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