Add a ground_level method to actor.
[crawl.git] / crawl-ref / source / actor.cc
blob0036ef3870b6b3f9c526b9a63e2743fe369e4179
1 #include "AppHdr.h"
3 #include "actor.h"
4 #include "areas.h"
5 #include "artefact.h"
6 #include "coord.h"
7 #include "coordit.h"
8 #include "env.h"
9 #include "itemprop.h"
10 #include "los.h"
11 #include "mon-death.h"
12 #include "player.h"
13 #include "random.h"
14 #include "state.h"
15 #include "stuff.h"
16 #include "terrain.h"
17 #include "traps.h"
19 actor::~actor()
23 bool actor::has_equipped(equipment_type eq, int sub_type) const
25 const item_def *item = slot_item(eq, false);
26 return (item && item->sub_type == sub_type);
29 bool actor::will_trigger_shaft() const
31 return (!(airborne() || is_wall_clinging())
32 && total_weight() > 0 && is_valid_shaft_level()
33 // let's pretend that they always make their saving roll
34 && !(atype() == ACT_MONSTER
35 && mons_is_elven_twin(static_cast<const monster* >(this))));
38 level_id actor::shaft_dest(bool known = false) const
40 return generic_shaft_dest(pos(), known);
43 bool actor::airborne() const
45 return (is_levitating() || (flight_mode() == FL_FLY && !cannot_move()));
48 /**
49 * Check if the actor is on the ground (or in water).
51 bool actor::ground_level() const
53 return (!airborne() && !is_wall_clinging());
56 bool actor::can_wield(const item_def* item, bool ignore_curse,
57 bool ignore_brand, bool ignore_shield,
58 bool ignore_transform) const
60 if (item == NULL)
62 // Unarmed combat.
63 item_def fake;
64 fake.base_type = OBJ_UNASSIGNED;
65 return can_wield(fake, ignore_curse, ignore_brand, ignore_transform);
67 else
68 return can_wield(*item, ignore_curse, ignore_brand, ignore_transform);
71 bool actor::can_pass_through(int x, int y) const
73 return can_pass_through_feat(grd[x][y]);
76 bool actor::can_pass_through(const coord_def &c) const
78 return can_pass_through_feat(grd(c));
81 bool actor::is_habitable(const coord_def &_pos) const
83 if (can_cling_to(_pos))
84 return true;
86 return is_habitable_feat(grd(_pos));
89 bool actor::handle_trap()
91 trap_def* trap = find_trap(pos());
92 if (trap)
93 trap->trigger(*this);
94 return (trap != NULL);
98 int actor::res_holy_fire() const
100 if (is_evil() || is_unholy())
101 return (-1);
102 else if (is_holy())
103 return (3);
104 return (0);
107 int actor::check_res_magic(int power)
109 const int mrs = res_magic();
111 if (mrs == MAG_IMMUNE)
112 return (100);
114 // Evil, evil hack to make weak one hd monsters easier for first level
115 // characters who have resistable 1st level spells. Six is a very special
116 // value because mrs = hd * 2 * 3 for most monsters, and the weak, low
117 // level monsters have been adjusted so that the "3" is typically a 1.
118 // There are some notable one hd monsters that shouldn't fall under this,
119 // so we do < 6, instead of <= 6... or checking mons->hit_dice. The
120 // goal here is to make the first level easier for these classes and give
121 // them a better shot at getting to level two or three and spells that can
122 // help them out (or building a level or two of their base skill so they
123 // aren't resisted as often). - bwr
124 if (atype() == ACT_MONSTER && mrs < 6 && coinflip())
125 return (-1);
127 power = stepdown_value(power, 30, 40, 100, 120);
129 const int mrchance = (100 + mrs) - power;
130 const int mrch2 = random2(100) + random2(101);
132 dprf("Power: %d, MR: %d, target: %d, roll: %d",
133 power, mrs, mrchance, mrch2);
135 return (mrchance - mrch2);
138 void actor::set_position(const coord_def &c)
140 const coord_def oldpos = position;
141 position = c;
142 los_actor_moved(this, oldpos);
143 areas_actor_moved(this, oldpos);
146 bool actor::can_hibernate(bool holi_only) const
148 // Undead, nonliving, and plants don't sleep.
149 const mon_holy_type holi = holiness();
150 if (holi == MH_UNDEAD || holi == MH_NONLIVING || holi == MH_PLANT)
151 return (false);
153 if (!holi_only)
155 // The monster is berserk or already asleep.
156 if (!can_sleep())
157 return (false);
159 // The monster is cold-resistant and can't be hibernated.
160 if (res_cold() > 0)
161 return (false);
163 // The monster has slept recently.
164 if (atype() == ACT_MONSTER
165 && static_cast<const monster* >(this)->has_ench(ENCH_SLEEP_WARY))
167 return (false);
171 return (true);
174 bool actor::can_sleep() const
176 const mon_holy_type holi = holiness();
177 if (holi == MH_UNDEAD || holi == MH_NONLIVING || holi == MH_PLANT)
178 return (false);
179 return !(berserk() || asleep());
182 void actor::shield_block_succeeded(actor *foe)
184 item_def *sh = shield();
185 unrandart_entry *unrand_entry;
187 if (sh
188 && sh->base_type == OBJ_ARMOUR
189 && get_armour_slot(*sh) == EQ_SHIELD
190 && is_artefact(*sh)
191 && is_unrandom_artefact(*sh)
192 && (unrand_entry = get_unrand_entry(sh->special))
193 && unrand_entry->fight_func.melee_effects)
195 unrand_entry->fight_func.melee_effects(sh, this, foe, false);
199 int actor::body_weight(bool base) const
201 switch (body_size(PSIZE_BODY, base))
203 case SIZE_TINY:
204 return (150);
205 case SIZE_LITTLE:
206 return (300);
207 case SIZE_SMALL:
208 return (425);
209 case SIZE_MEDIUM:
210 return (550);
211 case SIZE_LARGE:
212 return (1300);
213 case SIZE_BIG:
214 return (1500);
215 case SIZE_GIANT:
216 return (1800);
217 case SIZE_HUGE:
218 return (2200);
219 default:
220 mpr("ERROR: invalid body weight");
221 perror("actor::body_weight(): invalid body weight");
222 end(0);
223 return (0);
227 kill_category actor_kill_alignment(const actor *act)
229 return (act? act->kill_alignment() : KC_OTHER);
232 bool actor_slime_wall_immune(const actor *act)
234 return (act->atype() == ACT_PLAYER?
235 you.religion == GOD_JIYVA && !you.penance[GOD_JIYVA]
236 : act->res_acid() == 3);
239 bool actor::is_wall_clinging() const
241 return (clinging);
244 bool actor::can_cling_to(const coord_def& p) const
246 if (!in_bounds(p))
247 return (false);
249 if (!is_wall_clinging())
250 return (false);
252 if (!can_pass_through_feat(grd(p)))
253 return (false);
255 for (orth_adjacent_iterator ai(p); ai; ++ai)
256 if (feat_is_wall(env.grid(*ai)))
257 for (orth_adjacent_iterator ai2(*ai, false); ai2; ++ai2)
258 for (int i = 0, size = cling_to.size(); i < size; ++i)
259 if (cling_to[i] == *ai2)
260 return (true);
262 return (false);
265 void actor::check_clinging()
267 if (!can_cling_to_walls())
268 return;
270 cling_to.clear();
271 for (orth_adjacent_iterator ai(pos()); ai; ++ai)
272 if (feat_is_wall(env.grid(*ai)))
273 cling_to.push_back(*ai);
275 clinging = (cling_to.size() > 0) ? true : false;