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_explore.cpp - The explore action. */
12 //
13 //      (c) Copyright 1998-2019 by Lutz Sammer, Jimmy Salmon and Talas
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_explore.h"
39 
40 #include "animation.h"
41 #include "iolib.h"
42 #include "map.h"
43 #include "pathfinder.h"
44 #include "script.h"
45 #include "tile.h"
46 #include "ui.h"
47 #include "unit.h"
48 #include "unittype.h"
49 #include "video.h"
50 
51 /*----------------------------------------------------------------------------
52 --  Functions
53 ----------------------------------------------------------------------------*/
54 
GetExplorationTarget(const CUnit & unit,Vec2i & dest)55 static void GetExplorationTarget(const CUnit &unit, Vec2i &dest)
56 {
57 	int triesLeft = Map.NoFogOfWar ? 0 : 3;
58 	CMapField *field;
59 	const CPlayer &player = *unit.Player;
60 	dest.x = SyncRand(Map.Info.MapWidth - 1) + 1;
61 	dest.y = SyncRand(Map.Info.MapHeight - 1) + 1;
62 
63 	while (triesLeft > 0) {
64 		field = Map.Field(dest);
65 		if (field && !field->playerInfo.IsExplored(player))
66 			return; // unexplored, go here!
67 		dest.x = SyncRand(Map.Info.MapWidth - 1) + 1;
68 		dest.y = SyncRand(Map.Info.MapHeight - 1) + 1;
69 		--triesLeft;
70 	}
71 }
72 
NewActionExplore(const CUnit & unit)73 /* static */ COrder *COrder::NewActionExplore(const CUnit &unit)
74 {
75 	Vec2i dest;
76 	GetExplorationTarget(unit, dest);
77 	Assert(Map.Info.IsPointOnMap(dest));
78 
79 	COrder_Explore *order = new COrder_Explore();
80 
81 	order->goalPos = dest;
82 	return order;
83 }
84 
85 
Save(CFile & file,const CUnit & unit) const86 /* virtual */ void COrder_Explore::Save(CFile &file, const CUnit &unit) const
87 {
88 	file.printf("{\"action-explore\",");
89 
90 	if (this->Finished) {
91 		file.printf(" \"finished\", ");
92 	}
93 	file.printf(" \"tile\", {%d, %d},", this->goalPos.x, this->goalPos.y);
94 	file.printf(" \"range\", %d,", this->Range);
95 
96 	if (this->WaitingCycle != 0) {
97 		file.printf(" \"waiting-cycle\", %d,", this->WaitingCycle);
98 	}
99 	file.printf("}");
100 }
101 
ParseSpecificData(lua_State * l,int & j,const char * value,const CUnit & unit)102 /* virtual */ bool COrder_Explore::ParseSpecificData(lua_State *l, int &j, const char *value, const CUnit &unit)
103 {
104 	if (!strcmp(value, "waiting-cycle")) {
105 		++j;
106 		this->WaitingCycle = LuaToNumber(l, -1, j + 1);
107 	} else if (!strcmp(value, "range")) {
108 		++j;
109 		this->Range = LuaToNumber(l, -1, j + 1);
110 	} else if (!strcmp(value, "tile")) {
111 		++j;
112 		lua_rawgeti(l, -1, j + 1);
113 		CclGetPos(l, &this->goalPos.x , &this->goalPos.y);
114 		lua_pop(l, 1);
115 	} else {
116 		return false;
117 	}
118 	return true;
119 }
120 
IsValid() const121 /* virtual */ bool COrder_Explore::IsValid() const
122 {
123 	return true;
124 }
125 
Show(const CViewport & vp,const PixelPos & lastScreenPos) const126 /* virtual */ PixelPos COrder_Explore::Show(const CViewport &vp, const PixelPos &lastScreenPos) const
127 {
128 	const PixelPos pos1 = vp.TilePosToScreen_Center(this->goalPos);
129 
130 	Video.DrawLineClip(ColorGreen, lastScreenPos, pos1);
131 	Video.FillCircleClip(ColorBlue, pos1, 2);
132 	return pos1;
133 }
134 
UpdatePathFinderData(PathFinderInput & input)135 /* virtual */ void COrder_Explore::UpdatePathFinderData(PathFinderInput &input)
136 {
137 	input.SetMinRange(0);
138 	input.SetMaxRange(this->Range);
139 	const Vec2i tileSize(0, 0);
140 	input.SetGoal(this->goalPos, tileSize);
141 }
142 
143 
Execute(CUnit & unit)144 /* virtual */ void COrder_Explore::Execute(CUnit &unit)
145 {
146 	if (unit.Wait) {
147 		if (!unit.Waiting) {
148 			unit.Waiting = 1;
149 			unit.WaitBackup = unit.Anim;
150 		}
151 		UnitShowAnimation(unit, unit.Type->Animations->Still);
152 		unit.Wait--;
153 		return;
154 	}
155 	if (unit.Waiting) {
156 		unit.Anim = unit.WaitBackup;
157 		unit.Waiting = 0;
158 	}
159 
160 	switch (DoActionMove(unit)) {
161 		case PF_FAILED:
162 			this->WaitingCycle = 0;
163 			break;
164 		case PF_UNREACHABLE:
165 			// Increase range and try again
166 			this->WaitingCycle = 1;
167 			this->Range++;
168 			break;
169 
170 		case PF_REACHED:
171 		{
172 			this->WaitingCycle = 1;
173 			this->Range = 0;
174 			// pick a new place to explore
175 			GetExplorationTarget(unit, this->goalPos);
176 		}
177 			break;
178 		case PF_WAIT:
179 		{
180 			// Wait for a while then give up
181 			this->WaitingCycle++;
182 			if (this->WaitingCycle == 5) {
183 				this->WaitingCycle = 0;
184 				this->Range = 0;
185 				// pick a new place to explore
186 				GetExplorationTarget(unit, this->goalPos);
187 
188 				unit.pathFinderData->output.Cycles = 0; //moving counter
189 			}
190 		}
191 			break;
192 		default: // moving
193 			this->WaitingCycle = 0;
194 			break;
195 	}
196 
197 	if (!unit.Anim.Unbreakable) {
198 		if (AutoAttack(unit) || AutoRepair(unit) || AutoCast(unit)) {
199 			this->Finished = true;
200 		}
201 	}
202 }
203 
204 /**
205 **  Get goal position
206 */
GetGoalPos() const207 /* virtual */ const Vec2i COrder_Explore::GetGoalPos() const
208 {
209 	const Vec2i invalidPos(-1, -1);
210 	if (goalPos != invalidPos) {
211 		return goalPos;
212 	}
213 	if (this->HasGoal()) {
214 		return this->GetGoal()->tilePos;
215 	}
216 	return invalidPos;
217 }
218 
219 //@}
220