source: trunk/Start.pas

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