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