📄 cityscreen.pas
字号:
{$INCLUDE switches}
unit CityScreen;
interface
uses
Protocol,ClientTools,Term,ScreenTools,IsoEngine,PVSB,BaseWin,
Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,ExtCtrls,ButtonA,
ButtonB, ButtonBase;
const
{modes}
mSupp=1; mImp=2;
type
TCityDlg = class(TBaseDlg)
Timer1: TTimer;
BuyBtn: TButtonB;
CloseBtn: TButtonA;
SupportBtn: TButtonB;
BuiltBtn: TButtonB;
procedure FormCreate(Sender:TObject);
procedure FormDestroy(Sender:TObject);
procedure FormMouseDown(Sender:TObject;Button:TMouseButton;
Shift:TShiftState;x,y:integer);
procedure BuyClick(Sender:TObject);
procedure CloseBtnClick(Sender:TObject);
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Timer1Timer(Sender: TObject);
procedure SupportBtnClick(Sender: TObject);
procedure BuiltBtnClick(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: word;
Shift: TShiftState);
public
Mode,cix,cLoc,Happened: integer;
CloseAction: (None, Restore, RestoreAutoTurn);
ProdHint: boolean;
procedure ShowNow;
procedure OffscreenPaint; override;
private
c: TCity;
Report:TCityReport;
cOwner,cGov,
emix{EnemyModel Index},
BlinkTime,nDisplay,CityAge:integer;
imix:array[0..15] of integer;
sb:TPVScrollbar;
CityAreaInfo: TCityAreaInfo;
OuterCityTex, InnerCityTex: TTexture;
AreaMap: TIsoMap;
EventSoundEnabled: boolean;
procedure InitDisplay;
procedure ChooseProject;
procedure OffscreenUpdate;
procedure OnScroll(var m:TMessage); message WM_VSCROLL;
end;
var
CityDlg:TCityDlg;
implementation
uses
Select,Messg,MessgEx,Help,Inp;
{$R *.DFM}
const
xArea=24; yArea=41;
xView=232; yView=286;
xFood=325; yFood=277;
xProd=13; yProd=277;
xTrade=325; yTrade=44;
xMessage=24; yMessage=38;
xImp=49;{7} yImp=207; ImpPitch=64;
xSupp=49;{7} ySupp=207; SuppPitch=64;
var
ImpSorted: array[0..nImp-1] of integer;
procedure TCityDlg.FormCreate(Sender:TObject);
begin
inherited;
WideBottom:=true;
FullCaption:=false;
TexOverride:=true;
CaptionLeft:=140;
CreatePVSB(sb,Handle,243,ClientWidth-SideFrame,243+64);
AreaMap:=TIsoMap.Create;
AreaMap.SetOutput(offscreen);
AreaMap.SetPaintBounds(xArea,yArea,xArea+8*33,yArea+8*16);
Mode:=mImp;
ProdHint:=false;
EventSoundEnabled:=false;
InnerHeight:=ClientHeight-2*WideFrame;
InitButtons(self);
InitWindowRegion;
end;
procedure TCityDlg.FormDestroy(Sender:TObject);
begin
AreaMap.Free;
end;
procedure TCityDlg.CloseBtnClick(Sender:TObject);
begin
Close
end;
procedure TCityDlg.FormKeyDown(Sender: TObject; var Key: word;
Shift: TShiftState);
begin
if Key=13 then Close;
end;
procedure TCityDlg.InitDisplay;
var
Cnt,i: integer;
begin
Cnt:=0;
if Mode=mImp then
begin
nDisplay:=(InnerWidth-xImp-GetSystemMetrics(SM_CXVSCROLL)+ImpPitch-58) div ImpPitch;
for i:=0 to nImp-1 do if c.Built[i]=1 then inc(Cnt);
end
else
begin
nDisplay:=(InnerWidth-xSupp-GetSystemMetrics(SM_CXVSCROLL)) div 64;
for i:=0 to MyRO.nUn-1 do
if (MyUn[i].Loc>=0) and (MyUn[i].Home=cix) then inc(Cnt);
end;
if Cnt>0 then InitPVSB(sb,(Cnt+nDisplay-1) div nDisplay-1,1)
else InitPVSB(sb,0,1);
end;
procedure TCityDlg.OnScroll(var m:TMessage);
begin
if ProcessPVSB(sb,m) then
begin OffscreenPaint; SmartInvalidate; Update end;
end;
procedure TCityDlg.OffscreenPaint;
procedure FillBar(Cap: string; x,y,pos,Growth,max,Kind: integer);
var
s: string;
begin
if Growth>0 then
PaintProgressBar(offscreen.Canvas,Kind,x-3,y,pos*110 div max,
(Growth*110 +max div 2) div max,110,OuterCityTex)
else PaintProgressBar(offscreen.Canvas,Kind,x-3,y,pos*110 div max,
(Growth*110 -max div 2) div max,110,OuterCityTex);
with offscreen.Canvas do
begin
RisedTextOut(offscreen.Canvas,x-6,y-20,Cap);
s:=Format('%d/%d',[pos,max]);
RisedTextOut(offscreen.Canvas,x+128,y-7,s);
end
end;
procedure DisorderBar(x,y: integer);
var
s: string;
begin
DarkGradient(offscreen.Canvas,x-6,y+1,212,3);
if cGov=gAnarchy then s:=Phrases.Lookup('GOVERNMENT',gAnarchy)
else if c.Flags and chCaptured<>0 then
s:=Phrases.Lookup('CITYEVENTS',13)
else s:=Phrases.Lookup('CITYEVENTS',0);
RisedTextOut(offscreen.Canvas,x-2,y,s)
end;
procedure CaptionBar(dst:TBitmap;x,y:integer;Kind:integer; Cap:string;
val: integer);
var
s:string;
begin
with dst.Canvas do
begin
font.color:=OuterCityTex.clTextLight;
if Kind>=0 then
begin
LightGradient(dst.Canvas,x-6,y+1,16,
GrExt[HGrSystem].Data.Canvas.Pixels[187,115+kind]);
LightGradient(dst.Canvas,x-6+17,y+1,212-17,OuterCityTex.clTextShade);
Sprite(dst,HGrSystem,x-3,y+4,10,10,66+Kind mod 11 *11,
115+Kind div 11 *11);
TextOut(x+15,y,Cap)
end
else
begin
LightGradient(dst.Canvas,x-6,y+1,212,OuterCityTex.clTextShade);
TextOut(x-2,y,Cap);
end;
s:=IntToStr(val);
TextOut(x+170+32-TextWidth(s),y,s);
end
end;
procedure PaintResources(x,y,Loc:integer);
var
d,i,Total,xGr:integer;
TileInfo:TTileInfo;
rare: boolean;
begin
if Server(sGetCityTileInfo,me,Loc,TileInfo)<>eOk then
begin assert(cix<0); exit end;
Total:=TileInfo.Food+TileInfo.Prod+TileInfo.Trade;
rare:=MyMap[Loc] and $06000000>0;
if rare then inc(Total);
if Total>1 then d:=22 div (Total-1);
if d<1 then d:=1;
if d>4 then d:=4;
for i:=0 to Total-1 do
begin
if rare and (i=Total-1) then xGr:=66+110
else if i>=TileInfo.Food+TileInfo.Prod then xGr:=66+44
else if i>=TileInfo.Prod then xGr:=66
else xGr:=66+22;
Sprite(offscreen,HGrSystem,x+28+d*(2*i+1-Total),y+11,10,10,xGr,115);
end
end;
var
line: integer;
procedure CheckMessage(Flag: integer);
var
i, test: integer;
s: string;
begin
if Happened and Flag<>0 then
begin
i:=0;
test:=1;
while test<Flag do begin inc(i); inc(test,test) end;
if EventSoundEnabled then
begin
if Flag=chProduction then
begin
if c.Project0 and cpImp<>0 then
begin
if c.Project0 and cpIndex>=28 then // wonders have already extra message with sound
if not Play('IMP_SPECIAL',c.Project0 and cpIndex) then
Play('IMP_STD')
end
else Play('UNIT_STD');
EventSoundEnabled:=false;
end
else if Play('CITYEVENTS',i) then
EventSoundEnabled:=false;
end;
s:=Phrases.Lookup('CITYEVENTS',i);
if Flag=chNoGrowthWarning then
if c.Built[imAqueduct]=0 then
s:=Format(s,[Phrases.Lookup('IMPROVEMENTS',imAqueduct)])
else s:=Format(s,[Phrases.Lookup('IMPROVEMENTS',imSewer)]);
RisedTextOut(offscreen.Canvas,xMessage,yMessage+16*line,s);
inc(line)
end
end;
var
x,xGr,i,i1,j,d,dx,dy,mov0,PrCost,Cnt,Loc1,FreeSupp,TerrOwner,Paintiix: integer;
PrName:string;
UnitInfo: TUnitInfo;
Disorder,TestDeployed: boolean;
begin
inherited;
if cix>=0 then c:=MyCity[cix];
with offscreen.Canvas do
begin
Font.Assign(UniFont[ftSmall]);
Fill(offscreen.Canvas,0,0,InnerWidth,yArea-2,0,0,InnerCityTex);
Fill(offscreen.Canvas,0,yArea-2,xArea-1,132,0,0,InnerCityTex);
Fill(offscreen.Canvas,xArea+265,yArea-2,xTrade-xArea-278,132,0,0,InnerCityTex);
Fill(offscreen.Canvas,0,yArea+130,xTrade-13,yImp-yArea-130,0,0,InnerCityTex);
Fill(offscreen.Canvas,0,yImp,InnerWidth,yProd-yImp-6,0,0,InnerCityTex);
Fill(offscreen.Canvas,xTrade-12,yArea-2,InnerWidth-xTrade+11,yImp-yArea+1,0,0,OuterCityTex);
Fill(offscreen.Canvas,1,yProd-5,InnerWidth-2,InnerHeight-yProd+4,0,0,OuterCityTex);
Frame(offscreen.Canvas,xArea-1,yArea-1,xArea+8*33,yArea+8*16,InnerCityTex.clBevelShade,InnerCityTex.clBevelLight);
RFrame(offscreen.Canvas,xArea-2,yArea-2,xArea+8*33+1,yArea+8*16+1,InnerCityTex.clBevelShade,InnerCityTex.clBevelLight);
Frame(offscreen.Canvas,xTrade-13,yTrade-6,InnerWidth-1,yTrade+102,OuterCityTex.clBevelLight,OuterCityTex.clBevelShade);
Frame(offscreen.Canvas,xTrade-13,yTrade+103,InnerWidth-1,yTrade+162,OuterCityTex.clBevelLight,OuterCityTex.clBevelShade);
Frame(offscreen.Canvas,xProd-13,yProd-6,xFood-14,InnerHeight-1,OuterCityTex.clBevelLight,OuterCityTex.clBevelShade);
Frame(offscreen.Canvas,xFood-13,yFood-6,InnerWidth-1,InnerHeight-1,OuterCityTex.clBevelLight,OuterCityTex.clBevelShade);
AreaMap.Paint(xArea,yArea-16,dLoc(c.Loc,-3,-3),7,7,c.Loc,cOwner);
end;
for dy:=-3 to 3 do for dx:=-3 to 3 do
if ((dx+dy) and 1=0) and (dx*dx*dy*dy<81) then
begin
Loc1:=dLoc(c.Loc,dx,dy);
if (CityAreaInfo.Available[(dy+3) shl 2+(dx+3) shr 1] in [faNotAvailable,faTreaty])
and (MyMap[Loc1] and fCity=0) then
Sprite(offscreen,HGrTerrain,xArea+99+33*dx,yArea+48+16*dy,64,32,391,496);
if (1 shl((dy+3) shl 2+(dx+3) shr 1) and c.Tiles<>0) then
PaintResources(xArea+99+33*dx,yArea+48+16*dy,Loc1);
end;
Report.HypoTiles:=-1;
Report.HypoTax:=-1;
Report.HypoLux:=-1;
if cix>=0 then Server(sGetCityReport,me,cix,Report) // own city
else Server(sGetEnemyCityReport,me,cLoc,Report); // enemy city
Disorder:= (Report.Working-Report.Happy>c.Size div 2)
or (cGov=gAnarchy) or (c.Flags and chCaptured<>0);
i:=Report.FoodRep-Report.Eaten; // growth
// if (i>2) and (cGov=gDespotism) then i:=2;
if (cGov=gLybertarianism) or Disorder then
i:=0; {no growth}
FillBar(Phrases.Lookup('STORAGE'),xFood+4,yFood+83,c.Food,i,Report.Storage,1);
Sprite(offscreen,HGrSystem,InnerWidth div 2 -2,0,5,3,75,16);
if c.Size>1 then d:=400 div(c.Size-1);
if d>28 then d:=28;
for i:=c.Size-1 downto 0 do
begin
if i<c.Size-Report.Working then xGr:=57+i and 1*28
else if i<c.Size-Report.Working+Report.Happy then xGr:=1+i and 1 *28
else xGr:=113+i and 1 *28; {i and 1=male/female}
BitBlt(offscreen.Canvas.Handle,InnerWidth div 2+1 -(d*(c.Size-1)+27) div 2 +i*d,5,
27,30,GrExt[HGrSystem].Mask.Canvas.Handle,xGr,171{+CityAge*31!!!},SRCAND); {shadow}
Sprite(offscreen,HGrSystem,InnerWidth div 2 -(d*(c.Size-1)+27) div 2 +i*d,4,27,30,xGr,171{+CityAge*31!!!});
end;
if c.Project and cpImp=0 then
PrName:=Tribe[cOwner].ModelName[c.Project and cpIndex]
else PrName:=Phrases.Lookup('IMPROVEMENTS',c.Project and cpIndex);
PrCost:=Report.ProdCost;
CaptionBar(offscreen,xFood,yFood,0,Phrases.Lookup('FOOD'),Report.FoodRep);
CountBar(offscreen,xFood,yFood+19,0,Phrases.Lookup('DEMAND'),Report.Eaten,OuterCityTex);
if Report.FoodRep>=Report.Eaten then
if Disorder then DisorderBar(xFood,yFood+38)
else if (cGov=gLybertarianism)
or (c.Size>=NeedAqueductSize) and (Report.FoodRep<Report.Eaten+2) then
CountBar(offscreen,xFood,yFood+38,6,Phrases.Lookup('PROFIT'),
Report.FoodRep-Report.Eaten,OuterCityTex)
else CountBar(offscreen,xFood,yFood+38,0,Phrases.Lookup('SURPLUS'),
Report.FoodRep-Report.Eaten,OuterCityTex)
else CountBar(offscreen,xFood,yFood+38,1,Phrases.Lookup('LACK'),
Report.Eaten-Report.FoodRep,OuterCityTex);
CaptionBar(offscreen,xProd,yProd,2,Phrases.Lookup('MATERIAL'),Report.ProdRep);
if not Disorder then
CountBar(offscreen,xProd,yProd+19,2,Phrases.Lookup('SUPPORT'),
Report.Support,OuterCityTex);
if Report.ProdRep>=Report.Support then
if Disorder then DisorderBar(xProd,yProd+38)
else if c.Project and (cpImp+cpIndex)=cpImp+imTrGoods then
CountBar(offscreen,xProd,yProd+38,6,Phrases.Lookup('PROFIT'),
Report.ProdRep-Report.Support,OuterCityTex)
else CountBar(offscreen,xProd,yProd+38,2,Phrases.Lookup('PROD'),
Report.ProdRep-Report.Support,OuterCityTex)
else CountBar(offscreen,xProd,yProd+38,3,Phrases.Lookup('LACK'),
Report.Support-Report.ProdRep,OuterCityTex);
if Report.Trade>0 then
begin
CaptionBar(offscreen,xTrade,yTrade,4,Phrases.Lookup('TRADE'),Report.Trade);
CountBar(offscreen,xTrade,yTrade+19,5,Phrases.Lookup('CORR'),Report.Corruption,OuterCityTex);
if Disorder then DisorderBar(xTrade,yTrade+48)
else
begin
CountBar(offscreen,xTrade,yTrade+57,12,Phrases.Lookup('SCIENCE'),Report.Science,OuterCityTex);
CountBar(offscreen,xTrade,yTrade+38,6,Phrases.Lookup('TAX'),Report.Tax,OuterCityTex);
end;
CountBar(offscreen,xTrade,yTrade+76,8,Phrases.Lookup('LUX'),Report.Lux,OuterCityTex);
end;
if (c.Pollution>0) or (Report.PollRep>0) then
begin
CaptionBar(offscreen,xTrade,yTrade+109,-1,Phrases.Lookup('POLL'),Report.PollRep);
FillBar(Phrases.Lookup('DUMP'),xTrade+4,yTrade+148,c.Pollution,Report.PollRep,
MaxPollution,3);
end;
if c.Project and (cpImp+cpIndex)<>cpImp+imTrGoods then with offscreen.Canvas do
begin
if TextWidth(PrName)>171 then
begin
repeat Delete(PrName,Length(PrName),1) until TextWidth(PrName)<=171;
PrName:=PrName+'.'
end;
i:=Report.ProdRep-Report.Support;
if i<0 then i:=0;
if Disorder then i:=0; {disorder}
FillBar(PrName,xProd+4,yProd+83,c.Prod,i,PrCost,4);
end;
for i:=0 to nDisplay-1 do imix[i]:=-1;
Cnt:=0;
if Mode=mImp then
begin
for i:=0 to nImp-1 do if c.Built[ImpSorted[i]]=1 then
begin
i1:=ImpSorted[i];
if (Cnt>=nDisplay*sb.si.npos) and (Cnt<nDisplay*(sb.si.npos+1)) then
begin
imix[Cnt-nDisplay*sb.si.npos]:=i1;
x:=(Cnt-nDisplay*sb.si.npos)*ImpPitch+xImp;
FrameImage(offscreen.Canvas,BigImp,x,yImp+8,xSizeBig,ySizeBig,
i1 mod 7*xSizeBig, (i1+SystemIconLines*7) div 7*ySizeBig,
(cix>=0) and (ClientMode<scContact));
if Imp[i1].Maint>0 then
begin
if Imp[i1].Maint>1 then
begin d:=26 div(Imp[i1].Maint-1);if d>11 then d:=11 end;
for j:=0 to Imp[i1].Maint-1 do
Sprite(offscreen,HGrSystem,x+d*j,yImp+52,10,10,132,115);
end
end;
inc(Cnt);
end;
end
else {if mode=mSupp then}
begin
case cGov of
gAnarchy: FreeSupp:=9999;
gDespotism,gFundamentalism: FreeSupp:=c.Size;
gMonarchy,gCommunism: FreeSupp:=c.Size div 2;
gRepublic,gDemocracy,gLybertarianism: FreeSupp:=0;
end;
for i:=0 to MyRO.nUn-1 do if (MyUn[i].Loc>=0) and (MyUn[i].Home=cix) then
with MyModel[MyUn[i].mix] do
begin
if (Cnt>=nDisplay*sb.si.npos) and (Cnt<nDisplay*(sb.si.npos+1)) then
begin // unit visible in display
imix[Cnt-nDisplay*sb.si.npos]:=i;
x:=(Cnt-nDisplay*sb.si.npos)*64+xSupp;
MakeUnitInfo(me,MyUn[i],UnitInfo);
NoMap.SetOutput(offscreen);
NoMap.PaintUnit(x,ySupp+2,UnitInfo,MyUn[i].Status);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -