📄 innercore.pas
字号:
i:=0;
while (i<nEnemyCity) and (EnemyCity[i].Loc<>Loc) do
inc(i);
if i=nEnemyCity then
begin
inc(nEnemyCity);
assert(nEnemyCity<necmax);
EnemyCity[i].Status:=0;
EnemyCity[i].SavedStatus:=0;
if pTell=p then result:=true;
end;
MakeCityInfo(pFoundCity,cixFoundCity,EnemyCity[i]);
end;
end
else if Map[Loc] and fCity<>0 then // remove enemycity
for cix:=0 to nEnemyCity-1 do
if EnemyCity[cix].Loc=Loc then
EnemyCity[cix].Loc:=-1;
if Map[Loc]=fUNKNOWN then inc(Discovered[pTell]);
if euix>=-1 then
Map[Loc]:=Map[Loc] and not (fUnit or fCity or fOwned)
or Tile and (fUnit or fCity or fOwned)
else
begin
Map[Loc]:=Tile;
MapObservedLast[Loc]:=GTurn
end;
ObserveLevel[Loc]:=ObserveLevel[Loc] and not (3 shl (2*pTell))
or Cardinal(Level) shl (2*pTell);
end
end; // DiscoverTile
function Discover(Loc,p,r,AdjacentLevel: integer; TellAllied, EnableContact: boolean): boolean;
{player p discovers at Loc with radius r
result indicates whether new enemy units/cities spotted}
// implementation is critical for loading performance, change carefully
const
table_dy: array[0..41] of integer=
(1,0,2,-1,1,3,-2,0,2,2,-1,1,1,0, //14
2,-1,1,3,-2,0,2,4,-3,-1,1,3,3,-2,0,2,4,-3,-1,1,3,3,-2,0,2,2,-1,1); //28
adjacent: array[0..41] of integer=
(0,1,0,1,1,0,1,1,1,0,1,1,0,1, //14
0,0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0); //28
var
i,y0,y,dx,dmax,Loc1,pTell,Level,OldLevel,count,tablestart: integer;
begin
assert((Mode>moLoading_Fast) or (RW[p].nEnemyUn=0));
result:=false;
y0:=Loc div lx;
if r=4 then begin dmax:=3; tablestart:=14 end
else {if r=2 then} begin dmax:=2; tablestart:=0 end;
for dx:=-dmax to dmax do
begin
count:=table_dy[tablestart];
inc(tablestart);
y:=y0+table_dy[tablestart];
Loc1:=(Loc+(dx+y0 and 1+lx+lx) shr 1) mod lx +lx*y;
for i:=0 to count-1 do
begin
if (y>=0) and (y<ly) then
begin
if adjacent[tablestart]<>0 then Level:=AdjacentLevel
else Level:=lObserveUnhidden;
if TellAllied then
begin
for pTell:=0 to nPl-1 do
if (pTell=p) or (1 shl pTell and GAlive<>0)
and (RW[p].Treaty[pTell]=trAlliance) then
begin
OldLevel:=ObserveLevel[Loc1] shr (2*pTell) and 3;
if Level>OldLevel then
result:=DiscoverTile(Loc1,p,pTell,Level,EnableContact) or result;
end
end
else
begin
OldLevel:=ObserveLevel[Loc1] shr (2*p) and 3;
if Level>OldLevel then
result:=DiscoverTile(Loc1,p,p,Level,EnableContact) or result;
end
end;
inc(y,2);
inc(Loc1,lx+lx);
inc(tablestart);
end
end;
end;
(*unoptimized implementation:
function Discover(Loc,p,r:integer; SpotNearHidden, TellAllied, EnableContact: boolean): boolean;
var
y0,dx,dy,dmax,Loc1,pTell,Loc1x,r1,Level,OldLevel: integer;
begin
result:=false;
y0:=Loc div lx;
if r=4 then dmax:=3
else {if r=2 then} dmax:=2;
for dx:=-dmax to dmax do
begin
Loc1x:=(Loc+(dx+y0 and 1+lx+lx) shr 1) mod lx;
for dy:=-dmax to dmax do
if ((dx+dy) and 1=0) and (y0+dy>=0) and (y0+dy<ly) then
begin
r1:=abs(dx)+abs(dy);
if r1<=r then
begin
Loc1:=Loc1x +lx*(y0+dy);
if SpotNearHidden and (r1<=2) then Level:=lObserveAll
else Level:=lObserveUnhidden;
if TellAllied then
begin
for pTell:=0 to nPl-1 do
if (pTell=p) or (RW[p].Treaty[pTell]=trAlliance) then
begin
OldLevel:=ObserveLevel[Loc1] shr (2*pTell) and 3;
if Level>OldLevel then
result:=DiscoverTile(Loc1,p,pTell,Level,EnableContact) or result;
end
end
else
begin
OldLevel:=ObserveLevel[Loc1] shr (2*p) and 3;
if Level>OldLevel then
result:=DiscoverTile(Loc1,p,p,Level,EnableContact) or result;
end
end
end
end;
end;*)
procedure DiscoverAll(p, Level: integer);
{player p discovers complete playground (for supervisor)}
var
Loc, OldLevel: integer;
begin
assert((Mode>moLoading_Fast) or (RW[p].nEnemyUn=0));
for Loc:=0 to MapSize-1 do
begin
OldLevel:=ObserveLevel[Loc] shr (2*p) and 3;
if Level>OldLevel then
DiscoverTile(Loc,p,p,Level,false);
end;
end;
procedure DiscoverViewAreas(p: integer);
var
pTell, uix, cix: integer;
PModel: ^TModel;
begin // discover unit and city view areas
for pTell:=0 to nPl-1 do
if (pTell=p) or (RW[p].Treaty[pTell]=trAlliance) then
begin
for uix:=0 to RW[pTell].nUn-1 do with RW[pTell].Un[uix] do
if (Loc>=0) and (master<0) then
begin
PModel:=@RW[pTell].Model[mix];
if (PModel.Kind=mkDiplomat) or (PModel.Cap[mcSpy]>0) then
Discover(Loc,p,4,lObserveSuper,false,true)
else if (PModel.Cap[mcRadar]+PModel.Cap[mcCarrier]>0)
or (PModel.Domain=dAir) then
Discover(Loc,p,4,lObserveAll,false,false)
else if (RealMap[Loc] and fTerrain=fMountains)
or (PModel.Cap[mcAcademy]>0) then
Discover(Loc,p,4,lObserveUnhidden,false,PModel.Domain=dGround)
else Discover(Loc,p,2,lObserveUnhidden,false,PModel.Domain=dGround);
end;
for cix:=0 to RW[pTell].nCity-1 do if RW[pTell].City[cix].Loc>=0 then
Discover(RW[pTell].City[cix].Loc,p,4,lObserveUnhidden,false,true);
end;
if GWonder[woMir].EffectiveOwner=p then
DiscoverAll(p,lObserveUnhidden)
end;
function GetUnitStack(p,Loc: integer): integer;
var
uix: integer;
unx: ^TUn;
begin
result:=0;
if Occupant[Loc]<0 then exit;
for uix:=0 to RW[Occupant[Loc]].nUn-1 do
begin
unx:=@RW[Occupant[Loc]].Un[uix];
if unx.Loc=Loc then
begin
MakeUnitInfo(Occupant[Loc],unx^,RW[p].EnemyUn[RW[p].nEnemyUn+result]);
TellAboutModel(p,Occupant[Loc],unx.mix);
RW[p].EnemyUn[RW[p].nEnemyUn+result].emix:=RWemix[p,Occupant[Loc],unx.mix];
inc(result);
end
end
end;
procedure UpdateUnitMap(Loc: integer; CityChange: boolean = false);
// update maps and enemy units of all players after unit change
var
p, euix, OldLevel, ClearFlags: integer;
begin
if (Mode=moLoading_Fast) and not CityChange then exit;
for p:=0 to nPl-1 do if 1 shl p and GWatching<>0 then
begin
OldLevel:=ObserveLevel[Loc] shr (2*p) and 3;
if OldLevel>lNoObserve then
begin
if RW[p].Map[Loc] and (fUnit or fOwned)=fUnit then
begin
// replace unit located here in EnemyUn
// do not just set loc:=-1 because total number would be unlimited
euix:=RW[p].nEnemyUn-1;
while euix>=0 do
begin
if RW[p].EnemyUn[euix].Loc=Loc then
begin RW[p].EnemyUn[euix].Loc:=-1; Break; end;
dec(euix);
end;
RW[p].Map[Loc]:=RW[p].Map[Loc] and not fUnit
end
else
begin // look for empty slot in EnemyUn
euix:=RW[p].nEnemyUn-1;
while (euix>=0) and (RW[p].EnemyUn[euix].Loc>=0) do dec(euix);
end;
if (Occupant[Loc]<0) and not CityChange then
begin
if RealMap[Loc] and fCity=0 then
ClearFlags:=fUnit or fHiddenUnit or fStealthUnit or fOwned
else ClearFlags:=fUnit or fHiddenUnit or fStealthUnit;
RW[p].Map[Loc]:=RW[p].Map[Loc] and not ClearFlags;
end
else if (Occupant[Loc]<>p) or CityChange then
begin
ObserveLevel[Loc]:=ObserveLevel[Loc] and not (3 shl (2*p));
DiscoverTile(Loc, p, p, OldLevel, false, euix);
end
else {if (Occupant[Loc]=p) and not CityChange then}
RW[p].Map[Loc]:=RW[p].Map[Loc] or fUnit or fOwned;
end
end
end;
{
Territory Calculation
____________________________________________________________________
}
var
BorderChanges: array[0..sIntExpandTerritory and $F-1] of Cardinal;
procedure ChangeTerritory(Loc, p: integer);
var
p1: integer;
begin
assert(p>=0); // no player's territory indicated by p=nPl
dec(Territory[RealMap[Loc] shr 27]);
inc(Territory[p]);
RealMap[Loc]:=RealMap[Loc] and not fTerritory or Cardinal(p) shl 27;
for p1:=0 to nPl-1 do if 1 shl p1 and GWatching<>0 then
if ObserveLevel[Loc] and (3 shl (p1*2))>0 then
RW[p1].Map[Loc]:=RW[p1].Map[Loc] and not fTerritory or Cardinal(p) shl 27;
end;
procedure ExpandTerritory(p, OriginLoc: integer);
var
i,dx,dy,dxMax,dyMax,Loc,NewOwner: integer;
begin
i:=0;
dyMax:=0;
while (dyMax+1)+(dyMax+1) shr 1<=CountryRadius do
inc(dyMax);
for dy:=-dyMax to dyMax do
begin
dxMax:=dy and 1;
while abs(dy)+(dxMax+2)+abs(abs(dy)-(dxMax+2)) shr 1<=CountryRadius do
inc(dxMax,2);
for dx:=-dxMax to dxMax do if (dy+dx) and 1=0 then
begin
NewOwner:=BorderChanges[i div 8] shr (i mod 8 *4) and $F;
Loc:=dLoc(OriginLoc,dx,dy);
if (Loc>=0) and (Cardinal(NewOwner)<>RealMap[Loc] shr 27) then
ChangeTerritory(Loc,NewOwner);
inc(i);
end
end
end;
procedure CheckBorders(OriginLoc, PlayerLosingCity: integer);
// OriginLoc: only changes in CountryRadius around this location possible,
// -1 for complete map, -2 for double-check (no more changes allowed)
// PlayerLosingCity: do nothing but remove tiles no longer in reach from this
// player's territory, -1 for full border recalculation
var
i,r,Loc,Loc1,Loc1x,dx,dy,p1,p2,cix,NewDist,y0,dxMax,dyMax,OldOwner,
NewOwner: integer;
AtPeace: array[0..nPl,0..nPl] of boolean;
Country, FormerCountry, {to who's country a tile belongs}
Dist, FormerDist, StolenDist: array[0..lxmax*lymax-1] of ShortInt;
begin
if PlayerLosingCity>=0 then
begin
for Loc:=0 to MapSize-1 do StolenDist[Loc]:=CountryRadius+1;
for cix:=0 to RW[PlayerLosingCity].nCity-1 do
if RW[PlayerLosingCity].City[cix].Loc>=0 then
StolenDist[RW[PlayerLosingCity].City[cix].Loc]:=0;
for r:=1 to CountryRadius shr 1 do
begin
move(StolenDist,FormerDist,MapSize);
for Loc:=0 to MapSize-1 do
if (FormerDist[Loc]<=CountryRadius-2) // use same conditions as below!
and ((1 shl (RealMap[Loc] and fTerrain))
and (1 shl fShore+1 shl fMountains+1 shl fArctic)=0) then
begin
y0:=Loc div lx;
for dx:=-2 to 2 do
begin
Loc1x:=(Loc+(dx+y0 and 1+lx+lx) shr 1) mod lx;
for dy:=-2 to 2 do if abs(dx)+abs(dy)=2 then
begin
Loc1:=Loc1x+lx*(y0+dy);
NewDist:=FormerDist[Loc]+3-dy and 1;
if (Loc1>=0) and (Loc1<MapSize) and (NewDist<StolenDist[Loc1]) then
StolenDist[Loc1]:=NewDist;
end
end
end
end;
end;
FillChar(Country,MapSize,-1);
for Loc:=0 to MapSize-1 do Dist[Loc]:=CountryRadius+1;
for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then
for cix:=0 to RW[p1].nCity-1 do if RW[p1].City[cix].Loc>=0 then
begin
Country[RW[p1].City[cix].Loc]:=p1;
Dist[RW[p1].City[cix].Loc]:=0;
end;
for r:=1 to CountryRadius shr 1 do
begin
move(Country,FormerCountry,MapSize);
move(Dist,FormerDist,MapSize);
for Loc:=0 to MapSize-1 do
if (FormerDist[Loc]<=CountryRadius-2) // use same conditions as above!
and ((1 shl (RealMap[Loc] and fTerrain))
and (1 shl fShore+1 shl fMountains+1 shl fArctic)=0) then
begin
assert(FormerCountry[Loc]>=0);
y0:=Loc div lx;
for dx:=-2 to 2 do
begin
Loc1x:=(Loc+(dx+y0 and 1+lx+lx) shr 1) mod lx;
for dy:=-2 to 2 do if abs(dx)+abs(dy)=2 then
begin
Loc1:=Loc1x+lx*(y0+dy);
NewDist:=FormerDist[Loc]+3-dy and 1;
if (Loc1>=0) and (Loc1<MapSize) and (NewDist<Dist[Loc1]) then
begin
Country[Loc1]:=FormerCountry[Loc];
Dist[Loc1]:=NewDist;
end
end
end
end
end;
FillChar(AtPeace, sizeof(AtPeace), false);
for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then
for p2:=0 to nPl-1 do
if (p2<>p1) and (1 shl p2 and GAlive<>0) and (RW[p1].Treaty[p2]>=trPeace) then
AtPeace[p1,p2]:=true;
if OriginLoc>=0 then
begin // update area only
i:=0;
fillchar(BorderChanges, sizeof(BorderChanges), 0);
dyMax:=0;
while (dyMax+1)+(dyMax+1) shr 1<=CountryRadius do
inc(dyMax);
for dy:=-dyMax to dyMax do
begin
dxMax:=dy and 1;
while abs(dy)+(dxMax+2)+abs(abs(dy)-(dxMax+2)) shr 1<=CountryRadius do
inc(dxMax,2);
for dx:=-dxMax to dxMax do if (dy+dx) and 1=0 then
begin
Loc:=dLoc(OriginLoc,dx,dy);
if Loc>=0 then
begin
if Loc=2581 then
Loc:=Loc; //!!!
OldOwner:=RealMap[Loc] shr 27;
NewOwner:=Country[Loc] and $f;
if NewOwner<>OldOwner then
if AtPeace[NewOwner,OldOwner]
and not ((OldOwner=PlayerLosingCity) and (StolenDist[Loc]>CountryRadius)) then
NewOwner:=OldOwner // peace fixes borders
else ChangeTerritory(Loc,NewOwner);
inc(BorderChanges[i div 8],NewOwner shl (i mod 8 *4));
end;
inc(i);
end
end
end
else for Loc:=0 to MapSize-1 do // update complete map
begin
OldOwner:=RealMap[Loc] shr 27;
NewOwner:=Country[Loc] and $f;
if (NewOwner<>OldOwner)
and (not AtPeace[NewOwner,OldOwner]
or ((OldOwner=PlayerLosingCity) and (StolenDist[Loc]>CountryRadius))) then
begin
assert(OriginLoc<>-2); // !!!test if border saving works
ChangeTerritory(Loc,NewOwner);
end;
end;
{$IFOPT O-}if OriginLoc<>-2 then CheckBorders(-2);{$ENDIF} //!!! check: single pass should do!
end; //CheckBorders
procedure LogCheckBorders(p,cix,PlayerLosingCity: integer);
begin
CheckBorders(RW[p].City[cix].Loc,PlayerLosingCity);
IntServer(sIntExpandTerritory,p,cix,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -