source: branches/AlphaChannel/AI/StdAI/CustomAI_Reload.pas

Last change on this file was 160, checked in by chronos, 6 years ago
  • Added: StdAI from original game. Previously used only AI dev kit.
File size: 28.1 KB
Line 
1{$INCLUDE switches.pas}
2unit CustomAI;
3
4interface
5
6uses
7{$IFDEF DEBUG}SysUtils,{$ENDIF} // necessary for debug exceptions
8 Protocol;
9
10type
11TNegoTime=(BeginOfTurn, EndOfTurn, EnemyCalled);
12
13TCustomAI=class
14public
15 procedure Process(Command: integer; var Data);
16
17 // overridables
18 constructor Create(Nation: integer); virtual;
19 destructor Destroy; override;
20 procedure SetDataDefaults; virtual;
21 procedure SetDataRandom; virtual;
22 procedure OnBeforeEnemyAttack(UnitInfo: TUnitInfo;
23 ToLoc, EndHealth, EndHealthDef: integer); virtual;
24 procedure OnBeforeEnemyCapture(UnitInfo: TUnitInfo; ToLoc: integer); virtual;
25 procedure OnAfterEnemyAttack; virtual;
26 procedure OnAfterEnemyCapture; virtual;
27
28protected
29 me: integer; // index of the controlled nation
30 RO: ^TPlayerContext;
31 Map: ^TTileList;
32 MyUnit: ^TUnList;
33 MyCity: ^TCityList;
34 MyModel: ^TModelList;
35
36 cixStateImp: array[imPalace..imSpacePort] of integer;
37
38 // negotiation
39 Opponent: integer; // nation i'm in negotiation with, -1 indicates no-negotiation mode
40 MyAction, MyLastAction, OppoAction: integer;
41 MyOffer, MyLastOffer, OppoOffer: TOffer;
42
43 // overridables
44 procedure DoTurn; virtual;
45 procedure DoNegotiation; virtual;
46 function ChooseResearchAdvance: integer; virtual;
47 function ChooseStealAdvance: integer; virtual;
48 function ChooseGovernment: integer; virtual;
49 function WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean; virtual;
50 function OnNegoRejected_CancelTreaty: boolean; virtual;
51
52 // general functions
53 function IsResearched(Advance: integer): boolean;
54 function ResearchCost: integer;
55 function ChangeAttitude(Nation, Attitude: integer): integer;
56 function Revolution: integer;
57 function ChangeRates(Tax,Lux: integer): integer;
58 function PrepareNewModel(Domain: integer): integer;
59 function SetNewModelFeature(F, Count: integer): integer;
60 function AdvanceResearchable(Advance: integer): boolean;
61 function AdvanceStealable(Advance: integer): boolean;
62 function DebugMessage(Level: integer; Text: string): boolean;
63 function SetDebugMap(var DebugMap): boolean;
64
65 // unit functions
66 procedure Unit_FindMyDefender(Loc: integer; var uix: integer);
67 procedure Unit_FindEnemyDefender(Loc: integer; var euix: integer);
68 function Unit_Move(uix,ToLoc: integer): integer;
69 function Unit_Step(uix,ToLoc: integer): integer;
70 function Unit_Attack(uix,ToLoc: integer): integer;
71 function Unit_DoMission(uix,MissionType,ToLoc: integer): integer;
72 function Unit_MoveForecast(uix,ToLoc: integer; var RemainingMovement: integer): boolean;
73 function Unit_AttackForecast(uix,ToLoc,AttackMovement: integer; var RemainingHealth: integer): boolean;
74 function Unit_DefenseForecast(euix,ToLoc: integer; var RemainingHealth: integer): boolean;
75 function Unit_Disband(uix: integer): integer;
76 function Unit_StartJob(uix,NewJob: integer): integer;
77 function Unit_SetHomeHere(uix: integer): integer;
78 function Unit_Load(uix: integer): integer;
79 function Unit_Unload(uix: integer): integer;
80 function Unit_AddToCity(uix: integer): integer;
81
82 // city functions
83 procedure City_FindMyCity(Loc: integer; var cix: integer);
84 procedure City_FindEnemyCity(Loc: integer; var ecix: integer);
85 function City_HasProject(cix: integer): boolean;
86 function City_CurrentImprovementProject(cix: integer): integer;
87 function City_CurrentUnitProject(cix: integer): integer;
88 function City_GetTileInfo(cix,TileLoc: integer; var TileInfo: TTileInfo): integer;
89 function City_GetReport(cix: integer; var Report: TCityReport): integer;
90 function City_GetHypoReport(cix, HypoTiles, HypoTax, HypoLux: integer; var Report: TCityReport): integer;
91 function City_GetAreaInfo(cix: integer; var AreaInfo: TCityAreaInfo): integer;
92 function City_StartUnitProduction(cix,mix: integer): integer;
93 function City_StartEmigration(cix,mix: integer; AllowDisbandCity, AsConscripts: boolean): integer;
94 function City_StartImprovement(cix,iix: integer): integer;
95 function City_Improvable(cix,iix: integer): boolean;
96 function City_StopProduction(cix: integer): integer;
97 function City_BuyProject(cix: integer): integer;
98 function City_SellImprovement(cix,iix: integer): integer;
99 function City_RebuildImprovement(cix,iix: integer): integer;
100 function City_SetTiles(cix,NewTiles: integer): integer;
101
102 // negotiation
103 function Nego_CheckMyAction: integer;
104
105private
106 HaveTurned: boolean;
107 UnwantedNego: set of 0..nPl-1;
108 Contacted: set of 0..nPl-1;
109 procedure StealAdvance;
110 end;
111
112
113var
114Server: TServerCall;
115G: TNewGameData;
116RWDataSize, MapSize: integer;
117decompose24: cardinal;
118nodata: pointer;
119
120const
121CityOwnTile = 13; // = ab_to_V21(0,0)
122
123// additional return codes
124rLocationReached= $00010000; // Unit_Move: move was not interrupted, location reached
125rMoreTurns= $00020000; // Unit_Move: move was not interrupted, location not reached yet
126
127type
128TVicinity8Loc=array[0..7] of integer;
129TVicinity21Loc=array[0..27] of integer;
130
131
132procedure Init(NewGameData: TNewGameData);
133
134procedure ab_to_Loc(Loc0,a,b: integer; var Loc: integer);
135procedure Loc_to_ab(Loc0,Loc: integer; var a,b: integer);
136procedure ab_to_V8(a,b: integer; var V8: integer);
137procedure V8_to_ab(V8: integer; var a,b: integer);
138procedure ab_to_V21(a,b: integer; var V21: integer);
139procedure V21_to_ab(V21: integer; var a,b: integer);
140procedure V8_to_Loc(Loc0: integer; var VicinityLoc: TVicinity8Loc);
141procedure V21_to_Loc(Loc0: integer; var VicinityLoc: TVicinity21Loc);
142
143
144implementation
145
146const
147ab_v8: array[-4..4] of integer = (5,6,7,4,-1,0,3,2,1);
148v8_a: array[0..7] of integer = (1,1,0,-1,-1,-1,0,1);
149v8_b: array[0..7] of integer = (0,1,1,1,0,-1,-1,-1);
150
151
152procedure ab_to_Loc(Loc0,a,b: integer; var Loc: integer);
153{relative location from Loc0}
154var
155y0: integer;
156begin
157assert((Loc0>=0) and (Loc0<MapSize) and (a-b+G.lx>=0));
158y0:=cardinal(Loc0)*decompose24 shr 24;
159Loc:=(Loc0+(a-b+y0 and 1+G.lx+G.lx) shr 1) mod G.lx +G.lx*(y0+a+b);
160if Loc>=MapSize then Loc:=-$1000
161end;
162
163procedure Loc_to_ab(Loc0,Loc: integer; var a,b: integer);
164{$IFDEF FPC} // freepascal
165var
166dx,dy: integer;
167begin
168dx:=((Loc mod G.lx *2 +Loc div G.lx and 1)
169 -(Loc0 mod G.lx *2 +Loc0 div G.lx and 1)+3*G.lx) mod (2*G.lx) -G.lx;
170dy:=Loc div G.lx-Loc0 div G.lx;
171a:=(dx+dy) div 2;
172b:=(dy-dx) div 2;
173end;
174{$ELSE} // delphi
175register;
176asm
177push ebx
178
179// calculate
180push ecx
181div byte ptr [G]
182xor ebx,ebx
183mov bl,ah // ebx:=Loc0 mod G.lx
184mov ecx,eax
185and ecx,$000000FF // ecx:=Loc0 div G.lx
186mov eax,edx
187div byte ptr [G]
188xor edx,edx
189mov dl,ah // edx:=Loc mod G.lx
190and eax,$000000FF // eax:=Loc div G.lx
191sub edx,ebx // edx:=Loc mod G.lx-Loc0 mod G.lx
192mov ebx,eax
193sub ebx,ecx // ebx:=dy
194and eax,1
195and ecx,1
196add edx,edx
197add eax,edx
198sub eax,ecx // eax:=dx, not normalized
199pop ecx
200
201// normalize
202mov edx,dword ptr [G]
203cmp eax,edx
204jl @a
205 sub eax,edx
206 sub eax,edx
207 jmp @ok
208@a:
209neg edx
210cmp eax,edx
211jnl @ok
212 sub eax,edx
213 sub eax,edx
214
215// return results
216@ok:
217mov edx,ebx
218sub edx,eax
219add eax,ebx
220sar edx,1 // edx:=b
221mov ebx,[b]
222mov [ebx],edx
223sar eax,1 // eax:=a
224mov [a],eax
225
226pop ebx
227end;
228{$ENDIF}
229
230procedure ab_to_V8(a,b: integer; var V8: integer);
231begin
232assert((abs(a)<=1) and (abs(b)<=1) and ((a<>0) or (b<>0)));
233V8:=ab_v8[2*b+b+a];
234end;
235
236procedure V8_to_ab(V8: integer; var a,b: integer);
237begin
238a:=v8_a[V8]; b:=V8_b[V8];
239end;
240
241procedure ab_to_V21(a,b: integer; var V21: integer);
242begin
243V21:=(a+b+3) shl 2+(a-b+3) shr 1;
244end;
245
246procedure V21_to_ab(V21: integer; var a,b: integer);
247var
248dx,dy: integer;
249begin
250dy:=V21 shr 2-3;
251dx:=V21 and 3 shl 1 -3 + (dy+3) and 1;
252a:=(dx+dy) div 2;
253b:=(dy-dx) div 2;
254end;
255
256procedure V8_to_Loc(Loc0: integer; var VicinityLoc: TVicinity8Loc);
257var
258x0,y0,lx: integer;
259begin
260lx:=G.lx;
261y0:=cardinal(Loc0)*decompose24 shr 24;
262x0:=Loc0-y0*lx; // Loc0 mod lx;
263VicinityLoc[1]:=Loc0+lx*2;
264VicinityLoc[3]:=Loc0-1;
265VicinityLoc[5]:=Loc0-lx*2;
266VicinityLoc[7]:=Loc0+1;
267inc(Loc0,y0 and 1);
268VicinityLoc[0]:=Loc0+lx;
269VicinityLoc[2]:=Loc0+lx-1;
270VicinityLoc[4]:=Loc0-lx-1;
271VicinityLoc[6]:=Loc0-lx;
272
273// world is round!
274if x0<lx-1 then
275 begin
276 if x0=0 then
277 begin
278 inc(VicinityLoc[3],lx);
279 if y0 and 1=0 then
280 begin
281 inc(VicinityLoc[2],lx);
282 inc(VicinityLoc[4],lx);
283 end
284 end
285 end
286else
287 begin
288 dec(VicinityLoc[7],lx);
289 if y0 and 1=1 then
290 begin
291 dec(VicinityLoc[0],lx);
292 dec(VicinityLoc[6],lx);
293 end
294 end;
295
296// check south pole
297case G.ly-y0 of
298 1:
299 begin
300 VicinityLoc[0]:=-$1000;
301 VicinityLoc[1]:=-$1000;
302 VicinityLoc[2]:=-$1000;
303 end;
304 2: VicinityLoc[1]:=-$1000;
305 end
306end;
307
308procedure V21_to_Loc(Loc0: integer; var VicinityLoc: TVicinity21Loc);
309var
310dx,dy,bit,y0,xComp,yComp,xComp0,xCompSwitch: integer;
311dst: ^integer;
312begin
313y0:=cardinal(Loc0)*decompose24 shr 24;
314xComp0:=Loc0-y0*G.lx-1; // Loc0 mod G.lx -1
315xCompSwitch:=xComp0-1+y0 and 1;
316if xComp0<0 then inc(xComp0,G.lx);
317if xCompSwitch<0 then inc(xCompSwitch,G.lx);
318xCompSwitch:=xCompSwitch xor xComp0;
319yComp:=G.lx*(y0-3);
320dst:=@VicinityLoc;
321bit:=1;
322for dy:=0 to 6 do
323 if yComp<MapSize then
324 begin
325 xComp0:=xComp0 xor xCompSwitch;
326 xComp:=xComp0;
327 for dx:=0 to 3 do
328 begin
329 if bit and $67F7F76<>0 then dst^:=xComp+yComp
330 else dst^:=-1;
331 inc(xComp);
332 if xComp>=G.lx then dec(xComp, G.lx);
333 inc(dst);
334 bit:=bit shl 1;
335 end;
336 inc(yComp,G.lx);
337 end
338 else
339 begin
340 for dx:=0 to 3 do
341 begin dst^:=-$1000; inc(dst); end;
342 end
343end;
344
345
346procedure Init(NewGameData: TNewGameData);
347{$IFDEF DEBUG}var Loc: integer;{$ENDIF}
348begin
349G:=NewGameData;
350MapSize:=G.lx*G.ly;
351decompose24:=(1 shl 24-1) div G.lx +1;
352{$IFDEF DEBUG}for Loc:=0 to MapSize-1 do assert(cardinal(Loc)*decompose24 shr 24=cardinal(Loc div G.lx));{$ENDIF}
353end;
354
355
356constructor TCustomAI.Create(Nation: integer);
357begin
358inherited Create;
359me:=Nation;
360RO:=pointer(G.RO[Nation]);
361Map:=pointer(RO.Map);
362MyUnit:=pointer(RO.Un);
363MyCity:=pointer(RO.City);
364MyModel:=pointer(RO.Model);
365Opponent:=-1;
366end;
367
368destructor TCustomAI.Destroy;
369begin
370Server(sSetDebugMap,me,0,nodata^);
371end;
372
373
374procedure TCustomAI.Process(Command: integer; var Data);
375var
376Nation,NewResearch,NewGov,count,ad,cix,iix: integer;
377NegoTime: TNegoTime;
378begin
379case Command of
380 cTurn, cContinue:
381 begin
382 if RO.Alive and (1 shl me)=0 then
383 begin // I'm dead, huhu
384 Server(sTurn,me,0,nodata^);
385 exit
386 end;
387 if Command=cTurn then
388 begin
389 fillchar(cixStateImp, sizeof(cixStateImp), $FF);
390 for cix:=0 to RO.nCity-1 do if MyCity[cix].Loc>=0 then
391 for iix:=imPalace to imSpacePort do
392 if MyCity[cix].Built[iix]>0 then
393 cixStateImp[iix]:=cix;
394 if RO.Happened and phChangeGov<>0 then
395 begin
396 NewGov:=ChooseGovernment;
397 if NewGov>gAnarchy then
398 Server(sSetGovernment,me,NewGov,nodata^);
399 end;
400 HaveTurned:=false;
401 Contacted:=[];
402 end;
403 if (Command=cContinue) and (MyAction=scContact) then
404 begin
405 if OnNegoRejected_CancelTreaty then
406 if RO.Treaty[Opponent]>=trPeace then
407 if Server(sCancelTreaty,me,0,nodata^)<rExecuted then
408 assert(false)
409 end
410 else UnwantedNego:=[];
411 Opponent:=-1;
412 repeat
413 if HaveTurned then NegoTime:=EndOfTurn
414 else NegoTime:=BeginOfTurn;
415 if RO.Government<>gAnarchy then
416 for Nation:=0 to nPl-1 do
417 if (Nation<>me) and (1 shl Nation and RO.Alive<>0)
418 and (RO.Treaty[Nation]>=trNone)
419 and not (Nation in Contacted) and not (Nation in UnwantedNego)
420 and (Server(scContact-sExecute + Nation shl 4, me, 0, nodata^)>=rExecuted) then
421 if WantNegotiation(Nation, NegoTime) then
422 begin
423 if Server(scContact + Nation shl 4, me, 0, nodata^)>=rExecuted then
424 begin
425 include(Contacted, Nation);
426 Opponent:=Nation;
427 MyAction:=scContact;
428 exit;
429 end;
430 end
431 else include(UnwantedNego,Nation);
432 if NegoTime=BeginOfTurn then
433 begin
434 DoTurn;
435 HaveTurned:=true;
436 Contacted:=[];
437 UnwantedNego:=[];
438 end
439 else break;
440 until false;
441 if RO.Happened and phTech<>0 then
442 begin
443 NewResearch:=ChooseResearchAdvance;
444 if NewResearch<0 then
445 begin // choose random research
446 count:=0;
447 for ad:=0 to nAdv-1 do if AdvanceResearchable(ad) then
448 begin inc(count); if random(count)=0 then NewResearch:=ad end
449 end;
450 Server(sSetResearch,me,NewResearch,nodata^)
451 end;
452 if (me=1) and (RO.Turn=800) then
453 begin
454 count:=0;
455 Server(sReload,me,0,count)
456 end
457 else if (RO.Turn>10) and (random(1000)=0) then
458 begin
459 count:=RO.Turn-10;
460 Server(sReload,me,0,count)
461 end
462 else if Server(sTurn,me,0,nodata^)<rExecuted then
463 assert(false);
464 end;
465 scContact:
466 if WantNegotiation(integer(Data), EnemyCalled) then
467 begin
468 if Server(scDipStart, me, 0, nodata^)<rExecuted then
469 assert(false);
470 Opponent:=integer(Data);
471 MyAction:=scDipStart;
472 end
473 else
474 begin
475 if Server(scReject, me, 0, nodata^)<rExecuted then
476 assert(false);
477 end;
478 scDipStart, scDipNotice, scDipAccept, scDipCancelTreaty, scDipOffer, scDipBreak:
479 begin
480 OppoAction:=Command;
481 if Command=scDipOffer then OppoOffer:=TOffer(Data);
482 MyLastAction:=MyAction;
483 MyLastOffer:=MyOffer;
484 if (OppoAction=scDipCancelTreaty) or (OppoAction=scDipBreak) then
485 MyAction:=scDipNotice
486 else begin MyAction:=scDipOffer; MyOffer.nDeliver:=0; MyOffer.nCost:=0; end;
487 DoNegotiation;
488 assert((MyAction=scDipNotice) or (MyAction=scDipAccept)
489 or (MyAction=scDipCancelTreaty) or (MyAction=scDipOffer)
490 or (MyAction=scDipBreak));
491 if MyAction=scDipOffer then Server(MyAction, me, 0, MyOffer)
492 else Server(MyAction, me, 0, nodata^);
493 end;
494 cShowEndContact:
495 Opponent:=-1;
496 end;
497end;
498
499{$HINTS OFF}
500procedure TCustomAI.SetDataDefaults;
501begin
502end;
503
504procedure TCustomAI.SetDataRandom;
505begin
506end;
507
508procedure TCustomAI.DoTurn;
509begin
510end;
511
512procedure TCustomAI.DoNegotiation;
513begin
514end;
515
516procedure TCustomAI.OnBeforeEnemyAttack(UnitInfo: TUnitInfo; ToLoc, EndHealth,
517 EndHealthDef: integer);
518begin
519end;
520
521procedure TCustomAI.OnBeforeEnemyCapture(UnitInfo: TUnitInfo; ToLoc: integer);
522begin
523end;
524
525procedure TCustomAI.OnAfterEnemyAttack;
526begin
527end;
528
529procedure TCustomAI.OnAfterEnemyCapture;
530begin
531end;
532
533function TCustomAI.ChooseResearchAdvance: integer;
534begin
535result:=-1
536end;
537
538function TCustomAI.ChooseStealAdvance: integer;
539begin
540result:=-1
541end;
542
543function TCustomAI.ChooseGovernment: integer;
544begin
545result:=gDespotism
546end;
547
548function TCustomAI.WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean;
549begin
550result:=false;
551end;
552
553function TCustomAI.OnNegoRejected_CancelTreaty: boolean;
554begin
555result:=false;
556end;
557{$HINTS ON}
558
559procedure TCustomAI.StealAdvance;
560var
561Steal, ad, count: integer;
562begin
563Steal:=ChooseStealAdvance;
564if Steal<0 then
565 begin // choose random advance
566 count:=0;
567 for ad:=0 to nAdv-1 do if AdvanceStealable(ad) then
568 begin inc(count); if random(count)=0 then Steal:=ad end
569 end;
570if Steal>=0 then Server(sStealTech,me,Steal,nodata^);
571RO.Happened:=RO.Happened and not phStealTech
572end;
573
574function TCustomAI.IsResearched(Advance: integer): boolean;
575begin
576result:= RO.Tech[Advance]>=tsApplicable
577end;
578
579function TCustomAI.ResearchCost: integer;
580begin
581Server(sGetTechCost,me,0,result)
582end;
583
584function TCustomAI.ChangeAttitude(Nation, Attitude: integer): integer;
585begin
586result:=Server(sSetAttitude+Nation shl 4,me,Attitude,nodata^)
587end;
588
589function TCustomAI.Revolution: integer;
590begin
591result:=Server(sRevolution,me,0,nodata^);
592end;
593
594function TCustomAI.ChangeRates(Tax,Lux: integer): integer;
595begin
596result:=Server(sSetRates,me,Tax div 10 and $f+Lux div 10 and $f shl 4,nodata^)
597end;
598
599function TCustomAI.PrepareNewModel(Domain: integer): integer;
600begin
601result:=Server(sCreateDevModel,me,Domain,nodata^);
602end;
603
604function TCustomAI.SetNewModelFeature(F, Count: integer): integer;
605begin
606result:=Server(sSetDevModelCap+Count shl 4,me,F,nodata^)
607end;
608
609function TCustomAI.AdvanceResearchable(Advance: integer): boolean;
610begin
611result:= Server(sSetResearch-sExecute,me,Advance,nodata^)>=rExecuted;
612end;
613
614function TCustomAI.AdvanceStealable(Advance: integer): boolean;
615begin
616result:= Server(sStealTech-sExecute,me,Advance,nodata^)>=rExecuted;
617end;
618
619function TCustomAI.DebugMessage(Level: integer; Text: string): boolean;
620begin
621Text:=copy('P'+char(48+me)+' '+Text,1,254);
622Server(sMessage,me,Level,pchar(Text)^);
623
624result:=true;
625 // always returns true so that it can be used like
626 // "assert(DebugMessage(...));" -> not compiled in release build
627end;
628
629function TCustomAI.SetDebugMap(var DebugMap): boolean;
630begin
631Server(sSetDebugMap, me, 0, DebugMap);
632
633result:=true;
634 // always returns true so that it can be used like
635 // "assert(SetDebugMap(...));" -> not compiled in release build
636end;
637
638procedure TCustomAI.Unit_FindMyDefender(Loc: integer; var uix: integer);
639begin
640if Server(sGetDefender,me,Loc,uix)<rExecuted then uix:=-1
641end;
642
643procedure TCustomAI.Unit_FindEnemyDefender(Loc: integer; var euix: integer);
644begin
645euix:=RO.nEnemyUn-1;
646while (euix>=0) and (RO.EnemyUn[euix].Loc<>Loc) do
647 dec(euix);
648end;
649
650function TCustomAI.Unit_Move(uix,ToLoc: integer): integer;
651var
652Step: integer;
653DestinationReached: boolean;
654Advice: TMoveAdviceData;
655begin
656assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0)); // is a unit
657{Loc_to_ab(MyUnit[uix].Loc,ToLoc,a,b);
658assert((a<>0) or (b<>0));
659if (a>=-1) and (a<=1) and (b>=-1) and (b<=1) then
660 begin // move to adjacent tile
661 !!!problem: if move is invalid, return codes are not consistent with other branch (eNoWay)
662 Advice.nStep:=1;
663 Advice.dx[0]:=a-b;
664 Advice.dy[0]:=a+b;
665 Advice.MoreTurns:=0;
666 Advice.MaxHostile_MovementLeft:=MyUnit[uix].Movement;
667 result:=eOK;
668 end
669else}
670 begin // move to non-adjacent tile, find shortest path
671 Advice.ToLoc:=ToLoc;
672 Advice.MoreTurns:=9999;
673 Advice.MaxHostile_MovementLeft:=100;
674 result:=Server(sGetMoveAdvice,me,uix,Advice);
675 end;
676if result=eOk then
677 begin
678 DestinationReached:=false;
679 Step:=0;
680 repeat
681 if result and (rExecuted or rUnitRemoved)=rExecuted then // check if destination reached
682 if (ToLoc>=0) and (Advice.MoreTurns=0) and (Step=Advice.nStep-1)
683 and ((Map[ToLoc] and (fUnit or fOwned)=fUnit) // attack
684 or (Map[ToLoc] and (fCity or fOwned)=fCity)
685 and ((MyModel[MyUnit[uix].mix].Domain<>dGround) // bombardment
686 or (MyModel[MyUnit[uix].mix].Flags and mdCivil<>0))) then // can't capture
687 begin DestinationReached:=true; break end // stop next to destination
688 else if Step=Advice.nStep then
689 DestinationReached:=true; // normal move -- stop at destination
690
691 if (Step=Advice.nStep) or (result<>eOK) and (result<>eLoaded) then
692 break;
693
694 result:=Server(sMoveUnit+(Advice.dx[Step] and 7) shl 4 +(Advice.dy[Step] and 7) shl 7,
695 me,uix,nodata^);
696 inc(Step);
697 if RO.Happened and phStealTech<>0 then StealAdvance;
698 until false;
699 if DestinationReached then
700 if Advice.nStep=25 then
701 result:=Unit_Move(uix,ToLoc) // Shinkansen
702 else if Advice.MoreTurns=0 then
703 result:=result or rLocationReached
704 else result:=result or rMoreTurns;
705 end
706end;
707
708function TCustomAI.Unit_Step(uix,ToLoc: integer): integer;
709var
710a,b: integer;
711begin
712Loc_to_ab(MyUnit[uix].Loc, ToLoc, a, b);
713assert(((a<>0) or (b<>0)) and (a>=-1) and (a<=1) and (b>=-1) and (b<=1));
714result:=Server(sMoveUnit+((a-b) and 7) shl 4 +((a+b) and 7) shl 7, me, uix, nodata^);
715if RO.Happened and phStealTech<>0 then StealAdvance;
716end;
717
718function TCustomAI.Unit_Attack(uix,ToLoc: integer): integer;
719var
720a,b: integer;
721begin
722assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0) // is a unit
723 and ((Map[ToLoc] and (fUnit or fOwned)=fUnit) // is an attack
724 or (Map[ToLoc] and (fCity or fOwned)=fCity)
725 and (MyModel[MyUnit[uix].mix].Domain<>dGround))); // is a bombardment
726Loc_to_ab(MyUnit[uix].Loc,ToLoc,a,b);
727assert(((a<>0) or (b<>0)) and (a>=-1) and (a<=1) and (b>=-1) and (b<=1)); // attack to adjacent tile
728result:=Server(sMoveUnit+(a-b) and 7 shl 4 +(a+b) and 7 shl 7,me,uix,nodata^);
729end;
730
731function TCustomAI.Unit_DoMission(uix,MissionType,ToLoc: integer): integer;
732var
733a,b: integer;
734begin
735result:=Server(sSetSpyMission + MissionType shl 4,me,0,nodata^);
736if result>=rExecuted then
737 begin
738 assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0) // is a unit
739 and (MyModel[MyUnit[uix].mix].Kind=mkDiplomat)); // is a commando
740 Loc_to_ab(MyUnit[uix].Loc,ToLoc,a,b);
741 assert(((a<>0) or (b<>0)) and (a>=-1) and (a<=1) and (b>=-1) and (b<=1)); // city must be adjacent
742 result:=Server(sMoveUnit-sExecute+(a-b) and 7 shl 4 +(a+b) and 7 shl 7,me,uix,nodata^);
743 if result=eMissionDone then
744 result:=Server(sMoveUnit+(a-b) and 7 shl 4 +(a+b) and 7 shl 7,me,uix,nodata^)
745 else if (result<>eNoTime_Move) and (result<>eTreaty) and (result<>eNoTurn) then
746 result:=eInvalid // not a special commando mission!
747 end
748end;
749
750function TCustomAI.Unit_MoveForecast(uix,ToLoc: integer;
751 var RemainingMovement: integer): boolean;
752var
753Advice: TMoveAdviceData;
754begin
755assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0)); // is a unit
756Advice.ToLoc:=ToLoc;
757Advice.MoreTurns:=0;
758Advice.MaxHostile_MovementLeft:=100;
759if Server(sGetMoveAdvice,me,uix,Advice)=eOk then
760 begin
761 RemainingMovement:=Advice.MaxHostile_MovementLeft;
762 result:=true
763 end
764else
765 begin
766 RemainingMovement:=-1;
767 result:=false
768 end
769end;
770
771function TCustomAI.Unit_AttackForecast(uix,ToLoc,AttackMovement: integer;
772 var RemainingHealth: integer): boolean;
773var
774BattleForecast: TBattleForecast;
775begin
776assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0) // is a unit
777 and (Map[ToLoc] and (fUnit or fOwned)=fUnit)); // is an attack
778RemainingHealth:=-$100;
779result:=false;
780if AttackMovement>=0 then with MyUnit[uix] do
781 begin
782 BattleForecast.pAtt:=me;
783 BattleForecast.mixAtt:=mix;
784 BattleForecast.HealthAtt:=Health;
785 BattleForecast.ExpAtt:=Exp;
786 BattleForecast.FlagsAtt:=Flags;
787 BattleForecast.Movement:=AttackMovement;
788 if Server(sGetBattleForecast,me,ToLoc,BattleForecast)>=rExecuted then
789 begin
790 if BattleForecast.EndHealthAtt>0 then
791 RemainingHealth:=BattleForecast.EndHealthAtt
792 else RemainingHealth:=-BattleForecast.EndHealthDef;
793 result:=true
794 end
795 end
796end;
797
798function TCustomAI.Unit_DefenseForecast(euix,ToLoc: integer;
799 var RemainingHealth: integer): boolean;
800var
801BattleForecast: TBattleForecast;
802begin
803assert((euix>=0) and (euix<RO.nEnemyUn) and (RO.EnemyUn[euix].Loc>=0) // is an enemy unit
804 and (Map[ToLoc] and (fUnit or fOwned)=(fUnit or fOwned))); // is an attack
805RemainingHealth:=$100;
806result:=false;
807with RO.EnemyUn[euix] do
808 begin
809 BattleForecast.pAtt:=Owner;
810 BattleForecast.mixAtt:=mix;
811 BattleForecast.HealthAtt:=Health;
812 BattleForecast.ExpAtt:=Exp;
813 BattleForecast.FlagsAtt:=Flags;
814 BattleForecast.Movement:=100;
815 if Server(sGetBattleForecast,me,ToLoc,BattleForecast)>=rExecuted then
816 begin
817 if BattleForecast.EndHealthDef>0 then
818 RemainingHealth:=BattleForecast.EndHealthDef
819 else RemainingHealth:=-BattleForecast.EndHealthAtt;
820 result:=true
821 end
822 end
823end;
824
825function TCustomAI.Unit_Disband(uix: integer): integer;
826begin
827result:=Server(sRemoveUnit,me,uix,nodata^)
828end;
829
830function TCustomAI.Unit_StartJob(uix,NewJob: integer): integer;
831begin
832result:=Server(sStartJob+NewJob shl 4,me,uix,nodata^)
833end;
834
835function TCustomAI.Unit_SetHomeHere(uix: integer): integer;
836begin
837result:=Server(sSetUnitHome,me,uix,nodata^)
838end;
839
840function TCustomAI.Unit_Load(uix: integer): integer;
841begin
842result:=Server(sLoadUnit,me,uix,nodata^)
843end;
844
845function TCustomAI.Unit_Unload(uix: integer): integer;
846begin
847result:=Server(sUnloadUnit,me,uix,nodata^)
848end;
849
850function TCustomAI.Unit_AddToCity(uix: integer): integer;
851begin
852result:=Server(sAddToCity,me,uix,nodata^)
853end;
854
855
856procedure TCustomAI.City_FindMyCity(Loc: integer; var cix: integer);
857begin
858if Map[Loc] and (fCity or fOwned)<>fCity or fOwned then
859 cix:=-1
860else
861 begin
862 cix:=RO.nCity-1;
863 while (cix>=0) and (MyCity[cix].Loc<>Loc) do
864 dec(cix);
865 end
866end;
867
868procedure TCustomAI.City_FindEnemyCity(Loc: integer; var ecix: integer);
869begin
870if Map[Loc] and (fCity or fOwned)<>fCity then
871 ecix:=-1
872else
873 begin
874 ecix:=RO.nEnemyCity-1;
875 while (ecix>=0) and (RO.EnemyCity[ecix].Loc<>Loc) do
876 dec(ecix);
877 end
878end;
879
880function TCustomAI.City_HasProject(cix: integer): boolean;
881begin
882result:= MyCity[cix].Project and (cpImp+cpIndex)<>cpImp+imTrGoods
883end;
884
885function TCustomAI.City_CurrentImprovementProject(cix: integer): integer;
886begin
887if MyCity[cix].Project and cpImp=0 then result:=-1
888else
889 begin
890 result:=MyCity[cix].Project and cpIndex;
891 if result=imTrGoods then result:=-1
892 end
893end;
894
895function TCustomAI.City_CurrentUnitProject(cix: integer): integer;
896begin
897if MyCity[cix].Project and cpImp<>0 then result:=-1
898else result:=MyCity[cix].Project and cpIndex;
899end;
900
901function TCustomAI.City_GetTileInfo(cix,TileLoc: integer; var TileInfo: TTileInfo): integer;
902begin
903TileInfo.ExplCity:=cix;
904result:=Server(sGetHypoCityTileInfo,me,TileLoc,TileInfo)
905end;
906
907function TCustomAI.City_GetReport(cix: integer; var Report: TCityReport): integer;
908begin
909Report.HypoTiles:=-1;
910Report.HypoTax:=-1;
911Report.HypoLux:=-1;
912result:=Server(sGetCityReport,me,cix,Report)
913end;
914
915function TCustomAI.City_GetHypoReport(cix, HypoTiles, HypoTax, HypoLux: integer;
916 var Report: TCityReport): integer;
917begin
918Report.HypoTiles:=HypoTiles;
919Report.HypoTax:=HypoTax;
920Report.HypoLux:=HypoLux;
921result:=Server(sGetCityReport,me,cix,Report)
922end;
923
924function TCustomAI.City_GetAreaInfo(cix: integer; var AreaInfo: TCityAreaInfo): integer;
925begin
926result:=Server(sGetCityAreaInfo,me,cix,AreaInfo)
927end;
928
929function TCustomAI.City_StartUnitProduction(cix,mix: integer): integer;
930begin
931result:=Server(sSetCityProject,me,cix,mix)
932end;
933
934function TCustomAI.City_StartEmigration(cix,mix: integer;
935 AllowDisbandCity, AsConscripts: boolean): integer;
936var
937NewProject: integer;
938begin
939NewProject:=mix;
940if AllowDisbandCity then NewProject:=NewProject or cpDisbandCity;
941if AsConscripts then NewProject:=NewProject or cpConscripts;
942result:=Server(sSetCityProject,me,cix,NewProject)
943end;
944
945function TCustomAI.City_StartImprovement(cix,iix: integer): integer;
946var
947NewProject: integer;
948begin
949NewProject:=iix+cpImp;
950result:=Server(sSetCityProject,me,cix,NewProject)
951end;
952
953function TCustomAI.City_Improvable(cix,iix: integer): boolean;
954var
955NewProject: integer;
956begin
957NewProject:=iix+cpImp;
958result:= Server(sSetCityProject-sExecute,me,cix,NewProject)>=rExecuted;
959end;
960
961function TCustomAI.City_StopProduction(cix: integer): integer;
962var
963NewProject: integer;
964begin
965NewProject:=imTrGoods+cpImp;
966result:=Server(sSetCityProject,me,cix,NewProject)
967end;
968
969function TCustomAI.City_BuyProject(cix: integer): integer;
970begin
971result:=Server(sBuyCityProject,me,cix,nodata^)
972end;
973
974function TCustomAI.City_SellImprovement(cix,iix: integer): integer;
975begin
976result:=Server(sSellCityImprovement,me,cix,iix)
977end;
978
979function TCustomAI.City_RebuildImprovement(cix,iix: integer): integer;
980begin
981result:=Server(sRebuildCityImprovement,me,cix,iix)
982end;
983
984function TCustomAI.City_SetTiles(cix,NewTiles: integer): integer;
985begin
986result:=Server(sSetCityTiles,me,cix,NewTiles)
987end;
988
989
990// negotiation
991function TCustomAI.Nego_CheckMyAction: integer;
992begin
993assert(Opponent>=0); // only allowed in negotiation mode
994assert((MyAction=scDipNotice) or (MyAction=scDipAccept)
995 or (MyAction=scDipCancelTreaty) or (MyAction=scDipOffer)
996 or (MyAction=scDipBreak));
997if MyAction=scDipOffer then result:=Server(MyAction-sExecute, me, 0, MyOffer)
998else result:=Server(MyAction-sExecute, me, 0, nodata^);
999end;
1000
1001
1002initialization
1003nodata:=pointer(0);
1004RWDataSize:=0;
1005
1006end.
1007
Note: See TracBrowser for help on using the repository browser.