diff --git a/ChivalryServerLauncher.dpr b/ChivalryServerLauncher.dpr
index 1bb41a8..a1d972e 100644
--- a/ChivalryServerLauncher.dpr
+++ b/ChivalryServerLauncher.dpr
@@ -9,11 +9,11 @@ uses
Game.Chivalry in 'source\model\Game.Chivalry.pas',
Game.Registry in 'source\model\Game.Registry.pas',
Resources in 'source\Resources.pas',
- Game.Map in 'source\model\Game.Map.pas',
Forms.Game in 'source\view\Forms.Game.pas' {GameForm},
Bindings.Converters in 'source\bindings\Bindings.Converters.pas',
Game.List in 'source\model\Game.List.pas',
- Persist.GameList in 'source\persist\Persist.GameList.pas';
+ Persist.GameList in 'source\persist\Persist.GameList.pas',
+ Forms.Map in 'source\view\Forms.Map.pas' {MapForm};
{$R *.res}
diff --git a/ChivalryServerLauncher.dproj b/ChivalryServerLauncher.dproj
index fa57723..949299a 100644
--- a/ChivalryServerLauncher.dproj
+++ b/ChivalryServerLauncher.dproj
@@ -6,7 +6,7 @@
ChivalryServerLauncher.dpr
True
Build
- Win64
+ Win32
3
Application
@@ -89,7 +89,6 @@
-
dfm
@@ -97,6 +96,9 @@
+
+
+
Base
diff --git a/resources/images/toolbar/down.png b/resources/images/toolbar/down.png
new file mode 100644
index 0000000..d70cbf1
Binary files /dev/null and b/resources/images/toolbar/down.png differ
diff --git a/resources/images/toolbar/up.png b/resources/images/toolbar/up.png
new file mode 100644
index 0000000..3ca3afc
Binary files /dev/null and b/resources/images/toolbar/up.png differ
diff --git a/source/Resources.pas b/source/Resources.pas
index d7cf7c9..7c67ffe 100644
--- a/source/Resources.pas
+++ b/source/Resources.pas
@@ -15,12 +15,17 @@ const
implementation
uses
+ System.SysUtils,
+
X2UtApp;
function GetAssetPath(const AAsset: string): string;
begin
- Result := App.Path + AssetsPath + AAsset;
+ Result := App.UserPath + UserDataPath + AssetsPath + AAsset;
+
+ if not FileExists(Result) then
+ Result := App.Path + AssetsPath + AAsset;
end;
diff --git a/source/model/Game.Chivalry.MedievalWarfare.pas b/source/model/Game.Chivalry.MedievalWarfare.pas
index bdcae52..33b21d2 100644
--- a/source/model/Game.Chivalry.MedievalWarfare.pas
+++ b/source/model/Game.Chivalry.MedievalWarfare.pas
@@ -15,7 +15,7 @@ type
in the base Chivalry class. }
TChivalryMedievalWarfareGame = class(TChivalryGame)
protected
- procedure LoadSupportedMapList(AList: TList); override;
+ procedure LoadSupportedMapList(AList: TList); override;
public
class function GameName: string; override;
class function AutoDetect: TCustomGame; override;
@@ -31,7 +31,6 @@ uses
Winapi.Windows,
Resources,
- Game.Map,
Game.Registry;
@@ -56,6 +55,7 @@ var
serverPath: string;
begin
+ Result := nil;
steamPath := '';
registry := TRegistry.Create(KEY_READ);
@@ -81,7 +81,7 @@ begin
end;
-procedure TChivalryMedievalWarfareGame.LoadSupportedMapList(AList: TList);
+procedure TChivalryMedievalWarfareGame.LoadSupportedMapList(AList: TList);
var
mapListFileName: string;
mapList: TMemIniFile;
diff --git a/source/model/Game.Chivalry.pas b/source/model/Game.Chivalry.pas
index f5702e1..b9505c2 100644
--- a/source/model/Game.Chivalry.pas
+++ b/source/model/Game.Chivalry.pas
@@ -18,17 +18,19 @@ type
FServerName: string;
FMessageOfTheDay: string;
- FSupportedMapList: TList;
- FMapList: TList;
+ FSupportedMapList: TObjectList;
+ FMapList: TObjectList;
protected
- procedure LoadSupportedMapList(AList: TList); virtual; abstract;
+ procedure DoLoad; override;
+ procedure DoSave; override;
+
+ procedure LoadSupportedMapList(AList: TList); virtual; abstract;
+
+ function CreateGameMap(const AMapName: string): TGameMap; virtual;
public
constructor Create(const ALocation: string); override;
destructor Destroy; override;
- procedure Load; override;
- procedure Save; override;
-
{ IGameNetwork }
function GetServerPort: Integer;
function GetPeerPort: Integer;
@@ -53,13 +55,14 @@ type
property MessageOfTheDay: string read GetMessageOfTheDay write SetMessageOfTheDay;
{ IGameMapList }
- function GetMapList: System.Generics.Collections.TList;
- function GetSupportedMapList: System.Generics.Collections.TList;
+ function GetSupportedMapList: TList;
+ function GetMapList: TList;
end;
implementation
uses
+ System.Classes,
System.IniFiles,
System.SysUtils;
@@ -74,6 +77,9 @@ const
GameReplicationInfoServerName = 'ServerName';
GameReplicationInfoMessageOfTheDay = 'MessageOfTheDay';
+ GameAOCGame = 'AOC.AOCGame';
+ GameAOCGameMapList = 'Maplist';
+
EngineSettingsFileName = 'UDKGame\Config\PCServer-UDKEngine.ini';
EngineSteam = 'OnlineSubsystemSteamworks.OnlineSubsystemSteamworks';
@@ -86,8 +92,8 @@ constructor TChivalryGame.Create(const ALocation: string);
begin
inherited Create(ALocation);
- FSupportedMapList := TList.Create;
- FMapList := TList.Create;
+ FSupportedMapList := TObjectList.Create(True);
+ FMapList := TObjectList.Create(True);
LoadSupportedMapList(FSupportedMapList);
end;
@@ -101,10 +107,13 @@ begin
inherited Destroy;
end;
-procedure TChivalryGame.Load;
+
+procedure TChivalryGame.DoLoad;
var
gameSettings: TMemIniFile;
engineSettings: TMemIniFile;
+ mapListValues: TStringList;
+ valueIndex: Integer;
begin
gameSettings := TMemIniFile.Create(Location + GameSettingsFileName);
@@ -114,6 +123,20 @@ begin
FServerName := gameSettings.ReadString(GameReplicationInfo, GameReplicationInfoServerName, '');
FMessageOfTheDay := gameSettings.ReadString(GameReplicationInfo, GameReplicationInfoMessageOfTheDay, '');
+
+ { Maplist is special; it occurs multiple times and order matters }
+ mapListValues := TStringList.Create;
+ try
+ gameSettings.ReadSectionValues(GameAOCGame, mapListValues);
+
+ for valueIndex := 0 to Pred(mapListValues.Count) do
+ begin
+ if SameText(mapListValues.Names[valueIndex], GameAOCGameMapList) then
+ FMapList.Add(CreateGameMap(mapListValues.ValueFromIndex[valueIndex]));
+ end;
+ finally
+ FreeAndNil(mapListValues);
+ end;
finally
FreeAndNil(gameSettings);
end;
@@ -124,17 +147,35 @@ begin
finally
FreeAndNil(engineSettings);
end;
-
- // #ToDo1 -oMvR: 30-6-2014: load map list
end;
-procedure TChivalryGame.Save;
+procedure TChivalryGame.DoSave;
begin
// #ToDo1 -oMvR: 30-6-2014: save to INI files
end;
+function TChivalryGame.CreateGameMap(const AMapName: string): TGameMap;
+var
+ map: TGameMap;
+
+begin
+ Result := nil;
+
+ for map in GetSupportedMapList do
+ if SameText(map.Name, AMapName) then
+ begin
+ Result := TGameMap.Create(map);
+ break;
+ end;
+
+
+ if not Assigned(Result) then
+ Result := TGameMap.Create(AMapName, '', '');
+end;
+
+
function TChivalryGame.GetServerPort: Integer;
begin
Result := FServerPort;
@@ -215,13 +256,13 @@ begin
end;
-function TChivalryGame.GetMapList: System.Generics.Collections.TList;
+function TChivalryGame.GetMapList: TList;
begin
Result := FMapList;
end;
-function TChivalryGame.GetSupportedMapList: System.Generics.Collections.TList;
+function TChivalryGame.GetSupportedMapList: TList;
begin
Result := FSupportedMapList;
end;
diff --git a/source/model/Game.Intf.pas b/source/model/Game.Intf.pas
index 1680b93..d5ebfad 100644
--- a/source/model/Game.Intf.pas
+++ b/source/model/Game.Intf.pas
@@ -35,25 +35,55 @@ type
end;
- IGameMap = interface
- ['{B50A090C-3731-401F-91B5-0895CBE99921}']
- function GetCategory: string;
- function GetName: string;
- function GetDisplayName: string;
+ TGameMap = class(TObject)
+ private
+ FCategory: string;
+ FName: string;
+ FDisplayName: string;
+ protected
+ function GetDisplayName: string; virtual;
+ public
+ constructor Create(const AName: string; const ADisplayName, ACategory: string); overload;
+ constructor Create(AClone: TGameMap); overload;
- property Category: string read GetCategory;
- property Name: string read GetName;
+ property Category: string read FCategory;
+ property Name: string read FName;
property DisplayName: string read GetDisplayName;
end;
IGameMapList = interface
['{E8552B4C-9447-4FAD-BB20-C5EB3AF07B0E}']
- function GetSupportedMapList: TList;
- function GetMapList: TList;
+ function GetSupportedMapList: TList;
+ function GetMapList: TList;
end;
implementation
+uses
+ System.StrUtils;
+
+
+{ TGameMap }
+constructor TGameMap.Create(const AName, ADisplayName, ACategory: string);
+begin
+ inherited Create;
+
+ FName := AName;
+ FDisplayName := IfThen(Length(ADisplayName) > 0, ADisplayName, AName);
+ FCategory := ACategory;
+end;
+
+
+constructor TGameMap.Create(AClone: TGameMap);
+begin
+ Create(AClone.Name, AClone.DisplayName, AClone.Category);
+end;
+
+
+function TGameMap.GetDisplayName: string;
+begin
+ Result := FDisplayName;
+end;
end.
diff --git a/source/model/Game.List.pas b/source/model/Game.List.pas
index 103a322..cc3ed62 100644
--- a/source/model/Game.List.pas
+++ b/source/model/Game.List.pas
@@ -8,7 +8,7 @@ uses
type
- TGameList = class(TList)
+ TGameList = class(TObjectList)
private
class var SInstance: TGameList;
protected
@@ -37,7 +37,7 @@ end;
class function TGameList.Instance: TGameList;
begin
if not Assigned(SInstance) then
- SInstance := TGameList.Create;
+ SInstance := TGameList.Create(True);
Result := SInstance;
end;
diff --git a/source/view/Forms.Main.dfm b/source/view/Forms.Main.dfm
index 8355e5e..caf1dcb 100644
--- a/source/view/Forms.Main.dfm
+++ b/source/view/Forms.Main.dfm
@@ -21,32 +21,196 @@ object MainForm: TMainForm
TextHeight = 13
object grdMenu: TJvGradient
Left = 170
- Top = 75
+ Top = 76
Width = 4
- Height = 472
+ Height = 428
Align = alLeft
StartColor = clBtnShadow
EndColor = clBtnFace
ExplicitLeft = 244
ExplicitTop = 67
+ ExplicitHeight = 472
end
object shpMenu: TShape
Left = 169
- Top = 75
+ Top = 76
Width = 1
- Height = 472
+ Height = 428
Align = alLeft
Pen.Color = clWindowFrame
+ ExplicitTop = 75
+ ExplicitHeight = 472
+ end
+ object bvlButtons: TBevel
+ Left = 0
+ Top = 504
+ Width = 739
+ Height = 2
+ Align = alBottom
+ Shape = bsTopLine
+ ExplicitTop = 498
+ end
+ object shpLogo: TShape
+ Left = 0
+ Top = 75
+ Width = 739
+ Height = 1
+ Align = alTop
+ Pen.Color = clWindowFrame
+ ExplicitLeft = 174
+ ExplicitWidth = 472
end
object pcMain: TPageControl
Left = 174
- Top = 75
+ Top = 76
Width = 565
- Height = 472
- ActivePage = tsGames
+ Height = 428
+ ActivePage = tsMapList
Align = alClient
Style = tsButtons
TabOrder = 2
+ object tsMapList: TTabSheet
+ Caption = 'Game - MapList'
+ ImageIndex = 2
+ object vstMapList: TVirtualStringTree
+ AlignWithMargins = True
+ Left = 8
+ Top = 30
+ Width = 541
+ Height = 359
+ Margins.Left = 8
+ Margins.Top = 0
+ Margins.Right = 8
+ Margins.Bottom = 8
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'Tahoma'
+ Header.Font.Style = []
+ Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
+ TabOrder = 0
+ TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toWheelPanning, toEditOnClick]
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toFullRowSelect, toMiddleClickSelect, toMultiSelect, toRightClickSelect]
+ OnGetText = vstMapListGetText
+ Columns = <
+ item
+ Position = 0
+ Width = 337
+ WideText = 'Map name'
+ end
+ item
+ Position = 1
+ Width = 200
+ WideText = 'Category'
+ end>
+ end
+ object ToolBar1: TToolBar
+ AlignWithMargins = True
+ Left = 8
+ Top = 8
+ Width = 541
+ Height = 22
+ Margins.Left = 8
+ Margins.Top = 8
+ Margins.Right = 8
+ Margins.Bottom = 0
+ AutoSize = True
+ ButtonWidth = 89
+ Images = glToolbar
+ List = True
+ ShowCaptions = True
+ TabOrder = 1
+ object tbMapAdd: TToolButton
+ Left = 0
+ Top = 0
+ Action = actMapAdd
+ AutoSize = True
+ end
+ object tbMapRemove: TToolButton
+ Left = 73
+ Top = 0
+ Action = actMapRemove
+ AutoSize = True
+ end
+ object tbMapSep1: TToolButton
+ Left = 166
+ Top = 0
+ Width = 8
+ Caption = 'tbMapSep1'
+ ImageIndex = 2
+ Style = tbsSeparator
+ end
+ object tbMapUp: TToolButton
+ Left = 174
+ Top = 0
+ Action = actMapUp
+ AutoSize = True
+ end
+ object tbMapDown: TToolButton
+ Left = 246
+ Top = 0
+ Action = actMapDown
+ AutoSize = True
+ end
+ end
+ end
+ object tsConfiguration: TTabSheet
+ Caption = 'Server - Configuration'
+ ImageIndex = 1
+ object gbServerName: TGroupBox
+ AlignWithMargins = True
+ Left = 8
+ Top = 8
+ Width = 541
+ Height = 77
+ Margins.Left = 8
+ Margins.Top = 8
+ Margins.Right = 8
+ Margins.Bottom = 8
+ Align = alTop
+ TabOrder = 0
+ DesignSize = (
+ 541
+ 77)
+ object lblServerName: TLabel
+ Left = 12
+ Top = 15
+ Width = 65
+ Height = 13
+ Caption = 'Server name:'
+ end
+ object lblMessageOfTheDay: TLabel
+ Left = 12
+ Top = 42
+ Width = 99
+ Height = 13
+ Caption = 'Message of the day:'
+ end
+ object edtServerName: TEdit
+ Left = 132
+ Top = 12
+ Width = 401
+ Height = 21
+ Hint = 'INI:Engine.GameReplicationInfo>ServerName'
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 0
+ OnChange = EditChange
+ end
+ object edtMessageOfTheDay: TEdit
+ Left = 132
+ Top = 39
+ Width = 401
+ Height = 21
+ Hint = 'INI:Engine.GameReplicationInfo>MessageOfTheDay'
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 1
+ OnChange = EditChange
+ end
+ end
+ end
object tsNetwork: TTabSheet
Caption = 'Server - Network'
object gbPorts: TGroupBox
@@ -116,88 +280,6 @@ object MainForm: TMainForm
end
end
end
- object tsConfiguration: TTabSheet
- Caption = 'Server - Configuration'
- ImageIndex = 1
- object gbServerName: TGroupBox
- AlignWithMargins = True
- Left = 8
- Top = 8
- Width = 541
- Height = 77
- Margins.Left = 8
- Margins.Top = 8
- Margins.Right = 8
- Margins.Bottom = 8
- Align = alTop
- TabOrder = 0
- DesignSize = (
- 541
- 77)
- object lblServerName: TLabel
- Left = 12
- Top = 15
- Width = 65
- Height = 13
- Caption = 'Server name:'
- end
- object lblMessageOfTheDay: TLabel
- Left = 12
- Top = 42
- Width = 99
- Height = 13
- Caption = 'Message of the day:'
- end
- object edtServerName: TEdit
- Left = 132
- Top = 12
- Width = 401
- Height = 21
- Hint = 'INI:Engine.GameReplicationInfo>ServerName'
- Anchors = [akLeft, akTop, akRight]
- TabOrder = 0
- OnChange = EditChange
- end
- object edtMessageOfTheDay: TEdit
- Left = 132
- Top = 39
- Width = 401
- Height = 21
- Hint = 'INI:Engine.GameReplicationInfo>MessageOfTheDay'
- Anchors = [akLeft, akTop, akRight]
- TabOrder = 1
- OnChange = EditChange
- end
- end
- end
- object tsMapList: TTabSheet
- Caption = 'Game - MapList'
- ImageIndex = 2
- object vstMapList: TVirtualStringTree
- AlignWithMargins = True
- Left = 8
- Top = 8
- Width = 541
- Height = 425
- Margins.Left = 8
- Margins.Top = 8
- Margins.Right = 8
- Margins.Bottom = 8
- Align = alClient
- Header.AutoSizeIndex = 0
- Header.Font.Charset = DEFAULT_CHARSET
- Header.Font.Color = clWindowText
- Header.Font.Height = -11
- Header.Font.Name = 'Tahoma'
- Header.Font.Style = []
- Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
- TabOrder = 0
- Columns = <
- item
- Position = 0
- end>
- end
- end
object tsGames: TTabSheet
Caption = 'Launcher - Game locations'
ImageIndex = 3
@@ -206,7 +288,7 @@ object MainForm: TMainForm
Left = 8
Top = 30
Width = 541
- Height = 341
+ Height = 297
Margins.Left = 8
Margins.Top = 0
Margins.Right = 8
@@ -224,7 +306,6 @@ object MainForm: TMainForm
TreeOptions.SelectionOptions = [toFullRowSelect, toMiddleClickSelect, toRightClickSelect]
OnFocusChanged = vstGamesFocusChanged
OnGetText = vstGamesGetText
- OnInitNode = vstGamesInitNode
Columns = <
item
Position = 0
@@ -240,7 +321,7 @@ object MainForm: TMainForm
object pnlGamesWarning: TPanel
AlignWithMargins = True
Left = 8
- Top = 379
+ Top = 335
Width = 541
Height = 54
Margins.Left = 8
@@ -486,6 +567,7 @@ object MainForm: TMainForm
Height = 17
Caption = 'www.delphi-jedi.org'
TabOrder = 5
+ TabStop = True
OnLinkClick = llLinkClick
end
object llVirtualTreeview: TLinkLabel
@@ -496,7 +578,8 @@ object MainForm: TMainForm
Caption =
'www.soft-gems.net/index.php/controls/virtual-treeview'
- TabOrder = 6
+ TabOrder = 7
+ TabStop = True
OnLinkClick = llLinkClick
end
object llChivalry: TLinkLabel
@@ -506,6 +589,7 @@ object MainForm: TMainForm
Height = 17
Caption = 'www.tornbanner.com'
TabOrder = 0
+ TabStop = True
OnLinkClick = llLinkClick
end
object llPixelophilia: TLinkLabel
@@ -517,6 +601,7 @@ object MainForm: TMainForm
'omercetin.deviantart.' +
'com'
TabOrder = 1
+ TabStop = True
OnLinkClick = llLinkClick
end
object llGentleface: TLinkLabel
@@ -528,6 +613,7 @@ object MainForm: TMainForm
'gentleface.co' +
'm/free_icon_set.html'
TabOrder = 3
+ TabStop = True
OnLinkClick = llLinkClick
end
object llPixelophiliaCC: TLinkLabel
@@ -539,6 +625,7 @@ object MainForm: TMainForm
'Crea' +
'tive Commons Attribution-Noncommercial-No Derivate 3.0'
TabOrder = 2
+ TabStop = True
OnLinkClick = llLinkClick
end
object llGentlefaceCC: TLinkLabel
@@ -550,6 +637,7 @@ object MainForm: TMainForm
'Creativ' +
'e Commons Attribution-Noncommercial 3.0'
TabOrder = 4
+ TabStop = True
OnLinkClick = llLinkClick
end
object llSuperObject: TLinkLabel
@@ -560,33 +648,19 @@ object MainForm: TMainForm
Caption =
'code.google.com' +
'/p/superobject'
- TabOrder = 7
+ TabOrder = 6
+ TabStop = True
OnLinkClick = llLinkClick
end
end
end
object mbMenu: TX2MenuBar
Left = 0
- Top = 75
+ Top = 76
Width = 169
- Height = 472
+ Height = 428
Align = alLeft
Groups = <
- item
- Caption = 'Server'
- Expanded = True
- Items = <
- item
- Caption = 'Network'
- Enabled = False
- ImageIndex = 0
- end
- item
- Caption = 'Configuration'
- Enabled = False
- ImageIndex = 1
- end>
- end
item
Caption = 'Game'
Expanded = True
@@ -597,6 +671,21 @@ object MainForm: TMainForm
ImageIndex = 2
end>
end
+ item
+ Caption = 'Server'
+ Expanded = True
+ Items = <
+ item
+ Caption = 'Configuration'
+ Enabled = False
+ ImageIndex = 1
+ end
+ item
+ Caption = 'Network'
+ Enabled = False
+ ImageIndex = 0
+ end>
+ end
item
Caption = 'Launcher'
Expanded = True
@@ -1476,13 +1565,70 @@ object MainForm: TMainForm
ExplicitWidth = 307
end
end
+ object pnlButtons: TPanel
+ AlignWithMargins = True
+ Left = 8
+ Top = 514
+ Width = 723
+ Height = 25
+ Margins.Left = 8
+ Margins.Top = 8
+ Margins.Right = 8
+ Margins.Bottom = 8
+ Align = alBottom
+ BevelOuter = bvNone
+ TabOrder = 3
+ object btnLaunch: TButton
+ AlignWithMargins = True
+ Left = 0
+ Top = 0
+ Width = 113
+ Height = 25
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 8
+ Margins.Bottom = 0
+ Action = actLaunch
+ Align = alLeft
+ DropDownMenu = pmnLaunch
+ Style = bsSplitButton
+ TabOrder = 0
+ end
+ object btnClose: TButton
+ Left = 632
+ Top = 0
+ Width = 91
+ Height = 25
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 0
+ Margins.Bottom = 0
+ Action = actClose
+ Align = alRight
+ TabOrder = 1
+ end
+ object btnSave: TButton
+ AlignWithMargins = True
+ Left = 533
+ Top = 0
+ Width = 91
+ Height = 25
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 8
+ Margins.Bottom = 0
+ Action = actSave
+ Align = alRight
+ TabOrder = 2
+ end
+ end
object mbpMenuPainter: TX2MenuBarmusikCubePainter
- Left = 52
- Top = 460
+ Left = 44
+ Top = 444
end
object gcMenu: TX2GraphicContainer
- Left = 52
- Top = 400
+ Left = 44
+ Top = 388
object gcMenuNetwork: TX2GraphicContainerItem
Picture.Data = {
0954506E67496D61676589504E470D0A1A0A0000000D49484452000000100000
@@ -1656,13 +1802,13 @@ object MainForm: TMainForm
object glMenu: TX2GraphicList
Container = gcMenu
Convert = False
- Left = 112
- Top = 400
+ Left = 104
+ Top = 388
Bitmap = {}
end
object gcToolbar: TX2GraphicContainer
- Left = 52
- Top = 340
+ Left = 44
+ Top = 328
object gcToolbaradd: TX2GraphicContainerItem
Picture.Data = {
0954506E67496D61676589504E470D0A1A0A0000000D49484452000000100000
@@ -1879,17 +2025,247 @@ object MainForm: TMainForm
6CD9A8AA24D266B50000000049454E44AE426082}
PictureName = 'remove'
end
+ object gcToolbarup: TX2GraphicContainerItem
+ Picture.Data = {
+ 0954506E67496D61676589504E470D0A1A0A0000000D49484452000000100000
+ 001008060000001FF3FF6100000B2769545874584D4C3A636F6D2E61646F6265
+ 2E786D7000000000003C3F787061636B657420626567696E3D22EFBBBF222069
+ 643D2257354D304D7043656869487A7265537A4E54637A6B633964223F3E0A3C
+ 783A786D706D65746120786D6C6E733A783D2261646F62653A6E733A6D657461
+ 2F2220783A786D70746B3D2241646F626520584D5020436F726520352E302D63
+ 3036302036312E3133343737372C20323031302F30322F31322D31373A33323A
+ 30302020202020202020223E0A203C7264663A52444620786D6C6E733A726466
+ 3D22687474703A2F2F7777772E77332E6F72672F313939392F30322F32322D72
+ 64662D73796E7461782D6E7323223E0A20203C7264663A446573637269707469
+ 6F6E207264663A61626F75743D22220A20202020786D6C6E733A70686F746F73
+ 686F703D22687474703A2F2F6E732E61646F62652E636F6D2F70686F746F7368
+ 6F702F312E302F220A20202020786D6C6E733A786D705269676874733D226874
+ 74703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F726967687473
+ 2F220A20202020786D6C6E733A786D703D22687474703A2F2F6E732E61646F62
+ 652E636F6D2F7861702F312E302F220A20202020786D6C6E733A786D704D4D3D
+ 22687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F6D6D2F
+ 220A20202020786D6C6E733A73744576743D22687474703A2F2F6E732E61646F
+ 62652E636F6D2F7861702F312E302F73547970652F5265736F75726365457665
+ 6E7423220A20202020786D6C6E733A64633D22687474703A2F2F7075726C2E6F
+ 72672F64632F656C656D656E74732F312E312F220A20202020786D6C6E733A49
+ 70746334786D70436F72653D22687474703A2F2F697074632E6F72672F737464
+ 2F4970746334786D70436F72652F312E302F786D6C6E732F220A20202020786D
+ 6C6E733A706C75735F315F3D22687474703A2F2F6E732E757365706C75732E6F
+ 72672F6C64662F786D702F312E302F220A20202070686F746F73686F703A4865
+ 61646C696E653D225573657220696E74657266616365206D616B65207570220A
+ 202020786D705269676874733A4D61726B65643D2254727565220A202020786D
+ 703A4D65746164617461446174653D22323031312D30312D32355431333A3535
+ 3A31352B30313A3030220A202020786D704D4D3A496E7374616E636549443D22
+ 786D702E6969643A393546364339354138323238453031313938394343304131
+ 4144303242354332220A202020786D704D4D3A446F63756D656E7449443D2278
+ 6D702E6469643A30314135323744354530323745303131393839434330413141
+ 44303242354332220A202020786D704D4D3A4F726967696E616C446F63756D65
+ 6E7449443D22786D702E6469643A303141353237443545303237453031313938
+ 3943433041314144303242354332223E0A2020203C786D705269676874733A55
+ 736167655465726D733E0A202020203C7264663A416C743E0A20202020203C72
+ 64663A6C6920786D6C3A6C616E673D22782D64656661756C74223E4372656174
+ 69766520436F6D6D6F6E73204174747269627574696F6E2D4E6F6E436F6D6D65
+ 726369616C206C6963656E73653C2F7264663A6C693E0A202020203C2F726466
+ 3A416C743E0A2020203C2F786D705269676874733A55736167655465726D733E
+ 0A2020203C786D704D4D3A486973746F72793E0A202020203C7264663A536571
+ 3E0A20202020203C7264663A6C690A20202020202073744576743A616374696F
+ 6E3D227361766564220A20202020202073744576743A696E7374616E63654944
+ 3D22786D702E6969643A30314135323744354530323745303131393839434330
+ 41314144303242354332220A20202020202073744576743A7768656E3D223230
+ 31312D30312D32345431383A33393A30322B30313A3030220A20202020202073
+ 744576743A6368616E6765643D222F6D65746164617461222F3E0A2020202020
+ 3C7264663A6C690A20202020202073744576743A616374696F6E3D2273617665
+ 64220A20202020202073744576743A696E7374616E636549443D22786D702E69
+ 69643A3935463643393541383232384530313139383943433041314144303242
+ 354332220A20202020202073744576743A7768656E3D22323031312D30312D32
+ 355431333A35353A31352B30313A3030220A20202020202073744576743A6368
+ 616E6765643D222F6D65746164617461222F3E0A202020203C2F7264663A5365
+ 713E0A2020203C2F786D704D4D3A486973746F72793E0A2020203C64633A6372
+ 6561746F723E0A202020203C7264663A5365713E0A20202020203C7264663A6C
+ 693E47656E746C656661636520637573746F6D20746F6F6C6261722069636F6E
+ 732064657369676E3C2F7264663A6C693E0A202020203C2F7264663A5365713E
+ 0A2020203C2F64633A63726561746F723E0A2020203C64633A64657363726970
+ 74696F6E3E0A202020203C7264663A416C743E0A20202020203C7264663A6C69
+ 20786D6C3A6C616E673D22782D64656661756C74223E576972656672616D6520
+ 6D6F6E6F20746F6F6C6261722069636F6E733C2F7264663A6C693E0A20202020
+ 3C2F7264663A416C743E0A2020203C2F64633A6465736372697074696F6E3E0A
+ 2020203C64633A7375626A6563743E0A202020203C7264663A4261673E0A2020
+ 2020203C7264663A6C693E637573746F6D2069636F6E2064657369676E3C2F72
+ 64663A6C693E0A20202020203C7264663A6C693E746F6F6C6261722069636F6E
+ 733C2F7264663A6C693E0A20202020203C7264663A6C693E637573746F6D2069
+ 636F6E733C2F7264663A6C693E0A20202020203C7264663A6C693E696E746572
+ 666163652064657369676E3C2F7264663A6C693E0A20202020203C7264663A6C
+ 693E75692064657369676E3C2F7264663A6C693E0A20202020203C7264663A6C
+ 693E6775692064657369676E3C2F7264663A6C693E0A20202020203C7264663A
+ 6C693E7461736B6261722069636F6E733C2F7264663A6C693E0A202020203C2F
+ 7264663A4261673E0A2020203C2F64633A7375626A6563743E0A2020203C6463
+ 3A7269676874733E0A202020203C7264663A416C743E0A20202020203C726466
+ 3A6C6920786D6C3A6C616E673D22782D64656661756C74223E43726561746976
+ 6520436F6D6D6F6E73204174747269627574696F6E2D4E6F6E436F6D6D657263
+ 69616C206C6963656E73653C2F7264663A6C693E0A202020203C2F7264663A41
+ 6C743E0A2020203C2F64633A7269676874733E0A2020203C4970746334786D70
+ 436F72653A43726561746F72436F6E74616374496E666F0A2020202049707463
+ 34786D70436F72653A436955726C576F726B3D22687474703A2F2F7777772E67
+ 656E746C65666163652E636F6D222F3E0A2020203C706C75735F315F3A496D61
+ 676543726561746F723E0A202020203C7264663A5365713E0A20202020203C72
+ 64663A6C690A202020202020706C75735F315F3A496D61676543726561746F72
+ 4E616D653D2267656E746C65666163652E636F6D222F3E0A202020203C2F7264
+ 663A5365713E0A2020203C2F706C75735F315F3A496D61676543726561746F72
+ 3E0A2020203C706C75735F315F3A436F707972696768744F776E65723E0A2020
+ 20203C7264663A5365713E0A20202020203C7264663A6C690A20202020202070
+ 6C75735F315F3A436F707972696768744F776E65724E616D653D2267656E746C
+ 65666163652E636F6D222F3E0A202020203C2F7264663A5365713E0A2020203C
+ 2F706C75735F315F3A436F707972696768744F776E65723E0A20203C2F726466
+ 3A4465736372697074696F6E3E0A203C2F7264663A5244463E0A3C2F783A786D
+ 706D6574613E0A3C3F787061636B657420656E643D2272223F3E2642F45B0000
+ 001974455874536F6674776172650041646F626520496D616765526561647971
+ C9653C0000003C74455874414C54546167005468697320697320746865206963
+ 6F6E2066726F6D2047656E746C65666163652E636F6D20667265652069636F6E
+ 73207365742E20D86BE8C40000004474455874436F7079726967687400437265
+ 617469766520436F6D6D6F6E73204174747269627574696F6E204E6F6E2D436F
+ 6D6D65726369616C204E6F2044657269766174697665737BDDB0A00000004569
+ 5458744465736372697074696F6E000000000054686973206973207468652069
+ 636F6E2066726F6D2047656E746C65666163652E636F6D20667265652069636F
+ 6E73207365742E20BC11F81A0000004869545874436F70797269676874000000
+ 0000437265617469766520436F6D6D6F6E73204174747269627574696F6E204E
+ 6F6E2D436F6D6D65726369616C204E6F2044657269766174697665735882CB05
+ 000000F64944415478DACD923B0A83401086B3821622B8888556A6B0B2DA23E8
+ 0D921B2427CB11921B98236C6565112B2D442CAC2C343361577C850402C18581
+ 9D61FE6F666796EC7E3C64BB00C61825845CF0DEF7FD99735E7F0D0882802A8A
+ 1223478478D775519224F54780EFFB7B105FA13A1BC7A10B841CD3347DBC0578
+ 9EC744652A42B2E2E063275996F105C075DD8518FC082F208AE7903CCFF900B0
+ 6DFB80030393491CC54551BC3A701C870A0813CFA971B06559DE88699A2739ED
+ B1B8AAAAC9C02CCB9A40E47688AEEB180CC7E2A66956576618C61C7227AAAA86
+ 408AA10B0E16B56DBB2A9647D3348AF9600CF337FC95FF067802BD7672CA72B0
+ 05AE0000000049454E44AE426082}
+ PictureName = 'up'
+ end
+ object gcToolbardown: TX2GraphicContainerItem
+ Picture.Data = {
+ 0954506E67496D61676589504E470D0A1A0A0000000D49484452000000100000
+ 001008060000001FF3FF6100000B2769545874584D4C3A636F6D2E61646F6265
+ 2E786D7000000000003C3F787061636B657420626567696E3D22EFBBBF222069
+ 643D2257354D304D7043656869487A7265537A4E54637A6B633964223F3E0A3C
+ 783A786D706D65746120786D6C6E733A783D2261646F62653A6E733A6D657461
+ 2F2220783A786D70746B3D2241646F626520584D5020436F726520352E302D63
+ 3036302036312E3133343737372C20323031302F30322F31322D31373A33323A
+ 30302020202020202020223E0A203C7264663A52444620786D6C6E733A726466
+ 3D22687474703A2F2F7777772E77332E6F72672F313939392F30322F32322D72
+ 64662D73796E7461782D6E7323223E0A20203C7264663A446573637269707469
+ 6F6E207264663A61626F75743D22220A20202020786D6C6E733A70686F746F73
+ 686F703D22687474703A2F2F6E732E61646F62652E636F6D2F70686F746F7368
+ 6F702F312E302F220A20202020786D6C6E733A786D705269676874733D226874
+ 74703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F726967687473
+ 2F220A20202020786D6C6E733A786D703D22687474703A2F2F6E732E61646F62
+ 652E636F6D2F7861702F312E302F220A20202020786D6C6E733A786D704D4D3D
+ 22687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F6D6D2F
+ 220A20202020786D6C6E733A73744576743D22687474703A2F2F6E732E61646F
+ 62652E636F6D2F7861702F312E302F73547970652F5265736F75726365457665
+ 6E7423220A20202020786D6C6E733A64633D22687474703A2F2F7075726C2E6F
+ 72672F64632F656C656D656E74732F312E312F220A20202020786D6C6E733A49
+ 70746334786D70436F72653D22687474703A2F2F697074632E6F72672F737464
+ 2F4970746334786D70436F72652F312E302F786D6C6E732F220A20202020786D
+ 6C6E733A706C75735F315F3D22687474703A2F2F6E732E757365706C75732E6F
+ 72672F6C64662F786D702F312E302F220A20202070686F746F73686F703A4865
+ 61646C696E653D225573657220696E74657266616365206D616B65207570220A
+ 202020786D705269676874733A4D61726B65643D2254727565220A202020786D
+ 703A4D65746164617461446174653D22323031312D30312D32355431333A3535
+ 3A31352B30313A3030220A202020786D704D4D3A496E7374616E636549443D22
+ 786D702E6969643A444134444346354138323238453031313938394343304131
+ 4144303242354332220A202020786D704D4D3A446F63756D656E7449443D2278
+ 6D702E6469643A33373930333144354530323745303131393839434330413141
+ 44303242354332220A202020786D704D4D3A4F726967696E616C446F63756D65
+ 6E7449443D22786D702E6469643A333739303331443545303237453031313938
+ 3943433041314144303242354332223E0A2020203C786D705269676874733A55
+ 736167655465726D733E0A202020203C7264663A416C743E0A20202020203C72
+ 64663A6C6920786D6C3A6C616E673D22782D64656661756C74223E4372656174
+ 69766520436F6D6D6F6E73204174747269627574696F6E2D4E6F6E436F6D6D65
+ 726369616C206C6963656E73653C2F7264663A6C693E0A202020203C2F726466
+ 3A416C743E0A2020203C2F786D705269676874733A55736167655465726D733E
+ 0A2020203C786D704D4D3A486973746F72793E0A202020203C7264663A536571
+ 3E0A20202020203C7264663A6C690A20202020202073744576743A616374696F
+ 6E3D227361766564220A20202020202073744576743A696E7374616E63654944
+ 3D22786D702E6969643A33373930333144354530323745303131393839434330
+ 41314144303242354332220A20202020202073744576743A7768656E3D223230
+ 31312D30312D32345431383A33393A30322B30313A3030220A20202020202073
+ 744576743A6368616E6765643D222F6D65746164617461222F3E0A2020202020
+ 3C7264663A6C690A20202020202073744576743A616374696F6E3D2273617665
+ 64220A20202020202073744576743A696E7374616E636549443D22786D702E69
+ 69643A4441344443463541383232384530313139383943433041314144303242
+ 354332220A20202020202073744576743A7768656E3D22323031312D30312D32
+ 355431333A35353A31352B30313A3030220A20202020202073744576743A6368
+ 616E6765643D222F6D65746164617461222F3E0A202020203C2F7264663A5365
+ 713E0A2020203C2F786D704D4D3A486973746F72793E0A2020203C64633A6372
+ 6561746F723E0A202020203C7264663A5365713E0A20202020203C7264663A6C
+ 693E47656E746C656661636520637573746F6D20746F6F6C6261722069636F6E
+ 732064657369676E3C2F7264663A6C693E0A202020203C2F7264663A5365713E
+ 0A2020203C2F64633A63726561746F723E0A2020203C64633A64657363726970
+ 74696F6E3E0A202020203C7264663A416C743E0A20202020203C7264663A6C69
+ 20786D6C3A6C616E673D22782D64656661756C74223E576972656672616D6520
+ 6D6F6E6F20746F6F6C6261722069636F6E733C2F7264663A6C693E0A20202020
+ 3C2F7264663A416C743E0A2020203C2F64633A6465736372697074696F6E3E0A
+ 2020203C64633A7375626A6563743E0A202020203C7264663A4261673E0A2020
+ 2020203C7264663A6C693E637573746F6D2069636F6E2064657369676E3C2F72
+ 64663A6C693E0A20202020203C7264663A6C693E746F6F6C6261722069636F6E
+ 733C2F7264663A6C693E0A20202020203C7264663A6C693E637573746F6D2069
+ 636F6E733C2F7264663A6C693E0A20202020203C7264663A6C693E696E746572
+ 666163652064657369676E3C2F7264663A6C693E0A20202020203C7264663A6C
+ 693E75692064657369676E3C2F7264663A6C693E0A20202020203C7264663A6C
+ 693E6775692064657369676E3C2F7264663A6C693E0A20202020203C7264663A
+ 6C693E7461736B6261722069636F6E733C2F7264663A6C693E0A202020203C2F
+ 7264663A4261673E0A2020203C2F64633A7375626A6563743E0A2020203C6463
+ 3A7269676874733E0A202020203C7264663A416C743E0A20202020203C726466
+ 3A6C6920786D6C3A6C616E673D22782D64656661756C74223E43726561746976
+ 6520436F6D6D6F6E73204174747269627574696F6E2D4E6F6E436F6D6D657263
+ 69616C206C6963656E73653C2F7264663A6C693E0A202020203C2F7264663A41
+ 6C743E0A2020203C2F64633A7269676874733E0A2020203C4970746334786D70
+ 436F72653A43726561746F72436F6E74616374496E666F0A2020202049707463
+ 34786D70436F72653A436955726C576F726B3D22687474703A2F2F7777772E67
+ 656E746C65666163652E636F6D222F3E0A2020203C706C75735F315F3A496D61
+ 676543726561746F723E0A202020203C7264663A5365713E0A20202020203C72
+ 64663A6C690A202020202020706C75735F315F3A496D61676543726561746F72
+ 4E616D653D2267656E746C65666163652E636F6D222F3E0A202020203C2F7264
+ 663A5365713E0A2020203C2F706C75735F315F3A496D61676543726561746F72
+ 3E0A2020203C706C75735F315F3A436F707972696768744F776E65723E0A2020
+ 20203C7264663A5365713E0A20202020203C7264663A6C690A20202020202070
+ 6C75735F315F3A436F707972696768744F776E65724E616D653D2267656E746C
+ 65666163652E636F6D222F3E0A202020203C2F7264663A5365713E0A2020203C
+ 2F706C75735F315F3A436F707972696768744F776E65723E0A20203C2F726466
+ 3A4465736372697074696F6E3E0A203C2F7264663A5244463E0A3C2F783A786D
+ 706D6574613E0A3C3F787061636B657420656E643D2272223F3E5B45C3580000
+ 001974455874536F6674776172650041646F626520496D616765526561647971
+ C9653C0000003C74455874414C54546167005468697320697320746865206963
+ 6F6E2066726F6D2047656E746C65666163652E636F6D20667265652069636F6E
+ 73207365742E20D86BE8C40000004474455874436F7079726967687400437265
+ 617469766520436F6D6D6F6E73204174747269627574696F6E204E6F6E2D436F
+ 6D6D65726369616C204E6F2044657269766174697665737BDDB0A00000004569
+ 5458744465736372697074696F6E000000000054686973206973207468652069
+ 636F6E2066726F6D2047656E746C65666163652E636F6D20667265652069636F
+ 6E73207365742E20BC11F81A0000004869545874436F70797269676874000000
+ 0000437265617469766520436F6D6D6F6E73204174747269627574696F6E204E
+ 6F6E2D436F6D6D65726369616C204E6F2044657269766174697665735882CB05
+ 000001064944415478DADD523B0A83401075051BAB6DAC4488082208EA11DC1B
+ 24378827CB11921B982388958D18102B9BAD6C04CDCCB28A623E854DC854B333
+ F3DEBC9D19A2EC34F207046118C6849014FC6C180696E739FF04088280AAAA8A
+ F5D1388E8CF8BE8F8F18931010244551BC24F13C4F80A161244377E2BAEE1980
+ 97A9084990B92CCB1589E33814952EC00AF88998816DDB47E88C2454E68492BA
+ AE05896559B36C99E7F04EAAAABACD43344D330250BA20E1A844765AC501CC9A
+ A6C9365B300C0307331783CF25C10C069FB56D9BBD5D23A5F4004AAE0BB99365
+ D0F9C4397F7CBD035DD7A9FC4EB400B3AEEB36DB797B489AA65139580507D6F7
+ FDCBD5FEC029EF257802B99873F02768CFEC0000000049454E44AE426082}
+ PictureName = 'down'
+ end
end
object glToolbar: TX2GraphicList
Container = gcToolbar
- Left = 112
- Top = 340
+ Left = 104
+ Top = 328
Bitmap = {}
end
object alMain: TActionList
Images = glToolbar
- Left = 52
- Top = 288
+ Left = 44
+ Top = 276
object actGameAdd: TAction
Caption = '&Add game'
ImageIndex = 0
@@ -1901,5 +2277,45 @@ object MainForm: TMainForm
ImageIndex = 1
OnExecute = actGameRemoveExecute
end
+ object actMapAdd: TAction
+ Caption = '&Add map'
+ ImageIndex = 0
+ OnExecute = actMapAddExecute
+ end
+ object actMapRemove: TAction
+ Caption = '&Remove map'
+ Enabled = False
+ ImageIndex = 1
+ end
+ object actMapUp: TAction
+ Caption = 'Move &up'
+ Enabled = False
+ ImageIndex = 2
+ end
+ object actMapDown: TAction
+ Caption = 'Move &down'
+ Enabled = False
+ ImageIndex = 3
+ end
+ object actLaunch: TAction
+ Caption = '&Launch server'
+ end
+ object actCopyCmdLine: TAction
+ Caption = '&Copy command line'
+ end
+ object actSave: TAction
+ Caption = '&Save changes'
+ end
+ object actClose: TAction
+ Caption = '&Close'
+ OnExecute = actCloseExecute
+ end
+ end
+ object pmnLaunch: TPopupMenu
+ Left = 144
+ Top = 500
+ object pmnLaunchCopyCmdLine: TMenuItem
+ Action = actCopyCmdLine
+ end
end
end
diff --git a/source/view/Forms.Main.pas b/source/view/Forms.Main.pas
index 10d8f5c..c853c31 100644
--- a/source/view/Forms.Main.pas
+++ b/source/view/Forms.Main.pas
@@ -13,6 +13,7 @@ uses
Vcl.Imaging.pngimage,
Vcl.ImgList,
Vcl.Mask,
+ Vcl.Menus,
Vcl.StdCtrls,
Vcl.ToolWin,
@@ -32,6 +33,17 @@ uses
type
TMainForm = class(TForm)
+ actGameAdd: TAction;
+ actGameRemove: TAction;
+ actMapAdd: TAction;
+ actMapDown: TAction;
+ actMapRemove: TAction;
+ actMapUp: TAction;
+ alMain: TActionList;
+ btnClose: TButton;
+ btnLaunch: TButton;
+ btnSave: TButton;
+ bvlButtons: TBevel;
edtMessageOfTheDay: TEdit;
edtServerName: TEdit;
gbPorts: TGroupBox;
@@ -44,54 +56,67 @@ type
gcMenuSettings: TX2GraphicContainerItem;
gcToolbar: TX2GraphicContainer;
gcToolbaradd: TX2GraphicContainerItem;
+ gcToolbardown: TX2GraphicContainerItem;
gcToolbarremove: TX2GraphicContainerItem;
+ gcToolbarup: TX2GraphicContainerItem;
glMenu: TX2GraphicList;
glToolbar: TX2GraphicList;
grdMenu: TJvGradient;
imgGamesWarning: TImage;
imgLogo: TImage;
lblChivalry: TLabel;
- lblPixelophilia: TLabel;
lblGamesWarning: TLabel;
lblGentleface: TLabel;
lblJCL: TLabel;
lblMessageOfTheDay: TLabel;
lblPeerPort: TLabel;
+ lblPixelophilia: TLabel;
lblQueryPort: TLabel;
lblServerName: TLabel;
lblServerPort: TLabel;
+ lblSuperObject: TLabel;
lblVirtualTreeview: TLabel;
llChivalry: TLinkLabel;
- llPixelophilia: TLinkLabel;
llGentleface: TLinkLabel;
- llPixelophiliaCC: TLinkLabel;
llGentlefaceCC: TLinkLabel;
llJCL: TLinkLabel;
+ llPixelophilia: TLinkLabel;
+ llPixelophiliaCC: TLinkLabel;
+ llSuperObject: TLinkLabel;
llVirtualTreeview: TLinkLabel;
mbMenu: TX2MenuBar;
mbpMenuPainter: TX2MenuBarmusikCubePainter;
pcMain: TPageControl;
- pnlLogo: TPanel;
+ pmnLaunch: TPopupMenu;
+ pmnLaunchCopyCmdLine: TMenuItem;
+ pnlButtons: TPanel;
pnlGamesWarning: TPanel;
+ pnlLogo: TPanel;
sePeerPort: TJvSpinEdit;
seQueryPort: TJvSpinEdit;
seServerPort: TJvSpinEdit;
+ shpLogo: TShape;
shpMenu: TShape;
- tbGames: TToolBar;
tbGameAdd: TToolButton;
tbGameRemove: TToolButton;
+ tbGames: TToolBar;
+ tbMapAdd: TToolButton;
+ tbMapDown: TToolButton;
+ tbMapRemove: TToolButton;
+ tbMapSep1: TToolButton;
+ tbMapUp: TToolButton;
+ ToolBar1: TToolBar;
tsAbout: TTabSheet;
tsConfiguration: TTabSheet;
tsGames: TTabSheet;
tsMapList: TTabSheet;
tsNetwork: TTabSheet;
- vstMapList: TVirtualStringTree;
vstGames: TVirtualStringTree;
- alMain: TActionList;
- actGameAdd: TAction;
- actGameRemove: TAction;
- lblSuperObject: TLabel;
- llSuperObject: TLinkLabel;
+ vstMapList: TVirtualStringTree;
+ actLaunch: TAction;
+ actCopyCmdLine: TAction;
+ actSave: TAction;
+ actClose: TAction;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
@@ -102,9 +127,11 @@ type
procedure EditChange(Sender: TObject);
procedure actGameAddExecute(Sender: TObject);
procedure actGameRemoveExecute(Sender: TObject);
- procedure vstGamesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
procedure vstGamesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
procedure vstGamesFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
+ procedure vstMapListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
+ procedure actMapAddExecute(Sender: TObject);
+ procedure actCloseExecute(Sender: TObject);
private type
TBindingExpressionList = TList;
TPageMenuMap = TDictionary;
@@ -121,10 +148,10 @@ type
procedure Bind(const APropertyName: string; ADestObject: TObject; const ADestPropertyName: string);
procedure BindGameNetwork;
procedure BindGameName;
- procedure BindGameMapList;
- procedure UpdateMenu;
+ procedure UpdateMenu;
procedure UpdateGameList;
+ procedure UpdateMapList;
property ActiveGame: TCustomGame read FActiveGame write SetActiveGame;
property PageMenuMap: TPageMenuMap read FPageMenuMap;
@@ -148,6 +175,7 @@ uses
X2UtGraphics,
Forms.Game,
+ Forms.Map,
Game.Chivalry.MedievalWarfare,
Game.List,
Persist.GameList,
@@ -166,9 +194,6 @@ type
end;
- PCustomGame = ^TCustomGame;
-
-
const
INIHintPrefix = 'INI:';
INIHintSeparator = '>';
@@ -177,6 +202,9 @@ const
GameColumnName = 0;
GameColumnLocation = 1;
+ MapColumnName = 0;
+ MapColumnCategory = 1;
+
{$R *.dfm}
@@ -195,6 +223,10 @@ begin
FPageMenuMap := TPageMenuMap.Create(pcMain.PageCount);
+ vstGames.NodeDataSize := SizeOf(TCustomGame);
+ vstMapList.NodeDataSize := SizeOf(TCustomGame);
+
+
{ Configure pages }
for pageIndex := 0 to Pred(pcMain.PageCount) do
pcMain.Pages[pageIndex].TabVisible := False;
@@ -263,7 +295,7 @@ begin
BindGameName;
if Supports(ActiveGame, IGameMapList) then
- BindGameMapList;
+ UpdateMapList;
UpdateMenu;
end;
@@ -320,12 +352,6 @@ begin
end;
-procedure TMainForm.BindGameMapList;
-begin
- // #ToDo1 -oMvR: 30-6-2014: load map list
-end;
-
-
procedure TMainForm.UpdateMenu;
procedure EnablePageByInterface(APage: TTabSheet; AInterface: TGUID);
@@ -345,13 +371,20 @@ end;
procedure TMainForm.UpdateGameList;
begin
- vstGames.NodeDataSize := SizeOf(TCustomGame);
vstGames.RootNodeCount := TGameList.Instance.Count;
-
pnlGamesWarning.Visible := (TGameList.Instance.Count = 0);
end;
+procedure TMainForm.UpdateMapList;
+begin
+ if Assigned(ActiveGame) then
+ vstMapList.RootNodeCount := (ActiveGame as IGameMapList).GetMapList.Count
+ else
+ vstMapList.Clear;
+end;
+
+
procedure TMainForm.SetActiveGame(const Value: TCustomGame);
begin
if Value <> FActiveGame then
@@ -412,20 +445,23 @@ end;
procedure TMainForm.actGameRemoveExecute(Sender: TObject);
var
- nodeData: PCustomGame;
+ gameIndex: Integer;
+ game: TCustomGame;
begin
if not Assigned(vstGames.FocusedNode) then
exit;
- nodeData := vstGames.GetNodeData(vstGames.FocusedNode);
+ gameIndex := vstGames.FocusedNode^.Index;
+
if MessageBox(Self.Handle, 'Do you want to remove the selected game?', 'Remove', MB_YESNO or MB_ICONQUESTION) = ID_YES then
begin
vstGames.BeginUpdate;
try
- TGameList.Instance.Remove(nodeData^);
+ game := TGameList.Instance[gameIndex];
+ TGameList.Instance.Delete(gameIndex);
- if nodeData^ = ActiveGame then
+ if game = ActiveGame then
begin
if TGameList.Instance.Count > 0 then
ActiveGame := TGameList.Instance.First
@@ -444,29 +480,19 @@ begin
end;
-procedure TMainForm.vstGamesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
-var
- nodeData: PCustomGame;
-
-begin
- nodeData := Sender.GetNodeData(Node);
- nodeData^ := TGameList.Instance[Node^.Index];
-end;
-
-
procedure TMainForm.vstGamesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
- nodeData: PCustomGame;
+ game: TCustomGame;
begin
- nodeData := Sender.GetNodeData(Node);
+ game := TGameList.Instance[Node^.Index];
case Column of
GameColumnName:
- CellText := nodeData^.GameName;
+ CellText := game.GameName;
GameColumnLocation:
- CellText := nodeData^.Location;
+ CellText := game.Location;
end;
end;
@@ -477,6 +503,49 @@ begin
end;
+procedure TMainForm.vstMapListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
+var
+ map: TGameMap;
+
+begin
+ if not Assigned(ActiveGame) then
+ exit;
+
+ map := (ActiveGame as IGameMapList).GetMapList[Node^.Index];
+
+ case Column of
+ MapColumnName:
+ CellText := map.DisplayName;
+
+ MapColumnCategory:
+ CellText := map.Category;
+ end;
+end;
+
+
+procedure TMainForm.actMapAddExecute(Sender: TObject);
+var
+ mapList: IGameMapList;
+ map: TGameMap;
+
+begin
+ mapList := ActiveGame as IGameMapList;
+
+ if TMapForm.Insert(Self, mapList, map) then
+ begin
+ mapList.GetMapList.Add(map);
+ UpdateMapList;
+ end;
+end;
+
+
+procedure TMainForm.actCloseExecute(Sender: TObject);
+begin
+ Close;
+end;
+
+
+
{ TINIHintWindow }
function TINIHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string; AData: Pointer): TRect;
var
diff --git a/source/view/Forms.Map.dfm b/source/view/Forms.Map.dfm
new file mode 100644
index 0000000..12a6e85
--- /dev/null
+++ b/source/view/Forms.Map.dfm
@@ -0,0 +1,171 @@
+object MapForm: TMapForm
+ Left = 0
+ Top = 0
+ ActiveControl = vstMap
+ BorderIcons = [biSystemMenu]
+ BorderStyle = bsDialog
+ Caption = 'Map'
+ ClientHeight = 540
+ ClientWidth = 577
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poOwnerFormCenter
+ OnCreate = FormCreate
+ PixelsPerInch = 96
+ TextHeight = 13
+ object pnlButtons: TPanel
+ AlignWithMargins = True
+ Left = 8
+ Top = 507
+ Width = 561
+ Height = 25
+ Margins.Left = 8
+ Margins.Top = 0
+ Margins.Right = 8
+ Margins.Bottom = 8
+ Align = alBottom
+ AutoSize = True
+ BevelOuter = bvNone
+ TabOrder = 3
+ ExplicitTop = 91
+ ExplicitWidth = 503
+ object btnCancel: TButton
+ Left = 486
+ Top = 0
+ Width = 75
+ Height = 25
+ Align = alRight
+ Cancel = True
+ Caption = 'Cancel'
+ ModalResult = 2
+ TabOrder = 1
+ ExplicitLeft = 428
+ end
+ object btnOK: TButton
+ AlignWithMargins = True
+ Left = 403
+ Top = 0
+ Width = 75
+ Height = 25
+ Margins.Left = 0
+ Margins.Top = 0
+ Margins.Right = 8
+ Margins.Bottom = 0
+ Align = alRight
+ Caption = 'OK'
+ Default = True
+ TabOrder = 0
+ OnClick = btnOKClick
+ ExplicitLeft = 345
+ end
+ end
+ object vstMap: TVirtualStringTree
+ AlignWithMargins = True
+ Left = 8
+ Top = 37
+ Width = 561
+ Height = 433
+ Margins.Left = 8
+ Margins.Top = 8
+ Margins.Right = 8
+ Margins.Bottom = 8
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'Tahoma'
+ Header.Font.Style = []
+ Header.MainColumn = -1
+ TabOrder = 1
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toFullRowSelect]
+ OnCollapsing = vstMapCollapsing
+ OnCompareNodes = vstMapCompareNodes
+ OnFocusChanged = vstMapFocusChanged
+ OnFocusChanging = vstMapFocusChanging
+ OnGetText = vstMapGetText
+ OnPaintText = vstMapPaintText
+ ExplicitTop = 13
+ ExplicitHeight = 457
+ Columns = <>
+ end
+ object pnlMapName: TPanel
+ AlignWithMargins = True
+ Left = 8
+ Top = 478
+ Width = 561
+ Height = 21
+ Margins.Left = 8
+ Margins.Top = 0
+ Margins.Right = 8
+ Margins.Bottom = 8
+ Align = alBottom
+ AutoSize = True
+ BevelOuter = bvNone
+ TabOrder = 2
+ ExplicitTop = 468
+ ExplicitWidth = 689
+ DesignSize = (
+ 561
+ 21)
+ object lblMapName: TLabel
+ Left = 0
+ Top = 3
+ Width = 53
+ Height = 13
+ Caption = 'Map name:'
+ end
+ object edtMapName: TEdit
+ Left = 76
+ Top = 0
+ Width = 485
+ Height = 21
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 0
+ OnChange = edtMapNameChange
+ ExplicitWidth = 613
+ end
+ end
+ object pnlFilter: TPanel
+ AlignWithMargins = True
+ Left = 8
+ Top = 8
+ Width = 561
+ Height = 21
+ Margins.Left = 8
+ Margins.Top = 8
+ Margins.Right = 8
+ Margins.Bottom = 0
+ Align = alTop
+ AutoSize = True
+ BevelOuter = bvNone
+ TabOrder = 0
+ ExplicitLeft = 12
+ ExplicitTop = 482
+ DesignSize = (
+ 561
+ 21)
+ object lblFilter: TLabel
+ Left = 0
+ Top = 3
+ Width = 28
+ Height = 13
+ Caption = 'Filter:'
+ end
+ object edtFilter: TEdit
+ Left = 76
+ Top = 0
+ Width = 485
+ Height = 21
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 0
+ OnChange = edtFilterChange
+ end
+ end
+end
diff --git a/source/view/Forms.Map.pas b/source/view/Forms.Map.pas
new file mode 100644
index 0000000..7ae18fc
--- /dev/null
+++ b/source/view/Forms.Map.pas
@@ -0,0 +1,360 @@
+unit Forms.Map;
+
+interface
+uses
+ System.Classes,
+ Vcl.Controls,
+ Vcl.ExtCtrls,
+ Vcl.Forms,
+ Vcl.Graphics,
+ Vcl.StdCtrls,
+
+ VirtualTrees,
+
+ Game.Base,
+ Game.Intf;
+
+
+type
+ TMapForm = class(TForm)
+ btnCancel: TButton;
+ btnOK: TButton;
+ edtMapName: TEdit;
+ lblMapName: TLabel;
+ pnlButtons: TPanel;
+ pnlMapName: TPanel;
+ vstMap: TVirtualStringTree;
+ pnlFilter: TPanel;
+ lblFilter: TLabel;
+ edtFilter: TEdit;
+
+ procedure btnOKClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure vstMapGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
+ procedure vstMapPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
+ procedure vstMapFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean);
+ procedure vstMapFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
+ procedure vstMapCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode; var Allowed: Boolean);
+ procedure vstMapCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+ procedure edtMapNameChange(Sender: TObject);
+ procedure edtFilterChange(Sender: TObject);
+ private
+ FLockMapChange: Boolean;
+
+ function GetMapName: string;
+ procedure SetMapName(const Value: string);
+ protected
+ procedure LoadSupportedMapList(AGame: IGameMapList);
+ function CreateMap: TGameMap;
+
+ function FindMapNode(const AMapName: string): PVirtualNode;
+
+ property MapName: string read GetMapName write SetMapName;
+ public
+ class function Insert(AOwner: TComponent; AGame: IGameMapList; out AMap: TGameMap): Boolean;
+ end;
+
+
+implementation
+uses
+ System.Generics.Collections,
+ System.StrUtils,
+ System.SysUtils,
+ Winapi.Windows;
+
+
+type
+ PGameMap = ^TGameMap;
+
+
+const
+ EmptyCategory = 'Other';
+
+
+{$R *.dfm}
+
+
+{ TMapForm }
+class function TMapForm.Insert(AOwner: TComponent; AGame: IGameMapList; out AMap: TGameMap): Boolean;
+begin
+ with Self.Create(AOwner) do
+ try
+ LoadSupportedMapList(AGame);
+
+ Result := (ShowModal = mrOk);
+ if Result then
+ AMap := CreateMap;
+ finally
+ Free;
+ end;
+end;
+
+
+procedure TMapForm.FormCreate(Sender: TObject);
+begin
+ vstMap.NodeDataSize := SizeOf(PGameMap);
+end;
+
+
+procedure TMapForm.LoadSupportedMapList(AGame: IGameMapList);
+var
+ map: TGameMap;
+ categoryNodes: TDictionary;
+ parentNode: PVirtualNode;
+ node: PVirtualNode;
+
+begin
+ vstMap.BeginUpdate;
+ try
+ vstMap.Clear;
+
+ categoryNodes := TDictionary.Create;
+ try
+ for map in AGame.GetSupportedMapList do
+ begin
+ if categoryNodes.ContainsKey(map.Category) then
+ parentNode := categoryNodes[map.Category]
+ else
+ begin
+ parentNode := vstMap.AddChild(nil, map);
+ categoryNodes.Add(map.Category, parentNode);
+ end;
+
+ vstMap.AddChild(parentNode, map);
+ end;
+ finally
+ FreeAndNil(categoryNodes);
+ end;
+ finally
+ vstMap.FullExpand;
+
+ node := vstMap.GetFirstLevel(1);
+ if Assigned(node) then
+ begin
+ vstMap.FocusedNode := node;
+ vstMap.Selected[node] := True;
+ end;
+
+ vstMap.EndUpdate;
+ end;
+end;
+
+
+function TMapForm.CreateMap: TGameMap;
+var
+ node: PVirtualNode;
+ nodeData: PGameMap;
+
+begin
+ node := FindMapNode(MapName);
+ if Assigned(node) then
+ begin
+ nodeData := vstMap.GetNodeData(node);
+ Result := TGameMap.Create(nodeData^);
+ end else
+ Result := TGameMap.Create(MapName, '', '');
+end;
+
+
+function TMapForm.GetMapName: string;
+begin
+ Result := Trim(edtMapName.Text);
+end;
+
+
+procedure TMapForm.SetMapName(const Value: string);
+begin
+ edtMapName.Text := Value;
+end;
+
+
+function TMapForm.FindMapNode(const AMapName: string): PVirtualNode;
+begin
+ Result := vstMap.IterateSubtree(nil,
+ procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean)
+ var
+ nodeData: PGameMap;
+
+ begin
+ nodeData := Sender.GetNodeData(Node);
+ Abort := SameText(nodeData^.Name, AMapName);
+ end,
+ nil);
+end;
+
+
+procedure TMapForm.btnOKClick(Sender: TObject);
+begin
+ if Length(MapName) = 0 then
+ begin
+ MessageBox(Self.Handle, 'Please enter a map name', 'Error', MB_OK or MB_ICONERROR);
+ ActiveControl := edtMapName;
+ exit;
+ end;
+
+ ModalResult := mrOk;
+end;
+
+
+procedure TMapForm.vstMapGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
+var
+ nodeData: PGameMap;
+
+begin
+ nodeData := Sender.GetNodeData(Node);
+
+ if Sender.GetNodeLevel(Node) = 0 then
+ begin
+ if Length(nodeData^.Category) > 0 then
+ CellText := nodeData^.Category
+ else
+ CellText := EmptyCategory;
+ end else
+ CellText := nodeData^.DisplayName;
+end;
+
+
+procedure TMapForm.vstMapPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
+begin
+ if (TextType = ttNormal) and (Sender.GetNodeLevel(Node) = 0) then
+ TargetCanvas.Font.Style := [fsBold];
+end;
+
+
+procedure TMapForm.vstMapFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean);
+var
+ sibling: PVirtualNode;
+
+begin
+ Allowed := True;
+
+ if not Assigned(NewNode) then
+ exit;
+
+ { Prevent selection of categories while being keyboard-friendly }
+ if Sender.GetNodeLevel(NewNode) = 0 then
+ begin
+ if Assigned(OldNode) then
+ begin
+ if Sender.AbsoluteIndex(OldNode) < Sender.AbsoluteIndex(NewNode) then
+ begin
+ { Moving forwards }
+ Sender.FocusedNode := Sender.GetFirstChild(NewNode);
+ end else
+ begin
+ { Moving backwards }
+ sibling := Sender.GetPreviousSibling(NewNode);
+ if Assigned(sibling) then
+ Sender.FocusedNode := Sender.GetLastChild(sibling);
+ end;
+ end;
+
+ Allowed := False;
+ end;
+end;
+
+
+procedure TMapForm.vstMapFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
+var
+ nodeData: PGameMap;
+
+begin
+ if Assigned(Node) then
+ begin
+ nodeData := Sender.GetNodeData(Node);
+
+ FLockMapChange := True;
+ try
+ edtMapName.Text := nodeData^.Name;
+ finally
+ FLockMapChange := False;
+ end;
+ end;
+end;
+
+
+procedure TMapForm.vstMapCollapsing(Sender: TBaseVirtualTree; Node: PVirtualNode; var Allowed: Boolean);
+begin
+ Allowed := False;
+end;
+
+
+procedure TMapForm.vstMapCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+var
+ nodeData1: PGameMap;
+ nodeData2: PGameMap;
+
+begin
+ nodeData1 := Sender.GetNodeData(Node1);
+ nodeData2 := Sender.GetNodeData(Node2);
+
+ if Sender.GetNodeLevel(Node1) = 0 then
+ Result := CompareText(nodeData1^.Category, nodeData2^.Category)
+ else
+ Result := CompareText(nodeData1^.DisplayName, nodeData2^.DisplayName);
+end;
+
+
+procedure TMapForm.edtFilterChange(Sender: TObject);
+var
+ node: PVirtualNode;
+ filtered: Boolean;
+ childNode: PVirtualNode;
+
+begin
+ vstMap.BeginUpdate;
+ try
+ { First run; set visibility of map nodes }
+ vstMap.IterateSubtree(nil,
+ procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean)
+ var
+ nodeData: PGameMap;
+
+ begin
+ if Sender.GetNodeLevel(Node) > 0 then
+ begin
+ nodeData := Sender.GetNodeData(Node);
+ Sender.IsFiltered[Node] := (Length(edtFilter.Text) > 0) and (not ContainsText(nodeData^.DisplayName, edtFilter.Text));
+ end;
+ end,
+ nil);
+
+ { Second run; hide empty categories }
+ node := vstMap.GetFirst;
+ while Assigned(node) do
+ begin
+ vstMap.IsFiltered[Node] := not Assigned(vstMap.IterateSubtree(node,
+ procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean)
+ begin
+ Abort := not Sender.IsFiltered[Node];
+ end,
+ nil, [], False, True));
+
+ node := vstMap.GetNextSibling(node);
+ end;
+ finally
+ vstMap.EndUpdate;
+ end;
+end;
+
+
+procedure TMapForm.edtMapNameChange(Sender: TObject);
+var
+ node: PVirtualNode;
+
+begin
+ if FLockMapChange then
+ exit;
+
+ node := FindMapNode(MapName);
+ vstMap.FocusedNode := node;
+
+ if Assigned(node) then
+ begin
+ vstMap.Selected[node] := True;
+ vstMap.ScrollIntoView(node, True);
+ end else
+ vstMap.ClearSelection;
+end;
+
+end.