Changeset 143 for trunk/GameServer.pas


Ignore:
Timestamp:
May 8, 2018, 4:37:34 PM (7 years ago)
Author:
chronos
Message:
  • Modified: Brains array changed to object list and TBrainInfo record to TBrain class for better code maintainability.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/GameServer.pas

    r133 r143  
    77
    88uses
    9   Protocol, Database, dynlibs, Platform, dateutils;
     9  Protocol, Database, dynlibs, Platform, dateutils, fgl, FileUtil, Graphics;
    1010
    1111const
     
    5050
    5151  maxBrain = 255;
    52   bixNoTerm = 0;
    53   bixSuper_Virtual = 1;
    54   bixTerm = 2;
    55   bixRandom = 3;
    56   bixFirstAI = 4;
    5752
    5853type
    5954  TNotifyFunction = procedure(ID: integer);
    6055
    61   TBrainInfo = record
    62     FileName, DLLName, Name, Credits: string; { filename and full name }
     56  TBrainType = (btNoTerm, btSuperVirtual, btTerm, btRandom, btAI);
     57
     58  { TBrain }
     59
     60  TBrain = class
     61    FileName: string;
     62    DLLName: string;
     63    Name: string;
     64    Credits: string; { filename and full name }
    6365    hm: TLibHandle; { module handle }
    64     Flags, ServerVersion, DataVersion, DataSize: integer;
     66    Flags: Integer;
     67    ServerVersion: Integer;
     68    DataVersion: Integer;
     69    DataSize: Integer;
    6570    Client: TClientCall; { client function address }
    66     Initialized: boolean;
     71    Initialized: Boolean;
     72    Kind: TBrainType;
     73    Picture: TBitmap;
     74    procedure LoadFromFile(AIFileName: string);
     75    constructor Create;
     76    destructor Destroy; override;
     77  end;
     78
     79  { TBrains }
     80
     81  TBrains = class(TFPGObjectList<TBrain>)
     82    function AddNew: TBrain;
     83    function GetKindCount(Kind: TBrainType): Integer;
     84    procedure GetByKind(Kind: TBrainType; Brains: TBrains);
    6785  end;
    6886
     
    7593  // READ ONLY
    7694  DotNetClient: TClientCall;
    77   bixBeginner, // AI to use for beginner level
    78   nBrain: integer; { number of brains available }
    79   Brain: array [-1 .. maxBrain - 1] of TBrainInfo; { available brains }
     95  Brains: TBrains; // { available brains }
    8096  NotifyMessage: string;
     97
     98  BrainNoTerm: TBrain;
     99  BrainSuperVirtual: TBrain;
     100  BrainTerm: TBrain;
     101  BrainRandom: TBrain;
     102  BrainBeginner: TBrain; // AI to use for beginner level
    81103
    82104procedure Init(NotifyFunction: TNotifyFunction);
     
    145167    HandoverStack[nHandoverStack + 1] := Command;
    146168    inc(nHandoverStack, 2);
    147     Brain[bix[p]].Client(Command, p, Data);
     169    Brains[bix[p]].Client(Command, p, Data);
    148170    dec(nHandoverStack, 2);
    149171{$ELSE}
     
    165187    HandoverStack[nHandoverStack + 1] := Command;
    166188    inc(nHandoverStack, 2);
    167     Brain[bix].Client(Command, -1, Data);
     189    Brains[bix].Client(Command, -1, Data);
    168190    dec(nHandoverStack, 2);
    169191{$ELSE}
     
    179201procedure Init(NotifyFunction: TNotifyFunction);
    180202var
    181   i: integer;
    182203  f: TSearchRec;
    183   T: TextFile;
    184   s: string;
    185   Key: string;
    186   Value: string;
    187204  BasePath: string;
    188   AIFileName: string;
     205  NewBrain: TBrain;
    189206begin
    190207  Notify := NotifyFunction;
     
    192209
    193210  { get available brains }
    194   Brain[bixNoTerm].FileName := ':AIT';
    195   Brain[bixNoTerm].Flags := 0;
    196   Brain[bixNoTerm].Initialized := false;
    197   Brain[bixSuper_Virtual].FileName := ':Supervisor';
    198   Brain[bixSuper_Virtual].Flags := 0;
    199   Brain[bixSuper_Virtual].Initialized := false;
    200   Brain[bixTerm].FileName := ':StdIntf';
    201   Brain[bixTerm].Flags := fMultiple;
    202   Brain[bixTerm].Initialized := false;
    203   Brain[bixTerm].ServerVersion := Version;
    204   Brain[bixRandom].FileName := ':Random';
    205   Brain[bixRandom].Flags := fMultiple;
    206   Brain[bixRandom].Initialized := false;
    207   nBrain := bixFirstAI;
    208   bixBeginner := bixFirstAI;
     211  Brains := TBrains.Create;
     212  BrainNoTerm := Brains.AddNew;
     213  BrainNoTerm.FileName := ':AIT';
     214  BrainNoTerm.Flags := 0;
     215  BrainNoTerm.Initialized := false;
     216  BrainNoTerm.Kind := btNoTerm;
     217  BrainSuperVirtual := Brains.AddNew;
     218  BrainSuperVirtual.FileName := ':Supervisor';
     219  BrainSuperVirtual.Flags := 0;
     220  BrainSuperVirtual.Initialized := false;
     221  BrainSuperVirtual.Kind := btSuperVirtual;
     222  BrainTerm := Brains.AddNew;
     223  BrainTerm.FileName := ':StdIntf';
     224  BrainTerm.Flags := fMultiple;
     225  BrainTerm.Initialized := false;
     226  BrainTerm.ServerVersion := Version;
     227  BrainTerm.Kind := btTerm;
     228  BrainRandom := Brains.AddNew;
     229  BrainRandom.FileName := ':Random';
     230  BrainRandom.Flags := fMultiple;
     231  BrainRandom.Initialized := false;
     232  BrainRandom.Kind := btRandom;
     233
     234  BrainBeginner := nil;
     235
    209236  if FindFirst(HomeDir + 'AI' + DirectorySeparator + '*', faDirectory or faArchive or faReadOnly, f) = 0 then
    210237  repeat
    211238    BasePath := HomeDir + 'AI' + DirectorySeparator + f.Name;
    212239    if (f.Name <> '.') and (f.Name <> '..') and DirectoryExists(BasePath) then begin
    213       with Brain[nBrain] do begin
    214         FileName := f.Name;
    215         DLLName := BasePath + DirectorySeparator + FileName + '.dll';
    216         AIFileName := BasePath + DirectorySeparator + f.Name + '.ai.txt';
    217         Name := f.Name;
    218         Credits := '';
    219         Flags := fMultiple;
    220         Client := nil;
    221         Initialized := false;
    222         ServerVersion := 0;
    223         if not FileExists(AIFileName) then
    224           raise Exception.Create(Format('AI specification file %s not found', [AIFileName]));
    225         AssignFile(T, AIFileName);
    226         Reset(T);
    227         while not EOF(T) do
    228         begin
    229           ReadLn(T, s);
    230           s := trim(s);
    231           if Pos(' ', S) > 0 then begin
    232             Key := Copy(S, 1, Pos(' ', S) - 1);
    233             Value := Trim(Copy(S, Pos(' ', S) + 1, Length(S)));
    234           end else begin
    235             Key := S;
    236             Value := '';
    237           end;
    238           if Key = '#NAME' then
    239             Name := Value
    240           else if Key = '#.NET' then
    241             Flags := Flags or fDotNet
    242           else if Key = '#BEGINNER' then
    243             bixBeginner := nBrain
    244           else if Key = '#PATH' then
    245             DLLName := BasePath + DirectorySeparator + Value
    246           {$IFDEF WINDOWS}{$IFDEF CPU32}
    247           else if Key = '#PATH_WIN32' then
    248             DLLName := BasePath + DirectorySeparator + Value
    249           {$ENDIF}{$ENDIF}
    250           {$IFDEF WINDOWS}{$IFDEF CPU64}
    251           else if Key = '#PATH_WIN64' then
    252             DLLName := BasePath + DirectorySeparator + Value
    253           {$ENDIF}{$ENDIF}
    254           {$IFDEF LINUX}{$IFDEF CPU32}
    255           else if Key = '#PATH_LINUX32' then
    256             DLLName := BasePath + DirectorySeparator + Value
    257           {$ENDIF}{$ENDIF}
    258           {$IFDEF LINUX}{$IFDEF CPU64}
    259           else if Key = '#PATH_LINUX64' then
    260             DLLName := BasePath + DirectorySeparator + Value
    261           {$ENDIF}{$ENDIF}
    262           else if Key = '#GAMEVERSION' then
    263             for i := 1 to Length(Value) do
    264               case Value[i] of
    265                 '0' .. '9':
    266                   ServerVersion := ServerVersion and $FFFF00 + ServerVersion and
    267                     $FF * 10 + ord(Value[i]) - 48;
    268                 '.':
    269                   ServerVersion := ServerVersion shl 8;
    270               end
    271           else if Key = '#CREDITS' then
    272             Credits := Value
    273         end;
    274         CloseFile(T);
    275       end;
    276       if (Brain[nBrain].ServerVersion >= FirstAICompatibleVersion) and
    277         (Brain[nBrain].ServerVersion <= Version) and
    278         ((Brain[nBrain].Flags and fDotNet = 0) or (@DotNetClient <> nil)) then
    279         inc(nBrain);
     240      NewBrain := Brains.AddNew;
     241      NewBrain.Kind := btAI;
     242      NewBrain.LoadFromFile(BasePath + DirectorySeparator + F.Name + '.ai.txt');
     243      if (NewBrain.ServerVersion >= FirstAICompatibleVersion) and
     244        (NewBrain.ServerVersion <= Version) and
     245        ((NewBrain.Flags and fDotNet = 0) or (@DotNetClient <> nil)) then begin
     246        end else Brains.Delete(Brains.Count - 1);
    280247    end;
    281248  until FindNext(f) <> 0;
    282249  FindClose(F);
    283250
    284   if nBrain = 0 then
     251  if Brains.GetKindCount(btAI) = 0 then
    285252    raise Exception.Create(Format('No AI libraries found in directory %s', [HomeDir + 'AI']));
    286253end;
     
    288255procedure Done;
    289256var
    290   i: integer;
     257  I: Integer;
    291258begin
    292   for i := 0 to nBrain - 1 do
    293     if Brain[i].Initialized then
    294     begin
    295       CallClient(i, cReleaseModule, nil^);
    296       if (i >= bixFirstAI) and (Brain[i].Flags and fDotNet = 0) then
    297         FreeLibrary(Brain[i].hm);
     259  for I := 0 to Brains.Count - 1 do
     260  with Brains[I] do
     261    if Initialized then begin
     262      CallClient(I, cReleaseModule, nil^);
     263      if (Kind = btAI) and ((Flags and fDotNet) = 0) then
     264        FreeLibrary(hm);
    298265    end;
     266  Brains.Free;
    299267end;
    300268
     
    327295procedure PutMessage(Level: integer; Text: string);
    328296begin
    329   Brain[bix[0]].Client(cDebugMessage, Level, pchar(Text)^);
     297  Brains[bix[0]].Client(cDebugMessage, Level, pchar(Text)^);
    330298end;
    331299
     
    362330  LastClientTime := T;
    363331  PutMessage(1 shl 16 + 2, Format('CLIENT: calling %d (%s)',
    364     [CCPlayer, Brain[bix[CCPlayer]].Name]));
     332    [CCPlayer, Brains[bix[CCPlayer]].Name]));
    365333  if CCCommand = cTurn then
    366334    for p := 0 to nPl - 1 do
     
    371339  CCPlayer := -1;
    372340  CallPlayer(CCCommand, p, CCData);
    373   if (Mode = moPlaying) and (Brain[bix[p]].Flags and aiThreaded = 0) and
     341  if (Mode = moPlaying) and (Brains[bix[p]].Flags and aiThreaded = 0) and
    374342    (CCPlayer < 0) then
    375343  begin
     
    449417          end;
    450418      // log data changes
    451       if Brain[bix[p]].DataSize > 0 then
     419      if Brains[bix[p]].DataSize > 0 then
    452420      begin
    453421        CL.PutDataChanges(sIntDataChange, p, SavedData[p], RW[p].Data,
    454           Brain[bix[p]].DataSize);
    455         move(RW[p].Data^, SavedData[p]^, Brain[bix[p]].DataSize * 4);
     422          Brains[bix[p]].DataSize);
     423        move(RW[p].Data^, SavedData[p]^, Brains[bix[p]].DataSize * 4);
    456424      end
    457425    end;
     
    477445        with RW[p].EnemyCity[ix] do
    478446          SavedStatus := Status;
    479       if Brain[bix[p]].DataSize > 0 then
    480         move(RW[p].Data^, SavedData[p]^, Brain[bix[p]].DataSize * 4);
     447      if Brains[bix[p]].DataSize > 0 then
     448        move(RW[p].Data^, SavedData[p]^, Brains[bix[p]].DataSize * 4);
    481449    end;
    482450end;
     
    507475        result := true;
    508476  if RW[p].Data <> nil then
    509     for ix := 0 to Brain[bix[p]].DataSize - 1 do
     477    for ix := 0 to Brains[bix[p]].DataSize - 1 do
    510478      if PDWortList(SavedData[p])[ix] <> PDWortList(RW[p].Data)[ix] then
    511479        result := true
     
    516484  InitModuleData: TInitModuleData;
    517485begin
    518   assert(bix <> bixSuper_Virtual);
    519   with Brain[bix] do
    520   begin
     486  assert(Brains[bix].Kind <> btSuperVirtual);
     487  with Brains[bix] do begin
    521488    if Initialized then
    522489      exit;
    523     if bix >= bixFirstAI then
     490    if Kind = btAI then
    524491    begin { get client function }
    525492      Notify(ntInitModule + bix);
     
    635602  nLocal := 0;
    636603  for i := 0 to nPl - 1 do
    637     if bix[i] = bixTerm then
     604    if (bix[i] <> -1) and (Brains[bix[i]].Kind = btTerm) then
    638605      inc(nLocal);
    639606  if Difficulty[0] = 0 then
     
    683650    else
    684651    begin
    685       if bixView[i] >= bixRandom then
    686         s := Brain[bix[i]].FileName
    687       else
    688         s := Brain[bixView[i]].FileName;
     652      if Brains[bixView[i]].Kind in [btRandom, btAI] then
     653        s := Brains[bix[i]].FileName
     654      else
     655        s := Brains[bixView[i]].FileName;
    689656      move(zero, s[Length(s) + 1], 4);
    690657      LogFile.write(s, (Length(s) div 4 + 1) * 4);
     
    715682  Path: shortstring;
    716683  BrainUsed: Set of 0 .. 254; { used brains }
     684  AIBrains: TBrains;
    717685begin
    718   for p1 := 0 to nPl - 1 do
    719   begin
    720     if bixView[p1] = bixSuper_Virtual then
    721       bix[p1] := bixTerm // supervisor and local human use same module
    722     else if bixView[p1] = bixRandom then
    723       if nBrain <= bixFirstAI then
     686  for p1 := 0 to nPl - 1 do begin
     687    if (bixView[p1] <> -1) and (Brains[bixView[p1]].Kind = btSuperVirtual) then
     688      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
     690      if Brains.GetKindCount(btAI) = 0 then
    724691        bix[p1] := -1
    725       else
    726         bix[p1] := bixFirstAI + Delphirandom(nBrain - bixFirstAI)
     692      else begin
     693        AIBrains := TBrains.Create(False);
     694        bix[p1] := Brains.IndexOf(AIBrains[DelphiRandom(AIBrains.Count)]);
     695        AIBrains.Free;
     696      end
    727697    else
    728698      bix[p1] := bixView[p1];
     
    731701  end;
    732702
    733   if bix[0] <> bixNoTerm then
     703  if Brains[bix[0]].Kind <> btNoTerm then
    734704    Notify(ntInitLocalHuman);
    735705  BrainUsed := [];
     
    737707    if (bix[p] >= 0) and ((Mode <> moMovie) or (p = 0)) then
    738708    begin { initiate selected control module }
    739       AIInfo[p] := Brain[bix[p]].Name + #0;
     709      AIInfo[p] := Brains[bix[p]].Name + #0;
    740710      InitBrain(bix[p]);
    741711      if Mode = moPlaying then
    742712      begin // new game, this data version is original
    743         OriginalDataVersion[p] := Brain[bix[p]].DataVersion;
     713        OriginalDataVersion[p] := Brains[bix[p]].DataVersion;
    744714        ProcessClientData[p] := true;
    745715      end
    746716      else // loading game, compare with data version read from file
    747717        ProcessClientData[p] := ProcessClientData[p] and
    748           (OriginalDataVersion[p] = Brain[bix[p]].DataVersion);
    749       if @Brain[bix[p]].Client = nil then // client function not found
    750         if bix[0] = bixNoTerm then
     718          (OriginalDataVersion[p] = Brains[bix[p]].DataVersion);
     719      if @Brains[bix[p]].Client = nil then // client function not found
     720        if Brains[bix[0]].Kind = btNoTerm then
    751721          bix[p] := -1
    752722        else
    753723        begin
    754           bix[p] := bixTerm;
     724          bix[p] := Brains.IndexOf(BrainTerm);
    755725          OriginalDataVersion[p] := -1;
    756726          ProcessClientData[p] := false;
     
    773743      if Mode <> moMovie then
    774744        inc(GWatching, 1 shl p1);
    775       if bix[p1] >= bixFirstAI then
     745      if Brains[bix[p1]].Kind = btAI then
    776746        inc(GAI, 1 shl p1);
    777747      if Difficulty[p1] > 0 then
     
    780750        inc(nAlive);
    781751      end;
    782       ServerVersion[p1] := Brain[bix[p1]].ServerVersion;
     752      ServerVersion[p1] := Brains[bix[p1]].ServerVersion;
    783753    end;
    784   WinOnAlone := (bix[0] = bixNoTerm) and (nAlive > 1);
     754  WinOnAlone := (Brains[bix[0]].Kind = btNoTerm) and (nAlive > 1);
    785755  GWinner := 0;
    786756  GColdWarStart := -ColdWarTurns - 1;
     
    817787        OracleIncome := 0;
    818788
    819         if Brain[bix[p]].DataSize > 0 then
     789        if Brains[bix[p]].DataSize > 0 then
    820790        begin
    821           GetMem(SavedData[p], Brain[bix[p]].DataSize * 4);
    822           GetMem(Data, Brain[bix[p]].DataSize * 4);
    823           FillChar(SavedData[p]^, Brain[bix[p]].DataSize * 4, 0);
    824           FillChar(Data^, Brain[bix[p]].DataSize * 4, 0);
     791          GetMem(SavedData[p], Brains[bix[p]].DataSize * 4);
     792          GetMem(Data, Brains[bix[p]].DataSize * 4);
     793          FillChar(SavedData[p]^, Brains[bix[p]].DataSize * 4, 0);
     794          FillChar(Data^, Brains[bix[p]].DataSize * 4, 0);
    825795        end
    826796        else
     
    839809        for i := 0 to nStat - 1 do
    840810          GetMem(Stat[i, p], 4 * (MaxTurn + 1));
    841         if Brain[bix[p]].Flags and fDotNet <> 0 then
     811        if Brains[bix[p]].Flags and fDotNet <> 0 then
    842812        begin
    843813          GetMem(RW[p].DefaultDebugMap, MapSize * 4);
     
    865835    Human := 0;
    866836    for p1 := 0 to nPl - 1 do
    867       if bix[p1] = bixTerm then
     837      if Brains[bix[p1]].Kind = btTerm then
    868838        inc(Human, 1 shl p1);
    869839    InitMapGame(Human);
     
    876846
    877847  pTurn := -1;
    878   if bix[0] <> bixNoTerm then
     848  if Brains[bix[0]].Kind <> btNoTerm then
    879849    Notify(ntInitLocalHuman);
    880850  Game.lx := lx;
     
    887857  // move(Difficulty,GameEx.Difficulty,SizeOf(Difficulty));
    888858  AICredits := '';
    889   for i := 0 to nBrain - 1 do
    890     if Brain[i].Initialized then
     859  for i := 0 to Brains.Count - 1 do
     860  with Brains[I] do begin
     861    if Initialized then
    891862      if i in BrainUsed then
    892863      begin
    893         if i >= bixFirstAI then
     864        if Kind = btAI then
    894865          Notify(ntInitPlayers);
    895866        for p := 0 to nPl - 1 do
     
    899870          else
    900871            Game.RO[p] := nil;
    901           if (i = bixTerm) and (Difficulty[0] = 0) and (bix[p] >= 0) then
     872          if (Kind = btTerm) and (Difficulty[0] = 0) and (bix[p] >= 0) then
    902873            Game.SuperVisorRO[p] := @RW[p]
    903874          else
    904875            Game.SuperVisorRO[p] := nil;
    905876        end;
    906         if Brain[i].Flags and fDotNet > 0 then
     877        if Flags and fDotNet > 0 then
    907878        begin
    908           Path := Brain[i].DLLName;
     879          Path := DLLName;
    909880          move(Path[1], Game.AssemblyPath, Length(Path));
    910881          Game.AssemblyPath[Length(Path)] := #0;
     
    920891            CallClient(i, cNewGame, Game);
    921892        end;
    922         if (i >= bixFirstAI) and (Brain[i].Credits <> '') then
     893        if (Kind = btAI) and (Credits <> '') then
    923894          if AICredits = '' then
    924             AICredits := Brain[i].Credits
     895            AICredits := Credits
    925896          else
    926             AICredits := AICredits + '\' + Brain[i].Credits
     897            AICredits := AICredits + '\' + Credits;
    927898      end
    928899      else
    929900      begin { module no longer used -- unload }
    930901        CallClient(i, cReleaseModule, nil^);
    931         if i >= bixFirstAI then
     902        if Kind = btAI then
    932903        begin
    933           if Brain[i].Flags and fDotNet = 0 then
    934             FreeLibrary(Brain[i].hm);
    935           Brain[i].Client := nil;
     904          if Flags and fDotNet = 0 then
     905            FreeLibrary(hm);
     906          Client := nil;
    936907        end;
    937         Brain[i].Initialized := false;
    938       end;
     908        Initialized := false;
     909      end;
     910  end;
    939911  AICredits := AICredits + #0;
    940912
    941   if bix[0] <> bixNoTerm then
     913  if Brains[bix[0]].Kind <> btNoTerm then
    942914  begin
    943915    // uni ai?
    944916    bixUni := -1;
    945917    for p1 := 0 to nPl - 1 do
    946       if bix[p1] >= bixFirstAI then
     918      if (bix[p1] <> - 1) and (Brains[bix[p1]].Kind = btAI) then
    947919        if bixUni = -1 then
    948920          bixUni := bix[p1]
     
    950922          bixUni := -2;
    951923    for p1 := 0 to nPl - 1 do
    952       if bix[p1] >= bixFirstAI then
     924      if (bix[p1] <> -1) and (Brains[bix[p1]].Kind = btAI) then
    953925      begin
    954926        if bixUni = -2 then
    955           NotifyMessage := Brain[bix[p1]].FileName
     927          NotifyMessage := Brains[bix[p1]].FileName
    956928        else
    957929          NotifyMessage := '';
     
    11591131        LogFile.read(d, 4); { behavior }
    11601132        LogFile.read(Difficulty[p1], 4);
    1161         j := nBrain - 1;
    1162         while (j >= 0) and (AnsiCompareFileName(Brain[j].FileName, s) <> 0) do
     1133        j := Brains.Count - 1;
     1134        while (j >= 0) and (AnsiCompareFileName(Brains[j].FileName, s) <> 0) do
    11631135          dec(j);
    11641136        if j < 0 then
     
    11671139          NotifyMessage := s;
    11681140          Notify(ntAIError);
    1169           j := bixTerm;
     1141          j := Brains.IndexOf(BrainTerm);
    11701142        end
    11711143        else
    11721144          ProcessClientData[p1] := true;
    1173         if j = bixNoTerm then
    1174           j := bixSuper_Virtual;
     1145        if Brains[j].Kind = btNoTerm then
     1146          j := Brains.IndexOf(BrainSuperVirtual);
    11751147        // crashed tournament -- load as supervisor
    11761148        bixView[p1] := j;
     
    12051177  if MovieMode then
    12061178  begin
    1207     Brain[bix[0]].Client(cShowGame, 0, nil^);
     1179    Brains[bix[0]].Client(cShowGame, 0, nil^);
    12081180    Notify(ntBackOff);
    12091181  end
     
    12571229{$IFDEF TEXTLOG}LoadPos0 := CL.State.LoadPos; {$ENDIF}
    12581230      if ProcessClientData[p1] then
    1259         CL.GetDataChanges(RW[p1].Data, Brain[bix[p1]].DataSize)
     1231        CL.GetDataChanges(RW[p1].Data, Brains[bix[p1]].DataSize)
    12601232      else
    12611233        CL.GetDataChanges(nil, 0);
     
    12811253  begin
    12821254    Notify(ntBackOn);
    1283     Brain[bix[0]].Client(cBreakGame, -1, nil^);
     1255    Brains[bix[0]].Client(cBreakGame, -1, nil^);
    12841256    EndGame;
    12851257    Notify(ntStartGo);
     
    13261298    Notify(ntLoadError);
    13271299  end;
    1328   Brain[bix[0]].Client(cShowGame, 0, nil^);
     1300  Brains[bix[0]].Client(cShowGame, 0, nil^);
    13291301  Notify(ntBackOff);
    13301302  Inform(pTurn);
     
    13971369  nLogOpened := -1;
    13981370  LastEndClientCommand := -1;
    1399   Brain[bix[0]].Client(cShowGame, 0, nil^);
     1371  Brains[bix[0]].Client(cShowGame, 0, nil^);
    14001372  Notify(ntBackOff);
    14011373  Inform(pTurn);
     
    14051377procedure DirectHelp(Command: integer);
    14061378begin
    1407   InitBrain(bixTerm);
    1408   Brain[bixTerm].Client(Command, -1, nil^);
     1379  InitBrain(Brains.IndexOf(BrainTerm));
     1380  BrainTerm.Client(Command, -1, nil^);
    14091381  AICredits := #0;
    14101382end;
     
    14221394  MapSize := lx * ly;
    14231395  LandMass := NewLandMass;
    1424   bix[0] := bixTerm;
     1396  bix[0] := Brains.IndexOf(BrainTerm);
    14251397  Difficulty[0] := 0;
    1426   InitBrain(bixTerm);
     1398  InitBrain(Brains.IndexOf(BrainTerm));
    14271399
    14281400  DelphiRandomize;
     
    14461418    Game.Difficulty[p1] := -1
    14471419  end;
    1448   Brain[bixTerm].Client(cNewMap, -1, Game);
     1420  BrainTerm.Client(cNewMap, -1, Game);
    14491421
    14501422  DiscoverAll(0, lObserveSuper);
    14511423  Notify(ntEndInfo);
    1452   Brain[bix[0]].Client(cShowGame, 0, nil^);
     1424  Brains[bix[0]].Client(cShowGame, 0, nil^);
    14531425  Notify(ntBackOff);
    14541426  ChangeClientWhenDone(cEditMap, 0, nil^, 0)
     
    19051877    then { supervisor - all tiles visible }
    19061878    begin
    1907       if (bix[pTurn] <> bixNoTerm) and
     1879      if (Brains[bix[pTurn]].Kind <> btNoTerm) and
    19081880        ((Difficulty[pTurn] > 0) or (Mode > moLoading_Fast)) then
    19091881        DiscoverAll(pTurn, lObserveSuper)
     
    21022074          ShowMove.Flags := ShowMove.Flags or umShipLoading;
    21032075      for p1 := 0 to nPl - 1 do
    2104         if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm))
     2076        if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (Brains[bix[p1]].Kind = btTerm))
    21052077        then
    21062078        begin
     
    22732245    if Mode >= moMovie then { show after-move in interface modules }
    22742246      for p1 := 0 to nPl - 1 do
    2275         if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm))
     2247        if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (Brains[bix[p1]].Kind = btTerm))
    22762248        then
    22772249        begin
     
    23812353    if Mode >= moMovie then { show attack in interface modules }
    23822354      for p1 := 0 to nPl - 1 do
    2383         if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm))
     2355        if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (Brains[bix[p1]].Kind = btTerm))
    23842356        then
    23852357        begin
     
    25432515          Lost := Destroyed[p, Owner, mix];
    25442516      for p1 := 0 to nPl - 1 do { show after-attack in interface modules }
    2545         if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm))
     2517        if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (Brains[bix[p1]].Kind = btTerm))
    25462518        then
    25472519        begin
     
    28072779    }
    28082780    sMessage:
    2809       Brain[bix[0]].Client(cDebugMessage, Subject, Data);
     2781      Brains[bix[0]].Client(cDebugMessage, Subject, Data);
    28102782
    28112783    sSetDebugMap:
     
    28242796
    28252797    sRefreshDebugMap:
    2826       Brain[bix[0]].Client(cRefreshDebugMap, -1, Player);
     2798      Brains[bix[0]].Client(cRefreshDebugMap, -1, Player);
    28272799
    28282800    sGetChart .. sGetChart + (nStat - 1) shl 4:
     
    31213093        AllHumansDead := true;
    31223094        for p1 := 0 to nPl - 1 do
    3123           if (1 shl p1 and GAlive <> 0) and (bix[p1] = bixTerm) then
     3095          if (1 shl p1 and GAlive <> 0) and (Brains[bix[p1]].Kind = btTerm) then
    31243096            AllHumansDead := false;
    31253097        if (pDipActive >= 0) // still in negotiation mode
     
    32383210        if Command = sReload then
    32393211        begin
    3240           ok := (Difficulty[0] = 0) and (bix[0] <> bixNoTerm) and
     3212          ok := (Difficulty[0] = 0) and (Brains[bix[0]].Kind <> btNoTerm) and
    32413213            (integer(Data) >= 0) and (integer(Data) < GTurn);
    32423214          for p1 := 1 to nPl - 1 do
    3243             if bix[p1] = bixTerm then
     3215            if Brains[bix[p1]].Kind = btTerm then
    32443216              ok := false;
    32453217          // allow reload in AI-only games only
     
    32513223          if (Command = sBreak) or (Command = sResign) then
    32523224            Notify(ntBackOn);
    3253           for i := 0 to nBrain - 1 do
    3254             if Brain[i].Initialized then
     3225          for i := 0 to Brains.Count - 1 do
     3226            if Brains[i].Initialized then
    32553227            begin
    3256               if i >= bixFirstAI then
     3228              if Brains[i].Kind = btAI then
    32573229                Notify(ntDeinitModule + i);
    32583230              CallClient(i, cBreakGame, nil^);
     
    32893261          SaveMap(MapFileName);
    32903262        Notify(ntBackOn);
    3291         Brain[bixTerm].Client(cBreakGame, -1, nil^);
     3263        BrainTerm.Client(cBreakGame, -1, nil^);
    32923264        ReleaseMapEditor;
    32933265        if Command = sSaveMap then
     
    34693441                pTarget := p1;
    34703442                Action := Command;
    3471                 Brain[bix[0]].Client(cShowNego, 1 shl 16 + 3, ShowNegoData);
     3443                Brains[bix[0]].Client(cShowNego, 1 shl 16 + 3, ShowNegoData);
    34723444              end;
    34733445            pDipActive := p1;
     
    35703542                  Action := Command;
    35713543                  Offer := TOffer(Data);
    3572                   Brain[bix[0]].Client(cShowNego, 1 shl 16 + 3, ShowNegoData);
     3544                  Brains[bix[0]].Client(cShowNego, 1 shl 16 + 3, ShowNegoData);
    35733545                end;
    35743546              LastOffer := TOffer(Data);
     
    45074479end; { <<<server }
    45084480
     4481{ TBrain }
     4482
     4483procedure TBrain.LoadFromFile(AIFileName: string);
     4484var
     4485  T: Text;
     4486  Key: string;
     4487  Value: string;
     4488  S: string;
     4489  BasePath: string;
     4490  I: Integer;
     4491begin
     4492  BasePath := ExtractFileDir(AIFileName);
     4493  FileName := ExtractFileName(ExtractFileNameWithoutExt(ExtractFileNameWithoutExt(AIFileName)));
     4494  Name := FileName;
     4495  DLLName := BasePath + DirectorySeparator + Name + '.dll';
     4496  Credits := '';
     4497  Flags := fMultiple;
     4498  Client := nil;
     4499  Initialized := false;
     4500  ServerVersion := 0;
     4501  if not FileExists(AIFileName) then
     4502    raise Exception.Create(Format('AI specification file %s not found', [AIFileName]));
     4503  AssignFile(T, AIFileName);
     4504  Reset(T);
     4505  while not EOF(T) do
     4506  begin
     4507    ReadLn(T, s);
     4508    s := trim(s);
     4509    if Pos(' ', S) > 0 then begin
     4510      Key := Copy(S, 1, Pos(' ', S) - 1);
     4511      Value := Trim(Copy(S, Pos(' ', S) + 1, Length(S)));
     4512    end else begin
     4513      Key := S;
     4514      Value := '';
     4515    end;
     4516    if Key = '#NAME' then
     4517      Name := Value
     4518    else if Key = '#.NET' then
     4519      Flags := Flags or fDotNet
     4520    else if Key = '#BEGINNER' then
     4521      BrainBeginner := Self
     4522    else if Key = '#PATH' then
     4523      DLLName := BasePath + DirectorySeparator + Value
     4524    {$IFDEF WINDOWS}{$IFDEF CPU32}
     4525    else if Key = '#PATH_WIN32' then
     4526      DLLName := BasePath + DirectorySeparator + Value
     4527    {$ENDIF}{$ENDIF}
     4528    {$IFDEF WINDOWS}{$IFDEF CPU64}
     4529    else if Key = '#PATH_WIN64' then
     4530      DLLName := BasePath + DirectorySeparator + Value
     4531    {$ENDIF}{$ENDIF}
     4532    {$IFDEF LINUX}{$IFDEF CPU32}
     4533    else if Key = '#PATH_LINUX32' then
     4534      DLLName := BasePath + DirectorySeparator + Value
     4535    {$ENDIF}{$ENDIF}
     4536    {$IFDEF LINUX}{$IFDEF CPU64}
     4537    else if Key = '#PATH_LINUX64' then
     4538      DLLName := BasePath + DirectorySeparator + Value
     4539    {$ENDIF}{$ENDIF}
     4540    else if Key = '#GAMEVERSION' then
     4541      for i := 1 to Length(Value) do
     4542        case Value[i] of
     4543          '0' .. '9':
     4544            ServerVersion := ServerVersion and $FFFF00 + ServerVersion and
     4545              $FF * 10 + ord(Value[i]) - 48;
     4546          '.':
     4547          ServerVersion := ServerVersion shl 8;
     4548      end
     4549    else if Key = '#CREDITS' then
     4550      Credits := Value;
     4551  end;
     4552  CloseFile(T);
     4553end;
     4554
     4555constructor TBrain.Create;
     4556begin
     4557  Picture := nil;
     4558end;
     4559
     4560destructor TBrain.Destroy;
     4561begin
     4562  if Assigned(Picture) then Picture.Free;
     4563  inherited Destroy;
     4564end;
     4565
     4566{ TBrains }
     4567
     4568function TBrains.AddNew: TBrain;
     4569begin
     4570  Result := TBrain.Create;
     4571  Add(Result);
     4572end;
     4573
     4574function TBrains.GetKindCount(Kind: TBrainType): Integer;
     4575var
     4576  I: Integer;
     4577begin
     4578  Result := 0;
     4579  for I := 0 to Count - 1 do
     4580    if Items[I].Kind = Kind then Inc(Result);
     4581end;
     4582
     4583procedure TBrains.GetByKind(Kind: TBrainType; Brains: TBrains);
     4584var
     4585  I: Integer;
     4586begin
     4587  Brains.Clear;
     4588  for I := 0 to Count - 1 do
     4589    if Items[I].Kind = Kind then Brains.Add(Items[I]);
     4590end;
     4591
    45094592initialization
    45104593
Note: See TracChangeset for help on using the changeset viewer.