1 // _________ __ __
2 // / _____// |_____________ _/ |______ ____ __ __ ______
3 // \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
4 // / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
5 // /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
6 // \/ \/ \//_____/ \/
7 // ______________________ ______________________
8 // T H E W A R B E G I N S
9 // Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name action_defend.cpp - The defend action. */
12 //
13 // (c) Copyright 2012 by cybermind
14 //
15 // This program is free software; you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation; only version 2 of the License.
18 //
19 // This program is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 // GNU General Public License for more details.
23 //
24 // You should have received a copy of the GNU General Public License
25 // along with this program; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 // 02111-1307, USA.
28 //
29
30 //@{
31
32 /*----------------------------------------------------------------------------
33 -- Includes
34 ----------------------------------------------------------------------------*/
35
36 #include "stratagus.h"
37
38 #include "action/action_defend.h"
39
40 #include "animation.h"
41 #include "iolib.h"
42 #include "map.h"
43 #include "pathfinder.h"
44 #include "script.h"
45 #include "ui.h"
46 #include "unit.h"
47 #include "unittype.h"
48 #include "video.h"
49
50 enum {
51 State_Init = 0,
52 State_MovingToTarget,
53 State_Defending
54 };
55
56 /*----------------------------------------------------------------------------
57 -- Functions
58 ----------------------------------------------------------------------------*/
59
NewActionDefend(CUnit & dest)60 /* static */ COrder *COrder::NewActionDefend(CUnit &dest)
61 {
62 COrder_Defend *order = new COrder_Defend();
63
64 if (dest.Destroyed) {
65 order->goalPos = dest.tilePos + dest.Type->GetHalfTileSize();
66 } else {
67 order->SetGoal(&dest);
68 order->Range = 1;
69 }
70 return order;
71 }
72
Save(CFile & file,const CUnit & unit) const73 /* virtual */ void COrder_Defend::Save(CFile &file, const CUnit &unit) const
74 {
75 file.printf("{\"action-defend\",");
76
77 if (this->Finished) {
78 file.printf(" \"finished\", ");
79 }
80 file.printf(" \"range\", %d,", this->Range);
81 if (this->HasGoal()) {
82 file.printf(" \"goal\", \"%s\",", UnitReference(this->GetGoal()).c_str());
83 }
84 file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
85
86 file.printf(" \"state\", %d", this->State);
87
88 file.printf("}");
89 }
90
ParseSpecificData(lua_State * l,int & j,const char * value,const CUnit & unit)91 /* virtual */ bool COrder_Defend::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
92 {
93 if (!strcmp(value, "state")) {
94 ++j;
95 this->State = LuaToNumber(l, -1, j + 1);
96 } else if (!strcmp(value, "range")) {
97 ++j;
98 this->Range = LuaToNumber(l, -1, j + 1);
99 } else if (!strcmp(value, "tile")) {
100 ++j;
101 lua_rawgeti(l, -1, j + 1);
102 CclGetPos(l, &this->goalPos.x , &this->goalPos.y);
103 lua_pop(l, 1);
104 } else {
105 return false;
106 }
107 return true;
108 }
109
IsValid() const110 /* virtual */ bool COrder_Defend::IsValid() const
111 {
112 return true;
113 }
114
Show(const CViewport & vp,const PixelPos & lastScreenPos) const115 /* virtual */ PixelPos COrder_Defend::Show(const CViewport &vp, const PixelPos &lastScreenPos) const
116 {
117 PixelPos targetPos;
118
119 if (this->HasGoal()) {
120 targetPos = vp.MapToScreenPixelPos(this->GetGoal()->GetMapPixelPosCenter());
121 } else {
122 targetPos = vp.TilePosToScreen_Center(this->goalPos);
123 }
124 Video.FillCircleClip(ColorGreen, lastScreenPos, 2);
125 Video.DrawLineClip(ColorGreen, lastScreenPos, targetPos);
126 Video.FillCircleClip(ColorOrange, targetPos, 3);
127 return targetPos;
128 }
129
UpdatePathFinderData(PathFinderInput & input)130 /* virtual */ void COrder_Defend::UpdatePathFinderData(PathFinderInput &input)
131 {
132 input.SetMinRange(0);
133 input.SetMaxRange(this->Range);
134
135 Vec2i tileSize;
136 if (this->HasGoal()) {
137 CUnit *goal = this->GetGoal();
138 tileSize.x = goal->Type->TileWidth;
139 tileSize.y = goal->Type->TileHeight;
140 input.SetGoal(goal->tilePos, tileSize);
141 } else {
142 tileSize.x = 0;
143 tileSize.y = 0;
144 input.SetGoal(this->goalPos, tileSize);
145 }
146 }
147
148
Execute(CUnit & unit)149 /* virtual */ void COrder_Defend::Execute(CUnit &unit)
150 {
151 if (unit.Wait) {
152 if (!unit.Waiting) {
153 unit.Waiting = 1;
154 unit.WaitBackup = unit.Anim;
155 }
156 UnitShowAnimation(unit, unit.Type->Animations->Still);
157 unit.Wait--;
158 return;
159 }
160 if (unit.Waiting) {
161 unit.Anim = unit.WaitBackup;
162 unit.Waiting = 0;
163 }
164 CUnit *goal = this->GetGoal();
165
166 if (this->State == State_Init) {
167 if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
168 this->Finished = true;
169 return;
170 }
171 this->State = State_MovingToTarget;
172 } else if (this->State == State_Defending) {
173 if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
174 this->Finished = true;
175 return;
176 }
177 }
178
179 if (!unit.Anim.Unbreakable) {
180 if (AutoCast(unit) || AutoAttack(unit) || AutoRepair(unit)) {
181 return;
182 }
183 }
184
185 switch (DoActionMove(unit)) {
186 case PF_UNREACHABLE:
187 // Some tries to reach the goal
188 this->Range++;
189 break;
190 case PF_REACHED: {
191 if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { // goal has died
192 this->Finished = true;
193 return;
194 }
195
196 // Now defend the goal
197 this->goalPos = goal->tilePos;
198 this->State = State_Defending;
199 }
200 default:
201 break;
202 }
203
204 // Target destroyed?
205 if (goal && !goal->IsVisibleAsGoal(*unit.Player)) {
206 DebugPrint("Goal gone\n");
207 this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
208 this->ClearGoal();
209 goal = NULL;
210 if (this->State == State_Defending) {
211 this->Finished = true;
212 return;
213 }
214 }
215 }
216
217 /**
218 ** Get goal position
219 */
GetGoalPos() const220 /* virtual */ const Vec2i COrder_Defend::GetGoalPos() const
221 {
222 const Vec2i invalidPos(-1, -1);
223 if (goalPos != invalidPos) {
224 return goalPos;
225 }
226 if (this->HasGoal()) {
227 return this->GetGoal()->tilePos;
228 }
229 return invalidPos;
230 }
231