1 /**
2  * @file
3  * @brief Misc functions.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "misc.h"
9 #include "mpr.h"
10 
11 #include <algorithm>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 #ifdef UNIX
16 #include <unistd.h>
17 #endif
18 
19 #include "database.h"
20 #include "english.h"
21 #include "items.h"
22 #include "libutil.h"
23 #include "monster.h"
24 #include "state.h"
25 #include "terrain.h"
26 #include "tileview.h"
27 #include "traps.h"
28 
29 // Make the player swap positions with a given monster.
swap_with_monster(monster * mon_to_swap)30 void swap_with_monster(monster* mon_to_swap)
31 {
32     monster& mon(*mon_to_swap);
33     ASSERT(mon.alive());
34     const coord_def newpos = mon.pos();
35 
36     if (you.stasis())
37     {
38         mpr("Your stasis prevents you from teleporting.");
39         return;
40     }
41 
42     // Be nice: no swapping into uninhabitable environments.
43     if (!you.is_habitable(newpos) || !mon.is_habitable(you.pos()))
44     {
45         mpr("You spin around.");
46         return;
47     }
48 
49     const bool mon_caught = mon.caught();
50     const bool you_caught = you.attribute[ATTR_HELD];
51 
52     // If it was submerged, it surfaces first.
53     mon.del_ench(ENCH_SUBMERGED);
54 
55     mprf("You swap places with %s.", mon.name(DESC_THE).c_str());
56 
57     mon.move_to_pos(you.pos(), true, true);
58 
59     // XXX: destroy ammo == 1 webs if they don't catch the mons? very rare case
60 
61     if (you_caught)
62     {
63         // XXX: this doesn't correctly handle web traps
64         check_net_will_hold_monster(&mon);
65         if (!mon_caught)
66             stop_being_held();
67     }
68 
69     // Move you to its previous location.
70     move_player_to_grid(newpos, false);
71 
72     if (mon_caught)
73     {
74         // XXX: destroy ammo == 1 webs? (rare case)
75 
76         if (you.body_size(PSIZE_BODY) >= SIZE_GIANT) // e.g. dragonform
77         {
78             int net = get_trapping_net(you.pos());
79             if (net != NON_ITEM)
80             {
81                 destroy_item(net);
82                 mpr("The net rips apart!");
83             }
84 
85             if (you_caught)
86                 stop_being_held();
87         }
88         else // XXX: doesn't handle e.g. spiderform swapped into webs
89         {
90             you.attribute[ATTR_HELD] = 1;
91             if (get_trapping_net(you.pos()) != NON_ITEM)
92                 mpr("You become entangled in the net!");
93             else
94                 mpr("You get stuck in the web!");
95             quiver::set_needs_redraw();
96             you.redraw_evasion = true;
97         }
98 
99         if (!you_caught)
100             mon.del_ench(ENCH_HELD, true);
101     }
102 }
103 
handle_real_time(chrono::time_point<chrono::system_clock> now)104 void handle_real_time(chrono::time_point<chrono::system_clock> now)
105 {
106     const chrono::milliseconds elapsed =
107      chrono::duration_cast<chrono::milliseconds>(now - you.last_keypress_time);
108     you.real_time_delta = min<chrono::milliseconds>(
109       elapsed,
110       (chrono::milliseconds)(IDLE_TIME_CLAMP * 1000));
111     you.real_time_ms += you.real_time_delta;
112     you.last_keypress_time = now;
113 }
114 
breakpoint_rank(int val,const int breakpoints[],unsigned int num_breakpoints)115 unsigned int breakpoint_rank(int val, const int breakpoints[],
116                              unsigned int num_breakpoints)
117 {
118     unsigned int result = 0;
119     while (result < num_breakpoints && val >= breakpoints[result])
120         ++result;
121 
122     return result;
123 }
124 
counted_monster_list(vector<monster * > ms)125 counted_monster_list::counted_monster_list(vector<monster *> ms)
126 {
127     for (auto mon : ms)
128         add(mon);
129 }
130 
add(const monster * mons)131 void counted_monster_list::add(const monster* mons)
132 {
133     const string name = mons->name(DESC_PLAIN);
134     for (auto &entry : list)
135     {
136         if (entry.first->name(DESC_PLAIN) == name)
137         {
138             entry.second++;
139             return;
140         }
141     }
142     list.emplace_back(mons, 1);
143 }
144 
count()145 int counted_monster_list::count()
146 {
147     int nmons = 0;
148     for (const auto &entry : list)
149         nmons += entry.second;
150     return nmons;
151 }
152 
describe(description_level_type desc)153 string counted_monster_list::describe(description_level_type desc)
154 {
155     string out;
156 
157     for (auto i = list.begin(); i != list.end();)
158     {
159         const counted_monster &cm(*i);
160         if (i != list.begin())
161         {
162             ++i;
163             out += (i == list.end() ? " and " : ", ");
164         }
165         else
166             ++i;
167 
168         out += cm.second > 1
169                ? pluralise_monster(cm.first->name(desc, false, true))
170                : cm.first->name(desc);
171     }
172     return out;
173 }
174 
175 /**
176  * Halloween or Hallowe'en (/ˌhæləˈwiːn, -oʊˈiːn, ˌhɑːl-/; a contraction of
177  * "All Hallows' Evening"),[6] also known as Allhalloween,[7] All Hallows' Eve,
178  * [8] or All Saints' Eve,[9] is a yearly celebration observed in a number of
179  * countries on 31 October, the eve of the Western Christian feast of All
180  * Hallows' Day... Within Allhallowtide, the traditional focus of All Hallows'
181  * Eve revolves around the theme of using "humor and ridicule to confront the
182  * power of death."[12]
183  *
184  * Typical festive Halloween activities include trick-or-treating (or the
185  * related "guising"), attending costume parties, decorating, carving pumpkins
186  * into jack-o'-lanterns, lighting bonfires, apple bobbing, visiting haunted
187  * house attractions, playing pranks, telling scary stories, and watching
188  * horror films.
189  *
190  * @return  Whether the current day is Halloween. (Cunning players may reset
191  *          their system clocks to manipulate this. That's fine.)
192  */
today_is_halloween()193 bool today_is_halloween()
194 {
195     const time_t curr_time = time(nullptr);
196     const struct tm *date = TIME_FN(&curr_time);
197     // tm_mon is zero-based in case you are wondering
198     return date->tm_mon == 9 && date->tm_mday == 31;
199 }
200 
tobool(maybe_bool mb,bool def)201 bool tobool(maybe_bool mb, bool def)
202 {
203     switch (mb)
204     {
205     case MB_TRUE:
206         return true;
207     case MB_FALSE:
208         return false;
209     case MB_MAYBE:
210     default:
211         return def;
212     }
213 }
214 
frombool(bool b)215 maybe_bool frombool(bool b)
216 {
217     return b ? MB_TRUE : MB_FALSE;
218 }
219 
maybe_to_string(const maybe_bool mb)220 const string maybe_to_string(const maybe_bool mb)
221 {
222     switch (mb)
223     {
224     case MB_TRUE:
225         return "true";
226     case MB_FALSE:
227         return "false";
228     case MB_MAYBE:
229     default:
230         return "maybe";
231     }
232 }
233