| 1 | {$INCLUDE Switches.inc}
|
|---|
| 2 | {//$DEFINE PERF}
|
|---|
| 3 | unit AI;
|
|---|
| 4 |
|
|---|
| 5 | interface
|
|---|
| 6 |
|
|---|
| 7 | uses
|
|---|
| 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);
|
|---|
| 78 |
|
|---|
| 79 | type
|
|---|
| 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 |
|
|---|
| 154 |
|
|---|
| 155 | implementation
|
|---|
| 156 |
|
|---|
| 157 | uses
|
|---|
| 158 | Pile;
|
|---|
| 159 |
|
|---|
| 160 | const
|
|---|
| 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 |
|
|---|
| 168 |
|
|---|
| 169 | constructor TAI.Create(Nation: integer);
|
|---|
| 170 | begin
|
|---|
| 171 | inherited;
|
|---|
| 172 | Data:=pointer(RO.Data);
|
|---|
| 173 | {$IFDEF DEBUG}if Nation=1 then SetDebugMap(DebugMap);{$ENDIF}
|
|---|
| 174 | AdvanceValuesSet:=false;
|
|---|
| 175 | end;
|
|---|
| 176 |
|
|---|
| 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);
|
|---|
| 202 | var
|
|---|
| 203 | EffectiveTransport: integer;
|
|---|
| 204 | begin
|
|---|
| 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
|
|---|
| 309 | end
|
|---|
| 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;
|
|---|
| 695 | end;
|
|---|
| 696 |
|
|---|
| 697 | // ProcessSettlers: move settlers, do terrain improvement, found cities
|
|---|
| 698 | procedure TAI.ProcessSettlers;
|
|---|
| 699 | var
|
|---|
| 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;
|
|---|
| 716 |
|
|---|
| 717 | procedure ReserveCityRadius(Loc: integer);
|
|---|
| 718 | var
|
|---|
| 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
|
|---|
| 731 | end
|
|---|
| 732 | end;
|
|---|
| 733 |
|
|---|
| 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
|
|---|
| 760 | begin
|
|---|
| 761 | inc(History);
|
|---|
| 762 | if V8>=2 then
|
|---|
| 763 | begin
|
|---|
| 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
|
|---|
| 781 | end;
|
|---|
| 782 | end;
|
|---|
| 783 | end;
|
|---|
| 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
|
|---|
| 871 | begin
|
|---|
| 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])
|
|---|
| 1041 | end
|
|---|
| 1042 | end;
|
|---|
| 1043 | end
|
|---|
| 1044 | end;
|
|---|
| 1045 | end; // ProcessSettlers
|
|---|
| 1046 |
|
|---|
| 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;
|
|---|
| 1615 | const
|
|---|
| 1616 | PatrolDestination=lxmax*lymax;
|
|---|
| 1617 | FirstSurplusLoop: array[mctGroundDefender..mctGroundAttacker] of integer= (2,1);
|
|---|
| 1618 | var
|
|---|
| 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;
|
|---|
| 1630 | Adjacent: TVicinity8Loc;
|
|---|
| 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);
|
|---|
| 1671 | Pile.Create(MapSize);
|
|---|
| 1672 | with MyUnit[uix] do
|
|---|
| 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
|
|---|
| 1889 | begin // enemy unit
|
|---|
| 1890 | 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
|
|---|
| 1894 | begin // attack possible, but advantageous?
|
|---|
| 1895 | if AttackForecast=0 then
|
|---|
| 1896 | begin // enemy unit would be destroyed
|
|---|
| 1897 | MyDamage:=Health+DestroyBonus;
|
|---|
| 1898 | EnemyDamage:=RO.EnemyUn[euix].Health+DestroyBonus;
|
|---|
| 1899 | end
|
|---|
| 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
|
|---|
| 1906 | begin
|
|---|
| 1907 | MyDamage:=Health+DestroyBonus;
|
|---|
| 1908 | EnemyDamage:=RO.EnemyUn[euix].Health+AttackForecast;
|
|---|
| 1909 | end;
|
|---|
| 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
|
|---|
| 1915 | begin
|
|---|
| 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;
|
|---|
| 1927 | end
|
|---|
| 1928 | end;
|
|---|
| 1929 | end // enemy unit
|
|---|
| 1930 |
|
|---|
| 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
|
|---|
| 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
|
|---|
| 2024 | begin // no enemy city or unit here
|
|---|
| 2025 | V8_to_Loc(TestLoc,Adjacent);
|
|---|
| 2026 | for V8:=0 to 7 do
|
|---|
| 2027 | begin
|
|---|
| 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
|
|---|
| 2058 | begin
|
|---|
| 2059 | PatrolScore:=TestScore;
|
|---|
| 2060 | PatrolLoc:=TestLoc;
|
|---|
| 2061 | end
|
|---|
| 2062 | end;
|
|---|
| 2063 | end
|
|---|
| 2064 | end; // while Pile.Get
|
|---|
| 2065 | Pile.Free;
|
|---|
| 2066 |
|
|---|
| 2067 | if PatrolLoc>=0 then
|
|---|
| 2068 | begin // attack/capture/discover/patrol task found, execute it
|
|---|
| 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 |
|
|---|
| 2157 | procedure TAI.SetCityProduction;
|
|---|
| 2158 | var
|
|---|
| 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;
|
|---|
| 2168 |
|
|---|
| 2169 | procedure TryBuild(Improvement: integer);
|
|---|
| 2170 | begin
|
|---|
| 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
|
|---|
| 2326 | end;
|
|---|
| 2327 |
|
|---|
| 2328 | begin
|
|---|
| 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
|
|---|
| 2360 | begin // check production
|
|---|
| 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
|
|---|
| 2379 | end;
|
|---|
| 2380 |
|
|---|
| 2381 | if RO.Turn=0 then
|
|---|
| 2382 | begin
|
|---|
| 2383 | NewImprovement:=-1;
|
|---|
| 2384 | City_StartUnitProduction(cix,mixMilitia); // militia
|
|---|
| 2385 | end
|
|---|
| 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
|
|---|
| 2426 | begin
|
|---|
| 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);
|
|---|
| 2470 | 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
|
|---|
| 2532 | end;
|
|---|
| 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;
|
|---|
| 2580 | end; // SetCityProduction
|
|---|
| 2581 |
|
|---|
| 2582 |
|
|---|
| 2583 | function TAI.ChooseGovernment: integer;
|
|---|
| 2584 | begin
|
|---|
| 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
|
|---|
| 2731 | else
|
|---|
| 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);
|
|---|
| 2893 | end;
|
|---|
| 2894 |
|
|---|
| 2895 |
|
|---|
| 2896 | initialization
|
|---|
| 2897 | RWDataSize:=sizeof(TPersistentData);
|
|---|
| 2898 | SetLeaveOutValue;
|
|---|
| 2899 |
|
|---|
| 2900 | end.
|
|---|
| 2901 |
|
|---|