source: tags/1.2.0/Start.pas

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