From 23f1072a2ef69c56578c2037651c340a80538512 Mon Sep 17 00:00:00 2001 From: historic_bruno Date: Thu, 9 Jun 2011 23:45:12 +0000 Subject: [PATCH] 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. --- .../ScenarioEditor/Sections/Map/Map.cpp | 209 ++---- .../AtlasUI/ScenarioEditor/Sections/Map/Map.h | 4 +- .../ScenarioEditor/Sections/Object/Object.cpp | 97 ++- .../ScenarioEditor/Sections/Player/Player.cpp | 650 ++++++++++++++++++ .../ScenarioEditor/Sections/Player/Player.h | 42 ++ .../Sections/Terrain/Terrain.cpp | 13 +- 6 files changed, 836 insertions(+), 179 deletions(-) create mode 100644 source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp create mode 100644 source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.h diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp index f687f9893c..8180f8d416 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp @@ -19,12 +19,11 @@ #include "Map.h" -#include "General/Datafile.h" -#include "ScenarioEditor/Tools/Common/Tools.h" -#include "ScenarioEditor/ScenarioEditor.h" +#include "AtlasObject/AtlasObject.h" #include "AtlasScript/ScriptInterface.h" - #include "GameInterface/Messages.h" +#include "ScenarioEditor/ScenarioEditor.h" +#include "ScenarioEditor/Tools/Common/Tools.h" #include "wx/busyinfo.h" #include "wx/filename.h" @@ -35,7 +34,7 @@ enum ID_MapDescription, ID_MapReveal, ID_MapType, - ID_MapNumPlayers, + ID_MapTeams, ID_MapKW_Demo, ID_MapKW_Hidden, ID_RandomScript, @@ -58,8 +57,12 @@ enum SimPlayingSlow, SimPaused }; + 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 static wxWindow* Tooltipped(wxWindow* window, const wxString& tip) { @@ -78,13 +81,10 @@ private: AtObj obj; }; -// TODO: Some of these helper things should be moved out of this file -// and into shared locations - -class MapSettings : public wxPanel +class MapSettingsControl : public wxPanel { public: - MapSettings(wxWindow* parent, ScenarioEditor& scenarioEditor); + MapSettingsControl(wxWindow* parent, ScenarioEditor& scenarioEditor); void CreateWidgets(); void ReadFromEngine(); AtObj UpdateSettingsObject(); @@ -96,39 +96,29 @@ private: SendToEngine(); } - void OnEditSpin(wxSpinEvent& WXUNUSED(evt)) - { - SendToEngine(); - } - - static const size_t MAX_NUM_PLAYERS = 8; - - AtObj m_MapSettings; std::set m_MapSettingsKeywords; - std::vector m_PlayerCivChoices; - ScenarioEditor& m_ScenarioEditor; + Observable& m_MapSettings; DECLARE_EVENT_TABLE(); }; -BEGIN_EVENT_TABLE(MapSettings, wxPanel) - EVT_TEXT(ID_MapName, MapSettings::OnEdit) - EVT_TEXT(ID_MapDescription, MapSettings::OnEdit) - EVT_CHECKBOX(wxID_ANY, MapSettings::OnEdit) - EVT_CHOICE(wxID_ANY, MapSettings::OnEdit) - EVT_SPINCTRL(ID_MapNumPlayers, MapSettings::OnEditSpin) +BEGIN_EVENT_TABLE(MapSettingsControl, wxPanel) + EVT_TEXT(ID_MapName, MapSettingsControl::OnEdit) + EVT_TEXT(ID_MapDescription, MapSettingsControl::OnEdit) + EVT_CHECKBOX(wxID_ANY, MapSettingsControl::OnEdit) + EVT_CHOICE(wxID_ANY, MapSettingsControl::OnEdit) END_EVENT_TABLE(); -MapSettings::MapSettings(wxWindow* parent, ScenarioEditor& scenarioEditor) - : wxPanel(parent, wxID_ANY), m_ScenarioEditor(scenarioEditor) +MapSettingsControl::MapSettingsControl(wxWindow* parent, ScenarioEditor& scenarioEditor) + : wxPanel(parent, wxID_ANY), m_ScenarioEditor(scenarioEditor), m_MapSettings(scenarioEditor.GetMapSettings()) { wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Map settings")); SetSizer(sizer); } -void MapSettings::CreateWidgets() +void MapSettingsControl::CreateWidgets() { 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), _("Short description used on the map selection screen")), wxSizerFlags().Expand()); + sizer->AddSpacer(5); + wxArrayString gameTypes; gameTypes.Add(_T("conquest")); 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 wxCheckBox(this, ID_MapReveal, wxEmptyString)); 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 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)); - 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); - - wxArrayString civNames; - wxArrayString civCodes; - AtlasMessage::qGetCivData qryCiv; - qryCiv.Post(); - std::vector 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()); + sizer->AddSpacer(5); 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 wxCheckBox(this, ID_MapKW_Demo, wxEmptyString)); 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()); } -void MapSettings::ReadFromEngine() +void MapSettingsControl::ReadFromEngine() { AtlasMessage::qGetMapSettings qry; 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(); for (AtIter keyword = m_MapSettings["Keywords"]["item"]; keyword.defined(); ++keyword) @@ -228,37 +188,13 @@ void MapSettings::ReadFromEngine() else wxDynamicCast(FindWindow(ID_MapType), wxChoice)->SetSelection(0); - size_t numPlayers = m_MapSettings["PlayerData"]["item"].count(); - 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(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_MapTeams), wxCheckBox)->SetValue(wxString(m_MapSettings["LockTeams"]) == L"true"); 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); } -AtObj MapSettings::UpdateSettingsObject() +AtObj MapSettingsControl::UpdateSettingsObject() { 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()); - 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(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()) m_MapSettingsKeywords.insert(L"demo"); else @@ -303,6 +214,8 @@ AtObj MapSettings::UpdateSettingsObject() else m_MapSettingsKeywords.erase(L"hidden"); + m_MapSettings.setBool("LockTeams", wxDynamicCast(FindWindow(ID_MapTeams), wxCheckBox)->GetValue()); + AtObj keywords; keywords.set("@array", L""); for (std::set::iterator it = m_MapSettingsKeywords.begin(); it != m_MapSettingsKeywords.end(); ++it) @@ -312,7 +225,7 @@ AtObj MapSettings::UpdateSettingsObject() return m_MapSettings; } -void MapSettings::SendToEngine() +void MapSettingsControl::SendToEngine() { UpdateSettingsObject(); @@ -320,44 +233,40 @@ void MapSettings::SendToEngine() // 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) : Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), m_SimState(SimInactive) { - m_MapSettings = new MapSettings(this, m_ScenarioEditor); - m_MainSizer->Add(m_MapSettings, wxSizerFlags().Expand()); + m_MapSettingsCtrl = new MapSettingsControl(this, m_ScenarioEditor); + m_MainSizer->Add(m_MapSettingsCtrl, wxSizerFlags().Expand()); { wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Random map")); 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); 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(sizeChoice, wxSizerFlags().Expand()); gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Random seed")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT)); wxBoxSizer* seedSizer = new wxBoxSizer(wxHORIZONTAL); - seedSizer->Add(new wxTextCtrl(this, ID_RandomSeed, _T("0")), wxSizerFlags(1).Expand()); - seedSizer->Add(new wxButton(this, ID_RandomReseed, _("R"), wxDefaultPosition, wxSize(24, -1))); + 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(Tooltipped(new wxButton(this, ID_RandomReseed, _("R"), wxDefaultPosition, wxSize(24, -1)), _("New random seed"))); gridSizer->Add(seedSizer, wxSizerFlags().Expand()); sizer->Add(gridSizer, wxSizerFlags().Expand()); + sizer->AddSpacer(5); + sizer->Add(new wxButton(this, ID_RandomGenerate, _("Generate map")), wxSizerFlags().Expand()); m_MainSizer->Add(sizer, wxSizerFlags().Expand().Border(wxTOP, 16)); @@ -390,15 +299,27 @@ void MapSidebar::OnCollapse(wxCollapsiblePaneEvent& WXUNUSED(evt)) void MapSidebar::OnFirstDisplay() { - m_MapSettings->CreateWidgets(); - m_MapSettings->ReadFromEngine(); + // We do this here becase messages are used which requires simulation to be init'd + 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; qry.Post(); std::vector scripts = *qry.data; - wxChoice* scriptChoice = wxDynamicCast(FindWindow(ID_RandomScript), wxChoice); scriptChoice->Clear(); for (size_t i = 0; i < scripts.size(); ++i) @@ -414,7 +335,7 @@ void MapSidebar::OnFirstDisplay() void MapSidebar::OnMapReload() { - m_MapSettings->ReadFromEngine(); + m_MapSettingsCtrl->ReadFromEngine(); } void MapSidebar::UpdateSimButtons() @@ -518,7 +439,7 @@ void MapSidebar::OnRandomGenerate(wxCommandEvent& WXUNUSED(evt)) // TODO: this settings thing seems a bit of a mess, // since it's mixing data from three different sources - AtObj settings = m_MapSettings->UpdateSettingsObject(); + AtObj settings = m_MapSettingsCtrl->UpdateSettingsObject(); AtObj scriptSettings = dynamic_cast(scriptChoice->GetClientObject(scriptChoice->GetSelection()))->GetValue(); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.h index de1996577a..f150c98a08 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.h @@ -19,7 +19,7 @@ #include "wx/collpane.h" -class MapSettings; +class MapSettingsControl; class MapSidebar : public Sidebar { @@ -32,7 +32,7 @@ protected: virtual void OnFirstDisplay(); private: - MapSettings* m_MapSettings; + MapSettingsControl* m_MapSettingsCtrl; void OnCollapse(wxCollapsiblePaneEvent& evt); void OnSimPlay(wxCommandEvent& evt); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp index 878742f1bd..02fad2ae7f 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp @@ -20,9 +20,11 @@ #include "Object.h" #include "Buttons/ToolButton.h" +#include "General/Datafile.h" #include "ScenarioEditor/ScenarioEditor.h" #include "ScenarioEditor/Tools/Common/ObjectSettings.h" #include "ScenarioEditor/Tools/Common/MiscState.h" +#include "AtlasScript/ScriptInterface.h" #include "VariationControl.h" #include "GameInterface/Messages.h" @@ -32,6 +34,7 @@ enum { ID_ObjectType = 1, + ID_PlayerSelect, ID_SelectObject, ID_ToggleViewer, ID_ViewerWireframe, @@ -55,7 +58,7 @@ static wxWindow* Tooltipped(wxWindow* window, const wxString& tip) class ObjectBottomBar : public wxPanel { public: - ObjectBottomBar(wxWindow* parent, Observable& objectSettings, ObjectSidebarImpl* p); + ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEditor, Observable& objectSettings, Observable& mapSettings, ObjectSidebarImpl* p); void OnFirstDisplay(); @@ -76,6 +79,8 @@ private: ObjectSidebarImpl* p; + ScenarioEditor& m_ScenarioEditor; + 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_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); } @@ -219,27 +224,58 @@ END_EVENT_TABLE(); class PlayerComboBox : public wxComboBox { public: - PlayerComboBox(wxWindow* parent, wxArrayString& choices, Observable& objectSettings) - : wxComboBox(parent, -1, choices[objectSettings.GetPlayerID()], wxDefaultPosition, wxDefaultSize, choices, wxCB_READONLY) - , m_ObjectSettings(objectSettings) + PlayerComboBox(wxWindow* parent, Observable& objectSettings, Observable& mapSettings) + : wxComboBox(parent, ID_PlayerSelect, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY) + , 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: - ObservableScopedConnection m_Conn; + ObservableScopedConnection m_ObjectConn; Observable& m_ObjectSettings; + ObservableScopedConnection m_MapConn; + Observable& m_MapSettings; + wxArrayString m_Players; void OnObjectSettingsChange(const ObjectSettings& settings) { 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) { m_ObjectSettings.SetPlayerID(evt.GetInt()); - m_ObjectSettings.NotifyObserversExcept(m_Conn); + m_ObjectSettings.NotifyObserversExcept(m_ObjectConn); } DECLARE_EVENT_TABLE(); @@ -250,8 +286,8 @@ END_EVENT_TABLE(); ////////////////////////////////////////////////////////////////////////// -ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable& objectSettings, ObjectSidebarImpl* p) - : wxPanel(parent, wxID_ANY), p(p) +ObjectBottomBar::ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEditor, Observable& objectSettings, Observable& mapSettings, ObjectSidebarImpl* p) + : wxPanel(parent, wxID_ANY), p(p), m_ScenarioEditor(scenarioEditor) { m_ViewerWireframe = false; m_ViewerMove = false; @@ -276,12 +312,14 @@ ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable& o wxSizer* viewerAnimSizer = new wxStaticBoxSizer(wxVERTICAL, m_ViewerPanel, _("Animation")); - wxString animChoices[] = { - _T("idle"), _T("walk"), _T("run"), _T("melee"), _T("death"), _T("build"), - _T("gather_fruit"), _T("gather_grain"), _T("gather_meat"), _T("gather_tree"), - _T("gather_rock"), _T("gather_ore"), _T("gather_ruins"), _T("gather_treasure") - }; // TODO: this list should come from the actor - wxChoice* viewerAnimSelector = new wxChoice(m_ViewerPanel, ID_ViewerAnimation, wxDefaultPosition, wxDefaultSize, sizeof(animChoices)/sizeof(animChoices[0]), animChoices); + // TODO: this list should come from the actor + wxArrayString animChoices; + AtObj anims (Datafile::ReadList("animations")); + for (AtIter a = anims["item"]; a.defined(); ++a) + { + animChoices.Add(wxString(*a)); + } + wxChoice* viewerAnimSelector = new wxChoice(m_ViewerPanel, ID_ViewerAnimation, wxDefaultPosition, wxDefaultSize, animChoices); viewerAnimSelector->SetSelection(0); viewerAnimSizer->Add(viewerAnimSelector, wxSizerFlags().Expand()); @@ -301,19 +339,8 @@ ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable& o 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 + wxComboBox* playerSelect = new PlayerComboBox(this, objectSettings, mapSettings); playerVariationSizer->Add(playerSelect); wxWindow* variationSelect = new VariationControl(this, objectSettings); @@ -329,6 +356,20 @@ ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable& o 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 POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"wireframe", m_ViewerWireframe)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"walk", m_ViewerMove)); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp new file mode 100644 index 0000000000..80589913ef --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.cpp @@ -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 . + */ + +#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(GetPage(evt.GetSelection()))->OnDisplay(); + } + evt.Skip(); + } + +private: + ScenarioEditor& m_ScenarioEditor; + std::vector 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 m_PlayerControls; + Observable& 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 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(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(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(); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.h new file mode 100644 index 0000000000..6d814de383 --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.h @@ -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 . + */ + +#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(); +}; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp index ca05aa9d8e..87ea33914f 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp @@ -20,10 +20,10 @@ #include "Terrain.h" #include "Buttons/ToolButton.h" -#include "General/Datafile.h" #include "ScenarioEditor/ScenarioEditor.h" #include "ScenarioEditor/Tools/Common/Brushes.h" #include "ScenarioEditor/Tools/Common/MiscState.h" +#include "AtlasScript/ScriptInterface.h" #include "GameInterface/Messages.h" @@ -138,12 +138,15 @@ void TerrainSidebar::OnResizeMap(wxCommandEvent& WXUNUSED(evt)) wxArrayString sizeNames; std::vector sizeTiles; - AtObj sizes(Datafile::ReadList("mapsizes")); - for (AtIter s = sizes["size"]; s.defined(); ++s) + // Load the map sizes list + 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; - wxString(s["@tiles"]).ToLong(&tiles); - sizeNames.Add(wxString(s["@name"])); + wxString(s["Tiles"]).ToLong(&tiles); + sizeNames.Add(wxString(s["Name"])); sizeTiles.push_back((size_t)tiles); }