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

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