source: trunk/Start.pas

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