Apply the new ground_level method.
[crawl.git] / crawl-ref / source / l_mons.cc
blob7b9626ac6c25bf15216a19f98a61561c0d14e980
1 #include "AppHdr.h"
3 #include "cluautil.h"
4 #include "l_libs.h"
6 #include "delay.h"
7 #include "dlua.h"
8 #include "initfile.h"
9 #include "libutil.h"
10 #include "mon-act.h"
11 #include "mon-behv.h"
12 #include "mon-util.h"
13 #include "mon-stuff.h"
15 #define WRAPPED_MONSTER(ls, name) \
16 MonsterWrap *___mw = clua_get_userdata< MonsterWrap >(ls, MONS_METATABLE); \
17 if (!___mw \
18 || !___mw->mons \
19 || CLua::get_vm(ls).managed_vm && ___mw->turn != you.num_turns) \
20 { \
21 luaL_argerror(ls, 1, "Invalid monster wrapper"); \
22 } \
23 monster *name(___mw->mons)
25 /////////////////////////////////////////////////////////////////////
26 // Monster handling
28 void push_monster(lua_State *ls, monster* mons)
30 MonsterWrap *mw = clua_new_userdata< MonsterWrap >(ls, MONS_METATABLE);
31 mw->turn = you.num_turns;
32 mw->mons = mons;
35 #define MDEF(name) \
36 static int l_mons_##name(lua_State *ls, monster* mons, \
37 const char *attr) \
39 #define MDEFN(name, closure) \
40 static int l_mons_##name(lua_State *ls, monster* mons, const char *attrs) \
41 { \
42 lua_pushlightuserdata(ls, mons); \
43 lua_pushcclosure(ls, l_mons_##closure, 1); \
44 return (1); \
47 MDEF(name)
49 PLUARET(string, mons->name(DESC_PLAIN, true).c_str());
52 MDEF(unique)
54 PLUARET(boolean, mons_is_unique(mons->type));
57 MDEF(base_name)
59 PLUARET(string, mons->base_name(DESC_PLAIN, true).c_str());
62 MDEF(full_name)
64 PLUARET(string, mons->full_name(DESC_PLAIN, true).c_str());
67 MDEF(db_name)
69 PLUARET(string, mons->name(DESC_DBNAME, true).c_str());
72 MDEF(type_name)
74 PLUARET(string, mons_type_name(mons->type, DESC_PLAIN).c_str());
77 MDEF(entry_name)
79 ASSERT_DLUA;
81 const monsterentry *me = get_monster_data(mons->type);
82 if (me)
83 lua_pushstring(ls, me->name);
84 else
85 lua_pushnil(ls);
87 return (1);
90 MDEF(x)
92 PLUARET(number, int(mons->pos().x) - int(you.pos().x));
95 MDEF(y)
97 PLUARET(number, int(mons->pos().y) - int(you.pos().y));
100 static const char* _behaviour_name(beh_type beh);
101 MDEF(beh)
103 PLUARET(string, _behaviour_name(mons->behaviour));
106 MDEF(energy)
108 // XXX: fix this after speed_increment clean up
109 PLUARET(number, (mons->speed_increment - 79))
112 LUAFN(l_mons_add_energy)
114 ASSERT_DLUA;
115 monster* mons = clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
116 mons->speed_increment += luaL_checkint(ls, 1);
117 return (0);
119 MDEFN(add_energy, add_energy)
121 #define LUANAMEFN(name, expr) \
122 static int l_mons_##name##_fn(lua_State *ls) { \
123 ASSERT_DLUA; \
124 const monster* mons = \
125 clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1)); \
126 const description_level_type dtype = \
127 lua_isstring(ls, 1)? \
128 description_type_by_name(luaL_checkstring(ls, 1)) \
129 : DESC_PLAIN; \
130 PLUARET(string, expr.c_str()); \
132 MDEFN(name, name##_fn) \
134 LUANAMEFN(mname, mons->name(dtype, true))
135 LUANAMEFN(mfull_name, mons->full_name(dtype, true))
136 LUANAMEFN(mbase_name, mons->base_name(dtype, true))
138 MDEF(hd)
140 PLUARET(number, mons->hit_dice);
143 MDEF(targetx)
145 PLUARET(number, mons->target.x);
148 MDEF(targety)
150 PLUARET(number, mons->target.y);
153 MDEF(shapeshifter)
155 ASSERT_DLUA;
156 if (mons->has_ench(ENCH_GLOWING_SHAPESHIFTER))
157 lua_pushstring(ls, "glowing shapeshifter");
158 else if (mons->has_ench(ENCH_SHAPESHIFTER))
159 lua_pushstring(ls, "shapeshifter");
160 else
161 lua_pushnil(ls);
162 return (1);
165 MDEF(mimic)
167 ASSERT_DLUA;
168 if (mons_genus(mons->type) == MONS_GOLD_MIMIC)
170 switch (mons->type)
172 case MONS_GOLD_MIMIC:
173 lua_pushstring(ls, "gold mimic"); break;
174 case MONS_WEAPON_MIMIC:
175 lua_pushstring(ls, "weapon mimic"); break;
176 case MONS_ARMOUR_MIMIC:
177 lua_pushstring(ls, "armour mimic"); break;
178 case MONS_POTION_MIMIC:
179 lua_pushstring(ls, "potion mimic"); break;
180 case MONS_SCROLL_MIMIC:
181 lua_pushstring(ls, "scroll mimic"); break;
182 default:
183 lua_pushstring(ls, "unknown mimic"); break;
186 else
187 lua_pushnil(ls);
189 return (1);
192 MDEF(dancing_weapon)
194 ASSERT_DLUA;
196 if (mons_genus(mons->type) == MONS_DANCING_WEAPON)
197 lua_pushstring(ls, "dancing weapon");
198 else
199 lua_pushnil(ls);
201 return (1);
204 static const char *_monuse_names[] =
206 "nothing", "open_doors", "starting_equipment", "weapons_armour"
209 static const char *_monuse_to_str(mon_itemuse_type utyp)
211 COMPILE_CHECK(ARRAYSZ(_monuse_names) == NUM_MONUSE, c1);
212 return _monuse_names[utyp];
215 MDEF(muse)
217 if (const monsterentry *me = mons->find_monsterentry())
219 PLUARET(string, _monuse_to_str(me->gmon_use));
221 return (0);
224 static const char *_moneat_names[] =
226 "nothing", "items", "corpses", "food"
229 static const char *_moneat_to_str(mon_itemeat_type etyp)
231 COMPILE_CHECK(ARRAYSZ(_moneat_names) == NUM_MONEAT, c1);
232 return _moneat_names[etyp];
235 MDEF(meat)
237 if (const monsterentry *me = mons->find_monsterentry())
239 PLUARET(string, _moneat_to_str(me->gmon_eat));
241 return (0);
244 static int l_mons_do_dismiss(lua_State *ls)
246 // dismiss is only callable from dlua, not from managed VMs (i.e.
247 // end-user scripts cannot dismiss monsters).
248 ASSERT_DLUA;
249 monster* mons = clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
251 if (mons->alive())
253 mons->flags |= MF_HARD_RESET;
254 monster_die(mons, KILL_DISMISSED, NON_MONSTER);
256 return (0);
258 MDEFN(dismiss, do_dismiss)
260 // Run the monster AI code.
261 static int l_mons_do_run_ai(lua_State *ls)
263 ASSERT_DLUA;
264 monster* mons = clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
265 if (mons->alive())
266 handle_monster_move(mons);
267 return (0);
269 MDEFN(run_ai, do_run_ai)
271 static int l_mons_do_handle_behaviour(lua_State *ls)
273 ASSERT_DLUA;
274 monster* mons = clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
275 if (mons->alive())
276 handle_behaviour(mons);
277 return (0);
279 MDEFN(handle_behaviour, do_handle_behaviour)
281 static int l_mons_do_random_teleport(lua_State *ls)
283 // We should only be able to teleport monsters from dlua.
284 ASSERT_DLUA;
286 monster* mons = clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
288 if (mons->alive())
289 mons->teleport(true);
291 return (0);
294 MDEFN(random_teleport, do_random_teleport)
296 MDEF(experience)
298 ASSERT_DLUA;
299 PLUARET(number, exper_value(mons));
302 static int l_mons_do_set_prop(lua_State *ls)
304 // We should only be able to set properties from dlua.
305 ASSERT_DLUA;
307 monster* mons =
308 clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
310 const char *prop_name = luaL_checkstring(ls, 1);
312 if (lua_isnoneornil(ls, 2))
313 mons->props.erase(prop_name);
314 else if (lua_isboolean(ls, 2))
315 mons->props[prop_name] = (bool) lua_toboolean(ls, 2);
316 // NOTE: number has to be before string, or numbers will get converted
317 // into strings.
318 else if (lua_isnumber(ls, 2))
319 mons->props[prop_name].get_int() = luaL_checklong(ls, 2);
320 else if (lua_isstring(ls, 2))
321 mons->props[prop_name] = lua_tostring(ls, 2);
322 else if (lua_isfunction(ls, 2))
324 dlua_chunk chunk(ls);
325 mons->props[prop_name] = chunk;
327 else
329 std::string err
330 = make_stringf("Don't know how to set monster property of the "
331 "given value type for property '%s'", prop_name);
332 luaL_argerror(ls, 2, err.c_str());
335 return (0);
338 MDEFN(set_prop, do_set_prop)
340 static int l_mons_do_get_prop(lua_State *ls)
342 // We should only be able to set properties from dlua.
343 ASSERT_DLUA;
345 monster* mons =
346 clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
348 const char *prop_name = luaL_checkstring(ls, 1);
350 if (!mons->props.exists(prop_name))
352 if (lua_isboolean(ls, 2))
354 std::string err = make_stringf("Don't have a property called '%s'.", prop_name);
355 luaL_argerror(ls, 2, err.c_str());
358 return (0);
361 CrawlStoreValue prop = mons->props[prop_name];
362 int num_pushed = 1;
364 switch (prop.get_type())
366 case SV_NONE: lua_pushnil(ls); break;
367 case SV_BOOL: lua_pushboolean(ls, prop.get_bool()); break;
368 case SV_BYTE: lua_pushboolean(ls, prop.get_byte()); break;
369 case SV_SHORT: lua_pushnumber(ls, prop.get_short()); break;
370 case SV_INT: lua_pushnumber(ls, prop.get_int()); break;
371 case SV_FLOAT: lua_pushnumber(ls, prop.get_float()); break;
372 case SV_STR: lua_pushstring(ls, prop.get_string().c_str()); break;
373 case SV_COORD:
374 num_pushed++;
375 lua_pushnumber(ls, prop.get_coord().x);
376 lua_pushnumber(ls, prop.get_coord().y);
377 break;
378 default:
379 // Do nothing for some things.
380 lua_pushnil(ls);
381 break;
384 return (num_pushed);
387 MDEFN(get_prop, do_get_prop)
389 static int l_mons_do_has_prop(lua_State *ls)
391 // We should only be able to get properties from dlua.
392 ASSERT_DLUA;
394 monster* mons =
395 clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
397 const char *prop_name = luaL_checkstring(ls, 1);
399 lua_pushboolean(ls, mons->props.exists(prop_name));
400 return (1);
403 MDEFN(has_prop, do_has_prop)
405 static int l_mons_do_add_ench(lua_State *ls)
407 ASSERT_DLUA;
409 monster* mons =
410 clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
412 const char *ench_name = luaL_checkstring(ls, 1);
413 enchant_type met = name_to_ench(ench_name);
414 if (!met)
416 std::string err
417 = make_stringf("No such enchantment: %s", ench_name);
418 luaL_argerror(ls, 1, err.c_str());
419 return 0;
422 mons->add_ench(mon_enchant(met, luaL_checkint(ls, 2), KC_OTHER,
423 luaL_checkint(ls, 3)));
424 return 0;
427 MDEFN(add_ench, do_add_ench)
429 static int l_mons_do_del_ench(lua_State *ls)
431 ASSERT_DLUA;
433 monster* mons =
434 clua_get_lightuserdata<monster>(ls, lua_upvalueindex(1));
436 const char *ench_name = luaL_checkstring(ls, 1);
437 enchant_type met = name_to_ench(ench_name);
438 if (!met)
440 std::string err
441 = make_stringf("No such enchantment: %s", ench_name);
442 luaL_argerror(ls, 1, err.c_str());
443 return 0;
446 mons->del_ench(met);
447 return 0;
450 MDEFN(del_ench, do_del_ench)
452 MDEF(you_can_see)
454 ASSERT_DLUA;
455 PLUARET(boolean, you.can_see(mons));
458 struct MonsAccessor
460 const char *attribute;
461 int (*accessor)(lua_State *ls, monster* mons, const char *attr);
464 static MonsAccessor mons_attrs[] =
466 { "name", l_mons_name },
467 { "base_name", l_mons_base_name },
468 { "full_name", l_mons_full_name },
469 { "db_name", l_mons_db_name },
470 { "type_name", l_mons_type_name },
471 { "entry_name", l_mons_entry_name },
472 { "unique" , l_mons_unique },
473 { "shapeshifter", l_mons_shapeshifter },
474 { "mimic", l_mons_mimic },
475 { "dancing_weapon", l_mons_dancing_weapon },
477 { "x" , l_mons_x },
478 { "y" , l_mons_y },
479 { "hd" , l_mons_hd },
480 { "beh" , l_mons_beh },
481 { "muse", l_mons_muse },
482 { "meat", l_mons_meat },
484 { "targetx", l_mons_targetx },
485 { "targety", l_mons_targety },
487 { "mname", l_mons_mname },
488 { "mfull_name", l_mons_mfull_name },
489 { "mbase_name", l_mons_mbase_name },
490 { "energy", l_mons_energy },
491 { "add_energy", l_mons_add_energy },
492 { "dismiss", l_mons_dismiss },
493 { "run_ai", l_mons_run_ai },
494 { "handle_behaviour",l_mons_handle_behaviour },
495 { "experience", l_mons_experience },
496 { "random_teleport", l_mons_random_teleport },
497 { "set_prop", l_mons_set_prop },
498 { "get_prop", l_mons_get_prop },
499 { "has_prop", l_mons_has_prop },
500 { "add_ench", l_mons_add_ench },
501 { "del_ench", l_mons_del_ench },
502 { "you_can_see", l_mons_you_can_see }
505 static int monster_get(lua_State *ls)
507 WRAPPED_MONSTER(ls, mons);
509 const char *attr = luaL_checkstring(ls, 2);
510 if (!attr)
511 return (0);
513 for (unsigned i = 0; i < sizeof(mons_attrs) / sizeof(mons_attrs[0]); ++i)
514 if (!strcmp(attr, mons_attrs[i].attribute))
515 return (mons_attrs[i].accessor(ls, mons, attr));
517 return (0);
520 static const char *_monster_behaviour_names[] = {
521 "sleep",
522 "wander",
523 "seek",
524 "flee",
525 "cornered",
526 "panic",
527 "lurk"
530 static const char* _behaviour_name(beh_type beh)
532 if (0 <= beh && beh < static_cast<int>(ARRAYSZ(_monster_behaviour_names)))
533 return (_monster_behaviour_names[beh]);
534 else
535 return ("invalid");
538 static beh_type behaviour_by_name(const std::string &name)
540 ASSERT(ARRAYSZ(_monster_behaviour_names) == NUM_BEHAVIOURS);
542 for (unsigned i = 0; i < ARRAYSZ(_monster_behaviour_names); ++i)
543 if (name == _monster_behaviour_names[i])
544 return static_cast<beh_type>(i);
546 return NUM_BEHAVIOURS;
549 static int monster_set(lua_State *ls)
551 // Changing monster behaviour is for the dungeon builder only,
552 // never for user scripts.
553 ASSERT_DLUA;
555 MonsterWrap *mw = clua_get_userdata< MonsterWrap >(ls, MONS_METATABLE);
556 if (!mw || !mw->mons)
557 return (0);
559 const char *attr = luaL_checkstring(ls, 2);
560 if (!attr)
561 return (0);
563 if (!strcmp(attr, "beh"))
565 const beh_type beh =
566 lua_isnumber(ls, 3) ? static_cast<beh_type>(luaL_checkint(ls, 3)) :
567 lua_isstring(ls, 3) ? behaviour_by_name(lua_tostring(ls, 3))
568 : NUM_BEHAVIOURS;
570 if (beh != NUM_BEHAVIOURS)
571 mw->mons->behaviour = beh;
573 else if (!strcmp(attr, "targetx"))
574 mw->mons->target.x = luaL_checkint(ls, 3);
575 else if (!strcmp(attr, "targety"))
576 mw->mons->target.y = luaL_checkint(ls, 3);
578 return (0);
581 static int mons_behaviour(lua_State *ls)
583 if (lua_gettop(ls) < 1)
584 return (0);
586 if (lua_isnumber(ls, 1))
588 lua_pushvalue(ls, 1);
589 return (1);
591 else if (lua_isstring(ls, 1))
593 const beh_type beh = behaviour_by_name(lua_tostring(ls, 1));
594 if (beh != NUM_BEHAVIOURS)
596 lua_pushnumber(ls, beh);
597 return (1);
600 return (0);
603 static const struct luaL_reg mons_lib[] =
605 { "behaviour", mons_behaviour },
606 { NULL, NULL }
609 void dluaopen_monsters(lua_State *ls)
611 lua_stack_cleaner stack_clean(ls);
612 luaL_newmetatable(ls, MONS_METATABLE);
613 lua_pushstring(ls, "__index");
614 lua_pushcfunction(ls, monster_get);
615 lua_settable(ls, -3);
617 lua_pushstring(ls, "__newindex");
618 lua_pushcfunction(ls, monster_set);
619 lua_settable(ls, -3);
620 luaL_register(ls, "mons", mons_lib);