# Atlas updates: better unit ownership control; fixed bottom-bar display; fixed iterator problem in undo; renamed 'd' to 'msg' for consistency

This was SVN commit r3836.
This commit is contained in:
Ykkrosh 2006-05-04 02:44:03 +00:00
parent 37663d86fb
commit 9e74e3a077
25 changed files with 406 additions and 129 deletions

View File

@ -51,6 +51,9 @@ public:
// Set player ID of this unit
void SetPlayerID(int id);
// Get player ID of this unit
int GetPlayerID() { return m_PlayerID; }
int GetID() const { return m_ID; }
void SetID(int id) { m_ID = id; }

View File

@ -0,0 +1,28 @@
#ifndef OBSERVABLE_H__
#define OBSERVABLE_H__
#include <boost/signals.hpp>
#include <boost/bind.hpp>
typedef boost::signals::connection ObservableConnection;
template <typename T> class Observable : public T
{
public:
template<typename C> ObservableConnection RegisterObserver(int order, void (C::*callback) (const T&), C* obj)
{
return m_Signal.connect(order, boost::bind(std::mem_fun(callback), obj, _1));
}
void RemoveObserver(ObservableConnection handle)
{
handle.disconnect();
}
void NotifyObservers()
{
m_Signal(*this);
}
private:
boost::signal<void (const T&)> m_Signal;
};
#endif // OBSERVABLE_H__

View File

@ -34,6 +34,8 @@
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/signals.hpp>
#include <boost/bind.hpp>
// Nicer memory-leak detection:
#ifdef _DEBUG

View File

@ -36,13 +36,16 @@ protected:
if (event.GetSelection() != -1)
newPage = wxDynamicCast(GetPage(event.GetSelection()), Sidebar);
if (oldPage)
oldPage->OnSwitchAway();
if (newPage)
newPage->OnSwitchTo();
if (m_Splitter->IsSplit())
{
wxWindow* bottom;
if (newPage && NULL != (bottom = newPage->GetBottomBar(m_Splitter)))
if (newPage && NULL != (bottom = newPage->GetBottomBar()))
{
m_Splitter->ReplaceWindow(m_Splitter->GetWindow2(), bottom);
}
@ -54,7 +57,7 @@ protected:
else
{
wxWindow* bottom;
if (newPage && NULL != (bottom = newPage->GetBottomBar(m_Splitter)))
if (newPage && NULL != (bottom = newPage->GetBottomBar()))
{
m_Splitter->SplitHorizontally(m_Splitter->GetWindow1(), bottom);
}
@ -104,14 +107,24 @@ void SectionLayout::Build()
{
// TODO: wxWidgets bug (http://sourceforge.net/tracker/index.php?func=detail&aid=1298803&group_id=9863&atid=109863)
// - pressing menu keys (e.g. alt+f) with notebook tab focussed causes application to freeze
wxNotebook* sidebar = new SidebarNotebook(m_HorizSplitter, m_VertSplitter);
sidebar->AddPage(new MapSidebar(sidebar), _("Map"), false);
sidebar->AddPage(new TerrainSidebar(sidebar), _("Terrain"), false);
sidebar->AddPage(new ObjectSidebar(sidebar), _("Object"), false);
SidebarNotebook* sidebarBook = new SidebarNotebook(m_HorizSplitter, m_VertSplitter);
Sidebar* sidebar;
#define ADD_SIDEBAR(classname, label) \
sidebar = new classname(sidebarBook, m_VertSplitter); \
if (sidebar->GetBottomBar()) \
sidebar->GetBottomBar()->Show(false); \
sidebarBook->AddPage(sidebar, _(label));
ADD_SIDEBAR(MapSidebar, "Map");
ADD_SIDEBAR(TerrainSidebar, "Terrain");
ADD_SIDEBAR(ObjectSidebar, "Object");
#undef ADD_SIDEBAR
m_VertSplitter->SetDefaultSashPosition(-165);
m_VertSplitter->Initialize(m_Canvas);
m_HorizSplitter->SetDefaultSashPosition(200);
m_HorizSplitter->SplitVertically(sidebar, m_VertSplitter);
m_HorizSplitter->SplitVertically(sidebarBook, m_VertSplitter);
}

View File

@ -4,23 +4,27 @@
IMPLEMENT_DYNAMIC_CLASS(Sidebar, wxPanel)
Sidebar::Sidebar(wxWindow* parent)
: wxPanel(parent), m_AlreadyDisplayed(false)
Sidebar::Sidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: wxPanel(sidebarContainer), m_BottomBar(NULL), m_AlreadyDisplayed(false)
{
m_MainSizer = new wxBoxSizer(wxVERTICAL);
SetSizer(m_MainSizer);
}
wxWindow* Sidebar::GetBottomBar(wxWindow* WXUNUSED(parent))
void Sidebar::OnSwitchAway()
{
return NULL;
if (m_BottomBar)
m_BottomBar->Show(false);
}
void Sidebar::OnSwitchTo()
{
if (m_AlreadyDisplayed)
return;
if (! m_AlreadyDisplayed)
{
m_AlreadyDisplayed = true;
OnFirstDisplay();
}
if (m_BottomBar)
m_BottomBar->Show(true);
}

View File

@ -7,20 +7,21 @@ class Sidebar : public wxPanel
public:
Sidebar() {}
Sidebar(wxWindow* parent);
Sidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
void OnSwitchAway();
void OnSwitchTo();
virtual wxWindow* GetBottomBar(wxWindow* parent);
// called whenever the bottom bar is made visible; should usually be
// lazily constructed, then cached forever (to maximise responsiveness)
wxWindow* GetBottomBar() { return m_BottomBar; }
protected:
wxSizer* m_MainSizer; // vertical box sizer, used by most sidebars
wxWindow* m_BottomBar; // window that goes at the bottom of the screen; may be NULL
virtual void OnFirstDisplay() {}
// should be overridden when sidebars need to do expensive construction,
// so it can be delayed until it is required
// so it can be delayed until it is required;
private:
bool m_AlreadyDisplayed;

View File

@ -69,8 +69,8 @@ static void GenerateRMS(void* data)
//////////////////////////////////////////////////////////////////////////
MapSidebar::MapSidebar(wxWindow* parent)
: Sidebar(parent)
MapSidebar::MapSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(sidebarContainer, bottomBarContainer)
{
// TODO: Less ugliness
// TODO: Intercept arrow keys and send them to the GL window

View File

@ -3,5 +3,5 @@
class MapSidebar : public Sidebar
{
public:
MapSidebar(wxWindow* parent);
MapSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
};

View File

@ -5,7 +5,8 @@
#include "Buttons/ActionButton.h"
#include "Buttons/ToolButton.h"
#include "ScenarioEditor/Tools/Common/Tools.h"
#include "ScenarioEditor/Tools/Common/UnitSettings.h"
#include "ScenarioEditor/Tools/Common/ObjectSettings.h"
#include "ScenarioEditor/Tools/Common/MiscState.h"
#include "GameInterface/Messages.h"
@ -62,8 +63,8 @@ struct ObjectSidebarImpl
std::vector<AtlasMessage::sObjectsListItem> m_Objects;
};
ObjectSidebar::ObjectSidebar(wxWindow* parent)
: Sidebar(parent), p(new ObjectSidebarImpl())
ObjectSidebar::ObjectSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(sidebarContainer, bottomBarContainer), p(new ObjectSidebarImpl())
{
wxArrayString strings;
strings.Add(_("Entities"));
@ -72,6 +73,8 @@ ObjectSidebar::ObjectSidebar(wxWindow* parent)
p->m_ObjectListBox = new ObjectSelectListBox(this);
m_MainSizer->Add(p->m_ObjectListBox, wxSizerFlags().Proportion(1).Expand());
m_BottomBar = new ObjectBottomBar(bottomBarContainer);
}
ObjectSidebar::~ObjectSidebar()
@ -79,15 +82,6 @@ ObjectSidebar::~ObjectSidebar()
delete p;
}
wxWindow* ObjectSidebar::GetBottomBar(wxWindow* parent)
{
if (p->m_BottomBar)
return p->m_BottomBar;
p->m_BottomBar = new ObjectBottomBar(parent);
return p->m_BottomBar;
}
void ObjectSidebar::OnFirstDisplay()
{
AtlasMessage::qGetObjectsList qry;
@ -118,15 +112,27 @@ class PlayerComboBox : public wxComboBox
{
public:
PlayerComboBox(wxWindow* parent, wxArrayString& choices)
: wxComboBox(parent, -1, choices[g_UnitSettings.GetPlayerID()], wxDefaultPosition, wxDefaultSize, choices, wxCB_READONLY)
: wxComboBox(parent, -1, choices[g_ObjectSettings.GetPlayerID()], wxDefaultPosition, wxDefaultSize, choices, wxCB_READONLY)
{
m_Conn = g_SelectedObjects.RegisterObserver(1, &PlayerComboBox::OnSelectionChange, this);
}
~PlayerComboBox()
{
g_SelectedObjects.RemoveObserver(m_Conn);
}
private:
ObservableConnection m_Conn;
void OnSelectionChange(const std::vector<AtlasMessage::ObjectID>& selection)
{
SetSelection(g_ObjectSettings.GetPlayerID());
}
void OnSelect(wxCommandEvent& evt)
{
g_UnitSettings.SetPlayerID(evt.GetInt());
g_ObjectSettings.SetPlayerID(evt.GetInt());
}
DECLARE_EVENT_TABLE();
@ -135,6 +141,7 @@ BEGIN_EVENT_TABLE(PlayerComboBox, wxComboBox)
EVT_COMBOBOX(wxID_ANY, OnSelect)
END_EVENT_TABLE();
ObjectBottomBar::ObjectBottomBar(wxWindow* parent)
: wxPanel(parent, wxID_ANY)
{
@ -153,5 +160,6 @@ ObjectBottomBar::ObjectBottomBar(wxWindow* parent)
players.Add(_("Player 8"));
wxComboBox* playerSelect = new PlayerComboBox(this, players);
sizer->Add(playerSelect);
SetSizer(sizer);
}

View File

@ -4,9 +4,8 @@ struct ObjectSidebarImpl;
class ObjectSidebar : public Sidebar
{
public:
ObjectSidebar(wxWindow* parent);
ObjectSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
~ObjectSidebar();
wxWindow* GetBottomBar(wxWindow* parent);
void SetObjectFilter(int type);
protected:

View File

@ -13,8 +13,20 @@
#include "wx/spinctrl.h"
TerrainSidebar::TerrainSidebar(wxWindow* parent)
: Sidebar(parent), m_BottomBar(NULL)
class TextureNotebook;
class TerrainBottomBar : public wxPanel
{
public:
TerrainBottomBar(wxWindow* parent);
void LoadTerrain();
private:
TextureNotebook* m_Textures;
};
TerrainSidebar::TerrainSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(sidebarContainer, bottomBarContainer)
{
// TODO: Less ugliness
@ -36,15 +48,12 @@ TerrainSidebar::TerrainSidebar(wxWindow* parent)
m_MainSizer->Add(sizer);
}
m_BottomBar = new TerrainBottomBar(bottomBarContainer);
}
wxWindow* TerrainSidebar::GetBottomBar(wxWindow* parent)
void TerrainSidebar::OnFirstDisplay()
{
if (m_BottomBar)
return m_BottomBar;
m_BottomBar = new TerrainBottomBar(parent);
return m_BottomBar;
static_cast<TerrainBottomBar*>(m_BottomBar)->LoadTerrain();
}
//////////////////////////////////////////////////////////////////////////
@ -145,6 +154,13 @@ public:
TextureNotebook(wxWindow *parent)
: wxNotebook(parent, wxID_ANY/*, wxDefaultPosition, wxDefaultSize, wxNB_FIXEDWIDTH*/)
{
}
void LoadTerrain()
{
DeleteAllPages();
m_TerrainGroups.Clear();
// Get the list of terrain groups from the engine
AtlasMessage::qGetTerrainGroups qry;
qry.Post();
@ -164,7 +180,7 @@ public:
protected:
void OnPageChanged(wxNotebookEvent& event)
{
if (event.GetSelection() != -1)
if (event.GetSelection() >= 0 && event.GetSelection() < (int)GetPageCount())
{
static_cast<TextureNotebookPage*>(GetPage(event.GetSelection()))->OnDisplay();
}
@ -186,7 +202,12 @@ TerrainBottomBar::TerrainBottomBar(wxWindow* parent)
: wxPanel(parent, wxID_ANY)
{
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
wxNotebook* notebook = new TextureNotebook(this);
sizer->Add(notebook, wxSizerFlags().Expand().Proportion(1));
m_Textures = new TextureNotebook(this);
sizer->Add(m_Textures, wxSizerFlags().Expand().Proportion(1));
SetSizer(sizer);
}
void TerrainBottomBar::LoadTerrain()
{
m_Textures->LoadTerrain();
}

View File

@ -3,16 +3,8 @@
class TerrainSidebar : public Sidebar
{
public:
TerrainSidebar(wxWindow* parent);
wxWindow* GetBottomBar(wxWindow* parent);
TerrainSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
private:
wxWindow* m_BottomBar;
};
class TerrainBottomBar : public wxPanel
{
public:
TerrainBottomBar(wxWindow* parent);
private:
protected:
virtual void OnFirstDisplay();
};

View File

@ -3,3 +3,5 @@
#include "MiscState.h"
wxString g_SelectedTexture = _T("grass1_spring");
Observable<std::vector<AtlasMessage::ObjectID> > g_SelectedObjects;

View File

@ -1,6 +1,18 @@
#ifndef MISCSTATE_H__
#define MISCSTATE_H__
#include "General/Observable.h"
namespace AtlasMessage
{
typedef int ObjectID;
}
extern wxString g_SelectedTexture;
// Observer order:
// 0 = g_UnitSettings
// 1 = things that want to access g_UnitSettings
extern Observable<std::vector<AtlasMessage::ObjectID> > g_SelectedObjects;
#endif // MISCSTATE_H__

View File

@ -0,0 +1,77 @@
#include "stdafx.h"
#include "ObjectSettings.h"
#include "GameInterface/Messages.h"
#include "ScenarioEditor/Tools/Common/Tools.h"
ObjectSettings g_ObjectSettings;
ObjectSettings::ObjectSettings()
: m_PlayerID(0)
{
m_Conn = g_SelectedObjects.RegisterObserver(0, &ObjectSettings::OnSelectionChange, this);
}
ObjectSettings::~ObjectSettings()
{
m_Conn.disconnect();
}
int ObjectSettings::GetPlayerID()
{
return m_PlayerID;
}
void ObjectSettings::SetPlayerID(int playerID)
{
m_PlayerID = playerID;
PostToGame();
}
void ObjectSettings::SetActorSelections(const std::set<wxString>& selections)
{
m_ActorSelections = selections;
PostToGame();
}
AtlasMessage::sObjectSettings ObjectSettings::GetSettings() const
{
AtlasMessage::sObjectSettings settings;
settings.player = m_PlayerID;
std::vector<std::wstring> selections;
for (std::set<wxString>::const_iterator it = m_ActorSelections.begin(); it != m_ActorSelections.end(); ++it)
selections.push_back(it->c_str());
settings.selections = selections;
return settings;
}
void ObjectSettings::OnSelectionChange(const std::vector<AtlasMessage::ObjectID>& selection)
{
// TODO: what would be the sensible action if nothing's selected?
// and if multiple objects are selected?
if (selection.empty())
return;
AtlasMessage::qGetObjectSettings qry (selection[0]);
qry.Post();
m_PlayerID = qry.settings->player;
std::vector<std::wstring> selections = *qry.settings->selections;
m_ActorSelections.clear();
for (std::vector<std::wstring>::iterator it = selections.begin(); it != selections.end(); ++it)
m_ActorSelections.insert(it->c_str());
}
void ObjectSettings::PostToGame()
{
if (g_SelectedObjects.empty())
return;
POST_COMMAND(SetObjectSettings, (g_SelectedObjects[0], GetSettings()));
}

View File

@ -0,0 +1,47 @@
#ifndef ObjectSettings_H__
#define ObjectSettings_H__
#include <set>
#include "ScenarioEditor/Tools/Common/MiscState.h"
namespace AtlasMessage
{
struct sObjectSettings;
}
// Various settings to be applied to newly created units, or to the currently
// selected unit. If a unit is selected or being previewed, it should match
// these settings.
class ObjectSettings
{
public:
ObjectSettings();
~ObjectSettings();
int GetPlayerID();
void SetPlayerID(int playerID);
void SetActorSelections(const std::set<wxString>& selections);
AtlasMessage::sObjectSettings GetSettings() const;
private:
// 0 = gaia, 1..inf = normal players
int m_PlayerID;
// Set of user-chosen actor selections, potentially a superset of any single
// actor's possible variants (since it doesn't get reset if you select
// a new actor, and will accumulate variant names)
std::set<wxString> m_ActorSelections;
// Observe changes to unit selection
ObservableConnection m_Conn;
void OnSelectionChange(const std::vector<AtlasMessage::ObjectID>& selection);
// Transfer current settings to the currently selected unit (if any)
void PostToGame();
};
extern ObjectSettings g_ObjectSettings;
#endif // ObjectSettings_H__

View File

@ -3,7 +3,7 @@
#include "Common/Tools.h"
#include "Common/Brushes.h"
#include "Common/MiscState.h"
#include "Common/UnitSettings.h"
#include "Common/ObjectSettings.h"
#include "GameInterface/Messages.h"
using AtlasMessage::Position;
@ -30,9 +30,9 @@ public:
+ (m_ScreenPos.type1.y-m_Target.type1.y)*(m_ScreenPos.type1.y-m_Target.type1.y);
bool useTarget = (dragDistSq >= 16*16);
if (preview)
POST_MESSAGE(ObjectPreview, (m_ObjectID.c_str(), g_UnitSettings.GetSettings(), m_ObjPos, useTarget, m_Target, g_DefaultAngle));
POST_MESSAGE(ObjectPreview, (m_ObjectID.c_str(), g_ObjectSettings.GetSettings(), m_ObjPos, useTarget, m_Target, g_DefaultAngle));
else
POST_COMMAND(CreateObject, (m_ObjectID.c_str(), g_UnitSettings.GetSettings(), m_ObjPos, useTarget, m_Target, g_DefaultAngle));
POST_COMMAND(CreateObject, (m_ObjectID.c_str(), g_ObjectSettings.GetSettings(), m_ObjPos, useTarget, m_Target, g_DefaultAngle));
}
virtual void Init(void* initData)

View File

@ -11,7 +11,6 @@ class TransformObject : public StateDrivenTool<TransformObject>
{
DECLARE_DYNAMIC_CLASS(TransformObject);
std::vector<AtlasMessage::ObjectID> m_Selection;
int m_dx, m_dy;
public:
@ -22,8 +21,9 @@ public:
void OnDisable()
{
m_Selection.clear();
POST_MESSAGE(SetSelectionPreview, (m_Selection));
g_SelectedObjects.clear();
g_SelectedObjects.NotifyObservers();
POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects));
}
@ -36,25 +36,26 @@ public:
if (evt.LeftDown())
{
// TODO: multiple selection
AtlasMessage::qSelectObject qry(Position(evt.GetPosition()));
AtlasMessage::qPickObject qry(Position(evt.GetPosition()));
qry.Post();
obj->m_Selection.clear();
g_SelectedObjects.clear();
if (AtlasMessage::ObjectIDIsValid(qry.id))
{
obj->m_Selection.push_back(qry.id);
g_SelectedObjects.push_back(qry.id);
obj->m_dx = qry.offsetx;
obj->m_dy = qry.offsety;
SET_STATE(Dragging);
}
POST_MESSAGE(SetSelectionPreview, (obj->m_Selection));
g_SelectedObjects.NotifyObservers();
POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects));
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
return true;
}
else if (evt.Dragging() && evt.RightIsDown() || evt.RightDown())
{
Position pos (evt.GetPosition());
for (size_t i = 0; i < obj->m_Selection.size(); ++i)
POST_COMMAND(RotateObject, (obj->m_Selection[i], true, pos, 0.f));
for (size_t i = 0; i < g_SelectedObjects.size(); ++i)
POST_COMMAND(RotateObject, (g_SelectedObjects[i], true, pos, 0.f));
return true;
}
else
@ -65,10 +66,11 @@ public:
{
if (type == KEY_CHAR && evt.GetKeyCode() == WXK_DELETE)
{
for (size_t i = 0; i < obj->m_Selection.size(); ++i)
POST_COMMAND(DeleteObject, (obj->m_Selection[i]));
obj->m_Selection.clear();
POST_MESSAGE(SetSelectionPreview, (obj->m_Selection));
for (size_t i = 0; i < g_SelectedObjects.size(); ++i)
POST_COMMAND(DeleteObject, (g_SelectedObjects[i]));
g_SelectedObjects.clear();
g_SelectedObjects.NotifyObservers();
POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects));
return true;
}
else
@ -89,8 +91,8 @@ public:
else if (evt.Dragging())
{
Position pos (evt.GetPosition() + wxPoint(obj->m_dx, obj->m_dy));
for (size_t i = 0; i < obj->m_Selection.size(); ++i)
POST_COMMAND(MoveObject, (obj->m_Selection[i], pos));
for (size_t i = 0; i < g_SelectedObjects.size(); ++i)
POST_COMMAND(MoveObject, (g_SelectedObjects[i], pos));
return true;
}
else

View File

@ -8,15 +8,6 @@
template<typename T> T next(T x) { T t = x; return ++t; }
template<typename T, typename I> void delete_erase(T list, I first, I last)
{
while (first != last)
{
delete *first;
first = list.erase(first);
}
}
template<typename T> void delete_fn(T* v) { delete v; }
//////////////////////////////////////////////////////////////////////////
@ -63,7 +54,12 @@ void CommandProc::Destroy()
void CommandProc::Submit(Command* cmd)
{
delete_erase(m_Commands, next(m_CurrentCommand), m_Commands.end());
// If some commands have been undone at the time we insert this new one,
// delete and remove them all.
std::for_each(next(m_CurrentCommand), m_Commands.end(), delete_fn<Command>);
m_Commands.erase(next(m_CurrentCommand), m_Commands.end());
assert(next(m_CurrentCommand) == m_Commands.end());
m_CurrentCommand = m_Commands.insert(next(m_CurrentCommand), cmd);
(*m_CurrentCommand)->Do();

View File

@ -36,6 +36,8 @@ public:
private:
std::list<Command*> m_Commands;
typedef std::list<Command*>::iterator cmdIt;
// The 'current' command is the latest one which has been executed
// (ignoring any that have been undone)
cmdIt m_CurrentCommand;
};
@ -49,7 +51,7 @@ struct DataCommand : public Command // so commands can optionally override (De|C
{
void Destruct() {};
void Construct() {};
// MergeWithSelf should be overriden by commands, and implemented
// MergeWithSelf should be overridden by commands, and implemented
// to update 'prev' to include the effects of 'this'
void MergeWithSelf(void*) { debug_warn("MergeWithSelf unimplemented in some command"); }
};
@ -57,10 +59,10 @@ struct DataCommand : public Command // so commands can optionally override (De|C
#define BEGIN_COMMAND(t) \
class c##t : public DataCommand \
{ \
d##t* d; \
d##t* msg; \
public: \
c##t(d##t* data) : d(data) { Construct(); } \
~c##t() { Destruct(); AtlasMessage::ShareableDelete(d); /* d was allocated by mDoCommand() */ } \
c##t(d##t* data) : msg(data) { Construct(); } \
~c##t() { Destruct(); AtlasMessage::ShareableDelete(msg); /* msg was allocated by mDoCommand() */ } \
static Command* Create(const void* data) { return new c##t ((d##t*)data); } \
virtual void Merge(Command* prev) { MergeWithSelf((c##t*)prev); } \
virtual const char* GetType() const { return #t; }

View File

@ -91,12 +91,12 @@ BEGIN_COMMAND(AlterElevation)
void Do()
{
int amount = (int)d->amount;
int amount = (int)msg->amount;
// If the framerate is very high, 'amount' is often very
// small (even zero) so the integer truncation is significant
static float roundingError = 0.0;
roundingError += d->amount - (float)amount;
roundingError += msg->amount - (float)amount;
if (roundingError >= 1.f)
{
amount += (int)roundingError;
@ -104,7 +104,7 @@ BEGIN_COMMAND(AlterElevation)
}
static CVector3D previousPosition;
d->pos->GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition);
msg->pos->GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition);
previousPosition = g_CurrentBrush.m_Centre;
int x0, y0;
@ -160,10 +160,10 @@ BEGIN_COMMAND(FlattenElevation)
void Do()
{
int amount = (int)d->amount;
int amount = (int)msg->amount;
static CVector3D previousPosition;
d->pos->GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition);
msg->pos->GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition);
previousPosition = g_CurrentBrush.m_Centre;
int xc, yc;

View File

@ -103,6 +103,54 @@ MESSAGEHANDLER(SetSelectionPreview)
g_Selection = *msg->ids;
}
QUERYHANDLER(GetObjectSettings)
{
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
sObjectSettings settings;
settings.player = unit->GetPlayerID();
// TODO: actor variation
msg->settings = settings;
}
BEGIN_COMMAND(SetObjectSettings)
int m_PlayerOld, m_PlayerNew;
void Do()
{
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
sObjectSettings settings = msg->settings;
m_PlayerOld = unit->GetPlayerID();
m_PlayerNew = settings.player;
// TODO: actor variations
Redo();
}
void Redo()
{
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
unit->SetPlayerID(m_PlayerNew);
}
void Undo()
{
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
unit->SetPlayerID(m_PlayerOld);
}
END_COMMAND(SetObjectSettings);
//////////////////////////////////////////////////////////////////////////
@ -234,21 +282,27 @@ BEGIN_COMMAND(CreateObject)
void Do()
{
m_Pos = GetUnitPos(d->pos);
m_Player = d->settings->player;
// Calculate the position/orientation to create this unit with
if (d->usetarget)
m_Pos = GetUnitPos(msg->pos);
if (msg->usetarget)
{
// Aim from m_Pos towards msg->target
CVector3D target;
d->target->GetWorldSpace(target, m_Pos.Y);
msg->target->GetWorldSpace(target, m_Pos.Y);
CVector2D dir(target.X-m_Pos.X, target.Z-m_Pos.Z);
m_Angle = atan2(dir.x, dir.y);
}
else
{
m_Angle = d->angle;
m_Angle = msg->angle;
}
// TODO: variations too
m_Player = msg->settings->player;
// Get a new ID, for future reference to this unit
m_ID = g_UnitMan.GetNewID();
Redo();
@ -258,7 +312,7 @@ BEGIN_COMMAND(CreateObject)
{
bool isEntity;
CStrW name;
if (ParseObjectName(*d->id, isEntity, name))
if (ParseObjectName(*msg->id, isEntity, name))
{
std::set<CStrW> selections;
@ -309,6 +363,8 @@ BEGIN_COMMAND(CreateObject)
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = m_Pos.Z;
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
unit->GetModel()->SetTransform(m);
unit->SetPlayerID(m_Player);
}
}
}
@ -332,7 +388,7 @@ BEGIN_COMMAND(CreateObject)
END_COMMAND(CreateObject)
QUERYHANDLER(SelectObject)
QUERYHANDLER(PickObject)
{
float x, y;
msg->pos->GetScreenSpace(x, y);
@ -369,7 +425,7 @@ BEGIN_COMMAND(MoveObject)
void Do()
{
CUnit* unit = g_UnitMan.FindByID(d->id);
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
if (unit->GetEntity())
@ -382,14 +438,14 @@ BEGIN_COMMAND(MoveObject)
m_PosOld = m.GetTranslation();
}
m_PosNew = GetUnitPos(d->pos);
m_PosNew = GetUnitPos(msg->pos);
SetPos(m_PosNew);
}
void SetPos(CVector3D& pos)
{
CUnit* unit = g_UnitMan.FindByID(d->id);
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
if (unit->GetEntity())
@ -430,23 +486,23 @@ BEGIN_COMMAND(RotateObject)
void Do()
{
CUnit* unit = g_UnitMan.FindByID(d->id);
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
if (unit->GetEntity())
{
m_AngleOld = unit->GetEntity()->m_orientation;
if (d->usetarget)
if (msg->usetarget)
{
CVector3D& pos = unit->GetEntity()->m_position;
CVector3D target;
d->target->GetWorldSpace(target, pos.Y);
msg->target->GetWorldSpace(target, pos.Y);
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
m_AngleNew = atan2(dir.x, dir.y);
}
else
{
m_AngleNew = d->angle;
m_AngleNew = msg->angle;
}
}
else
@ -456,10 +512,10 @@ BEGIN_COMMAND(RotateObject)
CVector3D pos = unit->GetModel()->GetTransform().GetTranslation();
float s, c;
if (d->usetarget)
if (msg->usetarget)
{
CVector3D target;
d->target->GetWorldSpace(target, pos.Y);
msg->target->GetWorldSpace(target, pos.Y);
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
dir = dir.normalize();
s = dir.x;
@ -467,8 +523,8 @@ BEGIN_COMMAND(RotateObject)
}
else
{
s = sinf(d->angle);
c = cosf(d->angle);
s = sinf(msg->angle);
c = cosf(msg->angle);
}
CMatrix3D& m = m_TransformNew;
m._11 = -c; m._12 = 0.0f; m._13 = -s; m._14 = pos.X;
@ -482,7 +538,7 @@ BEGIN_COMMAND(RotateObject)
void SetAngle(float angle, CMatrix3D& transform)
{
CUnit* unit = g_UnitMan.FindByID(d->id);
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
if (unit->GetEntity())
@ -542,7 +598,7 @@ BEGIN_COMMAND(DeleteObject)
void Redo()
{
CUnit* unit = g_UnitMan.FindByID(d->id);
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
if (unit->GetEntity())

View File

@ -165,12 +165,12 @@ BEGIN_COMMAND(PaintTerrain)
void Do()
{
d->pos->GetWorldSpace(g_CurrentBrush.m_Centre);
msg->pos->GetWorldSpace(g_CurrentBrush.m_Centre);
int x0, y0;
g_CurrentBrush.GetBottomLeft(x0, y0);
CTextureEntry* texentry = g_TexMan.FindTexture(CStrW(*d->texture));
CTextureEntry* texentry = g_TexMan.FindTexture(CStrW(*msg->texture));
if (! texentry)
{
debug_warn("Can't find texentry"); // TODO: nicer error handling
@ -182,7 +182,7 @@ BEGIN_COMMAND(PaintTerrain)
for (int dx = 0; dx < g_CurrentBrush.m_W; ++dx)
{
if (g_CurrentBrush.Get(dx, dy) > 0.5f) // TODO: proper solid brushes
m_TerrainDelta.PaintTile(x0+dx, y0+dy, texture, d->priority);
m_TerrainDelta.PaintTile(x0+dx, y0+dy, texture, msg->priority);
}
g_Game->GetWorld()->GetTerrain()->MakeDirty(x0, y0, x0+g_CurrentBrush.m_W, y0+g_CurrentBrush.m_H, RENDERDATA_UPDATE_INDICES);

View File

@ -102,16 +102,16 @@ QUERY(GetObjectsList,
((std::vector<sObjectsListItem>, objects))
);
struct sUnitSettings
struct sObjectSettings
{
Shareable<int> player;
Shareable<std::vector<std::wstring> > selections;
};
SHAREABLE_STRUCT(sUnitSettings);
SHAREABLE_STRUCT(sObjectSettings);
MESSAGE(ObjectPreview,
((std::wstring, id)) // or empty string => disable
((sUnitSettings, settings))
((sObjectSettings, settings))
((Position, pos))
((bool, usetarget)) // true => use 'target' for orientation; false => use 'angle'
((Position, target))
@ -120,7 +120,7 @@ MESSAGE(ObjectPreview,
COMMAND(CreateObject, NOMERGE,
((std::wstring, id))
((sUnitSettings, settings))
((sObjectSettings, settings))
((Position, pos))
((bool, usetarget)) // true => use 'target' for orientation; false => use 'angle'
((Position, target))
@ -183,7 +183,7 @@ COMMAND(PaintTerrain, MERGE,
typedef int ObjectID;
inline bool ObjectIDIsValid(ObjectID id) { return (id >= 0); }
QUERY(SelectObject,
QUERY(PickObject,
((Position, pos))
,
((ObjectID, id))
@ -211,6 +211,18 @@ MESSAGE(SetSelectionPreview,
((std::vector<ObjectID>, ids))
);
QUERY(GetObjectSettings,
((ObjectID, id))
,
((sObjectSettings, settings))
);
COMMAND(SetObjectSettings, NOMERGE,
((ObjectID, id))
((sObjectSettings, settings))
);
//////////////////////////////////////////////////////////////////////////
#include "MessagesSetup.h"