1 /*
2 LUA_MONSTERS.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 the Lua monster classes
21 */
22 
23 #include "lua_monsters.h"
24 #include "lua_map.h"
25 #include "lua_objects.h"
26 #include "lua_player.h"
27 #include "lua_templates.h"
28 
29 #include "flood_map.h"
30 #include "monsters.h"
31 #include "player.h"
32 
33 #include <boost/bind.hpp>
34 
35 #define DONT_REPEAT_DEFINITIONS
36 #include "monster_definitions.h"
37 
38 #ifdef HAVE_LUA
39 
40 const float AngleConvert = 360/float(FULL_CIRCLE);
41 
powerOfTwo(int32 x)42 static inline bool powerOfTwo(int32 x)
43 {
44 	return !((x-1) & x);
45 }
46 
47 char Lua_MonsterClass_Name[] = "monster_class";
48 typedef L_Enum<Lua_MonsterClass_Name, int32> Lua_MonsterClass;
49 
Lua_MonsterClass_Valid(int32 index)50 bool Lua_MonsterClass_Valid(int32 index)
51 {
52 	return index >= 1 && index <= _class_yeti && powerOfTwo(index);
53 }
54 
55 char Lua_MonsterClasses_Name[] = "MonsterClasses";
56 typedef L_EnumContainer<Lua_MonsterClasses_Name, Lua_MonsterClass> Lua_MonsterClasses;
57 
58 template<>
_iterator(lua_State * L)59 int L_Container<Lua_MonsterClasses_Name, Lua_MonsterClass>::_iterator(lua_State *L)
60 {
61 	int32 index = static_cast<int32>(lua_tonumber(L, lua_upvalueindex(1)));
62 	while (index < Length())
63 	{
64 		if (Lua_MonsterClass::Valid(1 << index))
65 		{
66 			Lua_MonsterClass::Push(L, 1 << index);
67 			lua_pushnumber(L, ++index);
68 			lua_replace(L, lua_upvalueindex(1));
69 			return 1;
70 		}
71 		else
72 		{
73 			++index;
74 		}
75 	}
76 
77 	lua_pushnil(L);
78 	return 1;
79 }
80 
81 extern object_frequency_definition* monster_placement_info;
82 
83 char Lua_MonsterType_Enemies_Name[] = "monster_type_enemies";
84 typedef L_Class<Lua_MonsterType_Enemies_Name> Lua_MonsterType_Enemies;
85 
Lua_MonsterType_Enemies_Get(lua_State * L)86 static int Lua_MonsterType_Enemies_Get(lua_State *L)
87 {
88 	int monster_type = Lua_MonsterType_Enemies::Index(L, 1);
89 	int enemy_class = Lua_MonsterClass::ToIndex(L, 2);
90 
91 	monster_definition *definition = get_monster_definition_external(monster_type);
92 	lua_pushboolean(L, definition->enemies & enemy_class);
93 	return 1;
94 }
95 
Lua_MonsterType_Enemies_Set(lua_State * L)96 static int Lua_MonsterType_Enemies_Set(lua_State *L)
97 {
98 	if (!lua_isboolean(L, 3))
99 		return luaL_error(L, "enemies: incorrect argument type");
100 
101 	int monster_type = Lua_MonsterType_Enemies::Index(L, 1);
102 	int enemy_class = Lua_MonsterClass::ToIndex(L, 2);
103 	bool enemy = lua_toboolean(L, 3);
104 	monster_definition *definition = get_monster_definition_external(monster_type);
105 	if (enemy)
106 	{
107 		definition->enemies = definition->enemies | enemy_class;
108 	}
109 	else
110 	{
111 		definition->enemies = definition->enemies & ~(enemy_class);
112 	}
113 
114 	return 0;
115 }
116 
117 const luaL_Reg Lua_MonsterType_Enemies_Metatable[] = {
118 	{"__index", Lua_MonsterType_Enemies_Get},
119 	{"__newindex", Lua_MonsterType_Enemies_Set},
120 	{0, 0}
121 };
122 
123 char Lua_MonsterType_Friends_Name[] = "monster_type_friends";
124 typedef L_Class<Lua_MonsterType_Friends_Name> Lua_MonsterType_Friends;
125 
Lua_MonsterType_Friends_Get(lua_State * L)126 static int Lua_MonsterType_Friends_Get(lua_State *L)
127 {
128 	int monster_type = Lua_MonsterType_Friends::Index(L, 1);
129 	int friend_class = Lua_MonsterClass::ToIndex(L, 2);
130 
131 	monster_definition *definition = get_monster_definition_external(monster_type);
132 	lua_pushboolean(L, definition->friends & friend_class);
133 	return 1;
134 }
135 
Lua_MonsterType_Friends_Set(lua_State * L)136 static int Lua_MonsterType_Friends_Set(lua_State *L)
137 {
138 	if (!lua_isboolean(L, 3))
139 		return luaL_error(L, "enemies: incorrect argument type");
140 
141 	int monster_type = Lua_MonsterType_Friends::Index(L, 1);
142 	int friend_class = Lua_MonsterClass::ToIndex(L, 2);
143 	bool friendly = lua_toboolean(L, 3);
144 	monster_definition *definition = get_monster_definition_external(monster_type);
145 	if (friendly)
146 	{
147 		definition->friends = definition->friends | friend_class;
148 	}
149 	else
150 	{
151 		definition->friends = definition->friends & ~(friend_class);
152 	}
153 
154 	return 0;
155 }
156 
157 const luaL_Reg Lua_MonsterType_Friends_Metatable[] = {
158 	{"__index", Lua_MonsterType_Friends_Get},
159 	{"__newindex", Lua_MonsterType_Friends_Set},
160 	{0, 0}
161 };
162 
163 char Lua_MonsterType_Immunities_Name[] = "monster_type_immunities";
164 typedef L_Class<Lua_MonsterType_Immunities_Name> Lua_MonsterType_Immunities;
165 
Lua_MonsterType_Immunities_Get(lua_State * L)166 static int Lua_MonsterType_Immunities_Get(lua_State *L)
167 {
168 	int monster_type = Lua_MonsterType_Immunities::Index(L, 1);
169 	int damage_type = Lua_DamageType::ToIndex(L, 2);
170 
171 	monster_definition *definition = get_monster_definition_external(monster_type);
172 	lua_pushboolean(L, definition->immunities & (1 << damage_type));
173 	return 1;
174 }
175 
Lua_MonsterType_Immunities_Set(lua_State * L)176 static int Lua_MonsterType_Immunities_Set(lua_State *L)
177 {
178 	if (!lua_isboolean(L, 3))
179 		luaL_error(L, "immunities: incorrect argument type");
180 
181 	int monster_type = Lua_MonsterType_Immunities::Index(L, 1);
182 	int damage_type = Lua_DamageType::ToIndex(L, 2);
183 	bool immune = lua_toboolean(L, 3);
184 
185 	monster_definition *definition = get_monster_definition_external(monster_type);
186 	if (immune)
187 	{
188 		definition->immunities |= (1 << damage_type);
189 	}
190 	else
191 	{
192 		definition->immunities &= ~(1 << damage_type);
193 	}
194 
195 	return 0;
196 }
197 
198 const luaL_Reg Lua_MonsterType_Immunities_Metatable[] = {
199 	{"__index", Lua_MonsterType_Immunities_Get},
200 	{"__newindex", Lua_MonsterType_Immunities_Set},
201 	{0, 0}
202 };
203 
204 char Lua_MonsterType_Weaknesses_Name[] = "monster_type_weaknesses";
205 typedef L_Class<Lua_MonsterType_Weaknesses_Name> Lua_MonsterType_Weaknesses;
206 
Lua_MonsterType_Weaknesses_Get(lua_State * L)207 int Lua_MonsterType_Weaknesses_Get(lua_State *L)
208 {
209 	int monster_type = Lua_MonsterType_Weaknesses::Index(L, 1);
210 	int damage_type = Lua_DamageType::ToIndex(L, 2);
211 
212 	monster_definition *definition = get_monster_definition_external(monster_type);
213 	lua_pushboolean(L, definition->weaknesses & (1 << damage_type));
214 	return 1;
215 }
216 
Lua_MonsterType_Weaknesses_Set(lua_State * L)217 int Lua_MonsterType_Weaknesses_Set(lua_State *L)
218 {
219 	if (!lua_isboolean(L, 3))
220 		luaL_error(L, "immunities: incorrect argument type");
221 
222 	int monster_type = Lua_MonsterType_Weaknesses::Index(L, 1);
223 	int damage_type = Lua_DamageType::ToIndex(L, 2);
224 	bool weakness = lua_toboolean(L, 3);
225 
226 	monster_definition *definition = get_monster_definition_external(monster_type);
227 	if (weakness)
228 	{
229 		definition->weaknesses |= (1 << damage_type);
230 	}
231 	else
232 	{
233 		definition->weaknesses &= ~(1 << damage_type);
234 	}
235 
236 	return 0;
237 }
238 
239 const luaL_Reg Lua_MonsterType_Weaknesses_Metatable[] = {
240 	{"__index", Lua_MonsterType_Weaknesses_Get},
241 	{"__newindex", Lua_MonsterType_Weaknesses_Set},
242 	{0, 0}
243 };
244 
245 char Lua_MonsterType_Name[] = "monster_type";
246 
Lua_MonsterType_Valid(int16 index)247 static bool Lua_MonsterType_Valid(int16 index)
248 {
249 	return index >= 0 && index < NUMBER_OF_MONSTER_TYPES;
250 }
251 
252 
Lua_MonsterType_Get_Class(lua_State * L)253 static int Lua_MonsterType_Get_Class(lua_State *L) {
254 	monster_definition *definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
255 	Lua_MonsterClass::Push(L, definition->_class);
256 	return 1;
257 }
258 
Lua_MonsterType_Get_Enemies(lua_State * L)259 static int Lua_MonsterType_Get_Enemies(lua_State *L) {
260 	Lua_MonsterType_Enemies::Push(L, Lua_MonsterType::Index(L, 1));
261 	return 1;
262 }
263 
264 template<uint32 flag>
Lua_MonsterType_Get_Flag(lua_State * L)265 static int Lua_MonsterType_Get_Flag(lua_State* L)
266 {
267 	monster_definition* definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
268 	lua_pushboolean(L, definition->flags & flag);
269 	return 1;
270 }
271 
272 
Lua_MonsterType_Get_Height(lua_State * L)273 static int Lua_MonsterType_Get_Height(lua_State *L) {
274 	monster_definition *definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
275 	lua_pushnumber(L, (double) definition->height / WORLD_ONE);
276 	return 1;
277 }
278 
Lua_MonsterType_Get_Friends(lua_State * L)279 static int Lua_MonsterType_Get_Friends(lua_State *L) {
280 	Lua_MonsterType_Friends::Push(L, Lua_MonsterType::Index(L, 1));
281 	return 1;
282 }
283 
Lua_MonsterType_Get_Immunities(lua_State * L)284 static int Lua_MonsterType_Get_Immunities(lua_State *L) {
285 	Lua_MonsterType_Immunities::Push(L, Lua_MonsterType::Index(L, 1));
286 	return 1;
287 }
288 
Lua_MonsterType_Get_Impact_Effect(lua_State * L)289 static int Lua_MonsterType_Get_Impact_Effect(lua_State *L) {
290 	monster_definition *definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
291 	Lua_EffectType::Push(L, definition->impact_effect);
292 	return 1;
293 }
294 
Lua_MonsterType_Get_Initial_Count(lua_State * L)295 static int Lua_MonsterType_Get_Initial_Count(lua_State* L)
296 {
297 	lua_pushnumber(L, monster_placement_info[Lua_MonsterType::Index(L, 1)].initial_count);
298 	return 1;
299 }
300 
Lua_MonsterType_Get_Maximum_Count(lua_State * L)301 static int Lua_MonsterType_Get_Maximum_Count(lua_State* L)
302 {
303 	lua_pushnumber(L, monster_placement_info[Lua_MonsterType::Index(L, 1)].maximum_count);
304 	return 1;
305 }
306 
307 
Lua_MonsterType_Get_Melee_Impact_Effect(lua_State * L)308 static int Lua_MonsterType_Get_Melee_Impact_Effect(lua_State *L) {
309 	monster_definition *definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
310 	Lua_EffectType::Push(L, definition->melee_impact_effect);
311 	return 1;
312 }
313 
Lua_MonsterType_Get_Minimum_Count(lua_State * L)314 static int Lua_MonsterType_Get_Minimum_Count(lua_State* L)
315 {
316 	lua_pushnumber(L, monster_placement_info[Lua_MonsterType::Index(L, 1)].minimum_count);
317 	return 1;
318 }
319 
Lua_MonsterType_Get_Radius(lua_State * L)320 static int Lua_MonsterType_Get_Radius(lua_State *L) {
321 	monster_definition *definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
322 	lua_pushnumber(L, (double) definition->radius / WORLD_ONE);
323 	return 1;
324 }
325 
Lua_MonsterType_Get_Random_Chance(lua_State * L)326 static int Lua_MonsterType_Get_Random_Chance(lua_State* L)
327 {
328 	lua_pushnumber(L, (double) monster_placement_info[Lua_MonsterType::Index(L, 1)].random_chance / UINT16_MAX);
329 	return 1;
330 }
331 
Lua_MonsterType_Get_Random_Count(lua_State * L)332 static int Lua_MonsterType_Get_Random_Count(lua_State* L)
333 {
334 	lua_pushnumber(L, monster_placement_info[Lua_MonsterType::Index(L, 1)].random_count);
335 	return 1;
336 }
337 
Lua_MonsterType_Get_Random_Location(lua_State * L)338 static int Lua_MonsterType_Get_Random_Location(lua_State* L)
339 {
340 	lua_pushboolean(L, monster_placement_info[Lua_MonsterType::Index(L, 1)].flags & _reappears_in_random_location);
341 	return 1;
342 }
343 
Lua_MonsterType_Get_Weaknesses(lua_State * L)344 static int Lua_MonsterType_Get_Weaknesses(lua_State *L) {
345 	Lua_MonsterType_Weaknesses::Push(L, Lua_MonsterType::Index(L, 1));
346 	return 1;
347 }
348 
Lua_MonsterType_Get_Item(lua_State * L)349 static int Lua_MonsterType_Get_Item(lua_State *L) {
350 	monster_definition *definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
351 	Lua_ItemType::Push(L, definition->carrying_item_type);
352 	return 1;
353 }
354 
Lua_MonsterType_Set_Class(lua_State * L)355 static int Lua_MonsterType_Set_Class(lua_State *L) {
356 	monster_definition *definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
357 	definition->_class = static_cast<int32>(Lua_MonsterClass::ToIndex(L, 2));
358 	return 0;
359 }
360 
361 template<uint32 flag>
Lua_MonsterType_Set_Flag(lua_State * L)362 static int Lua_MonsterType_Set_Flag(lua_State* L)
363 {
364 	if (!lua_isboolean(L, 2))
365 		return luaL_error(L, "monster flag: incorrect argument type");
366 
367 	monster_definition* definition = get_monster_definition_external(Lua_MonsterType::Index(L, 1));
368 	if (lua_toboolean(L, 2))
369 	{
370 		definition->flags |= flag;
371 	}
372 	else
373 	{
374 		definition->flags &= ~flag;
375 	}
376 
377 	return 0;
378 }
379 
Lua_MonsterType_Set_Item(lua_State * L)380 static int Lua_MonsterType_Set_Item(lua_State *L) {
381 	int item_type = 0;
382 	if (lua_isnumber(L, 2))
383 	{
384 		item_type = static_cast<int>(lua_tonumber(L, 2));
385 	}
386 	else if (lua_isnil(L, 2))
387 	{
388 		item_type = NONE;
389 	}
390 	else
391 		return luaL_error(L, "item: incorrect argument type");
392 
393 	monster_definition *definition = get_monster_definition_external(Lua_MonsterType::ToIndex(L, 1));
394 
395 	definition->carrying_item_type = item_type;
396 	return 0;
397 }
398 
Lua_MonsterType_Set_Initial_Count(lua_State * L)399 static int Lua_MonsterType_Set_Initial_Count(lua_State* L)
400 {
401 	if (lua_isnumber(L, 2))
402 	{
403 		monster_placement_info[Lua_MonsterType::Index(L, 1)].initial_count = lua_tonumber(L, 2);
404 	}
405 	else
406 	{
407 		return luaL_error(L, "initial_count: incorrect argument type");
408 	}
409 	return 0;
410 }
411 
Lua_MonsterType_Set_Maximum_Count(lua_State * L)412 static int Lua_MonsterType_Set_Maximum_Count(lua_State* L)
413 {
414 	if (lua_isnumber(L, 2))
415 	{
416 		monster_placement_info[Lua_MonsterType::Index(L, 1)].maximum_count = lua_tonumber(L, 2);
417 	}
418 	else
419 	{
420 		return luaL_error(L, "maximum_count: incorrect argument type");
421 	}
422 	return 0;
423 }
424 
Lua_MonsterType_Set_Minimum_Count(lua_State * L)425 static int Lua_MonsterType_Set_Minimum_Count(lua_State* L)
426 {
427 	if (lua_isnumber(L, 2))
428 	{
429 		monster_placement_info[Lua_MonsterType::Index(L, 1)].minimum_count = lua_tonumber(L, 2);
430 	}
431 	else
432 	{
433 		return luaL_error(L, "minimum_count: incorrect argument type");
434 	}
435 	return 0;
436 }
437 
Lua_MonsterType_Set_Random_Chance(lua_State * L)438 static int Lua_MonsterType_Set_Random_Chance(lua_State* L)
439 {
440 	if (lua_isnumber(L, 2))
441 	{
442 		monster_placement_info[Lua_MonsterType::Index(L, 1)].random_chance = static_cast<uint16>(lua_tonumber(L, 2) * UINT16_MAX + 0.5);
443 	}
444 	else
445 	{
446 		return luaL_error(L, "random_chance: incorrect argument type");
447 	}
448 	return 0;
449 }
450 
Lua_MonsterType_Set_Random_Count(lua_State * L)451 static int Lua_MonsterType_Set_Random_Count(lua_State* L)
452 {
453 	if (lua_isnumber(L, 2))
454 	{
455 		monster_placement_info[Lua_MonsterType::Index(L, 1)].random_count = lua_tonumber(L, 2);
456 	}
457 	else
458 	{
459 		return luaL_error(L, "random_count: incorrect argument type");
460 	}
461 	return 0;
462 }
463 
Lua_MonsterType_Set_Random_Location(lua_State * L)464 static int Lua_MonsterType_Set_Random_Location(lua_State* L)
465 {
466 	if (lua_isboolean(L, 2))
467 	{
468 		if (lua_toboolean(L, 2))
469 		{
470 			monster_placement_info[Lua_MonsterType::Index(L, 1)].flags |= _reappears_in_random_location;
471 		}
472 		else
473 		{
474 			monster_placement_info[Lua_MonsterType::Index(L, 1)].flags &= ~_reappears_in_random_location;
475 		}
476 	}
477 	else
478 	{
479 		return luaL_error(L, "random_location: incorrect argument type");
480 	}
481 	return 0;
482 }
483 
484 const luaL_Reg Lua_MonsterType_Get[] = {
485 	{"attacks_immediately", Lua_MonsterType_Get_Flag<_monster_attacks_immediately>},
486 	{"cannot_be_dropped", Lua_MonsterType_Get_Flag<_monster_cannot_be_dropped>},
487 	{"class", Lua_MonsterType_Get_Class},
488 	{"enemies", Lua_MonsterType_Get_Enemies},
489 	{"friends", Lua_MonsterType_Get_Friends},
490 	{"height", Lua_MonsterType_Get_Height},
491 	{"immunities", Lua_MonsterType_Get_Immunities},
492 	{"impact_effect", Lua_MonsterType_Get_Impact_Effect},
493 	{"initial_count", Lua_MonsterType_Get_Initial_Count},
494 	{"major", Lua_MonsterType_Get_Flag<_monster_major>},
495 	{"maximum_count", Lua_MonsterType_Get_Maximum_Count},
496 	{"melee_impact_effect", Lua_MonsterType_Get_Melee_Impact_Effect},
497 	{"minimum_count", Lua_MonsterType_Get_Minimum_Count},
498 	{"minor", Lua_MonsterType_Get_Flag<_monster_minor>},
499 	{"item", Lua_MonsterType_Get_Item},
500 	{"radius", Lua_MonsterType_Get_Radius},
501 	{"random_chance", Lua_MonsterType_Get_Random_Chance},
502 	{"random_location", Lua_MonsterType_Get_Random_Location},
503 	{"total_available", Lua_MonsterType_Get_Random_Count},
504 	{"weaknesses", Lua_MonsterType_Get_Weaknesses},
505 	{"waits_with_clear_shot", Lua_MonsterType_Get_Flag<_monster_waits_with_clear_shot>},
506 	{0, 0}
507 };
508 
509 const luaL_Reg Lua_MonsterType_Set[] = {
510 	{"attacks_immediately", Lua_MonsterType_Set_Flag<_monster_attacks_immediately>},
511 	{"cannot_be_dropped", Lua_MonsterType_Set_Flag<_monster_cannot_be_dropped>},
512 	{"class", Lua_MonsterType_Set_Class},
513 	{"initial_count", Lua_MonsterType_Set_Initial_Count},
514 	{"item", Lua_MonsterType_Set_Item},
515 	{"major", Lua_MonsterType_Set_Flag<_monster_major>},
516 	{"maximum_count", Lua_MonsterType_Set_Maximum_Count},
517 	{"minimum_count", Lua_MonsterType_Set_Minimum_Count},
518 	{"minor", Lua_MonsterType_Set_Flag<_monster_minor>},
519 	{"random_chance", Lua_MonsterType_Set_Random_Chance},
520 	{"random_location", Lua_MonsterType_Set_Random_Location},
521 	{"total_available", Lua_MonsterType_Set_Random_Count},
522 	{"waits_with_clear_shot", Lua_MonsterType_Set_Flag<_monster_waits_with_clear_shot>},
523 	{0, 0}
524 };
525 
526 char Lua_MonsterMode_Name[] = "monster_mode";
527 typedef L_Enum<Lua_MonsterMode_Name> Lua_MonsterMode;
528 
529 char Lua_MonsterModes_Name[] = "MonsterModes";
530 typedef L_EnumContainer<Lua_MonsterModes_Name, Lua_MonsterMode> Lua_MonsterModes;
531 
532 char Lua_MonsterAction_Name[] = "monster_action";
533 
534 char Lua_MonsterActions_Name[] = "MonsterActions";
535 typedef L_EnumContainer<Lua_MonsterActions_Name, Lua_MonsterAction> Lua_MonsterActions;
536 
537 char Lua_MonsterTypes_Name[] = "MonsterTypes";
538 typedef L_EnumContainer<Lua_MonsterTypes_Name, Lua_MonsterType> Lua_MonsterTypes;
539 
540 char Lua_Monster_Name[] = "monster";
541 
Lua_Monster_Accelerate(lua_State * L)542 int Lua_Monster_Accelerate(lua_State *L)
543 {
544 	if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
545 		return luaL_error(L, "accelerate: incorrect argument type");
546 
547 	short monster_index = Lua_Monster::Index(L, 1);
548 	monster_data *monster = get_monster_data(monster_index);
549 	(void)monster;
550 	double direction = static_cast<double>(lua_tonumber(L, 2));
551 	double velocity = static_cast<double>(lua_tonumber(L, 3));
552 	double vertical_velocity = static_cast<double>(lua_tonumber(L, 4));
553 
554 	accelerate_monster(monster_index, static_cast<int>(vertical_velocity * WORLD_ONE), static_cast<int>(direction/AngleConvert), static_cast<int>(velocity * WORLD_ONE));
555 	return 0;
556 }
557 
Lua_Monster_Attack(lua_State * L)558 int Lua_Monster_Attack(lua_State *L)
559 {
560 	short target = 0;
561 	if (lua_isnumber(L, 2))
562 		target = static_cast<short>(lua_tonumber(L, 2));
563 	else if (Lua_Monster::Is(L, 2))
564 		target = Lua_Monster::Index(L, 2);
565 	else
566 		return luaL_error(L, "attack: incorrect argument type");
567 
568 	change_monster_target(Lua_Monster::Index(L, 1), target);
569 	return 0;
570 }
571 
Lua_Monster_Play_Sound(lua_State * L)572 int Lua_Monster_Play_Sound(lua_State *L)
573 {
574 	short sound_index = Lua_Sound::ToIndex(L, 2);
575 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
576 	play_object_sound(monster->object_index, sound_index);
577 	return 0;
578 }
579 
Lua_Monster_Damage(lua_State * L)580 int Lua_Monster_Damage(lua_State *L)
581 {
582 	if (!lua_isnumber(L, 2))
583 		return luaL_error(L, "damage: incorrect argument type");
584 
585 	int damage_amount = static_cast<int>(lua_tonumber(L, 2));
586 	int damage_type = NONE;
587 	if (lua_gettop(L) == 3)
588 	{
589 		damage_type = Lua_DamageType::ToIndex(L, 3);
590 	}
591 
592 	damage_definition damage;
593 	if (damage_type != NONE)
594 		damage.type = damage_type;
595 	else
596 		damage.type = _damage_fist;
597 
598 	damage.base = damage_amount;
599 	damage.random = 0;
600 	damage.flags = 0;
601 	damage.scale = FIXED_ONE;
602 
603 	int monster_index = Lua_Monster::Index(L, 1);
604 	monster_data *monster = get_monster_data(monster_index);
605 	damage_monster(monster_index, NONE, NONE, &(monster->sound_location), &damage, NONE);
606 	return 0;
607 }
608 
Lua_Monster_Valid(int16 index)609 int Lua_Monster_Valid(int16 index)
610 {
611 	if (index < 0 || index >= MAXIMUM_MONSTERS_PER_MAP)
612 		return false;
613 
614 	monster_data *monster = GetMemberWithBounds(monsters, index, MAXIMUM_MONSTERS_PER_MAP);
615 	return (SLOT_IS_USED(monster));
616 }
617 
618 struct monster_pathfinding_data
619 {
620 	struct monster_definition *definition;
621 	struct monster_data *monster;
622 
623 	bool cross_zone_boundaries;
624 };
625 
626 extern void advance_monster_path(short monster_index);
627 extern int32 monster_pathfinding_cost_function(short source_polygon_index, short line_index, short destination_polygon_index, void *data);
628 extern void set_monster_action(short monster_index, short action);
629 extern void set_monster_mode(short monster_index, short new_mode, short target_index);
630 
Lua_Monster_Move_By_Path(lua_State * L)631 int Lua_Monster_Move_By_Path(lua_State *L)
632 {
633 	int monster_index = Lua_Monster::Index(L, 1);
634 	int polygon_index = 0;
635 	if (lua_isnumber(L, 2))
636 	{
637 		polygon_index = static_cast<int>(lua_tonumber(L, 2));
638 		if (!Lua_Polygon::Valid(polygon_index))
639 			return luaL_error(L, "move_by_path: invalid polygon index");
640 	}
641 	else if (Lua_Polygon::Is(L, 2))
642 	{
643 		polygon_index = Lua_Polygon::Index(L, 2);
644 	}
645 	else
646 		return luaL_error(L, "move_by_path: incorrect argument type");
647 
648 	monster_data *monster = get_monster_data(monster_index);
649 	if (MONSTER_IS_PLAYER(monster))
650 		return luaL_error(L, "move_by_path: monster is player");
651 
652 	monster_definition *definition = get_monster_definition_external(monster->type);
653 	object_data *object = get_object_data(monster->object_index);
654 	monster_pathfinding_data path;
655 	world_point2d destination;
656 
657 	if (!MONSTER_IS_ACTIVE(monster))
658 		activate_monster(monster_index);
659 
660 	if (monster->path != NONE)
661 	{
662 		delete_path(monster->path);
663 		monster->path = NONE;
664 	}
665 
666 	SET_MONSTER_NEEDS_PATH_STATUS(monster, false);
667 	path.definition = definition;
668 	path.monster = monster;
669 	path.cross_zone_boundaries = true;
670 
671 	destination = get_polygon_data(polygon_index)->center;
672 
673 	monster->path = new_path((world_point2d *) &object->location, object->polygon, &destination, polygon_index, 3 * definition->radius, monster_pathfinding_cost_function, &path);
674 	if (monster->path == NONE)
675 	{
676 		if (monster->action != _monster_is_being_hit || MONSTER_IS_DYING(monster))
677 		{
678 			set_monster_action(monster_index, _monster_is_stationary);
679 		}
680 		set_monster_mode(monster_index, _monster_unlocked, NONE);
681 		return 0;
682 	}
683 
684 	advance_monster_path(monster_index);
685 	return 0;
686 }
687 
688 extern void add_object_to_polygon_object_list(short object_index, short polygon_index);
689 
Lua_Monster_Position(lua_State * L)690 int Lua_Monster_Position(lua_State *L)
691 {
692 	if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
693 		return luaL_error(L, "position: incorrect argument type");
694 
695 	short polygon_index = 0;
696 	if (lua_isnumber(L, 5))
697 	{
698 		polygon_index = static_cast<int>(lua_tonumber(L, 5));
699 		if (!Lua_Polygon::Valid(polygon_index))
700 			return luaL_error(L, "position: invalid polygon index");
701 	}
702 	else if (Lua_Polygon::Is(L, 5))
703 	{
704 		polygon_index = Lua_Polygon::Index(L, 5);
705 	}
706 	else
707 		return luaL_error(L, "position: incorrect argument type");
708 
709 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
710 	object_data *object = get_object_data(monster->object_index);
711 	object->location.x = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
712 	object->location.y = static_cast<int>(lua_tonumber(L, 3) * WORLD_ONE);
713 	object->location.z = static_cast<int>(lua_tonumber(L, 4) * WORLD_ONE);
714 
715 	if (polygon_index != object->polygon)
716 	{
717 		remove_object_from_polygon_object_list(monster->object_index);
718 		add_object_to_polygon_object_list(monster->object_index, polygon_index);
719 	}
720 	return 0;
721 }
722 
723 
Lua_Monster_Get_Action(lua_State * L)724 static int Lua_Monster_Get_Action(lua_State *L)
725 {
726 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
727 	Lua_MonsterAction::Push(L, monster->action);
728 	return 1;
729 }
730 
Lua_Monster_Get_Active(lua_State * L)731 static int Lua_Monster_Get_Active(lua_State *L)
732 {
733 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
734 	if (MONSTER_IS_PLAYER(monster))
735 		return luaL_error(L, "active: monster is a player");
736 
737 	lua_pushboolean(L, MONSTER_IS_ACTIVE(monster));
738 	return 1;
739 }
740 
Lua_Monster_Get_External_Velocity(lua_State * L)741 static int Lua_Monster_Get_External_Velocity(lua_State *L)
742 {
743 	monster_data* monster = get_monster_data(Lua_Monster::Index(L, 1));
744 	lua_pushnumber(L, (double) monster->external_velocity / WORLD_ONE);
745 	return 1;
746 }
747 
Lua_Monster_Get_Facing(lua_State * L)748 static int Lua_Monster_Get_Facing(lua_State *L)
749 {
750 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
751 	object_data *object = get_object_data(monster->object_index);
752 	lua_pushnumber(L, (double) object->facing * AngleConvert);
753 	return 1;
754 }
755 
Lua_Monster_Get_Mode(lua_State * L)756 static int Lua_Monster_Get_Mode(lua_State *L)
757 {
758 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
759 	Lua_MonsterMode::Push(L, monster->mode);
760 	return 1;
761 }
762 
Lua_Monster_Get_Player(lua_State * L)763 static int Lua_Monster_Get_Player(lua_State *L)
764 {
765 	int monster_index = Lua_Monster::Index(L, 1);
766 	monster_data *monster = get_monster_data(monster_index);
767 	if (MONSTER_IS_PLAYER(monster))
768 		Lua_Player::Push(L, monster_index_to_player_index(monster_index));
769 	else
770 		lua_pushnil(L);
771 
772 	return 1;
773 }
774 
Lua_Monster_Get_Polygon(lua_State * L)775 static int Lua_Monster_Get_Polygon(lua_State *L)
776 {
777 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
778 	object_data *object = get_object_data(monster->object_index);
779 	Lua_Polygon::Push(L, object->polygon);
780 	return 1;
781 }
782 
Lua_Monster_Get_Type(lua_State * L)783 static int Lua_Monster_Get_Type(lua_State *L)
784 {
785 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
786 	Lua_MonsterType::Push(L, monster->type);
787 	return 1;
788 }
789 
Lua_Monster_Get_Valid(lua_State * L)790 static int Lua_Monster_Get_Valid(lua_State *L)
791 {
792 	lua_pushboolean(L, Lua_Monster::Valid(Lua_Monster::Index(L, 1)));
793 	return 1;
794 }
795 
Lua_Monster_Get_Vertical_Velocity(lua_State * L)796 static int Lua_Monster_Get_Vertical_Velocity(lua_State *L)
797 {
798 	monster_data* monster = get_monster_data(Lua_Monster::Index(L, 1));
799 	lua_pushnumber(L, (double) monster->vertical_velocity / WORLD_ONE);
800 	return 1;
801 }
802 
Lua_Monster_Get_Visible(lua_State * L)803 static int Lua_Monster_Get_Visible(lua_State *L)
804 {
805 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
806 	object_data *object = get_object_data(monster->object_index);
807 	lua_pushboolean(L, OBJECT_IS_VISIBLE(object));
808 	return 1;
809 }
810 
Lua_Monster_Get_Vitality(lua_State * L)811 static int Lua_Monster_Get_Vitality(lua_State *L)
812 {
813 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
814 	lua_pushnumber(L, monster->vitality);
815 	return 1;
816 }
817 
Lua_Monster_Get_X(lua_State * L)818 static int Lua_Monster_Get_X(lua_State *L)
819 {
820 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
821 	object_data *object = get_object_data(monster->object_index);
822 	lua_pushnumber(L, (double) object->location.x / WORLD_ONE);
823 	return 1;
824 }
825 
Lua_Monster_Get_Y(lua_State * L)826 static int Lua_Monster_Get_Y(lua_State *L)
827 {
828 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
829 	object_data *object = get_object_data(monster->object_index);
830 	lua_pushnumber(L, (double) object->location.y / WORLD_ONE);
831 	return 1;
832 }
833 
Lua_Monster_Get_Z(lua_State * L)834 static int Lua_Monster_Get_Z(lua_State *L)
835 {
836 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
837 	object_data *object = get_object_data(monster->object_index);
838 	lua_pushnumber(L, (double) object->location.z / WORLD_ONE);
839 	return 1;
840 }
841 
Lua_Monster_Set_Active(lua_State * L)842 static int Lua_Monster_Set_Active(lua_State *L)
843 {
844 	if (!lua_isboolean(L, 2))
845 		return luaL_error(L, "active: incorrect argument type");
846 
847 	bool activate = lua_toboolean(L, 2);
848 	int monster_index = Lua_Monster::Index(L, 1);
849 	monster_data *monster = get_monster_data(monster_index);
850 	if (MONSTER_IS_PLAYER(monster))
851 		return luaL_error(L, "active: monster is a player");
852 	if (activate)
853 	{
854 		if (!MONSTER_IS_ACTIVE(monster))
855 			activate_monster(monster_index);
856 	}
857 	else
858 	{
859 		if (MONSTER_IS_ACTIVE(monster))
860 			deactivate_monster(monster_index);
861 	}
862 	return 0;
863 }
864 
Lua_Monster_Set_External_Velocity(lua_State * L)865 static int Lua_Monster_Set_External_Velocity(lua_State *L)
866 {
867 	if (!lua_isnumber(L, 2))
868 		return luaL_error(L, "external_velocity: incorrect argument type");
869 
870 	monster_data* monster = get_monster_data(Lua_Monster::Index(L, 1));
871 	monster->external_velocity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
872 	return 0;
873 }
874 
Lua_Monster_Set_Facing(lua_State * L)875 static int Lua_Monster_Set_Facing(lua_State *L)
876 {
877 	if (!lua_isnumber(L, 2))
878 		return luaL_error(L, "facing: incorrect argument type");
879 
880 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
881 	object_data *object = get_object_data(monster->object_index);
882 	object->facing = static_cast<int>(lua_tonumber(L, 2) / AngleConvert);
883 	return 0;
884 }
885 
Lua_Monster_Set_Vertical_Velocity(lua_State * L)886 static int Lua_Monster_Set_Vertical_Velocity(lua_State *L)
887 {
888 	if (!lua_isnumber(L, 2))
889 		return luaL_error(L, "vertical_velocity: incorrect argument type");
890 
891 	monster_data* monster = get_monster_data(Lua_Monster::Index(L, 1));
892 	monster->vertical_velocity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
893 	return 0;
894 }
895 
Lua_Monster_Set_Visible(lua_State * L)896 static int Lua_Monster_Set_Visible(lua_State *L) {
897 	int monster_index = Lua_Monster::Index(L, 1);
898 	monster_data *monster = get_monster_data(monster_index);
899 	object_data *object = get_object_data(monster->object_index);
900 	int invisible = !lua_toboolean(L, 2);
901 	if(monster->action == _monster_is_teleporting_out) return 0;
902 	if(MONSTER_IS_ACTIVE(monster) || monster->vitality >= 0) {
903 		// Cool stuff happens if you just set an active
904 		// monster to invisible.  What we should do instead of
905 		// the below is expose teleports_out_when_deactivated
906 		/*if(invisible) {
907 		  monster->flags |= (uint16)_monster_teleports_out_when_deactivated;
908 		  deactivate_monster(monster_index);
909 		  }*/
910 		return luaL_error(L, "visible: monster already activated");
911 	}
912 	else {
913 		// No real possibility of messing stuff up here.
914 		SET_OBJECT_INVISIBILITY(object, invisible);
915 	}
916 	return 0;
917 }
918 
Lua_Monster_Set_Vitality(lua_State * L)919 static int Lua_Monster_Set_Vitality(lua_State *L)
920 {
921 	if (!lua_isnumber(L, 2))
922 		return luaL_error(L, "vitality: incorrect argument type");
923 
924 	monster_data *monster = get_monster_data(Lua_Monster::Index(L, 1));
925 	monster->vitality = static_cast<int>(lua_tonumber(L, 2));
926 	return 0;
927 }
928 
929 const luaL_Reg Lua_Monster_Get[] = {
930 	{"accelerate", L_TableFunction<Lua_Monster_Accelerate>},
931 	{"action", Lua_Monster_Get_Action},
932 	{"active", Lua_Monster_Get_Active},
933 	{"attack", L_TableFunction<Lua_Monster_Attack>},
934 	{"damage", L_TableFunction<Lua_Monster_Damage>},
935 	{"external_velocity", Lua_Monster_Get_External_Velocity},
936 	{"facing", Lua_Monster_Get_Facing},
937 	{"life", Lua_Monster_Get_Vitality},
938 	{"mode", Lua_Monster_Get_Mode},
939 	{"move_by_path", L_TableFunction<Lua_Monster_Move_By_Path>},
940 	{"player", Lua_Monster_Get_Player},
941 	{"play_sound", L_TableFunction<Lua_Monster_Play_Sound>},
942 	{"polygon", Lua_Monster_Get_Polygon},
943 	{"position", L_TableFunction<Lua_Monster_Position>},
944 	{"type", Lua_Monster_Get_Type},
945 	{"valid", Lua_Monster_Get_Valid},
946 	{"vertical_velocity", Lua_Monster_Get_Vertical_Velocity},
947 	{"visible", Lua_Monster_Get_Visible},
948 	{"vitality", Lua_Monster_Get_Vitality},
949 	{"x", Lua_Monster_Get_X},
950 	{"y", Lua_Monster_Get_Y},
951 	{"yaw", Lua_Monster_Get_Facing},
952 	{"z", Lua_Monster_Get_Z},
953 	{0, 0}
954 };
955 
956 const luaL_Reg Lua_Monster_Set[] = {
957 	{"active", Lua_Monster_Set_Active},
958 	{"external_velocity", Lua_Monster_Set_External_Velocity},
959 	{"facing", Lua_Monster_Set_Facing},
960 	{"life", Lua_Monster_Set_Vitality},
961 	{"vertical_velocity", Lua_Monster_Set_Vertical_Velocity},
962 	{"visible", Lua_Monster_Set_Visible},
963 	{"vitality", Lua_Monster_Set_Vitality},
964 	{"yaw", Lua_Monster_Set_Facing},
965 	{0, 0}
966 };
967 
968 char Lua_Monsters_Name[] = "Monsters";
969 
970 // Monsters.new(x, y, height, polygon, type)
Lua_Monsters_New(lua_State * L)971 int Lua_Monsters_New(lua_State *L)
972 {
973 	if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3))
974 		luaL_error(L, "new: incorrect argument type");
975 
976 	int polygon_index = 0;
977 	if (lua_isnumber(L, 4))
978 	{
979 		polygon_index = static_cast<int>(lua_tonumber(L, 4));
980 		if (!Lua_Polygon::Valid(polygon_index))
981 			return luaL_error(L, "new: invalid polygon index");
982 	}
983 	else if (Lua_Polygon::Is(L, 4))
984 	{
985 		polygon_index = Lua_Polygon::Index(L, 4);
986 	}
987 	else
988 		return luaL_error(L, "new: incorrect argument type");
989 
990 	short monster_type = Lua_MonsterType::ToIndex(L, 5);
991 
992 	object_location location;
993 	location.p.x = static_cast<int>(lua_tonumber(L, 1) * WORLD_ONE);
994 	location.p.y = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
995 	location.p.z = static_cast<int>(lua_tonumber(L, 3) * WORLD_ONE);
996 
997 	location.polygon_index = polygon_index;
998 	location.yaw = 0;
999 	location.pitch = 0;
1000 	location.flags = 0;
1001 
1002 	short monster_index = ::new_monster(&location, monster_type);
1003 	if (monster_index == NONE)
1004 		return 0;
1005 
1006 	Lua_Monster::Push(L, monster_index);
1007 	return 1;
1008 }
1009 
1010 const luaL_Reg Lua_Monsters_Methods[] = {
1011 	{"new", L_TableFunction<Lua_Monsters_New>},
1012 	{0, 0}
1013 };
1014 
1015 static void compatibility(lua_State *L);
1016 
Lua_Monsters_register(lua_State * L)1017 int Lua_Monsters_register(lua_State *L)
1018 {
1019 	Lua_MonsterClass::Register(L, 0, 0, 0, Lua_MonsterClass_Mnemonics);
1020 	Lua_MonsterClass::Valid = Lua_MonsterClass_Valid;
1021 
1022 	Lua_MonsterClasses::Register(L);
1023 	Lua_MonsterClasses::Length = Lua_MonsterClasses::ConstantLength(_class_yeti_bit + 1);
1024 
1025 
1026 	Lua_MonsterType_Enemies::Register(L, 0, 0, Lua_MonsterType_Enemies_Metatable);
1027 	Lua_MonsterType_Friends::Register(L, 0, 0, Lua_MonsterType_Friends_Metatable);
1028 	Lua_MonsterType_Immunities::Register(L, 0, 0, Lua_MonsterType_Immunities_Metatable);
1029 	Lua_MonsterType_Weaknesses::Register(L, 0, 0, Lua_MonsterType_Weaknesses_Metatable);
1030 
1031 	Lua_MonsterMode::Register(L, 0, 0, 0, Lua_MonsterMode_Mnemonics);
1032 	Lua_MonsterMode::Valid = Lua_MonsterMode::ValidRange(NUMBER_OF_MONSTER_MODES);
1033 	Lua_MonsterModes::Register(L);
1034 	Lua_MonsterModes::Length = Lua_MonsterModes::ConstantLength(NUMBER_OF_MONSTER_MODES);
1035 
1036 	Lua_MonsterAction::Register(L, 0, 0, 0, Lua_MonsterAction_Mnemonics);
1037 	Lua_MonsterAction::Valid = Lua_MonsterAction::ValidRange(NUMBER_OF_MONSTER_ACTIONS);
1038 	Lua_MonsterActions::Register(L);
1039 	Lua_MonsterActions::Length = Lua_MonsterActions::ConstantLength(NUMBER_OF_MONSTER_ACTIONS);
1040 
1041 	Lua_MonsterType::Register(L, Lua_MonsterType_Get, Lua_MonsterType_Set, 0, Lua_MonsterType_Mnemonics);
1042 	Lua_MonsterType::Valid = Lua_MonsterType_Valid;
1043 
1044 	Lua_MonsterTypes::Register(L);
1045 	Lua_MonsterTypes::Length = Lua_MonsterTypes::ConstantLength(NUMBER_OF_MONSTER_TYPES);
1046 
1047 	Lua_Monster::Register(L, Lua_Monster_Get, Lua_Monster_Set);
1048 	Lua_Monster::Valid = Lua_Monster_Valid;
1049 
1050 	Lua_Monsters::Register(L, Lua_Monsters_Methods);
1051 	Lua_Monsters::Length = boost::bind(get_dynamic_limit, (int) _dynamic_limit_monsters);
1052 
1053 	compatibility(L);
1054 	return 0;
1055 }
1056 
1057 static const char *compatibility_script = ""
1058 // there are some conversions to and from internal units, because old
1059 // monster API was wrong
1060 	"function activate_monster(monster) Monsters[monster].active = true end\n"
1061 	"function attack_monster(agressor, target) Monsters[aggressor]:attack(target) end\n"
1062 	"function damage_monster(monster, damage, type) if type then Monsters[monster]:damage(damage, type) else Monsters[monster]:damage(damage) end end\n"
1063 	"function deactivate_monster(monster) Monsters[monster].active = false end\n"
1064 	"function get_monster_action(monster) if Monsters[monster].action then return Monsters[monster].action.index else return -1 end end\n"
1065 	"function get_monster_enemy(monster_type, enemy_type) return MonsterTypes[monster_type].enemies[enemy_type] end\n"
1066 	"function get_monster_friend(monster_type, friend_type) return MonsterTypes[monster_type].friends[friend_type] end\n"
1067 	"function get_monster_facing(monster) return Monsters[monster].facing * 512 / 360 end\n"
1068 	"function get_monster_immunity(monster, damage_type) return MonsterTypes[monster].immunities[damage_type] end\n"
1069 	"function get_monster_item(monster) if MonsterTypes[monster].item then return MonsterTypes[monster].item.index else return -1 end end\n"
1070 	"function get_monster_mode(monster) if Monsters[monster].mode then return Monsters[monster].mode.index else return -1 end end\n"
1071 	"function get_monster_polygon(monster) return Monsters[monster].polygon.index end\n"
1072 	"function get_monster_position(monster) return Monsters[monster].x * 1024, Monsters[monster].y * 1024, Monsters[monster].z * 1024 end\n"
1073 	"function get_monster_type(monster) return Monsters[monster].type.index end\n"
1074 	"function get_monster_type_class(monster) return MonsterTypes[monster].class.index end\n"
1075 	"function get_monster_visible(monster) return Monsters[monster].visible end\n"
1076 	"function get_monster_vitality(monster) return Monsters[monster].vitality end\n"
1077 	"function get_monster_weakness(monster, damage) return MonsterTypes[monster].weaknesses[damage] end\n"
1078 	"function monster_index_valid(monster) if Monsters[monster] then return true else return false end end\n"
1079 	"function move_monster(monster, polygon) Monsters[monster]:move_by_path(polygon) end\n"
1080 	"function new_monster(type, poly, facing, height, x, y) if (x and y) then m = Monsters.new(x, y, height / 1024, poly, type) elseif (height) then m = Monsters.new(Polygons[poly].x, Polygons[poly].y, height / 1024, poly, type) else m = Monsters.new(Polygons[poly].x, Polygons[poly].y, 0, poly, type) end if m then return m.index else return -1 end end\n"
1081 	"function set_monster_enemy(monster_type, enemy_type, hostile) MonsterTypes[monster_type].enemies[enemy_type] = hostile end\n"
1082 	"function set_monster_friend(monster_type, friend_type, friendly) MonsterTypes[monster_type].friends[friend_type] = friendly end\n"
1083 	"function set_monster_immunity(monster, damage, immune) MonsterTypes[monster].immunities[damage] = immune end\n"
1084 	"function set_monster_item(monster, item) if item == -1 then MonsterTypes[monster].item = nil else MonsterTypes[monster].item = item end end\n"
1085 	"function set_monster_position(monster, polygon, x, y, z) Monsters[monster]:position(x, y, z, polygon) end\n"
1086 	"function set_monster_type_class(monster, class) MonsterTypes[monster].class = class end\n"
1087 	"function set_monster_vitality(monster, vitality) Monsters[monster].vitality = vitality end\n"
1088 	"function set_monster_weakness(monster, damage, weak) MonsterTypes[monster].weaknesses[damage] = weak end\n"
1089 	;
1090 
compatibility(lua_State * L)1091 static void compatibility(lua_State *L)
1092 {
1093 	luaL_loadbuffer(L, compatibility_script, strlen(compatibility_script), "monsters_compatibility");
1094 	lua_pcall(L, 0, 0, 0);
1095 }
1096 
1097 
1098 
1099 #endif
1100