📄 outercore.pas
字号:
if AddTiles<>0 then
begin
// check if new tiles possible
GetCityAreaInfo(p, Loc, CityAreaInfo);
for fix:=1 to 26 do if AddTiles and (1 shl fix)<>0 then
if CityAreaInfo.Available[fix]<>faAvailable then
begin result:=eTileNotAvailable; exit end;
// not more tiles than inhabitants
Working:=0;
for fix:=0 to 26 do if NewTiles and (1 shl fix)<>0 then inc(Working);
if Working>Size then
begin result:=eNoWorkerAvailable; exit end;
end;
end;
result:=eOK;
if not TestOnly then
begin
for fix:=1 to 26 do if ChangeTiles and (1 shl fix)<>0 then
begin
dy:=fix shr 2-3; dx:=fix and 3 shl 1 -3 + (dy+3) and 1;
Loc1:=dLoc(Loc,dx,dy);
if NewTiles and (1 shl fix)<>0 then UsedByCity[Loc1]:=Loc // employ tile
else UsedByCity[Loc1]:=-1 // unemploy tile
end;
Tiles:=NewTiles
end
end;
end;
function CityGrowth(p,cix: integer): boolean;
var
fix: integer;
AltCityReport:TCityReport;
begin
with RW[p].City[cix] do
if (Size<MaxCitySize) and ((Size<NeedAqueductSize)
or (Built[imAqueduct]=1) and (Size<NeedSewerSize)
or (Built[imSewer]=1)) then
begin
inc(Size);
fix:=NextBest(p,cix);
if fix>=0 then
begin {test whether exploitation of fix would lead to disorder}
AltCityReport.HypoTiles:=Tiles+1 shl fix;
AltCityReport.HypoTax:=-1;
AltCityReport.HypoLux:=-1;
GetCityReport(p,cix,AltCityReport);
if AltCityReport.Working-AltCityReport.Happy<=Size shr 1 then
AddCityTile(p,cix,fix) {no disorder -- exploit fix}
end;
result:=true
end
else result:=false
end;
procedure CityShrink(p,cix: integer);
var
fix, Working: integer;
AltCityReport:TCityReport;
begin
with RW[p].City[cix] do
begin
Working:=0;
for fix:=1 to 26 do if Tiles and (1 shl fix)<>0 then inc(Working);
dec(Size);
{ if RW[p].Government=gLybertarianism then
if Food>StorageSize[Difficulty[p]]*2 then Food:=StorageSize[Difficulty[p]]*2
else else} if Food>StorageSize[Difficulty[p]] then Food:=StorageSize[Difficulty[p]];
fix:=NextWorst(p,cix);
if Working>Size then RemoveCityTile(p,cix,fix)
{all citizens were working -- worst tile no longer exploited}
else {test whether exploitation of fix would lead to disorder}
begin
AltCityReport.HypoTiles:=-1;
AltCityReport.HypoTax:=-1;
AltCityReport.HypoLux:=-1;
GetCityReport(p,cix,AltCityReport);
if AltCityReport.Working-AltCityReport.Happy>Size shr 1 then
RemoveCityTile(p,cix,fix) {disorder -- don't exploit fix}
end;
end
end;
function Work(p,uix: integer): boolean;
var
uix1,j0,fix: integer;
begin
result:=false;
with RW[p].Un[uix] do if Movement>=100 then
begin
if Job>=jRoad then
if integer(Movement)>=integer(ToWork[Loc,Job]) then {work complete}
begin
result:=true;
if Job<>jIrr then
Health:=Health-Thurst(p,mix,Loc,ToWork[Loc,Job]);
dec(Movement,ToWork[Loc,Job]);
if not (Job in [jCity,jPillage,jPoll]) then
inc(Worked[p],ToWork[Loc,Job]);
if Job=jCity then
begin // found new city
FoundCity(p,Loc);
inc(Founded[p]);
with RW[p].City[RW[p].nCity-1] do
begin
ID:=p shl 12+Founded[p]-1;
Flags:=chFounded;
end;
fix:=NextBest(p,RW[p].nCity-1);
if fix>=0 then AddCityTile(p,RW[p].nCity-1,fix);
if Mode=moPlaying then LogCheckBorders(p,RW[p].nCity-1);
RW[p].Un[uix].Health:=0; // causes unit to be removed later
end
else CompleteJob(p,Loc,Job);
ToWork[Loc,Job]:=0;
j0:=Job;
for uix1:=0 to RW[p].nUn-1 do
if (RW[p].Un[uix1].Loc=Loc) and (RW[p].Un[uix1].Job=j0) then
RW[p].Un[uix1].Job:=jNone
end
else
begin
dec(ToWork[Loc,Job],Movement);
if not (Job in [jCity,jPillage,jPoll]) then
inc(Worked[p],Movement);
Health:=Health-Thurst(p,mix,Loc,Movement);
Movement:=0;
end
end
end; // work
function GetBattleForecast(Loc: integer; var BattleForecast: TBattleForecast;
var Duix,Dcix: integer): integer;
var
Time,Defender,AStr,DStr,ABon,DBon,DCnt,Damage:integer;
PModel,DModel: ^TModel;
begin
with BattleForecast do
begin
Defender:=Occupant[Loc];
if (Defender<0) or (Defender=pAtt) then
begin result:=eOK; exit end; // no attack, simple move
PModel:=@RW[pAtt].Model[mixAtt];
if (PModel.Kind=mkDiplomat) and (RealMap[Loc] and fCity<>0) then
begin result:=eOk; exit end; // spy mission -- return as if move was possible
if Movement=0 then
begin result:=eNoTime_Attack; exit end;
Strongest(Loc,Duix,DStr,DBon,DCnt); {get defense strength and bonus}
DModel:=@RW[Defender].Model[RW[Defender].Un[Duix].mix];
if (PModel.Attack=0)
and not ((PModel.Cap[mcBombs]>0) and (FlagsAtt and unBombsLoaded<>0)
and (DModel.Domain<dAir)) then
begin result:=eInvalid; exit end;
if (RealMap[Loc] and fCity=0) and (RealMap[Loc] and fTerImp<>tiBase) then
begin
if (DModel.Cap[mcSub]>0)
and (RealMap[Loc] and fTerrain<fGrass)
and (ObserveLevel[Loc] shr (2*pAtt) and 3<lObserveAll) then
begin result:=eHiddenUnit; exit; end; //attacking submarine not allowed
if (DModel.Cap[mcStealth]>0)
and (ObserveLevel[Loc] shr (2*pAtt) and 3<>lObserveSuper) then
begin result:=eStealthUnit; exit; end; //attacking stealth aircraft not allowed
if (DModel.Domain=dAir) and (DModel.Kind<>mkSpecial_Glider)
and (PModel.Domain<>dAir) then
begin result:=eDomainMismatch; exit end; //can't attack plane
end;
if (PModel.Cap[mcLongRange]=0)
and ((PModel.Domain<dSea) and (RealMap[Loc] and fTerrain<fGrass)
or (PModel.Domain=dSea) and (RealMap[Loc] and fTerrain>=fGrass)) then
begin result:=eDomainMismatch; exit end;
if RW[pAtt].Treaty[Defender]>=trPeace then
begin
if (DModel.Kind=mkDiplomat) and (PModel.Domain=dGround)
and (PModel.Attack>0) and (integer(RealMap[Loc] shr 27)=pAtt) then
if Movement>=100 then
begin // expel friendly spy
EndHealthDef:=RW[Defender].Un[Duix].Health;
EndHealthAtt:=HealthAtt;
result:=eExpelled
end
else result:=eNoTime_Expel
else result:=eTreaty;
exit;
end;
// calculate defender strength
if RealMap[Loc] and fCity<>0 then
begin // consider city improvements
SearchCity(Loc,Defender,Dcix);
if (PModel.Domain<dSea) and (PModel.Cap[mcLongRange]=0)
and ((RW[Defender].City[Dcix].Built[imWalls]=1)
or (Continent[RW[Defender].City[Dcix].Loc]=GrWallContinent[Defender])) then
inc(DBon,8)
else if (PModel.Domain=dSea)
and (RW[Defender].City[Dcix].Built[imCoastalFort]=1) then
inc(DBon,4)
else if (PModel.Domain=dAir)
and (RW[Defender].City[Dcix].Built[imMissileBat]=1) then
inc(DBon,4);
if RW[Defender].City[Dcix].Built[imBunker]=1 then
inc(DBon,4)
end;
if (PModel.Domain=dAir) and (DModel.Cap[mcAirDef]>0) then
inc(DBon,4);
DStr:=DModel.Defense*DBon*100;
if (DModel.Domain=dAir) and ((RealMap[Loc] and fCity<>0)
or (RealMap[Loc] and fTerImp=tiBase)) then
DStr:=0;
if (DModel.Domain=dSea) and (RealMap[Loc] and fTerrain>=fGrass) then
DStr:=DStr shr 1;
// calculate attacker strength
if PModel.Cap[mcWill]>0 then Time:=100
else begin Time:=Movement; if Time>100 then Time:=100; end;
ABon:=4+ExpAtt div ExpCost;
AStr:=PModel.Attack;
if (FlagsAtt and unBombsLoaded<>0) and (DModel.Domain<dAir) then // use bombs
AStr:=AStr+PModel.Cap[mcBombs]*PModel.MStrength*2;
AStr:=Time*AStr*ABon;
// calculate damage for defender
if DStr=0 then Damage:=100
else
begin
Damage:=HealthAtt*AStr div DStr;
if PModel.Cap[mcFanatic]>0 then Damage:=Damage*2;
if Damage=0 then Damage:=1;
end;
EndHealthDef:=RW[Defender].Un[Duix].Health-Damage;
if EndHealthDef<0 then EndHealthDef:=0;
// calculate damage for attacker
if AStr=0 then Damage:=100
else
begin
Damage:=RW[Defender].Un[Duix].Health*DStr div AStr;
if DModel.Cap[mcFanatic]>0 then Damage:=Damage*2;
if PModel.Cap[mcFirst]>0 then Damage:=Damage shr 1;
if Damage=0 then Damage:=1;
end;
Time:=Movement; if Time>100 then Time:=100;
EndHealthAtt:=HealthAtt-Damage-Thurst(pAtt,mixAtt,Loc,Time);
if EndHealthAtt<0 then EndHealthAtt:=0;
if EndHealthDef>0 then result:=eLost
else if EndHealthAtt>0 then result:=eWon
else result:=eBloody
end
end;
var
MaxTurn,
LoadTurn, {turn where to stop loading}
nLogOpened, {nLog of opened book}
{$IFOPT O-}nHandoverStack,{$ENDIF}
LastEndClientCommand,
pContacted, // player contacted for negotiation
pDipActive, // player who's to speak in a negotiation
pTurn, {player who's turn it is}
GWinner,
GColdWarStart,
GStealFrom,
SpyMission,
ZOCTile,
CCCommand,
CCPlayer: integer;
DebugMap: pointer;
AutoSaveState: TCmdListState;
MapField: ^Cardinal; // predefined map
LastOffer: TOffer;
CCData: array[0..14] of integer;
DevModelTurn, {turn of last call to sResetModel}
bix, {brain index of the players}
OriginalDataVersion: array[0..nPl-1] of integer;
SavedData: array[0..nPl-1] of pointer;
HomeDir,
LogFileName, SavePath, {name of file for saving the current game}
MapFileName, // name of map to use, empty for random
AICredits: string;
Notify: TNotifyFunction;
PerfFreq, LastClientTime: int64;
{$IFOPT O-}HandoverStack: array[0..31] of Cardinal;{$ENDIF}
AutoSaveExists,
LoadOK, WinOnAlone, PreviewElevation: boolean;
const
PreviewRND=41601260; {randseed for preview map}
ContraJobs: array[0..nJob-1] of Set of 0..nJob-1=
([], //jNone
[jCity], //jRoad
[jCity], //jRR
[jCity,jTrans], //jClear
[jCity,jFarm,jAfforest,jMine,jBase,jFort], //jIrr
[jCity,jIrr,jAfforest,jMine,jBase,jFort], //jFarm
[jCity,jIrr,jFarm,jTrans], //jAfforest
[jCity,jTrans,jIrr,jFarm,jBase,jFort], //jMine
[jCity,jTrans], //jCanal
[jCity,jClear,jAfforest,jMine,jCanal], //jTrans
[jCity,jIrr,jFarm,jMine,jBase], //jFort
[jCity], //jPoll
[jCity,jIrr,jFarm,jMine,jFort], //jBase
[jCity], //jPillage
[jRoad..jPillage]); //jCity
function Server(Command,Player,Subject:integer;var Data): integer; stdcall; forward;
procedure Init(NotifyFunction: TNotifyFunction);
var
i,TestVersion: integer;
f: TSearchRec;
T: TextFile;
s: string;
begin
Notify:=NotifyFunction;
PreviewElevation:=false;
{get available brains}
Brain[bixNoTerm].FileName:=':AIT';
Brain[bixNoTerm].Flags:=0;
Brain[bixNoTerm].Client:=nil;
Brain[bixSuper_Virtual].FileName:=':Supervisor';
Brain[bixSuper_Virtual].Flags:=0;
Brain[bixSuper_Virtual].Client:=nil;
Brain[bixTerm].FileName:=':StdIntf';
Brain[bixTerm].Flags:=fMultiple;
Brain[bixTerm].Client:=nil;
nBrain:=3;
if FindFirst(HomeDir+'*.ai.txt',$21,f)=0 then
repeat
with Brain[nBrain] do
begin
FileName:=Copy(f.Name,1,Length(f.Name)-7);
DLLName:=HomeDir+FileName;
Name:=Copy(f.Name,1,Length(f.Name)-7);
Credits:='';
Flags:=0;
Client:=nil;
TestVersion:=0;
AssignFile(T,HomeDir+f.Name);
Reset(T);
while not EOF(T) do
begin
ReadLn(T,s);
if Copy(s,1,5)='#NAME' then Name:=Copy(s,7,255)
else if Copy(s,1,9)='#MULTIPLE' then
Flags:=Flags or fMultiple
else if Copy(s,1,10)='#BROADCAST' then
Flags:=Flags or fBroadcast
else if Copy(s,1,5)='#PATH' then
DLLName:=HomeDir+Copy(s,7,255)
else if Copy(s,1,12)='#GAMEVERSION' then
for i:=13 to Length(s) do
case s[i] of
'0'..'9': TestVersion:=TestVersion and $FFFF00
+TestVersion and $FF *10+ord(s[i])-48;
'.': TestVersion:=TestVersion shl 8;
end
else if Copy(s,1,8)='#CREDITS' then
Credits:=Copy(s,10,255)
end;
CloseFile(T);
end;
if (TestVersion>=FirstAICompatibleVersion) and (TestVersion<=Version) then
inc(nBrain);
until FindNext(f)<>0;
end;
procedure Done;
var
i: integer;
begin
for i:=1 to nBrain-1 do if @Brain[i].Client<>nil then
begin
Brain[i].Client(cReleaseModule,-1,nil^);
if i>1 then FreeLibrary(Brain[i].hm);
end;
end;
function PreviewMap(lm: integer): pointer;
begin
lx:=lxmax; ly:=lymax; MapSize:=lx*ly;
LandMass:=lm;
RandSeed:=PreviewRND;
if not PreviewElevation then
begin
CreateElevation;
PreviewElevation:=true;
end;
CreateMap(true);
result:=@RealMap;
end;
procedure ChangeClientWhenDone(Command, Player: integer; var Data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -