1 /* Copyright (C) 2013 Wildfire Games. 2 * This file is part of 0 A.D. 3 * 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * 0 A.D. is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "precompiled.h" 19 20 #include "ScenarioEditor/ScenarioEditor.h" 21 #include "Common/Tools.h" 22 #include "Common/Brushes.h" 23 #include "Common/MiscState.h" 24 #include "Common/ObjectSettings.h" 25 #include "GameInterface/Messages.h" 26 27 using AtlasMessage::Position; 28 29 static float g_DefaultAngle = (float)(M_PI*3.0/4.0); 30 31 class PlaceObject : public StateDrivenTool<PlaceObject> 32 { 33 DECLARE_DYNAMIC_CLASS(PlaceObject); 34 35 Position m_ScreenPos, m_ObjPos, m_Target; 36 wxString m_ObjectID; 37 unsigned int m_ActorSeed; 38 39 public: PlaceObject()40 PlaceObject() 41 { 42 SetState(&Waiting); 43 } 44 SendObjectMsg(bool preview)45 void SendObjectMsg(bool preview) 46 { 47 int dragDistSq = 48 (m_ScreenPos.type1.x-m_Target.type1.x)*(m_ScreenPos.type1.x-m_Target.type1.x) 49 + (m_ScreenPos.type1.y-m_Target.type1.y)*(m_ScreenPos.type1.y-m_Target.type1.y); 50 bool useTarget = (dragDistSq >= 16*16); 51 if (preview) 52 POST_MESSAGE(ObjectPreview, ((std::wstring)m_ObjectID.wc_str(), GetScenarioEditor().GetObjectSettings().GetSettings(), m_ObjPos, useTarget, m_Target, g_DefaultAngle, m_ActorSeed, true)); 53 else 54 { 55 POST_COMMAND(CreateObject, ((std::wstring)m_ObjectID.wc_str(), GetScenarioEditor().GetObjectSettings().GetSettings(), m_ObjPos, useTarget, m_Target, g_DefaultAngle, m_ActorSeed)); 56 RandomizeActorSeed(); 57 } 58 } 59 Init(void * initData,ScenarioEditor * scenarioEditor)60 virtual void Init(void* initData, ScenarioEditor* scenarioEditor) 61 { 62 StateDrivenTool<PlaceObject>::Init(initData, scenarioEditor); 63 64 wxASSERT(initData); 65 wxString& id = *static_cast<wxString*>(initData); 66 m_ObjectID = id; 67 SendObjectMsg(true); 68 } 69 OnEnable()70 void OnEnable() 71 { 72 RandomizeActorSeed(); 73 } 74 OnDisable()75 void OnDisable() 76 { 77 m_ObjectID = _T(""); 78 SendObjectMsg(true); 79 } 80 81 /* 82 Object placement: 83 * Select unit from list 84 * Move mouse around screen; preview of unit follows mouse 85 * Left mouse down -> remember position, fix preview to point 86 * Mouse move -> if moved > [limit], rotate unit to face mouse; else default orientation 87 * Left mouse release -> finalise placement of object on map 88 89 * Page up/down -> rotate default orientation 90 91 * Escape -> cancel placement tool 92 93 TOOD: what happens if somebody saves while the preview is active? 94 */ 95 OnMouseOverride(wxMouseEvent & WXUNUSED (evt))96 bool OnMouseOverride(wxMouseEvent& WXUNUSED(evt)) 97 { 98 // This used to let the scroll-wheel rotate units, but that overrides 99 // the camera zoom and makes navigation very awkward, so it doesn't 100 // any more. 101 return false; 102 } 103 OnKeyOverride(wxKeyEvent & evt,KeyEventType type)104 bool OnKeyOverride(wxKeyEvent& evt, KeyEventType type) 105 { 106 if (type == KEY_CHAR && evt.GetKeyCode() == WXK_ESCAPE) 107 { 108 SetState(&Disabled); 109 return true; 110 } 111 else 112 return false; 113 } 114 RotateTick(float dt)115 void RotateTick(float dt) 116 { 117 int dir = 0; 118 if (wxGetKeyState(WXK_PAGEDOWN)) ++dir; // page-down key 119 if (wxGetKeyState(WXK_PAGEUP)) --dir; // page-up key 120 if (dir) 121 { 122 float speed = M_PI/2.f * ScenarioEditor::GetSpeedModifier(); // radians per second 123 g_DefaultAngle += (dir * dt * speed); 124 SendObjectMsg(true); 125 } 126 } 127 RandomizeActorSeed()128 void RandomizeActorSeed() 129 { 130 m_ActorSeed = (unsigned int)floor((rand() / (float)RAND_MAX) * 65535.f); 131 } 132 133 struct sWaiting : public State 134 { OnMousePlaceObject::sWaiting135 bool OnMouse(PlaceObject* obj, wxMouseEvent& evt) 136 { 137 if (obj->OnMouseOverride(evt)) 138 return true; 139 else if (evt.LeftDown()) 140 { 141 obj->m_ObjPos = obj->m_ScreenPos = obj->m_Target = Position(evt.GetPosition()); 142 obj->SendObjectMsg(true); 143 obj->m_ObjPos = Position::Unchanged(); // make sure object is stationary even if the camera moves 144 SET_STATE(Placing); 145 return true; 146 } 147 else if (evt.Moving()) 148 { 149 obj->m_ObjPos = obj->m_ScreenPos = obj->m_Target = Position(evt.GetPosition()); 150 obj->SendObjectMsg(true); 151 return true; 152 } 153 else 154 return false; 155 } OnKeyPlaceObject::sWaiting156 bool OnKey(PlaceObject* obj, wxKeyEvent& evt, KeyEventType type) 157 { 158 if (type == KEY_CHAR && (evt.GetKeyCode() >= '0' && evt.GetKeyCode() <= '9')) 159 { 160 int playerID = evt.GetKeyCode() - '0'; 161 obj->GetScenarioEditor().GetObjectSettings().SetPlayerID(playerID); 162 obj->GetScenarioEditor().GetObjectSettings().NotifyObservers(); 163 obj->SendObjectMsg(true); 164 return true; 165 } 166 else 167 return obj->OnKeyOverride(evt, type); 168 } OnTickPlaceObject::sWaiting169 void OnTick(PlaceObject* obj, float dt) 170 { 171 obj->RotateTick(dt); 172 } 173 } 174 Waiting; 175 176 struct sPlacing : public State 177 { OnMousePlaceObject::sPlacing178 bool OnMouse(PlaceObject* obj, wxMouseEvent& evt) 179 { 180 if (obj->OnMouseOverride(evt)) 181 return true; 182 else if (evt.LeftUp()) 183 { 184 obj->m_Target = Position(evt.GetPosition()); 185 // Create the actual object 186 obj->SendObjectMsg(false); 187 // Go back to preview mode 188 SET_STATE(Waiting); 189 obj->m_ObjPos = obj->m_ScreenPos = obj->m_Target; 190 obj->SendObjectMsg(true); 191 return true; 192 } 193 else if (evt.Dragging()) 194 { 195 obj->m_Target = Position(evt.GetPosition()); 196 obj->SendObjectMsg(true); 197 return true; 198 } 199 else 200 return false; 201 } OnKeyPlaceObject::sPlacing202 bool OnKey(PlaceObject* obj, wxKeyEvent& evt, KeyEventType type) 203 { 204 return obj->OnKeyOverride(evt, type); 205 } OnTickPlaceObject::sPlacing206 void OnTick(PlaceObject* obj, float dt) 207 { 208 obj->RotateTick(dt); 209 } 210 } 211 Placing; 212 }; 213 214 IMPLEMENT_DYNAMIC_CLASS(PlaceObject, StateDrivenTool<PlaceObject>); 215