1
0
forked from 0ad/0ad

Adds AI control to Atlas player panel

Adds camera control to Atlas player panel
Changes map reader to handle per-player starting camera position. See
#55
Adds entity name filter to Atlas object panel
Fixes bug in Atlas map settings (caused crash when object panel was not
loaded)

This was SVN commit r9617.
This commit is contained in:
historic_bruno 2011-06-13 23:32:41 +00:00
parent 7e1cbf6ece
commit 3e4d74480d
18 changed files with 412 additions and 77 deletions

View File

@ -25,6 +25,7 @@ Player.prototype.Init = function()
this.diplomacy = []; // array of diplomatic stances for this player with respect to other players (including self)
this.conquestCriticalEntitiesCount = 0; // number of owned units with ConquestCritical class
this.phase = "village";
this.startCam = undefined;
};
Player.prototype.SetPlayerID = function(id)
@ -225,6 +226,21 @@ Player.prototype.SetPhase = function(p)
this.phase = p;
};
Player.prototype.GetStartingCamera = function()
{
return this.startCam;
}
Player.prototype.SetStartingCamera = function(pos)
{
this.startCam = pos;
}
Player.prototype.HasStartingCamera = function()
{
return (this.startCam !== undefined);
}
/**
* Keep track of population effects of all entities that
* become owned or unowned by this player

View File

@ -128,6 +128,11 @@ function LoadPlayerSettings(settings)
{ //Set default
player.SetDiplomacy(diplomacy);
}
if (getSetting(pData, pDefs, "StartingCamera") !== undefined)
{
player.SetStartingCamera(getSetting(pData, pDefs, "StartingCamera"));
}
}
else
{ // Copy gaia data from defaults

View File

@ -74,8 +74,7 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
pTrigMan = pTrigMan_;
pSimulation2 = pSimulation2_;
m_PlayerID = playerID_;
m_CameraStartupTarget = INVALID_ENTITY;
m_StartingCameraTarget = INVALID_ENTITY;
filename_xml = pathname.ChangeExtension(L".xml");
@ -146,8 +145,7 @@ void CMapReader::LoadRandomMap(const CStrW& scriptFile, const CScriptValRooted&
pTrigMan = pTrigMan_;
pSimulation2 = pSimulation2_;
m_PlayerID = playerID_;
m_CameraStartupTarget = INVALID_ENTITY;
m_StartingCameraTarget = INVALID_ENTITY;
// delete all existing entities
if (pSimulation2)
@ -284,13 +282,24 @@ int CMapReader::ApplyData()
if (pLightEnv)
*pLightEnv = m_LightEnv;
if (pGameView)
{
pGameView->ResetCameraTarget(pGameView->GetCamera()->GetFocus());
CmpPtr<ICmpPlayerManager> cmpPlayerManager(*pSimulation2, SYSTEM_ENTITY);
if (m_CameraStartupTarget != INVALID_ENTITY)
if (pGameView && !cmpPlayerManager.null())
{
// Default to global camera (with constraints)
pGameView->ResetCameraTarget(pGameView->GetCamera()->GetFocus());
CmpPtr<ICmpPlayer> cmpPlayer(*pSimulation2, cmpPlayerManager->GetPlayerByID(m_PlayerID));
if (!cmpPlayer.null() && cmpPlayer->HasStartingCamera())
{
CmpPtr<ICmpPosition> cmpPosition(*pSimulation2, m_CameraStartupTarget);
// Use player starting camera
CFixedVector3D pos = cmpPlayer->GetStartingCamera();
pGameView->ResetCameraTarget(CVector3D(pos.X.ToFloat(), pos.Y.ToFloat(), pos.Z.ToFloat()));
}
else if (m_StartingCameraTarget != INVALID_ENTITY)
{
// Point camera at entity
CmpPtr<ICmpPosition> cmpPosition(*pSimulation2, m_StartingCameraTarget);
if (!cmpPosition.null())
{
CFixedVector3D pos = cmpPosition->GetPosition();
@ -678,6 +687,7 @@ void CXMLReader::ReadEnvironment(XMBElement parent)
void CXMLReader::ReadCamera(XMBElement parent)
{
// defaults if we don't find player starting camera
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
EL(declination);
@ -849,7 +859,7 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
XMBElementList entities = parent.GetChildNodes();
CSimulation2& sim = *m_MapReader.pSimulation2;
CmpPtr<ICmpPlayerManager> cmpPlayerManager(sim.GetSimContext(), SYSTEM_ENTITY);
CmpPtr<ICmpPlayerManager> cmpPlayerManager(sim, SYSTEM_ENTITY);
while (entity_idx < entities.Count)
{
@ -907,14 +917,13 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
}
entity_id_t ent = sim.AddEntity(TemplateName, EntityUid);
if (ent == INVALID_ENTITY)
{
entity_id_t player = cmpPlayerManager->GetPlayerByID(PlayerID);
if (ent == INVALID_ENTITY || player == INVALID_ENTITY)
{ // Don't add entities with invalid player IDs
LOGERROR(L"Failed to load entity template '%ls'", TemplateName.c_str());
}
else if (cmpPlayerManager->GetPlayerByID(PlayerID) != INVALID_ENTITY)
{ // Don't add entities with invalid player IDs
// TODO: Is a warning OK or should it just silently fail?
else
{
CmpPtr<ICmpPosition> cmpPosition(sim, ent);
if (!cmpPosition.null())
{
@ -927,13 +936,10 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
if (!cmpOwner.null())
cmpOwner->SetOwner(PlayerID);
if (boost::algorithm::ends_with(TemplateName, L"civil_centre"))
if (PlayerID == m_MapReader.m_PlayerID && (boost::algorithm::ends_with(TemplateName, L"civil_centre") || m_MapReader.m_StartingCameraTarget == INVALID_ENTITY))
{
// HACK: we special-case civil centre files to initialise the camera.
// This ought to be based on a more generic mechanism for indicating
// per-player camera start locations.
if (m_MapReader.m_CameraStartupTarget == INVALID_ENTITY && PlayerID == m_MapReader.m_PlayerID && !cmpPosition.null())
m_MapReader.m_CameraStartupTarget = ent;
// Focus on civil centre or first entity owned by player
m_MapReader.m_StartingCameraTarget = ent;
}
}
@ -1201,6 +1207,9 @@ int CMapReader::ParseEntities()
if (!pSimulation2->GetScriptInterface().GetProperty(m_MapData.get(), "entities", entities))
LOGWARNING(L"CMapReader::ParseEntities() failed to get 'entities' property");
CSimulation2& sim = *pSimulation2;
CmpPtr<ICmpPlayerManager> cmpPlayerManager(sim, SYSTEM_ENTITY);
size_t entity_idx = 0;
size_t num_entities = entities.size();
@ -1212,33 +1221,33 @@ int CMapReader::ParseEntities()
currEnt = entities[entity_idx];
entity_id_t ent = pSimulation2->AddEntity(currEnt.templateName, currEnt.entityID);
// Check that entity was added
if (ent == INVALID_ENTITY)
{
entity_id_t player = cmpPlayerManager->GetPlayerByID(currEnt.playerID);
if (ent == INVALID_ENTITY || player == INVALID_ENTITY)
{ // Don't add entities with invalid player IDs
LOGERROR(L"Failed to load entity template '%ls'", currEnt.templateName.c_str());
}
else
{
CmpPtr<ICmpPosition> cmpPosition(*pSimulation2, ent);
CFixedVector3D Position;
Position.X = fixed::FromFloat(currEnt.positionX);
Position.Z = fixed::FromFloat(currEnt.positionZ);
CmpPtr<ICmpPosition> cmpPosition(sim, ent);
if (!cmpPosition.null())
{
cmpPosition->JumpTo(entity_pos_t::FromFloat(currEnt.positionX), entity_pos_t::FromFloat(currEnt.positionZ));
cmpPosition->JumpTo(Position.X, Position.Z);
cmpPosition->SetYRotation(entity_angle_t::FromFloat(currEnt.orientationY));
// TODO: other parts of the position
}
CmpPtr<ICmpOwnership> cmpOwner(*pSimulation2, ent);
CmpPtr<ICmpOwnership> cmpOwner(sim, ent);
if (!cmpOwner.null())
cmpOwner->SetOwner(currEnt.playerID);
if (boost::algorithm::ends_with(currEnt.templateName, L"civil_centre"))
if (currEnt.playerID == m_PlayerID && (boost::algorithm::ends_with(currEnt.templateName, L"civil_centre") || m_StartingCameraTarget == INVALID_ENTITY))
{
// HACK: we special-case civil centre files to initialise the camera.
// This ought to be based on a more generic mechanism for indicating
// per-player camera start locations.
if (m_CameraStartupTarget == INVALID_ENTITY && currEnt.playerID == m_PlayerID && !cmpPosition.null())
m_CameraStartupTarget = ent;
// Focus on civil centre or first entity owned by player
m_StartingCameraTarget = currEnt.entityID;
}
}
@ -1327,7 +1336,7 @@ int CMapReader::ParseEnvironment()
int CMapReader::ParseCamera()
{
// parse camera settings from map data
// defaults if we don't find camera
// defaults if we don't find player starting camera
float declination = DEGTORAD(30.f), rotation = DEGTORAD(-45.f);
CVector3D translation = CVector3D(100, 150, -100);

View File

@ -137,7 +137,8 @@ private:
VfsPath filename_xml;
bool only_xml;
u32 file_format_version;
entity_id_t m_CameraStartupTarget;
entity_id_t m_StartingCameraTarget;
CVector3D m_StartingCamera;
// UnpackTerrain generator state
size_t cur_terrain_tex;

View File

@ -625,3 +625,16 @@ std::string CSimulation2::ReadJSON(VfsPath path)
return data;
}
std::string CSimulation2::GetAIData()
{
ScriptInterface& scriptInterface = GetScriptInterface();
std::vector<CScriptValRooted> aiData = ICmpAIManager::GetAIs(scriptInterface);
// Build single JSON string with array of AI data
CScriptValRooted ais;
if (!scriptInterface.Eval("({})", ais) || !scriptInterface.SetProperty(ais.get(), "AIData", aiData))
return std::string();
return scriptInterface.StringifyJSON(ais.get());
}

View File

@ -233,6 +233,13 @@ public:
*/
std::string GetMapSizes();
/**
* Get AI data
*
* @return string containing JSON format data
*/
std::string GetAIData();
private:
CSimulation2Impl* m;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* 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
@ -19,6 +19,7 @@
#include "ICmpPlayer.h"
#include "maths/FixedVector3D.h"
#include "simulation2/system/InterfaceScripted.h"
#include "simulation2/scripting/ScriptComponent.h"
@ -51,6 +52,16 @@ public:
{
return m_Script.Call<CColor>("GetColour");
}
virtual CFixedVector3D GetStartingCamera()
{
return m_Script.Call<CFixedVector3D>("GetStartingCamera");
}
virtual bool HasStartingCamera()
{
return m_Script.Call<bool>("HasStartingCamera");
}
};
REGISTER_COMPONENT_SCRIPT_WRAPPER(PlayerScripted)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* 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
@ -21,6 +21,7 @@
#include "simulation2/system/Interface.h"
struct CColor;
class CFixedVector3D;
/**
* Player data.
@ -35,6 +36,9 @@ public:
virtual void SetColour(u8 r, u8 g, u8 b) = 0;
virtual CColor GetColour() = 0;
virtual CFixedVector3D GetStartingCamera() = 0;
virtual bool HasStartingCamera() = 0;
DECLARE_INTERFACE_TYPE(Player)
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* 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
@ -153,6 +153,7 @@ public:
void set(const char* key, const wchar_t* value);
void set(const char* key, AtObj& data);
void setBool(const char* key, bool value);
void setDouble(const char* key, double value);
void setInt(const char* key, int value);
void setString(const wchar_t* value);
void addOverlay(AtObj& data);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* 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
@ -175,6 +175,19 @@ void AtObj::setBool(const char* key, bool value)
p = p->setChild(key, AtNode::Ptr(o));
}
void AtObj::setDouble(const char* key, double value)
{
std::wstringstream str;
str << value;
AtNode* o = new AtNode(str.str().c_str());
o->children.insert(AtNode::child_pairtype("@number", AtNode::Ptr(new AtNode())));
if (!p)
p = new AtNode();
p = p->setChild(key, AtNode::Ptr(o));
}
void AtObj::setInt(const char* key, int value)
{
std::wstringstream str;

View File

@ -448,15 +448,9 @@ void MapSidebar::OnRandomGenerate(wxCommandEvent& WXUNUSED(evt))
wxChoice* sizeChoice = wxDynamicCast(FindWindow(ID_RandomSize), wxChoice);
wxString size;
size << (intptr_t)sizeChoice->GetClientData(sizeChoice->GetSelection());
AtObj sizeObj;
sizeObj.setString(size);
sizeObj.set("@number", L"");
settings.set("Size", sizeObj);
settings.setInt("Size", wxAtoi(size));
AtObj seedObj;
seedObj.setString(wxDynamicCast(FindWindow(ID_RandomSeed), wxTextCtrl)->GetValue());
seedObj.set("@number", L"");
settings.set("Seed", seedObj);
settings.setInt("Seed", wxAtoi(wxDynamicCast(FindWindow(ID_RandomSeed), wxTextCtrl)->GetValue()));
std::string json = AtlasObject::SaveToJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), settings);

View File

@ -34,6 +34,7 @@
enum
{
ID_ObjectType = 1,
ID_ObjectFilter,
ID_PlayerSelect,
ID_SelectObject,
ID_ToggleViewer,
@ -110,6 +111,12 @@ struct ObjectSidebarImpl
ObjectSidebar::ObjectSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), p(new ObjectSidebarImpl())
{
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(new wxStaticText(this, wxID_ANY, _("Filter")), wxSizerFlags().Align(wxALIGN_CENTER));
wxTextCtrl* objectFilter = new wxTextCtrl(this, ID_ObjectFilter);
sizer->Add(objectFilter, wxSizerFlags().Expand().Proportion(1));
m_MainSizer->Add(sizer, wxSizerFlags().Expand());
wxArrayString strings;
strings.Add(_("Entities"));
strings.Add(_("Actors (all)"));
@ -158,20 +165,27 @@ void ObjectSidebar::OnFirstDisplay()
qry.Post();
p->m_Objects = *qry.objects;
// Display first group of objects
SetObjectFilter(0);
FilterObjects();
}
void ObjectSidebar::SetObjectFilter(int type)
void ObjectSidebar::FilterObjects()
{
int filterType = wxDynamicCast(FindWindow(ID_ObjectType), wxChoice)->GetSelection();
wxString filterName = wxDynamicCast(FindWindow(ID_ObjectFilter), wxTextCtrl)->GetValue();
p->m_ObjectListBox->Freeze();
p->m_ObjectListBox->Clear();
for (std::vector<AtlasMessage::sObjectsListItem>::iterator it = p->m_Objects.begin(); it != p->m_Objects.end(); ++it)
{
if (it->type == type)
if (it->type == filterType)
{
wxString id = it->id.c_str();
wxString name = it->name.c_str();
p->m_ObjectListBox->Append(name, new wxStringClientData(id));
if (name.Lower().Find(filterName.Lower()) != wxNOT_FOUND)
{
p->m_ObjectListBox->Append(name, new wxStringClientData(id));
}
}
}
p->m_ObjectListBox->Thaw();
@ -185,10 +199,9 @@ void ObjectSidebar::ToggleViewer(wxCommandEvent& WXUNUSED(evt))
m_ScenarioEditor.GetToolManager().SetCurrentTool(_T("ActorViewerTool"), NULL);
}
void ObjectSidebar::OnSelectType(wxCommandEvent& evt)
void ObjectSidebar::OnSelectType(wxCommandEvent& WXUNUSED(evt))
{
// Switch between displayed lists of objects (e.g. entities vs actors)
SetObjectFilter(evt.GetSelection());
FilterObjects();
}
void ObjectSidebar::OnSelectObject(wxCommandEvent& evt)
@ -213,8 +226,14 @@ void ObjectSidebar::OnSelectObject(wxCommandEvent& evt)
}
}
void ObjectSidebar::OnSelectFilter(wxCommandEvent& WXUNUSED(evt))
{
FilterObjects();
}
BEGIN_EVENT_TABLE(ObjectSidebar, Sidebar)
EVT_CHOICE(ID_ObjectType, ObjectSidebar::OnSelectType)
EVT_TEXT(ID_ObjectFilter, ObjectSidebar::OnSelectFilter)
EVT_LISTBOX(ID_SelectObject, ObjectSidebar::OnSelectObject)
EVT_BUTTON(ID_ToggleViewer, ObjectSidebar::ToggleViewer)
END_EVENT_TABLE();
@ -256,7 +275,7 @@ private:
// Adjust displayed number of players
Clear();
size_t numPlayers = settings["PlayerData"]["item"].count();
for (size_t i = 0; i <= numPlayers; ++i)
for (size_t i = 0; i <= numPlayers && i < m_Players.Count(); ++i)
{
Append(m_Players[i]);
}

View File

@ -25,7 +25,7 @@ class ObjectSidebar : public Sidebar
public:
ObjectSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
~ObjectSidebar();
void SetObjectFilter(int type);
void FilterObjects();
protected:
virtual void OnFirstDisplay();
@ -35,6 +35,7 @@ private:
void ToggleViewer(wxCommandEvent& evt);
void OnSelectType(wxCommandEvent& evt);
void OnSelectFilter(wxCommandEvent& evt);
void OnSelectObject(wxCommandEvent& evt);
ObjectSidebarImpl* p;

View File

@ -21,7 +21,6 @@
#include "AtlasObject/AtlasObject.h"
#include "AtlasScript/ScriptInterface.h"
#include "GameInterface/Messages.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "wx/choicebk.h"
@ -34,21 +33,12 @@ enum
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;
ID_PlayerColour,
ID_PlayerHuman,
ID_PlayerAI,
ID_CameraSet,
ID_CameraView,
ID_CameraClear
};
// TODO: Some of these helper things should be moved out of this file
@ -71,6 +61,8 @@ public:
: wxPanel(parent, wxID_ANY), m_ScenarioEditor(scenarioEditor), m_Name(name), m_PlayerID(playerID)
{
m_Controls.page = this;
Freeze();
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
@ -93,6 +85,10 @@ public:
wxButton* colourButton = new wxButton(this, ID_PlayerColour);
gridSizer->Add(Tooltipped(colourButton, _("Set player colour")), wxSizerFlags(1).Expand().Align(wxALIGN_RIGHT));
m_Controls.colour = colourButton;
gridSizer->Add(new wxStaticText(this, wxID_ANY, _("Default AI")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
wxChoice* aiChoice = new wxChoice(this, wxID_ANY);
gridSizer->Add(Tooltipped(aiChoice, _("Select default AI")), wxSizerFlags(1).Expand().Align(wxALIGN_RIGHT));
m_Controls.ai = aiChoice;
playerInfoSizer->Add(gridSizer, wxSizerFlags(1).Expand());
sizer->Add(playerInfoSizer, wxSizerFlags().Expand());
@ -142,7 +138,6 @@ public:
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();
@ -150,6 +145,20 @@ public:
sizer->Add(diplomacySizer, wxSizerFlags().Expand());
/////////////////////////////////////////////////////////////////////////
// Camera
wxStaticBoxSizer* cameraSizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Starting Camera"));
wxButton* cameraSet = new wxButton(this, ID_CameraSet, _("Set"));
cameraSizer->Add(Tooltipped(cameraSet, _("Set player camera to this view")), wxSizerFlags(1));
wxButton* cameraView = new wxButton(this, ID_CameraView, _("View"));
cameraView->Enable(false);
cameraSizer->Add(Tooltipped(cameraView, _("View the player camera")), wxSizerFlags(1));
wxButton* cameraClear = new wxButton(this, ID_CameraClear, _("Clear"));
cameraClear->Enable(false);
cameraSizer->Add(Tooltipped(cameraClear, _("Clear player camera")), wxSizerFlags(1));
sizer->Add(cameraSizer, wxSizerFlags().Expand());
Layout();
Thaw();
@ -174,6 +183,26 @@ public:
return m_PlayerID;
}
bool IsCameraDefined()
{
return m_CameraDefined;
}
sCameraInfo GetCamera()
{
return m_Camera;
}
void SetCamera(sCameraInfo info, bool isDefined = true)
{
m_Camera = info;
m_CameraDefined = isDefined;
// Enable/disable controls
wxDynamicCast(FindWindow(ID_CameraView), wxButton)->Enable(isDefined);
wxDynamicCast(FindWindow(ID_CameraClear), wxButton)->Enable(isDefined);
}
private:
void OnColour(wxCommandEvent& evt)
{
@ -193,10 +222,35 @@ private:
}
}
ScenarioEditor& m_ScenarioEditor;
void OnCameraSet(wxCommandEvent& evt)
{
AtlasMessage::qGetView qryView;
qryView.Post();
SetCamera(qryView.info, true);
// Pass event on to next handler
evt.Skip();
}
void OnCameraView(wxCommandEvent& WXUNUSED(evt))
{
POST_MESSAGE(SetView, (m_Camera));
}
void OnCameraClear(wxCommandEvent& evt)
{
SetCamera(sCameraInfo(), false);
// Pass event on to next handler
evt.Skip();
}
sCameraInfo m_Camera;
bool m_CameraDefined;
wxString m_Name;
size_t m_PlayerID;
ScenarioEditor& m_ScenarioEditor;
PlayerPageControls m_Controls;
DECLARE_EVENT_TABLE();
@ -204,6 +258,9 @@ private:
BEGIN_EVENT_TABLE(PlayerNotebookPage, wxPanel)
EVT_BUTTON(ID_PlayerColour, PlayerNotebookPage::OnColour)
EVT_BUTTON(ID_CameraSet, PlayerNotebookPage::OnCameraSet)
EVT_BUTTON(ID_CameraView, PlayerNotebookPage::OnCameraView)
EVT_BUTTON(ID_CameraClear, PlayerNotebookPage::OnCameraClear)
END_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
@ -331,6 +388,8 @@ private:
BEGIN_EVENT_TABLE(PlayerSettingsControl, wxPanel)
EVT_BUTTON(ID_PlayerColour, PlayerSettingsControl::OnEdit)
EVT_BUTTON(ID_CameraSet, PlayerSettingsControl::OnEdit)
EVT_BUTTON(ID_CameraClear, PlayerSettingsControl::OnEdit)
EVT_CHOICE(wxID_ANY, PlayerSettingsControl::OnEdit)
EVT_TEXT(wxID_ANY, PlayerSettingsControl::OnEdit)
EVT_SPINCTRL(ID_NumPlayers, PlayerSettingsControl::OnNumPlayersChanged)
@ -382,6 +441,16 @@ void PlayerSettingsControl::CreateWidgets()
civCodes.Add(wxString(civ["Code"]));
}
// Load AI data
ArrayOfAIData ais(AIData::CompareAIData);
AtlasMessage::qGetAIData qryAI;
qryAI.Post();
AtObj aiData = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qryAI.data);
for (AtIter a = aiData["AIData"]["item"]; a.defined(); ++a)
{
ais.Add(new AIData(wxString(a["id"]), wxString(a["data"]["name"])));
}
// Create player pages
AtIter player = m_PlayerDefaults["item"];
++player; // Skip gaia
@ -395,6 +464,14 @@ void PlayerSettingsControl::CreateWidgets()
wxChoice* civChoice = controls.civ;
for (size_t j = 0; j < civNames.Count(); ++j)
civChoice->Append(civNames[j], new wxStringClientData(civCodes[j]));
civChoice->SetSelection(0);
// Populate ai choice box
wxChoice* aiChoice = controls.ai;
aiChoice->Append(_("<None>"), new wxStringClientData());
for (size_t j = 0; j < ais.Count(); ++j)
aiChoice->Append(ais[j]->GetName(), new wxStringClientData(ais[j]->GetID()));
aiChoice->SetSelection(0);
}
m_InGUIUpdate = false;
@ -418,6 +495,10 @@ void PlayerSettingsControl::ReadFromEngine()
// Prevent error if there's no map settings to parse
m_MapSettings = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qry.settings);
}
else
{ // Use blank object, it will be created next
m_MapSettings = AtObj();
}
AtIter player = m_MapSettings["PlayerData"]["item"];
size_t numPlayers = player.count();
@ -480,6 +561,31 @@ void PlayerSettingsControl::ReadFromEngine()
}
controls.colour->SetBackgroundColour(colour);
// player type
wxString aiID;
if (player["AI"].defined())
aiID = wxString(player["AI"]);
else
aiID = wxString(playerDefs["AI"]);
choice = controls.ai;
if (!aiID.empty())
{ // AI
for (size_t j = 0; j < choice->GetCount(); ++j)
{
wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(j));
if (str->GetData() == aiID)
{
choice->SetSelection(j);
break;
}
}
}
else
{ // Human
choice->SetSelection(0);
}
// resources
AtObj resObj = *player["Resources"];
if (resObj.defined() && resObj["food"].defined())
@ -514,6 +620,20 @@ void PlayerSettingsControl::ReadFromEngine()
else
controls.team->SetSelection(0);
// camera
if (player["StartingCamera"].defined())
{
AtObj cam = *player["StartingCamera"];
sCameraInfo info;
info.pX = wxAtof(*cam["x"]);
info.pY = wxAtof(*cam["y"]);
info.pZ = wxAtof(*cam["z"]);
controls.page->SetCamera(info, true);
}
else
controls.page->SetCamera(sCameraInfo(), false);
}
m_InGUIUpdate = false;
@ -556,6 +676,18 @@ AtObj PlayerSettingsControl::UpdateSettingsObject()
clrObj.setInt("b", (int)colour.Blue());
player.set("Colour", clrObj);
// player type
choice = controls.ai;
if (choice->GetSelection() > 0)
{ // ai - get id
wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(choice->GetSelection()));
player.set("AI", str->GetData());
}
else
{ // human
player.set("AI", _T(""));
}
// resources
AtObj resObj;
if (controls.food->GetValue() > 0)
@ -581,6 +713,17 @@ AtObj PlayerSettingsControl::UpdateSettingsObject()
player.setInt("Team", choice->GetSelection() - 1);
}
// camera
if (controls.page->IsCameraDefined())
{
sCameraInfo cam = controls.page->GetCamera();
AtObj camObj;
camObj.setDouble("x", cam.pX);
camObj.setDouble("y", cam.pY);
camObj.setDouble("z", cam.pZ);
player.set("StartingCamera", camObj);
}
players.add("item", player);
if (oldPlayer.defined())
++oldPlayer;

View File

@ -17,8 +17,13 @@
#include "../Common/Sidebar.h"
#include "GameInterface/Messages.h"
#include "wx/collpane.h"
using namespace AtlasMessage;
class PlayerNotebookPage;
class PlayerSettingsControl;
class PlayerSidebar : public Sidebar
@ -40,3 +45,50 @@ private:
DECLARE_EVENT_TABLE();
};
// Controls present on each player page
struct PlayerPageControls
{
PlayerNotebookPage* page;
wxTextCtrl* name;
wxChoice* civ;
wxButton* colour;
wxSpinCtrl* food;
wxSpinCtrl* wood;
wxSpinCtrl* stone;
wxSpinCtrl* metal;
wxSpinCtrl* pop;
wxChoice* team;
wxChoice* ai;
};
// Definitions for keeping AI data sorted
class AIData
{
public:
AIData(const wxString& id, const wxString& name)
: m_ID(id), m_Name(name)
{
}
wxString& GetID()
{
return m_ID;
}
wxString& GetName()
{
return m_Name;
}
static int CompareAIData(AIData* ai1, AIData* ai2)
{
return ai1->m_Name.Cmp(ai2->m_Name);
}
private:
wxString m_ID;
wxString m_Name;
};
WX_DEFINE_SORTED_ARRAY(AIData*, ArrayOfAIData);

View File

@ -219,5 +219,32 @@ MESSAGEHANDLER(LookAt)
camera.UpdateFrustum();
}
QUERYHANDLER(GetView)
{
CVector3D focus = g_Game->GetView()->GetCamera()->GetFocus();
sCameraInfo info;
info.pX = focus.X;
info.pY = focus.Y;
info.pZ = focus.Z;
// TODO: Rotation
msg->info = info;
}
MESSAGEHANDLER(SetView)
{
if (g_Game->GetView()->GetCinema()->IsPlaying())
return;
CGameView* view = g_Game->GetView();
view->ResetCameraTarget(view->GetCamera()->GetFocus());
sCameraInfo cam = msg->info;
view->ResetCameraTarget(CVector3D(cam.pX, cam.pY, cam.pZ));
}
}

View File

@ -35,4 +35,9 @@ QUERYHANDLER(GetPlayerDefaults)
msg->defaults = g_Game->GetSimulation2()->GetPlayerDefaults();
}
QUERYHANDLER(GetAIData)
{
msg->data = g_Game->GetSimulation2()->GetAIData();
}
}

View File

@ -183,6 +183,11 @@ QUERY(GetPlayerDefaults,
((std::string, defaults))
);
QUERY(GetAIData,
,
((std::string, data))
);
//////////////////////////////////////////////////////////////////////////
MESSAGE(RenderStyle,
@ -362,6 +367,15 @@ MESSAGE(LookAt,
MESSAGE(CameraReset, );
QUERY(GetView,
,
((sCameraInfo, info))
);
MESSAGE(SetView,
((sCameraInfo, info))
);
//////////////////////////////////////////////////////////////////////////
#ifndef MESSAGES_SKIP_STRUCTS