Changeset 6 for trunk/GameServer.pas
- Timestamp:
- Jan 7, 2017, 11:32:14 AM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/GameServer.pas
r2 r6 1 1 {$INCLUDE switches} 2 // {$DEFINE TEXTLOG}3 // {$DEFINE LOADPERF}2 // {$DEFINE TEXTLOG} 3 // {$DEFINE LOADPERF} 4 4 unit GameServer; 5 5 … … 7 7 8 8 uses 9 Protocol, Database;9 Protocol, Database; 10 10 11 11 const 12 Version=$010200; 13 FirstAICompatibleVersion=$000D00; 14 FirstBookCompatibleVersion=$010103; 15 16 // notifications 17 ntCreateWorld=0; ntInitModule=$100; ntInitLocalHuman=$1FF; 18 ntDLLError=$200; ntAIError=$2FF; 19 ntClientError=$300; 20 ntInitPlayers=$400; ntDeactivationMissing=$410; 21 ntSetAIName=$420; 22 ntException=$500; 23 ntLoadBegin=$600; ntLoadState=$601; 24 ntEndInfo=$6FC; ntBackOn=$6FD; ntBackOff=$6FE; ntLoadError=$6FF; 25 ntStartDone=$700; ntStartGo=$701; ntStartGoRefresh=$702; 26 ntStartGoRefreshMaps=$703; 27 ntChangeClient=$800; ntNextPlayer=$810; 28 ntDeinitModule=$900; 29 30 // module flags 31 fMultiple=$10000000; fDotNet=$20000000; fUsed=$40000000; 32 33 // save map tile flags 34 smOwned=$20; smUnit=$40; smCity=$80; 35 36 maxBrain=255; 37 bixNoTerm=0; bixSuper_Virtual=1; bixTerm=2; bixRandom=3; bixFirstAI=4; 12 Version = $010200; 13 FirstAICompatibleVersion = $000D00; 14 FirstBookCompatibleVersion = $010103; 15 16 // notifications 17 ntCreateWorld = 0; 18 ntInitModule = $100; 19 ntInitLocalHuman = $1FF; 20 ntDLLError = $200; 21 ntAIError = $2FF; 22 ntClientError = $300; 23 ntInitPlayers = $400; 24 ntDeactivationMissing = $410; 25 ntSetAIName = $420; 26 ntException = $500; 27 ntLoadBegin = $600; 28 ntLoadState = $601; 29 ntEndInfo = $6FC; 30 ntBackOn = $6FD; 31 ntBackOff = $6FE; 32 ntLoadError = $6FF; 33 ntStartDone = $700; 34 ntStartGo = $701; 35 ntStartGoRefresh = $702; 36 ntStartGoRefreshMaps = $703; 37 ntChangeClient = $800; 38 ntNextPlayer = $810; 39 ntDeinitModule = $900; 40 41 // module flags 42 fMultiple = $10000000; 43 fDotNet = $20000000; 44 fUsed = $40000000; 45 46 // save map tile flags 47 smOwned = $20; 48 smUnit = $40; 49 smCity = $80; 50 51 maxBrain = 255; 52 bixNoTerm = 0; 53 bixSuper_Virtual = 1; 54 bixTerm = 2; 55 bixRandom = 3; 56 bixFirstAI = 4; 38 57 39 58 type 40 TNotifyFunction = procedure(ID: integer); 41 42 TBrainInfo= record 43 FileName, DLLName, Name, Credits: string; {filename and full name} 44 hm, {module handle} 45 Flags, 46 ServerVersion, 47 DataVersion, DataSize: integer; 48 Client: TClientCall; {client function address} 49 Initialized: boolean; 59 TNotifyFunction = procedure(ID: integer); 60 61 TBrainInfo = record 62 FileName, DLLName, Name, Credits: string; { filename and full name } 63 hm, { module handle } 64 Flags, ServerVersion, DataVersion, DataSize: integer; 65 Client: TClientCall; { client function address } 66 Initialized: boolean; 50 67 end; 51 68 52 69 var 53 // PARAMETERS 54 bixView: array[0..nPl-1]of integer; {brain index of the players} 55 Difficulty: array[0..nPl-1]of integer absolute Database.Difficulty; {difficulty} 56 57 // READ ONLY 58 DotNetClient: TClientCall; 59 bixBeginner, // AI to use for beginner level 60 nBrain: integer; {number of brains available} 61 Brain: array[-1..maxBrain-1] of TBrainInfo; {available brains} 62 NotifyMessage: string; 70 // PARAMETERS 71 bixView: array [0 .. nPl - 1] of integer; { brain index of the players } 72 Difficulty: array [0 .. nPl - 1] of integer absolute Database.Difficulty; 73 { difficulty } 74 75 // READ ONLY 76 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 } 80 NotifyMessage: string; 63 81 64 82 procedure Init(NotifyFunction: TNotifyFunction); 65 83 procedure Done; 66 84 67 procedure StartNewGame(const Path, FileName, Map: string; Newlx, Newly, 68 NewLandMass, NewMaxTurn: integer); 69 function LoadGame(const Path, FileName: string; Turn: integer; MovieMode: boolean): boolean; 85 procedure StartNewGame(const Path, FileName, Map: string; 86 Newlx, Newly, NewLandMass, NewMaxTurn: integer); 87 function LoadGame(const Path, FileName: string; Turn: integer; 88 MovieMode: boolean): boolean; 70 89 procedure EditMap(const Map: string; Newlx, Newly, NewLandMass: integer); 71 90 procedure DirectHelp(Command: integer); … … 75 94 function PreviewMap(lm: integer): pointer; 76 95 77 78 96 implementation 79 97 80 98 uses 81 Directories, CityProcessing, UnitProcessing, CmdList, 82 83 Windows,Classes,SysUtils; 84 99 Directories, CityProcessing, UnitProcessing, CmdList, 100 101 Windows, Classes, SysUtils; 85 102 86 103 var 87 MaxTurn, 88 LoadTurn, {turn where to stop loading} 89 nLogOpened, {nLog of opened book} 90 {$IFOPT O-}nHandoverStack,{$ENDIF} 91 LastEndClientCommand, 92 pContacted, // player contacted for negotiation 93 pDipActive, // player who's to speak in a negotiation 94 pTurn, {player who's turn it is} 95 GWinner, 96 GColdWarStart, 97 GStealFrom, 98 SpyMission, 99 ZOCTile, 100 CCCommand, 101 CCPlayer: integer; 102 DebugMap: array[0..nPl-1] of pointer; 103 ExeInfo: TSearchRec; 104 Stat: array[0..nStat-1, 0..nPl-1] of ^TChart; 105 AutoSaveState: TCmdListState; 106 MapField: ^Cardinal; // predefined map 107 LastOffer: TOffer; 108 CCData: array[0..14] of integer; 109 DevModelTurn, {turn of last call to sResetModel} 110 bix, {brain index of the players} 111 OriginalDataVersion: array[0..nPl-1] of integer; 112 SavedTiles{, SavedResourceWeights}: array[0..ncmax-1] of cardinal; 113 SavedData: array[0..nPl-1] of pointer; 114 LogFileName, SavePath, {name of file for saving the current game} 115 MapFileName, // name of map to use, empty for random 116 AICredits: string; 117 AIInfo: array[0..nPl-1] of string; 118 Notify: TNotifyFunction; 119 PerfFreq, LastClientTime: int64; 120 {$IFOPT O-}HandoverStack: array[0..31] of Cardinal;{$ENDIF} 121 AutoSaveExists, 122 LoadOK, WinOnAlone, PreviewElevation, MovieStopped: boolean; 104 MaxTurn, LoadTurn, { turn where to stop loading } 105 nLogOpened, { nLog of opened book } 106 {$IFOPT O-}nHandoverStack, {$ENDIF} 107 LastEndClientCommand, pContacted, // player contacted for negotiation 108 pDipActive, // player who's to speak in a negotiation 109 pTurn, { player who's turn it is } 110 GWinner, GColdWarStart, GStealFrom, SpyMission, ZOCTile, CCCommand, 111 CCPlayer: integer; 112 DebugMap: array [0 .. nPl - 1] of pointer; 113 ExeInfo: TSearchRec; 114 Stat: array [0 .. nStat - 1, 0 .. nPl - 1] of ^TChart; 115 AutoSaveState: TCmdListState; 116 MapField: ^Cardinal; // predefined map 117 LastOffer: TOffer; 118 CCData: array [0 .. 14] of integer; 119 DevModelTurn, { turn of last call to sResetModel } 120 bix, { brain index of the players } 121 OriginalDataVersion: array [0 .. nPl - 1] of integer; 122 SavedTiles { , SavedResourceWeights } : array [0 .. ncmax - 1] of Cardinal; 123 SavedData: array [0 .. nPl - 1] of pointer; 124 LogFileName, SavePath, { name of file for saving the current game } 125 MapFileName, // name of map to use, empty for random 126 AICredits: string; 127 AIInfo: array [0 .. nPl - 1] of string; 128 Notify: TNotifyFunction; 129 PerfFreq, LastClientTime: int64; 130 {$IFOPT O-}HandoverStack: array [0 .. 31] of Cardinal; {$ENDIF} 131 AutoSaveExists, LoadOK, WinOnAlone, PreviewElevation, MovieStopped: boolean; 123 132 124 133 const 125 PreviewRND=41601260; {randseed for preview map}126 127 function Server(Command, Player,Subject:integer;var Data): integer; stdcall; forward;128 129 130 procedure CallPlayer(Command, p: integer; var Data);134 PreviewRND = 41601260; { randseed for preview map } 135 136 function Server(Command, Player, Subject: integer; var Data): integer; 137 stdcall; forward; 138 139 procedure CallPlayer(Command, p: integer; var Data); 131 140 begin 132 if ((Mode<>moMovie) or (p=0)) then141 if ((Mode <> moMovie) or (p = 0)) then 133 142 begin 134 135 HandoverStack[nHandoverStack]:=p;136 HandoverStack[nHandoverStack+1]:=Command;137 inc(nHandoverStack,2);138 Brain[bix[p]].Client(Command,p,Data);139 dec(nHandoverStack,2);140 141 try142 Brain[bix[p]].Client(Command,p,Data);143 except144 Notify(ntException+bix[p]);143 {$IFOPT O-} 144 HandoverStack[nHandoverStack] := p; 145 HandoverStack[nHandoverStack + 1] := Command; 146 inc(nHandoverStack, 2); 147 Brain[bix[p]].Client(Command, p, Data); 148 dec(nHandoverStack, 2); 149 {$ELSE} 150 try 151 Brain[bix[p]].Client(Command, p, Data); 152 except 153 Notify(ntException + bix[p]); 145 154 end; 146 155 {$ENDIF} 147 156 end 148 157 end; 149 158 150 procedure CallClient(bix, Command: integer; var Data);159 procedure CallClient(bix, Command: integer; var Data); 151 160 begin 152 if ((Mode<>moMovie) or (bix=GameServer.bix[0])) then161 if ((Mode <> moMovie) or (bix = GameServer.bix[0])) then 153 162 begin 154 155 HandoverStack[nHandoverStack]:=bix;156 HandoverStack[nHandoverStack+1]:=Command;157 inc(nHandoverStack,2);158 Brain[bix].Client(Command,-1,Data);159 dec(nHandoverStack,2);160 161 try162 Brain[bix].Client(Command,-1,Data);163 except164 Notify(ntException+bix);163 {$IFOPT O-} 164 HandoverStack[nHandoverStack] := bix; 165 HandoverStack[nHandoverStack + 1] := Command; 166 inc(nHandoverStack, 2); 167 Brain[bix].Client(Command, -1, Data); 168 dec(nHandoverStack, 2); 169 {$ELSE} 170 try 171 Brain[bix].Client(Command, -1, Data); 172 except 173 Notify(ntException + bix); 165 174 end; 166 175 {$ENDIF} 167 176 end 168 177 end; … … 170 179 procedure Init(NotifyFunction: TNotifyFunction); 171 180 var 172 i: integer;173 f: TSearchRec;174 T: TextFile;175 s: string;181 i: integer; 182 f: TSearchRec; 183 T: TextFile; 184 s: string; 176 185 177 186 begin 178 Notify:=NotifyFunction;179 PreviewElevation:=false;180 181 {get available brains}182 Brain[bixNoTerm].FileName:=':AIT';183 Brain[bixNoTerm].Flags:=0;184 Brain[bixNoTerm].Initialized:=false;185 Brain[bixSuper_Virtual].FileName:=':Supervisor';186 Brain[bixSuper_Virtual].Flags:=0;187 Brain[bixSuper_Virtual].Initialized:=false;188 Brain[bixTerm].FileName:=':StdIntf';189 Brain[bixTerm].Flags:=fMultiple;190 Brain[bixTerm].Initialized:=false;191 Brain[bixTerm].ServerVersion:=Version;192 Brain[bixRandom].FileName:=':Random';193 Brain[bixRandom].Flags:=fMultiple;194 Brain[bixRandom].Initialized:=false;195 nBrain:=bixFirstAI;196 bixBeginner:=bixFirstAI;197 if FindFirst(HomeDir+'*.ai.txt',$21,f)=0 then198 repeat199 with Brain[nBrain] do200 begin 201 FileName:=Copy(f.Name,1,Length(f.Name)-7);202 DLLName:=HomeDir+FileName;203 Name:=Copy(f.Name,1,Length(f.Name)-7);204 Credits:='';205 Flags:=fMultiple;206 Client:=nil;207 Initialized:=false;208 ServerVersion:=0;209 AssignFile(T,HomeDir+f.Name);210 Reset(T);211 while not EOF(T) do187 Notify := NotifyFunction; 188 PreviewElevation := false; 189 190 { get available brains } 191 Brain[bixNoTerm].FileName := ':AIT'; 192 Brain[bixNoTerm].Flags := 0; 193 Brain[bixNoTerm].Initialized := false; 194 Brain[bixSuper_Virtual].FileName := ':Supervisor'; 195 Brain[bixSuper_Virtual].Flags := 0; 196 Brain[bixSuper_Virtual].Initialized := false; 197 Brain[bixTerm].FileName := ':StdIntf'; 198 Brain[bixTerm].Flags := fMultiple; 199 Brain[bixTerm].Initialized := false; 200 Brain[bixTerm].ServerVersion := Version; 201 Brain[bixRandom].FileName := ':Random'; 202 Brain[bixRandom].Flags := fMultiple; 203 Brain[bixRandom].Initialized := false; 204 nBrain := bixFirstAI; 205 bixBeginner := bixFirstAI; 206 if FindFirst(HomeDir + '*.ai.txt', $21, f) = 0 then 207 repeat 208 with Brain[nBrain] do 209 begin 210 FileName := Copy(f.Name, 1, Length(f.Name) - 7); 211 DLLName := HomeDir + FileName; 212 Name := Copy(f.Name, 1, Length(f.Name) - 7); 213 Credits := ''; 214 Flags := fMultiple; 215 Client := nil; 216 Initialized := false; 217 ServerVersion := 0; 218 AssignFile(T, HomeDir + f.Name); 219 Reset(T); 220 while not EOF(T) do 212 221 begin 213 ReadLn(T,s); 214 s:=trim(s); 215 if Copy(s,1,5)='#NAME' then Name:=Copy(s,7,255) 216 else if Copy(s,1,10)='#.NET' then 217 Flags:=Flags or fDotNet 218 else if Copy(s,1,9)='#BEGINNER' then 219 bixBeginner:=nBrain 220 else if Copy(s,1,5)='#PATH' then 221 DLLName:=HomeDir+trim(Copy(s,7,255)) 222 else if Copy(s,1,12)='#GAMEVERSION' then 223 for i:=13 to Length(s) do 224 case s[i] of 225 '0'..'9': ServerVersion:=ServerVersion and $FFFF00 226 +ServerVersion and $FF *10+ord(s[i])-48; 227 '.': ServerVersion:=ServerVersion shl 8; 222 ReadLn(T, s); 223 s := trim(s); 224 if Copy(s, 1, 5) = '#NAME' then 225 Name := Copy(s, 7, 255) 226 else if Copy(s, 1, 10) = '#.NET' then 227 Flags := Flags or fDotNet 228 else if Copy(s, 1, 9) = '#BEGINNER' then 229 bixBeginner := nBrain 230 else if Copy(s, 1, 5) = '#PATH' then 231 DLLName := HomeDir + trim(Copy(s, 7, 255)) 232 else if Copy(s, 1, 12) = '#GAMEVERSION' then 233 for i := 13 to Length(s) do 234 case s[i] of 235 '0' .. '9': 236 ServerVersion := ServerVersion and $FFFF00 + ServerVersion and 237 $FF * 10 + ord(s[i]) - 48; 238 '.': 239 ServerVersion := ServerVersion shl 8; 228 240 end 229 else if Copy(s,1,8)='#CREDITS' then230 Credits:=Copy(s,10,255)241 else if Copy(s, 1, 8) = '#CREDITS' then 242 Credits := Copy(s, 10, 255) 231 243 end; 232 CloseFile(T);233 end; 234 if (Brain[nBrain].ServerVersion>=FirstAICompatibleVersion)235 and (Brain[nBrain].ServerVersion<=Version)236 and ((Brain[nBrain].Flags and fDotNet=0) or (@DotNetClient<>nil)) then237 inc(nBrain);238 until FindNext(f)<>0;244 CloseFile(T); 245 end; 246 if (Brain[nBrain].ServerVersion >= FirstAICompatibleVersion) and 247 (Brain[nBrain].ServerVersion <= Version) and 248 ((Brain[nBrain].Flags and fDotNet = 0) or (@DotNetClient <> nil)) then 249 inc(nBrain); 250 until FindNext(f) <> 0; 239 251 end; 240 252 241 253 procedure Done; 242 254 var 243 i: integer;255 i: integer; 244 256 begin 245 for i:=0 to nBrain-1 do if Brain[i].Initialized then 246 begin 247 CallClient(i, cReleaseModule, nil^); 248 if (i>=bixFirstAI) and (Brain[i].Flags and fDotNet=0) then 249 FreeLibrary(Brain[i].hm); 250 end; 257 for i := 0 to nBrain - 1 do 258 if Brain[i].Initialized then 259 begin 260 CallClient(i, cReleaseModule, nil^); 261 if (i >= bixFirstAI) and (Brain[i].Flags and fDotNet = 0) then 262 FreeLibrary(Brain[i].hm); 263 end; 251 264 end; 252 265 253 266 function PreviewMap(lm: integer): pointer; 254 267 begin 255 lx:=lxmax; ly:=lymax; MapSize:=lx*ly; 256 LandMass:=lm; 257 RandSeed:=PreviewRND; 258 if not PreviewElevation then 268 lx := lxmax; 269 ly := lymax; 270 MapSize := lx * ly; 271 LandMass := lm; 272 RandSeed := PreviewRND; 273 if not PreviewElevation then 259 274 begin 260 CreateElevation;261 PreviewElevation:=true;275 CreateElevation; 276 PreviewElevation := true; 262 277 end; 263 CreateMap(true);264 result:=@RealMap;278 CreateMap(true); 279 result := @RealMap; 265 280 end; 266 281 … … 268 283 DataSize: integer); 269 284 begin 270 CCCommand:=Command; 271 CCPlayer:=Player; 272 if DataSize>0 then move(Data,CCData,DataSize); 273 Notify(ntChangeClient); 285 CCCommand := Command; 286 CCPlayer := Player; 287 if DataSize > 0 then 288 move(Data, CCData, DataSize); 289 Notify(ntChangeClient); 274 290 end; 275 291 276 292 procedure PutMessage(Level: integer; Text: string); 277 293 begin 278 Brain[bix[0]].Client(cDebugMessage,Level,pchar(Text)^);294 Brain[bix[0]].Client(cDebugMessage, Level, pchar(Text)^); 279 295 end; 280 296 281 297 procedure ForceClientDeactivation; 282 298 var 283 NullOffer: TOffer;299 NullOffer: TOffer; 284 300 begin 285 if pDipActive<0 then Server(sTurn,pTurn,0,nil^) // no nego mode 286 else case LastEndClientCommand of // nego mode 287 scContact: Server(scReject,pDipActive,0,nil^); 288 scDipCancelTreaty, scDipBreak: Server(scDipNotice,pDipActive,0,nil^); 301 if pDipActive < 0 then 302 Server(sTurn, pTurn, 0, nil^) // no nego mode 289 303 else 290 begin // make null offer 291 NullOffer.nDeliver:=0; 292 NullOffer.nCost:=0; 293 Server(scDipOffer,pDipActive,0,NullOffer); 304 case LastEndClientCommand of // nego mode 305 scContact: 306 Server(scReject, pDipActive, 0, nil^); 307 scDipCancelTreaty, scDipBreak: 308 Server(scDipNotice, pDipActive, 0, nil^); 309 else 310 begin // make null offer 311 NullOffer.nDeliver := 0; 312 NullOffer.nCost := 0; 313 Server(scDipOffer, pDipActive, 0, NullOffer); 314 end 315 end 316 end; 317 318 procedure ChangeClient; 319 // hand over control to other client (as specified by CC...) 320 var 321 p: integer; 322 T: int64; 323 begin 324 QueryPerformanceCounter(T); 325 PutMessage(1 shl 16 + 2, Format('CLIENT: took %.1f ms', 326 [{$IFDEF VER100}(T.LowPart - LastClientTime.LowPart) 327 {$ELSE}(T - LastClientTime){$ENDIF} * 1000.0 / PerfFreq])); 328 LastClientTime := T; 329 PutMessage(1 shl 16 + 2, Format('CLIENT: calling %d (%s)', 330 [CCPlayer, Brain[bix[CCPlayer]].Name])); 331 if CCCommand = cTurn then 332 for p := 0 to nPl - 1 do 333 if (p <> CCPlayer) and (1 shl p and GWatching <> 0) then 334 CallPlayer(cShowTurnChange, p, CCPlayer); 335 336 p := CCPlayer; 337 CCPlayer := -1; 338 CallPlayer(CCCommand, p, CCData); 339 if (Mode = moPlaying) and (Brain[bix[p]].Flags and aiThreaded = 0) and 340 (CCPlayer < 0) then 341 begin 342 Notify(ntDeactivationMissing + p); 343 ForceClientDeactivation; 344 end 345 end; 346 347 procedure Inform(p: integer); 348 var 349 i, p1: integer; 350 begin 351 RW[p].Turn := GTurn; 352 if (GTurn = MaxTurn) and (p = pTurn) and (p = 0) then 353 RW[p].Happened := RW[p].Happened or phTimeUp; 354 if (GWinner > 0) and (p = pTurn) and (p = 0) then 355 RW[p].Happened := RW[p].Happened or phShipComplete; 356 RW[p].Alive := GAlive; 357 move(GWonder, RW[p].Wonder, SizeOf(GWonder)); 358 move(GShip, RW[p].Ship, SizeOf(GShip)); 359 for p1 := 0 to nPl - 1 do 360 if (p1 <> p) and (bix[p1] >= 0) and (Difficulty[p1] > 0) then 361 RW[p].EnemyReport[p1].Credibility := RW[p1].Credibility; 362 for p1 := 0 to nPl - 1 do 363 if (p1 <> p) and (1 shl p1 and GAlive <> 0) then 364 begin 365 if (GTestFlags and tfUncover <> 0) or (Difficulty[p] = 0) or 366 (RW[p].Treaty[p1] >= trFriendlyContact) then 367 GiveCivilReport(p, p1); 368 if (GTestFlags and tfUncover <> 0) or (Difficulty[p] = 0) or 369 (RW[p].Treaty[p1] = trAlliance) then 370 GiveMilReport(p, p1) 371 end; 372 for i := 0 to RW[p].nEnemyModel - 1 do 373 with RW[p].EnemyModel[i] do 374 Lost := Destroyed[p, Owner, mix]; 375 end; 376 377 procedure LogChanges; 378 var 379 p, ix: integer; 380 begin 381 for p := 0 to nPl - 1 do 382 if (1 shl p and GWatching <> 0) and ProcessClientData[p] then 383 begin 384 // log unit status changes 385 for ix := 0 to RW[p].nUn - 1 do 386 with RW[p].Un[ix] do 387 if (Loc >= 0) and (SavedStatus <> Status) then 388 begin 389 CL.Put(sIntSetUnitStatus, p, ix, @Status); 390 SavedStatus := Status 391 end; 392 // log city status changes 393 for ix := 0 to RW[p].nCity - 1 do 394 with RW[p].City[ix] do 395 if (Loc >= 0) and (SavedStatus <> Status) then 396 begin 397 CL.Put(sIntSetCityStatus, p, ix, @Status); 398 SavedStatus := Status 399 end; 400 // log model status changes 401 for ix := 0 to RW[p].nModel - 1 do 402 with RW[p].Model[ix] do 403 if SavedStatus <> Status then 404 begin 405 CL.Put(sIntSetModelStatus, p, ix, @Status); 406 SavedStatus := Status 407 end; 408 // log enemy city status changes 409 for ix := 0 to RW[p].nEnemyCity - 1 do 410 with RW[p].EnemyCity[ix] do 411 if (Loc >= 0) and (SavedStatus <> Status) then 412 begin 413 CL.Put(sIntSetECityStatus, p, ix, @Status); 414 SavedStatus := Status 415 end; 416 // log data changes 417 if Brain[bix[p]].DataSize > 0 then 418 begin 419 CL.PutDataChanges(sIntDataChange, p, SavedData[p], RW[p].Data, 420 Brain[bix[p]].DataSize); 421 move(RW[p].Data^, SavedData[p]^, Brain[bix[p]].DataSize * 4); 422 end 423 end; 424 end; 425 426 procedure NoLogChanges; 427 var 428 p, ix: integer; 429 begin 430 for p := 0 to nPl - 1 do 431 if (1 shl p and GWatching <> 0) and ProcessClientData[p] then 432 begin 433 for ix := 0 to RW[p].nUn - 1 do 434 with RW[p].Un[ix] do 435 SavedStatus := Status; 436 for ix := 0 to RW[p].nCity - 1 do 437 with RW[p].City[ix] do 438 SavedStatus := Status; 439 for ix := 0 to RW[p].nModel - 1 do 440 with RW[p].Model[ix] do 441 SavedStatus := Status; 442 for ix := 0 to RW[p].nEnemyCity - 1 do 443 with RW[p].EnemyCity[ix] do 444 SavedStatus := Status; 445 if Brain[bix[p]].DataSize > 0 then 446 move(RW[p].Data^, SavedData[p]^, Brain[bix[p]].DataSize * 4); 447 end; 448 end; 449 450 function HasChanges(p: integer): boolean; 451 type 452 TDWordList = array [0 .. INFIN] of Cardinal; 453 PDWortList = ^TDWordList; 454 var 455 ix: integer; 456 begin 457 result := false; 458 for ix := 0 to RW[p].nUn - 1 do 459 with RW[p].Un[ix] do 460 if (Loc >= 0) and (SavedStatus <> Status) then 461 result := true; 462 for ix := 0 to RW[p].nCity - 1 do 463 with RW[p].City[ix] do 464 if (Loc >= 0) and (SavedStatus <> Status) then 465 result := true; 466 for ix := 0 to RW[p].nModel - 1 do 467 with RW[p].Model[ix] do 468 if SavedStatus <> Status then 469 result := true; 470 for ix := 0 to RW[p].nEnemyCity - 1 do 471 with RW[p].EnemyCity[ix] do 472 if (Loc >= 0) and (SavedStatus <> Status) then 473 result := true; 474 if RW[p].Data <> nil then 475 for ix := 0 to Brain[bix[p]].DataSize - 1 do 476 if PDWortList(SavedData[p])[ix] <> PDWortList(RW[p].Data)[ix] then 477 result := true 478 end; 479 480 procedure InitBrain(bix: integer); 481 var 482 InitModuleData: TInitModuleData; 483 begin 484 assert(bix <> bixSuper_Virtual); 485 with Brain[bix] do 486 begin 487 if Initialized then 488 exit; 489 if bix >= bixFirstAI then 490 begin { get client function } 491 Notify(ntInitModule + bix); 492 if Flags and fDotNet > 0 then 493 Client := DotNetClient 494 else 495 begin 496 hm := LoadLibrary(pchar(DLLName)); 497 if hm = 0 then 498 begin 499 Client := nil; 500 Notify(ntDLLError + bix); 501 end 502 else 503 begin 504 Client := GetProcAddress(hm, 'client'); 505 if @Client = nil then 506 Notify(ntClientError + bix); 507 end 508 end 509 end; 510 if @Client <> nil then 511 begin 512 Initialized := true; 513 InitModuleData.Server := @Server; 514 InitModuleData.DataVersion := 0; 515 InitModuleData.DataSize := 0; 516 InitModuleData.Flags := 0; 517 CallClient(bix, cInitModule, InitModuleData); 518 DataVersion := InitModuleData.DataVersion; 519 DataSize := (InitModuleData.DataSize + 3) div 4; 520 if DataSize > MaxDataSize then 521 DataSize := 0; 522 Flags := Flags or InitModuleData.Flags; 294 523 end 295 524 end 296 525 end; 297 526 298 procedure ChangeClient; 299 //hand over control to other client (as specified by CC...) 527 procedure SaveMap(FileName: string); 300 528 var 301 p: integer; 302 T: int64; 529 i: integer; 530 MapFile: TFileStream; 531 s: string[255]; 303 532 begin 304 QueryPerformanceCounter(T); 305 PutMessage(1 shl 16+2, Format('CLIENT: took %.1f ms', 306 [{$IFDEF VER100}(T.LowPart-LastClientTime.LowPart) 307 {$ELSE}(T-LastClientTime){$ENDIF}*1000.0/PerfFreq])); 308 LastClientTime:=T; 309 PutMessage(1 shl 16+2, Format('CLIENT: calling %d (%s)', 310 [CCPlayer,Brain[bix[CCPlayer]].Name])); 311 if CCCommand=cTurn then 312 for p:=0 to nPl-1 do if (p<>CCPlayer) and (1 shl p and GWatching<>0) then 313 CallPlayer(cShowTurnChange,p,CCPlayer); 314 315 p:=CCPlayer; 316 CCPlayer:=-1; 317 CallPlayer(CCCommand,p,CCData); 318 if (Mode=moPlaying) and (Brain[bix[p]].Flags and aiThreaded=0) and (CCPlayer<0) then 533 MapFile := TFileStream.Create(DataDir + 'Maps\' + FileName, 534 fmCreate or fmShareExclusive); 535 MapFile.Position := 0; 536 s := 'cEvoMap'#0; 537 MapFile.write(s[1], 8); { file id } 538 i := 0; 539 MapFile.write(i, 4); { format id } 540 MapFile.write(MaxTurn, 4); 541 MapFile.write(lx, 4); 542 MapFile.write(ly, 4); 543 MapFile.write(RealMap, MapSize * 4); 544 MapFile.Free; 545 end; 546 547 function LoadMap(FileName: string): boolean; 548 var 549 i, Loc1: integer; 550 MapFile: TFileStream; 551 s: string[255]; 552 begin 553 result := false; 554 MapFile := nil; 555 try 556 MapFile := TFileStream.Create(DataDir + 'Maps\' + FileName, 557 fmOpenRead or fmShareExclusive); 558 MapFile.Position := 0; 559 MapFile.read(s[1], 8); { file id } 560 MapFile.read(i, 4); { format id } 561 if i = 0 then 562 begin 563 MapFile.read(i, 4); // MaxTurn 564 MapFile.read(lx, 4); 565 MapFile.read(ly, 4); 566 ly := ly and not 1; 567 if lx > lxmax then 568 lx := lxmax; 569 if ly > lymax then 570 ly := lymax; 571 MapSize := lx * ly; 572 MapFile.read(RealMap, MapSize * 4); 573 for Loc1 := 0 to MapSize - 1 do 574 begin 575 RealMap[Loc1] := RealMap[Loc1] and 576 ($7F01FFFF or fPrefStartPos or fStartPos) or ($F shl 27); 577 if RealMap[Loc1] and (fTerrain or fSpecial) = fSwamp or fSpecial2 then 578 RealMap[Loc1] := RealMap[Loc1] and not(fTerrain or fSpecial) or 579 (fSwamp or fSpecial1); 580 if (RealMap[Loc1] and fDeadLands <> 0) and 581 (RealMap[Loc1] and fTerrain <> fArctic) then 582 RealMap[Loc1] := RealMap[Loc1] and not(fTerrain or fSpecial) 583 or fDesert; 584 end; 585 result := true; 586 end; 587 MapFile.Free; 588 except 589 if MapFile <> nil then 590 MapFile.Free; 591 end; 592 end; 593 594 procedure SaveGame(FileName: string; auto: boolean); 595 var 596 x, y, i, zero, Tile, nLocal: integer; 597 LogFile: TFileStream; 598 s: string[255]; 599 SaveMap: array [0 .. lxmax * lymax - 1] of Byte; 600 begin 601 nLocal := 0; 602 for i := 0 to nPl - 1 do 603 if bix[i] = bixTerm then 604 inc(nLocal); 605 if Difficulty[0] = 0 then 606 nLocal := 0; 607 if nLocal <= 1 then 608 for y := 0 to ly - 1 do 609 for x := 0 to lx - 1 do 610 begin 611 Tile := RW[0].Map[(x + SaveMapCenterLoc + lx shr 1) mod lx + lx * y]; 612 SaveMap[x + lx * y] := Tile and fTerrain + Tile and 613 (fCity or fUnit or fOwned) shr 16; 614 end; 615 616 if auto and AutoSaveExists then // append to existing file 617 LogFile := TFileStream.Create(SavePath + FileName, fmOpenReadWrite or 618 fmShareExclusive) 619 else // create new file 620 LogFile := TFileStream.Create(SavePath + FileName, 621 fmCreate or fmShareExclusive); 622 623 zero := 0; 624 LogFile.Position := 0; 625 s := 'cEvoBook'; 626 LogFile.write(s[1], 8); { file id } 627 i := Version; 628 LogFile.write(i, 4); { c-evo version } 629 LogFile.write(ExeInfo.Time, 4); 630 LogFile.write(lx, 4); 631 LogFile.write(ly, 4); 632 LogFile.write(LandMass, 4); 633 if LandMass = 0 then 634 LogFile.write(MapField^, MapSize * 4); 635 636 LogFile.write(MaxTurn, 4); 637 LogFile.write(RND, 4); 638 LogFile.write(GTurn, 4); 639 if nLocal > 1 then // multiplayer game -- no quick view 319 640 begin 320 Notify(ntDeactivationMissing+p); 321 ForceClientDeactivation; 641 i := $80; 642 LogFile.write(i, 4); 643 end 644 else 645 LogFile.write(SaveMap, ((MapSize - 1) div 4 + 1) * 4); 646 for i := 0 to nPl - 1 do 647 if bix[i] < 0 then 648 LogFile.write(zero, 4) 649 else 650 begin 651 if bixView[i] >= bixRandom then 652 s := Brain[bix[i]].FileName 653 else 654 s := Brain[bixView[i]].FileName; 655 move(zero, s[Length(s) + 1], 4); 656 LogFile.write(s, (Length(s) div 4 + 1) * 4); 657 LogFile.write(OriginalDataVersion[i], 4); 658 s := ''; { behavior } 659 move(zero, s[Length(s) + 1], 4); 660 LogFile.write(s, (Length(s) div 4 + 1) * 4); 661 LogFile.write(Difficulty[i], 4); 662 end; 663 664 if auto and AutoSaveExists then 665 CL.AppendToFile(LogFile, AutoSaveState) 666 else 667 CL.SaveToFile(LogFile); 668 LogFile.Free; 669 if auto then 670 begin 671 AutoSaveState := CL.State; 672 AutoSaveExists := true 322 673 end 323 674 end; 324 675 325 procedure Inform(p: integer);676 procedure StartGame; 326 677 var 327 i,p1: integer; 678 i, p, p1, Human, nAlive, bixUni: integer; 679 Game: TNewGameData; 680 // GameEx: TNewGameExData; 681 Path: shortstring; 682 BrainUsed: Set of 0 .. 254; { used brains } 328 683 begin 329 RW[p].Turn:=GTurn; 330 if (GTurn=MaxTurn) and (p=pTurn) and (p=0) then 331 RW[p].Happened:=RW[p].Happened or phTimeUp; 332 if (GWinner>0) and (p=pTurn) and (p=0) then 333 RW[p].Happened:=RW[p].Happened or phShipComplete; 334 RW[p].Alive:=GAlive; 335 move(GWonder,RW[p].Wonder,SizeOf(GWonder)); 336 move(GShip,RW[p].Ship,SizeOf(GShip)); 337 for p1:=0 to nPl-1 do 338 if (p1<>p) and (bix[p1]>=0) and (Difficulty[p1]>0) then 339 RW[p].EnemyReport[p1].Credibility:=RW[p1].Credibility; 340 for p1:=0 to nPl-1 do 341 if (p1<>p) and (1 shl p1 and GAlive<>0) then 684 for p1 := 0 to nPl - 1 do 685 begin 686 if bixView[p1] = bixSuper_Virtual then 687 bix[p1] := bixTerm // supervisor and local human use same module 688 else if bixView[p1] = bixRandom then 689 if nBrain <= bixFirstAI then 690 bix[p1] := -1 691 else 692 bix[p1] := bixFirstAI + random(nBrain - bixFirstAI) 693 else 694 bix[p1] := bixView[p1]; 695 if bixView[p1] < 0 then 696 Difficulty[p1] := -1; 697 end; 698 699 if bix[0] <> bixNoTerm then 700 Notify(ntInitLocalHuman); 701 BrainUsed := []; 702 for p := 0 to nPl - 1 do 703 if (bix[p] >= 0) and ((Mode <> moMovie) or (p = 0)) then 704 begin { initiate selected control module } 705 AIInfo[p] := Brain[bix[p]].Name + #0; 706 InitBrain(bix[p]); 707 if Mode = moPlaying then 708 begin // new game, this data version is original 709 OriginalDataVersion[p] := Brain[bix[p]].DataVersion; 710 ProcessClientData[p] := true; 711 end 712 else // loading game, compare with data version read from file 713 ProcessClientData[p] := ProcessClientData[p] and 714 (OriginalDataVersion[p] = Brain[bix[p]].DataVersion); 715 if @Brain[bix[p]].Client = nil then // client function not found 716 if bix[0] = bixNoTerm then 717 bix[p] := -1 718 else 719 begin 720 bix[p] := bixTerm; 721 OriginalDataVersion[p] := -1; 722 ProcessClientData[p] := false; 723 end; 724 if bix[p] >= 0 then 725 include(BrainUsed, bix[p]) 726 end; 727 728 Notify(ntCreateWorld); 729 nAlive := 0; 730 GAlive := 0; 731 if Mode = moMovie then 732 GWatching := 1 733 else 734 GWatching := 0; 735 GAI := 0; 736 for p1 := 0 to nPl - 1 do 737 if bix[p1] >= 0 then 342 738 begin 343 if (GTestFlags and tfUncover<>0) or (Difficulty[p]=0) 344 or (RW[p].Treaty[p1]>=trFriendlyContact) then 345 GiveCivilReport(p, p1); 346 if (GTestFlags and tfUncover<>0) or (Difficulty[p]=0) 347 or (RW[p].Treaty[p1]=trAlliance) then 348 GiveMilReport(p, p1) 739 if Mode <> moMovie then 740 inc(GWatching, 1 shl p1); 741 if bix[p1] >= bixFirstAI then 742 inc(GAI, 1 shl p1); 743 if Difficulty[p1] > 0 then 744 begin 745 inc(GAlive, 1 shl p1); 746 inc(nAlive); 747 end; 748 ServerVersion[p1] := Brain[bix[p1]].ServerVersion; 349 749 end; 350 for i:=0 to RW[p].nEnemyModel-1 do with RW[p].EnemyModel[i] do 351 Lost:=Destroyed[p,Owner,mix]; 750 WinOnAlone := (bix[0] = bixNoTerm) and (nAlive > 1); 751 GWinner := 0; 752 GColdWarStart := -ColdWarTurns - 1; 753 uixSelectedTransport := -1; 754 SpyMission := smSabotageProd; 755 for p1 := 0 to nPl - 1 do 756 DebugMap[p1] := nil; 757 758 GTurn := 0; 759 for i := 0 to 27 do 760 with GWonder[i] do 761 begin 762 CityID := -1; 763 EffectiveOwner := -1 764 end; 765 FillChar(GShip, SizeOf(GShip), 0); 766 767 for p := 0 to nPl - 1 do 768 if 1 shl p and (GAlive or GWatching) <> 0 then 769 with RW[p] do 770 begin 771 Government := gDespotism; 772 Money := StartMoney; 773 TaxRate := 30; 774 LuxRate := 0; 775 Research := 0; 776 ResearchTech := -2; 777 AnarchyStart := -AnarchyTurns - 1; 778 Happened := 0; 779 LastValidStat[p] := -1; 780 Worked[p] := 0; 781 Founded[p] := 0; 782 DevModelTurn[p] := -1; 783 OracleIncome := 0; 784 785 if Brain[bix[p]].DataSize > 0 then 786 begin 787 GetMem(SavedData[p], Brain[bix[p]].DataSize * 4); 788 GetMem(Data, Brain[bix[p]].DataSize * 4); 789 FillChar(SavedData[p]^, Brain[bix[p]].DataSize * 4, 0); 790 FillChar(Data^, Brain[bix[p]].DataSize * 4, 0); 791 end 792 else 793 begin 794 Data := nil; 795 SavedData[p] := nil 796 end; 797 nBattleHistory := 0; 798 BattleHistory := nil; 799 { if bix[p]=bixTerm then 800 begin 801 GetMem(BorderHelper,MapSize); 802 FillChar(BorderHelper^,MapSize,0); 803 end 804 else } BorderHelper := nil; 805 for i := 0 to nStat - 1 do 806 GetMem(Stat[i, p], 4 * (MaxTurn + 1)); 807 if Brain[bix[p]].Flags and fDotNet <> 0 then 808 begin 809 GetMem(RW[p].DefaultDebugMap, MapSize * 4); 810 FillChar(RW[p].DefaultDebugMap^, MapSize * 4, 0); 811 DebugMap[p] := RW[p].DefaultDebugMap; 812 end 813 else 814 RW[p].DefaultDebugMap := nil; 815 816 { !!!for i:=0 to nShipPart-1 do GShip[p].Parts[i]:=random((3-i)*2);{ } 817 end; 818 819 if LandMass > 0 then 820 begin // random map 821 InitRandomGame; 822 PreviewElevation := false; 823 MapField := nil; 824 end 825 else 826 begin // predefined map 827 if Mode = moPlaying then 828 LoadMap(MapFileName); // new game -- load map from file 829 GetMem(MapField, MapSize * 4); 830 move(RealMap, MapField^, MapSize * 4); 831 Human := 0; 832 for p1 := 0 to nPl - 1 do 833 if bix[p1] = bixTerm then 834 inc(Human, 1 shl p1); 835 InitMapGame(Human); 836 end; 837 CityProcessing.InitGame; 838 UnitProcessing.InitGame; 839 for p := 0 to nPl - 1 do 840 if 1 shl p and (GAlive or GWatching) <> 0 then 841 Inform(p); 842 843 pTurn := -1; 844 if bix[0] <> bixNoTerm then 845 Notify(ntInitLocalHuman); 846 Game.lx := lx; 847 Game.ly := ly; 848 Game.LandMass := LandMass; 849 Game.MaxTurn := MaxTurn; 850 move(Difficulty, Game.Difficulty, SizeOf(Difficulty)); 851 // GameEx.lx:=lx; GameEx.ly:=ly; GameEx.LandMass:=LandMass; 852 // GameEx.MaxTurn:=MaxTurn; GameEx.RND:=RND; 853 // move(Difficulty,GameEx.Difficulty,SizeOf(Difficulty)); 854 AICredits := ''; 855 for i := 0 to nBrain - 1 do 856 if Brain[i].Initialized then 857 if i in BrainUsed then 858 begin 859 if i >= bixFirstAI then 860 Notify(ntInitPlayers); 861 for p := 0 to nPl - 1 do 862 begin 863 if bix[p] = i then 864 Game.RO[p] := @RW[p] 865 else 866 Game.RO[p] := nil; 867 if (i = bixTerm) and (Difficulty[0] = 0) and (bix[p] >= 0) then 868 Game.SuperVisorRO[p] := @RW[p] 869 else 870 Game.SuperVisorRO[p] := nil; 871 end; 872 if Brain[i].Flags and fDotNet > 0 then 873 begin 874 Path := Brain[i].DLLName; 875 move(Path[1], Game.AssemblyPath, Length(Path)); 876 Game.AssemblyPath[Length(Path)] := #0; 877 end 878 else 879 Game.AssemblyPath[0] := #0; 880 case Mode of 881 moLoading, moLoading_Fast: 882 CallClient(i, cLoadGame, Game); 883 moMovie: 884 CallClient(i, cMovie, Game); 885 moPlaying: 886 CallClient(i, cNewGame, Game); 887 end; 888 if (i >= bixFirstAI) and (Brain[i].Credits <> '') then 889 if AICredits = '' then 890 AICredits := Brain[i].Credits 891 else 892 AICredits := AICredits + '\' + Brain[i].Credits 893 end 894 else 895 begin { module no longer used -- unload } 896 CallClient(i, cReleaseModule, nil^); 897 if i >= bixFirstAI then 898 begin 899 if Brain[i].Flags and fDotNet = 0 then 900 FreeLibrary(Brain[i].hm); 901 Brain[i].Client := nil; 902 end; 903 Brain[i].Initialized := false; 904 end; 905 AICredits := AICredits + #0; 906 907 if bix[0] <> bixNoTerm then 908 begin 909 // uni ai? 910 bixUni := -1; 911 for p1 := 0 to nPl - 1 do 912 if bix[p1] >= bixFirstAI then 913 if bixUni = -1 then 914 bixUni := bix[p1] 915 else if bixUni <> bix[p1] then 916 bixUni := -2; 917 for p1 := 0 to nPl - 1 do 918 if bix[p1] >= bixFirstAI then 919 begin 920 if bixUni = -2 then 921 NotifyMessage := Brain[bix[p1]].FileName 922 else 923 NotifyMessage := ''; 924 Notify(ntSetAIName + p1); 925 end 926 end; 927 928 CheckBorders(-1); 929 {$IFOPT O-}InvalidTreatyMap := 0; {$ENDIF} 930 AutoSaveExists := false; 931 pDipActive := -1; 932 pTurn := 0; 933 934 if Mode >= moMovie then 935 Notify(ntEndInfo); 936 end; { StartGame } 937 938 procedure EndGame; 939 var 940 i, p1: integer; 941 begin 942 if LandMass = 0 then 943 FreeMem(MapField); 944 for p1 := 0 to nPl - 1 do 945 if bix[p1] >= 0 then 946 begin 947 for i := 0 to nStat - 1 do 948 FreeMem(Stat[i, p1]); 949 if RW[p1].BattleHistory <> nil then 950 FreeMem(RW[p1].BattleHistory); 951 { if RW[p1].BorderHelper<>nil then FreeMem(RW[p1].BorderHelper); } 952 FreeMem(RW[p1].Data); 953 FreeMem(SavedData[p1]); 954 if RW[p1].DefaultDebugMap <> nil then 955 FreeMem(RW[p1].DefaultDebugMap); 956 end; 957 UnitProcessing.ReleaseGame; 958 CityProcessing.ReleaseGame; 959 Database.ReleaseGame; 960 CL.Free; 352 961 end; 353 962 354 procedure LogChanges;963 procedure GenerateStat(p: integer); 355 964 var 356 p,ix: integer;965 cix, uix: integer; 357 966 begin 358 for p:=0 to nPl-1 do 359 if (1 shl p and GWatching<>0) and ProcessClientData[p] then967 if Difficulty[p] > 0 then 968 with RW[p] do 360 969 begin 361 // log unit status changes 362 for ix:=0 to RW[p].nUn-1 do with RW[p].Un[ix] do 363 if (Loc>=0) and (SavedStatus<>Status) then 364 begin 365 CL.Put(sIntSetUnitStatus, p, ix, @Status); 366 SavedStatus:=Status 367 end; 368 // log city status changes 369 for ix:=0 to RW[p].nCity-1 do with RW[p].City[ix] do 370 if (Loc>=0) and (SavedStatus<>Status) then 371 begin 372 CL.Put(sIntSetCityStatus, p, ix, @Status); 373 SavedStatus:=Status 374 end; 375 // log model status changes 376 for ix:=0 to RW[p].nModel-1 do with RW[p].Model[ix] do 377 if SavedStatus<>Status then 378 begin 379 CL.Put(sIntSetModelStatus, p, ix, @Status); 380 SavedStatus:=Status 381 end; 382 // log enemy city status changes 383 for ix:=0 to RW[p].nEnemyCity-1 do with RW[p].EnemyCity[ix] do 384 if (Loc>=0) and (SavedStatus<>Status) then 385 begin 386 CL.Put(sIntSetECityStatus, p, ix, @Status); 387 SavedStatus:=Status 388 end; 389 // log data changes 390 if Brain[bix[p]].DataSize>0 then 391 begin 392 CL.PutDataChanges(sIntDataChange, p, SavedData[p], RW[p].Data, 393 Brain[bix[p]].DataSize); 394 move(RW[p].Data^,SavedData[p]^,Brain[bix[p]].DataSize*4); 395 end 970 Stat[stPop, p, GTurn] := 0; 971 for cix := 0 to nCity - 1 do 972 if City[cix].Loc >= 0 then 973 inc(Stat[stPop, p, GTurn], City[cix].Size); 974 Stat[stScience, p, GTurn] := Researched[p] * 50; 975 if (RW[p].ResearchTech >= 0) and (RW[p].ResearchTech <> adMilitary) then 976 inc(Stat[stScience, p, GTurn], Research * 100 div TechBaseCost(nTech[p], 977 Difficulty[p])); 978 Stat[stMil, p, GTurn] := 0; 979 for uix := 0 to nUn - 1 do 980 if Un[uix].Loc >= 0 then 981 with Model[Un[uix].mix] do 982 begin 983 if (Kind <= mkEnemyDeveloped) and (Un[uix].mix <> 1) then 984 inc(Stat[stMil, p, GTurn], Weight * MStrength * 985 Un[uix].Health div 100) 986 else if Domain = dGround then 987 inc(Stat[stMil, p, GTurn], (Attack + 2 * Defense) * 988 Un[uix].Health div 100) 989 else 990 inc(Stat[stMil, p, GTurn], (Attack + Defense) * 991 Un[uix].Health div 100); 992 case Kind of 993 mkSlaves: 994 inc(Stat[stPop, p, GTurn]); 995 mkSettler: 996 inc(Stat[stPop, p, GTurn], 2); 997 end; 998 end; 999 Stat[stMil, p, GTurn] := Stat[stMil, p, GTurn] div 16; 1000 Stat[stExplore, p, GTurn] := Discovered[p]; 1001 Stat[stTerritory, p, GTurn] := TerritoryCount[p]; 1002 Stat[stWork, p, GTurn] := Worked[p]; 1003 LastValidStat[p] := GTurn; 396 1004 end; 397 1005 end; 398 1006 399 procedure NoLogChanges;1007 procedure LogCityTileChanges; 400 1008 var 401 p,ix: integer;1009 cix: integer; 402 1010 begin 403 for p:=0 to nPl-1 do 404 if (1 shl p and GWatching<>0) and ProcessClientData[p] then 1011 for cix := 0 to RW[pTurn].nCity - 1 do 1012 with RW[pTurn].City[cix] do 1013 if Loc >= 0 then 1014 begin 1015 { if SavedResourceWeights[cix]<>ResourceWeights then 1016 begin // log city resource weight changes 1017 CL.Put(sSetCityResourceWeights, pTurn, cix, @ResourceWeights); 1018 SavedResourceWeights[cix]:=ResourceWeights; 1019 end; } 1020 if SavedTiles[cix] <> Tiles then 1021 begin // log city tile changes 1022 CL.Put(sSetCityTiles, pTurn, cix, @Tiles); 1023 SavedTiles[cix] := Tiles; 1024 end; 1025 end; 1026 end; 1027 1028 procedure NoLogCityTileChanges; 1029 var 1030 cix: integer; 1031 begin 1032 for cix := 0 to RW[pTurn].nCity - 1 do 1033 with RW[pTurn].City[cix] do 1034 if Loc >= 0 then 1035 begin 1036 // SavedResourceWeights[cix]:=ResourceWeights; 1037 SavedTiles[cix] := Tiles; 1038 end; 1039 end; 1040 1041 function HasCityTileChanges: boolean; 1042 var 1043 cix: integer; 1044 begin 1045 result := false; 1046 for cix := 0 to RW[pTurn].nCity - 1 do 1047 with RW[pTurn].City[cix] do 1048 if Loc >= 0 then 1049 begin 1050 // if SavedResourceWeights[cix]<>ResourceWeights then result:=true; 1051 if SavedTiles[cix] <> Tiles then 1052 result := true; 1053 end; 1054 end; 1055 1056 procedure BeforeTurn0; 1057 var 1058 p1, uix: integer; 1059 begin 1060 for uix := 0 to RW[pTurn].nUn - 1 do { init movement points for first turn } 1061 with RW[pTurn].Un[uix] do 1062 Movement := RW[pTurn].Model[mix].Speed; 1063 1064 if Difficulty[pTurn] > 0 then 1065 DiscoverViewAreas(pTurn) 1066 else { supervisor } 1067 begin 1068 DiscoverAll(pTurn, lObserveSuper); 1069 for p1 := 1 to nPl - 1 do 1070 if 1 shl p1 and GAlive <> 0 then 1071 begin 1072 GiveCivilReport(pTurn, p1); 1073 GiveMilReport(pTurn, p1) 1074 end; 1075 end; 1076 // CheckContact; 1077 end; 1078 1079 function LoadGame(const Path, FileName: string; Turn: integer; 1080 MovieMode: boolean): boolean; 1081 var 1082 i, j, ix, d, p1, Command, Subject: integer; 1083 {$IFDEF TEXTLOG}LoadPos0: integer; {$ENDIF} 1084 Data: pointer; 1085 LogFile: TFileStream; 1086 FormerCLState: TCmdListState; 1087 s: string[255]; 1088 SaveMap: array [0 .. lxmax * lymax - 1] of Byte; 1089 started, StatRequest: boolean; 1090 begin 1091 SavePath := Path; 1092 LogFileName := FileName; 1093 LoadTurn := Turn; 1094 LogFile := TFileStream.Create(SavePath + LogFileName, fmOpenRead or 1095 fmShareExclusive); 1096 LogFile.Position := 0; 1097 LogFile.read(s[1], 8); { file id } 1098 LogFile.read(i, 4); { c-evo version } 1099 LogFile.read(j, 4); { exe time } 1100 1101 if (i >= FirstBookCompatibleVersion) and (i <= Version) then 1102 begin 1103 result := true; 1104 LogFile.read(lx, 4); 1105 LogFile.read(ly, 4); 1106 MapSize := lx * ly; 1107 LogFile.read(LandMass, 4); 1108 if LandMass = 0 then 1109 LogFile.read(RealMap, MapSize * 4); // use predefined map 1110 LogFile.read(MaxTurn, 4); 1111 LogFile.read(RND, 4); 1112 LogFile.read(GTurn, 4); 1113 LogFile.read(SaveMap, 4); 1114 if SaveMap[0] <> $80 then 1115 LogFile.read(SaveMap[4], ((MapSize - 1) div 4 + 1) * 4 - 4); 1116 for p1 := 0 to nPl - 1 do 405 1117 begin 406 for ix:=0 to RW[p].nUn-1 do with RW[p].Un[ix] do 407 SavedStatus:=Status; 408 for ix:=0 to RW[p].nCity-1 do with RW[p].City[ix] do 409 SavedStatus:=Status; 410 for ix:=0 to RW[p].nModel-1 do with RW[p].Model[ix] do 411 SavedStatus:=Status; 412 for ix:=0 to RW[p].nEnemyCity-1 do with RW[p].EnemyCity[ix] do 413 SavedStatus:=Status; 414 if Brain[bix[p]].DataSize>0 then 415 move(RW[p].Data^,SavedData[p]^,Brain[bix[p]].DataSize*4); 1118 LogFile.read(s[0], 4); 1119 if s[0] = #0 then 1120 bixView[p1] := -1 1121 else 1122 begin 1123 LogFile.read(s[4], Byte(s[0]) div 4 * 4); 1124 LogFile.read(OriginalDataVersion[p1], 4); 1125 LogFile.read(d, 4); { behavior } 1126 LogFile.read(Difficulty[p1], 4); 1127 j := nBrain - 1; 1128 while (j >= 0) and (AnsiCompareFileName(Brain[j].FileName, s) <> 0) do 1129 dec(j); 1130 if j < 0 then 1131 begin // ai not found -- replace by local player 1132 ProcessClientData[p1] := false; 1133 NotifyMessage := s; 1134 Notify(ntAIError); 1135 j := bixTerm; 1136 end 1137 else 1138 ProcessClientData[p1] := true; 1139 if j = bixNoTerm then 1140 j := bixSuper_Virtual; 1141 // crashed tournament -- load as supervisor 1142 bixView[p1] := j; 1143 end; 416 1144 end; 417 end; 418 419 function HasChanges(p: integer): boolean; 420 type 421 TDWordList= array[0..INFIN] of Cardinal; 422 PDWortList=^TDWordList; 1145 end 1146 else 1147 result := false; 1148 1149 if result then 1150 begin 1151 CL := TCmdList.Create; 1152 CL.LoadFromFile(LogFile); 1153 end; 1154 LogFile.Free; 1155 if not result then 1156 exit; 1157 1158 Notify(ntStartDone); 1159 if LoadTurn < 0 then 1160 LoadTurn := GTurn; 1161 if MovieMode then 1162 Mode := moMovie 1163 else if LoadTurn = 0 then 1164 Mode := moLoading 1165 else 1166 Mode := moLoading_Fast; 1167 {$IFDEF TEXTLOG}AssignFile(TextLog, SavePath + LogFileName + '.txt'); 1168 Rewrite(TextLog); {$ENDIF} 1169 LoadOK := true; 1170 StartGame; 1171 if MovieMode then 1172 begin 1173 Brain[bix[0]].Client(cShowGame, 0, nil^); 1174 Notify(ntBackOff); 1175 end 1176 else 1177 Notify(ntLoadBegin); 1178 1179 started := false; 1180 StatRequest := false; 1181 MovieStopped := false; 1182 {$IFDEF LOADPERF}QueryPerformanceCounter(time_total0); 1183 time_a := 0; 1184 time_b := 0; 1185 time_c := 0; {$ENDIF} 1186 while not MovieStopped and (CL.Progress < 1000) do 1187 begin 1188 FormerCLState := CL.State; 1189 CL.Get(Command, p1, Subject, Data); 1190 if p1 < 0 then 1191 p1 := pTurn; 1192 if StatRequest and (Command and (sctMask or sExecute) <> sctInternal or 1193 sExecute) then 1194 begin 1195 GenerateStat(pTurn); 1196 StatRequest := false 1197 end; 1198 // complete all internal commands following an sTurn before generating statistics 1199 if (Command = sTurn) and not started then 1200 begin 1201 {$IFDEF TEXTLOG}WriteLn(TextLog, '---Turn 0 P0---'); {$ENDIF} 1202 for p1 := 0 to nPl - 1 do 1203 if (bix[p1] >= 0) and ((Mode <> moMovie) or (p1 = 0)) then 1204 CallPlayer(cReplay, p1, nil^); 1205 BeforeTurn0; 1206 if MovieMode then 1207 begin 1208 Inform(pTurn); 1209 CallPlayer(cMovieTurn, 0, nil^); 1210 end; 1211 StatRequest := true; 1212 started := true; 1213 end 1214 else if (Command = sTurn) and (pTurn = 0) and (GTurn = LoadTurn) then 1215 begin 1216 assert(CL.State.LoadPos = FormerCLState.LoadPos + 4); // size of sTurn 1217 CL.State := FormerCLState; 1218 CL.Cut; 1219 Break; 1220 end 1221 else if Command = sIntDataChange then 1222 begin 1223 {$IFDEF TEXTLOG}LoadPos0 := CL.State.LoadPos; {$ENDIF} 1224 if ProcessClientData[p1] then 1225 CL.GetDataChanges(RW[p1].Data, Brain[bix[p1]].DataSize) 1226 else 1227 CL.GetDataChanges(nil, 0); 1228 {$IFDEF TEXTLOG}WriteLn(TextLog, Format('Data Changes P%d (%d Bytes)', [p1, CL.State.LoadPos - LoadPos0])); {$ENDIF} 1229 end 1230 else 1231 begin 1232 {$IFDEF TEXTLOG}CmdInfo := Format('Command %x', [Command]); {$ENDIF} 1233 if Command and (sctMask or sExecute) = sctInternal or sExecute then 1234 IntServer(Command, p1, Subject, Data^) // internal command 1235 else 1236 begin 1237 StatRequest := Command = sTurn; 1238 Server(Command, p1, Subject, Data^); 1239 end; 1240 {$IFDEF TEXTLOG}WriteLn(TextLog, CmdInfo); {$ENDIF} 1241 end; 1242 if not MovieMode then 1243 Notify(ntLoadState + CL.Progress * 128 div 1000); 1244 end; 1245 1246 if MovieMode then 1247 begin 1248 Notify(ntBackOn); 1249 Brain[bix[0]].Client(cBreakGame, -1, nil^); 1250 EndGame; 1251 Notify(ntStartGo); 1252 result := false; 1253 exit; 1254 end; 1255 1256 if StatRequest then 1257 GenerateStat(pTurn); 1258 assert(started); 1259 {$IFDEF TEXTLOG}CloseFile(TextLog); {$ENDIF} 1260 {$IFDEF LOADPERF}QueryPerformanceCounter(time_total); { time in s is: (time_total-time_total0)/PerfFreq }{$ENDIF} 1261 NoLogChanges; 1262 NoLogCityTileChanges; 1263 if LogFileName[1] = '~' then 1264 begin 1265 Delete(LogFileName, 1, 1); 1266 nLogOpened := -1 1267 end 1268 else 1269 nLogOpened := CL.State.nLog; 1270 1271 Mode := moPlaying; 1272 LastEndClientCommand := -1; 1273 if (GTestFlags and tfUncover <> 0) or (Difficulty[pTurn] = 0) then 1274 DiscoverAll(pTurn, lObserveSuper) { supervisor - all tiles visible } 1275 else 1276 DiscoverViewAreas(pTurn); 1277 1278 for p1 := 0 to nPl - 1 do 1279 if 1 shl p1 and (GAlive or GWatching) <> 0 then 1280 begin 1281 RecalcPeaceMap(p1); 1282 for ix := 0 to RW[p1].nEnemyUn - 1 do 1283 with RW[p1].EnemyUn[ix] do 1284 emix := RWemix[p1, Owner, mix]; 1285 Inform(p1); 1286 end; 1287 {$IFOPT O-}CheckBorders(-2); {$ENDIF} // for testing only 1288 Notify(ntEndInfo); 1289 if not LoadOK then 1290 begin 1291 NotifyMessage := SavePath + LogFileName; 1292 Notify(ntLoadError); 1293 end; 1294 Brain[bix[0]].Client(cShowGame, 0, nil^); 1295 Notify(ntBackOff); 1296 Inform(pTurn); 1297 ChangeClientWhenDone(cResume, 0, nil^, 0); 1298 end; // LoadGame 1299 1300 procedure InsertTerritoryUpdateCommands; 423 1301 var 424 ix: integer; 1302 p1, Command, Subject: integer; 1303 Data: pointer; 1304 FormerCLState: TCmdListState; 425 1305 begin 426 result:=false; 427 for ix:=0 to RW[p].nUn-1 do with RW[p].Un[ix] do 428 if (Loc>=0) and (SavedStatus<>Status) then result:=true; 429 for ix:=0 to RW[p].nCity-1 do with RW[p].City[ix] do 430 if (Loc>=0) and (SavedStatus<>Status) then result:=true; 431 for ix:=0 to RW[p].nModel-1 do with RW[p].Model[ix] do 432 if SavedStatus<>Status then result:=true; 433 for ix:=0 to RW[p].nEnemyCity-1 do with RW[p].EnemyCity[ix] do 434 if (Loc>=0) and (SavedStatus<>Status) then result:=true; 435 if RW[p].Data<>nil then for ix:=0 to Brain[bix[p]].DataSize-1 do 436 if PDWortList(SavedData[p])[ix]<>PDWortList(RW[p].Data)[ix] then result:=true 437 end; 438 439 procedure InitBrain(bix: integer); 440 var 441 InitModuleData: TInitModuleData; 442 begin 443 assert(bix<>bixSuper_Virtual); 444 with Brain[bix] do 1306 while CL.Progress < 1000 do 445 1307 begin 446 if Initialized then exit; 447 if bix>=bixFirstAI then 448 begin {get client function} 449 Notify(ntInitModule+bix); 450 if Flags and fDotNet>0 then 451 Client:=DotNetClient 1308 FormerCLState := CL.State; 1309 CL.Get(Command, p1, Subject, Data); 1310 if (Command = sIntExpandTerritory) and (p1 = pTurn) then 1311 begin 1312 IntServer(Command, p1, Subject, Data^); 1313 {$IFDEF TEXTLOG}WriteLn(TextLog, 'AfterTurn - ExpandTerritory'); {$ENDIF} 1314 end 452 1315 else 453 begin454 hm:=LoadLibrary(pchar(DLLName));455 if hm=0 then456 begin457 Client:=nil;458 Notify(ntDLLError+bix);459 end460 else461 begin462 Client:=GetProcAddress(hm,'client');463 if @Client=nil then Notify(ntClientError+bix);464 end465 end466 end;467 if @Client<>nil then468 1316 begin 469 Initialized:=true; 470 InitModuleData.Server:=@Server; 471 InitModuleData.DataVersion:=0; 472 InitModuleData.DataSize:=0; 473 InitModuleData.Flags:=0; 474 CallClient(bix, cInitModule, InitModuleData); 475 DataVersion:=InitModuleData.DataVersion; 476 DataSize:=(InitModuleData.DataSize+3) div 4; 477 if DataSize>MaxDataSize then DataSize:=0; 478 Flags:=Flags or InitModuleData.Flags; 479 end 480 end 481 end; 482 483 procedure SaveMap(FileName: string); 484 var 485 i: integer; 486 MapFile: TFileStream; 487 s: string[255]; 488 begin 489 MapFile:=TFileStream.Create(DataDir+'Maps\'+FileName, fmCreate or fmShareExclusive); 490 MapFile.Position:=0; 491 s:='cEvoMap'#0; MapFile.write(s[1],8); {file id} 492 i:=0; MapFile.write(i,4); {format id} 493 MapFile.write(MaxTurn,4); 494 MapFile.write(lx,4); 495 MapFile.write(ly,4); 496 MapFile.write(RealMap,MapSize*4); 497 MapFile.Free; 498 end; 499 500 function LoadMap(FileName: string): boolean; 501 var 502 i,Loc1: integer; 503 MapFile: TFileStream; 504 s: string[255]; 505 begin 506 result:=false; 507 MapFile:=nil; 508 try 509 MapFile:=TFileStream.Create(DataDir+'Maps\'+FileName, fmOpenRead or fmShareExclusive); 510 MapFile.Position:=0; 511 MapFile.read(s[1],8); {file id} 512 MapFile.read(i,4); {format id} 513 if i=0 then 514 begin 515 MapFile.read(i,4); //MaxTurn 516 MapFile.read(lx,4); 517 MapFile.read(ly,4); 518 ly:=ly and not 1; 519 if lx>lxmax then lx:=lxmax; 520 if ly>lymax then ly:=lymax; 521 MapSize:=lx*ly; 522 MapFile.read(RealMap,MapSize*4); 523 for Loc1:=0 to MapSize-1 do 524 begin 525 RealMap[Loc1]:=RealMap[Loc1] and ($7F01FFFF or fPrefStartPos or fStartPos) 526 or ($F shl 27); 527 if RealMap[Loc1] and (fTerrain or fSpecial)=fSwamp or fSpecial2 then 528 RealMap[Loc1]:=RealMap[Loc1] and not (fTerrain or fSpecial) or (fSwamp or fSpecial1); 529 if (RealMap[Loc1] and fDeadLands<>0) and (RealMap[Loc1] and fTerrain<>fArctic) then 530 RealMap[Loc1]:=RealMap[Loc1] and not (fTerrain or fSpecial) or fDesert; 531 end; 532 result:=true; 533 end; 534 MapFile.Free; 535 except 536 if MapFile<>nil then MapFile.Free; 537 end; 538 end; 539 540 procedure SaveGame(FileName: string; auto: boolean); 541 var 542 x,y,i,zero,Tile,nLocal: integer; 543 LogFile: TFileStream; 544 s: string[255]; 545 SaveMap: array[0..lxmax*lymax-1] of Byte; 546 begin 547 nLocal:=0; 548 for i:=0 to nPl-1 do if bix[i]=bixTerm then inc(nLocal); 549 if Difficulty[0]=0 then nLocal:=0; 550 if nLocal<=1 then for y:=0 to ly-1 do for x:=0 to lx-1 do 551 begin 552 Tile:=RW[0].Map[(x+SaveMapCenterLoc+lx shr 1) mod lx +lx*y]; 553 SaveMap[x+lx*y]:=Tile and fTerrain + Tile and (fCity or fUnit or fOwned) shr 16; 554 end; 555 556 if auto and AutoSaveExists then // append to existing file 557 LogFile:=TFileStream.Create(SavePath+FileName, 558 fmOpenReadWrite or fmShareExclusive) 559 else // create new file 560 LogFile:=TFileStream.Create(SavePath+FileName, fmCreate or fmShareExclusive); 561 562 zero:=0; 563 LogFile.Position:=0; 564 s:='cEvoBook'; LogFile.write(s[1],8); {file id} 565 i:=Version; LogFile.write(i,4); {c-evo version} 566 LogFile.write(ExeInfo.Time,4); 567 LogFile.write(lx,4); 568 LogFile.write(ly,4); 569 LogFile.write(LandMass,4); 570 if LandMass=0 then 571 LogFile.write(MapField^,MapSize*4); 572 573 LogFile.write(MaxTurn,4); 574 LogFile.write(RND,4); 575 LogFile.write(GTurn,4); 576 if nLocal>1 then // multiplayer game -- no quick view 577 begin i:=$80; LogFile.write(i,4); end 578 else LogFile.write(SaveMap,((MapSize-1) div 4+1)*4); 579 for i:=0 to nPl-1 do 580 if bix[i]<0 then LogFile.write(zero,4) 581 else 582 begin 583 if bixView[i]>=bixRandom then s:=Brain[bix[i]].FileName 584 else s:=Brain[bixView[i]].FileName; 585 move(zero,s[Length(s)+1],4); 586 LogFile.write(s,(Length(s) div 4+1)*4); 587 LogFile.write(OriginalDataVersion[i],4); 588 s:=''; {behavior} move(zero,s[Length(s)+1],4); 589 LogFile.write(s,(Length(s) div 4+1)*4); 590 LogFile.write(Difficulty[i],4); 591 end; 592 593 if auto and AutoSaveExists then CL.AppendToFile(LogFile, AutoSaveState) 594 else CL.SaveToFile(LogFile); 595 LogFile.Free; 596 if auto then 597 begin AutoSaveState:=CL.State; AutoSaveExists:=true end 598 end; 599 600 procedure StartGame; 601 var 602 i,p,p1,Human,nAlive,bixUni: integer; 603 Game: TNewGameData; 604 //GameEx: TNewGameExData; 605 path: shortstring; 606 BrainUsed: Set of 0..254; {used brains} 607 begin 608 for p1:=0 to nPl-1 do 609 begin 610 if bixView[p1]=bixSuper_Virtual then bix[p1]:=bixTerm // supervisor and local human use same module 611 else if bixView[p1]=bixRandom then 612 if nBrain<=bixFirstAI then bix[p1]:=-1 613 else bix[p1]:=bixFirstAI+random(nBrain-bixFirstAI) 614 else bix[p1]:=bixView[p1]; 615 if bixView[p1]<0 then Difficulty[p1]:=-1; 616 end; 617 618 if bix[0]<>bixNoTerm then Notify(ntInitLocalHuman); 619 BrainUsed:=[]; 620 for p:=0 to nPl-1 do 621 if (bix[p]>=0) and ((Mode<>moMovie) or (p=0)) then 622 begin {initiate selected control module} 623 AIInfo[p]:=Brain[bix[p]].Name+#0; 624 InitBrain(bix[p]); 625 if Mode=moPlaying then 626 begin // new game, this data version is original 627 OriginalDataVersion[p]:=Brain[bix[p]].DataVersion; 628 ProcessClientData[p]:=true; 629 end 630 else // loading game, compare with data version read from file 631 ProcessClientData[p]:=ProcessClientData[p] 632 and (OriginalDataVersion[p]=Brain[bix[p]].DataVersion); 633 if @Brain[bix[p]].Client=nil then // client function not found 634 if bix[0]=bixNoTerm then 635 bix[p]:=-1 636 else 637 begin 638 bix[p]:=bixTerm; 639 OriginalDataVersion[p]:=-1; 640 ProcessClientData[p]:=false; 641 end; 642 if bix[p]>=0 then include(BrainUsed,bix[p]) 643 end; 644 645 Notify(ntCreateWorld); 646 nAlive:=0; 647 GAlive:=0; 648 if Mode=moMovie then GWatching:=1 649 else GWatching:=0; 650 GAI:=0; 651 for p1:=0 to nPl-1 do if bix[p1]>=0 then 652 begin 653 if Mode<>moMovie then inc(GWatching,1 shl p1); 654 if bix[p1]>=bixFirstAI then inc(GAI,1 shl p1); 655 if Difficulty[p1]>0 then 656 begin inc(GAlive,1 shl p1); inc(nAlive); end; 657 ServerVersion[p1]:=Brain[bix[p1]].ServerVersion; 658 end; 659 WinOnAlone:= (bix[0]=bixNoTerm) and (nAlive>1); 660 GWinner:=0; 661 GColdWarStart:=-ColdWarTurns-1; 662 uixSelectedTransport:=-1; 663 SpyMission:=smSabotageProd; 664 for p1:=0 to nPl-1 do 665 DebugMap[p1]:=nil; 666 667 GTurn:=0; 668 for i:=0 to 27 do with GWonder[i] do 669 begin CityID:=-1; EffectiveOwner:=-1 end; 670 FillChar(GShip,SizeOf(GShip),0); 671 672 for p:=0 to nPl-1 do if 1 shl p and (GAlive or GWatching)<>0 then with RW[p] do 673 begin 674 Government:=gDespotism; 675 Money:=StartMoney; 676 TaxRate:=30; 677 LuxRate:=0; 678 Research:=0; 679 ResearchTech:=-2; 680 AnarchyStart:=-AnarchyTurns-1; 681 Happened:=0; 682 LastValidStat[p]:=-1; 683 Worked[p]:=0; 684 Founded[p]:=0; 685 DevModelTurn[p]:=-1; 686 OracleIncome:=0; 687 688 if Brain[bix[p]].DataSize>0 then 689 begin 690 GetMem(SavedData[p], Brain[bix[p]].DataSize*4); 691 GetMem(Data, Brain[bix[p]].DataSize*4); 692 FillChar(SavedData[p]^,Brain[bix[p]].DataSize*4,0); 693 FillChar(Data^,Brain[bix[p]].DataSize*4,0); 694 end 695 else begin Data:=nil; SavedData[p]:=nil end; 696 nBattleHistory:=0; 697 BattleHistory:=nil; 698 {if bix[p]=bixTerm then 699 begin 700 GetMem(BorderHelper,MapSize); 701 FillChar(BorderHelper^,MapSize,0); 702 end 703 else} BorderHelper:=nil; 704 for i:=0 to nStat-1 do GetMem(Stat[i,p],4*(MaxTurn+1)); 705 if Brain[bix[p]].Flags and fDotNet<>0 then 706 begin 707 GetMem(RW[p].DefaultDebugMap, MapSize*4); 708 FillChar(RW[p].DefaultDebugMap^, MapSize*4, 0); 709 DebugMap[p]:=RW[p].DefaultDebugMap; 710 end 711 else RW[p].DefaultDebugMap:=nil; 712 713 {!!!for i:=0 to nShipPart-1 do GShip[p].Parts[i]:=random((3-i)*2);{} 714 end; 715 716 if LandMass>0 then 717 begin // random map 718 InitRandomGame; 719 PreviewElevation:=false; 720 MapField:=nil; 721 end 722 else 723 begin // predefined map 724 if Mode=moPlaying then 725 LoadMap(MapFileName); // new game -- load map from file 726 GetMem(MapField,MapSize*4); 727 move(RealMap,MapField^,MapSize*4); 728 Human:=0; 729 for p1:=0 to nPl-1 do if bix[p1]=bixTerm then inc(Human,1 shl p1); 730 InitMapGame(Human); 731 end; 732 CityProcessing.InitGame; 733 UnitProcessing.InitGame; 734 for p:=0 to nPl-1 do if 1 shl p and (GAlive or GWatching)<>0 then 735 Inform(p); 736 737 pTurn:=-1; 738 if bix[0]<>bixNoTerm then 739 Notify(ntInitLocalHuman); 740 Game.lx:=lx; Game.ly:=ly; Game.LandMass:=LandMass; Game.MaxTurn:=MaxTurn; 741 move(Difficulty,Game.Difficulty,SizeOf(Difficulty)); 742 //GameEx.lx:=lx; GameEx.ly:=ly; GameEx.LandMass:=LandMass; 743 //GameEx.MaxTurn:=MaxTurn; GameEx.RND:=RND; 744 //move(Difficulty,GameEx.Difficulty,SizeOf(Difficulty)); 745 AICredits:=''; 746 for i:=0 to nBrain-1 do if Brain[i].Initialized then 747 if i in BrainUsed then 748 begin 749 if i>=bixFirstAI then 750 Notify(ntInitPlayers); 751 for p:=0 to nPl-1 do 752 begin 753 if bix[p]=i then 754 Game.RO[p]:=@RW[p] 755 else Game.RO[p]:=nil; 756 if (i=bixTerm) and (Difficulty[0]=0) and (bix[p]>=0) then 757 Game.SuperVisorRO[p]:=@RW[p] 758 else Game.SuperVisorRO[p]:=nil; 759 end; 760 if Brain[i].Flags and fDotNet>0 then 761 begin 762 path:=Brain[i].DLLName; 763 move(path[1], Game.AssemblyPath, Length(path)); 764 Game.AssemblyPath[Length(path)]:=#0; 765 end 766 else Game.AssemblyPath[0]:=#0; 767 case Mode of 768 moLoading, moLoading_Fast: CallClient(i, cLoadGame, Game); 769 moMovie: CallClient(i, cMovie, Game); 770 moPlaying: CallClient(i, cNewGame, Game); 771 end; 772 if (i>=bixFirstAI) and (Brain[i].Credits<>'') then 773 if AICredits='' then AICredits:=Brain[i].Credits 774 else AICredits:=AICredits+'\'+Brain[i].Credits 775 end 776 else 777 begin {module no longer used -- unload} 778 CallClient(i, cReleaseModule, nil^); 779 if i>=bixFirstAI then 780 begin 781 if Brain[i].Flags and fDotNet=0 then 782 FreeLibrary(Brain[i].hm); 783 Brain[i].Client:=nil; 784 end; 785 Brain[i].Initialized:=false; 786 end; 787 AICredits:=AICredits+#0; 788 789 if bix[0]<>bixNoTerm then 790 begin 791 // uni ai? 792 bixUni:=-1; 793 for p1:=0 to nPl-1 do if bix[p1]>=bixFirstAI then 794 if bixUni=-1 then bixUni:=bix[p1] 795 else if bixUni<>bix[p1] then bixUni:=-2; 796 for p1:=0 to nPl-1 do if bix[p1]>=bixFirstAI then 797 begin 798 if bixUni=-2 then NotifyMessage:=Brain[bix[p1]].FileName 799 else NotifyMessage:=''; 800 Notify(ntSetAIName+p1); 1317 CL.State := FormerCLState; 1318 Break 801 1319 end 802 1320 end; 803 804 CheckBorders(-1); 805 {$IFOPT O-}InvalidTreatyMap:=0;{$ENDIF} 806 AutoSaveExists:=false; 807 pDipActive:=-1; 808 pTurn:=0; 809 810 if Mode>=moMovie then 1321 {$IFOPT O-}InvalidTreatyMap := 0; {$ENDIF} 1322 end; 1323 1324 procedure StartNewGame(const Path, FileName, Map: string; 1325 Newlx, Newly, NewLandMass, NewMaxTurn: integer); 1326 var 1327 p: integer; 1328 begin 1329 Notify(ntStartDone); 1330 SavePath := Path; 1331 LogFileName := FileName; 1332 MapFileName := Map; 1333 if FastContact then 1334 begin 1335 lx := 24; 1336 ly := 42; 1337 end 1338 else 1339 begin 1340 lx := Newlx; 1341 ly := Newly 1342 end; 1343 MapSize := lx * ly; 1344 if MapFileName <> '' then 1345 LandMass := 0 1346 else 1347 LandMass := NewLandMass; 1348 MaxTurn := NewMaxTurn; 1349 Randomize; 1350 RND := RandSeed; 1351 Mode := moPlaying; 1352 CL := TCmdList.Create; 1353 StartGame; 1354 NoLogChanges; 1355 for p := 0 to nPl - 1 do 1356 if bix[p] >= 0 then 1357 CallPlayer(cGetReady, p, nil^); 1358 LogChanges; 1359 CL.Put(sTurn, 0, 0, nil); 1360 BeforeTurn0; 1361 NoLogCityTileChanges; 1362 GenerateStat(pTurn); 1363 nLogOpened := -1; 1364 LastEndClientCommand := -1; 1365 Brain[bix[0]].Client(cShowGame, 0, nil^); 1366 Notify(ntBackOff); 1367 Inform(pTurn); 1368 ChangeClientWhenDone(cTurn, 0, nil^, 0) 1369 end; 1370 1371 procedure DirectHelp(Command: integer); 1372 begin 1373 InitBrain(bixTerm); 1374 Brain[bixTerm].Client(Command, -1, nil^); 1375 AICredits := #0; 1376 end; 1377 1378 procedure EditMap(const Map: string; Newlx, Newly, NewLandMass: integer); 1379 var 1380 p1, Loc1: integer; 1381 Game: TNewGameData; 1382 begin 1383 Notify(ntStartDone); 1384 Notify(ntInitLocalHuman); 1385 MapFileName := Map; 1386 lx := Newlx; 1387 ly := Newly; 1388 MapSize := lx * ly; 1389 LandMass := NewLandMass; 1390 bix[0] := bixTerm; 1391 Difficulty[0] := 0; 1392 InitBrain(bixTerm); 1393 1394 Randomize; 1395 GAlive := 0; 1396 GWatching := 1; 1397 if not LoadMap(MapFileName) then 1398 for Loc1 := 0 to MapSize - 1 do 1399 RealMap[Loc1] := fOcean or ($F shl 27); 1400 CL := nil; 1401 InitMapEditor; 1402 RW[0].Data := nil; 1403 RW[0].BorderHelper := nil; 1404 RW[0].Alive := 0; 1405 Game.lx := lx; 1406 Game.ly := ly; 1407 Game.RO[0] := @RW[0]; 1408 Game.Difficulty[0] := 0; 1409 for p1 := 1 to nPl - 1 do 1410 begin 1411 Game.RO[p1] := nil; 1412 Game.Difficulty[p1] := -1 1413 end; 1414 Brain[bixTerm].Client(cNewMap, -1, Game); 1415 1416 DiscoverAll(0, lObserveSuper); 811 1417 Notify(ntEndInfo); 812 end;{StartGame} 813 814 procedure EndGame; 1418 Brain[bix[0]].Client(cShowGame, 0, nil^); 1419 Notify(ntBackOff); 1420 ChangeClientWhenDone(cEditMap, 0, nil^, 0) 1421 end; 1422 1423 procedure DestroySpacePort_TellPlayers(p, pCapturer: integer); 815 1424 var 816 i,p1: integer; 1425 cix, i, p1: integer; 1426 ShowShipChange: TShowShipChange; 817 1427 begin 818 if LandMass=0 then FreeMem(MapField); 819 for p1:=0 to nPl-1 do if bix[p1]>=0 then 1428 // stop ship part production 1429 for cix := 0 to RW[p].nCity - 1 do 1430 with RW[p].City[cix] do 1431 if (Loc >= 0) and (Project and cpImp <> 0) and 1432 ((Project and cpIndex = woMIR) or 1433 (Imp[Project and cpIndex].Kind = ikShipPart)) then 1434 begin 1435 inc(RW[p].Money, Prod0); 1436 Prod := 0; 1437 Prod0 := 0; 1438 Project := cpImp + imTrGoods; 1439 Project0 := cpImp + imTrGoods 1440 end; 1441 1442 // destroy ship 1443 with GShip[p] do 1444 if Parts[0] + Parts[1] + Parts[2] > 0 then 1445 begin 1446 for i := 0 to nShipPart - 1 do 1447 begin 1448 ShowShipChange.Ship1Change[i] := -Parts[i]; 1449 if pCapturer >= 0 then 1450 begin 1451 ShowShipChange.Ship2Change[i] := Parts[i]; 1452 inc(GShip[pCapturer].Parts[i], Parts[i]); 1453 end; 1454 Parts[i] := 0; 1455 end; 1456 if Mode >= moMovie then 1457 begin 1458 if pCapturer >= 0 then 1459 ShowShipChange.Reason := scrCapture 1460 else 1461 ShowShipChange.Reason := scrDestruction; 1462 ShowShipChange.Ship1Owner := p; 1463 ShowShipChange.Ship2Owner := pCapturer; 1464 for p1 := 0 to nPl - 1 do 1465 if 1 shl p1 and (GAlive or GWatching) <> 0 then 1466 begin 1467 move(GShip, RW[p1].Ship, SizeOf(GShip)); 1468 if 1 shl p1 and GWatching <> 0 then 1469 CallPlayer(cShowShipChange, p1, ShowShipChange); 1470 end; 1471 end 1472 end 1473 end; 1474 1475 procedure DestroyCity_TellPlayers(p, cix: integer; SaveUnits: boolean); 1476 begin 1477 if RW[p].City[cix].built[imSpacePort] > 0 then 1478 DestroySpacePort_TellPlayers(p, -1); 1479 DestroyCity(p, cix, SaveUnits); 1480 end; 1481 1482 procedure ChangeCityOwner_TellPlayers(pOld, cixOld, pNew: integer); 1483 begin 1484 if RW[pOld].City[cixOld].built[imSpacePort] > 0 then 1485 if RW[pNew].NatBuilt[imSpacePort] > 0 then 1486 DestroySpacePort_TellPlayers(pOld, pNew) 1487 else 1488 DestroySpacePort_TellPlayers(pOld, -1); 1489 ChangeCityOwner(pOld, cixOld, pNew); 1490 end; 1491 1492 procedure CheckWin(p: integer); 1493 var 1494 i: integer; 1495 ShipComplete: boolean; 1496 begin 1497 ShipComplete := true; 1498 for i := 0 to nShipPart - 1 do 1499 if GShip[p].Parts[i] < ShipNeed[i] then 1500 ShipComplete := false; 1501 if ShipComplete then 1502 GWinner := GWinner or 1 shl p; // game won! 1503 end; 1504 1505 procedure BeforeTurn; 1506 var 1507 i, p1, uix, cix, V21, Loc1, Cost, Job0, nAlive, nAppliers, ad, OldLoc, 1508 SiegedTiles, nUpdateLoc: integer; 1509 UpdateLoc: array [0 .. numax - 1] of integer; 1510 Radius: TVicinity21Loc; 1511 ShowShipChange: TShowShipChange; 1512 TribeExtinct, JobDone, MirBuilt: boolean; 1513 begin 1514 {$IFOPT O-}assert(1 shl pTurn and InvalidTreatyMap = 0); {$ENDIF} 1515 assert(1 shl pTurn and (GAlive or GWatching) <> 0); 1516 if (1 shl pTurn and GAlive = 0) and (Difficulty[pTurn] > 0) then 1517 exit; 1518 1519 if (GWonder[woGrLibrary].EffectiveOwner = pTurn) and (GWinner = 0) then 1520 begin // check great library effect 1521 nAlive := 0; 1522 for p1 := 0 to nPl - 1 do 1523 if 1 shl p1 and GAlive <> 0 then 1524 inc(nAlive); 1525 for ad := 0 to nAdv - 5 do 1526 if RW[pTurn].Tech[ad] < tsSeen then 1527 begin 1528 nAppliers := 0; 1529 for p1 := 0 to nPl - 1 do 1530 if (p1 <> pTurn) and (1 shl p1 and GAlive <> 0) and 1531 (RW[p1].Tech[ad] >= tsApplicable) then 1532 inc(nAppliers); 1533 if nAppliers * 2 > nAlive then 1534 begin 1535 SeeTech(pTurn, ad); 1536 inc(nTech[pTurn]); 1537 if Mode >= moMovie then 1538 CallPlayer(cShowGreatLibTech, pTurn, ad); 1539 // do not call CallPlayer(pTurn) while map is invalid 1540 end; 1541 end; 1542 end; 1543 1544 MaskD(ObserveLevel, MapSize, not Cardinal(3 shl (2 * pTurn))); 1545 if Mode > moLoading_Fast then 1546 MaskD(RW[pTurn].Map^, MapSize, not Cardinal(fUnit or fHiddenUnit or 1547 fStealthUnit or fObserved or fSpiedOut or fOwned or fOwnZoCUnit or 1548 fInEnemyZoC)); 1549 RW[pTurn].nEnemyUn := 0; 1550 1551 MirBuilt := false; 1552 if (Difficulty[pTurn] > 0) and (GWinner = 0) then 1553 with RW[pTurn] do 1554 begin 1555 if nCity > 0 then 1556 for p1 := 0 to nPl - 1 do 1557 if GTurn = EvaStart[p1] + PeaceEvaTurns then 1558 begin // peace contract -- remove all units from p1's territory 1559 Loc1 := City[0].Loc; // search destination for homeless units 1560 for cix := 1 to nCity - 1 do 1561 if (City[cix].Loc >= 0) and 1562 ((Loc1 < 0) or (City[cix].built[imPalace] > 0)) then 1563 Loc1 := City[cix].Loc; 1564 for uix := 0 to nUn - 1 do 1565 with Un[uix] do 1566 if (Loc >= 0) and (Model[mix].Kind <> mkDiplomat) and 1567 ((Home >= 0) or (Loc1 >= 0)) and 1568 (RealMap[Loc] shr 27 = Cardinal(p1)) then 1569 begin 1570 OldLoc := Loc; 1571 if Master >= 0 then 1572 begin // transport unload 1573 if Model[mix].Domain = dAir then 1574 dec(Un[Master].AirLoad) 1575 else 1576 dec(Un[Master].TroopLoad); 1577 Master := -1; 1578 end 1579 else 1580 FreeUnit(pTurn, uix); 1581 1582 if Home >= 0 then 1583 Loc := City[Home].Loc 1584 else 1585 Loc := Loc1; 1586 PlaceUnit(pTurn, uix); 1587 UpdateUnitMap(OldLoc); 1588 UpdateUnitMap(Loc); 1589 Flags := Flags or unWithdrawn; 1590 Happened := Happened or phPeaceEvacuation; 1591 end 1592 end; 1593 1594 if Mode >= moMovie then 1595 FillChar(ShowShipChange, SizeOf(ShowShipChange), 0); 1596 TribeExtinct := true; 1597 nUpdateLoc := 0; 1598 for cix := 0 to nCity - 1 do 1599 with City[cix] do 1600 if Loc >= 0 then 1601 begin { next turn for all cities - city loop 1 } 1602 // if ServerVersion[pTurn]>=$000EF0 then 1603 // Flags:=Flags and (chFounded or chCaptured or chProductionSabotaged or chDisorder) 1604 // else Flags:=Flags and (chCaptured or chProductionSabotaged or chDisorder); 1605 // check for siege 1606 SiegedTiles := 0; 1607 V21_to_Loc(Loc, Radius); 1608 for V21 := 1 to 26 do 1609 if Tiles and (1 shl V21) and not(1 shl CityOwnTile) <> 0 then 1610 begin 1611 Loc1 := Radius[V21]; 1612 assert((Loc1 >= 0) and (Loc1 < MapSize) and 1613 (UsedByCity[Loc1] = Loc)); 1614 p1 := RealMap[Loc1] shr 27; 1615 if (RealMap[Loc1] and fCity <> 0) or (p1 < nPl) and 1616 (p1 <> pTurn) and (RW[pTurn].Treaty[p1] >= trPeace) or 1617 (ZoCMap[Loc1] > 0) and (Occupant[Loc1] <> pTurn) and 1618 (Treaty[Occupant[Loc1]] < trPeace) then 1619 begin 1620 Tiles := Tiles and not(1 shl V21); 1621 UsedByCity[Loc1] := -1; 1622 Flags := Flags or chSiege; 1623 inc(SiegedTiles); 1624 end; 1625 end; 1626 while SiegedTiles > 0 do // replace sieged tiles 1627 begin 1628 if not AddBestCityTile(pTurn, cix) then 1629 Break; 1630 dec(SiegedTiles); 1631 end; 1632 1633 if Flags and chFounded = 0 then 1634 begin 1635 // CollectCityResources(pTurn,cix); // old style 1636 1637 if CityTurn(pTurn, cix) then 1638 TribeExtinct := false 1639 else 1640 begin // city is erased 1641 RemoveDomainUnits(dSea, pTurn, Loc); 1642 RemoveDomainUnits(dAir, pTurn, Loc); 1643 Map[Loc] := Map[Loc] and not fCity; // !!! do this in inner core 1644 UpdateLoc[nUpdateLoc] := Loc; 1645 inc(nUpdateLoc); 1646 DestroyCity_TellPlayers(pTurn, cix, true); 1647 end; 1648 1649 if (Flags and chProduction <> 0) and (Project0 and cpImp <> 0) 1650 then 1651 begin 1652 if Project0 and cpIndex = woMIR then // MIR completed 1653 MirBuilt := true 1654 else if Project0 and cpIndex = woManhattan then 1655 GColdWarStart := GTurn 1656 else if Imp[Project0 and cpIndex].Kind = ikShipPart 1657 then { ship parts produced } 1658 inc(ShowShipChange.Ship1Change[Project0 and cpIndex - 1659 imShipComp]); 1660 end 1661 end 1662 end; { city loop 1 } 1663 if nUpdateLoc > 0 then 1664 begin 1665 CheckBorders(-1, pTurn); 1666 for i := 0 to nUpdateLoc - 1 do 1667 UpdateUnitMap(UpdateLoc[i], true); 1668 if Mode >= moMovie then 1669 for p1 := 0 to nPl - 1 do 1670 if (1 shl p1 and GWatching <> 0) and (p1 <> pTurn) then 1671 for i := 0 to nUpdateLoc - 1 do 1672 if ObserveLevel[UpdateLoc[i]] shr (2 * p1) and 3 >= lObserveUnhidden 1673 then 1674 CallPlayer(cShowCityChanged, p1, UpdateLoc[i]); 1675 end; 1676 1677 for uix := 0 to nUn - 1 do 1678 with Un[uix] do 1679 if Loc >= 0 then 1680 begin // unit loop 2 1681 if Health < 100 then 1682 Recover(pTurn, uix); 1683 1684 if Flags and unMountainDelay <> 0 then 1685 begin 1686 Movement := 0; 1687 Flags := Flags and not unMountainDelay 1688 end 1689 else 1690 Movement := UnitSpeed(pTurn, mix, Health); { refresh movement } 1691 1692 assert(Loc >= 0); 1693 if Model[mix].Kind <> mkDiplomat then 1694 begin // check treaty violation 1695 p1 := RealMap[Loc] shr 27; 1696 if (p1 < nPl) and (p1 <> pTurn) and (Treaty[p1] >= trPeace) then 1697 begin 1698 if (Job in [jCity, jPillage, jClear, jAfforest, jTrans]) or 1699 (Job in [jIrr, jMine, jFort, jBase]) and 1700 (RealMap[Loc] and fTerImp <> 0) then 1701 Job := jNone; 1702 if (GTurn > EvaStart[p1] + PeaceEvaTurns) and 1703 (Treaty[p1] <> trAlliance) then 1704 begin 1705 EvaStart[p1] := GTurn; 1706 Happened := Happened or phPeaceViolation; 1707 if Mode >= moMovie then 1708 CallPlayer(cShowPeaceViolation, p1, pTurn); 1709 end; 1710 end; 1711 end; 1712 1713 if ServerVersion[pTurn] >= $000EF0 then 1714 begin 1715 if (Health <= 0) or TribeExtinct then 1716 RemoveUnit_UpdateMap(pTurn, uix); 1717 end 1718 end; 1719 1720 if ServerVersion[pTurn] < $000EF0 then 1721 for uix := 0 to nUn - 1 do 1722 with Un[uix] do 1723 if Loc >= 0 then 1724 begin // unit loop 3 1725 Loc1 := Loc; 1726 Job0 := Job; 1727 if Job <> jNone then 1728 JobDone := Work(pTurn, uix); 1729 { settlers do terrain improvement jobs } 1730 if (Health <= 0) or TribeExtinct then 1731 RemoveUnit_UpdateMap(pTurn, uix); 1732 1733 if (Job0 = jCity) and JobDone then // new city 1734 begin 1735 AddBestCityTile(pTurn, RW[pTurn].nCity - 1); 1736 UpdateUnitMap(Loc1, true); 1737 if Mode >= moMovie then // tell enemies 1738 for p1 := 0 to nPl - 1 do 1739 if (1 shl p1 and GWatching <> 0) and (p1 <> pTurn) and 1740 (ObserveLevel[Loc1] and (3 shl (2 * p1)) > 0) then 1741 CallPlayer(cShowCityChanged, p1, Loc1); 1742 end 1743 end; 1744 1745 { pollution - city loop 3 } 1746 for cix := 0 to nCity - 1 do 1747 with City[cix] do 1748 if (Loc >= 0) and (Pollution >= MaxPollution) then 1749 Pollute(pTurn, cix); 1750 1751 CompactLists(pTurn); 1752 if (nUn = 0) and (nCity = 0) then 1753 begin // nation made extinct 1754 Happened := Happened or phExtinct; 1755 GAlive := GAlive and not(1 shl pTurn); 1756 Stat[stPop, pTurn, GTurn] := 0; 1757 Stat[stMil, pTurn, GTurn] := 0; 1758 Stat[stScience, pTurn, GTurn] := 0; 1759 Stat[stExplore, pTurn, GTurn] := 0; 1760 Stat[stTerritory, pTurn, GTurn] := 0; 1761 Stat[stWork, pTurn, GTurn] := 0; 1762 for p1 := 0 to nPl - 1 do 1763 if 1 shl p1 and (GAlive or GWatching) <> 0 then 1764 begin 1765 if p1 <> pTurn then 1766 begin 1767 GiveCivilReport(p1, pTurn); 1768 if (GTestFlags and tfUncover <> 0) or (Difficulty[p1] = 0) or 1769 (RW[p1].Treaty[pTurn] = trAlliance) then 1770 GiveMilReport(p1, pTurn); 1771 end; 1772 with RW[p1] do 1773 begin 1774 Alive := GAlive; 1775 for Loc1 := 0 to MapSize - 1 do 1776 if Territory[Loc1] = pTurn then 1777 // remove territory of extinct nation from player maps 1778 begin 1779 Territory[Loc1] := -1; 1780 Map[Loc1] := Map[Loc1] and not fPeace 1781 end 1782 end; 1783 end; 1784 exit 1785 end; 1786 1787 // check research 1788 Cost := TechCost(pTurn); 1789 if GTestFlags and tfImmAdvance <> 0 then 1790 Research := Cost; 1791 if (Happened and phTech = 0) and (Research >= Cost) then 1792 begin 1793 if ResearchTech = adMilitary then 1794 EnableDevModel(pTurn) { new Unit class initiated } 1795 else if ResearchTech >= 0 then 1796 DiscoverTech(pTurn, ResearchTech); 1797 1798 dec(Research, Cost); 1799 Happened := Happened or phTech; 1800 ResearchTech := -1 1801 end 1802 else if (ResearchTech = -2) and (nCity > 0) then 1803 begin 1804 Happened := Happened or phTech; 1805 ResearchTech := -1 1806 end; 1807 1808 if Credibility < MaxCredibility then 1809 for p1 := 0 to nPl - 1 do 1810 if (p1 <> pTurn) and (1 shl p1 and GAlive <> 0) and 1811 (Treaty[p1] >= trPeace) then 1812 begin 1813 inc(Credibility); 1814 Break 1815 end; 1816 1817 if GWinner = 0 then 1818 CheckWin(pTurn); 1819 if (Mode >= moMovie) and (GWinner = 0) and 1820 ((ShowShipChange.Ship1Change[0] > 0) or 1821 (ShowShipChange.Ship1Change[1] > 0) or 1822 (ShowShipChange.Ship1Change[2] > 0)) then 1823 begin 1824 ShowShipChange.Reason := scrProduction; 1825 ShowShipChange.Ship1Owner := pTurn; 1826 ShowShipChange.Ship2Owner := -1; 1827 for p1 := 0 to nPl - 1 do 1828 if (p1 <> pTurn) and (1 shl p1 and (GAlive or GWatching) <> 0) then 1829 begin 1830 move(GShip, RW[p1].Ship, SizeOf(GShip)); 1831 if 1 shl p1 and GWatching <> 0 then 1832 CallPlayer(cShowShipChange, p1, ShowShipChange); 1833 end 1834 end; 1835 if WinOnAlone and (GAlive and not(1 shl pTurn or 1) = 0) then 1836 GWinner := 1 shl pTurn; // break if only one nation left 1837 1838 if GTurn = AnarchyStart + AnarchyTurns then 1839 begin 1840 AnarchyStart := -AnarchyTurns - 1; 1841 Government := gDespotism; 1842 for p1 := 0 to nPl - 1 do 1843 if (p1 <> pTurn) and ((GAlive or GWatching) and (1 shl p1) <> 0) then 1844 RW[p1].EnemyReport[pTurn].Government := gDespotism; 1845 inc(Happened, phChangeGov) 1846 end; 1847 end; // if Difficulty[pTurn]>0 1848 1849 if (pTurn = 0) and (GWinner > 0) then 1850 begin // game over, give world map and all reports to player 0 1851 DiscoverAll(pTurn, lObserveSuper); 1852 for p1 := 1 to nPl - 1 do 1853 if 1 shl p1 and GAlive <> 0 then 1854 begin 1855 if RW[pTurn].Treaty[p1] < trNone then 1856 begin 1857 RW[pTurn].Treaty[p1] := trNone; 1858 RW[p1].Treaty[pTurn] := trNone; 1859 end; 1860 GiveCivilReport(pTurn, p1); 1861 GiveMilReport(pTurn, p1); 1862 end; 1863 end 1864 else 820 1865 begin 821 for i:=0 to nStat-1 do FreeMem(Stat[i,p1]); 822 if RW[p1].BattleHistory<>nil then FreeMem(RW[p1].BattleHistory); 823 {if RW[p1].BorderHelper<>nil then FreeMem(RW[p1].BorderHelper);} 824 FreeMem(RW[p1].Data); 825 FreeMem(SavedData[p1]); 826 if RW[p1].DefaultDebugMap<>nil then 827 FreeMem(RW[p1].DefaultDebugMap); 828 end; 829 UnitProcessing.ReleaseGame; 830 CityProcessing.ReleaseGame; 831 Database.ReleaseGame; 832 CL.Free; 833 end; 834 835 procedure GenerateStat(p: integer); 836 var 837 cix,uix: integer; 838 begin 839 if Difficulty[p]>0 then with RW[p] do 840 begin 841 Stat[stPop,p,GTurn]:=0; 842 for cix:=0 to nCity-1 do if City[cix].Loc>=0 then 843 inc(Stat[stPop,p,GTurn],City[cix].Size); 844 Stat[stScience,p,GTurn]:=Researched[p]*50; 845 if (RW[p].ResearchTech>=0) and (RW[p].ResearchTech<>adMilitary) then 846 inc(Stat[stScience,p,GTurn], 847 Research*100 div TechBaseCost(nTech[p],Difficulty[p])); 848 Stat[stMil,p,GTurn]:=0; 849 for uix:=0 to nUn-1 do if Un[uix].Loc>=0 then 850 with Model[Un[uix].mix] do 851 begin 852 if (Kind<=mkEnemyDeveloped) and (Un[uix].mix<>1) then 853 inc(Stat[stMil,p,GTurn],Weight*MStrength*Un[uix].Health div 100) 854 else if Domain=dGround then inc(Stat[stMil,p,GTurn],(Attack+2*Defense)*Un[uix].Health div 100) 855 else inc(Stat[stMil,p,GTurn],(Attack+Defense)*Un[uix].Health div 100); 856 case Kind of 857 mkSlaves: inc(Stat[stPop,p,GTurn]); 858 mkSettler: inc(Stat[stPop,p,GTurn],2); 859 end; 860 end; 861 Stat[stMil,p,GTurn]:=Stat[stMil,p,GTurn] div 16; 862 Stat[stExplore,p,GTurn]:=Discovered[p]; 863 Stat[stTerritory,p,GTurn]:=TerritoryCount[p]; 864 Stat[stWork,p,GTurn]:=Worked[p]; 865 LastValidStat[p]:=GTurn; 866 end; 867 end; 868 869 procedure LogCityTileChanges; 870 var 871 cix: integer; 872 begin 873 for cix:=0 to RW[pTurn].nCity-1 do 874 with RW[pTurn].City[cix] do if Loc>=0 then 1866 // show observed areas 1867 if (GTestFlags and tfUncover <> 0) or (Difficulty[pTurn] = 0) 1868 then { supervisor - all tiles visible } 875 1869 begin 876 { if SavedResourceWeights[cix]<>ResourceWeights then 877 begin // log city resource weight changes 878 CL.Put(sSetCityResourceWeights, pTurn, cix, @ResourceWeights); 879 SavedResourceWeights[cix]:=ResourceWeights; 880 end;} 881 if SavedTiles[cix]<>Tiles then 882 begin // log city tile changes 883 CL.Put(sSetCityTiles, pTurn, cix, @Tiles); 884 SavedTiles[cix]:=Tiles; 885 end; 886 end; 887 end; 888 889 procedure NoLogCityTileChanges; 890 var 891 cix: integer; 892 begin 893 for cix:=0 to RW[pTurn].nCity-1 do 894 with RW[pTurn].City[cix] do if Loc>=0 then 1870 if (bix[pTurn] <> bixNoTerm) and 1871 ((Difficulty[pTurn] > 0) or (Mode > moLoading_Fast)) then 1872 DiscoverAll(pTurn, lObserveSuper) 1873 end 1874 else 895 1875 begin 896 // SavedResourceWeights[cix]:=ResourceWeights; 897 SavedTiles[cix]:=Tiles; 898 end; 899 end; 900 901 function HasCityTileChanges: boolean; 902 var 903 cix: integer; 904 begin 905 result:=false; 906 for cix:=0 to RW[pTurn].nCity-1 do 907 with RW[pTurn].City[cix] do if Loc>=0 then 908 begin 909 // if SavedResourceWeights[cix]<>ResourceWeights then result:=true; 910 if SavedTiles[cix]<>Tiles then result:=true; 911 end; 912 end; 913 914 procedure BeforeTurn0; 915 var 916 p1,uix: integer; 917 begin 918 for uix:=0 to RW[pTurn].nUn-1 do {init movement points for first turn} 919 with RW[pTurn].Un[uix] do Movement:=RW[pTurn].Model[mix].Speed; 920 921 if Difficulty[pTurn]>0 then 922 DiscoverViewAreas(pTurn) 923 else {supervisor} 924 begin 925 DiscoverAll(pTurn,lObserveSuper); 926 for p1:=1 to nPl-1 do 927 if 1 shl p1 and GAlive<>0 then 928 begin 929 GiveCivilReport(pTurn, p1); 930 GiveMilReport(pTurn, p1) 931 end; 932 end; 933 //CheckContact; 934 end; 935 936 function LoadGame(const Path, FileName: string; Turn: integer; MovieMode: boolean): boolean; 937 var 938 i,j,ix,d,p1,Command,Subject: integer; 939 {$IFDEF TEXTLOG}LoadPos0: integer;{$ENDIF} 940 Data: pointer; 941 LogFile: TFileStream; 942 FormerCLState: TCmdListState; 943 s: string[255]; 944 SaveMap: array[0..lxmax*lymax-1] of Byte; 945 started,StatRequest: boolean; 946 begin 947 SavePath:=Path; 948 LogFileName:=FileName; 949 LoadTurn:=Turn; 950 LogFile:=TFileStream.Create(SavePath+LogFileName,fmOpenRead or fmShareExclusive); 951 LogFile.Position:=0; 952 LogFile.read(s[1],8); {file id} 953 LogFile.read(i,4); {c-evo version} 954 LogFile.read(j,4); {exe time} 955 956 if (i>=FirstBookCompatibleVersion) and (i<=Version) then 957 begin 958 result:=true; 959 LogFile.read(lx,4); 960 LogFile.read(ly,4); 961 MapSize:=lx*ly; 962 LogFile.read(LandMass,4); 963 if LandMass=0 then 964 LogFile.read(RealMap,MapSize*4); // use predefined map 965 LogFile.read(MaxTurn,4); 966 LogFile.read(RND,4); 967 LogFile.read(GTurn,4); 968 LogFile.read(SaveMap,4); 969 if SaveMap[0]<>$80 then 970 LogFile.read(SaveMap[4],((MapSize-1) div 4+1)*4-4); 971 for p1:=0 to nPl-1 do 972 begin 973 LogFile.read(s[0],4); 974 if s[0]=#0 then bixView[p1]:=-1 975 else 976 begin 977 LogFile.read(s[4],Byte(s[0]) div 4 *4); 978 LogFile.read(OriginalDataVersion[p1],4); 979 LogFile.read(d,4);{behavior} 980 LogFile.read(Difficulty[p1],4); 981 j:=nBrain-1; 982 while (j>=0) and (AnsiCompareFileName(Brain[j].FileName,s)<>0) do 983 dec(j); 984 if j<0 then 985 begin // ai not found -- replace by local player 986 ProcessClientData[p1]:=false; 987 NotifyMessage:=s; 988 Notify(ntAIError); 989 j:=bixTerm; 990 end 991 else ProcessClientData[p1]:=true; 992 if j=bixNoTerm then j:=bixSuper_Virtual; 993 // crashed tournament -- load as supervisor 994 bixView[p1]:=j; 995 end; 996 end; 997 end 998 else result:=false; 999 1000 if result then 1001 begin 1002 CL:=TCmdList.Create; 1003 CL.LoadFromFile(LogFile); 1004 end; 1005 LogFile.Free; 1006 if not result then exit; 1007 1008 Notify(ntStartDone); 1009 if LoadTurn<0 then LoadTurn:=GTurn; 1010 if MovieMode then Mode:=moMovie 1011 else if LoadTurn=0 then Mode:=moLoading 1012 else Mode:=moLoading_Fast; 1013 {$IFDEF TEXTLOG}AssignFile(TextLog,SavePath+LogFileName+'.txt');Rewrite(TextLog);{$ENDIF} 1014 LoadOK:=true; 1015 StartGame; 1016 if MovieMode then 1017 begin 1018 Brain[bix[0]].Client(cShowGame,0,nil^); 1019 Notify(ntBackOff); 1020 end 1021 else Notify(ntLoadBegin); 1022 1023 started:=false; 1024 StatRequest:=false; 1025 MovieStopped:=false; 1026 {$IFDEF LOADPERF}QueryPerformanceCounter(time_total0); time_a:=0; time_b:=0; time_c:=0;{$ENDIF} 1027 while not MovieStopped and (CL.Progress<1000) do 1028 begin 1029 FormerCLState:=CL.State; 1030 CL.Get(Command, p1, Subject, Data); 1031 if p1<0 then p1:=pTurn; 1032 if StatRequest 1033 and (Command and (sctMask or sExecute)<>sctInternal or sExecute) then 1034 begin GenerateStat(pTurn); StatRequest:=false end; 1035 // complete all internal commands following an sTurn before generating statistics 1036 if (Command=sTurn) and not started then 1037 begin 1038 {$IFDEF TEXTLOG}WriteLn(TextLog,'---Turn 0 P0---');{$ENDIF} 1039 for p1:=0 to nPl-1 do 1040 if (bix[p1]>=0) and ((Mode<>moMovie) or (p1=0)) then 1041 CallPlayer(cReplay,p1,nil^); 1042 BeforeTurn0; 1043 if MovieMode then 1044 begin 1045 Inform(pTurn); 1046 CallPlayer(cMovieTurn,0,nil^); 1047 end; 1048 StatRequest:=true; 1049 started:=true; 1050 end 1051 else if (Command=sTurn) and (pTurn=0) and (GTurn=LoadTurn) then 1052 begin 1053 assert(CL.State.LoadPos=FormerCLState.LoadPos+4); // size of sTurn 1054 CL.State:=FormerCLState; 1055 CL.Cut; 1056 Break; 1057 end 1058 else if Command=sIntDataChange then 1059 begin 1060 {$IFDEF TEXTLOG}LoadPos0:=CL.State.LoadPos;{$ENDIF} 1061 if ProcessClientData[p1] then 1062 CL.GetDataChanges(RW[p1].Data, Brain[bix[p1]].DataSize) 1063 else CL.GetDataChanges(nil, 0); 1064 {$IFDEF TEXTLOG}WriteLn(TextLog,Format('Data Changes P%d (%d Bytes)', [p1,CL.State.LoadPos-LoadPos0]));{$ENDIF} 1065 end 1066 else 1067 begin 1068 {$IFDEF TEXTLOG}CmdInfo:=Format('Command %x',[Command]);{$ENDIF} 1069 if Command and (sctMask or sExecute)=sctInternal or sExecute then 1070 IntServer(Command, p1, Subject, Data^) // internal command 1071 else 1072 begin 1073 StatRequest:= Command=sTurn; 1074 Server(Command, p1, Subject, Data^); 1075 end; 1076 {$IFDEF TEXTLOG}WriteLn(TextLog,CmdInfo);{$ENDIF} 1077 end; 1078 if not MovieMode then Notify(ntLoadState+CL.Progress*128 div 1000); 1079 end; 1080 1081 if MovieMode then 1082 begin 1083 Notify(ntBackOn); 1084 Brain[bix[0]].Client(cBreakGame,-1,nil^); 1085 EndGame; 1086 Notify(ntStartGo); 1087 result:=false; 1088 exit; 1089 end; 1090 1091 if StatRequest then GenerateStat(pTurn); 1092 assert(started); 1093 {$IFDEF TEXTLOG}CloseFile(TextLog);{$ENDIF} 1094 {$IFDEF LOADPERF}QueryPerformanceCounter(time_total);{time in s is: (time_total-time_total0)/PerfFreq}{$ENDIF} 1095 NoLogChanges; 1096 NoLogCityTileChanges; 1097 if LogFileName[1]='~' then 1098 begin Delete(LogFileName,1,1); nLogOpened:=-1 end 1099 else nLogOpened:=CL.State.nLog; 1100 1101 Mode:=moPlaying; 1102 LastEndClientCommand:=-1; 1103 if (GTestFlags and tfUncover<>0) or (Difficulty[pTurn]=0) then 1104 DiscoverAll(pTurn,lObserveSuper) {supervisor - all tiles visible} 1105 else DiscoverViewAreas(pTurn); 1106 1107 for p1:=0 to nPl-1 do if 1 shl p1 and (GAlive or GWatching)<>0 then 1108 begin 1109 RecalcPeaceMap(p1); 1110 for ix:=0 to RW[p1].nEnemyUn-1 do with RW[p1].EnemyUn[ix] do 1111 emix:=RWemix[p1,Owner,mix]; 1112 Inform(p1); 1113 end; 1114 {$IFOPT O-}CheckBorders(-2);{$ENDIF} // for testing only 1115 Notify(ntEndInfo); 1116 if not LoadOK then 1117 begin NotifyMessage:=SavePath+LogFileName; Notify(ntLoadError); end; 1118 Brain[bix[0]].Client(cShowGame,0,nil^); 1119 Notify(ntBackOff); 1120 Inform(pTurn); 1121 ChangeClientWhenDone(cResume,0,nil^,0); 1122 end; //LoadGame 1123 1124 procedure InsertTerritoryUpdateCommands; 1125 var 1126 p1,Command,Subject: integer; 1127 Data: pointer; 1128 FormerCLState: TCmdListState; 1129 begin 1130 while CL.Progress<1000 do 1131 begin 1132 FormerCLState:=CL.State; 1133 CL.Get(Command, p1, Subject, Data); 1134 if (Command=sIntExpandTerritory) and (p1=pTurn) then 1135 begin 1136 IntServer(Command, p1, Subject, Data^); 1137 {$IFDEF TEXTLOG}WriteLn(TextLog,'AfterTurn - ExpandTerritory');{$ENDIF} 1138 end 1139 else 1140 begin 1141 CL.State:=FormerCLState; 1142 break 1876 DiscoverViewAreas(pTurn); 1877 if MirBuilt then 1878 DiscoverAll(pTurn, lObserveUnhidden) 1143 1879 end 1144 1880 end; 1145 {$IFOPT O-}InvalidTreatyMap:=0;{$ENDIF} 1881 // CheckContact; 1882 end; { BeforeTurn } 1883 1884 procedure AfterTurn; 1885 var 1886 cix, uix, p1, Loc1, Job0: integer; 1887 JobDone: boolean; 1888 begin 1889 with RW[pTurn] do 1890 begin 1891 for cix := 0 to nCity - 1 do 1892 if City[cix].Loc >= 0 then 1893 begin 1894 // City[cix].Flags:=City[cix].Flags and not chProductionSabotaged; 1895 City[cix].Flags := City[cix].Flags and (chCaptured or chDisorder); 1896 CollectCityResources(pTurn, cix); // new style 1897 end; 1898 1899 inc(Money, OracleIncome); 1900 OracleIncome := 0; 1901 if GWonder[woOracle].EffectiveOwner = pTurn then 1902 begin 1903 for p1 := 0 to nPl - 1 do 1904 if (1 shl p1 and GAlive <> 0) and 1905 ((p1 = pTurn) or (RW[pTurn].Treaty[p1] > trNoContact)) then 1906 for cix := 0 to RW[p1].nCity - 1 do 1907 if (RW[p1].City[cix].Loc >= 0) and 1908 (RW[p1].City[cix].built[imTemple] > 0) then 1909 inc(OracleIncome); 1910 end; 1911 1912 if (GTestFlags and tfImmImprove = 0) and (Government <> gAnarchy) then 1913 for cix := 0 to nCity - 1 do 1914 if (City[cix].Loc >= 0) and (City[cix].Flags and chCaptured = 0) then 1915 PayCityMaintenance(pTurn, cix); 1916 1917 if ServerVersion[pTurn] >= $000EF0 then 1918 begin // let settlers work 1919 for cix := 0 to nCity - 1 do 1920 City[cix].Flags := City[cix].Flags and not chFounded; 1921 for uix := 0 to nUn - 1 do 1922 with Un[uix] do 1923 if Loc >= 0 then 1924 begin 1925 Loc1 := Loc; 1926 Job0 := Job; 1927 if Job <> jNone then 1928 JobDone := Work(pTurn, uix); 1929 { settlers do terrain improvement jobs } 1930 if Health <= 0 then 1931 RemoveUnit_UpdateMap(pTurn, uix); 1932 1933 if (Job0 = jCity) and JobDone then // new city 1934 begin 1935 AddBestCityTile(pTurn, RW[pTurn].nCity - 1); 1936 UpdateUnitMap(Loc1, true); 1937 if Mode >= moMovie then // tell enemies 1938 for p1 := 0 to nPl - 1 do 1939 if (1 shl p1 and GWatching <> 0) and (p1 <> pTurn) and 1940 (ObserveLevel[Loc1] and (3 shl (2 * p1)) > 0) then 1941 CallPlayer(cShowCityChanged, p1, Loc1); 1942 end 1943 end; 1944 end; 1945 1946 for uix := 0 to nUn - 1 do 1947 with Un[uix] do 1948 if Loc >= 0 then 1949 begin { next turn for all units } 1950 if Model[mix].Domain = dAir then 1951 if (Master >= 0) or (RealMap[Loc] and fCity <> 0) or 1952 (RealMap[Loc] and fTerImp = tiBase) then 1953 begin 1954 Fuel := Model[mix].Cap[mcFuel]; 1955 Flags := Flags or unBombsLoaded 1956 end 1957 else if Model[mix].Kind = mkSpecial_Glider then { glider } 1958 begin 1959 if RealMap[Loc] and fTerrain < fGrass then 1960 begin 1961 RemoveUnit_UpdateMap(pTurn, uix); // unit lost 1962 Happened := Happened or phGliderLost 1963 end 1964 end 1965 else 1966 begin 1967 dec(Fuel); 1968 if Fuel < 0 then 1969 begin 1970 RemoveUnit_UpdateMap(pTurn, uix); // unit lost 1971 Happened := Happened or phPlaneLost 1972 end 1973 end 1974 else if (Master < 0) and (Movement > 0) then // check HostileDamage 1975 begin 1976 Health := Health - HostileDamage(pTurn, mix, Loc, Movement); 1977 if Health < 0 then 1978 RemoveUnit_UpdateMap(pTurn, uix); 1979 end 1980 end; { unit loop 1 } 1981 1982 for uix := 0 to nUn - 1 do 1983 with Un[uix] do 1984 begin 1985 Flags := Flags and not unWithdrawn; 1986 if (Loc >= 0) and (Model[mix].Domain = dGround) and (Master < 0) and 1987 ((integer(Movement) = Model[mix].Speed) or 1988 (Model[mix].Cap[mcAcademy] > 0) and (Movement * 2 >= Model[mix].Speed)) 1989 then 1990 Flags := Flags or unFortified; // fortify unmoved units 1991 end; 1992 1993 if (GTestFlags and tfUncover = 0) and (Difficulty[pTurn] > 0) then 1994 begin // restrict view area to current positions 1995 MaskD(ObserveLevel, MapSize, not Cardinal(3 shl (2 * pTurn))); 1996 if Mode > moLoading_Fast then 1997 MaskD(RW[pTurn].Map^, MapSize, not Cardinal(fUnit or fHiddenUnit or 1998 fStealthUnit or fObserved or fSpiedOut or fOwned or fOwnZoCUnit or 1999 fInEnemyZoC)); 2000 RW[pTurn].nEnemyUn := 0; 2001 DiscoverViewAreas(pTurn); 2002 end; 2003 2004 if GWinner = 0 then 2005 for p1 := 0 to nPl - 1 do 2006 if 1 shl p1 and GAlive <> 0 then 2007 CheckWin(p1); 2008 end; 2009 end; // Afterturn 2010 2011 procedure NextPlayer; 2012 begin 2013 if GTurn = 0 then 2014 BeforeTurn0 2015 else 2016 BeforeTurn; 2017 NoLogCityTileChanges; 2018 GenerateStat(pTurn); 2019 Inform(pTurn); 2020 ChangeClient; 1146 2021 end; 1147 2022 1148 procedure StartNewGame(const Path, FileName, Map: string; Newlx, Newly, 1149 NewLandMass, NewMaxTurn: integer);2023 function ExecuteMove(p, uix, ToLoc: integer; var MoveInfo: TMoveInfo; 2024 ShowMove: TShowMove): integer; 1150 2025 var 1151 p: integer; 2026 i, p1, FromLoc, uix1, nUpdateLoc: integer; 2027 MinLevel, MissionResult: Cardinal; 2028 PModel: ^TModel; 2029 UpdateLoc: array [0 .. numax - 1] of integer; 2030 SeeFrom, SeeTo, ExtDiscover: boolean; 1152 2031 begin 1153 Notify(ntStartDone); 1154 SavePath:=Path; 1155 LogFileName:=FileName; 1156 MapFileName:=Map; 1157 if FastContact then begin lx:=24; ly:=42; end 1158 else begin lx:=Newlx; ly:=Newly end; 1159 MapSize:=lx*ly; 1160 if MapFileName<>'' then LandMass:=0 1161 else LandMass:=NewLandMass; 1162 MaxTurn:=NewMaxTurn; 1163 Randomize; 1164 RND:=RandSeed; 1165 Mode:=moPlaying; 1166 CL:=TCmdList.Create; 1167 StartGame; 1168 NoLogChanges; 1169 for p:=0 to nPl-1 do if bix[p]>=0 then 1170 CallPlayer(cGetReady,p,nil^); 1171 LogChanges; 1172 CL.Put(sTurn, 0, 0, nil); 1173 BeforeTurn0; 1174 NoLogCityTileChanges; 1175 GenerateStat(pTurn); 1176 nLogOpened:=-1; 1177 LastEndClientCommand:=-1; 1178 Brain[bix[0]].Client(cShowGame,0,nil^); 1179 Notify(ntBackOff); 1180 Inform(pTurn); 1181 ChangeClientWhenDone(cTurn,0,nil^,0) 1182 end; 1183 1184 procedure DirectHelp(Command: integer); 1185 begin 1186 InitBrain(bixTerm); 1187 Brain[bixTerm].Client(Command,-1,nil^); 1188 AICredits:=#0; 1189 end; 1190 1191 procedure EditMap(const Map: string; Newlx, Newly, NewLandMass: integer); 1192 var 1193 p1,Loc1: integer; 1194 Game: TNewGameData; 1195 begin 1196 Notify(ntStartDone); 1197 Notify(ntInitLocalHuman); 1198 MapFileName:=Map; 1199 lx:=Newlx; 1200 ly:=Newly; 1201 MapSize:=lx*ly; 1202 LandMass:=NewLandMass; 1203 bix[0]:=bixTerm; 1204 Difficulty[0]:=0; 1205 InitBrain(bixTerm); 1206 1207 Randomize; 1208 GAlive:=0; 1209 GWatching:=1; 1210 if not LoadMap(MapFileName) then 1211 for Loc1:=0 to MapSize-1 do RealMap[Loc1]:=fOcean or ($F shl 27); 1212 CL:=nil; 1213 InitMapEditor; 1214 RW[0].Data:=nil; 1215 RW[0].BorderHelper:=nil; 1216 RW[0].Alive:=0; 1217 Game.lx:=lx; Game.ly:=ly; 1218 Game.RO[0]:=@RW[0]; 1219 Game.Difficulty[0]:=0; 1220 for p1:=1 to nPl-1 do begin Game.RO[p1]:=nil; Game.Difficulty[p1]:=-1 end; 1221 Brain[bixTerm].Client(cNewMap,-1,Game); 1222 1223 DiscoverAll(0,lObserveSuper); 1224 Notify(ntEndInfo); 1225 Brain[bix[0]].Client(cShowGame,0,nil^); 1226 Notify(ntBackOff); 1227 ChangeClientWhenDone(cEditMap,0,nil^,0) 1228 end; 1229 1230 procedure DestroySpacePort_TellPlayers(p,pCapturer: integer); 1231 var 1232 cix,i,p1: integer; 1233 ShowShipChange: TShowShipChange; 1234 begin 1235 // stop ship part production 1236 for cix:=0 to RW[p].nCity-1 do with RW[p].City[cix] do 1237 if (Loc>=0) and (Project and cpImp<>0) 1238 and ((Project and cpIndex=woMIR) 1239 or (Imp[Project and cpIndex].Kind=ikShipPart)) then 2032 result := 0; 2033 with RW[p], Un[uix] do 2034 begin 2035 PModel := @Model[mix]; 2036 FromLoc := Loc; 2037 2038 if Master < 0 then 2039 FreeUnit(p, uix); 2040 if (MoveInfo.MoveType in [mtMove, mtCapture]) and MoveInfo.MountainDelay 2041 then 1240 2042 begin 1241 inc(RW[p].Money,Prod0); 1242 Prod:=0; 1243 Prod0:=0; 1244 Project:=cpImp+imTrGoods; 1245 Project0:=cpImp+imTrGoods 2043 Flags := Flags or unMountainDelay; 1246 2044 end; 1247 1248 // destroy ship 1249 with GShip[p] do if Parts[0]+Parts[1]+Parts[2]>0 then 1250 begin 1251 for i:=0 to nShipPart-1 do 2045 Loc := -2; 2046 if TroopLoad + AirLoad > 0 then 2047 for i := 0 to nUn - 1 do 2048 if (Un[i].Loc >= 0) and (Un[i].Master = uix) then 2049 Un[i].Loc := -2; 2050 UpdateUnitMap(FromLoc); 2051 2052 if Mode >= moMovie then { show move in interface modules } 1252 2053 begin 1253 ShowShipChange.Ship1Change[i]:=-Parts[i]; 1254 if pCapturer>=0 then 1255 begin 1256 ShowShipChange.Ship2Change[i]:=Parts[i]; 1257 inc(GShip[pCapturer].Parts[i], Parts[i]); 1258 end; 1259 Parts[i]:=0; 2054 ShowMove.EndHealth := MoveInfo.EndHealth; 2055 ShowMove.EndHealthDef := -1; 2056 if Master >= 0 then 2057 if Model[Un[Master].mix].Domain = dAir then 2058 ShowMove.Flags := ShowMove.Flags or umPlaneUnloading 2059 else 2060 ShowMove.Flags := ShowMove.Flags or umShipUnloading; 2061 if MoveInfo.ToMaster >= 0 then 2062 if Model[Un[MoveInfo.ToMaster].mix].Domain = dAir then 2063 ShowMove.Flags := ShowMove.Flags or umPlaneLoading 2064 else 2065 ShowMove.Flags := ShowMove.Flags or umShipLoading; 2066 for p1 := 0 to nPl - 1 do 2067 if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm)) 2068 then 2069 begin 2070 if PModel.Cap[mcStealth] > 0 then 2071 MinLevel := lObserveSuper 2072 else if PModel.Cap[mcSub] > 0 then 2073 MinLevel := lObserveAll 2074 else 2075 MinLevel := lObserveUnhidden; 2076 SeeFrom := (p1 = p) or (ObserveLevel[FromLoc] shr (2 * p1) and 2077 3 >= MinLevel); 2078 SeeTo := (p1 = p) or (ObserveLevel[ToLoc] shr (2 * p1) and 2079 3 >= MinLevel); 2080 if SeeFrom and SeeTo then 2081 begin 2082 TellAboutModel(p1, p, mix); 2083 if p1 = p then 2084 ShowMove.emix := -1 2085 else 2086 ShowMove.emix := emixSafe(p1, p, mix); 2087 if MoveInfo.MoveType = mtCapture then 2088 CallPlayer(cShowCapturing, p1, ShowMove) 2089 else 2090 CallPlayer(cShowMoving, p1, ShowMove); 2091 end 2092 else if SeeFrom then 2093 CallPlayer(cShowUnitChanged, p1, FromLoc); 2094 end; 1260 2095 end; 1261 if Mode>=moMovie then 2096 2097 if MoveInfo.MoveType <> mtSpyMission then 2098 Loc := ToLoc; 2099 if TroopLoad + AirLoad > 0 then 2100 for i := 0 to nUn - 1 do 2101 if Un[i].Loc = -2 then 2102 Un[i].Loc := ToLoc; 2103 2104 ExtDiscover := false; 2105 nUpdateLoc := 0; 2106 if MoveInfo.MoveType = mtCapture then 1262 2107 begin 1263 if pCapturer>=0 then ShowShipChange.Reason:=scrCapture 1264 else ShowShipChange.Reason:=scrDestruction; 1265 ShowShipChange.Ship1Owner:=p; 1266 ShowShipChange.Ship2Owner:=pCapturer; 1267 for p1:=0 to nPl-1 do if 1 shl p1 and (GAlive or GWatching)<>0 then 1268 begin 1269 move(GShip,RW[p1].Ship,SizeOf(GShip)); 1270 if 1 shl p1 and GWatching<>0 then 1271 CallPlayer(cShowShipChange,p1,ShowShipChange); 1272 end; 1273 end 1274 end 1275 end; 1276 1277 procedure DestroyCity_TellPlayers(p,cix: integer; SaveUnits: boolean); 1278 begin 1279 if RW[p].City[cix].built[imSpacePort]>0 then 1280 DestroySpacePort_TellPlayers(p,-1); 1281 DestroyCity(p,cix,SaveUnits); 1282 end; 1283 1284 procedure ChangeCityOwner_TellPlayers(pOld,cixOld,pNew: integer); 1285 begin 1286 if RW[pOld].City[cixOld].built[imSpacePort]>0 then 1287 if RW[pNew].NatBuilt[imSpacePort]>0 then 1288 DestroySpacePort_TellPlayers(pOld,pNew) 1289 else DestroySpacePort_TellPlayers(pOld,-1); 1290 ChangeCityOwner(pOld,cixOld,pNew); 1291 end; 1292 1293 procedure CheckWin(p: integer); 1294 var 1295 i: integer; 1296 ShipComplete: boolean; 1297 begin 1298 ShipComplete:=true; 1299 for i:=0 to nShipPart-1 do 1300 if GShip[p].Parts[i]<ShipNeed[i] then ShipComplete:=false; 1301 if ShipComplete then GWinner:=GWinner or 1 shl p; // game won! 1302 end; 1303 1304 procedure BeforeTurn; 1305 var 1306 i,p1,uix,cix,V21,Loc1,Cost,Job0,nAlive,nAppliers,ad, 1307 OldLoc,SiegedTiles,nUpdateLoc: integer; 1308 UpdateLoc: array[0..numax-1] of integer; 1309 Radius: TVicinity21Loc; 1310 ShowShipChange: TShowShipChange; 1311 TribeExtinct, JobDone, MirBuilt: boolean; 1312 begin 1313 {$IFOPT O-}assert(1 shl pTurn and InvalidTreatyMap=0);{$ENDIF} 1314 assert(1 shl pTurn and (GAlive or GWatching)<>0); 1315 if (1 shl pTurn and GAlive=0) and (Difficulty[pTurn]>0) then 1316 exit; 1317 1318 if (GWonder[woGrLibrary].EffectiveOwner=pTurn) and (GWinner=0) then 1319 begin // check great library effect 1320 nAlive:=0; 1321 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then inc(nAlive); 1322 for ad:=0 to nAdv-5 do if RW[pTurn].Tech[ad]<tsSeen then 1323 begin 1324 nAppliers:=0; 1325 for p1:=0 to nPl-1 do 1326 if (p1<>pTurn) and (1 shl p1 and GAlive<>0) 1327 and (RW[p1].Tech[ad]>=tsApplicable) then 1328 inc(nAppliers); 1329 if nAppliers*2>nAlive then 1330 begin 1331 SeeTech(pTurn,ad); 1332 inc(nTech[pTurn]); 1333 if Mode>=moMovie then 1334 CallPlayer(cShowGreatLibTech,pTurn,ad); 1335 // do not call CallPlayer(pTurn) while map is invalid 1336 end; 1337 end; 1338 end; 1339 1340 MaskD(ObserveLevel,MapSize,not Cardinal(3 shl (2*pTurn))); 1341 if Mode>moLoading_Fast then 1342 MaskD(RW[pTurn].Map^,MapSize,not Cardinal(fUnit or fHiddenUnit or fStealthUnit 1343 or fObserved or fSpiedOut or fOwned or fOwnZoCUnit or fInEnemyZoC)); 1344 RW[pTurn].nEnemyUn:=0; 1345 1346 MirBuilt:=false; 1347 if (Difficulty[pTurn]>0) and (GWinner=0) then with RW[pTurn] do 1348 begin 1349 if nCity>0 then for p1:=0 to nPl-1 do 1350 if GTurn=EvaStart[p1]+PeaceEvaTurns then 1351 begin // peace contract -- remove all units from p1's territory 1352 Loc1:=City[0].Loc; // search destination for homeless units 1353 for cix:=1 to nCity-1 do 1354 if (City[cix].Loc>=0) and ((Loc1<0) or (City[cix].Built[imPalace]>0)) then 1355 Loc1:=City[cix].Loc; 1356 for uix:=0 to nUn-1 do with Un[uix] do 1357 if (Loc>=0) and (Model[mix].Kind<>mkDiplomat) 1358 and ((Home>=0) or (Loc1>=0)) 1359 and (RealMap[Loc] shr 27=Cardinal(p1)) then 2108 assert(Occupant[ToLoc] < 0); 2109 for uix1 := 0 to RW[MoveInfo.Defender].nUn - 1 do 2110 with RW[MoveInfo.Defender].Un[uix1] do 2111 if (Loc >= 0) and (Home = MoveInfo.Dcix) then 1360 2112 begin 1361 OldLoc:=Loc; 1362 if Master>=0 then 1363 begin // transport unload 1364 if Model[mix].Domain=dAir then dec(Un[Master].AirLoad) 1365 else dec(Un[Master].TroopLoad); 1366 Master:=-1; 1367 end 1368 else FreeUnit(pTurn,uix); 1369 1370 if Home>=0 then Loc:=City[Home].Loc 1371 else Loc:=Loc1; 1372 PlaceUnit(pTurn,uix); 1373 UpdateUnitMap(OldLoc); 1374 UpdateUnitMap(Loc); 1375 Flags:=Flags or unWithdrawn; 1376 Happened:=Happened or phPeaceEvacuation; 1377 end 1378 end; 1379 1380 if Mode>=moMovie then 1381 fillchar(ShowShipChange,sizeof(ShowShipChange),0); 1382 TribeExtinct:=true; 1383 nUpdateLoc:=0; 1384 for cix:=0 to nCity-1 do with City[cix] do if Loc>=0 then 1385 begin {next turn for all cities - city loop 1} 1386 // if ServerVersion[pTurn]>=$000EF0 then 1387 // Flags:=Flags and (chFounded or chCaptured or chProductionSabotaged or chDisorder) 1388 // else Flags:=Flags and (chCaptured or chProductionSabotaged or chDisorder); 1389 // check for siege 1390 SiegedTiles:=0; 1391 V21_to_Loc(Loc,Radius); 1392 for V21:=1 to 26 do if Tiles and (1 shl V21) and not (1 shl CityOwnTile)<>0 then 1393 begin 1394 Loc1:=Radius[V21]; 1395 assert((Loc1>=0) and (Loc1<MapSize) and (UsedByCity[Loc1]=Loc)); 1396 p1:=RealMap[Loc1] shr 27; 1397 if (RealMap[Loc1] and fCity<>0) 1398 or (p1<nPl) and (p1<>pTurn) and (RW[pTurn].Treaty[p1]>=trPeace) 1399 or (ZoCMap[Loc1]>0) and (Occupant[Loc1]<>pTurn) 1400 and (Treaty[Occupant[Loc1]]<trPeace) then 2113 UpdateLoc[nUpdateLoc] := Loc; 2114 inc(nUpdateLoc) 2115 end; 2116 // unit will be removed -- remember position and update for all players 2117 2118 if (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size > 2) and (nCity < ncmax) 2119 then 2120 begin // city captured 2121 ChangeCityOwner_TellPlayers(MoveInfo.Defender, MoveInfo.Dcix, p); 2122 City[nCity - 1].Flags := CaptureTurns shl 16; 2123 CityShrink(p, nCity - 1); 2124 if Mode = moPlaying then 2125 with RW[p].City[nCity - 1] do 2126 begin 2127 // SavedResourceWeights[nCity-1]:=ResourceWeights; 2128 SavedTiles[nCity - 1] := Tiles; 2129 end; 2130 ExtDiscover := true; 2131 2132 // Temple of Zeus effect 2133 if GWonder[woZeus].EffectiveOwner = p then 1401 2134 begin 1402 Tiles:=Tiles and not (1 shl V21); 1403 UsedByCity[Loc1]:=-1; 1404 Flags:=Flags or chSiege; 1405 inc(SiegedTiles); 1406 end; 1407 end; 1408 while SiegedTiles>0 do // replace sieged tiles 1409 begin 1410 if not AddBestCityTile(pTurn,cix) then break; 1411 dec(SiegedTiles); 1412 end; 1413 1414 if Flags and chFounded=0 then 1415 begin 1416 // CollectCityResources(pTurn,cix); // old style 1417 1418 if CityTurn(pTurn,cix) then 1419 TribeExtinct:=false 1420 else 1421 begin // city is erased 1422 RemoveDomainUnits(dSea,pTurn,Loc); 1423 RemoveDomainUnits(dAir,pTurn,Loc); 1424 Map[Loc]:=Map[Loc] and not fCity; // !!! do this in inner core 1425 UpdateLoc[nUpdateLoc]:=Loc; 1426 inc(nUpdateLoc); 1427 DestroyCity_TellPlayers(pTurn,cix,true); 1428 end; 1429 1430 if (Flags and chProduction<>0) and (Project0 and cpImp<>0) then 1431 begin 1432 if Project0 and cpIndex=woMir then // MIR completed 1433 MirBuilt:=true 1434 else if Project0 and cpIndex=woManhattan then 1435 GColdWarStart:=GTurn 1436 else if Imp[Project0 and cpIndex].Kind=ikShipPart then {ship parts produced} 1437 inc(ShowShipChange.Ship1Change[Project0 and cpIndex-imShipComp]); 1438 end 1439 end 1440 end;{city loop 1} 1441 if nUpdateLoc>0 then 1442 begin 1443 CheckBorders(-1,pTurn); 1444 for i:=0 to nUpdateLoc-1 do UpdateUnitMap(UpdateLoc[i],true); 1445 if Mode>=moMovie then 1446 for p1:=0 to nPl-1 do 1447 if (1 shl p1 and GWatching<>0) and (p1<>pTurn) then 1448 for i:=0 to nUpdateLoc-1 do 1449 if ObserveLevel[UpdateLoc[i]] shr (2*p1) and 3>=lObserveUnhidden then 1450 CallPlayer(cShowCityChanged,p1,UpdateLoc[i]); 1451 end; 1452 1453 for uix:=0 to nUn-1 do with Un[uix] do if Loc>=0 then 1454 begin // unit loop 2 1455 if Health<100 then Recover(pTurn,uix); 1456 1457 if Flags and unMountainDelay<>0 then 1458 begin 1459 Movement:=0; 1460 Flags:=Flags and not unMountainDelay 1461 end 1462 else Movement:=UnitSpeed(pTurn,mix,Health); {refresh movement} 1463 1464 assert(Loc>=0); 1465 if Model[mix].Kind<>mkDiplomat then 1466 begin // check treaty violation 1467 p1:=RealMap[Loc] shr 27; 1468 if (p1<nPl) and (p1<>pTurn) and (Treaty[p1]>=trPeace) then 1469 begin 1470 if (Job in [jCity,jPillage,jClear,jAfforest,jTrans]) 1471 or (Job in [jIrr,jMine,jFort,jBase]) and (RealMap[Loc] and fTerImp<>0) then 1472 Job:=jNone; 1473 if (GTurn>EvaStart[p1]+PeaceEvaTurns) and (Treaty[p1]<>trAlliance) then 1474 begin 1475 EvaStart[p1]:=GTurn; 1476 Happened:=Happened or phPeaceViolation; 1477 if Mode>=moMovie then 1478 CallPlayer(cShowPeaceViolation,p1,pTurn); 1479 end; 1480 end; 1481 end; 1482 1483 if ServerVersion[pTurn]>=$000EF0 then 1484 begin 1485 if (Health<=0) or TribeExtinct then RemoveUnit_UpdateMap(pTurn,uix); 1486 end 1487 end; 1488 1489 if ServerVersion[pTurn]<$000EF0 then 1490 for uix:=0 to nUn-1 do with Un[uix] do if Loc>=0 then 1491 begin // unit loop 3 1492 Loc1:=Loc; 1493 Job0:=Job; 1494 if Job<>jNone then JobDone:=Work(pTurn,uix); 1495 {settlers do terrain improvement jobs} 1496 if (Health<=0) or TribeExtinct then RemoveUnit_UpdateMap(pTurn,uix); 1497 1498 if (Job0=jCity) and JobDone then // new city 1499 begin 1500 AddBestCityTile(pTurn,RW[pTurn].nCity-1); 1501 UpdateUnitMap(Loc1,true); 1502 if Mode>=moMovie then // tell enemies 1503 for p1:=0 to nPl-1 do 1504 if (1 shl p1 and GWatching<>0) and (p1<>pTurn) 1505 and (ObserveLevel[Loc1] and (3 shl (2*p1))>0) then 1506 CallPlayer(cShowCityChanged,p1,Loc1); 1507 end 1508 end; 1509 1510 {pollution - city loop 3} 1511 for cix:=0 to nCity-1 do with City[cix] do 1512 if (Loc>=0) and (Pollution>=MaxPollution) then 1513 Pollute(pTurn,cix); 1514 1515 CompactLists(pTurn); 1516 if (nUn=0) and (nCity=0) then 1517 begin // nation made extinct 1518 Happened:=Happened or phExtinct; 1519 GAlive:=GAlive and not (1 shl pTurn); 1520 Stat[stPop,pTurn,GTurn]:=0; 1521 Stat[stMil,pTurn,GTurn]:=0; 1522 Stat[stScience,pTurn,GTurn]:=0; 1523 Stat[stExplore,pTurn,GTurn]:=0; 1524 Stat[stTerritory,pTurn,GTurn]:=0; 1525 Stat[stWork,pTurn,GTurn]:=0; 1526 for p1:=0 to nPl-1 do if 1 shl p1 and (GAlive or GWatching)<>0 then 1527 begin 1528 if p1<>pTurn then 1529 begin 1530 GiveCivilReport(p1, pTurn); 1531 if (GTestFlags and tfUncover<>0) or (Difficulty[p1]=0) 1532 or (RW[p1].Treaty[pTurn]=trAlliance) then 1533 GiveMilReport(p1, pTurn); 1534 end; 1535 with RW[p1] do 1536 begin 1537 Alive:=GAlive; 1538 for Loc1:=0 to MapSize-1 do 1539 if Territory[Loc1]=pTurn then // remove territory of extinct nation from player maps 2135 GiveCivilReport(p, MoveInfo.Defender); 2136 for i := 0 to nAdv - 1 do 2137 if not(i in FutureTech) and (RW[p].Tech[i] < tsSeen) and 2138 (RW[MoveInfo.Defender].Tech[i] >= tsApplicable) then 1540 2139 begin 1541 Territory[Loc1]:=-1; 1542 Map[Loc1]:=Map[Loc1] and not fPeace 2140 Happened := Happened or phStealTech; 2141 GStealFrom := MoveInfo.Defender; 2142 Break 1543 2143 end 1544 2144 end; 1545 end; 1546 exit 1547 end; 1548 1549 // check research 1550 Cost:=TechCost(pTurn); 1551 if GTestFlags and tfImmAdvance<>0 then Research:=Cost; 1552 if (Happened and phTech=0) and (Research>=Cost) then 1553 begin 1554 if ResearchTech=adMilitary then EnableDevModel(pTurn) {new Unit class initiated} 1555 else if ResearchTech>=0 then 1556 DiscoverTech(pTurn,ResearchTech); 1557 1558 dec(Research,Cost); 1559 Happened:=Happened or phTech; 1560 ResearchTech:=-1 1561 end 1562 else if (ResearchTech=-2) and (nCity>0) then 1563 begin 1564 Happened:=Happened or phTech; 1565 ResearchTech:=-1 1566 end; 1567 1568 if Credibility<MaxCredibility then 1569 for p1:=0 to nPl-1 do 1570 if (p1<>pTurn) and (1 shl p1 and GAlive<>0) 1571 and (Treaty[p1]>=trPeace) then 1572 begin inc(Credibility); Break end; 1573 1574 if GWinner=0 then CheckWin(pTurn); 1575 if (Mode>=moMovie) and (GWinner=0) and ((ShowShipChange.Ship1Change[0]>0) 1576 or (ShowShipChange.Ship1Change[1]>0) or (ShowShipChange.Ship1Change[2]>0)) then 1577 begin 1578 ShowShipChange.Reason:=scrProduction; 1579 ShowShipChange.Ship1Owner:=pTurn; 1580 ShowShipChange.Ship2Owner:=-1; 1581 for p1:=0 to nPl-1 do 1582 if (p1<>pTurn) and (1 shl p1 and (GAlive or GWatching)<>0) then 1583 begin 1584 move(GShip,RW[p1].Ship,SizeOf(GShip)); 1585 if 1 shl p1 and GWatching<>0 then 1586 CallPlayer(cShowShipChange,p1,ShowShipChange); 1587 end 1588 end; 1589 if WinOnAlone and (GAlive and not (1 shl pTurn or 1)=0) then 1590 GWinner:=1 shl pTurn; // break if only one nation left 1591 1592 if GTurn=AnarchyStart+AnarchyTurns then 1593 begin 1594 AnarchyStart:=-AnarchyTurns-1; 1595 Government:=gDespotism; 1596 for p1:=0 to nPl-1 do if (p1<>pTurn) and ((GAlive or GWatching) and (1 shl p1)<>0) then 1597 RW[p1].EnemyReport[pTurn].Government:=gDespotism; 1598 inc(Happened,phChangeGov) 1599 end; 1600 end; // if Difficulty[pTurn]>0 1601 1602 if (pTurn=0) and (GWinner>0) then 1603 begin // game over, give world map and all reports to player 0 1604 DiscoverAll(pTurn,lObserveSuper); 1605 for p1:=1 to nPl-1 do if 1 shl p1 and GAlive<>0 then 1606 begin 1607 if RW[pTurn].Treaty[p1]<trNone then 1608 begin 1609 RW[pTurn].Treaty[p1]:=trNone; 1610 RW[p1].Treaty[pTurn]:=trNone; 1611 end; 1612 GiveCivilReport(pTurn,p1); 1613 GiveMilReport(pTurn,p1); 1614 end; 1615 end 1616 else 1617 begin 1618 // show observed areas 1619 if (GTestFlags and tfUncover<>0) or (Difficulty[pTurn]=0) then {supervisor - all tiles visible} 1620 begin 1621 if (bix[pTurn]<>bixNoTerm) 1622 and ((Difficulty[pTurn]>0) or (Mode>moLoading_Fast)) then 1623 DiscoverAll(pTurn,lObserveSuper) 1624 end 1625 else 1626 begin 1627 DiscoverViewAreas(pTurn); 1628 if MirBuilt then 1629 DiscoverAll(pTurn,lObserveUnhidden) 1630 end 1631 end; 1632 //CheckContact; 1633 end; {BeforeTurn} 1634 1635 procedure AfterTurn; 1636 var 1637 cix,uix,p1,Loc1,Job0: integer; 1638 JobDone: boolean; 1639 begin 1640 with RW[pTurn] do 1641 begin 1642 for cix:=0 to nCity-1 do if City[cix].Loc>=0 then 1643 begin 1644 // City[cix].Flags:=City[cix].Flags and not chProductionSabotaged; 1645 City[cix].Flags:=City[cix].Flags and (chCaptured or chDisorder); 1646 CollectCityResources(pTurn,cix); // new style 1647 end; 1648 1649 inc(Money,OracleIncome); 1650 OracleIncome:=0; 1651 if GWonder[woOracle].EffectiveOwner=pTurn then 1652 begin 1653 for p1:=0 to nPl-1 do 1654 if (1 shl p1 and GAlive<>0) 1655 and ((p1=pTurn) or (RW[pTurn].Treaty[p1]>trNoContact)) then 1656 for cix:=0 to RW[p1].nCity-1 do 1657 if (RW[p1].City[cix].Loc>=0) and (RW[p1].City[cix].Built[imTemple]>0) then 1658 inc(OracleIncome); 1659 end; 1660 1661 if (GTestFlags and tfImmImprove=0) and (Government<>gAnarchy) then 1662 for cix:=0 to nCity-1 do 1663 if (City[cix].Loc>=0) and (City[cix].Flags and chCaptured=0) then 1664 PayCityMaintenance(pTurn,cix); 1665 1666 if ServerVersion[pTurn]>=$000EF0 then 1667 begin // let settlers work 1668 for cix:=0 to nCity-1 do 1669 City[cix].Flags:=City[cix].Flags and not chFounded; 1670 for uix:=0 to nUn-1 do with Un[uix] do if Loc>=0 then 1671 begin 1672 Loc1:=Loc; 1673 Job0:=Job; 1674 if Job<>jNone then JobDone:=Work(pTurn,uix); 1675 {settlers do terrain improvement jobs} 1676 if Health<=0 then RemoveUnit_UpdateMap(pTurn,uix); 1677 1678 if (Job0=jCity) and JobDone then // new city 1679 begin 1680 AddBestCityTile(pTurn,RW[pTurn].nCity-1); 1681 UpdateUnitMap(Loc1,true); 1682 if Mode>=moMovie then // tell enemies 1683 for p1:=0 to nPl-1 do 1684 if (1 shl p1 and GWatching<>0) and (p1<>pTurn) 1685 and (ObserveLevel[Loc1] and (3 shl (2*p1))>0) then 1686 CallPlayer(cShowCityChanged,p1,Loc1); 1687 end 1688 end; 1689 end; 1690 1691 for uix:=0 to nUn-1 do with Un[uix] do if Loc>=0 then 1692 begin {next turn for all units} 1693 if Model[mix].Domain=dAir then 1694 if (Master>=0) or (RealMap[Loc] and fCity<>0) 1695 or (RealMap[Loc] and fTerImp=tiBase) then 1696 begin 1697 Fuel:=Model[mix].Cap[mcFuel]; 1698 Flags:=Flags or unBombsLoaded 1699 end 1700 else if Model[mix].Kind=mkSpecial_Glider then {glider} 1701 begin 1702 if RealMap[Loc] and fTerrain<fGrass then 1703 begin 1704 RemoveUnit_UpdateMap(pTurn,uix); // unit lost 1705 Happened:=Happened or phGliderLost 1706 end 1707 end 1708 else 1709 begin 1710 dec(Fuel); 1711 if Fuel<0 then 1712 begin 1713 RemoveUnit_UpdateMap(pTurn,uix); // unit lost 1714 Happened:=Happened or phPlaneLost 1715 end 1716 end 1717 else if (Master<0) and (Movement>0) then // check HostileDamage 1718 begin 1719 Health:=Health-HostileDamage(pTurn,mix,Loc,Movement); 1720 if Health<0 then RemoveUnit_UpdateMap(pTurn,uix); 1721 end 1722 end; {unit loop 1} 1723 1724 for uix:=0 to nUn-1 do with Un[uix] do 1725 begin 1726 Flags:=Flags and not unWithdrawn; 1727 if (Loc>=0) and (Model[mix].Domain=dGround) and (Master<0) 1728 and ((integer(Movement)=Model[mix].Speed) 1729 or (Model[mix].Cap[mcAcademy]>0) and (Movement*2>=Model[mix].Speed)) then 1730 Flags:=Flags or unFortified; // fortify unmoved units 1731 end; 1732 1733 if (GTestFlags and tfUncover=0) and (Difficulty[pTurn]>0) then 1734 begin // restrict view area to current positions 1735 MaskD(ObserveLevel,MapSize,not Cardinal(3 shl (2*pTurn))); 1736 if Mode>moLoading_Fast then 1737 MaskD(RW[pTurn].Map^,MapSize,not Cardinal(fUnit or fHiddenUnit or fStealthUnit 1738 or fObserved or fSpiedOut or fOwned or fOwnZoCUnit or fInEnemyZoC)); 1739 RW[pTurn].nEnemyUn:=0; 1740 DiscoverViewAreas(pTurn); 1741 end; 1742 1743 if GWinner=0 then 1744 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then 1745 CheckWin(p1); 1746 end; 1747 end; //Afterturn 1748 1749 procedure NextPlayer; 1750 begin 1751 if GTurn=0 then BeforeTurn0 1752 else BeforeTurn; 1753 NoLogCityTileChanges; 1754 GenerateStat(pTurn); 1755 Inform(pTurn); 1756 ChangeClient; 1757 end; 1758 1759 function ExecuteMove(p,uix,ToLoc: integer; 1760 var MoveInfo: TMoveInfo; ShowMove: TShowMove): integer; 1761 var 1762 i,p1,FromLoc,uix1,nUpdateLoc: integer; 1763 MinLevel, MissionResult: Cardinal; 1764 PModel: ^TModel; 1765 UpdateLoc: array[0..numax-1] of integer; 1766 SeeFrom,SeeTo,ExtDiscover: boolean; 1767 begin 1768 result:=0; 1769 with RW[p],Un[uix] do 1770 begin 1771 PModel:=@Model[mix]; 1772 FromLoc:=Loc; 1773 1774 if Master<0 then 1775 FreeUnit(p,uix); 1776 if (MoveInfo.MoveType in [mtMove,mtCapture]) and MoveInfo.MountainDelay then 1777 begin Flags:=Flags or unMountainDelay; end; 1778 Loc:=-2; 1779 if TroopLoad+AirLoad>0 then 1780 for i:=0 to nUn-1 do 1781 if (Un[i].Loc>=0) and (Un[i].Master=uix) then 1782 Un[i].Loc:=-2; 1783 UpdateUnitMap(FromLoc); 1784 1785 if Mode>=moMovie then {show move in interface modules} 1786 begin 1787 ShowMove.EndHealth:=MoveInfo.EndHealth; 1788 ShowMove.EndHealthDef:=-1; 1789 if Master>=0 then 1790 if Model[Un[Master].mix].Domain=dAir then 1791 ShowMove.Flags:=ShowMove.Flags or umPlaneUnloading 1792 else ShowMove.Flags:=ShowMove.Flags or umShipUnloading; 1793 if MoveInfo.ToMaster>=0 then 1794 if Model[Un[MoveInfo.ToMaster].mix].Domain=dAir then 1795 ShowMove.Flags:=ShowMove.Flags or umPlaneLoading 1796 else ShowMove.Flags:=ShowMove.Flags or umShipLoading; 1797 for p1:=0 to nPl-1 do 1798 if (1 shl p1 and GWatching<>0) 1799 and ((p1<>p) or (bix[p1]=bixTerm)) then 1800 begin 1801 if PModel.Cap[mcStealth]>0 then MinLevel:=lObserveSuper 1802 else if PModel.Cap[mcSub]>0 then MinLevel:=lObserveAll 1803 else MinLevel:=lObserveUnhidden; 1804 SeeFrom:= (p1=p) or (ObserveLevel[FromLoc] shr (2*p1) and 3>=MinLevel); 1805 SeeTo:= (p1=p) or (ObserveLevel[ToLoc] shr (2*p1) and 3>=MinLevel); 1806 if SeeFrom and SeeTo then 1807 begin 1808 TellAboutModel(p1,p,mix); 1809 if p1=p then ShowMove.emix:=-1 1810 else ShowMove.emix:=emixSafe(p1,p,mix); 1811 if MoveInfo.MoveType=mtCapture then CallPlayer(cShowCapturing,p1,ShowMove) 1812 else CallPlayer(cShowMoving,p1,ShowMove); 1813 end 1814 else if SeeFrom then 1815 CallPlayer(cShowUnitChanged,p1,FromLoc); 1816 end; 1817 end; 1818 1819 if MoveInfo.MoveType<>mtSpyMission then 1820 Loc:=ToLoc; 1821 if TroopLoad+AirLoad>0 then 1822 for i:=0 to nUn-1 do 1823 if Un[i].Loc=-2 then Un[i].Loc:=ToLoc; 1824 1825 ExtDiscover:=false; 1826 nUpdateLoc:=0; 1827 if MoveInfo.MoveType=mtCapture then 1828 begin 1829 assert(Occupant[ToLoc]<0); 1830 for uix1:=0 to RW[MoveInfo.Defender].nUn-1 do with RW[MoveInfo.Defender].Un[uix1] do 1831 if (Loc>=0) and (Home=MoveInfo.Dcix) then 1832 begin UpdateLoc[nUpdateLoc]:=Loc; inc(nUpdateLoc) end; 1833 // unit will be removed -- remember position and update for all players 1834 1835 if (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size>2) and (nCity<ncmax) then 1836 begin // city captured 1837 ChangeCityOwner_TellPlayers(MoveInfo.Defender,MoveInfo.Dcix,p); 1838 City[nCity-1].Flags:=CaptureTurns shl 16; 1839 CityShrink(p,nCity-1); 1840 if Mode=moPlaying then with RW[p].City[nCity-1] do 1841 begin 1842 // SavedResourceWeights[nCity-1]:=ResourceWeights; 1843 SavedTiles[nCity-1]:=Tiles; 1844 end; 1845 ExtDiscover:=true; 1846 1847 // Temple of Zeus effect 1848 if GWonder[woZeus].EffectiveOwner=p then 1849 begin 1850 GiveCivilReport(p,MoveInfo.Defender); 1851 for i:=0 to nAdv-1 do 1852 if not (i in FutureTech) and (RW[p].Tech[i]<tsSeen) 1853 and (RW[MoveInfo.Defender].Tech[i]>=tsApplicable) then 1854 begin 1855 Happened:=Happened or phStealTech; 1856 GStealFrom:=MoveInfo.Defender; 1857 Break 1858 end 1859 end; 1860 if Mode=moPlaying then LogCheckBorders(p,nCity-1,MoveInfo.Defender); 1861 {$IFOPT O-}if Mode<moPlaying then InvalidTreatyMap:=not(1 shl p);{$ENDIF} 2145 if Mode = moPlaying then 2146 LogCheckBorders(p, nCity - 1, MoveInfo.Defender); 2147 {$IFOPT O-} if Mode < moPlaying then 2148 InvalidTreatyMap := not(1 shl p); {$ENDIF} 1862 2149 // territory should not be considered for the rest of the command 1863 2150 // execution, because during loading a game it's incorrect before 1864 2151 // subsequent sIntExpandTerritory is processed 1865 2152 end 1866 else // city destroyed1867 begin 1868 DestroyCity_TellPlayers(MoveInfo.Defender,MoveInfo.Dcix,false);1869 CheckBorders(ToLoc,MoveInfo.Defender);1870 end; 1871 RecalcPeaceMap(p);1872 if Mode>=moMovie then1873 move(GWonder,Wonder,SizeOf(GWonder));1874 end; { if MoveInfo.MoveType=mtCapture}1875 1876 if MoveInfo.MoveType=mtSpyMission then2153 else // city destroyed 2154 begin 2155 DestroyCity_TellPlayers(MoveInfo.Defender, MoveInfo.Dcix, false); 2156 CheckBorders(ToLoc, MoveInfo.Defender); 2157 end; 2158 RecalcPeaceMap(p); 2159 if Mode >= moMovie then 2160 move(GWonder, Wonder, SizeOf(GWonder)); 2161 end; { if MoveInfo.MoveType=mtCapture } 2162 2163 if MoveInfo.MoveType = mtSpyMission then 1877 2164 begin 1878 MissionResult:=DoSpyMission(p,MoveInfo.Defender,MoveInfo.Dcix,SpyMission); 1879 if (Mode=moPlaying) and (SpyMission=smStealForeignReports) then 1880 CallPlayer(cShowMissionResult,p,MissionResult); 2165 MissionResult := DoSpyMission(p, MoveInfo.Defender, MoveInfo.Dcix, 2166 SpyMission); 2167 if (Mode = moPlaying) and (SpyMission = smStealForeignReports) then 2168 CallPlayer(cShowMissionResult, p, MissionResult); 1881 2169 end; 1882 2170 1883 Health:=MoveInfo.EndHealth;1884 dec(Movement,MoveInfo.Cost);1885 // transport unload1886 if Master>=0 then2171 Health := MoveInfo.EndHealth; 2172 dec(Movement, MoveInfo.Cost); 2173 // transport unload 2174 if Master >= 0 then 1887 2175 begin 1888 if PModel.Domain=dAir then dec(Un[Master].AirLoad) 2176 if PModel.Domain = dAir then 2177 dec(Un[Master].AirLoad) 2178 else 2179 begin 2180 dec(Un[Master].TroopLoad); 2181 assert(Movement <= 0); 2182 end; 2183 Master := -1; 2184 end; 2185 2186 if (Health <= 0) or (MoveInfo.MoveType = mtSpyMission) then 2187 RemoveUnit(p, uix) // spy mission or victim of HostileDamage 1889 2188 else 1890 begin 1891 dec(Un[Master].TroopLoad); 1892 assert(Movement<=0); 1893 end; 1894 Master:=-1; 2189 begin // transport load 2190 Master := MoveInfo.ToMaster; 2191 if MoveInfo.ToMaster >= 0 then 2192 begin 2193 if PModel.Domain = dAir then 2194 inc(Un[MoveInfo.ToMaster].AirLoad) 2195 else 2196 inc(Un[MoveInfo.ToMaster].TroopLoad); 2197 end 2198 else 2199 PlaceUnit(p, uix); 1895 2200 end; 1896 2201 1897 if (Health<=0) or (MoveInfo.MoveType=mtSpyMission) then 1898 RemoveUnit(p,uix) // spy mission or victim of HostileDamage 1899 else 1900 begin // transport load 1901 Master:=MoveInfo.ToMaster; 1902 if MoveInfo.ToMaster>=0 then 1903 begin 1904 if PModel.Domain=dAir then inc(Un[MoveInfo.ToMaster].AirLoad) 1905 else inc(Un[MoveInfo.ToMaster].TroopLoad); 2202 if (MoveInfo.MoveType = mtCapture) and (nUpdateLoc > 0) then 2203 RecalcMapZoC(p); 2204 UpdateUnitMap(ToLoc, MoveInfo.MoveType = mtCapture); 2205 for i := 0 to nUpdateLoc - 1 do 2206 UpdateUnitMap(UpdateLoc[i]); 2207 // tell about lost units of defender 2208 2209 if (MoveInfo.MoveType <> mtSpyMission) and (Master < 0) then 2210 begin 2211 if (PModel.Kind = mkDiplomat) or (PModel.Domain = dAir) or 2212 (PModel.Cap[mcRadar] + PModel.Cap[mcCarrier] + PModel.Cap[mcAcademy] > 2213 0) or (RealMap[ToLoc] and fTerrain = fMountains) or 2214 (RealMap[ToLoc] and fTerImp = tiFort) or 2215 (RealMap[ToLoc] and fTerImp = tiBase) then 2216 ExtDiscover := true; 2217 if (PModel.Kind = mkDiplomat) or (PModel.Cap[mcSpy] > 0) then 2218 i := lObserveSuper 2219 else if (PModel.Domain = dAir) or 2220 (PModel.Cap[mcRadar] + PModel.Cap[mcCarrier] > 0) then 2221 i := lObserveAll 2222 else 2223 i := lObserveUnhidden; 2224 if ExtDiscover then 2225 begin 2226 if Discover21(ToLoc, p, i, true, PModel.Domain = dGround) then 2227 result := result or rEnemySpotted; 1906 2228 end 1907 else PlaceUnit(p,uix); 2229 else 2230 begin 2231 if Discover9(ToLoc, p, i, true, PModel.Domain = dGround) then 2232 result := result or rEnemySpotted; 2233 end; 1908 2234 end; 1909 2235 1910 if (MoveInfo.MoveType=mtCapture) and (nUpdateLoc>0) then 1911 RecalcMapZoC(p); 1912 UpdateUnitMap(ToLoc,MoveInfo.MoveType=mtCapture); 1913 for i:=0 to nUpdateLoc-1 do UpdateUnitMap(UpdateLoc[i]); 1914 // tell about lost units of defender 1915 1916 if (MoveInfo.MoveType<>mtSpyMission) and (Master<0) then 1917 begin 1918 if (PModel.Kind=mkDiplomat) or (PModel.Domain=dAir) 1919 or (PModel.Cap[mcRadar]+PModel.Cap[mcCarrier]+PModel.Cap[mcAcademy]>0) 1920 or (RealMap[ToLoc] and fTerrain=fMountains) 1921 or (RealMap[ToLoc] and fTerImp=tiFort) 1922 or (RealMap[ToLoc] and fTerImp=tiBase) then 1923 ExtDiscover:=true; 1924 if (PModel.Kind=mkDiplomat) or (PModel.Cap[mcSpy]>0) then 1925 i:=lObserveSuper 1926 else if (PModel.Domain=dAir) 1927 or (PModel.Cap[mcRadar]+PModel.Cap[mcCarrier]>0) then 1928 i:=lObserveAll 1929 else i:=lObserveUnhidden; 1930 if ExtDiscover then 1931 begin 1932 if Discover21(ToLoc,p,i,true, PModel.Domain=dGround) then 1933 result:=result or rEnemySpotted; 1934 end 1935 else 1936 begin 1937 if Discover9(ToLoc,p,i,true, PModel.Domain=dGround) then 1938 result:=result or rEnemySpotted; 1939 end; 1940 end; 1941 1942 if Mode>=moMovie then {show after-move in interface modules} 1943 for p1:=0 to nPl-1 do 1944 if (1 shl p1 and GWatching<>0) 1945 and ((p1<>p) or (bix[p1]=bixTerm)) then 2236 if Mode >= moMovie then { show after-move in interface modules } 2237 for p1 := 0 to nPl - 1 do 2238 if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm)) 2239 then 1946 2240 begin 1947 if PModel.Cap[mcStealth]>0 then MinLevel:=lObserveSuper 1948 else if PModel.Cap[mcSub]>0 then MinLevel:=lObserveAll 1949 else MinLevel:=lObserveUnhidden; 1950 SeeFrom:= (p1=p) or (ObserveLevel[FromLoc] shr (2*p1) and 3>=MinLevel); 1951 SeeTo:= (p1=p) or (ObserveLevel[ToLoc] shr (2*p1) and 3>=MinLevel); 1952 if SeeTo and (MoveInfo.MoveType=mtCapture) then 1953 CallPlayer(cShowCityChanged,p1,ToLoc); 1954 if SeeFrom and SeeTo then 1955 CallPlayer(cShowAfterMove,p1,ToLoc) 1956 else if (MoveInfo.MoveType<>mtSpyMission) and SeeTo then 1957 CallPlayer(cShowUnitChanged,p1,ToLoc); 1958 for i:=0 to nUpdateLoc-1 do 1959 if ObserveLevel[UpdateLoc[i]] shr (2*p1) and 3>=lObserveUnhidden then 1960 CallPlayer(cShowUnitChanged,p1,UpdateLoc[i]); 2241 if PModel.Cap[mcStealth] > 0 then 2242 MinLevel := lObserveSuper 2243 else if PModel.Cap[mcSub] > 0 then 2244 MinLevel := lObserveAll 2245 else 2246 MinLevel := lObserveUnhidden; 2247 SeeFrom := (p1 = p) or (ObserveLevel[FromLoc] shr (2 * p1) and 2248 3 >= MinLevel); 2249 SeeTo := (p1 = p) or (ObserveLevel[ToLoc] shr (2 * p1) and 2250 3 >= MinLevel); 2251 if SeeTo and (MoveInfo.MoveType = mtCapture) then 2252 CallPlayer(cShowCityChanged, p1, ToLoc); 2253 if SeeFrom and SeeTo then 2254 CallPlayer(cShowAfterMove, p1, ToLoc) 2255 else if (MoveInfo.MoveType <> mtSpyMission) and SeeTo then 2256 CallPlayer(cShowUnitChanged, p1, ToLoc); 2257 for i := 0 to nUpdateLoc - 1 do 2258 if ObserveLevel[UpdateLoc[i]] shr (2 * p1) and 3 >= lObserveUnhidden 2259 then 2260 CallPlayer(cShowUnitChanged, p1, UpdateLoc[i]); 1961 2261 end; 1962 2262 end; 1963 2263 end; // ExecuteMove 1964 2264 1965 function ExecuteAttack(p, uix,ToLoc: integer;1966 var MoveInfo: TMoveInfo;ShowMove: TShowMove): integer;1967 1968 procedure WriteBattleHistory(ToLoc, FromLoc, Attacker, Defender, 1969 mix Attacker, mixDefender: integer; AttackerLost, DefenderLost: boolean);2265 function ExecuteAttack(p, uix, ToLoc: integer; var MoveInfo: TMoveInfo; 2266 ShowMove: TShowMove): integer; 2267 2268 procedure WriteBattleHistory(ToLoc, FromLoc, Attacker, Defender, mixAttacker, 2269 mixDefender: integer; AttackerLost, DefenderLost: boolean); 1970 2270 var 1971 AttackerBattle, DefenderBattle: ^TBattle;2271 AttackerBattle, DefenderBattle: ^TBattle; 1972 2272 begin 1973 with RW[Attacker] do2273 with RW[Attacker] do 1974 2274 begin 1975 if nBattleHistory=0 then1976 ReallocMem(BattleHistory, 16*SizeOf(TBattle))1977 else if (nBattleHistory>=16)1978 and (nBattleHistory and (nBattleHistory-1)=0) then1979 ReallocMem(BattleHistory, nBattleHistory*(2*SizeOf(TBattle)));1980 AttackerBattle:=@BattleHistory[nBattleHistory];1981 inc(nBattleHistory);2275 if nBattleHistory = 0 then 2276 ReallocMem(BattleHistory, 16 * SizeOf(TBattle)) 2277 else if (nBattleHistory >= 16) and 2278 (nBattleHistory and (nBattleHistory - 1) = 0) then 2279 ReallocMem(BattleHistory, nBattleHistory * (2 * SizeOf(TBattle))); 2280 AttackerBattle := @BattleHistory[nBattleHistory]; 2281 inc(nBattleHistory); 1982 2282 end; 1983 with RW[Defender] do2283 with RW[Defender] do 1984 2284 begin 1985 if nBattleHistory=0 then1986 ReallocMem(BattleHistory, 16*SizeOf(TBattle))1987 else if (nBattleHistory>=16)1988 and (nBattleHistory and (nBattleHistory-1)=0) then1989 ReallocMem(BattleHistory, nBattleHistory*(2*SizeOf(TBattle)));1990 DefenderBattle:=@BattleHistory[nBattleHistory];1991 inc(nBattleHistory);2285 if nBattleHistory = 0 then 2286 ReallocMem(BattleHistory, 16 * SizeOf(TBattle)) 2287 else if (nBattleHistory >= 16) and 2288 (nBattleHistory and (nBattleHistory - 1) = 0) then 2289 ReallocMem(BattleHistory, nBattleHistory * (2 * SizeOf(TBattle))); 2290 DefenderBattle := @BattleHistory[nBattleHistory]; 2291 inc(nBattleHistory); 1992 2292 end; 1993 AttackerBattle.Enemy:=Defender;1994 AttackerBattle.Flags:=0;1995 AttackerBattle.Turn:=GTurn;1996 AttackerBattle.mix:=mixAttacker;1997 AttackerBattle.mixEnemy:=mixDefender;1998 AttackerBattle.ToLoc:=ToLoc;1999 AttackerBattle.FromLoc:=FromLoc;2000 DefenderBattle.Enemy:=Attacker;2001 DefenderBattle.Flags:=bhEnemyAttack;2002 DefenderBattle.Turn:=GTurn;2003 DefenderBattle.mix:=mixDefender;2004 DefenderBattle.mixEnemy:=mixAttacker;2005 DefenderBattle.ToLoc:=ToLoc;2006 DefenderBattle.FromLoc:=FromLoc;2007 if AttackerLost then2293 AttackerBattle.Enemy := Defender; 2294 AttackerBattle.Flags := 0; 2295 AttackerBattle.Turn := GTurn; 2296 AttackerBattle.mix := mixAttacker; 2297 AttackerBattle.mixEnemy := mixDefender; 2298 AttackerBattle.ToLoc := ToLoc; 2299 AttackerBattle.FromLoc := FromLoc; 2300 DefenderBattle.Enemy := Attacker; 2301 DefenderBattle.Flags := bhEnemyAttack; 2302 DefenderBattle.Turn := GTurn; 2303 DefenderBattle.mix := mixDefender; 2304 DefenderBattle.mixEnemy := mixAttacker; 2305 DefenderBattle.ToLoc := ToLoc; 2306 DefenderBattle.FromLoc := FromLoc; 2307 if AttackerLost then 2008 2308 begin 2009 AttackerBattle.Flags:=AttackerBattle.Flags or bhMyUnitLost;2010 DefenderBattle.Flags:=DefenderBattle.Flags or bhEnemyUnitLost;2309 AttackerBattle.Flags := AttackerBattle.Flags or bhMyUnitLost; 2310 DefenderBattle.Flags := DefenderBattle.Flags or bhEnemyUnitLost; 2011 2311 end; 2012 if DefenderLost then2312 if DefenderLost then 2013 2313 begin 2014 AttackerBattle.Flags:=AttackerBattle.Flags or bhEnemyUnitLost;2015 DefenderBattle.Flags:=DefenderBattle.Flags or bhMyUnitLost;2314 AttackerBattle.Flags := AttackerBattle.Flags or bhEnemyUnitLost; 2315 DefenderBattle.Flags := DefenderBattle.Flags or bhMyUnitLost; 2016 2316 end; 2017 2317 end; 2018 2318 2019 2319 var 2020 i,p1,FromLoc,uix1,nUpdateLoc,ExpGain, ExpelToLoc,cix1: integer;2021 PModel: ^TModel;2022 UpdateLoc: array[0..numax-1] of integer;2023 LoseCityPop,CityDestroyed,SeeFrom,SeeTo,ZoCDefenderDestroyed: boolean;2320 i, p1, FromLoc, uix1, nUpdateLoc, ExpGain, ExpelToLoc, cix1: integer; 2321 PModel: ^TModel; 2322 UpdateLoc: array [0 .. numax - 1] of integer; 2323 LoseCityPop, CityDestroyed, SeeFrom, SeeTo, ZoCDefenderDestroyed: boolean; 2024 2324 begin 2025 result:=0;2026 with RW[p].Un[uix] do2325 result := 0; 2326 with RW[p].Un[uix] do 2027 2327 begin 2028 PModel:=@RW[p].Model[mix];2029 FromLoc:=Loc;2030 2031 ShowMove.EndHealth:=MoveInfo.EndHealth;2032 ShowMove.EndHealthDef:=MoveInfo.EndHealthDef;2033 if MoveInfo.MoveType=mtAttack then2034 WriteBattleHistory(ToLoc, FromLoc, p, MoveInfo.Defender, mix,2035 RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix,2036 MoveInfo.EndHealth<=0, MoveInfo.EndHealthDef<=0);2037 2038 {if RW[p].Treaty[MoveInfo.Defender]=trCeaseFire then2039 begin2040 if Mode>=moMovie then2328 PModel := @RW[p].Model[mix]; 2329 FromLoc := Loc; 2330 2331 ShowMove.EndHealth := MoveInfo.EndHealth; 2332 ShowMove.EndHealthDef := MoveInfo.EndHealthDef; 2333 if MoveInfo.MoveType = mtAttack then 2334 WriteBattleHistory(ToLoc, FromLoc, p, MoveInfo.Defender, mix, 2335 RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix, MoveInfo.EndHealth <= 0, 2336 MoveInfo.EndHealthDef <= 0); 2337 2338 { if RW[p].Treaty[MoveInfo.Defender]=trCeaseFire then 2339 begin 2340 if Mode>=moMovie then 2041 2341 CallPlayer(cShowCancelTreaty,MoveInfo.Defender,p); 2042 CancelTreaty(p,MoveInfo.Defender)2043 end;}2044 if Mode>=moMovie then {show attack in interface modules}2045 for p1:=0 to nPl-1 do2046 if (1 shl p1 and GWatching<>0)2047 and ((p1<>p) or (bix[p1]=bixTerm))then2342 CancelTreaty(p,MoveInfo.Defender) 2343 end; } 2344 if Mode >= moMovie then { show attack in interface modules } 2345 for p1 := 0 to nPl - 1 do 2346 if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm)) 2347 then 2048 2348 begin 2049 SeeFrom:= ObserveLevel[FromLoc] shr (2*p1) and 3>=lObserveUnhidden; 2050 SeeTo:= ObserveLevel[ToLoc] shr (2*p1) and 3>=lObserveUnhidden; 2051 if SeeFrom and SeeTo then 2349 SeeFrom := ObserveLevel[FromLoc] shr (2 * p1) and 2350 3 >= lObserveUnhidden; 2351 SeeTo := ObserveLevel[ToLoc] shr (2 * p1) and 3 >= lObserveUnhidden; 2352 if SeeFrom and SeeTo then 2052 2353 begin 2053 TellAboutModel(p1,p,mix); 2054 if p1=p then ShowMove.emix:=-1 2055 else ShowMove.emix:=emixSafe(p1,p,mix); 2056 CallPlayer(cShowAttacking,p1,ShowMove); 2354 TellAboutModel(p1, p, mix); 2355 if p1 = p then 2356 ShowMove.emix := -1 2357 else 2358 ShowMove.emix := emixSafe(p1, p, mix); 2359 CallPlayer(cShowAttacking, p1, ShowMove); 2057 2360 end; 2058 2361 end; 2059 2362 2060 LoseCityPop:=false; 2061 if (RealMap[ToLoc] and fCity<>0) and 2062 ((MoveInfo.MoveType=mtAttack) and (MoveInfo.EndHealthDef<=0) 2063 or (MoveInfo.MoveType=mtBombard) and (BombardmentDestroysCity or (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size>2))) then 2064 case PModel.Domain of 2065 dGround: LoseCityPop:= (PModel.Cap[mcArtillery]>0) 2066 or (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Built[imWalls]=0) 2067 and (Continent[ToLoc]<>GrWallContinent[MoveInfo.Defender]); 2068 dSea: LoseCityPop:= RW[MoveInfo.Defender].City[MoveInfo.Dcix].Built[imCoastalFort]=0; 2069 dAir: LoseCityPop:= RW[MoveInfo.Defender].City[MoveInfo.Dcix].Built[imMissileBat]=0; 2070 end; 2071 CityDestroyed:=LoseCityPop and (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size<=2); 2072 2073 if MoveInfo.MoveType=mtBombard then 2363 LoseCityPop := false; 2364 if (RealMap[ToLoc] and fCity <> 0) and 2365 ((MoveInfo.MoveType = mtAttack) and (MoveInfo.EndHealthDef <= 0) or 2366 (MoveInfo.MoveType = mtBombard) and (BombardmentDestroysCity or 2367 (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size > 2))) then 2368 case PModel.Domain of 2369 dGround: 2370 LoseCityPop := (PModel.Cap[mcArtillery] > 0) or 2371 (RW[MoveInfo.Defender].City[MoveInfo.Dcix].built[imWalls] = 0) and 2372 (Continent[ToLoc] <> GrWallContinent[MoveInfo.Defender]); 2373 dSea: 2374 LoseCityPop := RW[MoveInfo.Defender].City[MoveInfo.Dcix].built 2375 [imCoastalFort] = 0; 2376 dAir: 2377 LoseCityPop := RW[MoveInfo.Defender].City[MoveInfo.Dcix].built 2378 [imMissileBat] = 0; 2379 end; 2380 CityDestroyed := LoseCityPop and 2381 (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size <= 2); 2382 2383 if MoveInfo.MoveType = mtBombard then 2074 2384 begin 2075 assert(Movement>=100); 2076 if PModel.Attack=0 then Flags:=Flags and not unBombsLoaded; 2077 dec(Movement,100) 2385 assert(Movement >= 100); 2386 if PModel.Attack = 0 then 2387 Flags := Flags and not unBombsLoaded; 2388 dec(Movement, 100) 2078 2389 end 2079 else if MoveInfo.MoveType=mtExpel then2390 else if MoveInfo.MoveType = mtExpel then 2080 2391 begin 2081 assert(Movement>=100);2082 Job:=jNone;2083 Flags:=Flags and not unFortified;2084 dec(Movement,100)2392 assert(Movement >= 100); 2393 Job := jNone; 2394 Flags := Flags and not unFortified; 2395 dec(Movement, 100) 2085 2396 end 2086 else2397 else 2087 2398 begin 2088 assert(MoveInfo.MoveType=mtAttack); 2089 if MoveInfo.EndHealth=0 then 2090 RemoveUnit(p,uix,MoveInfo.Defender) // destroy attacker 2399 assert(MoveInfo.MoveType = mtAttack); 2400 if MoveInfo.EndHealth = 0 then 2401 RemoveUnit(p, uix, MoveInfo.Defender) // destroy attacker 2402 else 2403 begin // update attacker 2404 ExpGain := (Health - MoveInfo.EndHealth + 1) shr 1; 2405 if Exp + ExpGain > (nExp - 1) * ExpCost then 2406 Exp := (nExp - 1) * ExpCost 2407 else 2408 inc(Exp, ExpGain); 2409 Health := MoveInfo.EndHealth; 2410 Job := jNone; 2411 if RW[MoveInfo.Defender].Model[RW[MoveInfo.Defender].Un[MoveInfo.Duix] 2412 .mix].Domain < dAir then 2413 Flags := Flags and not unBombsLoaded; 2414 Flags := Flags and not unFortified; 2415 if Movement > 100 then 2416 dec(Movement, 100) 2417 else 2418 Movement := 0; 2419 end; 2420 end; 2421 2422 ZoCDefenderDestroyed := false; 2423 nUpdateLoc := 0; 2424 if MoveInfo.MoveType = mtExpel then 2425 with RW[MoveInfo.Defender], Un[MoveInfo.Duix] do 2426 begin // expel friendly unit 2427 if Home >= 0 then 2428 ExpelToLoc := City[Home].Loc 2429 else 2430 begin 2431 ExpelToLoc := City[0].Loc; // search destination for homeless units 2432 for cix1 := 1 to nCity - 1 do 2433 if (City[cix1].Loc >= 0) and 2434 ((ExpelToLoc < 0) or (City[cix1].built[imPalace] > 0)) then 2435 ExpelToLoc := City[cix1].Loc; 2436 end; 2437 if ExpelToLoc >= 0 then 2438 begin 2439 FreeUnit(MoveInfo.Defender, MoveInfo.Duix); 2440 Loc := ExpelToLoc; 2441 PlaceUnit(MoveInfo.Defender, MoveInfo.Duix); 2442 UpdateLoc[nUpdateLoc] := Loc; 2443 inc(nUpdateLoc); 2444 Flags := Flags or unWithdrawn; 2445 end 2446 end 2447 else if (MoveInfo.MoveType = mtAttack) and (MoveInfo.EndHealthDef > 0) then 2448 with RW[MoveInfo.Defender].Un[MoveInfo.Duix] do 2449 begin // update defender 2450 ExpGain := (Health - MoveInfo.EndHealthDef + 1) shr 1; 2451 if Exp + ExpGain > (nExp - 1) * ExpCost then 2452 Exp := (nExp - 1) * ExpCost 2453 else 2454 inc(Exp, ExpGain); 2455 Health := MoveInfo.EndHealthDef; 2456 end 2091 2457 else 2092 begin // update attacker2093 ExpGain:=(Health-MoveInfo.EndHealth+1) shr 1;2094 if Exp+ExpGain>(nExp-1)*ExpCost then Exp:=(nExp-1)*ExpCost2095 else inc(Exp,ExpGain);2096 Health:=MoveInfo.EndHealth;2097 Job:=jNone;2098 if RW[MoveInfo.Defender].Model[RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix].Domain<dAir then2099 Flags:=Flags and not unBombsLoaded;2100 Flags:=Flags and not unFortified;2101 if Movement>100 then dec(Movement,100)2102 else Movement:=0;2103 end;2104 end;2105 2106 ZoCDefenderDestroyed:=false;2107 nUpdateLoc:=0;2108 if MoveInfo.MoveType=mtExpel then with RW[MoveInfo.Defender],Un[MoveInfo.Duix] do2109 begin // expel friendly unit2110 if Home>=0 then ExpelToLoc:=City[Home].Loc2111 else2112 begin2113 ExpelToLoc:=City[0].Loc; // search destination for homeless units2114 for cix1:=1 to nCity-1 do2115 if (City[cix1].Loc>=0) and ((ExpelToLoc<0) or (City[cix1].Built[imPalace]>0)) then2116 ExpelToLoc:=City[cix1].Loc;2117 end;2118 if ExpelToLoc>=0 then2119 begin2120 FreeUnit(MoveInfo.Defender,MoveInfo.Duix);2121 Loc:=ExpelToLoc;2122 PlaceUnit(MoveInfo.Defender,MoveInfo.Duix);2123 UpdateLoc[nUpdateLoc]:=Loc;2124 inc(nUpdateLoc);2125 Flags:=Flags or unWithdrawn;2126 end2127 end2128 else if (MoveInfo.MoveType=mtAttack) and (MoveInfo.EndHealthDef>0) then2129 with RW[MoveInfo.Defender].Un[MoveInfo.Duix] do2130 begin // update defender2131 ExpGain:=(Health-MoveInfo.EndHealthDef+1) shr 1;2132 if Exp+ExpGain>(nExp-1)*ExpCost then Exp:=(nExp-1)*ExpCost2133 else inc(Exp,ExpGain);2134 Health:=MoveInfo.EndHealthDef;2135 end2136 else2137 2458 begin // destroy defenders 2138 if MoveInfo.MoveType<>mtBombard then 2139 begin 2140 ZoCDefenderDestroyed:=RW[MoveInfo.Defender].Model[RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix].Flags and mdZOC<>0; 2141 if ((RealMap[ToLoc] and fCity=0) 2142 and (RealMap[ToLoc] and fTerImp<>tiBase) 2143 and (RealMap[ToLoc] and fTerImp<>tiFort)) 2144 or LoseCityPop and (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size=2) then 2145 RemoveAllUnits(MoveInfo.Defender,ToLoc,p) {no city, base or fortress} 2146 else RemoveUnit(MoveInfo.Defender,MoveInfo.Duix,p); 2147 end; 2148 2149 if LoseCityPop then // city defender defeated -- shrink city 2150 if not CityDestroyed then 2151 CityShrink(MoveInfo.Defender,MoveInfo.Dcix) 2152 else 2459 if MoveInfo.MoveType <> mtBombard then 2460 begin 2461 ZoCDefenderDestroyed := RW[MoveInfo.Defender].Model 2462 [RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix].Flags and mdZOC <> 0; 2463 if ((RealMap[ToLoc] and fCity = 0) and 2464 (RealMap[ToLoc] and fTerImp <> tiBase) and 2465 (RealMap[ToLoc] and fTerImp <> tiFort)) or LoseCityPop and 2466 (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size = 2) then 2467 RemoveAllUnits(MoveInfo.Defender, ToLoc, p) 2468 { no city, base or fortress } 2469 else 2470 RemoveUnit(MoveInfo.Defender, MoveInfo.Duix, p); 2471 end; 2472 2473 if LoseCityPop then // city defender defeated -- shrink city 2474 if not CityDestroyed then 2475 CityShrink(MoveInfo.Defender, MoveInfo.Dcix) 2476 else 2153 2477 begin 2154 for uix1:=0 to RW[MoveInfo.Defender].nUn-1 do with RW[MoveInfo.Defender].Un[uix1] do 2155 if (Loc>=0) and (Home=MoveInfo.Dcix) then 2156 begin UpdateLoc[nUpdateLoc]:=Loc; inc(nUpdateLoc) end; 2157 // unit will be removed -- remember position and update for all players 2158 DestroyCity_TellPlayers(MoveInfo.Defender,MoveInfo.Dcix,false); 2159 CheckBorders(ToLoc,MoveInfo.Defender); 2160 RecalcPeaceMap(p); 2478 for uix1 := 0 to RW[MoveInfo.Defender].nUn - 1 do 2479 with RW[MoveInfo.Defender].Un[uix1] do 2480 if (Loc >= 0) and (Home = MoveInfo.Dcix) then 2481 begin 2482 UpdateLoc[nUpdateLoc] := Loc; 2483 inc(nUpdateLoc) 2484 end; 2485 // unit will be removed -- remember position and update for all players 2486 DestroyCity_TellPlayers(MoveInfo.Defender, MoveInfo.Dcix, false); 2487 CheckBorders(ToLoc, MoveInfo.Defender); 2488 RecalcPeaceMap(p); 2161 2489 end; 2162 2490 end; 2163 2491 2164 if CityDestroyed and (nUpdateLoc>0) then 2165 RecalcMapZoC(p) 2166 else if ZoCDefenderDestroyed then 2167 RecalcV8ZoC(p,ToLoc); 2168 UpdateUnitMap(FromLoc); 2169 UpdateUnitMap(ToLoc,LoseCityPop); 2170 for i:=0 to nUpdateLoc-1 do UpdateUnitMap(UpdateLoc[i]); 2492 if CityDestroyed and (nUpdateLoc > 0) then 2493 RecalcMapZoC(p) 2494 else if ZoCDefenderDestroyed then 2495 RecalcV8ZoC(p, ToLoc); 2496 UpdateUnitMap(FromLoc); 2497 UpdateUnitMap(ToLoc, LoseCityPop); 2498 for i := 0 to nUpdateLoc - 1 do 2499 UpdateUnitMap(UpdateLoc[i]); 2171 2500 // tell about lost units of defender 2172 2501 2173 if Mode>=moMovie then2502 if Mode >= moMovie then 2174 2503 begin 2175 for i:=0 to RW[p].nEnemyModel-1 do with RW[p].EnemyModel[i] do 2176 Lost:=Destroyed[p,Owner,mix]; 2177 for p1:=0 to nPl-1 do {show after-attack in interface modules} 2178 if (1 shl p1 and GWatching<>0) 2179 and ((p1<>p) or (bix[p1]=bixTerm)) then 2504 for i := 0 to RW[p].nEnemyModel - 1 do 2505 with RW[p].EnemyModel[i] do 2506 Lost := Destroyed[p, Owner, mix]; 2507 for p1 := 0 to nPl - 1 do { show after-attack in interface modules } 2508 if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm)) 2509 then 2180 2510 begin 2181 SeeFrom:= ObserveLevel[FromLoc] shr (2*p1) and 3>=lObserveUnhidden; 2182 SeeTo:= ObserveLevel[ToLoc] shr (2*p1) and 3>=lObserveUnhidden; 2183 if SeeTo and CityDestroyed then 2184 CallPlayer(cShowCityChanged,p1,ToLoc); // city was destroyed 2185 if SeeFrom and SeeTo then 2511 SeeFrom := ObserveLevel[FromLoc] shr (2 * p1) and 2512 3 >= lObserveUnhidden; 2513 SeeTo := ObserveLevel[ToLoc] shr (2 * p1) and 3 >= lObserveUnhidden; 2514 if SeeTo and CityDestroyed then 2515 CallPlayer(cShowCityChanged, p1, ToLoc); // city was destroyed 2516 if SeeFrom and SeeTo then 2186 2517 begin 2187 CallPlayer(cShowAfterAttack,p1,ToLoc);2188 CallPlayer(cShowAfterAttack,p1,FromLoc);2518 CallPlayer(cShowAfterAttack, p1, ToLoc); 2519 CallPlayer(cShowAfterAttack, p1, FromLoc); 2189 2520 end 2190 else2521 else 2191 2522 begin 2192 if SeeTo then2193 CallPlayer(cShowUnitChanged,p1,ToLoc);2194 if SeeFrom then2195 CallPlayer(cShowUnitChanged,p1,FromLoc);2523 if SeeTo then 2524 CallPlayer(cShowUnitChanged, p1, ToLoc); 2525 if SeeFrom then 2526 CallPlayer(cShowUnitChanged, p1, FromLoc); 2196 2527 end; 2197 if SeeTo and (MoveInfo.MoveType=mtExpel) and (ExpelToLoc>=0) then2198 CallPlayer(cShowUnitChanged,p1,ExpelToLoc);2528 if SeeTo and (MoveInfo.MoveType = mtExpel) and (ExpelToLoc >= 0) then 2529 CallPlayer(cShowUnitChanged, p1, ExpelToLoc); 2199 2530 end; 2200 2531 end … … 2202 2533 end; // ExecuteAttack 2203 2534 2204 function MoveUnit(p, uix,dx,dy: integer; TestOnly: boolean): integer;2535 function MoveUnit(p, uix, dx, dy: integer; TestOnly: boolean): integer; 2205 2536 var 2206 ToLoc: integer;2207 MoveInfo: TMoveInfo;2208 ShowMove: TShowMove;2537 ToLoc: integer; 2538 MoveInfo: TMoveInfo; 2539 ShowMove: TShowMove; 2209 2540 begin 2210 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap =0);{$ENDIF}2211 with RW[p].Un[uix] do2541 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap = 0); {$ENDIF} 2542 with RW[p].Un[uix] do 2212 2543 begin 2213 ToLoc:=dLoc(Loc,dx,dy); 2214 if (ToLoc<0) or (ToLoc>=MapSize) then 2215 begin result:=eInvalid; exit end; 2216 result:=CalculateMove(p,uix,ToLoc,3-dy and 1,TestOnly,MoveInfo); 2217 if result=eZOC_EnemySpotted then 2218 ZOCTile:=ToLoc; 2219 if (result>=rExecuted) and not TestOnly then 2544 ToLoc := dLoc(Loc, dx, dy); 2545 if (ToLoc < 0) or (ToLoc >= MapSize) then 2220 2546 begin 2221 ShowMove.dx:=dx; 2222 ShowMove.dy:=dy; 2223 ShowMove.FromLoc:=Loc; 2224 ShowMove.mix:=mix; 2225 ShowMove.Health:=Health; 2226 ShowMove.Fuel:=Fuel; 2227 ShowMove.Exp:=Exp; 2228 ShowMove.Load:=TroopLoad+AirLoad; 2229 ShowMove.Owner:=p; 2230 if (TroopLoad>0) or (AirLoad>0) then 2231 ShowMove.Flags:=unMulti 2232 else ShowMove.Flags:=0; 2233 case MoveInfo.MoveType of 2234 mtCapture: ShowMove.Flags:=ShowMove.Flags or umCapturing; 2235 mtSpyMission: ShowMove.Flags:=ShowMove.Flags or umSpyMission; 2236 mtBombard: ShowMove.Flags:=ShowMove.Flags or umBombarding; 2237 mtExpel: ShowMove.Flags:=ShowMove.Flags or umExpelling; 2238 end; 2239 case MoveInfo.MoveType of 2240 mtMove,mtCapture,mtSpyMission: 2241 result:=ExecuteMove(p,uix,ToLoc,MoveInfo,ShowMove) or result; 2242 mtAttack,mtBombard,mtExpel: 2243 result:=ExecuteAttack(p,uix,ToLoc,MoveInfo,ShowMove) or result 2547 result := eInvalid; 2548 exit 2549 end; 2550 result := CalculateMove(p, uix, ToLoc, 3 - dy and 1, TestOnly, MoveInfo); 2551 if result = eZOC_EnemySpotted then 2552 ZOCTile := ToLoc; 2553 if (result >= rExecuted) and not TestOnly then 2554 begin 2555 ShowMove.dx := dx; 2556 ShowMove.dy := dy; 2557 ShowMove.FromLoc := Loc; 2558 ShowMove.mix := mix; 2559 ShowMove.Health := Health; 2560 ShowMove.Fuel := Fuel; 2561 ShowMove.Exp := Exp; 2562 ShowMove.Load := TroopLoad + AirLoad; 2563 ShowMove.Owner := p; 2564 if (TroopLoad > 0) or (AirLoad > 0) then 2565 ShowMove.Flags := unMulti 2566 else 2567 ShowMove.Flags := 0; 2568 case MoveInfo.MoveType of 2569 mtCapture: 2570 ShowMove.Flags := ShowMove.Flags or umCapturing; 2571 mtSpyMission: 2572 ShowMove.Flags := ShowMove.Flags or umSpyMission; 2573 mtBombard: 2574 ShowMove.Flags := ShowMove.Flags or umBombarding; 2575 mtExpel: 2576 ShowMove.Flags := ShowMove.Flags or umExpelling; 2577 end; 2578 case MoveInfo.MoveType of 2579 mtMove, mtCapture, mtSpyMission: 2580 result := ExecuteMove(p, uix, ToLoc, MoveInfo, ShowMove) or result; 2581 mtAttack, mtBombard, mtExpel: 2582 result := ExecuteAttack(p, uix, ToLoc, MoveInfo, ShowMove) or result 2244 2583 end; 2245 2584 end 2246 2585 end; // with 2247 end; { MoveUnit}2248 2249 function Server(Command, Player,Subject:integer;var Data): integer; stdcall;2586 end; { MoveUnit } 2587 2588 function Server(Command, Player, Subject: integer; var Data): integer; stdcall; 2250 2589 2251 2590 function CountPrice(const Offer: TOffer; PriceType: integer): integer; 2252 2591 var 2253 i: integer;2592 i: integer; 2254 2593 begin 2255 result:=0; 2256 for i:=0 to Offer.nDeliver+Offer.nCost-1 do 2257 if Offer.Price[i] and $FFFF0000=Cardinal(PriceType) then inc(result); 2594 result := 0; 2595 for i := 0 to Offer.nDeliver + Offer.nCost - 1 do 2596 if Offer.Price[i] and $FFFF0000 = Cardinal(PriceType) then 2597 inc(result); 2258 2598 end; 2259 2599 2260 { 2600 { procedure UpdateBorderHelper; 2261 2601 var 2262 2602 x, y, Loc, Loc1, dx, dy, ObserveMask: integer; … … 2264 2604 ObserveMask:=3 shl (2*pTurn); 2265 2605 for x:=0 to lx-1 do for y:=0 to ly shr 1-1 do 2266 begin 2267 Loc:=lx*(y*2)+x; 2268 if ObserveLevel[Loc] and ObserveMask<>0 then 2269 begin 2270 for dy:=0 to 1 do for dx:=0 to 1 do 2606 begin 2607 Loc:=lx*(y*2)+x; 2608 if ObserveLevel[Loc] and ObserveMask<>0 then 2609 begin 2610 for dy:=0 to 1 do for dx:=0 to 1 do 2611 begin 2612 Loc1:=(Loc+dx-1+lx) mod lx +lx*((y+dy)*2-1); 2613 if (Loc1>=0) and (Loc1<MapSize) 2614 and (ObserveLevel[Loc1] and ObserveMask<>0) then 2615 if RealMap[Loc1] and $78000000=RealMap[Loc] and $78000000 then 2616 begin 2617 RW[pTurn].BorderHelper[Loc]:=RW[pTurn].BorderHelper[Loc] and not (1 shl (dy*2+dx)); 2618 RW[pTurn].BorderHelper[Loc1]:=RW[pTurn].BorderHelper[Loc1] and not (8 shr (dy*2+dx)) 2619 end 2620 else 2621 begin 2622 RW[pTurn].BorderHelper[Loc]:=RW[pTurn].BorderHelper[Loc] or (1 shl (dy*2+dx)); 2623 RW[pTurn].BorderHelper[Loc1]:=RW[pTurn].BorderHelper[Loc1] or (8 shr (dy*2+dx)); 2624 end 2625 end 2626 end 2627 end 2628 end; } 2629 2630 const 2631 ptSelect = 0; 2632 ptTrGoods = 1; 2633 ptUn = 2; 2634 ptCaravan = 3; 2635 ptImp = 4; 2636 ptWonder = 6; 2637 ptShip = 7; 2638 ptInvalid = 8; 2639 2640 function ProjectType(Project: integer): integer; 2641 begin 2642 if Project and cpCompleted <> 0 then 2643 result := ptSelect 2644 else if Project and (cpImp + cpIndex) = cpImp + imTrGoods then 2645 result := ptTrGoods 2646 else if Project and cpImp = 0 then 2647 if RW[Player].Model[Project and cpIndex].Kind = mkCaravan then 2648 result := ptCaravan 2649 else 2650 result := ptUn 2651 else if Project and cpIndex >= nImp then 2652 result := ptInvalid 2653 else if Imp[Project and cpIndex].Kind = ikWonder then 2654 result := ptWonder 2655 else if Imp[Project and cpIndex].Kind = ikShipPart then 2656 result := ptShip 2657 else 2658 result := ptImp 2659 end; 2660 2661 const 2662 Dirx: array [0 .. 7] of integer = (1, 2, 1, 0, -1, -2, -1, 0); 2663 Diry: array [0 .. 7] of integer = (-1, 0, 1, 2, 1, 0, -1, -2); 2664 2665 var 2666 d, i, j, p1, p2, pt0, pt1, uix1, cix1, Loc0, Loc1, dx, dy, NewCap, MinCap, 2667 MaxCap, CapWeight, Cost, NextProd, Preq, TotalFood, TotalProd, CheckSum, 2668 StopTurn, FutureMCost, NewProject, OldImp, mix, V8, V21, AStr, DStr, 2669 ABaseDamage, DBaseDamage: integer; 2670 CityReport, AltCityReport: TCityReport; 2671 FormerCLState: TCmdListState; 2672 EndTime: int64; 2673 Adjacent: TVicinity8Loc; 2674 Radius: TVicinity21Loc; 2675 ShowShipChange: TShowShipChange; 2676 ShowNegoData: TShowNegoData; 2677 logged, ok, HasShipChanged, AllHumansDead, OfferFullySupported: boolean; 2678 2679 begin { >>>server } 2680 if Command = sTurn then 2681 begin 2682 p2 := -1; 2683 for p1 := 0 to nPl - 1 do 2684 if (p1 <> Player) and (1 shl p1 and GWatching <> 0) then 2685 CallPlayer(cShowTurnChange, p1, p2); 2686 end; 2687 2688 assert(MapSize = lx * ly); 2689 assert(Command and (sctMask or sExecute) <> sctInternal or sExecute); 2690 // not for internal commands 2691 if (Command < 0) or (Command >= $10000) then 2692 begin 2693 result := eUnknown; 2694 exit 2695 end; 2696 2697 if (Player < 0) or (Player >= nPl) or 2698 ((Command and (sctMask or sExecute) <> sctInfo) and 2699 ((Subject < 0) or (Subject >= $1000))) then 2700 begin 2701 result := eInvalid; 2702 exit 2703 end; 2704 2705 if (1 shl Player and (GAlive or GWatching) = 0) and 2706 not((Command = sTurn) or (Command = sBreak) or (Command = sResign) or 2707 (Command = sGetAIInfo) or (Command = sGetAICredits) or 2708 (Command = sGetVersion) or (Command and $FF0F = sGetChart)) then 2709 begin 2710 PutMessage(1 shl 16 + 1, Format('NOT Alive: %d', [Player])); 2711 result := eNoTurn; 2712 exit 2713 end; 2714 2715 result := eOK; 2716 2717 // check if command allowed now 2718 if (Mode = moPlaying) and not((Command >= cClientEx) or (Command = sMessage) 2719 or (Command = sSetDebugMap) or (Command = sGetDebugMap) or 2720 (Command = sGetAIInfo) or (Command = sGetAICredits) or 2721 (Command = sGetVersion) or (Command = sGetTechCost) or 2722 (Command = sGetDefender) or (Command = sGetUnitReport) or 2723 (Command = sGetCityReport) or (Command = sGetCityTileInfo) or 2724 (Command = sGetCity) or (Command = sGetEnemyCityReport) or 2725 (Command = sGetEnemyCityAreaInfo) or (Command = sGetCityReportNew) or 2726 (Command and $FF0F = sGetChart) or (Command and $FF0F = sSetAttitude)) 2727 // commands always allowed 2728 and not((Player = pTurn) and (Command < $1000)) 2729 // info request always allowed for pTurn 2730 and ((pDipActive < 0) and (Player <> pTurn) // not his turn 2731 or (pDipActive >= 0) and (Player <> pDipActive) 2732 // not active in negotiation mode 2733 or (pDipActive >= 0) and (Command and sctMask <> sctEndClient)) then 2734 // no nego command 2735 begin 2736 PutMessage(1 shl 16 + 1, Format('No Turn: %d calls %x', 2737 [Player, Command shr 4])); 2738 result := eNoTurn; 2739 exit 2740 end; 2741 2742 // do not use EXIT hereafter! 2743 2744 {$IFOPT O-} 2745 HandoverStack[nHandoverStack] := Player + $1000; 2746 HandoverStack[nHandoverStack + 1] := Command; 2747 inc(nHandoverStack, 2); 2748 2749 InvalidTreatyMap := 0; 2750 // new command, sIntExpandTerritory of previous command was processed 2751 {$ENDIF} 2752 if (Mode = moPlaying) and (Command >= sExecute) and 2753 ((Command and sctMask <> sctEndClient) or (Command = sTurn)) and 2754 (Command and sctMask <> sctModel) and (Command <> sCancelTreaty) and 2755 (Command <> sSetCityTiles) and (Command <> sBuyCityProject) and 2756 ((Command < cClientEx) or ProcessClientData[Player]) then 2757 begin { log command } 2758 FormerCLState := CL.State; 2759 CL.Put(Command, Player, Subject, @Data); 2760 logged := true; 2761 end 2762 else 2763 logged := false; 2764 2765 case Command of 2766 2767 { 2768 Info Request Commands 2769 ____________________________________________________________________ 2770 } 2771 sMessage: 2772 Brain[bix[0]].Client(cDebugMessage, Subject, Data); 2773 2774 sSetDebugMap: 2775 DebugMap[Player] := @Data; 2776 2777 sGetDebugMap: 2778 pointer(Data) := DebugMap[Subject]; 2779 2780 { sChangeSuperView: 2781 if Difficulty[Player]=0 then 2782 begin 2783 for i:=0 to nBrain-1 do if Brain[i].Initialized then 2784 CallClient(i, cShowSuperView, Subject) 2785 end 2786 else result:=eInvalid; } 2787 2788 sRefreshDebugMap: 2789 Brain[bix[0]].Client(cRefreshDebugMap, -1, Player); 2790 2791 sGetChart .. sGetChart + (nStat - 1) shl 4: 2792 if (Subject >= 0) and (Subject < nPl) and (bix[Subject] >= 0) then 2793 begin 2794 StopTurn := 0; 2795 if (Difficulty[Player] = 0) or (GTestFlags and tfUncover <> 0) 2796 // supervisor 2797 or (Subject = Player) // own chart 2798 or (GWinner > 0) // game end chart 2799 or (1 shl Subject and GAlive = 0) then // chart of extinct nation 2800 if Subject > Player then 2801 StopTurn := GTurn 2802 else 2803 StopTurn := GTurn + 1 2804 else if RW[Player].Treaty[Subject] > trNoContact then 2805 if Command shr 4 and $F = stMil then 2806 StopTurn := RW[Player].EnemyReport[Subject].TurnOfMilReport + 1 2807 else 2808 StopTurn := RW[Player].EnemyReport[Subject].TurnOfCivilReport + 1; 2809 move(Stat[Command shr 4 and $F, Subject]^, Data, 2810 StopTurn * SizeOf(integer)); 2811 FillChar(TChart(Data)[StopTurn], (GTurn - StopTurn) * 2812 SizeOf(integer), 0); 2813 end 2814 else 2815 result := eInvalid; 2816 2817 sGetTechCost: 2818 integer(Data) := TechCost(Player); 2819 2820 sGetAIInfo: 2821 if AIInfo[Subject] = '' then 2822 pchar(Data) := nil 2823 else 2824 pchar(Data) := @AIInfo[Subject][1]; 2825 2826 sGetAICredits: 2827 if AICredits = '' then 2828 pchar(Data) := nil 2829 else 2830 pchar(Data) := @AICredits[1]; 2831 2832 sGetVersion: 2833 integer(Data) := Version; 2834 2835 sGetGameChanged: 2836 if Player <> 0 then 2837 result := eInvalid 2838 else if (CL <> nil) and (CL.State.nLog = nLogOpened) and 2839 (CL.State.MoveCode = 0) and not HasCityTileChanges and 2840 not HasChanges(Player) then 2841 result := eNotChanged; 2842 2843 sGetTileInfo: 2844 if (Subject >= 0) and (Subject < MapSize) then 2845 result := GetTileInfo(Player, -2, Subject, TTileInfo(Data)) 2846 else 2847 result := eInvalid; 2848 2849 sGetCityTileInfo: 2850 if (Subject >= 0) and (Subject < MapSize) then 2851 result := GetTileInfo(Player, -1, Subject, TTileInfo(Data)) 2852 else 2853 result := eInvalid; 2854 2855 sGetHypoCityTileInfo: 2856 if (Subject >= 0) and (Subject < MapSize) then 2857 begin 2858 if (TTileInfo(Data).ExplCity < 0) or 2859 (TTileInfo(Data).ExplCity >= RW[Player].nCity) then 2860 result := eInvalid 2861 else if ObserveLevel[Subject] shr (Player * 2) and 3 = 0 then 2862 result := eNoPreq 2863 else 2864 result := GetTileInfo(Player, TTileInfo(Data).ExplCity, Subject, 2865 TTileInfo(Data)) 2866 end 2867 else 2868 result := eInvalid; 2869 2870 sGetJobProgress: 2871 if (Subject >= 0) and (Subject < MapSize) then 2872 begin 2873 if ObserveLevel[Subject] shr (Player * 2) and 3 = 0 then 2874 result := eNoPreq 2875 else 2876 result := GetJobProgress(Player, Subject, TJobProgressData(Data)) 2877 end 2878 else 2879 result := eInvalid; 2880 2881 sGetModels: 2882 if (GTestFlags and tfUncover <> 0) or (Difficulty[Player] = 0) 2883 then { supervisor only command } 2884 begin 2885 for p1 := 0 to nPl - 1 do 2886 if (p1 <> Player) and (1 shl p1 and GAlive <> 0) then 2887 for mix := 0 to RW[p1].nModel - 1 do 2888 TellAboutModel(Player, p1, mix); 2889 end 2890 else 2891 result := eInvalid; 2892 2893 sGetUnits: 2894 if (Subject >= 0) and (Subject < MapSize) and 2895 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) then 2896 integer(Data) := GetUnitStack(Player, Subject) 2897 else 2898 result := eNoPreq; 2899 2900 sGetDefender: 2901 if (Subject >= 0) and (Subject < MapSize) and (Occupant[Subject] = Player) 2902 then 2903 Strongest(Subject, integer(Data), d, i, j) 2904 else 2905 result := eInvalid; 2906 2907 sGetBattleForecast, sGetBattleForecastEx: 2908 if (Subject >= 0) and (Subject < MapSize) and 2909 (ObserveLevel[Subject] and (3 shl (Player * 2)) > 0) then 2910 with TBattleForecast(Data) do 2911 if (1 shl pAtt and GAlive <> 0) and (mixAtt >= 0) and 2912 (mixAtt < RW[pAtt].nModel) and 2913 ((pAtt = Player) or (RWemix[Player, pAtt, mixAtt] >= 0)) then 2914 begin 2915 result := GetBattleForecast(Subject, TBattleForecast(Data), uix1, 2916 cix1, AStr, DStr, ABaseDamage, DBaseDamage); 2917 if Command = sGetBattleForecastEx then 2918 begin 2919 TBattleForecastEx(Data).AStr := (AStr + 200) div 400; 2920 TBattleForecastEx(Data).DStr := (DStr + 200) div 400; 2921 TBattleForecastEx(Data).ABaseDamage := ABaseDamage; 2922 TBattleForecastEx(Data).DBaseDamage := DBaseDamage; 2923 end; 2924 if result = eOK then 2925 result := eInvalid // no enemy unit there! 2926 end 2927 else 2928 result := eInvalid 2929 else 2930 result := eInvalid; 2931 2932 sGetUnitReport: 2933 if (Subject < 0) or (Subject >= RW[Player].nUn) or 2934 (RW[Player].Un[Subject].Loc < 0) then 2935 result := eInvalid 2936 else 2937 GetUnitReport(Player, Subject, TUnitReport(Data)); 2938 2939 sGetMoveAdvice: 2940 if (Subject < 0) or (Subject >= RW[Player].nUn) or 2941 (RW[Player].Un[Subject].Loc < 0) then 2942 result := eInvalid 2943 else 2944 result := GetMoveAdvice(Player, Subject, TMoveAdviceData(Data)); 2945 2946 sGetPlaneReturn: 2947 if (Subject < 0) or (Subject >= RW[Player].nUn) or 2948 (RW[Player].Un[Subject].Loc < 0) or 2949 (RW[Player].Model[RW[Player].Un[Subject].mix].Domain <> dAir) then 2950 result := eInvalid 2951 else 2952 begin 2953 if CanPlaneReturn(Player, Subject, TPlaneReturnData(Data)) then 2954 result := eOK 2955 else 2956 result := eNoWay 2957 end; 2958 2959 sGetCity: 2960 if (Subject >= 0) and (Subject < MapSize) and 2961 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) and 2962 (RealMap[Subject] and fCity <> 0) then 2963 with TGetCityData(Data) do 2271 2964 begin 2272 Loc1:=(Loc+dx-1+lx) mod lx +lx*((y+dy)*2-1); 2273 if (Loc1>=0) and (Loc1<MapSize) 2274 and (ObserveLevel[Loc1] and ObserveMask<>0) then 2275 if RealMap[Loc1] and $78000000=RealMap[Loc] and $78000000 then 2965 Owner := Player; 2966 SearchCity(Subject, Owner, cix1); 2967 c := RW[Owner].City[cix1]; 2968 if (Owner <> Player) and (c.Project and cpImp = 0) then 2969 TellAboutModel(Player, Owner, c.Project and cpIndex); 2970 end 2971 else 2972 result := eInvalid; 2973 2974 sGetCityReport: 2975 if (Subject < 0) or (Subject >= RW[Player].nCity) or 2976 (RW[Player].City[Subject].Loc < 0) then 2977 result := eInvalid 2978 else 2979 result := GetCityReport(Player, Subject, TCityReport(Data)); 2980 2981 sGetCityReportNew: 2982 if (Subject < 0) or (Subject >= RW[Player].nCity) or 2983 (RW[Player].City[Subject].Loc < 0) then 2984 result := eInvalid 2985 else 2986 GetCityReportNew(Player, Subject, TCityReportNew(Data)); 2987 2988 sGetCityAreaInfo: 2989 if (Subject < 0) or (Subject >= RW[Player].nCity) or 2990 (RW[Player].City[Subject].Loc < 0) then 2991 result := eInvalid 2992 else 2993 GetCityAreaInfo(Player, RW[Player].City[Subject].Loc, 2994 TCityAreaInfo(Data)); 2995 2996 sGetEnemyCityReport: 2997 if (Subject >= 0) and (Subject < MapSize) and 2998 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) and 2999 (RealMap[Subject] and fCity <> 0) then 3000 begin 3001 p1 := Occupant[Subject]; 3002 if p1 < 0 then 3003 p1 := 1; 3004 SearchCity(Subject, p1, cix1); 3005 TCityReport(Data).HypoTiles := -1; 3006 TCityReport(Data).HypoTax := -1; 3007 TCityReport(Data).HypoLux := -1; 3008 GetCityReport(p1, cix1, TCityReport(Data)) 3009 end 3010 else 3011 result := eInvalid; 3012 3013 sGetEnemyCityReportNew: 3014 if (Subject >= 0) and (Subject < MapSize) and 3015 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) and 3016 (RealMap[Subject] and fCity <> 0) then 3017 begin 3018 p1 := Occupant[Subject]; 3019 if p1 < 0 then 3020 p1 := 1; 3021 SearchCity(Subject, p1, cix1); 3022 TCityReport(Data).HypoTiles := -1; 3023 TCityReport(Data).HypoTax := -1; 3024 TCityReport(Data).HypoLux := -1; 3025 GetCityReportNew(p1, cix1, TCityReportNew(Data)); 3026 end 3027 else 3028 result := eInvalid; 3029 3030 sGetEnemyCityAreaInfo: 3031 if (Subject >= 0) and (Subject < MapSize) and 3032 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) and 3033 (RealMap[Subject] and fCity <> 0) then 3034 begin 3035 p1 := Occupant[Subject]; 3036 if p1 < 0 then 3037 p1 := 1; 3038 SearchCity(Subject, p1, cix1); 3039 GetCityAreaInfo(p1, Subject, TCityAreaInfo(Data)) 3040 end 3041 else 3042 result := eInvalid; 3043 3044 sGetCityTileAdvice: 3045 if (Subject < 0) or (Subject >= RW[Player].nCity) or 3046 (RW[Player].City[Subject].Loc < 0) then 3047 result := eInvalid 3048 else 3049 GetCityTileAdvice(Player, Subject, TCityTileAdviceData(Data)); 3050 3051 { 3052 Map Editor Commands 3053 ____________________________________________________________________ 3054 } 3055 sEditTile: 3056 if Player = 0 then 3057 with TEditTileData(Data) do 3058 EditTile(Loc, NewTile) 3059 else 3060 result := eInvalid; 3061 3062 sRandomMap: 3063 if (Player = 0) and MapGeneratorAvailable then 3064 begin 3065 CreateElevation; 3066 PreviewElevation := false; 3067 CreateMap(false); 3068 FillChar(ObserveLevel, MapSize * 4, 0); 3069 DiscoverAll(Player, lObserveSuper); 3070 end 3071 else 3072 result := eInvalid; 3073 3074 sMapGeneratorRequest: 3075 if not MapGeneratorAvailable then 3076 result := eInvalid; 3077 3078 { 3079 Client Deactivation Commands 3080 ____________________________________________________________________ 3081 } 3082 sTurn, sTurn - sExecute: 3083 begin 3084 AllHumansDead := true; 3085 for p1 := 0 to nPl - 1 do 3086 if (1 shl p1 and GAlive <> 0) and (bix[p1] = bixTerm) then 3087 AllHumansDead := false; 3088 if (pDipActive >= 0) // still in negotiation mode 3089 or (pTurn = 0) and ((GWinner > 0) or (GTurn = MaxTurn) or 3090 (Difficulty[0] > 0) and AllHumansDead) then // game end reached 3091 result := eViolation 3092 else if Command >= sExecute then 3093 begin 3094 if Mode = moPlaying then 3095 begin 3096 CL.State := FormerCLState; 3097 LogCityTileChanges; 3098 {$IFNDEF SCR} 3099 if pTurn = 0 then 2276 3100 begin 2277 RW[pTurn].BorderHelper[Loc]:=RW[pTurn].BorderHelper[Loc] and not (1 shl (dy*2+dx));2278 RW[pTurn].BorderHelper[Loc1]:=RW[pTurn].BorderHelper[Loc1] and not (8 shr (dy*2+dx))3101 LogChanges; 3102 SaveGame('~' + LogFileName, true); 2279 3103 end 3104 {$ENDIF} 3105 end 3106 else if (Mode = moMovie) and (pTurn = 0) then 3107 CallPlayer(cMovieEndTurn, 0, nil^); 3108 GWatching := GWatching and GAlive or 1; 3109 RW[pTurn].Happened := 0; 3110 uixSelectedTransport := -1; 3111 SpyMission := smSabotageProd; 3112 if 1 shl pTurn and GAlive <> 0 then 3113 begin 3114 // calculate checksum 3115 TotalFood := 0; 3116 TotalProd := 0; 3117 for i := 0 to RW[pTurn].nCity - 1 do 3118 if RW[pTurn].City[i].Loc >= 0 then 3119 begin 3120 inc(TotalFood, RW[pTurn].City[i].Food); 3121 inc(TotalProd, RW[pTurn].City[i].Prod); 3122 end; 3123 CheckSum := TotalFood and 7 + TotalProd and 7 shl 3 + 3124 RW[pTurn].Money and 7 shl 6 + Worked[pTurn] div 100 and 7 shl 9; 3125 end 2280 3126 else 3127 CheckSum := 0; 3128 3129 if Mode < moPlaying then // check checksum 3130 begin 3131 if CheckSum <> Subject then 3132 LoadOK := false 3133 end 3134 else // save checksum 3135 CL.Put(Command, Player, CheckSum, @Data); 3136 {$IFDEF TEXTLOG} 3137 CmdInfo := ''; 3138 if CheckSum and 7 <> Subject and 7 then 3139 CmdInfo := Format('***ERROR (Food %d) ', 3140 [(CheckSum and 7 - Subject and 7 + 12) mod 8 - 4]) + CmdInfo; 3141 if CheckSum shr 3 and 7 <> Subject shr 3 and 7 then 3142 CmdInfo := '***ERROR (Prod) ' + CmdInfo; 3143 if CheckSum shr 6 and 7 <> Subject shr 6 and 7 then 3144 CmdInfo := '***ERROR (Research) ' + CmdInfo; 3145 if CheckSum shr 9 and 7 <> Subject shr 9 and 7 then 3146 CmdInfo := '***ERROR (Work) ' + CmdInfo; 3147 {$ENDIF} 3148 if 1 shl pTurn and GAlive <> 0 then 3149 begin 3150 AfterTurn; 3151 if Mode < moPlaying then 3152 InsertTerritoryUpdateCommands; 3153 // if bix[pTurn]=bixTerm then UpdateBorderHelper; 3154 end; 3155 3156 repeat 3157 pTurn := (pTurn + 1) mod nPl; 3158 if pTurn = 0 then 3159 inc(GTurn); 3160 if (bix[pTurn] >= 0) and ((1 shl pTurn) and GAlive = 0) then 3161 begin // already made extinct -- continue statistics 3162 Stat[stExplore, pTurn, GTurn] := 0; 3163 Stat[stPop, pTurn, GTurn] := 0; 3164 Stat[stTerritory, pTurn, GTurn] := 0; 3165 Stat[stScience, pTurn, GTurn] := 0; 3166 Stat[stWork, pTurn, GTurn] := 0; 3167 Stat[stMil, pTurn, GTurn] := 0; 3168 end; 3169 until (pTurn = 0) or ((1 shl pTurn and (GAlive or GWatching) <> 0) and 3170 (GWinner = 0)); 3171 if (Mode = moLoading_Fast) and 3172 ((GTurn = LoadTurn) or (GTurn = LoadTurn - 1) and (pTurn > 0)) then 3173 Mode := moLoading; 3174 if Mode = moPlaying then 3175 begin 3176 CCCommand := cTurn; 3177 CCPlayer := pTurn; 3178 Notify(ntNextPlayer) 3179 end 3180 else 3181 begin 3182 if GTurn = 0 then 3183 BeforeTurn0 3184 else 3185 BeforeTurn; 3186 if (Mode = moMovie) and (pTurn = 0) then 2281 3187 begin 2282 RW[pTurn].BorderHelper[Loc]:=RW[pTurn].BorderHelper[Loc] or (1 shl (dy*2+dx)); 2283 RW[pTurn].BorderHelper[Loc1]:=RW[pTurn].BorderHelper[Loc1] or (8 shr (dy*2+dx)); 2284 end 3188 Inform(pTurn); 3189 CallPlayer(cMovieTurn, 0, nil^); 3190 end; 3191 end; 3192 {$IFDEF TEXTLOG}CmdInfo := CmdInfo + Format('---Turn %d P%d---', [GTurn, pTurn]); {$ENDIF} 3193 end; 3194 end; // sTurn 3195 3196 sBreak, sResign, sNextRound, sReload: 3197 if Mode = moMovie then 3198 MovieStopped := true 3199 else 3200 begin 3201 if Command = sReload then 3202 begin 3203 ok := (Difficulty[0] = 0) and (bix[0] <> bixNoTerm) and 3204 (integer(Data) >= 0) and (integer(Data) < GTurn); 3205 for p1 := 1 to nPl - 1 do 3206 if bix[p1] = bixTerm then 3207 ok := false; 3208 // allow reload in AI-only games only 3209 end 3210 else 3211 ok := Player = 0; 3212 if ok then 3213 begin 3214 if (Command = sBreak) or (Command = sResign) then 3215 Notify(ntBackOn); 3216 for i := 0 to nBrain - 1 do 3217 if Brain[i].Initialized then 3218 begin 3219 if i >= bixFirstAI then 3220 Notify(ntDeinitModule + i); 3221 CallClient(i, cBreakGame, nil^); 3222 end; 3223 Notify(ntEndInfo); 3224 if (Command = sBreak) or (Command = sReload) then 3225 begin 3226 LogCityTileChanges; 3227 LogChanges; 3228 SaveGame(LogFileName, false); 3229 end; 3230 DeleteFile(SavePath + '~' + LogFileName); 3231 EndGame; 3232 case Command of 3233 sBreak: 3234 Notify(ntStartGoRefresh); 3235 sResign: 3236 Notify(ntStartGo); 3237 sNextRound: 3238 StartNewGame(SavePath, LogFileName, MapFileName, lx, ly, 3239 LandMass, MaxTurn); 3240 sReload: 3241 LoadGame(SavePath, LogFileName, integer(Data), false); 3242 end 3243 end 3244 else 3245 result := eInvalid; 3246 end; 3247 3248 sAbandonMap, sSaveMap: 3249 if Player = 0 then 3250 begin 3251 if Command = sSaveMap then 3252 SaveMap(MapFileName); 3253 Notify(ntBackOn); 3254 Brain[bixTerm].Client(cBreakGame, -1, nil^); 3255 ReleaseMapEditor; 3256 if Command = sSaveMap then 3257 Notify(ntStartGoRefreshMaps) 3258 else 3259 Notify(ntStartGo) 3260 end 3261 else 3262 result := eInvalid; 3263 3264 scContact .. scContact + (nPl - 1) shl 4, scContact - sExecute .. scContact 3265 - sExecute + (nPl - 1) shl 4: 3266 if (pDipActive >= 0) or (1 shl (Command shr 4 and $F) and GAlive = 0) then 3267 result := eInvalid 3268 else if GWinner > 0 then 3269 result := eViolation // game end reached 3270 else if RW[Player].Treaty[Command shr 4 and $F] = trNoContact then 3271 result := eNoPreq 3272 else if GTurn < GColdWarStart + ColdWarTurns then 3273 result := eColdWar 3274 else if RW[Player].Government = gAnarchy then 3275 result := eAnarchy 3276 else if RW[Command shr 4 and $F].Government = gAnarchy then 3277 begin 3278 result := eAnarchy; 3279 LastEndClientCommand := scReject; // enable cancel treaty 3280 pContacted := Command shr 4 and $F; 3281 end 3282 else if Command >= sExecute then 3283 begin // contact request 3284 pContacted := Command shr 4 and $F; 3285 pDipActive := pContacted; 3286 assert(Mode = moPlaying); 3287 Inform(pDipActive); 3288 ChangeClientWhenDone(scContact, pDipActive, pTurn, 4); 3289 end; 3290 3291 scReject, scReject - sExecute: 3292 if LastEndClientCommand and $FF0F = scContact then 3293 begin 3294 if Command >= sExecute then 3295 begin // contact requested and not accepted yet 3296 pDipActive := -1; 3297 assert(Mode = moPlaying); 3298 ChangeClientWhenDone(cContinue, pTurn, nil^, 0); 2285 3299 end 2286 3300 end 2287 end 2288 end;} 2289 2290 const 2291 ptSelect=0; ptTrGoods=1; ptUn=2; ptCaravan=3; ptImp=4; ptWonder=6; 2292 ptShip=7; ptInvalid=8; 2293 2294 function ProjectType(Project: integer): integer; 2295 begin 2296 if Project and cpCompleted<>0 then result:=ptSelect 2297 else if Project and (cpImp+cpIndex)=cpImp+imTrGoods then result:=ptTrGoods 2298 else if Project and cpImp=0 then 2299 if RW[Player].Model[Project and cpIndex].Kind=mkCaravan then result:=ptCaravan 2300 else result:=ptUn 2301 else if Project and cpIndex>=nImp then result:=ptInvalid 2302 else if Imp[Project and cpIndex].Kind=ikWonder then result:=ptWonder 2303 else if Imp[Project and cpIndex].Kind=ikShipPart then result:=ptShip 2304 else result:=ptImp 2305 end; 2306 2307 const 2308 Dirx: array[0..7] of integer=(1,2,1,0,-1,-2,-1,0); 2309 Diry: array[0..7] of integer=(-1,0,1,2,1,0,-1,-2); 2310 2311 var 2312 d,i,j,p1,p2,pt0,pt1,uix1,cix1,Loc0,Loc1,dx,dy,NewCap,MinCap,MaxCap, 2313 CapWeight,Cost,NextProd,Preq,TotalFood,TotalProd,CheckSum,StopTurn, 2314 FutureMCost,NewProject,OldImp,mix,V8,V21,AStr,DStr,ABaseDamage,DBaseDamage: integer; 2315 CityReport,AltCityReport:TCityReport; 2316 FormerCLState: TCmdListState; 2317 EndTime: int64; 2318 Adjacent: TVicinity8Loc; 2319 Radius: TVicinity21Loc; 2320 ShowShipChange: TShowShipChange; 2321 ShowNegoData: TShowNegoData; 2322 logged,ok,HasShipChanged,AllHumansDead,OfferFullySupported:boolean; 2323 2324 begin {>>>server} 2325 if Command=sTurn then 2326 begin 2327 p2:=-1; 2328 for p1:=0 to nPl-1 do if (p1<>Player) and (1 shl p1 and GWatching<>0) then 2329 CallPlayer(cShowTurnChange,p1,p2); 2330 end; 2331 2332 assert(MapSize=lx*ly); 2333 assert(Command and (sctMask or sExecute)<>sctInternal or sExecute); // not for internal commands 2334 if (Command<0) or (Command>=$10000) then 2335 begin result:=eUnknown; exit end; 2336 2337 if (Player<0) or (Player>=nPl) 2338 or ((Command and (sctMask or sExecute)<>sctInfo) 2339 and ((Subject<0) or (Subject>=$1000))) then 2340 begin result:=eInvalid; exit end; 2341 2342 if (1 shl Player and (GAlive or GWatching)=0) and 2343 not ((Command=sTurn) or (Command=sBreak) or (Command=sResign) 2344 or (Command=sGetAIInfo) or (Command=sGetAICredits) or (Command=sGetVersion) 2345 or (Command and $FF0F=sGetChart)) then 2346 begin 2347 PutMessage(1 shl 16+1, Format('NOT Alive: %d',[Player])); 2348 result:=eNoTurn; 2349 exit 2350 end; 2351 2352 result:=eOK; 2353 2354 // check if command allowed now 2355 if (Mode=moPlaying) 2356 and not ((Command>=cClientEx) or (Command=sMessage) or (Command=sSetDebugMap) 2357 or (Command=sGetDebugMap) 2358 or (Command=sGetAIInfo) or (Command=sGetAICredits) or (Command=sGetVersion) 2359 or (Command=sGetTechCost) or (Command=sGetDefender) 2360 or (Command=sGetUnitReport) 2361 or (Command=sGetCityReport) or (Command=sGetCityTileInfo) 2362 or (Command=sGetCity) or (Command=sGetEnemyCityReport) 2363 or (Command=sGetEnemyCityAreaInfo) or (Command=sGetCityReportNew) 2364 or (Command and $FF0F=sGetChart) or (Command and $FF0F=sSetAttitude)) 2365 // commands always allowed 2366 and not ((Player=pTurn) and (Command<$1000)) 2367 // info request always allowed for pTurn 2368 and ((pDipActive<0) and (Player<>pTurn) // not his turn 2369 or (pDipActive>=0) and (Player<>pDipActive) // not active in negotiation mode 2370 or (pDipActive>=0) and (Command and sctMask<>sctEndClient)) then // no nego command 2371 begin 2372 PutMessage(1 shl 16+1, Format('No Turn: %d calls %x', 2373 [Player,Command shr 4])); 2374 result:=eNoTurn; 2375 exit 2376 end; 2377 2378 // do not use EXIT hereafter! 2379 2380 {$IFOPT O-} 2381 HandoverStack[nHandoverStack]:=Player+$1000; 2382 HandoverStack[nHandoverStack+1]:=Command; 2383 inc(nHandoverStack,2); 2384 2385 InvalidTreatyMap:=0; // new command, sIntExpandTerritory of previous command was processed 2386 {$ENDIF} 2387 2388 if (Mode=moPlaying) and (Command>=sExecute) 2389 and ((Command and sctMask<>sctEndClient) or (Command=sTurn)) 2390 and (Command and sctMask<>sctModel) and (Command<>sCancelTreaty) 2391 and (Command<>sSetCityTiles) and (Command<>sBuyCityProject) 2392 and ((Command<cClientEx) or ProcessClientData[Player]) then 2393 begin {log command} 2394 FormerCLState:=CL.State; 2395 CL.Put(Command, Player, Subject, @Data); 2396 logged:=true; 2397 end 2398 else logged:=false; 2399 2400 case Command of 2401 2402 { 2403 Info Request Commands 2404 ____________________________________________________________________ 2405 } 2406 sMessage: 2407 Brain[bix[0]].Client(cDebugMessage,Subject,Data); 2408 2409 sSetDebugMap: 2410 DebugMap[Player]:=@Data; 2411 2412 sGetDebugMap: 2413 pointer(Data):=DebugMap[Subject]; 2414 2415 {sChangeSuperView: 2416 if Difficulty[Player]=0 then 2417 begin 2418 for i:=0 to nBrain-1 do if Brain[i].Initialized then 2419 CallClient(i, cShowSuperView, Subject) 2420 end 2421 else result:=eInvalid;} 2422 2423 sRefreshDebugMap: 2424 Brain[bix[0]].Client(cRefreshDebugMap,-1,Player); 2425 2426 sGetChart..sGetChart+(nStat-1) shl 4: 2427 if (Subject>=0) and (Subject<nPl) and (bix[Subject]>=0) then 2428 begin 2429 StopTurn:=0; 2430 if (Difficulty[Player]=0) or (GTestFlags and tfUncover<>0) // supervisor 2431 or (Subject=Player) // own chart 2432 or (GWinner>0) // game end chart 2433 or (1 shl Subject and GAlive=0) then // chart of extinct nation 2434 if Subject>Player then StopTurn:=GTurn 2435 else StopTurn:=GTurn+1 2436 else if RW[Player].Treaty[Subject]>trNoContact then 2437 if Command shr 4 and $f=stMil then 2438 StopTurn:=RW[Player].EnemyReport[Subject].TurnOfMilReport+1 2439 else StopTurn:=RW[Player].EnemyReport[Subject].TurnOfCivilReport+1; 2440 move(Stat[Command shr 4 and $f, Subject]^, Data, StopTurn*SizeOf(integer)); 2441 FillChar(TChart(Data)[StopTurn],(GTurn-StopTurn)*SizeOf(integer),0); 2442 end 2443 else result:=eInvalid; 2444 2445 sGetTechCost: 2446 integer(Data):=TechCost(Player); 2447 2448 sGetAIInfo: 2449 if AIInfo[Subject]='' then pchar(Data):=nil 2450 else pchar(Data):=@AIInfo[Subject][1]; 2451 2452 sGetAICredits: 2453 if AICredits='' then pchar(Data):=nil 2454 else pchar(Data):=@AICredits[1]; 2455 2456 sGetVersion: 2457 integer(Data):=Version; 2458 2459 sGetGameChanged: 2460 if Player<>0 then result:=eInvalid 2461 else if (CL<>nil) and (CL.state.nLog=nLogOpened) and (CL.state.MoveCode=0) 2462 and not HasCityTileChanges and not HasChanges(Player) then 2463 result:=eNotChanged; 2464 2465 sGetTileInfo: 2466 if (Subject>=0) and (Subject<MapSize) then 2467 result:=GetTileInfo(Player,-2,Subject,TTileInfo(Data)) 2468 else result:=eInvalid; 2469 2470 sGetCityTileInfo: 2471 if (Subject>=0) and (Subject<MapSize) then 2472 result:=GetTileInfo(Player,-1,Subject,TTileInfo(Data)) 2473 else result:=eInvalid; 2474 2475 sGetHypoCityTileInfo: 2476 if (Subject>=0) and (Subject<MapSize) then 2477 begin 2478 if (TTileInfo(Data).ExplCity<0) or (TTileInfo(Data).ExplCity>=RW[Player].nCity) then 2479 result:=eInvalid 2480 else if ObserveLevel[Subject] shr (Player*2) and 3=0 then 2481 result:=eNoPreq 2482 else result:=GetTileInfo(Player,TTileInfo(Data).ExplCity,Subject,TTileInfo(Data)) 2483 end 2484 else result:=eInvalid; 2485 2486 sGetJobProgress: 2487 if (Subject>=0) and (Subject<MapSize) then 2488 begin 2489 if ObserveLevel[Subject] shr (Player*2) and 3=0 then 2490 result:=eNoPreq 2491 else result:=GetJobProgress(Player,Subject,TJobProgressData(Data)) 2492 end 2493 else result:=eInvalid; 2494 2495 sGetModels: 2496 if (GTestFlags and tfUncover<>0) or (Difficulty[Player]=0) then {supervisor only command} 2497 begin 2498 for p1:=0 to nPl-1 do if (p1<>Player) and (1 shl p1 and GAlive<>0) then 2499 for mix:=0 to RW[p1].nModel-1 do 2500 TellAboutModel(Player,p1,mix); 2501 end 2502 else result:=eInvalid; 2503 2504 sGetUnits: 2505 if (Subject>=0) and (Subject<MapSize) 2506 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) then 2507 integer(Data):=GetUnitStack(Player,Subject) 2508 else result:=eNoPreq; 2509 2510 sGetDefender: 2511 if (Subject>=0) and (Subject<MapSize) and (Occupant[Subject]=Player) then 2512 Strongest(Subject,integer(Data),d,i,j) 2513 else result:=eInvalid; 2514 2515 sGetBattleForecast,sGetBattleForecastEx: 2516 if (Subject>=0) and (Subject<MapSize) 2517 and (ObserveLevel[Subject] and (3 shl (Player*2))>0) then 2518 with TBattleForecast(Data) do 2519 if (1 shl pAtt and GAlive<>0) 2520 and (mixAtt>=0) and (mixAtt<RW[pAtt].nModel) 2521 and ((pAtt=Player) or (RWemix[Player,pAtt,mixAtt]>=0)) then 2522 begin 2523 result:=GetBattleForecast(Subject,TBattleForecast(Data),uix1,cix1, 2524 AStr,DStr,ABaseDamage,DBaseDamage); 2525 if Command=sGetBattleForecastEx then 2526 begin 2527 TBattleForecastEx(Data).AStr:=(AStr+200) div 400; 2528 TBattleForecastEx(Data).DStr:=(DStr+200) div 400; 2529 TBattleForecastEx(Data).ABaseDamage:=ABaseDamage; 2530 TBattleForecastEx(Data).DBaseDamage:=DBaseDamage; 2531 end; 2532 if result=eOk then 2533 result:=eInvalid // no enemy unit there! 2534 end 2535 else result:=eInvalid 2536 else result:=eInvalid; 2537 2538 sGetUnitReport: 2539 if (Subject<0) or (Subject>=RW[Player].nUn) 2540 or (RW[Player].Un[Subject].Loc<0) then 2541 result:=eInvalid 2542 else GetUnitReport(Player, Subject, TUnitReport(Data)); 2543 2544 sGetMoveAdvice: 2545 if (Subject<0) or (Subject>=RW[Player].nUn) 2546 or (RW[Player].Un[Subject].Loc<0) then 2547 result:=eInvalid 2548 else result:=GetMoveAdvice(Player,Subject, TMoveAdviceData(Data)); 2549 2550 sGetPlaneReturn: 2551 if (Subject<0) or (Subject>=RW[Player].nUn) 2552 or (RW[Player].Un[Subject].Loc<0) 2553 or (RW[Player].Model[RW[Player].Un[Subject].mix].Domain<>dAir) then 2554 result:=eInvalid 2555 else 2556 begin 2557 if CanPlaneReturn(Player,Subject, TPlaneReturnData(Data)) then result:=eOK 2558 else result:=eNoWay 2559 end; 2560 2561 sGetCity: 2562 if (Subject>=0) and (Subject<MapSize) 2563 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) 2564 and (RealMap[Subject] and fCity<>0) then 2565 with TGetCityData(Data) do 2566 begin 2567 Owner:=Player; 2568 SearchCity(Subject,Owner,cix1); 2569 c:=RW[Owner].City[cix1]; 2570 if (Owner<>Player) and (c.Project and cpImp=0) then 2571 TellAboutModel(Player,Owner,c.Project and cpIndex); 2572 end 2573 else result:=eInvalid; 2574 2575 sGetCityReport: 2576 if (Subject<0) or (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 2577 result:=eInvalid 2578 else result:=GetCityReport(Player,Subject,TCityReport(Data)); 2579 2580 sGetCityReportNew: 2581 if (Subject<0) or (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 2582 result:=eInvalid 2583 else GetCityReportNew(Player,Subject,TCityReportNew(Data)); 2584 2585 sGetCityAreaInfo: 2586 if (Subject<0) or (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 2587 result:=eInvalid 2588 else GetCityAreaInfo(Player, RW[Player].City[Subject].Loc, 2589 TCityAreaInfo(Data)); 2590 2591 sGetEnemyCityReport: 2592 if (Subject>=0) and (Subject<MapSize) 2593 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) 2594 and (RealMap[Subject] and fCity<>0) then 2595 begin 2596 p1:=Occupant[Subject]; 2597 if p1<0 then p1:=1; 2598 SearchCity(Subject,p1,cix1); 2599 TCityReport(Data).HypoTiles:=-1; 2600 TCityReport(Data).HypoTax:=-1; 2601 TCityReport(Data).HypoLux:=-1; 2602 GetCityReport(p1,cix1,TCityReport(Data)) 2603 end 2604 else result:=eInvalid; 2605 2606 sGetEnemyCityReportNew: 2607 if (Subject>=0) and (Subject<MapSize) 2608 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) 2609 and (RealMap[Subject] and fCity<>0) then 2610 begin 2611 p1:=Occupant[Subject]; 2612 if p1<0 then p1:=1; 2613 SearchCity(Subject,p1,cix1); 2614 TCityReport(Data).HypoTiles:=-1; 2615 TCityReport(Data).HypoTax:=-1; 2616 TCityReport(Data).HypoLux:=-1; 2617 GetCityReportNew(p1,cix1,TCityReportNew(Data)); 2618 end 2619 else result:=eInvalid; 2620 2621 sGetEnemyCityAreaInfo: 2622 if (Subject>=0) and (Subject<MapSize) 2623 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) 2624 and (RealMap[Subject] and fCity<>0) then 2625 begin 2626 p1:=Occupant[Subject]; 2627 if p1<0 then p1:=1; 2628 SearchCity(Subject,p1,cix1); 2629 GetCityAreaInfo(p1,Subject,TCityAreaInfo(Data)) 2630 end 2631 else result:=eInvalid; 2632 2633 sGetCityTileAdvice: 2634 if (Subject<0) or (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 2635 result:=eInvalid 2636 else GetCityTileAdvice(Player, Subject, TCityTileAdviceData(Data)); 2637 2638 { 2639 Map Editor Commands 2640 ____________________________________________________________________ 2641 } 2642 sEditTile: 2643 if Player=0 then with TEditTileData(Data) do EditTile(Loc, NewTile) 2644 else result:=eInvalid; 2645 2646 sRandomMap: 2647 if (Player=0) and MapGeneratorAvailable then 2648 begin 2649 CreateElevation; 2650 PreviewElevation:=false; 2651 CreateMap(false); 2652 FillChar(ObserveLevel,MapSize*4,0); 2653 DiscoverAll(Player,lObserveSuper); 2654 end 2655 else result:=eInvalid; 2656 2657 sMapGeneratorRequest: 2658 if not MapGeneratorAvailable then result:=eInvalid; 2659 2660 { 2661 Client Deactivation Commands 2662 ____________________________________________________________________ 2663 } 2664 sTurn, sTurn-sExecute: 2665 begin 2666 AllHumansDead:=true; 2667 for p1:=0 to nPl-1 do 2668 if (1 shl p1 and GAlive<>0) and (bix[p1]=bixTerm) then 2669 AllHumansDead:=false; 2670 if (pDipActive>=0) // still in negotiation mode 2671 or (pTurn=0) and ((GWinner>0) or (GTurn=MaxTurn) 2672 or (Difficulty[0]>0) and AllHumansDead) then // game end reached 2673 result:=eViolation 2674 else if Command>=sExecute then 2675 begin 2676 if Mode=moPlaying then 2677 begin 2678 CL.State:=FormerCLState; 2679 LogCityTileChanges; 2680 {$IFNDEF SCR} 2681 if pTurn=0 then 2682 begin LogChanges; SaveGame('~'+LogFileName,true); end 2683 {$ENDIF} 2684 end 2685 else if (Mode=moMovie) and (pTurn=0) then 2686 CallPlayer(cMovieEndTurn,0,nil^); 2687 GWatching:=GWatching and GAlive or 1; 2688 RW[pTurn].Happened:=0; 2689 uixSelectedTransport:=-1; 2690 SpyMission:=smSabotageProd; 2691 if 1 shl pTurn and GAlive<>0 then 2692 begin 2693 // calculate checksum 2694 TotalFood:=0; 2695 TotalProd:=0; 2696 for i:=0 to RW[pTurn].nCity-1 do if RW[pTurn].City[i].Loc>=0 then 2697 begin 2698 inc(TotalFood,RW[pTurn].City[i].Food); 2699 inc(TotalProd,RW[pTurn].City[i].Prod); 2700 end; 2701 CheckSum:=TotalFood and 7 + TotalProd and 7 shl 3 2702 + RW[pTurn].Money and 7 shl 6 2703 + Worked[pTurn] div 100 and 7 shl 9; 2704 end 2705 else CheckSum:=0; 2706 2707 if Mode<moPlaying then // check checksum 2708 begin 2709 if CheckSum<>Subject then 2710 LoadOK:=false 2711 end 2712 else // save checksum 2713 CL.Put(Command, Player, CheckSum, @Data); 2714 {$IFDEF TEXTLOG} 2715 CmdInfo:=''; 2716 if CheckSum and 7<>Subject and 7 then CmdInfo:=Format('***ERROR (Food %d) ',[(CheckSum and 7-Subject and 7+12) mod 8 -4])+CmdInfo; 2717 if CheckSum shr 3 and 7<>Subject shr 3 and 7 then CmdInfo:='***ERROR (Prod) '+CmdInfo; 2718 if CheckSum shr 6 and 7<>Subject shr 6 and 7 then CmdInfo:='***ERROR (Research) '+CmdInfo; 2719 if CheckSum shr 9 and 7<>Subject shr 9 and 7 then CmdInfo:='***ERROR (Work) '+CmdInfo; 2720 {$ENDIF} 2721 2722 if 1 shl pTurn and GAlive<>0 then 2723 begin 2724 AfterTurn; 2725 if Mode<moPlaying then 2726 InsertTerritoryUpdateCommands; 2727 //if bix[pTurn]=bixTerm then UpdateBorderHelper; 2728 end; 2729 2730 repeat 2731 pTurn:=(pTurn+1) mod nPl; 2732 if pTurn=0 then inc(GTurn); 2733 if (bix[pTurn]>=0) and ((1 shl pTurn) and GAlive=0) then 2734 begin // already made extinct -- continue statistics 2735 Stat[stExplore,pTurn,GTurn]:=0; 2736 Stat[stPop,pTurn,GTurn]:=0; 2737 Stat[stTerritory,pTurn,GTurn]:=0; 2738 Stat[stScience,pTurn,GTurn]:=0; 2739 Stat[stWork,pTurn,GTurn]:=0; 2740 Stat[stMil,pTurn,GTurn]:=0; 2741 end; 2742 until (pTurn=0) or ((1 shl pTurn and (GAlive or GWatching)<>0) and (GWinner=0)); 2743 if (Mode=moLoading_Fast) and ((GTurn=LoadTurn) or (GTurn=LoadTurn-1) and (pTurn>0)) then 2744 Mode:=moLoading; 2745 if Mode=moPlaying then 2746 begin 2747 CCCommand:=cTurn; CCPlayer:=pTurn; 2748 Notify(ntNextPlayer) 2749 end 2750 else 2751 begin 2752 if GTurn=0 then BeforeTurn0 2753 else BeforeTurn; 2754 if (Mode=moMovie) and (pTurn=0) then 2755 begin 2756 Inform(pTurn); 2757 CallPlayer(cMovieTurn,0,nil^); 2758 end; 2759 end; 2760 {$IFDEF TEXTLOG}CmdInfo:=CmdInfo+Format('---Turn %d P%d---', [GTurn,pTurn]);{$ENDIF} 2761 end; 2762 end; // sTurn 2763 2764 sBreak, sResign, sNextRound, sReload: 2765 if Mode=moMovie then 2766 MovieStopped:=true 2767 else 2768 begin 2769 if Command=sReload then 2770 begin 2771 ok:= (Difficulty[0]=0) and (bix[0]<>bixNoTerm) 2772 and (integer(Data)>=0) and (integer(Data)<GTurn); 2773 for p1:=1 to nPl-1 do if bix[p1]=bixTerm then ok:=false; 2774 // allow reload in AI-only games only 2775 end 2776 else ok:= Player=0; 2777 if ok then 2778 begin 2779 if (Command=sBreak) or (Command=sResign) then Notify(ntBackOn); 2780 for i:=0 to nBrain-1 do if Brain[i].Initialized then 2781 begin 2782 if i>=bixFirstAI then 2783 Notify(ntDeinitModule+i); 2784 CallClient(i, cBreakGame, nil^); 2785 end; 2786 Notify(ntEndInfo); 2787 if (Command=sBreak) or (Command=sReload) then 2788 begin 2789 LogCityTileChanges; 2790 LogChanges; 2791 SaveGame(LogFileName,false); 2792 end; 2793 DeleteFile(SavePath+'~'+LogFileName); 2794 EndGame; 2795 case Command of 2796 sBreak: Notify(ntStartGoRefresh); 2797 sResign: Notify(ntStartGo); 2798 sNextRound: StartNewGame(SavePath, LogFileName, MapFileName, lx, ly, LandMass, 2799 MaxTurn); 2800 sReload: LoadGame(SavePath,LogFileName,integer(Data),false); 2801 end 2802 end 2803 else result:=eInvalid; 2804 end; 2805 2806 sAbandonMap, sSaveMap: 2807 if Player=0 then 2808 begin 2809 if Command=sSaveMap then SaveMap(MapFileName); 2810 Notify(ntBackOn); 2811 Brain[bixTerm].Client(cBreakGame,-1,nil^); 2812 ReleaseMapEditor; 2813 if Command=sSaveMap then Notify(ntStartGoRefreshMaps) 2814 else Notify(ntStartGo) 2815 end 2816 else result:=eInvalid; 2817 2818 scContact..scContact+(nPl-1) shl 4, 2819 scContact-sExecute..scContact-sExecute+(nPl-1) shl 4: 2820 if (pDipActive>=0) or (1 shl (Command shr 4 and $f) and GAlive=0) then 2821 result:=eInvalid 2822 else if GWinner>0 then result:=eViolation // game end reached 2823 else if RW[Player].Treaty[Command shr 4 and $f]=trNoContact then 2824 result:=eNoPreq 2825 else if GTurn<GColdWarStart+ColdWarTurns then result:=eColdWar 2826 else if RW[Player].Government=gAnarchy then 2827 result:=eAnarchy 2828 else if RW[Command shr 4 and $f].Government=gAnarchy then 2829 begin 2830 result:=eAnarchy; 2831 LastEndClientCommand:=scReject; //enable cancel treaty 2832 pContacted:=Command shr 4 and $f; 2833 end 2834 else if Command>=sExecute then 2835 begin // contact request 2836 pContacted:=Command shr 4 and $f; 2837 pDipActive:=pContacted; 2838 assert(Mode=moPlaying); 2839 Inform(pDipActive); 2840 ChangeClientWhenDone(scContact,pDipActive,pTurn,4); 2841 end; 2842 2843 scReject, scReject-sExecute: 2844 if LastEndClientCommand and $FF0F=scContact then 2845 begin 2846 if Command>=sExecute then 2847 begin // contact requested and not accepted yet 2848 pDipActive:=-1; 2849 assert(Mode=moPlaying); 2850 ChangeClientWhenDone(cContinue,pTurn,nil^,0); 3301 else 3302 result := eInvalid; 3303 3304 scDipStart, scDipStart - sExecute: 3305 if LastEndClientCommand and $FF0F = scContact then 3306 begin 3307 if Command >= sExecute then 3308 begin // accept contact 3309 pContacted := pDipActive; 3310 RW[pContacted].EnemyReport[pTurn].Credibility := 3311 RW[pTurn].Credibility; 3312 pDipActive := pTurn; 3313 assert(Mode = moPlaying); 3314 IntServer(sIntHaveContact, pTurn, pContacted, nil^); 3315 ChangeClientWhenDone(scDipStart, pDipActive, nil^, 0); 2851 3316 end 2852 3317 end 2853 else result:=eInvalid; 2854 2855 scDipStart, scDipStart-sExecute: 2856 if LastEndClientCommand and $FF0F=scContact then 2857 begin 2858 if Command>=sExecute then 2859 begin // accept contact 2860 pContacted:=pDipActive; 2861 RW[pContacted].EnemyReport[pTurn].Credibility:=RW[pTurn].Credibility; 2862 pDipActive:=pTurn; 2863 assert(Mode=moPlaying); 2864 IntServer(sIntHaveContact,pTurn,pContacted,nil^); 2865 ChangeClientWhenDone(scDipStart,pDipActive,nil^,0); 2866 end 2867 end 2868 else result:=eInvalid; 2869 2870 scDipNotice, scDipAccept, scDipCancelTreaty, scDipBreak, 2871 scDipNotice-sExecute, scDipAccept-sExecute, scDipCancelTreaty-sExecute, 2872 scDipBreak-sExecute: 2873 if pDipActive>=0 then 2874 begin 2875 assert(Mode=moPlaying); 2876 if pDipActive=pTurn then p1:=pContacted 2877 else p1:=pTurn; 2878 if (Command and not sExecute=scDipBreak and not sExecute) 2879 and (LastEndClientCommand<>scDipBreak) then // ok 2880 else if (Command and not sExecute=scDipNotice and not sExecute) 2881 and ((LastEndClientCommand=scDipCancelTreaty) 2882 or (LastEndClientCommand=scDipBreak)) then // ok 2883 else if (Command and not sExecute=scDipAccept and not sExecute) 2884 and (LastEndClientCommand=scDipOffer) then with LastOffer do 3318 else 3319 result := eInvalid; 3320 3321 scDipNotice, scDipAccept, scDipCancelTreaty, scDipBreak, 3322 scDipNotice - sExecute, scDipAccept - sExecute, 3323 scDipCancelTreaty - sExecute, scDipBreak - sExecute: 3324 if pDipActive >= 0 then 3325 begin 3326 assert(Mode = moPlaying); 3327 if pDipActive = pTurn then 3328 p1 := pContacted 3329 else 3330 p1 := pTurn; 3331 if (Command and not sExecute = scDipBreak and not sExecute) and 3332 (LastEndClientCommand <> scDipBreak) then // ok 3333 else if (Command and not sExecute = scDipNotice and not sExecute) and 3334 ((LastEndClientCommand = scDipCancelTreaty) or 3335 (LastEndClientCommand = scDipBreak)) then // ok 3336 else if (Command and not sExecute = scDipAccept and not sExecute) and 3337 (LastEndClientCommand = scDipOffer) then 3338 with LastOffer do 3339 begin 3340 // check if offer can be accepted 3341 if nDeliver + nCost = 0 then 3342 result := eOfferNotAcceptable; 3343 for i := 0 to nDeliver + nCost - 1 do 3344 if Price[i] = opChoose then 3345 result := eOfferNotAcceptable; 3346 for i := 0 to nCost - 1 do 3347 if not PayPrice(pDipActive, p1, Price[nDeliver + i], false) then 3348 result := eOfferNotAcceptable; 3349 if (Command >= sExecute) and (result >= rExecuted) then 3350 begin 3351 IntServer(sIntPayPrices + nDeliver + nCost, p1, pDipActive, 3352 LastOffer); 3353 // CheckContact; 3354 3355 // tell other players about ship part trades 3356 HasShipChanged := false; 3357 FillChar(ShowShipChange, SizeOf(ShowShipChange), 0); 3358 for i := 0 to nDeliver + nCost - 1 do 3359 if Price[i] and opMask = opShipParts then 3360 begin 3361 HasShipChanged := true; 3362 if i >= nDeliver then 3363 begin // p1 has demanded from pDipActive 3364 ShowShipChange.Ship1Change[Price[i] shr 16 and 3] := 3365 +integer(Price[i] and $FFFF); 3366 ShowShipChange.Ship2Change[Price[i] shr 16 and 3] := 3367 -integer(Price[i] and $FFFF); 3368 end 3369 else 3370 begin // p1 has delivered to pDipActive 3371 ShowShipChange.Ship1Change[Price[i] shr 16 and 3] := 3372 -integer(Price[i] and $FFFF); 3373 ShowShipChange.Ship2Change[Price[i] shr 16 and 3] := 3374 +integer(Price[i] and $FFFF); 3375 end 3376 end; 3377 if HasShipChanged then 3378 begin 3379 ShowShipChange.Reason := scrTrade; 3380 ShowShipChange.Ship1Owner := p1; 3381 ShowShipChange.Ship2Owner := pDipActive; 3382 for p2 := 0 to nPl - 1 do 3383 if (p2 <> p1) and (p2 <> pDipActive) and 3384 (1 shl p2 and (GAlive or GWatching) <> 0) then 3385 begin 3386 move(GShip, RW[p2].Ship, SizeOf(GShip)); 3387 if 1 shl p2 and GWatching <> 0 then 3388 CallPlayer(cShowShipChange, p2, ShowShipChange); 3389 end 3390 end 3391 end; 3392 end 3393 else if (Command and not sExecute = scDipCancelTreaty and not sExecute) 3394 and (RW[pDipActive].Treaty[p1] >= trPeace) then 2885 3395 begin 2886 // check if offer can be accepted 2887 if nDeliver+nCost=0 then result:=eOfferNotAcceptable; 2888 for i:=0 to nDeliver+nCost-1 do 2889 if Price[i]=opChoose then result:=eOfferNotAcceptable; 2890 for i:=0 to nCost-1 do 2891 if not PayPrice(pDipActive,p1,Price[nDeliver+i],false) then 2892 result:=eOfferNotAcceptable; 2893 if (Command>=sExecute) and (result>=rExecuted) then 3396 if (ServerVersion[pDipActive] >= $010100) and 3397 (GTurn < RW[pDipActive].LastCancelTreaty[p1] + CancelTreatyTurns) 3398 then 3399 result := eCancelTreatyRush 3400 else if Command >= sExecute then 2894 3401 begin 2895 IntServer(sIntPayPrices+nDeliver+nCost,p1,pDipActive,LastOffer); 2896 // CheckContact; 2897 2898 // tell other players about ship part trades 2899 HasShipChanged:=false; 2900 fillchar(ShowShipChange,sizeof(ShowShipChange),0); 2901 for i:=0 to nDeliver+nCost-1 do 2902 if Price[i] and opMask=opShipParts then 3402 IntServer(sIntCancelTreaty, pDipActive, p1, nil^); 3403 for p2 := 0 to nPl - 1 do 3404 if (p2 <> p1) and (1 shl p2 and PeaceEnded <> 0) then 2903 3405 begin 2904 HasShipChanged:=true; 2905 if i>=nDeliver then 2906 begin // p1 has demanded from pDipActive 2907 ShowShipChange.Ship1Change[Price[i] shr 16 and 3]:=+integer(Price[i] and $FFFF); 2908 ShowShipChange.Ship2Change[Price[i] shr 16 and 3]:=-integer(Price[i] and $FFFF); 2909 end 2910 else 2911 begin // p1 has delivered to pDipActive 2912 ShowShipChange.Ship1Change[Price[i] shr 16 and 3]:=-integer(Price[i] and $FFFF); 2913 ShowShipChange.Ship2Change[Price[i] shr 16 and 3]:=+integer(Price[i] and $FFFF); 2914 end 3406 i := p1 shl 4 + pDipActive; 3407 CallPlayer(cShowSupportAllianceAgainst, p2, i); 2915 3408 end; 2916 if HasShipChanged then 2917 begin 2918 ShowShipChange.Reason:=scrTrade; 2919 ShowShipChange.Ship1Owner:=p1; 2920 ShowShipChange.Ship2Owner:=pDipActive; 2921 for p2:=0 to nPl-1 do 2922 if (p2<>p1) and (p2<>pDipActive) and (1 shl p2 and (GAlive or GWatching)<>0) then 2923 begin 2924 move(GShip,RW[p2].Ship,SizeOf(GShip)); 2925 if 1 shl p2 and GWatching<>0 then 2926 CallPlayer(cShowShipChange,p2,ShowShipChange); 2927 end 2928 end 2929 end; 2930 end 2931 else if (Command and not sExecute=scDipCancelTreaty and not sExecute) 2932 and (RW[pDipActive].Treaty[p1]>=trPeace) then 2933 begin 2934 if (ServerVersion[pDipActive]>=$010100) 2935 and (GTurn<RW[pDipActive].LastCancelTreaty[p1]+CancelTreatyTurns) then 2936 result:=eCancelTreatyRush 2937 else if Command>=sExecute then 2938 begin 2939 IntServer(sIntCancelTreaty,pDipActive,p1,nil^); 2940 for p2:=0 to nPl-1 do 2941 if (p2<>p1) and (1 shl p2 and PeaceEnded<>0) then 3409 for p2 := 0 to nPl - 1 do 3410 if (p2 <> p1) and (1 shl p2 and PeaceEnded <> 0) then 2942 3411 begin 2943 i:=p1 shl 4+pDipActive; 2944 CallPlayer(cShowSupportAllianceAgainst,p2,i); 2945 end; 2946 for p2:=0 to nPl-1 do 2947 if (p2<>p1) and (1 shl p2 and PeaceEnded<>0) then 2948 begin 2949 i:=p2; 2950 CallPlayer(cShowCancelTreatyByAlliance,pDipActive,i); 3412 i := p2; 3413 CallPlayer(cShowCancelTreatyByAlliance, pDipActive, i); 2951 3414 end; 2952 3415 end 2953 3416 end 2954 else result:=eInvalid; 2955 if (Command>=sExecute) and (result>=rExecuted) then 2956 if LastEndClientCommand=scDipBreak then 3417 else 3418 result := eInvalid; 3419 if (Command >= sExecute) and (result >= rExecuted) then 3420 if LastEndClientCommand = scDipBreak then 2957 3421 begin // break negotiation 2958 pDipActive:=-1;2959 CallPlayer(cShowEndContact,pContacted,nil^);2960 ChangeClientWhenDone(cContinue,pTurn,nil^,0);3422 pDipActive := -1; 3423 CallPlayer(cShowEndContact, pContacted, nil^); 3424 ChangeClientWhenDone(cContinue, pTurn, nil^, 0); 2961 3425 end 2962 else3426 else 2963 3427 begin 2964 if (GTestFlags and tfUncover<>0) or (Difficulty[0]=0) then2965 with ShowNegoData do3428 if (GTestFlags and tfUncover <> 0) or (Difficulty[0] = 0) then 3429 with ShowNegoData do 2966 3430 begin // display negotiation in log window 2967 pSender:=pDipActive;2968 pTarget:=p1;2969 Action:=Command;2970 Brain[bix[0]].Client(cShowNego,1 shl 16+3,ShowNegoData);3431 pSender := pDipActive; 3432 pTarget := p1; 3433 Action := Command; 3434 Brain[bix[0]].Client(cShowNego, 1 shl 16 + 3, ShowNegoData); 2971 3435 end; 2972 pDipActive:=p1;2973 ChangeClientWhenDone(Command,pDipActive,nil^,0);3436 pDipActive := p1; 3437 ChangeClientWhenDone(Command, pDipActive, nil^, 0); 2974 3438 end 2975 3439 end 2976 else result:=eInvalid; 2977 2978 scDipOffer, scDipOffer-sExecute: 2979 if (pDipActive>=0) and (LastEndClientCommand<>scDipCancelTreaty) 2980 and (LastEndClientCommand<>scDipBreak) then 2981 if (LastEndClientCommand=scDipOffer) and (LastOffer.nDeliver+LastOffer.nCost 2982 +TOffer(Data).nDeliver+TOffer(Data).nCost=0) then 3440 else 3441 result := eInvalid; 3442 3443 scDipOffer, scDipOffer - sExecute: 3444 if (pDipActive >= 0) and (LastEndClientCommand <> scDipCancelTreaty) and 3445 (LastEndClientCommand <> scDipBreak) then 3446 if (LastEndClientCommand = scDipOffer) and 3447 (LastOffer.nDeliver + LastOffer.nCost + TOffer(Data).nDeliver + 3448 TOffer(Data).nCost = 0) then 2983 3449 begin 2984 if Command>=sExecute then3450 if Command >= sExecute then 2985 3451 begin // agreed discussion end 2986 pDipActive:=-1;2987 CallPlayer(cShowEndContact,pContacted,nil^);2988 assert(Mode=moPlaying);2989 ChangeClientWhenDone(cContinue,pTurn,nil^,0);3452 pDipActive := -1; 3453 CallPlayer(cShowEndContact, pContacted, nil^); 3454 assert(Mode = moPlaying); 3455 ChangeClientWhenDone(cContinue, pTurn, nil^, 0); 2990 3456 end 2991 3457 end 2992 else3458 else 2993 3459 begin 2994 // check if offer can be made 2995 if pDipActive=pTurn then p1:=pContacted 2996 else p1:=pTurn; 2997 if RW[pDipActive].Treaty[p1]<trPeace then 3460 // check if offer can be made 3461 if pDipActive = pTurn then 3462 p1 := pContacted 3463 else 3464 p1 := pTurn; 3465 if RW[pDipActive].Treaty[p1] < trPeace then 2998 3466 begin // no tribute allowed! 2999 for i:=0 to TOffer(Data).nDeliver+TOffer(Data).nCost-1 do 3000 if (TOffer(Data).Price[i] and opMask=opTribute) then result:=eInvalidOffer; 3001 for i:=0 to TOffer(Data).nDeliver+TOffer(Data).nCost-1 do 3002 if (TOffer(Data).Price[i]=opTreaty+trPeace) then result:=eOK; 3467 for i := 0 to TOffer(Data).nDeliver + TOffer(Data).nCost - 1 do 3468 if (TOffer(Data).Price[i] and opMask = opTribute) then 3469 result := eInvalidOffer; 3470 for i := 0 to TOffer(Data).nDeliver + TOffer(Data).nCost - 1 do 3471 if (TOffer(Data).Price[i] = opTreaty + trPeace) then 3472 result := eOK; 3003 3473 end; 3004 for i:=0 to TOffer(Data).nDeliver-1 do 3005 if (TOffer(Data).Price[i]<>opChoose) 3006 and not PayPrice(pDipActive,p1,TOffer(Data).Price[i],false) then 3007 result:=eInvalidOffer; 3008 if CountPrice(TOffer(Data),opTreaty)>1 then 3009 result:=eInvalidOffer; 3010 for i:=0 to nShipPart-1 do 3011 if CountPrice(TOffer(Data),opShipParts+i shl 16)>1 then 3012 result:=eInvalidOffer; 3013 if CountPrice(TOffer(Data),opMoney)>1 then 3014 result:=eInvalidOffer; 3015 if CountPrice(TOffer(Data),opTribute)>1 then 3016 result:=eInvalidOffer; 3017 case CountPrice(TOffer(Data),opChoose) of 3018 0:; 3019 1: 3020 if (TOffer(Data).nCost=0) or (TOffer(Data).nDeliver=0) then 3021 result:=eInvalidOffer; 3022 else result:=eInvalidOffer; 3474 for i := 0 to TOffer(Data).nDeliver - 1 do 3475 if (TOffer(Data).Price[i] <> opChoose) and 3476 not PayPrice(pDipActive, p1, TOffer(Data).Price[i], false) then 3477 result := eInvalidOffer; 3478 if CountPrice(TOffer(Data), opTreaty) > 1 then 3479 result := eInvalidOffer; 3480 for i := 0 to nShipPart - 1 do 3481 if CountPrice(TOffer(Data), opShipParts + i shl 16) > 1 then 3482 result := eInvalidOffer; 3483 if CountPrice(TOffer(Data), opMoney) > 1 then 3484 result := eInvalidOffer; 3485 if CountPrice(TOffer(Data), opTribute) > 1 then 3486 result := eInvalidOffer; 3487 case CountPrice(TOffer(Data), opChoose) of 3488 0: 3489 ; 3490 1: 3491 if (TOffer(Data).nCost = 0) or (TOffer(Data).nDeliver = 0) then 3492 result := eInvalidOffer; 3493 else 3494 result := eInvalidOffer; 3023 3495 end; 3024 3496 3025 // !!! check here if cost can be demanded3026 3027 if (Command>=sExecute) and (result>=rExecuted) then3497 // !!! check here if cost can be demanded 3498 3499 if (Command >= sExecute) and (result >= rExecuted) then 3028 3500 begin 3029 OfferFullySupported:= (TOffer(Data).nDeliver<=2)3030 and (TOffer(Data).nCost<=2); // >2 no more allowed3031 for i:=0 to TOffer(Data).nDeliver+TOffer(Data).nCost-1 do3501 OfferFullySupported := (TOffer(Data).nDeliver <= 2) and 3502 (TOffer(Data).nCost <= 2); // >2 no more allowed 3503 for i := 0 to TOffer(Data).nDeliver + TOffer(Data).nCost - 1 do 3032 3504 begin 3033 if TOffer(Data).Price[i] and opMask=opTribute then 3034 OfferFullySupported:=false; // tribute no more part of the game 3035 if (TOffer(Data).Price[i] and opMask=opTreaty) 3036 and (TOffer(Data).Price[i]-opTreaty<=RW[pDipActive].Treaty[p1]) then 3037 OfferFullySupported:=false; // agreed treaty end no more part of the game 3038 if TOffer(Data).Price[i]=opTreaty+trCeaseFire then 3039 OfferFullySupported:=false; // ceasefire no more part of the game 3505 if TOffer(Data).Price[i] and opMask = opTribute then 3506 OfferFullySupported := false; 3507 // tribute no more part of the game 3508 if (TOffer(Data).Price[i] and opMask = opTreaty) and 3509 (TOffer(Data).Price[i] - opTreaty <= RW[pDipActive].Treaty[p1]) 3510 then 3511 OfferFullySupported := false; 3512 // agreed treaty end no more part of the game 3513 if TOffer(Data).Price[i] = opTreaty + trCeaseFire then 3514 OfferFullySupported := false; 3515 // ceasefire no more part of the game 3040 3516 end; 3041 if not OfferFullySupported then3517 if not OfferFullySupported then 3042 3518 begin 3043 // some elements have been removed from the game - 3044 // automatically respond will null-offer 3045 LastOffer.nDeliver:=0; 3046 LastOffer.nCost:=0; 3047 ChangeClientWhenDone(scDipOffer,pDipActive,LastOffer,SizeOf(LastOffer)); 3519 // some elements have been removed from the game - 3520 // automatically respond will null-offer 3521 LastOffer.nDeliver := 0; 3522 LastOffer.nCost := 0; 3523 ChangeClientWhenDone(scDipOffer, pDipActive, LastOffer, 3524 SizeOf(LastOffer)); 3048 3525 end 3049 else3526 else 3050 3527 begin 3051 if (GTestFlags and tfUncover<>0) or (Difficulty[0]=0) then3052 with ShowNegoData do3528 if (GTestFlags and tfUncover <> 0) or (Difficulty[0] = 0) then 3529 with ShowNegoData do 3053 3530 begin // display negotiation in log window 3054 pSender:=pDipActive;3055 pTarget:=p1;3056 Action:=Command;3057 Offer:=TOffer(Data);3058 Brain[bix[0]].Client(cShowNego,1 shl 16+3,ShowNegoData);3531 pSender := pDipActive; 3532 pTarget := p1; 3533 Action := Command; 3534 Offer := TOffer(Data); 3535 Brain[bix[0]].Client(cShowNego, 1 shl 16 + 3, ShowNegoData); 3059 3536 end; 3060 LastOffer:=TOffer(Data); 3061 // show offered things to receiver 3062 for i:=0 to LastOffer.nDeliver-1 do 3063 ShowPrice(pDipActive,p1,LastOffer.Price[i]); 3064 pDipActive:=p1; 3065 assert(Mode=moPlaying); 3066 ChangeClientWhenDone(scDipOffer,pDipActive,LastOffer,SizeOf(LastOffer)); 3537 LastOffer := TOffer(Data); 3538 // show offered things to receiver 3539 for i := 0 to LastOffer.nDeliver - 1 do 3540 ShowPrice(pDipActive, p1, LastOffer.Price[i]); 3541 pDipActive := p1; 3542 assert(Mode = moPlaying); 3543 ChangeClientWhenDone(scDipOffer, pDipActive, LastOffer, 3544 SizeOf(LastOffer)); 3067 3545 end 3068 3546 end 3069 3547 end 3070 else result:=eInvalid; 3071 3072 { 3073 General Commands 3074 ____________________________________________________________________ 3075 } 3076 sClearTestFlag: 3077 if Player=0 then 3078 begin 3079 {$IFDEF TEXTLOG}CmdInfo:=Format('ClearTestFlag %x', [Subject]);{$ENDIF} 3080 ClearTestFlags(Subject); 3548 else 3549 result := eInvalid; 3550 3551 { 3552 General Commands 3553 ____________________________________________________________________ 3554 } 3555 sClearTestFlag: 3556 if Player = 0 then 3557 begin 3558 {$IFDEF TEXTLOG}CmdInfo := Format('ClearTestFlag %x', [Subject]); {$ENDIF} 3559 ClearTestFlags(Subject); 3081 3560 end 3082 else result:=eInvalid; 3083 3084 sSetTestFlag: 3085 if Player=0 then 3086 begin 3087 {$IFDEF TEXTLOG}CmdInfo:=Format('SetTestFlag %x', [Subject]);{$ENDIF} 3088 SetTestFlags(Player,Subject); 3089 // CheckContact; 3561 else 3562 result := eInvalid; 3563 3564 sSetTestFlag: 3565 if Player = 0 then 3566 begin 3567 {$IFDEF TEXTLOG}CmdInfo := Format('SetTestFlag %x', [Subject]); {$ENDIF} 3568 SetTestFlags(Player, Subject); 3569 // CheckContact; 3090 3570 end 3091 else result:=eInvalid; 3092 3093 sSetGovernment, sSetGovernment-sExecute: 3094 begin 3095 {$IFDEF TEXTLOG}CmdInfo:=Format('SetGovernment P%d: %d', [Player,Subject]);{$ENDIF} 3096 if RW[Player].Happened and phChangeGov=0 then result:=eViolation 3097 else if RW[Player].Government=Subject then result:=eNotChanged 3098 else if (Subject>=nGov) then result:=eInvalid 3099 else if (Subject>=gMonarchy) 3100 and (RW[Player].Tech[GovPreq[Subject]]<tsApplicable) then 3101 result:=eNoPreq 3102 else if Command>=sExecute then 3103 begin 3104 RW[Player].Government:=Subject; 3105 for p1:=0 to nPl-1 do if (p1<>Player) and ((GAlive or GWatching) and (1 shl p1)<>0) then 3106 RW[p1].EnemyReport[Player].Government:=Subject; 3107 end 3108 end; 3109 3110 sSetRates, sSetRates-sExecute: 3111 begin 3112 {$IFDEF TEXTLOG}CmdInfo:=Format('SetRates P%d: %d/%d', [Player,Subject and $f *10,Subject shr 4 *10]);{$ENDIF} 3113 if Subject and $f+Subject shr 4>10 then result:=eInvalid 3114 else if (RW[Player].TaxRate=Subject and $f *10) 3115 and (RW[Player].LuxRate=Subject shr 4 *10) then 3116 result:=eNotChanged 3117 else if Command>=sExecute then 3118 begin 3119 RW[Player].TaxRate:=Subject and $f *10; 3120 RW[Player].LuxRate:=Subject shr 4 *10; 3121 end 3122 end; 3123 3124 sRevolution: 3125 begin 3126 {$IFDEF TEXTLOG}CmdInfo:=Format('Revolution P%d', [Player]);{$ENDIF} 3127 if RW[Player].Government=gAnarchy then result:=eInvalid 3128 else 3129 begin 3130 RW[Player].Government:=gAnarchy; 3131 for p1:=0 to nPl-1 do if (p1<>Player) and ((GAlive or GWatching) and (1 shl p1)<>0) then 3132 RW[p1].EnemyReport[Player].Government:=gAnarchy; 3133 RW[Player].AnarchyStart:=GTurn; 3134 end; 3135 end; 3136 3137 sSetResearch, sSetResearch-sExecute: with RW[Player] do 3138 begin 3139 {$IFDEF TEXTLOG}CmdInfo:=Format('SetResearch P%d: %d', [Player,Subject]);{$ENDIF} 3140 if (Happened and phTech<>0) 3141 and ((Subject<nAdv) or (Subject=adMilitary)) then 3142 begin 3143 if (Mode=moPlaying) and (Subject=adMilitary) 3144 and (DevModelTurn[Player]<>GTurn) then 3145 result:=eNoModel 3146 else if Subject<>adMilitary then 3571 else 3572 result := eInvalid; 3573 3574 sSetGovernment, sSetGovernment - sExecute: 3575 begin 3576 {$IFDEF TEXTLOG}CmdInfo := Format('SetGovernment P%d: %d', [Player, Subject]); {$ENDIF} 3577 if RW[Player].Happened and phChangeGov = 0 then 3578 result := eViolation 3579 else if RW[Player].Government = Subject then 3580 result := eNotChanged 3581 else if (Subject >= nGov) then 3582 result := eInvalid 3583 else if (Subject >= gMonarchy) and 3584 (RW[Player].Tech[GovPreq[Subject]] < tsApplicable) then 3585 result := eNoPreq 3586 else if Command >= sExecute then 3147 3587 begin 3148 if Subject=futComputingTechnology then 3588 RW[Player].Government := Subject; 3589 for p1 := 0 to nPl - 1 do 3590 if (p1 <> Player) and ((GAlive or GWatching) and (1 shl p1) <> 0) 3591 then 3592 RW[p1].EnemyReport[Player].Government := Subject; 3593 end 3594 end; 3595 3596 sSetRates, sSetRates - sExecute: 3597 begin 3598 {$IFDEF TEXTLOG}CmdInfo := Format('SetRates P%d: %d/%d', [Player, Subject and $F * 10, Subject shr 4 * 10]); {$ENDIF} 3599 if Subject and $F + Subject shr 4 > 10 then 3600 result := eInvalid 3601 else if (RW[Player].TaxRate = Subject and $F * 10) and 3602 (RW[Player].LuxRate = Subject shr 4 * 10) then 3603 result := eNotChanged 3604 else if Command >= sExecute then 3605 begin 3606 RW[Player].TaxRate := Subject and $F * 10; 3607 RW[Player].LuxRate := Subject shr 4 * 10; 3608 end 3609 end; 3610 3611 sRevolution: 3612 begin 3613 {$IFDEF TEXTLOG}CmdInfo := Format('Revolution P%d', [Player]); {$ENDIF} 3614 if RW[Player].Government = gAnarchy then 3615 result := eInvalid 3616 else 3617 begin 3618 RW[Player].Government := gAnarchy; 3619 for p1 := 0 to nPl - 1 do 3620 if (p1 <> Player) and ((GAlive or GWatching) and (1 shl p1) <> 0) 3621 then 3622 RW[p1].EnemyReport[Player].Government := gAnarchy; 3623 RW[Player].AnarchyStart := GTurn; 3624 end; 3625 end; 3626 3627 sSetResearch, sSetResearch - sExecute: 3628 with RW[Player] do 3629 begin 3630 {$IFDEF TEXTLOG}CmdInfo := Format('SetResearch P%d: %d', [Player, Subject]); 3631 {$ENDIF} 3632 if (Happened and phTech <> 0) and 3633 ((Subject < nAdv) or (Subject = adMilitary)) then 3634 begin 3635 if (Mode = moPlaying) and (Subject = adMilitary) and 3636 (DevModelTurn[Player] <> GTurn) then 3637 result := eNoModel 3638 else if Subject <> adMilitary then 3149 3639 begin 3150 if Tech[Subject]>=MaxFutureTech_Computing then result:=eInvalid 3640 if Subject = futComputingTechnology then 3641 begin 3642 if Tech[Subject] >= MaxFutureTech_Computing then 3643 result := eInvalid 3644 end 3645 else if Subject in FutureTech then 3646 begin 3647 if Tech[Subject] >= MaxFutureTech then 3648 result := eInvalid 3649 end 3650 else if Tech[Subject] >= tsApplicable then 3651 result := eInvalid; // already discovered 3652 if Tech[Subject] <> tsSeen then // look if preqs met 3653 if AdvPreq[Subject, 2] <> preNone then 3654 begin // 2 of 3 required 3655 i := 0; 3656 for j := 0 to 2 do 3657 if Tech[AdvPreq[Subject, j]] >= tsApplicable then 3658 inc(i); 3659 if i < 2 then 3660 result := eNoPreq 3661 end 3662 else if (AdvPreq[Subject, 0] <> preNone) and 3663 (Tech[AdvPreq[Subject, 0]] < tsApplicable) or 3664 (AdvPreq[Subject, 1] <> preNone) and 3665 (Tech[AdvPreq[Subject, 1]] < tsApplicable) then 3666 result := eNoPreq 3667 end; 3668 if (result = eOK) and (Command >= sExecute) then 3669 begin 3670 if (Mode = moPlaying) and (Subject = adMilitary) then 3671 IntServer(sIntSetDevModel, Player, 0, DevModel.Kind); 3672 // save DevModel, because sctModel commands are not logged 3673 ResearchTech := Subject; 3151 3674 end 3152 else if Subject in FutureTech then 3675 end 3676 else 3677 result := eViolation; 3678 end; 3679 3680 sStealTech, sStealTech - sExecute: 3681 begin 3682 {$IFDEF TEXTLOG}CmdInfo := Format('StealTech P%d: %d', [Player, Subject]); 3683 {$ENDIF} 3684 if RW[Player].Happened and phStealTech = 0 then 3685 result := eInvalid 3686 else if (Subject >= nAdv) or (Subject in FutureTech) or 3687 (RW[Player].Tech[Subject] >= tsSeen) or 3688 (RW[GStealFrom].Tech[Subject] < tsApplicable) then 3689 result := eInvalid 3690 else if Command >= sExecute then 3691 begin 3692 SeeTech(Player, Subject); 3693 dec(RW[Player].Happened, phStealTech); 3694 end 3695 end; 3696 3697 sSetAttitude .. sSetAttitude + (nPl - 1) shl 4, 3698 sSetAttitude - sExecute .. sSetAttitude - sExecute + (nPl - 1) shl 4: 3699 begin 3700 p1 := Command shr 4 and $F; 3701 {$IFDEF TEXTLOG}CmdInfo := Format('SetAttitude P%d to P%d: %d', [Player, p1, Subject]); {$ENDIF} 3702 if (Subject >= nAttitude) or (p1 >= nPl) or 3703 (RW[Player].EnemyReport[p1] = nil) then 3704 result := eInvalid 3705 else if RW[Player].Treaty[p1] = trNoContact then 3706 result := eNoPreq 3707 else if RW[Player].Attitude[p1] = Subject then 3708 result := eNotChanged 3709 else if Command >= sExecute then 3710 begin 3711 RW[Player].Attitude[p1] := Subject; 3712 RW[p1].EnemyReport[Player].Attitude := Subject; 3713 end 3714 end; 3715 3716 sCancelTreaty, sCancelTreaty - sExecute: 3717 if (LastEndClientCommand <> scReject) or 3718 (RW[Player].Treaty[pContacted] < trPeace) then 3719 result := eInvalid 3720 else if (ServerVersion[Player] >= $010100) and 3721 (GTurn < RW[Player].LastCancelTreaty[pContacted] + CancelTreatyTurns) 3722 then 3723 result := eCancelTreatyRush 3724 else if Command >= sExecute then 3725 begin 3726 CallPlayer(cShowCancelTreaty, pContacted, Player); 3727 IntServer(sIntCancelTreaty, Player, pContacted, nil^); 3728 for p2 := 0 to nPl - 1 do 3729 if (p2 <> pContacted) and (1 shl p2 and PeaceEnded <> 0) then 3153 3730 begin 3154 if Tech[Subject]>=MaxFutureTech then result:=eInvalid 3731 i := pContacted shl 4 + Player; 3732 CallPlayer(cShowSupportAllianceAgainst, p2, i); 3733 end; 3734 for p2 := 0 to nPl - 1 do 3735 if (p2 <> pContacted) and (1 shl p2 and PeaceEnded <> 0) then 3736 begin 3737 i := p2; 3738 CallPlayer(cShowCancelTreatyByAlliance, Player, i); 3739 end; 3740 LastEndClientCommand := sTurn; 3741 end; 3742 3743 { 3744 Model Related Commands 3745 ____________________________________________________________________ 3746 } 3747 sCreateDevModel, sCreateDevModel - sExecute: 3748 begin 3749 {$IFDEF TEXTLOG}CmdInfo := Format('CreateDevModel P%d', [Player]); {$ENDIF} 3750 if Subject >= 4 then 3751 result := eInvalid 3752 else if (upgrade[Subject, 0].Preq <> preNone) and 3753 (RW[Player].Tech[upgrade[Subject, 0].Preq] < tsApplicable) then 3754 result := eNoPreq 3755 else if Command >= sExecute then 3756 begin 3757 with RW[Player].DevModel do 3758 begin 3759 Domain := Subject; 3760 MStrength := 0; 3761 MTrans := 0; 3762 MCost := 0; 3763 Upgrades := 0; 3764 FutureMCost := 0; 3765 for i := 0 to nUpgrade - 1 do 3766 with upgrade[Domain, i] do 3767 if (Preq = preNone) or (Preq >= 0) and 3768 ((RW[Player].Tech[Preq] >= tsApplicable) or 3769 (Preq in FutureTech) and (RW[Player].Tech[Preq] >= 0)) then 3770 begin 3771 if Preq in FutureTech then 3772 begin 3773 j := RW[Player].Tech[Preq]; 3774 inc(FutureMCost, j * Cost); 3775 end 3776 else 3777 begin 3778 j := 1; 3779 if Cost > MCost then 3780 MCost := Cost; 3781 end; 3782 inc(Upgrades, 1 shl i); 3783 inc(MStrength, j * Strength); 3784 inc(MTrans, j * Trans); 3785 end; 3786 inc(MCost, FutureMCost); 3787 FillChar(Cap, SizeOf(Cap), 0); 3788 Cap[mcOffense] := 2; 3789 Cap[mcDefense] := 1; 3790 for i := 0 to nFeature - 1 do 3791 with Feature[i] do 3792 if (1 shl Domain and Domains <> 0) and 3793 ((Preq = preNone) or (Preq = preSun) and 3794 (GWonder[woSun].EffectiveOwner = Player) or (Preq >= 0) and 3795 (RW[Player].Tech[Preq] >= tsApplicable)) and (i in AutoFeature) 3796 then 3797 Cap[i] := 1; 3798 MaxWeight := 5; 3799 if (WeightPreq7[Domain] <> preNA) and 3800 (RW[Player].Tech[WeightPreq7[Domain]] >= tsApplicable) then 3801 MaxWeight := 7; 3802 if (WeightPreq10[Domain] <> preNA) and 3803 (RW[Player].Tech[WeightPreq10[Domain]] >= tsApplicable) then 3804 if Domain = dSea then 3805 MaxWeight := 9 3806 else 3807 MaxWeight := 10; 3808 end; 3809 CalculateModel(RW[Player].DevModel); 3810 DevModelTurn[Player] := GTurn; 3811 end 3812 end; 3813 3814 sSetDevModelCap .. sSetDevModelCap + $3F0, 3815 sSetDevModelCap - sExecute .. sSetDevModelCap - sExecute + $3F0: 3816 begin 3817 {$IFDEF TEXTLOG}CmdInfo := Format('SetDevModelCap P%d', [Player]); {$ENDIF} 3818 if Subject >= nFeature then 3819 result := eInvalid 3820 else if DevModelTurn[Player] = GTurn then 3821 begin 3822 NewCap := Command shr 4 and $3F; { new value } 3823 with RW[Player].DevModel do 3824 if 1 shl Domain and Feature[Subject].Domains = 0 then 3825 result := eDomainMismatch 3826 else if not((Feature[Subject].Preq = preNone) or 3827 (Feature[Subject].Preq = preSun) and 3828 (GWonder[woSun].EffectiveOwner = Player) or 3829 (Feature[Subject].Preq >= 0) and 3830 (RW[Player].Tech[Feature[Subject].Preq] >= tsApplicable)) then 3831 result := eNoPreq 3832 else 3833 begin 3834 if (Subject in AutoFeature) or (Subject = mcDefense) then 3835 MinCap := 1 3836 else 3837 MinCap := 0; { MinCap - minimum use of feature } 3838 if Subject >= mcFirstNonCap then 3839 MaxCap := 1 3840 else if Subject = mcDefense then 3841 begin 3842 if Domain = dGround then 3843 MaxCap := 2 3844 else 3845 MaxCap := 3; 3846 if RW[Player].Tech[adSteel] >= tsApplicable then 3847 inc(MaxCap) 3848 end 3849 else 3850 MaxCap := 8; { MaxCap - maximum use of this feature } 3851 if (Domain = dGround) and (Subject = mcDefense) then 3852 CapWeight := 2 3853 else 3854 CapWeight := Feature[Subject].Weight; 3855 if (NewCap < MinCap) or (NewCap > MaxCap) or 3856 (Weight + (NewCap - Cap[Subject]) * CapWeight > MaxWeight) then 3857 result := eViolation 3858 else if Command >= sExecute then 3859 begin 3860 Cap[Subject] := NewCap; 3861 3862 // mutual feature exclusion 3863 case Subject of 3864 mcSub: 3865 begin 3866 if ServerVersion[Player] >= $010103 then 3867 Cap[mcSeaTrans] := 0; 3868 Cap[mcArtillery] := 0; 3869 Cap[mcCarrier] := 0; 3870 if Cap[mcDefense] > 2 then 3871 Cap[mcDefense] := 2 3872 end; 3873 mcSeaTrans: 3874 begin 3875 if ServerVersion[Player] >= $010103 then 3876 Cap[mcSub] := 0; 3877 end; 3878 mcCarrier: 3879 Cap[mcSub] := 0; 3880 mcArtillery: 3881 Cap[mcSub] := 0; 3882 mcAlpine: 3883 begin 3884 Cap[mcOver] := 0; 3885 Cap[mcMob] := 0; 3886 end; 3887 mcOver: 3888 Cap[mcAlpine] := 0; 3889 mcMob: 3890 begin 3891 Cap[mcAlpine] := 0; 3892 end; 3893 end; 3894 3895 CalculateModel(RW[Player].DevModel); 3896 end 3897 end; 3898 end 3899 else 3900 result := eNoModel; 3901 end; 3902 3903 { 3904 Unit Related Commands 3905 ____________________________________________________________________ 3906 } 3907 sRemoveUnit, sRemoveUnit - sExecute: 3908 begin 3909 {$IFDEF TEXTLOG}CmdInfo := Format('RemoveUnit P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 3910 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 3911 result := eInvalid 3912 else 3913 begin 3914 result := eRemoved; 3915 Loc0 := RW[Player].Un[Subject].Loc; 3916 if RealMap[Loc0] and fCity <> 0 then { check utilize } 3917 begin 3918 SearchCity(Loc0, Player, cix1); 3919 with RW[Player].City[cix1] do 3920 begin 3921 if (RW[Player].Model[RW[Player].Un[Subject].mix].Kind = mkCaravan) 3922 and ((Project and cpImp = 0) or 3923 (Imp[Project and cpIndex].Kind <> ikShipPart)) or 3924 (Project and cpImp = 0) and 3925 (RW[Player].Model[Project and cpIndex].Kind <> mkCaravan) then 3926 result := eUtilized; 3927 if Command >= sExecute then 3928 begin 3929 if result = eUtilized then 3930 begin 3931 with RW[Player].Un[Subject] do 3932 begin 3933 Cost := integer(RW[Player].Model[mix].Cost) * Health * 3934 BuildCostMod[Difficulty[Player]] div 1200; 3935 if RW[Player].Model[mix].Cap[mcLine] > 0 then 3936 Cost := Cost div 2; 3937 end; 3938 if Project and (cpImp + cpIndex) = cpImp + imTrGoods then 3939 inc(RW[Player].Money, Cost) 3940 else 3941 begin 3942 inc(Prod, Cost * 2 div 3); 3943 Project0 := Project0 and not cpCompleted; 3944 if Project0 and not cpAuto <> Project and not cpAuto then 3945 Project0 := Project; 3946 Prod0 := Prod; 3947 end 3948 end; 3949 RemoveUnit_UpdateMap(Player, Subject); 3950 end; 3951 end; 3155 3952 end 3156 else if Tech[Subject]>=tsApplicable then 3157 result:=eInvalid; // already discovered 3158 if Tech[Subject]<>tsSeen then // look if preqs met 3159 if AdvPreq[Subject,2]<>preNone then 3160 begin // 2 of 3 required 3161 i:=0; 3162 for j:=0 to 2 do 3163 if Tech[AdvPreq[Subject,j]]>=tsApplicable then inc(i); 3164 if i<2 then result:=eNoPreq 3165 end 3166 else if (AdvPreq[Subject,0]<>preNone) 3167 and (Tech[AdvPreq[Subject,0]]<tsApplicable) 3168 or (AdvPreq[Subject,1]<>preNone) 3169 and (Tech[AdvPreq[Subject,1]]<tsApplicable) then 3170 result:=eNoPreq 3953 else if Command >= sExecute then 3954 RemoveUnit_UpdateMap(Player, Subject); 3955 end 3956 end; 3957 3958 sSetUnitHome, sSetUnitHome - sExecute: 3959 begin 3960 {$IFDEF TEXTLOG}CmdInfo := Format('SetUnitHome P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 3961 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 3962 result := eInvalid 3963 else 3964 begin 3965 Loc0 := RW[Player].Un[Subject].Loc; 3966 if RealMap[Loc0] and fCity = 0 then 3967 result := eInvalid 3968 else 3969 begin 3970 SearchCity(Loc0, Player, cix1); 3971 if RW[Player].City[cix1].Flags and chCaptured <> 0 then 3972 result := eViolation 3973 else if Command >= sExecute then 3974 RW[Player].Un[Subject].Home := cix1 3975 end 3976 end 3977 end; 3978 3979 sSetSpyMission .. sSetSpyMission + (nSpyMission - 1) shl 4, 3980 sSetSpyMission - sExecute .. sSetSpyMission - sExecute + 3981 (nSpyMission - 1) shl 4: 3982 if Command >= sExecute then 3983 SpyMission := Command shr 4 and $F; 3984 3985 sLoadUnit, sLoadUnit - sExecute: 3986 begin 3987 {$IFDEF TEXTLOG}CmdInfo := Format('LoadUnit P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 3988 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 3989 result := eInvalid 3990 else 3991 result := LoadUnit(Player, Subject, Command < sExecute); 3992 end; 3993 3994 sUnloadUnit, sUnloadUnit - sExecute: 3995 begin 3996 {$IFDEF TEXTLOG}CmdInfo := Format('UnloadUnit P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 3997 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 3998 result := eInvalid 3999 else 4000 result := UnloadUnit(Player, Subject, Command < sExecute) 4001 end; 4002 4003 sSelectTransport, sSelectTransport - sExecute: 4004 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 4005 result := eInvalid 4006 else 4007 with RW[Player].Model[RW[Player].Un[Subject].mix] do 4008 begin 4009 if Cap[mcSeaTrans] + Cap[mcAirTrans] + Cap[mcCarrier] = 0 then 4010 result := eInvalid 4011 else if Command >= sExecute then 4012 uixSelectedTransport := Subject; 3171 4013 end; 3172 if (result=eOK) and (Command>=sExecute) then 4014 4015 sCreateUnit .. sCreateUnit + (nPl - 1) shl 4, 4016 sCreateUnit - sExecute .. sCreateUnit - sExecute + (nPl - 1) shl 4: 4017 if (GTestFlags and tfUncover <> 0) or (Difficulty[Player] = 0) 4018 then { supervisor only command } 4019 begin 4020 p1 := Command shr 4 and $F; 4021 Loc1 := integer(Data); 4022 if (Occupant[Loc1] >= 0) and (p1 <> Occupant[Loc1]) or 4023 (RealMap[Loc1] and fCity <> 0) and 4024 (RealMap[Loc1] shr 27 <> Cardinal(p1)) or 4025 (RW[p1].Model[Subject].Domain < dAir) and 4026 ((RW[p1].Model[Subject].Domain = dSea) <> (RealMap[integer(Data)] and 4027 fTerrain < fGrass)) then 4028 result := eViolation 4029 else if Command >= sExecute then 3173 4030 begin 3174 if (Mode=moPlaying) and (Subject=adMilitary) then3175 IntServer(sIntSetDevModel,Player,0,DevModel.Kind);3176 // save DevModel, because sctModel commands are not logged3177 ResearchTech:=Subject;4031 CreateUnit(p1, Subject); 4032 RW[p1].Un[RW[p1].nUn - 1].Loc := integer(Data); 4033 PlaceUnit(p1, RW[p1].nUn - 1); 4034 UpdateUnitMap(integer(Data)); 3178 4035 end 3179 4036 end 3180 else result:=eViolation; 3181 end; 3182 3183 sStealTech, sStealTech-sExecute: 3184 begin 3185 {$IFDEF TEXTLOG}CmdInfo:=Format('StealTech P%d: %d', [Player,Subject]);{$ENDIF} 3186 if RW[Player].Happened and phStealTech=0 then result:=eInvalid 3187 else if (Subject>=nAdv) or (Subject in FutureTech) 3188 or (RW[Player].Tech[Subject]>=tsSeen) 3189 or (RW[GStealFrom].Tech[Subject]<tsApplicable) then 3190 result:=eInvalid 3191 else if Command>=sExecute then 3192 begin 3193 SeeTech(Player,Subject); 3194 dec(RW[Player].Happened,phStealTech); 3195 end 3196 end; 3197 3198 sSetAttitude..sSetAttitude+(nPl-1) shl 4, 3199 sSetAttitude-sExecute..sSetAttitude-sExecute+(nPl-1) shl 4: 3200 begin 3201 p1:=Command shr 4 and $f; 3202 {$IFDEF TEXTLOG}CmdInfo:=Format('SetAttitude P%d to P%d: %d', [Player,p1,Subject]);{$ENDIF} 3203 if (Subject>=nAttitude) or (p1>=nPl) 3204 or (RW[Player].EnemyReport[p1]=nil) then 3205 result:=eInvalid 3206 else if RW[Player].Treaty[p1]=trNoContact then 3207 result:=eNoPreq 3208 else if RW[Player].Attitude[p1]=Subject then 3209 result:=eNotChanged 3210 else if Command>=sExecute then 3211 begin 3212 RW[Player].Attitude[p1]:=Subject; 3213 RW[p1].EnemyReport[Player].Attitude:=Subject; 3214 end 3215 end; 3216 3217 sCancelTreaty, sCancelTreaty-sExecute: 3218 if (LastEndClientCommand<>scReject) 3219 or (RW[Player].Treaty[pContacted]<trPeace) then 3220 result:=eInvalid 3221 else if (ServerVersion[Player]>=$010100) 3222 and (GTurn<RW[Player].LastCancelTreaty[pContacted]+CancelTreatyTurns) then 3223 result:=eCancelTreatyRush 3224 else if Command>=sExecute then 3225 begin 3226 CallPlayer(cShowCancelTreaty,pContacted,Player); 3227 IntServer(sIntCancelTreaty,Player,pContacted,nil^); 3228 for p2:=0 to nPl-1 do 3229 if (p2<>pContacted) and (1 shl p2 and PeaceEnded<>0) then 4037 else 4038 result := eInvalid; 4039 4040 sMoveUnit + (0 + 6 * 8) * 16, sMoveUnit + (1 + 7 * 8) * 16, 4041 sMoveUnit + (2 + 0 * 8) * 16, sMoveUnit + (1 + 1 * 8) * 16, 4042 sMoveUnit + (0 + 2 * 8) * 16, sMoveUnit + (7 + 1 * 8) * 16, 4043 sMoveUnit + (6 + 0 * 8) * 16, sMoveUnit + (7 + 7 * 8) * 16, 4044 sMoveUnit - sExecute + (0 + 6 * 8) * 16, sMoveUnit - sExecute + 4045 (1 + 7 * 8) * 16, sMoveUnit - sExecute + (2 + 0 * 8) * 16, 4046 sMoveUnit - sExecute + (1 + 1 * 8) * 16, sMoveUnit - sExecute + 4047 (0 + 2 * 8) * 16, sMoveUnit - sExecute + (7 + 1 * 8) * 16, 4048 sMoveUnit - sExecute + (6 + 0 * 8) * 16, sMoveUnit - sExecute + 4049 (7 + 7 * 8) * 16: 4050 begin 4051 dx := (Command shr 4 + 4) and 7 - 4; 4052 dy := (Command shr 7 + 4) and 7 - 4; 4053 {$IFDEF TEXTLOG}CmdInfo := Format('MoveUnit P%d I%d Mod%d Loc%d (%d,%d)', [Player, Subject, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc, dx, dy]); {$ENDIF} 4054 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 4055 result := eInvalid 4056 else 4057 result := MoveUnit(Player, Subject, dx, dy, Command < sExecute); 4058 end; 4059 4060 { 4061 Settlers Related Commands 4062 ____________________________________________________________________ 4063 } 4064 sAddToCity, sAddToCity - sExecute: 4065 begin 4066 {$IFDEF TEXTLOG}CmdInfo := Format('AddToCity P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 4067 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 4068 result := eInvalid 4069 else if not(RW[Player].Model[RW[Player].Un[Subject].mix].Kind 4070 in [mkSettler, mkSlaves]) and 4071 (RW[Player].Un[Subject].Flags and unConscripts = 0) then 4072 result := eViolation 4073 else 4074 begin 4075 Loc0 := RW[Player].Un[Subject].Loc; 4076 if RealMap[Loc0] and fCity = 0 then 4077 result := eInvalid 4078 else 3230 4079 begin 3231 i:=pContacted shl 4+Player; 3232 CallPlayer(cShowSupportAllianceAgainst,p2,i); 4080 SearchCity(Loc0, Player, cix1); 4081 with RW[Player].City[cix1] do 4082 if not CanCityGrow(Player, cix1) then 4083 result := eMaxSize 4084 else if Command >= sExecute then 4085 begin { add to city } 4086 if Mode = moPlaying then 4087 SavedTiles[cix1] := 0; // save in every case 4088 if CanCityGrow(Player, cix1) then 4089 CityGrowth(Player, cix1); 4090 if (RW[Player].Model[RW[Player].Un[Subject].mix] 4091 .Kind = mkSettler) and CanCityGrow(Player, cix1) then 4092 CityGrowth(Player, cix1); 4093 RemoveUnit_UpdateMap(Player, Subject); 4094 end 4095 end 4096 end 4097 end; 4098 4099 sStartJob .. sStartJob + $3F0, sStartJob - sExecute .. sStartJob + $3F0 4100 - sExecute: 4101 begin 4102 Loc0 := RW[Player].Un[Subject].Loc; 4103 i := Command shr 4 and $3F; // new job 4104 {$IFDEF TEXTLOG}CmdInfo := Format('StartJob P%d Mod%d Loc%d: %d', [Player, RW[Player].Un[Subject].mix, Loc0, i]); {$ENDIF} 4105 if (Subject >= RW[Player].nUn) or (Loc0 < 0) then 4106 result := eInvalid 4107 else if i >= nJob then 4108 result := eInvalid 4109 else 4110 begin 4111 result := StartJob(Player, Subject, i, Command < sExecute); 4112 if result = eCity then 4113 begin // new city 4114 cix1 := RW[Player].nCity - 1; 4115 AddBestCityTile(Player, cix1); 4116 if Mode = moPlaying then 4117 with RW[Player].City[cix1] do 4118 begin 4119 // SavedResourceWeights[cix1]:=ResourceWeights; 4120 SavedTiles[cix1] := 0; // save in every case 4121 end; 4122 if Mode >= moMovie then { show new city in interface modules } 4123 for p1 := 0 to nPl - 1 do 4124 if (1 shl p1 and GWatching <> 0) and (p1 <> Player) and 4125 (ObserveLevel[Loc0] and (3 shl (2 * p1)) > 0) then 4126 CallPlayer(cShowCityChanged, p1, Loc0); 4127 end 4128 end; 4129 end; 4130 4131 { 4132 City Related Commands 4133 ____________________________________________________________________ 4134 } 4135 sSetCityProject, sSetCityProject - sExecute: 4136 begin 4137 NewProject := integer(Data) and not cpAuto; 4138 {$IFDEF TEXTLOG}CmdInfo := Format('SetCityProject P%d Loc%d: %d', [Player, RW[Player].City[Subject].Loc, NewProject]); {$ENDIF} 4139 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4140 then 4141 result := eInvalid 4142 else 4143 with RW[Player].City[Subject] do 4144 begin 4145 if NewProject = Project then 4146 result := eNotChanged 4147 else 4148 begin 4149 pt0 := ProjectType(Project0); 4150 pt1 := ProjectType(NewProject); 4151 if NewProject and cpImp = 0 then 4152 begin 4153 if NewProject and cpIndex >= RW[Player].nModel then 4154 result := eInvalid 4155 else if (NewProject and cpConscripts <> 0) and 4156 not((RW[Player].Tech[adConscription] >= tsApplicable) and 4157 (RW[Player].Model[NewProject and cpIndex].Domain = dGround) 4158 and (RW[Player].Model[NewProject and cpIndex].Kind < mkScout)) 4159 then 4160 result := eViolation 4161 // else if (RW[Player].Model[NewProject and cpIndex].Kind=mkSlaves) 4162 // and (GWonder[woPyramids].EffectiveOwner<>Player) then 4163 // result:=eNoPreq 4164 end 4165 else if NewProject and cpIndex >= nImp then 4166 result := eInvalid 4167 else 4168 begin 4169 Preq := Imp[NewProject and cpIndex].Preq; 4170 for i := 0 to nImpReplacement - 1 do 4171 if (ImpReplacement[i].OldImp = NewProject and cpIndex) and 4172 (built[ImpReplacement[i].NewImp] > 0) then 4173 result := eObsolete; 4174 if result = eObsolete then 4175 else if Preq = preNA then 4176 result := eInvalid 4177 else if (Preq >= 0) and (RW[Player].Tech[Preq] < tsApplicable) 4178 then 4179 result := eNoPreq 4180 else if built[NewProject and cpIndex] > 0 then 4181 result := eInvalid 4182 else if (NewProject and cpIndex < 28) and 4183 (GWonder[NewProject and cpIndex].CityID <> -1) then 4184 result := eViolation // wonder already exists 4185 else if (NewProject and cpIndex = imSpacePort) and 4186 (RW[Player].NatBuilt[imSpacePort] > 0) then 4187 result := eViolation // space port already exists 4188 else if (NewProject = cpImp + imBank) and (built[imMarket] = 0) 4189 or (NewProject = cpImp + imUniversity) and 4190 (built[imLibrary] = 0) or (NewProject = cpImp + imResLab) and 4191 (built[imUniversity] = 0) or (NewProject = cpImp + imMfgPlant) 4192 and (built[imFactory] = 0) then 4193 result := eNoPreq; 4194 case NewProject - cpImp of 4195 woLighthouse, woMagellan, imCoastalFort, imHarbor, imPlatform: 4196 begin { city at ocean? } 4197 Preq := 0; 4198 V8_to_Loc(Loc, Adjacent); 4199 for V8 := 0 to 7 do 4200 begin 4201 Loc1 := Adjacent[V8]; 4202 if (Loc1 >= 0) and (Loc1 < MapSize) and 4203 (RealMap[Loc1] and fTerrain = fShore) then 4204 inc(Preq); 4205 end; 4206 if Preq = 0 then 4207 result := eNoPreq; 4208 end; 4209 woHoover, imHydro: 4210 begin { city at river or mountains? } 4211 Preq := 0; 4212 V8_to_Loc(Loc, Adjacent); 4213 for V8 := 0 to 7 do 4214 begin 4215 Loc1 := Adjacent[V8]; 4216 if (Loc1 >= 0) and (Loc1 < MapSize) and 4217 ((RealMap[Loc1] and fTerrain = fMountains) or 4218 (RealMap[Loc1] and fRiver <> 0)) then 4219 inc(Preq); 4220 end; 4221 if Preq = 0 then 4222 result := eNoPreq; 4223 end; 4224 woMIR, imShipComp, imShipPow, imShipHab: 4225 if RW[Player].NatBuilt[imSpacePort] = 0 then 4226 result := eNoPreq; 4227 end; 4228 if (GTestFlags and tfNoRareNeed = 0) and 4229 (Imp[NewProject and cpIndex].Kind = ikShipPart) then 4230 if RW[Player].Tech[adMassProduction] < tsApplicable then 4231 result := eNoPreq 4232 else 4233 begin // check for rare resources 4234 if NewProject and cpIndex = imShipComp then 4235 j := 1 4236 else if NewProject and cpIndex = imShipPow then 4237 j := 2 4238 else { if NewProject and cpIndex=imShipHab then } 4239 j := 3; 4240 // j = rare resource required 4241 Preq := 0; 4242 V21_to_Loc(Loc, Radius); 4243 for V21 := 1 to 26 do 4244 begin 4245 Loc1 := Radius[V21]; 4246 if (Loc1 >= 0) and (Loc1 < MapSize) and 4247 (RealMap[Loc1] shr 25 and 3 = Cardinal(j)) then 4248 inc(Preq); 4249 end; 4250 if Preq = 0 then 4251 result := eNoPreq; 4252 end 4253 end; 4254 4255 if (Command >= sExecute) and (result >= rExecuted) then 4256 begin 4257 if pt0 <> ptSelect then 4258 if NewProject and (cpImp or cpIndex) = Project0 and 4259 (cpImp or cpIndex) then 4260 Prod := Prod0 4261 else if (pt1 = ptTrGoods) or (pt1 = ptShip) or (pt1 <> pt0) 4262 and (pt0 <> ptCaravan) then 4263 begin 4264 inc(RW[Player].Money, Prod0); 4265 Prod := 0; 4266 Prod0 := 0; 4267 Project0 := cpImp + imTrGoods 4268 end 4269 else 4270 Prod := Prod0 * 2 div 3; 4271 Project := NewProject 4272 end 4273 end 4274 end 4275 end; 4276 4277 sBuyCityProject, sBuyCityProject - sExecute: 4278 begin 4279 {$IFDEF TEXTLOG}CmdInfo := Format('BuyCityProject P%d Loc%d', [Player, RW[Player].City[Subject].Loc]); {$ENDIF} 4280 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4281 then 4282 result := eInvalid 4283 else 4284 with RW[Player].City[Subject] do 4285 if (RW[Player].Government = gAnarchy) or (Flags and chCaptured <> 0) 4286 then 4287 result := eOutOfControl 4288 else if (Project and cpImp <> 0) and 4289 ((Project and cpIndex = imTrGoods) or 4290 (Imp[Project and cpIndex].Kind = ikShipPart)) then 4291 result := eInvalid // don't buy colony ship 4292 else 4293 begin 4294 CityReport.HypoTiles := -1; 4295 CityReport.HypoTax := -1; 4296 CityReport.HypoLux := -1; 4297 GetCityReport(Player, Subject, CityReport); 4298 Cost := CityReport.ProdCost; 4299 NextProd := CityReport.ProdRep - CityReport.Support; 4300 if (CityReport.Working - CityReport.Happy > Size shr 1) or 4301 (NextProd < 0) then // !!! change to new style disorder 4302 NextProd := 0; 4303 Cost := Cost - Prod - NextProd; 4304 if (GWonder[woMich].EffectiveOwner = Player) and 4305 (Project and cpImp <> 0) then 4306 Cost := Cost * 2 4307 else 4308 Cost := Cost * 4; 4309 if Cost <= 0 then 4310 result := eNotChanged 4311 else if Cost > RW[Player].Money then 4312 result := eViolation 4313 else if Command >= sExecute then 4314 IntServer(sIntBuyMaterial, Player, Subject, Cost); 4315 // need to save material/cost because city tiles are not correct 4316 // when loading 4317 end; 4318 end; 4319 4320 sSellCityProject, sSellCityProject - sExecute: 4321 begin 4322 {$IFDEF TEXTLOG}CmdInfo := Format('SellCityProject P%d Loc%d', [Player, RW[Player].City[Subject].Loc]); {$ENDIF} 4323 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4324 then 4325 result := eInvalid 4326 else if Command >= sExecute then 4327 with RW[Player].City[Subject] do 4328 begin 4329 inc(RW[Player].Money, Prod0); 4330 Prod := 0; 4331 Prod0 := 0; 3233 4332 end; 3234 for p2:=0 to nPl-1 do 3235 if (p2<>pContacted) and (1 shl p2 and PeaceEnded<>0) then 3236 begin 3237 i:=p2; 3238 CallPlayer(cShowCancelTreatyByAlliance,Player,i); 3239 end; 3240 LastEndClientCommand:=sTurn; 3241 end; 3242 3243 { 3244 Model Related Commands 3245 ____________________________________________________________________ 3246 } 3247 sCreateDevModel, sCreateDevModel-sExecute: 3248 begin 3249 {$IFDEF TEXTLOG}CmdInfo:=Format('CreateDevModel P%d', [Player]);{$ENDIF} 3250 if Subject>=4 then result:=eInvalid 3251 else if (upgrade[Subject,0].Preq<>preNone) 3252 and (RW[Player].Tech[upgrade[Subject,0].Preq]<tsApplicable) then 3253 result:=eNoPreq 3254 else if Command>=sExecute then 3255 begin 3256 with RW[Player].DevModel do 3257 begin 3258 Domain:=Subject; 3259 MStrength:=0; MTrans:=0; MCost:=0; Upgrades:=0; 3260 FutureMCost:=0; 3261 for i:=0 to nUpgrade-1 do with upgrade[Domain,i] do 3262 if (Preq=preNone) 3263 or (Preq>=0) and ((RW[Player].Tech[Preq]>=tsApplicable) 3264 or (Preq in FutureTech) and (RW[Player].Tech[Preq]>=0)) then 4333 end; 4334 4335 sSellCityImprovement, sSellCityImprovement - sExecute: 4336 begin 4337 {$IFDEF TEXTLOG}CmdInfo := Format('SellCityImprovement P%d Loc%d: %d', [Player, RW[Player].City[Subject].Loc, integer(Data)]); {$ENDIF} 4338 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4339 then 4340 result := eInvalid 4341 else 4342 with RW[Player].City[Subject] do 4343 if built[integer(Data)] = 0 then 4344 result := eInvalid 4345 else if (RW[Player].Government = gAnarchy) or 4346 (Flags and chCaptured <> 0) then 4347 result := eOutOfControl 4348 else if Flags and chImprovementSold <> 0 then 4349 result := eOnlyOnce 4350 else if Command >= sExecute then 3265 4351 begin 3266 if Preq in FutureTech then 4352 inc(RW[Player].Money, Imp[integer(Data)].Cost * BuildCostMod 4353 [Difficulty[Player]] div 12); 4354 built[integer(Data)] := 0; 4355 if Imp[integer(Data)].Kind in [ikNatLocal, ikNatGlobal] then 3267 4356 begin 3268 j:=RW[Player].Tech[Preq]; 3269 inc(FutureMCost,j*Cost); 3270 end 3271 else 3272 begin 3273 j:=1; 3274 if Cost>MCost then MCost:=Cost; 3275 end; 3276 inc(Upgrades,1 shl i); 3277 inc(MStrength,j*Strength); 3278 inc(MTrans,j*Trans); 3279 end; 3280 inc(MCost,FutureMCost); 3281 FillChar(Cap,SizeOf(Cap),0); 3282 Cap[mcOffense]:=2; 3283 Cap[mcDefense]:=1; 3284 for i:=0 to nFeature-1 do with Feature[i] do 3285 if (1 shl Domain and Domains<>0) and ((Preq=preNone) 3286 or (Preq=preSun) and (GWonder[woSun].EffectiveOwner=Player) 3287 or (Preq>=0) and (RW[Player].Tech[Preq]>=tsApplicable)) 3288 and (i in AutoFeature) then Cap[i]:=1; 3289 MaxWeight:=5; 3290 if (WeightPreq7[Domain]<>preNA) 3291 and (RW[Player].Tech[WeightPreq7[Domain]]>=tsApplicable) then 3292 MaxWeight:=7; 3293 if (WeightPreq10[Domain]<>preNA) 3294 and (RW[Player].Tech[WeightPreq10[Domain]]>=tsApplicable) then 3295 if Domain=dSea then MaxWeight:=9 3296 else MaxWeight:=10; 3297 end; 3298 CalculateModel(RW[Player].DevModel); 3299 DevModelTurn[Player]:=GTurn; 3300 end 3301 end; 3302 3303 sSetDevModelCap..sSetDevModelCap+$3F0, 3304 sSetDevModelCap-sExecute..sSetDevModelCap-sExecute+$3F0: 3305 begin 3306 {$IFDEF TEXTLOG}CmdInfo:=Format('SetDevModelCap P%d', [Player]);{$ENDIF} 3307 if Subject>=nFeature then result:=eInvalid 3308 else if DevModelTurn[Player]=GTurn then 3309 begin 3310 NewCap:=Command shr 4 and $3F; {new value} 3311 with RW[Player].DevModel do 3312 if 1 shl Domain and Feature[Subject].Domains=0 then 3313 result:=eDomainMismatch 3314 else if not ((Feature[Subject].Preq=preNone) 3315 or (Feature[Subject].Preq=preSun) 3316 and (GWonder[woSun].EffectiveOwner=Player) 3317 or (Feature[Subject].Preq>=0) 3318 and (RW[Player].Tech[Feature[Subject].Preq]>=tsApplicable)) then 3319 result:=eNoPreq 3320 else 3321 begin 3322 if (Subject in AutoFeature) or (Subject=mcDefense) then MinCap:=1 3323 else MinCap:=0; {MinCap - minimum use of feature} 3324 if Subject>=mcFirstNonCap then MaxCap:=1 3325 else if Subject=mcDefense then 3326 begin 3327 if Domain=dGround then MaxCap:=2 3328 else MaxCap:=3; 3329 if RW[Player].Tech[adSteel]>=tsApplicable then inc(MaxCap) 3330 end 3331 else MaxCap:=8; {MaxCap - maximum use of this feature} 3332 if (Domain=dGround) and (Subject=mcDefense) then CapWeight:=2 3333 else CapWeight:=Feature[Subject].Weight; 3334 if (NewCap<MinCap) or (NewCap>MaxCap) 3335 or (Weight+(NewCap-Cap[Subject])*CapWeight>MaxWeight) then 3336 result:=eViolation 3337 else if Command>=sExecute then 3338 begin 3339 Cap[Subject]:=NewCap; 3340 3341 // mutual feature exclusion 3342 case Subject of 3343 mcSub: 3344 begin 3345 if ServerVersion[Player]>=$010103 then 3346 Cap[mcSeaTrans]:=0; 3347 Cap[mcArtillery]:=0; 3348 Cap[mcCarrier]:=0; 3349 if Cap[mcDefense]>2 then Cap[mcDefense]:=2 3350 end; 3351 mcSeaTrans: 3352 begin 3353 if ServerVersion[Player]>=$010103 then 3354 Cap[mcSub]:=0; 3355 end; 3356 mcCarrier: Cap[mcSub]:=0; 3357 mcArtillery: Cap[mcSub]:=0; 3358 mcAlpine: 3359 begin Cap[mcOver]:=0; Cap[mcMob]:=0; end; 3360 mcOver: Cap[mcAlpine]:=0; 3361 mcMob: begin Cap[mcAlpine]:=0; end; 3362 end; 3363 3364 CalculateModel(RW[Player].DevModel); 3365 end 3366 end; 3367 end 3368 else result:=eNoModel; 3369 end; 3370 3371 { 3372 Unit Related Commands 3373 ____________________________________________________________________ 3374 } 3375 sRemoveUnit,sRemoveUnit-sExecute: 3376 begin 3377 {$IFDEF TEXTLOG}CmdInfo:=Format('RemoveUnit P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3378 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3379 result:=eInvalid 3380 else 3381 begin 3382 result:=eRemoved; 3383 Loc0:=RW[Player].Un[Subject].Loc; 3384 if RealMap[Loc0] and fCity<>0 then {check utilize} 3385 begin 3386 SearchCity(Loc0,Player,cix1); 3387 with RW[Player].City[cix1] do 3388 begin 3389 if (RW[Player].Model[RW[Player].Un[Subject].mix].Kind=mkCaravan) 3390 and ((Project and cpImp=0) or (Imp[Project and cpIndex].Kind<>ikShipPart)) 3391 or (Project and cpImp=0) and (RW[Player].Model[Project 3392 and cpIndex].Kind<>mkCaravan) then 3393 result:=eUtilized; 3394 if Command>=sExecute then 3395 begin 3396 if result=eUtilized then 3397 begin 3398 with RW[Player].Un[Subject] do 3399 begin 3400 Cost:=integer(RW[Player].Model[mix].Cost)*Health 3401 *BuildCostMod[Difficulty[Player]] div 1200; 3402 if RW[Player].Model[mix].Cap[mcLine]>0 then 3403 Cost:=Cost div 2; 3404 end; 3405 if Project and (cpImp+cpIndex)=cpImp+imTrGoods then 3406 inc(RW[Player].Money,Cost) 3407 else 3408 begin 3409 inc(Prod,Cost*2 div 3); 3410 Project0:=Project0 and not cpCompleted; 3411 if Project0 and not cpAuto<>Project and not cpAuto then 3412 Project0:=Project; 3413 Prod0:=Prod; 4357 RW[Player].NatBuilt[integer(Data)] := 0; 4358 case integer(Data) of 4359 imGrWall: 4360 GrWallContinent[Player] := -1; 4361 imSpacePort: 4362 DestroySpacePort_TellPlayers(Player, -1); 3414 4363 end 3415 4364 end; 3416 RemoveUnit_UpdateMap(Player,Subject); 3417 end; 3418 end; 4365 inc(Flags, chImprovementSold); 4366 end 4367 end; 4368 4369 sRebuildCityImprovement, sRebuildCityImprovement - sExecute: 4370 begin 4371 OldImp := integer(Data); 4372 {$IFDEF TEXTLOG}CmdInfo := Format('RebuildCityImprovement P%d Loc%d: %d', [Player, RW[Player].City[Subject].Loc, OldImp]); {$ENDIF} 4373 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4374 then 4375 result := eInvalid 4376 else 4377 begin 4378 if (OldImp < 0) or (OldImp >= nImp) or 4379 not(Imp[OldImp].Kind in [ikCommon, ikNatLocal, ikNatGlobal]) then 4380 result := eInvalid 4381 else 4382 with RW[Player].City[Subject] do 4383 if (built[OldImp] = 0) or (Project and cpImp = 0) or 4384 not(Imp[Project and cpIndex].Kind in [ikCommon, ikNatLocal, 4385 ikNatGlobal]) then 4386 result := eInvalid 4387 else if (RW[Player].Government = gAnarchy) or 4388 (Flags and chCaptured <> 0) then 4389 result := eOutOfControl 4390 else if Flags and chImprovementSold <> 0 then 4391 result := eOnlyOnce 4392 else if Command >= sExecute then 4393 begin 4394 inc(Prod, Imp[OldImp].Cost * BuildCostMod[Difficulty[Player]] 4395 div 12 * 2 div 3); 4396 Project0 := Project0 and not cpCompleted; 4397 if Project0 and not cpAuto <> Project and not cpAuto then 4398 Project0 := Project; 4399 Prod0 := Prod; 4400 built[OldImp] := 0; 4401 if Imp[OldImp].Kind in [ikNatLocal, ikNatGlobal] then 4402 begin // nat. project lost 4403 RW[Player].NatBuilt[OldImp] := 0; 4404 case OldImp of 4405 imGrWall: 4406 GrWallContinent[Player] := -1; 4407 imSpacePort: 4408 DestroySpacePort_TellPlayers(Player, -1); 4409 end 4410 end; 4411 inc(Flags, chImprovementSold); 4412 end 3419 4413 end 3420 else if Command>=sExecute then 3421 RemoveUnit_UpdateMap(Player,Subject); 3422 end 4414 end; 4415 4416 sSetCityTiles, sSetCityTiles - sExecute: 4417 begin 4418 {$IFDEF TEXTLOG}CmdInfo := Format('SetCityTiles P%d Loc%d: %x', [Player, RW[Player].City[Subject].Loc, integer(Data)]); {$ENDIF} 4419 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4420 then 4421 result := eInvalid 4422 else 4423 result := SetCityTiles(Player, Subject, integer(Data), 4424 Command < sExecute); 4425 end; 4426 4427 { 4428 Client Exclusive Commands 4429 ____________________________________________________________________ 4430 } 4431 else 4432 if Command >= cClientEx then 4433 begin 4434 {$IFDEF TEXTLOG}CmdInfo := Format('ClientEx%x P%d', [Command, Player]); 4435 {$ENDIF} 4436 if ProcessClientData[Player] or (Mode = moPlaying) then 4437 CallPlayer(Command, Player, Data) 4438 end 4439 else 4440 result := eUnknown; 4441 end; { case command } 4442 4443 // do not log invalid and non-relevant commands 4444 if result = eZOC_EnemySpotted then 4445 begin 4446 assert(Mode = moPlaying); 4447 CL.State := FormerCLState; 4448 IntServer(sIntDiscoverZOC, Player, 0, ZOCTile); 4449 end 4450 else if result and rEffective = 0 then 4451 if Mode < moPlaying then 4452 begin 4453 {$IFDEF TEXTLOG}CmdInfo := Format('***ERROR (%x) ', [result]) + CmdInfo; 4454 {$ENDIF} 4455 LoadOK := false; 4456 end 4457 else 4458 begin 4459 if logged then 4460 CL.State := FormerCLState; 4461 if (result < rExecuted) and (Command >= sExecute) then 4462 PutMessage(1 shl 16 + 1, Format('INVALID: %d calls %x (%d)', 4463 [Player, Command, Subject])); 3423 4464 end; 3424 4465 3425 sSetUnitHome,sSetUnitHome-sExecute: 3426 begin 3427 {$IFDEF TEXTLOG}CmdInfo:=Format('SetUnitHome P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3428 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3429 result:=eInvalid 3430 else 3431 begin 3432 Loc0:=RW[Player].Un[Subject].Loc; 3433 if RealMap[Loc0] and fCity=0 then result:=eInvalid 3434 else 3435 begin 3436 SearchCity(Loc0,Player,cix1); 3437 if RW[Player].City[cix1].Flags and chCaptured<>0 then 3438 result:=eViolation 3439 else if Command>=sExecute then 3440 RW[Player].Un[Subject].Home:=cix1 3441 end 3442 end 3443 end; 3444 3445 sSetSpyMission..sSetSpyMission+(nSpyMission-1) shl 4, 3446 sSetSpyMission-sExecute..sSetSpyMission-sExecute+(nSpyMission-1) shl 4: 3447 if Command>=sExecute then 3448 SpyMission:=Command shr 4 and $F; 3449 3450 sLoadUnit,sLoadUnit-sExecute: 3451 begin 3452 {$IFDEF TEXTLOG}CmdInfo:=Format('LoadUnit P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3453 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3454 result:=eInvalid 3455 else result:=LoadUnit(Player,Subject,Command<sExecute); 3456 end; 3457 3458 sUnloadUnit,sUnloadUnit-sExecute: 3459 begin 3460 {$IFDEF TEXTLOG}CmdInfo:=Format('UnloadUnit P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3461 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3462 result:=eInvalid 3463 else result:=UnloadUnit(Player,Subject,Command<sExecute) 3464 end; 3465 3466 sSelectTransport,sSelectTransport-sExecute: 3467 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3468 result:=eInvalid 3469 else with RW[Player].Model[RW[Player].Un[Subject].mix] do 3470 begin 3471 if Cap[mcSeaTrans]+Cap[mcAirTrans]+Cap[mcCarrier]=0 then 3472 result:=eInvalid 3473 else if Command>=sExecute then 3474 uixSelectedTransport:=Subject; 3475 end; 3476 3477 sCreateUnit..sCreateUnit+(nPl-1) shl 4, 3478 sCreateUnit-sExecute..sCreateUnit-sExecute+(nPl-1) shl 4: 3479 if (GTestFlags and tfUncover<>0) or (Difficulty[Player]=0) then {supervisor only command} 3480 begin 3481 p1:=Command shr 4 and $f; 3482 Loc1:=integer(Data); 3483 if (Occupant[Loc1]>=0) and (p1<>Occupant[Loc1]) 3484 or (RealMap[Loc1] and fCity<>0) and (RealMap[Loc1] shr 27<>Cardinal(p1)) 3485 or (RW[p1].Model[Subject].Domain<dAir) 3486 and ((RW[p1].Model[Subject].Domain=dSea) 3487 <>(RealMap[integer(Data)] and fTerrain<fGrass)) then 3488 result:=eViolation 3489 else if Command>=sExecute then 3490 begin 3491 CreateUnit(p1,Subject); 3492 RW[p1].Un[RW[p1].nUn-1].Loc:=integer(Data); 3493 PlaceUnit(p1,RW[p1].nUn-1); 3494 UpdateUnitMap(integer(Data)); 3495 end 3496 end 3497 else result:=eInvalid; 3498 3499 sMoveUnit+(0+6*8)*16,sMoveUnit+(1+7*8)*16, 3500 sMoveUnit+(2+0*8)*16,sMoveUnit+(1+1*8)*16, 3501 sMoveUnit+(0+2*8)*16,sMoveUnit+(7+1*8)*16, 3502 sMoveUnit+(6+0*8)*16,sMoveUnit+(7+7*8)*16, 3503 sMoveUnit-sExecute+(0+6*8)*16,sMoveUnit-sExecute+(1+7*8)*16, 3504 sMoveUnit-sExecute+(2+0*8)*16,sMoveUnit-sExecute+(1+1*8)*16, 3505 sMoveUnit-sExecute+(0+2*8)*16,sMoveUnit-sExecute+(7+1*8)*16, 3506 sMoveUnit-sExecute+(6+0*8)*16,sMoveUnit-sExecute+(7+7*8)*16: 3507 begin 3508 dx:=(Command shr 4 +4) and 7-4; dy:=(Command shr 7 +4) and 7-4; 3509 {$IFDEF TEXTLOG}CmdInfo:=Format('MoveUnit P%d I%d Mod%d Loc%d (%d,%d)', [Player,Subject,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc,dx,dy]);{$ENDIF} 3510 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3511 result:=eInvalid 3512 else result:=MoveUnit(Player,Subject,dx,dy,Command<sExecute); 3513 end; 3514 3515 { 3516 Settlers Related Commands 3517 ____________________________________________________________________ 3518 } 3519 sAddToCity, sAddToCity-sExecute: 3520 begin 3521 {$IFDEF TEXTLOG}CmdInfo:=Format('AddToCity P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3522 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3523 result:=eInvalid 3524 else if not (RW[Player].Model[RW[Player].Un[Subject].mix].Kind in [mkSettler,mkSlaves]) 3525 and (RW[Player].Un[Subject].Flags and unConscripts=0) then 3526 result:=eViolation 3527 else 3528 begin 3529 Loc0:=RW[Player].Un[Subject].Loc; 3530 if RealMap[Loc0] and fCity=0 then result:=eInvalid 3531 else 3532 begin 3533 SearchCity(Loc0,Player,cix1); 3534 with RW[Player].City[cix1] do 3535 if not CanCityGrow(Player,cix1) then 3536 result:=eMaxSize 3537 else if Command>=sExecute then 3538 begin {add to city} 3539 if Mode=moPlaying then 3540 SavedTiles[cix1]:=0; // save in every case 3541 if CanCityGrow(Player,cix1) then 3542 CityGrowth(Player,cix1); 3543 if (RW[Player].Model[RW[Player].Un[Subject].mix].Kind=mkSettler) 3544 and CanCityGrow(Player,cix1) then 3545 CityGrowth(Player,cix1); 3546 RemoveUnit_UpdateMap(Player,Subject); 3547 end 3548 end 3549 end 3550 end; 3551 3552 sStartJob..sStartJob+$3F0, sStartJob-sExecute..sStartJob+$3F0-sExecute: 3553 begin 3554 Loc0:=RW[Player].Un[Subject].Loc; 3555 i:=Command shr 4 and $3F; // new job 3556 {$IFDEF TEXTLOG}CmdInfo:=Format('StartJob P%d Mod%d Loc%d: %d', [Player,RW[Player].Un[Subject].mix,Loc0,i]);{$ENDIF} 3557 if (Subject>=RW[Player].nUn) or (Loc0<0) then 3558 result:=eInvalid 3559 else if i>=nJob then result:=eInvalid 3560 else 3561 begin 3562 result:=StartJob(Player,Subject,i,Command<sExecute); 3563 if result=eCity then 3564 begin // new city 3565 cix1:=RW[Player].nCity-1; 3566 AddBestCityTile(Player,cix1); 3567 if Mode=moPlaying then with RW[Player].City[cix1] do 3568 begin 3569 // SavedResourceWeights[cix1]:=ResourceWeights; 3570 SavedTiles[cix1]:=0; // save in every case 3571 end; 3572 if Mode>=moMovie then {show new city in interface modules} 3573 for p1:=0 to nPl-1 do 3574 if (1 shl p1 and GWatching<>0) and (p1<>Player) 3575 and (ObserveLevel[Loc0] and (3 shl (2*p1))>0) then 3576 CallPlayer(cShowCityChanged,p1,Loc0); 3577 end 3578 end; 3579 end; 3580 3581 { 3582 City Related Commands 3583 ____________________________________________________________________ 3584 } 3585 sSetCityProject,sSetCityProject-sExecute: 3586 begin 3587 NewProject:=integer(Data) and not cpAuto; 3588 {$IFDEF TEXTLOG}CmdInfo:=Format('SetCityProject P%d Loc%d: %d', [Player,RW[Player].City[Subject].Loc,NewProject]);{$ENDIF} 3589 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3590 result:=eInvalid 3591 else with RW[Player].City[Subject] do 3592 begin 3593 if NewProject=Project then result:=eNotChanged 3594 else 3595 begin 3596 pt0:=ProjectType(Project0); 3597 pt1:=ProjectType(NewProject); 3598 if NewProject and cpImp=0 then 3599 begin 3600 if NewProject and cpIndex>=RW[Player].nModel then 3601 result:=eInvalid 3602 else if (NewProject and cpConscripts<>0) 3603 and not ((RW[Player].Tech[adConscription]>=tsApplicable) 3604 and (RW[Player].Model[NewProject and cpIndex].Domain=dGround) 3605 and (RW[Player].Model[NewProject and cpIndex].Kind<mkScout)) then 3606 result:=eViolation 3607 // else if (RW[Player].Model[NewProject and cpIndex].Kind=mkSlaves) 3608 // and (GWonder[woPyramids].EffectiveOwner<>Player) then 3609 // result:=eNoPreq 3610 end 3611 else if NewProject and cpIndex>=nImp then 3612 result:=eInvalid 3613 else 3614 begin 3615 Preq:=Imp[NewProject and cpIndex].Preq; 3616 for i:=0 to nImpReplacement-1 do 3617 if (ImpReplacement[i].OldImp=NewProject and cpIndex) 3618 and (Built[ImpReplacement[i].NewImp]>0) then 3619 result:=eObsolete; 3620 if result=eObsolete then 3621 else if Preq=preNA then result:=eInvalid 3622 else if (Preq>=0) and (RW[Player].Tech[Preq]<tsApplicable) then 3623 result:=eNoPreq 3624 else if Built[NewProject and cpIndex]>0 then result:=eInvalid 3625 else if (NewProject and cpIndex<28) 3626 and (GWonder[NewProject and cpIndex].CityID<>-1) then 3627 result:=eViolation // wonder already exists 3628 else if (NewProject and cpIndex=imSpacePort) 3629 and (RW[Player].NatBuilt[imSpacePort]>0) then 3630 result:=eViolation // space port already exists 3631 else if (NewProject=cpImp+imBank) and (Built[imMarket]=0) 3632 or (NewProject=cpImp+imUniversity) and (Built[imLibrary]=0) 3633 or (NewProject=cpImp+imResLab) and (Built[imUniversity]=0) 3634 or (NewProject=cpImp+imMfgPlant) and (Built[imFactory]=0) then 3635 result:=eNoPreq; 3636 case NewProject-cpImp of 3637 woLighthouse,woMagellan,imCoastalFort,imHarbor,imPlatform: 3638 begin {city at ocean?} 3639 Preq:=0; 3640 V8_to_Loc(Loc,Adjacent); 3641 for V8:=0 to 7 do 3642 begin 3643 Loc1:=Adjacent[V8]; 3644 if (Loc1>=0) and (Loc1<MapSize) 3645 and (RealMap[Loc1] and fTerrain=fShore) then 3646 inc(Preq); 3647 end; 3648 if Preq=0 then result:=eNoPreq; 3649 end; 3650 woHoover,imHydro: 3651 begin {city at river or mountains?} 3652 Preq:=0; 3653 V8_to_Loc(Loc,Adjacent); 3654 for V8:=0 to 7 do 3655 begin 3656 Loc1:=Adjacent[V8]; 3657 if (Loc1>=0) and (Loc1<MapSize) 3658 and ((RealMap[Loc1] and fTerrain=fMountains) 3659 or (RealMap[Loc1] and fRiver<>0)) then inc(Preq); 3660 end; 3661 if Preq=0 then result:=eNoPreq; 3662 end; 3663 woMIR,imShipComp,imShipPow,imShipHab: 3664 if RW[Player].NatBuilt[imSpacePort]=0 then result:=eNoPreq; 3665 end; 3666 if (GTestFlags and tfNoRareNeed=0) 3667 and (Imp[NewProject and cpIndex].Kind=ikShipPart) then 3668 if RW[Player].Tech[adMassProduction]<tsApplicable then result:=eNoPreq 3669 else 3670 begin // check for rare resources 3671 if NewProject and cpIndex=imShipComp then j:=1 3672 else if NewProject and cpIndex=imShipPow then j:=2 3673 else {if NewProject and cpIndex=imShipHab then} j:=3; 3674 // j = rare resource required 3675 Preq:=0; 3676 V21_to_Loc(Loc,Radius); 3677 for V21:=1 to 26 do 3678 begin 3679 Loc1:=Radius[V21]; 3680 if (Loc1>=0) and (Loc1<MapSize) 3681 and (RealMap[Loc1] shr 25 and 3=Cardinal(j)) then 3682 inc(Preq); 3683 end; 3684 if Preq=0 then result:=eNoPreq; 3685 end 3686 end; 3687 3688 if (Command>=sExecute) and (result>=rExecuted) then 3689 begin 3690 if pt0<>ptSelect then 3691 if NewProject and (cpImp or cpIndex)=Project0 and (cpImp or cpIndex) then 3692 Prod:=Prod0 3693 else if (pt1=ptTrGoods) or (pt1=ptShip) or (pt1<>pt0) and (pt0<>ptCaravan) then 3694 begin 3695 inc(RW[Player].Money,Prod0); 3696 Prod:=0; 3697 Prod0:=0; 3698 Project0:=cpImp+imTrGoods 3699 end 3700 else Prod:=Prod0*2 div 3; 3701 Project:=NewProject 3702 end 3703 end 3704 end 3705 end; 3706 3707 sBuyCityProject,sBuyCityProject-sExecute: 3708 begin 3709 {$IFDEF TEXTLOG}CmdInfo:=Format('BuyCityProject P%d Loc%d', [Player,RW[Player].City[Subject].Loc]);{$ENDIF} 3710 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3711 result:=eInvalid 3712 else with RW[Player].City[Subject] do 3713 if (RW[Player].Government=gAnarchy) or (Flags and chCaptured<>0) then 3714 result:=eOutOfControl 3715 else if (Project and cpImp<>0) and ((Project and cpIndex=imTrGoods) 3716 or (Imp[Project and cpIndex].Kind=ikShipPart)) then 3717 result:=eInvalid // don't buy colony ship 3718 else 3719 begin 3720 CityReport.HypoTiles:=-1; 3721 CityReport.HypoTax:=-1; 3722 CityReport.HypoLux:=-1; 3723 GetCityReport(Player,Subject,CityReport); 3724 Cost:=CityReport.ProdCost; 3725 NextProd:=CityReport.ProdRep-CityReport.Support; 3726 if (CityReport.Working-CityReport.Happy>Size shr 1) or (NextProd<0) then // !!! change to new style disorder 3727 NextProd:=0; 3728 Cost:=Cost-Prod-NextProd; 3729 if (GWonder[woMich].EffectiveOwner=Player) and (Project and cpImp<>0) then 3730 Cost:=Cost*2 3731 else Cost:=Cost*4; 3732 if Cost<=0 then result:=eNotChanged 3733 else if Cost>RW[Player].Money then result:=eViolation 3734 else if Command>=sExecute then 3735 IntServer(sIntBuyMaterial, Player, Subject, Cost); 3736 // need to save material/cost because city tiles are not correct 3737 // when loading 3738 end; 3739 end; 3740 3741 sSellCityProject,sSellCityProject-sExecute: 3742 begin 3743 {$IFDEF TEXTLOG}CmdInfo:=Format('SellCityProject P%d Loc%d', [Player,RW[Player].City[Subject].Loc]);{$ENDIF} 3744 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3745 result:=eInvalid 3746 else if Command>=sExecute then 3747 with RW[Player].City[Subject] do 3748 begin inc(RW[Player].Money,Prod0); Prod:=0; Prod0:=0; end; 3749 end; 3750 3751 sSellCityImprovement,sSellCityImprovement-sExecute: 3752 begin 3753 {$IFDEF TEXTLOG}CmdInfo:=Format('SellCityImprovement P%d Loc%d: %d', [Player,RW[Player].City[Subject].Loc,integer(Data)]);{$ENDIF} 3754 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3755 result:=eInvalid 3756 else with RW[Player].City[Subject] do 3757 if Built[integer(Data)]=0 then result:=eInvalid 3758 else if (RW[Player].Government=gAnarchy) or (Flags and chCaptured<>0) then 3759 result:=eOutOfControl 3760 else if Flags and chImprovementSold<>0 then result:=eOnlyOnce 3761 else if Command>=sExecute then 3762 begin 3763 inc(RW[Player].Money, 3764 Imp[integer(Data)].Cost*BuildCostMod[Difficulty[Player]] div 12); 3765 Built[integer(Data)]:=0; 3766 if Imp[integer(Data)].Kind in [ikNatLocal,ikNatGlobal] then 3767 begin 3768 RW[Player].NatBuilt[integer(Data)]:=0; 3769 case integer(Data) of 3770 imGrWall: GrWallContinent[Player]:=-1; 3771 imSpacePort: DestroySpacePort_TellPlayers(Player,-1); 3772 end 3773 end; 3774 inc(Flags,chImprovementSold); 3775 end 3776 end; 3777 3778 sRebuildCityImprovement,sRebuildCityImprovement-sExecute: 3779 begin 3780 OldImp:=integer(Data); 3781 {$IFDEF TEXTLOG}CmdInfo:=Format('RebuildCityImprovement P%d Loc%d: %d', [Player,RW[Player].City[Subject].Loc,OldImp]);{$ENDIF} 3782 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3783 result:=eInvalid 3784 else 3785 begin 3786 if (OldImp<0) or (OldImp>=nImp) 3787 or not (Imp[OldImp].Kind in [ikCommon,ikNatLocal,ikNatGlobal]) then 3788 result:=eInvalid 3789 else with RW[Player].City[Subject] do 3790 if (Built[OldImp]=0) or (Project and cpImp=0) 3791 or not (Imp[Project and cpIndex].Kind in [ikCommon,ikNatLocal,ikNatGlobal]) then 3792 result:=eInvalid 3793 else if (RW[Player].Government=gAnarchy) or (Flags and chCaptured<>0) then 3794 result:=eOutOfControl 3795 else if Flags and chImprovementSold<>0 then result:=eOnlyOnce 3796 else if Command>=sExecute then 3797 begin 3798 inc(Prod,Imp[OldImp].Cost 3799 *BuildCostMod[Difficulty[Player]] div 12 *2 div 3); 3800 Project0:=Project0 and not cpCompleted; 3801 if Project0 and not cpAuto<>Project and not cpAuto then 3802 Project0:=Project; 3803 Prod0:=Prod; 3804 Built[OldImp]:=0; 3805 if Imp[OldImp].Kind in [ikNatLocal,ikNatGlobal] then 3806 begin // nat. project lost 3807 RW[Player].NatBuilt[OldImp]:=0; 3808 case OldImp of 3809 imGrWall: GrWallContinent[Player]:=-1; 3810 imSpacePort: DestroySpacePort_TellPlayers(Player,-1); 3811 end 3812 end; 3813 inc(Flags,chImprovementSold); 3814 end 3815 end 3816 end; 3817 3818 sSetCityTiles, sSetCityTiles-sExecute: 3819 begin 3820 {$IFDEF TEXTLOG}CmdInfo:=Format('SetCityTiles P%d Loc%d: %x', [Player,RW[Player].City[Subject].Loc,integer(data)]);{$ENDIF} 3821 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3822 result:=eInvalid 3823 else result:=SetCityTiles(Player, Subject, integer(Data), Command<sExecute); 3824 end; 3825 3826 { 3827 Client Exclusive Commands 3828 ____________________________________________________________________ 3829 } 3830 else 3831 if Command>=cClientEx then 3832 begin 3833 {$IFDEF TEXTLOG}CmdInfo:=Format('ClientEx%x P%d', [Command,Player]);{$ENDIF} 3834 if ProcessClientData[Player] or (Mode=moPlaying) then 3835 CallPlayer(Command,Player,Data) 3836 end 3837 else result:=eUnknown; 3838 end;{case command} 3839 3840 // do not log invalid and non-relevant commands 3841 if result=eZOC_EnemySpotted then 3842 begin 3843 assert(Mode=moPlaying); 3844 CL.State:=FormerCLState; 3845 IntServer(sIntDiscoverZOC,Player,0,ZOCTile); 3846 end 3847 else if result and rEffective=0 then 3848 if Mode<moPlaying then 3849 begin 3850 {$IFDEF TEXTLOG}CmdInfo:=Format('***ERROR (%x) ',[result])+CmdInfo;{$ENDIF} 3851 LoadOK:=false; 3852 end 3853 else 3854 begin 3855 if logged then CL.State:=FormerCLState; 3856 if (result<rExecuted) and (Command>=sExecute) then 3857 PutMessage(1 shl 16+1, Format('INVALID: %d calls %x (%d)', 3858 [Player,Command,Subject])); 3859 end; 3860 3861 if (Command and (cClientEx or sExecute or sctMask)=sExecute or sctEndClient) 3862 and (result>=rExecuted) then LastEndClientCommand:=Command; 3863 {$IFOPT O-}dec(nHandoverStack,2);{$ENDIF} 3864 end;{<<<server} 3865 4466 if (Command and (cClientEx or sExecute or sctMask) = sExecute or sctEndClient) 4467 and (result >= rExecuted) then 4468 LastEndClientCommand := Command; 4469 {$IFOPT O-}dec(nHandoverStack, 2); {$ENDIF} 4470 end; { <<<server } 3866 4471 3867 4472 initialization 4473 3868 4474 QueryPerformanceFrequency(PerfFreq); 3869 FindFirst(ParamStr(0), $21,ExeInfo);3870 3871 {$IFOPT O-}nHandoverStack :=0;{$ENDIF}4475 FindFirst(ParamStr(0), $21, ExeInfo); 4476 4477 {$IFOPT O-}nHandoverStack := 0; {$ENDIF} 3872 4478 3873 4479 end. 3874
Note:
See TracChangeset
for help on using the changeset viewer.