Changeset 6
- Timestamp:
- Jan 7, 2017, 11:32:14 AM (9 years ago)
- Location:
- trunk
- Files:
-
- 62 edited
-
Back.pas (modified) (4 diffs)
-
CityProcessing.pas (modified) (5 diffs)
-
CmdList.pas (modified) (6 diffs)
-
Database.pas (modified) (29 diffs)
-
Direct.dfm (modified) ( previous)
-
Direct.pas (modified) (5 diffs)
-
Directories.pas (modified) (3 diffs)
-
GameServer.pas (modified) (7 diffs)
-
Inp.dfm (modified) ( previous)
-
Inp.pas (modified) (3 diffs)
-
Integrated.dpr (modified) (5 diffs)
-
Integrated.dproj (modified) (2 diffs)
-
LocalPlayer/BaseWin.pas (modified) (8 diffs)
-
LocalPlayer/Battle.dfm (modified) ( previous)
-
LocalPlayer/Battle.pas (modified) (8 diffs)
-
LocalPlayer/CityScreen.pas (modified) (15 diffs)
-
LocalPlayer/CityType.dfm (modified) ( previous)
-
LocalPlayer/CityType.pas (modified) (6 diffs)
-
LocalPlayer/ClientTools.pas (modified) (4 diffs)
-
LocalPlayer/Diagram.dfm (modified) ( previous)
-
LocalPlayer/Diagram.pas (modified) (6 diffs)
-
LocalPlayer/Diplomacy.pas (modified) (3 diffs)
-
LocalPlayer/Draft.dfm (modified) ( previous)
-
LocalPlayer/Draft.pas (modified) (11 diffs)
-
LocalPlayer/Enhance.dfm (modified) ( previous)
-
LocalPlayer/Enhance.pas (modified) (5 diffs)
-
LocalPlayer/Help.dfm (modified) ( previous)
-
LocalPlayer/Help.pas (modified) (13 diffs)
-
LocalPlayer/IsoEngine.pas (modified) (3 diffs)
-
LocalPlayer/LocalPlayer.pas (modified) (1 diff)
-
LocalPlayer/MessgEx.dfm (modified) ( previous)
-
LocalPlayer/MessgEx.pas (modified) (7 diffs)
-
LocalPlayer/NatStat.dfm (modified) ( previous)
-
LocalPlayer/NatStat.pas (modified) (10 diffs)
-
LocalPlayer/Nego.dfm (modified) ( previous)
-
LocalPlayer/Nego.pas (modified) (9 diffs)
-
LocalPlayer/PVSB.pas (modified) (4 diffs)
-
LocalPlayer/Rates.dfm (modified) ( previous)
-
LocalPlayer/Rates.pas (modified) (2 diffs)
-
LocalPlayer/Select.dfm (modified) ( previous)
-
LocalPlayer/Select.pas (modified) (15 diffs)
-
LocalPlayer/TechTree.pas (modified) (8 diffs)
-
LocalPlayer/Term.dfm (modified) ( previous)
-
LocalPlayer/Term.pas (modified) (12 diffs)
-
LocalPlayer/Tribes.pas (modified) (3 diffs)
-
LocalPlayer/UnitStat.dfm (modified) ( previous)
-
LocalPlayer/UnitStat.pas (modified) (7 diffs)
-
LocalPlayer/Wonders.dfm (modified) ( previous)
-
LocalPlayer/Wonders.pas (modified) (7 diffs)
-
Log.dfm (modified) ( previous)
-
Log.pas (modified) (6 diffs)
-
Messg.dfm (modified) ( previous)
-
Messg.pas (modified) (9 diffs)
-
NoTerm.dfm (modified) ( previous)
-
NoTerm.pas (modified) (6 diffs)
-
Protocol.pas (modified) (4 diffs)
-
ScreenTools.pas (modified) (13 diffs)
-
Sound.pas (modified) (5 diffs)
-
Start.dfm (modified) ( previous)
-
Start.pas (modified) (15 diffs)
-
StringTables.pas (modified) (3 diffs)
-
UnitProcessing.pas (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Back.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit Back; 4 3 … … 24 23 25 24 uses 26 Directories,ScreenTools,Start;25 Directories, ScreenTools, Start; 27 26 28 27 {$R *.DFM} … … 30 29 procedure TBackground.FormCreate(Sender: TObject); 31 30 begin 32 img:=nil;31 img := nil; 33 32 end; 34 33 35 34 procedure TBackground.FormShow(Sender: TObject); 36 35 begin 37 img:=nil;38 if FullScreen then36 img := nil; 37 if FullScreen then 39 38 begin 40 if FileExists(HomeDir+'Graphics\Background.bmp')41 or FileExists(HomeDir+'Graphics\Background.png') then39 if FileExists(HomeDir + 'Graphics\Background.bmp') or 40 FileExists(HomeDir + 'Graphics\Background.png') then 42 41 begin 43 img:=TBitmap.Create;44 LoadGraphicFile(img, HomeDir+'Graphics\Background');42 img := TBitmap.Create; 43 LoadGraphicFile(img, HomeDir + 'Graphics\Background'); 45 44 end 46 45 end 47 else46 else 48 47 begin 49 WindowState:=wsNormal;50 Width:=StartDlg.Width+16;51 Height:=StartDlg.Height+16;52 Left:=StartDlg.Left-8;53 Top:=StartDlg.Top-8;48 WindowState := wsNormal; 49 Width := StartDlg.Width + 16; 50 Height := StartDlg.Height + 16; 51 Left := StartDlg.Left - 8; 52 Top := StartDlg.Top - 8; 54 53 end 55 54 end; … … 57 56 procedure TBackground.FormPaint(Sender: TObject); 58 57 begin 59 if img<>nil then 60 BitBlt(Canvas.Handle, 61 Screen.Width-img.Width-(Screen.Width-800)*3 div 8, 62 (Screen.Height-600) div 3, 63 img.Width,img.Height, 64 img.Canvas.Handle,0,0,SRCCOPY); 58 if img <> nil then 59 BitBlt(Canvas.Handle, Screen.Width - img.Width - (Screen.Width - 800) * 60 3 div 8, (Screen.Height - 600) div 3, img.Width, img.Height, 61 img.Canvas.Handle, 0, 0, SRCCOPY); 65 62 end; 66 63 67 64 procedure TBackground.FormClose(Sender: TObject; var Action: TCloseAction); 68 65 begin 69 if img<>nil then begin img.Free; img:=nil end; 66 if img <> nil then 67 begin 68 img.Free; 69 img := nil 70 end; 70 71 end; 71 72 72 73 end. 73 -
trunk/CityProcessing.pas
r2 r6 5 5 6 6 uses 7 Protocol, Database;7 Protocol, Database; 8 8 9 9 // Reporting 10 procedure GetCityAreaInfo(p,Loc: integer; var CityAreaInfo: TCityAreaInfo); 11 function CanCityGrow(p,cix: integer): boolean; 12 function GetCityReport(p,cix: integer; var CityReport: TCityReport): integer; 13 function GetCityReportNew(p,cix: integer; var CityReportNew: TCityReportNew): integer; 10 procedure GetCityAreaInfo(p, Loc: integer; var CityAreaInfo: TCityAreaInfo); 11 function CanCityGrow(p, cix: integer): boolean; 12 function GetCityReport(p, cix: integer; var CityReport: TCityReport): integer; 13 function GetCityReportNew(p, cix: integer; 14 var CityReportNew: TCityReportNew): integer; 14 15 15 16 // Internal Tile Picking 16 function AddBestCityTile(p, cix: integer): boolean;17 procedure CityGrowth(p, cix: integer);18 procedure CityShrink(p, cix: integer);19 procedure Pollute(p, cix: integer);17 function AddBestCityTile(p, cix: integer): boolean; 18 procedure CityGrowth(p, cix: integer); 19 procedure CityShrink(p, cix: integer); 20 procedure Pollute(p, cix: integer); 20 21 21 22 // Turn Processing 22 procedure PayCityMaintenance(p, cix: integer);23 procedure CollectCityResources(p, cix: integer);24 function CityTurn(p, cix: integer): boolean;23 procedure PayCityMaintenance(p, cix: integer); 24 procedure CollectCityResources(p, cix: integer); 25 function CityTurn(p, cix: integer): boolean; 25 26 26 27 // Tile Access 27 function SetCityTiles(p, cix, NewTiles: integer; TestOnly: boolean = false): integer; 28 function SetCityTiles(p, cix, NewTiles: integer; 29 TestOnly: boolean = false): integer; 28 30 procedure GetCityTileAdvice(p, cix: integer; var Advice: TCityTileAdviceData); 29 31 … … 32 34 procedure ReleaseGame; 33 35 34 35 36 implementation 36 37 37 38 type 38 TTradeProcessing=record 39 TaxBonus,LuxBonus,ScienceBonus,FutResBonus,ScienceDoubling,HappyBase: integer; 40 RelCorr: single; 41 FlexibleLuxury: boolean; 39 TTradeProcessing = record 40 TaxBonus, LuxBonus, ScienceBonus, FutResBonus, ScienceDoubling, 41 HappyBase: integer; 42 RelCorr: single; 43 FlexibleLuxury: boolean; 42 44 end; 43 45 44 TProdProcessing=record45 ProdBonus,PollBonus,FutProdBonus,PollThreshold: integer;46 TProdProcessing = record 47 ProdBonus, PollBonus, FutProdBonus, PollThreshold: integer; 46 48 end; 47 49 48 PCityReportEx=^TCityReportEx; 49 TCityReportEx=record 50 BaseHappiness,BaseControl,Material: integer; 50 PCityReportEx = ^TCityReportEx; 51 52 TCityReportEx = record 53 BaseHappiness, BaseControl, Material: integer; 54 ProdProcessing: TProdProcessing; 55 TradeProcessing: TTradeProcessing; 56 end; 57 58 var 59 MaxDist: integer; 60 61 { 62 Reporting 63 ____________________________________________________________________ 64 } 65 procedure GetCityAreaInfo(p, Loc: integer; var CityAreaInfo: TCityAreaInfo); 66 var 67 V21, Loc1, p1: integer; 68 Radius: TVicinity21Loc; 69 begin 70 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap = 0); {$ENDIF} 71 with CityAreaInfo do 72 begin 73 V21_to_Loc(Loc, Radius); 74 for V21 := 0 to 26 do 75 begin 76 Loc1 := Radius[V21]; 77 if (Loc1 < 0) or (Loc1 >= MapSize) then 78 Available[V21] := faInvalid 79 else 80 begin 81 p1 := RealMap[Loc1] shr 27; 82 if (p1 < nPl) and (p1 <> p) and (RW[p].Treaty[p1] >= trPeace) then 83 Available[V21] := faTreaty 84 else if (ZoCMap[Loc1] > 0) and (Occupant[Loc1] <> p) and 85 (RW[p].Treaty[Occupant[Loc1]] < trAlliance) then 86 Available[V21] := faSiege 87 else if (UsedByCity[Loc1] <> -1) and (UsedByCity[Loc1] <> Loc) then 88 Available[V21] := faNotAvailable 89 else 90 Available[V21] := faAvailable 91 end 92 end; 93 end 94 end; 95 96 function CanCityGrow(p, cix: integer): boolean; 97 begin 98 with RW[p].City[cix] do 99 result := (Size < MaxCitySize) and 100 ((Size < NeedAqueductSize) or (Built[imAqueduct] = 1) and 101 (Size < NeedSewerSize) or (Built[imSewer] = 1)); 102 end; 103 104 procedure DetermineCityProdProcessing(p, cix: integer; 105 var ProdProcessing: TProdProcessing); 106 begin 107 with RW[p].City[cix], ProdProcessing do 108 begin 109 ProdBonus := 0; 110 PollBonus := 0; 111 if Built[imFactory] = 1 then 112 inc(ProdBonus); 113 if Built[imMfgPlant] = 1 then 114 inc(ProdBonus); 115 if (Built[imPower] = 1) or (Built[imHydro] = 1) or (Built[imNuclear] = 1) or 116 (GWonder[woHoover].EffectiveOwner = p) then 117 ProdBonus := ProdBonus * 2; 118 if Built[imFactory] = 1 then 119 inc(PollBonus); 120 if Built[imMfgPlant] = 1 then 121 inc(PollBonus); 122 if (Built[imFactory] + Built[imMfgPlant] > 0) then 123 if (Built[imHydro] > 0) or (GWonder[woHoover].EffectiveOwner = p) then 124 dec(PollBonus) 125 else if (Built[imNuclear] = 0) and (Built[imPower] = 1) then 126 inc(PollBonus); 127 if (RW[p].Government <= gDespotism) or (Built[imRecycling] = 1) then 128 PollBonus := -2; // no pollution 129 PollThreshold := Size; 130 FutProdBonus := 0; 131 if RW[p].Tech[futProductionTechnology] > 0 then 132 begin // future tech benefits 133 if Built[imFactory] = 1 then 134 inc(FutProdBonus, FactoryFutureBonus * RW[p].Tech 135 [futProductionTechnology]); 136 if Built[imMfgPlant] = 1 then 137 inc(FutProdBonus, MfgPlantFutureBonus * RW[p].Tech 138 [futProductionTechnology]); 139 end; 140 end; 141 end; 142 143 procedure BoostProd(BaseProd: integer; ProdProcessing: TProdProcessing; 144 var Prod, Poll: integer); 145 begin 146 Poll := BaseProd * (2 + ProdProcessing.PollBonus) shr 1; 147 if Poll <= ProdProcessing.PollThreshold then 148 Poll := 0 149 else 150 dec(Poll, ProdProcessing.PollThreshold); 151 if ProdProcessing.FutProdBonus > 0 then 152 Prod := BaseProd * (100 + ProdProcessing.ProdBonus * 50 + 153 ProdProcessing.FutProdBonus) div 100 154 else 155 Prod := BaseProd * (2 + ProdProcessing.ProdBonus) shr 1; 156 end; 157 158 procedure DetermineCityTradeProcessing(p, cix, HappinessBeforeLux: integer; 159 var TradeProcessing: TTradeProcessing); 160 var 161 i, Dist: integer; 162 begin 163 with RW[p].City[cix], TradeProcessing do 164 begin 165 TaxBonus := 0; 166 ScienceBonus := 0; 167 if Built[imMarket] = 1 then 168 inc(TaxBonus, 2); 169 if Built[imBank] = 1 then 170 begin 171 inc(TaxBonus, 3); 172 if RW[p].NatBuilt[imStockEx] = 1 then 173 inc(TaxBonus, 3); 174 end; 175 LuxBonus := TaxBonus; 176 if Built[imLibrary] = 1 then 177 inc(ScienceBonus, 2); 178 if Built[imUniversity] = 1 then 179 inc(ScienceBonus, 3); 180 if Built[imResLab] = 1 then 181 inc(ScienceBonus, 3); 182 ScienceDoubling := 0; 183 if Built[imNatObs] > 0 then 184 inc(ScienceDoubling); 185 if RW[p].Government = gFundamentalism then 186 dec(ScienceDoubling) 187 else if (GWonder[woNewton].EffectiveOwner = p) and 188 (RW[p].Government = gMonarchy) then 189 inc(ScienceDoubling); 190 FlexibleLuxury := ((ServerVersion[p] >= $0100F1) and 191 (GWonder[woLiberty].EffectiveOwner = p) or (ServerVersion[p] < $0100F1) 192 and (GWonder[woMich].EffectiveOwner = p)) and 193 (RW[p].Government <> gAnarchy); 194 FutResBonus := 0; 195 if RW[p].Tech[futResearchTechnology] > 0 then 196 begin // future tech benefits 197 if Built[imUniversity] = 1 then 198 inc(FutResBonus, UniversityFutureBonus * RW[p].Tech 199 [futResearchTechnology]); 200 if Built[imResLab] = 1 then 201 inc(FutResBonus, ResLabFutureBonus * RW[p].Tech[futResearchTechnology]); 202 end; 203 if (RW[p].NatBuilt[imPalace] > 0) or (ServerVersion[p] < $010000) then 204 begin // calculate corruption 205 Dist := MaxDist; 206 for i := 0 to RW[p].nCity - 1 do 207 if (RW[p].City[i].Loc >= 0) and (RW[p].City[i].Built[imPalace] = 1) then 208 Dist := Distance(Loc, RW[p].City[i].Loc); 209 if (Dist = 0) or (CorrLevel[RW[p].Government] = 0) then 210 RelCorr := 0.0 211 else 212 begin 213 RelCorr := Dist / MaxDist; 214 if CorrLevel[RW[p].Government] > 1 then 215 RelCorr := Exp(ln(RelCorr) / CorrLevel[RW[p].Government]); 216 if Built[imCourt] = 1 then 217 RelCorr := RelCorr / 2; 218 // !!! floating point calculation always deterministic??? 219 end 220 end 221 else if Built[imCourt] = 1 then 222 RelCorr := 0.5 223 else 224 RelCorr := 1.0; 225 HappyBase := Size + HappinessBeforeLux; 226 end 227 end; 228 229 procedure SplitTrade(Trade, TaxRate, LuxRate, Working: integer; 230 TradeProcessing: TTradeProcessing; var Corruption, Tax, Lux, 231 Science: integer); 232 var 233 plus: integer; 234 begin 235 Corruption := Trunc(Trade * TradeProcessing.RelCorr); 236 Tax := (TaxRate * (Trade - Corruption) + 50) div 100; 237 if TradeProcessing.FlexibleLuxury then 238 begin 239 plus := Working * 2 - TradeProcessing.HappyBase; 240 // required additional luxury 241 if plus > 0 then 242 begin 243 Lux := (4 * plus + 3 + TradeProcessing.LuxBonus) 244 div (4 + TradeProcessing.LuxBonus); 245 if Lux > Trade - Corruption then 246 Lux := Trade - Corruption; 247 if Tax > Trade - Corruption - Lux then 248 Tax := Trade - Corruption - Lux; 249 end 250 else 251 Lux := 0; 252 end 253 else if (LuxRate = 0) or (TaxRate = 100) then 254 Lux := 0 255 else 256 Lux := (LuxRate * (Trade - Corruption) + 49) div 100; 257 Science := Trade - Corruption - Lux - Tax; 258 Tax := Tax * (4 + TradeProcessing.TaxBonus) shr 2; 259 Lux := Lux * (4 + TradeProcessing.LuxBonus) shr 2; 260 if TradeProcessing.FutResBonus > 0 then 261 Science := Science * (100 + TradeProcessing.ScienceBonus * 25 + 262 TradeProcessing.FutResBonus) div 100 263 else 264 Science := Science * (4 + TradeProcessing.ScienceBonus) shr 2; 265 Science := Science shl 2 shr (2 - TradeProcessing.ScienceDoubling); 266 end; 267 268 function GetProjectCost(p, cix: integer): integer; 269 var 270 i: integer; 271 begin 272 with RW[p].City[cix] do 273 begin 274 if Project and cpImp = 0 then 275 begin 276 result := RW[p].Model[Project and cpIndex].Cost; { unit project } 277 if Project and cpConscripts <> 0 then 278 begin 279 i := RW[p].Model[Project and cpIndex].MCost; 280 result := result - 3 * i; 281 if result <= 0 then 282 result := i 283 end 284 else if RW[p].Model[Project and cpIndex].Cap[mcLine] > 0 then 285 if Project0 and (not cpAuto or cpRepeat) = Project and not cpAuto or cpRepeat 286 then 287 result := result shr 1 288 else 289 result := result * 2 290 end 291 else 292 begin { improvement project } 293 result := Imp[Project and cpIndex].Cost; 294 if (Project and cpIndex < 28) and (GWonder[woColossus].EffectiveOwner = p) 295 then 296 result := result * ColossusEffect div 100; 297 end; 298 result := result * BuildCostMod[Difficulty[p]] div 12; 299 end 300 end; 301 302 function GetSmallCityReport(p, cix: integer; var CityReport: TCityReport; 303 PCityReportEx: PCityReportEx = nil): integer; 304 var 305 i, uix, V21, Loc1, ForcedSupport, BaseHappiness, Control: integer; 51 306 ProdProcessing: TProdProcessing; 52 307 TradeProcessing: TTradeProcessing; 308 Radius: TVicinity21Loc; 309 UnitReport: TUnitReport; 310 RareOK: array [0 .. 3] of integer; 311 TileInfo: TTileInfo; 312 begin 313 with RW[p].City[cix], CityReport do 314 begin 315 if HypoTiles <= 0 then 316 HypoTiles := Tiles; 317 if HypoTax < 0 then 318 HypoTax := RW[p].TaxRate; 319 if HypoLux < 0 then 320 HypoLux := RW[p].LuxRate; 321 322 if (Flags and chCaptured <> 0) or (RW[p].Government = gAnarchy) then 323 begin 324 Working := 0; 325 for V21 := 1 to 26 do 326 if HypoTiles and (1 shl V21) <> 0 then 327 inc(Working); // for backward compatibility 328 329 if RW[p].Government = gFundamentalism then 330 begin 331 Happy := Size; 332 Control := Size 333 end // !!! old bug, kept for compatibility 334 else 335 begin 336 Happy := 0; 337 Control := 0 338 end; 339 340 BaseHappiness := BasicHappy * 2; 341 Support := 0; 342 Deployed := 0; 343 Eaten := Size * 2; 344 FoodRep := Size * 2; 345 ProdRep := 0; 346 Trade := 0; 347 PollRep := 0; 348 Corruption := 0; 349 Tax := 0; 350 Lux := 0; 351 Science := 0; 352 353 if PCityReportEx <> nil then 354 begin 355 PCityReportEx.Material := ProdRep; 356 PCityReportEx.BaseHappiness := BaseHappiness; 357 PCityReportEx.BaseControl := Control; 358 end; 359 end 360 else // not captured, no anarchy 361 begin 362 Control := 0; 363 BaseHappiness := BasicHappy * 2; 364 Happy := BasicHappy; 365 if (Built[imColosseum] > 0) then 366 begin 367 if (Happy < (Size + 1) shr 1) then 368 Happy := (Size + 1) shr 1; 369 if Size > 4 then 370 BaseHappiness := Size; 371 end; 372 for i := 0 to 27 do 373 if Built[i] = 1 then 374 begin 375 inc(Happy); 376 inc(BaseHappiness, 2) 377 end; 378 if Built[imTemple] = 1 then 379 begin 380 inc(Happy); 381 inc(BaseHappiness, 2) 382 end; 383 if Built[imCathedral] = 1 then 384 begin 385 inc(Happy, 2); 386 inc(BaseHappiness, 4); 387 if GWonder[woBach].EffectiveOwner = p then 388 begin 389 inc(Happy); 390 inc(BaseHappiness, 2) 391 end; 392 end; 393 if Built[imTheater] > 0 then 394 begin 395 inc(Happy, 2); 396 inc(BaseHappiness, 4) 397 end; 398 399 // calculate unit support 400 {$IFOPT O-}assert(InvalidTreatyMap = 0); {$ENDIF} 401 Support := 0; 402 ForcedSupport := 0; 403 Eaten := Size * 2; 404 Deployed := 0; 405 for uix := 0 to RW[p].nUn - 1 do 406 with RW[p].Un[uix] do 407 if (Loc >= 0) and (Home = cix) then 408 begin 409 GetUnitReport(p, uix, UnitReport); 410 inc(Eaten, UnitReport.FoodSupport); 411 if UnitReport.ReportFlags and urfAlwaysSupport <> 0 then 412 inc(ForcedSupport, UnitReport.ProdSupport) 413 else 414 inc(Support, UnitReport.ProdSupport); 415 if UnitReport.ReportFlags and urfDeployed <> 0 then 416 inc(Deployed); 417 end; 418 if Deployed >= Happy then 419 Happy := 0 420 else 421 dec(Happy, Deployed); 422 dec(Support, Size * SupportFree[RW[p].Government] shr 1); 423 if Support < 0 then 424 Support := 0; 425 inc(Support, ForcedSupport); 426 427 { control } 428 case RW[p].Government of 429 gDespotism: 430 for uix := 0 to RW[p].nUn - 1 do 431 if (RW[p].Un[uix].Loc = Loc) and 432 (RW[p].Model[RW[p].Un[uix].mix].Kind = mkSpecial_TownGuard) then 433 begin 434 inc(Happy); 435 inc(Control, 2) 436 end; 437 gFundamentalism: 438 begin 439 BaseHappiness := 0; // done by control 440 Happy := Size; 441 Control := Size 442 end; 443 end; 444 445 // collect processing parameters 446 DetermineCityProdProcessing(p, cix, ProdProcessing); 447 DetermineCityTradeProcessing(p, cix, BaseHappiness + Control - 2 * 448 Deployed, TradeProcessing); 449 450 // collect resources 451 Working := 0; 452 FoodRep := 0; 453 ProdRep := 0; 454 Trade := 0; 455 FillChar(RareOK, SizeOf(RareOK), 0); 456 V21_to_Loc(Loc, Radius); 457 for V21 := 1 to 26 do 458 if HypoTiles and (1 shl V21) <> 0 then 459 begin { sum resources of exploited tiles } 460 Loc1 := Radius[V21]; 461 if (Loc1 < 0) or (Loc1 >= MapSize) then 462 // HypoTiles go beyond map border! 463 begin 464 result := eInvalid; 465 exit 466 end; 467 GetTileInfo(p, cix, Loc1, TileInfo); 468 inc(FoodRep, TileInfo.Food); 469 inc(ProdRep, TileInfo.Prod); 470 inc(Trade, TileInfo.Trade); 471 if (RealMap[Loc1] and fModern <> 0) and 472 (RW[p].Tech[adMassProduction] >= tsApplicable) then 473 inc(RareOK[RealMap[Loc1] shr 25 and 3]); 474 inc(Working) 475 end; 476 if Built[imAlgae] = 1 then 477 inc(FoodRep, 12); 478 479 if PCityReportEx <> nil then 480 begin 481 PCityReportEx.Material := ProdRep; 482 PCityReportEx.BaseHappiness := BaseHappiness; 483 PCityReportEx.BaseControl := Control; 484 PCityReportEx.ProdProcessing := ProdProcessing; 485 PCityReportEx.TradeProcessing := TradeProcessing; 486 end; 487 488 BoostProd(ProdRep, ProdProcessing, ProdRep, PollRep); 489 SplitTrade(Trade, HypoTax, HypoLux, Working, TradeProcessing, Corruption, 490 Tax, Lux, Science); 491 Happy := Happy + (Lux + Size and 1) shr 1; 492 // new style disorder requires 1 lux less for cities with odd size 493 494 // check if rare resource available 495 if (GTestFlags and tfNoRareNeed = 0) and (ProdRep > Support) and 496 (Project and cpImp <> 0) and ((Project and cpIndex = imShipComp) and 497 (RareOK[1] = 0) or (Project and cpIndex = imShipPow) and (RareOK[2] = 0) 498 or (Project and cpIndex = imShipHab) and (RareOK[3] = 0)) then 499 ProdRep := Support; 500 end; 53 501 end; 54 55 var 56 MaxDist: integer; 502 result := eOk; 503 end; { GetSmallCityReport } 504 505 function GetCityReport(p, cix: integer; var CityReport: TCityReport): integer; 506 begin 507 result := GetSmallCityReport(p, cix, CityReport); 508 CityReport.Storage := StorageSize[Difficulty[p]]; 509 CityReport.ProdCost := GetProjectCost(p, cix); 510 end; 511 512 function GetCityReportNew(p, cix: integer; 513 var CityReportNew: TCityReportNew): integer; 514 var 515 CityReport: TCityReport; 516 CityReportEx: TCityReportEx; 517 begin 518 with CityReportNew do 519 begin 520 CityReport.HypoTiles := HypoTiles; 521 CityReport.HypoTax := HypoTaxRate; 522 CityReport.HypoLux := HypoLuxuryRate; 523 result := GetSmallCityReport(p, cix, CityReport, @CityReportEx); 524 FoodSupport := CityReport.Eaten - 2 * RW[p].City[cix].Size; 525 MaterialSupport := CityReport.Support; 526 ProjectCost := GetProjectCost(p, cix); 527 Storage := StorageSize[Difficulty[p]]; 528 Deployed := CityReport.Deployed; 529 Morale := CityReportEx.BaseHappiness; 530 CollectedControl := CityReportEx.BaseControl + 531 (RW[p].City[cix].Size - CityReport.Working) * 2; 532 CollectedFood := CityReport.FoodRep; 533 CollectedMaterial := CityReportEx.Material; 534 CollectedTrade := CityReport.Trade; 535 Working := CityReport.Working; 536 Production := CityReport.ProdRep - CityReport.Support; 537 AddPollution := CityReport.PollRep; 538 Corruption := CityReport.Corruption; 539 Tax := CityReport.Tax; 540 Science := CityReport.Science; 541 Luxury := CityReport.Lux; 542 FoodSurplus := CityReport.FoodRep - CityReport.Eaten; 543 HappinessBalance := Morale + Luxury + CollectedControl - RW[p].City[cix] 544 .Size - 2 * Deployed; 545 end; 546 end; 57 547 58 548 { 59 Reporting60 ____________________________________________________________________549 Internal Tile Picking 550 ____________________________________________________________________ 61 551 } 62 procedure GetCityAreaInfo(p,Loc: integer; var CityAreaInfo: TCityAreaInfo); 63 var 64 V21, Loc1, p1: integer; 65 Radius: TVicinity21Loc; 66 begin 67 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap=0);{$ENDIF} 68 with CityAreaInfo do 552 procedure NextBest(p, cix: integer; var SelectedLoc, SelectedV21: integer); 553 { best tile unused but available by city cix } 554 var 555 Resources, Most, Loc1, p1, V21: integer; 556 TileInfo: TTileInfo; 557 Radius: TVicinity21Loc; 558 begin 559 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap = 0); {$ENDIF} 560 Most := 0; 561 SelectedLoc := -1; 562 SelectedV21 := -1; 563 with RW[p].City[cix] do 69 564 begin 70 V21_to_Loc(Loc,Radius); 71 for V21:=0 to 26 do 72 begin 73 Loc1:=Radius[V21]; 74 if (Loc1<0) or (Loc1>=MapSize) then Available[V21]:=faInvalid 75 else 76 begin 77 p1:=RealMap[Loc1] shr 27; 78 if (p1<nPl) and (p1<>p) and (RW[p].Treaty[p1]>=trPeace) then 79 Available[V21]:=faTreaty 80 else if (ZoCMap[Loc1]>0) and (Occupant[Loc1]<>p) 81 and (RW[p].Treaty[Occupant[Loc1]]<trAlliance) then 82 Available[V21]:=faSiege 83 else if (UsedByCity[Loc1]<>-1) and (UsedByCity[Loc1]<>Loc) then 84 Available[V21]:=faNotAvailable 85 else Available[V21]:=faAvailable 86 end 87 end; 88 end 89 end; 90 91 function CanCityGrow(p,cix: integer): boolean; 92 begin 93 with RW[p].City[cix] do 94 result:= (Size<MaxCitySize) and ((Size<NeedAqueductSize) 95 or (Built[imAqueduct]=1) and (Size<NeedSewerSize) 96 or (Built[imSewer]=1)); 97 end; 98 99 procedure DetermineCityProdProcessing(p,cix: integer; 100 var ProdProcessing: TProdProcessing); 101 begin 102 with RW[p].City[cix],ProdProcessing do 103 begin 104 ProdBonus:=0; 105 PollBonus:=0; 106 if Built[imFactory]=1 then 107 inc(ProdBonus); 108 if Built[imMfgPlant]=1 then 109 inc(ProdBonus); 110 if (Built[imPower]=1) or (Built[imHydro]=1) 111 or (Built[imNuclear]=1) or (GWonder[woHoover].EffectiveOwner=p) then 112 ProdBonus:=ProdBonus*2; 113 if Built[imFactory]=1 then 114 inc(PollBonus); 115 if Built[imMfgPlant]=1 then 116 inc(PollBonus); 117 if (Built[imFactory]+Built[imMfgPlant]>0) then 118 if (Built[imHydro]>0) 119 or (GWonder[woHoover].EffectiveOwner=p) then 120 dec(PollBonus) 121 else if (Built[imNuclear]=0) and (Built[imPower]=1) then 122 inc(PollBonus); 123 if (RW[p].Government<=gDespotism) or (Built[imRecycling]=1) then 124 PollBonus:=-2; // no pollution 125 PollThreshold:=Size; 126 FutProdBonus:=0; 127 if RW[p].Tech[futProductionTechnology]>0 then 128 begin // future tech benefits 129 if Built[imFactory]=1 then 130 inc(FutProdBonus,FactoryFutureBonus*RW[p].Tech[futProductionTechnology]); 131 if Built[imMfgPlant]=1 then 132 inc(FutProdBonus,MfgPlantFutureBonus*RW[p].Tech[futProductionTechnology]); 133 end; 134 end; 135 end; 136 137 procedure BoostProd(BaseProd: integer; ProdProcessing: TProdProcessing; 138 var Prod,Poll: integer); 139 begin 140 Poll:=BaseProd*(2+ProdProcessing.PollBonus) shr 1; 141 if Poll<=ProdProcessing.PollThreshold then 142 Poll:=0 143 else dec(Poll,ProdProcessing.PollThreshold); 144 if ProdProcessing.FutProdBonus>0 then 145 Prod:=BaseProd*(100+ProdProcessing.ProdBonus*50+ProdProcessing.FutProdBonus) div 100 146 else Prod:=BaseProd*(2+ProdProcessing.ProdBonus) shr 1; 147 end; 148 149 procedure DetermineCityTradeProcessing(p,cix,HappinessBeforeLux: integer; 150 var TradeProcessing: TTradeProcessing); 151 var 152 i,Dist: integer; 153 begin 154 with RW[p].City[cix],TradeProcessing do 155 begin 156 TaxBonus:=0; 157 ScienceBonus:=0; 158 if Built[imMarket]=1 then 159 inc(TaxBonus,2); 160 if Built[imBank]=1 then 161 begin 162 inc(TaxBonus,3); 163 if RW[p].NatBuilt[imStockEx]=1 then 164 inc(TaxBonus,3); 165 end; 166 LuxBonus:=TaxBonus; 167 if Built[imLibrary]=1 then 168 inc(ScienceBonus,2); 169 if Built[imUniversity]=1 then 170 inc(ScienceBonus,3); 171 if Built[imResLab]=1 then 172 inc(ScienceBonus,3); 173 ScienceDoubling:=0; 174 if Built[imNatObs]>0 then 175 inc(ScienceDoubling); 176 if RW[p].Government=gFundamentalism then 177 dec(ScienceDoubling) 178 else if (GWonder[woNewton].EffectiveOwner=p) and (RW[p].Government=gMonarchy) then 179 inc(ScienceDoubling); 180 FlexibleLuxury:= 181 ((ServerVersion[p]>=$0100F1) and (GWonder[woLiberty].EffectiveOwner=p) 182 or (ServerVersion[p]<$0100F1) and (GWonder[woMich].EffectiveOwner=p)) 183 and (RW[p].Government<>gAnarchy); 184 FutResBonus:=0; 185 if RW[p].Tech[futResearchTechnology]>0 then 186 begin // future tech benefits 187 if Built[imUniversity]=1 then 188 inc(FutResBonus,UniversityFutureBonus*RW[p].Tech[futResearchTechnology]); 189 if Built[imResLab]=1 then 190 inc(FutResBonus,ResLabFutureBonus*RW[p].Tech[futResearchTechnology]); 191 end; 192 if (RW[p].NatBuilt[imPalace]>0) or (ServerVersion[p]<$010000) then 193 begin // calculate corruption 194 Dist:=MaxDist; 195 for i:=0 to RW[p].nCity-1 do 196 if (RW[p].City[i].Loc>=0) and (RW[p].City[i].Built[imPalace]=1) then 197 Dist:=Distance(Loc,RW[p].City[i].Loc); 198 if (Dist=0) or (CorrLevel[RW[p].Government]=0) then 199 RelCorr:=0.0 200 else 201 begin 202 RelCorr:=Dist/MaxDist; 203 if CorrLevel[RW[p].Government]>1 then 204 RelCorr:= 205 Exp(ln(RelCorr)/CorrLevel[RW[p].Government]); 206 if Built[imCourt]=1 then 207 RelCorr:=RelCorr/2; 208 // !!! floating point calculation always deterministic??? 209 end 210 end 211 else if Built[imCourt]=1 then 212 RelCorr:=0.5 213 else RelCorr:=1.0; 214 HappyBase:=Size+HappinessBeforeLux; 215 end 216 end; 217 218 procedure SplitTrade(Trade,TaxRate,LuxRate,Working: integer; 219 TradeProcessing :TTradeProcessing; var Corruption,Tax,Lux,Science: integer); 220 var 221 plus: integer; 222 begin 223 Corruption:=Trunc(Trade*TradeProcessing.RelCorr); 224 Tax:=(TaxRate*(Trade-Corruption)+50) div 100; 225 if TradeProcessing.FlexibleLuxury then 226 begin 227 plus:=Working*2-TradeProcessing.HappyBase; // required additional luxury 228 if plus>0 then 229 begin 230 Lux:=(4*plus +3+TradeProcessing.LuxBonus) div (4+TradeProcessing.LuxBonus); 231 if Lux>Trade-Corruption then Lux:=Trade-Corruption; 232 if Tax>Trade-Corruption-Lux then Tax:=Trade-Corruption-Lux; 233 end 234 else Lux:=0; 235 end 236 else if (LuxRate=0) or (TaxRate=100) then Lux:=0 237 else Lux:=(LuxRate*(Trade-Corruption)+49) div 100; 238 Science:=Trade-Corruption-Lux-Tax; 239 Tax:=Tax*(4+TradeProcessing.TaxBonus) shr 2; 240 Lux:=Lux*(4+TradeProcessing.LuxBonus) shr 2; 241 if TradeProcessing.FutResBonus>0 then 242 Science:=Science*(100+TradeProcessing.ScienceBonus*25+TradeProcessing.FutResBonus) div 100 243 else Science:=Science*(4+TradeProcessing.ScienceBonus) shr 2; 244 Science:=Science shl 2 shr (2-TradeProcessing.ScienceDoubling); 245 end; 246 247 function GetProjectCost(p,cix: integer): integer; 248 var 249 i: integer; 250 begin 251 with RW[p].City[cix] do 252 begin 253 if Project and cpImp=0 then 254 begin 255 result:=RW[p].Model[Project and cpIndex].Cost; {unit project} 256 if Project and cpConscripts<>0 then 257 begin 258 i:=RW[p].Model[Project and cpIndex].MCost; 259 result:=result-3*i; 260 if result<=0 then result:=i 261 end 262 else if RW[p].Model[Project and cpIndex].Cap[mcLine]>0 then 263 if Project0 and (not cpAuto or cpRepeat)=Project and not cpAuto or cpRepeat then 264 result:=result shr 1 265 else result:=result*2 266 end 267 else 268 begin {improvement project} 269 result:=Imp[Project and cpIndex].Cost; 270 if (Project and cpIndex<28) and (GWonder[woColossus].EffectiveOwner=p) then 271 result:=result*ColossusEffect div 100; 272 end; 273 result:=result*BuildCostMod[Difficulty[p]] div 12; 274 end 275 end; 276 277 function GetSmallCityReport(p,cix: integer; var CityReport: TCityReport; 278 pCityReportEx: PCityReportEx = nil): integer; 279 var 280 i,uix,V21,Loc1,ForcedSupport,BaseHappiness,Control: integer; 281 ProdProcessing: TProdProcessing; 282 TradeProcessing: TTradeProcessing; 283 Radius: TVicinity21Loc; 284 UnitReport: TUnitReport; 285 RareOK: array[0..3] of integer; 286 TileInfo:TTileInfo; 287 begin 288 with RW[p].City[cix], CityReport do 289 begin 290 if HypoTiles<=0 then HypoTiles:=Tiles; 291 if HypoTax<0 then HypoTax:=RW[p].TaxRate; 292 if HypoLux<0 then HypoLux:=RW[p].LuxRate; 293 294 if (Flags and chCaptured<>0) or (RW[p].Government=gAnarchy) then 295 begin 296 Working:=0; 297 for V21:=1 to 26 do if HypoTiles and (1 shl V21)<>0 then 298 inc(Working); // for backward compatibility 299 300 if RW[p].Government=gFundamentalism then 301 begin Happy:=Size; Control:=Size end // !!! old bug, kept for compatibility 302 else begin Happy:=0; Control:=0 end; 303 304 BaseHappiness:=BasicHappy*2; 305 Support:=0; 306 Deployed:=0; 307 Eaten:=Size*2; 308 FoodRep:=Size*2; 309 ProdRep:=0; 310 Trade:=0; 311 PollRep:=0; 312 Corruption:=0; 313 Tax:=0; 314 Lux:=0; 315 Science:=0; 316 317 if pCityReportEx<>nil then 318 begin 319 pCityReportEx.Material:=ProdRep; 320 pCityReportEx.BaseHappiness:=BaseHappiness; 321 pCityReportEx.BaseControl:=Control; 322 end; 323 end 324 else // not captured, no anarchy 325 begin 326 Control:=0; 327 BaseHappiness:=BasicHappy*2; 328 Happy:=BasicHappy; 329 if (Built[imColosseum]>0) then 330 begin 331 if (Happy<(Size+1) shr 1) then 332 Happy:=(Size+1) shr 1; 333 if Size>4 then 334 BaseHappiness:=Size; 335 end; 336 for i:=0 to 27 do if Built[i]=1 then 337 begin inc(Happy); inc(BaseHappiness,2) end; 338 if Built[imTemple]=1 then 339 begin inc(Happy); inc(BaseHappiness,2) end; 340 if Built[imCathedral]=1 then 341 begin 342 inc(Happy,2); inc(BaseHappiness,4); 343 if GWonder[woBach].EffectiveOwner=p then 344 begin inc(Happy); inc(BaseHappiness,2) end; 345 end; 346 if Built[imTheater]>0 then 347 begin inc(Happy,2); inc(BaseHappiness,4) end; 348 349 // calculate unit support 350 {$IFOPT O-}assert(InvalidTreatyMap=0);{$ENDIF} 351 Support:=0; ForcedSupport:=0; Eaten:=Size*2; Deployed:=0; 352 for uix:=0 to RW[p].nUn-1 do with RW[p].Un[uix] do 353 if (Loc>=0) and (Home=cix) then 565 V21_to_Loc(Loc, Radius); 566 for V21 := 1 to 26 do 567 begin 568 Loc1 := Radius[V21]; 569 if (Loc1 >= 0) and (Loc1 < MapSize) and (UsedByCity[Loc1] = -1) then 570 begin 571 p1 := RealMap[Loc1] shr 27; 572 if ((p1 = nPl) or (p1 = p) or (RW[p].Treaty[p1] < trPeace)) and 573 ((ZoCMap[Loc1] = 0) or (Occupant[Loc1] = p) or 574 (RW[p].Treaty[Occupant[Loc1]] = trAlliance)) then 354 575 begin 355 GetUnitReport(p,uix,UnitReport); 356 inc(Eaten,UnitReport.FoodSupport); 357 if UnitReport.ReportFlags and urfAlwaysSupport<>0 then 358 inc(ForcedSupport, UnitReport.ProdSupport) 359 else inc(Support, UnitReport.ProdSupport); 360 if UnitReport.ReportFlags and urfDeployed<>0 then 361 inc(Deployed); 362 end; 363 if Deployed>=Happy then Happy:=0 else dec(Happy,Deployed); 364 dec(Support,Size*SupportFree[RW[p].Government] shr 1); 365 if Support<0 then Support:=0; 366 inc(Support,ForcedSupport); 367 368 {control} 369 case RW[p].Government of 370 gDespotism: 371 for uix:=0 to RW[p].nUn-1 do 372 if (RW[p].Un[uix].Loc=Loc) 373 and (RW[p].Model[RW[p].Un[uix].mix].Kind=mkSpecial_TownGuard) then 374 begin inc(Happy); inc(Control,2) end; 375 gFundamentalism: 376 begin 377 BaseHappiness:=0; // done by control 378 Happy:=Size; 379 Control:=Size 380 end; 381 end; 382 383 // collect processing parameters 384 DetermineCityProdProcessing(p, cix, ProdProcessing); 385 DetermineCityTradeProcessing(p, cix, BaseHappiness+Control-2*Deployed, TradeProcessing); 386 387 // collect resources 388 Working:=0; 389 FoodRep:=0;ProdRep:=0;Trade:=0; 390 FillChar(RareOK,SizeOf(RareOK),0); 391 V21_to_Loc(Loc,Radius); 392 for V21:=1 to 26 do if HypoTiles and (1 shl V21)<>0 then 393 begin {sum resources of exploited tiles} 394 Loc1:=Radius[V21]; 395 if (Loc1<0) or (Loc1>=MapSize) then // HypoTiles go beyond map border! 396 begin result:=eInvalid; exit end; 397 GetTileInfo(p,cix,Loc1,TileInfo); 398 inc(FoodRep,TileInfo.Food); 399 inc(ProdRep,TileInfo.Prod); 400 inc(Trade,TileInfo.Trade); 401 if (RealMap[Loc1] and fModern<>0) and (RW[p].Tech[adMassProduction]>=tsApplicable) then 402 inc(RareOK[RealMap[Loc1] shr 25 and 3]); 403 inc(Working) 404 end; 405 if Built[imAlgae]=1 then 406 inc(FoodRep,12); 407 408 if pCityReportEx<>nil then 409 begin 410 pCityReportEx.Material:=ProdRep; 411 pCityReportEx.BaseHappiness:=BaseHappiness; 412 pCityReportEx.BaseControl:=Control; 413 pCityReportEx.ProdProcessing:=ProdProcessing; 414 pCityReportEx.TradeProcessing:=TradeProcessing; 415 end; 416 417 BoostProd(ProdRep,ProdProcessing,ProdRep,PollRep); 418 SplitTrade(Trade,HypoTax,HypoLux,Working,TradeProcessing, 419 Corruption,Tax,Lux,Science); 420 Happy:=Happy+(Lux+Size and 1) shr 1; 421 //new style disorder requires 1 lux less for cities with odd size 422 423 // check if rare resource available 424 if (GTestFlags and tfNoRareNeed=0) and (ProdRep>Support) 425 and (Project and cpImp<>0) 426 and ((Project and cpIndex=imShipComp) and (RareOK[1]=0) 427 or (Project and cpIndex=imShipPow) and (RareOK[2]=0) 428 or (Project and cpIndex=imShipHab) and (RareOK[3]=0)) then 429 ProdRep:=Support; 430 end; 431 end; 432 result:=eOk; 433 end; {GetSmallCityReport} 434 435 function GetCityReport(p,cix: integer; var CityReport: TCityReport): integer; 436 begin 437 result:=GetSmallCityReport(p,cix,CityReport); 438 CityReport.Storage:=StorageSize[Difficulty[p]]; 439 CityReport.ProdCost:=GetProjectCost(p,cix); 440 end; 441 442 function GetCityReportNew(p,cix: integer; var CityReportNew: TCityReportNew): integer; 443 var 444 CityReport: TCityReport; 445 CityReportEx: TCityReportEx; 446 begin 447 with CityReportNew do 448 begin 449 CityReport.HypoTiles:=HypoTiles; 450 CityReport.HypoTax:=HypoTaxRate; 451 CityReport.HypoLux:=HypoLuxuryRate; 452 result:=GetSmallCityReport(p,cix,CityReport,@CityReportEx); 453 FoodSupport:=CityReport.Eaten-2*RW[p].City[cix].Size; 454 MaterialSupport:=CityReport.Support; 455 ProjectCost:=GetProjectCost(p,cix); 456 Storage:=StorageSize[Difficulty[p]]; 457 Deployed:=CityReport.Deployed; 458 Morale:=CityReportEx.BaseHappiness; 459 CollectedControl:=CityReportEx.BaseControl+(RW[p].City[cix].Size-CityReport.Working)*2; 460 CollectedFood:=CityReport.FoodRep; 461 CollectedMaterial:=CityReportEx.Material; 462 CollectedTrade:=CityReport.Trade; 463 Working:=CityReport.Working; 464 Production:=CityReport.ProdRep-CityReport.Support; 465 AddPollution:=CityReport.PollRep; 466 Corruption:=CityReport.Corruption; 467 Tax:=CityReport.Tax; 468 Science:=CityReport.Science; 469 Luxury:=CityReport.Lux; 470 FoodSurplus:=CityReport.FoodRep-CityReport.Eaten; 471 HappinessBalance:=Morale+Luxury+CollectedControl 472 -RW[p].City[cix].Size-2*Deployed; 473 end; 474 end; 475 476 { 477 Internal Tile Picking 478 ____________________________________________________________________ 479 } 480 procedure NextBest(p,cix:integer; var SelectedLoc, SelectedV21: integer); 481 {best tile unused but available by city cix} 482 var 483 Resources,Most,Loc1,p1,V21:integer; 484 TileInfo:TTileInfo; 485 Radius: TVicinity21Loc; 486 begin 487 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap=0);{$ENDIF} 488 Most:=0; 489 SelectedLoc:=-1; 490 SelectedV21:=-1; 491 with RW[p].City[cix] do 492 begin 493 V21_to_Loc(Loc,Radius); 494 for V21:=1 to 26 do 495 begin 496 Loc1:=Radius[V21]; 497 if (Loc1>=0) and (Loc1<MapSize) and (UsedByCity[Loc1]=-1) then 498 begin 499 p1:=RealMap[Loc1] shr 27; 500 if ((p1=nPl) or (p1=p) or (RW[p].Treaty[p1]<trPeace)) 501 and ((ZoCMap[Loc1]=0) or (Occupant[Loc1]=p) 502 or (RW[p].Treaty[Occupant[Loc1]]=trAlliance)) then 503 begin 504 GetTileInfo(p,cix,Loc1,TileInfo); 505 Resources:=TileInfo.Food shl 16+TileInfo.Prod shl 8+TileInfo.Trade; 506 {priority: 1.food - 2.prod - 3.trade} 507 if Resources>Most then 576 GetTileInfo(p, cix, Loc1, TileInfo); 577 Resources := TileInfo.Food shl 16 + TileInfo.Prod shl 8 + 578 TileInfo.Trade; 579 { priority: 1.food - 2.prod - 3.trade } 580 if Resources > Most then 508 581 begin 509 SelectedLoc:=Loc1;510 SelectedV21:=V21;511 Most:=Resources582 SelectedLoc := Loc1; 583 SelectedV21 := V21; 584 Most := Resources 512 585 end 513 586 end … … 517 590 end; 518 591 519 procedure NextWorst(p, cix:integer; var SelectedLoc, SelectedV21: integer);520 { worst tile used by city cix}521 var 522 Resources,Least,Loc1,V21:integer;523 Radius: TVicinity21Loc;524 TileInfo:TTileInfo;525 begin 526 Least:=MaxInt;527 SelectedLoc:=-1;528 SelectedV21:=-1;529 with RW[p].City[cix] do592 procedure NextWorst(p, cix: integer; var SelectedLoc, SelectedV21: integer); 593 { worst tile used by city cix } 594 var 595 Resources, Least, Loc1, V21: integer; 596 Radius: TVicinity21Loc; 597 TileInfo: TTileInfo; 598 begin 599 Least := MaxInt; 600 SelectedLoc := -1; 601 SelectedV21 := -1; 602 with RW[p].City[cix] do 530 603 begin 531 V21_to_Loc(Loc,Radius); 532 for V21:=1 to 26 do if V21<>CityOwnTile then 533 begin 534 Loc1:=Radius[V21]; 535 if (Loc1>=0) and (Loc1<MapSize) and (1 shl V21 and Tiles<>0) then 536 begin 537 GetTileInfo(p,cix,Loc1,TileInfo); 538 Resources:=TileInfo.Food shl 16+TileInfo.Prod shl 8+TileInfo.Trade; 539 {priority: 1.food - 2.prod - 3.trade} 540 if Resources<Least then 604 V21_to_Loc(Loc, Radius); 605 for V21 := 1 to 26 do 606 if V21 <> CityOwnTile then 607 begin 608 Loc1 := Radius[V21]; 609 if (Loc1 >= 0) and (Loc1 < MapSize) and (1 shl V21 and Tiles <> 0) then 541 610 begin 542 SelectedLoc:=Loc1; 543 SelectedV21:=V21; 544 Least:=Resources 545 end 546 end; 547 end 611 GetTileInfo(p, cix, Loc1, TileInfo); 612 Resources := TileInfo.Food shl 16 + TileInfo.Prod shl 8 + 613 TileInfo.Trade; 614 { priority: 1.food - 2.prod - 3.trade } 615 if Resources < Least then 616 begin 617 SelectedLoc := Loc1; 618 SelectedV21 := V21; 619 Least := Resources 620 end 621 end; 622 end 548 623 end 549 624 end; 550 625 551 function NextPoll(p, cix:integer):integer;552 var 553 Resources,Best,dx,dy,Loc1,Dist,BestDist,V21,pTerr:integer;554 Radius: TVicinity21Loc;555 TileInfo:TTileInfo;556 begin 557 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap =0);{$ENDIF}558 Best:=0;559 result:=-1;560 with RW[p].City[cix] do626 function NextPoll(p, cix: integer): integer; 627 var 628 Resources, Best, dx, dy, Loc1, Dist, BestDist, V21, pTerr: integer; 629 Radius: TVicinity21Loc; 630 TileInfo: TTileInfo; 631 begin 632 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap = 0); {$ENDIF} 633 Best := 0; 634 result := -1; 635 with RW[p].City[cix] do 561 636 begin 562 V21_to_Loc(Loc,Radius); 563 for V21:=1 to 26 do if V21<>CityOwnTile then 564 begin 565 Loc1:=Radius[V21]; 566 if (Loc1>=0) and (Loc1<MapSize) 567 and (RealMap[Loc1] and fTerrain>=fGrass) 568 and (RealMap[Loc1] and (fPoll or fDeadLands or fCity)=0) then 569 begin 570 pTerr:=RealMap[Loc1] shr 27; 571 if (pTerr=nPl) or (pTerr=p) or (RW[p].Treaty[pTerr]<trPeace) then 637 V21_to_Loc(Loc, Radius); 638 for V21 := 1 to 26 do 639 if V21 <> CityOwnTile then 640 begin 641 Loc1 := Radius[V21]; 642 if (Loc1 >= 0) and (Loc1 < MapSize) and 643 (RealMap[Loc1] and fTerrain >= fGrass) and 644 (RealMap[Loc1] and (fPoll or fDeadLands or fCity) = 0) then 572 645 begin 573 GetTileInfo(p,cix,Loc1,TileInfo); 574 Resources:=TileInfo.Prod shl 16+TileInfo.Trade shl 8+TileInfo.Food; 575 {priority: 1.prod - 2.trade - 3.food} 576 dy:=V21 shr 2-3; 577 dx:=V21 and 3 shl 1 -3 + (dy+3) and 1; 578 Dist:=abs(dx)+abs(dy)+abs(abs(dx)-abs(dy)) shr 1; 579 if (Resources>Best) or (Resources=Best) and (Dist<BestDist) then 646 pTerr := RealMap[Loc1] shr 27; 647 if (pTerr = nPl) or (pTerr = p) or (RW[p].Treaty[pTerr] < trPeace) 648 then 580 649 begin 581 result:=Loc1; 582 Best:=Resources; 583 BestDist:=Dist 584 end 585 end 586 end 587 end; 588 end 589 end; 590 591 function AddBestCityTile(p,cix: integer): boolean; 592 var 593 TileLoc,V21: integer; 594 begin 595 NextBest(p,cix,TileLoc,V21); 596 result:= TileLoc>=0; 597 if result then with RW[p].City[cix] do 598 begin 599 assert(1 shl V21 and Tiles=0); 600 Tiles:=Tiles or (1 shl V21); 601 UsedByCity[TileLoc]:=Loc 602 end 603 end; 604 605 procedure CityGrowth(p,cix: integer); 606 var 607 TileLoc,V21: integer; 608 AltCityReport:TCityReport; 609 begin 610 with RW[p].City[cix] do 611 begin 612 inc(Size); 613 NextBest(p,cix,TileLoc,V21); 614 if TileLoc>=0 then 615 begin {test whether exploitation of tile would lead to disorder} 616 AltCityReport.HypoTiles:=Tiles+1 shl V21; 617 AltCityReport.HypoTax:=-1; 618 AltCityReport.HypoLux:=-1; 619 GetSmallCityReport(p,cix,AltCityReport); 620 if AltCityReport.Working-AltCityReport.Happy<=Size shr 1 then // !!! change to new style disorder 621 begin {no disorder -- exploit tile} 622 assert(1 shl V21 and Tiles=0); 623 Tiles:=Tiles or (1 shl V21); 624 UsedByCity[TileLoc]:=Loc 625 end 626 end; 627 end 628 end; 629 630 procedure CityShrink(p,cix: integer); 631 var 632 TileLoc, V21, Working: integer; 633 AltCityReport:TCityReport; 634 begin 635 with RW[p].City[cix] do 636 begin 637 Working:=0; 638 for V21:=1 to 26 do if Tiles and (1 shl V21)<>0 then inc(Working); 639 dec(Size); 640 if Food>StorageSize[Difficulty[p]] then Food:=StorageSize[Difficulty[p]]; 641 NextWorst(p,cix,TileLoc,V21); 642 if Working>Size then 643 begin {all citizens were working -- worst tile no longer exploited} 644 assert(1 shl V21 and Tiles<>0); 645 Tiles:=Tiles and not (1 shl V21); 646 UsedByCity[TileLoc]:=-1 647 end 648 else {test whether exploitation of tile would lead to disorder} 649 begin 650 AltCityReport.HypoTiles:=-1; 651 AltCityReport.HypoTax:=-1; 652 AltCityReport.HypoLux:=-1; 653 GetSmallCityReport(p,cix,AltCityReport); 654 if AltCityReport.Working-AltCityReport.Happy>Size shr 1 then // !!! change to new style disorder 655 begin {disorder -- don't exploit tile} 656 assert(1 shl V21 and Tiles<>0); 657 Tiles:=Tiles and not (1 shl V21); 658 UsedByCity[TileLoc]:=-1 659 end 660 end; 661 end 662 end; 663 664 procedure Pollute(p,cix: integer); 665 var 666 PollutionLoc: integer; 667 begin 668 with RW[p].City[cix] do 669 begin 670 Pollution:=Pollution-MaxPollution; 671 PollutionLoc:=NextPoll(p,cix); 672 if PollutionLoc>=0 then 673 begin 674 inc(Flags,chPollution); 675 RealMap[PollutionLoc]:=RealMap[PollutionLoc] or fPoll; 676 end 677 end; 678 end; 679 680 { 681 Turn Processing 682 ____________________________________________________________________ 683 } 684 procedure PayCityMaintenance(p,cix: integer); 685 var 686 i: integer; 687 begin 688 with RW[p],City[cix] do 689 for i:=28 to nImp-1 do 690 if (Built[i]>0) 691 and (Project0 and (cpImp or cpIndex)<>(cpImp or i)) then // don't pay maintenance when just completed 692 begin 693 dec(Money,Imp[i].Maint); 694 if Money<0 then 695 begin {out of money - sell improvement} 696 inc(Money,Imp[i].Cost*BuildCostMod[Difficulty[p]] div 12); 697 Built[i]:=0; 698 if Imp[i].Kind<>ikCommon then 699 begin 700 assert(i<>imSpacePort); // never sell automatically! (solution: no maintenance) 701 NatBuilt[i]:=0; 702 if i=imGrWall then GrWallContinent[p]:=-1; 703 end; 704 inc(Flags,chImprovementLost) 705 end 706 end; 707 end; 708 709 procedure CollectCityResources(p,cix: integer); 710 var 711 CityStorage,CityProjectCost: integer; 712 CityReport: TCityReportNew; 713 Disorder: boolean; 714 begin 715 with RW[p],City[cix],CityReport do 716 if Flags and chCaptured<>0 then 717 begin 718 Flags:=Flags and not chDisorder; 719 dec(Flags,$10000); 720 if Flags and chCaptured=0 then 721 Flags:=Flags or chAfterCapture; 722 end 723 else if Government=gAnarchy then 724 Flags:=Flags and not chDisorder 725 else 726 begin 727 HypoTiles:=-1; 728 HypoTaxRate:=-1; 729 HypoLuxuryRate:=-1; 730 GetCityReportNew(p,cix,CityReport); 731 CityStorage:=StorageSize[Difficulty[p]]; 732 CityProjectCost:=GetProjectCost(p,cix); 733 734 Disorder:= (HappinessBalance<0); 735 if Disorder and (Flags and chDisorder<>0) then 736 CollectedMaterial:=0; // second turn disorder 737 if Disorder then 738 Flags:=Flags or chDisorder 739 else Flags:=Flags and not chDisorder; 740 741 if not Disorder 742 and ((Government=gFuture) 743 or (Size>=NeedAqueductSize) and (FoodSurplus<2)) and (FoodSurplus>0) then 744 inc(Money,FoodSurplus) 745 else if not (Disorder and (FoodSurplus>0)) then 746 begin {calculate new food storage} 747 Food:=Food+FoodSurplus; 748 if ((GTestFlags and tfImmGrow<>0) 749 or (Food>=CityStorage) and (Food-FoodSurplus<CityStorage)) // only warn once 750 and (Size<MaxCitySize) 751 and (Project and (cpImp+cpIndex)<>cpImp+imAqueduct) 752 and (Project and (cpImp+cpIndex)<>cpImp+imSewer) 753 and not CanCityGrow(p,cix) then 754 inc(Flags,chNoGrowthWarning); 755 end; 756 757 if Prod>CityProjectCost then 758 begin inc(Money,Prod-CityProjectCost); Prod:=CityProjectCost end; 759 if Production<0 then 760 Flags:=Flags or chUnitLost 761 else if not Disorder and (Flags and chProductionSabotaged=0) then 762 if Project and (cpImp+cpIndex)=cpImp+imTrGoods then 763 inc(Money,Production) 764 else inc(Prod,Production); 765 766 if not Disorder then 767 begin 768 {sum research points and taxes} 769 inc(Research,Science); 770 inc(Money,Tax); 771 Pollution:=Pollution+AddPollution; 772 end; 773 end; 774 end; 775 776 function CityTurn(p,cix: integer): boolean; 777 // return value: whether city keeps existing 778 var 779 i,uix,cix2,p1,SizeMod,CityStorage,CityProjectCost,NewImp,Det,TestDet: integer; 780 LackOfMaterial, CheckGrow, DoProd, IsActive: boolean; 781 begin 782 with RW[p],City[cix] do 783 begin 784 SizeMod:=0; 785 CityStorage:=StorageSize[Difficulty[p]]; 786 CityProjectCost:=GetProjectCost(p,cix); 787 788 LackOfMaterial:= Flags and chUnitLost<>0; 789 Flags:=Flags and not chUnitLost; 790 791 IsActive:= (Government<>gAnarchy) and (Flags and chCaptured=0); 792 CheckGrow:=(Flags and chDisorder=0) and IsActive 793 and (Government<>gFuture); 794 if CheckGrow and (GTestFlags and tfImmGrow<>0) then {fast growth} 795 begin 796 if CanCityGrow(p,cix) then inc(SizeMod) 797 end 798 else if CheckGrow and (Food>=CityStorage) then {normal growth} 799 begin 800 if CanCityGrow(p,cix) then 801 begin 802 if Built[imGranary]=1 then dec(Food,CityStorage shr 1) 803 else dec(Food,CityStorage); 804 inc(SizeMod) 805 end 806 end 807 else if Food<0 then {famine} 808 begin 809 Food:=0; 810 // check if settlers or conscripts there to disband 811 uix:=-1; 812 for i:=0 to nUn-1 do 813 if (Un[i].Loc>=0) and (Un[i].Home=cix) 814 and ((Model[Un[i].mix].Kind=mkSettler) 815 {and (GWonder[woFreeSettlers].EffectiveOwner<>p)} 816 or (Un[i].Flags and unConscripts<>0)) 817 and ((uix=-1) or (Model[Un[i].mix].Cost<Model[Un[uix].mix].Cost) 818 or (Model[Un[i].mix].Cost=Model[Un[uix].mix].Cost) 819 and (Un[i].Exp<Un[uix].Exp)) then 820 uix:=i; 821 822 if uix>=0 then 823 begin RemoveUnit_UpdateMap(p,uix); inc(Flags,chUnitLost); end 824 else begin dec(SizeMod); inc(Flags,chPopDecrease) end 825 end; 826 if Food>CityStorage then Food:=CityStorage; 827 828 if LackOfMaterial then 829 begin 830 if Flags and chUnitLost=0 then 831 begin {one unit lost} 832 uix:=-1; 833 Det:=MaxInt; 834 for i:=0 to nUn-1 do if (Un[i].Loc>=0) and (Un[i].Home=cix) then 835 with Model[Un[i].mix] do 836 begin 837 if Kind=mkSpecial_TownGuard then 838 TestDet:=Un[i].Health+Un[i].Exp shl 8 // disband townguards first 839 else 650 GetTileInfo(p, cix, Loc1, TileInfo); 651 Resources := TileInfo.Prod shl 16 + TileInfo.Trade shl 8 + 652 TileInfo.Food; 653 { priority: 1.prod - 2.trade - 3.food } 654 dy := V21 shr 2 - 3; 655 dx := V21 and 3 shl 1 - 3 + (dy + 3) and 1; 656 Dist := abs(dx) + abs(dy) + abs(abs(dx) - abs(dy)) shr 1; 657 if (Resources > Best) or (Resources = Best) and (Dist < BestDist) 658 then 840 659 begin 841 TestDet:=Un[i].Health+Un[i].Exp shl 8+Cost shl 16; // value of unit 842 if Flags and mdDoubleSupport<>0 then 843 TestDet:=TestDet shr 1; // double support, tend to disband first 844 end; 845 if TestDet<Det then 846 begin uix:=i; Det:=TestDet end; 847 end; 848 if uix>=0 then 849 begin 850 RemoveUnit_UpdateMap(p,uix); 851 inc(Flags,chUnitLost); 852 end 853 end 854 end; 855 856 if GTestFlags and tfImmImprove<>0 then Prod:=CityProjectCost; 857 DoProd:= (Project and (cpImp+cpIndex)<>cpImp+imTrGoods) 858 and (Prod>=CityProjectCost); 859 860 // check if wonder already built 861 if (Project and cpImp<>0) and (Project and cpIndex<28) 862 and (GWonder[Project and cpIndex].CityID<>-1) then 863 begin inc(Flags,chOldWonder); DoProd:=false; end; 864 865 // check if producing settlers would disband city 866 if DoProd and (Project and (cpImp or cpDisbandCity)=0) 867 and ((Size+SizeMod-2<2) and (Model[Project and cpIndex].Kind=mkSettler) 868 or (Size+SizeMod-1<2) and ((Model[Project and cpIndex].Kind=mkSlaves) 869 or (Project and cpConscripts<>0))) then 870 begin inc(Flags,chNoSettlerProd); DoProd:=false; end; 871 872 if DoProd then 873 begin {project complete} 874 dec(Prod,CityProjectCost); 875 if Project and cpImp=0 then {produce unit} 876 begin 877 if nUn<numax then 878 begin 879 CreateUnit(p,Project and cpIndex); 880 Un[nUn-1].Loc:=Loc; 881 with Un[nUn-1] do 882 begin 883 Home:=cix; 884 if (Model[mix].Domain<dSea) and (Built[imElite]=1) then 885 Exp:=ExpCost*(nExp-1){elite} 886 else if (Model[mix].Domain<dSea) and (Built[imBarracks]=1) 887 or (Model[mix].Domain=dSea) and (Built[imDockyard]=1) 888 or (Model[mix].Domain=dAir) and (Built[imAirport]=1) then 889 Exp:=ExpCost*2;{vet} 890 if Project and cpConscripts<>0 then Flags:=Flags or unConscripts 891 end; 892 PlaceUnit(p,nUn-1); 893 UpdateUnitMap(Loc); 894 if Model[Project and cpIndex].Kind=mkSettler then 895 dec(SizeMod,2) {settler produced - city shrink} 896 else if (Model[Project and cpIndex].Kind=mkSlaves) 897 or (Project and cpConscripts<>0) then 898 dec(SizeMod); {slaves/conscripts produced - city shrink} 899 end; 900 Project0:=Project or cpRepeat or cpCompleted; 901 end 902 else if Imp[Project and cpIndex].Kind=ikShipPart then 903 begin {produce ship parts} 904 inc(GShip[p].Parts[Project and cpIndex-imShipComp]); 905 Project0:=Project or cpCompleted; 906 end 907 else {produce improvement} 908 begin 909 NewImp:=Project and cpIndex; 910 inc(Money,Prod);{change rest to money} 911 Project0:=Project or cpCompleted; 912 Project:=cpImp+imTrGoods; 913 Prod:=0; 914 915 if Imp[NewImp].Kind in [ikNatLocal,ikNatGlobal] then 916 begin // nat. project 917 for i:=0 to nCity-1 do 918 if (City[i].Loc>=0) and (City[i].Built[NewImp]=1) then 919 begin {allowed only once} 920 inc(Money,Imp[NewImp].Cost 921 *BuildCostMod[Difficulty[p]] div 12); 922 City[i].Built[NewImp]:=0; 923 end; 924 NatBuilt[NewImp]:=1; 925 926 // immediate nat. project effects 927 case NewImp of 928 imGrWall: GrWallContinent[p]:=Continent[Loc]; 929 end; 930 end; 931 932 if NewImp<28 then 933 begin // wonder 934 GWonder[NewImp].CityID:=ID; 935 GWonder[NewImp].EffectiveOwner:=p; 936 CheckExpiration(NewImp); 937 938 // immediate wonder effects 939 case NewImp of 940 woEiffel: 941 begin // reactivate wonders 942 for i:=0 to 27 do if Imp[i].Expiration>=0 then 943 for cix2:=0 to nCity-1 do 944 if (City[cix2].Loc>=0) and (City[cix2].Built[i]=1) then 945 GWonder[i].EffectiveOwner:=p 946 end; 947 woLighthouse: CheckSpecialModels(p,preLighthouse); 948 woLeo: 949 begin 950 inc(Research, 951 TechBaseCost(nTech[p],Difficulty[p]) 952 +TechBaseCost(nTech[p]+2,Difficulty[p])); 953 CheckSpecialModels(p,preLeo); 954 end; 955 woPyramids: CheckSpecialModels(p,preBuilder); 956 woMir: 957 begin 958 for p1:=0 to nPl-1 do 959 if (p1<>p) and (1 shl p1 and GAlive<>0) then 960 begin 961 if RW[p].Treaty[p1]=trNoContact then 962 IntroduceEnemy(p,p1); 963 GiveCivilReport(p, p1); 964 GiveMilReport(p, p1) 965 end; 966 end 967 end; 968 end; 969 970 for i:=0 to nImpReplacement-1 do // sell obsolete buildings 971 if (ImpReplacement[i].NewImp=NewImp) 972 and (Built[ImpReplacement[i].OldImp]>0) then 973 begin 974 inc(RW[p].Money, Imp[ImpReplacement[i].OldImp].Cost 975 *BuildCostMod[Difficulty[p]] div 12); 976 Built[ImpReplacement[i].OldImp]:=0; 977 end; 978 979 if NewImp in [imPower,imHydro,imNuclear] then 980 for i:=0 to nImp-1 do 981 if (i<>NewImp) and (i in [imPower,imHydro,imNuclear]) 982 and (Built[i]>0) then 983 begin // sell obsolete power plant 984 inc(RW[p].Money, Imp[i].Cost*BuildCostMod[Difficulty[p]] div 12); 985 Built[i]:=0; 986 end; 987 988 Built[NewImp]:=1; 989 end; 990 Prod0:=Prod; 991 inc(Flags,chProduction) 992 end 993 else 994 begin 995 Project0:=Project0 and not cpCompleted; 996 if Project0 and not cpAuto<>Project and not cpAuto then 997 Project0:=Project; 998 Prod0:=Prod; 999 end; 1000 1001 if SizeMod>0 then 1002 begin 1003 CityGrowth(p,cix); 1004 inc(Flags,chPopIncrease); 1005 end; 1006 result:= Size+SizeMod>=2; 1007 if result then 1008 while SizeMod<0 do 1009 begin CityShrink(p,cix); inc(SizeMod) end; 1010 end 1011 end; //CityTurn 1012 1013 { 1014 Tile Access 1015 ____________________________________________________________________ 1016 } 1017 function SetCityTiles(p, cix, NewTiles: integer; TestOnly: boolean = false): integer; 1018 var 1019 V21,Working,ChangeTiles,AddTiles,Loc1: integer; 1020 CityAreaInfo: TCityAreaInfo; 1021 Radius: TVicinity21Loc; 1022 begin 1023 with RW[p].City[cix] do 1024 begin 1025 ChangeTiles:=NewTiles xor integer(Tiles); 1026 AddTiles:=NewTiles and not Tiles; 1027 if Mode=moPlaying then 1028 begin // do all checks 1029 if NewTiles and not $67F7F76<>0 then 1030 begin result:=eInvalid; exit end; // invalid tile index included 1031 if NewTiles and (1 shl 13)=0 then 1032 begin result:=eViolation; exit end; // city tile must be exploited 1033 if ChangeTiles=0 then 1034 begin result:=eNotChanged; exit end; 1035 if AddTiles<>0 then 1036 begin 1037 // check if new tiles possible 1038 GetCityAreaInfo(p, Loc, CityAreaInfo); 1039 for V21:=1 to 26 do if AddTiles and (1 shl V21)<>0 then 1040 if CityAreaInfo.Available[V21]<>faAvailable then 1041 begin result:=eTileNotAvailable; exit end; 1042 // not more tiles than inhabitants 1043 Working:=0; 1044 for V21:=1 to 26 do if NewTiles and (1 shl V21)<>0 then inc(Working); 1045 if Working>Size then 1046 begin result:=eNoWorkerAvailable; exit end; 1047 end; 1048 end; 1049 result:=eOK; 1050 if not TestOnly then 1051 begin 1052 V21_to_Loc(Loc,Radius); 1053 for V21:=1 to 26 do if ChangeTiles and (1 shl V21)<>0 then 1054 begin 1055 Loc1:=Radius[V21]; 1056 assert((Loc1>=0) and (Loc1<MapSize)); 1057 if NewTiles and (1 shl V21)<>0 then UsedByCity[Loc1]:=Loc // employ tile 1058 else if UsedByCity[Loc1]<>Loc then 1059 assert(Mode<moPlaying) 1060 // should only happen during loading, because of wrong sSetCityTiles command order 1061 else UsedByCity[Loc1]:=-1 // unemploy tile 1062 end; 1063 Tiles:=NewTiles 1064 end 1065 end; 1066 end; 1067 1068 procedure GetCityTileAdvice(p, cix: integer; var Advice: TCityTileAdviceData); 1069 const 1070 oFood=0; oProd=1; oTax=2; oScience=3; 1071 type 1072 TTileData=record 1073 Food,Prod,Trade,SubValue,V21: integer; 1074 end; 1075 var 1076 i,V21,Loc1,nHierarchy,iH,iT,iH_Switch,MinWorking,MaxWorking, 1077 WantedProd,MinFood,MinProd,count,Take,MaxTake,AreaSize,FormulaCode, 1078 NeedRare, RareTiles,cix1,dx,dy,BestTiles,ProdBeforeBoost,TestTiles, 1079 SubPlus,SuperPlus: integer; 1080 SuperValue,BestSuperValue,SubValue,BestSubValue: integer; 1081 Value,BestValue,ValuePlus: extended; 1082 ValueFormula_Weight: array[oFood..oScience] of extended; 1083 ValueFormula_Multiply: array[oFood..oScience] of boolean; 1084 Output: array[oFood..oScience] of integer; 1085 TileInfo, BaseTileInfo: TTileInfo; 1086 Radius, Radius1: TVicinity21Loc; 1087 TestReport: TCityReport; 1088 CityReportEx: TCityReportEx; 1089 CityAreaInfo: TCityAreaInfo; 1090 Hierarchy: array[0..20,0..31] of TTileData; 1091 nTile,nSelection: array[0..20] of integer; 1092 SubCriterion: array[0..27] of integer; 1093 FoodWasted, FoodToTax, ProdToTax, RareOk, NeedStep2, IsBest: boolean; 1094 begin 1095 if (RW[p].Government=gAnarchy) or (RW[p].City[cix].Flags and chCaptured<>0) then 1096 begin 1097 Fillchar(Advice.CityReport, sizeof(Advice.CityReport), 0); 1098 Advice.Tiles:=1 shl CityOwnTile; 1099 Advice.CityReport.HypoTiles:=1 shl CityOwnTile; 1100 exit; 1101 end; 1102 1103 for i:=oFood to oScience do 1104 begin //decode evaluation formula from weights parameter 1105 FormulaCode:=Advice.ResourceWeights shr (24-8*i) and $FF; 1106 ValueFormula_Multiply[i]:= FormulaCode and $80<>0; 1107 if FormulaCode and $40<>0 then 1108 ValueFormula_Weight[i]:=(FormulaCode and $0F) 1109 *(1 shl (FormulaCode and $30 shr 4))/16 1110 else ValueFormula_Weight[i]:=(FormulaCode and $0F) 1111 *(1 shl (FormulaCode and $30 shr 4)); 1112 end; 1113 1114 TestReport.HypoTiles:=1 shl CityOwnTile; 1115 TestReport.HypoTax:=-1; 1116 TestReport.HypoLux:=-1; 1117 GetSmallCityReport(p,cix,TestReport,@CityReportEx); 1118 with RW[p].City[cix] do 1119 begin 1120 V21_to_Loc(Loc,Radius); 1121 FoodToTax:= RW[p].Government=gFuture; 1122 ProdToTax:= Project and (cpImp+cpIndex)=cpImp+imTrGoods; 1123 FoodWasted:=not FoodToTax and (Food=StorageSize[Difficulty[p]]) 1124 and not CanCityGrow(p,cix); 1125 1126 // sub criteria 1127 for V21:=1 to 26 do 1128 begin 1129 Loc1:=Radius[V21]; 1130 if Loc1>=0 then 1131 SubCriterion[V21]:=3360-(Distance(Loc,Loc1)-1)*32-V21 xor $15; 1132 end; 1133 for cix1:=0 to RW[p].nCity-1 do if cix1<>cix then 1134 begin 1135 Loc1:=RW[p].City[cix1].Loc; 1136 if Loc1>=0 then 1137 begin 1138 if Distance(Loc,Loc1)<=10 then 1139 begin // cities overlap -- prefer tiles outside common range 1140 V21_to_Loc(Loc1,Radius1); 1141 for V21:=1 to 26 do 1142 begin 1143 Loc1:=Radius1[V21]; 1144 if (Loc1>=0) and (Loc1<MapSize) and (Distance(Loc,Loc1)<=5) then 1145 begin 1146 dxdy(Loc,Loc1,dx,dy); 1147 dec(SubCriterion[(dy+3) shl 2+(dx+3) shr 1],160); 660 result := Loc1; 661 Best := Resources; 662 BestDist := Dist 1148 663 end 1149 664 end 1150 665 end 666 end; 667 end 668 end; 669 670 function AddBestCityTile(p, cix: integer): boolean; 671 var 672 TileLoc, V21: integer; 673 begin 674 NextBest(p, cix, TileLoc, V21); 675 result := TileLoc >= 0; 676 if result then 677 with RW[p].City[cix] do 678 begin 679 assert(1 shl V21 and Tiles = 0); 680 Tiles := Tiles or (1 shl V21); 681 UsedByCity[TileLoc] := Loc 682 end 683 end; 684 685 procedure CityGrowth(p, cix: integer); 686 var 687 TileLoc, V21: integer; 688 AltCityReport: TCityReport; 689 begin 690 with RW[p].City[cix] do 691 begin 692 inc(Size); 693 NextBest(p, cix, TileLoc, V21); 694 if TileLoc >= 0 then 695 begin { test whether exploitation of tile would lead to disorder } 696 AltCityReport.HypoTiles := Tiles + 1 shl V21; 697 AltCityReport.HypoTax := -1; 698 AltCityReport.HypoLux := -1; 699 GetSmallCityReport(p, cix, AltCityReport); 700 if AltCityReport.Working - AltCityReport.Happy <= Size shr 1 then 701 // !!! change to new style disorder 702 begin { no disorder -- exploit tile } 703 assert(1 shl V21 and Tiles = 0); 704 Tiles := Tiles or (1 shl V21); 705 UsedByCity[TileLoc] := Loc 1151 706 end 1152 707 end; 1153 1154 GetCityAreaInfo(p,Loc,CityAreaInfo); 1155 AreaSize:=0; 1156 for V21:=1 to 26 do 1157 if CityAreaInfo.Available[V21]=faAvailable then 1158 inc(AreaSize); 1159 1160 if RW[p].Government=gFundamentalism then 1161 begin 1162 MinWorking:=Size; 1163 MaxWorking:=Size; 708 end 709 end; 710 711 procedure CityShrink(p, cix: integer); 712 var 713 TileLoc, V21, Working: integer; 714 AltCityReport: TCityReport; 715 begin 716 with RW[p].City[cix] do 717 begin 718 Working := 0; 719 for V21 := 1 to 26 do 720 if Tiles and (1 shl V21) <> 0 then 721 inc(Working); 722 dec(Size); 723 if Food > StorageSize[Difficulty[p]] then 724 Food := StorageSize[Difficulty[p]]; 725 NextWorst(p, cix, TileLoc, V21); 726 if Working > Size then 727 begin { all citizens were working -- worst tile no longer exploited } 728 assert(1 shl V21 and Tiles <> 0); 729 Tiles := Tiles and not(1 shl V21); 730 UsedByCity[TileLoc] := -1 1164 731 end 1165 else 1166 begin 1167 MinWorking:=CityReportEx.TradeProcessing.HappyBase shr 1; 1168 if MinWorking>Size then 1169 MinWorking:=Size; 1170 if (RW[p].LuxRate=0) 1171 and not CityReportEx.TradeProcessing.FlexibleLuxury then 1172 MaxWorking:=MinWorking 1173 else MaxWorking:=Size; 1174 end; 1175 if MaxWorking>AreaSize then 1176 begin 1177 MaxWorking:=AreaSize; 1178 if MinWorking>AreaSize then 1179 MinWorking:=AreaSize; 1180 end; 1181 if TestReport.Support=0 then 1182 WantedProd:=0 1183 else WantedProd:=1+(TestReport.Support*100-1) 1184 div (100+CityReportEx.ProdProcessing.ProdBonus*50+CityReportEx.ProdProcessing.FutProdBonus); 1185 1186 // consider resources for ship parts 1187 NeedRare:=0; 1188 if (GTestFlags and tfNoRareNeed=0) and (Project and cpImp<>0) then 1189 case Project and cpIndex of 1190 imShipComp: NeedRare:=fCobalt; 1191 imShipPow: NeedRare:=fUranium; 1192 imShipHab: NeedRare:=fMercury; 1193 end; 1194 if NeedRare>0 then 1195 begin 1196 RareTiles:=0; 1197 for V21:=1 to 26 do 1198 begin 1199 Loc1:=Radius[V21]; 1200 if (Loc1>=0) and (Loc1<MapSize) and (RealMap[Loc1] and fModern=cardinal(NeedRare)) then 1201 RareTiles:=RareTiles or (1 shl V21); 732 else { test whether exploitation of tile would lead to disorder } 733 begin 734 AltCityReport.HypoTiles := -1; 735 AltCityReport.HypoTax := -1; 736 AltCityReport.HypoLux := -1; 737 GetSmallCityReport(p, cix, AltCityReport); 738 if AltCityReport.Working - AltCityReport.Happy > Size shr 1 then 739 // !!! change to new style disorder 740 begin { disorder -- don't exploit tile } 741 assert(1 shl V21 and Tiles <> 0); 742 Tiles := Tiles and not(1 shl V21); 743 UsedByCity[TileLoc] := -1 1202 744 end 1203 745 end; 1204 1205 // step 1: sort tiles to hierarchies 1206 nHierarchy:=0; 1207 for V21:=1 to 26 do // non-rare tiles 1208 if (CityAreaInfo.Available[V21]=faAvailable) 1209 and ((NeedRare=0) or (1 shl V21 and RareTiles=0)) then 1210 begin 1211 Loc1:=Radius[V21]; 1212 assert((Loc1>=0) and (Loc1<MapSize)); 1213 GetTileInfo(p,cix,Loc1,TileInfo); 1214 if V21=CityOwnTile then 1215 BaseTileInfo:=TileInfo 746 end 747 end; 748 749 procedure Pollute(p, cix: integer); 750 var 751 PollutionLoc: integer; 752 begin 753 with RW[p].City[cix] do 754 begin 755 Pollution := Pollution - MaxPollution; 756 PollutionLoc := NextPoll(p, cix); 757 if PollutionLoc >= 0 then 758 begin 759 inc(Flags, chPollution); 760 RealMap[PollutionLoc] := RealMap[PollutionLoc] or fPoll; 761 end 762 end; 763 end; 764 765 { 766 Turn Processing 767 ____________________________________________________________________ 768 } 769 procedure PayCityMaintenance(p, cix: integer); 770 var 771 i: integer; 772 begin 773 with RW[p], City[cix] do 774 for i := 28 to nImp - 1 do 775 if (Built[i] > 0) and (Project0 and (cpImp or cpIndex) <> (cpImp or i)) 776 then // don't pay maintenance when just completed 777 begin 778 dec(Money, Imp[i].Maint); 779 if Money < 0 then 780 begin { out of money - sell improvement } 781 inc(Money, Imp[i].Cost * BuildCostMod[Difficulty[p]] div 12); 782 Built[i] := 0; 783 if Imp[i].Kind <> ikCommon then 784 begin 785 assert(i <> imSpacePort); 786 // never sell automatically! (solution: no maintenance) 787 NatBuilt[i] := 0; 788 if i = imGrWall then 789 GrWallContinent[p] := -1; 790 end; 791 inc(Flags, chImprovementLost) 792 end 793 end; 794 end; 795 796 procedure CollectCityResources(p, cix: integer); 797 var 798 CityStorage, CityProjectCost: integer; 799 CityReport: TCityReportNew; 800 Disorder: boolean; 801 begin 802 with RW[p], City[cix], CityReport do 803 if Flags and chCaptured <> 0 then 804 begin 805 Flags := Flags and not chDisorder; 806 dec(Flags, $10000); 807 if Flags and chCaptured = 0 then 808 Flags := Flags or chAfterCapture; 809 end 810 else if Government = gAnarchy then 811 Flags := Flags and not chDisorder 812 else 813 begin 814 HypoTiles := -1; 815 HypoTaxRate := -1; 816 HypoLuxuryRate := -1; 817 GetCityReportNew(p, cix, CityReport); 818 CityStorage := StorageSize[Difficulty[p]]; 819 CityProjectCost := GetProjectCost(p, cix); 820 821 Disorder := (HappinessBalance < 0); 822 if Disorder and (Flags and chDisorder <> 0) then 823 CollectedMaterial := 0; // second turn disorder 824 if Disorder then 825 Flags := Flags or chDisorder 1216 826 else 1217 begin 1218 iH:=0; 1219 while iH<nHierarchy do 1220 begin 1221 iT:=0; 1222 while (iT<nTile[iH]) 1223 and (TileInfo.Food<=Hierarchy[iH,iT].Food) 1224 and (TileInfo.Prod<=Hierarchy[iH,iT].Prod) 1225 and (TileInfo.Trade<=Hierarchy[iH,iT].Trade) 1226 and not ((TileInfo.Food=Hierarchy[iH,iT].Food) 1227 and (TileInfo.Prod=Hierarchy[iH,iT].Prod) 1228 and (TileInfo.Trade=Hierarchy[iH,iT].Trade) 1229 and (SubCriterion[V21]>=SubCriterion[Hierarchy[iH,iT].V21])) do 1230 inc(iT); 1231 if (iT=nTile[iH]) // new worst tile in this hierarchy 1232 or ((TileInfo.Food>=Hierarchy[iH,iT].Food) // new middle tile in this hierarchy 1233 and (TileInfo.Prod>=Hierarchy[iH,iT].Prod) 1234 and (TileInfo.Trade>=Hierarchy[iH,iT].Trade)) then 1235 break; // insert position found! 1236 inc(iH); 1237 end; 1238 if iH=nHierarchy then 1239 begin // need to start new hierarchy 1240 nTile[iH]:=0; 1241 inc(nHierarchy); 1242 iT:=0; 1243 end; 1244 move(Hierarchy[iH,iT], Hierarchy[iH,iT+1], (nTile[iH]-iT)*sizeof(TTileData)); 1245 inc(nTile[iH]); 1246 Hierarchy[iH,iT].V21:=V21; 1247 Hierarchy[iH,iT].Food:=TileInfo.Food; 1248 Hierarchy[iH,iT].Prod:=TileInfo.Prod; 1249 Hierarchy[iH,iT].Trade:=TileInfo.Trade; 1250 Hierarchy[iH,iT].SubValue:=SubCriterion[V21]; 1251 end 1252 end; 1253 if NeedRare<>0 then 1254 begin // rare tiles need own hierarchy 1255 iH:=nHierarchy; 1256 for V21:=1 to 26 do 1257 if (CityAreaInfo.Available[V21]=faAvailable) 1258 and (1 shl V21 and RareTiles<>0) then 1259 begin 1260 Loc1:=Radius[V21]; 1261 assert((V21<>CityOwnTile) and (Loc1>=0) and (Loc1<MapSize)); 1262 GetTileInfo(p,cix,Loc1,TileInfo); 1263 if iH=nHierarchy then 1264 begin // need to start new hierarchy 1265 nTile[iH]:=0; 1266 inc(nHierarchy); 1267 iT:=0; 1268 end 1269 else iT:=nTile[iH]; 1270 inc(nTile[iH]); 1271 Hierarchy[iH,iT].V21:=V21; 1272 Hierarchy[iH,iT].Food:=TileInfo.Food; // = 0 1273 Hierarchy[iH,iT].Prod:=TileInfo.Prod; // = 1 1274 Hierarchy[iH,iT].Trade:=TileInfo.Trade; // = 0 1275 Hierarchy[iH,iT].SubValue:=SubCriterion[V21]; 1276 end; 1277 end; 1278 if Built[imAlgae]>0 then 1279 inc(BaseTileInfo.Food,12); 1280 1281 // step 2: summarize resources 1282 for iH:=0 to nHierarchy-1 do 1283 begin 1284 move(Hierarchy[iH,0], Hierarchy[iH,1], nTile[iH]*sizeof(TTileData)); 1285 Hierarchy[iH,0].Food:=0; 1286 Hierarchy[iH,0].Prod:=0; 1287 Hierarchy[iH,0].Trade:=0; 1288 Hierarchy[iH,0].SubValue:=0; 1289 Hierarchy[iH,0].V21:=0; 1290 for iT:=1 to nTile[iH] do 1291 begin 1292 inc(Hierarchy[iH,iT].Food, Hierarchy[iH,iT-1].Food); 1293 inc(Hierarchy[iH,iT].Prod, Hierarchy[iH,iT-1].Prod); 1294 inc(Hierarchy[iH,iT].Trade, Hierarchy[iH,iT-1].Trade); 1295 inc(Hierarchy[iH,iT].SubValue, Hierarchy[iH,iT-1].SubValue); 1296 Hierarchy[iH,iT].V21:=1 shl Hierarchy[iH,iT].V21+Hierarchy[iH,iT-1].V21; 1297 end; 1298 end; 1299 1300 // step 3: try all combinations 1301 BestValue:=0.0; 1302 BestSuperValue:=0; 1303 BestSubValue:=0; 1304 BestTiles:=0; 1305 fillchar(nSelection, sizeof(nSelection),0); 1306 TestReport.FoodRep:=BaseTileInfo.Food; 1307 ProdBeforeBoost:=BaseTileInfo.Prod; 1308 TestReport.Trade:=BaseTileInfo.Trade; 1309 TestReport.Working:=1; 1310 MinFood:=0; 1311 MinProd:=0; 1312 iH_Switch:=nHierarchy; 1313 count:=0; 1314 repeat 1315 // ensure minima 1316 iH:=0; 1317 while (TestReport.Working<MaxWorking) and (iH<iH_Switch) 1318 and ((TestReport.Working<MinWorking) or (TestReport.FoodRep<TestReport.Eaten) 1319 or (ProdBeforeBoost<WantedProd)) do 1320 begin 1321 assert(nSelection[iH]=0); 1322 Take:=MinWorking-TestReport.Working; 1323 if Take>nTile[iH] then 1324 Take:=nTile[iH] 827 Flags := Flags and not chDisorder; 828 829 if not Disorder and ((Government = gFuture) or (Size >= NeedAqueductSize) 830 and (FoodSurplus < 2)) and (FoodSurplus > 0) then 831 inc(Money, FoodSurplus) 832 else if not(Disorder and (FoodSurplus > 0)) then 833 begin { calculate new food storage } 834 Food := Food + FoodSurplus; 835 if ((GTestFlags and tfImmGrow <> 0) or (Food >= CityStorage) and 836 (Food - FoodSurplus < CityStorage)) // only warn once 837 and (Size < MaxCitySize) and 838 (Project and (cpImp + cpIndex) <> cpImp + imAqueduct) and 839 (Project and (cpImp + cpIndex) <> cpImp + imSewer) and 840 not CanCityGrow(p, cix) then 841 inc(Flags, chNoGrowthWarning); 842 end; 843 844 if Prod > CityProjectCost then 845 begin 846 inc(Money, Prod - CityProjectCost); 847 Prod := CityProjectCost 848 end; 849 if Production < 0 then 850 Flags := Flags or chUnitLost 851 else if not Disorder and (Flags and chProductionSabotaged = 0) then 852 if Project and (cpImp + cpIndex) = cpImp + imTrGoods then 853 inc(Money, Production) 854 else 855 inc(Prod, Production); 856 857 if not Disorder then 858 begin 859 { sum research points and taxes } 860 inc(Research, Science); 861 inc(Money, Tax); 862 Pollution := Pollution + AddPollution; 863 end; 864 end; 865 end; 866 867 function CityTurn(p, cix: integer): boolean; 868 // return value: whether city keeps existing 869 var 870 i, uix, cix2, p1, SizeMod, CityStorage, CityProjectCost, NewImp, Det, 871 TestDet: integer; 872 LackOfMaterial, CheckGrow, DoProd, IsActive: boolean; 873 begin 874 with RW[p], City[cix] do 875 begin 876 SizeMod := 0; 877 CityStorage := StorageSize[Difficulty[p]]; 878 CityProjectCost := GetProjectCost(p, cix); 879 880 LackOfMaterial := Flags and chUnitLost <> 0; 881 Flags := Flags and not chUnitLost; 882 883 IsActive := (Government <> gAnarchy) and (Flags and chCaptured = 0); 884 CheckGrow := (Flags and chDisorder = 0) and IsActive and 885 (Government <> gFuture); 886 if CheckGrow and (GTestFlags and tfImmGrow <> 0) then { fast growth } 887 begin 888 if CanCityGrow(p, cix) then 889 inc(SizeMod) 890 end 891 else if CheckGrow and (Food >= CityStorage) then { normal growth } 892 begin 893 if CanCityGrow(p, cix) then 894 begin 895 if Built[imGranary] = 1 then 896 dec(Food, CityStorage shr 1) 897 else 898 dec(Food, CityStorage); 899 inc(SizeMod) 900 end 901 end 902 else if Food < 0 then { famine } 903 begin 904 Food := 0; 905 // check if settlers or conscripts there to disband 906 uix := -1; 907 for i := 0 to nUn - 1 do 908 if (Un[i].Loc >= 0) and (Un[i].Home = cix) and 909 ((Model[Un[i].mix].Kind = mkSettler) 910 { and (GWonder[woFreeSettlers].EffectiveOwner<>p) } 911 or (Un[i].Flags and unConscripts <> 0)) and 912 ((uix = -1) or (Model[Un[i].mix].Cost < Model[Un[uix].mix].Cost) or 913 (Model[Un[i].mix].Cost = Model[Un[uix].mix].Cost) and 914 (Un[i].Exp < Un[uix].Exp)) then 915 uix := i; 916 917 if uix >= 0 then 918 begin 919 RemoveUnit_UpdateMap(p, uix); 920 inc(Flags, chUnitLost); 921 end 1325 922 else 1326 begin 1327 if Take<0 then 1328 Take:=0; 1329 MaxTake:=nTile[iH]; 1330 if TestReport.Working+MaxTake>MaxWorking then 1331 MaxTake:=MaxWorking-TestReport.Working; 1332 while (Take<MaxTake) and (TestReport.FoodRep+Hierarchy[iH,Take].Food<MinFood) do 1333 inc(Take); 1334 while (Take<MaxTake) and (ProdBeforeBoost+Hierarchy[iH,Take].Prod<MinProd) do 1335 inc(Take); 1336 end; 1337 nSelection[iH]:=Take; 1338 inc(TestReport.Working, Take); 1339 with Hierarchy[iH,Take] do 1340 begin 1341 inc(TestReport.FoodRep,Food); 1342 inc(ProdBeforeBoost,Prod); 1343 inc(TestReport.Trade,Trade); 1344 end; 1345 inc(iH); 1346 end; 1347 1348 assert((TestReport.Working>=MinWorking) and (TestReport.Working<=MaxWorking)); 1349 if (TestReport.FoodRep>=MinFood) and (ProdBeforeBoost>=MinProd) then 1350 begin 1351 SplitTrade(TestReport.Trade,RW[p].TaxRate,RW[p].LuxRate,TestReport.Working, 1352 CityReportEx.TradeProcessing, TestReport.Corruption, TestReport.Tax, 1353 TestReport.Lux, TestReport.Science); 1354 1355 if CityReportEx.BaseHappiness+CityReportEx.BaseControl+TestReport.Lux 1356 +2*(Size-TestReport.Working)-2*TestReport.Deployed>=Size then 1357 begin // city is not in disorder -- evaluate combination 1358 inc(count); 1359 if (MinProd<WantedProd) and (ProdBeforeBoost>MinProd) then 1360 begin // no combination reached wanted prod yet 1361 MinProd:=ProdBeforeBoost; 1362 if MinProd>WantedProd then 1363 MinProd:=WantedProd 1364 end; 1365 if MinProd=WantedProd then // do not care for food before prod is ensured 1366 if (MinFood<TestReport.Eaten) and (TestReport.FoodRep>MinFood) then 1367 begin // no combination reached wanted food yet 1368 MinFood:=TestReport.FoodRep; 1369 if MinFood>TestReport.Eaten then 1370 MinFood:=TestReport.Eaten 1371 end; 1372 BoostProd(ProdBeforeBoost, CityReportEx.ProdProcessing, 1373 TestReport.ProdRep, TestReport.PollRep); 1374 SuperValue:=0; 1375 1376 // super-criterion A: unit support granted? 1377 if TestReport.ProdRep>=TestReport.Support then 1378 SuperValue:=SuperValue or 1 shl 30; 1379 1380 // super-criterion B: food demand granted? 1381 if TestReport.FoodRep>=TestReport.Eaten then 1382 SuperValue:=SuperValue or 63 shl 24 1383 else if TestReport.FoodRep>TestReport.Eaten-63 then 1384 SuperValue:=SuperValue or (63-(TestReport.Eaten-TestReport.FoodRep)) shl 24; 1385 1386 SuperPlus:=SuperValue-BestSuperValue; 1387 if SuperPlus>=0 then 1388 begin 1389 Output[oTax]:=TestReport.Tax; 1390 Output[oScience]:=TestReport.Science; 1391 1392 if TestReport.FoodRep<TestReport.Eaten then 1393 Output[oFood]:=TestReport.FoodRep 1394 // appreciate what we have, combination will have bad supervalue anyway 1395 else if FoodWasted then 1396 Output[oFood]:=0 1397 else 923 begin 924 dec(SizeMod); 925 inc(Flags, chPopDecrease) 926 end 927 end; 928 if Food > CityStorage then 929 Food := CityStorage; 930 931 if LackOfMaterial then 932 begin 933 if Flags and chUnitLost = 0 then 934 begin { one unit lost } 935 uix := -1; 936 Det := MaxInt; 937 for i := 0 to nUn - 1 do 938 if (Un[i].Loc >= 0) and (Un[i].Home = cix) then 939 with Model[Un[i].mix] do 1398 940 begin 1399 Output[oFood]:=TestReport.FoodRep-TestReport.Eaten; 1400 if FoodToTax or (Size>=NeedAqueductSize) and (Output[oFood]=1) then 941 if Kind = mkSpecial_TownGuard then 942 TestDet := Un[i].Health + Un[i].Exp shl 8 943 // disband townguards first 944 else 1401 945 begin 1402 inc(Output[oTax],Output[oFood]); 1403 Output[oFood]:=0; 946 TestDet := Un[i].Health + Un[i].Exp shl 8 + Cost shl 16; 947 // value of unit 948 if Flags and mdDoubleSupport <> 0 then 949 TestDet := TestDet shr 1; 950 // double support, tend to disband first 951 end; 952 if TestDet < Det then 953 begin 954 uix := i; 955 Det := TestDet 1404 956 end; 1405 957 end; 1406 1407 if TestReport.ProdRep<TestReport.Support then 1408 Output[oProd]:=TestReport.ProdRep 1409 // appreciate what we have, combination will have bad supervalue anyway 958 if uix >= 0 then 959 begin 960 RemoveUnit_UpdateMap(p, uix); 961 inc(Flags, chUnitLost); 962 end 963 end 964 end; 965 966 if GTestFlags and tfImmImprove <> 0 then 967 Prod := CityProjectCost; 968 DoProd := (Project and (cpImp + cpIndex) <> cpImp + imTrGoods) and 969 (Prod >= CityProjectCost); 970 971 // check if wonder already built 972 if (Project and cpImp <> 0) and (Project and cpIndex < 28) and 973 (GWonder[Project and cpIndex].CityID <> -1) then 974 begin 975 inc(Flags, chOldWonder); 976 DoProd := false; 977 end; 978 979 // check if producing settlers would disband city 980 if DoProd and (Project and (cpImp or cpDisbandCity) = 0) and 981 ((Size + SizeMod - 2 < 2) and 982 (Model[Project and cpIndex].Kind = mkSettler) or (Size + SizeMod - 1 < 2) 983 and ((Model[Project and cpIndex].Kind = mkSlaves) or 984 (Project and cpConscripts <> 0))) then 985 begin 986 inc(Flags, chNoSettlerProd); 987 DoProd := false; 988 end; 989 990 if DoProd then 991 begin { project complete } 992 dec(Prod, CityProjectCost); 993 if Project and cpImp = 0 then { produce unit } 994 begin 995 if nUn < numax then 996 begin 997 CreateUnit(p, Project and cpIndex); 998 Un[nUn - 1].Loc := Loc; 999 with Un[nUn - 1] do 1000 begin 1001 Home := cix; 1002 if (Model[mix].Domain < dSea) and (Built[imElite] = 1) then 1003 Exp := ExpCost * (nExp - 1) { elite } 1004 else if (Model[mix].Domain < dSea) and (Built[imBarracks] = 1) or 1005 (Model[mix].Domain = dSea) and (Built[imDockyard] = 1) or 1006 (Model[mix].Domain = dAir) and (Built[imAirport] = 1) then 1007 Exp := ExpCost * 2; { vet } 1008 if Project and cpConscripts <> 0 then 1009 Flags := Flags or unConscripts 1010 end; 1011 PlaceUnit(p, nUn - 1); 1012 UpdateUnitMap(Loc); 1013 if Model[Project and cpIndex].Kind = mkSettler then 1014 dec(SizeMod, 2) { settler produced - city shrink } 1015 else if (Model[Project and cpIndex].Kind = mkSlaves) or 1016 (Project and cpConscripts <> 0) then 1017 dec(SizeMod); { slaves/conscripts produced - city shrink } 1018 end; 1019 Project0 := Project or cpRepeat or cpCompleted; 1020 end 1021 else if Imp[Project and cpIndex].Kind = ikShipPart then 1022 begin { produce ship parts } 1023 inc(GShip[p].Parts[Project and cpIndex - imShipComp]); 1024 Project0 := Project or cpCompleted; 1025 end 1026 else { produce improvement } 1027 begin 1028 NewImp := Project and cpIndex; 1029 inc(Money, Prod); { change rest to money } 1030 Project0 := Project or cpCompleted; 1031 Project := cpImp + imTrGoods; 1032 Prod := 0; 1033 1034 if Imp[NewImp].Kind in [ikNatLocal, ikNatGlobal] then 1035 begin // nat. project 1036 for i := 0 to nCity - 1 do 1037 if (City[i].Loc >= 0) and (City[i].Built[NewImp] = 1) then 1038 begin { allowed only once } 1039 inc(Money, Imp[NewImp].Cost * BuildCostMod[Difficulty[p]] div 12); 1040 City[i].Built[NewImp] := 0; 1041 end; 1042 NatBuilt[NewImp] := 1; 1043 1044 // immediate nat. project effects 1045 case NewImp of 1046 imGrWall: 1047 GrWallContinent[p] := Continent[Loc]; 1048 end; 1049 end; 1050 1051 if NewImp < 28 then 1052 begin // wonder 1053 GWonder[NewImp].CityID := ID; 1054 GWonder[NewImp].EffectiveOwner := p; 1055 CheckExpiration(NewImp); 1056 1057 // immediate wonder effects 1058 case NewImp of 1059 woEiffel: 1060 begin // reactivate wonders 1061 for i := 0 to 27 do 1062 if Imp[i].Expiration >= 0 then 1063 for cix2 := 0 to nCity - 1 do 1064 if (City[cix2].Loc >= 0) and (City[cix2].Built[i] = 1) 1065 then 1066 GWonder[i].EffectiveOwner := p 1067 end; 1068 woLighthouse: 1069 CheckSpecialModels(p, preLighthouse); 1070 woLeo: 1071 begin 1072 inc(Research, TechBaseCost(nTech[p], Difficulty[p]) + 1073 TechBaseCost(nTech[p] + 2, Difficulty[p])); 1074 CheckSpecialModels(p, preLeo); 1075 end; 1076 woPyramids: 1077 CheckSpecialModels(p, preBuilder); 1078 woMir: 1079 begin 1080 for p1 := 0 to nPl - 1 do 1081 if (p1 <> p) and (1 shl p1 and GAlive <> 0) then 1082 begin 1083 if RW[p].Treaty[p1] = trNoContact then 1084 IntroduceEnemy(p, p1); 1085 GiveCivilReport(p, p1); 1086 GiveMilReport(p, p1) 1087 end; 1088 end 1089 end; 1090 end; 1091 1092 for i := 0 to nImpReplacement - 1 do // sell obsolete buildings 1093 if (ImpReplacement[i].NewImp = NewImp) and 1094 (Built[ImpReplacement[i].OldImp] > 0) then 1095 begin 1096 inc(RW[p].Money, Imp[ImpReplacement[i].OldImp].Cost * BuildCostMod 1097 [Difficulty[p]] div 12); 1098 Built[ImpReplacement[i].OldImp] := 0; 1099 end; 1100 1101 if NewImp in [imPower, imHydro, imNuclear] then 1102 for i := 0 to nImp - 1 do 1103 if (i <> NewImp) and (i in [imPower, imHydro, imNuclear]) and 1104 (Built[i] > 0) then 1105 begin // sell obsolete power plant 1106 inc(RW[p].Money, Imp[i].Cost * BuildCostMod[Difficulty[p] 1107 ] div 12); 1108 Built[i] := 0; 1109 end; 1110 1111 Built[NewImp] := 1; 1112 end; 1113 Prod0 := Prod; 1114 inc(Flags, chProduction) 1115 end 1116 else 1117 begin 1118 Project0 := Project0 and not cpCompleted; 1119 if Project0 and not cpAuto <> Project and not cpAuto then 1120 Project0 := Project; 1121 Prod0 := Prod; 1122 end; 1123 1124 if SizeMod > 0 then 1125 begin 1126 CityGrowth(p, cix); 1127 inc(Flags, chPopIncrease); 1128 end; 1129 result := Size + SizeMod >= 2; 1130 if result then 1131 while SizeMod < 0 do 1132 begin 1133 CityShrink(p, cix); 1134 inc(SizeMod) 1135 end; 1136 end 1137 end; // CityTurn 1138 1139 { 1140 Tile Access 1141 ____________________________________________________________________ 1142 } 1143 function SetCityTiles(p, cix, NewTiles: integer; 1144 TestOnly: boolean = false): integer; 1145 var 1146 V21, Working, ChangeTiles, AddTiles, Loc1: integer; 1147 CityAreaInfo: TCityAreaInfo; 1148 Radius: TVicinity21Loc; 1149 begin 1150 with RW[p].City[cix] do 1151 begin 1152 ChangeTiles := NewTiles xor integer(Tiles); 1153 AddTiles := NewTiles and not Tiles; 1154 if Mode = moPlaying then 1155 begin // do all checks 1156 if NewTiles and not $67F7F76 <> 0 then 1157 begin 1158 result := eInvalid; 1159 exit 1160 end; // invalid tile index included 1161 if NewTiles and (1 shl 13) = 0 then 1162 begin 1163 result := eViolation; 1164 exit 1165 end; // city tile must be exploited 1166 if ChangeTiles = 0 then 1167 begin 1168 result := eNotChanged; 1169 exit 1170 end; 1171 if AddTiles <> 0 then 1172 begin 1173 // check if new tiles possible 1174 GetCityAreaInfo(p, Loc, CityAreaInfo); 1175 for V21 := 1 to 26 do 1176 if AddTiles and (1 shl V21) <> 0 then 1177 if CityAreaInfo.Available[V21] <> faAvailable then 1178 begin 1179 result := eTileNotAvailable; 1180 exit 1181 end; 1182 // not more tiles than inhabitants 1183 Working := 0; 1184 for V21 := 1 to 26 do 1185 if NewTiles and (1 shl V21) <> 0 then 1186 inc(Working); 1187 if Working > Size then 1188 begin 1189 result := eNoWorkerAvailable; 1190 exit 1191 end; 1192 end; 1193 end; 1194 result := eOk; 1195 if not TestOnly then 1196 begin 1197 V21_to_Loc(Loc, Radius); 1198 for V21 := 1 to 26 do 1199 if ChangeTiles and (1 shl V21) <> 0 then 1200 begin 1201 Loc1 := Radius[V21]; 1202 assert((Loc1 >= 0) and (Loc1 < MapSize)); 1203 if NewTiles and (1 shl V21) <> 0 then 1204 UsedByCity[Loc1] := Loc // employ tile 1205 else if UsedByCity[Loc1] <> Loc then 1206 assert(Mode < moPlaying) 1207 // should only happen during loading, because of wrong sSetCityTiles command order 1410 1208 else 1209 UsedByCity[Loc1] := -1 // unemploy tile 1210 end; 1211 Tiles := NewTiles 1212 end 1213 end; 1214 end; 1215 1216 procedure GetCityTileAdvice(p, cix: integer; var Advice: TCityTileAdviceData); 1217 const 1218 oFood = 0; 1219 oProd = 1; 1220 oTax = 2; 1221 oScience = 3; 1222 type 1223 TTileData = record 1224 Food, Prod, Trade, SubValue, V21: integer; 1225 end; 1226 var 1227 i, V21, Loc1, nHierarchy, iH, iT, iH_Switch, MinWorking, MaxWorking, 1228 WantedProd, MinFood, MinProd, count, Take, MaxTake, AreaSize, FormulaCode, 1229 NeedRare, RareTiles, cix1, dx, dy, BestTiles, ProdBeforeBoost, TestTiles, 1230 SubPlus, SuperPlus: integer; 1231 SuperValue, BestSuperValue, SubValue, BestSubValue: integer; 1232 Value, BestValue, ValuePlus: extended; 1233 ValueFormula_Weight: array [oFood .. oScience] of extended; 1234 ValueFormula_Multiply: array [oFood .. oScience] of boolean; 1235 Output: array [oFood .. oScience] of integer; 1236 TileInfo, BaseTileInfo: TTileInfo; 1237 Radius, Radius1: TVicinity21Loc; 1238 TestReport: TCityReport; 1239 CityReportEx: TCityReportEx; 1240 CityAreaInfo: TCityAreaInfo; 1241 Hierarchy: array [0 .. 20, 0 .. 31] of TTileData; 1242 nTile, nSelection: array [0 .. 20] of integer; 1243 SubCriterion: array [0 .. 27] of integer; 1244 FoodWasted, FoodToTax, ProdToTax, RareOK, NeedStep2, IsBest: boolean; 1245 begin 1246 if (RW[p].Government = gAnarchy) or (RW[p].City[cix].Flags and chCaptured <> 0) 1247 then 1248 begin 1249 FillChar(Advice.CityReport, SizeOf(Advice.CityReport), 0); 1250 Advice.Tiles := 1 shl CityOwnTile; 1251 Advice.CityReport.HypoTiles := 1 shl CityOwnTile; 1252 exit; 1253 end; 1254 1255 for i := oFood to oScience do 1256 begin // decode evaluation formula from weights parameter 1257 FormulaCode := Advice.ResourceWeights shr (24 - 8 * i) and $FF; 1258 ValueFormula_Multiply[i] := FormulaCode and $80 <> 0; 1259 if FormulaCode and $40 <> 0 then 1260 ValueFormula_Weight[i] := (FormulaCode and $0F) * 1261 (1 shl (FormulaCode and $30 shr 4)) / 16 1262 else 1263 ValueFormula_Weight[i] := (FormulaCode and $0F) * 1264 (1 shl (FormulaCode and $30 shr 4)); 1265 end; 1266 1267 TestReport.HypoTiles := 1 shl CityOwnTile; 1268 TestReport.HypoTax := -1; 1269 TestReport.HypoLux := -1; 1270 GetSmallCityReport(p, cix, TestReport, @CityReportEx); 1271 with RW[p].City[cix] do 1272 begin 1273 V21_to_Loc(Loc, Radius); 1274 FoodToTax := RW[p].Government = gFuture; 1275 ProdToTax := Project and (cpImp + cpIndex) = cpImp + imTrGoods; 1276 FoodWasted := not FoodToTax and (Food = StorageSize[Difficulty[p]]) and 1277 not CanCityGrow(p, cix); 1278 1279 // sub criteria 1280 for V21 := 1 to 26 do 1281 begin 1282 Loc1 := Radius[V21]; 1283 if Loc1 >= 0 then 1284 SubCriterion[V21] := 3360 - (Distance(Loc, Loc1) - 1) * 32 - 1285 V21 xor $15; 1286 end; 1287 for cix1 := 0 to RW[p].nCity - 1 do 1288 if cix1 <> cix then 1289 begin 1290 Loc1 := RW[p].City[cix1].Loc; 1291 if Loc1 >= 0 then 1292 begin 1293 if Distance(Loc, Loc1) <= 10 then 1294 begin // cities overlap -- prefer tiles outside common range 1295 V21_to_Loc(Loc1, Radius1); 1296 for V21 := 1 to 26 do 1411 1297 begin 1412 if NeedRare>0 then 1298 Loc1 := Radius1[V21]; 1299 if (Loc1 >= 0) and (Loc1 < MapSize) and (Distance(Loc, Loc1) <= 5) 1300 then 1413 1301 begin 1414 RareOk:=false; 1415 for iH:=0 to nHierarchy-1 do 1416 if Hierarchy[iH,nSelection[iH]].V21 and RareTiles<>0 then 1417 RareOk:=true; 1418 if not RareOk then 1419 TestReport.ProdRep:=TestReport.Support; 1420 end; 1421 Output[oProd]:=TestReport.ProdRep-TestReport.Support; 1422 if ProdToTax then 1302 dxdy(Loc, Loc1, dx, dy); 1303 dec(SubCriterion[(dy + 3) shl 2 + (dx + 3) shr 1], 160); 1304 end 1305 end 1306 end 1307 end 1308 end; 1309 1310 GetCityAreaInfo(p, Loc, CityAreaInfo); 1311 AreaSize := 0; 1312 for V21 := 1 to 26 do 1313 if CityAreaInfo.Available[V21] = faAvailable then 1314 inc(AreaSize); 1315 1316 if RW[p].Government = gFundamentalism then 1317 begin 1318 MinWorking := Size; 1319 MaxWorking := Size; 1320 end 1321 else 1322 begin 1323 MinWorking := CityReportEx.TradeProcessing.HappyBase shr 1; 1324 if MinWorking > Size then 1325 MinWorking := Size; 1326 if (RW[p].LuxRate = 0) and not CityReportEx.TradeProcessing.FlexibleLuxury 1327 then 1328 MaxWorking := MinWorking 1329 else 1330 MaxWorking := Size; 1331 end; 1332 if MaxWorking > AreaSize then 1333 begin 1334 MaxWorking := AreaSize; 1335 if MinWorking > AreaSize then 1336 MinWorking := AreaSize; 1337 end; 1338 if TestReport.Support = 0 then 1339 WantedProd := 0 1340 else 1341 WantedProd := 1 + (TestReport.Support * 100 - 1) 1342 div (100 + CityReportEx.ProdProcessing.ProdBonus * 50 + 1343 CityReportEx.ProdProcessing.FutProdBonus); 1344 1345 // consider resources for ship parts 1346 NeedRare := 0; 1347 if (GTestFlags and tfNoRareNeed = 0) and (Project and cpImp <> 0) then 1348 case Project and cpIndex of 1349 imShipComp: 1350 NeedRare := fCobalt; 1351 imShipPow: 1352 NeedRare := fUranium; 1353 imShipHab: 1354 NeedRare := fMercury; 1355 end; 1356 if NeedRare > 0 then 1357 begin 1358 RareTiles := 0; 1359 for V21 := 1 to 26 do 1360 begin 1361 Loc1 := Radius[V21]; 1362 if (Loc1 >= 0) and (Loc1 < MapSize) and 1363 (RealMap[Loc1] and fModern = cardinal(NeedRare)) then 1364 RareTiles := RareTiles or (1 shl V21); 1365 end 1366 end; 1367 1368 // step 1: sort tiles to hierarchies 1369 nHierarchy := 0; 1370 for V21 := 1 to 26 do // non-rare tiles 1371 if (CityAreaInfo.Available[V21] = faAvailable) and 1372 ((NeedRare = 0) or (1 shl V21 and RareTiles = 0)) then 1373 begin 1374 Loc1 := Radius[V21]; 1375 assert((Loc1 >= 0) and (Loc1 < MapSize)); 1376 GetTileInfo(p, cix, Loc1, TileInfo); 1377 if V21 = CityOwnTile then 1378 BaseTileInfo := TileInfo 1379 else 1380 begin 1381 iH := 0; 1382 while iH < nHierarchy do 1383 begin 1384 iT := 0; 1385 while (iT < nTile[iH]) and (TileInfo.Food <= Hierarchy[iH, iT].Food) 1386 and (TileInfo.Prod <= Hierarchy[iH, iT].Prod) and 1387 (TileInfo.Trade <= Hierarchy[iH, iT].Trade) and 1388 not((TileInfo.Food = Hierarchy[iH, iT].Food) and 1389 (TileInfo.Prod = Hierarchy[iH, iT].Prod) and 1390 (TileInfo.Trade = Hierarchy[iH, iT].Trade) and 1391 (SubCriterion[V21] >= SubCriterion[Hierarchy[iH, iT].V21])) do 1392 inc(iT); 1393 if (iT = nTile[iH]) // new worst tile in this hierarchy 1394 or ((TileInfo.Food >= Hierarchy[iH, iT].Food) 1395 // new middle tile in this hierarchy 1396 and (TileInfo.Prod >= Hierarchy[iH, iT].Prod) and 1397 (TileInfo.Trade >= Hierarchy[iH, iT].Trade)) then 1398 break; // insert position found! 1399 inc(iH); 1400 end; 1401 if iH = nHierarchy then 1402 begin // need to start new hierarchy 1403 nTile[iH] := 0; 1404 inc(nHierarchy); 1405 iT := 0; 1406 end; 1407 move(Hierarchy[iH, iT], Hierarchy[iH, iT + 1], 1408 (nTile[iH] - iT) * SizeOf(TTileData)); 1409 inc(nTile[iH]); 1410 Hierarchy[iH, iT].V21 := V21; 1411 Hierarchy[iH, iT].Food := TileInfo.Food; 1412 Hierarchy[iH, iT].Prod := TileInfo.Prod; 1413 Hierarchy[iH, iT].Trade := TileInfo.Trade; 1414 Hierarchy[iH, iT].SubValue := SubCriterion[V21]; 1415 end 1416 end; 1417 if NeedRare <> 0 then 1418 begin // rare tiles need own hierarchy 1419 iH := nHierarchy; 1420 for V21 := 1 to 26 do 1421 if (CityAreaInfo.Available[V21] = faAvailable) and 1422 (1 shl V21 and RareTiles <> 0) then 1423 begin 1424 Loc1 := Radius[V21]; 1425 assert((V21 <> CityOwnTile) and (Loc1 >= 0) and (Loc1 < MapSize)); 1426 GetTileInfo(p, cix, Loc1, TileInfo); 1427 if iH = nHierarchy then 1428 begin // need to start new hierarchy 1429 nTile[iH] := 0; 1430 inc(nHierarchy); 1431 iT := 0; 1432 end 1433 else 1434 iT := nTile[iH]; 1435 inc(nTile[iH]); 1436 Hierarchy[iH, iT].V21 := V21; 1437 Hierarchy[iH, iT].Food := TileInfo.Food; // = 0 1438 Hierarchy[iH, iT].Prod := TileInfo.Prod; // = 1 1439 Hierarchy[iH, iT].Trade := TileInfo.Trade; // = 0 1440 Hierarchy[iH, iT].SubValue := SubCriterion[V21]; 1441 end; 1442 end; 1443 if Built[imAlgae] > 0 then 1444 inc(BaseTileInfo.Food, 12); 1445 1446 // step 2: summarize resources 1447 for iH := 0 to nHierarchy - 1 do 1448 begin 1449 move(Hierarchy[iH, 0], Hierarchy[iH, 1], nTile[iH] * SizeOf(TTileData)); 1450 Hierarchy[iH, 0].Food := 0; 1451 Hierarchy[iH, 0].Prod := 0; 1452 Hierarchy[iH, 0].Trade := 0; 1453 Hierarchy[iH, 0].SubValue := 0; 1454 Hierarchy[iH, 0].V21 := 0; 1455 for iT := 1 to nTile[iH] do 1456 begin 1457 inc(Hierarchy[iH, iT].Food, Hierarchy[iH, iT - 1].Food); 1458 inc(Hierarchy[iH, iT].Prod, Hierarchy[iH, iT - 1].Prod); 1459 inc(Hierarchy[iH, iT].Trade, Hierarchy[iH, iT - 1].Trade); 1460 inc(Hierarchy[iH, iT].SubValue, Hierarchy[iH, iT - 1].SubValue); 1461 Hierarchy[iH, iT].V21 := 1 shl Hierarchy[iH, iT].V21 + 1462 Hierarchy[iH, iT - 1].V21; 1463 end; 1464 end; 1465 1466 // step 3: try all combinations 1467 BestValue := 0.0; 1468 BestSuperValue := 0; 1469 BestSubValue := 0; 1470 BestTiles := 0; 1471 FillChar(nSelection, SizeOf(nSelection), 0); 1472 TestReport.FoodRep := BaseTileInfo.Food; 1473 ProdBeforeBoost := BaseTileInfo.Prod; 1474 TestReport.Trade := BaseTileInfo.Trade; 1475 TestReport.Working := 1; 1476 MinFood := 0; 1477 MinProd := 0; 1478 iH_Switch := nHierarchy; 1479 count := 0; 1480 repeat 1481 // ensure minima 1482 iH := 0; 1483 while (TestReport.Working < MaxWorking) and (iH < iH_Switch) and 1484 ((TestReport.Working < MinWorking) or 1485 (TestReport.FoodRep < TestReport.Eaten) or 1486 (ProdBeforeBoost < WantedProd)) do 1487 begin 1488 assert(nSelection[iH] = 0); 1489 Take := MinWorking - TestReport.Working; 1490 if Take > nTile[iH] then 1491 Take := nTile[iH] 1492 else 1493 begin 1494 if Take < 0 then 1495 Take := 0; 1496 MaxTake := nTile[iH]; 1497 if TestReport.Working + MaxTake > MaxWorking then 1498 MaxTake := MaxWorking - TestReport.Working; 1499 while (Take < MaxTake) and 1500 (TestReport.FoodRep + Hierarchy[iH, Take].Food < MinFood) do 1501 inc(Take); 1502 while (Take < MaxTake) and 1503 (ProdBeforeBoost + Hierarchy[iH, Take].Prod < MinProd) do 1504 inc(Take); 1505 end; 1506 nSelection[iH] := Take; 1507 inc(TestReport.Working, Take); 1508 with Hierarchy[iH, Take] do 1509 begin 1510 inc(TestReport.FoodRep, Food); 1511 inc(ProdBeforeBoost, Prod); 1512 inc(TestReport.Trade, Trade); 1513 end; 1514 inc(iH); 1515 end; 1516 1517 assert((TestReport.Working >= MinWorking) and 1518 (TestReport.Working <= MaxWorking)); 1519 if (TestReport.FoodRep >= MinFood) and (ProdBeforeBoost >= MinProd) then 1520 begin 1521 SplitTrade(TestReport.Trade, RW[p].TaxRate, RW[p].LuxRate, 1522 TestReport.Working, CityReportEx.TradeProcessing, 1523 TestReport.Corruption, TestReport.Tax, TestReport.Lux, 1524 TestReport.Science); 1525 1526 if CityReportEx.BaseHappiness + CityReportEx.BaseControl + 1527 TestReport.Lux + 2 * (Size - TestReport.Working) - 2 * 1528 TestReport.Deployed >= Size then 1529 begin // city is not in disorder -- evaluate combination 1530 inc(count); 1531 if (MinProd < WantedProd) and (ProdBeforeBoost > MinProd) then 1532 begin // no combination reached wanted prod yet 1533 MinProd := ProdBeforeBoost; 1534 if MinProd > WantedProd then 1535 MinProd := WantedProd 1536 end; 1537 if MinProd = WantedProd then 1538 // do not care for food before prod is ensured 1539 if (MinFood < TestReport.Eaten) and (TestReport.FoodRep > MinFood) 1540 then 1541 begin // no combination reached wanted food yet 1542 MinFood := TestReport.FoodRep; 1543 if MinFood > TestReport.Eaten then 1544 MinFood := TestReport.Eaten 1545 end; 1546 BoostProd(ProdBeforeBoost, CityReportEx.ProdProcessing, 1547 TestReport.ProdRep, TestReport.PollRep); 1548 SuperValue := 0; 1549 1550 // super-criterion A: unit support granted? 1551 if TestReport.ProdRep >= TestReport.Support then 1552 SuperValue := SuperValue or 1 shl 30; 1553 1554 // super-criterion B: food demand granted? 1555 if TestReport.FoodRep >= TestReport.Eaten then 1556 SuperValue := SuperValue or 63 shl 24 1557 else if TestReport.FoodRep > TestReport.Eaten - 63 then 1558 SuperValue := SuperValue or 1559 (63 - (TestReport.Eaten - TestReport.FoodRep)) shl 24; 1560 1561 SuperPlus := SuperValue - BestSuperValue; 1562 if SuperPlus >= 0 then 1563 begin 1564 Output[oTax] := TestReport.Tax; 1565 Output[oScience] := TestReport.Science; 1566 1567 if TestReport.FoodRep < TestReport.Eaten then 1568 Output[oFood] := TestReport.FoodRep 1569 // appreciate what we have, combination will have bad supervalue anyway 1570 else if FoodWasted then 1571 Output[oFood] := 0 1572 else 1573 begin 1574 Output[oFood] := TestReport.FoodRep - TestReport.Eaten; 1575 if FoodToTax or (Size >= NeedAqueductSize) and (Output[oFood] = 1) 1576 then 1423 1577 begin 1424 inc(Output[oTax],Output[oProd]);1425 Output[oProd]:=0;1578 inc(Output[oTax], Output[oFood]); 1579 Output[oFood] := 0; 1426 1580 end; 1427 1581 end; 1428 1582 1429 NeedStep2:=false; 1430 Value:=0; 1431 for i:=oFood to oScience do 1432 if ValueFormula_Multiply[i] then 1433 NeedStep2:=true 1434 else Value:=Value+ValueFormula_Weight[i]*Output[i]; 1435 if NeedStep2 then 1583 if TestReport.ProdRep < TestReport.Support then 1584 Output[oProd] := TestReport.ProdRep 1585 // appreciate what we have, combination will have bad supervalue anyway 1586 else 1436 1587 begin 1437 if Value>0 then 1438 Value:=ln(Value)+123; 1439 for i:=oFood to oScience do 1440 if ValueFormula_Multiply[i] and (Output[i]>0) then 1441 Value:=Value+ValueFormula_Weight[i]*(ln(Output[i])+123); 1588 if NeedRare > 0 then 1589 begin 1590 RareOK := false; 1591 for iH := 0 to nHierarchy - 1 do 1592 if Hierarchy[iH, nSelection[iH]].V21 and RareTiles <> 0 then 1593 RareOK := true; 1594 if not RareOK then 1595 TestReport.ProdRep := TestReport.Support; 1596 end; 1597 Output[oProd] := TestReport.ProdRep - TestReport.Support; 1598 if ProdToTax then 1599 begin 1600 inc(Output[oTax], Output[oProd]); 1601 Output[oProd] := 0; 1602 end; 1442 1603 end; 1443 1604 1444 ValuePlus:=Value-BestValue; 1445 if (SuperPlus>0) or (ValuePlus>=0.0) then 1605 NeedStep2 := false; 1606 Value := 0; 1607 for i := oFood to oScience do 1608 if ValueFormula_Multiply[i] then 1609 NeedStep2 := true 1610 else 1611 Value := Value + ValueFormula_Weight[i] * Output[i]; 1612 if NeedStep2 then 1446 1613 begin 1447 SubValue:=(TestReport.FoodRep+ProdBeforeBoost+TestReport.Trade) shl 18; 1448 TestTiles:=1 shl CityOwnTile; 1449 for iH:=0 to nHierarchy-1 do 1614 if Value > 0 then 1615 Value := ln(Value) + 123; 1616 for i := oFood to oScience do 1617 if ValueFormula_Multiply[i] and (Output[i] > 0) then 1618 Value := Value + ValueFormula_Weight[i] * 1619 (ln(Output[i]) + 123); 1620 end; 1621 1622 ValuePlus := Value - BestValue; 1623 if (SuperPlus > 0) or (ValuePlus >= 0.0) then 1624 begin 1625 SubValue := (TestReport.FoodRep + ProdBeforeBoost + 1626 TestReport.Trade) shl 18; 1627 TestTiles := 1 shl CityOwnTile; 1628 for iH := 0 to nHierarchy - 1 do 1450 1629 begin 1451 inc(TestTiles, Hierarchy[iH,nSelection[iH]].V21);1452 inc(SubValue, Hierarchy[iH,nSelection[iH]].SubValue);1630 inc(TestTiles, Hierarchy[iH, nSelection[iH]].V21); 1631 inc(SubValue, Hierarchy[iH, nSelection[iH]].SubValue); 1453 1632 end; 1454 IsBest:=true;1455 if (SuperPlus=0) and (ValuePlus=0.0) then1633 IsBest := true; 1634 if (SuperPlus = 0) and (ValuePlus = 0.0) then 1456 1635 begin 1457 SubPlus:=SubValue-BestSubValue;1458 if SubPlus<0 then1459 IsBest:=false1460 else if SubPlus=0 then1636 SubPlus := SubValue - BestSubValue; 1637 if SubPlus < 0 then 1638 IsBest := false 1639 else if SubPlus = 0 then 1461 1640 begin 1462 assert(TestTiles<>BestTiles);1463 IsBest:= TestTiles>BestTiles1641 assert(TestTiles <> BestTiles); 1642 IsBest := TestTiles > BestTiles 1464 1643 end 1465 1644 end; 1466 if IsBest then1645 if IsBest then 1467 1646 begin 1468 BestSuperValue:=SuperValue; 1469 BestValue:=Value; 1470 BestSubValue:=SubValue; 1471 BestTiles:=TestTiles; 1472 TestReport.Happy:=(CityReportEx.TradeProcessing.HappyBase-Size) div 2 1473 +TestReport.Lux shr 1; 1474 Advice.CityReport:=TestReport; 1647 BestSuperValue := SuperValue; 1648 BestValue := Value; 1649 BestSubValue := SubValue; 1650 BestTiles := TestTiles; 1651 TestReport.Happy := 1652 (CityReportEx.TradeProcessing.HappyBase - Size) div 2 + 1653 TestReport.Lux shr 1; 1654 Advice.CityReport := TestReport; 1475 1655 end 1476 1656 end // if (SuperPlus>0) or (ValuePlus>=0.0) … … 1479 1659 end; 1480 1660 1481 // calculate next combination1482 iH_Switch:=0;1483 repeat1484 with Hierarchy[iH_Switch,nSelection[iH_Switch]] do1661 // calculate next combination 1662 iH_Switch := 0; 1663 repeat 1664 with Hierarchy[iH_Switch, nSelection[iH_Switch]] do 1485 1665 begin 1486 dec(TestReport.FoodRep,Food);1487 dec(ProdBeforeBoost,Prod);1488 dec(TestReport.Trade,Trade);1666 dec(TestReport.FoodRep, Food); 1667 dec(ProdBeforeBoost, Prod); 1668 dec(TestReport.Trade, Trade); 1489 1669 end; 1490 inc(nSelection[iH_Switch]); 1491 inc(TestReport.Working); 1492 if (nSelection[iH_Switch]<=nTile[iH_Switch]) and (TestReport.Working<=MaxWorking) then 1670 inc(nSelection[iH_Switch]); 1671 inc(TestReport.Working); 1672 if (nSelection[iH_Switch] <= nTile[iH_Switch]) and 1673 (TestReport.Working <= MaxWorking) then 1493 1674 begin 1494 with Hierarchy[iH_Switch,nSelection[iH_Switch]] do1675 with Hierarchy[iH_Switch, nSelection[iH_Switch]] do 1495 1676 begin 1496 inc(TestReport.FoodRep,Food);1497 inc(ProdBeforeBoost,Prod);1498 inc(TestReport.Trade,Trade);1677 inc(TestReport.FoodRep, Food); 1678 inc(ProdBeforeBoost, Prod); 1679 inc(TestReport.Trade, Trade); 1499 1680 end; 1500 break;1681 break; 1501 1682 end; 1502 dec(TestReport.Working,nSelection[iH_Switch]);1503 nSelection[iH_Switch]:=0;1504 inc(iH_Switch);1505 until iH_Switch=nHierarchy;1506 until iH_Switch=nHierarchy; // everything tested -- done1683 dec(TestReport.Working, nSelection[iH_Switch]); 1684 nSelection[iH_Switch] := 0; 1685 inc(iH_Switch); 1686 until iH_Switch = nHierarchy; 1687 until iH_Switch = nHierarchy; // everything tested -- done 1507 1688 end; 1508 assert(BestSuperValue>0); // advice should always be possible1509 Advice.Tiles:=BestTiles;1510 Advice.CityReport.HypoTiles:=BestTiles;1689 assert(BestSuperValue > 0); // advice should always be possible 1690 Advice.Tiles := BestTiles; 1691 Advice.CityReport.HypoTiles := BestTiles; 1511 1692 end; // GetCityTileAdvice 1512 1693 1513 1694 { 1514 Start/End Game1515 ____________________________________________________________________1695 Start/End Game 1696 ____________________________________________________________________ 1516 1697 } 1517 1698 procedure InitGame; 1518 1699 var 1519 p,i,mixTownGuard: integer; 1520 begin 1521 MaxDist:=Distance(0,MapSize-lx shr 1); 1522 for p:=0 to nPl-1 do if (1 shl p and GAlive<>0) then with RW[p] do 1523 begin // initialize capital 1524 mixTownGuard:=0; 1525 while Model[mixTownGuard].Kind<>mkSpecial_TownGuard do 1526 inc(mixTownGuard); 1527 with City[0] do 1528 begin 1529 Built[imPalace]:=1; 1530 Size:=4; 1531 for i:=2 to Size do 1532 AddBestCityTile(p,0); 1533 Project:=mixTownGuard; 1534 end; 1535 NatBuilt[imPalace]:=1; 1536 end; 1700 p, i, mixTownGuard: integer; 1701 begin 1702 MaxDist := Distance(0, MapSize - lx shr 1); 1703 for p := 0 to nPl - 1 do 1704 if (1 shl p and GAlive <> 0) then 1705 with RW[p] do 1706 begin // initialize capital 1707 mixTownGuard := 0; 1708 while Model[mixTownGuard].Kind <> mkSpecial_TownGuard do 1709 inc(mixTownGuard); 1710 with City[0] do 1711 begin 1712 Built[imPalace] := 1; 1713 Size := 4; 1714 for i := 2 to Size do 1715 AddBestCityTile(p, 0); 1716 Project := mixTownGuard; 1717 end; 1718 NatBuilt[imPalace] := 1; 1719 end; 1537 1720 end; 1538 1721 … … 1542 1725 1543 1726 end. 1544 -
trunk/CmdList.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit CmdList; 4 3 … … 6 5 7 6 uses 8 Classes;7 Classes; 9 8 10 9 const 11 MaxDataSize=1024;10 MaxDataSize = 1024; 12 11 13 12 type 14 TLogData=array[0..999999999] of Byte;15 16 TCmdListState=record17 nLog, {used size of LogData in bytes}18 LoadPos, {position in LogData when loading a game}19 LastMovingUnit: integer;20 MoveCode, LoadMoveCode: Cardinal;13 TLogData = array [0 .. 999999999] of Byte; 14 15 TCmdListState = record 16 nLog, { used size of LogData in bytes } 17 LoadPos, { position in LogData when loading a game } 18 LastMovingUnit: integer; 19 MoveCode, LoadMoveCode: Cardinal; 21 20 end; 22 21 23 TCmdList=class 24 constructor Create; 25 destructor Destroy; override; 26 procedure Get(var Command, Player, Subject: integer; var Data: pointer); 27 procedure GetDataChanges(Data: pointer; DataSize: integer); 28 procedure Put(Command, Player, Subject: integer; Data: pointer); 29 procedure PutDataChanges(Command, Player: integer; OldData, NewData: pointer; DataSize: integer); 30 procedure LoadFromFile(const f: TFileStream); 31 procedure SaveToFile(const f: TFileStream); 32 procedure AppendToFile(const f: TFileStream; const OldState: TCmdListState); 33 procedure Cut; 34 function Progress: integer; 35 private 36 LogAlloc: integer; {allocated size of LogData in bytes} 37 LogData: ^TLogData; 38 FState: TCmdListState; 39 procedure PutData(Data: pointer; Length: integer); 40 procedure CompleteMoveCode; 41 public 42 property State: TCmdListState read FState write FState; 22 TCmdList = class 23 constructor Create; 24 destructor Destroy; override; 25 procedure Get(var Command, Player, Subject: integer; var Data: pointer); 26 procedure GetDataChanges(Data: pointer; DataSize: integer); 27 procedure Put(Command, Player, Subject: integer; Data: pointer); 28 procedure PutDataChanges(Command, Player: integer; 29 OldData, NewData: pointer; DataSize: integer); 30 procedure LoadFromFile(const f: TFileStream); 31 procedure SaveToFile(const f: TFileStream); 32 procedure AppendToFile(const f: TFileStream; const OldState: TCmdListState); 33 procedure Cut; 34 function Progress: integer; 35 private 36 LogAlloc: integer; { allocated size of LogData in bytes } 37 LogData: ^TLogData; 38 FState: TCmdListState; 39 procedure PutData(Data: pointer; Length: integer); 40 procedure CompleteMoveCode; 41 public 42 property State: TCmdListState read FState write FState; 43 43 end; 44 44 … … 46 46 47 47 uses 48 Protocol;48 Protocol; 49 49 50 50 const 51 LogGrow=1 shl 18;51 LogGrow = 1 shl 18; 52 52 53 53 type 54 TData=array[0..MaxDataSize-1] of Cardinal;55 PData=^TData;54 TData = array [0 .. MaxDataSize - 1] of Cardinal; 55 PData = ^TData; 56 56 57 57 constructor TCmdList.Create; 58 58 begin 59 inherited Create;60 FState.nLog:=0;61 LogAlloc:=0;62 LogData:=nil;63 FState.LastMovingUnit:=-1;64 FState.MoveCode:=0;65 FState.LoadMoveCode:=0;59 inherited Create; 60 FState.nLog := 0; 61 LogAlloc := 0; 62 LogData := nil; 63 FState.LastMovingUnit := -1; 64 FState.MoveCode := 0; 65 FState.LoadMoveCode := 0; 66 66 end; 67 67 68 68 destructor TCmdList.Destroy; 69 69 begin 70 ReallocMem(LogData, 0); 71 inherited Destroy; 72 end; 73 74 procedure TCmdList.Get(var Command, Player, Subject: integer; var Data: pointer); 70 ReallocMem(LogData, 0); 71 inherited Destroy; 72 end; 73 74 procedure TCmdList.Get(var Command, Player, Subject: integer; 75 var Data: pointer); 75 76 var 76 DirCode, code: Cardinal;77 begin 78 if FState.LoadMoveCode>0 then79 begin 80 Player:=-1;81 if FState.LoadMoveCode and 1=1 then77 DirCode, code: Cardinal; 78 begin 79 if FState.LoadMoveCode > 0 then 80 begin 81 Player := -1; 82 if FState.LoadMoveCode and 1 = 1 then 82 83 begin // FM 83 DirCode:=FState.LoadMoveCode shr 1 and 7; 84 Subject:=FState.LastMovingUnit; 85 FState.LoadMoveCode:=FState.LoadMoveCode shr 4; 86 end 84 DirCode := FState.LoadMoveCode shr 1 and 7; 85 Subject := FState.LastMovingUnit; 86 FState.LoadMoveCode := FState.LoadMoveCode shr 4; 87 end 88 else 89 begin // M 90 DirCode := FState.LoadMoveCode shr 3 and 7; 91 Subject := FState.LoadMoveCode shr 6 and $FFF; 92 FState.LoadMoveCode := FState.LoadMoveCode shr 18; 93 FState.LastMovingUnit := Subject 94 end; 95 case DirCode of 96 0: 97 Command := sMoveUnit + $090; 98 1: 99 Command := sMoveUnit + $0F0; 100 2: 101 Command := sMoveUnit + $390; 102 3: 103 Command := sMoveUnit + $3F0; 104 4: 105 Command := sMoveUnit + $020; 106 5: 107 Command := sMoveUnit + $060; 108 6: 109 Command := sMoveUnit + $100; 110 7: 111 Command := sMoveUnit + $300; 112 end; 113 Data := nil; 114 end 87 115 else 88 begin // M 89 DirCode:=FState.LoadMoveCode shr 3 and 7; 90 Subject:=FState.LoadMoveCode shr 6 and $FFF; 91 FState.LoadMoveCode:=FState.LoadMoveCode shr 18; 92 FState.LastMovingUnit:=Subject 93 end; 94 case DirCode of 95 0: Command:=sMoveUnit+$090; 96 1: Command:=sMoveUnit+$0F0; 97 2: Command:=sMoveUnit+$390; 98 3: Command:=sMoveUnit+$3F0; 99 4: Command:=sMoveUnit+$020; 100 5: Command:=sMoveUnit+$060; 101 6: Command:=sMoveUnit+$100; 102 7: Command:=sMoveUnit+$300; 103 end; 104 Data:=nil; 105 end 106 else 107 begin 108 code:=Cardinal((@LogData[FState.LoadPos])^); 109 if code and 3=0 then 116 begin 117 code := Cardinal((@LogData[FState.LoadPos])^); 118 if code and 3 = 0 then 110 119 begin // non-clientex command 111 Command:=code shr 2 and $3FFF +sExecute;112 Player:=code shr 16 and $f;113 Subject:=code shr 20 and $FFF;114 inc(FState.LoadPos,4);115 end 116 else if code and 7=2 then120 Command := code shr 2 and $3FFF + sExecute; 121 Player := code shr 16 and $F; 122 Subject := code shr 20 and $FFF; 123 inc(FState.LoadPos, 4); 124 end 125 else if code and 7 = 2 then 117 126 begin // clientex command 118 Command:=code shr 3 and $FFFF;119 Player:=code shr 19 and $f;120 Subject:=0;121 inc(FState.LoadPos,3);122 end 123 else127 Command := code shr 3 and $FFFF; 128 Player := code shr 19 and $F; 129 Subject := 0; 130 inc(FState.LoadPos, 3); 131 end 132 else 124 133 begin // move command shortcut 125 if (code and 1=1) and (code and (7 shl 4)<>6 shl 4) then 126 begin FState.LoadMoveCode:=code and $FF; inc(FState.LoadPos) end 127 else begin FState.LoadMoveCode:=code and $FFFFFF; inc(FState.LoadPos,3); end; 128 Get(Command, Player, Subject, Data); 129 exit; 130 end; 131 132 if Command and $f=0 then Data:=nil 133 else 134 begin 135 Data:=@LogData[FState.LoadPos]; 136 inc(FState.LoadPos,Command and $f *4); 134 if (code and 1 = 1) and (code and (7 shl 4) <> 6 shl 4) then 135 begin 136 FState.LoadMoveCode := code and $FF; 137 inc(FState.LoadPos) 138 end 139 else 140 begin 141 FState.LoadMoveCode := code and $FFFFFF; 142 inc(FState.LoadPos, 3); 143 end; 144 Get(Command, Player, Subject, Data); 145 exit; 146 end; 147 148 if Command and $F = 0 then 149 Data := nil 150 else 151 begin 152 Data := @LogData[FState.LoadPos]; 153 inc(FState.LoadPos, Command and $F * 4); 137 154 end 138 155 end … … 141 158 procedure TCmdList.GetDataChanges(Data: pointer; DataSize: integer); 142 159 var 143 b0, b1: integer; 144 Map0, Map1: Cardinal; 145 begin 146 Map0:=Cardinal((@LogData[FState.LoadPos])^); 147 inc(FState.LoadPos,4); 148 b0:=0; 149 while Map0>0 do 150 begin 151 if Map0 and 1<>0 then 152 begin 153 Map1:=Cardinal((@LogData[FState.LoadPos])^); 154 inc(FState.LoadPos,4); 155 for b1:=0 to 31 do if 1 shl b1 and Map1<>0 then 156 begin 157 if b0*32+b1<DataSize then 158 PData(Data)[b0*32+b1]:=Cardinal((@LogData[FState.LoadPos])^); 159 inc(FState.LoadPos,4); 160 end; 161 end; 162 inc(b0); 163 Map0:=Map0 shr 1; 160 b0, b1: integer; 161 Map0, Map1: Cardinal; 162 begin 163 Map0 := Cardinal((@LogData[FState.LoadPos])^); 164 inc(FState.LoadPos, 4); 165 b0 := 0; 166 while Map0 > 0 do 167 begin 168 if Map0 and 1 <> 0 then 169 begin 170 Map1 := Cardinal((@LogData[FState.LoadPos])^); 171 inc(FState.LoadPos, 4); 172 for b1 := 0 to 31 do 173 if 1 shl b1 and Map1 <> 0 then 174 begin 175 if b0 * 32 + b1 < DataSize then 176 PData(Data)[b0 * 32 + b1] := Cardinal((@LogData[FState.LoadPos])^); 177 inc(FState.LoadPos, 4); 178 end; 179 end; 180 inc(b0); 181 Map0 := Map0 shr 1; 164 182 end 165 183 end; … … 167 185 procedure TCmdList.Put(Command, Player, Subject: integer; Data: pointer); 168 186 var 169 DirCode, code: Cardinal;170 begin 171 if Command and $FC00=sMoveUnit then187 DirCode, code: Cardinal; 188 begin 189 if Command and $FC00 = sMoveUnit then 172 190 begin // move command shortcut 173 case Command of 174 sMoveUnit+$090: DirCode:=0; 175 sMoveUnit+$0F0: DirCode:=1; 176 sMoveUnit+$390: DirCode:=2; 177 sMoveUnit+$3F0: DirCode:=3; 178 sMoveUnit+$020: DirCode:=4; 179 sMoveUnit+$060: DirCode:=5; 180 sMoveUnit+$100: DirCode:=6; 181 sMoveUnit+$300: DirCode:=7; 182 end; 183 if Subject=FState.LastMovingUnit then code:=1+DirCode shl 1 184 else code:=6+DirCode shl 3+Cardinal(Subject) shl 6; 185 if FState.MoveCode=0 then FState.MoveCode:=code 186 else if FState.MoveCode and 1=1 then 191 case Command of 192 sMoveUnit + $090: 193 DirCode := 0; 194 sMoveUnit + $0F0: 195 DirCode := 1; 196 sMoveUnit + $390: 197 DirCode := 2; 198 sMoveUnit + $3F0: 199 DirCode := 3; 200 sMoveUnit + $020: 201 DirCode := 4; 202 sMoveUnit + $060: 203 DirCode := 5; 204 sMoveUnit + $100: 205 DirCode := 6; 206 sMoveUnit + $300: 207 DirCode := 7; 208 end; 209 if Subject = FState.LastMovingUnit then 210 code := 1 + DirCode shl 1 211 else 212 code := 6 + DirCode shl 3 + Cardinal(Subject) shl 6; 213 if FState.MoveCode = 0 then 214 FState.MoveCode := code 215 else if FState.MoveCode and 1 = 1 then 187 216 begin // FM + this 188 FState.MoveCode:=FState.MoveCode+code shl 4; 189 if code and 1=1 then PutData(@FState.MoveCode, 1) // FM + FM 190 else PutData(@FState.MoveCode, 3); // FM + M 191 FState.MoveCode:=0; 192 end 193 else if code and 1=1 then 217 FState.MoveCode := FState.MoveCode + code shl 4; 218 if code and 1 = 1 then 219 PutData(@FState.MoveCode, 1) // FM + FM 220 else 221 PutData(@FState.MoveCode, 3); // FM + M 222 FState.MoveCode := 0; 223 end 224 else if code and 1 = 1 then 194 225 begin // M + FM 195 FState.MoveCode:=FState.MoveCode+code shl 18;196 PutData(@FState.MoveCode, 3);197 FState.MoveCode:=0;198 end 199 else // M + M200 begin 201 PutData(@FState.MoveCode, 3);202 FState.MoveCode:=code203 end; 204 FState.LastMovingUnit:=Subject;226 FState.MoveCode := FState.MoveCode + code shl 18; 227 PutData(@FState.MoveCode, 3); 228 FState.MoveCode := 0; 229 end 230 else // M + M 231 begin 232 PutData(@FState.MoveCode, 3); 233 FState.MoveCode := code 234 end; 235 FState.LastMovingUnit := Subject; 205 236 end 206 else 207 begin 237 else 238 begin 239 CompleteMoveCode; 240 if Command >= cClientEx then 241 begin 242 code := 2 + Command shl 3 + Player shl 19; 243 PutData(@code, 3); 244 end 245 else 246 begin 247 code := Cardinal(Command - sExecute) shl 2 + Cardinal(Player) shl 16 + 248 Cardinal(Subject) shl 20; 249 PutData(@code, 4); 250 end; 251 end; 252 if Command and $F <> 0 then 253 PutData(Data, Command and $F * 4); 254 end; 255 256 procedure TCmdList.PutDataChanges(Command, Player: integer; 257 OldData, NewData: pointer; DataSize: integer); 258 var 259 MapPos, LogPos, b0, b1, RowEnd: integer; 260 Map0, Map1, code: Cardinal; 261 begin 262 if DataSize <= 0 then 263 exit; 264 if DataSize > MaxDataSize then 265 DataSize := MaxDataSize; 208 266 CompleteMoveCode; 209 if Command>=cClientEx then 210 begin 211 code:=2+Command shl 3+Player shl 19; 212 PutData(@code, 3); 213 end 214 else 215 begin 216 code:=Cardinal(Command-sExecute) shl 2+Cardinal(Player) shl 16 217 +Cardinal(Subject) shl 20; 218 PutData(@code, 4); 267 MapPos := FState.nLog + 8; 268 LogPos := MapPos + 4; 269 Map0 := 0; 270 for b0 := 0 to (DataSize - 1) div 32 do 271 begin 272 if LogPos + 4 * 32 > LogAlloc then 273 begin 274 inc(LogAlloc, LogGrow); 275 ReallocMem(LogData, LogAlloc); 276 end; 277 Map0 := Map0 shr 1; 278 Map1 := 0; 279 RowEnd := DataSize - 1; 280 if RowEnd > b0 * 32 + 31 then 281 RowEnd := b0 * 32 + 31; 282 for b1 := b0 * 32 to RowEnd do 283 begin 284 Map1 := Map1 shr 1; 285 if PData(NewData)[b1] <> PData(OldData)[b1] then 286 begin 287 Cardinal((@LogData[LogPos])^) := PData(NewData)[b1]; 288 inc(LogPos, 4); 289 inc(Map1, $80000000); 290 end; 291 end; 292 if Map1 > 0 then 293 begin 294 Map1 := Map1 shr (b0 * 32 + 31 - RowEnd); 295 Cardinal((@LogData[MapPos])^) := Map1; 296 MapPos := LogPos; 297 inc(LogPos, 4); 298 inc(Map0, $80000000); 219 299 end; 220 300 end; 221 if Command and $f<>0 then PutData(Data, Command and $f *4); 222 end; 223 224 procedure TCmdList.PutDataChanges(Command, Player: integer; OldData, 225 NewData: pointer; DataSize: integer); 226 var 227 MapPos, LogPos, b0, b1, RowEnd: integer; 228 Map0, Map1, code: Cardinal; 229 begin 230 if DataSize<=0 then exit; 231 if DataSize>MaxDataSize then DataSize:=MaxDataSize; 232 CompleteMoveCode; 233 MapPos:=FState.nLog+8; 234 LogPos:=MapPos+4; 235 Map0:=0; 236 for b0:=0 to (DataSize-1) div 32 do 237 begin 238 if LogPos+4*32>LogAlloc then 239 begin 301 if Map0 = 0 then 302 exit; // no changes 303 304 Map0 := Map0 shr (31 - (DataSize - 1) div 32); 305 Cardinal((@LogData[FState.nLog + 4])^) := Map0; 306 code := Cardinal(Command - sExecute) shl 2 + Cardinal(Player) shl 16; 307 Cardinal((@LogData[FState.nLog])^) := code; 308 FState.nLog := MapPos 309 end; 310 311 procedure TCmdList.PutData(Data: pointer; Length: integer); 312 begin 313 if FState.nLog + Length > LogAlloc then 314 begin 240 315 inc(LogAlloc, LogGrow); 241 316 ReallocMem(LogData, LogAlloc); 242 end;243 Map0:=Map0 shr 1;244 Map1:=0;245 RowEnd:=DataSize-1;246 if RowEnd>b0*32+31 then RowEnd:=b0*32+31;247 for b1:=b0*32 to RowEnd do248 begin249 Map1:=Map1 shr 1;250 if PData(NewData)[b1]<>PData(OldData)[b1] then251 begin252 Cardinal((@LogData[LogPos])^):=PData(NewData)[b1];253 inc(LogPos,4);254 inc(Map1,$80000000);255 end;256 end;257 if Map1>0 then258 begin259 Map1:=Map1 shr (b0*32+31-RowEnd);260 Cardinal((@LogData[MapPos])^):=Map1;261 MapPos:=LogPos;262 inc(LogPos,4);263 inc(Map0,$80000000);264 end;265 317 end; 266 if Map0=0 then exit; // no changes 267 268 Map0:=Map0 shr (31-(DataSize-1) div 32); 269 Cardinal((@LogData[FState.nLog+4])^):=Map0; 270 code:=Cardinal(Command-sExecute) shl 2+Cardinal(Player) shl 16; 271 Cardinal((@LogData[FState.nLog])^):=code; 272 FState.nLog:=MapPos 273 end; 274 275 procedure TCmdList.PutData(Data: pointer; Length: integer); 276 begin 277 if FState.nLog+Length>LogAlloc then 278 begin 279 inc(LogAlloc, LogGrow); 318 move(Data^, LogData[FState.nLog], Length); 319 inc(FState.nLog, Length); 320 end; 321 322 procedure TCmdList.CompleteMoveCode; 323 begin 324 if FState.MoveCode > 0 then 325 begin 326 if FState.MoveCode and 1 = 1 then 327 PutData(@FState.MoveCode, 1) // Single FM 328 else 329 PutData(@FState.MoveCode, 3); // Single M 330 FState.MoveCode := 0; 331 end 332 end; 333 334 procedure TCmdList.LoadFromFile(const f: TFileStream); 335 begin 336 f.read(FState.nLog, 4); 337 LogData := nil; 338 LogAlloc := ((FState.nLog + 2) div LogGrow + 1) * LogGrow; 280 339 ReallocMem(LogData, LogAlloc); 281 end; 282 move(Data^, LogData[FState.nLog], Length); 283 inc(FState.nLog, Length); 284 end; 285 286 procedure TCmdList.CompleteMoveCode; 287 begin 288 if FState.MoveCode>0 then 289 begin 290 if FState.MoveCode and 1=1 then PutData(@FState.MoveCode, 1) // Single FM 291 else PutData(@FState.MoveCode, 3); // Single M 292 FState.MoveCode:=0; 293 end 294 end; 295 296 procedure TCmdList.LoadFromFile(const f: TFileStream); 297 begin 298 f.read(FState.nLog, 4); 299 LogData:=nil; 300 LogAlloc:=((FState.nLog+2) div LogGrow +1)*LogGrow; 301 ReallocMem(LogData, LogAlloc); 302 f.read(LogData^, FState.nLog); 303 FState.LoadPos:=0; 340 f.read(LogData^, FState.nLog); 341 FState.LoadPos := 0; 304 342 end; 305 343 306 344 procedure TCmdList.SaveToFile(const f: TFileStream); 307 345 begin 308 CompleteMoveCode; 309 f.write(FState.nLog, 4); 310 f.write(LogData^, FState.nLog) 311 end; 312 313 procedure TCmdList.AppendToFile(const f: TFileStream; const OldState: TCmdListState); 314 begin 315 CompleteMoveCode; 316 f.write(FState.nLog, 4); 317 f.Position:=f.Position+OldState.nLog; 318 f.write(LogData[OldState.nLog], FState.nLog-OldState.nLog) 346 CompleteMoveCode; 347 f.write(FState.nLog, 4); 348 f.write(LogData^, FState.nLog) 349 end; 350 351 procedure TCmdList.AppendToFile(const f: TFileStream; 352 const OldState: TCmdListState); 353 begin 354 CompleteMoveCode; 355 f.write(FState.nLog, 4); 356 f.Position := f.Position + OldState.nLog; 357 f.write(LogData[OldState.nLog], FState.nLog - OldState.nLog) 319 358 end; 320 359 321 360 procedure TCmdList.Cut; 322 361 begin 323 FState.nLog:=FState.LoadPos;362 FState.nLog := FState.LoadPos; 324 363 end; 325 364 326 365 function TCmdList.Progress: integer; 327 366 begin 328 if (FState.LoadPos=FState.nLog) and (FState.LoadMoveCode=0) then 329 result:=1000 // loading complete 330 else if FState.nLog>1 shl 20 then 331 result:=(FState.LoadPos shr 8)*999 div (FState.nLog shr 8) 332 else result:=FState.LoadPos*999 div FState.nLog 333 end; 334 335 {Format Specification: 336 337 Non-ClientEx-Command: 367 if (FState.LoadPos = FState.nLog) and (FState.LoadMoveCode = 0) then 368 result := 1000 // loading complete 369 else if FState.nLog > 1 shl 20 then 370 result := (FState.LoadPos shr 8) * 999 div (FState.nLog shr 8) 371 else 372 result := FState.LoadPos * 999 div FState.nLog 373 end; 374 375 { Format Specification: 376 377 Non-ClientEx-Command: 338 378 Byte3 Byte2 Byte1 Byte0 339 379 ssssssss sssspppp cccccccc cccccc00 340 380 (c = Command-sExecute, p = Player, s = Subject) 341 381 342 ClientEx-Command:382 ClientEx-Command: 343 383 Byte2 Byte1 Byte0 344 384 0ppppccc cccccccc ccccc010 345 385 (c = Command, p = Player) 346 386 347 Single Move:387 Single Move: 348 388 Byte2 Byte1 Byte0 349 389 000000ss ssssssss ssaaa110 350 390 (a = Direction, s = Subject) 351 391 352 Move + Follow Move:392 Move + Follow Move: 353 393 Byte2 Byte1 Byte0 354 394 00bbb1ss ssssssss ssaaa110 355 395 (a = Direction 1, s = Subject 1, b = Direction 2) 356 396 357 Follow Move + Move:397 Follow Move + Move: 358 398 Byte2 Byte1 Byte0 359 399 00ssssss ssssssbb b110aaa1 360 400 (a = Direction 1, b = Direction 2, s = Subject 2) 361 401 362 Single Follow Move:402 Single Follow Move: 363 403 Byte0 364 404 0000aaa1 365 405 (a = Direction) 366 406 367 Double Follow Move:407 Double Follow Move: 368 408 Byte0 369 409 bbb1aaa1 … … 372 412 373 413 end. 374 -
trunk/Database.pas
r2 r6 1 1 {$INCLUDE switches} 2 // {$DEFINE TEXTLOG}3 // {$DEFINE LOADPERF}2 // {$DEFINE TEXTLOG} 3 // {$DEFINE LOADPERF} 4 4 unit Database; 5 5 … … 7 7 8 8 uses 9 Protocol,CmdList;9 Protocol, CmdList; 10 10 11 11 const 12 // additional test flags 13 FastContact=false; {extra small world with railroad everywhere} 14 15 neumax=4096; 16 necmax=1024; 17 nemmax=1024; 18 19 lNoObserve=0; lObserveUnhidden=1; lObserveAll=2; lObserveSuper=3; //observe levels 20 21 TerrType_Canalable=[fGrass,fDesert,fPrairie,fTundra,fSwamp,fForest,fHills]; 22 23 nStartUn=1; 24 StartUn: array[0..nStartUn-1] of integer=(0); //mix of start units 25 26 CityOwnTile=13; 27 28 var 29 GAlive, {players alive; bitset of 1 shl p} 30 GWatching, 31 GInitialized, 32 GAI, 33 RND, {world map randseed} 34 lx,ly, 35 MapSize, // = lx*ly 36 LandMass, 37 {$IFOPT O-}InvalidTreatyMap,{$ENDIF} 38 SaveMapCenterLoc, 39 PeaceEnded, 40 GTurn, {current turn} 41 GTestFlags: integer; 42 Mode: (moLoading_Fast, moLoading, moMovie, moPlaying); 43 GWonder: array[0..27] of TWonderInfo; 44 ServerVersion: array[0..nPl-1] of integer; 45 ProcessClientData: array[0..nPl-1] of boolean; 46 CL: TCmdList; 47 {$IFDEF TEXTLOG}CmdInfo: string; TextLog: TextFile;{$ENDIF} 48 {$IFDEF LOADPERF}time_total,time_total0,time_x0,time_x1,time_a,time_b,time_c: int64;{$ENDIF} 49 50 // map data 51 RealMap: array[0..lxmax*lymax-1] of Cardinal; 52 Continent:array[0..lxmax*lymax-1] of integer; {continent id for each tile} 53 Occupant:array[0..lxmax*lymax-1] of ShortInt; {occupying player for each tile} 54 ZoCMap:array[0..lxmax*lymax-1] of ShortInt; 55 ObserveLevel:array[0..lxmax*lymax-1] of Cardinal; 56 {Observe Level of player p in bits 2*p and 2*p+1} 57 UsedByCity:array[0..lxmax*lymax-1] of integer; {location of exploiting city for 58 each tile, =-1 if not exploited} 59 60 // player data 61 RW: array[0..nPl-1] of TPlayerContext;{player data} 62 Difficulty: array[0..nPl-1] of integer; 63 GShip: array[0..nPl-1] of TShipInfo; 64 ResourceMask: array[0..nPl-1] of Cardinal; 65 Founded: array[0..nPl-1] of integer; {number of cities founded} 66 TerritoryCount: array[0..nPl] of integer; 67 LastValidStat, 68 Researched, 69 Discovered, // number of tiles discovered 70 GrWallContinent: array[0..nPl-1] of integer; 71 RWemix: array[0..nPl-1, 0..nPl-1, 0..nmmax-1] of SmallInt; 12 // additional test flags 13 FastContact = false; { extra small world with railroad everywhere } 14 15 neumax = 4096; 16 necmax = 1024; 17 nemmax = 1024; 18 19 lNoObserve = 0; 20 lObserveUnhidden = 1; 21 lObserveAll = 2; 22 lObserveSuper = 3; // observe levels 23 24 TerrType_Canalable = [fGrass, fDesert, fPrairie, fTundra, fSwamp, 25 fForest, fHills]; 26 27 nStartUn = 1; 28 StartUn: array [0 .. nStartUn - 1] of integer = (0); // mix of start units 29 30 CityOwnTile = 13; 31 32 var 33 GAlive, { players alive; bitset of 1 shl p } 34 GWatching, GInitialized, GAI, RND, { world map randseed } 35 lx, ly, MapSize, // = lx*ly 36 LandMass, 37 {$IFOPT O-}InvalidTreatyMap, {$ENDIF} 38 SaveMapCenterLoc, PeaceEnded, GTurn, { current turn } 39 GTestFlags: integer; 40 Mode: (moLoading_Fast, moLoading, moMovie, moPlaying); 41 GWonder: array [0 .. 27] of TWonderInfo; 42 ServerVersion: array [0 .. nPl - 1] of integer; 43 ProcessClientData: array [0 .. nPl - 1] of boolean; 44 CL: TCmdList; 45 {$IFDEF TEXTLOG}CmdInfo: string; 46 TextLog: TextFile; {$ENDIF} 47 {$IFDEF LOADPERF}time_total, time_total0, time_x0, time_x1, time_a, time_b, time_c: int64; {$ENDIF} 48 // map data 49 RealMap: array [0 .. lxmax * lymax - 1] of Cardinal; 50 Continent: array [0 .. lxmax * lymax - 1] of integer; 51 { continent id for each tile } 52 Occupant: array [0 .. lxmax * lymax - 1] of ShortInt; 53 { occupying player for each tile } 54 ZoCMap: array [0 .. lxmax * lymax - 1] of ShortInt; 55 ObserveLevel: array [0 .. lxmax * lymax - 1] of Cardinal; 56 { Observe Level of player p in bits 2*p and 2*p+1 } 57 UsedByCity: array [0 .. lxmax * lymax - 1] of integer; 58 { location of exploiting city for 59 each tile, =-1 if not exploited } 60 61 // player data 62 RW: array [0 .. nPl - 1] of TPlayerContext; { player data } 63 Difficulty: array [0 .. nPl - 1] of integer; 64 GShip: array [0 .. nPl - 1] of TShipInfo; 65 ResourceMask: array [0 .. nPl - 1] of Cardinal; 66 Founded: array [0 .. nPl - 1] of integer; { number of cities founded } 67 TerritoryCount: array [0 .. nPl] of integer; 68 LastValidStat, Researched, Discovered, // number of tiles discovered 69 GrWallContinent: array [0 .. nPl - 1] of integer; 70 RWemix: array [0 .. nPl - 1, 0 .. nPl - 1, 0 .. nmmax - 1] of SmallInt; 72 71 // [p1,p2,mix] -> index of p2's model mix in p1's enemy model list 73 Destroyed: array[0..nPl-1, 0..nPl-1, 0..nmmax-1] of SmallInt;72 Destroyed: array [0 .. nPl - 1, 0 .. nPl - 1, 0 .. nmmax - 1] of SmallInt; 74 73 // [p1,p2,mix] -> number of p2's units with model mix that p1 has destroyed 75 nTech: array[0..nPl-1] of integer; {number of known techs}76 //NewContact: array[0..nPl-1,0..nPl-1] of boolean;74 nTech: array [0 .. nPl - 1] of integer; { number of known techs } 75 // NewContact: array[0..nPl-1,0..nPl-1] of boolean; 77 76 78 77 type 79 TVicinity8Loc=array[0..7] of integer;80 TVicinity21Loc=array[0..27] of integer;78 TVicinity8Loc = array [0 .. 7] of integer; 79 TVicinity21Loc = array [0 .. 27] of integer; 81 80 82 81 procedure MaskD(var x; Count, Mask: Cardinal); 83 procedure IntServer(Command, Player,Subject:integer;var Data);82 procedure IntServer(Command, Player, Subject: integer; var Data); 84 83 procedure CompactLists(p: integer); 85 84 procedure ClearTestFlags(ClearFlags: integer); 86 procedure SetTestFlags(p, SetFlags: integer);85 procedure SetTestFlags(p, SetFlags: integer); 87 86 88 87 // Tech Related Functions 89 function TechBaseCost(nTech, diff: integer): integer;88 function TechBaseCost(nTech, diff: integer): integer; 90 89 function TechCost(p: integer): integer; 91 90 procedure CalculateModel(var m: TModel); 92 procedure CheckSpecialModels(p, pre: integer);91 procedure CheckSpecialModels(p, pre: integer); 93 92 procedure EnableDevModel(p: integer); 94 procedure SeeTech(p, ad: integer);95 procedure DiscoverTech(p, ad: integer);93 procedure SeeTech(p, ad: integer); 94 procedure DiscoverTech(p, ad: integer); 96 95 procedure CheckExpiration(Wonder: integer); 97 96 98 97 // Location Navigation 99 function dLoc(Loc, dx,dy: integer): integer;100 procedure dxdy(Loc0, Loc1: integer; var dx,dy: integer);101 function Distance(Loc0, Loc1: integer): integer;98 function dLoc(Loc, dx, dy: integer): integer; 99 procedure dxdy(Loc0, Loc1: integer; var dx, dy: integer); 100 function Distance(Loc0, Loc1: integer): integer; 102 101 procedure V8_to_Loc(Loc0: integer; var VicinityLoc: TVicinity8Loc); 103 102 procedure V21_to_Loc(Loc0: integer; var VicinityLoc: TVicinity21Loc); … … 118 117 // Map Revealing 119 118 function GetTileInfo(p, cix, Loc: integer; var Info: TTileInfo): integer; 120 procedure Strongest(Loc: integer;var uix,Strength,Bonus,Cnt:integer);119 procedure Strongest(Loc: integer; var uix, Strength, Bonus, Cnt: integer); 121 120 function UnitSpeed(p, mix, Health: integer): integer; 122 procedure GetUnitReport(p,uix: integer; var UnitReport: TUnitReport); 123 procedure SearchCity(Loc: integer; var p,cix: integer); 124 procedure TellAboutModel(p,taOwner,tamix: integer); 125 function emixSafe(p,taOwner,tamix: integer): integer; 126 function Discover9(Loc,p,Level: integer; TellAllied, EnableContact: boolean): boolean; 127 function Discover21(Loc,p,AdjacentLevel: integer; TellAllied, EnableContact: boolean): boolean; 121 procedure GetUnitReport(p, uix: integer; var UnitReport: TUnitReport); 122 procedure SearchCity(Loc: integer; var p, cix: integer); 123 procedure TellAboutModel(p, taOwner, tamix: integer); 124 function emixSafe(p, taOwner, tamix: integer): integer; 125 function Discover9(Loc, p, Level: integer; 126 TellAllied, EnableContact: boolean): boolean; 127 function Discover21(Loc, p, AdjacentLevel: integer; 128 TellAllied, EnableContact: boolean): boolean; 128 129 procedure DiscoverAll(p, Level: integer); 129 130 procedure DiscoverViewAreas(p: integer); 130 function GetUnitStack(p, Loc: integer): integer;131 function GetUnitStack(p, Loc: integer): integer; 131 132 procedure UpdateUnitMap(Loc: integer; CityChange: boolean = false); 132 procedure RecalcV8ZoC(p, Loc: integer);133 procedure RecalcV8ZoC(p, Loc: integer); 133 134 procedure RecalcMapZoC(p: integer); 134 135 procedure RecalcPeaceMap(p: integer); … … 136 137 // Territory Calculation 137 138 procedure CheckBorders(OriginLoc: integer; PlayerLosingCity: integer = -1); 138 procedure LogCheckBorders(p, cix: integer; PlayerLosingCity: integer = -1);139 procedure LogCheckBorders(p, cix: integer; PlayerLosingCity: integer = -1); 139 140 140 141 // Map Processing 141 procedure CreateUnit(p, mix: integer);142 procedure FreeUnit(p, uix: integer);143 procedure PlaceUnit(p, uix: integer);144 procedure RemoveUnit(p, uix: integer; Enemy: integer = -1);145 procedure RemoveUnit_UpdateMap(p, uix: integer);146 procedure RemoveAllUnits(p, Loc: integer; Enemy: integer = -1);147 procedure RemoveDomainUnits(d, p,Loc: integer);148 procedure FoundCity(p, FoundLoc: integer);149 procedure DestroyCity(p, cix: integer; SaveUnits: boolean);150 procedure ChangeCityOwner(pOld, cixOld,pNew: integer);151 procedure CompleteJob(p, Loc,Job: integer);142 procedure CreateUnit(p, mix: integer); 143 procedure FreeUnit(p, uix: integer); 144 procedure PlaceUnit(p, uix: integer); 145 procedure RemoveUnit(p, uix: integer; Enemy: integer = -1); 146 procedure RemoveUnit_UpdateMap(p, uix: integer); 147 procedure RemoveAllUnits(p, Loc: integer; Enemy: integer = -1); 148 procedure RemoveDomainUnits(d, p, Loc: integer); 149 procedure FoundCity(p, FoundLoc: integer); 150 procedure DestroyCity(p, cix: integer; SaveUnits: boolean); 151 procedure ChangeCityOwner(pOld, cixOld, pNew: integer); 152 procedure CompleteJob(p, Loc, Job: integer); 152 153 153 154 // Diplomacy 154 procedure IntroduceEnemy(p1, p2: integer);155 procedure IntroduceEnemy(p1, p2: integer); 155 156 procedure GiveCivilReport(p, pAbout: integer); 156 157 procedure GiveMilReport(p, pAbout: integer); … … 158 159 function PayPrice(pSender, pTarget, Price: integer; execute: boolean): boolean; 159 160 procedure CancelTreaty(p, pWith: integer; DecreaseCredibility: boolean = true); 160 function DoSpyMission(p,pCity,cix,Mission: integer): Cardinal; 161 161 function DoSpyMission(p, pCity, cix, Mission: integer): Cardinal; 162 162 163 163 implementation 164 164 165 165 uses 166 {$IFDEF LOADPERF}SysUtils, Windows,{$ENDIF} 167 {$IFDEF TEXTLOG}SysUtils,{$ENDIF} 168 IPQ; 169 170 var 171 UnBuilt: array[0..nPl-1] of integer; {number of units built} 172 166 {$IFDEF LOADPERF}SysUtils, Windows, {$ENDIF} 167 {$IFDEF TEXTLOG}SysUtils, {$ENDIF} 168 IPQ; 169 170 var 171 UnBuilt: array [0 .. nPl - 1] of integer; { number of units built } 173 172 174 173 procedure MaskD(var x; Count, Mask: Cardinal); Register; 175 174 asm 176 sub eax,4175 sub eax,4 177 176 @r: and [eax+edx*4],ecx 178 dec edx179 jnz @r177 dec edx 178 jnz @r 180 179 end; 181 180 182 181 procedure CompactLists(p: integer); 183 182 var 184 uix,uix1,cix: integer; 185 {$IFOPT O-}V21: integer; Radius: TVicinity21Loc;{$ENDIF} 186 begin 187 with RW[p] do 188 begin 189 // compact unit list 190 uix:=0; 191 while uix<nUn do 192 if Un[uix].Loc<0 then 193 begin 194 dec(nUn); 195 Un[uix]:=Un[nUn]; {replace removed unit by last} 196 if (Un[uix].TroopLoad>0) or (Un[uix].AirLoad>0) then 197 for uix1:=0 to nUn-1 do 198 if Un[uix1].Master=nUn then Un[uix1].Master:=uix; 199 // index of last unit changes 183 uix, uix1, cix: integer; 184 {$IFOPT O-}V21: integer; 185 Radius: TVicinity21Loc; {$ENDIF} 186 begin 187 with RW[p] do 188 begin 189 // compact unit list 190 uix := 0; 191 while uix < nUn do 192 if Un[uix].Loc < 0 then 193 begin 194 dec(nUn); 195 Un[uix] := Un[nUn]; { replace removed unit by last } 196 if (Un[uix].TroopLoad > 0) or (Un[uix].AirLoad > 0) then 197 for uix1 := 0 to nUn - 1 do 198 if Un[uix1].Master = nUn then 199 Un[uix1].Master := uix; 200 // index of last unit changes 200 201 end 201 else inc(uix); 202 203 // compact city list 204 cix:=0; 205 while cix<nCity do 206 if City[cix].Loc<0 then 207 begin 208 dec(nCity); 209 City[cix]:=City[nCity]; {replace city by last} 210 for uix1:=0 to nUn-1 do 211 if Un[uix1].Home=nCity then Un[uix1].Home:=cix; 212 {index of last city changes} 202 else 203 inc(uix); 204 205 // compact city list 206 cix := 0; 207 while cix < nCity do 208 if City[cix].Loc < 0 then 209 begin 210 dec(nCity); 211 City[cix] := City[nCity]; { replace city by last } 212 for uix1 := 0 to nUn - 1 do 213 if Un[uix1].Home = nCity then 214 Un[uix1].Home := cix; 215 { index of last city changes } 213 216 end 214 else inc(cix); 215 216 // compact enemy city list 217 cix:=0; 218 while cix<nEnemyCity do 219 if EnemyCity[cix].Loc<0 then 220 begin 221 dec(nEnemyCity); 222 EnemyCity[cix]:=EnemyCity[nEnemyCity]; {replace city by last} 217 else 218 inc(cix); 219 220 // compact enemy city list 221 cix := 0; 222 while cix < nEnemyCity do 223 if EnemyCity[cix].Loc < 0 then 224 begin 225 dec(nEnemyCity); 226 EnemyCity[cix] := EnemyCity[nEnemyCity]; { replace city by last } 223 227 end 224 else inc(cix); 228 else 229 inc(cix); 225 230 226 231 {$IFOPT O-} 227 for cix:=0 to nCity-1 do with City[cix] do 228 begin 229 V21_to_Loc(Loc,Radius); 230 for V21:=1 to 26 do if Tiles and (1 shl V21)<>0 then 231 assert(UsedByCity[Radius[V21]]=Loc); 232 for cix := 0 to nCity - 1 do 233 with City[cix] do 234 begin 235 V21_to_Loc(Loc, Radius); 236 for V21 := 1 to 26 do 237 if Tiles and (1 shl V21) <> 0 then 238 assert(UsedByCity[Radius[V21]] = Loc); 239 end 240 {$ENDIF} 241 end; 242 end; // CompactLists 243 244 { 245 Tech Related Functions 246 ____________________________________________________________________ 247 } 248 function TechBaseCost(nTech, diff: integer): integer; 249 var 250 c0: single; 251 begin 252 c0 := TechFormula_M[diff] * (nTech + 4) * 253 exp((nTech + 4) / TechFormula_D[diff]); 254 if c0 >= $10000000 then 255 result := $10000000 256 else 257 result := trunc(c0) 258 end; 259 260 function TechCost(p: integer): integer; 261 begin 262 with RW[p] do 263 begin 264 result := TechBaseCost(nTech[p], Difficulty[p]); 265 if ResearchTech >= 0 then 266 if (ResearchTech = adMilitary) or (Tech[ResearchTech] = tsSeen) then 267 result := result shr 1 268 else if ResearchTech in FutureTech then 269 if Government = gFuture then 270 result := result * 2 271 else 272 result := result * 4; 273 end 274 end; 275 276 procedure SetModelFlags(var m: TModel); 277 begin 278 m.Flags := 0; 279 if (m.Domain = dGround) and (m.Kind <> mkDiplomat) then 280 m.Flags := m.Flags or mdZOC; 281 if (m.Kind = mkDiplomat) or (m.Attack + m.Cap[mcBombs] = 0) then 282 m.Flags := m.Flags or mdCivil; 283 if (m.Cap[mcOver] > 0) or (m.Domain = dSea) and (m.Weight >= 6) then 284 m.Flags := m.Flags or mdDoubleSupport; 285 end; 286 287 procedure CalculateModel(var m: TModel); 288 { calculate attack, defense, cost... of a model by features } 289 var 290 i: integer; 291 begin 292 with m do 293 begin 294 Attack := (Cap[mcOffense] + Cap[mcOver]) * MStrength; 295 Defense := (Cap[mcDefense] + Cap[mcOver]) * MStrength; 296 case Domain of 297 dGround: 298 Speed := 150 + Cap[mcMob] * 50; 299 dSea: 300 begin 301 Speed := 350 + 200 * Cap[mcNP] + 200 * Cap[mcTurbines]; 302 if Cap[mcNP] = 0 then 303 inc(Speed, 100 * Cap[mcSE]); 304 end; 305 dAir: 306 Speed := 850 + 400 * Cap[mcJet]; 307 end; 308 Cost := 0; 309 for i := 0 to nFeature - 1 do 310 if 1 shl Domain and Feature[i].Domains <> 0 then 311 inc(Cost, Cap[i] * Feature[i].Cost); 312 Cost := Cost * MCost; 313 Weight := 0; 314 for i := 0 to nFeature - 1 do 315 if 1 shl Domain and Feature[i].Domains <> 0 then 316 if (Domain = dGround) and (i = mcDefense) then 317 inc(Weight, Cap[i] * 2) 318 else 319 inc(Weight, Cap[i] * Feature[i].Weight); 320 end; 321 SetModelFlags(m); 322 end; 323 324 procedure CheckSpecialModels(p, pre: integer); 325 var 326 i, mix1: integer; 327 HasAlready: boolean; 328 begin 329 for i := 0 to nSpecialModel - 330 1 do { check whether new special model available } 331 if (SpecialModelPreq[i] = pre) and (RW[p].nModel < nmmax) then 332 begin 333 HasAlready := false; 334 for mix1 := 0 to RW[p].nModel - 1 do 335 if (RW[p].Model[mix1].Kind = SpecialModel[i].Kind) and 336 (RW[p].Model[mix1].Attack = SpecialModel[i].Attack) and 337 (RW[p].Model[mix1].Speed = SpecialModel[i].Speed) then 338 HasAlready := true; 339 if not HasAlready then 340 begin 341 RW[p].Model[RW[p].nModel] := SpecialModel[i]; 342 SetModelFlags(RW[p].Model[RW[p].nModel]); 343 with RW[p].Model[RW[p].nModel] do 344 begin 345 Status := 0; 346 SavedStatus := 0; 347 IntroTurn := GTurn; 348 Built := 0; 349 Lost := 0; 350 ID := p shl 12 + RW[p].nModel; 351 if (Kind = mkSpecial_Boat) and (ServerVersion[p] < $000EF0) then 352 Speed := 350; // old longboat 353 end; 354 inc(RW[p].nModel); 355 end 356 end; 357 end; 358 359 procedure EnableDevModel(p: integer); 360 begin 361 with RW[p] do 362 if nModel < nmmax then 363 begin 364 Model[nModel] := DevModel; 365 with Model[nModel] do 366 begin 367 Status := 0; 368 SavedStatus := 0; 369 IntroTurn := GTurn; 370 Built := 0; 371 Lost := 0; 372 ID := p shl 12 + nModel 373 end; 374 inc(nModel); 375 inc(Researched[p]) 232 376 end 233 {$ENDIF} 234 end; 235 end; // CompactLists 236 237 { 238 Tech Related Functions 239 ____________________________________________________________________ 240 } 241 function TechBaseCost(nTech,diff: integer): integer; 242 var 243 c0: single; 244 begin 245 c0:=TechFormula_M[diff]*(nTech+4)*exp((nTech+4)/TechFormula_D[diff]); 246 if c0>=$10000000 then result:=$10000000 247 else result:=trunc(c0) 248 end; 249 250 function TechCost(p: integer): integer; 251 begin 252 with RW[p] do 253 begin 254 result:=TechBaseCost(nTech[p],Difficulty[p]); 255 if ResearchTech>=0 then 256 if (ResearchTech=adMilitary) or (Tech[ResearchTech]=tsSeen) then 257 result:=result shr 1 258 else if ResearchTech in FutureTech then 259 if Government=gFuture then 260 result:=result*2 261 else result:=result*4; 377 end; 378 379 procedure SeeTech(p, ad: integer); 380 begin 381 {$IFDEF TEXTLOG}CmdInfo := CmdInfo + Format(' P%d:A%d', [p, ad]); {$ENDIF} 382 RW[p].Tech[ad] := tsSeen; 383 // inc(nTech[p]); 384 inc(Researched[p]) 385 end; 386 387 procedure FreeSlaves; 388 var 389 p1, uix: integer; 390 begin 391 for p1 := 0 to nPl - 1 do 392 if (GAlive and (1 shl p1) <> 0) then 393 for uix := 0 to RW[p1].nUn - 1 do 394 if RW[p1].Model[RW[p1].Un[uix].mix].Kind = mkSlaves then 395 RW[p1].Un[uix].Job := jNone 396 end; 397 398 procedure DiscoverTech(p, ad: integer); 399 400 procedure TellAboutKeyTech(p, Source: integer); 401 var 402 i, p1: integer; 403 begin 404 for i := 1 to 3 do 405 if ad = AgePreq[i] then 406 for p1 := 0 to nPl - 1 do 407 if (p1 <> p) and ((GAlive or GWatching) and (1 shl p1) <> 0) then 408 RW[p1].EnemyReport[p].Tech[ad] := Source; 409 end; 410 411 var 412 i: integer; 413 begin 414 if ad in FutureTech then 415 begin 416 if RW[p].Tech[ad] < tsApplicable then 417 RW[p].Tech[ad] := 1 418 else 419 inc(RW[p].Tech[ad]); 420 if ad <> futResearchTechnology then 421 inc(nTech[p], 2); 422 inc(Researched[p], 8); 423 exit; 424 end; 425 426 if RW[p].Tech[ad] = tsSeen then 427 begin 428 inc(nTech[p]); 429 inc(Researched[p]); 262 430 end 263 end; 264 265 procedure SetModelFlags(var m: TModel); 266 begin 267 m.Flags:=0; 268 if (m.Domain=dGround) and (m.Kind<>mkDiplomat) then 269 m.Flags:=m.Flags or mdZOC; 270 if (m.Kind=mkDiplomat) or (m.Attack+m.Cap[mcBombs]=0) then 271 m.Flags:=m.Flags or mdCivil; 272 if (m.Cap[mcOver]>0) or (m.Domain=dSea) and (m.Weight>=6) then 273 m.Flags:=m.Flags or mdDoubleSupport; 274 end; 275 276 procedure CalculateModel(var m: TModel); 277 {calculate attack, defense, cost... of a model by features} 278 var 279 i: integer; 280 begin 281 with m do 282 begin 283 Attack:=(Cap[mcOffense]+Cap[mcOver])*MStrength; 284 Defense:=(Cap[mcDefense]+Cap[mcOver])*MStrength; 285 case Domain of 286 dGround: Speed:=150+Cap[mcMob]*50; 287 dSea: 288 begin 289 Speed:=350+200*Cap[mcNP]+200*Cap[mcTurbines]; 290 if Cap[mcNP]=0 then 291 inc(Speed,100*Cap[mcSE]); 292 end; 293 dAir: Speed:=850+400*Cap[mcJet]; 294 end; 295 Cost:=0; 296 for i:=0 to nFeature-1 do 297 if 1 shl Domain and Feature[i].Domains<>0 then 298 inc(Cost,Cap[i]*Feature[i].Cost); 299 Cost:=Cost*MCost; 300 Weight:=0; 301 for i:=0 to nFeature-1 do 302 if 1 shl Domain and Feature[i].Domains<>0 then 303 if (Domain=dGround) and (i=mcDefense) then inc(Weight,Cap[i]*2) 304 else inc(Weight,Cap[i]*Feature[i].Weight); 305 end; 306 SetModelFlags(m); 307 end; 308 309 procedure CheckSpecialModels(p,pre: integer); 310 var 311 i,mix1: integer; 312 HasAlready: boolean; 313 begin 314 for i:=0 to nSpecialModel-1 do {check whether new special model available} 315 if (SpecialModelPreq[i]=pre) and (RW[p].nModel<nmmax) then 316 begin 317 HasAlready:=false; 318 for mix1:=0 to RW[p].nModel-1 do 319 if (RW[p].Model[mix1].Kind=SpecialModel[i].Kind) 320 and (RW[p].Model[mix1].Attack=SpecialModel[i].Attack) 321 and (RW[p].Model[mix1].Speed=SpecialModel[i].Speed) then 322 HasAlready:=true; 323 if not HasAlready then 324 begin 325 RW[p].Model[RW[p].nModel]:=SpecialModel[i]; 326 SetModelFlags(RW[p].Model[RW[p].nModel]); 327 with RW[p].Model[RW[p].nModel] do 328 begin 329 Status:=0; 330 SavedStatus:=0; 331 IntroTurn:=GTurn; 332 Built:=0; 333 Lost:=0; 334 ID:=p shl 12+RW[p].nModel; 335 if (Kind=mkSpecial_Boat) and (ServerVersion[p]<$000EF0) then 336 Speed:=350; // old longboat 337 end; 338 inc(RW[p].nModel); 339 end 340 end; 341 end; 342 343 procedure EnableDevModel(p: integer); 344 begin 345 with RW[p] do if nModel<nmmax then 346 begin 347 Model[nModel]:=DevModel; 348 with Model[nModel] do 349 begin 350 Status:=0; 351 SavedStatus:=0; 352 IntroTurn:=GTurn; 353 Built:=0; 354 Lost:=0; 355 ID:=p shl 12+nModel 356 end; 357 inc(nModel); 358 inc(Researched[p]) 359 end 360 end; 361 362 procedure SeeTech(p,ad: integer); 363 begin 364 {$IFDEF TEXTLOG}CmdInfo:=CmdInfo+Format(' P%d:A%d', [p,ad]);{$ENDIF} 365 RW[p].Tech[ad]:=tsSeen; 366 //inc(nTech[p]); 367 inc(Researched[p]) 368 end; 369 370 procedure FreeSlaves; 371 var 372 p1,uix: integer; 373 begin 374 for p1:=0 to nPl-1 do if (GAlive and (1 shl p1)<>0) then 375 for uix:=0 to RW[p1].nUn-1 do 376 if RW[p1].Model[RW[p1].Un[uix].mix].Kind=mkSlaves then 377 RW[p1].Un[uix].Job:=jNone 378 end; 379 380 procedure DiscoverTech(p,ad: integer); 381 382 procedure TellAboutKeyTech(p,Source: integer); 383 var 384 i,p1: integer; 385 begin 386 for i:=1 to 3 do if ad=AgePreq[i] then 387 for p1:=0 to nPl-1 do if (p1<>p) and ((GAlive or GWatching) and (1 shl p1)<>0) then 388 RW[p1].EnemyReport[p].Tech[ad]:=Source; 389 end; 390 391 var 392 i: integer; 393 begin 394 if ad in FutureTech then 395 begin 396 if RW[p].Tech[ad]<tsApplicable then RW[p].Tech[ad]:=1 397 else inc(RW[p].Tech[ad]); 398 if ad<>futResearchTechnology then inc(nTech[p],2); 399 inc(Researched[p],8); 400 exit; 401 end; 402 403 if RW[p].Tech[ad]=tsSeen then 404 begin inc(nTech[p]); inc(Researched[p]); end 405 else begin inc(nTech[p],2); inc(Researched[p],2); end; 406 RW[p].Tech[ad]:=tsResearched; 407 TellAboutKeyTech(p,tsResearched); 408 CheckSpecialModels(p,ad); 409 if ad=adScience then 410 ResourceMask[p]:=ResourceMask[p] or fSpecial2; 411 if ad=adMassProduction then 412 ResourceMask[p]:=ResourceMask[p] or fModern; 413 414 for i:=0 to 27 do {check whether wonders expired} 415 if (GWonder[i].EffectiveOwner<>GWonder[woEiffel].EffectiveOwner) 416 and (Imp[i].Expiration=ad) then 417 begin 418 GWonder[i].EffectiveOwner:=-1; 419 if i=woPyramids then FreeSlaves; 431 else 432 begin 433 inc(nTech[p], 2); 434 inc(Researched[p], 2); 435 end; 436 RW[p].Tech[ad] := tsResearched; 437 TellAboutKeyTech(p, tsResearched); 438 CheckSpecialModels(p, ad); 439 if ad = adScience then 440 ResourceMask[p] := ResourceMask[p] or fSpecial2; 441 if ad = adMassProduction then 442 ResourceMask[p] := ResourceMask[p] or fModern; 443 444 for i := 0 to 27 do { check whether wonders expired } 445 if (GWonder[i].EffectiveOwner <> GWonder[woEiffel].EffectiveOwner) and 446 (Imp[i].Expiration = ad) then 447 begin 448 GWonder[i].EffectiveOwner := -1; 449 if i = woPyramids then 450 FreeSlaves; 420 451 end; 421 452 end; … … 424 455 // GWonder[Wonder].EffectiveOwner must be set before! 425 456 var 426 p: integer; 427 begin 428 if (Imp[Wonder].Expiration>=0) 429 and (GWonder[woEiffel].EffectiveOwner<>GWonder[Wonder].EffectiveOwner) then 430 for p:=0 to nPl-1 do // check if already expired 431 if (1 shl p and GAlive<>0) and (RW[p].Tech[Imp[Wonder].Expiration]>=tsApplicable) then 432 begin 433 GWonder[Wonder].EffectiveOwner:=-1; 434 if Wonder=woPyramids then FreeSlaves 457 p: integer; 458 begin 459 if (Imp[Wonder].Expiration >= 0) and 460 (GWonder[woEiffel].EffectiveOwner <> GWonder[Wonder].EffectiveOwner) then 461 for p := 0 to nPl - 1 do // check if already expired 462 if (1 shl p and GAlive <> 0) and 463 (RW[p].Tech[Imp[Wonder].Expiration] >= tsApplicable) then 464 begin 465 GWonder[Wonder].EffectiveOwner := -1; 466 if Wonder = woPyramids then 467 FreeSlaves 435 468 end 436 469 end; 437 470 438 471 { 439 Location Navigation440 ____________________________________________________________________472 Location Navigation 473 ____________________________________________________________________ 441 474 } 442 function dLoc(Loc,dx,dy: integer): integer; 443 {relative location, dx in hor and dy in ver direction from Loc} 444 var 445 y0: integer; 446 begin 447 assert((Loc>=0) and (Loc<MapSize) and (dx+lx>=0)); 448 y0:=Loc div lx; 449 result:=(Loc+(dx+y0 and 1+lx+lx) shr 1) mod lx +lx*(y0+dy); 450 if (result<0) or (result>=MapSize) then result:=-1; 451 end; 452 453 procedure dxdy(Loc0,Loc1: integer; var dx,dy: integer); 454 begin 455 dx:=((Loc1 mod lx *2 +Loc1 div lx and 1) 456 -(Loc0 mod lx *2 +Loc0 div lx and 1)+3*lx) mod (2*lx) -lx; 457 dy:=Loc1 div lx-Loc0 div lx; 458 end; 459 460 function Distance(Loc0,Loc1: integer): integer; 461 var 462 dx,dy: integer; 463 begin 464 dxdy(Loc0,Loc1,dx,dy); 465 dx:=abs(dx); 466 dy:=abs(dy); 467 result:=dx+dy+abs(dx-dy) shr 1; 475 function dLoc(Loc, dx, dy: integer): integer; 476 { relative location, dx in hor and dy in ver direction from Loc } 477 var 478 y0: integer; 479 begin 480 assert((Loc >= 0) and (Loc < MapSize) and (dx + lx >= 0)); 481 y0 := Loc div lx; 482 result := (Loc + (dx + y0 and 1 + lx + lx) shr 1) mod lx + lx * (y0 + dy); 483 if (result < 0) or (result >= MapSize) then 484 result := -1; 485 end; 486 487 procedure dxdy(Loc0, Loc1: integer; var dx, dy: integer); 488 begin 489 dx := ((Loc1 mod lx * 2 + Loc1 div lx and 1) - 490 (Loc0 mod lx * 2 + Loc0 div lx and 1) + 3 * lx) mod (2 * lx) - lx; 491 dy := Loc1 div lx - Loc0 div lx; 492 end; 493 494 function Distance(Loc0, Loc1: integer): integer; 495 var 496 dx, dy: integer; 497 begin 498 dxdy(Loc0, Loc1, dx, dy); 499 dx := abs(dx); 500 dy := abs(dy); 501 result := dx + dy + abs(dx - dy) shr 1; 468 502 end; 469 503 470 504 procedure V8_to_Loc(Loc0: integer; var VicinityLoc: TVicinity8Loc); 471 505 var 472 x0,y0,lx0: integer;473 begin 474 lx0:=lx; // put in register!475 y0:=Loc0 div lx0;476 x0:=Loc0-y0*lx0; // Loc0 mod lx;477 y0:=y0 and 1;478 VicinityLoc[1]:=Loc0+lx0*2;479 VicinityLoc[3]:=Loc0-1;480 VicinityLoc[5]:=Loc0-lx0*2;481 VicinityLoc[7]:=Loc0+1;482 inc(Loc0,y0);483 VicinityLoc[0]:=Loc0+lx0;484 VicinityLoc[2]:=Loc0+lx0-1;485 VicinityLoc[4]:=Loc0-lx0-1;486 VicinityLoc[6]:=Loc0-lx0;487 488 // world is round!489 if x0<lx0-1 then490 begin 491 if x0=0 then492 begin 493 inc(VicinityLoc[3],lx0);494 if y0=0 then495 begin 496 inc(VicinityLoc[2],lx0);497 inc(VicinityLoc[4],lx0);506 x0, y0, lx0: integer; 507 begin 508 lx0 := lx; // put in register! 509 y0 := Loc0 div lx0; 510 x0 := Loc0 - y0 * lx0; // Loc0 mod lx; 511 y0 := y0 and 1; 512 VicinityLoc[1] := Loc0 + lx0 * 2; 513 VicinityLoc[3] := Loc0 - 1; 514 VicinityLoc[5] := Loc0 - lx0 * 2; 515 VicinityLoc[7] := Loc0 + 1; 516 inc(Loc0, y0); 517 VicinityLoc[0] := Loc0 + lx0; 518 VicinityLoc[2] := Loc0 + lx0 - 1; 519 VicinityLoc[4] := Loc0 - lx0 - 1; 520 VicinityLoc[6] := Loc0 - lx0; 521 522 // world is round! 523 if x0 < lx0 - 1 then 524 begin 525 if x0 = 0 then 526 begin 527 inc(VicinityLoc[3], lx0); 528 if y0 = 0 then 529 begin 530 inc(VicinityLoc[2], lx0); 531 inc(VicinityLoc[4], lx0); 498 532 end 499 533 end 500 534 end 501 else502 begin 503 dec(VicinityLoc[7],lx0);504 if y0=1 then505 begin 506 dec(VicinityLoc[0],lx0);507 dec(VicinityLoc[6],lx0);535 else 536 begin 537 dec(VicinityLoc[7], lx0); 538 if y0 = 1 then 539 begin 540 dec(VicinityLoc[0], lx0); 541 dec(VicinityLoc[6], lx0); 508 542 end 509 543 end; … … 512 546 procedure V21_to_Loc(Loc0: integer; var VicinityLoc: TVicinity21Loc); 513 547 var 514 dx,dy,bit,y0,xComp,yComp,xComp0,xCompSwitch: integer; 515 dst: ^integer; 516 begin 517 y0:=Loc0 div lx; 518 xComp0:=Loc0-y0*lx-1; // Loc0 mod lx -1 519 xCompSwitch:=xComp0-1+y0 and 1; 520 if xComp0<0 then inc(xComp0,lx); 521 if xCompSwitch<0 then inc(xCompSwitch,lx); 522 xCompSwitch:=xCompSwitch xor xComp0; 523 yComp:=lx*(y0-3); 524 dst:=@VicinityLoc; 525 bit:=1; 526 for dy:=0 to 6 do 527 begin 528 xComp0:=xComp0 xor xCompSwitch; 529 xComp:=xComp0; 530 for dx:=0 to 3 do 531 begin 532 if bit and $67F7F76<>0 then dst^:=xComp+yComp 533 else dst^:=-1; 534 inc(xComp); 535 if xComp>=lx then dec(xComp, lx); 536 inc(dst); 537 bit:=bit shl 1; 538 end; 539 inc(yComp,lx); 540 end; 541 end; 542 548 dx, dy, bit, y0, xComp, yComp, xComp0, xCompSwitch: integer; 549 dst: ^integer; 550 begin 551 y0 := Loc0 div lx; 552 xComp0 := Loc0 - y0 * lx - 1; // Loc0 mod lx -1 553 xCompSwitch := xComp0 - 1 + y0 and 1; 554 if xComp0 < 0 then 555 inc(xComp0, lx); 556 if xCompSwitch < 0 then 557 inc(xCompSwitch, lx); 558 xCompSwitch := xCompSwitch xor xComp0; 559 yComp := lx * (y0 - 3); 560 dst := @VicinityLoc; 561 bit := 1; 562 for dy := 0 to 6 do 563 begin 564 xComp0 := xComp0 xor xCompSwitch; 565 xComp := xComp0; 566 for dx := 0 to 3 do 567 begin 568 if bit and $67F7F76 <> 0 then 569 dst^ := xComp + yComp 570 else 571 dst^ := -1; 572 inc(xComp); 573 if xComp >= lx then 574 dec(xComp, lx); 575 inc(dst); 576 bit := bit shl 1; 577 end; 578 inc(yComp, lx); 579 end; 580 end; 543 581 544 582 { 545 Map Creation546 ____________________________________________________________________583 Map Creation 584 ____________________________________________________________________ 547 585 } 548 586 var 549 primitive: integer;550 StartLoc, StartLoc2: array[0..nPl-1] of integer; {starting coordinates}551 Elevation: array[0..lxmax*lymax-1] of Byte; {map elevation}552 ElCount: array[Byte] of integer; {count of elevation occurance}587 primitive: integer; 588 StartLoc, StartLoc2: array [0 .. nPl - 1] of integer; { starting coordinates } 589 Elevation: array [0 .. lxmax * lymax - 1] of Byte; { map elevation } 590 ElCount: array [Byte] of integer; { count of elevation occurance } 553 591 554 592 procedure CalculatePrimitive; 555 593 var 556 i,j: integer; 557 begin 558 primitive:=1; 559 i:=2; 560 while i*i<=MapSize+1 do // test whether prime 561 begin if (MapSize+1) mod i=0 then primitive:=0; inc(i) end; 562 563 if primitive>0 then 564 repeat 565 inc(primitive); 566 i:=1; 567 j:=0; 568 repeat inc(j); i:=i*primitive mod (MapSize+1) until (i=1) or (j=MapSize+1); 569 until j=MapSize; 594 i, j: integer; 595 begin 596 primitive := 1; 597 i := 2; 598 while i * i <= MapSize + 1 do // test whether prime 599 begin 600 if (MapSize + 1) mod i = 0 then 601 primitive := 0; 602 inc(i) 603 end; 604 605 if primitive > 0 then 606 repeat 607 inc(primitive); 608 i := 1; 609 j := 0; 610 repeat 611 inc(j); 612 i := i * primitive mod (MapSize + 1) 613 until (i = 1) or (j = MapSize + 1); 614 until j = MapSize; 570 615 end; 571 616 572 617 function MapGeneratorAvailable: boolean; 573 618 begin 574 result:=(primitive>0) and (lx>=20) and (ly>=40)619 result := (primitive > 0) and (lx >= 20) and (ly >= 40) 575 620 end; 576 621 577 622 procedure CreateElevation; 578 623 const 579 d=64;580 Smooth=0.049;{causes low amplitude of short waves}581 Detail=0.095;{causes short period of short waves}582 Merge=5;{elevation merging range at the connection line of the583 round world,in relation to lx}584 585 var 586 sa,ca,f1,f2:array[1..d] of single;587 imerge,x,y:integer;588 v,maxv:single;589 590 function Value(x, y:integer):single;{elevation formula}624 d = 64; 625 Smooth = 0.049; { causes low amplitude of short waves } 626 Detail = 0.095; { causes short period of short waves } 627 Merge = 5; { elevation merging range at the connection line of the 628 round world,in relation to lx } 629 630 var 631 sa, ca, f1, f2: array [1 .. d] of single; 632 imerge, x, y: integer; 633 v, maxv: single; 634 635 function Value(x, y: integer): single; { elevation formula } 591 636 var 592 i:integer; 593 begin 594 result:=0; 595 for i:=1 to d do result:=result+sin(f1[i]*((x*2+y and 1)*sa[i]+y*1.5*ca[i])) 596 *f2[i]; 597 {x values effectively multiplied with 2 to get 2 horizantal periods 598 of the prime waves} 599 end; 600 601 begin 602 for x:=1 to d do {prepare formula parameters} 603 begin 604 {$IFNDEF SCR}if x=1 then v:=pi/2 {first wave goes horizontal} 605 else{$ENDIF} v:=Random*2*pi; 606 sa[x]:=sin(v)/lx; 607 ca[x]:=cos(v)/ly; 608 f1[x]:=2*pi*Exp(Detail*(x-1)); 609 f2[x]:=Exp(-x*Smooth) 610 end; 611 612 imerge:=2*lx div Merge; 613 FillChar(ElCount,SizeOf(ElCount),0); 614 maxv:=0; 615 for x:=0 to lx-1 do for y:=0 to ly-1 do 616 begin 617 v:=Value(x,y); 618 if x*2<imerge then v:=(x*2*v+(imerge-x*2)*Value(x+lx,y))/imerge; 619 v:=v-sqr(sqr(2*y/ly-1));{soft cut at poles} 620 if v>maxv then maxv:=v; 621 622 if v<-4 then Elevation[x+lx*y]:=0 623 else if v>8.75 then Elevation[x+lx*y]:=255 624 else Elevation[x+lx*y]:=Round((v+4)*20); 625 inc(ElCount[Elevation[x+lx*y]]) 626 end; 637 i: integer; 638 begin 639 result := 0; 640 for i := 1 to d do 641 result := result + sin(f1[i] * ((x * 2 + y and 1) * sa[i] + y * 1.5 * 642 ca[i])) * f2[i]; 643 { x values effectively multiplied with 2 to get 2 horizantal periods 644 of the prime waves } 645 end; 646 647 begin 648 for x := 1 to d do { prepare formula parameters } 649 begin 650 {$IFNDEF SCR} if x = 1 then 651 v := pi / 2 { first wave goes horizontal } 652 else {$ENDIF} v := Random * 2 * pi; 653 sa[x] := sin(v) / lx; 654 ca[x] := cos(v) / ly; 655 f1[x] := 2 * pi * exp(Detail * (x - 1)); 656 f2[x] := exp(-x * Smooth) 657 end; 658 659 imerge := 2 * lx div Merge; 660 FillChar(ElCount, SizeOf(ElCount), 0); 661 maxv := 0; 662 for x := 0 to lx - 1 do 663 for y := 0 to ly - 1 do 664 begin 665 v := Value(x, y); 666 if x * 2 < imerge then 667 v := (x * 2 * v + (imerge - x * 2) * Value(x + lx, y)) / imerge; 668 v := v - sqr(sqr(2 * y / ly - 1)); { soft cut at poles } 669 if v > maxv then 670 maxv := v; 671 672 if v < -4 then 673 Elevation[x + lx * y] := 0 674 else if v > 8.75 then 675 Elevation[x + lx * y] := 255 676 else 677 Elevation[x + lx * y] := Round((v + 4) * 20); 678 inc(ElCount[Elevation[x + lx * y]]) 679 end; 627 680 end; 628 681 629 682 procedure FindContinents; 630 683 631 procedure ReplaceCont(a, b,Stop:integer);632 { replace continent name a by b}684 procedure ReplaceCont(a, b, Stop: integer); 685 { replace continent name a by b } 633 686 // make sure always continent[loc]<=loc 634 687 var 635 i: integer; 636 begin 637 if a<b then begin i:=a; a:=b; b:=i end; 638 if a>b then 639 for i:=a to Stop do if Continent[i]=a then Continent[i]:=b 640 end; 641 642 var 643 x,y,Loc,Wrong:integer; 644 begin 645 for y:=1 to ly-2 do for x:=0 to lx-1 do 646 begin 647 Loc:=x+lx*y; 648 Continent[Loc]:=-1; 649 if RealMap[Loc] and fTerrain>=fGrass then 650 begin 651 if (y-2>=1) and (RealMap[Loc-2*lx] and fTerrain>=fGrass) then 652 Continent[Loc]:=Continent[Loc-2*lx]; 653 if (x-1+y and 1>=0) and (y-1>=1) 654 and (RealMap[Loc-1+y and 1-lx] and fTerrain>=fGrass) then 655 Continent[Loc]:=Continent[Loc-1+y and 1-lx]; 656 if (x+y and 1<lx) and (y-1>=1) 657 and (RealMap[Loc+y and 1-lx] and fTerrain>=fGrass) then 658 Continent[Loc]:=Continent[Loc+y and 1-lx]; 659 if (x-1>=0) and (RealMap[Loc-1] and fTerrain>=fGrass) then 660 if Continent[Loc]=-1 then Continent[Loc]:=Continent[Loc-1] 661 else ReplaceCont(Continent[Loc-1],Continent[Loc],Loc); 662 if Continent[Loc]=-1 then Continent[Loc]:=Loc 663 end 664 end; 665 666 {connect continents due to round earth} 667 for y:=1 to ly-2 do if RealMap[lx*y] and fTerrain>=fGrass then 668 begin 669 Wrong:=-1; 670 if RealMap[lx-1+lx*y] and fTerrain>=fGrass then Wrong:=Continent[lx-1+lx*y]; 671 if (y and 1=0) and (y-1>=1) and (RealMap[lx-1+lx*(y-1)] and fTerrain>=fGrass) then 672 Wrong:=Continent[lx-1+lx*(y-1)]; 673 if (y and 1=0) and (y+1<ly-1) 674 and (RealMap[lx-1+lx*(y+1)] and fTerrain>=fGrass) then 675 Wrong:=Continent[lx-1+lx*(y+1)]; 676 if Wrong>=0 then ReplaceCont(Wrong,Continent[lx*y],MapSize-1) 677 end; 688 i: integer; 689 begin 690 if a < b then 691 begin 692 i := a; 693 a := b; 694 b := i 695 end; 696 if a > b then 697 for i := a to Stop do 698 if Continent[i] = a then 699 Continent[i] := b 700 end; 701 702 var 703 x, y, Loc, Wrong: integer; 704 begin 705 for y := 1 to ly - 2 do 706 for x := 0 to lx - 1 do 707 begin 708 Loc := x + lx * y; 709 Continent[Loc] := -1; 710 if RealMap[Loc] and fTerrain >= fGrass then 711 begin 712 if (y - 2 >= 1) and (RealMap[Loc - 2 * lx] and fTerrain >= fGrass) then 713 Continent[Loc] := Continent[Loc - 2 * lx]; 714 if (x - 1 + y and 1 >= 0) and (y - 1 >= 1) and 715 (RealMap[Loc - 1 + y and 1 - lx] and fTerrain >= fGrass) then 716 Continent[Loc] := Continent[Loc - 1 + y and 1 - lx]; 717 if (x + y and 1 < lx) and (y - 1 >= 1) and 718 (RealMap[Loc + y and 1 - lx] and fTerrain >= fGrass) then 719 Continent[Loc] := Continent[Loc + y and 1 - lx]; 720 if (x - 1 >= 0) and (RealMap[Loc - 1] and fTerrain >= fGrass) then 721 if Continent[Loc] = -1 then 722 Continent[Loc] := Continent[Loc - 1] 723 else 724 ReplaceCont(Continent[Loc - 1], Continent[Loc], Loc); 725 if Continent[Loc] = -1 then 726 Continent[Loc] := Loc 727 end 728 end; 729 730 { connect continents due to round earth } 731 for y := 1 to ly - 2 do 732 if RealMap[lx * y] and fTerrain >= fGrass then 733 begin 734 Wrong := -1; 735 if RealMap[lx - 1 + lx * y] and fTerrain >= fGrass then 736 Wrong := Continent[lx - 1 + lx * y]; 737 if (y and 1 = 0) and (y - 1 >= 1) and 738 (RealMap[lx - 1 + lx * (y - 1)] and fTerrain >= fGrass) then 739 Wrong := Continent[lx - 1 + lx * (y - 1)]; 740 if (y and 1 = 0) and (y + 1 < ly - 1) and 741 (RealMap[lx - 1 + lx * (y + 1)] and fTerrain >= fGrass) then 742 Wrong := Continent[lx - 1 + lx * (y + 1)]; 743 if Wrong >= 0 then 744 ReplaceCont(Wrong, Continent[lx * y], MapSize - 1) 745 end; 678 746 end; 679 747 … … 682 750 // must be done after FindContinents 683 751 var 684 i,j,Cnt,x,y,dx,dy,Loc0,Loc1,xworst,yworst,totalrare,RareMaxWater,RareType, 685 iBest,jbest,MinDist,xBlock,yBlock,V8: integer; 686 AreaCount, RareByArea, RareAdjacent: array[0..7,0..4] of integer; 687 RareLoc: array[0..11] of integer; 688 Dist: array[0..11,0..11] of integer; 689 Adjacent: TVicinity8Loc; 690 begin 691 RareMaxWater:=0; 692 repeat 693 FillChar(AreaCount, SizeOf(AreaCount), 0); 694 for y:=1 to ly-2 do 695 begin 696 yBlock:=y*5 div ly; 697 if yBlock=(y+1)*5 div ly then for x:=0 to lx-1 do 698 begin 699 xBlock:=x*8 div lx; 700 if xBlock=(x+1)*8 div lx then 701 begin 702 Loc0:=x+lx*y; 703 if RealMap[Loc0] and fTerrain>=fGrass then 752 i, j, Cnt, x, y, dx, dy, Loc0, Loc1, xworst, yworst, totalrare, RareMaxWater, 753 RareType, iBest, jbest, MinDist, xBlock, yBlock, V8: integer; 754 AreaCount, RareByArea, RareAdjacent: array [0 .. 7, 0 .. 4] of integer; 755 RareLoc: array [0 .. 11] of integer; 756 Dist: array [0 .. 11, 0 .. 11] of integer; 757 Adjacent: TVicinity8Loc; 758 begin 759 RareMaxWater := 0; 760 repeat 761 FillChar(AreaCount, SizeOf(AreaCount), 0); 762 for y := 1 to ly - 2 do 763 begin 764 yBlock := y * 5 div ly; 765 if yBlock = (y + 1) * 5 div ly then 766 for x := 0 to lx - 1 do 767 begin 768 xBlock := x * 8 div lx; 769 if xBlock = (x + 1) * 8 div lx then 704 770 begin 705 Cnt:=0; 706 V8_to_Loc(Loc0,Adjacent); 707 for V8:=0 to 7 do 771 Loc0 := x + lx * y; 772 if RealMap[Loc0] and fTerrain >= fGrass then 708 773 begin 709 Loc1:=Adjacent[V8]; 710 if (Loc1>=0) and (Loc1<MapSize) 711 and (RealMap[Loc1] and fTerrain<fGrass) then 712 inc(Cnt); // count adjacent water 774 Cnt := 0; 775 V8_to_Loc(Loc0, Adjacent); 776 for V8 := 0 to 7 do 777 begin 778 Loc1 := Adjacent[V8]; 779 if (Loc1 >= 0) and (Loc1 < MapSize) and 780 (RealMap[Loc1] and fTerrain < fGrass) then 781 inc(Cnt); // count adjacent water 782 end; 783 if Cnt <= RareMaxWater then // inner land 784 begin 785 inc(AreaCount[xBlock, yBlock]); 786 if Random(AreaCount[xBlock, yBlock]) = 0 then 787 RareByArea[xBlock, yBlock] := Loc0 788 end 713 789 end; 714 if Cnt<=RareMaxWater then // inner land 790 end; 791 end 792 end; 793 totalrare := 0; 794 for x := 0 to 7 do 795 for y := 0 to 4 do 796 if AreaCount[x, y] > 0 then 797 inc(totalrare); 798 inc(RareMaxWater); 799 until totalrare >= 12; 800 801 while totalrare > 12 do 802 begin // remove rarebyarea resources too close to each other 803 FillChar(RareAdjacent, SizeOf(RareAdjacent), 0); 804 for x := 0 to 7 do 805 for y := 0 to 4 do 806 if AreaCount[x, y] > 0 then 807 begin 808 if (AreaCount[(x + 1) mod 8, y] > 0) and 809 (Continent[RareByArea[x, y]] = Continent 810 [RareByArea[(x + 1) mod 8, y]]) then 811 begin 812 inc(RareAdjacent[x, y]); 813 inc(RareAdjacent[(x + 1) mod 8, y]); 814 end; 815 if y < 4 then 816 begin 817 if (AreaCount[x, y + 1] > 0) and 818 (Continent[RareByArea[x, y]] = Continent[RareByArea[x, y + 1]]) 819 then 715 820 begin 716 inc(AreaCount[xBlock,yBlock]); 717 if Random(AreaCount[xBlock,yBlock])=0 then 718 RareByArea[xBlock,yBlock]:=Loc0 821 inc(RareAdjacent[x, y]); 822 inc(RareAdjacent[x, y + 1]); 823 end; 824 if (AreaCount[(x + 1) mod 8, y + 1] > 0) and 825 (Continent[RareByArea[x, y]] = Continent[RareByArea[(x + 1) mod 8, 826 y + 1]]) then 827 begin 828 inc(RareAdjacent[x, y]); 829 inc(RareAdjacent[(x + 1) mod 8, y + 1]); 830 end; 831 if (AreaCount[(x + 7) mod 8, y + 1] > 0) and 832 (Continent[RareByArea[x, y]] = Continent[RareByArea[(x + 7) mod 8, 833 y + 1]]) then 834 begin 835 inc(RareAdjacent[x, y]); 836 inc(RareAdjacent[(x + 7) mod 8, y + 1]); 837 end; 838 end 839 end; 840 xworst := 0; 841 yworst := 0; 842 Cnt := 0; 843 for x := 0 to 7 do 844 for y := 0 to 4 do 845 if AreaCount[x, y] > 0 then 846 begin 847 if (Cnt = 0) or (RareAdjacent[x, y] > RareAdjacent[xworst, yworst]) 848 then 849 begin 850 xworst := x; 851 yworst := y; 852 Cnt := 1 853 end 854 else if (RareAdjacent[x, y] = RareAdjacent[xworst, yworst]) then 855 begin 856 inc(Cnt); 857 if Random(Cnt) = 0 then 858 begin 859 xworst := x; 860 yworst := y; 719 861 end 720 862 end; 721 863 end; 722 end 723 end; 724 totalrare:=0; 725 for x:=0 to 7 do for y:=0 to 4 do if AreaCount[x,y]>0 then 726 inc(totalrare); 727 inc(RareMaxWater); 728 until totalrare>=12; 729 730 while totalrare>12 do 731 begin // remove rarebyarea resources too close to each other 732 FillChar(RareAdjacent,SizeOf(RareAdjacent),0); 733 for x:=0 to 7 do for y:=0 to 4 do if AreaCount[x,y]>0 then 734 begin 735 if (AreaCount[(x+1) mod 8,y]>0) 736 and (Continent[RareByArea[x,y]]=Continent[RareByArea[(x+1) mod 8,y]]) then 737 begin 738 inc(RareAdjacent[x,y]); 739 inc(RareAdjacent[(x+1) mod 8,y]); 740 end; 741 if y<4 then 742 begin 743 if (AreaCount[x,y+1]>0) 744 and (Continent[RareByArea[x,y]]=Continent[RareByArea[x,y+1]]) then 745 begin 746 inc(RareAdjacent[x,y]); 747 inc(RareAdjacent[x,y+1]); 748 end; 749 if (AreaCount[(x+1) mod 8,y+1]>0) 750 and (Continent[RareByArea[x,y]]=Continent[RareByArea[(x+1) mod 8,y+1]]) then 751 begin 752 inc(RareAdjacent[x,y]); 753 inc(RareAdjacent[(x+1) mod 8,y+1]); 754 end; 755 if (AreaCount[(x+7) mod 8,y+1]>0) 756 and (Continent[RareByArea[x,y]]=Continent[RareByArea[(x+7) mod 8,y+1]]) then 757 begin 758 inc(RareAdjacent[x,y]); 759 inc(RareAdjacent[(x+7) mod 8,y+1]); 760 end; 761 end 762 end; 763 xworst:=0; yworst:=0; 764 Cnt:=0; 765 for x:=0 to 7 do for y:=0 to 4 do if AreaCount[x,y]>0 then 766 begin 767 if (Cnt=0) or (RareAdjacent[x,y]>RareAdjacent[xworst,yworst]) then 768 begin xworst:=x; yworst:=y; Cnt:=1 end 769 else if (RareAdjacent[x,y]=RareAdjacent[xworst,yworst]) then 770 begin 771 inc(Cnt); 772 if Random(Cnt)=0 then begin xworst:=x; yworst:=y; end 773 end; 774 end; 775 AreaCount[xworst,yworst]:=0; 776 dec(totalrare) 777 end; 778 779 Cnt:=0; 780 for x:=0 to 7 do for y:=0 to 4 do if AreaCount[x,y]>0 then 781 begin RareLoc[Cnt]:=RareByArea[x,y]; inc(Cnt) end; 782 for i:=0 to 11 do 783 begin 784 RealMap[RareLoc[i]]:=RealMap[RareLoc[i]] 785 and not (fTerrain or fSpecial) or (fDesert or fDeadLands); 786 for dy:=-1 to 1 do for dx:=-1 to 1 do if (dx+dy) and 1=0 then 787 begin 788 Loc1:=dLoc(RareLoc[i],dx,dy); 789 if (Loc1>=0) and (RealMap[Loc1] and fTerrain=fMountains) then 790 RealMap[Loc1]:=RealMap[Loc1] and not fTerrain or fHills; 791 end 792 end; 793 for i:=0 to 11 do for j:=0 to 11 do 794 Dist[i,j]:=Distance(RareLoc[i],RareLoc[j]); 795 796 MinDist:=Distance(0,MapSize-lx shr 1) shr 1; 797 for RareType:=1 to 3 do 798 begin 799 Cnt:=0; 800 for i:=0 to 11 do if RareLoc[i]>=0 then 801 for j:=0 to 11 do if RareLoc[j]>=0 then 802 if (Cnt>0) and (Dist[iBest,jbest]>=MinDist) then 803 begin 804 if Dist[i,j]>=MinDist then 805 begin 806 inc(Cnt); 807 if Random(Cnt)=0 then 808 begin iBest:=i; jbest:=j end 809 end 864 AreaCount[xworst, yworst] := 0; 865 dec(totalrare) 866 end; 867 868 Cnt := 0; 869 for x := 0 to 7 do 870 for y := 0 to 4 do 871 if AreaCount[x, y] > 0 then 872 begin 873 RareLoc[Cnt] := RareByArea[x, y]; 874 inc(Cnt) 875 end; 876 for i := 0 to 11 do 877 begin 878 RealMap[RareLoc[i]] := RealMap[RareLoc[i]] and not(fTerrain or fSpecial) or 879 (fDesert or fDeadLands); 880 for dy := -1 to 1 do 881 for dx := -1 to 1 do 882 if (dx + dy) and 1 = 0 then 883 begin 884 Loc1 := dLoc(RareLoc[i], dx, dy); 885 if (Loc1 >= 0) and (RealMap[Loc1] and fTerrain = fMountains) then 886 RealMap[Loc1] := RealMap[Loc1] and not fTerrain or fHills; 810 887 end 811 else if (Cnt=0) or (Dist[i,j]>Dist[iBest,jbest]) then 812 begin iBest:=i; jbest:=j; Cnt:=1; end; 813 RealMap[RareLoc[iBest]]:=RealMap[RareLoc[iBest]] or Cardinal(RareType) shl 25; 814 RealMap[RareLoc[jbest]]:=RealMap[RareLoc[jbest]] or Cardinal(RareType) shl 25; 815 RareLoc[iBest]:=-1; 816 RareLoc[jbest]:=-1; 888 end; 889 for i := 0 to 11 do 890 for j := 0 to 11 do 891 Dist[i, j] := Distance(RareLoc[i], RareLoc[j]); 892 893 MinDist := Distance(0, MapSize - lx shr 1) shr 1; 894 for RareType := 1 to 3 do 895 begin 896 Cnt := 0; 897 for i := 0 to 11 do 898 if RareLoc[i] >= 0 then 899 for j := 0 to 11 do 900 if RareLoc[j] >= 0 then 901 if (Cnt > 0) and (Dist[iBest, jbest] >= MinDist) then 902 begin 903 if Dist[i, j] >= MinDist then 904 begin 905 inc(Cnt); 906 if Random(Cnt) = 0 then 907 begin 908 iBest := i; 909 jbest := j 910 end 911 end 912 end 913 else if (Cnt = 0) or (Dist[i, j] > Dist[iBest, jbest]) then 914 begin 915 iBest := i; 916 jbest := j; 917 Cnt := 1; 918 end; 919 RealMap[RareLoc[iBest]] := RealMap[RareLoc[iBest]] or 920 Cardinal(RareType) shl 25; 921 RealMap[RareLoc[jbest]] := RealMap[RareLoc[jbest]] or 922 Cardinal(RareType) shl 25; 923 RareLoc[iBest] := -1; 924 RareLoc[jbest] := -1; 817 925 end; 818 926 end; // RarePositions … … 820 928 function CheckShore(Loc: integer): boolean; 821 929 var 822 Loc1,OldTile,V21: integer;823 Radius: TVicinity21Loc;824 begin 825 result:=false;826 OldTile:=RealMap[Loc];827 if OldTile and fTerrain<fGrass then828 begin 829 RealMap[Loc]:=RealMap[Loc] and not fTerrain or fOcean;830 V21_to_Loc(Loc,Radius);831 for V21:=1 to 26 do832 begin 833 Loc1:=Radius[V21];834 if (Loc1>=0) and (Loc1<MapSize)835 and (RealMap[Loc1] and fTerrain>=fGrass)836 and (RealMap[Loc1] and fTerrain<>fArctic) then837 RealMap[Loc]:=RealMap[Loc] and not fTerrain or fShore;838 end; 839 if (RealMap[Loc] xor Cardinal(OldTile)) and fTerrain<>0 then840 result:=true930 Loc1, OldTile, V21: integer; 931 Radius: TVicinity21Loc; 932 begin 933 result := false; 934 OldTile := RealMap[Loc]; 935 if OldTile and fTerrain < fGrass then 936 begin 937 RealMap[Loc] := RealMap[Loc] and not fTerrain or fOcean; 938 V21_to_Loc(Loc, Radius); 939 for V21 := 1 to 26 do 940 begin 941 Loc1 := Radius[V21]; 942 if (Loc1 >= 0) and (Loc1 < MapSize) and 943 (RealMap[Loc1] and fTerrain >= fGrass) and 944 (RealMap[Loc1] and fTerrain <> fArctic) then 945 RealMap[Loc] := RealMap[Loc] and not fTerrain or fShore; 946 end; 947 if (RealMap[Loc] xor Cardinal(OldTile)) and fTerrain <> 0 then 948 result := true 841 949 end; 842 950 end; … … 844 952 function ActualSpecialTile(Loc: integer): Cardinal; 845 953 begin 846 result:=SpecialTile(Loc, RealMap[Loc] and fTerrain, lx);954 result := SpecialTile(Loc, RealMap[Loc] and fTerrain, lx); 847 955 end; 848 956 849 957 procedure CreateMap(preview: boolean); 850 958 const 851 ShHiHills=6; {of land} 852 ShMountains=6; {of land} 853 ShRandHills=12; {of land} 854 ShTestRiver=40; 855 ShSwamp=25; {of grassland} 856 MinRivLen=3; 857 unification=70; 858 hotunification=50; // min. 25 859 860 Zone:array[0..3,2..9] of single= {terrain distribution} 861 ((0.25,0, 0, 0.4 ,0,0,0,0.35), 862 (0.55,0, 0.1 ,0, 0,0,0,0.35), 863 (0.4, 0, 0.35,0, 0,0,0,0.25), 864 (0, 0.7, 0, 0, 0,0,0,0.3)); 865 {Grs Dst Pra Tun - - - For} 866 867 function RndLow(y:integer):Cardinal; 868 {random lowland appropriate to climate} 959 ShHiHills = 6; { of land } 960 ShMountains = 6; { of land } 961 ShRandHills = 12; { of land } 962 ShTestRiver = 40; 963 ShSwamp = 25; { of grassland } 964 MinRivLen = 3; 965 unification = 70; 966 hotunification = 50; // min. 25 967 968 Zone: array [0 .. 3, 2 .. 9] of single = { terrain distribution } 969 ((0.25, 0, 0, 0.4, 0, 0, 0, 0.35), (0.55, 0, 0.1, 0, 0, 0, 0, 0.35), 970 (0.4, 0, 0.35, 0, 0, 0, 0, 0.25), (0, 0.7, 0, 0, 0, 0, 0, 0.3)); 971 { Grs Dst Pra Tun - - - For } 972 973 function RndLow(y: integer): Cardinal; 974 { random lowland appropriate to climate } 869 975 var 870 z0,i:integer; 871 p,p0,ZPlus:single; 872 begin 873 if ly-1-y>y then begin z0:=6*y div ly;ZPlus:=6*y/ly -z0 end 874 else begin z0:=6*(ly-1-y) div ly;ZPlus:=6*(ly-1-y)/ly -z0 end; 875 p0:=1; 876 for i:=2 to 9 do 877 begin 878 p:=Zone[z0,i]*(1-ZPlus)+Zone[z0+1,i]*ZPlus; 879 {weight between zones z0 and z0+1} 880 if Random*p0<p then begin RndLow:=i;Break end; 881 p0:=p0-p 976 z0, i: integer; 977 p, p0, ZPlus: single; 978 begin 979 if ly - 1 - y > y then 980 begin 981 z0 := 6 * y div ly; 982 ZPlus := 6 * y / ly - z0 983 end 984 else 985 begin 986 z0 := 6 * (ly - 1 - y) div ly; 987 ZPlus := 6 * (ly - 1 - y) / ly - z0 988 end; 989 p0 := 1; 990 for i := 2 to 9 do 991 begin 992 p := Zone[z0, i] * (1 - ZPlus) + Zone[z0 + 1, i] * ZPlus; 993 { weight between zones z0 and z0+1 } 994 if Random * p0 < p then 995 begin 996 RndLow := i; 997 Break 998 end; 999 p0 := p0 - p 882 1000 end; 883 1001 end; 884 1002 885 1003 function RunRiver(Loc0: integer): integer; 886 { runs river from start point Loc0; return value: length}1004 { runs river from start point Loc0; return value: length } 887 1005 var 888 Dir,T,Loc,Loc1,Cost: integer;889 Q: TIPQ;890 From: array[0..lxmax*lymax-1] of integer;891 Time: array[0..lxmax*lymax-1] of integer;892 OneTileLake: boolean;893 begin 894 FillChar(Time,SizeOf(Time),255); {-1}895 Q:=TIPQ.Create(MapSize);896 Q.Put(Loc0,0);897 while Q.Get(Loc,T) and (RealMap[Loc] and fRiver=0) do898 begin 899 if (RealMap[Loc] and fTerrain<fGrass) then900 begin 901 OneTileLake:=true;902 for Dir:=0 to 3 do903 begin 904 Loc1:=dLoc(Loc,Dir and 1 *2 -1,Dir shr 1 *2 -1);905 if (Loc1>=0) and (RealMap[Loc1] and fTerrain<fGrass) then906 OneTileLake:=false;1006 Dir, T, Loc, Loc1, Cost: integer; 1007 Q: TIPQ; 1008 From: array [0 .. lxmax * lymax - 1] of integer; 1009 Time: array [0 .. lxmax * lymax - 1] of integer; 1010 OneTileLake: boolean; 1011 begin 1012 FillChar(Time, SizeOf(Time), 255); { -1 } 1013 Q := TIPQ.Create(MapSize); 1014 Q.Put(Loc0, 0); 1015 while Q.Get(Loc, T) and (RealMap[Loc] and fRiver = 0) do 1016 begin 1017 if (RealMap[Loc] and fTerrain < fGrass) then 1018 begin 1019 OneTileLake := true; 1020 for Dir := 0 to 3 do 1021 begin 1022 Loc1 := dLoc(Loc, Dir and 1 * 2 - 1, Dir shr 1 * 2 - 1); 1023 if (Loc1 >= 0) and (RealMap[Loc1] and fTerrain < fGrass) then 1024 OneTileLake := false; 907 1025 end; 908 if not OneTileLake then Break; 909 end; 910 Time[Loc]:=T; 911 for Dir:=0 to 3 do 912 begin 913 Loc1:=dLoc(Loc,Dir and 1 *2 -1,Dir shr 1 *2 -1); 914 if (Loc1>=lx) and (Loc1<lx*(ly-1)) and (Time[Loc1]<0) then 915 begin 916 if RealMap[Loc1] and fRiver=0 then 1026 if not OneTileLake then 1027 Break; 1028 end; 1029 Time[Loc] := T; 1030 for Dir := 0 to 3 do 1031 begin 1032 Loc1 := dLoc(Loc, Dir and 1 * 2 - 1, Dir shr 1 * 2 - 1); 1033 if (Loc1 >= lx) and (Loc1 < lx * (ly - 1)) and (Time[Loc1] < 0) then 1034 begin 1035 if RealMap[Loc1] and fRiver = 0 then 917 1036 begin 918 Cost:=Elevation[Loc1]-Elevation[Loc]; 919 if Cost<0 then Cost:=0; 1037 Cost := Elevation[Loc1] - Elevation[Loc]; 1038 if Cost < 0 then 1039 Cost := 0; 920 1040 end 921 else Cost:=0; 922 if Q.Put(Loc1,T+Cost shl 8+1) then From[Loc1]:=Loc 1041 else 1042 Cost := 0; 1043 if Q.Put(Loc1, T + Cost shl 8 + 1) then 1044 From[Loc1] := Loc 923 1045 end 924 1046 end 925 1047 end; 926 Loc1:=Loc; 927 result:=0; 928 while Loc<>Loc0 do begin Loc:=From[Loc]; inc(result); end; 929 if (result>1) and ((result>=MinRivLen) or (RealMap[Loc1] and fTerrain>=fGrass)) then 930 begin 931 Loc:=Loc1; 932 while Loc<>Loc0 do 933 begin 934 Loc:=From[Loc]; 935 if RealMap[Loc] and fTerrain in [fHills,fMountains] then 936 RealMap[Loc]:=fGrass or fRiver 937 else if RealMap[Loc] and fTerrain>=fGrass then 938 RealMap[Loc]:=RealMap[Loc] or fRiver; 1048 Loc1 := Loc; 1049 result := 0; 1050 while Loc <> Loc0 do 1051 begin 1052 Loc := From[Loc]; 1053 inc(result); 1054 end; 1055 if (result > 1) and ((result >= MinRivLen) or 1056 (RealMap[Loc1] and fTerrain >= fGrass)) then 1057 begin 1058 Loc := Loc1; 1059 while Loc <> Loc0 do 1060 begin 1061 Loc := From[Loc]; 1062 if RealMap[Loc] and fTerrain in [fHills, fMountains] then 1063 RealMap[Loc] := fGrass or fRiver 1064 else if RealMap[Loc] and fTerrain >= fGrass then 1065 RealMap[Loc] := RealMap[Loc] or fRiver; 939 1066 end 940 1067 end 941 else result:=0; 942 Q.Free 943 end; 944 945 var 946 x,y,n,Dir,plus,Count,Loc0,Loc1,bLand,bHills,bMountains,V8: integer; 947 CopyFrom: array[0..lxmax*lymax-1] of integer; 948 Adjacent: TVicinity8Loc; 949 950 begin 951 FillChar(RealMap,MapSize*4,0); 952 plus:=0; 953 bMountains:=256; 954 while plus<MapSize*LandMass*ShMountains div 10000 do 955 begin dec(bMountains);inc(plus,ElCount[bMountains]) end; 956 Count:=plus; 957 plus:=0; 958 bHills:=bMountains; 959 while plus<MapSize*LandMass*ShHiHills div 10000 do 960 begin dec(bHills);inc(plus,ElCount[bHills]) end; 961 inc(Count,plus); 962 bLand:=bHills; 963 while Count<MapSize*LandMass div 100 do 964 begin dec(bLand);inc(Count,ElCount[bLand]) end; 965 966 for Loc0:=lx to lx*(ly-1)-1 do 967 if Elevation[Loc0]>=bMountains then RealMap[Loc0]:=fMountains 968 else if Elevation[Loc0]>=bHills then RealMap[Loc0]:=fHills 969 else if Elevation[Loc0]>=bLand then RealMap[Loc0]:=fGrass; 970 971 // remove one-tile islands 972 for Loc0:=0 to MapSize-1 do 973 if RealMap[Loc0]>=fGrass then 974 begin 975 Count:=0; 976 V8_to_Loc(Loc0,Adjacent); 977 for V8:=0 to 7 do 978 begin 979 Loc1:=Adjacent[V8]; 980 if (Loc1<0) or (Loc1>=MapSize) 981 or (RealMap[Loc1] and fTerrain<fGrass) 982 or (RealMap[Loc1] and fTerrain=fArctic) then 983 inc(Count); // count adjacent water 984 end; 985 if Count=8 then RealMap[Loc0]:=fOcean 986 end; 987 988 if not preview then 989 begin 990 plus:=36*56*20*ShTestRiver div (LandMass*100); 991 if plus>MapSize then plus:=MapSize; 992 Loc0:=Random(MapSize); 993 for n:=0 to plus-1 do 994 begin 995 if (RealMap[Loc0] and fTerrain>=fGrass) and (Loc0>=lx) and (Loc0<MapSize-lx) then 996 RunRiver(Loc0); 997 Loc0:=(Loc0+1)*primitive mod (MapSize+1) -1; 998 end; 999 end; 1000 1001 for Loc0:=0 to MapSize-1 do 1002 if (RealMap[Loc0]=fGrass) and (Random(100)<ShRandHills) then 1003 RealMap[Loc0]:=RealMap[Loc0] or fHills; 1004 1005 // make terrain types coherent 1006 for Loc0:=0 to MapSize-1 do CopyFrom[Loc0]:=Loc0; 1007 1008 for n:=0 to unification*MapSize div 100 do 1009 begin 1010 y:=Random(ly); 1011 if abs(y-(ly shr 1))>ly div 4+Random(ly*hotunification div 100) then 1012 if y<ly shr 1 then y:=ly shr 1-y 1013 else y:=3*ly shr 1-y; 1014 Loc0:=lx*y+Random(lx); 1015 if RealMap[Loc0] and fTerrain=fGrass then 1016 begin 1017 Dir:=Random(4); 1018 Loc1:=dLoc(Loc0,Dir and 1 *2 -1,Dir shr 1 *2 -1); 1019 if (Loc1>=0) and (RealMap[Loc1] and fTerrain=fGrass) then 1020 begin 1021 while CopyFrom[Loc0]<>Loc0 do Loc0:=CopyFrom[Loc0]; 1022 while CopyFrom[Loc1]<>Loc1 do Loc1:=CopyFrom[Loc1]; 1023 if Loc1<Loc0 then CopyFrom[Loc0]:=Loc1 1024 else CopyFrom[Loc1]:=Loc0; 1025 end; 1026 end; 1027 end; 1028 1029 for Loc0:=0 to MapSize-1 do 1030 if (RealMap[Loc0] and fTerrain=fGrass) and (CopyFrom[Loc0]=Loc0) then 1031 RealMap[Loc0]:=RealMap[Loc0] and not fTerrain or RndLow(Loc0 div lx); 1032 1033 for Loc0:=0 to MapSize-1 do 1034 if RealMap[Loc0] and fTerrain=fGrass then 1035 begin 1036 Loc1:=Loc0; 1037 while CopyFrom[Loc1]<>Loc1 do Loc1:=CopyFrom[Loc1]; 1038 RealMap[Loc0]:=RealMap[Loc0] and not fTerrain or RealMap[Loc1] and fTerrain 1039 end; 1040 1041 for Loc0:=0 to MapSize-1 do 1042 if RealMap[Loc0] and fTerrain=fGrass then 1068 else 1069 result := 0; 1070 Q.Free 1071 end; 1072 1073 var 1074 x, y, n, Dir, plus, Count, Loc0, Loc1, bLand, bHills, bMountains, V8: integer; 1075 CopyFrom: array [0 .. lxmax * lymax - 1] of integer; 1076 Adjacent: TVicinity8Loc; 1077 1078 begin 1079 FillChar(RealMap, MapSize * 4, 0); 1080 plus := 0; 1081 bMountains := 256; 1082 while plus < MapSize * LandMass * ShMountains div 10000 do 1083 begin 1084 dec(bMountains); 1085 inc(plus, ElCount[bMountains]) 1086 end; 1087 Count := plus; 1088 plus := 0; 1089 bHills := bMountains; 1090 while plus < MapSize * LandMass * ShHiHills div 10000 do 1091 begin 1092 dec(bHills); 1093 inc(plus, ElCount[bHills]) 1094 end; 1095 inc(Count, plus); 1096 bLand := bHills; 1097 while Count < MapSize * LandMass div 100 do 1098 begin 1099 dec(bLand); 1100 inc(Count, ElCount[bLand]) 1101 end; 1102 1103 for Loc0 := lx to lx * (ly - 1) - 1 do 1104 if Elevation[Loc0] >= bMountains then 1105 RealMap[Loc0] := fMountains 1106 else if Elevation[Loc0] >= bHills then 1107 RealMap[Loc0] := fHills 1108 else if Elevation[Loc0] >= bLand then 1109 RealMap[Loc0] := fGrass; 1110 1111 // remove one-tile islands 1112 for Loc0 := 0 to MapSize - 1 do 1113 if RealMap[Loc0] >= fGrass then 1114 begin 1115 Count := 0; 1116 V8_to_Loc(Loc0, Adjacent); 1117 for V8 := 0 to 7 do 1118 begin 1119 Loc1 := Adjacent[V8]; 1120 if (Loc1 < 0) or (Loc1 >= MapSize) or 1121 (RealMap[Loc1] and fTerrain < fGrass) or 1122 (RealMap[Loc1] and fTerrain = fArctic) then 1123 inc(Count); // count adjacent water 1124 end; 1125 if Count = 8 then 1126 RealMap[Loc0] := fOcean 1127 end; 1128 1129 if not preview then 1130 begin 1131 plus := 36 * 56 * 20 * ShTestRiver div (LandMass * 100); 1132 if plus > MapSize then 1133 plus := MapSize; 1134 Loc0 := Random(MapSize); 1135 for n := 0 to plus - 1 do 1136 begin 1137 if (RealMap[Loc0] and fTerrain >= fGrass) and (Loc0 >= lx) and 1138 (Loc0 < MapSize - lx) then 1139 RunRiver(Loc0); 1140 Loc0 := (Loc0 + 1) * primitive mod (MapSize + 1) - 1; 1141 end; 1142 end; 1143 1144 for Loc0 := 0 to MapSize - 1 do 1145 if (RealMap[Loc0] = fGrass) and (Random(100) < ShRandHills) then 1146 RealMap[Loc0] := RealMap[Loc0] or fHills; 1147 1148 // make terrain types coherent 1149 for Loc0 := 0 to MapSize - 1 do 1150 CopyFrom[Loc0] := Loc0; 1151 1152 for n := 0 to unification * MapSize div 100 do 1153 begin 1154 y := Random(ly); 1155 if abs(y - (ly shr 1)) > ly div 4 + Random(ly * hotunification div 100) then 1156 if y < ly shr 1 then 1157 y := ly shr 1 - y 1158 else 1159 y := 3 * ly shr 1 - y; 1160 Loc0 := lx * y + Random(lx); 1161 if RealMap[Loc0] and fTerrain = fGrass then 1162 begin 1163 Dir := Random(4); 1164 Loc1 := dLoc(Loc0, Dir and 1 * 2 - 1, Dir shr 1 * 2 - 1); 1165 if (Loc1 >= 0) and (RealMap[Loc1] and fTerrain = fGrass) then 1166 begin 1167 while CopyFrom[Loc0] <> Loc0 do 1168 Loc0 := CopyFrom[Loc0]; 1169 while CopyFrom[Loc1] <> Loc1 do 1170 Loc1 := CopyFrom[Loc1]; 1171 if Loc1 < Loc0 then 1172 CopyFrom[Loc0] := Loc1 1173 else 1174 CopyFrom[Loc1] := Loc0; 1175 end; 1176 end; 1177 end; 1178 1179 for Loc0 := 0 to MapSize - 1 do 1180 if (RealMap[Loc0] and fTerrain = fGrass) and (CopyFrom[Loc0] = Loc0) then 1181 RealMap[Loc0] := RealMap[Loc0] and not fTerrain or RndLow(Loc0 div lx); 1182 1183 for Loc0 := 0 to MapSize - 1 do 1184 if RealMap[Loc0] and fTerrain = fGrass then 1185 begin 1186 Loc1 := Loc0; 1187 while CopyFrom[Loc1] <> Loc1 do 1188 Loc1 := CopyFrom[Loc1]; 1189 RealMap[Loc0] := RealMap[Loc0] and not fTerrain or 1190 RealMap[Loc1] and fTerrain 1191 end; 1192 1193 for Loc0 := 0 to MapSize - 1 do 1194 if RealMap[Loc0] and fTerrain = fGrass then 1043 1195 begin // change grassland to swamp 1044 if Random(100)<ShSwamp then 1045 RealMap[Loc0]:=RealMap[Loc0] and not fTerrain or fSwamp; 1046 end; 1047 1048 for Loc0:=0 to MapSize-1 do // change desert to prairie 1 1049 if RealMap[Loc0] and fTerrain=fDesert then 1050 begin 1051 if RealMap[Loc0] and fRiver<>0 then Count:=5 1052 else 1053 begin 1054 Count:=0; 1055 for Dir:=0 to 3 do 1056 begin 1057 Loc1:=dLoc(Loc0,Dir and 1 *2 -1,Dir shr 1 *2 -1); 1058 if Loc1>=0 then 1059 if RealMap[Loc1] and fTerrain<fGrass then inc(Count,2) 1196 if Random(100) < ShSwamp then 1197 RealMap[Loc0] := RealMap[Loc0] and not fTerrain or fSwamp; 1198 end; 1199 1200 for Loc0 := 0 to MapSize - 1 do // change desert to prairie 1 1201 if RealMap[Loc0] and fTerrain = fDesert then 1202 begin 1203 if RealMap[Loc0] and fRiver <> 0 then 1204 Count := 5 1205 else 1206 begin 1207 Count := 0; 1208 for Dir := 0 to 3 do 1209 begin 1210 Loc1 := dLoc(Loc0, Dir and 1 * 2 - 1, Dir shr 1 * 2 - 1); 1211 if Loc1 >= 0 then 1212 if RealMap[Loc1] and fTerrain < fGrass then 1213 inc(Count, 2) 1060 1214 end; 1061 1215 end; 1062 if Count>=4 then RealMap[Loc0]:=RealMap[Loc0] and not fTerrain or fPrairie 1063 end; 1064 1065 for Loc0:=0 to MapSize-1 do // change desert to prairie 2 1066 if RealMap[Loc0] and fTerrain=fDesert then 1067 begin 1068 Count:=0; 1069 for Dir:=0 to 3 do 1070 begin 1071 Loc1:=dLoc(Loc0,Dir and 1 *2 -1,Dir shr 1 *2 -1); 1072 if Loc1>=0 then 1073 if RealMap[Loc1] and fTerrain<>fDesert then inc(Count) 1074 end; 1075 if Count>=4 then RealMap[Loc0]:=RealMap[Loc0] and not fTerrain or fPrairie 1076 end; 1077 1078 for Loc0:=0 to MapSize-1 do CheckShore(Loc0); // change ocean to shore 1079 for x:=0 to lx-1 do 1080 begin 1081 RealMap[x+lx*0]:=fArctic; 1082 if RealMap[x+lx*1]>=fGrass then 1083 RealMap[x+lx*1]:=RealMap[x+lx*1] and not fTerrain or fTundra; 1084 if RealMap[x+lx*(ly-2)]>=fGrass then 1085 RealMap[x+lx*(ly-2)]:=RealMap[x+lx*(ly-2)] and not fTerrain or fTundra; 1086 RealMap[x+lx*(ly-1)]:=fArctic 1087 end; 1088 1089 for Loc0:=0 to MapSize-1 do //define special terrain tiles 1090 RealMap[Loc0]:=RealMap[Loc0] or ActualSpecialTile(Loc0) shl 5 or ($F shl 27); 1091 1092 if not preview then 1093 begin FindContinents; RarePositions; end; 1216 if Count >= 4 then 1217 RealMap[Loc0] := RealMap[Loc0] and not fTerrain or fPrairie 1218 end; 1219 1220 for Loc0 := 0 to MapSize - 1 do // change desert to prairie 2 1221 if RealMap[Loc0] and fTerrain = fDesert then 1222 begin 1223 Count := 0; 1224 for Dir := 0 to 3 do 1225 begin 1226 Loc1 := dLoc(Loc0, Dir and 1 * 2 - 1, Dir shr 1 * 2 - 1); 1227 if Loc1 >= 0 then 1228 if RealMap[Loc1] and fTerrain <> fDesert then 1229 inc(Count) 1230 end; 1231 if Count >= 4 then 1232 RealMap[Loc0] := RealMap[Loc0] and not fTerrain or fPrairie 1233 end; 1234 1235 for Loc0 := 0 to MapSize - 1 do 1236 CheckShore(Loc0); // change ocean to shore 1237 for x := 0 to lx - 1 do 1238 begin 1239 RealMap[x + lx * 0] := fArctic; 1240 if RealMap[x + lx * 1] >= fGrass then 1241 RealMap[x + lx * 1] := RealMap[x + lx * 1] and not fTerrain or fTundra; 1242 if RealMap[x + lx * (ly - 2)] >= fGrass then 1243 RealMap[x + lx * (ly - 2)] := RealMap[x + lx * (ly - 2)] and 1244 not fTerrain or fTundra; 1245 RealMap[x + lx * (ly - 1)] := fArctic 1246 end; 1247 1248 for Loc0 := 0 to MapSize - 1 do // define special terrain tiles 1249 RealMap[Loc0] := RealMap[Loc0] or ActualSpecialTile(Loc0) shl 5 or 1250 ($F shl 27); 1251 1252 if not preview then 1253 begin 1254 FindContinents; 1255 RarePositions; 1256 end; 1094 1257 end; 1095 1258 … … 1099 1262 1100 1263 var 1101 CountGood:(cgBest,cgFlat,cgLand);1264 CountGood: (cgBest, cgFlat, cgLand); 1102 1265 1103 1266 function IsGoodTile(Loc: integer): boolean; 1104 1267 var 1105 xLoc,yLoc: integer; 1106 begin 1107 xLoc:=Loc mod lx; yLoc:=Loc div lx; 1108 if RealMap[Loc] and fDeadLands<>0 then result:=false 1109 else 1110 case CountGood of 1111 cgBest: 1112 result:=(RealMap[Loc] and fTerrain in [fGrass,fPrairie,fTundra,fSwamp,fForest]) 1113 and Odd((lymax+xLoc-yLoc shr 1) shr 1+xLoc+(yLoc+1) shr 1); 1114 cgFlat: 1115 result:=(RealMap[Loc] and fTerrain in [fGrass,fPrairie,fTundra,fSwamp,fForest]); 1116 cgLand: 1117 result:= RealMap[Loc] and fTerrain>=fGrass; 1268 xLoc, yLoc: integer; 1269 begin 1270 xLoc := Loc mod lx; 1271 yLoc := Loc div lx; 1272 if RealMap[Loc] and fDeadLands <> 0 then 1273 result := false 1274 else 1275 case CountGood of 1276 cgBest: 1277 result := (RealMap[Loc] and fTerrain in [fGrass, fPrairie, fTundra, 1278 fSwamp, fForest]) and Odd((lymax + xLoc - yLoc shr 1) shr 1 + xLoc + 1279 (yLoc + 1) shr 1); 1280 cgFlat: 1281 result := (RealMap[Loc] and fTerrain in [fGrass, fPrairie, fTundra, 1282 fSwamp, fForest]); 1283 cgLand: 1284 result := RealMap[Loc] and fTerrain >= fGrass; 1118 1285 end; 1119 1286 end; 1120 1287 1121 1288 const 1122 MaxCityLoc=64; 1123 1124 var 1125 p1,p2,nAlive,c,Loc,Loc1,CntGood,CntGoodGrass,MinDist,Tries,i,j,n,nsc,TestLoc, 1126 V21,V8,BestDist,TestDist,MinGood,nIrrLoc,xLoc,yLoc,qx,qy,FineDistSQR, 1127 nRest:integer; 1128 ccount:array[0..lxmax*lymax-1] of word; 1129 sc,StartLoc0,sccount: array[1..nPl] of integer; 1130 TestStartLoc: array[0..nPl-1] of integer; 1131 CityLoc: array[1..nPl,0..MaxCityLoc-1] of integer; 1132 nCityLoc: array[1..nPl] of integer; 1133 RestLoc: array[0..MaxCityLoc-1] of integer; 1134 IrrLoc: array[0..20] of integer; 1135 Radius: TVicinity21Loc; 1136 Adjacent: TVicinity8Loc; 1137 ok: boolean; 1138 1139 begin 1140 nAlive:=0; 1141 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then inc(nAlive); 1142 if nAlive=0 then exit; 1143 1144 {count good tiles} 1145 FillChar(ccount,MapSize*2,0); 1146 for Loc:=0 to MapSize-1 do 1147 if RealMap[Loc] and fTerrain=fGrass then 1148 if ActualSpecialTile(Loc)=1 then inc(ccount[Continent[Loc]],3) 1149 else inc(ccount[Continent[Loc]],2) 1150 else if RealMap[Loc] and fTerrain in [fPrairie,fSwamp,fForest,fHills] then 1151 inc(ccount[Continent[Loc]]); 1152 1153 Loc:=0;while ccount[Loc]>0 do inc(Loc); 1154 for i:=1 to nAlive do begin sc[i]:=Loc; sccount[i]:=1 end; 1155 {init with zero size start continents, then search bigger ones} 1156 for Loc:=0 to MapSize-1 do if ccount[Loc]>0 then 1157 begin // search biggest continents 1158 p1:=nAlive+1; 1159 while (p1>1) and (ccount[Loc]>ccount[sc[p1-1]]) do 1160 begin if p1<nAlive+1 then sc[p1]:=sc[p1-1]; dec(p1) end; 1161 if p1<nAlive+1 then sc[p1]:=Loc; 1162 end; 1163 nsc:=nAlive; 1164 repeat 1165 c:=1; // search least crowded continent after smallest 1166 for i:=2 to nsc-1 do 1167 if ccount[sc[i]]*(2*sccount[c]+1)>ccount[sc[c]]*(2*sccount[i]+1) then 1168 c:=i; 1169 if ccount[sc[nsc]]*(2*sccount[c]+1)>ccount[sc[c]] then 1170 Break; // even least crowded continent is more crowded than smallest 1171 inc(sccount[c]); 1172 dec(nsc) 1173 until sccount[nsc]>1; 1174 1175 MinGood:=7; 1176 CountGood:=cgBest; 1177 repeat 1178 dec(MinGood); 1179 if (MinGood=3) and (CountGood<cgLand) then // too demanding! 1180 begin inc(CountGood); MinGood:=6 end; 1181 FillChar(nCityLoc,SizeOf(nCityLoc),0); 1182 Loc:=Random(MapSize); 1183 for i:=0 to MapSize-1 do 1184 begin 1185 if ((Loc>=4*lx) and (Loc<MapSize-4*lx) or (CountGood>=cgLand)) 1186 and IsGoodTile(Loc) then 1187 begin 1188 c:=nsc; 1189 while (c>0) and (Continent[Loc]<>sc[c]) do dec(c); 1190 if (c>0) and (nCityLoc[c]<MaxCityLoc) then 1191 begin 1192 CntGood:=1; 1193 V21_to_Loc(Loc,Radius); 1194 for V21:=1 to 26 do if V21<>CityOwnTile then 1289 MaxCityLoc = 64; 1290 1291 var 1292 p1, p2, nAlive, c, Loc, Loc1, CntGood, CntGoodGrass, MinDist, Tries, i, j, n, 1293 nsc, TestLoc, V21, V8, BestDist, TestDist, MinGood, nIrrLoc, xLoc, yLoc, qx, 1294 qy, FineDistSQR, nRest: integer; 1295 ccount: array [0 .. lxmax * lymax - 1] of word; 1296 sc, StartLoc0, sccount: array [1 .. nPl] of integer; 1297 TestStartLoc: array [0 .. nPl - 1] of integer; 1298 CityLoc: array [1 .. nPl, 0 .. MaxCityLoc - 1] of integer; 1299 nCityLoc: array [1 .. nPl] of integer; 1300 RestLoc: array [0 .. MaxCityLoc - 1] of integer; 1301 IrrLoc: array [0 .. 20] of integer; 1302 Radius: TVicinity21Loc; 1303 Adjacent: TVicinity8Loc; 1304 ok: boolean; 1305 1306 begin 1307 nAlive := 0; 1308 for p1 := 0 to nPl - 1 do 1309 if 1 shl p1 and GAlive <> 0 then 1310 inc(nAlive); 1311 if nAlive = 0 then 1312 exit; 1313 1314 { count good tiles } 1315 FillChar(ccount, MapSize * 2, 0); 1316 for Loc := 0 to MapSize - 1 do 1317 if RealMap[Loc] and fTerrain = fGrass then 1318 if ActualSpecialTile(Loc) = 1 then 1319 inc(ccount[Continent[Loc]], 3) 1320 else 1321 inc(ccount[Continent[Loc]], 2) 1322 else if RealMap[Loc] and fTerrain in [fPrairie, fSwamp, fForest, fHills] 1323 then 1324 inc(ccount[Continent[Loc]]); 1325 1326 Loc := 0; 1327 while ccount[Loc] > 0 do 1328 inc(Loc); 1329 for i := 1 to nAlive do 1330 begin 1331 sc[i] := Loc; 1332 sccount[i] := 1 1333 end; 1334 { init with zero size start continents, then search bigger ones } 1335 for Loc := 0 to MapSize - 1 do 1336 if ccount[Loc] > 0 then 1337 begin // search biggest continents 1338 p1 := nAlive + 1; 1339 while (p1 > 1) and (ccount[Loc] > ccount[sc[p1 - 1]]) do 1340 begin 1341 if p1 < nAlive + 1 then 1342 sc[p1] := sc[p1 - 1]; 1343 dec(p1) 1344 end; 1345 if p1 < nAlive + 1 then 1346 sc[p1] := Loc; 1347 end; 1348 nsc := nAlive; 1349 repeat 1350 c := 1; // search least crowded continent after smallest 1351 for i := 2 to nsc - 1 do 1352 if ccount[sc[i]] * (2 * sccount[c] + 1) > ccount[sc[c]] * 1353 (2 * sccount[i] + 1) then 1354 c := i; 1355 if ccount[sc[nsc]] * (2 * sccount[c] + 1) > ccount[sc[c]] then 1356 Break; // even least crowded continent is more crowded than smallest 1357 inc(sccount[c]); 1358 dec(nsc) 1359 until sccount[nsc] > 1; 1360 1361 MinGood := 7; 1362 CountGood := cgBest; 1363 repeat 1364 dec(MinGood); 1365 if (MinGood = 3) and (CountGood < cgLand) then // too demanding! 1366 begin 1367 inc(CountGood); 1368 MinGood := 6 1369 end; 1370 FillChar(nCityLoc, SizeOf(nCityLoc), 0); 1371 Loc := Random(MapSize); 1372 for i := 0 to MapSize - 1 do 1373 begin 1374 if ((Loc >= 4 * lx) and (Loc < MapSize - 4 * lx) or (CountGood >= cgLand)) 1375 and IsGoodTile(Loc) then 1376 begin 1377 c := nsc; 1378 while (c > 0) and (Continent[Loc] <> sc[c]) do 1379 dec(c); 1380 if (c > 0) and (nCityLoc[c] < MaxCityLoc) then 1381 begin 1382 CntGood := 1; 1383 V21_to_Loc(Loc, Radius); 1384 for V21 := 1 to 26 do 1385 if V21 <> CityOwnTile then 1386 begin 1387 Loc1 := Radius[V21]; 1388 if (Loc1 >= 0) and (Loc1 < MapSize) and IsGoodTile(Loc1) then 1389 inc(CntGood) 1390 end; 1391 if CntGood >= MinGood then 1195 1392 begin 1196 Loc1:=Radius[V21]; 1197 if (Loc1>=0) and (Loc1<MapSize) and IsGoodTile(Loc1) then 1198 inc(CntGood) 1199 end; 1200 if CntGood>=MinGood then 1201 begin 1202 CityLoc[c,nCityLoc[c]]:=Loc; 1203 inc(nCityLoc[c]) 1393 CityLoc[c, nCityLoc[c]] := Loc; 1394 inc(nCityLoc[c]) 1204 1395 end 1205 1396 end 1206 1397 end; 1207 Loc:=(Loc+1)*primitive mod (MapSize+1) -1; 1208 end; 1209 1210 ok:=true; 1211 for c:=1 to nsc do 1212 if nCityLoc[c]<sccount[c]*(8-MinGood) div (7-MinGood) then ok:=false; 1213 until ok; 1214 1215 FineDistSQR:=MapSize*LandMass*9 div (nAlive*100); 1216 p1:=1; 1217 for c:=1 to nsc do 1398 Loc := (Loc + 1) * primitive mod (MapSize + 1) - 1; 1399 end; 1400 1401 ok := true; 1402 for c := 1 to nsc do 1403 if nCityLoc[c] < sccount[c] * (8 - MinGood) div (7 - MinGood) then 1404 ok := false; 1405 until ok; 1406 1407 FineDistSQR := MapSize * LandMass * 9 div (nAlive * 100); 1408 p1 := 1; 1409 for c := 1 to nsc do 1218 1410 begin // for all start continents 1219 if sccount[c]=1 then StartLoc0[p1]:=CityLoc[c,Random(nCityLoc[c])] 1220 else 1221 begin 1222 BestDist:=0; 1223 n:=1 shl sccount[c] *32; // number of tries to find good distribution 1224 if n>1 shl 12 then n:=1 shl 12; 1225 while (n>0) and (BestDist*BestDist<FineDistSQR) do 1226 begin 1227 MinDist:=MaxInt; 1228 nRest:=nCityLoc[c]; 1229 for i:=0 to nRest-1 do RestLoc[i]:=CityLoc[c,i]; 1230 for i:=0 to sccount[c]-1 do 1231 begin 1232 if nRest=0 then break; 1233 j:=Random(nRest); 1234 TestStartLoc[i]:=RestLoc[j]; 1235 RestLoc[j]:=RestLoc[nRest-1]; 1236 dec(nRest); 1237 for j:=0 to i-1 do 1411 if sccount[c] = 1 then 1412 StartLoc0[p1] := CityLoc[c, Random(nCityLoc[c])] 1413 else 1414 begin 1415 BestDist := 0; 1416 n := 1 shl sccount[c] * 32; // number of tries to find good distribution 1417 if n > 1 shl 12 then 1418 n := 1 shl 12; 1419 while (n > 0) and (BestDist * BestDist < FineDistSQR) do 1420 begin 1421 MinDist := MaxInt; 1422 nRest := nCityLoc[c]; 1423 for i := 0 to nRest - 1 do 1424 RestLoc[i] := CityLoc[c, i]; 1425 for i := 0 to sccount[c] - 1 do 1426 begin 1427 if nRest = 0 then 1428 Break; 1429 j := Random(nRest); 1430 TestStartLoc[i] := RestLoc[j]; 1431 RestLoc[j] := RestLoc[nRest - 1]; 1432 dec(nRest); 1433 for j := 0 to i - 1 do 1238 1434 begin 1239 TestDist:=Distance(TestStartLoc[i],TestStartLoc[j]); 1240 if TestDist<MinDist then MinDist:=TestDist 1435 TestDist := Distance(TestStartLoc[i], TestStartLoc[j]); 1436 if TestDist < MinDist then 1437 MinDist := TestDist 1241 1438 end; 1242 if i=sccount[c]-1 then1439 if i = sccount[c] - 1 then 1243 1440 begin 1244 assert(MinDist>BestDist); 1245 BestDist:=MinDist; 1246 for j:=0 to sccount[c]-1 do StartLoc0[p1+j]:=TestStartLoc[j]; 1441 assert(MinDist > BestDist); 1442 BestDist := MinDist; 1443 for j := 0 to sccount[c] - 1 do 1444 StartLoc0[p1 + j] := TestStartLoc[j]; 1247 1445 end 1248 else if BestDist>0 then1446 else if BestDist > 0 then 1249 1447 begin 1250 j:=0;1251 while j<nRest do1448 j := 0; 1449 while j < nRest do 1252 1450 begin // remove all locs from rest which have too little distance to this one 1253 TestDist:=Distance(TestStartLoc[i],RestLoc[j]); 1254 if TestDist<=BestDist then 1255 begin RestLoc[j]:=RestLoc[nRest-1]; dec(nRest); end 1256 else inc(j); 1451 TestDist := Distance(TestStartLoc[i], RestLoc[j]); 1452 if TestDist <= BestDist then 1453 begin 1454 RestLoc[j] := RestLoc[nRest - 1]; 1455 dec(nRest); 1456 end 1457 else 1458 inc(j); 1257 1459 end; 1258 1460 end; 1259 1461 end; 1260 dec(n) 1261 end; 1262 end; 1263 p1:=p1+sccount[c] 1264 end; 1265 1266 // make start locs fertile 1267 for p1:=1 to nAlive do 1268 begin 1269 RealMap[StartLoc0[p1]]:=RealMap[StartLoc0[p1]] and not (fTerrain or fSpecial) 1270 or fGrass or fSpecial1; 1271 CntGood:=1; 1272 CntGoodGrass:=1; 1273 V21_to_Loc(StartLoc0[p1],Radius); 1274 for V21:=1 to 26 do if V21<>CityOwnTile then 1275 begin 1276 Loc1:=Radius[V21]; 1277 if (Loc1>=0) and (Loc1<MapSize) and IsGoodTile(Loc1) then 1278 if RealMap[Loc1] and fTerrain=fGrass then inc(CntGoodGrass) 1279 else inc(CntGood); 1280 end; 1281 for V21:=1 to 26 do if V21<>CityOwnTile then 1282 begin 1283 Loc1:=Radius[V21]; 1284 if (Loc1>=0) and (Loc1<MapSize) and (RealMap[Loc1] and fDeadLands=0) then 1285 if IsGoodTile(Loc1) and (random(CntGood)<MinGood-CntGoodGrass+1) then 1286 begin 1287 RealMap[Loc1]:=RealMap[Loc1] and not (fTerrain or fSpecial) or fGrass; 1288 RealMap[Loc1]:=RealMap[Loc1] or ActualSpecialTile(Loc1) shl 5; 1462 dec(n) 1463 end; 1464 end; 1465 p1 := p1 + sccount[c] 1466 end; 1467 1468 // make start locs fertile 1469 for p1 := 1 to nAlive do 1470 begin 1471 RealMap[StartLoc0[p1]] := RealMap[StartLoc0[p1]] and 1472 not(fTerrain or fSpecial) or fGrass or fSpecial1; 1473 CntGood := 1; 1474 CntGoodGrass := 1; 1475 V21_to_Loc(StartLoc0[p1], Radius); 1476 for V21 := 1 to 26 do 1477 if V21 <> CityOwnTile then 1478 begin 1479 Loc1 := Radius[V21]; 1480 if (Loc1 >= 0) and (Loc1 < MapSize) and IsGoodTile(Loc1) then 1481 if RealMap[Loc1] and fTerrain = fGrass then 1482 inc(CntGoodGrass) 1483 else 1484 inc(CntGood); 1485 end; 1486 for V21 := 1 to 26 do 1487 if V21 <> CityOwnTile then 1488 begin 1489 Loc1 := Radius[V21]; 1490 if (Loc1 >= 0) and (Loc1 < MapSize) and 1491 (RealMap[Loc1] and fDeadLands = 0) then 1492 if IsGoodTile(Loc1) and (Random(CntGood) < MinGood - CntGoodGrass + 1) 1493 then 1494 begin 1495 RealMap[Loc1] := RealMap[Loc1] and not(fTerrain or fSpecial) 1496 or fGrass; 1497 RealMap[Loc1] := RealMap[Loc1] or ActualSpecialTile(Loc1) shl 5; 1498 end 1499 else if RealMap[Loc1] and fTerrain = fDesert then 1500 RealMap[Loc1] := RealMap[Loc1] and not fTerrain or fPrairie 1501 else if (RealMap[Loc1] and fTerrain in [fPrairie, fTundra, fSwamp]) 1502 and (Random(2) = 0) then 1503 RealMap[Loc1] := RealMap[Loc1] and not fTerrain or fForest; 1504 end; 1505 1506 // first irrigation 1507 nIrrLoc := 0; 1508 for V21 := 1 to 26 do 1509 if V21 <> CityOwnTile then 1510 begin 1511 Loc1 := Radius[V21]; 1512 if (Loc1 >= 0) and (Loc1 < MapSize) and 1513 (RealMap[Loc1] and (fTerrain or fSpecial) = fGrass or fSpecial1) then 1514 begin 1515 IrrLoc[nIrrLoc] := Loc1; 1516 inc(nIrrLoc); 1517 end; 1518 end; 1519 i := 2; 1520 if i > nIrrLoc then 1521 i := nIrrLoc; 1522 while i > 0 do 1523 begin 1524 j := Random(nIrrLoc); 1525 RealMap[IrrLoc[j]] := RealMap[IrrLoc[j]] or tiIrrigation; 1526 IrrLoc[j] := IrrLoc[nIrrLoc - 1]; 1527 dec(nIrrLoc); 1528 dec(i) 1529 end; 1530 end; 1531 1532 StartLoc[0] := 0; 1533 for p1 := 0 to nPl - 1 do 1534 if 1 shl p1 and GAlive <> 0 then 1535 begin 1536 repeat 1537 i := Random(nAlive) + 1 1538 until StartLoc0[i] >= 0; 1539 StartLoc[p1] := StartLoc0[i]; 1540 StartLoc0[i] := -1 1541 end; 1542 SaveMapCenterLoc := StartLoc[0]; 1543 1544 // second unit starting position 1545 for p1 := 0 to nPl - 1 do 1546 if 1 shl p1 and GAlive <> 0 then 1547 begin 1548 StartLoc2[p1] := StartLoc[p1]; 1549 V8_to_Loc(StartLoc[p1], Adjacent); 1550 for V8 := 0 to 7 do 1551 begin 1552 Loc1 := Adjacent[V8]; 1553 for p2 := 0 to nPl - 1 do 1554 if (1 shl p2 and GAlive <> 0) and (StartLoc[p2] = Loc1) then 1555 Loc1 := -1; 1556 for p2 := 0 to p1 - 1 do 1557 if (1 shl p2 and GAlive <> 0) and (StartLoc2[p2] = Loc1) then 1558 Loc1 := -1; 1559 if (Loc1 < 0) or (Loc1 >= MapSize) or 1560 (RealMap[Loc1] and fTerrain in [fOcean, fShore, fDesert, fArctic, 1561 fMountains]) or (RealMap[Loc1] and fDeadLands <> 0) then 1562 TestDist := -1 1563 else if RealMap[Loc1] and fTerrain = fGrass then 1564 TestDist := 2 1565 else if Terrain[RealMap[Loc1] and fTerrain].IrrEff > 0 then 1566 TestDist := 1 1567 else 1568 TestDist := 0; 1569 if (StartLoc2[p1] = StartLoc[p1]) or (TestDist > BestDist) then 1570 begin 1571 StartLoc2[p1] := Loc1; 1572 BestDist := TestDist; 1573 n := 1; 1289 1574 end 1290 else if RealMap[Loc1] and fTerrain=fDesert then 1291 RealMap[Loc1]:=RealMap[Loc1] and not fTerrain or fPrairie 1292 else if (RealMap[Loc1] and fTerrain in [fPrairie,fTundra,fSwamp]) 1293 and (random(2)=0) then 1294 RealMap[Loc1]:=RealMap[Loc1] and not fTerrain or fForest; 1295 end; 1296 1297 // first irrigation 1298 nIrrLoc:=0; 1299 for V21:=1 to 26 do if V21<>CityOwnTile then 1300 begin 1301 Loc1:=Radius[V21]; 1302 if (Loc1>=0) and (Loc1<MapSize) 1303 and (RealMap[Loc1] and (fTerrain or fSpecial)=fGrass or fSpecial1) then 1304 begin 1305 IrrLoc[nIrrLoc]:=Loc1; 1306 inc(nIrrLoc); 1307 end; 1308 end; 1309 i:=2; 1310 if i>nIrrLoc then i:=nIrrLoc; 1311 while i>0 do 1312 begin 1313 j:=random(nIrrLoc); 1314 RealMap[IrrLoc[j]]:=RealMap[IrrLoc[j]] or tiIrrigation; 1315 IrrLoc[j]:=IrrLoc[nIrrLoc-1]; 1316 dec(nIrrLoc); 1317 dec(i) 1318 end; 1319 end; 1320 1321 StartLoc[0]:=0; 1322 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then 1323 begin 1324 repeat i:=Random(nAlive)+1 until StartLoc0[i]>=0; 1325 StartLoc[p1]:=StartLoc0[i]; 1326 StartLoc0[i]:=-1 1327 end; 1328 SaveMapCenterLoc:=StartLoc[0]; 1329 1330 // second unit starting position 1331 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then 1332 begin 1333 StartLoc2[p1]:=StartLoc[p1]; 1334 V8_to_Loc(StartLoc[p1],Adjacent); 1335 for V8:=0 to 7 do 1336 begin 1337 Loc1:=Adjacent[V8]; 1338 for p2:=0 to nPl-1 do 1339 if (1 shl p2 and GAlive<>0) and (StartLoc[p2]=Loc1) then Loc1:=-1; 1340 for p2:=0 to p1-1 do 1341 if (1 shl p2 and GAlive<>0) and (StartLoc2[p2]=Loc1) then Loc1:=-1; 1342 if (Loc1<0) or (Loc1>=MapSize) 1343 or (RealMap[Loc1] and fTerrain in [fOcean, fShore, fDesert, fArctic, fMountains]) 1344 or (RealMap[Loc1] and fDeadLands<>0) then 1345 TestDist:=-1 1346 else if RealMap[Loc1] and fTerrain=fGrass then TestDist:=2 1347 else if Terrain[RealMap[Loc1] and fTerrain].IrrEff>0 then TestDist:=1 1348 else TestDist:=0; 1349 if (StartLoc2[p1]=StartLoc[p1]) or (TestDist>BestDist) then 1350 begin StartLoc2[p1]:=Loc1; BestDist:=TestDist; n:=1; end 1351 else if TestDist=BestDist then 1352 begin inc(n); if random(n)=0 then StartLoc2[p1]:=Loc1; end; 1353 end 1354 end; 1355 end; {StartPositions} 1575 else if TestDist = BestDist then 1576 begin 1577 inc(n); 1578 if Random(n) = 0 then 1579 StartLoc2[p1] := Loc1; 1580 end; 1581 end 1582 end; 1583 end; { StartPositions } 1356 1584 1357 1585 procedure PredefinedStartPositions(Human: integer); 1358 1586 // use predefined nation start positions 1359 1587 var 1360 i,p1,Loc1,nAlive,nStartLoc0,nPrefStartLoc0,imax: integer; 1361 StartLoc0: array[0..lxmax*lymax-1] of integer; 1362 ishuman: boolean; 1363 begin 1364 nAlive:=0; 1365 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then inc(nAlive); 1366 if nAlive=0 then exit; 1367 1368 // calculate starting positions 1369 nStartLoc0:=0; 1370 nPrefStartLoc0:=0; 1371 for Loc1:=0 to MapSize-1 do 1372 if RealMap[Loc1] and fPrefStartPos<>0 then 1373 begin 1374 StartLoc0[nStartLoc0]:=StartLoc0[nPrefStartLoc0]; 1375 StartLoc0[nPrefStartLoc0]:=Loc1; 1376 inc(nPrefStartLoc0); 1377 inc(nStartLoc0); 1378 RealMap[Loc1]:=RealMap[Loc1] and not fPrefStartPos; 1588 i, p1, Loc1, nAlive, nStartLoc0, nPrefStartLoc0, imax: integer; 1589 StartLoc0: array [0 .. lxmax * lymax - 1] of integer; 1590 ishuman: boolean; 1591 begin 1592 nAlive := 0; 1593 for p1 := 0 to nPl - 1 do 1594 if 1 shl p1 and GAlive <> 0 then 1595 inc(nAlive); 1596 if nAlive = 0 then 1597 exit; 1598 1599 // calculate starting positions 1600 nStartLoc0 := 0; 1601 nPrefStartLoc0 := 0; 1602 for Loc1 := 0 to MapSize - 1 do 1603 if RealMap[Loc1] and fPrefStartPos <> 0 then 1604 begin 1605 StartLoc0[nStartLoc0] := StartLoc0[nPrefStartLoc0]; 1606 StartLoc0[nPrefStartLoc0] := Loc1; 1607 inc(nPrefStartLoc0); 1608 inc(nStartLoc0); 1609 RealMap[Loc1] := RealMap[Loc1] and not fPrefStartPos; 1379 1610 end 1380 else if RealMap[Loc1] and fStartPos<>0 then 1381 begin 1382 StartLoc0[nStartLoc0]:=Loc1; 1383 inc(nStartLoc0); 1384 RealMap[Loc1]:=RealMap[Loc1] and not fStartPos; 1385 end; 1386 assert(nStartLoc0>=nAlive); 1387 1388 StartLoc[0]:=0; 1389 for ishuman:=true downto false do for p1:=0 to nPl-1 do 1390 if (1 shl p1 and GAlive<>0) and ((1 shl p1 and Human<>0)=ishuman) then 1391 begin 1392 dec(nStartLoc0); 1393 imax:=nStartLoc0; 1394 if nPrefStartLoc0>0 then 1395 begin 1396 dec(nPrefStartLoc0); 1397 imax:=nPrefStartLoc0; 1398 end; 1399 i:=Random(imax+1); 1400 StartLoc[p1]:=StartLoc0[i]; 1401 StartLoc2[p1]:=StartLoc0[i]; 1402 StartLoc0[i]:=StartLoc0[imax]; 1403 StartLoc0[imax]:=StartLoc0[nStartLoc0]; 1404 end; 1405 SaveMapCenterLoc:=StartLoc[0]; 1406 end; {PredefinedStartPositions} 1611 else if RealMap[Loc1] and fStartPos <> 0 then 1612 begin 1613 StartLoc0[nStartLoc0] := Loc1; 1614 inc(nStartLoc0); 1615 RealMap[Loc1] := RealMap[Loc1] and not fStartPos; 1616 end; 1617 assert(nStartLoc0 >= nAlive); 1618 1619 StartLoc[0] := 0; 1620 for ishuman := true downto false do 1621 for p1 := 0 to nPl - 1 do 1622 if (1 shl p1 and GAlive <> 0) and ((1 shl p1 and Human <> 0) = ishuman) 1623 then 1624 begin 1625 dec(nStartLoc0); 1626 imax := nStartLoc0; 1627 if nPrefStartLoc0 > 0 then 1628 begin 1629 dec(nPrefStartLoc0); 1630 imax := nPrefStartLoc0; 1631 end; 1632 i := Random(imax + 1); 1633 StartLoc[p1] := StartLoc0[i]; 1634 StartLoc2[p1] := StartLoc0[i]; 1635 StartLoc0[i] := StartLoc0[imax]; 1636 StartLoc0[imax] := StartLoc0[nStartLoc0]; 1637 end; 1638 SaveMapCenterLoc := StartLoc[0]; 1639 end; { PredefinedStartPositions } 1407 1640 1408 1641 procedure InitGame; 1409 1642 var 1410 i, p, p1, uix, Loc1: integer; 1411 begin 1412 if FastContact then {Railroad everywhere} 1413 for Loc1:=0 to MapSize-1 do 1414 if RealMap[Loc1] and fTerrain>=fGrass then RealMap[Loc1]:=RealMap[Loc1] or fRR; 1415 1416 {!!!for Loc1:=0 to MapSize-1 do 1417 if RealMap[Loc1] and fterrain>=fGrass then 1643 i, p, p1, uix, Loc1: integer; 1644 begin 1645 if FastContact then { Railroad everywhere } 1646 for Loc1 := 0 to MapSize - 1 do 1647 if RealMap[Loc1] and fTerrain >= fGrass then 1648 RealMap[Loc1] := RealMap[Loc1] or fRR; 1649 1650 { !!!for Loc1:=0 to MapSize-1 do 1651 if RealMap[Loc1] and fterrain>=fGrass then 1418 1652 if random(3)=0 then RealMap[Loc1]:=RealMap[Loc1] or fRoad 1419 1653 else if random(3)=0 then RealMap[Loc1]:=RealMap[Loc1] or fRR; 1420 {random Road and Railroad} 1421 {!!!for Loc1:=0 to MapSize-1 do 1422 if (RealMap[Loc1] and fterrain>=fGrass) and (random(20)=0) then 1423 RealMap[Loc1]:=RealMap[Loc1] or fPoll;} 1424 1425 FillChar(Occupant,MapSize,-1); 1426 FillChar(ZoCMap,MapSize,0); 1427 FillChar(ObserveLevel,MapSize*4,0); 1428 FillChar(UsedByCity,MapSize*4,-1); 1429 GTestFlags:=0; 1430 GInitialized:=GAlive or GWatching; 1431 for p:=0 to nPl-1 do if 1 shl p and GInitialized<>0 then with RW[p] do 1432 begin 1433 Researched[p]:=0; 1434 Discovered[p]:=0; 1435 TerritoryCount[p]:=0; 1436 nTech[p]:=0; 1437 if Difficulty[p]=0 then ResourceMask[p]:=$FFFFFFFF 1438 else ResourceMask[p]:=$FFFFFFFF and not (fSpecial2 or fModern); 1439 GrWallContinent[p]:=-1; 1440 1441 GetMem(Map,4*MapSize); 1442 GetMem(MapObservedLast,2*MapSize); 1443 FillChar(MapObservedLast^,2*MapSize,-1); 1444 GetMem(Territory,MapSize); 1445 FillChar(Territory^,MapSize,$FF); 1446 GetMem(Un,numax*SizeOf(TUn)); 1447 GetMem(Model,(nmmax+1)*SizeOf(TModel)); // draft needs one model behind last 1448 GetMem(City,ncmax*SizeOf(TCity)); 1449 GetMem(EnemyUn,neumax*SizeOf(TUnitInfo)); 1450 GetMem(EnemyCity,necmax*SizeOf(TCityInfo)); 1451 GetMem(EnemyModel,nemmax*SizeOf(TModelInfo)); 1452 for p1:=0 to nPl-1 do 1453 begin 1454 if 1 shl p1 and GInitialized<>0 then 1455 begin 1456 FillChar(RWemix[p,p1],SizeOf(RWemix[p,p1]),255); {-1} 1457 FillChar(Destroyed[p,p1],SizeOf(Destroyed[p,p1]),0); 1458 end; 1459 Attitude[p1]:=atNeutral; 1460 Treaty[p1]:=trNoContact; 1461 LastCancelTreaty[p1]:=-CancelTreatyTurns-1; 1462 EvaStart[p1]:=-PeaceEvaTurns-1; 1463 Tribute[p1]:=0; 1464 TributePaid[p1]:=0; 1465 if (p1<>p) and (1 shl p1 and GAlive<>0) then 1466 begin // initialize enemy report 1467 GetMem(EnemyReport[p1],SizeOf(TEnemyReport)-2*(INFIN+1-nmmax)); 1468 FillChar(EnemyReport[p1].Tech,nAdv,tsNA); 1469 EnemyReport[p1].TurnOfContact:=-1; 1470 EnemyReport[p1].TurnOfCivilReport:=-1; 1471 EnemyReport[p1].TurnOfMilReport:=-1; 1472 EnemyReport[p1].Attitude:=atNeutral; 1473 EnemyReport[p1].Government:=gDespotism; 1474 if 1 shl p and GAlive=0 then Treaty[p1]:=trNone // supervisor 1475 end 1476 else EnemyReport[p1]:=nil; 1477 end; 1478 TestFlags:=GTestFlags; 1479 Credibility:=InitialCredibility; 1480 MaxCredibility:=100; 1481 nUn:=0; 1482 nModel:=0; 1483 nCity:=0; 1484 nEnemyUn:=0; 1485 nEnemyCity:=0; 1486 nEnemyModel:=0; 1487 for Loc1:=0 to MapSize-1 do Map[Loc1]:=fUNKNOWN; 1488 FillChar(Tech,nAdv,tsNA); 1489 FillChar(NatBuilt,SizeOf(NatBuilt),0); 1490 end; 1491 1492 // create initial models and units 1493 for p:=0 to nPl-1 do if (1 shl p and GAlive<>0) then with RW[p] do 1494 begin 1495 nModel:=0; 1496 for i:=0 to nSpecialModel-1 do if SpecialModelPreq[i]=preNone then 1497 begin 1498 Model[nModel]:=SpecialModel[i]; 1499 Model[nModel].Status:=0; 1500 Model[nModel].IntroTurn:=0; 1501 Model[nModel].Built:=0; 1502 Model[nModel].Lost:=0; 1503 Model[nModel].ID:=p shl 12+nModel; 1504 SetModelFlags(Model[nModel]); 1505 inc(nModel) 1506 end; 1507 nUn:=0; 1508 UnBuilt[p]:=0; 1509 for uix:=0 to nStartUn-1 do 1510 begin 1511 CreateUnit(p, StartUn[uix]); 1512 dec(Model[StartUn[uix]].Built); 1513 Un[uix].Loc:=StartLoc2[p]; 1514 PlaceUnit(p,uix); 1515 end; 1516 FoundCity(p,StartLoc[p]); // capital 1517 Founded[p]:=1; 1518 with City[0] do 1519 begin 1520 ID:=p shl 12; 1521 Flags:=chFounded; 1522 end; 1523 end; 1524 1525 TerritoryCount[nPl]:=MapSize; 1526 //fillchar(NewContact, sizeof(NewContact), false); 1654 {random Road and Railroad } 1655 { !!!for Loc1:=0 to MapSize-1 do 1656 if (RealMap[Loc1] and fterrain>=fGrass) and (random(20)=0) then 1657 RealMap[Loc1]:=RealMap[Loc1] or fPoll; } 1658 1659 FillChar(Occupant, MapSize, -1); 1660 FillChar(ZoCMap, MapSize, 0); 1661 FillChar(ObserveLevel, MapSize * 4, 0); 1662 FillChar(UsedByCity, MapSize * 4, -1); 1663 GTestFlags := 0; 1664 GInitialized := GAlive or GWatching; 1665 for p := 0 to nPl - 1 do 1666 if 1 shl p and GInitialized <> 0 then 1667 with RW[p] do 1668 begin 1669 Researched[p] := 0; 1670 Discovered[p] := 0; 1671 TerritoryCount[p] := 0; 1672 nTech[p] := 0; 1673 if Difficulty[p] = 0 then 1674 ResourceMask[p] := $FFFFFFFF 1675 else 1676 ResourceMask[p] := $FFFFFFFF and not(fSpecial2 or fModern); 1677 GrWallContinent[p] := -1; 1678 1679 GetMem(Map, 4 * MapSize); 1680 GetMem(MapObservedLast, 2 * MapSize); 1681 FillChar(MapObservedLast^, 2 * MapSize, -1); 1682 GetMem(Territory, MapSize); 1683 FillChar(Territory^, MapSize, $FF); 1684 GetMem(Un, numax * SizeOf(TUn)); 1685 GetMem(Model, (nmmax + 1) * SizeOf(TModel)); 1686 // draft needs one model behind last 1687 GetMem(City, ncmax * SizeOf(TCity)); 1688 GetMem(EnemyUn, neumax * SizeOf(TUnitInfo)); 1689 GetMem(EnemyCity, necmax * SizeOf(TCityInfo)); 1690 GetMem(EnemyModel, nemmax * SizeOf(TModelInfo)); 1691 for p1 := 0 to nPl - 1 do 1692 begin 1693 if 1 shl p1 and GInitialized <> 0 then 1694 begin 1695 FillChar(RWemix[p, p1], SizeOf(RWemix[p, p1]), 255); { -1 } 1696 FillChar(Destroyed[p, p1], SizeOf(Destroyed[p, p1]), 0); 1697 end; 1698 Attitude[p1] := atNeutral; 1699 Treaty[p1] := trNoContact; 1700 LastCancelTreaty[p1] := -CancelTreatyTurns - 1; 1701 EvaStart[p1] := -PeaceEvaTurns - 1; 1702 Tribute[p1] := 0; 1703 TributePaid[p1] := 0; 1704 if (p1 <> p) and (1 shl p1 and GAlive <> 0) then 1705 begin // initialize enemy report 1706 GetMem(EnemyReport[p1], SizeOf(TEnemyReport) - 2 * 1707 (INFIN + 1 - nmmax)); 1708 FillChar(EnemyReport[p1].Tech, nAdv, tsNA); 1709 EnemyReport[p1].TurnOfContact := -1; 1710 EnemyReport[p1].TurnOfCivilReport := -1; 1711 EnemyReport[p1].TurnOfMilReport := -1; 1712 EnemyReport[p1].Attitude := atNeutral; 1713 EnemyReport[p1].Government := gDespotism; 1714 if 1 shl p and GAlive = 0 then 1715 Treaty[p1] := trNone // supervisor 1716 end 1717 else 1718 EnemyReport[p1] := nil; 1719 end; 1720 TestFlags := GTestFlags; 1721 Credibility := InitialCredibility; 1722 MaxCredibility := 100; 1723 nUn := 0; 1724 nModel := 0; 1725 nCity := 0; 1726 nEnemyUn := 0; 1727 nEnemyCity := 0; 1728 nEnemyModel := 0; 1729 for Loc1 := 0 to MapSize - 1 do 1730 Map[Loc1] := fUNKNOWN; 1731 FillChar(Tech, nAdv, tsNA); 1732 FillChar(NatBuilt, SizeOf(NatBuilt), 0); 1733 end; 1734 1735 // create initial models and units 1736 for p := 0 to nPl - 1 do 1737 if (1 shl p and GAlive <> 0) then 1738 with RW[p] do 1739 begin 1740 nModel := 0; 1741 for i := 0 to nSpecialModel - 1 do 1742 if SpecialModelPreq[i] = preNone then 1743 begin 1744 Model[nModel] := SpecialModel[i]; 1745 Model[nModel].Status := 0; 1746 Model[nModel].IntroTurn := 0; 1747 Model[nModel].Built := 0; 1748 Model[nModel].Lost := 0; 1749 Model[nModel].ID := p shl 12 + nModel; 1750 SetModelFlags(Model[nModel]); 1751 inc(nModel) 1752 end; 1753 nUn := 0; 1754 UnBuilt[p] := 0; 1755 for uix := 0 to nStartUn - 1 do 1756 begin 1757 CreateUnit(p, StartUn[uix]); 1758 dec(Model[StartUn[uix]].Built); 1759 Un[uix].Loc := StartLoc2[p]; 1760 PlaceUnit(p, uix); 1761 end; 1762 FoundCity(p, StartLoc[p]); // capital 1763 Founded[p] := 1; 1764 with City[0] do 1765 begin 1766 ID := p shl 12; 1767 Flags := chFounded; 1768 end; 1769 end; 1770 1771 TerritoryCount[nPl] := MapSize; 1772 // fillchar(NewContact, sizeof(NewContact), false); 1527 1773 end; // InitGame 1528 1774 1529 1775 procedure InitRandomGame; 1530 1776 begin 1531 RandSeed:=RND;1532 CalculatePrimitive;1533 CreateElevation;1534 CreateMap(false);1535 StartPositions;1536 InitGame;1537 end; { InitRandomGame}1777 RandSeed := RND; 1778 CalculatePrimitive; 1779 CreateElevation; 1780 CreateMap(false); 1781 StartPositions; 1782 InitGame; 1783 end; { InitRandomGame } 1538 1784 1539 1785 procedure InitMapGame(Human: integer); 1540 1786 begin 1541 RandSeed:=RND;1542 FindContinents;1543 PredefinedStartPositions(Human);1544 InitGame;1545 end; { InitMapGame}1787 RandSeed := RND; 1788 FindContinents; 1789 PredefinedStartPositions(Human); 1790 InitGame; 1791 end; { InitMapGame } 1546 1792 1547 1793 procedure ReleaseGame; 1548 1794 var 1549 p1,p2: integer; 1550 begin 1551 for p1:=0 to nPl-1 do if 1 shl p1 and GInitialized<>0 then 1552 begin 1553 for p2:=0 to nPl-1 do 1554 if RW[p1].EnemyReport[p2]<>nil then 1555 FreeMem(RW[p1].EnemyReport[p2]); 1556 FreeMem(RW[p1].EnemyUn); 1557 FreeMem(RW[p1].EnemyCity); 1558 FreeMem(RW[p1].EnemyModel); 1559 FreeMem(RW[p1].Un); 1560 FreeMem(RW[p1].City); 1561 FreeMem(RW[p1].Model); 1562 FreeMem(RW[p1].Territory); 1563 FreeMem(RW[p1].MapObservedLast); 1564 FreeMem(RW[p1].Map); 1565 end 1795 p1, p2: integer; 1796 begin 1797 for p1 := 0 to nPl - 1 do 1798 if 1 shl p1 and GInitialized <> 0 then 1799 begin 1800 for p2 := 0 to nPl - 1 do 1801 if RW[p1].EnemyReport[p2] <> nil then 1802 FreeMem(RW[p1].EnemyReport[p2]); 1803 FreeMem(RW[p1].EnemyUn); 1804 FreeMem(RW[p1].EnemyCity); 1805 FreeMem(RW[p1].EnemyModel); 1806 FreeMem(RW[p1].Un); 1807 FreeMem(RW[p1].City); 1808 FreeMem(RW[p1].Model); 1809 FreeMem(RW[p1].Territory); 1810 FreeMem(RW[p1].MapObservedLast); 1811 FreeMem(RW[p1].Map); 1812 end 1566 1813 end; 1567 1814 1568 1815 procedure InitMapEditor; 1569 1816 var 1570 p1: integer; 1571 begin 1572 CalculatePrimitive; 1573 FillChar(Occupant,MapSize,-1); 1574 FillChar(ObserveLevel,MapSize*4,0); 1575 with RW[0] do 1576 begin 1577 ResourceMask[0]:=$FFFFFFFF; 1578 GetMem(Map,4*MapSize); 1579 GetMem(MapObservedLast,2*MapSize); 1580 FillChar(MapObservedLast^,2*MapSize,-1); 1581 GetMem(Territory,MapSize); 1582 FillChar(Territory^,MapSize,$FF); 1583 Un:=nil; 1584 Model:=nil; 1585 City:=nil; 1586 EnemyUn:=nil; 1587 EnemyCity:=nil; 1588 EnemyModel:=nil; 1589 for p1:=0 to nPl-1 do EnemyReport[p1]:=nil; 1590 nUn:=0; 1591 nModel:=0; 1592 nCity:=0; 1593 nEnemyUn:=0; 1594 nEnemyCity:=0; 1595 nEnemyModel:=0; 1817 p1: integer; 1818 begin 1819 CalculatePrimitive; 1820 FillChar(Occupant, MapSize, -1); 1821 FillChar(ObserveLevel, MapSize * 4, 0); 1822 with RW[0] do 1823 begin 1824 ResourceMask[0] := $FFFFFFFF; 1825 GetMem(Map, 4 * MapSize); 1826 GetMem(MapObservedLast, 2 * MapSize); 1827 FillChar(MapObservedLast^, 2 * MapSize, -1); 1828 GetMem(Territory, MapSize); 1829 FillChar(Territory^, MapSize, $FF); 1830 Un := nil; 1831 Model := nil; 1832 City := nil; 1833 EnemyUn := nil; 1834 EnemyCity := nil; 1835 EnemyModel := nil; 1836 for p1 := 0 to nPl - 1 do 1837 EnemyReport[p1] := nil; 1838 nUn := 0; 1839 nModel := 0; 1840 nCity := 0; 1841 nEnemyUn := 0; 1842 nEnemyCity := 0; 1843 nEnemyModel := 0; 1596 1844 end; 1597 1845 end; … … 1599 1847 procedure ReleaseMapEditor; 1600 1848 begin 1601 FreeMem(RW[0].Territory);1602 FreeMem(RW[0].MapObservedLast);1603 FreeMem(RW[0].Map);1849 FreeMem(RW[0].Territory); 1850 FreeMem(RW[0].MapObservedLast); 1851 FreeMem(RW[0].Map); 1604 1852 end; 1605 1853 1606 1854 procedure EditTile(Loc, NewTile: integer); 1607 1855 var 1608 Loc1,V21: integer; 1609 Radius: TVicinity21Loc; 1610 begin 1611 if NewTile and fDeadLands<>0 then 1612 NewTile:=NewTile and (fDeadLands or fModern or fRiver) or fDesert; 1613 case NewTile and fTerrain of 1614 fOcean, fShore: NewTile:=NewTile and (fTerrain or fSpecial); 1615 fMountains,fArctic: NewTile:=NewTile and not fRiver; 1616 end; 1617 with Terrain[NewTile and fTerrain] do 1618 if (ClearTerrain>=0) or (AfforestTerrain>=0) or (TransTerrain>=0) then 1619 NewTile:=NewTile or fSpecial; // only automatic special resources for transformable tiles 1620 if NewTile and fRR<>0 then NewTile:=NewTile and not fRoad; 1621 if not ((NewTile and fTerrain) in TerrType_Canalable) then 1622 NewTile:=NewTile and not fCanal; 1623 if Terrain[NewTile and fTerrain].IrrEff=0 then 1624 begin 1625 NewTile:=NewTile and not (fPrefStartPos or fStartPos); 1626 if (NewTile and fTerImp=tiIrrigation) or (NewTile and fTerImp=tiFarm) then 1627 NewTile:=NewTile and not fTerImp 1628 end; 1629 if (Terrain[NewTile and fTerrain].MineEff=0) 1630 and (NewTile and fTerImp=tiMine) then 1631 NewTile:=NewTile and not fTerImp; 1632 1633 RealMap[Loc]:=NewTile; 1634 if NewTile and fSpecial=fSpecial then // standard special resource distribution 1635 RealMap[Loc]:=RealMap[Loc] and not fSpecial or ActualSpecialTile(Loc) shl 5; 1636 1637 // automatic shore tiles 1638 V21_to_Loc(Loc,Radius); 1639 for V21:=1 to 26 do 1640 begin 1641 Loc1:=Radius[V21]; 1642 if (Loc1>=0) and (Loc1<MapSize) then 1643 begin 1644 if CheckShore(Loc1) then 1645 RealMap[Loc1]:=RealMap[Loc1] and not fSpecial or ActualSpecialTile(Loc1) shl 5; 1646 RealMap[Loc1]:=RealMap[Loc1] or ($F shl 27); 1647 RW[0].Map[Loc1]:=RealMap[Loc1] and $07FFFFFF or fObserved; 1856 Loc1, V21: integer; 1857 Radius: TVicinity21Loc; 1858 begin 1859 if NewTile and fDeadLands <> 0 then 1860 NewTile := NewTile and (fDeadLands or fModern or fRiver) or fDesert; 1861 case NewTile and fTerrain of 1862 fOcean, fShore: 1863 NewTile := NewTile and (fTerrain or fSpecial); 1864 fMountains, fArctic: 1865 NewTile := NewTile and not fRiver; 1866 end; 1867 with Terrain[NewTile and fTerrain] do 1868 if (ClearTerrain >= 0) or (AfforestTerrain >= 0) or (TransTerrain >= 0) then 1869 NewTile := NewTile or fSpecial; 1870 // only automatic special resources for transformable tiles 1871 if NewTile and fRR <> 0 then 1872 NewTile := NewTile and not fRoad; 1873 if not((NewTile and fTerrain) in TerrType_Canalable) then 1874 NewTile := NewTile and not fCanal; 1875 if Terrain[NewTile and fTerrain].IrrEff = 0 then 1876 begin 1877 NewTile := NewTile and not(fPrefStartPos or fStartPos); 1878 if (NewTile and fTerImp = tiIrrigation) or (NewTile and fTerImp = tiFarm) 1879 then 1880 NewTile := NewTile and not fTerImp 1881 end; 1882 if (Terrain[NewTile and fTerrain].MineEff = 0) and 1883 (NewTile and fTerImp = tiMine) then 1884 NewTile := NewTile and not fTerImp; 1885 1886 RealMap[Loc] := NewTile; 1887 if NewTile and fSpecial = fSpecial then 1888 // standard special resource distribution 1889 RealMap[Loc] := RealMap[Loc] and not fSpecial or 1890 ActualSpecialTile(Loc) shl 5; 1891 1892 // automatic shore tiles 1893 V21_to_Loc(Loc, Radius); 1894 for V21 := 1 to 26 do 1895 begin 1896 Loc1 := Radius[V21]; 1897 if (Loc1 >= 0) and (Loc1 < MapSize) then 1898 begin 1899 if CheckShore(Loc1) then 1900 RealMap[Loc1] := RealMap[Loc1] and not fSpecial or 1901 ActualSpecialTile(Loc1) shl 5; 1902 RealMap[Loc1] := RealMap[Loc1] or ($F shl 27); 1903 RW[0].Map[Loc1] := RealMap[Loc1] and $07FFFFFF or fObserved; 1648 1904 end 1649 1905 end; 1650 //RealMap[Loc]:=RealMap[Loc] and not fSpecial;1651 //RW[0].Map[Loc]:=RealMap[Loc] or fObserved;1906 // RealMap[Loc]:=RealMap[Loc] and not fSpecial; 1907 // RW[0].Map[Loc]:=RealMap[Loc] or fObserved; 1652 1908 end; 1653 1909 1654 1910 { 1655 Map Revealing1656 ____________________________________________________________________1911 Map Revealing 1912 ____________________________________________________________________ 1657 1913 } 1658 1914 function GetTileInfo(p, cix, Loc: integer; var Info: TTileInfo): integer; … … 1661 1917 // cix=-2 - don't search city, don't calculate city benefits, just government of player p 1662 1918 var 1663 p0,Tile,special: integer; 1664 begin 1665 with Info do 1666 begin 1667 p0:=p; 1668 if cix>=0 then Tile:=RealMap[Loc] 1669 else 1670 begin 1671 Tile:=RW[p].Map[Loc]; 1672 if Tile and fTerrain=fUNKNOWN then begin result:=eNoPreq; exit end; 1673 end; 1674 1675 if (cix=-1) and (UsedByCity[Loc]>=0) then 1919 p0, Tile, special: integer; 1920 begin 1921 with Info do 1922 begin 1923 p0 := p; 1924 if cix >= 0 then 1925 Tile := RealMap[Loc] 1926 else 1927 begin 1928 Tile := RW[p].Map[Loc]; 1929 if Tile and fTerrain = fUNKNOWN then 1930 begin 1931 result := eNoPreq; 1932 exit 1933 end; 1934 end; 1935 1936 if (cix = -1) and (UsedByCity[Loc] >= 0) then 1676 1937 begin // search exploiting player and city 1677 SearchCity(UsedByCity[Loc],p,cix); 1678 if not ((p=p0) or (ObserveLevel[UsedByCity[Loc]] shr (2*p0) and 3=lObserveSuper)) then 1679 cix:=-1 1680 end; 1681 if cix=-1 then begin result:=eInvalid; exit end; // no city found here 1682 1683 special:=Tile and fSpecial and ResourceMask[p] shr 5; 1684 with Terrain[Tile and fTerrain] do 1685 begin 1686 Food:=FoodRes[special]; 1687 Prod:=ProdRes[special]; 1688 Trade:=TradeRes[special]; 1689 if (special>0) and (Tile and fTerrain<>fGrass) 1690 and (RW[p].NatBuilt[imSpacePort]>0) then 1938 SearchCity(UsedByCity[Loc], p, cix); 1939 if not((p = p0) or (ObserveLevel[UsedByCity[Loc]] shr (2 * p0) and 1940 3 = lObserveSuper)) then 1941 cix := -1 1942 end; 1943 if cix = -1 then 1944 begin 1945 result := eInvalid; 1946 exit 1947 end; // no city found here 1948 1949 special := Tile and fSpecial and ResourceMask[p] shr 5; 1950 with Terrain[Tile and fTerrain] do 1951 begin 1952 Food := FoodRes[special]; 1953 Prod := ProdRes[special]; 1954 Trade := TradeRes[special]; 1955 if (special > 0) and (Tile and fTerrain <> fGrass) and 1956 (RW[p].NatBuilt[imSpacePort] > 0) then 1691 1957 begin // GeoSat effect 1692 Food:=2*Food-FoodRes[0]; 1693 Prod:=2*Prod-ProdRes[0]; 1694 Trade:=2*Trade-TradeRes[0]; 1695 end; 1696 1697 if (Tile and fTerImp=tiIrrigation) or (Tile and fTerImp=tiFarm) 1698 or (Tile and fCity<>0) then 1699 inc(Food,IrrEff); {irrigation effect} 1700 if Tile and fTerImp=tiMine then inc(Prod,MineEff); {mining effect} 1701 if (Tile and fRiver<>0) and (RW[p].Tech[adMapMaking]>=tsApplicable) then 1702 inc(Trade); {river effect} 1703 if (Tile and (fRoad or fRR)<>0) and (MoveCost=1) 1704 and (RW[p].Tech[adWheel]>=tsApplicable) then 1705 inc(Trade); {road effect} 1706 if (Tile and (fRR or fCity)<>0) and (RW[p].Tech[adRailroad]>=tsApplicable) then 1707 inc(Prod,Prod shr 1); {railroad effect} 1708 1709 ExplCity:=-1; 1710 if (cix>=0) and (p=p0) then ExplCity:=cix; 1711 if cix>=0 then 1712 if Tile and fTerrain>=fGrass then 1713 begin 1714 if ((Tile and fTerImp=tiFarm) or (Tile and fCity<>0)) 1715 and (RW[p].City[cix].Built[imSupermarket]>0) then 1716 inc(Food,Food shr 1); {farmland effect} 1717 if (Tile and (fRoad or fRR)<>0) and (MoveCost=1) 1718 and (RW[p].City[cix].Built[imHighways]>0) then 1719 inc(Trade,1); {superhighway effect} 1958 Food := 2 * Food - FoodRes[0]; 1959 Prod := 2 * Prod - ProdRes[0]; 1960 Trade := 2 * Trade - TradeRes[0]; 1961 end; 1962 1963 if (Tile and fTerImp = tiIrrigation) or (Tile and fTerImp = tiFarm) or 1964 (Tile and fCity <> 0) then 1965 inc(Food, IrrEff); { irrigation effect } 1966 if Tile and fTerImp = tiMine then 1967 inc(Prod, MineEff); { mining effect } 1968 if (Tile and fRiver <> 0) and (RW[p].Tech[adMapMaking] >= tsApplicable) 1969 then 1970 inc(Trade); { river effect } 1971 if (Tile and (fRoad or fRR) <> 0) and (MoveCost = 1) and 1972 (RW[p].Tech[adWheel] >= tsApplicable) then 1973 inc(Trade); { road effect } 1974 if (Tile and (fRR or fCity) <> 0) and 1975 (RW[p].Tech[adRailroad] >= tsApplicable) then 1976 inc(Prod, Prod shr 1); { railroad effect } 1977 1978 ExplCity := -1; 1979 if (cix >= 0) and (p = p0) then 1980 ExplCity := cix; 1981 if cix >= 0 then 1982 if Tile and fTerrain >= fGrass then 1983 begin 1984 if ((Tile and fTerImp = tiFarm) or (Tile and fCity <> 0)) and 1985 (RW[p].City[cix].Built[imSupermarket] > 0) then 1986 inc(Food, Food shr 1); { farmland effect } 1987 if (Tile and (fRoad or fRR) <> 0) and (MoveCost = 1) and 1988 (RW[p].City[cix].Built[imHighways] > 0) then 1989 inc(Trade, 1); { superhighway effect } 1720 1990 end 1721 else 1722 begin 1723 if RW[p].City[cix].Built[imHarbor]>0 then inc(Food); {harbour effect} 1724 if RW[p].City[cix].Built[imPlatform]>0 then inc(Prod); {oil platform effect} 1725 if GWonder[woLighthouse].EffectiveOwner=p then inc(Prod); 1991 else 1992 begin 1993 if RW[p].City[cix].Built[imHarbor] > 0 then 1994 inc(Food); { harbour effect } 1995 if RW[p].City[cix].Built[imPlatform] > 0 then 1996 inc(Prod); { oil platform effect } 1997 if GWonder[woLighthouse].EffectiveOwner = p then 1998 inc(Prod); 1726 1999 end; 1727 2000 end; 1728 2001 1729 {good government influence} 1730 if (RW[p].Government in [gRepublic,gDemocracy,gFuture]) and (Trade>0) then 1731 inc(Trade); 1732 if (RW[p].Government=gCommunism) and (Prod>1) then 1733 inc(Prod); 1734 1735 if RW[p].Government in [gAnarchy,gDespotism] then 1736 begin {bad government influence} 1737 if Food>3 then Food:=3; 1738 if Prod>2 then Prod:=2; 1739 if Trade>2 then Trade:=2; 1740 end; 1741 1742 if Tile and (fTerrain or fPoll)>fPoll then 1743 begin {pollution - decrease ressources} 1744 dec(Food,Food shr 1); 1745 dec(Prod,Prod shr 1); 1746 dec(Trade,Trade shr 1); 1747 end; 1748 1749 if Tile and fCity<>0 then Trade:=0 1750 else if (cix>=0) 1751 and (RW[p].City[cix].Built[imCourt]+RW[p].City[cix].Built[imPalace]=0) then 1752 if RW[p].City[cix].Built[imTownHall]=0 then Trade:=0 1753 else if Trade>3 then Trade:=3; 1754 end; 1755 result:=eOK; 1756 end; {GetTileInfo} 1757 1758 procedure Strongest(Loc:integer;var uix,Strength,Bonus,Cnt:integer); 1759 {find strongest defender at Loc} 1760 var 1761 Defender,uix1,Det,Cost,TestStrength,TestBonus,TestDet,TestCost,Domain: integer; 1762 PUn: ^TUn; 1763 PModel: ^TModel; 1764 begin 1765 Defender:=Occupant[Loc]; 1766 Cnt:=0; 1767 Det:=-1; 1768 for uix1:=0 to RW[Defender].nUn-1 do 1769 begin 1770 PUn:=@RW[Defender].Un[uix1]; 1771 PModel:=@RW[Defender].Model[PUn.mix]; 1772 if PModel.Kind=mkSpecial_Glider then Domain:=dGround 1773 else Domain:=PModel.Domain; 1774 if PUn.Loc=Loc then 1775 begin 1776 inc(Cnt); 1777 if PUn.Master<0 then 1778 begin 1779 if Domain<dSea then 1780 begin 1781 TestBonus:=Terrain[RealMap[Loc] and fTerrain].Defense; 1782 if RealMap[Loc] and fTerImp=tiFort then inc(TestBonus,4); 1783 if PUn.Flags and unFortified<>0 then inc(TestBonus,2); 1784 if (PModel.Kind=mkSpecial_TownGuard) and (RealMap[Loc] and fCity<>0) then 1785 inc(TestBonus,4); 2002 { good government influence } 2003 if (RW[p].Government in [gRepublic, gDemocracy, gFuture]) and (Trade > 0) 2004 then 2005 inc(Trade); 2006 if (RW[p].Government = gCommunism) and (Prod > 1) then 2007 inc(Prod); 2008 2009 if RW[p].Government in [gAnarchy, gDespotism] then 2010 begin { bad government influence } 2011 if Food > 3 then 2012 Food := 3; 2013 if Prod > 2 then 2014 Prod := 2; 2015 if Trade > 2 then 2016 Trade := 2; 2017 end; 2018 2019 if Tile and (fTerrain or fPoll) > fPoll then 2020 begin { pollution - decrease ressources } 2021 dec(Food, Food shr 1); 2022 dec(Prod, Prod shr 1); 2023 dec(Trade, Trade shr 1); 2024 end; 2025 2026 if Tile and fCity <> 0 then 2027 Trade := 0 2028 else if (cix >= 0) and (RW[p].City[cix].Built[imCourt] + RW[p].City[cix] 2029 .Built[imPalace] = 0) then 2030 if RW[p].City[cix].Built[imTownHall] = 0 then 2031 Trade := 0 2032 else if Trade > 3 then 2033 Trade := 3; 2034 end; 2035 result := eOK; 2036 end; { GetTileInfo } 2037 2038 procedure Strongest(Loc: integer; var uix, Strength, Bonus, Cnt: integer); 2039 { find strongest defender at Loc } 2040 var 2041 Defender, uix1, Det, Cost, TestStrength, TestBonus, TestDet, TestCost, 2042 Domain: integer; 2043 PUn: ^TUn; 2044 PModel: ^TModel; 2045 begin 2046 Defender := Occupant[Loc]; 2047 Cnt := 0; 2048 Det := -1; 2049 for uix1 := 0 to RW[Defender].nUn - 1 do 2050 begin 2051 PUn := @RW[Defender].Un[uix1]; 2052 PModel := @RW[Defender].Model[PUn.mix]; 2053 if PModel.Kind = mkSpecial_Glider then 2054 Domain := dGround 2055 else 2056 Domain := PModel.Domain; 2057 if PUn.Loc = Loc then 2058 begin 2059 inc(Cnt); 2060 if PUn.Master < 0 then 2061 begin 2062 if Domain < dSea then 2063 begin 2064 TestBonus := Terrain[RealMap[Loc] and fTerrain].Defense; 2065 if RealMap[Loc] and fTerImp = tiFort then 2066 inc(TestBonus, 4); 2067 if PUn.Flags and unFortified <> 0 then 2068 inc(TestBonus, 2); 2069 if (PModel.Kind = mkSpecial_TownGuard) and 2070 (RealMap[Loc] and fCity <> 0) then 2071 inc(TestBonus, 4); 1786 2072 end 1787 else TestBonus:=4; 1788 inc(TestBonus,PUn.Exp div ExpCost); 1789 TestStrength:=PModel.Defense*TestBonus*PUn.Health; 1790 if (Domain=dAir) and ((RealMap[Loc] and fCity<>0) 1791 or (RealMap[Loc] and fTerImp=tiBase)) then 1792 TestStrength:=0; 1793 if (Domain=dSea) and (RealMap[Loc] and fTerrain>=fGrass) then 1794 TestStrength:=TestStrength shr 1; 1795 TestDet:=TestStrength; 1796 if PModel.Cap[mcStealth]>0 then 1797 else if PModel.Cap[mcSub]>0 then inc(TestDet,1 shl 28) 1798 else if (Domain=dGround) and (PModel.Cap[mcFanatic]>0) 1799 and not (RW[Defender].Government in [gRepublic,gDemocracy,gFuture]) then 1800 inc(TestDet,4 shl 28) // fanatic ground units always defend 1801 else if PModel.Flags and mdZOC<>0 then 1802 inc(TestDet,3 shl 28) 1803 else inc(TestDet,2 shl 28); 1804 TestCost:=RW[Defender].Model[PUn.mix].Cost; 1805 if (TestDet>Det) or (TestDet=Det) and (TestCost<Cost) then 1806 begin 1807 uix:=uix1; 1808 Strength:=TestStrength; 1809 Bonus:=TestBonus; 1810 Det:=TestDet; 1811 Cost:=TestCost; 2073 else 2074 TestBonus := 4; 2075 inc(TestBonus, PUn.exp div ExpCost); 2076 TestStrength := PModel.Defense * TestBonus * PUn.Health; 2077 if (Domain = dAir) and ((RealMap[Loc] and fCity <> 0) or 2078 (RealMap[Loc] and fTerImp = tiBase)) then 2079 TestStrength := 0; 2080 if (Domain = dSea) and (RealMap[Loc] and fTerrain >= fGrass) then 2081 TestStrength := TestStrength shr 1; 2082 TestDet := TestStrength; 2083 if PModel.Cap[mcStealth] > 0 then 2084 else if PModel.Cap[mcSub] > 0 then 2085 inc(TestDet, 1 shl 28) 2086 else if (Domain = dGround) and (PModel.Cap[mcFanatic] > 0) and 2087 not(RW[Defender].Government in [gRepublic, gDemocracy, gFuture]) then 2088 inc(TestDet, 4 shl 28) // fanatic ground units always defend 2089 else if PModel.Flags and mdZOC <> 0 then 2090 inc(TestDet, 3 shl 28) 2091 else 2092 inc(TestDet, 2 shl 28); 2093 TestCost := RW[Defender].Model[PUn.mix].Cost; 2094 if (TestDet > Det) or (TestDet = Det) and (TestCost < Cost) then 2095 begin 2096 uix := uix1; 2097 Strength := TestStrength; 2098 Bonus := TestBonus; 2099 Det := TestDet; 2100 Cost := TestCost; 1812 2101 end 1813 2102 end … … 1818 2107 function UnitSpeed(p, mix, Health: integer): integer; 1819 2108 begin 1820 with RW[p].Model[mix] do 1821 begin 1822 result:=Speed; 1823 if Domain=dSea then 1824 begin 1825 if GWonder[woMagellan].EffectiveOwner=p then inc(result,200); 1826 if Health<100 then 1827 result:=((result-250)*Health div 5000)*50+250; 2109 with RW[p].Model[mix] do 2110 begin 2111 result := Speed; 2112 if Domain = dSea then 2113 begin 2114 if GWonder[woMagellan].EffectiveOwner = p then 2115 inc(result, 200); 2116 if Health < 100 then 2117 result := ((result - 250) * Health div 5000) * 50 + 250; 1828 2118 end 1829 2119 end 1830 2120 end; 1831 2121 1832 procedure GetUnitReport(p,uix: integer; var UnitReport: TUnitReport); 1833 var 1834 TerrOwner: integer; 1835 PModel: ^TModel; 1836 begin 1837 UnitReport.FoodSupport:=0; 1838 UnitReport.ProdSupport:=0; 1839 UnitReport.ReportFlags:=0; 1840 if RW[p].Government<>gAnarchy then with RW[p].Un[uix] do 1841 begin 1842 PModel:=@RW[p].Model[mix]; 1843 if (PModel.Kind=mkSettler) {and (GWonder[woFreeSettlers].EffectiveOwner<>p)} then 1844 UnitReport.FoodSupport:=SettlerFood[RW[p].Government] 1845 else if Flags and unConscripts<>0 then UnitReport.FoodSupport:=1; 1846 1847 if RW[p].Government<>gFundamentalism then 1848 begin 1849 if GTestFlags and tfImmImprove=0 then 1850 begin 1851 if PModel.Flags and mdDoubleSupport<>0 then 1852 UnitReport.ProdSupport:=2 1853 else UnitReport.ProdSupport:=1; 1854 if PModel.Kind=mkSpecial_TownGuard then 1855 UnitReport.ReportFlags:=UnitReport.ReportFlags or urfAlwaysSupport; 1856 end; 1857 if PModel.Flags and mdCivil=0 then 1858 begin 1859 TerrOwner:=RealMap[Loc] shr 27; 1860 case RW[p].Government of 1861 gRepublic, gFuture: 1862 if (TerrOwner<>p) and (TerrOwner<nPl) 1863 and (RW[p].Treaty[TerrOwner]<trAlliance) then 1864 UnitReport.ReportFlags:=UnitReport.ReportFlags or urfDeployed; 1865 gDemocracy: 1866 if (TerrOwner>=nPl) or (TerrOwner<>p) 1867 and (RW[p].Treaty[TerrOwner]<trAlliance) then 1868 UnitReport.ReportFlags:=UnitReport.ReportFlags or urfDeployed; 2122 procedure GetUnitReport(p, uix: integer; var UnitReport: TUnitReport); 2123 var 2124 TerrOwner: integer; 2125 PModel: ^TModel; 2126 begin 2127 UnitReport.FoodSupport := 0; 2128 UnitReport.ProdSupport := 0; 2129 UnitReport.ReportFlags := 0; 2130 if RW[p].Government <> gAnarchy then 2131 with RW[p].Un[uix] do 2132 begin 2133 PModel := @RW[p].Model[mix]; 2134 if (PModel.Kind = mkSettler) 2135 { and (GWonder[woFreeSettlers].EffectiveOwner<>p) } then 2136 UnitReport.FoodSupport := SettlerFood[RW[p].Government] 2137 else if Flags and unConscripts <> 0 then 2138 UnitReport.FoodSupport := 1; 2139 2140 if RW[p].Government <> gFundamentalism then 2141 begin 2142 if GTestFlags and tfImmImprove = 0 then 2143 begin 2144 if PModel.Flags and mdDoubleSupport <> 0 then 2145 UnitReport.ProdSupport := 2 2146 else 2147 UnitReport.ProdSupport := 1; 2148 if PModel.Kind = mkSpecial_TownGuard then 2149 UnitReport.ReportFlags := UnitReport.ReportFlags or 2150 urfAlwaysSupport; 1869 2151 end; 1870 end 1871 end; 1872 end; 1873 end; 1874 1875 procedure SearchCity(Loc: integer; var p,cix: integer); 2152 if PModel.Flags and mdCivil = 0 then 2153 begin 2154 TerrOwner := RealMap[Loc] shr 27; 2155 case RW[p].Government of 2156 gRepublic, gFuture: 2157 if (TerrOwner <> p) and (TerrOwner < nPl) and 2158 (RW[p].Treaty[TerrOwner] < trAlliance) then 2159 UnitReport.ReportFlags := UnitReport.ReportFlags or urfDeployed; 2160 gDemocracy: 2161 if (TerrOwner >= nPl) or (TerrOwner <> p) and 2162 (RW[p].Treaty[TerrOwner] < trAlliance) then 2163 UnitReport.ReportFlags := UnitReport.ReportFlags or urfDeployed; 2164 end; 2165 end 2166 end; 2167 end; 2168 end; 2169 2170 procedure SearchCity(Loc: integer; var p, cix: integer); 1876 2171 // set p to supposed owner before call 1877 2172 var 1878 i: integer; 1879 begin 1880 if RealMap[Loc]<nPl shl 27 then p:=RealMap[Loc] shr 27; 1881 for i:=0 to nPl-1 do 1882 begin 1883 if 1 shl p and GAlive<>0 then with RW[p] do 1884 begin 1885 cix:=nCity-1; 1886 while (cix>=0) and (City[cix].Loc<>Loc) do dec(cix); 1887 if cix>=0 then exit; 1888 end; 1889 assert(i<nPl-1); 1890 p:=(p+1) mod nPl; 2173 i: integer; 2174 begin 2175 if RealMap[Loc] < nPl shl 27 then 2176 p := RealMap[Loc] shr 27; 2177 for i := 0 to nPl - 1 do 2178 begin 2179 if 1 shl p and GAlive <> 0 then 2180 with RW[p] do 2181 begin 2182 cix := nCity - 1; 2183 while (cix >= 0) and (City[cix].Loc <> Loc) do 2184 dec(cix); 2185 if cix >= 0 then 2186 exit; 2187 end; 2188 assert(i < nPl - 1); 2189 p := (p + 1) mod nPl; 1891 2190 end; 1892 2191 end; … … 1894 2193 procedure MakeCityInfo(p, cix: integer; var ci: TCityInfo); 1895 2194 begin 1896 assert((p>=0) and (p<nPl)); 1897 assert((cix>=0) and (cix<RW[p].nCity)); 1898 with RW[p].City[cix] do 1899 begin 1900 ci.Loc:=Loc; 1901 ci.ID:=ID; 1902 ci.Owner:=p; 1903 ci.Size:=Size; 1904 ci.Flags:=0; 1905 if Built[imPalace]>0 then inc(ci.Flags,ciCapital); 1906 if (Built[imWalls]>0) or (Continent[Loc]=GrWallContinent[p]) then 1907 inc(ci.Flags,ciWalled); 1908 if Built[imCoastalFort]>0 then inc(ci.Flags,ciCoastalFort); 1909 if Built[imMissileBat]>0 then inc(ci.Flags,ciMissileBat); 1910 if Built[imBunker]>0 then inc(ci.Flags,ciBunker); 1911 if Built[imSpacePort]>0 then inc(ci.Flags,ciSpacePort); 1912 end; 1913 end; 1914 1915 procedure TellAboutModel(p,taOwner,tamix: integer); 1916 var 1917 i: integer; 1918 begin 1919 if (p=taOwner) or (Mode<moPlaying) then exit; 1920 i:=0; 1921 while (i<RW[p].nEnemyModel) 1922 and ((RW[p].EnemyModel[i].Owner<>taOwner) 1923 or (RW[p].EnemyModel[i].mix<>tamix)) do inc(i); 1924 if i=RW[p].nEnemyModel then 1925 IntServer(sIntTellAboutModel+p shl 4,taOwner,tamix,nil^); 1926 end; 1927 1928 function emixSafe(p,taOwner,tamix: integer): integer; 1929 begin 1930 result:=RWemix[p,taOwner,tamix]; 1931 if result<0 then 2195 assert((p >= 0) and (p < nPl)); 2196 assert((cix >= 0) and (cix < RW[p].nCity)); 2197 with RW[p].City[cix] do 2198 begin 2199 ci.Loc := Loc; 2200 ci.ID := ID; 2201 ci.Owner := p; 2202 ci.Size := Size; 2203 ci.Flags := 0; 2204 if Built[imPalace] > 0 then 2205 inc(ci.Flags, ciCapital); 2206 if (Built[imWalls] > 0) or (Continent[Loc] = GrWallContinent[p]) then 2207 inc(ci.Flags, ciWalled); 2208 if Built[imCoastalFort] > 0 then 2209 inc(ci.Flags, ciCoastalFort); 2210 if Built[imMissileBat] > 0 then 2211 inc(ci.Flags, ciMissileBat); 2212 if Built[imBunker] > 0 then 2213 inc(ci.Flags, ciBunker); 2214 if Built[imSpacePort] > 0 then 2215 inc(ci.Flags, ciSpacePort); 2216 end; 2217 end; 2218 2219 procedure TellAboutModel(p, taOwner, tamix: integer); 2220 var 2221 i: integer; 2222 begin 2223 if (p = taOwner) or (Mode < moPlaying) then 2224 exit; 2225 i := 0; 2226 while (i < RW[p].nEnemyModel) and ((RW[p].EnemyModel[i].Owner <> taOwner) or 2227 (RW[p].EnemyModel[i].mix <> tamix)) do 2228 inc(i); 2229 if i = RW[p].nEnemyModel then 2230 IntServer(sIntTellAboutModel + p shl 4, taOwner, tamix, nil^); 2231 end; 2232 2233 function emixSafe(p, taOwner, tamix: integer): integer; 2234 begin 2235 result := RWemix[p, taOwner, tamix]; 2236 if result < 0 then 1932 2237 begin // sIntTellAboutModel comes too late 1933 assert(Mode=moMovie);1934 result:=$FFFF;1935 end; 1936 end; 1937 1938 procedure IntroduceEnemy(p1, p2: integer);1939 begin 1940 RW[p1].Treaty[p2]:=trNone;1941 RW[p2].Treaty[p1]:=trNone;1942 end; 1943 1944 function DiscoverTile(Loc, p, pTell, Level: integer; 1945 EnableContact: boolean;euix: integer = -2): boolean;2238 assert(Mode = moMovie); 2239 result := $FFFF; 2240 end; 2241 end; 2242 2243 procedure IntroduceEnemy(p1, p2: integer); 2244 begin 2245 RW[p1].Treaty[p2] := trNone; 2246 RW[p2].Treaty[p1] := trNone; 2247 end; 2248 2249 function DiscoverTile(Loc, p, pTell, Level: integer; EnableContact: boolean; 2250 euix: integer = -2): boolean; 1946 2251 // euix = -2: full discover 1947 2252 // euix = -1: unit and city only, append units in EnemyUn 1948 2253 // euix >= 0: unit and city only, replace EnemyUn[euix] 1949 2254 1950 procedure SetContact(p1,p2: integer); 1951 begin 1952 if (Mode<moPlaying) or (p1=p2) or (RW[p1].Treaty[p2]>trNoContact) then exit; 1953 IntServer(sIntTellAboutNation,p1,p2,nil^); 1954 // NewContact[p1,p2]:=true 1955 end; 1956 1957 var 1958 i,uix,cix,TerrOwner,TerrOwnerTreaty,Strength,Bonus,Cnt,pFoundCity, 1959 cixFoundCity,MinLevel,Loc1,V8: integer; 1960 Tile,AddFlags: Cardinal; 1961 Adjacent: TVicinity8Loc; 1962 unx: ^TUn; 1963 mox: ^TModel; 1964 begin 1965 result:=false; 1966 with RW[pTell] do 1967 begin 1968 Tile:=RealMap[Loc] and ResourceMask[pTell]; 1969 if Mode=moLoading_Fast then AddFlags:=0 // don't discover units 1970 else 1971 begin 1972 AddFlags:=Map[Loc] and fInEnemyZoC // always preserve this flag! 1973 or fObserved; 1974 if Level=lObserveSuper then 1975 AddFlags:=AddFlags or fSpiedOut; 1976 if (GrWallContinent[pTell]>=0) and (Continent[Loc]=GrWallContinent[pTell]) then 1977 AddFlags:=AddFlags or fGrWall; 1978 if (Mode=moPlaying) and ((Tile and (nPl shl 27)<>nPl shl 27) and (pTell=p)) then 2255 procedure SetContact(p1, p2: integer); 2256 begin 2257 if (Mode < moPlaying) or (p1 = p2) or (RW[p1].Treaty[p2] > trNoContact) then 2258 exit; 2259 IntServer(sIntTellAboutNation, p1, p2, nil^); 2260 // NewContact[p1,p2]:=true 2261 end; 2262 2263 var 2264 i, uix, cix, TerrOwner, TerrOwnerTreaty, Strength, Bonus, Cnt, pFoundCity, 2265 cixFoundCity, MinLevel, Loc1, V8: integer; 2266 Tile, AddFlags: Cardinal; 2267 Adjacent: TVicinity8Loc; 2268 unx: ^TUn; 2269 mox: ^TModel; 2270 begin 2271 result := false; 2272 with RW[pTell] do 2273 begin 2274 Tile := RealMap[Loc] and ResourceMask[pTell]; 2275 if Mode = moLoading_Fast then 2276 AddFlags := 0 // don't discover units 2277 else 2278 begin 2279 AddFlags := Map[Loc] and fInEnemyZoC // always preserve this flag! 2280 or fObserved; 2281 if Level = lObserveSuper then 2282 AddFlags := AddFlags or fSpiedOut; 2283 if (GrWallContinent[pTell] >= 0) and 2284 (Continent[Loc] = GrWallContinent[pTell]) then 2285 AddFlags := AddFlags or fGrWall; 2286 if (Mode = moPlaying) and ((Tile and (nPl shl 27) <> nPl shl 27) and 2287 (pTell = p)) then 1979 2288 begin // set fPeace flag? 1980 TerrOwner:=Tile shr 27;1981 if TerrOwner<>pTell then1982 begin 1983 TerrOwnerTreaty:=RW[pTell].Treaty[TerrOwner];1984 if 1 shl TerrOwnerTreaty1985 and (1 shl trPeace or 1 shl TrFriendlyContact)<>0 then1986 AddFlags:=AddFlags or fPeace;2289 TerrOwner := Tile shr 27; 2290 if TerrOwner <> pTell then 2291 begin 2292 TerrOwnerTreaty := RW[pTell].Treaty[TerrOwner]; 2293 if 1 shl TerrOwnerTreaty and 2294 (1 shl trPeace or 1 shl TrFriendlyContact) <> 0 then 2295 AddFlags := AddFlags or fPeace; 1987 2296 end 1988 2297 end; 1989 2298 1990 if Occupant[Loc]>=0 then 1991 if Occupant[Loc]=pTell then 1992 begin 1993 AddFlags:=AddFlags or (fOwned or fUnit); 1994 if ZoCMap[Loc]>0 then AddFlags:=AddFlags or fOwnZoCUnit; 1995 // Level:=lObserveSuper // always see own units 2299 if Occupant[Loc] >= 0 then 2300 if Occupant[Loc] = pTell then 2301 begin 2302 AddFlags := AddFlags or (fOwned or fUnit); 2303 if ZoCMap[Loc] > 0 then 2304 AddFlags := AddFlags or fOwnZoCUnit; 2305 // Level:=lObserveSuper // always see own units 1996 2306 end 1997 else if Map[Loc] and fUnit<>0 then 1998 AddFlags:=AddFlags or fUnit 1999 else 2000 begin 2001 Strongest(Loc,uix,Strength,Bonus,Cnt); 2002 unx:=@RW[Occupant[Loc]].Un[uix]; 2003 mox:=@RW[Occupant[Loc]].Model[unx.mix]; 2004 assert((ZoCMap[Loc]<>0)=(mox.Flags and mdZOC<>0)); 2005 if (mox.Cap[mcStealth]>0) and (Tile and fCity=0) 2006 and (Tile and fTerImp<>tiBase) then 2007 MinLevel:=lObserveSuper 2008 else if (mox.Cap[mcSub]>0) and (Tile and fTerrain<fGrass) then 2009 MinLevel:=lObserveAll 2010 else MinLevel:=lObserveUnhidden; 2011 if Level>=MinLevel then 2307 else if Map[Loc] and fUnit <> 0 then 2308 AddFlags := AddFlags or fUnit 2309 else 2310 begin 2311 Strongest(Loc, uix, Strength, Bonus, Cnt); 2312 unx := @RW[Occupant[Loc]].Un[uix]; 2313 mox := @RW[Occupant[Loc]].Model[unx.mix]; 2314 assert((ZoCMap[Loc] <> 0) = (mox.Flags and mdZOC <> 0)); 2315 if (mox.Cap[mcStealth] > 0) and (Tile and fCity = 0) and 2316 (Tile and fTerImp <> tiBase) then 2317 MinLevel := lObserveSuper 2318 else if (mox.Cap[mcSub] > 0) and (Tile and fTerrain < fGrass) then 2319 MinLevel := lObserveAll 2320 else 2321 MinLevel := lObserveUnhidden; 2322 if Level >= MinLevel then 2012 2323 begin 2013 AddFlags:=AddFlags or fUnit; 2014 if euix>=0 then uix:=euix 2015 else 2324 AddFlags := AddFlags or fUnit; 2325 if euix >= 0 then 2326 uix := euix 2327 else 2016 2328 begin 2017 uix:=nEnemyUn;2018 inc(nEnemyUn);2019 assert(nEnemyUn<neumax);2329 uix := nEnemyUn; 2330 inc(nEnemyUn); 2331 assert(nEnemyUn < neumax); 2020 2332 end; 2021 MakeUnitInfo(Occupant[Loc],unx^,EnemyUn[uix]);2022 if Cnt>1 then2023 EnemyUn[uix].Flags:=EnemyUn[uix].Flags or unMulti;2024 if (mox.Flags and mdZOC<>0) and (pTell=p)2025 and (Treaty[Occupant[Loc]]<trAlliance) then2333 MakeUnitInfo(Occupant[Loc], unx^, EnemyUn[uix]); 2334 if Cnt > 1 then 2335 EnemyUn[uix].Flags := EnemyUn[uix].Flags or unMulti; 2336 if (mox.Flags and mdZOC <> 0) and (pTell = p) and 2337 (Treaty[Occupant[Loc]] < trAlliance) then 2026 2338 begin // set fInEnemyZoC flags of surrounding tiles 2027 V8_to_Loc(Loc,Adjacent);2028 for V8:=0 to 7 do2339 V8_to_Loc(Loc, Adjacent); 2340 for V8 := 0 to 7 do 2029 2341 begin 2030 Loc1:=Adjacent[V8];2031 if (Loc1>=0) and (Loc1<MapSize) then2032 Map[Loc1]:=Map[Loc1] or fInEnemyZoC2342 Loc1 := Adjacent[V8]; 2343 if (Loc1 >= 0) and (Loc1 < MapSize) then 2344 Map[Loc1] := Map[Loc1] or fInEnemyZoC 2033 2345 end 2034 2346 end; 2035 if EnableContact and (mox.Domain=dGround) then2036 SetContact(pTell,Occupant[Loc]);2037 if Mode>=moMovie then2347 if EnableContact and (mox.Domain = dGround) then 2348 SetContact(pTell, Occupant[Loc]); 2349 if Mode >= moMovie then 2038 2350 begin 2039 TellAboutModel(pTell,Occupant[Loc],unx.mix);2040 EnemyUn[uix].emix:=emixSafe(pTell,Occupant[Loc],unx.mix);2351 TellAboutModel(pTell, Occupant[Loc], unx.mix); 2352 EnemyUn[uix].emix := emixSafe(pTell, Occupant[Loc], unx.mix); 2041 2353 end; 2042 //Level:=lObserveSuper; // don't discover unit twice2043 if (pTell=p)2044 and ((Tile and fCity=0) or (1 shl pTell and GAI<>0)) then2045 result:=true;2354 // Level:=lObserveSuper; // don't discover unit twice 2355 if (pTell = p) and 2356 ((Tile and fCity = 0) or (1 shl pTell and GAI <> 0)) then 2357 result := true; 2046 2358 end 2047 else AddFlags:=AddFlags or Map[Loc] and (fStealthUnit or fHiddenUnit) 2359 else 2360 AddFlags := AddFlags or Map[Loc] and (fStealthUnit or fHiddenUnit) 2048 2361 end 2049 2362 end; // if Mode>moLoading_Fast 2050 2363 2051 if Tile and fCity<>0 then 2052 if ObserveLevel[Loc] shr (2*pTell) and 3>0 then 2053 AddFlags:=AddFlags or Map[Loc] and fOwned 2054 else 2055 begin 2056 pFoundCity:=Tile shr 27; 2057 if pFoundCity=pTell then AddFlags:=AddFlags or fOwned 2364 if Tile and fCity <> 0 then 2365 if ObserveLevel[Loc] shr (2 * pTell) and 3 > 0 then 2366 AddFlags := AddFlags or Map[Loc] and fOwned 2058 2367 else 2059 begin 2060 if EnableContact then SetContact(pTell,pFoundCity); 2061 cixFoundCity:=RW[pFoundCity].nCity-1; 2062 while (cixFoundCity>=0) 2063 and (RW[pFoundCity].City[cixFoundCity].Loc<>Loc) do 2064 dec(cixFoundCity); 2065 assert(cixFoundCity>=0); 2066 i:=0; 2067 while (i<nEnemyCity) and (EnemyCity[i].Loc<>Loc) do 2068 inc(i); 2069 if i=nEnemyCity then 2368 begin 2369 pFoundCity := Tile shr 27; 2370 if pFoundCity = pTell then 2371 AddFlags := AddFlags or fOwned 2372 else 2373 begin 2374 if EnableContact then 2375 SetContact(pTell, pFoundCity); 2376 cixFoundCity := RW[pFoundCity].nCity - 1; 2377 while (cixFoundCity >= 0) and 2378 (RW[pFoundCity].City[cixFoundCity].Loc <> Loc) do 2379 dec(cixFoundCity); 2380 assert(cixFoundCity >= 0); 2381 i := 0; 2382 while (i < nEnemyCity) and (EnemyCity[i].Loc <> Loc) do 2383 inc(i); 2384 if i = nEnemyCity then 2070 2385 begin 2071 inc(nEnemyCity); 2072 assert(nEnemyCity<necmax); 2073 EnemyCity[i].Status:=0; 2074 EnemyCity[i].SavedStatus:=0; 2075 if pTell=p then result:=true; 2386 inc(nEnemyCity); 2387 assert(nEnemyCity < necmax); 2388 EnemyCity[i].Status := 0; 2389 EnemyCity[i].SavedStatus := 0; 2390 if pTell = p then 2391 result := true; 2076 2392 end; 2077 MakeCityInfo(pFoundCity,cixFoundCity,EnemyCity[i]);2393 MakeCityInfo(pFoundCity, cixFoundCity, EnemyCity[i]); 2078 2394 end; 2079 2395 end 2080 else if Map[Loc] and fCity<>0 then // remove enemycity 2081 for cix:=0 to nEnemyCity-1 do 2082 if EnemyCity[cix].Loc=Loc then 2083 EnemyCity[cix].Loc:=-1; 2084 2085 if Map[Loc] and fTerrain=fUNKNOWN then inc(Discovered[pTell]); 2086 if euix>=-1 then 2087 Map[Loc]:=Map[Loc] and not (fUnit or fCity or fOwned or fOwnZoCUnit) 2088 or (Tile and $07FFFFFF or AddFlags) and (fUnit or fCity or fOwned or fOwnZoCUnit) 2089 else 2090 begin 2091 Map[Loc]:=Tile and $07FFFFFF or AddFlags; 2092 if Tile and $78000000=$78000000 then Territory[Loc]:=-1 2093 else Territory[Loc]:=Tile shr 27; 2094 MapObservedLast[Loc]:=GTurn 2095 end; 2096 ObserveLevel[Loc]:=ObserveLevel[Loc] and not (3 shl (2*pTell)) 2097 or Cardinal(Level) shl (2*pTell); 2396 else if Map[Loc] and fCity <> 0 then // remove enemycity 2397 for cix := 0 to nEnemyCity - 1 do 2398 if EnemyCity[cix].Loc = Loc then 2399 EnemyCity[cix].Loc := -1; 2400 2401 if Map[Loc] and fTerrain = fUNKNOWN then 2402 inc(Discovered[pTell]); 2403 if euix >= -1 then 2404 Map[Loc] := Map[Loc] and not(fUnit or fCity or fOwned or fOwnZoCUnit) or 2405 (Tile and $07FFFFFF or AddFlags) and 2406 (fUnit or fCity or fOwned or fOwnZoCUnit) 2407 else 2408 begin 2409 Map[Loc] := Tile and $07FFFFFF or AddFlags; 2410 if Tile and $78000000 = $78000000 then 2411 Territory[Loc] := -1 2412 else 2413 Territory[Loc] := Tile shr 27; 2414 MapObservedLast[Loc] := GTurn 2415 end; 2416 ObserveLevel[Loc] := ObserveLevel[Loc] and not(3 shl (2 * pTell)) or 2417 Cardinal(Level) shl (2 * pTell); 2098 2418 end 2099 2419 end; // DiscoverTile 2100 2420 2101 function Discover9(Loc,p,Level: integer; TellAllied, EnableContact: boolean): boolean; 2102 var 2103 V9,Loc1,pTell,OldLevel: integer; 2104 Radius: TVicinity8Loc; 2105 begin 2106 assert((Mode>moLoading_Fast) or (RW[p].nEnemyUn=0)); 2107 result:=false; 2108 V8_to_Loc(Loc,Radius); 2109 for V9:=0 to 8 do 2110 begin 2111 if V9=8 then Loc1:=Loc 2112 else Loc1:=Radius[V9]; 2113 if (Loc1>=0) and (Loc1<MapSize) then 2114 if TellAllied then 2115 begin 2116 for pTell:=0 to nPl-1 do 2117 if (pTell=p) or (1 shl pTell and GAlive<>0) 2118 and (RW[p].Treaty[pTell]=trAlliance) then 2421 function Discover9(Loc, p, Level: integer; 2422 TellAllied, EnableContact: boolean): boolean; 2423 var 2424 V9, Loc1, pTell, OldLevel: integer; 2425 Radius: TVicinity8Loc; 2426 begin 2427 assert((Mode > moLoading_Fast) or (RW[p].nEnemyUn = 0)); 2428 result := false; 2429 V8_to_Loc(Loc, Radius); 2430 for V9 := 0 to 8 do 2431 begin 2432 if V9 = 8 then 2433 Loc1 := Loc 2434 else 2435 Loc1 := Radius[V9]; 2436 if (Loc1 >= 0) and (Loc1 < MapSize) then 2437 if TellAllied then 2438 begin 2439 for pTell := 0 to nPl - 1 do 2440 if (pTell = p) or (1 shl pTell and GAlive <> 0) and 2441 (RW[p].Treaty[pTell] = trAlliance) then 2119 2442 begin 2120 OldLevel:=ObserveLevel[Loc1] shr (2*pTell) and 3; 2121 if Level>OldLevel then 2122 result:=DiscoverTile(Loc1,p,pTell,Level,EnableContact) or result; 2443 OldLevel := ObserveLevel[Loc1] shr (2 * pTell) and 3; 2444 if Level > OldLevel then 2445 result := DiscoverTile(Loc1, p, pTell, Level, EnableContact) 2446 or result; 2123 2447 end 2124 2448 end 2125 else2126 begin 2127 OldLevel:=ObserveLevel[Loc1] shr (2*p) and 3;2128 if Level>OldLevel then2129 result:=DiscoverTile(Loc1,p,p,Level,EnableContact) or result;2449 else 2450 begin 2451 OldLevel := ObserveLevel[Loc1] shr (2 * p) and 3; 2452 if Level > OldLevel then 2453 result := DiscoverTile(Loc1, p, p, Level, EnableContact) or result; 2130 2454 end 2131 2455 end; 2132 2456 end; 2133 2457 2134 function Discover21(Loc,p,AdjacentLevel: integer; TellAllied, EnableContact: boolean): boolean; 2135 var 2136 V21,Loc1,pTell,Level,OldLevel,AdjacentFlags: integer; 2137 Radius: TVicinity21Loc; 2138 begin 2139 assert((Mode>moLoading_Fast) or (RW[p].nEnemyUn=0)); 2140 result:=false; 2141 AdjacentFlags:=$00267620 shr 1; 2142 V21_to_Loc(Loc,Radius); 2143 for V21:=1 to 26 do 2144 begin 2145 Loc1:=Radius[V21]; 2146 if (Loc1>=0) and (Loc1<MapSize) then 2147 begin 2148 if AdjacentFlags and 1<>0 then Level:=AdjacentLevel 2149 else Level:=lObserveUnhidden; 2150 if TellAllied then 2151 begin 2152 for pTell:=0 to nPl-1 do 2153 if (pTell=p) or (1 shl pTell and GAlive<>0) 2154 and (RW[p].Treaty[pTell]=trAlliance) then 2458 function Discover21(Loc, p, AdjacentLevel: integer; 2459 TellAllied, EnableContact: boolean): boolean; 2460 var 2461 V21, Loc1, pTell, Level, OldLevel, AdjacentFlags: integer; 2462 Radius: TVicinity21Loc; 2463 begin 2464 assert((Mode > moLoading_Fast) or (RW[p].nEnemyUn = 0)); 2465 result := false; 2466 AdjacentFlags := $00267620 shr 1; 2467 V21_to_Loc(Loc, Radius); 2468 for V21 := 1 to 26 do 2469 begin 2470 Loc1 := Radius[V21]; 2471 if (Loc1 >= 0) and (Loc1 < MapSize) then 2472 begin 2473 if AdjacentFlags and 1 <> 0 then 2474 Level := AdjacentLevel 2475 else 2476 Level := lObserveUnhidden; 2477 if TellAllied then 2478 begin 2479 for pTell := 0 to nPl - 1 do 2480 if (pTell = p) or (1 shl pTell and GAlive <> 0) and 2481 (RW[p].Treaty[pTell] = trAlliance) then 2155 2482 begin 2156 OldLevel:=ObserveLevel[Loc1] shr (2*pTell) and 3; 2157 if Level>OldLevel then 2158 result:=DiscoverTile(Loc1,p,pTell,Level,EnableContact) or result; 2483 OldLevel := ObserveLevel[Loc1] shr (2 * pTell) and 3; 2484 if Level > OldLevel then 2485 result := DiscoverTile(Loc1, p, pTell, Level, EnableContact) 2486 or result; 2159 2487 end 2160 2488 end 2161 else2162 begin 2163 OldLevel:=ObserveLevel[Loc1] shr (2*p) and 3;2164 if Level>OldLevel then2165 result:=DiscoverTile(Loc1,p,p,Level,EnableContact) or result;2489 else 2490 begin 2491 OldLevel := ObserveLevel[Loc1] shr (2 * p) and 3; 2492 if Level > OldLevel then 2493 result := DiscoverTile(Loc1, p, p, Level, EnableContact) or result; 2166 2494 end 2167 2495 end; 2168 AdjacentFlags:=AdjacentFlags shr 1;2496 AdjacentFlags := AdjacentFlags shr 1; 2169 2497 end; 2170 2498 end; 2171 2499 2172 2500 procedure DiscoverAll(p, Level: integer); 2173 { player p discovers complete playground (for supervisor)}2174 var 2175 Loc, OldLevel: integer;2176 begin 2177 assert((Mode>moLoading_Fast) or (RW[p].nEnemyUn=0));2178 for Loc:=0 to MapSize-1 do2179 begin 2180 OldLevel:=ObserveLevel[Loc] shr (2*p) and 3;2181 if Level>OldLevel then2182 DiscoverTile(Loc,p,p,Level,false);2501 { player p discovers complete playground (for supervisor) } 2502 var 2503 Loc, OldLevel: integer; 2504 begin 2505 assert((Mode > moLoading_Fast) or (RW[p].nEnemyUn = 0)); 2506 for Loc := 0 to MapSize - 1 do 2507 begin 2508 OldLevel := ObserveLevel[Loc] shr (2 * p) and 3; 2509 if Level > OldLevel then 2510 DiscoverTile(Loc, p, p, Level, false); 2183 2511 end; 2184 2512 end; … … 2186 2514 procedure DiscoverViewAreas(p: integer); 2187 2515 var 2188 pTell, uix, cix, ecix, Loc, RealOwner: integer;2189 PModel: ^TModel;2516 pTell, uix, cix, ecix, Loc, RealOwner: integer; 2517 PModel: ^TModel; 2190 2518 begin // discover unit and city view areas 2191 for pTell:=0 to nPl-1 do 2192 if (pTell=p) or (RW[p].Treaty[pTell]=trAlliance) then 2193 begin 2194 for uix:=0 to RW[pTell].nUn-1 do with RW[pTell].Un[uix] do 2195 if (Loc>=0) and (master<0) and (RealMap[Loc] and fCity=0) then 2196 begin 2197 PModel:=@RW[pTell].Model[mix]; 2198 if (PModel.Kind=mkDiplomat) or (PModel.Cap[mcSpy]>0) then 2199 Discover21(Loc,p,lObserveSuper,false,true) 2200 else if (PModel.Cap[mcRadar]+PModel.Cap[mcCarrier]>0) 2201 or (PModel.Domain=dAir) then 2202 Discover21(Loc,p,lObserveAll,false,false) 2203 else if (RealMap[Loc] and fTerrain=fMountains) 2204 or (RealMap[Loc] and fTerImp=tiFort) 2205 or (RealMap[Loc] and fTerImp=tiBase) 2206 or (PModel.Cap[mcAcademy]>0) then 2207 Discover21(Loc,p,lObserveUnhidden,false,PModel.Domain=dGround) 2208 else Discover9(Loc,p,lObserveUnhidden,false,PModel.Domain=dGround); 2209 end; 2210 for cix:=0 to RW[pTell].nCity-1 do if RW[pTell].City[cix].Loc>=0 then 2211 Discover21(RW[pTell].City[cix].Loc,p,lObserveUnhidden,false,true); 2212 for ecix:=0 to RW[pTell].nEnemyCity-1 do 2519 for pTell := 0 to nPl - 1 do 2520 if (pTell = p) or (RW[p].Treaty[pTell] = trAlliance) then 2521 begin 2522 for uix := 0 to RW[pTell].nUn - 1 do 2523 with RW[pTell].Un[uix] do 2524 if (Loc >= 0) and (Master < 0) and (RealMap[Loc] and fCity = 0) then 2525 begin 2526 PModel := @RW[pTell].Model[mix]; 2527 if (PModel.Kind = mkDiplomat) or (PModel.Cap[mcSpy] > 0) then 2528 Discover21(Loc, p, lObserveSuper, false, true) 2529 else if (PModel.Cap[mcRadar] + PModel.Cap[mcCarrier] > 0) or 2530 (PModel.Domain = dAir) then 2531 Discover21(Loc, p, lObserveAll, false, false) 2532 else if (RealMap[Loc] and fTerrain = fMountains) or 2533 (RealMap[Loc] and fTerImp = tiFort) or 2534 (RealMap[Loc] and fTerImp = tiBase) or (PModel.Cap[mcAcademy] > 0) 2535 then 2536 Discover21(Loc, p, lObserveUnhidden, false, 2537 PModel.Domain = dGround) 2538 else 2539 Discover9(Loc, p, lObserveUnhidden, false, 2540 PModel.Domain = dGround); 2541 end; 2542 for cix := 0 to RW[pTell].nCity - 1 do 2543 if RW[pTell].City[cix].Loc >= 0 then 2544 Discover21(RW[pTell].City[cix].Loc, p, lObserveUnhidden, false, true); 2545 for ecix := 0 to RW[pTell].nEnemyCity - 1 do 2213 2546 begin // players know territory, so no use in hiding city owner 2214 Loc:=RW[pTell].EnemyCity[ecix].Loc;2215 if Loc>=0 then2216 begin 2217 RealOwner:=(RealMap[Loc] shr 27) and $F;2218 if RealOwner<nPl then2219 RW[pTell].EnemyCity[ecix].owner:=RealOwner2220 else2547 Loc := RW[pTell].EnemyCity[ecix].Loc; 2548 if Loc >= 0 then 2549 begin 2550 RealOwner := (RealMap[Loc] shr 27) and $F; 2551 if RealOwner < nPl then 2552 RW[pTell].EnemyCity[ecix].Owner := RealOwner 2553 else 2221 2554 begin 2222 RW[pTell].EnemyCity[ecix].Loc:=-1;2223 RW[pTell].Map[Loc]:=RW[pTell].Map[Loc] and not fCity2555 RW[pTell].EnemyCity[ecix].Loc := -1; 2556 RW[pTell].Map[Loc] := RW[pTell].Map[Loc] and not fCity 2224 2557 end 2225 2558 end … … 2228 2561 end; 2229 2562 2230 function GetUnitStack(p,Loc: integer): integer; 2231 var 2232 uix: integer; 2233 unx: ^TUn; 2234 begin 2235 result:=0; 2236 if Occupant[Loc]<0 then exit; 2237 for uix:=0 to RW[Occupant[Loc]].nUn-1 do 2238 begin 2239 unx:=@RW[Occupant[Loc]].Un[uix]; 2240 if unx.Loc=Loc then 2241 begin 2242 MakeUnitInfo(Occupant[Loc],unx^,RW[p].EnemyUn[RW[p].nEnemyUn+result]); 2243 TellAboutModel(p,Occupant[Loc],unx.mix); 2244 RW[p].EnemyUn[RW[p].nEnemyUn+result].emix:=RWemix[p,Occupant[Loc],unx.mix]; 2245 inc(result); 2563 function GetUnitStack(p, Loc: integer): integer; 2564 var 2565 uix: integer; 2566 unx: ^TUn; 2567 begin 2568 result := 0; 2569 if Occupant[Loc] < 0 then 2570 exit; 2571 for uix := 0 to RW[Occupant[Loc]].nUn - 1 do 2572 begin 2573 unx := @RW[Occupant[Loc]].Un[uix]; 2574 if unx.Loc = Loc then 2575 begin 2576 MakeUnitInfo(Occupant[Loc], unx^, RW[p].EnemyUn[RW[p].nEnemyUn + result]); 2577 TellAboutModel(p, Occupant[Loc], unx.mix); 2578 RW[p].EnemyUn[RW[p].nEnemyUn + result].emix := 2579 RWemix[p, Occupant[Loc], unx.mix]; 2580 inc(result); 2246 2581 end 2247 2582 end … … 2251 2586 // update maps and enemy units of all players after unit change 2252 2587 var 2253 p, euix, OldLevel: integer; 2254 AddFlags, ClearFlags: Cardinal; 2255 begin 2256 if (Mode=moLoading_Fast) and not CityChange then exit; 2257 for p:=0 to nPl-1 do if 1 shl p and (GAlive or GWatching)<>0 then 2258 begin 2259 OldLevel:=ObserveLevel[Loc] shr (2*p) and 3; 2260 if OldLevel>lNoObserve then 2261 begin 2262 if RW[p].Map[Loc] and (fUnit or fOwned)=fUnit then 2263 begin 2264 // replace unit located here in EnemyUn 2265 // do not just set loc:=-1 because total number would be unlimited 2266 euix:=RW[p].nEnemyUn-1; 2267 while euix>=0 do 2268 begin 2269 if RW[p].EnemyUn[euix].Loc=Loc then 2270 begin RW[p].EnemyUn[euix].Loc:=-1; Break; end; 2271 dec(euix); 2588 p, euix, OldLevel: integer; 2589 AddFlags, ClearFlags: Cardinal; 2590 begin 2591 if (Mode = moLoading_Fast) and not CityChange then 2592 exit; 2593 for p := 0 to nPl - 1 do 2594 if 1 shl p and (GAlive or GWatching) <> 0 then 2595 begin 2596 OldLevel := ObserveLevel[Loc] shr (2 * p) and 3; 2597 if OldLevel > lNoObserve then 2598 begin 2599 if RW[p].Map[Loc] and (fUnit or fOwned) = fUnit then 2600 begin 2601 // replace unit located here in EnemyUn 2602 // do not just set loc:=-1 because total number would be unlimited 2603 euix := RW[p].nEnemyUn - 1; 2604 while euix >= 0 do 2605 begin 2606 if RW[p].EnemyUn[euix].Loc = Loc then 2607 begin 2608 RW[p].EnemyUn[euix].Loc := -1; 2609 Break; 2610 end; 2611 dec(euix); 2612 end; 2613 RW[p].Map[Loc] := RW[p].Map[Loc] and not fUnit 2614 end 2615 else 2616 begin // look for empty slot in EnemyUn 2617 euix := RW[p].nEnemyUn - 1; 2618 while (euix >= 0) and (RW[p].EnemyUn[euix].Loc >= 0) do 2619 dec(euix); 2272 2620 end; 2273 RW[p].Map[Loc]:=RW[p].Map[Loc] and not fUnit 2274 end 2275 else 2276 begin // look for empty slot in EnemyUn 2277 euix:=RW[p].nEnemyUn-1; 2278 while (euix>=0) and (RW[p].EnemyUn[euix].Loc>=0) do dec(euix); 2279 end; 2280 if (Occupant[Loc]<0) and not CityChange then 2281 begin // calling DiscoverTile not necessary, only clear map flags 2282 ClearFlags:=fUnit or fHiddenUnit or fStealthUnit or fOwnZoCUnit; 2283 if RealMap[Loc] and fCity=0 then 2284 ClearFlags:=ClearFlags or fOwned; 2285 RW[p].Map[Loc]:=RW[p].Map[Loc] and not ClearFlags; 2286 end 2287 else if (Occupant[Loc]<>p) or CityChange then 2288 begin // city or enemy unit update necessary, call DiscoverTile 2289 ObserveLevel[Loc]:=ObserveLevel[Loc] and not (3 shl (2*p)); 2290 DiscoverTile(Loc, p, p, OldLevel, false, euix); 2291 end 2292 else {if (Occupant[Loc]=p) and not CityChange then} 2293 begin // calling DiscoverTile not necessary, only set map flags 2294 ClearFlags:=0; 2295 AddFlags:=fUnit or fOwned; 2296 if ZoCMap[Loc]>0 then AddFlags:=AddFlags or fOwnZoCUnit 2297 else ClearFlags:=ClearFlags or fOwnZoCUnit; 2298 RW[p].Map[Loc]:=RW[p].Map[Loc] and not ClearFlags or AddFlags; 2299 end 2300 end 2301 end 2302 end; 2303 2304 procedure RecalcV8ZoC(p,Loc: integer); 2305 // recalculate fInEnemyZoC flags around single tile 2306 var 2307 v8,V8V8,Loc1,Loc2,p1,ObserveMask: integer; 2308 Tile1: ^Cardinal; 2309 Adjacent,AdjacentAdjacent: TVicinity8Loc; 2310 begin 2311 if Mode=moLoading_Fast then exit; 2312 ObserveMask:=3 shl (2*p); 2313 V8_to_Loc(Loc,Adjacent); 2314 for V8:=0 to 7 do 2315 begin 2316 Loc1:=Adjacent[V8]; 2317 if (Loc1>=0) and (Loc1<MapSize) then 2318 begin 2319 Tile1:=@RW[p].Map[Loc1]; 2320 Tile1^:=Tile1^ and not fInEnemyZoC; 2321 V8_to_Loc(Loc1,AdjacentAdjacent); 2322 for V8V8:=0 to 7 do 2323 begin 2324 Loc2:=AdjacentAdjacent[V8V8]; 2325 if (Loc2>=0) and (Loc2<MapSize) and (ZoCMap[Loc2]>0) 2326 and (ObserveLevel[Loc2] and ObserveMask<>0) then 2327 begin 2328 p1:=Occupant[Loc2]; 2329 assert(p1<>nPl); 2330 if (p1<>p) and (RW[p].Treaty[p1]<trAlliance) then 2331 begin Tile1^:=Tile1^ or fInEnemyZoC; break end 2621 if (Occupant[Loc] < 0) and not CityChange then 2622 begin // calling DiscoverTile not necessary, only clear map flags 2623 ClearFlags := fUnit or fHiddenUnit or fStealthUnit or fOwnZoCUnit; 2624 if RealMap[Loc] and fCity = 0 then 2625 ClearFlags := ClearFlags or fOwned; 2626 RW[p].Map[Loc] := RW[p].Map[Loc] and not ClearFlags; 2332 2627 end 2333 end; 2334 end 2335 end 2336 end; 2337 2338 procedure RecalcMapZoC(p: integer); 2339 // recalculate fInEnemyZoC flags for the whole map 2340 var 2341 Loc,Loc1,V8,p1,ObserveMask: integer; 2342 Adjacent: TVicinity8Loc; 2343 begin 2344 if Mode=moLoading_Fast then exit; 2345 MaskD(RW[p].Map^,MapSize,not Cardinal(fInEnemyZoC)); 2346 ObserveMask:=3 shl (2*p); 2347 for Loc:=0 to MapSize-1 do 2348 if (ZoCMap[Loc]>0) and (ObserveLevel[Loc] and ObserveMask<>0) then 2349 begin 2350 p1:=Occupant[Loc]; 2351 assert(p1<>nPl); 2352 if (p1<>p) and (RW[p].Treaty[p1]<trAlliance) then 2353 begin // this non-allied enemy ZoC unit is known to this player -- set flags! 2354 V8_to_Loc(Loc,Adjacent); 2355 for V8:=0 to 7 do 2356 begin 2357 Loc1:=Adjacent[V8]; 2358 if (Loc1>=0) and (Loc1<MapSize) then 2359 RW[p].Map[Loc1]:=RW[p].Map[Loc1] or fInEnemyZoC 2628 else if (Occupant[Loc] <> p) or CityChange then 2629 begin // city or enemy unit update necessary, call DiscoverTile 2630 ObserveLevel[Loc] := ObserveLevel[Loc] and not(3 shl (2 * p)); 2631 DiscoverTile(Loc, p, p, OldLevel, false, euix); 2632 end 2633 else { if (Occupant[Loc]=p) and not CityChange then } 2634 begin // calling DiscoverTile not necessary, only set map flags 2635 ClearFlags := 0; 2636 AddFlags := fUnit or fOwned; 2637 if ZoCMap[Loc] > 0 then 2638 AddFlags := AddFlags or fOwnZoCUnit 2639 else 2640 ClearFlags := ClearFlags or fOwnZoCUnit; 2641 RW[p].Map[Loc] := RW[p].Map[Loc] and not ClearFlags or AddFlags; 2360 2642 end 2361 2643 end … … 2363 2645 end; 2364 2646 2647 procedure RecalcV8ZoC(p, Loc: integer); 2648 // recalculate fInEnemyZoC flags around single tile 2649 var 2650 V8, V8V8, Loc1, Loc2, p1, ObserveMask: integer; 2651 Tile1: ^Cardinal; 2652 Adjacent, AdjacentAdjacent: TVicinity8Loc; 2653 begin 2654 if Mode = moLoading_Fast then 2655 exit; 2656 ObserveMask := 3 shl (2 * p); 2657 V8_to_Loc(Loc, Adjacent); 2658 for V8 := 0 to 7 do 2659 begin 2660 Loc1 := Adjacent[V8]; 2661 if (Loc1 >= 0) and (Loc1 < MapSize) then 2662 begin 2663 Tile1 := @RW[p].Map[Loc1]; 2664 Tile1^ := Tile1^ and not fInEnemyZoC; 2665 V8_to_Loc(Loc1, AdjacentAdjacent); 2666 for V8V8 := 0 to 7 do 2667 begin 2668 Loc2 := AdjacentAdjacent[V8V8]; 2669 if (Loc2 >= 0) and (Loc2 < MapSize) and (ZoCMap[Loc2] > 0) and 2670 (ObserveLevel[Loc2] and ObserveMask <> 0) then 2671 begin 2672 p1 := Occupant[Loc2]; 2673 assert(p1 <> nPl); 2674 if (p1 <> p) and (RW[p].Treaty[p1] < trAlliance) then 2675 begin 2676 Tile1^ := Tile1^ or fInEnemyZoC; 2677 Break 2678 end 2679 end 2680 end; 2681 end 2682 end 2683 end; 2684 2685 procedure RecalcMapZoC(p: integer); 2686 // recalculate fInEnemyZoC flags for the whole map 2687 var 2688 Loc, Loc1, V8, p1, ObserveMask: integer; 2689 Adjacent: TVicinity8Loc; 2690 begin 2691 if Mode = moLoading_Fast then 2692 exit; 2693 MaskD(RW[p].Map^, MapSize, not Cardinal(fInEnemyZoC)); 2694 ObserveMask := 3 shl (2 * p); 2695 for Loc := 0 to MapSize - 1 do 2696 if (ZoCMap[Loc] > 0) and (ObserveLevel[Loc] and ObserveMask <> 0) then 2697 begin 2698 p1 := Occupant[Loc]; 2699 assert(p1 <> nPl); 2700 if (p1 <> p) and (RW[p].Treaty[p1] < trAlliance) then 2701 begin // this non-allied enemy ZoC unit is known to this player -- set flags! 2702 V8_to_Loc(Loc, Adjacent); 2703 for V8 := 0 to 7 do 2704 begin 2705 Loc1 := Adjacent[V8]; 2706 if (Loc1 >= 0) and (Loc1 < MapSize) then 2707 RW[p].Map[Loc1] := RW[p].Map[Loc1] or fInEnemyZoC 2708 end 2709 end 2710 end 2711 end; 2712 2365 2713 procedure RecalcPeaceMap(p: integer); 2366 2714 // recalculate fPeace flags for the whole map 2367 2715 var 2368 Loc,p1: integer;2369 PeacePlayer: array[-1..nPl-1] of boolean;2370 begin 2371 if Mode<>moPlaying then exit; 2372 MaskD(RW[p].Map^,MapSize,not Cardinal(fPeace));2373 for p1:=-1 to nPl-1 do 2374 PeacePlayer[p1]:= (p1>=0) and (p1<>p) and (1 shl p1 and GAlive<>0)2375 and (RW[p].Treaty[p1] in [trPeace,trFriendlyContact]);2376 for Loc:=0 to MapSize-1 do 2377 if PeacePlayer[RW[p].Territory[Loc]] then2378 RW[p].Map[Loc]:=RW[p].Map[Loc] or fPeace2379 end; 2380 2716 Loc, p1: integer; 2717 PeacePlayer: array [-1 .. nPl - 1] of boolean; 2718 begin 2719 if Mode <> moPlaying then 2720 exit; 2721 MaskD(RW[p].Map^, MapSize, not Cardinal(fPeace)); 2722 for p1 := -1 to nPl - 1 do 2723 PeacePlayer[p1] := (p1 >= 0) and (p1 <> p) and (1 shl p1 and GAlive <> 0) 2724 and (RW[p].Treaty[p1] in [trPeace, TrFriendlyContact]); 2725 for Loc := 0 to MapSize - 1 do 2726 if PeacePlayer[RW[p].Territory[Loc]] then 2727 RW[p].Map[Loc] := RW[p].Map[Loc] or fPeace 2728 end; 2381 2729 2382 2730 { 2383 Territory Calculation2384 ____________________________________________________________________2731 Territory Calculation 2732 ____________________________________________________________________ 2385 2733 } 2386 2734 var 2387 BorderChanges: array[0..sIntExpandTerritory and $F-1] of Cardinal;2735 BorderChanges: array [0 .. sIntExpandTerritory and $F - 1] of Cardinal; 2388 2736 2389 2737 procedure ChangeTerritory(Loc, p: integer); 2390 2738 var 2391 p1: integer; 2392 begin 2393 assert(p>=0); // no player's territory indicated by p=nPl 2394 dec(TerritoryCount[RealMap[Loc] shr 27]); 2395 inc(TerritoryCount[p]); 2396 RealMap[Loc]:=RealMap[Loc] and not ($F shl 27) or Cardinal(p) shl 27; 2397 if p=$F then p:=-1; 2398 for p1:=0 to nPl-1 do if 1 shl p1 and (GAlive or GWatching)<>0 then 2399 if RW[p1].Map[Loc] and fTerrain<>fUNKNOWN then 2400 begin 2401 RW[p1].Territory[Loc]:=p; 2402 if (p<nPl) and (p<>p1) and (1 shl p and GAlive<>0) 2403 and (RW[p1].Treaty[p] in [trPeace,trFriendlyContact]) then 2404 RW[p1].Map[Loc]:=RW[p1].Map[Loc] or fPeace 2405 else RW[p1].Map[Loc]:=RW[p1].Map[Loc] and not fPeace; 2406 end 2739 p1: integer; 2740 begin 2741 assert(p >= 0); // no player's territory indicated by p=nPl 2742 dec(TerritoryCount[RealMap[Loc] shr 27]); 2743 inc(TerritoryCount[p]); 2744 RealMap[Loc] := RealMap[Loc] and not($F shl 27) or Cardinal(p) shl 27; 2745 if p = $F then 2746 p := -1; 2747 for p1 := 0 to nPl - 1 do 2748 if 1 shl p1 and (GAlive or GWatching) <> 0 then 2749 if RW[p1].Map[Loc] and fTerrain <> fUNKNOWN then 2750 begin 2751 RW[p1].Territory[Loc] := p; 2752 if (p < nPl) and (p <> p1) and (1 shl p and GAlive <> 0) and 2753 (RW[p1].Treaty[p] in [trPeace, TrFriendlyContact]) then 2754 RW[p1].Map[Loc] := RW[p1].Map[Loc] or fPeace 2755 else 2756 RW[p1].Map[Loc] := RW[p1].Map[Loc] and not fPeace; 2757 end 2407 2758 end; 2408 2759 2409 2760 procedure ExpandTerritory(OriginLoc: integer); 2410 2761 var 2411 i,dx,dy,dxMax,dyMax,Loc,NewOwner: integer; 2412 begin 2413 i:=0; 2414 dyMax:=0; 2415 while (dyMax+1)+(dyMax+1) shr 1<=CountryRadius do 2416 inc(dyMax); 2417 for dy:=-dyMax to dyMax do 2418 begin 2419 dxMax:=dy and 1; 2420 while abs(dy)+(dxMax+2)+abs(abs(dy)-(dxMax+2)) shr 1<=CountryRadius do 2421 inc(dxMax,2); 2422 for dx:=-dxMax to dxMax do if (dy+dx) and 1=0 then 2423 begin 2424 NewOwner:=BorderChanges[i div 8] shr (i mod 8 *4) and $F; 2425 Loc:=dLoc(OriginLoc,dx,dy); 2426 if (Loc>=0) and (Cardinal(NewOwner)<>RealMap[Loc] shr 27) then 2427 ChangeTerritory(Loc,NewOwner); 2428 inc(i); 2429 end 2762 i, dx, dy, dxMax, dyMax, Loc, NewOwner: integer; 2763 begin 2764 i := 0; 2765 dyMax := 0; 2766 while (dyMax + 1) + (dyMax + 1) shr 1 <= CountryRadius do 2767 inc(dyMax); 2768 for dy := -dyMax to dyMax do 2769 begin 2770 dxMax := dy and 1; 2771 while abs(dy) + (dxMax + 2) + abs(abs(dy) - (dxMax + 2)) shr 1 <= 2772 CountryRadius do 2773 inc(dxMax, 2); 2774 for dx := -dxMax to dxMax do 2775 if (dy + dx) and 1 = 0 then 2776 begin 2777 NewOwner := BorderChanges[i div 8] shr (i mod 8 * 4) and $F; 2778 Loc := dLoc(OriginLoc, dx, dy); 2779 if (Loc >= 0) and (Cardinal(NewOwner) <> RealMap[Loc] shr 27) then 2780 ChangeTerritory(Loc, NewOwner); 2781 inc(i); 2782 end 2430 2783 end 2431 2784 end; … … 2433 2786 procedure CheckBorders(OriginLoc, PlayerLosingCity: integer); 2434 2787 // OriginLoc: only changes in CountryRadius around this location possible, 2435 // -1 for complete map, -2 for double-check (no more changes allowed)2788 // -1 for complete map, -2 for double-check (no more changes allowed) 2436 2789 // PlayerLosingCity: do nothing but remove tiles no longer in reach from this 2437 // player's territory, -1 for full border recalculation 2438 var 2439 i,r,Loc,Loc1,dx,dy,p1,p2,cix,NewDist,dxMax,dyMax,OldOwner,V8, 2440 NewOwner: integer; 2441 Adjacent: TVicinity8Loc; 2442 AtPeace: array[0..nPl,0..nPl] of boolean; 2443 Country, FormerCountry, {to who's country a tile belongs} 2444 Dist, FormerDist, StolenDist: array[0..lxmax*lymax-1] of ShortInt; 2445 begin 2446 if PlayerLosingCity>=0 then 2447 begin 2448 for Loc:=0 to MapSize-1 do StolenDist[Loc]:=CountryRadius+1; 2449 for cix:=0 to RW[PlayerLosingCity].nCity-1 do 2450 if RW[PlayerLosingCity].City[cix].Loc>=0 then 2451 StolenDist[RW[PlayerLosingCity].City[cix].Loc]:=0; 2452 2453 for r:=1 to CountryRadius shr 1 do 2454 begin 2455 move(StolenDist,FormerDist,MapSize); 2456 for Loc:=0 to MapSize-1 do 2457 if (FormerDist[Loc]<=CountryRadius-2) // use same conditions as below! 2458 and ((1 shl (RealMap[Loc] and fTerrain)) 2459 and (1 shl fShore+1 shl fMountains+1 shl fArctic)=0) then 2460 begin 2461 V8_to_Loc(Loc,Adjacent); 2462 for V8:=0 to 7 do 2790 // player's territory, -1 for full border recalculation 2791 var 2792 i, r, Loc, Loc1, dx, dy, p1, p2, cix, NewDist, dxMax, dyMax, OldOwner, V8, 2793 NewOwner: integer; 2794 Adjacent: TVicinity8Loc; 2795 AtPeace: array [0 .. nPl, 0 .. nPl] of boolean; 2796 Country, FormerCountry, { to who's country a tile belongs } 2797 Dist, FormerDist, StolenDist: array [0 .. lxmax * lymax - 1] of ShortInt; 2798 begin 2799 if PlayerLosingCity >= 0 then 2800 begin 2801 for Loc := 0 to MapSize - 1 do 2802 StolenDist[Loc] := CountryRadius + 1; 2803 for cix := 0 to RW[PlayerLosingCity].nCity - 1 do 2804 if RW[PlayerLosingCity].City[cix].Loc >= 0 then 2805 StolenDist[RW[PlayerLosingCity].City[cix].Loc] := 0; 2806 2807 for r := 1 to CountryRadius shr 1 do 2808 begin 2809 move(StolenDist, FormerDist, MapSize); 2810 for Loc := 0 to MapSize - 1 do 2811 if (FormerDist[Loc] <= CountryRadius - 2) 2812 // use same conditions as below! 2813 and ((1 shl (RealMap[Loc] and fTerrain)) and 2814 (1 shl fShore + 1 shl fMountains + 1 shl fArctic) = 0) then 2815 begin 2816 V8_to_Loc(Loc, Adjacent); 2817 for V8 := 0 to 7 do 2463 2818 begin 2464 Loc1:=Adjacent[V8]; 2465 NewDist:=FormerDist[Loc]+2+V8 and 1; 2466 if (Loc1>=0) and (Loc1<MapSize) and (NewDist<StolenDist[Loc1]) then 2467 StolenDist[Loc1]:=NewDist; 2819 Loc1 := Adjacent[V8]; 2820 NewDist := FormerDist[Loc] + 2 + V8 and 1; 2821 if (Loc1 >= 0) and (Loc1 < MapSize) and (NewDist < StolenDist[Loc1]) 2822 then 2823 StolenDist[Loc1] := NewDist; 2468 2824 end 2469 2825 end … … 2471 2827 end; 2472 2828 2473 FillChar(Country,MapSize,-1); 2474 for Loc:=0 to MapSize-1 do Dist[Loc]:=CountryRadius+1; 2475 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then 2476 for cix:=0 to RW[p1].nCity-1 do if RW[p1].City[cix].Loc>=0 then 2477 begin 2478 Country[RW[p1].City[cix].Loc]:=p1; 2479 Dist[RW[p1].City[cix].Loc]:=0; 2480 end; 2481 2482 for r:=1 to CountryRadius shr 1 do 2483 begin 2484 move(Country,FormerCountry,MapSize); 2485 move(Dist,FormerDist,MapSize); 2486 for Loc:=0 to MapSize-1 do 2487 if (FormerDist[Loc]<=CountryRadius-2) // use same conditions as above! 2488 and ((1 shl (RealMap[Loc] and fTerrain)) 2489 and (1 shl fShore+1 shl fMountains+1 shl fArctic)=0) then 2490 begin 2491 assert(FormerCountry[Loc]>=0); 2492 V8_to_Loc(Loc,Adjacent); 2493 for V8:=0 to 7 do 2494 begin 2495 Loc1:=Adjacent[V8]; 2496 NewDist:=FormerDist[Loc]+2+V8 and 1; 2497 if (Loc1>=0) and (Loc1<MapSize) and (NewDist<Dist[Loc1]) then 2829 FillChar(Country, MapSize, -1); 2830 for Loc := 0 to MapSize - 1 do 2831 Dist[Loc] := CountryRadius + 1; 2832 for p1 := 0 to nPl - 1 do 2833 if 1 shl p1 and GAlive <> 0 then 2834 for cix := 0 to RW[p1].nCity - 1 do 2835 if RW[p1].City[cix].Loc >= 0 then 2836 begin 2837 Country[RW[p1].City[cix].Loc] := p1; 2838 Dist[RW[p1].City[cix].Loc] := 0; 2839 end; 2840 2841 for r := 1 to CountryRadius shr 1 do 2842 begin 2843 move(Country, FormerCountry, MapSize); 2844 move(Dist, FormerDist, MapSize); 2845 for Loc := 0 to MapSize - 1 do 2846 if (FormerDist[Loc] <= CountryRadius - 2) // use same conditions as above! 2847 and ((1 shl (RealMap[Loc] and fTerrain)) and 2848 (1 shl fShore + 1 shl fMountains + 1 shl fArctic) = 0) then 2849 begin 2850 assert(FormerCountry[Loc] >= 0); 2851 V8_to_Loc(Loc, Adjacent); 2852 for V8 := 0 to 7 do 2853 begin 2854 Loc1 := Adjacent[V8]; 2855 NewDist := FormerDist[Loc] + 2 + V8 and 1; 2856 if (Loc1 >= 0) and (Loc1 < MapSize) and (NewDist < Dist[Loc1]) then 2498 2857 begin 2499 Country[Loc1]:=FormerCountry[Loc];2500 Dist[Loc1]:=NewDist;2858 Country[Loc1] := FormerCountry[Loc]; 2859 Dist[Loc1] := NewDist; 2501 2860 end 2502 2861 end … … 2504 2863 end; 2505 2864 2506 FillChar(AtPeace, sizeof(AtPeace), false); 2507 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then 2508 for p2:=0 to nPl-1 do 2509 if (p2<>p1) and (1 shl p2 and GAlive<>0) and (RW[p1].Treaty[p2]>=trPeace) then 2510 AtPeace[p1,p2]:=true; 2511 2512 if OriginLoc>=0 then 2865 FillChar(AtPeace, SizeOf(AtPeace), false); 2866 for p1 := 0 to nPl - 1 do 2867 if 1 shl p1 and GAlive <> 0 then 2868 for p2 := 0 to nPl - 1 do 2869 if (p2 <> p1) and (1 shl p2 and GAlive <> 0) and 2870 (RW[p1].Treaty[p2] >= trPeace) then 2871 AtPeace[p1, p2] := true; 2872 2873 if OriginLoc >= 0 then 2513 2874 begin // update area only 2514 i:=0; 2515 fillchar(BorderChanges, sizeof(BorderChanges), 0); 2516 dyMax:=0; 2517 while (dyMax+1)+(dyMax+1) shr 1<=CountryRadius do 2518 inc(dyMax); 2519 for dy:=-dyMax to dyMax do 2520 begin 2521 dxMax:=dy and 1; 2522 while abs(dy)+(dxMax+2)+abs(abs(dy)-(dxMax+2)) shr 1<=CountryRadius do 2523 inc(dxMax,2); 2524 for dx:=-dxMax to dxMax do if (dy+dx) and 1=0 then 2525 begin 2526 Loc:=dLoc(OriginLoc,dx,dy); 2527 if Loc>=0 then 2528 begin 2529 OldOwner:=RealMap[Loc] shr 27; 2530 NewOwner:=Country[Loc] and $f; 2531 if NewOwner<>OldOwner then 2532 if AtPeace[NewOwner,OldOwner] 2533 and not ((OldOwner=PlayerLosingCity) and (StolenDist[Loc]>CountryRadius)) then 2534 NewOwner:=OldOwner // peace fixes borders 2535 else ChangeTerritory(Loc,NewOwner); 2536 inc(BorderChanges[i div 8],NewOwner shl (i mod 8 *4)); 2537 end; 2538 inc(i); 2539 end 2875 i := 0; 2876 FillChar(BorderChanges, SizeOf(BorderChanges), 0); 2877 dyMax := 0; 2878 while (dyMax + 1) + (dyMax + 1) shr 1 <= CountryRadius do 2879 inc(dyMax); 2880 for dy := -dyMax to dyMax do 2881 begin 2882 dxMax := dy and 1; 2883 while abs(dy) + (dxMax + 2) + abs(abs(dy) - (dxMax + 2)) shr 1 <= 2884 CountryRadius do 2885 inc(dxMax, 2); 2886 for dx := -dxMax to dxMax do 2887 if (dy + dx) and 1 = 0 then 2888 begin 2889 Loc := dLoc(OriginLoc, dx, dy); 2890 if Loc >= 0 then 2891 begin 2892 OldOwner := RealMap[Loc] shr 27; 2893 NewOwner := Country[Loc] and $F; 2894 if NewOwner <> OldOwner then 2895 if AtPeace[NewOwner, OldOwner] and 2896 not((OldOwner = PlayerLosingCity) and 2897 (StolenDist[Loc] > CountryRadius)) then 2898 NewOwner := OldOwner // peace fixes borders 2899 else 2900 ChangeTerritory(Loc, NewOwner); 2901 inc(BorderChanges[i div 8], NewOwner shl (i mod 8 * 4)); 2902 end; 2903 inc(i); 2904 end 2540 2905 end 2541 2906 end 2542 else for Loc:=0 to MapSize-1 do // update complete map 2543 begin 2544 OldOwner:=RealMap[Loc] shr 27; 2545 NewOwner:=Country[Loc] and $f; 2546 if (NewOwner<>OldOwner) 2547 and (not AtPeace[NewOwner,OldOwner] 2548 or ((OldOwner=PlayerLosingCity) and (StolenDist[Loc]>CountryRadius))) then 2549 begin 2550 assert(OriginLoc<>-2); // test if border saving works 2551 ChangeTerritory(Loc,NewOwner); 2552 end; 2553 end; 2554 2555 {$IFOPT O-}if OriginLoc<>-2 then CheckBorders(-2);{$ENDIF} //check: single pass should do! 2556 end; //CheckBorders 2557 2558 procedure LogCheckBorders(p,cix,PlayerLosingCity: integer); 2559 begin 2560 CheckBorders(RW[p].City[cix].Loc,PlayerLosingCity); 2561 IntServer(sIntExpandTerritory,p,cix,BorderChanges); 2907 else 2908 for Loc := 0 to MapSize - 1 do // update complete map 2909 begin 2910 OldOwner := RealMap[Loc] shr 27; 2911 NewOwner := Country[Loc] and $F; 2912 if (NewOwner <> OldOwner) and (not AtPeace[NewOwner, OldOwner] or 2913 ((OldOwner = PlayerLosingCity) and (StolenDist[Loc] > CountryRadius))) 2914 then 2915 begin 2916 assert(OriginLoc <> -2); // test if border saving works 2917 ChangeTerritory(Loc, NewOwner); 2918 end; 2919 end; 2920 2921 {$IFOPT O-} if OriginLoc <> -2 then 2922 CheckBorders(-2); {$ENDIF} // check: single pass should do! 2923 end; // CheckBorders 2924 2925 procedure LogCheckBorders(p, cix, PlayerLosingCity: integer); 2926 begin 2927 CheckBorders(RW[p].City[cix].Loc, PlayerLosingCity); 2928 IntServer(sIntExpandTerritory, p, cix, BorderChanges); 2562 2929 end; 2563 2930 2564 2931 { 2565 Map Processing2566 ____________________________________________________________________2932 Map Processing 2933 ____________________________________________________________________ 2567 2934 } 2568 2935 2569 procedure CreateUnit(p,mix: integer); 2570 begin 2571 with RW[p] do 2572 begin 2573 Un[nUn].mix:=mix; 2574 with Un[nUn] do 2575 begin 2576 ID:=UnBuilt[p]; 2577 inc(UnBuilt[p]); 2578 Status:=0; 2579 SavedStatus:=0; 2580 inc(Model[mix].Built); 2581 Home:=-1; 2582 Health:=100; 2583 Flags:=0; 2584 Movement:=0; 2585 if Model[mix].Domain=dAir then 2586 begin 2587 Fuel:=Model[mix].Cap[mcFuel]; 2588 Flags:=Flags or unBombsLoaded 2589 end; 2590 Job:=jNone; 2591 Exp:=ExpCost shr 1; 2592 TroopLoad:=0; AirLoad:=0; Master:=-1; 2593 end; 2594 inc(nUn); 2936 procedure CreateUnit(p, mix: integer); 2937 begin 2938 with RW[p] do 2939 begin 2940 Un[nUn].mix := mix; 2941 with Un[nUn] do 2942 begin 2943 ID := UnBuilt[p]; 2944 inc(UnBuilt[p]); 2945 Status := 0; 2946 SavedStatus := 0; 2947 inc(Model[mix].Built); 2948 Home := -1; 2949 Health := 100; 2950 Flags := 0; 2951 Movement := 0; 2952 if Model[mix].Domain = dAir then 2953 begin 2954 Fuel := Model[mix].Cap[mcFuel]; 2955 Flags := Flags or unBombsLoaded 2956 end; 2957 Job := jNone; 2958 exp := ExpCost shr 1; 2959 TroopLoad := 0; 2960 AirLoad := 0; 2961 Master := -1; 2962 end; 2963 inc(nUn); 2595 2964 end 2596 2965 end; 2597 2966 2598 procedure FreeUnit(p, uix: integer);2967 procedure FreeUnit(p, uix: integer); 2599 2968 // loc or master should be set after call 2600 2969 // implementation is critical for loading performance, change carefully 2601 2970 var 2602 Loc0, uix1: integer; 2603 Occ, ZoC: boolean; 2604 begin 2605 with RW[p].Un[uix] do 2606 begin 2607 Job:=jNone; 2608 Flags:=Flags and not (unFortified or unMountainDelay); 2609 Loc0:=Loc 2610 end; 2611 if Occupant[Loc0]>=0 then 2612 begin 2613 assert(Occupant[Loc0]=p); 2614 Occ:=false; 2615 ZoC:=false; 2616 for uix1:=0 to RW[p].nUn-1 do with RW[p].Un[uix1] do 2617 if (Loc=Loc0) and (Master<0) and (uix1<>uix) then 2618 begin 2619 Occ:=true; 2620 if RW[p].Model[mix].Flags and mdZOC<>0 then 2621 begin ZoC:=true; Break end 2622 end; 2623 if not Occ then Occupant[Loc0]:=-1; 2624 if not ZoC then ZoCMap[Loc0]:=0; 2625 end; 2626 end; 2627 2628 procedure PlaceUnit(p,uix: integer); 2629 begin 2630 with RW[p].Un[uix] do 2631 begin 2632 Occupant[Loc]:=p; 2633 if RW[p].Model[mix].Flags and mdZOC<>0 then ZoCMap[Loc]:=1; 2971 Loc0, uix1: integer; 2972 Occ, ZoC: boolean; 2973 begin 2974 with RW[p].Un[uix] do 2975 begin 2976 Job := jNone; 2977 Flags := Flags and not(unFortified or unMountainDelay); 2978 Loc0 := Loc 2979 end; 2980 if Occupant[Loc0] >= 0 then 2981 begin 2982 assert(Occupant[Loc0] = p); 2983 Occ := false; 2984 ZoC := false; 2985 for uix1 := 0 to RW[p].nUn - 1 do 2986 with RW[p].Un[uix1] do 2987 if (Loc = Loc0) and (Master < 0) and (uix1 <> uix) then 2988 begin 2989 Occ := true; 2990 if RW[p].Model[mix].Flags and mdZOC <> 0 then 2991 begin 2992 ZoC := true; 2993 Break 2994 end 2995 end; 2996 if not Occ then 2997 Occupant[Loc0] := -1; 2998 if not ZoC then 2999 ZoCMap[Loc0] := 0; 3000 end; 3001 end; 3002 3003 procedure PlaceUnit(p, uix: integer); 3004 begin 3005 with RW[p].Un[uix] do 3006 begin 3007 Occupant[Loc] := p; 3008 if RW[p].Model[mix].Flags and mdZOC <> 0 then 3009 ZoCMap[Loc] := 1; 2634 3010 end 2635 3011 end; … … 2637 3013 procedure CountLost(p, mix, Enemy: integer); 2638 3014 begin 2639 inc(RW[p].Model[mix].Lost);2640 TellAboutModel(Enemy,p,mix);2641 inc(Destroyed[Enemy,p,mix]);2642 end; 2643 2644 procedure RemoveUnit(p, uix: integer; Enemy: integer = -1);3015 inc(RW[p].Model[mix].Lost); 3016 TellAboutModel(Enemy, p, mix); 3017 inc(Destroyed[Enemy, p, mix]); 3018 end; 3019 3020 procedure RemoveUnit(p, uix: integer; Enemy: integer = -1); 2645 3021 // use enemy only from inside sMoveUnit if attack 2646 3022 var 2647 uix1: integer; 2648 begin 2649 with RW[p].Un[uix] do 2650 begin 2651 assert((Loc>=0) or (RW[p].Model[mix].Kind=mkDiplomat)); // already freed when spy mission 2652 if Loc>=0 then 2653 FreeUnit(p,uix); 2654 if Master>=0 then 2655 if RW[p].Model[mix].Domain=dAir then dec(RW[p].Un[Master].AirLoad) 2656 else dec(RW[p].Un[Master].TroopLoad); 2657 if (TroopLoad>0) or (AirLoad>0) then 2658 for uix1:=0 to RW[p].nUn-1 do 2659 if (RW[p].Un[uix1].Loc>=0) and (RW[p].Un[uix1].Master=uix) then 2660 {unit mastered by removed unit -- remove too} 2661 begin 2662 RW[p].Un[uix1].Loc:=-1; 2663 if Enemy>=0 then CountLost(p,RW[p].Un[uix1].mix,Enemy); 3023 uix1: integer; 3024 begin 3025 with RW[p].Un[uix] do 3026 begin 3027 assert((Loc >= 0) or (RW[p].Model[mix].Kind = mkDiplomat)); 3028 // already freed when spy mission 3029 if Loc >= 0 then 3030 FreeUnit(p, uix); 3031 if Master >= 0 then 3032 if RW[p].Model[mix].Domain = dAir then 3033 dec(RW[p].Un[Master].AirLoad) 3034 else 3035 dec(RW[p].Un[Master].TroopLoad); 3036 if (TroopLoad > 0) or (AirLoad > 0) then 3037 for uix1 := 0 to RW[p].nUn - 1 do 3038 if (RW[p].Un[uix1].Loc >= 0) and (RW[p].Un[uix1].Master = uix) then 3039 { unit mastered by removed unit -- remove too } 3040 begin 3041 RW[p].Un[uix1].Loc := -1; 3042 if Enemy >= 0 then 3043 CountLost(p, RW[p].Un[uix1].mix, Enemy); 2664 3044 end; 2665 Loc:=-1; 2666 if Enemy>=0 then CountLost(p,mix,Enemy); 3045 Loc := -1; 3046 if Enemy >= 0 then 3047 CountLost(p, mix, Enemy); 2667 3048 end 2668 end;{RemoveUnit} 2669 2670 procedure RemoveUnit_UpdateMap(p,uix: integer); 2671 var 2672 Loc0: integer; 2673 begin 2674 Loc0:=RW[p].Un[uix].Loc; 2675 RemoveUnit(p,uix); 2676 if Mode>moLoading_Fast then UpdateUnitMap(Loc0); 2677 end; 2678 2679 procedure RemoveAllUnits(p,Loc: integer; Enemy: integer = -1); 2680 var 2681 uix: integer; 2682 begin 2683 for uix:=0 to RW[p].nUn-1 do 2684 if RW[p].Un[uix].Loc=Loc then 2685 begin 2686 if Enemy>=0 then CountLost(p,RW[p].Un[uix].mix,Enemy); 2687 RW[p].Un[uix].Loc:=-1 2688 end; 2689 Occupant[Loc]:=-1; 2690 ZoCMap[Loc]:=0; 2691 end; 2692 2693 procedure RemoveDomainUnits(d,p,Loc: integer); 2694 var 2695 uix: integer; 2696 begin 2697 for uix:=0 to RW[p].nUn-1 do 2698 if (RW[p].Model[RW[p].Un[uix].mix].Domain=d) and (RW[p].Un[uix].Loc=Loc) then 2699 RemoveUnit(p,uix); 2700 end; 2701 2702 procedure FoundCity(p,FoundLoc: integer); 2703 var 2704 p1,cix1,V21,dx,dy: integer; 2705 begin 2706 if RW[p].nCity=ncmax then exit; 2707 inc(RW[p].nCity); 2708 with RW[p].City[RW[p].nCity-1] do 2709 begin 2710 Size:=2; 2711 Status:=0; 2712 SavedStatus:=0; 2713 FillChar(Built,SizeOf(Built),0); 2714 Food:=0; 2715 Project:=cpImp+imTrGoods; 2716 Prod:=0; 2717 Project0:=Project; 2718 Prod0:=0; 2719 Pollution:=0; 2720 N1:=0; 2721 Loc:=FoundLoc; 2722 if UsedByCity[FoundLoc]>=0 then 2723 begin {central tile is exploited - toggle in exploiting city} 2724 p1:=p; 2725 SearchCity(UsedByCity[FoundLoc],p1,cix1); 2726 dxdy(UsedByCity[FoundLoc],FoundLoc,dx,dy); 2727 V21:=(dy+3) shl 2+(dx+3) shr 1; 2728 RW[p1].City[cix1].Tiles:=RW[p1].City[cix1].Tiles and not (1 shl V21); 2729 end; 2730 Tiles:=1 shl 13; {exploit central tile} 2731 UsedByCity[FoundLoc]:=FoundLoc; 2732 RealMap[FoundLoc]:=RealMap[FoundLoc] 2733 and (fTerrain or fSpecial or fRiver or nPl shl 27) or fCity; 2734 2735 ChangeTerritory(Loc,p) 2736 end; 2737 end; {FoundCity} 2738 2739 procedure StealCity(p,cix: integer; SaveUnits: boolean); 2740 var 2741 i,j,uix1,cix1,nearest: integer; 2742 begin 2743 for i:=0 to 27 do 2744 if RW[p].City[cix].Built[i]=1 then 2745 begin 2746 GWonder[i].EffectiveOwner:=-1; 2747 if i=woPyramids then FreeSlaves; 2748 if i=woEiffel then // deactivate expired wonders 2749 for j:=0 to 27 do if GWonder[j].EffectiveOwner=p then 2750 CheckExpiration(j); 2751 end; 2752 for i:=28 to nImp-1 do 2753 if (Imp[i].Kind<>ikCommon) and (RW[p].City[cix].Built[i]>0) then 2754 begin {destroy national projects} 2755 RW[p].NatBuilt[i]:=0; 2756 if i=imGrWall then GrWallContinent[p]:=-1; 2757 end; 2758 2759 for uix1:=0 to RW[p].nUn-1 do with RW[p].Un[uix1] do 2760 if (Loc>=0) and (Home=cix) then 2761 if SaveUnits then 2762 begin // support units by nearest other city 2763 nearest:=-1; 2764 for cix1:=0 to RW[p].nCity-1 do 2765 if (cix1<>cix) and (RW[p].City[cix1].Loc>=0) 2766 and ((nearest<0) or (Distance(RW[p].City[cix1].Loc,Loc) 2767 <Distance(RW[p].City[nearest].Loc,Loc))) then 2768 nearest:=cix1; 2769 Home:=nearest 3049 end; { RemoveUnit } 3050 3051 procedure RemoveUnit_UpdateMap(p, uix: integer); 3052 var 3053 Loc0: integer; 3054 begin 3055 Loc0 := RW[p].Un[uix].Loc; 3056 RemoveUnit(p, uix); 3057 if Mode > moLoading_Fast then 3058 UpdateUnitMap(Loc0); 3059 end; 3060 3061 procedure RemoveAllUnits(p, Loc: integer; Enemy: integer = -1); 3062 var 3063 uix: integer; 3064 begin 3065 for uix := 0 to RW[p].nUn - 1 do 3066 if RW[p].Un[uix].Loc = Loc then 3067 begin 3068 if Enemy >= 0 then 3069 CountLost(p, RW[p].Un[uix].mix, Enemy); 3070 RW[p].Un[uix].Loc := -1 3071 end; 3072 Occupant[Loc] := -1; 3073 ZoCMap[Loc] := 0; 3074 end; 3075 3076 procedure RemoveDomainUnits(d, p, Loc: integer); 3077 var 3078 uix: integer; 3079 begin 3080 for uix := 0 to RW[p].nUn - 1 do 3081 if (RW[p].Model[RW[p].Un[uix].mix].Domain = d) and (RW[p].Un[uix].Loc = Loc) 3082 then 3083 RemoveUnit(p, uix); 3084 end; 3085 3086 procedure FoundCity(p, FoundLoc: integer); 3087 var 3088 p1, cix1, V21, dx, dy: integer; 3089 begin 3090 if RW[p].nCity = ncmax then 3091 exit; 3092 inc(RW[p].nCity); 3093 with RW[p].City[RW[p].nCity - 1] do 3094 begin 3095 Size := 2; 3096 Status := 0; 3097 SavedStatus := 0; 3098 FillChar(Built, SizeOf(Built), 0); 3099 Food := 0; 3100 Project := cpImp + imTrGoods; 3101 Prod := 0; 3102 Project0 := Project; 3103 Prod0 := 0; 3104 Pollution := 0; 3105 N1 := 0; 3106 Loc := FoundLoc; 3107 if UsedByCity[FoundLoc] >= 0 then 3108 begin { central tile is exploited - toggle in exploiting city } 3109 p1 := p; 3110 SearchCity(UsedByCity[FoundLoc], p1, cix1); 3111 dxdy(UsedByCity[FoundLoc], FoundLoc, dx, dy); 3112 V21 := (dy + 3) shl 2 + (dx + 3) shr 1; 3113 RW[p1].City[cix1].Tiles := RW[p1].City[cix1].Tiles and not(1 shl V21); 3114 end; 3115 Tiles := 1 shl 13; { exploit central tile } 3116 UsedByCity[FoundLoc] := FoundLoc; 3117 RealMap[FoundLoc] := RealMap[FoundLoc] and 3118 (fTerrain or fSpecial or fRiver or nPl shl 27) or fCity; 3119 3120 ChangeTerritory(Loc, p) 3121 end; 3122 end; { FoundCity } 3123 3124 procedure StealCity(p, cix: integer; SaveUnits: boolean); 3125 var 3126 i, j, uix1, cix1, nearest: integer; 3127 begin 3128 for i := 0 to 27 do 3129 if RW[p].City[cix].Built[i] = 1 then 3130 begin 3131 GWonder[i].EffectiveOwner := -1; 3132 if i = woPyramids then 3133 FreeSlaves; 3134 if i = woEiffel then // deactivate expired wonders 3135 for j := 0 to 27 do 3136 if GWonder[j].EffectiveOwner = p then 3137 CheckExpiration(j); 3138 end; 3139 for i := 28 to nImp - 1 do 3140 if (Imp[i].Kind <> ikCommon) and (RW[p].City[cix].Built[i] > 0) then 3141 begin { destroy national projects } 3142 RW[p].NatBuilt[i] := 0; 3143 if i = imGrWall then 3144 GrWallContinent[p] := -1; 3145 end; 3146 3147 for uix1 := 0 to RW[p].nUn - 1 do 3148 with RW[p].Un[uix1] do 3149 if (Loc >= 0) and (Home = cix) then 3150 if SaveUnits then 3151 begin // support units by nearest other city 3152 nearest := -1; 3153 for cix1 := 0 to RW[p].nCity - 1 do 3154 if (cix1 <> cix) and (RW[p].City[cix1].Loc >= 0) and 3155 ((nearest < 0) or (Distance(RW[p].City[cix1].Loc, Loc) < 3156 Distance(RW[p].City[nearest].Loc, Loc))) then 3157 nearest := cix1; 3158 Home := nearest 3159 end 3160 else 3161 RemoveUnit(p, uix1); // destroy supported units 3162 end; // StealCity 3163 3164 procedure DestroyCity(p, cix: integer; SaveUnits: boolean); 3165 var 3166 i, V21: integer; 3167 Radius: TVicinity21Loc; 3168 begin 3169 StealCity(p, cix, SaveUnits); 3170 with RW[p].City[cix] do 3171 begin 3172 for i := 0 to 27 do 3173 if Built[i] > 0 then 3174 GWonder[i].CityID := -2; // wonder destroyed 3175 V21_to_Loc(Loc, Radius); 3176 for V21 := 1 to 26 do 3177 if 1 shl V21 and Tiles <> 0 then 3178 UsedByCity[Radius[V21]] := -1; 3179 RealMap[Loc] := RealMap[Loc] and not fCity; 3180 Loc := -1 3181 end 3182 end; // DestroyCity 3183 3184 procedure ChangeCityOwner(pOld, cixOld, pNew: integer); 3185 var 3186 i, j, cix1, Loc1, V21: integer; 3187 Radius: TVicinity21Loc; 3188 begin 3189 inc(RW[pNew].nCity); 3190 RW[pNew].City[RW[pNew].nCity - 1] := RW[pOld].City[cixOld]; 3191 StealCity(pOld, cixOld, false); 3192 RW[pOld].City[cixOld].Loc := -1; 3193 with RW[pNew].City[(RW[pNew].nCity - 1)] do 3194 begin 3195 Food := 0; 3196 Project := cpImp + imTrGoods; 3197 Prod := 0; 3198 Project0 := Project; 3199 Prod0 := 0; 3200 Status := 0; 3201 SavedStatus := 0; 3202 N1 := 0; 3203 3204 // check for siege 3205 V21_to_Loc(Loc, Radius); 3206 for V21 := 1 to 26 do 3207 if Tiles and (1 shl V21) and not(1 shl CityOwnTile) <> 0 then 3208 begin 3209 Loc1 := Radius[V21]; 3210 assert((Loc1 >= 0) and (Loc1 < MapSize) and (UsedByCity[Loc1] = Loc)); 3211 if (ZoCMap[Loc1] > 0) and (Occupant[Loc1] <> pNew) and 3212 (RW[pNew].Treaty[Occupant[Loc1]] < trAlliance) then 3213 begin // tile can't remain exploited 3214 Tiles := Tiles and not(1 shl V21); 3215 UsedByCity[Loc1] := -1; 3216 end; 3217 // don't check for siege by peace territory here, because territory 3218 // might not be up to date -- done in turn beginning anyway 3219 end; 3220 Built[imTownHall] := 0; 3221 Built[imCourt] := 0; 3222 for i := 28 to nImp - 1 do 3223 if Imp[i].Kind <> ikCommon then 3224 Built[i] := 0; { destroy national projects } 3225 for i := 0 to 27 do 3226 if Built[i] = 1 then 3227 begin // new wonder owner! 3228 GWonder[i].EffectiveOwner := pNew; 3229 if i = woEiffel then // reactivate expired wonders 3230 begin 3231 for j := 0 to 27 do 3232 if Imp[j].Expiration >= 0 then 3233 for cix1 := 0 to (RW[pNew].nCity - 1) do 3234 if RW[pNew].City[cix1].Built[j] = 1 then 3235 GWonder[j].EffectiveOwner := pNew 3236 end 3237 else 3238 CheckExpiration(i); 3239 case i of 3240 woLighthouse: 3241 CheckSpecialModels(pNew, preLighthouse); 3242 woLeo: 3243 CheckSpecialModels(pNew, preLeo); 3244 woPyramids: 3245 CheckSpecialModels(pNew, preBuilder); 3246 end; 3247 end; 3248 3249 // remove city from enemy cities 3250 // not done by Discover, because fCity still set! 3251 cix1 := RW[pNew].nEnemyCity - 1; 3252 while (cix1 >= 0) and (RW[pNew].EnemyCity[cix1].Loc <> Loc) do 3253 dec(cix1); 3254 assert(cix1 >= 0); 3255 RW[pNew].EnemyCity[cix1].Loc := -1; 3256 3257 ChangeTerritory(Loc, pNew); 3258 end; 3259 end; // ChangeCityOwner 3260 3261 procedure CompleteJob(p, Loc, Job: integer); 3262 var 3263 ChangedTerrain, p1: integer; 3264 begin 3265 assert(Job <> jCity); 3266 ChangedTerrain := -1; 3267 case Job of 3268 jRoad: 3269 RealMap[Loc] := RealMap[Loc] or fRoad; 3270 jRR: 3271 RealMap[Loc] := RealMap[Loc] and not fRoad or fRR; 3272 jClear: 3273 begin 3274 ChangedTerrain := Terrain[RealMap[Loc] and fTerrain].ClearTerrain; 3275 RealMap[Loc] := RealMap[Loc] and not fTerrain or 3276 Cardinal(ChangedTerrain); 3277 RealMap[Loc] := RealMap[Loc] and not(3 shl 5) or 3278 ActualSpecialTile(Loc) shl 5; 3279 end; 3280 jIrr: 3281 RealMap[Loc] := RealMap[Loc] and not fTerImp or tiIrrigation; 3282 jFarm: 3283 RealMap[Loc] := RealMap[Loc] and not fTerImp or tiFarm; 3284 jAfforest: 3285 begin 3286 ChangedTerrain := Terrain[RealMap[Loc] and fTerrain].AfforestTerrain; 3287 RealMap[Loc] := RealMap[Loc] and not fTerrain or 3288 Cardinal(ChangedTerrain); 3289 RealMap[Loc] := RealMap[Loc] and not(3 shl 5) or 3290 ActualSpecialTile(Loc) shl 5; 3291 end; 3292 jMine: 3293 RealMap[Loc] := RealMap[Loc] and not fTerImp or tiMine; 3294 jFort: 3295 RealMap[Loc] := RealMap[Loc] and not fTerImp or tiFort; 3296 jCanal: 3297 RealMap[Loc] := RealMap[Loc] or fCanal; 3298 jTrans: 3299 begin 3300 ChangedTerrain := Terrain[RealMap[Loc] and fTerrain].TransTerrain; 3301 RealMap[Loc] := RealMap[Loc] and not fTerrain or 3302 Cardinal(ChangedTerrain); 3303 RealMap[Loc] := RealMap[Loc] and not(3 shl 5) or 3304 ActualSpecialTile(Loc) shl 5; 3305 if not(RealMap[Loc] and fTerrain in TerrType_Canalable) then 3306 begin 3307 RemoveDomainUnits(dSea, p, Loc); 3308 RealMap[Loc] := RealMap[Loc] and not fCanal; 3309 end; 3310 end; 3311 jPoll: 3312 RealMap[Loc] := RealMap[Loc] and not fPoll; 3313 jBase: 3314 RealMap[Loc] := RealMap[Loc] and not fTerImp or tiBase; 3315 jPillage: 3316 if RealMap[Loc] and fTerImp <> 0 then 3317 begin 3318 if RealMap[Loc] and fTerImp = tiBase then 3319 RemoveDomainUnits(dAir, p, Loc); 3320 RealMap[Loc] := RealMap[Loc] and not fTerImp 2770 3321 end 2771 else RemoveUnit(p,uix1); // destroy supported units 2772 end; //StealCity 2773 2774 procedure DestroyCity(p,cix: integer; SaveUnits: boolean); 2775 var 2776 i,V21: integer; 2777 Radius: TVicinity21Loc; 2778 begin 2779 StealCity(p,cix,SaveUnits); 2780 with RW[p].City[cix] do 2781 begin 2782 for i:=0 to 27 do 2783 if Built[i]>0 then GWonder[i].CityID:=-2; // wonder destroyed 2784 V21_to_Loc(Loc,Radius); 2785 for V21:=1 to 26 do if 1 shl V21 and Tiles<>0 then 2786 UsedByCity[Radius[V21]]:=-1; 2787 RealMap[Loc]:=RealMap[Loc] and not fCity; 2788 Loc:=-1 2789 end 2790 end; //DestroyCity 2791 2792 procedure ChangeCityOwner(pOld,cixOld,pNew: integer); 2793 var 2794 i,j,cix1,Loc1,V21: integer; 2795 Radius: TVicinity21Loc; 2796 begin 2797 inc(RW[pNew].nCity); 2798 RW[pNew].City[RW[pNew].nCity-1]:=RW[pOld].City[cixOld]; 2799 StealCity(pOld,cixOld,false); 2800 RW[pOld].City[cixOld].Loc:=-1; 2801 with RW[pNew].City[(RW[pNew].nCity-1)] do 2802 begin 2803 Food:=0; 2804 Project:=cpImp+imTrGoods; 2805 Prod:=0; 2806 Project0:=Project; 2807 Prod0:=0; 2808 Status:=0; 2809 SavedStatus:=0; 2810 N1:=0; 2811 2812 // check for siege 2813 V21_to_Loc(Loc,Radius); 2814 for V21:=1 to 26 do if Tiles and (1 shl V21) and not (1 shl CityOwnTile)<>0 then 2815 begin 2816 Loc1:=Radius[V21]; 2817 assert((Loc1>=0) and (Loc1<MapSize) and (UsedByCity[Loc1]=Loc)); 2818 if (ZoCMap[Loc1]>0) and (Occupant[Loc1]<>pNew) 2819 and (RW[pNew].Treaty[Occupant[Loc1]]<trAlliance) then 2820 begin // tile can't remain exploited 2821 Tiles:=Tiles and not (1 shl V21); 2822 UsedByCity[Loc1]:=-1; 2823 end; 2824 // don't check for siege by peace territory here, because territory 2825 // might not be up to date -- done in turn beginning anyway 2826 end; 2827 Built[imTownHall]:=0; 2828 Built[imCourt]:=0; 2829 for i:=28 to nImp-1 do if Imp[i].Kind<>ikCommon then 2830 Built[i]:=0; {destroy national projects} 2831 for i:=0 to 27 do 2832 if Built[i]=1 then 2833 begin // new wonder owner! 2834 GWonder[i].EffectiveOwner:=pNew; 2835 if i=woEiffel then // reactivate expired wonders 2836 begin 2837 for j:=0 to 27 do if Imp[j].Expiration>=0 then 2838 for cix1:=0 to (RW[pNew].nCity-1) do 2839 if RW[pNew].City[cix1].Built[j]=1 then 2840 GWonder[j].EffectiveOwner:=pNew 2841 end 2842 else CheckExpiration(i); 2843 case i of 2844 woLighthouse: CheckSpecialModels(pNew,preLighthouse); 2845 woLeo: CheckSpecialModels(pNew,preLeo); 2846 woPyramids: CheckSpecialModels(pNew,preBuilder); 2847 end; 2848 end; 2849 2850 // remove city from enemy cities 2851 // not done by Discover, because fCity still set! 2852 cix1:=RW[pNew].nEnemyCity-1; 2853 while (cix1>=0) and (RW[pNew].EnemyCity[cix1].Loc<>Loc) do dec(cix1); 2854 assert(cix1>=0); 2855 RW[pNew].EnemyCity[cix1].Loc:=-1; 2856 2857 ChangeTerritory(Loc,pNew); 2858 end; 2859 end; //ChangeCityOwner 2860 2861 procedure CompleteJob(p,Loc,Job: integer); 2862 var 2863 ChangedTerrain,p1: integer; 2864 begin 2865 assert(Job<>jCity); 2866 ChangedTerrain:=-1; 2867 case Job of 2868 jRoad: 2869 RealMap[Loc]:=RealMap[Loc] or fRoad; 2870 jRR: 2871 RealMap[Loc]:=RealMap[Loc] and not fRoad or fRR; 2872 jClear: 2873 begin 2874 ChangedTerrain:=Terrain[RealMap[Loc] and fTerrain].ClearTerrain; 2875 RealMap[Loc]:=RealMap[Loc] and not fTerrain or Cardinal(ChangedTerrain); 2876 RealMap[Loc]:=RealMap[Loc] and not (3 shl 5) or ActualSpecialTile(Loc) shl 5; 2877 end; 2878 jIrr: 2879 RealMap[Loc]:=RealMap[Loc] and not fTerImp or tiIrrigation; 2880 jFarm: 2881 RealMap[Loc]:=RealMap[Loc] and not fTerImp or tiFarm; 2882 jAfforest: 2883 begin 2884 ChangedTerrain:=Terrain[RealMap[Loc] and fTerrain].AfforestTerrain; 2885 RealMap[Loc]:=RealMap[Loc] and not fTerrain or Cardinal(ChangedTerrain); 2886 RealMap[Loc]:=RealMap[Loc] and not (3 shl 5) or ActualSpecialTile(Loc) shl 5; 2887 end; 2888 jMine: 2889 RealMap[Loc]:=RealMap[Loc] and not fTerImp or tiMine; 2890 jFort: 2891 RealMap[Loc]:=RealMap[Loc] and not fTerImp or tiFort; 2892 jCanal: 2893 RealMap[Loc]:=RealMap[Loc] or fCanal; 2894 jTrans: 2895 begin 2896 ChangedTerrain:=Terrain[RealMap[Loc] and fTerrain].TransTerrain; 2897 RealMap[Loc]:=RealMap[Loc] and not fTerrain or Cardinal(ChangedTerrain); 2898 RealMap[Loc]:=RealMap[Loc] and not (3 shl 5) or ActualSpecialTile(Loc) shl 5; 2899 if not (RealMap[Loc] and fTerrain in TerrType_Canalable) then 2900 begin 2901 RemoveDomainUnits(dSea,p,Loc); 2902 RealMap[Loc]:=RealMap[Loc] and not fCanal; 2903 end; 2904 end; 2905 jPoll: 2906 RealMap[Loc]:=RealMap[Loc] and not fPoll; 2907 jBase: 2908 RealMap[Loc]:=RealMap[Loc] and not fTerImp or tiBase; 2909 jPillage: 2910 if RealMap[Loc] and fTerImp<>0 then 2911 begin 2912 if RealMap[Loc] and fTerImp=tiBase then 2913 RemoveDomainUnits(dAir,p,Loc); 2914 RealMap[Loc]:=RealMap[Loc] and not fTerImp 3322 else if RealMap[Loc] and fCanal <> 0 then 3323 begin 3324 RemoveDomainUnits(dSea, p, Loc); 3325 RealMap[Loc] := RealMap[Loc] and not fCanal 2915 3326 end 2916 else if RealMap[Loc] and fCanal<>0 then 2917 begin 2918 RemoveDomainUnits(dSea,p,Loc); 2919 RealMap[Loc]:=RealMap[Loc] and not fCanal 2920 end 2921 else if RealMap[Loc] and fRR<>0 then 2922 RealMap[Loc]:=RealMap[Loc] and not fRR or fRoad 2923 else if RealMap[Loc] and fRoad<>0 then 2924 RealMap[Loc]:=RealMap[Loc] and not fRoad; 2925 end; 2926 if ChangedTerrain>=0 then 3327 else if RealMap[Loc] and fRR <> 0 then 3328 RealMap[Loc] := RealMap[Loc] and not fRR or fRoad 3329 else if RealMap[Loc] and fRoad <> 0 then 3330 RealMap[Loc] := RealMap[Loc] and not fRoad; 3331 end; 3332 if ChangedTerrain >= 0 then 2927 3333 begin // remove terrain improvements if not possible on new terrain 2928 if ((RealMap[Loc] and fTerImp=tiIrrigation) 2929 or (RealMap[Loc] and fTerImp=tiFarm)) 2930 and ((Terrain[ChangedTerrain].IrrClearWork=0) 2931 or (Terrain[ChangedTerrain].ClearTerrain>=0)) then 2932 RealMap[Loc]:=RealMap[Loc] and not fTerImp; 2933 if (RealMap[Loc] and fTerImp=tiMine) 2934 and ((Terrain[ChangedTerrain].MineAfforestWork=0) 2935 or (Terrain[ChangedTerrain].AfforestTerrain>=0)) then 2936 RealMap[Loc]:=RealMap[Loc] and not fTerImp; 2937 end; 2938 2939 // update map of all observing players 2940 if Mode>moLoading_Fast then 2941 for p1:=0 to nPl-1 do 2942 if (1 shl p1 and (GAlive or GWatching)<>0) 2943 and (ObserveLevel[Loc] shr (2*p1) and 3>lNoObserve) then 2944 RW[p1].Map[Loc]:=RW[p1].Map[Loc] 2945 and not (fTerrain or fSpecial or fTerImp or fRoad or fRR or fCanal or fPoll) 2946 or RealMap[Loc] and (fTerrain or fSpecial or fTerImp or fRoad or fRR or fCanal or fPoll); 2947 end; //CompleteJob 3334 if ((RealMap[Loc] and fTerImp = tiIrrigation) or 3335 (RealMap[Loc] and fTerImp = tiFarm)) and 3336 ((Terrain[ChangedTerrain].IrrClearWork = 0) or 3337 (Terrain[ChangedTerrain].ClearTerrain >= 0)) then 3338 RealMap[Loc] := RealMap[Loc] and not fTerImp; 3339 if (RealMap[Loc] and fTerImp = tiMine) and 3340 ((Terrain[ChangedTerrain].MineAfforestWork = 0) or 3341 (Terrain[ChangedTerrain].AfforestTerrain >= 0)) then 3342 RealMap[Loc] := RealMap[Loc] and not fTerImp; 3343 end; 3344 3345 // update map of all observing players 3346 if Mode > moLoading_Fast then 3347 for p1 := 0 to nPl - 1 do 3348 if (1 shl p1 and (GAlive or GWatching) <> 0) and 3349 (ObserveLevel[Loc] shr (2 * p1) and 3 > lNoObserve) then 3350 RW[p1].Map[Loc] := RW[p1].Map[Loc] and 3351 not(fTerrain or fSpecial or fTerImp or fRoad or fRR or fCanal or 3352 fPoll) or RealMap[Loc] and (fTerrain or fSpecial or fTerImp or 3353 fRoad or fRR or fCanal or fPoll); 3354 end; // CompleteJob 2948 3355 2949 3356 { 2950 Diplomacy2951 ____________________________________________________________________3357 Diplomacy 3358 ____________________________________________________________________ 2952 3359 } 2953 3360 procedure GiveCivilReport(p, pAbout: integer); 2954 3361 begin 2955 with RW[p].EnemyReport[pAbout]^ do2956 begin 2957 // general info2958 TurnOfCivilReport:=LastValidStat[pAbout];2959 move(RW[pAbout].Treaty, Treaty, SizeOf(Treaty));2960 Government:=RW[pAbout].Government;2961 Money:=RW[pAbout].Money;2962 2963 // tech info2964 ResearchTech:=RW[pAbout].ResearchTech;2965 ResearchDone:=RW[pAbout].Research*100 div TechCost(pAbout);2966 if ResearchDone>100 then2967 ResearchDone:=100;2968 move(RW[pAbout].Tech, Tech, nAdv);3362 with RW[p].EnemyReport[pAbout]^ do 3363 begin 3364 // general info 3365 TurnOfCivilReport := LastValidStat[pAbout]; 3366 move(RW[pAbout].Treaty, Treaty, SizeOf(Treaty)); 3367 Government := RW[pAbout].Government; 3368 Money := RW[pAbout].Money; 3369 3370 // tech info 3371 ResearchTech := RW[pAbout].ResearchTech; 3372 ResearchDone := RW[pAbout].Research * 100 div TechCost(pAbout); 3373 if ResearchDone > 100 then 3374 ResearchDone := 100; 3375 move(RW[pAbout].Tech, Tech, nAdv); 2969 3376 end; 2970 3377 end; … … 2972 3379 procedure GiveMilReport(p, pAbout: integer); 2973 3380 var 2974 uix,mix: integer; 2975 begin 2976 with RW[p].EnemyReport[pAbout]^ do 2977 begin 2978 TurnOfMilReport:=LastValidStat[pAbout]; 2979 nModelCounted:=RW[pAbout].nModel; 2980 for mix:=0 to RW[pAbout].nModel-1 do 2981 begin TellAboutModel(p,pAbout,mix); UnCount[mix]:=0 end; 2982 for uix:=0 to RW[pAbout].nUn-1 do 2983 if RW[pAbout].Un[uix].Loc>=0 then inc(UnCount[RW[pAbout].Un[uix].mix]); 3381 uix, mix: integer; 3382 begin 3383 with RW[p].EnemyReport[pAbout]^ do 3384 begin 3385 TurnOfMilReport := LastValidStat[pAbout]; 3386 nModelCounted := RW[pAbout].nModel; 3387 for mix := 0 to RW[pAbout].nModel - 1 do 3388 begin 3389 TellAboutModel(p, pAbout, mix); 3390 UnCount[mix] := 0 3391 end; 3392 for uix := 0 to RW[pAbout].nUn - 1 do 3393 if RW[pAbout].Un[uix].Loc >= 0 then 3394 inc(UnCount[RW[pAbout].Un[uix].mix]); 2984 3395 end 2985 3396 end; … … 2987 3398 procedure ShowPrice(pSender, pTarget, Price: integer); 2988 3399 begin 2989 case Price and opMask of2990 opTech: // + advance2991 with RW[pTarget].EnemyReport[pSender]^ do2992 if Tech[Price-opTech]<tsApplicable then2993 Tech[Price-opTech]:=tsApplicable;2994 opModel: // + model index2995 TellAboutModel(pTarget,pSender,Price-opModel);2996 {opCity: // + city ID2997 begin2998 end;}3400 case Price and opMask of 3401 opTech: // + advance 3402 with RW[pTarget].EnemyReport[pSender]^ do 3403 if Tech[Price - opTech] < tsApplicable then 3404 Tech[Price - opTech] := tsApplicable; 3405 opModel: // + model index 3406 TellAboutModel(pTarget, pSender, Price - opModel); 3407 { opCity: // + city ID 3408 begin 3409 end; } 2999 3410 end 3000 3411 end; … … 3002 3413 function CopyCivilReport(pSender, pTarget, pAbout: integer): boolean; 3003 3414 var 3004 i: integer;3005 rSender, rTarget: ^TEnemyReport;3415 i: integer; 3416 rSender, rTarget: ^TEnemyReport; 3006 3417 begin // copy third nation civil report 3007 result:=false;3008 if RW[pTarget].Treaty[pAbout]=trNoContact then3009 IntroduceEnemy(pTarget, pAbout);3010 rSender:=pointer(RW[pSender].EnemyReport[pAbout]);3011 rTarget:=pointer(RW[pTarget].EnemyReport[pAbout]);3012 if rSender.TurnOfCivilReport>rTarget.TurnOfCivilReport then3418 result := false; 3419 if RW[pTarget].Treaty[pAbout] = trNoContact then 3420 IntroduceEnemy(pTarget, pAbout); 3421 rSender := pointer(RW[pSender].EnemyReport[pAbout]); 3422 rTarget := pointer(RW[pTarget].EnemyReport[pAbout]); 3423 if rSender.TurnOfCivilReport > rTarget.TurnOfCivilReport then 3013 3424 begin // only if newer than current information 3014 rTarget.TurnOfCivilReport:=rSender.TurnOfCivilReport;3015 rTarget.Treaty:=rSender.Treaty;3016 rTarget.Government:=rSender.Government;3017 rTarget.Money:=rSender.Money;3018 rTarget.ResearchTech:=rSender.ResearchTech;3019 rTarget.ResearchDone:=rSender.ResearchDone;3020 result:=true3021 end; 3022 for i:=0 to nAdv-1 do3023 if rTarget.Tech[i]<rSender.Tech[i] then3024 begin 3025 rTarget.Tech[i]:=rSender.Tech[i];3026 result:=true3425 rTarget.TurnOfCivilReport := rSender.TurnOfCivilReport; 3426 rTarget.Treaty := rSender.Treaty; 3427 rTarget.Government := rSender.Government; 3428 rTarget.Money := rSender.Money; 3429 rTarget.ResearchTech := rSender.ResearchTech; 3430 rTarget.ResearchDone := rSender.ResearchDone; 3431 result := true 3432 end; 3433 for i := 0 to nAdv - 1 do 3434 if rTarget.Tech[i] < rSender.Tech[i] then 3435 begin 3436 rTarget.Tech[i] := rSender.Tech[i]; 3437 result := true 3027 3438 end 3028 3439 end; … … 3030 3441 function CopyMilReport(pSender, pTarget, pAbout: integer): boolean; 3031 3442 var 3032 mix: integer;3033 rSender, rTarget: ^TEnemyReport;3443 mix: integer; 3444 rSender, rTarget: ^TEnemyReport; 3034 3445 begin // copy third nation military report 3035 result:=false;3036 if RW[pTarget].Treaty[pAbout]=trNoContact then3037 IntroduceEnemy(pTarget, pAbout);3038 rSender:=pointer(RW[pSender].EnemyReport[pAbout]);3039 rTarget:=pointer(RW[pTarget].EnemyReport[pAbout]);3040 if rSender.TurnOfMilReport>rTarget.TurnOfMilReport then3446 result := false; 3447 if RW[pTarget].Treaty[pAbout] = trNoContact then 3448 IntroduceEnemy(pTarget, pAbout); 3449 rSender := pointer(RW[pSender].EnemyReport[pAbout]); 3450 rTarget := pointer(RW[pTarget].EnemyReport[pAbout]); 3451 if rSender.TurnOfMilReport > rTarget.TurnOfMilReport then 3041 3452 begin // only if newer than current information 3042 rTarget.TurnOfMilReport:=rSender.TurnOfMilReport;3043 rTarget.nModelCounted:=rSender.nModelCounted;3044 move(rSender.UnCount, rTarget.UnCount, 2*rSender.nModelCounted);3045 for mix:=0 to rTarget.nModelCounted-1 do3046 TellAboutModel(pTarget,pAbout,mix);3047 result:=true3453 rTarget.TurnOfMilReport := rSender.TurnOfMilReport; 3454 rTarget.nModelCounted := rSender.nModelCounted; 3455 move(rSender.UnCount, rTarget.UnCount, 2 * rSender.nModelCounted); 3456 for mix := 0 to rTarget.nModelCounted - 1 do 3457 TellAboutModel(pTarget, pAbout, mix); 3458 result := true 3048 3459 end 3049 3460 end; 3050 3461 3051 procedure CopyModel(pSender,pTarget,mix: integer); 3052 var 3053 i: integer; 3054 miSender, miTarget: TModelInfo; 3055 ok: boolean; 3056 begin 3057 // only if target doesn't already have a model like this 3058 ok:= RW[pTarget].nModel<nmmax; 3059 MakeModelInfo(pSender,mix,RW[pSender].Model[mix],miSender); 3060 for i:=0 to RW[pTarget].nModel-1 do 3061 begin 3062 MakeModelInfo(pTarget,i,RW[pTarget].Model[i],miTarget); 3063 if IsSameModel(miSender,miTarget) then ok:=false 3064 end; 3065 if ok then 3066 begin 3067 RW[pTarget].Model[RW[pTarget].nModel]:=RW[pSender].Model[mix]; 3068 with RW[pTarget].Model[RW[pTarget].nModel] do 3069 begin 3070 IntroTurn:=GTurn; 3071 if Kind=mkSelfDeveloped then Kind:=mkEnemyDeveloped; 3072 Status:=0; 3073 SavedStatus:=0; 3074 Built:=0; 3075 Lost:=0; 3076 end; 3077 inc(RW[pTarget].nModel); 3078 inc(Researched[pTarget]); 3079 TellAboutModel(pSender,pTarget,RW[pTarget].nModel-1); 3462 procedure CopyModel(pSender, pTarget, mix: integer); 3463 var 3464 i: integer; 3465 miSender, miTarget: TModelInfo; 3466 ok: boolean; 3467 begin 3468 // only if target doesn't already have a model like this 3469 ok := RW[pTarget].nModel < nmmax; 3470 MakeModelInfo(pSender, mix, RW[pSender].Model[mix], miSender); 3471 for i := 0 to RW[pTarget].nModel - 1 do 3472 begin 3473 MakeModelInfo(pTarget, i, RW[pTarget].Model[i], miTarget); 3474 if IsSameModel(miSender, miTarget) then 3475 ok := false 3476 end; 3477 if ok then 3478 begin 3479 RW[pTarget].Model[RW[pTarget].nModel] := RW[pSender].Model[mix]; 3480 with RW[pTarget].Model[RW[pTarget].nModel] do 3481 begin 3482 IntroTurn := GTurn; 3483 if Kind = mkSelfDeveloped then 3484 Kind := mkEnemyDeveloped; 3485 Status := 0; 3486 SavedStatus := 0; 3487 Built := 0; 3488 Lost := 0; 3489 end; 3490 inc(RW[pTarget].nModel); 3491 inc(Researched[pTarget]); 3492 TellAboutModel(pSender, pTarget, RW[pTarget].nModel - 1); 3080 3493 end 3081 3494 end; … … 3083 3496 procedure CopyMap(pSender, pTarget: integer); 3084 3497 var 3085 Loc,i,cix:integer; 3086 Tile: Cardinal; 3087 begin 3088 for Loc:=0 to MapSize-1 do 3089 if (RW[pSender].MapObservedLast[Loc]>RW[pTarget].MapObservedLast[Loc]) then 3090 begin 3091 Tile:=RW[pSender].Map[Loc]; 3092 if Tile and fCity<>0 then 3093 begin 3094 i:=0; 3095 while (i<RW[pTarget].nEnemyCity) and (RW[pTarget].EnemyCity[i].Loc<>Loc) do 3096 inc(i); 3097 if i=RW[pTarget].nEnemyCity then 3098 begin 3099 inc(RW[pTarget].nEnemyCity); 3100 assert(RW[pTarget].nEnemyCity<necmax); 3101 RW[pTarget].EnemyCity[i].Status:=0; 3102 RW[pTarget].EnemyCity[i].SavedStatus:=0; 3498 Loc, i, cix: integer; 3499 Tile: Cardinal; 3500 begin 3501 for Loc := 0 to MapSize - 1 do 3502 if (RW[pSender].MapObservedLast[Loc] > RW[pTarget].MapObservedLast[Loc]) 3503 then 3504 begin 3505 Tile := RW[pSender].Map[Loc]; 3506 if Tile and fCity <> 0 then 3507 begin 3508 i := 0; 3509 while (i < RW[pTarget].nEnemyCity) and 3510 (RW[pTarget].EnemyCity[i].Loc <> Loc) do 3511 inc(i); 3512 if i = RW[pTarget].nEnemyCity then 3513 begin 3514 inc(RW[pTarget].nEnemyCity); 3515 assert(RW[pTarget].nEnemyCity < necmax); 3516 RW[pTarget].EnemyCity[i].Status := 0; 3517 RW[pTarget].EnemyCity[i].SavedStatus := 0; 3103 3518 end; 3104 if Tile and fOwned<>0 then3519 if Tile and fOwned <> 0 then 3105 3520 begin // city owned by sender -- create new info 3106 cix:=RW[pSender].nCity-1; 3107 while (cix>=0) and (RW[pSender].City[cix].Loc<>Loc) do dec(cix); 3108 MakeCityInfo(pSender, cix, RW[pTarget].EnemyCity[i]); 3521 cix := RW[pSender].nCity - 1; 3522 while (cix >= 0) and (RW[pSender].City[cix].Loc <> Loc) do 3523 dec(cix); 3524 MakeCityInfo(pSender, cix, RW[pTarget].EnemyCity[i]); 3109 3525 end 3110 else // city not owned by sender -- copy old info 3111 begin 3112 cix:=RW[pSender].nEnemyCity-1; 3113 while (cix>=0) and (RW[pSender].EnemyCity[cix].Loc<>Loc) do dec(cix); 3114 RW[pTarget].EnemyCity[i]:=RW[pSender].EnemyCity[cix]; 3526 else // city not owned by sender -- copy old info 3527 begin 3528 cix := RW[pSender].nEnemyCity - 1; 3529 while (cix >= 0) and (RW[pSender].EnemyCity[cix].Loc <> Loc) do 3530 dec(cix); 3531 RW[pTarget].EnemyCity[i] := RW[pSender].EnemyCity[cix]; 3115 3532 end; 3116 3533 end 3117 else if RW[pTarget].Map[Loc] and fCity<>0 then // remove enemycity 3118 for cix:=0 to RW[pTarget].nEnemyCity-1 do 3119 if RW[pTarget].EnemyCity[cix].Loc=Loc then 3120 RW[pTarget].EnemyCity[cix].Loc:=-1; 3121 3122 Tile:=Tile and (not (fSpecial or fModern) or ResourceMask[pTarget]); 3123 Tile:=Tile or (RW[pTarget].Map[Loc] and fModern); 3124 if (Tile and fTerrain=RW[pTarget].Map[Loc] and fTerrain) then 3125 Tile:=Tile or (RW[pTarget].Map[Loc] and fSpecial); 3126 3127 if RW[pTarget].Map[Loc] and fTerrain=fUNKNOWN then inc(Discovered[pTarget]); 3128 RW[pTarget].Map[Loc]:=RW[pTarget].Map[Loc] and fInEnemyZoC // always preserve this flag! 3129 or Tile and not (fUnit or fHiddenUnit or fStealthUnit 3130 or fObserved or fSpiedOut or fOwned or fInEnemyZoC or fOwnZoCUnit 3131 or fPeace or fGrWall); 3132 if RW[pSender].Territory[Loc]<>RW[pTarget].Territory[Loc] then 3133 begin 3134 RW[pTarget].Territory[Loc]:=RW[pSender].Territory[Loc]; 3135 {if RW[pTarget].BorderHelper<>nil then 3136 RW[pTarget].BorderHelper[Loc]:=0;} 3137 end; 3138 RW[pTarget].Territory[Loc]:=RW[pSender].Territory[Loc]; 3139 RW[pTarget].MapObservedLast[Loc]:=RW[pSender].MapObservedLast[Loc]; 3534 else if RW[pTarget].Map[Loc] and fCity <> 0 then // remove enemycity 3535 for cix := 0 to RW[pTarget].nEnemyCity - 1 do 3536 if RW[pTarget].EnemyCity[cix].Loc = Loc then 3537 RW[pTarget].EnemyCity[cix].Loc := -1; 3538 3539 Tile := Tile and (not(fSpecial or fModern) or ResourceMask[pTarget]); 3540 Tile := Tile or (RW[pTarget].Map[Loc] and fModern); 3541 if (Tile and fTerrain = RW[pTarget].Map[Loc] and fTerrain) then 3542 Tile := Tile or (RW[pTarget].Map[Loc] and fSpecial); 3543 3544 if RW[pTarget].Map[Loc] and fTerrain = fUNKNOWN then 3545 inc(Discovered[pTarget]); 3546 RW[pTarget].Map[Loc] := RW[pTarget].Map[Loc] and fInEnemyZoC 3547 // always preserve this flag! 3548 or Tile and not(fUnit or fHiddenUnit or fStealthUnit or fObserved or 3549 fSpiedOut or fOwned or fInEnemyZoC or fOwnZoCUnit or fPeace or fGrWall); 3550 if RW[pSender].Territory[Loc] <> RW[pTarget].Territory[Loc] then 3551 begin 3552 RW[pTarget].Territory[Loc] := RW[pSender].Territory[Loc]; 3553 { if RW[pTarget].BorderHelper<>nil then 3554 RW[pTarget].BorderHelper[Loc]:=0; } 3555 end; 3556 RW[pTarget].Territory[Loc] := RW[pSender].Territory[Loc]; 3557 RW[pTarget].MapObservedLast[Loc] := RW[pSender].MapObservedLast[Loc]; 3140 3558 end; 3141 3559 end; … … 3143 3561 function PayPrice(pSender, pTarget, Price: integer; execute: boolean): boolean; 3144 3562 var 3145 pSubject,i,n,NewTreaty: integer; 3146 begin 3147 result:=true; 3148 case Price and opMask of 3149 opCivilReport: // + turn + concerned player shl 16 3150 begin 3151 pSubject:=Price shr 16 and $f; 3152 if pTarget=pSubject then result:=false 3153 else if pSender=pSubject then 3154 begin 3155 if execute then GiveCivilReport(pTarget,pSender) 3156 end 3157 else if RW[pSender].EnemyReport[pSubject].TurnOfCivilReport<0 then 3158 result:=false 3159 else if execute then CopyCivilReport(pSender, pTarget, pSubject); 3160 end; 3161 opMilReport: // + turn + concerned player shl 16 3162 begin 3163 pSubject:=Price shr 16 and $f; 3164 if pTarget=pSubject then result:=false 3165 else if pSender=pSubject then 3166 begin 3167 if execute then GiveMilReport(pTarget,pSender) 3168 end 3169 else if RW[pSender].EnemyReport[pSubject].TurnOfMilReport<0 then 3170 result:=false 3171 else if execute then CopyMilReport(pSender, pTarget, pSubject) 3172 end; 3173 opMap: 3174 if execute then 3175 begin 3176 CopyMap(pSender, pTarget); 3177 RecalcPeaceMap(pTarget); 3178 end; 3179 opTreaty..opTreaty+trAlliance: // + nation treaty 3180 begin 3181 if Price-opTreaty=RW[pSender].Treaty[pTarget]-1 then 3182 begin // agreed treaty end 3183 if execute then CancelTreaty(pSender,pTarget,false) 3184 end 3185 else 3186 begin 3187 NewTreaty:=-1; 3188 if Price-opTreaty=RW[pSender].Treaty[pTarget]+1 then 3189 NewTreaty:=Price-opTreaty 3190 else if (RW[pSender].Treaty[pTarget]=trNone) and (Price-opTreaty=trPeace) then 3191 NewTreaty:=trPeace; 3192 if NewTreaty<0 then result:=false 3193 else if execute then 3194 begin 3195 assert(NewTreaty>RW[pSender].Treaty[pTarget]); 3196 RW[pSender].Treaty[pTarget]:=NewTreaty; 3197 RW[pTarget].Treaty[pSender]:=NewTreaty; 3198 if NewTreaty>=trFriendlyContact then 3563 pSubject, i, n, NewTreaty: integer; 3564 begin 3565 result := true; 3566 case Price and opMask of 3567 opCivilReport: // + turn + concerned player shl 16 3568 begin 3569 pSubject := Price shr 16 and $F; 3570 if pTarget = pSubject then 3571 result := false 3572 else if pSender = pSubject then 3573 begin 3574 if execute then 3575 GiveCivilReport(pTarget, pSender) 3576 end 3577 else if RW[pSender].EnemyReport[pSubject].TurnOfCivilReport < 0 then 3578 result := false 3579 else if execute then 3580 CopyCivilReport(pSender, pTarget, pSubject); 3581 end; 3582 opMilReport: // + turn + concerned player shl 16 3583 begin 3584 pSubject := Price shr 16 and $F; 3585 if pTarget = pSubject then 3586 result := false 3587 else if pSender = pSubject then 3588 begin 3589 if execute then 3590 GiveMilReport(pTarget, pSender) 3591 end 3592 else if RW[pSender].EnemyReport[pSubject].TurnOfMilReport < 0 then 3593 result := false 3594 else if execute then 3595 CopyMilReport(pSender, pTarget, pSubject) 3596 end; 3597 opMap: 3598 if execute then 3599 begin 3600 CopyMap(pSender, pTarget); 3601 RecalcPeaceMap(pTarget); 3602 end; 3603 opTreaty .. opTreaty + trAlliance: // + nation treaty 3604 begin 3605 if Price - opTreaty = RW[pSender].Treaty[pTarget] - 1 then 3606 begin // agreed treaty end 3607 if execute then 3608 CancelTreaty(pSender, pTarget, false) 3609 end 3610 else 3611 begin 3612 NewTreaty := -1; 3613 if Price - opTreaty = RW[pSender].Treaty[pTarget] + 1 then 3614 NewTreaty := Price - opTreaty 3615 else if (RW[pSender].Treaty[pTarget] = trNone) and 3616 (Price - opTreaty = trPeace) then 3617 NewTreaty := trPeace; 3618 if NewTreaty < 0 then 3619 result := false 3620 else if execute then 3199 3621 begin 3200 GiveCivilReport(pTarget, pSender); 3201 GiveCivilReport(pSender, pTarget); 3202 end; 3203 if NewTreaty=trAlliance then 3622 assert(NewTreaty > RW[pSender].Treaty[pTarget]); 3623 RW[pSender].Treaty[pTarget] := NewTreaty; 3624 RW[pTarget].Treaty[pSender] := NewTreaty; 3625 if NewTreaty >= TrFriendlyContact then 3626 begin 3627 GiveCivilReport(pTarget, pSender); 3628 GiveCivilReport(pSender, pTarget); 3629 end; 3630 if NewTreaty = trAlliance then 3631 begin 3632 GiveMilReport(pTarget, pSender); 3633 GiveMilReport(pSender, pTarget); 3634 CopyMap(pSender, pTarget); 3635 CopyMap(pTarget, pSender); 3636 RecalcMapZoC(pSender); 3637 RecalcMapZoC(pTarget); 3638 end; 3639 if not(NewTreaty in [trPeace, TrFriendlyContact]) then 3640 begin 3641 RW[pSender].EvaStart[pTarget] := -PeaceEvaTurns - 1; 3642 RW[pTarget].EvaStart[pSender] := -PeaceEvaTurns - 1; 3643 end; 3644 RecalcPeaceMap(pSender); 3645 RecalcPeaceMap(pTarget); 3646 end 3647 end 3648 end; 3649 opShipParts: // + number + part type shl 16 3650 begin 3651 n := Price and $FFFF; // number 3652 i := Price shr 16 and $F; // type 3653 if (i < nShipPart) and (GShip[pSender].Parts[i] >= n) then 3654 begin 3655 if execute then 3204 3656 begin 3205 GiveMilReport(pTarget, pSender); 3206 GiveMilReport(pSender, pTarget); 3207 CopyMap(pSender, pTarget); 3208 CopyMap(pTarget, pSender); 3209 RecalcMapZoC(pSender); 3210 RecalcMapZoC(pTarget); 3211 end; 3212 if not (NewTreaty in [trPeace,trFriendlyContact]) then 3213 begin 3214 RW[pSender].EvaStart[pTarget]:=-PeaceEvaTurns-1; 3215 RW[pTarget].EvaStart[pSender]:=-PeaceEvaTurns-1; 3216 end; 3217 RecalcPeaceMap(pSender); 3218 RecalcPeaceMap(pTarget); 3657 dec(GShip[pSender].Parts[i], n); 3658 RW[pSender].Ship[pSender].Parts[i] := GShip[pSender].Parts[i]; 3659 RW[pTarget].Ship[pSender].Parts[i] := GShip[pSender].Parts[i]; 3660 if RW[pTarget].NatBuilt[imSpacePort] > 0 then 3661 begin // space ship control requires space port 3662 inc(GShip[pTarget].Parts[i], n); 3663 RW[pSender].Ship[pTarget].Parts[i] := GShip[pTarget].Parts[i]; 3664 RW[pTarget].Ship[pTarget].Parts[i] := GShip[pTarget].Parts[i]; 3665 end 3666 end 3667 end 3668 else 3669 result := false; 3670 end; 3671 opMoney: // + value 3672 if (Price - opMoney <= MaxMoneyPrice) and 3673 (RW[pSender].Money >= Price - opMoney) then 3674 begin 3675 if execute then 3676 begin 3677 dec(RW[pSender].Money, Price - opMoney); 3678 inc(RW[pTarget].Money, Price - opMoney); 3219 3679 end 3220 3680 end 3221 end; 3222 opShipParts: // + number + part type shl 16 3223 begin 3224 n:=Price and $FFFF; // number 3225 i:=Price shr 16 and $f; // type 3226 if (i<nShipPart) and (GShip[pSender].Parts[i]>=n) then 3227 begin 3681 else 3682 result := false; 3683 opTribute: // + value 3228 3684 if execute then 3229 begin 3230 dec(GShip[pSender].Parts[i],n); 3231 RW[pSender].Ship[pSender].Parts[i]:=GShip[pSender].Parts[i]; 3232 RW[pTarget].Ship[pSender].Parts[i]:=GShip[pSender].Parts[i]; 3233 if RW[pTarget].NatBuilt[imSpacePort]>0 then 3234 begin // space ship control requires space port 3235 inc(GShip[pTarget].Parts[i],n); 3236 RW[pSender].Ship[pTarget].Parts[i]:=GShip[pTarget].Parts[i]; 3237 RW[pTarget].Ship[pTarget].Parts[i]:=GShip[pTarget].Parts[i]; 3238 end 3685 begin 3686 end; 3687 opTech: // + advance 3688 if RW[pSender].Tech[Price - opTech] >= tsApplicable then 3689 begin 3690 if execute and (RW[pTarget].Tech[Price - opTech] = tsNA) then 3691 begin 3692 SeeTech(pTarget, Price - opTech); 3693 RW[pSender].EnemyReport[pTarget].Tech[Price - opTech] := tsSeen; 3239 3694 end 3240 3695 end 3241 else result:=false; 3242 end; 3243 opMoney: // + value 3244 if (Price-opMoney<=MaxMoneyPrice) and (RW[pSender].Money>=Price-opMoney) then 3245 begin 3696 else 3697 result := false; 3698 opAllTech: 3246 3699 if execute then 3247 begin 3248 dec(RW[pSender].Money,Price-opMoney); 3249 inc(RW[pTarget].Money,Price-opMoney); 3700 for i := 0 to nAdv - 1 do 3701 if (RW[pSender].Tech[i] >= tsApplicable) and 3702 (RW[pTarget].Tech[i] = tsNA) then 3703 begin 3704 SeeTech(pTarget, i); 3705 RW[pSender].EnemyReport[pTarget].Tech[i] := tsSeen; 3706 RW[pTarget].EnemyReport[pSender].Tech[i] := tsApplicable; 3707 end; 3708 opModel: // + model index 3709 if Price - opModel < RW[pSender].nModel then 3710 begin 3711 if execute then 3712 CopyModel(pSender, pTarget, Price - opModel) 3713 end 3714 else 3715 result := false; 3716 opAllModel: 3717 if execute then 3718 for i := 0 to RW[pSender].nModel - 1 do 3719 begin 3720 TellAboutModel(pTarget, pSender, i); 3721 CopyModel(pSender, pTarget, i); 3722 end; 3723 { opCity: // + city ID 3724 begin 3725 result:=false 3726 end; } 3727 end 3728 end; 3729 3730 procedure CancelTreaty(p, pWith: integer; DecreaseCredibility: boolean); 3731 // side effect: PeaceEnded := bitarray of players with which peace treaty was canceled 3732 var 3733 p1, OldTreaty: integer; 3734 begin 3735 OldTreaty := RW[p].Treaty[pWith]; 3736 PeaceEnded := 0; 3737 if OldTreaty >= trPeace then 3738 RW[p].LastCancelTreaty[pWith] := GTurn; 3739 if DecreaseCredibility then 3740 begin 3741 case OldTreaty of 3742 trPeace: 3743 begin 3744 RW[p].Credibility := RW[p].Credibility shr 1; 3745 if RW[p].MaxCredibility > 0 then 3746 dec(RW[p].MaxCredibility, 10); 3747 if RW[p].Credibility > RW[p].MaxCredibility then 3748 RW[p].Credibility := RW[p].MaxCredibility; 3749 end; 3750 trAlliance: 3751 RW[p].Credibility := RW[p].Credibility * 3 div 4; 3752 end; 3753 RW[pWith].EnemyReport[p].Credibility := RW[p].Credibility; 3754 end; 3755 3756 if OldTreaty = trPeace then 3757 begin 3758 for p1 := 0 to nPl - 1 do 3759 if (p1 = pWith) or DecreaseCredibility and (p1 <> p) and 3760 (RW[pWith].Treaty[p1] = trAlliance) and (RW[p].Treaty[p1] >= trPeace) 3761 then 3762 begin 3763 RW[p].Treaty[p1] := trNone; 3764 RW[p1].Treaty[p] := trNone; 3765 RW[p].EvaStart[p1] := -PeaceEvaTurns - 1; 3766 RW[p1].EvaStart[p] := -PeaceEvaTurns - 1; 3767 inc(PeaceEnded, 1 shl p1); 3768 end; 3769 CheckBorders(-1); 3770 if (Mode > moLoading_Fast) and (PeaceEnded > 0) then 3771 RecalcMapZoC(p); 3772 end 3773 else 3774 begin 3775 RW[p].Treaty[pWith] := OldTreaty - 1; 3776 RW[pWith].Treaty[p] := OldTreaty - 1; 3777 if OldTreaty = TrFriendlyContact then 3778 begin // necessary for loading 3779 GiveCivilReport(p, pWith); 3780 GiveCivilReport(pWith, p); 3781 end 3782 else if OldTreaty = trAlliance then 3783 begin // necessary for loading 3784 GiveMilReport(p, pWith); 3785 GiveMilReport(pWith, p); 3786 end; 3787 if (Mode > moLoading_Fast) and (OldTreaty = trAlliance) then 3788 begin 3789 RecalcMapZoC(p); 3790 RecalcMapZoC(pWith); 3791 end 3792 end; 3793 if OldTreaty in [trPeace, trAlliance] then 3794 begin 3795 RecalcPeaceMap(p); 3796 RecalcPeaceMap(pWith); 3797 end 3798 end; 3799 3800 function DoSpyMission(p, pCity, cix, Mission: integer): Cardinal; 3801 var 3802 p1: integer; 3803 begin 3804 result := 0; 3805 case Mission of 3806 smSabotageProd: 3807 RW[pCity].City[cix].Flags := RW[pCity].City[cix].Flags or 3808 chProductionSabotaged; 3809 smStealMap: 3810 begin 3811 CopyMap(pCity, p); 3812 RecalcPeaceMap(p); 3813 end; 3814 smStealCivilReport: 3815 begin 3816 if RW[p].Treaty[pCity] = trNoContact then 3817 IntroduceEnemy(p, pCity); 3818 GiveCivilReport(p, pCity); 3819 end; 3820 smStealMilReport: 3821 begin 3822 if RW[p].Treaty[pCity] = trNoContact then 3823 IntroduceEnemy(p, pCity); 3824 GiveMilReport(p, pCity); 3825 end; 3826 smStealForeignReports: 3827 begin 3828 for p1 := 0 to nPl - 1 do 3829 if (p1 <> p) and (p1 <> pCity) and (RW[pCity].EnemyReport[p1] <> nil) 3830 then 3831 begin 3832 if RW[pCity].EnemyReport[p1].TurnOfCivilReport >= 0 then 3833 if CopyCivilReport(pCity, p, p1) then 3834 result := result or (1 shl (2 * p1)); 3835 if RW[pCity].EnemyReport[p1].TurnOfMilReport >= 0 then 3836 if CopyMilReport(pCity, p, p1) then 3837 result := result or (2 shl (2 * p1)); 3838 end 3839 end; 3840 end; 3841 end; 3842 3843 { 3844 Test Flags 3845 ____________________________________________________________________ 3846 } 3847 procedure ClearTestFlags(ClearFlags: integer); 3848 var 3849 p1: integer; 3850 begin 3851 GTestFlags := GTestFlags and (not ClearFlags or tfTested or tfAllTechs or 3852 tfAllContact); 3853 for p1 := 0 to nPl - 1 do 3854 if 1 shl p1 and (GAlive or GWatching) <> 0 then 3855 RW[p1].TestFlags := GTestFlags; 3856 end; 3857 3858 procedure SetTestFlags(p, SetFlags: integer); 3859 var 3860 i, p1, p2, MoreFlags: integer; 3861 begin 3862 MoreFlags := SetFlags and not GTestFlags; 3863 GTestFlags := GTestFlags or (SetFlags and $7FF); 3864 for p1 := 0 to nPl - 1 do 3865 if 1 shl p1 and (GAlive or GWatching) <> 0 then 3866 RW[p1].TestFlags := GTestFlags; 3867 3868 if MoreFlags and (tfUncover or tfAllContact) <> 0 then 3869 for p1 := 0 to nPl - 2 do 3870 if 1 shl p1 and GAlive <> 0 then 3871 for p2 := p1 + 1 to nPl - 1 do 3872 if 1 shl p2 and GAlive <> 0 then 3873 begin // make p1 and p2 know each other 3874 if RW[p1].Treaty[p2] = trNoContact then 3875 IntroduceEnemy(p1, p2) 3876 end; 3877 3878 if MoreFlags and tfAllTechs <> 0 then 3879 for p1 := 0 to nPl - 1 do 3880 begin 3881 ResourceMask[p1] := $FFFFFFFF; 3882 if 1 shl p1 and GAlive <> 0 then 3883 begin 3884 for i := 0 to nAdv - 1 do // give all techs to player p1 3885 if not(i in FutureTech) and (RW[p1].Tech[i] < tsApplicable) then 3886 begin 3887 RW[p1].Tech[i] := tsCheat; 3888 CheckSpecialModels(p1, i); 3889 end; 3890 for p2 := 0 to nPl - 1 do 3891 if (p2 <> p1) and (1 shl p2 and (GAlive or GWatching) <> 0) then 3892 for i := 1 to 3 do 3893 if RW[p2].EnemyReport[p1].Tech[AgePreq[i]] < tsApplicable then 3894 RW[p2].EnemyReport[p1].Tech[AgePreq[i]] := tsCheat; 3895 end 3896 end; 3897 3898 if MoreFlags and tfUncover <> 0 then 3899 begin 3900 DiscoverAll(p, lObserveSuper); 3901 for p1 := 0 to nPl - 1 do 3902 if 1 shl p1 and GAlive <> 0 then 3903 begin 3904 ResourceMask[p1] := $FFFFFFFF; 3905 if p1 <> p then 3906 begin 3907 GiveCivilReport(p, p1); 3908 GiveMilReport(p, p1); 3250 3909 end 3251 3910 end 3252 else result:=false;3253 opTribute: // + value3254 if execute then3255 begin3256 end;3257 opTech: // + advance3258 if RW[pSender].Tech[Price-opTech]>=tsApplicable then3259 begin3260 if execute and (RW[pTarget].Tech[Price-opTech]=tsNA) then3261 begin3262 SeeTech(pTarget,Price-opTech);3263 RW[pSender].EnemyReport[pTarget].Tech[Price-opTech]:=tsSeen;3264 end3265 end3266 else result:=false;3267 opAllTech:3268 if execute then for i:=0 to nAdv-1 do3269 if (RW[pSender].Tech[i]>=tsApplicable) and (RW[pTarget].Tech[i]=tsNA) then3270 begin3271 SeeTech(pTarget,i);3272 RW[pSender].EnemyReport[pTarget].Tech[i]:=tsSeen;3273 RW[pTarget].EnemyReport[pSender].Tech[i]:=tsApplicable;3274 end;3275 opModel: // + model index3276 if Price-opModel<RW[pSender].nModel then3277 begin3278 if execute then CopyModel(pSender,pTarget,Price-opModel)3279 end3280 else result:=false;3281 opAllModel:3282 if execute then for i:=0 to RW[pSender].nModel-1 do3283 begin3284 TellAboutModel(pTarget,pSender,i);3285 CopyModel(pSender,pTarget,i);3286 end;3287 { opCity: // + city ID3288 begin3289 result:=false3290 end;}3291 end3292 end;3293 3294 procedure CancelTreaty(p, pWith: integer; DecreaseCredibility: boolean);3295 // side effect: PeaceEnded := bitarray of players with which peace treaty was canceled3296 var3297 p1,OldTreaty: integer;3298 begin3299 OldTreaty:=RW[p].Treaty[pWith];3300 PeaceEnded:=0;3301 if OldTreaty>=trPeace then3302 RW[p].LastCancelTreaty[pWith]:=GTurn;3303 if DecreaseCredibility then3304 begin3305 case OldTreaty of3306 trPeace:3307 begin3308 RW[p].Credibility:=RW[p].Credibility shr 1;3309 if RW[p].MaxCredibility>0 then3310 dec(RW[p].MaxCredibility,10);3311 if RW[p].Credibility>RW[p].MaxCredibility then3312 RW[p].Credibility:=RW[p].MaxCredibility;3313 end;3314 trAlliance:3315 RW[p].Credibility:=RW[p].Credibility*3 div 4;3316 end;3317 RW[pWith].EnemyReport[p].Credibility:=RW[p].Credibility;3318 end;3319 3320 if OldTreaty=trPeace then3321 begin3322 for p1:=0 to nPl-1 do3323 if (p1=pWith)3324 or DecreaseCredibility and (p1<>p)3325 and (RW[pWith].Treaty[p1]=trAlliance)3326 and (RW[p].Treaty[p1]>=trPeace) then3327 begin3328 RW[p].Treaty[p1]:=trNone;3329 RW[p1].Treaty[p]:=trNone;3330 RW[p].EvaStart[p1]:=-PeaceEvaTurns-1;3331 RW[p1].EvaStart[p]:=-PeaceEvaTurns-1;3332 inc(PeaceEnded,1 shl p1);3333 end;3334 CheckBorders(-1);3335 if (Mode>moLoading_Fast) and (PeaceEnded>0) then3336 RecalcMapZoC(p);3337 end3338 else3339 begin3340 RW[p].Treaty[pWith]:=OldTreaty-1;3341 RW[pWith].Treaty[p]:=OldTreaty-1;3342 if OldTreaty=trFriendlyContact then3343 begin // necessary for loading3344 GiveCivilReport(p, pWith);3345 GiveCivilReport(pWith, p);3346 end3347 else if OldTreaty=trAlliance then3348 begin // necessary for loading3349 GiveMilReport(p, pWith);3350 GiveMilReport(pWith, p);3351 end;3352 if (Mode>moLoading_Fast) and (OldTreaty=trAlliance) then3353 begin3354 RecalcMapZoC(p);3355 RecalcMapZoC(pWith);3356 end3357 end;3358 if OldTreaty in [trPeace,trAlliance] then3359 begin3360 RecalcPeaceMap(p);3361 RecalcPeaceMap(pWith);3362 end3363 end;3364 3365 function DoSpyMission(p,pCity,cix,Mission: integer): Cardinal;3366 var3367 p1: integer;3368 begin3369 result:=0;3370 case Mission of3371 smSabotageProd: RW[pCity].City[cix].Flags:=3372 RW[pCity].City[cix].Flags or chProductionSabotaged;3373 smStealMap:3374 begin3375 CopyMap(pCity,p);3376 RecalcPeaceMap(p);3377 end;3378 smStealCivilReport:3379 begin3380 if RW[p].Treaty[pCity]=trNoContact then IntroduceEnemy(p,pCity);3381 GiveCivilReport(p,pCity);3382 end;3383 smStealMilReport:3384 begin3385 if RW[p].Treaty[pCity]=trNoContact then IntroduceEnemy(p,pCity);3386 GiveMilReport(p,pCity);3387 end;3388 smStealForeignReports:3389 begin3390 for p1:=0 to nPl-1 do if (p1<>p) and (p1<>pCity)3391 and (RW[pCity].EnemyReport[p1]<>nil) then3392 begin3393 if RW[pCity].EnemyReport[p1].TurnOfCivilReport>=0 then3394 if CopyCivilReport(pCity,p,p1) then3395 result:=result or (1 shl (2*p1));3396 if RW[pCity].EnemyReport[p1].TurnOfMilReport>=0 then3397 if CopyMilReport(pCity,p,p1) then3398 result:=result or (2 shl (2*p1));3399 end3400 end;3401 3911 end; 3402 3912 end; 3403 3913 3404 3914 { 3405 Test Flags3406 ____________________________________________________________________3915 Internal Command Processing 3916 ____________________________________________________________________ 3407 3917 } 3408 procedure ClearTestFlags(ClearFlags: integer); 3409 var 3410 p1: integer; 3411 begin 3412 GTestFlags:=GTestFlags and (not ClearFlags or tfTested or tfAllTechs or tfAllContact); 3413 for p1:=0 to nPl-1 do if 1 shl p1 and (GAlive or GWatching)<>0 then 3414 RW[p1].TestFlags:=GTestFlags; 3415 end; 3416 3417 procedure SetTestFlags(p,SetFlags: integer); 3418 var 3419 i,p1,p2,MoreFlags: integer; 3420 begin 3421 MoreFlags:=SetFlags and not GTestFlags; 3422 GTestFlags:=GTestFlags or (SetFlags and $7FF); 3423 for p1:=0 to nPl-1 do if 1 shl p1 and (GAlive or GWatching)<>0 then 3424 RW[p1].TestFlags:=GTestFlags; 3425 3426 if MoreFlags and (tfUncover or tfAllContact)<>0 then 3427 for p1:=0 to nPl-2 do 3428 if 1 shl p1 and GAlive<>0 then 3429 for p2:=p1+1 to nPl-1 do if 1 shl p2 and GAlive<>0 then 3430 begin // make p1 and p2 know each other 3431 if RW[p1].Treaty[p2]=trNoContact then 3432 IntroduceEnemy(p1,p2) 3433 end; 3434 3435 if MoreFlags and tfAllTechs<>0 then 3436 for p1:=0 to nPl-1 do 3437 begin 3438 ResourceMask[p1]:=$FFFFFFFF; 3439 if 1 shl p1 and GAlive<>0 then 3440 begin 3441 for i:=0 to nAdv-1 do // give all techs to player p1 3442 if not (i in FutureTech) and (RW[p1].Tech[i]<tsApplicable) then 3443 begin 3444 RW[p1].Tech[i]:=tsCheat; 3445 CheckSpecialModels(p1,i); 3446 end; 3447 for p2:=0 to nPl-1 do if (p2<>p1) and (1 shl p2 and (GAlive or GWatching)<>0) then 3448 for i:=1 to 3 do 3449 if RW[p2].EnemyReport[p1].Tech[AgePreq[i]]<tsApplicable then 3450 RW[p2].EnemyReport[p1].Tech[AgePreq[i]]:=tsCheat; 3451 end 3452 end; 3453 3454 if MoreFlags and tfUncover<>0 then 3455 begin 3456 DiscoverAll(p,lObserveSuper); 3457 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then 3458 begin 3459 ResourceMask[p1]:=$FFFFFFFF; 3460 if p1<>p then 3461 begin 3462 GiveCivilReport(p, p1); 3463 GiveMilReport(p, p1); 3464 end 3465 end 3466 end; 3467 end; 3468 3469 { 3470 Internal Command Processing 3471 ____________________________________________________________________ 3472 } 3473 procedure IntServer(Command,Player,Subject:integer;var Data); 3474 var 3475 i,p1: integer; 3476 3477 begin 3478 if Mode=moPlaying then 3479 CL.Put(Command, Player, Subject, @Data); 3480 3481 case Command of 3482 3483 sIntTellAboutNation: 3484 begin 3485 {$IFDEF TEXTLOG}CmdInfo:=Format('IntTellAboutNation P%d+P%d', [Player,Subject]);{$ENDIF} 3486 assert((Player>=0) and (Player<nPl) and (Subject>=0) and (Subject<nPl)); 3487 IntroduceEnemy(Player,Subject); 3488 end; 3489 3490 sIntHaveContact: 3491 begin 3492 {$IFDEF TEXTLOG}CmdInfo:=Format('IntHaveContact P%d+P%d', [Player,Subject]);{$ENDIF} 3493 assert(RW[Player].Treaty[Subject]>trNoContact); 3494 RW[Player].EnemyReport[Subject].TurnOfContact:=GTurn; 3495 RW[Subject].EnemyReport[Player].TurnOfContact:=GTurn; 3496 end; 3497 3498 sIntCancelTreaty: 3499 begin 3500 {$IFDEF TEXTLOG}CmdInfo:=Format('IntCancelTreaty P%d with P%d', [Player,Subject]);{$ENDIF} 3501 CancelTreaty(Player,Subject); 3502 end; 3503 3504 (* sIntChoosePeace: 3505 begin 3506 {$IFDEF TEXTLOG}CmdInfo:=Format('IntChoosePeace P%d+P%d', [Player,Subject]);{$ENDIF} 3507 RW[Player].Treaty[Subject]:=trPeace; 3508 RW[Subject].Treaty[Player]:=trPeace; 3509 end;*) 3510 3511 sIntTellAboutModel..sIntTellAboutModel+(nPl-1) shl 4: 3512 begin 3513 p1:=(Command-sIntTellAboutModel) shr 4; // told player 3514 {$IFDEF TEXTLOG}CmdInfo:=Format('IntTellAboutModel P%d about P%d Mod%d', [p1,Player,Subject]);{$ENDIF} 3515 assert((Player>=0) and (Player<nPl)); 3516 assert((Subject>=0) and (Subject<RW[Player].nModel)); 3517 MakeModelInfo(Player,Subject,RW[Player].Model[Subject], 3518 RW[p1].EnemyModel[RW[p1].nEnemyModel]); 3519 RWemix[p1,Player,Subject]:=RW[p1].nEnemyModel; 3520 inc(RW[p1].nEnemyModel); 3521 assert(RW[p1].nEnemyModel<nemmax); 3522 end; 3523 3524 sIntDiscoverZOC: 3525 begin 3526 {$IFDEF TEXTLOG}CmdInfo:=Format('IntDiscoverZOC P%d Loc%d', [Player,integer(data)]);{$ENDIF} 3527 Discover9(integer(Data),Player,lObserveUnhidden,true,false); 3528 end; 3529 3530 sIntExpandTerritory: 3531 if Mode<moPlaying then 3532 begin 3533 {$IFDEF TEXTLOG}CmdInfo:=Format('IntExpandTerritory P%d Loc%d', [Player,RW[Player].City[Subject].Loc]);{$ENDIF} 3534 move(Data,BorderChanges,sizeof(BorderChanges)); 3535 ExpandTerritory(RW[Player].City[Subject].Loc); 3536 end; 3537 3538 sIntBuyMaterial: 3539 with RW[Player].City[Subject] do 3540 begin 3541 {$IFDEF TEXTLOG}CmdInfo:=Format('IntBuyMaterial P%d Loc%d Cost%d', [Player,Loc,integer(Data)]);{$ENDIF} 3542 dec(RW[Player].Money,integer(Data)); 3543 if (GWonder[woMich].EffectiveOwner=Player) and (Project and cpImp<>0) then 3544 inc(Prod,integer(Data) div 2) 3545 else inc(Prod,integer(Data) div 4); 3546 if Project0 and not cpAuto<>Project and not cpAuto then 3547 Project0:=Project; 3548 Prod0:=Prod; 3549 end; 3550 3551 sIntPayPrices..sIntPayPrices+12: 3552 begin 3553 {$IFDEF TEXTLOG}CmdInfo:=Format('IntPayPrices P%d+P%d', [Player,Subject]);{$ENDIF} 3554 for i:=0 to TOffer(Data).nDeliver-1 do 3555 PayPrice(Player,Subject,TOffer(Data).Price[i],true); 3556 for i:=0 to TOffer(Data).nCost-1 do 3557 PayPrice(Subject,Player,TOffer(Data).Price[TOffer(Data).nDeliver+i],true); 3558 for i:=0 to TOffer(Data).nDeliver+TOffer(Data).nCost-1 do 3559 if TOffer(Data).Price[i]=opTreaty+trAlliance then 3560 begin // add view area of allied player 3561 DiscoverViewAreas(Player); 3562 DiscoverViewAreas(Subject); 3563 break 3564 end 3565 end; 3566 3567 sIntSetDevModel: 3568 if Mode<moPlaying then 3569 move(Data, RW[Player].DevModel.Kind, sIntSetDevModel and $F *4); 3570 3571 sIntSetModelStatus: if ProcessClientData[Player] then 3572 begin 3573 {$IFDEF TEXTLOG}CmdInfo:=Format('IntSetModelStatus P%d', [Player]);{$ENDIF} 3574 RW[Player].Model[Subject].Status:=integer(Data); 3575 end; 3576 3577 sIntSetUnitStatus: if ProcessClientData[Player] then 3578 begin 3579 {$IFDEF TEXTLOG}CmdInfo:=Format('IntSetUnitStatus P%d', [Player]);{$ENDIF} 3580 RW[Player].Un[Subject].Status:=integer(Data); 3581 end; 3582 3583 sIntSetCityStatus: if ProcessClientData[Player] then 3584 begin 3585 {$IFDEF TEXTLOG}CmdInfo:=Format('IntSetCityStatus P%d', [Player]);{$ENDIF} 3586 RW[Player].City[Subject].Status:=integer(Data); 3587 end; 3588 3589 sIntSetECityStatus: if ProcessClientData[Player] then 3590 begin 3591 {$IFDEF TEXTLOG}CmdInfo:=Format('IntSetECityStatus P%d', [Player]);{$ENDIF} 3592 RW[Player].EnemyCity[Subject].Status:=integer(Data); 3593 end; 3594 3595 end;{case command} 3596 end;{IntServer} 3918 procedure IntServer(Command, Player, Subject: integer; var Data); 3919 var 3920 i, p1: integer; 3921 3922 begin 3923 if Mode = moPlaying then 3924 CL.Put(Command, Player, Subject, @Data); 3925 3926 case Command of 3927 3928 sIntTellAboutNation: 3929 begin 3930 {$IFDEF TEXTLOG}CmdInfo := Format('IntTellAboutNation P%d+P%d', [Player, Subject]); {$ENDIF} 3931 assert((Player >= 0) and (Player < nPl) and (Subject >= 0) and 3932 (Subject < nPl)); 3933 IntroduceEnemy(Player, Subject); 3934 end; 3935 3936 sIntHaveContact: 3937 begin 3938 {$IFDEF TEXTLOG}CmdInfo := Format('IntHaveContact P%d+P%d', [Player, Subject]); {$ENDIF} 3939 assert(RW[Player].Treaty[Subject] > trNoContact); 3940 RW[Player].EnemyReport[Subject].TurnOfContact := GTurn; 3941 RW[Subject].EnemyReport[Player].TurnOfContact := GTurn; 3942 end; 3943 3944 sIntCancelTreaty: 3945 begin 3946 {$IFDEF TEXTLOG}CmdInfo := Format('IntCancelTreaty P%d with P%d', [Player, Subject]); {$ENDIF} 3947 CancelTreaty(Player, Subject); 3948 end; 3949 3950 (* sIntChoosePeace: 3951 begin 3952 {$IFDEF TEXTLOG}CmdInfo:=Format('IntChoosePeace P%d+P%d', [Player,Subject]);{$ENDIF} 3953 RW[Player].Treaty[Subject]:=trPeace; 3954 RW[Subject].Treaty[Player]:=trPeace; 3955 end; *) 3956 3957 sIntTellAboutModel .. sIntTellAboutModel + (nPl - 1) shl 4: 3958 begin 3959 p1 := (Command - sIntTellAboutModel) shr 4; // told player 3960 {$IFDEF TEXTLOG}CmdInfo := Format('IntTellAboutModel P%d about P%d Mod%d', [p1, Player, Subject]); {$ENDIF} 3961 assert((Player >= 0) and (Player < nPl)); 3962 assert((Subject >= 0) and (Subject < RW[Player].nModel)); 3963 MakeModelInfo(Player, Subject, RW[Player].Model[Subject], 3964 RW[p1].EnemyModel[RW[p1].nEnemyModel]); 3965 RWemix[p1, Player, Subject] := RW[p1].nEnemyModel; 3966 inc(RW[p1].nEnemyModel); 3967 assert(RW[p1].nEnemyModel < nemmax); 3968 end; 3969 3970 sIntDiscoverZOC: 3971 begin 3972 {$IFDEF TEXTLOG}CmdInfo := Format('IntDiscoverZOC P%d Loc%d', [Player, integer(Data)]); {$ENDIF} 3973 Discover9(integer(Data), Player, lObserveUnhidden, true, false); 3974 end; 3975 3976 sIntExpandTerritory: 3977 if Mode < moPlaying then 3978 begin 3979 {$IFDEF TEXTLOG}CmdInfo := Format('IntExpandTerritory P%d Loc%d', [Player, RW[Player].City[Subject].Loc]); {$ENDIF} 3980 move(Data, BorderChanges, SizeOf(BorderChanges)); 3981 ExpandTerritory(RW[Player].City[Subject].Loc); 3982 end; 3983 3984 sIntBuyMaterial: 3985 with RW[Player].City[Subject] do 3986 begin 3987 {$IFDEF TEXTLOG}CmdInfo := Format('IntBuyMaterial P%d Loc%d Cost%d', [Player, Loc, integer(Data)]); {$ENDIF} 3988 dec(RW[Player].Money, integer(Data)); 3989 if (GWonder[woMich].EffectiveOwner = Player) and (Project and cpImp <> 0) 3990 then 3991 inc(Prod, integer(Data) div 2) 3992 else 3993 inc(Prod, integer(Data) div 4); 3994 if Project0 and not cpAuto <> Project and not cpAuto then 3995 Project0 := Project; 3996 Prod0 := Prod; 3997 end; 3998 3999 sIntPayPrices .. sIntPayPrices + 12: 4000 begin 4001 {$IFDEF TEXTLOG}CmdInfo := Format('IntPayPrices P%d+P%d', [Player, Subject]); {$ENDIF} 4002 for i := 0 to TOffer(Data).nDeliver - 1 do 4003 PayPrice(Player, Subject, TOffer(Data).Price[i], true); 4004 for i := 0 to TOffer(Data).nCost - 1 do 4005 PayPrice(Subject, Player, TOffer(Data).Price[TOffer(Data).nDeliver 4006 + i], true); 4007 for i := 0 to TOffer(Data).nDeliver + TOffer(Data).nCost - 1 do 4008 if TOffer(Data).Price[i] = opTreaty + trAlliance then 4009 begin // add view area of allied player 4010 DiscoverViewAreas(Player); 4011 DiscoverViewAreas(Subject); 4012 Break 4013 end 4014 end; 4015 4016 sIntSetDevModel: 4017 if Mode < moPlaying then 4018 move(Data, RW[Player].DevModel.Kind, sIntSetDevModel and $F * 4); 4019 4020 sIntSetModelStatus: 4021 if ProcessClientData[Player] then 4022 begin 4023 {$IFDEF TEXTLOG}CmdInfo := Format('IntSetModelStatus P%d', [Player]); 4024 {$ENDIF} 4025 RW[Player].Model[Subject].Status := integer(Data); 4026 end; 4027 4028 sIntSetUnitStatus: 4029 if ProcessClientData[Player] then 4030 begin 4031 {$IFDEF TEXTLOG}CmdInfo := Format('IntSetUnitStatus P%d', [Player]); 4032 {$ENDIF} 4033 RW[Player].Un[Subject].Status := integer(Data); 4034 end; 4035 4036 sIntSetCityStatus: 4037 if ProcessClientData[Player] then 4038 begin 4039 {$IFDEF TEXTLOG}CmdInfo := Format('IntSetCityStatus P%d', [Player]); 4040 {$ENDIF} 4041 RW[Player].City[Subject].Status := integer(Data); 4042 end; 4043 4044 sIntSetECityStatus: 4045 if ProcessClientData[Player] then 4046 begin 4047 {$IFDEF TEXTLOG}CmdInfo := Format('IntSetECityStatus P%d', [Player]); 4048 {$ENDIF} 4049 RW[Player].EnemyCity[Subject].Status := integer(Data); 4050 end; 4051 4052 end; { case command } 4053 end; { IntServer } 3597 4054 3598 4055 end. 3599 -
trunk/Direct.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit Direct; 4 3 … … 11 10 12 11 const 13 WM_GO = WM_USER;14 WM_CHANGECLIENT = WM_USER+1; // hand over control to other client15 WM_NEXTPLAYER = WM_USER+2; // active player's turn ended, next player16 WM_AIEXCEPTION = WM_USER+3;12 WM_GO = WM_USER; 13 WM_CHANGECLIENT = WM_USER + 1; // hand over control to other client 14 WM_NEXTPLAYER = WM_USER + 2; // active player's turn ended, next player 15 WM_AIEXCEPTION = WM_USER + 3; 17 16 18 17 type … … 30 29 procedure SetInfo(x: string); 31 30 procedure SetState(x: integer); 32 procedure OnGo(var m: TMessage); message WM_GO;33 procedure OnChangeClient(var m: TMessage); message WM_CHANGECLIENT;34 procedure OnNextPlayer(var m: TMessage); message WM_NEXTPLAYER;35 procedure OnAIException(var Msg: TMessage); message WM_AIEXCEPTION;31 procedure OnGo(var m: TMessage); message WM_GO; 32 procedure OnChangeClient(var m: TMessage); message WM_CHANGECLIENT; 33 procedure OnNextPlayer(var m: TMessage); message WM_NEXTPLAYER; 34 procedure OnAIException(var Msg: TMessage); message WM_AIEXCEPTION; 36 35 end; 37 36 … … 42 41 43 42 uses 44 ScreenTools,Protocol,GameServer,Start,LocalPlayer,NoTerm,Back,ShellAPI;43 ScreenTools, Protocol, GameServer, Start, LocalPlayer, NoTerm, Back, ShellAPI; 45 44 46 45 {$R *.DFM} … … 48 47 procedure Notify(ID: integer); 49 48 begin 50 DirectDlg.DlgNotify(ID);49 DirectDlg.DlgNotify(ID); 51 50 end; 52 51 53 52 procedure TDirectDlg.DlgNotify(ID: integer); 54 53 var 55 hMem: Cardinal; 56 p: pointer; 57 s: string; 58 begin 59 case ID of 60 ntInitLocalHuman: 54 hMem: Cardinal; 55 p: pointer; 56 s: string; 57 begin 58 case ID of 59 ntInitLocalHuman: 60 begin 61 SetMainTextureByAge(-1); 62 State := -1; 63 Info := Phrases.Lookup('BUSY_MODLH'); 64 Show; 65 Invalidate; 66 Update; 67 end; 68 ntInitModule .. ntInitModule + maxBrain - 1: 69 if visible then 70 begin 71 s := Format(Phrases.Lookup('BUSY_MOD'), 72 [Brain[ID - ntInitModule].Name]); 73 while BiColorTextWidth(Canvas, s) + 64 > ClientWidth do 74 Delete(s, Length(s), 1); 75 SetInfo(s); 76 end; 77 ntCreateWorld: 78 if visible then 79 SetInfo(Phrases.Lookup('BUSY_START')); 80 ntInitPlayers: 81 if visible then 82 SetInfo(Phrases.Lookup('BUSY_INIT')); 83 ntDeactivationMissing .. ntDeactivationMissing + nPl - 1: 84 SimpleMessage(Format(Phrases.Lookup('MISSDEACT'), 85 [ID - ntDeactivationMissing])); 86 ntSetAIName .. ntSetAIName + nPl - 1: 87 LocalPlayer.SetAIName(ID - ntSetAIName, NotifyMessage); 88 ntException .. ntException + maxBrain - 1: 89 PostMessage(Handle, WM_AIEXCEPTION, ID - ntException, 0); 90 ntLoadBegin: 91 begin 92 Info := Phrases.Lookup('BUSY_LOAD'); 93 SetState(0); 94 end; 95 ntLoadState .. ntLoadState + 128: 96 SetState(ID - ntLoadState); 97 ntDLLError .. ntDLLError + 128: 98 SimpleMessage(Format(Phrases.Lookup('DLLERROR'), 99 [Brain[ID - ntDLLError].FileName])); 100 ntAIError: 101 SimpleMessage(Format(Phrases.Lookup('AIERROR'), [NotifyMessage])); 102 ntClientError .. ntClientError + 128: 103 SimpleMessage(Format(Phrases.Lookup('CLIENTERROR'), 104 [Brain[ID - ntClientError].FileName])); 105 ntEndInfo: 106 begin 107 Hide; 108 background.Update 109 end; 110 ntLoadError: 111 begin 112 if OpenClipboard(Handle) then 113 begin // copy file path to clipboard 114 NotifyMessage := NotifyMessage + #0; 115 hMem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, 116 Length(NotifyMessage)); 117 p := GlobalLock(hMem); 118 if p <> nil then 119 move(NotifyMessage[1], p^, Length(NotifyMessage)); 120 GlobalUnlock(hMem); 121 SetClipboardData(CF_TEXT, hMem); 122 CloseClipboard; 123 end; 124 with MessgDlg do 125 begin 126 MessgText := Phrases.Lookup('LOADERROR'); 127 Kind := mkYesNo; 128 ShowModal; 129 if ModalResult = mrOK then 130 ShellExecute(Handle, 'open', 131 'http://c-evo.org/_sg/contact/cevobug.html', '', '', 132 SW_SHOWNORMAL); 133 end 134 end; 135 ntStartDone: 136 if not Quick then 137 begin 138 StartDlg.Hide; 139 background.Update 140 end; 141 ntStartGo, ntStartGoRefresh, ntStartGoRefreshMaps: 142 if Quick then 143 Close 144 else 145 begin 146 if ID = ntStartGoRefresh then 147 StartDlg.UpdateFormerGames 148 else if ID = ntStartGoRefreshMaps then 149 StartDlg.UpdateMaps; 150 StartDlg.Show; 151 end; 152 ntChangeClient: 153 PostMessage(Handle, WM_CHANGECLIENT, 0, 0); 154 ntNextPlayer: 155 PostMessage(Handle, WM_NEXTPLAYER, 0, 0); 156 ntDeinitModule .. ntDeinitModule + maxBrain - 1: 157 begin 158 Info := Format(Phrases2.Lookup('BUSY_DEINIT'), 159 [Brain[ID - ntDeinitModule].Name]); 160 while BiColorTextWidth(Canvas, Info) + 64 > ClientWidth do 161 Delete(Info, Length(Info), 1); 162 SetMainTextureByAge(-1); 163 State := -1; 164 Show; 165 Invalidate; 166 Update; 167 end; 168 ntBackOn: 169 begin 170 background.Show; 171 background.Update; 172 sleep(50); // prevent flickering 173 end; 174 ntBackOff: 175 background.Close; 176 end; 177 end; 178 179 procedure TDirectDlg.FormCreate(Sender: TObject); 180 begin 181 Gone := false; 182 State := -1; 183 Info := ''; 184 GameServer.Init(Notify); 185 Brain[bixNoTerm].Client := NoTerm.Client; 186 Brain[bixSuper_Virtual].Client := nil; 187 Brain[bixTerm].Client := LocalPlayer.Client; 188 Brain[bixNoTerm].Name := Phrases.Lookup('AIT'); 189 Brain[bixSuper_Virtual].Name := Phrases.Lookup('SUPER'); 190 Brain[bixTerm].Name := Phrases.Lookup('HUMAN'); 191 Brain[bixRandom].Name := Phrases.Lookup('RANDOMAI'); 192 Canvas.Font.Assign(UniFont[ftNormal]); 193 Canvas.Brush.Style := bsClear; 194 end; 195 196 procedure TDirectDlg.FormShow(Sender: TObject); 197 begin 198 if not Gone then 199 begin 200 PostMessage(Handle, WM_GO, 0, 0); 201 Gone := true 202 end 203 end; 204 205 procedure TDirectDlg.FormClose(Sender: TObject; var Action: TCloseAction); 206 begin 207 GameServer.Done; 208 end; 209 210 procedure TDirectDlg.OnGo(var m: TMessage); 211 var 212 i: integer; 213 s: string; 214 begin 215 Hide; 216 if nBrain = 3 then 217 begin 218 Application.MessageBox(PChar(Phrases.Lookup('NOAI')), 'C-evo', 0); 219 Close; 220 exit 221 end; 222 Quick := false; 223 if ParamCount > 0 then 224 begin 225 s := ParamStr(1); 226 if (s[1] = '-') or (s[1] = '/') then 227 begin // special mode 228 Delete(s, 1, 1); 229 for i := 1 to Length(s) do 230 if s[i] in ['a' .. 'z'] then 231 dec(s[i], 32); 232 if s = 'MAN' then 233 begin 234 Quick := true; 235 DirectHelp(cHelpOnly); 236 Close 237 end; 238 end 239 else if (FileExists(ParamStr(1))) then 61 240 begin 62 SetMainTextureByAge(-1); 63 State:=-1; 64 Info:=Phrases.Lookup('BUSY_MODLH'); 65 Show; Invalidate; Update; 66 end; 67 ntInitModule..ntInitModule+maxBrain-1: 68 if visible then 69 begin 70 s:=Format(Phrases.Lookup('BUSY_MOD'),[Brain[ID-ntInitModule].Name]); 71 while BiColorTextWidth(Canvas,s)+64>ClientWidth do Delete(s,Length(s),1); 72 SetInfo(s); 73 end; 74 ntCreateWorld: 75 if visible then SetInfo(Phrases.Lookup('BUSY_START')); 76 ntInitPlayers: 77 if visible then SetInfo(Phrases.Lookup('BUSY_INIT')); 78 ntDeactivationMissing..ntDeactivationMissing+nPl-1: 79 SimpleMessage(Format(Phrases.Lookup('MISSDEACT'),[ID-ntDeactivationMissing])); 80 ntSetAIName..ntSetAIName+nPl-1: 81 LocalPlayer.SetAIName(ID-ntSetAIName, NotifyMessage); 82 ntException..ntException+maxBrain-1: 83 PostMessage(Handle,WM_AIEXCEPTION,ID-ntException,0); 84 ntLoadBegin: 85 begin Info:=Phrases.Lookup('BUSY_LOAD'); SetState(0); end; 86 ntLoadState..ntLoadState+128: 87 SetState(ID-ntLoadState); 88 ntDLLError..ntDLLError+128: 89 SimpleMessage(Format(Phrases.Lookup('DLLERROR'),[Brain[ID-ntDLLError].FileName])); 90 ntAIError: 91 SimpleMessage(Format(Phrases.Lookup('AIERROR'),[NotifyMessage])); 92 ntClientError..ntClientError+128: 93 SimpleMessage(Format(Phrases.Lookup('CLIENTERROR'),[Brain[ID-ntClientError].FileName])); 94 ntEndInfo: 95 begin Hide; background.update end; 96 ntLoadError: 97 begin 98 if OpenClipboard(Handle) then 99 begin // copy file path to clipboard 100 NotifyMessage:=NotifyMessage+#0; 101 hMem:=GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, Length(NotifyMessage)); 102 p:=GlobalLock(hMem); 103 if p<>nil then 104 move(NotifyMessage[1],p^,Length(NotifyMessage)); 105 GlobalUnlock(hMem); 106 SetClipboardData(CF_TEXT, hMem); 107 CloseClipboard; 108 end; 109 with MessgDlg do 110 begin 111 MessgText:=Phrases.Lookup('LOADERROR'); 112 Kind:=mkYesNo; 113 ShowModal; 114 if ModalResult=mrOK then 115 ShellExecute(Handle,'open','http://c-evo.org/_sg/contact/cevobug.html', 116 '','',SW_SHOWNORMAL); 117 end 118 end; 119 ntStartDone: 120 if not Quick then 121 begin StartDlg.Hide; background.Update end; 122 ntStartGo, ntStartGoRefresh, ntStartGoRefreshMaps: 123 if Quick then Close 124 else 125 begin 126 if ID=ntStartGoRefresh then 127 StartDlg.UpdateFormerGames 128 else if ID=ntStartGoRefreshMaps then 129 StartDlg.UpdateMaps; 130 StartDlg.Show; 131 end; 132 ntChangeClient: 133 PostMessage(Handle,WM_CHANGECLIENT,0,0); 134 ntNextPlayer: 135 PostMessage(Handle,WM_NEXTPLAYER,0,0); 136 ntDeinitModule..ntDeinitModule+maxBrain-1: 137 begin 138 Info:=Format(Phrases2.Lookup('BUSY_DEINIT'), 139 [Brain[ID-ntDeinitModule].Name]); 140 while BiColorTextWidth(Canvas,Info)+64>ClientWidth do 141 Delete(Info,Length(Info),1); 142 SetMainTextureByAge(-1); 143 State:=-1; 144 Show; 145 Invalidate; 146 Update; 147 end; 148 ntBackOn: 149 begin 150 background.Show; 151 background.update; 152 sleep(50); // prevent flickering 153 end; 154 ntBackOff: 155 background.Close; 156 end; 157 end; 158 159 procedure TDirectDlg.FormCreate(Sender: TObject); 160 begin 161 Gone:=false; 162 State:=-1; 163 Info:=''; 164 GameServer.Init(Notify); 165 Brain[bixNoTerm].Client:=NoTerm.Client; 166 Brain[bixSuper_Virtual].Client:=nil; 167 Brain[bixTerm].Client:=LocalPlayer.Client; 168 Brain[bixNoTerm].Name:=Phrases.Lookup('AIT'); 169 Brain[bixSuper_Virtual].Name:=Phrases.Lookup('SUPER'); 170 Brain[bixTerm].Name:=Phrases.Lookup('HUMAN'); 171 Brain[bixRandom].name:=Phrases.Lookup('RANDOMAI'); 172 Canvas.Font.Assign(UniFont[ftNormal]); 173 Canvas.Brush.Style:=bsClear; 174 end; 175 176 procedure TDirectDlg.FormShow(Sender: TObject); 177 begin 178 if not Gone then 179 begin PostMessage(Handle,WM_GO,0,0); Gone:=true end 180 end; 181 182 procedure TDirectDlg.FormClose(Sender: TObject; var Action: TCloseAction); 183 begin 184 GameServer.Done; 185 end; 186 187 procedure TDirectDlg.OnGo(var m:TMessage); 188 var 189 i: integer; 190 s: string; 191 begin 192 Hide; 193 if nBrain=3 then 194 begin 195 Application.MessageBox(PChar(Phrases.Lookup('NOAI')), 'C-evo', 0); 196 close; 197 exit 198 end; 199 Quick:=false; 200 if ParamCount>0 then 201 begin 202 s:=ParamStr(1); 203 if (s[1]='-') or (s[1]='/') then 204 begin // special mode 205 Delete(s,1,1); 206 for i:=1 to Length(s) do if s[i] in ['a'..'z'] then dec(s[i],32); 207 if s='MAN' then 208 begin Quick:=true; DirectHelp(cHelpOnly); Close end; 209 end 210 else if (FileExists(ParamStr(1))) then 211 begin 212 Quick:=true; 213 if not LoadGame(ExtractFilePath(ParamStr(1)),ExtractFileName(ParamStr(1)),-1,false) then 214 begin 215 SimpleMessage(Phrases.Lookup('LOADERR')); 216 Close 241 Quick := true; 242 if not LoadGame(ExtractFilePath(ParamStr(1)), ExtractFileName(ParamStr(1) 243 ), -1, false) then 244 begin 245 SimpleMessage(Phrases.Lookup('LOADERR')); 246 Close 217 247 end 218 248 end 219 249 end; 220 if not Quick then 221 begin background.Show; StartDlg.Show end 222 end; 223 224 procedure TDirectDlg.OnChangeClient(var m:TMessage); 225 begin 226 ChangeClient; 227 end; 228 229 procedure TDirectDlg.OnNextPlayer(var m:TMessage); 230 begin 231 NextPlayer; 232 end; 233 234 procedure TDirectDlg.OnAIException(var Msg:TMessage); 235 begin 236 Application.MessageBox(PChar(Format(Phrases.Lookup('AIEXCEPTION'), 237 [Brain[Msg.WParam].Name])), 'C-evo', 0); 250 if not Quick then 251 begin 252 background.Show; 253 StartDlg.Show 254 end 255 end; 256 257 procedure TDirectDlg.OnChangeClient(var m: TMessage); 258 begin 259 ChangeClient; 260 end; 261 262 procedure TDirectDlg.OnNextPlayer(var m: TMessage); 263 begin 264 NextPlayer; 265 end; 266 267 procedure TDirectDlg.OnAIException(var Msg: TMessage); 268 begin 269 Application.MessageBox(PChar(Format(Phrases.Lookup('AIEXCEPTION'), 270 [Brain[Msg.WParam].Name])), 'C-evo', 0); 238 271 end; 239 272 240 273 procedure TDirectDlg.FormPaint(Sender: TObject); 241 274 begin 242 PaintBackground(self,3,3,ClientWidth-6,ClientHeight-6); 243 Frame(Canvas,0,0,ClientWidth-1,ClientHeight-1,0,0); 244 Frame(Canvas,1,1,ClientWidth-2,ClientHeight-2,MainTexture.clBevelLight, 245 MainTexture.clBevelShade); 246 Frame(Canvas,2,2,ClientWidth-3,ClientHeight-3,MainTexture.clBevelLight, 247 MainTexture.clBevelShade); 248 if State>=0 then 249 RisedTextOut(Canvas,(ClientWidth-BiColorTextWidth(Canvas,Info)) div 2,16,Info) 250 else RisedTextOut(Canvas,(ClientWidth-BiColorTextWidth(Canvas,Info)) div 2, 251 (ClientHeight-Canvas.TextHeight(Info)) div 2,Info); 252 if State>=0 then 253 PaintProgressBar(Canvas,3,ClientWidth div 2 -64,40,State,0,128,MainTexture); 275 PaintBackground(self, 3, 3, ClientWidth - 6, ClientHeight - 6); 276 Frame(Canvas, 0, 0, ClientWidth - 1, ClientHeight - 1, 0, 0); 277 Frame(Canvas, 1, 1, ClientWidth - 2, ClientHeight - 2, 278 MainTexture.clBevelLight, MainTexture.clBevelShade); 279 Frame(Canvas, 2, 2, ClientWidth - 3, ClientHeight - 3, 280 MainTexture.clBevelLight, MainTexture.clBevelShade); 281 if State >= 0 then 282 RisedTextOut(Canvas, (ClientWidth - BiColorTextWidth(Canvas, Info)) 283 div 2, 16, Info) 284 else 285 RisedTextOut(Canvas, (ClientWidth - BiColorTextWidth(Canvas, Info)) div 2, 286 (ClientHeight - Canvas.TextHeight(Info)) div 2, Info); 287 if State >= 0 then 288 PaintProgressBar(Canvas, 3, ClientWidth div 2 - 64, 40, State, 0, 128, 289 MainTexture); 254 290 end; 255 291 256 292 procedure TDirectDlg.SetInfo(x: string); 257 293 begin 258 Info:=x;259 Invalidate;260 Update;294 Info := x; 295 Invalidate; 296 Update; 261 297 end; 262 298 263 299 procedure TDirectDlg.SetState(x: integer); 264 300 begin 265 if (x<0)<>(State<0) then 266 begin State:=x; Invalidate; Update end 267 else if x<>State then 268 begin 269 State:=x; 270 PaintProgressBar(Canvas,6,ClientWidth div 2 -64,40,State,128-State,128,MainTexture); 301 if (x < 0) <> (State < 0) then 302 begin 303 State := x; 304 Invalidate; 305 Update 271 306 end 307 else if x <> State then 308 begin 309 State := x; 310 PaintProgressBar(Canvas, 6, ClientWidth div 2 - 64, 40, State, 128 - State, 311 128, MainTexture); 312 end 272 313 end; 273 314 274 315 end. 275 -
trunk/Directories.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit Directories; 4 3 … … 6 5 7 6 var 8 HomeDir, DataDir: string;7 HomeDir, DataDir: string; 9 8 10 9 function LocalizedFilePath(path: string): string; 11 12 10 13 11 implementation 14 12 15 13 uses 16 ShlObj,Windows,SysUtils;14 ShlObj, Windows, SysUtils; 17 15 18 16 function GetSpecialDirectory(const CSIDL: integer): string; 19 17 var 20 RecPath: PChar;18 RecPath: PChar; 21 19 begin 22 RecPath:=StrAlloc(MAX_PATH); 23 try 24 FillChar(RecPath^, MAX_PATH, 0); 25 if SHGetSpecialFolderPath(0, RecPath, CSIDL, false) then 26 result:=RecPath 27 else result:=''; 28 finally 29 StrDispose(RecPath); 20 RecPath := StrAlloc(MAX_PATH); 21 try 22 FillChar(RecPath^, MAX_PATH, 0); 23 if SHGetSpecialFolderPath(0, RecPath, CSIDL, false) then 24 result := RecPath 25 else 26 result := ''; 27 finally 28 StrDispose(RecPath); 30 29 end 31 30 end; … … 33 32 function DirectoryExists(path: string): boolean; 34 33 var 35 f: TSearchRec;34 f: TSearchRec; 36 35 begin 37 result:=FindFirst(path,faDirectory,f)=0;36 result := FindFirst(path, faDirectory, f) = 0; 38 37 end; 39 38 40 39 function LocalizedFilePath(path: string): string; 41 40 begin 42 result:=DataDir+'Localization\'+path;43 if not FileExists(result) then44 result:=HomeDir+path41 result := DataDir + 'Localization\' + path; 42 if not FileExists(result) then 43 result := HomeDir + path 45 44 end; 46 45 47 48 46 var 49 AppDataDir: string;50 src,dst: TSearchRec;47 AppDataDir: string; 48 src, dst: TSearchRec; 51 49 52 50 initialization 53 HomeDir:=ExtractFilePath(ParamStr(0));54 51 52 HomeDir := ExtractFilePath(ParamStr(0)); 55 53 56 AppDataDir :=GetSpecialDirectory(CSIDL_APPDATA);57 if AppDataDir ='' then58 DataDir :=HomeDir54 AppDataDir := GetSpecialDirectory(CSIDL_APPDATA); 55 if AppDataDir = '' then 56 DataDir := HomeDir 59 57 else 60 begin61 if not DirectoryExists(AppDataDir +'\C-evo') then62 CreateDir(AppDataDir +'\C-evo');63 DataDir :=AppDataDir+'\C-evo\';64 end;65 if not DirectoryExists(DataDir +'Saved') then66 CreateDir(DataDir +'Saved');67 if not DirectoryExists(DataDir +'Maps') then68 CreateDir(DataDir +'Maps');58 begin 59 if not DirectoryExists(AppDataDir + '\C-evo') then 60 CreateDir(AppDataDir + '\C-evo'); 61 DataDir := AppDataDir + '\C-evo\'; 62 end; 63 if not DirectoryExists(DataDir + 'Saved') then 64 CreateDir(DataDir + 'Saved'); 65 if not DirectoryExists(DataDir + 'Maps') then 66 CreateDir(DataDir + 'Maps'); 69 67 70 68 // copy appdata if not done yet 71 if FindFirst(HomeDir +'AppData\Saved\*.cevo',$21,src)=0 then69 if FindFirst(HomeDir + 'AppData\Saved\*.cevo', $21, src) = 0 then 72 70 repeat 73 if (FindFirst(DataDir+'Saved\'+src.Name,$21,dst)<>0) 74 or (dst.Time<src.Time) then 75 CopyFile(PChar(HomeDir+'AppData\Saved\'+src.Name), 76 PChar(DataDir+'Saved\'+src.Name),false); 77 until FindNext(src)<>0; 71 if (FindFirst(DataDir + 'Saved\' + src.Name, $21, dst) <> 0) or 72 (dst.Time < src.Time) then 73 CopyFile(PChar(HomeDir + 'AppData\Saved\' + src.Name), 74 PChar(DataDir + 'Saved\' + src.Name), false); 75 until FindNext(src) <> 0; 76 78 77 end. -
trunk/GameServer.pas
r2 r6 1 1 {$INCLUDE switches} 2 // {$DEFINE TEXTLOG}3 // {$DEFINE LOADPERF}2 // {$DEFINE TEXTLOG} 3 // {$DEFINE LOADPERF} 4 4 unit GameServer; 5 5 … … 7 7 8 8 uses 9 Protocol, Database;9 Protocol, Database; 10 10 11 11 const 12 Version=$010200; 13 FirstAICompatibleVersion=$000D00; 14 FirstBookCompatibleVersion=$010103; 15 16 // notifications 17 ntCreateWorld=0; ntInitModule=$100; ntInitLocalHuman=$1FF; 18 ntDLLError=$200; ntAIError=$2FF; 19 ntClientError=$300; 20 ntInitPlayers=$400; ntDeactivationMissing=$410; 21 ntSetAIName=$420; 22 ntException=$500; 23 ntLoadBegin=$600; ntLoadState=$601; 24 ntEndInfo=$6FC; ntBackOn=$6FD; ntBackOff=$6FE; ntLoadError=$6FF; 25 ntStartDone=$700; ntStartGo=$701; ntStartGoRefresh=$702; 26 ntStartGoRefreshMaps=$703; 27 ntChangeClient=$800; ntNextPlayer=$810; 28 ntDeinitModule=$900; 29 30 // module flags 31 fMultiple=$10000000; fDotNet=$20000000; fUsed=$40000000; 32 33 // save map tile flags 34 smOwned=$20; smUnit=$40; smCity=$80; 35 36 maxBrain=255; 37 bixNoTerm=0; bixSuper_Virtual=1; bixTerm=2; bixRandom=3; bixFirstAI=4; 12 Version = $010200; 13 FirstAICompatibleVersion = $000D00; 14 FirstBookCompatibleVersion = $010103; 15 16 // notifications 17 ntCreateWorld = 0; 18 ntInitModule = $100; 19 ntInitLocalHuman = $1FF; 20 ntDLLError = $200; 21 ntAIError = $2FF; 22 ntClientError = $300; 23 ntInitPlayers = $400; 24 ntDeactivationMissing = $410; 25 ntSetAIName = $420; 26 ntException = $500; 27 ntLoadBegin = $600; 28 ntLoadState = $601; 29 ntEndInfo = $6FC; 30 ntBackOn = $6FD; 31 ntBackOff = $6FE; 32 ntLoadError = $6FF; 33 ntStartDone = $700; 34 ntStartGo = $701; 35 ntStartGoRefresh = $702; 36 ntStartGoRefreshMaps = $703; 37 ntChangeClient = $800; 38 ntNextPlayer = $810; 39 ntDeinitModule = $900; 40 41 // module flags 42 fMultiple = $10000000; 43 fDotNet = $20000000; 44 fUsed = $40000000; 45 46 // save map tile flags 47 smOwned = $20; 48 smUnit = $40; 49 smCity = $80; 50 51 maxBrain = 255; 52 bixNoTerm = 0; 53 bixSuper_Virtual = 1; 54 bixTerm = 2; 55 bixRandom = 3; 56 bixFirstAI = 4; 38 57 39 58 type 40 TNotifyFunction = procedure(ID: integer); 41 42 TBrainInfo= record 43 FileName, DLLName, Name, Credits: string; {filename and full name} 44 hm, {module handle} 45 Flags, 46 ServerVersion, 47 DataVersion, DataSize: integer; 48 Client: TClientCall; {client function address} 49 Initialized: boolean; 59 TNotifyFunction = procedure(ID: integer); 60 61 TBrainInfo = record 62 FileName, DLLName, Name, Credits: string; { filename and full name } 63 hm, { module handle } 64 Flags, ServerVersion, DataVersion, DataSize: integer; 65 Client: TClientCall; { client function address } 66 Initialized: boolean; 50 67 end; 51 68 52 69 var 53 // PARAMETERS 54 bixView: array[0..nPl-1]of integer; {brain index of the players} 55 Difficulty: array[0..nPl-1]of integer absolute Database.Difficulty; {difficulty} 56 57 // READ ONLY 58 DotNetClient: TClientCall; 59 bixBeginner, // AI to use for beginner level 60 nBrain: integer; {number of brains available} 61 Brain: array[-1..maxBrain-1] of TBrainInfo; {available brains} 62 NotifyMessage: string; 70 // PARAMETERS 71 bixView: array [0 .. nPl - 1] of integer; { brain index of the players } 72 Difficulty: array [0 .. nPl - 1] of integer absolute Database.Difficulty; 73 { difficulty } 74 75 // READ ONLY 76 DotNetClient: TClientCall; 77 bixBeginner, // AI to use for beginner level 78 nBrain: integer; { number of brains available } 79 Brain: array [-1 .. maxBrain - 1] of TBrainInfo; { available brains } 80 NotifyMessage: string; 63 81 64 82 procedure Init(NotifyFunction: TNotifyFunction); 65 83 procedure Done; 66 84 67 procedure StartNewGame(const Path, FileName, Map: string; Newlx, Newly, 68 NewLandMass, NewMaxTurn: integer); 69 function LoadGame(const Path, FileName: string; Turn: integer; MovieMode: boolean): boolean; 85 procedure StartNewGame(const Path, FileName, Map: string; 86 Newlx, Newly, NewLandMass, NewMaxTurn: integer); 87 function LoadGame(const Path, FileName: string; Turn: integer; 88 MovieMode: boolean): boolean; 70 89 procedure EditMap(const Map: string; Newlx, Newly, NewLandMass: integer); 71 90 procedure DirectHelp(Command: integer); … … 75 94 function PreviewMap(lm: integer): pointer; 76 95 77 78 96 implementation 79 97 80 98 uses 81 Directories, CityProcessing, UnitProcessing, CmdList, 82 83 Windows,Classes,SysUtils; 84 99 Directories, CityProcessing, UnitProcessing, CmdList, 100 101 Windows, Classes, SysUtils; 85 102 86 103 var 87 MaxTurn, 88 LoadTurn, {turn where to stop loading} 89 nLogOpened, {nLog of opened book} 90 {$IFOPT O-}nHandoverStack,{$ENDIF} 91 LastEndClientCommand, 92 pContacted, // player contacted for negotiation 93 pDipActive, // player who's to speak in a negotiation 94 pTurn, {player who's turn it is} 95 GWinner, 96 GColdWarStart, 97 GStealFrom, 98 SpyMission, 99 ZOCTile, 100 CCCommand, 101 CCPlayer: integer; 102 DebugMap: array[0..nPl-1] of pointer; 103 ExeInfo: TSearchRec; 104 Stat: array[0..nStat-1, 0..nPl-1] of ^TChart; 105 AutoSaveState: TCmdListState; 106 MapField: ^Cardinal; // predefined map 107 LastOffer: TOffer; 108 CCData: array[0..14] of integer; 109 DevModelTurn, {turn of last call to sResetModel} 110 bix, {brain index of the players} 111 OriginalDataVersion: array[0..nPl-1] of integer; 112 SavedTiles{, SavedResourceWeights}: array[0..ncmax-1] of cardinal; 113 SavedData: array[0..nPl-1] of pointer; 114 LogFileName, SavePath, {name of file for saving the current game} 115 MapFileName, // name of map to use, empty for random 116 AICredits: string; 117 AIInfo: array[0..nPl-1] of string; 118 Notify: TNotifyFunction; 119 PerfFreq, LastClientTime: int64; 120 {$IFOPT O-}HandoverStack: array[0..31] of Cardinal;{$ENDIF} 121 AutoSaveExists, 122 LoadOK, WinOnAlone, PreviewElevation, MovieStopped: boolean; 104 MaxTurn, LoadTurn, { turn where to stop loading } 105 nLogOpened, { nLog of opened book } 106 {$IFOPT O-}nHandoverStack, {$ENDIF} 107 LastEndClientCommand, pContacted, // player contacted for negotiation 108 pDipActive, // player who's to speak in a negotiation 109 pTurn, { player who's turn it is } 110 GWinner, GColdWarStart, GStealFrom, SpyMission, ZOCTile, CCCommand, 111 CCPlayer: integer; 112 DebugMap: array [0 .. nPl - 1] of pointer; 113 ExeInfo: TSearchRec; 114 Stat: array [0 .. nStat - 1, 0 .. nPl - 1] of ^TChart; 115 AutoSaveState: TCmdListState; 116 MapField: ^Cardinal; // predefined map 117 LastOffer: TOffer; 118 CCData: array [0 .. 14] of integer; 119 DevModelTurn, { turn of last call to sResetModel } 120 bix, { brain index of the players } 121 OriginalDataVersion: array [0 .. nPl - 1] of integer; 122 SavedTiles { , SavedResourceWeights } : array [0 .. ncmax - 1] of Cardinal; 123 SavedData: array [0 .. nPl - 1] of pointer; 124 LogFileName, SavePath, { name of file for saving the current game } 125 MapFileName, // name of map to use, empty for random 126 AICredits: string; 127 AIInfo: array [0 .. nPl - 1] of string; 128 Notify: TNotifyFunction; 129 PerfFreq, LastClientTime: int64; 130 {$IFOPT O-}HandoverStack: array [0 .. 31] of Cardinal; {$ENDIF} 131 AutoSaveExists, LoadOK, WinOnAlone, PreviewElevation, MovieStopped: boolean; 123 132 124 133 const 125 PreviewRND=41601260; {randseed for preview map}126 127 function Server(Command, Player,Subject:integer;var Data): integer; stdcall; forward;128 129 130 procedure CallPlayer(Command, p: integer; var Data);134 PreviewRND = 41601260; { randseed for preview map } 135 136 function Server(Command, Player, Subject: integer; var Data): integer; 137 stdcall; forward; 138 139 procedure CallPlayer(Command, p: integer; var Data); 131 140 begin 132 if ((Mode<>moMovie) or (p=0)) then141 if ((Mode <> moMovie) or (p = 0)) then 133 142 begin 134 {$IFOPT O-}135 HandoverStack[nHandoverStack]:=p;136 HandoverStack[nHandoverStack+1]:=Command;137 inc(nHandoverStack,2);138 Brain[bix[p]].Client(Command,p,Data);139 dec(nHandoverStack,2);140 {$ELSE}141 try142 Brain[bix[p]].Client(Command,p,Data);143 except144 Notify(ntException+bix[p]);143 {$IFOPT O-} 144 HandoverStack[nHandoverStack] := p; 145 HandoverStack[nHandoverStack + 1] := Command; 146 inc(nHandoverStack, 2); 147 Brain[bix[p]].Client(Command, p, Data); 148 dec(nHandoverStack, 2); 149 {$ELSE} 150 try 151 Brain[bix[p]].Client(Command, p, Data); 152 except 153 Notify(ntException + bix[p]); 145 154 end; 146 {$ENDIF}155 {$ENDIF} 147 156 end 148 157 end; 149 158 150 procedure CallClient(bix, Command: integer; var Data);159 procedure CallClient(bix, Command: integer; var Data); 151 160 begin 152 if ((Mode<>moMovie) or (bix=GameServer.bix[0])) then161 if ((Mode <> moMovie) or (bix = GameServer.bix[0])) then 153 162 begin 154 {$IFOPT O-}155 HandoverStack[nHandoverStack]:=bix;156 HandoverStack[nHandoverStack+1]:=Command;157 inc(nHandoverStack,2);158 Brain[bix].Client(Command,-1,Data);159 dec(nHandoverStack,2);160 {$ELSE}161 try162 Brain[bix].Client(Command,-1,Data);163 except164 Notify(ntException+bix);163 {$IFOPT O-} 164 HandoverStack[nHandoverStack] := bix; 165 HandoverStack[nHandoverStack + 1] := Command; 166 inc(nHandoverStack, 2); 167 Brain[bix].Client(Command, -1, Data); 168 dec(nHandoverStack, 2); 169 {$ELSE} 170 try 171 Brain[bix].Client(Command, -1, Data); 172 except 173 Notify(ntException + bix); 165 174 end; 166 {$ENDIF}175 {$ENDIF} 167 176 end 168 177 end; … … 170 179 procedure Init(NotifyFunction: TNotifyFunction); 171 180 var 172 i: integer;173 f: TSearchRec;174 T: TextFile;175 s: string;181 i: integer; 182 f: TSearchRec; 183 T: TextFile; 184 s: string; 176 185 177 186 begin 178 Notify:=NotifyFunction;179 PreviewElevation:=false;180 181 {get available brains}182 Brain[bixNoTerm].FileName:=':AIT';183 Brain[bixNoTerm].Flags:=0;184 Brain[bixNoTerm].Initialized:=false;185 Brain[bixSuper_Virtual].FileName:=':Supervisor';186 Brain[bixSuper_Virtual].Flags:=0;187 Brain[bixSuper_Virtual].Initialized:=false;188 Brain[bixTerm].FileName:=':StdIntf';189 Brain[bixTerm].Flags:=fMultiple;190 Brain[bixTerm].Initialized:=false;191 Brain[bixTerm].ServerVersion:=Version;192 Brain[bixRandom].FileName:=':Random';193 Brain[bixRandom].Flags:=fMultiple;194 Brain[bixRandom].Initialized:=false;195 nBrain:=bixFirstAI;196 bixBeginner:=bixFirstAI;197 if FindFirst(HomeDir+'*.ai.txt',$21,f)=0 then198 repeat199 with Brain[nBrain] do200 begin 201 FileName:=Copy(f.Name,1,Length(f.Name)-7);202 DLLName:=HomeDir+FileName;203 Name:=Copy(f.Name,1,Length(f.Name)-7);204 Credits:='';205 Flags:=fMultiple;206 Client:=nil;207 Initialized:=false;208 ServerVersion:=0;209 AssignFile(T,HomeDir+f.Name);210 Reset(T);211 while not EOF(T) do187 Notify := NotifyFunction; 188 PreviewElevation := false; 189 190 { get available brains } 191 Brain[bixNoTerm].FileName := ':AIT'; 192 Brain[bixNoTerm].Flags := 0; 193 Brain[bixNoTerm].Initialized := false; 194 Brain[bixSuper_Virtual].FileName := ':Supervisor'; 195 Brain[bixSuper_Virtual].Flags := 0; 196 Brain[bixSuper_Virtual].Initialized := false; 197 Brain[bixTerm].FileName := ':StdIntf'; 198 Brain[bixTerm].Flags := fMultiple; 199 Brain[bixTerm].Initialized := false; 200 Brain[bixTerm].ServerVersion := Version; 201 Brain[bixRandom].FileName := ':Random'; 202 Brain[bixRandom].Flags := fMultiple; 203 Brain[bixRandom].Initialized := false; 204 nBrain := bixFirstAI; 205 bixBeginner := bixFirstAI; 206 if FindFirst(HomeDir + '*.ai.txt', $21, f) = 0 then 207 repeat 208 with Brain[nBrain] do 209 begin 210 FileName := Copy(f.Name, 1, Length(f.Name) - 7); 211 DLLName := HomeDir + FileName; 212 Name := Copy(f.Name, 1, Length(f.Name) - 7); 213 Credits := ''; 214 Flags := fMultiple; 215 Client := nil; 216 Initialized := false; 217 ServerVersion := 0; 218 AssignFile(T, HomeDir + f.Name); 219 Reset(T); 220 while not EOF(T) do 212 221 begin 213 ReadLn(T,s); 214 s:=trim(s); 215 if Copy(s,1,5)='#NAME' then Name:=Copy(s,7,255) 216 else if Copy(s,1,10)='#.NET' then 217 Flags:=Flags or fDotNet 218 else if Copy(s,1,9)='#BEGINNER' then 219 bixBeginner:=nBrain 220 else if Copy(s,1,5)='#PATH' then 221 DLLName:=HomeDir+trim(Copy(s,7,255)) 222 else if Copy(s,1,12)='#GAMEVERSION' then 223 for i:=13 to Length(s) do 224 case s[i] of 225 '0'..'9': ServerVersion:=ServerVersion and $FFFF00 226 +ServerVersion and $FF *10+ord(s[i])-48; 227 '.': ServerVersion:=ServerVersion shl 8; 222 ReadLn(T, s); 223 s := trim(s); 224 if Copy(s, 1, 5) = '#NAME' then 225 Name := Copy(s, 7, 255) 226 else if Copy(s, 1, 10) = '#.NET' then 227 Flags := Flags or fDotNet 228 else if Copy(s, 1, 9) = '#BEGINNER' then 229 bixBeginner := nBrain 230 else if Copy(s, 1, 5) = '#PATH' then 231 DLLName := HomeDir + trim(Copy(s, 7, 255)) 232 else if Copy(s, 1, 12) = '#GAMEVERSION' then 233 for i := 13 to Length(s) do 234 case s[i] of 235 '0' .. '9': 236 ServerVersion := ServerVersion and $FFFF00 + ServerVersion and 237 $FF * 10 + ord(s[i]) - 48; 238 '.': 239 ServerVersion := ServerVersion shl 8; 228 240 end 229 else if Copy(s,1,8)='#CREDITS' then230 Credits:=Copy(s,10,255)241 else if Copy(s, 1, 8) = '#CREDITS' then 242 Credits := Copy(s, 10, 255) 231 243 end; 232 CloseFile(T);233 end; 234 if (Brain[nBrain].ServerVersion>=FirstAICompatibleVersion)235 and (Brain[nBrain].ServerVersion<=Version)236 and ((Brain[nBrain].Flags and fDotNet=0) or (@DotNetClient<>nil)) then237 inc(nBrain);238 until FindNext(f)<>0;244 CloseFile(T); 245 end; 246 if (Brain[nBrain].ServerVersion >= FirstAICompatibleVersion) and 247 (Brain[nBrain].ServerVersion <= Version) and 248 ((Brain[nBrain].Flags and fDotNet = 0) or (@DotNetClient <> nil)) then 249 inc(nBrain); 250 until FindNext(f) <> 0; 239 251 end; 240 252 241 253 procedure Done; 242 254 var 243 i: integer;255 i: integer; 244 256 begin 245 for i:=0 to nBrain-1 do if Brain[i].Initialized then 246 begin 247 CallClient(i, cReleaseModule, nil^); 248 if (i>=bixFirstAI) and (Brain[i].Flags and fDotNet=0) then 249 FreeLibrary(Brain[i].hm); 250 end; 257 for i := 0 to nBrain - 1 do 258 if Brain[i].Initialized then 259 begin 260 CallClient(i, cReleaseModule, nil^); 261 if (i >= bixFirstAI) and (Brain[i].Flags and fDotNet = 0) then 262 FreeLibrary(Brain[i].hm); 263 end; 251 264 end; 252 265 253 266 function PreviewMap(lm: integer): pointer; 254 267 begin 255 lx:=lxmax; ly:=lymax; MapSize:=lx*ly; 256 LandMass:=lm; 257 RandSeed:=PreviewRND; 258 if not PreviewElevation then 268 lx := lxmax; 269 ly := lymax; 270 MapSize := lx * ly; 271 LandMass := lm; 272 RandSeed := PreviewRND; 273 if not PreviewElevation then 259 274 begin 260 CreateElevation;261 PreviewElevation:=true;275 CreateElevation; 276 PreviewElevation := true; 262 277 end; 263 CreateMap(true);264 result:=@RealMap;278 CreateMap(true); 279 result := @RealMap; 265 280 end; 266 281 … … 268 283 DataSize: integer); 269 284 begin 270 CCCommand:=Command; 271 CCPlayer:=Player; 272 if DataSize>0 then move(Data,CCData,DataSize); 273 Notify(ntChangeClient); 285 CCCommand := Command; 286 CCPlayer := Player; 287 if DataSize > 0 then 288 move(Data, CCData, DataSize); 289 Notify(ntChangeClient); 274 290 end; 275 291 276 292 procedure PutMessage(Level: integer; Text: string); 277 293 begin 278 Brain[bix[0]].Client(cDebugMessage,Level,pchar(Text)^);294 Brain[bix[0]].Client(cDebugMessage, Level, pchar(Text)^); 279 295 end; 280 296 281 297 procedure ForceClientDeactivation; 282 298 var 283 NullOffer: TOffer;299 NullOffer: TOffer; 284 300 begin 285 if pDipActive<0 then Server(sTurn,pTurn,0,nil^) // no nego mode 286 else case LastEndClientCommand of // nego mode 287 scContact: Server(scReject,pDipActive,0,nil^); 288 scDipCancelTreaty, scDipBreak: Server(scDipNotice,pDipActive,0,nil^); 301 if pDipActive < 0 then 302 Server(sTurn, pTurn, 0, nil^) // no nego mode 289 303 else 290 begin // make null offer 291 NullOffer.nDeliver:=0; 292 NullOffer.nCost:=0; 293 Server(scDipOffer,pDipActive,0,NullOffer); 304 case LastEndClientCommand of // nego mode 305 scContact: 306 Server(scReject, pDipActive, 0, nil^); 307 scDipCancelTreaty, scDipBreak: 308 Server(scDipNotice, pDipActive, 0, nil^); 309 else 310 begin // make null offer 311 NullOffer.nDeliver := 0; 312 NullOffer.nCost := 0; 313 Server(scDipOffer, pDipActive, 0, NullOffer); 314 end 315 end 316 end; 317 318 procedure ChangeClient; 319 // hand over control to other client (as specified by CC...) 320 var 321 p: integer; 322 T: int64; 323 begin 324 QueryPerformanceCounter(T); 325 PutMessage(1 shl 16 + 2, Format('CLIENT: took %.1f ms', 326 [{$IFDEF VER100}(T.LowPart - LastClientTime.LowPart) 327 {$ELSE}(T - LastClientTime){$ENDIF} * 1000.0 / PerfFreq])); 328 LastClientTime := T; 329 PutMessage(1 shl 16 + 2, Format('CLIENT: calling %d (%s)', 330 [CCPlayer, Brain[bix[CCPlayer]].Name])); 331 if CCCommand = cTurn then 332 for p := 0 to nPl - 1 do 333 if (p <> CCPlayer) and (1 shl p and GWatching <> 0) then 334 CallPlayer(cShowTurnChange, p, CCPlayer); 335 336 p := CCPlayer; 337 CCPlayer := -1; 338 CallPlayer(CCCommand, p, CCData); 339 if (Mode = moPlaying) and (Brain[bix[p]].Flags and aiThreaded = 0) and 340 (CCPlayer < 0) then 341 begin 342 Notify(ntDeactivationMissing + p); 343 ForceClientDeactivation; 344 end 345 end; 346 347 procedure Inform(p: integer); 348 var 349 i, p1: integer; 350 begin 351 RW[p].Turn := GTurn; 352 if (GTurn = MaxTurn) and (p = pTurn) and (p = 0) then 353 RW[p].Happened := RW[p].Happened or phTimeUp; 354 if (GWinner > 0) and (p = pTurn) and (p = 0) then 355 RW[p].Happened := RW[p].Happened or phShipComplete; 356 RW[p].Alive := GAlive; 357 move(GWonder, RW[p].Wonder, SizeOf(GWonder)); 358 move(GShip, RW[p].Ship, SizeOf(GShip)); 359 for p1 := 0 to nPl - 1 do 360 if (p1 <> p) and (bix[p1] >= 0) and (Difficulty[p1] > 0) then 361 RW[p].EnemyReport[p1].Credibility := RW[p1].Credibility; 362 for p1 := 0 to nPl - 1 do 363 if (p1 <> p) and (1 shl p1 and GAlive <> 0) then 364 begin 365 if (GTestFlags and tfUncover <> 0) or (Difficulty[p] = 0) or 366 (RW[p].Treaty[p1] >= trFriendlyContact) then 367 GiveCivilReport(p, p1); 368 if (GTestFlags and tfUncover <> 0) or (Difficulty[p] = 0) or 369 (RW[p].Treaty[p1] = trAlliance) then 370 GiveMilReport(p, p1) 371 end; 372 for i := 0 to RW[p].nEnemyModel - 1 do 373 with RW[p].EnemyModel[i] do 374 Lost := Destroyed[p, Owner, mix]; 375 end; 376 377 procedure LogChanges; 378 var 379 p, ix: integer; 380 begin 381 for p := 0 to nPl - 1 do 382 if (1 shl p and GWatching <> 0) and ProcessClientData[p] then 383 begin 384 // log unit status changes 385 for ix := 0 to RW[p].nUn - 1 do 386 with RW[p].Un[ix] do 387 if (Loc >= 0) and (SavedStatus <> Status) then 388 begin 389 CL.Put(sIntSetUnitStatus, p, ix, @Status); 390 SavedStatus := Status 391 end; 392 // log city status changes 393 for ix := 0 to RW[p].nCity - 1 do 394 with RW[p].City[ix] do 395 if (Loc >= 0) and (SavedStatus <> Status) then 396 begin 397 CL.Put(sIntSetCityStatus, p, ix, @Status); 398 SavedStatus := Status 399 end; 400 // log model status changes 401 for ix := 0 to RW[p].nModel - 1 do 402 with RW[p].Model[ix] do 403 if SavedStatus <> Status then 404 begin 405 CL.Put(sIntSetModelStatus, p, ix, @Status); 406 SavedStatus := Status 407 end; 408 // log enemy city status changes 409 for ix := 0 to RW[p].nEnemyCity - 1 do 410 with RW[p].EnemyCity[ix] do 411 if (Loc >= 0) and (SavedStatus <> Status) then 412 begin 413 CL.Put(sIntSetECityStatus, p, ix, @Status); 414 SavedStatus := Status 415 end; 416 // log data changes 417 if Brain[bix[p]].DataSize > 0 then 418 begin 419 CL.PutDataChanges(sIntDataChange, p, SavedData[p], RW[p].Data, 420 Brain[bix[p]].DataSize); 421 move(RW[p].Data^, SavedData[p]^, Brain[bix[p]].DataSize * 4); 422 end 423 end; 424 end; 425 426 procedure NoLogChanges; 427 var 428 p, ix: integer; 429 begin 430 for p := 0 to nPl - 1 do 431 if (1 shl p and GWatching <> 0) and ProcessClientData[p] then 432 begin 433 for ix := 0 to RW[p].nUn - 1 do 434 with RW[p].Un[ix] do 435 SavedStatus := Status; 436 for ix := 0 to RW[p].nCity - 1 do 437 with RW[p].City[ix] do 438 SavedStatus := Status; 439 for ix := 0 to RW[p].nModel - 1 do 440 with RW[p].Model[ix] do 441 SavedStatus := Status; 442 for ix := 0 to RW[p].nEnemyCity - 1 do 443 with RW[p].EnemyCity[ix] do 444 SavedStatus := Status; 445 if Brain[bix[p]].DataSize > 0 then 446 move(RW[p].Data^, SavedData[p]^, Brain[bix[p]].DataSize * 4); 447 end; 448 end; 449 450 function HasChanges(p: integer): boolean; 451 type 452 TDWordList = array [0 .. INFIN] of Cardinal; 453 PDWortList = ^TDWordList; 454 var 455 ix: integer; 456 begin 457 result := false; 458 for ix := 0 to RW[p].nUn - 1 do 459 with RW[p].Un[ix] do 460 if (Loc >= 0) and (SavedStatus <> Status) then 461 result := true; 462 for ix := 0 to RW[p].nCity - 1 do 463 with RW[p].City[ix] do 464 if (Loc >= 0) and (SavedStatus <> Status) then 465 result := true; 466 for ix := 0 to RW[p].nModel - 1 do 467 with RW[p].Model[ix] do 468 if SavedStatus <> Status then 469 result := true; 470 for ix := 0 to RW[p].nEnemyCity - 1 do 471 with RW[p].EnemyCity[ix] do 472 if (Loc >= 0) and (SavedStatus <> Status) then 473 result := true; 474 if RW[p].Data <> nil then 475 for ix := 0 to Brain[bix[p]].DataSize - 1 do 476 if PDWortList(SavedData[p])[ix] <> PDWortList(RW[p].Data)[ix] then 477 result := true 478 end; 479 480 procedure InitBrain(bix: integer); 481 var 482 InitModuleData: TInitModuleData; 483 begin 484 assert(bix <> bixSuper_Virtual); 485 with Brain[bix] do 486 begin 487 if Initialized then 488 exit; 489 if bix >= bixFirstAI then 490 begin { get client function } 491 Notify(ntInitModule + bix); 492 if Flags and fDotNet > 0 then 493 Client := DotNetClient 494 else 495 begin 496 hm := LoadLibrary(pchar(DLLName)); 497 if hm = 0 then 498 begin 499 Client := nil; 500 Notify(ntDLLError + bix); 501 end 502 else 503 begin 504 Client := GetProcAddress(hm, 'client'); 505 if @Client = nil then 506 Notify(ntClientError + bix); 507 end 508 end 509 end; 510 if @Client <> nil then 511 begin 512 Initialized := true; 513 InitModuleData.Server := @Server; 514 InitModuleData.DataVersion := 0; 515 InitModuleData.DataSize := 0; 516 InitModuleData.Flags := 0; 517 CallClient(bix, cInitModule, InitModuleData); 518 DataVersion := InitModuleData.DataVersion; 519 DataSize := (InitModuleData.DataSize + 3) div 4; 520 if DataSize > MaxDataSize then 521 DataSize := 0; 522 Flags := Flags or InitModuleData.Flags; 294 523 end 295 524 end 296 525 end; 297 526 298 procedure ChangeClient; 299 //hand over control to other client (as specified by CC...) 527 procedure SaveMap(FileName: string); 300 528 var 301 p: integer; 302 T: int64; 529 i: integer; 530 MapFile: TFileStream; 531 s: string[255]; 303 532 begin 304 QueryPerformanceCounter(T); 305 PutMessage(1 shl 16+2, Format('CLIENT: took %.1f ms', 306 [{$IFDEF VER100}(T.LowPart-LastClientTime.LowPart) 307 {$ELSE}(T-LastClientTime){$ENDIF}*1000.0/PerfFreq])); 308 LastClientTime:=T; 309 PutMessage(1 shl 16+2, Format('CLIENT: calling %d (%s)', 310 [CCPlayer,Brain[bix[CCPlayer]].Name])); 311 if CCCommand=cTurn then 312 for p:=0 to nPl-1 do if (p<>CCPlayer) and (1 shl p and GWatching<>0) then 313 CallPlayer(cShowTurnChange,p,CCPlayer); 314 315 p:=CCPlayer; 316 CCPlayer:=-1; 317 CallPlayer(CCCommand,p,CCData); 318 if (Mode=moPlaying) and (Brain[bix[p]].Flags and aiThreaded=0) and (CCPlayer<0) then 533 MapFile := TFileStream.Create(DataDir + 'Maps\' + FileName, 534 fmCreate or fmShareExclusive); 535 MapFile.Position := 0; 536 s := 'cEvoMap'#0; 537 MapFile.write(s[1], 8); { file id } 538 i := 0; 539 MapFile.write(i, 4); { format id } 540 MapFile.write(MaxTurn, 4); 541 MapFile.write(lx, 4); 542 MapFile.write(ly, 4); 543 MapFile.write(RealMap, MapSize * 4); 544 MapFile.Free; 545 end; 546 547 function LoadMap(FileName: string): boolean; 548 var 549 i, Loc1: integer; 550 MapFile: TFileStream; 551 s: string[255]; 552 begin 553 result := false; 554 MapFile := nil; 555 try 556 MapFile := TFileStream.Create(DataDir + 'Maps\' + FileName, 557 fmOpenRead or fmShareExclusive); 558 MapFile.Position := 0; 559 MapFile.read(s[1], 8); { file id } 560 MapFile.read(i, 4); { format id } 561 if i = 0 then 562 begin 563 MapFile.read(i, 4); // MaxTurn 564 MapFile.read(lx, 4); 565 MapFile.read(ly, 4); 566 ly := ly and not 1; 567 if lx > lxmax then 568 lx := lxmax; 569 if ly > lymax then 570 ly := lymax; 571 MapSize := lx * ly; 572 MapFile.read(RealMap, MapSize * 4); 573 for Loc1 := 0 to MapSize - 1 do 574 begin 575 RealMap[Loc1] := RealMap[Loc1] and 576 ($7F01FFFF or fPrefStartPos or fStartPos) or ($F shl 27); 577 if RealMap[Loc1] and (fTerrain or fSpecial) = fSwamp or fSpecial2 then 578 RealMap[Loc1] := RealMap[Loc1] and not(fTerrain or fSpecial) or 579 (fSwamp or fSpecial1); 580 if (RealMap[Loc1] and fDeadLands <> 0) and 581 (RealMap[Loc1] and fTerrain <> fArctic) then 582 RealMap[Loc1] := RealMap[Loc1] and not(fTerrain or fSpecial) 583 or fDesert; 584 end; 585 result := true; 586 end; 587 MapFile.Free; 588 except 589 if MapFile <> nil then 590 MapFile.Free; 591 end; 592 end; 593 594 procedure SaveGame(FileName: string; auto: boolean); 595 var 596 x, y, i, zero, Tile, nLocal: integer; 597 LogFile: TFileStream; 598 s: string[255]; 599 SaveMap: array [0 .. lxmax * lymax - 1] of Byte; 600 begin 601 nLocal := 0; 602 for i := 0 to nPl - 1 do 603 if bix[i] = bixTerm then 604 inc(nLocal); 605 if Difficulty[0] = 0 then 606 nLocal := 0; 607 if nLocal <= 1 then 608 for y := 0 to ly - 1 do 609 for x := 0 to lx - 1 do 610 begin 611 Tile := RW[0].Map[(x + SaveMapCenterLoc + lx shr 1) mod lx + lx * y]; 612 SaveMap[x + lx * y] := Tile and fTerrain + Tile and 613 (fCity or fUnit or fOwned) shr 16; 614 end; 615 616 if auto and AutoSaveExists then // append to existing file 617 LogFile := TFileStream.Create(SavePath + FileName, fmOpenReadWrite or 618 fmShareExclusive) 619 else // create new file 620 LogFile := TFileStream.Create(SavePath + FileName, 621 fmCreate or fmShareExclusive); 622 623 zero := 0; 624 LogFile.Position := 0; 625 s := 'cEvoBook'; 626 LogFile.write(s[1], 8); { file id } 627 i := Version; 628 LogFile.write(i, 4); { c-evo version } 629 LogFile.write(ExeInfo.Time, 4); 630 LogFile.write(lx, 4); 631 LogFile.write(ly, 4); 632 LogFile.write(LandMass, 4); 633 if LandMass = 0 then 634 LogFile.write(MapField^, MapSize * 4); 635 636 LogFile.write(MaxTurn, 4); 637 LogFile.write(RND, 4); 638 LogFile.write(GTurn, 4); 639 if nLocal > 1 then // multiplayer game -- no quick view 319 640 begin 320 Notify(ntDeactivationMissing+p); 321 ForceClientDeactivation; 641 i := $80; 642 LogFile.write(i, 4); 643 end 644 else 645 LogFile.write(SaveMap, ((MapSize - 1) div 4 + 1) * 4); 646 for i := 0 to nPl - 1 do 647 if bix[i] < 0 then 648 LogFile.write(zero, 4) 649 else 650 begin 651 if bixView[i] >= bixRandom then 652 s := Brain[bix[i]].FileName 653 else 654 s := Brain[bixView[i]].FileName; 655 move(zero, s[Length(s) + 1], 4); 656 LogFile.write(s, (Length(s) div 4 + 1) * 4); 657 LogFile.write(OriginalDataVersion[i], 4); 658 s := ''; { behavior } 659 move(zero, s[Length(s) + 1], 4); 660 LogFile.write(s, (Length(s) div 4 + 1) * 4); 661 LogFile.write(Difficulty[i], 4); 662 end; 663 664 if auto and AutoSaveExists then 665 CL.AppendToFile(LogFile, AutoSaveState) 666 else 667 CL.SaveToFile(LogFile); 668 LogFile.Free; 669 if auto then 670 begin 671 AutoSaveState := CL.State; 672 AutoSaveExists := true 322 673 end 323 674 end; 324 675 325 procedure Inform(p: integer);676 procedure StartGame; 326 677 var 327 i,p1: integer; 678 i, p, p1, Human, nAlive, bixUni: integer; 679 Game: TNewGameData; 680 // GameEx: TNewGameExData; 681 Path: shortstring; 682 BrainUsed: Set of 0 .. 254; { used brains } 328 683 begin 329 RW[p].Turn:=GTurn; 330 if (GTurn=MaxTurn) and (p=pTurn) and (p=0) then 331 RW[p].Happened:=RW[p].Happened or phTimeUp; 332 if (GWinner>0) and (p=pTurn) and (p=0) then 333 RW[p].Happened:=RW[p].Happened or phShipComplete; 334 RW[p].Alive:=GAlive; 335 move(GWonder,RW[p].Wonder,SizeOf(GWonder)); 336 move(GShip,RW[p].Ship,SizeOf(GShip)); 337 for p1:=0 to nPl-1 do 338 if (p1<>p) and (bix[p1]>=0) and (Difficulty[p1]>0) then 339 RW[p].EnemyReport[p1].Credibility:=RW[p1].Credibility; 340 for p1:=0 to nPl-1 do 341 if (p1<>p) and (1 shl p1 and GAlive<>0) then 684 for p1 := 0 to nPl - 1 do 685 begin 686 if bixView[p1] = bixSuper_Virtual then 687 bix[p1] := bixTerm // supervisor and local human use same module 688 else if bixView[p1] = bixRandom then 689 if nBrain <= bixFirstAI then 690 bix[p1] := -1 691 else 692 bix[p1] := bixFirstAI + random(nBrain - bixFirstAI) 693 else 694 bix[p1] := bixView[p1]; 695 if bixView[p1] < 0 then 696 Difficulty[p1] := -1; 697 end; 698 699 if bix[0] <> bixNoTerm then 700 Notify(ntInitLocalHuman); 701 BrainUsed := []; 702 for p := 0 to nPl - 1 do 703 if (bix[p] >= 0) and ((Mode <> moMovie) or (p = 0)) then 704 begin { initiate selected control module } 705 AIInfo[p] := Brain[bix[p]].Name + #0; 706 InitBrain(bix[p]); 707 if Mode = moPlaying then 708 begin // new game, this data version is original 709 OriginalDataVersion[p] := Brain[bix[p]].DataVersion; 710 ProcessClientData[p] := true; 711 end 712 else // loading game, compare with data version read from file 713 ProcessClientData[p] := ProcessClientData[p] and 714 (OriginalDataVersion[p] = Brain[bix[p]].DataVersion); 715 if @Brain[bix[p]].Client = nil then // client function not found 716 if bix[0] = bixNoTerm then 717 bix[p] := -1 718 else 719 begin 720 bix[p] := bixTerm; 721 OriginalDataVersion[p] := -1; 722 ProcessClientData[p] := false; 723 end; 724 if bix[p] >= 0 then 725 include(BrainUsed, bix[p]) 726 end; 727 728 Notify(ntCreateWorld); 729 nAlive := 0; 730 GAlive := 0; 731 if Mode = moMovie then 732 GWatching := 1 733 else 734 GWatching := 0; 735 GAI := 0; 736 for p1 := 0 to nPl - 1 do 737 if bix[p1] >= 0 then 342 738 begin 343 if (GTestFlags and tfUncover<>0) or (Difficulty[p]=0) 344 or (RW[p].Treaty[p1]>=trFriendlyContact) then 345 GiveCivilReport(p, p1); 346 if (GTestFlags and tfUncover<>0) or (Difficulty[p]=0) 347 or (RW[p].Treaty[p1]=trAlliance) then 348 GiveMilReport(p, p1) 739 if Mode <> moMovie then 740 inc(GWatching, 1 shl p1); 741 if bix[p1] >= bixFirstAI then 742 inc(GAI, 1 shl p1); 743 if Difficulty[p1] > 0 then 744 begin 745 inc(GAlive, 1 shl p1); 746 inc(nAlive); 747 end; 748 ServerVersion[p1] := Brain[bix[p1]].ServerVersion; 349 749 end; 350 for i:=0 to RW[p].nEnemyModel-1 do with RW[p].EnemyModel[i] do 351 Lost:=Destroyed[p,Owner,mix]; 750 WinOnAlone := (bix[0] = bixNoTerm) and (nAlive > 1); 751 GWinner := 0; 752 GColdWarStart := -ColdWarTurns - 1; 753 uixSelectedTransport := -1; 754 SpyMission := smSabotageProd; 755 for p1 := 0 to nPl - 1 do 756 DebugMap[p1] := nil; 757 758 GTurn := 0; 759 for i := 0 to 27 do 760 with GWonder[i] do 761 begin 762 CityID := -1; 763 EffectiveOwner := -1 764 end; 765 FillChar(GShip, SizeOf(GShip), 0); 766 767 for p := 0 to nPl - 1 do 768 if 1 shl p and (GAlive or GWatching) <> 0 then 769 with RW[p] do 770 begin 771 Government := gDespotism; 772 Money := StartMoney; 773 TaxRate := 30; 774 LuxRate := 0; 775 Research := 0; 776 ResearchTech := -2; 777 AnarchyStart := -AnarchyTurns - 1; 778 Happened := 0; 779 LastValidStat[p] := -1; 780 Worked[p] := 0; 781 Founded[p] := 0; 782 DevModelTurn[p] := -1; 783 OracleIncome := 0; 784 785 if Brain[bix[p]].DataSize > 0 then 786 begin 787 GetMem(SavedData[p], Brain[bix[p]].DataSize * 4); 788 GetMem(Data, Brain[bix[p]].DataSize * 4); 789 FillChar(SavedData[p]^, Brain[bix[p]].DataSize * 4, 0); 790 FillChar(Data^, Brain[bix[p]].DataSize * 4, 0); 791 end 792 else 793 begin 794 Data := nil; 795 SavedData[p] := nil 796 end; 797 nBattleHistory := 0; 798 BattleHistory := nil; 799 { if bix[p]=bixTerm then 800 begin 801 GetMem(BorderHelper,MapSize); 802 FillChar(BorderHelper^,MapSize,0); 803 end 804 else } BorderHelper := nil; 805 for i := 0 to nStat - 1 do 806 GetMem(Stat[i, p], 4 * (MaxTurn + 1)); 807 if Brain[bix[p]].Flags and fDotNet <> 0 then 808 begin 809 GetMem(RW[p].DefaultDebugMap, MapSize * 4); 810 FillChar(RW[p].DefaultDebugMap^, MapSize * 4, 0); 811 DebugMap[p] := RW[p].DefaultDebugMap; 812 end 813 else 814 RW[p].DefaultDebugMap := nil; 815 816 { !!!for i:=0 to nShipPart-1 do GShip[p].Parts[i]:=random((3-i)*2);{ } 817 end; 818 819 if LandMass > 0 then 820 begin // random map 821 InitRandomGame; 822 PreviewElevation := false; 823 MapField := nil; 824 end 825 else 826 begin // predefined map 827 if Mode = moPlaying then 828 LoadMap(MapFileName); // new game -- load map from file 829 GetMem(MapField, MapSize * 4); 830 move(RealMap, MapField^, MapSize * 4); 831 Human := 0; 832 for p1 := 0 to nPl - 1 do 833 if bix[p1] = bixTerm then 834 inc(Human, 1 shl p1); 835 InitMapGame(Human); 836 end; 837 CityProcessing.InitGame; 838 UnitProcessing.InitGame; 839 for p := 0 to nPl - 1 do 840 if 1 shl p and (GAlive or GWatching) <> 0 then 841 Inform(p); 842 843 pTurn := -1; 844 if bix[0] <> bixNoTerm then 845 Notify(ntInitLocalHuman); 846 Game.lx := lx; 847 Game.ly := ly; 848 Game.LandMass := LandMass; 849 Game.MaxTurn := MaxTurn; 850 move(Difficulty, Game.Difficulty, SizeOf(Difficulty)); 851 // GameEx.lx:=lx; GameEx.ly:=ly; GameEx.LandMass:=LandMass; 852 // GameEx.MaxTurn:=MaxTurn; GameEx.RND:=RND; 853 // move(Difficulty,GameEx.Difficulty,SizeOf(Difficulty)); 854 AICredits := ''; 855 for i := 0 to nBrain - 1 do 856 if Brain[i].Initialized then 857 if i in BrainUsed then 858 begin 859 if i >= bixFirstAI then 860 Notify(ntInitPlayers); 861 for p := 0 to nPl - 1 do 862 begin 863 if bix[p] = i then 864 Game.RO[p] := @RW[p] 865 else 866 Game.RO[p] := nil; 867 if (i = bixTerm) and (Difficulty[0] = 0) and (bix[p] >= 0) then 868 Game.SuperVisorRO[p] := @RW[p] 869 else 870 Game.SuperVisorRO[p] := nil; 871 end; 872 if Brain[i].Flags and fDotNet > 0 then 873 begin 874 Path := Brain[i].DLLName; 875 move(Path[1], Game.AssemblyPath, Length(Path)); 876 Game.AssemblyPath[Length(Path)] := #0; 877 end 878 else 879 Game.AssemblyPath[0] := #0; 880 case Mode of 881 moLoading, moLoading_Fast: 882 CallClient(i, cLoadGame, Game); 883 moMovie: 884 CallClient(i, cMovie, Game); 885 moPlaying: 886 CallClient(i, cNewGame, Game); 887 end; 888 if (i >= bixFirstAI) and (Brain[i].Credits <> '') then 889 if AICredits = '' then 890 AICredits := Brain[i].Credits 891 else 892 AICredits := AICredits + '\' + Brain[i].Credits 893 end 894 else 895 begin { module no longer used -- unload } 896 CallClient(i, cReleaseModule, nil^); 897 if i >= bixFirstAI then 898 begin 899 if Brain[i].Flags and fDotNet = 0 then 900 FreeLibrary(Brain[i].hm); 901 Brain[i].Client := nil; 902 end; 903 Brain[i].Initialized := false; 904 end; 905 AICredits := AICredits + #0; 906 907 if bix[0] <> bixNoTerm then 908 begin 909 // uni ai? 910 bixUni := -1; 911 for p1 := 0 to nPl - 1 do 912 if bix[p1] >= bixFirstAI then 913 if bixUni = -1 then 914 bixUni := bix[p1] 915 else if bixUni <> bix[p1] then 916 bixUni := -2; 917 for p1 := 0 to nPl - 1 do 918 if bix[p1] >= bixFirstAI then 919 begin 920 if bixUni = -2 then 921 NotifyMessage := Brain[bix[p1]].FileName 922 else 923 NotifyMessage := ''; 924 Notify(ntSetAIName + p1); 925 end 926 end; 927 928 CheckBorders(-1); 929 {$IFOPT O-}InvalidTreatyMap := 0; {$ENDIF} 930 AutoSaveExists := false; 931 pDipActive := -1; 932 pTurn := 0; 933 934 if Mode >= moMovie then 935 Notify(ntEndInfo); 936 end; { StartGame } 937 938 procedure EndGame; 939 var 940 i, p1: integer; 941 begin 942 if LandMass = 0 then 943 FreeMem(MapField); 944 for p1 := 0 to nPl - 1 do 945 if bix[p1] >= 0 then 946 begin 947 for i := 0 to nStat - 1 do 948 FreeMem(Stat[i, p1]); 949 if RW[p1].BattleHistory <> nil then 950 FreeMem(RW[p1].BattleHistory); 951 { if RW[p1].BorderHelper<>nil then FreeMem(RW[p1].BorderHelper); } 952 FreeMem(RW[p1].Data); 953 FreeMem(SavedData[p1]); 954 if RW[p1].DefaultDebugMap <> nil then 955 FreeMem(RW[p1].DefaultDebugMap); 956 end; 957 UnitProcessing.ReleaseGame; 958 CityProcessing.ReleaseGame; 959 Database.ReleaseGame; 960 CL.Free; 352 961 end; 353 962 354 procedure LogChanges;963 procedure GenerateStat(p: integer); 355 964 var 356 p,ix: integer;965 cix, uix: integer; 357 966 begin 358 for p:=0 to nPl-1 do 359 if (1 shl p and GWatching<>0) and ProcessClientData[p] then967 if Difficulty[p] > 0 then 968 with RW[p] do 360 969 begin 361 // log unit status changes 362 for ix:=0 to RW[p].nUn-1 do with RW[p].Un[ix] do 363 if (Loc>=0) and (SavedStatus<>Status) then 364 begin 365 CL.Put(sIntSetUnitStatus, p, ix, @Status); 366 SavedStatus:=Status 367 end; 368 // log city status changes 369 for ix:=0 to RW[p].nCity-1 do with RW[p].City[ix] do 370 if (Loc>=0) and (SavedStatus<>Status) then 371 begin 372 CL.Put(sIntSetCityStatus, p, ix, @Status); 373 SavedStatus:=Status 374 end; 375 // log model status changes 376 for ix:=0 to RW[p].nModel-1 do with RW[p].Model[ix] do 377 if SavedStatus<>Status then 378 begin 379 CL.Put(sIntSetModelStatus, p, ix, @Status); 380 SavedStatus:=Status 381 end; 382 // log enemy city status changes 383 for ix:=0 to RW[p].nEnemyCity-1 do with RW[p].EnemyCity[ix] do 384 if (Loc>=0) and (SavedStatus<>Status) then 385 begin 386 CL.Put(sIntSetECityStatus, p, ix, @Status); 387 SavedStatus:=Status 388 end; 389 // log data changes 390 if Brain[bix[p]].DataSize>0 then 391 begin 392 CL.PutDataChanges(sIntDataChange, p, SavedData[p], RW[p].Data, 393 Brain[bix[p]].DataSize); 394 move(RW[p].Data^,SavedData[p]^,Brain[bix[p]].DataSize*4); 395 end 970 Stat[stPop, p, GTurn] := 0; 971 for cix := 0 to nCity - 1 do 972 if City[cix].Loc >= 0 then 973 inc(Stat[stPop, p, GTurn], City[cix].Size); 974 Stat[stScience, p, GTurn] := Researched[p] * 50; 975 if (RW[p].ResearchTech >= 0) and (RW[p].ResearchTech <> adMilitary) then 976 inc(Stat[stScience, p, GTurn], Research * 100 div TechBaseCost(nTech[p], 977 Difficulty[p])); 978 Stat[stMil, p, GTurn] := 0; 979 for uix := 0 to nUn - 1 do 980 if Un[uix].Loc >= 0 then 981 with Model[Un[uix].mix] do 982 begin 983 if (Kind <= mkEnemyDeveloped) and (Un[uix].mix <> 1) then 984 inc(Stat[stMil, p, GTurn], Weight * MStrength * 985 Un[uix].Health div 100) 986 else if Domain = dGround then 987 inc(Stat[stMil, p, GTurn], (Attack + 2 * Defense) * 988 Un[uix].Health div 100) 989 else 990 inc(Stat[stMil, p, GTurn], (Attack + Defense) * 991 Un[uix].Health div 100); 992 case Kind of 993 mkSlaves: 994 inc(Stat[stPop, p, GTurn]); 995 mkSettler: 996 inc(Stat[stPop, p, GTurn], 2); 997 end; 998 end; 999 Stat[stMil, p, GTurn] := Stat[stMil, p, GTurn] div 16; 1000 Stat[stExplore, p, GTurn] := Discovered[p]; 1001 Stat[stTerritory, p, GTurn] := TerritoryCount[p]; 1002 Stat[stWork, p, GTurn] := Worked[p]; 1003 LastValidStat[p] := GTurn; 396 1004 end; 397 1005 end; 398 1006 399 procedure NoLogChanges;1007 procedure LogCityTileChanges; 400 1008 var 401 p,ix: integer;1009 cix: integer; 402 1010 begin 403 for p:=0 to nPl-1 do 404 if (1 shl p and GWatching<>0) and ProcessClientData[p] then 1011 for cix := 0 to RW[pTurn].nCity - 1 do 1012 with RW[pTurn].City[cix] do 1013 if Loc >= 0 then 1014 begin 1015 { if SavedResourceWeights[cix]<>ResourceWeights then 1016 begin // log city resource weight changes 1017 CL.Put(sSetCityResourceWeights, pTurn, cix, @ResourceWeights); 1018 SavedResourceWeights[cix]:=ResourceWeights; 1019 end; } 1020 if SavedTiles[cix] <> Tiles then 1021 begin // log city tile changes 1022 CL.Put(sSetCityTiles, pTurn, cix, @Tiles); 1023 SavedTiles[cix] := Tiles; 1024 end; 1025 end; 1026 end; 1027 1028 procedure NoLogCityTileChanges; 1029 var 1030 cix: integer; 1031 begin 1032 for cix := 0 to RW[pTurn].nCity - 1 do 1033 with RW[pTurn].City[cix] do 1034 if Loc >= 0 then 1035 begin 1036 // SavedResourceWeights[cix]:=ResourceWeights; 1037 SavedTiles[cix] := Tiles; 1038 end; 1039 end; 1040 1041 function HasCityTileChanges: boolean; 1042 var 1043 cix: integer; 1044 begin 1045 result := false; 1046 for cix := 0 to RW[pTurn].nCity - 1 do 1047 with RW[pTurn].City[cix] do 1048 if Loc >= 0 then 1049 begin 1050 // if SavedResourceWeights[cix]<>ResourceWeights then result:=true; 1051 if SavedTiles[cix] <> Tiles then 1052 result := true; 1053 end; 1054 end; 1055 1056 procedure BeforeTurn0; 1057 var 1058 p1, uix: integer; 1059 begin 1060 for uix := 0 to RW[pTurn].nUn - 1 do { init movement points for first turn } 1061 with RW[pTurn].Un[uix] do 1062 Movement := RW[pTurn].Model[mix].Speed; 1063 1064 if Difficulty[pTurn] > 0 then 1065 DiscoverViewAreas(pTurn) 1066 else { supervisor } 1067 begin 1068 DiscoverAll(pTurn, lObserveSuper); 1069 for p1 := 1 to nPl - 1 do 1070 if 1 shl p1 and GAlive <> 0 then 1071 begin 1072 GiveCivilReport(pTurn, p1); 1073 GiveMilReport(pTurn, p1) 1074 end; 1075 end; 1076 // CheckContact; 1077 end; 1078 1079 function LoadGame(const Path, FileName: string; Turn: integer; 1080 MovieMode: boolean): boolean; 1081 var 1082 i, j, ix, d, p1, Command, Subject: integer; 1083 {$IFDEF TEXTLOG}LoadPos0: integer; {$ENDIF} 1084 Data: pointer; 1085 LogFile: TFileStream; 1086 FormerCLState: TCmdListState; 1087 s: string[255]; 1088 SaveMap: array [0 .. lxmax * lymax - 1] of Byte; 1089 started, StatRequest: boolean; 1090 begin 1091 SavePath := Path; 1092 LogFileName := FileName; 1093 LoadTurn := Turn; 1094 LogFile := TFileStream.Create(SavePath + LogFileName, fmOpenRead or 1095 fmShareExclusive); 1096 LogFile.Position := 0; 1097 LogFile.read(s[1], 8); { file id } 1098 LogFile.read(i, 4); { c-evo version } 1099 LogFile.read(j, 4); { exe time } 1100 1101 if (i >= FirstBookCompatibleVersion) and (i <= Version) then 1102 begin 1103 result := true; 1104 LogFile.read(lx, 4); 1105 LogFile.read(ly, 4); 1106 MapSize := lx * ly; 1107 LogFile.read(LandMass, 4); 1108 if LandMass = 0 then 1109 LogFile.read(RealMap, MapSize * 4); // use predefined map 1110 LogFile.read(MaxTurn, 4); 1111 LogFile.read(RND, 4); 1112 LogFile.read(GTurn, 4); 1113 LogFile.read(SaveMap, 4); 1114 if SaveMap[0] <> $80 then 1115 LogFile.read(SaveMap[4], ((MapSize - 1) div 4 + 1) * 4 - 4); 1116 for p1 := 0 to nPl - 1 do 405 1117 begin 406 for ix:=0 to RW[p].nUn-1 do with RW[p].Un[ix] do 407 SavedStatus:=Status; 408 for ix:=0 to RW[p].nCity-1 do with RW[p].City[ix] do 409 SavedStatus:=Status; 410 for ix:=0 to RW[p].nModel-1 do with RW[p].Model[ix] do 411 SavedStatus:=Status; 412 for ix:=0 to RW[p].nEnemyCity-1 do with RW[p].EnemyCity[ix] do 413 SavedStatus:=Status; 414 if Brain[bix[p]].DataSize>0 then 415 move(RW[p].Data^,SavedData[p]^,Brain[bix[p]].DataSize*4); 1118 LogFile.read(s[0], 4); 1119 if s[0] = #0 then 1120 bixView[p1] := -1 1121 else 1122 begin 1123 LogFile.read(s[4], Byte(s[0]) div 4 * 4); 1124 LogFile.read(OriginalDataVersion[p1], 4); 1125 LogFile.read(d, 4); { behavior } 1126 LogFile.read(Difficulty[p1], 4); 1127 j := nBrain - 1; 1128 while (j >= 0) and (AnsiCompareFileName(Brain[j].FileName, s) <> 0) do 1129 dec(j); 1130 if j < 0 then 1131 begin // ai not found -- replace by local player 1132 ProcessClientData[p1] := false; 1133 NotifyMessage := s; 1134 Notify(ntAIError); 1135 j := bixTerm; 1136 end 1137 else 1138 ProcessClientData[p1] := true; 1139 if j = bixNoTerm then 1140 j := bixSuper_Virtual; 1141 // crashed tournament -- load as supervisor 1142 bixView[p1] := j; 1143 end; 416 1144 end; 417 end; 418 419 function HasChanges(p: integer): boolean; 420 type 421 TDWordList= array[0..INFIN] of Cardinal; 422 PDWortList=^TDWordList; 1145 end 1146 else 1147 result := false; 1148 1149 if result then 1150 begin 1151 CL := TCmdList.Create; 1152 CL.LoadFromFile(LogFile); 1153 end; 1154 LogFile.Free; 1155 if not result then 1156 exit; 1157 1158 Notify(ntStartDone); 1159 if LoadTurn < 0 then 1160 LoadTurn := GTurn; 1161 if MovieMode then 1162 Mode := moMovie 1163 else if LoadTurn = 0 then 1164 Mode := moLoading 1165 else 1166 Mode := moLoading_Fast; 1167 {$IFDEF TEXTLOG}AssignFile(TextLog, SavePath + LogFileName + '.txt'); 1168 Rewrite(TextLog); {$ENDIF} 1169 LoadOK := true; 1170 StartGame; 1171 if MovieMode then 1172 begin 1173 Brain[bix[0]].Client(cShowGame, 0, nil^); 1174 Notify(ntBackOff); 1175 end 1176 else 1177 Notify(ntLoadBegin); 1178 1179 started := false; 1180 StatRequest := false; 1181 MovieStopped := false; 1182 {$IFDEF LOADPERF}QueryPerformanceCounter(time_total0); 1183 time_a := 0; 1184 time_b := 0; 1185 time_c := 0; {$ENDIF} 1186 while not MovieStopped and (CL.Progress < 1000) do 1187 begin 1188 FormerCLState := CL.State; 1189 CL.Get(Command, p1, Subject, Data); 1190 if p1 < 0 then 1191 p1 := pTurn; 1192 if StatRequest and (Command and (sctMask or sExecute) <> sctInternal or 1193 sExecute) then 1194 begin 1195 GenerateStat(pTurn); 1196 StatRequest := false 1197 end; 1198 // complete all internal commands following an sTurn before generating statistics 1199 if (Command = sTurn) and not started then 1200 begin 1201 {$IFDEF TEXTLOG}WriteLn(TextLog, '---Turn 0 P0---'); {$ENDIF} 1202 for p1 := 0 to nPl - 1 do 1203 if (bix[p1] >= 0) and ((Mode <> moMovie) or (p1 = 0)) then 1204 CallPlayer(cReplay, p1, nil^); 1205 BeforeTurn0; 1206 if MovieMode then 1207 begin 1208 Inform(pTurn); 1209 CallPlayer(cMovieTurn, 0, nil^); 1210 end; 1211 StatRequest := true; 1212 started := true; 1213 end 1214 else if (Command = sTurn) and (pTurn = 0) and (GTurn = LoadTurn) then 1215 begin 1216 assert(CL.State.LoadPos = FormerCLState.LoadPos + 4); // size of sTurn 1217 CL.State := FormerCLState; 1218 CL.Cut; 1219 Break; 1220 end 1221 else if Command = sIntDataChange then 1222 begin 1223 {$IFDEF TEXTLOG}LoadPos0 := CL.State.LoadPos; {$ENDIF} 1224 if ProcessClientData[p1] then 1225 CL.GetDataChanges(RW[p1].Data, Brain[bix[p1]].DataSize) 1226 else 1227 CL.GetDataChanges(nil, 0); 1228 {$IFDEF TEXTLOG}WriteLn(TextLog, Format('Data Changes P%d (%d Bytes)', [p1, CL.State.LoadPos - LoadPos0])); {$ENDIF} 1229 end 1230 else 1231 begin 1232 {$IFDEF TEXTLOG}CmdInfo := Format('Command %x', [Command]); {$ENDIF} 1233 if Command and (sctMask or sExecute) = sctInternal or sExecute then 1234 IntServer(Command, p1, Subject, Data^) // internal command 1235 else 1236 begin 1237 StatRequest := Command = sTurn; 1238 Server(Command, p1, Subject, Data^); 1239 end; 1240 {$IFDEF TEXTLOG}WriteLn(TextLog, CmdInfo); {$ENDIF} 1241 end; 1242 if not MovieMode then 1243 Notify(ntLoadState + CL.Progress * 128 div 1000); 1244 end; 1245 1246 if MovieMode then 1247 begin 1248 Notify(ntBackOn); 1249 Brain[bix[0]].Client(cBreakGame, -1, nil^); 1250 EndGame; 1251 Notify(ntStartGo); 1252 result := false; 1253 exit; 1254 end; 1255 1256 if StatRequest then 1257 GenerateStat(pTurn); 1258 assert(started); 1259 {$IFDEF TEXTLOG}CloseFile(TextLog); {$ENDIF} 1260 {$IFDEF LOADPERF}QueryPerformanceCounter(time_total); { time in s is: (time_total-time_total0)/PerfFreq }{$ENDIF} 1261 NoLogChanges; 1262 NoLogCityTileChanges; 1263 if LogFileName[1] = '~' then 1264 begin 1265 Delete(LogFileName, 1, 1); 1266 nLogOpened := -1 1267 end 1268 else 1269 nLogOpened := CL.State.nLog; 1270 1271 Mode := moPlaying; 1272 LastEndClientCommand := -1; 1273 if (GTestFlags and tfUncover <> 0) or (Difficulty[pTurn] = 0) then 1274 DiscoverAll(pTurn, lObserveSuper) { supervisor - all tiles visible } 1275 else 1276 DiscoverViewAreas(pTurn); 1277 1278 for p1 := 0 to nPl - 1 do 1279 if 1 shl p1 and (GAlive or GWatching) <> 0 then 1280 begin 1281 RecalcPeaceMap(p1); 1282 for ix := 0 to RW[p1].nEnemyUn - 1 do 1283 with RW[p1].EnemyUn[ix] do 1284 emix := RWemix[p1, Owner, mix]; 1285 Inform(p1); 1286 end; 1287 {$IFOPT O-}CheckBorders(-2); {$ENDIF} // for testing only 1288 Notify(ntEndInfo); 1289 if not LoadOK then 1290 begin 1291 NotifyMessage := SavePath + LogFileName; 1292 Notify(ntLoadError); 1293 end; 1294 Brain[bix[0]].Client(cShowGame, 0, nil^); 1295 Notify(ntBackOff); 1296 Inform(pTurn); 1297 ChangeClientWhenDone(cResume, 0, nil^, 0); 1298 end; // LoadGame 1299 1300 procedure InsertTerritoryUpdateCommands; 423 1301 var 424 ix: integer; 1302 p1, Command, Subject: integer; 1303 Data: pointer; 1304 FormerCLState: TCmdListState; 425 1305 begin 426 result:=false; 427 for ix:=0 to RW[p].nUn-1 do with RW[p].Un[ix] do 428 if (Loc>=0) and (SavedStatus<>Status) then result:=true; 429 for ix:=0 to RW[p].nCity-1 do with RW[p].City[ix] do 430 if (Loc>=0) and (SavedStatus<>Status) then result:=true; 431 for ix:=0 to RW[p].nModel-1 do with RW[p].Model[ix] do 432 if SavedStatus<>Status then result:=true; 433 for ix:=0 to RW[p].nEnemyCity-1 do with RW[p].EnemyCity[ix] do 434 if (Loc>=0) and (SavedStatus<>Status) then result:=true; 435 if RW[p].Data<>nil then for ix:=0 to Brain[bix[p]].DataSize-1 do 436 if PDWortList(SavedData[p])[ix]<>PDWortList(RW[p].Data)[ix] then result:=true 437 end; 438 439 procedure InitBrain(bix: integer); 440 var 441 InitModuleData: TInitModuleData; 442 begin 443 assert(bix<>bixSuper_Virtual); 444 with Brain[bix] do 1306 while CL.Progress < 1000 do 445 1307 begin 446 if Initialized then exit; 447 if bix>=bixFirstAI then 448 begin {get client function} 449 Notify(ntInitModule+bix); 450 if Flags and fDotNet>0 then 451 Client:=DotNetClient 1308 FormerCLState := CL.State; 1309 CL.Get(Command, p1, Subject, Data); 1310 if (Command = sIntExpandTerritory) and (p1 = pTurn) then 1311 begin 1312 IntServer(Command, p1, Subject, Data^); 1313 {$IFDEF TEXTLOG}WriteLn(TextLog, 'AfterTurn - ExpandTerritory'); {$ENDIF} 1314 end 452 1315 else 453 begin454 hm:=LoadLibrary(pchar(DLLName));455 if hm=0 then456 begin457 Client:=nil;458 Notify(ntDLLError+bix);459 end460 else461 begin462 Client:=GetProcAddress(hm,'client');463 if @Client=nil then Notify(ntClientError+bix);464 end465 end466 end;467 if @Client<>nil then468 1316 begin 469 Initialized:=true; 470 InitModuleData.Server:=@Server; 471 InitModuleData.DataVersion:=0; 472 InitModuleData.DataSize:=0; 473 InitModuleData.Flags:=0; 474 CallClient(bix, cInitModule, InitModuleData); 475 DataVersion:=InitModuleData.DataVersion; 476 DataSize:=(InitModuleData.DataSize+3) div 4; 477 if DataSize>MaxDataSize then DataSize:=0; 478 Flags:=Flags or InitModuleData.Flags; 479 end 480 end 481 end; 482 483 procedure SaveMap(FileName: string); 484 var 485 i: integer; 486 MapFile: TFileStream; 487 s: string[255]; 488 begin 489 MapFile:=TFileStream.Create(DataDir+'Maps\'+FileName, fmCreate or fmShareExclusive); 490 MapFile.Position:=0; 491 s:='cEvoMap'#0; MapFile.write(s[1],8); {file id} 492 i:=0; MapFile.write(i,4); {format id} 493 MapFile.write(MaxTurn,4); 494 MapFile.write(lx,4); 495 MapFile.write(ly,4); 496 MapFile.write(RealMap,MapSize*4); 497 MapFile.Free; 498 end; 499 500 function LoadMap(FileName: string): boolean; 501 var 502 i,Loc1: integer; 503 MapFile: TFileStream; 504 s: string[255]; 505 begin 506 result:=false; 507 MapFile:=nil; 508 try 509 MapFile:=TFileStream.Create(DataDir+'Maps\'+FileName, fmOpenRead or fmShareExclusive); 510 MapFile.Position:=0; 511 MapFile.read(s[1],8); {file id} 512 MapFile.read(i,4); {format id} 513 if i=0 then 514 begin 515 MapFile.read(i,4); //MaxTurn 516 MapFile.read(lx,4); 517 MapFile.read(ly,4); 518 ly:=ly and not 1; 519 if lx>lxmax then lx:=lxmax; 520 if ly>lymax then ly:=lymax; 521 MapSize:=lx*ly; 522 MapFile.read(RealMap,MapSize*4); 523 for Loc1:=0 to MapSize-1 do 524 begin 525 RealMap[Loc1]:=RealMap[Loc1] and ($7F01FFFF or fPrefStartPos or fStartPos) 526 or ($F shl 27); 527 if RealMap[Loc1] and (fTerrain or fSpecial)=fSwamp or fSpecial2 then 528 RealMap[Loc1]:=RealMap[Loc1] and not (fTerrain or fSpecial) or (fSwamp or fSpecial1); 529 if (RealMap[Loc1] and fDeadLands<>0) and (RealMap[Loc1] and fTerrain<>fArctic) then 530 RealMap[Loc1]:=RealMap[Loc1] and not (fTerrain or fSpecial) or fDesert; 531 end; 532 result:=true; 533 end; 534 MapFile.Free; 535 except 536 if MapFile<>nil then MapFile.Free; 537 end; 538 end; 539 540 procedure SaveGame(FileName: string; auto: boolean); 541 var 542 x,y,i,zero,Tile,nLocal: integer; 543 LogFile: TFileStream; 544 s: string[255]; 545 SaveMap: array[0..lxmax*lymax-1] of Byte; 546 begin 547 nLocal:=0; 548 for i:=0 to nPl-1 do if bix[i]=bixTerm then inc(nLocal); 549 if Difficulty[0]=0 then nLocal:=0; 550 if nLocal<=1 then for y:=0 to ly-1 do for x:=0 to lx-1 do 551 begin 552 Tile:=RW[0].Map[(x+SaveMapCenterLoc+lx shr 1) mod lx +lx*y]; 553 SaveMap[x+lx*y]:=Tile and fTerrain + Tile and (fCity or fUnit or fOwned) shr 16; 554 end; 555 556 if auto and AutoSaveExists then // append to existing file 557 LogFile:=TFileStream.Create(SavePath+FileName, 558 fmOpenReadWrite or fmShareExclusive) 559 else // create new file 560 LogFile:=TFileStream.Create(SavePath+FileName, fmCreate or fmShareExclusive); 561 562 zero:=0; 563 LogFile.Position:=0; 564 s:='cEvoBook'; LogFile.write(s[1],8); {file id} 565 i:=Version; LogFile.write(i,4); {c-evo version} 566 LogFile.write(ExeInfo.Time,4); 567 LogFile.write(lx,4); 568 LogFile.write(ly,4); 569 LogFile.write(LandMass,4); 570 if LandMass=0 then 571 LogFile.write(MapField^,MapSize*4); 572 573 LogFile.write(MaxTurn,4); 574 LogFile.write(RND,4); 575 LogFile.write(GTurn,4); 576 if nLocal>1 then // multiplayer game -- no quick view 577 begin i:=$80; LogFile.write(i,4); end 578 else LogFile.write(SaveMap,((MapSize-1) div 4+1)*4); 579 for i:=0 to nPl-1 do 580 if bix[i]<0 then LogFile.write(zero,4) 581 else 582 begin 583 if bixView[i]>=bixRandom then s:=Brain[bix[i]].FileName 584 else s:=Brain[bixView[i]].FileName; 585 move(zero,s[Length(s)+1],4); 586 LogFile.write(s,(Length(s) div 4+1)*4); 587 LogFile.write(OriginalDataVersion[i],4); 588 s:=''; {behavior} move(zero,s[Length(s)+1],4); 589 LogFile.write(s,(Length(s) div 4+1)*4); 590 LogFile.write(Difficulty[i],4); 591 end; 592 593 if auto and AutoSaveExists then CL.AppendToFile(LogFile, AutoSaveState) 594 else CL.SaveToFile(LogFile); 595 LogFile.Free; 596 if auto then 597 begin AutoSaveState:=CL.State; AutoSaveExists:=true end 598 end; 599 600 procedure StartGame; 601 var 602 i,p,p1,Human,nAlive,bixUni: integer; 603 Game: TNewGameData; 604 //GameEx: TNewGameExData; 605 path: shortstring; 606 BrainUsed: Set of 0..254; {used brains} 607 begin 608 for p1:=0 to nPl-1 do 609 begin 610 if bixView[p1]=bixSuper_Virtual then bix[p1]:=bixTerm // supervisor and local human use same module 611 else if bixView[p1]=bixRandom then 612 if nBrain<=bixFirstAI then bix[p1]:=-1 613 else bix[p1]:=bixFirstAI+random(nBrain-bixFirstAI) 614 else bix[p1]:=bixView[p1]; 615 if bixView[p1]<0 then Difficulty[p1]:=-1; 616 end; 617 618 if bix[0]<>bixNoTerm then Notify(ntInitLocalHuman); 619 BrainUsed:=[]; 620 for p:=0 to nPl-1 do 621 if (bix[p]>=0) and ((Mode<>moMovie) or (p=0)) then 622 begin {initiate selected control module} 623 AIInfo[p]:=Brain[bix[p]].Name+#0; 624 InitBrain(bix[p]); 625 if Mode=moPlaying then 626 begin // new game, this data version is original 627 OriginalDataVersion[p]:=Brain[bix[p]].DataVersion; 628 ProcessClientData[p]:=true; 629 end 630 else // loading game, compare with data version read from file 631 ProcessClientData[p]:=ProcessClientData[p] 632 and (OriginalDataVersion[p]=Brain[bix[p]].DataVersion); 633 if @Brain[bix[p]].Client=nil then // client function not found 634 if bix[0]=bixNoTerm then 635 bix[p]:=-1 636 else 637 begin 638 bix[p]:=bixTerm; 639 OriginalDataVersion[p]:=-1; 640 ProcessClientData[p]:=false; 641 end; 642 if bix[p]>=0 then include(BrainUsed,bix[p]) 643 end; 644 645 Notify(ntCreateWorld); 646 nAlive:=0; 647 GAlive:=0; 648 if Mode=moMovie then GWatching:=1 649 else GWatching:=0; 650 GAI:=0; 651 for p1:=0 to nPl-1 do if bix[p1]>=0 then 652 begin 653 if Mode<>moMovie then inc(GWatching,1 shl p1); 654 if bix[p1]>=bixFirstAI then inc(GAI,1 shl p1); 655 if Difficulty[p1]>0 then 656 begin inc(GAlive,1 shl p1); inc(nAlive); end; 657 ServerVersion[p1]:=Brain[bix[p1]].ServerVersion; 658 end; 659 WinOnAlone:= (bix[0]=bixNoTerm) and (nAlive>1); 660 GWinner:=0; 661 GColdWarStart:=-ColdWarTurns-1; 662 uixSelectedTransport:=-1; 663 SpyMission:=smSabotageProd; 664 for p1:=0 to nPl-1 do 665 DebugMap[p1]:=nil; 666 667 GTurn:=0; 668 for i:=0 to 27 do with GWonder[i] do 669 begin CityID:=-1; EffectiveOwner:=-1 end; 670 FillChar(GShip,SizeOf(GShip),0); 671 672 for p:=0 to nPl-1 do if 1 shl p and (GAlive or GWatching)<>0 then with RW[p] do 673 begin 674 Government:=gDespotism; 675 Money:=StartMoney; 676 TaxRate:=30; 677 LuxRate:=0; 678 Research:=0; 679 ResearchTech:=-2; 680 AnarchyStart:=-AnarchyTurns-1; 681 Happened:=0; 682 LastValidStat[p]:=-1; 683 Worked[p]:=0; 684 Founded[p]:=0; 685 DevModelTurn[p]:=-1; 686 OracleIncome:=0; 687 688 if Brain[bix[p]].DataSize>0 then 689 begin 690 GetMem(SavedData[p], Brain[bix[p]].DataSize*4); 691 GetMem(Data, Brain[bix[p]].DataSize*4); 692 FillChar(SavedData[p]^,Brain[bix[p]].DataSize*4,0); 693 FillChar(Data^,Brain[bix[p]].DataSize*4,0); 694 end 695 else begin Data:=nil; SavedData[p]:=nil end; 696 nBattleHistory:=0; 697 BattleHistory:=nil; 698 {if bix[p]=bixTerm then 699 begin 700 GetMem(BorderHelper,MapSize); 701 FillChar(BorderHelper^,MapSize,0); 702 end 703 else} BorderHelper:=nil; 704 for i:=0 to nStat-1 do GetMem(Stat[i,p],4*(MaxTurn+1)); 705 if Brain[bix[p]].Flags and fDotNet<>0 then 706 begin 707 GetMem(RW[p].DefaultDebugMap, MapSize*4); 708 FillChar(RW[p].DefaultDebugMap^, MapSize*4, 0); 709 DebugMap[p]:=RW[p].DefaultDebugMap; 710 end 711 else RW[p].DefaultDebugMap:=nil; 712 713 {!!!for i:=0 to nShipPart-1 do GShip[p].Parts[i]:=random((3-i)*2);{} 714 end; 715 716 if LandMass>0 then 717 begin // random map 718 InitRandomGame; 719 PreviewElevation:=false; 720 MapField:=nil; 721 end 722 else 723 begin // predefined map 724 if Mode=moPlaying then 725 LoadMap(MapFileName); // new game -- load map from file 726 GetMem(MapField,MapSize*4); 727 move(RealMap,MapField^,MapSize*4); 728 Human:=0; 729 for p1:=0 to nPl-1 do if bix[p1]=bixTerm then inc(Human,1 shl p1); 730 InitMapGame(Human); 731 end; 732 CityProcessing.InitGame; 733 UnitProcessing.InitGame; 734 for p:=0 to nPl-1 do if 1 shl p and (GAlive or GWatching)<>0 then 735 Inform(p); 736 737 pTurn:=-1; 738 if bix[0]<>bixNoTerm then 739 Notify(ntInitLocalHuman); 740 Game.lx:=lx; Game.ly:=ly; Game.LandMass:=LandMass; Game.MaxTurn:=MaxTurn; 741 move(Difficulty,Game.Difficulty,SizeOf(Difficulty)); 742 //GameEx.lx:=lx; GameEx.ly:=ly; GameEx.LandMass:=LandMass; 743 //GameEx.MaxTurn:=MaxTurn; GameEx.RND:=RND; 744 //move(Difficulty,GameEx.Difficulty,SizeOf(Difficulty)); 745 AICredits:=''; 746 for i:=0 to nBrain-1 do if Brain[i].Initialized then 747 if i in BrainUsed then 748 begin 749 if i>=bixFirstAI then 750 Notify(ntInitPlayers); 751 for p:=0 to nPl-1 do 752 begin 753 if bix[p]=i then 754 Game.RO[p]:=@RW[p] 755 else Game.RO[p]:=nil; 756 if (i=bixTerm) and (Difficulty[0]=0) and (bix[p]>=0) then 757 Game.SuperVisorRO[p]:=@RW[p] 758 else Game.SuperVisorRO[p]:=nil; 759 end; 760 if Brain[i].Flags and fDotNet>0 then 761 begin 762 path:=Brain[i].DLLName; 763 move(path[1], Game.AssemblyPath, Length(path)); 764 Game.AssemblyPath[Length(path)]:=#0; 765 end 766 else Game.AssemblyPath[0]:=#0; 767 case Mode of 768 moLoading, moLoading_Fast: CallClient(i, cLoadGame, Game); 769 moMovie: CallClient(i, cMovie, Game); 770 moPlaying: CallClient(i, cNewGame, Game); 771 end; 772 if (i>=bixFirstAI) and (Brain[i].Credits<>'') then 773 if AICredits='' then AICredits:=Brain[i].Credits 774 else AICredits:=AICredits+'\'+Brain[i].Credits 775 end 776 else 777 begin {module no longer used -- unload} 778 CallClient(i, cReleaseModule, nil^); 779 if i>=bixFirstAI then 780 begin 781 if Brain[i].Flags and fDotNet=0 then 782 FreeLibrary(Brain[i].hm); 783 Brain[i].Client:=nil; 784 end; 785 Brain[i].Initialized:=false; 786 end; 787 AICredits:=AICredits+#0; 788 789 if bix[0]<>bixNoTerm then 790 begin 791 // uni ai? 792 bixUni:=-1; 793 for p1:=0 to nPl-1 do if bix[p1]>=bixFirstAI then 794 if bixUni=-1 then bixUni:=bix[p1] 795 else if bixUni<>bix[p1] then bixUni:=-2; 796 for p1:=0 to nPl-1 do if bix[p1]>=bixFirstAI then 797 begin 798 if bixUni=-2 then NotifyMessage:=Brain[bix[p1]].FileName 799 else NotifyMessage:=''; 800 Notify(ntSetAIName+p1); 1317 CL.State := FormerCLState; 1318 Break 801 1319 end 802 1320 end; 803 804 CheckBorders(-1); 805 {$IFOPT O-}InvalidTreatyMap:=0;{$ENDIF} 806 AutoSaveExists:=false; 807 pDipActive:=-1; 808 pTurn:=0; 809 810 if Mode>=moMovie then 1321 {$IFOPT O-}InvalidTreatyMap := 0; {$ENDIF} 1322 end; 1323 1324 procedure StartNewGame(const Path, FileName, Map: string; 1325 Newlx, Newly, NewLandMass, NewMaxTurn: integer); 1326 var 1327 p: integer; 1328 begin 1329 Notify(ntStartDone); 1330 SavePath := Path; 1331 LogFileName := FileName; 1332 MapFileName := Map; 1333 if FastContact then 1334 begin 1335 lx := 24; 1336 ly := 42; 1337 end 1338 else 1339 begin 1340 lx := Newlx; 1341 ly := Newly 1342 end; 1343 MapSize := lx * ly; 1344 if MapFileName <> '' then 1345 LandMass := 0 1346 else 1347 LandMass := NewLandMass; 1348 MaxTurn := NewMaxTurn; 1349 Randomize; 1350 RND := RandSeed; 1351 Mode := moPlaying; 1352 CL := TCmdList.Create; 1353 StartGame; 1354 NoLogChanges; 1355 for p := 0 to nPl - 1 do 1356 if bix[p] >= 0 then 1357 CallPlayer(cGetReady, p, nil^); 1358 LogChanges; 1359 CL.Put(sTurn, 0, 0, nil); 1360 BeforeTurn0; 1361 NoLogCityTileChanges; 1362 GenerateStat(pTurn); 1363 nLogOpened := -1; 1364 LastEndClientCommand := -1; 1365 Brain[bix[0]].Client(cShowGame, 0, nil^); 1366 Notify(ntBackOff); 1367 Inform(pTurn); 1368 ChangeClientWhenDone(cTurn, 0, nil^, 0) 1369 end; 1370 1371 procedure DirectHelp(Command: integer); 1372 begin 1373 InitBrain(bixTerm); 1374 Brain[bixTerm].Client(Command, -1, nil^); 1375 AICredits := #0; 1376 end; 1377 1378 procedure EditMap(const Map: string; Newlx, Newly, NewLandMass: integer); 1379 var 1380 p1, Loc1: integer; 1381 Game: TNewGameData; 1382 begin 1383 Notify(ntStartDone); 1384 Notify(ntInitLocalHuman); 1385 MapFileName := Map; 1386 lx := Newlx; 1387 ly := Newly; 1388 MapSize := lx * ly; 1389 LandMass := NewLandMass; 1390 bix[0] := bixTerm; 1391 Difficulty[0] := 0; 1392 InitBrain(bixTerm); 1393 1394 Randomize; 1395 GAlive := 0; 1396 GWatching := 1; 1397 if not LoadMap(MapFileName) then 1398 for Loc1 := 0 to MapSize - 1 do 1399 RealMap[Loc1] := fOcean or ($F shl 27); 1400 CL := nil; 1401 InitMapEditor; 1402 RW[0].Data := nil; 1403 RW[0].BorderHelper := nil; 1404 RW[0].Alive := 0; 1405 Game.lx := lx; 1406 Game.ly := ly; 1407 Game.RO[0] := @RW[0]; 1408 Game.Difficulty[0] := 0; 1409 for p1 := 1 to nPl - 1 do 1410 begin 1411 Game.RO[p1] := nil; 1412 Game.Difficulty[p1] := -1 1413 end; 1414 Brain[bixTerm].Client(cNewMap, -1, Game); 1415 1416 DiscoverAll(0, lObserveSuper); 811 1417 Notify(ntEndInfo); 812 end;{StartGame} 813 814 procedure EndGame; 1418 Brain[bix[0]].Client(cShowGame, 0, nil^); 1419 Notify(ntBackOff); 1420 ChangeClientWhenDone(cEditMap, 0, nil^, 0) 1421 end; 1422 1423 procedure DestroySpacePort_TellPlayers(p, pCapturer: integer); 815 1424 var 816 i,p1: integer; 1425 cix, i, p1: integer; 1426 ShowShipChange: TShowShipChange; 817 1427 begin 818 if LandMass=0 then FreeMem(MapField); 819 for p1:=0 to nPl-1 do if bix[p1]>=0 then 1428 // stop ship part production 1429 for cix := 0 to RW[p].nCity - 1 do 1430 with RW[p].City[cix] do 1431 if (Loc >= 0) and (Project and cpImp <> 0) and 1432 ((Project and cpIndex = woMIR) or 1433 (Imp[Project and cpIndex].Kind = ikShipPart)) then 1434 begin 1435 inc(RW[p].Money, Prod0); 1436 Prod := 0; 1437 Prod0 := 0; 1438 Project := cpImp + imTrGoods; 1439 Project0 := cpImp + imTrGoods 1440 end; 1441 1442 // destroy ship 1443 with GShip[p] do 1444 if Parts[0] + Parts[1] + Parts[2] > 0 then 1445 begin 1446 for i := 0 to nShipPart - 1 do 1447 begin 1448 ShowShipChange.Ship1Change[i] := -Parts[i]; 1449 if pCapturer >= 0 then 1450 begin 1451 ShowShipChange.Ship2Change[i] := Parts[i]; 1452 inc(GShip[pCapturer].Parts[i], Parts[i]); 1453 end; 1454 Parts[i] := 0; 1455 end; 1456 if Mode >= moMovie then 1457 begin 1458 if pCapturer >= 0 then 1459 ShowShipChange.Reason := scrCapture 1460 else 1461 ShowShipChange.Reason := scrDestruction; 1462 ShowShipChange.Ship1Owner := p; 1463 ShowShipChange.Ship2Owner := pCapturer; 1464 for p1 := 0 to nPl - 1 do 1465 if 1 shl p1 and (GAlive or GWatching) <> 0 then 1466 begin 1467 move(GShip, RW[p1].Ship, SizeOf(GShip)); 1468 if 1 shl p1 and GWatching <> 0 then 1469 CallPlayer(cShowShipChange, p1, ShowShipChange); 1470 end; 1471 end 1472 end 1473 end; 1474 1475 procedure DestroyCity_TellPlayers(p, cix: integer; SaveUnits: boolean); 1476 begin 1477 if RW[p].City[cix].built[imSpacePort] > 0 then 1478 DestroySpacePort_TellPlayers(p, -1); 1479 DestroyCity(p, cix, SaveUnits); 1480 end; 1481 1482 procedure ChangeCityOwner_TellPlayers(pOld, cixOld, pNew: integer); 1483 begin 1484 if RW[pOld].City[cixOld].built[imSpacePort] > 0 then 1485 if RW[pNew].NatBuilt[imSpacePort] > 0 then 1486 DestroySpacePort_TellPlayers(pOld, pNew) 1487 else 1488 DestroySpacePort_TellPlayers(pOld, -1); 1489 ChangeCityOwner(pOld, cixOld, pNew); 1490 end; 1491 1492 procedure CheckWin(p: integer); 1493 var 1494 i: integer; 1495 ShipComplete: boolean; 1496 begin 1497 ShipComplete := true; 1498 for i := 0 to nShipPart - 1 do 1499 if GShip[p].Parts[i] < ShipNeed[i] then 1500 ShipComplete := false; 1501 if ShipComplete then 1502 GWinner := GWinner or 1 shl p; // game won! 1503 end; 1504 1505 procedure BeforeTurn; 1506 var 1507 i, p1, uix, cix, V21, Loc1, Cost, Job0, nAlive, nAppliers, ad, OldLoc, 1508 SiegedTiles, nUpdateLoc: integer; 1509 UpdateLoc: array [0 .. numax - 1] of integer; 1510 Radius: TVicinity21Loc; 1511 ShowShipChange: TShowShipChange; 1512 TribeExtinct, JobDone, MirBuilt: boolean; 1513 begin 1514 {$IFOPT O-}assert(1 shl pTurn and InvalidTreatyMap = 0); {$ENDIF} 1515 assert(1 shl pTurn and (GAlive or GWatching) <> 0); 1516 if (1 shl pTurn and GAlive = 0) and (Difficulty[pTurn] > 0) then 1517 exit; 1518 1519 if (GWonder[woGrLibrary].EffectiveOwner = pTurn) and (GWinner = 0) then 1520 begin // check great library effect 1521 nAlive := 0; 1522 for p1 := 0 to nPl - 1 do 1523 if 1 shl p1 and GAlive <> 0 then 1524 inc(nAlive); 1525 for ad := 0 to nAdv - 5 do 1526 if RW[pTurn].Tech[ad] < tsSeen then 1527 begin 1528 nAppliers := 0; 1529 for p1 := 0 to nPl - 1 do 1530 if (p1 <> pTurn) and (1 shl p1 and GAlive <> 0) and 1531 (RW[p1].Tech[ad] >= tsApplicable) then 1532 inc(nAppliers); 1533 if nAppliers * 2 > nAlive then 1534 begin 1535 SeeTech(pTurn, ad); 1536 inc(nTech[pTurn]); 1537 if Mode >= moMovie then 1538 CallPlayer(cShowGreatLibTech, pTurn, ad); 1539 // do not call CallPlayer(pTurn) while map is invalid 1540 end; 1541 end; 1542 end; 1543 1544 MaskD(ObserveLevel, MapSize, not Cardinal(3 shl (2 * pTurn))); 1545 if Mode > moLoading_Fast then 1546 MaskD(RW[pTurn].Map^, MapSize, not Cardinal(fUnit or fHiddenUnit or 1547 fStealthUnit or fObserved or fSpiedOut or fOwned or fOwnZoCUnit or 1548 fInEnemyZoC)); 1549 RW[pTurn].nEnemyUn := 0; 1550 1551 MirBuilt := false; 1552 if (Difficulty[pTurn] > 0) and (GWinner = 0) then 1553 with RW[pTurn] do 1554 begin 1555 if nCity > 0 then 1556 for p1 := 0 to nPl - 1 do 1557 if GTurn = EvaStart[p1] + PeaceEvaTurns then 1558 begin // peace contract -- remove all units from p1's territory 1559 Loc1 := City[0].Loc; // search destination for homeless units 1560 for cix := 1 to nCity - 1 do 1561 if (City[cix].Loc >= 0) and 1562 ((Loc1 < 0) or (City[cix].built[imPalace] > 0)) then 1563 Loc1 := City[cix].Loc; 1564 for uix := 0 to nUn - 1 do 1565 with Un[uix] do 1566 if (Loc >= 0) and (Model[mix].Kind <> mkDiplomat) and 1567 ((Home >= 0) or (Loc1 >= 0)) and 1568 (RealMap[Loc] shr 27 = Cardinal(p1)) then 1569 begin 1570 OldLoc := Loc; 1571 if Master >= 0 then 1572 begin // transport unload 1573 if Model[mix].Domain = dAir then 1574 dec(Un[Master].AirLoad) 1575 else 1576 dec(Un[Master].TroopLoad); 1577 Master := -1; 1578 end 1579 else 1580 FreeUnit(pTurn, uix); 1581 1582 if Home >= 0 then 1583 Loc := City[Home].Loc 1584 else 1585 Loc := Loc1; 1586 PlaceUnit(pTurn, uix); 1587 UpdateUnitMap(OldLoc); 1588 UpdateUnitMap(Loc); 1589 Flags := Flags or unWithdrawn; 1590 Happened := Happened or phPeaceEvacuation; 1591 end 1592 end; 1593 1594 if Mode >= moMovie then 1595 FillChar(ShowShipChange, SizeOf(ShowShipChange), 0); 1596 TribeExtinct := true; 1597 nUpdateLoc := 0; 1598 for cix := 0 to nCity - 1 do 1599 with City[cix] do 1600 if Loc >= 0 then 1601 begin { next turn for all cities - city loop 1 } 1602 // if ServerVersion[pTurn]>=$000EF0 then 1603 // Flags:=Flags and (chFounded or chCaptured or chProductionSabotaged or chDisorder) 1604 // else Flags:=Flags and (chCaptured or chProductionSabotaged or chDisorder); 1605 // check for siege 1606 SiegedTiles := 0; 1607 V21_to_Loc(Loc, Radius); 1608 for V21 := 1 to 26 do 1609 if Tiles and (1 shl V21) and not(1 shl CityOwnTile) <> 0 then 1610 begin 1611 Loc1 := Radius[V21]; 1612 assert((Loc1 >= 0) and (Loc1 < MapSize) and 1613 (UsedByCity[Loc1] = Loc)); 1614 p1 := RealMap[Loc1] shr 27; 1615 if (RealMap[Loc1] and fCity <> 0) or (p1 < nPl) and 1616 (p1 <> pTurn) and (RW[pTurn].Treaty[p1] >= trPeace) or 1617 (ZoCMap[Loc1] > 0) and (Occupant[Loc1] <> pTurn) and 1618 (Treaty[Occupant[Loc1]] < trPeace) then 1619 begin 1620 Tiles := Tiles and not(1 shl V21); 1621 UsedByCity[Loc1] := -1; 1622 Flags := Flags or chSiege; 1623 inc(SiegedTiles); 1624 end; 1625 end; 1626 while SiegedTiles > 0 do // replace sieged tiles 1627 begin 1628 if not AddBestCityTile(pTurn, cix) then 1629 Break; 1630 dec(SiegedTiles); 1631 end; 1632 1633 if Flags and chFounded = 0 then 1634 begin 1635 // CollectCityResources(pTurn,cix); // old style 1636 1637 if CityTurn(pTurn, cix) then 1638 TribeExtinct := false 1639 else 1640 begin // city is erased 1641 RemoveDomainUnits(dSea, pTurn, Loc); 1642 RemoveDomainUnits(dAir, pTurn, Loc); 1643 Map[Loc] := Map[Loc] and not fCity; // !!! do this in inner core 1644 UpdateLoc[nUpdateLoc] := Loc; 1645 inc(nUpdateLoc); 1646 DestroyCity_TellPlayers(pTurn, cix, true); 1647 end; 1648 1649 if (Flags and chProduction <> 0) and (Project0 and cpImp <> 0) 1650 then 1651 begin 1652 if Project0 and cpIndex = woMIR then // MIR completed 1653 MirBuilt := true 1654 else if Project0 and cpIndex = woManhattan then 1655 GColdWarStart := GTurn 1656 else if Imp[Project0 and cpIndex].Kind = ikShipPart 1657 then { ship parts produced } 1658 inc(ShowShipChange.Ship1Change[Project0 and cpIndex - 1659 imShipComp]); 1660 end 1661 end 1662 end; { city loop 1 } 1663 if nUpdateLoc > 0 then 1664 begin 1665 CheckBorders(-1, pTurn); 1666 for i := 0 to nUpdateLoc - 1 do 1667 UpdateUnitMap(UpdateLoc[i], true); 1668 if Mode >= moMovie then 1669 for p1 := 0 to nPl - 1 do 1670 if (1 shl p1 and GWatching <> 0) and (p1 <> pTurn) then 1671 for i := 0 to nUpdateLoc - 1 do 1672 if ObserveLevel[UpdateLoc[i]] shr (2 * p1) and 3 >= lObserveUnhidden 1673 then 1674 CallPlayer(cShowCityChanged, p1, UpdateLoc[i]); 1675 end; 1676 1677 for uix := 0 to nUn - 1 do 1678 with Un[uix] do 1679 if Loc >= 0 then 1680 begin // unit loop 2 1681 if Health < 100 then 1682 Recover(pTurn, uix); 1683 1684 if Flags and unMountainDelay <> 0 then 1685 begin 1686 Movement := 0; 1687 Flags := Flags and not unMountainDelay 1688 end 1689 else 1690 Movement := UnitSpeed(pTurn, mix, Health); { refresh movement } 1691 1692 assert(Loc >= 0); 1693 if Model[mix].Kind <> mkDiplomat then 1694 begin // check treaty violation 1695 p1 := RealMap[Loc] shr 27; 1696 if (p1 < nPl) and (p1 <> pTurn) and (Treaty[p1] >= trPeace) then 1697 begin 1698 if (Job in [jCity, jPillage, jClear, jAfforest, jTrans]) or 1699 (Job in [jIrr, jMine, jFort, jBase]) and 1700 (RealMap[Loc] and fTerImp <> 0) then 1701 Job := jNone; 1702 if (GTurn > EvaStart[p1] + PeaceEvaTurns) and 1703 (Treaty[p1] <> trAlliance) then 1704 begin 1705 EvaStart[p1] := GTurn; 1706 Happened := Happened or phPeaceViolation; 1707 if Mode >= moMovie then 1708 CallPlayer(cShowPeaceViolation, p1, pTurn); 1709 end; 1710 end; 1711 end; 1712 1713 if ServerVersion[pTurn] >= $000EF0 then 1714 begin 1715 if (Health <= 0) or TribeExtinct then 1716 RemoveUnit_UpdateMap(pTurn, uix); 1717 end 1718 end; 1719 1720 if ServerVersion[pTurn] < $000EF0 then 1721 for uix := 0 to nUn - 1 do 1722 with Un[uix] do 1723 if Loc >= 0 then 1724 begin // unit loop 3 1725 Loc1 := Loc; 1726 Job0 := Job; 1727 if Job <> jNone then 1728 JobDone := Work(pTurn, uix); 1729 { settlers do terrain improvement jobs } 1730 if (Health <= 0) or TribeExtinct then 1731 RemoveUnit_UpdateMap(pTurn, uix); 1732 1733 if (Job0 = jCity) and JobDone then // new city 1734 begin 1735 AddBestCityTile(pTurn, RW[pTurn].nCity - 1); 1736 UpdateUnitMap(Loc1, true); 1737 if Mode >= moMovie then // tell enemies 1738 for p1 := 0 to nPl - 1 do 1739 if (1 shl p1 and GWatching <> 0) and (p1 <> pTurn) and 1740 (ObserveLevel[Loc1] and (3 shl (2 * p1)) > 0) then 1741 CallPlayer(cShowCityChanged, p1, Loc1); 1742 end 1743 end; 1744 1745 { pollution - city loop 3 } 1746 for cix := 0 to nCity - 1 do 1747 with City[cix] do 1748 if (Loc >= 0) and (Pollution >= MaxPollution) then 1749 Pollute(pTurn, cix); 1750 1751 CompactLists(pTurn); 1752 if (nUn = 0) and (nCity = 0) then 1753 begin // nation made extinct 1754 Happened := Happened or phExtinct; 1755 GAlive := GAlive and not(1 shl pTurn); 1756 Stat[stPop, pTurn, GTurn] := 0; 1757 Stat[stMil, pTurn, GTurn] := 0; 1758 Stat[stScience, pTurn, GTurn] := 0; 1759 Stat[stExplore, pTurn, GTurn] := 0; 1760 Stat[stTerritory, pTurn, GTurn] := 0; 1761 Stat[stWork, pTurn, GTurn] := 0; 1762 for p1 := 0 to nPl - 1 do 1763 if 1 shl p1 and (GAlive or GWatching) <> 0 then 1764 begin 1765 if p1 <> pTurn then 1766 begin 1767 GiveCivilReport(p1, pTurn); 1768 if (GTestFlags and tfUncover <> 0) or (Difficulty[p1] = 0) or 1769 (RW[p1].Treaty[pTurn] = trAlliance) then 1770 GiveMilReport(p1, pTurn); 1771 end; 1772 with RW[p1] do 1773 begin 1774 Alive := GAlive; 1775 for Loc1 := 0 to MapSize - 1 do 1776 if Territory[Loc1] = pTurn then 1777 // remove territory of extinct nation from player maps 1778 begin 1779 Territory[Loc1] := -1; 1780 Map[Loc1] := Map[Loc1] and not fPeace 1781 end 1782 end; 1783 end; 1784 exit 1785 end; 1786 1787 // check research 1788 Cost := TechCost(pTurn); 1789 if GTestFlags and tfImmAdvance <> 0 then 1790 Research := Cost; 1791 if (Happened and phTech = 0) and (Research >= Cost) then 1792 begin 1793 if ResearchTech = adMilitary then 1794 EnableDevModel(pTurn) { new Unit class initiated } 1795 else if ResearchTech >= 0 then 1796 DiscoverTech(pTurn, ResearchTech); 1797 1798 dec(Research, Cost); 1799 Happened := Happened or phTech; 1800 ResearchTech := -1 1801 end 1802 else if (ResearchTech = -2) and (nCity > 0) then 1803 begin 1804 Happened := Happened or phTech; 1805 ResearchTech := -1 1806 end; 1807 1808 if Credibility < MaxCredibility then 1809 for p1 := 0 to nPl - 1 do 1810 if (p1 <> pTurn) and (1 shl p1 and GAlive <> 0) and 1811 (Treaty[p1] >= trPeace) then 1812 begin 1813 inc(Credibility); 1814 Break 1815 end; 1816 1817 if GWinner = 0 then 1818 CheckWin(pTurn); 1819 if (Mode >= moMovie) and (GWinner = 0) and 1820 ((ShowShipChange.Ship1Change[0] > 0) or 1821 (ShowShipChange.Ship1Change[1] > 0) or 1822 (ShowShipChange.Ship1Change[2] > 0)) then 1823 begin 1824 ShowShipChange.Reason := scrProduction; 1825 ShowShipChange.Ship1Owner := pTurn; 1826 ShowShipChange.Ship2Owner := -1; 1827 for p1 := 0 to nPl - 1 do 1828 if (p1 <> pTurn) and (1 shl p1 and (GAlive or GWatching) <> 0) then 1829 begin 1830 move(GShip, RW[p1].Ship, SizeOf(GShip)); 1831 if 1 shl p1 and GWatching <> 0 then 1832 CallPlayer(cShowShipChange, p1, ShowShipChange); 1833 end 1834 end; 1835 if WinOnAlone and (GAlive and not(1 shl pTurn or 1) = 0) then 1836 GWinner := 1 shl pTurn; // break if only one nation left 1837 1838 if GTurn = AnarchyStart + AnarchyTurns then 1839 begin 1840 AnarchyStart := -AnarchyTurns - 1; 1841 Government := gDespotism; 1842 for p1 := 0 to nPl - 1 do 1843 if (p1 <> pTurn) and ((GAlive or GWatching) and (1 shl p1) <> 0) then 1844 RW[p1].EnemyReport[pTurn].Government := gDespotism; 1845 inc(Happened, phChangeGov) 1846 end; 1847 end; // if Difficulty[pTurn]>0 1848 1849 if (pTurn = 0) and (GWinner > 0) then 1850 begin // game over, give world map and all reports to player 0 1851 DiscoverAll(pTurn, lObserveSuper); 1852 for p1 := 1 to nPl - 1 do 1853 if 1 shl p1 and GAlive <> 0 then 1854 begin 1855 if RW[pTurn].Treaty[p1] < trNone then 1856 begin 1857 RW[pTurn].Treaty[p1] := trNone; 1858 RW[p1].Treaty[pTurn] := trNone; 1859 end; 1860 GiveCivilReport(pTurn, p1); 1861 GiveMilReport(pTurn, p1); 1862 end; 1863 end 1864 else 820 1865 begin 821 for i:=0 to nStat-1 do FreeMem(Stat[i,p1]); 822 if RW[p1].BattleHistory<>nil then FreeMem(RW[p1].BattleHistory); 823 {if RW[p1].BorderHelper<>nil then FreeMem(RW[p1].BorderHelper);} 824 FreeMem(RW[p1].Data); 825 FreeMem(SavedData[p1]); 826 if RW[p1].DefaultDebugMap<>nil then 827 FreeMem(RW[p1].DefaultDebugMap); 828 end; 829 UnitProcessing.ReleaseGame; 830 CityProcessing.ReleaseGame; 831 Database.ReleaseGame; 832 CL.Free; 833 end; 834 835 procedure GenerateStat(p: integer); 836 var 837 cix,uix: integer; 838 begin 839 if Difficulty[p]>0 then with RW[p] do 840 begin 841 Stat[stPop,p,GTurn]:=0; 842 for cix:=0 to nCity-1 do if City[cix].Loc>=0 then 843 inc(Stat[stPop,p,GTurn],City[cix].Size); 844 Stat[stScience,p,GTurn]:=Researched[p]*50; 845 if (RW[p].ResearchTech>=0) and (RW[p].ResearchTech<>adMilitary) then 846 inc(Stat[stScience,p,GTurn], 847 Research*100 div TechBaseCost(nTech[p],Difficulty[p])); 848 Stat[stMil,p,GTurn]:=0; 849 for uix:=0 to nUn-1 do if Un[uix].Loc>=0 then 850 with Model[Un[uix].mix] do 851 begin 852 if (Kind<=mkEnemyDeveloped) and (Un[uix].mix<>1) then 853 inc(Stat[stMil,p,GTurn],Weight*MStrength*Un[uix].Health div 100) 854 else if Domain=dGround then inc(Stat[stMil,p,GTurn],(Attack+2*Defense)*Un[uix].Health div 100) 855 else inc(Stat[stMil,p,GTurn],(Attack+Defense)*Un[uix].Health div 100); 856 case Kind of 857 mkSlaves: inc(Stat[stPop,p,GTurn]); 858 mkSettler: inc(Stat[stPop,p,GTurn],2); 859 end; 860 end; 861 Stat[stMil,p,GTurn]:=Stat[stMil,p,GTurn] div 16; 862 Stat[stExplore,p,GTurn]:=Discovered[p]; 863 Stat[stTerritory,p,GTurn]:=TerritoryCount[p]; 864 Stat[stWork,p,GTurn]:=Worked[p]; 865 LastValidStat[p]:=GTurn; 866 end; 867 end; 868 869 procedure LogCityTileChanges; 870 var 871 cix: integer; 872 begin 873 for cix:=0 to RW[pTurn].nCity-1 do 874 with RW[pTurn].City[cix] do if Loc>=0 then 1866 // show observed areas 1867 if (GTestFlags and tfUncover <> 0) or (Difficulty[pTurn] = 0) 1868 then { supervisor - all tiles visible } 875 1869 begin 876 { if SavedResourceWeights[cix]<>ResourceWeights then 877 begin // log city resource weight changes 878 CL.Put(sSetCityResourceWeights, pTurn, cix, @ResourceWeights); 879 SavedResourceWeights[cix]:=ResourceWeights; 880 end;} 881 if SavedTiles[cix]<>Tiles then 882 begin // log city tile changes 883 CL.Put(sSetCityTiles, pTurn, cix, @Tiles); 884 SavedTiles[cix]:=Tiles; 885 end; 886 end; 887 end; 888 889 procedure NoLogCityTileChanges; 890 var 891 cix: integer; 892 begin 893 for cix:=0 to RW[pTurn].nCity-1 do 894 with RW[pTurn].City[cix] do if Loc>=0 then 1870 if (bix[pTurn] <> bixNoTerm) and 1871 ((Difficulty[pTurn] > 0) or (Mode > moLoading_Fast)) then 1872 DiscoverAll(pTurn, lObserveSuper) 1873 end 1874 else 895 1875 begin 896 // SavedResourceWeights[cix]:=ResourceWeights; 897 SavedTiles[cix]:=Tiles; 898 end; 899 end; 900 901 function HasCityTileChanges: boolean; 902 var 903 cix: integer; 904 begin 905 result:=false; 906 for cix:=0 to RW[pTurn].nCity-1 do 907 with RW[pTurn].City[cix] do if Loc>=0 then 908 begin 909 // if SavedResourceWeights[cix]<>ResourceWeights then result:=true; 910 if SavedTiles[cix]<>Tiles then result:=true; 911 end; 912 end; 913 914 procedure BeforeTurn0; 915 var 916 p1,uix: integer; 917 begin 918 for uix:=0 to RW[pTurn].nUn-1 do {init movement points for first turn} 919 with RW[pTurn].Un[uix] do Movement:=RW[pTurn].Model[mix].Speed; 920 921 if Difficulty[pTurn]>0 then 922 DiscoverViewAreas(pTurn) 923 else {supervisor} 924 begin 925 DiscoverAll(pTurn,lObserveSuper); 926 for p1:=1 to nPl-1 do 927 if 1 shl p1 and GAlive<>0 then 928 begin 929 GiveCivilReport(pTurn, p1); 930 GiveMilReport(pTurn, p1) 931 end; 932 end; 933 //CheckContact; 934 end; 935 936 function LoadGame(const Path, FileName: string; Turn: integer; MovieMode: boolean): boolean; 937 var 938 i,j,ix,d,p1,Command,Subject: integer; 939 {$IFDEF TEXTLOG}LoadPos0: integer;{$ENDIF} 940 Data: pointer; 941 LogFile: TFileStream; 942 FormerCLState: TCmdListState; 943 s: string[255]; 944 SaveMap: array[0..lxmax*lymax-1] of Byte; 945 started,StatRequest: boolean; 946 begin 947 SavePath:=Path; 948 LogFileName:=FileName; 949 LoadTurn:=Turn; 950 LogFile:=TFileStream.Create(SavePath+LogFileName,fmOpenRead or fmShareExclusive); 951 LogFile.Position:=0; 952 LogFile.read(s[1],8); {file id} 953 LogFile.read(i,4); {c-evo version} 954 LogFile.read(j,4); {exe time} 955 956 if (i>=FirstBookCompatibleVersion) and (i<=Version) then 957 begin 958 result:=true; 959 LogFile.read(lx,4); 960 LogFile.read(ly,4); 961 MapSize:=lx*ly; 962 LogFile.read(LandMass,4); 963 if LandMass=0 then 964 LogFile.read(RealMap,MapSize*4); // use predefined map 965 LogFile.read(MaxTurn,4); 966 LogFile.read(RND,4); 967 LogFile.read(GTurn,4); 968 LogFile.read(SaveMap,4); 969 if SaveMap[0]<>$80 then 970 LogFile.read(SaveMap[4],((MapSize-1) div 4+1)*4-4); 971 for p1:=0 to nPl-1 do 972 begin 973 LogFile.read(s[0],4); 974 if s[0]=#0 then bixView[p1]:=-1 975 else 976 begin 977 LogFile.read(s[4],Byte(s[0]) div 4 *4); 978 LogFile.read(OriginalDataVersion[p1],4); 979 LogFile.read(d,4);{behavior} 980 LogFile.read(Difficulty[p1],4); 981 j:=nBrain-1; 982 while (j>=0) and (AnsiCompareFileName(Brain[j].FileName,s)<>0) do 983 dec(j); 984 if j<0 then 985 begin // ai not found -- replace by local player 986 ProcessClientData[p1]:=false; 987 NotifyMessage:=s; 988 Notify(ntAIError); 989 j:=bixTerm; 990 end 991 else ProcessClientData[p1]:=true; 992 if j=bixNoTerm then j:=bixSuper_Virtual; 993 // crashed tournament -- load as supervisor 994 bixView[p1]:=j; 995 end; 996 end; 997 end 998 else result:=false; 999 1000 if result then 1001 begin 1002 CL:=TCmdList.Create; 1003 CL.LoadFromFile(LogFile); 1004 end; 1005 LogFile.Free; 1006 if not result then exit; 1007 1008 Notify(ntStartDone); 1009 if LoadTurn<0 then LoadTurn:=GTurn; 1010 if MovieMode then Mode:=moMovie 1011 else if LoadTurn=0 then Mode:=moLoading 1012 else Mode:=moLoading_Fast; 1013 {$IFDEF TEXTLOG}AssignFile(TextLog,SavePath+LogFileName+'.txt');Rewrite(TextLog);{$ENDIF} 1014 LoadOK:=true; 1015 StartGame; 1016 if MovieMode then 1017 begin 1018 Brain[bix[0]].Client(cShowGame,0,nil^); 1019 Notify(ntBackOff); 1020 end 1021 else Notify(ntLoadBegin); 1022 1023 started:=false; 1024 StatRequest:=false; 1025 MovieStopped:=false; 1026 {$IFDEF LOADPERF}QueryPerformanceCounter(time_total0); time_a:=0; time_b:=0; time_c:=0;{$ENDIF} 1027 while not MovieStopped and (CL.Progress<1000) do 1028 begin 1029 FormerCLState:=CL.State; 1030 CL.Get(Command, p1, Subject, Data); 1031 if p1<0 then p1:=pTurn; 1032 if StatRequest 1033 and (Command and (sctMask or sExecute)<>sctInternal or sExecute) then 1034 begin GenerateStat(pTurn); StatRequest:=false end; 1035 // complete all internal commands following an sTurn before generating statistics 1036 if (Command=sTurn) and not started then 1037 begin 1038 {$IFDEF TEXTLOG}WriteLn(TextLog,'---Turn 0 P0---');{$ENDIF} 1039 for p1:=0 to nPl-1 do 1040 if (bix[p1]>=0) and ((Mode<>moMovie) or (p1=0)) then 1041 CallPlayer(cReplay,p1,nil^); 1042 BeforeTurn0; 1043 if MovieMode then 1044 begin 1045 Inform(pTurn); 1046 CallPlayer(cMovieTurn,0,nil^); 1047 end; 1048 StatRequest:=true; 1049 started:=true; 1050 end 1051 else if (Command=sTurn) and (pTurn=0) and (GTurn=LoadTurn) then 1052 begin 1053 assert(CL.State.LoadPos=FormerCLState.LoadPos+4); // size of sTurn 1054 CL.State:=FormerCLState; 1055 CL.Cut; 1056 Break; 1057 end 1058 else if Command=sIntDataChange then 1059 begin 1060 {$IFDEF TEXTLOG}LoadPos0:=CL.State.LoadPos;{$ENDIF} 1061 if ProcessClientData[p1] then 1062 CL.GetDataChanges(RW[p1].Data, Brain[bix[p1]].DataSize) 1063 else CL.GetDataChanges(nil, 0); 1064 {$IFDEF TEXTLOG}WriteLn(TextLog,Format('Data Changes P%d (%d Bytes)', [p1,CL.State.LoadPos-LoadPos0]));{$ENDIF} 1065 end 1066 else 1067 begin 1068 {$IFDEF TEXTLOG}CmdInfo:=Format('Command %x',[Command]);{$ENDIF} 1069 if Command and (sctMask or sExecute)=sctInternal or sExecute then 1070 IntServer(Command, p1, Subject, Data^) // internal command 1071 else 1072 begin 1073 StatRequest:= Command=sTurn; 1074 Server(Command, p1, Subject, Data^); 1075 end; 1076 {$IFDEF TEXTLOG}WriteLn(TextLog,CmdInfo);{$ENDIF} 1077 end; 1078 if not MovieMode then Notify(ntLoadState+CL.Progress*128 div 1000); 1079 end; 1080 1081 if MovieMode then 1082 begin 1083 Notify(ntBackOn); 1084 Brain[bix[0]].Client(cBreakGame,-1,nil^); 1085 EndGame; 1086 Notify(ntStartGo); 1087 result:=false; 1088 exit; 1089 end; 1090 1091 if StatRequest then GenerateStat(pTurn); 1092 assert(started); 1093 {$IFDEF TEXTLOG}CloseFile(TextLog);{$ENDIF} 1094 {$IFDEF LOADPERF}QueryPerformanceCounter(time_total);{time in s is: (time_total-time_total0)/PerfFreq}{$ENDIF} 1095 NoLogChanges; 1096 NoLogCityTileChanges; 1097 if LogFileName[1]='~' then 1098 begin Delete(LogFileName,1,1); nLogOpened:=-1 end 1099 else nLogOpened:=CL.State.nLog; 1100 1101 Mode:=moPlaying; 1102 LastEndClientCommand:=-1; 1103 if (GTestFlags and tfUncover<>0) or (Difficulty[pTurn]=0) then 1104 DiscoverAll(pTurn,lObserveSuper) {supervisor - all tiles visible} 1105 else DiscoverViewAreas(pTurn); 1106 1107 for p1:=0 to nPl-1 do if 1 shl p1 and (GAlive or GWatching)<>0 then 1108 begin 1109 RecalcPeaceMap(p1); 1110 for ix:=0 to RW[p1].nEnemyUn-1 do with RW[p1].EnemyUn[ix] do 1111 emix:=RWemix[p1,Owner,mix]; 1112 Inform(p1); 1113 end; 1114 {$IFOPT O-}CheckBorders(-2);{$ENDIF} // for testing only 1115 Notify(ntEndInfo); 1116 if not LoadOK then 1117 begin NotifyMessage:=SavePath+LogFileName; Notify(ntLoadError); end; 1118 Brain[bix[0]].Client(cShowGame,0,nil^); 1119 Notify(ntBackOff); 1120 Inform(pTurn); 1121 ChangeClientWhenDone(cResume,0,nil^,0); 1122 end; //LoadGame 1123 1124 procedure InsertTerritoryUpdateCommands; 1125 var 1126 p1,Command,Subject: integer; 1127 Data: pointer; 1128 FormerCLState: TCmdListState; 1129 begin 1130 while CL.Progress<1000 do 1131 begin 1132 FormerCLState:=CL.State; 1133 CL.Get(Command, p1, Subject, Data); 1134 if (Command=sIntExpandTerritory) and (p1=pTurn) then 1135 begin 1136 IntServer(Command, p1, Subject, Data^); 1137 {$IFDEF TEXTLOG}WriteLn(TextLog,'AfterTurn - ExpandTerritory');{$ENDIF} 1138 end 1139 else 1140 begin 1141 CL.State:=FormerCLState; 1142 break 1876 DiscoverViewAreas(pTurn); 1877 if MirBuilt then 1878 DiscoverAll(pTurn, lObserveUnhidden) 1143 1879 end 1144 1880 end; 1145 {$IFOPT O-}InvalidTreatyMap:=0;{$ENDIF} 1881 // CheckContact; 1882 end; { BeforeTurn } 1883 1884 procedure AfterTurn; 1885 var 1886 cix, uix, p1, Loc1, Job0: integer; 1887 JobDone: boolean; 1888 begin 1889 with RW[pTurn] do 1890 begin 1891 for cix := 0 to nCity - 1 do 1892 if City[cix].Loc >= 0 then 1893 begin 1894 // City[cix].Flags:=City[cix].Flags and not chProductionSabotaged; 1895 City[cix].Flags := City[cix].Flags and (chCaptured or chDisorder); 1896 CollectCityResources(pTurn, cix); // new style 1897 end; 1898 1899 inc(Money, OracleIncome); 1900 OracleIncome := 0; 1901 if GWonder[woOracle].EffectiveOwner = pTurn then 1902 begin 1903 for p1 := 0 to nPl - 1 do 1904 if (1 shl p1 and GAlive <> 0) and 1905 ((p1 = pTurn) or (RW[pTurn].Treaty[p1] > trNoContact)) then 1906 for cix := 0 to RW[p1].nCity - 1 do 1907 if (RW[p1].City[cix].Loc >= 0) and 1908 (RW[p1].City[cix].built[imTemple] > 0) then 1909 inc(OracleIncome); 1910 end; 1911 1912 if (GTestFlags and tfImmImprove = 0) and (Government <> gAnarchy) then 1913 for cix := 0 to nCity - 1 do 1914 if (City[cix].Loc >= 0) and (City[cix].Flags and chCaptured = 0) then 1915 PayCityMaintenance(pTurn, cix); 1916 1917 if ServerVersion[pTurn] >= $000EF0 then 1918 begin // let settlers work 1919 for cix := 0 to nCity - 1 do 1920 City[cix].Flags := City[cix].Flags and not chFounded; 1921 for uix := 0 to nUn - 1 do 1922 with Un[uix] do 1923 if Loc >= 0 then 1924 begin 1925 Loc1 := Loc; 1926 Job0 := Job; 1927 if Job <> jNone then 1928 JobDone := Work(pTurn, uix); 1929 { settlers do terrain improvement jobs } 1930 if Health <= 0 then 1931 RemoveUnit_UpdateMap(pTurn, uix); 1932 1933 if (Job0 = jCity) and JobDone then // new city 1934 begin 1935 AddBestCityTile(pTurn, RW[pTurn].nCity - 1); 1936 UpdateUnitMap(Loc1, true); 1937 if Mode >= moMovie then // tell enemies 1938 for p1 := 0 to nPl - 1 do 1939 if (1 shl p1 and GWatching <> 0) and (p1 <> pTurn) and 1940 (ObserveLevel[Loc1] and (3 shl (2 * p1)) > 0) then 1941 CallPlayer(cShowCityChanged, p1, Loc1); 1942 end 1943 end; 1944 end; 1945 1946 for uix := 0 to nUn - 1 do 1947 with Un[uix] do 1948 if Loc >= 0 then 1949 begin { next turn for all units } 1950 if Model[mix].Domain = dAir then 1951 if (Master >= 0) or (RealMap[Loc] and fCity <> 0) or 1952 (RealMap[Loc] and fTerImp = tiBase) then 1953 begin 1954 Fuel := Model[mix].Cap[mcFuel]; 1955 Flags := Flags or unBombsLoaded 1956 end 1957 else if Model[mix].Kind = mkSpecial_Glider then { glider } 1958 begin 1959 if RealMap[Loc] and fTerrain < fGrass then 1960 begin 1961 RemoveUnit_UpdateMap(pTurn, uix); // unit lost 1962 Happened := Happened or phGliderLost 1963 end 1964 end 1965 else 1966 begin 1967 dec(Fuel); 1968 if Fuel < 0 then 1969 begin 1970 RemoveUnit_UpdateMap(pTurn, uix); // unit lost 1971 Happened := Happened or phPlaneLost 1972 end 1973 end 1974 else if (Master < 0) and (Movement > 0) then // check HostileDamage 1975 begin 1976 Health := Health - HostileDamage(pTurn, mix, Loc, Movement); 1977 if Health < 0 then 1978 RemoveUnit_UpdateMap(pTurn, uix); 1979 end 1980 end; { unit loop 1 } 1981 1982 for uix := 0 to nUn - 1 do 1983 with Un[uix] do 1984 begin 1985 Flags := Flags and not unWithdrawn; 1986 if (Loc >= 0) and (Model[mix].Domain = dGround) and (Master < 0) and 1987 ((integer(Movement) = Model[mix].Speed) or 1988 (Model[mix].Cap[mcAcademy] > 0) and (Movement * 2 >= Model[mix].Speed)) 1989 then 1990 Flags := Flags or unFortified; // fortify unmoved units 1991 end; 1992 1993 if (GTestFlags and tfUncover = 0) and (Difficulty[pTurn] > 0) then 1994 begin // restrict view area to current positions 1995 MaskD(ObserveLevel, MapSize, not Cardinal(3 shl (2 * pTurn))); 1996 if Mode > moLoading_Fast then 1997 MaskD(RW[pTurn].Map^, MapSize, not Cardinal(fUnit or fHiddenUnit or 1998 fStealthUnit or fObserved or fSpiedOut or fOwned or fOwnZoCUnit or 1999 fInEnemyZoC)); 2000 RW[pTurn].nEnemyUn := 0; 2001 DiscoverViewAreas(pTurn); 2002 end; 2003 2004 if GWinner = 0 then 2005 for p1 := 0 to nPl - 1 do 2006 if 1 shl p1 and GAlive <> 0 then 2007 CheckWin(p1); 2008 end; 2009 end; // Afterturn 2010 2011 procedure NextPlayer; 2012 begin 2013 if GTurn = 0 then 2014 BeforeTurn0 2015 else 2016 BeforeTurn; 2017 NoLogCityTileChanges; 2018 GenerateStat(pTurn); 2019 Inform(pTurn); 2020 ChangeClient; 1146 2021 end; 1147 2022 1148 procedure StartNewGame(const Path, FileName, Map: string; Newlx, Newly, 1149 NewLandMass, NewMaxTurn: integer);2023 function ExecuteMove(p, uix, ToLoc: integer; var MoveInfo: TMoveInfo; 2024 ShowMove: TShowMove): integer; 1150 2025 var 1151 p: integer; 2026 i, p1, FromLoc, uix1, nUpdateLoc: integer; 2027 MinLevel, MissionResult: Cardinal; 2028 PModel: ^TModel; 2029 UpdateLoc: array [0 .. numax - 1] of integer; 2030 SeeFrom, SeeTo, ExtDiscover: boolean; 1152 2031 begin 1153 Notify(ntStartDone); 1154 SavePath:=Path; 1155 LogFileName:=FileName; 1156 MapFileName:=Map; 1157 if FastContact then begin lx:=24; ly:=42; end 1158 else begin lx:=Newlx; ly:=Newly end; 1159 MapSize:=lx*ly; 1160 if MapFileName<>'' then LandMass:=0 1161 else LandMass:=NewLandMass; 1162 MaxTurn:=NewMaxTurn; 1163 Randomize; 1164 RND:=RandSeed; 1165 Mode:=moPlaying; 1166 CL:=TCmdList.Create; 1167 StartGame; 1168 NoLogChanges; 1169 for p:=0 to nPl-1 do if bix[p]>=0 then 1170 CallPlayer(cGetReady,p,nil^); 1171 LogChanges; 1172 CL.Put(sTurn, 0, 0, nil); 1173 BeforeTurn0; 1174 NoLogCityTileChanges; 1175 GenerateStat(pTurn); 1176 nLogOpened:=-1; 1177 LastEndClientCommand:=-1; 1178 Brain[bix[0]].Client(cShowGame,0,nil^); 1179 Notify(ntBackOff); 1180 Inform(pTurn); 1181 ChangeClientWhenDone(cTurn,0,nil^,0) 1182 end; 1183 1184 procedure DirectHelp(Command: integer); 1185 begin 1186 InitBrain(bixTerm); 1187 Brain[bixTerm].Client(Command,-1,nil^); 1188 AICredits:=#0; 1189 end; 1190 1191 procedure EditMap(const Map: string; Newlx, Newly, NewLandMass: integer); 1192 var 1193 p1,Loc1: integer; 1194 Game: TNewGameData; 1195 begin 1196 Notify(ntStartDone); 1197 Notify(ntInitLocalHuman); 1198 MapFileName:=Map; 1199 lx:=Newlx; 1200 ly:=Newly; 1201 MapSize:=lx*ly; 1202 LandMass:=NewLandMass; 1203 bix[0]:=bixTerm; 1204 Difficulty[0]:=0; 1205 InitBrain(bixTerm); 1206 1207 Randomize; 1208 GAlive:=0; 1209 GWatching:=1; 1210 if not LoadMap(MapFileName) then 1211 for Loc1:=0 to MapSize-1 do RealMap[Loc1]:=fOcean or ($F shl 27); 1212 CL:=nil; 1213 InitMapEditor; 1214 RW[0].Data:=nil; 1215 RW[0].BorderHelper:=nil; 1216 RW[0].Alive:=0; 1217 Game.lx:=lx; Game.ly:=ly; 1218 Game.RO[0]:=@RW[0]; 1219 Game.Difficulty[0]:=0; 1220 for p1:=1 to nPl-1 do begin Game.RO[p1]:=nil; Game.Difficulty[p1]:=-1 end; 1221 Brain[bixTerm].Client(cNewMap,-1,Game); 1222 1223 DiscoverAll(0,lObserveSuper); 1224 Notify(ntEndInfo); 1225 Brain[bix[0]].Client(cShowGame,0,nil^); 1226 Notify(ntBackOff); 1227 ChangeClientWhenDone(cEditMap,0,nil^,0) 1228 end; 1229 1230 procedure DestroySpacePort_TellPlayers(p,pCapturer: integer); 1231 var 1232 cix,i,p1: integer; 1233 ShowShipChange: TShowShipChange; 1234 begin 1235 // stop ship part production 1236 for cix:=0 to RW[p].nCity-1 do with RW[p].City[cix] do 1237 if (Loc>=0) and (Project and cpImp<>0) 1238 and ((Project and cpIndex=woMIR) 1239 or (Imp[Project and cpIndex].Kind=ikShipPart)) then 2032 result := 0; 2033 with RW[p], Un[uix] do 2034 begin 2035 PModel := @Model[mix]; 2036 FromLoc := Loc; 2037 2038 if Master < 0 then 2039 FreeUnit(p, uix); 2040 if (MoveInfo.MoveType in [mtMove, mtCapture]) and MoveInfo.MountainDelay 2041 then 1240 2042 begin 1241 inc(RW[p].Money,Prod0); 1242 Prod:=0; 1243 Prod0:=0; 1244 Project:=cpImp+imTrGoods; 1245 Project0:=cpImp+imTrGoods 2043 Flags := Flags or unMountainDelay; 1246 2044 end; 1247 1248 // destroy ship 1249 with GShip[p] do if Parts[0]+Parts[1]+Parts[2]>0 then 1250 begin 1251 for i:=0 to nShipPart-1 do 2045 Loc := -2; 2046 if TroopLoad + AirLoad > 0 then 2047 for i := 0 to nUn - 1 do 2048 if (Un[i].Loc >= 0) and (Un[i].Master = uix) then 2049 Un[i].Loc := -2; 2050 UpdateUnitMap(FromLoc); 2051 2052 if Mode >= moMovie then { show move in interface modules } 1252 2053 begin 1253 ShowShipChange.Ship1Change[i]:=-Parts[i]; 1254 if pCapturer>=0 then 1255 begin 1256 ShowShipChange.Ship2Change[i]:=Parts[i]; 1257 inc(GShip[pCapturer].Parts[i], Parts[i]); 1258 end; 1259 Parts[i]:=0; 2054 ShowMove.EndHealth := MoveInfo.EndHealth; 2055 ShowMove.EndHealthDef := -1; 2056 if Master >= 0 then 2057 if Model[Un[Master].mix].Domain = dAir then 2058 ShowMove.Flags := ShowMove.Flags or umPlaneUnloading 2059 else 2060 ShowMove.Flags := ShowMove.Flags or umShipUnloading; 2061 if MoveInfo.ToMaster >= 0 then 2062 if Model[Un[MoveInfo.ToMaster].mix].Domain = dAir then 2063 ShowMove.Flags := ShowMove.Flags or umPlaneLoading 2064 else 2065 ShowMove.Flags := ShowMove.Flags or umShipLoading; 2066 for p1 := 0 to nPl - 1 do 2067 if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm)) 2068 then 2069 begin 2070 if PModel.Cap[mcStealth] > 0 then 2071 MinLevel := lObserveSuper 2072 else if PModel.Cap[mcSub] > 0 then 2073 MinLevel := lObserveAll 2074 else 2075 MinLevel := lObserveUnhidden; 2076 SeeFrom := (p1 = p) or (ObserveLevel[FromLoc] shr (2 * p1) and 2077 3 >= MinLevel); 2078 SeeTo := (p1 = p) or (ObserveLevel[ToLoc] shr (2 * p1) and 2079 3 >= MinLevel); 2080 if SeeFrom and SeeTo then 2081 begin 2082 TellAboutModel(p1, p, mix); 2083 if p1 = p then 2084 ShowMove.emix := -1 2085 else 2086 ShowMove.emix := emixSafe(p1, p, mix); 2087 if MoveInfo.MoveType = mtCapture then 2088 CallPlayer(cShowCapturing, p1, ShowMove) 2089 else 2090 CallPlayer(cShowMoving, p1, ShowMove); 2091 end 2092 else if SeeFrom then 2093 CallPlayer(cShowUnitChanged, p1, FromLoc); 2094 end; 1260 2095 end; 1261 if Mode>=moMovie then 2096 2097 if MoveInfo.MoveType <> mtSpyMission then 2098 Loc := ToLoc; 2099 if TroopLoad + AirLoad > 0 then 2100 for i := 0 to nUn - 1 do 2101 if Un[i].Loc = -2 then 2102 Un[i].Loc := ToLoc; 2103 2104 ExtDiscover := false; 2105 nUpdateLoc := 0; 2106 if MoveInfo.MoveType = mtCapture then 1262 2107 begin 1263 if pCapturer>=0 then ShowShipChange.Reason:=scrCapture 1264 else ShowShipChange.Reason:=scrDestruction; 1265 ShowShipChange.Ship1Owner:=p; 1266 ShowShipChange.Ship2Owner:=pCapturer; 1267 for p1:=0 to nPl-1 do if 1 shl p1 and (GAlive or GWatching)<>0 then 1268 begin 1269 move(GShip,RW[p1].Ship,SizeOf(GShip)); 1270 if 1 shl p1 and GWatching<>0 then 1271 CallPlayer(cShowShipChange,p1,ShowShipChange); 1272 end; 1273 end 1274 end 1275 end; 1276 1277 procedure DestroyCity_TellPlayers(p,cix: integer; SaveUnits: boolean); 1278 begin 1279 if RW[p].City[cix].built[imSpacePort]>0 then 1280 DestroySpacePort_TellPlayers(p,-1); 1281 DestroyCity(p,cix,SaveUnits); 1282 end; 1283 1284 procedure ChangeCityOwner_TellPlayers(pOld,cixOld,pNew: integer); 1285 begin 1286 if RW[pOld].City[cixOld].built[imSpacePort]>0 then 1287 if RW[pNew].NatBuilt[imSpacePort]>0 then 1288 DestroySpacePort_TellPlayers(pOld,pNew) 1289 else DestroySpacePort_TellPlayers(pOld,-1); 1290 ChangeCityOwner(pOld,cixOld,pNew); 1291 end; 1292 1293 procedure CheckWin(p: integer); 1294 var 1295 i: integer; 1296 ShipComplete: boolean; 1297 begin 1298 ShipComplete:=true; 1299 for i:=0 to nShipPart-1 do 1300 if GShip[p].Parts[i]<ShipNeed[i] then ShipComplete:=false; 1301 if ShipComplete then GWinner:=GWinner or 1 shl p; // game won! 1302 end; 1303 1304 procedure BeforeTurn; 1305 var 1306 i,p1,uix,cix,V21,Loc1,Cost,Job0,nAlive,nAppliers,ad, 1307 OldLoc,SiegedTiles,nUpdateLoc: integer; 1308 UpdateLoc: array[0..numax-1] of integer; 1309 Radius: TVicinity21Loc; 1310 ShowShipChange: TShowShipChange; 1311 TribeExtinct, JobDone, MirBuilt: boolean; 1312 begin 1313 {$IFOPT O-}assert(1 shl pTurn and InvalidTreatyMap=0);{$ENDIF} 1314 assert(1 shl pTurn and (GAlive or GWatching)<>0); 1315 if (1 shl pTurn and GAlive=0) and (Difficulty[pTurn]>0) then 1316 exit; 1317 1318 if (GWonder[woGrLibrary].EffectiveOwner=pTurn) and (GWinner=0) then 1319 begin // check great library effect 1320 nAlive:=0; 1321 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then inc(nAlive); 1322 for ad:=0 to nAdv-5 do if RW[pTurn].Tech[ad]<tsSeen then 1323 begin 1324 nAppliers:=0; 1325 for p1:=0 to nPl-1 do 1326 if (p1<>pTurn) and (1 shl p1 and GAlive<>0) 1327 and (RW[p1].Tech[ad]>=tsApplicable) then 1328 inc(nAppliers); 1329 if nAppliers*2>nAlive then 1330 begin 1331 SeeTech(pTurn,ad); 1332 inc(nTech[pTurn]); 1333 if Mode>=moMovie then 1334 CallPlayer(cShowGreatLibTech,pTurn,ad); 1335 // do not call CallPlayer(pTurn) while map is invalid 1336 end; 1337 end; 1338 end; 1339 1340 MaskD(ObserveLevel,MapSize,not Cardinal(3 shl (2*pTurn))); 1341 if Mode>moLoading_Fast then 1342 MaskD(RW[pTurn].Map^,MapSize,not Cardinal(fUnit or fHiddenUnit or fStealthUnit 1343 or fObserved or fSpiedOut or fOwned or fOwnZoCUnit or fInEnemyZoC)); 1344 RW[pTurn].nEnemyUn:=0; 1345 1346 MirBuilt:=false; 1347 if (Difficulty[pTurn]>0) and (GWinner=0) then with RW[pTurn] do 1348 begin 1349 if nCity>0 then for p1:=0 to nPl-1 do 1350 if GTurn=EvaStart[p1]+PeaceEvaTurns then 1351 begin // peace contract -- remove all units from p1's territory 1352 Loc1:=City[0].Loc; // search destination for homeless units 1353 for cix:=1 to nCity-1 do 1354 if (City[cix].Loc>=0) and ((Loc1<0) or (City[cix].Built[imPalace]>0)) then 1355 Loc1:=City[cix].Loc; 1356 for uix:=0 to nUn-1 do with Un[uix] do 1357 if (Loc>=0) and (Model[mix].Kind<>mkDiplomat) 1358 and ((Home>=0) or (Loc1>=0)) 1359 and (RealMap[Loc] shr 27=Cardinal(p1)) then 2108 assert(Occupant[ToLoc] < 0); 2109 for uix1 := 0 to RW[MoveInfo.Defender].nUn - 1 do 2110 with RW[MoveInfo.Defender].Un[uix1] do 2111 if (Loc >= 0) and (Home = MoveInfo.Dcix) then 1360 2112 begin 1361 OldLoc:=Loc; 1362 if Master>=0 then 1363 begin // transport unload 1364 if Model[mix].Domain=dAir then dec(Un[Master].AirLoad) 1365 else dec(Un[Master].TroopLoad); 1366 Master:=-1; 1367 end 1368 else FreeUnit(pTurn,uix); 1369 1370 if Home>=0 then Loc:=City[Home].Loc 1371 else Loc:=Loc1; 1372 PlaceUnit(pTurn,uix); 1373 UpdateUnitMap(OldLoc); 1374 UpdateUnitMap(Loc); 1375 Flags:=Flags or unWithdrawn; 1376 Happened:=Happened or phPeaceEvacuation; 1377 end 1378 end; 1379 1380 if Mode>=moMovie then 1381 fillchar(ShowShipChange,sizeof(ShowShipChange),0); 1382 TribeExtinct:=true; 1383 nUpdateLoc:=0; 1384 for cix:=0 to nCity-1 do with City[cix] do if Loc>=0 then 1385 begin {next turn for all cities - city loop 1} 1386 // if ServerVersion[pTurn]>=$000EF0 then 1387 // Flags:=Flags and (chFounded or chCaptured or chProductionSabotaged or chDisorder) 1388 // else Flags:=Flags and (chCaptured or chProductionSabotaged or chDisorder); 1389 // check for siege 1390 SiegedTiles:=0; 1391 V21_to_Loc(Loc,Radius); 1392 for V21:=1 to 26 do if Tiles and (1 shl V21) and not (1 shl CityOwnTile)<>0 then 1393 begin 1394 Loc1:=Radius[V21]; 1395 assert((Loc1>=0) and (Loc1<MapSize) and (UsedByCity[Loc1]=Loc)); 1396 p1:=RealMap[Loc1] shr 27; 1397 if (RealMap[Loc1] and fCity<>0) 1398 or (p1<nPl) and (p1<>pTurn) and (RW[pTurn].Treaty[p1]>=trPeace) 1399 or (ZoCMap[Loc1]>0) and (Occupant[Loc1]<>pTurn) 1400 and (Treaty[Occupant[Loc1]]<trPeace) then 2113 UpdateLoc[nUpdateLoc] := Loc; 2114 inc(nUpdateLoc) 2115 end; 2116 // unit will be removed -- remember position and update for all players 2117 2118 if (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size > 2) and (nCity < ncmax) 2119 then 2120 begin // city captured 2121 ChangeCityOwner_TellPlayers(MoveInfo.Defender, MoveInfo.Dcix, p); 2122 City[nCity - 1].Flags := CaptureTurns shl 16; 2123 CityShrink(p, nCity - 1); 2124 if Mode = moPlaying then 2125 with RW[p].City[nCity - 1] do 2126 begin 2127 // SavedResourceWeights[nCity-1]:=ResourceWeights; 2128 SavedTiles[nCity - 1] := Tiles; 2129 end; 2130 ExtDiscover := true; 2131 2132 // Temple of Zeus effect 2133 if GWonder[woZeus].EffectiveOwner = p then 1401 2134 begin 1402 Tiles:=Tiles and not (1 shl V21); 1403 UsedByCity[Loc1]:=-1; 1404 Flags:=Flags or chSiege; 1405 inc(SiegedTiles); 1406 end; 1407 end; 1408 while SiegedTiles>0 do // replace sieged tiles 1409 begin 1410 if not AddBestCityTile(pTurn,cix) then break; 1411 dec(SiegedTiles); 1412 end; 1413 1414 if Flags and chFounded=0 then 1415 begin 1416 // CollectCityResources(pTurn,cix); // old style 1417 1418 if CityTurn(pTurn,cix) then 1419 TribeExtinct:=false 1420 else 1421 begin // city is erased 1422 RemoveDomainUnits(dSea,pTurn,Loc); 1423 RemoveDomainUnits(dAir,pTurn,Loc); 1424 Map[Loc]:=Map[Loc] and not fCity; // !!! do this in inner core 1425 UpdateLoc[nUpdateLoc]:=Loc; 1426 inc(nUpdateLoc); 1427 DestroyCity_TellPlayers(pTurn,cix,true); 1428 end; 1429 1430 if (Flags and chProduction<>0) and (Project0 and cpImp<>0) then 1431 begin 1432 if Project0 and cpIndex=woMir then // MIR completed 1433 MirBuilt:=true 1434 else if Project0 and cpIndex=woManhattan then 1435 GColdWarStart:=GTurn 1436 else if Imp[Project0 and cpIndex].Kind=ikShipPart then {ship parts produced} 1437 inc(ShowShipChange.Ship1Change[Project0 and cpIndex-imShipComp]); 1438 end 1439 end 1440 end;{city loop 1} 1441 if nUpdateLoc>0 then 1442 begin 1443 CheckBorders(-1,pTurn); 1444 for i:=0 to nUpdateLoc-1 do UpdateUnitMap(UpdateLoc[i],true); 1445 if Mode>=moMovie then 1446 for p1:=0 to nPl-1 do 1447 if (1 shl p1 and GWatching<>0) and (p1<>pTurn) then 1448 for i:=0 to nUpdateLoc-1 do 1449 if ObserveLevel[UpdateLoc[i]] shr (2*p1) and 3>=lObserveUnhidden then 1450 CallPlayer(cShowCityChanged,p1,UpdateLoc[i]); 1451 end; 1452 1453 for uix:=0 to nUn-1 do with Un[uix] do if Loc>=0 then 1454 begin // unit loop 2 1455 if Health<100 then Recover(pTurn,uix); 1456 1457 if Flags and unMountainDelay<>0 then 1458 begin 1459 Movement:=0; 1460 Flags:=Flags and not unMountainDelay 1461 end 1462 else Movement:=UnitSpeed(pTurn,mix,Health); {refresh movement} 1463 1464 assert(Loc>=0); 1465 if Model[mix].Kind<>mkDiplomat then 1466 begin // check treaty violation 1467 p1:=RealMap[Loc] shr 27; 1468 if (p1<nPl) and (p1<>pTurn) and (Treaty[p1]>=trPeace) then 1469 begin 1470 if (Job in [jCity,jPillage,jClear,jAfforest,jTrans]) 1471 or (Job in [jIrr,jMine,jFort,jBase]) and (RealMap[Loc] and fTerImp<>0) then 1472 Job:=jNone; 1473 if (GTurn>EvaStart[p1]+PeaceEvaTurns) and (Treaty[p1]<>trAlliance) then 1474 begin 1475 EvaStart[p1]:=GTurn; 1476 Happened:=Happened or phPeaceViolation; 1477 if Mode>=moMovie then 1478 CallPlayer(cShowPeaceViolation,p1,pTurn); 1479 end; 1480 end; 1481 end; 1482 1483 if ServerVersion[pTurn]>=$000EF0 then 1484 begin 1485 if (Health<=0) or TribeExtinct then RemoveUnit_UpdateMap(pTurn,uix); 1486 end 1487 end; 1488 1489 if ServerVersion[pTurn]<$000EF0 then 1490 for uix:=0 to nUn-1 do with Un[uix] do if Loc>=0 then 1491 begin // unit loop 3 1492 Loc1:=Loc; 1493 Job0:=Job; 1494 if Job<>jNone then JobDone:=Work(pTurn,uix); 1495 {settlers do terrain improvement jobs} 1496 if (Health<=0) or TribeExtinct then RemoveUnit_UpdateMap(pTurn,uix); 1497 1498 if (Job0=jCity) and JobDone then // new city 1499 begin 1500 AddBestCityTile(pTurn,RW[pTurn].nCity-1); 1501 UpdateUnitMap(Loc1,true); 1502 if Mode>=moMovie then // tell enemies 1503 for p1:=0 to nPl-1 do 1504 if (1 shl p1 and GWatching<>0) and (p1<>pTurn) 1505 and (ObserveLevel[Loc1] and (3 shl (2*p1))>0) then 1506 CallPlayer(cShowCityChanged,p1,Loc1); 1507 end 1508 end; 1509 1510 {pollution - city loop 3} 1511 for cix:=0 to nCity-1 do with City[cix] do 1512 if (Loc>=0) and (Pollution>=MaxPollution) then 1513 Pollute(pTurn,cix); 1514 1515 CompactLists(pTurn); 1516 if (nUn=0) and (nCity=0) then 1517 begin // nation made extinct 1518 Happened:=Happened or phExtinct; 1519 GAlive:=GAlive and not (1 shl pTurn); 1520 Stat[stPop,pTurn,GTurn]:=0; 1521 Stat[stMil,pTurn,GTurn]:=0; 1522 Stat[stScience,pTurn,GTurn]:=0; 1523 Stat[stExplore,pTurn,GTurn]:=0; 1524 Stat[stTerritory,pTurn,GTurn]:=0; 1525 Stat[stWork,pTurn,GTurn]:=0; 1526 for p1:=0 to nPl-1 do if 1 shl p1 and (GAlive or GWatching)<>0 then 1527 begin 1528 if p1<>pTurn then 1529 begin 1530 GiveCivilReport(p1, pTurn); 1531 if (GTestFlags and tfUncover<>0) or (Difficulty[p1]=0) 1532 or (RW[p1].Treaty[pTurn]=trAlliance) then 1533 GiveMilReport(p1, pTurn); 1534 end; 1535 with RW[p1] do 1536 begin 1537 Alive:=GAlive; 1538 for Loc1:=0 to MapSize-1 do 1539 if Territory[Loc1]=pTurn then // remove territory of extinct nation from player maps 2135 GiveCivilReport(p, MoveInfo.Defender); 2136 for i := 0 to nAdv - 1 do 2137 if not(i in FutureTech) and (RW[p].Tech[i] < tsSeen) and 2138 (RW[MoveInfo.Defender].Tech[i] >= tsApplicable) then 1540 2139 begin 1541 Territory[Loc1]:=-1; 1542 Map[Loc1]:=Map[Loc1] and not fPeace 2140 Happened := Happened or phStealTech; 2141 GStealFrom := MoveInfo.Defender; 2142 Break 1543 2143 end 1544 2144 end; 1545 end; 1546 exit 1547 end; 1548 1549 // check research 1550 Cost:=TechCost(pTurn); 1551 if GTestFlags and tfImmAdvance<>0 then Research:=Cost; 1552 if (Happened and phTech=0) and (Research>=Cost) then 1553 begin 1554 if ResearchTech=adMilitary then EnableDevModel(pTurn) {new Unit class initiated} 1555 else if ResearchTech>=0 then 1556 DiscoverTech(pTurn,ResearchTech); 1557 1558 dec(Research,Cost); 1559 Happened:=Happened or phTech; 1560 ResearchTech:=-1 1561 end 1562 else if (ResearchTech=-2) and (nCity>0) then 1563 begin 1564 Happened:=Happened or phTech; 1565 ResearchTech:=-1 1566 end; 1567 1568 if Credibility<MaxCredibility then 1569 for p1:=0 to nPl-1 do 1570 if (p1<>pTurn) and (1 shl p1 and GAlive<>0) 1571 and (Treaty[p1]>=trPeace) then 1572 begin inc(Credibility); Break end; 1573 1574 if GWinner=0 then CheckWin(pTurn); 1575 if (Mode>=moMovie) and (GWinner=0) and ((ShowShipChange.Ship1Change[0]>0) 1576 or (ShowShipChange.Ship1Change[1]>0) or (ShowShipChange.Ship1Change[2]>0)) then 1577 begin 1578 ShowShipChange.Reason:=scrProduction; 1579 ShowShipChange.Ship1Owner:=pTurn; 1580 ShowShipChange.Ship2Owner:=-1; 1581 for p1:=0 to nPl-1 do 1582 if (p1<>pTurn) and (1 shl p1 and (GAlive or GWatching)<>0) then 1583 begin 1584 move(GShip,RW[p1].Ship,SizeOf(GShip)); 1585 if 1 shl p1 and GWatching<>0 then 1586 CallPlayer(cShowShipChange,p1,ShowShipChange); 1587 end 1588 end; 1589 if WinOnAlone and (GAlive and not (1 shl pTurn or 1)=0) then 1590 GWinner:=1 shl pTurn; // break if only one nation left 1591 1592 if GTurn=AnarchyStart+AnarchyTurns then 1593 begin 1594 AnarchyStart:=-AnarchyTurns-1; 1595 Government:=gDespotism; 1596 for p1:=0 to nPl-1 do if (p1<>pTurn) and ((GAlive or GWatching) and (1 shl p1)<>0) then 1597 RW[p1].EnemyReport[pTurn].Government:=gDespotism; 1598 inc(Happened,phChangeGov) 1599 end; 1600 end; // if Difficulty[pTurn]>0 1601 1602 if (pTurn=0) and (GWinner>0) then 1603 begin // game over, give world map and all reports to player 0 1604 DiscoverAll(pTurn,lObserveSuper); 1605 for p1:=1 to nPl-1 do if 1 shl p1 and GAlive<>0 then 1606 begin 1607 if RW[pTurn].Treaty[p1]<trNone then 1608 begin 1609 RW[pTurn].Treaty[p1]:=trNone; 1610 RW[p1].Treaty[pTurn]:=trNone; 1611 end; 1612 GiveCivilReport(pTurn,p1); 1613 GiveMilReport(pTurn,p1); 1614 end; 1615 end 1616 else 1617 begin 1618 // show observed areas 1619 if (GTestFlags and tfUncover<>0) or (Difficulty[pTurn]=0) then {supervisor - all tiles visible} 1620 begin 1621 if (bix[pTurn]<>bixNoTerm) 1622 and ((Difficulty[pTurn]>0) or (Mode>moLoading_Fast)) then 1623 DiscoverAll(pTurn,lObserveSuper) 1624 end 1625 else 1626 begin 1627 DiscoverViewAreas(pTurn); 1628 if MirBuilt then 1629 DiscoverAll(pTurn,lObserveUnhidden) 1630 end 1631 end; 1632 //CheckContact; 1633 end; {BeforeTurn} 1634 1635 procedure AfterTurn; 1636 var 1637 cix,uix,p1,Loc1,Job0: integer; 1638 JobDone: boolean; 1639 begin 1640 with RW[pTurn] do 1641 begin 1642 for cix:=0 to nCity-1 do if City[cix].Loc>=0 then 1643 begin 1644 // City[cix].Flags:=City[cix].Flags and not chProductionSabotaged; 1645 City[cix].Flags:=City[cix].Flags and (chCaptured or chDisorder); 1646 CollectCityResources(pTurn,cix); // new style 1647 end; 1648 1649 inc(Money,OracleIncome); 1650 OracleIncome:=0; 1651 if GWonder[woOracle].EffectiveOwner=pTurn then 1652 begin 1653 for p1:=0 to nPl-1 do 1654 if (1 shl p1 and GAlive<>0) 1655 and ((p1=pTurn) or (RW[pTurn].Treaty[p1]>trNoContact)) then 1656 for cix:=0 to RW[p1].nCity-1 do 1657 if (RW[p1].City[cix].Loc>=0) and (RW[p1].City[cix].Built[imTemple]>0) then 1658 inc(OracleIncome); 1659 end; 1660 1661 if (GTestFlags and tfImmImprove=0) and (Government<>gAnarchy) then 1662 for cix:=0 to nCity-1 do 1663 if (City[cix].Loc>=0) and (City[cix].Flags and chCaptured=0) then 1664 PayCityMaintenance(pTurn,cix); 1665 1666 if ServerVersion[pTurn]>=$000EF0 then 1667 begin // let settlers work 1668 for cix:=0 to nCity-1 do 1669 City[cix].Flags:=City[cix].Flags and not chFounded; 1670 for uix:=0 to nUn-1 do with Un[uix] do if Loc>=0 then 1671 begin 1672 Loc1:=Loc; 1673 Job0:=Job; 1674 if Job<>jNone then JobDone:=Work(pTurn,uix); 1675 {settlers do terrain improvement jobs} 1676 if Health<=0 then RemoveUnit_UpdateMap(pTurn,uix); 1677 1678 if (Job0=jCity) and JobDone then // new city 1679 begin 1680 AddBestCityTile(pTurn,RW[pTurn].nCity-1); 1681 UpdateUnitMap(Loc1,true); 1682 if Mode>=moMovie then // tell enemies 1683 for p1:=0 to nPl-1 do 1684 if (1 shl p1 and GWatching<>0) and (p1<>pTurn) 1685 and (ObserveLevel[Loc1] and (3 shl (2*p1))>0) then 1686 CallPlayer(cShowCityChanged,p1,Loc1); 1687 end 1688 end; 1689 end; 1690 1691 for uix:=0 to nUn-1 do with Un[uix] do if Loc>=0 then 1692 begin {next turn for all units} 1693 if Model[mix].Domain=dAir then 1694 if (Master>=0) or (RealMap[Loc] and fCity<>0) 1695 or (RealMap[Loc] and fTerImp=tiBase) then 1696 begin 1697 Fuel:=Model[mix].Cap[mcFuel]; 1698 Flags:=Flags or unBombsLoaded 1699 end 1700 else if Model[mix].Kind=mkSpecial_Glider then {glider} 1701 begin 1702 if RealMap[Loc] and fTerrain<fGrass then 1703 begin 1704 RemoveUnit_UpdateMap(pTurn,uix); // unit lost 1705 Happened:=Happened or phGliderLost 1706 end 1707 end 1708 else 1709 begin 1710 dec(Fuel); 1711 if Fuel<0 then 1712 begin 1713 RemoveUnit_UpdateMap(pTurn,uix); // unit lost 1714 Happened:=Happened or phPlaneLost 1715 end 1716 end 1717 else if (Master<0) and (Movement>0) then // check HostileDamage 1718 begin 1719 Health:=Health-HostileDamage(pTurn,mix,Loc,Movement); 1720 if Health<0 then RemoveUnit_UpdateMap(pTurn,uix); 1721 end 1722 end; {unit loop 1} 1723 1724 for uix:=0 to nUn-1 do with Un[uix] do 1725 begin 1726 Flags:=Flags and not unWithdrawn; 1727 if (Loc>=0) and (Model[mix].Domain=dGround) and (Master<0) 1728 and ((integer(Movement)=Model[mix].Speed) 1729 or (Model[mix].Cap[mcAcademy]>0) and (Movement*2>=Model[mix].Speed)) then 1730 Flags:=Flags or unFortified; // fortify unmoved units 1731 end; 1732 1733 if (GTestFlags and tfUncover=0) and (Difficulty[pTurn]>0) then 1734 begin // restrict view area to current positions 1735 MaskD(ObserveLevel,MapSize,not Cardinal(3 shl (2*pTurn))); 1736 if Mode>moLoading_Fast then 1737 MaskD(RW[pTurn].Map^,MapSize,not Cardinal(fUnit or fHiddenUnit or fStealthUnit 1738 or fObserved or fSpiedOut or fOwned or fOwnZoCUnit or fInEnemyZoC)); 1739 RW[pTurn].nEnemyUn:=0; 1740 DiscoverViewAreas(pTurn); 1741 end; 1742 1743 if GWinner=0 then 1744 for p1:=0 to nPl-1 do if 1 shl p1 and GAlive<>0 then 1745 CheckWin(p1); 1746 end; 1747 end; //Afterturn 1748 1749 procedure NextPlayer; 1750 begin 1751 if GTurn=0 then BeforeTurn0 1752 else BeforeTurn; 1753 NoLogCityTileChanges; 1754 GenerateStat(pTurn); 1755 Inform(pTurn); 1756 ChangeClient; 1757 end; 1758 1759 function ExecuteMove(p,uix,ToLoc: integer; 1760 var MoveInfo: TMoveInfo; ShowMove: TShowMove): integer; 1761 var 1762 i,p1,FromLoc,uix1,nUpdateLoc: integer; 1763 MinLevel, MissionResult: Cardinal; 1764 PModel: ^TModel; 1765 UpdateLoc: array[0..numax-1] of integer; 1766 SeeFrom,SeeTo,ExtDiscover: boolean; 1767 begin 1768 result:=0; 1769 with RW[p],Un[uix] do 1770 begin 1771 PModel:=@Model[mix]; 1772 FromLoc:=Loc; 1773 1774 if Master<0 then 1775 FreeUnit(p,uix); 1776 if (MoveInfo.MoveType in [mtMove,mtCapture]) and MoveInfo.MountainDelay then 1777 begin Flags:=Flags or unMountainDelay; end; 1778 Loc:=-2; 1779 if TroopLoad+AirLoad>0 then 1780 for i:=0 to nUn-1 do 1781 if (Un[i].Loc>=0) and (Un[i].Master=uix) then 1782 Un[i].Loc:=-2; 1783 UpdateUnitMap(FromLoc); 1784 1785 if Mode>=moMovie then {show move in interface modules} 1786 begin 1787 ShowMove.EndHealth:=MoveInfo.EndHealth; 1788 ShowMove.EndHealthDef:=-1; 1789 if Master>=0 then 1790 if Model[Un[Master].mix].Domain=dAir then 1791 ShowMove.Flags:=ShowMove.Flags or umPlaneUnloading 1792 else ShowMove.Flags:=ShowMove.Flags or umShipUnloading; 1793 if MoveInfo.ToMaster>=0 then 1794 if Model[Un[MoveInfo.ToMaster].mix].Domain=dAir then 1795 ShowMove.Flags:=ShowMove.Flags or umPlaneLoading 1796 else ShowMove.Flags:=ShowMove.Flags or umShipLoading; 1797 for p1:=0 to nPl-1 do 1798 if (1 shl p1 and GWatching<>0) 1799 and ((p1<>p) or (bix[p1]=bixTerm)) then 1800 begin 1801 if PModel.Cap[mcStealth]>0 then MinLevel:=lObserveSuper 1802 else if PModel.Cap[mcSub]>0 then MinLevel:=lObserveAll 1803 else MinLevel:=lObserveUnhidden; 1804 SeeFrom:= (p1=p) or (ObserveLevel[FromLoc] shr (2*p1) and 3>=MinLevel); 1805 SeeTo:= (p1=p) or (ObserveLevel[ToLoc] shr (2*p1) and 3>=MinLevel); 1806 if SeeFrom and SeeTo then 1807 begin 1808 TellAboutModel(p1,p,mix); 1809 if p1=p then ShowMove.emix:=-1 1810 else ShowMove.emix:=emixSafe(p1,p,mix); 1811 if MoveInfo.MoveType=mtCapture then CallPlayer(cShowCapturing,p1,ShowMove) 1812 else CallPlayer(cShowMoving,p1,ShowMove); 1813 end 1814 else if SeeFrom then 1815 CallPlayer(cShowUnitChanged,p1,FromLoc); 1816 end; 1817 end; 1818 1819 if MoveInfo.MoveType<>mtSpyMission then 1820 Loc:=ToLoc; 1821 if TroopLoad+AirLoad>0 then 1822 for i:=0 to nUn-1 do 1823 if Un[i].Loc=-2 then Un[i].Loc:=ToLoc; 1824 1825 ExtDiscover:=false; 1826 nUpdateLoc:=0; 1827 if MoveInfo.MoveType=mtCapture then 1828 begin 1829 assert(Occupant[ToLoc]<0); 1830 for uix1:=0 to RW[MoveInfo.Defender].nUn-1 do with RW[MoveInfo.Defender].Un[uix1] do 1831 if (Loc>=0) and (Home=MoveInfo.Dcix) then 1832 begin UpdateLoc[nUpdateLoc]:=Loc; inc(nUpdateLoc) end; 1833 // unit will be removed -- remember position and update for all players 1834 1835 if (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size>2) and (nCity<ncmax) then 1836 begin // city captured 1837 ChangeCityOwner_TellPlayers(MoveInfo.Defender,MoveInfo.Dcix,p); 1838 City[nCity-1].Flags:=CaptureTurns shl 16; 1839 CityShrink(p,nCity-1); 1840 if Mode=moPlaying then with RW[p].City[nCity-1] do 1841 begin 1842 // SavedResourceWeights[nCity-1]:=ResourceWeights; 1843 SavedTiles[nCity-1]:=Tiles; 1844 end; 1845 ExtDiscover:=true; 1846 1847 // Temple of Zeus effect 1848 if GWonder[woZeus].EffectiveOwner=p then 1849 begin 1850 GiveCivilReport(p,MoveInfo.Defender); 1851 for i:=0 to nAdv-1 do 1852 if not (i in FutureTech) and (RW[p].Tech[i]<tsSeen) 1853 and (RW[MoveInfo.Defender].Tech[i]>=tsApplicable) then 1854 begin 1855 Happened:=Happened or phStealTech; 1856 GStealFrom:=MoveInfo.Defender; 1857 Break 1858 end 1859 end; 1860 if Mode=moPlaying then LogCheckBorders(p,nCity-1,MoveInfo.Defender); 1861 {$IFOPT O-}if Mode<moPlaying then InvalidTreatyMap:=not(1 shl p);{$ENDIF} 2145 if Mode = moPlaying then 2146 LogCheckBorders(p, nCity - 1, MoveInfo.Defender); 2147 {$IFOPT O-} if Mode < moPlaying then 2148 InvalidTreatyMap := not(1 shl p); {$ENDIF} 1862 2149 // territory should not be considered for the rest of the command 1863 2150 // execution, because during loading a game it's incorrect before 1864 2151 // subsequent sIntExpandTerritory is processed 1865 2152 end 1866 else // city destroyed1867 begin 1868 DestroyCity_TellPlayers(MoveInfo.Defender,MoveInfo.Dcix,false);1869 CheckBorders(ToLoc,MoveInfo.Defender);1870 end; 1871 RecalcPeaceMap(p);1872 if Mode>=moMovie then1873 move(GWonder,Wonder,SizeOf(GWonder));1874 end; { if MoveInfo.MoveType=mtCapture}1875 1876 if MoveInfo.MoveType=mtSpyMission then2153 else // city destroyed 2154 begin 2155 DestroyCity_TellPlayers(MoveInfo.Defender, MoveInfo.Dcix, false); 2156 CheckBorders(ToLoc, MoveInfo.Defender); 2157 end; 2158 RecalcPeaceMap(p); 2159 if Mode >= moMovie then 2160 move(GWonder, Wonder, SizeOf(GWonder)); 2161 end; { if MoveInfo.MoveType=mtCapture } 2162 2163 if MoveInfo.MoveType = mtSpyMission then 1877 2164 begin 1878 MissionResult:=DoSpyMission(p,MoveInfo.Defender,MoveInfo.Dcix,SpyMission); 1879 if (Mode=moPlaying) and (SpyMission=smStealForeignReports) then 1880 CallPlayer(cShowMissionResult,p,MissionResult); 2165 MissionResult := DoSpyMission(p, MoveInfo.Defender, MoveInfo.Dcix, 2166 SpyMission); 2167 if (Mode = moPlaying) and (SpyMission = smStealForeignReports) then 2168 CallPlayer(cShowMissionResult, p, MissionResult); 1881 2169 end; 1882 2170 1883 Health:=MoveInfo.EndHealth;1884 dec(Movement,MoveInfo.Cost);1885 // transport unload1886 if Master>=0 then2171 Health := MoveInfo.EndHealth; 2172 dec(Movement, MoveInfo.Cost); 2173 // transport unload 2174 if Master >= 0 then 1887 2175 begin 1888 if PModel.Domain=dAir then dec(Un[Master].AirLoad) 2176 if PModel.Domain = dAir then 2177 dec(Un[Master].AirLoad) 2178 else 2179 begin 2180 dec(Un[Master].TroopLoad); 2181 assert(Movement <= 0); 2182 end; 2183 Master := -1; 2184 end; 2185 2186 if (Health <= 0) or (MoveInfo.MoveType = mtSpyMission) then 2187 RemoveUnit(p, uix) // spy mission or victim of HostileDamage 1889 2188 else 1890 begin 1891 dec(Un[Master].TroopLoad); 1892 assert(Movement<=0); 1893 end; 1894 Master:=-1; 2189 begin // transport load 2190 Master := MoveInfo.ToMaster; 2191 if MoveInfo.ToMaster >= 0 then 2192 begin 2193 if PModel.Domain = dAir then 2194 inc(Un[MoveInfo.ToMaster].AirLoad) 2195 else 2196 inc(Un[MoveInfo.ToMaster].TroopLoad); 2197 end 2198 else 2199 PlaceUnit(p, uix); 1895 2200 end; 1896 2201 1897 if (Health<=0) or (MoveInfo.MoveType=mtSpyMission) then 1898 RemoveUnit(p,uix) // spy mission or victim of HostileDamage 1899 else 1900 begin // transport load 1901 Master:=MoveInfo.ToMaster; 1902 if MoveInfo.ToMaster>=0 then 1903 begin 1904 if PModel.Domain=dAir then inc(Un[MoveInfo.ToMaster].AirLoad) 1905 else inc(Un[MoveInfo.ToMaster].TroopLoad); 2202 if (MoveInfo.MoveType = mtCapture) and (nUpdateLoc > 0) then 2203 RecalcMapZoC(p); 2204 UpdateUnitMap(ToLoc, MoveInfo.MoveType = mtCapture); 2205 for i := 0 to nUpdateLoc - 1 do 2206 UpdateUnitMap(UpdateLoc[i]); 2207 // tell about lost units of defender 2208 2209 if (MoveInfo.MoveType <> mtSpyMission) and (Master < 0) then 2210 begin 2211 if (PModel.Kind = mkDiplomat) or (PModel.Domain = dAir) or 2212 (PModel.Cap[mcRadar] + PModel.Cap[mcCarrier] + PModel.Cap[mcAcademy] > 2213 0) or (RealMap[ToLoc] and fTerrain = fMountains) or 2214 (RealMap[ToLoc] and fTerImp = tiFort) or 2215 (RealMap[ToLoc] and fTerImp = tiBase) then 2216 ExtDiscover := true; 2217 if (PModel.Kind = mkDiplomat) or (PModel.Cap[mcSpy] > 0) then 2218 i := lObserveSuper 2219 else if (PModel.Domain = dAir) or 2220 (PModel.Cap[mcRadar] + PModel.Cap[mcCarrier] > 0) then 2221 i := lObserveAll 2222 else 2223 i := lObserveUnhidden; 2224 if ExtDiscover then 2225 begin 2226 if Discover21(ToLoc, p, i, true, PModel.Domain = dGround) then 2227 result := result or rEnemySpotted; 1906 2228 end 1907 else PlaceUnit(p,uix); 2229 else 2230 begin 2231 if Discover9(ToLoc, p, i, true, PModel.Domain = dGround) then 2232 result := result or rEnemySpotted; 2233 end; 1908 2234 end; 1909 2235 1910 if (MoveInfo.MoveType=mtCapture) and (nUpdateLoc>0) then 1911 RecalcMapZoC(p); 1912 UpdateUnitMap(ToLoc,MoveInfo.MoveType=mtCapture); 1913 for i:=0 to nUpdateLoc-1 do UpdateUnitMap(UpdateLoc[i]); 1914 // tell about lost units of defender 1915 1916 if (MoveInfo.MoveType<>mtSpyMission) and (Master<0) then 1917 begin 1918 if (PModel.Kind=mkDiplomat) or (PModel.Domain=dAir) 1919 or (PModel.Cap[mcRadar]+PModel.Cap[mcCarrier]+PModel.Cap[mcAcademy]>0) 1920 or (RealMap[ToLoc] and fTerrain=fMountains) 1921 or (RealMap[ToLoc] and fTerImp=tiFort) 1922 or (RealMap[ToLoc] and fTerImp=tiBase) then 1923 ExtDiscover:=true; 1924 if (PModel.Kind=mkDiplomat) or (PModel.Cap[mcSpy]>0) then 1925 i:=lObserveSuper 1926 else if (PModel.Domain=dAir) 1927 or (PModel.Cap[mcRadar]+PModel.Cap[mcCarrier]>0) then 1928 i:=lObserveAll 1929 else i:=lObserveUnhidden; 1930 if ExtDiscover then 1931 begin 1932 if Discover21(ToLoc,p,i,true, PModel.Domain=dGround) then 1933 result:=result or rEnemySpotted; 1934 end 1935 else 1936 begin 1937 if Discover9(ToLoc,p,i,true, PModel.Domain=dGround) then 1938 result:=result or rEnemySpotted; 1939 end; 1940 end; 1941 1942 if Mode>=moMovie then {show after-move in interface modules} 1943 for p1:=0 to nPl-1 do 1944 if (1 shl p1 and GWatching<>0) 1945 and ((p1<>p) or (bix[p1]=bixTerm)) then 2236 if Mode >= moMovie then { show after-move in interface modules } 2237 for p1 := 0 to nPl - 1 do 2238 if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm)) 2239 then 1946 2240 begin 1947 if PModel.Cap[mcStealth]>0 then MinLevel:=lObserveSuper 1948 else if PModel.Cap[mcSub]>0 then MinLevel:=lObserveAll 1949 else MinLevel:=lObserveUnhidden; 1950 SeeFrom:= (p1=p) or (ObserveLevel[FromLoc] shr (2*p1) and 3>=MinLevel); 1951 SeeTo:= (p1=p) or (ObserveLevel[ToLoc] shr (2*p1) and 3>=MinLevel); 1952 if SeeTo and (MoveInfo.MoveType=mtCapture) then 1953 CallPlayer(cShowCityChanged,p1,ToLoc); 1954 if SeeFrom and SeeTo then 1955 CallPlayer(cShowAfterMove,p1,ToLoc) 1956 else if (MoveInfo.MoveType<>mtSpyMission) and SeeTo then 1957 CallPlayer(cShowUnitChanged,p1,ToLoc); 1958 for i:=0 to nUpdateLoc-1 do 1959 if ObserveLevel[UpdateLoc[i]] shr (2*p1) and 3>=lObserveUnhidden then 1960 CallPlayer(cShowUnitChanged,p1,UpdateLoc[i]); 2241 if PModel.Cap[mcStealth] > 0 then 2242 MinLevel := lObserveSuper 2243 else if PModel.Cap[mcSub] > 0 then 2244 MinLevel := lObserveAll 2245 else 2246 MinLevel := lObserveUnhidden; 2247 SeeFrom := (p1 = p) or (ObserveLevel[FromLoc] shr (2 * p1) and 2248 3 >= MinLevel); 2249 SeeTo := (p1 = p) or (ObserveLevel[ToLoc] shr (2 * p1) and 2250 3 >= MinLevel); 2251 if SeeTo and (MoveInfo.MoveType = mtCapture) then 2252 CallPlayer(cShowCityChanged, p1, ToLoc); 2253 if SeeFrom and SeeTo then 2254 CallPlayer(cShowAfterMove, p1, ToLoc) 2255 else if (MoveInfo.MoveType <> mtSpyMission) and SeeTo then 2256 CallPlayer(cShowUnitChanged, p1, ToLoc); 2257 for i := 0 to nUpdateLoc - 1 do 2258 if ObserveLevel[UpdateLoc[i]] shr (2 * p1) and 3 >= lObserveUnhidden 2259 then 2260 CallPlayer(cShowUnitChanged, p1, UpdateLoc[i]); 1961 2261 end; 1962 2262 end; 1963 2263 end; // ExecuteMove 1964 2264 1965 function ExecuteAttack(p, uix,ToLoc: integer;1966 var MoveInfo: TMoveInfo;ShowMove: TShowMove): integer;1967 1968 procedure WriteBattleHistory(ToLoc, FromLoc, Attacker, Defender, 1969 mix Attacker, mixDefender: integer; AttackerLost, DefenderLost: boolean);2265 function ExecuteAttack(p, uix, ToLoc: integer; var MoveInfo: TMoveInfo; 2266 ShowMove: TShowMove): integer; 2267 2268 procedure WriteBattleHistory(ToLoc, FromLoc, Attacker, Defender, mixAttacker, 2269 mixDefender: integer; AttackerLost, DefenderLost: boolean); 1970 2270 var 1971 AttackerBattle, DefenderBattle: ^TBattle;2271 AttackerBattle, DefenderBattle: ^TBattle; 1972 2272 begin 1973 with RW[Attacker] do2273 with RW[Attacker] do 1974 2274 begin 1975 if nBattleHistory=0 then1976 ReallocMem(BattleHistory, 16*SizeOf(TBattle))1977 else if (nBattleHistory>=16)1978 and (nBattleHistory and (nBattleHistory-1)=0) then1979 ReallocMem(BattleHistory, nBattleHistory*(2*SizeOf(TBattle)));1980 AttackerBattle:=@BattleHistory[nBattleHistory];1981 inc(nBattleHistory);2275 if nBattleHistory = 0 then 2276 ReallocMem(BattleHistory, 16 * SizeOf(TBattle)) 2277 else if (nBattleHistory >= 16) and 2278 (nBattleHistory and (nBattleHistory - 1) = 0) then 2279 ReallocMem(BattleHistory, nBattleHistory * (2 * SizeOf(TBattle))); 2280 AttackerBattle := @BattleHistory[nBattleHistory]; 2281 inc(nBattleHistory); 1982 2282 end; 1983 with RW[Defender] do2283 with RW[Defender] do 1984 2284 begin 1985 if nBattleHistory=0 then1986 ReallocMem(BattleHistory, 16*SizeOf(TBattle))1987 else if (nBattleHistory>=16)1988 and (nBattleHistory and (nBattleHistory-1)=0) then1989 ReallocMem(BattleHistory, nBattleHistory*(2*SizeOf(TBattle)));1990 DefenderBattle:=@BattleHistory[nBattleHistory];1991 inc(nBattleHistory);2285 if nBattleHistory = 0 then 2286 ReallocMem(BattleHistory, 16 * SizeOf(TBattle)) 2287 else if (nBattleHistory >= 16) and 2288 (nBattleHistory and (nBattleHistory - 1) = 0) then 2289 ReallocMem(BattleHistory, nBattleHistory * (2 * SizeOf(TBattle))); 2290 DefenderBattle := @BattleHistory[nBattleHistory]; 2291 inc(nBattleHistory); 1992 2292 end; 1993 AttackerBattle.Enemy:=Defender;1994 AttackerBattle.Flags:=0;1995 AttackerBattle.Turn:=GTurn;1996 AttackerBattle.mix:=mixAttacker;1997 AttackerBattle.mixEnemy:=mixDefender;1998 AttackerBattle.ToLoc:=ToLoc;1999 AttackerBattle.FromLoc:=FromLoc;2000 DefenderBattle.Enemy:=Attacker;2001 DefenderBattle.Flags:=bhEnemyAttack;2002 DefenderBattle.Turn:=GTurn;2003 DefenderBattle.mix:=mixDefender;2004 DefenderBattle.mixEnemy:=mixAttacker;2005 DefenderBattle.ToLoc:=ToLoc;2006 DefenderBattle.FromLoc:=FromLoc;2007 if AttackerLost then2293 AttackerBattle.Enemy := Defender; 2294 AttackerBattle.Flags := 0; 2295 AttackerBattle.Turn := GTurn; 2296 AttackerBattle.mix := mixAttacker; 2297 AttackerBattle.mixEnemy := mixDefender; 2298 AttackerBattle.ToLoc := ToLoc; 2299 AttackerBattle.FromLoc := FromLoc; 2300 DefenderBattle.Enemy := Attacker; 2301 DefenderBattle.Flags := bhEnemyAttack; 2302 DefenderBattle.Turn := GTurn; 2303 DefenderBattle.mix := mixDefender; 2304 DefenderBattle.mixEnemy := mixAttacker; 2305 DefenderBattle.ToLoc := ToLoc; 2306 DefenderBattle.FromLoc := FromLoc; 2307 if AttackerLost then 2008 2308 begin 2009 AttackerBattle.Flags:=AttackerBattle.Flags or bhMyUnitLost;2010 DefenderBattle.Flags:=DefenderBattle.Flags or bhEnemyUnitLost;2309 AttackerBattle.Flags := AttackerBattle.Flags or bhMyUnitLost; 2310 DefenderBattle.Flags := DefenderBattle.Flags or bhEnemyUnitLost; 2011 2311 end; 2012 if DefenderLost then2312 if DefenderLost then 2013 2313 begin 2014 AttackerBattle.Flags:=AttackerBattle.Flags or bhEnemyUnitLost;2015 DefenderBattle.Flags:=DefenderBattle.Flags or bhMyUnitLost;2314 AttackerBattle.Flags := AttackerBattle.Flags or bhEnemyUnitLost; 2315 DefenderBattle.Flags := DefenderBattle.Flags or bhMyUnitLost; 2016 2316 end; 2017 2317 end; 2018 2318 2019 2319 var 2020 i,p1,FromLoc,uix1,nUpdateLoc,ExpGain, ExpelToLoc,cix1: integer;2021 PModel: ^TModel;2022 UpdateLoc: array[0..numax-1] of integer;2023 LoseCityPop,CityDestroyed,SeeFrom,SeeTo,ZoCDefenderDestroyed: boolean;2320 i, p1, FromLoc, uix1, nUpdateLoc, ExpGain, ExpelToLoc, cix1: integer; 2321 PModel: ^TModel; 2322 UpdateLoc: array [0 .. numax - 1] of integer; 2323 LoseCityPop, CityDestroyed, SeeFrom, SeeTo, ZoCDefenderDestroyed: boolean; 2024 2324 begin 2025 result:=0;2026 with RW[p].Un[uix] do2325 result := 0; 2326 with RW[p].Un[uix] do 2027 2327 begin 2028 PModel:=@RW[p].Model[mix];2029 FromLoc:=Loc;2030 2031 ShowMove.EndHealth:=MoveInfo.EndHealth;2032 ShowMove.EndHealthDef:=MoveInfo.EndHealthDef;2033 if MoveInfo.MoveType=mtAttack then2034 WriteBattleHistory(ToLoc, FromLoc, p, MoveInfo.Defender, mix,2035 RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix,2036 MoveInfo.EndHealth<=0, MoveInfo.EndHealthDef<=0);2037 2038 {if RW[p].Treaty[MoveInfo.Defender]=trCeaseFire then2039 begin2040 if Mode>=moMovie then2328 PModel := @RW[p].Model[mix]; 2329 FromLoc := Loc; 2330 2331 ShowMove.EndHealth := MoveInfo.EndHealth; 2332 ShowMove.EndHealthDef := MoveInfo.EndHealthDef; 2333 if MoveInfo.MoveType = mtAttack then 2334 WriteBattleHistory(ToLoc, FromLoc, p, MoveInfo.Defender, mix, 2335 RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix, MoveInfo.EndHealth <= 0, 2336 MoveInfo.EndHealthDef <= 0); 2337 2338 { if RW[p].Treaty[MoveInfo.Defender]=trCeaseFire then 2339 begin 2340 if Mode>=moMovie then 2041 2341 CallPlayer(cShowCancelTreaty,MoveInfo.Defender,p); 2042 CancelTreaty(p,MoveInfo.Defender)2043 end;}2044 if Mode>=moMovie then {show attack in interface modules}2045 for p1:=0 to nPl-1 do2046 if (1 shl p1 and GWatching<>0)2047 and ((p1<>p) or (bix[p1]=bixTerm))then2342 CancelTreaty(p,MoveInfo.Defender) 2343 end; } 2344 if Mode >= moMovie then { show attack in interface modules } 2345 for p1 := 0 to nPl - 1 do 2346 if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm)) 2347 then 2048 2348 begin 2049 SeeFrom:= ObserveLevel[FromLoc] shr (2*p1) and 3>=lObserveUnhidden; 2050 SeeTo:= ObserveLevel[ToLoc] shr (2*p1) and 3>=lObserveUnhidden; 2051 if SeeFrom and SeeTo then 2349 SeeFrom := ObserveLevel[FromLoc] shr (2 * p1) and 2350 3 >= lObserveUnhidden; 2351 SeeTo := ObserveLevel[ToLoc] shr (2 * p1) and 3 >= lObserveUnhidden; 2352 if SeeFrom and SeeTo then 2052 2353 begin 2053 TellAboutModel(p1,p,mix); 2054 if p1=p then ShowMove.emix:=-1 2055 else ShowMove.emix:=emixSafe(p1,p,mix); 2056 CallPlayer(cShowAttacking,p1,ShowMove); 2354 TellAboutModel(p1, p, mix); 2355 if p1 = p then 2356 ShowMove.emix := -1 2357 else 2358 ShowMove.emix := emixSafe(p1, p, mix); 2359 CallPlayer(cShowAttacking, p1, ShowMove); 2057 2360 end; 2058 2361 end; 2059 2362 2060 LoseCityPop:=false; 2061 if (RealMap[ToLoc] and fCity<>0) and 2062 ((MoveInfo.MoveType=mtAttack) and (MoveInfo.EndHealthDef<=0) 2063 or (MoveInfo.MoveType=mtBombard) and (BombardmentDestroysCity or (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size>2))) then 2064 case PModel.Domain of 2065 dGround: LoseCityPop:= (PModel.Cap[mcArtillery]>0) 2066 or (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Built[imWalls]=0) 2067 and (Continent[ToLoc]<>GrWallContinent[MoveInfo.Defender]); 2068 dSea: LoseCityPop:= RW[MoveInfo.Defender].City[MoveInfo.Dcix].Built[imCoastalFort]=0; 2069 dAir: LoseCityPop:= RW[MoveInfo.Defender].City[MoveInfo.Dcix].Built[imMissileBat]=0; 2070 end; 2071 CityDestroyed:=LoseCityPop and (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size<=2); 2072 2073 if MoveInfo.MoveType=mtBombard then 2363 LoseCityPop := false; 2364 if (RealMap[ToLoc] and fCity <> 0) and 2365 ((MoveInfo.MoveType = mtAttack) and (MoveInfo.EndHealthDef <= 0) or 2366 (MoveInfo.MoveType = mtBombard) and (BombardmentDestroysCity or 2367 (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size > 2))) then 2368 case PModel.Domain of 2369 dGround: 2370 LoseCityPop := (PModel.Cap[mcArtillery] > 0) or 2371 (RW[MoveInfo.Defender].City[MoveInfo.Dcix].built[imWalls] = 0) and 2372 (Continent[ToLoc] <> GrWallContinent[MoveInfo.Defender]); 2373 dSea: 2374 LoseCityPop := RW[MoveInfo.Defender].City[MoveInfo.Dcix].built 2375 [imCoastalFort] = 0; 2376 dAir: 2377 LoseCityPop := RW[MoveInfo.Defender].City[MoveInfo.Dcix].built 2378 [imMissileBat] = 0; 2379 end; 2380 CityDestroyed := LoseCityPop and 2381 (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size <= 2); 2382 2383 if MoveInfo.MoveType = mtBombard then 2074 2384 begin 2075 assert(Movement>=100); 2076 if PModel.Attack=0 then Flags:=Flags and not unBombsLoaded; 2077 dec(Movement,100) 2385 assert(Movement >= 100); 2386 if PModel.Attack = 0 then 2387 Flags := Flags and not unBombsLoaded; 2388 dec(Movement, 100) 2078 2389 end 2079 else if MoveInfo.MoveType=mtExpel then2390 else if MoveInfo.MoveType = mtExpel then 2080 2391 begin 2081 assert(Movement>=100);2082 Job:=jNone;2083 Flags:=Flags and not unFortified;2084 dec(Movement,100)2392 assert(Movement >= 100); 2393 Job := jNone; 2394 Flags := Flags and not unFortified; 2395 dec(Movement, 100) 2085 2396 end 2086 else2397 else 2087 2398 begin 2088 assert(MoveInfo.MoveType=mtAttack); 2089 if MoveInfo.EndHealth=0 then 2090 RemoveUnit(p,uix,MoveInfo.Defender) // destroy attacker 2399 assert(MoveInfo.MoveType = mtAttack); 2400 if MoveInfo.EndHealth = 0 then 2401 RemoveUnit(p, uix, MoveInfo.Defender) // destroy attacker 2402 else 2403 begin // update attacker 2404 ExpGain := (Health - MoveInfo.EndHealth + 1) shr 1; 2405 if Exp + ExpGain > (nExp - 1) * ExpCost then 2406 Exp := (nExp - 1) * ExpCost 2407 else 2408 inc(Exp, ExpGain); 2409 Health := MoveInfo.EndHealth; 2410 Job := jNone; 2411 if RW[MoveInfo.Defender].Model[RW[MoveInfo.Defender].Un[MoveInfo.Duix] 2412 .mix].Domain < dAir then 2413 Flags := Flags and not unBombsLoaded; 2414 Flags := Flags and not unFortified; 2415 if Movement > 100 then 2416 dec(Movement, 100) 2417 else 2418 Movement := 0; 2419 end; 2420 end; 2421 2422 ZoCDefenderDestroyed := false; 2423 nUpdateLoc := 0; 2424 if MoveInfo.MoveType = mtExpel then 2425 with RW[MoveInfo.Defender], Un[MoveInfo.Duix] do 2426 begin // expel friendly unit 2427 if Home >= 0 then 2428 ExpelToLoc := City[Home].Loc 2429 else 2430 begin 2431 ExpelToLoc := City[0].Loc; // search destination for homeless units 2432 for cix1 := 1 to nCity - 1 do 2433 if (City[cix1].Loc >= 0) and 2434 ((ExpelToLoc < 0) or (City[cix1].built[imPalace] > 0)) then 2435 ExpelToLoc := City[cix1].Loc; 2436 end; 2437 if ExpelToLoc >= 0 then 2438 begin 2439 FreeUnit(MoveInfo.Defender, MoveInfo.Duix); 2440 Loc := ExpelToLoc; 2441 PlaceUnit(MoveInfo.Defender, MoveInfo.Duix); 2442 UpdateLoc[nUpdateLoc] := Loc; 2443 inc(nUpdateLoc); 2444 Flags := Flags or unWithdrawn; 2445 end 2446 end 2447 else if (MoveInfo.MoveType = mtAttack) and (MoveInfo.EndHealthDef > 0) then 2448 with RW[MoveInfo.Defender].Un[MoveInfo.Duix] do 2449 begin // update defender 2450 ExpGain := (Health - MoveInfo.EndHealthDef + 1) shr 1; 2451 if Exp + ExpGain > (nExp - 1) * ExpCost then 2452 Exp := (nExp - 1) * ExpCost 2453 else 2454 inc(Exp, ExpGain); 2455 Health := MoveInfo.EndHealthDef; 2456 end 2091 2457 else 2092 begin // update attacker2093 ExpGain:=(Health-MoveInfo.EndHealth+1) shr 1;2094 if Exp+ExpGain>(nExp-1)*ExpCost then Exp:=(nExp-1)*ExpCost2095 else inc(Exp,ExpGain);2096 Health:=MoveInfo.EndHealth;2097 Job:=jNone;2098 if RW[MoveInfo.Defender].Model[RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix].Domain<dAir then2099 Flags:=Flags and not unBombsLoaded;2100 Flags:=Flags and not unFortified;2101 if Movement>100 then dec(Movement,100)2102 else Movement:=0;2103 end;2104 end;2105 2106 ZoCDefenderDestroyed:=false;2107 nUpdateLoc:=0;2108 if MoveInfo.MoveType=mtExpel then with RW[MoveInfo.Defender],Un[MoveInfo.Duix] do2109 begin // expel friendly unit2110 if Home>=0 then ExpelToLoc:=City[Home].Loc2111 else2112 begin2113 ExpelToLoc:=City[0].Loc; // search destination for homeless units2114 for cix1:=1 to nCity-1 do2115 if (City[cix1].Loc>=0) and ((ExpelToLoc<0) or (City[cix1].Built[imPalace]>0)) then2116 ExpelToLoc:=City[cix1].Loc;2117 end;2118 if ExpelToLoc>=0 then2119 begin2120 FreeUnit(MoveInfo.Defender,MoveInfo.Duix);2121 Loc:=ExpelToLoc;2122 PlaceUnit(MoveInfo.Defender,MoveInfo.Duix);2123 UpdateLoc[nUpdateLoc]:=Loc;2124 inc(nUpdateLoc);2125 Flags:=Flags or unWithdrawn;2126 end2127 end2128 else if (MoveInfo.MoveType=mtAttack) and (MoveInfo.EndHealthDef>0) then2129 with RW[MoveInfo.Defender].Un[MoveInfo.Duix] do2130 begin // update defender2131 ExpGain:=(Health-MoveInfo.EndHealthDef+1) shr 1;2132 if Exp+ExpGain>(nExp-1)*ExpCost then Exp:=(nExp-1)*ExpCost2133 else inc(Exp,ExpGain);2134 Health:=MoveInfo.EndHealthDef;2135 end2136 else2137 2458 begin // destroy defenders 2138 if MoveInfo.MoveType<>mtBombard then 2139 begin 2140 ZoCDefenderDestroyed:=RW[MoveInfo.Defender].Model[RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix].Flags and mdZOC<>0; 2141 if ((RealMap[ToLoc] and fCity=0) 2142 and (RealMap[ToLoc] and fTerImp<>tiBase) 2143 and (RealMap[ToLoc] and fTerImp<>tiFort)) 2144 or LoseCityPop and (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size=2) then 2145 RemoveAllUnits(MoveInfo.Defender,ToLoc,p) {no city, base or fortress} 2146 else RemoveUnit(MoveInfo.Defender,MoveInfo.Duix,p); 2147 end; 2148 2149 if LoseCityPop then // city defender defeated -- shrink city 2150 if not CityDestroyed then 2151 CityShrink(MoveInfo.Defender,MoveInfo.Dcix) 2152 else 2459 if MoveInfo.MoveType <> mtBombard then 2460 begin 2461 ZoCDefenderDestroyed := RW[MoveInfo.Defender].Model 2462 [RW[MoveInfo.Defender].Un[MoveInfo.Duix].mix].Flags and mdZOC <> 0; 2463 if ((RealMap[ToLoc] and fCity = 0) and 2464 (RealMap[ToLoc] and fTerImp <> tiBase) and 2465 (RealMap[ToLoc] and fTerImp <> tiFort)) or LoseCityPop and 2466 (RW[MoveInfo.Defender].City[MoveInfo.Dcix].Size = 2) then 2467 RemoveAllUnits(MoveInfo.Defender, ToLoc, p) 2468 { no city, base or fortress } 2469 else 2470 RemoveUnit(MoveInfo.Defender, MoveInfo.Duix, p); 2471 end; 2472 2473 if LoseCityPop then // city defender defeated -- shrink city 2474 if not CityDestroyed then 2475 CityShrink(MoveInfo.Defender, MoveInfo.Dcix) 2476 else 2153 2477 begin 2154 for uix1:=0 to RW[MoveInfo.Defender].nUn-1 do with RW[MoveInfo.Defender].Un[uix1] do 2155 if (Loc>=0) and (Home=MoveInfo.Dcix) then 2156 begin UpdateLoc[nUpdateLoc]:=Loc; inc(nUpdateLoc) end; 2157 // unit will be removed -- remember position and update for all players 2158 DestroyCity_TellPlayers(MoveInfo.Defender,MoveInfo.Dcix,false); 2159 CheckBorders(ToLoc,MoveInfo.Defender); 2160 RecalcPeaceMap(p); 2478 for uix1 := 0 to RW[MoveInfo.Defender].nUn - 1 do 2479 with RW[MoveInfo.Defender].Un[uix1] do 2480 if (Loc >= 0) and (Home = MoveInfo.Dcix) then 2481 begin 2482 UpdateLoc[nUpdateLoc] := Loc; 2483 inc(nUpdateLoc) 2484 end; 2485 // unit will be removed -- remember position and update for all players 2486 DestroyCity_TellPlayers(MoveInfo.Defender, MoveInfo.Dcix, false); 2487 CheckBorders(ToLoc, MoveInfo.Defender); 2488 RecalcPeaceMap(p); 2161 2489 end; 2162 2490 end; 2163 2491 2164 if CityDestroyed and (nUpdateLoc>0) then 2165 RecalcMapZoC(p) 2166 else if ZoCDefenderDestroyed then 2167 RecalcV8ZoC(p,ToLoc); 2168 UpdateUnitMap(FromLoc); 2169 UpdateUnitMap(ToLoc,LoseCityPop); 2170 for i:=0 to nUpdateLoc-1 do UpdateUnitMap(UpdateLoc[i]); 2492 if CityDestroyed and (nUpdateLoc > 0) then 2493 RecalcMapZoC(p) 2494 else if ZoCDefenderDestroyed then 2495 RecalcV8ZoC(p, ToLoc); 2496 UpdateUnitMap(FromLoc); 2497 UpdateUnitMap(ToLoc, LoseCityPop); 2498 for i := 0 to nUpdateLoc - 1 do 2499 UpdateUnitMap(UpdateLoc[i]); 2171 2500 // tell about lost units of defender 2172 2501 2173 if Mode>=moMovie then2502 if Mode >= moMovie then 2174 2503 begin 2175 for i:=0 to RW[p].nEnemyModel-1 do with RW[p].EnemyModel[i] do 2176 Lost:=Destroyed[p,Owner,mix]; 2177 for p1:=0 to nPl-1 do {show after-attack in interface modules} 2178 if (1 shl p1 and GWatching<>0) 2179 and ((p1<>p) or (bix[p1]=bixTerm)) then 2504 for i := 0 to RW[p].nEnemyModel - 1 do 2505 with RW[p].EnemyModel[i] do 2506 Lost := Destroyed[p, Owner, mix]; 2507 for p1 := 0 to nPl - 1 do { show after-attack in interface modules } 2508 if (1 shl p1 and GWatching <> 0) and ((p1 <> p) or (bix[p1] = bixTerm)) 2509 then 2180 2510 begin 2181 SeeFrom:= ObserveLevel[FromLoc] shr (2*p1) and 3>=lObserveUnhidden; 2182 SeeTo:= ObserveLevel[ToLoc] shr (2*p1) and 3>=lObserveUnhidden; 2183 if SeeTo and CityDestroyed then 2184 CallPlayer(cShowCityChanged,p1,ToLoc); // city was destroyed 2185 if SeeFrom and SeeTo then 2511 SeeFrom := ObserveLevel[FromLoc] shr (2 * p1) and 2512 3 >= lObserveUnhidden; 2513 SeeTo := ObserveLevel[ToLoc] shr (2 * p1) and 3 >= lObserveUnhidden; 2514 if SeeTo and CityDestroyed then 2515 CallPlayer(cShowCityChanged, p1, ToLoc); // city was destroyed 2516 if SeeFrom and SeeTo then 2186 2517 begin 2187 CallPlayer(cShowAfterAttack,p1,ToLoc);2188 CallPlayer(cShowAfterAttack,p1,FromLoc);2518 CallPlayer(cShowAfterAttack, p1, ToLoc); 2519 CallPlayer(cShowAfterAttack, p1, FromLoc); 2189 2520 end 2190 else2521 else 2191 2522 begin 2192 if SeeTo then2193 CallPlayer(cShowUnitChanged,p1,ToLoc);2194 if SeeFrom then2195 CallPlayer(cShowUnitChanged,p1,FromLoc);2523 if SeeTo then 2524 CallPlayer(cShowUnitChanged, p1, ToLoc); 2525 if SeeFrom then 2526 CallPlayer(cShowUnitChanged, p1, FromLoc); 2196 2527 end; 2197 if SeeTo and (MoveInfo.MoveType=mtExpel) and (ExpelToLoc>=0) then2198 CallPlayer(cShowUnitChanged,p1,ExpelToLoc);2528 if SeeTo and (MoveInfo.MoveType = mtExpel) and (ExpelToLoc >= 0) then 2529 CallPlayer(cShowUnitChanged, p1, ExpelToLoc); 2199 2530 end; 2200 2531 end … … 2202 2533 end; // ExecuteAttack 2203 2534 2204 function MoveUnit(p, uix,dx,dy: integer; TestOnly: boolean): integer;2535 function MoveUnit(p, uix, dx, dy: integer; TestOnly: boolean): integer; 2205 2536 var 2206 ToLoc: integer;2207 MoveInfo: TMoveInfo;2208 ShowMove: TShowMove;2537 ToLoc: integer; 2538 MoveInfo: TMoveInfo; 2539 ShowMove: TShowMove; 2209 2540 begin 2210 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap =0);{$ENDIF}2211 with RW[p].Un[uix] do2541 {$IFOPT O-}assert(1 shl p and InvalidTreatyMap = 0); {$ENDIF} 2542 with RW[p].Un[uix] do 2212 2543 begin 2213 ToLoc:=dLoc(Loc,dx,dy); 2214 if (ToLoc<0) or (ToLoc>=MapSize) then 2215 begin result:=eInvalid; exit end; 2216 result:=CalculateMove(p,uix,ToLoc,3-dy and 1,TestOnly,MoveInfo); 2217 if result=eZOC_EnemySpotted then 2218 ZOCTile:=ToLoc; 2219 if (result>=rExecuted) and not TestOnly then 2544 ToLoc := dLoc(Loc, dx, dy); 2545 if (ToLoc < 0) or (ToLoc >= MapSize) then 2220 2546 begin 2221 ShowMove.dx:=dx; 2222 ShowMove.dy:=dy; 2223 ShowMove.FromLoc:=Loc; 2224 ShowMove.mix:=mix; 2225 ShowMove.Health:=Health; 2226 ShowMove.Fuel:=Fuel; 2227 ShowMove.Exp:=Exp; 2228 ShowMove.Load:=TroopLoad+AirLoad; 2229 ShowMove.Owner:=p; 2230 if (TroopLoad>0) or (AirLoad>0) then 2231 ShowMove.Flags:=unMulti 2232 else ShowMove.Flags:=0; 2233 case MoveInfo.MoveType of 2234 mtCapture: ShowMove.Flags:=ShowMove.Flags or umCapturing; 2235 mtSpyMission: ShowMove.Flags:=ShowMove.Flags or umSpyMission; 2236 mtBombard: ShowMove.Flags:=ShowMove.Flags or umBombarding; 2237 mtExpel: ShowMove.Flags:=ShowMove.Flags or umExpelling; 2238 end; 2239 case MoveInfo.MoveType of 2240 mtMove,mtCapture,mtSpyMission: 2241 result:=ExecuteMove(p,uix,ToLoc,MoveInfo,ShowMove) or result; 2242 mtAttack,mtBombard,mtExpel: 2243 result:=ExecuteAttack(p,uix,ToLoc,MoveInfo,ShowMove) or result 2547 result := eInvalid; 2548 exit 2549 end; 2550 result := CalculateMove(p, uix, ToLoc, 3 - dy and 1, TestOnly, MoveInfo); 2551 if result = eZOC_EnemySpotted then 2552 ZOCTile := ToLoc; 2553 if (result >= rExecuted) and not TestOnly then 2554 begin 2555 ShowMove.dx := dx; 2556 ShowMove.dy := dy; 2557 ShowMove.FromLoc := Loc; 2558 ShowMove.mix := mix; 2559 ShowMove.Health := Health; 2560 ShowMove.Fuel := Fuel; 2561 ShowMove.Exp := Exp; 2562 ShowMove.Load := TroopLoad + AirLoad; 2563 ShowMove.Owner := p; 2564 if (TroopLoad > 0) or (AirLoad > 0) then 2565 ShowMove.Flags := unMulti 2566 else 2567 ShowMove.Flags := 0; 2568 case MoveInfo.MoveType of 2569 mtCapture: 2570 ShowMove.Flags := ShowMove.Flags or umCapturing; 2571 mtSpyMission: 2572 ShowMove.Flags := ShowMove.Flags or umSpyMission; 2573 mtBombard: 2574 ShowMove.Flags := ShowMove.Flags or umBombarding; 2575 mtExpel: 2576 ShowMove.Flags := ShowMove.Flags or umExpelling; 2577 end; 2578 case MoveInfo.MoveType of 2579 mtMove, mtCapture, mtSpyMission: 2580 result := ExecuteMove(p, uix, ToLoc, MoveInfo, ShowMove) or result; 2581 mtAttack, mtBombard, mtExpel: 2582 result := ExecuteAttack(p, uix, ToLoc, MoveInfo, ShowMove) or result 2244 2583 end; 2245 2584 end 2246 2585 end; // with 2247 end; { MoveUnit}2248 2249 function Server(Command, Player,Subject:integer;var Data): integer; stdcall;2586 end; { MoveUnit } 2587 2588 function Server(Command, Player, Subject: integer; var Data): integer; stdcall; 2250 2589 2251 2590 function CountPrice(const Offer: TOffer; PriceType: integer): integer; 2252 2591 var 2253 i: integer;2592 i: integer; 2254 2593 begin 2255 result:=0; 2256 for i:=0 to Offer.nDeliver+Offer.nCost-1 do 2257 if Offer.Price[i] and $FFFF0000=Cardinal(PriceType) then inc(result); 2594 result := 0; 2595 for i := 0 to Offer.nDeliver + Offer.nCost - 1 do 2596 if Offer.Price[i] and $FFFF0000 = Cardinal(PriceType) then 2597 inc(result); 2258 2598 end; 2259 2599 2260 { procedure UpdateBorderHelper;2600 { procedure UpdateBorderHelper; 2261 2601 var 2262 2602 x, y, Loc, Loc1, dx, dy, ObserveMask: integer; … … 2264 2604 ObserveMask:=3 shl (2*pTurn); 2265 2605 for x:=0 to lx-1 do for y:=0 to ly shr 1-1 do 2266 begin 2267 Loc:=lx*(y*2)+x; 2268 if ObserveLevel[Loc] and ObserveMask<>0 then 2269 begin 2270 for dy:=0 to 1 do for dx:=0 to 1 do 2606 begin 2607 Loc:=lx*(y*2)+x; 2608 if ObserveLevel[Loc] and ObserveMask<>0 then 2609 begin 2610 for dy:=0 to 1 do for dx:=0 to 1 do 2611 begin 2612 Loc1:=(Loc+dx-1+lx) mod lx +lx*((y+dy)*2-1); 2613 if (Loc1>=0) and (Loc1<MapSize) 2614 and (ObserveLevel[Loc1] and ObserveMask<>0) then 2615 if RealMap[Loc1] and $78000000=RealMap[Loc] and $78000000 then 2616 begin 2617 RW[pTurn].BorderHelper[Loc]:=RW[pTurn].BorderHelper[Loc] and not (1 shl (dy*2+dx)); 2618 RW[pTurn].BorderHelper[Loc1]:=RW[pTurn].BorderHelper[Loc1] and not (8 shr (dy*2+dx)) 2619 end 2620 else 2621 begin 2622 RW[pTurn].BorderHelper[Loc]:=RW[pTurn].BorderHelper[Loc] or (1 shl (dy*2+dx)); 2623 RW[pTurn].BorderHelper[Loc1]:=RW[pTurn].BorderHelper[Loc1] or (8 shr (dy*2+dx)); 2624 end 2625 end 2626 end 2627 end 2628 end; } 2629 2630 const 2631 ptSelect = 0; 2632 ptTrGoods = 1; 2633 ptUn = 2; 2634 ptCaravan = 3; 2635 ptImp = 4; 2636 ptWonder = 6; 2637 ptShip = 7; 2638 ptInvalid = 8; 2639 2640 function ProjectType(Project: integer): integer; 2641 begin 2642 if Project and cpCompleted <> 0 then 2643 result := ptSelect 2644 else if Project and (cpImp + cpIndex) = cpImp + imTrGoods then 2645 result := ptTrGoods 2646 else if Project and cpImp = 0 then 2647 if RW[Player].Model[Project and cpIndex].Kind = mkCaravan then 2648 result := ptCaravan 2649 else 2650 result := ptUn 2651 else if Project and cpIndex >= nImp then 2652 result := ptInvalid 2653 else if Imp[Project and cpIndex].Kind = ikWonder then 2654 result := ptWonder 2655 else if Imp[Project and cpIndex].Kind = ikShipPart then 2656 result := ptShip 2657 else 2658 result := ptImp 2659 end; 2660 2661 const 2662 Dirx: array [0 .. 7] of integer = (1, 2, 1, 0, -1, -2, -1, 0); 2663 Diry: array [0 .. 7] of integer = (-1, 0, 1, 2, 1, 0, -1, -2); 2664 2665 var 2666 d, i, j, p1, p2, pt0, pt1, uix1, cix1, Loc0, Loc1, dx, dy, NewCap, MinCap, 2667 MaxCap, CapWeight, Cost, NextProd, Preq, TotalFood, TotalProd, CheckSum, 2668 StopTurn, FutureMCost, NewProject, OldImp, mix, V8, V21, AStr, DStr, 2669 ABaseDamage, DBaseDamage: integer; 2670 CityReport, AltCityReport: TCityReport; 2671 FormerCLState: TCmdListState; 2672 EndTime: int64; 2673 Adjacent: TVicinity8Loc; 2674 Radius: TVicinity21Loc; 2675 ShowShipChange: TShowShipChange; 2676 ShowNegoData: TShowNegoData; 2677 logged, ok, HasShipChanged, AllHumansDead, OfferFullySupported: boolean; 2678 2679 begin { >>>server } 2680 if Command = sTurn then 2681 begin 2682 p2 := -1; 2683 for p1 := 0 to nPl - 1 do 2684 if (p1 <> Player) and (1 shl p1 and GWatching <> 0) then 2685 CallPlayer(cShowTurnChange, p1, p2); 2686 end; 2687 2688 assert(MapSize = lx * ly); 2689 assert(Command and (sctMask or sExecute) <> sctInternal or sExecute); 2690 // not for internal commands 2691 if (Command < 0) or (Command >= $10000) then 2692 begin 2693 result := eUnknown; 2694 exit 2695 end; 2696 2697 if (Player < 0) or (Player >= nPl) or 2698 ((Command and (sctMask or sExecute) <> sctInfo) and 2699 ((Subject < 0) or (Subject >= $1000))) then 2700 begin 2701 result := eInvalid; 2702 exit 2703 end; 2704 2705 if (1 shl Player and (GAlive or GWatching) = 0) and 2706 not((Command = sTurn) or (Command = sBreak) or (Command = sResign) or 2707 (Command = sGetAIInfo) or (Command = sGetAICredits) or 2708 (Command = sGetVersion) or (Command and $FF0F = sGetChart)) then 2709 begin 2710 PutMessage(1 shl 16 + 1, Format('NOT Alive: %d', [Player])); 2711 result := eNoTurn; 2712 exit 2713 end; 2714 2715 result := eOK; 2716 2717 // check if command allowed now 2718 if (Mode = moPlaying) and not((Command >= cClientEx) or (Command = sMessage) 2719 or (Command = sSetDebugMap) or (Command = sGetDebugMap) or 2720 (Command = sGetAIInfo) or (Command = sGetAICredits) or 2721 (Command = sGetVersion) or (Command = sGetTechCost) or 2722 (Command = sGetDefender) or (Command = sGetUnitReport) or 2723 (Command = sGetCityReport) or (Command = sGetCityTileInfo) or 2724 (Command = sGetCity) or (Command = sGetEnemyCityReport) or 2725 (Command = sGetEnemyCityAreaInfo) or (Command = sGetCityReportNew) or 2726 (Command and $FF0F = sGetChart) or (Command and $FF0F = sSetAttitude)) 2727 // commands always allowed 2728 and not((Player = pTurn) and (Command < $1000)) 2729 // info request always allowed for pTurn 2730 and ((pDipActive < 0) and (Player <> pTurn) // not his turn 2731 or (pDipActive >= 0) and (Player <> pDipActive) 2732 // not active in negotiation mode 2733 or (pDipActive >= 0) and (Command and sctMask <> sctEndClient)) then 2734 // no nego command 2735 begin 2736 PutMessage(1 shl 16 + 1, Format('No Turn: %d calls %x', 2737 [Player, Command shr 4])); 2738 result := eNoTurn; 2739 exit 2740 end; 2741 2742 // do not use EXIT hereafter! 2743 2744 {$IFOPT O-} 2745 HandoverStack[nHandoverStack] := Player + $1000; 2746 HandoverStack[nHandoverStack + 1] := Command; 2747 inc(nHandoverStack, 2); 2748 2749 InvalidTreatyMap := 0; 2750 // new command, sIntExpandTerritory of previous command was processed 2751 {$ENDIF} 2752 if (Mode = moPlaying) and (Command >= sExecute) and 2753 ((Command and sctMask <> sctEndClient) or (Command = sTurn)) and 2754 (Command and sctMask <> sctModel) and (Command <> sCancelTreaty) and 2755 (Command <> sSetCityTiles) and (Command <> sBuyCityProject) and 2756 ((Command < cClientEx) or ProcessClientData[Player]) then 2757 begin { log command } 2758 FormerCLState := CL.State; 2759 CL.Put(Command, Player, Subject, @Data); 2760 logged := true; 2761 end 2762 else 2763 logged := false; 2764 2765 case Command of 2766 2767 { 2768 Info Request Commands 2769 ____________________________________________________________________ 2770 } 2771 sMessage: 2772 Brain[bix[0]].Client(cDebugMessage, Subject, Data); 2773 2774 sSetDebugMap: 2775 DebugMap[Player] := @Data; 2776 2777 sGetDebugMap: 2778 pointer(Data) := DebugMap[Subject]; 2779 2780 { sChangeSuperView: 2781 if Difficulty[Player]=0 then 2782 begin 2783 for i:=0 to nBrain-1 do if Brain[i].Initialized then 2784 CallClient(i, cShowSuperView, Subject) 2785 end 2786 else result:=eInvalid; } 2787 2788 sRefreshDebugMap: 2789 Brain[bix[0]].Client(cRefreshDebugMap, -1, Player); 2790 2791 sGetChart .. sGetChart + (nStat - 1) shl 4: 2792 if (Subject >= 0) and (Subject < nPl) and (bix[Subject] >= 0) then 2793 begin 2794 StopTurn := 0; 2795 if (Difficulty[Player] = 0) or (GTestFlags and tfUncover <> 0) 2796 // supervisor 2797 or (Subject = Player) // own chart 2798 or (GWinner > 0) // game end chart 2799 or (1 shl Subject and GAlive = 0) then // chart of extinct nation 2800 if Subject > Player then 2801 StopTurn := GTurn 2802 else 2803 StopTurn := GTurn + 1 2804 else if RW[Player].Treaty[Subject] > trNoContact then 2805 if Command shr 4 and $F = stMil then 2806 StopTurn := RW[Player].EnemyReport[Subject].TurnOfMilReport + 1 2807 else 2808 StopTurn := RW[Player].EnemyReport[Subject].TurnOfCivilReport + 1; 2809 move(Stat[Command shr 4 and $F, Subject]^, Data, 2810 StopTurn * SizeOf(integer)); 2811 FillChar(TChart(Data)[StopTurn], (GTurn - StopTurn) * 2812 SizeOf(integer), 0); 2813 end 2814 else 2815 result := eInvalid; 2816 2817 sGetTechCost: 2818 integer(Data) := TechCost(Player); 2819 2820 sGetAIInfo: 2821 if AIInfo[Subject] = '' then 2822 pchar(Data) := nil 2823 else 2824 pchar(Data) := @AIInfo[Subject][1]; 2825 2826 sGetAICredits: 2827 if AICredits = '' then 2828 pchar(Data) := nil 2829 else 2830 pchar(Data) := @AICredits[1]; 2831 2832 sGetVersion: 2833 integer(Data) := Version; 2834 2835 sGetGameChanged: 2836 if Player <> 0 then 2837 result := eInvalid 2838 else if (CL <> nil) and (CL.State.nLog = nLogOpened) and 2839 (CL.State.MoveCode = 0) and not HasCityTileChanges and 2840 not HasChanges(Player) then 2841 result := eNotChanged; 2842 2843 sGetTileInfo: 2844 if (Subject >= 0) and (Subject < MapSize) then 2845 result := GetTileInfo(Player, -2, Subject, TTileInfo(Data)) 2846 else 2847 result := eInvalid; 2848 2849 sGetCityTileInfo: 2850 if (Subject >= 0) and (Subject < MapSize) then 2851 result := GetTileInfo(Player, -1, Subject, TTileInfo(Data)) 2852 else 2853 result := eInvalid; 2854 2855 sGetHypoCityTileInfo: 2856 if (Subject >= 0) and (Subject < MapSize) then 2857 begin 2858 if (TTileInfo(Data).ExplCity < 0) or 2859 (TTileInfo(Data).ExplCity >= RW[Player].nCity) then 2860 result := eInvalid 2861 else if ObserveLevel[Subject] shr (Player * 2) and 3 = 0 then 2862 result := eNoPreq 2863 else 2864 result := GetTileInfo(Player, TTileInfo(Data).ExplCity, Subject, 2865 TTileInfo(Data)) 2866 end 2867 else 2868 result := eInvalid; 2869 2870 sGetJobProgress: 2871 if (Subject >= 0) and (Subject < MapSize) then 2872 begin 2873 if ObserveLevel[Subject] shr (Player * 2) and 3 = 0 then 2874 result := eNoPreq 2875 else 2876 result := GetJobProgress(Player, Subject, TJobProgressData(Data)) 2877 end 2878 else 2879 result := eInvalid; 2880 2881 sGetModels: 2882 if (GTestFlags and tfUncover <> 0) or (Difficulty[Player] = 0) 2883 then { supervisor only command } 2884 begin 2885 for p1 := 0 to nPl - 1 do 2886 if (p1 <> Player) and (1 shl p1 and GAlive <> 0) then 2887 for mix := 0 to RW[p1].nModel - 1 do 2888 TellAboutModel(Player, p1, mix); 2889 end 2890 else 2891 result := eInvalid; 2892 2893 sGetUnits: 2894 if (Subject >= 0) and (Subject < MapSize) and 2895 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) then 2896 integer(Data) := GetUnitStack(Player, Subject) 2897 else 2898 result := eNoPreq; 2899 2900 sGetDefender: 2901 if (Subject >= 0) and (Subject < MapSize) and (Occupant[Subject] = Player) 2902 then 2903 Strongest(Subject, integer(Data), d, i, j) 2904 else 2905 result := eInvalid; 2906 2907 sGetBattleForecast, sGetBattleForecastEx: 2908 if (Subject >= 0) and (Subject < MapSize) and 2909 (ObserveLevel[Subject] and (3 shl (Player * 2)) > 0) then 2910 with TBattleForecast(Data) do 2911 if (1 shl pAtt and GAlive <> 0) and (mixAtt >= 0) and 2912 (mixAtt < RW[pAtt].nModel) and 2913 ((pAtt = Player) or (RWemix[Player, pAtt, mixAtt] >= 0)) then 2914 begin 2915 result := GetBattleForecast(Subject, TBattleForecast(Data), uix1, 2916 cix1, AStr, DStr, ABaseDamage, DBaseDamage); 2917 if Command = sGetBattleForecastEx then 2918 begin 2919 TBattleForecastEx(Data).AStr := (AStr + 200) div 400; 2920 TBattleForecastEx(Data).DStr := (DStr + 200) div 400; 2921 TBattleForecastEx(Data).ABaseDamage := ABaseDamage; 2922 TBattleForecastEx(Data).DBaseDamage := DBaseDamage; 2923 end; 2924 if result = eOK then 2925 result := eInvalid // no enemy unit there! 2926 end 2927 else 2928 result := eInvalid 2929 else 2930 result := eInvalid; 2931 2932 sGetUnitReport: 2933 if (Subject < 0) or (Subject >= RW[Player].nUn) or 2934 (RW[Player].Un[Subject].Loc < 0) then 2935 result := eInvalid 2936 else 2937 GetUnitReport(Player, Subject, TUnitReport(Data)); 2938 2939 sGetMoveAdvice: 2940 if (Subject < 0) or (Subject >= RW[Player].nUn) or 2941 (RW[Player].Un[Subject].Loc < 0) then 2942 result := eInvalid 2943 else 2944 result := GetMoveAdvice(Player, Subject, TMoveAdviceData(Data)); 2945 2946 sGetPlaneReturn: 2947 if (Subject < 0) or (Subject >= RW[Player].nUn) or 2948 (RW[Player].Un[Subject].Loc < 0) or 2949 (RW[Player].Model[RW[Player].Un[Subject].mix].Domain <> dAir) then 2950 result := eInvalid 2951 else 2952 begin 2953 if CanPlaneReturn(Player, Subject, TPlaneReturnData(Data)) then 2954 result := eOK 2955 else 2956 result := eNoWay 2957 end; 2958 2959 sGetCity: 2960 if (Subject >= 0) and (Subject < MapSize) and 2961 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) and 2962 (RealMap[Subject] and fCity <> 0) then 2963 with TGetCityData(Data) do 2271 2964 begin 2272 Loc1:=(Loc+dx-1+lx) mod lx +lx*((y+dy)*2-1); 2273 if (Loc1>=0) and (Loc1<MapSize) 2274 and (ObserveLevel[Loc1] and ObserveMask<>0) then 2275 if RealMap[Loc1] and $78000000=RealMap[Loc] and $78000000 then 2965 Owner := Player; 2966 SearchCity(Subject, Owner, cix1); 2967 c := RW[Owner].City[cix1]; 2968 if (Owner <> Player) and (c.Project and cpImp = 0) then 2969 TellAboutModel(Player, Owner, c.Project and cpIndex); 2970 end 2971 else 2972 result := eInvalid; 2973 2974 sGetCityReport: 2975 if (Subject < 0) or (Subject >= RW[Player].nCity) or 2976 (RW[Player].City[Subject].Loc < 0) then 2977 result := eInvalid 2978 else 2979 result := GetCityReport(Player, Subject, TCityReport(Data)); 2980 2981 sGetCityReportNew: 2982 if (Subject < 0) or (Subject >= RW[Player].nCity) or 2983 (RW[Player].City[Subject].Loc < 0) then 2984 result := eInvalid 2985 else 2986 GetCityReportNew(Player, Subject, TCityReportNew(Data)); 2987 2988 sGetCityAreaInfo: 2989 if (Subject < 0) or (Subject >= RW[Player].nCity) or 2990 (RW[Player].City[Subject].Loc < 0) then 2991 result := eInvalid 2992 else 2993 GetCityAreaInfo(Player, RW[Player].City[Subject].Loc, 2994 TCityAreaInfo(Data)); 2995 2996 sGetEnemyCityReport: 2997 if (Subject >= 0) and (Subject < MapSize) and 2998 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) and 2999 (RealMap[Subject] and fCity <> 0) then 3000 begin 3001 p1 := Occupant[Subject]; 3002 if p1 < 0 then 3003 p1 := 1; 3004 SearchCity(Subject, p1, cix1); 3005 TCityReport(Data).HypoTiles := -1; 3006 TCityReport(Data).HypoTax := -1; 3007 TCityReport(Data).HypoLux := -1; 3008 GetCityReport(p1, cix1, TCityReport(Data)) 3009 end 3010 else 3011 result := eInvalid; 3012 3013 sGetEnemyCityReportNew: 3014 if (Subject >= 0) and (Subject < MapSize) and 3015 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) and 3016 (RealMap[Subject] and fCity <> 0) then 3017 begin 3018 p1 := Occupant[Subject]; 3019 if p1 < 0 then 3020 p1 := 1; 3021 SearchCity(Subject, p1, cix1); 3022 TCityReport(Data).HypoTiles := -1; 3023 TCityReport(Data).HypoTax := -1; 3024 TCityReport(Data).HypoLux := -1; 3025 GetCityReportNew(p1, cix1, TCityReportNew(Data)); 3026 end 3027 else 3028 result := eInvalid; 3029 3030 sGetEnemyCityAreaInfo: 3031 if (Subject >= 0) and (Subject < MapSize) and 3032 (ObserveLevel[Subject] shr (Player * 2) and 3 = lObserveSuper) and 3033 (RealMap[Subject] and fCity <> 0) then 3034 begin 3035 p1 := Occupant[Subject]; 3036 if p1 < 0 then 3037 p1 := 1; 3038 SearchCity(Subject, p1, cix1); 3039 GetCityAreaInfo(p1, Subject, TCityAreaInfo(Data)) 3040 end 3041 else 3042 result := eInvalid; 3043 3044 sGetCityTileAdvice: 3045 if (Subject < 0) or (Subject >= RW[Player].nCity) or 3046 (RW[Player].City[Subject].Loc < 0) then 3047 result := eInvalid 3048 else 3049 GetCityTileAdvice(Player, Subject, TCityTileAdviceData(Data)); 3050 3051 { 3052 Map Editor Commands 3053 ____________________________________________________________________ 3054 } 3055 sEditTile: 3056 if Player = 0 then 3057 with TEditTileData(Data) do 3058 EditTile(Loc, NewTile) 3059 else 3060 result := eInvalid; 3061 3062 sRandomMap: 3063 if (Player = 0) and MapGeneratorAvailable then 3064 begin 3065 CreateElevation; 3066 PreviewElevation := false; 3067 CreateMap(false); 3068 FillChar(ObserveLevel, MapSize * 4, 0); 3069 DiscoverAll(Player, lObserveSuper); 3070 end 3071 else 3072 result := eInvalid; 3073 3074 sMapGeneratorRequest: 3075 if not MapGeneratorAvailable then 3076 result := eInvalid; 3077 3078 { 3079 Client Deactivation Commands 3080 ____________________________________________________________________ 3081 } 3082 sTurn, sTurn - sExecute: 3083 begin 3084 AllHumansDead := true; 3085 for p1 := 0 to nPl - 1 do 3086 if (1 shl p1 and GAlive <> 0) and (bix[p1] = bixTerm) then 3087 AllHumansDead := false; 3088 if (pDipActive >= 0) // still in negotiation mode 3089 or (pTurn = 0) and ((GWinner > 0) or (GTurn = MaxTurn) or 3090 (Difficulty[0] > 0) and AllHumansDead) then // game end reached 3091 result := eViolation 3092 else if Command >= sExecute then 3093 begin 3094 if Mode = moPlaying then 3095 begin 3096 CL.State := FormerCLState; 3097 LogCityTileChanges; 3098 {$IFNDEF SCR} 3099 if pTurn = 0 then 2276 3100 begin 2277 RW[pTurn].BorderHelper[Loc]:=RW[pTurn].BorderHelper[Loc] and not (1 shl (dy*2+dx));2278 RW[pTurn].BorderHelper[Loc1]:=RW[pTurn].BorderHelper[Loc1] and not (8 shr (dy*2+dx))3101 LogChanges; 3102 SaveGame('~' + LogFileName, true); 2279 3103 end 3104 {$ENDIF} 3105 end 3106 else if (Mode = moMovie) and (pTurn = 0) then 3107 CallPlayer(cMovieEndTurn, 0, nil^); 3108 GWatching := GWatching and GAlive or 1; 3109 RW[pTurn].Happened := 0; 3110 uixSelectedTransport := -1; 3111 SpyMission := smSabotageProd; 3112 if 1 shl pTurn and GAlive <> 0 then 3113 begin 3114 // calculate checksum 3115 TotalFood := 0; 3116 TotalProd := 0; 3117 for i := 0 to RW[pTurn].nCity - 1 do 3118 if RW[pTurn].City[i].Loc >= 0 then 3119 begin 3120 inc(TotalFood, RW[pTurn].City[i].Food); 3121 inc(TotalProd, RW[pTurn].City[i].Prod); 3122 end; 3123 CheckSum := TotalFood and 7 + TotalProd and 7 shl 3 + 3124 RW[pTurn].Money and 7 shl 6 + Worked[pTurn] div 100 and 7 shl 9; 3125 end 2280 3126 else 3127 CheckSum := 0; 3128 3129 if Mode < moPlaying then // check checksum 3130 begin 3131 if CheckSum <> Subject then 3132 LoadOK := false 3133 end 3134 else // save checksum 3135 CL.Put(Command, Player, CheckSum, @Data); 3136 {$IFDEF TEXTLOG} 3137 CmdInfo := ''; 3138 if CheckSum and 7 <> Subject and 7 then 3139 CmdInfo := Format('***ERROR (Food %d) ', 3140 [(CheckSum and 7 - Subject and 7 + 12) mod 8 - 4]) + CmdInfo; 3141 if CheckSum shr 3 and 7 <> Subject shr 3 and 7 then 3142 CmdInfo := '***ERROR (Prod) ' + CmdInfo; 3143 if CheckSum shr 6 and 7 <> Subject shr 6 and 7 then 3144 CmdInfo := '***ERROR (Research) ' + CmdInfo; 3145 if CheckSum shr 9 and 7 <> Subject shr 9 and 7 then 3146 CmdInfo := '***ERROR (Work) ' + CmdInfo; 3147 {$ENDIF} 3148 if 1 shl pTurn and GAlive <> 0 then 3149 begin 3150 AfterTurn; 3151 if Mode < moPlaying then 3152 InsertTerritoryUpdateCommands; 3153 // if bix[pTurn]=bixTerm then UpdateBorderHelper; 3154 end; 3155 3156 repeat 3157 pTurn := (pTurn + 1) mod nPl; 3158 if pTurn = 0 then 3159 inc(GTurn); 3160 if (bix[pTurn] >= 0) and ((1 shl pTurn) and GAlive = 0) then 3161 begin // already made extinct -- continue statistics 3162 Stat[stExplore, pTurn, GTurn] := 0; 3163 Stat[stPop, pTurn, GTurn] := 0; 3164 Stat[stTerritory, pTurn, GTurn] := 0; 3165 Stat[stScience, pTurn, GTurn] := 0; 3166 Stat[stWork, pTurn, GTurn] := 0; 3167 Stat[stMil, pTurn, GTurn] := 0; 3168 end; 3169 until (pTurn = 0) or ((1 shl pTurn and (GAlive or GWatching) <> 0) and 3170 (GWinner = 0)); 3171 if (Mode = moLoading_Fast) and 3172 ((GTurn = LoadTurn) or (GTurn = LoadTurn - 1) and (pTurn > 0)) then 3173 Mode := moLoading; 3174 if Mode = moPlaying then 3175 begin 3176 CCCommand := cTurn; 3177 CCPlayer := pTurn; 3178 Notify(ntNextPlayer) 3179 end 3180 else 3181 begin 3182 if GTurn = 0 then 3183 BeforeTurn0 3184 else 3185 BeforeTurn; 3186 if (Mode = moMovie) and (pTurn = 0) then 2281 3187 begin 2282 RW[pTurn].BorderHelper[Loc]:=RW[pTurn].BorderHelper[Loc] or (1 shl (dy*2+dx)); 2283 RW[pTurn].BorderHelper[Loc1]:=RW[pTurn].BorderHelper[Loc1] or (8 shr (dy*2+dx)); 2284 end 3188 Inform(pTurn); 3189 CallPlayer(cMovieTurn, 0, nil^); 3190 end; 3191 end; 3192 {$IFDEF TEXTLOG}CmdInfo := CmdInfo + Format('---Turn %d P%d---', [GTurn, pTurn]); {$ENDIF} 3193 end; 3194 end; // sTurn 3195 3196 sBreak, sResign, sNextRound, sReload: 3197 if Mode = moMovie then 3198 MovieStopped := true 3199 else 3200 begin 3201 if Command = sReload then 3202 begin 3203 ok := (Difficulty[0] = 0) and (bix[0] <> bixNoTerm) and 3204 (integer(Data) >= 0) and (integer(Data) < GTurn); 3205 for p1 := 1 to nPl - 1 do 3206 if bix[p1] = bixTerm then 3207 ok := false; 3208 // allow reload in AI-only games only 3209 end 3210 else 3211 ok := Player = 0; 3212 if ok then 3213 begin 3214 if (Command = sBreak) or (Command = sResign) then 3215 Notify(ntBackOn); 3216 for i := 0 to nBrain - 1 do 3217 if Brain[i].Initialized then 3218 begin 3219 if i >= bixFirstAI then 3220 Notify(ntDeinitModule + i); 3221 CallClient(i, cBreakGame, nil^); 3222 end; 3223 Notify(ntEndInfo); 3224 if (Command = sBreak) or (Command = sReload) then 3225 begin 3226 LogCityTileChanges; 3227 LogChanges; 3228 SaveGame(LogFileName, false); 3229 end; 3230 DeleteFile(SavePath + '~' + LogFileName); 3231 EndGame; 3232 case Command of 3233 sBreak: 3234 Notify(ntStartGoRefresh); 3235 sResign: 3236 Notify(ntStartGo); 3237 sNextRound: 3238 StartNewGame(SavePath, LogFileName, MapFileName, lx, ly, 3239 LandMass, MaxTurn); 3240 sReload: 3241 LoadGame(SavePath, LogFileName, integer(Data), false); 3242 end 3243 end 3244 else 3245 result := eInvalid; 3246 end; 3247 3248 sAbandonMap, sSaveMap: 3249 if Player = 0 then 3250 begin 3251 if Command = sSaveMap then 3252 SaveMap(MapFileName); 3253 Notify(ntBackOn); 3254 Brain[bixTerm].Client(cBreakGame, -1, nil^); 3255 ReleaseMapEditor; 3256 if Command = sSaveMap then 3257 Notify(ntStartGoRefreshMaps) 3258 else 3259 Notify(ntStartGo) 3260 end 3261 else 3262 result := eInvalid; 3263 3264 scContact .. scContact + (nPl - 1) shl 4, scContact - sExecute .. scContact 3265 - sExecute + (nPl - 1) shl 4: 3266 if (pDipActive >= 0) or (1 shl (Command shr 4 and $F) and GAlive = 0) then 3267 result := eInvalid 3268 else if GWinner > 0 then 3269 result := eViolation // game end reached 3270 else if RW[Player].Treaty[Command shr 4 and $F] = trNoContact then 3271 result := eNoPreq 3272 else if GTurn < GColdWarStart + ColdWarTurns then 3273 result := eColdWar 3274 else if RW[Player].Government = gAnarchy then 3275 result := eAnarchy 3276 else if RW[Command shr 4 and $F].Government = gAnarchy then 3277 begin 3278 result := eAnarchy; 3279 LastEndClientCommand := scReject; // enable cancel treaty 3280 pContacted := Command shr 4 and $F; 3281 end 3282 else if Command >= sExecute then 3283 begin // contact request 3284 pContacted := Command shr 4 and $F; 3285 pDipActive := pContacted; 3286 assert(Mode = moPlaying); 3287 Inform(pDipActive); 3288 ChangeClientWhenDone(scContact, pDipActive, pTurn, 4); 3289 end; 3290 3291 scReject, scReject - sExecute: 3292 if LastEndClientCommand and $FF0F = scContact then 3293 begin 3294 if Command >= sExecute then 3295 begin // contact requested and not accepted yet 3296 pDipActive := -1; 3297 assert(Mode = moPlaying); 3298 ChangeClientWhenDone(cContinue, pTurn, nil^, 0); 2285 3299 end 2286 3300 end 2287 end 2288 end;} 2289 2290 const 2291 ptSelect=0; ptTrGoods=1; ptUn=2; ptCaravan=3; ptImp=4; ptWonder=6; 2292 ptShip=7; ptInvalid=8; 2293 2294 function ProjectType(Project: integer): integer; 2295 begin 2296 if Project and cpCompleted<>0 then result:=ptSelect 2297 else if Project and (cpImp+cpIndex)=cpImp+imTrGoods then result:=ptTrGoods 2298 else if Project and cpImp=0 then 2299 if RW[Player].Model[Project and cpIndex].Kind=mkCaravan then result:=ptCaravan 2300 else result:=ptUn 2301 else if Project and cpIndex>=nImp then result:=ptInvalid 2302 else if Imp[Project and cpIndex].Kind=ikWonder then result:=ptWonder 2303 else if Imp[Project and cpIndex].Kind=ikShipPart then result:=ptShip 2304 else result:=ptImp 2305 end; 2306 2307 const 2308 Dirx: array[0..7] of integer=(1,2,1,0,-1,-2,-1,0); 2309 Diry: array[0..7] of integer=(-1,0,1,2,1,0,-1,-2); 2310 2311 var 2312 d,i,j,p1,p2,pt0,pt1,uix1,cix1,Loc0,Loc1,dx,dy,NewCap,MinCap,MaxCap, 2313 CapWeight,Cost,NextProd,Preq,TotalFood,TotalProd,CheckSum,StopTurn, 2314 FutureMCost,NewProject,OldImp,mix,V8,V21,AStr,DStr,ABaseDamage,DBaseDamage: integer; 2315 CityReport,AltCityReport:TCityReport; 2316 FormerCLState: TCmdListState; 2317 EndTime: int64; 2318 Adjacent: TVicinity8Loc; 2319 Radius: TVicinity21Loc; 2320 ShowShipChange: TShowShipChange; 2321 ShowNegoData: TShowNegoData; 2322 logged,ok,HasShipChanged,AllHumansDead,OfferFullySupported:boolean; 2323 2324 begin {>>>server} 2325 if Command=sTurn then 2326 begin 2327 p2:=-1; 2328 for p1:=0 to nPl-1 do if (p1<>Player) and (1 shl p1 and GWatching<>0) then 2329 CallPlayer(cShowTurnChange,p1,p2); 2330 end; 2331 2332 assert(MapSize=lx*ly); 2333 assert(Command and (sctMask or sExecute)<>sctInternal or sExecute); // not for internal commands 2334 if (Command<0) or (Command>=$10000) then 2335 begin result:=eUnknown; exit end; 2336 2337 if (Player<0) or (Player>=nPl) 2338 or ((Command and (sctMask or sExecute)<>sctInfo) 2339 and ((Subject<0) or (Subject>=$1000))) then 2340 begin result:=eInvalid; exit end; 2341 2342 if (1 shl Player and (GAlive or GWatching)=0) and 2343 not ((Command=sTurn) or (Command=sBreak) or (Command=sResign) 2344 or (Command=sGetAIInfo) or (Command=sGetAICredits) or (Command=sGetVersion) 2345 or (Command and $FF0F=sGetChart)) then 2346 begin 2347 PutMessage(1 shl 16+1, Format('NOT Alive: %d',[Player])); 2348 result:=eNoTurn; 2349 exit 2350 end; 2351 2352 result:=eOK; 2353 2354 // check if command allowed now 2355 if (Mode=moPlaying) 2356 and not ((Command>=cClientEx) or (Command=sMessage) or (Command=sSetDebugMap) 2357 or (Command=sGetDebugMap) 2358 or (Command=sGetAIInfo) or (Command=sGetAICredits) or (Command=sGetVersion) 2359 or (Command=sGetTechCost) or (Command=sGetDefender) 2360 or (Command=sGetUnitReport) 2361 or (Command=sGetCityReport) or (Command=sGetCityTileInfo) 2362 or (Command=sGetCity) or (Command=sGetEnemyCityReport) 2363 or (Command=sGetEnemyCityAreaInfo) or (Command=sGetCityReportNew) 2364 or (Command and $FF0F=sGetChart) or (Command and $FF0F=sSetAttitude)) 2365 // commands always allowed 2366 and not ((Player=pTurn) and (Command<$1000)) 2367 // info request always allowed for pTurn 2368 and ((pDipActive<0) and (Player<>pTurn) // not his turn 2369 or (pDipActive>=0) and (Player<>pDipActive) // not active in negotiation mode 2370 or (pDipActive>=0) and (Command and sctMask<>sctEndClient)) then // no nego command 2371 begin 2372 PutMessage(1 shl 16+1, Format('No Turn: %d calls %x', 2373 [Player,Command shr 4])); 2374 result:=eNoTurn; 2375 exit 2376 end; 2377 2378 // do not use EXIT hereafter! 2379 2380 {$IFOPT O-} 2381 HandoverStack[nHandoverStack]:=Player+$1000; 2382 HandoverStack[nHandoverStack+1]:=Command; 2383 inc(nHandoverStack,2); 2384 2385 InvalidTreatyMap:=0; // new command, sIntExpandTerritory of previous command was processed 2386 {$ENDIF} 2387 2388 if (Mode=moPlaying) and (Command>=sExecute) 2389 and ((Command and sctMask<>sctEndClient) or (Command=sTurn)) 2390 and (Command and sctMask<>sctModel) and (Command<>sCancelTreaty) 2391 and (Command<>sSetCityTiles) and (Command<>sBuyCityProject) 2392 and ((Command<cClientEx) or ProcessClientData[Player]) then 2393 begin {log command} 2394 FormerCLState:=CL.State; 2395 CL.Put(Command, Player, Subject, @Data); 2396 logged:=true; 2397 end 2398 else logged:=false; 2399 2400 case Command of 2401 2402 { 2403 Info Request Commands 2404 ____________________________________________________________________ 2405 } 2406 sMessage: 2407 Brain[bix[0]].Client(cDebugMessage,Subject,Data); 2408 2409 sSetDebugMap: 2410 DebugMap[Player]:=@Data; 2411 2412 sGetDebugMap: 2413 pointer(Data):=DebugMap[Subject]; 2414 2415 {sChangeSuperView: 2416 if Difficulty[Player]=0 then 2417 begin 2418 for i:=0 to nBrain-1 do if Brain[i].Initialized then 2419 CallClient(i, cShowSuperView, Subject) 2420 end 2421 else result:=eInvalid;} 2422 2423 sRefreshDebugMap: 2424 Brain[bix[0]].Client(cRefreshDebugMap,-1,Player); 2425 2426 sGetChart..sGetChart+(nStat-1) shl 4: 2427 if (Subject>=0) and (Subject<nPl) and (bix[Subject]>=0) then 2428 begin 2429 StopTurn:=0; 2430 if (Difficulty[Player]=0) or (GTestFlags and tfUncover<>0) // supervisor 2431 or (Subject=Player) // own chart 2432 or (GWinner>0) // game end chart 2433 or (1 shl Subject and GAlive=0) then // chart of extinct nation 2434 if Subject>Player then StopTurn:=GTurn 2435 else StopTurn:=GTurn+1 2436 else if RW[Player].Treaty[Subject]>trNoContact then 2437 if Command shr 4 and $f=stMil then 2438 StopTurn:=RW[Player].EnemyReport[Subject].TurnOfMilReport+1 2439 else StopTurn:=RW[Player].EnemyReport[Subject].TurnOfCivilReport+1; 2440 move(Stat[Command shr 4 and $f, Subject]^, Data, StopTurn*SizeOf(integer)); 2441 FillChar(TChart(Data)[StopTurn],(GTurn-StopTurn)*SizeOf(integer),0); 2442 end 2443 else result:=eInvalid; 2444 2445 sGetTechCost: 2446 integer(Data):=TechCost(Player); 2447 2448 sGetAIInfo: 2449 if AIInfo[Subject]='' then pchar(Data):=nil 2450 else pchar(Data):=@AIInfo[Subject][1]; 2451 2452 sGetAICredits: 2453 if AICredits='' then pchar(Data):=nil 2454 else pchar(Data):=@AICredits[1]; 2455 2456 sGetVersion: 2457 integer(Data):=Version; 2458 2459 sGetGameChanged: 2460 if Player<>0 then result:=eInvalid 2461 else if (CL<>nil) and (CL.state.nLog=nLogOpened) and (CL.state.MoveCode=0) 2462 and not HasCityTileChanges and not HasChanges(Player) then 2463 result:=eNotChanged; 2464 2465 sGetTileInfo: 2466 if (Subject>=0) and (Subject<MapSize) then 2467 result:=GetTileInfo(Player,-2,Subject,TTileInfo(Data)) 2468 else result:=eInvalid; 2469 2470 sGetCityTileInfo: 2471 if (Subject>=0) and (Subject<MapSize) then 2472 result:=GetTileInfo(Player,-1,Subject,TTileInfo(Data)) 2473 else result:=eInvalid; 2474 2475 sGetHypoCityTileInfo: 2476 if (Subject>=0) and (Subject<MapSize) then 2477 begin 2478 if (TTileInfo(Data).ExplCity<0) or (TTileInfo(Data).ExplCity>=RW[Player].nCity) then 2479 result:=eInvalid 2480 else if ObserveLevel[Subject] shr (Player*2) and 3=0 then 2481 result:=eNoPreq 2482 else result:=GetTileInfo(Player,TTileInfo(Data).ExplCity,Subject,TTileInfo(Data)) 2483 end 2484 else result:=eInvalid; 2485 2486 sGetJobProgress: 2487 if (Subject>=0) and (Subject<MapSize) then 2488 begin 2489 if ObserveLevel[Subject] shr (Player*2) and 3=0 then 2490 result:=eNoPreq 2491 else result:=GetJobProgress(Player,Subject,TJobProgressData(Data)) 2492 end 2493 else result:=eInvalid; 2494 2495 sGetModels: 2496 if (GTestFlags and tfUncover<>0) or (Difficulty[Player]=0) then {supervisor only command} 2497 begin 2498 for p1:=0 to nPl-1 do if (p1<>Player) and (1 shl p1 and GAlive<>0) then 2499 for mix:=0 to RW[p1].nModel-1 do 2500 TellAboutModel(Player,p1,mix); 2501 end 2502 else result:=eInvalid; 2503 2504 sGetUnits: 2505 if (Subject>=0) and (Subject<MapSize) 2506 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) then 2507 integer(Data):=GetUnitStack(Player,Subject) 2508 else result:=eNoPreq; 2509 2510 sGetDefender: 2511 if (Subject>=0) and (Subject<MapSize) and (Occupant[Subject]=Player) then 2512 Strongest(Subject,integer(Data),d,i,j) 2513 else result:=eInvalid; 2514 2515 sGetBattleForecast,sGetBattleForecastEx: 2516 if (Subject>=0) and (Subject<MapSize) 2517 and (ObserveLevel[Subject] and (3 shl (Player*2))>0) then 2518 with TBattleForecast(Data) do 2519 if (1 shl pAtt and GAlive<>0) 2520 and (mixAtt>=0) and (mixAtt<RW[pAtt].nModel) 2521 and ((pAtt=Player) or (RWemix[Player,pAtt,mixAtt]>=0)) then 2522 begin 2523 result:=GetBattleForecast(Subject,TBattleForecast(Data),uix1,cix1, 2524 AStr,DStr,ABaseDamage,DBaseDamage); 2525 if Command=sGetBattleForecastEx then 2526 begin 2527 TBattleForecastEx(Data).AStr:=(AStr+200) div 400; 2528 TBattleForecastEx(Data).DStr:=(DStr+200) div 400; 2529 TBattleForecastEx(Data).ABaseDamage:=ABaseDamage; 2530 TBattleForecastEx(Data).DBaseDamage:=DBaseDamage; 2531 end; 2532 if result=eOk then 2533 result:=eInvalid // no enemy unit there! 2534 end 2535 else result:=eInvalid 2536 else result:=eInvalid; 2537 2538 sGetUnitReport: 2539 if (Subject<0) or (Subject>=RW[Player].nUn) 2540 or (RW[Player].Un[Subject].Loc<0) then 2541 result:=eInvalid 2542 else GetUnitReport(Player, Subject, TUnitReport(Data)); 2543 2544 sGetMoveAdvice: 2545 if (Subject<0) or (Subject>=RW[Player].nUn) 2546 or (RW[Player].Un[Subject].Loc<0) then 2547 result:=eInvalid 2548 else result:=GetMoveAdvice(Player,Subject, TMoveAdviceData(Data)); 2549 2550 sGetPlaneReturn: 2551 if (Subject<0) or (Subject>=RW[Player].nUn) 2552 or (RW[Player].Un[Subject].Loc<0) 2553 or (RW[Player].Model[RW[Player].Un[Subject].mix].Domain<>dAir) then 2554 result:=eInvalid 2555 else 2556 begin 2557 if CanPlaneReturn(Player,Subject, TPlaneReturnData(Data)) then result:=eOK 2558 else result:=eNoWay 2559 end; 2560 2561 sGetCity: 2562 if (Subject>=0) and (Subject<MapSize) 2563 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) 2564 and (RealMap[Subject] and fCity<>0) then 2565 with TGetCityData(Data) do 2566 begin 2567 Owner:=Player; 2568 SearchCity(Subject,Owner,cix1); 2569 c:=RW[Owner].City[cix1]; 2570 if (Owner<>Player) and (c.Project and cpImp=0) then 2571 TellAboutModel(Player,Owner,c.Project and cpIndex); 2572 end 2573 else result:=eInvalid; 2574 2575 sGetCityReport: 2576 if (Subject<0) or (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 2577 result:=eInvalid 2578 else result:=GetCityReport(Player,Subject,TCityReport(Data)); 2579 2580 sGetCityReportNew: 2581 if (Subject<0) or (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 2582 result:=eInvalid 2583 else GetCityReportNew(Player,Subject,TCityReportNew(Data)); 2584 2585 sGetCityAreaInfo: 2586 if (Subject<0) or (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 2587 result:=eInvalid 2588 else GetCityAreaInfo(Player, RW[Player].City[Subject].Loc, 2589 TCityAreaInfo(Data)); 2590 2591 sGetEnemyCityReport: 2592 if (Subject>=0) and (Subject<MapSize) 2593 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) 2594 and (RealMap[Subject] and fCity<>0) then 2595 begin 2596 p1:=Occupant[Subject]; 2597 if p1<0 then p1:=1; 2598 SearchCity(Subject,p1,cix1); 2599 TCityReport(Data).HypoTiles:=-1; 2600 TCityReport(Data).HypoTax:=-1; 2601 TCityReport(Data).HypoLux:=-1; 2602 GetCityReport(p1,cix1,TCityReport(Data)) 2603 end 2604 else result:=eInvalid; 2605 2606 sGetEnemyCityReportNew: 2607 if (Subject>=0) and (Subject<MapSize) 2608 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) 2609 and (RealMap[Subject] and fCity<>0) then 2610 begin 2611 p1:=Occupant[Subject]; 2612 if p1<0 then p1:=1; 2613 SearchCity(Subject,p1,cix1); 2614 TCityReport(Data).HypoTiles:=-1; 2615 TCityReport(Data).HypoTax:=-1; 2616 TCityReport(Data).HypoLux:=-1; 2617 GetCityReportNew(p1,cix1,TCityReportNew(Data)); 2618 end 2619 else result:=eInvalid; 2620 2621 sGetEnemyCityAreaInfo: 2622 if (Subject>=0) and (Subject<MapSize) 2623 and (ObserveLevel[Subject] shr (Player*2) and 3=lObserveSuper) 2624 and (RealMap[Subject] and fCity<>0) then 2625 begin 2626 p1:=Occupant[Subject]; 2627 if p1<0 then p1:=1; 2628 SearchCity(Subject,p1,cix1); 2629 GetCityAreaInfo(p1,Subject,TCityAreaInfo(Data)) 2630 end 2631 else result:=eInvalid; 2632 2633 sGetCityTileAdvice: 2634 if (Subject<0) or (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 2635 result:=eInvalid 2636 else GetCityTileAdvice(Player, Subject, TCityTileAdviceData(Data)); 2637 2638 { 2639 Map Editor Commands 2640 ____________________________________________________________________ 2641 } 2642 sEditTile: 2643 if Player=0 then with TEditTileData(Data) do EditTile(Loc, NewTile) 2644 else result:=eInvalid; 2645 2646 sRandomMap: 2647 if (Player=0) and MapGeneratorAvailable then 2648 begin 2649 CreateElevation; 2650 PreviewElevation:=false; 2651 CreateMap(false); 2652 FillChar(ObserveLevel,MapSize*4,0); 2653 DiscoverAll(Player,lObserveSuper); 2654 end 2655 else result:=eInvalid; 2656 2657 sMapGeneratorRequest: 2658 if not MapGeneratorAvailable then result:=eInvalid; 2659 2660 { 2661 Client Deactivation Commands 2662 ____________________________________________________________________ 2663 } 2664 sTurn, sTurn-sExecute: 2665 begin 2666 AllHumansDead:=true; 2667 for p1:=0 to nPl-1 do 2668 if (1 shl p1 and GAlive<>0) and (bix[p1]=bixTerm) then 2669 AllHumansDead:=false; 2670 if (pDipActive>=0) // still in negotiation mode 2671 or (pTurn=0) and ((GWinner>0) or (GTurn=MaxTurn) 2672 or (Difficulty[0]>0) and AllHumansDead) then // game end reached 2673 result:=eViolation 2674 else if Command>=sExecute then 2675 begin 2676 if Mode=moPlaying then 2677 begin 2678 CL.State:=FormerCLState; 2679 LogCityTileChanges; 2680 {$IFNDEF SCR} 2681 if pTurn=0 then 2682 begin LogChanges; SaveGame('~'+LogFileName,true); end 2683 {$ENDIF} 2684 end 2685 else if (Mode=moMovie) and (pTurn=0) then 2686 CallPlayer(cMovieEndTurn,0,nil^); 2687 GWatching:=GWatching and GAlive or 1; 2688 RW[pTurn].Happened:=0; 2689 uixSelectedTransport:=-1; 2690 SpyMission:=smSabotageProd; 2691 if 1 shl pTurn and GAlive<>0 then 2692 begin 2693 // calculate checksum 2694 TotalFood:=0; 2695 TotalProd:=0; 2696 for i:=0 to RW[pTurn].nCity-1 do if RW[pTurn].City[i].Loc>=0 then 2697 begin 2698 inc(TotalFood,RW[pTurn].City[i].Food); 2699 inc(TotalProd,RW[pTurn].City[i].Prod); 2700 end; 2701 CheckSum:=TotalFood and 7 + TotalProd and 7 shl 3 2702 + RW[pTurn].Money and 7 shl 6 2703 + Worked[pTurn] div 100 and 7 shl 9; 2704 end 2705 else CheckSum:=0; 2706 2707 if Mode<moPlaying then // check checksum 2708 begin 2709 if CheckSum<>Subject then 2710 LoadOK:=false 2711 end 2712 else // save checksum 2713 CL.Put(Command, Player, CheckSum, @Data); 2714 {$IFDEF TEXTLOG} 2715 CmdInfo:=''; 2716 if CheckSum and 7<>Subject and 7 then CmdInfo:=Format('***ERROR (Food %d) ',[(CheckSum and 7-Subject and 7+12) mod 8 -4])+CmdInfo; 2717 if CheckSum shr 3 and 7<>Subject shr 3 and 7 then CmdInfo:='***ERROR (Prod) '+CmdInfo; 2718 if CheckSum shr 6 and 7<>Subject shr 6 and 7 then CmdInfo:='***ERROR (Research) '+CmdInfo; 2719 if CheckSum shr 9 and 7<>Subject shr 9 and 7 then CmdInfo:='***ERROR (Work) '+CmdInfo; 2720 {$ENDIF} 2721 2722 if 1 shl pTurn and GAlive<>0 then 2723 begin 2724 AfterTurn; 2725 if Mode<moPlaying then 2726 InsertTerritoryUpdateCommands; 2727 //if bix[pTurn]=bixTerm then UpdateBorderHelper; 2728 end; 2729 2730 repeat 2731 pTurn:=(pTurn+1) mod nPl; 2732 if pTurn=0 then inc(GTurn); 2733 if (bix[pTurn]>=0) and ((1 shl pTurn) and GAlive=0) then 2734 begin // already made extinct -- continue statistics 2735 Stat[stExplore,pTurn,GTurn]:=0; 2736 Stat[stPop,pTurn,GTurn]:=0; 2737 Stat[stTerritory,pTurn,GTurn]:=0; 2738 Stat[stScience,pTurn,GTurn]:=0; 2739 Stat[stWork,pTurn,GTurn]:=0; 2740 Stat[stMil,pTurn,GTurn]:=0; 2741 end; 2742 until (pTurn=0) or ((1 shl pTurn and (GAlive or GWatching)<>0) and (GWinner=0)); 2743 if (Mode=moLoading_Fast) and ((GTurn=LoadTurn) or (GTurn=LoadTurn-1) and (pTurn>0)) then 2744 Mode:=moLoading; 2745 if Mode=moPlaying then 2746 begin 2747 CCCommand:=cTurn; CCPlayer:=pTurn; 2748 Notify(ntNextPlayer) 2749 end 2750 else 2751 begin 2752 if GTurn=0 then BeforeTurn0 2753 else BeforeTurn; 2754 if (Mode=moMovie) and (pTurn=0) then 2755 begin 2756 Inform(pTurn); 2757 CallPlayer(cMovieTurn,0,nil^); 2758 end; 2759 end; 2760 {$IFDEF TEXTLOG}CmdInfo:=CmdInfo+Format('---Turn %d P%d---', [GTurn,pTurn]);{$ENDIF} 2761 end; 2762 end; // sTurn 2763 2764 sBreak, sResign, sNextRound, sReload: 2765 if Mode=moMovie then 2766 MovieStopped:=true 2767 else 2768 begin 2769 if Command=sReload then 2770 begin 2771 ok:= (Difficulty[0]=0) and (bix[0]<>bixNoTerm) 2772 and (integer(Data)>=0) and (integer(Data)<GTurn); 2773 for p1:=1 to nPl-1 do if bix[p1]=bixTerm then ok:=false; 2774 // allow reload in AI-only games only 2775 end 2776 else ok:= Player=0; 2777 if ok then 2778 begin 2779 if (Command=sBreak) or (Command=sResign) then Notify(ntBackOn); 2780 for i:=0 to nBrain-1 do if Brain[i].Initialized then 2781 begin 2782 if i>=bixFirstAI then 2783 Notify(ntDeinitModule+i); 2784 CallClient(i, cBreakGame, nil^); 2785 end; 2786 Notify(ntEndInfo); 2787 if (Command=sBreak) or (Command=sReload) then 2788 begin 2789 LogCityTileChanges; 2790 LogChanges; 2791 SaveGame(LogFileName,false); 2792 end; 2793 DeleteFile(SavePath+'~'+LogFileName); 2794 EndGame; 2795 case Command of 2796 sBreak: Notify(ntStartGoRefresh); 2797 sResign: Notify(ntStartGo); 2798 sNextRound: StartNewGame(SavePath, LogFileName, MapFileName, lx, ly, LandMass, 2799 MaxTurn); 2800 sReload: LoadGame(SavePath,LogFileName,integer(Data),false); 2801 end 2802 end 2803 else result:=eInvalid; 2804 end; 2805 2806 sAbandonMap, sSaveMap: 2807 if Player=0 then 2808 begin 2809 if Command=sSaveMap then SaveMap(MapFileName); 2810 Notify(ntBackOn); 2811 Brain[bixTerm].Client(cBreakGame,-1,nil^); 2812 ReleaseMapEditor; 2813 if Command=sSaveMap then Notify(ntStartGoRefreshMaps) 2814 else Notify(ntStartGo) 2815 end 2816 else result:=eInvalid; 2817 2818 scContact..scContact+(nPl-1) shl 4, 2819 scContact-sExecute..scContact-sExecute+(nPl-1) shl 4: 2820 if (pDipActive>=0) or (1 shl (Command shr 4 and $f) and GAlive=0) then 2821 result:=eInvalid 2822 else if GWinner>0 then result:=eViolation // game end reached 2823 else if RW[Player].Treaty[Command shr 4 and $f]=trNoContact then 2824 result:=eNoPreq 2825 else if GTurn<GColdWarStart+ColdWarTurns then result:=eColdWar 2826 else if RW[Player].Government=gAnarchy then 2827 result:=eAnarchy 2828 else if RW[Command shr 4 and $f].Government=gAnarchy then 2829 begin 2830 result:=eAnarchy; 2831 LastEndClientCommand:=scReject; //enable cancel treaty 2832 pContacted:=Command shr 4 and $f; 2833 end 2834 else if Command>=sExecute then 2835 begin // contact request 2836 pContacted:=Command shr 4 and $f; 2837 pDipActive:=pContacted; 2838 assert(Mode=moPlaying); 2839 Inform(pDipActive); 2840 ChangeClientWhenDone(scContact,pDipActive,pTurn,4); 2841 end; 2842 2843 scReject, scReject-sExecute: 2844 if LastEndClientCommand and $FF0F=scContact then 2845 begin 2846 if Command>=sExecute then 2847 begin // contact requested and not accepted yet 2848 pDipActive:=-1; 2849 assert(Mode=moPlaying); 2850 ChangeClientWhenDone(cContinue,pTurn,nil^,0); 3301 else 3302 result := eInvalid; 3303 3304 scDipStart, scDipStart - sExecute: 3305 if LastEndClientCommand and $FF0F = scContact then 3306 begin 3307 if Command >= sExecute then 3308 begin // accept contact 3309 pContacted := pDipActive; 3310 RW[pContacted].EnemyReport[pTurn].Credibility := 3311 RW[pTurn].Credibility; 3312 pDipActive := pTurn; 3313 assert(Mode = moPlaying); 3314 IntServer(sIntHaveContact, pTurn, pContacted, nil^); 3315 ChangeClientWhenDone(scDipStart, pDipActive, nil^, 0); 2851 3316 end 2852 3317 end 2853 else result:=eInvalid; 2854 2855 scDipStart, scDipStart-sExecute: 2856 if LastEndClientCommand and $FF0F=scContact then 2857 begin 2858 if Command>=sExecute then 2859 begin // accept contact 2860 pContacted:=pDipActive; 2861 RW[pContacted].EnemyReport[pTurn].Credibility:=RW[pTurn].Credibility; 2862 pDipActive:=pTurn; 2863 assert(Mode=moPlaying); 2864 IntServer(sIntHaveContact,pTurn,pContacted,nil^); 2865 ChangeClientWhenDone(scDipStart,pDipActive,nil^,0); 2866 end 2867 end 2868 else result:=eInvalid; 2869 2870 scDipNotice, scDipAccept, scDipCancelTreaty, scDipBreak, 2871 scDipNotice-sExecute, scDipAccept-sExecute, scDipCancelTreaty-sExecute, 2872 scDipBreak-sExecute: 2873 if pDipActive>=0 then 2874 begin 2875 assert(Mode=moPlaying); 2876 if pDipActive=pTurn then p1:=pContacted 2877 else p1:=pTurn; 2878 if (Command and not sExecute=scDipBreak and not sExecute) 2879 and (LastEndClientCommand<>scDipBreak) then // ok 2880 else if (Command and not sExecute=scDipNotice and not sExecute) 2881 and ((LastEndClientCommand=scDipCancelTreaty) 2882 or (LastEndClientCommand=scDipBreak)) then // ok 2883 else if (Command and not sExecute=scDipAccept and not sExecute) 2884 and (LastEndClientCommand=scDipOffer) then with LastOffer do 3318 else 3319 result := eInvalid; 3320 3321 scDipNotice, scDipAccept, scDipCancelTreaty, scDipBreak, 3322 scDipNotice - sExecute, scDipAccept - sExecute, 3323 scDipCancelTreaty - sExecute, scDipBreak - sExecute: 3324 if pDipActive >= 0 then 3325 begin 3326 assert(Mode = moPlaying); 3327 if pDipActive = pTurn then 3328 p1 := pContacted 3329 else 3330 p1 := pTurn; 3331 if (Command and not sExecute = scDipBreak and not sExecute) and 3332 (LastEndClientCommand <> scDipBreak) then // ok 3333 else if (Command and not sExecute = scDipNotice and not sExecute) and 3334 ((LastEndClientCommand = scDipCancelTreaty) or 3335 (LastEndClientCommand = scDipBreak)) then // ok 3336 else if (Command and not sExecute = scDipAccept and not sExecute) and 3337 (LastEndClientCommand = scDipOffer) then 3338 with LastOffer do 3339 begin 3340 // check if offer can be accepted 3341 if nDeliver + nCost = 0 then 3342 result := eOfferNotAcceptable; 3343 for i := 0 to nDeliver + nCost - 1 do 3344 if Price[i] = opChoose then 3345 result := eOfferNotAcceptable; 3346 for i := 0 to nCost - 1 do 3347 if not PayPrice(pDipActive, p1, Price[nDeliver + i], false) then 3348 result := eOfferNotAcceptable; 3349 if (Command >= sExecute) and (result >= rExecuted) then 3350 begin 3351 IntServer(sIntPayPrices + nDeliver + nCost, p1, pDipActive, 3352 LastOffer); 3353 // CheckContact; 3354 3355 // tell other players about ship part trades 3356 HasShipChanged := false; 3357 FillChar(ShowShipChange, SizeOf(ShowShipChange), 0); 3358 for i := 0 to nDeliver + nCost - 1 do 3359 if Price[i] and opMask = opShipParts then 3360 begin 3361 HasShipChanged := true; 3362 if i >= nDeliver then 3363 begin // p1 has demanded from pDipActive 3364 ShowShipChange.Ship1Change[Price[i] shr 16 and 3] := 3365 +integer(Price[i] and $FFFF); 3366 ShowShipChange.Ship2Change[Price[i] shr 16 and 3] := 3367 -integer(Price[i] and $FFFF); 3368 end 3369 else 3370 begin // p1 has delivered to pDipActive 3371 ShowShipChange.Ship1Change[Price[i] shr 16 and 3] := 3372 -integer(Price[i] and $FFFF); 3373 ShowShipChange.Ship2Change[Price[i] shr 16 and 3] := 3374 +integer(Price[i] and $FFFF); 3375 end 3376 end; 3377 if HasShipChanged then 3378 begin 3379 ShowShipChange.Reason := scrTrade; 3380 ShowShipChange.Ship1Owner := p1; 3381 ShowShipChange.Ship2Owner := pDipActive; 3382 for p2 := 0 to nPl - 1 do 3383 if (p2 <> p1) and (p2 <> pDipActive) and 3384 (1 shl p2 and (GAlive or GWatching) <> 0) then 3385 begin 3386 move(GShip, RW[p2].Ship, SizeOf(GShip)); 3387 if 1 shl p2 and GWatching <> 0 then 3388 CallPlayer(cShowShipChange, p2, ShowShipChange); 3389 end 3390 end 3391 end; 3392 end 3393 else if (Command and not sExecute = scDipCancelTreaty and not sExecute) 3394 and (RW[pDipActive].Treaty[p1] >= trPeace) then 2885 3395 begin 2886 // check if offer can be accepted 2887 if nDeliver+nCost=0 then result:=eOfferNotAcceptable; 2888 for i:=0 to nDeliver+nCost-1 do 2889 if Price[i]=opChoose then result:=eOfferNotAcceptable; 2890 for i:=0 to nCost-1 do 2891 if not PayPrice(pDipActive,p1,Price[nDeliver+i],false) then 2892 result:=eOfferNotAcceptable; 2893 if (Command>=sExecute) and (result>=rExecuted) then 3396 if (ServerVersion[pDipActive] >= $010100) and 3397 (GTurn < RW[pDipActive].LastCancelTreaty[p1] + CancelTreatyTurns) 3398 then 3399 result := eCancelTreatyRush 3400 else if Command >= sExecute then 2894 3401 begin 2895 IntServer(sIntPayPrices+nDeliver+nCost,p1,pDipActive,LastOffer); 2896 // CheckContact; 2897 2898 // tell other players about ship part trades 2899 HasShipChanged:=false; 2900 fillchar(ShowShipChange,sizeof(ShowShipChange),0); 2901 for i:=0 to nDeliver+nCost-1 do 2902 if Price[i] and opMask=opShipParts then 3402 IntServer(sIntCancelTreaty, pDipActive, p1, nil^); 3403 for p2 := 0 to nPl - 1 do 3404 if (p2 <> p1) and (1 shl p2 and PeaceEnded <> 0) then 2903 3405 begin 2904 HasShipChanged:=true; 2905 if i>=nDeliver then 2906 begin // p1 has demanded from pDipActive 2907 ShowShipChange.Ship1Change[Price[i] shr 16 and 3]:=+integer(Price[i] and $FFFF); 2908 ShowShipChange.Ship2Change[Price[i] shr 16 and 3]:=-integer(Price[i] and $FFFF); 2909 end 2910 else 2911 begin // p1 has delivered to pDipActive 2912 ShowShipChange.Ship1Change[Price[i] shr 16 and 3]:=-integer(Price[i] and $FFFF); 2913 ShowShipChange.Ship2Change[Price[i] shr 16 and 3]:=+integer(Price[i] and $FFFF); 2914 end 3406 i := p1 shl 4 + pDipActive; 3407 CallPlayer(cShowSupportAllianceAgainst, p2, i); 2915 3408 end; 2916 if HasShipChanged then 2917 begin 2918 ShowShipChange.Reason:=scrTrade; 2919 ShowShipChange.Ship1Owner:=p1; 2920 ShowShipChange.Ship2Owner:=pDipActive; 2921 for p2:=0 to nPl-1 do 2922 if (p2<>p1) and (p2<>pDipActive) and (1 shl p2 and (GAlive or GWatching)<>0) then 2923 begin 2924 move(GShip,RW[p2].Ship,SizeOf(GShip)); 2925 if 1 shl p2 and GWatching<>0 then 2926 CallPlayer(cShowShipChange,p2,ShowShipChange); 2927 end 2928 end 2929 end; 2930 end 2931 else if (Command and not sExecute=scDipCancelTreaty and not sExecute) 2932 and (RW[pDipActive].Treaty[p1]>=trPeace) then 2933 begin 2934 if (ServerVersion[pDipActive]>=$010100) 2935 and (GTurn<RW[pDipActive].LastCancelTreaty[p1]+CancelTreatyTurns) then 2936 result:=eCancelTreatyRush 2937 else if Command>=sExecute then 2938 begin 2939 IntServer(sIntCancelTreaty,pDipActive,p1,nil^); 2940 for p2:=0 to nPl-1 do 2941 if (p2<>p1) and (1 shl p2 and PeaceEnded<>0) then 3409 for p2 := 0 to nPl - 1 do 3410 if (p2 <> p1) and (1 shl p2 and PeaceEnded <> 0) then 2942 3411 begin 2943 i:=p1 shl 4+pDipActive; 2944 CallPlayer(cShowSupportAllianceAgainst,p2,i); 2945 end; 2946 for p2:=0 to nPl-1 do 2947 if (p2<>p1) and (1 shl p2 and PeaceEnded<>0) then 2948 begin 2949 i:=p2; 2950 CallPlayer(cShowCancelTreatyByAlliance,pDipActive,i); 3412 i := p2; 3413 CallPlayer(cShowCancelTreatyByAlliance, pDipActive, i); 2951 3414 end; 2952 3415 end 2953 3416 end 2954 else result:=eInvalid; 2955 if (Command>=sExecute) and (result>=rExecuted) then 2956 if LastEndClientCommand=scDipBreak then 3417 else 3418 result := eInvalid; 3419 if (Command >= sExecute) and (result >= rExecuted) then 3420 if LastEndClientCommand = scDipBreak then 2957 3421 begin // break negotiation 2958 pDipActive:=-1;2959 CallPlayer(cShowEndContact,pContacted,nil^);2960 ChangeClientWhenDone(cContinue,pTurn,nil^,0);3422 pDipActive := -1; 3423 CallPlayer(cShowEndContact, pContacted, nil^); 3424 ChangeClientWhenDone(cContinue, pTurn, nil^, 0); 2961 3425 end 2962 else3426 else 2963 3427 begin 2964 if (GTestFlags and tfUncover<>0) or (Difficulty[0]=0) then2965 with ShowNegoData do3428 if (GTestFlags and tfUncover <> 0) or (Difficulty[0] = 0) then 3429 with ShowNegoData do 2966 3430 begin // display negotiation in log window 2967 pSender:=pDipActive;2968 pTarget:=p1;2969 Action:=Command;2970 Brain[bix[0]].Client(cShowNego,1 shl 16+3,ShowNegoData);3431 pSender := pDipActive; 3432 pTarget := p1; 3433 Action := Command; 3434 Brain[bix[0]].Client(cShowNego, 1 shl 16 + 3, ShowNegoData); 2971 3435 end; 2972 pDipActive:=p1;2973 ChangeClientWhenDone(Command,pDipActive,nil^,0);3436 pDipActive := p1; 3437 ChangeClientWhenDone(Command, pDipActive, nil^, 0); 2974 3438 end 2975 3439 end 2976 else result:=eInvalid; 2977 2978 scDipOffer, scDipOffer-sExecute: 2979 if (pDipActive>=0) and (LastEndClientCommand<>scDipCancelTreaty) 2980 and (LastEndClientCommand<>scDipBreak) then 2981 if (LastEndClientCommand=scDipOffer) and (LastOffer.nDeliver+LastOffer.nCost 2982 +TOffer(Data).nDeliver+TOffer(Data).nCost=0) then 3440 else 3441 result := eInvalid; 3442 3443 scDipOffer, scDipOffer - sExecute: 3444 if (pDipActive >= 0) and (LastEndClientCommand <> scDipCancelTreaty) and 3445 (LastEndClientCommand <> scDipBreak) then 3446 if (LastEndClientCommand = scDipOffer) and 3447 (LastOffer.nDeliver + LastOffer.nCost + TOffer(Data).nDeliver + 3448 TOffer(Data).nCost = 0) then 2983 3449 begin 2984 if Command>=sExecute then3450 if Command >= sExecute then 2985 3451 begin // agreed discussion end 2986 pDipActive:=-1;2987 CallPlayer(cShowEndContact,pContacted,nil^);2988 assert(Mode=moPlaying);2989 ChangeClientWhenDone(cContinue,pTurn,nil^,0);3452 pDipActive := -1; 3453 CallPlayer(cShowEndContact, pContacted, nil^); 3454 assert(Mode = moPlaying); 3455 ChangeClientWhenDone(cContinue, pTurn, nil^, 0); 2990 3456 end 2991 3457 end 2992 else3458 else 2993 3459 begin 2994 // check if offer can be made 2995 if pDipActive=pTurn then p1:=pContacted 2996 else p1:=pTurn; 2997 if RW[pDipActive].Treaty[p1]<trPeace then 3460 // check if offer can be made 3461 if pDipActive = pTurn then 3462 p1 := pContacted 3463 else 3464 p1 := pTurn; 3465 if RW[pDipActive].Treaty[p1] < trPeace then 2998 3466 begin // no tribute allowed! 2999 for i:=0 to TOffer(Data).nDeliver+TOffer(Data).nCost-1 do 3000 if (TOffer(Data).Price[i] and opMask=opTribute) then result:=eInvalidOffer; 3001 for i:=0 to TOffer(Data).nDeliver+TOffer(Data).nCost-1 do 3002 if (TOffer(Data).Price[i]=opTreaty+trPeace) then result:=eOK; 3467 for i := 0 to TOffer(Data).nDeliver + TOffer(Data).nCost - 1 do 3468 if (TOffer(Data).Price[i] and opMask = opTribute) then 3469 result := eInvalidOffer; 3470 for i := 0 to TOffer(Data).nDeliver + TOffer(Data).nCost - 1 do 3471 if (TOffer(Data).Price[i] = opTreaty + trPeace) then 3472 result := eOK; 3003 3473 end; 3004 for i:=0 to TOffer(Data).nDeliver-1 do 3005 if (TOffer(Data).Price[i]<>opChoose) 3006 and not PayPrice(pDipActive,p1,TOffer(Data).Price[i],false) then 3007 result:=eInvalidOffer; 3008 if CountPrice(TOffer(Data),opTreaty)>1 then 3009 result:=eInvalidOffer; 3010 for i:=0 to nShipPart-1 do 3011 if CountPrice(TOffer(Data),opShipParts+i shl 16)>1 then 3012 result:=eInvalidOffer; 3013 if CountPrice(TOffer(Data),opMoney)>1 then 3014 result:=eInvalidOffer; 3015 if CountPrice(TOffer(Data),opTribute)>1 then 3016 result:=eInvalidOffer; 3017 case CountPrice(TOffer(Data),opChoose) of 3018 0:; 3019 1: 3020 if (TOffer(Data).nCost=0) or (TOffer(Data).nDeliver=0) then 3021 result:=eInvalidOffer; 3022 else result:=eInvalidOffer; 3474 for i := 0 to TOffer(Data).nDeliver - 1 do 3475 if (TOffer(Data).Price[i] <> opChoose) and 3476 not PayPrice(pDipActive, p1, TOffer(Data).Price[i], false) then 3477 result := eInvalidOffer; 3478 if CountPrice(TOffer(Data), opTreaty) > 1 then 3479 result := eInvalidOffer; 3480 for i := 0 to nShipPart - 1 do 3481 if CountPrice(TOffer(Data), opShipParts + i shl 16) > 1 then 3482 result := eInvalidOffer; 3483 if CountPrice(TOffer(Data), opMoney) > 1 then 3484 result := eInvalidOffer; 3485 if CountPrice(TOffer(Data), opTribute) > 1 then 3486 result := eInvalidOffer; 3487 case CountPrice(TOffer(Data), opChoose) of 3488 0: 3489 ; 3490 1: 3491 if (TOffer(Data).nCost = 0) or (TOffer(Data).nDeliver = 0) then 3492 result := eInvalidOffer; 3493 else 3494 result := eInvalidOffer; 3023 3495 end; 3024 3496 3025 // !!! check here if cost can be demanded3026 3027 if (Command>=sExecute) and (result>=rExecuted) then3497 // !!! check here if cost can be demanded 3498 3499 if (Command >= sExecute) and (result >= rExecuted) then 3028 3500 begin 3029 OfferFullySupported:= (TOffer(Data).nDeliver<=2)3030 and (TOffer(Data).nCost<=2); // >2 no more allowed3031 for i:=0 to TOffer(Data).nDeliver+TOffer(Data).nCost-1 do3501 OfferFullySupported := (TOffer(Data).nDeliver <= 2) and 3502 (TOffer(Data).nCost <= 2); // >2 no more allowed 3503 for i := 0 to TOffer(Data).nDeliver + TOffer(Data).nCost - 1 do 3032 3504 begin 3033 if TOffer(Data).Price[i] and opMask=opTribute then 3034 OfferFullySupported:=false; // tribute no more part of the game 3035 if (TOffer(Data).Price[i] and opMask=opTreaty) 3036 and (TOffer(Data).Price[i]-opTreaty<=RW[pDipActive].Treaty[p1]) then 3037 OfferFullySupported:=false; // agreed treaty end no more part of the game 3038 if TOffer(Data).Price[i]=opTreaty+trCeaseFire then 3039 OfferFullySupported:=false; // ceasefire no more part of the game 3505 if TOffer(Data).Price[i] and opMask = opTribute then 3506 OfferFullySupported := false; 3507 // tribute no more part of the game 3508 if (TOffer(Data).Price[i] and opMask = opTreaty) and 3509 (TOffer(Data).Price[i] - opTreaty <= RW[pDipActive].Treaty[p1]) 3510 then 3511 OfferFullySupported := false; 3512 // agreed treaty end no more part of the game 3513 if TOffer(Data).Price[i] = opTreaty + trCeaseFire then 3514 OfferFullySupported := false; 3515 // ceasefire no more part of the game 3040 3516 end; 3041 if not OfferFullySupported then3517 if not OfferFullySupported then 3042 3518 begin 3043 // some elements have been removed from the game - 3044 // automatically respond will null-offer 3045 LastOffer.nDeliver:=0; 3046 LastOffer.nCost:=0; 3047 ChangeClientWhenDone(scDipOffer,pDipActive,LastOffer,SizeOf(LastOffer)); 3519 // some elements have been removed from the game - 3520 // automatically respond will null-offer 3521 LastOffer.nDeliver := 0; 3522 LastOffer.nCost := 0; 3523 ChangeClientWhenDone(scDipOffer, pDipActive, LastOffer, 3524 SizeOf(LastOffer)); 3048 3525 end 3049 else3526 else 3050 3527 begin 3051 if (GTestFlags and tfUncover<>0) or (Difficulty[0]=0) then3052 with ShowNegoData do3528 if (GTestFlags and tfUncover <> 0) or (Difficulty[0] = 0) then 3529 with ShowNegoData do 3053 3530 begin // display negotiation in log window 3054 pSender:=pDipActive;3055 pTarget:=p1;3056 Action:=Command;3057 Offer:=TOffer(Data);3058 Brain[bix[0]].Client(cShowNego,1 shl 16+3,ShowNegoData);3531 pSender := pDipActive; 3532 pTarget := p1; 3533 Action := Command; 3534 Offer := TOffer(Data); 3535 Brain[bix[0]].Client(cShowNego, 1 shl 16 + 3, ShowNegoData); 3059 3536 end; 3060 LastOffer:=TOffer(Data); 3061 // show offered things to receiver 3062 for i:=0 to LastOffer.nDeliver-1 do 3063 ShowPrice(pDipActive,p1,LastOffer.Price[i]); 3064 pDipActive:=p1; 3065 assert(Mode=moPlaying); 3066 ChangeClientWhenDone(scDipOffer,pDipActive,LastOffer,SizeOf(LastOffer)); 3537 LastOffer := TOffer(Data); 3538 // show offered things to receiver 3539 for i := 0 to LastOffer.nDeliver - 1 do 3540 ShowPrice(pDipActive, p1, LastOffer.Price[i]); 3541 pDipActive := p1; 3542 assert(Mode = moPlaying); 3543 ChangeClientWhenDone(scDipOffer, pDipActive, LastOffer, 3544 SizeOf(LastOffer)); 3067 3545 end 3068 3546 end 3069 3547 end 3070 else result:=eInvalid; 3071 3072 { 3073 General Commands 3074 ____________________________________________________________________ 3075 } 3076 sClearTestFlag: 3077 if Player=0 then 3078 begin 3079 {$IFDEF TEXTLOG}CmdInfo:=Format('ClearTestFlag %x', [Subject]);{$ENDIF} 3080 ClearTestFlags(Subject); 3548 else 3549 result := eInvalid; 3550 3551 { 3552 General Commands 3553 ____________________________________________________________________ 3554 } 3555 sClearTestFlag: 3556 if Player = 0 then 3557 begin 3558 {$IFDEF TEXTLOG}CmdInfo := Format('ClearTestFlag %x', [Subject]); {$ENDIF} 3559 ClearTestFlags(Subject); 3081 3560 end 3082 else result:=eInvalid; 3083 3084 sSetTestFlag: 3085 if Player=0 then 3086 begin 3087 {$IFDEF TEXTLOG}CmdInfo:=Format('SetTestFlag %x', [Subject]);{$ENDIF} 3088 SetTestFlags(Player,Subject); 3089 // CheckContact; 3561 else 3562 result := eInvalid; 3563 3564 sSetTestFlag: 3565 if Player = 0 then 3566 begin 3567 {$IFDEF TEXTLOG}CmdInfo := Format('SetTestFlag %x', [Subject]); {$ENDIF} 3568 SetTestFlags(Player, Subject); 3569 // CheckContact; 3090 3570 end 3091 else result:=eInvalid; 3092 3093 sSetGovernment, sSetGovernment-sExecute: 3094 begin 3095 {$IFDEF TEXTLOG}CmdInfo:=Format('SetGovernment P%d: %d', [Player,Subject]);{$ENDIF} 3096 if RW[Player].Happened and phChangeGov=0 then result:=eViolation 3097 else if RW[Player].Government=Subject then result:=eNotChanged 3098 else if (Subject>=nGov) then result:=eInvalid 3099 else if (Subject>=gMonarchy) 3100 and (RW[Player].Tech[GovPreq[Subject]]<tsApplicable) then 3101 result:=eNoPreq 3102 else if Command>=sExecute then 3103 begin 3104 RW[Player].Government:=Subject; 3105 for p1:=0 to nPl-1 do if (p1<>Player) and ((GAlive or GWatching) and (1 shl p1)<>0) then 3106 RW[p1].EnemyReport[Player].Government:=Subject; 3107 end 3108 end; 3109 3110 sSetRates, sSetRates-sExecute: 3111 begin 3112 {$IFDEF TEXTLOG}CmdInfo:=Format('SetRates P%d: %d/%d', [Player,Subject and $f *10,Subject shr 4 *10]);{$ENDIF} 3113 if Subject and $f+Subject shr 4>10 then result:=eInvalid 3114 else if (RW[Player].TaxRate=Subject and $f *10) 3115 and (RW[Player].LuxRate=Subject shr 4 *10) then 3116 result:=eNotChanged 3117 else if Command>=sExecute then 3118 begin 3119 RW[Player].TaxRate:=Subject and $f *10; 3120 RW[Player].LuxRate:=Subject shr 4 *10; 3121 end 3122 end; 3123 3124 sRevolution: 3125 begin 3126 {$IFDEF TEXTLOG}CmdInfo:=Format('Revolution P%d', [Player]);{$ENDIF} 3127 if RW[Player].Government=gAnarchy then result:=eInvalid 3128 else 3129 begin 3130 RW[Player].Government:=gAnarchy; 3131 for p1:=0 to nPl-1 do if (p1<>Player) and ((GAlive or GWatching) and (1 shl p1)<>0) then 3132 RW[p1].EnemyReport[Player].Government:=gAnarchy; 3133 RW[Player].AnarchyStart:=GTurn; 3134 end; 3135 end; 3136 3137 sSetResearch, sSetResearch-sExecute: with RW[Player] do 3138 begin 3139 {$IFDEF TEXTLOG}CmdInfo:=Format('SetResearch P%d: %d', [Player,Subject]);{$ENDIF} 3140 if (Happened and phTech<>0) 3141 and ((Subject<nAdv) or (Subject=adMilitary)) then 3142 begin 3143 if (Mode=moPlaying) and (Subject=adMilitary) 3144 and (DevModelTurn[Player]<>GTurn) then 3145 result:=eNoModel 3146 else if Subject<>adMilitary then 3571 else 3572 result := eInvalid; 3573 3574 sSetGovernment, sSetGovernment - sExecute: 3575 begin 3576 {$IFDEF TEXTLOG}CmdInfo := Format('SetGovernment P%d: %d', [Player, Subject]); {$ENDIF} 3577 if RW[Player].Happened and phChangeGov = 0 then 3578 result := eViolation 3579 else if RW[Player].Government = Subject then 3580 result := eNotChanged 3581 else if (Subject >= nGov) then 3582 result := eInvalid 3583 else if (Subject >= gMonarchy) and 3584 (RW[Player].Tech[GovPreq[Subject]] < tsApplicable) then 3585 result := eNoPreq 3586 else if Command >= sExecute then 3147 3587 begin 3148 if Subject=futComputingTechnology then 3588 RW[Player].Government := Subject; 3589 for p1 := 0 to nPl - 1 do 3590 if (p1 <> Player) and ((GAlive or GWatching) and (1 shl p1) <> 0) 3591 then 3592 RW[p1].EnemyReport[Player].Government := Subject; 3593 end 3594 end; 3595 3596 sSetRates, sSetRates - sExecute: 3597 begin 3598 {$IFDEF TEXTLOG}CmdInfo := Format('SetRates P%d: %d/%d', [Player, Subject and $F * 10, Subject shr 4 * 10]); {$ENDIF} 3599 if Subject and $F + Subject shr 4 > 10 then 3600 result := eInvalid 3601 else if (RW[Player].TaxRate = Subject and $F * 10) and 3602 (RW[Player].LuxRate = Subject shr 4 * 10) then 3603 result := eNotChanged 3604 else if Command >= sExecute then 3605 begin 3606 RW[Player].TaxRate := Subject and $F * 10; 3607 RW[Player].LuxRate := Subject shr 4 * 10; 3608 end 3609 end; 3610 3611 sRevolution: 3612 begin 3613 {$IFDEF TEXTLOG}CmdInfo := Format('Revolution P%d', [Player]); {$ENDIF} 3614 if RW[Player].Government = gAnarchy then 3615 result := eInvalid 3616 else 3617 begin 3618 RW[Player].Government := gAnarchy; 3619 for p1 := 0 to nPl - 1 do 3620 if (p1 <> Player) and ((GAlive or GWatching) and (1 shl p1) <> 0) 3621 then 3622 RW[p1].EnemyReport[Player].Government := gAnarchy; 3623 RW[Player].AnarchyStart := GTurn; 3624 end; 3625 end; 3626 3627 sSetResearch, sSetResearch - sExecute: 3628 with RW[Player] do 3629 begin 3630 {$IFDEF TEXTLOG}CmdInfo := Format('SetResearch P%d: %d', [Player, Subject]); 3631 {$ENDIF} 3632 if (Happened and phTech <> 0) and 3633 ((Subject < nAdv) or (Subject = adMilitary)) then 3634 begin 3635 if (Mode = moPlaying) and (Subject = adMilitary) and 3636 (DevModelTurn[Player] <> GTurn) then 3637 result := eNoModel 3638 else if Subject <> adMilitary then 3149 3639 begin 3150 if Tech[Subject]>=MaxFutureTech_Computing then result:=eInvalid 3640 if Subject = futComputingTechnology then 3641 begin 3642 if Tech[Subject] >= MaxFutureTech_Computing then 3643 result := eInvalid 3644 end 3645 else if Subject in FutureTech then 3646 begin 3647 if Tech[Subject] >= MaxFutureTech then 3648 result := eInvalid 3649 end 3650 else if Tech[Subject] >= tsApplicable then 3651 result := eInvalid; // already discovered 3652 if Tech[Subject] <> tsSeen then // look if preqs met 3653 if AdvPreq[Subject, 2] <> preNone then 3654 begin // 2 of 3 required 3655 i := 0; 3656 for j := 0 to 2 do 3657 if Tech[AdvPreq[Subject, j]] >= tsApplicable then 3658 inc(i); 3659 if i < 2 then 3660 result := eNoPreq 3661 end 3662 else if (AdvPreq[Subject, 0] <> preNone) and 3663 (Tech[AdvPreq[Subject, 0]] < tsApplicable) or 3664 (AdvPreq[Subject, 1] <> preNone) and 3665 (Tech[AdvPreq[Subject, 1]] < tsApplicable) then 3666 result := eNoPreq 3667 end; 3668 if (result = eOK) and (Command >= sExecute) then 3669 begin 3670 if (Mode = moPlaying) and (Subject = adMilitary) then 3671 IntServer(sIntSetDevModel, Player, 0, DevModel.Kind); 3672 // save DevModel, because sctModel commands are not logged 3673 ResearchTech := Subject; 3151 3674 end 3152 else if Subject in FutureTech then 3675 end 3676 else 3677 result := eViolation; 3678 end; 3679 3680 sStealTech, sStealTech - sExecute: 3681 begin 3682 {$IFDEF TEXTLOG}CmdInfo := Format('StealTech P%d: %d', [Player, Subject]); 3683 {$ENDIF} 3684 if RW[Player].Happened and phStealTech = 0 then 3685 result := eInvalid 3686 else if (Subject >= nAdv) or (Subject in FutureTech) or 3687 (RW[Player].Tech[Subject] >= tsSeen) or 3688 (RW[GStealFrom].Tech[Subject] < tsApplicable) then 3689 result := eInvalid 3690 else if Command >= sExecute then 3691 begin 3692 SeeTech(Player, Subject); 3693 dec(RW[Player].Happened, phStealTech); 3694 end 3695 end; 3696 3697 sSetAttitude .. sSetAttitude + (nPl - 1) shl 4, 3698 sSetAttitude - sExecute .. sSetAttitude - sExecute + (nPl - 1) shl 4: 3699 begin 3700 p1 := Command shr 4 and $F; 3701 {$IFDEF TEXTLOG}CmdInfo := Format('SetAttitude P%d to P%d: %d', [Player, p1, Subject]); {$ENDIF} 3702 if (Subject >= nAttitude) or (p1 >= nPl) or 3703 (RW[Player].EnemyReport[p1] = nil) then 3704 result := eInvalid 3705 else if RW[Player].Treaty[p1] = trNoContact then 3706 result := eNoPreq 3707 else if RW[Player].Attitude[p1] = Subject then 3708 result := eNotChanged 3709 else if Command >= sExecute then 3710 begin 3711 RW[Player].Attitude[p1] := Subject; 3712 RW[p1].EnemyReport[Player].Attitude := Subject; 3713 end 3714 end; 3715 3716 sCancelTreaty, sCancelTreaty - sExecute: 3717 if (LastEndClientCommand <> scReject) or 3718 (RW[Player].Treaty[pContacted] < trPeace) then 3719 result := eInvalid 3720 else if (ServerVersion[Player] >= $010100) and 3721 (GTurn < RW[Player].LastCancelTreaty[pContacted] + CancelTreatyTurns) 3722 then 3723 result := eCancelTreatyRush 3724 else if Command >= sExecute then 3725 begin 3726 CallPlayer(cShowCancelTreaty, pContacted, Player); 3727 IntServer(sIntCancelTreaty, Player, pContacted, nil^); 3728 for p2 := 0 to nPl - 1 do 3729 if (p2 <> pContacted) and (1 shl p2 and PeaceEnded <> 0) then 3153 3730 begin 3154 if Tech[Subject]>=MaxFutureTech then result:=eInvalid 3731 i := pContacted shl 4 + Player; 3732 CallPlayer(cShowSupportAllianceAgainst, p2, i); 3733 end; 3734 for p2 := 0 to nPl - 1 do 3735 if (p2 <> pContacted) and (1 shl p2 and PeaceEnded <> 0) then 3736 begin 3737 i := p2; 3738 CallPlayer(cShowCancelTreatyByAlliance, Player, i); 3739 end; 3740 LastEndClientCommand := sTurn; 3741 end; 3742 3743 { 3744 Model Related Commands 3745 ____________________________________________________________________ 3746 } 3747 sCreateDevModel, sCreateDevModel - sExecute: 3748 begin 3749 {$IFDEF TEXTLOG}CmdInfo := Format('CreateDevModel P%d', [Player]); {$ENDIF} 3750 if Subject >= 4 then 3751 result := eInvalid 3752 else if (upgrade[Subject, 0].Preq <> preNone) and 3753 (RW[Player].Tech[upgrade[Subject, 0].Preq] < tsApplicable) then 3754 result := eNoPreq 3755 else if Command >= sExecute then 3756 begin 3757 with RW[Player].DevModel do 3758 begin 3759 Domain := Subject; 3760 MStrength := 0; 3761 MTrans := 0; 3762 MCost := 0; 3763 Upgrades := 0; 3764 FutureMCost := 0; 3765 for i := 0 to nUpgrade - 1 do 3766 with upgrade[Domain, i] do 3767 if (Preq = preNone) or (Preq >= 0) and 3768 ((RW[Player].Tech[Preq] >= tsApplicable) or 3769 (Preq in FutureTech) and (RW[Player].Tech[Preq] >= 0)) then 3770 begin 3771 if Preq in FutureTech then 3772 begin 3773 j := RW[Player].Tech[Preq]; 3774 inc(FutureMCost, j * Cost); 3775 end 3776 else 3777 begin 3778 j := 1; 3779 if Cost > MCost then 3780 MCost := Cost; 3781 end; 3782 inc(Upgrades, 1 shl i); 3783 inc(MStrength, j * Strength); 3784 inc(MTrans, j * Trans); 3785 end; 3786 inc(MCost, FutureMCost); 3787 FillChar(Cap, SizeOf(Cap), 0); 3788 Cap[mcOffense] := 2; 3789 Cap[mcDefense] := 1; 3790 for i := 0 to nFeature - 1 do 3791 with Feature[i] do 3792 if (1 shl Domain and Domains <> 0) and 3793 ((Preq = preNone) or (Preq = preSun) and 3794 (GWonder[woSun].EffectiveOwner = Player) or (Preq >= 0) and 3795 (RW[Player].Tech[Preq] >= tsApplicable)) and (i in AutoFeature) 3796 then 3797 Cap[i] := 1; 3798 MaxWeight := 5; 3799 if (WeightPreq7[Domain] <> preNA) and 3800 (RW[Player].Tech[WeightPreq7[Domain]] >= tsApplicable) then 3801 MaxWeight := 7; 3802 if (WeightPreq10[Domain] <> preNA) and 3803 (RW[Player].Tech[WeightPreq10[Domain]] >= tsApplicable) then 3804 if Domain = dSea then 3805 MaxWeight := 9 3806 else 3807 MaxWeight := 10; 3808 end; 3809 CalculateModel(RW[Player].DevModel); 3810 DevModelTurn[Player] := GTurn; 3811 end 3812 end; 3813 3814 sSetDevModelCap .. sSetDevModelCap + $3F0, 3815 sSetDevModelCap - sExecute .. sSetDevModelCap - sExecute + $3F0: 3816 begin 3817 {$IFDEF TEXTLOG}CmdInfo := Format('SetDevModelCap P%d', [Player]); {$ENDIF} 3818 if Subject >= nFeature then 3819 result := eInvalid 3820 else if DevModelTurn[Player] = GTurn then 3821 begin 3822 NewCap := Command shr 4 and $3F; { new value } 3823 with RW[Player].DevModel do 3824 if 1 shl Domain and Feature[Subject].Domains = 0 then 3825 result := eDomainMismatch 3826 else if not((Feature[Subject].Preq = preNone) or 3827 (Feature[Subject].Preq = preSun) and 3828 (GWonder[woSun].EffectiveOwner = Player) or 3829 (Feature[Subject].Preq >= 0) and 3830 (RW[Player].Tech[Feature[Subject].Preq] >= tsApplicable)) then 3831 result := eNoPreq 3832 else 3833 begin 3834 if (Subject in AutoFeature) or (Subject = mcDefense) then 3835 MinCap := 1 3836 else 3837 MinCap := 0; { MinCap - minimum use of feature } 3838 if Subject >= mcFirstNonCap then 3839 MaxCap := 1 3840 else if Subject = mcDefense then 3841 begin 3842 if Domain = dGround then 3843 MaxCap := 2 3844 else 3845 MaxCap := 3; 3846 if RW[Player].Tech[adSteel] >= tsApplicable then 3847 inc(MaxCap) 3848 end 3849 else 3850 MaxCap := 8; { MaxCap - maximum use of this feature } 3851 if (Domain = dGround) and (Subject = mcDefense) then 3852 CapWeight := 2 3853 else 3854 CapWeight := Feature[Subject].Weight; 3855 if (NewCap < MinCap) or (NewCap > MaxCap) or 3856 (Weight + (NewCap - Cap[Subject]) * CapWeight > MaxWeight) then 3857 result := eViolation 3858 else if Command >= sExecute then 3859 begin 3860 Cap[Subject] := NewCap; 3861 3862 // mutual feature exclusion 3863 case Subject of 3864 mcSub: 3865 begin 3866 if ServerVersion[Player] >= $010103 then 3867 Cap[mcSeaTrans] := 0; 3868 Cap[mcArtillery] := 0; 3869 Cap[mcCarrier] := 0; 3870 if Cap[mcDefense] > 2 then 3871 Cap[mcDefense] := 2 3872 end; 3873 mcSeaTrans: 3874 begin 3875 if ServerVersion[Player] >= $010103 then 3876 Cap[mcSub] := 0; 3877 end; 3878 mcCarrier: 3879 Cap[mcSub] := 0; 3880 mcArtillery: 3881 Cap[mcSub] := 0; 3882 mcAlpine: 3883 begin 3884 Cap[mcOver] := 0; 3885 Cap[mcMob] := 0; 3886 end; 3887 mcOver: 3888 Cap[mcAlpine] := 0; 3889 mcMob: 3890 begin 3891 Cap[mcAlpine] := 0; 3892 end; 3893 end; 3894 3895 CalculateModel(RW[Player].DevModel); 3896 end 3897 end; 3898 end 3899 else 3900 result := eNoModel; 3901 end; 3902 3903 { 3904 Unit Related Commands 3905 ____________________________________________________________________ 3906 } 3907 sRemoveUnit, sRemoveUnit - sExecute: 3908 begin 3909 {$IFDEF TEXTLOG}CmdInfo := Format('RemoveUnit P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 3910 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 3911 result := eInvalid 3912 else 3913 begin 3914 result := eRemoved; 3915 Loc0 := RW[Player].Un[Subject].Loc; 3916 if RealMap[Loc0] and fCity <> 0 then { check utilize } 3917 begin 3918 SearchCity(Loc0, Player, cix1); 3919 with RW[Player].City[cix1] do 3920 begin 3921 if (RW[Player].Model[RW[Player].Un[Subject].mix].Kind = mkCaravan) 3922 and ((Project and cpImp = 0) or 3923 (Imp[Project and cpIndex].Kind <> ikShipPart)) or 3924 (Project and cpImp = 0) and 3925 (RW[Player].Model[Project and cpIndex].Kind <> mkCaravan) then 3926 result := eUtilized; 3927 if Command >= sExecute then 3928 begin 3929 if result = eUtilized then 3930 begin 3931 with RW[Player].Un[Subject] do 3932 begin 3933 Cost := integer(RW[Player].Model[mix].Cost) * Health * 3934 BuildCostMod[Difficulty[Player]] div 1200; 3935 if RW[Player].Model[mix].Cap[mcLine] > 0 then 3936 Cost := Cost div 2; 3937 end; 3938 if Project and (cpImp + cpIndex) = cpImp + imTrGoods then 3939 inc(RW[Player].Money, Cost) 3940 else 3941 begin 3942 inc(Prod, Cost * 2 div 3); 3943 Project0 := Project0 and not cpCompleted; 3944 if Project0 and not cpAuto <> Project and not cpAuto then 3945 Project0 := Project; 3946 Prod0 := Prod; 3947 end 3948 end; 3949 RemoveUnit_UpdateMap(Player, Subject); 3950 end; 3951 end; 3155 3952 end 3156 else if Tech[Subject]>=tsApplicable then 3157 result:=eInvalid; // already discovered 3158 if Tech[Subject]<>tsSeen then // look if preqs met 3159 if AdvPreq[Subject,2]<>preNone then 3160 begin // 2 of 3 required 3161 i:=0; 3162 for j:=0 to 2 do 3163 if Tech[AdvPreq[Subject,j]]>=tsApplicable then inc(i); 3164 if i<2 then result:=eNoPreq 3165 end 3166 else if (AdvPreq[Subject,0]<>preNone) 3167 and (Tech[AdvPreq[Subject,0]]<tsApplicable) 3168 or (AdvPreq[Subject,1]<>preNone) 3169 and (Tech[AdvPreq[Subject,1]]<tsApplicable) then 3170 result:=eNoPreq 3953 else if Command >= sExecute then 3954 RemoveUnit_UpdateMap(Player, Subject); 3955 end 3956 end; 3957 3958 sSetUnitHome, sSetUnitHome - sExecute: 3959 begin 3960 {$IFDEF TEXTLOG}CmdInfo := Format('SetUnitHome P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 3961 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 3962 result := eInvalid 3963 else 3964 begin 3965 Loc0 := RW[Player].Un[Subject].Loc; 3966 if RealMap[Loc0] and fCity = 0 then 3967 result := eInvalid 3968 else 3969 begin 3970 SearchCity(Loc0, Player, cix1); 3971 if RW[Player].City[cix1].Flags and chCaptured <> 0 then 3972 result := eViolation 3973 else if Command >= sExecute then 3974 RW[Player].Un[Subject].Home := cix1 3975 end 3976 end 3977 end; 3978 3979 sSetSpyMission .. sSetSpyMission + (nSpyMission - 1) shl 4, 3980 sSetSpyMission - sExecute .. sSetSpyMission - sExecute + 3981 (nSpyMission - 1) shl 4: 3982 if Command >= sExecute then 3983 SpyMission := Command shr 4 and $F; 3984 3985 sLoadUnit, sLoadUnit - sExecute: 3986 begin 3987 {$IFDEF TEXTLOG}CmdInfo := Format('LoadUnit P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 3988 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 3989 result := eInvalid 3990 else 3991 result := LoadUnit(Player, Subject, Command < sExecute); 3992 end; 3993 3994 sUnloadUnit, sUnloadUnit - sExecute: 3995 begin 3996 {$IFDEF TEXTLOG}CmdInfo := Format('UnloadUnit P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 3997 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 3998 result := eInvalid 3999 else 4000 result := UnloadUnit(Player, Subject, Command < sExecute) 4001 end; 4002 4003 sSelectTransport, sSelectTransport - sExecute: 4004 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 4005 result := eInvalid 4006 else 4007 with RW[Player].Model[RW[Player].Un[Subject].mix] do 4008 begin 4009 if Cap[mcSeaTrans] + Cap[mcAirTrans] + Cap[mcCarrier] = 0 then 4010 result := eInvalid 4011 else if Command >= sExecute then 4012 uixSelectedTransport := Subject; 3171 4013 end; 3172 if (result=eOK) and (Command>=sExecute) then 4014 4015 sCreateUnit .. sCreateUnit + (nPl - 1) shl 4, 4016 sCreateUnit - sExecute .. sCreateUnit - sExecute + (nPl - 1) shl 4: 4017 if (GTestFlags and tfUncover <> 0) or (Difficulty[Player] = 0) 4018 then { supervisor only command } 4019 begin 4020 p1 := Command shr 4 and $F; 4021 Loc1 := integer(Data); 4022 if (Occupant[Loc1] >= 0) and (p1 <> Occupant[Loc1]) or 4023 (RealMap[Loc1] and fCity <> 0) and 4024 (RealMap[Loc1] shr 27 <> Cardinal(p1)) or 4025 (RW[p1].Model[Subject].Domain < dAir) and 4026 ((RW[p1].Model[Subject].Domain = dSea) <> (RealMap[integer(Data)] and 4027 fTerrain < fGrass)) then 4028 result := eViolation 4029 else if Command >= sExecute then 3173 4030 begin 3174 if (Mode=moPlaying) and (Subject=adMilitary) then3175 IntServer(sIntSetDevModel,Player,0,DevModel.Kind);3176 // save DevModel, because sctModel commands are not logged3177 ResearchTech:=Subject;4031 CreateUnit(p1, Subject); 4032 RW[p1].Un[RW[p1].nUn - 1].Loc := integer(Data); 4033 PlaceUnit(p1, RW[p1].nUn - 1); 4034 UpdateUnitMap(integer(Data)); 3178 4035 end 3179 4036 end 3180 else result:=eViolation; 3181 end; 3182 3183 sStealTech, sStealTech-sExecute: 3184 begin 3185 {$IFDEF TEXTLOG}CmdInfo:=Format('StealTech P%d: %d', [Player,Subject]);{$ENDIF} 3186 if RW[Player].Happened and phStealTech=0 then result:=eInvalid 3187 else if (Subject>=nAdv) or (Subject in FutureTech) 3188 or (RW[Player].Tech[Subject]>=tsSeen) 3189 or (RW[GStealFrom].Tech[Subject]<tsApplicable) then 3190 result:=eInvalid 3191 else if Command>=sExecute then 3192 begin 3193 SeeTech(Player,Subject); 3194 dec(RW[Player].Happened,phStealTech); 3195 end 3196 end; 3197 3198 sSetAttitude..sSetAttitude+(nPl-1) shl 4, 3199 sSetAttitude-sExecute..sSetAttitude-sExecute+(nPl-1) shl 4: 3200 begin 3201 p1:=Command shr 4 and $f; 3202 {$IFDEF TEXTLOG}CmdInfo:=Format('SetAttitude P%d to P%d: %d', [Player,p1,Subject]);{$ENDIF} 3203 if (Subject>=nAttitude) or (p1>=nPl) 3204 or (RW[Player].EnemyReport[p1]=nil) then 3205 result:=eInvalid 3206 else if RW[Player].Treaty[p1]=trNoContact then 3207 result:=eNoPreq 3208 else if RW[Player].Attitude[p1]=Subject then 3209 result:=eNotChanged 3210 else if Command>=sExecute then 3211 begin 3212 RW[Player].Attitude[p1]:=Subject; 3213 RW[p1].EnemyReport[Player].Attitude:=Subject; 3214 end 3215 end; 3216 3217 sCancelTreaty, sCancelTreaty-sExecute: 3218 if (LastEndClientCommand<>scReject) 3219 or (RW[Player].Treaty[pContacted]<trPeace) then 3220 result:=eInvalid 3221 else if (ServerVersion[Player]>=$010100) 3222 and (GTurn<RW[Player].LastCancelTreaty[pContacted]+CancelTreatyTurns) then 3223 result:=eCancelTreatyRush 3224 else if Command>=sExecute then 3225 begin 3226 CallPlayer(cShowCancelTreaty,pContacted,Player); 3227 IntServer(sIntCancelTreaty,Player,pContacted,nil^); 3228 for p2:=0 to nPl-1 do 3229 if (p2<>pContacted) and (1 shl p2 and PeaceEnded<>0) then 4037 else 4038 result := eInvalid; 4039 4040 sMoveUnit + (0 + 6 * 8) * 16, sMoveUnit + (1 + 7 * 8) * 16, 4041 sMoveUnit + (2 + 0 * 8) * 16, sMoveUnit + (1 + 1 * 8) * 16, 4042 sMoveUnit + (0 + 2 * 8) * 16, sMoveUnit + (7 + 1 * 8) * 16, 4043 sMoveUnit + (6 + 0 * 8) * 16, sMoveUnit + (7 + 7 * 8) * 16, 4044 sMoveUnit - sExecute + (0 + 6 * 8) * 16, sMoveUnit - sExecute + 4045 (1 + 7 * 8) * 16, sMoveUnit - sExecute + (2 + 0 * 8) * 16, 4046 sMoveUnit - sExecute + (1 + 1 * 8) * 16, sMoveUnit - sExecute + 4047 (0 + 2 * 8) * 16, sMoveUnit - sExecute + (7 + 1 * 8) * 16, 4048 sMoveUnit - sExecute + (6 + 0 * 8) * 16, sMoveUnit - sExecute + 4049 (7 + 7 * 8) * 16: 4050 begin 4051 dx := (Command shr 4 + 4) and 7 - 4; 4052 dy := (Command shr 7 + 4) and 7 - 4; 4053 {$IFDEF TEXTLOG}CmdInfo := Format('MoveUnit P%d I%d Mod%d Loc%d (%d,%d)', [Player, Subject, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc, dx, dy]); {$ENDIF} 4054 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 4055 result := eInvalid 4056 else 4057 result := MoveUnit(Player, Subject, dx, dy, Command < sExecute); 4058 end; 4059 4060 { 4061 Settlers Related Commands 4062 ____________________________________________________________________ 4063 } 4064 sAddToCity, sAddToCity - sExecute: 4065 begin 4066 {$IFDEF TEXTLOG}CmdInfo := Format('AddToCity P%d Mod%d Loc%d', [Player, RW[Player].Un[Subject].mix, RW[Player].Un[Subject].Loc]); {$ENDIF} 4067 if (Subject >= RW[Player].nUn) or (RW[Player].Un[Subject].Loc < 0) then 4068 result := eInvalid 4069 else if not(RW[Player].Model[RW[Player].Un[Subject].mix].Kind 4070 in [mkSettler, mkSlaves]) and 4071 (RW[Player].Un[Subject].Flags and unConscripts = 0) then 4072 result := eViolation 4073 else 4074 begin 4075 Loc0 := RW[Player].Un[Subject].Loc; 4076 if RealMap[Loc0] and fCity = 0 then 4077 result := eInvalid 4078 else 3230 4079 begin 3231 i:=pContacted shl 4+Player; 3232 CallPlayer(cShowSupportAllianceAgainst,p2,i); 4080 SearchCity(Loc0, Player, cix1); 4081 with RW[Player].City[cix1] do 4082 if not CanCityGrow(Player, cix1) then 4083 result := eMaxSize 4084 else if Command >= sExecute then 4085 begin { add to city } 4086 if Mode = moPlaying then 4087 SavedTiles[cix1] := 0; // save in every case 4088 if CanCityGrow(Player, cix1) then 4089 CityGrowth(Player, cix1); 4090 if (RW[Player].Model[RW[Player].Un[Subject].mix] 4091 .Kind = mkSettler) and CanCityGrow(Player, cix1) then 4092 CityGrowth(Player, cix1); 4093 RemoveUnit_UpdateMap(Player, Subject); 4094 end 4095 end 4096 end 4097 end; 4098 4099 sStartJob .. sStartJob + $3F0, sStartJob - sExecute .. sStartJob + $3F0 4100 - sExecute: 4101 begin 4102 Loc0 := RW[Player].Un[Subject].Loc; 4103 i := Command shr 4 and $3F; // new job 4104 {$IFDEF TEXTLOG}CmdInfo := Format('StartJob P%d Mod%d Loc%d: %d', [Player, RW[Player].Un[Subject].mix, Loc0, i]); {$ENDIF} 4105 if (Subject >= RW[Player].nUn) or (Loc0 < 0) then 4106 result := eInvalid 4107 else if i >= nJob then 4108 result := eInvalid 4109 else 4110 begin 4111 result := StartJob(Player, Subject, i, Command < sExecute); 4112 if result = eCity then 4113 begin // new city 4114 cix1 := RW[Player].nCity - 1; 4115 AddBestCityTile(Player, cix1); 4116 if Mode = moPlaying then 4117 with RW[Player].City[cix1] do 4118 begin 4119 // SavedResourceWeights[cix1]:=ResourceWeights; 4120 SavedTiles[cix1] := 0; // save in every case 4121 end; 4122 if Mode >= moMovie then { show new city in interface modules } 4123 for p1 := 0 to nPl - 1 do 4124 if (1 shl p1 and GWatching <> 0) and (p1 <> Player) and 4125 (ObserveLevel[Loc0] and (3 shl (2 * p1)) > 0) then 4126 CallPlayer(cShowCityChanged, p1, Loc0); 4127 end 4128 end; 4129 end; 4130 4131 { 4132 City Related Commands 4133 ____________________________________________________________________ 4134 } 4135 sSetCityProject, sSetCityProject - sExecute: 4136 begin 4137 NewProject := integer(Data) and not cpAuto; 4138 {$IFDEF TEXTLOG}CmdInfo := Format('SetCityProject P%d Loc%d: %d', [Player, RW[Player].City[Subject].Loc, NewProject]); {$ENDIF} 4139 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4140 then 4141 result := eInvalid 4142 else 4143 with RW[Player].City[Subject] do 4144 begin 4145 if NewProject = Project then 4146 result := eNotChanged 4147 else 4148 begin 4149 pt0 := ProjectType(Project0); 4150 pt1 := ProjectType(NewProject); 4151 if NewProject and cpImp = 0 then 4152 begin 4153 if NewProject and cpIndex >= RW[Player].nModel then 4154 result := eInvalid 4155 else if (NewProject and cpConscripts <> 0) and 4156 not((RW[Player].Tech[adConscription] >= tsApplicable) and 4157 (RW[Player].Model[NewProject and cpIndex].Domain = dGround) 4158 and (RW[Player].Model[NewProject and cpIndex].Kind < mkScout)) 4159 then 4160 result := eViolation 4161 // else if (RW[Player].Model[NewProject and cpIndex].Kind=mkSlaves) 4162 // and (GWonder[woPyramids].EffectiveOwner<>Player) then 4163 // result:=eNoPreq 4164 end 4165 else if NewProject and cpIndex >= nImp then 4166 result := eInvalid 4167 else 4168 begin 4169 Preq := Imp[NewProject and cpIndex].Preq; 4170 for i := 0 to nImpReplacement - 1 do 4171 if (ImpReplacement[i].OldImp = NewProject and cpIndex) and 4172 (built[ImpReplacement[i].NewImp] > 0) then 4173 result := eObsolete; 4174 if result = eObsolete then 4175 else if Preq = preNA then 4176 result := eInvalid 4177 else if (Preq >= 0) and (RW[Player].Tech[Preq] < tsApplicable) 4178 then 4179 result := eNoPreq 4180 else if built[NewProject and cpIndex] > 0 then 4181 result := eInvalid 4182 else if (NewProject and cpIndex < 28) and 4183 (GWonder[NewProject and cpIndex].CityID <> -1) then 4184 result := eViolation // wonder already exists 4185 else if (NewProject and cpIndex = imSpacePort) and 4186 (RW[Player].NatBuilt[imSpacePort] > 0) then 4187 result := eViolation // space port already exists 4188 else if (NewProject = cpImp + imBank) and (built[imMarket] = 0) 4189 or (NewProject = cpImp + imUniversity) and 4190 (built[imLibrary] = 0) or (NewProject = cpImp + imResLab) and 4191 (built[imUniversity] = 0) or (NewProject = cpImp + imMfgPlant) 4192 and (built[imFactory] = 0) then 4193 result := eNoPreq; 4194 case NewProject - cpImp of 4195 woLighthouse, woMagellan, imCoastalFort, imHarbor, imPlatform: 4196 begin { city at ocean? } 4197 Preq := 0; 4198 V8_to_Loc(Loc, Adjacent); 4199 for V8 := 0 to 7 do 4200 begin 4201 Loc1 := Adjacent[V8]; 4202 if (Loc1 >= 0) and (Loc1 < MapSize) and 4203 (RealMap[Loc1] and fTerrain = fShore) then 4204 inc(Preq); 4205 end; 4206 if Preq = 0 then 4207 result := eNoPreq; 4208 end; 4209 woHoover, imHydro: 4210 begin { city at river or mountains? } 4211 Preq := 0; 4212 V8_to_Loc(Loc, Adjacent); 4213 for V8 := 0 to 7 do 4214 begin 4215 Loc1 := Adjacent[V8]; 4216 if (Loc1 >= 0) and (Loc1 < MapSize) and 4217 ((RealMap[Loc1] and fTerrain = fMountains) or 4218 (RealMap[Loc1] and fRiver <> 0)) then 4219 inc(Preq); 4220 end; 4221 if Preq = 0 then 4222 result := eNoPreq; 4223 end; 4224 woMIR, imShipComp, imShipPow, imShipHab: 4225 if RW[Player].NatBuilt[imSpacePort] = 0 then 4226 result := eNoPreq; 4227 end; 4228 if (GTestFlags and tfNoRareNeed = 0) and 4229 (Imp[NewProject and cpIndex].Kind = ikShipPart) then 4230 if RW[Player].Tech[adMassProduction] < tsApplicable then 4231 result := eNoPreq 4232 else 4233 begin // check for rare resources 4234 if NewProject and cpIndex = imShipComp then 4235 j := 1 4236 else if NewProject and cpIndex = imShipPow then 4237 j := 2 4238 else { if NewProject and cpIndex=imShipHab then } 4239 j := 3; 4240 // j = rare resource required 4241 Preq := 0; 4242 V21_to_Loc(Loc, Radius); 4243 for V21 := 1 to 26 do 4244 begin 4245 Loc1 := Radius[V21]; 4246 if (Loc1 >= 0) and (Loc1 < MapSize) and 4247 (RealMap[Loc1] shr 25 and 3 = Cardinal(j)) then 4248 inc(Preq); 4249 end; 4250 if Preq = 0 then 4251 result := eNoPreq; 4252 end 4253 end; 4254 4255 if (Command >= sExecute) and (result >= rExecuted) then 4256 begin 4257 if pt0 <> ptSelect then 4258 if NewProject and (cpImp or cpIndex) = Project0 and 4259 (cpImp or cpIndex) then 4260 Prod := Prod0 4261 else if (pt1 = ptTrGoods) or (pt1 = ptShip) or (pt1 <> pt0) 4262 and (pt0 <> ptCaravan) then 4263 begin 4264 inc(RW[Player].Money, Prod0); 4265 Prod := 0; 4266 Prod0 := 0; 4267 Project0 := cpImp + imTrGoods 4268 end 4269 else 4270 Prod := Prod0 * 2 div 3; 4271 Project := NewProject 4272 end 4273 end 4274 end 4275 end; 4276 4277 sBuyCityProject, sBuyCityProject - sExecute: 4278 begin 4279 {$IFDEF TEXTLOG}CmdInfo := Format('BuyCityProject P%d Loc%d', [Player, RW[Player].City[Subject].Loc]); {$ENDIF} 4280 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4281 then 4282 result := eInvalid 4283 else 4284 with RW[Player].City[Subject] do 4285 if (RW[Player].Government = gAnarchy) or (Flags and chCaptured <> 0) 4286 then 4287 result := eOutOfControl 4288 else if (Project and cpImp <> 0) and 4289 ((Project and cpIndex = imTrGoods) or 4290 (Imp[Project and cpIndex].Kind = ikShipPart)) then 4291 result := eInvalid // don't buy colony ship 4292 else 4293 begin 4294 CityReport.HypoTiles := -1; 4295 CityReport.HypoTax := -1; 4296 CityReport.HypoLux := -1; 4297 GetCityReport(Player, Subject, CityReport); 4298 Cost := CityReport.ProdCost; 4299 NextProd := CityReport.ProdRep - CityReport.Support; 4300 if (CityReport.Working - CityReport.Happy > Size shr 1) or 4301 (NextProd < 0) then // !!! change to new style disorder 4302 NextProd := 0; 4303 Cost := Cost - Prod - NextProd; 4304 if (GWonder[woMich].EffectiveOwner = Player) and 4305 (Project and cpImp <> 0) then 4306 Cost := Cost * 2 4307 else 4308 Cost := Cost * 4; 4309 if Cost <= 0 then 4310 result := eNotChanged 4311 else if Cost > RW[Player].Money then 4312 result := eViolation 4313 else if Command >= sExecute then 4314 IntServer(sIntBuyMaterial, Player, Subject, Cost); 4315 // need to save material/cost because city tiles are not correct 4316 // when loading 4317 end; 4318 end; 4319 4320 sSellCityProject, sSellCityProject - sExecute: 4321 begin 4322 {$IFDEF TEXTLOG}CmdInfo := Format('SellCityProject P%d Loc%d', [Player, RW[Player].City[Subject].Loc]); {$ENDIF} 4323 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4324 then 4325 result := eInvalid 4326 else if Command >= sExecute then 4327 with RW[Player].City[Subject] do 4328 begin 4329 inc(RW[Player].Money, Prod0); 4330 Prod := 0; 4331 Prod0 := 0; 3233 4332 end; 3234 for p2:=0 to nPl-1 do 3235 if (p2<>pContacted) and (1 shl p2 and PeaceEnded<>0) then 3236 begin 3237 i:=p2; 3238 CallPlayer(cShowCancelTreatyByAlliance,Player,i); 3239 end; 3240 LastEndClientCommand:=sTurn; 3241 end; 3242 3243 { 3244 Model Related Commands 3245 ____________________________________________________________________ 3246 } 3247 sCreateDevModel, sCreateDevModel-sExecute: 3248 begin 3249 {$IFDEF TEXTLOG}CmdInfo:=Format('CreateDevModel P%d', [Player]);{$ENDIF} 3250 if Subject>=4 then result:=eInvalid 3251 else if (upgrade[Subject,0].Preq<>preNone) 3252 and (RW[Player].Tech[upgrade[Subject,0].Preq]<tsApplicable) then 3253 result:=eNoPreq 3254 else if Command>=sExecute then 3255 begin 3256 with RW[Player].DevModel do 3257 begin 3258 Domain:=Subject; 3259 MStrength:=0; MTrans:=0; MCost:=0; Upgrades:=0; 3260 FutureMCost:=0; 3261 for i:=0 to nUpgrade-1 do with upgrade[Domain,i] do 3262 if (Preq=preNone) 3263 or (Preq>=0) and ((RW[Player].Tech[Preq]>=tsApplicable) 3264 or (Preq in FutureTech) and (RW[Player].Tech[Preq]>=0)) then 4333 end; 4334 4335 sSellCityImprovement, sSellCityImprovement - sExecute: 4336 begin 4337 {$IFDEF TEXTLOG}CmdInfo := Format('SellCityImprovement P%d Loc%d: %d', [Player, RW[Player].City[Subject].Loc, integer(Data)]); {$ENDIF} 4338 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4339 then 4340 result := eInvalid 4341 else 4342 with RW[Player].City[Subject] do 4343 if built[integer(Data)] = 0 then 4344 result := eInvalid 4345 else if (RW[Player].Government = gAnarchy) or 4346 (Flags and chCaptured <> 0) then 4347 result := eOutOfControl 4348 else if Flags and chImprovementSold <> 0 then 4349 result := eOnlyOnce 4350 else if Command >= sExecute then 3265 4351 begin 3266 if Preq in FutureTech then 4352 inc(RW[Player].Money, Imp[integer(Data)].Cost * BuildCostMod 4353 [Difficulty[Player]] div 12); 4354 built[integer(Data)] := 0; 4355 if Imp[integer(Data)].Kind in [ikNatLocal, ikNatGlobal] then 3267 4356 begin 3268 j:=RW[Player].Tech[Preq]; 3269 inc(FutureMCost,j*Cost); 3270 end 3271 else 3272 begin 3273 j:=1; 3274 if Cost>MCost then MCost:=Cost; 3275 end; 3276 inc(Upgrades,1 shl i); 3277 inc(MStrength,j*Strength); 3278 inc(MTrans,j*Trans); 3279 end; 3280 inc(MCost,FutureMCost); 3281 FillChar(Cap,SizeOf(Cap),0); 3282 Cap[mcOffense]:=2; 3283 Cap[mcDefense]:=1; 3284 for i:=0 to nFeature-1 do with Feature[i] do 3285 if (1 shl Domain and Domains<>0) and ((Preq=preNone) 3286 or (Preq=preSun) and (GWonder[woSun].EffectiveOwner=Player) 3287 or (Preq>=0) and (RW[Player].Tech[Preq]>=tsApplicable)) 3288 and (i in AutoFeature) then Cap[i]:=1; 3289 MaxWeight:=5; 3290 if (WeightPreq7[Domain]<>preNA) 3291 and (RW[Player].Tech[WeightPreq7[Domain]]>=tsApplicable) then 3292 MaxWeight:=7; 3293 if (WeightPreq10[Domain]<>preNA) 3294 and (RW[Player].Tech[WeightPreq10[Domain]]>=tsApplicable) then 3295 if Domain=dSea then MaxWeight:=9 3296 else MaxWeight:=10; 3297 end; 3298 CalculateModel(RW[Player].DevModel); 3299 DevModelTurn[Player]:=GTurn; 3300 end 3301 end; 3302 3303 sSetDevModelCap..sSetDevModelCap+$3F0, 3304 sSetDevModelCap-sExecute..sSetDevModelCap-sExecute+$3F0: 3305 begin 3306 {$IFDEF TEXTLOG}CmdInfo:=Format('SetDevModelCap P%d', [Player]);{$ENDIF} 3307 if Subject>=nFeature then result:=eInvalid 3308 else if DevModelTurn[Player]=GTurn then 3309 begin 3310 NewCap:=Command shr 4 and $3F; {new value} 3311 with RW[Player].DevModel do 3312 if 1 shl Domain and Feature[Subject].Domains=0 then 3313 result:=eDomainMismatch 3314 else if not ((Feature[Subject].Preq=preNone) 3315 or (Feature[Subject].Preq=preSun) 3316 and (GWonder[woSun].EffectiveOwner=Player) 3317 or (Feature[Subject].Preq>=0) 3318 and (RW[Player].Tech[Feature[Subject].Preq]>=tsApplicable)) then 3319 result:=eNoPreq 3320 else 3321 begin 3322 if (Subject in AutoFeature) or (Subject=mcDefense) then MinCap:=1 3323 else MinCap:=0; {MinCap - minimum use of feature} 3324 if Subject>=mcFirstNonCap then MaxCap:=1 3325 else if Subject=mcDefense then 3326 begin 3327 if Domain=dGround then MaxCap:=2 3328 else MaxCap:=3; 3329 if RW[Player].Tech[adSteel]>=tsApplicable then inc(MaxCap) 3330 end 3331 else MaxCap:=8; {MaxCap - maximum use of this feature} 3332 if (Domain=dGround) and (Subject=mcDefense) then CapWeight:=2 3333 else CapWeight:=Feature[Subject].Weight; 3334 if (NewCap<MinCap) or (NewCap>MaxCap) 3335 or (Weight+(NewCap-Cap[Subject])*CapWeight>MaxWeight) then 3336 result:=eViolation 3337 else if Command>=sExecute then 3338 begin 3339 Cap[Subject]:=NewCap; 3340 3341 // mutual feature exclusion 3342 case Subject of 3343 mcSub: 3344 begin 3345 if ServerVersion[Player]>=$010103 then 3346 Cap[mcSeaTrans]:=0; 3347 Cap[mcArtillery]:=0; 3348 Cap[mcCarrier]:=0; 3349 if Cap[mcDefense]>2 then Cap[mcDefense]:=2 3350 end; 3351 mcSeaTrans: 3352 begin 3353 if ServerVersion[Player]>=$010103 then 3354 Cap[mcSub]:=0; 3355 end; 3356 mcCarrier: Cap[mcSub]:=0; 3357 mcArtillery: Cap[mcSub]:=0; 3358 mcAlpine: 3359 begin Cap[mcOver]:=0; Cap[mcMob]:=0; end; 3360 mcOver: Cap[mcAlpine]:=0; 3361 mcMob: begin Cap[mcAlpine]:=0; end; 3362 end; 3363 3364 CalculateModel(RW[Player].DevModel); 3365 end 3366 end; 3367 end 3368 else result:=eNoModel; 3369 end; 3370 3371 { 3372 Unit Related Commands 3373 ____________________________________________________________________ 3374 } 3375 sRemoveUnit,sRemoveUnit-sExecute: 3376 begin 3377 {$IFDEF TEXTLOG}CmdInfo:=Format('RemoveUnit P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3378 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3379 result:=eInvalid 3380 else 3381 begin 3382 result:=eRemoved; 3383 Loc0:=RW[Player].Un[Subject].Loc; 3384 if RealMap[Loc0] and fCity<>0 then {check utilize} 3385 begin 3386 SearchCity(Loc0,Player,cix1); 3387 with RW[Player].City[cix1] do 3388 begin 3389 if (RW[Player].Model[RW[Player].Un[Subject].mix].Kind=mkCaravan) 3390 and ((Project and cpImp=0) or (Imp[Project and cpIndex].Kind<>ikShipPart)) 3391 or (Project and cpImp=0) and (RW[Player].Model[Project 3392 and cpIndex].Kind<>mkCaravan) then 3393 result:=eUtilized; 3394 if Command>=sExecute then 3395 begin 3396 if result=eUtilized then 3397 begin 3398 with RW[Player].Un[Subject] do 3399 begin 3400 Cost:=integer(RW[Player].Model[mix].Cost)*Health 3401 *BuildCostMod[Difficulty[Player]] div 1200; 3402 if RW[Player].Model[mix].Cap[mcLine]>0 then 3403 Cost:=Cost div 2; 3404 end; 3405 if Project and (cpImp+cpIndex)=cpImp+imTrGoods then 3406 inc(RW[Player].Money,Cost) 3407 else 3408 begin 3409 inc(Prod,Cost*2 div 3); 3410 Project0:=Project0 and not cpCompleted; 3411 if Project0 and not cpAuto<>Project and not cpAuto then 3412 Project0:=Project; 3413 Prod0:=Prod; 4357 RW[Player].NatBuilt[integer(Data)] := 0; 4358 case integer(Data) of 4359 imGrWall: 4360 GrWallContinent[Player] := -1; 4361 imSpacePort: 4362 DestroySpacePort_TellPlayers(Player, -1); 3414 4363 end 3415 4364 end; 3416 RemoveUnit_UpdateMap(Player,Subject); 3417 end; 3418 end; 4365 inc(Flags, chImprovementSold); 4366 end 4367 end; 4368 4369 sRebuildCityImprovement, sRebuildCityImprovement - sExecute: 4370 begin 4371 OldImp := integer(Data); 4372 {$IFDEF TEXTLOG}CmdInfo := Format('RebuildCityImprovement P%d Loc%d: %d', [Player, RW[Player].City[Subject].Loc, OldImp]); {$ENDIF} 4373 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4374 then 4375 result := eInvalid 4376 else 4377 begin 4378 if (OldImp < 0) or (OldImp >= nImp) or 4379 not(Imp[OldImp].Kind in [ikCommon, ikNatLocal, ikNatGlobal]) then 4380 result := eInvalid 4381 else 4382 with RW[Player].City[Subject] do 4383 if (built[OldImp] = 0) or (Project and cpImp = 0) or 4384 not(Imp[Project and cpIndex].Kind in [ikCommon, ikNatLocal, 4385 ikNatGlobal]) then 4386 result := eInvalid 4387 else if (RW[Player].Government = gAnarchy) or 4388 (Flags and chCaptured <> 0) then 4389 result := eOutOfControl 4390 else if Flags and chImprovementSold <> 0 then 4391 result := eOnlyOnce 4392 else if Command >= sExecute then 4393 begin 4394 inc(Prod, Imp[OldImp].Cost * BuildCostMod[Difficulty[Player]] 4395 div 12 * 2 div 3); 4396 Project0 := Project0 and not cpCompleted; 4397 if Project0 and not cpAuto <> Project and not cpAuto then 4398 Project0 := Project; 4399 Prod0 := Prod; 4400 built[OldImp] := 0; 4401 if Imp[OldImp].Kind in [ikNatLocal, ikNatGlobal] then 4402 begin // nat. project lost 4403 RW[Player].NatBuilt[OldImp] := 0; 4404 case OldImp of 4405 imGrWall: 4406 GrWallContinent[Player] := -1; 4407 imSpacePort: 4408 DestroySpacePort_TellPlayers(Player, -1); 4409 end 4410 end; 4411 inc(Flags, chImprovementSold); 4412 end 3419 4413 end 3420 else if Command>=sExecute then 3421 RemoveUnit_UpdateMap(Player,Subject); 3422 end 4414 end; 4415 4416 sSetCityTiles, sSetCityTiles - sExecute: 4417 begin 4418 {$IFDEF TEXTLOG}CmdInfo := Format('SetCityTiles P%d Loc%d: %x', [Player, RW[Player].City[Subject].Loc, integer(Data)]); {$ENDIF} 4419 if (Subject >= RW[Player].nCity) or (RW[Player].City[Subject].Loc < 0) 4420 then 4421 result := eInvalid 4422 else 4423 result := SetCityTiles(Player, Subject, integer(Data), 4424 Command < sExecute); 4425 end; 4426 4427 { 4428 Client Exclusive Commands 4429 ____________________________________________________________________ 4430 } 4431 else 4432 if Command >= cClientEx then 4433 begin 4434 {$IFDEF TEXTLOG}CmdInfo := Format('ClientEx%x P%d', [Command, Player]); 4435 {$ENDIF} 4436 if ProcessClientData[Player] or (Mode = moPlaying) then 4437 CallPlayer(Command, Player, Data) 4438 end 4439 else 4440 result := eUnknown; 4441 end; { case command } 4442 4443 // do not log invalid and non-relevant commands 4444 if result = eZOC_EnemySpotted then 4445 begin 4446 assert(Mode = moPlaying); 4447 CL.State := FormerCLState; 4448 IntServer(sIntDiscoverZOC, Player, 0, ZOCTile); 4449 end 4450 else if result and rEffective = 0 then 4451 if Mode < moPlaying then 4452 begin 4453 {$IFDEF TEXTLOG}CmdInfo := Format('***ERROR (%x) ', [result]) + CmdInfo; 4454 {$ENDIF} 4455 LoadOK := false; 4456 end 4457 else 4458 begin 4459 if logged then 4460 CL.State := FormerCLState; 4461 if (result < rExecuted) and (Command >= sExecute) then 4462 PutMessage(1 shl 16 + 1, Format('INVALID: %d calls %x (%d)', 4463 [Player, Command, Subject])); 3423 4464 end; 3424 4465 3425 sSetUnitHome,sSetUnitHome-sExecute: 3426 begin 3427 {$IFDEF TEXTLOG}CmdInfo:=Format('SetUnitHome P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3428 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3429 result:=eInvalid 3430 else 3431 begin 3432 Loc0:=RW[Player].Un[Subject].Loc; 3433 if RealMap[Loc0] and fCity=0 then result:=eInvalid 3434 else 3435 begin 3436 SearchCity(Loc0,Player,cix1); 3437 if RW[Player].City[cix1].Flags and chCaptured<>0 then 3438 result:=eViolation 3439 else if Command>=sExecute then 3440 RW[Player].Un[Subject].Home:=cix1 3441 end 3442 end 3443 end; 3444 3445 sSetSpyMission..sSetSpyMission+(nSpyMission-1) shl 4, 3446 sSetSpyMission-sExecute..sSetSpyMission-sExecute+(nSpyMission-1) shl 4: 3447 if Command>=sExecute then 3448 SpyMission:=Command shr 4 and $F; 3449 3450 sLoadUnit,sLoadUnit-sExecute: 3451 begin 3452 {$IFDEF TEXTLOG}CmdInfo:=Format('LoadUnit P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3453 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3454 result:=eInvalid 3455 else result:=LoadUnit(Player,Subject,Command<sExecute); 3456 end; 3457 3458 sUnloadUnit,sUnloadUnit-sExecute: 3459 begin 3460 {$IFDEF TEXTLOG}CmdInfo:=Format('UnloadUnit P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3461 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3462 result:=eInvalid 3463 else result:=UnloadUnit(Player,Subject,Command<sExecute) 3464 end; 3465 3466 sSelectTransport,sSelectTransport-sExecute: 3467 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3468 result:=eInvalid 3469 else with RW[Player].Model[RW[Player].Un[Subject].mix] do 3470 begin 3471 if Cap[mcSeaTrans]+Cap[mcAirTrans]+Cap[mcCarrier]=0 then 3472 result:=eInvalid 3473 else if Command>=sExecute then 3474 uixSelectedTransport:=Subject; 3475 end; 3476 3477 sCreateUnit..sCreateUnit+(nPl-1) shl 4, 3478 sCreateUnit-sExecute..sCreateUnit-sExecute+(nPl-1) shl 4: 3479 if (GTestFlags and tfUncover<>0) or (Difficulty[Player]=0) then {supervisor only command} 3480 begin 3481 p1:=Command shr 4 and $f; 3482 Loc1:=integer(Data); 3483 if (Occupant[Loc1]>=0) and (p1<>Occupant[Loc1]) 3484 or (RealMap[Loc1] and fCity<>0) and (RealMap[Loc1] shr 27<>Cardinal(p1)) 3485 or (RW[p1].Model[Subject].Domain<dAir) 3486 and ((RW[p1].Model[Subject].Domain=dSea) 3487 <>(RealMap[integer(Data)] and fTerrain<fGrass)) then 3488 result:=eViolation 3489 else if Command>=sExecute then 3490 begin 3491 CreateUnit(p1,Subject); 3492 RW[p1].Un[RW[p1].nUn-1].Loc:=integer(Data); 3493 PlaceUnit(p1,RW[p1].nUn-1); 3494 UpdateUnitMap(integer(Data)); 3495 end 3496 end 3497 else result:=eInvalid; 3498 3499 sMoveUnit+(0+6*8)*16,sMoveUnit+(1+7*8)*16, 3500 sMoveUnit+(2+0*8)*16,sMoveUnit+(1+1*8)*16, 3501 sMoveUnit+(0+2*8)*16,sMoveUnit+(7+1*8)*16, 3502 sMoveUnit+(6+0*8)*16,sMoveUnit+(7+7*8)*16, 3503 sMoveUnit-sExecute+(0+6*8)*16,sMoveUnit-sExecute+(1+7*8)*16, 3504 sMoveUnit-sExecute+(2+0*8)*16,sMoveUnit-sExecute+(1+1*8)*16, 3505 sMoveUnit-sExecute+(0+2*8)*16,sMoveUnit-sExecute+(7+1*8)*16, 3506 sMoveUnit-sExecute+(6+0*8)*16,sMoveUnit-sExecute+(7+7*8)*16: 3507 begin 3508 dx:=(Command shr 4 +4) and 7-4; dy:=(Command shr 7 +4) and 7-4; 3509 {$IFDEF TEXTLOG}CmdInfo:=Format('MoveUnit P%d I%d Mod%d Loc%d (%d,%d)', [Player,Subject,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc,dx,dy]);{$ENDIF} 3510 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3511 result:=eInvalid 3512 else result:=MoveUnit(Player,Subject,dx,dy,Command<sExecute); 3513 end; 3514 3515 { 3516 Settlers Related Commands 3517 ____________________________________________________________________ 3518 } 3519 sAddToCity, sAddToCity-sExecute: 3520 begin 3521 {$IFDEF TEXTLOG}CmdInfo:=Format('AddToCity P%d Mod%d Loc%d', [Player,RW[Player].Un[Subject].mix,RW[Player].Un[Subject].Loc]);{$ENDIF} 3522 if (Subject>=RW[Player].nUn) or (RW[Player].Un[Subject].Loc<0) then 3523 result:=eInvalid 3524 else if not (RW[Player].Model[RW[Player].Un[Subject].mix].Kind in [mkSettler,mkSlaves]) 3525 and (RW[Player].Un[Subject].Flags and unConscripts=0) then 3526 result:=eViolation 3527 else 3528 begin 3529 Loc0:=RW[Player].Un[Subject].Loc; 3530 if RealMap[Loc0] and fCity=0 then result:=eInvalid 3531 else 3532 begin 3533 SearchCity(Loc0,Player,cix1); 3534 with RW[Player].City[cix1] do 3535 if not CanCityGrow(Player,cix1) then 3536 result:=eMaxSize 3537 else if Command>=sExecute then 3538 begin {add to city} 3539 if Mode=moPlaying then 3540 SavedTiles[cix1]:=0; // save in every case 3541 if CanCityGrow(Player,cix1) then 3542 CityGrowth(Player,cix1); 3543 if (RW[Player].Model[RW[Player].Un[Subject].mix].Kind=mkSettler) 3544 and CanCityGrow(Player,cix1) then 3545 CityGrowth(Player,cix1); 3546 RemoveUnit_UpdateMap(Player,Subject); 3547 end 3548 end 3549 end 3550 end; 3551 3552 sStartJob..sStartJob+$3F0, sStartJob-sExecute..sStartJob+$3F0-sExecute: 3553 begin 3554 Loc0:=RW[Player].Un[Subject].Loc; 3555 i:=Command shr 4 and $3F; // new job 3556 {$IFDEF TEXTLOG}CmdInfo:=Format('StartJob P%d Mod%d Loc%d: %d', [Player,RW[Player].Un[Subject].mix,Loc0,i]);{$ENDIF} 3557 if (Subject>=RW[Player].nUn) or (Loc0<0) then 3558 result:=eInvalid 3559 else if i>=nJob then result:=eInvalid 3560 else 3561 begin 3562 result:=StartJob(Player,Subject,i,Command<sExecute); 3563 if result=eCity then 3564 begin // new city 3565 cix1:=RW[Player].nCity-1; 3566 AddBestCityTile(Player,cix1); 3567 if Mode=moPlaying then with RW[Player].City[cix1] do 3568 begin 3569 // SavedResourceWeights[cix1]:=ResourceWeights; 3570 SavedTiles[cix1]:=0; // save in every case 3571 end; 3572 if Mode>=moMovie then {show new city in interface modules} 3573 for p1:=0 to nPl-1 do 3574 if (1 shl p1 and GWatching<>0) and (p1<>Player) 3575 and (ObserveLevel[Loc0] and (3 shl (2*p1))>0) then 3576 CallPlayer(cShowCityChanged,p1,Loc0); 3577 end 3578 end; 3579 end; 3580 3581 { 3582 City Related Commands 3583 ____________________________________________________________________ 3584 } 3585 sSetCityProject,sSetCityProject-sExecute: 3586 begin 3587 NewProject:=integer(Data) and not cpAuto; 3588 {$IFDEF TEXTLOG}CmdInfo:=Format('SetCityProject P%d Loc%d: %d', [Player,RW[Player].City[Subject].Loc,NewProject]);{$ENDIF} 3589 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3590 result:=eInvalid 3591 else with RW[Player].City[Subject] do 3592 begin 3593 if NewProject=Project then result:=eNotChanged 3594 else 3595 begin 3596 pt0:=ProjectType(Project0); 3597 pt1:=ProjectType(NewProject); 3598 if NewProject and cpImp=0 then 3599 begin 3600 if NewProject and cpIndex>=RW[Player].nModel then 3601 result:=eInvalid 3602 else if (NewProject and cpConscripts<>0) 3603 and not ((RW[Player].Tech[adConscription]>=tsApplicable) 3604 and (RW[Player].Model[NewProject and cpIndex].Domain=dGround) 3605 and (RW[Player].Model[NewProject and cpIndex].Kind<mkScout)) then 3606 result:=eViolation 3607 // else if (RW[Player].Model[NewProject and cpIndex].Kind=mkSlaves) 3608 // and (GWonder[woPyramids].EffectiveOwner<>Player) then 3609 // result:=eNoPreq 3610 end 3611 else if NewProject and cpIndex>=nImp then 3612 result:=eInvalid 3613 else 3614 begin 3615 Preq:=Imp[NewProject and cpIndex].Preq; 3616 for i:=0 to nImpReplacement-1 do 3617 if (ImpReplacement[i].OldImp=NewProject and cpIndex) 3618 and (Built[ImpReplacement[i].NewImp]>0) then 3619 result:=eObsolete; 3620 if result=eObsolete then 3621 else if Preq=preNA then result:=eInvalid 3622 else if (Preq>=0) and (RW[Player].Tech[Preq]<tsApplicable) then 3623 result:=eNoPreq 3624 else if Built[NewProject and cpIndex]>0 then result:=eInvalid 3625 else if (NewProject and cpIndex<28) 3626 and (GWonder[NewProject and cpIndex].CityID<>-1) then 3627 result:=eViolation // wonder already exists 3628 else if (NewProject and cpIndex=imSpacePort) 3629 and (RW[Player].NatBuilt[imSpacePort]>0) then 3630 result:=eViolation // space port already exists 3631 else if (NewProject=cpImp+imBank) and (Built[imMarket]=0) 3632 or (NewProject=cpImp+imUniversity) and (Built[imLibrary]=0) 3633 or (NewProject=cpImp+imResLab) and (Built[imUniversity]=0) 3634 or (NewProject=cpImp+imMfgPlant) and (Built[imFactory]=0) then 3635 result:=eNoPreq; 3636 case NewProject-cpImp of 3637 woLighthouse,woMagellan,imCoastalFort,imHarbor,imPlatform: 3638 begin {city at ocean?} 3639 Preq:=0; 3640 V8_to_Loc(Loc,Adjacent); 3641 for V8:=0 to 7 do 3642 begin 3643 Loc1:=Adjacent[V8]; 3644 if (Loc1>=0) and (Loc1<MapSize) 3645 and (RealMap[Loc1] and fTerrain=fShore) then 3646 inc(Preq); 3647 end; 3648 if Preq=0 then result:=eNoPreq; 3649 end; 3650 woHoover,imHydro: 3651 begin {city at river or mountains?} 3652 Preq:=0; 3653 V8_to_Loc(Loc,Adjacent); 3654 for V8:=0 to 7 do 3655 begin 3656 Loc1:=Adjacent[V8]; 3657 if (Loc1>=0) and (Loc1<MapSize) 3658 and ((RealMap[Loc1] and fTerrain=fMountains) 3659 or (RealMap[Loc1] and fRiver<>0)) then inc(Preq); 3660 end; 3661 if Preq=0 then result:=eNoPreq; 3662 end; 3663 woMIR,imShipComp,imShipPow,imShipHab: 3664 if RW[Player].NatBuilt[imSpacePort]=0 then result:=eNoPreq; 3665 end; 3666 if (GTestFlags and tfNoRareNeed=0) 3667 and (Imp[NewProject and cpIndex].Kind=ikShipPart) then 3668 if RW[Player].Tech[adMassProduction]<tsApplicable then result:=eNoPreq 3669 else 3670 begin // check for rare resources 3671 if NewProject and cpIndex=imShipComp then j:=1 3672 else if NewProject and cpIndex=imShipPow then j:=2 3673 else {if NewProject and cpIndex=imShipHab then} j:=3; 3674 // j = rare resource required 3675 Preq:=0; 3676 V21_to_Loc(Loc,Radius); 3677 for V21:=1 to 26 do 3678 begin 3679 Loc1:=Radius[V21]; 3680 if (Loc1>=0) and (Loc1<MapSize) 3681 and (RealMap[Loc1] shr 25 and 3=Cardinal(j)) then 3682 inc(Preq); 3683 end; 3684 if Preq=0 then result:=eNoPreq; 3685 end 3686 end; 3687 3688 if (Command>=sExecute) and (result>=rExecuted) then 3689 begin 3690 if pt0<>ptSelect then 3691 if NewProject and (cpImp or cpIndex)=Project0 and (cpImp or cpIndex) then 3692 Prod:=Prod0 3693 else if (pt1=ptTrGoods) or (pt1=ptShip) or (pt1<>pt0) and (pt0<>ptCaravan) then 3694 begin 3695 inc(RW[Player].Money,Prod0); 3696 Prod:=0; 3697 Prod0:=0; 3698 Project0:=cpImp+imTrGoods 3699 end 3700 else Prod:=Prod0*2 div 3; 3701 Project:=NewProject 3702 end 3703 end 3704 end 3705 end; 3706 3707 sBuyCityProject,sBuyCityProject-sExecute: 3708 begin 3709 {$IFDEF TEXTLOG}CmdInfo:=Format('BuyCityProject P%d Loc%d', [Player,RW[Player].City[Subject].Loc]);{$ENDIF} 3710 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3711 result:=eInvalid 3712 else with RW[Player].City[Subject] do 3713 if (RW[Player].Government=gAnarchy) or (Flags and chCaptured<>0) then 3714 result:=eOutOfControl 3715 else if (Project and cpImp<>0) and ((Project and cpIndex=imTrGoods) 3716 or (Imp[Project and cpIndex].Kind=ikShipPart)) then 3717 result:=eInvalid // don't buy colony ship 3718 else 3719 begin 3720 CityReport.HypoTiles:=-1; 3721 CityReport.HypoTax:=-1; 3722 CityReport.HypoLux:=-1; 3723 GetCityReport(Player,Subject,CityReport); 3724 Cost:=CityReport.ProdCost; 3725 NextProd:=CityReport.ProdRep-CityReport.Support; 3726 if (CityReport.Working-CityReport.Happy>Size shr 1) or (NextProd<0) then // !!! change to new style disorder 3727 NextProd:=0; 3728 Cost:=Cost-Prod-NextProd; 3729 if (GWonder[woMich].EffectiveOwner=Player) and (Project and cpImp<>0) then 3730 Cost:=Cost*2 3731 else Cost:=Cost*4; 3732 if Cost<=0 then result:=eNotChanged 3733 else if Cost>RW[Player].Money then result:=eViolation 3734 else if Command>=sExecute then 3735 IntServer(sIntBuyMaterial, Player, Subject, Cost); 3736 // need to save material/cost because city tiles are not correct 3737 // when loading 3738 end; 3739 end; 3740 3741 sSellCityProject,sSellCityProject-sExecute: 3742 begin 3743 {$IFDEF TEXTLOG}CmdInfo:=Format('SellCityProject P%d Loc%d', [Player,RW[Player].City[Subject].Loc]);{$ENDIF} 3744 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3745 result:=eInvalid 3746 else if Command>=sExecute then 3747 with RW[Player].City[Subject] do 3748 begin inc(RW[Player].Money,Prod0); Prod:=0; Prod0:=0; end; 3749 end; 3750 3751 sSellCityImprovement,sSellCityImprovement-sExecute: 3752 begin 3753 {$IFDEF TEXTLOG}CmdInfo:=Format('SellCityImprovement P%d Loc%d: %d', [Player,RW[Player].City[Subject].Loc,integer(Data)]);{$ENDIF} 3754 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3755 result:=eInvalid 3756 else with RW[Player].City[Subject] do 3757 if Built[integer(Data)]=0 then result:=eInvalid 3758 else if (RW[Player].Government=gAnarchy) or (Flags and chCaptured<>0) then 3759 result:=eOutOfControl 3760 else if Flags and chImprovementSold<>0 then result:=eOnlyOnce 3761 else if Command>=sExecute then 3762 begin 3763 inc(RW[Player].Money, 3764 Imp[integer(Data)].Cost*BuildCostMod[Difficulty[Player]] div 12); 3765 Built[integer(Data)]:=0; 3766 if Imp[integer(Data)].Kind in [ikNatLocal,ikNatGlobal] then 3767 begin 3768 RW[Player].NatBuilt[integer(Data)]:=0; 3769 case integer(Data) of 3770 imGrWall: GrWallContinent[Player]:=-1; 3771 imSpacePort: DestroySpacePort_TellPlayers(Player,-1); 3772 end 3773 end; 3774 inc(Flags,chImprovementSold); 3775 end 3776 end; 3777 3778 sRebuildCityImprovement,sRebuildCityImprovement-sExecute: 3779 begin 3780 OldImp:=integer(Data); 3781 {$IFDEF TEXTLOG}CmdInfo:=Format('RebuildCityImprovement P%d Loc%d: %d', [Player,RW[Player].City[Subject].Loc,OldImp]);{$ENDIF} 3782 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3783 result:=eInvalid 3784 else 3785 begin 3786 if (OldImp<0) or (OldImp>=nImp) 3787 or not (Imp[OldImp].Kind in [ikCommon,ikNatLocal,ikNatGlobal]) then 3788 result:=eInvalid 3789 else with RW[Player].City[Subject] do 3790 if (Built[OldImp]=0) or (Project and cpImp=0) 3791 or not (Imp[Project and cpIndex].Kind in [ikCommon,ikNatLocal,ikNatGlobal]) then 3792 result:=eInvalid 3793 else if (RW[Player].Government=gAnarchy) or (Flags and chCaptured<>0) then 3794 result:=eOutOfControl 3795 else if Flags and chImprovementSold<>0 then result:=eOnlyOnce 3796 else if Command>=sExecute then 3797 begin 3798 inc(Prod,Imp[OldImp].Cost 3799 *BuildCostMod[Difficulty[Player]] div 12 *2 div 3); 3800 Project0:=Project0 and not cpCompleted; 3801 if Project0 and not cpAuto<>Project and not cpAuto then 3802 Project0:=Project; 3803 Prod0:=Prod; 3804 Built[OldImp]:=0; 3805 if Imp[OldImp].Kind in [ikNatLocal,ikNatGlobal] then 3806 begin // nat. project lost 3807 RW[Player].NatBuilt[OldImp]:=0; 3808 case OldImp of 3809 imGrWall: GrWallContinent[Player]:=-1; 3810 imSpacePort: DestroySpacePort_TellPlayers(Player,-1); 3811 end 3812 end; 3813 inc(Flags,chImprovementSold); 3814 end 3815 end 3816 end; 3817 3818 sSetCityTiles, sSetCityTiles-sExecute: 3819 begin 3820 {$IFDEF TEXTLOG}CmdInfo:=Format('SetCityTiles P%d Loc%d: %x', [Player,RW[Player].City[Subject].Loc,integer(data)]);{$ENDIF} 3821 if (Subject>=RW[Player].nCity) or (RW[Player].City[Subject].Loc<0) then 3822 result:=eInvalid 3823 else result:=SetCityTiles(Player, Subject, integer(Data), Command<sExecute); 3824 end; 3825 3826 { 3827 Client Exclusive Commands 3828 ____________________________________________________________________ 3829 } 3830 else 3831 if Command>=cClientEx then 3832 begin 3833 {$IFDEF TEXTLOG}CmdInfo:=Format('ClientEx%x P%d', [Command,Player]);{$ENDIF} 3834 if ProcessClientData[Player] or (Mode=moPlaying) then 3835 CallPlayer(Command,Player,Data) 3836 end 3837 else result:=eUnknown; 3838 end;{case command} 3839 3840 // do not log invalid and non-relevant commands 3841 if result=eZOC_EnemySpotted then 3842 begin 3843 assert(Mode=moPlaying); 3844 CL.State:=FormerCLState; 3845 IntServer(sIntDiscoverZOC,Player,0,ZOCTile); 3846 end 3847 else if result and rEffective=0 then 3848 if Mode<moPlaying then 3849 begin 3850 {$IFDEF TEXTLOG}CmdInfo:=Format('***ERROR (%x) ',[result])+CmdInfo;{$ENDIF} 3851 LoadOK:=false; 3852 end 3853 else 3854 begin 3855 if logged then CL.State:=FormerCLState; 3856 if (result<rExecuted) and (Command>=sExecute) then 3857 PutMessage(1 shl 16+1, Format('INVALID: %d calls %x (%d)', 3858 [Player,Command,Subject])); 3859 end; 3860 3861 if (Command and (cClientEx or sExecute or sctMask)=sExecute or sctEndClient) 3862 and (result>=rExecuted) then LastEndClientCommand:=Command; 3863 {$IFOPT O-}dec(nHandoverStack,2);{$ENDIF} 3864 end;{<<<server} 3865 4466 if (Command and (cClientEx or sExecute or sctMask) = sExecute or sctEndClient) 4467 and (result >= rExecuted) then 4468 LastEndClientCommand := Command; 4469 {$IFOPT O-}dec(nHandoverStack, 2); {$ENDIF} 4470 end; { <<<server } 3866 4471 3867 4472 initialization 4473 3868 4474 QueryPerformanceFrequency(PerfFreq); 3869 FindFirst(ParamStr(0), $21,ExeInfo);3870 3871 {$IFOPT O-}nHandoverStack :=0;{$ENDIF}4475 FindFirst(ParamStr(0), $21, ExeInfo); 4476 4477 {$IFOPT O-}nHandoverStack := 0; {$ENDIF} 3872 4478 3873 4479 end. 3874 -
trunk/Inp.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit Inp; 4 3 … … 6 5 7 6 uses 8 ScreenTools, Messg,7 ScreenTools, Messg, 9 8 10 9 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, … … 36 35 procedure TInputDlg.FormCreate(Sender: TObject); 37 36 begin 38 Canvas.Font.Assign(UniFont[ftNormal]);39 Canvas.Brush.Style:=bsClear;40 TitleHeight:=ClientHeight;41 InitButtons();42 Center:=true37 Canvas.Font.Assign(UniFont[ftNormal]); 38 Canvas.Brush.Style := bsClear; 39 TitleHeight := ClientHeight; 40 InitButtons(); 41 Center := true 43 42 end; 44 43 45 44 procedure TInputDlg.FormPaint(Sender: TObject); 46 45 begin 47 PaintBackground(self,3,3,ClientWidth-6,ClientHeight-6); 48 Frame(Canvas,0,0,ClientWidth-1,ClientHeight-1,0,0); 49 Frame(Canvas,1,1,ClientWidth-2,ClientHeight-2,MainTexture.clBevelLight, 50 MainTexture.clBevelShade); 51 Frame(Canvas,2,2,ClientWidth-3,ClientHeight-3,MainTexture.clBevelLight, 52 MainTexture.clBevelShade); 53 EditFrame(Canvas,EInput.BoundsRect,MainTexture); 54 BtnFrame(Canvas,OKBtn.BoundsRect,MainTexture); 55 RisedTextOut(Canvas,(ClientWidth-BiColorTextWidth(Canvas,Caption)) div 2,9,Caption); 56 {Corner(canvas,1,1,0,MainTexture); 57 Corner(canvas,ClientWidth-9,1,1,MainTexture); 58 Corner(canvas,1,ClientHeight-9,2,MainTexture); 59 Corner(canvas,ClientWidth-9,ClientHeight-9,3,MainTexture);} 46 PaintBackground(self, 3, 3, ClientWidth - 6, ClientHeight - 6); 47 Frame(Canvas, 0, 0, ClientWidth - 1, ClientHeight - 1, 0, 0); 48 Frame(Canvas, 1, 1, ClientWidth - 2, ClientHeight - 2, 49 MainTexture.clBevelLight, MainTexture.clBevelShade); 50 Frame(Canvas, 2, 2, ClientWidth - 3, ClientHeight - 3, 51 MainTexture.clBevelLight, MainTexture.clBevelShade); 52 EditFrame(Canvas, EInput.BoundsRect, MainTexture); 53 BtnFrame(Canvas, OKBtn.BoundsRect, MainTexture); 54 RisedTextOut(Canvas, (ClientWidth - BiColorTextWidth(Canvas, Caption)) div 2, 55 9, Caption); 56 { Corner(canvas,1,1,0,MainTexture); 57 Corner(canvas,ClientWidth-9,1,1,MainTexture); 58 Corner(canvas,1,ClientHeight-9,2,MainTexture); 59 Corner(canvas,ClientWidth-9,ClientHeight-9,3,MainTexture); } 60 60 end; 61 61 62 62 procedure TInputDlg.OKBtnClick(Sender: TObject); 63 63 begin 64 if EInput.Text='' then ModalResult:=mrCancel 65 else ModalResult:=mrOK 64 if EInput.Text = '' then 65 ModalResult := mrCancel 66 else 67 ModalResult := mrOK 66 68 end; 67 69 68 70 procedure TInputDlg.EInputKeyPress(Sender: TObject; var Key: Char); 69 71 begin 70 if (Key=#13) and (EInput.Text<>'') then begin Key:=#0 ; ModalResult:=mrOK end 71 else if Key=#27 then begin Key:=#0; ModalResult:=mrCancel end 72 if (Key = #13) and (EInput.Text <> '') then 73 begin 74 Key := #0; 75 ModalResult := mrOK 76 end 77 else if Key = #27 then 78 begin 79 Key := #0; 80 ModalResult := mrCancel 81 end 72 82 end; 73 83 74 84 procedure TInputDlg.FormShow(Sender: TObject); 75 85 begin 76 OKBtn.Caption:=Phrases.Lookup('BTN_OK'); 77 EInput.Font.Color:=MainTexture.clMark; 78 EInput.SelStart:=0; 79 EInput.SelLength:=Length(EInput.Text); 80 if Center then CenterToRect(Rect(0,0,Screen.Width,Screen.Height)); 86 OKBtn.Caption := Phrases.Lookup('BTN_OK'); 87 EInput.Font.Color := MainTexture.clMark; 88 EInput.SelStart := 0; 89 EInput.SelLength := Length(EInput.Text); 90 if Center then 91 CenterToRect(Rect(0, 0, Screen.Width, Screen.Height)); 81 92 end; 82 93 83 94 procedure TInputDlg.FormClose(Sender: TObject; var Action: TCloseAction); 84 95 begin 85 Center:=true96 Center := true 86 97 end; 87 98 88 99 procedure TInputDlg.CenterToRect(Rect: TRect); 89 100 begin 90 Center:=false;91 Left:=Rect.Left+(Rect.Right-Rect.Left-Width) div 2;92 Top:=Rect.Top+(Rect.Bottom-Rect.Top-Height) div 2;101 Center := false; 102 Left := Rect.Left + (Rect.Right - Rect.Left - Width) div 2; 103 Top := Rect.Top + (Rect.Bottom - Rect.Top - Height) div 2; 93 104 end; 94 105 95 106 end. 96 -
trunk/Integrated.dpr
r2 r6 1 1 {$INCLUDE switches} 2 3 2 program cevo; 4 3 … … 13 12 CityProcessing in 'CityProcessing.pas', 14 13 UnitProcessing in 'UnitProcessing.pas', 15 Direct in 'Direct.pas' {DirectDlg} ,14 Direct in 'Direct.pas' {DirectDlg} , 16 15 ScreenTools in 'ScreenTools.pas', 17 Start in 'Start.pas' {StartDlg} ,18 Messg in 'Messg.pas' {MessgDlg} ,19 Inp in 'Inp.pas' {InputDlg} ,20 Back in 'Back.pas' {Background} ,21 Log in 'Log.pas' {LogDlg} ,16 Start in 'Start.pas' {StartDlg} , 17 Messg in 'Messg.pas' {MessgDlg} , 18 Inp in 'Inp.pas' {InputDlg} , 19 Back in 'Back.pas' {Background} , 20 Log in 'Log.pas' {LogDlg} , 22 21 PVSB in 'LocalPlayer\PVSB.pas', 23 22 LocalPlayer in 'LocalPlayer\LocalPlayer.pas', … … 26 25 Tribes in 'LocalPlayer\Tribes.pas', 27 26 IsoEngine in 'LocalPlayer\IsoEngine.pas', 28 Term in 'LocalPlayer\Term.pas' {MainScreen} ,29 MessgEx in 'LocalPlayer\MessgEx.pas' {MessgExDlg} ,27 Term in 'LocalPlayer\Term.pas' {MainScreen} , 28 MessgEx in 'LocalPlayer\MessgEx.pas' {MessgExDlg} , 30 29 BaseWin in 'LocalPlayer\BaseWin.pas', 31 Help in 'LocalPlayer\Help.pas' {HelpDlg} ,32 Select in 'LocalPlayer\Select.pas' {ListDlg} ,33 CityScreen in 'LocalPlayer\CityScreen.pas' {CityDlg} ,34 UnitStat in 'LocalPlayer\UnitStat.pas' {UnitStatDlg} ,35 Draft in 'LocalPlayer\Draft.pas' {DraftDlg} ,36 NatStat in 'LocalPlayer\NatStat.pas' {NatStatDlg} ,37 Diagram in 'LocalPlayer\Diagram.pas' {DiaDlg} ,38 Wonders in 'LocalPlayer\Wonders.pas' {WonderDlg} ,39 Nego in 'LocalPlayer\Nego.pas' {NegoDlg} ,40 CityType in 'LocalPlayer\CityType.pas' {CityTypeDlg} ,41 Enhance in 'LocalPlayer\Enhance.pas' {EnhanceDlg} ,42 NoTerm in 'NoTerm.pas' {NoTermDlg} ,43 Sound in 'Sound.pas' {SoundPlayer} ,44 Battle in 'LocalPlayer\Battle.pas' {BattleDlg} ,45 Rates in 'LocalPlayer\Rates.pas' {RatesDlg} ,30 Help in 'LocalPlayer\Help.pas' {HelpDlg} , 31 Select in 'LocalPlayer\Select.pas' {ListDlg} , 32 CityScreen in 'LocalPlayer\CityScreen.pas' {CityDlg} , 33 UnitStat in 'LocalPlayer\UnitStat.pas' {UnitStatDlg} , 34 Draft in 'LocalPlayer\Draft.pas' {DraftDlg} , 35 NatStat in 'LocalPlayer\NatStat.pas' {NatStatDlg} , 36 Diagram in 'LocalPlayer\Diagram.pas' {DiaDlg} , 37 Wonders in 'LocalPlayer\Wonders.pas' {WonderDlg} , 38 Nego in 'LocalPlayer\Nego.pas' {NegoDlg} , 39 CityType in 'LocalPlayer\CityType.pas' {CityTypeDlg} , 40 Enhance in 'LocalPlayer\Enhance.pas' {EnhanceDlg} , 41 NoTerm in 'NoTerm.pas' {NoTermDlg} , 42 Sound in 'Sound.pas' {SoundPlayer} , 43 Battle in 'LocalPlayer\Battle.pas' {BattleDlg} , 44 Rates in 'LocalPlayer\Rates.pas' {RatesDlg} , 46 45 TechTree in 'LocalPlayer\TechTree.pas' {TechTreeDlg}; 47 46 … … 49 48 50 49 begin 51 DotNetClient :=nil;50 DotNetClient := nil; 52 51 Application.Initialize; 53 52 Application.Title := 'C-evo'; … … 59 58 Application.CreateForm(TLogDlg, LogDlg); 60 59 Application.Run; 60 61 61 end. 62 -
trunk/Integrated.dproj
r3 r6 230 230 <Platform value="Win32">True</Platform> 231 231 </Platforms> 232 <Deployment Version="2"> 233 <DeployFile LocalName="Win32\Debug\Integrated.exe" Configuration="Debug" Class="ProjectOutput"> 234 <Platform Name="Win32"> 235 <RemoteName>Integrated.exe</RemoteName> 236 <Overwrite>true</Overwrite> 237 </Platform> 238 </DeployFile> 239 <DeployClass Name="DependencyModule"> 240 <Platform Name="Win32"> 241 <Operation>0</Operation> 242 <Extensions>.dll;.bpl</Extensions> 243 </Platform> 244 <Platform Name="iOSDevice64"> 245 <Operation>1</Operation> 246 <Extensions>.dylib</Extensions> 247 </Platform> 248 <Platform Name="OSX32"> 249 <RemoteDir>Contents\MacOS</RemoteDir> 250 <Operation>1</Operation> 251 <Extensions>.dylib</Extensions> 252 </Platform> 253 <Platform Name="iOSDevice32"> 254 <Operation>1</Operation> 255 <Extensions>.dylib</Extensions> 256 </Platform> 257 <Platform Name="iOSSimulator"> 258 <Operation>1</Operation> 259 <Extensions>.dylib</Extensions> 260 </Platform> 261 </DeployClass> 262 <DeployClass Name="ProjectOSXResource"> 263 <Platform Name="OSX32"> 264 <RemoteDir>Contents\Resources</RemoteDir> 265 <Operation>1</Operation> 266 </Platform> 267 </DeployClass> 268 <DeployClass Name="AndroidClassesDexFile"> 269 <Platform Name="Android"> 270 <RemoteDir>classes</RemoteDir> 271 <Operation>1</Operation> 272 </Platform> 273 </DeployClass> 274 <DeployClass Name="AdditionalDebugSymbols"> 275 <Platform Name="Win32"> 276 <RemoteDir>Contents\MacOS</RemoteDir> 277 <Operation>0</Operation> 278 </Platform> 279 <Platform Name="iOSSimulator"> 280 <Operation>1</Operation> 281 </Platform> 282 <Platform Name="OSX32"> 283 <RemoteDir>Contents\MacOS</RemoteDir> 284 <Operation>1</Operation> 285 </Platform> 286 </DeployClass> 287 <DeployClass Name="iPad_Launch768"> 288 <Platform Name="iOSSimulator"> 289 <Operation>1</Operation> 290 </Platform> 291 <Platform Name="iOSDevice64"> 292 <Operation>1</Operation> 293 </Platform> 294 <Platform Name="iOSDevice32"> 295 <Operation>1</Operation> 296 </Platform> 297 </DeployClass> 298 <DeployClass Name="Android_LauncherIcon144"> 299 <Platform Name="Android"> 300 <RemoteDir>res\drawable-xxhdpi</RemoteDir> 301 <Operation>1</Operation> 302 </Platform> 303 </DeployClass> 304 <DeployClass Name="AndroidLibnativeMipsFile"> 305 <Platform Name="Android"> 306 <RemoteDir>library\lib\mips</RemoteDir> 307 <Operation>1</Operation> 308 </Platform> 309 </DeployClass> 310 <DeployClass Required="true" Name="ProjectOutput"> 311 <Platform Name="Win32"> 312 <Operation>0</Operation> 313 </Platform> 314 <Platform Name="iOSDevice64"> 315 <Operation>1</Operation> 316 </Platform> 317 <Platform Name="OSX32"> 318 <RemoteDir>Contents\MacOS</RemoteDir> 319 <Operation>1</Operation> 320 </Platform> 321 <Platform Name="iOSDevice32"> 322 <Operation>1</Operation> 323 </Platform> 324 <Platform Name="Android"> 325 <RemoteDir>library\lib\armeabi-v7a</RemoteDir> 326 <Operation>1</Operation> 327 </Platform> 328 <Platform Name="iOSSimulator"> 329 <Operation>1</Operation> 330 </Platform> 331 </DeployClass> 332 <DeployClass Name="DependencyFramework"> 333 <Platform Name="Win32"> 334 <Operation>0</Operation> 335 </Platform> 336 <Platform Name="OSX32"> 337 <RemoteDir>Contents\MacOS</RemoteDir> 338 <Operation>1</Operation> 339 <Extensions>.framework</Extensions> 340 </Platform> 341 </DeployClass> 342 <DeployClass Name="iPhone_Launch640"> 343 <Platform Name="iOSSimulator"> 344 <Operation>1</Operation> 345 </Platform> 346 <Platform Name="iOSDevice64"> 347 <Operation>1</Operation> 348 </Platform> 349 <Platform Name="iOSDevice32"> 350 <Operation>1</Operation> 351 </Platform> 352 </DeployClass> 353 <DeployClass Name="iPad_Launch1024"> 354 <Platform Name="iOSSimulator"> 355 <Operation>1</Operation> 356 </Platform> 357 <Platform Name="iOSDevice64"> 358 <Operation>1</Operation> 359 </Platform> 360 <Platform Name="iOSDevice32"> 361 <Operation>1</Operation> 362 </Platform> 363 </DeployClass> 364 <DeployClass Name="ProjectiOSDeviceDebug"> 365 <Platform Name="iOSDevice64"> 366 <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> 367 <Operation>1</Operation> 368 </Platform> 369 <Platform Name="iOSDevice32"> 370 <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> 371 <Operation>1</Operation> 372 </Platform> 373 </DeployClass> 374 <DeployClass Name="AndroidLibnativeX86File"> 375 <Platform Name="Android"> 376 <RemoteDir>library\lib\x86</RemoteDir> 377 <Operation>1</Operation> 378 </Platform> 379 </DeployClass> 380 <DeployClass Name="iPhone_Launch320"> 381 <Platform Name="iOSSimulator"> 382 <Operation>1</Operation> 383 </Platform> 384 <Platform Name="iOSDevice64"> 385 <Operation>1</Operation> 386 </Platform> 387 <Platform Name="iOSDevice32"> 388 <Operation>1</Operation> 389 </Platform> 390 </DeployClass> 391 <DeployClass Name="ProjectiOSInfoPList"> 392 <Platform Name="iOSSimulator"> 393 <Operation>1</Operation> 394 </Platform> 395 <Platform Name="iOSDevice64"> 396 <Operation>1</Operation> 397 </Platform> 398 <Platform Name="iOSDevice32"> 399 <Operation>1</Operation> 400 </Platform> 401 </DeployClass> 402 <DeployClass Name="AndroidLibnativeArmeabiFile"> 403 <Platform Name="Android"> 404 <RemoteDir>library\lib\armeabi</RemoteDir> 405 <Operation>1</Operation> 406 </Platform> 407 </DeployClass> 408 <DeployClass Name="DebugSymbols"> 409 <Platform Name="Win32"> 410 <Operation>0</Operation> 411 </Platform> 412 <Platform Name="iOSSimulator"> 413 <Operation>1</Operation> 414 </Platform> 415 <Platform Name="OSX32"> 416 <RemoteDir>Contents\MacOS</RemoteDir> 417 <Operation>1</Operation> 418 </Platform> 419 </DeployClass> 420 <DeployClass Name="iPad_Launch1536"> 421 <Platform Name="iOSSimulator"> 422 <Operation>1</Operation> 423 </Platform> 424 <Platform Name="iOSDevice64"> 425 <Operation>1</Operation> 426 </Platform> 427 <Platform Name="iOSDevice32"> 428 <Operation>1</Operation> 429 </Platform> 430 </DeployClass> 431 <DeployClass Name="Android_SplashImage470"> 432 <Platform Name="Android"> 433 <RemoteDir>res\drawable-normal</RemoteDir> 434 <Operation>1</Operation> 435 </Platform> 436 </DeployClass> 437 <DeployClass Name="Android_LauncherIcon96"> 438 <Platform Name="Android"> 439 <RemoteDir>res\drawable-xhdpi</RemoteDir> 440 <Operation>1</Operation> 441 </Platform> 442 </DeployClass> 443 <DeployClass Name="Android_SplashImage640"> 444 <Platform Name="Android"> 445 <RemoteDir>res\drawable-large</RemoteDir> 446 <Operation>1</Operation> 447 </Platform> 448 </DeployClass> 449 <DeployClass Name="iPhone_Launch640x1136"> 450 <Platform Name="iOSSimulator"> 451 <Operation>1</Operation> 452 </Platform> 453 <Platform Name="iOSDevice64"> 454 <Operation>1</Operation> 455 </Platform> 456 <Platform Name="iOSDevice32"> 457 <Operation>1</Operation> 458 </Platform> 459 </DeployClass> 460 <DeployClass Name="ProjectiOSEntitlements"> 461 <Platform Name="iOSDevice64"> 462 <RemoteDir>../</RemoteDir> 463 <Operation>1</Operation> 464 </Platform> 465 <Platform Name="iOSDevice32"> 466 <RemoteDir>../</RemoteDir> 467 <Operation>1</Operation> 468 </Platform> 469 </DeployClass> 470 <DeployClass Name="Android_LauncherIcon72"> 471 <Platform Name="Android"> 472 <RemoteDir>res\drawable-hdpi</RemoteDir> 473 <Operation>1</Operation> 474 </Platform> 475 </DeployClass> 476 <DeployClass Name="AndroidGDBServer"> 477 <Platform Name="Android"> 478 <RemoteDir>library\lib\armeabi-v7a</RemoteDir> 479 <Operation>1</Operation> 480 </Platform> 481 </DeployClass> 482 <DeployClass Name="ProjectOSXInfoPList"> 483 <Platform Name="OSX32"> 484 <RemoteDir>Contents</RemoteDir> 485 <Operation>1</Operation> 486 </Platform> 487 </DeployClass> 488 <DeployClass Name="ProjectOSXEntitlements"> 489 <Platform Name="OSX32"> 490 <RemoteDir>../</RemoteDir> 491 <Operation>1</Operation> 492 </Platform> 493 </DeployClass> 494 <DeployClass Name="iPad_Launch2048"> 495 <Platform Name="iOSSimulator"> 496 <Operation>1</Operation> 497 </Platform> 498 <Platform Name="iOSDevice64"> 499 <Operation>1</Operation> 500 </Platform> 501 <Platform Name="iOSDevice32"> 502 <Operation>1</Operation> 503 </Platform> 504 </DeployClass> 505 <DeployClass Name="AndroidSplashStyles"> 506 <Platform Name="Android"> 507 <RemoteDir>res\values</RemoteDir> 508 <Operation>1</Operation> 509 </Platform> 510 </DeployClass> 511 <DeployClass Name="Android_SplashImage426"> 512 <Platform Name="Android"> 513 <RemoteDir>res\drawable-small</RemoteDir> 514 <Operation>1</Operation> 515 </Platform> 516 </DeployClass> 517 <DeployClass Name="AndroidSplashImageDef"> 518 <Platform Name="Android"> 519 <RemoteDir>res\drawable</RemoteDir> 520 <Operation>1</Operation> 521 </Platform> 522 </DeployClass> 523 <DeployClass Name="ProjectiOSResource"> 524 <Platform Name="iOSSimulator"> 525 <Operation>1</Operation> 526 </Platform> 527 <Platform Name="iOSDevice64"> 528 <Operation>1</Operation> 529 </Platform> 530 <Platform Name="iOSDevice32"> 531 <Operation>1</Operation> 532 </Platform> 533 </DeployClass> 534 <DeployClass Name="ProjectAndroidManifest"> 535 <Platform Name="Android"> 536 <Operation>1</Operation> 537 </Platform> 538 </DeployClass> 539 <DeployClass Name="Android_DefaultAppIcon"> 540 <Platform Name="Android"> 541 <RemoteDir>res\drawable</RemoteDir> 542 <Operation>1</Operation> 543 </Platform> 544 </DeployClass> 545 <DeployClass Name="File"> 546 <Platform Name="Win32"> 547 <Operation>0</Operation> 548 </Platform> 549 <Platform Name="iOSDevice64"> 550 <Operation>0</Operation> 551 </Platform> 552 <Platform Name="OSX32"> 553 <RemoteDir>Contents\Resources\StartUp\</RemoteDir> 554 <Operation>0</Operation> 555 </Platform> 556 <Platform Name="iOSDevice32"> 557 <Operation>0</Operation> 558 </Platform> 559 <Platform Name="Android"> 560 <Operation>0</Operation> 561 </Platform> 562 <Platform Name="iOSSimulator"> 563 <Operation>0</Operation> 564 </Platform> 565 </DeployClass> 566 <DeployClass Name="AndroidServiceOutput"> 567 <Platform Name="Android"> 568 <RemoteDir>library\lib\armeabi-v7a</RemoteDir> 569 <Operation>1</Operation> 570 </Platform> 571 </DeployClass> 572 <DeployClass Required="true" Name="DependencyPackage"> 573 <Platform Name="Win32"> 574 <Operation>0</Operation> 575 <Extensions>.bpl</Extensions> 576 </Platform> 577 <Platform Name="iOSDevice64"> 578 <Operation>1</Operation> 579 <Extensions>.dylib</Extensions> 580 </Platform> 581 <Platform Name="OSX32"> 582 <RemoteDir>Contents\MacOS</RemoteDir> 583 <Operation>1</Operation> 584 <Extensions>.dylib</Extensions> 585 </Platform> 586 <Platform Name="iOSDevice32"> 587 <Operation>1</Operation> 588 <Extensions>.dylib</Extensions> 589 </Platform> 590 <Platform Name="iOSSimulator"> 591 <Operation>1</Operation> 592 <Extensions>.dylib</Extensions> 593 </Platform> 594 </DeployClass> 595 <DeployClass Name="Android_LauncherIcon48"> 596 <Platform Name="Android"> 597 <RemoteDir>res\drawable-mdpi</RemoteDir> 598 <Operation>1</Operation> 599 </Platform> 600 </DeployClass> 601 <DeployClass Name="Android_SplashImage960"> 602 <Platform Name="Android"> 603 <RemoteDir>res\drawable-xlarge</RemoteDir> 604 <Operation>1</Operation> 605 </Platform> 606 </DeployClass> 607 <DeployClass Name="Android_LauncherIcon36"> 608 <Platform Name="Android"> 609 <RemoteDir>res\drawable-ldpi</RemoteDir> 610 <Operation>1</Operation> 611 </Platform> 612 </DeployClass> 613 <DeployClass Name="ProjectiOSDeviceResourceRules"> 614 <Platform Name="iOSDevice64"> 615 <Operation>1</Operation> 616 </Platform> 617 <Platform Name="iOSDevice32"> 618 <Operation>1</Operation> 619 </Platform> 620 </DeployClass> 621 <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/> 622 <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/> 623 <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/> 624 <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/> 625 <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/> 626 <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/> 627 <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/> 628 </Deployment> 232 629 </BorlandProject> 233 630 <ProjectFileVersion>12</ProjectFileVersion> … … 235 632 <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> 236 633 <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> 634 <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/> 237 635 </Project> -
trunk/LocalPlayer/BaseWin.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit BaseWin; 4 3 … … 6 5 7 6 uses 8 ScreenTools, Messg,9 10 Windows, Messages,SysUtils,Classes,Graphics,Controls,Forms;7 ScreenTools, Messg, 8 9 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms; 11 10 12 11 type … … 16 15 constructor Create(AOwner: TComponent); override; 17 16 procedure FormClose(Sender: TObject; var Action: TCloseAction); 18 procedure FormPaint(Sender:TObject); 19 procedure FormKeyDown(Sender: TObject; var Key: Word; 20 Shift: TShiftState); 17 procedure FormPaint(Sender: TObject); 18 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 21 19 procedure FormDeactivate(Sender: TObject); 22 20 procedure SmartUpdateContent(ImmUpdate: boolean = false); 23 21 procedure StayOnTop_Workaround; 24 22 protected 25 FWindowMode, ModalFrameIndent: integer;23 FWindowMode, ModalFrameIndent: integer; 26 24 HelpContext: string; 27 25 procedure ShowNewContent(NewMode: integer; forceclose: boolean = false); 28 procedure MarkUsedOffscreen(xMax, yMax: integer);26 procedure MarkUsedOffscreen(xMax, yMax: integer); 29 27 procedure OffscreenPaint; virtual; 30 28 procedure VPaint; virtual; … … 33 31 end; 34 32 35 36 33 TFramedDlg = class(TBufferedDrawDlg) 37 34 public 38 35 constructor Create(AOwner: TComponent); override; 39 procedure FormCreate(Sender: TObject);36 procedure FormCreate(Sender: TObject); 40 37 procedure SmartInvalidate; override; 41 38 protected … … 44 41 procedure InitWindowRegion; 45 42 procedure VPaint; override; 46 procedure FillOffscreen(Left,Top,Width,Height: integer); 47 end; 48 43 procedure FillOffscreen(Left, Top, Width, Height: integer); 44 end; 49 45 50 46 const 51 // window modes 52 wmNone=0; wmModal=$1; wmPersistent=$2; wmSubmodal=$3; 53 54 55 yUnused=161; 56 NarrowFrame=11; WideFrame=36; SideFrame=9; 47 // window modes 48 wmNone = 0; 49 wmModal = $1; 50 wmPersistent = $2; 51 wmSubmodal = $3; 52 53 yUnused = 161; 54 NarrowFrame = 11; 55 WideFrame = 36; 56 SideFrame = 9; 57 57 58 58 var 59 UsedOffscreenWidth, UsedOffscreenHeight: integer;60 Offscreen: TBitmap;61 OffscreenUser: TForm;59 UsedOffscreenWidth, UsedOffscreenHeight: integer; 60 Offscreen: TBitmap; 61 OffscreenUser: TForm; 62 62 63 63 procedure CreateOffscreen; 64 64 65 66 65 implementation 67 66 68 67 uses 69 Term, Help, ButtonBase, Area; 70 68 Term, Help, ButtonBase, Area; 71 69 72 70 constructor TBufferedDrawDlg.Create; 73 71 begin 74 OnClose:=FormClose;75 OnPaint:=FormPaint;76 OnKeyDown:=FormKeyDown;77 OnDeactivate:=FormDeactivate;78 inherited;79 FWindowMode:=wmNone;80 HelpContext:='CONCEPTS';81 TitleHeight:=WideFrame;82 ModalFrameIndent:=45;83 UserLeft:=(Screen.Width-Width) div 2;84 UserTop:=(Screen.Height-Height) div 2;72 OnClose := FormClose; 73 OnPaint := FormPaint; 74 OnKeyDown := FormKeyDown; 75 OnDeactivate := FormDeactivate; 76 inherited; 77 FWindowMode := wmNone; 78 HelpContext := 'CONCEPTS'; 79 TitleHeight := WideFrame; 80 ModalFrameIndent := 45; 81 UserLeft := (Screen.Width - Width) div 2; 82 UserTop := (Screen.Height - Height) div 2; 85 83 end; 86 84 87 85 procedure TBufferedDrawDlg.FormClose(Sender: TObject; var Action: TCloseAction); 88 86 begin 89 if FWindowMode=wmPersistent then 90 begin UserLeft:=Left; UserTop:=Top end; 91 if OffscreenUser=self then OffscreenUser:=nil; 92 end; 93 94 procedure TBufferedDrawDlg.FormPaint(Sender:TObject); 95 begin 96 if OffscreenUser<>self then OffscreenPaint; 97 VPaint 87 if FWindowMode = wmPersistent then 88 begin 89 UserLeft := Left; 90 UserTop := Top 91 end; 92 if OffscreenUser = self then 93 OffscreenUser := nil; 94 end; 95 96 procedure TBufferedDrawDlg.FormPaint(Sender: TObject); 97 begin 98 if OffscreenUser <> self then 99 OffscreenPaint; 100 VPaint 98 101 end; 99 102 … … 101 104 Shift: TShiftState); 102 105 begin 103 if Key=VK_ESCAPE then 104 begin 105 if fsModal in FormState then ModalResult:=mrCancel 106 end 107 else if Key=VK_RETURN then 108 begin 109 if fsModal in FormState then ModalResult:=mrOK 110 end 111 else if Key=VK_F1 then 112 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkText, HelpDlg.TextIndex(HelpContext)) 113 else if FWindowMode=wmPersistent then 114 MainScreen.FormKeyDown(Sender, Key, Shift); 106 if Key = VK_ESCAPE then 107 begin 108 if fsModal in FormState then 109 ModalResult := mrCancel 110 end 111 else if Key = VK_RETURN then 112 begin 113 if fsModal in FormState then 114 ModalResult := mrOK 115 end 116 else if Key = VK_F1 then 117 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkText, 118 HelpDlg.TextIndex(HelpContext)) 119 else if FWindowMode = wmPersistent then 120 MainScreen.FormKeyDown(Sender, Key, Shift); 115 121 end; 116 122 117 123 procedure TBufferedDrawDlg.FormDeactivate(Sender: TObject); 118 124 begin 119 if FWindowMode=wmSubmodal then Close 125 if FWindowMode = wmSubmodal then 126 Close 120 127 end; 121 128 122 129 procedure TBufferedDrawDlg.OffscreenPaint; 123 130 begin 124 if (OffscreenUser<>nil) and (OffscreenUser<>self) then125 OffscreenUser.Update; // complete working with old owner to prevent rebound126 OffscreenUser:=self;131 if (OffscreenUser <> nil) and (OffscreenUser <> self) then 132 OffscreenUser.Update; // complete working with old owner to prevent rebound 133 OffscreenUser := self; 127 134 end; 128 135 129 136 procedure TBufferedDrawDlg.VPaint; 130 137 begin 131 BitBlt(Canvas.Handle, 0, 0, ClientWidth, 132 ClientHeight, offscreen.Canvas. Handle, 0, 0, SRCCOPY); 133 end; 134 135 procedure TBufferedDrawDlg.ShowNewContent(NewMode: integer; forceclose: boolean); 136 begin 137 if Visible then 138 begin 139 assert((NewMode=wmModal) or (FWindowMode<>wmModal)); // don't make modal window non-modal 140 if (NewMode=wmModal) and (forceclose or (FWindowMode<>wmModal)) then 138 BitBlt(Canvas.Handle, 0, 0, ClientWidth, ClientHeight, 139 Offscreen.Canvas.Handle, 0, 0, SRCCOPY); 140 end; 141 142 procedure TBufferedDrawDlg.ShowNewContent(NewMode: integer; 143 forceclose: boolean); 144 begin 145 if Visible then 146 begin 147 assert((NewMode = wmModal) or (FWindowMode <> wmModal)); 148 // don't make modal window non-modal 149 if (NewMode = wmModal) and (forceclose or (FWindowMode <> wmModal)) then 141 150 begin // make modal 142 UserLeft:=Left;143 UserTop:=Top;144 Visible:=false;145 FWindowMode:=NewMode;146 ShowModal;151 UserLeft := Left; 152 UserTop := Top; 153 Visible := false; 154 FWindowMode := NewMode; 155 ShowModal; 147 156 end 148 else if forceclose then157 else if forceclose then 149 158 begin // make modal 150 Visible:=false;151 FWindowMode:=NewMode;152 Left:=UserLeft;153 Top:=UserTop;154 Show;159 Visible := false; 160 FWindowMode := NewMode; 161 Left := UserLeft; 162 Top := UserTop; 163 Show; 155 164 end 156 else157 begin 158 FWindowMode:=NewMode;159 if @OnShow<>nil then160 OnShow(nil);161 Invalidate;162 BringToFront165 else 166 begin 167 FWindowMode := NewMode; 168 if @OnShow <> nil then 169 OnShow(nil); 170 Invalidate; 171 BringToFront 163 172 end 164 173 end 165 else 166 begin 167 FWindowMode:=NewMode; 168 Left:=UserLeft; 169 Top:=UserTop; 170 if FWindowMode=wmModal then ShowModal 171 else Show 174 else 175 begin 176 FWindowMode := NewMode; 177 Left := UserLeft; 178 Top := UserTop; 179 if FWindowMode = wmModal then 180 ShowModal 181 else 182 Show 172 183 end 173 184 end; … … 175 186 procedure TBufferedDrawDlg.SmartUpdateContent(ImmUpdate: boolean); 176 187 begin 177 if Visible then 178 begin 179 OffscreenPaint; 180 SmartInvalidate; 181 if ImmUpdate then Update 182 end 183 end; 184 185 procedure TBufferedDrawDlg.MarkUsedOffscreen(xMax,yMax: integer); 186 begin 187 if xMax>UsedOffscreenWidth then UsedOffscreenWidth:=xMax; 188 if yMax>UsedOffscreenHeight then UsedOffscreenHeight:=yMax; 188 if Visible then 189 begin 190 OffscreenPaint; 191 SmartInvalidate; 192 if ImmUpdate then 193 Update 194 end 195 end; 196 197 procedure TBufferedDrawDlg.MarkUsedOffscreen(xMax, yMax: integer); 198 begin 199 if xMax > UsedOffscreenWidth then 200 UsedOffscreenWidth := xMax; 201 if yMax > UsedOffscreenHeight then 202 UsedOffscreenHeight := yMax; 189 203 end; 190 204 … … 193 207 // after application lost focus, so show all stayontop-windows in first turn 194 208 var 195 SaveOnShow, SaveOnPaint: TNotifyEvent; 196 begin 197 Top:=Screen.Height; 198 SaveOnShow:=OnShow; 199 OnShow:=nil; 200 SaveOnPaint:=OnPaint; 201 OnPaint:=nil; 202 FWindowMode:=wmNone; 203 Show; 204 Hide; 205 OnShow:=SaveOnShow; 206 OnPaint:=SaveOnPaint; 207 end; 208 209 SaveOnShow, SaveOnPaint: TNotifyEvent; 210 begin 211 Top := Screen.Height; 212 SaveOnShow := OnShow; 213 OnShow := nil; 214 SaveOnPaint := OnPaint; 215 OnPaint := nil; 216 FWindowMode := wmNone; 217 Show; 218 Hide; 219 OnShow := SaveOnShow; 220 OnPaint := SaveOnPaint; 221 end; 209 222 210 223 constructor TFramedDlg.Create; 211 224 begin 212 OnCreate:=FormCreate; 213 inherited; 214 end; 215 216 procedure TFramedDlg.FormCreate(Sender:TObject); 217 begin 218 CaptionLeft:=0; CaptionRight:=$FFFF; 219 WideBottom:=false; 220 FullCaption:=true; 221 TexOverride:=false; 222 ModalIndication:=true; 223 Canvas.Brush.Style:=bsClear; 224 InnerWidth:=ClientWidth-2*SideFrame; 225 InnerHeight:=ClientHeight-TitleHeight-NarrowFrame; 225 OnCreate := FormCreate; 226 inherited; 227 end; 228 229 procedure TFramedDlg.FormCreate(Sender: TObject); 230 begin 231 CaptionLeft := 0; 232 CaptionRight := $FFFF; 233 WideBottom := false; 234 FullCaption := true; 235 TexOverride := false; 236 ModalIndication := true; 237 Canvas.Brush.Style := bsClear; 238 InnerWidth := ClientWidth - 2 * SideFrame; 239 InnerHeight := ClientHeight - TitleHeight - NarrowFrame; 226 240 end; 227 241 228 242 procedure TFramedDlg.SmartInvalidate; 229 243 var 230 i,BottomFrame: integer; 231 r0,r1: HRgn; 232 begin 233 if WideBottom then BottomFrame:=WideFrame else BottomFrame:=NarrowFrame; 234 r0:=CreateRectRgn(SideFrame,TitleHeight,ClientWidth-SideFrame, 235 ClientHeight-BottomFrame); 236 for i:=0 to ControlCount-1 do 237 if not (Controls[i] is TArea) and Controls[i].Visible then 238 begin 239 with Controls[i].BoundsRect do 240 r1:=CreateRectRgn(Left,Top,Right,Bottom); 241 CombineRgn(r0,r0,r1,RGN_DIFF); 242 DeleteObject(r1); 244 i, BottomFrame: integer; 245 r0, r1: HRgn; 246 begin 247 if WideBottom then 248 BottomFrame := WideFrame 249 else 250 BottomFrame := NarrowFrame; 251 r0 := CreateRectRgn(SideFrame, TitleHeight, ClientWidth - SideFrame, 252 ClientHeight - BottomFrame); 253 for i := 0 to ControlCount - 1 do 254 if not(Controls[i] is TArea) and Controls[i].Visible then 255 begin 256 with Controls[i].BoundsRect do 257 r1 := CreateRectRgn(Left, Top, Right, Bottom); 258 CombineRgn(r0, r0, r1, RGN_DIFF); 259 DeleteObject(r1); 243 260 end; 244 InvalidateRgn(Handle,r0,false);245 DeleteObject(r0);261 InvalidateRgn(Handle, r0, false); 262 DeleteObject(r0); 246 263 end; 247 264 248 265 procedure TFramedDlg.VPaint; 249 266 250 procedure CornerFrame(x0,y0,x1,y1: integer); 251 begin 252 Frame(Canvas,x0+1,y0+1,x1-2,y1-2,MainTexture.clBevelLight,MainTexture.clBevelShade); 253 Frame(Canvas,x0+2,y0+2,x1-3,y1-3,MainTexture.clBevelLight,MainTexture.clBevelShade); 254 Corner(Canvas,x0+1,y0+1,0,MainTexture); 255 Corner(Canvas,x1-9,y0+1,1,MainTexture); 256 Corner(Canvas,x0+1,y1-9,2,MainTexture); 257 Corner(Canvas,x1-9,y1-9,3,MainTexture); 267 procedure CornerFrame(x0, y0, x1, y1: integer); 268 begin 269 Frame(Canvas, x0 + 1, y0 + 1, x1 - 2, y1 - 2, MainTexture.clBevelLight, 270 MainTexture.clBevelShade); 271 Frame(Canvas, x0 + 2, y0 + 2, x1 - 3, y1 - 3, MainTexture.clBevelLight, 272 MainTexture.clBevelShade); 273 Corner(Canvas, x0 + 1, y0 + 1, 0, MainTexture); 274 Corner(Canvas, x1 - 9, y0 + 1, 1, MainTexture); 275 Corner(Canvas, x0 + 1, y1 - 9, 2, MainTexture); 276 Corner(Canvas, x1 - 9, y1 - 9, 3, MainTexture); 258 277 end; 259 278 260 279 var 261 i,l,FrameTop,FrameBottom,InnerBottom,Cut,xTexOffset,yTexOffset: integer; 262 R: TRect; 263 begin 264 if not TexOverride then 265 begin 266 if (FWindowMode=wmModal) and ModalIndication then MainTexture:=MainTexture 267 else MainTexture:=MainTexture; 268 MainTexture:=MainTexture 269 end; 270 Canvas.Font.Assign(UniFont[ftCaption]); 271 l:=BiColorTextWidth(Canvas,Caption); 272 Cut:=(ClientWidth-l) div 2; 273 xTexOffset:=(wMaintexture-ClientWidth) div 2; 274 yTexOffset:=(hMaintexture-ClientHeight) div 2; 275 if WideBottom then InnerBottom:=ClientHeight-WideFrame 276 else InnerBottom:=ClientHeight-NarrowFrame; 277 if FullCaption then begin FrameTop:=0; FrameBottom:=ClientHeight end 278 else 279 begin 280 FrameTop:=TitleHeight-NarrowFrame; 281 if WideBottom then FrameBottom:=ClientHeight-(WideFrame-NarrowFrame) 282 else FrameBottom:=ClientHeight 283 end; 284 Fill(Canvas,3,InnerBottom+1,ClientWidth-6,ClientHeight-InnerBottom-4, 285 xTexOffset,yTexOffset); 286 Fill(Canvas,3,TitleHeight-2,SideFrame-3,InnerBottom-TitleHeight+4, 287 xTexOffset,yTexOffset); 288 Fill(Canvas,ClientWidth-SideFrame,TitleHeight-2,SideFrame-3, 289 InnerBottom-TitleHeight+4,xTexOffset,yTexOffset); 290 Frame(Canvas,0,FrameTop,ClientWidth-1,FrameBottom-1,0,0); 291 Frame(Canvas,SideFrame-1,TitleHeight-1,ClientWidth-SideFrame, 292 InnerBottom,MainTexture.clBevelShade,MainTexture.clBevelLight); 293 //RFrame(Canvas,SideFrame-2,TitleHeight-2,ClientWidth-SideFrame+1, 294 // InnerBottom+1,MainTexture.clBevelShade,MainTexture.clBevelLight); 295 if FullCaption then 296 begin 297 if (FWindowMode<>wmModal) or not ModalIndication then 298 begin 299 Fill(Canvas,3,3+FrameTop,ClientWidth-6,TitleHeight-FrameTop-4, 300 xTexOffset,yTexOffset); 301 CornerFrame(0,FrameTop,ClientWidth,FrameBottom); 280 i, l, FrameTop, FrameBottom, InnerBottom, Cut, xTexOffset, 281 yTexOffset: integer; 282 R: TRect; 283 begin 284 if not TexOverride then 285 begin 286 if (FWindowMode = wmModal) and ModalIndication then 287 MainTexture := MainTexture 288 else 289 MainTexture := MainTexture; 290 MainTexture := MainTexture 291 end; 292 Canvas.Font.Assign(UniFont[ftCaption]); 293 l := BiColorTextWidth(Canvas, Caption); 294 Cut := (ClientWidth - l) div 2; 295 xTexOffset := (wMaintexture - ClientWidth) div 2; 296 yTexOffset := (hMaintexture - ClientHeight) div 2; 297 if WideBottom then 298 InnerBottom := ClientHeight - WideFrame 299 else 300 InnerBottom := ClientHeight - NarrowFrame; 301 if FullCaption then 302 begin 303 FrameTop := 0; 304 FrameBottom := ClientHeight 305 end 306 else 307 begin 308 FrameTop := TitleHeight - NarrowFrame; 309 if WideBottom then 310 FrameBottom := ClientHeight - (WideFrame - NarrowFrame) 311 else 312 FrameBottom := ClientHeight 313 end; 314 Fill(Canvas, 3, InnerBottom + 1, ClientWidth - 6, ClientHeight - InnerBottom - 315 4, xTexOffset, yTexOffset); 316 Fill(Canvas, 3, TitleHeight - 2, SideFrame - 3, InnerBottom - TitleHeight + 4, 317 xTexOffset, yTexOffset); 318 Fill(Canvas, ClientWidth - SideFrame, TitleHeight - 2, SideFrame - 3, 319 InnerBottom - TitleHeight + 4, xTexOffset, yTexOffset); 320 Frame(Canvas, 0, FrameTop, ClientWidth - 1, FrameBottom - 1, 0, 0); 321 Frame(Canvas, SideFrame - 1, TitleHeight - 1, ClientWidth - SideFrame, 322 InnerBottom, MainTexture.clBevelShade, MainTexture.clBevelLight); 323 // RFrame(Canvas,SideFrame-2,TitleHeight-2,ClientWidth-SideFrame+1, 324 // InnerBottom+1,MainTexture.clBevelShade,MainTexture.clBevelLight); 325 if FullCaption then 326 begin 327 if (FWindowMode <> wmModal) or not ModalIndication then 328 begin 329 Fill(Canvas, 3, 3 + FrameTop, ClientWidth - 6, TitleHeight - FrameTop - 4, 330 xTexOffset, yTexOffset); 331 CornerFrame(0, FrameTop, ClientWidth, FrameBottom); 302 332 end 303 else with Canvas do 304 begin 305 Fill(Canvas,3+ModalFrameIndent,3+FrameTop,ClientWidth-6-2*ModalFrameIndent, 306 TitleHeight-FrameTop-4,xTexOffset,yTexOffset); 307 Fill(Canvas,ClientWidth-3-ModalFrameIndent,3+FrameTop,ModalFrameIndent, 308 TitleHeight-FrameTop-4,xTexOffset,yTexOffset); 309 Fill(Canvas,3,3+FrameTop,ModalFrameIndent,TitleHeight-FrameTop-4, 310 xTexOffset,yTexOffset); 311 CornerFrame(0,FrameTop,ClientWidth,FrameBottom); 312 Pen.Color:=MainTexture.clBevelShade; 313 MoveTo(3+ModalFrameIndent,2); LineTo(3+ModalFrameIndent,TitleHeight); 314 Pen.Color:=MainTexture.clBevelShade; 315 MoveTo(4+ModalFrameIndent,TitleHeight-1); 316 LineTo(ClientWidth-4-ModalFrameIndent,TitleHeight-1); 317 LineTo(ClientWidth-4-ModalFrameIndent,1); 318 Pen.Color:=MainTexture.clBevelLight; 319 MoveTo(ClientWidth-5-ModalFrameIndent,2); 320 LineTo(4+ModalFrameIndent,2); 321 LineTo(4+ModalFrameIndent,TitleHeight); 322 MoveTo(ClientWidth-4-ModalFrameIndent,1); 323 LineTo(3+ModalFrameIndent,1); 324 Pen.Color:=MainTexture.clBevelLight; 325 MoveTo(ClientWidth-3-ModalFrameIndent,3); LineTo(ClientWidth-3-ModalFrameIndent,TitleHeight); 326 end 327 end 328 else 329 begin 330 Fill(Canvas,3,3+FrameTop,ClientWidth-6,TitleHeight-FrameTop-4, 331 xTexOffset,yTexOffset); 332 CornerFrame(0,FrameTop,ClientWidth,FrameBottom); 333 334 Frame(Canvas,CaptionLeft,0,ClientWidth-CaptionLeft-1,FrameTop,0,0); 335 Fill(Canvas,CaptionLeft+3,3,ClientWidth-2*(CaptionLeft)-6,TitleHeight-4, 336 xTexOffset,yTexOffset); 337 338 Frame(Canvas,CaptionLeft+1,0+1, 339 ClientWidth-CaptionLeft-2,TitleHeight-1,MainTexture.clBevelLight,MainTexture.clBevelShade); 340 Frame(Canvas,CaptionLeft+2,0+2, 341 ClientWidth-CaptionLeft-3,TitleHeight-1,MainTexture.clBevelLight,MainTexture.clBevelShade); 342 Corner(Canvas,CaptionLeft+1,0+1,0,MainTexture); 343 Corner(Canvas,ClientWidth-CaptionLeft-9,0+1,1,MainTexture); 344 345 with Canvas do 346 begin 347 Pen.Color:=MainTexture.clBevelShade; 348 MoveTo(CaptionLeft+1,FrameTop+2); 349 LineTo(CaptionLeft+1,TitleHeight); 350 Pen.Color:=MainTexture.clBevelLight; 351 MoveTo(ClientWidth-CaptionLeft-2,FrameTop+2); 352 LineTo(ClientWidth-CaptionLeft-2,TitleHeight); 333 else 334 with Canvas do 335 begin 336 Fill(Canvas, 3 + ModalFrameIndent, 3 + FrameTop, 337 ClientWidth - 6 - 2 * ModalFrameIndent, TitleHeight - FrameTop - 4, 338 xTexOffset, yTexOffset); 339 Fill(Canvas, ClientWidth - 3 - ModalFrameIndent, 3 + FrameTop, 340 ModalFrameIndent, TitleHeight - FrameTop - 4, xTexOffset, yTexOffset); 341 Fill(Canvas, 3, 3 + FrameTop, ModalFrameIndent, TitleHeight - FrameTop - 342 4, xTexOffset, yTexOffset); 343 CornerFrame(0, FrameTop, ClientWidth, FrameBottom); 344 Pen.Color := MainTexture.clBevelShade; 345 MoveTo(3 + ModalFrameIndent, 2); 346 LineTo(3 + ModalFrameIndent, TitleHeight); 347 Pen.Color := MainTexture.clBevelShade; 348 MoveTo(4 + ModalFrameIndent, TitleHeight - 1); 349 LineTo(ClientWidth - 4 - ModalFrameIndent, TitleHeight - 1); 350 LineTo(ClientWidth - 4 - ModalFrameIndent, 1); 351 Pen.Color := MainTexture.clBevelLight; 352 MoveTo(ClientWidth - 5 - ModalFrameIndent, 2); 353 LineTo(4 + ModalFrameIndent, 2); 354 LineTo(4 + ModalFrameIndent, TitleHeight); 355 MoveTo(ClientWidth - 4 - ModalFrameIndent, 1); 356 LineTo(3 + ModalFrameIndent, 1); 357 Pen.Color := MainTexture.clBevelLight; 358 MoveTo(ClientWidth - 3 - ModalFrameIndent, 3); 359 LineTo(ClientWidth - 3 - ModalFrameIndent, TitleHeight); 360 end 361 end 362 else 363 begin 364 Fill(Canvas, 3, 3 + FrameTop, ClientWidth - 6, TitleHeight - FrameTop - 4, 365 xTexOffset, yTexOffset); 366 CornerFrame(0, FrameTop, ClientWidth, FrameBottom); 367 368 Frame(Canvas, CaptionLeft, 0, ClientWidth - CaptionLeft - 1, 369 FrameTop, 0, 0); 370 Fill(Canvas, CaptionLeft + 3, 3, ClientWidth - 2 * (CaptionLeft) - 6, 371 TitleHeight - 4, xTexOffset, yTexOffset); 372 373 Frame(Canvas, CaptionLeft + 1, 0 + 1, ClientWidth - CaptionLeft - 2, 374 TitleHeight - 1, MainTexture.clBevelLight, MainTexture.clBevelShade); 375 Frame(Canvas, CaptionLeft + 2, 0 + 2, ClientWidth - CaptionLeft - 3, 376 TitleHeight - 1, MainTexture.clBevelLight, MainTexture.clBevelShade); 377 Corner(Canvas, CaptionLeft + 1, 0 + 1, 0, MainTexture); 378 Corner(Canvas, ClientWidth - CaptionLeft - 9, 0 + 1, 1, MainTexture); 379 380 with Canvas do 381 begin 382 Pen.Color := MainTexture.clBevelShade; 383 MoveTo(CaptionLeft + 1, FrameTop + 2); 384 LineTo(CaptionLeft + 1, TitleHeight); 385 Pen.Color := MainTexture.clBevelLight; 386 MoveTo(ClientWidth - CaptionLeft - 2, FrameTop + 2); 387 LineTo(ClientWidth - CaptionLeft - 2, TitleHeight); 353 388 end; 354 if WideBottom then 355 begin 356 Frame(Canvas,CaptionLeft,FrameBottom,ClientWidth-CaptionLeft-1,ClientHeight-1,0,0); 357 Fill(Canvas,CaptionLeft+3,ClientHeight-3-(WideFrame-5), 358 ClientWidth-2*(CaptionLeft)-6,WideFrame-5,xTexOffset,yTexOffset); 359 Frame(Canvas,CaptionLeft+1,ClientHeight-WideFrame-1+1, 360 ClientWidth-CaptionLeft-2,ClientHeight-2,MainTexture.clBevelLight,MainTexture.clBevelShade); 361 Frame(Canvas,CaptionLeft+2,ClientHeight-WideFrame-1+1, 362 ClientWidth-CaptionLeft-3,ClientHeight-3,MainTexture.clBevelLight,MainTexture.clBevelShade); 363 Corner(Canvas,CaptionLeft+1,ClientHeight-9,2,MainTexture); 364 Corner(Canvas,ClientWidth-CaptionLeft-9,ClientHeight-9,3,MainTexture); 365 366 with Canvas do 389 if WideBottom then 390 begin 391 Frame(Canvas, CaptionLeft, FrameBottom, ClientWidth - CaptionLeft - 1, 392 ClientHeight - 1, 0, 0); 393 Fill(Canvas, CaptionLeft + 3, ClientHeight - 3 - (WideFrame - 5), 394 ClientWidth - 2 * (CaptionLeft) - 6, WideFrame - 5, xTexOffset, 395 yTexOffset); 396 Frame(Canvas, CaptionLeft + 1, ClientHeight - WideFrame - 1 + 1, 397 ClientWidth - CaptionLeft - 2, ClientHeight - 2, 398 MainTexture.clBevelLight, MainTexture.clBevelShade); 399 Frame(Canvas, CaptionLeft + 2, ClientHeight - WideFrame - 1 + 1, 400 ClientWidth - CaptionLeft - 3, ClientHeight - 3, 401 MainTexture.clBevelLight, MainTexture.clBevelShade); 402 Corner(Canvas, CaptionLeft + 1, ClientHeight - 9, 2, MainTexture); 403 Corner(Canvas, ClientWidth - CaptionLeft - 9, ClientHeight - 9, 3, 404 MainTexture); 405 406 with Canvas do 367 407 begin 368 Pen.Color:=MainTexture.clBevelShade;369 MoveTo(CaptionLeft+1,ClientHeight-WideFrame);370 LineTo(CaptionLeft+1,FrameBottom-2);371 Pen.Color:=MainTexture.clBevelLight;372 MoveTo(ClientWidth-CaptionLeft-2,ClientHeight-WideFrame);373 LineTo(ClientWidth-CaptionLeft-2,FrameBottom-2);408 Pen.Color := MainTexture.clBevelShade; 409 MoveTo(CaptionLeft + 1, ClientHeight - WideFrame); 410 LineTo(CaptionLeft + 1, FrameBottom - 2); 411 Pen.Color := MainTexture.clBevelLight; 412 MoveTo(ClientWidth - CaptionLeft - 2, ClientHeight - WideFrame); 413 LineTo(ClientWidth - CaptionLeft - 2, FrameBottom - 2); 374 414 end; 375 415 end 376 416 end; 377 RisedTextOut(Canvas,Cut-1,7,Caption);378 379 for i:=0 to ControlCount-1 do380 if Controls[i].Visible and (Controls[i] is TButtonBase) then381 begin 382 R:=Controls[i].BoundsRect;383 if (R.Bottom<=TitleHeight) or (R.Top>=InnerBottom) then384 BtnFrame(Canvas,R,MainTexture);417 RisedTextOut(Canvas, Cut - 1, 7, Caption); 418 419 for i := 0 to ControlCount - 1 do 420 if Controls[i].Visible and (Controls[i] is TButtonBase) then 421 begin 422 R := Controls[i].BoundsRect; 423 if (R.Bottom <= TitleHeight) or (R.Top >= InnerBottom) then 424 BtnFrame(Canvas, R, MainTexture); 385 425 end; 386 426 387 BitBlt(Canvas.Handle,SideFrame,TitleHeight,ClientWidth-2*SideFrame,388 InnerBottom-TitleHeight,offscreen.Canvas.Handle,0,0,SRCCOPY);427 BitBlt(Canvas.Handle, SideFrame, TitleHeight, ClientWidth - 2 * SideFrame, 428 InnerBottom - TitleHeight, Offscreen.Canvas.Handle, 0, 0, SRCCOPY); 389 429 end; 390 430 391 431 procedure TFramedDlg.InitWindowRegion; 392 432 var 393 r0,r1: HRgn; 394 begin 395 if FullCaption then exit; 396 r0:=CreateRectRgn(0,0,ClientWidth,ClientHeight); 397 r1:=CreateRectRgn(0,0,CaptionLeft,TitleHeight-NarrowFrame); 398 CombineRgn(r0,r0,r1,RGN_DIFF); 399 //DeleteObject(r1); 400 r1:=CreateRectRgn(ClientWidth-CaptionLeft,0,ClientWidth,TitleHeight-NarrowFrame); 401 CombineRgn(r0,r0,r1,RGN_DIFF); 402 //DeleteObject(r1); 403 if WideBottom then 404 begin 405 r1:=CreateRectRgn(0,ClientHeight-(WideFrame-NarrowFrame),CaptionLeft, 406 ClientHeight); 407 CombineRgn(r0,r0,r1,RGN_DIFF); 408 //DeleteObject(r1); 409 r1:=CreateRectRgn(ClientWidth-CaptionLeft, 410 ClientHeight-(WideFrame-NarrowFrame),ClientWidth,ClientHeight); 411 CombineRgn(r0,r0,r1,RGN_DIFF); 412 //DeleteObject(r1); 413 end; 414 SetWindowRgn(Handle,r0,false); 415 //DeleteObject(r0); // causes crash with Windows 95 416 end; 417 418 procedure TFramedDlg.FillOffscreen(Left,Top,Width,Height: integer); 419 begin 420 Fill(Offscreen.Canvas,Left,Top,Width,Height,SideFrame+(wMaintexture-ClientWidth) div 2, 421 TitleHeight+(hMaintexture-ClientHeight) div 2); 422 end; 423 433 r0, r1: HRgn; 434 begin 435 if FullCaption then 436 exit; 437 r0 := CreateRectRgn(0, 0, ClientWidth, ClientHeight); 438 r1 := CreateRectRgn(0, 0, CaptionLeft, TitleHeight - NarrowFrame); 439 CombineRgn(r0, r0, r1, RGN_DIFF); 440 // DeleteObject(r1); 441 r1 := CreateRectRgn(ClientWidth - CaptionLeft, 0, ClientWidth, 442 TitleHeight - NarrowFrame); 443 CombineRgn(r0, r0, r1, RGN_DIFF); 444 // DeleteObject(r1); 445 if WideBottom then 446 begin 447 r1 := CreateRectRgn(0, ClientHeight - (WideFrame - NarrowFrame), 448 CaptionLeft, ClientHeight); 449 CombineRgn(r0, r0, r1, RGN_DIFF); 450 // DeleteObject(r1); 451 r1 := CreateRectRgn(ClientWidth - CaptionLeft, 452 ClientHeight - (WideFrame - NarrowFrame), ClientWidth, ClientHeight); 453 CombineRgn(r0, r0, r1, RGN_DIFF); 454 // DeleteObject(r1); 455 end; 456 SetWindowRgn(Handle, r0, false); 457 // DeleteObject(r0); // causes crash with Windows 95 458 end; 459 460 procedure TFramedDlg.FillOffscreen(Left, Top, Width, Height: integer); 461 begin 462 Fill(Offscreen.Canvas, Left, Top, Width, Height, 463 SideFrame + (wMaintexture - ClientWidth) div 2, 464 TitleHeight + (hMaintexture - ClientHeight) div 2); 465 end; 424 466 425 467 procedure CreateOffscreen; 426 468 begin 427 if OffScreen<>nil then exit; 428 offscreen:=TBitmap.Create; 429 Offscreen.PixelFormat:=pf24bit; 430 offscreen.Width:=Screen.Width; 431 if Screen.Height-yUnused<480 then offscreen.Height:=480 432 else offscreen.Height:=Screen.Height-yUnused; 433 offscreen.Canvas.Brush.Style:=bsClear; 434 end; 435 469 if Offscreen <> nil then 470 exit; 471 Offscreen := TBitmap.Create; 472 Offscreen.PixelFormat := pf24bit; 473 Offscreen.Width := Screen.Width; 474 if Screen.Height - yUnused < 480 then 475 Offscreen.Height := 480 476 else 477 Offscreen.Height := Screen.Height - yUnused; 478 Offscreen.Canvas.Brush.Style := bsClear; 479 end; 436 480 437 481 initialization 438 offscreen:=nil; 439 OffscreenUser:=nil; 482 483 Offscreen := nil; 484 OffscreenUser := nil; 440 485 441 486 finalization 442 offscreen.Free; 487 488 Offscreen.Free; 443 489 444 490 end. 445 -
trunk/LocalPlayer/Battle.pas
r2 r6 5 5 6 6 uses 7 ScreenTools, Protocol,Messg,ButtonBase, ButtonA,7 ScreenTools, Protocol, Messg, ButtonBase, ButtonA, 8 8 9 9 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms; … … 17 17 Shift: TShiftState; X, Y: Integer); 18 18 procedure FormDeactivate(Sender: TObject); 19 procedure FormKeyDown(Sender: TObject; var Key: Word; 20 Shift: TShiftState); 19 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 21 20 procedure FormCreate(Sender: TObject); 22 21 procedure FormShow(Sender: TObject); … … 24 23 procedure CancelBtnClick(Sender: TObject); 25 24 public 26 uix, ToLoc: integer;25 uix, ToLoc: Integer; 27 26 Forecast: TBattleForecastEx; 28 27 IsSuicideQuery: boolean; … … 32 31 BattleDlg: TBattleDlg; 33 32 34 procedure PaintBattleOutcome(ca: TCanvas; xm, ym,uix,ToLoc: integer;33 procedure PaintBattleOutcome(ca: TCanvas; xm, ym, uix, ToLoc: Integer; 35 34 Forecast: TBattleForecastEx); 36 35 37 38 36 implementation 39 37 40 38 uses 41 Term,ClientTools,IsoEngine;39 Term, ClientTools, IsoEngine; 42 40 43 41 {$R *.DFM} 44 42 45 43 const 46 Border=3; 47 MessageLineSpacing=20; 48 49 DamageColor=$0000E0; 50 FanaticColor=$800080; 51 FirstStrikeColor=$A0A0A0; 52 53 54 procedure PaintBattleOutcome(ca: TCanvas; xm,ym,uix,ToLoc: integer; 44 Border = 3; 45 MessageLineSpacing = 20; 46 47 DamageColor = $0000E0; 48 FanaticColor = $800080; 49 FirstStrikeColor = $A0A0A0; 50 51 procedure PaintBattleOutcome(ca: TCanvas; xm, ym, uix, ToLoc: Integer; 55 52 Forecast: TBattleForecastEx); 56 53 var 57 euix,ADamage,DDamage,StrMax,DamageMax,MaxBar,LAStr,LDStr, 58 LADamage,LDDamage,LABaseDamage,LAAvoidedDamage,LDBaseDamage: integer; 59 //TerrType: Cardinal; 60 UnitInfo: TUnitInfo; 61 TextSize: TSize; 62 LabelText: string; 63 FirstStrike: boolean; 64 begin 65 MaxBar:=65; 66 67 //TerrType:=MyMap[ToLoc] and fTerrain; 68 GetUnitInfo(ToLoc,euix,UnitInfo); 69 70 FirstStrike:=(MyModel[MyUn[uix].mix].Cap[mcFirst]>0) 71 and (Forecast.DBaseDamage>=UnitInfo.Health); 72 ADamage:=MyUn[uix].Health-Forecast.EndHealthAtt; 73 if FirstStrike then 74 ADamage:=ADamage+Forecast.ABaseDamage div 2; 75 DDamage:=UnitInfo.Health-Forecast.EndHealthDef; 76 if Forecast.AStr>Forecast.DStr then 77 StrMax:=Forecast.AStr 78 else StrMax:=Forecast.DStr; 79 if ADamage>DDamage then 80 DamageMax:=ADamage 81 else DamageMax:=DDamage; 82 if Forecast.ABaseDamage>Forecast.DBaseDamage then 83 StrMax:=StrMax*DamageMax div Forecast.ABaseDamage 84 else StrMax:=StrMax*DamageMax div Forecast.DBaseDamage; 85 86 LAStr:=Forecast.AStr*MaxBar div StrMax; 87 LDStr:=Forecast.DStr*MaxBar div StrMax; 88 LADamage:=ADamage*MaxBar div DamageMax; 89 LABaseDamage:=Forecast.ABaseDamage*MaxBar div DamageMax; 90 if FirstStrike then 91 LAAvoidedDamage:=LABaseDamage div 2 92 else LAAvoidedDamage:=0; 93 LDDamage:=DDamage*MaxBar div DamageMax; 94 LDBaseDamage:=Forecast.DBaseDamage*MaxBar div DamageMax; 95 96 DarkGradient(ca,xm-8-LAStr,ym-8,LAStr,2); 97 VDarkGradient(ca,xm-8,ym-8-LDStr,LDStr,2); 98 LightGradient(ca,xm+8,ym-8,LDBaseDamage,DamageColor); 99 if LDDamage>LDBaseDamage then 100 LightGradient(ca,xm+8+LDBaseDamage,ym-8,LDDamage-LDBaseDamage,FanaticColor); 101 if LAAvoidedDamage>0 then 102 VLightGradient(ca,xm-8,ym+8,LAAvoidedDamage,FirstStrikeColor); 103 VLightGradient(ca,xm-8,ym+8+LAAvoidedDamage,LABaseDamage-LAAvoidedDamage, 104 DamageColor); 105 if LADamage>LABaseDamage then 106 VLightGradient(ca,xm-8,ym+8+LABaseDamage,LADamage-LABaseDamage,FanaticColor); 107 BitBlt(ca.Handle,xm-12,ym-12,24,24, 108 GrExt[HGrSystem].Mask.Canvas.Handle,26,146,SRCAND); 109 BitBlt(ca.Handle,xm-12,ym-12,24,24, 110 GrExt[HGrSystem].Data.Canvas.Handle,26,146,SRCPAINT); 111 112 LabelText:=Format('%d', [Forecast.AStr]); 113 TextSize:=ca.TextExtent(LabelText); 114 if TextSize.cx div 2+2>LAStr div 2 then 115 RisedTextOut(ca,xm-10-TextSize.cx,ym-(TextSize.cy+1) div 2, LabelText) 116 else RisedTextOut(ca,xm-8-(LAStr+TextSize.cx) div 2,ym-(TextSize.cy+1) div 2, LabelText); 117 118 LabelText:=Format('%d', [Forecast.DStr]); 119 TextSize:=ca.TextExtent(LabelText); 120 if TextSize.cy div 2>LDStr div 2 then 121 RisedTextOut(ca,xm-(TextSize.cx+1) div 2, ym-8-TextSize.cy,LabelText) 122 else RisedTextOut(ca,xm-(TextSize.cx+1) div 2, ym-8-(LDStr+TextSize.cy) div 2,LabelText); 123 124 if Forecast.EndHealthDef<=0 then 125 begin 126 BitBlt(ca.Handle,xm+9+LDDamage-7,ym-6,14,17, 127 GrExt[HGrSystem].Mask.Canvas.Handle,51,153,SRCAND); 128 BitBlt(ca.Handle,xm+8+LDDamage-7,ym-7,14,17, 129 GrExt[HGrSystem].Mask.Canvas.Handle,51,153,SRCAND); 130 BitBlt(ca.Handle,xm+8+LDDamage-7,ym-7,14,17, 131 GrExt[HGrSystem].Data.Canvas.Handle,51,153,SRCPAINT); 132 end; 133 LabelText:=Format('%d', [DDamage]); 134 TextSize:=ca.TextExtent(LabelText); 135 if TextSize.cx div 2+2>LDDamage div 2 then 136 begin 137 if Forecast.EndHealthDef>0 then 138 RisedTextOut(ca,xm+10,ym-(TextSize.cy+1) div 2, LabelText) 139 end 140 else RisedTextOut(ca,xm+8+(LDDamage-TextSize.cx) div 2,ym-(TextSize.cy+1) div 2, LabelText); 141 142 if Forecast.EndHealthAtt<=0 then 143 begin 144 BitBlt(ca.Handle,xm-6,ym+9+LADamage-7,14,17, 145 GrExt[HGrSystem].Mask.Canvas.Handle,51,153,SRCAND); 146 BitBlt(ca.Handle,xm-7,ym+8+LADamage-7,14,17, 147 GrExt[HGrSystem].Mask.Canvas.Handle,51,153,SRCAND); 148 BitBlt(ca.Handle,xm-7,ym+8+LADamage-7,14,17, 149 GrExt[HGrSystem].Data.Canvas.Handle,51,153,SRCPAINT); 150 end; 151 LabelText:=Format('%d', [MyUn[uix].Health-Forecast.EndHealthAtt]); 152 TextSize:=ca.TextExtent(LabelText); 153 if TextSize.cy div 2>(LADamage-LAAvoidedDamage) div 2+LAAvoidedDamage then 154 begin 155 if Forecast.EndHealthAtt>0 then 156 RisedTextOut(ca,xm-(TextSize.cx+1) div 2, ym+8+LAAvoidedDamage,LabelText) 157 end 158 else RisedTextOut(ca,xm-(TextSize.cx+1) div 2, ym+8+LAAvoidedDamage+(LADamage-LAAvoidedDamage-TextSize.cy) div 2,LabelText); 159 160 NoMap.SetOutput(Buffer); 161 BitBlt(Buffer.Canvas.Handle,0,0,66,48,ca.Handle,xm+8+4,ym-8-12-48,SRCCOPY); 162 {if TerrType<fForest then 163 Sprite(Buffer,HGrTerrain,0,16,66,32,1+TerrType*(xxt*2+1),1+yyt) 164 else 165 begin 166 Sprite(Buffer,HGrTerrain,0,16,66,32,1+2*(xxt*2+1),1+yyt+2*(yyt*3+1)); 167 if (TerrType=fForest) and IsJungle(ToLoc div G.lx) then 54 euix, ADamage, DDamage, StrMax, DamageMax, MaxBar, LAStr, LDStr, LADamage, 55 LDDamage, LABaseDamage, LAAvoidedDamage, LDBaseDamage: Integer; 56 // TerrType: Cardinal; 57 UnitInfo: TUnitInfo; 58 TextSize: TSize; 59 LabelText: string; 60 FirstStrike: boolean; 61 begin 62 MaxBar := 65; 63 64 // TerrType:=MyMap[ToLoc] and fTerrain; 65 GetUnitInfo(ToLoc, euix, UnitInfo); 66 67 FirstStrike := (MyModel[MyUn[uix].mix].Cap[mcFirst] > 0) and 68 (Forecast.DBaseDamage >= UnitInfo.Health); 69 ADamage := MyUn[uix].Health - Forecast.EndHealthAtt; 70 if FirstStrike then 71 ADamage := ADamage + Forecast.ABaseDamage div 2; 72 DDamage := UnitInfo.Health - Forecast.EndHealthDef; 73 if Forecast.AStr > Forecast.DStr then 74 StrMax := Forecast.AStr 75 else 76 StrMax := Forecast.DStr; 77 if ADamage > DDamage then 78 DamageMax := ADamage 79 else 80 DamageMax := DDamage; 81 if Forecast.ABaseDamage > Forecast.DBaseDamage then 82 StrMax := StrMax * DamageMax div Forecast.ABaseDamage 83 else 84 StrMax := StrMax * DamageMax div Forecast.DBaseDamage; 85 86 LAStr := Forecast.AStr * MaxBar div StrMax; 87 LDStr := Forecast.DStr * MaxBar div StrMax; 88 LADamage := ADamage * MaxBar div DamageMax; 89 LABaseDamage := Forecast.ABaseDamage * MaxBar div DamageMax; 90 if FirstStrike then 91 LAAvoidedDamage := LABaseDamage div 2 92 else 93 LAAvoidedDamage := 0; 94 LDDamage := DDamage * MaxBar div DamageMax; 95 LDBaseDamage := Forecast.DBaseDamage * MaxBar div DamageMax; 96 97 DarkGradient(ca, xm - 8 - LAStr, ym - 8, LAStr, 2); 98 VDarkGradient(ca, xm - 8, ym - 8 - LDStr, LDStr, 2); 99 LightGradient(ca, xm + 8, ym - 8, LDBaseDamage, DamageColor); 100 if LDDamage > LDBaseDamage then 101 LightGradient(ca, xm + 8 + LDBaseDamage, ym - 8, LDDamage - LDBaseDamage, 102 FanaticColor); 103 if LAAvoidedDamage > 0 then 104 VLightGradient(ca, xm - 8, ym + 8, LAAvoidedDamage, FirstStrikeColor); 105 VLightGradient(ca, xm - 8, ym + 8 + LAAvoidedDamage, 106 LABaseDamage - LAAvoidedDamage, DamageColor); 107 if LADamage > LABaseDamage then 108 VLightGradient(ca, xm - 8, ym + 8 + LABaseDamage, LADamage - LABaseDamage, 109 FanaticColor); 110 BitBlt(ca.Handle, xm - 12, ym - 12, 24, 24, 111 GrExt[HGrSystem].Mask.Canvas.Handle, 26, 146, SRCAND); 112 BitBlt(ca.Handle, xm - 12, ym - 12, 24, 24, 113 GrExt[HGrSystem].Data.Canvas.Handle, 26, 146, SRCPAINT); 114 115 LabelText := Format('%d', [Forecast.AStr]); 116 TextSize := ca.TextExtent(LabelText); 117 if TextSize.cx div 2 + 2 > LAStr div 2 then 118 RisedTextOut(ca, xm - 10 - TextSize.cx, ym - (TextSize.cy + 1) div 2, 119 LabelText) 120 else 121 RisedTextOut(ca, xm - 8 - (LAStr + TextSize.cx) div 2, 122 ym - (TextSize.cy + 1) div 2, LabelText); 123 124 LabelText := Format('%d', [Forecast.DStr]); 125 TextSize := ca.TextExtent(LabelText); 126 if TextSize.cy div 2 > LDStr div 2 then 127 RisedTextOut(ca, xm - (TextSize.cx + 1) div 2, ym - 8 - TextSize.cy, 128 LabelText) 129 else 130 RisedTextOut(ca, xm - (TextSize.cx + 1) div 2, 131 ym - 8 - (LDStr + TextSize.cy) div 2, LabelText); 132 133 if Forecast.EndHealthDef <= 0 then 134 begin 135 BitBlt(ca.Handle, xm + 9 + LDDamage - 7, ym - 6, 14, 17, 136 GrExt[HGrSystem].Mask.Canvas.Handle, 51, 153, SRCAND); 137 BitBlt(ca.Handle, xm + 8 + LDDamage - 7, ym - 7, 14, 17, 138 GrExt[HGrSystem].Mask.Canvas.Handle, 51, 153, SRCAND); 139 BitBlt(ca.Handle, xm + 8 + LDDamage - 7, ym - 7, 14, 17, 140 GrExt[HGrSystem].Data.Canvas.Handle, 51, 153, SRCPAINT); 141 end; 142 LabelText := Format('%d', [DDamage]); 143 TextSize := ca.TextExtent(LabelText); 144 if TextSize.cx div 2 + 2 > LDDamage div 2 then 145 begin 146 if Forecast.EndHealthDef > 0 then 147 RisedTextOut(ca, xm + 10, ym - (TextSize.cy + 1) div 2, LabelText) 148 end 149 else 150 RisedTextOut(ca, xm + 8 + (LDDamage - TextSize.cx) div 2, 151 ym - (TextSize.cy + 1) div 2, LabelText); 152 153 if Forecast.EndHealthAtt <= 0 then 154 begin 155 BitBlt(ca.Handle, xm - 6, ym + 9 + LADamage - 7, 14, 17, 156 GrExt[HGrSystem].Mask.Canvas.Handle, 51, 153, SRCAND); 157 BitBlt(ca.Handle, xm - 7, ym + 8 + LADamage - 7, 14, 17, 158 GrExt[HGrSystem].Mask.Canvas.Handle, 51, 153, SRCAND); 159 BitBlt(ca.Handle, xm - 7, ym + 8 + LADamage - 7, 14, 17, 160 GrExt[HGrSystem].Data.Canvas.Handle, 51, 153, SRCPAINT); 161 end; 162 LabelText := Format('%d', [MyUn[uix].Health - Forecast.EndHealthAtt]); 163 TextSize := ca.TextExtent(LabelText); 164 if TextSize.cy div 2 > (LADamage - LAAvoidedDamage) div 2 + LAAvoidedDamage 165 then 166 begin 167 if Forecast.EndHealthAtt > 0 then 168 RisedTextOut(ca, xm - (TextSize.cx + 1) div 2, ym + 8 + LAAvoidedDamage, 169 LabelText) 170 end 171 else 172 RisedTextOut(ca, xm - (TextSize.cx + 1) div 2, ym + 8 + LAAvoidedDamage + 173 (LADamage - LAAvoidedDamage - TextSize.cy) div 2, LabelText); 174 175 NoMap.SetOutput(Buffer); 176 BitBlt(Buffer.Canvas.Handle, 0, 0, 66, 48, ca.Handle, xm + 8 + 4, 177 ym - 8 - 12 - 48, SRCCOPY); 178 { if TerrType<fForest then 179 Sprite(Buffer,HGrTerrain,0,16,66,32,1+TerrType*(xxt*2+1),1+yyt) 180 else 181 begin 182 Sprite(Buffer,HGrTerrain,0,16,66,32,1+2*(xxt*2+1),1+yyt+2*(yyt*3+1)); 183 if (TerrType=fForest) and IsJungle(ToLoc div G.lx) then 168 184 Sprite(Buffer,HGrTerrain,0,16,66,32,1+7*(xxt*2+1),1+yyt+19*(yyt*3+1)) 169 else Sprite(Buffer,HGrTerrain,0,16,66,32,1+7*(xxt*2+1),1+yyt+2*(2+TerrType-fForest)*(yyt*3+1)); 170 end;} 171 NoMap.PaintUnit(1,0,UnitInfo,0); 172 BitBlt(ca.Handle,xm+8+4,ym-8-12-48,66,48,Buffer.Canvas.Handle,0,0,SRCCOPY); 173 174 BitBlt(Buffer.Canvas.Handle,0,0,66,48,ca.Handle,xm-8-4-66,ym+8+12,SRCCOPY); 175 MakeUnitInfo(me,MyUn[uix],UnitInfo); 176 UnitInfo.Flags:=UnitInfo.Flags and not unFortified; 177 NoMap.PaintUnit(1,0,UnitInfo,0); 178 BitBlt(ca.Handle,xm-8-4-66,ym+8+12,66,48,Buffer.Canvas.Handle,0,0,SRCCOPY); 179 end; {PaintBattleOutcome} 180 185 else Sprite(Buffer,HGrTerrain,0,16,66,32,1+7*(xxt*2+1),1+yyt+2*(2+TerrType-fForest)*(yyt*3+1)); 186 end; } 187 NoMap.PaintUnit(1, 0, UnitInfo, 0); 188 BitBlt(ca.Handle, xm + 8 + 4, ym - 8 - 12 - 48, 66, 48, Buffer.Canvas.Handle, 189 0, 0, SRCCOPY); 190 191 BitBlt(Buffer.Canvas.Handle, 0, 0, 66, 48, ca.Handle, xm - 8 - 4 - 66, 192 ym + 8 + 12, SRCCOPY); 193 MakeUnitInfo(me, MyUn[uix], UnitInfo); 194 UnitInfo.Flags := UnitInfo.Flags and not unFortified; 195 NoMap.PaintUnit(1, 0, UnitInfo, 0); 196 BitBlt(ca.Handle, xm - 8 - 4 - 66, ym + 8 + 12, 66, 48, Buffer.Canvas.Handle, 197 0, 0, SRCCOPY); 198 end; { PaintBattleOutcome } 181 199 182 200 procedure TBattleDlg.FormCreate(Sender: TObject); 183 201 begin 184 OKBtn.Caption:=Phrases.Lookup('BTN_YES');185 CancelBtn.Caption:=Phrases.Lookup('BTN_NO');186 InitButtons();202 OKBtn.Caption := Phrases.Lookup('BTN_YES'); 203 CancelBtn.Caption := Phrases.Lookup('BTN_NO'); 204 InitButtons(); 187 205 end; 188 206 189 207 procedure TBattleDlg.FormShow(Sender: TObject); 190 208 begin 191 if IsSuicideQuery then192 begin 193 ClientWidth:=300;194 ClientHeight:=288;195 OKBtn.Visible:=true;196 CancelBtn.Visible:=true;197 Left:=(Screen.Width-ClientWidth) div 2; // center on screen198 Top:=(Screen.Height-ClientHeight) div 2;199 end 200 else201 begin 202 ClientWidth:=178;203 ClientHeight:=178;204 OKBtn.Visible:=false;205 CancelBtn.Visible:=false;209 if IsSuicideQuery then 210 begin 211 ClientWidth := 300; 212 ClientHeight := 288; 213 OKBtn.Visible := true; 214 CancelBtn.Visible := true; 215 Left := (Screen.Width - ClientWidth) div 2; // center on screen 216 Top := (Screen.Height - ClientHeight) div 2; 217 end 218 else 219 begin 220 ClientWidth := 178; 221 ClientHeight := 178; 222 OKBtn.Visible := false; 223 CancelBtn.Visible := false; 206 224 end; 207 225 end; … … 209 227 procedure TBattleDlg.FormPaint(Sender: TObject); 210 228 var 211 ym,cix,p: integer; 212 s,s1: string; 213 begin 214 with Canvas do 215 begin 216 Brush.Color:=0; 217 FillRect(Rect(0,0,ClientWidth,ClientHeight)); 218 Brush.Style:=bsClear; 219 PaintBackground(self,3+Border,3+Border,ClientWidth-(6+2*Border), 220 ClientHeight-(6+2*Border)) 221 end; 222 Frame(Canvas,Border+1,Border+1,ClientWidth-(2+Border),ClientHeight-(2+Border), 223 MainTexture.clBevelLight,MainTexture.clBevelShade); 224 Frame(Canvas,2+Border,2+Border,ClientWidth-(3+Border),ClientHeight-(3+Border), 225 MainTexture.clBevelLight,MainTexture.clBevelShade); 226 227 if IsSuicideQuery then 228 begin 229 Canvas.Font.Assign(UniFont[ftCaption]); 230 s:=Phrases.Lookup('TITLE_SUICIDE'); 231 RisedTextout(Canvas,(ClientWidth-BiColorTextWidth(Canvas,s)) div 2, 7+Border, s); 232 Canvas.Font.Assign(UniFont[ftNormal]); 233 s:=Phrases.Lookup('SUICIDE'); 234 p:=pos('\',s); 235 if p=0 then 236 RisedTextout(Canvas,(ClientWidth-BiColorTextWidth(Canvas,s)) div 2, 205, s) 237 else 229 ym, cix, p: Integer; 230 s, s1: string; 231 begin 232 with Canvas do 233 begin 234 Brush.Color := 0; 235 FillRect(Rect(0, 0, ClientWidth, ClientHeight)); 236 Brush.Style := bsClear; 237 PaintBackground(self, 3 + Border, 3 + Border, 238 ClientWidth - (6 + 2 * Border), ClientHeight - (6 + 2 * Border)) 239 end; 240 Frame(Canvas, Border + 1, Border + 1, ClientWidth - (2 + Border), 241 ClientHeight - (2 + Border), MainTexture.clBevelLight, 242 MainTexture.clBevelShade); 243 Frame(Canvas, 2 + Border, 2 + Border, ClientWidth - (3 + Border), 244 ClientHeight - (3 + Border), MainTexture.clBevelLight, 245 MainTexture.clBevelShade); 246 247 if IsSuicideQuery then 248 begin 249 Canvas.Font.Assign(UniFont[ftCaption]); 250 s := Phrases.Lookup('TITLE_SUICIDE'); 251 RisedTextOut(Canvas, (ClientWidth - BiColorTextWidth(Canvas, s)) div 2, 252 7 + Border, s); 253 Canvas.Font.Assign(UniFont[ftNormal]); 254 s := Phrases.Lookup('SUICIDE'); 255 p := pos('\', s); 256 if p = 0 then 257 RisedTextOut(Canvas, (ClientWidth - BiColorTextWidth(Canvas, s)) 258 div 2, 205, s) 259 else 238 260 begin 239 s1:=copy(s,1,p-1);240 RisedTextout(Canvas,(ClientWidth-BiColorTextWidth(Canvas,s1)) div 2,241 205-MessageLineSpacing div 2, s1);242 s1:=copy(s,p+1,255);243 RisedTextout(Canvas,(ClientWidth-BiColorTextWidth(Canvas,s1)) div 2,244 205+(MessageLineSpacing-MessageLineSpacing div 2), s1);261 s1 := copy(s, 1, p - 1); 262 RisedTextOut(Canvas, (ClientWidth - BiColorTextWidth(Canvas, s1)) div 2, 263 205 - MessageLineSpacing div 2, s1); 264 s1 := copy(s, p + 1, 255); 265 RisedTextOut(Canvas, (ClientWidth - BiColorTextWidth(Canvas, s1)) div 2, 266 205 + (MessageLineSpacing - MessageLineSpacing div 2), s1); 245 267 end; 246 ym:=110 247 end 248 else ym:=ClientHeight div 2; 249 Canvas.Font.Assign(UniFont[ftSmall]); 250 PaintBattleOutcome(Canvas, ClientWidth div 2, ym, uix, ToLoc, Forecast); 251 252 for cix:=0 to ControlCount-1 do 253 if (Controls[cix].Visible) and (Controls[cix] is TButtonBase) then 254 BtnFrame(Canvas,Controls[cix].BoundsRect,MainTexture); 268 ym := 110 269 end 270 else 271 ym := ClientHeight div 2; 272 Canvas.Font.Assign(UniFont[ftSmall]); 273 PaintBattleOutcome(Canvas, ClientWidth div 2, ym, uix, ToLoc, Forecast); 274 275 for cix := 0 to ControlCount - 1 do 276 if (Controls[cix].Visible) and (Controls[cix] is TButtonBase) then 277 BtnFrame(Canvas, Controls[cix].BoundsRect, MainTexture); 255 278 end; 256 279 … … 258 281 Shift: TShiftState; X, Y: Integer); 259 282 begin 260 if not IsSuicideQuery then261 Close;283 if not IsSuicideQuery then 284 Close; 262 285 end; 263 286 264 287 procedure TBattleDlg.FormDeactivate(Sender: TObject); 265 288 begin 266 if not IsSuicideQuery then267 Close289 if not IsSuicideQuery then 290 Close 268 291 end; 269 292 … … 271 294 Shift: TShiftState); 272 295 begin 273 if not IsSuicideQuery and (Key<>VK_SHIFT) then274 begin 275 Close;276 MainScreen.Update;277 if Key<>VK_ESCAPE then278 MainScreen.FormKeyDown(Sender, Key, Shift);296 if not IsSuicideQuery and (Key <> VK_SHIFT) then 297 begin 298 Close; 299 MainScreen.Update; 300 if Key <> VK_ESCAPE then 301 MainScreen.FormKeyDown(Sender, Key, Shift); 279 302 end 280 303 end; … … 282 305 procedure TBattleDlg.OKBtnClick(Sender: TObject); 283 306 begin 284 ModalResult:=mrOK;307 ModalResult := mrOK; 285 308 end; 286 309 287 310 procedure TBattleDlg.CancelBtnClick(Sender: TObject); 288 311 begin 289 ModalResult:=mrCancel;312 ModalResult := mrCancel; 290 313 end; 291 314 292 315 end. 293 -
trunk/LocalPlayer/CityScreen.pas
r3 r6 1 1 {$INCLUDE switches} 2 3 2 unit CityScreen; 4 3 … … 6 5 7 6 uses 8 Protocol,ClientTools,Term,ScreenTools,IsoEngine,BaseWin, 9 10 Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,ExtCtrls,ButtonA, 7 Protocol, ClientTools, Term, ScreenTools, IsoEngine, BaseWin, 8 9 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, ExtCtrls, 10 ButtonA, 11 11 ButtonB, ButtonBase, ButtonC, Area; 12 12 13 13 const 14 WM_PLAYSOUND=WM_USER;14 WM_PLAYSOUND = WM_USER; 15 15 16 16 type 17 TCityCloseAction =(None, RestoreFocus, StepFocus);17 TCityCloseAction = (None, RestoreFocus, StepFocus); 18 18 19 19 TCityDlg = class(TBufferedDrawDlg) … … 36 36 Pop1Area: TArea; 37 37 SupportArea: TArea; 38 procedure FormCreate(Sender: TObject);39 procedure FormDestroy(Sender: TObject);40 procedure FormMouseDown(Sender: TObject;Button:TMouseButton;41 Shift: TShiftState;x,y:integer);42 procedure BuyClick(Sender: TObject);43 procedure CloseBtnClick(Sender: TObject);38 procedure FormCreate(Sender: TObject); 39 procedure FormDestroy(Sender: TObject); 40 procedure FormMouseDown(Sender: TObject; Button: TMouseButton; 41 Shift: TShiftState; x, y: integer); 42 procedure BuyClick(Sender: TObject); 43 procedure CloseBtnClick(Sender: TObject); 44 44 procedure FormShow(Sender: TObject); 45 45 procedure FormClose(Sender: TObject; var Action: TCloseAction); … … 48 48 procedure NextCityBtnClick(Sender: TObject); 49 49 procedure PrevCityBtnClick(Sender: TObject); 50 procedure FormKeyDown(Sender: TObject; var Key: Word; 51 Shift: TShiftState); 52 //procedure AdviceBtnClick(Sender: TObject); 50 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 51 // procedure AdviceBtnClick(Sender: TObject); 53 52 procedure PageUpBtnClick(Sender: TObject); 54 53 procedure PageDownBtnClick(Sender: TObject); … … 58 57 CloseAction: TCityCloseAction; 59 58 procedure OffscreenPaint; override; 60 procedure ShowNewContent(NewMode, Loc: integer; ShowEvent: cardinal);59 procedure ShowNewContent(NewMode, Loc: integer; ShowEvent: cardinal); 61 60 procedure Reset; 62 61 procedure CheckAge; … … 64 63 private 65 64 c: TCity; 66 Report:TCityReportNew; 67 cOwner,cGov, 68 emix{enemy model index of produced unit}, 69 cix,cLoc,Mode,ZoomArea,Page,PageCount,BlinkTime,OpenSoundEvent, 70 SizeClass,AgePrepared: integer; 71 Optimize_cixTileChange,Optimize_TilesBeforeChange: integer; 65 Report: TCityReportNew; 66 cOwner, cGov, emix { enemy model index of produced unit } , cix, cLoc, Mode, 67 ZoomArea, Page, PageCount, BlinkTime, OpenSoundEvent, SizeClass, 68 AgePrepared: integer; 69 Optimize_cixTileChange, Optimize_TilesBeforeChange: integer; 72 70 Happened: cardinal; 73 imix: array[0..15] of integer;71 imix: array [0 .. 15] of integer; 74 72 CityAreaInfo: TCityAreaInfo; 75 73 AreaMap: TIsoMap; 76 CityMapTemplate, SmallCityMapTemplate, Back, SmallCityMap, ZoomCityMap, Template: TBitmap; 77 IsPort,ProdHint,AllowChange: boolean; 74 CityMapTemplate, SmallCityMapTemplate, Back, SmallCityMap, ZoomCityMap, 75 Template: TBitmap; 76 IsPort, ProdHint, AllowChange: boolean; 78 77 procedure InitSmallCityMap; 79 78 procedure InitZoomCityMap; … … 81 80 procedure ChangeCity(d: integer); 82 81 procedure ChangeResourceWeights(iResourceWeights: integer); 83 procedure OnPlaySound(var Msg: TMessage); message WM_PLAYSOUND;82 procedure OnPlaySound(var Msg: TMessage); message WM_PLAYSOUND; 84 83 end; 85 84 86 85 var 87 CityDlg: TCityDlg;86 CityDlg: TCityDlg; 88 87 89 88 implementation 90 89 91 90 uses 92 Select, Messg,MessgEx,Help,Inp,Tribes,Directories,91 Select, Messg, MessgEx, Help, Inp, Tribes, Directories, 93 92 94 93 Math; … … 97 96 98 97 const 99 {modes} 100 mSupp=1; mImp=2; 101 102 wBar=106; 103 xDiv=400; xService=296; 104 xmArea=197; ymArea=170; 105 xView=326; yView=275; 106 dxBar=wBar+12; dyBar=39; 107 xHapp=404; yHapp=9; 108 xFood=404; yFood=yHapp+3*dyBar+6; 109 xProd=404; yProd=yFood+3*dyBar+6; 110 xTrade=404; yTrade=yProd+2*dyBar+22; 111 xPoll=xmArea-186; yPoll=ymArea+64; 112 xmOpt=40; ymOpt=ymArea+96+34; 113 xSmallMap=271; ySmallMap=339; wSmallMap=98; hSmallMap=74; 114 xSupport=xSmallMap; ySupport=ySmallmap+hSmallmap+2; wSupport=64; hSupport=18; 115 xZoomMap=34; yZoomMap=338; wZoomMap=228; hZoomMap=124; wZoomEnvironment=68; 116 117 ImpPosition: array[28..nImp-1] of integer= 118 (-1, //imTrGoods 119 21, //imBarracks 120 6, //imGranary 121 1, //imTemple 122 7, //imMarket 123 14, //imLibrary 124 8, //imCourt 125 18, //imWalls 126 10, //imAqueduct 127 11, //imBank 128 5, //imCathedral 129 13, //imUniversity 130 29, //imHarbor 131 2, //imTheater 132 24, //imFactory 133 25, //imMfgPlant 134 28, //imRecycling 135 27, //imPower 136 27, //imHydro 137 27, //imNuclear 138 26, //imPlatform 139 8, //imTownHall 140 10, //imSewer 141 3, //imSupermarket 142 17, //imHighways 143 15, //imResLab 144 19, //imMissileBat 145 23, //imCoastalFort 146 22, //imAirport 147 20, //imDockyard 148 8, //imPalace 149 -1, //imGrWall 150 4, //imColosseum 151 16, //imObservatory 152 21, //imMilAcademy 153 -1, //imBunker 154 -1, //imAlgae 155 9, //imStockEx 156 -1, //imSpacePort 157 -1, //imShipComp 158 -1, //imShipPow 159 -1); //imShipHab 160 98 { modes } 99 mSupp = 1; 100 mImp = 2; 101 102 wBar = 106; 103 xDiv = 400; 104 xService = 296; 105 xmArea = 197; 106 ymArea = 170; 107 xView = 326; 108 yView = 275; 109 dxBar = wBar + 12; 110 dyBar = 39; 111 xHapp = 404; 112 yHapp = 9; 113 xFood = 404; 114 yFood = yHapp + 3 * dyBar + 6; 115 xProd = 404; 116 yProd = yFood + 3 * dyBar + 6; 117 xTrade = 404; 118 yTrade = yProd + 2 * dyBar + 22; 119 xPoll = xmArea - 186; 120 yPoll = ymArea + 64; 121 xmOpt = 40; 122 ymOpt = ymArea + 96 + 34; 123 xSmallMap = 271; 124 ySmallMap = 339; 125 wSmallMap = 98; 126 hSmallMap = 74; 127 xSupport = xSmallMap; 128 ySupport = ySmallMap + hSmallMap + 2; 129 wSupport = 64; 130 hSupport = 18; 131 xZoomMap = 34; 132 yZoomMap = 338; 133 wZoomMap = 228; 134 hZoomMap = 124; 135 wZoomEnvironment = 68; 136 137 ImpPosition: array [28 .. nImp - 1] of integer = (-1, // imTrGoods 138 21, // imBarracks 139 6, // imGranary 140 1, // imTemple 141 7, // imMarket 142 14, // imLibrary 143 8, // imCourt 144 18, // imWalls 145 10, // imAqueduct 146 11, // imBank 147 5, // imCathedral 148 13, // imUniversity 149 29, // imHarbor 150 2, // imTheater 151 24, // imFactory 152 25, // imMfgPlant 153 28, // imRecycling 154 27, // imPower 155 27, // imHydro 156 27, // imNuclear 157 26, // imPlatform 158 8, // imTownHall 159 10, // imSewer 160 3, // imSupermarket 161 17, // imHighways 162 15, // imResLab 163 19, // imMissileBat 164 23, // imCoastalFort 165 22, // imAirport 166 20, // imDockyard 167 8, // imPalace 168 -1, // imGrWall 169 4, // imColosseum 170 16, // imObservatory 171 21, // imMilAcademy 172 -1, // imBunker 173 -1, // imAlgae 174 9, // imStockEx 175 -1, // imSpacePort 176 -1, // imShipComp 177 -1, // imShipPow 178 -1); // imShipHab 161 179 162 180 var 163 ImpSorted: array[0..nImp-1] of integer; 164 165 166 procedure TCityDlg.FormCreate(Sender:TObject); 167 begin 168 inherited; 169 AreaMap:=TIsoMap.Create; 170 AreaMap.SetOutput(offscreen); 171 AreaMap.SetPaintBounds(xmArea-192,ymArea-96-32,xmArea+192,ymArea+96); 172 Mode:=mImp; 173 ZoomArea:=1; 174 ProdHint:=false; 175 RestoreUnFocus:=-1; 176 OpenSoundEvent:=-1; 177 AgePrepared:=-2; 178 Optimize_cixTileChange:=-1; 179 InitButtons(); 180 //InitWindowRegion; 181 CloseBtn.Caption:=Phrases.Lookup('BTN_OK'); 182 BuyBtn.Hint:=Phrases.Lookup('BTN_BUY'); 183 if not Phrases2FallenBackToEnglish then 184 SupportArea.Hint:=Phrases2.Lookup('TIP_SUPUNITS') 185 else SupportArea.Hint:=Phrases.Lookup('SUPUNITS'); 186 if not Phrases2FallenBackToEnglish then 187 begin 188 Pop0Area.Hint:=Phrases2.Lookup('TIP_WORKING'); 189 Pop1Area.Hint:=Phrases2.Lookup('TIP_CIVIL'); 190 PrimacyArea.Hint:=Phrases2.Lookup('TIP_PRIMACY'); 191 ProjectArea.Hint:=Phrases2.Lookup('TIP_PROJECT'); 192 end; 193 194 Back:=TBitmap.Create; 195 Back.PixelFormat:=pf24bit; 196 Back.Width:=ClientWidth; Back.Height:=ClientHeight; 197 Template:=TBitmap.Create; 198 LoadGraphicFile(Template, HomeDir+'Graphics\City', gfNoGamma); 199 Template.PixelFormat:=pf8bit; 200 CityMapTemplate:=TBitmap.Create; 201 LoadGraphicFile(CityMapTemplate, HomeDir+'Graphics\BigCityMap', gfNoGamma); 202 CityMapTemplate.PixelFormat:=pf8bit; 203 SmallCityMapTemplate:=TBitmap.Create; 204 LoadGraphicFile(SmallCityMapTemplate, HomeDir+'Graphics\SmallCityMap', gfNoGamma); 205 SmallCityMapTemplate.PixelFormat:=pf24bit; 206 SmallCityMap:=TBitmap.Create; 207 SmallCityMap.PixelFormat:=pf24bit; 208 SmallCityMap.Width:=98; SmallCityMap.Height:=74; 209 ZoomCityMap:=TBitmap.Create; 210 ZoomCityMap.PixelFormat:=pf24bit; 211 ZoomCityMap.Width:=228; ZoomCityMap.Height:=124; 212 end; 213 214 procedure TCityDlg.FormDestroy(Sender:TObject); 215 begin 216 AreaMap.Free; 217 SmallCityMap.Free; 218 ZoomCityMap.Free; 219 CityMapTemplate.Free; 220 Template.Free; 221 Back.Free; 181 ImpSorted: array [0 .. nImp - 1] of integer; 182 183 procedure TCityDlg.FormCreate(Sender: TObject); 184 begin 185 inherited; 186 AreaMap := TIsoMap.Create; 187 AreaMap.SetOutput(offscreen); 188 AreaMap.SetPaintBounds(xmArea - 192, ymArea - 96 - 32, xmArea + 192, 189 ymArea + 96); 190 Mode := mImp; 191 ZoomArea := 1; 192 ProdHint := false; 193 RestoreUnFocus := -1; 194 OpenSoundEvent := -1; 195 AgePrepared := -2; 196 Optimize_cixTileChange := -1; 197 InitButtons(); 198 // InitWindowRegion; 199 CloseBtn.Caption := Phrases.Lookup('BTN_OK'); 200 BuyBtn.Hint := Phrases.Lookup('BTN_BUY'); 201 if not Phrases2FallenBackToEnglish then 202 SupportArea.Hint := Phrases2.Lookup('TIP_SUPUNITS') 203 else 204 SupportArea.Hint := Phrases.Lookup('SUPUNITS'); 205 if not Phrases2FallenBackToEnglish then 206 begin 207 Pop0Area.Hint := Phrases2.Lookup('TIP_WORKING'); 208 Pop1Area.Hint := Phrases2.Lookup('TIP_CIVIL'); 209 PrimacyArea.Hint := Phrases2.Lookup('TIP_PRIMACY'); 210 ProjectArea.Hint := Phrases2.Lookup('TIP_PROJECT'); 211 end; 212 213 Back := TBitmap.Create; 214 Back.PixelFormat := pf24bit; 215 Back.Width := ClientWidth; 216 Back.Height := ClientHeight; 217 Template := TBitmap.Create; 218 LoadGraphicFile(Template, HomeDir + 'Graphics\City', gfNoGamma); 219 Template.PixelFormat := pf8bit; 220 CityMapTemplate := TBitmap.Create; 221 LoadGraphicFile(CityMapTemplate, HomeDir + 'Graphics\BigCityMap', gfNoGamma); 222 CityMapTemplate.PixelFormat := pf8bit; 223 SmallCityMapTemplate := TBitmap.Create; 224 LoadGraphicFile(SmallCityMapTemplate, HomeDir + 'Graphics\SmallCityMap', 225 gfNoGamma); 226 SmallCityMapTemplate.PixelFormat := pf24bit; 227 SmallCityMap := TBitmap.Create; 228 SmallCityMap.PixelFormat := pf24bit; 229 SmallCityMap.Width := 98; 230 SmallCityMap.Height := 74; 231 ZoomCityMap := TBitmap.Create; 232 ZoomCityMap.PixelFormat := pf24bit; 233 ZoomCityMap.Width := 228; 234 ZoomCityMap.Height := 124; 235 end; 236 237 procedure TCityDlg.FormDestroy(Sender: TObject); 238 begin 239 AreaMap.Free; 240 SmallCityMap.Free; 241 ZoomCityMap.Free; 242 CityMapTemplate.Free; 243 Template.Free; 244 Back.Free; 222 245 end; 223 246 224 247 procedure TCityDlg.Reset; 225 248 begin 226 Mode:=mImp;227 ZoomArea:=1;249 Mode := mImp; 250 ZoomArea := 1; 228 251 end; 229 252 230 253 procedure TCityDlg.CheckAge; 231 254 begin 232 if MainTextureAge<>AgePrepared then233 begin 234 AgePrepared:=MainTextureAge;235 bitblt(Back.Canvas.Handle,0,0,ClientWidth,ClientHeight,236 MainTexture.Image.Canvas.Handle,0,0,SRCCOPY);237 ImageOp_B(Back,Template,0,0,0,0,ClientWidth,ClientHeight);255 if MainTextureAge <> AgePrepared then 256 begin 257 AgePrepared := MainTextureAge; 258 bitblt(Back.Canvas.Handle, 0, 0, ClientWidth, ClientHeight, 259 MainTexture.Image.Canvas.Handle, 0, 0, SRCCOPY); 260 ImageOp_B(Back, Template, 0, 0, 0, 0, ClientWidth, ClientHeight); 238 261 end 239 262 end; 240 263 241 procedure TCityDlg.CloseBtnClick(Sender: TObject);242 begin 243 Close264 procedure TCityDlg.CloseBtnClick(Sender: TObject); 265 begin 266 Close 244 267 end; 245 268 246 269 procedure TCityDlg.InitSmallCityMap; 247 270 var 248 i,iix,cli1,Color0,Color1,Color2: integer; 249 begin 250 if cix>=0 then c:=MyCity[cix]; 251 case MyMap[cLoc] and fTerrain of 252 fPrairie: cli1:=cliPrairie; 253 fHills: cli1:=cliHills; 254 fTundra: cli1:=cliTundra; 255 else cli1:=cliPlains; 256 end; 257 Color0:=Colors.Canvas.Pixels[clkAge0+Age,cliRoad]; 258 Color1:=Colors.Canvas.Pixels[clkCity,cli1]; 259 Color2:=Colors.Canvas.Pixels[clkAge0+Age,cliHouse]; 260 BitBlt(SmallCityMap.Canvas.Handle,0,0,83,hSmallMap,SmallCityMapTemplate.Canvas.Handle,83*SizeClass,0,SRCCOPY); 261 if IsPort then 262 begin 263 BitBlt(SmallCityMap.Canvas.Handle,83,0,15,hSmallMap,SmallCityMapTemplate.Canvas.Handle,332+15,0,SRCCOPY); 264 ImageOp_CCC(SmallCityMap,0,0,83,hSmallMap,Color0,Color1,Color2); 265 Color2:=Colors.Canvas.Pixels[clkCity,cliWater]; 266 ImageOp_CCC(SmallCityMap,83,0,15,hSmallMap,Color0,Color1,Color2); 271 i, iix, cli1, Color0, Color1, Color2: integer; 272 begin 273 if cix >= 0 then 274 c := MyCity[cix]; 275 case MyMap[cLoc] and fTerrain of 276 fPrairie: 277 cli1 := cliPrairie; 278 fHills: 279 cli1 := cliHills; 280 fTundra: 281 cli1 := cliTundra; 282 else 283 cli1 := cliPlains; 284 end; 285 Color0 := Colors.Canvas.Pixels[clkAge0 + Age, cliRoad]; 286 Color1 := Colors.Canvas.Pixels[clkCity, cli1]; 287 Color2 := Colors.Canvas.Pixels[clkAge0 + Age, cliHouse]; 288 bitblt(SmallCityMap.Canvas.Handle, 0, 0, 83, hSmallMap, 289 SmallCityMapTemplate.Canvas.Handle, 83 * SizeClass, 0, SRCCOPY); 290 if IsPort then 291 begin 292 bitblt(SmallCityMap.Canvas.Handle, 83, 0, 15, hSmallMap, 293 SmallCityMapTemplate.Canvas.Handle, 332 + 15, 0, SRCCOPY); 294 ImageOp_CCC(SmallCityMap, 0, 0, 83, hSmallMap, Color0, Color1, Color2); 295 Color2 := Colors.Canvas.Pixels[clkCity, cliWater]; 296 ImageOp_CCC(SmallCityMap, 83, 0, 15, hSmallMap, Color0, Color1, Color2); 267 297 end 268 else 269 begin 270 BitBlt(SmallCityMap.Canvas.Handle,83,0,15,hSmallMap,SmallCityMapTemplate.Canvas.Handle,332,0,SRCCOPY); 271 ImageOp_CCC(SmallCityMap,0,0,wSmallMap,hSmallMap,Color0,Color1,Color2); 272 end; 273 274 with SmallCityMap.canvas do 275 begin 276 brush.Color:=Colors.Canvas.Pixels[clkAge0+Age,cliImp]; 277 for i:=0 to 29 do 278 begin 279 for iix:=28 to nImp-1 do 280 if (ImpPosition[iix]=i) and (c.Built[iix]>0) then 298 else 299 begin 300 bitblt(SmallCityMap.Canvas.Handle, 83, 0, 15, hSmallMap, 301 SmallCityMapTemplate.Canvas.Handle, 332, 0, SRCCOPY); 302 ImageOp_CCC(SmallCityMap, 0, 0, wSmallMap, hSmallMap, Color0, 303 Color1, Color2); 304 end; 305 306 with SmallCityMap.Canvas do 307 begin 308 brush.Color := Colors.Canvas.Pixels[clkAge0 + Age, cliImp]; 309 for i := 0 to 29 do 310 begin 311 for iix := 28 to nImp - 1 do 312 if (ImpPosition[iix] = i) and (c.Built[iix] > 0) then 281 313 begin 282 FillRect(Rect(5+16*(i mod 3)+48*(i div 18), 3+12*(i mod 18 div 3), 283 13+16*(i mod 3)+48*(i div 18), 11+12*(i mod 18 div 3))); 284 break; 314 FillRect(Rect(5 + 16 * (i mod 3) + 48 * (i div 18), 315 3 + 12 * (i mod 18 div 3), 13 + 16 * (i mod 3) + 48 * (i div 18), 316 11 + 12 * (i mod 18 div 3))); 317 break; 285 318 end 286 319 end; 287 i:=30;288 for iix:=0 to nImp do289 if (c.Built[iix]>0) and ((iix<28) or (ImpPosition[iix]<0)) then320 i := 30; 321 for iix := 0 to nImp do 322 if (c.Built[iix] > 0) and ((iix < 28) or (ImpPosition[iix] < 0)) then 290 323 begin 291 FillRect(Rect(5+16*(i mod 3)+48*(i div 18), 3+12*(i mod 18 div 3), 292 13+16*(i mod 3)+48*(i div 18), 11+12*(i mod 18 div 3))); 293 inc(i); 294 if i=36 then break; // area is full 324 FillRect(Rect(5 + 16 * (i mod 3) + 48 * (i div 18), 325 3 + 12 * (i mod 18 div 3), 13 + 16 * (i mod 3) + 48 * (i div 18), 326 11 + 12 * (i mod 18 div 3))); 327 inc(i); 328 if i = 36 then 329 break; // area is full 295 330 end; 296 if c.Project and cpImp<>0 then297 begin 298 iix:=c.Project and cpIndex;299 if iix<>imTrGoods then331 if c.Project and cpImp <> 0 then 332 begin 333 iix := c.Project and cpIndex; 334 if iix <> imTrGoods then 300 335 begin 301 if (iix>=28) and (ImpPosition[iix]>=0) then302 i:=ImpPosition[iix];303 if i<36 then336 if (iix >= 28) and (ImpPosition[iix] >= 0) then 337 i := ImpPosition[iix]; 338 if i < 36 then 304 339 begin 305 brush.Color:=Colors.Canvas.Pixels[clkAge0+Age,cliImpProject]; 306 FillRect(Rect(5+16*(i mod 3)+48*(i div 18), 3+12*(i mod 18 div 3), 307 13+16*(i mod 3)+48*(i div 18), 11+12*(i mod 18 div 3))); 340 brush.Color := Colors.Canvas.Pixels[clkAge0 + Age, cliImpProject]; 341 FillRect(Rect(5 + 16 * (i mod 3) + 48 * (i div 18), 342 3 + 12 * (i mod 18 div 3), 13 + 16 * (i mod 3) + 48 * (i div 18), 343 11 + 12 * (i mod 18 div 3))); 308 344 end 309 345 end 310 346 end; 311 brush.style:=bsClear;347 brush.style := bsClear; 312 348 end 313 349 end; … … 315 351 procedure TCityDlg.InitZoomCityMap; 316 352 begin 317 bitblt(ZoomCityMap.canvas.handle,0,0,wZoomMap,hZoomMap,Back.Canvas.handle, 318 xZoomMap,yZoomMap,SRCCOPY); 319 if Mode=mImp then 320 begin 321 if ZoomArea<3 then 322 ImageOp_B(ZoomCityMap,CityMapTemplate,0,0,376*SizeClass, 323 112*ZoomArea,wZoomMap,hZoomMap) 324 else 325 begin 326 ImageOp_B(ZoomCityMap,CityMapTemplate,0,0,376*SizeClass+216, 327 112*(ZoomArea-3),wZoomMap-wZoomEnvironment,hZoomMap); 328 ImageOp_B(ZoomCityMap,CityMapTemplate,wZoomMap-wZoomEnvironment,0, 329 1504+wZoomEnvironment*byte(IsPort),112*(ZoomArea-3),wZoomEnvironment,hZoomMap); 330 end; 331 end 353 bitblt(ZoomCityMap.Canvas.Handle, 0, 0, wZoomMap, hZoomMap, 354 Back.Canvas.Handle, xZoomMap, yZoomMap, SRCCOPY); 355 if Mode = mImp then 356 begin 357 if ZoomArea < 3 then 358 ImageOp_B(ZoomCityMap, CityMapTemplate, 0, 0, 376 * SizeClass, 359 112 * ZoomArea, wZoomMap, hZoomMap) 360 else 361 begin 362 ImageOp_B(ZoomCityMap, CityMapTemplate, 0, 0, 376 * SizeClass + 216, 363 112 * (ZoomArea - 3), wZoomMap - wZoomEnvironment, hZoomMap); 364 ImageOp_B(ZoomCityMap, CityMapTemplate, wZoomMap - wZoomEnvironment, 0, 365 1504 + wZoomEnvironment * byte(IsPort), 112 * (ZoomArea - 3), 366 wZoomEnvironment, hZoomMap); 367 end; 368 end 332 369 end; 333 370 334 371 procedure TCityDlg.OffscreenPaint; 335 372 336 procedure FillBar(x,y,pos,Growth,max,Kind: integer; IndicateComplete: boolean); 373 procedure FillBar(x, y, pos, Growth, max, Kind: integer; 374 IndicateComplete: boolean); 337 375 var 338 Tex: TTexture;339 begin 340 Tex:=MainTexture;341 if Kind=3 then342 begin 343 Tex.clBevelLight:=GrExt[HGrSystem].Data.Canvas.Pixels[104,36];344 Tex.clBevelShade:=Tex.clBevelLight;345 end; 346 PaintRelativeProgressBar(offscreen.Canvas,Kind,x-3,y,wBar-4,pos,Growth,max,347 IndicateComplete,Tex);348 end; 349 350 procedure PaintResources(x, y,Loc:integer; Add4Happy: boolean);376 Tex: TTexture; 377 begin 378 Tex := MainTexture; 379 if Kind = 3 then 380 begin 381 Tex.clBevelLight := GrExt[HGrSystem].Data.Canvas.Pixels[104, 36]; 382 Tex.clBevelShade := Tex.clBevelLight; 383 end; 384 PaintRelativeProgressBar(offscreen.Canvas, Kind, x - 3, y, wBar - 4, pos, 385 Growth, max, IndicateComplete, Tex); 386 end; 387 388 procedure PaintResources(x, y, Loc: integer; Add4Happy: boolean); 351 389 var 352 d,i,Total,xGr,yGr:integer; 353 TileInfo:TTileInfo; 354 rare: boolean; 355 begin 356 if Server(sGetCityTileInfo,me,Loc,TileInfo)<>eOk then 357 begin assert(cix<0); exit end; 358 Total:=TileInfo.Food+TileInfo.Prod+TileInfo.Trade; 359 rare:=MyMap[Loc] and $06000000>0; 360 if rare then 361 inc(Total); 362 if Add4Happy then 363 inc(Total,4); 364 if Total>1 then d:=(xxt-11) div (Total-1); 365 if d<1 then d:=1; 366 if d>4 then d:=4; 367 for i:=0 to Total-1 do 368 begin 369 yGr:=115; 370 if Add4Happy and (i>=Total-4) then 371 begin xGr:=132; yGr:=126 end 372 else if rare and (i=Total-1) then xGr:=66+110 373 else if i>=TileInfo.Food+TileInfo.Prod then xGr:=66+44 374 else if i>=TileInfo.Prod then xGr:=66 375 else xGr:=66+22; 376 Sprite(offscreen,HGrSystem,x+xxt-5+d*(2*i+1-Total),y+yyt-5,10,10,xGr,yGr); 390 d, i, Total, xGr, yGr: integer; 391 TileInfo: TTileInfo; 392 rare: boolean; 393 begin 394 if Server(sGetCityTileInfo, me, Loc, TileInfo) <> eOk then 395 begin 396 assert(cix < 0); 397 exit 398 end; 399 Total := TileInfo.Food + TileInfo.Prod + TileInfo.Trade; 400 rare := MyMap[Loc] and $06000000 > 0; 401 if rare then 402 inc(Total); 403 if Add4Happy then 404 inc(Total, 4); 405 if Total > 1 then 406 d := (xxt - 11) div (Total - 1); 407 if d < 1 then 408 d := 1; 409 if d > 4 then 410 d := 4; 411 for i := 0 to Total - 1 do 412 begin 413 yGr := 115; 414 if Add4Happy and (i >= Total - 4) then 415 begin 416 xGr := 132; 417 yGr := 126 418 end 419 else if rare and (i = Total - 1) then 420 xGr := 66 + 110 421 else if i >= TileInfo.Food + TileInfo.Prod then 422 xGr := 66 + 44 423 else if i >= TileInfo.Prod then 424 xGr := 66 425 else 426 xGr := 66 + 22; 427 Sprite(offscreen, HGrSystem, x + xxt - 5 + d * (2 * i + 1 - Total), 428 y + yyt - 5, 10, 10, xGr, yGr); 377 429 end 378 430 end; 379 431 380 procedure MakeRed(x, y,w,h: integer);432 procedure MakeRed(x, y, w, h: integer); 381 433 type 382 TLine=array[0..99999,0..2] of Byte;383 PLine=^TLine;434 TLine = array [0 .. 99999, 0 .. 2] of byte; 435 PLine = ^TLine; 384 436 385 437 procedure RedLine(line: PLine; length: integer); 386 438 var 387 i,gray: integer;388 begin 389 for i:=0 to length-1 do439 i, gray: integer; 440 begin 441 for i := 0 to length - 1 do 390 442 begin 391 gray:=(integer(line[i,0])+integer(line[i,1])+integer(line[i,2])) *85 shr 8; 392 line[i,0]:=0; 393 line[i,1]:=0; 394 line[i,2]:=gray; //255-(255-gray) div 2; 443 gray := (integer(line[i, 0]) + integer(line[i, 1]) + integer(line[i, 2]) 444 ) * 85 shr 8; 445 line[i, 0] := 0; 446 line[i, 1] := 0; 447 line[i, 2] := gray; // 255-(255-gray) div 2; 395 448 end 396 449 end; 397 450 398 451 var 399 i: integer;400 begin 401 for i:=0 to h-1 do402 RedLine(@(PLine(Offscreen.ScanLine[y+i])[x]),w)452 i: integer; 453 begin 454 for i := 0 to h - 1 do 455 RedLine(@(PLine(offscreen.ScanLine[y + i])[x]), w) 403 456 end; 404 457 405 458 var 406 line, MessageCount: integer;459 line, MessageCount: integer; 407 460 408 461 procedure CheckMessage(Flag: integer); 409 462 var 410 i, test: integer; 411 s: string; 412 begin 413 if Happened and Flag<>0 then 414 begin 415 i:=0; 416 test:=1; 417 while test<Flag do begin inc(i); inc(test,test) end; 418 419 if AllowChange and (Sounds<>nil) and (OpenSoundEvent=-1) then 463 i, test: integer; 464 s: string; 465 begin 466 if Happened and Flag <> 0 then 467 begin 468 i := 0; 469 test := 1; 470 while test < Flag do 420 471 begin 421 s:=CityEventSoundItem[i]; 422 if s<>'' then s:=Sounds.Lookup(s); 423 if (Flag=chProduction) or (s<>'') and (s[1]<>'*') and (s[1]<>'[') then 424 OpenSoundEvent:=i 472 inc(i); 473 inc(test, test) 425 474 end; 426 475 427 s:=CityEventName(i); 428 { if Flag=chNoGrowthWarning then 429 if c.Built[imAqueduct]=0 then 476 if AllowChange and (Sounds <> nil) and (OpenSoundEvent = -1) then 477 begin 478 s := CityEventSoundItem[i]; 479 if s <> '' then 480 s := Sounds.Lookup(s); 481 if (Flag = chProduction) or (s <> '') and (s[1] <> '*') and (s[1] <> '[') 482 then 483 OpenSoundEvent := i 484 end; 485 486 s := CityEventName(i); 487 { if Flag=chNoGrowthWarning then 488 if c.Built[imAqueduct]=0 then 430 489 s:=Format(s,[Phrases.Lookup('IMPROVEMENTS',imAqueduct)]) 431 else s:=Format(s,[Phrases.Lookup('IMPROVEMENTS',imSewer)]);} 432 RisedTextOut(offscreen.Canvas,xmOpt+40,ymOpt-1-8*MessageCount+16*line,s); 433 inc(line) 490 else s:=Format(s,[Phrases.Lookup('IMPROVEMENTS',imSewer)]); } 491 RisedTextOut(offscreen.Canvas, xmOpt + 40, ymOpt - 1 - 8 * MessageCount + 492 16 * line, s); 493 inc(line) 434 494 end 435 495 end; 436 496 437 497 var 438 x,y,xGr,i,i1,j,iix,d,dx,dy,PrCost,Cnt,Loc1,FreeSupp,Paintiix,HappyGain, 439 OptiType,rx,ry,TrueFood,TrueProd,TruePoll: integer; 440 av: Integer; 441 PrName,s:string; 442 UnitInfo: TUnitInfo; 443 UnitReport: TUnitReport; 444 RedTex: TTexture; 445 IsCityAlive,CanGrow: boolean; 446 begin 447 inherited; 448 if cix>=0 then c:=MyCity[cix]; 449 Report.HypoTiles:=-1; 450 Report.HypoTaxRate:=-1; 451 Report.HypoLuxuryRate:=-1; 452 if cix>=0 then Server(sGetCityReportNew,me,cix,Report) // own city 453 else Server(sGetEnemyCityReportNew,me,cLoc,Report); // enemy city 454 TrueFood:=c.Food; 455 TrueProd:=c.Prod; 456 TruePoll:=c.Pollution; 457 if supervising or (cix<0) then 498 x, y, xGr, i, i1, j, iix, d, dx, dy, PrCost, Cnt, Loc1, FreeSupp, Paintiix, 499 HappyGain, OptiType, rx, ry, TrueFood, TrueProd, TruePoll: integer; 500 av: integer; 501 PrName, s: string; 502 UnitInfo: TUnitInfo; 503 UnitReport: TUnitReport; 504 RedTex: TTexture; 505 IsCityAlive, CanGrow: boolean; 506 begin 507 inherited; 508 if cix >= 0 then 509 c := MyCity[cix]; 510 Report.HypoTiles := -1; 511 Report.HypoTaxRate := -1; 512 Report.HypoLuxuryRate := -1; 513 if cix >= 0 then 514 Server(sGetCityReportNew, me, cix, Report) // own city 515 else 516 Server(sGetEnemyCityReportNew, me, cLoc, Report); // enemy city 517 TrueFood := c.Food; 518 TrueProd := c.Prod; 519 TruePoll := c.Pollution; 520 if supervising or (cix < 0) then 458 521 begin // normalize city from after-turn state 459 dec(TrueFood,Report.FoodSurplus); 460 if TrueFood<0 then 461 TrueFood:=0; // shouldn't happen 462 dec(TrueProd,Report.Production); 463 if TrueProd<0 then 464 TrueProd:=0; // shouldn't happen 465 dec(TruePoll,Report.AddPollution); 466 if TruePoll<0 then 467 TruePoll:=0; // shouldn't happen 468 end; 469 IsCityAlive:= (cGov<>gAnarchy) and (c.Flags and chCaptured=0); 470 if not IsCityAlive then Report.Working:=c.Size; 471 472 RedTex:=MainTexture; 473 RedTex.clBevelLight:=$0000FF; 474 RedTex.clBevelShade:=$000000; 475 RedTex.clTextLight:=$000000; 476 RedTex.clTextShade:=$0000FF; 477 478 bitblt(offscreen.canvas.handle,0,0,640,480,Back.Canvas.handle,0,0,SRCCOPY); 479 480 offscreen.Canvas.Font.Assign(UniFont[ftCaption]); 481 RisedTextout(offscreen.Canvas,42,7,Caption); 482 with offscreen.canvas do 522 dec(TrueFood, Report.FoodSurplus); 523 if TrueFood < 0 then 524 TrueFood := 0; // shouldn't happen 525 dec(TrueProd, Report.Production); 526 if TrueProd < 0 then 527 TrueProd := 0; // shouldn't happen 528 dec(TruePoll, Report.AddPollution); 529 if TruePoll < 0 then 530 TruePoll := 0; // shouldn't happen 531 end; 532 IsCityAlive := (cGov <> gAnarchy) and (c.Flags and chCaptured = 0); 533 if not IsCityAlive then 534 Report.Working := c.Size; 535 536 RedTex := MainTexture; 537 RedTex.clBevelLight := $0000FF; 538 RedTex.clBevelShade := $000000; 539 RedTex.clTextLight := $000000; 540 RedTex.clTextShade := $0000FF; 541 542 bitblt(offscreen.Canvas.Handle, 0, 0, 640, 480, Back.Canvas.Handle, 0, 543 0, SRCCOPY); 544 545 offscreen.Canvas.Font.Assign(UniFont[ftCaption]); 546 RisedTextOut(offscreen.Canvas, 42, 7, Caption); 547 with offscreen.Canvas do 483 548 begin // city size 484 brush.color:=$000000; 485 fillrect(rect(8+1,7+1,36+1,32+1)); 486 brush.color:=$FFFFFF; 487 fillrect(rect(8,7,36,32)); 488 brush.style:=bsClear; 489 font.color:=$000000; 490 s:=inttostr(c.Size); 491 TextOut(8+14-textwidth(s) div 2, 7, s); 492 end; 493 offscreen.Canvas.Font.Assign(UniFont[ftSmall]); 494 495 if not IsCityAlive then 496 begin 497 MakeRed(18,280,298,40); 498 if cGov=gAnarchy then s:=Phrases.Lookup('GOVERNMENT',gAnarchy) 499 else {if c.Flags and chCaptured<>0 then} 500 s:=Phrases.Lookup('CITYEVENTS',14); 501 RisedTextout(offscreen.canvas,167-BiColorTextWidth(offscreen.canvas,s) div 2,ymOpt-9, s); 549 brush.Color := $000000; 550 FillRect(Rect(8 + 1, 7 + 1, 36 + 1, 32 + 1)); 551 brush.Color := $FFFFFF; 552 FillRect(Rect(8, 7, 36, 32)); 553 brush.style := bsClear; 554 Font.Color := $000000; 555 s := inttostr(c.Size); 556 TextOut(8 + 14 - textwidth(s) div 2, 7, s); 557 end; 558 offscreen.Canvas.Font.Assign(UniFont[ftSmall]); 559 560 if not IsCityAlive then 561 begin 562 MakeRed(18, 280, 298, 40); 563 if cGov = gAnarchy then 564 s := Phrases.Lookup('GOVERNMENT', gAnarchy) 565 else { if c.Flags and chCaptured<>0 then } 566 s := Phrases.Lookup('CITYEVENTS', 14); 567 RisedTextOut(offscreen.Canvas, 167 - BiColorTextWidth(offscreen.Canvas, s) 568 div 2, ymOpt - 9, s); 502 569 end 503 else if AllowChange then 504 begin 505 OptiType:=c.Status shr 4 and $0F; 506 Sprite(offscreen,HGrSystem2,xmOpt-32,ymOpt-32,64,64,1+OptiType mod 3*64,217+OptiType div 3*64); 507 508 {display messages now} 509 MessageCount:=0; 510 for i:=0 to 31 do 511 if Happened and ($FFFFFFFF-chCaptured) and (1 shl i)<>0 then 512 inc(MessageCount); 513 if MessageCount>3 then 514 MessageCount:=3; 515 if MessageCount>0 then 516 begin 517 MakeBlue(Offscreen,74,280,242,40); 518 line:=0; 519 for i:=0 to nCityEventPriority-1 do 520 if line<MessageCount then 521 CheckMessage(CityEventPriority[i]); 570 else if AllowChange then 571 begin 572 OptiType := c.Status shr 4 and $0F; 573 Sprite(offscreen, HGrSystem2, xmOpt - 32, ymOpt - 32, 64, 64, 574 1 + OptiType mod 3 * 64, 217 + OptiType div 3 * 64); 575 576 { display messages now } 577 MessageCount := 0; 578 for i := 0 to 31 do 579 if Happened and ($FFFFFFFF - chCaptured) and (1 shl i) <> 0 then 580 inc(MessageCount); 581 if MessageCount > 3 then 582 MessageCount := 3; 583 if MessageCount > 0 then 584 begin 585 MakeBlue(offscreen, 74, 280, 242, 40); 586 line := 0; 587 for i := 0 to nCityEventPriority - 1 do 588 if line < MessageCount then 589 CheckMessage(CityEventPriority[i]); 522 590 end 523 else 524 begin 525 s:=Phrases.Lookup('CITYMANAGETYPE',OptiType); 526 j:=pos('\',s); 527 if j=0 then 528 LoweredTextout(offscreen.canvas, -1, MainTexture, xmOpt+40, ymOpt-9, s) 529 else 591 else 592 begin 593 s := Phrases.Lookup('CITYMANAGETYPE', OptiType); 594 j := pos('\', s); 595 if j = 0 then 596 LoweredTextout(offscreen.Canvas, -1, MainTexture, xmOpt + 40, 597 ymOpt - 9, s) 598 else 530 599 begin 531 LoweredTextout(offscreen.canvas, -1, MainTexture, xmOpt+40, ymOpt-17,532 copy(s,1,j-1));533 LoweredTextout(offscreen.canvas, -1, MainTexture, xmOpt+40, ymOpt-1,534 copy(s,j+1,255));600 LoweredTextout(offscreen.Canvas, -1, MainTexture, xmOpt + 40, 601 ymOpt - 17, copy(s, 1, j - 1)); 602 LoweredTextout(offscreen.Canvas, -1, MainTexture, xmOpt + 40, ymOpt - 1, 603 copy(s, j + 1, 255)); 535 604 end 536 605 end 537 606 end; 538 607 539 rx:=(192+xxt*2-1) div (xxt*2); 540 ry:=(96+yyt*2-1) div (yyt*2); 541 AreaMap.Paint(xmArea-xxt*2*rx,ymArea-yyt*2*ry-3*yyt,dLoc(cLoc,-2*rx+1,-2*ry-1),4*rx-1,4*ry+1,cLoc,cOwner, 542 false,AllowChange and IsCityAlive and (c.Status and csResourceWeightsMask=0)); 543 bitblt(offscreen.canvas.handle,xmArea+102,42,90,33,Back.Canvas.handle,xmArea+102,42,SRCCOPY); 544 545 if IsCityAlive then 546 for dy:=-3 to 3 do for dx:=-3 to 3 do 547 if ((dx+dy) and 1=0) and (dx*dx*dy*dy<81) then 608 rx := (192 + xxt * 2 - 1) div (xxt * 2); 609 ry := (96 + yyt * 2 - 1) div (yyt * 2); 610 AreaMap.Paint(xmArea - xxt * 2 * rx, ymArea - yyt * 2 * ry - 3 * yyt, 611 dLoc(cLoc, -2 * rx + 1, -2 * ry - 1), 4 * rx - 1, 4 * ry + 1, cLoc, cOwner, 612 false, AllowChange and IsCityAlive and 613 (c.Status and csResourceWeightsMask = 0)); 614 bitblt(offscreen.Canvas.Handle, xmArea + 102, 42, 90, 33, Back.Canvas.Handle, 615 xmArea + 102, 42, SRCCOPY); 616 617 if IsCityAlive then 618 for dy := -3 to 3 do 619 for dx := -3 to 3 do 620 if ((dx + dy) and 1 = 0) and (dx * dx * dy * dy < 81) then 621 begin 622 Loc1 := dLoc(cLoc, dx, dy); 623 av := CityAreaInfo.Available[(dy + 3) shl 2 + (dx + 3) shr 1]; 624 if ((av = faNotAvailable) or (av = faTreaty) or (av = faInvalid)) and 625 ((Loc1 < 0) or (Loc1 >= G.lx * G.ly) or (MyMap[Loc1] and fCity = 0)) 626 then 627 Sprite(offscreen, HGrTerrain, xmArea - xxt + xxt * dx, 628 ymArea - yyt + yyt * dy, xxt * 2, yyt * 2, 1 + 5 * (xxt * 2 + 1), 629 1 + yyt + 15 * (yyt * 3 + 1)); 630 if (1 shl ((dy + 3) shl 2 + (dx + 3) shr 1) and c.Tiles <> 0) then 631 PaintResources(xmArea - xxt + xxt * dx, ymArea - yyt + yyt * dy, 632 Loc1, (dx = 0) and (dy = 0)); 633 end; 634 635 if Report.Working > 1 then 636 d := (xService - (xmArea - 192) - 8 - 32) div (Report.Working - 1); 637 if d > 28 then 638 d := 28; 639 for i := Report.Working - 1 downto 0 do 640 begin 641 if IsCityAlive then 642 xGr := 29 643 else 644 xGr := 141; 645 bitblt(offscreen.Canvas.Handle, xmArea - 192 + 5 + i * d, ymArea - 96 - 29, 646 27, 30, GrExt[HGrSystem].Mask.Canvas.Handle, xGr, 171, SRCAND); { shadow } 647 Sprite(offscreen, HGrSystem, xmArea - 192 + 4 + i * d, ymArea - 96 - 30, 27, 648 30, xGr, 171); 649 end; 650 if c.Size - Report.Working > 1 then 651 d := (xmArea + 192 - xService - 32) div (c.Size - Report.Working - 1); 652 if d > 28 then 653 d := 28; 654 for i := 0 to c.Size - Report.Working - 1 do 655 begin 656 xGr := 1 + 112; 657 bitblt(offscreen.Canvas.Handle, xmArea + 192 - 27 + 1 - i * d, 29 + 1, 27, 658 30, GrExt[HGrSystem].Mask.Canvas.Handle, xGr, 171, SRCAND); { shadow } 659 Sprite(offscreen, HGrSystem, xmArea + 192 - 27 - i * d, 29, 27, 30, 660 xGr, 171); 661 Sprite(offscreen, HGrSystem, xmArea + 192 - 27 + 4 - i * d, 29 + 32, 10, 662 10, 121, 126); 663 Sprite(offscreen, HGrSystem, xmArea + 192 - 27 + 13 - i * d, 29 + 32, 10, 664 10, 121, 126); 665 // Sprite(offscreen,HGrSystem,xmArea+192-31+18-i*d,ymArea-96-80+32,10,10,88,115); 666 end; 667 668 if c.Project and cpImp = 0 then 669 PrName := Tribe[cOwner].ModelName[c.Project and cpIndex] 670 else 671 PrName := Phrases.Lookup('IMPROVEMENTS', c.Project and cpIndex); 672 PrCost := Report.ProjectCost; 673 674 // happiness section 675 if IsCityAlive then 676 begin 677 if cGov = gFundamentalism then 678 CountBar(offscreen, xHapp, yHapp + dyBar, wBar, 17, 679 Phrases.Lookup('FAITH'), Report.CollectedControl, MainTexture) 680 else 681 begin 682 CountBar(offscreen, xHapp, yHapp + dyBar, wBar, 17, 683 Phrases.Lookup('HAPPINESS'), Report.Morale, MainTexture); 684 CountBar(offscreen, xHapp, yHapp + 2 * dyBar, wBar, 16, 685 Phrases.Lookup('CONTROL'), Report.CollectedControl, MainTexture); 686 end; 687 CountBar(offscreen, xHapp, yHapp, wBar, 8, Phrases.Lookup('LUX'), 688 Report.Luxury, MainTexture); 689 CountBar(offscreen, xHapp + dxBar, yHapp, wBar, 19, 690 Phrases.Lookup('UNREST'), 2 * Report.Deployed, MainTexture); 691 CountBar(offscreen, xHapp + dxBar, yHapp + dyBar, wBar, 17, 692 Phrases.Lookup('HAPPINESSDEMAND'), c.Size, MainTexture); 693 if Report.HappinessBalance >= 0 then 694 CountBar(offscreen, xHapp + dxBar, yHapp + 2 * dyBar, wBar, 17, 695 Phrases.Lookup('HAPPINESSPLUS'), Report.HappinessBalance, MainTexture) 696 else 697 begin 698 MakeRed(xHapp + dxBar - 6, yHapp + 2 * dyBar, wBar + 10, 38); 699 CountBar(offscreen, xHapp + dxBar, yHapp + 2 * dyBar, wBar, 18, 700 Phrases.Lookup('LACK'), -Report.HappinessBalance, RedTex); 701 end; 702 end; 703 704 // food section 705 if IsCityAlive then 706 begin 707 CountBar(offscreen, xFood, yFood + dyBar div 2, wBar, 0, 708 Phrases.Lookup('FOOD'), Report.CollectedFood, MainTexture); 709 CountBar(offscreen, xFood + dxBar, yFood + dyBar, wBar, 0, 710 Phrases.Lookup('DEMAND'), 2 * c.Size, MainTexture); 711 CountBar(offscreen, xFood + dxBar, yFood, wBar, 0, 712 Phrases.Lookup('SUPPORT'), Report.FoodSupport, MainTexture); 713 if Report.FoodSurplus >= 0 then 714 if (cGov = gFuture) or (c.Size >= NeedAqueductSize) and 715 (Report.FoodSurplus < 2) then 716 CountBar(offscreen, xFood + dxBar, yFood + 2 * dyBar, wBar, 6, 717 Phrases.Lookup('PROFIT'), Report.FoodSurplus, MainTexture) 718 else 719 CountBar(offscreen, xFood + dxBar, yFood + 2 * dyBar, wBar, 0, 720 Phrases.Lookup('SURPLUS'), Report.FoodSurplus, MainTexture) 721 else 722 begin 723 MakeRed(xFood + dxBar - 6, yFood + 2 * dyBar, wBar + 10, 38); 724 CountBar(offscreen, xFood + dxBar, yFood + 2 * dyBar, wBar, 1, 725 Phrases.Lookup('LACK'), -Report.FoodSurplus, RedTex); 726 end; 727 end; 728 CanGrow := (c.Size < MaxCitySize) and (cGov <> gFuture) and 729 (Report.FoodSurplus > 0) and ((c.Size < NeedAqueductSize) or 730 (c.Built[imAqueduct] = 1) and (c.Size < NeedSewerSize) or 731 (c.Built[imSewer] = 1)); 732 FillBar(xFood + 3, yFood + 102, TrueFood, 733 CutCityFoodSurplus(Report.FoodSurplus, IsCityAlive, cGov, c.Size), 734 Report.Storage, 1, CanGrow); 735 LoweredTextout(offscreen.Canvas, -1, MainTexture, xFood + 3 - 5, 736 yFood + 102 - 20, Format('%d/%d', [TrueFood, Report.Storage])); 737 LoweredTextout(offscreen.Canvas, -1, MainTexture, xFood - 2, yFood + 66, 738 Phrases.Lookup('STORAGE')); 739 740 // production section 741 if IsCityAlive then 742 begin 743 CountBar(offscreen, xProd, yProd, wBar, 2, Phrases.Lookup('MATERIAL'), 744 Report.CollectedMaterial, MainTexture); 745 CountBar(offscreen, xProd + dxBar, yProd, wBar, 2, 746 Phrases.Lookup('SUPPORT'), Report.MaterialSupport, MainTexture); 747 if Report.Production >= 0 then 748 if c.Project and (cpImp + cpIndex) = cpImp + imTrGoods then 749 CountBar(offscreen, xProd + dxBar, yProd + dyBar + 16, wBar, 6, 750 Phrases.Lookup('PROFIT'), Report.Production, MainTexture) 751 else 752 CountBar(offscreen, xProd + dxBar, yProd + dyBar + 16, wBar, 2, 753 Phrases.Lookup('PROD'), Report.Production, MainTexture) 754 else 755 begin 756 MakeRed(xProd + dxBar - 6, yProd + dyBar, wBar + 10, 38); 757 CountBar(offscreen, xProd + dxBar, yProd + dyBar + 16, wBar, 3, 758 Phrases.Lookup('LACK'), -Report.Production, RedTex); 759 end; 760 end; 761 if c.Project and (cpImp + cpIndex) <> cpImp + imTrGoods then 762 with offscreen.Canvas do 763 begin 764 i := Report.Production; 765 if (i < 0) or not IsCityAlive then 766 i := 0; 767 FillBar(xProd + 3, yProd + 16 + 63, TrueProd, i, PrCost, 4, true); 768 LoweredTextout(offscreen.Canvas, -1, MainTexture, xProd + 3 - 5, 769 yProd + 16 + 43, Format('%d/%d', [TrueProd, PrCost])); 770 if BiColorTextWidth(offscreen.Canvas, PrName) > wBar + dxBar then 548 771 begin 549 Loc1:=dLoc(cLoc,dx,dy); 550 av := CityAreaInfo.Available[(dy+3) shl 2+(dx+3) shr 1]; 551 if ((av = faNotAvailable) or (av = faTreaty) or (av =faInvalid)) 552 and ((Loc1<0) or (Loc1>=G.lx*G.ly) or (MyMap[Loc1] and fCity=0)) then 553 Sprite(offscreen,HGrTerrain,xmArea-xxt+xxt*dx,ymArea-yyt+yyt*dy,xxt*2, 554 yyt*2,1+5*(xxt*2+1),1+yyt+15*(yyt*3+1)); 555 if (1 shl((dy+3) shl 2+(dx+3) shr 1) and c.Tiles<>0) then 556 PaintResources(xmArea-xxt+xxt*dx,ymArea-yyt+yyt*dy,Loc1,(dx=0) and (dy=0)); 772 repeat 773 Delete(PrName, length(PrName), 1) 774 until BiColorTextWidth(offscreen.Canvas, PrName) <= wBar + dxBar; 775 PrName := PrName + '.' 557 776 end; 558 559 if Report.Working>1 then d:=(xService-(xmArea-192)-8-32) div(Report.Working-1); 560 if d>28 then d:=28; 561 for i:=Report.Working-1 downto 0 do 562 begin 563 if IsCityAlive then xGr:=29 564 else xGr:=141; 565 BitBlt(offscreen.Canvas.Handle,xmArea-192+5+i*d,ymArea-96-29, 566 27,30,GrExt[HGrSystem].Mask.Canvas.Handle,xGr,171,SRCAND); {shadow} 567 Sprite(offscreen,HGrSystem,xmArea-192+4+i*d,ymArea-96-30,27,30,xGr,171); 568 end; 569 if c.Size-Report.Working>1 then d:=(xmArea+192-xService-32) div(c.Size-Report.Working-1); 570 if d>28 then d:=28; 571 for i:=0 to c.Size-Report.Working-1 do 572 begin 573 xGr:=1+112; 574 BitBlt(offscreen.Canvas.Handle,xmArea+192-27+1-i*d,29+1, 575 27,30,GrExt[HGrSystem].Mask.Canvas.Handle,xGr,171,SRCAND); {shadow} 576 Sprite(offscreen,HGrSystem,xmArea+192-27-i*d,29,27,30,xGr,171); 577 Sprite(offscreen,HGrSystem,xmArea+192-27+4-i*d,29+32,10,10,121,126); 578 Sprite(offscreen,HGrSystem,xmArea+192-27+13-i*d,29+32,10,10,121,126); 579 // Sprite(offscreen,HGrSystem,xmArea+192-31+18-i*d,ymArea-96-80+32,10,10,88,115); 580 end; 581 582 if c.Project and cpImp=0 then 583 PrName:=Tribe[cOwner].ModelName[c.Project and cpIndex] 584 else PrName:=Phrases.Lookup('IMPROVEMENTS',c.Project and cpIndex); 585 PrCost:=Report.ProjectCost; 586 587 // happiness section 588 if IsCityAlive then 589 begin 590 if cGov=gFundamentalism then 591 CountBar(offscreen,xHapp,yHapp+dyBar,wBar,17,Phrases.Lookup('FAITH'), 592 Report.CollectedControl,MainTexture) 777 end; 778 RisedTextOut(offscreen.Canvas, xProd - 2, yProd + 36, PrName); 779 780 // pollution section 781 if IsCityAlive and (Report.AddPollution > 0) then 782 begin 783 FillBar(xPoll + 3, yPoll + 20, TruePoll, Report.AddPollution, 784 MaxPollution, 3, true); 785 RisedTextOut(offscreen.Canvas, xPoll + 3 - 5, yPoll + 20 - 20, 786 Phrases.Lookup('POLL')); 787 end; 788 789 // trade section 790 if IsCityAlive and (Report.CollectedTrade > 0) then 791 begin 792 CountBar(offscreen, xTrade, yTrade + dyBar div 2, wBar, 4, 793 Phrases.Lookup('TRADE'), Report.CollectedTrade, MainTexture); 794 CountBar(offscreen, xTrade + dxBar, yTrade + 2 * dyBar, wBar, 5, 795 Phrases.Lookup('CORR'), Report.Corruption, MainTexture); 796 CountBar(offscreen, xTrade + dxBar, yTrade, wBar, 6, Phrases.Lookup('TAX'), 797 Report.Tax, MainTexture); 798 CountBar(offscreen, xTrade + dxBar, yTrade + dyBar, wBar, 12, 799 Phrases.Lookup('SCIENCE'), Report.Science, MainTexture); 800 end; 801 802 // small map 803 bitblt(offscreen.Canvas.Handle, xSmallMap, ySmallMap, wSmallMap, hSmallMap, 804 SmallCityMap.Canvas.Handle, 0, 0, SRCCOPY); 805 if Mode = mImp then 806 Frame(offscreen.Canvas, xSmallMap + 48 * (ZoomArea div 3), 807 ySmallMap + 24 * (ZoomArea mod 3), xSmallMap + 48 * (ZoomArea div 3) + 49, 808 ySmallMap + 24 * (ZoomArea mod 3) + 25, MainTexture.clMark, 809 MainTexture.clMark); 810 Frame(offscreen.Canvas, xSmallMap - 1, ySmallMap - 1, xSmallMap + wSmallMap, 811 ySmallMap + hSmallMap, $B0B0B0, $FFFFFF); 812 RFrame(offscreen.Canvas, xSmallMap - 2, ySmallMap - 2, xSmallMap + wSmallMap + 813 1, ySmallMap + hSmallMap + 1, $FFFFFF, $B0B0B0); 814 815 Frame(offscreen.Canvas, xSupport - 1, ySupport - 1, xSupport + wSupport, 816 ySupport + hSupport, $B0B0B0, $FFFFFF); 817 RFrame(offscreen.Canvas, xSupport - 2, ySupport - 2, xSupport + wSupport + 1, 818 ySupport + hSupport + 1, $FFFFFF, $B0B0B0); 819 x := xSupport + wSupport div 2; 820 y := ySupport + hSupport div 2; 821 if Mode = mSupp then 822 begin 823 offscreen.Canvas.brush.Color := MainTexture.clMark; 824 offscreen.Canvas.FillRect(Rect(x - 27, y - 6, x + 27, y + 6)); 825 offscreen.Canvas.brush.style := bsClear; 826 end; 827 Sprite(offscreen, HGrSystem, x - 16, y - 5, 10, 10, 88, 115); 828 Sprite(offscreen, HGrSystem, x - 5, y - 5, 10, 10, 66, 115); 829 Sprite(offscreen, HGrSystem, x + 6, y - 5, 10, 10, 154, 126); 830 831 bitblt(offscreen.Canvas.Handle, xZoomMap, yZoomMap, wZoomMap, hZoomMap, 832 ZoomCityMap.Canvas.Handle, 0, 0, SRCCOPY); 833 834 for i := 0 to 5 do 835 imix[i] := -1; 836 if Mode = mImp then 837 begin 838 if ZoomArea = 5 then 839 begin 840 Cnt := 0; 841 for iix := 0 to nImp - 1 do 842 if ((iix < 28) or (ImpPosition[iix] < 0)) and (c.Built[iix] > 0) then 843 begin 844 i := Cnt - Page * 6; 845 if (i >= 0) and (i < 6) then 846 imix[i] := iix; 847 inc(Cnt); 848 end; 849 PageCount := (Cnt + 5) div 6; 850 end 851 else 852 begin 853 for iix := 28 to nImp - 1 do 854 begin 855 i := ImpPosition[iix] - 6 * ZoomArea; 856 if (i >= 0) and (i < 6) and (c.Built[iix] > 0) then 857 imix[i] := iix; 858 end; 859 PageCount := 0; 860 end; 861 for i := 0 to 5 do 862 if imix[i] >= 0 then 863 begin 864 iix := imix[i]; 865 x := xZoomMap + 14 + 72 * (i mod 3); 866 y := yZoomMap + 14 + 56 * (i div 3); 867 ImpImage(offscreen.Canvas, x, y, iix, cGov, AllowChange and 868 (ClientMode < scContact)); 869 if IsCityAlive then 870 begin 871 if iix = imColosseum then 872 begin 873 Sprite(offscreen, HGrSystem, x + 46, y, 14, 14, 82, 100); 874 end 875 else 876 begin 877 HappyGain := 0; 878 case iix of 879 0 .. 27, imTemple: 880 HappyGain := 2; 881 imTheater: 882 HappyGain := 4; 883 imCathedral: 884 if MyRO.Wonder[woBach].EffectiveOwner = cOwner then 885 HappyGain := 6 886 else 887 HappyGain := 4; 888 end; 889 if HappyGain > 1 then 890 begin 891 d := 30 div (HappyGain - 1); 892 if d > 10 then 893 d := 10 894 end; 895 for j := 0 to HappyGain - 1 do 896 Sprite(offscreen, HGrSystem, x + 50, y + d * j, 10, 10, 132, 126); 897 end; 898 for j := 0 to Imp[iix].Maint - 1 do 899 Sprite(offscreen, HGrSystem, x - 4, y + 29 - 3 * j, 10, 10, 900 132, 115); 901 end 902 end; 903 if imix[0] >= 0 then 904 Imp0Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[0]) 905 else 906 Imp0Area.Hint := ''; 907 if imix[1] >= 0 then 908 Imp1Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[1]) 909 else 910 Imp1Area.Hint := ''; 911 if imix[2] >= 0 then 912 Imp2Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[2]) 913 else 914 Imp2Area.Hint := ''; 915 if imix[3] >= 0 then 916 Imp3Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[3]) 917 else 918 Imp3Area.Hint := ''; 919 if imix[4] >= 0 then 920 Imp4Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[4]) 921 else 922 Imp4Area.Hint := ''; 923 if imix[5] >= 0 then 924 Imp5Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[5]) 925 else 926 Imp5Area.Hint := ''; 927 end 928 else { if mode=mSupp then } 929 begin 930 LoweredTextout(offscreen.Canvas, -1, MainTexture, xZoomMap + 6, 931 yZoomMap + 2, Phrases.Lookup('SUPUNITS')); 932 FreeSupp := c.Size * SupportFree[cGov] shr 1; 933 Cnt := 0; 934 for i := 0 to MyRO.nUn - 1 do 935 if (MyUn[i].Loc >= 0) and (MyUn[i].Home = cix) then 936 with MyModel[MyUn[i].mix] do 937 begin 938 Server(sGetUnitReport, me, i, UnitReport); 939 if (Cnt >= 6 * Page) and (Cnt < 6 * (Page + 1)) then 940 begin // unit visible in display 941 imix[Cnt - 6 * Page] := i; 942 x := ((Cnt - 6 * Page) mod 3) * 64 + xZoomMap; 943 y := ((Cnt - 6 * Page) div 3) * 52 + yZoomMap + 20; 944 MakeUnitInfo(me, MyUn[i], UnitInfo); 945 NoMap.SetOutput(offscreen); 946 NoMap.PaintUnit(x, y, UnitInfo, MyUn[i].Status); 947 948 for j := 0 to UnitReport.FoodSupport - 1 do 949 Sprite(offscreen, HGrSystem, x + 38 + 11 * j, y + 40, 10, 950 10, 66, 115); 951 for j := 0 to UnitReport.ProdSupport - 1 do 952 begin 953 if (FreeSupp > 0) and 954 (UnitReport.ReportFlags and urfAlwaysSupport = 0) then 955 begin 956 Sprite(offscreen, HGrSystem, x + 16 - 11 * j, y + 40, 10, 957 10, 143, 115); 958 dec(FreeSupp); 959 end 960 else 961 Sprite(offscreen, HGrSystem, x + 16 - 11 * j, y + 40, 10, 962 10, 88, 115); 963 end; 964 if UnitReport.ReportFlags and urfDeployed <> 0 then 965 for j := 0 to 1 do 966 Sprite(offscreen, HGrSystem, x + 27 + 11 * j, y + 40, 10, 967 10, 154, 126) 968 end // unit visible in display 969 else 970 dec(FreeSupp, UnitReport.ProdSupport); 971 inc(Cnt); 972 end; 973 PageCount := (Cnt + 5) div 6; 974 Imp0Area.Hint := ''; 975 Imp1Area.Hint := ''; 976 Imp2Area.Hint := ''; 977 Imp3Area.Hint := ''; 978 Imp4Area.Hint := ''; 979 Imp5Area.Hint := ''; 980 end; 981 PageUpBtn.Visible := PageCount > 1; 982 PageDownBtn.Visible := PageCount > 1; 983 984 with offscreen.Canvas do 985 begin 986 { display project now } 987 DLine(offscreen.Canvas, xView + 9 + xSizeBig, xProd + 2 * wBar + 10, 988 yProd + dyBar + 16, $FFFFFF, $B0B0B0); 989 if ProdHint then 990 begin 991 Frame(offscreen.Canvas, xView + 9 - 1, yView + 5 - 1, 992 xView + 9 + xSizeBig, yView + 5 + ySizeBig, $B0B0B0, $FFFFFF); 993 RFrame(offscreen.Canvas, xView + 9 - 2, yView + 5 - 2, 994 xView + 9 + xSizeBig + 1, yView + 5 + ySizeBig + 1, $FFFFFF, $B0B0B0); 995 with offscreen.Canvas do 996 begin 997 brush.Color := $000000; 998 FillRect(Rect(xView + 9, yView + 5, xView + 1 + 72 - 8, 999 yView + 5 + 40)); 1000 brush.style := bsClear; 1001 end 1002 end 1003 else if AllowChange and (c.Status and 7 <> 0) then 1004 begin // city type autobuild 1005 FrameImage(offscreen.Canvas, bigimp, xView + 9, yView + 5, xSizeBig, 1006 ySizeBig, (c.Status and 7 - 1 + 3) * xSizeBig, 0, (cix >= 0) and 1007 (ClientMode < scContact)); 1008 end 1009 else if c.Project and cpImp = 0 then 1010 begin // project is unit 1011 FrameImage(offscreen.Canvas, bigimp, xView + 9, yView + 5, xSizeBig, 1012 ySizeBig, 0, 0, AllowChange and (ClientMode < scContact)); 1013 with Tribe[cOwner].ModelPicture[c.Project and cpIndex] do 1014 Sprite(offscreen, HGr, xView + 5, yView + 1, 64, 44, 1015 pix mod 10 * 65 + 1, pix div 10 * 49 + 1); 1016 end 1017 else 1018 begin // project is building 1019 if ProdHint then 1020 Paintiix := c.Project0 and cpIndex 1021 else 1022 Paintiix := c.Project and cpIndex; 1023 ImpImage(offscreen.Canvas, xView + 9, yView + 5, Paintiix, cGov, 1024 AllowChange and (ClientMode < scContact)); 1025 end; 1026 end; 1027 1028 if AllowChange and (ClientMode < scContact) then 1029 begin 1030 i := Server(sBuyCityProject - sExecute, me, cix, nil^); 1031 BuyBtn.Visible := (i = eOk) or (i = eViolation); 1032 end 593 1033 else 594 begin 595 CountBar(offscreen,xHapp,yHapp+dyBar,wBar,17,Phrases.Lookup('HAPPINESS'), 596 Report.Morale,MainTexture); 597 CountBar(offscreen,xHapp,yHapp+2*dyBar,wBar,16,Phrases.Lookup('CONTROL'), 598 Report.CollectedControl,MainTexture); 599 end; 600 CountBar(offscreen,xHapp,yHapp,wBar,8,Phrases.Lookup('LUX'), 601 Report.Luxury,MainTexture); 602 CountBar(offscreen,xHapp+dxBar,yHapp,wBar,19,Phrases.Lookup('UNREST'), 603 2*Report.Deployed,MainTexture); 604 CountBar(offscreen,xHapp+dxBar,yHapp+dyBar,wBar,17,Phrases.Lookup('HAPPINESSDEMAND'), 605 c.Size,MainTexture); 606 if Report.HappinessBalance>=0 then 607 CountBar(offscreen,xHapp+dxBar,yHapp+2*dyBar,wBar,17,Phrases.Lookup('HAPPINESSPLUS'), 608 Report.HappinessBalance,MainTexture) 1034 BuyBtn.Visible := false; 1035 1036 MarkUsedOffscreen(ClientWidth, ClientHeight); 1037 end; { OffscreenPaint } 1038 1039 procedure TCityDlg.FormShow(Sender: TObject); 1040 var 1041 dx, dy, Loc1: integer; 1042 GetCityData: TGetCityData; 1043 begin 1044 BlinkTime := 5; 1045 if cix >= 0 then 1046 begin { own city } 1047 c := MyCity[cix]; 1048 cOwner := me; 1049 cGov := MyRO.Government; 1050 ProdHint := (cGov <> gAnarchy) and 1051 (Happened and (chProduction or chFounded or chCaptured or 1052 chAllImpsMade) <> 0); 1053 Server(sGetCityAreaInfo, me, cix, CityAreaInfo); 1054 NextCityBtn.Visible := WindowMode = wmPersistent; 1055 PrevCityBtn.Visible := WindowMode = wmPersistent; 1056 end 1057 else { enemy city } 1058 begin 1059 Mode := mImp; 1060 Server(sGetCity, me, cLoc, GetCityData); 1061 c := GetCityData.c; 1062 cOwner := GetCityData.Owner; 1063 cGov := MyRO.EnemyReport[cOwner].Government; 1064 Happened := c.Flags and $7FFFFFFF; 1065 ProdHint := false; 1066 Server(sGetEnemyCityAreaInfo, me, cLoc, CityAreaInfo); 1067 1068 if c.Project and cpImp = 0 then 1069 begin 1070 emix := MyRO.nEnemyModel - 1; 1071 while (emix > 0) and ((MyRO.EnemyModel[emix].Owner <> cOwner) or 1072 (integer(MyRO.EnemyModel[emix].mix) <> c.Project and cpIndex)) do 1073 dec(emix); 1074 if Tribe[cOwner].ModelPicture[c.Project and cpIndex].HGr = 0 then 1075 InitEnemyModel(emix); 1076 end; 1077 1078 NextCityBtn.Visible := false; 1079 PrevCityBtn.Visible := false; 1080 end; 1081 Page := 0; 1082 1083 if c.Size < 5 then 1084 SizeClass := 0 1085 else if c.Size < 9 then 1086 SizeClass := 1 1087 else if c.Size < 13 then 1088 SizeClass := 2 609 1089 else 610 begin 611 MakeRed(xHapp+dxBar-6,yHapp+2*dyBar,wBar+10,38); 612 CountBar(offscreen,xHapp+dxBar,yHapp+2*dyBar,wBar,18,Phrases.Lookup('LACK'), 613 -Report.HappinessBalance,RedTex); 614 end; 615 end; 616 617 // food section 618 if IsCityAlive then 619 begin 620 CountBar(offscreen,xFood,yFood+dyBar div 2,wBar,0,Phrases.Lookup('FOOD'),Report.CollectedFood,MainTexture); 621 CountBar(offscreen,xFood+dxBar,yFood+dyBar,wBar,0,Phrases.Lookup('DEMAND'),2*c.Size,MainTexture); 622 CountBar(offscreen,xFood+dxBar,yFood,wBar,0,Phrases.Lookup('SUPPORT'),Report.FoodSupport,MainTexture); 623 if Report.FoodSurplus>=0 then 624 if (cGov=gFuture) 625 or (c.Size>=NeedAqueductSize) and (Report.FoodSurplus<2) then 626 CountBar(offscreen,xFood+dxBar,yFood+2*dyBar,wBar,6,Phrases.Lookup('PROFIT'), 627 Report.FoodSurplus,MainTexture) 628 else CountBar(offscreen,xFood+dxBar,yFood+2*dyBar,wBar,0,Phrases.Lookup('SURPLUS'), 629 Report.FoodSurplus,MainTexture) 1090 SizeClass := 3; 1091 1092 // check if port 1093 IsPort := false; 1094 for dx := -2 to 2 do 1095 for dy := -2 to 2 do 1096 if abs(dx) + abs(dy) = 2 then 1097 begin 1098 Loc1 := dLoc(cLoc, dx, dy); 1099 if (Loc1 >= 0) and (Loc1 < G.lx * G.ly) and 1100 (MyMap[Loc1] and fTerrain < fGrass) then 1101 IsPort := true; 1102 end; 1103 1104 if WindowMode = wmModal then 1105 begin { center on screen } 1106 Left := (Screen.Width - Width) div 2; 1107 Top := (Screen.Height - Height) div 2; 1108 end; 1109 1110 Caption := CityName(c.ID); 1111 1112 InitSmallCityMap; 1113 InitZoomCityMap; 1114 OpenSoundEvent := -1; 1115 OffscreenPaint; 1116 Timer1.Enabled := true; 1117 end; 1118 1119 procedure TCityDlg.ShowNewContent(NewMode, Loc: integer; ShowEvent: cardinal); 1120 begin 1121 if MyMap[Loc] and fOwned <> 0 then 1122 begin // own city 1123 cix := MyRO.nCity - 1; 1124 while (cix >= 0) and (MyCity[cix].Loc <> Loc) do 1125 dec(cix); 1126 assert(cix >= 0); 1127 if (Optimize_cixTileChange >= 0) and 1128 (Optimize_TilesBeforeChange and not MyCity[Optimize_cixTileChange].Tiles 1129 <> 0) then 1130 begin 1131 CityOptimizer_ReleaseCityTiles(Optimize_cixTileChange, 1132 Optimize_TilesBeforeChange and 1133 not MyCity[Optimize_cixTileChange].Tiles); 1134 if WindowMode <> wmModal then 1135 MainScreen.UpdateViews; 1136 end; 1137 Optimize_cixTileChange := cix; 1138 Optimize_TilesBeforeChange := MyCity[cix].Tiles; 1139 end 630 1140 else 631 begin 632 MakeRed(xFood+dxBar-6,yFood+2*dyBar,wBar+10,38); 633 CountBar(offscreen,xFood+dxBar,yFood+2*dyBar,wBar,1,Phrases.Lookup('LACK'), 634 -Report.FoodSurplus,RedTex); 635 end; 636 end; 637 CanGrow:= (c.Size<MaxCitySize) and (cGov<>gFuture) 638 and (Report.FoodSurplus>0) 639 and ((c.Size<NeedAqueductSize) 640 or (c.Built[imAqueduct]=1) and (c.Size<NeedSewerSize) 641 or (c.Built[imSewer]=1)); 642 FillBar(xFood+3,yFood+102,TrueFood, 643 CutCityFoodSurplus(Report.FoodSurplus,IsCityAlive,cGov,c.size), 644 Report.Storage,1,CanGrow); 645 LoweredTextOut(offscreen.Canvas,-1,MainTexture,xFood+3-5,yFood+102-20,Format('%d/%d',[TrueFood,Report.Storage])); 646 LoweredTextOut(offscreen.Canvas,-1,MainTexture,xFood-2,yFood+66,Phrases.Lookup('STORAGE')); 647 648 // production section 649 if IsCityAlive then 650 begin 651 CountBar(offscreen,xProd,yProd,wBar,2,Phrases.Lookup('MATERIAL'), 652 Report.CollectedMaterial,MainTexture); 653 CountBar(offscreen,xProd+dxBar,yProd,wBar,2,Phrases.Lookup('SUPPORT'), 654 Report.MaterialSupport,MainTexture); 655 if Report.Production>=0 then 656 if c.Project and (cpImp+cpIndex)=cpImp+imTrGoods then 657 CountBar(offscreen,xProd+dxBar,yProd+dyBar+16,wBar,6,Phrases.Lookup('PROFIT'), 658 Report.Production,MainTexture) 659 else CountBar(offscreen,xProd+dxBar,yProd+dyBar+16,wBar,2,Phrases.Lookup('PROD'), 660 Report.Production,MainTexture) 661 else 662 begin 663 MakeRed(xProd+dxBar-6,yProd+dyBar,wBar+10,38); 664 CountBar(offscreen,xProd+dxBar,yProd+dyBar+16,wBar,3,Phrases.Lookup('LACK'), 665 -Report.Production,RedTex); 666 end; 667 end; 668 if c.Project and (cpImp+cpIndex)<>cpImp+imTrGoods then with offscreen.Canvas do 669 begin 670 i:=Report.Production; 671 if (i<0) or not IsCityAlive then i:=0; 672 FillBar(xProd+3,yProd+16+63,TrueProd,i,PrCost,4,true); 673 LoweredTextOut(offscreen.Canvas,-1,MainTexture,xProd+3-5,yProd+16+43, 674 Format('%d/%d',[TrueProd,PrCost])); 675 if BiColorTextWidth(offscreen.Canvas,PrName)>wBar+dxBar then 676 begin 677 repeat Delete(PrName,Length(PrName),1) 678 until BiColorTextWidth(offscreen.Canvas,PrName)<=wBar+dxBar; 679 PrName:=PrName+'.' 680 end; 681 end; 682 RisedTextOut(offscreen.Canvas,xProd-2,yProd+36,PrName); 683 684 // pollution section 685 if IsCityAlive and (Report.AddPollution>0) then 686 begin 687 FillBar(xPoll+3,yPoll+20,TruePoll,Report.AddPollution, 688 MaxPollution,3,true); 689 RisedTextOut(offscreen.Canvas,xPoll+3-5,yPoll+20-20,Phrases.Lookup('POLL')); 690 end; 691 692 // trade section 693 if IsCityAlive and (Report.CollectedTrade>0) then 694 begin 695 CountBar(offscreen,xTrade,yTrade+dyBar div 2,wBar,4,Phrases.Lookup('TRADE'),Report.CollectedTrade,MainTexture); 696 CountBar(offscreen,xTrade+dxBar,yTrade+2*dyBar,wBar,5,Phrases.Lookup('CORR'),Report.Corruption,MainTexture); 697 CountBar(offscreen,xTrade+dxBar,yTrade,wBar,6,Phrases.Lookup('TAX'),Report.Tax,MainTexture); 698 CountBar(offscreen,xTrade+dxBar,yTrade+dyBar,wBar,12,Phrases.Lookup('SCIENCE'),Report.Science,MainTexture); 699 end; 700 701 // small map 702 BitBlt(Offscreen.Canvas.Handle,xSmallMap,ySmallmap,wSmallMap,hSmallMap,SmallCitymap.Canvas.Handle,0,0,SRCCOPY); 703 if Mode=mImp then 704 Frame(Offscreen.Canvas,xSmallMap+48*(ZoomArea div 3),ySmallmap+24*(ZoomArea mod 3), 705 xSmallMap+48*(ZoomArea div 3)+49,ySmallmap+24*(ZoomArea mod 3)+25, 706 MainTexture.clMark,MainTexture.clMark); 707 Frame(Offscreen.Canvas,xSmallMap-1,ySmallmap-1,xSmallMap+wSmallMap,ySmallmap+hSmallMap,$B0B0B0,$FFFFFF); 708 RFrame(Offscreen.Canvas,xSmallMap-2,ySmallmap-2,xSmallMap+wSmallMap+1,ySmallmap+hSmallMap+1,$FFFFFF,$B0B0B0); 709 710 Frame(Offscreen.Canvas,xSupport-1,ySupport-1,xSupport+wSupport,ySupport+hSupport,$B0B0B0,$FFFFFF); 711 RFrame(Offscreen.Canvas,xSupport-2,ySupport-2,xSupport+wSupport+1,ySupport+hSupport+1,$FFFFFF,$B0B0B0); 712 x:=xSupport+wSupport div 2; 713 y:=ySupport+hSupport div 2; 714 if Mode=mSupp then 715 begin 716 Offscreen.Canvas.brush.Color:=MainTexture.clMark; 717 Offscreen.Canvas.FillRect(Rect(x-27,y-6,x+27,y+6)); 718 Offscreen.Canvas.brush.style:=bsClear; 719 end; 720 Sprite(offscreen,HGrSystem,x-16,y-5,10,10,88,115); 721 Sprite(offscreen,HGrSystem,x-5,y-5,10,10,66,115); 722 Sprite(offscreen,HGrSystem,x+6,y-5,10,10,154,126); 723 724 BitBlt(Offscreen.Canvas.Handle,xZoomMap,yZoommap,wZoomMap,hZoomMap,ZoomCitymap.Canvas.Handle,0,0,SRCCOPY); 725 726 for i:=0 to 5 do imix[i]:=-1; 727 if Mode=mImp then 728 begin 729 if ZoomArea=5 then 730 begin 731 Cnt:=0; 732 for iix:=0 to nImp-1 do 733 if ((iix<28) or (ImpPosition[iix]<0)) and (c.Built[iix]>0) then 1141 cix := -1; 1142 AllowChange := not supervising and (cix >= 0); 1143 cLoc := Loc; 1144 Happened := ShowEvent; 1145 inherited ShowNewContent(NewMode); 1146 end; 1147 1148 procedure TCityDlg.FormMouseDown(Sender: TObject; Button: TMouseButton; 1149 Shift: TShiftState; x, y: integer); 1150 var 1151 i, qx, qy, dx, dy, fix, NewTiles, Loc1, iix, SellResult: integer; 1152 Rebuild: boolean; 1153 begin 1154 if (ssLeft in Shift) and (x >= xSmallMap) and (x < xSmallMap + wSmallMap) and 1155 (y >= ySmallMap) and (y < ySmallMap + hSmallMap) then 1156 begin 1157 Mode := mImp; 1158 ZoomArea := (y - ySmallMap) * 3 div hSmallMap + 3 * 1159 ((x - xSmallMap) * 2 div wSmallMap); 1160 Page := 0; 1161 InitZoomCityMap; 1162 SmartUpdateContent; 1163 exit; 1164 end; 1165 if (ssLeft in Shift) and (x >= xSupport) and (x < xSupport + wSupport) and 1166 (y >= ySupport) and (y < ySupport + hSupport) then 1167 begin 1168 Mode := mSupp; 1169 Page := 0; 1170 InitZoomCityMap; 1171 SmartUpdateContent; 1172 exit; 1173 end; 1174 if not AllowChange then 1175 exit; // not an own city 1176 1177 if (ssLeft in Shift) then 1178 if (ClientMode < scContact) and (x >= xView) and (y >= yView) and 1179 (x < xView + 73) and (y < yView + 50) then 1180 if cGov = gAnarchy then 1181 with MessgExDlg do 734 1182 begin 735 i:=Cnt-Page*6; 736 if (i>=0) and (i<6) then 737 imix[i]:=iix; 738 inc(Cnt); 739 end; 740 PageCount:=(Cnt+5) div 6; 741 end 742 else 743 begin 744 for iix:=28 to nImp-1 do 745 begin 746 i:=ImpPosition[iix]-6*ZoomArea; 747 if (i>=0) and (i<6) and (c.Built[iix]>0) then 748 imix[i]:=iix; 749 end; 750 PageCount:=0; 751 end; 752 for i:=0 to 5 do if imix[i]>=0 then 753 begin 754 iix:=imix[i]; 755 x:=xZoomMap+14+72*(i mod 3); 756 y:=yZoomMap+14+56*(i div 3); 757 ImpImage(offscreen.Canvas,x,y,iix,cGov,AllowChange and (ClientMode<scContact)); 758 if IsCityAlive then 759 begin 760 if iix=imColosseum then 761 begin 762 Sprite(offscreen,HGrSystem,x+46,y,14,14,82,100); 1183 { MessgText:=Phrases.Lookup('OUTOFCONTROL'); 1184 if c.Project and cpImp=0 then 1185 MessgText:=Format(MessgText,[Tribe[cOwner].ModelName[c.Project and cpIndex]]) 1186 else MessgText:=Format(MessgText,[Phrases.Lookup('IMPROVEMENTS',c.Project and cpIndex)]); } 1187 MessgText := Phrases.Lookup('NOCHANGEINANARCHY'); 1188 Kind := mkOk; 1189 ShowModal; 763 1190 end 764 1191 else 1192 begin 1193 if ProdHint then 765 1194 begin 766 HappyGain:=0; 767 case iix of 768 0..27,imTemple: HappyGain:=2; 769 imTheater: HappyGain:=4; 770 imCathedral: 771 if MyRO.Wonder[woBach].EffectiveOwner=cOwner then HappyGain:=6 772 else HappyGain:=4; 773 end; 774 if HappyGain>1 then 775 begin d:=30 div(HappyGain-1);if d>10 then d:=10 end; 776 for j:=0 to HappyGain-1 do 777 Sprite(offscreen,HGrSystem,x+50,y+d*j,10,10,132,126); 1195 ProdHint := false; 1196 SmartUpdateContent 778 1197 end; 779 for j:=0 to Imp[iix].Maint-1 do 780 Sprite(offscreen,HGrSystem,x-4,y+29-3*j,10,10,132,115); 1198 ChooseProject; 781 1199 end 782 end; 783 if imix[0]>=0 then 784 Imp0Area.Hint:=Phrases.Lookup('IMPROVEMENTS',imix[0]) 785 else Imp0Area.Hint:=''; 786 if imix[1]>=0 then 787 Imp1Area.Hint:=Phrases.Lookup('IMPROVEMENTS',imix[1]) 788 else Imp1Area.Hint:=''; 789 if imix[2]>=0 then 790 Imp2Area.Hint:=Phrases.Lookup('IMPROVEMENTS',imix[2]) 791 else Imp2Area.Hint:=''; 792 if imix[3]>=0 then 793 Imp3Area.Hint:=Phrases.Lookup('IMPROVEMENTS',imix[3]) 794 else Imp3Area.Hint:=''; 795 if imix[4]>=0 then 796 Imp4Area.Hint:=Phrases.Lookup('IMPROVEMENTS',imix[4]) 797 else Imp4Area.Hint:=''; 798 if imix[5]>=0 then 799 Imp5Area.Hint:=Phrases.Lookup('IMPROVEMENTS',imix[5]) 800 else Imp5Area.Hint:=''; 801 end 802 else {if mode=mSupp then} 803 begin 804 LoweredTextOut(offscreen.Canvas,-1,MainTexture,xZoomMap+6,yZoomMap+2,Phrases.Lookup('SUPUNITS')); 805 FreeSupp:=c.Size*SupportFree[cGov] shr 1; 806 Cnt:=0; 807 for i:=0 to MyRO.nUn-1 do if (MyUn[i].Loc>=0) and (MyUn[i].Home=cix) then 808 with MyModel[MyUn[i].mix] do 1200 else if (Mode = mImp) and (x >= xZoomMap) and (x < xZoomMap + wZoomMap) and 1201 (y >= yZoomMap) and (y < yZoomMap + hZoomMap) then 1202 begin 1203 i := 5; 1204 while (i >= 0) and not((x >= xZoomMap + 14 + 72 * (i mod 3)) and 1205 (x < xZoomMap + 14 + 56 + 72 * (i mod 3)) and 1206 (y >= yZoomMap + 14 + 56 * (i div 3)) and 1207 (y < yZoomMap + 14 + 40 + 56 * (i div 3))) do 1208 dec(i); 1209 if i >= 0 then 809 1210 begin 810 Server(sGetUnitReport, me, i, UnitReport); 811 if (Cnt>=6*Page) and (Cnt<6*(Page+1)) then 812 begin // unit visible in display 813 imix[Cnt-6*Page]:=i; 814 x:=((Cnt-6*Page) mod 3)*64+xZoomMap; 815 y:=((Cnt-6*Page) div 3)*52+yZoomMap+20; 816 MakeUnitInfo(me,MyUn[i],UnitInfo); 817 NoMap.SetOutput(offscreen); 818 NoMap.PaintUnit(x,y,UnitInfo,MyUn[i].Status); 819 820 for j:=0 to UnitReport.FoodSupport-1 do 821 Sprite(offscreen,HGrSystem,x+38+11*j,y+40,10,10,66,115); 822 for j:=0 to UnitReport.ProdSupport-1 do 823 begin 824 if (FreeSupp>0) and (UnitReport.ReportFlags and urfAlwaysSupport=0) then 1211 iix := imix[i]; 1212 if iix >= 0 then 1213 if ssShift in Shift then 1214 HelpDlg.ShowNewContent(Mode or wmPersistent, hkImp, iix) 1215 else if (ClientMode < scContact) then 1216 with MessgExDlg do 825 1217 begin 826 Sprite(offscreen,HGrSystem,x+16-11*j,y+40,10,10,143,115); 827 dec(FreeSupp); 828 end 829 else Sprite(offscreen,HGrSystem,x+16-11*j,y+40,10,10,88,115); 830 end; 831 if UnitReport.ReportFlags and urfDeployed<>0 then 832 for j:=0 to 1 do 833 Sprite(offscreen,HGrSystem,x+27+11*j,y+40,10,10,154,126) 834 end // unit visible in display 835 else dec(FreeSupp, UnitReport.ProdSupport); 836 inc(Cnt); 837 end; 838 PageCount:=(Cnt+5) div 6; 839 Imp0Area.Hint:=''; 840 Imp1Area.Hint:=''; 841 Imp2Area.Hint:=''; 842 Imp3Area.Hint:=''; 843 Imp4Area.Hint:=''; 844 Imp5Area.Hint:=''; 845 end; 846 PageUpBtn.Visible:= PageCount>1; 847 PageDownBtn.Visible:= PageCount>1; 848 849 with offscreen.Canvas do 850 begin 851 {display project now} 852 DLine(offscreen.Canvas,xView+9+xSizeBig,xProd+2*wBar+10,yProd+dyBar+16, 853 $FFFFFF,$B0B0B0); 854 if prodhint then 855 begin 856 Frame(offscreen.canvas,xView+9-1,yView+5-1,xView+9+xSizeBig,yView+5+ySizeBig,$B0B0B0,$FFFFFF); 857 RFrame(offscreen.canvas,xView+9-2,yView+5-2,xView+9+xSizeBig+1,yView+5+ySizeBig+1,$FFFFFF,$B0B0B0); 858 with offscreen.canvas do 859 begin 860 Brush.Color:=$000000; 861 FillRect(Rect(xView+9,yView+5,xView+1+72-8,yView+5+40)); 862 Brush.Style:=bsClear; 863 end 864 end 865 else if AllowChange and (c.Status and 7<>0) then 866 begin // city type autobuild 867 FrameImage(offscreen.canvas,bigimp,xView+9,yView+5,xSizeBig,ySizeBig, 868 (c.Status and 7-1+3)*xSizeBig,0, 869 (cix>=0) and (ClientMode<scContact)); 870 end 871 else if c.Project and cpImp=0 then 872 begin // project is unit 873 FrameImage(offscreen.canvas,bigimp,xView+9,yView+5,xSizeBig,ySizeBig,0,0, 874 AllowChange and (ClientMode<scContact)); 875 with Tribe[cOwner].ModelPicture[c.Project and cpIndex] do 876 Sprite(offscreen,HGr,xView+5,yView+1,64,44, 877 pix mod 10 *65+1,pix div 10*49+1); 878 end 879 else 880 begin // project is building 881 if ProdHint then Paintiix:=c.Project0 and cpIndex 882 else Paintiix:=c.Project and cpIndex; 883 ImpImage(Offscreen.Canvas,xView+9,yView+5,Paintiix,cGov, 884 AllowChange and (ClientMode<scContact)); 885 end; 886 end; 887 888 if AllowChange and (ClientMode<scContact) then 889 begin 890 i:=Server(sBuyCityProject-sExecute,me,cix,nil^); 891 BuyBtn.Visible:= (i=eOk) or (i=eViolation); 892 end 893 else BuyBtn.Visible:=false; 894 895 MarkUsedOffscreen(ClientWidth,ClientHeight); 896 end;{OffscreenPaint} 897 898 procedure TCityDlg.FormShow(Sender: TObject); 899 var 900 dx,dy,Loc1: integer; 901 GetCityData: TGetCityData; 902 begin 903 BlinkTime:=5; 904 if cix>=0 then 905 begin {own city} 906 c:=MyCity[cix]; 907 cOwner:=me; 908 cGov:=MyRO.Government; 909 ProdHint:= (cGov<>gAnarchy) 910 and (Happened and (chProduction or chFounded or chCaptured or chAllImpsMade)<>0); 911 Server(sGetCityAreaInfo,me,cix,CityAreaInfo); 912 NextCityBtn.Visible:= WindowMode=wmPersistent; 913 PrevCityBtn.Visible:= WindowMode=wmPersistent; 914 end 915 else {enemy city} 916 begin 917 Mode:=mImp; 918 Server(sGetCity,me,cLoc,GetCityData); 919 c:=GetCityData.c; 920 cOwner:=GetCityData.Owner; 921 cGov:=MyRO.EnemyReport[cOwner].Government; 922 Happened:=c.Flags and $7FFFFFFF; 923 ProdHint:=false; 924 Server(sGetEnemyCityAreaInfo,me,cLoc,CityAreaInfo); 925 926 if c.Project and cpImp=0 then 927 begin 928 emix:=MyRO.nEnemyModel-1; 929 while (emix>0) and ((MyRO.EnemyModel[emix].Owner<>cOwner) 930 or (integer(MyRO.EnemyModel[emix].mix)<>c.Project and cpIndex)) do dec(emix); 931 if Tribe[cOwner].ModelPicture[c.Project and cpIndex].HGr=0 then 932 InitEnemyModel(emix); 933 end; 934 935 NextCityBtn.Visible:=false; 936 PrevCityBtn.Visible:=false; 937 end; 938 Page:=0; 939 940 if c.Size<5 then SizeClass:=0 941 else if c.Size<9 then SizeClass:=1 942 else if c.Size<13 then SizeClass:=2 943 else SizeClass:=3; 944 945 // check if port 946 IsPort:=false; 947 for dx:=-2 to 2 do for dy:=-2 to 2 do if abs(dx)+abs(dy)=2 then 948 begin 949 Loc1:=dLoc(cLoc,dx,dy); 950 if (Loc1>=0) and (Loc1<G.lx*G.ly) and (MyMap[Loc1] and fTerrain<fGrass) then 951 IsPort:=true; 952 end; 953 954 if WindowMode=wmModal then 955 begin {center on screen} 956 Left:=(Screen.Width-Width) div 2; 957 Top:=(Screen.Height-Height) div 2; 958 end; 959 960 Caption:=CityName(c.ID); 961 962 InitSmallCityMap; 963 InitZoomCityMap; 964 OpenSoundEvent:=-1; 965 OffscreenPaint; 966 Timer1.Enabled:=true; 967 end; 968 969 procedure TCityDlg.ShowNewContent(NewMode,Loc: integer; ShowEvent: cardinal); 970 begin 971 if MyMap[Loc] and fOwned<>0 then 972 begin // own city 973 cix:=MyRO.nCity-1; 974 while (cix>=0) and (MyCity[cix].Loc<>Loc) do dec(cix); 975 assert(cix>=0); 976 if (Optimize_cixTileChange>=0) 977 and (Optimize_TilesBeforeChange 978 and not MyCity[Optimize_cixTileChange].Tiles<>0) then 979 begin 980 CityOptimizer_ReleaseCityTiles(Optimize_cixTileChange, 981 Optimize_TilesBeforeChange and not MyCity[Optimize_cixTileChange].Tiles); 982 if WindowMode<>wmModal then 983 MainScreen.UpdateViews; 984 end; 985 Optimize_cixTileChange:=cix; 986 Optimize_TilesBeforeChange:=MyCity[cix].Tiles; 987 end 988 else cix:=-1; 989 AllowChange:=not supervising and (cix>=0); 990 cLoc:=Loc; 991 Happened:=ShowEvent; 992 inherited ShowNewContent(NewMode); 993 end; 994 995 procedure TCityDlg.FormMouseDown(Sender:TObject; 996 Button:TMouseButton;Shift:TShiftState;x,y:integer); 997 var 998 i,qx,qy,dx,dy,fix,NewTiles,Loc1,iix,SellResult: integer; 999 Rebuild: boolean; 1000 begin 1001 if (ssLeft in Shift) and (x>=xSmallMap) and (x<xSmallMap+wSmallMap) 1002 and (y>=ySmallMap) and (y<ySmallMap+hSmallMap) then 1003 begin 1004 Mode:=mImp; 1005 ZoomArea:=(y-ySmallMap)*3 div hSmallMap+3*((x-xSmallMap)*2 div wSmallMap); 1006 Page:=0; 1007 InitZoomCityMap; 1008 SmartUpdateContent; 1009 exit; 1010 end; 1011 if (ssLeft in Shift) and (x>=xSupport) and (x<xSupport+wSupport) 1012 and (y>=ySupport) and (y<ySupport+hSupport) then 1013 begin 1014 Mode:=mSupp; 1015 Page:=0; 1016 InitZoomCityMap; 1017 SmartUpdateContent; 1018 exit; 1019 end; 1020 if not AllowChange then exit; // not an own city 1021 1022 if (ssLeft in Shift) then 1023 if (ClientMode<scContact) 1024 and (x>=xView) and (y>=yView) and (x<xView+73) and (y<yView+50) then 1025 if cGov=gAnarchy then with MessgExDlg do 1026 begin 1027 { MessgText:=Phrases.Lookup('OUTOFCONTROL'); 1028 if c.Project and cpImp=0 then 1029 MessgText:=Format(MessgText,[Tribe[cOwner].ModelName[c.Project and cpIndex]]) 1030 else MessgText:=Format(MessgText,[Phrases.Lookup('IMPROVEMENTS',c.Project and cpIndex)]);} 1031 MessgText:=Phrases.Lookup('NOCHANGEINANARCHY'); 1032 Kind:=mkOk; 1033 ShowModal; 1034 end 1035 else 1036 begin 1037 if ProdHint then 1038 begin 1039 ProdHint:=false; 1040 SmartUpdateContent 1041 end; 1042 ChooseProject; 1043 end 1044 else if (Mode=mImp) and (x>=xZoomMap) and (x<xZoomMap+wZoomMap) 1045 and (y>=yZoomMap) and (y<yZoomMap+hZoomMap) then 1046 begin 1047 i:=5; 1048 while (i>=0) and 1049 not ((x>=xZoomMap+14+72*(i mod 3)) 1050 and (x<xZoomMap+14+56+72*(i mod 3)) 1051 and (y>=yZoomMap+14+56*(i div 3)) 1052 and (y<yZoomMap+14+40+56*(i div 3))) do 1053 dec(i); 1054 if i>=0 then 1055 begin 1056 iix:=imix[i]; 1057 if iix>=0 then 1058 if ssShift in Shift then 1059 HelpDlg.ShowNewContent(Mode or wmPersistent, hkImp, iix) 1060 else if (ClientMode<scContact) then with MessgExDlg do 1061 begin 1062 IconKind:=mikImp; 1063 IconIndex:=iix; 1064 if (iix=imPalace) or (Imp[iix].Kind=ikWonder) then 1065 begin 1066 MessgText:=Phrases.Lookup('IMPROVEMENTS',iix); 1067 if iix=woOracle then 1068 MessgText:=MessgText+'\'+Format(Phrases.Lookup('ORACLEINCOME'), 1069 [MyRO.OracleIncome]); 1070 Kind:=mkOk; 1071 ShowModal; 1072 end 1073 else 1074 begin 1075 SellResult:=Server(sSellCityImprovement-sExecute,me,cix,iix); 1076 if SellResult<rExecuted then 1218 IconKind := mikImp; 1219 IconIndex := iix; 1220 if (iix = imPalace) or (Imp[iix].Kind = ikWonder) then 1077 1221 begin 1078 if SellResult=eOnlyOnce then1079 MessgText:=Phrases.Lookup('NOSELLAGAIN')1080 else MessgText:=Phrases.Lookup('OUTOFCONTROL');1081 MessgText:=Format(MessgText,[Phrases.Lookup('IMPROVEMENTS',iix)]);1082 Kind:=mkOk;1083 ShowModal;1222 MessgText := Phrases.Lookup('IMPROVEMENTS', iix); 1223 if iix = woOracle then 1224 MessgText := MessgText + '\' + 1225 Format(Phrases.Lookup('ORACLEINCOME'), [MyRO.OracleIncome]); 1226 Kind := mkOk; 1227 ShowModal; 1084 1228 end 1085 else1229 else 1086 1230 begin 1087 if Server(sRebuildCityImprovement-sExecute,me,cix,iix)<rExecuted then 1088 begin // no rebuild possible, ask for sell only 1089 Rebuild:=false; 1090 MessgText:=Phrases.Lookup('IMPROVEMENTS',iix); 1091 if not Phrases2FallenBackToEnglish then 1092 MessgText:=Format(Phrases2.Lookup('SELL2'),[MessgText, 1093 Imp[iix].Cost*BuildCostMod[G.Difficulty[me]] div 12]) 1094 else MessgText:=Format(Phrases.Lookup('SELL'),[MessgText]); 1095 if iix=imSpacePort then with MyRO.Ship[me] do 1096 if Parts[0]+Parts[1]+Parts[2]>0 then 1097 MessgText:=MessgText+' '+Phrases.Lookup('SPDESTRUCTQUERY'); 1098 Kind:=mkYesNo; 1099 ShowModal; 1100 if ModalResult<>mrOK then iix:=-1 1231 SellResult := Server(sSellCityImprovement - sExecute, me, 1232 cix, iix); 1233 if SellResult < rExecuted then 1234 begin 1235 if SellResult = eOnlyOnce then 1236 MessgText := Phrases.Lookup('NOSELLAGAIN') 1237 else 1238 MessgText := Phrases.Lookup('OUTOFCONTROL'); 1239 MessgText := Format(MessgText, 1240 [Phrases.Lookup('IMPROVEMENTS', iix)]); 1241 Kind := mkOk; 1242 ShowModal; 1101 1243 end 1102 else1244 else 1103 1245 begin 1104 Rebuild:=true; 1105 MessgText:=Phrases.Lookup('IMPROVEMENTS',iix); 1106 if not Phrases2FallenBackToEnglish then 1107 MessgText:=Format(Phrases2.Lookup('DISPOSE2'),[MessgText, 1108 Imp[iix].Cost*BuildCostMod[G.Difficulty[me]] div 12 *2 div 3]) 1109 else MessgText:=Format(Phrases.Lookup('DISPOSE'),[MessgText]); 1110 if iix=imSpacePort then with MyRO.Ship[me] do 1111 if Parts[0]+Parts[1]+Parts[2]>0 then 1112 MessgText:=MessgText+' '+Phrases.Lookup('SPDESTRUCTQUERY'); 1113 Kind:=mkYesNo; 1114 ShowModal; 1115 if ModalResult<>mrOK then iix:=-1 1116 end; 1117 if iix>=0 then 1118 begin 1119 if Rebuild then 1246 if Server(sRebuildCityImprovement - sExecute, me, cix, iix) < rExecuted 1247 then 1248 begin // no rebuild possible, ask for sell only 1249 Rebuild := false; 1250 MessgText := Phrases.Lookup('IMPROVEMENTS', iix); 1251 if not Phrases2FallenBackToEnglish then 1252 MessgText := Format(Phrases2.Lookup('SELL2'), 1253 [MessgText, Imp[iix].Cost * BuildCostMod 1254 [G.Difficulty[me]] div 12]) 1255 else 1256 MessgText := Format(Phrases.Lookup('SELL'), [MessgText]); 1257 if iix = imSpacePort then 1258 with MyRO.Ship[me] do 1259 if Parts[0] + Parts[1] + Parts[2] > 0 then 1260 MessgText := MessgText + ' ' + 1261 Phrases.Lookup('SPDESTRUCTQUERY'); 1262 Kind := mkYesNo; 1263 ShowModal; 1264 if ModalResult <> mrOK then 1265 iix := -1 1266 end 1267 else 1120 1268 begin 1121 Play('CITY_REBUILDIMP'); 1122 Server(sRebuildCityImprovement,me,cix,iix); 1269 Rebuild := true; 1270 MessgText := Phrases.Lookup('IMPROVEMENTS', iix); 1271 if not Phrases2FallenBackToEnglish then 1272 MessgText := Format(Phrases2.Lookup('DISPOSE2'), 1273 [MessgText, Imp[iix].Cost * BuildCostMod 1274 [G.Difficulty[me]] div 12 * 2 div 3]) 1275 else 1276 MessgText := Format(Phrases.Lookup('DISPOSE'), 1277 [MessgText]); 1278 if iix = imSpacePort then 1279 with MyRO.Ship[me] do 1280 if Parts[0] + Parts[1] + Parts[2] > 0 then 1281 MessgText := MessgText + ' ' + 1282 Phrases.Lookup('SPDESTRUCTQUERY'); 1283 Kind := mkYesNo; 1284 ShowModal; 1285 if ModalResult <> mrOK then 1286 iix := -1 1287 end; 1288 if iix >= 0 then 1289 begin 1290 if Rebuild then 1291 begin 1292 Play('CITY_REBUILDIMP'); 1293 Server(sRebuildCityImprovement, me, cix, iix); 1294 end 1295 else 1296 begin 1297 Play('CITY_SELLIMP'); 1298 Server(sSellCityImprovement, me, cix, iix); 1299 end; 1300 CityOptimizer_CityChange(cix); 1301 InitSmallCityMap; 1302 SmartUpdateContent; 1303 if WindowMode <> wmModal then 1304 MainScreen.UpdateViews; 1123 1305 end 1124 else1125 begin1126 Play('CITY_SELLIMP');1127 Server(sSellCityImprovement,me,cix,iix);1128 end;1129 CityOptimizer_CityChange(cix);1130 InitSmallCityMap;1131 SmartUpdateContent;1132 if WindowMode<>wmModal then1133 MainScreen.UpdateViews;1134 1306 end 1135 1307 end 1136 1308 end 1137 end1138 1309 end 1139 1310 end 1140 else if (Mode=mSupp) and (x>=xZoomMap) and (x<xZoomMap+wZoomMap)1141 and (y>=yZoomMap) and (y<yZoomMap+hZoomMap) then1142 begin 1143 i:=5;1144 while (i>=0) and1145 not ((x>=xZoomMap+64*(i mod 3))1146 and (x<xZoomMap+64+64*(i mod 3))1147 and (y>=yZoomMap+20+48*(i div 3))1148 and (y<yZoomMap+20+52+48*(i div 3))) do1149 dec(i);1150 if (i>=0) and (imix[i]>=0)then1151 if ssShift in Shift then1152 else if (cix>=0) and (ClientMode<scContact) and (WindowMode<>wmModal) then1311 else if (Mode = mSupp) and (x >= xZoomMap) and (x < xZoomMap + wZoomMap) and 1312 (y >= yZoomMap) and (y < yZoomMap + hZoomMap) then 1313 begin 1314 i := 5; 1315 while (i >= 0) and not((x >= xZoomMap + 64 * (i mod 3)) and 1316 (x < xZoomMap + 64 + 64 * (i mod 3)) and 1317 (y >= yZoomMap + 20 + 48 * (i div 3)) and 1318 (y < yZoomMap + 20 + 52 + 48 * (i div 3))) do 1319 dec(i); 1320 if (i >= 0) and (imix[i] >= 0) then 1321 if ssShift in Shift then 1322 else if (cix >= 0) and (ClientMode < scContact) and 1323 (WindowMode <> wmModal) then 1153 1324 begin 1154 CloseAction:=None;1155 Close;1156 MainScreen.CityClosed(imix[i],false,true);1325 CloseAction := None; 1326 Close; 1327 MainScreen.CityClosed(imix[i], false, true); 1157 1328 end 1158 1329 end 1159 else if (x>=xmArea-192) and (x<xmArea+192) and (y>=ymArea-96) and (y<ymArea+96) then 1160 begin 1161 qx:=((4000*xxt*yyt)+(x-xmArea)*(yyt*2)+(y-ymArea+yyt)*(xxt*2)) div (xxt*yyt*4)-1000; 1162 qy:=((4000*xxt*yyt)+(y-ymArea+yyt)*(xxt*2)-(x-xmArea)*(yyt*2)) div (xxt*yyt*4)-1000; 1163 dx:=qx-qy; 1164 dy:=qx+qy; 1165 if (dx>=-3) and (dx<=3) and (dy>=-3) and (dy<=3) and (dx*dx*dy*dy<81) 1166 and ((dx<>0) or (dy<>0)) then 1167 if ssShift in Shift then 1330 else if (x >= xmArea - 192) and (x < xmArea + 192) and (y >= ymArea - 96) 1331 and (y < ymArea + 96) then 1332 begin 1333 qx := ((4000 * xxt * yyt) + (x - xmArea) * (yyt * 2) + (y - ymArea + yyt) 1334 * (xxt * 2)) div (xxt * yyt * 4) - 1000; 1335 qy := ((4000 * xxt * yyt) + (y - ymArea + yyt) * (xxt * 2) - (x - xmArea) 1336 * (yyt * 2)) div (xxt * yyt * 4) - 1000; 1337 dx := qx - qy; 1338 dy := qx + qy; 1339 if (dx >= -3) and (dx <= 3) and (dy >= -3) and (dy <= 3) and 1340 (dx * dx * dy * dy < 81) and ((dx <> 0) or (dy <> 0)) then 1341 if ssShift in Shift then 1168 1342 begin // terrain help 1169 Loc1:=dLoc(cLoc,dx,dy);1170 if (Loc1>=0) and (Loc1<G.lx*G.ly) then1171 HelpOnTerrain(Loc1, Mode or wmPersistent)1343 Loc1 := dLoc(cLoc, dx, dy); 1344 if (Loc1 >= 0) and (Loc1 < G.lx * G.ly) then 1345 HelpOnTerrain(Loc1, Mode or wmPersistent) 1172 1346 end 1173 else if (ClientMode<scContact) and (cGov<>gAnarchy)1174 and (c.Flags and chCaptured=0) then1347 else if (ClientMode < scContact) and (cGov <> gAnarchy) and 1348 (c.Flags and chCaptured = 0) then 1175 1349 begin // toggle exploitation 1176 assert(not supervising);1177 if c.Status and csResourceWeightsMask<>0 then1350 assert(not supervising); 1351 if c.Status and csResourceWeightsMask <> 0 then 1178 1352 begin 1179 with MessgExDlg do1353 with MessgExDlg do 1180 1354 begin 1181 MessgText:=Phrases.Lookup('CITYMANAGEOFF');1182 OpenSound:='MSG_DEFAULT';1183 Kind:=mkOkCancel;1184 IconKind:=mikFullControl;1185 ShowModal;1355 MessgText := Phrases.Lookup('CITYMANAGEOFF'); 1356 OpenSound := 'MSG_DEFAULT'; 1357 Kind := mkOkCancel; 1358 IconKind := mikFullControl; 1359 ShowModal; 1186 1360 end; 1187 if MessgExDlg.ModalResult=mrOK then1361 if MessgExDlg.ModalResult = mrOK then 1188 1362 begin 1189 MyCity[cix].Status:=MyCity[cix].Status1190 andnot csResourceWeightsMask; // off1191 c.Status:=MyCity[cix].Status;1192 SmartUpdateContent1363 MyCity[cix].Status := MyCity[cix].Status and 1364 not csResourceWeightsMask; // off 1365 c.Status := MyCity[cix].Status; 1366 SmartUpdateContent 1193 1367 end; 1194 exit;1368 exit; 1195 1369 end; 1196 fix:=(dy+3) shl 2+(dx+3) shr 1;1197 NewTiles:=MyCity[cix].Tiles xor (1 shl fix);1198 if Server(sSetCityTiles,me,cix,NewTiles)>=rExecuted then1370 fix := (dy + 3) shl 2 + (dx + 3) shr 1; 1371 NewTiles := MyCity[cix].Tiles xor (1 shl fix); 1372 if Server(sSetCityTiles, me, cix, NewTiles) >= rExecuted then 1199 1373 begin 1200 SmartUpdateContent;1201 if WindowMode<>wmModal then1202 MainScreen.UpdateViews;1374 SmartUpdateContent; 1375 if WindowMode <> wmModal then 1376 MainScreen.UpdateViews; 1203 1377 end 1204 1378 end 1205 1379 end 1206 else if (ClientMode<scContact) and (cGov<>gAnarchy) and (c.Flags and chCaptured=0) 1207 and (x>=xmOpt-32) and (x<xmOpt+32) and (y>=ymOpt-32) and (y<ymOpt+32) then 1208 begin 1209 i:=sqr(x-xmOpt)+sqr(y-ymOpt); // click radius 1210 if i<=32*32 then 1380 else if (ClientMode < scContact) and (cGov <> gAnarchy) and 1381 (c.Flags and chCaptured = 0) and (x >= xmOpt - 32) and (x < xmOpt + 32) 1382 and (y >= ymOpt - 32) and (y < ymOpt + 32) then 1383 begin 1384 i := sqr(x - xmOpt) + sqr(y - ymOpt); // click radius 1385 if i <= 32 * 32 then 1211 1386 begin 1212 if i<16*16 then // inner area clicked 1213 if c.Status and csResourceWeightsMask<>0 then 1214 i:=(c.Status shr 4 and $0F) mod 5 +1 // rotate except off 1215 else i:=3 // rwGrowth 1216 else case trunc(arctan2(x-xmOpt,ymOpt-y)*180/pi) of 1217 -25-52*2..-26-52: i:=1; 1218 -25-52..-26: i:=2; 1219 -25..25: i:=3; 1220 26..25+52: i:=4; 1221 26+52..25+52*2: i:=5; 1222 180-26..180,-180..-180+26: i:=0; 1223 else i:=-1; 1224 end; 1225 if i>=0 then 1387 if i < 16 * 16 then // inner area clicked 1388 if c.Status and csResourceWeightsMask <> 0 then 1389 i := (c.Status shr 4 and $0F) mod 5 + 1 // rotate except off 1390 else 1391 i := 3 // rwGrowth 1392 else 1393 case trunc(arctan2(x - xmOpt, ymOpt - y) * 180 / pi) of 1394 - 25 - 52 * 2 .. -26 - 52: 1395 i := 1; 1396 -25 - 52 .. -26: 1397 i := 2; 1398 -25 .. 25: 1399 i := 3; 1400 26 .. 25 + 52: 1401 i := 4; 1402 26 + 52 .. 25 + 52 * 2: 1403 i := 5; 1404 180 - 26 .. 180, -180 .. -180 + 26: 1405 i := 0; 1406 else 1407 i := -1; 1408 end; 1409 if i >= 0 then 1226 1410 begin 1227 ChangeResourceWeights(i);1228 SmartUpdateContent;1229 if WindowMode<>wmModal then1230 MainScreen.UpdateViews;1411 ChangeResourceWeights(i); 1412 SmartUpdateContent; 1413 if WindowMode <> wmModal then 1414 MainScreen.UpdateViews; 1231 1415 end 1232 1416 end 1233 1417 end; 1234 end; {FormMouseDown}1418 end; { FormMouseDown } 1235 1419 1236 1420 procedure TCityDlg.ChooseProject; 1237 1421 const 1238 ptSelect=0; ptTrGoods=1; ptUn=2; ptCaravan=3; ptImp=4; ptWonder=6; 1239 ptShip=7; ptInvalid=8; 1422 ptSelect = 0; 1423 ptTrGoods = 1; 1424 ptUn = 2; 1425 ptCaravan = 3; 1426 ptImp = 4; 1427 ptWonder = 6; 1428 ptShip = 7; 1429 ptInvalid = 8; 1240 1430 1241 1431 function ProjectType(Project: integer): integer; 1242 1432 begin 1243 if Project and cpCompleted<>0 then result:=ptSelect 1244 else if Project and (cpImp+cpIndex)=cpImp+imTrGoods then result:=ptTrGoods 1245 else if Project and cpImp=0 then 1246 if MyModel[Project and cpIndex].Kind=mkCaravan then result:=ptCaravan 1247 else result:=ptUn 1248 else if Project and cpIndex>=nImp then result:=ptInvalid 1249 else if Imp[Project and cpIndex].Kind=ikWonder then result:=ptWonder 1250 else if Imp[Project and cpIndex].Kind=ikShipPart then result:=ptShip 1251 else result:=ptImp 1433 if Project and cpCompleted <> 0 then 1434 result := ptSelect 1435 else if Project and (cpImp + cpIndex) = cpImp + imTrGoods then 1436 result := ptTrGoods 1437 else if Project and cpImp = 0 then 1438 if MyModel[Project and cpIndex].Kind = mkCaravan then 1439 result := ptCaravan 1440 else 1441 result := ptUn 1442 else if Project and cpIndex >= nImp then 1443 result := ptInvalid 1444 else if Imp[Project and cpIndex].Kind = ikWonder then 1445 result := ptWonder 1446 else if Imp[Project and cpIndex].Kind = ikShipPart then 1447 result := ptShip 1448 else 1449 result := ptImp 1252 1450 end; 1253 1451 1254 1452 var 1255 NewProject, OldMoney,pt0,pt1,cix1: integer;1256 QueryOk: boolean;1257 begin 1258 assert(not supervising);1259 ModalSelectDlg.ShowNewContent_CityProject(wmModal,cix);1260 if ModalSelectDlg.result<>-1 then1261 begin 1262 if ModalSelectDlg.result and cpType<>0 then1263 begin 1264 MyCity[cix].Status:=MyCity[cix].Status and not 71265 or (1+ModalSelectDlg.result and cpIndex);1266 AutoBuild(cix, MyData.ImpOrder[ModalSelectDlg.result and cpIndex]);1453 NewProject, OldMoney, pt0, pt1, cix1: integer; 1454 QueryOk: boolean; 1455 begin 1456 assert(not supervising); 1457 ModalSelectDlg.ShowNewContent_CityProject(wmModal, cix); 1458 if ModalSelectDlg.result <> -1 then 1459 begin 1460 if ModalSelectDlg.result and cpType <> 0 then 1461 begin 1462 MyCity[cix].Status := MyCity[cix].Status and not 7 or 1463 (1 + ModalSelectDlg.result and cpIndex); 1464 AutoBuild(cix, MyData.ImpOrder[ModalSelectDlg.result and cpIndex]); 1267 1465 end 1268 else1269 begin 1270 NewProject:=ModalSelectDlg.result;1271 QueryOk:=true;1272 if (NewProject and cpImp<>0) and (NewProject and cpIndex>=28)1273 and (MyRO.NatBuilt[NewProject and cpIndex]>0) then1274 with MessgExDlg do1466 else 1467 begin 1468 NewProject := ModalSelectDlg.result; 1469 QueryOk := true; 1470 if (NewProject and cpImp <> 0) and (NewProject and cpIndex >= 28) and 1471 (MyRO.NatBuilt[NewProject and cpIndex] > 0) then 1472 with MessgExDlg do 1275 1473 begin 1276 cix1:=MyRO.nCity-1; 1277 while (cix1>=0) and (MyCity[cix1].Built[NewProject and cpIndex]=0) do 1278 dec(cix1); 1279 MessgText:=Format(Phrases.Lookup('DOUBLESTATEIMP'), 1280 [Phrases.Lookup('IMPROVEMENTS', NewProject and cpIndex), 1281 CityName(MyCity[cix1].ID)]); 1282 OpenSound:='MSG_DEFAULT'; 1283 Kind:=mkOkCancel; 1284 IconKind:=mikImp; 1285 IconIndex:=NewProject and cpIndex; 1286 ShowModal; 1287 QueryOk:= ModalResult=mrOK; 1474 cix1 := MyRO.nCity - 1; 1475 while (cix1 >= 0) and 1476 (MyCity[cix1].Built[NewProject and cpIndex] = 0) do 1477 dec(cix1); 1478 MessgText := Format(Phrases.Lookup('DOUBLESTATEIMP'), 1479 [Phrases.Lookup('IMPROVEMENTS', NewProject and cpIndex), 1480 CityName(MyCity[cix1].ID)]); 1481 OpenSound := 'MSG_DEFAULT'; 1482 Kind := mkOkCancel; 1483 IconKind := mikImp; 1484 IconIndex := NewProject and cpIndex; 1485 ShowModal; 1486 QueryOk := ModalResult = mrOK; 1288 1487 end; 1289 if not QueryOk then1290 exit;1291 1292 if (MyCity[cix].Prod>0) then1488 if not QueryOk then 1489 exit; 1490 1491 if (MyCity[cix].Prod > 0) then 1293 1492 begin 1294 pt0:=ProjectType(MyCity[cix].Project0);1295 pt1:=ProjectType(NewProject);1296 if (pt0<>ptSelect) and (pt1<>ptTrGoods) then1493 pt0 := ProjectType(MyCity[cix].Project0); 1494 pt1 := ProjectType(NewProject); 1495 if (pt0 <> ptSelect) and (pt1 <> ptTrGoods) then 1297 1496 begin 1298 if NewProject and (cpImp or cpIndex)<>MyCity[cix].Project0 and (cpImp or cpIndex) then 1497 if NewProject and (cpImp or cpIndex) <> MyCity[cix].Project0 and 1498 (cpImp or cpIndex) then 1299 1499 begin // loss of material -- do query 1300 if (pt1=ptTrGoods) or (pt1=ptShip) or (pt1<>pt0) and (pt0<>ptCaravan) then 1301 QueryOk:=SimpleQuery(mkOkCancel,Format(Phrases.Lookup('LOSEMAT'), 1302 [MyCity[cix].Prod0,MyCity[cix].Prod0]),'MSG_DEFAULT')=mrOK 1303 else if MyCity[cix].Project and (cpImp or cpIndex)=MyCity[cix].Project0 and (cpImp or cpIndex) then 1304 QueryOk:=SimpleQuery(mkOkCancel,Phrases.Lookup('LOSEMAT3'),'MSG_DEFAULT')=mrOK 1500 if (pt1 = ptTrGoods) or (pt1 = ptShip) or (pt1 <> pt0) and 1501 (pt0 <> ptCaravan) then 1502 QueryOk := SimpleQuery(mkOkCancel, 1503 Format(Phrases.Lookup('LOSEMAT'), [MyCity[cix].Prod0, 1504 MyCity[cix].Prod0]), 'MSG_DEFAULT') = mrOK 1505 else if MyCity[cix].Project and (cpImp or cpIndex) = MyCity[cix] 1506 .Project0 and (cpImp or cpIndex) then 1507 QueryOk := SimpleQuery(mkOkCancel, Phrases.Lookup('LOSEMAT3'), 1508 'MSG_DEFAULT') = mrOK 1305 1509 end; 1306 1510 end 1307 1511 end; 1308 if not QueryOk then 1309 exit; 1310 1311 OldMoney:=MyRO.Money; 1312 MyCity[cix].Status:=MyCity[cix].Status and not 7; 1313 if (NewProject and cpImp=0) 1314 and ((MyCity[cix].Size<4) and (MyModel[NewProject and cpIndex].Kind=mkSettler) 1315 or (MyCity[cix].Size<3) and ((MyModel[NewProject and cpIndex].Kind=mkSlaves) 1316 or (NewProject and cpConscripts<>0))) then 1317 if SimpleQuery(mkYesNo,Phrases.Lookup('EMIGRATE'),'MSG_DEFAULT')<>mrOK then 1318 NewProject:=NewProject or cpDisbandCity; 1319 Server(sSetCityProject,me,cix,NewProject); 1320 c.Project:=MyCity[cix].Project; 1321 if MyRO.Money>OldMoney then 1322 Play('CITY_SELLIMP'); 1323 end; 1324 CityOptimizer_CityChange(cix); 1325 1326 if WindowMode<>wmModal then 1327 MainScreen.UpdateViews; 1328 InitSmallCityMap; 1329 SmartUpdateContent; 1330 end; 1331 end; 1332 1333 procedure TCityDlg.BuyClick(Sender:TObject); 1512 if not QueryOk then 1513 exit; 1514 1515 OldMoney := MyRO.Money; 1516 MyCity[cix].Status := MyCity[cix].Status and not 7; 1517 if (NewProject and cpImp = 0) and 1518 ((MyCity[cix].Size < 4) and 1519 (MyModel[NewProject and cpIndex].Kind = mkSettler) or 1520 (MyCity[cix].Size < 3) and 1521 ((MyModel[NewProject and cpIndex].Kind = mkSlaves) or 1522 (NewProject and cpConscripts <> 0))) then 1523 if SimpleQuery(mkYesNo, Phrases.Lookup('EMIGRATE'), 'MSG_DEFAULT') <> mrOK 1524 then 1525 NewProject := NewProject or cpDisbandCity; 1526 Server(sSetCityProject, me, cix, NewProject); 1527 c.Project := MyCity[cix].Project; 1528 if MyRO.Money > OldMoney then 1529 Play('CITY_SELLIMP'); 1530 end; 1531 CityOptimizer_CityChange(cix); 1532 1533 if WindowMode <> wmModal then 1534 MainScreen.UpdateViews; 1535 InitSmallCityMap; 1536 SmartUpdateContent; 1537 end; 1538 end; 1539 1540 procedure TCityDlg.BuyClick(Sender: TObject); 1334 1541 var 1335 NextProd,Cost:integer; 1336 begin 1337 if (cix<0) or (ClientMode>=scContact) then exit; 1338 with MyCity[cix],MessgExDlg do 1339 begin 1340 Cost:=Report.ProjectCost; 1341 NextProd:=Report.Production; 1342 if NextProd<0 then NextProd:=0; 1343 Cost:=Cost-Prod-NextProd; 1344 if (MyRO.Wonder[woMich].EffectiveOwner=me) and (Project and cpImp<>0) then 1345 Cost:=Cost*2 1346 else Cost:=Cost*4; 1347 if (Cost<=0) and (Report.HappinessBalance>=0) {no disorder} then 1348 begin MessgText:=Phrases.Lookup('READY'); Kind:=mkOK; end 1349 else if Cost>MyRO.Money then 1350 begin 1351 OpenSound:='MSG_DEFAULT'; 1352 MessgText:=Format(Phrases.Lookup('NOMONEY'),[Cost,MyRO.Money]); 1353 Kind:=mkOK; 1542 NextProd, Cost: integer; 1543 begin 1544 if (cix < 0) or (ClientMode >= scContact) then 1545 exit; 1546 with MyCity[cix], MessgExDlg do 1547 begin 1548 Cost := Report.ProjectCost; 1549 NextProd := Report.Production; 1550 if NextProd < 0 then 1551 NextProd := 0; 1552 Cost := Cost - Prod - NextProd; 1553 if (MyRO.Wonder[woMich].EffectiveOwner = me) and (Project and cpImp <> 0) 1554 then 1555 Cost := Cost * 2 1556 else 1557 Cost := Cost * 4; 1558 if (Cost <= 0) and (Report.HappinessBalance >= 0) { no disorder } then 1559 begin 1560 MessgText := Phrases.Lookup('READY'); 1561 Kind := mkOk; 1354 1562 end 1355 else begin MessgText:=Format(Phrases.Lookup('BUY'),[Cost]); Kind:=mkYesNo; end; 1356 ShowModal; 1357 if (Kind=mkYesNo) and (ModalResult=mrOK) then 1358 begin 1359 if Server(sBuyCityProject,me,cix,nil^)>=rExecuted then 1563 else if Cost > MyRO.Money then 1564 begin 1565 OpenSound := 'MSG_DEFAULT'; 1566 MessgText := Format(Phrases.Lookup('NOMONEY'), [Cost, MyRO.Money]); 1567 Kind := mkOk; 1568 end 1569 else 1570 begin 1571 MessgText := Format(Phrases.Lookup('BUY'), [Cost]); 1572 Kind := mkYesNo; 1573 end; 1574 ShowModal; 1575 if (Kind = mkYesNo) and (ModalResult = mrOK) then 1576 begin 1577 if Server(sBuyCityProject, me, cix, nil^) >= rExecuted then 1360 1578 begin 1361 Play('CITY_BUYPROJECT');1362 SmartUpdateContent;1363 if WindowMode<>wmModal then1364 MainScreen.UpdateViews;1579 Play('CITY_BUYPROJECT'); 1580 SmartUpdateContent; 1581 if WindowMode <> wmModal then 1582 MainScreen.UpdateViews; 1365 1583 end 1366 1584 end … … 1370 1588 procedure TCityDlg.FormClose(Sender: TObject; var Action: TCloseAction); 1371 1589 begin 1372 Timer1.Enabled:=false; 1373 ProdHint:=false; 1374 MarkCityLoc:=-1; 1375 if Optimize_cixTileChange>=0 then 1376 begin 1377 if Optimize_TilesBeforeChange 1378 and not MyCity[Optimize_cixTileChange].Tiles<>0 then 1379 begin 1380 CityOptimizer_ReleaseCityTiles(Optimize_cixTileChange, 1381 Optimize_TilesBeforeChange and not MyCity[Optimize_cixTileChange].Tiles); 1382 if WindowMode<>wmModal then 1383 MainScreen.UpdateViews; 1384 end; 1385 Optimize_cixTileChange:=-1; 1386 end; 1387 if CloseAction>None then 1388 MainScreen.CityClosed(RestoreUnFocus,CloseAction=StepFocus); 1389 RestoreUnFocus:=-1; 1390 inherited; 1590 Timer1.Enabled := false; 1591 ProdHint := false; 1592 MarkCityLoc := -1; 1593 if Optimize_cixTileChange >= 0 then 1594 begin 1595 if Optimize_TilesBeforeChange and not MyCity[Optimize_cixTileChange] 1596 .Tiles <> 0 then 1597 begin 1598 CityOptimizer_ReleaseCityTiles(Optimize_cixTileChange, 1599 Optimize_TilesBeforeChange and 1600 not MyCity[Optimize_cixTileChange].Tiles); 1601 if WindowMode <> wmModal then 1602 MainScreen.UpdateViews; 1603 end; 1604 Optimize_cixTileChange := -1; 1605 end; 1606 if CloseAction > None then 1607 MainScreen.CityClosed(RestoreUnFocus, CloseAction = StepFocus); 1608 RestoreUnFocus := -1; 1609 inherited; 1391 1610 end; 1392 1611 1393 1612 procedure TCityDlg.Timer1Timer(Sender: TObject); 1394 1613 begin 1395 if ProdHint then 1396 begin 1397 BlinkTime:=(BlinkTime+1) mod 12; 1398 if BlinkTime=0 then with Canvas do 1399 begin 1400 BitBlt(canvas.Handle,xView+5,yView+1,64,2, 1401 back.Canvas.Handle,xView+5,yView+1,SRCCOPY); 1402 BitBlt(canvas.Handle,xView+5,yView+3,2,42, 1403 back.Canvas.Handle,xView+5,yView+3,SRCCOPY); 1404 BitBlt(canvas.Handle,xView+5+62,yView+3,2,42, 1405 back.Canvas.Handle,xView+5+62,yView+3,SRCCOPY); 1406 Frame(canvas,xView+9-1,yView+5-1,xView+9+xSizeBig,yView+5+ySizeBig,$B0B0B0,$FFFFFF); 1407 RFrame(canvas,xView+9-2,yView+5-2,xView+9+xSizeBig+1,yView+5+ySizeBig+1,$FFFFFF,$B0B0B0); 1408 Brush.Color:=$000000; 1409 FillRect(Rect(xView+9,yView+5,xView+1+72-8,yView+5+40)); 1410 Brush.Style:=bsClear; 1411 end 1412 else if BlinkTime=6 then 1413 begin 1414 if AllowChange and (c.Status and 7<>0) then 1614 if ProdHint then 1615 begin 1616 BlinkTime := (BlinkTime + 1) mod 12; 1617 if BlinkTime = 0 then 1618 with Canvas do 1619 begin 1620 bitblt(Canvas.Handle, xView + 5, yView + 1, 64, 2, Back.Canvas.Handle, 1621 xView + 5, yView + 1, SRCCOPY); 1622 bitblt(Canvas.Handle, xView + 5, yView + 3, 2, 42, Back.Canvas.Handle, 1623 xView + 5, yView + 3, SRCCOPY); 1624 bitblt(Canvas.Handle, xView + 5 + 62, yView + 3, 2, 42, 1625 Back.Canvas.Handle, xView + 5 + 62, yView + 3, SRCCOPY); 1626 Frame(Canvas, xView + 9 - 1, yView + 5 - 1, xView + 9 + xSizeBig, 1627 yView + 5 + ySizeBig, $B0B0B0, $FFFFFF); 1628 RFrame(Canvas, xView + 9 - 2, yView + 5 - 2, xView + 9 + xSizeBig + 1, 1629 yView + 5 + ySizeBig + 1, $FFFFFF, $B0B0B0); 1630 brush.Color := $000000; 1631 FillRect(Rect(xView + 9, yView + 5, xView + 1 + 72 - 8, 1632 yView + 5 + 40)); 1633 brush.style := bsClear; 1634 end 1635 else if BlinkTime = 6 then 1636 begin 1637 if AllowChange and (c.Status and 7 <> 0) then 1415 1638 begin // city type autobuild 1416 FrameImage(canvas,bigimp,xView+9,yView+5,xSizeBig,ySizeBig,1417 (c.Status and 7-1+3)*xSizeBig,0,true);1639 FrameImage(Canvas, bigimp, xView + 9, yView + 5, xSizeBig, ySizeBig, 1640 (c.Status and 7 - 1 + 3) * xSizeBig, 0, true); 1418 1641 end 1419 else if c.Project and cpImp=0 then1642 else if c.Project and cpImp = 0 then 1420 1643 begin // project is unit 1421 BitBlt(canvas.Handle,xView+9,yView+5,xSizeBig,ySizeBig,1422 bigimp.Canvas.Handle,0,0,SRCCOPY);1423 with Tribe[cOwner].ModelPicture[c.Project and cpIndex] do1424 Sprite(canvas,HGr,xView+5,yView+1,64,44,1425 pix mod 10 *65+1,pix div 10*49+1);1644 bitblt(Canvas.Handle, xView + 9, yView + 5, xSizeBig, ySizeBig, 1645 bigimp.Canvas.Handle, 0, 0, SRCCOPY); 1646 with Tribe[cOwner].ModelPicture[c.Project and cpIndex] do 1647 Sprite(Canvas, HGr, xView + 5, yView + 1, 64, 44, pix mod 10 * 65 + 1, 1648 pix div 10 * 49 + 1); 1426 1649 end 1427 else ImpImage(Canvas,xView+9,yView+5, 1428 c.Project0 and cpIndex,cGov,true); 1650 else 1651 ImpImage(Canvas, xView + 9, yView + 5, c.Project0 and cpIndex, 1652 cGov, true); 1429 1653 end 1430 1654 end … … 1433 1657 procedure TCityDlg.FormPaint(Sender: TObject); 1434 1658 begin 1435 inherited; 1436 if OpenSoundEvent>=0 then PostMessage(Handle, WM_PLAYSOUND, 0, 0); 1437 end; 1438 1439 procedure TCityDlg.OnPlaySound(var Msg:TMessage); 1440 begin 1441 if 1 shl OpenSoundEvent=chProduction then 1442 begin 1443 if c.Project0 and cpImp<>0 then 1444 begin 1445 if c.Project0 and cpIndex>=28 then // wonders have already extra message with sound 1446 if Imp[c.Project0 and cpIndex].Kind=ikShipPart then Play('SHIP_BUILT') 1447 else Play('CITY_IMPCOMPLETE') 1659 inherited; 1660 if OpenSoundEvent >= 0 then 1661 PostMessage(Handle, WM_PLAYSOUND, 0, 0); 1662 end; 1663 1664 procedure TCityDlg.OnPlaySound(var Msg: TMessage); 1665 begin 1666 if 1 shl OpenSoundEvent = chProduction then 1667 begin 1668 if c.Project0 and cpImp <> 0 then 1669 begin 1670 if c.Project0 and cpIndex >= 28 then 1671 // wonders have already extra message with sound 1672 if Imp[c.Project0 and cpIndex].Kind = ikShipPart then 1673 Play('SHIP_BUILT') 1674 else 1675 Play('CITY_IMPCOMPLETE') 1448 1676 end 1449 else Play('CITY_UNITCOMPLETE'); 1677 else 1678 Play('CITY_UNITCOMPLETE'); 1450 1679 end 1451 else Play(CityEventSoundItem[OpenSoundEvent]); 1452 OpenSoundEvent:=-2; 1680 else 1681 Play(CityEventSoundItem[OpenSoundEvent]); 1682 OpenSoundEvent := -2; 1453 1683 end; 1454 1684 1455 1685 function Prio(iix: integer): integer; 1456 1686 begin 1457 case Imp[iix].Kind of 1458 ikWonder: result:=iix+10000; 1459 ikNatLocal, ikNatGlobal: 1687 case Imp[iix].Kind of 1688 ikWonder: 1689 result := iix + 10000; 1690 ikNatLocal, ikNatGlobal: 1691 case iix of 1692 imPalace: 1693 result := 0; 1694 else 1695 result := iix + 20000; 1696 end; 1697 else 1460 1698 case iix of 1461 im Palace: result:=0;1462 else result:=iix+20000;1463 end;1464 else case iix of1465 imTownHall, imCourt: result:=iix+30000;1466 imAqueduct, imSewer: result:=iix+40000;1467 imTemple, imTheater, imCathedral: result:=iix+50000;1468 else result:=iix+90000;1699 imTownHall, imCourt: 1700 result := iix + 30000; 1701 imAqueduct, imSewer: 1702 result := iix + 40000; 1703 imTemple, imTheater, imCathedral: 1704 result := iix + 50000; 1705 else 1706 result := iix + 90000; 1469 1707 end; 1470 1708 end; … … 1473 1711 procedure TCityDlg.NextCityBtnClick(Sender: TObject); 1474 1712 begin 1475 ChangeCity(+1);1713 ChangeCity(+1); 1476 1714 end; 1477 1715 1478 1716 procedure TCityDlg.PrevCityBtnClick(Sender: TObject); 1479 1717 begin 1480 ChangeCity(-1);1718 ChangeCity(-1); 1481 1719 end; 1482 1720 1483 1721 procedure TCityDlg.ChangeCity(d: integer); 1484 1722 var 1485 cixNew: integer;1486 begin 1487 cixNew:=cix;1488 repeat1489 cixNew:=(cixNew+MyRO.nCity+d) mod MyRO.nCity;1490 until (MyCity[cixNew].Loc>=0) or (cixNew=cix);1491 if cixNew<>cix then1492 MainScreen.ZoomToCity(MyCity[cixNew].Loc);1723 cixNew: integer; 1724 begin 1725 cixNew := cix; 1726 repeat 1727 cixNew := (cixNew + MyRO.nCity + d) mod MyRO.nCity; 1728 until (MyCity[cixNew].Loc >= 0) or (cixNew = cix); 1729 if cixNew <> cix then 1730 MainScreen.ZoomToCity(MyCity[cixNew].Loc); 1493 1731 end; 1494 1732 … … 1496 1734 Shift: TShiftState); 1497 1735 begin 1498 if ((Key=VK_UP) or (Key=VK_NUMPAD8)) 1499 and (cix>=0) and (WindowMode=wmPersistent) then 1500 ChangeCity(-1) 1501 else if ((Key=VK_DOWN) or (Key=VK_NUMPAD2)) 1502 and (cix>=0) and (WindowMode=wmPersistent) then 1503 ChangeCity(+1) 1504 else inherited 1505 end; 1506 1507 {procedure TCityDlg.AdviceBtnClick(Sender: TObject); 1508 begin 1509 AdvisorDlg.GiveCityAdvice(cix); 1510 end;} 1736 if ((Key = VK_UP) or (Key = VK_NUMPAD8)) and (cix >= 0) and 1737 (WindowMode = wmPersistent) then 1738 ChangeCity(-1) 1739 else if ((Key = VK_DOWN) or (Key = VK_NUMPAD2)) and (cix >= 0) and 1740 (WindowMode = wmPersistent) then 1741 ChangeCity(+1) 1742 else 1743 inherited 1744 end; 1745 1746 { procedure TCityDlg.AdviceBtnClick(Sender: TObject); 1747 begin 1748 AdvisorDlg.GiveCityAdvice(cix); 1749 end; } 1511 1750 1512 1751 var 1513 i,j,k: integer;1752 i, j, k: integer; 1514 1753 1515 1754 procedure TCityDlg.PageUpBtnClick(Sender: TObject); 1516 1755 begin 1517 if Page>0 then1518 begin 1519 dec(Page);1520 SmartUpdateContent1756 if Page > 0 then 1757 begin 1758 dec(Page); 1759 SmartUpdateContent 1521 1760 end 1522 1761 end; … … 1524 1763 procedure TCityDlg.PageDownBtnClick(Sender: TObject); 1525 1764 begin 1526 if Page<PageCount-1 then1527 begin 1528 inc(Page);1529 SmartUpdateContent1765 if Page < PageCount - 1 then 1766 begin 1767 inc(Page); 1768 SmartUpdateContent 1530 1769 end 1531 1770 end; … … 1533 1772 procedure TCityDlg.ChangeResourceWeights(iResourceWeights: integer); 1534 1773 var 1535 Advice: TCityTileAdviceData; 1536 begin 1537 assert(not supervising); 1538 assert(cix>=0); 1539 MyCity[cix].Status:=MyCity[cix].Status 1540 and not csResourceWeightsMask or (iResourceWeights shl 4); 1541 c.Status:=MyCity[cix].Status; 1542 if iResourceWeights>0 then 1543 begin 1544 Advice.ResourceWeights:=OfferedResourceWeights[iResourceWeights]; 1545 Server(sGetCityTileAdvice,me,cix,Advice); 1546 if Advice.Tiles<>MyCity[cix].Tiles then 1547 Server(sSetCityTiles,me,cix,Advice.Tiles); 1548 end 1549 end; 1550 1774 Advice: TCityTileAdviceData; 1775 begin 1776 assert(not supervising); 1777 assert(cix >= 0); 1778 MyCity[cix].Status := MyCity[cix].Status and not csResourceWeightsMask or 1779 (iResourceWeights shl 4); 1780 c.Status := MyCity[cix].Status; 1781 if iResourceWeights > 0 then 1782 begin 1783 Advice.ResourceWeights := OfferedResourceWeights[iResourceWeights]; 1784 Server(sGetCityTileAdvice, me, cix, Advice); 1785 if Advice.Tiles <> MyCity[cix].Tiles then 1786 Server(sSetCityTiles, me, cix, Advice.Tiles); 1787 end 1788 end; 1551 1789 1552 1790 initialization 1553 for i:=0 to nImp-1 do ImpSorted[i]:=i; 1554 for i:=0 to nImp-2 do for j:=i+1 to nImp-1 do 1555 if Prio(ImpSorted[i])>Prio(ImpSorted[j]) then 1556 begin k:=ImpSorted[i]; ImpSorted[i]:=ImpSorted[j]; ImpSorted[j]:=k end; 1791 1792 for i := 0 to nImp - 1 do 1793 ImpSorted[i] := i; 1794 for i := 0 to nImp - 2 do 1795 for j := i + 1 to nImp - 1 do 1796 if Prio(ImpSorted[i]) > Prio(ImpSorted[j]) then 1797 begin 1798 k := ImpSorted[i]; 1799 ImpSorted[i] := ImpSorted[j]; 1800 ImpSorted[j] := k 1801 end; 1802 1557 1803 end. 1558 -
trunk/LocalPlayer/CityType.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit CityType; 4 3 … … 6 5 7 6 uses 8 Protocol, ClientTools,Term,ScreenTools,BaseWin,7 Protocol, ClientTools, Term, ScreenTools, BaseWin, 9 8 10 9 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, … … 26 25 procedure DeleteBtnClick(Sender: TObject); 27 26 public 28 procedure ShowNewContent(NewMode: integer); 27 procedure ShowNewContent(NewMode: integer); 29 28 protected 30 29 procedure OffscreenPaint; override; 31 30 private 32 nPool, dragiix,ctype: integer;33 Pooliix: array [0..nImp-1] of integer;34 listed: Set of 0 ..nImp;31 nPool, dragiix, ctype: integer; 32 Pooliix: array [0 .. nImp - 1] of integer; 33 listed: Set of 0 .. nImp; 35 34 Changed: boolean; 36 35 procedure LoadType(NewType: integer); … … 48 47 49 48 const 50 xList=7; yList=0; 51 nListRow=4; nListCol=10; 52 xPool=7; yPool=220; 53 nPoolRow=4; nPoolCol=10; 54 xSwitch=7; ySwitch=150; 55 xView=226; yView=130; 56 57 procedure TCityTypeDlg.FormCreate(Sender:TObject); 58 begin 59 inherited; 60 CaptionRight:=CloseBtn.Left; 61 InitButtons(); 62 HelpContext:='MACRO'; 63 Caption:=Phrases.Lookup('TITLE_CITYTYPES'); 64 DeleteBtn.Hint:=Phrases.Lookup('BTN_DELETE'); 65 end; 66 67 procedure TCityTypeDlg.CloseBtnClick(Sender:TObject); 68 begin 69 Close 70 end; 71 72 procedure TCityTypeDlg.FormPaint(Sender:TObject); 73 begin 74 inherited; 75 BtnFrame(Canvas,DeleteBtn.BoundsRect,MainTexture); 49 xList = 7; 50 yList = 0; 51 nListRow = 4; 52 nListCol = 10; 53 xPool = 7; 54 yPool = 220; 55 nPoolRow = 4; 56 nPoolCol = 10; 57 xSwitch = 7; 58 ySwitch = 150; 59 xView = 226; 60 yView = 130; 61 62 procedure TCityTypeDlg.FormCreate(Sender: TObject); 63 begin 64 inherited; 65 CaptionRight := CloseBtn.Left; 66 InitButtons(); 67 HelpContext := 'MACRO'; 68 Caption := Phrases.Lookup('TITLE_CITYTYPES'); 69 DeleteBtn.Hint := Phrases.Lookup('BTN_DELETE'); 70 end; 71 72 procedure TCityTypeDlg.CloseBtnClick(Sender: TObject); 73 begin 74 Close 75 end; 76 77 procedure TCityTypeDlg.FormPaint(Sender: TObject); 78 begin 79 inherited; 80 BtnFrame(Canvas, DeleteBtn.BoundsRect, MainTexture); 76 81 end; 77 82 78 83 procedure TCityTypeDlg.OffscreenPaint; 79 84 var 80 i,iix: integer; 81 s: string; 82 begin 83 inherited; 84 offscreen.Canvas.Font.Assign(UniFont[ftSmall]); 85 FillOffscreen(xList-7,yList,42*nListCol+14,32*nListRow); 86 FillOffscreen(xPool-7,yPool,42*nPoolCol+14,32*nPoolRow); 87 FillOffscreen(0,yList+32*nListRow,42*nPoolCol+14,yPool-yList-32*nListRow); 88 89 Frame(offscreen.Canvas,0,yList+32*nListRow,InnerWidth-255,yPool-23, 90 MainTexture.clBevelLight,MainTexture.clBevelShade); 91 Frame(offscreen.Canvas,InnerWidth-254,yList+32*nListRow,InnerWidth-89,yPool-23, 92 MainTexture.clBevelLight,MainTexture.clBevelShade); 93 Frame(offscreen.Canvas,InnerWidth-88,yList+32*nListRow,InnerWidth-1,yPool-23, 94 MainTexture.clBevelLight,MainTexture.clBevelShade); 95 Frame(offscreen.Canvas,0,yPool-22,InnerWidth-1,yPool-1, 96 MainTexture.clBevelLight,MainTexture.clBevelShade); 97 for i:=0 to nCityType-1 do 98 begin 99 RFrame(offscreen.Canvas,xSwitch+i*42,ySwitch,xSwitch+39+i*42,ySwitch+23, 100 MainTexture.clBevelShade,MainTexture.clBevelLight); 101 if i=ctype then 102 Frame(offscreen.Canvas,xSwitch+1+i*42,ySwitch+1,xSwitch+38+i*42,ySwitch+22, 103 MainTexture.clBevelShade,MainTexture.clBevelLight) 104 else Frame(offscreen.Canvas,xSwitch+1+i*42,ySwitch+1,xSwitch+38+i*42,ySwitch+22, 105 MainTexture.clBevelLight,MainTexture.clBevelShade); 106 BitBlt(offscreen.Canvas.Handle,xSwitch+2+i*42,ySwitch+2,xSizeSmall, 107 ySizeSmall,SmallImp.Canvas.Handle,(i+3)*xSizeSmall,0,SRCCOPY) 108 end; 109 RisedTextOut(offscreen.Canvas,8,yList+32*nListRow+2,Phrases.Lookup('BUILDORDER')); 110 RisedTextOut(offscreen.Canvas,8,ySwitch+26,Phrases.Lookup('CITYTYPE',ctype)); 111 s:=Phrases.Lookup('BUILDREST'); 112 RisedTextOut(offscreen.Canvas,(InnerWidth-BiColorTextWidth(Offscreen.Canvas,s)) div 2, 113 yList+72+32*nListRow,s); 114 115 with offscreen.Canvas do 116 begin 117 for i:=1 to nListRow-1 do 118 DLine(offscreen.Canvas,xList-5,xList+4+42*nListCol,yList-1+32*i, 119 MainTexture.clBevelLight,MainTexture.clBevelShade); 120 for i:=0 to nListCol*nListRow-1 do 121 begin 122 s:=IntToStr(i+1); 123 Font.Color:=MainTexture.clTextLight; 124 Textout(xList+20+i mod nListCol *42-TextWidth(s) div 2, 125 yList+15+i div nListCol *32-TextHeight(s) div 2,s); 85 i, iix: integer; 86 s: string; 87 begin 88 inherited; 89 offscreen.Canvas.Font.Assign(UniFont[ftSmall]); 90 FillOffscreen(xList - 7, yList, 42 * nListCol + 14, 32 * nListRow); 91 FillOffscreen(xPool - 7, yPool, 42 * nPoolCol + 14, 32 * nPoolRow); 92 FillOffscreen(0, yList + 32 * nListRow, 42 * nPoolCol + 14, 93 yPool - yList - 32 * nListRow); 94 95 Frame(offscreen.Canvas, 0, yList + 32 * nListRow, InnerWidth - 255, 96 yPool - 23, MainTexture.clBevelLight, MainTexture.clBevelShade); 97 Frame(offscreen.Canvas, InnerWidth - 254, yList + 32 * nListRow, 98 InnerWidth - 89, yPool - 23, MainTexture.clBevelLight, 99 MainTexture.clBevelShade); 100 Frame(offscreen.Canvas, InnerWidth - 88, yList + 32 * nListRow, 101 InnerWidth - 1, yPool - 23, MainTexture.clBevelLight, 102 MainTexture.clBevelShade); 103 Frame(offscreen.Canvas, 0, yPool - 22, InnerWidth - 1, yPool - 1, 104 MainTexture.clBevelLight, MainTexture.clBevelShade); 105 for i := 0 to nCityType - 1 do 106 begin 107 RFrame(offscreen.Canvas, xSwitch + i * 42, ySwitch, xSwitch + 39 + i * 42, 108 ySwitch + 23, MainTexture.clBevelShade, MainTexture.clBevelLight); 109 if i = ctype then 110 Frame(offscreen.Canvas, xSwitch + 1 + i * 42, ySwitch + 1, 111 xSwitch + 38 + i * 42, ySwitch + 22, MainTexture.clBevelShade, 112 MainTexture.clBevelLight) 113 else 114 Frame(offscreen.Canvas, xSwitch + 1 + i * 42, ySwitch + 1, 115 xSwitch + 38 + i * 42, ySwitch + 22, MainTexture.clBevelLight, 116 MainTexture.clBevelShade); 117 BitBlt(offscreen.Canvas.Handle, xSwitch + 2 + i * 42, ySwitch + 2, 118 xSizeSmall, ySizeSmall, SmallImp.Canvas.Handle, (i + 3) * xSizeSmall, 119 0, SRCCOPY) 120 end; 121 RisedTextOut(offscreen.Canvas, 8, yList + 32 * nListRow + 2, 122 Phrases.Lookup('BUILDORDER')); 123 RisedTextOut(offscreen.Canvas, 8, ySwitch + 26, 124 Phrases.Lookup('CITYTYPE', ctype)); 125 s := Phrases.Lookup('BUILDREST'); 126 RisedTextOut(offscreen.Canvas, 127 (InnerWidth - BiColorTextWidth(offscreen.Canvas, s)) div 2, 128 yList + 72 + 32 * nListRow, s); 129 130 with offscreen.Canvas do 131 begin 132 for i := 1 to nListRow - 1 do 133 DLine(offscreen.Canvas, xList - 5, xList + 4 + 42 * nListCol, 134 yList - 1 + 32 * i, MainTexture.clBevelLight, MainTexture.clBevelShade); 135 for i := 0 to nListCol * nListRow - 1 do 136 begin 137 s := IntToStr(i + 1); 138 Font.Color := MainTexture.clTextLight; 139 Textout(xList + 20 + i mod nListCol * 42 - TextWidth(s) div 2, 140 yList + 15 + i div nListCol * 32 - TextHeight(s) div 2, s); 126 141 end 127 142 end; 128 143 129 i:=0; 130 while MyData.ImpOrder[ctype,i]>=0 do 131 begin 132 RFrame(offscreen.Canvas, 133 xList+20-xSizeSmall div 2 + i mod nListCol *42, 134 yList+15-ySizeSmall div 2 + i div nListCol *32, 135 xList+21+xSizeSmall div 2 + i mod nListCol *42, 136 yList+16+ySizeSmall div 2 + i div nListCol *32, 137 MainTexture.clBevelLight,MainTexture.clBevelShade); 138 BitBlt(offscreen.Canvas.Handle, 139 xList+21-xSizeSmall div 2 + i mod nListCol *42, 140 yList+16-ySizeSmall div 2 + i div nListCol *32, 141 xSizeSmall,ySizeSmall,SmallImp.Canvas.Handle, 142 MyData.ImpOrder[ctype,i] mod 7*xSizeSmall, 143 (MyData.ImpOrder[ctype,i]+SystemIconLines*7) div 7*ySizeSmall,SRCCOPY); 144 inc(i); 145 end; 146 147 nPool:=0; 148 for iix:=28 to nImp-1 do 149 if not (iix in listed) and (Imp[iix].Kind=ikCommon) and (iix<>imTrGoods) 150 and (Imp[iix].Preq<>preNA) 151 and ((Imp[iix].Preq=preNone) or (MyRO.Tech[Imp[iix].Preq]>=tsApplicable)) then 152 begin 153 Pooliix[nPool]:=iix; 154 RFrame(offscreen.Canvas, 155 xPool+20-xSizeSmall div 2 + nPool mod nPoolCol *42, 156 yPool+15-ySizeSmall div 2 + nPool div nPoolCol *32, 157 xPool+21+xSizeSmall div 2 + nPool mod nPoolCol *42, 158 yPool+16+ySizeSmall div 2 + nPool div nPoolCol *32, 144 i := 0; 145 while MyData.ImpOrder[ctype, i] >= 0 do 146 begin 147 RFrame(offscreen.Canvas, xList + 20 - xSizeSmall div 2 + i mod nListCol * 148 42, yList + 15 - ySizeSmall div 2 + i div nListCol * 32, 149 xList + 21 + xSizeSmall div 2 + i mod nListCol * 42, 150 yList + 16 + ySizeSmall div 2 + i div nListCol * 32, 159 151 MainTexture.clBevelLight, MainTexture.clBevelShade); 160 BitBlt(offscreen.Canvas.Handle, 161 xPool+21-xSizeSmall div 2 + nPool mod nPoolCol *42, 162 yPool+16-ySizeSmall div 2 + nPool div nPoolCol *32, 163 xSizeSmall,ySizeSmall,SmallImp.Canvas.Handle, 164 iix mod 7*xSizeSmall,(iix+SystemIconLines*7) div 7*ySizeSmall,SRCCOPY); 165 inc(nPool) 152 BitBlt(offscreen.Canvas.Handle, xList + 21 - xSizeSmall div 2 + 153 i mod nListCol * 42, yList + 16 - ySizeSmall div 2 + i div nListCol * 32, 154 xSizeSmall, ySizeSmall, SmallImp.Canvas.Handle, 155 MyData.ImpOrder[ctype, i] mod 7 * xSizeSmall, 156 (MyData.ImpOrder[ctype, i] + SystemIconLines * 7) div 7 * 157 ySizeSmall, SRCCOPY); 158 inc(i); 159 end; 160 161 nPool := 0; 162 for iix := 28 to nImp - 1 do 163 if not(iix in listed) and (Imp[iix].Kind = ikCommon) and (iix <> imTrGoods) 164 and (Imp[iix].Preq <> preNA) and 165 ((Imp[iix].Preq = preNone) or (MyRO.Tech[Imp[iix].Preq] >= tsApplicable)) 166 then 167 begin 168 Pooliix[nPool] := iix; 169 RFrame(offscreen.Canvas, xPool + 20 - xSizeSmall div 2 + 170 nPool mod nPoolCol * 42, yPool + 15 - ySizeSmall div 2 + 171 nPool div nPoolCol * 32, xPool + 21 + xSizeSmall div 2 + 172 nPool mod nPoolCol * 42, yPool + 16 + ySizeSmall div 2 + 173 nPool div nPoolCol * 32, MainTexture.clBevelLight, 174 MainTexture.clBevelShade); 175 BitBlt(offscreen.Canvas.Handle, xPool + 21 - xSizeSmall div 2 + 176 nPool mod nPoolCol * 42, yPool + 16 - ySizeSmall div 2 + 177 nPool div nPoolCol * 32, xSizeSmall, ySizeSmall, SmallImp.Canvas.Handle, 178 iix mod 7 * xSizeSmall, (iix + SystemIconLines * 7) div 7 * 179 ySizeSmall, SRCCOPY); 180 inc(nPool) 166 181 end; 167 DeleteBtn.Visible:= MyData.ImpOrder[ctype,0]>=0; 168 169 if dragiix>=0 then 170 begin 171 ImpImage(offscreen.Canvas,xView+9,yView+5,dragiix); 172 s:=Phrases.Lookup('IMPROVEMENTS',dragiix); 173 RisedTextOut(offscreen.Canvas,xView+36-BiColorTextWidth(Offscreen.Canvas,s) div 2, 174 ySwitch+26,s); 175 end; 176 MarkUsedOffscreen(InnerWidth,InnerHeight); 177 end; {MainPaint} 182 DeleteBtn.Visible := MyData.ImpOrder[ctype, 0] >= 0; 183 184 if dragiix >= 0 then 185 begin 186 ImpImage(offscreen.Canvas, xView + 9, yView + 5, dragiix); 187 s := Phrases.Lookup('IMPROVEMENTS', dragiix); 188 RisedTextOut(offscreen.Canvas, 189 xView + 36 - BiColorTextWidth(offscreen.Canvas, s) div 2, 190 ySwitch + 26, s); 191 end; 192 MarkUsedOffscreen(InnerWidth, InnerHeight); 193 end; { MainPaint } 178 194 179 195 procedure TCityTypeDlg.LoadType(NewType: integer); 180 196 var 181 i: integer; 182 begin 183 ctype:=NewType; 184 listed:=[]; 185 i:=0; 186 while MyData.ImpOrder[ctype,i]>=0 do 187 begin include(listed,MyData.ImpOrder[ctype,i]); inc(i) end; 188 Changed:=false 197 i: integer; 198 begin 199 ctype := NewType; 200 listed := []; 201 i := 0; 202 while MyData.ImpOrder[ctype, i] >= 0 do 203 begin 204 include(listed, MyData.ImpOrder[ctype, i]); 205 inc(i) 206 end; 207 Changed := false 189 208 end; 190 209 191 210 procedure TCityTypeDlg.SaveType; 192 211 var 193 cix: integer;194 begin 195 if Changed then196 begin 197 for cix:=0 to MyRO.nCity-1 do198 if (MyCity[cix].Loc>=0) and (MyCity[cix].Status and 7=ctype+1) then199 AutoBuild(cix, MyData.ImpOrder[ctype]);200 Changed:=false212 cix: integer; 213 begin 214 if Changed then 215 begin 216 for cix := 0 to MyRO.nCity - 1 do 217 if (MyCity[cix].Loc >= 0) and (MyCity[cix].Status and 7 = ctype + 1) then 218 AutoBuild(cix, MyData.ImpOrder[ctype]); 219 Changed := false 201 220 end; 202 221 end; … … 204 223 procedure TCityTypeDlg.FormShow(Sender: TObject); 205 224 begin 206 LoadType(0);207 dragiix:=-1;208 OffscreenPaint;225 LoadType(0); 226 dragiix := -1; 227 OffscreenPaint; 209 228 end; 210 229 211 230 procedure TCityTypeDlg.ShowNewContent(NewMode: integer); 212 231 begin 213 inherited ShowNewContent(NewMode); 214 end; 215 216 procedure TCityTypeDlg.PaintBox1MouseDown(Sender: TObject; 217 Button: TMouseButton; Shift: TShiftState; x, y: integer); 218 var 219 i: integer; 220 begin 221 x:=x-SideFrame; y:=y-WideFrame; 222 i:=(x-xList) div 42+(y-yList) div 32 *nListCol; 223 if (i<nImp) and (MyData.ImpOrder[ctype,i]>=0) 224 and (x>xList+2+ i mod nListCol *42) and (y>yList+5+ i div nListCol *32) 225 and (x<xList+3+36+ i mod nListCol *42) and (y<yList+6+20+ i div nListCol *32) then 226 begin 227 if ssShift in Shift then 228 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkImp, MyData.ImpOrder[ctype,i]) 229 else 230 begin 231 dragiix:=MyData.ImpOrder[ctype,i]; 232 Screen.Cursor:=crImpDrag; 232 inherited ShowNewContent(NewMode); 233 end; 234 235 procedure TCityTypeDlg.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; 236 Shift: TShiftState; x, y: integer); 237 var 238 i: integer; 239 begin 240 x := x - SideFrame; 241 y := y - WideFrame; 242 i := (x - xList) div 42 + (y - yList) div 32 * nListCol; 243 if (i < nImp) and (MyData.ImpOrder[ctype, i] >= 0) and 244 (x > xList + 2 + i mod nListCol * 42) and 245 (y > yList + 5 + i div nListCol * 32) and 246 (x < xList + 3 + 36 + i mod nListCol * 42) and 247 (y < yList + 6 + 20 + i div nListCol * 32) then 248 begin 249 if ssShift in Shift then 250 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkImp, 251 MyData.ImpOrder[ctype, i]) 252 else 253 begin 254 dragiix := MyData.ImpOrder[ctype, i]; 255 Screen.Cursor := crImpDrag; 256 SmartUpdateContent 257 end; 258 exit; 259 end; 260 i := (x - xPool) div 42 + (y - yPool) div 32 * nPoolCol; 261 if (i < nPool) and (x > xPool + 2 + i mod nPoolCol * 42) and 262 (y > yPool + 5 + i div nPoolCol * 32) and 263 (x < xPool + 3 + 36 + i mod nPoolCol * 42) and 264 (y < yPool + 6 + 20 + i div nPoolCol * 32) then 265 begin 266 if ssShift in Shift then 267 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkImp, Pooliix[i]) 268 else 269 begin 270 dragiix := Pooliix[i]; 271 Screen.Cursor := crImpDrag; 272 SmartUpdateContent 273 end; 274 exit; 275 end; 276 i := (x - xSwitch) div 42; 277 if (i < nCityType) and (x > xSwitch + 2 + i * 42) and 278 (x < xSwitch + 3 + 36 + i * 42) and (y >= ySwitch + 2) and (y < ySwitch + 22) 279 then 280 begin 281 SaveType; 282 LoadType(i); 233 283 SmartUpdateContent 234 end;235 exit;236 end;237 i:=(x-xPool) div 42+(y-yPool) div 32 *nPoolCol;238 if (i<nPool) and (x>xPool+2+ i mod nPoolCol *42)239 and (y>yPool+5+ i div nPoolCol *32) and (x<xPool+3+36+ i mod nPoolCol *42)240 and (y<yPool+6+20+ i div nPoolCol *32) then241 begin242 if ssShift in Shift then243 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkImp, Pooliix[i])244 else245 begin246 dragiix:=Pooliix[i];247 Screen.Cursor:=crImpDrag;248 SmartUpdateContent249 end;250 exit;251 end;252 i:=(x-xSwitch) div 42;253 if (i<nCityType) and (x>xSwitch+2+ i*42) and (x<xSwitch+3+36+i*42)254 and (y>=ySwitch+2) and (y<ySwitch+22) then255 begin256 SaveType;257 LoadType(i);258 SmartUpdateContent259 284 end 260 285 end; … … 265 290 procedure UnList(iix: integer); 266 291 var 292 i: integer; 293 begin 294 i := 0; 295 while (MyData.ImpOrder[ctype, i] >= 0) and 296 (MyData.ImpOrder[ctype, i] <> iix) do 297 inc(i); 298 assert(MyData.ImpOrder[ctype, i] = iix); 299 move(MyData.ImpOrder[ctype, i + 1], MyData.ImpOrder[ctype, i], nImp - i); 300 Exclude(listed, iix); 301 end; 302 303 var 267 304 i: integer; 268 begin 269 i:=0; 270 while (MyData.ImpOrder[ctype,i]>=0) and (MyData.ImpOrder[ctype,i]<>iix) do 271 inc(i); 272 assert(MyData.ImpOrder[ctype,i]=iix); 273 move(MyData.ImpOrder[ctype,i+1],MyData.ImpOrder[ctype,i],nImp-i); 274 Exclude(listed,iix); 275 end; 276 277 var 278 i: integer; 279 begin 280 x:=x-SideFrame; y:=y-WideFrame; 281 if dragiix>=0 then 282 begin 283 if (x>=xList) and (x<xList+nListCol*42) 284 and (y>=yList) and (y<yList+nListRow*32) then 285 begin 286 if dragiix in listed then UnList(dragiix); 287 i:=(x-xList) div 42+(y-yList) div 32 *nListCol; 288 while (i>0) and (MyData.ImpOrder[ctype,i-1]<0) do dec(i); 289 move(MyData.ImpOrder[ctype,i],MyData.ImpOrder[ctype,i+1],nImp-i-1); 290 MyData.ImpOrder[ctype,i]:=dragiix; 291 include(listed,dragiix); 292 Changed:=true 305 begin 306 x := x - SideFrame; 307 y := y - WideFrame; 308 if dragiix >= 0 then 309 begin 310 if (x >= xList) and (x < xList + nListCol * 42) and (y >= yList) and 311 (y < yList + nListRow * 32) then 312 begin 313 if dragiix in listed then 314 UnList(dragiix); 315 i := (x - xList) div 42 + (y - yList) div 32 * nListCol; 316 while (i > 0) and (MyData.ImpOrder[ctype, i - 1] < 0) do 317 dec(i); 318 move(MyData.ImpOrder[ctype, i], MyData.ImpOrder[ctype, i + 1], 319 nImp - i - 1); 320 MyData.ImpOrder[ctype, i] := dragiix; 321 include(listed, dragiix); 322 Changed := true 293 323 end 294 else if (dragiix in listed) and (x>=xPool) and (x<xPool+nPoolCol*42)295 and (y>=yPool) and (y<yPool+nPoolRow*32) then296 begin 297 UnList(dragiix);298 Changed:=true324 else if (dragiix in listed) and (x >= xPool) and (x < xPool + nPoolCol * 42) 325 and (y >= yPool) and (y < yPool + nPoolRow * 32) then 326 begin 327 UnList(dragiix); 328 Changed := true 299 329 end; 300 dragiix:=-1; 330 dragiix := -1; 331 SmartUpdateContent 332 end; 333 Screen.Cursor := crDefault 334 end; 335 336 procedure TCityTypeDlg.FormClose(Sender: TObject; var Action: TCloseAction); 337 begin 338 SaveType; 339 inherited; 340 end; 341 342 procedure TCityTypeDlg.DeleteBtnClick(Sender: TObject); 343 begin 344 fillchar(MyData.ImpOrder[ctype], sizeof(MyData.ImpOrder[ctype]), -1); 345 listed := []; 346 Changed := true; 301 347 SmartUpdateContent 302 end;303 Screen.Cursor:=crDefault304 end;305 306 procedure TCityTypeDlg.FormClose(Sender: TObject; var Action: TCloseAction);307 begin308 SaveType;309 inherited;310 end;311 312 procedure TCityTypeDlg.DeleteBtnClick(Sender: TObject);313 begin314 fillchar(MyData.ImpOrder[ctype],sizeof(MyData.ImpOrder[ctype]),-1);315 listed:=[];316 Changed:=true;317 SmartUpdateContent318 348 end; 319 349 320 350 end. 321 -
trunk/LocalPlayer/ClientTools.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit ClientTools; 4 3 … … 9 8 10 9 const 11 nOfferedResourceWeights=6;12 OfferedResourceWeights: array[0..nOfferedResourceWeights-1] of cardinal=13 (rwOff, rwMaxScience, rwForceScience, rwMaxGrowth, rwForceProd, rwMaxProd);10 nOfferedResourceWeights = 6; 11 OfferedResourceWeights: array [0 .. nOfferedResourceWeights - 1] of cardinal = 12 (rwOff, rwMaxScience, rwForceScience, rwMaxGrowth, rwForceProd, rwMaxProd); 14 13 15 14 type 16 TImpOrder=array[0..(nImp+4) div 4 *4 -1] of ShortInt;17 TEnhancementJobs=array[0..11,0..7] of Byte;18 JobResultSet=set of 0..39;15 TImpOrder = array [0 .. (nImp + 4) div 4 * 4 - 1] of ShortInt; 16 TEnhancementJobs = array [0 .. 11, 0 .. 7] of Byte; 17 JobResultSet = set of 0 .. 39; 19 18 20 19 var 21 Server: TServerCall; 22 G: TNewGameData; 23 me: integer; 24 MyRO: ^TPlayerContext; 25 MyMap: ^TTileList; 26 MyUn: ^TUnList; 27 MyCity: ^TCityList; 28 MyModel: ^TModelList; 29 30 AdvValue: array[0..nAdv-1] of integer; 31 32 33 function dLoc(Loc,dx,dy: integer): integer; 34 function Distance(Loc0,Loc1: integer): integer; 35 function UnrestAtLoc(uix,Loc: integer): boolean; 20 Server: TServerCall; 21 G: TNewGameData; 22 me: integer; 23 MyRO: ^TPlayerContext; 24 MyMap: ^TTileList; 25 MyUn: ^TUnList; 26 MyCity: ^TCityList; 27 MyModel: ^TModelList; 28 29 AdvValue: array [0 .. nAdv - 1] of integer; 30 31 function dLoc(Loc, dx, dy: integer): integer; 32 function Distance(Loc0, Loc1: integer): integer; 33 function UnrestAtLoc(uix, Loc: integer): boolean; 36 34 function GetMoveAdvice(uix, ToLoc: integer; 37 35 var MoveAdviceData: TMoveAdviceData): integer; … … 43 41 function IsMilReportNew(Enemy: integer): boolean; 44 42 function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean; 45 gov,size: integer): integer; 46 function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer; 43 gov, size: integer): integer; 44 function CityTaxBalance(cix: integer; const CityReport: TCityReportNew) 45 : integer; 47 46 procedure SumCities(var TaxSum, ScienceSum: integer); 48 function JobTest(uix, Job: integer; IgnoreResults: JobResultSet = []): boolean;47 function JobTest(uix, Job: integer; IgnoreResults: JobResultSet = []): boolean; 49 48 procedure GetUnitInfo(Loc: integer; var uix: integer; var UnitInfo: TUnitInfo); 50 49 procedure GetCityInfo(Loc: integer; var cix: integer; var CityInfo: TCityInfo); 51 50 function UnitExhausted(uix: integer): boolean; 52 51 function ModelHash(const ModelInfo: TModelInfo): integer; 53 function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer; 52 function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs) 53 : integer; 54 54 function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean; 55 55 procedure DebugMessage(Level: integer; Text: string); … … 62 62 procedure CityOptimizer_EndOfTurn; 63 63 64 65 64 implementation 66 65 67 66 var 68 CityNeedsOptimize: array[0..ncmax-1] of boolean; 69 70 71 function dLoc(Loc,dx,dy: integer): integer; 67 CityNeedsOptimize: array [0 .. ncmax - 1] of boolean; 68 69 function dLoc(Loc, dx, dy: integer): integer; 72 70 var 73 y0: integer;71 y0: integer; 74 72 begin 75 y0:=(Loc+G.lx*1024) div G.lx -1024; 76 result:=(Loc+(dx+y0 and 1+G.lx*1024) shr 1) mod G.lx +G.lx*(y0+dy) 73 y0 := (Loc + G.lx * 1024) div G.lx - 1024; 74 result := (Loc + (dx + y0 and 1 + G.lx * 1024) shr 1) mod G.lx + G.lx 75 * (y0 + dy) 77 76 end; 78 77 79 function Distance(Loc0, Loc1: integer): integer;78 function Distance(Loc0, Loc1: integer): integer; 80 79 var 81 dx,dy: integer;80 dx, dy: integer; 82 81 begin 83 inc(Loc0,G.lx*1024);84 inc(Loc1,G.lx*1024);85 dx:=abs(((Loc1 mod G.lx *2 +Loc1 div G.lx and 1) 86 -(Loc0 mod G.lx *2 +Loc0 div G.lx and 1)+3*G.lx) mod (2*G.lx) -G.lx);87 dy:=abs(Loc1 div G.lx-Loc0 div G.lx);88 result:=dx+dy+abs(dx-dy) shr 1;82 inc(Loc0, G.lx * 1024); 83 inc(Loc1, G.lx * 1024); 84 dx := abs(((Loc1 mod G.lx * 2 + Loc1 div G.lx and 1) - (Loc0 mod G.lx * 2 + 85 Loc0 div G.lx and 1) + 3 * G.lx) mod (2 * G.lx) - G.lx); 86 dy := abs(Loc1 div G.lx - Loc0 div G.lx); 87 result := dx + dy + abs(dx - dy) shr 1; 89 88 end; 90 89 91 function UnrestAtLoc(uix, Loc: integer): boolean;90 function UnrestAtLoc(uix, Loc: integer): boolean; 92 91 var 93 uix1: integer;92 uix1: integer; 94 93 begin 95 result:=false;96 if MyModel[MyUn[uix].mix].Flags and mdCivil=0 then97 case MyRO.Government of98 gRepublic, gFuture:99 result:=(MyRO.Territory[Loc]>=0) and (MyRO.Territory[Loc]<>me)100 and (MyRO.Treaty[MyRO.Territory[Loc]]<trAlliance);101 gDemocracy:102 result:=(MyRO.Territory[Loc]<0) or (MyRO.Territory[Loc]<>me)103 and (MyRO.Treaty[MyRO.Territory[Loc]]<trAlliance);94 result := false; 95 if MyModel[MyUn[uix].mix].Flags and mdCivil = 0 then 96 case MyRO.Government of 97 gRepublic, gFuture: 98 result := (MyRO.Territory[Loc] >= 0) and (MyRO.Territory[Loc] <> me) and 99 (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance); 100 gDemocracy: 101 result := (MyRO.Territory[Loc] < 0) or (MyRO.Territory[Loc] <> me) and 102 (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance); 104 103 end; 105 with MyModel[MyUn[uix].mix] do106 if Cap[mcSeaTrans]+Cap[mcAirTrans]+Cap[mcCarrier]>0 then107 for uix1:=0 to MyRO.nUn-1 do // check transported units too108 if (MyUn[uix1].Loc>=0) and (MyUn[uix1].Master=uix) then109 result:=result or UnrestAtLoc(uix1,Loc);104 with MyModel[MyUn[uix].mix] do 105 if Cap[mcSeaTrans] + Cap[mcAirTrans] + Cap[mcCarrier] > 0 then 106 for uix1 := 0 to MyRO.nUn - 1 do // check transported units too 107 if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) then 108 result := result or UnrestAtLoc(uix1, Loc); 110 109 end; 111 110 112 function GetMoveAdvice(uix, ToLoc: integer; var MoveAdviceData: TMoveAdviceData): integer; 111 function GetMoveAdvice(uix, ToLoc: integer; 112 var MoveAdviceData: TMoveAdviceData): integer; 113 113 var 114 MinEndHealth: integer;114 MinEndHealth: integer; 115 115 begin 116 if MyModel[MyUn[uix].mix].Domain=dGround then MinEndHealth:=100 117 else MinEndHealth:=1; // resistent to hostile terrain -- don't consider 118 repeat 119 if MyUn[uix].Health>=MinEndHealth then 120 begin 121 MoveAdviceData.ToLoc:=ToLoc; 122 MoveAdviceData.MoreTurns:=999; 123 MoveAdviceData.MaxHostile_MovementLeft:=MyUn[uix].Health-MinEndHealth; 124 result:=Server(sGetMoveAdvice,me,uix,MoveAdviceData); 125 if (MinEndHealth<=1) or (result<>eNoWay) then exit; 116 if MyModel[MyUn[uix].mix].Domain = dGround then 117 MinEndHealth := 100 118 else 119 MinEndHealth := 1; // resistent to hostile terrain -- don't consider 120 repeat 121 if MyUn[uix].Health >= MinEndHealth then 122 begin 123 MoveAdviceData.ToLoc := ToLoc; 124 MoveAdviceData.MoreTurns := 999; 125 MoveAdviceData.MaxHostile_MovementLeft := MyUn[uix].Health - MinEndHealth; 126 result := Server(sGetMoveAdvice, me, uix, MoveAdviceData); 127 if (MinEndHealth <= 1) or (result <> eNoWay) then 128 exit; 126 129 end; 127 case MinEndHealth of 128 100: MinEndHealth:=50; 129 50: MinEndHealth:=25; 130 25: MinEndHealth:=12; 131 else MinEndHealth:=1 130 case MinEndHealth of 131 100: 132 MinEndHealth := 50; 133 50: 134 MinEndHealth := 25; 135 25: 136 MinEndHealth := 12; 137 else 138 MinEndHealth := 1 132 139 end; 133 until false 134 end; 135 136 function ColorOfHealth(Health: integer): integer; 137 var 138 red,green: integer; 139 begin 140 green:=400*Health div 100; if green>200 then green:=200; 141 red:=510*(100-Health) div 100; if red>255 then red:=255; 142 result:=green shl 8 + red 143 end; 144 145 function IsMultiPlayerGame: boolean; 146 var 147 p1: integer; 148 begin 149 result:=false; 150 for p1:=1 to nPl-1 do 151 if G.RO[p1]<>nil then result:=true; 152 end; 153 154 procedure ItsMeAgain(p: integer); 155 begin 156 if G.RO[p]<>nil then 157 MyRO:=pointer(G.RO[p]) 158 else if G.SuperVisorRO[p]<>nil then 159 MyRO:=pointer(G.SuperVisorRO[p]) 160 else exit; 161 me:=p; 162 MyMap:=pointer(MyRO.Map); 163 MyUn:=pointer(MyRO.Un); 164 MyCity:=pointer(MyRO.City); 165 MyModel:=pointer(MyRO.Model); 166 end; 167 168 function GetAge(p: integer): integer; 169 var 170 i: integer; 171 begin 172 if p=me then 173 begin 174 result:=0; 175 for i:=1 to 3 do 176 if MyRO.Tech[AgePreq[i]]>=tsApplicable then result:=i; 177 end 178 else 179 begin 180 result:=0; 181 for i:=1 to 3 do 182 if MyRO.EnemyReport[p].Tech[AgePreq[i]]>=tsApplicable then result:=i; 183 end 184 end; 185 186 function IsCivilReportNew(Enemy: integer): boolean; 187 var 188 i: integer; 189 begin 190 assert(Enemy<>me); 191 i:=MyRO.EnemyReport[Enemy].TurnOfCivilReport; 192 result:= (i=MyRO.Turn) or (i=MyRO.Turn-1) and (Enemy>me); 193 end; 194 195 function IsMilReportNew(Enemy: integer): boolean; 196 var 197 i: integer; 198 begin 199 assert(Enemy<>me); 200 i:=MyRO.EnemyReport[Enemy].TurnOfMilReport; 201 result:= (i=MyRO.Turn) or (i=MyRO.Turn-1) and (Enemy>me); 202 end; 203 204 function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean; 205 gov,size: integer): integer; 206 begin 207 result:=FoodSurplus; 208 if not IsCityAlive 209 or (result>0) 210 and ((gov=gFuture) 211 or (size>=NeedAqueductSize) and (result<2)) then 212 result:=0; {no growth} 213 end; 214 215 function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer; 216 var 217 i: integer; 218 begin 219 result:=0; 220 if (CityReport.HappinessBalance>=0) {no disorder} 221 and (MyCity[cix].Flags and chCaptured=0) then // not captured 222 begin 223 inc(result, CityReport.Tax); 224 if (MyCity[cix].Project and (cpImp+cpIndex)=cpImp+imTrGoods) 225 and (CityReport.Production>0) then 226 inc(result, CityReport.Production); 227 if ((MyRO.Government=gFuture) 228 or (MyCity[cix].Size>=NeedAqueductSize) 229 and (CityReport.FoodSurplus<2)) 230 and (CityReport.FoodSurplus>0) then 231 inc(result, CityReport.FoodSurplus); 232 end; 233 for i:=28 to nImp-1 do if MyCity[cix].Built[i]>0 then 234 dec(result, Imp[i].Maint); 235 end; 236 237 procedure SumCities(var TaxSum, ScienceSum: integer); 238 var 239 cix: integer; 240 CityReport: TCityReportNew; 241 begin 242 TaxSum:=MyRO.OracleIncome; 243 ScienceSum:=0; 244 if MyRO.Government=gAnarchy then exit; 245 for cix:=0 to MyRO.nCity-1 do if MyCity[cix].Loc>=0 then 246 begin 247 CityReport.HypoTiles:=-1; 248 CityReport.HypoTaxRate:=-1; 249 CityReport.HypoLuxuryRate:=-1; 250 Server(sGetCityReportNew,me,cix,CityReport); 251 if (CityReport.HappinessBalance>=0) {no disorder} 252 and (MyCity[cix].Flags and chCaptured=0) then // not captured 253 ScienceSum:=ScienceSum+CityReport.Science; 254 TaxSum:=TaxSum+CityTaxBalance(cix, CityReport); 255 end; 256 end; 257 258 function JobTest(uix,Job: integer; IgnoreResults: JobResultSet): boolean; 259 var 260 Test: integer; 261 begin 262 Test:=Server(sStartJob+Job shl 4-sExecute,me,uix,nil^); 263 result:= (Test>=rExecuted) or (Test in IgnoreResults); 264 end; 265 266 procedure GetUnitInfo(Loc: integer; var uix: integer; var UnitInfo: TUnitInfo); 267 var 268 i,Cnt: integer; 269 begin 270 if MyMap[Loc] and fOwned<>0 then 271 begin 272 Server(sGetDefender,me,Loc,uix); 273 Cnt:=0; 274 for i:=0 to MyRO.nUn-1 do 275 if MyUn[i].Loc=Loc then inc(Cnt); 276 MakeUnitInfo(me,MyUn[uix],UnitInfo); 277 if Cnt>1 then UnitInfo.Flags:=UnitInfo.Flags or unMulti; 278 end 279 else 280 begin 281 uix:=MyRO.nEnemyUn-1; 282 while (uix>=0) and (MyRO.EnemyUn[uix].Loc<>Loc) do dec(uix); 283 UnitInfo:=MyRO.EnemyUn[uix]; 284 end 285 end;{GetUnitInfo} 286 287 procedure GetCityInfo(Loc: integer; var cix: integer; var CityInfo: TCityInfo); 288 begin 289 if MyMap[Loc] and fOwned<>0 then 290 begin 291 CityInfo.Loc:=Loc; 292 cix:=MyRO.nCity-1; 293 while (cix>=0) and (MyCity[cix].Loc<>Loc) do dec(cix); 294 with CityInfo do 295 begin 296 Owner:=me; 297 ID:=MyCity[cix].ID; 298 Size:=MyCity[cix].Size; 299 Flags:=0; 300 if MyCity[cix].Built[imPalace]>0 then inc(Flags,ciCapital); 301 if (MyCity[cix].Built[imWalls]>0) 302 or (MyMap[MyCity[cix].Loc] and fGrWall<>0) then inc(Flags,ciWalled); 303 if MyCity[cix].Built[imCoastalFort]>0 then inc(Flags,ciCoastalFort); 304 if MyCity[cix].Built[imMissileBat]>0 then inc(Flags,ciMissileBat); 305 if MyCity[cix].Built[imBunker]>0 then inc(Flags,ciBunker); 306 if MyCity[cix].Built[imSpacePort]>0 then inc(Flags,ciSpacePort); 140 until false end; 141 142 function ColorOfHealth(Health: integer): integer; 143 var 144 red, green: integer; 145 begin 146 green := 400 * Health div 100; 147 if green > 200 then 148 green := 200; 149 red := 510 * (100 - Health) div 100; 150 if red > 255 then 151 red := 255; 152 result := green shl 8 + red 153 end; 154 155 function IsMultiPlayerGame: boolean; 156 var 157 p1: integer; 158 begin 159 result := false; 160 for p1 := 1 to nPl - 1 do 161 if G.RO[p1] <> nil then 162 result := true; 163 end; 164 165 procedure ItsMeAgain(p: integer); 166 begin 167 if G.RO[p] <> nil then 168 MyRO := pointer(G.RO[p]) 169 else if G.SuperVisorRO[p] <> nil then 170 MyRO := pointer(G.SuperVisorRO[p]) 171 else 172 exit; 173 me := p; 174 MyMap := pointer(MyRO.Map); 175 MyUn := pointer(MyRO.Un); 176 MyCity := pointer(MyRO.City); 177 MyModel := pointer(MyRO.Model); 178 end; 179 180 function GetAge(p: integer): integer; 181 var 182 i: integer; 183 begin 184 if p = me then 185 begin 186 result := 0; 187 for i := 1 to 3 do 188 if MyRO.Tech[AgePreq[i]] >= tsApplicable then 189 result := i; 307 190 end 308 end 309 else 310 begin 311 cix:=MyRO.nEnemyCity-1; 312 while (cix>=0) and (MyRO.EnemyCity[cix].Loc<>Loc) do dec(cix); 313 CityInfo:=MyRO.EnemyCity[cix]; 314 end 315 end; 316 317 function UnitExhausted(uix: integer): boolean; 318 // check if another move of this unit is still possible 319 var 320 dx, dy: integer; 321 begin 322 result:=true; 323 if (MyUn[uix].Movement>0) or (MyRO.Wonder[woShinkansen].EffectiveOwner=me) then 324 if (MyUn[uix].Movement>=100) or ((MyModel[MyUn[uix].mix].Kind=mkCaravan) 325 and (MyMap[MyUn[uix].Loc] and fCity<>0)) then 326 result:=false 327 else for dx:=-2 to 2 do for dy:=-2 to 2 do if abs(dx)+abs(dy)=2 then 328 if Server(sMoveUnit-sExecute+dx and 7 shl 4+dy and 7 shl 7,me,uix,nil^)>=rExecuted then 329 result:=false; 330 end; 331 332 function ModelHash(const ModelInfo: TModelInfo): integer; 333 var 334 i,FeatureCode,Hash1,Hash2,Hash2r,d: cardinal; 335 begin 336 with ModelInfo do 337 if Kind>mkEnemyDeveloped then 338 result:=integer($C0000000+Speed div 50+Kind shl 8) 339 else 340 begin 341 FeatureCode:=0; 342 for i:=mcFirstNonCap to nFeature-1 do 343 if 1 shl Domain and Feature[i].Domains<>0 then 344 begin 345 FeatureCode:=FeatureCode*2; 346 if 1 shl (i-mcFirstNonCap)<>0 then 347 inc(FeatureCode); 348 end; 349 case Domain of 350 dGround: 351 begin 352 assert(FeatureCode<1 shl 8); 353 assert(Attack<5113); 354 assert(Defense<2273); 355 assert(Cost<1611); 356 Hash1:=(Attack*2273+Defense)*9+(Speed-150) div 50; 357 Hash2:=FeatureCode*1611+Cost; 358 end; 359 dSea: 360 begin 361 assert(FeatureCode<1 shl 9); 362 assert(Attack<12193); 363 assert(Defense<6097); 364 assert(Cost<4381); 365 Hash1:=((Attack*6097+Defense)*5+(Speed-350) div 100)*2; 366 if Weight>=6 then inc(Hash1); 367 Hash2:=((TTrans*17+ATrans_Fuel) shl 9+FeatureCode)*4381+Cost; 368 end; 369 dAir: 370 begin 371 assert(FeatureCode<1 shl 5); 372 assert(Attack<2407); 373 assert(Defense<1605); 374 assert(Bombs<4813); 375 assert(Cost<2089); 376 Hash1:=(Attack*1605+Defense) shl 5+FeatureCode; 377 Hash2:=((Bombs*7+ATrans_Fuel)*4+TTrans)*2089+Cost; 378 end; 379 end; 380 Hash2r:=0; 381 for i:=0 to 7 do 382 begin 383 Hash2r:=Hash2r*13; 384 d:=Hash2 div 13; 385 inc(Hash2r,Hash2-d*13); 386 Hash2:=d 387 end; 388 result:=integer(Domain shl 30+Hash1 xor Hash2r) 191 else 192 begin 193 result := 0; 194 for i := 1 to 3 do 195 if MyRO.EnemyReport[p].Tech[AgePreq[i]] >= tsApplicable then 196 result := i; 389 197 end 390 end; 391 392 function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer; 393 { return values: 394 eJobDone - all applicable jobs done 395 eOK - enhancement not complete 396 eDied - job done and died (thurst) } 397 var 398 stage, NextJob, Tile: integer; 399 Done: Set of jNone..jTrans; 400 begin 401 Done:=[]; 402 Tile:=MyMap[MyUn[uix].Loc]; 403 if Tile and fRoad<>0 then include(Done,jRoad); 404 if Tile and fRR<>0 then include(Done,jRR); 405 if (Tile and fTerImp=tiIrrigation) or (Tile and fTerImp=tiFarm) then 406 include(Done,jIrr); 407 if Tile and fTerImp=tiFarm then include(Done,jFarm); 408 if Tile and fTerImp=tiMine then include(Done,jMine); 409 if Tile and fPoll=0 then include(Done,jPoll); 410 411 if MyUn[uix].Job=jNone then result:=eJobDone 412 else result:=eOK; 413 while (result<>eOK) and (result<>eDied) do 414 begin 415 stage:=-1; 416 repeat 417 if stage=-1 then NextJob:=jPoll 418 else NextJob:=Jobs[Tile and fTerrain,stage]; 419 if (NextJob=jNone) or not (NextJob in Done) then Break; 420 inc(stage); 421 until stage=5; 422 if (stage=5) or (NextJob=jNone) then 423 begin result:=eJobDone; Break; end; // tile enhancement complete 424 result:=Server(sStartJob+NextJob shl 4,me,uix,nil^); 425 include(Done,NextJob) 426 end; 427 end; 428 429 function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean; 430 var 431 i,NewProject: integer; 432 begin 433 result:=false; 434 if (MyCity[cix].Project and (cpImp+cpIndex)=cpImp+imTrGoods) 435 or (MyCity[cix].Flags and chProduction<>0) then 436 begin 437 i:=0; 438 repeat 439 while (ImpOrder[i]>=0) and (MyCity[cix].Built[ImpOrder[i]]>0) do inc(i); 440 if ImpOrder[i]<0 then Break; 441 assert(i<nImp); 442 NewProject:=cpImp+ImpOrder[i]; 443 if Server(sSetCityProject,me,cix,NewProject)>=rExecuted then 444 begin 445 result:=true; 446 CityOptimizer_CityChange(cix); 447 Break; 448 end; 449 inc(i); 450 until false 451 end 452 end; 453 454 procedure CalculateAdvValues; 455 var 456 i,j: integer; 457 known: array[0..nAdv-1] of integer; 458 459 procedure MarkPreqs(i: integer); 460 begin 461 if known[i]=0 then 462 begin 463 known[i]:=1; 464 if (i<>adScience) and (i<>adMassProduction) then 465 begin 466 if (AdvPreq[i,0]>=0) then MarkPreqs(AdvPreq[i,0]); 467 if (AdvPreq[i,1]>=0) then MarkPreqs(AdvPreq[i,1]); 198 end; 199 200 function IsCivilReportNew(Enemy: integer): boolean; 201 var 202 i: integer; 203 begin 204 assert(Enemy <> me); 205 i := MyRO.EnemyReport[Enemy].TurnOfCivilReport; 206 result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me); 207 end; 208 209 function IsMilReportNew(Enemy: integer): boolean; 210 var 211 i: integer; 212 begin 213 assert(Enemy <> me); 214 i := MyRO.EnemyReport[Enemy].TurnOfMilReport; 215 result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me); 216 end; 217 218 function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean; 219 gov, size: integer): integer; 220 begin 221 result := FoodSurplus; 222 if not IsCityAlive or (result > 0) and 223 ((gov = gFuture) or (size >= NeedAqueductSize) and (result < 2)) then 224 result := 0; { no growth } 225 end; 226 227 function CityTaxBalance(cix: integer; 228 const CityReport: TCityReportNew): integer; 229 var 230 i: integer; 231 begin 232 result := 0; 233 if (CityReport.HappinessBalance >= 0) { no disorder } 234 and (MyCity[cix].Flags and chCaptured = 0) then // not captured 235 begin 236 inc(result, CityReport.Tax); 237 if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) and 238 (CityReport.Production > 0) then 239 inc(result, CityReport.Production); 240 if ((MyRO.Government = gFuture) or (MyCity[cix].size >= NeedAqueductSize) 241 and (CityReport.FoodSurplus < 2)) and (CityReport.FoodSurplus > 0) then 242 inc(result, CityReport.FoodSurplus); 243 end; 244 for i := 28 to nImp - 1 do 245 if MyCity[cix].Built[i] > 0 then 246 dec(result, Imp[i].Maint); 247 end; 248 249 procedure SumCities(var TaxSum, ScienceSum: integer); 250 var 251 cix: integer; 252 CityReport: TCityReportNew; 253 begin 254 TaxSum := MyRO.OracleIncome; 255 ScienceSum := 0; 256 if MyRO.Government = gAnarchy then 257 exit; 258 for cix := 0 to MyRO.nCity - 1 do 259 if MyCity[cix].Loc >= 0 then 260 begin 261 CityReport.HypoTiles := -1; 262 CityReport.HypoTaxRate := -1; 263 CityReport.HypoLuxuryRate := -1; 264 Server(sGetCityReportNew, me, cix, CityReport); 265 if (CityReport.HappinessBalance >= 0) { no disorder } 266 and (MyCity[cix].Flags and chCaptured = 0) then // not captured 267 ScienceSum := ScienceSum + CityReport.Science; 268 TaxSum := TaxSum + CityTaxBalance(cix, CityReport); 269 end; 270 end; 271 272 function JobTest(uix, Job: integer; IgnoreResults: JobResultSet): boolean; 273 var 274 Test: integer; 275 begin 276 Test := Server(sStartJob + Job shl 4 - sExecute, me, uix, nil^); 277 result := (Test >= rExecuted) or (Test in IgnoreResults); 278 end; 279 280 procedure GetUnitInfo(Loc: integer; var uix: integer; 281 var UnitInfo: TUnitInfo); 282 var 283 i, Cnt: integer; 284 begin 285 if MyMap[Loc] and fOwned <> 0 then 286 begin 287 Server(sGetDefender, me, Loc, uix); 288 Cnt := 0; 289 for i := 0 to MyRO.nUn - 1 do 290 if MyUn[i].Loc = Loc then 291 inc(Cnt); 292 MakeUnitInfo(me, MyUn[uix], UnitInfo); 293 if Cnt > 1 then 294 UnitInfo.Flags := UnitInfo.Flags or unMulti; 295 end 296 else 297 begin 298 uix := MyRO.nEnemyUn - 1; 299 while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do 300 dec(uix); 301 UnitInfo := MyRO.EnemyUn[uix]; 302 end 303 end; { GetUnitInfo } 304 305 procedure GetCityInfo(Loc: integer; var cix: integer; 306 var CityInfo: TCityInfo); 307 begin 308 if MyMap[Loc] and fOwned <> 0 then 309 begin 310 CityInfo.Loc := Loc; 311 cix := MyRO.nCity - 1; 312 while (cix >= 0) and (MyCity[cix].Loc <> Loc) do 313 dec(cix); 314 with CityInfo do 315 begin 316 Owner := me; 317 ID := MyCity[cix].ID; 318 size := MyCity[cix].size; 319 Flags := 0; 320 if MyCity[cix].Built[imPalace] > 0 then 321 inc(Flags, ciCapital); 322 if (MyCity[cix].Built[imWalls] > 0) or 323 (MyMap[MyCity[cix].Loc] and fGrWall <> 0) then 324 inc(Flags, ciWalled); 325 if MyCity[cix].Built[imCoastalFort] > 0 then 326 inc(Flags, ciCoastalFort); 327 if MyCity[cix].Built[imMissileBat] > 0 then 328 inc(Flags, ciMissileBat); 329 if MyCity[cix].Built[imBunker] > 0 then 330 inc(Flags, ciBunker); 331 if MyCity[cix].Built[imSpacePort] > 0 then 332 inc(Flags, ciSpacePort); 468 333 end 469 334 end 470 end; 471 472 begin 473 FillChar(AdvValue,SizeOf(AdvValue),0); 474 for i:=0 to nAdv-1 do 475 begin 476 FillChar(known,SizeOf(known),0); 477 MarkPreqs(i); 478 for j:=0 to nAdv-1 do if known[j]>0 then inc(AdvValue[i]); 479 if i in FutureTech then inc(AdvValue[i],3000) 480 else if known[adMassProduction]>0 then inc(AdvValue[i],2000) 481 else if known[adScience]>0 then inc(AdvValue[i],1000) 482 end; 483 end; 484 485 procedure DebugMessage(Level: integer; Text: string); 486 begin 487 Server(sMessage,me,Level,pchar(Text)^) 488 end; 489 490 function MarkCitiesAround(Loc,cixExcept: integer): boolean; 491 // return whether a city was marked 492 var 493 cix: integer; 494 begin 495 result:=false; 496 for cix:=0 to MyRO.nCity-1 do 497 if (cix<>cixExcept) and (MyCity[cix].Loc>=0) 498 and (MyCity[cix].Flags and chCaptured=0) 499 and (Distance(MyCity[cix].Loc,Loc)<=5) then 500 begin 501 CityNeedsOptimize[cix]:=true; 502 result:=true; 335 else 336 begin 337 cix := MyRO.nEnemyCity - 1; 338 while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do 339 dec(cix); 340 CityInfo := MyRO.EnemyCity[cix]; 503 341 end 504 end; 505 506 procedure OptimizeCities(CheckOnly: boolean); 507 var 508 cix,fix,dx,dy,Loc1,OptiType: integer; 509 done: boolean; 510 Advice: TCityTileAdviceData; 511 begin 512 repeat 513 done:=true; 514 for cix:=0 to MyRO.nCity-1 do if CityNeedsOptimize[cix] then 515 begin 516 OptiType:=MyCity[cix].Status shr 4 and $0F; 517 if OptiType<>0 then 518 begin 519 Advice.ResourceWeights:=OfferedResourceWeights[OptiType]; 520 Server(sGetCityTileAdvice,me,cix,Advice); 521 if Advice.Tiles<>MyCity[cix].Tiles then 522 if CheckOnly then 523 assert(false) 342 end; 343 344 function UnitExhausted(uix: integer): boolean; 345 // check if another move of this unit is still possible 346 var 347 dx, dy: integer; 348 begin 349 result := true; 350 if (MyUn[uix].Movement > 0) or 351 (MyRO.Wonder[woShinkansen].EffectiveOwner = me) then 352 if (MyUn[uix].Movement >= 100) or 353 ((MyModel[MyUn[uix].mix].Kind = mkCaravan) and 354 (MyMap[MyUn[uix].Loc] and fCity <> 0)) then 355 result := false 356 else 357 for dx := -2 to 2 do 358 for dy := -2 to 2 do 359 if abs(dx) + abs(dy) = 2 then 360 if Server(sMoveUnit - sExecute + dx and 7 shl 4 + dy and 7 shl 7, 361 me, uix, nil^) >= rExecuted then 362 result := false; 363 end; 364 365 function ModelHash(const ModelInfo: TModelInfo): integer; 366 var 367 i, FeatureCode, Hash1, Hash2, Hash2r, d: cardinal; 368 begin 369 with ModelInfo do 370 if Kind > mkEnemyDeveloped then 371 result := integer($C0000000 + Speed div 50 + Kind shl 8) 372 else 373 begin 374 FeatureCode := 0; 375 for i := mcFirstNonCap to nFeature - 1 do 376 if 1 shl Domain and Feature[i].Domains <> 0 then 377 begin 378 FeatureCode := FeatureCode * 2; 379 if 1 shl (i - mcFirstNonCap) <> 0 then 380 inc(FeatureCode); 381 end; 382 case Domain of 383 dGround: 384 begin 385 assert(FeatureCode < 1 shl 8); 386 assert(Attack < 5113); 387 assert(Defense < 2273); 388 assert(Cost < 1611); 389 Hash1 := (Attack * 2273 + Defense) * 9 + (Speed - 150) div 50; 390 Hash2 := FeatureCode * 1611 + Cost; 391 end; 392 dSea: 393 begin 394 assert(FeatureCode < 1 shl 9); 395 assert(Attack < 12193); 396 assert(Defense < 6097); 397 assert(Cost < 4381); 398 Hash1 := ((Attack * 6097 + Defense) * 5 + (Speed - 350) 399 div 100) * 2; 400 if Weight >= 6 then 401 inc(Hash1); 402 Hash2 := ((TTrans * 17 + ATrans_Fuel) shl 9 + FeatureCode) * 403 4381 + Cost; 404 end; 405 dAir: 406 begin 407 assert(FeatureCode < 1 shl 5); 408 assert(Attack < 2407); 409 assert(Defense < 1605); 410 assert(Bombs < 4813); 411 assert(Cost < 2089); 412 Hash1 := (Attack * 1605 + Defense) shl 5 + FeatureCode; 413 Hash2 := ((Bombs * 7 + ATrans_Fuel) * 4 + TTrans) * 2089 + Cost; 414 end; 415 end; 416 Hash2r := 0; 417 for i := 0 to 7 do 418 begin 419 Hash2r := Hash2r * 13; 420 d := Hash2 div 13; 421 inc(Hash2r, Hash2 - d * 13); 422 Hash2 := d 423 end; 424 result := integer(Domain shl 30 + Hash1 xor Hash2r) 425 end 426 end; 427 428 function ProcessEnhancement(uix: integer; 429 const Jobs: TEnhancementJobs): integer; 430 { return values: 431 eJobDone - all applicable jobs done 432 eOK - enhancement not complete 433 eDied - job done and died (thurst) } 434 var 435 stage, NextJob, Tile: integer; 436 Done: Set of jNone .. jTrans; 437 begin 438 Done := []; 439 Tile := MyMap[MyUn[uix].Loc]; 440 if Tile and fRoad <> 0 then 441 include(Done, jRoad); 442 if Tile and fRR <> 0 then 443 include(Done, jRR); 444 if (Tile and fTerImp = tiIrrigation) or (Tile and fTerImp = tiFarm) then 445 include(Done, jIrr); 446 if Tile and fTerImp = tiFarm then 447 include(Done, jFarm); 448 if Tile and fTerImp = tiMine then 449 include(Done, jMine); 450 if Tile and fPoll = 0 then 451 include(Done, jPoll); 452 453 if MyUn[uix].Job = jNone then 454 result := eJobDone 455 else 456 result := eOK; 457 while (result <> eOK) and (result <> eDied) do 458 begin 459 stage := -1; 460 repeat 461 if stage = -1 then 462 NextJob := jPoll 524 463 else 464 NextJob := Jobs[Tile and fTerrain, stage]; 465 if (NextJob = jNone) or not(NextJob in Done) then 466 Break; 467 inc(stage); 468 until stage = 5; 469 if (stage = 5) or (NextJob = jNone) then 470 begin 471 result := eJobDone; 472 Break; 473 end; // tile enhancement complete 474 result := Server(sStartJob + NextJob shl 4, me, uix, nil^); 475 include(Done, NextJob) 476 end; 477 end; 478 479 function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean; 480 var 481 i, NewProject: integer; 482 begin 483 result := false; 484 if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) or 485 (MyCity[cix].Flags and chProduction <> 0) then 486 begin 487 i := 0; 488 repeat 489 while (ImpOrder[i] >= 0) and (MyCity[cix].Built[ImpOrder[i]] > 0) do 490 inc(i); 491 if ImpOrder[i] < 0 then 492 Break; 493 assert(i < nImp); 494 NewProject := cpImp + ImpOrder[i]; 495 if Server(sSetCityProject, me, cix, NewProject) >= rExecuted then 496 begin 497 result := true; 498 CityOptimizer_CityChange(cix); 499 Break; 500 end; 501 inc(i); 502 until false end end; 503 504 procedure CalculateAdvValues; 505 var 506 i, j: integer; 507 known: array [0 .. nAdv - 1] of integer; 508 509 procedure MarkPreqs(i: integer); 510 begin 511 if known[i] = 0 then 525 512 begin 526 for fix:=1 to 26 do 527 if MyCity[cix].Tiles and not Advice.Tiles and (1 shl fix)<>0 then 528 begin // tile no longer used by this city -- check using it by another 529 dy:=fix shr 2-3; dx:=fix and 3 shl 1 -3 + (dy+3) and 1; 530 Loc1:=dLoc(MyCity[cix].Loc,dx,dy); 531 if MarkCitiesAround(Loc1,cix) then 532 done:=false; 513 known[i] := 1; 514 if (i <> adScience) and (i <> adMassProduction) then 515 begin 516 if (AdvPreq[i, 0] >= 0) then 517 MarkPreqs(AdvPreq[i, 0]); 518 if (AdvPreq[i, 1] >= 0) then 519 MarkPreqs(AdvPreq[i, 1]); 520 end 521 end 522 end; 523 524 begin 525 FillChar(AdvValue, SizeOf(AdvValue), 0); 526 for i := 0 to nAdv - 1 do 527 begin 528 FillChar(known, SizeOf(known), 0); 529 MarkPreqs(i); 530 for j := 0 to nAdv - 1 do 531 if known[j] > 0 then 532 inc(AdvValue[i]); 533 if i in FutureTech then 534 inc(AdvValue[i], 3000) 535 else if known[adMassProduction] > 0 then 536 inc(AdvValue[i], 2000) 537 else if known[adScience] > 0 then 538 inc(AdvValue[i], 1000) 539 end; 540 end; 541 542 procedure DebugMessage(Level: integer; Text: string); 543 begin 544 Server(sMessage, me, Level, pchar(Text)^) 545 end; 546 547 function MarkCitiesAround(Loc, cixExcept: integer): boolean; 548 // return whether a city was marked 549 var 550 cix: integer; 551 begin 552 result := false; 553 for cix := 0 to MyRO.nCity - 1 do 554 if (cix <> cixExcept) and (MyCity[cix].Loc >= 0) and 555 (MyCity[cix].Flags and chCaptured = 0) and 556 (Distance(MyCity[cix].Loc, Loc) <= 5) then 557 begin 558 CityNeedsOptimize[cix] := true; 559 result := true; 560 end 561 end; 562 563 procedure OptimizeCities(CheckOnly: boolean); 564 var 565 cix, fix, dx, dy, Loc1, OptiType: integer; 566 Done: boolean; 567 Advice: TCityTileAdviceData; 568 begin 569 repeat 570 Done := true; 571 for cix := 0 to MyRO.nCity - 1 do 572 if CityNeedsOptimize[cix] then 573 begin 574 OptiType := MyCity[cix].Status shr 4 and $0F; 575 if OptiType <> 0 then 576 begin 577 Advice.ResourceWeights := OfferedResourceWeights[OptiType]; 578 Server(sGetCityTileAdvice, me, cix, Advice); 579 if Advice.Tiles <> MyCity[cix].Tiles then 580 if CheckOnly then 581 assert(false) 582 else 583 begin 584 for fix := 1 to 26 do 585 if MyCity[cix].Tiles and not Advice.Tiles and 586 (1 shl fix) <> 0 then 587 begin // tile no longer used by this city -- check using it by another 588 dy := fix shr 2 - 3; 589 dx := fix and 3 shl 1 - 3 + (dy + 3) and 1; 590 Loc1 := dLoc(MyCity[cix].Loc, dx, dy); 591 if MarkCitiesAround(Loc1, cix) then 592 Done := false; 593 end; 594 Server(sSetCityTiles, me, cix, Advice.Tiles); 595 end; 533 596 end; 534 Server(sSetCityTiles,me,cix,Advice.Tiles); 535 end; 536 end; 537 CityNeedsOptimize[cix]:=false; 538 end; 539 until done; 540 end; 541 542 procedure CityOptimizer_BeginOfTurn; 543 var 544 cix: integer; 545 begin 546 fillchar(CityNeedsOptimize,MyRO.nCity-1,0); //false 547 if MyRO.Government<>gAnarchy then 548 begin 549 for cix:=0 to MyRO.nCity-1 do 550 if (MyCity[cix].Loc>=0) and (MyCity[cix].Flags and chCaptured=0) then 551 CityNeedsOptimize[cix]:=true; 552 OptimizeCities(false); // optimize all cities 553 end 554 end; 555 556 procedure CityOptimizer_CityChange(cix: integer); 557 begin 558 if (MyRO.Government<>gAnarchy) and (MyCity[cix].Flags and chCaptured=0) then 559 begin 560 CityNeedsOptimize[cix]:=true; 561 OptimizeCities(false); 562 end 563 end; 564 565 procedure CityOptimizer_TileBecomesAvailable(Loc: integer); 566 begin 567 if (MyRO.Government<>gAnarchy) and MarkCitiesAround(Loc,-1) then 568 OptimizeCities(false); 569 end; 570 571 procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer); 572 var 573 fix,dx,dy,Loc1: integer; 574 done: boolean; 575 begin 576 if (MyRO.Government<>gAnarchy) and (ReleasedTiles<>0) then 577 begin 578 done:=true; 579 for fix:=1 to 26 do if ReleasedTiles and (1 shl fix)<>0 then 580 begin 581 dy:=fix shr 2-3; dx:=fix and 3 shl 1 -3 + (dy+3) and 1; 582 Loc1:=dLoc(MyCity[cix].Loc,dx,dy); 583 if MarkCitiesAround(Loc1,cix) then 584 done:=false; 585 end; 586 if not done then 587 OptimizeCities(false); 588 end 589 end; 590 591 procedure CityOptimizer_BeforeRemoveUnit(uix: integer); 592 var 593 uix1: integer; 594 begin 595 if MyRO.Government<>gAnarchy then 596 begin 597 if MyUn[uix].Home>=0 then 598 CityNeedsOptimize[MyUn[uix].Home]:=true; 599 600 // transported units are also removed 601 for uix1:=0 to MyRO.nUn-1 do 602 if (MyUn[uix1].Loc>=0) and (MyUn[uix1].Master=uix) 603 and (MyUn[uix1].Home>=0) then 604 CityNeedsOptimize[MyUn[uix1].Home]:=true; 605 end 606 end; 607 608 procedure CityOptimizer_AfterRemoveUnit; 609 begin 610 if MyRO.Government<>gAnarchy then 611 OptimizeCities(false); 612 end; 613 614 procedure CityOptimizer_EndOfTurn; 615 // all cities should already be optimized here -- only check this 616 var 617 cix: integer; 618 begin 597 CityNeedsOptimize[cix] := false; 598 end; 599 until Done; 600 end; 601 602 procedure CityOptimizer_BeginOfTurn; 603 var 604 cix: integer; 605 begin 606 FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false 607 if MyRO.Government <> gAnarchy then 608 begin 609 for cix := 0 to MyRO.nCity - 1 do 610 if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0) 611 then 612 CityNeedsOptimize[cix] := true; 613 OptimizeCities(false); // optimize all cities 614 end 615 end; 616 617 procedure CityOptimizer_CityChange(cix: integer); 618 begin 619 if (MyRO.Government <> gAnarchy) and 620 (MyCity[cix].Flags and chCaptured = 0) then 621 begin 622 CityNeedsOptimize[cix] := true; 623 OptimizeCities(false); 624 end 625 end; 626 627 procedure CityOptimizer_TileBecomesAvailable(Loc: integer); 628 begin 629 if (MyRO.Government <> gAnarchy) and MarkCitiesAround(Loc, -1) then 630 OptimizeCities(false); 631 end; 632 633 procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer); 634 var 635 fix, dx, dy, Loc1: integer; 636 Done: boolean; 637 begin 638 if (MyRO.Government <> gAnarchy) and (ReleasedTiles <> 0) then 639 begin 640 Done := true; 641 for fix := 1 to 26 do 642 if ReleasedTiles and (1 shl fix) <> 0 then 643 begin 644 dy := fix shr 2 - 3; 645 dx := fix and 3 shl 1 - 3 + (dy + 3) and 1; 646 Loc1 := dLoc(MyCity[cix].Loc, dx, dy); 647 if MarkCitiesAround(Loc1, cix) then 648 Done := false; 649 end; 650 if not Done then 651 OptimizeCities(false); 652 end 653 end; 654 655 procedure CityOptimizer_BeforeRemoveUnit(uix: integer); 656 var 657 uix1: integer; 658 begin 659 if MyRO.Government <> gAnarchy then 660 begin 661 if MyUn[uix].Home >= 0 then 662 CityNeedsOptimize[MyUn[uix].Home] := true; 663 664 // transported units are also removed 665 for uix1 := 0 to MyRO.nUn - 1 do 666 if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) and 667 (MyUn[uix1].Home >= 0) then 668 CityNeedsOptimize[MyUn[uix1].Home] := true; 669 end 670 end; 671 672 procedure CityOptimizer_AfterRemoveUnit; 673 begin 674 if MyRO.Government <> gAnarchy then 675 OptimizeCities(false); 676 end; 677 678 procedure CityOptimizer_EndOfTurn; 679 // all cities should already be optimized here -- only check this 680 var 681 cix: integer; 682 begin 619 683 {$IFOPT O-} 620 if MyRO.Government<>gAnarchy then 621 begin 622 fillchar(CityNeedsOptimize,MyRO.nCity-1,0); //false 623 for cix:=0 to MyRO.nCity-1 do 624 if (MyCity[cix].Loc>=0) and (MyCity[cix].Flags and chCaptured=0) then 625 CityNeedsOptimize[cix]:=true; 626 OptimizeCities(true); // check all cities 627 end; 684 if MyRO.Government <> gAnarchy then 685 begin 686 FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false 687 for cix := 0 to MyRO.nCity - 1 do 688 if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0) 689 then 690 CityNeedsOptimize[cix] := true; 691 OptimizeCities(true); // check all cities 692 end; 628 693 {$ENDIF} 629 end; 630 694 end; 631 695 632 696 initialization 633 assert(nImp<128); 697 698 assert(nImp < 128); 634 699 CalculateAdvValues; 635 700 636 701 end. 637 -
trunk/LocalPlayer/Diagram.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit Diagram; 4 3 … … 22 21 procedure ToggleBtnClick(Sender: TObject); 23 22 procedure PlayerClick(Sender: TObject); 24 procedure FormKeyDown(Sender: TObject; var Key: word; 25 Shift: TShiftState); 23 procedure FormKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); 26 24 27 25 public … … 31 29 32 30 private 33 Kind: (dkChart,dkShip);34 Player, Mode: integer;31 Kind: (dkChart, dkShip); 32 Player, Mode: integer; 35 33 end; 36 34 … … 38 36 DiaDlg: TDiaDlg; 39 37 40 procedure PaintColonyShip(canvas: TCanvas; Player,Left,Width,Top: integer); 41 38 procedure PaintColonyShip(canvas: TCanvas; Player, Left, Width, Top: integer); 42 39 43 40 implementation 44 41 45 42 uses 46 Protocol, ScreenTools, ClientTools,Term,Tribes;43 Protocol, ScreenTools, ClientTools, Term, Tribes; 47 44 48 45 {$R *.DFM} 49 46 50 47 const 51 Border=24; 52 RoundPixels: array[0..nStat-1] of integer=(0,0,0,5,5,5); 53 54 yArea=48; 55 xComp: array[0..5] of integer=(-60,-28,4,4,36,68); 56 yComp: array[0..5] of integer=(-40,-40,-79,-1,-40,-40); 57 xPow: array[0..3] of integer=(-116,-116,-116,-116); 58 yPow: array[0..3] of integer=(-28,0,-44,16); 59 xHab: array[0..1] of integer=(23,23); 60 yHab: array[0..1] of integer=(-81,1); 61 62 procedure PaintColonyShip(canvas: TCanvas; Player,Left,Width,Top: integer); 63 var 64 i,x,r,nComp,nPow,nHab: integer; 65 begin 66 with canvas do 67 begin 68 Brush.Color:=$000000; 69 FillRect(Rect(Left,Top,Left+Width,Top+200)); 70 Brush.Style:=bsClear; 71 Frame(Canvas,Left-1,Top-1,Left+Width,Top+200,MainTexture.clBevelShade,MainTexture.clBevelLight); 72 RFrame(Canvas,Left-2,Top-2,Left+Width+1,Top+200+1,MainTexture.clBevelShade,MainTexture.clBevelLight); 73 74 // stars 75 RandSeed:=Player*11111; 76 for i:=1 to Width-16 do 48 Border = 24; 49 RoundPixels: array [0 .. nStat - 1] of integer = (0, 0, 0, 5, 5, 5); 50 51 yArea = 48; 52 xComp: array [0 .. 5] of integer = (-60, -28, 4, 4, 36, 68); 53 yComp: array [0 .. 5] of integer = (-40, -40, -79, -1, -40, -40); 54 xPow: array [0 .. 3] of integer = (-116, -116, -116, -116); 55 yPow: array [0 .. 3] of integer = (-28, 0, -44, 16); 56 xHab: array [0 .. 1] of integer = (23, 23); 57 yHab: array [0 .. 1] of integer = (-81, 1); 58 59 procedure PaintColonyShip(canvas: TCanvas; Player, Left, Width, Top: integer); 60 var 61 i, x, r, nComp, nPow, nHab: integer; 62 begin 63 with canvas do 64 begin 65 Brush.Color := $000000; 66 FillRect(Rect(Left, Top, Left + Width, Top + 200)); 67 Brush.Style := bsClear; 68 Frame(canvas, Left - 1, Top - 1, Left + Width, Top + 200, 69 MainTexture.clBevelShade, MainTexture.clBevelLight); 70 RFrame(canvas, Left - 2, Top - 2, Left + Width + 1, Top + 200 + 1, 71 MainTexture.clBevelShade, MainTexture.clBevelLight); 72 73 // stars 74 RandSeed := Player * 11111; 75 for i := 1 to Width - 16 do 77 76 begin 78 x:=Random((Width-16)*200); 79 r:=Random(13)+28; 80 Pixels[x div 200+8,x mod 200+Top]:=(r*r*r*r div 10001)*$10101; 77 x := Random((Width - 16) * 200); 78 r := Random(13) + 28; 79 Pixels[x div 200 + 8, x mod 200 + Top] := 80 (r * r * r * r div 10001) * $10101; 81 81 end; 82 82 83 nComp:=MyRO.Ship[Player].Parts[spComp]; 84 nPow:=MyRO.Ship[Player].Parts[spPow]; 85 nHab:=MyRO.Ship[Player].Parts[spHab]; 86 if nComp>6 then nComp:=6; 87 if nPow>4 then nPow:=4; 88 if nHab>2 then nHab:=2; 89 for i:=0 to nHab-1 do 90 Sprite(canvas,HGrSystem2,Left+Width div 2+xHab[i],Top+100+yHab[i], 91 80,80,34,1); 92 for i:=0 to nComp-1 do 93 Sprite(canvas,HGrSystem2,Left+Width div 2+xComp[i],Top+100+yComp[i], 94 32,80,1,1); 95 if nComp>0 then 96 for i:=3 downto nPow do 97 Sprite(canvas,HGrSystem2,Left+Width div 2+xPow[i]+40,Top+100+yPow[i], 98 16,27,1,82); 99 for i:=nPow-1 downto 0 do 100 Sprite(canvas,HGrSystem2,Left+Width div 2+xPow[i],Top+100+yPow[i], 101 56,28,58,82); 102 if (nComp<3) and (nHab>=1) then 103 Sprite(canvas,HGrSystem2,Left+Width div 2+xComp[2]+32-16,Top+100+7+yComp[2], 104 16,27,1,82); 105 if (nComp>=3) and (nHab<1) then 106 Sprite(canvas,HGrSystem2,Left+Width div 2+xComp[2]+32,Top+100+7+yComp[2], 107 16,27,18,82); 108 if (nComp<4) and (nHab>=2) then 109 Sprite(canvas,HGrSystem2,Left+Width div 2+xComp[3]+32-16,Top+100+46+yComp[3], 110 16,27,1,82); 111 if (nComp>=4) and (nHab<2) then 112 Sprite(canvas,HGrSystem2,Left+Width div 2+xComp[3]+32,Top+100+46+yComp[3], 113 16,27,18,82); 114 if (nComp<>6) and (nComp<>2) and not ((nComp=0) and (nPow<1)) then 115 Sprite(canvas,HGrSystem2,Left+Width div 2+xComp[nComp],Top+100+7+yComp[nComp], 116 16,27,18,82); 117 if (nComp<>6) and (nComp<>3) and not ((nComp=0) and (nPow<2)) then 118 Sprite(canvas,HGrSystem2,Left+Width div 2+xComp[nComp],Top+100+46+yComp[nComp], 119 16,27,18,82); 120 if nComp=2 then 121 Sprite(canvas,HGrSystem2,Left+Width div 2+xComp[3],Top+100+7+yComp[3], 122 16,27,18,82); 123 if nComp=3 then 124 Sprite(canvas,HGrSystem2,Left+Width div 2+xComp[4],Top+100+7+yComp[4], 125 16,27,18,82); 83 nComp := MyRO.Ship[Player].Parts[spComp]; 84 nPow := MyRO.Ship[Player].Parts[spPow]; 85 nHab := MyRO.Ship[Player].Parts[spHab]; 86 if nComp > 6 then 87 nComp := 6; 88 if nPow > 4 then 89 nPow := 4; 90 if nHab > 2 then 91 nHab := 2; 92 for i := 0 to nHab - 1 do 93 Sprite(canvas, HGrSystem2, Left + Width div 2 + xHab[i], 94 Top + 100 + yHab[i], 80, 80, 34, 1); 95 for i := 0 to nComp - 1 do 96 Sprite(canvas, HGrSystem2, Left + Width div 2 + xComp[i], 97 Top + 100 + yComp[i], 32, 80, 1, 1); 98 if nComp > 0 then 99 for i := 3 downto nPow do 100 Sprite(canvas, HGrSystem2, Left + Width div 2 + xPow[i] + 40, 101 Top + 100 + yPow[i], 16, 27, 1, 82); 102 for i := nPow - 1 downto 0 do 103 Sprite(canvas, HGrSystem2, Left + Width div 2 + xPow[i], 104 Top + 100 + yPow[i], 56, 28, 58, 82); 105 if (nComp < 3) and (nHab >= 1) then 106 Sprite(canvas, HGrSystem2, Left + Width div 2 + xComp[2] + 32 - 16, 107 Top + 100 + 7 + yComp[2], 16, 27, 1, 82); 108 if (nComp >= 3) and (nHab < 1) then 109 Sprite(canvas, HGrSystem2, Left + Width div 2 + xComp[2] + 32, 110 Top + 100 + 7 + yComp[2], 16, 27, 18, 82); 111 if (nComp < 4) and (nHab >= 2) then 112 Sprite(canvas, HGrSystem2, Left + Width div 2 + xComp[3] + 32 - 16, 113 Top + 100 + 46 + yComp[3], 16, 27, 1, 82); 114 if (nComp >= 4) and (nHab < 2) then 115 Sprite(canvas, HGrSystem2, Left + Width div 2 + xComp[3] + 32, 116 Top + 100 + 46 + yComp[3], 16, 27, 18, 82); 117 if (nComp <> 6) and (nComp <> 2) and not((nComp = 0) and (nPow < 1)) then 118 Sprite(canvas, HGrSystem2, Left + Width div 2 + xComp[nComp], 119 Top + 100 + 7 + yComp[nComp], 16, 27, 18, 82); 120 if (nComp <> 6) and (nComp <> 3) and not((nComp = 0) and (nPow < 2)) then 121 Sprite(canvas, HGrSystem2, Left + Width div 2 + xComp[nComp], 122 Top + 100 + 46 + yComp[nComp], 16, 27, 18, 82); 123 if nComp = 2 then 124 Sprite(canvas, HGrSystem2, Left + Width div 2 + xComp[3], 125 Top + 100 + 7 + yComp[3], 16, 27, 18, 82); 126 if nComp = 3 then 127 Sprite(canvas, HGrSystem2, Left + Width div 2 + xComp[4], 128 Top + 100 + 7 + yComp[4], 16, 27, 18, 82); 126 129 end 127 130 end; … … 129 132 procedure TDiaDlg.FormCreate(Sender: TObject); 130 133 begin 131 inherited;132 TitleHeight:=WideFrame+20;133 InnerHeight:=ClientHeight-TitleHeight-NarrowFrame;134 CaptionRight:=CloseBtn.Left;135 CaptionLeft:=ToggleBtn.Left+ToggleBtn.Width;136 InitButtons();134 inherited; 135 TitleHeight := WideFrame + 20; 136 InnerHeight := ClientHeight - TitleHeight - NarrowFrame; 137 CaptionRight := CloseBtn.Left; 138 CaptionLeft := ToggleBtn.Left + ToggleBtn.Width; 139 InitButtons(); 137 140 end; 138 141 139 142 procedure TDiaDlg.CloseBtnClick(Sender: TObject); 140 143 begin 141 Close;144 Close; 142 145 end; 143 146 144 147 procedure TDiaDlg.OffscreenPaint; 145 148 type 146 TLine=array[0..99999,0..2] of Byte;147 var 148 p,T,max,x,y,y0,Stop,r,RoundRange,LineStep: integer;149 s: string;150 List: ^TChart;149 TLine = array [0 .. 99999, 0 .. 2] of Byte; 150 var 151 p, T, max, x, y, y0, Stop, r, RoundRange, LineStep: integer; 152 s: string; 153 List: ^TChart; 151 154 152 155 function Round(T: integer): integer; 153 156 var 154 n,i: integer; 155 begin 156 if T<RoundRange then n:=T else n:=RoundRange; 157 result:=0; 158 for i:=T-n to T do inc(result,List[i]); 159 result:=result div (n+1); 157 n, i: integer; 158 begin 159 if T < RoundRange then 160 n := T 161 else 162 n := RoundRange; 163 result := 0; 164 for i := T - n to T do 165 inc(result, List[i]); 166 result := result div (n + 1); 160 167 end; 161 168 162 procedure ShareBar(x,y:integer; Cap:string; val0,val1: integer); 163 begin 164 LoweredTextOut(offscreen.Canvas,-1,MainTexture,x-2,y,Cap); 165 DLine(offscreen.Canvas,x-2,x+169,y+16,MainTexture.clTextShade, 166 MainTexture.clTextLight); 167 if val0>0 then s:=Format(Phrases.Lookup('SHARE'),[val0,val1]) 168 else s:='0'; 169 RisedTextOut(offscreen.Canvas,x+170-BiColorTextWidth(Offscreen.Canvas,s),y,s); 169 procedure ShareBar(x, y: integer; Cap: string; val0, val1: integer); 170 begin 171 LoweredTextOut(offscreen.canvas, -1, MainTexture, x - 2, y, Cap); 172 DLine(offscreen.canvas, x - 2, x + 169, y + 16, MainTexture.clTextShade, 173 MainTexture.clTextLight); 174 if val0 > 0 then 175 s := Format(Phrases.Lookup('SHARE'), [val0, val1]) 176 else 177 s := '0'; 178 RisedTextOut(offscreen.canvas, 179 x + 170 - BiColorTextWidth(offscreen.canvas, s), y, s); 170 180 end; 171 181 172 182 begin 173 inherited; 174 if Kind=dkChart then with offscreen.Canvas do 175 begin 176 Font.Assign(UniFont[ftTiny]); 177 Font.Color:=$808080; 178 179 RoundRange:=RoundPixels[Mode]*(MyRO.Turn-1) div (InnerWidth-2*Border); 180 181 GetMem(List,4*(MyRO.Turn+2)); 182 if Mode=stExplore then max:=G.lx*G.ly 183 else 183 inherited; 184 if Kind = dkChart then 185 with offscreen.canvas do 184 186 begin 185 max:=-1; 186 for p:=0 to nPl-1 do 187 if (G.Difficulty[p]>0) 188 and (Server(sGetChart+Mode shl 4,me,p,List^)>=rExecuted) then 189 for T:=0 to MyRO.Turn-1 do 190 begin r:=Round(T); if r>max then max:=r; end; 187 Font.Assign(UniFont[ftTiny]); 188 Font.Color := $808080; 189 190 RoundRange := RoundPixels[Mode] * (MyRO.Turn - 1) 191 div (InnerWidth - 2 * Border); 192 193 GetMem(List, 4 * (MyRO.Turn + 2)); 194 if Mode = stExplore then 195 max := G.lx * G.ly 196 else 197 begin 198 max := -1; 199 for p := 0 to nPl - 1 do 200 if (G.Difficulty[p] > 0) and 201 (Server(sGetChart + Mode shl 4, me, p, List^) >= rExecuted) then 202 for T := 0 to MyRO.Turn - 1 do 203 begin 204 r := Round(T); 205 if r > max then 206 max := r; 207 end; 208 end; 209 210 Brush.Color := $000000; 211 FillRect(Rect(0, 0, InnerWidth, InnerHeight)); 212 Brush.Style := bsClear; 213 Pen.Color := $606060; 214 MoveTo(Border, InnerHeight - Border); 215 LineTo(InnerWidth - Border, InnerHeight - Border); 216 if MyRO.Turn >= 800 then 217 LineStep := 200 218 else if MyRO.Turn >= 400 then 219 LineStep := 100 220 else 221 LineStep := 50; 222 for T := 0 to (MyRO.Turn - 1) div LineStep do 223 begin 224 x := Border + (InnerWidth - 2 * Border) * T * 225 LineStep div (MyRO.Turn - 1); 226 MoveTo(x, Border); 227 LineTo(x, InnerHeight - Border); 228 s := IntToStr(abs(TurnToYear(T * LineStep))); 229 Textout(x - TextWidth(s) div 2, Border - 16, s); 230 end; 231 232 if max > 0 then 233 begin 234 for p := 0 to nPl - 1 do 235 if (G.Difficulty[p] > 0) and 236 (Server(sGetChart + Mode shl 4, me, p, List^) >= rExecuted) then 237 begin 238 Pen.Color := Tribe[p].Color; 239 Stop := MyRO.Turn - 1; 240 while (Stop > 0) and (List[Stop] = 0) do 241 dec(Stop); 242 for T := 0 to Stop do 243 begin 244 r := Round(T); 245 x := Border + (InnerWidth - 2 * Border) * T div (MyRO.Turn - 1); 246 y := InnerHeight - Border - (InnerHeight - 2 * Border) * 247 r div max; 248 if T = 0 then 249 MoveTo(x, y) 250 // else if Mode=stTerritory then 251 // begin LineTo(x,y0); LineTo(x,y) end 252 else if RoundPixels[Mode] = 0 then 253 begin 254 if (y <> y0) or (T = Stop) then 255 LineTo(x, y) 256 end 257 else 258 LineTo(x, y); 259 y0 := y; 260 end; 261 end; 262 end; 263 FreeMem(List); 264 end 265 else 266 with offscreen.canvas do 267 begin 268 Font.Assign(UniFont[ftSmall]); 269 FillOffscreen(0, 0, InnerWidth, InnerHeight); 270 271 PaintColonyShip(offscreen.canvas, Player, 8, InnerWidth - 16, yArea); 272 273 ShareBar(InnerWidth div 2 - 85, InnerHeight - 62, 274 Phrases.Lookup('SHIPHAB'), MyRO.Ship[Player].Parts[spHab], 2); 275 ShareBar(InnerWidth div 2 - 85, InnerHeight - 43, 276 Phrases.Lookup('SHIPPOW'), MyRO.Ship[Player].Parts[spPow], 4); 277 ShareBar(InnerWidth div 2 - 85, InnerHeight - 24, 278 Phrases.Lookup('SHIPCOMP'), MyRO.Ship[Player].Parts[spComp], 6); 191 279 end; 192 193 Brush.Color:=$000000; 194 FillRect(Rect(0,0,InnerWidth,InnerHeight)); 195 Brush.Style:=bsClear;196 Pen.Color:=$606060; 197 MoveTo(Border,InnerHeight-Border);198 LineTo(InnerWidth-Border,InnerHeight-Border); 199 i f MyRO.Turn>=800 then LineStep:=200200 else if MyRO.Turn>=400 then LineStep:=100201 else LineStep:=50;202 for T:=0 to (MyRO.Turn-1) div LineStep do203 begin204 x:=Border+(InnerWidth-2*Border)*T*LineStep div (MyRO.Turn-1);205 MoveTo(x,Border);206 LineTo(x,InnerHeight-Border);207 s:=IntToStr(abs(TurnToYear(T*LineStep)));208 Textout(x-TextWidth(s) div 2,Border-16,s); 209 end;210 211 if max>0then212 begin213 for p:=0 to nPl-1 do214 if (G.Difficulty[p]>0)215 and (Server(sGetChart+Mode shl 4,me,p,List^)>=rExecuted) then216 begin217 Pen.Color:=Tribe[p].Color;218 Stop:=MyRO.Turn-1; 219 while (Stop>0) and (List[Stop]=0) do dec(Stop);220 for T:=0 to Stop do 221 begin222 r:=Round(T);223 x:=Border+(InnerWidth-2*Border)*T div (MyRO.Turn-1);224 y:=InnerHeight-Border-(InnerHeight-2*Border)*r div max;225 if T=0 then MoveTo(x,y)226 // else if Mode=stTerritory then 227 // begin LineTo(x,y0); LineTo(x,y) end 228 else if RoundPixels[Mode]=0 then 229 begin 230 if (y<>y0) or (T=Stop) then LineTo(x,y) 231 end232 else LineTo(x,y);233 y0:=y;234 end;235 end;236 end;237 FreeMem(List);280 MarkUsedOffscreen(InnerWidth, InnerHeight); 281 end; // OffscreenPaint 282 283 procedure TDiaDlg.FormPaint(Sender: TObject); 284 var 285 s: string; 286 begin 287 inherited; 288 canvas.Font.Assign(UniFont[ftNormal]); 289 if Kind = dkChart then 290 s := Phrases.Lookup('DIAGRAM', Mode) 291 else 292 s := Tribe[Player].TPhrase('SHORTNAME'); 293 LoweredTextOut(canvas, -1, MainTexture, 294 (ClientWidth - BiColorTextWidth(canvas, s)) div 2, 31, s); 295 end; 296 297 procedure TDiaDlg.FormShow(Sender: TObject); 298 begin 299 if WindowMode = wmModal then 300 begin { center on screen } 301 Left := (Screen.Width - Width) div 2; 302 Top := (Screen.Height - Height) div 2; 303 end; 304 OffscreenPaint; 305 end; 306 307 procedure TDiaDlg.ShowNewContent_Charts(NewMode: integer); 308 begin 309 Kind := dkChart; 310 Mode := stPop; 311 ToggleBtn.ButtonIndex := 15; 312 ToggleBtn.Hint := Phrases.Lookup('BTN_PAGE'); 313 Caption := Phrases.Lookup('TITLE_DIAGRAMS'); 314 inherited ShowNewContent(NewMode); 315 end; 316 317 procedure TDiaDlg.ShowNewContent_Ship(NewMode, p: integer); 318 begin 319 Kind := dkShip; 320 if p < 0 then 321 begin 322 Player := me; 323 while MyRO.Ship[Player].Parts[spComp] + MyRO.Ship[Player].Parts[spPow] + 324 MyRO.Ship[Player].Parts[spHab] = 0 do 325 Player := (Player + 1) mod nPl; 238 326 end 239 else with offscreen.Canvas do 240 begin 241 Font.Assign(UniFont[ftSmall]); 242 FillOffscreen(0,0,InnerWidth,InnerHeight); 243 244 PaintColonyShip(offscreen.Canvas,Player,8,InnerWidth-16,yArea); 245 246 ShareBar(InnerWidth div 2-85,InnerHeight-62,Phrases.Lookup('SHIPHAB'), 247 MyRO.Ship[Player].Parts[spHab],2); 248 ShareBar(InnerWidth div 2-85,InnerHeight-43,Phrases.Lookup('SHIPPOW'), 249 MyRO.Ship[Player].Parts[spPow],4); 250 ShareBar(InnerWidth div 2-85,InnerHeight-24,Phrases.Lookup('SHIPCOMP'), 251 MyRO.Ship[Player].Parts[spComp],6); 252 end; 253 MarkUsedOffscreen(InnerWidth,InnerHeight); 254 end; // OffscreenPaint 255 256 procedure TDiaDlg.FormPaint(Sender: TObject); 257 var 258 s: string; 259 begin 260 inherited; 261 Canvas.Font.Assign(UniFont[ftNormal]); 262 if Kind=dkChart then s:=Phrases.Lookup('DIAGRAM',Mode) 263 else s:=Tribe[Player].TPhrase('SHORTNAME'); 264 LoweredTextOut(Canvas, -1, MainTexture, 265 (ClientWidth-BiColorTextWidth(Canvas,s)) div 2, 31, s); 266 end; 267 268 procedure TDiaDlg.FormShow(Sender: TObject); 269 begin 270 if WindowMode=wmModal then 271 begin {center on screen} 272 Left:=(Screen.Width-Width) div 2; 273 Top:=(Screen.Height-Height) div 2; 274 end; 275 OffscreenPaint; 276 end; 277 278 procedure TDiaDlg.ShowNewContent_Charts(NewMode: integer); 279 begin 280 Kind:=dkChart; 281 Mode:=stPop; 282 ToggleBtn.ButtonIndex:=15; 283 ToggleBtn.Hint:=Phrases.Lookup('BTN_PAGE'); 284 Caption:=Phrases.Lookup('TITLE_DIAGRAMS'); 285 inherited ShowNewContent(NewMode); 286 end; 287 288 procedure TDiaDlg.ShowNewContent_Ship(NewMode,p: integer); 289 begin 290 Kind:=dkShip; 291 if p<0 then 292 begin 293 Player:=me; 294 while MyRO.Ship[Player].Parts[spComp]+MyRO.Ship[Player].Parts[spPow] 295 +MyRO.Ship[Player].Parts[spHab]=0 do 296 Player:=(Player+1) mod nPl; 327 else 328 Player := p; 329 ToggleBtn.ButtonIndex := 28; 330 ToggleBtn.Hint := Phrases.Lookup('BTN_SELECT'); 331 Caption := Phrases.Lookup('TITLE_SHIPS'); 332 inherited ShowNewContent(NewMode); 333 end; 334 335 procedure TDiaDlg.ToggleBtnClick(Sender: TObject); 336 var 337 p1: integer; 338 m: TMenuItem; 339 begin 340 if Kind = dkChart then 341 begin 342 Mode := (Mode + 1) mod nStat; 343 OffscreenPaint; 344 Invalidate; 297 345 end 298 else Player:=p; 299 ToggleBtn.ButtonIndex:=28; 300 ToggleBtn.Hint:=Phrases.Lookup('BTN_SELECT');301 Caption:=Phrases.Lookup('TITLE_SHIPS'); 302 inherited ShowNewContent(NewMode); 303 end; 304 305 procedure TDiaDlg.ToggleBtnClick(Sender: TObject);306 var 307 p1: integer;308 m: TMenuItem;309 begin 310 if Kind=dkChartthen311 begin312 Mode:=(Mode+1) mod nStat;313 OffscreenPaint;314 Invalidate;346 else 347 begin 348 EmptyMenu(Popup.Items); 349 for p1 := 0 to nPl - 1 do 350 if MyRO.Ship[p1].Parts[spComp] + MyRO.Ship[p1].Parts[spPow] + 351 MyRO.Ship[p1].Parts[spHab] > 0 then 352 begin 353 m := TMenuItem.Create(Popup); 354 m.RadioItem := true; 355 m.Caption := Tribe[p1].TPhrase('SHORTNAME'); 356 m.Tag := p1; 357 m.OnClick := PlayerClick; 358 if p1 = Player then 359 m.Checked := true; 360 Popup.Items.Add(m); 361 end; 362 Popup.Popup(Left + ToggleBtn.Left, Top + ToggleBtn.Top + ToggleBtn.Height); 315 363 end 316 else317 begin318 EmptyMenu(Popup.Items);319 for p1:=0 to nPl-1 do320 if MyRO.Ship[p1].Parts[spComp]+MyRO.Ship[p1].Parts[spPow]321 +MyRO.Ship[p1].Parts[spHab]>0 then322 begin323 m:=TMenuItem.Create(Popup);324 m.RadioItem:=true;325 m.Caption:=Tribe[p1].TPhrase('SHORTNAME');326 m.Tag:=p1;327 m.OnClick:=PlayerClick;328 if p1=Player then m.Checked:=true;329 Popup.Items.Add(m);330 end;331 Popup.Popup(Left+ToggleBtn.Left, Top+ToggleBtn.Top+ToggleBtn.Height);332 end333 364 end; 334 365 335 366 procedure TDiaDlg.PlayerClick(Sender: TObject); 336 367 begin 337 ShowNewContent_Ship(FWindowMode, TComponent(Sender).Tag);368 ShowNewContent_Ship(FWindowMode, TComponent(Sender).Tag); 338 369 end; 339 370 … … 341 372 Shift: TShiftState); 342 373 begin 343 if (Key=VK_F6) and (Kind=dkChart) then // my key 344 ToggleBtnClick(nil) 345 else if (Key=VK_F8) and (Kind=dkShip) then // my other key 346 else inherited 374 if (Key = VK_F6) and (Kind = dkChart) then // my key 375 ToggleBtnClick(nil) 376 else if (Key = VK_F8) and (Kind = dkShip) then // my other key 377 else 378 inherited 347 379 end; 348 380 349 381 end. 350 -
trunk/LocalPlayer/Diplomacy.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit Diplomacy; 4 3 … … 7 6 uses Protocol; 8 7 9 function DipCommandToString(pSender, pTarget, Treaty, OppCommand, Command: integer;10 const OppOffer, Offer: TOffer): string;8 function DipCommandToString(pSender, pTarget, Treaty, OppCommand, 9 Command: integer; const OppOffer, Offer: TOffer): string; 11 10 12 11 implementation 13 12 14 13 uses 15 ScreenTools,Tribes,SysUtils;14 ScreenTools, Tribes, SysUtils; 16 15 17 16 function DipCommandToString; … … 19 18 function PriceToString(p, Price: integer): string; 20 19 begin 21 case Price and opMask of22 opChoose:23 result:=Phrases.Lookup('PRICE_CHOOSE');24 opCivilReport:25 result:=Tribe[p].TPhrase('PRICE_CIVIL');26 opMilReport:27 result:=Tribe[p].TPhrase('PRICE_MIL');28 opMap:29 result:=Tribe[p].TPhrase('PRICE_MAP');30 opTreaty:31 {if Price-opTreaty<Treaty then32 case Treaty of20 case Price and opMask of 21 opChoose: 22 result := Phrases.Lookup('PRICE_CHOOSE'); 23 opCivilReport: 24 result := Tribe[p].TPhrase('PRICE_CIVIL'); 25 opMilReport: 26 result := Tribe[p].TPhrase('PRICE_MIL'); 27 opMap: 28 result := Tribe[p].TPhrase('PRICE_MAP'); 29 opTreaty: 30 { if Price-opTreaty<Treaty then 31 case Treaty of 33 32 trPeace: result:=Phrases.Lookup('FRENDTREATY_PEACE'); 34 33 trFriendlyContact: result:=Phrases.Lookup('FRENDTREATY_FRIENDLY'); 35 34 trAlliance: result:=Phrases.Lookup('FRENDTREATY_ALLIANCE'); 36 35 end 37 else} result:=Phrases.Lookup('TREATY',Price-opTreaty); 38 opShipParts: 39 case Price shr 16 and $f of 40 0: result:=Format(Phrases.Lookup('PRICE_SHIPCOMP'),[Price and $FFFF]); 41 1: result:=Format(Phrases.Lookup('PRICE_SHIPPOW'),[Price and $FFFF]); 42 2: result:=Format(Phrases.Lookup('PRICE_SHIPHAB'),[Price and $FFFF]); 43 end; 44 opMoney: 45 result:=Format('%d%%c',[Price-opMoney]); 46 opTribute: 47 result:=Format(Phrases.Lookup('PRICE_TRIBUTE'),[Price-opTribute]); 48 opTech: 49 result:=Phrases.Lookup('ADVANCES',Price-opTech); 50 opAllTech: 51 result:=Tribe[p].TPhrase('PRICE_ALLTECH'); 52 opModel: 53 result:=Tribe[p].ModelName[Price-opModel]; 54 opAllModel: 55 result:=Tribe[p].TPhrase('PRICE_ALLMODEL'); 56 { opCity: 57 result:=Format(TPhrase('PRICE_CITY',p),[CityName(Price-opCity)]);} 36 else } result := Phrases.Lookup('TREATY', Price - opTreaty); 37 opShipParts: 38 case Price shr 16 and $F of 39 0: 40 result := Format(Phrases.Lookup('PRICE_SHIPCOMP'), 41 [Price and $FFFF]); 42 1: 43 result := Format(Phrases.Lookup('PRICE_SHIPPOW'), 44 [Price and $FFFF]); 45 2: 46 result := Format(Phrases.Lookup('PRICE_SHIPHAB'), 47 [Price and $FFFF]); 48 end; 49 opMoney: 50 result := Format('%d%%c', [Price - opMoney]); 51 opTribute: 52 result := Format(Phrases.Lookup('PRICE_TRIBUTE'), [Price - opTribute]); 53 opTech: 54 result := Phrases.Lookup('ADVANCES', Price - opTech); 55 opAllTech: 56 result := Tribe[p].TPhrase('PRICE_ALLTECH'); 57 opModel: 58 result := Tribe[p].ModelName[Price - opModel]; 59 opAllModel: 60 result := Tribe[p].TPhrase('PRICE_ALLMODEL'); 61 { opCity: 62 result:=Format(TPhrase('PRICE_CITY',p),[CityName(Price-opCity)]); } 58 63 end 59 64 end; 60 65 61 66 var 62 i: integer;63 sAdd,sDeliver, sCost: string;64 DoIntro: boolean;67 i: integer; 68 sAdd, sDeliver, sCost: string; 69 DoIntro: boolean; 65 70 begin 66 DoIntro:= OppCommand=scDipStart; 67 case Command of 68 scDipCancelTreaty: 69 begin 70 case Treaty of 71 trPeace: result:=Phrases.Lookup('FRCANCELTREATY_PEACE'); 72 trFriendlyContact: result:=Phrases.Lookup('FRCANCELTREATY_FRIENDLY'); 73 trAlliance: result:=Phrases.Lookup('FRCANCELTREATY_ALLIANCE'); 74 end; 75 DoIntro:=false; 76 end; 77 scDipNotice: result:=Phrases.Lookup('FRNOTICE'); 78 scDipAccept: 79 begin 80 if (OppOffer.nDeliver+OppOffer.nCost=1) 81 and (OppOffer.Price[0] and opMask=opTreaty) 82 and (integer(OppOffer.Price[0]-opTreaty)>Treaty) then // simple treaty offer 83 {if OppOffer.Price[0]-opTreaty=trCeaseFire then 84 result:=Tribe[pTarget].TPhrase('FRACCEPTCEASEFIRE') 85 else} result:=Tribe[pTarget].TPhrase('FRACCEPTTREATY') 86 else if OppOffer.nDeliver=0 then 87 result:=Tribe[pSender].TPhrase('FRACCEPTDEMAND_STRONG') 88 else if OppOffer.nCost=0 then 89 result:=Tribe[pSender].TPhrase('FRACCEPTPRESENT') 90 else result:=Tribe[pSender].TPhrase('FRACCEPTOFFER'); 91 end; 92 scDipBreak: 93 begin 94 result:=Tribe[pTarget].TPhrase('FRBREAK'); 95 DoIntro:=false; 96 end; 97 scDipOffer: 98 begin 99 result:=''; 100 if (OppCommand=scDipOffer) and ((OppOffer.nDeliver>0) or (OppOffer.nCost>0)) 101 and (Offer.nCost+Offer.nDeliver<=2) then 102 begin // respond to made offer before making own one 103 if (OppOffer.nDeliver+OppOffer.nCost=1) 104 and (OppOffer.Price[0] and opMask=opTreaty) 105 and (integer(OppOffer.Price[0]-opTreaty)>Treaty) then // simple treaty offer 106 result:=Tribe[pSender].TPhrase('FRNOTACCEPTTREATY')+'\' 107 else if OppOffer.nDeliver=0 then 108 result:=Tribe[pSender].TPhrase('FRNOTACCEPTDEMAND_STRONG')+'\' 109 else if OppOffer.nCost=0 then 110 result:=Tribe[pSender].TPhrase('FRNOTACCEPTPRESENT')+'\'; 111 end; 112 113 sDeliver:=''; 114 for i:=0 to Offer.nDeliver-1 do 115 begin 116 sAdd:=PriceToString(pSender,Offer.Price[i]); 117 if i=0 then sDeliver:=sAdd 118 else sDeliver:=Format(Phrases.Lookup('PRICE_CONCAT'),[sDeliver,sAdd]) 119 end; 120 sCost:=''; 121 for i:=0 to Offer.nCost-1 do 122 begin 123 sAdd:=PriceToString(pTarget,Offer.Price[Offer.nDeliver+i]); 124 if i=0 then sCost:=sAdd 125 else sCost:=Format(Phrases.Lookup('PRICE_CONCAT'),[sCost,sAdd]) 126 end; 127 128 if (Offer.nDeliver=0) and (Offer.nCost=0) then 129 begin // no offer made 130 if (OppCommand=scDipOffer) and ((OppOffer.nDeliver=0) and (OppOffer.nCost=0)) then 131 result:=Tribe[pTarget].TPhrase('FRBYE') 132 else 133 begin 134 if (result='') and (OppCommand=scDipOffer) 135 and ((OppOffer.nDeliver>0) or (OppOffer.nCost>0)) then 71 DoIntro := OppCommand = scDipStart; 72 case Command of 73 scDipCancelTreaty: 74 begin 75 case Treaty of 76 trPeace: 77 result := Phrases.Lookup('FRCANCELTREATY_PEACE'); 78 trFriendlyContact: 79 result := Phrases.Lookup('FRCANCELTREATY_FRIENDLY'); 80 trAlliance: 81 result := Phrases.Lookup('FRCANCELTREATY_ALLIANCE'); 82 end; 83 DoIntro := false; 84 end; 85 scDipNotice: 86 result := Phrases.Lookup('FRNOTICE'); 87 scDipAccept: 88 begin 89 if (OppOffer.nDeliver + OppOffer.nCost = 1) and 90 (OppOffer.Price[0] and opMask = opTreaty) and 91 (integer(OppOffer.Price[0] - opTreaty) > Treaty) then 92 // simple treaty offer 93 { if OppOffer.Price[0]-opTreaty=trCeaseFire then 94 result:=Tribe[pTarget].TPhrase('FRACCEPTCEASEFIRE') 95 else } result := Tribe[pTarget].TPhrase('FRACCEPTTREATY') 96 else if OppOffer.nDeliver = 0 then 97 result := Tribe[pSender].TPhrase('FRACCEPTDEMAND_STRONG') 98 else if OppOffer.nCost = 0 then 99 result := Tribe[pSender].TPhrase('FRACCEPTPRESENT') 100 else 101 result := Tribe[pSender].TPhrase('FRACCEPTOFFER'); 102 end; 103 scDipBreak: 104 begin 105 result := Tribe[pTarget].TPhrase('FRBREAK'); 106 DoIntro := false; 107 end; 108 scDipOffer: 109 begin 110 result := ''; 111 if (OppCommand = scDipOffer) and 112 ((OppOffer.nDeliver > 0) or (OppOffer.nCost > 0)) and 113 (Offer.nCost + Offer.nDeliver <= 2) then 114 begin // respond to made offer before making own one 115 if (OppOffer.nDeliver + OppOffer.nCost = 1) and 116 (OppOffer.Price[0] and opMask = opTreaty) and 117 (integer(OppOffer.Price[0] - opTreaty) > Treaty) then 118 // simple treaty offer 119 result := Tribe[pSender].TPhrase('FRNOTACCEPTTREATY') + '\' 120 else if OppOffer.nDeliver = 0 then 121 result := Tribe[pSender].TPhrase('FRNOTACCEPTDEMAND_STRONG') + '\' 122 else if OppOffer.nCost = 0 then 123 result := Tribe[pSender].TPhrase('FRNOTACCEPTPRESENT') + '\'; 124 end; 125 126 sDeliver := ''; 127 for i := 0 to Offer.nDeliver - 1 do 128 begin 129 sAdd := PriceToString(pSender, Offer.Price[i]); 130 if i = 0 then 131 sDeliver := sAdd 132 else 133 sDeliver := Format(Phrases.Lookup('PRICE_CONCAT'), [sDeliver, sAdd]) 134 end; 135 sCost := ''; 136 for i := 0 to Offer.nCost - 1 do 137 begin 138 sAdd := PriceToString(pTarget, Offer.Price[Offer.nDeliver + i]); 139 if i = 0 then 140 sCost := sAdd 141 else 142 sCost := Format(Phrases.Lookup('PRICE_CONCAT'), [sCost, sAdd]) 143 end; 144 145 if (Offer.nDeliver = 0) and (Offer.nCost = 0) then 146 begin // no offer made 147 if (OppCommand = scDipOffer) and 148 ((OppOffer.nDeliver = 0) and (OppOffer.nCost = 0)) then 149 result := Tribe[pTarget].TPhrase('FRBYE') 150 else 136 151 begin 137 if (OppOffer.nDeliver=1) and (OppOffer.Price[0]=opChoose) 138 and not Phrases2FallenBackToEnglish then 139 result:=Tribe[pSender].TString(Phrases2.Lookup('FRNOTACCEPTANYOFFER'))+' ' 140 else if (OppOffer.nCost=1) and (OppOffer.Price[OppOffer.nDeliver]=opChoose) 141 and not Phrases2FallenBackToEnglish then 142 result:=Tribe[pSender].TString(Phrases2.Lookup('FRNOTACCEPTANYWANT'))+' ' 143 else result:=Tribe[pSender].TPhrase('FRNOTACCEPTOFFER')+' '; 144 end; 145 result:=result+Phrases.Lookup('FRDONE'); 146 DoIntro:=false 152 if (result = '') and (OppCommand = scDipOffer) and 153 ((OppOffer.nDeliver > 0) or (OppOffer.nCost > 0)) then 154 begin 155 if (OppOffer.nDeliver = 1) and (OppOffer.Price[0] = opChoose) and 156 not Phrases2FallenBackToEnglish then 157 result := Tribe[pSender].TString 158 (Phrases2.Lookup('FRNOTACCEPTANYOFFER')) + ' ' 159 else if (OppOffer.nCost = 1) and 160 (OppOffer.Price[OppOffer.nDeliver] = opChoose) and not Phrases2FallenBackToEnglish 161 then 162 result := Tribe[pSender].TString 163 (Phrases2.Lookup('FRNOTACCEPTANYWANT')) + ' ' 164 else 165 result := Tribe[pSender].TPhrase('FRNOTACCEPTOFFER') + ' '; 166 end; 167 result := result + Phrases.Lookup('FRDONE'); 168 DoIntro := false 169 end 147 170 end 148 end 149 else if (Offer.nDeliver+Offer.nCost=1) 150 and (Offer.Price[0] and opMask=opTreaty) 151 and (integer(Offer.Price[0]-opTreaty)>Treaty) then // simple treaty offer 152 begin 153 case Offer.Price[0]-opTreaty of 154 //trCeaseFire: result:=result+Tribe[pTarget].TPhrase('FRCEASEFIRE'); 155 trPeace: result:=result+Tribe[pTarget].TPhrase('FRPEACE'); 156 trFriendlyContact: result:=result+Tribe[pTarget].TPhrase('FRFRIENDLY'); 157 trAlliance: result:=result+Tribe[pTarget].TPhrase('FRALLIANCE'); 171 else if (Offer.nDeliver + Offer.nCost = 1) and 172 (Offer.Price[0] and opMask = opTreaty) and 173 (integer(Offer.Price[0] - opTreaty) > Treaty) then 174 // simple treaty offer 175 begin 176 case Offer.Price[0] - opTreaty of 177 // trCeaseFire: result:=result+Tribe[pTarget].TPhrase('FRCEASEFIRE'); 178 trPeace: 179 result := result + Tribe[pTarget].TPhrase('FRPEACE'); 180 trFriendlyContact: 181 result := result + Tribe[pTarget].TPhrase('FRFRIENDLY'); 182 trAlliance: 183 result := result + Tribe[pTarget].TPhrase('FRALLIANCE'); 184 end 158 185 end 159 end 160 else if Offer.nDeliver=0 then // demand 161 begin 162 if (Treaty>=trFriendlyContact) and not Phrases2FallenBackToEnglish then 163 result:=result+Format(Tribe[pTarget].TString(Phrases2.Lookup('FRDEMAND_SOFT')),[sCost]) 164 else 165 begin 166 result:=result+Format(Tribe[pTarget].TPhrase('FRDEMAND_STRONG'),[sCost]); 167 DoIntro:=false 186 else if Offer.nDeliver = 0 then // demand 187 begin 188 if (Treaty >= trFriendlyContact) and not Phrases2FallenBackToEnglish 189 then 190 result := result + 191 Format(Tribe[pTarget].TString(Phrases2.Lookup('FRDEMAND_SOFT') 192 ), [sCost]) 193 else 194 begin 195 result := result + 196 Format(Tribe[pTarget].TPhrase('FRDEMAND_STRONG'), [sCost]); 197 DoIntro := false 198 end 168 199 end 169 end 170 else if Offer.nCost=0 then // present 171 result:=result+Format(Tribe[pTarget].TPhrase('FRPRESENT'),[sDeliver]) 172 else if (Offer.nDeliver=1) and (Offer.Price[0]=opChoose) then 173 result:=result+Format(Phrases.Lookup('FRDELCHOICE'),[sCost]) 174 else if (Offer.nCost=1) and (Offer.Price[Offer.nDeliver]=opChoose) then 175 result:=result+Format(Phrases.Lookup('FRCOSTCHOICE'),[sDeliver]) 176 else result:=result+Format(Phrases.Lookup('FROFFER'),[sDeliver,sCost]); 177 end; 200 else if Offer.nCost = 0 then // present 201 result := result + Format(Tribe[pTarget].TPhrase('FRPRESENT'), 202 [sDeliver]) 203 else if (Offer.nDeliver = 1) and (Offer.Price[0] = opChoose) then 204 result := result + Format(Phrases.Lookup('FRDELCHOICE'), [sCost]) 205 else if (Offer.nCost = 1) and (Offer.Price[Offer.nDeliver] = opChoose) 206 then 207 result := result + Format(Phrases.Lookup('FRCOSTCHOICE'), [sDeliver]) 208 else 209 result := result + Format(Phrases.Lookup('FROFFER'), 210 [sDeliver, sCost]); 211 end; 178 212 end; 179 if DoIntro then 180 if Treaty<trPeace then 181 result:=Tribe[pSender].TPhrase('FRSTART_NOTREATY')+' '+result 182 else result:=Tribe[pSender].TPhrase('FRSTART_PEACE')+' '+result 213 if DoIntro then 214 if Treaty < trPeace then 215 result := Tribe[pSender].TPhrase('FRSTART_NOTREATY') + ' ' + result 216 else 217 result := Tribe[pSender].TPhrase('FRSTART_PEACE') + ' ' + result 183 218 end; 184 219 185 220 end. 186 -
trunk/LocalPlayer/Draft.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit Draft; 4 3 … … 6 5 7 6 uses 8 Protocol,ClientTools,Term,ScreenTools,PVSB,BaseWin, 9 10 Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,ExtCtrls,ButtonA, 7 Protocol, ClientTools, Term, ScreenTools, PVSB, BaseWin, 8 9 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, ExtCtrls, 10 ButtonA, 11 11 ButtonB, ButtonBase, Area; 12 12 … … 28 28 procedure FormDestroy(Sender: TObject); 29 29 public 30 procedure ShowNewContent(NewMode: integer); 30 procedure ShowNewContent(NewMode: integer); 31 31 protected 32 32 procedure OffscreenPaint; override; 33 33 private 34 Domain, MaxLines,Lines,Cut,yDomain,yFeature,yWeight,yTotal,yView,IncCap,35 DecCap: integer;36 code: array [0..nFeature-1] of integer;37 Template, Back: TBitmap;38 function IsFeatureInList(d, i: integer): boolean;34 Domain, MaxLines, Lines, Cut, yDomain, yFeature, yWeight, yTotal, yView, 35 IncCap, DecCap: integer; 36 code: array [0 .. nFeature - 1] of integer; 37 Template, Back: TBitmap; 38 function IsFeatureInList(d, i: integer): boolean; 39 39 procedure SetDomain(d: integer); 40 40 end; … … 45 45 implementation 46 46 47 uses Help, Tribes,Directories;47 uses Help, Tribes, Directories; 48 48 49 49 {$R *.DFM} 50 50 51 51 const 52 MaxLines0=11; LinePitch=20; 53 xDomain=30; yDomain0=464; DomainPitch=40; 54 xFeature=38; yFeature0=42; 55 xWeight=100; yWeight0=271; 56 xTotal=20; xTotal2=34; yTotal0=354; 57 xView=17; yView0=283; 52 MaxLines0 = 11; 53 LinePitch = 20; 54 xDomain = 30; 55 yDomain0 = 464; 56 DomainPitch = 40; 57 xFeature = 38; 58 yFeature0 = 42; 59 xWeight = 100; 60 yWeight0 = 271; 61 xTotal = 20; 62 xTotal2 = 34; 63 yTotal0 = 354; 64 xView = 17; 65 yView0 = 283; 58 66 59 67 procedure TDraftDlg.FormCreate(Sender: TObject); 60 68 begin 61 inherited;62 InitButtons();63 HelpContext:='CLASSES';64 Caption:=Phrases.Lookup('TITLE_DRAFT');65 OKBtn.Caption:=Phrases.Lookup('BTN_OK');66 67 if not Phrases2FallenBackToEnglish then68 begin 69 GroundArea.Hint:=Phrases2.Lookup('DRAFTDOMAIN',0);70 SeaArea.Hint:=Phrases2.Lookup('DRAFTDOMAIN',1);71 AirArea.Hint:=Phrases2.Lookup('DRAFTDOMAIN',2);69 inherited; 70 InitButtons(); 71 HelpContext := 'CLASSES'; 72 Caption := Phrases.Lookup('TITLE_DRAFT'); 73 OKBtn.Caption := Phrases.Lookup('BTN_OK'); 74 75 if not Phrases2FallenBackToEnglish then 76 begin 77 GroundArea.Hint := Phrases2.Lookup('DRAFTDOMAIN', 0); 78 SeaArea.Hint := Phrases2.Lookup('DRAFTDOMAIN', 1); 79 AirArea.Hint := Phrases2.Lookup('DRAFTDOMAIN', 2); 72 80 end 73 else 74 begin 75 GroundArea.Hint:=Phrases.Lookup('DOMAIN',0); 76 SeaArea.Hint:=Phrases.Lookup('DOMAIN',1); 77 AirArea.Hint:=Phrases.Lookup('DOMAIN',2); 78 end; 79 80 Back:=TBitmap.Create; 81 Back.PixelFormat:=pf24bit; 82 Back.Width:=ClientWidth; Back.Height:=ClientHeight; 83 Template:=TBitmap.Create; 84 LoadGraphicFile(Template, HomeDir+'Graphics\MiliRes', gfNoGamma); 85 Template.PixelFormat:=pf8bit; 81 else 82 begin 83 GroundArea.Hint := Phrases.Lookup('DOMAIN', 0); 84 SeaArea.Hint := Phrases.Lookup('DOMAIN', 1); 85 AirArea.Hint := Phrases.Lookup('DOMAIN', 2); 86 end; 87 88 Back := TBitmap.Create; 89 Back.PixelFormat := pf24bit; 90 Back.Width := ClientWidth; 91 Back.Height := ClientHeight; 92 Template := TBitmap.Create; 93 LoadGraphicFile(Template, HomeDir + 'Graphics\MiliRes', gfNoGamma); 94 Template.PixelFormat := pf8bit; 86 95 end; 87 96 88 97 procedure TDraftDlg.FormDestroy(Sender: TObject); 89 98 begin 90 Template.Free;99 Template.Free; 91 100 end; 92 101 93 102 procedure TDraftDlg.CloseBtnClick(Sender: TObject); 94 103 begin 95 ModalResult:=mrCancel;104 ModalResult := mrCancel; 96 105 end; 97 106 … … 100 109 function DomainAvailable(d: integer): boolean; 101 110 begin 102 result:=(upgrade[d,0].Preq=preNone)103 or (MyRO.Tech[upgrade[d,0].Preq]>=tsApplicable);111 result := (upgrade[d, 0].Preq = preNone) or 112 (MyRO.Tech[upgrade[d, 0].Preq] >= tsApplicable); 104 113 end; 105 114 106 115 procedure PaintTotalBars; 107 116 var 108 i,y,dx,num,w: integer; 109 s: string; 110 begin 111 with offscreen.Canvas do 112 begin 113 // strength bar 114 y:=yTotal; 115 DarkGradient(Offscreen.Canvas,xTotal-6,y+1,184,2); 116 DarkGradient(Offscreen.Canvas,xTotal2+172,y+1,95,2); 117 RisedTextOut(Offscreen.Canvas,xTotal-2,y,Phrases.Lookup('UNITSTRENGTH')); 118 RisedTextOut(Offscreen.Canvas,xTotal+112+30,y,'x'+IntToStr(MyRO.DevModel.MStrength)); 119 RisedTextOut(Offscreen.Canvas,xTotal2+148+30,y,'='); 120 s:=IntToStr(MyRO.DevModel.Attack)+'/'+IntToStr(MyRO.DevModel.Defense); 121 RisedTextOut(Offscreen.Canvas,xTotal2+170+64+30-BiColorTextWidth(Offscreen.Canvas,s),y,s); 122 123 // transport bar 124 if MyRO.DevModel.MTrans>0 then 117 i, y, dx, num, w: integer; 118 s: string; 119 begin 120 with offscreen.Canvas do 121 begin 122 // strength bar 123 y := yTotal; 124 DarkGradient(offscreen.Canvas, xTotal - 6, y + 1, 184, 2); 125 DarkGradient(offscreen.Canvas, xTotal2 + 172, y + 1, 95, 2); 126 RisedTextOut(offscreen.Canvas, xTotal - 2, y, 127 Phrases.Lookup('UNITSTRENGTH')); 128 RisedTextOut(offscreen.Canvas, xTotal + 112 + 30, y, 129 'x' + IntToStr(MyRO.DevModel.MStrength)); 130 RisedTextOut(offscreen.Canvas, xTotal2 + 148 + 30, y, '='); 131 s := IntToStr(MyRO.DevModel.Attack) + '/' + 132 IntToStr(MyRO.DevModel.Defense); 133 RisedTextOut(offscreen.Canvas, xTotal2 + 170 + 64 + 30 - 134 BiColorTextWidth(offscreen.Canvas, s), y, s); 135 136 // transport bar 137 if MyRO.DevModel.MTrans > 0 then 125 138 begin 126 y:=yTotal+19; 127 DarkGradient(Offscreen.Canvas,xTotal-6,y+1,184,1); 128 DarkGradient(Offscreen.Canvas,xTotal2+172,y+1,95,1); 129 RisedTextOut(Offscreen.Canvas,xTotal-2,y,Phrases.Lookup('UNITTRANSPORT')); 130 RisedTextOut(Offscreen.Canvas,xTotal+112+30,y,'x'+IntToStr(MyRO.DevModel.MTrans)); 131 RisedTextOut(Offscreen.Canvas,xTotal2+148+30,y,'='); 132 133 Font.Color:=$000000; 134 dx:=-237-30; 135 for i:=mcFirstNonCap-1 downto 3 do 136 if i in [mcSeaTrans,mcCarrier,mcAirTrans] then 139 y := yTotal + 19; 140 DarkGradient(offscreen.Canvas, xTotal - 6, y + 1, 184, 1); 141 DarkGradient(offscreen.Canvas, xTotal2 + 172, y + 1, 95, 1); 142 RisedTextOut(offscreen.Canvas, xTotal - 2, y, 143 Phrases.Lookup('UNITTRANSPORT')); 144 RisedTextOut(offscreen.Canvas, xTotal + 112 + 30, y, 145 'x' + IntToStr(MyRO.DevModel.MTrans)); 146 RisedTextOut(offscreen.Canvas, xTotal2 + 148 + 30, y, '='); 147 148 Font.Color := $000000; 149 dx := -237 - 30; 150 for i := mcFirstNonCap - 1 downto 3 do 151 if i in [mcSeaTrans, mcCarrier, mcAirTrans] then 137 152 begin 138 num:=MyRO.DevModel.Cap[i]*MyRO.DevModel.MTrans;139 if num>0 then153 num := MyRO.DevModel.Cap[i] * MyRO.DevModel.MTrans; 154 if num > 0 then 140 155 begin 141 inc(dx,15); 142 Brush.Color:=$C0C0C0; 143 FrameRect(Rect(xTotal2-3-dx,y+2,xTotal2+11-dx,y+16)); 144 Brush.Style:=bsClear; 145 Sprite(Offscreen,HGrSystem,xTotal2-1-dx,y+4,10,10,66+i mod 11 *11,137+i div 11 *11); 146 if num>1 then 156 inc(dx, 15); 157 Brush.Color := $C0C0C0; 158 FrameRect(Rect(xTotal2 - 3 - dx, y + 2, 159 xTotal2 + 11 - dx, y + 16)); 160 Brush.Style := bsClear; 161 Sprite(offscreen, HGrSystem, xTotal2 - 1 - dx, y + 4, 10, 10, 162 66 + i mod 11 * 11, 137 + i div 11 * 11); 163 if num > 1 then 147 164 begin 148 s:=IntToStr(num); 149 w:=TextWidth(s); 150 inc(dx,w+1); 151 Brush.Color:=$FFFFFF; 152 FillRect(Rect(xTotal2-3-dx,y+2,xTotal2+w-1-dx,y+16)); 153 Brush.Style:=bsClear; 154 Textout(xTotal2-3-dx+1,y,s); 165 s := IntToStr(num); 166 w := TextWidth(s); 167 inc(dx, w + 1); 168 Brush.Color := $FFFFFF; 169 FillRect(Rect(xTotal2 - 3 - dx, y + 2, 170 xTotal2 + w - 1 - dx, y + 16)); 171 Brush.Style := bsClear; 172 Textout(xTotal2 - 3 - dx + 1, y, s); 155 173 end; 156 174 end; … … 158 176 end; 159 177 160 // speed bar 161 y:=yTotal+38; 162 LoweredTextOut(offscreen.Canvas,-1,MainTexture,xTotal-2,y,Phrases.Lookup('UNITSPEED')); 163 DLine(offscreen.Canvas,xTotal-2,xTotal+174,y+16,MainTexture.clBevelShade, 164 MainTexture.clBevelLight); 165 DLine(offscreen.Canvas,xTotal2+176,xTotal2+263,y+16,MainTexture.clBevelShade, 166 MainTexture.clBevelLight); 167 s:=MovementToString(MyRO.DevModel.Speed); 168 RisedTextOut(offscreen.Canvas,xTotal2+170+64+30-TextWidth(s),y,s); 169 170 // cost bar 171 y:=yTotal+57; 172 LoweredTextOut(offscreen.Canvas,-1,MainTexture,xTotal-2,y,Phrases.Lookup('UNITCOST')); 173 LoweredTextOut(Offscreen.Canvas,-1,MainTexture,xTotal+112+30,y,'x'+IntToStr(MyRO.DevModel.MCost)); 174 LoweredTextOut(Offscreen.Canvas,-1,MainTexture,xTotal2+148+30,y,'='); 175 DLine(offscreen.Canvas,xTotal-2,xTotal+174,y+16,MainTexture.clBevelShade, 176 MainTexture.clBevelLight); 177 DLine(offscreen.Canvas,xTotal2+176,xTotal2+263,y+16,MainTexture.clBevelShade, 178 MainTexture.clBevelLight); 179 s:=IntToStr(MyRO.DevModel.Cost); 180 RisedTextOut(offscreen.Canvas,xTotal2+170+64+30-12-TextWidth(s),y,s); 181 Sprite(offscreen,HGrSystem,xTotal2+170+54+30,y+4,10,10,88,115); 182 183 if G.Difficulty[me]<>2 then 178 // speed bar 179 y := yTotal + 38; 180 LoweredTextOut(offscreen.Canvas, -1, MainTexture, xTotal - 2, y, 181 Phrases.Lookup('UNITSPEED')); 182 DLine(offscreen.Canvas, xTotal - 2, xTotal + 174, y + 16, 183 MainTexture.clBevelShade, MainTexture.clBevelLight); 184 DLine(offscreen.Canvas, xTotal2 + 176, xTotal2 + 263, y + 16, 185 MainTexture.clBevelShade, MainTexture.clBevelLight); 186 s := MovementToString(MyRO.DevModel.Speed); 187 RisedTextOut(offscreen.Canvas, xTotal2 + 170 + 64 + 30 - 188 TextWidth(s), y, s); 189 190 // cost bar 191 y := yTotal + 57; 192 LoweredTextOut(offscreen.Canvas, -1, MainTexture, xTotal - 2, y, 193 Phrases.Lookup('UNITCOST')); 194 LoweredTextOut(offscreen.Canvas, -1, MainTexture, xTotal + 112 + 30, y, 195 'x' + IntToStr(MyRO.DevModel.MCost)); 196 LoweredTextOut(offscreen.Canvas, -1, MainTexture, 197 xTotal2 + 148 + 30, y, '='); 198 DLine(offscreen.Canvas, xTotal - 2, xTotal + 174, y + 16, 199 MainTexture.clBevelShade, MainTexture.clBevelLight); 200 DLine(offscreen.Canvas, xTotal2 + 176, xTotal2 + 263, y + 16, 201 MainTexture.clBevelShade, MainTexture.clBevelLight); 202 s := IntToStr(MyRO.DevModel.Cost); 203 RisedTextOut(offscreen.Canvas, xTotal2 + 170 + 64 + 30 - 12 - 204 TextWidth(s), y, s); 205 Sprite(offscreen, HGrSystem, xTotal2 + 170 + 54 + 30, y + 4, 10, 206 10, 88, 115); 207 208 if G.Difficulty[me] <> 2 then 184 209 begin // corrected cost bar 185 y:=yTotal+76; 186 LoweredTextOut(offscreen.Canvas,-1,MainTexture,xTotal-2,y, 187 Phrases.Lookup('COSTDIFF'+char(48+G.Difficulty[me]))); 188 LoweredTextOut(Offscreen.Canvas,-1,MainTexture,xTotal2+148+30,y,'='); 189 DLine(offscreen.Canvas,xTotal-2,xTotal+174,y+16,MainTexture.clBevelShade, 190 MainTexture.clBevelLight); 191 DLine(offscreen.Canvas,xTotal2+176,xTotal2+263,y+16,MainTexture.clBevelShade, 192 MainTexture.clBevelLight); 193 s:=IntToStr(MyRO.DevModel.Cost*BuildCostMod[G.Difficulty[me]] div 12); 194 RisedTextOut(offscreen.Canvas,xTotal2+170+64+30-12-TextWidth(s),y,s); 195 Sprite(offscreen,HGrSystem,xTotal2+170+54+30,y+4,10,10,88,115); 210 y := yTotal + 76; 211 LoweredTextOut(offscreen.Canvas, -1, MainTexture, xTotal - 2, y, 212 Phrases.Lookup('COSTDIFF' + char(48 + G.Difficulty[me]))); 213 LoweredTextOut(offscreen.Canvas, -1, MainTexture, 214 xTotal2 + 148 + 30, y, '='); 215 DLine(offscreen.Canvas, xTotal - 2, xTotal + 174, y + 16, 216 MainTexture.clBevelShade, MainTexture.clBevelLight); 217 DLine(offscreen.Canvas, xTotal2 + 176, xTotal2 + 263, y + 16, 218 MainTexture.clBevelShade, MainTexture.clBevelLight); 219 s := IntToStr(MyRO.DevModel.Cost * BuildCostMod 220 [G.Difficulty[me]] div 12); 221 RisedTextOut(offscreen.Canvas, xTotal2 + 170 + 64 + 30 - 12 - 222 TextWidth(s), y, s); 223 Sprite(offscreen, HGrSystem, xTotal2 + 170 + 54 + 30, y + 4, 10, 224 10, 88, 115); 196 225 end; 197 226 end; … … 199 228 200 229 var 201 i,j,x,d,n,TextColor,CapWeight,DomainCount: integer; 202 begin 203 inherited; 204 205 ClientHeight:=Template.Height-Cut; 206 if ClientHeight>hMainTexture then // assemble background from 2 texture tiles 207 begin 208 bitblt(Back.Canvas.Handle,0,0,ClientWidth,64,MainTexture.Image.Canvas.Handle, 209 (wMainTexture-ClientWidth) div 2,hMainTexture-64,SRCCOPY); 210 bitblt(Back.Canvas.Handle,0,64,ClientWidth,ClientHeight-64, 211 MainTexture.Image.Canvas.Handle,(wMainTexture-ClientWidth) div 2,0,SRCCOPY); 230 i, j, x, d, n, TextColor, CapWeight, DomainCount: integer; 231 begin 232 inherited; 233 234 ClientHeight := Template.Height - Cut; 235 if ClientHeight > hMainTexture then 236 // assemble background from 2 texture tiles 237 begin 238 bitblt(Back.Canvas.Handle, 0, 0, ClientWidth, 64, 239 MainTexture.Image.Canvas.Handle, (wMainTexture - ClientWidth) div 2, 240 hMainTexture - 64, SRCCOPY); 241 bitblt(Back.Canvas.Handle, 0, 64, ClientWidth, ClientHeight - 64, 242 MainTexture.Image.Canvas.Handle, (wMainTexture - ClientWidth) div 2, 243 0, SRCCOPY); 212 244 end 213 else bitblt(Back.Canvas.Handle,0,0,ClientWidth,ClientHeight,MainTexture.Image.Canvas.Handle, 214 (wMainTexture-ClientWidth) div 2,(hMainTexture-ClientHeight) div 2,SRCCOPY); 215 ImageOp_B(Back,Template,0,0,0,0,Template.Width,64); 216 ImageOp_B(Back,Template,0,64,0,64+Cut,Template.Width,Template.Height-64-Cut); 217 218 bitblt(offscreen.canvas.handle,0,0,ClientWidth,ClientHeight,Back.Canvas.handle,0,0,SRCCOPY); 219 220 offscreen.Canvas.Font.Assign(UniFont[ftCaption]); 221 RisedTextout(offscreen.Canvas,10,7,Caption); 222 offscreen.Canvas.Font.Assign(UniFont[ftSmall]); 223 224 with MyRO.DevModel do 225 begin 226 DomainCount:=0; 227 for d:=0 to nDomains-1 do 228 if DomainAvailable(d) then 229 inc(DomainCount); 230 if DomainCount>1 then 231 begin 232 for d:=0 to nDomains-1 do 245 else 246 bitblt(Back.Canvas.Handle, 0, 0, ClientWidth, ClientHeight, 247 MainTexture.Image.Canvas.Handle, (wMainTexture - ClientWidth) div 2, 248 (hMainTexture - ClientHeight) div 2, SRCCOPY); 249 ImageOp_B(Back, Template, 0, 0, 0, 0, Template.Width, 64); 250 ImageOp_B(Back, Template, 0, 64, 0, 64 + Cut, Template.Width, 251 Template.Height - 64 - Cut); 252 253 bitblt(offscreen.Canvas.Handle, 0, 0, ClientWidth, ClientHeight, 254 Back.Canvas.Handle, 0, 0, SRCCOPY); 255 256 offscreen.Canvas.Font.Assign(UniFont[ftCaption]); 257 RisedTextOut(offscreen.Canvas, 10, 7, Caption); 258 offscreen.Canvas.Font.Assign(UniFont[ftSmall]); 259 260 with MyRO.DevModel do 261 begin 262 DomainCount := 0; 263 for d := 0 to nDomains - 1 do 233 264 if DomainAvailable(d) then 265 inc(DomainCount); 266 if DomainCount > 1 then 267 begin 268 for d := 0 to nDomains - 1 do 269 if DomainAvailable(d) then 234 270 begin 235 x:=xDomain+d*DomainPitch; 236 if d=Domain then 237 ImageOp_BCC(Offscreen,Templates,x,yDomain,142,246+37*d,36,36,0,$00C0FF) 238 else ImageOp_BCC(Offscreen,Templates,x,yDomain,142,246+37*d,36,36,0,$606060); 271 x := xDomain + d * DomainPitch; 272 if d = Domain then 273 ImageOp_BCC(offscreen, Templates, x, yDomain, 142, 246 + 37 * d, 36, 274 36, 0, $00C0FF) 275 else 276 ImageOp_BCC(offscreen, Templates, x, yDomain, 142, 246 + 37 * d, 36, 277 36, 0, $606060); 239 278 end; 240 Frame(Offscreen.Canvas,xDomain-11,yDomain-3,xDomain+2*DomainPitch+46,241 yDomain+38,$B0B0B0,$FFFFFF);242 RFrame(Offscreen.Canvas,xDomain-12,yDomain-4,xDomain+2*DomainPitch+47,243 yDomain+39,$FFFFFF,$B0B0B0);244 end; 245 GroundArea.Top:=yDomain;246 GroundArea.Visible:=DomainAvailable(dGround);247 SeaArea.Top:=yDomain;248 SeaArea.Visible:=DomainAvailable(dSea);249 AirArea.Top:=yDomain;250 AirArea.Visible:=DomainAvailable(dAir);251 252 PaintTotalBars;253 254 // display weight255 with offscreen.Canvas do256 begin 257 for i:=0 to MaxWeight-1 do258 if i<Weight then259 ImageOp_BCC(Offscreen,Templates,xWeight+20*i,260 yWeight,123,400,18,20,0,$949494)261 else ImageOp_BCC(Offscreen,Templates,xWeight+20*i,262 yWeight,105,400,18,20,0,$949494);263 end;264 265 with offscreen.Canvas do for i:=0 to Lines-1 do 266 begin267 if not (code[i] in AutoFeature) then279 Frame(offscreen.Canvas, xDomain - 11, yDomain - 3, 280 xDomain + 2 * DomainPitch + 46, yDomain + 38, $B0B0B0, $FFFFFF); 281 RFrame(offscreen.Canvas, xDomain - 12, yDomain - 4, 282 xDomain + 2 * DomainPitch + 47, yDomain + 39, $FFFFFF, $B0B0B0); 283 end; 284 GroundArea.Top := yDomain; 285 GroundArea.Visible := DomainAvailable(dGround); 286 SeaArea.Top := yDomain; 287 SeaArea.Visible := DomainAvailable(dSea); 288 AirArea.Top := yDomain; 289 AirArea.Visible := DomainAvailable(dAir); 290 291 PaintTotalBars; 292 293 // display weight 294 with offscreen.Canvas do 295 begin 296 for i := 0 to MaxWeight - 1 do 297 if i < Weight then 298 ImageOp_BCC(offscreen, Templates, xWeight + 20 * i, yWeight, 123, 400, 299 18, 20, 0, $949494) 300 else 301 ImageOp_BCC(offscreen, Templates, xWeight + 20 * i, yWeight, 105, 400, 302 18, 20, 0, $949494); 303 end; 304 305 with offscreen.Canvas do 306 for i := 0 to Lines - 1 do 268 307 begin 269 // paint +/- butttons 270 if code[i]<mcFirstNonCap then 308 if not(code[i] in AutoFeature) then 271 309 begin 272 Dump(offscreen,HGrSystem,xFeature-21,yFeature+2+LinePitch*i, 273 12,12,169,172); 274 Dump(offscreen,HGrSystem,xFeature-9,yFeature+2+LinePitch*i, 275 12,12,169,159); 276 RFrame(offscreen.Canvas,xFeature-(21+1),yFeature+2+LinePitch*i-1, 277 xFeature-(21-24),yFeature+2+LinePitch*i+12, 278 MainTexture.clBevelShade,MainTexture.clBevelLight); 279 end 280 else 281 begin 282 Dump(offscreen,HGrSystem,xFeature-9,yFeature+2+LinePitch*i, 283 12,12,169,185+13*MyRO.DevModel.Cap[code[i]]); 284 RFrame(offscreen.Canvas,xFeature-(9+1),yFeature+2+LinePitch*i-1, 285 xFeature-(21-24),yFeature+2+LinePitch*i+12, 286 MainTexture.clBevelShade,MainTexture.clBevelLight); 287 end; 288 289 // paint cost 290 LightGradient(offscreen.Canvas,xFeature+34,yFeature+LinePitch*i,50, 291 GrExt[HGrSystem].Data.Canvas.Pixels[187,137]); 292 if (Domain=dGround) and (code[i]=mcDefense) then CapWeight:=2 293 else CapWeight:=Feature[code[i]].Weight; 294 n:=CapWeight+Feature[code[i]].Cost; 295 d:=6; 296 while (n-1)*d*2>48-10 do dec(d); 297 for j:=0 to n-1 do 298 if j<CapWeight then 299 Sprite(offscreen,HGrSystem,xFeature+54+(j*2+1-n)*d, 300 yFeature+2+LinePitch*i+1,10,10,88,126) 301 else Sprite(offscreen,HGrSystem,xFeature+54+(j*2+1-n)*d, 302 yFeature+2+LinePitch*i+1,10,10,88,115); 303 end; // if not (code[i] in AutoFeature) 304 DarkGradient(offscreen.Canvas,xFeature+17,yFeature+LinePitch*i,16,1); 305 Frame(offscreen.canvas,xFeature+18,yFeature+1+LinePitch*i, 306 xFeature+20-2+13,yFeature+2+1-2+13+LinePitch*i,$C0C0C0,$C0C0C0); 307 Sprite(offscreen,HGrSystem,xFeature+20,yFeature+2+1+LinePitch*i, 308 10,10,66+code[i] mod 11 *11,137+code[i] div 11 *11); 309 310 if MyRO.DevModel.Cap[code[i]]>0 then TextColor:=MainTexture.clLitText 311 else TextColor:=-1; 312 313 if code[i]<mcFirstNonCap then 314 LoweredTextOut(offscreen.Canvas,TextColor,MainTexture,xFeature+7, 315 yFeature+LinePitch*i-1,IntToStr(MyRO.DevModel.Cap[code[i]])); 316 LoweredTextOut(offscreen.Canvas,TextColor,MainTexture,xFeature+88, 317 yFeature+LinePitch*i-1,Phrases.Lookup('FEATURES',code[i])); 318 end; 319 end; 320 321 // free features 322 j:=0; 323 for i:=0 to nFeature-1 do 324 if (i in AutoFeature) 325 and (1 shl Domain and Feature[i].Domains<>0) and (Feature[i].Preq<>preNA) 326 and ((Feature[i].Preq=preSun) and (MyRO.Wonder[woSun].EffectiveOwner=me) 327 or (Feature[i].Preq>=0) and (MyRO.Tech[Feature[i].Preq]>=tsApplicable)) 328 and not ((Feature[i].Preq=adSteamEngine) 329 and (MyRO.Tech[adNuclearPower]>=tsApplicable)) then 330 begin 331 DarkGradient(offscreen.Canvas,xWeight+4,yWeight+32+LinePitch*j,16,1); 332 Frame(offscreen.canvas,xWeight+5,yWeight+33+LinePitch*j, 333 xWeight+18,yWeight+47+LinePitch*j,$C0C0C0,$C0C0C0); 334 Sprite(offscreen,HGrSystem,xWeight+7,yWeight+36+LinePitch*j, 335 10,10,66+i mod 11 *11,137+i div 11 *11); 336 LoweredTextOut(offscreen.Canvas,-1,MainTexture,xWeight+26, 337 yWeight+31+LinePitch*j,Phrases.Lookup('FEATURES',i)); 338 inc(j); 339 end; 340 341 with Tribe[me].ModelPicture[MyRO.nModel] do 342 begin 343 FrameImage(offscreen.canvas,BigImp,xView+4,yView+4,xSizeBig,ySizeBig,0,0); 344 Sprite(offscreen,HGr,xView,yView,64,44,pix mod 10 *65+1,pix div 10*49+1); 345 end; 346 MarkUsedOffscreen(ClientWidth,ClientHeight); 347 end;{MainPaint} 310 // paint +/- butttons 311 if code[i] < mcFirstNonCap then 312 begin 313 Dump(offscreen, HGrSystem, xFeature - 21, yFeature + 2 + LinePitch * 314 i, 12, 12, 169, 172); 315 Dump(offscreen, HGrSystem, xFeature - 9, yFeature + 2 + LinePitch * 316 i, 12, 12, 169, 159); 317 RFrame(offscreen.Canvas, xFeature - (21 + 1), 318 yFeature + 2 + LinePitch * i - 1, xFeature - (21 - 24), 319 yFeature + 2 + LinePitch * i + 12, MainTexture.clBevelShade, 320 MainTexture.clBevelLight); 321 end 322 else 323 begin 324 Dump(offscreen, HGrSystem, xFeature - 9, yFeature + 2 + LinePitch * 325 i, 12, 12, 169, 185 + 13 * MyRO.DevModel.Cap[code[i]]); 326 RFrame(offscreen.Canvas, xFeature - (9 + 1), 327 yFeature + 2 + LinePitch * i - 1, xFeature - (21 - 24), 328 yFeature + 2 + LinePitch * i + 12, MainTexture.clBevelShade, 329 MainTexture.clBevelLight); 330 end; 331 332 // paint cost 333 LightGradient(offscreen.Canvas, xFeature + 34, 334 yFeature + LinePitch * i, 50, GrExt[HGrSystem].Data.Canvas.Pixels 335 [187, 137]); 336 if (Domain = dGround) and (code[i] = mcDefense) then 337 CapWeight := 2 338 else 339 CapWeight := Feature[code[i]].Weight; 340 n := CapWeight + Feature[code[i]].Cost; 341 d := 6; 342 while (n - 1) * d * 2 > 48 - 10 do 343 dec(d); 344 for j := 0 to n - 1 do 345 if j < CapWeight then 346 Sprite(offscreen, HGrSystem, xFeature + 54 + (j * 2 + 1 - n) * d, 347 yFeature + 2 + LinePitch * i + 1, 10, 10, 88, 126) 348 else 349 Sprite(offscreen, HGrSystem, xFeature + 54 + (j * 2 + 1 - n) * d, 350 yFeature + 2 + LinePitch * i + 1, 10, 10, 88, 115); 351 end; // if not (code[i] in AutoFeature) 352 DarkGradient(offscreen.Canvas, xFeature + 17, 353 yFeature + LinePitch * i, 16, 1); 354 Frame(offscreen.Canvas, xFeature + 18, yFeature + 1 + LinePitch * i, 355 xFeature + 20 - 2 + 13, yFeature + 2 + 1 - 2 + 13 + LinePitch * i, 356 $C0C0C0, $C0C0C0); 357 Sprite(offscreen, HGrSystem, xFeature + 20, yFeature + 2 + 1 + LinePitch 358 * i, 10, 10, 66 + code[i] mod 11 * 11, 137 + code[i] div 11 * 11); 359 360 if MyRO.DevModel.Cap[code[i]] > 0 then 361 TextColor := MainTexture.clLitText 362 else 363 TextColor := -1; 364 365 if code[i] < mcFirstNonCap then 366 LoweredTextOut(offscreen.Canvas, TextColor, MainTexture, xFeature + 7, 367 yFeature + LinePitch * i - 1, IntToStr(MyRO.DevModel.Cap[code[i]])); 368 LoweredTextOut(offscreen.Canvas, TextColor, MainTexture, xFeature + 88, 369 yFeature + LinePitch * i - 1, Phrases.Lookup('FEATURES', code[i])); 370 end; 371 end; 372 373 // free features 374 j := 0; 375 for i := 0 to nFeature - 1 do 376 if (i in AutoFeature) and (1 shl Domain and Feature[i].Domains <> 0) and 377 (Feature[i].Preq <> preNA) and 378 ((Feature[i].Preq = preSun) and (MyRO.Wonder[woSun].EffectiveOwner = me) 379 or (Feature[i].Preq >= 0) and (MyRO.Tech[Feature[i].Preq] >= tsApplicable) 380 ) and not((Feature[i].Preq = adSteamEngine) and 381 (MyRO.Tech[adNuclearPower] >= tsApplicable)) then 382 begin 383 DarkGradient(offscreen.Canvas, xWeight + 4, yWeight + 32 + LinePitch 384 * j, 16, 1); 385 Frame(offscreen.Canvas, xWeight + 5, yWeight + 33 + LinePitch * j, 386 xWeight + 18, yWeight + 47 + LinePitch * j, $C0C0C0, $C0C0C0); 387 Sprite(offscreen, HGrSystem, xWeight + 7, yWeight + 36 + LinePitch * j, 388 10, 10, 66 + i mod 11 * 11, 137 + i div 11 * 11); 389 LoweredTextOut(offscreen.Canvas, -1, MainTexture, xWeight + 26, 390 yWeight + 31 + LinePitch * j, Phrases.Lookup('FEATURES', i)); 391 inc(j); 392 end; 393 394 with Tribe[me].ModelPicture[MyRO.nModel] do 395 begin 396 FrameImage(offscreen.Canvas, BigImp, xView + 4, yView + 4, xSizeBig, 397 ySizeBig, 0, 0); 398 Sprite(offscreen, HGr, xView, yView, 64, 44, pix mod 10 * 65 + 1, 399 pix div 10 * 49 + 1); 400 end; 401 MarkUsedOffscreen(ClientWidth, ClientHeight); 402 end; { MainPaint } 348 403 349 404 procedure TDraftDlg.SetDomain(d: integer); … … 351 406 function Prio(fix: integer): integer; 352 407 var 353 FeaturePreq: integer; 354 begin 355 FeaturePreq:=Feature[fix].Preq; 356 assert(FeaturePreq<>preNA); 357 if fix<mcFirstNonCap then result:=10000+fix 358 else if FeaturePreq=preNone then result:=20000 359 else if FeaturePreq<0 then result:=40000 360 else result:=30000+AdvValue[FeaturePreq]; 361 if not (fix in AutoFeature) then inc(result,90000); 408 FeaturePreq: integer; 409 begin 410 FeaturePreq := Feature[fix].Preq; 411 assert(FeaturePreq <> preNA); 412 if fix < mcFirstNonCap then 413 result := 10000 + fix 414 else if FeaturePreq = preNone then 415 result := 20000 416 else if FeaturePreq < 0 then 417 result := 40000 418 else 419 result := 30000 + AdvValue[FeaturePreq]; 420 if not(fix in AutoFeature) then 421 inc(result, 90000); 362 422 end; 363 423 364 424 var 365 i,j,x: integer; 366 begin 367 Domain:=d; 368 Lines:=0; 369 for i:=0 to nFeature-1 do 370 if IsFeatureInList(Domain,i) then 371 begin code[Lines]:=i; inc(Lines) end; 372 yFeature:=yFeature0+(MaxLines-Lines)*LinePitch div 2; 373 374 // sort features 375 for i:=0 to Lines-2 do for j:=i+1 to Lines-1 do 376 if Prio(code[i])>Prio(code[j]) then 377 begin // exchange 378 x:=code[i]; 379 code[i]:=code[j]; 380 code[j]:=x 381 end; 382 end; 383 384 function TDraftDlg.IsFeatureInList(d,i: integer): boolean; 385 begin 386 result:= not (i in AutoFeature) 387 and (1 shl d and Feature[i].Domains<>0) and (Feature[i].Preq<>preNA) 388 and ((Feature[i].Preq=preNone) 389 or (Feature[i].Preq=preSun) and (MyRO.Wonder[woSun].EffectiveOwner=me) 390 or (Feature[i].Preq>=0) and (MyRO.Tech[Feature[i].Preq]>=tsApplicable)); 425 i, j, x: integer; 426 begin 427 Domain := d; 428 Lines := 0; 429 for i := 0 to nFeature - 1 do 430 if IsFeatureInList(Domain, i) then 431 begin 432 code[Lines] := i; 433 inc(Lines) 434 end; 435 yFeature := yFeature0 + (MaxLines - Lines) * LinePitch div 2; 436 437 // sort features 438 for i := 0 to Lines - 2 do 439 for j := i + 1 to Lines - 1 do 440 if Prio(code[i]) > Prio(code[j]) then 441 begin // exchange 442 x := code[i]; 443 code[i] := code[j]; 444 code[j] := x 445 end; 446 end; 447 448 function TDraftDlg.IsFeatureInList(d, i: integer): boolean; 449 begin 450 result := not(i in AutoFeature) and (1 shl d and Feature[i].Domains <> 0) and 451 (Feature[i].Preq <> preNA) and 452 ((Feature[i].Preq = preNone) or (Feature[i].Preq = preSun) and 453 (MyRO.Wonder[woSun].EffectiveOwner = me) or (Feature[i].Preq >= 0) and 454 (MyRO.Tech[Feature[i].Preq] >= tsApplicable)); 391 455 end; 392 456 393 457 procedure TDraftDlg.FormShow(Sender: TObject); 394 458 var 395 count,d,i: integer; 396 begin 397 Domain:=dGround; 398 while (Domain<dAir) and (upgrade[Domain,0].Preq<>preNone) 399 and (MyRO.Tech[upgrade[Domain,0].Preq]<tsApplicable) do inc(Domain); 400 401 // count max number of features in any domain 402 MaxLines:=0; 403 for d:=0 to nDomains-1 do 404 if (upgrade[d,0].Preq=preNone) 405 or (MyRO.Tech[upgrade[d,0].Preq]>=tsApplicable) then 406 begin 407 count:=0; 408 for i:=0 to nFeature-1 do 409 if IsFeatureInList(d,i) then 410 inc(count); 411 if count>MaxLines then 412 MaxLines:=count; 413 end; 414 Cut:=(MaxLines0-MaxLines)*LinePitch; 415 OKBtn.Top:=477-Cut; 416 yDomain:=yDomain0-Cut; 417 yWeight:=yWeight0-Cut; 418 yTotal:=yTotal0-Cut; 419 yView:=yView0-Cut; 420 421 if WindowMode=wmModal then 422 begin {center on screen} 423 Left:=(Screen.Width-Template.Width) div 2; 424 Top:=(Screen.Height-(Template.Height-Cut)) div 2; 425 end; 426 427 SetDomain(Domain); 428 Server(sCreateDevModel,me,Domain,nil^); 429 MyModel[MyRO.nModel]:=MyRO.DevModel; 430 InitMyModel(MyRO.nModel,false); 431 OffscreenPaint; 432 IncCap:=-1; DecCap:=-1; 459 count, d, i: integer; 460 begin 461 Domain := dGround; 462 while (Domain < dAir) and (upgrade[Domain, 0].Preq <> preNone) and 463 (MyRO.Tech[upgrade[Domain, 0].Preq] < tsApplicable) do 464 inc(Domain); 465 466 // count max number of features in any domain 467 MaxLines := 0; 468 for d := 0 to nDomains - 1 do 469 if (upgrade[d, 0].Preq = preNone) or 470 (MyRO.Tech[upgrade[d, 0].Preq] >= tsApplicable) then 471 begin 472 count := 0; 473 for i := 0 to nFeature - 1 do 474 if IsFeatureInList(d, i) then 475 inc(count); 476 if count > MaxLines then 477 MaxLines := count; 478 end; 479 Cut := (MaxLines0 - MaxLines) * LinePitch; 480 OKBtn.Top := 477 - Cut; 481 yDomain := yDomain0 - Cut; 482 yWeight := yWeight0 - Cut; 483 yTotal := yTotal0 - Cut; 484 yView := yView0 - Cut; 485 486 if WindowMode = wmModal then 487 begin { center on screen } 488 Left := (Screen.Width - Template.Width) div 2; 489 Top := (Screen.Height - (Template.Height - Cut)) div 2; 490 end; 491 492 SetDomain(Domain); 493 Server(sCreateDevModel, me, Domain, nil^); 494 MyModel[MyRO.nModel] := MyRO.DevModel; 495 InitMyModel(MyRO.nModel, false); 496 OffscreenPaint; 497 IncCap := -1; 498 DecCap := -1; 433 499 end; 434 500 435 501 procedure TDraftDlg.ShowNewContent(NewMode: integer); 436 502 begin 437 inherited ShowNewContent(NewMode);503 inherited ShowNewContent(NewMode); 438 504 end; 439 505 … … 441 507 Shift: TShiftState; x, y: integer); 442 508 var 443 i,d: integer; 444 begin 445 if Button=mbLeft then 446 begin 447 for d:=0 to nDomains-1 do 448 if (d<>Domain) and ((upgrade[d,0].Preq=preNone) 449 or (MyRO.Tech[upgrade[d,0].Preq]>=tsApplicable)) 450 and (x>=xDomain+d*DomainPitch) and (x<xDomain+d*DomainPitch+36) 451 and (y>=yDomain) and (y<yDomain+36) then 509 i, d: integer; 510 begin 511 if Button = mbLeft then 512 begin 513 for d := 0 to nDomains - 1 do 514 if (d <> Domain) and ((upgrade[d, 0].Preq = preNone) or 515 (MyRO.Tech[upgrade[d, 0].Preq] >= tsApplicable)) and 516 (x >= xDomain + d * DomainPitch) and 517 (x < xDomain + d * DomainPitch + 36) and (y >= yDomain) and 518 (y < yDomain + 36) then 452 519 begin 453 SetDomain(d);454 Server(sCreateDevModel,me,Domain,nil^);455 MyModel[MyRO.nModel]:=MyRO.DevModel;456 InitMyModel(MyRO.nModel,false);457 SmartUpdateContent;520 SetDomain(d); 521 Server(sCreateDevModel, me, Domain, nil^); 522 MyModel[MyRO.nModel] := MyRO.DevModel; 523 InitMyModel(MyRO.nModel, false); 524 SmartUpdateContent; 458 525 end; 459 526 460 if (y>=yFeature) and (y<yFeature+LinePitch*Lines) then461 begin 462 i:=(y-yFeature) div LinePitch;463 if (x>=xFeature-21) and (x<ClientWidth) and (ssShift in Shift) then464 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkFeature, code[i])465 else if not(code[i] in AutoFeature) then527 if (y >= yFeature) and (y < yFeature + LinePitch * Lines) then 528 begin 529 i := (y - yFeature) div LinePitch; 530 if (x >= xFeature - 21) and (x < ClientWidth) and (ssShift in Shift) then 531 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkFeature, code[i]) 532 else if not(code[i] in AutoFeature) then 466 533 begin 467 if (code[i]<mcFirstNonCap) and (x>=xFeature-21) and (x<xFeature-21+12) then 534 if (code[i] < mcFirstNonCap) and (x >= xFeature - 21) and 535 (x < xFeature - 21 + 12) then 468 536 begin 469 IncCap:=code[i]; 470 Dump(offscreen,HGrSystem,xFeature-21,yFeature+2+LinePitch*i,12,12,182,172); 471 SmartInvalidate; 537 IncCap := code[i]; 538 Dump(offscreen, HGrSystem, xFeature - 21, yFeature + 2 + LinePitch * 539 i, 12, 12, 182, 172); 540 SmartInvalidate; 472 541 end 473 else if (x>=xFeature-9) and (x<xFeature-9+12) then542 else if (x >= xFeature - 9) and (x < xFeature - 9 + 12) then 474 543 begin 475 DecCap:=code[i]; 476 if code[i]<mcFirstNonCap then 477 Dump(offscreen,HGrSystem,xFeature-9,yFeature+2+LinePitch*i,12,12,182,159) 478 else Dump(offscreen,HGrSystem,xFeature-9,yFeature+2+LinePitch*i, 479 12,12,182,185+13*MyRO.DevModel.Cap[code[i]]); 480 SmartInvalidate; 544 DecCap := code[i]; 545 if code[i] < mcFirstNonCap then 546 Dump(offscreen, HGrSystem, xFeature - 9, yFeature + 2 + LinePitch * 547 i, 12, 12, 182, 159) 548 else 549 Dump(offscreen, HGrSystem, xFeature - 9, yFeature + 2 + LinePitch * 550 i, 12, 12, 182, 185 + 13 * MyRO.DevModel.Cap[code[i]]); 551 SmartInvalidate; 481 552 end; 482 553 end … … 488 559 Shift: TShiftState; x, y: integer); 489 560 var 490 NewValue: integer;491 begin 492 if IncCap>=0 then493 begin 494 NewValue:=MyRO.DevModel.Cap[IncCap]+1;495 Server(sSetDevModelCap+NewValue shl 4,me,IncCap,nil^);496 MyModel[MyRO.nModel]:=MyRO.DevModel;497 InitMyModel(MyRO.nModel,false);498 SmartUpdateContent;499 IncCap:=-1;561 NewValue: integer; 562 begin 563 if IncCap >= 0 then 564 begin 565 NewValue := MyRO.DevModel.Cap[IncCap] + 1; 566 Server(sSetDevModelCap + NewValue shl 4, me, IncCap, nil^); 567 MyModel[MyRO.nModel] := MyRO.DevModel; 568 InitMyModel(MyRO.nModel, false); 569 SmartUpdateContent; 570 IncCap := -1; 500 571 end 501 else if DecCap>=0 then 502 begin 503 if (DecCap>=mcFirstNonCap) or (MyRO.DevModel.Cap[DecCap]>0) then 504 begin 505 NewValue:=MyRO.DevModel.Cap[DecCap]-1; 506 if DecCap>=mcFirstNonCap then NewValue:=-NewValue; 507 Server(sSetDevModelCap+NewValue shl 4,me,DecCap,nil^); 508 MyModel[MyRO.nModel]:=MyRO.DevModel; 509 InitMyModel(MyRO.nModel,false); 510 end; 511 SmartUpdateContent; 512 DecCap:=-1; 572 else if DecCap >= 0 then 573 begin 574 if (DecCap >= mcFirstNonCap) or (MyRO.DevModel.Cap[DecCap] > 0) then 575 begin 576 NewValue := MyRO.DevModel.Cap[DecCap] - 1; 577 if DecCap >= mcFirstNonCap then 578 NewValue := -NewValue; 579 Server(sSetDevModelCap + NewValue shl 4, me, DecCap, nil^); 580 MyModel[MyRO.nModel] := MyRO.DevModel; 581 InitMyModel(MyRO.nModel, false); 582 end; 583 SmartUpdateContent; 584 DecCap := -1; 513 585 end; 514 586 end; … … 516 588 procedure TDraftDlg.OKBtnClick(Sender: TObject); 517 589 begin 518 ModalResult:=mrOK;590 ModalResult := mrOK; 519 591 end; 520 592 521 593 end. 522 -
trunk/LocalPlayer/Enhance.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit Enhance; 4 3 … … 6 5 7 6 uses 8 ScreenTools, BaseWin,Protocol,ClientTools,Term,7 ScreenTools, BaseWin, Protocol, ClientTools, Term, 9 8 10 9 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, … … 31 30 procedure TerrClick(Sender: TObject); 32 31 procedure JobClick(Sender: TObject); 33 procedure FormKeyDown(Sender: TObject; var Key: Word; 34 Shift: TShiftState); 32 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 35 33 public 36 34 procedure ShowNewContent(NewMode: integer; TerrType: integer = -1); … … 51 49 procedure TEnhanceDlg.FormCreate(Sender: TObject); 52 50 var 53 TerrType: integer; 54 m: TMenuItem; 55 begin 56 inherited; 57 CaptionRight:=CloseBtn.Left; 58 CaptionLeft:=ToggleBtn.Left+ToggleBtn.Width; 59 InitButtons(); 60 HelpContext:='MACRO'; 61 Caption:=Phrases.Lookup('TITLE_ENHANCE'); 62 ToggleBtn.Hint:=Phrases.Lookup('BTN_SELECT'); 63 64 for TerrType:=fGrass to fMountains do if TerrType<>fJungle then 51 TerrType: integer; 52 m: TMenuItem; 53 begin 54 inherited; 55 CaptionRight := CloseBtn.Left; 56 CaptionLeft := ToggleBtn.Left + ToggleBtn.Width; 57 InitButtons(); 58 HelpContext := 'MACRO'; 59 Caption := Phrases.Lookup('TITLE_ENHANCE'); 60 ToggleBtn.Hint := Phrases.Lookup('BTN_SELECT'); 61 62 for TerrType := fGrass to fMountains do 63 if TerrType <> fJungle then 64 begin 65 m := TMenuItem.Create(Popup); 66 m.RadioItem := true; 67 if TerrType = fGrass then 68 m.Caption := Format(Phrases.Lookup('TWOTERRAINS'), 69 [Phrases.Lookup('TERRAIN', fGrass), Phrases.Lookup('TERRAIN', 70 fGrass + 12)]) 71 else if TerrType = fForest then 72 m.Caption := Format(Phrases.Lookup('TWOTERRAINS'), 73 [Phrases.Lookup('TERRAIN', fForest), Phrases.Lookup('TERRAIN', 74 fJungle)]) 75 else 76 m.Caption := Phrases.Lookup('TERRAIN', TerrType); 77 m.Tag := TerrType; 78 m.OnClick := TerrClick; 79 Popup.Items.Add(m); 80 end; 81 end; 82 83 procedure TEnhanceDlg.FormPaint(Sender: TObject); 84 var 85 i: integer; 86 begin 87 inherited; 88 BtnFrame(Canvas, Rect(job1.Left, job1.Top, job7.Left + job7.Width, 89 job1.Top + job1.Height), MainTexture); 90 BtnFrame(Canvas, Rect(job3.Left, job3.Top, job9.Left + job9.Width, 91 job3.Top + job3.Height), MainTexture); 92 for i := 0 to ControlCount - 1 do 93 if Controls[i] is TButtonC then 94 BitBlt(Canvas.Handle, Controls[i].Left + 2, Controls[i].Top - 11, 8, 8, 95 GrExt[HGrSystem].Data.Canvas.Handle, 121 + Controls[i].Tag mod 7 * 9, 96 1 + Controls[i].Tag div 7 * 9, SRCCOPY); 97 end; 98 99 procedure TEnhanceDlg.FormShow(Sender: TObject); 100 begin 101 OffscreenPaint; 102 end; 103 104 procedure TEnhanceDlg.ShowNewContent(NewMode, TerrType: integer); 105 begin 106 if (TerrType < fGrass) or (TerrType > fMountains) then 107 Page := fGrass 108 else 109 Page := TerrType; 110 inherited ShowNewContent(NewMode); 111 end; 112 113 procedure TEnhanceDlg.OffscreenPaint; 114 var 115 i, stage, TerrType, TileImp, x, EndStage, Cost, LastJob: integer; 116 s: string; 117 Done: Set of jNone .. jTrans; 118 TypeChanged: boolean; 119 begin 120 OffscreenUser := self; 121 offscreen.Canvas.Font.Assign(UniFont[ftSmall]); 122 FillOffscreen(0, 0, InnerWidth, InnerHeight); 123 124 EndStage := 0; 125 while (EndStage < 5) and (MyData.EnhancementJobs[Page, EndStage] <> jNone) do 126 inc(EndStage); 127 x := InnerWidth div 2 - xxt - (xxt + 3) * EndStage; 128 129 TerrType := Page; 130 TileImp := 0; 131 Done := []; 132 Cost := 0; 133 for stage := 0 to EndStage do 65 134 begin 66 m:=TMenuItem.Create(Popup); 67 m.RadioItem:=true; 68 if TerrType=fGrass then 69 m.Caption:=Format(Phrases.Lookup('TWOTERRAINS'), 70 [Phrases.Lookup('TERRAIN',fGrass), Phrases.Lookup('TERRAIN',fGrass+12)]) 71 else if TerrType=fForest then 72 m.Caption:=Format(Phrases.Lookup('TWOTERRAINS'), 73 [Phrases.Lookup('TERRAIN',fForest), Phrases.Lookup('TERRAIN',fJungle)]) 74 else m.Caption:=Phrases.Lookup('TERRAIN',TerrType); 75 m.Tag:=TerrType; 76 m.OnClick:=TerrClick; 77 Popup.Items.Add(m); 78 end; 79 end; 80 81 procedure TEnhanceDlg.FormPaint(Sender: TObject); 82 var 83 i: integer; 84 begin 85 inherited; 86 BtnFrame(Canvas,Rect(job1.Left,job1.Top,job7.Left+job7.Width,job1.Top+job1.Height),MainTexture); 87 BtnFrame(Canvas,Rect(job3.Left,job3.Top,job9.Left+job9.Width,job3.Top+job3.Height),MainTexture); 88 for i:=0 to ControlCount-1 do if Controls[i] is TButtonC then 89 BitBlt(Canvas.Handle,Controls[i].Left+2,Controls[i].Top-11,8,8, 90 GrExt[HGrSystem].Data.Canvas.Handle,121+Controls[i].Tag mod 7 *9, 91 1+Controls[i].Tag div 7 *9,SRCCOPY); 92 end; 93 94 procedure TEnhanceDlg.FormShow(Sender: TObject); 95 begin 96 OffscreenPaint; 97 end; 98 99 procedure TEnhanceDlg.ShowNewContent(NewMode,TerrType: integer); 100 begin 101 if (TerrType<fGrass) or (TerrType>fMountains) then Page:=fGrass 102 else Page:=TerrType; 103 inherited ShowNewContent(NewMode); 104 end; 105 106 procedure TEnhanceDlg.OffscreenPaint; 107 var 108 i,stage,TerrType,TileImp,x,EndStage,Cost,LastJob: integer; 109 s: string; 110 Done: Set of jNone..jTrans; 111 TypeChanged: boolean; 112 begin 113 OffscreenUser:=self; 114 offscreen.Canvas.Font.Assign(UniFont[ftSmall]); 115 FillOffscreen(0,0,InnerWidth,InnerHeight); 116 117 EndStage:=0; 118 while (EndStage<5) and (MyData.EnhancementJobs[Page,EndStage]<>jNone) do 119 inc(EndStage); 120 x:=InnerWidth div 2-xxt-(xxt+3)*EndStage; 121 122 TerrType:=Page; 123 TileImp:=0; 124 Done:=[]; 125 Cost:=0; 126 for stage:=0 to EndStage do 127 begin 128 if stage>0 then 129 begin 130 Sprite(offscreen,HGrSystem,x-10,66,14,14,80,1); 131 case MyData.EnhancementJobs[Page,stage-1] of 132 jRoad: 133 begin 134 inc(Cost,Terrain[TerrType].MoveCost*RoadWork); 135 TileImp:=TileImp or fRoad; 136 end; 137 jRR: 138 begin 139 inc(Cost,Terrain[TerrType].MoveCost*RRWork); 140 TileImp:=TileImp or fRR; 141 end; 142 jIrr: 143 begin 144 inc(Cost,Terrain[TerrType].IrrClearWork); 145 TileImp:=TileImp and not fTerImp or tiIrrigation; 146 end; 147 jFarm: 148 begin 149 inc(Cost,Terrain[TerrType].IrrClearWork*FarmWork); 150 TileImp:=TileImp and not fTerImp or tiFarm; 151 end; 152 jMine: 153 begin 154 inc(Cost,Terrain[TerrType].MineAfforestWork); 155 TileImp:=TileImp and not fTerImp or tiMine; 156 end; 157 jClear: 158 begin 159 inc(Cost,Terrain[TerrType].IrrClearWork); 160 TerrType:=Terrain[TerrType].ClearTerrain; 161 end; 162 jAfforest: 163 begin 164 inc(Cost,Terrain[TerrType].MineAfforestWork); 165 TerrType:=Terrain[TerrType].AfforestTerrain; 166 end; 167 jTrans: 168 begin 169 inc(Cost,Terrain[TerrType].TransWork); 170 TerrType:=Terrain[TerrType].TransTerrain; 171 end; 135 if stage > 0 then 136 begin 137 Sprite(offscreen, HGrSystem, x - 10, 66, 14, 14, 80, 1); 138 case MyData.EnhancementJobs[Page, stage - 1] of 139 jRoad: 140 begin 141 inc(Cost, Terrain[TerrType].MoveCost * RoadWork); 142 TileImp := TileImp or fRoad; 143 end; 144 jRR: 145 begin 146 inc(Cost, Terrain[TerrType].MoveCost * RRWork); 147 TileImp := TileImp or fRR; 148 end; 149 jIrr: 150 begin 151 inc(Cost, Terrain[TerrType].IrrClearWork); 152 TileImp := TileImp and not fTerImp or tiIrrigation; 153 end; 154 jFarm: 155 begin 156 inc(Cost, Terrain[TerrType].IrrClearWork * FarmWork); 157 TileImp := TileImp and not fTerImp or tiFarm; 158 end; 159 jMine: 160 begin 161 inc(Cost, Terrain[TerrType].MineAfforestWork); 162 TileImp := TileImp and not fTerImp or tiMine; 163 end; 164 jClear: 165 begin 166 inc(Cost, Terrain[TerrType].IrrClearWork); 167 TerrType := Terrain[TerrType].ClearTerrain; 168 end; 169 jAfforest: 170 begin 171 inc(Cost, Terrain[TerrType].MineAfforestWork); 172 TerrType := Terrain[TerrType].AfforestTerrain; 173 end; 174 jTrans: 175 begin 176 inc(Cost, Terrain[TerrType].TransWork); 177 TerrType := Terrain[TerrType].TransTerrain; 178 end; 172 179 end; 173 include(Done,MyData.EnhancementJobs[Page,stage-1]); 174 end; 175 176 if TerrType<fForest then 177 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1+TerrType*(xxt*2+1),1+yyt) 178 else 179 begin 180 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1+2*(xxt*2+1),1+yyt+2*(yyt*3+1)); 181 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1+7*(xxt*2+1),1+yyt+2*(2+TerrType-fForest)*(yyt*3+1)); 182 end; 183 if TileImp and fTerImp=tiFarm then 184 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1+(xxt*2+1),1+yyt+12*(yyt*3+1)) 185 else if TileImp and fTerImp=tiIrrigation then 186 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1,1+yyt+12*(yyt*3+1)); 187 if TileImp and fRR<>0 then 188 begin 189 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1+6*(xxt*2+1),1+yyt+10*(yyt*3+1)); 190 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1+2*(xxt*2+1),1+yyt+10*(yyt*3+1)); 180 include(Done, MyData.EnhancementJobs[Page, stage - 1]); 181 end; 182 183 if TerrType < fForest then 184 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 185 1 + TerrType * (xxt * 2 + 1), 1 + yyt) 186 else 187 begin 188 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 189 1 + 2 * (xxt * 2 + 1), 1 + yyt + 2 * (yyt * 3 + 1)); 190 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 191 1 + 7 * (xxt * 2 + 1), 1 + yyt + 2 * (2 + TerrType - fForest) * 192 (yyt * 3 + 1)); 193 end; 194 if TileImp and fTerImp = tiFarm then 195 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 196 1 + (xxt * 2 + 1), 1 + yyt + 12 * (yyt * 3 + 1)) 197 else if TileImp and fTerImp = tiIrrigation then 198 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 1, 199 1 + yyt + 12 * (yyt * 3 + 1)); 200 if TileImp and fRR <> 0 then 201 begin 202 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 203 1 + 6 * (xxt * 2 + 1), 1 + yyt + 10 * (yyt * 3 + 1)); 204 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 205 1 + 2 * (xxt * 2 + 1), 1 + yyt + 10 * (yyt * 3 + 1)); 191 206 end 192 else if TileImp and fRoad<>0 then 193 begin 194 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1+6*(xxt*2+1),1+yyt+9*(yyt*3+1)); 195 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1+2*(xxt*2+1),1+yyt+9*(yyt*3+1)); 196 end; 197 if TileImp and fTerImp=tiMine then 198 Sprite(offscreen,HGrTerrain,x,64-yyt,xxt*2,yyt*2,1+2*(xxt*2+1),1+yyt+12*(yyt*3+1)); 199 inc(x,xxt*2+6) 200 end; 201 202 for i:=0 to Popup.Items.Count-1 do 203 if Popup.Items[i].Tag=Page then 204 s:=Popup.Items[i].Caption; 205 if Cost>0 then s:=Format(Phrases.Lookup('ENHANCE'),[s,MovementToString(Cost)]); 206 LoweredTextOut(offscreen.Canvas,-1,MainTexture, 207 (InnerWidth-BiColorTextWidth(Offscreen.Canvas,s)) div 2,12,s); 208 209 if EndStage>0 then LastJob:=MyData.EnhancementJobs[Page,EndStage-1] 210 else LastJob:=jNone; 211 if jRoad in Done then job1.ButtonIndex:=3 else job1.ButtonIndex:=2; 212 if jRR in Done then job2.ButtonIndex:=3 else job2.ButtonIndex:=2; 213 if jIrr in Done then job4.ButtonIndex:=3 else job4.ButtonIndex:=2; 214 if jFarm in Done then job5.ButtonIndex:=3 else job5.ButtonIndex:=2; 215 if jMine in Done then job7.ButtonIndex:=3 else job7.ButtonIndex:=2; 216 if LastJob=jClear then job3.ButtonIndex:=3 else job3.ButtonIndex:=2; 217 if LastJob=jAfforest then job6.ButtonIndex:=3 else job6.ButtonIndex:=2; 218 if LastJob=jTrans then job9.ButtonIndex:=3 else job9.ButtonIndex:=2; 219 220 TypeChanged:= LastJob in [jClear, jAfforest, jTrans]; 221 job1.Visible:=(jRoad in Done) or not TypeChanged; 222 job2.Visible:=(jRR in Done) or not TypeChanged; 223 job4.Visible:=(jIrr in Done) or not TypeChanged and (Terrain[TerrType].IrrEff>0); 224 job5.Visible:=(jFarm in Done) or not TypeChanged and (Terrain[TerrType].IrrEff>0); 225 job7.Visible:=(jMine in Done) or not TypeChanged and (Terrain[TerrType].MineEff>0); 226 job3.Visible:=not TypeChanged and (Terrain[TerrType].ClearTerrain>=0) 227 and ((TerrType<>fDesert) or (MyRO.Wonder[woGardens].EffectiveOwner=me)) 228 or (LastJob=jClear); 229 job6.Visible:=not TypeChanged and (Terrain[TerrType].AfforestTerrain>=0) 230 or (LastJob=jAfforest); 231 job9.Visible:=not TypeChanged and (Terrain[TerrType].TransTerrain>=0) 232 or (LastJob=jTrans); 233 234 MarkUsedOffscreen(InnerWidth,InnerHeight); 235 end; {OffscreenPaint} 207 else if TileImp and fRoad <> 0 then 208 begin 209 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 210 1 + 6 * (xxt * 2 + 1), 1 + yyt + 9 * (yyt * 3 + 1)); 211 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 212 1 + 2 * (xxt * 2 + 1), 1 + yyt + 9 * (yyt * 3 + 1)); 213 end; 214 if TileImp and fTerImp = tiMine then 215 Sprite(offscreen, HGrTerrain, x, 64 - yyt, xxt * 2, yyt * 2, 216 1 + 2 * (xxt * 2 + 1), 1 + yyt + 12 * (yyt * 3 + 1)); 217 inc(x, xxt * 2 + 6) 218 end; 219 220 for i := 0 to Popup.Items.Count - 1 do 221 if Popup.Items[i].Tag = Page then 222 s := Popup.Items[i].Caption; 223 if Cost > 0 then 224 s := Format(Phrases.Lookup('ENHANCE'), [s, MovementToString(Cost)]); 225 LoweredTextOut(offscreen.Canvas, -1, MainTexture, 226 (InnerWidth - BiColorTextWidth(offscreen.Canvas, s)) div 2, 12, s); 227 228 if EndStage > 0 then 229 LastJob := MyData.EnhancementJobs[Page, EndStage - 1] 230 else 231 LastJob := jNone; 232 if jRoad in Done then 233 job1.ButtonIndex := 3 234 else 235 job1.ButtonIndex := 2; 236 if jRR in Done then 237 job2.ButtonIndex := 3 238 else 239 job2.ButtonIndex := 2; 240 if jIrr in Done then 241 job4.ButtonIndex := 3 242 else 243 job4.ButtonIndex := 2; 244 if jFarm in Done then 245 job5.ButtonIndex := 3 246 else 247 job5.ButtonIndex := 2; 248 if jMine in Done then 249 job7.ButtonIndex := 3 250 else 251 job7.ButtonIndex := 2; 252 if LastJob = jClear then 253 job3.ButtonIndex := 3 254 else 255 job3.ButtonIndex := 2; 256 if LastJob = jAfforest then 257 job6.ButtonIndex := 3 258 else 259 job6.ButtonIndex := 2; 260 if LastJob = jTrans then 261 job9.ButtonIndex := 3 262 else 263 job9.ButtonIndex := 2; 264 265 TypeChanged := LastJob in [jClear, jAfforest, jTrans]; 266 job1.Visible := (jRoad in Done) or not TypeChanged; 267 job2.Visible := (jRR in Done) or not TypeChanged; 268 job4.Visible := (jIrr in Done) or not TypeChanged and 269 (Terrain[TerrType].IrrEff > 0); 270 job5.Visible := (jFarm in Done) or not TypeChanged and 271 (Terrain[TerrType].IrrEff > 0); 272 job7.Visible := (jMine in Done) or not TypeChanged and 273 (Terrain[TerrType].MineEff > 0); 274 job3.Visible := not TypeChanged and (Terrain[TerrType].ClearTerrain >= 0) and 275 ((TerrType <> fDesert) or (MyRO.Wonder[woGardens].EffectiveOwner = me)) or 276 (LastJob = jClear); 277 job6.Visible := not TypeChanged and (Terrain[TerrType].AfforestTerrain >= 0) 278 or (LastJob = jAfforest); 279 job9.Visible := not TypeChanged and (Terrain[TerrType].TransTerrain >= 0) or 280 (LastJob = jTrans); 281 282 MarkUsedOffscreen(InnerWidth, InnerHeight); 283 end; { OffscreenPaint } 236 284 237 285 procedure TEnhanceDlg.CloseBtnClick(Sender: TObject); 238 286 begin 239 Close287 Close 240 288 end; 241 289 242 290 procedure TEnhanceDlg.ToggleBtnClick(Sender: TObject); 243 291 var 244 i: integer;245 begin 246 for i:=0 to Popup.Items.Count-1 do247 Popup.Items[i].Checked:= Popup.Items[i].Tag=Page;248 Popup.Popup(Left+ToggleBtn.Left, Top+ToggleBtn.Top+ToggleBtn.Height);292 i: integer; 293 begin 294 for i := 0 to Popup.Items.Count - 1 do 295 Popup.Items[i].Checked := Popup.Items[i].Tag = Page; 296 Popup.Popup(Left + ToggleBtn.Left, Top + ToggleBtn.Top + ToggleBtn.Height); 249 297 end; 250 298 251 299 procedure TEnhanceDlg.TerrClick(Sender: TObject); 252 300 begin 253 Page:=TComponent(Sender).Tag;254 SmartUpdateContent301 Page := TComponent(Sender).Tag; 302 SmartUpdateContent 255 303 end; 256 304 257 305 procedure TEnhanceDlg.JobClick(Sender: TObject); 258 306 var 259 stage, NewJob: integer;260 Done: Set of jNone..jTrans;307 stage, NewJob: integer; 308 Done: Set of jNone .. jTrans; 261 309 262 310 procedure RemoveJob(j: integer); 263 311 begin // remove job 264 stage:=0;265 while (stage<5) and (MyData.EnhancementJobs[Page,stage]<>jNone) do266 begin 267 if (MyData.EnhancementJobs[Page,stage]=j) or (j=jRoad)268 and (MyData.EnhancementJobs[Page,stage]=jRR)269 or (j=jIrr) and (MyData.EnhancementJobs[Page,stage]=jFarm) then312 stage := 0; 313 while (stage < 5) and (MyData.EnhancementJobs[Page, stage] <> jNone) do 314 begin 315 if (MyData.EnhancementJobs[Page, stage] = j) or (j = jRoad) and 316 (MyData.EnhancementJobs[Page, stage] = jRR) or (j = jIrr) and 317 (MyData.EnhancementJobs[Page, stage] = jFarm) then 270 318 begin 271 if stage<4 then272 move(MyData.EnhancementJobs[Page,stage+1],273 MyData.EnhancementJobs[Page,stage],4-stage);274 MyData.EnhancementJobs[Page,4]:=jNone319 if stage < 4 then 320 move(MyData.EnhancementJobs[Page, stage + 1], 321 MyData.EnhancementJobs[Page, stage], 4 - stage); 322 MyData.EnhancementJobs[Page, 4] := jNone 275 323 end 276 else inc(stage); 277 end; 278 end; 279 280 begin 281 NewJob:=TButtonC(Sender).Tag; 282 Done:=[]; 283 stage:=0; 284 while (stage<5) and (MyData.EnhancementJobs[Page,stage]<>jNone) do 324 else 325 inc(stage); 326 end; 327 end; 328 329 begin 330 NewJob := TButtonC(Sender).Tag; 331 Done := []; 332 stage := 0; 333 while (stage < 5) and (MyData.EnhancementJobs[Page, stage] <> jNone) do 285 334 begin 286 include(Done, MyData.EnhancementJobs[Page,stage]); 287 inc(stage); 288 end; 289 if NewJob in Done then RemoveJob(NewJob) 290 else 335 include(Done, MyData.EnhancementJobs[Page, stage]); 336 inc(stage); 337 end; 338 if NewJob in Done then 339 RemoveJob(NewJob) 340 else 291 341 begin // add job 292 if NewJob in [jMine,jAfforest] then RemoveJob(jIrr); 293 if NewJob in [jIrr,jFarm,jTrans] then RemoveJob(jMine); 294 if (NewJob=jRR) and not (jRoad in Done) then 295 begin MyData.EnhancementJobs[Page,stage]:=jRoad; inc(stage) end; 296 if (NewJob=jFarm) and not (jIrr in Done) then 297 begin MyData.EnhancementJobs[Page,stage]:=jIrr; inc(stage) end; 298 MyData.EnhancementJobs[Page,stage]:=NewJob 299 end; 300 SmartUpdateContent 342 if NewJob in [jMine, jAfforest] then 343 RemoveJob(jIrr); 344 if NewJob in [jIrr, jFarm, jTrans] then 345 RemoveJob(jMine); 346 if (NewJob = jRR) and not(jRoad in Done) then 347 begin 348 MyData.EnhancementJobs[Page, stage] := jRoad; 349 inc(stage) 350 end; 351 if (NewJob = jFarm) and not(jIrr in Done) then 352 begin 353 MyData.EnhancementJobs[Page, stage] := jIrr; 354 inc(stage) 355 end; 356 MyData.EnhancementJobs[Page, stage] := NewJob 357 end; 358 SmartUpdateContent 301 359 end; 302 360 … … 304 362 Shift: TShiftState); 305 363 begin 306 if Key=VK_ESCAPE then Close 307 else if Key=VK_F1 then 308 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkText, HelpDlg.TextIndex('MACRO')) 364 if Key = VK_ESCAPE then 365 Close 366 else if Key = VK_F1 then 367 HelpDlg.ShowNewContent(FWindowMode or wmPersistent, hkText, 368 HelpDlg.TextIndex('MACRO')) 309 369 end; 310 370 311 371 end. 312 -
trunk/LocalPlayer/Help.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit Help; 4 3 … … 6 5 7 6 uses 8 Protocol, ScreenTools,BaseWin,StringTables,7 Protocol, ScreenTools, BaseWin, StringTables, 9 8 10 9 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, … … 12 11 13 12 const 14 MaxHist=16; 15 16 {link categories} 17 hkNoLink=0;hkAdv=1;hkImp=2;hkTer=3;hkFeature=4;hkInternet=5;hkModel=6;hkMisc=7; 18 hkCrossLink=$40; 19 hkText=$80; 20 21 liInvalid=$3FFF; // link index indicates invalid link 22 23 {link indices for category hkMisc} 24 miscMain=0; miscCredits=1; miscGovList=2; miscJobList=3; miscSearchResult=7; 25 26 fJungle=8; // pseudo terrain 27 13 MaxHist = 16; 14 15 { link categories } 16 hkNoLink = 0; 17 hkAdv = 1; 18 hkImp = 2; 19 hkTer = 3; 20 hkFeature = 4; 21 hkInternet = 5; 22 hkModel = 6; 23 hkMisc = 7; 24 hkCrossLink = $40; 25 hkText = $80; 26 27 liInvalid = $3FFF; // link index indicates invalid link 28 29 { link indices for category hkMisc } 30 miscMain = 0; 31 miscCredits = 1; 32 miscGovList = 2; 33 miscJobList = 3; 34 miscSearchResult = 7; 35 36 fJungle = 8; // pseudo terrain 28 37 29 38 type 30 THyperText =class(TStringList)31 procedure AddLine(s: String = ''; Format: integer =0; Picpix: integer =0;32 LinkCategory: integer = 0; LinkIndex: integer =0);39 THyperText = class(TStringList) 40 procedure AddLine(s: String = ''; Format: integer = 0; Picpix: integer = 0; 41 LinkCategory: integer = 0; LinkIndex: integer = 0); 33 42 procedure LF; 34 end;43 end; 35 44 36 45 THelpDlg = class(TFramedDlg) … … 39 48 TopBtn: TButtonB; 40 49 SearchBtn: TButtonB; 41 procedure FormCreate(Sender: TObject);42 procedure FormDestroy(Sender: TObject);43 procedure FormPaint(Sender: TObject);44 procedure CloseBtnClick(Sender: TObject);45 procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; x,46 y: integer);50 procedure FormCreate(Sender: TObject); 51 procedure FormDestroy(Sender: TObject); 52 procedure FormPaint(Sender: TObject); 53 procedure CloseBtnClick(Sender: TObject); 54 procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; 55 x, y: integer); 47 56 procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; 48 57 Shift: TShiftState; x, y: integer); … … 50 59 procedure TopBtnClick(Sender: TObject); 51 60 procedure FormClose(Sender: TObject; var Action: TCloseAction); 52 procedure FormKeyDown(Sender: TObject; var Key: Word; 53 Shift: TShiftState); 61 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 54 62 procedure SearchBtnClick(Sender: TObject); 55 63 public 56 64 Difficulty: integer; 57 procedure ShowNewContent(NewMode, Category,Index: integer);65 procedure ShowNewContent(NewMode, Category, Index: integer); 58 66 procedure ClearHistory; 59 67 function TextIndex(Item: string): integer; … … 61 69 procedure OffscreenPaint; override; 62 70 private 63 Kind,no,Sel,nHist,CaptionColor: integer; 64 hADVHELP, hIMPHELP, hFEATUREHELP, hGOVHELP, hSPECIALMODEL, hJOBHELP: integer; 71 Kind, no, Sel, nHist, CaptionColor: integer; 72 hADVHELP, hIMPHELP, hFEATUREHELP, hGOVHELP, hSPECIALMODEL, 73 hJOBHELP: integer; 65 74 SearchContent, NewSearchContent: string; 66 75 CaptionFont: TFont; 67 76 MainText, SearchResult: THyperText; 68 77 HelpText: TStringTable; 69 ExtPic, TerrIcon: TBitmap;70 sb: TPVScrollbar;71 x0: array [-2..18] of integer;72 HistKind: array [0..MaxHist-1] of integer;73 HistNo: array [0..MaxHist-1] of integer;74 HistPos: array [0..MaxHist-1] of integer;75 HistSearchContent: array [0..MaxHist-1] of shortstring;78 ExtPic, TerrIcon: TBitmap; 79 sb: TPVScrollbar; 80 x0: array [-2 .. 18] of integer; 81 HistKind: array [0 .. MaxHist - 1] of integer; 82 HistNo: array [0 .. MaxHist - 1] of integer; 83 HistPos: array [0 .. MaxHist - 1] of integer; 84 HistSearchContent: array [0 .. MaxHist - 1] of shortstring; 76 85 procedure line(ca: TCanvas; i: integer; lit: boolean); 77 86 procedure Prepare(sbPos: integer = 0); 78 procedure WaterSign(x0, y0,iix: integer);87 procedure WaterSign(x0, y0, iix: integer); 79 88 procedure Search(SearchString: string); 80 procedure OnScroll(var m: TMessage); message WM_VSCROLL;81 procedure OnMouseWheel(var m: TMessage); message WM_MOUSEWHEEL;82 procedure OnMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;89 procedure OnScroll(var m: TMessage); message WM_VSCROLL; 90 procedure OnMouseWheel(var m: TMessage); message WM_MOUSEWHEEL; 91 procedure OnMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE; 83 92 end; 84 93 … … 89 98 90 99 uses 91 Directories,ClientTools,Term,Tribes,ShellAPI, Inp,Messg;100 Directories, ClientTools, Term, Tribes, ShellAPI, Inp, Messg; 92 101 93 102 {$R *.DFM} 94 103 95 104 type 96 THelpLineInfo=packed record97 Format, Picpix: Byte;98 Link: Word;105 THelpLineInfo = packed record 106 Format, Picpix: Byte; 107 Link: Word; 99 108 end; 100 109 … … 102 111 LinkCategory: integer; LinkIndex: integer); 103 112 var 104 HelpLineInfo: THelpLineInfo;113 HelpLineInfo: THelpLineInfo; 105 114 begin 106 if LinkIndex<0 then LinkIndex:=liInvalid; 107 HelpLineInfo.Format:=Format; 108 HelpLineInfo.Picpix:=Picpix; 109 HelpLineInfo.Link:=LinkCategory shl 8+LinkIndex; 110 AddObject(s,TObject(HelpLineInfo)); 115 if LinkIndex < 0 then 116 LinkIndex := liInvalid; 117 HelpLineInfo.Format := Format; 118 HelpLineInfo.Picpix := Picpix; 119 HelpLineInfo.Link := LinkCategory shl 8 + LinkIndex; 120 AddObject(s, TObject(HelpLineInfo)); 111 121 end; 112 122 113 123 procedure THyperText.LF; 114 124 begin 115 AddLine;125 AddLine; 116 126 end; 117 127 118 119 128 const 120 {text formats} 121 pkNormal=0;pkCaption=1;pkSmallIcon=2;pkBigIcon=3;pkAdvIcon=4;pkTer=5; 122 pkBigTer=6;pkFeature=7;pkDot=8;pkNormal_Dot=9;pkDomain=10;pkSection=11; 123 pkBigFeature=12;pkExp=13;pkAITStat=14;pkExternal=15;pkModel=16;pkNormal_64=17; 124 pkIllu=18;pkLogo=19;pkTerImp=20;pkRightIcon=21;pkAdvIcon_AsPreq=22; 125 pkSmallIcon_AsPreq=23;pkSpecialIcon=24;pkGov=25; 126 127 nSeeAlso=14; 128 SeeAlso: array[0..nSeeAlso-1] of record Kind,no,SeeKind,SeeNo: integer end= 129 ((Kind:hkImp;no:imWalls;SeeKind:hkFeature;SeeNo:mcArtillery), 130 (Kind:hkImp;no:imHydro;SeeKind:hkImp;SeeNo:woHoover), 131 (Kind:hkImp;no:imWalls;SeeKind:hkImp;SeeNo:imGrWall), 132 (Kind:hkImp;no:imHighways;SeeKind:hkAdv;SeeNo:adWheel), 133 (Kind:hkImp;no:imCathedral;SeeKind:hkImp;SeeNo:woBach), 134 (Kind:hkImp;no:imBank;SeeKind:hkImp;SeeNo:imStockEx), 135 (Kind:hkImp;no:imShipComp;SeeKind:hkImp;SeeNo:imSpacePort), 136 (Kind:hkImp;no:imShipPow;SeeKind:hkImp;SeeNo:imSpacePort), 137 (Kind:hkImp;no:imShipHab;SeeKind:hkImp;SeeNo:imSpacePort), 138 (Kind:hkFeature;no:mcSub;SeeKind:hkFeature;SeeNo:mcRadar), 139 (Kind:hkFeature;no:mcDefense;SeeKind:hkAdv;SeeNo:adSteel), 140 (Kind:hkFeature;no:mcSE;SeeKind:hkFeature;SeeNo:mcNP), 141 (Kind:hkAdv;no:adWheel;SeeKind:hkImp;SeeNo:imHighways), 142 (Kind:hkAdv;no:adSteel;SeeKind:hkFeature;SeeNo:mcDefense)); 143 144 nTerrainHelp=14; 145 TerrainHelp: array[0..nTerrainHelp-1] of integer= 146 (fGrass,fGrass+12,fPrairie,fForest,fJungle,fHills,fMountains,fSwamp,fTundra,fArctic, 147 fDesert,3*12{DeadLands},fShore,fOcean); 148 149 nJobHelp=8; 150 JobHelp: array[0..nJobHelp-1] of integer= 151 (jRoad,jRR,jCanal,jIrr,jFarm,jMine,jFort,jBase); 152 153 154 procedure THelpDlg.FormCreate(Sender:TObject); 129 { text formats } 130 pkNormal = 0; 131 pkCaption = 1; 132 pkSmallIcon = 2; 133 pkBigIcon = 3; 134 pkAdvIcon = 4; 135 pkTer = 5; 136 pkBigTer = 6; 137 pkFeature = 7; 138 pkDot = 8; 139 pkNormal_Dot = 9; 140 pkDomain = 10; 141 pkSection = 11; 142 pkBigFeature = 12; 143 pkExp = 13; 144 pkAITStat = 14; 145 pkExternal = 15; 146 pkModel = 16; 147 pkNormal_64 = 17; 148 pkIllu = 18; 149 pkLogo = 19; 150 pkTerImp = 20; 151 pkRightIcon = 21; 152 pkAdvIcon_AsPreq = 22; 153 pkSmallIcon_AsPreq = 23; 154 pkSpecialIcon = 24; 155 pkGov = 25; 156 157 nSeeAlso = 14; 158 SeeAlso: array [0 .. nSeeAlso - 1] of record Kind, no, SeeKind, 159 SeeNo: integer end = ((Kind: hkImp; no: imWalls; SeeKind: hkFeature; 160 SeeNo: mcArtillery), (Kind: hkImp; no: imHydro; SeeKind: hkImp; 161 SeeNo: woHoover), (Kind: hkImp; no: imWalls; SeeKind: hkImp; 162 SeeNo: imGrWall), (Kind: hkImp; no: imHighways; SeeKind: hkAdv; 163 SeeNo: adWheel), (Kind: hkImp; no: imCathedral; SeeKind: hkImp; 164 SeeNo: woBach), (Kind: hkImp; no: imBank; SeeKind: hkImp; SeeNo: imStockEx), 165 (Kind: hkImp; no: imShipComp; SeeKind: hkImp; SeeNo: imSpacePort), 166 (Kind: hkImp; no: imShipPow; SeeKind: hkImp; SeeNo: imSpacePort), 167 (Kind: hkImp; no: imShipHab; SeeKind: hkImp; SeeNo: imSpacePort), 168 (Kind: hkFeature; no: mcSub; SeeKind: hkFeature; SeeNo: mcRadar), 169 (Kind: hkFeature; no: mcDefense; SeeKind: hkAdv; SeeNo: adSteel), 170 (Kind: hkFeature; no: mcSE; SeeKind: hkFeature; SeeNo: mcNP), (Kind: hkAdv; 171 no: adWheel; SeeKind: hkImp; SeeNo: imHighways), (Kind: hkAdv; no: adSteel; 172 SeeKind: hkFeature; SeeNo: mcDefense)); 173 174 nTerrainHelp = 14; 175 TerrainHelp: array [0 .. nTerrainHelp - 1] of integer = (fGrass, fGrass + 12, 176 fPrairie, fForest, fJungle, fHills, fMountains, fSwamp, fTundra, fArctic, 177 fDesert, 3 * 12 { DeadLands } , fShore, fOcean); 178 179 nJobHelp = 8; 180 JobHelp: array [0 .. nJobHelp - 1] of integer = (jRoad, jRR, jCanal, jIrr, 181 jFarm, jMine, jFort, jBase); 182 183 procedure THelpDlg.FormCreate(Sender: TObject); 155 184 begin 156 inherited; 157 CaptionLeft:=BackBtn.Left+BackBtn.Width; 158 CaptionRight:=SearchBtn.Left; 159 inc(ModalFrameIndent,29); 160 MainText:=THyperText.Create; 161 SearchResult:=THyperText.Create; 162 CreatePVSB(sb,Handle,36,551,36+432); 163 164 HelpText:=TStringTable.Create; 165 HelpText.LoadFromFile(LocalizedFilePath('Help\help.txt')); 166 hADVHELP:=HelpText.Gethandle('ADVHELP'); 167 hIMPHELP:=HelpText.Gethandle('IMPHELP'); 168 hFEATUREHELP:=HelpText.Gethandle('FEATUREHELP'); 169 hGOVHELP:=HelpText.Gethandle('GOVHELP'); 170 hSPECIALMODEL:=HelpText.Gethandle('SPECIALMODEL'); 171 hJOBHELP:=HelpText.Gethandle('JOBHELP'); 172 173 CaptionFont:=Font.Create; 174 CaptionFont.Assign(UniFont[ftNormal]); 175 CaptionFont.Style:=CaptionFont.Style+[fsItalic,fsBold]; 176 InitButtons(); 177 178 TopBtn.Hint:=Phrases.Lookup('BTN_CONTENTS'); 179 BackBtn.Hint:=Phrases.Lookup('BTN_BACK'); 180 SearchBtn.Hint:=Phrases.Lookup('BTN_SEARCH'); 181 182 ExtPic:=TBitmap.Create; 183 TerrIcon:=TBitmap.Create; 184 TerrIcon.PixelFormat:=pf24bit; 185 TerrIcon.Width:=xSizeBig; TerrIcon.Height:=ySizeBig; 186 SearchContent:=''; 187 nHist:=-1; 185 inherited; 186 CaptionLeft := BackBtn.Left + BackBtn.Width; 187 CaptionRight := SearchBtn.Left; 188 inc(ModalFrameIndent, 29); 189 MainText := THyperText.Create; 190 SearchResult := THyperText.Create; 191 CreatePVSB(sb, Handle, 36, 551, 36 + 432); 192 193 HelpText := TStringTable.Create; 194 HelpText.LoadFromFile(LocalizedFilePath('Help\help.txt')); 195 hADVHELP := HelpText.Gethandle('ADVHELP'); 196 hIMPHELP := HelpText.Gethandle('IMPHELP'); 197 hFEATUREHELP := HelpText.Gethandle('FEATUREHELP'); 198 hGOVHELP := HelpText.Gethandle('GOVHELP'); 199 hSPECIALMODEL := HelpText.Gethandle('SPECIALMODEL'); 200 hJOBHELP := HelpText.Gethandle('JOBHELP'); 201 202 CaptionFont := Font.Create; 203 CaptionFont.Assign(UniFont[ftNormal]); 204 CaptionFont.Style := CaptionFont.Style + [fsItalic, fsBold]; 205 InitButtons(); 206 207 TopBtn.Hint := Phrases.Lookup('BTN_CONTENTS'); 208 BackBtn.Hint := Phrases.Lookup('BTN_BACK'); 209 SearchBtn.Hint := Phrases.Lookup('BTN_SEARCH'); 210 211 ExtPic := TBitmap.Create; 212 TerrIcon := TBitmap.Create; 213 TerrIcon.PixelFormat := pf24bit; 214 TerrIcon.Width := xSizeBig; 215 TerrIcon.Height := ySizeBig; 216 SearchContent := ''; 217 nHist := -1; 188 218 end; 189 219 190 220 procedure THelpDlg.ClearHistory; 191 221 begin 192 nHist:=-1;222 nHist := -1; 193 223 end; 194 224 195 procedure THelpDlg.FormDestroy(Sender: TObject);225 procedure THelpDlg.FormDestroy(Sender: TObject); 196 226 begin 197 MainText.Free;198 SearchResult.Free;199 ExtPic.Free;200 TerrIcon.Free;201 HelpText.Free;202 //CaptionFont.Free;227 MainText.Free; 228 SearchResult.Free; 229 ExtPic.Free; 230 TerrIcon.Free; 231 HelpText.Free; 232 // CaptionFont.Free; 203 233 end; 204 234 205 procedure THelpDlg.CloseBtnClick(Sender: TObject);235 procedure THelpDlg.CloseBtnClick(Sender: TObject); 206 236 begin 207 Close237 Close 208 238 end; 209 239 210 procedure THelpDlg.OnScroll(var m: TMessage);240 procedure THelpDlg.OnScroll(var m: TMessage); 211 241 begin 212 if ProcessPVSB(sb,m) then 213 begin Sel:=-1; SmartUpdateContent(true) end 214 end; 215 216 procedure THelpDlg.OnMouseWheel(var m:TMessage); 217 begin 218 if ProcessMouseWheel(sb,m) then 219 begin 220 Sel:=-1; 221 SmartUpdateContent(true); 222 PaintBox1MouseMove(nil, [], m.lParam and $FFFF-Left, m.lParam shr 16-Top); 242 if ProcessPVSB(sb, m) then 243 begin 244 Sel := -1; 245 SmartUpdateContent(true) 223 246 end 224 247 end; 225 248 226 procedure THelpDlg.OnMouse Leave(var Msg:TMessage);249 procedure THelpDlg.OnMouseWheel(var m: TMessage); 227 250 begin 228 if Sel<>-1 then 229 begin 230 line(Canvas,Sel,false); 231 Sel:=-1 251 if ProcessMouseWheel(sb, m) then 252 begin 253 Sel := -1; 254 SmartUpdateContent(true); 255 PaintBox1MouseMove(nil, [], m.lParam and $FFFF - Left, 256 m.lParam shr 16 - Top); 232 257 end 233 258 end; 234 259 235 procedure THelpDlg. FormPaint(Sender:TObject);260 procedure THelpDlg.OnMouseLeave(var Msg: TMessage); 236 261 begin 237 inherited; 238 Canvas.Font.Assign(UniFont[ftNormal]); 262 if Sel <> -1 then 263 begin 264 line(Canvas, Sel, false); 265 Sel := -1 266 end 267 end; 268 269 procedure THelpDlg.FormPaint(Sender: TObject); 270 begin 271 inherited; 272 Canvas.Font.Assign(UniFont[ftNormal]); 239 273 end; 240 274 241 275 procedure THelpDlg.line(ca: TCanvas; i: integer; lit: boolean); 242 276 var 243 TextColor,x,y: integer;244 TextSize: TSize;245 s: string;277 TextColor, x, y: integer; 278 TextSize: TSize; 279 s: string; 246 280 begin 247 s:=MainText[sb.si.npos+i]; 248 if s='' then exit; 249 x:=x0[i]; y:=2+i*24; 250 if ca=Canvas then 251 begin x:=x+SideFrame; y:=y+WideFrame end; 252 if THelpLineInfo(MainText.Objects[sb.si.npos+i]).Format 253 in [pkCaption,pkBigTer,pkRightIcon,pkBigFeature] then 254 begin 255 ca.Font.Assign(CaptionFont); 256 { ca.brush.color:=CaptionColor; 257 ca.FillRect(rect(x,i*24,x+24,i*24+24)); 258 ca.brush.color:=$FFFFFF; 259 ca.FrameRect(rect(x+1,i*24+1,x+24-1,i*24+24-1)); 260 ca.Brush.Style:=bsClear;} 261 BitBlt(ca.handle,x,y-4,24,24,GrExt[HGrSystem].Data.Canvas.Handle,1,146,SRCCOPY); 262 BiColorTextOut(ca,$FFFFFF,$7F007F,x+10-ca.Textwidth(s[1]) div 2,y-3,s[1]); 263 BiColorTextOut(ca,CaptionColor,$7F007F,x+24,y-3,copy(s,2,255)); 264 ca.Font.Assign(UniFont[ftNormal]); 265 end 266 else if THelpLineInfo(MainText.Objects[sb.si.npos+i]).Format=pkSection then 267 begin 268 ca.Font.Assign(CaptionFont); 269 BiColorTextOut(ca,CaptionColor,$7F007F,x,y-3,s); 270 ca.Font.Assign(UniFont[ftNormal]); 271 end 272 else 273 begin 274 if (Kind=hkMisc) and (no=miscMain) then 281 s := MainText[sb.si.npos + i]; 282 if s = '' then 283 exit; 284 x := x0[i]; 285 y := 2 + i * 24; 286 if ca = Canvas then 287 begin 288 x := x + SideFrame; 289 y := y + WideFrame 290 end; 291 if THelpLineInfo(MainText.Objects[sb.si.npos + i]).Format 292 in [pkCaption, pkBigTer, pkRightIcon, pkBigFeature] then 293 begin 275 294 ca.Font.Assign(CaptionFont); 276 TextColor:=Colors.Canvas.Pixels[clkMisc,cliPaperText]; 277 if ca=Canvas then 278 begin 279 TextSize.cx:=BiColorTextWidth(ca,s); 280 TextSize.cy:=ca.TextHeight(s); 281 if y+TextSize.cy>=WideFrame+InnerHeight then 282 TextSize.cy:=WideFrame+InnerHeight-y; 283 FillSeamless(ca,x,y,TextSize.cx,TextSize.cy,-SideFrame,sb.si.npos*24-WideFrame, 284 Paper); 285 end; 286 BiColorTextOut(ca,TextColor,$7F007F,x,y,s); 287 if lit then with ca do 288 begin 289 assert(ca=Canvas); 290 pen.color:=TextColor; 291 moveto(x+1,y+TextSize.cy-2); 292 lineto(x+TextSize.cx,y+TextSize.cy-2); 293 end; 294 if (Kind=hkMisc) and (no=miscMain) then 295 { ca.brush.color:=CaptionColor; 296 ca.FillRect(rect(x,i*24,x+24,i*24+24)); 297 ca.brush.color:=$FFFFFF; 298 ca.FrameRect(rect(x+1,i*24+1,x+24-1,i*24+24-1)); 299 ca.Brush.Style:=bsClear; } 300 BitBlt(ca.Handle, x, y - 4, 24, 24, GrExt[HGrSystem].Data.Canvas.Handle, 1, 301 146, SRCCOPY); 302 BiColorTextOut(ca, $FFFFFF, $7F007F, x + 10 - ca.Textwidth(s[1]) div 2, 303 y - 3, s[1]); 304 BiColorTextOut(ca, CaptionColor, $7F007F, x + 24, y - 3, copy(s, 2, 255)); 295 305 ca.Font.Assign(UniFont[ftNormal]); 296 306 end 307 else if THelpLineInfo(MainText.Objects[sb.si.npos + i]).Format = pkSection 308 then 309 begin 310 ca.Font.Assign(CaptionFont); 311 BiColorTextOut(ca, CaptionColor, $7F007F, x, y - 3, s); 312 ca.Font.Assign(UniFont[ftNormal]); 313 end 314 else 315 begin 316 if (Kind = hkMisc) and (no = miscMain) then 317 ca.Font.Assign(CaptionFont); 318 TextColor := Colors.Canvas.Pixels[clkMisc, cliPaperText]; 319 if ca = Canvas then 320 begin 321 TextSize.cx := BiColorTextWidth(ca, s); 322 TextSize.cy := ca.TextHeight(s); 323 if y + TextSize.cy >= WideFrame + InnerHeight then 324 TextSize.cy := WideFrame + InnerHeight - y; 325 FillSeamless(ca, x, y, TextSize.cx, TextSize.cy, -SideFrame, 326 sb.si.npos * 24 - WideFrame, Paper); 327 end; 328 BiColorTextOut(ca, TextColor, $7F007F, x, y, s); 329 if lit then 330 with ca do 331 begin 332 assert(ca = Canvas); 333 pen.color := TextColor; 334 moveto(x + 1, y + TextSize.cy - 2); 335 lineto(x + TextSize.cx, y + TextSize.cy - 2); 336 end; 337 if (Kind = hkMisc) and (no = miscMain) then 338 ca.Font.Assign(UniFont[ftNormal]); 339 end 297 340 end; 298 341 299 procedure THelpDlg.WaterSign(x0, y0,iix: integer);342 procedure THelpDlg.WaterSign(x0, y0, iix: integer); 300 343 const 301 nHeaven=28;302 maxsum=9*9*255 *75 div 100;344 nHeaven = 28; 345 maxsum = 9 * 9 * 255 * 75 div 100; 303 346 type 304 TLine=array[0..649,0..2] of Byte;347 TLine = array [0 .. 649, 0 .. 2] of Byte; 305 348 var 306 x,y,dx,dy,xSrc,ySrc,sum,xx: integer;307 Heaven: array[0..nHeaven] of integer;308 PaintLine,CoalLine: ^TLine;309 ImpLine: array[-1..1] of ^TLine;349 x, y, dx, dy, xSrc, ySrc, sum, xx: integer; 350 Heaven: array [0 .. nHeaven] of integer; 351 PaintLine, CoalLine: ^TLine; 352 ImpLine: array [-1 .. 1] of ^TLine; 310 353 begin 311 // assume eiffel tower has free common heaven 312 for dy:=0 to nHeaven-1 do 313 Heaven[dy]:=BigImp.Canvas.Pixels[woEiffel mod 7 *xSizeBig, 314 (SystemIconLines+woEiffel div 7)*ySizeBig+dy]; 315 316 xSrc:=iix mod 7 *xSizeBig; 317 ySrc:=(iix div 7+1) *ySizeBig; 318 for y:=0 to ySizeBig*2-1 do if (y0+y>=0) and (y0+y<InnerHeight) then 319 begin 320 PaintLine:=OffScreen.ScanLine[y0+y]; 321 CoalLine:=Templates.ScanLine[yCoal+y]; 322 for dy:=-1 to 1 do 323 if ((y+dy) shr 1>=0) and ((y+dy) shr 1<ySizeBig) then 324 ImpLine[dy]:=BigImp.ScanLine[ySrc+(y+dy) shr 1]; 325 for x:=0 to xSizeBig*2-1 do 326 begin 327 sum:=0; 328 for dx:=-1 to 1 do 354 // assume eiffel tower has free common heaven 355 for dy := 0 to nHeaven - 1 do 356 Heaven[dy] := BigImp.Canvas.Pixels[woEiffel mod 7 * xSizeBig, 357 (SystemIconLines + woEiffel div 7) * ySizeBig + dy]; 358 359 xSrc := iix mod 7 * xSizeBig; 360 ySrc := (iix div 7 + 1) * ySizeBig; 361 for y := 0 to ySizeBig * 2 - 1 do 362 if (y0 + y >= 0) and (y0 + y < InnerHeight) then 363 begin 364 PaintLine := OffScreen.ScanLine[y0 + y]; 365 CoalLine := Templates.ScanLine[yCoal + y]; 366 for dy := -1 to 1 do 367 if ((y + dy) shr 1 >= 0) and ((y + dy) shr 1 < ySizeBig) then 368 ImpLine[dy] := BigImp.ScanLine[ySrc + (y + dy) shr 1]; 369 for x := 0 to xSizeBig * 2 - 1 do 329 370 begin 330 xx:=xSrc+(x+dx) shr 1; 331 for dy:=-1 to 1 do 332 if ((y+dy) shr 1<0) or ((y+dy) shr 1>=ySizeBig) 333 or ((x+dx) shr 1<0) or ((x+dx) shr 1>=xSizeBig) 334 or ((y+dy) shr 1<nHeaven) 335 and (ImpLine[dy,xx,0] shl 16+ImpLine[dy,xx,1] shl 8+ImpLine[dy,xx,2]=Heaven[(y+dy) shr 1]) then 336 sum:=sum+9*255 337 else sum:=sum+ImpLine[dy,xx,0]+5*ImpLine[dy,xx,1]+3*ImpLine[dy,xx,2]; 371 sum := 0; 372 for dx := -1 to 1 do 373 begin 374 xx := xSrc + (x + dx) shr 1; 375 for dy := -1 to 1 do 376 if ((y + dy) shr 1 < 0) or ((y + dy) shr 1 >= ySizeBig) or 377 ((x + dx) shr 1 < 0) or ((x + dx) shr 1 >= xSizeBig) or 378 ((y + dy) shr 1 < nHeaven) and 379 (ImpLine[dy, xx, 0] shl 16 + ImpLine[dy, xx, 1] shl 8 + 380 ImpLine[dy, xx, 2] = Heaven[(y + dy) shr 1]) then 381 sum := sum + 9 * 255 382 else 383 sum := sum + ImpLine[dy, xx, 0] + 5 * ImpLine[dy, xx, 1] + 3 * 384 ImpLine[dy, xx, 2]; 385 end; 386 if sum < maxsum then 387 begin // no saturation 388 sum := 1 shl 22 - (maxsum - sum) * (256 - CoalLine[xCoal + x, 0] * 2); 389 PaintLine[x0 + x, 0] := PaintLine[x0 + x, 0] * sum shr 22; 390 PaintLine[x0 + x, 1] := PaintLine[x0 + x, 1] * sum shr 22; 391 PaintLine[x0 + x, 2] := PaintLine[x0 + x, 2] * sum shr 22; 392 end 393 end 394 end; 395 end; 396 397 procedure THelpDlg.OffscreenPaint; 398 399 procedure PaintTerrIcon(x, y, xSrc, ySrc: integer); 400 begin 401 Frame(OffScreen.Canvas, x - 1, y - 1, x + xSizeBig, y + ySizeBig, 402 $000000, $000000); 403 if 2 * yyt < 40 then 404 begin 405 Sprite(OffScreen, HGrTerrain, x, y, 56, 2 * yyt, xSrc, ySrc); 406 Sprite(OffScreen, HGrTerrain, x, y + 2 * yyt, 56, 40 - 2 * yyt, 407 xSrc, ySrc); 408 end 409 else 410 Sprite(OffScreen, HGrTerrain, x, y, 56, 40, xSrc, ySrc); 411 Sprite(OffScreen, HGrTerrain, x, y, xxt, yyt, xSrc + xxt, ySrc + yyt); 412 Sprite(OffScreen, HGrTerrain, x, y + yyt, xxt, 40 - yyt, xSrc + xxt, ySrc); 413 Sprite(OffScreen, HGrTerrain, x + xxt, y, 56 - xxt, yyt, xSrc, ySrc + yyt); 414 Sprite(OffScreen, HGrTerrain, x + xxt, y + yyt, 56 - xxt, 40 - yyt, 415 xSrc, ySrc); 416 end; 417 418 var 419 i, j, yl, srcno, ofs, cnt, y: integer; 420 s: string; 421 HelpLineInfo: THelpLineInfo; 422 begin 423 inherited; 424 CaptionColor := Colors.Canvas.Pixels[clkMisc, cliPaperCaption]; 425 FillSeamless(OffScreen.Canvas, 0, 0, InnerWidth, InnerHeight, 0, 426 sb.si.npos * 24, Paper); 427 with OffScreen.Canvas do 428 begin 429 Font.Assign(UniFont[ftNormal]); 430 for i := -sb.si.npos to InnerHeight div 24 do 431 if sb.si.npos + i < MainText.Count then 432 begin 433 HelpLineInfo := THelpLineInfo(MainText.Objects[sb.si.npos + i]); 434 if HelpLineInfo.Format = pkExternal then 435 begin 436 yl := ExtPic.Height; 437 if 4 + i * 24 + yl > InnerHeight then 438 yl := InnerHeight - (4 + i * 24); 439 BitBlt(Handle, 8, 4 + i * 24, ExtPic.Width, yl, ExtPic.Canvas.Handle, 440 0, 0, SRCCOPY); 441 end 338 442 end; 339 if sum<maxsum then 340 begin // no saturation 341 sum:=1 shl 22 - (maxsum-sum)*(256-CoalLine[xCoal+x,0]*2); 342 PaintLine[x0+x,0]:=PaintLine[x0+x,0]*sum shr 22; 343 PaintLine[x0+x,1]:=PaintLine[x0+x,1]*sum shr 22; 344 PaintLine[x0+x,2]:=PaintLine[x0+x,2]*sum shr 22; 443 for i := -2 to InnerHeight div 24 do 444 if (sb.si.npos + i >= 0) and (sb.si.npos + i < MainText.Count) then 445 begin 446 HelpLineInfo := THelpLineInfo(MainText.Objects[sb.si.npos + i]); 447 if HelpLineInfo.Link <> 0 then 448 begin 449 if (Kind = hkMisc) and (no = miscSearchResult) then 450 Sprite(OffScreen, HGrSystem, 18, 9 + i * 24, 8, 8, 90, 16) 451 else if HelpLineInfo.Format in [pkSmallIcon_AsPreq, pkAdvIcon_AsPreq] 452 then 453 Sprite(OffScreen, HGrSystem, 12, i * 24 + 5, 14, 14, 65, 20) 454 else if HelpLineInfo.Link and (hkCrossLink shl 8) <> 0 then 455 Sprite(OffScreen, HGrSystem, 12, i * 24 + 5, 14, 14, 80, 1) 456 else if not((Kind = hkMisc) and (no = miscMain)) then 457 Sprite(OffScreen, HGrSystem, 10, i * 24 + 6, 14, 14, 65, 1); 458 x0[i] := 24; 459 end 460 else 461 x0[i] := 0; 462 case HelpLineInfo.Format of 463 pkLogo: 464 begin 465 Server(sGetVersion, 0, 0, j); 466 s := Format('%d.%d.%d', [j shr 16 and $FF, j shr 8 and $FF, 467 j and $FF]); 468 PaintLogo(OffScreen.Canvas, (InnerWidth - 122) div 2, i * 24 + 1, 469 GrExt[HGrSystem].Data.Canvas.Pixels[95, 1], $000000); 470 Font.Assign(UniFont[ftSmall]); 471 BiColorTextOut(OffScreen.Canvas, $000000, $7F007F, 472 (InnerWidth - Textwidth(s)) div 2, i * 24 + 26, s); 473 Font.Assign(UniFont[ftNormal]); 474 end; 475 pkSmallIcon, pkSmallIcon_AsPreq: 476 begin 477 Frame(OffScreen.Canvas, 8 - 1 + x0[i], 2 - 1 + i * 24, 478 8 + xSizeSmall + x0[i], 2 + 20 + i * 24, $000000, $000000); 479 if HelpLineInfo.Picpix = imPalace then 480 BitBlt(OffScreen.Canvas.Handle, 8 + x0[i], 2 + i * 24, 481 xSizeSmall, ySizeSmall, SmallImp.Canvas.Handle, 482 0 * xSizeSmall, 1 * ySizeSmall, SRCCOPY) 483 else 484 BitBlt(OffScreen.Canvas.Handle, 8 + x0[i], 2 + i * 24, 485 xSizeSmall, ySizeSmall, SmallImp.Canvas.Handle, 486 HelpLineInfo.Picpix mod 7 * xSizeSmall, 487 (HelpLineInfo.Picpix + SystemIconLines * 7) div 7 * 488 ySizeSmall, SRCCOPY); 489 x0[i] := x0[i] + (8 + 8 + 36); 490 end; 491 pkBigIcon: 492 begin 493 FrameImage(OffScreen.Canvas, BigImp, x0[i] + 12, i * 24 - 7, 56, 494 40, HelpLineInfo.Picpix mod 7 * xSizeBig, 495 HelpLineInfo.Picpix div 7 * ySizeBig); 496 x0[i] := 64 + 8 + 8 + x0[i]; 497 end; 498 pkSpecialIcon: 499 begin 500 case HelpLineInfo.Picpix of 501 0: 502 FrameImage(OffScreen.Canvas, GrExt[HGrSystem2].Data, 503 12 + x0[i], -7 + i * 24, 56, 40, 137, 127); 504 1: 505 begin 506 PaintTerrIcon(12 + x0[i], -7 + i * 24, 507 1 + 3 * (xxt * 2 + 1), 1 + yyt); 508 if 2 * yyt < 40 then 509 Sprite(OffScreen, HGrTerrain, 12 + x0[i], -7 + 4 + i * 24, 510 56, 2 * yyt, 1 + 3 * (xxt * 2 + 1) + xxt - 28, 511 1 + yyt + 1 * (yyt * 3 + 1)) 512 else 513 Sprite(OffScreen, HGrTerrain, 12 + x0[i], 514 -7 + 4 + i * 24 - 4, 56, 40, 1 + 3 * (xxt * 2 + 1) + xxt 515 - 28, 1 + yyt + 1 * (yyt * 3 + 1) + yyt - 20); 516 end; 517 2: 518 begin 519 PaintTerrIcon(12 + x0[i], -7 + i * 24, 520 1 + 7 * (xxt * 2 + 1), 1 + yyt + 4 * (yyt * 3 + 1)); 521 if 2 * yyt < 40 then 522 Sprite(OffScreen, HGrTerrain, 12 + x0[i], -7 + 4 + i * 24, 523 56, 32, 1 + 4 * (xxt * 2 + 1) + xxt - 28, 524 1 + yyt + 12 * (yyt * 3 + 1) + yyt - 16) 525 else 526 Sprite(OffScreen, HGrTerrain, 12 + x0[i], -7 + 4 + i * 24, 527 56, 32, 1 + 4 * (xxt * 2 + 1) + xxt - 28, 528 1 + yyt + 12 * (yyt * 3 + 1) + yyt - 16) 529 end; 530 end; 531 x0[i] := 64 + 8 + 8 + x0[i]; 532 end; 533 pkDomain: 534 begin 535 Frame(OffScreen.Canvas, 8 - 1 + x0[i], 2 - 1 + i * 24, 536 8 + 36 + x0[i], 2 + 20 + i * 24, $000000, $000000); 537 Dump(OffScreen, HGrSystem, 8 + x0[i], 2 + i * 24, 36, 20, 538 75 + HelpLineInfo.Picpix * 37, 295); 539 x0[i] := x0[i] + (8 + 8 + 36); 540 end; 541 pkAdvIcon, pkAdvIcon_AsPreq: 542 begin 543 Frame(OffScreen.Canvas, 8 - 1 + x0[i], 2 - 1 + i * 24, 544 8 + xSizeSmall + x0[i], 2 + ySizeSmall + i * 24, 545 $000000, $000000); 546 if AdvIcon[HelpLineInfo.Picpix] < 84 then 547 BitBlt(OffScreen.Canvas.Handle, 8 + x0[i], 2 + i * 24, 548 xSizeSmall, ySizeSmall, SmallImp.Canvas.Handle, 549 (AdvIcon[HelpLineInfo.Picpix] + SystemIconLines * 7) mod 7 * 550 xSizeSmall, (AdvIcon[HelpLineInfo.Picpix] + SystemIconLines * 551 7) div 7 * ySizeSmall, SRCCOPY) 552 else 553 Dump(OffScreen, HGrSystem, 8 + x0[i], 2 + i * 24, 36, 20, 554 1 + (AdvIcon[HelpLineInfo.Picpix] - 84) mod 8 * 37, 555 295 + (AdvIcon[HelpLineInfo.Picpix] - 84) div 8 * 21); 556 j := AdvValue[HelpLineInfo.Picpix] div 1000; 557 BitBlt(Handle, x0[i] + 4, 4 + i * 24, 14, 14, 558 GrExt[HGrSystem].Mask.Canvas.Handle, 127 + j * 15, 85, SRCAND); 559 Sprite(OffScreen, HGrSystem, x0[i] + 3, 3 + i * 24, 14, 14, 560 127 + j * 15, 85); 561 x0[i] := x0[i] + (8 + 8 + 36); 562 end; 563 pkRightIcon: 564 begin 565 if Imp[HelpLineInfo.Picpix].Kind <> ikWonder then 566 ImpImage(OffScreen.Canvas, InnerWidth - (40 + xSizeBig), i * 24, 567 HelpLineInfo.Picpix, gDespotism) 568 else 569 WaterSign(InnerWidth - (40 + 2 * xSizeBig), i * 24 - 8, 570 HelpLineInfo.Picpix + 7); 571 x0[i] := x0[i] + 8; 572 end; 573 pkIllu: 574 WaterSign(8, i * 24 - 8, HelpLineInfo.Picpix); 575 pkBigFeature: 576 begin 577 cnt := 0; 578 for j := nDomains - 1 downto 0 do 579 if 1 shl j and Feature[HelpLineInfo.Picpix].Domains <> 0 then 580 begin 581 inc(cnt); 582 Dump(OffScreen, HGrSystem, InnerWidth - 38 - 38 * cnt, 583 i * 24 + 1, 36, 20, 75 + j * 37, 295); 584 Frame(OffScreen.Canvas, InnerWidth - 39 - 38 * cnt, i * 24, 585 InnerWidth - 2 - 38 * cnt, i * 24 + 21, $000000, $000000); 586 end; 587 DarkGradient(OffScreen.Canvas, InnerWidth - 38 - 38 * cnt, 588 i * 24 + 23, cnt * 38 - 2, 1); 589 ofs := InnerWidth - (39 + 7) - 19 * cnt; 590 with OffScreen.Canvas do 591 begin 592 Brush.color := $C0C0C0; 593 FrameRect(Rect(ofs, 1 + 23 + i * 24, ofs + 14, 594 15 + 23 + i * 24)); 595 Brush.Style := bsClear; 596 Sprite(OffScreen, HGrSystem, ofs + 2, 3 + 23 + i * 24, 10, 10, 597 66 + HelpLineInfo.Picpix mod 11 * 11, 598 137 + HelpLineInfo.Picpix div 11 * 11); 599 end; 600 x0[i] := x0[i] + 8; 601 end; 602 pkTer, pkBigTer: 603 begin 604 if HelpLineInfo.Format = pkBigTer then 605 y := i * 24 - 3 + yyt 606 else 607 y := i * 24 + 13; 608 if HelpLineInfo.Picpix >= 3 * 12 then 609 srcno := 2 * 9 + 6 610 else if HelpLineInfo.Picpix mod 12 = fJungle then 611 srcno := 18 * 9 612 else if HelpLineInfo.Picpix mod 12 < fJungle then 613 srcno := HelpLineInfo.Picpix mod 12 614 else 615 srcno := 27 + (HelpLineInfo.Picpix mod 12 - 9) * 18; 616 if HelpLineInfo.Format = pkTer then 617 begin 618 ofs := x0[i] + 8; 619 x0[i] := 2 * xxt + 8 + ofs; 620 end 621 else 622 begin 623 ofs := InnerWidth - (2 * xxt + 38); 624 x0[i] := x0[i] + 8; 625 end; 626 if srcno >= fJungle then 627 begin 628 Sprite(OffScreen, HGrTerrain, ofs + 4, y - yyt + 2, xxt * 2 - 8, 629 yyt * 2 - 4, 5 + 2 * (xxt * 2 + 1), 630 3 + yyt + 2 * (yyt * 3 + 1)); 631 Sprite(OffScreen, HGrTerrain, ofs, y - 2 * yyt, xxt * 2, 632 yyt * 3 - 2, 1 + srcno mod 9 * (xxt * 2 + 1), 633 1 + srcno div 9 * (yyt * 3 + 1)); 634 end 635 else 636 Sprite(OffScreen, HGrTerrain, ofs + 4, y - yyt + 2, xxt * 2 - 8, 637 yyt * 2 - 4, 5 + srcno mod 9 * (xxt * 2 + 1), 638 3 + yyt + srcno div 9 * (yyt * 3 + 1)); 639 if HelpLineInfo.Picpix >= 3 * 12 then { rare resource } 640 Sprite(OffScreen, HGrTerrain, ofs, y - 2 * yyt, xxt * 2, 641 yyt * 3, 1 + 8 * (xxt * 2 + 1), 642 1 + (HelpLineInfo.Picpix - 2 * 12) * (yyt * 3 + 1)) 643 else if HelpLineInfo.Picpix >= 12 then { special tile } 644 begin 645 if HelpLineInfo.Picpix mod 12 = fJungle then 646 srcno := 17 * 9 + 8 647 else if HelpLineInfo.Picpix mod 12 < fJungle then 648 srcno := HelpLineInfo.Picpix mod 12 649 else 650 srcno := 18 + 8 + (HelpLineInfo.Picpix mod 12 - 9) * 18; 651 srcno := srcno + HelpLineInfo.Picpix div 12 * 9; 652 Sprite(OffScreen, HGrTerrain, ofs, y - 2 * yyt, xxt * 2, 653 yyt * 3, 1 + srcno mod 9 * (xxt * 2 + 1), 654 1 + srcno div 9 * (yyt * 3 + 1)); 655 end; 656 end; 657 pkTerImp: 658 begin 659 ofs := 8; 660 if HelpLineInfo.Picpix = 5 then 661 begin // display mine on hills 662 Sprite(OffScreen, HGrTerrain, ofs + 4, i * 24 + 13 - yyt, 663 xxt * 2 - 8, yyt * 2 - 4, 5 + 2 * (xxt * 2 + 1), 664 3 + yyt + 2 * (yyt * 3 + 1)); 665 srcno := 45 666 end 667 else 668 srcno := fPrairie; // display on prairie 669 Sprite(OffScreen, HGrTerrain, ofs + 4, i * 24 + 13 - yyt, 670 xxt * 2 - 8, yyt * 2 - 4, 5 + srcno mod 9 * (xxt * 2 + 1), 671 3 + yyt + srcno div 9 * (yyt * 3 + 1)); 672 if HelpLineInfo.Picpix = 12 then { river } 673 Sprite(OffScreen, HGrTerrain, ofs, i * 24 + 11 - yyt, xxt * 2, 674 yyt * 2, 1 + 5 * (xxt * 2 + 1), 1 + yyt + 13 * (yyt * 3 + 1)) 675 else if HelpLineInfo.Picpix >= 3 then { improvement 2 } 676 begin 677 if HelpLineInfo.Picpix = 6 then 678 Sprite(OffScreen, HGrTerrain, ofs, i * 24 + 11 - 2 * yyt, 679 xxt * 2, yyt * 3, 1 + 7 * (xxt * 2 + 1), 680 1 + 12 * (yyt * 3 + 1)); 681 Sprite(OffScreen, HGrTerrain, ofs, i * 24 + 11 - 2 * yyt, 682 xxt * 2, yyt * 3, 1 + (HelpLineInfo.Picpix - 3) * 683 (xxt * 2 + 1), 1 + 12 * (yyt * 3 + 1)) 684 end 685 else { improvement 1 } 686 begin 687 Sprite(OffScreen, HGrTerrain, ofs, i * 24 + 11 - 2 * yyt, 688 xxt * 2, yyt * 3, 1 + 2 * (xxt * 2 + 1), 689 1 + (9 + HelpLineInfo.Picpix) * (yyt * 3 + 1)); 690 Sprite(OffScreen, HGrTerrain, ofs, i * 24 + 11 - 2 * yyt, 691 xxt * 2, yyt * 3, 1 + 5 * (xxt * 2 + 1), 692 1 + (9 + HelpLineInfo.Picpix) * (yyt * 3 + 1)) 693 end; 694 x0[i] := x0[i] + 8; 695 end; 696 pkModel: 697 begin 698 FrameImage(OffScreen.Canvas, BigImp, x0[i] + 12, i * 24 - 7, 699 56, 40, 0, 0); 700 Sprite(OffScreen, HGrStdUnits, x0[i] + 8, i * 24 - 11, 64, 44, 701 1 + HelpLineInfo.Picpix mod 10 * 65, 702 1 + HelpLineInfo.Picpix div 10 * 49); 703 x0[i] := 64 + 8 + 8 + x0[i]; 704 end; 705 pkFeature: 706 begin 707 DarkGradient(OffScreen.Canvas, x0[i] + 8 - 1, 708 7 + i * 24 - 3, 16, 1); 709 Frame(OffScreen.Canvas, x0[i] + 8, 7 + i * 24 - 2, x0[i] + 8 + 13, 710 7 + i * 24 - 2 + 13, $C0C0C0, $C0C0C0); 711 Sprite(OffScreen, HGrSystem, x0[i] + 8 + 2, 7 + i * 24, 10, 10, 712 66 + HelpLineInfo.Picpix mod 11 * 11, 713 137 + HelpLineInfo.Picpix div 11 * 11); 714 x0[i] := x0[i] + 8 + 8 + 2 + 13; 715 end; 716 pkExp: 717 begin 718 Frame(OffScreen.Canvas, 20 - 1, 8 - 4 + i * 24, 20 + 12, 719 8 + 11 + i * 24, $000000, $000000); 720 Dump(OffScreen, HGrSystem, 20, 8 - 3 + i * 24, 12, 14, 721 121 + HelpLineInfo.Picpix * 13, 28); 722 x0[i] := 20 + 8 + 11; 723 end; 724 pkAITStat: 725 begin 726 Sprite(OffScreen, HGrSystem, 20, 6 + i * 24, 14, 14, 727 1 + HelpLineInfo.Picpix * 15, 316); 728 x0[i] := 20 + 8 + 11; 729 end; 730 pkGov: 731 begin 732 Frame(OffScreen.Canvas, 8 - 1 + x0[i], 2 - 1 + i * 24, 733 8 + xSizeSmall + x0[i], 2 + 20 + i * 24, $000000, $000000); 734 BitBlt(OffScreen.Canvas.Handle, 8 + x0[i], 2 + i * 24, xSizeSmall, 735 ySizeSmall, SmallImp.Canvas.Handle, (HelpLineInfo.Picpix - 1) * 736 xSizeSmall, ySizeSmall, SRCCOPY); 737 x0[i] := x0[i] + (8 + 8 + 36); 738 end; 739 pkDot: 740 begin 741 Sprite(OffScreen, HGrSystem, x0[i] + 18, 9 + i * 24, 8, 742 8, 81, 16); 743 x0[i] := 20 + 8 + 4; 744 end; 745 pkNormal_Dot: 746 x0[i] := 20 + 8 + 4; 747 pkNormal_64: 748 x0[i] := 64 + 8 + 8; 749 else 750 x0[i] := x0[i] + 8 751 end; 752 line(OffScreen.Canvas, i, false) 753 end 754 end; 755 MarkUsedOffscreen(InnerWidth, InnerHeight + 13 + 48); 756 end; { OffscreenPaint } 757 758 procedure THelpDlg.Prepare(sbPos: integer = 0); 759 var 760 i, j, special, Domain, Headline, TerrType, TerrSubType: integer; 761 s: string; 762 ps: pchar; 763 List: THyperText; 764 CheckSeeAlso: boolean; 765 766 procedure AddAdv(i: integer); 767 begin 768 MainText.AddLine(Phrases.Lookup('ADVANCES', i), pkAdvIcon, i, 769 hkAdv + hkCrossLink, i); 770 end; 771 772 procedure AddPreqAdv(i: integer); 773 begin 774 MainText.AddLine(Phrases.Lookup('ADVANCES', i), pkAdvIcon_AsPreq, i, 775 hkAdv + hkCrossLink, i); 776 end; 777 778 procedure AddImp(i: integer); 779 begin 780 MainText.AddLine(Phrases.Lookup('IMPROVEMENTS', i), pkSmallIcon, i, 781 hkImp + hkCrossLink, i); 782 end; 783 784 procedure AddPreqImp(i: integer); 785 begin 786 MainText.AddLine(Phrases.Lookup('IMPROVEMENTS', i), pkSmallIcon_AsPreq, i, 787 hkImp + hkCrossLink, i); 788 end; 789 790 procedure AddTer(i: integer); 791 begin 792 if MainText.Count > 1 then 793 begin 794 MainText.LF; 795 end; 796 MainText.AddLine(Phrases.Lookup('TERRAIN', i), pkTer, i, hkTer, i); 797 end; 798 799 procedure AddFeature(i: integer); 800 begin 801 MainText.AddLine(Phrases.Lookup('FEATURES', i), pkFeature, i, 802 hkFeature + hkCrossLink, i); 803 end; 804 805 procedure AddModel(i: integer); 806 var 807 pix: integer; 808 Name: string; 809 begin 810 if MainText.Count > 1 then 811 MainText.LF; 812 FindStdModelPicture(SpecialModelPictureCode[i], pix, Name); 813 MainText.AddLine(Name, pkModel, pix, hkModel + hkCrossLink, i) 814 end; 815 816 procedure AddStandardBlock(Item: string); 817 var 818 i: integer; 819 begin 820 with MainText do 821 begin 822 if Item = 'LOGO' then 823 begin 824 AddLine('', pkLogo); 825 LF; 826 end 827 else if Item = 'TECHFORMULA' then 828 begin 829 i := Difficulty; 830 if i = 0 then 831 i := 2; 832 AddLine(Format(HelpText.Lookup('TECHFORMULA'), [TechFormula_M[i], 833 TechFormula_D[i]])) 834 end 835 else if Item = 'EXPERIENCE' then 836 for i := 0 to nExp - 1 do 837 AddLine(Phrases.Lookup('EXPERIENCE', i), pkExp, i) 838 else if Item = 'MODERN' then 839 for i := 1 to 3 do 840 begin 841 LF; 842 AddLine(Phrases.Lookup('TERRAIN', 3 * 12 + i), pkTer, 3 * 12 + i); 843 end 844 else if Item = 'SAVED' then 845 AddLine(DataDir + 'Saved', pkNormal) 846 else if Item = 'AITSTAT' then 847 for i := 0 to 3 do 848 AddLine(Phrases2.Lookup('AITSTAT', i), pkAITStat, i) 849 end 850 end; 851 852 procedure DecodeItem(s: string; var Category, Index: integer); 853 var 854 i: integer; 855 begin 856 if (length(s) > 0) and (s[1] = ':') then 857 begin 858 Category := hkMisc; 859 Index := 0; 860 for i := 3 to length(s) do 861 Index := Index * 10 + ord(s[i]) - 48; 862 case s[2] of 863 'A': 864 Category := hkAdv; 865 'B': 866 Category := hkImp; 867 'T': 868 Category := hkTer; 869 'F': 870 Category := hkFeature; 871 'E': 872 Category := hkInternet; 873 'S': 874 Category := hkModel; 875 'C': 876 Index := miscCredits; 877 'J': 878 Index := miscJobList; 879 'G': 880 Index := miscGovList; 881 end; 882 if (Category <> hkMisc) and (Index = 0) then 883 Index := 200; 884 end 885 else 886 begin 887 Category := hkText; 888 Index := HelpText.Gethandle(copy(s, 1, 255)); 889 end; 890 end; 891 892 procedure AddText(s: string); 893 var 894 i, p, l, ofs, CurrentFormat, FollowFormat, Picpix, LinkCategory, LinkIndex, 895 RightMargin: integer; 896 Name: string; 897 begin 898 RightMargin := InnerWidth - 16 - GetSystemMetrics(SM_CXVSCROLL); 899 FollowFormat := pkNormal; 900 while s <> '' do 901 begin 902 Picpix := 0; 903 LinkCategory := 0; 904 LinkIndex := 0; 905 if s[1] = '$' then 906 begin // window caption 907 p := 1; 908 repeat 909 inc(p) 910 until (p > length(s)) or (s[p] = '\'); 911 Caption := copy(s, 2, p - 2); 912 Delete(s, 1, p); 913 end 914 else if s[1] = '&' then 915 begin // standard block 916 p := 1; 917 repeat 918 inc(p) 919 until (p > length(s)) or (s[p] = '\'); 920 AddStandardBlock(copy(s, 2, p - 2)); 921 Delete(s, 1, p); 922 end 923 else if s[1] = '@' then 924 begin // image 925 if (length(s) >= 2) and (s[2] = '@') then 926 begin // generate from icon 927 Picpix := 0; 928 p := 3; 929 while (p <= length(s)) and (s[p] <> '\') do 930 begin 931 Picpix := Picpix * 10 + ord(s[p]) - 48; 932 inc(p) 933 end; 934 if (Picpix < 0) or (Picpix >= nImp) then 935 Picpix := 0; 936 MainText.AddLine('', pkIllu, Picpix); 937 MainText.LF; 938 MainText.LF; 939 end 940 else 941 begin // external image 942 p := 1; 943 repeat 944 inc(p) 945 until (p > length(s)) or (s[p] = '\'); 946 if LoadLocalizedGraphicFile(ExtPic, 'Help\' + copy(s, 2, p - 2)) then 947 begin 948 MainText.AddLine('', pkExternal); 949 for i := 0 to (ExtPic.Height - 12) div 24 do 950 MainText.LF; 951 end; 952 end; 953 Delete(s, 1, p); 954 end 955 else 956 begin 957 case s[1] of 958 ':', ';': 959 begin // link 960 p := 1; 961 repeat 962 inc(p) 963 until (p > length(s)) or (s[p] = '\') or (s[p] = ' '); 964 DecodeItem(copy(s, 2, p - 2), LinkCategory, LinkIndex); 965 CurrentFormat := 0; 966 if (LinkCategory <> hkText) and (LinkIndex < 200) then 967 // show icon 968 case LinkCategory of 969 hkAdv: 970 begin 971 CurrentFormat := pkAdvIcon; 972 Picpix := LinkIndex 973 end; 974 hkImp: 975 begin 976 CurrentFormat := pkSmallIcon; 977 Picpix := LinkIndex 978 end; 979 hkTer: 980 begin 981 CurrentFormat := pkTer; 982 Picpix := LinkIndex 983 end; 984 hkFeature: 985 begin 986 CurrentFormat := pkFeature; 987 Picpix := LinkIndex 988 end; 989 hkModel: 990 begin 991 CurrentFormat := pkModel; 992 FindStdModelPicture(SpecialModelPictureCode[LinkIndex], 993 Picpix, Name); 994 end; 995 end; 996 if s[1] = ':' then 997 LinkCategory := LinkCategory + hkCrossLink; 998 if (p > length(s)) or (s[p] = ' ') then 999 Delete(s, 1, p) 1000 else 1001 Delete(s, 1, p - 1) 1002 end; 1003 '!': // highlited 1004 if (length(s) >= 2) and (s[2] = '!') then 1005 begin 1006 if MainText.Count > 1 then 1007 MainText.LF; 1008 FollowFormat := pkCaption; 1009 CurrentFormat := pkCaption; 1010 Delete(s, 1, 2); 1011 end 1012 else 1013 begin 1014 FollowFormat := pkSection; 1015 CurrentFormat := pkSection; 1016 Delete(s, 1, 1); 1017 end; 1018 '-': 1019 begin // list 1020 FollowFormat := pkNormal_Dot; 1021 CurrentFormat := pkDot; 1022 Delete(s, 1, 1); 1023 end; 1024 else 1025 CurrentFormat := FollowFormat; 1026 end; 1027 if FollowFormat = pkNormal_Dot then 1028 ofs := 20 + 4 + 8 1029 else 1030 ofs := 8; 1031 p := 0; 1032 repeat 1033 repeat 1034 inc(p) 1035 until (p > length(s)) or (s[p] = ' ') or (s[p] = '\'); 1036 if (BiColorTextWidth(OffScreen.Canvas, copy(s, 1, p - 1)) <= 1037 RightMargin - ofs) then 1038 l := p - 1 1039 else 1040 Break; 1041 until (p >= length(s)) or (s[l + 1] = '\'); 1042 MainText.AddLine(copy(s, 1, l), CurrentFormat, Picpix, LinkCategory, 1043 LinkIndex); 1044 if (l < length(s)) and (s[l + 1] = '\') then 1045 FollowFormat := pkNormal; 1046 Delete(s, 1, l + 1); 345 1047 end 346 1048 end 347 1049 end; 348 end;349 350 procedure THelpDlg.OffscreenPaint;351 352 procedure PaintTerrIcon(x,y,xSrc,ySrc: integer);353 begin354 Frame(offscreen.canvas,x-1,y-1,x+xSizeBig,y+ySizeBig,$000000,$000000);355 if 2*yyt<40 then356 begin357 Sprite(Offscreen, HGrTerrain, x, y, 56, 2*yyt, xSrc, ySrc);358 Sprite(Offscreen, HGrTerrain, x, y+2*yyt, 56, 40-2*yyt, xSrc, ySrc);359 end360 else Sprite(Offscreen, HGrTerrain, x, y, 56, 40, xSrc, ySrc);361 Sprite(Offscreen, HGrTerrain, x, y, xxt, yyt, xSrc+xxt, ySrc+yyt);362 Sprite(Offscreen, HGrTerrain, x, y+yyt, xxt, 40-yyt, xSrc+xxt, ySrc);363 Sprite(Offscreen, HGrTerrain, x+xxt, y, 56-xxt, yyt, xSrc, ySrc+yyt);364 Sprite(Offscreen, HGrTerrain, x+xxt, y+yyt, 56-xxt, 40-yyt, xSrc, ySrc);365 end;366 367 var368 i,j,yl,srcno,ofs,cnt,y: integer;369 s: string;370 HelpLineInfo: THelpLineInfo;371 begin372 inherited;373 CaptionColor:=Colors.Canvas.Pixels[clkMisc,cliPaperCaption];374 FillSeamless(offscreen.Canvas,0,0,InnerWidth,InnerHeight,0,sb.si.npos*24,375 Paper);376 with offscreen.Canvas do377 begin378 Font.Assign(UniFont[ftNormal]);379 for i:=-sb.si.npos to InnerHeight div 24 do380 if sb.si.npos+i<MainText.Count then381 begin382 HelpLineInfo:=THelpLineInfo(MainText.Objects[sb.si.npos+i]);383 if HelpLineInfo.Format=pkExternal then384 begin385 yl:=ExtPic.Height;386 if 4+i*24+yl>InnerHeight then yl:=InnerHeight-(4+i*24);387 BitBlt(Handle,8,4+i*24,ExtPic.Width,yl,388 ExtPic.Canvas.Handle,0,0,SRCCOPY);389 end390 end;391 for i:=-2 to InnerHeight div 24 do392 if (sb.si.npos+i>=0) and (sb.si.npos+i<MainText.Count) then393 begin394 HelpLineInfo:=THelpLineInfo(MainText.Objects[sb.si.npos+i]);395 if HelpLineInfo.Link<>0 then396 begin397 if (Kind=hkMisc) and (no=miscSearchResult) then398 Sprite(offscreen,HGrSystem,18,9+i*24,8,8,90,16)399 else if HelpLineInfo.Format in [pkSmallIcon_AsPreq,pkAdvIcon_AsPreq] then400 Sprite(offscreen,HGrSystem,12,i*24+5,14,14,65,20)401 else if HelpLineInfo.Link and (hkCrossLink shl 8)<>0 then402 Sprite(offscreen,HGrSystem,12,i*24+5,14,14,80,1)403 else if not ((Kind=hkMisc) and (no=miscMain)) then404 Sprite(offscreen,HGrSystem,10,i*24+6,14,14,65,1);405 x0[i]:=24;406 end407 else x0[i]:=0;408 case HelpLineInfo.Format of409 pkLogo:410 begin411 Server(sGetVersion,0,0,j);412 s:=Format('%d.%d.%d',[j shr 16 and $FF, j shr 8 and $FF, j and $FF]);413 PaintLogo(offscreen.canvas,(InnerWidth-122) div 2,i*24+1,414 GrExt[HGrSystem].Data.Canvas.Pixels[95,1],$000000);415 Font.Assign(UniFont[ftSmall]);416 BiColorTextout(offscreen.Canvas,$000000,$7F007F,417 (InnerWidth-TextWidth(s)) div 2,i*24+26,s);418 Font.Assign(UniFont[ftNormal]);419 end;420 pkSmallIcon,pkSmallIcon_AsPreq:421 begin422 Frame(offscreen.Canvas,8-1+x0[i],2-1+i*24,8+xSizeSmall+x0[i],2+20+i*24,423 $000000,$000000);424 if HelpLineInfo.Picpix=imPalace then425 BitBlt(offscreen.Canvas.Handle,8+x0[i],2+i*24,xSizeSmall,ySizeSmall,SmallImp.Canvas.Handle,426 0*xSizeSmall,1*ySizeSmall,SRCCOPY)427 else BitBlt(offscreen.Canvas.Handle,8+x0[i],2+i*24,xSizeSmall,ySizeSmall,SmallImp.Canvas.Handle,428 HelpLineInfo.Picpix mod 7*xSizeSmall,(HelpLineInfo.Picpix+SystemIconLines*7) div 7*ySizeSmall,SRCCOPY);429 x0[i]:=x0[i]+(8+8+36);430 end;431 pkBigIcon:432 begin433 FrameImage(offscreen.canvas,BigImp,x0[i]+12,i*24-7,56,40,434 HelpLineInfo.Picpix mod 7*xSizeBig,435 HelpLineInfo.Picpix div 7*ySizeBig);436 x0[i]:=64+8+8+x0[i];437 end;438 pkSpecialIcon:439 begin440 case HelpLineInfo.Picpix of441 0:442 FrameImage(Offscreen.Canvas, GrExt[HGrSystem2].Data, 12+x0[i],-7+i*24, 56, 40, 137, 127);443 1:444 begin445 PaintTerrIcon(12+x0[i],-7+i*24, 1+3*(xxt*2+1), 1+yyt);446 if 2*yyt<40 then447 Sprite(Offscreen, HGrTerrain, 12+x0[i],-7+4+i*24, 56, 2*yyt, 1+3*(xxt*2+1)+xxt-28, 1+yyt+1*(yyt*3+1))448 else Sprite(Offscreen, HGrTerrain, 12+x0[i],-7+4+i*24-4, 56, 40, 1+3*(xxt*2+1)+xxt-28, 1+yyt+1*(yyt*3+1)+yyt-20);449 end;450 2:451 begin452 PaintTerrIcon(12+x0[i],-7+i*24, 1+7*(xxt*2+1), 1+yyt+4*(yyt*3+1));453 if 2*yyt<40 then454 Sprite(Offscreen, HGrTerrain, 12+x0[i],-7+4+i*24, 56, 32, 1+4*(xxt*2+1)+xxt-28, 1+yyt+12*(yyt*3+1)+yyt-16)455 else Sprite(Offscreen, HGrTerrain, 12+x0[i],-7+4+i*24, 56, 32, 1+4*(xxt*2+1)+xxt-28, 1+yyt+12*(yyt*3+1)+yyt-16)456 end;457 end;458 x0[i]:=64+8+8+x0[i];459 end;460 pkDomain:461 begin462 Frame(offscreen.Canvas,8-1+x0[i],2-1+i*24,8+36+x0[i],2+20+i*24,463 $000000,$000000);464 Dump(offscreen,HGrSystem,8+x0[i],2+i*24,36,20,465 75+HelpLineInfo.Picpix*37,295);466 x0[i]:=x0[i]+(8+8+36);467 end;468 pkAdvIcon,pkAdvIcon_AsPreq:469 begin470 Frame(offscreen.Canvas,8-1+x0[i],2-1+i*24,8+xSizeSmall+x0[i],2+ySizeSmall+i*24,471 $000000,$000000);472 if AdvIcon[HelpLineInfo.Picpix]<84 then473 BitBlt(offscreen.Canvas.Handle,8+x0[i],2+i*24,xSizeSmall,ySizeSmall,474 SmallImp.Canvas.Handle, (AdvIcon[HelpLineInfo.Picpix]+SystemIconLines*7) mod 7*xSizeSmall,475 (AdvIcon[HelpLineInfo.Picpix]+SystemIconLines*7) div 7*ySizeSmall,SRCCOPY)476 else477 Dump(offscreen,HGrSystem,8+x0[i],2+i*24,36,20,478 1+(AdvIcon[HelpLineInfo.Picpix]-84) mod 8*37,479 295+(AdvIcon[HelpLineInfo.Picpix]-84) div 8*21);480 j:=AdvValue[HelpLineInfo.Picpix] div 1000;481 BitBlt(Handle,x0[i]+4,4+i*24,14,14,482 GrExt[HGrSystem].Mask.Canvas.Handle,127+j*15,85,SRCAND);483 Sprite(offscreen,HGrSystem,x0[i]+3,3+i*24,14,14,127+j*15,85);484 x0[i]:=x0[i]+(8+8+36);485 end;486 pkRightIcon:487 begin488 if Imp[HelpLineInfo.Picpix].Kind<>ikWonder then489 ImpImage(Offscreen.Canvas,InnerWidth-(40+xSizeBig),i*24,490 HelpLineInfo.Picpix, gDespotism)491 else WaterSign(InnerWidth-(40+2*xSizeBig),i*24-8,HelpLineInfo.Picpix+7);492 x0[i]:=x0[i]+8;493 end;494 pkIllu:495 WaterSign(8,i*24-8,HelpLineInfo.Picpix);496 pkBigFeature:497 begin498 cnt:=0;499 for j:=nDomains-1 downto 0 do500 if 1 shl j and Feature[HelpLineInfo.Picpix].Domains<>0 then501 begin502 inc(cnt);503 Dump(offscreen,HGrSystem,InnerWidth-38-38*cnt,i*24+1,36,20,75+j*37,295);504 Frame(offscreen.canvas,InnerWidth-39-38*cnt,i*24,505 InnerWidth-2-38*cnt,i*24+21,506 $000000,$000000);507 end;508 DarkGradient(offscreen.Canvas,InnerWidth-38-38*cnt,i*24+23,cnt*38-2,1);509 ofs:=InnerWidth-(39+7)-19*cnt;510 with offscreen.Canvas do511 begin512 Brush.Color:=$C0C0C0;513 FrameRect(Rect(ofs,1+23+i*24,ofs+14,15+23+i*24));514 Brush.Style:=bsClear;515 Sprite(offscreen,HGrSystem,ofs+2,3+23+i*24,10,10,516 66+HelpLineInfo.Picpix mod 11 *11,517 137+HelpLineInfo.Picpix div 11 *11);518 end;519 x0[i]:=x0[i]+8;520 end;521 pkTer,pkBigTer:522 begin523 if HelpLineInfo.Format=pkBigTer then524 y:=i*24-3+yyt525 else y:=i*24+13;526 if HelpLineInfo.Picpix>=3*12 then srcno:=2*9+6527 else if HelpLineInfo.Picpix mod 12=fJungle then srcno:=18*9528 else if HelpLineInfo.Picpix mod 12<fJungle then529 srcno:=HelpLineInfo.Picpix mod 12530 else srcno:=27+(HelpLineInfo.Picpix mod 12-9)*18;531 if HelpLineInfo.Format=pkTer then532 begin ofs:=x0[i]+8; x0[i]:=2*xxt+8+ofs; end533 else begin ofs:=InnerWidth-(2*xxt+38); x0[i]:=x0[i]+8; end;534 if srcno>=fJungle then535 begin536 Sprite(offscreen,HGrTerrain,ofs+4,y-yyt+2,xxt*2-8,yyt*2-4,537 5+2*(xxt*2+1),3+yyt+2*(yyt*3+1));538 Sprite(offscreen,HGrTerrain,ofs,y-2*yyt,xxt*2,yyt*3-2,539 1+srcno mod 9 *(xxt*2+1),1+srcno div 9 *(yyt*3+1));540 end541 else Sprite(offscreen,HGrTerrain,ofs+4,y-yyt+2,xxt*2-8,yyt*2-4,542 5+srcno mod 9 *(xxt*2+1),3+yyt+srcno div 9 *(yyt*3+1));543 if HelpLineInfo.Picpix>=3*12 then {rare resource}544 Sprite(offscreen,HGrTerrain,ofs,y-2*yyt,xxt*2,yyt*3,545 1+8*(xxt*2+1), 1+(HelpLineInfo.Picpix-2*12)*(yyt*3+1))546 else if HelpLineInfo.Picpix>=12 then {special tile}547 begin548 if HelpLineInfo.Picpix mod 12=fJungle then srcno:=17*9+8549 else if HelpLineInfo.Picpix mod 12<fJungle then550 srcno:=HelpLineInfo.Picpix mod 12551 else srcno:=18+8+(HelpLineInfo.Picpix mod 12-9)*18;552 srcno:=srcno+HelpLineInfo.Picpix div 12*9;553 Sprite(offscreen,HGrTerrain,ofs,y-2*yyt,xxt*2,yyt*3,554 1+srcno mod 9 *(xxt*2+1),1+srcno div 9 *(yyt*3+1));555 end;556 end;557 pkTerImp:558 begin559 ofs:=8;560 if HelpLineInfo.Picpix=5 then561 begin // display mine on hills562 Sprite(offscreen,HGrTerrain,ofs+4,i*24+13-yyt,xxt*2-8,yyt*2-4,563 5+2*(xxt*2+1),3+yyt+2*(yyt*3+1));564 srcno:=45565 end566 else srcno:=fPrairie; // display on prairie567 Sprite(offscreen,HGrTerrain,ofs+4,i*24+13-yyt,xxt*2-8,yyt*2-4,568 5+srcno mod 9 *(xxt*2+1),3+yyt+srcno div 9 *(yyt*3+1));569 if HelpLineInfo.Picpix=12 then {river}570 Sprite(offscreen,HGrTerrain,ofs,i*24+11-yyt,xxt*2,yyt*2,1+5*(xxt*2+1),571 1+yyt+13*(yyt*3+1))572 else if HelpLineInfo.Picpix>=3 then {improvement 2}573 begin574 if HelpLineInfo.Picpix=6 then575 Sprite(offscreen,HGrTerrain,ofs,i*24+11-2*yyt,xxt*2,yyt*3,576 1+7 *(xxt*2+1),1+12 *(yyt*3+1));577 Sprite(offscreen,HGrTerrain,ofs,i*24+11-2*yyt,xxt*2,yyt*3,578 1+(HelpLineInfo.Picpix-3)*(xxt*2+1), 1+12*(yyt*3+1))579 end580 else {improvement 1}581 begin582 Sprite(offscreen,HGrTerrain,ofs,i*24+11-2*yyt,xxt*2,yyt*3,583 1+2*(xxt*2+1),1+(9+HelpLineInfo.Picpix)*(yyt*3+1));584 Sprite(offscreen,HGrTerrain,ofs,i*24+11-2*yyt,xxt*2,yyt*3,585 1+5*(xxt*2+1),1+(9+HelpLineInfo.Picpix)*(yyt*3+1))586 end;587 x0[i]:=x0[i]+8;588 end;589 pkModel:590 begin591 FrameImage(offscreen.canvas,BigImp,x0[i]+12,i*24-7,56,40,0,0);592 Sprite(offscreen,HGrStdUnits,x0[i]+8,i*24-11,64,44,593 1+HelpLineInfo.Picpix mod 10 *65,1+HelpLineInfo.Picpix div 10 *49);594 x0[i]:=64+8+8+x0[i];595 end;596 pkFeature:597 begin598 DarkGradient(offscreen.Canvas,x0[i]+8-1,7+i*24-3,16,1);599 Frame(offscreen.canvas,x0[i]+8,7+i*24-2,x0[i]+8+13,7+i*24-2+13,600 $C0C0C0,$C0C0C0);601 Sprite(offscreen,HGrSystem,x0[i]+8+2,7+i*24,10,10,602 66+HelpLineInfo.Picpix mod 11*11,137+HelpLineInfo.Picpix div 11*11);603 x0[i]:=x0[i]+8+8+2+13;604 end;605 pkExp:606 begin607 Frame(offscreen.Canvas,20-1,8-4+i*24,20+12,8+11+i*24,$000000,$000000);608 Dump(offscreen,HGrSystem,20,8-3+i*24,12,14,121+HelpLineInfo.Picpix*13,28);609 x0[i]:=20+8+11;610 end;611 pkAITStat:612 begin613 Sprite(offscreen,HGrSystem,20,6+i*24,14,14,1+HelpLineInfo.Picpix*15,316);614 x0[i]:=20+8+11;615 end;616 pkGov:617 begin618 Frame(offscreen.Canvas,8-1+x0[i],2-1+i*24,8+xSizeSmall+x0[i],2+20+i*24,619 $000000,$000000);620 BitBlt(offscreen.Canvas.Handle,8+x0[i],2+i*24,xSizeSmall,ySizeSmall,SmallImp.Canvas.Handle,621 (HelpLineInfo.Picpix-1)*xSizeSmall,ySizeSmall,SRCCOPY);622 x0[i]:=x0[i]+(8+8+36);623 end;624 pkDot:625 begin626 Sprite(offscreen,HGrSystem,x0[i]+18,9+i*24,8,8,81,16);627 x0[i]:=20+8+4;628 end;629 pkNormal_Dot:630 x0[i]:=20+8+4;631 pkNormal_64:632 x0[i]:=64+8+8;633 else x0[i]:=x0[i]+8634 end;635 line(offscreen.Canvas,i,false)636 end637 end;638 MarkUsedOffscreen(InnerWidth,InnerHeight+13+48);639 end; {OffscreenPaint}640 641 procedure THelpDlg.Prepare(sbPos: integer = 0);642 var643 i,j,special,Domain,Headline,TerrType,TerrSubType: integer;644 s: string;645 ps: pchar;646 List: THyperText;647 CheckSeeAlso: boolean;648 649 procedure AddAdv(i: integer);650 begin651 MainText.AddLine(Phrases.Lookup('ADVANCES',i),pkAdvIcon,i,hkAdv+hkCrossLink,i);652 end;653 654 procedure AddPreqAdv(i: integer);655 begin656 MainText.AddLine(Phrases.Lookup('ADVANCES',i),pkAdvIcon_AsPreq,i,hkAdv+hkCrossLink,i);657 end;658 659 procedure AddImp(i: integer);660 begin661 MainText.AddLine(Phrases.Lookup('IMPROVEMENTS',i),pkSmallIcon,i,hkImp+hkCrossLink,i);662 end;663 664 procedure AddPreqImp(i: integer);665 begin666 MainText.AddLine(Phrases.Lookup('IMPROVEMENTS',i),pkSmallIcon_AsPreq,i,hkImp+hkCrossLink,i);667 end;668 669 procedure AddTer(i: integer);670 begin671 if MainText.Count>1 then begin MainText.LF; end;672 MainText.AddLine(Phrases.Lookup('TERRAIN',i),pkTer,i,hkTer,i);673 end;674 675 procedure AddFeature(i: integer);676 begin677 MainText.AddLine(Phrases.Lookup('FEATURES',i),pkFeature,i,hkFeature+hkCrossLink,i);678 end;679 680 procedure AddModel(i: integer);681 var682 pix: integer;683 Name: string;684 begin685 if MainText.Count>1 then MainText.LF;686 FindStdModelPicture(SpecialModelPictureCode[i],pix,Name);687 MainText.AddLine(Name,pkModel,pix,hkModel+hkCrossLink,i)688 end;689 690 procedure AddStandardBlock(Item: string);691 var692 i: integer;693 begin694 with MainText do695 begin696 if Item='LOGO' then697 begin AddLine('',pkLogo); LF; end698 else if Item='TECHFORMULA' then699 begin700 i:=Difficulty;701 if i=0 then i:=2;702 AddLine(Format(HelpText.Lookup('TECHFORMULA'),[TechFormula_M[i],TechFormula_D[i]]))703 end704 else if Item='EXPERIENCE' then705 for i:=0 to nExp-1 do AddLine(Phrases.Lookup('EXPERIENCE',i),pkExp,i)706 else if Item='MODERN' then707 for i:=1 to 3 do708 begin709 LF;710 AddLine(Phrases.Lookup('TERRAIN',3*12+i),pkTer,3*12+i);711 end712 else if Item='SAVED' then713 AddLine(DataDir+'Saved',pkNormal)714 else if Item='AITSTAT' then715 for i:=0 to 3 do AddLine(Phrases2.Lookup('AITSTAT',i),pkAITStat,i)716 end717 end;718 719 procedure DecodeItem(s: string; var Category, Index: integer);720 var721 i: integer;722 begin723 if (length(s)>0) and (s[1]=':') then724 begin725 Category:=hkMisc;726 Index:=0;727 for i:=3 to Length(s) do Index:=Index*10+ord(s[i])-48;728 case s[2] of729 'A': Category:=hkAdv;730 'B': Category:=hkImp;731 'T': Category:=hkTer;732 'F': Category:=hkFeature;733 'E': Category:=hkInternet;734 'S': Category:=hkModel;735 'C': Index:=miscCredits;736 'J': Index:=miscJobList;737 'G': Index:=miscGovList;738 end;739 if (Category<>hkMisc) and (Index=0) then740 Index:=200;741 end742 else743 begin744 Category:=hkText;745 Index:=HelpText.GetHandle(copy(s,1,255));746 end;747 end;748 749 procedure AddText(s: string);750 var751 i,p,l,ofs,CurrentFormat,FollowFormat,Picpix,LinkCategory,LinkIndex,RightMargin: integer;752 Name: string;753 begin754 RightMargin:=InnerWidth-16-GetSystemMetrics(SM_CXVSCROLL);755 FollowFormat:=pkNormal;756 while s<>'' do757 begin758 Picpix:=0;759 LinkCategory:=0;760 LinkIndex:=0;761 if s[1]='$' then762 begin // window caption763 p:=1;764 repeat inc(p) until (p>Length(s)) or (s[p]='\');765 Caption:=Copy(s,2,p-2);766 Delete(s,1,p);767 end768 else if s[1]='&' then769 begin // standard block770 p:=1;771 repeat inc(p) until (p>Length(s)) or (s[p]='\');772 AddStandardBlock(Copy(s,2,p-2));773 Delete(s,1,p);774 end775 else if s[1]='@' then776 begin // image777 if (Length(s)>=2) and (s[2]='@') then778 begin // generate from icon779 Picpix:=0;780 p:=3;781 while (p<=Length(s)) and (s[p]<>'\') do782 begin Picpix:=Picpix*10+ord(s[p])-48; inc(p) end;783 if (Picpix<0) or (Picpix>=nImp) then Picpix:=0;784 MainText.AddLine('',pkIllu,Picpix);785 MainText.LF;786 MainText.LF;787 end788 else789 begin // external image790 p:=1;791 repeat inc(p) until (p>Length(s)) or (s[p]='\');792 if LoadLocalizedGraphicFile(ExtPic, 'Help\'+Copy(s,2,p-2)) then793 begin794 MainText.AddLine('',pkExternal);795 for i:=0 to (ExtPic.Height-12) div 24 do MainText.LF;796 end;797 end;798 Delete(s,1,p);799 end800 else801 begin802 case s[1] of803 ':',';':804 begin // link805 p:=1;806 repeat inc(p) until (p>Length(s)) or (s[p]='\') or (s[p]=' ');807 DecodeItem(copy(s,2,p-2), LinkCategory, LinkIndex);808 CurrentFormat:=0;809 if (LinkCategory<>hkText) and (LinkIndex<200) then // show icon810 case LinkCategory of811 hkAdv:812 begin CurrentFormat:=pkAdvIcon; Picpix:=LinkIndex end;813 hkImp:814 begin CurrentFormat:=pkSmallIcon; Picpix:=LinkIndex end;815 hkTer:816 begin CurrentFormat:=pkTer; Picpix:=LinkIndex end;817 hkFeature:818 begin CurrentFormat:=pkFeature; Picpix:=LinkIndex end;819 hkModel:820 begin821 CurrentFormat:=pkModel;822 FindStdModelPicture(SpecialModelPictureCode[LinkIndex],Picpix,Name);823 end;824 end;825 if s[1]=':' then LinkCategory:=LinkCategory+hkCrossLink;826 if (p>Length(s)) or (s[p]=' ') then Delete(s,1,p)827 else Delete(s,1,p-1)828 end;829 '!': // highlited830 if (length(s)>=2) and (s[2]='!') then831 begin832 if MainText.Count>1 then MainText.LF;833 FollowFormat:=pkCaption;834 CurrentFormat:=pkCaption;835 Delete(s,1,2);836 end837 else838 begin839 FollowFormat:=pkSection;840 CurrentFormat:=pkSection;841 Delete(s,1,1);842 end;843 '-':844 begin // list845 FollowFormat:=pkNormal_Dot;846 CurrentFormat:=pkDot;847 Delete(s,1,1);848 end;849 else CurrentFormat:=FollowFormat;850 end;851 if FollowFormat=pkNormal_Dot then ofs:=20+4+8852 else ofs:=8;853 p:=0;854 repeat855 repeat inc(p) until (p>Length(s)) or (s[p]=' ') or (s[p]='\');856 if (BiColorTextWidth(Offscreen.Canvas,Copy(s,1,p-1))<=RightMargin-ofs) then857 l:=p-1858 else Break;859 until (p>=Length(s)) or (s[l+1]='\');860 MainText.AddLine(Copy(s,1,l),CurrentFormat,Picpix,LinkCategory,LinkIndex);861 if (l<Length(s)) and (s[l+1]='\') then FollowFormat:=pkNormal;862 Delete(s,1,l+1);863 end864 end865 end;866 1050 867 1051 procedure AddItem(Item: string); 868 1052 begin 869 AddText(HelpText.Lookup(Item));1053 AddText(HelpText.Lookup(Item)); 870 1054 end; 871 1055 872 1056 procedure AddModelText(i: integer); 873 1057 var 874 pix: integer; 875 s: string; 876 begin 877 with MainText do 878 begin 879 if Count>1 then begin LF; LF; end; 880 FindStdModelPicture(SpecialModelPictureCode[i],pix,s); 881 AddLine(s,pkSection); 882 AddLine(Format(HelpText.Lookup('STRENGTH'), 883 [SpecialModel[i].Attack,SpecialModel[i].Defense]),pkNormal_64); 884 AddLine(Format(HelpText.Lookup('SPEED'), 885 [MovementToString(SpecialModel[i].Speed)]),pkModel,pix); 886 if Difficulty=0 then 887 AddLine(Format(HelpText.Lookup('BUILDCOST'), 888 [SpecialModel[i].Cost]),pkNormal_64) 889 else AddLine(Format(HelpText.Lookup('BUILDCOST'), 890 [SpecialModel[i].Cost*BuildCostMod[Difficulty] div 12]),pkNormal_64); 891 s:=HelpText.LookupByHandle(hSPECIALMODEL,i); 892 if (s<>'') and (s<>'*') then AddText(s); 893 if SpecialModelPreq[i]>=0 then AddPreqAdv(SpecialModelPreq[i]) 894 else if SpecialModelPreq[i]=preLighthouse then AddPreqImp(woLighthouse) 895 else if SpecialModelPreq[i]=preBuilder then AddPreqImp(woPyramids) 896 else if SpecialModelPreq[i]=preLeo then AddPreqImp(woLeo); 897 if SpecialModelPreq[i]<>preNone then 898 MainText[Count-1]:=Format(HelpText.Lookup('REQUIRED'),[MainText[Count-1]]); 1058 pix: integer; 1059 s: string; 1060 begin 1061 with MainText do 1062 begin 1063 if Count > 1 then 1064 begin 1065 LF; 1066 LF; 1067 end; 1068 FindStdModelPicture(SpecialModelPictureCode[i], pix, s); 1069 AddLine(s, pkSection); 1070 AddLine(Format(HelpText.Lookup('STRENGTH'), [SpecialModel[i].Attack, 1071 SpecialModel[i].Defense]), pkNormal_64); 1072 AddLine(Format(HelpText.Lookup('SPEED'), 1073 [MovementToString(SpecialModel[i].Speed)]), pkModel, pix); 1074 if Difficulty = 0 then 1075 AddLine(Format(HelpText.Lookup('BUILDCOST'), [SpecialModel[i].Cost]), 1076 pkNormal_64) 1077 else 1078 AddLine(Format(HelpText.Lookup('BUILDCOST'), 1079 [SpecialModel[i].Cost * BuildCostMod[Difficulty] div 12]), 1080 pkNormal_64); 1081 s := HelpText.LookupByHandle(hSPECIALMODEL, i); 1082 if (s <> '') and (s <> '*') then 1083 AddText(s); 1084 if SpecialModelPreq[i] >= 0 then 1085 AddPreqAdv(SpecialModelPreq[i]) 1086 else if SpecialModelPreq[i] = preLighthouse then 1087 AddPreqImp(woLighthouse) 1088 else if SpecialModelPreq[i] = preBuilder then 1089 AddPreqImp(woPyramids) 1090 else if SpecialModelPreq[i] = preLeo then 1091 AddPreqImp(woLeo); 1092 if SpecialModelPreq[i] <> preNone then 1093 MainText[Count - 1] := Format(HelpText.Lookup('REQUIRED'), 1094 [MainText[Count - 1]]); 899 1095 end 900 1096 end; … … 902 1098 procedure AddJobList; 903 1099 var 904 i,JobCost: integer;905 begin 906 with MainText do907 begin 908 for i:=0 to nJobHelp-1 do1100 i, JobCost: integer; 1101 begin 1102 with MainText do 1103 begin 1104 for i := 0 to nJobHelp - 1 do 909 1105 begin 910 if i>0 then begin LF; LF end; 911 AddLine(Phrases.Lookup('JOBRESULT',JobHelp[i]),pkSection); 912 AddLine; 913 AddLine('',pkTerImp,i); 914 AddLine; 915 AddText(HelpText.LookupByHandle(hJOBHELP,i)); 916 JobCost:=-1; 917 case JobHelp[i] of 918 jCanal: JobCost:=CanalWork; 919 jFort: JobCost:=FortWork; 920 jBase: JobCost:=BaseWork; 1106 if i > 0 then 1107 begin 1108 LF; 1109 LF 921 1110 end; 922 if JobCost>=0 then 923 AddText(Format(HelpText.Lookup('JOBCOST'),[MovementToString(JobCost)])) 924 else AddText(HelpText.Lookup('JOBCOSTVAR')); 925 if JobPreq[JobHelp[i]]<>preNone then 1111 AddLine(Phrases.Lookup('JOBRESULT', JobHelp[i]), pkSection); 1112 AddLine; 1113 AddLine('', pkTerImp, i); 1114 AddLine; 1115 AddText(HelpText.LookupByHandle(hJOBHELP, i)); 1116 JobCost := -1; 1117 case JobHelp[i] of 1118 jCanal: 1119 JobCost := CanalWork; 1120 jFort: 1121 JobCost := FortWork; 1122 jBase: 1123 JobCost := BaseWork; 1124 end; 1125 if JobCost >= 0 then 1126 AddText(Format(HelpText.Lookup('JOBCOST'), 1127 [MovementToString(JobCost)])) 1128 else 1129 AddText(HelpText.Lookup('JOBCOSTVAR')); 1130 if JobPreq[JobHelp[i]] <> preNone then 926 1131 begin 927 AddPreqAdv(JobPreq[JobHelp[i]]); 928 MainText[Count-1]:=Format(HelpText.Lookup('REQUIRED'),[MainText[Count-1]]); 1132 AddPreqAdv(JobPreq[JobHelp[i]]); 1133 MainText[Count - 1] := Format(HelpText.Lookup('REQUIRED'), 1134 [MainText[Count - 1]]); 929 1135 end 930 1136 end; … … 934 1140 procedure AddGraphicCredits; 935 1141 var 936 i: integer; 937 s: string; 938 sr: TSearchRec; 939 List, plus: tstringlist; 940 begin 941 List:=tstringlist.Create; 942 plus:=tstringlist.Create; 943 if FindFirst(HomeDir+'Graphics\*.credits.txt',$27,sr)=0 then 944 repeat 945 plus.LoadFromFile(HomeDir+'Graphics\'+sr.Name); 946 List.AddStrings(plus); 947 until FindNext(sr)<>0; 948 FindClose(sr); 949 plus.Free; 950 951 List.Sort; 952 i:=1; 953 while i<List.Count do 954 if List[i]=List[i-1] then List.Delete(i) 955 else inc(i); 956 957 for i:=0 to List.Count-1 do 958 begin 959 s:=List[i]; 960 while BiColorTextWidth(Offscreen.Canvas,s)>InnerWidth-16 961 -GetSystemMetrics(SM_CXVSCROLL) do 962 Delete(s,Length(s),1); 963 MainText.AddLine(s); 1142 i: integer; 1143 s: string; 1144 sr: TSearchRec; 1145 List, plus: TStringList; 1146 begin 1147 List := TStringList.Create; 1148 plus := TStringList.Create; 1149 if FindFirst(HomeDir + 'Graphics\*.credits.txt', $27, sr) = 0 then 1150 repeat 1151 plus.LoadFromFile(HomeDir + 'Graphics\' + sr.Name); 1152 List.AddStrings(plus); 1153 until FindNext(sr) <> 0; 1154 FindClose(sr); 1155 plus.Free; 1156 1157 List.Sort; 1158 i := 1; 1159 while i < List.Count do 1160 if List[i] = List[i - 1] then 1161 List.Delete(i) 1162 else 1163 inc(i); 1164 1165 for i := 0 to List.Count - 1 do 1166 begin 1167 s := List[i]; 1168 while BiColorTextWidth(OffScreen.Canvas, s) > InnerWidth - 16 - 1169 GetSystemMetrics(SM_CXVSCROLL) do 1170 Delete(s, length(s), 1); 1171 MainText.AddLine(s); 964 1172 end; 965 List.Free;1173 List.Free; 966 1174 end; 967 1175 968 1176 procedure AddSoundCredits; 969 1177 var 970 i: integer;971 s: string;972 List: tstringlist;973 begin 974 List:=tstringlist.Create;975 List.LoadFromFile(HomeDir+'Sounds\sound.credits.txt');976 for i:=0 to List.Count-1 do977 begin 978 s:=List[i];979 while BiColorTextWidth(Offscreen.Canvas,s)>InnerWidth-16980 -GetSystemMetrics(SM_CXVSCROLL) do981 Delete(s,Length(s),1);982 MainText.AddLine(s);1178 i: integer; 1179 s: string; 1180 List: TStringList; 1181 begin 1182 List := TStringList.Create; 1183 List.LoadFromFile(HomeDir + 'Sounds\sound.credits.txt'); 1184 for i := 0 to List.Count - 1 do 1185 begin 1186 s := List[i]; 1187 while BiColorTextWidth(OffScreen.Canvas, s) > InnerWidth - 16 - 1188 GetSystemMetrics(SM_CXVSCROLL) do 1189 Delete(s, length(s), 1); 1190 MainText.AddLine(s); 983 1191 end; 984 List.Free;1192 List.Free; 985 1193 end; 986 1194 987 1195 procedure NextSection(Item: string); 988 1196 begin 989 if MainText.Count>1 then 990 if MainText.Count=Headline+1 then MainText.Delete(Headline) 991 else MainText.LF; 992 MainText.AddLine(HelpText.Lookup(Item),pkSection); 993 Headline:=MainText.Count-1; 994 end; 995 996 begin {Prepare} 997 with MainText do 998 begin 999 offscreen.Canvas.Font.Assign(UniFont[ftNormal]); 1000 CheckSeeAlso:=false; 1001 Clear; 1002 Headline:=-1; 1003 if (no>=200) or not (Kind in [hkAdv,hkImp,hkTer,hkFeature]) then 1004 LF; 1005 case Kind of 1006 hkText: AddText(HelpText.LookupByHandle(no)); 1007 hkMisc: 1008 begin 1009 case no of 1010 miscMain: 1197 if MainText.Count > 1 then 1198 if MainText.Count = Headline + 1 then 1199 MainText.Delete(Headline) 1200 else 1201 MainText.LF; 1202 MainText.AddLine(HelpText.Lookup(Item), pkSection); 1203 Headline := MainText.Count - 1; 1204 end; 1205 1206 begin { Prepare } 1207 with MainText do 1208 begin 1209 OffScreen.Canvas.Font.Assign(UniFont[ftNormal]); 1210 CheckSeeAlso := false; 1211 Clear; 1212 Headline := -1; 1213 if (no >= 200) or not(Kind in [hkAdv, hkImp, hkTer, hkFeature]) then 1214 LF; 1215 case Kind of 1216 hkText: 1217 AddText(HelpText.LookupByHandle(no)); 1218 hkMisc: 1219 begin 1220 case no of 1221 miscMain: 1222 begin 1223 Caption := HelpText.Lookup('HELPTITLE_MAIN'); 1224 AddLine(HelpText.Lookup('HELPTITLE_QUICKSTART'), pkSpecialIcon, 1225 0, { pkBigIcon,22, } hkText, HelpText.Gethandle('QUICK')); 1226 LF; 1227 AddLine(HelpText.Lookup('HELPTITLE_CONCEPTS'), pkBigIcon, 6, 1228 hkText, HelpText.Gethandle('CONCEPTS')); 1229 LF; 1230 AddLine(HelpText.Lookup('HELPTITLE_TERLIST'), pkSpecialIcon, 1, 1231 hkTer, 200); 1232 LF; 1233 AddLine(HelpText.Lookup('HELPTITLE_JOBLIST'), pkSpecialIcon, 2, 1234 hkMisc, miscJobList); 1235 LF; 1236 AddLine(HelpText.Lookup('HELPTITLE_TECHLIST'), pkBigIcon, 39, 1237 hkAdv, 200); 1238 LF; 1239 FindStdModelPicture(SpecialModelPictureCode[6], i, s); 1240 AddLine(HelpText.Lookup('HELPTITLE_MODELLIST'), pkModel, i, 1241 hkModel, 0); 1242 LF; 1243 AddLine(HelpText.Lookup('HELPTITLE_FEATURELIST'), pkBigIcon, 28, 1244 hkFeature, 200); 1245 LF; 1246 AddLine(HelpText.Lookup('HELPTITLE_IMPLIST'), pkBigIcon, 1247 7 * SystemIconLines + imCourt, hkImp, 200); 1248 LF; 1249 AddLine(HelpText.Lookup('HELPTITLE_UNIQUELIST'), pkBigIcon, 1250 7 * SystemIconLines + imStockEx, hkImp, 201); 1251 LF; 1252 AddLine(HelpText.Lookup('HELPTITLE_WONDERLIST'), pkBigIcon, 1253 7 * SystemIconLines, hkImp, 202); 1254 LF; 1255 AddLine(HelpText.Lookup('HELPTITLE_GOVLIST'), pkBigIcon, 1256 gDemocracy + 6, hkMisc, miscGovList); 1257 LF; 1258 AddLine(HelpText.Lookup('HELPTITLE_KEYS'), pkBigIcon, 2, hkText, 1259 HelpText.Gethandle('HOTKEYS')); 1260 LF; 1261 AddLine(HelpText.Lookup('HELPTITLE_ABOUT'), pkBigIcon, 1, 1262 hkText, HelpText.Gethandle('ABOUT')); 1263 LF; 1264 AddLine(HelpText.Lookup('HELPTITLE_CREDITS'), pkBigIcon, 22, 1265 hkMisc, miscCredits); 1266 end; 1267 miscCredits: 1268 begin 1269 AddItem('CREDITS'); 1270 LF; 1271 AddGraphicCredits; 1272 NextSection('CRED_CAPSOUND'); 1273 AddSoundCredits; 1274 NextSection('CRED_CAPAI'); 1275 Server(sGetAICredits, 0, 0, ps); 1276 AddText(ps); 1277 NextSection('CRED_CAPLANG'); 1278 AddItem('AUTHOR'); 1279 end; 1280 miscJobList: 1281 begin 1282 Caption := HelpText.Lookup('HELPTITLE_JOBLIST'); 1283 AddJobList; 1284 LF; 1285 AddItem('TERIMPEXCLUDE'); 1286 LF; 1287 AddItem('TERIMPCITY'); 1288 end; 1289 miscGovList: 1290 begin 1291 Caption := HelpText.Lookup('HELPTITLE_GOVLIST'); 1292 for i := 1 to nGov do 1293 begin 1294 AddLine(Phrases.Lookup('GOVERNMENT', i mod nGov), pkSection); 1295 LF; 1296 if i = nGov then 1297 AddLine('', pkBigIcon, 7 * SystemIconLines + imPalace) 1298 else 1299 AddLine('', pkBigIcon, i + 6); 1300 LF; 1301 AddText(HelpText.LookupByHandle(hGOVHELP, i mod nGov)); 1302 if i mod nGov >= 2 then 1303 begin 1304 AddPreqAdv(GovPreq[i mod nGov]); 1305 MainText[Count - 1] := Format(HelpText.Lookup('REQUIRED'), 1306 [MainText[Count - 1]]); 1307 end; 1308 if i < nGov then 1309 begin 1310 LF; 1311 LF; 1312 end 1313 end 1314 end; 1315 miscSearchResult: 1316 begin 1317 Caption := HelpText.Lookup('HELPTITLE_SEARCHRESULTS'); 1318 AddText(Format(HelpText.Lookup('MATCHES'), [SearchContent])); 1319 MainText.AddStrings(SearchResult); 1320 end 1321 end; // case no 1322 end; 1323 1324 hkAdv: 1325 if no = 200 then 1326 begin // complete advance list 1327 Caption := HelpText.Lookup('HELPTITLE_TECHLIST'); 1328 List := THyperText.Create; 1329 for j := 0 to 3 do 1011 1330 begin 1012 Caption:=HelpText.Lookup('HELPTITLE_MAIN'); 1013 AddLine(HelpText.Lookup('HELPTITLE_QUICKSTART'),pkSpecialIcon,0,{pkBigIcon,22,}hkText,HelpText.GetHandle('QUICK')); LF; 1014 AddLine(HelpText.Lookup('HELPTITLE_CONCEPTS'),pkBigIcon,6,hkText,HelpText.GetHandle('CONCEPTS')); LF; 1015 AddLine(HelpText.Lookup('HELPTITLE_TERLIST'),pkSpecialIcon,1,hkTer,200); LF; 1016 AddLine(HelpText.Lookup('HELPTITLE_JOBLIST'),pkSpecialIcon,2,hkMisc,miscJobList); LF; 1017 AddLine(HelpText.Lookup('HELPTITLE_TECHLIST'),pkBigIcon,39,hkAdv,200); LF; 1018 FindStdModelPicture(SpecialModelPictureCode[6],i,s); 1019 AddLine(HelpText.Lookup('HELPTITLE_MODELLIST'),pkModel,i,hkModel,0); LF; 1020 AddLine(HelpText.Lookup('HELPTITLE_FEATURELIST'),pkBigIcon,28,hkFeature,200); LF; 1021 AddLine(HelpText.Lookup('HELPTITLE_IMPLIST'),pkBigIcon,7*SystemIconLines+imCourt,hkImp,200); LF; 1022 AddLine(HelpText.Lookup('HELPTITLE_UNIQUELIST'),pkBigIcon,7*SystemIconLines+imStockEx,hkImp,201); LF; 1023 AddLine(HelpText.Lookup('HELPTITLE_WONDERLIST'),pkBigIcon,7*SystemIconLines,hkImp,202); LF; 1024 AddLine(HelpText.Lookup('HELPTITLE_GOVLIST'),pkBigIcon,gDemocracy+6,hkMisc,miscGovList); LF; 1025 AddLine(HelpText.Lookup('HELPTITLE_KEYS'),pkBigIcon,2,hkText,HelpText.GetHandle('HOTKEYS')); LF; 1026 AddLine(HelpText.Lookup('HELPTITLE_ABOUT'),pkBigIcon,1,hkText,HelpText.GetHandle('ABOUT')); LF; 1027 AddLine(HelpText.Lookup('HELPTITLE_CREDITS'),pkBigIcon,22,hkMisc,miscCredits); 1331 if j > 0 then 1332 begin 1333 LF; 1334 LF; 1335 end; 1336 AddLine(HelpText.Lookup('TECHAGE', j), pkSection); 1337 if j = 1 then 1338 AddLine(Phrases.Lookup('ADVANCES', adScience) + ' ' + 1339 HelpText.Lookup('BASETECH'), pkAdvIcon, adScience, hkAdv, 1340 adScience); 1341 if j = 2 then 1342 AddLine(Phrases.Lookup('ADVANCES', adMassProduction) + ' ' + 1343 HelpText.Lookup('BASETECH'), pkAdvIcon, adMassProduction, hkAdv, 1344 adMassProduction); 1345 List.Clear; 1346 for i := 0 to nAdv - 1 do 1347 if (i <> adScience) and (i <> adMassProduction) and 1348 (AdvValue[i] div 1000 = j) then 1349 List.AddLine(Phrases.Lookup('ADVANCES', i), pkAdvIcon, i, 1350 hkAdv, i); 1351 List.Sort; 1352 AddStrings(List); 1028 1353 end; 1029 miscCredits: 1354 List.Free 1355 end 1356 else // single advance 1357 begin 1358 Caption := Phrases.Lookup('ADVANCES', no); 1359 LF; 1360 AddLine(Phrases.Lookup('ADVANCES', no), pkCaption); 1361 if no in FutureTech then 1030 1362 begin 1031 AddItem('CREDITS'); 1032 LF; 1033 AddGraphicCredits; 1034 NextSection('CRED_CAPSOUND'); 1035 AddSoundCredits; 1036 NextSection('CRED_CAPAI'); 1037 Server(sGetAICredits,0,0,ps); 1038 AddText(ps); 1039 NextSection('CRED_CAPLANG'); 1040 AddItem('AUTHOR'); 1041 end; 1042 miscJobList: 1043 begin 1044 Caption:=HelpText.Lookup('HELPTITLE_JOBLIST'); 1045 AddJobList; 1046 LF; 1047 AddItem('TERIMPEXCLUDE'); 1048 LF; 1049 AddItem('TERIMPCITY'); 1050 end; 1051 miscGovList: 1052 begin 1053 Caption:=HelpText.Lookup('HELPTITLE_GOVLIST'); 1054 for i:=1 to nGov do 1055 begin 1056 AddLine(Phrases.Lookup('GOVERNMENT',i mod nGov),pkSection); 1363 AddLine(HelpText.Lookup('HELPSPEC_FUTURE')); 1057 1364 LF; 1058 if i=nGov then 1059 AddLine('',pkBigIcon,7*SystemIconLines+imPalace) 1060 else AddLine('',pkBigIcon,i+6); 1061 LF; 1062 AddText(HelpText.LookupByHandle(hGOVHELP,i mod nGov)); 1063 if i mod nGov>=2 then 1365 if no = futResearchTechnology then 1366 AddItem('FUTURETECHHELP100') 1367 else 1368 AddItem('FUTURETECHHELP25'); 1369 end 1370 else 1371 AddLine(HelpText.Lookup('HELPSPEC_ADV')); 1372 if AdvPreq[no, 2] <> preNone then 1373 NextSection('PREREQALT') 1374 else 1375 NextSection('PREREQ'); 1376 for i := 0 to 2 do 1377 if AdvPreq[no, i] <> preNone then 1378 AddPreqAdv(AdvPreq[no, i]); 1379 NextSection('GOVALLOW'); 1380 for i := 2 to nGov - 1 do 1381 if GovPreq[i] = no then 1382 AddLine(Phrases.Lookup('GOVERNMENT', i), pkGov, i, 1383 hkMisc + hkCrossLink, miscGovList); 1384 NextSection('BUILDALLOW'); 1385 for i := 0 to 27 do 1386 if Imp[i].Preq = no then 1387 AddImp(i); 1388 for i := 28 to nImp - 1 do 1389 if (Imp[i].Preq = no) and (Imp[i].Kind <> ikCommon) then 1390 AddImp(i); 1391 for i := 28 to nImp - 1 do 1392 if (Imp[i].Preq = no) and (Imp[i].Kind = ikCommon) then 1393 AddImp(i); 1394 NextSection('MODELALLOW'); 1395 for i := 0 to nSpecialModel - 1 do 1396 if SpecialModelPreq[i] = no then 1397 AddModel(i); 1398 NextSection('FEATALLOW'); 1399 for i := 0 to nFeature - 1 do 1400 if Feature[i].Preq = no then 1401 AddFeature(i); 1402 NextSection('FOLLOWADV'); 1403 for i := 0 to nAdv - 1 do 1404 if (AdvPreq[i, 0] = no) or (AdvPreq[i, 1] = no) or 1405 (AdvPreq[i, 2] = no) then 1406 AddAdv(i); 1407 NextSection('UPGRADEALLOW'); 1408 for Domain := 0 to nDomains - 1 do 1409 for i := 1 to nUpgrade - 1 do 1410 if upgrade[Domain, i].Preq = no then 1064 1411 begin 1065 AddPreqAdv(GovPreq[i mod nGov]); 1066 MainText[Count-1]:=Format(HelpText.Lookup('REQUIRED'),[MainText[Count-1]]); 1412 if upgrade[Domain, i].Strength > 0 then 1413 AddLine(Format(HelpText.Lookup('STRENGTHUP'), 1414 [Phrases.Lookup('DOMAIN', Domain), upgrade[Domain, 1415 i].Strength]), pkDomain, Domain); 1416 if upgrade[Domain, i].Trans > 0 then 1417 AddLine(Format(HelpText.Lookup('TRANSUP'), 1418 [Phrases.Lookup('DOMAIN', Domain), upgrade[Domain, i].Trans] 1419 ), pkDomain, Domain); 1420 if no in FutureTech then 1421 AddLine(Format(HelpText.Lookup('COSTUP'), 1422 [upgrade[Domain, i].Cost]), pkNormal_Dot) 1423 else 1424 AddLine(Format(HelpText.Lookup('COSTMIN'), 1425 [upgrade[Domain, i].Cost]), pkNormal_Dot) 1067 1426 end; 1068 if i<nGov then begin LF; LF; end 1069 end 1070 end; 1071 miscSearchResult: 1072 begin 1073 Caption:=HelpText.Lookup('HELPTITLE_SEARCHRESULTS'); 1074 AddText(Format(HelpText.Lookup('MATCHES'), [SearchContent])); 1075 MainText.AddStrings(SearchResult); 1076 end 1077 end; // case no 1078 end; 1079 1080 hkAdv: 1081 if no=200 then 1082 begin // complete advance list 1083 Caption:=HelpText.Lookup('HELPTITLE_TECHLIST'); 1084 List:=THyperText.Create; 1085 for j:=0 to 3 do 1086 begin 1087 if j>0 then begin LF; LF; end; 1088 AddLine(HelpText.Lookup('TECHAGE',j),pkSection); 1089 if j=1 then 1090 AddLine(Phrases.Lookup('ADVANCES',adScience)+' ' 1091 +HelpText.Lookup('BASETECH'), 1092 pkAdvIcon,adScience,hkAdv,adScience); 1093 if j=2 then 1094 AddLine(Phrases.Lookup('ADVANCES',adMassProduction)+' ' 1095 +HelpText.Lookup('BASETECH'), 1096 pkAdvIcon,adMassProduction,hkAdv,adMassProduction); 1097 List.Clear; 1098 for i:=0 to nAdv-1 do 1099 if (i<>adScience) and (i<>adMassProduction) and (AdvValue[i] div 1000=j) then 1100 List.AddLine(Phrases.Lookup('ADVANCES',i),pkAdvIcon,i,hkAdv,i); 1427 NextSection('EXPIRATION'); 1428 for i := 0 to 27 do 1429 if (Imp[i].Preq <> preNA) and (Imp[i].Expiration = no) then 1430 AddImp(i); 1431 NextSection('ADVEFFECT'); 1432 s := HelpText.LookupByHandle(hADVHELP, no); 1433 if s <> '*' then 1434 AddText(s); 1435 NextSection('SEEALSO'); 1436 CheckSeeAlso := true 1437 end; 1438 1439 hkImp: 1440 if no = 200 then 1441 begin // complete city improvement list 1442 Caption := HelpText.Lookup('HELPTITLE_IMPLIST'); 1443 // AddLine(HelpText.Lookup('HELPTITLE_IMPLIST'),pkSection); 1444 List := THyperText.Create; 1445 for i := 28 to nImp - 1 do 1446 if (i <> imTrGoods) and (Imp[i].Preq <> preNA) and 1447 (Imp[i].Kind = ikCommon) then 1448 List.AddLine(Phrases.Lookup('IMPROVEMENTS', i), pkSmallIcon, 1449 i, hkImp, i); 1101 1450 List.Sort; 1102 1451 AddStrings(List); 1452 List.Free 1453 end 1454 else if no = 201 then 1455 begin // complete nat. project list 1456 Caption := HelpText.Lookup('HELPTITLE_UNIQUELIST'); 1457 // AddLine(HelpText.Lookup('HELPTITLE_UNIQUELIST'),pkSection); 1458 for i := 28 to nImp - 1 do 1459 if (Imp[i].Preq <> preNA) and 1460 ((Imp[i].Kind = ikNatLocal) or (Imp[i].Kind = ikNatGlobal)) then 1461 AddLine(Phrases.Lookup('IMPROVEMENTS', i), pkSmallIcon, i, 1462 hkImp, i); 1463 { LF; 1464 LF; 1465 AddLine(HelpText.Lookup('HELPTITLE_SHIPPARTLIST'),pkSection); 1466 for i:=28 to nImp-1 do 1467 if (Imp[i].Preq<>preNA) and (Imp[i].Kind=ikShipPart) then 1468 AddLine(Phrases.Lookup('IMPROVEMENTS',i),pkSmallIcon,i,hkImp,i); } 1469 end 1470 else if no = 202 then 1471 begin // complete wonder list 1472 Caption := HelpText.Lookup('HELPTITLE_WONDERLIST'); 1473 // AddLine(HelpText.Lookup('HELPTITLE_WONDERLIST'),pkSection); 1474 for i := 0 to 27 do 1475 if Imp[i].Preq <> preNA then 1476 AddLine(Phrases.Lookup('IMPROVEMENTS', i), pkSmallIcon, i, 1477 hkImp, i); 1478 end 1479 else 1480 begin // single building 1481 Caption := Phrases.Lookup('IMPROVEMENTS', no); 1482 LF; 1483 AddLine(Phrases.Lookup('IMPROVEMENTS', no), pkRightIcon, no); 1484 case Imp[no].Kind of 1485 ikWonder: 1486 AddLine(HelpText.Lookup('HELPSPEC_WONDER')); 1487 ikCommon: 1488 AddLine(HelpText.Lookup('HELPSPEC_IMP')); 1489 ikShipPart: 1490 AddLine(HelpText.Lookup('HELPSPEC_SHIPPART')); 1491 else 1492 AddLine(HelpText.Lookup('HELPSPEC_NAT')) 1103 1493 end; 1104 List.Free 1494 if Imp[no].Kind <> ikShipPart then 1495 begin 1496 NextSection('EFFECT'); 1497 AddText(HelpText.LookupByHandle(hIMPHELP, no)); 1498 end; 1499 if no = woSun then 1500 begin 1501 AddFeature(mcFirst); 1502 AddFeature(mcWill); 1503 AddFeature(mcAcademy); 1504 end; 1505 if (no < 28) and not Phrases2FallenBackToEnglish then 1506 begin 1507 LF; 1508 if Imp[no].Expiration >= 0 then 1509 AddText(Phrases2.Lookup('HELP_WONDERMORALE1')) 1510 else 1511 AddText(Phrases2.Lookup('HELP_WONDERMORALE2')); 1512 end; 1513 if Imp[no].Preq <> preNone then 1514 begin 1515 NextSection('PREREQ'); 1516 AddPreqAdv(Imp[no].Preq); 1517 end; 1518 NextSection('COSTS'); 1519 if Difficulty = 0 then 1520 s := Format(HelpText.Lookup('BUILDCOST'), [Imp[no].Cost]) 1521 else 1522 s := Format(HelpText.Lookup('BUILDCOST'), 1523 [Imp[no].Cost * BuildCostMod[Difficulty] div 12]); 1524 AddLine(s); 1525 if Imp[no].Maint > 0 then 1526 AddLine(Format(HelpText.Lookup('MAINTCOST'), [Imp[no].Maint])); 1527 j := 0; 1528 for i := 0 to nImpReplacement - 1 do 1529 if ImpReplacement[i].NewImp = no then 1530 begin 1531 if j = 0 then 1532 begin 1533 NextSection('REPLACE'); 1534 AddItem('REPLACETEXT'); 1535 j := 1 1536 end; 1537 AddImp(ImpReplacement[i].OldImp); 1538 end; 1539 if Imp[no].Kind = ikShipPart then 1540 begin 1541 LF; 1542 if no = imShipComp then 1543 i := 1 1544 else if no = imShipPow then 1545 i := 2 1546 else { if no=imShipHab then } 1547 i := 3; 1548 AddLine(Format(HelpText.Lookup('RAREREQUIRED'), 1549 [Phrases.Lookup('TERRAIN', 3 * 12 + i)]), pkTer, 3 * 12 + i); 1550 end; 1551 if (no < 28) and (Imp[no].Expiration >= 0) then 1552 begin 1553 NextSection('EXPIRATION'); 1554 s := Format(HelpText.Lookup('EXPWITH'), 1555 [Phrases.Lookup('ADVANCES', Imp[no].Expiration)]); 1556 if no = woPyramids then 1557 s := s + ' ' + HelpText.Lookup('EXPSLAVE'); 1558 AddText(s); 1559 end; 1560 NextSection('SEEALSO'); 1561 if (no < 28) and (Imp[no].Expiration >= 0) then 1562 AddImp(woEiffel); 1563 for i := 0 to nImpReplacement - 1 do 1564 if ImpReplacement[i].OldImp = no then 1565 AddImp(ImpReplacement[i].NewImp); 1566 if no = imSupermarket then 1567 AddLine(HelpText.Lookup('HELPTITLE_JOBLIST'), pkNormal, 0, 1568 hkMisc + hkCrossLink, miscJobList); 1569 CheckSeeAlso := true 1570 end; 1571 1572 hkTer: 1573 if no = 200 then 1574 begin // complete terrain type list 1575 Caption := HelpText.Lookup('HELPTITLE_TERLIST'); 1576 // AddLine(HelpText.Lookup('HELPTITLE_TERLIST'),pkSection); 1577 for i := 0 to nTerrainHelp - 1 do 1578 AddTer(TerrainHelp[i]); 1105 1579 end 1106 else // single advance 1107 begin 1108 Caption:=Phrases.Lookup('ADVANCES',no); 1109 LF; 1110 AddLine(Phrases.Lookup('ADVANCES',no),pkCaption); 1111 if no in FutureTech then 1580 else 1581 begin // sigle terrain type 1582 TerrType := no mod 12; 1583 if TerrType = fJungle then 1584 TerrType := fForest; 1585 TerrSubType := no div 12; 1586 if no = 3 * 12 then 1112 1587 begin 1113 AddLine(HelpText.Lookup('HELPSPEC_FUTURE')); 1114 LF; 1115 if no=futResearchTechnology then 1116 AddItem('FUTURETECHHELP100') 1117 else AddItem('FUTURETECHHELP25'); 1118 end 1119 else AddLine(HelpText.Lookup('HELPSPEC_ADV')); 1120 if AdvPreq[no,2]<>preNone then NextSection('PREREQALT') 1121 else NextSection('PREREQ'); 1122 for i:=0 to 2 do 1123 if AdvPreq[no,i]<>preNone then AddPreqAdv(AdvPreq[no,i]); 1124 NextSection('GOVALLOW'); 1125 for i:=2 to nGov-1 do 1126 if GovPreq[i]=no then 1127 AddLine(Phrases.Lookup('GOVERNMENT',i),pkGov,i, 1128 hkMisc+hkCrossLink,miscGovList); 1129 NextSection('BUILDALLOW'); 1130 for i:=0 to 27 do 1131 if Imp[i].Preq=no then AddImp(i); 1132 for i:=28 to nImp-1 do 1133 if (Imp[i].Preq=no) and (Imp[i].Kind<>ikCommon) then AddImp(i); 1134 for i:=28 to nImp-1 do 1135 if (Imp[i].Preq=no) and (Imp[i].Kind=ikCommon) then AddImp(i); 1136 NextSection('MODELALLOW'); 1137 for i:=0 to nSpecialModel-1 do 1138 if SpecialModelPreq[i]=no then AddModel(i); 1139 NextSection('FEATALLOW'); 1140 for i:=0 to nFeature-1 do if Feature[i].Preq=no then AddFeature(i); 1141 NextSection('FOLLOWADV'); 1142 for i:=0 to nAdv-1 do 1143 if (AdvPreq[i,0]=no) or (AdvPreq[i,1]=no) or (AdvPreq[i,2]=no) then 1144 AddAdv(i); 1145 NextSection('UPGRADEALLOW'); 1146 for Domain:=0 to nDomains-1 do for i:=1 to nUpgrade-1 do 1147 if upgrade[Domain,i].Preq=no then 1148 begin 1149 if upgrade[Domain,i].Strength>0 then 1150 AddLine(Format(HelpText.Lookup('STRENGTHUP'), 1151 [Phrases.Lookup('DOMAIN',Domain),upgrade[Domain,i].Strength]), 1152 pkDomain,Domain); 1153 if upgrade[Domain,i].Trans>0 then 1154 AddLine(Format(HelpText.Lookup('TRANSUP'), 1155 [Phrases.Lookup('DOMAIN',Domain),upgrade[Domain,i].Trans]), 1156 pkDomain,Domain); 1157 if no in FutureTech then 1158 AddLine(Format(HelpText.Lookup('COSTUP'), 1159 [upgrade[Domain,i].Cost]),pkNormal_Dot) 1160 else 1161 AddLine(Format(HelpText.Lookup('COSTMIN'), 1162 [upgrade[Domain,i].Cost]),pkNormal_Dot) 1163 end; 1164 NextSection('EXPIRATION'); 1165 for i:=0 to 27 do 1166 if (Imp[i].Preq<>preNA) and (Imp[i].Expiration=no) then AddImp(i); 1167 NextSection('ADVEFFECT'); 1168 s:=HelpText.LookupByHandle(hADVHELP,no); 1169 if s<>'*' then AddText(s); 1170 NextSection('SEEALSO'); 1171 CheckSeeAlso:=true 1172 end; 1173 1174 hkImp: 1175 if no=200 then 1176 begin // complete city improvement list 1177 Caption:=HelpText.Lookup('HELPTITLE_IMPLIST'); 1178 // AddLine(HelpText.Lookup('HELPTITLE_IMPLIST'),pkSection); 1179 List:=THyperText.Create; 1180 for i:=28 to nImp-1 do 1181 if (i<>imTrGoods) and (Imp[i].Preq<>preNA) and (Imp[i].Kind=ikCommon) then 1182 List.AddLine(Phrases.Lookup('IMPROVEMENTS',i),pkSmallIcon,i,hkImp,i); 1183 List.Sort; 1184 AddStrings(List); 1185 List.Free 1186 end 1187 else if no=201 then 1188 begin // complete nat. project list 1189 Caption:=HelpText.Lookup('HELPTITLE_UNIQUELIST'); 1190 // AddLine(HelpText.Lookup('HELPTITLE_UNIQUELIST'),pkSection); 1191 for i:=28 to nImp-1 do 1192 if (Imp[i].Preq<>preNA) 1193 and ((Imp[i].Kind=ikNatLocal) or (Imp[i].Kind=ikNatGlobal)) then 1194 AddLine(Phrases.Lookup('IMPROVEMENTS',i),pkSmallIcon,i,hkImp,i); 1195 { LF; 1196 LF; 1197 AddLine(HelpText.Lookup('HELPTITLE_SHIPPARTLIST'),pkSection); 1198 for i:=28 to nImp-1 do 1199 if (Imp[i].Preq<>preNA) and (Imp[i].Kind=ikShipPart) then 1200 AddLine(Phrases.Lookup('IMPROVEMENTS',i),pkSmallIcon,i,hkImp,i);} 1201 end 1202 else if no=202 then 1203 begin // complete wonder list 1204 Caption:=HelpText.Lookup('HELPTITLE_WONDERLIST'); 1205 // AddLine(HelpText.Lookup('HELPTITLE_WONDERLIST'),pkSection); 1206 for i:=0 to 27 do if Imp[i].Preq<>preNA then 1207 AddLine(Phrases.Lookup('IMPROVEMENTS',i),pkSmallIcon,i,hkImp,i); 1208 end 1209 else 1210 begin // single building 1211 Caption:=Phrases.Lookup('IMPROVEMENTS',no); 1212 LF; 1213 AddLine(Phrases.Lookup('IMPROVEMENTS',no),pkRightIcon,no); 1214 case Imp[no].Kind of 1215 ikWonder: AddLine(HelpText.Lookup('HELPSPEC_WONDER')); 1216 ikCommon: AddLine(HelpText.Lookup('HELPSPEC_IMP')); 1217 ikShipPart: AddLine(HelpText.Lookup('HELPSPEC_SHIPPART')); 1218 else AddLine(HelpText.Lookup('HELPSPEC_NAT')) 1588 TerrType := fDesert; 1589 TerrSubType := 0 1219 1590 end; 1220 if Imp[no].Kind<>ikShipPart then1591 with Terrain[TerrType] do 1221 1592 begin 1222 NextSection('EFFECT'); 1223 AddText(HelpText.LookupByHandle(hIMPHELP,no)); 1224 end; 1225 if no=woSun then 1226 begin 1227 AddFeature(mcFirst); 1228 AddFeature(mcWill); 1229 AddFeature(mcAcademy); 1230 end; 1231 if (no<28) and not Phrases2FallenBackToEnglish then 1232 begin 1233 LF; 1234 if Imp[no].Expiration>=0 then 1235 AddText(Phrases2.Lookup('HELP_WONDERMORALE1')) 1236 else AddText(Phrases2.Lookup('HELP_WONDERMORALE2')); 1237 end; 1238 if Imp[no].Preq<>preNone then 1239 begin 1240 NextSection('PREREQ'); 1241 AddPreqAdv(Imp[no].Preq); 1242 end; 1243 NextSection('COSTS'); 1244 if Difficulty=0 then 1245 s:=Format(HelpText.Lookup('BUILDCOST'),[Imp[no].Cost]) 1246 else s:=Format(HelpText.Lookup('BUILDCOST'), 1247 [Imp[no].Cost*BuildCostMod[Difficulty] div 12]); 1248 AddLine(s); 1249 if Imp[no].Maint>0 then 1250 AddLine(Format(HelpText.Lookup('MAINTCOST'),[Imp[no].Maint])); 1251 j:=0; 1252 for i:=0 to nImpReplacement-1 do if ImpReplacement[i].NewImp=no then 1253 begin 1254 if j=0 then 1255 begin NextSection('REPLACE'); AddItem('REPLACETEXT'); j:=1 end; 1256 AddImp(ImpReplacement[i].OldImp); 1257 end; 1258 if Imp[no].Kind=ikShipPart then 1259 begin 1260 LF; 1261 if no=imShipComp then i:=1 1262 else if no=imShipPow then i:=2 1263 else {if no=imShipHab then} i:=3; 1264 AddLine(Format(HelpText.Lookup('RAREREQUIRED'), 1265 [Phrases.Lookup('TERRAIN',3*12+i)]),pkTer,3*12+i); 1266 end; 1267 if (no<28) and (Imp[no].Expiration>=0) then 1268 begin 1269 NextSection('EXPIRATION'); 1270 s:=Format(HelpText.Lookup('EXPWITH'),[Phrases.Lookup('ADVANCES',Imp[no].Expiration)]); 1271 if no=woPyramids then s:=s+' '+HelpText.Lookup('EXPSLAVE'); 1272 AddText(s); 1273 end; 1274 NextSection('SEEALSO'); 1275 if (no<28) and (Imp[no].Expiration>=0) then AddImp(woEiffel); 1276 for i:=0 to nImpReplacement-1 do if ImpReplacement[i].OldImp=no then 1277 AddImp(ImpReplacement[i].NewImp); 1278 if no=imSupermarket then 1279 AddLine(HelpText.Lookup('HELPTITLE_JOBLIST'),pkNormal,0,hkMisc+hkCrossLink,miscJobList); 1280 CheckSeeAlso:=true 1281 end; 1282 1283 hkTer: 1284 if no=200 then 1285 begin // complete terrain type list 1286 Caption:=HelpText.Lookup('HELPTITLE_TERLIST'); 1287 // AddLine(HelpText.Lookup('HELPTITLE_TERLIST'),pkSection); 1288 for i:=0 to nTerrainHelp-1 do AddTer(TerrainHelp[i]); 1289 end 1290 else 1291 begin // sigle terrain type 1292 TerrType:=no mod 12; 1293 if TerrType=fJungle then TerrType:=fForest; 1294 TerrSubType:=no div 12; 1295 if no=3*12 then 1296 begin TerrType:=fDesert; TerrSubType:=0 end; 1297 with Terrain[TerrType] do 1298 begin 1299 Caption:=Phrases.Lookup('TERRAIN',no); 1300 LF; 1301 AddLine(Phrases.Lookup('TERRAIN',no), pkBigTer, no); 1302 AddLine(HelpText.Lookup('HELPSPEC_TER')); 1303 LF; 1304 if (ProdRes[TerrSubType]>0) or (MineEff>0) then 1305 AddLine(Format(HelpText.Lookup('RESPROD'),[ProdRes[TerrSubType]])); 1306 if (no<3*12) and (MineEff>0) then 1307 MainText[Count-1]:=MainText[Count-1]+' ' 1308 +Format(HelpText.Lookup('MOREMINE'),[MineEff]); 1309 if (FoodRes[TerrSubType]>0) or (IrrEff>0) then 1310 AddLine(Format(HelpText.Lookup('RESFOOD'),[FoodRes[TerrSubType]])); 1311 if (no<3*12) and (IrrEff>0) then 1312 MainText[Count-1]:=MainText[Count-1]+' ' 1313 +Format(HelpText.Lookup('MOREIRR'),[IrrEff]); 1314 if TradeRes[TerrSubType]>0 then 1315 AddLine(Format(HelpText.Lookup('RESTRADE'),[TradeRes[TerrSubType]])); 1316 if Defense>4 then 1317 AddLine(Format(HelpText.Lookup('DEFBONUS'),[(Defense-4)*25])); 1318 if (TerrType>=fGrass) and (TerrType<>fMountains) then 1319 if MoveCost=2 then 1320 AddLine(HelpText.Lookup('MOVEHEAVY')) 1321 else AddLine(HelpText.Lookup('MOVEPLAIN')); 1322 if no=3*12 then 1323 begin 1593 Caption := Phrases.Lookup('TERRAIN', no); 1324 1594 LF; 1325 AddText(HelpText.Lookup('DEADLANDS')); 1326 end; 1327 if (TerrType=fDesert) and (no<>fDesert+12) then 1328 begin 1595 AddLine(Phrases.Lookup('TERRAIN', no), pkBigTer, no); 1596 AddLine(HelpText.Lookup('HELPSPEC_TER')); 1329 1597 LF; 1330 AddText(Format(HelpText.Lookup('HOSTILE'),[DesertThurst])); 1331 end; 1332 if TerrType=fArctic then 1333 begin 1334 LF; 1335 AddText(Format(HelpText.Lookup('HOSTILE'),[ArcticThurst])); 1336 end; 1337 if (no<3*12) and (TransTerrain>=0) then 1338 begin 1339 LF; 1340 i:=TransTerrain; 1341 if (TerrType<>fGrass) and (i<>fGrass) then 1342 i:=i+TerrSubType*12; // trafo to same special resource group 1343 AddLine(Format(HelpText.Lookup('TRAFO'), 1344 [Phrases.Lookup('TERRAIN',i)]),pkTer,i,hkTer+hkCrossLink,i); 1345 if no=fSwamp+12 then 1598 if (ProdRes[TerrSubType] > 0) or (MineEff > 0) then 1599 AddLine(Format(HelpText.Lookup('RESPROD'), 1600 [ProdRes[TerrSubType]])); 1601 if (no < 3 * 12) and (MineEff > 0) then 1602 MainText[Count - 1] := MainText[Count - 1] + ' ' + 1603 Format(HelpText.Lookup('MOREMINE'), [MineEff]); 1604 if (FoodRes[TerrSubType] > 0) or (IrrEff > 0) then 1605 AddLine(Format(HelpText.Lookup('RESFOOD'), 1606 [FoodRes[TerrSubType]])); 1607 if (no < 3 * 12) and (IrrEff > 0) then 1608 MainText[Count - 1] := MainText[Count - 1] + ' ' + 1609 Format(HelpText.Lookup('MOREIRR'), [IrrEff]); 1610 if TradeRes[TerrSubType] > 0 then 1611 AddLine(Format(HelpText.Lookup('RESTRADE'), 1612 [TradeRes[TerrSubType]])); 1613 if Defense > 4 then 1614 AddLine(Format(HelpText.Lookup('DEFBONUS'), 1615 [(Defense - 4) * 25])); 1616 if (TerrType >= fGrass) and (TerrType <> fMountains) then 1617 if MoveCost = 2 then 1618 AddLine(HelpText.Lookup('MOVEHEAVY')) 1619 else 1620 AddLine(HelpText.Lookup('MOVEPLAIN')); 1621 if no = 3 * 12 then 1622 begin 1623 LF; 1624 AddText(HelpText.Lookup('DEADLANDS')); 1625 end; 1626 if (TerrType = fDesert) and (no <> fDesert + 12) then 1627 begin 1628 LF; 1629 AddText(Format(HelpText.Lookup('HOSTILE'), [DesertThurst])); 1630 end; 1631 if TerrType = fArctic then 1632 begin 1633 LF; 1634 AddText(Format(HelpText.Lookup('HOSTILE'), [ArcticThurst])); 1635 end; 1636 if (no < 3 * 12) and (TransTerrain >= 0) then 1637 begin 1638 LF; 1639 i := TransTerrain; 1640 if (TerrType <> fGrass) and (i <> fGrass) then 1641 i := i + TerrSubType * 12; 1642 // trafo to same special resource group 1643 AddLine(Format(HelpText.Lookup('TRAFO'), 1644 [Phrases.Lookup('TERRAIN', i)]), pkTer, i, 1645 hkTer + hkCrossLink, i); 1646 if no = fSwamp + 12 then 1346 1647 begin 1648 LF; 1649 AddLine(Format(HelpText.Lookup('TRAFO'), 1650 [Phrases.Lookup('TERRAIN', TransTerrain + 24)]), pkTer, 1651 TransTerrain + 24, hkTer + hkCrossLink, TransTerrain + 24); 1652 end 1653 else if i = fGrass then 1654 begin 1655 LF; 1656 AddLine(Format(HelpText.Lookup('TRAFO'), 1657 [Phrases.Lookup('TERRAIN', fGrass + 12)]), pkTer, fGrass + 12, 1658 hkTer + hkCrossLink, fGrass + 12); 1659 end 1660 end; 1661 NextSection('SPECIAL'); 1662 if no = 3 * 12 then 1663 begin 1347 1664 LF; 1348 AddLine(Format(HelpText.Lookup('TRAFO'), 1349 [Phrases.Lookup('TERRAIN',TransTerrain+24)]),pkTer,TransTerrain+24, 1350 hkTer+hkCrossLink,TransTerrain+24); 1351 end 1352 else if i=fGrass then 1665 for special := 1 to 3 do 1353 1666 begin 1354 LF; 1355 AddLine(Format(HelpText.Lookup('TRAFO'), 1356 [Phrases.Lookup('TERRAIN',fGrass+12)]),pkTer,fGrass+12, 1357 hkTer+hkCrossLink,fGrass+12); 1358 end 1359 end; 1360 NextSection('SPECIAL'); 1361 if no=3*12 then 1362 begin 1363 LF; 1364 for special:=1 to 3 do 1365 begin 1366 if special>1 then LF; 1367 AddLine(Phrases.Lookup('TERRAIN',3*12+special),pkTer,3*12+special); 1667 if special > 1 then 1668 LF; 1669 AddLine(Phrases.Lookup('TERRAIN', 3 * 12 + special), pkTer, 1670 3 * 12 + special); 1368 1671 end 1369 1672 end 1370 else if (no<12) and (no<>fGrass) and (no<>fOcean) then1371 begin 1372 LF;1373 for special:=1 to 2 do1374 if (no<>fArctic) and (no<>fSwamp) or (special<2) then1673 else if (no < 12) and (no <> fGrass) and (no <> fOcean) then 1674 begin 1675 LF; 1676 for special := 1 to 2 do 1677 if (no <> fArctic) and (no <> fSwamp) or (special < 2) then 1375 1678 begin 1376 if special>1 then LF; 1377 AddLine(Phrases.Lookup('TERRAIN',no+special*12),pkTer,no+special*12); 1378 i:=FoodRes[special]-FoodRes[0]; 1379 if i<>0 then 1380 MainText[Count-1]:=MainText[Count-1]+Format(HelpText.Lookup('SPECIALFOOD'),[i]); 1381 i:=ProdRes[special]-ProdRes[0]; 1382 if i<>0 then 1383 MainText[Count-1]:=MainText[Count-1]+Format(HelpText.Lookup('SPECIALPROD'),[i]); 1384 i:=TradeRes[special]-TradeRes[0]; 1385 if i<>0 then 1386 MainText[Count-1]:=MainText[Count-1]+Format(HelpText.Lookup('SPECIALTRADE'),[i]); 1679 if special > 1 then 1680 LF; 1681 AddLine(Phrases.Lookup('TERRAIN', no + special * 12), pkTer, 1682 no + special * 12); 1683 i := FoodRes[special] - FoodRes[0]; 1684 if i <> 0 then 1685 MainText[Count - 1] := MainText[Count - 1] + 1686 Format(HelpText.Lookup('SPECIALFOOD'), [i]); 1687 i := ProdRes[special] - ProdRes[0]; 1688 if i <> 0 then 1689 MainText[Count - 1] := MainText[Count - 1] + 1690 Format(HelpText.Lookup('SPECIALPROD'), [i]); 1691 i := TradeRes[special] - TradeRes[0]; 1692 if i <> 0 then 1693 MainText[Count - 1] := MainText[Count - 1] + 1694 Format(HelpText.Lookup('SPECIALTRADE'), [i]); 1387 1695 end; 1388 1696 end; 1389 if no=3*12 then1390 begin 1391 LF;1392 AddText(HelpText.Lookup('RARE'));1393 end; 1394 if (no<3*12) and (TerrType in [fDesert,fArctic]) then1395 begin 1396 NextSection('SEEALSO');1397 AddImp(woGardens);1398 CheckSeeAlso:=true1697 if no = 3 * 12 then 1698 begin 1699 LF; 1700 AddText(HelpText.Lookup('RARE')); 1701 end; 1702 if (no < 3 * 12) and (TerrType in [fDesert, fArctic]) then 1703 begin 1704 NextSection('SEEALSO'); 1705 AddImp(woGardens); 1706 CheckSeeAlso := true 1399 1707 end 1400 1708 end 1401 1709 end; 1402 1710 1403 hkFeature:1404 if no=200 then1711 hkFeature: 1712 if no = 200 then 1405 1713 begin // complete feature list 1406 Caption:=HelpText.Lookup('HELPTITLE_FEATURELIST');1407 List:=THyperText.Create;1408 for special:=0 to 2 do1714 Caption := HelpText.Lookup('HELPTITLE_FEATURELIST'); 1715 List := THyperText.Create; 1716 for special := 0 to 2 do 1409 1717 begin 1410 if special>0 then begin LF; LF end; 1411 case special of 1412 0: AddLine(HelpText.Lookup('HELPTITLE_FEATURE1LIST'),pkSection); 1413 1: AddLine(HelpText.Lookup('HELPTITLE_FEATURE2LIST'),pkSection); 1414 2: AddLine(HelpText.Lookup('HELPTITLE_FEATURE3LIST'),pkSection); 1415 end; 1416 List.Clear; 1417 for i:=0 to nFeature-1 do if Feature[i].Preq<>preNA then 1418 begin 1419 if i<mcFirstNonCap then j:=0 1420 else if i in AutoFeature then j:=2 1421 else j:=1; 1422 if j=special then 1423 List.AddLine(Phrases.Lookup('FEATURES',i),pkFeature,i,hkFeature,i); 1424 end; 1425 List.Sort; 1426 AddStrings(List); 1718 if special > 0 then 1719 begin 1720 LF; 1721 LF 1722 end; 1723 case special of 1724 0: 1725 AddLine(HelpText.Lookup('HELPTITLE_FEATURE1LIST'), pkSection); 1726 1: 1727 AddLine(HelpText.Lookup('HELPTITLE_FEATURE2LIST'), pkSection); 1728 2: 1729 AddLine(HelpText.Lookup('HELPTITLE_FEATURE3LIST'), pkSection); 1730 end; 1731 List.Clear; 1732 for i := 0 to nFeature - 1 do 1733 if Feature[i].Preq <> preNA then 1734 begin 1735 if i < mcFirstNonCap then 1736 j := 0 1737 else if i in AutoFeature then 1738 j := 2 1739 else 1740 j := 1; 1741 if j = special then 1742 List.AddLine(Phrases.Lookup('FEATURES', i), pkFeature, i, 1743 hkFeature, i); 1744 end; 1745 List.Sort; 1746 AddStrings(List); 1427 1747 end; 1428 List.Free1748 List.Free 1429 1749 end 1430 else1750 else 1431 1751 begin // single feature 1432 Caption:=Phrases.Lookup('FEATURES',no); 1433 LF; 1434 AddLine(Phrases.Lookup('FEATURES',no),pkBigFeature,no); 1435 if no<mcFirstNonCap then 1436 AddLine(HelpText.Lookup('HELPSPEC_CAP')) 1437 else if no in AutoFeature then 1438 AddLine(HelpText.Lookup('HELPSPEC_STANDARD')) 1439 else AddLine(HelpText.Lookup('HELPSPEC_FEATURE')); 1440 NextSection('EFFECT'); 1441 AddText(HelpText.LookupByHandle(hFEATUREHELP,no)); 1442 if (Feature[no].Weight<>0) or (Feature[no].Cost<>0) then 1752 Caption := Phrases.Lookup('FEATURES', no); 1753 LF; 1754 AddLine(Phrases.Lookup('FEATURES', no), pkBigFeature, no); 1755 if no < mcFirstNonCap then 1756 AddLine(HelpText.Lookup('HELPSPEC_CAP')) 1757 else if no in AutoFeature then 1758 AddLine(HelpText.Lookup('HELPSPEC_STANDARD')) 1759 else 1760 AddLine(HelpText.Lookup('HELPSPEC_FEATURE')); 1761 NextSection('EFFECT'); 1762 AddText(HelpText.LookupByHandle(hFEATUREHELP, no)); 1763 if (Feature[no].Weight <> 0) or (Feature[no].Cost <> 0) then 1443 1764 begin 1444 NextSection('COSTS'); 1445 s:=IntToStr(Feature[no].Cost); 1446 if Feature[no].Cost>=0 then s:='+'+s; 1447 AddLine(Format(HelpText.Lookup('COSTBASE'),[s])); 1448 if Feature[no].Weight>0 then 1449 begin 1450 AddLine(Format(HelpText.Lookup('WEIGHT'), 1451 ['+'+IntToStr(Feature[no].Weight)])); 1452 if no=mcDefense then 1453 AddLine(Format(HelpText.Lookup('WEIGHT'),['+2']),pkDomain,dGround); 1765 NextSection('COSTS'); 1766 s := IntToStr(Feature[no].Cost); 1767 if Feature[no].Cost >= 0 then 1768 s := '+' + s; 1769 AddLine(Format(HelpText.Lookup('COSTBASE'), [s])); 1770 if Feature[no].Weight > 0 then 1771 begin 1772 AddLine(Format(HelpText.Lookup('WEIGHT'), 1773 ['+' + IntToStr(Feature[no].Weight)])); 1774 if no = mcDefense then 1775 AddLine(Format(HelpText.Lookup('WEIGHT'), ['+2']), 1776 pkDomain, dGround); 1454 1777 end 1455 1778 end; 1456 if Feature[no].Preq<>preNone then1779 if Feature[no].Preq <> preNone then 1457 1780 begin 1781 LF; 1782 if Feature[no].Preq = preSun then 1783 AddPreqImp(woSun) // sun tsu feature 1784 else 1785 AddPreqAdv(Feature[no].Preq); 1786 MainText[Count - 1] := Format(HelpText.Lookup('REQUIRED'), 1787 [MainText[Count - 1]]); 1788 end; 1789 NextSection('SEEALSO'); 1790 CheckSeeAlso := true 1791 end; 1792 1793 hkModel: 1794 begin 1795 Caption := HelpText.Lookup('HELPTITLE_MODELLIST'); 1796 for i := 0 to nSpecialModel - 1 do 1797 if i <> 2 then 1798 AddModelText(i); 1458 1799 LF; 1459 if Feature[no].Preq=preSun then AddPreqImp(woSun) // sun tsu feature 1460 else AddPreqAdv(Feature[no].Preq); 1461 MainText[Count-1]:=Format(HelpText.Lookup('REQUIRED'),[MainText[Count-1]]); 1800 AddItem('MODELNOTE'); 1801 end; 1802 1803 end; 1804 if CheckSeeAlso then 1805 for i := 0 to nSeeAlso - 1 do 1806 if (SeeAlso[i].Kind = Kind) and (SeeAlso[i].no = no) then 1807 case SeeAlso[i].SeeKind of 1808 hkImp: 1809 AddImp(SeeAlso[i].SeeNo); 1810 hkAdv: 1811 AddAdv(SeeAlso[i].SeeNo); 1812 hkFeature: 1813 AddFeature(SeeAlso[i].SeeNo); 1462 1814 end; 1463 NextSection('SEEALSO'); 1464 CheckSeeAlso:=true 1465 end; 1466 1467 hkModel: 1468 begin 1469 Caption:=HelpText.Lookup('HELPTITLE_MODELLIST'); 1470 for i:=0 to nSpecialModel-1 do if i<>2 then AddModelText(i); 1471 LF; 1472 AddItem('MODELNOTE'); 1473 end; 1474 1815 if (Headline >= 0) and (Count = Headline + 1) then 1816 Delete(Headline) 1817 else 1818 LF; 1819 1820 InitPVSB(sb, Count - 1, InnerHeight div 24); 1821 if sbPos <> 0 then 1822 begin 1823 sb.si.npos := sbPos; 1824 sb.si.FMask := SIF_POS; 1825 SetScrollInfo(sb.h, SB_CTL, sb.si, true); 1475 1826 end; 1476 if CheckSeeAlso then 1477 for i:=0 to nSeeAlso-1 do 1478 if (SeeAlso[i].Kind=Kind) and (SeeAlso[i].no=no) then 1479 case SeeAlso[i].SeeKind of 1480 hkImp: AddImp(SeeAlso[i].SeeNo); 1481 hkAdv: AddAdv(SeeAlso[i].SeeNo); 1482 hkFeature: AddFeature(SeeAlso[i].SeeNo); 1483 end; 1484 if (Headline>=0) and (Count=Headline+1) then Delete(Headline) 1485 else LF; 1486 1487 InitPVSB(sb,Count-1,InnerHeight div 24); 1488 if sbPos<>0 then 1489 begin 1490 sb.si.npos:=sbPos; 1491 sb.si.FMask:=SIF_POS; 1492 SetScrollInfo(sb.h,SB_CTL,sb.si,true); 1493 end; 1494 BackBtn.Visible:= nHist>0; 1495 TopBtn.Visible:= (nHist>0) or (Kind<>hkMisc) or (no<>miscMain); 1496 Sel:=-1; 1827 BackBtn.Visible := nHist > 0; 1828 TopBtn.Visible := (nHist > 0) or (Kind <> hkMisc) or (no <> miscMain); 1829 Sel := -1; 1497 1830 end; // with MainText 1498 end; { Prepare}1831 end; { Prepare } 1499 1832 1500 1833 procedure THelpDlg.ShowNewContent(NewMode, Category, Index: integer); 1501 1834 begin 1502 if (Category<>Kind) or (Index<>no) 1503 or (Category=hkMisc) and (Index=miscSearchResult) then 1504 begin 1505 if nHist=MaxHist then 1506 begin 1507 move(HistKind[2],HistKind[1],4*(nHist-2)); 1508 move(HistNo[2],HistNo[1],4*(nHist-2)); 1509 move(HistPos[2],HistPos[1],4*(nHist-2)); 1510 move(HistSearchContent[2],HistSearchContent[1],sizeof(shortstring)*(nHist-2)); 1835 if (Category <> Kind) or (Index <> no) or (Category = hkMisc) and 1836 (Index = miscSearchResult) then 1837 begin 1838 if nHist = MaxHist then 1839 begin 1840 move(HistKind[2], HistKind[1], 4 * (nHist - 2)); 1841 move(HistNo[2], HistNo[1], 4 * (nHist - 2)); 1842 move(HistPos[2], HistPos[1], 4 * (nHist - 2)); 1843 move(HistSearchContent[2], HistSearchContent[1], 1844 sizeof(shortstring) * (nHist - 2)); 1511 1845 end 1512 else inc(nHist); 1513 if nHist>0 then 1514 begin 1515 HistKind[nHist-1]:=Kind; 1516 HistNo[nHist-1]:=no; 1517 HistPos[nHist-1]:=sb.si.npos; 1518 HistSearchContent[nHist-1]:=SearchContent 1846 else 1847 inc(nHist); 1848 if nHist > 0 then 1849 begin 1850 HistKind[nHist - 1] := Kind; 1851 HistNo[nHist - 1] := no; 1852 HistPos[nHist - 1] := sb.si.npos; 1853 HistSearchContent[nHist - 1] := SearchContent 1519 1854 end 1520 1855 end; 1521 Kind:=Category;1522 no:=Index;1523 SearchContent:=NewSearchContent;1524 Prepare;1525 OffscreenPaint;1526 inherited ShowNewContent(NewMode);1856 Kind := Category; 1857 no := Index; 1858 SearchContent := NewSearchContent; 1859 Prepare; 1860 OffscreenPaint; 1861 inherited ShowNewContent(NewMode); 1527 1862 end; 1528 1863 … … 1530 1865 x, y: integer); 1531 1866 var 1532 i0,Sel0:integer;1867 i0, Sel0: integer; 1533 1868 begin 1534 y:=y-WideFrame; 1535 i0:=sb.si.npos; 1536 Sel0:=Sel; 1537 if (x>=SideFrame) and (x<SideFrame+InnerWidth) and (y>=0) and (y<InnerHeight) 1538 and (y mod 24>=8) then 1539 Sel:=y div 24 1540 else Sel:=-1; 1541 if (Sel+i0>=MainText.Count) or (Sel>=0) 1542 and (THelpLineInfo(MainText.Objects[Sel+i0]).Link=0) then Sel:=-1; 1543 if Sel<>Sel0 then 1544 begin 1545 if Sel0<>-1 then line(Canvas,Sel0,false); 1546 if Sel<>-1 then line(Canvas,Sel,true) 1869 y := y - WideFrame; 1870 i0 := sb.si.npos; 1871 Sel0 := Sel; 1872 if (x >= SideFrame) and (x < SideFrame + InnerWidth) and (y >= 0) and 1873 (y < InnerHeight) and (y mod 24 >= 8) then 1874 Sel := y div 24 1875 else 1876 Sel := -1; 1877 if (Sel + i0 >= MainText.Count) or (Sel >= 0) and 1878 (THelpLineInfo(MainText.Objects[Sel + i0]).Link = 0) then 1879 Sel := -1; 1880 if Sel <> Sel0 then 1881 begin 1882 if Sel0 <> -1 then 1883 line(Canvas, Sel0, false); 1884 if Sel <> -1 then 1885 line(Canvas, Sel, true) 1547 1886 end 1548 1887 end; 1549 1888 1550 procedure THelpDlg.PaintBox1MouseDown(Sender: TObject; 1551 Button: TMouseButton;Shift: TShiftState; x, y: integer);1889 procedure THelpDlg.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; 1890 Shift: TShiftState; x, y: integer); 1552 1891 begin 1553 if Sel>=0 then with THelpLineInfo(MainText.Objects[Sel+sb.si.npos]) do 1554 if Link shr 8 and $3F=hkInternet then 1555 case Link and $FF of 1556 1: ShellExecute(Handle,'open',pchar(HomeDir+'AI Template\AI development manual.html'),'','', 1557 SW_SHOWNORMAL); 1558 2: ShellExecute(Handle,'open','http://c-evo.org','','', 1559 SW_SHOWNORMAL); 1560 3: ShellExecute(Handle,'open','http://c-evo.org/_sg/contact','','', 1561 SW_SHOWNORMAL); 1892 if Sel >= 0 then 1893 with THelpLineInfo(MainText.Objects[Sel + sb.si.npos]) do 1894 if Link shr 8 and $3F = hkInternet then 1895 case Link and $FF of 1896 1: 1897 ShellExecute(Handle, 'open', 1898 pchar(HomeDir + 'AI Template\AI development manual.html'), '', '', 1899 SW_SHOWNORMAL); 1900 2: 1901 ShellExecute(Handle, 'open', 'http://c-evo.org', '', '', 1902 SW_SHOWNORMAL); 1903 3: 1904 ShellExecute(Handle, 'open', 'http://c-evo.org/_sg/contact', '', '', 1905 SW_SHOWNORMAL); 1906 end 1907 else 1908 begin 1909 if (Link >= $8000) and (Link and $3FFF = liInvalid) then 1910 exit; // invalid link; 1911 if Link >= $8000 then 1912 ShowNewContent(FWindowMode, hkText, Link and $3FFF) 1913 else 1914 ShowNewContent(FWindowMode, Link shr 8 and $3F, Link and $FF); 1562 1915 end 1563 else1564 begin1565 if (Link>=$8000) and (Link and $3FFF=liInvalid) then1566 exit; // invalid link;1567 if Link>=$8000 then1568 ShowNewContent(FWindowMode, hkText, Link and $3FFF)1569 else ShowNewContent(FWindowMode, Link shr 8 and $3F, Link and $FF);1570 end1571 1916 end; 1572 1917 1573 1918 procedure THelpDlg.BackBtnClick(Sender: TObject); 1574 1919 begin 1575 if nHist>0 then1576 begin 1577 dec(nHist);1578 if (HistKind[nHist]=hkMisc) and (HistNo[nHist]=miscSearchResult)1579 and (HistSearchContent[nHist]<>SearchContent) then1580 begin 1581 SearchContent:=HistSearchContent[nHist];1582 Search(SearchContent);1920 if nHist > 0 then 1921 begin 1922 dec(nHist); 1923 if (HistKind[nHist] = hkMisc) and (HistNo[nHist] = miscSearchResult) and 1924 (HistSearchContent[nHist] <> SearchContent) then 1925 begin 1926 SearchContent := HistSearchContent[nHist]; 1927 Search(SearchContent); 1583 1928 end; 1584 Kind:=HistKind[nHist]; 1585 no:=HistNo[nHist]; 1586 Prepare(HistPos[nHist]); 1929 Kind := HistKind[nHist]; 1930 no := HistNo[nHist]; 1931 Prepare(HistPos[nHist]); 1932 OffscreenPaint; 1933 Invalidate; 1934 end 1935 end; 1936 1937 procedure THelpDlg.TopBtnClick(Sender: TObject); 1938 begin 1939 nHist := 0; 1940 Kind := hkMisc; 1941 no := miscMain; 1942 Prepare; 1587 1943 OffscreenPaint; 1588 1944 Invalidate; 1589 end1590 end;1591 1592 procedure THelpDlg.TopBtnClick(Sender: TObject);1593 begin1594 nHist:=0;1595 Kind:=hkMisc;1596 no:=miscMain;1597 Prepare;1598 OffscreenPaint;1599 Invalidate;1600 1945 end; 1601 1946 1602 1947 procedure THelpDlg.FormClose(Sender: TObject; var Action: TCloseAction); 1603 1948 begin 1604 ExtPic.Height:=0;1605 inherited;1949 ExtPic.Height := 0; 1950 inherited; 1606 1951 end; 1607 1952 1608 1953 function THelpDlg.TextIndex(Item: string): integer; 1609 1954 begin 1610 result:=HelpText.GetHandle(Item)1955 result := HelpText.Gethandle(Item) 1611 1956 end; 1612 1957 … … 1614 1959 Shift: TShiftState); 1615 1960 begin 1616 if Key=VK_F1 then // my key 1617 else inherited 1961 if Key = VK_F1 then // my key 1962 else 1963 inherited 1618 1964 end; 1619 1965 1620 1966 procedure THelpDlg.SearchBtnClick(Sender: TObject); 1621 1967 begin 1622 InputDlg.Caption:=Phrases.Lookup('SEARCH'); 1623 InputDlg.EInput.Text:=SearchContent; 1624 InputDlg.CenterToRect(BoundsRect); 1625 InputDlg.ShowModal; 1626 if (InputDlg.ModalResult=mrOK) and (length(InputDlg.EInput.Text)>=2) then 1627 begin 1628 Search(InputDlg.EInput.Text); 1629 case SearchResult.Count of 1630 0: SimpleMessage(Format(HelpText.Lookup('NOMATCHES'), [InputDlg.EInput.Text])); 1631 1: 1632 with THelpLineInfo(SearchResult.Objects[0]) do 1633 if Link>=$8000 then 1634 ShowNewContent(FWindowMode, hkText, Link and $3FFF) 1635 else ShowNewContent(FWindowMode, Link shr 8 and $3F, Link and $FF); 1968 InputDlg.Caption := Phrases.Lookup('SEARCH'); 1969 InputDlg.EInput.Text := SearchContent; 1970 InputDlg.CenterToRect(BoundsRect); 1971 InputDlg.ShowModal; 1972 if (InputDlg.ModalResult = mrOK) and (length(InputDlg.EInput.Text) >= 2) then 1973 begin 1974 Search(InputDlg.EInput.Text); 1975 case SearchResult.Count of 1976 0: 1977 SimpleMessage(Format(HelpText.Lookup('NOMATCHES'), 1978 [InputDlg.EInput.Text])); 1979 1: 1980 with THelpLineInfo(SearchResult.Objects[0]) do 1981 if Link >= $8000 then 1982 ShowNewContent(FWindowMode, hkText, Link and $3FFF) 1983 else 1984 ShowNewContent(FWindowMode, Link shr 8 and $3F, Link and $FF); 1636 1985 else 1637 1986 begin 1638 NewSearchContent:=InputDlg.EInput.Text;1639 ShowNewContent(FWindowMode, hkMisc, miscSearchResult);1987 NewSearchContent := InputDlg.EInput.Text; 1988 ShowNewContent(FWindowMode, hkMisc, miscSearchResult); 1640 1989 end 1641 1990 end … … 1645 1994 procedure THelpDlg.Search(SearchString: string); 1646 1995 var 1647 h, i, PrevHandle, PrevIndex, p, RightMargin: integer;1648 s: string;1649 mADVHELP, mIMPHELP, mFEATUREHELP: set of 0..255;1650 bGOVHELP, bSPECIALMODEL, bJOBHELP: boolean;1996 h, i, PrevHandle, PrevIndex, p, RightMargin: integer; 1997 s: string; 1998 mADVHELP, mIMPHELP, mFEATUREHELP: set of 0 .. 255; 1999 bGOVHELP, bSPECIALMODEL, bJOBHELP: boolean; 1651 2000 begin 1652 SearchResult.Clear;1653 mADVHELP:=[];1654 mIMPHELP:=[];1655 mFEATUREHELP:=[];1656 bGOVHELP:=false;1657 bSPECIALMODEL:=false;1658 bJOBHELP:=false;1659 1660 // search in generic reference1661 SearchString:=UpperCase(SearchString);1662 for i:=0 to 35+4 do1663 begin 1664 s:=Phrases.Lookup('TERRAIN',i);1665 if pos(SearchString,UpperCase(s))>0 then1666 if i<36 then1667 SearchResult.AddLine(s+' '+HelpText.Lookup('HELPSPEC_TER'),pkNormal,0,1668 hkTer+hkCrossLink,i)1669 else2001 SearchResult.Clear; 2002 mADVHELP := []; 2003 mIMPHELP := []; 2004 mFEATUREHELP := []; 2005 bGOVHELP := false; 2006 bSPECIALMODEL := false; 2007 bJOBHELP := false; 2008 2009 // search in generic reference 2010 SearchString := UpperCase(SearchString); 2011 for i := 0 to 35 + 4 do 2012 begin 2013 s := Phrases.Lookup('TERRAIN', i); 2014 if pos(SearchString, UpperCase(s)) > 0 then 2015 if i < 36 then 2016 SearchResult.AddLine(s + ' ' + HelpText.Lookup('HELPSPEC_TER'), 2017 pkNormal, 0, hkTer + hkCrossLink, i) 2018 else 1670 2019 begin 1671 SearchResult.AddLine(Phrases.Lookup('TERRAIN',36)+' ' 1672 +HelpText.Lookup('HELPSPEC_TER'),pkNormal,0,hkTer+hkCrossLink,36); 1673 if i>36 then 1674 SearchResult.AddLine(Phrases.Lookup('IMPROVEMENTS',imShipComp+i-37) 1675 +' '+HelpText.Lookup('HELPSPEC_SHIPPART'), 1676 pkNormal,0,hkImp+hkCrossLink,imShipComp+i-37); 1677 break 2020 SearchResult.AddLine(Phrases.Lookup('TERRAIN', 36) + ' ' + 2021 HelpText.Lookup('HELPSPEC_TER'), pkNormal, 0, 2022 hkTer + hkCrossLink, 36); 2023 if i > 36 then 2024 SearchResult.AddLine(Phrases.Lookup('IMPROVEMENTS', 2025 imShipComp + i - 37) + ' ' + HelpText.Lookup('HELPSPEC_SHIPPART'), 2026 pkNormal, 0, hkImp + hkCrossLink, imShipComp + i - 37); 2027 Break 1678 2028 end 1679 2029 end; 1680 for i:=0 to nJobHelp-1 do 1681 if pos(SearchString,UpperCase(Phrases.Lookup('JOBRESULT',JobHelp[i])))>0 then 1682 begin 1683 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_JOBLIST'),pkNormal,0, 1684 hkMisc+hkCrossLink,miscJobList); 1685 bJOBHELP:=true; 1686 break 2030 for i := 0 to nJobHelp - 1 do 2031 if pos(SearchString, UpperCase(Phrases.Lookup('JOBRESULT', JobHelp[i]))) > 0 2032 then 2033 begin 2034 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_JOBLIST'), pkNormal, 0, 2035 hkMisc + hkCrossLink, miscJobList); 2036 bJOBHELP := true; 2037 Break 1687 2038 end; 1688 for i:=0 to nAdv-1 do 1689 begin 1690 s:=Phrases.Lookup('ADVANCES',i); 1691 if pos(SearchString,UpperCase(s))>0 then 1692 begin 1693 if i in FutureTech then s:=s+' '+HelpText.Lookup('HELPSPEC_FUTURE') 1694 else s:=s+' '+HelpText.Lookup('HELPSPEC_ADV'); 1695 SearchResult.AddLine(s,pkNormal,0,hkAdv+hkCrossLink,i); 1696 include(mADVHELP,i); 2039 for i := 0 to nAdv - 1 do 2040 begin 2041 s := Phrases.Lookup('ADVANCES', i); 2042 if pos(SearchString, UpperCase(s)) > 0 then 2043 begin 2044 if i in FutureTech then 2045 s := s + ' ' + HelpText.Lookup('HELPSPEC_FUTURE') 2046 else 2047 s := s + ' ' + HelpText.Lookup('HELPSPEC_ADV'); 2048 SearchResult.AddLine(s, pkNormal, 0, hkAdv + hkCrossLink, i); 2049 include(mADVHELP, i); 1697 2050 end 1698 2051 end; 1699 for i:=0 to nSpecialModel-1 do1700 begin 1701 FindStdModelPicture(SpecialModelPictureCode[i],h,s);1702 if pos(SearchString,UpperCase(s))>0 then1703 begin 1704 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_MODELLIST'),pkNormal,0,1705 hkModel+hkCrossLink,0);1706 bSPECIALMODEL:=true;1707 break2052 for i := 0 to nSpecialModel - 1 do 2053 begin 2054 FindStdModelPicture(SpecialModelPictureCode[i], h, s); 2055 if pos(SearchString, UpperCase(s)) > 0 then 2056 begin 2057 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_MODELLIST'), pkNormal, 0, 2058 hkModel + hkCrossLink, 0); 2059 bSPECIALMODEL := true; 2060 Break 1708 2061 end; 1709 2062 end; 1710 for i:=0 to nFeature-1 do 1711 begin 1712 s:=Phrases.Lookup('FEATURES',i); 1713 if pos(SearchString,UpperCase(s))>0 then 1714 begin 1715 if i<mcFirstNonCap then s:=s+' '+HelpText.Lookup('HELPSPEC_CAP') 1716 else if i in AutoFeature then s:=s+' '+HelpText.Lookup('HELPSPEC_STANDARD') 1717 else s:=s+' '+HelpText.Lookup('HELPSPEC_FEATURE'); 1718 SearchResult.AddLine(s,pkNormal,0,hkFeature+hkCrossLink,i); 1719 include(mFEATUREHELP,i); 2063 for i := 0 to nFeature - 1 do 2064 begin 2065 s := Phrases.Lookup('FEATURES', i); 2066 if pos(SearchString, UpperCase(s)) > 0 then 2067 begin 2068 if i < mcFirstNonCap then 2069 s := s + ' ' + HelpText.Lookup('HELPSPEC_CAP') 2070 else if i in AutoFeature then 2071 s := s + ' ' + HelpText.Lookup('HELPSPEC_STANDARD') 2072 else 2073 s := s + ' ' + HelpText.Lookup('HELPSPEC_FEATURE'); 2074 SearchResult.AddLine(s, pkNormal, 0, hkFeature + hkCrossLink, i); 2075 include(mFEATUREHELP, i); 1720 2076 end 1721 2077 end; 1722 for i:=0 to nImp-1 do 1723 begin 1724 s:=Phrases.Lookup('IMPROVEMENTS',i); 1725 if pos(SearchString,UpperCase(s))>0 then 1726 begin 1727 case Imp[i].Kind of 1728 ikWonder: s:=s+' '+HelpText.Lookup('HELPSPEC_WONDER'); 1729 ikCommon: s:=s+' '+HelpText.Lookup('HELPSPEC_IMP'); 1730 ikShipPart: s:=s+' '+HelpText.Lookup('HELPSPEC_SHIPPART'); 1731 else s:=s+' '+HelpText.Lookup('HELPSPEC_NAT') 2078 for i := 0 to nImp - 1 do 2079 begin 2080 s := Phrases.Lookup('IMPROVEMENTS', i); 2081 if pos(SearchString, UpperCase(s)) > 0 then 2082 begin 2083 case Imp[i].Kind of 2084 ikWonder: 2085 s := s + ' ' + HelpText.Lookup('HELPSPEC_WONDER'); 2086 ikCommon: 2087 s := s + ' ' + HelpText.Lookup('HELPSPEC_IMP'); 2088 ikShipPart: 2089 s := s + ' ' + HelpText.Lookup('HELPSPEC_SHIPPART'); 2090 else 2091 s := s + ' ' + HelpText.Lookup('HELPSPEC_NAT') 1732 2092 end; 1733 SearchResult.AddLine(s,pkNormal,0,hkImp+hkCrossLink,i);1734 include(mIMPHELP,i);2093 SearchResult.AddLine(s, pkNormal, 0, hkImp + hkCrossLink, i); 2094 include(mIMPHELP, i); 1735 2095 end 1736 2096 end; 1737 for i:=0 to nGov-1 do1738 if pos(SearchString,UpperCase(Phrases.Lookup('GOVERNMENT',i)))>0 then1739 begin 1740 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_GOVLIST'),pkNormal,0,1741 hkMisc+hkCrossLink,miscGovList);1742 bGOVHELP:=true;1743 break2097 for i := 0 to nGov - 1 do 2098 if pos(SearchString, UpperCase(Phrases.Lookup('GOVERNMENT', i))) > 0 then 2099 begin 2100 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_GOVLIST'), pkNormal, 0, 2101 hkMisc + hkCrossLink, miscGovList); 2102 bGOVHELP := true; 2103 Break 1744 2104 end; 1745 2105 1746 // full text search 1747 h:=-1; 1748 repeat 1749 PrevHandle:=h; 1750 PrevIndex:=i; 1751 if not HelpText.Search(SearchString, h, i) then 1752 break; 1753 if h=hADVHELP then 1754 begin 1755 if (i>=0) and ((i<>PrevIndex) or (h<>PrevHandle)) and not (i in mADVHELP) then 2106 // full text search 2107 h := -1; 2108 repeat 2109 PrevHandle := h; 2110 PrevIndex := i; 2111 if not HelpText.Search(SearchString, h, i) then 2112 Break; 2113 if h = hADVHELP then 2114 begin 2115 if (i >= 0) and ((i <> PrevIndex) or (h <> PrevHandle)) and 2116 not(i in mADVHELP) then 1756 2117 begin 1757 s:=Phrases.Lookup('ADVANCES',i); 1758 if i in FutureTech then s:=s+' '+HelpText.Lookup('HELPSPEC_FUTURE') 1759 else s:=s+' '+HelpText.Lookup('HELPSPEC_ADV'); 1760 SearchResult.AddLine(s,pkNormal,0,hkAdv+hkCrossLink,i) 2118 s := Phrases.Lookup('ADVANCES', i); 2119 if i in FutureTech then 2120 s := s + ' ' + HelpText.Lookup('HELPSPEC_FUTURE') 2121 else 2122 s := s + ' ' + HelpText.Lookup('HELPSPEC_ADV'); 2123 SearchResult.AddLine(s, pkNormal, 0, hkAdv + hkCrossLink, i) 1761 2124 end 1762 2125 end 1763 else if h=hIMPHELP then 1764 begin 1765 if (i>=0) and ((i<>PrevIndex) or (h<>PrevHandle)) and not (i in mIMPHELP) then 2126 else if h = hIMPHELP then 2127 begin 2128 if (i >= 0) and ((i <> PrevIndex) or (h <> PrevHandle)) and 2129 not(i in mIMPHELP) then 1766 2130 begin 1767 s:=Phrases.Lookup('IMPROVEMENTS',i); 1768 case Imp[i].Kind of 1769 ikWonder: s:=s+' '+HelpText.Lookup('HELPSPEC_WONDER'); 1770 ikCommon: s:=s+' '+HelpText.Lookup('HELPSPEC_IMP'); 1771 ikShipPart: s:=s+' '+HelpText.Lookup('HELPSPEC_SHIPPART'); 1772 else s:=s+' '+HelpText.Lookup('HELPSPEC_NAT') 2131 s := Phrases.Lookup('IMPROVEMENTS', i); 2132 case Imp[i].Kind of 2133 ikWonder: 2134 s := s + ' ' + HelpText.Lookup('HELPSPEC_WONDER'); 2135 ikCommon: 2136 s := s + ' ' + HelpText.Lookup('HELPSPEC_IMP'); 2137 ikShipPart: 2138 s := s + ' ' + HelpText.Lookup('HELPSPEC_SHIPPART'); 2139 else 2140 s := s + ' ' + HelpText.Lookup('HELPSPEC_NAT') 1773 2141 end; 1774 SearchResult.AddLine(s,pkNormal,0,hkImp+hkCrossLink,i)2142 SearchResult.AddLine(s, pkNormal, 0, hkImp + hkCrossLink, i) 1775 2143 end 1776 2144 end 1777 else if h=hFEATUREHELP then 1778 begin 1779 if (i>=0) and ((i<>PrevIndex) or (h<>PrevHandle)) and not (i in mFEATUREHELP) then 2145 else if h = hFEATUREHELP then 2146 begin 2147 if (i >= 0) and ((i <> PrevIndex) or (h <> PrevHandle)) and 2148 not(i in mFEATUREHELP) then 1780 2149 begin 1781 s:=Phrases.Lookup('FEATURES',i); 1782 if i<mcFirstNonCap then s:=s+' '+HelpText.Lookup('HELPSPEC_CAP') 1783 else if i in AutoFeature then s:=s+' '+HelpText.Lookup('HELPSPEC_STANDARD') 1784 else s:=s+' '+HelpText.Lookup('HELPSPEC_FEATURE'); 1785 SearchResult.AddLine(s,pkNormal,0,hkFeature+hkCrossLink,i); 2150 s := Phrases.Lookup('FEATURES', i); 2151 if i < mcFirstNonCap then 2152 s := s + ' ' + HelpText.Lookup('HELPSPEC_CAP') 2153 else if i in AutoFeature then 2154 s := s + ' ' + HelpText.Lookup('HELPSPEC_STANDARD') 2155 else 2156 s := s + ' ' + HelpText.Lookup('HELPSPEC_FEATURE'); 2157 SearchResult.AddLine(s, pkNormal, 0, hkFeature + hkCrossLink, i); 1786 2158 end 1787 2159 end 1788 else if h=hGOVHELP then1789 begin 1790 if (i>=0) and (h<>PrevHandle) and not bGOVHELP then1791 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_GOVLIST'),pkNormal,0,1792 hkMisc+hkCrossLink,miscGovList)2160 else if h = hGOVHELP then 2161 begin 2162 if (i >= 0) and (h <> PrevHandle) and not bGOVHELP then 2163 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_GOVLIST'), pkNormal, 0, 2164 hkMisc + hkCrossLink, miscGovList) 1793 2165 end 1794 else if h=hSPECIALMODEL then1795 begin 1796 if (i>=0) and (h<>PrevHandle) and not bSPECIALMODEL then1797 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_MODELLIST'),pkNormal,0,1798 hkModel+hkCrossLink,0)2166 else if h = hSPECIALMODEL then 2167 begin 2168 if (i >= 0) and (h <> PrevHandle) and not bSPECIALMODEL then 2169 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_MODELLIST'), pkNormal, 2170 0, hkModel + hkCrossLink, 0) 1799 2171 end 1800 else if h=hJOBHELP then1801 begin 1802 if (i>=0) and (h<>PrevHandle) and not bJOBHELP then1803 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_JOBLIST'),pkNormal,0,1804 hkMisc+hkCrossLink,miscJobList)2172 else if h = hJOBHELP then 2173 begin 2174 if (i >= 0) and (h <> PrevHandle) and not bJOBHELP then 2175 SearchResult.AddLine(HelpText.Lookup('HELPTITLE_JOBLIST'), pkNormal, 0, 2176 hkMisc + hkCrossLink, miscJobList) 1805 2177 end 1806 else if {(h<>hMAIN) and} (h<>PrevHandle) then1807 begin 1808 s:=HelpText.LookupByHandle(h);1809 p:=pos('$',s);1810 if p>0 then2178 else if { (h<>hMAIN) and } (h <> PrevHandle) then 2179 begin 2180 s := HelpText.LookupByHandle(h); 2181 p := pos('$', s); 2182 if p > 0 then 1811 2183 begin 1812 s:=copy(s,p+1,maxint);1813 p:=pos('\',s);1814 if p>0 then1815 s:=copy(s,1,p-1);1816 SearchResult.AddLine(s, pkNormal, 0, hkText+hkCrossLink, h);2184 s := copy(s, p + 1, maxint); 2185 p := pos('\', s); 2186 if p > 0 then 2187 s := copy(s, 1, p - 1); 2188 SearchResult.AddLine(s, pkNormal, 0, hkText + hkCrossLink, h); 1817 2189 end 1818 2190 end 1819 until false; 1820 1821 // cut lines to fit to window 1822 RightMargin:=InnerWidth-16-GetSystemMetrics(SM_CXVSCROLL); 1823 Offscreen.Canvas.Font.Assign(UniFont[ftNormal]); 1824 for i:=0 to SearchResult.Count-1 do 1825 begin 1826 while BiColorTextWidth(Offscreen.Canvas, SearchResult[i])>RightMargin-32 do 1827 SearchResult[i]:=copy(SearchResult[i], 1, length(SearchResult[i])-1) 1828 end; 1829 end; 2191 until false; 2192 2193 // cut lines to fit to window 2194 RightMargin := InnerWidth - 16 - GetSystemMetrics(SM_CXVSCROLL); 2195 OffScreen.Canvas.Font.Assign(UniFont[ftNormal]); 2196 for i := 0 to SearchResult.Count - 1 do 2197 begin 2198 while BiColorTextWidth(OffScreen.Canvas, SearchResult[i]) > 2199 RightMargin - 32 do 2200 SearchResult[i] := copy(SearchResult[i], 1, length(SearchResult[i]) - 1) 2201 end; 2202 end; 1830 2203 1831 2204 end. 1832 -
trunk/LocalPlayer/IsoEngine.pas
r2 r6 1 1 {$INCLUDE switches} 2 3 2 unit IsoEngine; 4 3 … … 6 5 7 6 uses 8 Protocol,ClientTools,ScreenTools,Tribes, 9 {$IFNDEF SCR}Term,{$ENDIF} 10 11 Windows,SysUtils,Classes,Graphics; 7 Protocol, ClientTools, ScreenTools, Tribes, 8 {$IFNDEF SCR}Term, {$ENDIF} 9 Windows, SysUtils, Classes, Graphics; 12 10 13 11 type 14 TInitEnemyModelEvent=function(emix: integer): boolean; 15 16 TIsoMap = class 17 constructor Create; 18 procedure SetOutput(Output: TBitmap); 19 procedure SetPaintBounds(Left, Top, Right, Bottom: integer); 20 procedure Paint(x,y,Loc,nx,ny,CityLoc,CityOwner:integer; UseBlink: boolean = false; CityAllowClick: boolean = false); 21 procedure PaintUnit(x,y:integer;const UnitInfo:TUnitInfo;Status:integer); 22 procedure PaintCity(x,y:integer;const CityInfo:TCityInfo; accessory: boolean = true); 23 procedure BitBlt(Src: TBitmap; x,y,Width,Height,xSrc,ySrc,Rop: integer); 24 25 procedure AttackBegin(const ShowMove: TShowMove); 26 procedure AttackEffect(const ShowMove: TShowMove); 27 procedure AttackEnd; 28 29 protected 30 FOutput: TBitmap; 31 FLeft, FTop, FRight, FBottom, RealTop, RealBottom, AttLoc, DefLoc, DefHealth, FAdviceLoc: integer; 32 OutDC, DataDC, MaskDC: Cardinal; 33 function Connection4(Loc,Mask,Value:integer):integer; 34 function Connection8(Loc,Mask:integer):integer; 35 function OceanConnection(Loc: integer): integer; 36 procedure PaintShore(x,y,Loc:integer); 37 procedure PaintTileExtraTerrain(x,y,Loc: integer); 38 procedure PaintTileObjects(x,y,Loc,CityLoc,CityOwner:integer; UseBlink: boolean); 39 procedure PaintGrid(x,y,nx,ny: integer); 40 procedure FillRect(x,y,Width,Height,Color: integer); 41 procedure Textout(x,y,Color: integer; const s: string); 42 procedure Sprite(HGr,xDst,yDst,Width,Height,xGr,yGr: integer); 43 procedure TSprite(xDst,yDst,grix: integer; PureBlack: boolean = false); 44 45 public 46 property AdviceLoc: integer read FAdviceLoc write FAdviceLoc; 12 TInitEnemyModelEvent = function(emix: integer): boolean; 13 14 TIsoMap = class 15 constructor Create; 16 procedure SetOutput(Output: TBitmap); 17 procedure SetPaintBounds(Left, Top, Right, Bottom: integer); 18 procedure Paint(x, y, Loc, nx, ny, CityLoc, CityOwner: integer; 19 UseBlink: boolean = false; CityAllowClick: boolean = false); 20 procedure PaintUnit(x, y: integer; const UnitInfo: TUnitInfo; 21 Status: integer); 22 procedure PaintCity(x, y: integer; const CityInfo: TCityInfo; 23 accessory: boolean = true); 24 procedure BitBlt(Src: TBitmap; x, y, Width, Height, xSrc, ySrc, 25 Rop: integer); 26 27 procedure AttackBegin(const ShowMove: TShowMove); 28 procedure AttackEffect(const ShowMove: TShowMove); 29 procedure AttackEnd; 30 31 protected 32 FOutput: TBitmap; 33 FLeft, FTop, FRight, FBottom, RealTop, RealBottom, AttLoc, DefLoc, 34 DefHealth, FAdviceLoc: integer; 35 OutDC, DataDC, MaskDC: Cardinal; 36 function Connection4(Loc, Mask, Value: integer): integer; 37 function Connection8(Loc, Mask: integer): integer; 38 function OceanConnection(Loc: integer): integer; 39 procedure PaintShore(x, y, Loc: integer); 40 procedure PaintTileExtraTerrain(x, y, Loc: integer); 41 procedure PaintTileObjects(x, y, Loc, CityLoc, CityOwner: integer; 42 UseBlink: boolean); 43 procedure PaintGrid(x, y, nx, ny: integer); 44 procedure FillRect(x, y, Width, Height, Color: integer); 45 procedure Textout(x, y, Color: integer; const s: string); 46 procedure Sprite(HGr, xDst, yDst, Width, Height, xGr, yGr: integer); 47 procedure TSprite(xDst, yDst, grix: integer; PureBlack: boolean = false); 48 49 public 50 property AdviceLoc: integer read FAdviceLoc write FAdviceLoc; 47 51 end; 48 52 49 50 53 const 51 // options switched by buttons 52 moPolitical=0; moCityNames=1; moGreatWall=4; moGrid=5; moBareTerrain=6; 53 54 // other options 55 moEditMode=16; moLocCodes=17; 56 54 // options switched by buttons 55 moPolitical = 0; 56 moCityNames = 1; 57 moGreatWall = 4; 58 moGrid = 5; 59 moBareTerrain = 6; 60 61 // other options 62 moEditMode = 16; 63 moLocCodes = 17; 57 64 58 65 var 59 NoMap: TIsoMap; 60 Options: integer; 61 pDebugMap: integer; //-1 for off 62 66 NoMap: TIsoMap; 67 Options: integer; 68 pDebugMap: integer; // -1 for off 63 69 64 70 function IsJungle(y: integer): boolean; … … 68 74 procedure Reset; 69 75 70 71 76 implementation 72 77 73 78 const 74 ShoreDither=fGrass;75 TerrainIconLines=21;79 ShoreDither = fGrass; 80 TerrainIconLines = 21; 76 81 77 82 var 78 BordersOK: integer;79 OnInitEnemyModel: TInitEnemyModelEvent;80 LandPatch,OceanPatch, Borders: TBitmap;81 TSpriteSize: array[0..TerrainIconLines*9-1] of TRect;82 DebugMap: ^TTileList;83 CitiesPictures: array[2..3,0..3] of TCityPicture;84 FoW, ShowLoc, ShowCityNames, ShowObjects, ShowBorder, ShowMyBorder,85 ShowGrWall, ShowDebug: boolean;83 BordersOK: integer; 84 OnInitEnemyModel: TInitEnemyModelEvent; 85 LandPatch, OceanPatch, Borders: TBitmap; 86 TSpriteSize: array [0 .. TerrainIconLines * 9 - 1] of TRect; 87 DebugMap: ^TTileList; 88 CitiesPictures: array [2 .. 3, 0 .. 3] of TCityPicture; 89 FoW, ShowLoc, ShowCityNames, ShowObjects, ShowBorder, ShowMyBorder, 90 ShowGrWall, ShowDebug: boolean; 86 91 87 92 function IsJungle(y: integer): boolean; 88 93 begin 89 result:= (y>(G.ly-2) div 4) and (G.ly-1-y>(G.ly-2) div 4)94 result := (y > (G.ly - 2) div 4) and (G.ly - 1 - y > (G.ly - 2) div 4) 90 95 end; 91 96 92 97 procedure Init(InitEnemyModelHandler: TInitEnemyModelEvent); 93 98 begin 94 OnInitEnemyModel:=InitEnemyModelHandler;95 if NoMap<>nil then96 NoMap.Free;97 NoMap:=TIsoMap.Create;99 OnInitEnemyModel := InitEnemyModelHandler; 100 if NoMap <> nil then 101 NoMap.Free; 102 NoMap := TIsoMap.Create; 98 103 end; 99 104 100 105 function ApplyTileSize(xxtNew, yytNew: integer): boolean; 101 106 type 102 TLine=array[0..INFIN,0..2] of Byte;107 TLine = array [0 .. INFIN, 0 .. 2] of Byte; 103 108 var 104 i,x,y,xSrc,ySrc,HGrTerrainNew,HGrCitiesNew,age,size:integer;105 LandMore,OceanMore,DitherMask,Mask24: TBitmap;106 MaskLine: array[0..32*3-1] of ^TLine; // 32 = assumed maximum for yyt107 Border: boolean;109 i, x, y, xSrc, ySrc, HGrTerrainNew, HGrCitiesNew, age, size: integer; 110 LandMore, OceanMore, DitherMask, Mask24: TBitmap; 111 MaskLine: array [0 .. 32 * 3 - 1] of ^TLine; // 32 = assumed maximum for yyt 112 Border: boolean; 108 113 begin 109 result:=false; 110 HGrTerrainNew:=LoadGraphicSet(Format('Terrain%dx%d',[xxtNew*2,yytNew*2])); 111 if HGrTerrainNew<0 then 112 exit; 113 HGrCitiesNew:=LoadGraphicSet(Format('Cities%dx%d',[xxtNew*2,yytNew*2])); 114 if HGrCitiesNew<0 then 115 exit; 116 xxt:=xxtNew; yyt:=yytNew; 117 HGrTerrain:=HGrTerrainNew; 118 HGrCities:=HGrCitiesNew; 119 result:=true; 120 121 // prepare age 2+3 cities 122 for age:=2 to 3 do 123 for size:=0 to 3 do with CitiesPictures[age,size] do 124 FindPosition(HGrCities,size*(xxt*2+1),(age-2)*(yyt*3+1),xxt*2-1,yyt*3-1, 125 $00FFFF,xShield,yShield); 126 127 {prepare dithered ground tiles} 128 if LandPatch<>nil then 129 LandPatch.Free; 130 LandPatch:=TBitmap.Create; 131 LandPatch.PixelFormat:=pf24bit; 132 LandPatch.Canvas.Brush.Color:=0; 133 LandPatch.Width:=xxt*18; LandPatch.Height:=yyt*9; 134 if OceanPatch<>nil then 135 OceanPatch.Free; 136 OceanPatch:=TBitmap.Create; 137 OceanPatch.PixelFormat:=pf24bit; 138 OceanPatch.Canvas.Brush.Color:=0; 139 OceanPatch.Width:=xxt*8; OceanPatch.Height:=yyt*4; 140 LandMore:=TBitmap.Create; 141 LandMore.PixelFormat:=pf24bit; 142 LandMore.Canvas.Brush.Color:=0; 143 LandMore.Width:=xxt*18; LandMore.Height:=yyt*9; 144 OceanMore:=TBitmap.Create; 145 OceanMore.PixelFormat:=pf24bit; 146 OceanMore.Canvas.Brush.Color:=0; 147 OceanMore.Width:=xxt*8; OceanMore.Height:=yyt*4; 148 DitherMask:=TBitmap.Create; 149 DitherMask.PixelFormat:=pf24bit; 150 DitherMask.Width:=xxt*2; DitherMask.Height:=yyt*2; 151 BitBlt(DitherMask.Canvas.Handle,0,0,xxt*2,yyt*2, 152 GrExt[HGrTerrain].Mask.Canvas.Handle,1+7*(xxt*2+1),1+yyt+15*(yyt*3+1),SRCAND); 153 154 for x:=-1 to 6 do 114 result := false; 115 HGrTerrainNew := LoadGraphicSet(Format('Terrain%dx%d', 116 [xxtNew * 2, yytNew * 2])); 117 if HGrTerrainNew < 0 then 118 exit; 119 HGrCitiesNew := LoadGraphicSet(Format('Cities%dx%d', 120 [xxtNew * 2, yytNew * 2])); 121 if HGrCitiesNew < 0 then 122 exit; 123 xxt := xxtNew; 124 yyt := yytNew; 125 HGrTerrain := HGrTerrainNew; 126 HGrCities := HGrCitiesNew; 127 result := true; 128 129 // prepare age 2+3 cities 130 for age := 2 to 3 do 131 for size := 0 to 3 do 132 with CitiesPictures[age, size] do 133 FindPosition(HGrCities, size * (xxt * 2 + 1), (age - 2) * (yyt * 3 + 1), 134 xxt * 2 - 1, yyt * 3 - 1, $00FFFF, xShield, yShield); 135 136 { prepare dithered ground tiles } 137 if LandPatch <> nil then 138 LandPatch.Free; 139 LandPatch := TBitmap.Create; 140 LandPatch.PixelFormat := pf24bit; 141 LandPatch.Canvas.Brush.Color := 0; 142 LandPatch.Width := xxt * 18; 143 LandPatch.Height := yyt * 9; 144 if OceanPatch <> nil then 145 OceanPatch.Free; 146 OceanPatch := TBitmap.Create; 147 OceanPatch.PixelFormat := pf24bit; 148 OceanPatch.Canvas.Brush.Color := 0; 149 OceanPatch.Width := xxt * 8; 150 OceanPatch.Height := yyt * 4; 151 LandMore := TBitmap.Create; 152 LandMore.PixelFormat := pf24bit; 153 LandMore.Canvas.Brush.Color := 0; 154 LandMore.Width := xxt * 18; 155 LandMore.Height := yyt * 9; 156 OceanMore := TBitmap.Create; 157 OceanMore.PixelFormat := pf24bit; 158 OceanMore.Canvas.Brush.Color := 0; 159 OceanMore.Width := xxt * 8; 160 OceanMore.Height := yyt * 4; 161 DitherMask := TBitmap.Create; 162 DitherMask.PixelFormat := pf24bit; 163 DitherMask.Width := xxt * 2; 164 DitherMask.Height := yyt * 2; 165 BitBlt(DitherMask.Canvas.Handle, 0, 0, xxt * 2, yyt * 2, 166 GrExt[HGrTerrain].Mask.Canvas.Handle, 1 + 7 * (xxt * 2 + 1), 167 1 + yyt + 15 * (yyt * 3 + 1), SRCAND); 168 169 for x := -1 to 6 do 155 170 begin 156 if x=-1 then begin xSrc:=ShoreDither*(xxt*2+1)+1; ySrc:=1+yyt end 157 else if x=6 then begin xSrc:=1+(xxt*2+1)*2; ySrc:=1+yyt+(yyt*3+1)*2 end 158 else begin xSrc:=(x+2)*(xxt*2+1)+1; ySrc:=1+yyt end; 159 for y:=-1 to 6 do 160 BitBlt(LandPatch.Canvas.Handle,(x+2)*(xxt*2),(y+2)*yyt,xxt*2,yyt, 161 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc,ySrc,SRCCOPY); 162 for y:=-2 to 6 do 163 BitBlt(LandPatch.Canvas.Handle,(x+2)*(xxt*2),(y+2)*yyt,xxt,yyt, 164 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc+xxt,ySrc+yyt,SRCPAINT); 165 for y:=-2 to 6 do 166 BitBlt(LandPatch.Canvas.Handle,(x+2)*(xxt*2)+xxt,(y+2)*yyt,xxt,yyt, 167 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc,ySrc+yyt,SRCPAINT); 168 for y:=-2 to 6 do 169 BitBlt(LandPatch.Canvas.Handle,(x+2)*(xxt*2),(y+2)*yyt,xxt,yyt, 170 DitherMask.Canvas.Handle,xxt,yyt,SRCAND); 171 for y:=-2 to 6 do 172 BitBlt(LandPatch.Canvas.Handle,(x+2)*(xxt*2)+xxt,(y+2)*yyt,xxt,yyt, 173 DitherMask.Canvas.Handle,0,yyt,SRCAND); 171 if x = -1 then 172 begin 173 xSrc := ShoreDither * (xxt * 2 + 1) + 1; 174 ySrc := 1 + yyt 175 end 176 else if x = 6 then 177 begin 178 xSrc := 1 + (xxt * 2 + 1) * 2; 179 ySrc := 1 + yyt + (yyt * 3 + 1) * 2 180 end 181 else 182 begin 183 xSrc := (x + 2) * (xxt * 2 + 1) + 1; 184 ySrc := 1 + yyt 185 end; 186 for y := -1 to 6 do 187 BitBlt(LandPatch.Canvas.Handle, (x + 2) * (xxt * 2), (y + 2) * yyt, 188 xxt * 2, yyt, GrExt[HGrTerrain].Data.Canvas.Handle, xSrc, ySrc, 189 SRCCOPY); 190 for y := -2 to 6 do 191 BitBlt(LandPatch.Canvas.Handle, (x + 2) * (xxt * 2), (y + 2) * yyt, xxt, 192 yyt, GrExt[HGrTerrain].Data.Canvas.Handle, xSrc + xxt, ySrc + yyt, 193 SRCPAINT); 194 for y := -2 to 6 do 195 BitBlt(LandPatch.Canvas.Handle, (x + 2) * (xxt * 2) + xxt, (y + 2) * yyt, 196 xxt, yyt, GrExt[HGrTerrain].Data.Canvas.Handle, xSrc, ySrc + yyt, 197 SRCPAINT); 198 for y := -2 to 6 do 199 BitBlt(LandPatch.Canvas.Handle, (x + 2) * (xxt * 2), (y + 2) * yyt, xxt, 200 yyt, DitherMask.Canvas.Handle, xxt, yyt, SRCAND); 201 for y := -2 to 6 do 202 BitBlt(LandPatch.Canvas.Handle, (x + 2) * (xxt * 2) + xxt, (y + 2) * yyt, 203 xxt, yyt, DitherMask.Canvas.Handle, 0, yyt, SRCAND); 174 204 end; 175 205 176 for y:=-1 to 6 do206 for y := -1 to 6 do 177 207 begin 178 if y=-1 then begin xSrc:=ShoreDither*(xxt*2+1)+1; ySrc:=1+yyt end 179 else if y=6 then begin xSrc:=1+2*(xxt*2+1); ySrc:=1+yyt+2*(yyt*3+1) end 180 else begin xSrc:=(y+2)*(xxt*2+1)+1; ySrc:=1+yyt end; 181 for x:=-2 to 6 do 182 BitBlt(LandMore.Canvas.Handle,(x+2)*(xxt*2),(y+2)*yyt,xxt*2,yyt, 183 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc,ySrc,SRCCOPY); 184 BitBlt(LandMore.Canvas.Handle,xxt*2,(y+2)*yyt,xxt,yyt, 185 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc+xxt,ySrc+yyt,SRCPAINT); 186 for x:=0 to 7 do 187 BitBlt(LandMore.Canvas.Handle,(x+2)*(xxt*2)-xxt,(y+2)*yyt,xxt*2,yyt, 188 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc,ySrc+yyt,SRCPAINT); 189 for x:=-2 to 6 do 190 BitBlt(LandMore.Canvas.Handle,(x+2)*(xxt*2),(y+2)*yyt,xxt*2,yyt, 191 DitherMask.Canvas.Handle,0,0,SRCAND); 208 if y = -1 then 209 begin 210 xSrc := ShoreDither * (xxt * 2 + 1) + 1; 211 ySrc := 1 + yyt 212 end 213 else if y = 6 then 214 begin 215 xSrc := 1 + 2 * (xxt * 2 + 1); 216 ySrc := 1 + yyt + 2 * (yyt * 3 + 1) 217 end 218 else 219 begin 220 xSrc := (y + 2) * (xxt * 2 + 1) + 1; 221 ySrc := 1 + yyt 222 end; 223 for x := -2 to 6 do 224 BitBlt(LandMore.Canvas.Handle, (x + 2) * (xxt * 2), (y + 2) * yyt, 225 xxt * 2, yyt, GrExt[HGrTerrain].Data.Canvas.Handle, xSrc, ySrc, 226 SRCCOPY); 227 BitBlt(LandMore.Canvas.Handle, xxt * 2, (y + 2) * yyt, xxt, yyt, 228 GrExt[HGrTerrain].Data.Canvas.Handle, xSrc + xxt, ySrc + yyt, SRCPAINT); 229 for x := 0 to 7 do 230 BitBlt(LandMore.Canvas.Handle, (x + 2) * (xxt * 2) - xxt, (y + 2) * yyt, 231 xxt * 2, yyt, GrExt[HGrTerrain].Data.Canvas.Handle, xSrc, ySrc + yyt, 232 SRCPAINT); 233 for x := -2 to 6 do 234 BitBlt(LandMore.Canvas.Handle, (x + 2) * (xxt * 2), (y + 2) * yyt, 235 xxt * 2, yyt, DitherMask.Canvas.Handle, 0, 0, SRCAND); 192 236 end; 193 237 194 for x:=0 to 3 do for y:=0 to 3 do 238 for x := 0 to 3 do 239 for y := 0 to 3 do 240 begin 241 if (x = 1) and (y = 1) then 242 xSrc := 1 243 else 244 xSrc := (x mod 2) * (xxt * 2 + 1) + 1; 245 ySrc := 1 + yyt; 246 if (x >= 1) = (y >= 2) then 247 BitBlt(OceanPatch.Canvas.Handle, x * (xxt * 2), y * yyt, xxt * 2, yyt, 248 GrExt[HGrTerrain].Data.Canvas.Handle, xSrc, ySrc, SRCCOPY); 249 if (x >= 1) and ((y < 2) or (x >= 2)) then 250 begin 251 BitBlt(OceanPatch.Canvas.Handle, x * (xxt * 2), y * yyt, xxt, yyt, 252 GrExt[HGrTerrain].Data.Canvas.Handle, xSrc + xxt, ySrc + yyt, 253 SRCPAINT); 254 BitBlt(OceanPatch.Canvas.Handle, x * (xxt * 2) + xxt, y * yyt, xxt, yyt, 255 GrExt[HGrTerrain].Data.Canvas.Handle, xSrc, ySrc + yyt, SRCPAINT); 256 end; 257 BitBlt(OceanPatch.Canvas.Handle, x * (xxt * 2), y * yyt, xxt, yyt, 258 DitherMask.Canvas.Handle, xxt, yyt, SRCAND); 259 BitBlt(OceanPatch.Canvas.Handle, x * (xxt * 2) + xxt, y * yyt, xxt, yyt, 260 DitherMask.Canvas.Handle, 0, yyt, SRCAND); 261 end; 262 263 for y := 0 to 3 do 264 for x := 0 to 3 do 265 begin 266 if (x = 1) and (y = 1) then 267 xSrc := 1 268 else 269 xSrc := (y mod 2) * (xxt * 2 + 1) + 1; 270 ySrc := 1 + yyt; 271 if (x < 1) or (y >= 2) then 272 BitBlt(OceanMore.Canvas.Handle, x * (xxt * 2), y * yyt, xxt * 2, yyt, 273 GrExt[HGrTerrain].Data.Canvas.Handle, xSrc, ySrc, SRCCOPY); 274 if (x = 1) and (y < 2) or (x >= 2) and (y >= 1) then 275 begin 276 BitBlt(OceanMore.Canvas.Handle, x * (xxt * 2), y * yyt, xxt, yyt, 277 GrExt[HGrTerrain].Data.Canvas.Handle, xSrc + xxt, ySrc + yyt, 278 SRCPAINT); 279 BitBlt(OceanMore.Canvas.Handle, x * (xxt * 2) + xxt, y * yyt, xxt, yyt, 280 GrExt[HGrTerrain].Data.Canvas.Handle, xSrc, ySrc + yyt, SRCPAINT); 281 end; 282 BitBlt(OceanMore.Canvas.Handle, x * (xxt * 2), y * yyt, xxt * 2, yyt, 283 DitherMask.Canvas.Handle, 0, 0, SRCAND); 284 end; 285 286 BitBlt(DitherMask.Canvas.Handle, 0, 0, xxt * 2, yyt * 2, 287 DitherMask.Canvas.Handle, 0, 0, DSTINVERT); { invert dither mask } 288 BitBlt(DitherMask.Canvas.Handle, 0, 0, xxt * 2, yyt * 2, 289 GrExt[HGrTerrain].Mask.Canvas.Handle, 1, 1 + yyt, SRCPAINT); 290 291 for x := -1 to 6 do 292 for y := -2 to 6 do 293 BitBlt(LandPatch.Canvas.Handle, (x + 2) * (xxt * 2), (y + 2) * yyt, 294 xxt * 2, yyt, DitherMask.Canvas.Handle, 0, 0, SRCAND); 295 296 for y := -1 to 6 do 297 for x := -2 to 7 do 298 BitBlt(LandMore.Canvas.Handle, (x + 2) * (xxt * 2) - xxt, (y + 2) * yyt, 299 xxt * 2, yyt, DitherMask.Canvas.Handle, 0, yyt, SRCAND); 300 301 BitBlt(LandPatch.Canvas.Handle, 0, 0, (xxt * 2) * 9, yyt * 9, 302 LandMore.Canvas.Handle, 0, 0, SRCPAINT); 303 304 for x := 0 to 3 do 305 for y := 0 to 3 do 306 BitBlt(OceanPatch.Canvas.Handle, x * (xxt * 2), y * yyt, xxt * 2, yyt, 307 DitherMask.Canvas.Handle, 0, 0, SRCAND); 308 309 for y := 0 to 3 do 310 for x := 0 to 4 do 311 BitBlt(OceanMore.Canvas.Handle, x * (xxt * 2) - xxt, y * yyt, xxt * 2, 312 yyt, DitherMask.Canvas.Handle, 0, yyt, SRCAND); 313 314 BitBlt(OceanPatch.Canvas.Handle, 0, 0, (xxt * 2) * 4, yyt * 4, 315 OceanMore.Canvas.Handle, 0, 0, SRCPAINT); 316 317 with DitherMask.Canvas do 195 318 begin 196 if (x=1) and (y=1) then xSrc:=1 197 else xSrc:=(x mod 2)*(xxt*2+1)+1; 198 ySrc:=1+yyt; 199 if (x>=1)=(y>=2) then 200 BitBlt(OceanPatch.Canvas.Handle,x*(xxt*2),y*yyt,xxt*2,yyt, 201 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc,ySrc,SRCCOPY); 202 if (x>=1) and ((y<2) or (x>=2)) then 319 Brush.Color := $FFFFFF; 320 FillRect(Rect(0, 0, xxt * 2, yyt)); 321 end; 322 BitBlt(DitherMask.Canvas.Handle, 0, 0, xxt * 2, yyt, 323 GrExt[HGrTerrain].Mask.Canvas.Handle, 1, 1 + yyt, SRCCOPY); 324 325 for x := 0 to 6 do 326 BitBlt(LandPatch.Canvas.Handle, (x + 2) * (xxt * 2), yyt, xxt * 2, yyt, 327 DitherMask.Canvas.Handle, 0, 0, SRCAND); 328 329 BitBlt(DitherMask.Canvas.Handle, 0, 0, xxt * 2, yyt, DitherMask.Canvas.Handle, 330 0, 0, DSTINVERT); 331 332 for y := 0 to 6 do 333 BitBlt(LandPatch.Canvas.Handle, xxt * 2, (y + 2) * yyt, xxt * 2, yyt, 334 DitherMask.Canvas.Handle, 0, 0, SRCAND); 335 336 LandMore.Free; 337 OceanMore.Free; 338 DitherMask.Free; 339 // LandPatch.Savetofile('landpatch.bmp'); 340 341 // reduce size of terrain icons 342 Mask24 := TBitmap.Create; 343 Mask24.Assign(GrExt[HGrTerrain].Mask); 344 Mask24.PixelFormat := pf24bit; 345 for ySrc := 0 to TerrainIconLines - 1 do 346 begin 347 for i := 0 to yyt * 3 - 1 do 348 MaskLine[i] := Mask24.ScanLine[1 + ySrc * (yyt * 3 + 1) + i]; 349 for xSrc := 0 to 9 - 1 do 203 350 begin 204 BitBlt(OceanPatch.Canvas.Handle,x*(xxt*2),y*yyt,xxt,yyt, 205 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc+xxt,ySrc+yyt,SRCPAINT); 206 BitBlt(OceanPatch.Canvas.Handle,x*(xxt*2)+xxt,y*yyt,xxt,yyt, 207 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc,ySrc+yyt,SRCPAINT); 208 end; 209 BitBlt(OceanPatch.Canvas.Handle,x*(xxt*2),y*yyt,xxt,yyt, 210 DitherMask.Canvas.Handle,xxt,yyt,SRCAND); 211 BitBlt(OceanPatch.Canvas.Handle,x*(xxt*2)+xxt,y*yyt,xxt,yyt, 212 DitherMask.Canvas.Handle,0,yyt,SRCAND); 213 end; 214 215 for y:=0 to 3 do for x:=0 to 3 do 216 begin 217 if (x=1) and (y=1) then xSrc:=1 218 else xSrc:=(y mod 2)*(xxt*2+1)+1; 219 ySrc:=1+yyt; 220 if (x<1) or (y>=2) then 221 BitBlt(OceanMore.Canvas.Handle,x*(xxt*2),y*yyt,xxt*2,yyt, 222 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc,ySrc,SRCCOPY); 223 if (x=1) and (y<2) or (x>=2) and (y>=1) then 224 begin 225 BitBlt(OceanMore.Canvas.Handle,x*(xxt*2),y*yyt,xxt,yyt, 226 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc+xxt,ySrc+yyt,SRCPAINT); 227 BitBlt(OceanMore.Canvas.Handle,x*(xxt*2)+xxt,y*yyt,xxt,yyt, 228 GrExt[HGrTerrain].Data.Canvas.Handle,xSrc,ySrc+yyt,SRCPAINT); 229 end; 230 BitBlt(OceanMore.Canvas.Handle,x*(xxt*2),y*yyt,xxt*2,yyt, 231 DitherMask.Canvas.Handle,0,0,SRCAND); 232 end; 233 234 BitBlt(DitherMask.Canvas.Handle,0,0,xxt*2,yyt*2, 235 DitherMask.Canvas.Handle,0,0,DSTINVERT); {invert dither mask} 236 BitBlt(DitherMask.Canvas.Handle,0,0,xxt*2,yyt*2, 237 GrExt[HGrTerrain].Mask.Canvas.Handle,1,1+yyt,SRCPAINT); 238 239 for x:=-1 to 6 do 240 for y:=-2 to 6 do 241 BitBlt(LandPatch.Canvas.Handle,(x+2)*(xxt*2),(y+2)*yyt,xxt*2,yyt, 242 DitherMask.Canvas.Handle,0,0,SRCAND); 243 244 for y:=-1 to 6 do 245 for x:=-2 to 7 do 246 BitBlt(LandMore.Canvas.Handle,(x+2)*(xxt*2)-xxt,(y+2)*yyt,xxt*2,yyt, 247 DitherMask.Canvas.Handle,0,yyt,SRCAND); 248 249 BitBlt(LandPatch.Canvas.Handle,0,0,(xxt*2)*9,yyt*9,LandMore.Canvas.Handle,0,0, 250 SRCPAINT); 251 252 for x:=0 to 3 do 253 for y:=0 to 3 do 254 BitBlt(OceanPatch.Canvas.Handle,x*(xxt*2),y*yyt,xxt*2,yyt, 255 DitherMask.Canvas.Handle,0,0,SRCAND); 256 257 for y:=0 to 3 do 258 for x:=0 to 4 do 259 BitBlt(OceanMore.Canvas.Handle,x*(xxt*2)-xxt,y*yyt,xxt*2,yyt, 260 DitherMask.Canvas.Handle,0,yyt,SRCAND); 261 262 BitBlt(OceanPatch.Canvas.Handle,0,0,(xxt*2)*4,yyt*4,OceanMore.Canvas.Handle,0,0, 263 SRCPAINT); 264 265 with DitherMask.Canvas do 266 begin 267 Brush.Color:=$FFFFFF; 268 FillRect(Rect(0,0,xxt*2,yyt)); 269 end; 270 BitBlt(DitherMask.Canvas.Handle,0,0,xxt*2,yyt, 271 GrExt[HGrTerrain].Mask.Canvas.Handle,1,1+yyt,SRCCOPY); 272 273 for x:=0 to 6 do 274 BitBlt(LandPatch.Canvas.Handle,(x+2)*(xxt*2),yyt,xxt*2,yyt, 275 DitherMask.Canvas.Handle,0,0,SRCAND); 276 277 BitBlt(DitherMask.Canvas.Handle,0,0,xxt*2,yyt, 278 DitherMask.Canvas.Handle,0,0,DSTINVERT); 279 280 for y:=0 to 6 do 281 BitBlt(LandPatch.Canvas.Handle,xxt*2,(y+2)*yyt,xxt*2,yyt, 282 DitherMask.Canvas.Handle,0,0,SRCAND); 283 284 LandMore.Free; OceanMore.Free; DitherMask.Free; 285 //LandPatch.Savetofile('landpatch.bmp'); 286 287 // reduce size of terrain icons 288 Mask24:=TBitmap.Create; 289 Mask24.Assign(GrExt[HGrTerrain].Mask); 290 Mask24.PixelFormat:=pf24bit; 291 for ySrc:=0 to TerrainIconLines-1 do 292 begin 293 for i:=0 to yyt*3-1 do 294 MaskLine[i]:=Mask24.ScanLine[1+ySrc*(yyt*3+1)+i]; 295 for xSrc:=0 to 9-1 do 296 begin 297 i:=ySrc*9+xSrc; 298 TSpriteSize[i].Left:=0; 299 repeat 300 Border:=true; 301 for y:=0 to yyt*3-1 do 302 if MaskLine[y]^[1+xSrc*(xxt*2+1)+TSpriteSize[i].Left,0]=0 then 303 Border:=false; 304 if Border then inc(TSpriteSize[i].Left) 305 until not Border or (TSpriteSize[i].Left=xxt*2-1); 306 TSpriteSize[i].Top:=0; 307 repeat 308 Border:=true; 309 for x:=0 to xxt*2-1 do 310 if MaskLine[TSpriteSize[i].Top]^[1+xSrc*(xxt*2+1)+x,0]=0 then 311 Border:=false; 312
