18 #include "mon-death.h"
21 #include "stringutil.h"
23 #include "transform.h"
32 bool actor::will_trigger_shaft() const
34 return is_valid_shaft_level()
35 // let's pretend that they always make their saving roll
37 && mons_is_elven_twin(static_cast<const monster* >(this)));
40 level_id actor::shaft_dest(bool known = false) const
42 return generic_shaft_dest(pos(), known);
46 * Check if the actor is on the ground (or in water).
48 bool actor::ground_level() const
50 return !airborne() && !is_wall_clinging()
51 #if TAG_MAJOR_VERSION == 34
52 && mons_species() != MONS_DJINNI
57 bool actor::stand_on_solid_ground() const
59 return ground_level() && feat_has_solid_floor(grd(pos()))
60 && !feat_is_water(grd(pos()));
63 // Give hands required to wield weapon.
64 hands_reqd_type actor::hands_reqd(const item_def &item) const
66 return basic_hands_reqd(item, body_size());
70 * Wrapper around the virtual actor::can_wield(const item_def&,bool,bool,bool,bool) const overload.
71 * @param item May be nullptr, in which case a dummy item will be passed in.
73 bool actor::can_wield(const item_def* item, bool ignore_curse,
74 bool ignore_brand, bool ignore_shield,
75 bool ignore_transform) const
81 fake.base_type = OBJ_UNASSIGNED;
82 return can_wield(fake, ignore_curse, ignore_brand, ignore_shield, ignore_transform);
85 return can_wield(*item, ignore_curse, ignore_brand, ignore_shield, ignore_transform);
88 bool actor::can_pass_through(int x, int y) const
90 return can_pass_through_feat(grd[x][y]);
93 bool actor::can_pass_through(const coord_def &c) const
95 return can_pass_through_feat(grd(c));
98 bool actor::is_habitable(const coord_def &_pos) const
100 if (can_cling_to(_pos))
103 return is_habitable_feat(grd(_pos));
106 bool actor::handle_trap()
108 trap_def* trap = find_trap(pos());
110 trap->trigger(*this);
111 return trap != nullptr;
114 int actor::skill_rdiv(skill_type sk, int mult, int div) const
116 return div_rand_round(skill(sk, mult * 256), div * 256);
119 int actor::check_res_magic(int power)
121 const int mrs = res_magic();
123 if (mrs == MAG_IMMUNE)
126 // Evil, evil hack to make weak one hd monsters easier for first level
127 // characters who have resistable 1st level spells. Six is a very special
128 // value because mrs = hd * 2 * 3 for most monsters, and the weak, low
129 // level monsters have been adjusted so that the "3" is typically a 1.
130 // There are some notable one hd monsters that shouldn't fall under this,
131 // so we do < 6, instead of <= 6... or checking mons->hit_dice. The
132 // goal here is to make the first level easier for these classes and give
133 // them a better shot at getting to level two or three and spells that can
134 // help them out (or building a level or two of their base skill so they
135 // aren't resisted as often). - bwr
136 if (is_monster() && mrs < 6 && coinflip())
139 power = ench_power_stepdown(power);
141 const int mrchance = (100 + mrs) - power;
142 const int mrch2 = random2(100) + random2(101);
144 dprf("Power: %d, MR: %d, target: %d, roll: %d",
145 power, mrs, mrchance, mrch2);
147 return mrchance - mrch2;
150 void actor::set_position(const coord_def &c)
152 const coord_def oldpos = position;
154 los_actor_moved(this, oldpos);
155 areas_actor_moved(this, oldpos);
158 bool actor::can_hibernate(bool holi_only, bool intrinsic_only) const
160 // Undead, nonliving, and plants don't sleep. If the monster is
161 // berserk or already asleep, it doesn't sleep either.
162 if (!can_sleep(holi_only))
167 // The monster is cold-resistant and can't be hibernated.
168 if (intrinsic_only && is_monster()
169 ? get_mons_resist(as_monster(), MR_RES_COLD) > 0
175 // The monster has slept recently.
176 if (is_monster() && !intrinsic_only
177 && static_cast<const monster* >(this)->has_ench(ENCH_SLEEP_WARY))
186 bool actor::can_sleep(bool holi_only) const
188 const mon_holy_type holi = holiness();
189 if (holi == MH_UNDEAD || holi == MH_NONLIVING || holi == MH_PLANT)
193 return !(berserk() || asleep());
198 void actor::shield_block_succeeded(actor *foe)
200 item_def *sh = shield();
201 const unrandart_entry *unrand_entry;
204 && sh->base_type == OBJ_ARMOUR
205 && get_armour_slot(*sh) == EQ_SHIELD
207 && is_unrandom_artefact(*sh)
208 && (unrand_entry = get_unrand_entry(sh->special))
209 && unrand_entry->melee_effects)
211 unrand_entry->melee_effects(sh, this, foe, false, 0);
215 int actor::inaccuracy() const
217 return wearing(EQ_AMULET, AMU_INACCURACY);
220 bool actor::gourmand(bool calc_unid, bool items) const
222 return items && wearing(EQ_AMULET, AMU_THE_GOURMAND, calc_unid);
225 bool actor::res_corr(bool calc_unid, bool items) const
227 return items && (wearing(EQ_AMULET, AMU_RESIST_CORROSION, calc_unid)
228 || scan_artefacts(ARTP_RCORR, calc_unid));
231 // This is a bit confusing. This is not the function that determines whether or
232 // not an actor is capable of teleporting, only whether they are specifically
233 // under the influence of the "notele" effect. See actor::no_tele() for a
234 // superset of this function.
235 bool actor::has_notele_item(bool calc_unid, vector<item_def> *matches) const
237 return scan_artefacts(ARTP_PREVENT_TELEPORTATION, calc_unid, matches);
240 bool actor::stasis(bool calc_unid, bool items) const
242 return items && wearing(EQ_AMULET, AMU_STASIS, calc_unid);
245 // permaswift effects like boots of running and lightning scales
246 bool actor::run(bool calc_unid, bool items) const
248 return items && wearing_ego(EQ_BOOTS, SPARM_RUNNING, calc_unid);
251 bool actor::angry(bool calc_unid, bool items) const
253 return items && scan_artefacts(ARTP_ANGRY, calc_unid);
256 bool actor::clarity(bool calc_unid, bool items) const
258 return items && (wearing(EQ_AMULET, AMU_CLARITY, calc_unid)
259 || scan_artefacts(ARTP_CLARITY, calc_unid));
262 bool actor::faith(bool calc_unid, bool items) const
264 return items && wearing(EQ_AMULET, AMU_FAITH, calc_unid);
267 bool actor::warding(bool calc_unid, bool items) const
269 // Note: when adding a new source of warding, please add it to
270 // melee_attack::attack_warded_off() as well.
271 return items && (wearing(EQ_AMULET, AMU_WARDING, calc_unid)
272 || wearing(EQ_STAFF, STAFF_SUMMONING, calc_unid));
275 int actor::archmagi(bool calc_unid, bool items) const
280 return wearing_ego(EQ_ALL_ARMOUR, SPARM_ARCHMAGI, calc_unid);
283 bool actor::no_cast(bool calc_unid, bool items) const
285 return items && scan_artefacts(ARTP_PREVENT_SPELLCASTING, calc_unid);
288 bool actor::rmut_from_item(bool calc_unid) const
290 return wearing(EQ_AMULET, AMU_RESIST_MUTATION, calc_unid)
291 || scan_artefacts(ARTP_RMUT, calc_unid);
294 bool actor::evokable_berserk(bool calc_unid) const
296 return wearing(EQ_AMULET, AMU_RAGE, calc_unid)
297 || scan_artefacts(ARTP_BERSERK, calc_unid);
300 bool actor::evokable_invis(bool calc_unid) const
302 return wearing(EQ_RINGS, RING_INVISIBILITY, calc_unid)
303 || wearing_ego(EQ_CLOAK, SPARM_INVISIBILITY, calc_unid)
304 || scan_artefacts(ARTP_INVISIBLE, calc_unid);
307 // Return an int so we know whether an item is the sole source.
308 int actor::evokable_flight(bool calc_unid) const
310 if (is_player() && get_form()->forbids_flight())
313 return wearing(EQ_RINGS, RING_FLIGHT, calc_unid)
314 + wearing_ego(EQ_ALL_ARMOUR, SPARM_FLYING, calc_unid)
315 + scan_artefacts(ARTP_FLY, calc_unid);
318 int actor::spirit_shield(bool calc_unid, bool items) const
324 ss += wearing_ego(EQ_ALL_ARMOUR, SPARM_SPIRIT_SHIELD, calc_unid);
325 ss += wearing(EQ_AMULET, AMU_GUARDIAN_SPIRIT, calc_unid);
329 ss += player_mutation_level(MUT_MANA_SHIELD);
334 int actor::apply_ac(int damage, int max_damage, ac_type ac_rule,
335 int stab_bypass) const
337 int ac = max(armour_class() - stab_bypass, 0);
338 int gdr = gdr_perc();
343 return damage; // no GDR, too
344 case AC_PROPORTIONAL:
345 ASSERT(stab_bypass == 0);
346 saved = damage - apply_chunked_AC(damage, ac);
347 saved = max(saved, div_rand_round(max_damage * gdr, 100));
348 return max(damage - saved, 0);
351 saved = random2(1 + ac);
354 saved = random2(1 + ac) / 2;
359 saved = random2(1 + ac) + random2(1 + ac) + random2(1 + ac);
361 // apply GDR only twice rather than thrice, that's probably still waaay
362 // too good. 50% gives 75% rather than 100%, too.
363 gdr = 100 - gdr * gdr / 100;
366 die("invalid AC rule");
369 saved = max(saved, min(gdr * max_damage / 100, ac / 2));
370 return max(damage - saved, 0);
373 bool actor_slime_wall_immune(const actor *act)
376 act->is_player() && you_worship(GOD_JIYVA) && !you.penance[GOD_JIYVA]
377 || act->res_acid() == 3;
381 * Accessor method to the clinging member.
383 * @return The value of clinging.
385 bool actor::is_wall_clinging() const
387 return props.exists(CLING_KEY) && props[CLING_KEY].get_bool();
391 * Check a cell to see if actor can keep clinging if it moves to it.
393 * @param p Coordinates of the cell checked.
394 * @return Whether the actor can cling.
396 bool actor::can_cling_to(const coord_def& p) const
398 if (!is_wall_clinging() || !can_pass_through_feat(grd(p)))
401 return cell_can_cling_to(pos(), p);
405 * Update the clinging status of an actor.
407 * It checks adjacent orthogonal walls to see if the actor can cling to them.
408 * If actor has fallen from the wall (wall dug or actor changed form), print a
409 * message and apply location effects.
411 * @param stepped Whether the actor has taken a step.
412 * @return the new clinging status.
414 bool actor::check_clinging(bool stepped, bool door)
416 bool was_clinging = is_wall_clinging();
417 bool clinging = can_cling_to_walls() && cell_is_clingable(pos())
420 if (can_cling_to_walls())
421 props[CLING_KEY] = clinging;
422 else if (props.exists(CLING_KEY))
423 props.erase(CLING_KEY);
425 if (!stepped && was_clinging && !clinging)
427 if (you.can_see(this))
429 mprf("%s %s off the %s.", name(DESC_THE).c_str(),
430 conj_verb("fall").c_str(),
431 door ? "door" : "wall");
433 apply_location_effects(pos());
438 void actor::clear_clinging()
440 if (props.exists(CLING_KEY))
441 props[CLING_KEY] = false;
444 void actor::clear_constricted()
451 // End my constriction of i->first, but don't yet update my constricting map,
452 // so as not to invalidate i.
453 void actor::end_constriction(mid_t whom, bool intentional, bool quiet)
455 actor *const constrictee = actor_by_mid(whom);
460 constrictee->clear_constricted();
462 if (!quiet && alive() && constrictee->alive()
463 && (you.see_cell(pos()) || you.see_cell(constrictee->pos())))
465 mprf("%s %s %s grip on %s.",
466 name(DESC_THE).c_str(),
467 conj_verb(intentional ? "release" : "lose").c_str(),
468 pronoun(PRONOUN_POSSESSIVE).c_str(),
469 constrictee->name(DESC_THE).c_str());
472 if (constrictee->is_player())
473 you.redraw_evasion = true;
476 void actor::stop_constricting(mid_t whom, bool intentional, bool quiet)
481 auto i = constricting->find(whom);
483 if (i != constricting->end())
485 end_constriction(whom, intentional, quiet);
486 constricting->erase(i);
488 if (constricting->empty())
496 void actor::stop_constricting_all(bool intentional, bool quiet)
501 for (const auto &entry : *constricting)
502 end_constriction(entry.first, intentional, quiet);
508 void actor::stop_being_constricted(bool quiet)
510 // Make sure we are actually being constricted.
511 actor* const constrictor = actor_by_mid(constricted_by);
514 constrictor->stop_constricting(mid, false, quiet);
516 // In case the actor no longer exists.
520 void actor::clear_far_constrictions()
523 actor* const constrictor = actor_by_mid(constricted_by);
525 if (!constrictor || !adjacent(pos(), constrictor->pos()))
526 stop_being_constricted();
531 vector<mid_t> need_cleared;
532 for (const auto &entry : *constricting)
534 actor* const constrictee = actor_by_mid(entry.first);
535 if (!constrictee || !adjacent(pos(), constrictee->pos()))
536 need_cleared.push_back(entry.first);
539 for (mid_t whom : need_cleared)
540 stop_constricting(whom, false, false);
543 void actor::start_constricting(actor &whom, int dur)
546 constricting = new constricting_t();
548 ASSERT(constricting->find(whom.mid) == constricting->end());
550 (*constricting)[whom.mid] = dur;
551 whom.constricted_by = mid;
552 whom.held = constriction_damage() ? HELD_CONSTRICTED : HELD_MONSTER;
554 if (whom.is_player())
555 you.redraw_evasion = true;
558 int actor::num_constricting() const
560 return constricting ? constricting->size() : 0;
563 bool actor::is_constricting() const
565 return constricting && !constricting->empty();
568 bool actor::is_constricted() const
570 return constricted_by;
573 void actor::accum_has_constricted()
578 for (auto &entry : *constricting)
579 entry.second += you.time_taken;
582 bool actor::can_constrict(actor* defender)
584 return (!is_constricting() || has_usable_tentacle())
585 && !defender->is_constricted()
588 && body_size(PSIZE_BODY) >= defender->body_size(PSIZE_BODY)
589 && defender->res_constrict() < 3
590 && adjacent(pos(), defender->pos());
593 #ifdef DEBUG_DIAGNOSTICS
594 # define DIAG_ONLY(x) x
596 # define DIAG_ONLY(x) (void)0
599 // Deal damage over time
600 void actor::handle_constriction()
602 if (is_sanctuary(pos()))
603 stop_constricting_all(true);
605 // Constriction should have stopped the moment the actors became
606 // non-adjacent; but disabling constriction by hand in every single place
607 // is too error-prone.
608 clear_far_constrictions();
610 if (!constricting || !constriction_damage())
613 auto i = constricting->begin();
614 // monster_die() can cause constricting() to go away.
615 while (constricting && i != constricting->end())
617 actor* const defender = actor_by_mid(i->first);
618 int duration = i->second;
621 // Must increment before potentially killing the constrictee and
622 // thus invalidating the old i.
625 int damage = constriction_damage();
627 DIAG_ONLY(const int basedam = damage);
628 damage += div_rand_round(damage * stepdown((float)duration, 50.0),
631 damage = div_rand_round(damage * (27 + 2 * you.experience_level), 81);
632 DIAG_ONLY(const int durdam = damage);
633 damage -= random2(1 + (defender->armour_class() / 2));
634 DIAG_ONLY(const int acdam = damage);
635 damage = timescale_damage(this, damage);
636 DIAG_ONLY(const int timescale_dam = damage);
638 damage = defender->hurt(this, damage, BEAM_MISSILE,
639 KILLED_BY_MONSTER, "", "", false);
640 DIAG_ONLY(const int infdam = damage);
643 if (damage <= 0 && is_player()
644 && you.can_see(defender))
646 exclamations = ", but do no damage.";
648 else if (damage < HIT_WEAK)
650 else if (damage < HIT_MED)
652 else if (damage < HIT_STRONG)
656 int tmpdamage = damage;
657 exclamations = "!!!";
658 while (tmpdamage >= 2*HIT_STRONG)
665 if (is_player() || you.can_see(this))
669 : name(DESC_THE).c_str()),
670 conj_verb("constrict").c_str(),
671 defender->name(DESC_THE).c_str(),
672 #ifdef DEBUG_DIAGNOSTICS
673 make_stringf(" for %d", damage).c_str(),
677 exclamations.c_str());
679 else if (you.can_see(defender) || defender->is_player())
681 mprf("%s %s constricted%s%s",
682 defender->name(DESC_THE).c_str(),
683 defender->conj_verb("are").c_str(),
684 #ifdef DEBUG_DIAGNOSTICS
685 make_stringf(" for %d", damage).c_str(),
689 exclamations.c_str());
692 dprf("constrict at: %s df: %s base %d dur %d ac %d tsc %d inf %d",
693 name(DESC_PLAIN, true).c_str(),
694 defender->name(DESC_PLAIN, true).c_str(),
695 basedam, durdam, acdam, timescale_dam, infdam);
697 if (defender->is_monster()
698 && defender->as_monster()->hit_points < 1)
700 monster_die(defender->as_monster(), this);
705 string actor::describe_props() const
709 if (props.size() == 0)
712 for (auto i = props.begin(); i != props.end(); ++i)
714 if (i != props.begin())
716 oss << string(i->first) << ": ";
718 CrawlStoreValue val = i->second;
720 switch (val.get_type())
723 oss << val.get_bool();
726 oss << val.get_byte();
729 oss << val.get_short();
732 oss << val.get_int();
735 oss << val.get_float();
738 oss << val.get_string();
742 coord_def coord = val.get_coord();
743 oss << "(" << coord.x << ", " << coord.y << ")";
748 monster mon = val.get_monster();
749 oss << mon.name(DESC_PLAIN) << "(" << mon.mid << ")";
753 oss << val.get_int64();
765 * Is the actor currently being slowed by a torpor snail?
767 bool actor::torpor_slowed() const
769 if (!props.exists(TORPOR_SLOWED_KEY) || is_sanctuary(pos())
771 || (is_monster() && as_monster()->check_stasis(true))
772 || (!is_monster() && stasis()))
777 for (monster_near_iterator ri(pos(), LOS_SOLID_SEE); ri; ++ri)
779 const monster *mons = *ri;
780 if (mons && mons->type == MONS_TORPOR_SNAIL
781 && !is_sanctuary(mons->pos())
782 && !mons_aligned(mons, this)
783 && !mons->has_ench(ENCH_CHARM) && mons->attitude == ATT_HOSTILE)
784 // friendly torpor snails are way too abusable otherwise :(
793 string actor::resist_margin_phrase(int margin) const
795 if (res_magic() == MAG_IMMUNE)
796 return " " + conj_verb("are") + " unaffected.";
798 static const string resist_messages[][2] =
800 { " barely %s.", "resist" },
801 { " %s to resist.", "struggle" },
802 { " %s with significant effort.", "resist" },
803 { " %s with some effort.", "resist" },
804 { " easily %s.", "resist" },
805 { " %s with almost no effort.", "resist" },
808 const int index = max(0, min((int)ARRAYSZ(resist_messages) - 1,
809 ((margin + 45) / 15)));
811 return make_stringf(resist_messages[index][0].c_str(),
812 conj_verb(resist_messages[index][1]).c_str());
815 void actor::collide(coord_def newpos, const actor *agent, int pow)
817 actor *other = actor_at(newpos);
818 ASSERT(this != other);
821 if (is_insubstantial())
825 behaviour_event(as_monster(), ME_WHACK, agent);
827 dice_def damage(2, 1 + pow / 10);
829 if (other && other->alive())
831 if (other->is_monster())
832 behaviour_event(other->as_monster(), ME_WHACK, agent);
833 if (you.can_see(this) || you.can_see(other))
835 mprf("%s %s with %s!",
836 name(DESC_THE).c_str(),
837 conj_verb("collide").c_str(),
838 other->name(DESC_THE).c_str());
840 const string thisname = name(DESC_A, true);
841 const string othername = other->name(DESC_A, true);
842 other->hurt(agent, other->apply_ac(damage.roll()),
843 BEAM_MISSILE, KILLED_BY_COLLISION,
844 othername, thisname);
847 hurt(agent, apply_ac(damage.roll()), BEAM_MISSILE,
848 KILLED_BY_COLLISION, thisname, othername);
853 if (you.can_see(this))
855 if (!can_pass_through_feat(grd(newpos)))
857 mprf("%s %s into %s!",
858 name(DESC_THE).c_str(), conj_verb("slam").c_str(),
859 env.map_knowledge(newpos).known()
860 ? feature_description_at(newpos, false, DESC_THE, false)
866 mprf("%s violently %s moving!",
867 name(DESC_THE).c_str(), conj_verb("stop").c_str());
870 hurt(agent, apply_ac(damage.roll()), BEAM_MISSILE,
871 KILLED_BY_COLLISION, "",
872 feature_description_at(newpos, false, DESC_A, false));