13 #include "mon-stuff.h"
15 #define WRAPPED_MONSTER(ls, name) \
16 MonsterWrap *___mw = clua_get_userdata< MonsterWrap >(ls, MONS_METATABLE); \
19 || CLua::get_vm(ls).managed_vm && ___mw->turn != you.num_turns) \
21 luaL_argerror(ls, 1, "Invalid monster wrapper"); \
23 monster *name(___mw->mons)
25 /////////////////////////////////////////////////////////////////////
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
;
36 static int l_mons_##name(lua_State *ls, monster* mons, \
39 #define MDEFN(name, closure) \
40 static int l_mons_##name(lua_State *ls, monster* mons, const char *attrs) \
42 lua_pushlightuserdata(ls, mons); \
43 lua_pushcclosure(ls, l_mons_##closure, 1); \
49 PLUARET(string
, mons
->name(DESC_PLAIN
, true).c_str());
54 PLUARET(boolean
, mons_is_unique(mons
->type
));
59 PLUARET(string
, mons
->base_name(DESC_PLAIN
, true).c_str());
64 PLUARET(string
, mons
->full_name(DESC_PLAIN
, true).c_str());
69 PLUARET(string
, mons
->name(DESC_DBNAME
, true).c_str());
74 PLUARET(string
, mons_type_name(mons
->type
, DESC_PLAIN
).c_str());
81 const monsterentry
*me
= get_monster_data(mons
->type
);
83 lua_pushstring(ls
, me
->name
);
92 PLUARET(number
, int(mons
->pos().x
) - int(you
.pos().x
));
97 PLUARET(number
, int(mons
->pos().y
) - int(you
.pos().y
));
100 static const char* _behaviour_name(beh_type beh
);
103 PLUARET(string
, _behaviour_name(mons
->behaviour
));
108 // XXX: fix this after speed_increment clean up
109 PLUARET(number
, (mons
->speed_increment
- 79))
112 LUAFN(l_mons_add_energy
)
115 monster
* mons
= clua_get_lightuserdata
<monster
>(ls
, lua_upvalueindex(1));
116 mons
->speed_increment
+= luaL_checkint(ls
, 1);
119 MDEFN(add_energy
, add_energy
)
121 #define LUANAMEFN(name, expr) \
122 static int l_mons_##name##_fn(lua_State *ls) { \
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)) \
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))
140 PLUARET(number
, mons
->hit_dice
);
145 PLUARET(number
, mons
->target
.x
);
150 PLUARET(number
, mons
->target
.y
);
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");
168 if (mons_genus(mons
->type
) == MONS_GOLD_MIMIC
)
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;
183 lua_pushstring(ls
, "unknown mimic"); break;
196 if (mons_genus(mons
->type
) == MONS_DANCING_WEAPON
)
197 lua_pushstring(ls
, "dancing weapon");
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
];
217 if (const monsterentry
*me
= mons
->find_monsterentry())
219 PLUARET(string
, _monuse_to_str(me
->gmon_use
));
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
];
237 if (const monsterentry
*me
= mons
->find_monsterentry())
239 PLUARET(string
, _moneat_to_str(me
->gmon_eat
));
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).
249 monster
* mons
= clua_get_lightuserdata
<monster
>(ls
, lua_upvalueindex(1));
253 mons
->flags
|= MF_HARD_RESET
;
254 monster_die(mons
, KILL_DISMISSED
, NON_MONSTER
);
258 MDEFN(dismiss
, do_dismiss
)
260 // Run the monster AI code.
261 static int l_mons_do_run_ai(lua_State
*ls
)
264 monster
* mons
= clua_get_lightuserdata
<monster
>(ls
, lua_upvalueindex(1));
266 handle_monster_move(mons
);
269 MDEFN(run_ai
, do_run_ai
)
271 static int l_mons_do_handle_behaviour(lua_State
*ls
)
274 monster
* mons
= clua_get_lightuserdata
<monster
>(ls
, lua_upvalueindex(1));
276 handle_behaviour(mons
);
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.
286 monster
* mons
= clua_get_lightuserdata
<monster
>(ls
, lua_upvalueindex(1));
289 mons
->teleport(true);
294 MDEFN(random_teleport
, do_random_teleport
)
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.
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
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
;
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());
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.
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());
361 CrawlStoreValue prop
= mons
->props
[prop_name
];
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;
375 lua_pushnumber(ls
, prop
.get_coord().x
);
376 lua_pushnumber(ls
, prop
.get_coord().y
);
379 // Do nothing for some things.
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.
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
));
403 MDEFN(has_prop
, do_has_prop
)
405 static int l_mons_do_add_ench(lua_State
*ls
)
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
);
417 = make_stringf("No such enchantment: %s", ench_name
);
418 luaL_argerror(ls
, 1, err
.c_str());
422 mons
->add_ench(mon_enchant(met
, luaL_checkint(ls
, 2), KC_OTHER
,
423 luaL_checkint(ls
, 3)));
427 MDEFN(add_ench
, do_add_ench
)
429 static int l_mons_do_del_ench(lua_State
*ls
)
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
);
441 = make_stringf("No such enchantment: %s", ench_name
);
442 luaL_argerror(ls
, 1, err
.c_str());
450 MDEFN(del_ench
, do_del_ench
)
455 PLUARET(boolean
, you
.can_see(mons
));
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
},
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);
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
));
520 static const char *_monster_behaviour_names
[] = {
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
]);
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.
555 MonsterWrap
*mw
= clua_get_userdata
< MonsterWrap
>(ls
, MONS_METATABLE
);
556 if (!mw
|| !mw
->mons
)
559 const char *attr
= luaL_checkstring(ls
, 2);
563 if (!strcmp(attr
, "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))
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);
581 static int mons_behaviour(lua_State
*ls
)
583 if (lua_gettop(ls
) < 1)
586 if (lua_isnumber(ls
, 1))
588 lua_pushvalue(ls
, 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
);
603 static const struct luaL_reg mons_lib
[] =
605 { "behaviour", mons_behaviour
},
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
);