source: trunk/Start.pas@ 209

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