1 /**
2  * @file
3  * @brief Game state functions.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "state.h"
9 
10 #if defined(UNIX) || defined(TARGET_COMPILER_MINGW)
11 #include <unistd.h>
12 #endif
13 
14 #include "dbg-util.h"
15 #include "delay.h"
16 #include "directn.h"
17 #include "hints.h"
18 #include "macro.h"
19 #include "menu.h"
20 #include "message.h"
21 #include "monster.h"
22 #include "player.h"
23 #include "religion.h"
24 #include "showsymb.h"
25 #include "unwind.h"
26 
game_state()27 game_state::game_state()
28     : game_crashed(false), crash_debug_scans_safe(true),
29       mouse_enabled(false), waiting_for_command(false),
30       terminal_resized(false), last_winch(0),
31       seed(0),
32       io_inited(false),
33       need_save(false), game_started(false), saving_game(false),
34       updating_scores(false),
35 #ifndef USE_TILE_LOCAL
36       smallterm(false),
37 #endif
38       seen_hups(0), map_stat_gen(false), map_stat_dump_disconnect(false),
39       obj_stat_gen(false), type(GAME_TYPE_NORMAL),
40       last_type(GAME_TYPE_UNSPECIFIED), last_game_exit(game_exit::unknown),
41       marked_as_won(false), arena_suspended(false),
42       generating_level(false), dump_maps(false), test(false), script(false),
43       build_db(false), tests_selected(),
44 #ifdef DGAMELAUNCH
45       throttle(true),
46       bypassed_startup_menu(true),
47 #else
48       throttle(false),
49       bypassed_startup_menu(false),
50 #endif
51       show_more_prompt(true), terminal_resize_handler(nullptr),
52       terminal_resize_check(nullptr), doing_prev_cmd_again(false),
53       prev_cmd(CMD_NO_CMD), repeat_cmd(CMD_NO_CMD),
54       cmd_repeat_started_unsafe(false), lua_calls_no_turn(0),
55       stat_gain_prompt(false), simulating_xp_gain(false),
56       level_annotation_shown(false),
57       viewport_monster_hp(false), viewport_weapons(false),
58       tiles_disabled(false),
59       title_screen(true),
60       invisible_targeting(false),
61       darken_range(nullptr), unsaved_macros(false), disables(),
62       minor_version(-1), save_rcs_version(),
63       nonempty_buffer_flush_errors(false),
64       last_builder_error_fatal(false),
65       mon_act(nullptr)
66 {
67     reset_cmd_repeat();
68     reset_cmd_again();
69 #ifndef UNIX
70     no_gdb = "Non-UNIX Platform -> not running gdb.";
71 #else
72     no_gdb = access(GDB_PATH, 1) ? "gdb not executable." : 0;
73 #endif
74 }
75 
76 /**
77  * Cleanup for when the game is reset.
78  *
79  * @see main.cc:_reset_game()
80  */
reset_game()81 void game_state::reset_game()
82 {
83     game_started = false;
84     // need_save is unset by death, but not by saving with restart_after_save.
85     need_save = false;
86     type = GAME_TYPE_UNSPECIFIED;
87     updating_scores = false;
88     clear_mon_acting();
89     reset_cmd_repeat();
90     reset_cmd_again();
91 }
92 
93 ///////////////////////////////////////////////////////////////////////////
94 // Repeating commands and doing the previous command over again.
95 
is_replaying_keys() const96 bool game_state::is_replaying_keys() const
97 {
98     return crawl_state.doing_prev_cmd_again
99            || crawl_state.is_repeating_cmd();
100 }
101 
is_repeating_cmd() const102 bool game_state::is_repeating_cmd() const
103 {
104     return repeat_cmd != CMD_NO_CMD;
105 }
106 
cancel_cmd_repeat(string reason,bool force)107 void game_state::cancel_cmd_repeat(string reason, bool force)
108 {
109     if (!force && !is_repeating_cmd())
110         return;
111 
112     if (repeat_cmd == CMD_WIZARD)
113     {
114         // Don't interrupt wizard testing of religion.
115         if (is_god_acting())
116             return;
117 
118         // Don't interrupt wizard testing just because we can't
119         // move.
120         if (you.cannot_act())
121             return;
122 
123         // We've probably just recovered from being unable to act;
124         // again, don't interrupt.
125         if (you.turn_is_over)
126             return;
127     }
128 
129     if (is_replaying_keys() || cmd_repeat_start)
130         flush_input_buffer(FLUSH_KEY_REPLAY_CANCEL);
131 
132     if (is_processing_macro())
133         flush_input_buffer(FLUSH_ABORT_MACRO);
134 
135     reset_cmd_repeat();
136 
137     if (!reason.empty())
138         mpr(reason);
139 }
140 
cancel_cmd_again(string reason,bool force)141 void game_state::cancel_cmd_again(string reason, bool force)
142 {
143     if (!force && !doing_prev_cmd_again)
144         return;
145 
146     if (is_replaying_keys() || cmd_repeat_start)
147         flush_input_buffer(FLUSH_KEY_REPLAY_CANCEL);
148 
149     if (is_processing_macro())
150         flush_input_buffer(FLUSH_ABORT_MACRO);
151 
152     reset_cmd_again();
153 
154     if (!reason.empty())
155         mpr(reason);
156 }
157 
cancel_cmd_all(string reason)158 void game_state::cancel_cmd_all(string reason)
159 {
160     cancel_cmd_repeat(reason);
161     cancel_cmd_again(reason);
162 }
163 
cant_cmd_repeat(string reason)164 void game_state::cant_cmd_repeat(string reason)
165 {
166     if (reason.empty())
167         reason = "Can't repeat that command.";
168 
169     cancel_cmd_repeat(reason);
170 }
171 
cant_cmd_again(string reason)172 void game_state::cant_cmd_again(string reason)
173 {
174     if (reason.empty())
175         reason = "Can't redo that command.";
176 
177     cancel_cmd_again(reason);
178 }
179 
cant_cmd_any(string reason)180 void game_state::cant_cmd_any(string reason)
181 {
182     cant_cmd_repeat(reason);
183     cant_cmd_again(reason);
184 }
185 
186 // The method is called to prevent the "no repeating zero turns
187 // commands" message that input() generates (in the absence of
188 // cancelling the repetition) for a repeated command that took no
189 // turns. A wrapper around cancel_cmd_repeat(), its only purpose is
190 // to make it clear why cancel_cmd_repeat() is being called.
zero_turns_taken()191 void game_state::zero_turns_taken()
192 {
193     ASSERT(!you.turn_is_over);
194     cancel_cmd_repeat();
195 }
196 
interrupt_cmd_repeat(activity_interrupt ai,const activity_interrupt_data & at)197 bool interrupt_cmd_repeat(activity_interrupt ai,
198                            const activity_interrupt_data &at)
199 {
200     if (crawl_state.cmd_repeat_start)
201         return false;
202 
203     if (crawl_state.repeat_cmd == CMD_WIZARD)
204         return false;
205 
206     switch (ai)
207     {
208     case activity_interrupt::teleport:
209     case activity_interrupt::force:
210     case activity_interrupt::hp_loss:
211     case activity_interrupt::monster_attacks:
212     case activity_interrupt::mimic:
213         crawl_state.cancel_cmd_repeat("Command repetition interrupted.");
214         return true;
215 
216     default:
217         break;
218     }
219 
220     if (ai == activity_interrupt::see_monster)
221     {
222         const monster* mon = at.mons_data;
223         ASSERT(mon);
224         if (!you.can_see(*mon))
225             return false;
226 
227         if (crawl_state.cmd_repeat_started_unsafe
228             && at.context != SC_NEWLY_SEEN)
229         {
230             return false;
231         }
232 
233         crawl_state.cancel_cmd_repeat();
234 
235 #ifndef DEBUG_DIAGNOSTICS
236         if (at.context == SC_NEWLY_SEEN)
237         {
238             monster_info mi(mon);
239 
240             mprf(MSGCH_WARN, "%s comes into view.",
241                  get_monster_equipment_desc(mi, DESC_WEAPON).c_str());
242         }
243 
244         if (crawl_state.game_is_hints())
245             hints_monster_seen(*mon);
246 #else
247         formatted_string fs(channel_to_colour(MSGCH_WARN));
248         fs.cprintf("%s (", mon->name(DESC_PLAIN, true).c_str());
249         monster_info mi(mon);
250         fs.add_glyph(get_mons_glyph(mi));
251         fs.cprintf(") in view: (%d,%d), see_cell: %s",
252                    mon->pos().x, mon->pos().y,
253                    you.see_cell(mon->pos())? "yes" : "no");
254         formatted_mpr(fs, MSGCH_WARN);
255 #endif
256 
257         return true;
258     }
259 
260     // If command repetition is being used to imitate the rest command,
261     // then everything interrupts it.
262     if (crawl_state.repeat_cmd == CMD_WAIT)
263     {
264         if (ai == activity_interrupt::full_mp)
265             crawl_state.cancel_cmd_repeat("Magic restored.");
266         else if (ai == activity_interrupt::full_hp)
267             crawl_state.cancel_cmd_repeat("HP restored");
268         else
269             crawl_state.cancel_cmd_repeat("Command repetition interrupted.");
270 
271         return true;
272     }
273 
274     if (crawl_state.cmd_repeat_started_unsafe)
275         return false;
276 
277     if (ai == activity_interrupt::hit_monster)
278     {
279         // This check is for when command repetition is used to
280         // whack away at a 0xp monster, since the player feels safe
281         // when the only monsters around are 0xp.
282         const monster* mon = at.mons_data;
283 
284         if (!mons_is_threatening(*mon) && mon->visible_to(&you))
285             return false;
286 
287         crawl_state.cancel_cmd_repeat("Command repetition interrupted.");
288         return true;
289     }
290 
291     return false;
292 }
293 
reset_cmd_repeat()294 void game_state::reset_cmd_repeat()
295 {
296     repeat_cmd           = CMD_NO_CMD;
297     cmd_repeat_start     = false;
298 }
299 
reset_cmd_again()300 void game_state::reset_cmd_again()
301 {
302     doing_prev_cmd_again = false;
303     prev_cmd             = CMD_NO_CMD;
304     prev_cmd_repeat_goal = 0;
305     prev_repeat_cmd      = CMD_NO_CMD;
306 
307     prev_cmd_keys.clear();
308 }
309 
310 ///////////////////////////////////////////////////////////
311 // Keeping track of which god is currently doing something
312 ///////////////////////////////////////////////////////////
313 
god_act_state()314 god_act_state::god_act_state()
315 {
316     reset();
317 }
318 
reset()319 void god_act_state::reset()
320 {
321     which_god   = GOD_NO_GOD;
322     retribution = false;
323     depth       = 0;
324 }
325 
is_god_acting() const326 bool game_state::is_god_acting() const
327 {
328     ASSERT(god_act.depth >= 0);
329     bool god_is_acting = god_act.depth > 0;
330     ASSERT(!(god_is_acting && god_act.which_god == GOD_NO_GOD));
331     ASSERT(god_is_acting || god_act.which_god == GOD_NO_GOD);
332     ASSERT(god_is_acting || god_act_stack.empty());
333 
334     return god_is_acting;
335 }
336 
is_god_retribution() const337 bool game_state::is_god_retribution() const
338 {
339     ASSERT(is_god_acting());
340 
341     return god_act.retribution;
342 }
343 
which_god_acting() const344 god_type game_state::which_god_acting() const
345 {
346     return god_act.which_god;
347 }
348 
inc_god_acting(bool is_retribution)349 void game_state::inc_god_acting(bool is_retribution)
350 {
351     inc_god_acting(you.religion, is_retribution);
352 }
353 
inc_god_acting(god_type which_god,bool is_retribution)354 void game_state::inc_god_acting(god_type which_god, bool is_retribution)
355 {
356     ASSERT(which_god != GOD_NO_GOD);
357 
358     if (god_act.which_god != GOD_NO_GOD
359         && god_act.which_god != which_god)
360     {
361         ASSERT(god_act.depth >= 1);
362 
363         god_act_stack.push_back(god_act);
364         god_act.reset();
365     }
366 
367     god_act.which_god   = which_god;
368     god_act.retribution = is_retribution || god_act.retribution;
369     god_act.depth++;
370 }
371 
dec_god_acting()372 void game_state::dec_god_acting()
373 {
374     dec_god_acting(you.religion);
375 }
376 
dec_god_acting(god_type which_god)377 void game_state::dec_god_acting(god_type which_god)
378 {
379     ASSERT(which_god != GOD_NO_GOD);
380     ASSERT(god_act.depth > 0);
381     ASSERT(god_act.which_god == which_god);
382 
383     god_act.depth--;
384 
385     if (god_act.depth == 0)
386     {
387         god_act.reset();
388         if (!god_act_stack.empty())
389         {
390             god_act = god_act_stack[god_act_stack.size() - 1];
391             god_act_stack.pop_back();
392             ASSERT(god_act.depth >= 1);
393             ASSERT(god_act.which_god != GOD_NO_GOD);
394             ASSERT(god_act.which_god != which_god);
395         }
396     }
397 }
398 
clear_god_acting()399 void game_state::clear_god_acting()
400 {
401     ASSERT(!is_god_acting());
402     ASSERT(god_act_stack.empty());
403 
404     god_act.reset();
405 }
406 
other_gods_acting() const407 vector<god_act_state> game_state::other_gods_acting() const
408 {
409     ASSERT(is_god_acting());
410     return god_act_stack;
411 }
412 
is_mon_acting() const413 bool game_state::is_mon_acting() const
414 {
415     return mon_act != nullptr;
416 }
417 
which_mon_acting() const418 monster* game_state::which_mon_acting() const
419 {
420     return mon_act;
421 }
422 
inc_mon_acting(monster * mon)423 void game_state::inc_mon_acting(monster* mon)
424 {
425     ASSERT(!invalid_monster(mon));
426 
427     if (mon_act != nullptr)
428         mon_act_stack.push_back(mon_act);
429 
430     mon_act = mon;
431 }
432 
dec_mon_acting(monster * mon)433 void game_state::dec_mon_acting(monster* mon)
434 {
435     ASSERT(mon_act == mon);
436 
437     mon_act = nullptr;
438 
439     const unsigned int size = mon_act_stack.size();
440     if (size > 0)
441     {
442         mon_act = mon_act_stack[size - 1];
443         ASSERT(!invalid_monster(mon_act));
444         mon_act_stack.pop_back();
445     }
446 }
447 
clear_mon_acting()448 void game_state::clear_mon_acting()
449 {
450     mon_act = nullptr;
451     mon_act_stack.clear();
452 }
453 
mon_gone(monster * mon)454 void game_state::mon_gone(monster* mon)
455 {
456     for (unsigned int i = 0, size = mon_act_stack.size(); i < size; i++)
457     {
458         if (mon_act_stack[i] == mon)
459         {
460             mon_act_stack.erase(mon_act_stack.begin() + i);
461             i--;
462             size--;
463         }
464     }
465 
466     if (mon_act == mon)
467         dec_mon_acting(mon);
468 }
469 
dump()470 void game_state::dump()
471 {
472     fprintf(stderr, "\nGame state:\n\n");
473 
474     fprintf(stderr, "mouse_enabled: %d, waiting_for_command: %d, "
475                   "terminal_resized: %d\n",
476             mouse_enabled, waiting_for_command, terminal_resized);
477     fprintf(stderr, "io_inited: %d, need_save: %d, saving_game: %d, "
478                   "updating_scores: %d:\n",
479             io_inited, need_save, saving_game, updating_scores);
480     fprintf(stderr, "seen_hups: %d, map_stat_gen: %d, type: %d, "
481                   "arena_suspended: %d\n",
482             seen_hups, map_stat_gen, type, arena_suspended);
483     if (last_winch)
484     {
485         fprintf(stderr, "Last resize was %" PRId64" seconds ago.\n",
486                 (int64_t)(time(0) - last_winch));
487     }
488 
489     fprintf(stderr, "\n");
490 
491     // Arena mode can change behavior of the rest of the code and/or lead
492     // to asserts.
493     unwind_var<game_type> _type(type, GAME_TYPE_NORMAL);
494     unwind_bool _arena_suspended(arena_suspended, false);
495 
496     fprintf(stderr, "prev_cmd = %s\n", command_to_name(prev_cmd).c_str());
497 
498     if (doing_prev_cmd_again)
499     {
500         fprintf(stderr, "Doing prev_cmd again with keys: ");
501         for (int key : prev_cmd_keys)
502             fprintf(stderr, "%d, ", key);
503         fprintf(stderr, "\n");
504         fprintf(stderr, "As ASCII keys: ");
505         for (int key : prev_cmd_keys)
506             fprintf(stderr, "%c", (char) key);
507         fprintf(stderr, "\n\n");
508     }
509     fprintf(stderr, "repeat_cmd = %s\n", command_to_name(repeat_cmd).c_str());
510 
511     fprintf(stderr, "\n");
512 
513     if (god_act.which_god != GOD_NO_GOD || god_act.depth != 0)
514     {
515         fprintf(stderr, "God %s currently acting with depth %d\n\n",
516                 god_name(god_act.which_god).c_str(), god_act.depth);
517     }
518 
519     if (!god_act_stack.empty())
520     {
521         fprintf(stderr, "Other gods acting:\n");
522         for (const god_act_state &godact : god_act_stack)
523         {
524             fprintf(stderr, "God %s with depth %d\n",
525                     god_name(godact.which_god).c_str(), godact.depth);
526         }
527         fprintf(stderr, "\n\n");
528     }
529 
530     if (mon_act != nullptr)
531     {
532         fprintf(stderr, "%s currently acting:\n\n",
533                 debug_mon_str(mon_act).c_str());
534         debug_dump_mon(mon_act, true);
535     }
536 
537     if (!mon_act_stack.empty())
538     {
539         fprintf(stderr, "Others monsters acting:\n");
540         for (const monster *mon : mon_act_stack)
541             fprintf(stderr, "    %s\n", debug_mon_str(mon).c_str());
542     }
543 }
544 
player_is_dead() const545 bool game_state::player_is_dead() const
546 {
547     return updating_scores && !need_save;
548 }
549 
game_standard_levelgen() const550 bool game_state::game_standard_levelgen() const
551 {
552     return game_is_normal() || game_is_hints();
553 }
554 
game_is_valid_type() const555 bool game_state::game_is_valid_type() const
556 {
557     return type < NUM_GAME_TYPE;
558 }
559 
game_is_normal() const560 bool game_state::game_is_normal() const
561 {
562     ASSERT(game_is_valid_type());
563     return type == GAME_TYPE_NORMAL || type == GAME_TYPE_CUSTOM_SEED
564                                     || type == GAME_TYPE_UNSPECIFIED;
565 }
566 
game_is_tutorial() const567 bool game_state::game_is_tutorial() const
568 {
569     ASSERT(game_is_valid_type());
570     return type == GAME_TYPE_TUTORIAL;
571 }
572 
game_is_arena() const573 bool game_state::game_is_arena() const
574 {
575     ASSERT(game_is_valid_type());
576     return type == GAME_TYPE_ARENA;
577 }
578 
game_is_sprint() const579 bool game_state::game_is_sprint() const
580 {
581     ASSERT(game_is_valid_type());
582     return type == GAME_TYPE_SPRINT;
583 }
584 
game_is_hints() const585 bool game_state::game_is_hints() const
586 {
587     ASSERT(game_is_valid_type());
588     return type == GAME_TYPE_HINTS;
589 }
590 
game_is_hints_tutorial() const591 bool game_state::game_is_hints_tutorial() const
592 {
593     return game_is_hints() || game_is_tutorial();
594 }
595 
game_type_name() const596 string game_state::game_type_name() const
597 {
598     return game_type_name_for(type);
599 }
600 
game_type_name_for(game_type _type)601 string game_state::game_type_name_for(game_type _type)
602 {
603     switch (_type)
604     {
605     case GAME_TYPE_UNSPECIFIED:
606     case GAME_TYPE_NORMAL:
607     case GAME_TYPE_HINTS:
608     default:
609         // No explicit game type name for default game.
610         return "";
611     case GAME_TYPE_CUSTOM_SEED:
612         return "Seeded";
613     case GAME_TYPE_TUTORIAL:
614         return "Tutorial";
615     case GAME_TYPE_ARENA:
616         return "Arena";
617     case GAME_TYPE_SPRINT:
618         return "Dungeon Sprint";
619     case NUM_GAME_TYPE:
620         return "Unknown";
621     }
622 }
623 
game_savedir_path() const624 string game_state::game_savedir_path() const
625 {
626     if (!game_is_valid_type())
627         return ""; // a game from the future -- avoid the ASSERT below
628     return game_is_sprint()? "sprint/" : "";
629 }
630 
game_type_qualifier() const631 string game_state::game_type_qualifier() const
632 {
633     if (type == GAME_TYPE_CUSTOM_SEED)
634         return "-seeded";
635     if (crawl_state.game_is_sprint())
636         return "-sprint";
637     if (crawl_state.game_is_tutorial())
638         return "-tutorial";
639     if (crawl_state.game_is_hints())
640         return "-hints";
641     return "";
642 }
643