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