Added: loading of MapList from INI files

Added: dialog for adding map
This commit is contained in:
Mark van Renswoude 2014-06-30 21:41:54 +00:00
parent 736cb4b231
commit f82b8bdcf8
13 changed files with 1296 additions and 202 deletions

View File

@ -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}

View File

@ -6,7 +6,7 @@
<MainSource>ChivalryServerLauncher.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Build</Config>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>3</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>
@ -89,7 +89,6 @@
<DCCReference Include="source\model\Game.Chivalry.pas"/>
<DCCReference Include="source\model\Game.Registry.pas"/>
<DCCReference Include="source\Resources.pas"/>
<DCCReference Include="source\model\Game.Map.pas"/>
<DCCReference Include="source\view\Forms.Game.pas">
<Form>GameForm</Form>
<FormType>dfm</FormType>
@ -97,6 +96,9 @@
<DCCReference Include="source\bindings\Bindings.Converters.pas"/>
<DCCReference Include="source\model\Game.List.pas"/>
<DCCReference Include="source\persist\Persist.GameList.pas"/>
<DCCReference Include="source\view\Forms.Map.pas">
<Form>MapForm</Form>
</DCCReference>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -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;

View File

@ -15,7 +15,7 @@ type
in the base Chivalry class. }
TChivalryMedievalWarfareGame = class(TChivalryGame)
protected
procedure LoadSupportedMapList(AList: TList<IGameMap>); override;
procedure LoadSupportedMapList(AList: TList<TGameMap>); 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<IGameMap>);
procedure TChivalryMedievalWarfareGame.LoadSupportedMapList(AList: TList<TGameMap>);
var
mapListFileName: string;
mapList: TMemIniFile;

View File

@ -18,17 +18,19 @@ type
FServerName: string;
FMessageOfTheDay: string;
FSupportedMapList: TList<IGameMap>;
FMapList: TList<string>;
FSupportedMapList: TObjectList<TGameMap>;
FMapList: TObjectList<TGameMap>;
protected
procedure LoadSupportedMapList(AList: TList<IGameMap>); virtual; abstract;
procedure DoLoad; override;
procedure DoSave; override;
procedure LoadSupportedMapList(AList: TList<TGameMap>); 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<System.string>;
function GetSupportedMapList: System.Generics.Collections.TList<Game.Intf.IGameMap>;
function GetSupportedMapList: TList<TGameMap>;
function GetMapList: TList<TGameMap>;
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<IGameMap>.Create;
FMapList := TList<string>.Create;
FSupportedMapList := TObjectList<TGameMap>.Create(True);
FMapList := TObjectList<TGameMap>.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<System.string>;
function TChivalryGame.GetMapList: TList<TGameMap>;
begin
Result := FMapList;
end;
function TChivalryGame.GetSupportedMapList: System.Generics.Collections.TList<Game.Intf.IGameMap>;
function TChivalryGame.GetSupportedMapList: TList<TGameMap>;
begin
Result := FSupportedMapList;
end;

View File

@ -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<IGameMap>;
function GetMapList: TList<string>;
function GetSupportedMapList: TList<TGameMap>;
function GetMapList: TList<TGameMap>;
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.

View File

@ -8,7 +8,7 @@ uses
type
TGameList = class(TList<TCustomGame>)
TGameList = class(TObjectList<TCustomGame>)
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;

View File

@ -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 = '<a href="http://www.delphi-jedi.org/">www.delphi-jedi.org</a>'
TabOrder = 5
TabStop = True
OnLinkClick = llLinkClick
end
object llVirtualTreeview: TLinkLabel
@ -496,7 +578,8 @@ object MainForm: TMainForm
Caption =
'<a href="http://www.soft-gems.net/index.php/controls/virtual-tre' +
'eview">www.soft-gems.net/index.php/controls/virtual-treeview</a>'
TabOrder = 6
TabOrder = 7
TabStop = True
OnLinkClick = llLinkClick
end
object llChivalry: TLinkLabel
@ -506,6 +589,7 @@ object MainForm: TMainForm
Height = 17
Caption = '<a href="http://www.tornbanner.com/">www.tornbanner.com</a>'
TabOrder = 0
TabStop = True
OnLinkClick = llLinkClick
end
object llPixelophilia: TLinkLabel
@ -517,6 +601,7 @@ object MainForm: TMainForm
'<a href="http://omercetin.deviantart.com/">omercetin.deviantart.' +
'com</a>'
TabOrder = 1
TabStop = True
OnLinkClick = llLinkClick
end
object llGentleface: TLinkLabel
@ -528,6 +613,7 @@ object MainForm: TMainForm
'<a href="http://gentleface.com/free_icon_set.html">gentleface.co' +
'm/free_icon_set.html</a>'
TabOrder = 3
TabStop = True
OnLinkClick = llLinkClick
end
object llPixelophiliaCC: TLinkLabel
@ -539,6 +625,7 @@ object MainForm: TMainForm
'<a href="http://creativecommons.org/licenses/by-nc-nd/3.0/">Crea' +
'tive Commons Attribution-Noncommercial-No Derivate 3.0</a>'
TabOrder = 2
TabStop = True
OnLinkClick = llLinkClick
end
object llGentlefaceCC: TLinkLabel
@ -550,6 +637,7 @@ object MainForm: TMainForm
'<a href="http://creativecommons.org/licenses/by-nc/3.0/">Creativ' +
'e Commons Attribution-Noncommercial 3.0</a>'
TabOrder = 4
TabStop = True
OnLinkClick = llLinkClick
end
object llSuperObject: TLinkLabel
@ -560,33 +648,19 @@ object MainForm: TMainForm
Caption =
'<a href="https://code.google.com/p/superobject/">code.google.com' +
'/p/superobject</a>'
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

View File

@ -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<TBindingExpression>;
TPageMenuMap = TDictionary<TTabSheet, TX2MenuBarItem>;
@ -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

171
source/view/Forms.Map.dfm Normal file
View File

@ -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

360
source/view/Forms.Map.pas Normal file
View File

@ -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<string, PVirtualNode>;
parentNode: PVirtualNode;
node: PVirtualNode;
begin
vstMap.BeginUpdate;
try
vstMap.Clear;
categoryNodes := TDictionary<string, PVirtualNode>.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.