Changeset 160 for trunk/AI/StdAI/AI.pas
- Timestamp:
- Mar 6, 2019, 8:10:23 AM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/AI/StdAI/AI.pas
r124 r160 1 1 {$INCLUDE Switches.inc} 2 {//$DEFINE PERF} 2 3 unit AI; 3 4 … … 5 6 6 7 uses 7 {$IFDEF DEBUG}SysUtils, {$ENDIF} // necessary for debug exceptions 8 Protocol, CustomAI, ToolAI; 8 {$IFDEF DEBUG}SysUtils,Names,{$ENDIF} // necessary for debug exceptions 9 {$IFDEF PERF}SysUtils,Windows,{$ENDIF} // necessary for performance measurement 10 Protocol, CustomAI, ToolAI, Barbarina; 11 12 13 const 14 WaitAfterReject=20; // don't try to contact this number of turn after contact was rejected 15 MinCityFood=3; 16 LeaveDespotism=80; // stay in despotism until this turn 17 TechReportOutdated=30; 18 MilProdShare=50; // minimum share of total production to specialize in military production 19 20 FutureTech=[futResearchTechnology,futProductionTechnology,futArmorTechnology, 21 futMissileTechnology]; 22 23 nResearchOrder=46; 24 ResearchOrder: array[0..1,0..nResearchOrder-1] of integer= 25 ((adWheel,adWarriorCode,adHorsebackRiding,adCeremonialBurial,adPolytheism, 26 adMonarchy,adMysticism,adPoetry,adAstronomy,adMonotheism, 27 adTheology,adChivalry,adPottery,adMedicine,adGunpowder,adChemistry, 28 adExplosives,adUniversity,adTactics,adSeafaring,adNavigation,adRefining,adCombustionEngine, 29 adAutomobile,adPhysics,adMagnetism,adElectricity,adRefrigeration, 30 adRadioCommunication,adTheoryOfGravity,adAtomicTheory,adElectronics, 31 adMassProduction,adPlastics,adFlight,adEnvironmentalism, 32 adSanitation,adMin,adComputers,adRecycling,adSyntheticFood, 33 adSelfContainedEnvironment,adNuclearFission,adNuclearPower,adTheLaser, 34 adIntelligenArms), 35 (adWheel,adWarriorCode,adHorsebackRiding,adAlphabet,adMapMaking,adBronzeWorking,adWriting, 36 adCodeOfLaws,adCurrency,adTrade,adLiterature,adTheRepublic,adMathematics, 37 adPhilosophy,adScience,adMasonry,adConstruction,adEngineering,adInvention, 38 adIronWorking,adBridgeBuilding,adSteamEngine,adRailroad,adSteel, 39 adBanking,adIndustrialization,adConscription,adDemocracy,adEconomics, 40 adTheCorporation,adMassProduction,adRobotics,adCommunism,adMetallurgy, 41 adBallistics,adMobileWarfare,adAmphibiousWarfare,adMin,adComputers,adRocketry,adAdvancedRocketry, 42 adAdvancedFlight,adSpaceFlight,adComposites,adIntelligence,adCombinedArms)); 43 44 LeaveOutTechs=[adPolytheism,adMysticism,adInvention,adEconomics,adPottery, 45 adMedicine,adEnvironmentalism,adRefining,adTrade,adLiterature,adMathematics, 46 adPhilosophy,adChemistry,adConscription,adCombustionEngine,adPhysics, 47 adTheoryOfGravity,adAtomicTheory,adSyntheticFood,adNuclearFission]; 48 49 TechValue_ForResearch_LeaveOut=$700; 50 TechValue_ForResearch_Urgent=$600; 51 TechValue_ForResearch_Next=$400; 52 TechValue_ForResearch=$FF; 53 ForceNeeded_NoLeaveOut=20; // advancedness behind to state-of-art 54 ForceNeeded_LeaveOut=30; // advancedness behind of state-of-art 55 Compromise=6; 56 57 // basic strategies 58 bGender=$0001; 59 bMale=$0000; 60 bFemale=$0001; 61 bBarbarina=$0006; 62 bBarbarina_Hide=$0002; 63 64 // model categories 65 nModelCat=4; 66 mctNone=-1; mctGroundDefender=0; mctGroundAttacker=1; mctTransport=2; mctCruiser=3; 67 68 // mil research 69 BetterQuality: array[0..nModelCat-1] of integer=(50,50,80,80); 70 MaxBuildWorseThanBestModel=20; MaxExistWorseThanBestModel=50; 71 72 maxCOD=256; 73 PresenceUnknown=$10000; 74 75 nRequestedTechs=48; 76 77 PlayerHash: array[0..nPl-1] of integer=(7,6,0,2,10,8,12,14,4,1,3,5,9,11,13); 9 78 10 79 type 11 UnitRole = (Roam, Defend); 12 13 TAI = class(TToolAI) 14 constructor Create(Nation: integer); override; 15 16 protected 17 procedure DoTurn; override; 18 procedure DoNegotiation; override; 19 function ChooseResearchAdvance: integer; override; 20 function ChooseGovernment: integer; override; 21 function WantNegotiation(Nation: integer; NegoTime: TNegoTime) 22 : boolean; override; 23 24 procedure ProcessSettlers; 25 procedure ProcessUnit(uix: integer; Role: UnitRole); 26 procedure SetCityProduction; 27 end; 80 Suggestion=(suContact, suPeace, suFriendly); 81 82 TPersistentData=record 83 LastResearchTech, BehaviorFlags, TheologyPartner: integer; 84 RejectTurn: array[Suggestion,0..15] of smallint; 85 RequestedTechs: array[0..nRequestedTechs-1] of integer; 86 // ad + p shl 8 + Turn shl 16 87 end; 88 89 TAI = class(TBarbarina) 90 constructor Create(Nation: integer); override; 91 92 procedure SetDataDefaults; override; 93 94 protected 95 Data: ^TPersistentData; 96 WarNations, BombardingNations, mixSettlers, mixCaravan, mixTownGuard, 97 mixSlaves, mixMilitia, mixCruiser, OceanWithShip: integer; 98 NegoCause: (Routine,CheckBarbarina); 99 SettlerSurplus: array[0..maxCOD-1] of integer; 100 uixPatrol: array[0..maxCOD-1] of integer; 101 102 ContinentPresence: array[0..maxCOD-1] of integer; 103 OceanPresence: array[0..maxCOD-1] of integer; 104 UnitLack: array[0..maxCOD-1,mctGroundDefender..mctGroundAttacker] of integer; 105 106 TotalPopulation: array[0..nPl-1] of integer; 107 ContinentPopulation: array[0..nPl-1,0..maxCOD-1] of integer; 108 // 1 means enemy territory spotted but no city 109 DistrictPopulation: array[0..maxCOD-1] of integer; 110 111 ModelCat: array[0..nMmax-1] of integer; 112 ModelQuality: array[0..nMmax-1] of integer; 113 ModelBestQuality: array[0..nModelCat-1] of integer; 114 115 AdvanceValue: array[0..nAdv-1] of integer; 116 AdvanceValuesSet: boolean; 117 118 procedure DoTurn; override; 119 procedure DoNegotiation; override; 120 function ChooseResearchAdvance: integer; override; 121 function ChooseStealAdvance: integer; override; 122 function ChooseGovernment: integer; override; 123 function WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean; override; 124 function OnNegoRejected_CancelTreaty: boolean; override; 125 126 procedure FindBestTrade(Nation: integer; var adWanted, adGiveAway: integer); 127 procedure CheckGender; 128 procedure AnalyzeMap; 129 procedure CollectModelCatStat; 130 procedure AttackAndPatrol; 131 procedure MoveUnitsHome; 132 procedure CheckAttack(uix: integer); 133 procedure Patrol(uix: integer); 134 procedure SetCityProduction; 135 procedure SetAdvanceValues; 136 function HavePort: boolean; 137 {$IFDEF DEBUG}procedure TraceAdvanceValues(Nation: integer);{$ENDIF} 138 139 // research 140 procedure RateModel(const mi: TModelInfo; var Category, Quality: integer); 141 procedure RateMyModel(mix: integer; var Category, Quality: integer); 142 function IsBetterModel(const mi: TModelInfo): boolean; 143 144 //terraforming 145 procedure TileWorkPlan(Loc, cix: integer; 146 var Value, NextJob, TotalWork: integer); 147 procedure ProcessSettlers; 148 149 // diplomacy 150 function MostWanted(Nation, adGiveAway: integer): integer; 151 152 end; 153 28 154 29 155 implementation 30 156 31 157 uses 32 158 Pile; 33 159 34 160 const 35 // fine adjustment 36 Aggressive = 40; // 0 = never attacks, 100 = attacks even with heavy losses 37 DestroyBonus = 30; // percent of building cost 161 // fine adjustment 162 Aggressive=40; // 0 = never attacks, 100 = attacks even with heavy losses 163 DestroyBonus=30; // percent of building cost 164 165 var 166 LeaveOutValue: array[0..nAdv-1] of integer; 167 38 168 39 169 constructor TAI.Create(Nation: integer); 40 170 begin 41 inherited; 171 inherited; 172 Data:=pointer(RO.Data); 173 {$IFDEF DEBUG}if Nation=1 then SetDebugMap(DebugMap);{$ENDIF} 174 AdvanceValuesSet:=false; 42 175 end; 43 176 44 45 // ------------------------------- 46 // MY TURN 47 // ------------------------------- 48 49 procedure TAI.DoTurn; 177 procedure TAI.SetDataDefaults; 178 begin 179 with Data^ do 180 begin 181 LastResearchTech:=-1; 182 if PlayerHash[me]>7 then BehaviorFlags:=bFemale else BehaviorFlags:=bMale; 183 DebugMessage(1, 'Gender:='+char(48+BehaviorFlags and bGender)); 184 TheologyPartner:=-1; 185 fillchar(RejectTurn,sizeof(RejectTurn),$FF); 186 Fillchar(RequestedTechs, sizeof(RequestedTechs), $FF); 187 end 188 end; 189 190 function TAI.OnNegoRejected_CancelTreaty: boolean; 191 begin 192 Data.RejectTurn[suContact,Opponent]:=RO.Turn; 193 result:= Data.BehaviorFlags and bBarbarina<>0; 194 end; 195 196 197 //------------------------------- 198 // RESEARCH 199 //------------------------------- 200 201 procedure TAI.RateModel(const mi: TModelInfo; var Category, Quality: integer); 50 202 var 51 uix: integer;203 EffectiveTransport: integer; 52 204 begin 53 // correct tax rate if necessary 54 if RO.Money > RO.nCity * 16 then 55 ChangeRates(RO.TaxRate - 10, 0) 56 else if RO.Money < RO.nCity * 8 then 57 ChangeRates(RO.TaxRate + 10, 0); 58 59 // better government form available? 60 if RO.Government <> gAnarchy then 61 if IsResearched(adTheRepublic) then 62 begin 63 if RO.Government <> gRepublic then 64 Revolution 205 if mi.Kind>=mkScout then 206 begin Category:=mctNone; exit end; 207 case mi.Domain of 208 dGround: 209 if mi.Speed>=250 then 210 begin 211 Category:=mctGroundAttacker; 212 if mi.Attack=0 then Quality:=0 213 else 214 begin 215 Quality:=trunc(100*(ln(mi.Attack)+ln(mi.Defense)+ln(mi.Speed/150)*1.7-ln(mi.Cost))); 216 if mi.Cap and (1 shl (mcFanatic-mcFirstNonCap))<>0 then 217 inc(Quality,trunc(100*ln(1.5))); 218 if mi.Cap and (1 shl (mcLongRange-mcFirstNonCap))<>0 then 219 inc(Quality,trunc(100*ln(1.5))); 220 end 221 end 222 else 223 begin 224 Category:=mctGroundDefender; 225 Quality:=trunc(100*(ln(mi.Defense)-ln(mi.Cost)*0.6)); 226 if mi.Cap and (1 shl (mcFanatic-mcFirstNonCap))<>0 then 227 inc(Quality,trunc(100*ln(1.5))); 228 end; 229 dSea: 230 if mi.Attack=0 then 231 begin 232 Category:=mctTransport; 233 if mi.TTrans=0 then Quality:=0 234 else 235 begin 236 EffectiveTransport:=mi.TTrans; 237 if EffectiveTransport>4 then EffectiveTransport:=4; // rarely used more 238 Quality:=100+trunc(100*(ln(EffectiveTransport)+ln(mi.Speed/150)+ln(mi.Defense)-ln(mi.Cost))); 239 if mi.Cap and (1 shl (mcNav-mcFirstNonCap))<>0 then 240 inc(Quality,trunc(100*ln(1.5))); 241 if mi.Cap and (1 shl (mcAirDef-mcFirstNonCap))<>0 then 242 inc(Quality,trunc(100*ln(1.3))); 243 end 244 end 245 else 246 begin 247 Category:=mctCruiser; 248 if mi.Attack=0 then Quality:=0 249 else 250 begin 251 Quality:=trunc(100*(ln(mi.Attack)+ln(mi.Defense)*0.6-ln(mi.Cost))); 252 if mi.Cap and (1 shl (mcNav-mcFirstNonCap))<>0 then 253 inc(Quality,trunc(100*ln(1.4))); 254 if mi.Cap and (1 shl (mcAirDef-mcFirstNonCap))<>0 then 255 inc(Quality,trunc(100*ln(1.3))); 256 if mi.Cap and (1 shl (mcLongRange-mcFirstNonCap))<>0 then 257 inc(Quality,trunc(100*ln(2.0))); 258 if mi.Cap and (1 shl (mcRadar-mcFirstNonCap))<>0 then 259 inc(Quality,trunc(100*ln(1.5))); 260 end 261 end; 262 dAir: 263 begin 264 Category:=mctNone; 265 Quality:=0 266 end; 267 end; 268 //!!!assert(Quality>0); 269 end; 270 271 procedure TAI.RateMyModel(mix: integer; var Category, Quality: integer); 272 var 273 mi: TModelInfo; 274 begin 275 MakeModelInfo(me,mix,MyModel[mix],mi); 276 RateModel(mi,Category,Quality); 277 end; 278 279 function TAI.IsBetterModel(const mi: TModelInfo): boolean; 280 var 281 mix,Cat,Quality,Cat1,Quality1: integer; 282 begin 283 RateModel(mi,Cat,Quality); 284 for mix:=0 to RO.nModel-1 do if mi.Domain=MyModel[mix].Domain then 285 begin 286 RateMyModel(mix,Cat1,Quality1); 287 if (Cat=Cat1) and (Quality<Quality1+BetterQuality[Cat])then 288 begin result:=false; exit end 289 end; 290 result:=true; 291 end; 292 293 function TAI.ChooseResearchAdvance: integer; 294 var 295 adNext,iad,i,ad,Count,EarliestNeeded,EarliestNeeded_NoLeaveOut, 296 NewResearch,StateOfArt,mix: integer; 297 mi: TModelInfo; 298 Entry: array[0..nAdv-1] of boolean; 299 ok: boolean; 300 301 function MarkEntry(ad: integer): boolean; 302 begin 303 if RO.Tech[ad]>=tsApplicable then 304 result:=false // nothing more to research here 305 else if RO.Tech[ad]=tsSeen then 306 begin 307 Entry[ad]:=true; 308 result:=true 65 309 end 66 else if IsResearched(adMonarchy) then 67 begin 68 if RO.Government <> gMonarchy then 69 Revolution 70 end; 71 72 // do combat 73 for uix := 0 to RO.nUn - 1 do 74 if (MyUnit[uix].Loc >= 0) and not(MyModel[MyUnit[uix].mix].Kind 75 in [mkSettler, mkSlaves]) then 76 ProcessUnit(uix, Roam); 77 78 ProcessSettlers; 79 80 // do discover/patrol 81 82 OptimizeCityTiles; 83 SetCityProduction; 310 else 311 begin 312 Entry[ad]:=true; 313 if ad=adScience then 314 begin 315 if MarkEntry(adTheology) then Entry[ad]:=false; 316 if MarkEntry(adPhilosophy) then Entry[ad]:=false; 317 end 318 else if ad=adMassProduction then 319 begin 320 if MarkEntry(adAutomobile) then Entry[ad]:=false; 321 if Data.BehaviorFlags and bGender=bMale then 322 begin if MarkEntry(adElectronics) then Entry[ad]:=false; end 323 else begin if MarkEntry(adTheCorporation) then Entry[ad]:=false; end 324 end 325 else 326 begin 327 if AdvPreq[ad,0]>=0 then 328 if MarkEntry(AdvPreq[ad,0]) then Entry[ad]:=false; 329 if AdvPreq[ad,1]>=0 then 330 if MarkEntry(AdvPreq[ad,1]) then Entry[ad]:=false; 331 end; 332 result:=true 333 end 334 end; 335 336 procedure OptimizeDevModel(OptimizeCaps: integer); 337 var 338 f,Cat,OriginalCat,Quality,BestQuality,Best: integer; 339 mi: TModelInfo; 340 begin 341 MakeModelInfo(me,0,RO.DevModel,mi); 342 RateModel(mi,OriginalCat,BestQuality); 343 repeat 344 Best:=-1; 345 for f:=0 to nFeature-1 do 346 if (1 shl f and OptimizeCaps<>0) 347 and ((Feature[f].Preq<0) or IsResearched(Feature[f].Preq)) // check prerequisite 348 and (RO.DevModel.Weight+Feature[f].Weight<=RO.DevModel.MaxWeight) 349 and not((f>=mcFirstNonCap) and (RO.DevModel.Cap[f]>0)) then 350 begin 351 if SetNewModelFeature(f,RO.DevModel.Cap[f]+1)>=rExecuted then 352 begin 353 MakeModelInfo(me,0,RO.DevModel,mi); 354 RateModel(mi,Cat,Quality); 355 assert(Cat=OriginalCat); 356 if Quality>BestQuality then 357 begin 358 Best:=f; 359 BestQuality:=Quality; 360 end; 361 SetNewModelFeature(f,RO.DevModel.Cap[f]-1) 362 end 363 end; 364 if Best>=0 then 365 SetNewModelFeature(Best,RO.DevModel.Cap[Best]+1) 366 until Best<0 367 end; 368 369 function LeaveOutsMissing(ad: integer): boolean; 370 var 371 i: integer; 372 begin 373 result:=false; 374 if RO.Tech[ad]<tsSeen then 375 if ad in LeaveOutTechs then result:=true 376 else if ad=adScience then 377 begin 378 result:=result or LeaveOutsMissing(adTheology); 379 result:=result or LeaveOutsMissing(adPhilosophy); 380 end 381 else if ad=adMassProduction then 382 result:=true 383 else for i:=0 to 1 do 384 if AdvPreq[ad,i]>=0 then 385 result:=result or LeaveOutsMissing(AdvPreq[ad,i]); 386 end; 387 388 begin 389 if Data.BehaviorFlags and bBarbarina<>0 then 390 begin 391 result:=Barbarina_ChooseResearchAdvance; 392 if result>=0 then exit 393 end; 394 395 SetAdvanceValues; 396 397 // always complete traded techs first 398 result:=-1; 399 for ad:=0 to nAdv-1 do 400 if (RO.Tech[ad]=tsSeen) 401 and ((result<0) or (AdvanceValue[ad]>AdvanceValue[result])) then 402 result:=ad; 403 if result>=0 then exit; 404 405 if Data.BehaviorFlags and bBarbarina=0 then 406 begin 407 // develop new model? 408 if IsResearched(adWarriorCode) and IsResearched(adHorsebackRiding) 409 and not ((Data.BehaviorFlags and bGender=bMale) and (RO.Tech[adIronWorking]>=tsApplicable) // wait for gunpowder 410 and (RO.Tech[adGunPowder]<tsApplicable)) then 411 begin // check new ground models 412 PrepareNewModel(dGround); 413 SetNewModelFeature(mcDefense,1); 414 SetNewModelFeature(mcOffense,2); 415 SetNewModelFeature(mcMob,2); 416 OptimizeDevModel(1 shl mcOffense+1 shl mcDefense+1 shl mcMob 417 +1 shl mcLongRange+1 shl mcFanatic); 418 MakeModelInfo(me,0,RO.DevModel,mi); 419 if IsBetterModel(mi) then 420 begin result:=adMilitary; exit end; 421 422 PrepareNewModel(dGround); 423 SetNewModelFeature(mcDefense,2); 424 SetNewModelFeature(mcOffense,1); 425 OptimizeDevModel(1 shl mcOffense+1 shl mcDefense+1 shl mcFanatic); 426 MakeModelInfo(me,0,RO.DevModel,mi); 427 if IsBetterModel(mi) then 428 begin result:=adMilitary; exit end; 429 end; 430 431 if IsResearched(adMapMaking) and IsResearched(adSeafaring) 432 and IsResearched(adNavigation) and IsResearched(adSteamEngine) then 433 begin 434 result:=adMilitary; 435 for mix:=0 to RO.nModel-1 do if MyModel[mix].Cap[mcNav]>0 then result:=-1; 436 if result=adMilitary then 437 begin 438 PrepareNewModel(dSea); 439 SetNewModelFeature(mcWeapons,0); 440 SetNewModelFeature(mcDefense,3); 441 exit 442 end 443 end; 444 445 (* 446 if IsResearched(adMapMaking) and IsResearched(adSeafaring) then 447 begin // check new naval models 448 PrepareNewModel(dSea); 449 if RO.DevModel.MTrans>1 then 450 begin // new transport? 451 SetNewModelFeature(mcDefense,2); 452 SetNewModelFeature(mcOffense,2); 453 SetNewModelFeature(mcSeaTrans,1); 454 OptimizeDevModel(1 shl mcDefense+1 shl mcSeaTrans+1 shl mcTurbines 455 +1 shl mcAirDef); 456 MakeModelInfo(me,0,RO.DevModel,mi); 457 if IsBetterModel(mi) then 458 begin result:=adMilitary; exit end; 459 end; 460 461 // new cruiser? 462 if IsResearched(adBallistics) or IsResearched(adGunPowder) then 463 begin 464 PrepareNewModel(dSea); 465 SetNewModelFeature(mcDefense,1); 466 SetNewModelFeature(mcOffense,2); 467 OptimizeDevModel(1 shl mcOffense+1 shl mcDefense 468 +1 shl mcLongRange+1 shl mcAirDef+1 shl mcRadar); 469 MakeModelInfo(me,0,RO.DevModel,mi); 470 if IsBetterModel(mi) then 471 begin result:=adMilitary; exit end; 472 end 473 end; 474 *) 475 end; 476 477 NewResearch:=-1; 478 479 // check if cooperation with other gender doesn't work -- go for old needed techs then 480 StateOfArt:=-1; 481 for ad:=0 to nAdv-1 do 482 if (RO.Tech[ad]>=tsApplicable) and (Advancedness[ad]>StateOfArt) then 483 StateOfArt:=Advancedness[ad]; 484 EarliestNeeded:=-1; 485 EarliestNeeded_NoLeaveOut:=-1; 486 for ad:=0 to nAdv-1 do 487 if (RO.Tech[ad]<tsSeen) and (AdvanceValue[ad]>=$100) 488 and ((EarliestNeeded<0) 489 or (Advancedness[ad]<Advancedness[EarliestNeeded])) then 490 begin 491 ok:=false; 492 for iad:=0 to nResearchOrder-1 do 493 if ResearchOrder[Data.BehaviorFlags and bGender,iad]=ad then 494 begin ok:=true; break; end; 495 if not ok then 496 begin 497 EarliestNeeded:=ad; 498 if not LeaveOutsMissing(ad) then 499 EarliestNeeded_NoLeaveOut:=ad; 500 end 501 end; 502 if EarliestNeeded>=0 then 503 begin 504 if (EarliestNeeded_NoLeaveOut>=0) 505 and (Advancedness[EarliestNeeded_NoLeaveOut]+ForceNeeded_NoLeaveOut<StateOfArt) then 506 begin 507 {$IFDEF DEBUG}DebugMessage(2,'No partner found, go for ' 508 +Name_Advance[EarliestNeeded_NoLeaveOut]);{$ENDIF} 509 NewResearch:=EarliestNeeded_NoLeaveOut 510 end 511 else if Advancedness[EarliestNeeded]+ForceNeeded_LeaveOut<StateOfArt then 512 begin 513 {$IFDEF DEBUG}DebugMessage(2,'No partner found, go for ' 514 +Name_Advance[EarliestNeeded]);{$ENDIF} 515 NewResearch:=EarliestNeeded 516 end 517 end; 518 519 // choose first directly researchable advance from own branch 520 adNext:=-1; 521 if NewResearch<0 then 522 for iad:=0 to nResearchOrder-1 do 523 begin 524 ad:=ResearchOrder[Data.BehaviorFlags and bGender,iad]; 525 if RO.Tech[ad]<tsApplicable then 526 begin 527 if adNext<0 then adNext:=ad; 528 if AdvPreq[ad,2]<>preNone then 529 begin // 2 of 3 required 530 count:=0; 531 for i:=0 to 2 do 532 if RO.Tech[AdvPreq[ad,i]]>=tsApplicable then inc(count); 533 if count>=2 then 534 begin result:=ad; exit end 535 end 536 else if ((AdvPreq[ad,0]=preNone) or (RO.Tech[AdvPreq[ad,0]]>=tsApplicable)) 537 and ((AdvPreq[ad,1]=preNone) or (RO.Tech[AdvPreq[ad,1]]>=tsApplicable)) then 538 begin result:=ad; exit end 539 end 540 end; 541 542 if NewResearch<0 then 543 if adNext>=0 then 544 NewResearch:=adNext // need tech from other gender 545 else if EarliestNeeded_NoLeaveOut>=0 then 546 NewResearch:=EarliestNeeded_NoLeaveOut // own branch complete, pick tech from other gender 547 else if EarliestNeeded>=0 then 548 NewResearch:=EarliestNeeded // own branch complete, pick tech from other gender 549 else 550 begin // go for future techs 551 result:=-1; 552 i:=0; 553 for ad:=nAdv-4 to nAdv-1 do 554 if (RO.Tech[ad]<MaxFutureTech) and (RO.Tech[AdvPreq[ad,0]]>=tsApplicable) then 555 begin 556 inc(i); 557 if random(i)=0 then result:=ad 558 end; 559 assert((result<0) or AdvanceResearchable(result)); 560 exit; 561 end; 562 563 assert(NewResearch>=0); 564 fillchar(Entry, sizeof(Entry), false); 565 MarkEntry(NewResearch); 566 result:=-1; 567 for ad:=0 to nAdv-1 do 568 if Entry[ad] 569 and ((result<0) or (Advancedness[ad]>Advancedness[result])) then 570 result:=ad; 571 assert(result>=0); 572 end; 573 574 function TAI.ChooseStealAdvance: integer; 575 var 576 ad: integer; 577 begin 578 result:=-1; 579 for ad:=0 to nAdv-1 do 580 if AdvanceStealable(ad) 581 and ((result<0) or (Advancedness[ad]>Advancedness[result])) then 582 result:=ad 583 end; 584 585 586 //------------------------------- 587 // TERRAFORMING 588 //------------------------------- 589 590 const 591 twpAllowFarmland=$0001; 592 593 procedure TAI.TileWorkPlan(Loc, cix: integer; 594 var Value, NextJob, TotalWork: integer); 595 var 596 OldTile,TerrType: Cardinal; 597 TileInfo: TTileInfo; 598 begin 599 TotalWork:=0; 600 NextJob:=jNone; 601 if Map[Loc] and (fRare1 or fRare2)<>0 then 602 begin Value:=3*8-1; exit end; // better than any tile with 2 food 603 604 OldTile:=Map[Loc]; 605 TerrType:=Map[Loc] and fTerrain; 606 if (TerrType>=fGrass) then 607 begin 608 if Map[Loc] and fPoll<>0 then 609 begin // clean pollution 610 if NextJob=jNone then NextJob:=jPoll; 611 inc(TotalWork,PollWork); 612 Map[Loc]:=Map[Loc] and not fPoll; 613 end; 614 if Map[Loc] and (fTerrain or fSpecial)=fSwamp then 615 begin // drain swamp 616 if NextJob=jNone then NextJob:=jClear; 617 inc(TotalWork,Terrain[TerrType].IrrClearWork); 618 Map[Loc]:=Map[Loc] and not fTerrain or fGrass; 619 TerrType:=fGrass; 620 Map[Loc]:=Map[Loc] or 621 Cardinal(SpecialTile(Loc,TerrType,G.lx) shl 5); 622 end 623 else if IsResearched(adExplosives) 624 and (Map[Loc] and (fTerrain or fSpecial) in [fTundra,fHills]) 625 and (Map[Loc] and fTerImp<>tiMine) 626 and (SpecialTile(Loc,fHills,G.lx)=0) then 627 begin // transform 628 if NextJob=jNone then NextJob:=jTrans; 629 inc(TotalWork,Terrain[TerrType].TransWork); 630 Map[Loc]:=Map[Loc] and not fTerrain or fGrass; 631 TerrType:=fGrass; 632 Map[Loc]:=Map[Loc] or 633 Cardinal(SpecialTile(Loc,TerrType,G.lx) shl 5); 634 end; 635 if (Terrain[TerrType].MineEff>0) and (RO.Government<>gDespotism) then 636 begin 637 if Map[Loc] and fTerImp<>tiMine then 638 begin // add mine 639 if NextJob=jNone then NextJob:=jMine; 640 inc(TotalWork,Terrain[TerrType].MineAfforestWork); 641 Map[Loc]:=Map[Loc] and not fTerImp or tiMine; 642 end 643 end 644 else if Terrain[TerrType].IrrEff>0 then 645 begin 646 if Map[Loc] and fTerImp=tiIrrigation then 647 begin // add farmland 648 if (MyCity[cix].Built[imSupermarket]>0) and IsResearched(adRefrigeration) 649 and (RO.Government<>gDespotism) then 650 begin 651 if NextJob=jNone then NextJob:=jFarm; 652 inc(TotalWork,Terrain[TerrType].IrrClearWork*FarmWork); 653 Map[Loc]:=Map[Loc] and not fTerImp or tiFarm; 654 end 655 end 656 else if Map[Loc] and fTerImp<>tiFarm then 657 begin // add irrigation 658 if (RO.Government<>gDespotism) 659 or (Map[Loc] and (fTerrain or fSpecial)<>fGrass) then 660 begin 661 if NextJob=jNone then NextJob:=jIrr; 662 inc(TotalWork,Terrain[TerrType].IrrClearWork); 663 Map[Loc]:=Map[Loc] and not fTerImp or tiIrrigation; 664 end 665 end 666 end; 667 if (Terrain[TerrType].MoveCost=1) 668 and (Map[Loc] and (fRoad or fRR)=0) 669 and ((Map[Loc] and fRiver=0) or IsResearched(adBridgeBuilding)) then 670 begin // add road 671 if NextJob=jNone then NextJob:=jRoad; 672 inc(TotalWork,RoadWork); 673 Map[Loc]:=Map[Loc] or fRoad; 674 end; 675 if ((Map[Loc] and fTerImp=tiMine) 676 or (Terrain[TerrType].ProdRes[Map[Loc] shr 5 and 3]>=2)) 677 and IsResearched(adRailroad) 678 and (Map[Loc] and fRR=0) 679 and ((Map[Loc] and fRiver=0) or IsResearched(adBridgeBuilding)) 680 and (RO.Government<>gDespotism) then 681 begin // add railroad 682 if Map[Loc] and fRoad=0 then 683 begin 684 if NextJob=jNone then NextJob:=jRoad; 685 inc(TotalWork,RoadWork*Terrain[TerrType].MoveCost); 686 end; 687 if NextJob=jNone then NextJob:=jRR; 688 inc(TotalWork,RRWork*Terrain[TerrType].MoveCost); 689 Map[Loc]:=Map[Loc] and not fRoad or fRR; 690 end; 691 end; 692 Server(sGetTileInfo,me,Loc,TileInfo); 693 Value:=TileInfo.Food*8+TileInfo.Prod*2+TileInfo.Trade; 694 Map[Loc]:=OldTile; 84 695 end; 85 696 … … 87 698 procedure TAI.ProcessSettlers; 88 699 var 89 uix, cix, ecix, Loc, RadiusLoc, TestScore, BestNearCityScore, TerrType, 90 Special, V21: integer; 91 Radius: TVicinity21Loc; 92 ResourceScore, CityScore: array [0 .. lxmax * lymax - 1] of integer; 700 i,uix,cix,ecix,dtr,Loc,RadiusLoc,Special,Food,Prod,Trade,CityFood,Happy, 701 TestScore,BestNearCityScore,BestUnusedValue,BestUnusedLoc, 702 Value,NextJob,TotalWork,V21,part,Loc1: integer; 703 Tile: Cardinal; 704 FoodOk,Started: boolean; 705 Radius: TVicinity21Loc; 706 CityAreaInfo: TCityAreaInfo; 707 TileFood, ResourceScore, CityScore: array[0..lxmax*lymax-1] of integer; 708 709 procedure AddJob(Loc,Job,Score: integer); 710 // set Score=1 for low-priority jobs 711 begin 712 JobAssignment_AddJob(Loc,Job,Score); 713 if (Score>1) and (District[Loc]>=0) and (District[Loc]<maxCOD) then 714 dec(SettlerSurplus[District[Loc]]); 715 end; 93 716 94 717 procedure ReserveCityRadius(Loc: integer); 95 718 var 96 V21, RadiusLoc: integer; 97 Radius: TVicinity21Loc; 98 begin 99 V21_to_Loc(Loc, Radius); 100 for V21 := 1 to 26 do 101 begin 102 RadiusLoc := Radius[V21]; 103 if (RadiusLoc >= 0) and (RadiusLoc < MapSize) then 104 ResourceScore[RadiusLoc] := 0 719 V21,RadiusLoc: integer; 720 Radius: TVicinity21Loc; 721 begin 722 V21_to_Loc(Loc,Radius); 723 for V21:=1 to 26 do 724 begin 725 RadiusLoc:=Radius[V21]; 726 if (RadiusLoc>=0) then 727 begin 728 ResourceScore[RadiusLoc]:=0; 729 TileFood[RadiusLoc]:=0; 730 end 105 731 end 106 732 end; 107 733 108 begin 109 JobAssignment_Initialize; 110 111 // rate resources of all tiles 112 fillchar(ResourceScore, MapSize * sizeof(integer), 0); 113 for Loc := 0 to MapSize - 1 do 114 if (Map[Loc] and fRare) = 0 then 115 if (Map[Loc] and fTerrain) = fGrass then 116 if (Map[Loc] and fSpecial) <> 0 then 117 ResourceScore[Loc] := 3 // plains, 3 points 118 else 119 ResourceScore[Loc] := 2 // grassland, 2 points 120 else if (Map[Loc] and fSpecial) <> 0 then 121 ResourceScore[Loc] := 4; // special resource, 4 points 122 for cix := 0 to RO.nCity - 1 do 123 if MyCity[cix].Loc >= 0 then 124 ReserveCityRadius(MyCity[cix].Loc); // these resources already have a city 125 for uix := 0 to RO.nUn - 1 do 126 if (MyUnit[uix].Loc >= 0) and (MyUnit[uix].Job = jCity) then 127 ReserveCityRadius(MyUnit[uix].Loc); 128 // these resources almost already have a city 129 for ecix := 0 to RO.nEnemyCity - 1 do 130 if RO.EnemyCity[ecix].Loc >= 0 then 131 ReserveCityRadius(RO.EnemyCity[ecix].Loc); 132 // these resources already have an enemy city 133 134 // rate possible new cities 135 fillchar(CityScore, MapSize * sizeof(integer), 0); 136 for Loc := 0 to MapSize - 1 do 137 if ((Map[Loc] and fTerrain) = fGrass) and ((Map[Loc] and fRare) = 0) and 138 ((RO.Territory[Loc] < 0) or (RO.Territory[Loc] = me)) then 139 // don't consider founding cities in foreign nation territory 140 begin 141 TestScore := 0; 142 BestNearCityScore := 0; 143 V21_to_Loc(Loc, Radius); 144 for V21 := 1 to 26 do 145 begin // sum resource scores in potential city radius 146 RadiusLoc := Radius[V21]; 147 if (RadiusLoc >= 0) and (RadiusLoc < MapSize) then 148 begin 149 TestScore := TestScore + ResourceScore[RadiusLoc]; 150 if CityScore[RadiusLoc] > BestNearCityScore then 151 BestNearCityScore := CityScore[RadiusLoc] 152 end 153 end; 154 if TestScore >= 10 then // city is worth founding 155 begin 156 TestScore := TestScore shl 8 + ((Loc xor me) * 4567) mod 251; 157 // some unexactness, random but always the same for this tile 158 if TestScore > BestNearCityScore then 159 begin // better than all other sites in radius 160 if BestNearCityScore > 0 then // found no other cities in radius 734 procedure ScoreRoadConnections; 735 var 736 V8,nFragments,Loc,Loc1,History,RoadScore,a,b,FullyDeveloped,ConnectMask: integer; 737 BridgeOk: boolean; 738 Adjacent: TVicinity8Loc; 739 begin 740 BridgeOk:= IsResearched(adBridgeBuilding); 741 if IsResearched(adRailroad) then FullyDeveloped:=fRR or fCity 742 else FullyDeveloped:=fRoad or fRR or fCity; 743 for Loc:=G.lx to G.lx*(G.ly-1)-1 do 744 if ((1 shl (Map[Loc] and fTerrain)) and (1 shl fOcean or 1 shl fShore or 1 shl fDesert or 1 shl fArctic or 1 shl fUNKNOWN)=0) 745 and (RO.Territory[Loc]=me) 746 and (Map[Loc] and FullyDeveloped=0) 747 and (BridgeOk or (Map[Loc] and fRiver=0)) then 748 begin 749 nFragments:=0; 750 History:=0; 751 if Map[Loc] and fRoad<>0 then ConnectMask:=fRR or fCity // check for railroad 752 else ConnectMask:=fRoad or fRR or fCity; // check for road 753 V8_to_Loc(Loc,Adjacent); 754 for V8:=0 to 9 do 755 begin 756 Loc1:=Adjacent[V8 and 7]; 757 History:=History shl 1; 758 if (Loc1>=0) and (RO.Territory[Loc1]=me) 759 and (Map[Loc1] and ConnectMask<>0) then 161 760 begin 162 for V21 := 1 to 26 do 761 inc(History); 762 if V8>=2 then 163 763 begin 164 RadiusLoc := Radius[V21]; 165 if (RadiusLoc >= 0) and (RadiusLoc < MapSize) then 166 CityScore[RadiusLoc] := 0; 764 inc(nFragments); 765 case V8 and 1 of 766 0: 767 if History and 6<>0 then 768 dec(nFragments); 769 1: 770 if History and 2<>0 then 771 dec(nFragments) 772 else if History and 4<>0 then 773 begin 774 V8_to_ab((V8-1) and 7,a,b); 775 ab_to_Loc(Loc,a shl 1,b shl 1,Loc1); 776 if (Loc1>=0) 777 and (Map[Loc1] and ConnectMask<>0) then 778 dec(nFragments) 779 end 780 end 167 781 end; 168 782 end; 169 CityScore[Loc] := TestScore170 783 end; 171 end 172 end; 173 for Loc := 0 to MapSize - 1 do 174 if CityScore[Loc] > 0 then 175 JobAssignment_AddJob(Loc, jCity, 10); 176 177 // improve terrain 178 for cix := 0 to RO.nCity - 1 do 179 with MyCity[cix] do 180 if Loc >= 0 then 181 begin 182 V21_to_Loc(Loc, Radius); 183 for V21 := 1 to 26 do 184 if (Tiles and (1 shl V21) and not(1 shl CityOwnTile)) <> 0 then 185 begin // tile is exploited, but not the city own tile -- check if improvable 186 RadiusLoc := Radius[V21]; 187 assert((RadiusLoc >= 0) and (RadiusLoc < MapSize)); 188 if (RadiusLoc >= 0) and (RadiusLoc < MapSize) then 784 if nFragments>=2 then // road or railroad connection desirable 785 begin 786 if Map[Loc] and fRiver<>0 then RoadScore:=44+(nFragments-2)*4 787 else RoadScore:=56-Terrain[Map[Loc] and fTerrain].MoveCost*4 788 +(nFragments-2)*4; 789 if Map[Loc] and fRoad<>0 then 790 AddJob(Loc, jRR, RoadScore) 791 else AddJob(Loc, jRoad, RoadScore) 792 end; 793 end; 794 end; 795 796 begin 797 fillchar(SettlerSurplus, sizeof(SettlerSurplus), 0); 798 JobAssignment_Initialize; 799 800 if (Data.BehaviorFlags and bBarbarina=0) or (RO.nCity<3) then 801 begin 802 fillchar(TileFood,sizeof(TileFood),0); 803 fillchar(ResourceScore,sizeof(ResourceScore),0); 804 for Loc:=0 to MapSize-1 do 805 if Map[Loc] and fTerrain<>fUNKNOWN then 806 if Map[Loc] and fDeadLands<>0 then 807 begin 808 if not IsResearched(adMassProduction) or (Map[Loc] and fModern<>0) then 809 ResourceScore[Loc]:=20; 810 end 811 else if Map[Loc] and fTerrain=fGrass then 812 TileFood[Loc]:=Terrain[fGrass].FoodRes[Map[Loc] shr 5 and 3]-1 813 else 814 begin 815 Special:=SpecialTile(Loc,Map[Loc] and fTerrain,G.lx); 816 if Special<>0 then with Terrain[Map[Loc] and fTerrain] do 817 begin 818 Food:=FoodRes[Special]; 819 if MineEff=0 then inc(Food,IrrEff); 820 Prod:=ProdRes[Special]+MineEff; 821 Trade:=TradeRes[Special]; 822 if MoveCost=1 then inc(Trade); 823 ResourceScore[Loc]:=Food+2*Prod+Trade-7; 824 if Food>2 then TileFood[Loc]:=Food-2; 825 end 826 end; 827 828 for cix:=0 to RO.nCity-1 do 829 if MyCity[cix].Loc>=0 then 830 ReserveCityRadius(MyCity[cix].Loc); // these resources already have a city 831 for uix:=0 to RO.nUn-1 do 832 if (MyUnit[uix].Loc>=0) and (MyUnit[uix].Job=jCity) then 833 ReserveCityRadius(MyUnit[uix].Loc); // these resources almost already have a city 834 for ecix:=0 to RO.nEnemyCity-1 do 835 if RO.EnemyCity[ecix].Loc>=0 then 836 ReserveCityRadius(RO.EnemyCity[ecix].Loc); // these resources already have an enemy city 837 838 // rate possible new cities 839 fillchar(CityScore, MapSize*sizeof(integer), 0); 840 for Loc:=0 to MapSize-1 do 841 begin 842 FoodOk:= (TileFood[Loc]>0) 843 and ((Map[Loc] and fTerrain=fGrass) 844 and ((RO.Government<>gDespotism) or (Map[Loc] and fSpecial=fSpecial1)) 845 or (Map[Loc] and (fTerrain or fSpecial)=fPrairie or fSpecial1)); 846 if FoodOk and ((RO.Territory[Loc]<0) or (RO.Territory[Loc]=me)) then 847 begin 848 TestScore:=0; 849 CityFood:=0; 850 BestNearCityScore:=0; 851 V21_to_Loc(Loc,Radius); 852 for V21:=1 to 26 do 853 begin // sum resource scores in potential city radius 854 RadiusLoc:=Radius[V21]; 855 if (RadiusLoc>=0) then 856 begin 857 inc(CityFood,TileFood[RadiusLoc]); 858 if ResourceScore[RadiusLoc]>0 then 859 inc(TestScore,ResourceScore[RadiusLoc]); 860 if CityScore[RadiusLoc]>BestNearCityScore then 861 BestNearCityScore:=CityScore[RadiusLoc] 862 end 863 end; 864 if CityFood>=MinCityFood then // city is worth founding 865 begin 866 TestScore:=(72+2*TestScore) shl 8 + ((loc xor me)*4567) mod 251; 867 // some unexactness, random but always the same for this tile 868 if TestScore>BestNearCityScore then 869 begin // better than all other sites in radius 870 if BestNearCityScore>0 then // found no other cities in radius 189 871 begin 190 TerrType := Map[RadiusLoc] and fTerrain; 191 Special := Map[RadiusLoc] shr 5 and 3; 192 if TerrType >= fGrass then // can't improve water tiles 193 if (Terrain[TerrType].IrrEff > 0) // terrain is irrigatable 194 and not((RO.Government = gDespotism) and 195 (Terrain[TerrType].FoodRes[Special] >= 3)) 196 // improvement makes no sense when limit is depotism 197 and ((Map[RadiusLoc] and fTerImp) = 0) then 198 // no terrain improvement yet 199 JobAssignment_AddJob(RadiusLoc, jIrr, 50) // irrigate! 200 else if (Terrain[TerrType].MoveCost = 1) // plain terrain 201 and ((Map[RadiusLoc] and (fRoad or fRR or fRiver)) = 0) then 202 // no road or railroad yet, no river 203 JobAssignment_AddJob(RadiusLoc, jRoad, 40); 204 // build road (The Wheel trade benefit) 872 for V21:=1 to 26 do 873 begin 874 RadiusLoc:=Radius[V21]; 875 if (RadiusLoc>=0) then 876 CityScore[RadiusLoc]:=0; 877 end; 878 end; 879 CityScore[Loc]:=TestScore 880 end; 881 end 882 end; 883 end; 884 for Loc:=0 to MapSize-1 do 885 if CityScore[Loc]>0 then 886 AddJob(Loc, jCity, CityScore[Loc] shr 8); 887 end; 888 889 // improve terrain 890 for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then 891 begin // order terrain improvements 892 BestUnusedValue:=0; 893 City_GetAreaInfo(cix,CityAreaInfo); 894 V21_to_Loc(Loc,Radius); 895 for V21:=1 to 26 do if V21<>CityOwnTile then 896 if 1 shl V21 and Tiles<>0 then 897 begin // tile is being exploited! 898 RadiusLoc:=Radius[V21]; 899 if not (Map[RadiusLoc] and fTerrain in [fDesert,fArctic]) then 900 begin 901 assert(RadiusLoc>=0); 902 TileWorkPlan(RadiusLoc,cix,Value,NextJob,TotalWork); 903 if (NextJob=jRoad) 904 and (Built[imPalace]+Built[imCourt]+Built[imTownHall]=0) then 905 AddJob(RadiusLoc, NextJob, 44) 906 else if NextJob<>jNone then 907 AddJob(RadiusLoc, NextJob, 84) 908 end 909 end 910 else if CityAreaInfo.Available[V21]=faAvailable then 911 begin // tile could be exploited 912 RadiusLoc:=Radius[V21]; 913 assert(RadiusLoc>=0); 914 if not (Map[RadiusLoc] and fTerrain in [fDesert,fArctic]) then 915 begin 916 TileWorkPlan(RadiusLoc,cix,Value,NextJob,TotalWork); 917 Value:=Value shl 16 +$FFFF-TotalWork; 918 if Value>BestUnusedValue then 919 begin 920 BestUnusedValue:=Value; 921 BestUnusedLoc:=RadiusLoc; 922 end 923 end 924 end; 925 if BestUnusedValue>0 then 926 begin 927 TileWorkPlan(BestUnusedLoc,cix,Value,NextJob,TotalWork); 928 if NextJob<>jNone then 929 AddJob(BestUnusedLoc, NextJob, 44) 930 end 931 end; 932 933 ScoreRoadConnections; 934 935 if Data.BehaviorFlags and bBarbarina=0 then // low priority jobs 936 for Loc:=0 to MapSize-1 do if RO.Territory[Loc]=me then 937 begin 938 Tile:=Map[Loc]; 939 if Tile and fPoll<>0 then 940 AddJob(Loc, jPoll, 1) 941 else case Tile and (fTerrain or fSpecial or fCity) of 942 fGrass, fGrass+fSpecial1: 943 if IsResearched(adExplosives) and (SpecialTile(Loc,fHills,G.lx)>0) then 944 AddJob(Loc, jTrans, 1); 945 fSwamp: 946 if SpecialTile(Loc,fSwamp,G.lx)=0 then 947 AddJob(Loc, jClear, 1); 948 fTundra,fHills: 949 if IsResearched(adExplosives) and (Tile and fTerImp<>tiMine) 950 and (SpecialTile(Loc,fHills,G.lx)=0) then 951 AddJob(Loc, jTrans, 1); 952 end 953 end; 954 955 // cities for colony ship production 956 if Data.BehaviorFlags and bBarbarina=bBarbarina then 957 begin 958 for part:=0 to nShipPart-1 do 959 for i:=0 to ColonyShipPlan[part].nLocFoundCity-1 do 960 begin 961 Loc:=ColonyShipPlan[part].LocFoundCity[i]; 962 Started:=false; 963 for uix:=0 to RO.nUn-1 do 964 if (MyUnit[uix].Loc=Loc) and (MyUnit[uix].Job=jCity) then 965 begin 966 Started:=true; 967 break 968 end; 969 if not Started then 970 begin 971 Tile:=RO.Map[Loc]; 972 if (Tile and fTerrain=fForest) or (Tile and fTerrain=fSwamp) then 973 AddJob(Loc,jClear,235) 974 else if Tile and fTerrain=fHills then 975 begin 976 if IsResearched(adExplosives) then 977 AddJob(Loc,jTrans,235) 978 end 979 else AddJob(Loc,jCity,235); 980 end; 981 V21_to_Loc(Loc, Radius); 982 for V21:=1 to 26 do 983 begin 984 Loc1:=Radius[V21]; 985 if (Loc1>=0) and (RO.Map[Loc1] and (fTerrain or fSpecial)=fSwamp) then 986 AddJob(Loc1,jClear,255); 987 end 988 end 989 end; 990 991 // choose all settlers to work 992 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 993 if (Loc>=0) and ((mix=mixSettlers) or (mix=mixSlaves) 994 or (Data.BehaviorFlags and bBarbarina<>0) and (MyModel[mix].Kind=mkSettler)) then 995 begin 996 JobAssignment_AddUnit(uix); 997 if (District[Loc]>=0) and (District[Loc]<maxCOD) then 998 inc(SettlerSurplus[District[Loc]]); 999 end; 1000 1001 JobAssignment_Go; 1002 1003 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1004 if (Loc>=0) and (Map[Loc] and fCity=0) and (Job=jNone) 1005 and ((mix=mixSettlers) or (mix=mixSlaves)) 1006 and not JobAssignment_GotJob(uix) then 1007 Unit_MoveEx(uix, maNextCity); 1008 1009 //{$IFDEF DEBUG}DebugMessage(2, Format('Settler surplus in district 0: %d',[SettlerSurplus[0]]));{$ENDIF} 1010 1011 // add settlers to city 1012 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1013 if (Loc>=0) and (Map[Loc] and fCity<>0) 1014 and (MyModel[MyUnit[uix].mix].Kind=mkSettler) then 1015 begin 1016 dtr:=District[Loc]; 1017 if (mix<>mixSettlers) 1018 or (dtr>=0) and (dtr<maxCOD) 1019 and (SettlerSurplus[dtr]>DistrictPopulation[dtr] div 8) then 1020 begin 1021 City_FindMyCity(Loc, cix); 1022 with MyCity[cix] do 1023 if (Built[imSewer]>0) 1024 or (Built[imAqueduct]>0) and (Size<=NeedSewerSize-2) 1025 or (Size<=NeedAqueductSize-2) then 1026 begin // settlers could be added to this city 1027 Happy:=BasicHappy; 1028 for i:=0 to 27 do if Built[i]>0 then inc(Happy); 1029 if Built[imTemple]>0 then inc(Happy); 1030 if Built[imCathedral]>0 then 1031 begin 1032 inc(Happy,2); 1033 if RO.Wonder[woBach].EffectiveOwner=me then inc(Happy,1) 1034 end; 1035 if Built[imTheater]>0 then inc(Happy,2); 1036 if (Built[imColosseum]>0) or (Happy shl 1>=Size+2) then 1037 begin // bigger city would be happy 1038 // {$IFDEF DEBUG}DebugMessage(2, Format('Adding settlers to city at %d',[Loc]));{$ENDIF} 1039 Unit_AddToCity(uix); 1040 if (dtr>=0) and (dtr<maxCOD) then dec(SettlerSurplus[dtr]) 205 1041 end 206 1042 end; 207 end; 208 209 // choose all settlers to work 210 for uix := 0 to RO.nUn - 1 do 211 if (MyUnit[uix].Loc >= 0) and 212 (MyModel[MyUnit[uix].mix].Kind in [mkSettler, mkSlaves]) then 213 JobAssignment_AddUnit(uix); 214 215 JobAssignment_Go; 1043 end 1044 end; 216 1045 end; // ProcessSettlers 217 1046 218 // ProcessUnit: execute attack, capture, discover or patrol task according to unit role 219 procedure TAI.ProcessUnit(uix: integer; Role: UnitRole); 1047 1048 //------------------------------- 1049 // MY TURN 1050 //------------------------------- 1051 1052 procedure TAI.DoTurn; 1053 var 1054 emix,i,p1,TaxSum,ScienceSum,NewTaxRate: integer; 1055 AllHateMe: boolean; 1056 {$IFDEF PERF}PF,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9: int64;{$ENDIF} 1057 begin 1058 {$IFDEF DEBUG}fillchar(DebugMap, sizeof(DebugMap),0);{$ENDIF} 1059 1060 {$IFDEF PERF}QueryPerformanceFrequency(PF);{$ENDIF} 1061 {$IFDEF PERF}QueryPerformanceCounter(t0);{$ENDIF} 1062 1063 WarNations:=PresenceUnknown; 1064 for p1:=0 to nPl-1 do 1065 if (p1<>me) and (1 shl p1 and RO.Alive<>0) and (RO.Treaty[p1]<trPeace) then 1066 inc(WarNations,1 shl p1); 1067 BombardingNations:=0; 1068 for emix:=0 to RO.nEnemyModel-1 do with RO.EnemyModel[emix] do 1069 if (Domain=dSea) and (1 shl (mcLongRange-mcFirstNonCap) and Cap<>0) then 1070 BombardingNations:=BombardingNations or (1 shl Owner); 1071 BombardingNations:=BombardingNations and WarNations; 1072 1073 AnalyzeMap; 1074 //for i:=0 to MapSize-1 do DebugMap[i]:=Formation[i]; 1075 1076 if (Data.BehaviorFlags and bBarbarina=0) 1077 and (RO.Tech[ResearchOrder[Data.BehaviorFlags and bGender,8]]<tsApplicable) then 1078 CheckGender; 1079 1080 if G.Difficulty[me]<MaxDiff then // not on beginner level 1081 begin 1082 if (Data.LastResearchTech=adHorsebackRiding) 1083 and (RO.ResearchTech<0) and (random(6)=0) 1084 and (HavePort or (ContinentPresence[0] and not (1 shl me or PresenceUnknown)<>0)) then 1085 begin 1086 Data.BehaviorFlags:=Data.BehaviorFlags or bBarbarina_Hide; 1087 DebugMessage(1, 'Early Barbarina!'); 1088 end; 1089 if Data.BehaviorFlags and bBarbarina=0 then 1090 begin 1091 AllHateMe:=false; 1092 for p1:=0 to nPl-1 do 1093 if (1 shl p1 and RO.Alive<>0) and (RO.Treaty[p1]>=trNone) then 1094 if (RO.Treaty[p1]<trPeace) and 1095 ((Data.RejectTurn[suContact,p1]>=0) 1096 or (Data.RejectTurn[suPeace,p1]>=0)) then 1097 AllHateMe:=true 1098 else begin AllHateMe:=false; break end; 1099 if AllHateMe then 1100 begin 1101 Data.BehaviorFlags:=Data.BehaviorFlags or bBarbarina_Hide; 1102 DebugMessage(1, 'All hate me!'); 1103 end 1104 end; 1105 1106 if Data.BehaviorFlags and bBarbarina=0 then 1107 if Barbarina_GoHidden then 1108 begin 1109 Data.BehaviorFlags:=Data.BehaviorFlags or bBarbarina_Hide; 1110 DebugMessage(1, 'Barbarina!'); 1111 end; 1112 if Data.BehaviorFlags and bBarbarina=bBarbarina_Hide then 1113 if Barbarina_Go then 1114 begin 1115 Data.BehaviorFlags:=Data.BehaviorFlags or bBarbarina; 1116 DebugMessage(1, 'Barbarina - no mercy!'); 1117 end; 1118 end; 1119 1120 {$IFDEF PERF}QueryPerformanceCounter(t1);{$ENDIF} 1121 1122 // better government form available? 1123 if (Data.BehaviorFlags and bBarbarina=0) and (RO.Turn>=LeaveDespotism) 1124 and (RO.Government<>gAnarchy) then 1125 if IsResearched(adDemocracy) then 1126 begin 1127 if RO.Government<>gDemocracy then 1128 Revolution //!!! 1129 end 1130 else if IsResearched(adTheRepublic) then 1131 begin 1132 if RO.Government<>gRepublic then 1133 Revolution 1134 end 1135 else if IsResearched(adMonarchy) then 1136 begin 1137 if RO.Government<>gMonarchy then 1138 Revolution 1139 end; 1140 1141 CollectModelCatStat; 1142 1143 if Data.BehaviorFlags and bBarbarina=bBarbarina then 1144 begin 1145 MakeColonyShipPlan; 1146 Barbarina_DoTurn 1147 end 1148 else 1149 begin 1150 {$IFDEF PERF}QueryPerformanceCounter(t2);{$ENDIF} 1151 1152 {$IFDEF PERF}QueryPerformanceCounter(t3);{$ENDIF} 1153 1154 AttackAndPatrol; 1155 1156 {$IFDEF PERF}QueryPerformanceCounter(t4);{$ENDIF} 1157 1158 MoveUnitsHome; 1159 1160 {$IFDEF PERF}QueryPerformanceCounter(t5);{$ENDIF} 1161 end; 1162 1163 ProcessSettlers; 1164 1165 {$IFDEF PERF}QueryPerformanceCounter(t6);{$ENDIF} 1166 1167 if Data.BehaviorFlags and bBarbarina<>0 then 1168 Barbarina_SetCityProduction 1169 else 1170 SetCityProduction; 1171 1172 {$IFDEF PERF}QueryPerformanceCounter(t7);{$ENDIF} 1173 1174 // correct tax rate if necessary 1175 if not IsResearched(adWheel) then 1176 ChangeRates(0,0) 1177 else 1178 begin 1179 if (RO.TaxRate=0) or (RO.Money<(TotalPopulation[me]-4)*2) then 1180 NewTaxRate:=RO.TaxRate // don't check decreasing tax 1181 else NewTaxRate:=RO.TaxRate-10; 1182 while NewTaxRate<100 do 1183 begin 1184 SumCities(NewTaxRate,TaxSum,ScienceSum); 1185 if RO.Money+TaxSum>=(TotalPopulation[me]-4) then break; // enough 1186 inc(NewTaxRate,10); 1187 end; 1188 if NewTaxRate<>RO.TaxRate then 1189 begin 1190 // {$IFDEF DEBUG}DebugMessage(3,Format('New tax rate: %d',[NewTaxRate]));{$ENDIF} 1191 ChangeRates(NewTaxRate,0) 1192 end; 1193 end; 1194 1195 // clean up RequestedTechs 1196 if (Data.LastResearchTech>=0) 1197 and (Data.LastResearchTech<>RO.ResearchTech) then // research completed 1198 for p1:=0 to nPl-1 do 1199 if (p1<>me) and (1 shl p1 and RO.Alive<>0) 1200 and (RO.EnemyReport[p1].TurnOfCivilReport+TechReportOutdated>RO.Turn) 1201 and (RO.EnemyReport[p1].Tech[Data.LastResearchTech]<tsSeen) then 1202 begin // latest researched advance might be of interest to this nation 1203 for i:=0 to nRequestedTechs-1 do 1204 if (Data.RequestedTechs[i]>=0) 1205 and (Data.RequestedTechs[i] shr 8 and $F=p1) then 1206 Data.RequestedTechs[i]:=-1; 1207 end; 1208 if RO.ResearchTech=adMilitary then Data.LastResearchTech:=-1 1209 else Data.LastResearchTech:=RO.ResearchTech; 1210 for i:=0 to nRequestedTechs-1 do 1211 if (Data.RequestedTechs[i]>=0) 1212 and (RO.Tech[Data.RequestedTechs[i] and $FF]>=tsSeen) then 1213 Data.RequestedTechs[i]:=-1; 1214 1215 // prepare negotiation 1216 AdvanceValuesSet:=false; 1217 SetAdvanceValues; 1218 1219 1220 {$IFDEF DEBUG} 1221 (*for p1:=0 to nPl-1 do 1222 if (p1<>me) and (1 shl p1 and RO.Alive<>0) and (RO.Treaty[p1]>=trPeace) 1223 and (RO.EnemyReport[p1].TurnOfCivilReport>=0) then 1224 TraceAdvanceValues(p1);*) 1225 {$ENDIF} 1226 1227 {$IFDEF PERF}DebugMessage(2,Format('t1=%d t2=%d t3=%d t4=%d t5=%d t6=%d t7=%d t8=%d t9=%d (ns)',[(t1-t0)*1000000 div PF,(t2-t1)*1000000 div PF,(t3-t2)*1000000 div PF,(t4-t3)*1000000 div PF,(t5-t4)*1000000 div PF,(t6-t5)*1000000 div PF,(t7-t6)*1000000 div PF,(t8-t7)*1000000 div PF,(t9-t8)*1000000 div PF]));{$ENDIF} 1228 end; 1229 1230 {$IFDEF DEBUG} 1231 procedure TAI.TraceAdvanceValues(Nation: integer); 1232 var 1233 ad: integer; 1234 begin 1235 for ad:=0 to nAdv-1 do 1236 if (RO.Tech[ad]<tsSeen) and (RO.EnemyReport[Nation].Tech[ad]>=tsApplicable) 1237 and (AdvanceValue[ad]>0) then 1238 begin 1239 DebugMessage(2,Format('%s (%d): +%x', 1240 [Name_Advance[ad], Advancedness[ad], AdvanceValue[ad]])) 1241 end 1242 end; 1243 {$ENDIF} 1244 1245 1246 procedure TAI.CheckGender; 1247 var 1248 p1,NewGender: integer; 1249 begin 1250 NewGender:=-1; 1251 for p1:=0 to nPl-1 do 1252 if (p1<>me) and (1 shl p1 and RO.Alive<>0) 1253 and (RO.Treaty[p1]>=trFriendlyContact) then 1254 if PlayerHash[me]>PlayerHash[p1] then 1255 begin 1256 if NewGender=bMale then 1257 begin NewGender:=-2; break end; // ambiguous, don't change gender 1258 NewGender:=bFemale; 1259 end 1260 else 1261 begin 1262 if NewGender=bFemale then 1263 begin NewGender:=-2; break end; // ambiguous, don't change gender 1264 NewGender:=bMale; 1265 end; 1266 if (NewGender>=0) and (NewGender<>Data.BehaviorFlags and bGender) then 1267 begin 1268 Data.BehaviorFlags:=Data.BehaviorFlags and not bGender or NewGender; 1269 DebugMessage(1, 'Gender:='+char(48+NewGender)); 1270 end 1271 end; 1272 1273 1274 procedure TAI.SetAdvanceValues; 1275 1276 procedure RateResearchAdv(ad, Time: integer); 1277 var 1278 Value: integer; 1279 begin 1280 if Time=0 then Value:=TechValue_ForResearch_Next 1281 else Value:=TechValue_ForResearch-Time; 1282 if AdvanceValue[ad]<Value then 1283 AdvanceValue[ad]:=Value; 1284 end; 1285 1286 procedure SetPreqValues(ad, Value: integer); 1287 begin 1288 if (RO.Tech[ad]<tsSeen) and (ad<>RO.ResearchTech) then 1289 begin 1290 if AdvanceValue[ad]<Value then 1291 AdvanceValue[ad]:=Value; 1292 if ad=adScience then 1293 begin 1294 SetPreqValues(adTheology,Value-1); 1295 SetPreqValues(adPhilosophy,Value-1); 1296 end 1297 else if ad=adMassProduction then 1298 // preqs should be researched now 1299 else 1300 begin 1301 if AdvPreq[ad,0]>=0 then 1302 SetPreqValues(AdvPreq[ad,0],Value-1); 1303 if AdvPreq[ad,1]>=0 then 1304 SetPreqValues(AdvPreq[ad,1],Value-1); 1305 end; 1306 end 1307 end; 1308 1309 procedure RateImpPreq(iix, Value: integer); 1310 begin 1311 if (Value>0) and (Imp[iix].Preq>=0) then 1312 inc(AdvanceValue[Imp[iix].Preq],Value); 1313 end; 1314 1315 var 1316 emix,cix,adMissing,iad,ad,count,i,Time,d,CurrentCost,CurrentStrength, 1317 MaxSize, MaxTrade: integer; 1318 PreView,Emergency,Bombarded: boolean; 1319 begin 1320 if AdvanceValuesSet then exit; 1321 AdvanceValuesSet:=true; 1322 1323 fillchar(AdvanceValue,sizeof(AdvanceValue),0); 1324 1325 // rate techs to ensure research progress 1326 Time:=0; 1327 for ad:=0 to nAdv-1 do if RO.Tech[ad]=tsSeen then inc(Time); 1328 adMissing:=-1; 1329 Emergency:=true; 1330 for iad:=0 to nResearchOrder-1 do 1331 begin 1332 ad:=ResearchOrder[Data.BehaviorFlags and bGender,iad]; 1333 if (ad<>RO.ResearchTech) and (RO.Tech[ad]<tsSeen) then 1334 begin 1335 if adMissing<0 then adMissing:=ad; 1336 RateResearchAdv(ad,Time); // unseen tech of own gender 1337 if AdvPreq[ad,2]<>preNone then 1338 begin // 2 of 3 required 1339 count:=0; 1340 for i:=0 to 2 do 1341 if (AdvPreq[ad,i]=RO.ResearchTech) 1342 or (RO.Tech[AdvPreq[ad,i]]>=tsSeen) then 1343 inc(count); 1344 if count>=2 then Emergency:=false 1345 else 1346 begin 1347 if ad<>adMassProduction then // don't score third preq for MP 1348 begin 1349 for i:=0 to 2 do 1350 if (AdvPreq[ad,i]<>RO.ResearchTech) 1351 and (RO.Tech[AdvPreq[ad,i]]<tsSeen) then 1352 RateResearchAdv(AdvPreq[ad,i],Time); 1353 end; 1354 inc(Time,2-count) 1355 end 1356 end 1357 else 1358 begin 1359 count:=0; 1360 for i:=0 to 1 do 1361 if (AdvPreq[ad,i]<>preNone) and (AdvPreq[ad,i]<>RO.ResearchTech) 1362 and (RO.Tech[AdvPreq[ad,i]]<tsSeen) then 1363 begin 1364 RateResearchAdv(AdvPreq[ad,i],Time); 1365 inc(count) 1366 end; 1367 if count=0 then Emergency:=false; 1368 inc(Time,count); 1369 end; 1370 inc(Time,2); 1371 end 1372 end; 1373 if Emergency and (adMissing>=0) then 1374 begin 1375 {$IFDEF DEBUG}DebugMessage(2, 'Research emergency: Go for' 1376 +Name_Advance[adMissing]+' now!');{$ENDIF} 1377 SetPreqValues(adMissing, TechValue_ForResearch_Urgent); 1378 end; 1379 for iad:=0 to nResearchOrder-1 do 1380 begin 1381 ad:=ResearchOrder[Data.BehaviorFlags and bGender xor 1,iad]; 1382 if ad=adScience then 1383 inc(AdvanceValue[ad], 5*TechValue_ForResearch_LeaveOut) 1384 else if LeaveOutValue[ad]>0 then 1385 if AdvanceValue[ad]>0 then 1386 inc(AdvanceValue[ad], LeaveOutValue[ad]*TechValue_ForResearch_LeaveOut) 1387 // else AdvanceValue[ad]:=1; 1388 end; 1389 1390 // rate military techs 1391 for d:=0 to nDomains-1 do 1392 begin 1393 CurrentCost:=0; 1394 CurrentStrength:=0; 1395 for PreView:=true downto false do 1396 for i:=0 to nUpgrade-1 do with Upgrade[d,i] do 1397 if (Preq>=0) and not (Preq in FutureTech) then 1398 if ((Ro.ResearchTech=Preq) or (RO.Tech[Preq]>=tsSeen)) = PreView then 1399 if PreView then 1400 begin 1401 if Cost>CurrentCost then CurrentCost:=Cost; 1402 inc(CurrentStrength, Strength); 1403 end 1404 else 1405 begin // rate 1406 if (i>0) and (Trans>0) then inc(AdvanceValue[Preq],$400); 1407 if Cost<=CurrentCost then 1408 inc(AdvanceValue[Preq], (4-d)*Strength*$400 div (CurrentStrength+Upgrade[d,0].Strength)) 1409 else inc(AdvanceValue[Preq], (4-d)*Strength*$200 div (CurrentStrength+Upgrade[d,0].Strength)) 1410 end; 1411 end; 1412 // speed 1413 inc(AdvanceValue[adSteamEngine],$400); 1414 inc(AdvanceValue[adNuclearPower],$400); 1415 inc(AdvanceValue[adRocketry],$400); 1416 // features 1417 inc(AdvanceValue[adBallistics],$800); 1418 inc(AdvanceValue[adCommunism],$800); 1419 // weight 1420 inc(AdvanceValue[adAutomobile],$800); 1421 inc(AdvanceValue[adSteel],$800); 1422 inc(AdvanceValue[adAdvancedFlight],$400); 1423 1424 // civil non-improvement 1425 if RO.Turn>=LeaveDespotism then 1426 begin 1427 inc(AdvanceValue[adDemocracy],$80*RO.nCity); 1428 inc(AdvanceValue[adTheRepublic],$800); 1429 end; 1430 inc(AdvanceValue[adRailroad],$800); 1431 // inc(AdvanceValue[adExplosives],$800); // no, has enough 1432 inc(AdvanceValue[adBridgeBuilding],$200); 1433 inc(AdvanceValue[adSpaceFlight],$200); 1434 inc(AdvanceValue[adSelfContainedEnvironment],$200); 1435 inc(AdvanceValue[adImpulseDrive],$200); 1436 inc(AdvanceValue[adTransstellarColonization],$200); 1437 1438 // city improvements 1439 MaxSize:=0; 1440 for cix:=0 to RO.nCity-1 do 1441 if MyCity[cix].Size>MaxSize then 1442 MaxSize:=MyCity[cix].Size; 1443 if RO.Government in [gRepublic,gDemocracy,gLybertarianism] then 1444 MaxTrade:=(MaxSize-1)*3 1445 else MaxTrade:=(MaxSize-1)*2; 1446 1447 RateImpPreq(imCourt,(RO.nCity-1)*$100); 1448 RateImpPreq(imLibrary,(MaxTrade-10)*$180); 1449 RateImpPreq(imMarket,(MaxTrade-10)*$140); 1450 RateImpPreq(imUniversity,(MaxTrade-10)*$140); 1451 RateImpPreq(imBank,(MaxTrade-10)*$100); 1452 RateImpPreq(imObservatory,(MaxTrade-10)*$100); 1453 RateImpPreq(imResLab,(MaxTrade-14)*$140); 1454 RateImpPreq(imStockEx,(MaxTrade-10)*$10*(RO.nCity-1)); 1455 RateImpPreq(imHighways,(MaxSize-5)*$200); 1456 RateImpPreq(imFactory,(MaxSize-8)*$200); 1457 RateImpPreq(imMfgPlant,(MaxSize-8)*$1C0); 1458 RateImpPreq(imRecycling,(MaxSize-8)*$180); 1459 RateImpPreq(imHarbor,(MaxSize-7)*$200); 1460 RateImpPreq(imSuperMarket,$300); 1461 if RO.Turn>=40 then RateImpPreq(imTemple,$400); 1462 if RO.Government<>gDespotism then 1463 begin 1464 RateImpPreq(imCathedral,$400); 1465 RateImpPreq(imTheater,$400); 1466 end; 1467 if MaxSize>=NeedAqueductSize-1 then 1468 begin 1469 RateImpPreq(imAqueduct,$600); 1470 RateImpPreq(imGrWall,$300); 1471 end; 1472 if cixStateImp[imPalace]>=0 then 1473 with MyCity[cixStateImp[imPalace]] do 1474 if (Built[imColosseum]+Built[imObservatory]>0) and (Size>=NeedSewerSize-1) then 1475 RateImpPreq(imSewer,$400); 1476 Bombarded:=false; 1477 for emix:=0 to RO.nEnemyModel-1 do 1478 if 1 shl (mcLongRange-mcFirstNonCap) and RO.EnemyModel[emix].Cap<>0 then 1479 Bombarded:=true; 1480 if Bombarded then 1481 RateImpPreq(imCoastalFort,$400); 1482 end; 1483 1484 procedure TAI.AnalyzeMap; 1485 var 1486 cix,Loc,Loc1,V8,f1,p1: integer; 1487 Adjacent: TVicinity8Loc; 1488 begin 1489 inherited AnalyzeMap; 1490 1491 // collect nation presence information for continents and oceans 1492 fillchar(ContinentPresence, sizeof(ContinentPresence), 0); 1493 fillchar(OceanPresence, sizeof(OceanPresence), 0); 1494 for Loc:=0 to MapSize-1 do 1495 begin 1496 f1:=Formation[Loc]; 1497 case f1 of 1498 0..maxCOD-1: 1499 begin 1500 p1:=RO.Territory[Loc]; 1501 if p1>=0 then 1502 if Map[Loc] and fTerrain>=fGrass then 1503 ContinentPresence[f1]:=ContinentPresence[f1] or (1 shl p1) 1504 else OceanPresence[f1]:=OceanPresence[f1] or (1 shl p1); 1505 end; 1506 nfUndiscovered: 1507 begin // adjacent formations are not completely discovered 1508 V8_to_Loc(Loc,Adjacent); 1509 for V8:=0 to 7 do 1510 begin 1511 Loc1:=Adjacent[V8]; 1512 if Loc1>=0 then 1513 begin 1514 f1:=Formation[Loc1]; 1515 if (f1>=0) and (f1<maxCOD) then 1516 if Map[Loc1] and fTerrain>=fGrass then 1517 ContinentPresence[f1]:=ContinentPresence[f1] or PresenceUnknown 1518 else OceanPresence[f1]:=OceanPresence[f1] or PresenceUnknown 1519 end 1520 end 1521 end; 1522 nfPeace: 1523 begin // nation present in adjacent formations 1524 V8_to_Loc(Loc,Adjacent); 1525 for V8:=0 to 7 do 1526 begin 1527 Loc1:=Adjacent[V8]; 1528 if Loc1>=0 then 1529 begin 1530 f1:=Formation[Loc1]; 1531 if (f1>=0) and (f1<maxCOD) then 1532 if Map[Loc1] and fTerrain>=fGrass then 1533 ContinentPresence[f1]:=ContinentPresence[f1] 1534 or (1 shl RO.Territory[Loc]) 1535 else OceanPresence[f1]:=OceanPresence[f1] 1536 or (1 shl RO.Territory[Loc]) 1537 end 1538 end 1539 end; 1540 end; 1541 end; 1542 1543 fillchar(TotalPopulation, sizeof(TotalPopulation), 0); 1544 fillchar(ContinentPopulation, sizeof(ContinentPopulation), 0); 1545 fillchar(DistrictPopulation, 4*nDistrict, 0); 1546 1547 // count population 1548 for cix:=0 to RO.nEnemyCity-1 do with RO.EnemyCity[cix] do if Loc>=0 then 1549 begin 1550 inc(TotalPopulation[Owner],Size); 1551 if (Formation[Loc]>=0) and (Formation[Loc]<maxCOD) then 1552 inc(ContinentPopulation[Owner,Formation[Loc]],Size); 1553 end; 1554 for cix:=0 to RO.nCity-1 do with RO.City[cix] do if Loc>=0 then 1555 begin 1556 inc(TotalPopulation[me],Size); 1557 assert(District[Loc]>=0); 1558 if District[Loc]<maxCOD then 1559 inc(DistrictPopulation[District[Loc]],Size); 1560 end; 1561 end; 1562 1563 procedure TAI.CollectModelCatStat; 1564 var 1565 i,uix,Cat,mix,Quality: integer; 1566 begin 1567 // categorize models 1568 for Cat:=0 to nModelCat-1 do 1569 ModelBestQuality[Cat]:=0; 1570 mixCaravan:=-1; 1571 mixSlaves:=-1; 1572 mixCruiser:=-1; 1573 for mix:=0 to RO.nModel-1 do 1574 begin 1575 ModelCat[mix]:=mctNone; 1576 if mix=1 then mixMilitia:=mix 1577 else 1578 case MyModel[mix].Kind of 1579 $00..$0F: // common units 1580 if MyModel[mix].Cap[mcNav]>0 then mixCruiser:=mix // temporary!!! 1581 else 1582 begin 1583 RateMyModel(mix,Cat,Quality); 1584 ModelCat[mix]:=Cat; 1585 ModelQuality[mix]:=Quality; 1586 if (Cat>=0) and (Quality>ModelBestQuality[Cat]) then 1587 ModelBestQuality[Cat]:=Quality; 1588 end; 1589 mkSpecial_TownGuard: mixTownGuard:=mix; 1590 mkSettler: mixSettlers:=mix; // engineers always have higher mix 1591 mkCaravan: mixCaravan:=mix; 1592 mkSlaves: mixSlaves:=mix 1593 end 1594 end; 1595 1596 // mark obsolete models with quality=0 1597 for mix:=0 to RO.nModel-1 do 1598 if (MyModel[mix].Kind<$10) and (ModelCat[mix]>=0) 1599 and (ModelQuality[mix]+MaxExistWorseThanBestModel 1600 < ModelBestQuality[ModelCat[mix]]) then 1601 ModelQuality[mix]:=ModelQuality[mix]-$40000000; 1602 1603 OceanWithShip:=0; 1604 if mixCruiser>=0 then 1605 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1606 if (Loc>=0) and (mix=mixCruiser) and (Map[Loc] and fTerrain<fGrass) then 1607 begin 1608 i:=Formation[Loc]; 1609 if (i>=0) and (i<maxCOD) then OceanWithShip:=OceanWithShip or (1 shl i) 1610 end; 1611 end; 1612 1613 1614 procedure TAI.MoveUnitsHome; 220 1615 const 221 DistanceScore = 4; 1616 PatrolDestination=lxmax*lymax; 1617 FirstSurplusLoop: array[mctGroundDefender..mctGroundAttacker] of integer= (2,1); 222 1618 var 223 BestScore, BestCount, BestLoc, TerrType, TestLoc, NextLoc, TestDistance, Tile, 224 V8, TestScore, euix, MyDamage, EnemyDamage, TerrOwner, StepSize, OldLoc, 225 AttackForecast, MoveResult, AttackResult: integer; 226 Exhausted: boolean; 227 TestTask, BestTask: (utNone, utAttack, utCapture, utDiscover, utPatrol, 228 utGoHome); 1619 Cat,i,mix,cix,uix,Loop,nModelOrder: integer; 1620 Adjacent: TVicinity8Loc; 1621 LocNeed: array[0..lxmax*lymax-1] of shortint; 1622 Destination: array[0..nUmax-1] of integer; 1623 DistrictNeed,DistrictNeed0: array[0..maxCOD-1] of integer; 1624 ModelOrder: array[0..nMmax-1] of integer; 1625 complete,Fortified: boolean; 1626 1627 function IsBombarded(cix: integer): boolean; 1628 var 1629 Loc1,V8: integer; 229 1630 Adjacent: TVicinity8Loc; 230 AdjacentUnknown: array [0 .. lxmax * lymax - 1] of integer; 231 232 begin 1631 begin 1632 result:=false; 1633 if BombardingNations<>0 then with MyCity[cix] do 1634 begin 1635 V8_to_Loc(Loc,Adjacent); 1636 for V8:=0 to 7 do 1637 begin 1638 Loc1:=Adjacent[V8]; 1639 if (Loc1>=0) and (Map[Loc1] and fTerrain<fGrass) 1640 and (Formation[Loc1]>=0) and (Formation[Loc1]<maxCOD) 1641 and (OceanPresence[Formation[Loc1]] and (BombardingNations or PresenceUnknown)<>0) then 1642 begin result:=true; exit end 1643 end; 1644 end; 1645 end; 1646 1647 procedure TryUtilize(uix: integer); 1648 var 1649 cix, ProdCost, UtilizeCost: integer; 1650 begin 1651 if (MyUnit[uix].Health=100) 1652 and (Map[MyUnit[uix].Loc] and (fCity or fOwned)=fCity or fOwned) then 1653 begin 1654 City_FindMyCity(MyUnit[uix].Loc,cix); 1655 with MyCity[cix] do if Project and cpImp=0 then 1656 begin 1657 ProdCost:=MyModel[Project and cpIndex].Cost; 1658 UtilizeCost:=MyModel[MyUnit[uix].mix].Cost; 1659 if Prod<(ProdCost-UtilizeCost*2 div 3)*BuildCostMod[G.Difficulty[me]] div 12 then 1660 Unit_Disband(uix); 1661 end 1662 end 1663 end; 1664 1665 procedure FindDestination(uix: integer); 1666 var 1667 MoveStyle,V8,Loc1,Time,NextLoc,NextTime,RecoverTurns: integer; 1668 Reached: array[0..lxmax*lymax-1] of boolean; 1669 begin 1670 fillchar(Reached, MapSize, false); 233 1671 Pile.Create(MapSize); 234 1672 with MyUnit[uix] do 235 repeat 236 BestScore := -999999; 237 BestTask := utNone; 238 fillchar(AdjacentUnknown, sizeof(AdjacentUnknown), $FF); 239 // -1, indicates tiles not checked yet 240 Pile.Empty; 241 Pile.Put(Loc, 0); // start search for something to do at current location 242 while Pile.Get(TestLoc, TestDistance) do 243 begin 244 TestScore := 0; 245 Tile := Map[TestLoc]; 246 AdjacentUnknown[TestLoc] := 0; 247 248 if ((Tile and fUnit) <> 0) and ((Tile and fOwned) = 0) then 1673 begin 1674 Pile.Put(Loc, $800-Movement); 1675 MoveStyle:=GetMyMoveStyle(mix, 100); 1676 end; 1677 while Pile.Get(Loc1, Time) do 1678 begin 1679 if LocNeed[Loc1]>0 then 1680 begin 1681 LocNeed[Loc1]:=0; 1682 if (District[Loc1]>=0) and (District[Loc1]<maxCOD) then 1683 begin 1684 assert(DistrictNeed[District[Loc1]]>0); 1685 dec(DistrictNeed[District[Loc1]]); 1686 end; 1687 Destination[uix]:=Loc1; 1688 break; 1689 end; 1690 Reached[Loc1]:=true; 1691 V8_to_Loc(Loc1, Adjacent); 1692 for V8:=0 to 7 do 1693 begin 1694 NextLoc:=Adjacent[V8]; 1695 if (NextLoc>=0) and not Reached[NextLoc] and (RO.Territory[NextLoc]=me) then 1696 case CheckStep(MoveStyle, Time, V8 and 1, NextTime, RecoverTurns, Map[Loc1], Map[NextLoc], false) of 1697 csOk: 1698 Pile.Put(NextLoc, NextTime); 1699 csForbiddenTile: 1700 Reached[NextLoc]:=true; // don't check moving there again 1701 csCheckTerritory: 1702 assert(false); 1703 end 1704 end; 1705 end; 1706 Pile.Free; 1707 end; 1708 1709 begin 1710 if not (RO.Government in [gAnarchy, gDespotism]) then // utilize townguards 1711 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1712 if (Loc>=0) and (Master<0) and (mix=mixTownGuard) then 1713 Unit_Disband(uix); 1714 1715 fillchar(UnitLack,sizeof(UnitLack),0); 1716 fillchar(Destination, 4*RO.nUn, $FF); 1717 for i:=0 to maxCOD-1 do 1718 if uixPatrol[i]>=0 then 1719 Destination[uixPatrol[i]]:=PatrolDestination; 1720 for uix:=0 to RO.nUn-1 do 1721 if (MyUnit[uix].mix=mixMilitia) or (MyUnit[uix].mix=mixCruiser) then 1722 Destination[uix]:=PatrolDestination; 1723 1724 // distribute attackers and defenders 1725 for Cat:=mctGroundDefender to mctGroundAttacker do 1726 begin 1727 nModelOrder:=0; 1728 for mix:=0 to Ro.nModel-1 do 1729 if ModelCat[mix]=Cat then 1730 begin 1731 i:=nModelOrder; 1732 while (i>0) and (ModelQuality[mix]<ModelQuality[ModelOrder[i-1]]) do 1733 begin ModelOrder[i]:=ModelOrder[i-1]; dec(i) end; 1734 ModelOrder[i]:=mix; 1735 inc(nModelOrder); 1736 end; 1737 1738 Loop:=0; 1739 repeat 1740 if Loop=FirstSurplusLoop[Cat] then 1741 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1742 if (Loc>=0) and (Destination[uix]<0) and (Master<0) 1743 and (ModelCat[mix]=Cat) 1744 and (ModelQuality[mix]<0) then 1745 TryUtilize(uix); 1746 1747 fillchar(LocNeed, MapSize, 0); 1748 fillchar(DistrictNeed, sizeof(DistrictNeed), 0); 1749 1750 for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then 1751 if ((Cat<>mctGroundDefender) or (Loop<>0) or IsBombarded(cix)) 1752 and ((Loop<>FirstSurplusLoop[Cat]) or (Built[imBarracks]+Built[imMilAcademy]>0)) 1753 and ((Loop<>FirstSurplusLoop[Cat]+1) or (Built[imBarracks]+Built[imMilAcademy]=0)) then 1754 begin 1755 LocNeed[Loc]:=1; 1756 if (District[Loc]>=0) and (District[Loc]<maxCOD) then 1757 begin 1758 inc(DistrictNeed[District[Loc]]); 1759 if Loop<FirstSurplusLoop[Cat] then 1760 inc(UnitLack[District[Loc],Cat]) 1761 end 1762 end; 1763 1764 if Loop=0 then // protect city building sites 1765 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1766 if (Loc>=0) and (Job=jCity) and (RO.Territory[Loc]=me) then 1767 begin 1768 LocNeed[Loc]:=1; 1769 if (District[Loc]>=0) and (District[Loc]<maxCOD) then 1770 inc(DistrictNeed[District[Loc]]); 1771 end; 1772 1773 complete:= Loop>=FirstSurplusLoop[Cat]; 1774 for i:=nModelOrder-1 downto 0 do 1775 begin 1776 for Fortified:=true downto false do 1777 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1778 if (mix=ModelOrder[i]) 1779 and (Loc>=0) and (Destination[uix]<0) and (Master<0) 1780 and ((Flags and unFortified<>0) = Fortified) 1781 and (LocNeed[Loc]>0) then 1782 begin 1783 LocNeed[Loc]:=0; 1784 if (District[Loc]>=0) and (District[Loc]<maxCOD) then 1785 dec(DistrictNeed[District[Loc]]); 1786 Destination[uix]:=Loc; 1787 complete:=false; 1788 end; 1789 1790 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1791 if (mix=ModelOrder[i]) 1792 and (Loc>=0) and (Destination[uix]<0) and (Master<0) then 1793 if (District[Loc]>=0) and (District[Loc]<maxCOD) 1794 and (DistrictNeed[District[Loc]]=0) then 1795 else 1796 begin // unassigned unit 1797 FindDestination(uix); 1798 if Destination[uix]>=0 then complete:=false; 1799 end; 1800 end; 1801 inc(Loop) 1802 until complete; 1803 end; 1804 1805 // distribute obsolete settlers 1806 repeat 1807 fillchar(LocNeed, MapSize, 0); 1808 fillchar(DistrictNeed, sizeof(DistrictNeed), 0); 1809 1810 for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then 1811 if (Built[imSewer]>0) 1812 or (Built[imAqueduct]>0) and (Size<=NeedSewerSize-2) 1813 or (Size<=NeedAqueductSize-2) 1814 or (Project=mixSettlers) then 1815 begin 1816 LocNeed[Loc]:=1; 1817 if (District[Loc]>=0) and (District[Loc]<maxCOD) then 1818 inc(DistrictNeed[District[Loc]]); 1819 end; 1820 DistrictNeed0:=DistrictNeed; 1821 1822 complete:=true; 1823 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1824 if (Loc>=0) and (Destination[uix]<0) and (Master<0) then 1825 if (MyModel[mix].Kind=mkSettler) and (mix<>mixSettlers) 1826 and (Job=jNone) then 1827 if (District[Loc]>=0) and (District[Loc]<maxCOD) 1828 and (DistrictNeed[District[Loc]]=0) then 1829 begin 1830 if DistrictNeed0[District[Loc]]>0 then 1831 complete:=false 1832 end 1833 else 1834 begin // unassigned unit 1835 FindDestination(uix); 1836 // if (Destination[uix]<0) and (RO.Territory[Loc]=me) then 1837 // complete:=false; // causes hangup when unit can't move due to zoc 1838 end; 1839 until complete; 1840 1841 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do if Loc>=0 then 1842 if Destination[uix]<0 then 1843 begin 1844 if (MyModel[mix].Kind<>mkSettler) and (MyModel[mix].Kind<>mkSlaves) 1845 and (Master<0) and (Map[Loc] and fCity=0) then 1846 Unit_MoveEx(uix, maNextCity); 1847 end 1848 else if (Destination[uix]<>PatrolDestination) and (Loc<>Destination[uix]) then 1849 Unit_MoveEx(uix, Destination[uix]); 1850 1851 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 1852 if (Loc>=0) and (RO.Territory[Loc]=me) 1853 and (District[Loc]>=0) and (District[Loc]<maxCOD) 1854 and (ModelQuality[mix]>0) then 1855 case ModelCat[mix] of 1856 mctGroundDefender,mctGroundAttacker: 1857 dec(UnitLack[District[Loc],ModelCat[mix]]) 1858 end; 1859 end; // MoveUnitsHome 1860 1861 1862 procedure TAI.CheckAttack(uix: integer); 1863 var 1864 AttackScore,BestCount,AttackLoc,TestLoc,NextLoc,TestTime,V8, 1865 TestScore,euix,MyDamage,EnemyDamage,OldLoc, 1866 AttackForecast,MoveResult,AttackResult,MoveStyle,NextTime,RecoverTurns: integer; 1867 Tile: Cardinal; 1868 Exhausted: boolean; 1869 Adjacent: TVicinity8Loc; 1870 Reached: array[0..lxmax*lymax-1] of boolean; 1871 1872 begin 1873 with MyUnit[uix] do 1874 begin 1875 MoveStyle:=GetMyMoveStyle(mix,Health); 1876 repeat 1877 AttackScore:=-999999; 1878 AttackLoc:=-1; 1879 fillchar(Reached, MapSize, false); 1880 Pile.Create(MapSize); 1881 Pile.Put(Loc, $800-Movement); // start search for something to do at current location 1882 while Pile.Get(TestLoc,TestTime) do 1883 begin 1884 TestScore:=0; 1885 Tile:=Map[TestLoc]; 1886 Reached[TestLoc]:=true; 1887 1888 if ((Tile and fUnit)<>0) and ((Tile and fOwned)=0) then 249 1889 begin // enemy unit 250 Unit_FindEnemyDefender(TestLoc, euix);251 if RO.Treaty[RO.EnemyUn[euix].Owner] < trPeace then252 begin // unfriendly unit -- check attack253 if Unit_AttackForecast(uix, TestLoc, 100,AttackForecast) then1890 assert(TestTime<$1000); 1891 Unit_FindEnemyDefender(TestLoc,euix); 1892 if RO.Treaty[RO.EnemyUn[euix].Owner]<trPeace then 1893 if Unit_AttackForecast(uix,TestLoc,$800-TestTime,AttackForecast) then 254 1894 begin // attack possible, but advantageous? 255 if AttackForecast >0 then1895 if AttackForecast=0 then 256 1896 begin // enemy unit would be destroyed 257 MyDamage := Health - AttackForecast;258 EnemyDamage := RO.EnemyUn[euix].Health +DestroyBonus;1897 MyDamage:=Health+DestroyBonus; 1898 EnemyDamage:=RO.EnemyUn[euix].Health+DestroyBonus; 259 1899 end 260 else // own unit would be destroyed 1900 else if AttackForecast>0 then 1901 begin // enemy unit would be destroyed 1902 MyDamage:=Health-AttackForecast; 1903 EnemyDamage:=RO.EnemyUn[euix].Health+DestroyBonus; 1904 end 1905 else // own unit would be destroyed 261 1906 begin 262 MyDamage := Health +DestroyBonus;263 EnemyDamage := RO.EnemyUn[euix].Health +AttackForecast;1907 MyDamage:=Health+DestroyBonus; 1908 EnemyDamage:=RO.EnemyUn[euix].Health+AttackForecast; 264 1909 end; 265 TestScore := Aggressive * 2 * 266 (EnemyDamage * RO.EnemyModel[RO.EnemyUn[euix].emix].Cost) 267 div (MyDamage * MyModel[mix].Cost); 268 if TestScore <= 100 then 269 TestScore := 0 // own losses exceed enemy losses, no good 270 else 1910 TestScore:=Aggressive*2 1911 *(EnemyDamage*RO.EnemyModel[RO.EnemyUn[euix].emix].Cost) 1912 div (MyDamage*MyModel[mix].Cost); 1913 if TestScore<=100 then TestScore:=0 // own losses exceed enemy losses, no good 1914 else 271 1915 begin 272 TestScore := (TestScore - 100) div 10 + 30; 273 TestTask := utAttack 1916 if TestScore>AttackScore then 1917 BestCount:=0; 1918 if TestScore>=AttackScore then 1919 begin 1920 inc(BestCount); 1921 if random(BestCount)=0 then 1922 begin 1923 AttackScore:=TestScore; 1924 AttackLoc:=TestLoc; 1925 end 1926 end; 274 1927 end 275 end 276 end 1928 end; 277 1929 end // enemy unit 278 1930 279 else if ((Tile and fCity) <> 0) and ((Tile and fOwned) = 0) then 280 begin // enemy city, empty or unobserved 281 if (MyModel[mix].Domain = dGround) 282 // ships of this AI have no long-range guns, so don't try to attack cities with them 283 and ((RO.Territory[TestLoc] < 0) 284 // happens only for unobserved cities of extinct tribes, new owner unknown 285 or (RO.Treaty[RO.Territory[TestLoc]] < trPeace)) then 286 begin // unfriendly city -- check attack/capture 287 if (Tile and fObserved) <> 0 then 288 begin // observed and no unit present -- city is undefended, capture! 289 TestScore := 40; 290 TestTask := utCapture 291 end 292 else if Role = Roam then 293 begin // unobserved city, possibly defended -- go for attack 294 TestScore := 30; 295 TestTask := utPatrol 296 end 297 end 298 end // enemy city, empty or unobserved 299 1931 else if ((Tile and fCity)<>0) and ((Tile and fOwned)=0) then 1932 // enemy city 1933 1934 else 1935 begin // no enemy city or unit here 1936 V8_to_Loc(TestLoc,Adjacent); 1937 for V8:=0 to 7 do 1938 begin 1939 NextLoc:=Adjacent[V8]; 1940 if (NextLoc>=0) and not Reached[NextLoc] 1941 and (Map[NextLoc] and fTerrain<>fUNKNOWN) then 1942 if Map[NextLoc] and (fUnit or fOwned)=fUnit then 1943 Pile.Put(NextLoc, TestTime) // foreign unit! 1944 else case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime, 1945 RecoverTurns, Map[Loc], Map[NextLoc], true) of 1946 csOk,csCheckTerritory: 1947 if NextTime<$1000 then Pile.Put(NextLoc, NextTime); 1948 csForbiddenTile: 1949 Reached[NextLoc]:=true; // don't check moving there again 1950 end 1951 end; 1952 end; // no enemy city or unit here 1953 end; // while Pile.Get 1954 Pile.Free; 1955 1956 if AttackLoc>=0 then 1957 begin 1958 OldLoc:=Loc; 1959 MoveResult:=Unit_Move(uix,AttackLoc); 1960 Exhausted:= (Loc=OldLoc) 1961 or ((MoveResult and (rMoreTurns or rUnitRemoved))<>0); 1962 if MoveResult and rLocationReached<>0 then 1963 if Movement<100 then 1964 Exhausted:=true 300 1965 else 1966 begin 1967 AttackResult:=Unit_Attack(uix,AttackLoc); 1968 Exhausted:= ((AttackResult and rExecuted)=0) 1969 or ((AttackResult and rUnitRemoved)<>0); 1970 end; 1971 end 1972 else Exhausted:=true; 1973 until Exhausted; 1974 end; 1975 end; // CheckAttack 1976 1977 1978 procedure TAI.Patrol(uix: integer); 1979 const 1980 DistanceScore=4; 1981 var 1982 PatrolScore,BestCount,PatrolLoc,TestLoc,NextLoc,TestTime,V8, 1983 TestScore,OldLoc,MoveResult,MoveStyle,NextTime,RecoverTurns: integer; 1984 Tile: Cardinal; 1985 Exhausted,CaptureOnly: boolean; 1986 Adjacent: TVicinity8Loc; 1987 AdjacentUnknown: array[0..lxmax*lymax-1] of shortint; 1988 1989 begin 1990 with MyUnit[uix] do 1991 begin 1992 CaptureOnly:= ((100-Health)*Terrain[Map[Loc] and fTerrain].Defense>60) 1993 and not (Map[Loc] and fTerrain in [fOcean, fShore, fArctic, fDesert]); 1994 MoveStyle:=GetMyMoveStyle(mix, Health); 1995 repeat 1996 PatrolScore:=-999999; 1997 PatrolLoc:=-1; 1998 FillChar(AdjacentUnknown,MapSize,$FF); // -1, indicates tiles not checked yet 1999 Pile.Create(MapSize); 2000 Pile.Put(Loc, $800-Movement); 2001 while Pile.Get(TestLoc,TestTime) do 2002 begin 2003 if (50*$1000-DistanceScore*TestTime<=PatrolScore) // assume a score of 50 is the best achievable 2004 or CaptureOnly and (TestTime>=$1000) then 2005 break; 2006 2007 TestScore:=0; 2008 Tile:=Map[TestLoc]; 2009 AdjacentUnknown[TestLoc]:=0; 2010 2011 if ((Tile and fUnit)<>0) and ((Tile and fOwned)=0) then 2012 // enemy unit 2013 2014 else if ((Tile and fCity)<>0) and ((Tile and fOwned)=0) then 2015 begin 2016 if ((Tile and fObserved)<>0) 2017 and (MyModel[mix].Domain=dGround) and (MyModel[mix].Attack>0) 2018 and ((RO.Territory[TestLoc]<0) // happens only for unobserved cities of extinct tribes, new owner unknown 2019 or (RO.Treaty[RO.Territory[TestLoc]]<trPeace)) then 2020 TestScore:=40 // unfriendly undefended city -- capture! 2021 end 2022 2023 else 301 2024 begin // no enemy city or unit here 302 // add surrounding tiles to queue, but only if there's a chance to beat BestScore 303 if 50 - DistanceScore * (TestDistance + 1) >= BestScore then 304 // assume a score of 50 is the best achievable 2025 V8_to_Loc(TestLoc,Adjacent); 2026 for V8:=0 to 7 do 305 2027 begin 306 V8_to_Loc(TestLoc, Adjacent); 307 for V8 := 0 to 7 do 2028 NextLoc:=Adjacent[V8]; 2029 if (NextLoc>=0) and (AdjacentUnknown[NextLoc]<0) then 2030 if Map[NextLoc] and fTerrain=fUNKNOWN then 2031 inc(AdjacentUnknown[TestLoc]) 2032 else if Formation[NextLoc]=Formation[TestLoc] then 2033 case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime, RecoverTurns, Map[TestLoc], Map[NextLoc], true) of 2034 csOk: 2035 Pile.Put(NextLoc, NextTime); 2036 csForbiddenTile: 2037 AdjacentUnknown[NextLoc]:=0; // don't check moving there again 2038 csCheckTerritory: 2039 if RO.Territory[NextLoc]=RO.Territory[TestLoc] then 2040 Pile.Put(NextLoc, NextTime); 2041 end 2042 end; 2043 if not CaptureOnly then 2044 if AdjacentUnknown[TestLoc]>0 then 2045 TestScore:=20+AdjacentUnknown[TestLoc] 2046 else TestScore:=(RO.Turn-RO.MapObservedLast[TestLoc]) div 16; 2047 end; // no enemy city or unit here 2048 2049 if TestScore>0 then 2050 begin 2051 TestScore:=TestScore*$1000-DistanceScore*TestTime; 2052 if TestScore>PatrolScore then 2053 BestCount:=0; 2054 if TestScore>=PatrolScore then 2055 begin 2056 inc(BestCount); 2057 if random(BestCount)=0 then 308 2058 begin 309 NextLoc := Adjacent[V8]; 310 if (NextLoc >= 0) and (NextLoc < MapSize) and 311 (AdjacentUnknown[NextLoc] < 0) then // tile not checked yet 312 begin 313 TerrType := Map[NextLoc] and fTerrain; 314 if TerrType = fUNKNOWN then 315 inc(AdjacentUnknown[TestLoc]) 316 else 317 begin 318 case MyModel[mix].Domain of 319 dGround: 320 begin 321 TerrOwner := RO.Territory[NextLoc]; 322 if (TerrType >= fGrass) and (TerrType <> fArctic) 323 // terrain can be walked 324 and ((TerrOwner < 0) or (TerrOwner = me) or 325 (RO.Treaty[TerrOwner] < trPeace)) 326 // no peace treaty violated 327 and (((Map[NextLoc] and (fUnit or fCity)) <> 0) or 328 (Map[TestLoc] and Map[NextLoc] and fInEnemyZoC = 0)) 329 then // no ZoC violated 330 begin // yes, consider walking this tile 331 if TerrType = fMountains then 332 StepSize := 2 // mountains cause delay 333 else 334 StepSize := 1 335 end 336 else 337 StepSize := 0 // no, don't walk here 338 end; 339 dSea: 340 if TerrType = fShore then 341 // ships of this AI can only move along shore 342 StepSize := 1 343 else 344 StepSize := 0; 345 dAir: 346 StepSize := 1; 347 end; 348 if StepSize > 0 then 349 Pile.Put(NextLoc, TestDistance + StepSize) 350 end 351 end; 352 end; 353 end; 354 if Role = Defend then 355 TestScore := 0 // don't discover/patrol 356 else if AdjacentUnknown[TestLoc] > 0 then 357 begin 358 TestScore := 20 + AdjacentUnknown[TestLoc]; 359 TestTask := utDiscover 360 end 361 else 362 begin 363 TestScore := (RO.Turn - RO.MapObservedLast[TestLoc]) div 10; 364 TestTask := utPatrol 365 end 366 end; // no enemy city or unit here 367 368 if TestScore > 0 then 369 begin 370 TestScore := TestScore - DistanceScore * TestDistance; 371 if TestScore > BestScore then 372 BestCount := 0; 373 if TestScore >= BestScore then 374 begin 375 inc(BestCount); 376 if random(BestCount) = 0 then 377 begin 378 BestScore := TestScore; 379 BestLoc := TestLoc; 380 BestTask := TestTask; 2059 PatrolScore:=TestScore; 2060 PatrolLoc:=TestLoc; 381 2061 end 382 2062 end; 383 2063 end 384 end; 385 386 if (BestTask = utNone) and ((Map[Loc] and fCity) = 0) then 387 begin // nothing to do, move home 388 if Home >= 0 then 389 BestLoc := MyCity[Home].Loc 390 else 391 BestLoc := maNextCity; 392 BestTask := utGoHome; 393 end; 394 if BestTask <> utNone then 2064 end; // while Pile.Get 2065 Pile.Free; 2066 2067 if PatrolLoc>=0 then 395 2068 begin // attack/capture/discover/patrol task found, execute it 396 OldLoc := Loc; 397 MoveResult := Unit_Move(uix, BestLoc); 398 Exhausted := (Loc = OldLoc) or 399 ((MoveResult and (rMoreTurns or rUnitRemoved)) <> 0); 400 if (BestTask = utAttack) and ((MoveResult and rLocationReached) <> 0) 401 then 402 if Movement < 100 then 403 Exhausted := true 404 else 405 begin 406 AttackResult := Unit_Attack(uix, BestLoc); 407 Exhausted := ((AttackResult and rExecuted) = 0) or 408 ((AttackResult and rUnitRemoved) <> 0); 409 end; 410 if not Exhausted then 411 Exhausted := (Movement < 100) and 412 ((Map[Loc] and (fRoad or fRR or fRiver or fCity)) = 0); 413 // no road, too few movement points for further movement 414 end 415 else 416 Exhausted := true; 417 until Exhausted; 418 Pile.Free; 419 end; // ProcessUnit 420 421 // SetCityProduction: choose production of each city 2069 OldLoc:=Loc; 2070 MoveResult:=Unit_Move(uix,PatrolLoc); 2071 Exhausted:= (Loc=OldLoc) 2072 or ((MoveResult and (rMoreTurns or rUnitRemoved))<>0); 2073 end 2074 else Exhausted:=true; 2075 until Exhausted; 2076 end; 2077 end; // Patrol 2078 2079 procedure TAI.AttackAndPatrol; 2080 const 2081 nAttackCatOrder=3; 2082 AttackCatOrder: array[0..nAttackCatOrder-1] of integer= 2083 (mctGroundAttacker, mctCruiser, mctGroundDefender); 2084 var 2085 iCat,uix,uix1: integer; 2086 IsPatrolUnit,Fortified: boolean; 2087 begin 2088 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do // utilize militia 2089 if (Loc>=0) and (mix=mixMilitia) 2090 and ((Formation[Loc]<0) or (Formation[Loc]>=maxCOD) 2091 or (ContinentPresence[Formation[Loc]] and PresenceUnknown=0)) then 2092 Unit_Disband(uix); 2093 2094 if RO.nEnemyUn>0 then 2095 for iCat:=0 to nAttackCatOrder-1 do 2096 for Fortified:=false to true do 2097 for uix:=RO.nUn-1 downto 0 do with MyUnit[uix] do 2098 if (Loc>=0) and (ModelCat[mix]=AttackCatOrder[iCat]) 2099 and (MyModel[mix].Attack>0) 2100 and ((Flags and unFortified<>0) = Fortified) then 2101 CheckAttack(uix); 2102 2103 fillchar(uixPatrol, sizeof(uixPatrol), $FF); 2104 for uix:=0 to RO.nUn-1 do with MyUnit[uix],MyModel[mix] do 2105 if (Loc>=0) and (Domain=dGround) and (Attack>0) and (Speed>=250) 2106 and (Map[Loc] and fTerrain>=fGrass) 2107 and (Formation[Loc]>=0) and (Formation[Loc]<maxCOD) 2108 and ((uixPatrol[Formation[Loc]]<0) 2109 or (MyUnit[uix].ID<MyUnit[uixPatrol[Formation[Loc]]].ID)) then 2110 uixPatrol[Formation[Loc]]:=uix; 2111 2112 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do if Loc>=0 then 2113 begin 2114 if mix=mixMilitia then 2115 if (RO.nUn<3) and (RO.nCity=1) or (Map[Loc] and fCity=0) then 2116 IsPatrolUnit:=true 2117 else 2118 begin // militia 2119 IsPatrolUnit:=false; 2120 for uix1:=0 to RO.nUn-1 do 2121 if (uix1<>uix) and (MyUnit[uix1].Loc=Loc) 2122 and (MyUnit[uix1].mix<>mixSettlers) then 2123 IsPatrolUnit:=true 2124 end 2125 else IsPatrolUnit:=(mix=mixCruiser) 2126 or (Map[Loc] and fTerrain>=fGrass) 2127 and (Formation[Loc]>=0) and (Formation[Loc]<maxCOD) 2128 and (uix=uixPatrol[Formation[Loc]]); 2129 if IsPatrolUnit then Patrol(uix); 2130 end 2131 end; // AttackAndPatrol 2132 2133 2134 function TAI.HavePort: boolean; 2135 var 2136 V8, cix,AdjacentLoc,f: integer; 2137 Adjacent: TVicinity8Loc; 2138 begin 2139 result:=false; 2140 for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then 2141 begin 2142 V8_to_Loc(Loc,Adjacent); 2143 for V8:=0 to 7 do 2144 begin 2145 AdjacentLoc:=Adjacent[V8]; 2146 if (AdjacentLoc>=0) and ((Map[AdjacentLoc] and fTerrain)<fGrass) then 2147 begin 2148 f:=Formation[AdjacentLoc]; 2149 if (f>=0) and (f<maxCOD) and (OceanPresence[f] and not (1 shl me)<>0) then 2150 result:=true; 2151 end 2152 end; 2153 end 2154 end; 2155 2156 422 2157 procedure TAI.SetCityProduction; 423 2158 var 424 cix, mix, mixSettler, mixShip, mixArmy, V8, NewImprovement, count, wix, 425 AdjacentLoc: integer; 426 IsPort: boolean; 427 Adjacent: TVicinity8Loc; 428 Report: TCityReport; 2159 uix,cix,iix,dtr,V8,V21,NewImprovement,AdjacentLoc,MaxSettlers, 2160 maxcount,cixMilAcademy: integer; 2161 TerrType: cardinal; 2162 IsPort,IsNavalBase,NeedCruiser,CheckProd,Destructed,ProduceSettlers,ProduceMil: boolean; 2163 Adjacent: TVicinity8Loc; 2164 Radius: TVicinity21Loc; 2165 Report: TCityReport; 2166 HomeCount, CityProdRep: array[0..nCmax-1] of integer; 2167 MilProdCity: array[0..nCmax-1] of boolean; 429 2168 430 2169 procedure TryBuild(Improvement: integer); 431 2170 begin 432 if (NewImprovement < 0) // already improvement of higher priority found 433 and (MyCity[cix].Built[Improvement] = 0) // not built yet 434 and City_Improvable(cix, Improvement) then 435 NewImprovement := Improvement; 2171 if (NewImprovement=imTrGoods) // not already improvement of higher priority found 2172 and (MyCity[cix].Built[Improvement]=0) // not built yet 2173 and ((Imp[Improvement].Preq=preNone) 2174 or (RO.Tech[Imp[Improvement].Preq]>=tsApplicable)) 2175 and City_Improvable(cix, Improvement) then 2176 NewImprovement:=Improvement; 2177 end; 2178 2179 procedure TryDestruct(Improvement: integer); 2180 begin 2181 if Destructed or (MyCity[cix].Built[Improvement]=0) then exit; 2182 if City_CurrentImprovementProject(cix)>=0 then 2183 City_RebuildImprovement(cix,Improvement) 2184 else City_SellImprovement(cix, Improvement); 2185 { if (CurrentImprovementProject>=0) 2186 and (Imp[CurrentImprovementProject].Kind in [ikCommon,ikNatGlobal,ikNatLocal]) 2187 and ((Imp[CurrentImprovementProject].Cost*3-Imp[Improvement].Cost*2) 2188 *BuildCostMod[G.Difficulty[me]]>MyCity[cix].Prod*(12*3)) then} 2189 Destructed:=true 2190 end; 2191 2192 function ChooseBuildModel(Cat: integer): integer; 2193 var 2194 count, mix: integer; 2195 begin 2196 count:=0; 2197 for mix:=0 to RO.nModel-1 do 2198 if (ModelCat[mix]=Cat) 2199 and (ModelQuality[mix]>=ModelBestQuality[Cat]-MaxBuildWorseThanBestModel) then 2200 begin inc(count); if random(count)=0 then result:=mix end; 2201 assert(count>0); 2202 end; 2203 2204 procedure NominateMilProdCities; 2205 // find military production cities 2206 var 2207 cix, Total, d, Threshold, NewThreshold, Share, SharePlus, cixWorst: integer; 2208 begin 2209 fillchar(MilProdCity, RO.nCity, 0); 2210 GetCityProdPotential; 2211 for d:=0 to maxCOD-1 do 2212 begin 2213 Total:=0; 2214 for cix:=0 to RO.nCity-1 do with MyCity[cix] do 2215 if (Loc>=0) and (District[Loc]=d) then 2216 Total:=Total+CityResult[cix]; 2217 if Total=0 then continue; // district does not exist 2218 2219 Share:=0; 2220 cixWorst:=-1; 2221 for cix:=0 to RO.nCity-1 do with MyCity[cix] do 2222 if (Loc>=0) and (District[Loc]=d) 2223 and (Built[imBarracks]+Built[imMilAcademy]>0) then 2224 begin 2225 MilProdCity[cix]:=true; 2226 inc(Share,CityResult[cix]); 2227 if (cixWorst<0) or (CityResult[cix]<CityResult[cixWorst]) then 2228 cixWorst:=cix 2229 end; 2230 2231 Threshold:=$FFFF; 2232 while (Threshold>0) and (Share<Total*MilProdShare div 100) do 2233 begin 2234 NewThreshold:=-1; 2235 for cix:=0 to RO.nCity-1 do with MyCity[cix] do 2236 if (Loc>=0) and (District[Loc]=d) 2237 and (Built[imBarracks]+Built[imMilAcademy]=0) and (Built[imObservatory]=0) 2238 and (CityResult[cix]<Threshold) 2239 and (CityResult[cix]>=NewThreshold) then 2240 if CityResult[cix]>NewThreshold then 2241 begin 2242 NewThreshold:=CityResult[cix]; 2243 SharePlus:=CityResult[cix] 2244 end 2245 else inc(SharePlus,CityResult[cix]); 2246 Threshold:=NewThreshold; 2247 inc(Share,SharePlus); 2248 end; 2249 2250 for cix:=0 to RO.nCity-1 do with MyCity[cix] do 2251 if (Loc>=0) and (District[Loc]=d) 2252 and (Built[imBarracks]+Built[imMilAcademy]=0) 2253 and (CityResult[cix]>=Threshold) then 2254 MilProdCity[cix]:=true; 2255 { if (cixWorst>=0) 2256 and (Share-CityResult[cixWorst]*2>=Total*MilProdShare div 100) then 2257 MilProdCity[cixWorst]:=false;} 2258 end; 2259 2260 // check best city for military academy 2261 cixMilAcademy:=cixStateImp[imMilAcademy]; 2262 if cixStateImp[imPalace]>=0 then 2263 begin 2264 d:=District[MyCity[cixStateImp[imPalace]].Loc]; 2265 if (d>=0) and (d<maxCOD) then 2266 begin 2267 cixMilAcademy:=-1; 2268 for cix:=0 to RO.nCity-1 do with MyCity[cix] do 2269 if (Loc>=0) and (District[Loc]=d) 2270 and (Built[imObservatory]+Built[imPalace]=0) 2271 and ((cixMilAcademy<0) or (CityResult[cix]>CityResult[cixMilAcademy])) then 2272 cixMilAcademy:=cix; 2273 end; 2274 if (cixMilAcademy>=0) and (cixStateImp[imMilAcademy]>=0) 2275 and (cixMilAcademy<>cixStateImp[imMilAcademy]) 2276 and (MyCity[cixStateImp[imMilAcademy]].Built[imObservatory]=0) 2277 and (CityResult[cixMilAcademy]<=CityResult[cixStateImp[imMilAcademy]]*3 div 2) then 2278 cixMilAcademy:=cixStateImp[imMilAcademy] // because not so much better 2279 end 2280 end; 2281 2282 procedure ChangeHomeCities; 2283 var 2284 uix,NewHome,HomeSupport,NewHomeSupport,SingleSupport: integer; 2285 begin 2286 if RO.Government in [gAnarchy, gFundamentalism] then exit; 2287 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 2288 if (Loc>=0) and (Home>=0) and (Map[Loc] and fCity<>0) 2289 and (MyCity[Home].Loc<>Loc) and (MyModel[mix].Kind<>mkSettler) then 2290 begin 2291 City_FindMyCity(Loc, NewHome); 2292 case RO.Government of 2293 gDespotism: 2294 begin 2295 HomeSupport:=HomeCount[Home]-MyCity[Home].Size; 2296 NewHomeSupport:=HomeCount[NewHome]-MyCity[NewHome].Size; 2297 end; 2298 gMonarchy, gCommunism: 2299 begin 2300 HomeSupport:=HomeCount[Home]-MyCity[Home].Size div 2; 2301 NewHomeSupport:=HomeCount[NewHome]-MyCity[NewHome].Size div 2; 2302 end; 2303 else 2304 begin 2305 HomeSupport:=HomeCount[Home]; 2306 NewHomeSupport:=HomeCount[NewHome]; 2307 end; 2308 end; 2309 if HomeSupport>0 then 2310 begin 2311 if MyModel[mix].Flags and mdDoubleSupport=0 then SingleSupport:=1 2312 else SingleSupport:=2; 2313 HomeSupport:=HomeSupport-SingleSupport; 2314 NewHomeSupport:=NewHomeSupport+SingleSupport; 2315 if HomeSupport<0 then HomeSupport:=0; 2316 if NewHomeSupport<0 then NewHomeSupport:=0; 2317 if (NewHomeSupport<=0) 2318 or (CityProdRep[Home]-HomeSupport<=CityProdRep[NewHome]-NewHomeSupport) then 2319 begin 2320 dec(HomeCount[Home],SingleSupport); 2321 inc(HomeCount[NewHome],SingleSupport); 2322 Unit_SetHomeHere(uix) 2323 end 2324 end 2325 end 436 2326 end; 437 2327 438 2328 begin 439 // only produce newest models 440 mixSettler := -1; 441 mixArmy := -1; 442 mixShip := -1; 443 for mix := 0 to RO.nModel - 1 do 444 with MyModel[mix] do 445 if Kind = mkSettler then 446 mixSettler := mix 447 else if (Domain = dGround) and (Kind < mkSpecial_TownGuard) then 448 mixArmy := mix 449 else if Domain = dSea then 450 mixShip := mix; 451 452 for cix := 0 to RO.nCity - 1 do 453 with MyCity[cix] do 454 if (RO.Turn = 0) or ((Flags and chProduction) <> 0) 455 // city production complete 456 or not City_HasProject(cix) then 2329 fillchar(HomeCount, 4*RO.nCity, 0); 2330 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do 2331 if (Loc>=0) and (Home>=0) then 2332 if MyModel[mix].Flags and mdDoubleSupport=0 then 2333 inc(HomeCount[Home]) 2334 else inc(HomeCount[Home],2); 2335 2336 NominateMilProdCities; 2337 2338 for cix:=0 to RO.nCity-1 do with MyCity[cix] do 2339 if (Loc>=0) and (Flags and chCaptured=0) and (District[Loc]>=0) then 2340 begin 2341 if size<4 then 2342 City_OptimizeTiles(cix,rwMaxGrowth) 2343 else City_OptimizeTiles(cix,rwForceProd); 2344 2345 City_GetReport(cix, Report); 2346 CityProdRep[cix]:=Report.ProdRep; 2347 2348 Destructed:=false; 2349 CheckProd:= (RO.Turn=0) or ((Flags and chProduction)<>0) // city production complete 2350 or not City_HasProject(cix); 2351 if not CheckProd then 2352 begin // check whether producing double state improvement or wonder 2353 iix:=City_CurrentImprovementProject(cix); 2354 if (iix>=0) 2355 and (((Imp[iix].Kind in [ikNatLocal,ikNatGlobal]) and (RO.NatBuilt[iix]>0)) 2356 or ((Imp[iix].Kind=ikWonder) and (RO.Wonder[iix].CityID<>-1))) then 2357 CheckProd:=true; 2358 end; 2359 if CheckProd then 457 2360 begin // check production 458 IsPort := false; 459 V8_to_Loc(Loc, Adjacent); 460 for V8 := 0 to 7 do 461 begin 462 AdjacentLoc := Adjacent[V8]; 463 if (AdjacentLoc >= 0) and (AdjacentLoc < MapSize) and 464 ((Map[AdjacentLoc] and fTerrain) = fShore) then 465 IsPort := true; // shore tile at adjacent location -- city is port! 2361 IsPort:=false; 2362 IsNavalBase:=false; 2363 NeedCruiser:=false; 2364 V8_to_Loc(Loc,Adjacent); 2365 for V8:=0 to 7 do 2366 begin 2367 AdjacentLoc:=Adjacent[V8]; 2368 if (AdjacentLoc>=0) and ((Map[AdjacentLoc] and fTerrain)<fGrass) then 2369 begin 2370 IsPort:=true; // shore tile at adjacent location -- city is port! 2371 if (Formation[AdjacentLoc]>=0) and (Formation[AdjacentLoc]<maxCOD) 2372 and (OceanPresence[Formation[AdjacentLoc]] and WarNations<>0) then 2373 begin 2374 IsNavalBase:=true; 2375 if (1 shl Formation[AdjacentLoc]) and OceanWithShip=0 then 2376 NeedCruiser:=true 2377 end 2378 end 466 2379 end; 467 City_GetReport(cix, Report); 468 469 if (Report.Support = 0) or (SupportFree[RO.Government] < 2) and 470 (Report.Support < Report.ProdRep div 2) then 471 begin // enough material to support more units 472 if (RO.Turn > 4) and 473 ((Report.Eaten - Size * 2) div SettlerFood[RO.Government] < 474 Size div 4) then 475 // less than 1 settler per 4 citizens -- produce more! 476 City_StartUnitProduction(cix, mixSettler) 477 else if IsPort and (mixShip >= 0) and (random(2) = 0) then 478 City_StartUnitProduction(cix, mixShip) 479 else 480 City_StartUnitProduction(cix, mixArmy) 2380 2381 if RO.Turn=0 then 2382 begin 2383 NewImprovement:=-1; 2384 City_StartUnitProduction(cix,mixMilitia); // militia 481 2385 end 482 else 483 begin // check for building a city improvement 484 NewImprovement := -1; 485 if Built[imPalace] + Built[imCourt] + Built[imTownHall] = 0 then 2386 else NewImprovement:=imTrGoods; 2387 2388 dtr:=District[Loc]; // formation of city 2389 2390 if NewImprovement=imTrGoods then 2391 begin 2392 if (Built[imPalace]+Built[imCourt]+Built[imTownHall]=0) then 2393 TryBuild(imTownHall); 2394 end; 2395 2396 if (NewImprovement=imTrGoods) 2397 and (RO.Government=gDespotism) and (Report.Support=0) then 2398 begin // produce town guard 2399 NewImprovement:=-1; 2400 City_StartUnitProduction(cix,mixTownGuard); 2401 end; 2402 2403 if NewImprovement=imTrGoods then 2404 begin 2405 if RO.Government=gDespotism then maxcount:=Size 2406 else maxcount:=Size div 2; 2407 2408 if IsResearched(adRailroad) and (mixSettlers=0) // better wait for engineers 2409 or (Built[imColosseum]+Built[imObservatory]>0) then 2410 MaxSettlers:=1 2411 else MaxSettlers:=(Size+2) div 6; 2412 ProduceSettlers:=(HomeCount[cix]<maxcount+Size div 2) 2413 and ((Report.Eaten-Size*2) div SettlerFood[RO.Government]<MaxSettlers) 2414 and ((dtr<0) or (dtr>=maxCOD) or (SettlerSurplus[dtr]<=0)); 2415 2416 ProduceMil:=(HomeCount[cix]<maxcount+Size div 2) 2417 and (Built[imBarracks]+Built[imMilAcademy]>0) 2418 and ((ModelBestQuality[mctGroundDefender]>0) 2419 or (ModelBestQuality[mctGroundAttacker]>0)) 2420 and ((dtr<maxCOD) 2421 and ((UnitLack[dtr,mctGroundAttacker]>0) 2422 or (UnitLack[dtr,mctGroundDefender]>0)) 2423 or (HomeCount[cix]<maxcount)); 2424 2425 if ProduceMil or not ProduceSettlers and (HomeCount[cix]<maxcount) then 486 2426 begin 487 TryBuild(imCourt); 488 TryBuild(imTownHall); 2427 NewImprovement:=-1; 2428 if (dtr>=maxCOD) 2429 or (ModelBestQuality[mctGroundDefender]=0) 2430 or (UnitLack[dtr,mctGroundAttacker] 2431 >=UnitLack[dtr,mctGroundDefender]) then 2432 City_StartUnitProduction(cix,ChooseBuildModel(mctGroundAttacker)) 2433 else City_StartUnitProduction(cix,ChooseBuildModel(mctGroundDefender)) 2434 end 2435 else if ProduceSettlers then 2436 begin 2437 NewImprovement:=-1; 2438 City_StartUnitProduction(cix,mixSettlers); 2439 end 2440 end; 2441 2442 if NewImprovement>=0 then 2443 begin // produce improvement 2444 if (RO.Turn>=40) and (Report.Happy*2<=Size) 2445 and (Built[imColosseum]=0) then 2446 TryBuild(imTemple); 2447 if cix=cixMilAcademy then 2448 TryBuild(imMilAcademy) 2449 else if ((Built[imPalace]>0) or MilProdCity[cix] and (Built[imTemple]>0)) 2450 and (Built[imObservatory]=0) then 2451 TryBuild(imBarracks); 2452 if Report.Trade-Report.Corruption>=11 then 2453 TryBuild(imLibrary); 2454 if Report.Trade-Report.Corruption>=11 then 2455 TryBuild(imMarket); 2456 if (Report.Trade-Report.Corruption>=11) and (Report.Happy>=4) then 2457 TryBuild(imUniversity); 2458 if (Built[imPalace]>0) and (Report.Trade-Report.Corruption>=11) 2459 and (Report.Happy>=4) and (RO.NatBuilt[imObservatory]=0) then 2460 TryBuild(imObservatory); // always build observatory in capital 2461 if (Report.Trade-Report.Corruption>=15) and (Report.Happy>=4) then 2462 TryBuild(imResLab); 2463 if (Size>=9) and (Built[imPalace]+Built[imCourt]>0) then 2464 TryBuild(imHighways); 2465 if (RO.Government<>gDespotism) and (Report.Happy*2<=Size) 2466 and (Built[imCathedral]+Built[imTheater]+Built[imColosseum]=0) then 2467 begin 2468 TryBuild(imCathedral); 2469 TryBuild(imTheater); 489 2470 end; 490 if Report.Trade - Report.Corruption >= 11 then 491 TryBuild(imLibrary); 492 if Report.Trade - Report.Corruption >= 11 then 493 TryBuild(imMarket); 494 if Size >= 9 then 495 TryBuild(imHighways); 496 if (RO.Government <> gDespotism) and (Size >= 4) then 497 TryBuild(imTemple); 498 if (RO.Government <> gDespotism) and (Size >= 6) then 499 TryBuild(imTheater); 500 if (RO.Government <> gDespotism) and (Size >= 8) then 501 TryBuild(imAqueduct); 502 if (Report.ProdRep >= 4) or (RO.nCity = 1) then 503 TryBuild(imBarracks); 504 TryBuild(imWalls); 505 if IsPort then 506 TryBuild(imCoastalFort); 507 if NewImprovement < 0 then 508 begin // nothing to produce -- check for building a wonder 509 count := 0; 510 for wix := 0 to nImp - 1 do 511 if (Imp[wix].Kind = ikWonder) and (RO.Wonder[wix].CityID = -1) 512 // not built yet 513 and ((Report.ProdRep - Report.Support) * 40 >= Imp[wix].Cost) 514 // takes less than 40 turns to produce 515 and City_Improvable(cix, wix) then 516 begin 517 inc(count); 518 if random(count) = 0 then 519 NewImprovement := wix // yes, build this wonder! 520 end; 2471 if (RO.Government<>gDespotism) and (Size>=NeedAqueductSize) then 2472 TryBuild(imAqueduct); 2473 if (Built[imColosseum]+Built[imObservatory]>0) and (Size>=NeedSewerSize) then 2474 TryBuild(imSewer); 2475 if (RO.NatBuilt[imGrWall]=0) and (Built[imObservatory]+Built[imMilAcademy]=0) 2476 and (RO.nCity>=6) and (cixStateImp[imPalace]>=0) 2477 and (Formation[Loc]=Formation[MyCity[cixStateImp[imPalace]].Loc]) 2478 and (Report.ProdRep-Report.Support>=6) then 2479 TryBuild(imGrWall); 2480 // if Map[Loc] and fGrWall=0 then 2481 // TryBuild(imWalls); 2482 // if IsNavalBase then 2483 // TryBuild(imCoastalFort); 2484 if (RO.NatBuilt[imSpacePort]=0) and (Built[imObservatory]+Built[imMilAcademy]=0) 2485 and (Report.ProdRep-Report.Support>=10) then 2486 TryBuild(imSpacePort); 2487 if Report.ProdRep>=8 then 2488 TryBuild(imFactory); 2489 if Report.ProdRep>=12 then 2490 TryBuild(imMfgPlant); 2491 if IsPort then 2492 if Size>8 then 2493 TryBuild(imHarbor) 2494 else if (Built[imHarbor]=0) and (Size>4) 2495 and ((Size and 1<>0) and (Report.Happy*2>Size) 2496 or (Built[imColosseum]>0)) then 2497 begin // check building harbor 2498 V21_to_Loc(Loc,Radius); 2499 for V21:=1 to 26 do // city is in growth mode - using any 1-food tile? 2500 if Tiles and (1 shl V21)<>0 then 2501 begin 2502 TerrType:=Map[Radius[V21]] and (fTerrain or fSpecial); 2503 if TerrType in [fDesert,fTundra,fSwamp,fForest,fHills,fMountains] then 2504 begin TryBuild(imHarbor); break end 2505 end 2506 end; 2507 if (Size<=10) and (Report.FoodRep-Report.Eaten<2) and 2508 (Report.Happy*2>=Size+2) then 2509 TryBuild(imSuperMarket); 2510 2511 // less important 2512 if (Built[imPalace]>0) and (RO.NatBuilt[imColosseum]=0) 2513 and (Size>=10) then 2514 TryBuild(imColosseum); // always build colosseum in capital 2515 if (Built[imPalace]+Built[imCourt]=0) 2516 and ((Report.Corruption>2) or IsResearched(Imp[imHighways].Preq)) then 2517 TryBuild(imCourt); // replace courthouse 2518 if Report.PollRep>=15 then 2519 TryBuild(imRecycling); 2520 if (Report.Trade-Report.Corruption>=11) 2521 and (RO.Money<TotalPopulation[me]*2) then 2522 TryBuild(imBank); 2523 if (RO.NatBuilt[imStockEx]=0) and (Built[imObservatory]+Built[imMilAcademy]=0) 2524 and (Report.ProdRep-Report.Support>=8) then 2525 TryBuild(imStockEx); 2526 2527 // every improvement checked -- start production now 2528 if NewImprovement<>imTrGoods then 2529 begin 2530 if City_StartImprovement(cix, NewImprovement)<rExecuted then 2531 NewImprovement:=imTrGoods 521 2532 end; 522 if NewImprovement >= 0 then 523 City_StartImprovement(cix, NewImprovement) 524 else if City_HasProject(cix) then 525 City_StopProduction(cix); // nothing to produce 526 end 527 end // check production 2533 if (NewImprovement=imTrGoods) and (RO.Turn and $F=0) then 2534 begin // try colony ship parts 2535 NewImprovement:=imShipComp; 2536 while (NewImprovement<=imShipHab) 2537 and ((RO.Tech[Imp[NewImprovement].Preq]<0) 2538 or (City_StartImprovement(cix, NewImprovement)<rExecuted)) do 2539 inc(NewImprovement); 2540 if NewImprovement>imShipHab then NewImprovement:=imTrGoods 2541 end 2542 end; 2543 2544 if (NewImprovement=imTrGoods) and NeedCruiser and (mixCruiser>=0) 2545 and (Project and (cpImp or cpIndex)<>mixCruiser) 2546 and (Report.ProdRep-Report.Support>=6) then 2547 begin 2548 NewImprovement:=-1; 2549 City_StartUnitProduction(cix,mixCruiser); 2550 end; 2551 2552 if (NewImprovement=imTrGoods) and City_HasProject(cix) then 2553 City_StopProduction(cix); 2554 2555 // rebuild imps no longer needed 2556 if (RO.TaxRate=0) and (RO.Money>=TotalPopulation[me]*4) then 2557 TryDestruct(imBank) 2558 else if Report.Happy*2>=Size+6 then 2559 TryDestruct(imTheater) 2560 else if Report.Happy*2>=Size+4 then 2561 TryDestruct(imTemple) 2562 end; 2563 2564 // rebuild imps no longer needed, no report needed 2565 if (Built[imObservatory]>0) 2566 or (Project and (cpImp or cpIndex)=cpImp or imObservatory) 2567 {or not MilProdCity[cix]} then 2568 TryDestruct(imBarracks); 2569 if Map[Loc] and fGrWall<>0 then 2570 TryDestruct(imWalls); 2571 if Built[imColosseum]>0 then 2572 begin 2573 TryDestruct(imTheater); 2574 TryDestruct(imCathedral); 2575 TryDestruct(imTemple); 2576 end; 2577 end; 2578 2579 ChangeHomeCities; 528 2580 end; // SetCityProduction 529 2581 530 function TAI.ChooseResearchAdvance: integer;531 var532 mix: integer;533 begin534 if not IsResearched(adWheel) then535 begin536 result := adWheel;537 exit538 end // research the wheel first539 else if not IsResearched(adWarriorCode) then540 begin541 result := adWarriorCode;542 exit543 end // research warrior code first544 else if not IsResearched(adHorsebackRiding) then545 begin546 result := adHorsebackRiding;547 exit548 end; // research horseback riding first549 550 result := -1; // random advance551 if random(10) = 0 then552 begin // check military research553 result := adMilitary;554 if IsResearched(adMapMaking) and (random(2) = 0) then555 begin // try to develop new ship556 PrepareNewModel(dSea);557 SetNewModelFeature(mcDefense, 3);558 SetNewModelFeature(mcOffense, RO.DevModel.MaxWeight - 3);559 end560 else561 begin // try to develop new ground unit562 PrepareNewModel(dGround);563 SetNewModelFeature(mcDefense, 1);564 SetNewModelFeature(mcOffense, RO.DevModel.MaxWeight - 4);565 SetNewModelFeature(mcMob, 2);566 end;567 568 // don't develop model twice569 for mix := 0 to RO.nModel - 1 do570 if (RO.DevModel.Domain = MyModel[mix].Domain) and571 (RO.DevModel.Attack = MyModel[mix].Attack) and572 (RO.DevModel.Defense = MyModel[mix].Defense) then573 result := -1; // already have this model574 end;575 end; // ChooseResearchAdvance576 2582 577 2583 function TAI.ChooseGovernment: integer; 578 2584 begin 579 if IsResearched(adTheRepublic) then 580 result := gRepublic 581 else if IsResearched(adMonarchy) then 582 result := gMonarchy 2585 if Data.BehaviorFlags and bBarbarina<>0 then 2586 if IsResearched(adTheology) then result:=gFundamentalism 2587 else result:=gDespotism 2588 else if IsResearched(adDemocracy) then 2589 result:=gDemocracy //!!! 2590 else if IsResearched(adTheRepublic) then 2591 result:=gRepublic 2592 else if IsResearched(adMonarchy) then 2593 result:=gMonarchy 2594 else result:=gDespotism 2595 end; 2596 2597 2598 //------------------------------- 2599 // DIPLOMACY 2600 //------------------------------- 2601 2602 function TAI.MostWanted(Nation, adGiveAway: integer): integer; 2603 var 2604 ad: integer; 2605 begin 2606 result:=-1; 2607 if RO.Tech[adGiveAway]>=tsApplicable then 2608 if (adGiveAway=adTheRepublic) and (Data.BehaviorFlags and bGender=bFemale) 2609 and (RO.Tech[adTheology]<tsSeen) then 2610 begin 2611 if RO.EnemyReport[Nation].Tech[adTheology]>=tsApplicable then 2612 result:=adTheology 2613 end 2614 else for ad:=0 to nAdv-5 do // no future techs 2615 if (AdvanceValue[ad]>0) 2616 and (RO.Tech[ad]<tsSeen) and (ad<>RO.ResearchTech) 2617 and (RO.EnemyReport[Nation].Tech[ad]>=tsApplicable) 2618 and ((Advancedness[adGiveAway]<=Advancedness[ad]+AdvanceValue[ad] shr 8+Compromise) 2619 or (adGiveAway=adScience) and (Nation=Data.TheologyPartner)) 2620 and ((result<0) 2621 or ((Advancedness[adGiveAway]+Compromise>=Advancedness[ad]) // acceptable for opponent 2622 or (ad=adScience)) 2623 and (AdvanceValue[ad]>AdvanceValue[result]) 2624 or (result<>adScience) 2625 and (Advancedness[adGiveAway]+Compromise<Advancedness[result]) 2626 and (Advancedness[ad]<Advancedness[result])) 2627 and ((ad<>adTheRepublic) or (Data.BehaviorFlags and bGender=bFemale) 2628 or (RO.EnemyReport[Nation].Tech[adTheology]>=tsSeen)) then 2629 result:=ad 2630 end; 2631 2632 procedure TAI.FindBestTrade(Nation: integer; var adWanted, adGiveAway: integer); 2633 var 2634 i,ad,ead,adTestGiveAway: integer; 2635 begin 2636 adWanted:=-1; 2637 adGiveAway:=-1; 2638 for ead:=0 to nAdv-5 do // no future techs 2639 if (AdvanceValue[ead]>=$100) 2640 and (RO.Tech[ead]<tsSeen) and (ead<>RO.ResearchTech) 2641 and (RO.EnemyReport[Nation].Tech[ead]>=tsApplicable) 2642 and ((adWanted<0) or (AdvanceValue[ead]>AdvanceValue[adWanted])) then 2643 begin 2644 adTestGiveAway:=-1; 2645 for i:=0 to nRequestedTechs-1 do 2646 if (Data.RequestedTechs[i]>=0) 2647 and (Data.RequestedTechs[i] and $FFFF=Nation shl 8+ead) then 2648 adTestGiveAway:=-2; // already requested before 2649 if adTestGiveAway=-1 then 2650 begin 2651 for ad:=0 to nAdv-5 do // no future techs 2652 if (RO.Tech[ad]>=tsApplicable) 2653 and (ad<>RO.EnemyReport[Nation].ResearchTech) 2654 and (RO.EnemyReport[Nation].Tech[ad]<tsSeen) 2655 and ((Advancedness[ad]+Compromise>=Advancedness[ead]) or (ead=adScience)) 2656 and (Advancedness[ad]<=Advancedness[ead]+AdvanceValue[ead] shr 8+Compromise) 2657 and ((adTestGiveAway<0) or (Advancedness[ad]<Advancedness[adTestGiveAway])) then 2658 adTestGiveAway:=ad; 2659 if adTestGiveAway>=0 then 2660 begin 2661 adWanted:=ead; 2662 adGiveAway:=adTestGiveAway 2663 end 2664 end 2665 end; 2666 end; 2667 2668 2669 function TAI.WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean; 2670 var 2671 p1,count,adWanted,adGiveAway: integer; 2672 begin 2673 if Data.BehaviorFlags and bBarbarina=bBarbarina then 2674 begin result:=Barbarina_WantNegotiation(Nation,NegoTime); exit end; 2675 2676 if RO.Treaty[Nation]<trPeace then 2677 begin 2678 if Data.BehaviorFlags and bBarbarina<>0 then 2679 begin result:=false; exit end; 2680 count:=0; 2681 for p1:=0 to nPl-1 do 2682 if (p1<>me) and (1 shl p1 and RO.Alive<>0) and (RO.Treaty[p1]>=trPeace) then 2683 inc(count); 2684 if count>=3 then // enough peace made 2685 begin result:=false; exit; end 2686 end; 2687 2688 NegoCause:=Routine; 2689 case NegoTime of 2690 EnemyCalled: 2691 result:=true; 2692 EndOfTurn: 2693 if (Data.RejectTurn[suContact,Nation]>=0) 2694 and (Data.RejectTurn[suContact,Nation]+WaitAfterReject>=RO.Turn) then 2695 result:=false 2696 else if RO.Treaty[Nation]<trPeace then 2697 result:=(Data.RejectTurn[suPeace,Nation]<0) 2698 or (Data.RejectTurn[suPeace,Nation]+WaitAfterReject<RO.Turn) 2699 else if RO.Treaty[Nation]=trPeace then 2700 result:= (Data.BehaviorFlags and bBarbarina=0) 2701 and ((Data.RejectTurn[suFriendly,Nation]<0) 2702 or (Data.RejectTurn[suFriendly,Nation]+WaitAfterReject<RO.Turn)) 2703 else 2704 begin 2705 FindBestTrade(Nation,adWanted,adGiveAway); 2706 result:= adWanted>=0; 2707 end; 2708 BeginOfTurn: 2709 if (Data.RejectTurn[suContact,Nation]>=0) 2710 and (Data.RejectTurn[suContact,Nation]+WaitAfterReject>=RO.Turn) then 2711 result:=false 2712 else if (Data.BehaviorFlags and bGender=bMale) and Barbarina_WantCheckNegotiation(Nation) then 2713 begin NegoCause:=CheckBarbarina; result:=true; end 2714 else result:=false; 2715 end; 2716 end; 2717 2718 procedure TAI.DoNegotiation; 2719 var 2720 i, adWanted, adGiveAway, adToGet, Slot: integer; 2721 BuildFreeOffer: boolean; 2722 begin 2723 if MyLastAction=scDipOffer then 2724 if OppoAction=scDipAccept then 2725 begin // evaluate accepted offers 2726 AdvanceValuesSet:=false; 2727 if (MyLastOffer.nDeliver=1) and (MyLastOffer.nCost>0) 2728 and (MyLastOffer.Price[1]=opTech+adTheology) then 2729 Data.TheologyPartner:=Opponent; 2730 end 583 2731 else 584 result := gDespotism 2732 begin // evaluate rejected offers 2733 if MyLastOffer.nDeliver+MyLastOffer.nCost=1 then 2734 if MyLastOffer.Price[0]=opTreaty+trPeace then 2735 Data.RejectTurn[suPeace,Opponent]:=RO.Turn 2736 else if MyLastOffer.Price[0]=opTreaty+trFriendlyContact then 2737 Data.RejectTurn[suFriendly,Opponent]:=RO.Turn; 2738 end; 2739 if OppoAction=scDipBreak then 2740 Data.RejectTurn[suContact,Opponent]:=RO.Turn 2741 else if OppoAction=scDipCancelTreaty then 2742 begin 2743 case RO.Treaty[Opponent] of 2744 trNone: Data.RejectTurn[suPeace,Opponent]:=RO.Turn; 2745 trPeace: Data.RejectTurn[suFriendly,Opponent]:=RO.Turn; 2746 end; 2747 end; 2748 2749 if Data.BehaviorFlags and bBarbarina=bBarbarina then 2750 begin Barbarina_DoNegotiation; exit end; 2751 2752 if NegoCause=CheckBarbarina then 2753 begin Barbarina_DoCheckNegotiation; exit end; 2754 2755 SetAdvanceValues; // in case no turn played after loading this game 2756 2757 BuildFreeOffer:=false; 2758 if (OppoAction=scDipStart) or (OppoAction=scDipAccept) then 2759 BuildFreeOffer:=true 2760 else if (OppoAction=scDipOffer) and (OppoOffer.nDeliver+OppoOffer.nCost=0) then 2761 BuildFreeOffer:=true 2762 else if OppoAction=scDipOffer then 2763 begin 2764 if (Data.BehaviorFlags and bBarbarina=0) 2765 and (OppoOffer.nDeliver+OppoOffer.nCost=1) 2766 and (OppoOffer.Price[0] and opMask=opTreaty) 2767 and (integer(OppoOffer.Price[0]-opTreaty)>RO.Treaty[Opponent]) 2768 and ((OppoOffer.Price[0]-opTreaty<trAlliance) or (RO.Tech[adScience]>=tsSeen)) then 2769 MyAction:=scDipAccept // accept all treaties 2770 else if (RO.Treaty[Opponent]>=trPeace) 2771 and (OppoOffer.nDeliver=1) 2772 and (OppoOffer.Price[0] and $FFFF0000=opCivilReport+cardinal(Opponent) shl 16) 2773 and (OppoOffer.nCost=1) 2774 and (OppoOffer.Price[1] and $FFFF0000=opCivilReport+cardinal(me) shl 16) then 2775 MyAction:=scDipAccept // accept exchange of civil reports 2776 else if (OppoOffer.nDeliver=1) and (OppoOffer.nCost=1) 2777 and (OppoOffer.Price[1] and opMask=opTech) then 2778 begin // opponent wants tech 2779 BuildFreeOffer:=true; 2780 adGiveAway:=OppoOffer.Price[1]-opTech; 2781 if (OppoOffer.Price[0] and opMask=opTech) 2782 and (MyLastAction=scDipOffer) 2783 and (MyLastOffer.nDeliver=1) and (MyLastOffer.nCost=1) 2784 and (OppoOffer.Price[0]=MyLastOffer.Price[1]) then 2785 begin // opponent makes counter offer, check whether to accept 2786 adToGet:=OppoOffer.Price[0]-opTech; 2787 if (adGiveAway=adTheRepublic) and (Data.BehaviorFlags and bGender=bFemale) 2788 and (RO.Tech[adTheology]<tsSeen) then 2789 begin 2790 if adToGet=adTheology then MyAction:=scDipAccept; 2791 end 2792 else if (RO.Tech[adGiveAway]>=tsApplicable) and (RO.Tech[adToGet]<tsSeen) 2793 and (AdvanceValue[adToGet]>0) 2794 and ((Advancedness[adGiveAway]<=Advancedness[adToGet] 2795 +AdvanceValue[adToGet] shr 8+Compromise) 2796 or (adGiveAway=adScience) and (Opponent=Data.TheologyPartner)) then 2797 MyAction:=scDipAccept 2798 end 2799 else if (OppoOffer.Price[0] and opMask=opChoose) 2800 or (OppoOffer.Price[0] and opMask=opTech) then 2801 begin // choose price 2802 adWanted:=MostWanted(Opponent,OppoOffer.Price[1]-opTech); 2803 if (OppoOffer.Price[0] and opMask=opTech) 2804 and (Cardinal(adWanted)=OppoOffer.Price[0]-opTech) then 2805 MyAction:=scDipAccept // opponent's offer is already perfect 2806 else if adWanted>=0 then 2807 begin // make improved counter offer 2808 MyOffer.nDeliver:=1; 2809 MyOffer.nCost:=1; 2810 MyOffer.Price[0]:=OppoOffer.Price[1]; 2811 MyOffer.Price[1]:=opTech+adWanted; 2812 MyAction:=scDipOffer; 2813 BuildFreeOffer:=false 2814 end 2815 end; 2816 if MyAction=scDipAccept then BuildFreeOffer:=false 2817 end 2818 else BuildFreeOffer:=true 2819 end; 2820 if (MyAction=scDipAccept) and (OppoAction=scDipOffer) then 2821 begin 2822 AdvanceValuesSet:=false; 2823 if (OppoOffer.nDeliver>0) and (OppoOffer.Price[0]=opTech+adTheology) then 2824 Data.TheologyPartner:=Opponent 2825 end; 2826 2827 if BuildFreeOffer then 2828 begin 2829 if (Data.BehaviorFlags and bBarbarina=0) 2830 and (RO.Treaty[Opponent]<trPeace) 2831 and ((Data.RejectTurn[suPeace,Opponent]<0) 2832 or (Data.RejectTurn[suPeace,Opponent]+WaitAfterReject<RO.Turn)) then 2833 begin 2834 MyOffer.nDeliver:=1; 2835 MyOffer.nCost:=0; 2836 MyOffer.Price[0]:=opTreaty+trPeace; 2837 MyAction:=scDipOffer 2838 end 2839 else if (Data.BehaviorFlags and bBarbarina=0) 2840 and (RO.Treaty[Opponent]=trPeace) 2841 and ((Data.RejectTurn[suFriendly,Opponent]<0) 2842 or (Data.RejectTurn[suFriendly,Opponent]+WaitAfterReject<RO.Turn)) then 2843 begin 2844 MyOffer.nDeliver:=1; 2845 MyOffer.nCost:=0; 2846 MyOffer.Price[0]:=opTreaty+trFriendlyContact; 2847 MyAction:=scDipOffer 2848 end 2849 else 2850 begin 2851 FindBestTrade(Opponent, adWanted, adGiveAway); 2852 if adWanted>=0 then 2853 begin 2854 MyOffer.nDeliver:=1; 2855 MyOffer.nCost:=1; 2856 MyOffer.Price[0]:=opTech+adGiveAway; 2857 MyOffer.Price[1]:=opTech+adWanted; 2858 MyAction:=scDipOffer; 2859 for i:=0 to nRequestedTechs-1 do 2860 if Data.RequestedTechs[i]<0 then 2861 begin Slot:=i; break end 2862 else if (i=0) or (Data.RequestedTechs[i] shr 16 2863 <Data.RequestedTechs[Slot] shr 16) then // find most outdated entry 2864 Slot:=i; 2865 Data.RequestedTechs[Slot]:=RO.Turn shl 16+Opponent shl 8+adWanted 2866 end 2867 end 2868 end; 2869 end; // Negotiation 2870 2871 2872 procedure SetLeaveOutValue; 2873 procedure Process(ad: integer); 2874 var 2875 i: integer; 2876 begin 2877 if LeaveOutValue[ad]<0 then 2878 begin 2879 LeaveOutValue[ad]:=0; 2880 for i:=0 to 1 do if AdvPreq[ad,i]>=0 then 2881 begin 2882 Process(AdvPreq[ad,i]); 2883 if AdvPreq[ad,i] in LeaveOutTechs then 2884 inc(LeaveOutValue[ad], LeaveOutValue[AdvPreq[ad,i]]+1) 2885 end 2886 end 2887 end; 2888 var 2889 ad: integer; 2890 begin 2891 FillChar(LeaveOutValue,SizeOf(LeaveOutValue),$FF); 2892 for ad:=0 to nAdv-5 do Process(ad); 585 2893 end; 586 2894 587 2895 588 // ------------------------------- 589 // DIPLOMACY 590 // ------------------------------- 591 592 function TAI.WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean; 593 begin 594 result := (NegoTime = EnemyCalled) // always accept contact 595 or (NegoTime = EndOfTurn) and (RO.Turn mod 20 = Nation + me) 596 // ask for contact only once in 20 turns 597 end; 598 599 procedure TAI.DoNegotiation; 600 begin 601 if (RO.Treaty[Opponent] < trPeace) and Odd(me + Opponent) then 602 // make peace with some random nations 603 if (OppoAction = scDipOffer) and (OppoOffer.nCost = 0) and 604 (OppoOffer.nDeliver = 1) and (OppoOffer.Price[0] = opTreaty + trPeace) 605 then 606 MyAction := scDipAccept // accept peace 607 else if OppoAction = scDipStart then 608 begin 609 MyOffer.nCost := 0; 610 MyOffer.nDeliver := 1; 611 MyOffer.Price[0] := opTreaty + trPeace; 612 // offer peace in exchange of nothing 613 MyAction := scDipOffer; 614 end 615 end; 2896 initialization 2897 RWDataSize:=sizeof(TPersistentData); 2898 SetLeaveOutValue; 616 2899 617 2900 end. 2901
Note:
See TracChangeset
for help on using the changeset viewer.