source: branches/AlphaChannel/Start.pas

Last change on this file was 261, checked in by chronos, 4 years ago
  • Added: Partial support for key bindings configuration.
File size: 71.5 KB
Line 
1{$INCLUDE Switches.inc}
2unit Start;
3
4interface
5
6uses
7 GameServer, Messg, ButtonBase, ButtonA, ButtonC, ButtonB, Area,
8 LCLIntf, LCLType, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls,
9 Menus, Registry, DrawDlg, fgl, Protocol;
10
11type
12 TPlayerSlot = class
13 DiffUpBtn: TButtonC;
14 DiffDownBtn: TButtonC;
15 MultiBtn: TButtonC;
16 OfferMultiple: Boolean;
17 Rect: TRect;
18 end;
19
20 TPlayerSlots = class(TFPGObjectList<TPlayerSlot>)
21 end;
22
23 TStartPage = (
24 pgStartRandom,
25 pgStartMap,
26 pgNoLoad,
27 pgLoad,
28 pgEditRandom,
29 pgEditMap,
30 pgMain
31 );
32
33 TStartTab = (tbMain, tbMap, tbNew, tbPrevious);
34 TMainAction = (maConfig, maManual, maCredits, maAIDev, maWeb, maNone);
35 TMainActionSet = set of TMainAction;
36
37 TMapArray = array[0 .. lxmax * lymax - 1] of Byte;
38
39 TMiniMode = (mmNone, mmPicture, mmMultiPlayer);
40
41 { TMiniMap }
42
43 TMiniMap = class
44 const
45 MaxWidthMapLogo = 96;
46 MaxHeightMapLogo = 96;
47 var
48 Bitmap: TBitmap; { game world sample preview }
49 Size: TPoint;
50 Colors: array [0 .. 11, 0 .. 1] of TColor;
51 Mode: TMiniMode;
52 procedure LoadFromLogFile(FileName: string; var LastTurn: Integer);
53 procedure LoadFromMapFile(FileName: string; var nMapLandTiles, nMapStartPositions: Integer);
54 procedure PaintRandom(Brightness, StartLandMass, WorldSize: Integer);
55 procedure PaintFile(SaveMap: TMapArray);
56 constructor Create;
57 destructor Destroy; override;
58 end;
59
60 { TStartDlg }
61
62 TStartDlg = class(TDrawDlg)
63 PopupMenu1: TPopupMenu;
64 StartBtn: TButtonA;
65 Down1Btn: TButtonC;
66 Up1Btn: TButtonC;
67 List: TListBox;
68 RenameBtn: TButtonB;
69 DeleteBtn: TButtonB;
70 Down2Btn: TButtonC;
71 Up2Btn: TButtonC;
72 QuitBtn: TButtonB;
73 CustomizeBtn: TButtonC;
74 AutoDiffUpBtn: TButtonC;
75 AutoDiffDownBtn: TButtonC;
76 AutoEnemyUpBtn: TButtonC;
77 AutoEnemyDownBtn: TButtonC;
78 ReplayBtn: TButtonB;
79 procedure StartBtnClick(Sender: TObject);
80 procedure FormPaint(Sender: TObject);
81 procedure FormShow(Sender: TObject);
82 procedure FormHide(Sender: TObject);
83 procedure FormClose(Sender: TObject; var Action: TCloseAction);
84 procedure FormCreate(Sender: TObject);
85 procedure FormDestroy(Sender: TObject);
86 procedure BrainClick(Sender: TObject);
87 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
88 procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
89 Shift: TShiftState; x, y: integer);
90 procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
91 Shift: TShiftState; x, y: integer);
92 procedure FormMouseMove(Sender: TObject; Shift: TShiftState; x, y: integer);
93 procedure Up1BtnClick(Sender: TObject);
94 procedure Down1BtnClick(Sender: TObject);
95 procedure ListClick(Sender: TObject);
96 procedure RenameBtnClick(Sender: TObject);
97 procedure DeleteBtnClick(Sender: TObject);
98 procedure DiffBtnClick(Sender: TObject);
99 procedure MultiBtnClick(Sender: TObject);
100 procedure Up2BtnClick(Sender: TObject);
101 procedure Down2BtnClick(Sender: TObject);
102 procedure QuitBtnClick(Sender: TObject);
103 procedure CustomizeBtnClick(Sender: TObject);
104 procedure AutoDiffUpBtnClick(Sender: TObject);
105 procedure AutoDiffDownBtnClick(Sender: TObject);
106 procedure AutoEnemyUpBtnClick(Sender: TObject);
107 procedure AutoEnemyDownBtnClick(Sender: TObject);
108 procedure ReplayBtnClick(Sender: TObject);
109 public
110 EmptyPicture: TBitmap;
111 procedure UpdateFormerGames;
112 procedure UpdateMaps;
113 private
114 WorldSize: Integer;
115 StartLandMass: Integer;
116 MaxTurn: Integer;
117 AutoEnemies: Integer;
118 AutoDiff: Integer;
119 MultiControl: Integer;
120 Page: TStartPage;
121 ShowTab: TStartTab;
122 Tab: TStartTab;
123 Diff0: Integer;
124 BrainDefault: TBrain;
125 nMapLandTiles: Integer;
126 nMapStartPositions: Integer;
127 LoadTurn: Integer;
128 LastTurn: Integer;
129 { last turn of selected former game }
130 SlotAvailable: Integer;
131 PlayerPopupIndex: Integer; { brain concerned by brain context menu }
132 ListIndex: array [TStartTab] of Integer;
133 MapFileName: string;
134 FormerGames: TStringList;
135 Maps: TStringList;
136 LogoBuffer: TBitmap;
137 // BookDate: string;
138 PlayerSlots: TPlayerSlots;
139 ActionsOffered: TMainActionSet;
140 SelectedAction: TMainAction;
141 TurnValid: Boolean;
142 Tracking: Boolean;
143 DefaultAI: string;
144 MiniMap: TMiniMap;
145 procedure DrawAction(y, IconIndex: integer; HeaderItem, TextItem: string);
146 procedure InitPopup(PlayerIndex: Integer);
147 procedure OfferBrain(Brain: TBrain; FixedLines: Integer);
148 procedure PaintInfo;
149 procedure ChangePage(NewPage: TStartPage);
150 procedure ChangeTab(NewTab: TStartTab);
151 procedure UnlistBackupFile(FileName: string);
152 procedure SmartInvalidate(x0, y0, x1, y1: integer;
153 invalidateTab0: boolean = false); overload;
154 procedure LoadConfig;
155 procedure SaveConfig;
156 procedure LoadAiBrainsPictures;
157 procedure UpdateInterface;
158 end;
159
160var
161 StartDlg: TStartDlg;
162
163
164implementation
165
166uses
167 Global, Directories, Direct, ScreenTools, Inp, Back, Settings, UPixelPointer,
168 UKeyBindings;
169
170{$R *.lfm}
171
172const
173 // predefined world size
174 // attention: lx*ly+1 must be prime!
175 { MaxWorldSize=8;
176 lxpre: array[0..nWorldSize-1] of integer =(30,40,50,60,70,90,110,130);
177 lypre: array[0..nWorldSize-1] of integer =(46,52,60,70,84,94,110,130);
178 DefaultWorldTiles=4200; }
179 MaxWorldSize = 6;
180 WorldSizes: array [0 .. MaxWorldSize - 1] of TPoint = ((X: 30; Y: 46),
181 (X: 40; Y: 52), (X: 50; Y: 60), (X: 60; Y: 70), (X: 75; Y: 82),
182 (X: 100; Y: 96));
183 DefaultWorldTiles = 4150;
184 DefaultWorldSize = 3;
185 DefaultLandMass = 30;
186
187 nPlOffered = 9;
188 yMain = 14;
189 xActionIcon = 55;
190 xAction = 111;
191 yAction = 60;
192 ActionPitch = 56;
193 ActionSideBorder = 24;
194 ActionBottomBorder = 10;
195 wBuffer = 91;
196 x0Mini = 437;
197 y0Mini = 178;
198 xTurnSlider = 346;
199 yTurnSlider = 262;
200 wTurnSlider = 168;
201 yLogo = 74;
202 xDefault = 234;
203 yDefault = 148;
204 x0Brain = 146;
205 y0Brain = 148;
206 dxBrain = 104;
207 dyBrain = 80;
208 xBrain: array [0 .. nPlOffered - 1] of integer = (x0Brain, x0Brain,
209 x0Brain + dxBrain, x0Brain + dxBrain, x0Brain + dxBrain, x0Brain,
210 x0Brain - dxBrain, x0Brain - dxBrain, x0Brain - dxBrain);
211 yBrain: array [0 .. nPlOffered - 1] of integer = (y0Brain, y0Brain - dyBrain,
212 y0Brain - dyBrain, y0Brain, y0Brain + dyBrain, y0Brain + dyBrain,
213 y0Brain + dyBrain, y0Brain, y0Brain - dyBrain);
214 TabOffset = -115;
215 TabSize = 159;
216 TabHeight = 40;
217
218 InitAlive: array [1 .. nPl] of integer = (1, 1 + 2, 1 + 2 + 32,
219 1 + 2 + 8 + 128, 1 + 2 + 8 + 32 + 128, 1 + 2 + 8 + 16 + 64 + 128,
220 1 + 2 + 4 + 16 + 32 + 64 + 256, 511 - 32, 511, 511 - 32, 511, 511 - 32, 511,
221 511 - 32, 511);
222 InitMulti: array [nPlOffered + 1 .. nPl] of integer = (256, 256, 256 + 128,
223 256 + 128, 256 + 128 + 64, 256 + 128 + 64);
224
225 PlayerAutoDiff: array [1 .. 5] of integer = (1, 1, 2, 2, 3);
226 EnemyAutoDiff: array [1 .. 5] of integer = (4, 3, 2, 1, 1);
227 KeyBindingsFileName = 'KeyBindings.txt';
228
229{ TMiniMap }
230
231constructor TMiniMap.Create;
232var
233 X, Y: Integer;
234begin
235 Bitmap := TBitmap.Create;
236
237 for X := 0 to 11 do
238 for Y := 0 to 1 do
239 Colors[x, y] := GrExt[HGrSystem].Data.Canvas.Pixels[66 + x, 67 + y];
240end;
241
242destructor TMiniMap.Destroy;
243begin
244 FreeAndNil(Bitmap);
245 inherited Destroy;
246end;
247
248procedure TMiniMap.LoadFromLogFile(FileName: string; var LastTurn: Integer);
249var
250 SaveMap: TMapArray;
251 y: Integer;
252 Dummy: Integer;
253 FileLandMass: integer;
254 LogFile: file;
255 s: string[255];
256 MapRow: array [0 .. lxmax - 1] of Cardinal;
257begin
258 AssignFile(LogFile, FileName);
259 try
260 Reset(LogFile, 4);
261 BlockRead(LogFile, s[1], 2); { file id }
262 BlockRead(LogFile, Dummy, 1); { format id }
263 if Dummy >= $000E01 then
264 BlockRead(LogFile, Dummy, 1); { item stored since 0.14.1 }
265 BlockRead(LogFile, Size.X, 1);
266 BlockRead(LogFile, Size.Y, 1);
267 BlockRead(LogFile, FileLandMass, 1);
268 if FileLandMass = 0 then
269 for y := 0 to Size.Y - 1 do
270 BlockRead(LogFile, MapRow, Size.X);
271 BlockRead(LogFile, Dummy, 1);
272 BlockRead(LogFile, Dummy, 1);
273 BlockRead(LogFile, LastTurn, 1);
274 BlockRead(LogFile, SaveMap, 1);
275 if SaveMap[0] = $80 then
276 Mode := mmMultiPlayer
277 else
278 Mode := mmPicture;
279 if Mode = mmPicture then
280 BlockRead(LogFile, SaveMap[4], (Size.X * Size.Y - 1) div 4);
281 CloseFile(LogFile);
282 except
283 CloseFile(LogFile);
284 LastTurn := 0;
285 Size := WorldSizes[DefaultWorldSize];
286 Mode := mmNone;
287 end;
288 PaintFile(SaveMap);
289end;
290
291procedure TMiniMap.LoadFromMapFile(FileName: string; var nMapLandTiles, nMapStartPositions: Integer);
292var
293 x, y, lxFile, lyFile: integer;
294 MapFile: file;
295 s: string[255];
296 MapRow: array [0 .. lxmax - 1] of Cardinal;
297 ImageFileName: string;
298begin
299 ImageFileName := Copy(FileName, 1, Length(FileName) - Length(CevoMapExt)) + '.png';
300 Mode := mmPicture;
301 if LoadGraphicFile(Bitmap, ImageFileName, gfNoError) then
302 begin
303 if Bitmap.width div 2 > MaxWidthMapLogo then
304 Bitmap.width := MaxWidthMapLogo * 2;
305 if Bitmap.height > MaxHeightMapLogo then
306 Bitmap.height := MaxHeightMapLogo;
307 Size.X := Bitmap.width div 2;
308 Size.Y := Bitmap.height;
309 end
310 else
311 begin
312 Mode := mmNone;
313 Size.X := MaxWidthMapLogo;
314 Size.Y := MaxHeightMapLogo;
315 end;
316
317 AssignFile(MapFile, FileName);
318 try
319 Reset(MapFile, 4);
320 BlockRead(MapFile, s[1], 2); { file id }
321 BlockRead(MapFile, x, 1); { format id }
322 BlockRead(MapFile, x, 1); // MaxTurn
323 BlockRead(MapFile, lxFile, 1);
324 BlockRead(MapFile, lyFile, 1);
325 nMapLandTiles := 0;
326 nMapStartPositions := 0;
327 for y := 0 to lyFile - 1 do begin
328 BlockRead(MapFile, MapRow, lxFile);
329 for x := 0 to lxFile - 1 do
330 begin
331 if (MapRow[x] and fTerrain) in [fGrass, fPrairie, fTundra, fSwamp,
332 fForest, fHills] then
333 inc(nMapLandTiles);
334 if MapRow[x] and (fPrefStartPos or fStartPos) <> 0 then
335 inc(nMapStartPositions);
336 end
337 end;
338 if nMapStartPositions > nPl then
339 nMapStartPositions := nPl;
340 CloseFile(MapFile);
341 except
342 CloseFile(MapFile);
343 end;
344end;
345
346procedure TMiniMap.PaintRandom(Brightness, StartLandMass, WorldSize: Integer);
347var
348 i, x, y, xm, cm: Integer;
349 MiniPixel: TPixelPointer;
350 Map: ^TTileList;
351begin
352 Map := PreviewMap(StartLandMass);
353 Size := WorldSizes[WorldSize];
354
355 Bitmap.PixelFormat := pf24bit;
356 Bitmap.SetSize(Size.X * 2, Size.Y);
357 Bitmap.BeginUpdate;
358 MiniPixel := PixelPointer(Bitmap);
359 for y := 0 to ScaleToNative(Size.Y) - 1 do begin
360 for x := 0 to ScaleToNative(Size.X) - 1 do begin
361 for i := 0 to 1 do begin
362 xm := (x * 2 + i + y and 1) mod (ScaleToNative(Size.X) * 2);
363 MiniPixel.SetX(xm);
364 cm := Colors
365 [Map[ScaleFromNative(x) * lxmax div Size.X + lxmax *
366 ((ScaleFromNative(y) * (lymax - 1) + Size.Y div 2) div (Size.Y - 1))] and
367 fTerrain, i];
368 MiniPixel.Pixel^.B := ((cm shr 16) and $FF) * Brightness div 3;
369 MiniPixel.Pixel^.G := ((cm shr 8) and $FF) * Brightness div 3;
370 MiniPixel.Pixel^.R := ((cm shr 0) and $FF) * Brightness div 3;
371 end;
372 end;
373 MiniPixel.NextLine;
374 end;
375 Bitmap.EndUpdate;
376end;
377
378procedure TMiniMap.PaintFile(SaveMap: TMapArray);
379var
380 i, x, y, xm, cm, Tile, OwnColor, EnemyColor: integer;
381 MiniPixel: TPixelPointer;
382 PrevMiniPixel: TPixelPointer;
383begin
384 OwnColor := GrExt[HGrSystem].Data.Canvas.Pixels[95, 67];
385 EnemyColor := GrExt[HGrSystem].Data.Canvas.Pixels[96, 67];
386 Bitmap.PixelFormat := pf24bit;
387 Bitmap.SetSize(Size.X * 2, Size.Y);
388 if Mode = mmPicture then begin
389 Bitmap.BeginUpdate;
390 MiniPixel := PixelPointer(Bitmap);
391 PrevMiniPixel := PixelPointer(Bitmap, 0, -1);
392 for y := 0 to ScaleToNative(Size.Y) - 1 do begin
393 for x := 0 to ScaleToNative(Size.X) - 1 do begin
394 for i := 0 to 1 do begin
395 xm := (x * 2 + i + y and 1) mod (ScaleToNative(Size.X) * 2);
396 MiniPixel.SetX(xm);
397 Tile := SaveMap[ScaleFromNative(x) + Size.X * ScaleFromNative(y)];
398 if Tile and fTerrain = fUNKNOWN then
399 cm := $000000
400 else if Tile and smCity <> 0 then
401 begin
402 if Tile and smOwned <> 0 then
403 cm := OwnColor
404 else
405 cm := EnemyColor;
406 if y > 0 then begin
407 // 2x2 city dot covers two lines
408 PrevMiniPixel.SetX(xm);
409 PrevMiniPixel.Pixel^.B := cm shr 16;
410 PrevMiniPixel.Pixel^.G:= cm shr 8 and $FF;
411 PrevMiniPixel.Pixel^.R := cm and $FF;
412 end;
413 end
414 else if (i = 0) and (Tile and smUnit <> 0) then
415 if Tile and smOwned <> 0 then
416 cm := OwnColor
417 else cm := EnemyColor
418 else
419 cm := Colors[Tile and fTerrain, i];
420 MiniPixel.Pixel^.B := (cm shr 16) and $ff;
421 MiniPixel.Pixel^.G := (cm shr 8) and $ff;
422 MiniPixel.Pixel^.R := (cm shr 0) and $ff;
423 end;
424 end;
425 MiniPixel.NextLine;
426 PrevMiniPixel.NextLine;
427 end;
428 Bitmap.EndUpdate;
429 end;
430end;
431
432{ TStartDlg }
433
434procedure TStartDlg.FormCreate(Sender: TObject);
435var
436 x, i: Integer;
437 PlayerSlot: TPlayerSlot;
438 AIBrains: TBrains;
439 KeyBindingsAbsoluteFileName: string;
440begin
441 PlayerSlots := TPlayerSlots.Create;
442 PlayerSlots.Count := nPlOffered;
443 for I := 0 to PlayerSlots.Count - 1 do begin
444 PlayerSlot := TPlayerSlot.Create;
445 PlayerSlot.Rect := Bounds(xBrain[I], YBrain[I], 0, 0);
446 PlayerSlots[I] := PlayerSlot;
447 end;
448 LoadConfig;
449 LoadAssets;
450 KeyBindingsAbsoluteFileName := DataDir + DirectorySeparator + KeyBindingsFileName;
451 if FileExists(KeyBindingsAbsoluteFileName) then KeyBindings.LoadFromFile(KeyBindingsAbsoluteFileName)
452 else begin
453 ForceDirectories(ExtractFileDir(KeyBindingsAbsoluteFileName));
454 KeyBindings.SaveToFile(KeyBindingsAbsoluteFileName);
455 end;
456
457 ActionsOffered := [maConfig, maManual, maCredits, maWeb];
458 if FileExists(HomeDir + AITemplateFileName) then
459 Include(ActionsOffered, maAIDev);
460
461 BrainDefault := nil;
462 for i := Brains.IndexOf(BrainRandom) to Brains.Count - 1 do
463 if AnsiCompareFileName(DefaultAI, Brains[i].FileName) = 0 then
464 BrainDefault := Brains[i];
465 if (BrainDefault = BrainRandom) and (Brains.GetKindCount(btAI) < 2) then
466 BrainDefault := nil;
467 if (not Assigned(BrainDefault)) and (Brains.GetKindCount(btAI) > 0) then
468 begin
469 AIBrains := TBrains.Create(False);
470 Brains.GetByKind(btAI, AIBrains);
471 BrainDefault := Brains[0];
472 AIBrains.Free;
473 end; // default AI not found, use any
474
475 DirectDlg.Left := (Screen.Width - DirectDlg.Width) div 2;
476 DirectDlg.Top := (Screen.Height - DirectDlg.Height) div 2;
477
478 UpdateInterface;
479
480 Canvas.Font.Assign(UniFont[ftNormal]);
481 Canvas.Brush.Style := bsClear;
482
483 QuitBtn.Hint := Phrases.Lookup('STARTCONTROLS', 0);
484 ReplayBtn.Hint := Phrases.Lookup('BTN_REPLAY');
485 PlayerSlots.Count := nPlOffered;
486 for i := 0 to PlayerSlots.Count - 1 do
487 with PlayerSlots[i] do begin
488 DiffUpBtn := TButtonC.Create(self);
489 DiffUpBtn.Graphic := GrExt[HGrSystem].Data;
490 DiffUpBtn.left := xBrain[i] - 18;
491 DiffUpBtn.top := yBrain[i] + 39;
492 DiffUpBtn.ButtonIndex := 1;
493 DiffUpBtn.Parent := self;
494 DiffUpBtn.OnClick := DiffBtnClick;
495 DiffDownBtn := TButtonC.Create(self);
496 DiffDownBtn.Graphic := GrExt[HGrSystem].Data;
497 DiffDownBtn.left := xBrain[i] - 18;
498 DiffDownBtn.top := yBrain[i] + 51;
499 DiffDownBtn.ButtonIndex := 0;
500 DiffDownBtn.Parent := self;
501 DiffDownBtn.OnClick := DiffBtnClick;
502 end;
503 for i := 6 to 8 do
504 with PlayerSlots[i] do begin
505 MultiBtn := TButtonC.Create(self);
506 MultiBtn.Graphic := GrExt[HGrSystem].Data;
507 MultiBtn.left := xBrain[i] - 18;
508 MultiBtn.top := yBrain[i];
509 MultiBtn.Parent := self;
510 MultiBtn.OnClick := MultiBtnClick;
511 OfferMultiple := True;
512 end;
513
514 x := BiColorTextWidth(Canvas, Phrases.Lookup('STARTCONTROLS', 7)) div 2;
515 CustomizeBtn.left := x0Brain + 32 - 16 - x;
516 if AutoDiff < 0 then
517 CustomizeBtn.ButtonIndex := 3
518 else
519 CustomizeBtn.ButtonIndex := 2;
520
521 BitBltBitmap(BrainNoTerm.Picture, 0, 0, 64, 64, GrExt[HGrSystem2].Data, 1, 111);
522 BitBltBitmap(BrainSuperVirtual.Picture, 0, 0, 64, 64, GrExt[HGrSystem2].Data, 66, 111);
523 BitBltBitmap(BrainTerm.Picture, 0, 0, 64, 64, GrExt[HGrSystem2].Data, 131, 111);
524 BitBltBitmap(BrainRandom.Picture, 0, 0, 64, 64, GrExt[HGrSystem2].Data, 131, 46);
525 LoadAiBrainsPictures;
526
527 EmptyPicture := TBitmap.Create;
528 EmptyPicture.PixelFormat := pf24bit;
529 EmptyPicture.SetSize(64, 64);
530 EmptyPicture.Canvas.FillRect(0, 0, EmptyPicture.Width, EmptyPicture.Height);
531 LogoBuffer := TBitmap.Create;
532 LogoBuffer.PixelFormat := pf24bit;
533 LogoBuffer.SetSize(wBuffer, 56);
534 LogoBuffer.Canvas.FillRect(0, 0, LogoBuffer.Width, LogoBuffer.Height);
535
536 MiniMap := TMiniMap.Create;
537 InitButtons;
538
539 PlayersBrain[0] := BrainTerm;
540 SlotAvailable := -1;
541 Tab := tbNew;
542 Diff0 := 2;
543 TurnValid := False;
544 Tracking := False;
545 FormerGames := TStringList.Create;
546 UpdateFormerGames;
547 ShowTab := tbNew; // always start with new book page
548 MapFileName := '';
549 Maps := TStringList.Create;
550 UpdateMaps;
551end;
552
553procedure TStartDlg.FormDestroy(Sender: TObject);
554begin
555 SaveConfig;
556 FreeAndNil(FormerGames);
557 FreeAndNil(Maps);
558 FreeAndNil(EmptyPicture);
559 FreeAndNil(LogoBuffer);
560 FreeAndNil(PlayerSlots);
561 FreeAndNil(MiniMap);
562end;
563
564procedure TStartDlg.SmartInvalidate(x0, y0, x1, y1: integer;
565 invalidateTab0: boolean);
566var
567 i: integer;
568 r0, r1: HRgn;
569begin
570 r0 := CreateRectRgn(x0, y0, x1, y1);
571 for i := 0 to ControlCount - 1 do
572 if not (Controls[i] is TArea) and Controls[i].Visible then
573 begin
574 with Controls[i].BoundsRect do
575 r1 := CreateRectRgn(left, top, Right, Bottom);
576 CombineRgn(r0, r0, r1, RGN_DIFF);
577 DeleteObject(r1);
578 end;
579 if not invalidateTab0 then begin
580 r1 := CreateRectRgn(0, 0, 6 + 36, 3 + 38); // tab 0 icon
581 CombineRgn(r0, r0, r1, RGN_DIFF);
582 DeleteObject(r1);
583 end;
584 InvalidateRgn(Handle, r0, false);
585 DeleteObject(r0);
586end;
587
588procedure TStartDlg.LoadConfig;
589var
590 Reg: TRegistry;
591 I: Integer;
592 S: string;
593 ResolutionX, ResolutionY, ResolutionBPP, ResolutionFreq: Integer;
594 ScreenMode: Integer;
595begin
596 Reg := TRegistry.Create;
597 with Reg do try
598 // Initialize AI assignment
599 OpenKey(AppRegistryKey + '\AI', True);
600 for I := 0 to nPlOffered - 1 do begin
601 if I = 0 then S := ':StdIntf'
602 else S := 'StdAI';
603 if not ValueExists('Control' + IntToStr(I)) then
604 WriteString('Control' + IntToStr(I), S);
605 if not ValueExists('Diff' + IntToStr(I)) then
606 WriteInteger('Diff' + IntToStr(I), 2);
607 end;
608
609 OpenKey(AppRegistryKey, True);
610 if ValueExists('Gamma') then Gamma := ReadInteger('Gamma')
611 else Gamma := 100;
612 if Gamma <> 100 then InitGammaLookupTable;
613 if ValueExists('Locale') then LocaleCode := ReadString('Locale')
614 else LocaleCode := '';
615 if ValueExists('WorldSize') then WorldSize := Reg.ReadInteger('WorldSize')
616 else WorldSize := DefaultWorldSize;
617 if ValueExists('LandMass') then StartLandMass := Reg.ReadInteger('LandMass')
618 else StartLandMass := DefaultLandMass;
619 if ValueExists('MaxTurn') then MaxTurn := Reg.ReadInteger('MaxTurn')
620 else MaxTurn := 800;
621 if ValueExists('DefaultAI') then DefaultAI := Reg.ReadString('DefaultAI')
622 else DefaultAI := 'StdAI';
623 if ValueExists('AutoEnemies') then AutoEnemies := Reg.ReadInteger('AutoEnemies')
624 else AutoEnemies := 8;
625 if ValueExists('AutoDiff') then AutoDiff := Reg.ReadInteger('AutoDiff')
626 else AutoDiff := 1;
627
628 if ValueExists('ScreenMode') then
629 ScreenMode := ReadInteger('ScreenMode')
630 else ScreenMode := 1;
631 FullScreen := ScreenMode > 0;
632 if ValueExists('ResolutionX') then
633 ResolutionX := ReadInteger('ResolutionX');
634 if ValueExists('ResolutionY') then
635 ResolutionY := ReadInteger('ResolutionY');
636 if ValueExists('ResolutionBPP') then
637 ResolutionBPP := ReadInteger('ResolutionBPP');
638 if ValueExists('ResolutionFreq') then
639 ResolutionFreq := ReadInteger('ResolutionFreq');
640 if ValueExists('MultiControl') then
641 MultiControl := ReadInteger('MultiControl')
642 else MultiControl := 0;
643 {$IFDEF WINDOWS}
644 if ScreenMode = 2 then
645 ChangeResolution(ResolutionX, ResolutionY, ResolutionBPP,
646 ResolutionFreq);
647 {$ENDIF}
648 finally
649 Free;
650 end;
651end;
652
653procedure TStartDlg.SaveConfig;
654var
655 Reg: TRegistry;
656begin
657 Reg := TRegistry.Create;
658 with Reg do try
659 OpenKey(AppRegistryKey, True);
660 WriteInteger('WorldSize', WorldSize);
661 WriteInteger('LandMass', StartLandMass);
662 WriteString('Locale', LocaleCode);
663 WriteInteger('Gamma', Gamma);
664 if FullScreen then WriteInteger('ScreenMode', 1)
665 else WriteInteger('ScreenMode', 0);
666 WriteInteger('MultiControl', MultiControl);
667 finally
668 Free;
669 end;
670end;
671
672procedure TStartDlg.LoadAiBrainsPictures;
673var
674 AIBrains: TBrains;
675 I: Integer;
676begin
677 AIBrains := TBrains.Create(False);
678 Brains.GetByKind(btAI, AIBrains);
679 for i := 0 to AIBrains.Count - 1 do
680 with AIBrains[I] do begin
681 if not LoadGraphicFile(AIBrains[i].Picture, GetAiDir + DirectorySeparator +
682 FileName + DirectorySeparator + FileName + '.png', gfNoError) then begin
683 with AIBrains[i].Picture.Canvas do begin
684 Brush.Color := $904830;
685 FillRect(Rect(0, 0, 64, 64));
686 Font.Assign(UniFont[ftTiny]);
687 Font.Style := [];
688 Font.Color := $5FDBFF;
689 Textout(32 - TextWidth(FileName) div 2,
690 32 - TextHeight(FileName) div 2, FileName);
691 end;
692 end;
693 end;
694 AIBrains.Free;
695end;
696
697procedure TStartDlg.UpdateInterface;
698var
699 r0, r1: HRgn;
700 Location: TPoint;
701begin
702 if FullScreen then begin
703 Location := Point((Screen.Width - 800) * 3 div 8,
704 Screen.Height - Height - (Screen.Height - 600) div 3);
705 BoundsRect := Bounds(Location.X, Location.Y, Width, Height);
706
707 r0 := CreateRectRgn(0, 0, Width, Height);
708 r1 := CreateRectRgn(TabOffset + 4 * TabSize + 2, 0, Width, TabHeight);
709 CombineRgn(r0, r0, r1, RGN_DIFF);
710 DeleteObject(r1);
711 r1 := CreateRectRgn(QuitBtn.Left, QuitBtn.Top, QuitBtn.Left + QuitBtn.Width,
712 QuitBtn.top + QuitBtn.Height);
713 CombineRgn(r0, r0, r1, RGN_OR);
714 DeleteObject(r1);
715 SetWindowRgn(Handle, r0, False);
716 DeleteObject(r0); // causes crash with Windows 95
717 end else begin
718 BoundsRect := Bounds((Screen.Width - Width) div 2,
719 (Screen.Height - Height) div 2, Width, Height)
720 end;
721end;
722
723procedure TStartDlg.DrawAction(y, IconIndex: integer; HeaderItem, TextItem: string);
724begin
725 Canvas.Font.Assign(UniFont[ftCaption]);
726 Canvas.Font.Style := Canvas.Font.Style + [fsUnderline];
727 RisedTextOut(Canvas, xAction, y - 3, Phrases2.Lookup(HeaderItem));
728 Canvas.Font.Assign(UniFont[ftNormal]);
729 BiColorTextOut(Canvas, Colors.Canvas.Pixels[clkAge0 - 1, cliDimmedText],
730 $000000, xAction, y + 21, Phrases2.Lookup(TextItem));
731
732 // TODO: Explicitly clear background to black but in fact BitBlt SRCCOPY should do it
733 LogoBuffer.Canvas.FillRect(0, 0, LogoBuffer.Width, LogoBuffer.Height);
734 BitBltCanvas(LogoBuffer.Canvas, 0, 0, 50, 50, Canvas,
735 xActionIcon - 2, y - 2);
736 GlowFrame(LogoBuffer, 8, 8, 34, 34, $202020);
737 BitBltCanvas(Canvas, xActionIcon - 2, y - 2, 50, 50,
738 LogoBuffer.Canvas, 0, 0);
739 BitBltCanvas(Canvas, xActionIcon, y, 40, 40, BigImp.Canvas,
740 (IconIndex mod 7) * xSizeBig + 8, (IconIndex div 7) * ySizeBig);
741 RFrame(Canvas, xActionIcon - 1, y - 1, xActionIcon + 40, y + 40,
742 $000000, $000000);
743end;
744
745procedure TStartDlg.FormPaint(Sender: TObject);
746const
747 TabNames: array[TStartTab] of Integer = (0, 11, 3, 4);
748var
749 i, w, h, xMini, yMini, y: integer;
750 s: string;
751 Tab2: TStartTab;
752 MainAction: TMainAction;
753begin
754 PaintBackground(self, 3, 3, TabOffset + 4 * TabSize - 4, TabHeight - 3);
755 PaintBackground(self, 3, TabHeight + 3, ClientWidth - 6,
756 ClientHeight - TabHeight - 6);
757 with Canvas do
758 begin
759 Brush.Color := $000000;
760 FillRect(Rect(0, 1, ClientWidth, 3));
761 FillRect(Rect(TabOffset + 4 * TabSize + 2, 0, ClientWidth, TabHeight));
762 Brush.Style := bsClear;
763 end;
764 if Page in [pgStartRandom, pgStartMap] then
765 begin
766 Frame(Canvas, 328, yMain + 112 - 15, ClientWidth, Up2Btn.top + 38,
767 MainTexture.clBevelShade, MainTexture.clBevelLight);
768 if AutoDiff > 0 then
769 begin
770 Frame(Canvas, -1 { x0Brain-dxBrain } ,
771 yMain + 112 - 15 { Up1Btn.Top-12 }{ y0Brain-dyBrain } ,
772 x0Brain + dxBrain + 64, Up2Btn.top + 38 { y0Brain+dyBrain+64 } ,
773 MainTexture.clBevelShade, MainTexture.clBevelLight);
774 end;
775 end
776 else if Page <> pgMain then
777 Frame(Canvas, 328, Up1Btn.top - 15, ClientWidth, Up2Btn.top + 38,
778 MainTexture.clBevelShade, MainTexture.clBevelLight);
779 Frame(Canvas, 0, 0, ClientWidth - 1, ClientHeight - 1, 0, 0);
780
781 // draw tabs
782 Frame(Canvas, 2, 2 + 2 * integer(Tab <> tbMain), TabOffset + (0 + 1) * TabSize - 1,
783 TabHeight, MainTexture.clBevelLight, MainTexture.clBevelShade);
784 Frame(Canvas, 1, 1 + 2 * integer(Tab <> tbMain), TabOffset + (0 + 1) * TabSize,
785 TabHeight, MainTexture.clBevelLight, MainTexture.clBevelShade);
786 Canvas.Pixels[1, 1 + 2 * integer(Tab <> tbMain)] := MainTexture.clBevelShade;
787 for Tab2 := tbMap to tbPrevious do
788 begin
789 Frame(Canvas, TabOffset + Integer(Tab2) * TabSize + 2, 2 + 2 * integer(Tab <> Tab2),
790 TabOffset + (Integer(Tab2) + 1) * TabSize - 1, TabHeight, MainTexture.clBevelLight,
791 MainTexture.clBevelShade);
792 Frame(Canvas, TabOffset + Integer(Tab2) * TabSize + 1, 1 + 2 * integer(Tab <> Tab2),
793 TabOffset + (Integer(Tab2) + 1) * TabSize, TabHeight, MainTexture.clBevelLight,
794 MainTexture.clBevelShade);
795 Canvas.Pixels[TabOffset + Integer(Tab2) * TabSize + 1, 1 + 2 * integer(Tab <> Tab2)] :=
796 MainTexture.clBevelShade;
797 end;
798 Canvas.Font.Assign(UniFont[ftNormal]);
799 for Tab2 := tbMap to tbPrevious do
800 begin
801 s := Phrases.Lookup('STARTCONTROLS', TabNames[Tab2]);
802 RisedTextOut(Canvas, TabOffset + Integer(Tab2) * TabSize + 1 +
803 (TabSize - BiColorTextWidth(Canvas, s)) div 2,
804 10 + 2 * integer(Tab <> Tab2), s);
805 end;
806 Frame(Canvas, TabOffset + 4 * TabSize + 1, -1, ClientWidth, TabHeight,
807 $000000, $000000);
808 Frame(Canvas, 1, TabHeight + 1, ClientWidth - 2, ClientHeight - 2,
809 MainTexture.clBevelLight, MainTexture.clBevelShade);
810 Frame(Canvas, 2, TabHeight + 2, ClientWidth - 3, ClientHeight - 3,
811 MainTexture.clBevelLight, MainTexture.clBevelShade);
812 if Tab = tbMain then
813 begin
814 PaintBackground(self, 3, TabHeight - 1, TabSize - 4 - 3 + TabOffset + 3, 4);
815 Canvas.Pixels[2, TabHeight] := MainTexture.clBevelLight;
816 end
817 else
818 begin
819 PaintBackground(self, TabOffset + 3 + Integer(Tab) * TabSize, TabHeight - 1,
820 TabSize - 4, 4);
821 Canvas.Pixels[TabOffset + Integer(Tab) * TabSize + 2, TabHeight] :=
822 MainTexture.clBevelLight;
823 end;
824 Canvas.Pixels[TabOffset + (Integer(Tab) + 1) * TabSize - 1, TabHeight + 1] :=
825 MainTexture.clBevelShade;
826 if Tab < tbPrevious then
827 Frame(Canvas, TabOffset + (Integer(Tab) + 1) * TabSize + 1, 3,
828 TabOffset + (Integer(Tab) + 1) * TabSize + 2, TabHeight, MainTexture.clBevelShade,
829 MainTexture.clBevelShade); // Tab shadow
830 // TODO: Explicitly clear background to black but in fact BitBlt SRCCOPY should do it
831 LogoBuffer.Canvas.FillRect(0, 0, LogoBuffer.Width, LogoBuffer.Height);
832 BitBltCanvas(LogoBuffer.Canvas, 0, 0, 36, 36, Canvas, 6,
833 3 + 2 * integer(Tab <> tbMain));
834
835 ImageOp_BCC(LogoBuffer, Templates, 0, 0, 145, 38, 36, 27, $BFBF20, $4040DF);
836 // logo part 1
837 ImageOp_BCC(LogoBuffer, Templates, 10, 27, 155, 38 + 27, 26, 9, $BFBF20,
838 $4040DF); // logo part 2
839 BitBltCanvas(Canvas, 6, 3 + 2 * integer(Tab <> tbMain), 36, 36,
840 LogoBuffer.Canvas, 0, 0);
841
842 if Page = pgMain then begin
843 if SelectedAction <> maNone then // mark selected action
844 for i := 0 to (ClientWidth - 2 * ActionSideBorder) div wBuffer + 1 do
845 begin
846 w := ClientWidth - 2 * ActionSideBorder - i * wBuffer;
847 if w > wBuffer then
848 w := wBuffer;
849 h := ActionPitch;
850 if yAction + Integer(SelectedAction) * ActionPitch - 8 + h > ClientHeight - ActionBottomBorder
851 then
852 h := ClientHeight - ActionBottomBorder -
853 (yAction + Integer(SelectedAction) * ActionPitch - 8);
854 // TODO: Explicitly clear background to black but in fact BitBlt SRCCOPY should do it
855 LogoBuffer.Canvas.FillRect(0, 0, LogoBuffer.Width, LogoBuffer.Height);
856 BitBltCanvas(LogoBuffer.Canvas, 0, 0, w, h, Canvas,
857 ActionSideBorder + i * wBuffer, yAction + Integer(SelectedAction) * ActionPitch
858 - 8);
859 MakeBlue(LogoBuffer, 0, 0, w, h);
860 BitBltCanvas(Canvas, ActionSideBorder + i * wBuffer,
861 yAction + Integer(SelectedAction) * ActionPitch - 8, w, h,
862 LogoBuffer.Canvas, 0, 0);
863 end;
864 y := yAction;
865 for MainAction := Low(TMainActionSet) to High(TMainActionSet) do
866 begin
867 if MainAction in ActionsOffered then
868 case MainAction of
869 maConfig: DrawAction(y, 25, 'ACTIONHEADER_CONFIG', 'ACTION_CONFIG');
870 maManual: DrawAction(y, 19, 'ACTIONHEADER_MANUAL', 'ACTION_MANUAL');
871 maCredits: DrawAction(y, 22, 'ACTIONHEADER_CREDITS', 'ACTION_CREDITS');
872 maAIDev: DrawAction(y, 24, 'ACTIONHEADER_AIDEV', 'ACTION_AIDEV');
873 maWeb:
874 begin
875 Canvas.Font.Assign(UniFont[ftCaption]);
876 // Canvas.Font.Style:=Canvas.Font.Style+[fsUnderline];
877 RisedTextOut(Canvas, xActionIcon + 99, y,
878 Phrases2.Lookup('ACTIONHEADER_WEB'));
879 Canvas.Font.Assign(UniFont[ftNormal]);
880 // TODO: Explicitly clear background to black but in fact BitBlt SRCCOPY should do it
881 LogoBuffer.Canvas.FillRect(0, 0, LogoBuffer.Width, LogoBuffer.Height);
882 BitBltCanvas(LogoBuffer.Canvas, 0, 0, 91, 25, Canvas,
883 xActionIcon, y + 2);
884 ImageOp_BCC(LogoBuffer, Templates, 0, 0, 1, 400, 91, 25, 0,
885 Colors.Canvas.Pixels[clkAge0 - 1, cliDimmedText]);
886 BitBltCanvas(Canvas, xActionIcon, y + 2, 91, 25,
887 LogoBuffer.Canvas, 0, 0);
888 end;
889 end;
890 Inc(y, ActionPitch);
891 end;
892 end
893 else if Page in [pgStartRandom, pgStartMap] then
894 begin
895 DLine(Canvas, 344, 514, y0Mini + 61 + 19, MainTexture.clBevelLight,
896 MainTexture.clBevelShade);
897 RisedTextOut(Canvas, 344, y0Mini + 61, Phrases.Lookup('STARTCONTROLS', 10));
898 s := TurnToString(MaxTurn);
899 RisedTextOut(Canvas, 514 - BiColorTextWidth(Canvas, s), y0Mini + 61, s);
900 s := Phrases.Lookup('STARTCONTROLS', 7);
901 w := Canvas.TextWidth(s);
902 LoweredTextOut(Canvas, -2, MainTexture, x0Brain + 32 - w div 2,
903 y0Brain + dyBrain + 69, s);
904
905 InitOrnament;
906 if AutoDiff < 0 then
907 begin
908 for i := 12 to 19 do
909 if (i < 13) or (i > 17) then
910 begin
911 BitBltCanvas(Canvas, 9 + i * 27, yLogo - 2, wOrna, hOrna,
912 GrExt[HGrSystem2].Mask.Canvas, xOrna, yOrna, SRCAND);
913 BitBltCanvas(Canvas, 9 + i * 27, yLogo - 2, wOrna, hOrna,
914 GrExt[HGrSystem2].Data.Canvas, xOrna, yOrna, SRCPAINT);
915 end;
916 PaintLogo(Canvas, 69 + 11 * 27, yLogo, MainTexture.clBevelLight,
917 MainTexture.clBevelShade);
918
919 for i := 0 to nPlOffered - 1 do
920 if 1 shl i and SlotAvailable <> 0 then
921 begin
922 if Assigned(PlayersBrain[i]) then
923 FrameImage(Canvas, PlayersBrain[i].Picture, xBrain[i], yBrain[i],
924 64, 64, 0, 0, true)
925 else
926 FrameImage(Canvas, EmptyPicture, xBrain[i], yBrain[i], 64, 64,
927 0, 0, true);
928 if Assigned(PlayersBrain[I]) and (PlayersBrain[i].Kind in [btTerm, btRandom, btAI]) then
929 begin
930 BitBltCanvas(Canvas, xBrain[i] - 18, yBrain[i] + 19, 12, 14,
931 GrExt[HGrSystem].Data.Canvas, 134 + (Difficulty[i] - 1) *
932 13, 28);
933 Frame(Canvas, xBrain[i] - 19, yBrain[i] + 18, xBrain[i] - 18 + 12,
934 yBrain[i] + (19 + 14), $000000, $000000);
935 RFrame(Canvas, PlayerSlots[i].DiffUpBtn.left - 1, PlayerSlots[i].DiffUpBtn.top - 1,
936 PlayerSlots[i].DiffUpBtn.left + 12, PlayerSlots[i].DiffUpBtn.top + 24,
937 MainTexture.clBevelShade, MainTexture.clBevelLight);
938 with Canvas do
939 begin
940 Brush.Color := $000000;
941 FillRect(Rect(xBrain[i] - 5, yBrain[i] + 25, xBrain[i] - 2,
942 yBrain[i] + 27));
943 Brush.Style := bsClear;
944 end;
945 if PlayerSlots[I].OfferMultiple then
946 begin
947 RFrame(Canvas, PlayerSlots[I].MultiBtn.left - 1, PlayerSlots[I].MultiBtn.top - 1,
948 PlayerSlots[I].MultiBtn.left + 12, PlayerSlots[I].MultiBtn.top + 12,
949 MainTexture.clBevelShade, MainTexture.clBevelLight);
950 BitBltCanvas(Canvas, xBrain[i] - 31, yBrain[i], 13, 12,
951 GrExt[HGrSystem].Data.Canvas, 88, 47);
952 end;
953 end;
954 if Assigned(PlayersBrain[i]) then
955 begin
956 PlayerSlots[i].DiffUpBtn.Hint := Format(Phrases.Lookup('STARTCONTROLS', 9),
957 [PlayersBrain[i].Name]);
958 PlayerSlots[i].DiffDownBtn.Hint := PlayerSlots[i].DiffUpBtn.Hint;
959 end;
960 end;
961 end
962 else
963 begin
964 DLine(Canvas, 24, 198, yMain + 140 + 19, MainTexture.clBevelLight,
965 MainTexture.clBevelShade);
966 RisedTextOut(Canvas, 24 { x0Brain+32-BiColorTextWidth(Canvas,s) div 2 } ,
967 yMain + 140 { y0Mini-77 } , Phrases.Lookup('STARTCONTROLS', 15));
968 if Page = pgStartRandom then
969 s := IntToStr(AutoEnemies)
970 else if nMapStartPositions = 0 then
971 s := '0'
972 else
973 s := IntToStr(nMapStartPositions - 1);
974 RisedTextOut(Canvas, 198 - BiColorTextWidth(Canvas, s), yMain + 140, s);
975 DLine(Canvas, 24, xDefault - 6, yMain + 164 + 19,
976 MainTexture.clBevelLight, MainTexture.clBevelShade);
977 RisedTextOut(Canvas, 24 { x0Brain+32-BiColorTextWidth(Canvas,s) div 2 } ,
978 yMain + 164 { y0Mini-77 } , Phrases.Lookup('STARTCONTROLS', 16));
979 if AutoDiff = 1 then
980 FrameImage(Canvas, BrainBeginner.Picture, xDefault, yDefault, 64,
981 64, 0, 0, false)
982 else
983 FrameImage(Canvas, BrainDefault.Picture, xDefault, yDefault, 64, 64,
984 0, 0, true);
985 DLine(Canvas, 56, 272, y0Mini + 61 + 19, MainTexture.clBevelLight,
986 MainTexture.clBevelShade);
987 RisedTextOut(Canvas, 56, y0Mini + 61,
988 Phrases.Lookup('STARTCONTROLS', 14));
989 s := Phrases.Lookup('AUTODIFF', AutoDiff - 1);
990 RisedTextOut(Canvas, 272 - BiColorTextWidth(Canvas, s), y0Mini + 61, s);
991
992 for i := 0 to 19 do
993 if (i < 2) or (i > 6) then
994 begin
995 BitBltCanvas(Canvas, 9 + i * 27, yLogo - 2, wOrna, hOrna,
996 GrExt[HGrSystem2].Mask.Canvas, xOrna, yOrna, SRCAND);
997 BitBltCanvas(Canvas, 9 + i * 27, yLogo - 2, wOrna, hOrna,
998 GrExt[HGrSystem2].Data.Canvas, xOrna, yOrna, SRCPAINT);
999 end;
1000 PaintLogo(Canvas, 69, yLogo, MainTexture.clBevelLight,
1001 MainTexture.clBevelShade);
1002 end;
1003 end
1004 else if Page = pgLoad then
1005 begin
1006 // RisedTextOut(Canvas,x0Mini+2-BiColorTextWidth(Canvas,BookDate) div 2,y0Mini-73,BookDate);
1007 if LastTurn > 0 then
1008 begin
1009 PaintProgressBar(Canvas, 6, xTurnSlider, yTurnSlider, 0,
1010 LoadTurn * wTurnSlider div LastTurn, wTurnSlider, MainTexture);
1011 Frame(Canvas, xTurnSlider - 2, yTurnSlider - 2, xTurnSlider + wTurnSlider
1012 + 1, yTurnSlider + 8, $B0B0B0, $FFFFFF);
1013 RFrame(Canvas, xTurnSlider - 3, yTurnSlider - 3, xTurnSlider + wTurnSlider
1014 + 2, yTurnSlider + 9, $FFFFFF, $B0B0B0);
1015 end
1016 else
1017 DLine(Canvas, 344, 514, y0Mini + 61 + 19, MainTexture.clBevelLight,
1018 MainTexture.clBevelShade);
1019 RisedTextOut(Canvas, 344, y0Mini + 61, Phrases.Lookup('STARTCONTROLS', 8));
1020 s := TurnToString(LoadTurn);
1021 RisedTextOut(Canvas, 514 - BiColorTextWidth(Canvas, s), y0Mini + 61, s);
1022 end
1023 else if Page = pgEditRandom then
1024 begin
1025 DLine(Canvas, 344, 514, y0Mini - 77 + 19, MainTexture.clBevelLight,
1026 MainTexture.clBevelShade);
1027 RisedTextOut(Canvas, 344, y0Mini - 77, Phrases.Lookup('STARTCONTROLS', 5));
1028 s := IntToStr((WorldSizes[WorldSize].X * WorldSizes[WorldSize].Y * 20 +
1029 DefaultWorldTiles div 2) div DefaultWorldTiles * 5) + '%';
1030 RisedTextOut(Canvas, 514 - BiColorTextWidth(Canvas, s), y0Mini - 77, s);
1031 DLine(Canvas, 344, 514, y0Mini + 61 + 19, MainTexture.clBevelLight,
1032 MainTexture.clBevelShade);
1033 RisedTextOut(Canvas, 344, y0Mini + 61, Phrases.Lookup('STARTCONTROLS', 6));
1034 s := IntToStr(StartLandMass) + '%';
1035 RisedTextOut(Canvas, 514 - BiColorTextWidth(Canvas, s), y0Mini + 61, s);
1036 end
1037 else if Page = pgEditMap then
1038 begin
1039 // DLine(Canvas,344,514,y0Mini+61+19,MainTexture.clBevelLight,MainTexture.clBevelShade);
1040 s := Format(Phrases2.Lookup('MAPPROP'),
1041 [(nMapLandTiles * 100 + 556) div 1112,
1042 // 1112 is typical for world with 100% size and default land mass
1043 nMapStartPositions]);
1044 RisedTextOut(Canvas, x0Mini - BiColorTextWidth(Canvas, s) div 2,
1045 y0Mini + 61, s);
1046 end;
1047
1048 if StartBtn.Visible then
1049 BtnFrame(Canvas, StartBtn.BoundsRect, MainTexture);
1050 if Up2Btn.Visible then
1051 RFrame(Canvas, Up2Btn.left - 1, Up2Btn.top - 1, Up2Btn.left + 12,
1052 Up2Btn.top + 24, MainTexture.clBevelShade, MainTexture.clBevelLight);
1053 if Up1Btn.Visible then
1054 RFrame(Canvas, Up1Btn.left - 1, Up1Btn.top - 1, Up1Btn.left + 12,
1055 Up1Btn.top + 24, MainTexture.clBevelShade, MainTexture.clBevelLight);
1056 if AutoDiffUpBtn.Visible then
1057 RFrame(Canvas, AutoDiffUpBtn.left - 1, AutoDiffUpBtn.top - 1,
1058 AutoDiffUpBtn.left + 12, AutoDiffUpBtn.top + 24, MainTexture.clBevelShade,
1059 MainTexture.clBevelLight);
1060 if AutoEnemyUpBtn.Visible then
1061 RFrame(Canvas, AutoEnemyUpBtn.left - 1, AutoEnemyUpBtn.top - 1,
1062 AutoEnemyUpBtn.left + 12, AutoEnemyUpBtn.top + 24,
1063 MainTexture.clBevelShade, MainTexture.clBevelLight);
1064 if CustomizeBtn.Visible then
1065 RFrame(Canvas, CustomizeBtn.left - 1, CustomizeBtn.top - 1,
1066 CustomizeBtn.left + 12, CustomizeBtn.top + 12, MainTexture.clBevelShade,
1067 MainTexture.clBevelLight);
1068 if List.Visible then
1069 EditFrame(Canvas, List.BoundsRect, MainTexture);
1070 if RenameBtn.Visible then
1071 BtnFrame(Canvas, RenameBtn.BoundsRect, MainTexture);
1072 if DeleteBtn.Visible then
1073 BtnFrame(Canvas, DeleteBtn.BoundsRect, MainTexture);
1074 if Page = pgLoad then
1075 BtnFrame(Canvas, ReplayBtn.BoundsRect, MainTexture);
1076
1077 if not (Page in [pgMain, pgNoLoad]) then
1078 begin
1079 xMini := x0Mini - MiniMap.Size.X;
1080 yMini := y0Mini - MiniMap.Size.Y div 2;
1081 Frame(Canvas, xMini, yMini, xMini + 3 + MiniMap.Size.X * 2,
1082 yMini + 3 + MiniMap.Size.Y, MainTexture.clBevelLight,
1083 MainTexture.clBevelShade);
1084 Frame(Canvas, xMini + 1, yMini + 1, xMini + 2 + MiniMap.Size.X * 2,
1085 yMini + 2 + MiniMap.Size.Y, MainTexture.clBevelShade,
1086 MainTexture.clBevelLight);
1087
1088 s := '';
1089 if MiniMap.Mode = mmPicture then
1090 begin
1091 BitBltCanvas(Canvas, xMini + 2, yMini + 2, MiniMap.Size.X * 2, MiniMap.Size.Y,
1092 MiniMap.Bitmap.Canvas, 0, 0);
1093 if Page = pgStartRandom then
1094 s := Phrases.Lookup('RANMAP')
1095 end
1096 else if MiniMap.Mode = mmMultiPlayer then
1097 s := Phrases.Lookup('MPMAP')
1098 else if Page = pgStartMap then
1099 s := Copy(MapFileName, 1, Length(MapFileName) - 9)
1100 else if Page = pgEditMap then
1101 s := List.Items[List.ItemIndex]
1102 else if Page = pgNoLoad then
1103 s := Phrases.Lookup('NOGAMES');
1104 if s <> '' then
1105 RisedTextOut(Canvas, x0Mini + 2 - BiColorTextWidth(Canvas, s) div 2,
1106 y0Mini - 8, s);
1107 end;
1108end;
1109
1110procedure TStartDlg.FormShow(Sender: TObject);
1111begin
1112 SetMainTextureByAge(-1);
1113 List.Font.Color := MainTexture.clMark;
1114
1115 Fill(EmptyPicture.Canvas, Bounds(0, 0, 64, 64),
1116 Point((wMaintexture - 64) div 2, (hMaintexture - 64) div 2));
1117
1118 DarkenImage(EmptyPicture, 28);
1119
1120 Difficulty[0] := Diff0;
1121
1122 SelectedAction := maNone;
1123 if ShowTab = tbPrevious then
1124 PreviewMap(StartLandMass); // avoid delay on first TabX change
1125 ChangeTab(ShowTab);
1126 Background.Enabled := False;
1127end;
1128
1129procedure TStartDlg.UnlistBackupFile(FileName: string);
1130var
1131 I: Integer;
1132begin
1133 if FileName[1] <> '~' then
1134 FileName := '~' + FileName;
1135 I := FormerGames.Count - 1;
1136 while (I >= 0) and (AnsiCompareFileName(FormerGames[I], FileName) <> 0) do
1137 Dec(I);
1138 if I >= 0 then
1139 begin
1140 FormerGames.Delete(I);
1141 if ListIndex[tbNew] = I then
1142 ListIndex[tbNew] := 0
1143 end;
1144end;
1145
1146procedure TStartDlg.StartBtnClick(Sender: TObject);
1147var
1148 I, GameCount, MapCount: Integer;
1149 FileName: string;
1150 Reg: TRegistry;
1151begin
1152 case Page of
1153 pgLoad:
1154 begin // load
1155 FileName := List.Items[List.ItemIndex];
1156 if LoadGame(GetSavedDir + DirectorySeparator, FileName + CevoExt, LoadTurn, false)
1157 then
1158 UnlistBackupFile(FileName)
1159 else
1160 SimpleMessage(Phrases.Lookup('LOADERR'));
1161 SlotAvailable := -1;
1162 end;
1163 pgStartRandom, pgStartMap:
1164 if Assigned(PlayersBrain[0]) then
1165 begin
1166 if (Page = pgStartMap) and (nMapStartPositions = 0) and (AutoDiff > 0)
1167 then
1168 begin
1169 SimpleMessage(Phrases.Lookup('NOSTARTPOS'));
1170 Exit;
1171 end;
1172
1173 Reg := TRegistry.Create;
1174 with Reg do
1175 try
1176 OpenKey(AppRegistryKey, true);
1177 if ValueExists('GameCount') then GameCount := ReadInteger('GameCount')
1178 else GameCount := 0;
1179
1180 if (AutoDiff < 0) and (PlayersBrain[0].Kind = btNoTerm) then
1181 FileName := 'Round' + IntToStr(GetProcessID())
1182 else begin
1183 Inc(GameCount);
1184 FileName := Format(Phrases.Lookup('GAME'), [GameCount]);
1185 end;
1186
1187 // Save settings and AI assignment
1188 if Page = pgStartRandom then begin
1189 SaveConfig;
1190 OpenKey(AppRegistryKey + '\AI', True);
1191 if AutoDiff < 0 then
1192 for I := 0 to nPlOffered - 1 do begin
1193 if not Assigned(PlayersBrain[I]) then
1194 Reg.WriteString('Control' + IntToStr(I), '')
1195 else Reg.WriteString('Control' + IntToStr(I),
1196 PlayersBrain[I].FileName);
1197 WriteInteger('Diff' + IntToStr(I), Difficulty[I]);
1198 end;
1199 end;
1200
1201 OpenKey(AppRegistryKey, True);
1202 if AutoDiff > 0 then
1203 begin
1204 WriteString('DefaultAI', BrainDefault.FileName);
1205 SlotAvailable := 0; // PlayerSlot will be invalid hereafter
1206 PlayersBrain[0] := BrainTerm;
1207 Difficulty[0] := PlayerAutoDiff[AutoDiff];
1208 for I := 1 to nPl - 1 do
1209 if (Page = pgStartRandom) and (I <= AutoEnemies) or
1210 (Page = pgStartMap) and (I < nMapStartPositions) then begin
1211 if AutoDiff = 1 then PlayersBrain[I] := BrainBeginner
1212 else PlayersBrain[I] := BrainDefault;
1213 Difficulty[I] := EnemyAutoDiff[AutoDiff];
1214 end else PlayersBrain[I] := nil;
1215 end else begin
1216 for I := 6 to 8 do
1217 if (PlayersBrain[0].Kind <> btNoTerm) and (MultiControl and (1 shl I) <> 0)
1218 then begin
1219 PlayersBrain[I + 3] := PlayersBrain[I];
1220 Difficulty[I + 3] := Difficulty[I];
1221 PlayersBrain[I + 6] := PlayersBrain[I];
1222 Difficulty[I + 6] := Difficulty[I];
1223 end else begin
1224 PlayersBrain[I + 3] := nil;
1225 PlayersBrain[I + 6] := nil;
1226 end;
1227 end;
1228
1229 WriteInteger('AutoDiff', AutoDiff);
1230 WriteInteger('AutoEnemies', AutoEnemies);
1231 WriteInteger('MaxTurn', MaxTurn);
1232 WriteInteger('GameCount', GameCount);
1233 finally
1234 Free;
1235 end;
1236
1237 StartNewGame(GetSavedDir + DirectorySeparator, FileName + CevoExt, MapFileName,
1238 WorldSizes[WorldSize].X, WorldSizes[WorldSize].Y, StartLandMass, MaxTurn);
1239 UnlistBackupFile(FileName);
1240 end;
1241 pgEditMap:
1242 EditMap(MapFileName, lxmax, lymax, StartLandMass);
1243 pgEditRandom: // new map
1244 begin
1245 Reg := TRegistry.Create;
1246 with Reg do
1247 try
1248 OpenKey(AppRegistryKey, True);
1249 if ValueExists('MapCount') then MapCount := ReadInteger('MapCount')
1250 else MapCount := 0;
1251 Inc(MapCount);
1252 WriteInteger('MapCount', MapCount);
1253 finally
1254 Free;
1255 end;
1256 MapFileName := Format(Phrases.Lookup('MAP'), [MapCount]) + CevoMapExt;
1257 EditMap(MapFileName, WorldSizes[WorldSize].X, WorldSizes[WorldSize].Y, StartLandMass);
1258 end;
1259 end;
1260end;
1261
1262procedure TStartDlg.PaintInfo;
1263begin
1264 case Page of
1265 pgStartRandom: begin
1266 MiniMap.Mode := mmPicture;
1267 MiniMap.PaintRandom(3, StartLandMass, WorldSize);
1268 end;
1269 pgNoLoad: begin
1270 MiniMap.Mode := mmNone;
1271 MiniMap.Size := WorldSizes[DefaultWorldSize];
1272 end;
1273 pgLoad: begin
1274 MiniMap.LoadFromLogFile(GetSavedDir + DirectorySeparator +
1275 List.Items[List.ItemIndex] + CevoExt, LastTurn);
1276 // BookDate:=DateToStr(FileDateToDateTime(FileAge(FileName)));
1277 if not TurnValid then begin
1278 LoadTurn := LastTurn;
1279 SmartInvalidate(xTurnSlider - 2, y0Mini + 61,
1280 xTurnSlider + wTurnSlider + 2, yTurnSlider + 9);
1281 end;
1282 TurnValid := True;
1283 end;
1284 pgEditRandom: begin
1285 MapFileName := '';
1286 MiniMap.Mode := mmPicture;
1287 MiniMap.PaintRandom(4, StartLandMass, WorldSize);
1288 end;
1289 pgStartMap, pgEditMap:
1290 begin
1291 if Page = pgEditMap then
1292 MapFileName := List.Items[List.ItemIndex] + CevoMapExt;
1293 MiniMap.LoadFromMapFile(GetMapsDir + DirectorySeparator + MapFileName, nMapLandTiles, nMapStartPositions);
1294 if Page = pgEditMap then
1295 SmartInvalidate(x0Mini - 112, y0Mini + 61, x0Mini + 112, y0Mini + 91);
1296 end;
1297 end;
1298 SmartInvalidate(x0Mini - lxmax, y0Mini - lymax div 2,
1299 x0Mini - lxmax + 2 * lxmax + 4, y0Mini - lymax div 2 + lymax + 4);
1300end;
1301
1302procedure TStartDlg.BrainClick(Sender: TObject);
1303var
1304 I: Integer;
1305begin
1306 // Play('BUTTON_UP');
1307 if PlayerPopupIndex < 0 then
1308 begin // change default AI
1309 BrainDefault := Brains[TMenuItem(Sender).Tag];
1310 SmartInvalidate(xDefault, yDefault, xDefault + 64, yDefault + 64);
1311 end
1312 else
1313 begin
1314 if Assigned(PlayersBrain[PlayerPopupIndex]) then
1315 PlayersBrain[PlayerPopupIndex].Flags := PlayersBrain[PlayerPopupIndex].Flags and not fUsed;
1316 if TMenuItem(Sender).Tag = -1 then begin
1317 PlayersBrain[PlayerPopupIndex] := nil;
1318 PlayerSlots[PlayerPopupIndex].DiffUpBtn.Visible := False;
1319 PlayerSlots[PlayerPopupIndex].DiffDownBtn.Visible := False;
1320 if PlayerSlots[PlayerPopupIndex].OfferMultiple then begin
1321 PlayerSlots[PlayerPopupIndex].MultiBtn.Visible := False;
1322 PlayerSlots[PlayerPopupIndex].MultiBtn.ButtonIndex := 2 + (MultiControl shr PlayerPopupIndex) and 1;
1323 end;
1324 MultiControl := MultiControl and not (1 shl PlayerPopupIndex);
1325 end else begin
1326 PlayersBrain[PlayerPopupIndex] := Brains[TMenuItem(Sender).Tag];
1327 PlayerSlots[PlayerPopupIndex].DiffUpBtn.Visible := PlayersBrain[PlayerPopupIndex].Kind in [btTerm, btRandom, btAI];
1328 PlayerSlots[PlayerPopupIndex].DiffDownBtn.Visible := PlayersBrain[PlayerPopupIndex].Kind in [btTerm, btRandom, btAI];
1329 if PlayerSlots[PlayerPopupIndex].OfferMultiple then begin
1330 PlayerSlots[PlayerPopupIndex].MultiBtn.Visible := PlayersBrain[PlayerPopupIndex].Kind in [btTerm, btRandom, btAI];
1331 PlayerSlots[PlayerPopupIndex].MultiBtn.ButtonIndex := 2 + (MultiControl shr PlayerPopupIndex) and 1;
1332 end;
1333 PlayersBrain[PlayerPopupIndex].Flags := PlayersBrain[PlayerPopupIndex].Flags or fUsed;
1334 if PlayersBrain[PlayerPopupIndex].Kind in [btNoTerm, btSuperVirtual] then
1335 Difficulty[PlayerPopupIndex] := 0 { supervisor }
1336 else
1337 Difficulty[PlayerPopupIndex] := 2;
1338 if (Page = pgStartRandom) and (PlayerSlots[PlayerPopupIndex].OfferMultiple) and
1339 (not Assigned(PlayersBrain[PlayerPopupIndex])) then
1340 MultiControl := MultiControl and not (1 shl PlayerPopupIndex);
1341 if (PlayerPopupIndex = 0) and (MapFileName <> '') then
1342 ChangePage(Page);
1343 if PlayersBrain[PlayerPopupIndex].Kind = btNoTerm then
1344 begin // turn all local players off
1345 for I := 1 to PlayerSlots.Count - 1 do
1346 if PlayersBrain[I].Kind = btTerm then begin
1347 PlayersBrain[I] := nil;
1348 PlayerSlots[I].DiffUpBtn.Visible := false;
1349 PlayerSlots[I].DiffUpBtn.Tag := 0;
1350 PlayerSlots[I].DiffDownBtn.Visible := false;
1351 PlayerSlots[I].DiffDownBtn.Tag := 0;
1352 if PlayerSlots[I].OfferMultiple then begin
1353 PlayerSlots[I].MultiBtn.Visible := false;
1354 PlayerSlots[I].MultiBtn.Tag := 0;
1355 end;
1356 SmartInvalidate(xBrain[I] - 31, yBrain[I] - 1, xBrain[I] + 64,
1357 PlayerSlots[I].DiffUpBtn.top + 25);
1358 end;
1359 BrainTerm.Flags := BrainTerm.Flags and not fUsed;
1360 end;
1361 end;
1362 SmartInvalidate(xBrain[PlayerPopupIndex] - 31, yBrain[PlayerPopupIndex] - 1,
1363 xBrain[PlayerPopupIndex] + 64, PlayerSlots[PlayerPopupIndex].DiffUpBtn.top + 25);
1364 end;
1365end;
1366
1367procedure TStartDlg.OfferBrain(Brain: TBrain; FixedLines: Integer);
1368var
1369 J: Integer;
1370 MenuItem: TMenuItem;
1371begin
1372 MenuItem := TMenuItem.Create(PopupMenu1);
1373 if not Assigned(Brain) then MenuItem.Caption := Phrases.Lookup('NOMOD')
1374 else MenuItem.Caption := Brain.Name;
1375 MenuItem.Tag := Brains.IndexOf(Brain);
1376 MenuItem.OnClick := BrainClick;
1377 J := FixedLines;
1378 while (J < PopupMenu1.Items.Count) and
1379 (StrIComp(pchar(MenuItem.Caption), pchar(PopupMenu1.Items[J].Caption)) > 0) do
1380 Inc(J);
1381 MenuItem.RadioItem := True;
1382 if (PlayerPopupIndex < 0) then MenuItem.Checked := BrainDefault = Brain
1383 else MenuItem.Checked := PlayersBrain[PlayerPopupIndex] = Brain;
1384 PopupMenu1.Items.Insert(J, MenuItem);
1385end;
1386
1387procedure TStartDlg.InitPopup(PlayerIndex: Integer);
1388var
1389 I: Integer;
1390 FixedLines: integer;
1391 MenuItem: TMenuItem;
1392 AIBrains: TBrains;
1393begin
1394 PlayerPopupIndex := PlayerIndex;
1395 EmptyMenu(PopupMenu1.Items);
1396 if PlayerPopupIndex < 0 then begin // select default AI
1397 FixedLines := 0;
1398 if Brains.GetKindCount(btAI) >= 2 then begin
1399 OfferBrain(BrainRandom, FixedLines);
1400 Inc(FixedLines);
1401 end;
1402 AIBrains := TBrains.Create(False);
1403 Brains.GetByKind(btAI, AIBrains);
1404 for I := 0 to AIBrains.Count - 1 do // offer available AIs
1405 if AIBrains[I].Flags and fMultiple <> 0 then
1406 OfferBrain(AIBrains[I], FixedLines);
1407 AIBrains.Free;
1408 end else begin
1409 FixedLines := 0;
1410 if PlayerPopupIndex > 0 then begin
1411 OfferBrain(nil, FixedLines);
1412 Inc(FixedLines);
1413 end;
1414 for I := Brains.IndexOf(BrainTerm) downto 0 do // offer game interfaces
1415 if (PlayerPopupIndex = 0) or (Brains[i].Kind = btTerm) and
1416 (PlayersBrain[0].Kind <> btNoTerm) then begin
1417 OfferBrain(Brains[I], FixedLines);
1418 Inc(FixedLines);
1419 end;
1420 if PlayerPopupIndex > 0 then begin
1421 MenuItem := TMenuItem.Create(PopupMenu1);
1422 MenuItem.Caption := '-';
1423 PopupMenu1.Items.Add(MenuItem);
1424 Inc(FixedLines);
1425 if Brains.GetKindCount(btAI) >= 2 then begin
1426 OfferBrain(BrainRandom, FixedLines);
1427 Inc(FixedLines);
1428 end;
1429 AIBrains := TBrains.Create(False);
1430 Brains.GetByKind(btAI, AIBrains);
1431 for I := 0 to AIBrains.Count - 1 do // offer available AIs
1432 if (AIBrains[I].Flags and fMultiple <> 0) or (AIBrains[I].Flags and fUsed = 0)
1433 or (Brains[I] = PlayersBrain[PlayerPopupIndex]) then
1434 OfferBrain(AIBrains[i], FixedLines);
1435 AIBrains.Free;
1436 end;
1437 end;
1438end;
1439
1440procedure TStartDlg.UpdateFormerGames;
1441var
1442 I: Integer;
1443 F: TSearchRec;
1444begin
1445 FormerGames.Clear;
1446 if FindFirst(GetSavedDir + DirectorySeparator + '*' + CevoExt, $21, F) = 0 then
1447 repeat
1448 I := FormerGames.Count;
1449 while (I > 0) and (F.Time < integer(FormerGames.Objects[I - 1])) do
1450 Dec(I);
1451 FormerGames.InsertObject(I, Copy(F.Name, 1, Length(F.Name) - 5),
1452 TObject(F.Time));
1453 until FindNext(F) <> 0;
1454 FindClose(F);
1455 ListIndex[tbNew] := FormerGames.Count - 1;
1456 if (ShowTab = tbNew) and (FormerGames.Count > 0) then
1457 ShowTab := tbPrevious;
1458 TurnValid := False;
1459end;
1460
1461procedure TStartDlg.UpdateMaps;
1462var
1463 f: TSearchRec;
1464begin
1465 Maps.Clear;
1466 if FindFirst(GetMapsDir + DirectorySeparator + '*' + CevoMapExt, $21, f) = 0 then
1467 repeat
1468 Maps.Add(Copy(f.Name, 1, Length(f.Name) - 9));
1469 until FindNext(f) <> 0;
1470 FindClose(F);
1471 Maps.Sort;
1472 Maps.Insert(0, Phrases.Lookup('RANMAP'));
1473 ListIndex[tbMain] := Maps.IndexOf(Copy(MapFileName, 1, Length(MapFileName) - 9));
1474 if ListIndex[tbMain] < 0 then
1475 ListIndex[tbMain] := 0;
1476end;
1477
1478procedure TStartDlg.ChangePage(NewPage: TStartPage);
1479var
1480 i, j, p1: integer;
1481 s: string;
1482 Reg: TRegistry;
1483 InvalidateTab0: boolean;
1484begin
1485 InvalidateTab0 := (Page = pgMain) or (NewPage = pgMain);
1486 Page := NewPage;
1487 case Page of
1488 pgStartRandom, pgStartMap:
1489 begin
1490 StartBtn.Caption := Phrases.Lookup('STARTCONTROLS', 1);
1491 if Page = pgStartRandom then
1492 i := nPlOffered
1493 else
1494 begin
1495 i := nMapStartPositions;
1496 if i = 0 then
1497 begin
1498 PlayersBrain[0] := BrainSuperVirtual;
1499 Difficulty[0] := 0
1500 end;
1501 if PlayersBrain[0].Kind in [btNoTerm, btSuperVirtual] then
1502 inc(i);
1503 if i > nPl then
1504 i := nPl;
1505 if i <= nPlOffered then
1506 MultiControl := 0
1507 else
1508 MultiControl := InitMulti[i];
1509 end;
1510 if InitAlive[i] <> SlotAvailable then
1511 if Page = pgStartRandom then
1512 begin // restore AI assignment of last start
1513 Reg := TRegistry.Create;
1514 with Reg do
1515 try
1516 OpenKey(AppRegistryKey + '\AI', True);
1517 for p1 := 0 to nPlOffered - 1 do begin
1518 PlayersBrain[p1] := nil;
1519 s := ReadString('Control' + IntToStr(p1));
1520 Difficulty[p1] := ReadInteger('Diff' + IntToStr(p1));
1521 if s <> '' then
1522 for j := 0 to Brains.Count - 1 do
1523 if AnsiCompareFileName(s, Brains[j].FileName) = 0 then
1524 PlayersBrain[p1] := Brains[j];
1525 end;
1526 finally
1527 Free;
1528 end;
1529 end
1530 else
1531 for p1 := 1 to nPl - 1 do
1532 if 1 shl p1 and InitAlive[i] <> 0 then
1533 begin
1534 PlayersBrain[p1] := BrainDefault;
1535 Difficulty[p1] := 2;
1536 end
1537 else
1538 PlayersBrain[p1] := nil;
1539 SlotAvailable := InitAlive[i];
1540 for i := 0 to nPlOffered - 1 do
1541 if (AutoDiff < 0) and Assigned(PlayersBrain[i]) and
1542 (PlayersBrain[i].Kind in [btTerm, btRandom, btAI]) then
1543 begin
1544 PlayerSlots[i].DiffUpBtn.Tag := 768;
1545 PlayerSlots[i].DiffDownBtn.Tag := 768;
1546 end
1547 else
1548 begin
1549 PlayerSlots[i].DiffUpBtn.Tag := 0;
1550 PlayerSlots[i].DiffDownBtn.Tag := 0;
1551 end;
1552 for i := 6 to 8 do
1553 if (AutoDiff < 0) and Assigned(PlayersBrain[i]) and
1554 (PlayersBrain[i].Kind in [btTerm, btRandom, btAI]) then
1555 begin
1556 PlayerSlots[i].MultiBtn.Tag := 768;
1557 PlayerSlots[i].MultiBtn.ButtonIndex := 2 + (MultiControl shr i) and 1;
1558 PlayerSlots[i].MultiBtn.Enabled := Page = pgStartRandom
1559 end
1560 else
1561 PlayerSlots[i].MultiBtn.Tag := 0;
1562 if (AutoDiff > 0) and (Page <> pgStartMap) then
1563 begin
1564 AutoEnemyUpBtn.Tag := 768;
1565 AutoEnemyDownBtn.Tag := 768;
1566 end
1567 else
1568 begin
1569 AutoEnemyUpBtn.Tag := 0;
1570 AutoEnemyDownBtn.Tag := 0;
1571 end;
1572 if AutoDiff > 0 then
1573 begin
1574 AutoDiffUpBtn.Tag := 768;
1575 AutoDiffDownBtn.Tag := 768;
1576 end
1577 else
1578 begin
1579 AutoDiffUpBtn.Tag := 0;
1580 AutoDiffDownBtn.Tag := 0;
1581 end;
1582 end;
1583
1584 pgNoLoad, pgLoad:
1585 begin
1586 StartBtn.Caption := Phrases.Lookup('STARTCONTROLS', 2);
1587 RenameBtn.Hint := Phrases.Lookup('BTN_RENGAME');
1588 DeleteBtn.Hint := Phrases.Lookup('BTN_DELGAME');
1589 end;
1590
1591 pgEditRandom, pgEditMap:
1592 begin
1593 StartBtn.Caption := Phrases.Lookup('STARTCONTROLS', 12);
1594 RenameBtn.Hint := Phrases.Lookup('BTN_RENMAP');
1595 DeleteBtn.Hint := Phrases.Lookup('BTN_DELMAP');
1596 end;
1597 end;
1598
1599 PaintInfo;
1600 for i := 0 to ControlCount - 1 do
1601 Controls[i].Visible := Controls[i].Tag and (256 shl Integer(Page)) <> 0;
1602 if Page = pgLoad then
1603 ReplayBtn.Visible := MiniMap.Mode <> mmMultiPlayer;
1604 List.Invalidate;
1605 SmartInvalidate(0, 0, ClientWidth, ClientHeight, invalidateTab0);
1606end;
1607
1608procedure TStartDlg.ChangeTab(NewTab: TStartTab);
1609begin
1610 Tab := NewTab;
1611 case Tab of
1612 tbMap:
1613 List.Items.Assign(Maps);
1614 tbPrevious:
1615 List.Items.Assign(FormerGames);
1616 end;
1617 if Tab <> tbNew then
1618 if List.Count > 0 then begin
1619 if (ListIndex[Tab] < List.Count) and (ListIndex[Tab] >= 0) then
1620 List.ItemIndex := ListIndex[Tab]
1621 else List.ItemIndex := 0;
1622 end else List.ItemIndex := -1;
1623 case Tab of
1624 tbMain:
1625 ChangePage(pgMain);
1626 tbMap:
1627 if List.ItemIndex = 0 then
1628 ChangePage(pgEditRandom)
1629 else
1630 ChangePage(pgEditMap);
1631 tbNew:
1632 if MapFileName = '' then
1633 ChangePage(pgStartRandom)
1634 else
1635 ChangePage(pgStartMap);
1636 tbPrevious:
1637 if FormerGames.Count = 0 then
1638 ChangePage(pgNoLoad)
1639 else
1640 ChangePage(pgLoad);
1641 end;
1642end;
1643
1644procedure TStartDlg.FormMouseDown(Sender: TObject; Button: TMouseButton;
1645 Shift: TShiftState; x, y: integer);
1646var
1647 I: Integer;
1648begin
1649 if (y < TabHeight + 1) and (x - TabOffset < TabSize * 4) and
1650 ((x - TabOffset) div TabSize <> Integer(Tab)) then
1651 begin
1652 // Play('BUTTON_DOWN');
1653 ListIndex[Tab] := List.ItemIndex;
1654 ChangeTab(TStartTab((x - TabOffset) div TabSize));
1655 end
1656 else if Page = pgMain then
1657 begin
1658 case SelectedAction of
1659 maConfig:
1660 begin
1661 SettingsDlg := TSettingsDlg.Create(nil);
1662 if SettingsDlg.ShowModal = mrOk then begin
1663 LoadAssets;
1664 Invalidate;
1665 UpdateInterface;
1666 Background.UpdateInterface;
1667 end;
1668 FreeAndNil(SettingsDlg);
1669 end;
1670 maManual:
1671 DirectHelp(cStartHelp);
1672 maCredits:
1673 DirectHelp(cStartCredits);
1674 maAIDev:
1675 OpenDocument(HomeDir + AITemplateFileName);
1676 maWeb:
1677 OpenURL(CevoHomepage);
1678 end;
1679 end
1680 else if (AutoDiff < 0) and ((Page = pgStartRandom) or (Page = pgStartMap) and
1681 (nMapStartPositions > 0)) then
1682 begin
1683 for I := 0 to nPlOffered - 1 do
1684 if (1 shl I and SlotAvailable <> 0) and (x >= xBrain[I]) and
1685 (y >= yBrain[I]) and (x < xBrain[I] + 64) and (y < yBrain[I] + 64) then
1686 begin
1687 InitPopup(I);
1688 if yBrain[I] > y0Brain then
1689 PopupMenu1.Popup(left + xBrain[I] + 4, top + yBrain[I] + 60)
1690 else
1691 PopupMenu1.Popup(left + xBrain[I] + 4, top + yBrain[I] + 4);
1692 end
1693 end
1694 else if (AutoDiff > 1) and ((Page = pgStartRandom) or (Page = pgStartMap)) and
1695 (x >= xDefault) and (y >= yDefault) and (x < xDefault + 64) and
1696 (y < yDefault + 64) then
1697 if Brains.GetKindCount(btAI) < 2 then
1698 SimpleMessage(Phrases.Lookup('NOALTAI'))
1699 else
1700 begin
1701 InitPopup(-1);
1702 PopupMenu1.Popup(left + xDefault + 4, top + yDefault + 4);
1703 end
1704 else if (Page = pgLoad) and (LastTurn > 0) and (y >= yTurnSlider) and
1705 (y < yTurnSlider + 7) and (x >= xTurnSlider) and
1706 (x <= xTurnSlider + wTurnSlider) then
1707 begin
1708 LoadTurn := LastTurn * (x - xTurnSlider) div wTurnSlider;
1709 SmartInvalidate(xTurnSlider - 2, y0Mini + 61, xTurnSlider + wTurnSlider + 2,
1710 yTurnSlider + 9);
1711 Tracking := True;
1712 end;
1713end;
1714
1715procedure TStartDlg.Up2BtnClick(Sender: TObject);
1716begin
1717 case Page of
1718 pgStartRandom, pgStartMap:
1719 if MaxTurn < 1400 then
1720 begin
1721 inc(MaxTurn, 200);
1722 SmartInvalidate(344, y0Mini + 61, 514, y0Mini + 82);
1723 end;
1724 pgLoad:
1725 if LoadTurn < LastTurn then
1726 begin
1727 inc(LoadTurn);
1728 SmartInvalidate(xTurnSlider - 2, y0Mini + 61, xTurnSlider + wTurnSlider
1729 + 2, yTurnSlider + 9);
1730 end;
1731 pgEditRandom:
1732 if StartLandMass < 96 then
1733 begin
1734 inc(StartLandMass, 5);
1735 PaintInfo;
1736 SmartInvalidate(344, y0Mini + 61, 514, y0Mini + 61 + 21);
1737 end;
1738 end;
1739end;
1740
1741procedure TStartDlg.Down2BtnClick(Sender: TObject);
1742begin
1743 case Page of
1744 pgStartRandom, pgStartMap:
1745 if MaxTurn > 400 then
1746 begin
1747 dec(MaxTurn, 200);
1748 SmartInvalidate(344, y0Mini + 61, 514, y0Mini + 82);
1749 end;
1750 pgLoad:
1751 if LoadTurn > 0 then
1752 begin
1753 dec(LoadTurn);
1754 SmartInvalidate(xTurnSlider - 2, y0Mini + 61, xTurnSlider + wTurnSlider
1755 + 2, yTurnSlider + 9);
1756 end;
1757 pgEditRandom:
1758 if StartLandMass > 10 then
1759 begin
1760 dec(StartLandMass, 5);
1761 PaintInfo;
1762 SmartInvalidate(344, y0Mini + 61, 514, y0Mini + 61 + 21);
1763 end;
1764 end;
1765end;
1766
1767procedure TStartDlg.Up1BtnClick(Sender: TObject);
1768begin
1769 if WorldSize < MaxWorldSize - 1 then
1770 begin
1771 Inc(WorldSize);
1772 PaintInfo;
1773 SmartInvalidate(344, y0Mini - 77, 510, y0Mini - 77 + 21);
1774 end;
1775end;
1776
1777procedure TStartDlg.Down1BtnClick(Sender: TObject);
1778begin
1779 if WorldSize > 0 then
1780 begin
1781 Dec(WorldSize);
1782 PaintInfo;
1783 SmartInvalidate(344, y0Mini - 77, 510, y0Mini - 77 + 21);
1784 end;
1785end;
1786
1787procedure TStartDlg.FormClose(Sender: TObject; var Action: TCloseAction);
1788begin
1789 DirectDlg.Close;
1790end;
1791
1792procedure TStartDlg.ListClick(Sender: TObject);
1793var
1794 I: Integer;
1795begin
1796 if (Tab = tbMap) and ((List.ItemIndex = 0) <> (Page = pgEditRandom)) then
1797 begin
1798 if List.ItemIndex = 0 then
1799 Page := pgEditRandom
1800 else
1801 Page := pgEditMap;
1802 for I := 0 to ControlCount - 1 do
1803 Controls[I].Visible := Controls[I].Tag and (256 shl Integer(Page)) <> 0;
1804 SmartInvalidate(328, Up1Btn.top - 12, ClientWidth, Up2Btn.top + 35);
1805 end;
1806 if Page = pgLoad then
1807 TurnValid := False;
1808 PaintInfo;
1809 if Page = pgLoad then
1810 ReplayBtn.Visible := MiniMap.Mode <> mmMultiPlayer;
1811end;
1812
1813procedure TStartDlg.RenameBtnClick(Sender: TObject);
1814var
1815 i: integer;
1816 NewName: string;
1817 f: file;
1818 ok: boolean;
1819begin
1820 if List.ItemIndex >= 0 then
1821 begin
1822 if Page = pgLoad then
1823 InputDlg.Caption := Phrases.Lookup('TITLE_BOOKNAME')
1824 else
1825 InputDlg.Caption := Phrases.Lookup('TITLE_MAPNAME');
1826 InputDlg.EInput.Text := List.Items[List.ItemIndex];
1827 InputDlg.CenterToRect(BoundsRect);
1828 InputDlg.ShowModal;
1829 NewName := InputDlg.EInput.Text;
1830 while (NewName <> '') and (NewName[1] = '~') do
1831 Delete(NewName, 1, 1);
1832 if (InputDlg.ModalResult = mrOK) and (NewName <> '') and
1833 (NewName <> List.Items[List.ItemIndex]) then
1834 begin
1835 for i := 1 to Length(NewName) do
1836 if NewName[i] in ['\', '/', ':', '*', '?', '"', '<', '>', '|'] then
1837 begin
1838 SimpleMessage(Format(Phrases.Lookup('NOFILENAME'), [NewName[i]]));
1839 exit
1840 end;
1841 if Page = pgLoad then
1842 AssignFile(f, GetSavedDir + DirectorySeparator + List.Items[List.ItemIndex] + CevoExt)
1843 else
1844 AssignFile(f, GetMapsDir + DirectorySeparator + List.Items[List.ItemIndex] +
1845 CevoMapExt);
1846 ok := true;
1847 try
1848 if Page = pgLoad then
1849 Rename(f, GetSavedDir + DirectorySeparator + NewName + CevoExt)
1850 else
1851 Rename(f, GetMapsDir + DirectorySeparator + NewName + CevoMapExt);
1852 except
1853 // Play('INVALID');
1854 ok := false
1855 end;
1856 if Page <> pgLoad then
1857 try // rename map picture
1858 AssignFile(f, GetMapsDir + DirectorySeparator + List.Items[List.ItemIndex]
1859 + '.png');
1860 Rename(f, GetMapsDir + DirectorySeparator + NewName + '.png');
1861 except
1862 end;
1863 if ok then
1864 begin
1865 if Page = pgLoad then
1866 FormerGames[List.ItemIndex] := NewName
1867 else
1868 Maps[List.ItemIndex] := NewName;
1869 List.Items[List.ItemIndex] := NewName;
1870 if Page = pgEditMap then
1871 PaintInfo;
1872 List.Invalidate;
1873 end;
1874 end;
1875 end;
1876end;
1877
1878procedure TStartDlg.DeleteBtnClick(Sender: TObject);
1879var
1880 iDel: integer;
1881 f: file;
1882begin
1883 if List.ItemIndex >= 0 then
1884 begin
1885 if Page = pgLoad then
1886 MessgDlg.MessgText := Phrases.Lookup('DELETEQUERY')
1887 else
1888 MessgDlg.MessgText := Phrases.Lookup('MAPDELETEQUERY');
1889 MessgDlg.Kind := mkOKCancel;
1890 MessgDlg.ShowModal;
1891 if MessgDlg.ModalResult = mrOK then
1892 begin
1893 if Page = pgLoad then
1894 AssignFile(f, GetSavedDir + DirectorySeparator + List.Items[List.ItemIndex] + CevoExt)
1895 else
1896 AssignFile(f, GetMapsDir + DirectorySeparator + List.Items[List.ItemIndex] +
1897 CevoMapExt);
1898 Erase(f);
1899 iDel := List.ItemIndex;
1900 if Page = pgLoad then
1901 FormerGames.Delete(iDel)
1902 else
1903 Maps.Delete(iDel);
1904 List.Items.Delete(iDel);
1905 if List.Items.Count = 0 then
1906 ChangePage(pgNoLoad)
1907 else
1908 begin
1909 if iDel = 0 then
1910 List.ItemIndex := 0
1911 else
1912 List.ItemIndex := iDel - 1;
1913 if (Page = pgEditMap) and (List.ItemIndex = 0) then
1914 ChangePage(pgEditRandom)
1915 else
1916 begin
1917 List.Invalidate;
1918 if Page = pgLoad then
1919 TurnValid := false;
1920 PaintInfo;
1921 if Page = pgLoad then
1922 ReplayBtn.Visible := MiniMap.Mode <> mmMultiPlayer;
1923 end;
1924 end;
1925 end;
1926 end;
1927end;
1928
1929procedure TStartDlg.DiffBtnClick(Sender: TObject);
1930var
1931 I: Integer;
1932begin
1933 for I := 0 to nPlOffered - 1 do
1934 if (Sender = PlayerSlots[I].DiffUpBtn) and (Difficulty[I] < 3) or
1935 (Sender = PlayerSlots[I].DiffDownBtn) and (Difficulty[I] > 1) then
1936 begin
1937 if Sender = PlayerSlots[I].DiffUpBtn then
1938 Inc(Difficulty[I])
1939 else
1940 Dec(Difficulty[I]);
1941 SmartInvalidate(xBrain[I] - 18, yBrain[I] + 19, xBrain[I] - 18 + 12,
1942 yBrain[I] + (19 + 14));
1943 end;
1944end;
1945
1946procedure TStartDlg.MultiBtnClick(Sender: TObject);
1947var
1948 I: Integer;
1949begin
1950 for I := 6 to 8 do
1951 if Sender = PlayerSlots[I].MultiBtn then
1952 begin
1953 MultiControl := MultiControl xor (1 shl I);
1954 TButtonC(Sender).ButtonIndex := 2 + (MultiControl shr I) and 1;
1955 end;
1956end;
1957
1958procedure TStartDlg.FormHide(Sender: TObject);
1959begin
1960 Diff0 := Difficulty[0];
1961 ListIndex[Tab] := List.ItemIndex;
1962 ShowTab := Tab;
1963 Background.Enabled := True;
1964end;
1965
1966procedure TStartDlg.QuitBtnClick(Sender: TObject);
1967begin
1968 Close;
1969end;
1970
1971procedure TStartDlg.FormKeyDown(Sender: TObject; var Key: Word;
1972 Shift: TShiftState);
1973begin
1974 if KeyToShortCut(Key, Shift) = BHelp.ShortCut then
1975 DirectHelp(cStartHelp);
1976end;
1977
1978procedure TStartDlg.CustomizeBtnClick(Sender: TObject);
1979begin
1980 AutoDiff := -AutoDiff;
1981 CustomizeBtn.ButtonIndex := CustomizeBtn.ButtonIndex xor 1;
1982 ChangePage(Page);
1983end;
1984
1985procedure TStartDlg.AutoDiffUpBtnClick(Sender: TObject);
1986begin
1987 if AutoDiff < 5 then
1988 begin
1989 Inc(AutoDiff);
1990 SmartInvalidate(120, y0Mini + 61, 272, y0Mini + 61 + 21);
1991 SmartInvalidate(xDefault - 2, yDefault - 2, xDefault + 64 + 2,
1992 yDefault + 64 + 2);
1993 end;
1994end;
1995
1996procedure TStartDlg.AutoDiffDownBtnClick(Sender: TObject);
1997begin
1998 if AutoDiff > 1 then
1999 begin
2000 Dec(AutoDiff);
2001 SmartInvalidate(120, y0Mini + 61, 272, y0Mini + 61 + 21);
2002 SmartInvalidate(xDefault - 2, yDefault - 2, xDefault + 64 + 2,
2003 yDefault + 64 + 2);
2004 end;
2005end;
2006
2007procedure TStartDlg.FormMouseUp(Sender: TObject; Button: TMouseButton;
2008 Shift: TShiftState; x, y: integer);
2009begin
2010 Tracking := False;
2011end;
2012
2013procedure TStartDlg.FormMouseMove(Sender: TObject; Shift: TShiftState;
2014 x, y: integer);
2015var
2016 OldLoadTurn: Integer;
2017 NewSelectedAction: TMainAction;
2018begin
2019 if Tracking then
2020 begin
2021 x := x - xTurnSlider;
2022 if x < 0 then
2023 x := 0
2024 else if x > wTurnSlider then
2025 x := wTurnSlider;
2026 OldLoadTurn := LoadTurn;
2027 LoadTurn := LastTurn * x div wTurnSlider;
2028 if LoadTurn < OldLoadTurn then
2029 begin
2030 SmartInvalidate(xTurnSlider + LoadTurn * wTurnSlider div LastTurn,
2031 yTurnSlider, xTurnSlider + OldLoadTurn * wTurnSlider div LastTurn + 1,
2032 yTurnSlider + 7);
2033 SmartInvalidate(344, y0Mini + 61, 514, y0Mini + 82);
2034 end
2035 else if LoadTurn > OldLoadTurn then
2036 begin
2037 SmartInvalidate(xTurnSlider + OldLoadTurn * wTurnSlider div LastTurn,
2038 yTurnSlider, xTurnSlider + LoadTurn * wTurnSlider div LastTurn + 1,
2039 yTurnSlider + 7);
2040 SmartInvalidate(344, y0Mini + 61, 514, y0Mini + 82);
2041 end;
2042 end
2043 else if Page = pgMain then
2044 begin
2045 if (x >= ActionSideBorder) and (x < ClientWidth - ActionSideBorder) and
2046 (y >= yAction - 8) and (y < ClientHeight - ActionBottomBorder) then
2047 begin
2048 NewSelectedAction := TMainAction((y - (yAction - 8)) div ActionPitch);
2049 if not (NewSelectedAction in ActionsOffered) then
2050 NewSelectedAction := maNone;
2051 end
2052 else
2053 NewSelectedAction := maNone;
2054 if NewSelectedAction <> SelectedAction then
2055 begin
2056 if SelectedAction <> maNone then
2057 SmartInvalidate(ActionSideBorder, yAction + Integer(SelectedAction) * ActionPitch
2058 - 8, ClientWidth - ActionSideBorder, yAction + (Integer(SelectedAction) + 1) *
2059 ActionPitch - 8);
2060 SelectedAction := NewSelectedAction;
2061 if SelectedAction <> maNone then
2062 SmartInvalidate(ActionSideBorder, yAction + Integer(SelectedAction) * ActionPitch
2063 - 8, ClientWidth - ActionSideBorder, yAction + (Integer(SelectedAction) + 1) *
2064 ActionPitch - 8);
2065 end;
2066 end;
2067end;
2068
2069procedure TStartDlg.AutoEnemyUpBtnClick(Sender: TObject);
2070begin
2071 if AutoEnemies < nPl - 1 then
2072 begin
2073 Inc(AutoEnemies);
2074 SmartInvalidate(160, yMain + 140, 198, yMain + 140 + 21);
2075 end;
2076end;
2077
2078procedure TStartDlg.AutoEnemyDownBtnClick(Sender: TObject);
2079begin
2080 if AutoEnemies > 0 then
2081 begin
2082 Dec(AutoEnemies);
2083 SmartInvalidate(160, yMain + 140, 198, yMain + 140 + 21);
2084 end;
2085end;
2086
2087procedure TStartDlg.ReplayBtnClick(Sender: TObject);
2088begin
2089 LoadGame(GetSavedDir + DirectorySeparator, List.Items[List.ItemIndex] + CevoExt,
2090 LastTurn, True);
2091 SlotAvailable := -1;
2092end;
2093
2094
2095end.
Note: See TracBrowser for help on using the repository browser.