📄 outercore.pas
字号:
{$INCLUDE switches}
//{$DEFINE TEXTLOG}
//{$DEFINE LOADPERF}
unit OuterCore;
interface
uses
Protocol, InnerCore;
const
Version=$000D00;
FirstAICompatibleVersion=$000D00;
FirstBookCompatibleVersion=$000D00;
// notifications
ntCreateWorld=0; ntInitModule=$100; ntInitLocalHuman=$1FF;
ntDLLError=$200; ntAIError=$2FF;
ntClientError=$300;
ntInitPlayers=$400; ntDeactivationMissing=$410;
ntLoadBegin=$500; ntLoadState=$501;
ntEndInfo=$600; ntBackOn=$601; ntBackOff=$602; ntLoadError=$603;
ntStartDone=$700; ntStartGo=$701; ntStartGoRefresh=$702;
ntStartGoRefreshMaps=$703;
ntChangeClient=$800; ntNextPlayer=$810;
// module flags
fMultiple=$02;fBroadcast=$04;fUsed=$08;
// save map tile flags
smOwned=$20; smUnit=$40; smCity=$80;
maxBrain=255;
bixNoTerm=0; bixSuper_Virtual=1; bixTerm=2;
// < bixTerm -> no active player
// > bixTerm -> AI
type
TNotifyFunction = procedure(ID: integer);
TBrainInfo= record
FileName, DLLName, Name, Credits: string; {filename and full name}
hm, {module handle}
Flags,
DataVersion, DataSize: integer;
Client: TClientCall; {client function address}
end;
var
// PARAMETERS
bixView: array[0..nPl-1]of integer; {brain index of the players}
Difficulty: array[0..nPl-1]of integer absolute InnerCore.Difficulty; {difficulty}
// READ ONLY
nBrain: integer; {number of brains available}
Brain: array[-1..maxBrain-1] of TBrainInfo; {available brains}
MissingBrain: string;
procedure Init(NotifyFunction: TNotifyFunction);
procedure Done;
procedure StartNewGame(const Path, FileName, Map: string; Newlx, Newly,
NewLandMass, NewMaxTurn: integer);
function LoadGame(const Path, FileName: string; Turn: integer): boolean;
procedure EditMap(const Map: string; Newlx, Newly, NewLandMass: integer);
procedure DirectHelp(StartHelp: boolean);
procedure ChangeClient;
procedure NextPlayer;
function PreviewMap(lm: integer): pointer;
implementation
uses
CmdList,IPQ,LocalHuman,NoTerm,
Windows,Classes,SysUtils;
const
eMountains=$6000FFFF; // additional return code for server internal use
type
TToWorkList = array[0..INFIN,0..nJob-1] of word;
var
MaxDist: integer;
ToWork: ^TToWorkList; {work left for each tile and job}
Worked: array[0..nPl-1] of integer; {settler work statistics}
Stat: array[0..nStat-1, 0..nPl-1] of ^TChart;
procedure MaskD(var x; Count, Mask: Cardinal); Register;
asm
sub eax,4
@r: and [eax+edx*4],ecx
dec edx
jnz @r
end;
function Thurst(p, mix, Loc, MP: integer): integer;
begin
if (RW[p].Model[mix].Domain>=dSea)
or (RealMap[Loc] and (fCity or fRiver or fCanal)<>0)
or (RealMap[Loc] and fTerImp=tiIrrigation)
or (RealMap[Loc] and fTerImp=tiFarm)
or (RealMap[Loc] and fTerImp=tiBase)
or (GWonder[woGardens].EffectiveOwner=p) then
result:=0
else if (RealMap[Loc] and fTerrain=fDesert)
and (RealMap[Loc] and fSpecial<>fSpecial1{Oasis}) then
result:=(DesertThurst*MP-1) div RW[p].Model[mix].Speed +1
else if RealMap[Loc] and fTerrain=fArctic then
result:=(ArcticThurst*MP-1) div RW[p].Model[mix].Speed +1
else result:=0
end;
function UnitSpeed(p, mix, Health: integer): integer;
begin
with RW[p].Model[mix] do
begin
result:=Speed;
if Domain=dSea then
begin
if GWonder[woMagellan].EffectiveOwner=p then inc(result,200);
if Health<100 then
result:=((result-250)*Health div 5000)*50+250;
end
end
end;
procedure GetCityReport(p,cix: integer; var CityReport: TCityReport);
var
i,y0,uix,dx,dy,fix,plus,ProdBonus,TradeBonus,ScienceBonus,PollBonus,FutResBonus,
FutProdBonus,Dist,Loc1,TerrOwner,ForcedSupport: integer;
RareOK: array[0..3] of integer;
RelCorr: single;
TileInfo:TTileInfo;
PModel: ^TModel;
begin
with RW[p].City[cix], CityReport do
begin
if HypoTiles<=0 then HypoTiles:=Tiles;
if HypoTax<0 then HypoTax:=RW[p].TaxRate;
if HypoLux<0 then HypoLux:=RW[p].LuxRate;
Working:=0;
FoodRep:=0;ProdRep:=0;Trade:=0;
FillChar(RareOK,SizeOf(RareOK),0);
y0:=Loc div lx;
for fix:=0 to 26 do if HypoTiles and (1 shl fix)<>0 then
begin {sum resources of exploited tiles}
dy:=fix shr 2-3; dx:=fix and 3 shl 1 -3 + (dy+3) and 1;
Loc1:=(Loc+(dx+y0 and 1+lx+lx) shr 1) mod lx +lx*(y0+dy);
GetTileInfo(p,cix,Loc1,TileInfo);
inc(FoodRep,TileInfo.Food);
inc(ProdRep,TileInfo.Prod);
inc(Trade,TileInfo.Trade);
if (RealMap[Loc1] and fRare<>0) and (RW[p].Tech[adMassProduction]>=tsApplicable) then
inc(RareOK[RealMap[Loc1] shr 25 and 3]);
inc(Working)
end;
Happy:=BasicHappy;
if (Built[imColosseum]>0) and (Happy<Working-Size shr 1) then
Happy:=Working-Size shr 1;
for i:=0 to 27 do if Built[i]=1 then inc(Happy);
if Built[imTemple]=1 then inc(Happy);
if Built[imCathedral]=1 then
begin
inc(Happy,2);
if GWonder[woBach].EffectiveOwner=p then inc(Happy,1)
end;
if Built[imTheater]>0 then inc(Happy,2);
if RW[p].Government=gAnarchy then Happy:=0;
ProdBonus:=0; TradeBonus:=0; ScienceBonus:=0; PollBonus:=0;
if Built[imAlgae]=1 then inc(FoodRep,12);
if Built[imMarket]=1 then inc(TradeBonus);
if Built[imBank]=1 then
begin
inc(TradeBonus,2);
if RW[p].NatBuilt[imStockEx]=1 then inc(TradeBonus,2);
end;
if Built[imLibrary]=1 then inc(ScienceBonus);
if Built[imUniversity]=1 then inc(ScienceBonus,2);
if Built[imResLab]=1 then inc(ScienceBonus,3);
if Built[imFactory]=1 then inc(ProdBonus);
if Built[imMfgPlant]=1 then inc(ProdBonus);
if (Built[imPower]=1) or (Built[imHydro]=1)
or (Built[imNuclear]=1) or (GWonder[woHoover].EffectiveOwner=p) then
ProdBonus:=ProdBonus*2;
if Built[imFactory]=1 then inc(PollBonus);
if Built[imMfgPlant]=1 then inc(PollBonus);
if (Built[imFactory]+Built[imMfgPlant]>0) then
if (Built[imHydro]>0)
or (GWonder[woHoover].EffectiveOwner=p) then dec(PollBonus)
else if (Built[imNuclear]=0) and (Built[imPower]=1) then inc(PollBonus);
if (RW[p].Government<=gDespotism) or (Built[imRecycling]=1) then
PollBonus:=-2; // no pollution
// future tech benefits
FutResBonus:=0;
if RW[p].Tech[futResearchTechnology]>0 then
begin
if Built[imUniversity]=1 then
inc(FutResBonus,UniversityFutureBonus*RW[p].Tech[futResearchTechnology]);
if Built[imResLab]=1 then
inc(FutResBonus,ResLabFutureBonus*RW[p].Tech[futResearchTechnology]);
end;
FutProdBonus:=0;
if RW[p].Tech[futProductionTechnology]>0 then
begin
if Built[imFactory]=1 then
inc(FutProdBonus,FactoryFutureBonus*RW[p].Tech[futProductionTechnology]);
if Built[imMfgPlant]=1 then
inc(FutProdBonus,MfgPlantFutureBonus*RW[p].Tech[futProductionTechnology]);
end;
// calculate unit support
Support:=0; ForcedSupport:=0; Eaten:=Size*2; Deployed:=0;
for uix:=0 to RW[p].nUn-1 do with RW[p].Un[uix] do
if (Loc>=0) and (Home=cix) then
begin
PModel:=@RW[p].Model[mix];
if (PModel.Kind=mkSettler) {and (GWonder[woFreeSettlers].EffectiveOwner<>p)} then
inc(Eaten,SettlerFood[RW[p].Government])
else if Flags and unConscripts<>0 then inc(Eaten);
if (RW[p].Government<>gAnarchy) and (RW[p].Government<>gFundamentalism)
and ((GWonder[woLiberty].EffectiveOwner<>p) or (RealMap[Loc] and fCity=0)
or (Movement<UnitSpeed(p,mix,Health))) then
begin
if GTestFlags and tfImmImprove=0 then
if PModel.Kind=mkSpecial_TownGuard then inc(ForcedSupport)
else if (PModel.Flags and mdDoubleSupport<>0) then inc(Support,2)
else inc(Support);
if PModel.Flags and mdCivil=0 then
begin
TerrOwner:=RealMap[Loc] shr 27;
case RW[p].Government of
gRepublic, gLybertarianism:
if (TerrOwner<>p) and (TerrOwner<nPl)
and (RW[p].Treaty[TerrOwner]<trAlliance) then
inc(Deployed);
gDemocracy:
if (TerrOwner>=nPl) or (TerrOwner<>p)
and (RW[p].Treaty[TerrOwner]<trAlliance) then
inc(Deployed);
end;
end
end;
end;
if Deployed>=Happy then Happy:=0 else dec(Happy,Deployed);
dec(Support,Size*SupportFree[RW[p].Government] shr 1);
if Support<0 then Support:=0;
inc(Support,ForcedSupport);
if RW[p].Government=gFundamentalism then
begin Happy:=Working; Science:=Science shr 1 end;
{police units}
case RW[p].Government of
gDespotism:
for i:=0 to RW[p].nUn-1 do
if (RW[p].Un[i].Loc=Loc)
and (RW[p].Model[RW[p].Un[i].mix].Kind=mkSpecial_TownGuard) then
inc(Happy);
end;
Dist:=MaxDist;
for i:=0 to RW[p].nCity-1 do
if (RW[p].City[i].Loc>=0) and (RW[p].City[i].Built[imPalace]=1) then
Dist:=Distance(Loc,RW[p].City[i].Loc);
if (Dist=0) or (CorrLevel[RW[p].Government]=0) then Corruption:=0
else
begin
RelCorr:=Dist/MaxDist;
if CorrLevel[RW[p].Government]>1 then
RelCorr:=Exp(ln(RelCorr)/CorrLevel[RW[p].Government]);
if Built[imCourt]=1 then RelCorr:=RelCorr/2;
Corruption:=Trunc(Trade*RelCorr);
// !!! floating point calculation always deterministic???
end;
Tax:=(HypoTax*(Trade-Corruption)+50) div 100;
if RW[p].Government=gAnarchy then Lux:=0
else if GWonder[woMich].EffectiveOwner=p then
begin
plus:= Working -Size shr 1 -Happy; // required additional happies
if plus>0 then
begin
Lux:=(4*plus +1+TradeBonus) div (2+TradeBonus);
if Lux>Trade-Corruption then Lux:=Trade-Corruption;
if Tax>Trade-Corruption-Lux then Tax:=Trade-Corruption-Lux;
end
else Lux:=0;
end
else if (HypoLux=0) or (HypoTax=100) then Lux:=0
else Lux:=(HypoLux*(Trade-Corruption-Tax) + (100-HypoTax) shr 1) div (100-HypoTax);
Science:=Trade-Corruption-Lux-Tax;
Tax:=Tax*(2+TradeBonus) shr 1;
Lux:=Lux*(2+TradeBonus) shr 1;
if FutResBonus>0 then
Science:=Science*(100+ScienceBonus*50+FutResBonus) div 100
else Science:=Science*(2+ScienceBonus) shr 1;
if Built[imNatObs]>0 then Science:=Science*2;
if RW[p].Government=gFundamentalism then Science:=Science shr 1
else if (GWonder[woNewton].EffectiveOwner=p) and (RW[p].Government=gMonarchy) then
Science:=Science*2;
PollRep:=ProdRep*(2+PollBonus) shr 1;
if PollRep<=Size then PollRep:=0 else dec(PollRep,Size);
if FutProdBonus>0 then
ProdRep:=ProdRep*(100+ProdBonus*50+FutProdBonus) div 100
else ProdRep:=ProdRep*(2+ProdBonus) shr 1;
Happy:=Happy+Lux shr 1;
// if Happy>Working then Happy:=Working;
// calculate storage size
Storage:=StorageSize[Difficulty[p]];
// if RW[p].Government=gLybertarianism then Storage:=Storage*2;
// check if rare resource available
if (GTestFlags and tfNoRareNeed=0) and (ProdRep>Support)
and (Project and cpImp<>0)
and ((Project and cpIndex=imShipComp) and (RareOK[1]=0)
or (Project and cpIndex=imShipPow) and (RareOK[2]=0)
or (Project and cpIndex=imShipHab) and (RareOK[3]=0)) then
ProdRep:=Support;
// calculate project cost
if Project and cpImp=0 then
begin
ProdCost:=RW[p].Model[Project and cpIndex].Cost; {unit project}
if Project and cpConscripts<>0 then
begin
i:=RW[p].Model[Project and cpIndex].MCost;
ProdCost:=ProdCost-3*i;
if ProdCost<=0 then ProdCost:=i
end
else if RW[p].Model[Project and cpIndex].Cap[mcLine]>0 then
if Project0 and (cpRepeat or cpIndex)=Project and cpIndex or cpRepeat then
ProdCost:=ProdCost shr 1
else ProdCost:=ProdCost*2
end
else
begin {improvement project}
ProdCost:=Imp[Project and cpIndex].Cost;
if (Project and cpIndex<28) and (GWonder[woColossus].EffectiveOwner=p) then
ProdCost:=ProdCost*ColossusEffect div 100;
end;
ProdCost:=ProdCost*BuildCostMod[Difficulty[p]] div 12;
end;
end; {GetCityReport}
procedure GetCityAreaInfo(p,Loc: integer; var CityAreaInfo: TCityAreaInfo);
var
dx, dy, fix, Loc1, p1: integer;
begin
with CityAreaInfo do
begin
for fix:=0 to 26 do Available[fix]:=faInvalid;
for dy:=-3 to 3 do for dx:=-3 to 3 do
if ((dx+dy) and 1=0) and ((dx<>3) and (dx<>-3) or (dy<>3) and (dy<>-3)) then
begin
fix:=(dy+3) shl 2+(dx+3) shr 1; {relative tile location code}
Loc1:=dLoc(Loc,dx,dy);
if Loc1<0 then Available[fix]:=faPole
else
begin
p1:=RealMap[Loc1] shr 27;
if (p1<nPl) and (p1<>p) and (RW[p].Treaty[p1]>=trPeace) then
Available[fix]:=faTreaty
else if (ZoCMap[Loc1]>0) and (Occupant[Loc1]<>p)
and (RW[p].Treaty[Occupant[Loc1]]<trAlliance) then
Available[fix]:=faSiege
else if (UsedByCity[Loc1]<>-1) and (UsedByCity[Loc1]<>Loc) then
Available[fix]:=faNotAvailable
else Available[fix]:=faAvailable
end
end;
end
end;
function SetCityTiles(p, cix, NewTiles: integer; TestOnly: boolean = false): integer;
var
fix,Working,ChangeTiles,AddTiles,dx,dy,Loc1: integer;
CityAreaInfo: TCityAreaInfo;
begin
with RW[p].City[cix] do
begin
ChangeTiles:=NewTiles xor integer(Tiles);
AddTiles:=NewTiles and not Tiles;
if Mode=moPlaying then
begin // do all checks
if NewTiles and not $67F7F76<>0 then
begin result:=eInvalid; exit end; // invalid tile index included
if NewTiles and (1 shl 13)=0 then
begin result:=eViolation; exit end; // city tile must be exploited
if ChangeTiles=0 then
begin result:=eNotChanged; exit end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -