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_patrol.cpp - The patrol action. */
12 //
13 // (c) Copyright 1998-2019 by Lutz Sammer, Jimmy Salmon and Andrettin
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_patrol.h"
39
40 #include "animation.h"
41 //Wyrmgus start
42 #include "commands.h"
43 //Wyrmgus end
44 #include "iolib.h"
45 #include "map/map.h"
46 #include "map/map_layer.h"
47 #include "map/tileset.h"
48 #include "pathfinder.h"
49 #include "script.h"
50 #include "ui/ui.h"
51 #include "unit/unit.h"
52 //Wyrmgus start
53 #include "unit/unit_find.h"
54 //Wyrmgus end
55 #include "unit/unittype.h"
56 #include "video.h"
57
58 /*----------------------------------------------------------------------------
59 -- Functions
60 ----------------------------------------------------------------------------*/
61
62 //Wyrmgus start
63 ///* static */ COrder *COrder::NewActionPatrol(const Vec2i ¤tPos, const Vec2i &dest)
NewActionPatrol(const Vec2i & currentPos,const Vec2i & dest,int current_z,int dest_z)64 /* static */ COrder *COrder::NewActionPatrol(const Vec2i ¤tPos, const Vec2i &dest, int current_z, int dest_z)
65 //Wyrmgus end
66 {
67 Assert(Map.Info.IsPointOnMap(currentPos, current_z));
68 Assert(Map.Info.IsPointOnMap(dest, dest_z));
69
70 COrder_Patrol *order = new COrder_Patrol();
71
72 order->goalPos = dest;
73 order->WayPoint = currentPos;
74 //Wyrmgus start
75 order->MapLayer = dest_z;
76 order->WayPointMapLayer = current_z;
77 //Wyrmgus end
78 return order;
79 }
80
81
Save(CFile & file,const CUnit & unit) const82 /* virtual */ void COrder_Patrol::Save(CFile &file, const CUnit &unit) const
83 {
84 file.printf("{\"action-patrol\",");
85
86 if (this->Finished) {
87 file.printf(" \"finished\", ");
88 }
89 file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
90 //Wyrmgus start
91 file.printf(" \"map-layer\", %d,", this->MapLayer);
92 //Wyrmgus end
93 file.printf(" \"range\", %d,", this->Range);
94
95 if (this->WaitingCycle != 0) {
96 file.printf(" \"waiting-cycle\", %d,", this->WaitingCycle);
97 }
98 //Wyrmgus start
99 // file.printf(" \"patrol\", {%d, %d}", this->WayPoint.x, this->WayPoint.y);
100 file.printf(" \"patrol\", {%d, %d},", this->WayPoint.x, this->WayPoint.y);
101 file.printf(" \"patrol-map-layer\", %d", this->WayPointMapLayer);
102 //Wyrmgus end
103 file.printf("}");
104 }
105
ParseSpecificData(lua_State * l,int & j,const char * value,const CUnit & unit)106 /* virtual */ bool COrder_Patrol::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
107 {
108 if (!strcmp(value, "patrol")) {
109 ++j;
110 lua_rawgeti(l, -1, j + 1);
111 CclGetPos(l, &this->WayPoint.x , &this->WayPoint.y);
112 lua_pop(l, 1);
113 //Wyrmgus start
114 } else if (!strcmp(value, "patrol-map-layer")) {
115 ++j;
116 this->WayPointMapLayer = LuaToNumber(l, -1, j + 1);
117 //Wyrmgus end
118 } else if (!strcmp(value, "waiting-cycle")) {
119 ++j;
120 this->WaitingCycle = LuaToNumber(l, -1, j + 1);
121 } else if (!strcmp(value, "range")) {
122 ++j;
123 this->Range = LuaToNumber(l, -1, j + 1);
124 } else if (!strcmp(value, "tile")) {
125 ++j;
126 lua_rawgeti(l, -1, j + 1);
127 CclGetPos(l, &this->goalPos.x , &this->goalPos.y);
128 lua_pop(l, 1);
129 //Wyrmgus start
130 } else if (!strcmp(value, "map-layer")) {
131 ++j;
132 this->MapLayer = LuaToNumber(l, -1, j + 1);
133 //Wyrmgus end
134 } else {
135 return false;
136 }
137 return true;
138 }
139
IsValid() const140 /* virtual */ bool COrder_Patrol::IsValid() const
141 {
142 return true;
143 }
144
Show(const CViewport & vp,const PixelPos & lastScreenPos) const145 /* virtual */ PixelPos COrder_Patrol::Show(const CViewport &vp, const PixelPos &lastScreenPos) const
146 {
147 if (this->MapLayer != UI.CurrentMapLayer->ID) {
148 return lastScreenPos;
149 }
150
151 const PixelPos pos1 = vp.TilePosToScreen_Center(this->goalPos);
152 const PixelPos pos2 = vp.TilePosToScreen_Center(this->WayPoint);
153
154 if (Preference.ShowPathlines) {
155 Video.DrawLineClip(ColorGreen, lastScreenPos, pos1);
156 Video.FillCircleClip(ColorBlue, pos1, 2);
157 Video.DrawLineClip(ColorBlue, pos1, pos2);
158 Video.FillCircleClip(ColorBlue, pos2, 3);
159 }
160
161 return pos2;
162 }
163
UpdatePathFinderData(PathFinderInput & input)164 /* virtual */ void COrder_Patrol::UpdatePathFinderData(PathFinderInput &input)
165 {
166 input.SetMinRange(0);
167 input.SetMaxRange(this->Range);
168 const Vec2i tileSize(0, 0);
169 input.SetGoal(this->goalPos, tileSize, this->MapLayer);
170 }
171
172
Execute(CUnit & unit)173 /* virtual */ void COrder_Patrol::Execute(CUnit &unit)
174 {
175 if (unit.Wait) {
176 if (!unit.Waiting) {
177 unit.Waiting = 1;
178 unit.WaitBackup = unit.Anim;
179 }
180 //Wyrmgus start
181 // UnitShowAnimation(unit, unit.Type->Animations->Still);
182 UnitShowAnimation(unit, unit.GetAnimations()->Still);
183 //Wyrmgus end
184 unit.Wait--;
185 return;
186 }
187 if (unit.Waiting) {
188 unit.Anim = unit.WaitBackup;
189 unit.Waiting = 0;
190 }
191
192 switch (DoActionMove(unit)) {
193 case PF_FAILED:
194 this->WaitingCycle = 0;
195 break;
196 case PF_UNREACHABLE:
197 //Wyrmgus start
198 if ((unit.MapLayer->Field(unit.tilePos)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) {
199 std::vector<CUnit *> table;
200 Select(unit.tilePos, unit.tilePos, table, unit.MapLayer->ID);
201 for (size_t i = 0; i != table.size(); ++i) {
202 if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) {
203 if (table[i]->CurrentAction() == UnitActionStill) {
204 CommandStopUnit(*table[i]);
205 CommandMove(*table[i], this->goalPos, FlushCommands, this->MapLayer);
206 }
207 return;
208 }
209 }
210 }
211 //Wyrmgus end
212 // Increase range and try again
213 this->WaitingCycle = 1;
214 this->Range++;
215 break;
216
217 case PF_REACHED:
218 this->WaitingCycle = 1;
219 this->Range = 0;
220 std::swap(this->WayPoint, this->goalPos);
221 //Wyrmgus start
222 std::swap(this->WayPointMapLayer, this->MapLayer);
223 //Wyrmgus end
224
225 break;
226 case PF_WAIT:
227 // Wait for a while then give up
228 this->WaitingCycle++;
229 if (this->WaitingCycle == 5) {
230 this->WaitingCycle = 0;
231 this->Range = 0;
232 std::swap(this->WayPoint, this->goalPos);
233 //Wyrmgus start
234 std::swap(this->WayPointMapLayer, this->MapLayer);
235 //Wyrmgus end
236
237 unit.pathFinderData->output.Cycles = 0; //moving counter
238 }
239 break;
240 default: // moving
241 this->WaitingCycle = 0;
242 break;
243 }
244
245 if (!unit.Anim.Unbreakable) {
246 if (AutoAttack(unit) || AutoRepair(unit) || AutoCast(unit)) {
247 this->Finished = true;
248 }
249 }
250 }
251
252 //@}
253