source: trunk/AI/StdAI/Barbarina.pas

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