source: tags/1.2.0/AI/StdAI/AI.pas

Last change on this file was 160, checked in by chronos, 5 years ago
  • Added: StdAI from original game. Previously used only AI dev kit.
File size: 96.4 KB
Line 
1{$INCLUDE Switches.inc}
2{//$DEFINE PERF}
3unit AI;
4
5interface
6
7uses
8{$IFDEF DEBUG}SysUtils,Names,{$ENDIF} // necessary for debug exceptions
9{$IFDEF PERF}SysUtils,Windows,{$ENDIF} // necessary for performance measurement
10Protocol, CustomAI, ToolAI, Barbarina;
11
12
13const
14WaitAfterReject=20; // don't try to contact this number of turn after contact was rejected
15MinCityFood=3;
16LeaveDespotism=80; // stay in despotism until this turn
17TechReportOutdated=30;
18MilProdShare=50; // minimum share of total production to specialize in military production
19
20FutureTech=[futResearchTechnology,futProductionTechnology,futArmorTechnology,
21 futMissileTechnology];
22
23nResearchOrder=46;
24ResearchOrder: array[0..1,0..nResearchOrder-1] of integer=
25((adWheel,adWarriorCode,adHorsebackRiding,adCeremonialBurial,adPolytheism,
26adMonarchy,adMysticism,adPoetry,adAstronomy,adMonotheism,
27adTheology,adChivalry,adPottery,adMedicine,adGunpowder,adChemistry,
28adExplosives,adUniversity,adTactics,adSeafaring,adNavigation,adRefining,adCombustionEngine,
29adAutomobile,adPhysics,adMagnetism,adElectricity,adRefrigeration,
30adRadioCommunication,adTheoryOfGravity,adAtomicTheory,adElectronics,
31adMassProduction,adPlastics,adFlight,adEnvironmentalism,
32adSanitation,adMin,adComputers,adRecycling,adSyntheticFood,
33adSelfContainedEnvironment,adNuclearFission,adNuclearPower,adTheLaser,
34adIntelligenArms),
35(adWheel,adWarriorCode,adHorsebackRiding,adAlphabet,adMapMaking,adBronzeWorking,adWriting,
36adCodeOfLaws,adCurrency,adTrade,adLiterature,adTheRepublic,adMathematics,
37adPhilosophy,adScience,adMasonry,adConstruction,adEngineering,adInvention,
38adIronWorking,adBridgeBuilding,adSteamEngine,adRailroad,adSteel,
39adBanking,adIndustrialization,adConscription,adDemocracy,adEconomics,
40adTheCorporation,adMassProduction,adRobotics,adCommunism,adMetallurgy,
41adBallistics,adMobileWarfare,adAmphibiousWarfare,adMin,adComputers,adRocketry,adAdvancedRocketry,
42adAdvancedFlight,adSpaceFlight,adComposites,adIntelligence,adCombinedArms));
43
44LeaveOutTechs=[adPolytheism,adMysticism,adInvention,adEconomics,adPottery,
45adMedicine,adEnvironmentalism,adRefining,adTrade,adLiterature,adMathematics,
46adPhilosophy,adChemistry,adConscription,adCombustionEngine,adPhysics,
47adTheoryOfGravity,adAtomicTheory,adSyntheticFood,adNuclearFission];
48
49TechValue_ForResearch_LeaveOut=$700;
50TechValue_ForResearch_Urgent=$600;
51TechValue_ForResearch_Next=$400;
52TechValue_ForResearch=$FF;
53ForceNeeded_NoLeaveOut=20; // advancedness behind to state-of-art
54ForceNeeded_LeaveOut=30; // advancedness behind of state-of-art
55Compromise=6;
56
57// basic strategies
58bGender=$0001;
59bMale=$0000;
60bFemale=$0001;
61bBarbarina=$0006;
62bBarbarina_Hide=$0002;
63
64// model categories
65nModelCat=4;
66mctNone=-1; mctGroundDefender=0; mctGroundAttacker=1; mctTransport=2; mctCruiser=3;
67
68// mil research
69BetterQuality: array[0..nModelCat-1] of integer=(50,50,80,80);
70MaxBuildWorseThanBestModel=20; MaxExistWorseThanBestModel=50;
71
72maxCOD=256;
73PresenceUnknown=$10000;
74
75nRequestedTechs=48;
76
77PlayerHash: array[0..nPl-1] of integer=(7,6,0,2,10,8,12,14,4,1,3,5,9,11,13);
78
79type
80Suggestion=(suContact, suPeace, suFriendly);
81
82TPersistentData=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
89TAI = class(TBarbarina)
90 constructor Create(Nation: integer); override;
91
92 procedure SetDataDefaults; override;
93
94protected
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
155implementation
156
157uses
158Pile;
159
160const
161// fine adjustment
162Aggressive=40; // 0 = never attacks, 100 = attacks even with heavy losses
163DestroyBonus=30; // percent of building cost
164
165var
166LeaveOutValue: array[0..nAdv-1] of integer;
167
168
169constructor TAI.Create(Nation: integer);
170begin
171inherited;
172Data:=pointer(RO.Data);
173{$IFDEF DEBUG}if Nation=1 then SetDebugMap(DebugMap);{$ENDIF}
174AdvanceValuesSet:=false;
175end;
176
177procedure TAI.SetDataDefaults;
178begin
179with 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
188end;
189
190function TAI.OnNegoRejected_CancelTreaty: boolean;
191begin
192Data.RejectTurn[suContact,Opponent]:=RO.Turn;
193result:= Data.BehaviorFlags and bBarbarina<>0;
194end;
195
196
197//-------------------------------
198// RESEARCH
199//-------------------------------
200
201procedure TAI.RateModel(const mi: TModelInfo; var Category, Quality: integer);
202var
203EffectiveTransport: integer;
204begin
205if mi.Kind>=mkScout then
206 begin Category:=mctNone; exit end;
207case 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);
269end;
270
271procedure TAI.RateMyModel(mix: integer; var Category, Quality: integer);
272var
273mi: TModelInfo;
274begin
275MakeModelInfo(me,mix,MyModel[mix],mi);
276RateModel(mi,Category,Quality);
277end;
278
279function TAI.IsBetterModel(const mi: TModelInfo): boolean;
280var
281mix,Cat,Quality,Cat1,Quality1: integer;
282begin
283RateModel(mi,Cat,Quality);
284for 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;
290result:=true;
291end;
292
293function TAI.ChooseResearchAdvance: integer;
294var
295adNext,iad,i,ad,Count,EarliestNeeded,EarliestNeeded_NoLeaveOut,
296 NewResearch,StateOfArt,mix: integer;
297mi: TModelInfo;
298Entry: array[0..nAdv-1] of boolean;
299ok: 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
388begin
389if Data.BehaviorFlags and bBarbarina<>0 then
390 begin
391 result:=Barbarina_ChooseResearchAdvance;
392 if result>=0 then exit
393 end;
394
395SetAdvanceValues;
396
397// always complete traded techs first
398result:=-1;
399for 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;
403if result>=0 then exit;
404
405if 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
477NewResearch:=-1;
478
479// check if cooperation with other gender doesn't work -- go for old needed techs then
480StateOfArt:=-1;
481for ad:=0 to nAdv-1 do
482 if (RO.Tech[ad]>=tsApplicable) and (Advancedness[ad]>StateOfArt) then
483 StateOfArt:=Advancedness[ad];
484EarliestNeeded:=-1;
485EarliestNeeded_NoLeaveOut:=-1;
486for 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;
502if 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
520adNext:=-1;
521if 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
542if 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
563assert(NewResearch>=0);
564fillchar(Entry, sizeof(Entry), false);
565MarkEntry(NewResearch);
566result:=-1;
567for ad:=0 to nAdv-1 do
568 if Entry[ad]
569 and ((result<0) or (Advancedness[ad]>Advancedness[result])) then
570 result:=ad;
571assert(result>=0);
572end;
573
574function TAI.ChooseStealAdvance: integer;
575var
576ad: integer;
577begin
578result:=-1;
579for ad:=0 to nAdv-1 do
580 if AdvanceStealable(ad)
581 and ((result<0) or (Advancedness[ad]>Advancedness[result])) then
582 result:=ad
583end;
584
585
586//-------------------------------
587// TERRAFORMING
588//-------------------------------
589
590const
591twpAllowFarmland=$0001;
592
593procedure TAI.TileWorkPlan(Loc, cix: integer;
594 var Value, NextJob, TotalWork: integer);
595var
596OldTile,TerrType: Cardinal;
597TileInfo: TTileInfo;
598begin
599TotalWork:=0;
600NextJob:=jNone;
601if Map[Loc] and (fRare1 or fRare2)<>0 then
602 begin Value:=3*8-1; exit end; // better than any tile with 2 food
603
604OldTile:=Map[Loc];
605TerrType:=Map[Loc] and fTerrain;
606if (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;
692Server(sGetTileInfo,me,Loc,TileInfo);
693Value:=TileInfo.Food*8+TileInfo.Prod*2+TileInfo.Trade;
694Map[Loc]:=OldTile;
695end;
696
697// ProcessSettlers: move settlers, do terrain improvement, found cities
698procedure TAI.ProcessSettlers;
699var
700i,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;
703Tile: Cardinal;
704FoodOk,Started: boolean;
705Radius: TVicinity21Loc;
706CityAreaInfo: TCityAreaInfo;
707TileFood, 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
796begin
797fillchar(SettlerSurplus, sizeof(SettlerSurplus), 0);
798JobAssignment_Initialize;
799
800if (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
890for 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
933ScoreRoadConnections;
934
935if 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
956if 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
992for 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
1001JobAssignment_Go;
1002
1003for 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
1012for 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;
1045end; // ProcessSettlers
1046
1047
1048//-------------------------------
1049// MY TURN
1050//-------------------------------
1051
1052procedure TAI.DoTurn;
1053var
1054emix,i,p1,TaxSum,ScienceSum,NewTaxRate: integer;
1055AllHateMe: boolean;
1056{$IFDEF PERF}PF,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9: int64;{$ENDIF}
1057begin
1058{$IFDEF DEBUG}fillchar(DebugMap, sizeof(DebugMap),0);{$ENDIF}
1059
1060{$IFDEF PERF}QueryPerformanceFrequency(PF);{$ENDIF}
1061{$IFDEF PERF}QueryPerformanceCounter(t0);{$ENDIF}
1062
1063WarNations:=PresenceUnknown;
1064for 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);
1067BombardingNations:=0;
1068for 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);
1071BombardingNations:=BombardingNations and WarNations;
1072
1073AnalyzeMap;
1074//for i:=0 to MapSize-1 do DebugMap[i]:=Formation[i];
1075
1076if (Data.BehaviorFlags and bBarbarina=0)
1077 and (RO.Tech[ResearchOrder[Data.BehaviorFlags and bGender,8]]<tsApplicable) then
1078 CheckGender;
1079
1080if 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?
1123if (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
1141CollectModelCatStat;
1142
1143if Data.BehaviorFlags and bBarbarina=bBarbarina then
1144 begin
1145 MakeColonyShipPlan;
1146 Barbarina_DoTurn
1147 end
1148else
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
1163ProcessSettlers;
1164
1165{$IFDEF PERF}QueryPerformanceCounter(t6);{$ENDIF}
1166
1167if Data.BehaviorFlags and bBarbarina<>0 then
1168 Barbarina_SetCityProduction
1169else
1170 SetCityProduction;
1171
1172{$IFDEF PERF}QueryPerformanceCounter(t7);{$ENDIF}
1173
1174// correct tax rate if necessary
1175if not IsResearched(adWheel) then
1176 ChangeRates(0,0)
1177else
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
1196if (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;
1208if RO.ResearchTech=adMilitary then Data.LastResearchTech:=-1
1209else Data.LastResearchTech:=RO.ResearchTech;
1210for 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
1216AdvanceValuesSet:=false;
1217SetAdvanceValues;
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}
1228end;
1229
1230{$IFDEF DEBUG}
1231procedure TAI.TraceAdvanceValues(Nation: integer);
1232var
1233ad: integer;
1234begin
1235for 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
1242end;
1243{$ENDIF}
1244
1245
1246procedure TAI.CheckGender;
1247var
1248p1,NewGender: integer;
1249begin
1250NewGender:=-1;
1251for 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;
1266if (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
1271end;
1272
1273
1274procedure 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
1315var
1316emix,cix,adMissing,iad,ad,count,i,Time,d,CurrentCost,CurrentStrength,
1317 MaxSize, MaxTrade: integer;
1318PreView,Emergency,Bombarded: boolean;
1319begin
1320if AdvanceValuesSet then exit;
1321AdvanceValuesSet:=true;
1322
1323fillchar(AdvanceValue,sizeof(AdvanceValue),0);
1324
1325// rate techs to ensure research progress
1326Time:=0;
1327for ad:=0 to nAdv-1 do if RO.Tech[ad]=tsSeen then inc(Time);
1328adMissing:=-1;
1329Emergency:=true;
1330for 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;
1373if 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;
1379for 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
1391for 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
1413inc(AdvanceValue[adSteamEngine],$400);
1414inc(AdvanceValue[adNuclearPower],$400);
1415inc(AdvanceValue[adRocketry],$400);
1416// features
1417inc(AdvanceValue[adBallistics],$800);
1418inc(AdvanceValue[adCommunism],$800);
1419// weight
1420inc(AdvanceValue[adAutomobile],$800);
1421inc(AdvanceValue[adSteel],$800);
1422inc(AdvanceValue[adAdvancedFlight],$400);
1423
1424// civil non-improvement
1425if RO.Turn>=LeaveDespotism then
1426 begin
1427 inc(AdvanceValue[adDemocracy],$80*RO.nCity);
1428 inc(AdvanceValue[adTheRepublic],$800);
1429 end;
1430inc(AdvanceValue[adRailroad],$800);
1431// inc(AdvanceValue[adExplosives],$800); // no, has enough
1432inc(AdvanceValue[adBridgeBuilding],$200);
1433inc(AdvanceValue[adSpaceFlight],$200);
1434inc(AdvanceValue[adSelfContainedEnvironment],$200);
1435inc(AdvanceValue[adImpulseDrive],$200);
1436inc(AdvanceValue[adTransstellarColonization],$200);
1437
1438// city improvements
1439MaxSize:=0;
1440for cix:=0 to RO.nCity-1 do
1441 if MyCity[cix].Size>MaxSize then
1442 MaxSize:=MyCity[cix].Size;
1443if RO.Government in [gRepublic,gDemocracy,gLybertarianism] then
1444 MaxTrade:=(MaxSize-1)*3
1445else MaxTrade:=(MaxSize-1)*2;
1446
1447RateImpPreq(imCourt,(RO.nCity-1)*$100);
1448RateImpPreq(imLibrary,(MaxTrade-10)*$180);
1449RateImpPreq(imMarket,(MaxTrade-10)*$140);
1450RateImpPreq(imUniversity,(MaxTrade-10)*$140);
1451RateImpPreq(imBank,(MaxTrade-10)*$100);
1452RateImpPreq(imObservatory,(MaxTrade-10)*$100);
1453RateImpPreq(imResLab,(MaxTrade-14)*$140);
1454RateImpPreq(imStockEx,(MaxTrade-10)*$10*(RO.nCity-1));
1455RateImpPreq(imHighways,(MaxSize-5)*$200);
1456RateImpPreq(imFactory,(MaxSize-8)*$200);
1457RateImpPreq(imMfgPlant,(MaxSize-8)*$1C0);
1458RateImpPreq(imRecycling,(MaxSize-8)*$180);
1459RateImpPreq(imHarbor,(MaxSize-7)*$200);
1460RateImpPreq(imSuperMarket,$300);
1461if RO.Turn>=40 then RateImpPreq(imTemple,$400);
1462if RO.Government<>gDespotism then
1463 begin
1464 RateImpPreq(imCathedral,$400);
1465 RateImpPreq(imTheater,$400);
1466 end;
1467if MaxSize>=NeedAqueductSize-1 then
1468 begin
1469 RateImpPreq(imAqueduct,$600);
1470 RateImpPreq(imGrWall,$300);
1471 end;
1472if 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);
1476Bombarded:=false;
1477for emix:=0 to RO.nEnemyModel-1 do
1478 if 1 shl (mcLongRange-mcFirstNonCap) and RO.EnemyModel[emix].Cap<>0 then
1479 Bombarded:=true;
1480if Bombarded then
1481 RateImpPreq(imCoastalFort,$400);
1482end;
1483
1484procedure TAI.AnalyzeMap;
1485var
1486cix,Loc,Loc1,V8,f1,p1: integer;
1487Adjacent: TVicinity8Loc;
1488begin
1489inherited AnalyzeMap;
1490
1491// collect nation presence information for continents and oceans
1492fillchar(ContinentPresence, sizeof(ContinentPresence), 0);
1493fillchar(OceanPresence, sizeof(OceanPresence), 0);
1494for 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
1543fillchar(TotalPopulation, sizeof(TotalPopulation), 0);
1544fillchar(ContinentPopulation, sizeof(ContinentPopulation), 0);
1545fillchar(DistrictPopulation, 4*nDistrict, 0);
1546
1547// count population
1548for 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;
1554for 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;
1561end;
1562
1563procedure TAI.CollectModelCatStat;
1564var
1565i,uix,Cat,mix,Quality: integer;
1566begin
1567// categorize models
1568for Cat:=0 to nModelCat-1 do
1569 ModelBestQuality[Cat]:=0;
1570mixCaravan:=-1;
1571mixSlaves:=-1;
1572mixCruiser:=-1;
1573for 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
1597for 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
1603OceanWithShip:=0;
1604if 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;
1611end;
1612
1613
1614procedure TAI.MoveUnitsHome;
1615const
1616PatrolDestination=lxmax*lymax;
1617FirstSurplusLoop: array[mctGroundDefender..mctGroundAttacker] of integer= (2,1);
1618var
1619Cat,i,mix,cix,uix,Loop,nModelOrder: integer;
1620Adjacent: TVicinity8Loc;
1621LocNeed: array[0..lxmax*lymax-1] of shortint;
1622Destination: array[0..nUmax-1] of integer;
1623DistrictNeed,DistrictNeed0: array[0..maxCOD-1] of integer;
1624ModelOrder: array[0..nMmax-1] of integer;
1625complete,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
1709begin
1710if 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
1715fillchar(UnitLack,sizeof(UnitLack),0);
1716fillchar(Destination, 4*RO.nUn, $FF);
1717for i:=0 to maxCOD-1 do
1718 if uixPatrol[i]>=0 then
1719 Destination[uixPatrol[i]]:=PatrolDestination;
1720for 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
1725for 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
1806repeat
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;
1839until complete;
1840
1841for 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
1851for 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;
1859end; // MoveUnitsHome
1860
1861
1862procedure TAI.CheckAttack(uix: integer);
1863var
1864AttackScore,BestCount,AttackLoc,TestLoc,NextLoc,TestTime,V8,
1865 TestScore,euix,MyDamage,EnemyDamage,OldLoc,
1866 AttackForecast,MoveResult,AttackResult,MoveStyle,NextTime,RecoverTurns: integer;
1867Tile: Cardinal;
1868Exhausted: boolean;
1869Adjacent: TVicinity8Loc;
1870Reached: array[0..lxmax*lymax-1] of boolean;
1871
1872begin
1873with 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;
1975end; // CheckAttack
1976
1977
1978procedure TAI.Patrol(uix: integer);
1979const
1980DistanceScore=4;
1981var
1982PatrolScore,BestCount,PatrolLoc,TestLoc,NextLoc,TestTime,V8,
1983 TestScore,OldLoc,MoveResult,MoveStyle,NextTime,RecoverTurns: integer;
1984Tile: Cardinal;
1985Exhausted,CaptureOnly: boolean;
1986Adjacent: TVicinity8Loc;
1987AdjacentUnknown: array[0..lxmax*lymax-1] of shortint;
1988
1989begin
1990with 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;
2077end; // Patrol
2078
2079procedure TAI.AttackAndPatrol;
2080const
2081nAttackCatOrder=3;
2082AttackCatOrder: array[0..nAttackCatOrder-1] of integer=
2083(mctGroundAttacker, mctCruiser, mctGroundDefender);
2084var
2085iCat,uix,uix1: integer;
2086IsPatrolUnit,Fortified: boolean;
2087begin
2088for 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
2094if 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
2103fillchar(uixPatrol, sizeof(uixPatrol), $FF);
2104for 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
2112for 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
2131end; // AttackAndPatrol
2132
2133
2134function TAI.HavePort: boolean;
2135var
2136V8, cix,AdjacentLoc,f: integer;
2137Adjacent: TVicinity8Loc;
2138begin
2139result:=false;
2140for 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
2154end;
2155
2156
2157procedure TAI.SetCityProduction;
2158var
2159uix,cix,iix,dtr,V8,V21,NewImprovement,AdjacentLoc,MaxSettlers,
2160 maxcount,cixMilAcademy: integer;
2161TerrType: cardinal;
2162IsPort,IsNavalBase,NeedCruiser,CheckProd,Destructed,ProduceSettlers,ProduceMil: boolean;
2163Adjacent: TVicinity8Loc;
2164Radius: TVicinity21Loc;
2165Report: TCityReport;
2166HomeCount, CityProdRep: array[0..nCmax-1] of integer;
2167MilProdCity: 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
2328begin
2329fillchar(HomeCount, 4*RO.nCity, 0);
2330for 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
2336NominateMilProdCities;
2337
2338for 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
2579ChangeHomeCities;
2580end; // SetCityProduction
2581
2582
2583function TAI.ChooseGovernment: integer;
2584begin
2585if Data.BehaviorFlags and bBarbarina<>0 then
2586 if IsResearched(adTheology) then result:=gFundamentalism
2587 else result:=gDespotism
2588else if IsResearched(adDemocracy) then
2589 result:=gDemocracy //!!!
2590else if IsResearched(adTheRepublic) then
2591 result:=gRepublic
2592else if IsResearched(adMonarchy) then
2593 result:=gMonarchy
2594else result:=gDespotism
2595end;
2596
2597
2598//-------------------------------
2599// DIPLOMACY
2600//-------------------------------
2601
2602function TAI.MostWanted(Nation, adGiveAway: integer): integer;
2603var
2604ad: integer;
2605begin
2606result:=-1;
2607if 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
2630end;
2631
2632procedure TAI.FindBestTrade(Nation: integer; var adWanted, adGiveAway: integer);
2633var
2634i,ad,ead,adTestGiveAway: integer;
2635begin
2636adWanted:=-1;
2637adGiveAway:=-1;
2638for 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;
2666end;
2667
2668
2669function TAI.WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean;
2670var
2671p1,count,adWanted,adGiveAway: integer;
2672begin
2673if Data.BehaviorFlags and bBarbarina=bBarbarina then
2674 begin result:=Barbarina_WantNegotiation(Nation,NegoTime); exit end;
2675
2676if 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
2688NegoCause:=Routine;
2689case 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;
2716end;
2717
2718procedure TAI.DoNegotiation;
2719var
2720i, adWanted, adGiveAway, adToGet, Slot: integer;
2721BuildFreeOffer: boolean;
2722begin
2723if 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;
2739if OppoAction=scDipBreak then
2740 Data.RejectTurn[suContact,Opponent]:=RO.Turn
2741else 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
2749if Data.BehaviorFlags and bBarbarina=bBarbarina then
2750 begin Barbarina_DoNegotiation; exit end;
2751
2752if NegoCause=CheckBarbarina then
2753 begin Barbarina_DoCheckNegotiation; exit end;
2754
2755SetAdvanceValues; // in case no turn played after loading this game
2756
2757BuildFreeOffer:=false;
2758if (OppoAction=scDipStart) or (OppoAction=scDipAccept) then
2759 BuildFreeOffer:=true
2760else if (OppoAction=scDipOffer) and (OppoOffer.nDeliver+OppoOffer.nCost=0) then
2761 BuildFreeOffer:=true
2762else 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;
2820if (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
2827if 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;
2869end; // Negotiation
2870
2871
2872procedure 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;
2888var
2889ad: integer;
2890begin
2891FillChar(LeaveOutValue,SizeOf(LeaveOutValue),$FF);
2892for ad:=0 to nAdv-5 do Process(ad);
2893end;
2894
2895
2896initialization
2897RWDataSize:=sizeof(TPersistentData);
2898SetLeaveOutValue;
2899
2900end.
2901
Note: See TracBrowser for help on using the repository browser.