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 &currentPos, const Vec2i &dest)
NewActionPatrol(const Vec2i & currentPos,const Vec2i & dest,int current_z,int dest_z)64 /* static */ COrder *COrder::NewActionPatrol(const Vec2i &currentPos, 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