1
0
forked from 0ad/0ad

Adds player editor to Atlas scenario editor. See #91

Fixes object panel so the list of players updates correctly.
Atlas map settings are now observable and shared between various panels.
Fixes panels for maps missing settings (caused JSON error)
Changes map reader so that entities with invalid players cause a warning
but are not added to the game. That prevents further errors. Fixes #869
Uses map size choices from simulation/data/map_sizes.json instead of
multiple locations. Fixes #787
Prepares Atlas map settings for undo/redo support

This was SVN commit r9608.
This commit is contained in:
historic_bruno 2011-06-09 23:45:12 +00:00
parent 266977bc78
commit 23f1072a2e
6 changed files with 836 additions and 179 deletions

View File

@ -19,12 +19,11 @@
#include "Map.h" #include "Map.h"
#include "General/Datafile.h" #include "AtlasObject/AtlasObject.h"
#include "ScenarioEditor/Tools/Common/Tools.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "AtlasScript/ScriptInterface.h" #include "AtlasScript/ScriptInterface.h"
#include "GameInterface/Messages.h" #include "GameInterface/Messages.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "ScenarioEditor/Tools/Common/Tools.h"
#include "wx/busyinfo.h" #include "wx/busyinfo.h"
#include "wx/filename.h" #include "wx/filename.h"
@ -35,7 +34,7 @@ enum
ID_MapDescription, ID_MapDescription,
ID_MapReveal, ID_MapReveal,
ID_MapType, ID_MapType,
ID_MapNumPlayers, ID_MapTeams,
ID_MapKW_Demo, ID_MapKW_Demo,
ID_MapKW_Hidden, ID_MapKW_Hidden,
ID_RandomScript, ID_RandomScript,
@ -58,8 +57,12 @@ enum
SimPlayingSlow, SimPlayingSlow,
SimPaused SimPaused
}; };
bool IsPlaying(int s) { return (s == SimPlaying || s == SimPlayingFast || s == SimPlayingSlow); } bool IsPlaying(int s) { return (s == SimPlaying || s == SimPlayingFast || s == SimPlayingSlow); }
// TODO: Some of these helper things should be moved out of this file
// and into shared locations
// Helper function for adding tooltips // Helper function for adding tooltips
static wxWindow* Tooltipped(wxWindow* window, const wxString& tip) static wxWindow* Tooltipped(wxWindow* window, const wxString& tip)
{ {
@ -78,13 +81,10 @@ private:
AtObj obj; AtObj obj;
}; };
// TODO: Some of these helper things should be moved out of this file class MapSettingsControl : public wxPanel
// and into shared locations
class MapSettings : public wxPanel
{ {
public: public:
MapSettings(wxWindow* parent, ScenarioEditor& scenarioEditor); MapSettingsControl(wxWindow* parent, ScenarioEditor& scenarioEditor);
void CreateWidgets(); void CreateWidgets();
void ReadFromEngine(); void ReadFromEngine();
AtObj UpdateSettingsObject(); AtObj UpdateSettingsObject();
@ -96,39 +96,29 @@ private:
SendToEngine(); SendToEngine();
} }
void OnEditSpin(wxSpinEvent& WXUNUSED(evt))
{
SendToEngine();
}
static const size_t MAX_NUM_PLAYERS = 8;
AtObj m_MapSettings;
std::set<std::wstring> m_MapSettingsKeywords; std::set<std::wstring> m_MapSettingsKeywords;
std::vector<wxChoice*> m_PlayerCivChoices; std::vector<wxChoice*> m_PlayerCivChoices;
ScenarioEditor& m_ScenarioEditor; ScenarioEditor& m_ScenarioEditor;
Observable<AtObj>& m_MapSettings;
DECLARE_EVENT_TABLE(); DECLARE_EVENT_TABLE();
}; };
BEGIN_EVENT_TABLE(MapSettings, wxPanel) BEGIN_EVENT_TABLE(MapSettingsControl, wxPanel)
EVT_TEXT(ID_MapName, MapSettings::OnEdit) EVT_TEXT(ID_MapName, MapSettingsControl::OnEdit)
EVT_TEXT(ID_MapDescription, MapSettings::OnEdit) EVT_TEXT(ID_MapDescription, MapSettingsControl::OnEdit)
EVT_CHECKBOX(wxID_ANY, MapSettings::OnEdit) EVT_CHECKBOX(wxID_ANY, MapSettingsControl::OnEdit)
EVT_CHOICE(wxID_ANY, MapSettings::OnEdit) EVT_CHOICE(wxID_ANY, MapSettingsControl::OnEdit)
EVT_SPINCTRL(ID_MapNumPlayers, MapSettings::OnEditSpin)
END_EVENT_TABLE(); END_EVENT_TABLE();
MapSettings::MapSettings(wxWindow* parent, ScenarioEditor& scenarioEditor) MapSettingsControl::MapSettingsControl(wxWindow* parent, ScenarioEditor& scenarioEditor)
: wxPanel(parent, wxID_ANY), m_ScenarioEditor(scenarioEditor) : wxPanel(parent, wxID_ANY), m_ScenarioEditor(scenarioEditor), m_MapSettings(scenarioEditor.GetMapSettings())
{ {
wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Map settings")); wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Map settings"));
SetSizer(sizer); SetSizer(sizer);
} }
void MapSettings::CreateWidgets() void MapSettingsControl::CreateWidgets()
{ {
wxSizer* sizer = GetSizer(); wxSizer* sizer = GetSizer();
@ -145,60 +135,26 @@ void MapSettings::CreateWidgets()
sizer->Add(Tooltipped(new wxTextCtrl(this, ID_MapDescription, wxEmptyString, wxDefaultPosition, wxSize(-1, 100), wxTE_MULTILINE), sizer->Add(Tooltipped(new wxTextCtrl(this, ID_MapDescription, wxEmptyString, wxDefaultPosition, wxSize(-1, 100), wxTE_MULTILINE),
_("Short description used on the map selection screen")), wxSizerFlags().Expand()); _("Short description used on the map selection screen")), wxSizerFlags().Expand());
sizer->AddSpacer(5);
wxArrayString gameTypes; wxArrayString gameTypes;
gameTypes.Add(_T("conquest")); gameTypes.Add(_T("conquest"));
gameTypes.Add(_T("endless")); gameTypes.Add(_T("endless"));
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 2); wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 2, 5, 5);
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Reveal map")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Reveal map")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(new wxCheckBox(this, ID_MapReveal, wxEmptyString)); gridSizer->Add(new wxCheckBox(this, ID_MapReveal, wxEmptyString));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Game type")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Game type")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(new wxChoice(this, ID_MapType, wxDefaultPosition, wxDefaultSize, gameTypes)); gridSizer->Add(new wxChoice(this, ID_MapType, wxDefaultPosition, wxDefaultSize, gameTypes));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Lock teams")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(new wxCheckBox(this, ID_MapTeams, wxEmptyString));
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Num players")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Num players")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxSpinCtrl* numPlayersSpin = new wxSpinCtrl(this, ID_MapNumPlayers, wxEmptyString, wxDefaultPosition, wxSize(40, -1));
numPlayersSpin->SetValue(MAX_NUM_PLAYERS);
numPlayersSpin->SetRange(1, MAX_NUM_PLAYERS);
gridSizer->Add(numPlayersSpin);
sizer->Add(gridSizer); sizer->Add(gridSizer);
sizer->AddSpacer(5);
wxArrayString civNames;
wxArrayString civCodes;
AtlasMessage::qGetCivData qryCiv;
qryCiv.Post();
std::vector<std::string> civData = *qryCiv.data;
for (size_t i = 0; i < civData.size(); ++i)
{
AtObj civ = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), civData[i]);
civNames.Add(wxString(civ["Name"]));
civCodes.Add(wxString(civ["Code"]));
}
wxCollapsiblePane* playersPane = new wxCollapsiblePane(this, wxID_ANY, _("Player settings"), wxDefaultPosition, wxDefaultSize, wxCP_NO_TLW_RESIZE);
wxFlexGridSizer* playersPaneSizer = new wxFlexGridSizer(2);
playersPaneSizer->AddGrowableCol(1);
playersPaneSizer->Add(new wxStaticText(playersPane->GetPane(), wxID_ANY, _T("")));
playersPaneSizer->Add(new wxStaticText(playersPane->GetPane(), wxID_ANY, _("Civ")));
for (size_t i = 0; i < MAX_NUM_PLAYERS; ++i)
{
wxString idStr;
idStr << (i+1);
playersPaneSizer->Add(new wxStaticText(playersPane->GetPane(), wxID_ANY, idStr), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT).Border(wxRIGHT, 2));
wxChoice* civChoice = new wxChoice(playersPane->GetPane(), wxID_ANY);
for (size_t j = 0; j < civNames.Count(); ++j)
civChoice->Append(civNames[j], new wxStringClientData(civCodes[j]));
m_PlayerCivChoices.push_back(civChoice);
playersPaneSizer->Add(civChoice);
// TODO: Team
// TODO: Resources?
}
playersPane->GetPane()->SetSizer(playersPaneSizer);
sizer->Add(playersPane, wxSizerFlags().Expand());
wxStaticBoxSizer* keywordsSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Keywords")); wxStaticBoxSizer* keywordsSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Keywords"));
wxFlexGridSizer* kwGridSizer = new wxFlexGridSizer(2, 2); wxFlexGridSizer* kwGridSizer = new wxFlexGridSizer(2, 2, 5, 5);
kwGridSizer->Add(new wxStaticText(this, wxID_ANY, _("Demo")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); kwGridSizer->Add(new wxStaticText(this, wxID_ANY, _("Demo")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
kwGridSizer->Add(new wxCheckBox(this, ID_MapKW_Demo, wxEmptyString)); kwGridSizer->Add(new wxCheckBox(this, ID_MapKW_Demo, wxEmptyString));
kwGridSizer->Add(new wxStaticText(this, wxID_ANY, _("Hidden")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); kwGridSizer->Add(new wxStaticText(this, wxID_ANY, _("Hidden")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
@ -207,11 +163,15 @@ void MapSettings::CreateWidgets()
sizer->Add(keywordsSizer, wxSizerFlags().Expand()); sizer->Add(keywordsSizer, wxSizerFlags().Expand());
} }
void MapSettings::ReadFromEngine() void MapSettingsControl::ReadFromEngine()
{ {
AtlasMessage::qGetMapSettings qry; AtlasMessage::qGetMapSettings qry;
qry.Post(); qry.Post();
m_MapSettings = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qry.settings); if (!(*qry.settings).empty())
{
// Prevent error if there's no map settings to parse
m_MapSettings = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qry.settings);
}
m_MapSettingsKeywords.clear(); m_MapSettingsKeywords.clear();
for (AtIter keyword = m_MapSettings["Keywords"]["item"]; keyword.defined(); ++keyword) for (AtIter keyword = m_MapSettings["Keywords"]["item"]; keyword.defined(); ++keyword)
@ -228,37 +188,13 @@ void MapSettings::ReadFromEngine()
else else
wxDynamicCast(FindWindow(ID_MapType), wxChoice)->SetSelection(0); wxDynamicCast(FindWindow(ID_MapType), wxChoice)->SetSelection(0);
size_t numPlayers = m_MapSettings["PlayerData"]["item"].count(); wxDynamicCast(FindWindow(ID_MapTeams), wxCheckBox)->SetValue(wxString(m_MapSettings["LockTeams"]) == L"true");
wxDynamicCast(FindWindow(ID_MapNumPlayers), wxSpinCtrl)->SetValue(numPlayers);
AtIter player = m_MapSettings["PlayerData"]["item"];
for (size_t i = 0; i < numPlayers && i < MAX_NUM_PLAYERS; ++i, ++player)
{
wxChoice* choice = m_PlayerCivChoices[i];
choice->Enable(true);
wxString civCode(player["Civ"]);
for (size_t j = 0; j < choice->GetCount(); ++j)
{
wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(j));
if (str->GetData() == civCode)
{
choice->SetSelection(j);
break;
}
}
}
for (size_t i = numPlayers; i < MAX_NUM_PLAYERS; ++i)
{
wxChoice* choice = m_PlayerCivChoices[i];
choice->SetSelection(0);
choice->Enable(false);
}
wxDynamicCast(FindWindow(ID_MapKW_Demo), wxCheckBox)->SetValue(m_MapSettingsKeywords.count(L"demo") != 0); 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_Hidden), wxCheckBox)->SetValue(m_MapSettingsKeywords.count(L"hidden") != 0);
} }
AtObj MapSettings::UpdateSettingsObject() AtObj MapSettingsControl::UpdateSettingsObject()
{ {
m_MapSettings.set("Name", wxDynamicCast(FindWindow(ID_MapName), wxTextCtrl)->GetValue()); m_MapSettings.set("Name", wxDynamicCast(FindWindow(ID_MapName), wxTextCtrl)->GetValue());
@ -268,31 +204,6 @@ AtObj MapSettings::UpdateSettingsObject()
m_MapSettings.set("GameType", wxDynamicCast(FindWindow(ID_MapType), wxChoice)->GetStringSelection()); m_MapSettings.set("GameType", wxDynamicCast(FindWindow(ID_MapType), wxChoice)->GetStringSelection());
AtIter oldPlayer = m_MapSettings["PlayerData"]["item"];
AtObj players;
players.set("@array", L"");
size_t numPlayers = (size_t)wxDynamicCast(FindWindow(ID_MapNumPlayers), wxSpinCtrl)->GetValue();
for (size_t i = 0; i < numPlayers && i < MAX_NUM_PLAYERS; ++i)
{
wxChoice* choice = m_PlayerCivChoices[i];
choice->Enable(true);
AtObj player = *oldPlayer;
if (choice->GetSelection() >= 0)
{
wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(choice->GetSelection()));
player.set("Civ", str->GetData());
}
players.add("item", player);
if (oldPlayer.defined())
++oldPlayer;
}
for (size_t i = numPlayers; i < MAX_NUM_PLAYERS; ++i)
{
wxChoice* choice = m_PlayerCivChoices[i];
choice->Enable(false);
}
m_MapSettings.set("PlayerData", players);
if (wxDynamicCast(FindWindow(ID_MapKW_Demo), wxCheckBox)->GetValue()) if (wxDynamicCast(FindWindow(ID_MapKW_Demo), wxCheckBox)->GetValue())
m_MapSettingsKeywords.insert(L"demo"); m_MapSettingsKeywords.insert(L"demo");
else else
@ -303,6 +214,8 @@ AtObj MapSettings::UpdateSettingsObject()
else else
m_MapSettingsKeywords.erase(L"hidden"); m_MapSettingsKeywords.erase(L"hidden");
m_MapSettings.setBool("LockTeams", wxDynamicCast(FindWindow(ID_MapTeams), wxCheckBox)->GetValue());
AtObj keywords; AtObj keywords;
keywords.set("@array", L""); keywords.set("@array", L"");
for (std::set<std::wstring>::iterator it = m_MapSettingsKeywords.begin(); it != m_MapSettingsKeywords.end(); ++it) for (std::set<std::wstring>::iterator it = m_MapSettingsKeywords.begin(); it != m_MapSettingsKeywords.end(); ++it)
@ -312,7 +225,7 @@ AtObj MapSettings::UpdateSettingsObject()
return m_MapSettings; return m_MapSettings;
} }
void MapSettings::SendToEngine() void MapSettingsControl::SendToEngine()
{ {
UpdateSettingsObject(); UpdateSettingsObject();
@ -320,44 +233,40 @@ void MapSettings::SendToEngine()
// TODO: would be nice if we supported undo for settings changes // TODO: would be nice if we supported undo for settings changes
POST_MESSAGE(SetMapSettings, (json)); POST_COMMAND(SetMapSettings, (json));
} }
MapSidebar::MapSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) MapSidebar::MapSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), m_SimState(SimInactive) : Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), m_SimState(SimInactive)
{ {
m_MapSettings = new MapSettings(this, m_ScenarioEditor); m_MapSettingsCtrl = new MapSettingsControl(this, m_ScenarioEditor);
m_MainSizer->Add(m_MapSettings, wxSizerFlags().Expand()); m_MainSizer->Add(m_MapSettingsCtrl, wxSizerFlags().Expand());
{ {
wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Random map")); wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Random map"));
sizer->Add(new wxChoice(this, ID_RandomScript), wxSizerFlags().Expand()); sizer->Add(new wxChoice(this, ID_RandomScript), wxSizerFlags().Expand());
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 2); sizer->AddSpacer(5);
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 2, 5, 5);
gridSizer->AddGrowableCol(1); gridSizer->AddGrowableCol(1);
wxChoice* sizeChoice = new wxChoice(this, ID_RandomSize); wxChoice* sizeChoice = new wxChoice(this, ID_RandomSize);
AtObj sizes(Datafile::ReadList("mapsizes"));
for (AtIter s = sizes["size"]; s.defined(); ++s)
{
long tiles = 0;
wxString(s["@tiles"]).ToLong(&tiles);
sizeChoice->Append(wxString(s["@name"]), (void*)(intptr_t)tiles);
}
sizeChoice->SetSelection(0);
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Map size")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Map size")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(sizeChoice, wxSizerFlags().Expand()); gridSizer->Add(sizeChoice, wxSizerFlags().Expand());
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Random seed")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Random seed")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxBoxSizer* seedSizer = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* seedSizer = new wxBoxSizer(wxHORIZONTAL);
seedSizer->Add(new wxTextCtrl(this, ID_RandomSeed, _T("0")), wxSizerFlags(1).Expand()); seedSizer->Add(Tooltipped(new wxTextCtrl(this, ID_RandomSeed, _T("0"), wxDefaultPosition, wxDefaultSize, 0, wxTextValidator(wxFILTER_NUMERIC)), _("Seed value for random map")), wxSizerFlags(1).Expand());
seedSizer->Add(new wxButton(this, ID_RandomReseed, _("R"), wxDefaultPosition, wxSize(24, -1))); seedSizer->Add(Tooltipped(new wxButton(this, ID_RandomReseed, _("R"), wxDefaultPosition, wxSize(24, -1)), _("New random seed")));
gridSizer->Add(seedSizer, wxSizerFlags().Expand()); gridSizer->Add(seedSizer, wxSizerFlags().Expand());
sizer->Add(gridSizer, wxSizerFlags().Expand()); sizer->Add(gridSizer, wxSizerFlags().Expand());
sizer->AddSpacer(5);
sizer->Add(new wxButton(this, ID_RandomGenerate, _("Generate map")), wxSizerFlags().Expand()); sizer->Add(new wxButton(this, ID_RandomGenerate, _("Generate map")), wxSizerFlags().Expand());
m_MainSizer->Add(sizer, wxSizerFlags().Expand().Border(wxTOP, 16)); m_MainSizer->Add(sizer, wxSizerFlags().Expand().Border(wxTOP, 16));
@ -390,15 +299,27 @@ void MapSidebar::OnCollapse(wxCollapsiblePaneEvent& WXUNUSED(evt))
void MapSidebar::OnFirstDisplay() void MapSidebar::OnFirstDisplay()
{ {
m_MapSettings->CreateWidgets(); // We do this here becase messages are used which requires simulation to be init'd
m_MapSettings->ReadFromEngine(); m_MapSettingsCtrl->CreateWidgets();
m_MapSettingsCtrl->ReadFromEngine();
// Load the RMS script list: // Load the map sizes list
AtlasMessage::qGetMapSizes qrySizes;
qrySizes.Post();
AtObj sizes = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qrySizes.sizes);
wxChoice* sizeChoice = wxDynamicCast(FindWindow(ID_RandomSize), wxChoice);
for (AtIter s = sizes["Sizes"]["item"]; s.defined(); ++s)
{
long tiles = 0;
wxString(s["Tiles"]).ToLong(&tiles);
sizeChoice->Append(wxString(s["Name"]), (void*)(intptr_t)tiles);
}
sizeChoice->SetSelection(0);
// Load the RMS script list
AtlasMessage::qGetRMSData qry; AtlasMessage::qGetRMSData qry;
qry.Post(); qry.Post();
std::vector<std::string> scripts = *qry.data; std::vector<std::string> scripts = *qry.data;
wxChoice* scriptChoice = wxDynamicCast(FindWindow(ID_RandomScript), wxChoice); wxChoice* scriptChoice = wxDynamicCast(FindWindow(ID_RandomScript), wxChoice);
scriptChoice->Clear(); scriptChoice->Clear();
for (size_t i = 0; i < scripts.size(); ++i) for (size_t i = 0; i < scripts.size(); ++i)
@ -414,7 +335,7 @@ void MapSidebar::OnFirstDisplay()
void MapSidebar::OnMapReload() void MapSidebar::OnMapReload()
{ {
m_MapSettings->ReadFromEngine(); m_MapSettingsCtrl->ReadFromEngine();
} }
void MapSidebar::UpdateSimButtons() void MapSidebar::UpdateSimButtons()
@ -518,7 +439,7 @@ void MapSidebar::OnRandomGenerate(wxCommandEvent& WXUNUSED(evt))
// TODO: this settings thing seems a bit of a mess, // TODO: this settings thing seems a bit of a mess,
// since it's mixing data from three different sources // since it's mixing data from three different sources
AtObj settings = m_MapSettings->UpdateSettingsObject(); AtObj settings = m_MapSettingsCtrl->UpdateSettingsObject();
AtObj scriptSettings = dynamic_cast<AtObjClientData*>(scriptChoice->GetClientObject(scriptChoice->GetSelection()))->GetValue(); AtObj scriptSettings = dynamic_cast<AtObjClientData*>(scriptChoice->GetClientObject(scriptChoice->GetSelection()))->GetValue();

View File

@ -19,7 +19,7 @@
#include "wx/collpane.h" #include "wx/collpane.h"
class MapSettings; class MapSettingsControl;
class MapSidebar : public Sidebar class MapSidebar : public Sidebar
{ {
@ -32,7 +32,7 @@ protected:
virtual void OnFirstDisplay(); virtual void OnFirstDisplay();
private: private:
MapSettings* m_MapSettings; MapSettingsControl* m_MapSettingsCtrl;
void OnCollapse(wxCollapsiblePaneEvent& evt); void OnCollapse(wxCollapsiblePaneEvent& evt);
void OnSimPlay(wxCommandEvent& evt); void OnSimPlay(wxCommandEvent& evt);

View File

@ -20,9 +20,11 @@
#include "Object.h" #include "Object.h"
#include "Buttons/ToolButton.h" #include "Buttons/ToolButton.h"
#include "General/Datafile.h"
#include "ScenarioEditor/ScenarioEditor.h" #include "ScenarioEditor/ScenarioEditor.h"
#include "ScenarioEditor/Tools/Common/ObjectSettings.h" #include "ScenarioEditor/Tools/Common/ObjectSettings.h"
#include "ScenarioEditor/Tools/Common/MiscState.h" #include "ScenarioEditor/Tools/Common/MiscState.h"
#include "AtlasScript/ScriptInterface.h"
#include "VariationControl.h" #include "VariationControl.h"
#include "GameInterface/Messages.h" #include "GameInterface/Messages.h"
@ -32,6 +34,7 @@
enum enum
{ {
ID_ObjectType = 1, ID_ObjectType = 1,
ID_PlayerSelect,
ID_SelectObject, ID_SelectObject,
ID_ToggleViewer, ID_ToggleViewer,
ID_ViewerWireframe, ID_ViewerWireframe,
@ -55,7 +58,7 @@ static wxWindow* Tooltipped(wxWindow* window, const wxString& tip)
class ObjectBottomBar : public wxPanel class ObjectBottomBar : public wxPanel
{ {
public: public:
ObjectBottomBar(wxWindow* parent, Observable<ObjectSettings>& objectSettings, ObjectSidebarImpl* p); ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEditor, Observable<ObjectSettings>& objectSettings, Observable<AtObj>& mapSettings, ObjectSidebarImpl* p);
void OnFirstDisplay(); void OnFirstDisplay();
@ -76,6 +79,8 @@ private:
ObjectSidebarImpl* p; ObjectSidebarImpl* p;
ScenarioEditor& m_ScenarioEditor;
DECLARE_EVENT_TABLE(); DECLARE_EVENT_TABLE();
}; };
@ -117,7 +122,7 @@ ObjectSidebar::ObjectSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarCo
m_MainSizer->Add(new wxButton(this, ID_ToggleViewer, _("Switch to Actor Viewer")), wxSizerFlags().Expand()); m_MainSizer->Add(new wxButton(this, ID_ToggleViewer, _("Switch to Actor Viewer")), wxSizerFlags().Expand());
m_BottomBar = new ObjectBottomBar(bottomBarContainer, scenarioEditor.GetObjectSettings(), p); m_BottomBar = new ObjectBottomBar(bottomBarContainer, scenarioEditor, scenarioEditor.GetObjectSettings(), scenarioEditor.GetMapSettings(), p);
p->m_ToolConn = scenarioEditor.GetToolManager().GetCurrentTool().RegisterObserver(0, &ObjectSidebar::OnToolChange, this); p->m_ToolConn = scenarioEditor.GetToolManager().GetCurrentTool().RegisterObserver(0, &ObjectSidebar::OnToolChange, this);
} }
@ -219,27 +224,58 @@ END_EVENT_TABLE();
class PlayerComboBox : public wxComboBox class PlayerComboBox : public wxComboBox
{ {
public: public:
PlayerComboBox(wxWindow* parent, wxArrayString& choices, Observable<ObjectSettings>& objectSettings) PlayerComboBox(wxWindow* parent, Observable<ObjectSettings>& objectSettings, Observable<AtObj>& mapSettings)
: wxComboBox(parent, -1, choices[objectSettings.GetPlayerID()], wxDefaultPosition, wxDefaultSize, choices, wxCB_READONLY) : wxComboBox(parent, ID_PlayerSelect, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY)
, m_ObjectSettings(objectSettings) , m_ObjectSettings(objectSettings), m_MapSettings(mapSettings)
{ {
m_Conn = m_ObjectSettings.RegisterObserver(1, &PlayerComboBox::OnObjectSettingsChange, this); m_ObjectConn = m_ObjectSettings.RegisterObserver(1, &PlayerComboBox::OnObjectSettingsChange, this);
m_MapConn = m_MapSettings.RegisterObserver(1, &PlayerComboBox::OnMapSettingsChange, this);
}
void SetPlayers(wxArrayString& names)
{
m_Players = names;
OnMapSettingsChange(m_MapSettings);
} }
private: private:
ObservableScopedConnection m_Conn; ObservableScopedConnection m_ObjectConn;
Observable<ObjectSettings>& m_ObjectSettings; Observable<ObjectSettings>& m_ObjectSettings;
ObservableScopedConnection m_MapConn;
Observable<AtObj>& m_MapSettings;
wxArrayString m_Players;
void OnObjectSettingsChange(const ObjectSettings& settings) void OnObjectSettingsChange(const ObjectSettings& settings)
{ {
SetSelection((long)settings.GetPlayerID()); SetSelection((long)settings.GetPlayerID());
} }
void OnMapSettingsChange(const AtObj& settings)
{
// Adjust displayed number of players
Clear();
size_t numPlayers = settings["PlayerData"]["item"].count();
for (size_t i = 0; i <= numPlayers; ++i)
{
Append(m_Players[i]);
}
if (m_ObjectSettings.GetPlayerID() > numPlayers)
{
// Invalid player
SetSelection((long)numPlayers);
}
else
{
SetSelection((long)m_ObjectSettings.GetPlayerID());
}
}
void OnSelect(wxCommandEvent& evt) void OnSelect(wxCommandEvent& evt)
{ {
m_ObjectSettings.SetPlayerID(evt.GetInt()); m_ObjectSettings.SetPlayerID(evt.GetInt());
m_ObjectSettings.NotifyObserversExcept(m_Conn); m_ObjectSettings.NotifyObserversExcept(m_ObjectConn);
} }
DECLARE_EVENT_TABLE(); DECLARE_EVENT_TABLE();
@ -250,8 +286,8 @@ END_EVENT_TABLE();
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable<ObjectSettings>& objectSettings, ObjectSidebarImpl* p) ObjectBottomBar::ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEditor, Observable<ObjectSettings>& objectSettings, Observable<AtObj>& mapSettings, ObjectSidebarImpl* p)
: wxPanel(parent, wxID_ANY), p(p) : wxPanel(parent, wxID_ANY), p(p), m_ScenarioEditor(scenarioEditor)
{ {
m_ViewerWireframe = false; m_ViewerWireframe = false;
m_ViewerMove = false; m_ViewerMove = false;
@ -276,12 +312,14 @@ ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable<ObjectSettings>& o
wxSizer* viewerAnimSizer = new wxStaticBoxSizer(wxVERTICAL, m_ViewerPanel, _("Animation")); wxSizer* viewerAnimSizer = new wxStaticBoxSizer(wxVERTICAL, m_ViewerPanel, _("Animation"));
wxString animChoices[] = { // TODO: this list should come from the actor
_T("idle"), _T("walk"), _T("run"), _T("melee"), _T("death"), _T("build"), wxArrayString animChoices;
_T("gather_fruit"), _T("gather_grain"), _T("gather_meat"), _T("gather_tree"), AtObj anims (Datafile::ReadList("animations"));
_T("gather_rock"), _T("gather_ore"), _T("gather_ruins"), _T("gather_treasure") for (AtIter a = anims["item"]; a.defined(); ++a)
}; // TODO: this list should come from the actor {
wxChoice* viewerAnimSelector = new wxChoice(m_ViewerPanel, ID_ViewerAnimation, wxDefaultPosition, wxDefaultSize, sizeof(animChoices)/sizeof(animChoices[0]), animChoices); animChoices.Add(wxString(*a));
}
wxChoice* viewerAnimSelector = new wxChoice(m_ViewerPanel, ID_ViewerAnimation, wxDefaultPosition, wxDefaultSize, animChoices);
viewerAnimSelector->SetSelection(0); viewerAnimSelector->SetSelection(0);
viewerAnimSizer->Add(viewerAnimSelector, wxSizerFlags().Expand()); viewerAnimSizer->Add(viewerAnimSelector, wxSizerFlags().Expand());
@ -301,19 +339,8 @@ ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable<ObjectSettings>& o
wxSizer* playerVariationSizer = new wxBoxSizer(wxVERTICAL); wxSizer* playerVariationSizer = new wxBoxSizer(wxVERTICAL);
wxArrayString players;
// TODO: get proper player names
players.Add(_("Gaia"));
players.Add(_("Player 1"));
players.Add(_("Player 2"));
players.Add(_("Player 3"));
players.Add(_("Player 4"));
players.Add(_("Player 5"));
players.Add(_("Player 6"));
players.Add(_("Player 7"));
players.Add(_("Player 8"));
wxComboBox* playerSelect = new PlayerComboBox(this, players, objectSettings);
// TODO: make this a wxChoice instead // TODO: make this a wxChoice instead
wxComboBox* playerSelect = new PlayerComboBox(this, objectSettings, mapSettings);
playerVariationSizer->Add(playerSelect); playerVariationSizer->Add(playerSelect);
wxWindow* variationSelect = new VariationControl(this, objectSettings); wxWindow* variationSelect = new VariationControl(this, objectSettings);
@ -329,6 +356,20 @@ ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable<ObjectSettings>& o
void ObjectBottomBar::OnFirstDisplay() void ObjectBottomBar::OnFirstDisplay()
{ {
// We use messages here because the simulation is not init'd otherwise (causing a crash)
// Get player names
wxArrayString players;
AtlasMessage::qGetPlayerDefaults qryPlayers;
qryPlayers.Post();
AtObj playerData = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qryPlayers.defaults);
AtObj playerDefs = *playerData["PlayerData"];
for (AtIter p = playerDefs["item"]; p.defined(); ++p)
{
players.Add(wxString(p["Name"]));
}
wxDynamicCast(FindWindow(ID_PlayerSelect), PlayerComboBox)->SetPlayers(players);
// Initialise the game with the default settings // Initialise the game with the default settings
POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"wireframe", m_ViewerWireframe)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"wireframe", m_ViewerWireframe));
POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"walk", m_ViewerMove)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"walk", m_ViewerMove));

View File

@ -0,0 +1,650 @@
/* Copyright (C) 2011 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 "Player.h"
#include "AtlasObject/AtlasObject.h"
#include "AtlasScript/ScriptInterface.h"
#include "GameInterface/Messages.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "wx/choicebk.h"
enum
{
ID_NumPlayers,
ID_PlayerFood,
ID_PlayerWood,
ID_PlayerMetal,
ID_PlayerStone,
ID_PlayerPop,
ID_PlayerColour
};
// Controls present on each player page
struct PlayerPageControls
{
wxTextCtrl* name;
wxChoice* civ;
wxButton* colour;
wxSpinCtrl* food;
wxSpinCtrl* wood;
wxSpinCtrl* stone;
wxSpinCtrl* metal;
wxSpinCtrl* pop;
wxChoice* team;
};
// TODO: Some of these helper things should be moved out of this file
// and into shared locations
// Helper function for adding tooltips
static wxWindow* Tooltipped(wxWindow* window, const wxString& tip)
{
window->SetToolTip(tip);
return window;
}
//////////////////////////////////////////////////////////////////////////
class PlayerNotebookPage : public wxPanel
{
public:
PlayerNotebookPage(ScenarioEditor& scenarioEditor, wxWindow* parent, const wxString& name, size_t playerID)
: wxPanel(parent, wxID_ANY), m_ScenarioEditor(scenarioEditor), m_Name(name), m_PlayerID(playerID)
{
Freeze();
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
SetSizer(sizer);
/////////////////////////////////////////////////////////////////////////
// Player Info
wxStaticBoxSizer* playerInfoSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Player info"));
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 2, 5, 5);
gridSizer->AddGrowableCol(1);
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Name")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxTextCtrl* nameCtrl = new wxTextCtrl(this, wxID_ANY);
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(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(Tooltipped(colourButton, _("Set player colour")), wxSizerFlags(1).Expand().Align(wxALIGN_RIGHT));
m_Controls.colour = colourButton;
playerInfoSizer->Add(gridSizer, wxSizerFlags(1).Expand());
sizer->Add(playerInfoSizer, wxSizerFlags().Expand());
/////////////////////////////////////////////////////////////////////////
// Resources
wxStaticBoxSizer* resourceSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Resources"));
gridSizer = new wxFlexGridSizer(2, 2, 5, 5);
gridSizer->AddGrowableCol(1);
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Food")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxSpinCtrl* foodCtrl = new wxSpinCtrl(this, ID_PlayerFood, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, INT_MAX);
gridSizer->Add(Tooltipped(foodCtrl, _("Initial value of food resource")));
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, 0, 0, INT_MAX);
gridSizer->Add(Tooltipped(woodCtrl, _("Initial value of wood resource")));
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, 0, 0, INT_MAX);
gridSizer->Add(Tooltipped(metalCtrl, _("Initial value of metal resource")));
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, 0, 0, INT_MAX);
gridSizer->Add(Tooltipped(stoneCtrl, _("Initial value of stone resource")));
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, 0, 0, INT_MAX);
gridSizer->Add(Tooltipped(popCtrl, _("Population limit for this player")));
m_Controls.pop = popCtrl;
resourceSizer->Add(gridSizer, wxSizerFlags(1).Expand());
sizer->Add(resourceSizer, wxSizerFlags().Expand());
/////////////////////////////////////////////////////////////////////////
// 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);
teamCtrl->Append(_("None"));
teamCtrl->Append(_T("1"));
teamCtrl->Append(_T("2"));
teamCtrl->Append(_T("3"));
teamCtrl->Append(_T("4"));
boxSizer->Add(teamCtrl);
m_Controls.team = teamCtrl;
diplomacySizer->Add(boxSizer, wxSizerFlags(1).Expand());
// TODO: possibly have advanced panel where each player's diplomacy can be set?
// Advanced panel
/*wxCollapsiblePane* advPane = new wxCollapsiblePane(this, wxID_ANY, _("Advanced"));
wxWindow* pane = advPane->GetPane();
diplomacySizer->Add(advPane, 0, wxGROW | wxALL, 2);*/
sizer->Add(diplomacySizer, wxSizerFlags().Expand());
Layout();
Thaw();
}
void OnDisplay()
{
}
PlayerPageControls GetControls()
{
return m_Controls;
}
wxString GetPlayerName()
{
return m_Name;
}
size_t GetPlayerID()
{
return m_PlayerID;
}
private:
void OnColour(wxCommandEvent& evt)
{
// Show colour dialog
wxColourData clrData;
clrData.SetColour(m_Controls.colour->GetBackgroundColour());
wxColourDialog colourDlg(this, &clrData);
colourDlg.SetTitle(_("Choose player colour"));
if (colourDlg.ShowModal() == wxID_OK)
{
m_Controls.colour->SetBackgroundColour(colourDlg.GetColourData().GetColour());
// Pass event on to next handler
evt.Skip();
}
}
ScenarioEditor& m_ScenarioEditor;
wxString m_Name;
size_t m_PlayerID;
PlayerPageControls m_Controls;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(PlayerNotebookPage, wxPanel)
EVT_BUTTON(ID_PlayerColour, PlayerNotebookPage::OnColour)
END_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
class PlayerNotebook : public wxChoicebook
{
public:
PlayerNotebook(ScenarioEditor& scenarioEditor, wxWindow *parent)
: wxChoicebook(parent, wxID_ANY/*, wxDefaultPosition, wxDefaultSize, wxNB_FIXEDWIDTH*/),
m_ScenarioEditor(scenarioEditor)
{
}
PlayerPageControls AddPlayer(wxString name, size_t player)
{
PlayerNotebookPage* playerPage = new PlayerNotebookPage(m_ScenarioEditor, this, name, player);
AddPage(playerPage, name);
m_Pages.push_back(playerPage);
return playerPage->GetControls();
}
void ResizePlayers(size_t numPlayers)
{
// We don't really want to destroy the windows corresponding
// to the tabs, so we've kept them in a vector and will
// only remove and add them to the notebook as needed
if (numPlayers <= m_Pages.size())
{
size_t pageCount = GetPageCount();
if (numPlayers > pageCount)
{
// Add previously removed pages
for (size_t i = pageCount; i < numPlayers; ++i)
{
AddPage(m_Pages[i], m_Pages[i]->GetPlayerName());
}
}
else
{
// Remove previously added pages
// we have to manually hide them or they remain visible
for (size_t i = pageCount - 1; i >= numPlayers; --i)
{
m_Pages[i]->Hide();
RemovePage(i);
}
}
}
}
protected:
void OnPageChanged(wxChoicebookEvent& evt)
{
if (evt.GetSelection() >= 0 && evt.GetSelection() < (int)GetPageCount())
{
static_cast<PlayerNotebookPage*>(GetPage(evt.GetSelection()))->OnDisplay();
}
evt.Skip();
}
private:
ScenarioEditor& m_ScenarioEditor;
std::vector<PlayerNotebookPage*> m_Pages;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(PlayerNotebook, wxChoicebook)
EVT_CHOICEBOOK_PAGE_CHANGED(wxID_ANY, PlayerNotebook::OnPageChanged)
END_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
class PlayerSettingsControl : public wxPanel
{
public:
PlayerSettingsControl(wxWindow* parent, ScenarioEditor& scenarioEditor);
void CreateWidgets();
void LoadDefaults();
void ReadFromEngine();
AtObj UpdateSettingsObject();
private:
void SendToEngine();
void OnEdit(wxCommandEvent& WXUNUSED(evt))
{
if (!m_InGUIUpdate)
{
SendToEngine();
}
}
void OnEditSpin(wxSpinEvent& WXUNUSED(evt))
{
if (!m_InGUIUpdate)
{
SendToEngine();
}
}
void OnNumPlayersChanged(wxSpinEvent& WXUNUSED(evt))
{
if (!m_InGUIUpdate)
{
m_Players->ResizePlayers(wxDynamicCast(FindWindow(ID_NumPlayers), wxSpinCtrl)->GetValue());
SendToEngine();
// Notify observers
m_MapSettings.NotifyObservers();
}
}
static const size_t MAX_NUM_PLAYERS = 8;
bool m_InGUIUpdate;
AtObj m_PlayerDefaults;
PlayerNotebook* m_Players;
ScenarioEditor& m_ScenarioEditor;
std::vector<PlayerPageControls> m_PlayerControls;
Observable<AtObj>& m_MapSettings;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(PlayerSettingsControl, wxPanel)
EVT_BUTTON(ID_PlayerColour, PlayerSettingsControl::OnEdit)
EVT_CHOICE(wxID_ANY, PlayerSettingsControl::OnEdit)
EVT_TEXT(wxID_ANY, PlayerSettingsControl::OnEdit)
EVT_SPINCTRL(ID_NumPlayers, PlayerSettingsControl::OnNumPlayersChanged)
EVT_SPINCTRL(ID_PlayerFood, PlayerSettingsControl::OnEditSpin)
EVT_SPINCTRL(ID_PlayerWood, PlayerSettingsControl::OnEditSpin)
EVT_SPINCTRL(ID_PlayerMetal, PlayerSettingsControl::OnEditSpin)
EVT_SPINCTRL(ID_PlayerStone, PlayerSettingsControl::OnEditSpin)
EVT_SPINCTRL(ID_PlayerPop, PlayerSettingsControl::OnEditSpin)
END_EVENT_TABLE();
PlayerSettingsControl::PlayerSettingsControl(wxWindow* parent, ScenarioEditor& scenarioEditor)
: wxPanel(parent, wxID_ANY), m_ScenarioEditor(scenarioEditor), m_InGUIUpdate(false), m_MapSettings(scenarioEditor.GetMapSettings())
{
// To prevent recursion, don't handle GUI events right now
m_InGUIUpdate = true;
wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Player settings"));
SetSizer(sizer);
wxBoxSizer* boxSizer = new wxBoxSizer(wxHORIZONTAL);
boxSizer->Add(new wxStaticText(this, wxID_ANY, _("Num players")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxSpinCtrl* numPlayersSpin = new wxSpinCtrl(this, ID_NumPlayers, wxEmptyString, wxDefaultPosition, wxSize(40, -1));
numPlayersSpin->SetValue(MAX_NUM_PLAYERS);
numPlayersSpin->SetRange(1, MAX_NUM_PLAYERS);
boxSizer->Add(numPlayersSpin);
sizer->Add(boxSizer, wxSizerFlags().Expand().Proportion(0));
sizer->AddSpacer(5);
m_Players = new PlayerNotebook(m_ScenarioEditor, this);
sizer->Add(m_Players, wxSizerFlags().Expand().Proportion(1));
m_InGUIUpdate = false;
}
void PlayerSettingsControl::CreateWidgets()
{
// To prevent recursion, don't handle GUI events right now
m_InGUIUpdate = true;
// Load default civ and player data
wxArrayString civNames;
wxArrayString civCodes;
AtlasMessage::qGetCivData qryCiv;
qryCiv.Post();
std::vector<std::string> civData = *qryCiv.data;
for (size_t i = 0; i < civData.size(); ++i)
{
AtObj civ = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), civData[i]);
civNames.Add(wxString(civ["Name"]));
civCodes.Add(wxString(civ["Code"]));
}
// Create player pages
AtIter player = m_PlayerDefaults["item"];
++player; // Skip gaia
for (size_t i = 0; i < MAX_NUM_PLAYERS; ++i, ++player)
{
// Create new player tab and get controls
PlayerPageControls controls = m_Players->AddPlayer(wxString(player["Name"]), i);
m_PlayerControls.push_back(controls);
// Populate civ choice box
wxChoice* civChoice = controls.civ;
for (size_t j = 0; j < civNames.Count(); ++j)
civChoice->Append(civNames[j], new wxStringClientData(civCodes[j]));
}
m_InGUIUpdate = false;
}
void PlayerSettingsControl::LoadDefaults()
{
AtlasMessage::qGetPlayerDefaults qryPlayers;
qryPlayers.Post();
AtObj playerData = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qryPlayers.defaults);
m_PlayerDefaults = *playerData["PlayerData"];
}
void PlayerSettingsControl::ReadFromEngine()
{
AtlasMessage::qGetMapSettings qry;
qry.Post();
if (!(*qry.settings).empty())
{
// Prevent error if there's no map settings to parse
m_MapSettings = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qry.settings);
}
AtIter player = m_MapSettings["PlayerData"]["item"];
size_t numPlayers = player.count();
if (!m_MapSettings.defined() || !player.defined() || numPlayers == 0)
{
// Player data missing - set number of players manually
numPlayers = MAX_NUM_PLAYERS;
}
// To prevent recursion, don't handle GUI events right now
m_InGUIUpdate = true;
// Update player controls with player data
AtIter playerDefs = m_PlayerDefaults["item"];
++playerDefs; // skip gaia
wxDynamicCast(FindWindow(ID_NumPlayers), wxSpinCtrl)->SetValue(numPlayers);
// Remove / add extra player pages as needed
m_Players->ResizePlayers(numPlayers);
for (size_t i = 0; i < numPlayers && i < MAX_NUM_PLAYERS; ++i, ++player, ++playerDefs)
{
PlayerPageControls controls = m_PlayerControls[i];
// name
wxString name;
if (player["Name"].defined())
name = wxString(player["Name"]);
else
name = wxString(playerDefs["Name"]);
controls.name->SetValue(name);
// civ
wxChoice* choice = controls.civ;
wxString civCode(player["Civ"]);
for (size_t j = 0; j < choice->GetCount(); ++j)
{
wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(j));
if (str->GetData() == civCode)
{
choice->SetSelection(j);
break;
}
}
// colour
wxColour colour;
AtObj clrObj = *player["Colour"];
if (clrObj.defined())
{
colour = wxColor(wxAtoi(*clrObj["r"]), wxAtoi(*clrObj["g"]), wxAtoi(*clrObj["b"]));
}
else
{
clrObj = *playerDefs["Colour"];
colour = wxColor(wxAtoi(*clrObj["r"]), wxAtoi(*clrObj["g"]), wxAtoi(*clrObj["b"]));
}
controls.colour->SetBackgroundColour(colour);
// resources
AtObj resObj = *player["Resources"];
if (resObj.defined() && resObj["food"].defined())
controls.food->SetValue(wxString(resObj["food"]));
else
controls.food->SetValue(0);
if (resObj.defined() && resObj["wood"].defined())
controls.wood->SetValue(wxString(resObj["wood"]));
else
controls.wood->SetValue(0);
if (resObj.defined() && resObj["metal"].defined())
controls.metal->SetValue(wxString(resObj["metal"]));
else
controls.metal->SetValue(0);
if (resObj.defined() && resObj["stone"].defined())
controls.stone->SetValue(wxString(resObj["stone"]));
else
controls.stone->SetValue(0);
// population limit
if (player["PopulationLimit"].defined())
controls.pop->SetValue(wxString(player["PopulationLimit"]));
else
controls.pop->SetValue(0);
// team
if (player["Team"].defined())
controls.team->SetSelection(wxAtoi(*player["Team"]));
else
controls.team->SetSelection(0);
}
m_InGUIUpdate = false;
}
AtObj PlayerSettingsControl::UpdateSettingsObject()
{
// Update player data in the map settings
AtIter oldPlayer = m_MapSettings["PlayerData"]["item"];
size_t numPlayers = wxDynamicCast(FindWindow(ID_NumPlayers), wxSpinCtrl)->GetValue();
AtObj players;
players.set("@array", L"");
for (size_t i = 0; i < numPlayers && i < MAX_NUM_PLAYERS; ++i)
{
PlayerPageControls controls = m_PlayerControls[i];
AtObj player = *oldPlayer;
// name
wxTextCtrl* text = controls.name;
if (!text->GetValue().empty())
{
player.set("Name", text->GetValue());
}
// civ
wxChoice* choice = controls.civ;
if (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);
// resources
AtObj resObj;
if (controls.food->GetValue() > 0)
resObj.setInt("food", controls.food->GetValue());
if (controls.wood->GetValue() > 0)
resObj.setInt("wood", controls.wood->GetValue());
if (controls.metal->GetValue() > 0)
resObj.setInt("metal", controls.metal->GetValue());
if (controls.stone->GetValue() > 0)
resObj.setInt("stone", controls.stone->GetValue());
if (resObj.defined())
player.set("Resources", resObj);
// population limit
if (controls.pop->GetValue() > 0)
player.setInt("PopulationLimit", controls.pop->GetValue());
// team
choice = controls.team;
if (choice->GetSelection() > 0)
{
// valid selection
player.setInt("Team", choice->GetSelection() - 1);
}
players.add("item", player);
if (oldPlayer.defined())
++oldPlayer;
}
m_MapSettings.set("PlayerData", players);
return m_MapSettings;
}
void PlayerSettingsControl::SendToEngine()
{
UpdateSettingsObject();
std::string json = AtlasObject::SaveToJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), m_MapSettings);
// TODO: would be nice if we supported undo for settings changes
POST_COMMAND(SetMapSettings, (json));
}
//////////////////////////////////////////////////////////////////////////
PlayerSidebar::PlayerSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), m_Loaded(false)
{
m_PlayerSettingsCtrl = new PlayerSettingsControl(this, m_ScenarioEditor);
m_MainSizer->Add(m_PlayerSettingsCtrl, wxSizerFlags().Expand());
}
void PlayerSidebar::OnCollapse(wxCollapsiblePaneEvent& WXUNUSED(evt))
{
Freeze();
// Toggling the collapsing doesn't seem to update the sidebar layout
// automatically, so do it explicitly here
Layout();
Refresh(); // fixes repaint glitch on Windows
Thaw();
}
void PlayerSidebar::OnFirstDisplay()
{
// We do this here becase messages are used which requires simulation to be init'd
m_PlayerSettingsCtrl->LoadDefaults();
m_PlayerSettingsCtrl->CreateWidgets();
m_PlayerSettingsCtrl->ReadFromEngine();
m_Loaded = true;
Layout();
}
void PlayerSidebar::OnMapReload()
{
// Make sure we've loaded the controls
if (m_Loaded)
{
m_PlayerSettingsCtrl->ReadFromEngine();
}
}
BEGIN_EVENT_TABLE(PlayerSidebar, Sidebar)
EVT_COLLAPSIBLEPANE_CHANGED(wxID_ANY, PlayerSidebar::OnCollapse)
END_EVENT_TABLE();

View File

@ -0,0 +1,42 @@
/* Copyright (C) 2011 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 "../Common/Sidebar.h"
#include "wx/collpane.h"
class PlayerSettingsControl;
class PlayerSidebar : public Sidebar
{
public:
PlayerSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
virtual void OnMapReload();
protected:
virtual void OnFirstDisplay();
private:
PlayerSettingsControl* m_PlayerSettingsCtrl;
void OnCollapse(wxCollapsiblePaneEvent& evt);
bool m_Loaded;
DECLARE_EVENT_TABLE();
};

View File

@ -20,10 +20,10 @@
#include "Terrain.h" #include "Terrain.h"
#include "Buttons/ToolButton.h" #include "Buttons/ToolButton.h"
#include "General/Datafile.h"
#include "ScenarioEditor/ScenarioEditor.h" #include "ScenarioEditor/ScenarioEditor.h"
#include "ScenarioEditor/Tools/Common/Brushes.h" #include "ScenarioEditor/Tools/Common/Brushes.h"
#include "ScenarioEditor/Tools/Common/MiscState.h" #include "ScenarioEditor/Tools/Common/MiscState.h"
#include "AtlasScript/ScriptInterface.h"
#include "GameInterface/Messages.h" #include "GameInterface/Messages.h"
@ -138,12 +138,15 @@ void TerrainSidebar::OnResizeMap(wxCommandEvent& WXUNUSED(evt))
wxArrayString sizeNames; wxArrayString sizeNames;
std::vector<size_t> sizeTiles; std::vector<size_t> sizeTiles;
AtObj sizes(Datafile::ReadList("mapsizes")); // Load the map sizes list
for (AtIter s = sizes["size"]; s.defined(); ++s) AtlasMessage::qGetMapSizes qrySizes;
qrySizes.Post();
AtObj sizes = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qrySizes.sizes);
for (AtIter s = sizes["Sizes"]["item"]; s.defined(); ++s)
{ {
long tiles = 0; long tiles = 0;
wxString(s["@tiles"]).ToLong(&tiles); wxString(s["Tiles"]).ToLong(&tiles);
sizeNames.Add(wxString(s["@name"])); sizeNames.Add(wxString(s["Name"]));
sizeTiles.push_back((size_t)tiles); sizeTiles.push_back((size_t)tiles);
} }