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 mapfield.cpp - The map field. */
12 //
13 //      (c) Copyright 2013 by Joris Dauphin
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 "tile.h"
39 
40 #include "fov.h"
41 #include "iolib.h"
42 #include "map.h"
43 #include "player.h"
44 #include "script.h"
45 #include "tileset.h"
46 #include "unit.h"
47 #include "unit_manager.h"
48 
CMapField()49 CMapField::CMapField() :
50 #ifdef DEBUG
51 	tilesetTile(0),
52 #endif
53 	tile(0),
54 	Flags(0),
55 	cost(0),
56 	Value(0),
57 	UnitCache()
58 {}
59 
IsTerrainResourceOnMap(int resource) const60 bool CMapField::IsTerrainResourceOnMap(int resource) const
61 {
62 	// TODO: Hard coded stuff.
63 	if (resource == WoodCost) {
64 		return this->ForestOnMap();
65 	}
66 	return false;
67 }
68 
IsTerrainResourceOnMap() const69 bool CMapField::IsTerrainResourceOnMap() const
70 {
71 	for (int i = 0; i != MaxCosts; ++i) {
72 		if (IsTerrainResourceOnMap(i)) {
73 			return true;
74 		}
75 	}
76 	return false;
77 }
78 
setTileIndex(const CTileset & tileset,unsigned int tileIndex,int value)79 void CMapField::setTileIndex(const CTileset &tileset, unsigned int tileIndex, int value)
80 {
81 	const CTile &tile = tileset.tiles[tileIndex];
82 	this->tile = tile.tile;
83 	this->Value = value;
84 #if 0
85 	this->Flags = tile.flag;
86 #else
87 	this->Flags &= ~(MapFieldOpaque | MapFieldHuman | MapFieldLandAllowed | MapFieldCoastAllowed |
88 					 MapFieldWaterAllowed | MapFieldNoBuilding | MapFieldUnpassable |
89 					 MapFieldWall | MapFieldRocks | MapFieldForest);
90 	this->Flags |= tile.flag;
91 #endif
92 	this->cost = 1 << (tile.flag & MapFieldSpeedMask);
93 #ifdef DEBUG
94 	this->tilesetTile = tileIndex;
95 #endif
96 }
97 
Save(CFile & file) const98 void CMapField::Save(CFile &file) const
99 {
100 	file.printf("  {%3d, %3d, %2d, %2d", tile, playerInfo.SeenTile, Value, cost);
101 	for (int i = 0; i != PlayerMax; ++i) {
102 		if (playerInfo.Visible[i] == 1) {
103 			file.printf(", \"explored\", %d", i);
104 		}
105 	}
106 	if (Flags & MapFieldOpaque) {
107 		file.printf(", \"opaque\"");
108 	}
109 	if (Flags & MapFieldHuman) {
110 		file.printf(", \"human\"");
111 	}
112 	if (Flags & MapFieldLandAllowed) {
113 		file.printf(", \"land\"");
114 	}
115 	if (Flags & MapFieldCoastAllowed) {
116 		file.printf(", \"coast\"");
117 	}
118 	if (Flags & MapFieldWaterAllowed) {
119 		file.printf(", \"water\"");
120 	}
121 	if (Flags & MapFieldNoBuilding) {
122 		file.printf(", \"mud\"");
123 	}
124 	if (Flags & MapFieldUnpassable) {
125 		file.printf(", \"block\"");
126 	}
127 	if (Flags & MapFieldWall) {
128 		file.printf(", \"wall\"");
129 	}
130 	if (Flags & MapFieldRocks) {
131 		file.printf(", \"rock\"");
132 	}
133 	if (Flags & MapFieldForest) {
134 		file.printf(", \"wood\"");
135 	}
136 #if 1
137 	// Not Required for save
138 	// These are required for now, UnitType::FieldFlags is 0 until
139 	// UpdateStats is called which is after the game is loaded
140 	if (Flags & MapFieldLandUnit) {
141 		file.printf(", \"ground\"");
142 	}
143 	if (Flags & MapFieldAirUnit) {
144 		file.printf(", \"air\"");
145 	}
146 	if (Flags & MapFieldSeaUnit) {
147 		file.printf(", \"sea\"");
148 	}
149 	if (Flags & MapFieldBuilding) {
150 		file.printf(", \"building\"");
151 	}
152 #endif
153 	file.printf("}");
154 }
155 
156 
parse(lua_State * l)157 void CMapField::parse(lua_State *l)
158 {
159 	if (!lua_istable(l, -1)) {
160 		LuaError(l, "incorrect argument");
161 	}
162 	const int len = lua_rawlen(l, -1);
163 	if (len < 4) {
164 		LuaError(l, "incorrect argument");
165 	}
166 
167 	this->tile = LuaToNumber(l, -1, 1);
168 	this->playerInfo.SeenTile = LuaToNumber(l, -1, 2);
169 	this->Value = LuaToNumber(l, -1, 3);
170 	this->cost = LuaToNumber(l, -1, 4);
171 
172 	for (int j = 4; j < len; ++j) {
173 		const char *value = LuaToString(l, -1, j + 1);
174 
175 		if (!strcmp(value, "explored")) {
176 			++j;
177 			this->playerInfo.Visible[LuaToNumber(l, -1, j + 1)] = 1;
178 		} else if (!strcmp(value, "opaque")) {
179 			this->Flags |= MapFieldOpaque;
180 		} else if (!strcmp(value, "human")) {
181 			this->Flags |= MapFieldHuman;
182 		} else if (!strcmp(value, "land")) {
183 			this->Flags |= MapFieldLandAllowed;
184 		} else if (!strcmp(value, "coast")) {
185 			this->Flags |= MapFieldCoastAllowed;
186 		} else if (!strcmp(value, "water")) {
187 			this->Flags |= MapFieldWaterAllowed;
188 		} else if (!strcmp(value, "mud")) {
189 			this->Flags |= MapFieldNoBuilding;
190 		} else if (!strcmp(value, "block")) {
191 			this->Flags |= MapFieldUnpassable;
192 		} else if (!strcmp(value, "wall")) {
193 			this->Flags |= MapFieldWall;
194 		} else if (!strcmp(value, "rock")) {
195 			this->Flags |= MapFieldRocks;
196 		} else if (!strcmp(value, "wood")) {
197 			this->Flags |= MapFieldForest;
198 		} else if (!strcmp(value, "ground")) {
199 			this->Flags |= MapFieldLandUnit;
200 		} else if (!strcmp(value, "air")) {
201 			this->Flags |= MapFieldAirUnit;
202 		} else if (!strcmp(value, "sea")) {
203 			this->Flags |= MapFieldSeaUnit;
204 		} else if (!strcmp(value, "building")) {
205 			this->Flags |= MapFieldBuilding;
206 		} else {
207 			LuaError(l, "Unsupported tag: %s" _C_ value);
208 		}
209 	}
210 }
211 
212 /**
213 ** Check if a field is opaque
214 ** We check not only MapFieldOpaque flag because some field types (f.e. forest/rock/wall)
215 ** may be set in the FieldOfView as opaque as well.
216 */
isOpaque() const217 bool CMapField::isOpaque() const
218 {
219 	return (FieldOfView.GetType() == FieldOfViewTypes::cShadowCasting
220 			&& FieldOfView.GetOpaqueFields() & this->Flags);
221 }
222 
223 /// Check if a field flags.
CheckMask(int mask) const224 bool CMapField::CheckMask(int mask) const
225 {
226 	return (this->Flags & mask) != 0;
227 }
228 
229 /// Returns true, if water on the map tile field
WaterOnMap() const230 bool CMapField::WaterOnMap() const
231 {
232 	return CheckMask(MapFieldWaterAllowed);
233 }
234 
235 /// Returns true, if coast on the map tile field
CoastOnMap() const236 bool CMapField::CoastOnMap() const
237 {
238 	return CheckMask(MapFieldCoastAllowed);
239 }
240 
241 /// Returns true, if water on the map tile field
ForestOnMap() const242 bool CMapField::ForestOnMap() const
243 {
244 	return CheckMask(MapFieldForest);
245 }
246 
247 /// Returns true, if coast on the map tile field
RockOnMap() const248 bool CMapField::RockOnMap() const
249 {
250 	return CheckMask(MapFieldRocks);
251 }
252 
253 /// Returns true if the field should not need mixing with the surroundings
isDecorative() const254 bool CMapField::isDecorative() const
255 {
256 	return CheckMask(MapFieldDecorative);
257 }
258 
isAWall() const259 bool CMapField::isAWall() const
260 {
261 	return Flags & MapFieldWall;
262 }
isHuman() const263 bool CMapField::isHuman() const
264 {
265 	return Flags & MapFieldHuman;
266 }
267 
isAHumanWall() const268 bool CMapField::isAHumanWall() const
269 {
270 	const unsigned int humanWallFlag = (MapFieldWall | MapFieldHuman);
271 	return (Flags & humanWallFlag) == humanWallFlag;
272 }
isAOrcWall() const273 bool CMapField::isAOrcWall() const
274 {
275 	const unsigned int humanWallFlag = (MapFieldWall | MapFieldHuman);
276 	return (Flags & humanWallFlag) == MapFieldWall;
277 }
278 
279 //
280 //  CMapFieldPlayerInfo
281 //
282 
TeamVisibilityState(const CPlayer & player) const283 unsigned char CMapFieldPlayerInfo::TeamVisibilityState(const CPlayer &player) const
284 {
285 	if (this->IsVisible(player)) {
286 		return 2;
287 	}
288 	unsigned char maxVision = 0;
289 	if (this->IsExplored(player)) {
290 		maxVision = 1;
291 	}
292 
293 	for (const uint8_t p : player.GetSharedVision()) {
294 		maxVision = std::max<uint8_t>(maxVision, this->Visible[p]);
295 		if (maxVision >= 2) {
296 			return 2;
297 		}
298 	}
299 
300 	if (maxVision == 1 && Map.NoFogOfWar) {
301 		return 2;
302 	}
303 	return maxVision;
304 }
305 
IsExplored(const CPlayer & player) const306 bool CMapFieldPlayerInfo::IsExplored(const CPlayer &player) const
307 {
308 	return this->Visible[player.Index] != 0;
309 }
310 
IsVisible(const CPlayer & player) const311 bool CMapFieldPlayerInfo::IsVisible(const CPlayer &player) const
312 {
313 	const bool fogOfWar = !Map.NoFogOfWar;
314 	return this->Visible[player.Index] >= 2 || (!fogOfWar && IsExplored(player));
315 }
316 
IsTeamVisible(const CPlayer & player) const317 bool CMapFieldPlayerInfo::IsTeamVisible(const CPlayer &player) const
318 {
319 	return this->TeamVisibilityState(player) == 2;
320 }
321 
322 //@}
323