source: trunk/AI/StdAI/Barbarina.pas

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