source: trunk/AI/StdAI/Barbarina.pas@ 319

Last change on this file since 319 was 319, checked in by chronos, 9 months ago
  • Modified: Optimized drawing of Wonders window.
  • Modified: Used named constants for Wonders CitiID special cases.
File size: 71.7 KB
Line 
1{$INCLUDE Switches.inc}
2unit Barbarina;
3
4interface
5
6uses
7{$IFDEF DEBUG}SysUtils,{$ENDIF} // necessary for debug exceptions
8{$IFDEF DEBUG}Names,{$ENDIF}
9 Protocol, ToolAI, CustomAI;
10
11const
12 nModelCategory = 4;
13 ctGroundSlow = 0;
14 ctGroundFast = 1;
15 ctSeaTrans = 2;
16 ctSeaArt = 3;
17
18 maxCOD = 256;
19
20 maxModern = 16;
21// maximum number of modern resources of one type being managed
22// (for designed maps only, number is 2 in standard game)
23
24
25type
26 TColonyShipPlan = array[0..nShipPart - 1] of record
27 cixProducing: integer;
28 LocResource: array[0..maxModern - 1] of integer;
29 nLocResource: integer;
30 LocFoundCity: array[0..maxModern - 1] of integer;
31 nLocFoundCity: integer;
32 end;
33
34 TBarbarina = class(TToolAI)
35 constructor Create(Nation: integer); override;
36
37 protected
38 ColonyShipPlan: TColonyShipPlan;
39 function Barbarina_GoHidden: boolean; // whether we should prepare for barbarina mode
40 function Barbarina_Go: boolean; // whether we should switch to barbarina mode now
41 procedure Barbarina_DoTurn;
42 procedure Barbarina_SetCityProduction;
43 function Barbarina_ChooseResearchAdvance: integer;
44 function Barbarina_WantCheckNegotiation(Nation: integer): boolean;
45 procedure Barbarina_DoCheckNegotiation;
46 function Barbarina_WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean;
47 procedure Barbarina_DoNegotiation;
48 procedure MakeColonyShipPlan;
49
50 private
51 TurnOfMapAnalysis, Neighbours: integer;
52 ContinentPresence: array[0..maxCOD - 1] of integer;
53 OceanPresence: array[0..maxCOD - 1] of integer;
54 ContinentSize: array[0..maxCOD - 1] of integer;
55 OceanSize: array[0..maxCOD - 1] of integer;
56 mixBest: array[0..nModelCategory - 1] of integer;
57 NegoCause: (CancelTreaty);
58 function IsModelAvailable(rmix: integer): boolean;
59 procedure FindBestModels;
60 procedure AnalyzeMap;
61 procedure RateAttack(uix: integer);
62 function DoAttack(uix, AttackLoc: integer): boolean;
63 function ProcessMove(uix: integer): boolean;
64 procedure AttackAndPatrol;
65 end;
66
67
68implementation
69
70uses
71 Pile;
72
73type
74 TResearchModel = record
75 Category, Domain, Weight, adStop, FutMStrength: integer;
76 Upgrades: cardinal;
77 Cap: array [0..nFeature - 1] of integer;
78 end;
79
80const
81 //UnitKind
82 ukSlow = $01;
83 ukFast = $02;
84
85 neumax = 4096;
86 mixTownGuard = 2;
87
88 PresenceUnknown = $10000;
89
90 WonderProductionThreshold = 15;
91 WonderInclination = 24.0; // higher value means lower probability of building wonder
92 ReduceDefense = 16; // if this is x, 1/x of all units is used to defend cities
93
94 nResearchOrder = 40;
95 ResearchOrder: array[0..nResearchOrder - 1] of integer =
96 (adBronzeWorking, -adMapMaking, adChivalry, adMonotheism, adIronWorking,
97 adGunPowder, adTheology, adConstruction, adCodeOfLaws, -adEngineering,
98 -adSeafaring, -adNavigation, adMetallurgy, adBallistics, adScience, adExplosives,
99 adTactics, adSteel, -adSteamEngine, -adAmphibiousWarfare, -adMagnetism, adRadio,
100 adAutomobile, adMobileWarfare, adRailroad, adCommunism, adDemocracy,
101 adTheCorporation, adMassProduction, adIndustrialization, adRobotics, adComposites,
102 adTheLaser, adFlight, adAdvancedFlight, adSpaceFlight,
103 adSyntheticFood, adTransstellarColonization, adElectronics, adSmartWeapons);
104
105 nResearchModel = 16;
106 ResearchModel: array[0..nResearchModel - 1] of TResearchModel =
107 // Wea Arm Mob Sea Car Tur Bom Fue Air Nav Rad Sub Art Alp Sup Ove Air Spy SE NP Jet Ste Fan Fir Wil Aca Lin
108 ((Category: ctGroundSlow; Domain: dGround; Weight: 7; adStop: adIronWorking;
109 Upgrades: $0003;
110 Cap: (3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
112 (Category: ctGroundFast; Domain: dGround; Weight: 7; adStop: adIronWorking;
113 Upgrades: $0003;
114 Cap: (3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
116 (Category: ctGroundSlow; Domain: dGround; Weight: 7; adStop: adExplosives;
117 Upgrades: $003F;
118 Cap: (3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
120 (Category: ctGroundFast; Domain: dGround; Weight: 7; adStop: adExplosives;
121 Upgrades: $003F;
122 Cap: (3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
124 (Category: ctSeaTrans; Domain: dSea; Weight: 7; adStop: adExplosives;
125 Upgrades: $000F;
126 Cap: (0, 3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
128 (Category: ctSeaArt; Domain: dSea; Weight: 7; adStop: adExplosives; Upgrades: $000F;
129 Cap: (4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
131 (Category: ctGroundSlow; Domain: dGround; Weight: 7; adStop: adAutomobile;
132 Upgrades: $00FF;
133 Cap: (1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
135 (Category: ctGroundFast; Domain: dGround; Weight: 7; adStop: adAutomobile;
136 Upgrades: $00FF;
137 Cap: (3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
139 (Category: ctSeaTrans; Domain: dSea; Weight: 9; adStop: -1; Upgrades: $00FF;
140 Cap: (0, 4, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
141 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
142 (Category: ctSeaArt; Domain: dSea; Weight: 9; adStop: -1; Upgrades: $00FF;
143 Cap: (5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
145 (Category: ctGroundSlow; Domain: dGround; Weight: 10; adStop: adCommunism;
146 Upgrades: $05FF;
147 Cap: (3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
149 (Category: ctGroundFast; Domain: dGround; Weight: 10; adStop: adCommunism;
150 Upgrades: $05FF;
151 Cap: (5, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
153 (Category: ctGroundSlow; Domain: dGround; Weight: 10; adStop: adComposites;
154 Upgrades: $07FF;
155 Cap: (3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
156 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1)),
157 (Category: ctGroundFast; Domain: dGround; Weight: 10; adStop: adComposites;
158 Upgrades: $07FF;
159 Cap: (5, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
160 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1)),
161 (Category: ctGroundSlow; Domain: dGround; Weight: 10; adStop: -1; Upgrades: $3FFF;
162 Cap: (3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
163 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1)),
164 (Category: ctGroundFast; Domain: dGround; Weight: 10; adStop: -1; Upgrades: $3FFF;
165 Cap: (5, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
166 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1)));
167 EntryModel_Base = 1;
168 EntryModel_GunPowder = 3;
169 EntryModel_MassProduction = 13;
170
171
172var
173 Moved: array[0..numax - 1] of boolean;
174 UnitPresence: array[0..lxmax * lymax - 1] of byte;
175 euixMap: array[0..lxmax * lymax - 1] of smallint;
176 uixAttack: array[0..neumax - 1] of smallint;
177 AttackScore: array[0..neumax - 1] of integer;
178
179constructor TBarbarina.Create(Nation: integer);
180begin
181 inherited;
182 TurnOfMapAnalysis := -1;
183end;
184
185// whether one of the existing models matches a specific research model
186function TBarbarina.IsModelAvailable(rmix: integer): boolean;
187var
188 i, mix, MStrength: integer;
189begin
190 Result := False;
191 with ResearchModel[rmix] do
192 begin
193 MStrength := CurrentMStrength(Domain);
194 for mix := 3 to RO.nModel - 1 do
195 if ((MyModel[mix].kind = mkSelfDeveloped) or
196 (MyModel[mix].kind = mkEnemyDeveloped)) and (MyModel[mix].Domain = Domain) and
197 (Upgrades and not MyModel[mix].Upgrades = 0) then
198 begin
199 Result := MStrength < (MyModel[mix].MStrength * 3) div 2;
200 // for future techs: don't count model available if 50% stronger possible
201 for i := 0 to nFeature - 1 do
202 if MyModel[mix].Cap[i] < Cap[i] then
203 begin
204 Result := False;
205 break;
206 end;
207 if Result then
208 break;
209 end;
210 end;
211end;
212
213function TBarbarina.Barbarina_GoHidden: boolean;
214var
215 V21, Loc1, cix: integer;
216 Radius: TVicinity21Loc;
217begin
218 if IsResearched(adMassProduction) then
219 begin
220 Result := True;
221 for cix := 0 to RO.nCity - 1 do
222 with MyCity[cix] do
223 if Loc >= 0 then
224 begin // search for modern resource
225 V21_to_Loc(Loc, Radius);
226 for V21 := 1 to 26 do
227 begin
228 Loc1 := Radius[V21];
229 if (Loc1 >= 0) and (RO.Map[Loc1] and fModern <> 0) then
230 Result := False;
231 end;
232 end;
233 end
234 else if IsResearched(adGunPowder) then
235 Result := (RO.Tech[adTheRepublic] < tsSeen) and IsResearched(adTheology)
236 else
237 Result := False;
238end;
239
240function TBarbarina.Barbarina_Go: boolean;
241begin
242 if IsResearched(adMassProduction) then
243 Result := IsResearched(adTheology) and IsModelAvailable(EntryModel_MassProduction)
244 else if IsResearched(adGunPowder) then
245 Result := IsResearched(adTheology) and IsResearched(adMapMaking) and
246 IsModelAvailable(EntryModel_GunPowder)
247 else
248 begin
249 Result := (RO.nCity >= 3) and IsResearched(adMapMaking) and
250 IsModelAvailable(EntryModel_Base);
251 exit;
252 end;
253 Result := Result and ((RO.nUn >= RO.nCity * 3) or
254 (RO.Wonder[woZeus].EffectiveOwner = me));
255end;
256
257procedure TBarbarina.AnalyzeMap;
258var
259 Loc, Loc1, V8, f1, p1, cix: integer;
260 Adjacent: TVicinity8Loc;
261begin
262 if TurnOfMapAnalysis = RO.Turn then
263 exit;
264
265 // inherited;
266
267 // collect nation presence information for continents and oceans
268 fillchar(ContinentPresence, sizeof(ContinentPresence), 0);
269 fillchar(OceanPresence, sizeof(OceanPresence), 0);
270 fillchar(ContinentSize, sizeof(ContinentSize), 0);
271 fillchar(OceanSize, sizeof(OceanSize), 0);
272 for Loc := 0 to MapSize - 1 do
273 begin
274 f1 := Formation[Loc];
275 case f1 of
276 0..maxCOD - 1:
277 begin
278 p1 := RO.Territory[Loc];
279 if p1 >= 0 then
280 if Map[Loc] and fTerrain >= fGrass then
281 begin
282 Inc(ContinentSize[f1]);
283 ContinentPresence[f1] := ContinentPresence[f1] or (1 shl p1);
284 end
285 else
286 begin
287 Inc(OceanSize[f1]);
288 OceanPresence[f1] := OceanPresence[f1] or (1 shl p1);
289 end;
290 end;
291 nfUndiscovered:
292 begin // adjacent formations are not completely discovered
293 V8_to_Loc(Loc, Adjacent);
294 for V8 := 0 to 7 do
295 begin
296 Loc1 := Adjacent[V8];
297 if Loc1 >= 0 then
298 begin
299 f1 := Formation[Loc1];
300 if (f1 >= 0) and (f1 < maxCOD) then
301 if Map[Loc1] and fTerrain >= fGrass then
302 ContinentPresence[f1] := ContinentPresence[f1] or PresenceUnknown
303 else
304 OceanPresence[f1] := OceanPresence[f1] or PresenceUnknown;
305 end;
306 end;
307 end;
308 nfPeace:
309 begin // nation present in adjacent formations
310 V8_to_Loc(Loc, Adjacent);
311 for V8 := 0 to 7 do
312 begin
313 Loc1 := Adjacent[V8];
314 if Loc1 >= 0 then
315 begin
316 f1 := Formation[Loc1];
317 if (f1 >= 0) and (f1 < maxCOD) then
318 if Map[Loc1] and fTerrain >= fGrass then
319 ContinentPresence[f1] :=
320 ContinentPresence[f1] or (1 shl RO.Territory[Loc])
321 else
322 OceanPresence[f1] := OceanPresence[f1] or (1 shl RO.Territory[Loc]);
323 end;
324 end;
325 end;
326 end;
327 end;
328
329 Neighbours := 0;
330 for cix := 0 to RO.nCity - 1 do
331 with MyCity[cix] do
332 if (Loc >= 0) and (Formation[Loc] >= 0) and (Formation[Loc] < maxCOD) then
333 Neighbours := Neighbours or ContinentPresence[Formation[Loc]];
334 Neighbours := Neighbours and not PresenceUnknown;
335
336 TurnOfMapAnalysis := RO.Turn;
337end;
338
339procedure TBarbarina.FindBestModels;
340var
341 i, mix, rmix, cat: integer;
342begin
343 for i := 0 to nModelCategory - 1 do
344 mixBest[i] := -1;
345 for rmix := nResearchModel - 1 downto 0 do
346 with ResearchModel[rmix] do
347 if mixBest[Category] < 0 then
348 for mix := 3 to RO.nModel - 1 do
349 if (MyModel[mix].Domain = Domain) and
350 (Upgrades and not MyModel[mix].Upgrades = 0) then
351 begin
352 mixBest[Category] := mix;
353 for i := 0 to nFeature - 1 do
354 if MyModel[mix].Cap[i] < Cap[i] then
355 begin
356 mixBest[Category] := -1;
357 break;
358 end;
359 if mixBest[Category] >= 0 then
360 break;
361 end;
362 for mix := 3 to RO.nModel - 1 do
363 with MyModel[mix] do
364 if Kind <= mkEnemyDeveloped then
365 begin
366 cat := -1;
367 case Domain of
368 dGround:
369 if Speed >= 250 then
370 cat := ctGroundFast
371 else
372 cat := ctGroundSlow;
373 dSea:
374 if Cap[mcSeaTrans] > 0 then
375 cat := ctSeaTrans
376 else if Cap[mcArtillery] > 0 then
377 cat := ctSeaArt;
378 end;
379 if (cat >= 0) and (mix <> mixBest[cat]) and
380 ((mixBest[cat] < 0) or (Weight * MStrength > MyModel[mixBest[cat]].Weight +
381 MyModel[mixBest[cat]].MStrength)) then
382 mixBest[cat] := mix;
383 end;
384 if (mixBest[ctSeaTrans] < 0) and not IsResearched(adExplosives) then // longboat?
385 for mix := 3 to RO.nModel - 1 do
386 if MyModel[mix].Cap[mcSeaTrans] > 0 then
387 begin
388 mixBest[ctSeaTrans] := mix;
389 break;
390 end;
391end;
392
393procedure TBarbarina.Barbarina_DoTurn;
394begin
395 if (RO.Government in [gRepublic, gDemocracy, gFuture]) or
396 (RO.Government <> gFundamentalism) and (RO.Government <> gAnarchy) and
397 IsResearched(adTheology) then
398 Revolution;
399
400 AnalyzeMap;
401
402 FindBestModels;
403
404 AttackAndPatrol;
405end;
406
407// find one unit to destroy each known enemy unit, result in uixAttack
408procedure TBarbarina.RateAttack(uix: integer);
409var
410 MoveStyle, TestLoc, TestTime, NextLoc, NextTime, V8, RemHealth,
411 RecoverTurns, Score, BestScore, euixBest, uixOld: integer;
412 NextTile: cardinal;
413 Adjacent: TVicinity8Loc;
414 Defense: ^TUnitInfo;
415 Reached: array[0..lxmax * lymax - 1] of boolean;
416begin
417 with MyUnit[uix] do
418 if Movement > 0 then
419 begin
420 BestScore := 0;
421 fillchar(Reached, MapSize, False);
422 MoveStyle := GetMyMoveStyle(mix, Health);
423 Pile.Create(MapSize);
424 Pile.Put(Loc, $800 - Movement);
425 while Pile.Get(TestLoc, TestTime) do
426 begin
427 Reached[TestLoc] := True;
428 V8_to_Loc(TestLoc, Adjacent);
429 for V8 := 0 to 7 do
430 begin
431 NextLoc := Adjacent[V8];
432 if (NextLoc >= 0) and not Reached[NextLoc] then
433 begin
434 NextTile := Map[NextLoc];
435 if euixMap[NextLoc] >= 0 then
436 begin // check attack
437 Defense := @RO.EnemyUn[euixMap[NextLoc]];
438 if Unit_AttackForecast(uix, NextLoc, $800 - TestTime, RemHealth) then
439 begin
440 if RemHealth <= 0 then // send unit into death?
441 begin
442 Score := 0;
443 if ($800 - TestTime >= 100) and
444 ((MyModel[mix].Domain = dGround) and
445 (NextTile and fTerrain >= fGrass) or
446 (MyModel[mix].Domain = dSea) and (NextTile and
447 fTerrain < fGrass)) and
448 (MyModel[mix].Attack > MyModel[mix].Defense) then
449 begin
450 Score := (Defense.Health + RemHealth) *
451 RO.EnemyModel[Defense.emix].Cost * 2 div MyModel[mix].Cost;
452 if NextTile and fCity <> 0 then
453 Score := Score * 4;
454 end;
455 end
456 else
457 Score := RO.EnemyModel[Defense.emix].Cost * 25 -
458 (Health - RemHealth) * MyModel[mix].Cost shr 4;
459 if (Score > BestScore) and (Score > AttackScore[euixMap[NextLoc]]) then
460 begin
461 BestScore := Score;
462 euixBest := euixMap[NextLoc];
463 end;
464 end;
465 end
466 else if (NextTile and (fUnit or fCity) = 0) or
467 (NextTile and fOwned <> 0) then
468 case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
469 RecoverTurns, Map[TestLoc], NextTile, True) of
470 csOk:
471 if NextTime < $800 then
472 Pile.Put(NextLoc, NextTime);
473 csForbiddenTile:
474 Reached[NextLoc] := True; // don't check moving there again
475 csCheckTerritory:
476 if (NextTime < $800) and (RO.Territory[NextLoc] =
477 RO.Territory[TestLoc]) then
478 Pile.Put(NextLoc, NextTime);
479 end;
480 end;
481 end;
482 end;
483 Pile.Free;
484
485 if BestScore > 0 then
486 begin
487 uixOld := uixAttack[euixBest];
488 AttackScore[euixBest] := BestScore;
489 uixAttack[euixBest] := uix;
490 if uixOld >= 0 then
491 RateAttack(uixOld);
492 end;
493 end;
494end;
495
496function TBarbarina.DoAttack(uix, AttackLoc: integer): boolean;
497 // AttackLoc=maNextCity means bombard only
498var
499 MoveResult, Kind, Temp, MoveStyle, TestLoc, TestTime, NextLoc,
500 NextTime, V8, RecoverTurns, ecix: integer;
501 NextTile: cardinal;
502 AttackPositionReached, IsBombardment: boolean;
503 Adjacent: TVicinity8Loc;
504 PreLoc: array[0..lxmax * lymax - 1] of word;
505 Reached: array[0..lxmax * lymax - 1] of boolean;
506begin
507 Result := False;
508 IsBombardment := AttackLoc = maNextCity;
509 with MyUnit[uix] do
510 begin
511 if (MyModel[mix].Domain = dGround) and (MyModel[mix].Attack > 0) then
512 if MyModel[mix].Speed >= 250 then
513 Kind := ukFast
514 else
515 Kind := ukSlow
516 else
517 Kind := 0;
518 fillchar(Reached, MapSize, False);
519 AttackPositionReached := False;
520 MoveStyle := GetMyMoveStyle(mix, Health);
521 Pile.Create(MapSize);
522 Pile.Put(Loc, $800 - Movement);
523 while Pile.Get(TestLoc, TestTime) do
524 begin
525 if (TestTime >= $800) or (AttackLoc = maNextCity) and (TestTime > $800 - 100) then
526 break;
527 Reached[TestLoc] := True;
528 V8_to_Loc(TestLoc, Adjacent);
529 for V8 := 0 to 7 do
530 begin
531 NextLoc := Adjacent[V8];
532 if NextLoc >= 0 then
533 begin
534 if IsBombardment and (Map[NextLoc] and (fCity or
535 fUnit or fOwned or fObserved) = fCity or fObserved) and
536 (RO.Treaty[RO.Territory[NextLoc]] < trPeace) then
537 begin
538 City_FindEnemyCity(NextLoc, ecix);
539 assert(ecix >= 0);
540 with RO.EnemyCity[ecix] do
541 if (Size > 2) and (Flags and ciCoastalFort = 0) then
542 AttackLoc := NextLoc;
543 end;
544 if (NextLoc = AttackLoc) and ((MyModel[mix].Domain <> dSea) or
545 (Map[TestLoc] and fTerrain < fGrass)) then
546 // ships can only attack from water
547 begin
548 AttackPositionReached := True;
549 break;
550 end
551 else if not Reached[NextLoc] then
552 begin
553 NextTile := Map[NextLoc];
554 if (NextTile and (fUnit or fCity) = 0) or
555 (NextTile and fOwned <> 0) then
556 case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
557 RecoverTurns, Map[TestLoc], NextTile, True) of
558 csOk:
559 if Pile.Put(NextLoc, NextTime) then
560 PreLoc[NextLoc] := TestLoc;
561 csForbiddenTile:
562 Reached[NextLoc] := True; // don't check moving there again
563 csCheckTerritory:
564 if RO.Territory[NextLoc] = RO.Territory[TestLoc] then
565 if Pile.Put(NextLoc, NextTime) then
566 PreLoc[NextLoc] := TestLoc;
567 end;
568 end;
569 end;
570 end;
571 if AttackPositionReached then
572 begin
573 PreLoc[NextLoc] := TestLoc;
574 break;
575 end;
576 end;
577 Pile.Free;
578 if not AttackPositionReached then
579 exit;
580
581 TestLoc := AttackLoc;
582 NextLoc := PreLoc[TestLoc];
583 while TestLoc <> Loc do
584 begin
585 Temp := TestLoc;
586 TestLoc := NextLoc;
587 NextLoc := PreLoc[TestLoc];
588 PreLoc[TestLoc] := Temp;
589 end;
590
591 UnitPresence[Loc] := UnitPresence[Loc] and not Kind;
592 // assume unit was only one of kind here
593 repeat
594 NextLoc := PreLoc[Loc];
595 MoveResult := Unit_Step(uix, NextLoc);
596 until (NextLoc = AttackLoc) or (MoveResult and rExecuted = 0) or
597 (MoveResult and rUnitRemoved <> 0);
598 Result := (NextLoc = AttackLoc) and (MoveResult and rExecuted <> 0);
599
600 if IsBombardment and Result then
601 begin
602 City_FindEnemyCity(AttackLoc, ecix);
603 assert(ecix >= 0);
604 while (Movement >= 100) and (RO.EnemyCity[ecix].Size > 2) do
605 Unit_Step(uix, AttackLoc);
606 end;
607
608 if Loc >= 0 then
609 UnitPresence[Loc] := UnitPresence[Loc] or Kind;
610 end;
611end;
612
613function TBarbarina.ProcessMove(uix: integer): boolean;
614 // return true if no new enemy spotted
615const
616 DistanceScore = 4;
617var
618 PatrolScore, BestCount, PatrolLoc, TestLoc, NextLoc, TestTime, V8,
619 TestScore, MoveResult, MoveStyle, NextTime, TerrOwner, Kind, Temp,
620 RecoverTurns, MaxScore: integer;
621 Tile, NextTile: cardinal;
622 CaptureOnly, PeaceBorder, done, NextToEnemyCity: boolean;
623 Adjacent: TVicinity8Loc;
624 AdjacentUnknown: array[0..lxmax * lymax - 1] of shortint;
625 PreLoc: array[0..lxmax * lymax - 1] of word;
626 MoreTurn: array[0..lxmax * lymax - 1] of byte;
627
628begin
629 Result := True;
630 done := False;
631 while not done do
632 with MyUnit[uix] do
633 begin
634 if (MyModel[mix].Domain = dSea) and (Health < 100) and
635 ((Health < 34) or (MyModel[mix].Cap[mcSeaTrans] > 0)) then
636 begin
637 if Map[Loc] and fCity = 0 then
638 Unit_MoveEx(uix, maNextCity);
639 exit;
640 end;
641
642 if (MyModel[mix].Domain = dGround) and (MyModel[mix].Attack > 0) then
643 if MyModel[mix].Speed >= 250 then
644 Kind := ukFast
645 else
646 Kind := ukSlow
647 else
648 Kind := 0;
649 CaptureOnly := (Health < 100) and ((Map[Loc] and fCity <> 0) or
650 ((100 - Health) * Terrain[Map[Loc] and fTerrain].Defense > 60) and
651 not (Map[Loc] and fTerrain in [fOcean, fShore, fArctic, fDesert]));
652 MoveStyle := GetMyMoveStyle(mix, Health);
653
654 if MyModel[mix].Attack > 0 then
655 MaxScore := $400
656 else
657 MaxScore := $400 - 32 + 5;
658 PatrolScore := -999999;
659 PatrolLoc := -1;
660 FillChar(AdjacentUnknown, MapSize, $FF); // -1, indicates tiles not checked yet
661 Pile.Create(MapSize);
662 Pile.Put(Loc, $800 - Movement);
663 while Pile.Get(TestLoc, TestTime) do
664 begin
665 if (MaxScore * $1000 - DistanceScore * TestTime <= PatrolScore)
666 // assume a score of $400 is the best achievable
667 or CaptureOnly and (TestTime >= $1000) then
668 break;
669
670 TestScore := 0;
671 Tile := Map[TestLoc];
672 assert(Tile and (fUnit or fOwned) <> fUnit);
673 TerrOwner := RO.Territory[TestLoc];
674 AdjacentUnknown[TestLoc] := 0;
675 PeaceBorder := False;
676 NextToEnemyCity := False;
677
678 if ((Tile and fCity) <> 0) and ((Tile and fOwned) = 0) then
679 begin
680 if (MyModel[mix].Domain = dGround) and (MyModel[mix].Attack > 0) and
681 ((TerrOwner < 0)
682 // happens only for unobserved cities of extinct tribes, new owner unknown
683 or (RO.Treaty[TerrOwner] < trPeace)) then
684 if (Tile and fObserved <> 0) and (Tile and fUnit = 0) then
685 TestScore := $400 // unfriendly undefended city -- capture!
686 else
687 TestScore := $400 - 14; // unfriendly city, not observed or defended
688 end
689
690 else
691 begin // no enemy city or unit here
692 V8_to_Loc(TestLoc, Adjacent);
693 for V8 := 0 to 7 do
694 begin
695 NextLoc := Adjacent[V8];
696 if (NextLoc >= 0) and (AdjacentUnknown[NextLoc] < 0) then
697 begin
698 NextTile := Map[NextLoc];
699 if NextTile and fTerrain = fUNKNOWN then
700 Inc(AdjacentUnknown[TestLoc])
701 else if NextTile and fTerrain = fArctic then
702 else if NextTile and (fCity or fUnit or fOwned or fObserved) =
703 fCity or fUnit or fObserved then
704 NextToEnemyCity := True
705 else
706 case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
707 RecoverTurns, Tile, NextTile, True) of
708 csOk:
709{ if (NextTime and $7FFFF000=TestTime and $7FFFF000)
710 or (UnitPresence[TestLoc] and Kind=0)
711 or (Tile and fCity<>0)
712 or (Tile and fTerImp=tiFort) or (Tile and fTerImp=tiBase) then}
713 begin
714 if Pile.Put(NextLoc, NextTime + RecoverTurns * $1000) then
715 begin
716 PreLoc[NextLoc] := TestLoc;
717 MoreTurn[NextLoc] := NextTime shr 12 and $FFF;
718 end;
719 end;
720 csForbiddenTile:
721 begin
722 AdjacentUnknown[NextLoc] := 0; // don't check moving there again
723 if NextTile and fPeace <> 0 then
724 PeaceBorder := True;
725 end;
726 csCheckTerritory:
727 if RO.Territory[NextLoc] = TerrOwner then
728 begin
729 if Pile.Put(NextLoc, NextTime + RecoverTurns * $1000) then
730 begin
731 PreLoc[NextLoc] := TestLoc;
732 MoreTurn[NextLoc] := NextTime shr 12 and $FFF;
733 end;
734 end
735 else
736 PeaceBorder := True;
737 end;
738 end;
739 end;
740 if not CaptureOnly then
741 if NextToEnemyCity and (MyModel[mix].Attack > 0) and
742 (MyModel[mix].Domain = dGround) then
743 TestScore := $400 - 14
744 else if AdjacentUnknown[TestLoc] > 0 then
745 if PeaceBorder or (TerrOwner >= 0) and (TerrOwner <> me) and
746 (RO.Treaty[TerrOwner] < trPeace) then
747 TestScore := $400 - 32 + AdjacentUnknown[TestLoc]
748 else
749 TestScore := $400 - 64 + AdjacentUnknown[TestLoc]
750 else if PeaceBorder then
751 TestScore := $400 - 32
752 else
753 TestScore := (RO.Turn - RO.MapObservedLast[TestLoc]) div 16;
754 end; // no enemy city or unit here
755
756 if TestScore > 0 then
757 begin
758 TestScore := TestScore * $1000 - DistanceScore * TestTime;
759 if TestScore > PatrolScore then
760 BestCount := 0;
761 if TestScore >= PatrolScore then
762 begin
763 Inc(BestCount);
764 if random(BestCount) = 0 then
765 begin
766 PatrolScore := TestScore;
767 PatrolLoc := TestLoc;
768 end;
769 end;
770 end;
771 end; // while Pile.Get
772 Pile.Free;
773
774 if (PatrolLoc >= 0) and (PatrolLoc <> Loc) then
775 begin // capture/discover/patrol task found, execute it
776 while (PatrolLoc <> Loc) and (MoreTurn[PatrolLoc] > 0) and
777 ((MoreTurn[PatrolLoc] > 1) or not (Map[PatrolLoc] and fTerrain in
778 [fMountains, fDesert, fArctic])) do
779 begin
780 PatrolLoc := PreLoc[PatrolLoc];
781 done := True; // no effect if enemy spotted
782 end;
783 while (PatrolLoc <> Loc) and (UnitPresence[PatrolLoc] and Kind <> 0) and
784 (Map[PatrolLoc] and fCity = 0) and (Map[PatrolLoc] and fTerImp <> tiFort) and
785 (Map[PatrolLoc] and fTerImp <> tiBase) and not
786 (Map[PreLoc[PatrolLoc]] and fTerrain in [fDesert, fArctic]) do
787 begin
788 PatrolLoc := PreLoc[PatrolLoc];
789 done := True; // no effect if enemy spotted
790 end;
791 if PatrolLoc = Loc then
792 exit;
793 TestLoc := PatrolLoc;
794 NextLoc := PreLoc[TestLoc];
795 while TestLoc <> Loc do
796 begin
797 Temp := TestLoc;
798 TestLoc := NextLoc;
799 NextLoc := PreLoc[TestLoc];
800 PreLoc[TestLoc] := Temp;
801 end;
802
803 UnitPresence[Loc] := UnitPresence[Loc] and not Kind;
804 // assume unit was only one of kind here
805 while Loc <> PatrolLoc do
806 begin
807 NextLoc := PreLoc[Loc];
808 MoveResult := Unit_Step(uix, NextLoc);
809 if (MoveResult and (rUnitRemoved or rEnemySpotted) <> 0) or
810 (MoveResult and rExecuted = 0) then
811 begin
812 if MoveResult and rExecuted = 0 then
813 Moved[uix] := True;
814 Result := MoveResult and rEnemySpotted = 0;
815 done := True;
816 break;
817 end;
818 assert(Loc = NextLoc);
819 end;
820 if Loc >= 0 then
821 begin
822 UnitPresence[Loc] := UnitPresence[Loc] or Kind;
823 if Map[Loc] and fCity <> 0 then
824 begin
825 Moved[uix] := True;
826 done := True; // stay in captured city as defender
827 end;
828 end;
829 end
830 else
831 done := True;
832 end; // while not done
833 if Result then
834 Moved[uix] := True;
835end; // ProcessMove
836
837procedure TBarbarina.AttackAndPatrol;
838
839 procedure SetCityDefenders;
840 var
841 uix, cix, V8, Loc1, Best, uixBest, det: integer;
842 Adjacent: TVicinity8Loc;
843 IsPort: boolean;
844 begin
845 for cix := 0 to RO.nCity - 1 do
846 with MyCity[cix] do
847 if Loc >= 0 then
848 begin
849 IsPort := False;
850 V8_to_Loc(Loc, Adjacent);
851 for V8 := 0 to 7 do
852 begin
853 Loc1 := Adjacent[V8];
854 if (Loc1 >= 0) and (Map[Loc1] and fTerrain < fGrass) and
855 (Formation[Loc1] >= 0) and (Formation[Loc1] < maxCOD) and
856 (OceanPresence[Formation[Loc1]] and not Neighbours <> 0) then
857 IsPort := True;
858 end;
859 Best := -1;
860 for uix := 0 to RO.nUn - 1 do
861 if MyUnit[uix].Loc = Loc then
862 with MyUnit[uix] do
863 if (MyModel[mix].Domain = dGround) and (MyModel[mix].Attack > 0) then
864 begin
865 if (mix = 2) and (RO.Government = gDespotism) then
866 begin
867 det := 1 shl 16;
868 Moved[uix] := True;
869 end // town guard
870 else if IsPort then
871 det := MyModel[mix].Defense shl 8 + Flags and
872 unFortified shl 7 - health
873 else
874 det := MyModel[mix].Speed shl 8 + Flags and
875 unFortified shl 7 - health;
876 if det > Best then
877 begin
878 Best := det;
879 uixBest := uix;
880 end;
881 end;
882 if Best >= 0 then
883 Moved[uixBest] := True;
884 end;
885 end;
886
887 procedure ProcessSeaTransport;
888 var
889 i, f, uix, Loc1, a, b: integer;
890 ready, go: boolean;
891 TransportPlan: TGroupTransportPlan;
892 begin
893 go := False;
894 for f := 0 to maxCOD - 1 do
895 if (f < nContinent) and (ContinentPresence[f] and not
896 (1 shl me or PresenceUnknown) <> 0) then
897 go := True; // any enemy island known?
898 if not go then
899 exit;
900
901 SeaTransport_BeginInitialize;
902 go := False;
903 for uix := 0 to RO.nUn - 1 do
904 if not Moved[uix] then
905 with MyUnit[uix] do
906 if (Loc >= 0) and (MyModel[mix].Domain = dGround) and
907 (MyModel[mix].Attack > 0) and (Map[Loc] and fTerrain >= fGrass) then
908 begin
909 f := Formation[Loc];
910 if (f >= 0) and (f < maxCOD) and (ContinentPresence[f] and
911 not (1 shl me) = 0) then
912 begin
913 go := True;
914 SeaTransport_AddLoad(uix);
915 end;
916 end;
917 if go then
918 begin
919 go := False;
920 for uix := 0 to RO.nUn - 1 do
921 if not Moved[uix] then
922 with MyUnit[uix] do
923 if (Loc >= 0) and (mix = mixBest[ctSeaTrans]) and
924 (TroopLoad = 0) and (Health = 100) then
925 begin
926 go := True;
927 SeaTransport_AddTransport(uix);
928 end;
929 end;
930 if go then
931 for Loc1 := 0 to MapSize - 1 do
932 if Map[Loc1] and fTerrain >= fGrass then
933 begin
934 f := Formation[Loc1];
935 if (f >= 0) and (f < maxCOD) and (ContinentPresence[f] and
936 not (1 shl me or PresenceUnknown) <> 0) then
937 SeaTransport_AddDestination(Loc1);
938 end;
939 SeaTransport_EndInitialize;
940 while SeaTransport_MakeGroupPlan(TransportPlan) do
941 begin
942 Moved[TransportPlan.uixTransport] := True;
943 ready := MyUnit[TransportPlan.uixTransport].Loc = TransportPlan.LoadLoc;
944 if not ready then
945 begin
946 Unit_MoveEx(TransportPlan.uixTransport, TransportPlan.LoadLoc);
947 ready := MyUnit[TransportPlan.uixTransport].Loc = TransportPlan.LoadLoc;
948 end;
949 if ready then
950 for i := 0 to TransportPlan.nLoad - 1 do
951 begin
952 Loc_to_ab(TransportPlan.LoadLoc,
953 MyUnit[TransportPlan.uixLoad[i]].Loc, a, b);
954 ready := ready and (abs(a) <= 1) and (abs(b) <= 1);
955 end;
956 if ready then
957 begin
958 for i := 0 to TransportPlan.nLoad - 1 do
959 begin
960 Unit_Step(TransportPlan.uixLoad[i], TransportPlan.LoadLoc);
961 Moved[TransportPlan.uixLoad[i]] := True;
962 end;
963 end
964 else
965 begin
966 for i := 0 to TransportPlan.nLoad - 1 do
967 begin
968 Unit_MoveEx(TransportPlan.uixLoad[i], TransportPlan.LoadLoc, mxAdjacent);
969 Moved[TransportPlan.uixLoad[i]] := True;
970 end;
971 end;
972 end;
973 end;
974
975 procedure ProcessUnload(uix: integer);
976
977 procedure Unload(Kind, ToLoc: integer);
978 var
979 uix1: integer;
980 begin
981 for uix1 := 0 to RO.nUn - 1 do
982 with MyUnit[uix1] do
983 if (Loc >= 0) and (Master = uix) and (MyModel[mix].Domain = dGround) and
984 (MyModel[mix].Attack > 0) and (Movement = MyModel[mix].Speed) and
985 ((MyModel[mix].Speed >= 250) = (Kind = ukFast)) then
986 begin
987 Unit_Step(uix1, ToLoc);
988 UnitPresence[ToLoc] := UnitPresence[ToLoc] or Kind;
989 break;
990 end;
991 end;
992
993 var
994 uix1, MoveStyle, TestLoc, TestTime, NextLoc, NextTime, V8,
995 RecoverTurns, nSlow, nFast, SlowUnloadLoc, FastUnloadLoc, EndLoc, f: integer;
996 NextTile: cardinal;
997 Adjacent: TVicinity8Loc;
998 Reached: array[0..lxmax * lymax - 1] of boolean;
999 begin
1000 // inventory
1001 nSlow := 0;
1002 nFast := 0;
1003 for uix1 := 0 to RO.nUn - 1 do
1004 with MyUnit[uix1] do
1005 if (Loc >= 0) and (Master = uix) and (MyModel[mix].Domain = dGround) and
1006 (MyModel[mix].Attack > 0) then
1007 if MyModel[mix].Speed >= 250 then
1008 Inc(nFast)
1009 else
1010 Inc(nSlow);
1011
1012 with MyUnit[uix] do
1013 begin
1014 MoveStyle := GetMyMoveStyle(mix, Health);
1015 repeat
1016 SlowUnloadLoc := -1;
1017 FastUnloadLoc := -1;
1018 EndLoc := -1;
1019 fillchar(Reached, MapSize, False);
1020 Pile.Create(MapSize);
1021 Pile.Put(Loc, $800 - Movement);
1022 while (SlowUnloadLoc < 0) and (FastUnloadLoc < 0) and
1023 Pile.Get(TestLoc, TestTime) do
1024 begin
1025 Reached[TestLoc] := True;
1026 V8_to_Loc(TestLoc, Adjacent);
1027 for V8 := 0 to 7 do
1028 begin
1029 NextLoc := Adjacent[V8];
1030 if (NextLoc >= 0) and not Reached[NextLoc] then
1031 begin
1032 NextTile := Map[NextLoc];
1033 if NextTile and fTerrain = fUnknown then
1034 else if NextTile and fTerrain >= fGrass then
1035 begin
1036 f := Formation[NextLoc];
1037 if (f >= 0) and (f < maxCOD) and
1038 (ContinentPresence[f] and not (1 shl me or PresenceUnknown) <> 0) and
1039 (NextTile and (fUnit or fOwned) <> fUnit) then
1040 begin
1041 if (nSlow > 0) and (UnitPresence[NextLoc] and
1042 ukSlow = 0) and ((SlowUnloadLoc < 0) or
1043 (Terrain[Map[NextLoc] and fTerrain].Defense >
1044 Terrain[Map[SlowUnloadLoc] and fTerrain].Defense)) then
1045 begin
1046 EndLoc := TestLoc;
1047 SlowUnloadLoc := NextLoc;
1048 end;
1049 if (nFast > 0) and (UnitPresence[NextLoc] and
1050 ukFast = 0) and ((FastUnloadLoc < 0) or
1051 (Terrain[Map[NextLoc] and fTerrain].Defense >
1052 Terrain[Map[FastUnloadLoc] and fTerrain].Defense)) then
1053 begin
1054 EndLoc := TestLoc;
1055 FastUnloadLoc := NextLoc;
1056 end;
1057 end;
1058 end
1059 else if EndLoc < 0 then
1060 case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
1061 RecoverTurns, Map[TestLoc], NextTile, True) of
1062 csOk:
1063 Pile.Put(NextLoc, NextTime);
1064 csForbiddenTile:
1065 Reached[NextLoc] := True; // don't check moving there again
1066 csCheckTerritory:
1067 if RO.Territory[NextLoc] = RO.Territory[TestLoc] then
1068 Pile.Put(NextLoc, NextTime);
1069 end;
1070 end;
1071 end;
1072 end;
1073 Pile.Free;
1074
1075 if EndLoc < 0 then
1076 exit;
1077 if Loc <> EndLoc then
1078 Unit_MoveEx(uix, EndLoc);
1079 if Loc <> EndLoc then
1080 exit;
1081 if SlowUnloadLoc >= 0 then
1082 begin
1083 Unload(ukSlow, SlowUnloadLoc);
1084 Dec(nSlow);
1085 end;
1086 if FastUnloadLoc >= 0 then
1087 begin
1088 Unload(ukFast, FastUnloadLoc);
1089 Dec(nFast);
1090 end;
1091 if TroopLoad = 0 then
1092 begin
1093 Moved[uix] := False;
1094 exit;
1095 end
1096 until False;
1097 end;
1098 end;
1099
1100var
1101 uix, euix, Kind, euixBest, AttackLoc: integer;
1102 OldTile: cardinal;
1103 BackToStart, FirstLoop: boolean;
1104begin
1105 fillchar(UnitPresence, MapSize, 0);
1106 for uix := 0 to RO.nUn - 1 do
1107 with MyUnit[uix] do
1108 if (Loc >= 0) and (MyModel[mix].Domain = dGround) and
1109 (MyModel[mix].Attack > 0) then
1110 begin
1111 if MyModel[mix].Speed >= 250 then
1112 Kind := ukFast
1113 else
1114 Kind := ukSlow;
1115 UnitPresence[Loc] := UnitPresence[Loc] or Kind;
1116 end;
1117
1118 fillchar(Moved, RO.nUn, False);
1119 for uix := 0 to RO.nUn - 1 do
1120 if (MyUnit[uix].Master >= 0) or (MyUnit[uix].TroopLoad > 0) then
1121 Moved[uix] := True;
1122
1123 FirstLoop := True;
1124 repeat
1125 // ATTACK
1126 repeat
1127 BackToStart := False;
1128 if RO.nEnemyUn > 0 then
1129 begin
1130 fillchar(euixMap, MapSize * 2, $FF);
1131 fillchar(AttackScore, RO.nEnemyUn * 4, 0);
1132 for euix := 0 to RO.nEnemyUn - 1 do
1133 with RO.EnemyUn[euix] do
1134 if (Loc >= 0) and (RO.Treaty[Owner] < trPeace) then
1135 begin
1136 BackToStart := True;
1137 euixMap[Loc] := euix;
1138 uixAttack[euix] := -1;
1139 end;
1140 end;
1141 if not BackToStart then
1142 break;
1143
1144 for uix := 0 to RO.nUn - 1 do
1145 with MyUnit[uix] do
1146 if (Loc >= 0) and (Master < 0) and (MyModel[mix].Attack > 0) then
1147 RateAttack(uix);
1148
1149 BackToStart := False;
1150 repeat
1151 euixBest := -1;
1152 for euix := 0 to RO.nEnemyUn - 1 do
1153 if (AttackScore[euix] > 0) and ((euixBest < 0) or
1154 (AttackScore[euix] > AttackScore[euixBest])) then
1155 euixBest := euix;
1156 if euixBest < 0 then
1157 break;
1158 uix := uixAttack[euixBest];
1159 AttackLoc := RO.EnemyUn[euixBest].Loc;
1160 OldTile := Map[AttackLoc];
1161 if (AttackLoc < 0)
1162 // only happens when city was destroyd with attack and enemy units have disappeared
1163 or (DoAttack(uix, AttackLoc) and
1164 ((Map[AttackLoc] and fUnit <> 0) or (OldTile and fCity <> 0) and
1165 (Map[AttackLoc] and fCity = 0))) then
1166 BackToStart := True // new situation, rethink
1167 else
1168 begin
1169 euixMap[AttackLoc] := -1;
1170 AttackScore[euixBest] := 0;
1171 uixAttack[euixBest] := -1;
1172 if MyUnit[uix].Loc >= 0 then
1173 RateAttack(uix);
1174 end
1175 until BackToStart
1176 until not BackToStart;
1177
1178 if FirstLoop then
1179 begin
1180 SetCityDefenders;
1181 ProcessSeaTransport;
1182 for uix := 0 to RO.nUn - 1 do
1183 with MyUnit[uix] do
1184 if (Loc >= 0) and (TroopLoad > 0) then
1185 ProcessUnload(uix);
1186 end;
1187 FirstLoop := False;
1188
1189 for uix := 0 to RO.nUn - 1 do
1190 with MyUnit[uix], MyModel[mix] do
1191 if not Moved[uix] and (Loc >= 0) and (Domain = dSea) and
1192 (Attack > 0) and (Cap[mcArtillery] > 0) then
1193 DoAttack(uix, maNextCity); // check bombardments
1194
1195 // MOVE
1196 for uix := 0 to RO.nUn - 1 do
1197 if not Moved[uix] then
1198 with MyUnit[uix] do
1199 if (Loc >= 0) and ((MyModel[mix].Attack > 0) or
1200 (MyModel[mix].Domain = dSea)) then
1201 if not ProcessMove(uix) then
1202 begin
1203 BackToStart := True;
1204 break;
1205 end
1206 until not BackToStart;
1207end; // AttackAndPatrol
1208
1209procedure TBarbarina.Barbarina_SetCityProduction;
1210
1211const
1212 CoastalWonder = 1 shl woLighthouse + 1 shl woMagellan;
1213 PrimeWonder = 1 shl woColossus + 1 shl woGrLibrary + 1 shl woSun +
1214 1 shl woMagellan + 1 shl woEiffel + 1 shl woLiberty + 1 shl woShinkansen;
1215
1216 function LowPriority(cix: integer): boolean;
1217 var
1218 part, cixHighPriority, TestDistance: integer;
1219 begin
1220 Result := False;
1221 for part := 0 to nShipPart - 1 do
1222 begin
1223 cixHighPriority := ColonyShipPlan[part].cixProducing;
1224 if (cixHighPriority >= 0) and (cixHighPriority <> cix) then
1225 begin
1226 TestDistance := Distance(MyCity[cix].Loc, MyCity[cixHighPriority].Loc);
1227 if TestDistance < 11 then
1228 begin
1229 Result := True;
1230 exit;
1231 end;
1232 end;
1233 end;
1234 end;
1235
1236 function ChooseWonderToBuild(WonderAvailable: integer; AllowCoastal: boolean): integer;
1237 var
1238 Count, iix: integer;
1239 begin
1240 if (WonderAvailable and PrimeWonder > 0) and (AllowCoastal or
1241 (WonderAvailable and PrimeWonder and not CoastalWonder > 0)) then
1242 WonderAvailable := WonderAvailable and PrimeWonder; // alway prefer prime wonders
1243 Count := 0;
1244 for iix := 0 to 27 do
1245 begin
1246 if (1 shl iix) and WonderAvailable <> 0 then
1247 if (1 shl iix) and CoastalWonder <> 0 then
1248 begin
1249 if AllowCoastal then
1250 Inc(Count, 2);
1251 end
1252 else
1253 Inc(Count);
1254 end;
1255 Count := Random(Count);
1256 for iix := 0 to 27 do
1257 begin
1258 if (1 shl iix) and WonderAvailable <> 0 then
1259 if (1 shl iix) and CoastalWonder <> 0 then
1260 begin
1261 if AllowCoastal then
1262 Dec(Count, 2);
1263 end
1264 else
1265 Dec(Count);
1266 if Count < 0 then
1267 begin
1268 Result := iix;
1269 exit;
1270 end;
1271 end;
1272 end;
1273
1274var
1275 i, iix, cix, mix, uix, mixProduce, mixShip, V8, V21, Loc1, TotalPop,
1276 AlonePop, f, f1, nTownGuard, ShipPart, ProduceShipPart, TestDistance,
1277 part, WonderAvailable, WonderInWork, cixNewCapital, Center, Score, BestScore: integer;
1278 mixCount: array[0..nmmax - 1] of integer;
1279 //RareLoc: array[0..5] of integer;
1280 Adjacent: TVicinity8Loc;
1281 IsCoastal, IsPort, IsUnitProjectObsolete, HasSettler, SpezializeShipProduction,
1282 AlgaeAvailable, ProjectComplete, DoLowPriority, WillProduceColonyShip,
1283 ImportantCity: boolean;
1284 Radius: TVicinity21Loc;
1285 Report: TCityReportNew;
1286begin
1287 AnalyzeMap;
1288
1289 FindBestModels;
1290
1291 fillchar(mixCount, RO.nModel * 4, 0);
1292 for uix := 0 to RO.nUn - 1 do
1293 with MyUnit[uix] do
1294 if Loc >= 0 then
1295 Inc(mixCount[mix]);
1296 if (mixBest[ctGroundSlow] >= 0) and ((mixBest[ctGroundFast] < 0) or
1297 (mixCount[mixBest[ctGroundSlow]] < mixCount[mixBest[ctGroundFast]])) then
1298 mixProduce := mixBest[ctGroundSlow]
1299 else
1300 mixProduce := mixBest[ctGroundFast];
1301 if (mixBest[ctSeaTrans] >= 0) and ((mixBest[ctSeaArt] < 0) or
1302 (mixCount[mixBest[ctSeaTrans]] < mixCount[mixBest[ctSeaArt]])) then
1303 mixShip := mixBest[ctSeaTrans]
1304 else
1305 mixShip := mixBest[ctSeaArt];
1306 if (mixProduce >= 0) and (mixBest[ctSeaTrans] >= 0) and
1307 (mixCount[mixShip] * RO.Model[mixBest[ctSeaTrans]].Cap[mcSeaTrans] *
1308 RO.Model[mixBest[ctSeaTrans]].MTrans div 2 >= mixCount[mixProduce]) then
1309 mixShip := -1;
1310
1311 // produce ships only on certain continents?
1312 TotalPop := 0;
1313 AlonePop := 0;
1314 for cix := 0 to RO.nCity - 1 do
1315 with MyCity[cix] do
1316 if (Loc >= 0) and (Flags and chCaptured = 0) then
1317 begin
1318 Inc(TotalPop, Size);
1319 f := Formation[Loc];
1320 if (f < 0) or (f >= maxCOD) or (ContinentPresence[f] = 1 shl me) then
1321 Inc(AlonePop, Size);
1322 end;
1323 SpezializeShipProduction := AlonePop * 2 >= TotalPop;
1324
1325 cixNewCapital := -1;
1326 WonderAvailable := 0;
1327 WonderInWork := 0;
1328 for iix := 0 to 27 do
1329 if (Imp[iix].Preq <> preNA) and ((Imp[iix].Preq = preNone) or
1330 IsResearched(Imp[iix].Preq)) and (RO.Wonder[iix].CityID = WonderNotBuiltYet) then
1331 Inc(WonderAvailable, 1 shl iix);
1332 for cix := 0 to RO.nCity - 1 do
1333 if MyCity[cix].Loc >= 0 then
1334 begin
1335 iix := City_CurrentImprovementProject(cix);
1336 if (iix >= 0) and (iix < 28) then
1337 Inc(WonderInWork, 1 shl iix)
1338 else if iix = imPalace then
1339 cixNewCapital := cix;
1340 end;
1341
1342 if (RO.NatBuilt[imPalace] = 0) and (cixNewCapital < 0) then
1343 begin // palace was destroyed, build new one
1344 Center := CenterOfEmpire;
1345 BestScore := 0;
1346 for cix := 0 to RO.nCity - 1 do
1347 with MyCity[cix] do
1348 if (Loc >= 0) and (Flags and chCaptured = 0) then
1349 begin // evaluate city as new capital
1350 Score := Size * 12 + 512 - Distance(Loc, Center);
1351 V8_to_Loc(Loc, Adjacent);
1352 for V8 := 0 to 7 do
1353 begin
1354 Loc1 := Adjacent[V8];
1355 if (Loc1 >= 0) and (Map[Loc1] and fTerrain < fGrass) then
1356 begin
1357 f1 := Formation[Loc1];
1358 if (f1 >= 0) and (f1 < maxCOD) and
1359 ((OceanSize[f1] >= 8) or (OceanPresence[f1] and not
1360 (1 shl me) <> 0)) then
1361 begin // prefer non-coastal cities
1362 Dec(Score, 18);
1363 break;
1364 end;
1365 end;
1366 end;
1367 if Score > BestScore then
1368 begin
1369 BestScore := Score;
1370 cixNewCapital := cix;
1371 end;
1372 end;
1373 end;
1374
1375 AlgaeAvailable := (RO.NatBuilt[imAlgae] = 0) and
1376 (RO.Tech[Imp[imAlgae].Preq] >= tsApplicable);
1377 for cix := 0 to RO.nCity - 1 do
1378 with MyCity[cix] do
1379 if (Loc >= 0) and (Project and (cpImp + cpIndex) = cpImp + imAlgae) then
1380 AlgaeAvailable := False;
1381
1382 for cix := 0 to RO.nCity - 1 do
1383 with MyCity[cix] do
1384 if (Loc >= 0) and (Flags and chCaptured = 0) and LowPriority(cix) then
1385 City_SetTiles(cix, 1 shl CityOwnTile); // free all tiles of low-prio cities
1386 for DoLowPriority := False to True do
1387 for cix := 0 to RO.nCity - 1 do
1388 with MyCity[cix] do
1389 if (Loc >= 0) and (Flags and chCaptured = 0) and
1390 (LowPriority(cix) = DoLowPriority) then
1391 begin
1392 f := Formation[Loc];
1393 IsCoastal := False;
1394 IsPort := False;
1395 V8_to_Loc(Loc, Adjacent);
1396 for V8 := 0 to 7 do
1397 begin
1398 Loc1 := Adjacent[V8];
1399 if (Loc1 >= 0) and (Map[Loc1] and fTerrain < fGrass) then
1400 begin
1401 IsCoastal := True;
1402 f1 := Formation[Loc1];
1403 if (f1 >= 0) and (f1 < maxCOD) and (OceanSize[f1] >= 8) and
1404 (OceanPresence[f1] and not (1 shl me) <> 0) then
1405 begin
1406 IsPort := True;
1407 break;
1408 end;
1409 end;
1410 end;
1411 if (City_CurrentUnitProject(cix) >= 0) and
1412 (RO.Model[City_CurrentUnitProject(cix)].Kind <> mkSettler) then
1413 begin
1414 i := nModelCategory - 1;
1415 while (i >= 0) and (City_CurrentUnitProject(cix) <> mixBest[i]) do
1416 Dec(i);
1417 IsUnitProjectObsolete := i < 0;
1418 end
1419 else
1420 IsUnitProjectObsolete := False;
1421 if RO.Government = gDespotism then
1422 begin
1423 nTownGuard := 0;
1424 for uix := 0 to RO.nUn - 1 do
1425 if (MyUnit[uix].mix = mixTownGuard) and (MyUnit[uix].Loc = Loc) then
1426 Inc(nTownGuard);
1427 end;
1428
1429 iix := City_CurrentImprovementProject(cix);
1430 if (iix >= 0) and (iix < 28) or (iix = imPalace) or
1431 (iix = imShipComp) or (iix = imShipPow) or (iix = imShipHab) then
1432 City_OptimizeTiles(cix, rwMaxProd)
1433 else if size < 8 then
1434 City_OptimizeTiles(cix, rwMaxGrowth)
1435 else
1436 City_OptimizeTiles(cix, rwForceProd);
1437
1438 WillProduceColonyShip := False;
1439 ProduceShipPart := -1;
1440 for part := 0 to nShipPart - 1 do
1441 if ColonyShipPlan[part].cixProducing = cix then
1442 begin
1443 WillProduceColonyShip := True;
1444 ProduceShipPart := ShipImpIndex[part];
1445 end;
1446
1447 if cix = cixNewCapital then
1448 City_StartImprovement(cix, imPalace)
1449 else if (iix >= 0) and (iix < 28) and ((1 shl iix) and
1450 WonderAvailable <> 0) then
1451 // complete wonder production first
1452 else if (mixProduce >= 0) and (City_CurrentUnitProject(cix) >= 0) and
1453 not IsUnitProjectObsolete and ((Flags and chProduction = 0) or
1454 (RO.Model[City_CurrentUnitProject(cix)].Cap[mcLine] > 0) and
1455 (mixCount[City_CurrentUnitProject(cix)] < RO.nCity * (2 + cix and 3))) then
1456 // complete unit production first
1457 else
1458 begin
1459 if ProduceShipPart >= 0 then
1460 begin
1461 if (Built[imGranary] = 0) and (Size < 10) and
1462 City_Improvable(cix, imGranary) then
1463 City_StartImprovement(cix, imGranary)
1464 else if (Built[imAqueduct] = 0) and City_Improvable(cix, imAqueduct) then
1465 City_StartImprovement(cix, imAqueduct)
1466 else if (Built[imAqueduct] > 0) and (Size < 12) and
1467 (AlgaeAvailable or (Project and (cpImp + cpIndex) =
1468 cpImp + imAlgae)) then
1469 City_StartImprovement(cix, imAlgae)
1470 else if (Built[imFactory] = 0) and City_Improvable(cix, imFactory) then
1471 City_StartImprovement(cix, imFactory)
1472 else if (Built[imPower] + Built[imHydro] + Built[imNuclear] = 0) and
1473 (City_Improvable(cix, imPower) or
1474 City_Improvable(cix, imHydro) or City_Improvable(cix, imNuclear)) then
1475 begin
1476 if City_Improvable(cix, imHydro) then
1477 City_StartImprovement(cix, imHydro)
1478 else if City_Improvable(cix, imPower) then
1479 City_StartImprovement(cix, imPower)
1480 else
1481 City_StartImprovement(cix, imNuclear);
1482 end
1483 else if (Built[imMfgPlant] = 0) and City_Improvable(cix, imMfgPlant) then
1484 City_StartImprovement(cix, imMfgPlant)
1485 else if City_Improvable(cix, ProduceShipPart) then
1486 City_StartImprovement(cix, ProduceShipPart)
1487 else
1488 ProduceShipPart := -1;
1489 end;
1490 if ProduceShipPart < 0 then
1491 begin
1492 ProjectComplete :=
1493 not City_HasProject(cix) or (Flags and chProduction <> 0);
1494 HasSettler := False;
1495 for uix := 0 to RO.nUn - 1 do
1496 with MyUnit[uix] do
1497 if (Loc >= 0) and (Home = cix) and
1498 (MyModel[mix].Kind = mkSettler) then
1499 HasSettler := True;
1500 if ((RO.Government <> gDespotism) or (RO.nUn >= RO.nCity * 4)) and
1501 not IsResearched(adMassProduction) and (Built[imPalace] > 0) and
1502 (RO.Wonder[woZeus].CityID = WonderNotBuiltYet) and City_Improvable(cix, woZeus) then
1503 City_StartImprovement(cix, woZeus)
1504 else if (City_CurrentImprovementProject(cix) >= 0) and
1505 (City_CurrentImprovementProject(cix) < 28) then
1506 begin// wonder already built, try to switch to different one
1507 if (WonderAvailable and not WonderInWork > 0) and
1508 (IsCoastal or (WonderAvailable and not WonderInWork and
1509 not CoastalWonder > 0)) then
1510 begin
1511 iix := ChooseWonderToBuild(WonderAvailable and not
1512 WonderInWork, IsCoastal);
1513 City_StartImprovement(cix, iix);
1514 WonderInWork := WonderInWork or (1 shl iix);
1515 end
1516 else
1517 City_StopProduction(cix);
1518 end
1519 else if (Built[imPalace] > 0) and (RO.NatBuilt[imSpacePort] = 0) and
1520 City_Improvable(cix, imSpacePort) then
1521 City_StartImprovement(cix, imSpacePort)
1522 else if Built[imPalace] + Built[imCourt] + Built[imTownHall] = 0 then
1523 begin
1524 if City_Improvable(cix, imCourt) then
1525 City_StartImprovement(cix, imCourt)
1526 else
1527 City_StartImprovement(cix, imTownHall);
1528 end
1529 else if not HasSettler and (RO.nUn >= RO.nCity * 4) then
1530 begin
1531 if ProjectComplete and (City_CurrentUnitProject(cix) <> 0) then
1532 begin
1533 mix := RO.nModel - 1;
1534 while RO.Model[mix].Kind <> mkSettler do
1535 Dec(mix);
1536 City_StartUnitProduction(cix, mix);
1537 end;
1538 end
1539 else if (RO.Government = gDespotism) and (nTownGuard < 2) and
1540 (nTownGuard * 2 + 3 < Size) then
1541 begin
1542 if ProjectComplete then
1543 City_StartUnitProduction(cix, 2);
1544 end
1545 else if (RO.Government = gFundamentalism) and
1546 (Size >= 8) and (Built[imAqueduct] = 0) and
1547 City_Improvable(cix, imAqueduct) and (RO.nUn >= RO.nCity * 4) then
1548 begin
1549 if ProjectComplete then
1550 City_StartImprovement(cix, imAqueduct);
1551 end
1552 else if ProjectComplete then
1553 begin // low prio projects
1554 ImportantCity := WillProduceColonyShip or (Built[imPalace] > 0);
1555 for iix := 0 to 27 do
1556 if Built[iix] > 0 then
1557 ImportantCity := True;
1558 City_GetReportNew(cix, Report);
1559 if (Report.Corruption >= 6) and (RO.nUn >= RO.nCity * 4) and
1560 City_Improvable(cix, imCourt) then
1561 City_StartImprovement(cix, imCourt)
1562 else if (Report.Production >= WonderProductionThreshold) and
1563 (WonderAvailable and not WonderInWork > 0) and
1564 (IsCoastal or (WonderAvailable and not WonderInWork and
1565 not CoastalWonder > 0)) and (Random >=
1566 (1 + WonderInclination) / (RO.nCity + WonderInclination)) then
1567 begin
1568 iix := ChooseWonderToBuild(WonderAvailable and not
1569 WonderInWork, IsCoastal);
1570 City_StartImprovement(cix, iix);
1571 WonderInWork := WonderInWork or (1 shl iix);
1572 end
1573 else if (ImportantCity or (Loc mod 9 = 0)) and
1574 (Built[imWalls] = 0) and City_Improvable(cix, imWalls) then
1575 City_StartImprovement(cix, imWalls)
1576 else if IsPort and (ImportantCity or (Loc mod 7 = 0)) and
1577 (Built[imCoastalFort] = 0) and City_Improvable(cix, imCoastalFort) then
1578 City_StartImprovement(cix, imCoastalFort)
1579 {else if (ImportantCity or (Loc mod 11=0)) and (Built[imMissileBat]=0)
1580 and City_Improvable(cix,imMissileBat) then
1581 City_StartImprovement(cix,imMissileBat)}
1582 else if IsPort and (not SpezializeShipProduction or
1583 (f < 0) or (f >= maxCOD) or (ContinentPresence[f] = 1 shl me)) and
1584 (Built[imDockyard] = 0) and City_Improvable(cix, imDockyard) then
1585 City_StartImprovement(cix, imDockyard)
1586 else if IsPort and (mixShip >= 0) and
1587 (not SpezializeShipProduction or (f < 0) or
1588 (f >= maxCOD) or (ContinentPresence[f] = 1 shl me)) then
1589 City_StartUnitProduction(cix, mixShip)
1590 else if (Built[imBarracks] + Built[imMilAcademy] = 0) and
1591 City_Improvable(cix, imBarracks) then
1592 City_StartImprovement(cix, imBarracks)
1593 else if mixProduce >= 0 then
1594 City_StartUnitProduction(cix, mixProduce)
1595 else if City_HasProject(cix) then
1596 City_StopProduction(cix);
1597 end;
1598 end;
1599 end;
1600 if (City_CurrentImprovementProject(cix) = imCourt) and
1601 (Built[imTownHall] > 0) and (prod >= imp[imCourt].cost *
1602 BuildCostMod[G.Difficulty[me]] div 12 -
1603 (imp[imTownHall].cost * BuildCostMod[G.Difficulty[me]] div 12) *
1604 2 div 3) then
1605 City_RebuildImprovement(cix, imTownHall)
1606 else if (RO.Government = gFundamentalism) and not WillProduceColonyShip then
1607 for iix := 28 to nImp - 1 do
1608 if (Built[iix] > 0) and
1609 ((iix in [imTemple, imTheater, imCathedral, imColosseum,
1610 imLibrary, imUniversity, imResLab, imHarbor, imSuperMarket]) or
1611 (iix in [imFactory, imMfgPlant, imPower, imHydro, imNuclear]) and
1612 (Built[imRecycling] = 0)) then
1613 begin
1614 if City_RebuildImprovement(cix, iix) < rExecuted then
1615 City_SellImprovement(cix, iix);
1616 break;
1617 end;
1618 end;
1619end;
1620
1621function TBarbarina.Barbarina_ChooseResearchAdvance: integer;
1622var
1623 nPreq, rmix, rmixChosen, i, MaxWeight, MaxDefense, ChosenPreq: integer;
1624 NeedSeaUnits, ready: boolean;
1625 ModelExists: set of 0..nModelCategory - 1;
1626 known: array[0..nAdv - 1] of integer;
1627
1628 procedure ChoosePreq(ad: integer);
1629 var
1630 i: integer;
1631 PreqOk: boolean;
1632 begin
1633 assert(RO.Tech[ad] < tsApplicable);
1634 if known[ad] = 0 then
1635 begin
1636 known[ad] := 1;
1637 PreqOk := True;
1638 if not (ad in [adScience, adMassProduction]) and (RO.Tech[ad] < tsSeen) then
1639 for i := 0 to 1 do
1640 if (AdvPreq[ad, i] >= 0) and (RO.Tech[AdvPreq[ad, i]] < tsApplicable) then
1641 begin
1642 PreqOk := False;
1643 ChoosePreq(AdvPreq[ad, i]);
1644 end;
1645 if PreqOk then
1646 begin
1647 Inc(nPreq);
1648 if random(nPreq) = 0 then
1649 ChosenPreq := ad;
1650 end;
1651 end;
1652 end;
1653
1654begin
1655 // check military research
1656 rmixChosen := -1;
1657 ModelExists := [];
1658 for rmix := nResearchModel - 1 downto 0 do
1659 with ResearchModel[rmix] do
1660 if not (Category in ModelExists) and ((adStop < 0) or not
1661 IsResearched(adStop)) then
1662 begin
1663 MaxWeight := 0;
1664 case Domain of
1665 dGround:
1666 begin
1667 if IsResearched(adWarriorCode) then
1668 MaxWeight := 5;
1669 if IsResearched(adHorsebackRiding) then
1670 MaxWeight := 7;
1671 if IsResearched(adAutomobile) then
1672 MaxWeight := 10;
1673 end;
1674 dSea:
1675 begin
1676 if IsResearched(adMapMaking) then
1677 MaxWeight := 5;
1678 if IsResearched(adSeaFaring) then
1679 MaxWeight := 7;
1680 if IsResearched(adSteel) then
1681 MaxWeight := 9;
1682 end;
1683 dAir:
1684 begin
1685 if IsResearched(adFlight) then
1686 MaxWeight := 5;
1687 if IsResearched(adAdvancedFlight) then
1688 MaxWeight := 7;
1689 end;
1690 end;
1691 if Domain = dGround then
1692 MaxDefense := 2
1693 else
1694 MaxDefense := 3;
1695 if IsResearched(adSteel) then
1696 Inc(MaxDefense);
1697 ready := (MaxWeight >= Weight) and (MaxDefense >= Cap[mcDefense]);
1698 if ready then
1699 for i := 0 to nFeature - 1 do
1700 if (Cap[i] > 0) and (Feature[i].Preq <> preNone) and
1701 ((Feature[i].Preq < 0) or not IsResearched(Feature[i].Preq)) then
1702 ready := False;
1703 if ready then
1704 begin
1705 for i := 0 to nUpgrade - 1 do
1706 if (Upgrades and (1 shl i) <> 0) and not
1707 IsResearched(Upgrade[Domain, i].Preq) then
1708 ready := False;
1709 end;
1710 if ready then
1711 begin
1712 include(ModelExists, Category);
1713 if not IsModelAvailable(rmix) then
1714 rmixChosen := rmix;
1715 end;
1716 end;
1717 if rmixChosen >= 0 then
1718 with ResearchModel[rmixChosen] do
1719 begin
1720 PrepareNewModel(Domain);
1721 for i := 0 to nFeature - 1 do
1722 if (i < 2) or (Cap[i] > 0) then
1723 SetNewModelFeature(i, Cap[i]);
1724 if RO.Wonder[woSun].EffectiveOwner = me then
1725 begin
1726 //if Cap[mcWeapons]>=2*Cap[mcArmor] then
1727 // SetNewModelFeature(mcFirst,1);
1728 if Cap[mcWeapons] >= Cap[mcArmor] then
1729 SetNewModelFeature(mcWill, 1);
1730 end;
1731 Result := adMilitary;
1732 exit;
1733 end;
1734
1735 NeedSeaUnits := True;
1736 i := 0;
1737 while (i < nResearchOrder) and (not NeedSeaUnits and (ResearchOrder[i] < 0) or
1738 IsResearched(abs(ResearchOrder[i]))) do
1739 Inc(i);
1740 if i >= nResearchOrder then // list done, continue with future tech
1741 begin
1742 if random(2) = 1 then
1743 Result := futArtificialIntelligence
1744 else
1745 Result := futMaterialTechnology;
1746 end
1747 else
1748 begin
1749 FillChar(known, SizeOf(known), 0);
1750 nPreq := 0;
1751 ChosenPreq := -1;
1752 ChoosePreq(abs(ResearchOrder[i]));
1753 assert(nPreq > 0);
1754 Result := ChosenPreq;
1755 end;
1756end;
1757
1758function TBarbarina.Barbarina_WantCheckNegotiation(Nation: integer): boolean;
1759begin
1760 if (RO.Tech[adTheRepublic] < tsSeen) and (RO.Tech[adTheology] >= tsApplicable) and
1761 (RO.Tech[adGunPowder] >= tsApplicable) and
1762 (RO.EnemyReport[Nation].Tech[adTheRepublic] >= tsApplicable) then
1763 Result := True
1764 else
1765 Result := False;
1766end;
1767
1768procedure TBarbarina.Barbarina_DoCheckNegotiation;
1769begin
1770 if RO.Tech[adTheRepublic] >= tsSeen then
1771 exit; // default reaction
1772 if MyLastAction = scContact then
1773 begin
1774 MyAction := scDipOffer;
1775 MyOffer.nDeliver := 1;
1776 MyOffer.nCost := 1;
1777 if (RO.Tech[adTheology] >= tsApplicable) and
1778 (RO.EnemyReport[Opponent].Tech[adTheology] < tsSeen) then
1779 MyOffer.Price[0] := opTech + adTheology
1780 else
1781 MyOffer.Price[0] := opChoose;
1782 MyOffer.Price[1] := opTech + adTheRepublic;
1783 end
1784 else if OppoAction = scDipAccept then
1785 else if OppoAction = scDipOffer then
1786 begin
1787 if (OppoOffer.nDeliver = 1) and (OppoOffer.Price[0] = opTech + adTheRepublic) and
1788 ((OppoOffer.nCost = 0) or (OppoOffer.nCost = 1) and
1789 (OppoOffer.Price[1] and opMask = opTech) and
1790 (RO.Tech[OppoOffer.Price[1] - opTech] >= tsApplicable)) then
1791 MyAction := scDipAccept
1792 else
1793 MyAction := scDipBreak;
1794 end
1795 else if OppoAction <> scDipBreak then
1796 MyAction := scDipBreak;
1797end;
1798
1799function TBarbarina.Barbarina_WantNegotiation(Nation: integer;
1800 NegoTime: TNegoTime): boolean;
1801var
1802 uix, TestLoc, V8: integer;
1803 Adjacent: TVicinity8Loc;
1804begin
1805 Result := False;
1806 case NegoTime of
1807 EnemyCalled:
1808 Result := False;
1809 EndOfTurn:
1810 Result := False;
1811 BeginOfTurn:
1812 if RO.Turn >= RO.LastCancelTreaty[Nation] + CancelTreatyTurns then
1813 begin
1814 if (RO.Turn and 3 = (Nation + $F - me) and 3) and
1815 (RO.Treaty[Nation] > trPeace) then
1816 begin
1817 DebugMessage(1, 'End alliance/friendly contact with P' + char(48 + Nation));
1818 NegoCause := CancelTreaty;
1819 Result := True;
1820 end
1821 else if RO.Treaty[Nation] = trPeace then
1822 begin // declare war now?
1823 for uix := 0 to RO.nUn - 1 do
1824 with MyUnit[uix] do
1825 if (Loc >= 0) and (MyModel[mix].Attack > 0) then
1826 begin
1827 V8_to_Loc(Loc, Adjacent);
1828 for V8 := 0 to 7 do
1829 begin
1830 TestLoc := Adjacent[V8];
1831 if (TestLoc >= 0) and (RO.Territory[TestLoc] = Nation) and
1832 ((Map[TestLoc] and fTerrain >= fGrass) or
1833 (Master >= 0) or (MyModel[mix].Domain <> dGround)) and
1834 ((Map[TestLoc] and fTerrain < fGrass) or
1835 (MyModel[mix].Domain <> dSea)) then
1836 begin
1837 DebugMessage(1, 'Declare war on P' + char(48 + Nation));
1838 NegoCause := CancelTreaty;
1839 Result := True;
1840 exit;
1841 end;
1842 end;
1843 end;
1844 end;
1845 end;
1846 end;
1847end;
1848
1849procedure TBarbarina.Barbarina_DoNegotiation;
1850begin
1851 if OppoAction = scDipStart then
1852 begin
1853 if NegoCause = CancelTreaty then
1854 MyAction := scDipCancelTreaty;
1855 end;
1856end;
1857
1858procedure TBarbarina.MakeColonyShipPlan;
1859var
1860 i, V21, V21C, CityLoc, Loc1, part, cix, BestValue, TestValue, FoodCount,
1861 ProdCount, ProdExtra, Score, BestScore: integer;
1862 Tile: cardinal;
1863 ok, check: boolean;
1864 Radius, RadiusC: TVicinity21Loc;
1865begin
1866 for part := 0 to nShipPart - 1 do
1867 begin
1868 ColonyShipPlan[part].cixProducing := -1;
1869 ColonyShipPlan[part].nLocResource := 0;
1870 ColonyShipPlan[part].nLocFoundCity := 0;
1871 end;
1872 if RO.Tech[adMassProduction] >= tsApplicable then // able to recognize ressources yet
1873 begin
1874 // check already existing cities
1875 for cix := 0 to RO.nCity - 1 do
1876 with MyCity[cix] do
1877 if Loc >= 0 then
1878 begin
1879 V21_to_Loc(Loc, Radius);
1880 for V21 := 1 to 26 do
1881 begin
1882 Loc1 := Radius[V21];
1883 if Loc1 >= 0 then
1884 begin
1885 Tile := RO.Map[Loc1];
1886 if Tile and fModern <> 0 then
1887 begin
1888 part := (Tile and fModern) shr 25 - 1;
1889 if RO.Ship[me].Parts[part] < ShipNeed[part] then
1890 // not enough of this kind already
1891 begin
1892 ok := True;
1893 if ColonyShipPlan[part].cixProducing >= 0 then
1894 begin // another city is already assigned to this ship part, choose one of the two
1895 TestValue := (ID and $FFF) shl 4 + ((ID shr 12) + 15 - me) and $F;
1896 BestValue :=
1897 (MyCity[ColonyShipPlan[part].cixProducing].ID and $FFF) shl
1898 4 + ((MyCity[ColonyShipPlan[part].cixProducing].ID shr 12) +
1899 15 - me) and $F;
1900 if TestValue <= BestValue then
1901 ok := False;
1902 end;
1903 if ok then
1904 ColonyShipPlan[part].cixProducing := cix;
1905 end;
1906 end;
1907 end;
1908 end;
1909 end;
1910
1911 // for parts without existing city, look for location of city to found
1912 check := False;
1913 for part := 0 to nShipPart - 1 do
1914 if (RO.Ship[me].Parts[part] < ShipNeed[part]) // not enough of this kind already
1915 and (ColonyShipPlan[part].cixProducing < 0) then // no city to produce
1916 check := True;
1917 if check then
1918 begin
1919 for Loc1 := 0 to MapSize - 1 do
1920 begin
1921 Tile := RO.Map[Loc1];
1922 if Tile and fModern <> 0 then
1923 begin
1924 part := (Tile and fModern) shr 25 - 1;
1925 if ColonyShipPlan[part].nLocResource < maxModern then
1926 begin
1927 ColonyShipPlan[part].LocResource[ColonyShipPlan[part].nLocResource] := Loc1;
1928 Inc(ColonyShipPlan[part].nLocResource);
1929 end;
1930 end;
1931 end;
1932 for part := 0 to nShipPart - 1 do
1933 if (RO.Ship[me].Parts[part] < ShipNeed[part]) // not enough of this kind already
1934 and (ColonyShipPlan[part].cixProducing < 0) // no city to produce
1935 and (ColonyShipPlan[part].nLocResource > 0) then // resource is known
1936 begin
1937 for i := 0 to ColonyShipPlan[part].nLocResource - 1 do
1938 begin
1939 BestScore := 0;
1940 V21_to_Loc(ColonyShipPlan[part].LocResource[i], Radius);
1941 for V21 := 1 to 26 do
1942 begin // check all potential cities in range
1943 CityLoc := Radius[V21];
1944 if CityLoc >= 0 then
1945 begin
1946 Tile := RO.Map[CityLoc];
1947 if (Tile and fTerrain <> fUNKNOWN) and
1948 ((Tile and fTerrain = fForest) or
1949 (Tile and fTerrain = fSwamp) or
1950 (Terrain[Tile and fTerrain].IrrEff > 0)) then
1951 begin
1952 FoodCount := 0;
1953 ProdCount := 0;
1954 ProdExtra := 0;
1955 V21_to_Loc(CityLoc, RadiusC);
1956 for V21C := 1 to 26 do
1957 begin
1958 Loc1 := RadiusC[V21C];
1959 if Loc1 >= 0 then
1960 begin
1961 case RO.Map[Loc1] and (fTerrain or fSpecial) of
1962 fGrass, fGrass + fSpecial1, fSwamp: Inc(FoodCount);
1963 fHills, fHills + fSpecial1: Inc(ProdCount);
1964 fShore + fSpecial1, fDesert + fSpecial1, fPrairie + fSpecial1,
1965 fForest + fSpecial1:
1966 Inc(FoodCount, 2);
1967 fSwamp + fSpecial1, fShore + fSpecial2, fDesert + fSpecial2,
1968 fPrairie + fSpecial2, fTundra + fSpecial2, fArctic + fSpecial1,
1969 fHills + fSpecial2, fMountains + fSpecial1:
1970 begin
1971 Inc(ProdCount);
1972 Inc(ProdExtra);
1973 end;
1974 end;
1975 end;
1976 end;
1977 if FoodCount = 0 then
1978 Score := 0
1979 else
1980 begin
1981 if ProdCount > 7 then
1982 ProdCount := 7;
1983 if FoodCount < 5 then
1984 Dec(ProdCount, 5 - FoodCount);
1985 Score := ProdCount * 4 + ProdExtra * 8 + FoodCount;
1986 Score := Score shl 8 + ((CityLoc xor me) * 4567) mod 251;
1987 // some unexactness, random but always the same for this tile
1988 end;
1989 if Score > BestScore then
1990 begin
1991 BestScore := Score;
1992 ColonyShipPlan[part].LocFoundCity[
1993 ColonyShipPlan[part].nLocFoundCity] :=
1994 CityLoc;
1995 end;
1996 end;
1997 end;
1998 end;
1999 if BestScore > 0 then
2000 Inc(ColonyShipPlan[part].nLocFoundCity);
2001 end;
2002 end;
2003 end;
2004 end;
2005end;
2006
2007end.
Note: See TracBrowser for help on using the repository browser.