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-2005 by Lutz Sammer and Jimmy Salmon
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 #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 /*----------------------------------------------------------------------------
51 --  Functions
52 ----------------------------------------------------------------------------*/
53 
NewActionPatrol(const Vec2i & currentPos,const Vec2i & dest)54 /* static */ COrder *COrder::NewActionPatrol(const Vec2i &currentPos, const Vec2i &dest)
55 {
56 	Assert(Map.Info.IsPointOnMap(currentPos));
57 	Assert(Map.Info.IsPointOnMap(dest));
58 
59 	COrder_Patrol *order = new COrder_Patrol();
60 
61 	order->goalPos = dest;
62 	order->WayPoint = currentPos;
63 	return order;
64 }
65 
66 
Save(CFile & file,const CUnit & unit) const67 /* virtual */ void COrder_Patrol::Save(CFile &file, const CUnit &unit) const
68 {
69 	file.printf("{\"action-patrol\",");
70 
71 	if (this->Finished) {
72 		file.printf(" \"finished\", ");
73 	}
74 	file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
75 	file.printf(" \"range\", %d,", this->Range);
76 
77 	if (this->WaitingCycle != 0) {
78 		file.printf(" \"waiting-cycle\", %d,", this->WaitingCycle);
79 	}
80 	file.printf(" \"patrol\", {%d, %d}", this->WayPoint.x, this->WayPoint.y);
81 	file.printf("}");
82 }
83 
ParseSpecificData(lua_State * l,int & j,const char * value,const CUnit & unit)84 /* virtual */ bool COrder_Patrol::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
85 {
86 	if (!strcmp(value, "patrol")) {
87 		++j;
88 		lua_rawgeti(l, -1, j + 1);
89 		CclGetPos(l, &this->WayPoint.x , &this->WayPoint.y);
90 		lua_pop(l, 1);
91 	} else if (!strcmp(value, "waiting-cycle")) {
92 		++j;
93 		this->WaitingCycle = LuaToNumber(l, -1, j + 1);
94 	} else if (!strcmp(value, "range")) {
95 		++j;
96 		this->Range = LuaToNumber(l, -1, j + 1);
97 	} else if (!strcmp(value, "tile")) {
98 		++j;
99 		lua_rawgeti(l, -1, j + 1);
100 		CclGetPos(l, &this->goalPos.x , &this->goalPos.y);
101 		lua_pop(l, 1);
102 	} else {
103 		return false;
104 	}
105 	return true;
106 }
107 
IsValid() const108 /* virtual */ bool COrder_Patrol::IsValid() const
109 {
110 	return true;
111 }
112 
Show(const CViewport & vp,const PixelPos & lastScreenPos) const113 /* virtual */ PixelPos COrder_Patrol::Show(const CViewport &vp, const PixelPos &lastScreenPos) const
114 {
115 	const PixelPos pos1 = vp.TilePosToScreen_Center(this->goalPos);
116 	const PixelPos pos2 = vp.TilePosToScreen_Center(this->WayPoint);
117 
118 	Video.DrawLineClip(ColorGreen, lastScreenPos, pos1);
119 	Video.FillCircleClip(ColorBlue, pos1, 2);
120 	Video.DrawLineClip(ColorBlue, pos1, pos2);
121 	Video.FillCircleClip(ColorBlue, pos2, 3);
122 	return pos2;
123 }
124 
UpdatePathFinderData(PathFinderInput & input)125 /* virtual */ void COrder_Patrol::UpdatePathFinderData(PathFinderInput &input)
126 {
127 	input.SetMinRange(0);
128 	input.SetMaxRange(this->Range);
129 	const Vec2i tileSize(0, 0);
130 	input.SetGoal(this->goalPos, tileSize);
131 }
132 
133 
Execute(CUnit & unit)134 /* virtual */ void COrder_Patrol::Execute(CUnit &unit)
135 {
136 	if (unit.Wait) {
137 		if (!unit.Waiting) {
138 			unit.Waiting = 1;
139 			unit.WaitBackup = unit.Anim;
140 		}
141 		UnitShowAnimation(unit, unit.Type->Animations->Still);
142 		unit.Wait--;
143 		return;
144 	}
145 	if (unit.Waiting) {
146 		unit.Anim = unit.WaitBackup;
147 		unit.Waiting = 0;
148 	}
149 
150 	switch (DoActionMove(unit)) {
151 		case PF_FAILED:
152 			this->WaitingCycle = 0;
153 			break;
154 		case PF_UNREACHABLE:
155 			// Increase range and try again
156 			this->WaitingCycle = 1;
157 			this->Range++;
158 			break;
159 
160 		case PF_REACHED:
161 			this->WaitingCycle = 1;
162 			this->Range = 0;
163 			std::swap(this->WayPoint, this->goalPos);
164 
165 			break;
166 		case PF_WAIT:
167 			// Wait for a while then give up
168 			this->WaitingCycle++;
169 			if (this->WaitingCycle == 5) {
170 				this->WaitingCycle = 0;
171 				this->Range = 0;
172 				std::swap(this->WayPoint, this->goalPos);
173 
174 				unit.pathFinderData->output.Cycles = 0; //moving counter
175 			}
176 			break;
177 		default: // moving
178 			this->WaitingCycle = 0;
179 			break;
180 	}
181 
182 	if (!unit.Anim.Unbreakable) {
183 		if (AutoAttack(unit) || AutoRepair(unit) || AutoCast(unit)) {
184 			this->Finished = true;
185 		}
186 	}
187 }
188 
189 /**
190 **  Get goal position
191 */
GetGoalPos() const192 /* virtual */ const Vec2i COrder_Patrol::GetGoalPos() const
193 {
194 	const Vec2i invalidPos(-1, -1);
195 	if (goalPos != invalidPos) {
196 		return goalPos;
197 	}
198 	if (this->HasGoal()) {
199 		return this->GetGoal()->tilePos;
200 	}
201 	return invalidPos;
202 }
203 
204 //@}
205