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 script_map.cpp - The map ccl functions. */
12 //
13 //      (c) Copyright 1999-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 "map.h"
39 #include "fov.h"
40 #include "fow.h"
41 #include "iolib.h"
42 #include "netconnect.h"
43 #include "network.h"
44 #include "script.h"
45 #include "tileset.h"
46 #include "translate.h"
47 #include "ui.h"
48 #include "unit.h"
49 #include "version.h"
50 #include "video.h"
51 
52 /*----------------------------------------------------------------------------
53 --  Variables
54 ----------------------------------------------------------------------------*/
55 
56 /*----------------------------------------------------------------------------
57 --  Functions
58 ----------------------------------------------------------------------------*/
59 
60 /**
61 **  Parse a map.
62 **
63 **  @param l  Lua state.
64 */
CclStratagusMap(lua_State * l)65 static int CclStratagusMap(lua_State *l)
66 {
67 	int args = lua_gettop(l);
68 	for (int j = 0; j < args; ++j) {
69 		const char *value = LuaToString(l, j + 1);
70 		++j;
71 
72 		if (!strcmp(value, "version")) {
73 			char buf[32];
74 
75 			const char *version = LuaToString(l, j + 1);
76 			strncpy(buf, VERSION, sizeof(buf));
77 			if (strcmp(buf, version)) {
78 				fprintf(stderr, "Warning not saved with this version.\n");
79 			}
80 		} else if (!strcmp(value, "uid")) {
81 			Map.Info.MapUID = LuaToNumber(l, j + 1);
82 		} else if (!strcmp(value, "description")) {
83 			Map.Info.Description = LuaToString(l, j + 1);
84 		} else if (!strcmp(value, "the-map")) {
85 			if (!lua_istable(l, j + 1)) {
86 				LuaError(l, "incorrect argument");
87 			}
88 			int subargs = lua_rawlen(l, j + 1);
89 			for (int k = 0; k < subargs; ++k) {
90 				const char *value = LuaToString(l, j + 1, k + 1);
91 				++k;
92 
93 				if (!strcmp(value, "size")) {
94 					lua_rawgeti(l, j + 1, k + 1);
95 					CclGetPos(l, &Map.Info.MapWidth, &Map.Info.MapHeight);
96 					lua_pop(l, 1);
97 
98 					delete[] Map.Fields;
99 					Map.Fields = new CMapField[Map.Info.MapWidth * Map.Info.MapHeight];
100 					// FIXME: this should be CreateMap or InitMap?
101 				} else if (!strcmp(value, "fog-of-war")) {
102 					Map.NoFogOfWar = false;
103 					--k;
104 				} else if (!strcmp(value, "no-fog-of-war")) {
105 					Map.NoFogOfWar = true;
106 					--k;
107 				} else if (!strcmp(value, "filename")) {
108 					Map.Info.Filename = LuaToString(l, j + 1, k + 1);
109 				} else if (!strcmp(value, "map-fields")) {
110 					lua_rawgeti(l, j + 1, k + 1);
111 					if (!lua_istable(l, -1)) {
112 						LuaError(l, "incorrect argument");
113 					}
114 					const int subsubargs = lua_rawlen(l, -1);
115 					if (subsubargs != Map.Info.MapWidth * Map.Info.MapHeight) {
116 						fprintf(stderr, "Wrong tile table length: %d\n", subsubargs);
117 					}
118 					for (int i = 0; i < subsubargs; ++i) {
119 						lua_rawgeti(l, -1, i + 1);
120 						if (!lua_istable(l, -1)) {
121 							LuaError(l, "incorrect argument");
122 						}
123 						Map.Fields[i].parse(l);
124 						lua_pop(l, 1);
125 					}
126 					lua_pop(l, 1);
127 				} else {
128 					LuaError(l, "Unsupported tag: %s" _C_ value);
129 				}
130 			}
131 		} else {
132 			LuaError(l, "Unsupported tag: %s" _C_ value);
133 		}
134 	}
135 	return 0;
136 }
137 
138 /**
139 **  Reveal the complete map.
140 **
141 **  @param l  Lua state.
142 */
CclRevealMap(lua_State * l)143 static int CclRevealMap(lua_State *l)
144 {
145 	LuaCheckArgs(l, 1);
146 
147 	int newMode;
148 	const char *revealMode = LuaToString(l, 1);
149 	if (!strcmp(revealMode, "hidden")) {
150 		newMode = MapRevealModes::cHidden;
151 	} else 	if (!strcmp(revealMode, "known")) {
152 		newMode = MapRevealModes::cKnown;
153 	} else if (!strcmp(revealMode, "explored")) {
154 		newMode = MapRevealModes::cExplored;
155 	} else {
156 		PrintFunction();
157 		fprintf(stdout, "Accessible reveal modes: \"hidden\", \"known\", \"explored\".\n");
158 		return 1;
159 	}
160 
161 	if (CclInConfigFile || !Map.Fields) {
162 		FlagRevealMap = newMode;
163 	} else if (!IsNetworkGame()) {
164 		Map.Reveal(newMode);
165 	} else {
166 		NetworkSendExtendedCommand(ExtendedMessageRevealMapDB, int(newMode), 0, 0, 0, 0);
167 	}
168 	return 0;
169 }
170 
171 /**
172 ** <b>Description</b>
173 **
174 **  Center the map.
175 **
176 **  @param l  Lua state.
177 **
178 ** Example:
179 **
180 ** <div class="example"><code>-- Center the view at position x=11 and y=1.
181 **		  <strong>CenterMap</strong>(11, 1)</code></div>
182 */
CclCenterMap(lua_State * l)183 static int CclCenterMap(lua_State *l)
184 {
185 	LuaCheckArgs(l, 2);
186 	const Vec2i pos(LuaToNumber(l, 1), LuaToNumber(l, 2));
187 
188 	UI.SelectedViewport->Center(Map.TilePosToMapPixelPos_Center(pos));
189 	return 0;
190 }
191 
192 /**
193 ** <b>Description</b>
194 **
195 **  Define the starting viewpoint for a given player.
196 **
197 **  @param l  Lua state.
198 **
199 ** Example:
200 **
201 ** <div class="example"><code>-- Start view for player 0.
202 **		  <strong>SetStartView</strong>(0, 25, 12)
203 **		  -- Start view for player 1.
204 **		  <strong>SetStartView</strong>(1, 71, 38)</code></div>
205 */
CclSetStartView(lua_State * l)206 static int CclSetStartView(lua_State *l)
207 {
208 	LuaCheckArgs(l, 3);
209 
210 	const int p = LuaToNumber(l, 1);
211 	Players[p].StartPos.x = LuaToNumber(l, 2);
212 	Players[p].StartPos.y = LuaToNumber(l, 3);
213 
214 	return 0;
215 }
216 
217 /**
218 **  Show Map Location
219 **
220 **  @param l  Lua state.
221 */
CclShowMapLocation(lua_State * l)222 static int CclShowMapLocation(lua_State *l)
223 {
224 	// Put a unit on map, use its properties, except for
225 	// what is listed below
226 
227 	LuaCheckArgs(l, 5);
228 	const char *unitname = LuaToString(l, 5);
229 	CUnitType *unitType = UnitTypeByIdent(unitname);
230 	if (!unitType) {
231 		DebugPrint("Unable to find UnitType '%s'" _C_ unitname);
232 		return 0;
233 	}
234 	CUnit *target = MakeUnit(*unitType, ThisPlayer);
235 	if (target != NULL) {
236 		target->Variable[HP_INDEX].Value = 0;
237 		target->tilePos.x = LuaToNumber(l, 1);
238 		target->tilePos.y = LuaToNumber(l, 2);
239 		target->TTL = GameCycle + LuaToNumber(l, 4);
240 		target->CurrentSightRange = LuaToNumber(l, 3);
241 		MapMarkUnitSight(*target);
242 	} else {
243 		DebugPrint("Unable to allocate Unit");
244 	}
245 	return 0;
246 }
247 
248 /**
249 ** <b>Description</b>
250 **
251 **  Set fog of war on/off.
252 **
253 ** Example:
254 **
255 ** <div class="example"><code><strong>SetFogOfWar</strong>(true)</code></div>
256 **
257 **  @param l  Lua state.
258 */
CclSetFogOfWar(lua_State * l)259 static int CclSetFogOfWar(lua_State *l)
260 {
261 
262 	LuaCheckArgs(l, 1);
263 	Map.NoFogOfWar = !LuaToBoolean(l, 1);
264 	if (!CclInConfigFile && Map.Fields) {
265 		UpdateFogOfWarChange();
266 		// FIXME: save setting in replay log
267 		//CommandLog("input", NoUnitP, FlushCommands, -1, -1, NoUnitP, "fow off", -1);
268 	}
269 	return 0;
270 }
271 
272 /**
273 ** <b>Description</b>
274 **
275 **  Get if the fog of war is enabled.
276 **
277 **  @param l  Lua state.
278 **
279 ** Example:
280 **
281 ** <div class="example"><code><strong>GetFogOfWar</strong>()</code></div>
282 */
CclGetFogOfWar(lua_State * l)283 static int CclGetFogOfWar(lua_State *l)
284 {
285 	LuaCheckArgs(l, 0);
286 	lua_pushboolean(l, !Map.NoFogOfWar);
287 	return 1;
288 }
289 
290 /**
291 ** <b>Description</b>
292 **
293 **  Enable display of terrain in minimap.
294 **
295 **  @param l  Lua state.
296 **
297 ** Example:
298 **
299 ** <div class="example"><code>-- Show the minimap terrain
300 **		<strong>SetMinimapTerrain</strong>(true)</code></div>
301 */
CclSetMinimapTerrain(lua_State * l)302 static int CclSetMinimapTerrain(lua_State *l)
303 {
304 	LuaCheckArgs(l, 1);
305 	UI.Minimap.WithTerrain = LuaToBoolean(l, 1);
306 	return 0;
307 }
308 
309 /**
310 **  Activate map grid  (true|false)
311 **
312 **  @param l  Lua state.
313 **
314 **  @return   0 for success, 1 for wrong type;
315 */
CclSetEnableMapGrid(lua_State * l)316 static int CclSetEnableMapGrid(lua_State *l)
317 {
318 	LuaCheckArgs(l, 1);
319 	CViewport::EnableGrid(LuaToBoolean(l, 1));
320 	return 0;
321 }
322 
323 /**
324 **  Check if map grid is enabled
325 */
CclGetIsMapGridEnabled(lua_State * l)326 static int CclGetIsMapGridEnabled(lua_State *l)
327 {
328 	LuaCheckArgs(l, 0);
329 	lua_pushboolean(l, CViewport::isGridEnabled());
330 	return 1;
331 }
332 
333 /**
334 **  Select unit's field of view algorithm -  ShadowCasting or SimpleRadial
335 **
336 **  @param l  Lua state.
337 **
338 **  @return   0 for success, 1 for wrong type;
339 */
CclSetFieldOfViewType(lua_State * l)340 static int CclSetFieldOfViewType(lua_State *l)
341 {
342 	LuaCheckArgs(l, 1);
343 
344 	FieldOfViewTypes new_type;
345 	const char *type_name = LuaToString(l, 1);
346 	if (!strcmp(type_name, "shadow-casting")) {
347 		new_type = FieldOfViewTypes::cShadowCasting;
348 		/// Tiled types of FOW don't work with shadow casting
349 		if (FogOfWar.GetType() != FogOfWarTypes::cEnhanced) {
350 			FogOfWar.SetType(FogOfWarTypes::cEnhanced);
351 		}
352 	} else if (!strcmp(type_name, "simple-radial")) {
353 		new_type = FieldOfViewTypes::cSimpleRadial;
354 	} else {
355 		PrintFunction();
356 		fprintf(stdout, "Accessible Field of View types: \"shadow-casting\", \"simple-radial\".\n");
357 		return 1;
358 	}
359 	if (!IsNetworkGame()) {
360 		FieldOfView.SetType(new_type);
361 	} else {
362 		NetworkSendExtendedCommand(ExtendedMessageFieldOfViewDB, int(new_type), 0, 0, 0, 0);
363 	}
364 	return 0;
365 }
366 
367 /**
368 **  Get unit's field of view type -  ShadowCasting or SimpleRadial
369 */
CclGetFieldOfViewType(lua_State * l)370 static int CclGetFieldOfViewType(lua_State *l)
371 {
372 	LuaCheckArgs(l, 0);
373 	lua_pushinteger(l, int(FieldOfView.GetType()));
374 	return 1;
375 }
376 
377 /**
378 **  Set opaque for the tile's terrain.
379 **
380 **  @param l  Lua state.
381 **
382 **  @return   0 for success, 1 for wrong tile's terrain;
383 */
CclSetOpaqueFor(lua_State * l)384 static int CclSetOpaqueFor(lua_State *l)
385 {
386 	uint16_t new_flag = 0;
387 	const int args = lua_gettop(l);
388 	if (args < 1) {
389 		LuaError(l, "argument missed");
390 		return 1;
391 	}
392 	for (int arg = 0; arg < args; ++arg) {
393 		const char *flag_name = LuaToString(l, arg + 1);
394 		if (!strcmp(flag_name, "wall")) {
395 			new_flag |= MapFieldWall;
396 		} else if (!strcmp(flag_name, "rock")) {
397 			new_flag |= MapFieldRocks;
398 		} else if (!strcmp(flag_name, "forest")) {
399 			new_flag |= MapFieldForest;
400 		} else {
401 			PrintFunction();
402 			fprintf(stdout, "Opaque can only be set for \"wall\", \"rock\" or \"forest\". \n");
403 			return 1;
404 		}
405 	}
406 	if (!IsNetworkGame()) {
407 		FieldOfView.SetOpaqueFields(FieldOfView.GetOpaqueFields() | new_flag);
408 	} else {
409 		NetworkSendExtendedCommand(ExtendedMessageMapFieldsOpacityDB, 0,
410 								   FieldOfView.GetOpaqueFields() | new_flag, 0, 0, 0);
411 	}
412 	return 0;
413 }
414 /**
415 **  Check opacity for the tile's terrain.
416 **
417 **  @param l  Lua state.
418 **
419 */
CclGetIsOpaqueFor(lua_State * l)420 static int CclGetIsOpaqueFor(lua_State *l)
421 {
422 	LuaCheckArgs(l, 1);
423 
424 	uint16_t flagToCheck = 0;
425 	const char *flag_name = LuaToString(l, 1);
426 	if (!strcmp(flag_name, "wall")) {
427 		flagToCheck = MapFieldWall;
428 	} else if (!strcmp(flag_name, "rock")) {
429 		flagToCheck = MapFieldRocks;
430 	} else if (!strcmp(flag_name, "forest")) {
431 		flagToCheck = MapFieldForest;
432 	} else {
433 		PrintFunction();
434 		fprintf(stdout, "Opaque can only be checked for \"wall\", \"rock\" or \"forest\". \n");
435 	}
436 
437 	lua_pushboolean(l, FieldOfView.GetOpaqueFields() & flagToCheck);
438 	return 1;
439 }
440 
CclRemoveOpaqueFor(lua_State * l)441 static int CclRemoveOpaqueFor(lua_State *l)
442 {
443 	unsigned short new_flag = 0;
444 	const int args = lua_gettop(l);
445 	if (args < 1) {
446 		LuaError(l, "argument missed");
447 		return 1;
448 	}
449 	for (int arg = 0; arg < args; ++arg) {
450 		const char *flag_name = LuaToString(l, arg + 1);
451 		if (!strcmp(flag_name, "wall")) {
452 			new_flag |= MapFieldWall;
453 		} else if (!strcmp(flag_name, "rock")) {
454 			new_flag |= MapFieldRocks;
455 		} else if (!strcmp(flag_name, "forest")) {
456 			new_flag |= MapFieldForest;
457 		} else {
458 			PrintFunction();
459 			fprintf(stdout, "Opaque can only be removed for \"wall\", \"rock\" or \"forest\". \n");
460 			return 1;
461 		}
462 	}
463 	if (!IsNetworkGame()) {
464 		FieldOfView.SetOpaqueFields(FieldOfView.GetOpaqueFields() & ~new_flag);
465 	} else {
466 		NetworkSendExtendedCommand(ExtendedMessageMapFieldsOpacityDB, 0,
467 								   FieldOfView.GetOpaqueFields() & ~new_flag, 0, 0, 0);
468 	}
469 	return 0;
470 }
471 
472 
473 /**
474 **  Select which type of Fog of War to use
475 **
476 **  @param l  Lua state.
477 **
478 **  @return   0 for success, 1 for wrong type;
479 */
CclSetFogOfWarType(lua_State * l)480 static int CclSetFogOfWarType(lua_State *l)
481 {
482 	LuaCheckArgs(l, 1);
483 
484 	FogOfWarTypes new_type;
485 	const std::string type_name {LuaToString(l, 1)};
486 	if (type_name == "tiled" || type_name == "fast") {
487 		new_type = type_name == "tiled" ? FogOfWarTypes::cTiled : FogOfWarTypes::cTiledLegacy;
488 		/// Tiled types of FOW don't work with shadow casting
489 		if (FieldOfView.GetType() == FieldOfViewTypes::cShadowCasting) {
490 			if (!IsNetworkGame()) {
491 				FieldOfView.SetType(FieldOfViewTypes::cSimpleRadial);
492 			} else {
493 				NetworkSendExtendedCommand(ExtendedMessageFieldOfViewDB,
494 										   int(FieldOfViewTypes::cSimpleRadial), 0, 0, 0, 0);
495 			}
496 		}
497 	} else if (type_name == "enhanced") {
498 		new_type = FogOfWarTypes::cEnhanced;
499 	} else {
500 		PrintFunction();
501 		fprintf(stdout, "Accessible Fog of War types: \"tiled\", \"enhanced\" and \"fast\".\n");
502 		return 1;
503 	}
504 	FogOfWar.SetType(new_type);
505 	return 0;
506 }
507 
508 /**
509 **  Get Fog of War type - legacy or enhanced
510 */
CclGetFogOfWarType(lua_State * l)511 static int CclGetFogOfWarType(lua_State *l)
512 {
513 	LuaCheckArgs(l, 0);
514 	lua_pushinteger(l, int(FogOfWar.GetType()));
515 	return 1;
516 }
517 
518 /**
519 **  Set opacity (alpha) for different levels of fog of war - explored, revealed, unseen
520 **
521 **  @param l  Lua state.
522 **
523 **  @return   0 for success, 1 for wrong type;
524 */
CclSetFogOfWarOpacityLevels(lua_State * l)525 static int CclSetFogOfWarOpacityLevels(lua_State *l)
526 {
527 	LuaCheckArgs(l, 3);
528 	const int explored = LuaToNumber(l, 1);
529 	if (explored <= 0 || explored > 255) {
530 		PrintFunction();
531 		fprintf(stderr, "Invalid value (%d) of opacity for Explored tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", explored);
532 		return 1;
533 	}
534 	const int revealed = LuaToNumber(l, 2);
535 	if (revealed <= explored || revealed > 255) {
536 		PrintFunction();
537 		fprintf(stderr, "Invalid value (%d) of opacity for Revealed tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", revealed);
538 		return 1;
539 	}
540 	const int unseen = LuaToNumber(l, 3);
541 	if (unseen < revealed || unseen > 255) {
542 		PrintFunction();
543 		fprintf(stderr, "Invalid value (%d) of opacity for Unseen tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", unseen);
544 		return 1;
545 	}
546 
547 	FogOfWar.SetOpacityLevels(explored, revealed, unseen);
548 
549 	return 0;
550 }
551 
552 /**
553 **  Set parameters for FOW blurer (radiuses and number of iterations)
554 **
555 **  @param l  Lua state.
556 **
557 **  @return   0 for success, 1 for wrong type;
558 */
CclSetFogOfWarBlur(lua_State * l)559 static int CclSetFogOfWarBlur(lua_State *l)
560 {
561 	LuaCheckArgs(l, 3);
562 
563 	const float radiusSimple = LuaToFloat(l, 1);
564 	if (radiusSimple <= 0 ) {
565 		PrintFunction();
566 		fprintf(stdout, "Radius should be a positive float number. Blur is disabled.\n");
567 	}
568 
569 	const float radiusBilinear = LuaToFloat(l, 2);
570 	if (radiusBilinear <= 0 ) {
571 		PrintFunction();
572 		fprintf(stdout, "Radius should be a positive float number. Blur is disabled.\n");
573 	}
574 
575 	const int iterations = LuaToNumber(l, 3);
576 	if (iterations <= 0 ) {
577 		PrintFunction();
578 		fprintf(stdout, "Number of box blur iterations should be greater than 0. Blur is disabled.\n");
579 	}
580 	FogOfWar.InitBlurer(radiusSimple, radiusBilinear, iterations);
581 	return 0;
582 }
583 
584 /**
585 **  Activate FOW bilinear upscaling type  (true|false)
586 **
587 **  @param l  Lua state.
588 **
589 **  @return   0 for success, 1 for wrong type;
590 */
CclSetFogOfWarBilinear(lua_State * l)591 static int CclSetFogOfWarBilinear(lua_State *l)
592 {
593 	LuaCheckArgs(l, 1);
594 	FogOfWar.EnableBilinearUpscale(LuaToBoolean(l, 1));
595 	return 0;
596 }
597 
598 /**
599 **  Check if FOW bilinear upscaling enabled
600 */
CclGetIsFogOfWarBilinear(lua_State * l)601 static int CclGetIsFogOfWarBilinear(lua_State *l)
602 {
603 	LuaCheckArgs(l, 0);
604 	lua_pushboolean(l, FogOfWar.IsBilinearUpscaleEnabled());
605 	return 1;
606 }
607 
608 /**
609 ** <b>Description</b>
610 **
611 **  Set forest regeneration speed.
612 **
613 **  @param l  Lua state.
614 **
615 **  @return   Old speed
616 **
617 ** Example:
618 **
619 ** <div class="example"><code>-- No regeneration.
620 **		  <strong>SetForestRegeneration</strong>(0)
621 **		  -- Slow regeneration every 50 seconds
622 **		  <strong>SetForestRegeneration</strong>(50)
623 **		  -- Extremely slow regeneration every 1h of game time
624 **		  <strong>SetForestRegeneration</strong>(3600)</code></div>
625 */
CclSetForestRegeneration(lua_State * l)626 static int CclSetForestRegeneration(lua_State *l)
627 {
628 	LuaCheckArgs(l, 1);
629 	int i = LuaToNumber(l, 1);
630 	int frequency = 1;
631 	if (i < 0) {
632 		LuaError(l, "Regeneration speed should be >= 0\n");
633 	}
634 	while (i / frequency > 255) {
635 		frequency++;
636 	}
637 	i = i / frequency;
638 	const int old = ForestRegeneration * ForestRegenerationFrequency;
639 	ForestRegeneration = i;
640 	ForestRegenerationFrequency = frequency;
641 
642 	lua_pushnumber(l, old);
643 	return 1;
644 }
645 
646 /**
647 ** <b>Description</b>
648 **
649 **  Set Fog color.
650 **
651 **  @param l  Lua state.
652 **
653 ** Example:
654 **
655 ** <div class="example"><code>-- Red fog of war
656 **		<strong>SetFogOfWarColor</strong>(128,0,0)</code></div>
657 */
CclSetFogOfWarColor(lua_State * l)658 static int CclSetFogOfWarColor(lua_State *l)
659 {
660 	LuaCheckArgs(l, 3);
661 	int r = LuaToNumber(l, 1);
662 	int g = LuaToNumber(l, 2);
663 	int b = LuaToNumber(l, 3);
664 
665 	if ((r < 0 || r > 255) ||
666 		(g < 0 || g > 255) ||
667 		(b < 0 || b > 255)) {
668 		LuaError(l, "Arguments must be in the range 0-255");
669 	}
670 
671 	FogOfWar.SetFogColor(r, g, b);
672 
673 	return 0;
674 }
675 
676 /**
677 **  Define Fog graphics
678 **
679 **  @param l  Lua state.
680 */
CclSetFogOfWarGraphics(lua_State * l)681 static int CclSetFogOfWarGraphics(lua_State *l)
682 {
683 	std::string FogGraphicFile;
684 
685 	LuaCheckArgs(l, 1);
686 	FogGraphicFile = LuaToString(l, 1);
687 	CFogOfWar::SetTiledFogGraphic(FogGraphicFile);
688 
689 	return 0;
690 }
691 
692 
693 /**
694 **  Set opacity (alpha) for different levels of fog of war - explored, revealed, unexplored for mini map
695 **
696 **  @param l  Lua state.
697 **
698 **  @return   0 for success, 1 for wrong type;
699 */
CclSetMMFogOfWarOpacityLevels(lua_State * l)700 static int CclSetMMFogOfWarOpacityLevels(lua_State *l)
701 {
702 	LuaCheckArgs(l, 3);
703 	const int explored = LuaToNumber(l, 1);
704 	if (explored <= 0 || explored > 255) {
705 		PrintFunction();
706 		fprintf(stderr, "Invalid value (%d) of opacity for Minimap's Explored tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", explored);
707 		return 1;
708 	}
709 	const int revealed = LuaToNumber(l, 2);
710 	if (revealed <= explored || revealed > 255) {
711 		PrintFunction();
712 		fprintf(stderr, "Invalid value (%d) of opacity for Minimap's  Revealed tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", revealed);
713 		return 1;
714 	}
715 	const int unseen = LuaToNumber(l, 3);
716 	if (unseen < revealed || unseen > 255) {
717 		PrintFunction();
718 		fprintf(stderr, "Invalid value (%d) of opacity for Minimap's Unseen tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", unseen);
719 		return 1;
720 	}
721 
722 	UI.Minimap.SetFogOpacityLevels(explored, revealed, unseen);
723 
724 	return 0;
725 }
726 
727 /**
728 ** <b>Description</b>
729 **
730 **  Define size in pixels (x,y) of a tile in this game
731 **
732 **  @param l  Lua state.
733 **
734 ** Example:
735 **
736 ** <div class="example"><code><strong>SetTileSize</strong>(32,32)</code></div>
737 */
CclSetTileSize(lua_State * l)738 static int CclSetTileSize(lua_State *l)
739 {
740 	LuaCheckArgs(l, 2);
741 	PixelTileSize.x = LuaToNumber(l, 1);
742 	PixelTileSize.y = LuaToNumber(l, 2);
743 	return 0;
744 }
745 
746 /**
747 **  Set a tile
748 **
749 **  @param tileIndex   Tile number
750 **  @param pos    coordinate
751 **  @param value  Value of the tile
752 */
SetTile(unsigned int tileIndex,const Vec2i & pos,int value)753 void SetTile(unsigned int tileIndex, const Vec2i &pos, int value)
754 {
755 	if (!Map.Info.IsPointOnMap(pos)) {
756 		fprintf(stderr, "Invalid map coordonate : (%d, %d)\n", pos.x, pos.y);
757 		return;
758 	}
759 	if (Map.Tileset->getTileCount() <= tileIndex) {
760 		fprintf(stderr, "Invalid tile number: %u\n", tileIndex);
761 		return;
762 	}
763 	if (value < 0 || value >= 256) {
764 		fprintf(stderr, "Invalid tile number: %u\n", tileIndex);
765 		return;
766 	}
767 
768 	if (Map.Fields) {
769 		CMapField &mf = *Map.Field(pos);
770 
771 		mf.setTileIndex(*Map.Tileset, tileIndex, value);
772 	}
773 }
774 
775 /**
776 **  Define the type of each player available for the map
777 **
778 **  @param l  Lua state.
779 */
CclDefinePlayerTypes(lua_State * l)780 static int CclDefinePlayerTypes(lua_State *l)
781 {
782 	int numplayers = lua_gettop(l); /* Number of players == number of arguments */
783 	if (numplayers < 2) {
784 		LuaError(l, "Not enough players");
785 	}
786 
787 	for (int i = 0; i < numplayers && i < PlayerMax; ++i) {
788 		if (lua_isnil(l, i + 1)) {
789 			numplayers = i;
790 			break;
791 		}
792 		const char *type = LuaToString(l, i + 1);
793 		if (!strcmp(type, "neutral")) {
794 			Map.Info.PlayerType[i] = PlayerNeutral;
795 		} else if (!strcmp(type, "nobody")) {
796 			Map.Info.PlayerType[i] = PlayerNobody;
797 		} else if (!strcmp(type, "computer")) {
798 			Map.Info.PlayerType[i] = PlayerComputer;
799 		} else if (!strcmp(type, "person")) {
800 			Map.Info.PlayerType[i] = PlayerPerson;
801 		} else if (!strcmp(type, "rescue-passive")) {
802 			Map.Info.PlayerType[i] = PlayerRescuePassive;
803 		} else if (!strcmp(type, "rescue-active")) {
804 			Map.Info.PlayerType[i] = PlayerRescueActive;
805 		} else {
806 			LuaError(l, "Unsupported tag: %s" _C_ type);
807 		}
808 	}
809 	for (int i = numplayers; i < PlayerMax - 1; ++i) {
810 		Map.Info.PlayerType[i] = PlayerNobody;
811 	}
812 	if (numplayers < PlayerMax) {
813 		Map.Info.PlayerType[PlayerMax - 1] = PlayerNeutral;
814 	}
815 	return 0;
816 }
817 
818 /**
819 ** Load the lua file which will define the tile models
820 **
821 **  @param l  Lua state.
822 */
CclLoadTileModels(lua_State * l)823 static int CclLoadTileModels(lua_State *l)
824 {
825 	if (lua_gettop(l) != 1) {
826 		LuaError(l, "incorrect argument");
827 	}
828 	Map.TileModelsFileName = LuaToString(l, 1);
829 	const std::string filename = LibraryFileName(Map.TileModelsFileName.c_str());
830 	if (LuaLoadFile(filename) == -1) {
831 		DebugPrint("Load failed: %s\n" _C_ filename.c_str());
832 	}
833 	return 0;
834 }
835 
836 /**
837 **  Define tileset
838 **
839 **  @param l  Lua state.
840 */
CclDefineTileset(lua_State * l)841 static int CclDefineTileset(lua_State *l)
842 {
843 	Map.Tileset->parse(l);
844 
845 	//  Load and prepare the tileset
846 	PixelTileSize = Map.Tileset->getPixelTileSize();
847 
848 	ShowLoadProgress(_("Tileset '%s'"), Map.Tileset->ImageFile.c_str());
849 	Map.TileGraphic = CGraphic::New(Map.Tileset->ImageFile, PixelTileSize.x, PixelTileSize.y);
850 	Map.TileGraphic->Load();
851 	return 0;
852 }
853 /**
854 ** Build tileset tables like humanWallTable or mixedLookupTable
855 **
856 ** Called after DefineTileset and only for tilesets that have wall,
857 ** trees and rocks. This function will be deleted when removing
858 ** support of walls and alike in the tileset.
859 */
CclBuildTilesetTables(lua_State * l)860 static int CclBuildTilesetTables(lua_State *l)
861 {
862 	LuaCheckArgs(l, 0);
863 
864 	Map.Tileset->buildTable(l);
865 	return 0;
866 }
867 /**
868 **  Set the flags like "water" for a tile of a tileset
869 **
870 **  @param l  Lua state.
871 */
CclSetTileFlags(lua_State * l)872 static int CclSetTileFlags(lua_State *l)
873 {
874 	if (lua_gettop(l) < 2) {
875 		LuaError(l, "No flags defined");
876 	}
877 	const unsigned int tilenumber = LuaToNumber(l, 1);
878 
879 	if (tilenumber >= Map.Tileset->tiles.size()) {
880 		LuaError(l, "Accessed a tile that's not defined");
881 	}
882 	int j = 0;
883 	int flags = 0;
884 
885 	unsigned char newBase = Map.Tileset->parseTilesetTileFlags(l, &flags, &j);
886 	Map.Tileset->tiles[tilenumber].flag = flags;
887 	if (newBase) {
888 		Map.Tileset->tiles[tilenumber].tileinfo.BaseTerrain = newBase;
889 	}
890 	return 0;
891 }
892 
893 /**
894 **  Get the name of the terrain of the tile.
895 **
896 **  @param l  Lua state.
897 **
898 **  @return   The name of the terrain of the tile.
899 */
CclGetTileTerrainName(lua_State * l)900 static int CclGetTileTerrainName(lua_State *l)
901 {
902 	LuaCheckArgs(l, 2);
903 
904 	const Vec2i pos(LuaToNumber(l, 1), LuaToNumber(l, 2));
905 
906 	const CMapField &mf = *Map.Field(pos);
907 	const CTileset &tileset = *Map.Tileset;
908 	const int index = tileset.findTileIndexByTile(mf.getGraphicTile());
909 	Assert(index != -1);
910 	const int baseTerrainIdx = tileset.tiles[index].tileinfo.BaseTerrain;
911 
912 	lua_pushstring(l, tileset.getTerrainName(baseTerrainIdx).c_str());
913 	return 1;
914 }
915 
916 /**
917 **  Check if the tile's terrain has a particular flag.
918 **
919 **  @param l  Lua state.
920 **
921 **  @return   True if has the flag, false if not.
922 */
CclGetTileTerrainHasFlag(lua_State * l)923 static int CclGetTileTerrainHasFlag(lua_State *l)
924 {
925 	LuaCheckArgs(l, 3);
926 
927 	const Vec2i pos(LuaToNumber(l, 1), LuaToNumber(l, 2));
928 
929 	unsigned short flag = 0;
930 	const char *flag_name = LuaToString(l, 3);
931 	if (!strcmp(flag_name, "opaque")) {
932 		flag = MapFieldOpaque;
933 	} else if (!strcmp(flag_name, "water")) {
934 		flag = MapFieldWaterAllowed;
935 	} else if (!strcmp(flag_name, "land")) {
936 		flag = MapFieldLandAllowed;
937 	} else if (!strcmp(flag_name, "coast")) {
938 		flag = MapFieldCoastAllowed;
939 	} else if (!strcmp(flag_name, "no-building")) {
940 		flag = MapFieldNoBuilding;
941 	} else if (!strcmp(flag_name, "unpassable")) {
942 		flag = MapFieldUnpassable;
943 	} else if (!strcmp(flag_name, "wall")) {
944 		flag = MapFieldWall;
945 	} else if (!strcmp(flag_name, "rock")) {
946 		flag = MapFieldRocks;
947 	} else if (!strcmp(flag_name, "forest")) {
948 		flag = MapFieldForest;
949 	}
950 
951 	const CMapField &mf = *Map.Field(pos);
952 
953 	if (mf.getFlag() & flag) {
954 		lua_pushboolean(l, 1);
955 	} else {
956 		lua_pushboolean(l, 0);
957 	}
958 
959 	return 1;
960 }
961 
962 /**
963 **  Enable walls enabled for single player games (for debug purposes)
964 **
965 **  @param l  Lua state.
966 **
967 **  @return   0 for success, 1 for wrong type;
968 */
CclSetEnableWallsForSP(lua_State * l)969 static int CclSetEnableWallsForSP(lua_State *l)
970 {
971 	LuaCheckArgs(l, 1);
972 	EnableWallsInSinglePlayer = LuaToBoolean(l, 1);
973 	return 0;
974 }
975 
976 /**
977 **  Check if walls enabled for single player games (for debug purposes)
978 */
CclIsWallsEnabledForSP(lua_State * l)979 static int CclIsWallsEnabledForSP(lua_State *l)
980 {
981 	LuaCheckArgs(l, 0);
982 	lua_pushboolean(l, EnableWallsInSinglePlayer);
983 	return 1;
984 }
985 
986 /**
987 **  Check if network game was created on this PC
988 */
CclGetIsGameHoster(lua_State * l)989 static int CclGetIsGameHoster(lua_State *l)
990 {
991 	LuaCheckArgs(l, 0);
992 	lua_pushboolean(l, (ThisPlayer->Index == Hosts[0].PlyNr) ? true : false);
993 	return 1;
994 }
995 
996 /**
997 **  Register CCL features for map.
998 */
MapCclRegister()999 void MapCclRegister()
1000 {
1001 	lua_register(Lua, "StratagusMap", CclStratagusMap);
1002 	lua_register(Lua, "RevealMap", CclRevealMap);
1003 	lua_register(Lua, "CenterMap", CclCenterMap);
1004 	lua_register(Lua, "SetStartView", CclSetStartView);
1005 	lua_register(Lua, "ShowMapLocation", CclShowMapLocation);
1006 
1007 	lua_register(Lua, "SetTileSize", CclSetTileSize);
1008 
1009 	lua_register(Lua, "SetFogOfWar", CclSetFogOfWar);
1010 	lua_register(Lua, "GetFogOfWar", CclGetFogOfWar);
1011 	lua_register(Lua, "SetMinimapTerrain", CclSetMinimapTerrain);
1012 
1013 	lua_register(Lua, "SetEnableMapGrid", CclSetEnableMapGrid);
1014 	lua_register(Lua, "GetIsMapGridEnabled", CclGetIsMapGridEnabled);
1015 
1016 	lua_register(Lua, "SetFieldOfViewType", CclSetFieldOfViewType);
1017 	lua_register(Lua, "GetFieldOfViewType", CclGetFieldOfViewType);
1018 	lua_register(Lua, "SetOpaqueFor", CclSetOpaqueFor);
1019 	lua_register(Lua, "RemoveOpaqueFor", CclRemoveOpaqueFor);
1020 	lua_register(Lua, "GetIsOpaqueFor", CclGetIsOpaqueFor);
1021 
1022 	lua_register(Lua, "SetFogOfWarType", CclSetFogOfWarType);
1023 	lua_register(Lua, "GetFogOfWarType", CclGetFogOfWarType);
1024 
1025 	lua_register(Lua, "SetFogOfWarOpacityLevels", CclSetFogOfWarOpacityLevels);
1026 	lua_register(Lua, "SetFogOfWarBlur", CclSetFogOfWarBlur);
1027 	lua_register(Lua, "SetFogOfWarBilinear", CclSetFogOfWarBilinear);
1028 	lua_register(Lua, "GetIsFogOfWarBilinear", CclGetIsFogOfWarBilinear);
1029 
1030 	lua_register(Lua, "SetFogOfWarGraphics", CclSetFogOfWarGraphics);
1031 	lua_register(Lua, "SetFogOfWarColor", CclSetFogOfWarColor);
1032 
1033 	lua_register(Lua, "SetMMFogOfWarOpacityLevels", CclSetMMFogOfWarOpacityLevels);
1034 
1035 	lua_register(Lua, "SetForestRegeneration", CclSetForestRegeneration);
1036 
1037 	lua_register(Lua, "LoadTileModels", CclLoadTileModels);
1038 	lua_register(Lua, "DefinePlayerTypes", CclDefinePlayerTypes);
1039 
1040 	lua_register(Lua, "DefineTileset", CclDefineTileset);
1041 	lua_register(Lua, "SetTileFlags", CclSetTileFlags);
1042 	lua_register(Lua, "BuildTilesetTables", CclBuildTilesetTables);
1043 
1044 	lua_register(Lua, "GetTileTerrainName", CclGetTileTerrainName);
1045 	lua_register(Lua, "GetTileTerrainHasFlag", CclGetTileTerrainHasFlag);
1046 
1047 	lua_register(Lua, "SetEnableWallsForSP", CclSetEnableWallsForSP);
1048 	lua_register(Lua, "GetIsWallsEnabledForSP", CclIsWallsEnabledForSP);
1049 
1050 	lua_register(Lua, "GetIsGameHoster", CclGetIsGameHoster);
1051 
1052 }
1053 
1054 //@}
1055