1 /*
2 LUA_MAP.CPP
3 
4 	Copyright (C) 2008 by Gregory Smith
5 
6 	This program is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 3 of the License, or
9 	(at your option) any later version.
10 
11 	This program is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	This license is contained in the file "COPYING",
17 	which is included with this source code; it is available online at
18 	http://www.gnu.org/licenses/gpl.html
19 
20 	Implements Lua map classes
21 */
22 
23 #include <unordered_map>
24 
25 #include "interface.h" // get_game_state
26 #include "network.h"   // game_info
27 #include "lua_map.h"
28 #include "lua_monsters.h"
29 #include "lua_objects.h"
30 #include "lua_templates.h"
31 #include "lightsource.h"
32 #include "map.h"
33 #include "media.h"
34 #include "platforms.h"
35 #include "OGL_Setup.h"
36 #include "SoundManager.h"
37 
38 #include "collection_definition.h"
39 
40 #include <boost/bind.hpp>
41 
42 #ifdef HAVE_LUA
43 
44 char Lua_AmbientSound_Name[] = "ambient_sound";
45 char Lua_AmbientSounds_Name[] = "AmbientSounds";
46 
47 extern collection_definition *get_collection_definition(short);
48 
49 char Lua_Collection_Name[] = "collection";
50 
Lua_Collection_Get_Bitmap_Count(lua_State * L)51 static int Lua_Collection_Get_Bitmap_Count(lua_State *L)
52 {
53 	collection_definition *collection = get_collection_definition(Lua_Collection::Index(L, 1));
54 	lua_pushnumber(L, collection->bitmap_count);
55 	return 1;
56 }
57 
58 const luaL_Reg Lua_Collection_Get[] = {
59 	{"bitmap_count", Lua_Collection_Get_Bitmap_Count},
60 	{0, 0},
61 };
62 
63 char Lua_Collections_Name[] = "Collections";
64 
65 char Lua_ControlPanelClass_Name[] = "control_panel_class";
66 char Lua_ControlPanelClasses_Name[] = "ControlPanelClasses";
67 
68 char Lua_ControlPanelType_Name[] = "control_panel_type";
69 
70 extern short get_panel_class(short panel_type);
71 
72 // no devices.h, so copy this from devices.cpp:
73 
74 enum // control panel sounds
75 {
76 	_activating_sound,
77 	_deactivating_sound,
78 	_unusuable_sound,
79 
80 	NUMBER_OF_CONTROL_PANEL_SOUNDS
81 };
82 
83 struct control_panel_definition
84 {
85 	int16 _class;
86 	uint16 flags;
87 
88 	int16 collection;
89 	int16 active_shape, inactive_shape;
90 
91 	int16 sounds[NUMBER_OF_CONTROL_PANEL_SOUNDS];
92 	_fixed sound_frequency;
93 
94 	int16 item;
95 };
96 
97 extern control_panel_definition* get_control_panel_definition(int16);
98 
Lua_ControlPanelType_Get_Active_Texture_Index(lua_State * L)99 static int Lua_ControlPanelType_Get_Active_Texture_Index(lua_State *L)
100 {
101 	control_panel_definition *definition = get_control_panel_definition(Lua_ControlPanelType::Index(L, 1));
102 	lua_pushnumber(L, GET_DESCRIPTOR_SHAPE(definition->active_shape));
103 	return 1;
104 }
105 
Lua_ControlPanelType_Get_Inactive_Texture_Index(lua_State * L)106 static int Lua_ControlPanelType_Get_Inactive_Texture_Index(lua_State *L)
107 {
108 	control_panel_definition *definition = get_control_panel_definition(Lua_ControlPanelType::Index(L, 1));
109 	lua_pushnumber(L, GET_DESCRIPTOR_SHAPE(definition->inactive_shape));
110 	return 1;
111 }
112 
Lua_ControlPanelType_Get_Class(lua_State * L)113 static int Lua_ControlPanelType_Get_Class(lua_State *L)
114 {
115 	Lua_ControlPanelClass::Push(L, get_panel_class(Lua_ControlPanelType::Index(L, 1)));
116 	return 1;
117 }
118 
Lua_ControlPanelType_Get_Collection(lua_State * L)119 static int Lua_ControlPanelType_Get_Collection(lua_State *L)
120 {
121 	control_panel_definition *definition = get_control_panel_definition(Lua_ControlPanelType::Index(L, 1));
122 	Lua_Collection::Push(L, definition->collection);
123 	return 1;
124 }
125 
126 const luaL_Reg Lua_ControlPanelType_Get[] = {
127 	{"active_texture_index", Lua_ControlPanelType_Get_Active_Texture_Index},
128 	{"class", Lua_ControlPanelType_Get_Class},
129 	{"collection", Lua_ControlPanelType_Get_Collection},
130 	{"inactive_texture_index", Lua_ControlPanelType_Get_Inactive_Texture_Index},
131 	{0, 0}
132 };
133 
134 char Lua_ControlPanelTypes_Name[] = "ControlPanelTypes";
135 
136 char Lua_DamageType_Name[] = "damage_type";
137 char Lua_DamageTypes_Name[] = "DamageTypes";
138 
139 char Lua_Endpoint_Name[] = "endpoint";
140 typedef L_Class<Lua_Endpoint_Name> Lua_Endpoint;
141 
Lua_Endpoint_Get_X(lua_State * L)142 static int Lua_Endpoint_Get_X(lua_State *L)
143 {
144 	endpoint_data *endpoint = get_endpoint_data(Lua_Endpoint::Index(L, 1));
145 	lua_pushnumber(L, (double) endpoint->vertex.x / WORLD_ONE);
146 	return 1;
147 }
148 
Lua_Endpoint_Get_Y(lua_State * L)149 static int Lua_Endpoint_Get_Y(lua_State *L)
150 {
151 	endpoint_data *endpoint = get_endpoint_data(Lua_Endpoint::Index(L, 1));
152 	lua_pushnumber(L, (double) endpoint->vertex.y / WORLD_ONE);
153 	return 1;
154 }
155 
Lua_Endpoint_Valid(int16 index)156 static bool Lua_Endpoint_Valid(int16 index)
157 {
158 	return index >= 0 && index < EndpointList.size();
159 }
160 
161 const luaL_Reg Lua_Endpoint_Get[] = {
162 	{"x", Lua_Endpoint_Get_X},
163 	{"y", Lua_Endpoint_Get_Y},
164 	{0, 0}
165 };
166 
167 char Lua_Endpoints_Name[] = "Endpoints";
168 typedef L_Container<Lua_Endpoints_Name, Lua_Endpoint> Lua_Endpoints;
Lua_Endpoints_Length()169 int16 Lua_Endpoints_Length() { return EndpointList.size(); }
170 
171 char Lua_Line_Endpoints_Name[] = "line_endpoints";
172 typedef L_Class<Lua_Line_Endpoints_Name> Lua_Line_Endpoints;
173 
Lua_Line_Endpoints_Get(lua_State * L)174 static int Lua_Line_Endpoints_Get(lua_State *L)
175 {
176 	if (lua_isnumber(L, 2))
177 	{
178 		short line_index = Lua_Line::Index(L, 1);
179 		line_data *line = get_line_data(line_index);
180 		int endpoint_index = static_cast<int>(lua_tonumber(L, 2));
181 		if (endpoint_index == 0 || endpoint_index == 1)
182 		{
183 			Lua_Endpoint::Push(L, line->endpoint_indexes[endpoint_index]);
184 		}
185 		else
186 		{
187 			lua_pushnil(L);
188 		}
189 	}
190 
191 	return 1;
192 }
193 
Lua_Line_Endpoints_Length(lua_State * L)194 static int Lua_Line_Endpoints_Length(lua_State *L)
195 {
196 	lua_pushnumber(L, 2);
197 	return 1;
198 }
199 
200 const luaL_Reg Lua_Line_Endpoints_Metatable[] = {
201 	{"__index", Lua_Line_Endpoints_Get},
202 	{"__len", Lua_Line_Endpoints_Length},
203 	{0, 0}
204 };
205 
206 char Lua_Line_Name[] = "line";
207 
Lua_Line_Get_Clockwise_Polygon(lua_State * L)208 static int Lua_Line_Get_Clockwise_Polygon(lua_State *L)
209 {
210 	Lua_Polygon::Push(L, get_line_data(Lua_Line::Index(L, 1))->clockwise_polygon_owner);
211 	return 1;
212 }
213 
Lua_Line_Get_Counterclockwise_Polygon(lua_State * L)214 static int Lua_Line_Get_Counterclockwise_Polygon(lua_State *L)
215 {
216 	Lua_Polygon::Push(L, get_line_data(Lua_Line::Index(L, 1))->counterclockwise_polygon_owner);
217 	return 1;
218 }
219 
Lua_Line_Get_Clockwise_Side(lua_State * L)220 static int Lua_Line_Get_Clockwise_Side(lua_State *L)
221 {
222 	Lua_Side::Push(L, get_line_data(Lua_Line::Index(L, 1))->clockwise_polygon_side_index);
223 	return 1;
224 }
225 
Lua_Line_Get_Counterclockwise_Side(lua_State * L)226 static int Lua_Line_Get_Counterclockwise_Side(lua_State *L)
227 {
228 	Lua_Side::Push(L, get_line_data(Lua_Line::Index(L, 1))->counterclockwise_polygon_side_index);
229 	return 1;
230 }
231 
Lua_Line_Get_Endpoints(lua_State * L)232 static int Lua_Line_Get_Endpoints(lua_State *L)
233 {
234 	Lua_Line_Endpoints::Push(L, Lua_Line::Index(L, 1));
235 	return 1;
236 }
237 
Lua_Line_Get_Has_Transparent_Side(lua_State * L)238 static int Lua_Line_Get_Has_Transparent_Side(lua_State *L)
239 {
240 	lua_pushboolean(L, LINE_HAS_TRANSPARENT_SIDE(get_line_data(Lua_Line::Index(L, 1))));
241 	return 1;
242 }
243 
Lua_Line_Get_Highest_Adjacent_Floor(lua_State * L)244 static int Lua_Line_Get_Highest_Adjacent_Floor(lua_State *L)
245 {
246 	lua_pushnumber(L, (double) get_line_data(Lua_Line::Index(L, 1))->highest_adjacent_floor / WORLD_ONE);
247 	return 1;
248 }
249 
Lua_Line_Get_Length(lua_State * L)250 static int Lua_Line_Get_Length(lua_State *L)
251 {
252 	lua_pushnumber(L, (double) get_line_data(Lua_Line::Index(L, 1))->length / WORLD_ONE);
253 	return 1;
254 }
255 
Lua_Line_Get_Lowest_Adjacent_Ceiling(lua_State * L)256 static int Lua_Line_Get_Lowest_Adjacent_Ceiling(lua_State *L)
257 {
258 	lua_pushnumber(L, (double) get_line_data(Lua_Line::Index(L, 1))->lowest_adjacent_ceiling / WORLD_ONE);
259 	return 1;
260 }
261 
Lua_Line_Get_Solid(lua_State * L)262 static int Lua_Line_Get_Solid(lua_State *L)
263 {
264 	line_data *line = get_line_data(Lua_Line::Index(L, 1));
265 	lua_pushboolean(L, LINE_IS_SOLID(line));
266 	return 1;
267 }
268 
Lua_Line_Get_Visible_On_Automap(lua_State * L)269 static int Lua_Line_Get_Visible_On_Automap(lua_State *L)
270 {
271 	lua_pushboolean(L, LINE_IS_IN_AUTOMAP(Lua_Line::Index(L, 1)));
272 	return 1;
273 }
274 
Lua_Line_Set_Visible_On_Automap(lua_State * L)275 static int Lua_Line_Set_Visible_On_Automap(lua_State *L)
276 {
277 	if (!lua_isboolean(L, 2))
278 		return luaL_error(L, ("visible_on_automap: incorrect argument type"));
279 
280 	if (lua_toboolean(L, 2))
281 		ADD_LINE_TO_AUTOMAP(Lua_Line::Index(L, 1));
282 	else
283 		CLEAR_LINE_FROM_AUTOMAP(Lua_Line::Index(L, 1));
284 	return 0;
285 }
286 
287 
288 const luaL_Reg Lua_Line_Get[] = {
289 	{"cw_polygon", Lua_Line_Get_Clockwise_Polygon},
290 	{"ccw_polygon", Lua_Line_Get_Counterclockwise_Polygon},
291 	{"cw_side", Lua_Line_Get_Clockwise_Side},
292 	{"ccw_side", Lua_Line_Get_Counterclockwise_Side},
293 	{"clockwise_polygon", Lua_Line_Get_Clockwise_Polygon},
294 	{"clockwise_side", Lua_Line_Get_Clockwise_Side},
295 	{"counterclockwise_polygon", Lua_Line_Get_Counterclockwise_Polygon},
296 	{"counterclockwise_side", Lua_Line_Get_Counterclockwise_Side},
297 	{"endpoints", Lua_Line_Get_Endpoints},
298 	{"has_transparent_side", Lua_Line_Get_Has_Transparent_Side},
299 	{"highest_adjacent_floor", Lua_Line_Get_Highest_Adjacent_Floor},
300 	{"length", Lua_Line_Get_Length},
301 	{"lowest_adjacent_ceiling", Lua_Line_Get_Lowest_Adjacent_Ceiling},
302 	{"solid", Lua_Line_Get_Solid},
303 	{"visible_on_automap", Lua_Line_Get_Visible_On_Automap},
304 	{0, 0}
305 };
306 
307 const luaL_Reg Lua_Line_Set[] = {
308 	{"visible_on_automap", Lua_Line_Set_Visible_On_Automap},
309 	{0, 0}
310 };
311 
Lua_Line_Valid(int16 index)312 static bool Lua_Line_Valid(int16 index)
313 {
314 	return index >= 0 && index < LineList.size();
315 }
316 
317 char Lua_Lines_Name[] = "Lines";
Lua_Lines_Length()318 static int16 Lua_Lines_Length() { return LineList.size(); }
319 
320 char Lua_PlatformType_Name[] = "platform_type";
321 char Lua_PlatformTypes_Name[] = "PlatformTypes";
322 
323 char Lua_Platform_Name[] = "platform";
Lua_Platform_Valid(int16 index)324 bool Lua_Platform_Valid(int16 index)
325 {
326 	return index >= 0 && index < dynamic_world->platform_count;
327 }
328 
329 template<int flag_bit> int
Lua_Platform_Get_Static_Flag(lua_State * L)330 Lua_Platform_Get_Static_Flag(lua_State* L)
331 {
332 	platform_data* platform = get_platform_data(Lua_Platform::Index(L, 1));
333 	lua_pushboolean(L, platform->static_flags & (1 << flag_bit));
334 	return 1;
335 }
336 
337 template<int flag_bit> int
Lua_Platform_Set_Static_Flag(lua_State * L)338 Lua_Platform_Set_Static_Flag(lua_State* L)
339 {
340 	if (!lua_isboolean(L, 2))
341 		return luaL_error(L, "platform: incorrect argument type");
342 
343 	platform_data* platform = get_platform_data(Lua_Platform::Index(L, 1));
344 	bool flag = lua_toboolean(L, 2);
345 	if (flag)
346 		platform->static_flags |= (1 << flag_bit);
347 	else
348 		platform->static_flags &= ~(1 << flag_bit);
349 
350 	return 0;
351 }
352 
Lua_Platform_Get_Active(lua_State * L)353 static int Lua_Platform_Get_Active(lua_State *L)
354 {
355 	platform_data *platform = get_platform_data(Lua_Platform::Index(L, 1));
356 	lua_pushboolean(L, PLATFORM_IS_ACTIVE(platform));
357 	return 1;
358 }
359 
Lua_Platform_Get_Ceiling_Height(lua_State * L)360 static int Lua_Platform_Get_Ceiling_Height(lua_State *L)
361 {
362 	platform_data *platform = get_platform_data(Lua_Platform::Index(L, 1));
363 	lua_pushnumber(L, (double) platform->ceiling_height / WORLD_ONE);
364 	return 1;
365 }
366 
Lua_Platform_Get_Contracting(lua_State * L)367 static int Lua_Platform_Get_Contracting(lua_State *L)
368 {
369 	platform_data *platform = get_platform_data(Lua_Platform::Index(L, 1));
370 	lua_pushboolean(L, !PLATFORM_IS_EXTENDING(platform));
371 	return 1;
372 }
373 
Lua_Platform_Get_Extending(lua_State * L)374 static int Lua_Platform_Get_Extending(lua_State *L)
375 {
376 	platform_data *platform = get_platform_data(Lua_Platform::Index(L, 1));
377 	lua_pushboolean(L, PLATFORM_IS_EXTENDING(platform));
378 	return 1;
379 }
380 
Lua_Platform_Get_Floor_Height(lua_State * L)381 static int Lua_Platform_Get_Floor_Height(lua_State *L)
382 {
383 	platform_data *platform = get_platform_data(Lua_Platform::Index(L, 1));
384 	lua_pushnumber(L, (double) platform->floor_height / WORLD_ONE);
385 	return 1;
386 }
387 
Lua_Platform_Get_Polygon(lua_State * L)388 static int Lua_Platform_Get_Polygon(lua_State *L)
389 {
390 	Lua_Polygon::Push(L, get_platform_data(Lua_Platform::Index(L, 1))->polygon_index);
391 	return 1;
392 }
393 
Lua_Platform_Get_Speed(lua_State * L)394 static int Lua_Platform_Get_Speed(lua_State *L)
395 {
396 	platform_data *platform = get_platform_data(Lua_Platform::Index(L, 1));
397 	lua_pushnumber(L, (double) platform->speed / WORLD_ONE);
398 	return 1;
399 }
400 
Lua_Platform_Get_Type(lua_State * L)401 static int Lua_Platform_Get_Type(lua_State* L)
402 {
403 	platform_data* platform = get_platform_data(Lua_Platform::Index(L, 1));
404 	Lua_PlatformType::Push(L, platform->type);
405 	return 1;
406 }
407 
408 extern bool set_platform_state(short, bool, short);
409 
Lua_Platform_Set_Active(lua_State * L)410 static int Lua_Platform_Set_Active(lua_State *L)
411 {
412 	if (!lua_isboolean(L, 2))
413 		return luaL_error(L, "active: incorrect argument type");
414 
415 	short platform_index = Lua_Platform::Index(L, 1);
416 	set_platform_state(platform_index, lua_toboolean(L, 2), NONE);
417 	return 0;
418 }
419 
Lua_Platform_Set_Ceiling_Height(lua_State * L)420 static int Lua_Platform_Set_Ceiling_Height(lua_State *L)
421 {
422 	if (!lua_isnumber(L, 2))
423 		return luaL_error(L, "ceiling_height: incorrect argument type");
424 
425 	short platform_index = Lua_Platform::Index(L, 1);
426 	platform_data *platform = get_platform_data(platform_index);
427 
428 	platform->ceiling_height = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
429 	adjust_platform_endpoint_and_line_heights(platform_index);
430 	adjust_platform_for_media(platform_index, false);
431 
432 	return 0;
433 }
434 
Lua_Platform_Set_Contracting(lua_State * L)435 static int Lua_Platform_Set_Contracting(lua_State *L)
436 {
437 	if (!lua_isboolean(L, 2))
438 		return luaL_error(L, "contracting: incorrect argument type");
439 
440 	platform_data *platform = get_platform_data(Lua_Platform::Index(L, 1));
441 	bool contracting = lua_toboolean(L, 2);
442 	if (contracting)
443 		SET_PLATFORM_IS_CONTRACTING(platform);
444 	else
445 		SET_PLATFORM_IS_EXTENDING(platform);
446 	return 0;
447 }
448 
Lua_Platform_Set_Extending(lua_State * L)449 static int Lua_Platform_Set_Extending(lua_State *L)
450 {
451 	if (!lua_isboolean(L, 2))
452 		return luaL_error(L, "extending: incorrect argument type");
453 
454 	platform_data *platform = get_platform_data(Lua_Platform::Index(L, 1));
455 	bool extending = lua_toboolean(L, 2);
456 	if (extending)
457 		SET_PLATFORM_IS_EXTENDING(platform);
458 	else
459 		SET_PLATFORM_IS_CONTRACTING(platform);
460 	return 0;
461 }
462 
Lua_Platform_Set_Floor_Height(lua_State * L)463 static int Lua_Platform_Set_Floor_Height(lua_State *L)
464 {
465 	if (!lua_isnumber(L, 2))
466 		return luaL_error(L, "ceiling_height: incorrect argument type");
467 
468 	short platform_index = Lua_Platform::Index(L, 1);
469 	platform_data *platform = get_platform_data(platform_index);
470 
471 	platform->floor_height = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
472 	adjust_platform_endpoint_and_line_heights(platform_index);
473 	adjust_platform_for_media(platform_index, false);
474 
475 	return 0;
476 }
477 
Lua_Platform_Set_Speed(lua_State * L)478 static int Lua_Platform_Set_Speed(lua_State *L)
479 {
480 	if (!lua_isnumber(L, 2))
481 		return luaL_error(L, "speed: incorrect argument type");
482 
483 	platform_data *platform = get_platform_data(Lua_Platform::Index(L, 1));
484 	platform->speed = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
485 	return 0;
486 }
487 
Lua_Platform_Set_Type(lua_State * L)488 static int Lua_Platform_Set_Type(lua_State* L)
489 {
490 	platform_data* platform = get_platform_data(Lua_Platform::Index(L, 1));
491 	platform->type = Lua_PlatformType::ToIndex(L, 2);
492 	return 0;
493 }
494 
495 
496 const luaL_Reg Lua_Platform_Get[] = {
497 	{"active", Lua_Platform_Get_Active},
498 	{"ceiling_height", Lua_Platform_Get_Ceiling_Height},
499 	{"contracting", Lua_Platform_Get_Contracting},
500 	{"door", Lua_Platform_Get_Static_Flag<_platform_is_door>},
501 	{"extending", Lua_Platform_Get_Extending},
502 	{"floor_height", Lua_Platform_Get_Floor_Height},
503 	{"locked", Lua_Platform_Get_Static_Flag<_platform_is_locked>},
504 	{"monster_controllable", Lua_Platform_Get_Static_Flag<_platform_is_monster_controllable>},
505 	{"player_controllable", Lua_Platform_Get_Static_Flag<_platform_is_player_controllable>},
506 	{"polygon", Lua_Platform_Get_Polygon},
507 	{"secret", Lua_Platform_Get_Static_Flag<_platform_is_secret>},
508 	{"speed", Lua_Platform_Get_Speed},
509 	{"type", Lua_Platform_Get_Type},
510 	{0, 0}
511 };
512 
513 const luaL_Reg Lua_Platform_Set[] = {
514 	{"active", Lua_Platform_Set_Active},
515 	{"ceiling_height", Lua_Platform_Set_Ceiling_Height},
516 	{"contracting", Lua_Platform_Set_Contracting},
517 	{"door", Lua_Platform_Set_Static_Flag<_platform_is_door>},
518 	{"extending", Lua_Platform_Set_Extending},
519 	{"floor_height", Lua_Platform_Set_Floor_Height},
520 	{"locked", Lua_Platform_Set_Static_Flag<_platform_is_locked>},
521 	{"monster_controllable", Lua_Platform_Set_Static_Flag<_platform_is_monster_controllable>},
522 	{"player_controllable", Lua_Platform_Set_Static_Flag<_platform_is_player_controllable>},
523 	{"secret", Lua_Platform_Set_Static_Flag<_platform_is_secret>},
524 	{"speed", Lua_Platform_Set_Speed},
525 	{"type", Lua_Platform_Set_Type},
526 	{0, 0}
527 };
528 
529 char Lua_Platforms_Name[] = "Platforms";
Lua_Platforms_Length()530 int16 Lua_Platforms_Length() {
531 	return dynamic_world->platform_count;
532 }
533 
534 char Lua_Polygon_Floor_Name[] = "polygon_floor";
535 
Lua_Polygon_Floor_Get_Collection(lua_State * L)536 static int Lua_Polygon_Floor_Get_Collection(lua_State *L)
537 {
538 	Lua_Collection::Push(L, GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(get_polygon_data(Lua_Polygon_Floor::Index(L, 1))->floor_texture)));
539 	return 1;
540 }
541 
Lua_Polygon_Floor_Get_Height(lua_State * L)542 static int Lua_Polygon_Floor_Get_Height(lua_State *L)
543 {
544 	lua_pushnumber(L, (double) (get_polygon_data(Lua_Polygon_Floor::Index(L, 1))->floor_height) / WORLD_ONE);
545 	return 1;
546 }
547 
Lua_Polygon_Floor_Get_Light(lua_State * L)548 static int Lua_Polygon_Floor_Get_Light(lua_State *L)
549 {
550 	Lua_Light::Push(L, get_polygon_data(Lua_Polygon_Floor::Index(L, 1))->floor_lightsource_index);
551 	return 1;
552 }
553 
Lua_Polygon_Floor_Get_Texture_Index(lua_State * L)554 static int Lua_Polygon_Floor_Get_Texture_Index(lua_State *L)
555 {
556 	lua_pushnumber(L, GET_DESCRIPTOR_SHAPE(get_polygon_data(Lua_Polygon_Floor::Index(L, 1))->floor_texture));
557 	return 1;
558 }
559 
Lua_Polygon_Floor_Get_Texture_X(lua_State * L)560 static int Lua_Polygon_Floor_Get_Texture_X(lua_State *L)
561 {
562 	lua_pushnumber(L, (double) (get_polygon_data(Lua_Polygon_Floor::Index(L, 1))->floor_origin.x) / WORLD_ONE);
563 	return 1;
564 }
565 
Lua_Polygon_Floor_Get_Texture_Y(lua_State * L)566 static int Lua_Polygon_Floor_Get_Texture_Y(lua_State *L)
567 {
568 	lua_pushnumber(L, (double) (get_polygon_data(Lua_Polygon_Floor::Index(L, 1))->floor_origin.y) / WORLD_ONE);
569 	return 1;
570 }
571 
Lua_Polygon_Floor_Get_Transfer_Mode(lua_State * L)572 static int Lua_Polygon_Floor_Get_Transfer_Mode(lua_State *L)
573 {
574 	Lua_TransferMode::Push(L, get_polygon_data(Lua_Polygon_Floor::Index(L, 1))->floor_transfer_mode);
575 	return 1;
576 }
577 
Lua_Polygon_Floor_Set_Collection(lua_State * L)578 static int Lua_Polygon_Floor_Set_Collection(lua_State *L)
579 {
580 	short polygon_index = Lua_Polygon_Floor::Index(L, 1);
581 	short collection_index = Lua_Collection::ToIndex(L, 2);
582 
583 	polygon_data *polygon = get_polygon_data(polygon_index);
584 	polygon->floor_texture = BUILD_DESCRIPTOR(collection_index, GET_DESCRIPTOR_SHAPE(polygon->floor_texture));
585 	return 0;
586 }
587 
Lua_Polygon_Floor_Set_Height(lua_State * L)588 static int Lua_Polygon_Floor_Set_Height(lua_State *L)
589 {
590 	if (!lua_isnumber(L, 2))
591 	{
592 		luaL_error(L, "height: incorrect argument type");
593 	}
594 
595 	struct polygon_data *polygon = get_polygon_data(Lua_Polygon_Floor::Index(L, 1));
596 	polygon->floor_height = static_cast<world_distance>(lua_tonumber(L,2)*WORLD_ONE);
597 	for (short i = 0; i < polygon->vertex_count; ++i)
598 	{
599 		recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i]);
600 		recalculate_redundant_line_data(polygon->line_indexes[i]);
601 	}
602 	return 0;
603 }
604 
Lua_Polygon_Floor_Set_Light(lua_State * L)605 static int Lua_Polygon_Floor_Set_Light(lua_State *L)
606 {
607 	short light_index;
608 	if (lua_isnumber(L, 2))
609 	{
610 		light_index = static_cast<short>(lua_tonumber(L, 2));
611 		if (light_index < 0 || light_index >= MAXIMUM_LIGHTS_PER_MAP)
612 			return luaL_error(L, "light: invalid light index");
613 	}
614 	else
615 	{
616 		light_index = Lua_Light::Index(L, 2);
617 	}
618 
619 	get_polygon_data(Lua_Polygon_Floor::Index(L, 1))->floor_lightsource_index = light_index;
620 	return 0;
621 }
622 
Lua_Polygon_Floor_Set_Texture_Index(lua_State * L)623 static int Lua_Polygon_Floor_Set_Texture_Index(lua_State *L)
624 {
625 	polygon_data *polygon = get_polygon_data(Lua_Polygon_Floor::Index(L, 1));
626 	if (!lua_isnumber(L, 2))
627 		return luaL_error(L, "texture_index: incorrect argument type");
628 
629 	short shape_index = static_cast<short>(lua_tonumber(L, 2));
630 	if (shape_index < 0 || shape_index >= MAXIMUM_SHAPES_PER_COLLECTION)
631 		return luaL_error(L, "texture_index: invalid texture index");
632 
633 	polygon->floor_texture = BUILD_DESCRIPTOR(GET_DESCRIPTOR_COLLECTION(polygon->floor_texture), shape_index);
634 	return 0;
635 }
636 
Lua_Polygon_Floor_Set_Texture_X(lua_State * L)637 static int Lua_Polygon_Floor_Set_Texture_X(lua_State *L)
638 {
639 	polygon_data *polygon = get_polygon_data(Lua_Polygon_Floor::Index(L, 1));
640 	if (!lua_isnumber(L, 2))
641 		return luaL_error(L, "texture_x: incorrect argument type");
642 
643 	polygon->floor_origin.x = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
644 	return 0;
645 }
646 
Lua_Polygon_Floor_Set_Texture_Y(lua_State * L)647 static int Lua_Polygon_Floor_Set_Texture_Y(lua_State *L)
648 {
649 	polygon_data *polygon = get_polygon_data(Lua_Polygon_Floor::Index(L, 1));
650 	if (!lua_isnumber(L, 2))
651 		return luaL_error(L, "texture_y: incorrect argument type");
652 
653 	polygon->floor_origin.y = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
654 	return 0;
655 }
656 
Lua_Polygon_Floor_Set_Transfer_Mode(lua_State * L)657 static int Lua_Polygon_Floor_Set_Transfer_Mode(lua_State *L)
658 {
659 	polygon_data *polygon = get_polygon_data(Lua_Polygon_Floor::Index(L, 1));
660 	polygon->floor_transfer_mode = Lua_TransferMode::ToIndex(L, 2);
661 	return 0;
662 }
663 
664 const luaL_Reg Lua_Polygon_Floor_Get[] = {
665 	{"collection", Lua_Polygon_Floor_Get_Collection},
666 	{"height", Lua_Polygon_Floor_Get_Height},
667 	{"light", Lua_Polygon_Floor_Get_Light},
668 	{"texture_index", Lua_Polygon_Floor_Get_Texture_Index},
669 	{"texture_x", Lua_Polygon_Floor_Get_Texture_X},
670 	{"texture_y", Lua_Polygon_Floor_Get_Texture_Y},
671 	{"transfer_mode", Lua_Polygon_Floor_Get_Transfer_Mode},
672 	{"z", Lua_Polygon_Floor_Get_Height},
673 	{0, 0}
674 };
675 
676 const luaL_Reg Lua_Polygon_Floor_Set[] = {
677 	{"collection", Lua_Polygon_Floor_Set_Collection},
678 	{"height", Lua_Polygon_Floor_Set_Height},
679 	{"light", Lua_Polygon_Floor_Set_Light},
680 	{"texture_index", Lua_Polygon_Floor_Set_Texture_Index},
681 	{"texture_x", Lua_Polygon_Floor_Set_Texture_X},
682 	{"texture_y", Lua_Polygon_Floor_Set_Texture_Y},
683 	{"transfer_mode", Lua_Polygon_Floor_Set_Transfer_Mode},
684 	{"z", Lua_Polygon_Floor_Set_Height},
685 	{0, 0}
686 };
687 
688 char Lua_Polygon_Ceiling_Name[] = "polygon_ceiling";
689 
Lua_Polygon_Ceiling_Get_Collection(lua_State * L)690 static int Lua_Polygon_Ceiling_Get_Collection(lua_State *L)
691 {
692 	Lua_Collection::Push(L, GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1))->ceiling_texture)));
693 	return 1;
694 }
695 
Lua_Polygon_Ceiling_Get_Height(lua_State * L)696 static int Lua_Polygon_Ceiling_Get_Height(lua_State *L)
697 {
698 	lua_pushnumber(L, (double) (get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1))->ceiling_height) / WORLD_ONE);
699 	return 1;
700 }
701 
Lua_Polygon_Ceiling_Get_Light(lua_State * L)702 static int Lua_Polygon_Ceiling_Get_Light(lua_State *L)
703 {
704 	Lua_Light::Push(L, get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1))->ceiling_lightsource_index);
705 	return 1;
706 }
707 
Lua_Polygon_Ceiling_Get_Texture_Index(lua_State * L)708 static int Lua_Polygon_Ceiling_Get_Texture_Index(lua_State *L)
709 {
710 	lua_pushnumber(L, GET_DESCRIPTOR_SHAPE(get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1))->ceiling_texture));
711 	return 1;
712 }
713 
Lua_Polygon_Ceiling_Get_Texture_X(lua_State * L)714 static int Lua_Polygon_Ceiling_Get_Texture_X(lua_State *L)
715 {
716 	lua_pushnumber(L, (double) (get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1))->ceiling_origin.x) / WORLD_ONE);
717 	return 1;
718 }
719 
Lua_Polygon_Ceiling_Get_Texture_Y(lua_State * L)720 static int Lua_Polygon_Ceiling_Get_Texture_Y(lua_State *L)
721 {
722 	lua_pushnumber(L, (double) (get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1))->ceiling_origin.y) / WORLD_ONE);
723 	return 1;
724 }
725 
Lua_Polygon_Ceiling_Get_Transfer_Mode(lua_State * L)726 static int Lua_Polygon_Ceiling_Get_Transfer_Mode(lua_State *L)
727 {
728 	Lua_TransferMode::Push(L, get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1))->ceiling_transfer_mode);
729 	return 1;
730 }
731 
Lua_Polygon_Ceiling_Set_Collection(lua_State * L)732 static int Lua_Polygon_Ceiling_Set_Collection(lua_State *L)
733 {
734 	short polygon_index = Lua_Polygon_Ceiling::Index(L, 1);
735 	short collection_index = Lua_Collection::ToIndex(L, 2);
736 
737 	polygon_data *polygon = get_polygon_data(polygon_index);
738 	polygon->ceiling_texture = BUILD_DESCRIPTOR(collection_index, GET_DESCRIPTOR_SHAPE(polygon->ceiling_texture));
739 	return 0;
740 }
741 
Lua_Polygon_Ceiling_Set_Height(lua_State * L)742 static int Lua_Polygon_Ceiling_Set_Height(lua_State *L)
743 {
744 	if (!lua_isnumber(L, 2))
745 	{
746 		luaL_error(L, "height: incorrect argument type");
747 	}
748 
749 	struct polygon_data *polygon = get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1));
750 	polygon->ceiling_height = static_cast<world_distance>(lua_tonumber(L,2)*WORLD_ONE);
751 	for (short i = 0; i < polygon->vertex_count; ++i)
752 	{
753 		recalculate_redundant_endpoint_data(polygon->endpoint_indexes[i]);
754 		recalculate_redundant_line_data(polygon->line_indexes[i]);
755 	}
756 	return 0;
757 }
758 
Lua_Polygon_Ceiling_Set_Light(lua_State * L)759 static int Lua_Polygon_Ceiling_Set_Light(lua_State *L)
760 {
761 	short light_index;
762 	if (lua_isnumber(L, 2))
763 	{
764 		light_index = static_cast<short>(lua_tonumber(L, 2));
765 		if (light_index < 0 || light_index >= MAXIMUM_LIGHTS_PER_MAP)
766 			return luaL_error(L, "light: invalid light index");
767 	}
768 	else
769 	{
770 		light_index = Lua_Light::Index(L, 2);
771 	}
772 
773 	get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1))->ceiling_lightsource_index = light_index;
774 	return 0;
775 }
776 
Lua_Polygon_Ceiling_Set_Texture_Index(lua_State * L)777 static int Lua_Polygon_Ceiling_Set_Texture_Index(lua_State *L)
778 {
779 	polygon_data *polygon = get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1));
780 	if (!lua_isnumber(L, 2))
781 		return luaL_error(L, "texture_index: incorrect argument type");
782 
783 	short shape_index = static_cast<short>(lua_tonumber(L, 2));
784 	if (shape_index < 0 || shape_index >= MAXIMUM_SHAPES_PER_COLLECTION)
785 		return luaL_error(L, "texture_index: invalid texture index");
786 
787 	polygon->ceiling_texture = BUILD_DESCRIPTOR(GET_DESCRIPTOR_COLLECTION(polygon->ceiling_texture), shape_index);
788 	return 0;
789 }
790 
Lua_Polygon_Ceiling_Set_Texture_X(lua_State * L)791 static int Lua_Polygon_Ceiling_Set_Texture_X(lua_State *L)
792 {
793 	polygon_data *polygon = get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1));
794 	if (!lua_isnumber(L, 2))
795 		return luaL_error(L, "texture_x: incorrect argument type");
796 
797 	polygon->ceiling_origin.x = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
798 	return 0;
799 }
800 
Lua_Polygon_Ceiling_Set_Texture_Y(lua_State * L)801 static int Lua_Polygon_Ceiling_Set_Texture_Y(lua_State *L)
802 {
803 	polygon_data *polygon = get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1));
804 	if (!lua_isnumber(L, 2))
805 		return luaL_error(L, "texture_y: incorrect argument type");
806 
807 	polygon->ceiling_origin.y = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
808 	return 0;
809 }
810 
Lua_Polygon_Ceiling_Set_Transfer_Mode(lua_State * L)811 static int Lua_Polygon_Ceiling_Set_Transfer_Mode(lua_State *L)
812 {
813 	polygon_data *polygon = get_polygon_data(Lua_Polygon_Ceiling::Index(L, 1));
814 	polygon->ceiling_transfer_mode = Lua_TransferMode::ToIndex(L, 2);
815 	return 0;
816 }
817 
818 const luaL_Reg Lua_Polygon_Ceiling_Get[] = {
819 	{"collection", Lua_Polygon_Ceiling_Get_Collection},
820 	{"height", Lua_Polygon_Ceiling_Get_Height},
821 	{"light", Lua_Polygon_Ceiling_Get_Light},
822 	{"texture_index", Lua_Polygon_Ceiling_Get_Texture_Index},
823 	{"texture_x", Lua_Polygon_Ceiling_Get_Texture_X},
824 	{"texture_y", Lua_Polygon_Ceiling_Get_Texture_Y},
825 	{"transfer_mode", Lua_Polygon_Ceiling_Get_Transfer_Mode},
826 	{"z", Lua_Polygon_Ceiling_Get_Height},
827 	{0, 0}
828 };
829 
830 const luaL_Reg Lua_Polygon_Ceiling_Set[] = {
831 	{"collection", Lua_Polygon_Ceiling_Set_Collection},
832 	{"height", Lua_Polygon_Ceiling_Set_Height},
833 	{"light", Lua_Polygon_Ceiling_Set_Light},
834 	{"texture_index", Lua_Polygon_Ceiling_Set_Texture_Index},
835 	{"texture_x", Lua_Polygon_Ceiling_Set_Texture_X},
836 	{"texture_y", Lua_Polygon_Ceiling_Set_Texture_Y},
837 	{"transfer_mode", Lua_Polygon_Ceiling_Set_Transfer_Mode},
838 	{"z", Lua_Polygon_Ceiling_Set_Height},
839 	{0, 0}
840 };
841 
842 char Lua_PolygonType_Name[] = "polygon_type";
843 typedef L_Enum<Lua_PolygonType_Name> Lua_PolygonType;
844 
845 char Lua_PolygonTypes_Name[] = "PolygonTypes";
846 typedef L_EnumContainer<Lua_PolygonTypes_Name, Lua_PolygonType> Lua_PolygonTypes;
847 
848 char Lua_Polygon_Name[] = "polygon";
849 
850 char Lua_Adjacent_Polygons_Name[] = "adjacent_polygons";
851 typedef L_Class<Lua_Adjacent_Polygons_Name> Lua_Adjacent_Polygons;
852 
Lua_Adjacent_Polygons_Iterator(lua_State * L)853 static int Lua_Adjacent_Polygons_Iterator(lua_State *L)
854 {
855 	int index = static_cast<int>(lua_tonumber(L, lua_upvalueindex(1)));
856 	short polygon_index = Lua_Adjacent_Polygons::Index(L, lua_upvalueindex(2));
857 	polygon_data *polygon = get_polygon_data(polygon_index);
858 
859 	while (index < polygon->vertex_count)
860 	{
861 		if (polygon->adjacent_polygon_indexes[index] != NONE)
862 		{
863 			Lua_Polygon::Push(L, polygon->adjacent_polygon_indexes[index]);
864 			lua_pushnumber(L, ++index);
865 			lua_replace(L, lua_upvalueindex(1));
866 			return 1;
867 		}
868 		else
869 		{
870 			index++;
871 		}
872 	}
873 
874 	lua_pushnil(L);
875 	return 1;
876 }
877 
Lua_Adjacent_Polygons_Call(lua_State * L)878 static int Lua_Adjacent_Polygons_Call(lua_State *L)
879 {
880 	lua_pushnumber(L, 0);
881 	lua_pushvalue(L, 1);
882 	lua_pushcclosure(L, Lua_Adjacent_Polygons_Iterator, 2);
883 	return 1;
884 }
885 
Lua_Adjacent_Polygons_Get(lua_State * L)886 static int Lua_Adjacent_Polygons_Get(lua_State *L)
887 {
888 	if (lua_isnumber(L, 2))
889 	{
890 		short polygon_index = Lua_Adjacent_Polygons::Index(L, 1);
891 		polygon_data *polygon = get_polygon_data(polygon_index);
892 		int adjacent_polygon_index = static_cast<int>(lua_tonumber(L, 2));
893 		if (adjacent_polygon_index >= 0 && adjacent_polygon_index < polygon->vertex_count)
894 		{
895 			Lua_Polygon::Push(L, polygon->adjacent_polygon_indexes[adjacent_polygon_index]);
896 		}
897 		else
898 		{
899 			lua_pushnil(L);
900 		}
901 	}
902 	else
903 	{
904 		lua_pushnil(L);
905 	}
906 
907 	return 1;
908 }
909 
Lua_Adjacent_Polygons_Length(lua_State * L)910 static int Lua_Adjacent_Polygons_Length(lua_State *L)
911 {
912 	lua_pushnumber(L, get_polygon_data(Lua_Adjacent_Polygons::Index(L, 1))->vertex_count);
913 	return 1;
914 }
915 
916 const luaL_Reg Lua_Adjacent_Polygons_Metatable[] = {
917 	{"__index", Lua_Adjacent_Polygons_Get},
918 	{"__call", Lua_Adjacent_Polygons_Call},
919 	{"__len", Lua_Adjacent_Polygons_Length},
920 	{0, 0}
921 };
922 
923 char Lua_Polygon_Endpoints_Name[] = "polygon_endpoints";
924 typedef L_Class<Lua_Polygon_Endpoints_Name> Lua_Polygon_Endpoints;
925 
Lua_Polygon_Endpoints_Iterator(lua_State * L)926 static int Lua_Polygon_Endpoints_Iterator(lua_State *L)
927 {
928 	int index = static_cast<int>(lua_tonumber(L, lua_upvalueindex(1)));
929 	short polygon_index = Lua_Polygon_Endpoints::Index(L, lua_upvalueindex(2));
930 	polygon_data *polygon = get_polygon_data(polygon_index);
931 
932 	while (index < polygon->vertex_count)
933 	{
934 		if (polygon->endpoint_indexes[index] != NONE)
935 		{
936 			Lua_Endpoint::Push(L, polygon->endpoint_indexes[index]);
937 			lua_pushnumber(L, ++index);
938 			lua_replace(L, lua_upvalueindex(1));
939 			return 1;
940 		}
941 		else
942 		{
943 			index++;
944 		}
945 	}
946 
947 	lua_pushnil(L);
948 	return 1;
949 }
950 
Lua_Polygon_Endpoints_Call(lua_State * L)951 static int Lua_Polygon_Endpoints_Call(lua_State *L)
952 {
953 	lua_pushnumber(L, 0);
954 	lua_pushvalue(L, 1);
955 	lua_pushcclosure(L, Lua_Polygon_Endpoints_Iterator, 2);
956 	return 1;
957 }
958 
Lua_Polygon_Endpoints_Get(lua_State * L)959 static int Lua_Polygon_Endpoints_Get(lua_State *L)
960 {
961 	if (lua_isnumber(L, 2))
962 	{
963 		short polygon_index = Lua_Polygon_Endpoints::Index(L, 1);
964 		polygon_data *polygon = get_polygon_data(polygon_index);
965 		int endpoint_index = static_cast<int>(lua_tonumber(L, 2));
966 		if (endpoint_index >= 0 && endpoint_index < polygon->vertex_count)
967 		{
968 			Lua_Endpoint::Push(L, polygon->endpoint_indexes[endpoint_index]);
969 		}
970 		else
971 		{
972 			lua_pushnil(L);
973 		}
974 	}
975 
976 	return 1;
977 }
978 
Lua_Polygon_Endpoints_Length(lua_State * L)979 static int Lua_Polygon_Endpoints_Length(lua_State *L)
980 {
981 	lua_pushnumber(L, get_polygon_data(Lua_Polygon_Endpoints::Index(L, 1))->vertex_count);
982 	return 1;
983 }
984 
985 const luaL_Reg Lua_Polygon_Endpoints_Metatable[] = {
986 	{"__index", Lua_Polygon_Endpoints_Get},
987 	{"__call", Lua_Polygon_Endpoints_Call},
988 	{"__len", Lua_Polygon_Endpoints_Length},
989 	{0, 0}
990 };
991 
992 char Lua_Polygon_Lines_Name[] = "polygon_lines";
993 typedef L_Class<Lua_Polygon_Lines_Name> Lua_Polygon_Lines;
994 
Lua_Polygon_Lines_Iterator(lua_State * L)995 static int Lua_Polygon_Lines_Iterator(lua_State *L)
996 {
997 	int index = static_cast<int>(lua_tonumber(L, lua_upvalueindex(1)));
998 	short polygon_index = Lua_Polygon_Lines::Index(L, lua_upvalueindex(2));
999 	polygon_data *polygon = get_polygon_data(polygon_index);
1000 
1001 	while (index < polygon->vertex_count)
1002 	{
1003 		if (polygon->line_indexes[index] != NONE)
1004 		{
1005 			Lua_Line::Push(L, polygon->line_indexes[index]);
1006 			lua_pushnumber(L, ++index);
1007 			lua_replace(L, lua_upvalueindex(1));
1008 			return 1;
1009 		}
1010 		else
1011 		{
1012 			index++;
1013 		}
1014 	}
1015 
1016 	lua_pushnil(L);
1017 	return 1;
1018 }
1019 
Lua_Polygon_Lines_Call(lua_State * L)1020 static int Lua_Polygon_Lines_Call(lua_State *L)
1021 {
1022 	lua_pushnumber(L, 0);
1023 	lua_pushvalue(L, 1);
1024 	lua_pushcclosure(L, Lua_Polygon_Lines_Iterator, 2);
1025 	return 1;
1026 }
1027 
Lua_Polygon_Lines_Get(lua_State * L)1028 static int Lua_Polygon_Lines_Get(lua_State *L)
1029 {
1030 	if (lua_isnumber(L, 2))
1031 	{
1032 		short polygon_index = Lua_Polygon_Lines::Index(L, 1);
1033 		polygon_data *polygon = get_polygon_data(polygon_index);
1034 		int line_index = static_cast<int>(lua_tonumber(L, 2));
1035 		if (line_index >= 0 && line_index < polygon->vertex_count)
1036 		{
1037 			Lua_Line::Push(L, polygon->line_indexes[line_index]);
1038 		}
1039 		else
1040 		{
1041 			lua_pushnil(L);
1042 		}
1043 	}
1044 
1045 	return 1;
1046 }
1047 
Lua_Polygon_Lines_Length(lua_State * L)1048 static int Lua_Polygon_Lines_Length(lua_State *L)
1049 {
1050 	lua_pushnumber(L, get_polygon_data(Lua_Polygon_Lines::Index(L, 1))->vertex_count);
1051 	return 1;
1052 }
1053 
1054 const luaL_Reg Lua_Polygon_Lines_Metatable[] = {
1055 	{"__index", Lua_Polygon_Lines_Get},
1056 	{"__call", Lua_Polygon_Lines_Call},
1057 	{"__len", Lua_Polygon_Lines_Length},
1058 	{0, 0}
1059 };
1060 
1061 char Lua_Polygon_Sides_Name[] = "polygon_sides";
1062 typedef L_Class<Lua_Polygon_Sides_Name> Lua_Polygon_Sides;
1063 
Lua_Polygon_Sides_Iterator(lua_State * L)1064 static int Lua_Polygon_Sides_Iterator(lua_State *L)
1065 {
1066 	int index = static_cast<int>(lua_tonumber(L, lua_upvalueindex(1)));
1067 	short polygon_index = Lua_Polygon_Sides::Index(L, lua_upvalueindex(2));
1068 	polygon_data *polygon = get_polygon_data(polygon_index);
1069 
1070 	while (index < polygon->vertex_count)
1071 	{
1072 		if (polygon->side_indexes[index] != NONE)
1073 		{
1074 			Lua_Side::Push(L, polygon->side_indexes[index]);
1075 			lua_pushnumber(L, ++index);
1076 			lua_replace(L, lua_upvalueindex(1));
1077 			return 1;
1078 		}
1079 		else
1080 		{
1081 			index++;
1082 		}
1083 	}
1084 
1085 	lua_pushnil(L);
1086 	return 1;
1087 }
1088 
Lua_Polygon_Sides_Call(lua_State * L)1089 static int Lua_Polygon_Sides_Call(lua_State *L)
1090 {
1091 	lua_pushnumber(L, 0);
1092 	lua_pushvalue(L, 1);
1093 	lua_pushcclosure(L, Lua_Polygon_Sides_Iterator, 2);
1094 	return 1;
1095 }
1096 
Lua_Polygon_Sides_Get(lua_State * L)1097 static int Lua_Polygon_Sides_Get(lua_State *L)
1098 {
1099 	if (lua_isnumber(L, 2))
1100 	{
1101 		short polygon_index = Lua_Polygon_Sides::Index(L, 1);
1102 		polygon_data *polygon = get_polygon_data(polygon_index);
1103 		int side_index = static_cast<int>(lua_tonumber(L, 2));
1104 		if (side_index >= 0 && side_index < polygon->vertex_count)
1105 		{
1106 			Lua_Side::Push(L, polygon->side_indexes[side_index]);
1107 		}
1108 		else
1109 		{
1110 			lua_pushnil(L);
1111 		}
1112 	}
1113 
1114 	return 1;
1115 }
1116 
Lua_Polygon_Sides_Length(lua_State * L)1117 static int Lua_Polygon_Sides_Length(lua_State *L)
1118 {
1119 	lua_pushnumber(L, get_polygon_data(Lua_Polygon_Sides::Index(L, 1))->vertex_count);
1120 	return 1;
1121 }
1122 
1123 const luaL_Reg Lua_Polygon_Sides_Metatable[] = {
1124 	{"__index", Lua_Polygon_Sides_Get},
1125 	{"__call", Lua_Polygon_Sides_Call},
1126 	{"__len", Lua_Polygon_Sides_Length},
1127 	{0, 0}
1128 };
1129 
1130 // contains(x, y, z)
Lua_Polygon_Contains(lua_State * L)1131 int Lua_Polygon_Contains(lua_State *L)
1132 {
1133 	if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3))
1134 		return luaL_error(L, ("contains: incorrect argument type"));
1135 
1136 	short polygon_index = Lua_Polygon::Index(L, 1);
1137 	polygon_data *polygon = get_polygon_data(polygon_index);
1138 
1139 	world_point2d p;
1140 	p.x = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
1141 	p.y = static_cast<world_distance>(lua_tonumber(L, 3) * WORLD_ONE);
1142 
1143 	world_distance z;
1144 	if (lua_gettop(L) == 4)
1145 	{
1146 		if (lua_isnumber(L, 4))
1147 			z = static_cast<world_distance>(lua_tonumber(L, 4) * WORLD_ONE);
1148 		else
1149 			return luaL_error(L, "contains: incorrect argument type");
1150 	}
1151 	else
1152 	{
1153 		z = polygon->floor_height;
1154 	}
1155 
1156 	lua_pushboolean(L, point_in_polygon(polygon_index, &p) && z >= polygon->floor_height && z <= polygon->ceiling_height);
1157 	return 1;
1158 }
1159 
1160 // line_crossed_leaving(x1, y1, x2, y2)
Lua_Polygon_Find_Line_Crossed_Leaving(lua_State * L)1161 int Lua_Polygon_Find_Line_Crossed_Leaving(lua_State *L)
1162 {
1163 	if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4) || !lua_isnumber(L, 5))
1164 		return luaL_error(L, ("find_line_crossed_leaving: incorrect argument type"));
1165 
1166 	world_point2d origin;
1167 	origin.x = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
1168 	origin.y = static_cast<world_distance>(lua_tonumber(L, 3) * WORLD_ONE);
1169 
1170 	world_point2d destination;
1171 	destination.x = static_cast<world_distance>(lua_tonumber(L, 4) * WORLD_ONE);
1172 	destination.y = static_cast<world_distance>(lua_tonumber(L, 5) * WORLD_ONE);
1173 
1174 	short line_index = find_line_crossed_leaving_polygon(Lua_Polygon::Index(L, 1), &origin, &destination);
1175 	if (line_index != NONE)
1176 	{
1177 		Lua_Line::Push(L, line_index);
1178 	}
1179 	else
1180 	{
1181 		lua_pushnil(L);
1182 	}
1183 
1184 	return 1;
1185 }
1186 
Lua_Polygon_Monsters_Iterator(lua_State * L)1187 static int Lua_Polygon_Monsters_Iterator(lua_State *L)
1188 {
1189 	int index = static_cast<int>(lua_tonumber(L, lua_upvalueindex(1)));
1190 	lua_pushvalue(L, lua_upvalueindex(2));
1191 	lua_pushnumber(L, index);
1192 	lua_gettable(L, -2);
1193 	lua_remove(L, -2);
1194 
1195 	lua_pushnumber(L, ++index);
1196 	lua_replace(L, lua_upvalueindex(1));
1197 
1198 	return 1;
1199 }
1200 
Lua_Polygon_Monsters(lua_State * L)1201 int Lua_Polygon_Monsters(lua_State *L)
1202 {
1203 	polygon_data *polygon = get_polygon_data(Lua_Polygon::Index(L, 1));
1204 
1205 	int table_index = 1;
1206 	short object_index = polygon->first_object;
1207 
1208 	lua_pushnumber(L, 1);
1209 	lua_newtable(L);
1210 	while (object_index != NONE)
1211 	{
1212 		object_data *object = get_object_data(object_index);
1213 		if (GET_OBJECT_OWNER(object) == _object_is_monster)
1214 		{
1215 			lua_pushnumber(L, table_index++);
1216 			Lua_Monster::Push(L, object->permutation);
1217 			lua_settable(L, -3);
1218 		}
1219 
1220 		object_index = object->next_object;
1221 	}
1222 
1223 	lua_pushcclosure(L, Lua_Polygon_Monsters_Iterator, 2);
1224 	return 1;
1225 }
1226 
1227 // play_sound(sound) or play_sound(x, y, z, sound, [pitch])
Lua_Polygon_Play_Sound(lua_State * L)1228 int Lua_Polygon_Play_Sound(lua_State *L)
1229 {
1230 	if (lua_gettop(L) == 2)
1231 	{
1232 		short sound_code = Lua_Sound::ToIndex(L, 2);
1233 		play_polygon_sound(Lua_Polygon::Index(L, 1), sound_code);
1234 	}
1235 	else
1236 	{
1237 		if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
1238 			return luaL_error(L, "play_sound: incorrect argument type");
1239 		world_location3d source;
1240 		source.point.x = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
1241 		source.point.y = static_cast<world_distance>(lua_tonumber(L, 3) * WORLD_ONE);
1242 		source.point.z = static_cast<world_distance>(lua_tonumber(L, 4) * WORLD_ONE);
1243 		source.polygon_index = Lua_Polygon::Index(L, 1);
1244 		short sound_code = Lua_Sound::ToIndex(L, 5);
1245 		_fixed pitch = FIXED_ONE;
1246 		if (lua_gettop(L) == 6)
1247 		{
1248 			if (!lua_isnumber(L, 6))
1249 				return luaL_error(L, "play_sound: incorrect argument type");
1250 			pitch = static_cast<_fixed>(lua_tonumber(L, 6) * FIXED_ONE);
1251 		}
1252 
1253 		SoundManager::instance()->PlaySound(sound_code, &source, NONE, pitch);
1254 	}
1255 
1256 	return 0;
1257 }
1258 
Lua_Polygon_Get_Adjacent(lua_State * L)1259 static int Lua_Polygon_Get_Adjacent(lua_State *L)
1260 {
1261 	Lua_Adjacent_Polygons::Push(L, Lua_Polygon::Index(L, 1));
1262 	return 1;
1263 }
1264 
Lua_Polygon_Get_Area(lua_State * L)1265 static int Lua_Polygon_Get_Area(lua_State *L)
1266 {
1267 	lua_pushnumber(L, (double) get_polygon_data(Lua_Polygon::Index(L, 1))->area / WORLD_ONE / WORLD_ONE);
1268 	return 1;
1269 }
1270 
Lua_Polygon_Get_Ceiling(lua_State * L)1271 static int Lua_Polygon_Get_Ceiling(lua_State *L)
1272 {
1273 	Lua_Polygon_Ceiling::Push(L, Lua_Polygon::Index(L, 1));
1274 	return 1;
1275 }
1276 
Lua_Polygon_Get_Endpoints(lua_State * L)1277 static int Lua_Polygon_Get_Endpoints(lua_State *L)
1278 {
1279 	Lua_Polygon_Endpoints::Push(L, Lua_Polygon::Index(L, 1));
1280 	return 1;
1281 }
1282 
Lua_Polygon_Get_Floor(lua_State * L)1283 static int Lua_Polygon_Get_Floor(lua_State *L)
1284 {
1285 	Lua_Polygon_Floor::Push(L, Lua_Polygon::Index(L, 1));
1286 	return 1;
1287 }
1288 
Lua_Polygon_Get_Lines(lua_State * L)1289 static int Lua_Polygon_Get_Lines(lua_State *L)
1290 {
1291 	Lua_Polygon_Lines::Push(L, Lua_Polygon::Index(L, 1));
1292 	return 1;
1293 }
1294 
Lua_Polygon_Get_Media(lua_State * L)1295 static int Lua_Polygon_Get_Media(lua_State *L)
1296 {
1297 	polygon_data *polygon = get_polygon_data(Lua_Polygon::Index(L, 1));
1298 	if (polygon->media_index != NONE)
1299 	{
1300 		Lua_Media::Push(L, polygon->media_index);
1301 	}
1302 	else
1303 	{
1304 		lua_pushnil(L);
1305 	}
1306 
1307 	return 1;
1308 }
1309 
Lua_Polygon_Get_Permutation(lua_State * L)1310 static int Lua_Polygon_Get_Permutation(lua_State *L)
1311 {
1312 	polygon_data *polygon = get_polygon_data(Lua_Polygon::Index(L, 1));
1313 	lua_pushnumber(L, polygon->permutation);
1314 	return 1;
1315 }
1316 
Lua_Polygon_Get_Sides(lua_State * L)1317 static int Lua_Polygon_Get_Sides(lua_State *L)
1318 {
1319 	Lua_Polygon_Sides::Push(L, Lua_Polygon::Index(L, 1));
1320 	return 1;
1321 }
1322 
Lua_Polygon_Get_Type(lua_State * L)1323 static int Lua_Polygon_Get_Type(lua_State *L)
1324 {
1325 	Lua_PolygonType::Push(L, get_polygon_data(Lua_Polygon::Index(L, 1))->type);
1326 	return 1;
1327 }
1328 
Lua_Polygon_Get_Platform(lua_State * L)1329 static int Lua_Polygon_Get_Platform(lua_State *L)
1330 {
1331 	polygon_data *polygon = get_polygon_data(Lua_Polygon::Index(L, 1));
1332 	if (polygon->type == _polygon_is_platform)
1333 	{
1334 		Lua_Platform::Push(L, polygon->permutation);
1335 	}
1336 	else
1337 	{
1338 		lua_pushnil(L);
1339 	}
1340 
1341 	return 1;
1342 }
1343 
Lua_Polygon_Get_X(lua_State * L)1344 static int Lua_Polygon_Get_X(lua_State *L)
1345 {
1346 	lua_pushnumber(L, (double) get_polygon_data(Lua_Polygon::Index(L, 1))->center.x / WORLD_ONE);
1347 	return 1;
1348 }
1349 
Lua_Polygon_Get_Y(lua_State * L)1350 static int Lua_Polygon_Get_Y(lua_State *L)
1351 {
1352 	lua_pushnumber(L, (double) get_polygon_data(Lua_Polygon::Index(L, 1))->center.y / WORLD_ONE);
1353 	return 1;
1354 }
1355 
Lua_Polygon_Get_Z(lua_State * L)1356 static int Lua_Polygon_Get_Z(lua_State *L)
1357 {
1358 	lua_pushnumber(L, (double) get_polygon_data(Lua_Polygon::Index(L, 1))->floor_height / WORLD_ONE);
1359 	return 1;
1360 }
1361 
Lua_Polygon_Get_Visible_On_Automap(lua_State * L)1362 static int Lua_Polygon_Get_Visible_On_Automap(lua_State *L)
1363 {
1364 	lua_pushboolean(L, POLYGON_IS_IN_AUTOMAP(Lua_Polygon::Index(L, 1)));
1365 	return 1;
1366 }
1367 
Lua_Polygon_Set_Media(lua_State * L)1368 static int Lua_Polygon_Set_Media(lua_State *L)
1369 {
1370 	polygon_data *polygon = get_polygon_data(Lua_Polygon::Index(L, 1));
1371 	short media_index = NONE;
1372 	if (lua_isnumber(L, 2))
1373 	{
1374 		media_index = static_cast<short>(lua_tonumber(L, 2));
1375 		if (media_index < 0 || media_index > MAXIMUM_MEDIAS_PER_MAP)
1376 			return luaL_error(L, "media: invalid media index");
1377 
1378 	}
1379 	else if (Lua_Media::Is(L, 2))
1380 	{
1381 		media_index = Lua_Media::Index(L, 2);
1382 	}
1383 	else if (!lua_isnil(L, 2))
1384 	{
1385 		return luaL_error(L, "media: incorrect argument type");
1386 	}
1387 
1388 	polygon->media_index = media_index;
1389 	return 0;
1390 }
1391 
Lua_Polygon_Set_Permutation(lua_State * L)1392 static int Lua_Polygon_Set_Permutation(lua_State *L)
1393 {
1394 	if (!lua_isnumber(L, 2))
1395 		return luaL_error(L, ("type: incorrect argument type"));
1396 
1397 	int permutation = static_cast<int>(lua_tonumber(L, 2));
1398 	get_polygon_data(Lua_Polygon::Index(L, 1))->permutation = permutation;
1399 	return 0;
1400 }
1401 
Lua_Polygon_Set_Type(lua_State * L)1402 static int Lua_Polygon_Set_Type(lua_State *L)
1403 {
1404 	short type = NONE;
1405 	if (lua_isnumber(L, 2))
1406 	{
1407 		type = static_cast<short>(lua_tonumber(L, 2));
1408 		if (type < 0 || type > _polygon_is_superglue) {
1409 			luaL_error(L, "type: invalid polygon type index");
1410 		}
1411 	}
1412 	else if (Lua_PolygonType::Is(L, 2)) {
1413 		type = Lua_PolygonType::Index(L, 2);
1414 	}
1415 	else
1416 	{
1417 		return luaL_error(L, "type: incorrect argument type");
1418 	}
1419 
1420 	get_polygon_data(Lua_Polygon::Index(L, 1))->type = type;
1421 	return 0;
1422 }
1423 
Lua_Polygon_Set_Visible_On_Automap(lua_State * L)1424 static int Lua_Polygon_Set_Visible_On_Automap(lua_State *L)
1425 {
1426 	if (!lua_isboolean(L, 2))
1427 		return luaL_error(L, ("visible_on_automap: incorrect argument type"));
1428 
1429 	if (lua_toboolean(L, 2))
1430 		ADD_POLYGON_TO_AUTOMAP(Lua_Polygon::Index(L, 1));
1431 	else
1432 		CLEAR_POLYGON_FROM_AUTOMAP(Lua_Polygon::Index(L, 1));
1433 	return 0;
1434 }
1435 
Lua_Polygon_Valid(int16 index)1436 static bool Lua_Polygon_Valid(int16 index)
1437 {
1438 	return index >= 0 && index < dynamic_world->polygon_count;
1439 }
1440 
1441 const luaL_Reg Lua_Polygon_Get[] = {
1442 	{"adjacent_polygons", Lua_Polygon_Get_Adjacent},
1443 	{"area", Lua_Polygon_Get_Area},
1444 	{"ceiling", Lua_Polygon_Get_Ceiling},
1445 	{"contains", L_TableFunction<Lua_Polygon_Contains>},
1446 	{"endpoints", Lua_Polygon_Get_Endpoints},
1447 	{"find_line_crossed_leaving", L_TableFunction<Lua_Polygon_Find_Line_Crossed_Leaving>},
1448 	{"floor", Lua_Polygon_Get_Floor},
1449 	{"lines", Lua_Polygon_Get_Lines},
1450 	{"media", Lua_Polygon_Get_Media},
1451 	{"monsters", L_TableFunction<Lua_Polygon_Monsters>},
1452 	{"permutation", Lua_Polygon_Get_Permutation},
1453 	{"platform", Lua_Polygon_Get_Platform},
1454 	{"play_sound", L_TableFunction<Lua_Polygon_Play_Sound>},
1455 	{"sides", Lua_Polygon_Get_Sides},
1456 	{"type", Lua_Polygon_Get_Type},
1457 	{"visible_on_automap", Lua_Polygon_Get_Visible_On_Automap},
1458 	{"x", Lua_Polygon_Get_X},
1459 	{"y", Lua_Polygon_Get_Y},
1460 	{"z", Lua_Polygon_Get_Z},
1461 	{0, 0}
1462 };
1463 
1464 const luaL_Reg Lua_Polygon_Set[] = {
1465 	{"media", Lua_Polygon_Set_Media},
1466 	{"permutation", Lua_Polygon_Set_Permutation},
1467 	{"type", Lua_Polygon_Set_Type},
1468 	{"visible_on_automap", Lua_Polygon_Set_Visible_On_Automap},
1469 	{0, 0}
1470 };
1471 
1472 char Lua_Polygons_Name[] = "Polygons";
1473 
Lua_Polygons_Length()1474 int16 Lua_Polygons_Length() {
1475 	return dynamic_world->polygon_count;
1476 }
1477 
1478 char Lua_Side_ControlPanel_Name[] = "side_control_panel";
1479 typedef L_Class<Lua_Side_ControlPanel_Name> Lua_Side_ControlPanel;
1480 
1481 template<int16 flag>
Lua_Side_ControlPanel_Get_Flag(lua_State * L)1482 static int Lua_Side_ControlPanel_Get_Flag(lua_State *L)
1483 {
1484 	side_data *side = get_side_data(Lua_Side_ControlPanel::Index(L, 1));
1485 	lua_pushboolean(L, side->flags & flag);
1486 	return 1;
1487 }
1488 
1489 template<int16 flag>
Lua_Side_ControlPanel_Set_Flag(lua_State * L)1490 static int Lua_Side_ControlPanel_Set_Flag(lua_State *L)
1491 {
1492 	if (!lua_isboolean(L, 2))
1493 		return luaL_error(L, "control_panel: incorrect argument type");
1494 
1495 	side_data *side = get_side_data(Lua_Side_ControlPanel::Index(L, 1));
1496 	if (lua_toboolean(L, 2))
1497 		side->flags |= flag;
1498 	else
1499 		side->flags &= ~flag;
1500 	return 0;
1501 }
1502 
Lua_Side_ControlPanel_Get_Type(lua_State * L)1503 static int Lua_Side_ControlPanel_Get_Type(lua_State *L)
1504 {
1505 	Lua_ControlPanelType::Push(L, get_side_data(Lua_Side_ControlPanel::Index(L, 1))->control_panel_type);
1506 	return 1;
1507 }
1508 
Lua_Side_ControlPanel_Get_Permutation(lua_State * L)1509 static int Lua_Side_ControlPanel_Get_Permutation(lua_State *L)
1510 {
1511 	lua_pushnumber(L, get_side_data(Lua_Side_ControlPanel::Index(L, 1))->control_panel_permutation);
1512 	return 1;
1513 }
1514 
Lua_Side_ControlPanel_Get_UsesItem(lua_State * L)1515 static int Lua_Side_ControlPanel_Get_UsesItem(lua_State* L)
1516 {
1517 	control_panel_definition* definition = get_control_panel_definition(get_side_data(Lua_Side_ControlPanel::Index(L, 1))->control_panel_type);
1518 	lua_pushboolean(L, definition->item != NONE);
1519 	return 1;
1520 }
1521 
1522 const luaL_Reg Lua_Side_ControlPanel_Get[] = {
1523 	{"can_be_destroyed", Lua_Side_ControlPanel_Get_Flag<_side_switch_can_be_destroyed>},
1524 	{"light_dependent", Lua_Side_ControlPanel_Get_Flag<_side_is_lighted_switch>},
1525 	{"only_toggled_by_weapons", Lua_Side_ControlPanel_Get_Flag<_side_switch_can_only_be_hit_by_projectiles>},
1526 	{"repair", Lua_Side_ControlPanel_Get_Flag<_side_is_repair_switch>},
1527 	{"status", Lua_Side_ControlPanel_Get_Flag<_control_panel_status>},
1528 	{"type", Lua_Side_ControlPanel_Get_Type},
1529 	{"permutation", Lua_Side_ControlPanel_Get_Permutation},
1530 	{"uses_item", Lua_Side_ControlPanel_Get_UsesItem},
1531 	{0, 0}
1532 };
1533 
Lua_Side_ControlPanel_Set_Permutation(lua_State * L)1534 static int Lua_Side_ControlPanel_Set_Permutation(lua_State *L)
1535 {
1536 	if (!lua_isnumber(L, 2))
1537 		return luaL_error(L, "permutation: incorrect argument type");
1538 
1539 	side_data *side = get_side_data(Lua_Side_ControlPanel::Index(L, 1));
1540 	side->control_panel_permutation = static_cast<int16>(lua_tonumber(L, 2));
1541 	return 0;
1542 }
1543 
1544 extern void set_control_panel_texture(side_data *);
1545 
Lua_Side_ControlPanel_Set_Type(lua_State * L)1546 static int Lua_Side_ControlPanel_Set_Type(lua_State *L)
1547 {
1548 	side_data *side = get_side_data(Lua_Side_ControlPanel::Index(L, 1));
1549 	side->control_panel_type = Lua_ControlPanelType::ToIndex(L, 2);
1550 	set_control_panel_texture(side);
1551 	return 0;
1552 }
1553 
1554 // the old version set a useless flag; instead, do nothing
Lua_Side_ControlPanel_Set_UsesItem(lua_State *)1555 static int Lua_Side_ControlPanel_Set_UsesItem(lua_State*)
1556 {
1557     return 0;
1558 }
1559 
1560 const luaL_Reg Lua_Side_ControlPanel_Set[] = {
1561 	{"can_be_destroyed", Lua_Side_ControlPanel_Set_Flag<_side_switch_can_be_destroyed>},
1562 	{"light_dependent", Lua_Side_ControlPanel_Set_Flag<_side_is_lighted_switch>},
1563 	{"only_toggled_by_weapons", Lua_Side_ControlPanel_Set_Flag<_side_switch_can_only_be_hit_by_projectiles>},
1564 	{"permutation", Lua_Side_ControlPanel_Set_Permutation},
1565 	{"repair", Lua_Side_ControlPanel_Set_Flag<_side_is_repair_switch>},
1566 	{"status", Lua_Side_ControlPanel_Set_Flag<_control_panel_status>},
1567 	{"type", Lua_Side_ControlPanel_Set_Type},
1568 	{"uses_item", Lua_Side_ControlPanel_Set_UsesItem},
1569 	{0, 0}
1570 };
1571 
1572 char Lua_Primary_Side_Name[] = "primary_side";
1573 typedef L_Class<Lua_Primary_Side_Name> Lua_Primary_Side;
1574 
Lua_Primary_Side_Get_Collection(lua_State * L)1575 static int Lua_Primary_Side_Get_Collection(lua_State *L)
1576 {
1577 	Lua_Collection::Push(L, GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(get_side_data(Lua_Primary_Side::Index(L, 1))->primary_texture.texture)));
1578 	return 1;
1579 }
1580 
Lua_Primary_Side_Get_Light(lua_State * L)1581 static int Lua_Primary_Side_Get_Light(lua_State *L)
1582 {
1583 	Lua_Light::Push(L, get_side_data(Lua_Primary_Side::Index(L, 1))->primary_lightsource_index);
1584 	return 1;
1585 }
1586 
Lua_Primary_Side_Get_Texture_Index(lua_State * L)1587 static int Lua_Primary_Side_Get_Texture_Index(lua_State *L)
1588 {
1589 	lua_pushnumber(L, GET_DESCRIPTOR_SHAPE(get_side_data(Lua_Primary_Side::Index(L, 1))->primary_texture.texture));
1590 	return 1;
1591 }
1592 
Lua_Primary_Side_Get_Texture_X(lua_State * L)1593 static int Lua_Primary_Side_Get_Texture_X(lua_State *L)
1594 {
1595 	lua_pushnumber(L, (double) (get_side_data(Lua_Primary_Side::Index(L, 1))->primary_texture.x0) / WORLD_ONE);
1596 	return 1;
1597 }
1598 
Lua_Primary_Side_Get_Texture_Y(lua_State * L)1599 static int Lua_Primary_Side_Get_Texture_Y(lua_State *L)
1600 {
1601 	lua_pushnumber(L, (double) (get_side_data(Lua_Primary_Side::Index(L, 1))->primary_texture.y0) / WORLD_ONE);
1602 	return 1;
1603 }
1604 
Lua_Primary_Side_Get_Transfer_Mode(lua_State * L)1605 static int Lua_Primary_Side_Get_Transfer_Mode(lua_State *L)
1606 {
1607 	Lua_TransferMode::Push(L, get_side_data(Lua_Primary_Side::Index(L, 1))->primary_transfer_mode);
1608 	return 1;
1609 }
1610 
update_line_redundancy(short line_index)1611 static void update_line_redundancy(short line_index)
1612 {
1613 	line_data *line= get_line_data(line_index);
1614 	side_data *clockwise_side= NULL, *counterclockwise_side= NULL;
1615 
1616 	bool landscaped= false;
1617 	bool transparent_texture= false;
1618 
1619 	if (line->clockwise_polygon_side_index!=NONE)
1620 	{
1621 		clockwise_side= get_side_data(line->clockwise_polygon_side_index);
1622 	}
1623 	if (line->counterclockwise_polygon_side_index!=NONE)
1624 	{
1625 		counterclockwise_side= get_side_data(line->counterclockwise_polygon_side_index);
1626 	}
1627 
1628 	if ((clockwise_side&&clockwise_side->primary_transfer_mode==_xfer_landscape) ||
1629 		(counterclockwise_side&&counterclockwise_side->primary_transfer_mode==_xfer_landscape))
1630 	{
1631 		landscaped= true;
1632 	}
1633 
1634 	if ((clockwise_side && clockwise_side->transparent_texture.texture!=UNONE) ||
1635 		(counterclockwise_side && counterclockwise_side->transparent_texture.texture!=UNONE))
1636 	{
1637 		transparent_texture= true;
1638 	}
1639 
1640 	SET_LINE_LANDSCAPE_STATUS(line, landscaped);
1641 	SET_LINE_HAS_TRANSPARENT_SIDE(line, transparent_texture);
1642 }
1643 
Lua_Primary_Side_Set_Collection(lua_State * L)1644 static int Lua_Primary_Side_Set_Collection(lua_State *L)
1645 {
1646 	short side_index = Lua_Primary_Side::Index(L, 1);
1647 	short collection_index = Lua_Collection::ToIndex(L, 2);
1648 
1649 	side_data *side = get_side_data(side_index);
1650 	side->primary_texture.texture = BUILD_DESCRIPTOR(collection_index, GET_DESCRIPTOR_SHAPE(side->primary_texture.texture));
1651 	update_line_redundancy(side->line_index);
1652 	return 0;
1653 }
1654 
Lua_Primary_Side_Set_Light(lua_State * L)1655 static int Lua_Primary_Side_Set_Light(lua_State *L)
1656 {
1657 	short light_index;
1658 	if (lua_isnumber(L, 2))
1659 	{
1660 		light_index = static_cast<short>(lua_tonumber(L, 2));
1661 		if (light_index < 0 || light_index >= MAXIMUM_LIGHTS_PER_MAP)
1662 			return luaL_error(L, "light: invalid light index");
1663 	}
1664 	else
1665 	{
1666 		light_index = Lua_Light::Index(L, 2);
1667 	}
1668 
1669 	get_side_data(Lua_Polygon_Floor::Index(L, 1))->primary_lightsource_index = light_index;
1670 	return 0;
1671 }
Lua_Primary_Side_Set_Texture_Index(lua_State * L)1672 static int Lua_Primary_Side_Set_Texture_Index(lua_State *L)
1673 {
1674 	side_data *side = get_side_data(Lua_Primary_Side::Index(L, 1));
1675 	if (!lua_isnumber(L, 2))
1676 		return luaL_error(L, "texture_index: incorrect argument type");
1677 
1678 	short shape_index = static_cast<short>(lua_tonumber(L, 2));
1679 	if (shape_index < 0 || shape_index >= MAXIMUM_SHAPES_PER_COLLECTION)
1680 		return luaL_error(L, "texture_index: invalid texture index");
1681 
1682 	side->primary_texture.texture = BUILD_DESCRIPTOR(GET_DESCRIPTOR_COLLECTION(side->primary_texture.texture), shape_index);
1683 	update_line_redundancy(side->line_index);
1684 	return 0;
1685 }
1686 
Lua_Primary_Side_Set_Texture_X(lua_State * L)1687 static int Lua_Primary_Side_Set_Texture_X(lua_State *L)
1688 {
1689 	side_data *side = get_side_data(Lua_Primary_Side::Index(L, 1));
1690 	if (!lua_isnumber(L, 2))
1691 		return luaL_error(L, "texture_x: incorrect argument type");
1692 
1693 	side->primary_texture.x0 = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
1694 	return 0;
1695 }
1696 
Lua_Primary_Side_Set_Texture_Y(lua_State * L)1697 static int Lua_Primary_Side_Set_Texture_Y(lua_State *L)
1698 {
1699 	side_data *side = get_side_data(Lua_Primary_Side::Index(L, 1));
1700 	if (!lua_isnumber(L, 2))
1701 		return luaL_error(L, "texture_y: incorrect argument type");
1702 
1703 	side->primary_texture.y0 = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
1704 	return 0;
1705 }
1706 
Lua_Primary_Side_Set_Transfer_Mode(lua_State * L)1707 static int Lua_Primary_Side_Set_Transfer_Mode(lua_State *L)
1708 {
1709 	side_data *side = get_side_data(Lua_Primary_Side::Index(L, 1));
1710 	side->primary_transfer_mode = Lua_TransferMode::ToIndex(L, 2);
1711 	return 0;
1712 }
1713 const luaL_Reg Lua_Primary_Side_Get[] = {
1714 	{"collection", Lua_Primary_Side_Get_Collection},
1715 	{"light", Lua_Primary_Side_Get_Light},
1716 	{"texture_index", Lua_Primary_Side_Get_Texture_Index},
1717 	{"texture_x", Lua_Primary_Side_Get_Texture_X},
1718 	{"texture_y", Lua_Primary_Side_Get_Texture_Y},
1719 	{"transfer_mode", Lua_Primary_Side_Get_Transfer_Mode},
1720 	{0, 0}
1721 };
1722 
1723 const luaL_Reg Lua_Primary_Side_Set[] = {
1724 	{"collection", Lua_Primary_Side_Set_Collection},
1725 	{"light", Lua_Primary_Side_Set_Light},
1726 	{"texture_index", Lua_Primary_Side_Set_Texture_Index},
1727 	{"texture_x", Lua_Primary_Side_Set_Texture_X},
1728 	{"texture_y", Lua_Primary_Side_Set_Texture_Y},
1729 	{"transfer_mode", Lua_Primary_Side_Set_Transfer_Mode},
1730 	{0, 0}
1731 };
1732 
1733 char Lua_Secondary_Side_Name[] = "secondary_side";
1734 typedef L_Class<Lua_Secondary_Side_Name> Lua_Secondary_Side;
1735 
Lua_Secondary_Side_Get_Collection(lua_State * L)1736 static int Lua_Secondary_Side_Get_Collection(lua_State *L)
1737 {
1738 	Lua_Collection::Push(L, GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(get_side_data(Lua_Secondary_Side::Index(L, 1))->secondary_texture.texture)));
1739 	return 1;
1740 }
1741 
Lua_Secondary_Side_Get_Light(lua_State * L)1742 static int Lua_Secondary_Side_Get_Light(lua_State *L)
1743 {
1744 	Lua_Light::Push(L, get_side_data(Lua_Secondary_Side::Index(L, 1))->secondary_lightsource_index);
1745 	return 1;
1746 }
1747 
Lua_Secondary_Side_Get_Texture_Index(lua_State * L)1748 static int Lua_Secondary_Side_Get_Texture_Index(lua_State *L)
1749 {
1750 	lua_pushnumber(L, GET_DESCRIPTOR_SHAPE(get_side_data(Lua_Secondary_Side::Index(L, 1))->secondary_texture.texture));
1751 	return 1;
1752 }
1753 
Lua_Secondary_Side_Get_Texture_X(lua_State * L)1754 static int Lua_Secondary_Side_Get_Texture_X(lua_State *L)
1755 {
1756 	lua_pushnumber(L, (double) (get_side_data(Lua_Secondary_Side::Index(L, 1))->secondary_texture.x0) / WORLD_ONE);
1757 	return 1;
1758 }
1759 
Lua_Secondary_Side_Get_Texture_Y(lua_State * L)1760 static int Lua_Secondary_Side_Get_Texture_Y(lua_State *L)
1761 {
1762 	lua_pushnumber(L, (double) (get_side_data(Lua_Secondary_Side::Index(L, 1))->secondary_texture.y0) / WORLD_ONE);
1763 	return 1;
1764 }
1765 
Lua_Secondary_Side_Get_Transfer_Mode(lua_State * L)1766 static int Lua_Secondary_Side_Get_Transfer_Mode(lua_State *L)
1767 {
1768 	Lua_TransferMode::Push(L, get_side_data(Lua_Secondary_Side::Index(L, 1))->secondary_transfer_mode);
1769 	return 1;
1770 }
1771 
Lua_Secondary_Side_Set_Collection(lua_State * L)1772 static int Lua_Secondary_Side_Set_Collection(lua_State *L)
1773 {
1774 	short side_index = Lua_Secondary_Side::Index(L, 1);
1775 	short collection_index = Lua_Collection::ToIndex(L, 2);
1776 
1777 	side_data *side = get_side_data(side_index);
1778 	side->secondary_texture.texture = BUILD_DESCRIPTOR(collection_index, GET_DESCRIPTOR_SHAPE(side->secondary_texture.texture));
1779 	update_line_redundancy(side->line_index);
1780 	return 0;
1781 }
1782 
Lua_Secondary_Side_Set_Light(lua_State * L)1783 static int Lua_Secondary_Side_Set_Light(lua_State *L)
1784 {
1785 	short light_index;
1786 	if (lua_isnumber(L, 2))
1787 	{
1788 		light_index = static_cast<short>(lua_tonumber(L, 2));
1789 		if (light_index < 0 || light_index >= MAXIMUM_LIGHTS_PER_MAP)
1790 			return luaL_error(L, "light: invalid light index");
1791 	}
1792 	else
1793 	{
1794 		light_index = Lua_Light::Index(L, 2);
1795 	}
1796 
1797 	get_side_data(Lua_Polygon_Floor::Index(L, 1))->secondary_lightsource_index = light_index;
1798 	return 0;
1799 }
Lua_Secondary_Side_Set_Texture_Index(lua_State * L)1800 static int Lua_Secondary_Side_Set_Texture_Index(lua_State *L)
1801 {
1802 	side_data *side = get_side_data(Lua_Secondary_Side::Index(L, 1));
1803 	if (!lua_isnumber(L, 2))
1804 		return luaL_error(L, "texture_index: incorrect argument type");
1805 
1806 	short shape_index = static_cast<short>(lua_tonumber(L, 2));
1807 	if (shape_index < 0 || shape_index >= MAXIMUM_SHAPES_PER_COLLECTION)
1808 		return luaL_error(L, "texture_index: invalid texture index");
1809 
1810 	side->secondary_texture.texture = BUILD_DESCRIPTOR(GET_DESCRIPTOR_COLLECTION(side->secondary_texture.texture), shape_index);
1811 	update_line_redundancy(side->line_index);
1812 	return 0;
1813 }
1814 
Lua_Secondary_Side_Set_Texture_X(lua_State * L)1815 static int Lua_Secondary_Side_Set_Texture_X(lua_State *L)
1816 {
1817 	side_data *side = get_side_data(Lua_Secondary_Side::Index(L, 1));
1818 	if (!lua_isnumber(L, 2))
1819 		return luaL_error(L, "texture_x: incorrect argument type");
1820 
1821 	side->secondary_texture.x0 = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
1822 	return 0;
1823 }
1824 
Lua_Secondary_Side_Set_Texture_Y(lua_State * L)1825 static int Lua_Secondary_Side_Set_Texture_Y(lua_State *L)
1826 {
1827 	side_data *side = get_side_data(Lua_Secondary_Side::Index(L, 1));
1828 	if (!lua_isnumber(L, 2))
1829 		return luaL_error(L, "texture_y: incorrect argument type");
1830 
1831 	side->secondary_texture.y0 = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
1832 	return 0;
1833 }
1834 
Lua_Secondary_Side_Set_Transfer_Mode(lua_State * L)1835 static int Lua_Secondary_Side_Set_Transfer_Mode(lua_State *L)
1836 {
1837 	side_data *side = get_side_data(Lua_Secondary_Side::Index(L, 1));
1838 	side->secondary_transfer_mode = Lua_TransferMode::ToIndex(L, 2);
1839 	return 0;
1840 }
1841 const luaL_Reg Lua_Secondary_Side_Get[] = {
1842 	{"collection", Lua_Secondary_Side_Get_Collection},
1843 	{"light", Lua_Secondary_Side_Get_Light},
1844 	{"texture_index", Lua_Secondary_Side_Get_Texture_Index},
1845 	{"texture_x", Lua_Secondary_Side_Get_Texture_X},
1846 	{"texture_y", Lua_Secondary_Side_Get_Texture_Y},
1847 	{"transfer_mode", Lua_Secondary_Side_Get_Transfer_Mode},
1848 	{0, 0}
1849 };
1850 
1851 const luaL_Reg Lua_Secondary_Side_Set[] = {
1852 	{"collection", Lua_Secondary_Side_Set_Collection},
1853 	{"light", Lua_Secondary_Side_Set_Light},
1854 	{"texture_index", Lua_Secondary_Side_Set_Texture_Index},
1855 	{"texture_x", Lua_Secondary_Side_Set_Texture_X},
1856 	{"texture_y", Lua_Secondary_Side_Set_Texture_Y},
1857 	{"transfer_mode", Lua_Secondary_Side_Set_Transfer_Mode},
1858 	{0, 0}
1859 };
1860 
1861 char Lua_Transparent_Side_Name[] = "transparent_side";
1862 typedef L_Class<Lua_Transparent_Side_Name> Lua_Transparent_Side;
1863 
Lua_Transparent_Side_Get_Collection(lua_State * L)1864 static int Lua_Transparent_Side_Get_Collection(lua_State *L)
1865 {
1866 	Lua_Collection::Push(L, GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(get_side_data(Lua_Transparent_Side::Index(L, 1))->transparent_texture.texture)));
1867 	return 1;
1868 }
1869 
Lua_Transparent_Side_Get_Empty(lua_State * L)1870 static int Lua_Transparent_Side_Get_Empty(lua_State *L)
1871 {
1872 	lua_pushboolean(L, get_side_data(Lua_Transparent_Side::Index(L, 1))->transparent_texture.texture == UNONE);
1873 	return 1;
1874 }
1875 
Lua_Transparent_Side_Get_Light(lua_State * L)1876 static int Lua_Transparent_Side_Get_Light(lua_State *L)
1877 {
1878 	Lua_Light::Push(L, get_side_data(Lua_Transparent_Side::Index(L, 1))->transparent_lightsource_index);
1879 	return 1;
1880 }
1881 
Lua_Transparent_Side_Get_Texture_Index(lua_State * L)1882 static int Lua_Transparent_Side_Get_Texture_Index(lua_State *L)
1883 {
1884 	lua_pushnumber(L, GET_DESCRIPTOR_SHAPE(get_side_data(Lua_Transparent_Side::Index(L, 1))->transparent_texture.texture));
1885 	return 1;
1886 }
1887 
Lua_Transparent_Side_Get_Texture_X(lua_State * L)1888 static int Lua_Transparent_Side_Get_Texture_X(lua_State *L)
1889 {
1890 	lua_pushnumber(L, (double) (get_side_data(Lua_Transparent_Side::Index(L, 1))->transparent_texture.x0) / WORLD_ONE);
1891 	return 1;
1892 }
1893 
Lua_Transparent_Side_Get_Texture_Y(lua_State * L)1894 static int Lua_Transparent_Side_Get_Texture_Y(lua_State *L)
1895 {
1896 	lua_pushnumber(L, (double) (get_side_data(Lua_Transparent_Side::Index(L, 1))->transparent_texture.y0) / WORLD_ONE);
1897 	return 1;
1898 }
1899 
Lua_Transparent_Side_Get_Transfer_Mode(lua_State * L)1900 static int Lua_Transparent_Side_Get_Transfer_Mode(lua_State *L)
1901 {
1902 	Lua_TransferMode::Push(L, get_side_data(Lua_Transparent_Side::Index(L, 1))->transparent_transfer_mode);
1903 	return 1;
1904 }
1905 
Lua_Transparent_Side_Set_Collection(lua_State * L)1906 static int Lua_Transparent_Side_Set_Collection(lua_State *L)
1907 {
1908 	short side_index = Lua_Transparent_Side::Index(L, 1);
1909 	short collection_index = Lua_Collection::ToIndex(L, 2);
1910 
1911 	side_data *side = get_side_data(side_index);
1912 	side->transparent_texture.texture = BUILD_DESCRIPTOR(collection_index, GET_DESCRIPTOR_SHAPE(side->transparent_texture.texture));
1913 	update_line_redundancy(side->line_index);
1914 	return 0;
1915 }
1916 
Lua_Transparent_Side_Set_Empty(lua_State * L)1917 static int Lua_Transparent_Side_Set_Empty(lua_State *L)
1918 {
1919 	short side_index = Lua_Transparent_Side::Index(L, 1);
1920 	if (!lua_isboolean(L, 2))
1921 		return luaL_error(L, "empty: incorrect argument type");
1922 
1923 	if (lua_toboolean(L, 2))
1924 	{
1925 		side_data *side = get_side_data(side_index);
1926 		side->transparent_texture.texture = UNONE;
1927 		update_line_redundancy(side->line_index);
1928 	}
1929 	return 0;
1930 }
1931 
Lua_Transparent_Side_Set_Light(lua_State * L)1932 static int Lua_Transparent_Side_Set_Light(lua_State *L)
1933 {
1934 	short light_index;
1935 	if (lua_isnumber(L, 2))
1936 	{
1937 		light_index = static_cast<short>(lua_tonumber(L, 2));
1938 		if (light_index < 0 || light_index >= MAXIMUM_LIGHTS_PER_MAP)
1939 			return luaL_error(L, "light: invalid light index");
1940 	}
1941 	else
1942 	{
1943 		light_index = Lua_Light::Index(L, 2);
1944 	}
1945 
1946 	get_side_data(Lua_Polygon_Floor::Index(L, 1))->transparent_lightsource_index = light_index;
1947 	return 0;
1948 }
1949 
Lua_Transparent_Side_Set_Texture_Index(lua_State * L)1950 static int Lua_Transparent_Side_Set_Texture_Index(lua_State *L)
1951 {
1952 	side_data *side = get_side_data(Lua_Transparent_Side::Index(L, 1));
1953 	if (!lua_isnumber(L, 2))
1954 		return luaL_error(L, "texture_index: incorrect argument type");
1955 
1956 	short shape_index = static_cast<short>(lua_tonumber(L, 2));
1957 	if (shape_index < 0 || shape_index >= MAXIMUM_SHAPES_PER_COLLECTION)
1958 		return luaL_error(L, "texture_index: invalid texture index");
1959 
1960 	side->transparent_texture.texture = BUILD_DESCRIPTOR(GET_DESCRIPTOR_COLLECTION(side->transparent_texture.texture), shape_index);
1961 	update_line_redundancy(side->line_index);
1962 	return 0;
1963 }
1964 
Lua_Transparent_Side_Set_Texture_X(lua_State * L)1965 static int Lua_Transparent_Side_Set_Texture_X(lua_State *L)
1966 {
1967 	side_data *side = get_side_data(Lua_Transparent_Side::Index(L, 1));
1968 	if (!lua_isnumber(L, 2))
1969 		return luaL_error(L, "texture_x: incorrect argument type");
1970 
1971 	side->transparent_texture.x0 = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
1972 	return 0;
1973 }
1974 
Lua_Transparent_Side_Set_Texture_Y(lua_State * L)1975 static int Lua_Transparent_Side_Set_Texture_Y(lua_State *L)
1976 {
1977 	side_data *side = get_side_data(Lua_Transparent_Side::Index(L, 1));
1978 	if (!lua_isnumber(L, 2))
1979 		return luaL_error(L, "texture_y: incorrect argument type");
1980 
1981 	side->transparent_texture.y0 = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
1982 	return 0;
1983 }
1984 
Lua_Transparent_Side_Set_Transfer_Mode(lua_State * L)1985 static int Lua_Transparent_Side_Set_Transfer_Mode(lua_State *L)
1986 {
1987 	side_data *side = get_side_data(Lua_Transparent_Side::Index(L, 1));
1988 	side->transparent_transfer_mode = Lua_TransferMode::ToIndex(L, 2);
1989 	return 0;
1990 }
1991 const luaL_Reg Lua_Transparent_Side_Get[] = {
1992 	{"collection", Lua_Transparent_Side_Get_Collection},
1993 	{"empty", Lua_Transparent_Side_Get_Empty},
1994 	{"light", Lua_Transparent_Side_Get_Light},
1995 	{"texture_index", Lua_Transparent_Side_Get_Texture_Index},
1996 	{"texture_x", Lua_Transparent_Side_Get_Texture_X},
1997 	{"texture_y", Lua_Transparent_Side_Get_Texture_Y},
1998 	{"transfer_mode", Lua_Transparent_Side_Get_Transfer_Mode},
1999 	{0, 0}
2000 };
2001 
2002 const luaL_Reg Lua_Transparent_Side_Set[] = {
2003 	{"collection", Lua_Transparent_Side_Set_Collection},
2004 	{"empty", Lua_Transparent_Side_Set_Empty},
2005 	{"light", Lua_Transparent_Side_Set_Light},
2006 	{"texture_index", Lua_Transparent_Side_Set_Texture_Index},
2007 	{"texture_x", Lua_Transparent_Side_Set_Texture_X},
2008 	{"texture_y", Lua_Transparent_Side_Set_Texture_Y},
2009 	{"transfer_mode", Lua_Transparent_Side_Set_Transfer_Mode},
2010 	{0, 0}
2011 };
2012 
2013 char Lua_SideType_Name[] = "side_type";
2014 char Lua_SideTypes_Name[] = "SideTypes";
2015 
2016 char Lua_Side_Name[] = "side";
2017 
Lua_Side_Play_Sound(lua_State * L)2018 int Lua_Side_Play_Sound(lua_State *L)
2019 {
2020 	short sound_code = Lua_Sound::ToIndex(L, 2);
2021 	_fixed pitch = FIXED_ONE;
2022 	if (lua_gettop(L) == 3)
2023 	{
2024 		if (!lua_isnumber(L, 3))
2025 			return luaL_error(L, "play_sound: incorrect argument type");
2026 		pitch = static_cast<_fixed>(lua_tonumber(L, 3) * FIXED_ONE);
2027 	}
2028 
2029 	_play_side_sound(Lua_Side::Index(L, 1), sound_code, pitch);
2030 	return 0;
2031 }
2032 
Lua_Side_Recalculate_Type(lua_State * L)2033 int Lua_Side_Recalculate_Type(lua_State *L)
2034 {
2035 	recalculate_side_type(Lua_Side::Index(L, 1));
2036 	return 0;
2037 }
2038 
Lua_Side_Get_Control_Panel(lua_State * L)2039 static int Lua_Side_Get_Control_Panel(lua_State *L)
2040 {
2041 	int16 side_index = Lua_Side::Index(L, 1);
2042 	side_data *side = get_side_data(side_index);
2043 	if (SIDE_IS_CONTROL_PANEL(side))
2044 	{
2045 		Lua_Side_ControlPanel::Push(L, side_index);
2046 	}
2047 	else
2048 	{
2049 		lua_pushnil(L);
2050 	}
2051 
2052 	return 1;
2053 }
2054 
Lua_Side_Get_Line(lua_State * L)2055 static int Lua_Side_Get_Line(lua_State *L)
2056 {
2057 	Lua_Line::Push(L, get_side_data(Lua_Side::Index(L, 1))->line_index);
2058 	return 1;
2059 }
2060 
Lua_Side_Get_Polygon(lua_State * L)2061 static int Lua_Side_Get_Polygon(lua_State *L)
2062 {
2063 	Lua_Polygon::Push(L, get_side_data(Lua_Side::Index(L, 1))->polygon_index);
2064 	return 1;
2065 }
2066 
Lua_Side_Get_Primary(lua_State * L)2067 static int Lua_Side_Get_Primary(lua_State *L)
2068 {
2069 	Lua_Primary_Side::Push(L, Lua_Side::Index(L, 1));
2070 	return 1;
2071 }
2072 
Lua_Side_Get_Secondary(lua_State * L)2073 static int Lua_Side_Get_Secondary(lua_State *L)
2074 {
2075 	Lua_Secondary_Side::Push(L, Lua_Side::Index(L, 1));
2076 	return 1;
2077 }
2078 
Lua_Side_Get_Transparent(lua_State * L)2079 static int Lua_Side_Get_Transparent(lua_State *L)
2080 {
2081 	Lua_Transparent_Side::Push(L, Lua_Side::Index(L, 1));
2082 	return 1;
2083 }
2084 
Lua_Side_Get_Type(lua_State * L)2085 static int Lua_Side_Get_Type(lua_State *L)
2086 {
2087 	Lua_SideType::Push(L, get_side_data(Lua_Side::Index(L, 1))->type);
2088 	return 1;
2089 }
2090 
2091 const luaL_Reg Lua_Side_Get[] = {
2092 	{"control_panel", Lua_Side_Get_Control_Panel},
2093 	{"line", Lua_Side_Get_Line},
2094 	{"play_sound", L_TableFunction<Lua_Side_Play_Sound>},
2095 	{"polygon", Lua_Side_Get_Polygon},
2096 	{"primary", Lua_Side_Get_Primary},
2097 	{"recalculate_type", L_TableFunction<Lua_Side_Recalculate_Type>},
2098 	{"secondary", Lua_Side_Get_Secondary},
2099 	{"transparent", Lua_Side_Get_Transparent},
2100 	{"type", Lua_Side_Get_Type},
2101 	{0, 0}
2102 };
2103 
Lua_Side_Set_Control_Panel(lua_State * L)2104 static int Lua_Side_Set_Control_Panel(lua_State *L)
2105 {
2106 	if (!lua_isboolean(L, 2))
2107 		return luaL_error(L, "control_panel: incorrect argument type");
2108 
2109 	side_data *side = get_side_data(Lua_Side::Index(L, 1));
2110 
2111 	if (lua_toboolean(L, 2) != (side->flags & _side_is_control_panel))
2112 	{
2113 		// new control panel, or deleting old; clear either way
2114 		side->control_panel_type = NONE;
2115 		side->flags &= ~(_control_panel_status | _side_is_control_panel | _side_is_repair_switch | _side_is_destructive_switch | _side_is_lighted_switch | _side_switch_can_be_destroyed | _side_switch_can_only_be_hit_by_projectiles);
2116 
2117 		if (lua_toboolean(L, 2))
2118 			side->flags |= _side_is_control_panel;
2119 	}
2120 
2121 	return 0;
2122 }
2123 
2124 const luaL_Reg Lua_Side_Set[] = {
2125 	{"control_panel", Lua_Side_Set_Control_Panel},
2126 	{0, 0}
2127 };
2128 
2129 
Lua_Side_Valid(int16 index)2130 static bool Lua_Side_Valid(int16 index)
2131 {
2132 	return index >= 0 && index < SideList.size();
2133 }
2134 
2135 char Lua_Sides_Name[] = "Sides";
Lua_Sides_Length()2136 static int16 Lua_Sides_Length() { return SideList.size(); }
2137 
2138 // Sides.new(polygon, line)
Lua_Sides_New(lua_State * L)2139 int Lua_Sides_New(lua_State *L)
2140 {
2141 	short polygon_index;
2142 	if (lua_isnumber(L, 1))
2143 	{
2144 		polygon_index = static_cast<short>(lua_tonumber(L, 1));
2145 		if (!Lua_Polygon::Valid(polygon_index))
2146 			return luaL_error(L, "new: invalid polygon index");
2147 	}
2148 	else if (Lua_Polygon::Is(L, 1))
2149 		polygon_index = Lua_Polygon::Index(L, 1);
2150 	else
2151 		return luaL_error(L, "new: incorrect argument type");
2152 
2153 	short line_index;
2154 	if (lua_isnumber(L, 2))
2155 	{
2156 		line_index = static_cast<short>(lua_tonumber(L, 2));
2157 		if (!Lua_Line::Valid(line_index))
2158 			return luaL_error(L, "new: invalid line index");
2159 	}
2160 	else if (Lua_Line::Is(L, 2))
2161 		line_index = Lua_Line::Index(L, 2);
2162 	else
2163 		return luaL_error(L, "new: incorrect argument type");
2164 
2165 	// make sure we don't assert
2166 	line_data *line = get_line_data(line_index);
2167 	if (!(line->clockwise_polygon_owner == polygon_index || line->counterclockwise_polygon_owner == polygon_index))
2168 		return luaL_error(L, "new: line does not belong to polygon");
2169 
2170 	if ((line->clockwise_polygon_owner == polygon_index && line->clockwise_polygon_side_index != NONE) || (line->counterclockwise_polygon_owner == polygon_index && line->counterclockwise_polygon_side_index != NONE))
2171 		return luaL_error(L, "new: side already exists");
2172 
2173 	Lua_Side::Push(L, new_side(polygon_index, line_index));
2174 	return 1;
2175 }
2176 
2177 const luaL_Reg Lua_Sides_Methods[] = {
2178 	{"new", L_TableFunction<Lua_Sides_New>},
2179 	{0, 0}
2180 };
2181 
2182 char Lua_LightFunction_Name[] = "light_function";
2183 typedef L_Enum<Lua_LightFunction_Name> Lua_LightFunction;
2184 
2185 char Lua_LightFunctions_Name[] = "LightFunctions";
2186 typedef L_EnumContainer<Lua_LightFunctions_Name, Lua_LightFunction> Lua_LightFunctions;
2187 
2188 char Lua_LightPreset_Name[] = "light_preset";
2189 typedef L_Enum<Lua_LightPreset_Name> Lua_LightPreset;
2190 
2191 char Lua_LightPresets_Name[] = "LightPresets";
2192 typedef L_EnumContainer<Lua_LightPresets_Name, Lua_LightPreset> Lua_LightPresets;
2193 
2194 char Lua_LightState_Name[] = "light_state";
2195 typedef L_Enum<Lua_LightState_Name> Lua_LightState;
2196 
2197 char Lua_LightStates_Name[] = "LightStates";
2198 typedef L_EnumContainer<Lua_LightStates_Name, Lua_LightState> Lua_LightStates;
2199 
2200 char Lua_Light_State_Name[] = "light_state_subtable";
2201 
2202 class Lua_Light_State : public L_Class<Lua_Light_State_Name>
2203 {
2204 public:
2205 	int16 m_light_index;
2206 	static Lua_Light_State* Push(lua_State* L, int16 light_index, int16 index);
2207 	static int16 LightIndex(lua_State* L, int index);
2208 };
2209 
Push(lua_State * L,int16 light_index,int16 index)2210 Lua_Light_State* Lua_Light_State::Push(lua_State* L, int16 light_index, int16 index)
2211 {
2212 	Lua_Light_State* t = 0;
2213 
2214 	if (!Lua_Light_State::Valid(index) || !Lua_Light::Valid(light_index))
2215 	{
2216 		lua_pushnil(L);
2217 		return 0;
2218 	}
2219 
2220 	t = NewInstance<Lua_Light_State>(L, index);
2221 	t->m_light_index = light_index;
2222 
2223 	return t;
2224 }
2225 
LightIndex(lua_State * L,int index)2226 int16 Lua_Light_State::LightIndex(lua_State* L, int index)
2227 {
2228 	Lua_Light_State* t = static_cast<Lua_Light_State*>(Instance(L, index));
2229 	if (!t) luaL_typerror(L, index, Lua_Light_State_Name);
2230 	return t->m_light_index;
2231 }
2232 
get_light_function_spec(int light_index,int state)2233 static lighting_function_specification* get_light_function_spec(int light_index, int state)
2234 {
2235 	light_data* light = get_light_data(light_index);
2236 	switch (state)
2237 	{
2238 	case _light_becoming_active:
2239 		return &light->static_data.becoming_active;
2240 	case _light_primary_active:
2241 		return &light->static_data.primary_active;
2242 	case _light_secondary_active:
2243 		return &light->static_data.secondary_active;
2244 	case _light_becoming_inactive:
2245 		return &light->static_data.becoming_inactive;
2246 	case _light_primary_inactive:
2247 		return &light->static_data.primary_inactive;
2248 	case _light_secondary_inactive:
2249 		return &light->static_data.secondary_inactive;
2250 	default:
2251 		assert(false);
2252 	}
2253 
2254 	return 0;
2255 }
2256 
Lua_Light_State_Get_Delta_Intensity(lua_State * L)2257 static int Lua_Light_State_Get_Delta_Intensity(lua_State* L)
2258 {
2259 	int light_index = Lua_Light_State::LightIndex(L, 1);
2260 	lighting_function_specification* spec = get_light_function_spec(light_index, Lua_Light_State::Index(L, 1));
2261 	lua_pushnumber(L, static_cast<double>(spec->delta_intensity) / FIXED_ONE);
2262 	return 1;
2263 }
2264 
Lua_Light_State_Get_Delta_Period(lua_State * L)2265 static int Lua_Light_State_Get_Delta_Period(lua_State* L)
2266 {
2267 	int light_index = Lua_Light_State::LightIndex(L, 1);
2268 	lighting_function_specification* spec = get_light_function_spec(light_index, Lua_Light_State::Index(L, 1));
2269 	lua_pushnumber(L, static_cast<double>(spec->delta_period));
2270 	return 1;
2271 }
2272 
Lua_Light_State_Get_Function(lua_State * L)2273 static int Lua_Light_State_Get_Function(lua_State* L)
2274 {
2275 	int light_index = Lua_Light_State::LightIndex(L, 1);
2276 	lighting_function_specification* spec = get_light_function_spec(light_index, Lua_Light_State::Index(L, 1));
2277 	Lua_LightFunction::Push(L, spec->function);
2278 	return 1;
2279 }
2280 
Lua_Light_State_Get_Intensity(lua_State * L)2281 static int Lua_Light_State_Get_Intensity(lua_State* L)
2282 {
2283 	int light_index = Lua_Light_State::LightIndex(L, 1);
2284 	lighting_function_specification* spec = get_light_function_spec(light_index, Lua_Light_State::Index(L, 1));
2285 	lua_pushnumber(L, static_cast<double>(spec->intensity) / FIXED_ONE);
2286 	return 1;
2287 }
2288 
Lua_Light_State_Get_Period(lua_State * L)2289 static int Lua_Light_State_Get_Period(lua_State* L)
2290 {
2291 	int light_index = Lua_Light_State::LightIndex(L, 1);
2292 	lighting_function_specification* spec = get_light_function_spec(light_index, Lua_Light_State::Index(L, 1));
2293 	lua_pushnumber(L, static_cast<double>(spec->period));
2294 	return 1;
2295 }
2296 
2297 
2298 const luaL_Reg Lua_Light_State_Get[] = {
2299 	{"delta_intensity", Lua_Light_State_Get_Delta_Intensity},
2300 	{"delta_period", Lua_Light_State_Get_Delta_Period},
2301 	{"intensity", Lua_Light_State_Get_Intensity},
2302 	{"light_function", Lua_Light_State_Get_Function},
2303 	{"period", Lua_Light_State_Get_Period},
2304 	{0, 0}
2305 };
2306 
Lua_Light_State_Set_Delta_Intensity(lua_State * L)2307 static int Lua_Light_State_Set_Delta_Intensity(lua_State* L)
2308 {
2309 	if (!lua_isnumber(L, 2))
2310 		return luaL_error(L, "delta_intensity: incorrect argument type");
2311 
2312 	lighting_function_specification* spec = get_light_function_spec(Lua_Light_State::LightIndex(L, 1), Lua_Light_State::Index(L, 1));
2313 	spec->delta_intensity = static_cast<int32>(lua_tonumber(L, 2) * FIXED_ONE);
2314 	return 1;
2315 }
2316 
Lua_Light_State_Set_Delta_Period(lua_State * L)2317 static int Lua_Light_State_Set_Delta_Period(lua_State* L)
2318 {
2319 	if (!lua_isnumber(L, 2))
2320 		return luaL_error(L, "delta_period: incorrect argument type");
2321 
2322 	int16 period = lua_tonumber(L, 2);
2323 	if (period < 0)
2324 		return luaL_error(L, "delta_period: must be nonnegative");
2325 
2326 	lighting_function_specification* spec = get_light_function_spec(Lua_Light_State::LightIndex(L, 1), Lua_Light_State::Index(L, 1));
2327 	spec->delta_period = period;
2328 	return 1;
2329 }
2330 
Lua_Light_State_Set_Function(lua_State * L)2331 static int Lua_Light_State_Set_Function(lua_State* L)
2332 {
2333 	int16 function = Lua_LightFunction::ToIndex(L, 2);
2334 	lighting_function_specification* spec = get_light_function_spec(Lua_Light_State::LightIndex(L, 1), Lua_Light_State::Index(L, 1));
2335 	spec->function = function;
2336 	return 1;
2337 }
2338 
Lua_Light_State_Set_Intensity(lua_State * L)2339 static int Lua_Light_State_Set_Intensity(lua_State* L)
2340 {
2341 	if (!lua_isnumber(L, 2))
2342 		return luaL_error(L, "intensity: incorrect argument type");
2343 
2344 	lighting_function_specification* spec = get_light_function_spec(Lua_Light_State::LightIndex(L, 1), Lua_Light_State::Index(L, 1));
2345 	spec->intensity = static_cast<int32>(lua_tonumber(L, 2) * FIXED_ONE);
2346 	return 1;
2347 }
2348 
Lua_Light_State_Set_Period(lua_State * L)2349 static int Lua_Light_State_Set_Period(lua_State* L)
2350 {
2351 	if (!lua_isnumber(L, 2))
2352 		return luaL_error(L, "period: incorrect argument type");
2353 
2354 	int16 period = lua_tonumber(L, 2);
2355 	if (period < 0)
2356 		return luaL_error(L, "period: must be nonnegative");
2357 
2358 	lighting_function_specification* spec = get_light_function_spec(Lua_Light_State::LightIndex(L, 1), Lua_Light_State::Index(L, 1));
2359 	spec->period = period;
2360 	return 1;
2361 }
2362 
2363 const luaL_Reg Lua_Light_State_Set[] = {
2364 	{"delta_intensity", Lua_Light_State_Set_Delta_Intensity},
2365 	{"delta_period", Lua_Light_State_Set_Delta_Period},
2366 	{"intensity", Lua_Light_State_Set_Intensity},
2367 	{"light_function", Lua_Light_State_Set_Function},
2368 	{"period", Lua_Light_State_Set_Period},
2369 	{0, 0}
2370 };
2371 
2372 char Lua_Light_States_Name[] = "light_states";
2373 typedef L_Class<Lua_Light_States_Name> Lua_Light_States;
2374 
Lua_Light_States_Get(lua_State * L)2375 static int Lua_Light_States_Get(lua_State* L)
2376 {
2377 	int light_index = Lua_Light_States::Index(L, 1);
2378 	int state_index = Lua_LightState::ToIndex(L, 2);
2379 	Lua_Light_State::Push(L, light_index, state_index);
2380 	return 1;
2381 }
2382 
Lua_Light_States_Length(lua_State * L)2383 static int Lua_Light_States_Length(lua_State* L)
2384 {
2385 	lua_pushnumber(L, static_cast<int16>(_light_secondary_inactive) + 1);
2386 	return 1;
2387 }
2388 
2389 const luaL_Reg Lua_Light_States_Metatable[] = {
2390 	{"__index", Lua_Light_States_Get},
2391 	{"__len", Lua_Light_States_Length},
2392 	{0, 0}
2393 };
2394 
2395 char Lua_Light_Name[] = "light";
2396 
Lua_Light_Get_Active(lua_State * L)2397 static int Lua_Light_Get_Active(lua_State *L)
2398 {
2399 	lua_pushboolean(L, get_light_status(Lua_Light::Index(L, 1)));
2400 	return 1;
2401 }
2402 
Lua_Light_Get_Intensity(lua_State * L)2403 static int Lua_Light_Get_Intensity(lua_State* L)
2404 {
2405 	lua_pushnumber(L, static_cast<double>(get_light_intensity(Lua_Light::Index(L, 1))) / FIXED_ONE);
2406 	return 1;
2407 }
2408 
Lua_Light_Get_Initial_Phase(lua_State * L)2409 static int Lua_Light_Get_Initial_Phase(lua_State* L)
2410 {
2411 	light_data* data = get_light_data(Lua_Light::Index(L, 1));
2412 	lua_pushnumber(L, static_cast<double>(data->static_data.phase));
2413 	return 1;
2414 }
2415 
Lua_Light_Get_Initially_Active(lua_State * L)2416 static int Lua_Light_Get_Initially_Active(lua_State* L)
2417 {
2418 	light_data* data = get_light_data(Lua_Light::Index(L, 1));
2419 	lua_pushboolean(L, data->static_data.flags & _light_is_initially_active);
2420 	return 1;
2421 }
2422 
Lua_Light_Get_States(lua_State * L)2423 static int Lua_Light_Get_States(lua_State *L)
2424 {
2425 	Lua_Light_States::Push(L, Lua_Light::Index(L, 1));
2426 	return 1;
2427 }
2428 
Lua_Light_Get_Tag(lua_State * L)2429 static int Lua_Light_Get_Tag(lua_State* L)
2430 {
2431 	light_data* data = get_light_data(Lua_Light::Index(L, 1));
2432 	Lua_Tag::Push(L, data->static_data.tag);
2433 	return 1;
2434 }
2435 
2436 const luaL_Reg Lua_Light_Get[] = {
2437 	{"active", Lua_Light_Get_Active},
2438 	{"initial_phase", Lua_Light_Get_Initial_Phase},
2439 	{"initially_active", Lua_Light_Get_Initially_Active},
2440 	{"intensity", Lua_Light_Get_Intensity},
2441 	{"states", Lua_Light_Get_States},
2442 	{"tag", Lua_Light_Get_Tag},
2443 	{0, 0}
2444 };
2445 
Lua_Light_Set_Active(lua_State * L)2446 static int Lua_Light_Set_Active(lua_State *L)
2447 {
2448 	if (!lua_isboolean(L, 2))
2449 		return luaL_error(L, "active: incorrect argument type");
2450 
2451 	size_t light_index = Lua_Light::Index(L, 1);
2452 	bool active = lua_toboolean(L, 2);
2453 
2454 	set_light_status(light_index, active);
2455 	assume_correct_switch_position(_panel_is_light_switch, static_cast<short>(light_index), active);
2456 	return 0;
2457 }
2458 
Lua_Light_Set_Initially_Active(lua_State * L)2459 static int Lua_Light_Set_Initially_Active(lua_State* L)
2460 {
2461 	if (!lua_isboolean(L, 2))
2462 		return luaL_error(L, "initially_active: incorrect argument type");
2463 
2464 	light_data* data = get_light_data(Lua_Light::Index(L, 1));
2465 	bool active = lua_toboolean(L, 2);
2466 	if (active)
2467 	{
2468 		data->static_data.flags |= _light_is_initially_active;
2469 	}
2470 	else
2471 	{
2472 		data->static_data.flags &= ~_light_is_initially_active;
2473 	}
2474 
2475 	return 0;
2476 }
2477 
Lua_Light_Set_Phase(lua_State * L)2478 static int Lua_Light_Set_Phase(lua_State* L)
2479 {
2480 	if (!lua_isnumber(L, 2))
2481 		return luaL_error(L, "phase: incorrect argument type");
2482 
2483 	light_data* data = get_light_data(Lua_Light::Index(L, 1));
2484 	data->static_data.phase = static_cast<int16>(lua_tonumber(L, 2));
2485 	return 0;
2486 }
2487 
Lua_Light_Set_Tag(lua_State * L)2488 static int Lua_Light_Set_Tag(lua_State* L)
2489 {
2490 	int16 tag = NONE;
2491 	if (lua_isnumber(L, 2))
2492 	{
2493 		tag = static_cast<int16>(lua_tonumber(L, 2));
2494 		if (!Lua_Tag::Valid(tag))
2495 			return luaL_error(L, "tag: invalid tag index");
2496 	}
2497 	else if (Lua_Tag::Is(L, 2))
2498 	{
2499 		tag = Lua_Tag::Index(L, 2);
2500 	}
2501 	else return luaL_error(L, "tag: incorrect argument type");
2502 
2503 	light_data* data = get_light_data(Lua_Light::Index(L, 1));
2504 	data->static_data.tag = tag;
2505 	return 0;
2506 }
2507 
2508 const luaL_Reg Lua_Light_Set[] = {
2509 	{"active", Lua_Light_Set_Active},
2510 	{"initial_phase", Lua_Light_Set_Phase},
2511 	{"initially_active", Lua_Light_Set_Initially_Active},
2512 	{"tag", Lua_Light_Set_Tag},
2513 	{0, 0}
2514 };
2515 
Lua_Light_Valid(int16 index)2516 bool Lua_Light_Valid(int16 index)
2517 {
2518 	return index >= 0 && index < MAXIMUM_LIGHTS_PER_MAP;
2519 }
2520 
2521 char Lua_Lights_Name[] = "Lights";
Lua_Lights_Length()2522 static int16 Lua_Lights_Length() { return LightList.size(); }
2523 
Lua_Lights_New(lua_State * L)2524 int Lua_Lights_New(lua_State* L)
2525 {
2526 	if (LightList.size() == INT16_MAX)
2527 		return 0;
2528 
2529 	short type;
2530 	if (lua_isnil(L, 1))
2531 	{
2532 		type = _normal_light;
2533 	}
2534 	else
2535 	{
2536 		type = Lua_LightPreset::ToIndex(L, 1);
2537 	}
2538 
2539 	LightList.resize(LightList.size() + 1);
2540 	short index = new_light(get_defaults_for_light_type(type));
2541 	Lua_Light::Push(L, index);
2542 	return 1;
2543 }
2544 
2545 const luaL_Reg Lua_Lights_Methods[] = {
2546 	{"new", L_TableFunction<Lua_Lights_New>},
2547 	{0, 0}
2548 };
2549 
2550 char Lua_Tag_Name[] = "tag";
2551 
Lua_Tag_Get_Active(lua_State * L)2552 static int Lua_Tag_Get_Active(lua_State *L)
2553 {
2554 	int tag = Lua_Tag::Index(L, 1);
2555 	bool changed = false;
2556 
2557 	size_t light_index;
2558 	light_data *light;
2559 
2560 	for (light_index= 0, light= lights; light_index<MAXIMUM_LIGHTS_PER_MAP && !changed; ++light_index, ++light)
2561 	{
2562 		if (light->static_data.tag==tag)
2563 		{
2564 			if (get_light_status(light_index))
2565 			{
2566 				changed= true;
2567 			}
2568 		}
2569 	}
2570 
2571 	short platform_index;
2572 	platform_data *platform;
2573 
2574 	for (platform_index= 0, platform= platforms; platform_index<dynamic_world->platform_count && !changed; ++platform_index, ++platform)
2575 	{
2576 		if (platform->tag==tag)
2577 		{
2578 			if (PLATFORM_IS_ACTIVE(platform))
2579 			{
2580 				changed= true;
2581 			}
2582 		}
2583 	}
2584 
2585 	lua_pushboolean(L, changed);
2586 	return 1;
2587 }
2588 
Lua_Tag_Set_Active(lua_State * L)2589 static int Lua_Tag_Set_Active(lua_State *L)
2590 {
2591 	if (!lua_isboolean(L, 2))
2592 		return luaL_error(L, "active: incorrect argument type");
2593 
2594 	int16 tag = Lua_Tag::Index(L, 1);
2595 	bool active = lua_toboolean(L, 2);
2596 
2597 	set_tagged_light_statuses(tag, active);
2598 	try_and_change_tagged_platform_states(tag, active);
2599 	assume_correct_switch_position(_panel_is_tag_switch, tag, active);
2600 
2601 	return 0;
2602 }
2603 
2604 const luaL_Reg Lua_Tag_Get[] = {
2605 	{"active", Lua_Tag_Get_Active},
2606 	{0, 0}
2607 };
2608 
2609 const luaL_Reg Lua_Tag_Set[] = {
2610 	{"active", Lua_Tag_Set_Active},
2611 	{0, 0}
2612 };
2613 
Lua_Tag_Valid(int16 index)2614 bool Lua_Tag_Valid(int16 index) { return index >= 0; }
2615 
2616 char Lua_Tags_Name[] = "Tags";
2617 
2618 char Lua_Terminal_Name[] = "terminal";
2619 
2620 extern short number_of_terminal_texts();
2621 
Lua_Terminal_Valid(int16 index)2622 static bool Lua_Terminal_Valid(int16 index)
2623 {
2624 	return index >= 0 && index < number_of_terminal_texts();
2625 }
2626 
2627 char Lua_Terminals_Name[] = "Terminals";
2628 
Lua_Terminals_Length()2629 static int16 Lua_Terminals_Length() {
2630 	return number_of_terminal_texts();
2631 }
2632 
2633 char Lua_MediaType_Name[] = "media_type";
2634 typedef L_Enum<Lua_MediaType_Name> Lua_MediaType;
2635 
2636 char Lua_MediaTypes_Name[] = "MediaTypes";
2637 typedef L_EnumContainer<Lua_MediaTypes_Name, Lua_MediaType> Lua_MediaTypes;
2638 
2639 char Lua_Media_Name[] = "media";
2640 
2641 const float AngleConvert = 360/float(FULL_CIRCLE);
2642 
Lua_Media_Get_Direction(lua_State * L)2643 static int Lua_Media_Get_Direction(lua_State* L)
2644 {
2645 	media_data* media = get_media_data(Lua_Media::Index(L, 1));
2646 	lua_pushnumber(L, static_cast<double>(media->current_direction) * AngleConvert);
2647 	return 1;
2648 }
2649 
Lua_Media_Get_Height(lua_State * L)2650 static int Lua_Media_Get_Height(lua_State* L)
2651 {
2652 	media_data* media = get_media_data(Lua_Media::Index(L, 1));
2653 	lua_pushnumber(L, static_cast<double>(media->height) / WORLD_ONE);
2654 	return 1;
2655 }
2656 
Lua_Media_Get_High(lua_State * L)2657 static int Lua_Media_Get_High(lua_State* L)
2658 {
2659 	media_data* media = get_media_data(Lua_Media::Index(L, 1));
2660 	lua_pushnumber(L, static_cast<double>(media->high) / WORLD_ONE);
2661 	return 1;
2662 }
2663 
Lua_Media_Get_Light(lua_State * L)2664 static int Lua_Media_Get_Light(lua_State* L)
2665 {
2666 	media_data* media = get_media_data(Lua_Media::Index(L, 1));
2667 	Lua_Light::Push(L, media->light_index);
2668 	return 1;
2669 }
2670 
Lua_Media_Get_Low(lua_State * L)2671 static int Lua_Media_Get_Low(lua_State* L)
2672 {
2673 	media_data* media = get_media_data(Lua_Media::Index(L, 1));
2674 	lua_pushnumber(L, static_cast<double>(media->low) / WORLD_ONE);
2675 	return 1;
2676 }
2677 
Lua_Media_Get_Speed(lua_State * L)2678 static int Lua_Media_Get_Speed(lua_State* L)
2679 {
2680 	media_data* media = get_media_data(Lua_Media::Index(L, 1));
2681 	lua_pushnumber(L, static_cast<double>(media->current_magnitude) / WORLD_ONE);
2682 	return 1;
2683 }
2684 
Lua_Media_Get_Type(lua_State * L)2685 static int Lua_Media_Get_Type(lua_State *L)
2686 {
2687 	media_data *media = get_media_data(Lua_Media::Index(L, 1));
2688 	Lua_MediaType::Push(L, media->type);
2689 	return 1;
2690 }
2691 
2692 const luaL_Reg Lua_Media_Get[] = {
2693 	{"direction", Lua_Media_Get_Direction},
2694 	{"height", Lua_Media_Get_Height},
2695 	{"high", Lua_Media_Get_High},
2696 	{"light", Lua_Media_Get_Light},
2697 	{"low", Lua_Media_Get_Low},
2698 	{"speed", Lua_Media_Get_Speed},
2699 	{"type", Lua_Media_Get_Type},
2700 	{0, 0}
2701 };
2702 
2703 extern void update_one_media(size_t, bool);
2704 
Lua_Media_Set_Direction(lua_State * L)2705 static int Lua_Media_Set_Direction(lua_State* L)
2706 {
2707 	if (!lua_isnumber(L, 2))
2708 		return luaL_error(L, "direction: incorrect argument type");
2709 
2710 	media_data* media = get_media_data(Lua_Media::Index(L, 1));
2711 	media->current_direction = static_cast<angle>(lua_tonumber(L, 2) / AngleConvert);
2712 	return 0;
2713 }
2714 
Lua_Media_Set_High(lua_State * L)2715 static int Lua_Media_Set_High(lua_State* L)
2716 {
2717 	if (!lua_isnumber(L, 2))
2718 		return luaL_error(L, "high: incorrect argument type");
2719 
2720 	int media_index = Lua_Media::Index(L, 1);
2721 	media_data* media = get_media_data(media_index);
2722 	media->high = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
2723 	update_one_media(media_index, true);
2724 	return 0;
2725 }
2726 
Lua_Media_Set_Light(lua_State * L)2727 static int Lua_Media_Set_Light(lua_State* L)
2728 {
2729 	int light_index;
2730 	if (lua_isnumber(L, 2))
2731 	{
2732 		light_index = static_cast<int>(lua_tonumber(L, 2));
2733 		if (!Lua_Light::Valid(light_index))
2734 			return luaL_error(L, "light: invalid light index");
2735 	}
2736 	else if (Lua_Light::Is(L, 2))
2737 	{
2738 		light_index = Lua_Light::Index(L, 2);
2739 	}
2740 	else
2741 	{
2742 		return luaL_error(L, "light: incorrect argument type");
2743 	}
2744 
2745 	int media_index = Lua_Media::Index(L, 1);
2746 	media_data* media = get_media_data(media_index);
2747 	media->light_index = light_index;
2748 	update_one_media(media_index, true);
2749 	return 0;
2750 }
2751 
Lua_Media_Set_Low(lua_State * L)2752 static int Lua_Media_Set_Low(lua_State* L)
2753 {
2754 	if (!lua_isnumber(L, 2))
2755 		return luaL_error(L, "high: incorrect argument type");
2756 
2757 	int media_index = Lua_Media::Index(L, 1);
2758 	media_data* media = get_media_data(media_index);
2759 	media->low = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
2760 	update_one_media(media_index, true);
2761 	return 0;
2762 }
2763 
Lua_Media_Set_Speed(lua_State * L)2764 static int Lua_Media_Set_Speed(lua_State* L)
2765 {
2766 	if (!lua_isnumber(L, 2))
2767 		return luaL_error(L, "speed: incorrect argument type");
2768 
2769 	media_data* media = get_media_data(Lua_Media::Index(L, 1));
2770 	media->current_magnitude = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
2771 	return 0;
2772 }
2773 
Lua_Media_Set_Type(lua_State * L)2774 static int Lua_Media_Set_Type(lua_State* L)
2775 {
2776 	int media_index = Lua_Media::Index(L, 1);
2777 	media_data* media = get_media_data(media_index);
2778 	media->type = Lua_MediaType::ToIndex(L, 2);
2779 	update_one_media(media_index, true);
2780 	return 0;
2781 }
2782 
2783 const luaL_Reg Lua_Media_Set[] = {
2784 	{"direction", Lua_Media_Set_Direction},
2785 	{"high", Lua_Media_Set_High},
2786 	{"light", Lua_Media_Set_Light},
2787 	{"low", Lua_Media_Set_Low},
2788 	{"speed", Lua_Media_Set_Speed},
2789 	{"type", Lua_Media_Set_Type},
2790 	{0, 0}
2791 };
2792 
Lua_Media_Valid(int16 index)2793 static bool Lua_Media_Valid(int16 index)
2794 {
2795 	return index >= 0 && index< MAXIMUM_MEDIAS_PER_MAP;
2796 }
2797 
2798 char Lua_Medias_Name[] = "Media";
Lua_Medias_Length()2799 static int16 Lua_Medias_Length() { return MediaList.size(); }
2800 
2801 char Lua_Annotation_Name[] = "annotation";
2802 typedef L_Class<Lua_Annotation_Name> Lua_Annotation;
2803 
Lua_Annotation_Get_Polygon(lua_State * L)2804 static int Lua_Annotation_Get_Polygon(lua_State *L)
2805 {
2806 	Lua_Polygon::Push(L, MapAnnotationList[Lua_Annotation::Index(L, 1)].polygon_index);
2807 	return 1;
2808 }
2809 
Lua_Annotation_Get_Text(lua_State * L)2810 static int Lua_Annotation_Get_Text(lua_State *L)
2811 {
2812 	lua_pushstring(L, MapAnnotationList[Lua_Annotation::Index(L, 1)].text);
2813 	return 1;
2814 }
2815 
Lua_Annotation_Get_X(lua_State * L)2816 static int Lua_Annotation_Get_X(lua_State *L)
2817 {
2818 	lua_pushnumber(L, (double) MapAnnotationList[Lua_Annotation::Index(L, 1)].location.x / WORLD_ONE);
2819 	return 1;
2820 }
2821 
Lua_Annotation_Get_Y(lua_State * L)2822 static int Lua_Annotation_Get_Y(lua_State *L)
2823 {
2824 	lua_pushnumber(L, (double) MapAnnotationList[Lua_Annotation::Index(L, 1)].location.y / WORLD_ONE);
2825 	return 1;
2826 }
2827 
2828 const luaL_Reg Lua_Annotation_Get[] = {
2829 	{"polygon", Lua_Annotation_Get_Polygon},
2830 	{"text", Lua_Annotation_Get_Text},
2831 	{"x", Lua_Annotation_Get_X},
2832 	{"y", Lua_Annotation_Get_Y},
2833 	{0, 0}
2834 };
2835 
Lua_Annotation_Set_Polygon(lua_State * L)2836 static int Lua_Annotation_Set_Polygon(lua_State *L)
2837 {
2838 	int polygon_index = NONE;
2839 	if (lua_isnil(L, 2))
2840 	{
2841 		polygon_index = NONE;
2842 	}
2843 	else
2844 	{
2845 		polygon_index = Lua_Polygon::Index(L, 2);
2846 	}
2847 
2848 	MapAnnotationList[Lua_Annotation::Index(L, 1)].polygon_index = polygon_index;
2849 	return 0;
2850 }
2851 
Lua_Annotation_Set_Text(lua_State * L)2852 static int Lua_Annotation_Set_Text(lua_State *L)
2853 {
2854 	if (!lua_isstring(L, 2))
2855 		return luaL_error(L, "text: incorrect argument type");
2856 
2857 	int annotation_index = Lua_Annotation::Index(L, 1);
2858 	strncpy(MapAnnotationList[annotation_index].text, lua_tostring(L, 2), MAXIMUM_ANNOTATION_TEXT_LENGTH);
2859 	MapAnnotationList[annotation_index].text[MAXIMUM_ANNOTATION_TEXT_LENGTH-1] = '\0';
2860 	return 0;
2861 }
2862 
Lua_Annotation_Set_X(lua_State * L)2863 static int Lua_Annotation_Set_X(lua_State *L)
2864 {
2865 	if (!lua_isnumber(L, 2))
2866 		return luaL_error(L, "x: incorrect argument type");
2867 
2868 	MapAnnotationList[Lua_Annotation::Index(L, 1)].location.x = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
2869 	return 0;
2870 }
2871 
Lua_Annotation_Set_Y(lua_State * L)2872 static int Lua_Annotation_Set_Y(lua_State *L)
2873 {
2874 	if (!lua_isnumber(L, 2))
2875 		return luaL_error(L, "y: incorrect argument type");
2876 
2877 	MapAnnotationList[Lua_Annotation::Index(L, 1)].location.y = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
2878 	return 0;
2879 }
2880 
2881 const luaL_Reg Lua_Annotation_Set[] = {
2882 	{"polygon", Lua_Annotation_Set_Polygon},
2883 	{"text", Lua_Annotation_Set_Text},
2884 	{"x", Lua_Annotation_Set_X},
2885 	{"y", Lua_Annotation_Set_Y},
2886 	{0, 0}
2887 };
2888 
Lua_Annotation_Valid(int16 index)2889 bool Lua_Annotation_Valid(int16 index)
2890 {
2891 	return index >= 0 && index < MapAnnotationList.size();
2892 }
2893 
2894 char Lua_Annotations_Name[] = "Annotations";
2895 typedef L_Container<Lua_Annotations_Name, Lua_Annotation> Lua_Annotations;
2896 
2897 // Annotations.new(polygon, text, [x, y])
Lua_Annotations_New(lua_State * L)2898 int Lua_Annotations_New(lua_State *L)
2899 {
2900 	if (dynamic_world->default_annotation_count == INT16_MAX)
2901 		return luaL_error(L, "new: annotation limit reached");
2902 
2903 	if (!lua_isstring(L, 2))
2904 		return luaL_error(L, "new: incorrect argument type");
2905 
2906 	map_annotation annotation;
2907 	annotation.type = 0;
2908 
2909 	if (lua_isnil(L, 1))
2910 	{
2911 		annotation.polygon_index = NONE;
2912 	}
2913 	else
2914 	{
2915 		annotation.polygon_index = Lua_Polygon::Index(L, 1);
2916 	}
2917 
2918 	int x = 0, y = 0;
2919 	if (annotation.polygon_index != NONE)
2920 	{
2921 		polygon_data *polygon = get_polygon_data(annotation.polygon_index);
2922 		x = polygon->center.x;
2923 		y = polygon->center.y;
2924 	}
2925 
2926 	annotation.location.x = luaL_optint(L, 3, x);
2927 	annotation.location.y = luaL_optint(L, 4, y);
2928 
2929 	strncpy(annotation.text, lua_tostring(L, 2), MAXIMUM_ANNOTATION_TEXT_LENGTH);
2930 	annotation.text[MAXIMUM_ANNOTATION_TEXT_LENGTH-1] = '\0';
2931 
2932 	MapAnnotationList.push_back(annotation);
2933 	dynamic_world->default_annotation_count++;
2934 	Lua_Annotation::Push(L, MapAnnotationList.size() - 1);
2935 	return 1;
2936 }
2937 
2938 const luaL_Reg Lua_Annotations_Methods[] = {
2939 	{"new", L_TableFunction<Lua_Annotations_New>},
2940 	{0, 0}
2941 };
2942 
Lua_Annotations_Length()2943 int16 Lua_Annotations_Length() {
2944 	return MapAnnotationList.size();
2945 }
2946 
2947 char Lua_Fog_Color_Name[] = "fog_color";
2948 typedef L_Class<Lua_Fog_Color_Name> Lua_Fog_Color;
2949 
Lua_Fog_Color_Get_R(lua_State * L)2950 static int Lua_Fog_Color_Get_R(lua_State *L)
2951 {
2952 	lua_pushnumber(L, (float) (OGL_GetFogData(Lua_Fog_Color::Index(L, 1))->Color.red) / 65535);
2953 	return 1;
2954 }
2955 
Lua_Fog_Color_Get_G(lua_State * L)2956 static int Lua_Fog_Color_Get_G(lua_State *L)
2957 {
2958 	lua_pushnumber(L, (float) (OGL_GetFogData(Lua_Fog_Color::Index(L, 1))->Color.green) / 65535);
2959 	return 1;
2960 }
2961 
Lua_Fog_Color_Get_B(lua_State * L)2962 static int Lua_Fog_Color_Get_B(lua_State *L)
2963 {
2964 	lua_pushnumber(L, (float) (OGL_GetFogData(Lua_Fog_Color::Index(L, 1))->Color.blue) / 65535);
2965 	return 1;
2966 }
2967 
Lua_Fog_Color_Set_R(lua_State * L)2968 static int Lua_Fog_Color_Set_R(lua_State *L)
2969 {
2970 	if (!lua_isnumber(L, 2))
2971 		luaL_error(L, "r: incorrect argument type");
2972 
2973 	float color = static_cast<float>(lua_tonumber(L, 2));
2974 	OGL_GetFogData(Lua_Fog_Color::Index(L, 1))->Color.red = PIN(int(65535 * color + 0.5), 0, 65535);
2975 	return 0;
2976 }
2977 
Lua_Fog_Color_Set_G(lua_State * L)2978 static int Lua_Fog_Color_Set_G(lua_State *L)
2979 {
2980 	if (!lua_isnumber(L, 2))
2981 		luaL_error(L, "g: incorrect argument type");
2982 
2983 	float color = static_cast<float>(lua_tonumber(L, 2));
2984 	OGL_GetFogData(Lua_Fog_Color::Index(L, 1))->Color.green = PIN(int(65535 * color + 0.5), 0, 65535);
2985 	return 0;
2986 }
2987 
Lua_Fog_Color_Set_B(lua_State * L)2988 static int Lua_Fog_Color_Set_B(lua_State *L)
2989 {
2990 	if (!lua_isnumber(L, 2))
2991 		luaL_error(L, "b: incorrect argument type");
2992 
2993 	float color = static_cast<float>(lua_tonumber(L, 2));
2994 	OGL_GetFogData(Lua_Fog_Color::Index(L, 1))->Color.blue = PIN(int(65535 * color + 0.5), 0, 65535);
2995 	return 0;
2996 }
2997 
2998 const luaL_Reg Lua_Fog_Color_Get[] = {
2999 	{"r", Lua_Fog_Color_Get_R},
3000 	{"g", Lua_Fog_Color_Get_G},
3001 	{"b", Lua_Fog_Color_Get_B},
3002 	{0, 0}
3003 };
3004 
3005 const luaL_Reg Lua_Fog_Color_Set[] = {
3006 	{"r", Lua_Fog_Color_Set_R},
3007 	{"g", Lua_Fog_Color_Set_G},
3008 	{"b", Lua_Fog_Color_Set_B},
3009 	{0, 0}
3010 };
3011 
3012 char Lua_Fog_Name[] = "fog";
3013 typedef L_Class<Lua_Fog_Name> Lua_Fog;
3014 
Lua_Fog_Get_Active(lua_State * L)3015 static int Lua_Fog_Get_Active(lua_State *L)
3016 {
3017 	lua_pushboolean(L, OGL_GetFogData(Lua_Fog::Index(L, 1))->IsPresent);
3018 	return 1;
3019 }
3020 
Lua_Fog_Get_Affects_Landscapes(lua_State * L)3021 static int Lua_Fog_Get_Affects_Landscapes(lua_State *L)
3022 {
3023 	lua_pushboolean(L, OGL_GetFogData(Lua_Fog::Index(L, 1))->AffectsLandscapes);
3024 	return 1;
3025 }
3026 
Lua_Fog_Get_Color(lua_State * L)3027 static int Lua_Fog_Get_Color(lua_State *L)
3028 {
3029 	Lua_Fog_Color::Push(L, Lua_Fog::Index(L, 1));
3030 	return 1;
3031 }
3032 
Lua_Fog_Get_Depth(lua_State * L)3033 static int Lua_Fog_Get_Depth(lua_State *L)
3034 {
3035 	lua_pushnumber(L, OGL_GetFogData(Lua_Fog::Index(L, 1))->Depth);
3036 	return 1;
3037 }
3038 
3039 const luaL_Reg Lua_Fog_Get[] = {
3040 	{"active", Lua_Fog_Get_Active},
3041 	{"affects_landscapes", Lua_Fog_Get_Affects_Landscapes},
3042 	{"color", Lua_Fog_Get_Color},
3043 	{"depth", Lua_Fog_Get_Depth},
3044 	{"present", Lua_Fog_Get_Active},
3045 	{0, 0}
3046 };
3047 
Lua_Fog_Set_Active(lua_State * L)3048 static int Lua_Fog_Set_Active(lua_State *L)
3049 {
3050 	if (!lua_isboolean(L, 2))
3051 		return luaL_error(L, "active: incorrect argument type");
3052 
3053 	OGL_GetFogData(Lua_Fog::Index(L, 1))->IsPresent = static_cast<bool>(lua_toboolean(L, 2));
3054 	return 0;
3055 }
3056 
Lua_Fog_Set_Affects_Landscapes(lua_State * L)3057 static int Lua_Fog_Set_Affects_Landscapes(lua_State *L)
3058 {
3059 	if (!lua_isboolean(L, 2))
3060 		return luaL_error(L, "affects_landscapes: incorrect argument type");
3061 
3062 	OGL_GetFogData(Lua_Fog::Index(L, 1))->AffectsLandscapes = static_cast<bool>(lua_toboolean(L, 2));
3063 	return 0;
3064 }
3065 
Lua_Fog_Set_Depth(lua_State * L)3066 static int Lua_Fog_Set_Depth(lua_State *L)
3067 {
3068 	if (!lua_isnumber(L, 2))
3069 		return luaL_error(L, "depth: incorrect argument type");
3070 
3071 	OGL_GetFogData(Lua_Fog::Index(L, 1))->Depth = static_cast<float>(lua_tonumber(L, 2));
3072 	return 0;
3073 }
3074 
3075 const luaL_Reg Lua_Fog_Set[] = {
3076 	{"active", Lua_Fog_Set_Active},
3077 	{"affects_landscapes", Lua_Fog_Set_Affects_Landscapes},
3078 	{"depth", Lua_Fog_Set_Depth},
3079 	{"present", Lua_Fog_Set_Active},
3080 	{0, 0}
3081 };
3082 
3083 
3084 char Lua_Level_Stash_Name[] = "LevelStash";
3085 typedef L_Class<Lua_Level_Stash_Name> Lua_Level_Stash;
3086 
3087 extern std::unordered_map<std::string, std::string> lua_stash;
3088 
Lua_Level_Stash_Get(lua_State * L)3089 static int Lua_Level_Stash_Get(lua_State* L)
3090 {
3091         if (!lua_isstring(L, 2))
3092                 return luaL_error(L, "stash: incorrect argument type");
3093 
3094         auto it = lua_stash.find(lua_tostring(L, 2));
3095         if (it != lua_stash.end())
3096         {
3097                 lua_pushlstring(L, it->second.data(), it->second.size());
3098         }
3099         else
3100         {
3101                 lua_pushnil(L);
3102         }
3103 
3104         return 1;
3105 }
3106 
Lua_Level_Stash_Set(lua_State * L)3107 static int Lua_Level_Stash_Set(lua_State* L)
3108 {
3109         if (!lua_isstring(L, 3) && !lua_isnil(L, 3))
3110                 return luaL_error(L, "stash: incorrect argument type");
3111 
3112         auto key = lua_tostring(L, 2);
3113         if (lua_isstring(L, 3))
3114         {
3115                 size_t len;
3116                 auto s = lua_tolstring(L, 3, &len);
3117                 lua_stash[key] = std::string{s, len};
3118         }
3119         else
3120         {
3121                 lua_stash.erase(key);
3122         }
3123 
3124         return 0;
3125 }
3126 
3127 const luaL_Reg Lua_Level_Stash_Metatable[] = {
3128         {"__index", Lua_Level_Stash_Get},
3129         {"__newindex", Lua_Level_Stash_Set},
3130         {0, 0}
3131 };
3132 
3133 char Lua_Level_Name[] = "Level";
3134 typedef L_Class<Lua_Level_Name> Lua_Level;
3135 
3136 char Lua_CompletionState_Name[] = "completion_state";
3137 typedef L_Enum<Lua_CompletionState_Name> Lua_CompletionState;
3138 
3139 char Lua_CompletionStates_Name[] = "CompletionStates";
3140 typedef L_EnumContainer<Lua_CompletionStates_Name, Lua_CompletionState> Lua_CompletionStates;
3141 
Lua_Level_Calculate_Completion_State(lua_State * L)3142 int Lua_Level_Calculate_Completion_State(lua_State *L)
3143 {
3144 	Lua_CompletionState::Push(L, calculate_level_completion_state());
3145 	return 1;
3146 }
3147 
Lua_Level_Get_Completed(lua_State * L)3148 int Lua_Level_Get_Completed(lua_State* L)
3149 {
3150 	lua_pushboolean(L, get_game_state() == _change_level);
3151 	return 1;
3152 }
3153 
3154 template<int16 flag>
Lua_Level_Get_Environment_Flag(lua_State * L)3155 static int Lua_Level_Get_Environment_Flag(lua_State *L)
3156 {
3157 	lua_pushboolean(L, static_world->environment_flags & flag);
3158 	return 1;
3159 }
3160 
3161 template<int16 flag>
Lua_Level_Get_Mission_Flag(lua_State * L)3162 static int Lua_Level_Get_Mission_Flag(lua_State *L)
3163 {
3164 	lua_pushboolean(L, static_world->mission_flags & flag);
3165 	return 1;
3166 }
3167 
Lua_Level_Get_Fog(lua_State * L)3168 static int Lua_Level_Get_Fog(lua_State *L)
3169 {
3170 	Lua_Fog::Push(L, OGL_Fog_AboveLiquid);
3171 	return 1;
3172 }
3173 
Lua_Level_Get_Name(lua_State * L)3174 static int Lua_Level_Get_Name(lua_State *L)
3175 {
3176 	lua_pushstring(L, static_world->level_name);
3177 	return 1;
3178 }
3179 
Lua_Level_Get_Index(lua_State * L)3180 static int Lua_Level_Get_Index(lua_State *L)
3181 {
3182 	lua_pushinteger(L, dynamic_world->current_level_number);
3183 	return 1;
3184 }
3185 
Lua_Level_Get_Map_Checksum(lua_State * L)3186 static int Lua_Level_Get_Map_Checksum(lua_State *L)
3187 {
3188 #if !defined(DISABLE_NETWORKING)
3189 	if (game_is_networked)
3190 		lua_pushinteger(L, ((game_info *) NetGetGameData())->parent_checksum);
3191 	else
3192 #endif
3193 		lua_pushinteger(L, get_current_map_checksum());
3194 	return 1;
3195 }
3196 
Lua_Level_Get_Stash(lua_State * L)3197 static int Lua_Level_Get_Stash(lua_State* L)
3198 {
3199         Lua_Level_Stash::Push(L, 0);
3200         return 1;
3201 }
3202 
Lua_Level_Get_Underwater_Fog(lua_State * L)3203 static int Lua_Level_Get_Underwater_Fog(lua_State *L)
3204 {
3205 	Lua_Fog::Push(L, OGL_Fog_BelowLiquid);
3206 	return 1;
3207 }
3208 
3209 const luaL_Reg Lua_Level_Get[] = {
3210 	{"calculate_completion_state", L_TableFunction<Lua_Level_Calculate_Completion_State>},
3211 	{"completed", Lua_Level_Get_Completed},
3212 	{"extermination", Lua_Level_Get_Mission_Flag<_mission_extermination>},
3213 	{"exploration", Lua_Level_Get_Mission_Flag<_mission_exploration>},
3214 	{"fog", Lua_Level_Get_Fog},
3215 	{"low_gravity", Lua_Level_Get_Environment_Flag<_environment_low_gravity>},
3216 	{"magnetic", Lua_Level_Get_Environment_Flag<_environment_magnetic>},
3217 	{"name", Lua_Level_Get_Name},
3218 	{"index", Lua_Level_Get_Index},
3219 	{"map_checksum", Lua_Level_Get_Map_Checksum},
3220 	{"rebellion", Lua_Level_Get_Environment_Flag<_environment_rebellion>},
3221 	{"retrieval", Lua_Level_Get_Mission_Flag<_mission_retrieval>},
3222 	{"repair", Lua_Level_Get_Mission_Flag<_mission_repair>},
3223 	{"rescue", Lua_Level_Get_Mission_Flag<_mission_rescue>},
3224         {"stash", Lua_Level_Get_Stash},
3225 	{"underwater_fog", Lua_Level_Get_Underwater_Fog},
3226 	{"vacuum", Lua_Level_Get_Environment_Flag<_environment_vacuum>},
3227 	{0, 0}
3228 };
3229 
3230 char Lua_TransferMode_Name[] = "transfer_mode";
3231 char Lua_TransferModes_Name[] = "TransferModes";
3232 
3233 static void compatibility(lua_State *L);
3234 #define NUMBER_OF_CONTROL_PANEL_DEFINITIONS 54
3235 
3236 extern bool collection_loaded(short);
3237 
Lua_Map_register(lua_State * L)3238 int Lua_Map_register(lua_State *L)
3239 {
3240 	Lua_AmbientSound::Register(L, 0, 0, 0, Lua_AmbientSound_Mnemonics);
3241 	Lua_AmbientSound::Valid = Lua_AmbientSound::ValidRange(NUMBER_OF_AMBIENT_SOUND_DEFINITIONS);
3242 	Lua_AmbientSounds::Register(L);
3243 	Lua_AmbientSounds::Length = Lua_AmbientSounds::ConstantLength(NUMBER_OF_AMBIENT_SOUND_DEFINITIONS);
3244 
3245 	Lua_Collection::Register(L, Lua_Collection_Get, 0, 0, Lua_Collection_Mnemonics);
3246 	Lua_Collection::Valid = collection_loaded;
3247 	Lua_Collections::Register(L);
3248 	Lua_Collections::Length = Lua_Collections::ConstantLength(MAXIMUM_COLLECTIONS);
3249 
3250 	Lua_CompletionState::Register(L, 0, 0, 0, Lua_CompletionState_Mnemonics);
3251 	Lua_CompletionState::Valid = Lua_CompletionState::ValidRange(static_cast<int16>(_level_failed) + 1);
3252 	Lua_CompletionStates::Register(L);
3253 	Lua_CompletionStates::Length = Lua_CompletionStates::ConstantLength(static_cast<int16>(_level_failed) + 1);
3254 
3255 	Lua_ControlPanelClass::Register(L, 0, 0, 0, Lua_ControlPanelClass_Mnemonics);
3256 	Lua_ControlPanelClass::Valid = Lua_ControlPanelClass::ValidRange(NUMBER_OF_CONTROL_PANELS);
3257 
3258 	Lua_ControlPanelClasses::Register(L);
3259 	Lua_ControlPanelClasses::Length = Lua_ControlPanelClasses::ConstantLength(NUMBER_OF_CONTROL_PANELS);
3260 
3261 	Lua_ControlPanelType::Register(L, Lua_ControlPanelType_Get);
3262 	Lua_ControlPanelType::Valid = Lua_ControlPanelType::ValidRange(NUMBER_OF_CONTROL_PANEL_DEFINITIONS);
3263 
3264 	Lua_ControlPanelTypes::Register(L);
3265 	Lua_ControlPanelTypes::Length = Lua_ControlPanelTypes::ConstantLength(NUMBER_OF_CONTROL_PANEL_DEFINITIONS);
3266 
3267 	Lua_DamageType::Register(L, 0, 0, 0, Lua_DamageType_Mnemonics);
3268 	Lua_DamageType::Valid = Lua_DamageType::ValidRange(NUMBER_OF_DAMAGE_TYPES);
3269 	Lua_DamageTypes::Register(L);
3270 	Lua_DamageTypes::Length = Lua_DamageTypes::ConstantLength(NUMBER_OF_DAMAGE_TYPES);
3271 
3272 	Lua_Endpoint::Register(L, Lua_Endpoint_Get);
3273 	Lua_Endpoint::Valid = Lua_Endpoint_Valid;
3274 
3275 	Lua_Endpoints::Register(L);
3276 	// CodeWarrior doesn't let me do this:
3277 //	Lua_Endpoints::Length = boost::bind(&std::vector<endpoint_data>::size, &EndpointList);
3278 	Lua_Endpoints::Length = Lua_Endpoints_Length;
3279 
3280 	Lua_Line_Endpoints::Register(L, 0, 0, Lua_Line_Endpoints_Metatable);
3281 
3282 	Lua_Line::Register(L, Lua_Line_Get, Lua_Line_Set);
3283 	Lua_Line::Valid = Lua_Line_Valid;
3284 
3285 	Lua_Lines::Register(L);
3286 	Lua_Lines::Length = Lua_Lines_Length;
3287 
3288 	Lua_Platform::Register(L, Lua_Platform_Get, Lua_Platform_Set);
3289 	Lua_Platform::Valid = Lua_Platform_Valid;
3290 
3291 	Lua_Platforms::Register(L);
3292 	Lua_Platforms::Length = Lua_Platforms_Length;
3293 
3294 	Lua_PlatformType::Register(L, 0, 0, 0, Lua_PlatformType_Mnemonics);
3295 	Lua_PlatformType::Valid = Lua_PlatformType::ValidRange(NUMBER_OF_PLATFORM_TYPES);
3296 
3297 	Lua_PlatformTypes::Register(L);
3298 	Lua_PlatformTypes::Length = Lua_PlatformTypes::ConstantLength(NUMBER_OF_PLATFORM_TYPES);
3299 
3300 	Lua_Polygon_Floor::Register(L, Lua_Polygon_Floor_Get, Lua_Polygon_Floor_Set);
3301 	Lua_Polygon_Floor::Valid = Lua_Polygon_Valid;
3302 
3303 	Lua_Polygon_Ceiling::Register(L, Lua_Polygon_Ceiling_Get, Lua_Polygon_Ceiling_Set);
3304 	Lua_Polygon_Ceiling::Valid = Lua_Polygon_Valid;
3305 
3306 	Lua_PolygonType::Register(L, 0, 0, 0, Lua_PolygonType_Mnemonics);
3307 	Lua_PolygonType::Valid = Lua_PolygonType::ValidRange(static_cast<int16>(_polygon_is_superglue) + 1);
3308 
3309 	Lua_PolygonTypes::Register(L);
3310 	Lua_PolygonTypes::Length = Lua_PolygonTypes::ConstantLength(static_cast<int16>(_polygon_is_superglue) + 1);
3311 
3312 	Lua_Adjacent_Polygons::Register(L, 0, 0, Lua_Adjacent_Polygons_Metatable);
3313 	Lua_Polygon_Endpoints::Register(L, 0, 0, Lua_Polygon_Endpoints_Metatable);
3314 	Lua_Polygon_Lines::Register(L, 0, 0, Lua_Polygon_Lines_Metatable);
3315 	Lua_Polygon_Sides::Register(L, 0, 0, Lua_Polygon_Sides_Metatable);
3316 
3317 	Lua_Polygon::Register(L, Lua_Polygon_Get, Lua_Polygon_Set);
3318 	Lua_Polygon::Valid = Lua_Polygon_Valid;
3319 
3320 	Lua_Polygons::Register(L);
3321 	Lua_Polygons::Length = Lua_Polygons_Length;
3322 
3323 	Lua_Side_ControlPanel::Register(L, Lua_Side_ControlPanel_Get, Lua_Side_ControlPanel_Set);
3324 
3325 	Lua_Primary_Side::Register(L, Lua_Primary_Side_Get, Lua_Primary_Side_Set);
3326 	Lua_Secondary_Side::Register(L, Lua_Secondary_Side_Get, Lua_Secondary_Side_Set);
3327 	Lua_Transparent_Side::Register(L, Lua_Transparent_Side_Get, Lua_Transparent_Side_Set);
3328 
3329 	Lua_Side::Register(L, Lua_Side_Get, Lua_Side_Set);
3330 	Lua_Side::Valid = Lua_Side_Valid;
3331 
3332 	Lua_Sides::Register(L, Lua_Sides_Methods);
3333 	Lua_Sides::Length = Lua_Sides_Length;
3334 
3335 	Lua_SideType::Register(L, 0, 0, 0, Lua_SideType_Mnemonics);
3336 	Lua_SideType::Valid = Lua_SideType::ValidRange(static_cast<int16>(_split_side) + 1);
3337 	Lua_SideTypes::Register(L);
3338 	Lua_SideTypes::Length = Lua_SideTypes::ConstantLength(static_cast<int16>(_split_side) + 1);
3339 
3340 	Lua_Light_State::Register(L, Lua_Light_State_Get, Lua_Light_State_Set);
3341 	Lua_Light_State::Valid = Lua_Light_State::ValidRange(static_cast<int16>(_light_secondary_inactive) + 1);
3342 
3343 	Lua_Light_States::Register(L, 0, 0, Lua_Light_States_Metatable);
3344 	Lua_Light_States::Valid = Lua_Light_Valid;
3345 
3346 	Lua_LightPreset::Register(L, 0, 0, 0, Lua_LightPreset_Mnemonics);
3347 	Lua_LightPreset::Valid = Lua_LightPreset::ValidRange(NUMBER_OF_LIGHT_TYPES);
3348 
3349 	Lua_LightPresets::Register(L);
3350 	Lua_LightPresets::Length = Lua_LightPresets::ConstantLength(NUMBER_OF_LIGHT_TYPES);
3351 
3352 	Lua_LightFunction::Register(L, 0, 0, 0, Lua_LightFunction_Mnenonics);
3353 	Lua_LightFunction::Valid = Lua_LightFunction::ValidRange(NUMBER_OF_LIGHTING_FUNCTIONS);
3354 
3355 	Lua_LightFunctions::Register(L);
3356 	Lua_LightFunctions::Length = Lua_LightFunctions::ConstantLength(NUMBER_OF_LIGHTING_FUNCTIONS);
3357 
3358 	Lua_LightState::Register(L, 0, 0, 0, Lua_LightState_Mnemonics);
3359 	Lua_LightState::Valid = Lua_LightState::ValidRange(static_cast<int16>(_light_secondary_inactive) + 1);
3360 
3361 	Lua_LightStates::Register(L);
3362 	Lua_LightStates::Length = Lua_LightStates::ConstantLength(static_cast<int16>(_light_secondary_inactive) + 1);
3363 
3364 	Lua_Light::Register(L, Lua_Light_Get, Lua_Light_Set);
3365 	Lua_Light::Valid = Lua_Light_Valid;
3366 
3367 	Lua_Lights::Register(L, Lua_Lights_Methods);
3368 	Lua_Lights::Length = Lua_Lights_Length;
3369 
3370 	Lua_Tag::Register(L, Lua_Tag_Get, Lua_Tag_Set);
3371 	Lua_Tag::Valid = Lua_Tag_Valid;
3372 
3373 	Lua_Tags::Register(L);
3374 	Lua_Tags::Length = Lua_Tags::ConstantLength(INT16_MAX);
3375 
3376 	Lua_Terminal::Register(L);
3377 	Lua_Terminal::Valid = Lua_Terminal_Valid;
3378 
3379 	Lua_Terminals::Register(L);
3380 	Lua_Terminals::Length = Lua_Terminals_Length;
3381 
3382 	Lua_TransferMode::Register(L, 0, 0, 0, Lua_TransferMode_Mnemonics);
3383 	Lua_TransferMode::Valid = Lua_TransferMode::ValidRange(NUMBER_OF_TRANSFER_MODES);
3384 
3385 	Lua_TransferModes::Register(L);
3386 	Lua_TransferModes::Length = Lua_TransferModes::ConstantLength(NUMBER_OF_TRANSFER_MODES);
3387 
3388 	Lua_MediaType::Register(L, 0, 0, 0, Lua_MediaType_Mnemonics);
3389 	Lua_MediaType::Valid = Lua_MediaType::ValidRange(NUMBER_OF_MEDIA_TYPES);
3390 
3391 	Lua_MediaTypes::Register(L);
3392 	Lua_MediaTypes::Length = Lua_MediaTypes::ConstantLength(NUMBER_OF_MEDIA_TYPES);
3393 
3394 	Lua_Media::Register(L, Lua_Media_Get, Lua_Media_Set);
3395 	Lua_Media::Valid = Lua_Media_Valid;
3396 
3397 	Lua_Medias::Register(L);
3398 	Lua_Medias::Length = Lua_Medias_Length;
3399 
3400         Lua_Level_Stash::Register(L, 0, 0, Lua_Level_Stash_Metatable);
3401 
3402 	Lua_Level::Register(L, Lua_Level_Get);
3403 
3404 	Lua_Annotation::Register(L, Lua_Annotation_Get, Lua_Annotation_Set);
3405 	Lua_Annotation::Valid = Lua_Annotation_Valid;
3406 
3407 	Lua_Annotations::Register(L, Lua_Annotations_Methods);
3408 	Lua_Annotations::Length = Lua_Annotations_Length;
3409 
3410 	Lua_Fog::Register(L, Lua_Fog_Get, Lua_Fog_Set);
3411 
3412 	Lua_Fog_Color::Register(L, Lua_Fog_Color_Get, Lua_Fog_Color_Set);
3413 
3414 	// register one Level userdatum globally
3415 	Lua_Level::Push(L, 0);
3416 	lua_setglobal(L, Lua_Level_Name);
3417 
3418 	compatibility(L);
3419 	return 0;
3420 }
3421 
3422 static const char* compatibility_script = ""
3423 	"function annotations() local i = 0 local n = # Annotations return function() if i < n then a = Annotations[i] i = i + 1 if a.polygon then p = a.polygon.index else p = -1 end return a.text, p, a.x, a.y else return nil end end end\n"
3424 	"function get_all_fog_attributes() local attributes = { OGL_Fog_AboveLiquid = { Depth = Level.fog.depth, Color = { red = Level.fog.color.r, blue = Level.fog.color.b, green = Level.fog.color.g }, IsPresent = Level.fog.present, AffectsLandscapes = Level.fog.affects_landscapes }, OGL_Fog_BelowLiquid = { Depth = Level.underwater_fog.depth, Color = { red = Level.underwater_fog.color.r, green = Level.underwater_fog.color.g, blue = Level.underwater_fog.color.b, }, IsPresent = Level.underwater_fog.present, AffectsLandscapes = Level.underwater_fog.affects_landscapes } } return attributes end\n"
3425 	"function get_fog_affects_landscapes() return Level.fog.affects_landscapes end\n"
3426 	"function get_fog_color() return Level.fog.color.r, Level.fog.color.g, Level.fog.color.b end\n"
3427 	"function get_fog_depth() return Level.fog.depth end\n"
3428 	"function get_fog_present() return Level.fog.active end\n"
3429 	"function get_level_name() return Level.name end\n"
3430 	"function get_light_state(light) return Lights[light].active end\n"
3431 	"function get_map_environment() return Level.vacuum, Level.magnetic, Level.rebellion, Level.low_gravity end\n"
3432 	"function get_platform_ceiling_height(polygon) if Polygons[polygon].platform then return Polygons[polygon].platform.ceiling_height end end\n"
3433 	"function get_platform_floor_height(polygon) if Polygons[polygon].platform then return Polygons[polygon].platform.floor_height end end\n"
3434 	"function get_platform_index(polygon) if Polygons[polygon].platform then return Polygons[polygon].platform.index else return -1 end end\n"
3435 	"function get_polygon_media(polygon) if Polygons[polygon].media then return Polygons[polygon].media.index else return -1 end end\n"
3436 	"function get_platform_monster_control(polygon) if Polygons[polygon].platform then return Polygons[polygon].platform.monster_controllable end end\n"
3437 	"function get_platform_movement(polygon) if Polygons[polygon].platform then return Polygons[polygon].platform.extending end end\n"
3438 	"function get_platform_player_control(polygon) if Polygons[polygon].platform then return Polygons[polygon].platform.player_controllable end end\n"
3439 	"function get_platform_speed(polygon) if Polygons[polygon].platform then return Polygons[polygon].platform.speed * 1024 end end\n"
3440 	"function get_platform_state(polygon) if Polygons[polygon].platform then return Polygons[polygon].platform.active end end\n"
3441 	"function get_polygon_ceiling_height(polygon) return Polygons[polygon].ceiling.height end\n"
3442 	"function get_polygon_center(polygon) return Polygons[polygon].x * 1024, Polygons[polygon].y * 1024 end\n"
3443 	"function get_polygon_floor_height(polygon) return Polygons[polygon].floor.height end\n"
3444 	"function get_polygon_target(polygon) return Polygons[polygon].permutation end\n"
3445 	"function get_polygon_type(polygon) return Polygons[polygon].type.index end\n"
3446 	"function get_tag_state(tag) return Tags[tag].active end\n"
3447 	"function get_terminal_text_number(poly, line) if Lines[line].ccw_polygon == Polygons[poly] then s = Lines[line].ccw_side elseif Lines[line].cw_polygon == Polygons[poly] then s = Lines[line].cw_side else return line end if s.control_panel and s.control_panel.type.class == 8 then return s.control_panel.permutation else return line end end\n"
3448 	"function get_underwater_fog_affects_landscapes() return Level.underwater_fog.affects_landscapes end\n"
3449 	"function get_underwater_fog_color() return Level.underwater_fog.color.r, Level.underwater_fog.color.g, Level.underwater_fog.color.b end\n"
3450 	"function get_underwater_fog_depth() return Level.underwater_fog.depth end\n"
3451 	"function get_underwater_fog_present() return Level.underwater_fog.active end\n"
3452 
3453 	"function number_of_polygons() return # Polygons end\n"
3454 	"function select_monster(type, poly) for m in Polygons[poly]:monsters() do if m.type == type and m.visible and (m.action < 6 or m.action > 9) then return m.index end end return nil end\n"
3455 	"function set_all_fog_attributes(t) Level.fog.depth = t.OGL_Fog_AboveLiquid.Depth Level.fog.present = t.OGL_Fog_AboveLiquid.IsPresent Level.fog.affects_landscapes = t.OGL_Fog_AboveLiquid.AffectsLandscapes Level.fog.color.r = t.OGL_Fog_AboveLiquid.Color.red Level.fog.color.g = t.OGL_Fog_AboveLiquid.Color.green Level.fog.color.b = t.OGL_Fog_AboveLiquid.Color.blue Level.underwater_fog.depth = t.OGL_Fog_BelowLiquid.Depth Level.underwater_fog.present = t.OGL_Fog_BelowLiquid.IsPresent Level.underwater_fog.affects_landscapes = t.OGL_Fog_BelowLiquid.AffectsLandscapes Level.underwater_fog.color.r = t.OGL_Fog_BelowLiquid.Color.red Level.underwater_fog.color.g = t.OGL_Fog_BelowLiquid.Color.green Level.underwater_fog.color.b = t.OGL_Fog_BelowLiquid.Color.blue end\n"
3456 	"function set_fog_affects_landscapes(affects_landscapes) Level.fog.affects_landscapes = affects_landscapes end\n"
3457 	"function set_fog_color(r, g, b) Level.fog.color.r = r Level.fog.color.g = g Level.fog.color.b = b end\n"
3458 	"function set_fog_depth(depth) Level.fog.depth = depth end\n"
3459 	"function set_fog_present(present) Level.fog.active = present end\n"
3460 	"function set_light_state(light, state) Lights[light].active = state end\n"
3461 	"function set_platform_ceiling_height(polygon, height) if Polygons[polygon].platform then Polygons[polygon].platform.ceiling_height = height end end\n"
3462 	"function set_platform_floor_height(polygon, height) if Polygons[polygon].platform then Polygons[polygon].platform.floor_height = height end end\n"
3463 	"function set_platform_monster_control(polygon, control) if Polygons[polygon].platform then Polygons[polygon].platform.monster_controllable = control end end\n"
3464 	"function set_platform_movement(polygon, movement) if Polygons[polygon].platform then Polygons[polygon].platform.extending = movement end end\n"
3465 	"function set_platform_player_control(polygon, control) if Polygons[polygon].platform then Polygons[polygon].platform.player_controllable = control end end\n"
3466 	"function set_platform_speed(polygon, speed) if Polygons[polygon].platform then Polygons[polygon].platform.speed = speed / 1024 end end\n"
3467 	"function set_platform_state(polygon, state) if Polygons[polygon].platform then Polygons[polygon].platform.active = state end end\n"
3468 	"function set_polygon_ceiling_height(polygon, height) Polygons[polygon].ceiling.height = height end\n"
3469 	"function set_polygon_floor_height(polygon, height) Polygons[polygon].floor.height = height end\n"
3470 	"function set_polygon_media(polygon, media) if media == -1 then Polygons[polygon].media = nil else Polygons[polygon].media = media end end\n"
3471 	"function set_polygon_target(polygon, target) Polygons[polygon].permutation = target end\n"
3472 	"function set_polygon_type(polygon, type) Polygons[polygon].type = type end\n"
3473 	"function set_tag_state(tag, state) Tags[tag].active = state end\n"
3474 	"function set_terminal_text_number(poly, line, id) if Lines[line].ccw_polygon == Polygons[poly] then s = Lines[line].ccw_side elseif Lines[line].cw_polygon == Polygons[poly] then s = Lines[line].cw_side else return end if s.control_panel and s.control_panel.type.class == 8 then s.control_panel.permutation = id end end\n"
3475 	"function set_underwater_fog_affects_landscapes(affects_landscapes) Level.underwater_fog.affects_landscapes = affects_landscapes end\n"
3476 	"function set_underwater_fog_color(r, g, b) Level.underwater_fog.color.r = r Level.underwater_fog.color.g = g Level.underwater_fog.color.b = b end\n"
3477 	"function set_underwater_fog_depth(depth) Level.underwater_fog.depth = depth end\n"
3478 	"function set_underwater_fog_present(present) Level.underwater_fog.active = present end\n"
3479 	;
3480 
compatibility(lua_State * L)3481 static void compatibility(lua_State *L)
3482 {
3483 	luaL_loadbuffer(L, compatibility_script, strlen(compatibility_script), "map_compatibility");
3484 	lua_pcall(L, 0, 0, 0);
3485 }
3486 
3487 #endif
3488 
3489