1
0
forked from 0ad/0ad

Implements skirmish maps, based on patch by sanderd17, fixes #1198. Skirmish maps are like scenarios, except the player can choose their civ during match setup. To create a skirmish map: place some skirmish entities for each player in Atlas (see templates/skirmish/* for examples), uncheck the player's civ in Atlas' player panel if desired, and save in the maps/skirmishes directory. The map will appear in match setup under the "Skirmish" match type.

Implements custom, VFS-based map load/save dialogs for Atlas (replaces
broken native file dialogs), fixes #631, #889.
Fixes map loading/saving to handle arbitrary subdirectories for better
organization.
Adds default settings to Atlas player panel, fixes #1872. Each setting
now has a checkbox to choose whether it should be saved with the map
(avoids writing lots of useless default data for each map).
Adds map preview setting to Atlas, refs #1745.
Cleans up and simplifies some duplicate code.
Fixes optional serialization performance test.

This was SVN commit r13938.
This commit is contained in:
historic_bruno 2013-10-04 02:29:16 +00:00
parent 5c35690309
commit 7901ed51d4
37 changed files with 997 additions and 226 deletions

View File

@ -107,8 +107,8 @@ function initMain()
// Init map types
var mapTypes = getGUIObjectByName("mapTypeSelection");
mapTypes.list = ["Scenario","Random"];
mapTypes.list_data = ["scenario","random"];
mapTypes.list = ["Scenario","Skirmish","Random"];
mapTypes.list_data = ["scenario","skirmish","random"];
// Setup map filters - will appear in order they are added
addFilter("Default", function(settings) { return settings && !keywordTestOR(settings.Keywords, ["naval", "demo", "hidden"]); });
@ -471,6 +471,7 @@ function initMapNameList()
switch (g_GameAttributes.mapType)
{
case "scenario":
case "skirmish":
mapFiles = getXMLFileList(g_GameAttributes.mapPath);
break;
@ -487,7 +488,7 @@ function initMapNameList()
var mapList = [];
for (var i = 0; i < mapFiles.length; ++i)
{
var file = mapFiles[i];
var file = g_GameAttributes.mapPath + mapFiles[i];
var mapData = loadMapData(file);
if (g_GameAttributes.mapFilter && mapData && testFilter(g_GameAttributes.mapFilter, mapData.settings))
@ -521,22 +522,20 @@ function loadMapData(name)
if (!name)
return undefined;
if (name == "random")
{
g_MapData[name] = {settings : {"Name" : "Random", "Description" : "Randomly selects a map from the list"}};
return g_MapData[name];
}
if (!g_MapData[name])
{
switch (g_GameAttributes.mapType)
{
case "scenario":
g_MapData[name] = Engine.LoadMapSettings(g_GameAttributes.mapPath+name);
case "skirmish":
g_MapData[name] = Engine.LoadMapSettings(name);
break;
case "random":
g_MapData[name] = parseJSONData(g_GameAttributes.mapPath+name+".json");
if (name == "random")
g_MapData[name] = {settings : {"Name" : "Random", "Description" : "Randomly selects a map from the list"}};
else
g_MapData[name] = parseJSONData(name+".json");
break;
default:
@ -652,8 +651,17 @@ function selectMapType(type)
case "scenario":
// Set a default map
// TODO: This should be remembered from the last session
g_GameAttributes.map = (g_IsNetworked ? DEFAULT_NETWORKED_MAP : DEFAULT_OFFLINE_MAP);
g_GameAttributes.mapPath = "maps/scenarios/";
g_GameAttributes.map = g_GameAttributes.mapPath + (g_IsNetworked ? DEFAULT_NETWORKED_MAP : DEFAULT_OFFLINE_MAP);
break;
case "skirmish":
g_GameAttributes.mapPath = "maps/skirmishes/";
g_GameAttributes.settings = {
PlayerData: g_DefaultPlayerData.slice(0, 4),
Seed: Math.floor(Math.random() * 65536),
CheatsEnabled: g_GameAttributes.settings.CheatsEnabled
};
break;
case "random":
@ -800,7 +808,7 @@ function launchGame()
else
var chosenName = civAINames[Math.floor(Math.random() * civAINames.length)];
for (var j = 0; j < numPlayers; ++j)
if (g_GameAttributes.settings.PlayerData[j].Name.indexOf(chosenName) !== -1)
if (g_GameAttributes.settings.PlayerData[j].Name && g_GameAttributes.settings.PlayerData[j].Name.indexOf(chosenName) !== -1)
usedName++;
// Assign civ specific names to AI players
@ -899,12 +907,16 @@ function onGameAttributesChange()
startingResources.selected = (STARTING_RESOURCES_DATA.indexOf(mapSettings.StartingResources) != -1 ? STARTING_RESOURCES_DATA.indexOf(mapSettings.StartingResources) : STARTING_RESOURCES_DEFAULTIDX);
startingResourcesText.caption = STARTING_RESOURCES[startingResources.selected];
// Update map preview
getGUIObjectByName("mapPreview").sprite = "cropped:(0.78125,0.5859375)session/icons/mappreview/" + getMapPreview(mapName);
// Handle map type specific logic
switch (g_GameAttributes.mapType)
{
case "random":
if (g_IsController)
{ //Host
{
//Host
numPlayersSelection.selected = numPlayers - 1;
numPlayersSelection.hidden = false;
mapSize.hidden = false;
@ -922,9 +934,6 @@ function onGameAttributesChange()
populationCapText.hidden = true;
startingResourcesText.hidden = true;
// Update map preview
getGUIObjectByName("mapPreview").sprite = "cropped:(0.78125,0.5859375)session/icons/mappreview/" + getMapPreview(mapName);
mapSizeText.caption = "Map size:";
mapSize.selected = sizeIdx;
revealMapText.caption = "Reveal map:";
@ -947,8 +956,6 @@ function onGameAttributesChange()
populationCapText.hidden = false;
startingResources.hidden = true;
startingResourcesText.hidden = false;
// Update map preview
getGUIObjectByName("mapPreview").sprite = "cropped:(0.78125,0.5859375)session/icons/mappreview/" + getMapPreview(mapName);
numPlayersText.caption = numPlayers;
mapSizeText.caption = g_MapSizes.names[sizeIdx];
@ -959,6 +966,57 @@ function onGameAttributesChange()
break;
case "skirmish":
mapSizeText.caption = "Default";
numPlayersText.caption = numPlayers;
numPlayersSelection.hidden = true;
mapSize.hidden = true;
if (g_IsController)
{
//Host
revealMap.hidden = false;
victoryCondition.hidden = false;
lockTeams.hidden = false;
populationCap.hidden = false;
startingResources.hidden = false;
numPlayersText.hidden = false;
mapSizeText.hidden = false;
revealMapText.hidden = true;
victoryConditionText.hidden = true;
lockTeamsText.hidden = true;
populationCapText.hidden = true;
startingResourcesText.hidden = true;
revealMapText.caption = "Reveal map:";
revealMap.checked = (mapSettings.RevealMap ? true : false);
victoryConditionText.caption = "Victory condition:";
victoryCondition.selected = victoryIdx;
lockTeamsText.caption = "Teams locked:";
lockTeams.checked = (mapSettings.LockTeams ? true : false);
}
else
{
// Client
numPlayersText.hidden = false;
mapSizeText.hidden = false;
revealMapText.hidden = false;
victoryConditionText.hidden = false;
lockTeamsText.hidden = false;
populationCap.hidden = true;
populationCapText.hidden = false;
startingResources.hidden = true;
startingResourcesText.hidden = false;
revealMapText.caption = (mapSettings.RevealMap ? "Yes" : "No");
victoryConditionText.caption = VICTORY_TEXT[victoryIdx];
lockTeamsText.caption = (mapSettings.LockTeams ? "Yes" : "No");
}
break;
case "scenario":
// For scenario just reflect settings for the current map
numPlayersSelection.hidden = true;
@ -976,8 +1034,6 @@ function onGameAttributesChange()
startingResources.hidden = true;
startingResourcesText.hidden = false;
// Update map preview
getGUIObjectByName("mapPreview").sprite = "cropped:(0.78125,0.5859375)session/icons/mappreview/" + getMapPreview(mapName);
numPlayersText.caption = numPlayers;
mapSizeText.caption = "Default";
revealMapText.caption = (mapSettings.RevealMap ? "Yes" : "No");
@ -1046,7 +1102,7 @@ function onGameAttributesChange()
pCivText.caption = g_CivData[civ].Name;
pTeamText.caption = (team !== undefined && team >= 0) ? team+1 : "-";
}
else if (g_GameAttributes.mapType == "random")
else if (g_GameAttributes.mapType != "scenario")
{
pCivText.hidden = true;
pCiv.hidden = false;

View File

@ -46,6 +46,7 @@ function init(data)
var mapName = data.attribs.settings.Name;
switch (data.attribs.mapType)
{
case "skirmish":
case "scenario":
loadingMapName.caption = "Loading \"" + mapName + "\"";
break;

View File

@ -0,0 +1,63 @@
const civList = ["general", "athen", "brit", "cart", "celt", "gaul", "hele", "iber", "mace", "maur", "pers", "rome", "spart"];
function SkirmishReplacer() {}
SkirmishReplacer.prototype.Schema = "";
for each (var civ in civList)
SkirmishReplacer.prototype.Schema +=
"<optional>" +
"<element name='"+civ+"' a:help='Replacement template for this civ. If this element is not present, the \"general\" element (with {civ} replaced by the civ code) is taken. If this element is empty, or not defined, and also no general element, this entity is just deleted.'>" +
"<text/>" +
"</element>" +
"</optional>";
SkirmishReplacer.prototype.Init = function()
{
};
SkirmishReplacer.prototype.OnOwnershipChanged = function(msg)
{
if (msg.to == 0)
warn("Skirmish map elements can only be owned by regular players. Please delete entity "+this.entity+" or change the ownership to a non-gaia player.");
};
/**
* Replace this entity with a civ-specific entity on the first turn
*/
SkirmishReplacer.prototype.OnUpdate = function(msg)
{
var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
var civ = cmpPlayer.GetCiv();
var templateName = "";
if (civ in this.template)
templateName = this.template[civ];
else if ("general" in this.template)
templateName = this.template.general;
if (!templateName || civ == "gaia")
{
Engine.DestroyEntity(this.entity);
return;
}
templateName = templateName.replace(/\{civ\}/g, civ);
var cmpCurPosition = Engine.QueryInterface(this.entity, IID_Position);
var replacement = Engine.AddEntity(templateName);
var cmpReplacementPosition = Engine.QueryInterface(replacement, IID_Position)
var pos = cmpCurPosition.GetPosition2D();
cmpReplacementPosition.JumpTo(pos.x, pos.y);
var rot = cmpCurPosition.GetRotation();
cmpReplacementPosition.SetYRotation(rot.y);
var cmpCurOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
var cmpReplacementOwnership = Engine.QueryInterface(replacement, IID_Ownership);
cmpReplacementOwnership.SetOwner(cmpCurOwnership.GetOwner());
Engine.DestroyEntity(this.entity);
};
Engine.RegisterComponentType(IID_SkirmishReplacer, "SkirmishReplacer", SkirmishReplacer);

View File

@ -0,0 +1 @@
Engine.RegisterInterface("SkirmishReplacer");

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_civic_civil_centre">
<Identity>
<Civ>skirm</Civ>
</Identity>
<SkirmishReplacer>
<general>structures/{civ}_civil_centre</general>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/athenians/civic_centre_new.xml</Actor>
</VisualActor>
</Entity>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_gate">
<Footprint>
<Square width="39.0" depth="8.0"/>
<Height>9.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Obstructions>
<Right width="12" depth="6.5" x="12.5" z="0"/>
<Left width="12" depth="6.5" x="-12.5" z="0"/>
<Door width="13" depth="6.5" x="0" z="0"/>
</Obstructions>
</Obstruction>
<SkirmishReplacer>
<general>structures/{civ}_wall_gate</general>
<spart/>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/hellenes/wall_gate.xml</Actor>
</VisualActor>
<WallPiece>
<Length>38.0</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_long">
<Footprint>
<Square width="37" depth="9"/>
<Height>9.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Static width="36.0" depth="8"/>
</Obstruction>
<SkirmishReplacer>
<general>structures/{civ}_wall_long</general>
<spart/>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/hellenes/wall_long.xml</Actor>
</VisualActor>
<WallPiece>
<Length>36.0</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_medium">
<Footprint>
<Square width="25" depth="9"/>
<Height>9.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Static width="24.0" depth="8"/>
</Obstruction>
<SkirmishReplacer>
<general>structures/{civ}_wall_medium</general>
<spart/>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/hellenes/wall_medium.xml</Actor>
</VisualActor>
<WallPiece>
<Length>24.0</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_short">
<Footprint>
<Square width="13" depth="9"/>
<Height>9.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Static width="12.0" depth="8"/>
</Obstruction>
<SkirmishReplacer>
<general>structures/{civ}_wall_short</general>
<spart/>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/hellenes/wall_short.xml</Actor>
</VisualActor>
<WallPiece>
<Length>12.0</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_tower">
<Footprint replace="">
<Circle radius="6.2"/>
<Height>15.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Static width="10" depth="10"/>
</Obstruction>
<SkirmishReplacer>
<general>structures/{civ}_wall_tower</general>
<spart/>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/hellenes/wall_tower.xml</Actor>
</VisualActor>
<WallPiece>
<Length>10</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_gate">
<Footprint>
<Square width="37.0" depth="9.5"/>
<Height>9.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Obstructions>
<Right width="10" depth="8.5" x="13" z="0"/>
<Left width="10" depth="8.5" x="-13" z="0"/>
<Door width="16.0" depth="8.5" x="0" z="0"/>
</Obstructions>
</Obstruction>
<SkirmishReplacer>
<iber>structures/iber_wall_gate</iber>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/iberians/wall_gate.xml</Actor>
</VisualActor>
<WallPiece>
<Length>36.0</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_long">
<Footprint>
<Square width="37" depth="9"/>
<Height>9.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Static width="36.0" depth="8"/>
</Obstruction>
<SkirmishReplacer>
<iber>structures/iber_wall_long</iber>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/iberians/wall_long.xml</Actor>
</VisualActor>
<WallPiece>
<Length>36.0</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_medium">
<Footprint>
<Square width="25" depth="9"/>
<Height>9.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Static width="24.0" depth="8"/>
</Obstruction>
<SkirmishReplacer>
<iber>structures/iber_wall_medium</iber>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/iberians/wall_medium.xml</Actor>
</VisualActor>
<WallPiece>
<Length>24.0</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_short">
<Footprint>
<Square width="13" depth="9"/>
<Height>9.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Static width="12.0" depth="8"/>
</Obstruction>
<SkirmishReplacer>
<iber>structures/iber_wall_short</iber>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/iberians/wall_short.xml</Actor>
</VisualActor>
<WallPiece>
<Length>12.0</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_defense_wall_tower">
<Footprint replace="">
<Circle radius="6.2"/>
<Height>15.0</Height>
</Footprint>
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Static width="10" depth="10"/>
</Obstruction>
<SkirmishReplacer>
<iber>structures/iber_wall_tower</iber>
</SkirmishReplacer>
<VisualActor>
<Actor>structures/iberians/wall_tower.xml</Actor>
</VisualActor>
<WallPiece>
<Length>10</Length>
</WallPiece>
</Entity>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_cavalry">
<Identity>
<Civ>skirm</Civ>
</Identity>
<Promotion disable=""/>
<SkirmishReplacer>
<general>units/{civ}_cavalry_javelinist_b</general>
<celt>units/celt_cavalry_swordsman_b</celt>
<gaul>units/gaul_cavalry_swordsman_b</gaul>
<hele>units/hele_cavalry_swordsman_b</hele>
<iber>units/iber_cavalry_spearman_b</iber>
<maur>units/maur_support_elephant</maur>
<rome>units/rome_cavalry_spearman_b</rome>
</SkirmishReplacer>
<VisualActor>
<Actor>units/athenians/cavalry_javelinist_b.xml</Actor>
</VisualActor>
</Entity>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_infantry_melee">
<Identity>
<Civ>skirm</Civ>
</Identity>
<Promotion disable=""/>
<SkirmishReplacer>
<general>units/{civ}_infantry_spearman_b</general>
<rome>units/rome_infantry_swordsman_b</rome>
</SkirmishReplacer>
<VisualActor>
<Actor>units/athenians/infantry_spearman_b.xml</Actor>
</VisualActor>
</Entity>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_infantry_ranged">
<Identity>
<Civ>skirm</Civ>
</Identity>
<Promotion disable=""/>
<SkirmishReplacer>
<general>units/{civ}_infantry_javelinist_b</general>
<athen>units/athen_infantry_slinger_b</athen>
<brit>units/brit_infantry_slinger_b</brit>
<cart>units/cart_infantry_archer_b</cart>
<maur>units/maur_infantry_archer_b</maur>
<pers>units/pers_infantry_archer_b</pers>
</SkirmishReplacer>
<VisualActor>
<Actor>units/athenians/infantry_slinger_b.xml</Actor>
</VisualActor>
</Entity>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_support_female_citizen">
<Identity>
<Civ>skirm</Civ>
</Identity>
<SkirmishReplacer>
<general>units/{civ}_support_female_citizen</general>
</SkirmishReplacer>
<VisualActor>
<Actor>units/athenians/female_citizen.xml</Actor>
</VisualActor>
</Entity>

View File

@ -951,6 +951,7 @@ function setup_atlas_projects()
"CustomControls/EditableListCtrl",
"CustomControls/FileHistory",
"CustomControls/HighResTimer",
"CustomControls/MapDialog",
"CustomControls/SnapSplitterWindow",
"CustomControls/VirtualDirTreeCtrl",
"CustomControls/Windows",

View File

@ -64,7 +64,7 @@ CMapReader::CMapReader()
}
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
void CMapReader::LoadMap(const VfsPath& pathname, const CScriptValRooted& settings, CTerrain *pTerrain_,
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_, CPostprocManager* pPostproc_,
CSimulation2 *pSimulation2_, const CSimContext* pSimContext_, int playerID_, bool skipEntities)
@ -83,6 +83,7 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
m_PlayerID = playerID_;
m_SkipEntities = skipEntities;
m_StartingCameraTarget = INVALID_ENTITY;
m_ScriptSettings = settings;
filename_xml = pathname.ChangeExtension(L".xml");
@ -116,8 +117,11 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
if (pPostproc)
pPostproc->SetPostEffect(L"default");
// load map settings script
RegMemFun(this, &CMapReader::LoadScriptSettings, L"CMapReader::LoadScriptSettings", 50);
// load map or script settings script
if (settings.undefined())
RegMemFun(this, &CMapReader::LoadScriptSettings, L"CMapReader::LoadScriptSettings", 50);
else
RegMemFun(this, &CMapReader::LoadRMSettings, L"CMapReader::LoadRMSettings", 50);
// load player settings script (must be done before reading map)
RegMemFun(this, &CMapReader::LoadPlayerSettings, L"CMapReader::LoadPlayerSettings", 50);
@ -138,7 +142,6 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
RegMemFun(this, &CMapReader::DelayLoadFinished, L"CMapReader::DelayLoadFinished", 5);
}
// LoadRandomMap: try to load the map data; reinitialise the scene to new data if successful
void CMapReader::LoadRandomMap(const CStrW& scriptFile, const CScriptValRooted& settings, CTerrain *pTerrain_,
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
@ -1196,6 +1199,7 @@ int CMapReader::DelayLoadFinished()
int CMapReader::LoadRMSettings()
{
// copy random map settings over to sim
ENSURE(pSimulation2);
pSimulation2->SetMapSettings(m_ScriptSettings);
return 0;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2011 Wildfire Games.
/* Copyright (C) 2013 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -53,7 +53,7 @@ public:
~CMapReader();
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void LoadMap(const VfsPath& pathname, CTerrain*, WaterManager*, SkyManager*, CLightEnv*, CGameView*,
void LoadMap(const VfsPath& pathname, const CScriptValRooted& settings, CTerrain*, WaterManager*, SkyManager*, CLightEnv*, CGameView*,
CCinemaManager*, CTriggerManager*, CPostprocManager* pPostproc, CSimulation2*, const CSimContext*,
int playerID, bool skipEntities);

View File

@ -421,7 +421,7 @@ CScriptVal LoadMapSettings(void* cbdata, VfsPath pathname)
CMapSummaryReader reader;
if (reader.LoadMap(pathname.ChangeExtension(L".xml")) != PSRETURN_OK)
if (reader.LoadMap(pathname) != PSRETURN_OK)
return CScriptVal();
return reader.GetMapSettings(guiManager->GetScriptInterface()).get();

View File

@ -142,15 +142,7 @@ void CGame::RegisterInit(const CScriptValRooted& attribs, const std::string& sav
if (m_GameView)
m_GameView->RegisterInit();
if (mapType == "scenario")
{
// Load scenario attributes
std::wstring mapFile;
m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "map", mapFile);
m_World->RegisterInit(mapFile, m_PlayerID);
}
else if (mapType == "random")
if (mapType == "random")
{
// Load random map attributes
std::wstring scriptFile;
@ -161,6 +153,16 @@ void CGame::RegisterInit(const CScriptValRooted& attribs, const std::string& sav
m_World->RegisterInitRMS(scriptFile, settings, m_PlayerID);
}
else
{
std::wstring mapFile;
m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "map", mapFile);
CScriptValRooted settings;
if (mapType == "skirmish")
m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "settings", settings);
m_World->RegisterInit(mapFile, settings, m_PlayerID);
}
if (m_IsSavedGame)
RegMemFun(this, &CGame::LoadInitialState, L"Loading game", 1000);

View File

@ -1081,6 +1081,7 @@ bool Autostart(const CmdLineArgs& args)
* -autostart-ip=127.0.0.1 -- multiplayer connect to 127.0.0.1
* -autostart-random=104 -- random map, optional seed value = 104 (default is 0, random is -1)
* -autostart-size=192 -- random map size in tiles = 192 (default is 192)
* -autostart-civ=1:hele -- set player #1 civ to "hele"
*
* Examples:
* -autostart=Acropolis -autostart-host -autostart-players=2 -- Host game on Acropolis map, 2 players
@ -1131,8 +1132,7 @@ bool Autostart(const CmdLineArgs& args)
}
// Random map definition will be loaded from JSON file, so we need to parse it
std::wstring mapPath = L"maps/random/";
std::wstring scriptPath = mapPath + autoStartName.FromUTF8() + L".json";
std::wstring scriptPath = L"maps/random/" + autoStartName.FromUTF8() + L".json";
CScriptValRooted scriptData = scriptInterface.ReadJSONFile(scriptPath);
if (!scriptData.undefined() && scriptInterface.GetProperty(scriptData.get(), "settings", settings))
{
@ -1157,7 +1157,6 @@ bool Autostart(const CmdLineArgs& args)
}
scriptInterface.SetProperty(attrs.get(), "map", std::string(autoStartName));
scriptInterface.SetProperty(attrs.get(), "mapPath", mapPath);
scriptInterface.SetProperty(attrs.get(), "mapType", std::string("random"));
scriptInterface.SetProperty(settings.get(), "Seed", seed); // Random seed
scriptInterface.SetProperty(settings.get(), "Size", mapSize); // Random map size (in patches)
@ -1184,7 +1183,9 @@ bool Autostart(const CmdLineArgs& args)
}
else
{
scriptInterface.SetProperty(attrs.get(), "map", std::string(autoStartName));
// TODO: support akirmish maps
std::string mapFile = "maps/scenarios/" + autoStartName;
scriptInterface.SetProperty(attrs.get(), "map", mapFile);
scriptInterface.SetProperty(attrs.get(), "mapType", std::string("scenario"));
}

View File

@ -65,19 +65,19 @@ CWorld::CWorld(CGame *pGame):
/**
* Initializes the game world with the attributes provided.
**/
void CWorld::RegisterInit(const CStrW& mapFile, int playerID)
void CWorld::RegisterInit(const CStrW& mapFile, const CScriptValRooted& settings, int playerID)
{
// Load the map, if one was specified
if (mapFile.length())
{
VfsPath mapfilename(VfsPath("maps/scenarios") / (mapFile + L".pmp"));
VfsPath mapfilename = VfsPath(mapFile).ChangeExtension(L".pmp");
CMapReader* reader = 0;
try
{
reader = new CMapReader;
CTriggerManager* pTriggerManager = NULL;
reader->LoadMap(mapfilename, m_Terrain,
reader->LoadMap(mapfilename, settings, m_Terrain,
CRenderer::IsInitialised() ? g_Renderer.GetWaterManager() : NULL,
CRenderer::IsInitialised() ? g_Renderer.GetSkyManager() : NULL,
&g_LightEnv, m_pGame->GetView(),
@ -89,8 +89,8 @@ void CWorld::RegisterInit(const CStrW& mapFile, int playerID)
catch (PSERROR_File& err)
{
delete reader;
LOGERROR(L"Failed to load scenario %ls: %hs", mapfilename.string().c_str(), err.what());
throw PSERROR_Game_World_MapLoadFailed("Failed to load scenario.\nCheck application log for details.");
LOGERROR(L"Failed to load map %ls: %hs", mapfilename.string().c_str(), err.what());
throw PSERROR_Game_World_MapLoadFailed("Failed to load map.\nCheck application log for details.");
}
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2011 Wildfire Games.
/* Copyright (C) 2013 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -73,7 +73,7 @@ public:
/*
Initialize the World - load the map and all objects
*/
void RegisterInit(const CStrW& mapFile, int playerID);
void RegisterInit(const CStrW& mapFile, const CScriptValRooted& settings, int playerID);
/*
Initialize the World - generate and load the random map

View File

@ -387,22 +387,20 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
// TODO: this duplicates CWorld::RegisterInit and could probably be cleaned up a bit
std::string mapType;
m_ComponentManager.GetScriptInterface().GetProperty(m_InitAttributes.get(), "mapType", mapType);
if (mapType == "scenario")
{
// Load scenario attributes
std::wstring mapFile;
m_ComponentManager.GetScriptInterface().GetProperty(m_InitAttributes.get(), "map", mapFile);
VfsPath mapfilename(VfsPath("maps/scenarios") / (mapFile + L".pmp"));
mapReader->LoadMap(mapfilename, &secondaryTerrain, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, &secondaryContext, INVALID_PLAYER, true); // throws exception on failure
}
else
if (mapType == "random")
{
// TODO: support random map scripts
debug_warn(L"Serialization test mode only supports scenarios");
}
else
{
std::wstring mapFile;
m_ComponentManager.GetScriptInterface().GetProperty(m_InitAttributes.get(), "map", mapFile);
VfsPath mapfilename = VfsPath(mapFile).ChangeExtension(L".pmp");
mapReader->LoadMap(mapfilename, CScriptValRooted(), &secondaryTerrain, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, &secondaryContext, INVALID_PLAYER, true); // throws exception on failure
}
LDR_EndRegistering();
ENSURE(LDR_NonprogressiveLoad() == INFO::OK);

View File

@ -68,7 +68,7 @@ public:
CMapReader* mapReader = new CMapReader(); // it'll call "delete this" itself
LDR_BeginRegistering();
mapReader->LoadMap(L"maps/scenarios/Median Oasis 01.pmp", &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
mapReader->LoadMap(L"maps/scenarios/Median Oasis 01.pmp", CScriptValRooted(), &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&sim2, &sim2.GetSimContext(), -1, false);
LDR_EndRegistering();
TS_ASSERT_OK(LDR_NonprogressiveLoad());

View File

@ -25,6 +25,7 @@
#include "graphics/MapReader.h"
#include "graphics/Terrain.h"
#include "graphics/TerrainTextureManager.h"
#include "lib/timer.h"
#include "ps/CLogger.h"
#include "ps/Filesystem.h"
@ -635,6 +636,12 @@ public:
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"public", VFS_MOUNT_MUST_EXIST));
TS_ASSERT_OK(g_VFS->Mount(L"cache/", DataDir()/"cache"));
// Need some stuff for terrain movement costs:
// (TODO: this ought to be independent of any graphics code)
tex_codec_register_all();
new CTerrainTextureManager;
g_TexMan.LoadTerrainTextures();
CTerrain terrain;
CSimulation2 sim2(NULL, &terrain);
@ -644,7 +651,7 @@ public:
CMapReader* mapReader = new CMapReader(); // it'll call "delete this" itself
LDR_BeginRegistering();
mapReader->LoadMap(L"maps/scenarios/Latium.pmp", &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
mapReader->LoadMap(L"maps/scenarios/Acropolis 01.pmp", CScriptValRooted(), &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&sim2, &sim2.GetSimContext(), -1, false);
LDR_EndRegistering();
TS_ASSERT_OK(LDR_NonprogressiveLoad());
@ -677,6 +684,8 @@ public:
debug_printf(L"# time = %f (%f/%d)\n", t/reps, t, (int)reps);
// Shut down the world
delete &g_TexMan;
tex_codec_unregister_all();
g_VFS.reset();
CXeromyces::Terminate();
}

View File

@ -0,0 +1,214 @@
/* Copyright (C) 2013 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "MapDialog.h"
#include "GameInterface/MessagePasser.h"
#include "GameInterface/Messages.h"
enum {
ID_MapDialogFilename = 1,
ID_MapDialogNotebook,
ID_ScenarioPage,
ID_SkirmishPage
};
static const wxString scenarioPath(L"maps/scenarios/");
static const wxString skirmishPath(L"maps/skirmishes/");
MapDialog::MapDialog(wxWindow* parent, MapDialogType type)
: wxDialog(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(600,400), wxCAPTION|wxRESIZE_BORDER|wxCLOSE_BOX|wxSYSTEM_MENU), m_Type(type)
{
Freeze();
SetIcon(wxIcon(_T("ICON_ScenarioEditor"))); // load from atlas.rc
if (m_Type == MAPDIALOG_OPEN)
SetTitle(_("Choose map to open"));
else // MAPDIALOG_SAVE
SetTitle(_("Choose map to save"));
AtlasMessage::qGetMapList qry;
qry.Post();
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
wxNotebook* notebook = new wxNotebook(this, ID_MapDialogNotebook);
{
wxPanel* page = new wxPanel(notebook, ID_ScenarioPage);
wxSizer* pageSizer = new wxBoxSizer(wxVERTICAL);
// TODO: Should display something nicer than raw VFS paths
wxListBox* listBox = new wxListBox(page, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE|wxLB_HSCROLL);
const std::vector<std::wstring>& scenarioFilenames = *qry.scenarioFilenames;
for (size_t i = 0; i < scenarioFilenames.size(); ++i)
{
wxString name = scenarioFilenames[i].substr(scenarioPath.Length());
listBox->Append(name, new wxStringClientData(scenarioFilenames[i]));
}
pageSizer->Add(listBox, wxSizerFlags().Proportion(1).Expand().Align(wxBOTTOM));
page->SetSizer(pageSizer);
notebook->AddPage(page, _("Scenarios"));
}
{
wxPanel* page = new wxPanel(notebook, ID_SkirmishPage);
wxSizer* pageSizer = new wxBoxSizer(wxVERTICAL);
// TODO: Should display something nicer than raw VFS paths
wxListBox* listBox = new wxListBox(page, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE|wxLB_HSCROLL);
const std::vector<std::wstring>& skirmishFilenames = *qry.skirmishFilenames;
for (size_t i = 0; i < skirmishFilenames.size(); ++i)
{
wxString name = skirmishFilenames[i].substr(skirmishPath.Length());
listBox->Append(name, new wxStringClientData(skirmishFilenames[i]));
}
pageSizer->Add(listBox, wxSizerFlags().Proportion(1).Expand());
page->SetSizer(pageSizer);
notebook->AddPage(page, _("Skirmishes"));
}
notebook->SetSelection(0);
sizer->Add(notebook, wxSizerFlags().Proportion(1).Expand());
sizer->AddSpacer(5);
wxSizer* filenameSizer = new wxBoxSizer(wxHORIZONTAL);
filenameSizer->AddSpacer(10);
filenameSizer->Add(new wxStaticText(this, wxID_ANY, _("Map name: ")), wxSizerFlags().Align(wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL));
wxTextCtrl* filename = new wxTextCtrl(this, ID_MapDialogFilename, wxEmptyString);
if (m_Type == MAPDIALOG_OPEN)
filename->Disable();
filenameSizer->Add(filename, wxSizerFlags().Proportion(1).Expand());
sizer->Add(filenameSizer, wxSizerFlags().Expand());
sizer->AddSpacer(20);
wxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
if (m_Type == MAPDIALOG_OPEN)
buttonSizer->Add(new wxButton(this, wxID_OPEN, _("Open")));
else // MAPDIALOG_SAVE
buttonSizer->Add(new wxButton(this, wxID_SAVE, _("Save")));
buttonSizer->AddSpacer(5);
buttonSizer->Add(new wxButton(this, wxID_CANCEL, _("Cancel")));
sizer->Add(buttonSizer, wxSizerFlags().Align(wxALIGN_RIGHT).Border(wxRIGHT|wxBOTTOM, 10));
SetSizer(sizer);
Layout();
Thaw();
}
wxString MapDialog::GetFilename() const
{
wxFileName filename(m_Filename, wxPATH_UNIX);
filename.SetExt(L"xml");
if (m_SelectedPage == 0)
return scenarioPath + filename.GetFullPath(wxPATH_UNIX);
else if (m_SelectedPage == 1)
return skirmishPath + filename.GetFullPath(wxPATH_UNIX);
else
return wxEmptyString;
}
void MapDialog::OnListBox(wxCommandEvent& evt)
{
if (evt.GetInt() < 0)
m_Filename = wxEmptyString;
else
m_Filename = evt.GetString();
wxDynamicCast(FindWindow(ID_MapDialogFilename), wxTextCtrl)->ChangeValue(m_Filename);
if (evt.GetEventType() == wxEVT_COMMAND_LISTBOX_DOUBLECLICKED)
{
if (m_Type == MAPDIALOG_OPEN)
OpenFile();
else
SaveFile();
}
}
void MapDialog::OnCancel(wxCommandEvent& WXUNUSED(evt))
{
EndModal(wxID_CANCEL);
}
void MapDialog::OnOpen(wxCommandEvent& WXUNUSED(evt))
{
OpenFile();
}
void MapDialog::OnSave(wxCommandEvent& WXUNUSED(evt))
{
SaveFile();
}
void MapDialog::OnFilename(wxCommandEvent& evt)
{
m_Filename = evt.GetString();
}
void MapDialog::OnNotebookChanged(wxNotebookEvent& evt)
{
m_SelectedPage = evt.GetSelection();
}
void MapDialog::OpenFile()
{
wxString filename = GetFilename();
if (filename.empty())
return;
AtlasMessage::qVFSFileExists qry(filename.wc_str());
qry.Post();
if (!qry.exists)
return;
EndModal(wxID_OK);
}
void MapDialog::SaveFile()
{
wxString filename = GetFilename();
if (filename.empty())
return;
// TODO: this test would work better outside the VFS
AtlasMessage::qVFSFileExists qry(filename.wc_str());
qry.Post();
if (qry.exists)
{
if (wxMessageBox(_("WARNING: '") + filename + _("' already exists, it may be overwritten. Continue?"), _("Overwrite map confirmation"), wxICON_EXCLAMATION | wxYES_NO) != wxYES)
return;
}
EndModal(wxID_OK);
}
BEGIN_EVENT_TABLE(MapDialog, wxDialog)
EVT_BUTTON (wxID_CANCEL, MapDialog::OnCancel)
EVT_BUTTON (wxID_OPEN, MapDialog::OnOpen)
EVT_BUTTON (wxID_SAVE, MapDialog::OnSave)
EVT_LISTBOX (wxID_ANY, MapDialog::OnListBox)
EVT_LISTBOX_DCLICK (wxID_ANY, MapDialog::OnListBox)
EVT_TEXT (ID_MapDialogFilename, MapDialog::OnFilename)
EVT_NOTEBOOK_PAGE_CHANGED (ID_MapDialogNotebook, MapDialog::OnNotebookChanged)
END_EVENT_TABLE()

View File

@ -0,0 +1,55 @@
/* Copyright (C) 2013 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_MAPDIALOG
#define INCLUDED_MAPDIALOG
#include <wx/dialog.h>
enum MapDialogType { MAPDIALOG_OPEN, MAPDIALOG_SAVE };
class MapDialog : public wxDialog
{
public:
MapDialog(wxWindow* parent, MapDialogType type);
/**
* Returns VFS path of selected map with .xml extension, else empty string
*/
wxString GetFilename() const;
private:
void OnCancel(wxCommandEvent& evt);
void OnOpen(wxCommandEvent& evt);
void OnSave(wxCommandEvent& evt);
void OnListBox(wxCommandEvent& evt);
void OnFilename(wxCommandEvent& evt);
void OnNotebookChanged(wxNotebookEvent& evt);
void OpenFile();
void SaveFile();
wxArrayString m_MapFilenames;
wxString m_Filename;
MapDialogType m_Type;
int m_SelectedPage;
DECLARE_EVENT_TABLE();
};
#endif // INCLUDED_MAPDIALOG

View File

@ -35,6 +35,7 @@
#include "CustomControls/Buttons/ToolButton.h"
#include "CustomControls/Canvas/Canvas.h"
#include "CustomControls/HighResTimer/HighResTimer.h"
#include "CustomControls/MapDialog/MapDialog.h"
#include "GameInterface/MessagePasser.h"
#include "GameInterface/Messages.h"
@ -521,7 +522,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
// Start with a blank map (so that the editor can assume there's always
// a valid map loaded)
POST_MESSAGE(LoadMap, (_T("_default")));
POST_MESSAGE(LoadMap, (_T("maps/scenarios/_default.xml")));
POST_MESSAGE(SimPlay, (0.f, false));
// Select the initial sidebar (after the map has loaded)
@ -626,7 +627,7 @@ void ScenarioEditor::OnRedo(wxCommandEvent&)
void ScenarioEditor::OnNew(wxCommandEvent& WXUNUSED(event))
{
if (wxMessageBox(_("Discard current map and start blank new map?"), _("New map"), wxOK|wxCANCEL|wxICON_QUESTION, this) == wxOK)
OpenFile(_T("_default"), _T(""));
OpenFile(_T(""), _T("maps/scenarios/_default.xml"));
}
bool ScenarioEditor::OpenFile(const wxString& name, const wxString& filename)
@ -634,48 +635,20 @@ bool ScenarioEditor::OpenFile(const wxString& name, const wxString& filename)
wxBusyInfo busy(_("Loading ") + name);
wxBusyCursor busyc;
wxString mapPath(_T("maps/scenarios/"));
wxFileName fullFilename(filename);
// For compatibility it's still possible to load xml maps but in that case,
// we want a blank filename so that we're forced to Save As
if (filename.IsEmpty() || fullFilename.GetExt().IsSameAs(_T("xml"), false))
{
fullFilename = _T("");
}
else
{ // force extension to pmp
fullFilename.SetExt(_T("pmp"));
// check if pmp exists
qVFSFileExists qry(std::wstring((mapPath + fullFilename.GetFullName()).wc_str()));
qry.Post();
if (!qry.exists)
{
return false;
}
}
// Every map requires an xml file, so check that it exists
wxFileName xmlName(name);
xmlName.SetExt(_T("xml"));
qVFSFileExists qry(std::wstring((mapPath + xmlName.GetFullName()).wc_str()));
AtlasMessage::qVFSFileExists qry(filename.wc_str());
qry.Post();
if (!qry.exists)
{
return false;
}
// Deactivate tools, so they don't carry forwards into the new CWorld
// and crash.
m_ToolManager.SetCurrentTool(_T(""));
// TODO: clear the undo buffer, etc
// TODO: Work when the map is not in .../maps/scenarios/
std::wstring map(name.wc_str());
std::wstring map(filename.wc_str());
POST_MESSAGE(LoadMap, (map));
SetOpenFilename(fullFilename.GetFullName());
SetOpenFilename(name);
{ // Wait for it to load, while the wxBusyInfo is telling the user that we're doing that
qPing qry;
@ -692,27 +665,12 @@ bool ScenarioEditor::OpenFile(const wxString& name, const wxString& filename)
void ScenarioEditor::OnOpen(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog dlg (NULL, wxFileSelectorPromptStr,
Datafile::GetDataDirectory() + _T("/mods/public/maps/scenarios"), m_OpenFilename,
_T("PMP files (*.pmp)|*.pmp|All files (*.*)|*.*"),
wxFD_OPEN);
// Set default filter
dlg.SetFilterIndex(0);
wxString cwd = wxFileName::GetCwd();
MapDialog dlg (NULL, MAPDIALOG_OPEN);
if (dlg.ShowModal() == wxID_OK)
{
// TODO: Handle maps in subdirectories of maps/scenarios
wxFileName filename(dlg.GetFilename());
if (!OpenFile(filename.GetName(), filename.GetFullName()))
{
wxLogError(_("Map '%ls' does not exist"), filename.GetName().c_str());
}
// paranoia - MSDN says OFN_NOCHANGEDIR (used when we don't give wxCHANGE_DIR)
// "is ineffective for GetOpenFileName", but it seems to work anyway
wxCHECK_RET(cwd == wxFileName::GetCwd(), _T("cwd changed"));
wxString filename = dlg.GetFilename();
if (!OpenFile(filename, filename))
wxLogError(_("Map '%ls' does not exist"), filename.c_str());
}
// TODO: Make this a non-undoable command
@ -727,12 +685,10 @@ void ScenarioEditor::OnImportHeightmap(wxCommandEvent& WXUNUSED(event))
// Set default filter
dlg.SetFilterIndex(0);
wxString cwd = wxFileName::GetCwd();
if (dlg.ShowModal() != wxID_OK)
return;
OpenFile(_T("_default"), _T(""));
OpenFile(_T(""), _T("maps/scenarios/_default.xml"));
std::wstring image(dlg.GetPath().wc_str());
POST_MESSAGE(ImportHeightmap, (image));
@ -744,8 +700,16 @@ void ScenarioEditor::OnMRUFile(wxCommandEvent& event)
{
wxString filename(m_FileHistory.GetHistoryFile(event.GetId() - wxID_FILE1));
// Handle old MRU filenames
if (filename.Mid(0, 5) != _T("maps/"))
{
filename = L"maps/scenarios/" + filename;
m_FileHistory.RemoveFileFromHistory(event.GetId() - wxID_FILE1);
}
if (!OpenFile(filename, filename))
{ // Missing or invalid - warn and remove from MRU
{
// Missing or invalid - warn and remove from MRU
wxLogError(_("Map '%ls' does not exist"), filename.c_str());
m_FileHistory.RemoveFileFromHistory(event.GetId() - wxID_FILE1);
}
@ -767,7 +731,6 @@ void ScenarioEditor::OnSave(wxCommandEvent& event)
// the preview units.)
m_ToolManager.SetCurrentTool(_T(""));
// TODO: Handle maps in subdirectories of maps/scenarios
std::wstring map(m_OpenFilename.wc_str());
POST_MESSAGE(SaveMap, (map));
@ -779,35 +742,19 @@ void ScenarioEditor::OnSave(wxCommandEvent& event)
void ScenarioEditor::OnSaveAs(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog dlg (NULL, wxFileSelectorPromptStr,
Datafile::GetDataDirectory() + _T("/mods/public/maps/scenarios"), m_OpenFilename,
_T("PMP files (*.pmp)|*.pmp|All files (*.*)|*.*"),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
// Set default filter
dlg.SetFilterIndex(0);
MapDialog dlg(NULL, MAPDIALOG_SAVE);
if (dlg.ShowModal() == wxID_OK)
{
// On wxMSW the extension is automatically set to pmp if that filter is selected
// but not on wxGTK or wxOSX. Set it explicitly since it's the only possible format.
wxFileName filename(dlg.GetFilename());
filename.SetExt(_T("pmp"));
if (!filename.IsOk())
{ // Shouldn't happen
wxLogError(_("Invalid filename '%ls'"), filename.GetFullName().c_str());
return;
}
wxBusyInfo busy(_("Saving ") + filename.GetFullName());
wxString filename(dlg.GetFilename());
wxBusyInfo busy(_("Saving ") + filename);
wxBusyCursor busyc;
m_ToolManager.SetCurrentTool(_T(""));
// TODO: Handle maps in subdirectories of maps/scenarios
std::wstring map(filename.GetFullName().wc_str());
std::wstring map(filename.wc_str());
POST_MESSAGE(SaveMap, (map));
SetOpenFilename(filename.GetFullName());
SetOpenFilename(filename);
// Wait for it to finish saving
qPing qry;

View File

@ -34,9 +34,10 @@ enum
ID_MapDescription,
ID_MapReveal,
ID_MapType,
ID_MapPreview,
ID_MapTeams,
ID_MapKW_Demo,
ID_MapKW_Hidden,
ID_MapKW_Naval,
ID_RandomScript,
ID_RandomSize,
ID_RandomSeed,
@ -109,6 +110,7 @@ private:
BEGIN_EVENT_TABLE(MapSettingsControl, wxPanel)
EVT_TEXT(ID_MapName, MapSettingsControl::OnEdit)
EVT_TEXT(ID_MapDescription, MapSettingsControl::OnEdit)
EVT_TEXT(ID_MapPreview, MapSettingsControl::OnEdit)
EVT_CHECKBOX(wxID_ANY, MapSettingsControl::OnEdit)
EVT_CHOICE(wxID_ANY, MapSettingsControl::OnEdit)
END_EVENT_TABLE();
@ -147,6 +149,10 @@ void MapSettingsControl::CreateWidgets()
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 5, 5);
gridSizer->AddGrowableCol(1);
// TODO: have preview selector tool?
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Preview")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(new wxTextCtrl(this, ID_MapPreview, wxEmptyString),
_("Texture used for map preview")), wxSizerFlags().Expand());
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Reveal map")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(new wxCheckBox(this, ID_MapReveal, wxEmptyString),
_("If checked, players won't need to explore")));
@ -161,12 +167,12 @@ void MapSettingsControl::CreateWidgets()
sizer->AddSpacer(5);
wxStaticBoxSizer* keywordsSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Keywords"));
wxFlexGridSizer* kwGridSizer = new wxFlexGridSizer(2, 5, 5);
wxFlexGridSizer* kwGridSizer = new wxFlexGridSizer(4, 5, 5);
kwGridSizer->Add(new wxStaticText(this, wxID_ANY, _("Demo")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
kwGridSizer->Add(Tooltipped(new wxCheckBox(this, ID_MapKW_Demo, wxEmptyString),
_("If checked, map will only be visible using filters in game setup")));
kwGridSizer->Add(new wxStaticText(this, wxID_ANY, _("Hidden")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
kwGridSizer->Add(Tooltipped(new wxCheckBox(this, ID_MapKW_Hidden, wxEmptyString),
kwGridSizer->Add(new wxStaticText(this, wxID_ANY, _("Naval")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
kwGridSizer->Add(Tooltipped(new wxCheckBox(this, ID_MapKW_Naval, wxEmptyString),
_("If checked, map will only be visible using filters in game setup")));
keywordsSizer->Add(kwGridSizer);
sizer->Add(keywordsSizer, wxSizerFlags().Expand());
@ -188,6 +194,9 @@ void MapSettingsControl::ReadFromEngine()
// map description
wxDynamicCast(FindWindow(ID_MapDescription), wxTextCtrl)->ChangeValue(wxString(m_MapSettings["Description"]));
// map preview
wxDynamicCast(FindWindow(ID_MapPreview), wxTextCtrl)->ChangeValue(wxString(m_MapSettings["Preview"]));
// reveal map
wxDynamicCast(FindWindow(ID_MapReveal), wxCheckBox)->SetValue(wxString(m_MapSettings["RevealMap"]) == L"true");
@ -207,7 +216,7 @@ void MapSettingsControl::ReadFromEngine()
m_MapSettingsKeywords.insert(std::wstring(keyword));
wxDynamicCast(FindWindow(ID_MapKW_Demo), wxCheckBox)->SetValue(m_MapSettingsKeywords.count(L"demo") != 0);
wxDynamicCast(FindWindow(ID_MapKW_Hidden), wxCheckBox)->SetValue(m_MapSettingsKeywords.count(L"hidden") != 0);
wxDynamicCast(FindWindow(ID_MapKW_Naval), wxCheckBox)->SetValue(m_MapSettingsKeywords.count(L"naval") != 0);
}
}
@ -227,6 +236,9 @@ AtObj MapSettingsControl::UpdateSettingsObject()
// map description
m_MapSettings.set("Description", wxDynamicCast(FindWindow(ID_MapDescription), wxTextCtrl)->GetValue());
// map preview
m_MapSettings.set("Preview", wxDynamicCast(FindWindow(ID_MapPreview), wxTextCtrl)->GetValue());
// reveal map
m_MapSettings.setBool("RevealMap", wxDynamicCast(FindWindow(ID_MapReveal), wxCheckBox)->GetValue());
@ -240,10 +252,10 @@ AtObj MapSettingsControl::UpdateSettingsObject()
else
m_MapSettingsKeywords.erase(L"demo");
if (wxDynamicCast(FindWindow(ID_MapKW_Hidden), wxCheckBox)->GetValue())
m_MapSettingsKeywords.insert(L"hidden");
if (wxDynamicCast(FindWindow(ID_MapKW_Naval), wxCheckBox)->GetValue())
m_MapSettingsKeywords.insert(L"naval");
else
m_MapSettingsKeywords.erase(L"hidden");
m_MapSettingsKeywords.erase(L"naval");
AtObj keywords;
keywords.set("@array", L"");

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2011 Wildfire Games.
/* Copyright (C) 2013 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -35,8 +35,18 @@ enum
ID_PlayerStone,
ID_PlayerPop,
ID_PlayerColour,
ID_PlayerHuman,
ID_PlayerAI,
ID_DefaultName,
ID_DefaultCiv,
ID_DefaultColour,
ID_DefaultAI,
ID_DefaultFood,
ID_DefaultWood,
ID_DefaultMetal,
ID_DefaultStone,
ID_DefaultPop,
ID_DefaultTeam,
ID_CameraSet,
ID_CameraView,
ID_CameraClear
@ -54,6 +64,39 @@ static wxWindow* Tooltipped(wxWindow* window, const wxString& tip)
//////////////////////////////////////////////////////////////////////////
class DefaultCheckbox : public wxCheckBox
{
public:
DefaultCheckbox(wxWindow* parent, wxWindowID id, wxWindow* control, bool initialValue = false)
: wxCheckBox(parent, id, wxEmptyString), m_Control(control)
{
SetValue(initialValue);
}
virtual void SetValue(bool value)
{
m_Control->Enable(value);
wxCheckBox::SetValue(value);
}
void OnChecked(wxCommandEvent& evt)
{
m_Control->Enable(evt.IsChecked());
evt.Skip();
}
private:
wxWindow* m_Control;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(DefaultCheckbox, wxCheckBox)
EVT_CHECKBOX(wxID_ANY, DefaultCheckbox::OnChecked)
END_EVENT_TABLE();
class PlayerNotebookPage : public wxPanel
{
@ -73,25 +116,33 @@ public:
/////////////////////////////////////////////////////////////////////////
// Player Info
wxStaticBoxSizer* playerInfoSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Player info"));
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 5, 5);
gridSizer->AddGrowableCol(1);
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Name")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(3, 5, 5);
gridSizer->AddGrowableCol(2);
wxTextCtrl* nameCtrl = new wxTextCtrl(this, wxID_ANY);
gridSizer->Add(new DefaultCheckbox(this, ID_DefaultName, nameCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Name")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(nameCtrl, wxSizerFlags(1).Expand().Align(wxALIGN_RIGHT));
m_Controls.name = nameCtrl;
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Civilisation")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxChoice* civChoice = new wxChoice(this, wxID_ANY);
gridSizer->Add(new DefaultCheckbox(this, ID_DefaultCiv, civChoice), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Civilisation")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(civChoice, wxSizerFlags(1).Expand().Align(wxALIGN_RIGHT));
m_Controls.civ = civChoice;
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Colour")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxButton* colourButton = new wxButton(this, ID_PlayerColour);
gridSizer->Add(new DefaultCheckbox(this, ID_DefaultColour, colourButton), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Colour")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(colourButton,
_("Set player colour")), wxSizerFlags(1).Expand().Align(wxALIGN_RIGHT));
m_Controls.colour = colourButton;
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Default AI")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxChoice* aiChoice = new wxChoice(this, wxID_ANY);
gridSizer->Add(new DefaultCheckbox(this, ID_DefaultAI, aiChoice), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("AI")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(aiChoice,
_("Select default AI")), wxSizerFlags(1).Expand().Align(wxALIGN_RIGHT));
_("Select AI")), wxSizerFlags(1).Expand().Align(wxALIGN_RIGHT));
m_Controls.ai = aiChoice;
playerInfoSizer->Add(gridSizer, wxSizerFlags(1).Expand());
@ -102,30 +153,40 @@ public:
/////////////////////////////////////////////////////////////////////////
// Resources
wxStaticBoxSizer* resourceSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Resources"));
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 5, 5);
gridSizer->AddGrowableCol(1);
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Food")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(3, 5, 5);
gridSizer->AddGrowableCol(2);
wxSpinCtrl* foodCtrl = new wxSpinCtrl(this, ID_PlayerFood, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(this, ID_DefaultFood, foodCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Food")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(foodCtrl,
_("Initial value of food resource")), wxSizerFlags().Expand());
m_Controls.food = foodCtrl;
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Wood")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxSpinCtrl* woodCtrl = new wxSpinCtrl(this, ID_PlayerWood, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(this, ID_DefaultWood, woodCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Wood")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(woodCtrl,
_("Initial value of wood resource")), wxSizerFlags().Expand());
m_Controls.wood = woodCtrl;
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Metal")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxSpinCtrl* metalCtrl = new wxSpinCtrl(this, ID_PlayerMetal, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(this, ID_DefaultMetal, metalCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Metal")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(metalCtrl,
_("Initial value of metal resource")), wxSizerFlags().Expand());
m_Controls.metal = metalCtrl;
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Stone")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxSpinCtrl* stoneCtrl = new wxSpinCtrl(this, ID_PlayerStone, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(this, ID_DefaultStone, stoneCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Stone")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(stoneCtrl,
_("Initial value of stone resource")), wxSizerFlags().Expand());
m_Controls.stone = stoneCtrl;
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Pop limit")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxSpinCtrl* popCtrl = new wxSpinCtrl(this, ID_PlayerPop, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(this, ID_DefaultPop, popCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Pop limit")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(popCtrl,
_("Population limit for this player")), wxSizerFlags().Expand());
m_Controls.pop = popCtrl;
@ -138,8 +199,11 @@ public:
// Diplomacy
wxStaticBoxSizer* diplomacySizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Diplomacy"));
wxBoxSizer* boxSizer = new wxBoxSizer(wxHORIZONTAL);
boxSizer->Add(new wxStaticText(this, wxID_ANY, _("Team")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxChoice* teamCtrl = new wxChoice(this, wxID_ANY);
boxSizer->Add(new DefaultCheckbox(this, ID_DefaultTeam, teamCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
boxSizer->AddSpacer(5);
boxSizer->Add(new wxStaticText(this, wxID_ANY, _("Team")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
boxSizer->AddSpacer(5);
teamCtrl->Append(_("None"));
teamCtrl->Append(_T("1"));
teamCtrl->Append(_T("2"));
@ -479,6 +543,7 @@ BEGIN_EVENT_TABLE(PlayerSettingsControl, wxPanel)
EVT_BUTTON(ID_PlayerColour, PlayerSettingsControl::OnPlayerColour)
EVT_BUTTON(ID_CameraSet, PlayerSettingsControl::OnEdit)
EVT_BUTTON(ID_CameraClear, PlayerSettingsControl::OnEdit)
EVT_CHECKBOX(wxID_ANY, PlayerSettingsControl::OnEdit)
EVT_CHOICE(wxID_ANY, PlayerSettingsControl::OnEdit)
EVT_TEXT(ID_NumPlayers, PlayerSettingsControl::OnNumPlayersText)
EVT_TEXT(wxID_ANY, PlayerSettingsControl::OnEdit)
@ -596,7 +661,8 @@ void PlayerSettingsControl::ReadFromEngine()
m_MapSettings = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qry.settings);
}
else
{ // Use blank object, it will be created next
{
// Use blank object, it will be created next
m_MapSettings = AtObj();
}
@ -607,9 +673,7 @@ void PlayerSettingsControl::ReadFromEngine()
m_NumPlayers = MAX_NUM_PLAYERS;
}
else
{
m_NumPlayers = player.count();
}
wxASSERT(m_NumPlayers <= MAX_NUM_PLAYERS && m_NumPlayers != 0);
@ -628,21 +692,24 @@ void PlayerSettingsControl::ReadFromEngine()
for (size_t i = 0; i < MAX_NUM_PLAYERS; ++i)
{
PlayerPageControls controls = m_PlayerControls[i];
const PlayerPageControls& controls = m_PlayerControls[i];
// name
wxString name(_("Unknown"));
if (player["Name"].defined())
bool defined = player["Name"].defined();
if (defined)
name = wxString(player["Name"]);
else if (playerDefs["Name"].defined())
name = wxString(playerDefs["Name"]);
controls.name->SetValue(name);
wxDynamicCast(FindWindowById(ID_DefaultName, controls.page), DefaultCheckbox)->SetValue(defined);
// civ
wxChoice* choice = controls.civ;
wxString civCode;
if (player["Civ"].defined())
defined = player["Civ"].defined();
if (defined)
civCode = wxString(player["Civ"]);
else
civCode = wxString(playerDefs["Civ"]);
@ -656,31 +723,30 @@ void PlayerSettingsControl::ReadFromEngine()
break;
}
}
wxDynamicCast(FindWindowById(ID_DefaultCiv, controls.page), DefaultCheckbox)->SetValue(defined);
// colour
wxColour colour;
AtObj clrObj = *player["Colour"];
if (clrObj.defined())
{
colour = wxColor((*clrObj["r"]).getInt(), (*clrObj["g"]).getInt(), (*clrObj["b"]).getInt());
}
else
{
defined = clrObj.defined();
if (!defined)
clrObj = *playerDefs["Colour"];
colour = wxColor((*clrObj["r"]).getInt(), (*clrObj["g"]).getInt(), (*clrObj["b"]).getInt());
}
colour = wxColor((*clrObj["r"]).getInt(), (*clrObj["g"]).getInt(), (*clrObj["b"]).getInt());
controls.colour->SetBackgroundColour(colour);
wxDynamicCast(FindWindowById(ID_DefaultColour, controls.page), DefaultCheckbox)->SetValue(defined);
// player type
wxString aiID;
if (player["AI"].defined())
defined = player["AI"].defined();
if (defined)
aiID = wxString(player["AI"]);
else
aiID = wxString(playerDefs["AI"]);
choice = controls.ai;
if (!aiID.empty())
{ // AI
{
// AI
for (size_t j = 0; j < choice->GetCount(); ++j)
{
wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(j));
@ -691,44 +757,55 @@ void PlayerSettingsControl::ReadFromEngine()
}
}
}
else
{ // Human
else // Human
choice->SetSelection(0);
}
wxDynamicCast(FindWindowById(ID_DefaultAI, controls.page), DefaultCheckbox)->SetValue(defined);
// resources
AtObj resObj = *player["Resources"];
if (resObj.defined() && resObj["food"].defined())
defined = resObj.defined() && resObj["food"].defined();
if (defined)
controls.food->SetValue(wxString(resObj["food"]));
else
controls.food->SetValue(0);
wxDynamicCast(FindWindowById(ID_DefaultFood, controls.page), DefaultCheckbox)->SetValue(defined);
if (resObj.defined() && resObj["wood"].defined())
defined = resObj.defined() && resObj["wood"].defined();
if (defined)
controls.wood->SetValue(wxString(resObj["wood"]));
else
controls.wood->SetValue(0);
wxDynamicCast(FindWindowById(ID_DefaultWood, controls.page), DefaultCheckbox)->SetValue(defined);
if (resObj.defined() && resObj["metal"].defined())
defined = resObj.defined() && resObj["metal"].defined();
if (defined)
controls.metal->SetValue(wxString(resObj["metal"]));
else
controls.metal->SetValue(0);
wxDynamicCast(FindWindowById(ID_DefaultMetal, controls.page), DefaultCheckbox)->SetValue(defined);
if (resObj.defined() && resObj["stone"].defined())
defined = resObj.defined() && resObj["stone"].defined();
if (defined)
controls.stone->SetValue(wxString(resObj["stone"]));
else
controls.stone->SetValue(0);
wxDynamicCast(FindWindowById(ID_DefaultStone, controls.page), DefaultCheckbox)->SetValue(defined);
// population limit
if (player["PopulationLimit"].defined())
defined = player["PopulationLimit"].defined();
if (defined)
controls.pop->SetValue(wxString(player["PopulationLimit"]));
else
controls.pop->SetValue(0);
wxDynamicCast(FindWindowById(ID_DefaultPop, controls.page), DefaultCheckbox)->SetValue(defined);
// team
if (player["Team"].defined())
defined = player["Team"].defined();
if (defined)
controls.team->SetSelection((*player["Team"]).getInt() + 1);
else
controls.team->SetSelection(0);
wxDynamicCast(FindWindowById(ID_DefaultTeam, controls.page), DefaultCheckbox)->SetValue(defined);
// camera
if (player["StartingCamera"].defined())
@ -767,7 +844,6 @@ void PlayerSettingsControl::ReadFromEngine()
AtObj PlayerSettingsControl::UpdateSettingsObject()
{
// Update player data in the map settings
AtIter oldPlayer = m_MapSettings["PlayerData"]["item"];
AtObj players;
players.set("@array", L"");
@ -777,66 +853,67 @@ AtObj PlayerSettingsControl::UpdateSettingsObject()
{
PlayerPageControls controls = m_PlayerControls[i];
AtObj player = *oldPlayer;
AtObj player;
// name
wxTextCtrl* text = controls.name;
if (!text->GetValue().empty())
{
if (text->IsEnabled())
player.set("Name", text->GetValue());
}
// civ
wxChoice* choice = controls.civ;
if (choice->GetSelection() >= 0)
if (choice->IsEnabled() && choice->GetSelection() >= 0)
{
wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(choice->GetSelection()));
player.set("Civ", str->GetData());
}
// colour
wxColour colour = controls.colour->GetBackgroundColour();
AtObj clrObj;
clrObj.setInt("r", (int)colour.Red());
clrObj.setInt("g", (int)colour.Green());
clrObj.setInt("b", (int)colour.Blue());
player.set("Colour", clrObj);
if (controls.colour->IsEnabled())
{
wxColour colour = controls.colour->GetBackgroundColour();
AtObj clrObj;
clrObj.setInt("r", (int)colour.Red());
clrObj.setInt("g", (int)colour.Green());
clrObj.setInt("b", (int)colour.Blue());
player.set("Colour", clrObj);
}
// player type
choice = controls.ai;
if (choice->GetSelection() > 0)
{ // ai - get id
wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(choice->GetSelection()));
player.set("AI", str->GetData());
}
else
{ // human
player.set("AI", _T(""));
if (choice->IsEnabled())
{
if (choice->GetSelection() > 0)
{
// ai - get id
wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(choice->GetSelection()));
player.set("AI", str->GetData());
}
else // human
player.set("AI", _T(""));
}
// resources
AtObj resObj;
if (controls.food->GetValue() > 0)
if (controls.food->IsEnabled())
resObj.setInt("food", controls.food->GetValue());
if (controls.wood->GetValue() > 0)
if (controls.wood->IsEnabled())
resObj.setInt("wood", controls.wood->GetValue());
if (controls.metal->GetValue() > 0)
if (controls.metal->IsEnabled())
resObj.setInt("metal", controls.metal->GetValue());
if (controls.stone->GetValue() > 0)
if (controls.stone->IsEnabled())
resObj.setInt("stone", controls.stone->GetValue());
if (resObj.defined())
player.set("Resources", resObj);
// population limit
if (controls.pop->GetValue() > 0)
if (controls.pop->IsEnabled())
player.setInt("PopulationLimit", controls.pop->GetValue());
// team
choice = controls.team;
if (choice->GetSelection() >= 0)
{ // valid selection
if (choice->IsEnabled() && choice->GetSelection() >= 0)
player.setInt("Team", choice->GetSelection() - 1);
}
// camera
AtObj camObj;
@ -858,8 +935,6 @@ AtObj PlayerSettingsControl::UpdateSettingsObject()
player.set("StartingCamera", camObj);
players.add("item", player);
if (oldPlayer.defined())
++oldPlayer;
}
m_MapSettings.set("PlayerData", players);

View File

@ -116,7 +116,7 @@ QUERYHANDLER(GenerateMap)
CScriptValRooted atts;
si.Eval("({})", atts);
si.SetProperty(atts.get(), "mapType", std::string("scenario"));
si.SetProperty(atts.get(), "map", std::wstring(L"_default"));
si.SetProperty(atts.get(), "map", std::wstring(L"maps/scenarios/_default"));
StartGame(atts);
msg->status = -1;
@ -226,7 +226,7 @@ MESSAGEHANDLER(ImportHeightmap)
MESSAGEHANDLER(SaveMap)
{
CMapWriter writer;
const VfsPath pathname = VfsPath("maps/scenarios") / *msg->filename;
VfsPath pathname = VfsPath(*msg->filename).ChangeExtension(L".pmp");
writer.SaveMap(pathname,
g_Game->GetWorld()->GetTerrain(),
g_Renderer.GetWaterManager(), g_Renderer.GetSkyManager(),
@ -352,4 +352,22 @@ QUERYHANDLER(VFSFileExists)
msg->exists = VfsFileExists(*msg->path);
}
static Status AddToFilenames(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
{
std::vector<std::wstring>& filenames = *(std::vector<std::wstring>*)cbData;
filenames.push_back(pathname.string().c_str());
return INFO::OK;
}
QUERYHANDLER(GetMapList)
{
std::vector<std::wstring> scenarioFilenames;
vfs::ForEachFile(g_VFS, L"maps/scenarios/", AddToFilenames, (uintptr_t)&scenarioFilenames, L"*.xml", vfs::DIR_RECURSIVE);
msg->scenarioFilenames = scenarioFilenames;
std::vector<std::wstring> skirmishFilenames;
vfs::ForEachFile(g_VFS, L"maps/skirmishes/", AddToFilenames, (uintptr_t)&skirmishFilenames, L"*.xml", vfs::DIR_RECURSIVE);
msg->skirmishFilenames = skirmishFilenames;
}
}

View File

@ -159,6 +159,12 @@ MESSAGE(SaveMap,
((std::wstring, filename))
);
QUERY(GetMapList,
,
((std::vector<std::wstring>, scenarioFilenames))
((std::vector<std::wstring>, skirmishFilenames))
);
QUERY(GetMapSettings,
,
((std::string, settings))