1 /*** Information about the player.
2  * @module you
3  */
4 #include "AppHdr.h"
5 
6 #include <cmath>
7 
8 #include "l-libs.h"
9 
10 #include "ability.h"
11 #include "abyss.h"
12 #include "areas.h"
13 #include "artefact.h"
14 #include "branch.h"
15 #include "chardump.h"
16 #include "cluautil.h"
17 #include "delay.h"
18 #include "english.h"
19 #include "env.h"
20 #include "initfile.h"
21 #include "item-name.h"
22 #include "item-prop.h"
23 #include "items.h"
24 #include "jobs.h"
25 #include "losglobal.h"
26 #include "mutation.h"
27 #include "nearby-danger.h"
28 #include "newgame-def.h"
29 #include "ng-setup.h"
30 #include "ouch.h"
31 #include "output.h"
32 #include "place.h"
33 #include "player.h"
34 #include "prompt.h"
35 #include "religion.h"
36 #include "shopping.h"
37 #include "skills.h"
38 #include "spl-book.h"
39 #include "spl-transloc.h"
40 #include "spl-util.h"
41 #include "status.h"
42 #include "stringutil.h"
43 #include "tag-version.h"
44 #include "transform.h"
45 #include "traps.h"
46 #include "travel.h"
47 #include "wiz-you.h"
48 
49 //
50 // Bindings to get information on the player (clua).
51 //
52 
53 /*** Has player done something that takes time?
54  * @treturn boolean
55  * @function turn_is_over
56  */
57 LUARET1(you_turn_is_over, boolean, you.turn_is_over)
58 /*** Get player's name.
59  * @treturn string
60  * @function name
61  */
62 LUARET1(you_name, string, you.your_name.c_str())
63 /*** Get name of player's race.
64  * @treturn string
65  * @function race
66  */
67 LUARET1(you_race, string, species::name(you.species).c_str())
68 /*** Get name of player's background.
69  * @treturn string
70  * @function class
71  */
72  LUARET1(you_class, string, get_job_name(you.char_class))
73 /*** Get noun for player's hands.
74  * @treturn string
75  * @function hand
76  */
77  LUARET1(you_hand, string, species::hand_name(you.species).c_str())
78 /*** Is player in wizard mode?
79  * @treturn boolean
80  * @function wizard
81  */
82 LUARET1(you_wizard, boolean, you.wizard)
83 /*** Get name of player's god
84  * @treturn string
85  * @function god
86  */
87 LUARET1(you_god, string, god_name(you.religion).c_str())
88 /*** Is this [player's] god good?
89  * @tparam[opt=you.god()] string god
90  * @treturn boolean
91  * @function good_god
92  */
93 LUARET1(you_good_god, boolean,
94         lua_isstring(ls, 1) ? is_good_god(str_to_god(lua_tostring(ls, 1)))
95         : is_good_god(you.religion))
96 /*** Is this [player's] god evil?
97  * @tparam[opt=you.god()] string god
98  * @treturn boolean
99  * @function evil_god
100  */
101 LUARET1(you_evil_god, boolean,
102         lua_isstring(ls, 1) ? is_evil_god(str_to_god(lua_tostring(ls, 1)))
103         : is_evil_god(you.religion))
104 /*** Has the [player's] current god's one-time ability been used? (if any).
105  * @treturn boolean
106  * @function one_time_ability_used
107  */
108 LUARET1(you_one_time_ability_used, boolean,
109         you.one_time_ability_used[you.religion])
110 /*** Hit points.
111  * @treturn int current hp
112  * @treturn int current max hp
113  * @function hp
114  */
115 LUARET2(you_hp, number, you.hp, you.hp_max)
116 /*** Magic points.
117  * @treturn int current mp
118  * @treturn int current max mp
119  * @function mp
120  */
121 LUARET2(you_mp, number, you.magic_points, you.max_magic_points)
122 /*** Base max mp.
123  * @treturn int
124  * @function base_mp
125  */
LUARET1(you_base_mp,number,get_real_mp (false))126 LUARET1(you_base_mp, number, get_real_mp(false))
127 /*** How much drain.
128  * @treturn int
129  * @function drain
130  */
131 LUARET1(you_drain, number, player_drained())
132 /*** Minimum hp after poison wears off.
133  * @treturn int
134  * @function poison_survival
135  */
136 LUARET1(you_poison_survival, number, poison_survival())
137 /*** Corrosion amount.
138  * @treturn int
139  * @function corrosion
140  */
141 LUARET1(you_corrosion, number, you.props["corrosion_amount"].get_int())
142 /*** Strength.
143  * @treturn int current strength
144  * @treturn int max strength
145  * @function strength
146  */
147 LUARET2(you_strength, number, you.strength(false), you.max_strength())
148 /*** Intelligence.
149  * @treturn int current intelligence
150  * @treturn int max intelligence
151  * @function intelligence
152  */
153 LUARET2(you_intelligence, number, you.intel(false), you.max_intel())
154 /*** Dexterity.
155  * @treturn int current dexterity
156  * @treturn int max dexterity
157  * @function dexterity
158  */
159 LUARET2(you_dexterity, number, you.dex(false), you.max_dex())
160 /*** XL.
161  * @treturn int xl
162  * @tfunction xl
163  */
164 LUARET1(you_xl, number, you.experience_level)
165 /*** XL progress.
166  * @treturn number percentage of the way to the next xl [0,100]
167  * @function xl_progress
168  */
169 LUARET1(you_xl_progress, number, get_exp_progress())
170 
171 /*** Skill progress.
172  * @tparam string name skill name
173  * @treturn number percentage of the way to the next skill level
174  * @function skill_progress
175  */
176 LUAFN(you_skill_progress)
177 {
178     string sk_name = luaL_checkstring(ls, 1);
179     skill_type sk = str_to_skill(lua_tostring(ls, 1));
180     if (sk > NUM_SKILLS)
181     {
182         string err = make_stringf("Unknown skill name `%s`.", sk_name.c_str());
183         return luaL_argerror(ls, 1, err.c_str());
184     }
185     PLUARET(number, get_skill_percentage(str_to_skill(lua_tostring(ls, 1))));
186 }
187 
188 /*** Can a skill be trained?
189  * @tparam string name skill name
190  * @treturn boolean
191  * @function can_train_skill
192  */
LUAFN(you_can_train_skill)193 LUAFN(you_can_train_skill)
194 {
195     string sk_name = luaL_checkstring(ls, 1);
196     skill_type sk = str_to_skill(lua_tostring(ls, 1));
197     if (sk > NUM_SKILLS)
198     {
199         string err = make_stringf("Unknown skill name `%s`.", sk_name.c_str());
200         return luaL_argerror(ls, 1, err.c_str());
201     }
202     PLUARET(boolean, you.can_currently_train[sk]);
203 }
204 
205 /*** Best skill.
206  * @treturn string
207  * @function best_skill
208  */
LUARET1(you_best_skill,string,skill_name (best_skill (SK_FIRST_SKILL,SK_LAST_SKILL)))209 LUARET1(you_best_skill, string,
210         skill_name(best_skill(SK_FIRST_SKILL, SK_LAST_SKILL)))
211 /*** Poison resistance (rPois).
212  * @treturn int resistance level
213  * @function res_poison
214  */
215 LUARET1(you_res_poison, number, player_res_poison(false))
216 /*** Fire resistance (rF).
217  * @treturn int resistance level
218  * @function res_fire
219  */
220 LUARET1(you_res_fire, number, player_res_fire(false))
221 /*** Cold resistance (rC).
222  * @treturn int resistance level
223  * @function res_cold
224  */
225 LUARET1(you_res_cold, number, player_res_cold(false))
226 /*** Negative energy resistance (rN).
227  * @treturn int resistance level
228  * @function res_draining
229  */
230 LUARET1(you_res_draining, number, player_prot_life(false))
231 /*** Electric resistance (rElec).
232  * @treturn int resistance level
233  * @function res_shock
234  */
235 LUARET1(you_res_shock, number, player_res_electricity(false))
236 /*** Stealth pips.
237  * @treturn int number of stealth pips
238  * @function stealth_pips
239  */
240 LUARET1(you_stealth_pips, number, stealth_pips())
241 /*** Willpower (WL).
242  * @treturn int number of WL pips
243  * @function willpower
244  */
245 LUARET1(you_willpower, number, player_willpower(false) / WL_PIP)
246 /*** Drowning resistance (rDrown).
247  * @treturn int resistance level
248  * @function res_drowning
249  */
250 LUARET1(you_res_drowning, boolean, you.res_water_drowning())
251 /*** Mutation resistance (rMut).
252  * @treturn int resistance level
253  * @function res_mutation
254  */
255 LUARET1(you_res_mutation, number, you.rmut_from_item(false) ? 1 : 0)
256 /*** See invisible (sInv).
257  * @treturn boolean
258  * @function see_invisible
259  */
260 LUARET1(you_see_invisible, boolean, you.can_see_invisible(false))
261 /*** Guardian spirit.
262  * Returns a number for backwards compatibility.
263  * @treturn int
264  * @function spirit_shield
265  */
266 LUARET1(you_spirit_shield, number, you.spirit_shield(false) ? 1 : 0)
267 /*** Corrosion resistance (rCorr).
268  * @treturn int resistance level
269  * @function res_corr
270  */
271 LUARET1(you_res_corr, boolean, you.res_corr(false))
272 /*** Are you flying?
273  * @treturn boolean
274  * @function flying
275  */
276 LUARET1(you_flying, boolean, you.airborne())
277 /*** Current transformation, if any.
278  * @treturn string transformation name
279  * @function transform
280  */
281 LUARET1(you_transform, string, you.form == transformation::none
282                                ? "" : transform_name())
283 /*** Are you berserk?
284  * @treturn boolean
285  * @function berserk
286  */
287 LUARET1(you_berserk, boolean, you.berserk())
288 /*** Are you confused?
289  * @treturn boolean
290  * @function confused
291  */
292 LUARET1(you_confused, boolean, you.confused())
293 /*** Are you currently +Swift or -Swift?
294  * If you have neither, returns 0. If you are +Swift, +1, and -Swift, -1.
295  * @treturn int Swift level
296  * @function swift
297  */
298 LUARET1(you_swift, number, you.duration[DUR_SWIFTNESS] ? ((you.attribute[ATTR_SWIFTNESS] >= 0) ? 1 : -1) : 0)
299 /*** What was the loudest noise you heard in the last turn?
300  * Returns a number from [0, 1000], representing the current noise bar.
301  * If the player's coordinates are silenced, return 0.
302  *
303  * Noise bar colour breakpoints, listed here for clua api convenience:
304  * LIGHTGREY <= 333 , YELLOW <= 666 , RED < 1000 , else LIGHTMAGENTA
305  * Each colour breakpoint aims to approximate 1 additional los radius of noise.
306  *
307  * @treturn int noise value
308  * @function noise_perception
309  */
310 LUARET1(you_noise_perception, number, silenced(you.pos())
311                                       ? 0 : you.get_noise_perception(true))
312 /*** Are you paralysed?
313  * @treturn boolean
314  * @function paralysed
315  */
316 LUARET1(you_paralysed, boolean, you.paralysed())
317 /*** Are you asleep?
318  * @treturn boolean
319  * @function asleep
320  */
321 LUARET1(you_asleep, boolean, you.asleep())
322 /*** Are you hasted?
323  * @treturn boolean
324  * @function hasted
325  */
326 LUARET1(you_hasted, boolean, you.duration[DUR_HASTE])
327 /*** Are you slowed?
328  * @treturn boolean
329  * @function slowed
330  */
331 LUARET1(you_slowed, boolean, you.duration[DUR_SLOW])
332 /*** Are you exhausted?
333  * @treturn boolean
334  * @function exhausted
335  */
336 LUARET1(you_exhausted, boolean, you.duration[DUR_EXHAUSTED])
337 /*** Are you teleporting?
338  * @treturn boolean
339  * @function teleporting
340  */
341 LUARET1(you_teleporting, boolean, you.duration[DUR_TELEPORT])
342 /*** Are you dimensionally anchored?
343  * @treturn boolean
344  * @function anchored
345  */
346 LUARET1(you_anchored, boolean, you.duration[DUR_DIMENSION_ANCHOR])
347 /*** Are you rooted?
348  * @treturn boolean
349  * @function rooted
350  */
351 LUARET1(you_rooted, boolean, you.duration[DUR_GRASPING_ROOTS])
352 /*** Are you poisoned?
353  * @treturn boolean
354  * @function poisoned
355  */
356 LUARET1(you_poisoned, boolean, you.duration[DUR_POISONING])
357 /*** Are you invisible?
358  * @treturn boolean
359  * @function invisible
360  */
361 LUARET1(you_invisible, boolean, you.duration[DUR_INVIS])
362 /*** Are you mesmerised?
363  * @treturn boolean
364  * @function mesmerised
365  */
366 LUARET1(you_mesmerised, boolean, you.duration[DUR_MESMERISED])
367 /*** Are you on fire?
368  * @treturn boolean
369  * @function on_fire
370  */
371 LUARET1(you_on_fire, boolean, you.duration[DUR_LIQUID_FLAMES])
372 /*** Are you petrifying?
373  * @treturn boolean
374  * @function petrifying
375  */
376 LUARET1(you_petrifying, boolean, you.duration[DUR_PETRIFYING])
377 /*** Are you silencing the world around you?
378  * @treturn boolean
379  * @function silencing
380  */
381 LUARET1(you_silencing, boolean, you.duration[DUR_SILENCE])
382 /*** Are you regenerating?
383  * @treturn boolean
384  * @function regenerating
385  */
386 LUARET1(you_regenerating, boolean, you.duration[DUR_TROGS_HAND])
387 /*** Are you out of breath?
388  * @treturn boolean
389  * @function breath_timeout
390  */
391 LUARET1(you_breath_timeout, boolean, you.duration[DUR_BREATH_WEAPON])
392 /*** Are you extra resistant?
393  * @treturn boolean
394  * @function extra_resistant
395  */
396 LUARET1(you_extra_resistant, boolean, you.duration[DUR_RESISTANCE])
397 /*** Are you mighty?
398  * @treturn boolean
399  * @function mighty
400  */
401 LUARET1(you_mighty, boolean, you.duration[DUR_MIGHT])
402 /*** Are you agile?
403  * @treturn boolean
404  * @function agile
405  */
406 LUARET1(you_agile, boolean, you.duration[DUR_AGILITY])
407 /*** Are you brilliant?
408  * @treturn boolean
409  * @function brilliant
410  */
411 LUARET1(you_brilliant, boolean, you.duration[DUR_BRILLIANCE])
412 /*** Are you silenced?
413  * @treturn boolean
414  * @function silenced
415  */
416 LUARET1(you_silenced, boolean, silenced(you.pos()))
417 /*** Are you sick?
418  * @treturn boolean
419  * @function sick
420  */
421 LUARET1(you_sick, boolean, you.duration[DUR_SICKNESS])
422 /*** Are you contaminated?
423  * @treturn number
424  * @function contaminated
425  */
426 LUARET1(you_contaminated, number, get_contamination_level())
427 /*** Do you feel safe?
428  * @treturn boolean
429  * @function feel_safe
430  */
431 LUARET1(you_feel_safe, boolean, i_feel_safe())
432 /*** How many times have you died?
433  * @treturn int
434  * @function deaths
435  */
436 LUARET1(you_deaths, number, you.deaths)
437 /*** How many extra lives do you have?
438  * @treturn int
439  * @function lives
440  */
441 LUARET1(you_lives, number, you.lives)
442 
443 /*** Where are you?
444  * @treturn string
445  * @function where
446  */
447 LUARET1(you_where, string, level_id::current().describe().c_str())
448 /*** What branch are you in?
449  * @treturn string
450  * @function branch
451  */
452 LUARET1(you_branch, string, level_id::current().describe(false, false).c_str())
453 /*** Your current depth in that branch.
454  * @treturn int
455  * @function depth
456  */
457 LUARET1(you_depth, number, you.depth)
458 /*** What fraction of the branch you've gone into.
459  * @treturn number
460  * @function depth_fraction
461  */
462 LUARET1(you_depth_fraction, number,
463         (brdepth[you.where_are_you] <= 1) ? 1
464         : ((float)(you.depth - 1) / (brdepth[you.where_are_you] - 1)))
465 /*** The current "absolute depth".
466  * Absolute depth of the current location.
467  * @treturn number
468  * @function absdepth
469  */
470 // [ds] Absolute depth is 1-based for Lua to match things like DEPTH:
471 // which are also 1-based. Yes, this is confusing. FIXME: eventually
472 // change you.absdepth0 to be 1-based as well.
473 // [1KB] FIXME: eventually eliminate the notion of absolute depth at all.
474 LUARET1(you_absdepth, number, env.absdepth0 + 1)
475 /*** How long has the player been on the current level?
476  * @treturn number
477  * @function turns_on_level
478  */
479 LUARET1(you_turns_on_level, number, env.turns_on_level)
480 /*** Interrupt the current multi-turn activity or macro sequence.
481  * @function stop_activity
482  */
483 LUAWRAP(you_stop_activity, interrupt_activity(activity_interrupt::force))
484 /*** Are you taking the stairs?
485  * @treturn boolean
486  * @function taking_stairs
487  */
488 LUARET1(you_taking_stairs, boolean, player_stair_delay())
489 /*** How many turns have been taken.
490  * @treturn int
491  * @function turns
492  */
493 LUARET1(you_turns, number, you.num_turns)
494 /*** Total elapsed time in auts.
495  * @treturn int
496  * @function time
497  */
498 LUARET1(you_time, number, you.elapsed_time)
499 /*** How many spell levels are currently available.
500  * @treturn int
501  * @function spell_levels
502  */
503 LUARET1(you_spell_levels, number, player_spell_levels())
504 /*** Can you smell?
505  * @treturn boolean
506  * @function can_smell
507  */
508 LUARET1(you_can_smell, boolean, you.can_smell())
509 /*** Do you have claws?
510  * @treturn int claws level
511  * @function has_claws
512  */
513 LUARET1(you_has_claws, number, you.has_claws(false))
514 /*** How many temporary mutations do you have?
515  * @treturn int
516  * @function temp_mutations
517  */
518 LUARET1(you_temp_mutations, number, you.attribute[ATTR_TEMP_MUTATIONS])
519 /*** Mutation overview string.
520  * @treturn string
521  * @function mutation_overview
522  */
523 LUARET1(you_mutation_overview, string, terse_mutation_list().c_str())
524 
525 /*** LOS Radius.
526  * @treturn int
527  * @function los
528  */
529 LUARET1(you_los, number, get_los_radius())
530 /*** Can you see a cell?
531  * Uses player-centered coordinates
532  * @tparam int x
533  * @tparam int y
534  * @treturn boolean
535  * @function see_cell
536  */
537 LUARET1(you_see_cell_rel, boolean,
538         you.see_cell(coord_def(luaL_safe_checkint(ls, 1), luaL_safe_checkint(ls, 2)) + you.pos()))
539 /*** Can you see this cell without looking through a window?
540  * Checks line of sight treating transparent rock and stone as opaque.
541  * Uses player-centered coordinates.
542  * @tparam int x
543  * @tparam int y
544  * @treturn boolean
545  * @function see_cell_no_trans
546  */
547 LUARET1(you_see_cell_no_trans_rel, boolean,
548         you.see_cell_no_trans(coord_def(luaL_safe_checkint(ls, 1), luaL_safe_checkint(ls, 2)) + you.pos()))
549 /*** Can you see this cell without something solid in the way?
550  * Checks line of sight treating all solid features as opaque.
551  * Uses player-centered coordinates.
552  * @tparam int x
553  * @tparam int y
554  * @treturn boolean
555  * @function see_cell_solid
556  */
557 LUARET1(you_see_cell_solid_rel, boolean,
558         cell_see_cell(you.pos(),
559                       (coord_def(luaL_safe_checkint(ls, 1),
560                                  luaL_safe_checkint(ls, 2)) + you.pos()),
561                       LOS_SOLID))
562 /*** Can you see this cell with nothing in the way?
563  * Checks line of sight treating all solid features as opaque and properly
564  * checking bushes and clouds.
565  * Uses player-centered coordinates.
566  * @tparam int x
567  * @tparam int y
568  * @treturn boolean
569  * @function see_cell_solid_see
570  */
571 LUARET1(you_see_cell_solid_see_rel, boolean,
572         cell_see_cell(you.pos(),
573                       (coord_def(luaL_safe_checkint(ls, 1),
574                                  luaL_safe_checkint(ls, 2)) + you.pos()),
575                       LOS_SOLID_SEE))
576 /*** Stars of piety.
577  * @treturn int
578  * @function piety_rank
579  */
580 LUARET1(you_piety_rank, number, piety_rank())
581 /*** Are you under penance?
582  * @treturn boolean
583  * @function under_penance
584  */
585 LUARET1(you_under_penance, boolean,
586         lua_isstring(ls, 1) ? player_under_penance(str_to_god(lua_tostring(ls, 1)))
587                             : player_under_penance())
588 /*** Are you currently constricted?
589  * @treturn boolean
590  * @function constricted
591  */
592 LUARET1(you_constricted, boolean, you.is_constricted())
593 /*** Are you currently constricting anything?
594  * @treturn boolean
595  * @function constricting
596  */
597 LUARET1(you_constricting, boolean, you.is_constricting())
598 
599 /*** The name of your monster type.
600  * @treturn string
601  * @function monster
602  */
603 static int l_you_monster(lua_State *ls)
604 {
605     const monster_type mons = you.mons_species();
606 
607     string name = mons_type_name(mons, DESC_PLAIN);
608     lowercase(name);
609 
610     lua_pushstring(ls, name.c_str());
611     return 1;
612 }
613 
614 /*** Your genus.
615  * As a lower-case plural string.
616  * @treturn string
617  * @function genus
618  */
l_you_genus(lua_State * ls)619 static int l_you_genus(lua_State *ls)
620 {
621     bool plural = lua_toboolean(ls, 1);
622     string genus = species::name(you.species, species::SPNAME_GENUS);
623     lowercase(genus);
624     if (plural)
625         genus = pluralise(genus);
626     lua_pushstring(ls, genus.c_str());
627     return 1;
628 }
629 
630 /*** The items on your cell on the floor.
631  * @treturn array an Array of @{items.Item} objects
632  * @function floor_items
633  */
you_floor_items(lua_State * ls)634 static int you_floor_items(lua_State *ls)
635 {
636     lua_push_floor_items(ls, you.visible_igrd(you.pos()));
637     return 1;
638 }
639 
640 /*** List your spells
641  * @treturn array An array of spell names
642  * @see spells
643  * @function spells
644  */
l_you_spells(lua_State * ls)645 static int l_you_spells(lua_State *ls)
646 {
647     lua_newtable(ls);
648     int index = 0;
649     for (int i = 0; i < 52; ++i)
650     {
651         const spell_type spell = get_spell_by_letter(index_to_letter(i));
652         if (spell == SPELL_NO_SPELL)
653             continue;
654 
655         lua_pushstring(ls, spell_title(spell));
656         lua_rawseti(ls, -2, ++index);
657     }
658     return 1;
659 }
660 
661 /*** Currently used spell letters
662  * @treturn array An array of letters
663  * @see spells
664  * @function spell_letters
665  */
l_you_spell_letters(lua_State * ls)666 static int l_you_spell_letters(lua_State *ls)
667 {
668     lua_newtable(ls);
669     int index = 0;
670 
671     char buf[2];
672     buf[1] = 0;
673 
674     for (int i = 0; i < 52; ++i)
675     {
676         buf[0] = index_to_letter(i);
677         const spell_type spell = get_spell_by_letter(buf[0]);
678         if (spell == SPELL_NO_SPELL)
679             continue;
680 
681         lua_pushstring(ls, buf);
682         lua_rawseti(ls, -2, ++index);
683     }
684     return 1;
685 }
686 
687 /*** Get the spell table.
688  * @treturn table A table matching spell letters to spell names
689  * @see spells
690  * @function spell_table
691  */
l_you_spell_table(lua_State * ls)692 static int l_you_spell_table(lua_State *ls)
693 {
694     lua_newtable(ls);
695 
696     char buf[2];
697     buf[1] = 0;
698 
699     for (int i = 0; i < 52; ++i)
700     {
701         buf[0] = index_to_letter(i);
702         const spell_type spell = get_spell_by_letter(buf[0]);
703         if (spell == SPELL_NO_SPELL)
704             continue;
705 
706         lua_pushstring(ls, buf);
707         lua_pushstring(ls, spell_title(spell));
708         lua_rawset(ls, -3);
709     }
710     return 1;
711 }
712 
713 /*** Get memorisable spells.
714  * This lists the spells available in the spell library.
715  * @treturn array An array of spell names.
716  * @function mem_spells
717  */
l_you_mem_spells(lua_State * ls)718 static int l_you_mem_spells(lua_State *ls)
719 {
720     lua_newtable(ls);
721 
722     vector<spell_type> mem_spells = get_sorted_spell_list(true);
723 
724     for (size_t i = 0; i < mem_spells.size(); ++i)
725     {
726         lua_pushstring(ls, spell_title(mem_spells[i]));
727         lua_rawseti(ls, -2, i + 1);
728     }
729     return 1;
730 }
731 
732 /*** Memorise a spell by name
733  * Memorise a spell by name, erroring only on an invalid spell name.
734  * @treturn boolean whether memorisation succeeded
735  * @function memorise
736  */
l_you_memorise(lua_State * ls)737 static int l_you_memorise(lua_State *ls)
738 {
739     string spellname = luaL_checkstring(ls, 1);
740     spell_type s = spell_by_name(spellname, true);
741     if (!is_valid_spell(s))
742     {
743         const string err = make_stringf("Invalid spell: '%s'.", spellname.c_str());
744         return luaL_argerror(ls, 1, err.c_str());
745     }
746     // further error cases printed to messages if this call fails
747     PLUARET(boolean, learn_spell(s, false, false));
748 }
749 
750 /*** Available abilities
751  * @treturn array An array of ability names.
752  * @function abils
753  */
l_you_abils(lua_State * ls)754 static int l_you_abils(lua_State *ls)
755 {
756     lua_newtable(ls);
757 
758     vector<const char *>abils = get_ability_names();
759     for (int i = 0, size = abils.size(); i < size; ++i)
760     {
761         lua_pushstring(ls, abils[i]);
762         lua_rawseti(ls, -2, i + 1);
763     }
764     return 1;
765 }
766 
767 /*** Ability letters in use.
768  * @treturn array An array of ability letters
769  * @function abil_letters
770  */
l_you_abil_letters(lua_State * ls)771 static int l_you_abil_letters(lua_State *ls)
772 {
773     lua_newtable(ls);
774 
775     char buf[2];
776     buf[1] = 0;
777 
778     vector<talent> talents = your_talents(false);
779     for (int i = 0, size = talents.size(); i < size; ++i)
780     {
781         buf[0] = talents[i].hotkey;
782         lua_pushstring(ls, buf);
783         lua_rawseti(ls, -2, i + 1);
784     }
785     return 1;
786 }
787 
788 /*** Ability table.
789  * @treturn table A map of letters to ability names
790  * @function abil_table
791  */
l_you_abil_table(lua_State * ls)792 static int l_you_abil_table(lua_State *ls)
793 {
794     lua_newtable(ls);
795 
796     char buf[2];
797     buf[1] = 0;
798 
799     for (const talent &tal : your_talents(false))
800     {
801         buf[0] = tal.hotkey;
802         lua_pushstring(ls, buf);
803         lua_pushstring(ls, ability_name(tal.which));
804         lua_rawset(ls, -3);
805     }
806     return 1;
807 }
808 
809 
810 /*** Activate an ability by name, supplying a target where relevant. If the
811  * ability is not targeted, the target is ignored. An invalid target will
812  * open interactive targeting.
813  *
814  * @tparam string the name of the ability
815  * @tparam[opt=0] number x coordinate
816  * @tparam[opt=0] number y coordinate
817  * @tparam[opt=false] boolean if true, aim at the target; if false, shoot past it
818  * @treturn boolean whether an action took place
819  * @function activate_ability
820  */
you_activate_ability(lua_State * ls)821 static int you_activate_ability(lua_State *ls)
822 {
823     if (you.turn_is_over)
824         return 0;
825     const string abil_name = luaL_checkstring(ls, 1);
826 
827     ability_type abil = ability_by_name(abil_name);
828     if (abil == ABIL_NON_ABILITY)
829     {
830         luaL_argerror(ls, 1, ("Invalid ability: " + abil_name).c_str());
831         return 0;
832     }
833     PLAYERCOORDS(c, 2, 3);
834     dist target;
835     target.target = c;
836     target.isEndpoint = lua_toboolean(ls, 4); // can be nil
837     quiver::ability_to_action(abil)->trigger(target);
838     PLUARET(boolean, you.turn_is_over);
839 }
840 
841 /*** How much gold do you have?
842  * @treturn int
843  * @function gold
844  */
you_gold(lua_State * ls)845 static int you_gold(lua_State *ls)
846 {
847     if (lua_gettop(ls) >= 1 && !CLua::get_vm(ls).managed_vm)
848     {
849         const int new_gold = luaL_safe_checkint(ls, 1);
850         const int old_gold = you.gold;
851         you.set_gold(max(new_gold, 0));
852         if (new_gold > old_gold)
853             you.attribute[ATTR_GOLD_FOUND] += new_gold - old_gold;
854         else if (old_gold > new_gold)
855             you.attribute[ATTR_MISC_SPENDING] += old_gold - new_gold;
856     }
857     PLUARET(number, you.gold);
858 }
859 
860 /*** Can you eat chunks?
861  * @treturn boolean
862  * @function you_can_consume_corpses
863  */
you_can_consume_corpses(lua_State * ls)864 static int you_can_consume_corpses(lua_State *ls)
865 {
866     lua_pushboolean(ls, false);
867     return 1;
868 }
869 
_you_have_rune(lua_State * ls)870 static int _you_have_rune(lua_State *ls)
871 {
872     int which_rune = NUM_RUNE_TYPES;
873     if (lua_gettop(ls) >= 1 && lua_isnumber(ls, 1))
874         which_rune = luaL_safe_checkint(ls, 1);
875     else if (lua_gettop(ls) >= 1 && lua_isstring(ls, 1))
876     {
877         const char *spec = lua_tostring(ls, 1);
878         for (which_rune = 0; which_rune < NUM_RUNE_TYPES; which_rune++)
879             if (!strcasecmp(spec, rune_type_name(which_rune)))
880                 break;
881     }
882     bool have_rune = false;
883     if (which_rune >= 0 && which_rune < NUM_RUNE_TYPES)
884         have_rune = you.runes[which_rune];
885     lua_pushboolean(ls, have_rune);
886     return 1;
887 }
888 
889 /*** Are you intrinsically immune to this particular hex spell?
890  * @tparam string spell name
891  * @treturn boolean
892  * @function you_immune_to_hex
893  */
you_immune_to_hex(lua_State * ls)894 static int you_immune_to_hex(lua_State *ls)
895 {
896     spell_type spell = spell_by_name(luaL_checkstring(ls, 1), false);
897     lua_pushboolean(ls, you.immune_to_hex(spell));
898     return 1;
899 }
900 
901 /*** How many runes do you have?
902  * @treturn int
903  * @function num_runes
904  */
LUARET1(you_num_runes,number,runes_in_pack ())905 LUARET1(you_num_runes, number, runes_in_pack())
906 
907 /*** Do you have the orb?
908  * @treturn boolean
909  * @function have_orb
910  */
911 LUARET1(you_have_orb, boolean, player_has_orb())
912 
913 /*** Are you caught in something?
914  * @treturn string|nil what's got you
915  * @function caught
916  */
917 LUAFN(you_caught)
918 {
919     if (you.caught())
920         lua_pushstring(ls, held_status(&you));
921     else
922         lua_pushnil(ls);
923 
924     return 1;
925 }
926 
927 /*** Get the mutation level of a mutation.
928  * If all optional parameters are false this returns zero.
929  * @tparam string mutationname
930  * @tparam[opt=true] boolean innate include innate mutations
931  * @tparam[optchain=true] boolean temp include temporary mutations
932  * @tparam[optchain=true] boolean normal include normal mutations
933  * @treturn int level
934  * @function get_base_mutation_level
935  */
LUAFN(you_get_base_mutation_level)936 LUAFN(you_get_base_mutation_level)
937 {
938     string mutname = luaL_checkstring(ls, 1);
939     bool innate = true;
940     bool temp = true;
941     bool normal = true;
942     if (!lua_isnoneornil(ls, 2))
943         innate = lua_toboolean(ls, 2);
944     if (!lua_isnoneornil(ls, 3))
945         temp = lua_toboolean(ls, 3);
946     if (!lua_isnoneornil(ls, 4))
947         normal = lua_toboolean(ls, 4);
948     mutation_type mut = mutation_from_name(mutname, false);
949     if (mut != NUM_MUTATIONS)
950         PLUARET(integer, you.get_base_mutation_level(mut, innate, temp, normal)); // includes innate mutations
951 
952     string err = make_stringf("No such mutation: '%s'.", mutname.c_str());
953     return luaL_argerror(ls, 1, err.c_str());
954 }
955 
956 /*** How mutated are you?
957  * Adds up the total number (including levels if requested) of mutations.
958  * @tparam boolean innate include innate mutations
959  * @tparam boolean levels count levels
960  * @tparam boolean temp include temporary mutations
961  * @treturn int
962  * @function how_mutated
963  */
LUAFN(you_how_mutated)964 LUAFN(you_how_mutated)
965 {
966     bool innate = lua_toboolean(ls, 1); // whether to include innate mutations
967     bool levels = lua_toboolean(ls, 2); // whether to count levels
968     bool temp = lua_toboolean(ls, 3); // whether to include temporary mutations
969     int result = you.how_mutated(innate, levels, temp);
970     PLUARET(number, result);
971 }
972 
973 /*** Deprecated: use @{you.get_base_mutation_level}.
974  * Equivalent to `you.get_base_mutation_level(name)`
975  * @tparam string mutation name
976  * @treturn int num
977  * @function mutation
978  */
LUAFN(you_mutation)979 LUAFN(you_mutation)
980 {
981     string mutname = luaL_checkstring(ls, 1);
982     mutation_type mut = mutation_from_name(mutname, false);
983     if (mut != NUM_MUTATIONS)
984         PLUARET(integer, you.get_base_mutation_level(mut, true, true, true)); // includes innate, temp mutations. I'm not sure if this is what was intended but this was the old behaviour.
985 
986     string err = make_stringf("No such mutation: '%s'.", mutname.c_str());
987     return luaL_argerror(ls, 1, err.c_str());
988 }
989 
990 
991 /*** Deprecated: use @{you.get_base_mutation_level}.
992  * Equivalent to `you.get_base_mutation_level(name, false, true, false)`
993  * @tparam string mutation name
994  * @treturn int num
995  * @function temp_mutation
996  */
LUAFN(you_temp_mutation)997 LUAFN(you_temp_mutation)
998 {
999     string mutname = luaL_checkstring(ls, 1);
1000     mutation_type mut = mutation_from_name(mutname, false);
1001     if (mut != NUM_MUTATIONS)
1002         PLUARET(integer, you.get_base_mutation_level(mut, false, true, false));
1003 
1004     string err = make_stringf("No such mutation: '%s'.", mutname.c_str());
1005     return luaL_argerror(ls, 1, err.c_str());
1006 }
1007 
1008 /*** Check the level stack.
1009  * When entering portal branches or the abyss crawl tracks
1010  * where we came from with a level stack, which we can query.
1011  * Can take a Branch or Branch:depth string.
1012  * @tparam string levelname
1013  * @treturn boolean
1014  * @function is_level_on_stack
1015  */
LUAFN(you_is_level_on_stack)1016 LUAFN(you_is_level_on_stack)
1017 {
1018     string levname = luaL_checkstring(ls, 1);
1019     level_id lev;
1020     try
1021     {
1022         lev = level_id::parse_level_id(levname);
1023     }
1024     catch (const bad_level_id &err)
1025     {
1026         return luaL_argerror(ls, 1, err.what());
1027     }
1028 
1029     PLUARET(boolean, is_level_on_stack(lev));
1030 }
1031 
1032 /*** Current skill level.
1033  * @tparam string name
1034  * @treturn number
1035  * @function skill
1036  */
LUAFN(you_skill)1037 LUAFN(you_skill)
1038 {
1039     skill_type sk = str_to_skill_safe(luaL_checkstring(ls, 1));
1040 
1041     PLUARET(number, you.skill(sk, 10) * 0.1);
1042 }
1043 
1044 /*** Base skill level.
1045  * Ignores drain, crosstraining, &c.
1046  * @tparam string name
1047  * @function base_skill
1048  */
LUAFN(you_base_skill)1049 LUAFN(you_base_skill)
1050 {
1051     skill_type sk = str_to_skill_safe(luaL_checkstring(ls, 1));
1052 
1053     PLUARET(number, you.skill(sk, 10, true) * 0.1);
1054 }
1055 
1056 /*** Train a skill.
1057  * Training levels:
1058  *
1059  * - 0 is disable
1060  * - 1 is enable
1061  * - 2 is focus
1062  *
1063  * If no level is passed, does not change the current training.
1064  * @tparam string name
1065  * @tparam[opt] int level set training level
1066  * @treturn int training level
1067  * @function train_skill
1068  */
LUAFN(you_train_skill)1069 LUAFN(you_train_skill)
1070 {
1071     skill_type sk = str_to_skill_safe(luaL_checkstring(ls, 1));
1072     if (lua_gettop(ls) >= 2 && can_enable_skill(sk))
1073     {
1074         you.train[sk] = min(max((training_status)luaL_safe_checkint(ls, 2),
1075                                                  TRAINING_DISABLED),
1076                                              TRAINING_FOCUSED);
1077         reset_training();
1078     }
1079 
1080     PLUARET(number, you.train[sk]);
1081 }
1082 
1083 /*** Get a training target.
1084  * @tparam string name
1085  * @treturn number
1086  * @function get_training_target
1087  */
LUAFN(you_get_training_target)1088 LUAFN(you_get_training_target)
1089 {
1090     string sk_name = luaL_checkstring(ls, 1);
1091     skill_type sk = str_to_skill(sk_name);
1092     if (sk == SK_NONE)
1093     {
1094         string err = make_stringf("Unknown skill name `%s`", sk_name.c_str());
1095         return luaL_argerror(ls, 1, err.c_str());
1096     }
1097 
1098     PLUARET(number, (double) you.get_training_target(sk) * 0.1);
1099 }
1100 
1101 /*** Set a training target.
1102  * @tparam string name
1103  * @tparam number target
1104  * @treturn number|nil if successfully set the new target
1105  * @function set_training_target
1106  */
LUAFN(you_set_training_target)1107 LUAFN(you_set_training_target)
1108 {
1109     string sk_name = luaL_checkstring(ls, 1);
1110     skill_type sk = str_to_skill(sk_name);
1111     if (sk == SK_NONE)
1112     {
1113         string err = make_stringf("Unknown skill name `%s`", sk_name.c_str());
1114         return luaL_argerror(ls, 1, err.c_str());
1115     }
1116     else if (!you.set_training_target(sk, luaL_checknumber(ls, 2), true))
1117         return 0; // not a full-on error
1118     return 1;
1119 }
1120 
1121 /*** Cost of training this skill.
1122  * @tparam string name
1123  * @treturn number
1124  * @function skill_cost
1125  */
LUAFN(you_skill_cost)1126 LUAFN(you_skill_cost)
1127 {
1128     skill_type sk = str_to_skill_safe(luaL_checkstring(ls, 1));
1129     float cost = scaled_skill_cost(sk);
1130     if (cost == 0)
1131     {
1132         lua_pushnil(ls);
1133         return 1;
1134     }
1135     PLUARET(number, max(1, (int)(10.0 * cost + 0.5)) * 0.1);
1136 }
1137 
1138 /*** Check status effects.
1139  * Given a specific status name, checks for that status.
1140  * Otherwise, lists all statuses.
1141  * @tparam[opt] string stat
1142  * @treturn string|boolean
1143  * @function status
1144  */
LUAFN(you_status)1145 LUAFN(you_status)
1146 {
1147     const char* which = nullptr;
1148     if (lua_gettop(ls) >= 1)
1149         which = luaL_checkstring(ls, 1);
1150 
1151     string status_effects = "";
1152     status_info inf;
1153     for (unsigned i = 0; i <= STATUS_LAST_STATUS; ++i)
1154     {
1155         if (fill_status_info(i, inf) && !inf.short_text.empty())
1156         {
1157             if (which)
1158             {
1159                 if (inf.short_text == which)
1160                     PLUARET(boolean, true);
1161             }
1162             else
1163             {
1164                 if (!status_effects.empty())
1165                     status_effects += ",";
1166                 status_effects += inf.short_text;
1167             }
1168         }
1169     }
1170     if (which)
1171         PLUARET(boolean, false);
1172     PLUARET(string, status_effects.c_str());
1173 }
1174 
LUAFN(you_quiver_valid)1175 LUAFN(you_quiver_valid)
1176 {
1177     // 0 = launcher quiver
1178     // 1 = regular quiver
1179     // this order is slightly weird but is aimed at forward compatibility
1180     const int q_num = luaL_safe_checkint(ls, 1);
1181     auto &q = q_num == 0 ? you.launcher_action : you.quiver_action;
1182     PLUARET(boolean, !q.is_empty() && q.get()->is_valid());
1183 }
1184 
LUAFN(you_quiver_enabled)1185 LUAFN(you_quiver_enabled)
1186 {
1187     // 0 = launcher quiver
1188     // 1 = regular quiver
1189     const int q_num = luaL_safe_checkint(ls, 1);
1190     auto &q = q_num == 0 ? you.launcher_action : you.quiver_action;
1191     PLUARET(boolean, !q.is_empty() && q.get()->is_enabled());
1192 }
1193 
LUAFN(you_quiver_uses_mp)1194 LUAFN(you_quiver_uses_mp)
1195 {
1196     // ignore launcher quiver here
1197     PLUARET(boolean, quiver::get_secondary_action()->uses_mp());
1198 }
1199 
LUAFN(you_quiver_allows_autofight)1200 LUAFN(you_quiver_allows_autofight)
1201 {
1202     // don't bother with launcher quiver
1203     PLUARET(boolean, quiver::get_secondary_action()->allow_autofight());
1204 }
1205 
1206 static const struct luaL_reg you_clib[] =
1207 {
1208     { "turn_is_over", you_turn_is_over },
1209     { "turns"       , you_turns },
1210     { "time"        , you_time },
1211     { "spells"      , l_you_spells },
1212     { "spell_letters", l_you_spell_letters },
1213     { "spell_table" , l_you_spell_table },
1214     { "spell_levels", you_spell_levels },
1215     { "mem_spells",   l_you_mem_spells },
1216     { "memorise",     l_you_memorise },
1217     { "abilities"   , l_you_abils },
1218     { "ability_letters", l_you_abil_letters },
1219     { "ability_table", l_you_abil_table },
1220     { "name"        , you_name },
1221     { "race"        , you_race },
1222     { "hand"        , you_hand },
1223     { "class"       , you_class },
1224     { "genus"       , l_you_genus },
1225     { "monster"     , l_you_monster },
1226     { "wizard"      , you_wizard },
1227     { "god"         , you_god },
1228     { "gold"        , you_gold },
1229     { "good_god"    , you_good_god },
1230     { "evil_god"    , you_evil_god },
1231     { "one_time_ability_used" , you_one_time_ability_used },
1232     { "hp"          , you_hp },
1233     { "mp"          , you_mp },
1234     { "base_mp"     , you_base_mp },
1235     { "drain"       , you_drain },
1236     { "strength"    , you_strength },
1237     { "intelligence", you_intelligence },
1238     { "dexterity"   , you_dexterity },
1239     { "skill"       , you_skill },
1240     { "base_skill"  , you_base_skill },
1241     { "skill_progress", you_skill_progress },
1242     { "can_train_skill", you_can_train_skill },
1243     { "best_skill",   you_best_skill },
1244     { "train_skill",  you_train_skill },
1245     { "skill_cost"  , you_skill_cost },
1246     { "get_training_target", you_get_training_target },
1247     { "set_training_target", you_set_training_target },
1248     { "xl"          , you_xl },
1249     { "xl_progress" , you_xl_progress },
1250     { "res_poison"  , you_res_poison },
1251     { "res_fire"    , you_res_fire   },
1252     { "res_cold"    , you_res_cold   },
1253     { "res_draining", you_res_draining },
1254     { "res_shock"   , you_res_shock },
1255     { "stealth_pips", you_stealth_pips },
1256     { "willpower"   , you_willpower },
1257     { "res_drowning", you_res_drowning },
1258     { "res_mutation", you_res_mutation },
1259     { "see_invisible", you_see_invisible },
1260     { "spirit_shield", you_spirit_shield },
1261     { "res_corr",     you_res_corr },
1262     { "flying",       you_flying },
1263     { "transform",    you_transform },
1264     { "berserk",      you_berserk },
1265     { "confused",     you_confused },
1266     { "noise_perception", you_noise_perception },
1267     { "paralysed",    you_paralysed },
1268     { "swift",        you_swift },
1269     { "caught",       you_caught },
1270     { "asleep",       you_asleep },
1271     { "hasted",       you_hasted },
1272     { "slowed",       you_slowed },
1273     { "exhausted",    you_exhausted },
1274     { "teleporting",  you_teleporting },
1275     { "anchored",     you_anchored },
1276     { "rooted",       you_rooted },
1277     { "poisoned",     you_poisoned },
1278     { "poison_survival", you_poison_survival },
1279     { "corrosion",    you_corrosion },
1280     { "invisible",    you_invisible },
1281     { "mesmerised",   you_mesmerised },
1282     { "on_fire",      you_on_fire },
1283     { "petrifying",   you_petrifying },
1284     { "silencing",    you_silencing },
1285     { "regenerating", you_regenerating },
1286     { "breath_timeout", you_breath_timeout },
1287     { "extra_resistant", you_extra_resistant },
1288     { "mighty",       you_mighty },
1289     { "agile",        you_agile },
1290     { "brilliant",    you_brilliant },
1291     { "silenced",     you_silenced },
1292     { "sick",         you_sick },
1293     { "contaminated", you_contaminated },
1294     { "feel_safe",    you_feel_safe },
1295     { "deaths",       you_deaths },
1296     { "lives",        you_lives },
1297     { "piety_rank",   you_piety_rank },
1298     { "under_penance", you_under_penance },
1299     { "constricted",  you_constricted },
1300     { "constricting", you_constricting },
1301     { "status",       you_status },
1302     { "immune_to_hex", you_immune_to_hex },
1303 
1304     { "can_consume_corpses",      you_can_consume_corpses },
1305 
1306     { "stop_activity", you_stop_activity },
1307     { "taking_stairs", you_taking_stairs },
1308 
1309     { "floor_items",  you_floor_items },
1310 
1311     { "where",        you_where },
1312     { "branch",       you_branch },
1313     { "depth",        you_depth },
1314     { "depth_fraction", you_depth_fraction },
1315     { "absdepth",     you_absdepth },
1316     { "turns_on_level", you_turns_on_level },
1317     { "is_level_on_stack", you_is_level_on_stack },
1318 
1319     { "can_smell",         you_can_smell },
1320     { "has_claws",         you_has_claws },
1321 
1322     { "los",               you_los },
1323     { "see_cell",          you_see_cell_rel },
1324     { "see_cell_no_trans", you_see_cell_no_trans_rel },
1325     { "see_cell_solid",    you_see_cell_solid_rel },
1326     { "see_cell_solid_see",you_see_cell_solid_see_rel },
1327 
1328     { "get_base_mutation_level", you_get_base_mutation_level },
1329     { "mutation",                you_mutation }, // still here for compatibility
1330     { "temp_mutation",           you_temp_mutation }, // still here for compatibility
1331     { "how_mutated",             you_how_mutated },
1332     { "temp_mutations",          you_temp_mutations },
1333     { "mutation_overview",       you_mutation_overview},
1334 
1335     { "num_runes",          you_num_runes },
1336     { "have_rune",          _you_have_rune },
1337     { "have_orb",           you_have_orb},
1338     { "quiver_valid",       you_quiver_valid},
1339     { "quiver_enabled",     you_quiver_enabled},
1340     { "quiver_uses_mp",     you_quiver_uses_mp},
1341     { "quiver_allows_autofight", you_quiver_allows_autofight },
1342     { "activate_ability",        you_activate_ability},
1343 
1344     { nullptr, nullptr },
1345 };
1346 
cluaopen_you(lua_State * ls)1347 void cluaopen_you(lua_State *ls)
1348 {
1349     luaL_openlib(ls, "you", you_clib, 0);
1350 }
1351 
1352 //
1353 // Player information (dlua). Grid coordinates etc.
1354 //
1355 
1356 LUARET1(you_can_hear_pos, boolean,
1357         player_can_hear(coord_def(luaL_safe_checkint(ls,1), luaL_safe_checkint(ls, 2))))
1358 LUARET1(you_x_pos, number, you.pos().x)
1359 LUARET1(you_y_pos, number, you.pos().y)
1360 LUARET2(you_pos, number, you.pos().x, you.pos().y)
1361 
1362 LUARET1(you_see_cell, boolean,
1363         you.see_cell(coord_def(luaL_safe_checkint(ls, 1), luaL_safe_checkint(ls, 2))))
1364 LUARET1(you_see_cell_no_trans, boolean,
1365         you.see_cell_no_trans(coord_def(luaL_safe_checkint(ls, 1), luaL_safe_checkint(ls, 2))))
1366 
LUAWRAP(you_stop_running,stop_running ())1367 LUAWRAP(you_stop_running, stop_running())
1368 
1369 LUAFN(you_moveto)
1370 {
1371     const coord_def place(luaL_safe_checkint(ls, 1), luaL_safe_checkint(ls, 2));
1372     ASSERT(map_bounds(place));
1373     you.moveto(place);
1374     return 0;
1375 }
1376 
LUAFN(you_teleport_to)1377 LUAFN(you_teleport_to)
1378 {
1379     const coord_def place(luaL_safe_checkint(ls, 1), luaL_safe_checkint(ls, 2));
1380     bool move_monsters = false;
1381     if (lua_gettop(ls) == 3)
1382         move_monsters = lua_toboolean(ls, 3);
1383 
1384     lua_pushboolean(ls, you_teleport_to(place, move_monsters));
1385     if (player_in_branch(BRANCH_ABYSS))
1386         maybe_shift_abyss_around_player();
1387 
1388     return 1;
1389 }
1390 
LUAWRAP(you_random_teleport,you_teleport_now ())1391 LUAWRAP(you_random_teleport, you_teleport_now())
1392 
1393 static int _you_uniques(lua_State *ls)
1394 {
1395     bool unique_found = false;
1396 
1397     if (lua_gettop(ls) >= 1 && lua_isstring(ls, 1))
1398     {
1399         unique_found =
1400             you.unique_creatures[get_monster_by_name(lua_tostring(ls, 1))];
1401     }
1402 
1403     lua_pushboolean(ls, unique_found);
1404     return 1;
1405 }
1406 
_you_unrands(lua_State * ls)1407 static int _you_unrands(lua_State *ls)
1408 {
1409     bool unrand_found = false;
1410 
1411     if (lua_gettop(ls) >= 1 && lua_isstring(ls, 1))
1412     {
1413         int unrand_num = get_unrandart_num(lua_tostring(ls, 1));
1414         if (unrand_num != SPWPN_NORMAL)
1415             unrand_found = get_unique_item_status(unrand_num);
1416     }
1417 
1418     lua_pushboolean(ls, unrand_found);
1419     return 1;
1420 }
1421 
LUAWRAP(_you_die,ouch (INSTANT_DEATH,KILLED_BY_SOMETHING))1422 LUAWRAP(_you_die,ouch(INSTANT_DEATH, KILLED_BY_SOMETHING))
1423 
1424 static int _you_piety(lua_State *ls)
1425 {
1426     if (lua_gettop(ls) >= 1)
1427     {
1428         const int new_piety = min(max(luaL_safe_checkint(ls, 1), 0), MAX_PIETY);
1429         set_piety(new_piety);
1430     }
1431     PLUARET(number, you.piety);
1432 }
1433 
you_dock_piety(lua_State * ls)1434 static int you_dock_piety(lua_State *ls)
1435 {
1436     const int piety_loss = luaL_safe_checkint(ls, 1);
1437     const int penance = luaL_safe_checkint(ls, 2);
1438     dock_piety(piety_loss, penance);
1439     return 0;
1440 }
1441 
you_lose_piety(lua_State * ls)1442 static int you_lose_piety(lua_State *ls)
1443 {
1444     const int piety_loss = luaL_safe_checkint(ls, 1);
1445     lose_piety(piety_loss);
1446     return 0;
1447 }
1448 
LUAFN(you_in_branch)1449 LUAFN(you_in_branch)
1450 {
1451     const char* name = luaL_checkstring(ls, 1);
1452 
1453     int br = NUM_BRANCHES;
1454 
1455     for (branch_iterator it; it; ++it)
1456     {
1457         if (strcasecmp(name, it->shortname) == 0
1458             || strcasecmp(name, it->longname) == 0
1459             || strcasecmp(name, it->abbrevname) == 0)
1460         {
1461             if (br != NUM_BRANCHES)
1462             {
1463                 string err = make_stringf(
1464                     "'%s' matches both branch '%s' and '%s'",
1465                     name, branches[br].abbrevname,
1466                     it->abbrevname);
1467                 return luaL_argerror(ls, 1, err.c_str());
1468             }
1469             br = it->id;
1470         }
1471     }
1472 
1473     if (br == NUM_BRANCHES)
1474     {
1475         string err = make_stringf("'%s' matches no branches.", name);
1476         return luaL_argerror(ls, 1, err.c_str());
1477     }
1478 
1479     bool in_branch = (br == you.where_are_you);
1480     PLUARET(boolean, in_branch);
1481 }
1482 
LUAFN(_you_at_branch_bottom)1483 LUAFN(_you_at_branch_bottom)
1484 {
1485     PLUARET(boolean, at_branch_bottom());
1486 }
1487 
1488 LUAWRAP(you_gain_exp, gain_exp(luaL_safe_checkint(ls, 1)))
1489 
LUAFN(you_mutate)1490 LUAFN(you_mutate)
1491 {
1492     string mutname = luaL_checkstring(ls, 1);
1493     string reason = luaL_checkstring(ls, 2);
1494     bool temp = false;
1495     bool force = true;
1496     if (!lua_isnoneornil(ls, 3))
1497         temp = lua_toboolean(ls, 3);
1498     if (!lua_isnoneornil(ls, 4))
1499         force = lua_toboolean(ls, 4);
1500     const mutation_permanence_class mutclass = temp ? MUTCLASS_TEMPORARY : MUTCLASS_NORMAL;
1501     mutation_type mut = mutation_from_name(mutname, true); // requires exact match
1502     if (mut != NUM_MUTATIONS)
1503         PLUARET(boolean, mutate(mut, reason, true, force, false, false, mutclass));
1504 
1505     string err = make_stringf("No such mutation: '%s'.", mutname.c_str());
1506     return luaL_argerror(ls, 1, err.c_str());
1507 }
1508 
LUAFN(you_delete_mutation)1509 LUAFN(you_delete_mutation)
1510 {
1511     string mutname = luaL_checkstring(ls, 1);
1512     string reason = luaL_checkstring(ls, 2);
1513     mutation_type mut = mutation_from_name(mutname, true); // requires exact match
1514     if (mut != NUM_MUTATIONS)
1515         PLUARET(boolean, delete_mutation(mut, reason, false));
1516 
1517     string err = make_stringf("No such mutation: '%s'.", mutname.c_str());
1518     return luaL_argerror(ls, 1, err.c_str());
1519 }
1520 
1521 
1522 // clear one or all temporary mutations.
LUAFN(you_delete_temp_mutations)1523 LUAFN(you_delete_temp_mutations)
1524 {
1525     bool result;
1526     bool clear_all = lua_toboolean(ls, 1);
1527     string reason = luaL_checkstring(ls, 2);
1528     if (clear_all)
1529         result = delete_all_temp_mutations(reason);
1530     else
1531         result = temp_mutation_wanes();
1532     PLUARET(boolean, result);
1533 }
1534 
1535 // clear one or all temporary mutations.
LUAFN(you_delete_all_mutations)1536 LUAFN(you_delete_all_mutations)
1537 {
1538     bool result;
1539     string reason = luaL_checkstring(ls, 1);
1540     result = delete_all_mutations(reason);
1541     PLUARET(boolean, result);
1542 }
1543 
LUAFN(you_change_species)1544 LUAFN(you_change_species)
1545 {
1546     string species = luaL_checkstring(ls, 1);
1547     const species_type sp = species::from_str_loose(species);
1548 
1549     if (sp == SP_UNKNOWN)
1550     {
1551         mpr("That species isn't available.");
1552         PLUARET(boolean, false);
1553     }
1554 
1555     change_species_to(sp);
1556     PLUARET(boolean, true);
1557 }
1558 
1559 #ifdef WIZARD
LUAFN(you_set_xl)1560 LUAFN(you_set_xl)
1561 {
1562     const int newxl = luaL_safe_checkint(ls, 1);
1563     bool train = lua_toboolean(ls, 2); // whether to train skills
1564     if (newxl < 1 || newxl > you.get_max_xl())
1565     {
1566         mprf("Can't change to invalid xl %d", newxl);
1567         PLUARET(boolean, false);
1568     }
1569     if (newxl == you.experience_level)
1570         PLUARET(boolean, true);
1571     set_xl(newxl, train, newxl < you.experience_level); // most useful for testing if it's not silent on levelup
1572     PLUARET(boolean, true);
1573 }
1574 #endif
1575 
1576 /*
1577  * Init the player class.
1578  *
1579  * @param combo a string with the species and background abbreviations to use.
1580  * @param weapon optional string with the weapon to give.
1581  * @return a string with the weapon skill name.
1582  */
LUAFN(you_init)1583 LUAFN(you_init)
1584 {
1585     const string combo = luaL_checkstring(ls, 1);
1586     newgame_def ng;
1587     ng.type = GAME_TYPE_NORMAL;
1588     ng.species = species::from_abbrev(combo.substr(0, 2).c_str());
1589     ng.job = get_job_by_abbrev(combo.substr(2, 2).c_str());
1590     ng.weapon = str_to_weapon(luaL_checkstring(ls, 2));
1591     setup_game(ng);
1592     you.save->unlink();
1593     you.save = nullptr;
1594     PLUARET(string, skill_name(item_attack_skill(OBJ_WEAPONS, ng.weapon)));
1595 }
1596 
1597 LUAWRAP(you_enter_wizard_mode, you.wizard = true)
1598 
1599 LUARET1(you_exp_needed, number, exp_needed(luaL_safe_checkint(ls, 1)))
1600 LUAWRAP(you_exercise, exercise(str_to_skill(luaL_checkstring(ls, 1)), 1))
1601 LUARET1(you_skill_cost_level, number, you.skill_cost_level)
1602 LUARET1(you_skill_points, number,
1603         you.skill_points[str_to_skill(luaL_checkstring(ls, 1))])
1604 LUARET1(you_zigs_completed, number, you.zigs_completed)
1605 
1606 static const struct luaL_reg you_dlib[] =
1607 {
1608 { "hear_pos",           you_can_hear_pos },
1609 { "silenced",           you_silenced },
1610 { "x_pos",              you_x_pos },
1611 { "y_pos",              you_y_pos },
1612 { "pos",                you_pos },
1613 { "moveto",             you_moveto },
1614 { "see_cell",           you_see_cell },
1615 { "see_cell_no_trans",  you_see_cell_no_trans },
1616 { "random_teleport",    you_random_teleport },
1617 { "teleport_to",        you_teleport_to },
1618 { "uniques",            _you_uniques },
1619 { "unrands",            _you_unrands },
1620 { "die",                _you_die },
1621 { "piety",              _you_piety },
1622 { "dock_piety",         you_dock_piety },
1623 { "lose_piety",         you_lose_piety },
1624 { "in_branch",          you_in_branch },
1625 { "stop_running",       you_stop_running },
1626 { "at_branch_bottom",   _you_at_branch_bottom },
1627 { "gain_exp",           you_gain_exp },
1628 { "init",               you_init },
1629 { "exp_needed",         you_exp_needed },
1630 { "exercise",           you_exercise },
1631 { "skill_cost_level",   you_skill_cost_level },
1632 { "skill_points",       you_skill_points },
1633 { "zigs_completed",     you_zigs_completed },
1634 { "mutate",             you_mutate },
1635 { "delete_mutation",    you_delete_mutation },
1636 { "delete_temp_mutations", you_delete_temp_mutations },
1637 { "delete_all_mutations", you_delete_all_mutations },
1638 { "change_species",     you_change_species },
1639 #ifdef WIZARD
1640 { "enter_wizard_mode",  you_enter_wizard_mode },
1641 { "set_xl",             you_set_xl },
1642 #endif
1643 
1644 { nullptr, nullptr }
1645 };
1646 
dluaopen_you(lua_State * ls)1647 void dluaopen_you(lua_State *ls)
1648 {
1649     luaL_openlib(ls, "you", you_dlib, 0);
1650 }
1651