Changeset 144


Ignore:
Timestamp:
May 11, 2018, 11:57:25 PM (7 years ago)
Author:
chronos
Message:
  • Modified: More code refactoring related to players brain selection.
Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Components/ScreenTools.pas

    r130 r144  
    5151function Play(Item: string; Index: integer = -1): boolean;
    5252procedure PreparePlay(Item: string; Index: integer = -1);
    53 procedure EmptyMenu(MenuItems: TMenuItem; Keep: integer = 0);
     53procedure EmptyMenu(MenuItems: TMenuItem; Keep: Integer = 0);
    5454function turntoyear(Turn: integer): integer;
    5555function TurnToString(Turn: integer): string;
     
    295295end;
    296296
    297 procedure EmptyMenu(MenuItems: TMenuItem; Keep: integer = 0);
    298 var
    299   m: TMenuItem;
    300 begin
    301   while MenuItems.Count > Keep do
    302   begin
    303     m := MenuItems[MenuItems.Count - 1];
     297procedure EmptyMenu(MenuItems: TMenuItem; Keep: Integer = 0);
     298var
     299  MenuItem: TMenuItem;
     300begin
     301  while MenuItems.Count > Keep do begin
     302    MenuItem := MenuItems[MenuItems.Count - 1];
    304303    MenuItems.Delete(MenuItems.Count - 1);
    305     m.Free;
     304    MenuItem.Free;
    306305  end;
    307306end;
  • trunk/Database.pas

    r120 r144  
    3131
    3232var
    33   GAlive, { players alive; bitset of 1 shl p }
    34   GWatching, GInitialized, GAI, RND, { world map randseed }
    35   lx, ly, MapSize, // = lx*ly
    36   LandMass,
     33  GAlive: Integer; { players alive; bitset of 1 shl p }
     34  GWatching: Integer;
     35  GInitialized: Integer;
     36  GAI: Integer;
     37  RND: Integer; { world map randseed }
     38  lx: Integer;
     39  ly: Integer;
     40  MapSize: Integer; // = lx*ly
     41  LandMass: Integer;
    3742{$IFOPT O-}InvalidTreatyMap, {$ENDIF}
    38   SaveMapCenterLoc, PeaceEnded, GTurn, { current turn }
    39   GTestFlags: integer;
     43  SaveMapCenterLoc: Integer;
     44  PeaceEnded: Integer;
     45  GTurn: Integer; { current turn }
     46  GTestFlags: Integer;
    4047  Mode: (moLoading_Fast, moLoading, moMovie, moPlaying);
    4148  GWonder: array [0 .. 27] of TWonderInfo;
  • trunk/GameServer.pas

    r143 r144  
    8787var
    8888  // PARAMETERS
    89   bixView: array [0 .. nPl - 1] of integer; { brain index of the players }
     89  PlayersBrain: TBrains; { brain index of the players }
    9090  Difficulty: array [0 .. nPl - 1] of integer absolute Database.Difficulty;
    9191  { difficulty }
     
    124124
    125125var
    126   MaxTurn, LoadTurn, { turn where to stop loading }
    127   nLogOpened, { nLog of opened book }
     126  MaxTurn: Integer;
     127  LoadTurn: Integer; { turn where to stop loading }
     128  nLogOpened: Integer; { nLog of opened book }
    128129{$IFOPT O-}nHandoverStack, {$ENDIF}
    129   LastEndClientCommand, pContacted, // player contacted for negotiation
    130   pDipActive, // player who's to speak in a negotiation
    131   pTurn, { player who's turn it is }
    132   GWinner, GColdWarStart, GStealFrom, SpyMission, ZOCTile, CCCommand,
    133     CCPlayer: integer;
    134   DebugMap: array [0 .. nPl - 1] of pointer;
     130  LastEndClientCommand: Integer;
     131  pContacted: Integer; // player contacted for negotiation
     132  pDipActive: Integer; // player who's to speak in a negotiation
     133  pTurn: Integer; { player who's turn it is }
     134  GWinner: Integer;
     135  GColdWarStart: Integer;
     136  GStealFrom: Integer;
     137  SpyMission: Integer;
     138  ZOCTile: Integer;
     139  CCCommand: Integer;
     140  CCPlayer: Integer;
     141  DebugMap: array [0 .. nPl - 1] of Pointer;
    135142  ExeInfo: TSearchRec;
    136143  Stat: array [0 .. nStat - 1, 0 .. nPl - 1] of ^TChart;
     
    144151  SavedTiles { , SavedResourceWeights } : array [0 .. ncmax - 1] of Cardinal;
    145152  SavedData: array [0 .. nPl - 1] of pointer;
    146   LogFileName, SavePath, { name of file for saving the current game }
    147   MapFileName, // name of map to use, empty for random
     153  LogFileName: string;
     154  SavePath: string; { name of file for saving the current game }
     155  MapFileName: string; // name of map to use, empty for random
    148156  AICredits: string;
    149157  AIInfo: array [0 .. nPl - 1] of string;
     
    151159  LastClientTime: TDateTime;
    152160{$IFOPT O-}HandoverStack: array [0 .. 31] of Cardinal; {$ENDIF}
    153   AutoSaveExists, LoadOK, WinOnAlone, PreviewElevation, MovieStopped: boolean;
     161  AutoSaveExists: Boolean;
     162  LoadOK: Boolean;
     163  WinOnAlone: Boolean;
     164  PreviewElevation: Boolean;
     165  MovieStopped: Boolean;
    154166
    155167const
     
    204216  BasePath: string;
    205217  NewBrain: TBrain;
     218  I: Integer;
    206219begin
    207220  Notify := NotifyFunction;
    208221  PreviewElevation := false;
     222  PlayersBrain := TBrains.Create(False);
     223  PlayersBrain.Count := nPl;
     224  for I := 0 to nPl - 1 do
     225    PlayersBrain[I] := nil;
    209226
    210227  { get available brains }
     
    264281        FreeLibrary(hm);
    265282    end;
     283  PlayersBrain.Free;
    266284  Brains.Free;
    267285end;
     
    650668    else
    651669    begin
    652       if Brains[bixView[i]].Kind in [btRandom, btAI] then
     670      if PlayersBrain[i].Kind in [btRandom, btAI] then
    653671        s := Brains[bix[i]].FileName
    654672      else
    655         s := Brains[bixView[i]].FileName;
     673        s := PlayersBrain[i].FileName;
    656674      move(zero, s[Length(s) + 1], 4);
    657675      LogFile.write(s, (Length(s) div 4 + 1) * 4);
     
    685703begin
    686704  for p1 := 0 to nPl - 1 do begin
    687     if (bixView[p1] <> -1) and (Brains[bixView[p1]].Kind = btSuperVirtual) then
     705    if Assigned(PlayersBrain[p1]) and (PlayersBrain[p1].Kind = btSuperVirtual) then
    688706      bix[p1] := Brains.IndexOf(BrainTerm) // supervisor and local human use same module
    689     else if (bixView[p1] <> -1) and (Brains[bixView[p1]].Kind = btRandom) then
     707    else if Assigned(PlayersBrain[p1]) and (PlayersBrain[p1].Kind = btRandom) then
    690708      if Brains.GetKindCount(btAI) = 0 then
    691709        bix[p1] := -1
    692710      else begin
    693711        AIBrains := TBrains.Create(False);
     712        Brains.GetByKind(btAI, AIBrains);
    694713        bix[p1] := Brains.IndexOf(AIBrains[DelphiRandom(AIBrains.Count)]);
    695714        AIBrains.Free;
    696715      end
    697716    else
    698       bix[p1] := bixView[p1];
    699     if bixView[p1] < 0 then
     717      bix[p1] := Brains.IndexOf(PlayersBrain[p1]);
     718    if not Assigned(PlayersBrain[p1]) then
    700719      Difficulty[p1] := -1;
    701720  end;
     
    10861105  MovieMode: boolean): boolean;
    10871106var
    1088   i, j, ix, d, p1, Command, Subject: integer;
     1107  j: TBrain;
     1108  i, ix, d, p1, Command, Subject: integer;
    10891109{$IFDEF TEXTLOG}LoadPos0: integer; {$ENDIF}
    10901110  Data: pointer;
     
    11241144      LogFile.read(s[0], 4);
    11251145      if s[0] = #0 then
    1126         bixView[p1] := -1
     1146        PlayersBrain[p1] := nil
    11271147      else
    11281148      begin
     
    11311151        LogFile.read(d, 4); { behavior }
    11321152        LogFile.read(Difficulty[p1], 4);
    1133         j := Brains.Count - 1;
    1134         while (j >= 0) and (AnsiCompareFileName(Brains[j].FileName, s) <> 0) do
    1135           dec(j);
    1136         if j < 0 then
     1153        j := Brains.Last;
     1154        while Assigned(J) and (AnsiCompareFileName(j.FileName, s) <> 0) do
     1155          J := PlayersBrain[PlayersBrain.IndexOf(J) - 1];
     1156        if not Assigned(j) then
    11371157        begin // ai not found -- replace by local player
    11381158          ProcessClientData[p1] := false;
    11391159          NotifyMessage := s;
    11401160          Notify(ntAIError);
    1141           j := Brains.IndexOf(BrainTerm);
     1161          j := BrainTerm;
    11421162        end
    11431163        else
    11441164          ProcessClientData[p1] := true;
    1145         if Brains[j].Kind = btNoTerm then
    1146           j := Brains.IndexOf(BrainSuperVirtual);
     1165        if j.Kind = btNoTerm then
     1166          j := BrainSuperVirtual;
    11471167        // crashed tournament -- load as supervisor
    1148         bixView[p1] := j;
     1168        PlayersBrain[p1] := j;
    11491169      end;
    11501170    end;
  • trunk/LocalPlayer/Term.pas

    r120 r144  
    304304    TPriceSet = Set of $00 .. $FF;
    305305
    306   const
    307     crImpDrag = 2;
    308     crFlatHand = 3;
    309 
    310     xxu = 32;
    311     yyu = 24; // half of unit slot size x/y
    312     yyu_anchor = 32;
    313     xxc = 32;
    314     yyc = 16; // 1/2 of city slot size in x, 1/2 of ground tile size in y (=1/3 of slot)
    315 
    316     // layout
    317     TopBarHeight = 41;
    318     PanelHeight = 168;
    319     MidPanelHeight = 120;
    320     // TopBarHeight+MidPanelHeight should be same as BaseWin.yUnused
    321     MapCenterUp = (MidPanelHeight - TopBarHeight) div 2;
    322 
    323     nCityType = 4;
    324 
    325     { client exclusive commands: }
    326     cSetTribe = $9000;
    327     cSetNewModelPicture = $9100;
    328     cSetModelName = $9110;
    329     cSetModelPicture = $9120;
    330     cSetSlaveIndex = $9131;
    331     cSetCityName = $9200;
    332 
    333     // city status flags
    334     csTypeMask = $0007;
    335     csToldDelay = $0008;
    336     csResourceWeightsMask = $00F0;
    337     csToldBombard = $0100;
    338 
    339     { unit status flags }
    340     usStay = $01;
    341     usWaiting = $02;
    342     usGoto = $04;
    343     usEnhance = $08;
    344     usRecover = $10;
    345     usToldNoReturn = $100;
    346     usPersistent = usStay or usGoto or usEnhance or usRecover or
    347       integer($FFFF0000);
    348 
    349     { model status flags }
    350     msObsolete = $1;
    351     msAllowConscripts = $2;
    352 
    353     { additional city happened flags }
    354     chTypeDel = $8000;
    355     chAllImpsMade = $4000;
    356 
    357     adNone = $801;
    358     adFar = $802;
    359     adNexus = $803;
    360 
    361     SpecialModelPictureCode: array [0 .. nSpecialModel - 1] of integer = (10,
    362       11, 40, 41, 21, 30, { 50,51, } 64, 74, { 71, } 73);
    363 
    364     pixSlaves = 0;
    365     pixNoSlaves = 1; // index of slaves in StdUnits
    366 
    367     // icons.bmp properties
    368     xSizeSmall = 36;
    369     ySizeSmall = 20;
    370     SystemIconLines = 2;
    371     // lines of system icons in icons.bmp before improvements
    372 
    373     // save options apart from what's defined by SaveOption
    374     soTellAI = 30;
    375     soExtraMask = $40000000;
    376 
    377     nCityEventPriority = 16;
    378     CityEventPriority: array [0 .. nCityEventPriority - 1] of integer =
    379       (chDisorder, chImprovementLost, chUnitLost, chAllImpsMade, chProduction,
    380       chOldWonder, chNoSettlerProd, chPopDecrease, chProductionSabotaged,
    381       chNoGrowthWarning, chPollution, chTypeDel, chFounded, chSiege,
    382       chAfterCapture, chPopIncrease);
    383 
    384     CityEventSoundItem: array [0 .. 15] of string = ('CITY_DISORDER', '',
    385       'CITY_POPPLUS', 'CITY_POPMINUS', 'CITY_UNITLOST', 'CITY_IMPLOST',
    386       'CITY_SABOTAGE', 'CITY_GROWTHNEEDSIMP', 'CITY_POLLUTION', 'CITY_SIEGE',
    387       'CITY_WONDEREX', 'CITY_EMDELAY', 'CITY_FOUNDED', 'CITY_FOUNDED', '',
    388       'CITY_INVALIDTYPE');
    389 
    390   type
    391     TPersistentData = record
    392       FarTech, ToldAge, ToldModels, ToldAlive, ToldContact, ToldOwnCredibility,
    393         ColdWarStart, PeaceEvaHappened: integer;
    394       EnhancementJobs: TEnhancementJobs;
    395       ImpOrder: array [0 .. nCityType - 1] of TImpOrder;
    396       ToldWonders: array [0 .. 27] of TWonderInfo;
    397       ToldTech: array [0 .. nAdv - 1] of ShortInt;
    398     end;
    399 
    400   var
    401     MyData: ^TPersistentData;
    402     AdvIcon: array [0 .. nAdv - 1] of integer;
    403     { icons displayed with the technologies }
    404     xxt, yyt, // half of tile size x/y
    405     GameMode, ClientMode, Age, UnFocus, OptionChecked, MapOptionChecked,
    406       nLostArmy, ScienceSum, TaxSum, SoundPreloadDone, MarkCityLoc, HGrTerrain,
    407       HGrCities, MovieSpeed: integer;
    408     CityRepMask: Cardinal;
    409     ReceivedOffer: TOffer;
    410     Buffer, SmallImp: TBitmap;
    411     BlinkON, DestinationMarkON, StartRunning, StayOnTop_Ensured,
    412       supervising: boolean;
    413     UnusedTribeFiles, TribeNames: tstringlist;
    414     TribeOriginal: array [0 .. nPl - 1] of boolean;
    415     LostArmy: array [0 .. nPl * nMmax - 1] of integer;
    416     DipMem: array [0 .. nPl - 1] of record pContact, SentCommand,
    417       FormerTreaty: integer;
     306const
     307  crImpDrag = 2;
     308  crFlatHand = 3;
     309
     310  xxu = 32;
     311  yyu = 24; // half of unit slot size x/y
     312  yyu_anchor = 32;
     313  xxc = 32;
     314  yyc = 16; // 1/2 of city slot size in x, 1/2 of ground tile size in y (=1/3 of slot)
     315
     316  // layout
     317  TopBarHeight = 41;
     318  PanelHeight = 168;
     319  MidPanelHeight = 120;
     320  // TopBarHeight+MidPanelHeight should be same as BaseWin.yUnused
     321  MapCenterUp = (MidPanelHeight - TopBarHeight) div 2;
     322
     323  nCityType = 4;
     324
     325  { client exclusive commands: }
     326  cSetTribe = $9000;
     327  cSetNewModelPicture = $9100;
     328  cSetModelName = $9110;
     329  cSetModelPicture = $9120;
     330  cSetSlaveIndex = $9131;
     331  cSetCityName = $9200;
     332
     333  // city status flags
     334  csTypeMask = $0007;
     335  csToldDelay = $0008;
     336  csResourceWeightsMask = $00F0;
     337  csToldBombard = $0100;
     338
     339  { unit status flags }
     340  usStay = $01;
     341  usWaiting = $02;
     342  usGoto = $04;
     343  usEnhance = $08;
     344  usRecover = $10;
     345  usToldNoReturn = $100;
     346  usPersistent = usStay or usGoto or usEnhance or usRecover or
     347    integer($FFFF0000);
     348
     349  { model status flags }
     350  msObsolete = $1;
     351  msAllowConscripts = $2;
     352
     353  { additional city happened flags }
     354  chTypeDel = $8000;
     355  chAllImpsMade = $4000;
     356
     357  adNone = $801;
     358  adFar = $802;
     359  adNexus = $803;
     360
     361  SpecialModelPictureCode: array [0 .. nSpecialModel - 1] of integer = (10,
     362    11, 40, 41, 21, 30, { 50,51, } 64, 74, { 71, } 73);
     363
     364  pixSlaves = 0;
     365  pixNoSlaves = 1; // index of slaves in StdUnits
     366
     367  // icons.bmp properties
     368  xSizeSmall = 36;
     369  ySizeSmall = 20;
     370  SystemIconLines = 2;
     371  // lines of system icons in icons.bmp before improvements
     372
     373  // save options apart from what's defined by SaveOption
     374  soTellAI = 30;
     375  soExtraMask = $40000000;
     376
     377  nCityEventPriority = 16;
     378  CityEventPriority: array [0 .. nCityEventPriority - 1] of integer =
     379    (chDisorder, chImprovementLost, chUnitLost, chAllImpsMade, chProduction,
     380    chOldWonder, chNoSettlerProd, chPopDecrease, chProductionSabotaged,
     381    chNoGrowthWarning, chPollution, chTypeDel, chFounded, chSiege,
     382    chAfterCapture, chPopIncrease);
     383
     384  CityEventSoundItem: array [0 .. 15] of string = ('CITY_DISORDER', '',
     385    'CITY_POPPLUS', 'CITY_POPMINUS', 'CITY_UNITLOST', 'CITY_IMPLOST',
     386    'CITY_SABOTAGE', 'CITY_GROWTHNEEDSIMP', 'CITY_POLLUTION', 'CITY_SIEGE',
     387    'CITY_WONDEREX', 'CITY_EMDELAY', 'CITY_FOUNDED', 'CITY_FOUNDED', '',
     388    'CITY_INVALIDTYPE');
     389
     390type
     391  TPersistentData = record
     392    FarTech: Integer;
     393    ToldAge: Integer;
     394    ToldModels: Integer;
     395    ToldAlive: Integer;
     396    ToldContact: Integer;
     397    ToldOwnCredibility: Integer;
     398    ColdWarStart: Integer;
     399    PeaceEvaHappened: Integer;
     400    EnhancementJobs: TEnhancementJobs;
     401    ImpOrder: array [0 .. nCityType - 1] of TImpOrder;
     402    ToldWonders: array [0 .. 27] of TWonderInfo;
     403    ToldTech: array [0 .. nAdv - 1] of ShortInt;
     404  end;
     405
     406var
     407  MyData: ^TPersistentData;
     408  AdvIcon: array [0 .. nAdv - 1] of Integer;
     409  { icons displayed with the technologies }
     410  xxt, yyt, // half of tile size x/y
     411  GameMode: Integer;
     412  ClientMode: Integer;
     413  Age: Integer;
     414  UnFocus: Integer;
     415  OptionChecked: Integer;
     416  MapOptionChecked: Integer;
     417  nLostArmy: Integer;
     418  ScienceSum: Integer;
     419  TaxSum: Integer;
     420  SoundPreloadDone: Integer;
     421  MarkCityLoc: Integer;
     422  HGrTerrain: Integer;
     423  HGrCities: Integer;
     424  MovieSpeed: Integer;
     425  CityRepMask: Cardinal;
     426  ReceivedOffer: TOffer;
     427  Buffer: TBitmap;
     428  SmallImp: TBitmap;
     429  BlinkON: Boolean;
     430  DestinationMarkON: Boolean;
     431  StartRunning: Boolean;
     432  StayOnTop_Ensured: Boolean;
     433  Supervising: Boolean;
     434  UnusedTribeFiles: TStringList;
     435  TribeNames: TStringList;
     436  TribeOriginal: array [0 .. nPl - 1] of Boolean;
     437  LostArmy: array [0 .. nPl * nMmax - 1] of Integer;
     438  DipMem: array [0 .. nPl - 1] of record
     439    pContact: Integer;
     440    SentCommand: Integer;
     441    FormerTreaty: Integer;
    418442    SentOffer: TOffer;
    419     DeliveredPrices, ReceivedPrices: TPriceSet;
     443    DeliveredPrices: TPriceSet;
     444    ReceivedPrices: TPriceSet;
    420445  end;
    421446
  • trunk/NoTerm.pas

    r143 r144  
    234234        begin // game ended, update statistics
    235235          for p := 1 to nPlOffered - 1 do
    236             if bixView[p] >= 0 then
     236            if Assigned(PlayersBrain[p]) then
    237237              if 1 shl p and G.RO[me].Alive = 0 then
    238238                inc(ExtStat[p]) // extinct
     
    323323  Canvas.Font.Assign(UniFont[ftSmall]);
    324324  for i := 1 to nPlOffered - 1 do
    325     if bixView[i] >= 0 then
     325    if Assigned(PlayersBrain[i]) then
    326326    begin
    327327      Frame(Canvas, xBrain[i] - 24, yBrain[i] - 8 - 16, xBrain[i] - 24 + 111,
    328328        yBrain[i] - 8 - 16 + 111, MainTexture.clBevelShade,
    329329        MainTexture.clBevelShade);
    330       FrameImage(Canvas, Brains[bixView[i]].Picture, xBrain[i],
     330      FrameImage(Canvas, PlayersBrain[i].Picture, xBrain[i],
    331331        yBrain[i] - 16, 64, 64, 0, 0);
    332332      if 1 shl i and G.RO[me].Alive = 0 then
  • trunk/Start.pas

    r143 r144  
    77  GameServer, Messg, ButtonBase, ButtonA, ButtonC, ButtonB, Area, Math,
    88  LCLIntf, LCLType, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls,
    9   Menus, Registry, DrawDlg;
     9  Menus, Registry, DrawDlg, fgl;
    1010
    1111const
     
    1919
    2020type
     21  TPlayerSlot = class
     22    DiffUpBtn: TButtonC;
     23    DiffDownBtn: TButtonC;
     24    MultiBtn: TButtonC;
     25    OfferMultiple: Boolean;
     26    Rect: TRect;
     27  end;
     28
     29  TPlayerSlots = class(TFPGObjectList<TPlayerSlot>)
     30
     31  end;
    2132
    2233  { TStartDlg }
     
    8798    Tab: Integer;
    8899    Diff0: Integer;
    89     bixDefault: Integer;
     100    BrainDefault: TBrain;
    90101    nMapLandTiles: Integer;
    91102    nMapStartPositions: Integer;
     
    94105    { last turn of selected former game }
    95106    SlotAvailable: Integer;
    96     bixPopup: Integer; { brain concerned by brain context menu }
     107    PlayerPopupIndex: Integer; { brain concerned by brain context menu }
    97108    ListIndex: array [0 .. 3] of integer;
    98109    MapFileName: string;
     
    101112    MiniColors: array [0 .. 11, 0 .. 1] of TColor;
    102113    // BookDate: string;
    103     DiffUpBtn: array [0 .. 8] of TButtonC;
    104     DiffDownBtn: array [0 .. 8] of TButtonC;
    105     MultiBtn: array [6 .. 8] of TButtonC;
     114    PlayerSlots: TPlayerSlots;
    106115    MiniMode: (mmNone, mmPicture, mmMultiPlayer);
    107116    ActionsOffered: set of 0 .. nMainActions - 1;
    108117    TurnValid, Tracking: boolean;
    109118    DefaultAI: string;
    110     procedure InitPopup(PopupIndex: integer);
     119    procedure InitPopup(PlayerIndex: Integer);
    111120    procedure PaintInfo;
    112121    procedure ChangePage(NewPage: integer);
     
    191200  pgMain = 6;
    192201
    193   OfferMultiple = [6, 7, 8];
    194 
    195202  PlayerAutoDiff: array [1 .. 5] of integer = (1, 1, 2, 2, 3);
    196203  EnemyAutoDiff: array [1 .. 5] of integer = (4, 3, 2, 1, 1);
     
    202209  Location: TPoint;
    203210  AIBrains: TBrains;
    204 begin
     211  PlayerSlot: TPlayerSlot;
     212begin
     213  PlayerSlots := TPlayerSlots.Create;
     214  PlayerSlots.Count := nPlOffered;
     215  for I := 0 to PlayerSlots.Count - 1 do begin
     216    PlayerSlot := TPlayerSlot.Create;
     217    PlayerSlot.Rect := Bounds(xBrain[I], YBrain[I], 0, 0);
     218    PlayerSlots[I] := PlayerSlot;
     219  end;
    205220  LoadConfig;
    206221
     
    210225    Include(ActionsOffered, maAIDev);
    211226
    212   bixDefault := -1;
     227  BrainDefault := nil;
    213228  for i := Brains.IndexOf(BrainRandom) to Brains.Count - 1 do
    214229    if AnsiCompareFileName(DefaultAI, Brains[i].FileName) = 0 then
    215       bixDefault := i;
    216   if (bixDefault = Brains.IndexOf(BrainRandom)) and (Brains.GetKindCount(btAI) < 2) then
    217     bixDefault := -1;
    218   if (bixDefault < 0) and (Brains.GetKindCount(btAI) > 0) then
     230      BrainDefault := Brains[i];
     231  if (BrainDefault = BrainRandom) and (Brains.GetKindCount(btAI) < 2) then
     232    BrainDefault := nil;
     233  if (not Assigned(BrainDefault)) and (Brains.GetKindCount(btAI) > 0) then
    219234    begin
    220235      AIBrains := TBrains.Create(False);
    221236      Brains.GetByKind(btAI, AIBrains);
    222       bixDefault := Brains.IndexOf(Brains[0]);
     237      BrainDefault := Brains[0];
    223238      AIBrains.Free;
    224239    end; // default AI not found, use any
     
    256271  QuitBtn.Hint := Phrases.Lookup('STARTCONTROLS', 0);
    257272  ReplayBtn.Hint := Phrases.Lookup('BTN_REPLAY');
    258   for i := 0 to nPlOffered - 1 do
    259   begin
    260     DiffUpBtn[i] := TButtonC.Create(self);
    261     DiffUpBtn[i].Graphic := GrExt[HGrSystem].Data;
    262     DiffUpBtn[i].left := xBrain[i] - 18;
    263     DiffUpBtn[i].top := yBrain[i] + 39;
    264     DiffUpBtn[i].ButtonIndex := 1;
    265     DiffUpBtn[i].Parent := self;
    266     DiffUpBtn[i].OnClick := DiffBtnClick;
    267     DiffDownBtn[i] := TButtonC.Create(self);
    268     DiffDownBtn[i].Graphic := GrExt[HGrSystem].Data;
    269     DiffDownBtn[i].left := xBrain[i] - 18;
    270     DiffDownBtn[i].top := yBrain[i] + 51;
    271     DiffDownBtn[i].ButtonIndex := 0;
    272     DiffDownBtn[i].Parent := self;
    273     DiffDownBtn[i].OnClick := DiffBtnClick;
     273  PlayerSlots.Count := nPlOffered;
     274  for i := 0 to PlayerSlots.Count - 1 do
     275  with PlayerSlots[i] do begin
     276    DiffUpBtn := TButtonC.Create(self);
     277    DiffUpBtn.Graphic := GrExt[HGrSystem].Data;
     278    DiffUpBtn.left := xBrain[i] - 18;
     279    DiffUpBtn.top := yBrain[i] + 39;
     280    DiffUpBtn.ButtonIndex := 1;
     281    DiffUpBtn.Parent := self;
     282    DiffUpBtn.OnClick := DiffBtnClick;
     283    DiffDownBtn := TButtonC.Create(self);
     284    DiffDownBtn.Graphic := GrExt[HGrSystem].Data;
     285    DiffDownBtn.left := xBrain[i] - 18;
     286    DiffDownBtn.top := yBrain[i] + 51;
     287    DiffDownBtn.ButtonIndex := 0;
     288    DiffDownBtn.Parent := self;
     289    DiffDownBtn.OnClick := DiffBtnClick;
    274290  end;
    275291  for i := 6 to 8 do
    276   begin
    277     MultiBtn[i] := TButtonC.Create(self);
    278     MultiBtn[i].Graphic := GrExt[HGrSystem].Data;
    279     MultiBtn[i].left := xBrain[i] - 18;
    280     MultiBtn[i].top := yBrain[i];
    281     MultiBtn[i].Parent := self;
    282     MultiBtn[i].OnClick := MultiBtnClick;
     292  with PlayerSlots[i] do begin
     293    MultiBtn := TButtonC.Create(self);
     294    MultiBtn.Graphic := GrExt[HGrSystem].Data;
     295    MultiBtn.left := xBrain[i] - 18;
     296    MultiBtn.top := yBrain[i];
     297    MultiBtn.Parent := self;
     298    MultiBtn.OnClick := MultiBtnClick;
     299    OfferMultiple := True;
    283300  end;
    284301
     
    344361  InitButtons;
    345362
    346   bixView[0] := Brains.IndexOf(BrainTerm);
     363  PlayersBrain[0] := BrainTerm;
    347364  SlotAvailable := -1;
    348365  Tab := 2;
     
    365382  FreeAndNil(EmptyPicture);
    366383  FreeAndNil(LogoBuffer);
     384  FreeAndNil(PlayerSlots);
    367385end;
    368386
     
    645663        if 1 shl i and SlotAvailable <> 0 then
    646664        begin
    647           if bixView[i] >= 0 then
    648             FrameImage(Canvas, Brains[bixView[i]].Picture, xBrain[i], yBrain[i],
     665          if Assigned(PlayersBrain[i]) then
     666            FrameImage(Canvas, PlayersBrain[i].Picture, xBrain[i], yBrain[i],
    649667              64, 64, 0, 0, true)
    650668          else
    651669            FrameImage(Canvas, EmptyPicture, xBrain[i], yBrain[i], 64, 64,
    652670              0, 0, true);
    653           if Brains[bixView[i]].Kind in [btTerm, btRandom, btAI] then
     671          if Assigned(PlayersBrain[I]) and (PlayersBrain[i].Kind in [btTerm, btRandom, btAI]) then
    654672          begin
    655673            BitBlt(Canvas.Handle, xBrain[i] - 18, yBrain[i] + 19, 12, 14,
     
    658676            Frame(Canvas, xBrain[i] - 19, yBrain[i] + 18, xBrain[i] - 18 + 12,
    659677              yBrain[i] + (19 + 14), $000000, $000000);
    660             RFrame(Canvas, DiffUpBtn[i].left - 1, DiffUpBtn[i].top - 1,
    661               DiffUpBtn[i].left + 12, DiffUpBtn[i].top + 24,
     678            RFrame(Canvas, PlayerSlots[i].DiffUpBtn.left - 1, PlayerSlots[i].DiffUpBtn.top - 1,
     679              PlayerSlots[i].DiffUpBtn.left + 12, PlayerSlots[i].DiffUpBtn.top + 24,
    662680              MainTexture.clBevelShade, MainTexture.clBevelLight);
    663681            with Canvas do
     
    668686              Brush.Style := bsClear;
    669687            end;
    670             if i in OfferMultiple then
     688            if PlayerSlots[I].OfferMultiple then
    671689            begin
    672               RFrame(Canvas, MultiBtn[i].left - 1, MultiBtn[i].top - 1,
    673                 MultiBtn[i].left + 12, MultiBtn[i].top + 12,
     690              RFrame(Canvas, PlayerSlots[I].MultiBtn.left - 1, PlayerSlots[I].MultiBtn.top - 1,
     691                PlayerSlots[I].MultiBtn.left + 12, PlayerSlots[I].MultiBtn.top + 12,
    674692                MainTexture.clBevelShade, MainTexture.clBevelLight);
    675693              BitBlt(Canvas.Handle, xBrain[i] - 31, yBrain[i], 13, 12,
     
    677695            end
    678696          end;
    679           if bixView[i] >= 0 then
     697          if Assigned(PlayersBrain[i]) then
    680698          begin
    681             DiffUpBtn[i].Hint := Format(Phrases.Lookup('STARTCONTROLS', 9),
    682               [Brains[bixView[i]].Name]);
    683             DiffDownBtn[i].Hint := DiffUpBtn[i].Hint;
     699            PlayerSlots[i].DiffUpBtn.Hint := Format(Phrases.Lookup('STARTCONTROLS', 9),
     700              [PlayersBrain[i].Name]);
     701            PlayerSlots[i].DiffDownBtn.Hint := PlayerSlots[i].DiffUpBtn.Hint;
    684702          end
    685703        end;
     
    706724          64, 0, 0, false)
    707725      else
    708         FrameImage(Canvas, Brains[bixDefault].Picture, xDefault, yDefault, 64, 64,
     726        FrameImage(Canvas, BrainDefault.Picture, xDefault, yDefault, 64, 64,
    709727          0, 0, true);
    710728      DLine(Canvas, 56, 272, y0Mini + 61 + 19, MainTexture.clBevelLight,
     
    901919
    902920    pgStartRandom, pgStartMap:
    903       if bixView[0] >= 0 then
     921      if Assigned(PlayersBrain[0]) then
    904922      begin
    905923        if (Page = pgStartMap) and (nMapStartPositions = 0) and (AutoDiff > 0)
     
    917935            else GameCount := 0;
    918936
    919           if (AutoDiff < 0) and (Brains[bixView[0]].Kind = btNoTerm) then
     937          if (AutoDiff < 0) and (PlayersBrain[0].Kind = btNoTerm) then
    920938            FileName := 'Round' + IntToStr(GetProcessID())
    921939          else begin
     
    932950            if AutoDiff < 0 then
    933951              for i := 0 to nPlOffered - 1 do begin
    934                 if bixView[i] = -1 then
     952                if not Assigned(PlayersBrain[i]) then
    935953                  Reg.WriteString('Control' + IntToStr(i), '')
    936954                else Reg.WriteString('Control' + IntToStr(i),
    937                   Brains[bixView[i]].FileName);
     955                  PlayersBrain[i].FileName);
    938956                WriteInteger('Diff' + IntToStr(i), Difficulty[i]);
    939957              end;
     
    944962          if AutoDiff > 0 then
    945963          begin
    946             WriteString('DefaultAI', Brains[bixDefault].FileName);
     964            WriteString('DefaultAI', BrainDefault.FileName);
    947965            SlotAvailable := 0; // bixView will be invalid hereafter
    948             bixView[0] := Brains.IndexOf(BrainTerm);
     966            PlayersBrain[0] := BrainTerm;
    949967            Difficulty[0] := PlayerAutoDiff[AutoDiff];
    950968            for i := 1 to nPl - 1 do
    951969              if (Page = pgStartRandom) and (i <= AutoEnemies) or
    952970                (Page = pgStartMap) and (i < nMapStartPositions) then begin
    953                 if AutoDiff = 1 then bixView[i] := Brains.IndexOf(BrainBeginner)
    954                   else bixView[i] := bixDefault;
     971                if AutoDiff = 1 then PlayersBrain[i] := BrainBeginner
     972                  else PlayersBrain[i] := BrainDefault;
    955973                Difficulty[i] := EnemyAutoDiff[AutoDiff];
    956               end  else bixView[i] := -1;
     974              end  else PlayersBrain[i] := nil;
    957975          end else begin
    958976            for i := 6 to 8 do
    959               if (Brains[bixView[0]].Kind <> btNoTerm) and (MultiControl and (1 shl i) <> 0)
     977              if (PlayersBrain[0].Kind <> btNoTerm) and (MultiControl and (1 shl i) <> 0)
    960978              then begin
    961                 bixView[i + 3] := bixView[i];
     979                PlayersBrain[i + 3] := PlayersBrain[i];
    962980                Difficulty[i + 3] := Difficulty[i];
    963                 bixView[i + 6] := bixView[i];
     981                PlayersBrain[i + 6] := PlayersBrain[i];
    964982                Difficulty[i + 6] := Difficulty[i];
    965983              end else begin
    966                 bixView[i + 3] := -1;
    967                 bixView[i + 6] := -1;
     984                PlayersBrain[i + 3] := nil;
     985                PlayersBrain[i + 6] := nil;
    968986              end
    969987          end;
     
    12331251begin
    12341252  // Play('BUTTON_UP');
    1235   if bixPopup < 0 then
     1253  if PlayerPopupIndex < 0 then
    12361254  begin // change default AI
    1237     bixDefault := TMenuItem(Sender).Tag;
     1255    BrainDefault := Brains[TMenuItem(Sender).Tag];
    12381256    SmartInvalidate(xDefault, yDefault, xDefault + 64, yDefault + 64);
    12391257  end
    12401258  else
    12411259  begin
    1242     Brains[bixView[bixPopup]].Flags := Brains[bixView[bixPopup]].Flags and
    1243       not fUsed;
    1244     bixView[bixPopup] := TMenuItem(Sender).Tag;
    1245     DiffUpBtn[bixPopup].Visible := Brains[bixView[bixPopup]].Kind in [btTerm, btRandom, btAI];
    1246     DiffDownBtn[bixPopup].Visible := Brains[bixView[bixPopup]].Kind in [btTerm, btRandom, btAI];
    1247     if bixPopup in OfferMultiple then
    1248     begin
    1249       MultiBtn[bixPopup].Visible := Brains[bixView[bixPopup]].Kind in [btTerm, btRandom, btAI];
    1250       MultiBtn[bixPopup].ButtonIndex := 2 + (MultiControl shr bixPopup) and 1;
     1260    if Assigned(PlayersBrain[PlayerPopupIndex]) then
     1261      PlayersBrain[PlayerPopupIndex].Flags := PlayersBrain[PlayerPopupIndex].Flags and not fUsed;
     1262    if TMenuItem(Sender).Tag = -1 then begin
     1263      PlayersBrain[PlayerPopupIndex] := nil;
     1264      PlayerSlots[PlayerPopupIndex].DiffUpBtn.Visible := False;
     1265      PlayerSlots[PlayerPopupIndex].DiffDownBtn.Visible := False;
     1266      if PlayerSlots[PlayerPopupIndex].OfferMultiple then begin
     1267        PlayerSlots[PlayerPopupIndex].MultiBtn.Visible := False;
     1268        PlayerSlots[PlayerPopupIndex].MultiBtn.ButtonIndex := 2 + (MultiControl shr PlayerPopupIndex) and 1;
     1269      end;
     1270      MultiControl := MultiControl and not (1 shl PlayerPopupIndex);
     1271    end else begin
     1272      PlayersBrain[PlayerPopupIndex] := Brains[TMenuItem(Sender).Tag];
     1273      PlayerSlots[PlayerPopupIndex].DiffUpBtn.Visible := PlayersBrain[PlayerPopupIndex].Kind in [btTerm, btRandom, btAI];
     1274      PlayerSlots[PlayerPopupIndex].DiffDownBtn.Visible := PlayersBrain[PlayerPopupIndex].Kind in [btTerm, btRandom, btAI];
     1275      if PlayerSlots[PlayerPopupIndex].OfferMultiple then begin
     1276        PlayerSlots[PlayerPopupIndex].MultiBtn.Visible := PlayersBrain[PlayerPopupIndex].Kind in [btTerm, btRandom, btAI];
     1277        PlayerSlots[PlayerPopupIndex].MultiBtn.ButtonIndex := 2 + (MultiControl shr PlayerPopupIndex) and 1;
     1278      end;
     1279      PlayersBrain[PlayerPopupIndex].Flags := PlayersBrain[PlayerPopupIndex].Flags or fUsed;
     1280      if PlayersBrain[PlayerPopupIndex].Kind in [btNoTerm, btSuperVirtual] then
     1281        Difficulty[PlayerPopupIndex] := 0 { supervisor }
     1282      else
     1283        Difficulty[PlayerPopupIndex] := 2;
     1284      if (Page = pgStartRandom) and (PlayerSlots[PlayerPopupIndex].OfferMultiple) and
     1285        (not Assigned(PlayersBrain[PlayerPopupIndex])) then
     1286        MultiControl := MultiControl and not (1 shl PlayerPopupIndex);
     1287      if (PlayerPopupIndex = 0) and (MapFileName <> '') then
     1288        ChangePage(Page);
     1289      if PlayersBrain[PlayerPopupIndex].Kind = btNoTerm then
     1290      begin // turn all local players off
     1291        for I := 1 to PlayerSlots.Count - 1 do
     1292          if PlayersBrain[I].Kind = btTerm then begin
     1293            PlayersBrain[i] := nil;
     1294            PlayerSlots[i].DiffUpBtn.Visible := false;
     1295            PlayerSlots[i].DiffUpBtn.Tag := 0;
     1296            PlayerSlots[i].DiffDownBtn.Visible := false;
     1297            PlayerSlots[i].DiffDownBtn.Tag := 0;
     1298            if PlayerSlots[i].OfferMultiple then begin
     1299              PlayerSlots[i].MultiBtn.Visible := false;
     1300              PlayerSlots[i].MultiBtn.Tag := 0;
     1301            end;
     1302            SmartInvalidate(xBrain[i] - 31, yBrain[i] - 1, xBrain[i] + 64,
     1303              PlayerSlots[i].DiffUpBtn.top + 25);
     1304          end;
     1305        BrainTerm.Flags := BrainTerm.Flags and not fUsed;
     1306      end;
    12511307    end;
    1252     Brains[bixView[bixPopup]].Flags := Brains[bixView[bixPopup]].Flags or fUsed;
    1253     if Brains[bixView[bixPopup]].Kind in [btNoTerm, btSuperVirtual] then
    1254       Difficulty[bixPopup] := 0 { supervisor }
    1255     else
    1256       Difficulty[bixPopup] := 2;
    1257     if (Page = pgStartRandom) and (bixPopup in OfferMultiple) and
    1258       (bixView[bixPopup] < 0) then
    1259       MultiControl := MultiControl and not(1 shl bixPopup);
    1260     if (bixPopup = 0) and (MapFileName <> '') then
    1261       ChangePage(Page);
    1262     if Brains[bixView[bixPopup]].Kind = btNoTerm then
    1263     begin // turn all local players off
    1264       for i := 1 to nPlOffered - 1 do
    1265         if Brains[bixView[i]].Kind = btTerm then
    1266         begin
    1267           bixView[i] := -1;
    1268           DiffUpBtn[i].Visible := false;
    1269           DiffUpBtn[i].Tag := 0;
    1270           DiffDownBtn[i].Visible := false;
    1271           DiffDownBtn[i].Tag := 0;
    1272           if i in OfferMultiple then
    1273           begin
    1274             MultiBtn[i].Visible := false;
    1275             MultiBtn[i].Tag := 0;
    1276           end;
    1277           SmartInvalidate(xBrain[i] - 31, yBrain[i] - 1, xBrain[i] + 64,
    1278             DiffUpBtn[i].top + 25);
    1279         end;
    1280       BrainTerm.Flags := BrainTerm.Flags and not fUsed;
    1281     end;
    1282     SmartInvalidate(xBrain[bixPopup] - 31, yBrain[bixPopup] - 1,
    1283       xBrain[bixPopup] + 64, DiffUpBtn[bixPopup].top + 25);
    1284   end
    1285 end;
    1286 
    1287 procedure TStartDlg.InitPopup(PopupIndex: integer);
    1288 var
    1289   i, FixedLines: integer;
    1290   m: TMenuItem;
     1308    SmartInvalidate(xBrain[PlayerPopupIndex] - 31, yBrain[PlayerPopupIndex] - 1,
     1309      xBrain[PlayerPopupIndex] + 64, PlayerSlots[PlayerPopupIndex].DiffUpBtn.top + 25);
     1310  end
     1311end;
     1312
     1313procedure TStartDlg.InitPopup(PlayerIndex: Integer);
     1314var
     1315  I: Integer;
     1316  FixedLines: integer;
     1317  MenuItem: TMenuItem;
    12911318  AIBrains: TBrains;
    12921319
    1293   procedure OfferBrain(Index: integer);
     1320  procedure OfferBrain(Brain: TBrain);
    12941321  var
    1295     j: integer;
    1296   begin
    1297     m := TMenuItem.Create(PopupMenu1);
    1298     if Index < 0 then
    1299       m.Caption := Phrases.Lookup('NOMOD')
    1300     else
    1301       m.Caption := Brains[Index].Name;
    1302     m.Tag := Index;
    1303     m.OnClick := BrainClick;
    1304     j := FixedLines;
    1305     while (j < PopupMenu1.Items.Count) and
    1306       (StrIComp(pchar(m.Caption), pchar(PopupMenu1.Items[j].Caption)) > 0) do
    1307       inc(j);
    1308     m.RadioItem := true;
    1309     if bixPopup < 0 then
    1310       m.Checked := bixDefault = Index
    1311     else
    1312       m.Checked := bixView[bixPopup] = Index;
    1313     PopupMenu1.Items.Insert(j, m);
    1314   end;
    1315 
    1316 begin
    1317   bixPopup := PopupIndex;
     1322    J: Integer;
     1323  begin
     1324    MenuItem := TMenuItem.Create(PopupMenu1);
     1325    if not Assigned(Brain) then MenuItem.Caption := Phrases.Lookup('NOMOD')
     1326      else MenuItem.Caption := Brain.Name;
     1327    MenuItem.Tag := Brains.IndexOf(Brain);
     1328    MenuItem.OnClick := BrainClick;
     1329    J := FixedLines;
     1330    while (J < PopupMenu1.Items.Count) and
     1331      (StrIComp(pchar(MenuItem.Caption), pchar(PopupMenu1.Items[J].Caption)) > 0) do
     1332      Inc(J);
     1333    MenuItem.RadioItem := True;
     1334    if (PlayerPopupIndex < 0) then MenuItem.Checked := BrainDefault = Brain
     1335      else MenuItem.Checked := PlayersBrain[PlayerPopupIndex] = Brain;
     1336    PopupMenu1.Items.Insert(J, MenuItem);
     1337  end;
     1338
     1339begin
     1340  PlayerPopupIndex := PlayerIndex;
    13181341  EmptyMenu(PopupMenu1.Items);
    1319   if bixPopup < 0 then
    1320   begin // select default AI
     1342  if PlayerPopupIndex < 0 then begin // select default AI
    13211343    FixedLines := 0;
    1322     if Brains.GetKindCount(btAI) >= 2 then
    1323     begin
    1324       OfferBrain(Brains.IndexOf(BrainRandom));
    1325       inc(FixedLines)
     1344    if Brains.GetKindCount(btAI) >= 2 then begin
     1345      OfferBrain(BrainRandom);
     1346      Inc(FixedLines);
    13261347    end;
    13271348    AIBrains := TBrains.Create(False);
    13281349    Brains.GetByKind(btAI, AIBrains);
    1329     for i := 0 to AIBrains.Count - 1 do // offer available AIs
    1330       if AIBrains[i].Flags and fMultiple <> 0 then
    1331         OfferBrain(Brains.IndexOf(AIBrains[i]));
     1350    for I := 0 to AIBrains.Count - 1 do // offer available AIs
     1351      if AIBrains[I].Flags and fMultiple <> 0 then
     1352        OfferBrain(AIBrains[I]);
    13321353    AIBrains.Free;
    1333   end
    1334   else
    1335   begin
     1354  end else begin
    13361355    FixedLines := 0;
    1337     if bixPopup > 0 then
    1338     begin
    1339       OfferBrain(-1);
    1340       inc(FixedLines);
     1356    if PlayerPopupIndex > 0 then begin
     1357      OfferBrain(nil);
     1358      Inc(FixedLines);
    13411359    end;
    1342     for i := Brains.IndexOf(BrainTerm) downto 0 do // offer game interfaces
    1343       if (bixPopup = 0) or (Brains[i].Kind = btTerm) and (Brains[bixView[0]].Kind <> btNoTerm) then
    1344       begin
    1345         OfferBrain(i);
    1346         inc(FixedLines);
    1347       end;
    1348     if bixPopup > 0 then
    1349     begin
    1350       m := TMenuItem.Create(PopupMenu1);
    1351       m.Caption := '-';
    1352       PopupMenu1.Items.Add(m);
    1353       inc(FixedLines);
    1354       if Brains.GetKindCount(btAI) >= 2 then
    1355       begin
    1356         OfferBrain(Brains.IndexOf(BrainRandom));
    1357         inc(FixedLines);
     1360    for I := Brains.IndexOf(BrainTerm) downto 0 do // offer game interfaces
     1361      if (PlayerPopupIndex = 0) or (Brains[i].Kind = btTerm) and
     1362        (PlayersBrain[0].Kind <> btNoTerm) then begin
     1363        OfferBrain(Brains[I]);
     1364        Inc(FixedLines);
     1365      end;
     1366    if PlayerPopupIndex > 0 then begin
     1367      MenuItem := TMenuItem.Create(PopupMenu1);
     1368      MenuItem.Caption := '-';
     1369      PopupMenu1.Items.Add(MenuItem);
     1370      Inc(FixedLines);
     1371      if Brains.GetKindCount(btAI) >= 2 then begin
     1372        OfferBrain(BrainRandom);
     1373        Inc(FixedLines);
    13581374      end;
    13591375      AIBrains := TBrains.Create(False);
    13601376      Brains.GetByKind(btAI, AIBrains);
    1361       for i := 0 to AIBrains.Count - 1 do // offer available AIs
    1362         if (AIBrains[i].Flags and fMultiple <> 0) or (AIBrains[i].Flags and fUsed = 0)
    1363           or (i = bixView[bixPopup]) then
    1364           OfferBrain(Brains.IndexOf(AIBrains[i]));
     1377      for I := 0 to AIBrains.Count - 1 do // offer available AIs
     1378        if (AIBrains[I].Flags and fMultiple <> 0) or (AIBrains[I].Flags and fUsed = 0)
     1379          or (Brains[I] = PlayersBrain[PlayerPopupIndex]) then
     1380          OfferBrain(AIBrains[i]);
    13651381      AIBrains.Free;
    13661382    end;
    1367   end
     1383  end;
    13681384end;
    13691385
     
    14261442          if i = 0 then
    14271443          begin
    1428             bixView[0] := Brains.IndexOf(BrainSuperVirtual);
     1444            PlayersBrain[0] := BrainSuperVirtual;
    14291445            Difficulty[0] := 0
    14301446          end;
    1431           if Brains[bixView[0]].Kind in [btNoTerm, btSuperVirtual] then
     1447          if PlayersBrain[0].Kind in [btNoTerm, btSuperVirtual] then
    14321448            inc(i);
    14331449          if i > nPl then
     
    14461462              OpenKey(AppRegistryKey + '\AI', True);
    14471463              for p1 := 0 to nPlOffered - 1 do begin
    1448                 bixView[p1] := -1;
     1464                PlayersBrain[p1] := nil;
    14491465                s := ReadString('Control' + IntToStr(p1));
    14501466                Difficulty[p1] := ReadInteger('Diff' + IntToStr(p1));
     
    14521468                  for j := 0 to Brains.Count - 1 do
    14531469                    if AnsiCompareFileName(s, Brains[j].FileName) = 0 then
    1454                       bixView[p1] := j;
     1470                      PlayersBrain[p1] := Brains[j];
    14551471              end;
    14561472              MultiControl := Reg.ReadInteger('MultiControl');
     
    14631479              if 1 shl p1 and InitAlive[i] <> 0 then
    14641480              begin
    1465                 bixView[p1] := bixDefault;
     1481                PlayersBrain[p1] := BrainDefault;
    14661482                Difficulty[p1] := 2;
    14671483              end
    14681484              else
    1469                 bixView[p1] := -1;
     1485                PlayersBrain[p1] := nil;
    14701486        SlotAvailable := InitAlive[i];
    14711487        for i := 0 to nPlOffered - 1 do
    1472           if (AutoDiff < 0) and (Brains[bixView[i]].Kind in [btTerm, btRandom, btAI]) then
     1488          if (AutoDiff < 0) and Assigned(PlayersBrain[i]) and
     1489            (PlayersBrain[i].Kind in [btTerm, btRandom, btAI]) then
    14731490          begin
    1474             DiffUpBtn[i].Tag := 768;
    1475             DiffDownBtn[i].Tag := 768;
     1491            PlayerSlots[i].DiffUpBtn.Tag := 768;
     1492            PlayerSlots[i].DiffDownBtn.Tag := 768;
    14761493          end
    14771494          else
    14781495          begin
    1479             DiffUpBtn[i].Tag := 0;
    1480             DiffDownBtn[i].Tag := 0;
     1496            PlayerSlots[i].DiffUpBtn.Tag := 0;
     1497            PlayerSlots[i].DiffDownBtn.Tag := 0;
    14811498          end;
    14821499        for i := 6 to 8 do
    1483           if (AutoDiff < 0) and (Brains[bixView[i]].Kind in [btTerm, btRandom, btAI]) then
     1500          if (AutoDiff < 0) and Assigned(PlayersBrain[i]) and
     1501            (PlayersBrain[i].Kind in [btTerm, btRandom, btAI]) then
    14841502          begin
    1485             MultiBtn[i].Tag := 768;
    1486             MultiBtn[i].ButtonIndex := 2 + (MultiControl shr i) and 1;
    1487             MultiBtn[i].Enabled := Page = pgStartRandom
     1503            PlayerSlots[i].MultiBtn.Tag := 768;
     1504            PlayerSlots[i].MultiBtn.ButtonIndex := 2 + (MultiControl shr i) and 1;
     1505            PlayerSlots[i].MultiBtn.Enabled := Page = pgStartRandom
    14881506          end
    14891507          else
    1490             MultiBtn[i].Tag := 0;
     1508            PlayerSlots[i].MultiBtn.Tag := 0;
    14911509        if (AutoDiff > 0) and (Page <> pgStartMap) then
    14921510        begin
     
    15081526          AutoDiffUpBtn.Tag := 0;
    15091527          AutoDiffDownBtn.Tag := 0;
    1510         end
     1528        end;
    15111529      end;
    15121530
     
    18591877begin
    18601878  for i := 0 to nPlOffered - 1 do
    1861     if (Sender = DiffUpBtn[i]) and (Difficulty[i] < 3) or
    1862       (Sender = DiffDownBtn[i]) and (Difficulty[i] > 1) then
     1879    if (Sender = PlayerSlots[i].DiffUpBtn) and (Difficulty[i] < 3) or
     1880      (Sender = PlayerSlots[i].DiffDownBtn) and (Difficulty[i] > 1) then
    18631881    begin
    1864       if Sender = DiffUpBtn[i] then
     1882      if Sender = PlayerSlots[i].DiffUpBtn then
    18651883        inc(Difficulty[i])
    18661884      else
     
    18761894begin
    18771895  for i := 6 to 8 do
    1878     if Sender = MultiBtn[i] then
     1896    if Sender = PlayerSlots[i].MultiBtn then
    18791897    begin
    18801898      MultiControl := MultiControl xor (1 shl i);
Note: See TracChangeset for help on using the changeset viewer.