Changeset 294 for trunk/LocalPlayer/ClientTools.pas
- Timestamp:
- Mar 5, 2021, 1:49:27 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LocalPlayer/ClientTools.pas
r205 r294 13 13 14 14 type 15 TImpOrder = array [0 .. (nImp + 4) div 4 * 4 - 1] of ShortInt;16 TEnhancementJobs = array [0 .. 11, 0 .. 7] of Byte;15 TImpOrder = array [0 .. (nImp + 4) div 4 * 4 - 1] of shortint; 16 TEnhancementJobs = array [0 .. 11, 0 .. 7] of byte; 17 17 JobResultSet = set of 0 .. 39; 18 18 … … 42 42 function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean; 43 43 gov, size: integer): integer; 44 function CityTaxBalance(cix: integer; const CityReport: TCityReportNew) 45 : integer; 44 function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer; 46 45 procedure SumCities(var TaxSum, ScienceSum: integer); 47 46 function JobTest(uix, Job: integer; IgnoreResults: JobResultSet = []): boolean; … … 50 49 function UnitExhausted(uix: integer): boolean; 51 50 function ModelHash(const ModelInfo: TModelInfo): integer; 52 function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs) 53 : integer; 51 function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer; 54 52 function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean; 55 53 procedure DebugMessage(Level: integer; Text: string); … … 62 60 procedure CityOptimizer_EndOfTurn; 63 61 62 64 63 implementation 65 64 … … 72 71 begin 73 72 y0 := (Loc + G.lx * 1024) div G.lx - 1024; 74 result := (Loc + (dx + y0 and 1 + G.lx * 1024) shr 1) mod G.lx + G.lx 75 * (y0 + dy) 73 Result := (Loc + (dx + y0 and 1 + G.lx * 1024) shr 1) mod G.lx + G.lx * (y0 + dy); 76 74 end; 77 75 … … 80 78 dx, dy: integer; 81 79 begin 82 inc(Loc0, G.lx * 1024);83 inc(Loc1, G.lx * 1024);84 dx := abs(((Loc1 mod G.lx * 2 + Loc1 div G.lx and 1) - (Loc0 mod G.lx * 2 +85 Loc0 div G.lx and 1) + 3 * G.lx) mod (2 * G.lx) - G.lx);80 Inc(Loc0, G.lx * 1024); 81 Inc(Loc1, G.lx * 1024); 82 dx := abs(((Loc1 mod G.lx * 2 + Loc1 div G.lx and 1) - 83 (Loc0 mod G.lx * 2 + Loc0 div G.lx and 1) + 3 * G.lx) mod (2 * G.lx) - G.lx); 86 84 dy := abs(Loc1 div G.lx - Loc0 div G.lx); 87 result := dx + dy + abs(dx - dy) shr 1;85 Result := dx + dy + abs(dx - dy) shr 1; 88 86 end; 89 87 … … 92 90 uix1: integer; 93 91 begin 94 result := false;92 Result := False; 95 93 if MyModel[MyUn[uix].mix].Flags and mdCivil = 0 then 96 94 case MyRO.Government of 97 95 gRepublic, gFuture: 98 result := (MyRO.Territory[Loc] >= 0) and (MyRO.Territory[Loc] <> me) and96 Result := (MyRO.Territory[Loc] >= 0) and (MyRO.Territory[Loc] <> me) and 99 97 (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance); 100 98 gDemocracy: 101 result := (MyRO.Territory[Loc] < 0) or (MyRO.Territory[Loc] <> me) and99 Result := (MyRO.Territory[Loc] < 0) or (MyRO.Territory[Loc] <> me) and 102 100 (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance); 103 101 end; … … 106 104 for uix1 := 0 to MyRO.nUn - 1 do // check transported units too 107 105 if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) then 108 result := result or UnrestAtLoc(uix1, Loc);106 Result := Result or UnrestAtLoc(uix1, Loc); 109 107 end; 110 108 … … 124 122 MoveAdviceData.MoreTurns := 999; 125 123 MoveAdviceData.MaxHostile_MovementLeft := MyUn[uix].Health - MinEndHealth; 126 result := Server(sGetMoveAdvice, me, uix, MoveAdviceData);127 if (MinEndHealth <= 1) or ( result <> eNoWay) then124 Result := Server(sGetMoveAdvice, me, uix, MoveAdviceData); 125 if (MinEndHealth <= 1) or (Result <> eNoWay) then 128 126 exit; 129 127 end; … … 135 133 25: 136 134 MinEndHealth := 12; 135 else 136 MinEndHealth := 1 137 end; 138 until False; 139 end; 140 141 function ColorOfHealth(Health: integer): integer; 142 var 143 red, green: integer; 144 begin 145 green := 400 * Health div 100; 146 if green > 200 then 147 green := 200; 148 red := 510 * (100 - Health) div 100; 149 if red > 255 then 150 red := 255; 151 Result := green shl 8 + red; 152 end; 153 154 function IsMultiPlayerGame: boolean; 155 var 156 p1: integer; 157 begin 158 Result := False; 159 for p1 := 1 to nPl - 1 do 160 if G.RO[p1] <> nil then 161 Result := True; 162 end; 163 164 procedure ItsMeAgain(p: integer); 165 begin 166 if G.RO[p] <> nil then 167 MyRO := pointer(G.RO[p]) 168 else if G.SuperVisorRO[p] <> nil then 169 MyRO := pointer(G.SuperVisorRO[p]) 170 else 171 exit; 172 me := p; 173 MyMap := pointer(MyRO.Map); 174 MyUn := pointer(MyRO.Un); 175 MyCity := pointer(MyRO.City); 176 MyModel := pointer(MyRO.Model); 177 end; 178 179 function GetAge(p: integer): integer; 180 var 181 i: integer; 182 begin 183 if p = me then 184 begin 185 Result := 0; 186 for i := 1 to 3 do 187 if MyRO.Tech[AgePreq[i]] >= tsApplicable then 188 Result := i; 189 end 190 else 191 begin 192 Result := 0; 193 for i := 1 to 3 do 194 if MyRO.EnemyReport[p].Tech[AgePreq[i]] >= tsApplicable then 195 Result := i; 196 end; 197 end; 198 199 function IsCivilReportNew(Enemy: integer): boolean; 200 var 201 i: integer; 202 begin 203 assert(Enemy <> me); 204 i := MyRO.EnemyReport[Enemy].TurnOfCivilReport; 205 Result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me); 206 end; 207 208 function IsMilReportNew(Enemy: integer): boolean; 209 var 210 i: integer; 211 begin 212 assert(Enemy <> me); 213 i := MyRO.EnemyReport[Enemy].TurnOfMilReport; 214 Result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me); 215 end; 216 217 function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean; 218 gov, size: integer): integer; 219 begin 220 Result := FoodSurplus; 221 if not IsCityAlive or (Result > 0) and ((gov = gFuture) or 222 (size >= NeedAqueductSize) and (Result < 2)) then 223 Result := 0; { no growth } 224 end; 225 226 function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer; 227 var 228 i: integer; 229 begin 230 Result := 0; 231 if (CityReport.HappinessBalance >= 0) { no disorder } and 232 (MyCity[cix].Flags and chCaptured = 0) then // not captured 233 begin 234 Inc(Result, CityReport.Tax); 235 if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) and 236 (CityReport.Production > 0) then 237 Inc(Result, CityReport.Production); 238 if ((MyRO.Government = gFuture) or (MyCity[cix].size >= 239 NeedAqueductSize) and (CityReport.FoodSurplus < 2)) and 240 (CityReport.FoodSurplus > 0) then 241 Inc(Result, CityReport.FoodSurplus); 242 end; 243 for i := 28 to nImp - 1 do 244 if MyCity[cix].Built[i] > 0 then 245 Dec(Result, Imp[i].Maint); 246 end; 247 248 procedure SumCities(var TaxSum, ScienceSum: integer); 249 var 250 cix: integer; 251 CityReport: TCityReportNew; 252 begin 253 TaxSum := MyRO.OracleIncome; 254 ScienceSum := 0; 255 if MyRO.Government = gAnarchy then 256 exit; 257 for cix := 0 to MyRO.nCity - 1 do 258 if MyCity[cix].Loc >= 0 then 259 begin 260 CityReport.HypoTiles := -1; 261 CityReport.HypoTaxRate := -1; 262 CityReport.HypoLuxuryRate := -1; 263 Server(sGetCityReportNew, me, cix, CityReport); 264 if (CityReport.HappinessBalance >= 0) { no disorder } and 265 (MyCity[cix].Flags and chCaptured = 0) then // not captured 266 ScienceSum := ScienceSum + CityReport.Science; 267 TaxSum := TaxSum + CityTaxBalance(cix, CityReport); 268 end; 269 end; 270 271 function JobTest(uix, Job: integer; IgnoreResults: JobResultSet): boolean; 272 var 273 Test: integer; 274 begin 275 Test := Server(sStartJob + Job shl 4 - sExecute, me, uix, nil^); 276 Result := (Test >= rExecuted) or (Test in IgnoreResults); 277 end; 278 279 procedure GetUnitInfo(Loc: integer; var uix: integer; var UnitInfo: TUnitInfo); 280 var 281 i, Cnt: integer; 282 begin 283 if MyMap[Loc] and fOwned <> 0 then 284 begin 285 Server(sGetDefender, me, Loc, uix); 286 Cnt := 0; 287 for i := 0 to MyRO.nUn - 1 do 288 if MyUn[i].Loc = Loc then 289 Inc(Cnt); 290 MakeUnitInfo(me, MyUn[uix], UnitInfo); 291 if Cnt > 1 then 292 UnitInfo.Flags := UnitInfo.Flags or unMulti; 293 end 294 else 295 begin 296 uix := MyRO.nEnemyUn - 1; 297 while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do 298 Dec(uix); 299 UnitInfo := MyRO.EnemyUn[uix]; 300 end; 301 end; { GetUnitInfo } 302 303 procedure GetCityInfo(Loc: integer; var cix: integer; var CityInfo: TCityInfo); 304 begin 305 if MyMap[Loc] and fOwned <> 0 then 306 begin 307 CityInfo.Loc := Loc; 308 cix := MyRO.nCity - 1; 309 while (cix >= 0) and (MyCity[cix].Loc <> Loc) do 310 Dec(cix); 311 with CityInfo do 312 begin 313 Owner := me; 314 ID := MyCity[cix].ID; 315 size := MyCity[cix].size; 316 Flags := 0; 317 if MyCity[cix].Built[imPalace] > 0 then 318 Inc(Flags, ciCapital); 319 if (MyCity[cix].Built[imWalls] > 0) or 320 (MyMap[MyCity[cix].Loc] and fGrWall <> 0) then 321 Inc(Flags, ciWalled); 322 if MyCity[cix].Built[imCoastalFort] > 0 then 323 Inc(Flags, ciCoastalFort); 324 if MyCity[cix].Built[imMissileBat] > 0 then 325 Inc(Flags, ciMissileBat); 326 if MyCity[cix].Built[imBunker] > 0 then 327 Inc(Flags, ciBunker); 328 if MyCity[cix].Built[imSpacePort] > 0 then 329 Inc(Flags, ciSpacePort); 330 end; 331 end 332 else 333 begin 334 cix := MyRO.nEnemyCity - 1; 335 while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do 336 Dec(cix); 337 CityInfo := MyRO.EnemyCity[cix]; 338 end; 339 end; 340 341 function UnitExhausted(uix: integer): boolean; 342 // check if another move of this unit is still possible 343 var 344 dx, dy: integer; 345 begin 346 Result := True; 347 if (MyUn[uix].Movement > 0) or 348 (MyRO.Wonder[woShinkansen].EffectiveOwner = me) then 349 if (MyUn[uix].Movement >= 100) or 350 ((MyModel[MyUn[uix].mix].Kind = mkCaravan) and 351 (MyMap[MyUn[uix].Loc] and fCity <> 0)) then 352 Result := False 137 353 else 138 MinEndHealth := 1 139 end; 140 until false end; 141 142 function ColorOfHealth(Health: integer): integer; 143 var 144 red, green: integer; 145 begin 146 green := 400 * Health div 100; 147 if green > 200 then 148 green := 200; 149 red := 510 * (100 - Health) div 100; 150 if red > 255 then 151 red := 255; 152 result := green shl 8 + red 153 end; 154 155 function IsMultiPlayerGame: boolean; 156 var 157 p1: integer; 158 begin 159 result := false; 160 for p1 := 1 to nPl - 1 do 161 if G.RO[p1] <> nil then 162 result := true; 163 end; 164 165 procedure ItsMeAgain(p: integer); 166 begin 167 if G.RO[p] <> nil then 168 MyRO := pointer(G.RO[p]) 169 else if G.SuperVisorRO[p] <> nil then 170 MyRO := pointer(G.SuperVisorRO[p]) 171 else 172 exit; 173 me := p; 174 MyMap := pointer(MyRO.Map); 175 MyUn := pointer(MyRO.Un); 176 MyCity := pointer(MyRO.City); 177 MyModel := pointer(MyRO.Model); 178 end; 179 180 function GetAge(p: integer): integer; 181 var 182 i: integer; 183 begin 184 if p = me then 185 begin 186 result := 0; 187 for i := 1 to 3 do 188 if MyRO.Tech[AgePreq[i]] >= tsApplicable then 189 result := i; 190 end 354 for dx := -2 to 2 do 355 for dy := -2 to 2 do 356 if abs(dx) + abs(dy) = 2 then 357 if Server(sMoveUnit - sExecute + dx and 7 shl 4 + dy and 358 7 shl 7, me, uix, nil^) >= rExecuted then 359 Result := False; 360 end; 361 362 function ModelHash(const ModelInfo: TModelInfo): integer; 363 var 364 i, FeatureCode, Hash1, Hash2, Hash2r, d: cardinal; 365 begin 366 with ModelInfo do 367 if Kind > mkEnemyDeveloped then 368 Result := integer($C0000000 + Speed div 50 + Kind shl 8) 191 369 else 192 370 begin 193 result := 0; 194 for i := 1 to 3 do 195 if MyRO.EnemyReport[p].Tech[AgePreq[i]] >= tsApplicable then 196 result := i; 197 end 198 end; 199 200 function IsCivilReportNew(Enemy: integer): boolean; 201 var 202 i: integer; 203 begin 204 assert(Enemy <> me); 205 i := MyRO.EnemyReport[Enemy].TurnOfCivilReport; 206 result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me); 207 end; 208 209 function IsMilReportNew(Enemy: integer): boolean; 210 var 211 i: integer; 212 begin 213 assert(Enemy <> me); 214 i := MyRO.EnemyReport[Enemy].TurnOfMilReport; 215 result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me); 216 end; 217 218 function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean; 219 gov, size: integer): integer; 220 begin 221 result := FoodSurplus; 222 if not IsCityAlive or (result > 0) and 223 ((gov = gFuture) or (size >= NeedAqueductSize) and (result < 2)) then 224 result := 0; { no growth } 225 end; 226 227 function CityTaxBalance(cix: integer; 228 const CityReport: TCityReportNew): integer; 229 var 230 i: integer; 231 begin 232 result := 0; 233 if (CityReport.HappinessBalance >= 0) { no disorder } 234 and (MyCity[cix].Flags and chCaptured = 0) then // not captured 235 begin 236 inc(result, CityReport.Tax); 237 if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) and 238 (CityReport.Production > 0) then 239 inc(result, CityReport.Production); 240 if ((MyRO.Government = gFuture) or (MyCity[cix].size >= NeedAqueductSize) 241 and (CityReport.FoodSurplus < 2)) and (CityReport.FoodSurplus > 0) then 242 inc(result, CityReport.FoodSurplus); 371 FeatureCode := 0; 372 for i := mcFirstNonCap to nFeature - 1 do 373 if 1 shl Domain and Feature[i].Domains <> 0 then 374 begin 375 FeatureCode := FeatureCode * 2; 376 if 1 shl (i - mcFirstNonCap) <> 0 then 377 Inc(FeatureCode); 378 end; 379 case Domain of 380 dGround: 381 begin 382 assert(FeatureCode < 1 shl 8); 383 assert(Attack < 5113); 384 assert(Defense < 2273); 385 assert(Cost < 1611); 386 Hash1 := (Attack * 2273 + Defense) * 9 + (Speed - 150) div 50; 387 Hash2 := FeatureCode * 1611 + Cost; 388 end; 389 dSea: 390 begin 391 assert(FeatureCode < 1 shl 9); 392 assert(Attack < 12193); 393 assert(Defense < 6097); 394 assert(Cost < 4381); 395 Hash1 := ((Attack * 6097 + Defense) * 5 + 396 (Speed - 350) div 100) * 2; 397 if Weight >= 6 then 398 Inc(Hash1); 399 Hash2 := ((TTrans * 17 + ATrans_Fuel) shl 9 + FeatureCode) * 400 4381 + Cost; 401 end; 402 dAir: 403 begin 404 assert(FeatureCode < 1 shl 5); 405 assert(Attack < 2407); 406 assert(Defense < 1605); 407 assert(Bombs < 4813); 408 assert(Cost < 2089); 409 Hash1 := (Attack * 1605 + Defense) shl 5 + FeatureCode; 410 Hash2 := ((Bombs * 7 + ATrans_Fuel) * 4 + TTrans) * 2089 + Cost; 411 end; 412 end; 413 Hash2r := 0; 414 for i := 0 to 7 do 415 begin 416 Hash2r := Hash2r * 13; 417 d := Hash2 div 13; 418 Inc(Hash2r, Hash2 - d * 13); 419 Hash2 := d; 420 end; 421 Result := integer(Domain shl 30 + Hash1 xor Hash2r); 243 422 end; 244 for i := 28 to nImp - 1 do 245 if MyCity[cix].Built[i] > 0 then 246 dec(result, Imp[i].Maint); 247 end; 248 249 procedure SumCities(var TaxSum, ScienceSum: integer); 250 var 251 cix: integer; 252 CityReport: TCityReportNew; 253 begin 254 TaxSum := MyRO.OracleIncome; 255 ScienceSum := 0; 256 if MyRO.Government = gAnarchy then 257 exit; 258 for cix := 0 to MyRO.nCity - 1 do 259 if MyCity[cix].Loc >= 0 then 260 begin 261 CityReport.HypoTiles := -1; 262 CityReport.HypoTaxRate := -1; 263 CityReport.HypoLuxuryRate := -1; 264 Server(sGetCityReportNew, me, cix, CityReport); 265 if (CityReport.HappinessBalance >= 0) { no disorder } 266 and (MyCity[cix].Flags and chCaptured = 0) then // not captured 267 ScienceSum := ScienceSum + CityReport.Science; 268 TaxSum := TaxSum + CityTaxBalance(cix, CityReport); 269 end; 270 end; 271 272 function JobTest(uix, Job: integer; IgnoreResults: JobResultSet): boolean; 273 var 274 Test: integer; 275 begin 276 Test := Server(sStartJob + Job shl 4 - sExecute, me, uix, nil^); 277 result := (Test >= rExecuted) or (Test in IgnoreResults); 278 end; 279 280 procedure GetUnitInfo(Loc: integer; var uix: integer; 281 var UnitInfo: TUnitInfo); 282 var 283 i, Cnt: integer; 284 begin 285 if MyMap[Loc] and fOwned <> 0 then 286 begin 287 Server(sGetDefender, me, Loc, uix); 288 Cnt := 0; 289 for i := 0 to MyRO.nUn - 1 do 290 if MyUn[i].Loc = Loc then 291 inc(Cnt); 292 MakeUnitInfo(me, MyUn[uix], UnitInfo); 293 if Cnt > 1 then 294 UnitInfo.Flags := UnitInfo.Flags or unMulti; 295 end 296 else 297 begin 298 uix := MyRO.nEnemyUn - 1; 299 while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do 300 dec(uix); 301 UnitInfo := MyRO.EnemyUn[uix]; 302 end 303 end; { GetUnitInfo } 304 305 procedure GetCityInfo(Loc: integer; var cix: integer; 306 var CityInfo: TCityInfo); 307 begin 308 if MyMap[Loc] and fOwned <> 0 then 309 begin 310 CityInfo.Loc := Loc; 311 cix := MyRO.nCity - 1; 312 while (cix >= 0) and (MyCity[cix].Loc <> Loc) do 313 dec(cix); 314 with CityInfo do 315 begin 316 Owner := me; 317 ID := MyCity[cix].ID; 318 size := MyCity[cix].size; 319 Flags := 0; 320 if MyCity[cix].Built[imPalace] > 0 then 321 inc(Flags, ciCapital); 322 if (MyCity[cix].Built[imWalls] > 0) or 323 (MyMap[MyCity[cix].Loc] and fGrWall <> 0) then 324 inc(Flags, ciWalled); 325 if MyCity[cix].Built[imCoastalFort] > 0 then 326 inc(Flags, ciCoastalFort); 327 if MyCity[cix].Built[imMissileBat] > 0 then 328 inc(Flags, ciMissileBat); 329 if MyCity[cix].Built[imBunker] > 0 then 330 inc(Flags, ciBunker); 331 if MyCity[cix].Built[imSpacePort] > 0 then 332 inc(Flags, ciSpacePort); 333 end 334 end 335 else 336 begin 337 cix := MyRO.nEnemyCity - 1; 338 while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do 339 dec(cix); 340 CityInfo := MyRO.EnemyCity[cix]; 341 end 342 end; 343 344 function UnitExhausted(uix: integer): boolean; 345 // check if another move of this unit is still possible 346 var 347 dx, dy: integer; 348 begin 349 result := true; 350 if (MyUn[uix].Movement > 0) or 351 (MyRO.Wonder[woShinkansen].EffectiveOwner = me) then 352 if (MyUn[uix].Movement >= 100) or 353 ((MyModel[MyUn[uix].mix].Kind = mkCaravan) and 354 (MyMap[MyUn[uix].Loc] and fCity <> 0)) then 355 result := false 356 else 357 for dx := -2 to 2 do 358 for dy := -2 to 2 do 359 if abs(dx) + abs(dy) = 2 then 360 if Server(sMoveUnit - sExecute + dx and 7 shl 4 + dy and 7 shl 7, 361 me, uix, nil^) >= rExecuted then 362 result := false; 363 end; 364 365 function ModelHash(const ModelInfo: TModelInfo): integer; 366 var 367 i, FeatureCode, Hash1, Hash2, Hash2r, d: cardinal; 368 begin 369 with ModelInfo do 370 if Kind > mkEnemyDeveloped then 371 result := integer($C0000000 + Speed div 50 + Kind shl 8) 372 else 373 begin 374 FeatureCode := 0; 375 for i := mcFirstNonCap to nFeature - 1 do 376 if 1 shl Domain and Feature[i].Domains <> 0 then 377 begin 378 FeatureCode := FeatureCode * 2; 379 if 1 shl (i - mcFirstNonCap) <> 0 then 380 inc(FeatureCode); 381 end; 382 case Domain of 383 dGround: 384 begin 385 assert(FeatureCode < 1 shl 8); 386 assert(Attack < 5113); 387 assert(Defense < 2273); 388 assert(Cost < 1611); 389 Hash1 := (Attack * 2273 + Defense) * 9 + (Speed - 150) div 50; 390 Hash2 := FeatureCode * 1611 + Cost; 391 end; 392 dSea: 393 begin 394 assert(FeatureCode < 1 shl 9); 395 assert(Attack < 12193); 396 assert(Defense < 6097); 397 assert(Cost < 4381); 398 Hash1 := ((Attack * 6097 + Defense) * 5 + (Speed - 350) 399 div 100) * 2; 400 if Weight >= 6 then 401 inc(Hash1); 402 Hash2 := ((TTrans * 17 + ATrans_Fuel) shl 9 + FeatureCode) * 403 4381 + Cost; 404 end; 405 dAir: 406 begin 407 assert(FeatureCode < 1 shl 5); 408 assert(Attack < 2407); 409 assert(Defense < 1605); 410 assert(Bombs < 4813); 411 assert(Cost < 2089); 412 Hash1 := (Attack * 1605 + Defense) shl 5 + FeatureCode; 413 Hash2 := ((Bombs * 7 + ATrans_Fuel) * 4 + TTrans) * 2089 + Cost; 414 end; 415 end; 416 Hash2r := 0; 417 for i := 0 to 7 do 418 begin 419 Hash2r := Hash2r * 13; 420 d := Hash2 div 13; 421 inc(Hash2r, Hash2 - d * 13); 422 Hash2 := d 423 end; 424 result := integer(Domain shl 30 + Hash1 xor Hash2r) 425 end 426 end; 427 428 function ProcessEnhancement(uix: integer; 429 const Jobs: TEnhancementJobs): integer; 423 end; 424 425 function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer; 430 426 { return values: 431 427 eJobDone - all applicable jobs done 432 428 eOK - enhancement not complete 433 429 eDied - job done and died (thurst) } 434 var 435 stage, NextJob, Tile: integer; 436 Done: Set of jNone .. jPoll; 437 begin 438 Done := []; 439 Tile := MyMap[MyUn[uix].Loc]; 440 if Tile and fRoad <> 0 then 441 include(Done, jRoad); 442 if Tile and fRR <> 0 then 443 include(Done, jRR); 444 if (Tile and fTerImp = tiIrrigation) or (Tile and fTerImp = tiFarm) then 445 include(Done, jIrr); 446 if Tile and fTerImp = tiFarm then 447 include(Done, jFarm); 448 if Tile and fTerImp = tiMine then 449 include(Done, jMine); 450 if Tile and fPoll = 0 then 451 include(Done, jPoll); 452 453 if MyUn[uix].Job = jNone then 454 result := eJobDone 455 else 456 result := eOK; 457 while (result <> eOK) and (result <> eDied) do 430 var 431 stage, NextJob, Tile: integer; 432 Done: set of jNone .. jPoll; 433 begin 434 Done := []; 435 Tile := MyMap[MyUn[uix].Loc]; 436 if Tile and fRoad <> 0 then 437 include(Done, jRoad); 438 if Tile and fRR <> 0 then 439 include(Done, jRR); 440 if (Tile and fTerImp = tiIrrigation) or (Tile and fTerImp = tiFarm) then 441 include(Done, jIrr); 442 if Tile and fTerImp = tiFarm then 443 include(Done, jFarm); 444 if Tile and fTerImp = tiMine then 445 include(Done, jMine); 446 if Tile and fPoll = 0 then 447 include(Done, jPoll); 448 449 if MyUn[uix].Job = jNone then 450 Result := eJobDone 451 else 452 Result := eOK; 453 while (Result <> eOK) and (Result <> eDied) do 454 begin 455 stage := -1; 456 repeat 457 if stage = -1 then 458 NextJob := jPoll 459 else 460 NextJob := Jobs[Tile and fTerrain, stage]; 461 if (NextJob = jNone) or not (NextJob in Done) then 462 Break; 463 Inc(stage); 464 until stage = 5; 465 if (stage = 5) or (NextJob = jNone) then 458 466 begin 459 stage := -1; 460 repeat 461 if stage = -1 then 462 NextJob := jPoll 463 else 464 NextJob := Jobs[Tile and fTerrain, stage]; 465 if (NextJob = jNone) or not(NextJob in Done) then 466 Break; 467 inc(stage); 468 until stage = 5; 469 if (stage = 5) or (NextJob = jNone) then 467 Result := eJobDone; 468 Break; 469 end; // tile enhancement complete 470 Result := Server(sStartJob + NextJob shl 4, me, uix, nil^); 471 include(Done, NextJob); 472 end; 473 end; 474 475 function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean; 476 var 477 i, NewProject: integer; 478 begin 479 Result := False; 480 if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) or 481 (MyCity[cix].Flags and chProduction <> 0) then 482 begin 483 i := 0; 484 repeat 485 while (ImpOrder[i] >= 0) and (MyCity[cix].Built[ImpOrder[i]] > 0) do 486 Inc(i); 487 if ImpOrder[i] < 0 then 488 Break; 489 assert(i < nImp); 490 NewProject := cpImp + ImpOrder[i]; 491 if Server(sSetCityProject, me, cix, NewProject) >= rExecuted then 470 492 begin 471 result := eJobDone; 493 Result := True; 494 CityOptimizer_CityChange(cix); 472 495 Break; 473 end; // tile enhancement complete 474 result := Server(sStartJob + NextJob shl 4, me, uix, nil^); 475 include(Done, NextJob) 496 end; 497 Inc(i); 498 until False; 499 end; 500 end; 501 502 procedure CalculateAdvValues; 503 var 504 i, j: integer; 505 known: array [0 .. nAdv - 1] of integer; 506 507 procedure MarkPreqs(i: integer); 508 begin 509 if known[i] = 0 then 510 begin 511 known[i] := 1; 512 if (i <> adScience) and (i <> adMassProduction) then 513 begin 514 if (AdvPreq[i, 0] >= 0) then 515 MarkPreqs(AdvPreq[i, 0]); 516 if (AdvPreq[i, 1] >= 0) then 517 MarkPreqs(AdvPreq[i, 1]); 518 end; 476 519 end; 477 520 end; 478 521 479 function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean; 480 var 481 i, NewProject: integer; 482 begin 483 result := false; 484 if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) or 485 (MyCity[cix].Flags and chProduction <> 0) then 522 begin 523 FillChar(AdvValue, SizeOf(AdvValue), 0); 524 for i := 0 to nAdv - 1 do 525 begin 526 FillChar(known, SizeOf(known), 0); 527 MarkPreqs(i); 528 for j := 0 to nAdv - 1 do 529 if known[j] > 0 then 530 Inc(AdvValue[i]); 531 if i in FutureTech then 532 Inc(AdvValue[i], 3000) 533 else if known[adMassProduction] > 0 then 534 Inc(AdvValue[i], 2000) 535 else if known[adScience] > 0 then 536 Inc(AdvValue[i], 1000); 537 end; 538 end; 539 540 procedure DebugMessage(Level: integer; Text: string); 541 begin 542 Server(sMessage, me, Level, PChar(Text)^); 543 end; 544 545 function MarkCitiesAround(Loc, cixExcept: integer): boolean; 546 // return whether a city was marked 547 var 548 cix: integer; 549 begin 550 Result := False; 551 for cix := 0 to MyRO.nCity - 1 do 552 if (cix <> cixExcept) and (MyCity[cix].Loc >= 0) and 553 (MyCity[cix].Flags and chCaptured = 0) and 554 (Distance(MyCity[cix].Loc, Loc) <= 5) then 486 555 begin 487 i := 0; 488 repeat 489 while (ImpOrder[i] >= 0) and (MyCity[cix].Built[ImpOrder[i]] > 0) do 490 inc(i); 491 if ImpOrder[i] < 0 then 492 Break; 493 assert(i < nImp); 494 NewProject := cpImp + ImpOrder[i]; 495 if Server(sSetCityProject, me, cix, NewProject) >= rExecuted then 556 CityNeedsOptimize[cix] := True; 557 Result := True; 558 end; 559 end; 560 561 procedure OptimizeCities(CheckOnly: boolean); 562 var 563 cix, fix, dx, dy, Loc1, OptiType: integer; 564 Done: boolean; 565 Advice: TCityTileAdviceData; 566 begin 567 repeat 568 Done := True; 569 for cix := 0 to MyRO.nCity - 1 do 570 if CityNeedsOptimize[cix] then 571 begin 572 OptiType := (MyCity[cix].Status shr 4) and $0F; 573 if OptiType <> 0 then 496 574 begin 497 result := true; 498 CityOptimizer_CityChange(cix); 499 Break; 575 Advice.ResourceWeights := OfferedResourceWeights[OptiType]; 576 Server(sGetCityTileAdvice, me, cix, Advice); 577 if Advice.Tiles <> MyCity[cix].Tiles then 578 if CheckOnly then 579 begin 580 // TODO: What is this assert for? 581 // Need to optimize city tiles but CheckOnly true? 582 //assert(false) 583 end 584 else 585 begin 586 for fix := 1 to 26 do 587 if MyCity[cix].Tiles and not Advice.Tiles and 588 (1 shl fix) <> 0 then 589 begin // tile no longer used by this city -- check using it by another 590 dy := fix shr 2 - 3; 591 dx := fix and 3 shl 1 - 3 + (dy + 3) and 1; 592 Loc1 := dLoc(MyCity[cix].Loc, dx, dy); 593 if MarkCitiesAround(Loc1, cix) then 594 Done := False; 595 end; 596 Server(sSetCityTiles, me, cix, Advice.Tiles); 597 end; 500 598 end; 501 inc(i); 502 until false end end; 503 504 procedure CalculateAdvValues; 505 var 506 i, j: integer; 507 known: array [0 .. nAdv - 1] of integer; 508 509 procedure MarkPreqs(i: integer); 510 begin 511 if known[i] = 0 then 512 begin 513 known[i] := 1; 514 if (i <> adScience) and (i <> adMassProduction) then 515 begin 516 if (AdvPreq[i, 0] >= 0) then 517 MarkPreqs(AdvPreq[i, 0]); 518 if (AdvPreq[i, 1] >= 0) then 519 MarkPreqs(AdvPreq[i, 1]); 520 end 521 end 522 end; 523 599 CityNeedsOptimize[cix] := False; 600 end; 601 until Done; 602 end; 603 604 procedure CityOptimizer_BeginOfTurn; 605 var 606 cix: integer; 607 begin 608 FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false 609 if MyRO.Government <> gAnarchy then 610 begin 611 for cix := 0 to MyRO.nCity - 1 do 612 if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0) 613 then 614 CityNeedsOptimize[cix] := True; 615 OptimizeCities(False); // optimize all cities 616 end; 617 end; 618 619 procedure CityOptimizer_CityChange(cix: integer); 620 begin 621 if (MyRO.Government <> gAnarchy) and (MyCity[cix].Flags and 622 chCaptured = 0) then 623 begin 624 CityNeedsOptimize[cix] := True; 625 OptimizeCities(False); 626 end; 627 end; 628 629 procedure CityOptimizer_TileBecomesAvailable(Loc: integer); 630 begin 631 if (MyRO.Government <> gAnarchy) and MarkCitiesAround(Loc, -1) then 632 OptimizeCities(False); 633 end; 634 635 procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer); 636 var 637 fix, dx, dy, Loc1: integer; 638 Done: boolean; 639 begin 640 if (MyRO.Government <> gAnarchy) and (ReleasedTiles <> 0) then 641 begin 642 Done := True; 643 for fix := 1 to 26 do 644 if ReleasedTiles and (1 shl fix) <> 0 then 524 645 begin 525 FillChar(AdvValue, SizeOf(AdvValue), 0); 526 for i := 0 to nAdv - 1 do 527 begin 528 FillChar(known, SizeOf(known), 0); 529 MarkPreqs(i); 530 for j := 0 to nAdv - 1 do 531 if known[j] > 0 then 532 inc(AdvValue[i]); 533 if i in FutureTech then 534 inc(AdvValue[i], 3000) 535 else if known[adMassProduction] > 0 then 536 inc(AdvValue[i], 2000) 537 else if known[adScience] > 0 then 538 inc(AdvValue[i], 1000) 539 end; 646 dy := fix shr 2 - 3; 647 dx := fix and 3 shl 1 - 3 + (dy + 3) and 1; 648 Loc1 := dLoc(MyCity[cix].Loc, dx, dy); 649 if MarkCitiesAround(Loc1, cix) then 650 Done := False; 540 651 end; 541 542 procedure DebugMessage(Level: integer; Text: string); 543 begin 544 Server(sMessage, me, Level, pchar(Text)^) 545 end; 546 547 function MarkCitiesAround(Loc, cixExcept: integer): boolean; 548 // return whether a city was marked 549 var 550 cix: integer; 551 begin 552 result := false; 553 for cix := 0 to MyRO.nCity - 1 do 554 if (cix <> cixExcept) and (MyCity[cix].Loc >= 0) and 555 (MyCity[cix].Flags and chCaptured = 0) and 556 (Distance(MyCity[cix].Loc, Loc) <= 5) then 557 begin 558 CityNeedsOptimize[cix] := true; 559 result := true; 560 end 561 end; 562 563 procedure OptimizeCities(CheckOnly: boolean); 564 var 565 cix, fix, dx, dy, Loc1, OptiType: integer; 566 Done: boolean; 567 Advice: TCityTileAdviceData; 568 begin 569 repeat 570 Done := true; 571 for cix := 0 to MyRO.nCity - 1 do 572 if CityNeedsOptimize[cix] then begin 573 OptiType := (MyCity[cix].Status shr 4) and $0F; 574 if OptiType <> 0 then begin 575 Advice.ResourceWeights := OfferedResourceWeights[OptiType]; 576 Server(sGetCityTileAdvice, me, cix, Advice); 577 if Advice.Tiles <> MyCity[cix].Tiles then 578 if CheckOnly then begin 579 // TODO: What is this assert for? 580 // Need to optimize city tiles but CheckOnly true? 581 //assert(false) 582 end else begin 583 for fix := 1 to 26 do 584 if MyCity[cix].Tiles and not Advice.Tiles and 585 (1 shl fix) <> 0 then 586 begin // tile no longer used by this city -- check using it by another 587 dy := fix shr 2 - 3; 588 dx := fix and 3 shl 1 - 3 + (dy + 3) and 1; 589 Loc1 := dLoc(MyCity[cix].Loc, dx, dy); 590 if MarkCitiesAround(Loc1, cix) then 591 Done := false; 592 end; 593 Server(sSetCityTiles, me, cix, Advice.Tiles); 594 end; 595 end; 596 CityNeedsOptimize[cix] := false; 597 end; 598 until Done; 599 end; 600 601 procedure CityOptimizer_BeginOfTurn; 602 var 603 cix: integer; 604 begin 605 FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false 606 if MyRO.Government <> gAnarchy then 607 begin 608 for cix := 0 to MyRO.nCity - 1 do 609 if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0) 610 then 611 CityNeedsOptimize[cix] := true; 612 OptimizeCities(false); // optimize all cities 613 end 614 end; 615 616 procedure CityOptimizer_CityChange(cix: integer); 617 begin 618 if (MyRO.Government <> gAnarchy) and 619 (MyCity[cix].Flags and chCaptured = 0) then 620 begin 621 CityNeedsOptimize[cix] := true; 622 OptimizeCities(false); 623 end 624 end; 625 626 procedure CityOptimizer_TileBecomesAvailable(Loc: integer); 627 begin 628 if (MyRO.Government <> gAnarchy) and MarkCitiesAround(Loc, -1) then 629 OptimizeCities(false); 630 end; 631 632 procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer); 633 var 634 fix, dx, dy, Loc1: integer; 635 Done: boolean; 636 begin 637 if (MyRO.Government <> gAnarchy) and (ReleasedTiles <> 0) then 638 begin 639 Done := true; 640 for fix := 1 to 26 do 641 if ReleasedTiles and (1 shl fix) <> 0 then 642 begin 643 dy := fix shr 2 - 3; 644 dx := fix and 3 shl 1 - 3 + (dy + 3) and 1; 645 Loc1 := dLoc(MyCity[cix].Loc, dx, dy); 646 if MarkCitiesAround(Loc1, cix) then 647 Done := false; 648 end; 649 if not Done then 650 OptimizeCities(false); 651 end 652 end; 653 654 procedure CityOptimizer_BeforeRemoveUnit(uix: integer); 655 var 656 uix1: integer; 657 begin 658 if MyRO.Government <> gAnarchy then 659 begin 660 if MyUn[uix].Home >= 0 then 661 CityNeedsOptimize[MyUn[uix].Home] := true; 662 663 // transported units are also removed 664 for uix1 := 0 to MyRO.nUn - 1 do 665 if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) and 666 (MyUn[uix1].Home >= 0) then 667 CityNeedsOptimize[MyUn[uix1].Home] := true; 668 end 669 end; 670 671 procedure CityOptimizer_AfterRemoveUnit; 672 begin 673 if MyRO.Government <> gAnarchy then 674 OptimizeCities(false); 675 end; 676 677 procedure CityOptimizer_EndOfTurn; 678 // all cities should already be optimized here -- only check this 679 var 680 cix: integer; 681 begin 652 if not Done then 653 OptimizeCities(False); 654 end; 655 end; 656 657 procedure CityOptimizer_BeforeRemoveUnit(uix: integer); 658 var 659 uix1: integer; 660 begin 661 if MyRO.Government <> gAnarchy then 662 begin 663 if MyUn[uix].Home >= 0 then 664 CityNeedsOptimize[MyUn[uix].Home] := True; 665 666 // transported units are also removed 667 for uix1 := 0 to MyRO.nUn - 1 do 668 if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) and 669 (MyUn[uix1].Home >= 0) then 670 CityNeedsOptimize[MyUn[uix1].Home] := True; 671 end; 672 end; 673 674 procedure CityOptimizer_AfterRemoveUnit; 675 begin 676 if MyRO.Government <> gAnarchy then 677 OptimizeCities(False); 678 end; 679 680 procedure CityOptimizer_EndOfTurn; 681 // all cities should already be optimized here -- only check this 682 var 683 cix: integer; 684 begin 682 685 {$IFOPT O-} 683 684 685 686 687 688 689 CityNeedsOptimize[cix] := true;690 OptimizeCities(true); // check all cities691 686 if MyRO.Government <> gAnarchy then 687 begin 688 FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false 689 for cix := 0 to MyRO.nCity - 1 do 690 if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0) 691 then 692 CityNeedsOptimize[cix] := True; 693 OptimizeCities(True); // check all cities 694 end; 692 695 {$ENDIF} 693 696 end; 694 697 695 698 initialization 696 699 697 Assert(nImp < 128);698 CalculateAdvValues;700 Assert(nImp < 128); 701 CalculateAdvValues; 699 702 700 703 end.
Note:
See TracChangeset
for help on using the changeset viewer.