diff options
-rw-r--r-- | crawl-ref/source/acr.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.cc | 64 | ||||
-rw-r--r-- | crawl-ref/source/effects.cc | 94 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/fight.cc | 62 | ||||
-rw-r--r-- | crawl-ref/source/it_use3.cc | 10 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 37 | ||||
-rw-r--r-- | crawl-ref/source/monplace.h | 13 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 313 | ||||
-rw-r--r-- | crawl-ref/source/tags.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/tags.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/travel.cc | 4 |
12 files changed, 376 insertions, 235 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 06f82d291d..397abc48dd 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -3516,8 +3516,8 @@ static void _open_door(int move_x, int move_y, bool check_confused) } - you_attack(mgrd[dx][dy], true); you.turn_is_over = true; + you_attack(mgrd[dx][dy], true); if (you.berserk_penalty != NO_BERSERK_PENALTY) you.berserk_penalty = 0; @@ -4075,8 +4075,8 @@ static void _move_player(int move_x, int move_y) // an invisible monster attacks the monster, thus allowing // the player to figure out which adjacent wall an invis // monster is in "for free". - you_attack( targ_monst, true ); you.turn_is_over = true; + you_attack( targ_monst, true ); // We don't want to create a penalty if there isn't // supposed to be one. diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 9e7cbe1c76..c87f158c14 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -1789,8 +1789,8 @@ static bool _make_box(int room_x1, int room_y1, int room_x2, int room_y2, return true; } -// take care of labyrinth, abyss, pandemonium -// returns 1 if we should skip further generation, +// Take care of labyrinth, abyss, pandemonium. +// Returns 1 if we should skip further generation, // -1 if we should immediately quit, and 0 otherwise. static builder_rc_type _builder_by_type(int level_number, char level_type) { @@ -2874,9 +2874,9 @@ static int _place_monster_vector(std::vector<monster_type> montypes, int result = 0; mgen_data mg; - mg.power = level_number; + mg.power = level_number; mg.behaviour = BEH_SLEEP; - mg.flags |= MG_PERMIT_BANDS; + mg.flags |= MG_PERMIT_BANDS; mg.map_mask |= MMT_NO_MONS; for (int i = 0; i < num_to_place; i++) @@ -2962,8 +2962,8 @@ static void _builder_monsters(int level_number, char level_type, int mon_wanted) for (int i = 0; i < mon_wanted; i++) { mgen_data mg; - mg.power = level_number; - mg.flags |= MG_PERMIT_BANDS; + mg.power = level_number; + mg.flags |= MG_PERMIT_BANDS; mg.map_mask |= MMT_NO_MONS; place_monster(mg); @@ -3191,9 +3191,9 @@ static void _fill_monster_pit( spec_room &sr, FixedVector<pit_mons_def, if (lord_type != MONS_PROGRAM_BUG) { mgen_data mg; - mg.cls = lord_type; + mg.cls = lord_type; mg.behaviour = BEH_SLEEP; - mg.pos = coord_def(lordx, lordy); + mg.pos = coord_def(lordx, lordy); mons_place( mgen_data::sleeper_at(lord_type, coord_def(lordx, lordy))); @@ -3218,9 +3218,8 @@ static void _fill_monster_pit( spec_room &sr, FixedVector<pit_mons_def, if (roll < pit_list[i].rare) { mons_place( - mgen_data::sleeper_at( - pit_list[i].type, - coord_def(x, y))); + mgen_data::sleeper_at( pit_list[i].type, + coord_def(x, y))); break; } } @@ -3336,9 +3335,8 @@ static void _special_room(int level_number, spec_room &sr) continue; mons_place( - mgen_data::sleeper_at( - mons_alloc[random2(10)], - coord_def(x, y))); + mgen_data::sleeper_at( mons_alloc[random2(10)], + coord_def(x, y) )); } break; @@ -3372,9 +3370,8 @@ static void _special_room(int level_number, spec_room &sr) continue; mons_place( - mgen_data::sleeper_at( - mons_alloc[random2(10)], - coord_def(x, y) )); + mgen_data::sleeper_at( mons_alloc[random2(10)], + coord_def(x, y) )); } // put the boss monster down @@ -3384,7 +3381,7 @@ static void _special_room(int level_number, spec_room &sr) break; case SROOM_TREASURY: - // should only appear in deep levels, with a guardian + // Should only appear in deep levels, with a guardian // Maybe have several types of treasure room? // place treasure {dlb}: for (x = sr.x1; x <= sr.x2; x++) @@ -3417,7 +3414,8 @@ static void _special_room(int level_number, spec_room &sr) mgen_data::sleeper_at( MONS_GUARDIAN_NAGA, coord_def(sr.x1 + random2( sr.x2 - sr.x1 ), - sr.y1 + random2( sr.y2 - sr.y1 )) )); + sr.y1 + random2( sr.y2 - sr.y1 )), + MG_PATROLLING )); break; case SROOM_BEEHIVE: @@ -3472,15 +3470,16 @@ static void _beehive(spec_room &sr) mons_place( mgen_data::sleeper_at( - one_chance_in(7) ? - MONS_KILLER_BEE_LARVA : MONS_KILLER_BEE, + one_chance_in(7) ? MONS_KILLER_BEE_LARVA + : MONS_KILLER_BEE, coord_def(x, y))); } mons_place( mgen_data::sleeper_at( MONS_QUEEN_BEE, - coord_def(queenx, queeny ))); + coord_def(queenx, queeny ), + MG_PATROLLING)); } // used for placement of vaults @@ -4517,7 +4516,7 @@ bool dgn_place_monster(mons_spec &mspec, if (mspec.mid != -1) { const int mid = mspec.mid; - const bool m_generate_awake = generate_awake || mspec.generate_awake; + const bool m_generate_awake = (generate_awake || mspec.generate_awake); const int mlev = mspec.mlevel; if (mlev) @@ -4541,12 +4540,12 @@ bool dgn_place_monster(mons_spec &mspec, } mgen_data mg(static_cast<monster_type>(mid)); - mg.power = monster_level; - mg.behaviour = m_generate_awake ? BEH_WANDER : BEH_SLEEP; + mg.power = monster_level; + mg.behaviour = (m_generate_awake ? BEH_WANDER : BEH_SLEEP); mg.base_type = mspec.monbase; - mg.number = mspec.number; - mg.colour = mspec.colour; - mg.pos = coord_def(vx, vy); + mg.number = mspec.number; + mg.colour = mspec.colour; + mg.pos = coord_def(vx, vy); const int mindex = place_monster(mg); if (mindex != -1) @@ -4878,8 +4877,8 @@ static int _vault_grid( vault_placement &place, if (vgrid == 'S' || vgrid == 'H') { - const monster_type mtype = - (vgrid == 'H') ? MONS_ORANGE_STATUE : MONS_SILVER_STATUE; + const monster_type mtype = ((vgrid == 'H') ? MONS_ORANGE_STATUE + : MONS_SILVER_STATUE); grd[vx][vy] = DNGN_FLOOR; @@ -6231,10 +6230,7 @@ static void _labyrinth_place_items(const coord_def &end) static void _labyrinth_place_exit(const coord_def &end) { _labyrinth_place_items(end); - mons_place( - mgen_data::sleeper_at( - MONS_MINOTAUR, - end)); + mons_place( mgen_data::sleeper_at(MONS_MINOTAUR, end, MG_PATROLLING) ); grd(end) = DNGN_ESCAPE_HATCH_UP; } diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index 9a49d673fa..e8ef2d8705 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -1902,14 +1902,33 @@ bool recharge_wand(int item_slot) } // end recharge_wand() // Sets foe target of friendly monsters. -static void set_friendly_foes() +// If allow_patrol is true, patrolling monsters get MHITNOT instead. +static void _set_friendly_foes(bool allow_patrol = false) { for (int i = 0; i < MAX_MONSTERS; ++i) { monsters *mon(&menv[i]); if (!mon->alive() || !mons_near(mon) || !mons_friendly(mon)) continue; - mon->foe = you.pet_target; + + mon->foe = (allow_patrol && mon->is_patrolling() ? MHITNOT + : you.pet_target); + } +} + +static void _set_allies_patrol_point(bool clear = false) +{ + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *mon(&menv[i]); + if (!mon->alive() || !mons_near(mon) || !mons_friendly(mon)) + continue; + + mon->patrol_point = (clear ? coord_def(0, 0) + : coord_def(mon->x, mon->y)); + + if (!clear) + mon->behaviour = BEH_WANDER; } } @@ -1986,7 +2005,9 @@ void yell(bool force) } } - mpr(" h - Order allies to stop attacking"); + mpr(" s - Order allies to stop attacking"); + mpr(" w - Order allies to wait here"); + mpr(" f - Order allies to follow you"); } mprf(" Anything else - Stay silent%s", @@ -1996,13 +2017,47 @@ void yell(bool force) switch (keyn) { - case '!': // for players using the old keyset + case '!': // for players using the old keyset case 't': mprf(MSGCH_SOUND, "You %s for attention!", shout_verb.c_str()); you.turn_is_over = true; noisy( noise_level, you.x_pos, you.y_pos ); return; + case 'f': + case 's': + mons_targd = MHITYOU; + if (keyn == 'f') + { + // Don't reset patrol points for 'Stop fighting!' + _set_allies_patrol_point(true); + mpr("Follow me!"); + } + else + mpr("Stop fighting!"); + break; + + case 'w': + mpr("Wait here!"); + mons_targd = MHITNOT; + _set_allies_patrol_point(); + break; + + case 'p': + if (you.duration[DUR_BERSERKER]) + { + canned_msg(MSG_TOO_BERSERK); + return; + } + + if (targ_prev) + { + mons_targd = you.prev_targ; + mpr("Attack!"); + break; + } + + // fall through case 'a': if (you.duration[DUR_BERSERKER]) { @@ -2027,39 +2082,22 @@ void yell(bool force) } mons_targd = mgrd[targ.tx][targ.ty]; + mpr("Attack!"); break; - case 'p': - if (you.duration[DUR_BERSERKER]) - { - canned_msg(MSG_TOO_BERSERK); - return; - } - - if (targ_prev) - { - mons_targd = you.prev_targ; - break; - } - - case 'h': - mons_targd = MHITYOU; - break; - - // fall through... default: mpr("Okely-dokely."); return; } - if (mons_targd != MHITNOT) - { - you.pet_target = mons_targd; - set_friendly_foes(); - } + you.pet_target = mons_targd; + // Allow patrolling for "Stop fighting!" and "Wait here!" + _set_friendly_foes(keyn == 's' || keyn == 'w'); + + if (mons_targd != MHITNOT && mons_targd != MHITYOU) + mpr("Attack!"); noisy( 10, you.x_pos, you.y_pos ); - mpr(mons_targd == MHITYOU ? "Come here!" : "Attack!"); } // end yell() bool forget_inventory(bool quiet) diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 5c70f5e1f5..ed86c042b7 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -1028,6 +1028,7 @@ public: unsigned char y; unsigned char target_x; unsigned char target_y; + coord_def patrol_point; FixedVector<short, NUM_MONSTER_SLOTS> inv; monster_spells spells; mon_attitude_type attitude; @@ -1104,6 +1105,7 @@ public: void timeout_enchantments(int levels); + bool is_patrolling() const; bool needs_transit() const; void set_transit(const level_id &destination); bool find_place_to_live(bool near_player = false); diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index 9fea017008..8a26e078f8 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -357,13 +357,12 @@ melee_attack::melee_attack(actor *attk, actor *defn, void melee_attack::check_hand_half_bonus_eligible() { - hand_half_bonus = - unarmed_ok - && !can_do_unarmed - && !shield - && weapon - && !item_cursed( *weapon ) - && hands == HANDS_HALF; + hand_half_bonus = (unarmed_ok + && !can_do_unarmed + && !shield + && weapon + && !item_cursed( *weapon ) + && hands == HANDS_HALF); } void melee_attack::init_attack() @@ -396,11 +395,11 @@ void melee_attack::init_attack() water_attack = is_water_attack(attacker, defender); attacker_visible = attacker->visible(); - attacker_invisible = !attacker_visible && see_grid(attacker->pos()); - defender_visible = defender && defender->visible(); - defender_invisible = !defender_visible && defender - && see_grid(defender->pos()); - needs_message = attacker_visible || defender_visible; + attacker_invisible = (!attacker_visible && see_grid(attacker->pos())); + defender_visible = (defender && defender->visible()); + defender_invisible = (!defender_visible && defender + && see_grid(defender->pos())); + needs_message = (attacker_visible || defender_visible); if (defender && defender->submerged()) unarmed_ok = false; @@ -607,10 +606,13 @@ bool melee_attack::attack() if (attacker->atype() == ACT_PLAYER) { - if (!stop_attack_prompt(def, false, false)) - set_attack_conducts(def, conduct); - else + if (stop_attack_prompt(def, false, false)) + { cancel_attack = true; + return (false); + } + else + set_attack_conducts(def, conduct); } // Trying to stay general beyond this point is a recipe for insanity. @@ -782,8 +784,8 @@ bool melee_attack::player_attack() if (damage_done > 0) { - int blood = - _modify_blood_amount(damage_done, attacker->damage_type()); + int blood = _modify_blood_amount(damage_done, + attacker->damage_type()); if (blood > defender->stat_hp()) blood = defender->stat_hp(); @@ -3080,8 +3082,8 @@ bool melee_attack::mons_attack_mons() behaviour_event(def, ME_WHACK, monster_index(atk)); } - // if an enemy attacked a friend, set the pet target if it isn't - // set already + // If an enemy attacked a friend, set the pet target if it isn't + // set already. if (perceived_attack && atk->alive() && mons_friendly(def) && !mons_wont_attack(atk) && you.pet_target == MHITNOT) { @@ -3837,8 +3839,8 @@ void melee_attack::mons_perform_attack_rounds() if (defender->atype() == ACT_MONSTER) type = defender->id(); - int blood - = _modify_blood_amount(damage_done, attacker->damage_type()); + int blood = _modify_blood_amount(damage_done, + attacker->damage_type()); if (blood > defender->stat_hp()) blood = defender->stat_hp(); @@ -3983,12 +3985,20 @@ bool you_attack(int monster_attacked, bool unarmed_attacks) wielded_weapon_check(attk.weapon); bool attack = attk.attack(); - if (attack && (is_sanctuary(you.x_pos, you.y_pos) - || is_sanctuary(defender->x, defender->y))) + if (!attack) + { + // Attack was cancelled or unsuccessful... + if (attk.cancel_attack) + you.turn_is_over = false; + return (false); + } + + if (is_sanctuary(you.x_pos, you.y_pos) + || is_sanctuary(defender->x, defender->y)) { remove_sanctuary(true); } - return attack; + return (true); } // Lose attack energy for attacking with a weapon. The monster has already lost @@ -4026,7 +4036,7 @@ bool monster_attack(int monster_attacking) // Friendly and good neutral monsters won't attack unless confused. if (mons_wont_attack(attacker) && !mons_is_confused(attacker)) - return false; + return (false); // In case the monster hasn't noticed you, bumping into it will // change that. @@ -4034,7 +4044,7 @@ bool monster_attack(int monster_attacking) melee_attack attk(attacker, &you); attk.attack(); - return true; + return (true); } // end monster_attack() bool monsters_fight(int monster_attacking, int monster_attacked) diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc index f478c5ee9d..4c8478290c 100644 --- a/crawl-ref/source/it_use3.cc +++ b/crawl-ref/source/it_use3.cc @@ -296,16 +296,16 @@ static bool reaching_weapon_attack(const item_def& wpn) * slips between the squares. */ - // if we're attacking more than a space away - if ((x_distance > 1) || (y_distance > 1)) + // If we're attacking more than a space away... + if (x_distance > 1 || y_distance > 1) { const int x_middle = MAX(beam.tx, you.x_pos) - (x_distance / 2); const int y_middle = MAX(beam.ty, you.y_pos) - (y_distance / 2); - // if either the x or the y is the same, we should check for + // If either the x or the y is the same, we should check for // a monster: - if (((beam.tx == you.x_pos) || (beam.ty == you.y_pos)) - && (mgrd[x_middle][y_middle] != NON_MONSTER)) + if ((beam.tx == you.x_pos || beam.ty == you.y_pos) + && mgrd[x_middle][y_middle] != NON_MONSTER) { const int skill = weapon_skill( wpn.base_type, wpn.sub_type ); diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 5197d2ac2f..edd906743f 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -2214,7 +2214,7 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell ) // life-protected if he has triple life protection. const mon_holy_type holiness = foe->holiness(); return (holiness == MH_UNDEAD || holiness == MH_DEMONIC - || holiness == MH_NONLIVING || holiness == MH_PLANT); + || holiness == MH_NONLIVING || holiness == MH_PLANT); } case SPELL_DISPEL_UNDEAD: @@ -2222,7 +2222,7 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell ) case SPELL_BACKLIGHT: { - ret = !foe || foe->backlit(); + ret = (!foe || foe->backlit()); break; } @@ -2591,10 +2591,11 @@ bool monster_senior(const monsters *m1, const monsters *m2) monsters::monsters() : type(-1), hit_points(0), max_hit_points(0), hit_dice(0), ac(0), ev(0), speed(0), speed_increment(0), x(0), y(0), - target_x(0), target_y(0), inv(NON_ITEM), spells(), attitude(ATT_HOSTILE), - behaviour(BEH_WANDER), foe(MHITYOU), enchantments(), flags(0L), - experience(0), number(0), colour(BLACK), foe_memory(0), shield_blocks(0), - god(GOD_NO_GOD), ghost(), seen_context("") + target_x(0), target_y(0), patrol_point(0, 0), inv(NON_ITEM), spells(), + attitude(ATT_HOSTILE), behaviour(BEH_WANDER), foe(MHITYOU), + enchantments(), flags(0L), experience(0), number(0), colour(BLACK), + foe_memory(0), shield_blocks(0), god(GOD_NO_GOD), ghost(), + seen_context("") { } @@ -2641,6 +2642,7 @@ void monsters::reset() mgrd[x][y] = NON_MONSTER; x = y = 0; + patrol_point = coord_def(0, 0); ghost.reset(NULL); } @@ -2660,6 +2662,7 @@ void monsters::init_with(const monsters &mon) y = mon.y; target_x = mon.target_x; target_y = mon.target_y; + patrol_point = mon.patrol_point; inv = mon.inv; spells = mon.spells; attitude = mon.attitude; @@ -4558,12 +4561,17 @@ void monsters::destroy_inventory() } } +bool monsters::is_patrolling() const +{ + return (patrol_point != coord_def(0, 0)); +} + bool monsters::needs_transit() const { return ((mons_is_unique(type) - || (flags & MF_BANISHED) - || type == MONS_ROYAL_JELLY - || (you.level_type == LEVEL_DUNGEON && hit_dice > 8 + random2(25))) + || (flags & MF_BANISHED) + || type == MONS_ROYAL_JELLY + || you.level_type == LEVEL_DUNGEON && hit_dice > 8 + random2(25)) && !mons_is_summoned(this)); } @@ -4613,7 +4621,7 @@ void monsters::load_spells(mon_spellbook_type book) bool monsters::has_hydra_multi_attack() const { return (type == MONS_HYDRA - || (mons_is_zombified(this) && base_monster == MONS_HYDRA)); + || mons_is_zombified(this) && base_monster == MONS_HYDRA); } bool monsters::has_ench(enchant_type ench) const @@ -4728,9 +4736,9 @@ void monsters::add_enchantment_effect(const mon_enchant &ench, bool quiet) case ENCH_CHARM: behaviour = BEH_SEEK; - target_x = you.x_pos; - target_y = you.y_pos; - foe = MHITYOU; + target_x = you.x_pos; + target_y = you.y_pos; + foe = MHITYOU; break; default: @@ -5572,7 +5580,8 @@ actor *monsters::get_foe() const int monsters::foe_distance() const { const actor *afoe = get_foe(); - return (afoe? pos().distance_from(afoe->pos()) : INFINITE_DISTANCE); + return (afoe ? pos().distance_from(afoe->pos()) + : INFINITE_DISTANCE); } bool monsters::can_go_berserk() const diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h index 6a72bca628..05be654743 100644 --- a/crawl-ref/source/monplace.h +++ b/crawl-ref/source/monplace.h @@ -94,10 +94,11 @@ enum proximity_type // proximity to player to create monster enum mgen_flag_type { - MG_PERMIT_BANDS = 0x1, - MG_FORCE_PLACE = 0x2, - MG_FORCE_BEH = 0x4, - MG_PLAYER_MADE = 0x8 + MG_PERMIT_BANDS = 0x01, + MG_FORCE_PLACE = 0x02, + MG_FORCE_BEH = 0x04, + MG_PLAYER_MADE = 0x08, + MG_PATROLLING = 0x10 }; // A structure with all the data needed to whip up a new monster. @@ -186,6 +187,7 @@ struct mgen_data bool permit_bands() const { return (flags & MG_PERMIT_BANDS); } bool force_place() const { return (flags & MG_FORCE_PLACE); } + bool needs_patrol_point() const { return (flags & MG_PATROLLING); } // Is there a valid position set on this struct that we want to use // when placing the monster? @@ -194,7 +196,8 @@ struct mgen_data bool summoned() const { return (abjuration_duration > 0); } static mgen_data sleeper_at(monster_type what, - const coord_def &where) + const coord_def &where, + unsigned flags = 0) { return mgen_data(what, BEH_SLEEP, 0, where); } diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 5d782c3120..ab4a48d441 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -732,7 +732,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) if (mons_is_caught(monster)) mons_clear_trapping_net(monster); - // update list of monsters beholding player + // Update list of monsters beholding player. update_beholders(monster, true); const int monster_killed = monster_index(monster); @@ -1029,7 +1029,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) MDAM_DEAD); } - // no piety loss if god gifts killed by other monsters + // No piety loss if god gifts killed by other monsters. if (mons_friendly(monster) && !testbits(monster->flags,MF_GOD_GIFT)) { did_god_conduct(DID_FRIEND_DIED, 1 + (monster->hit_dice / 2), @@ -1319,7 +1319,7 @@ void monster_cleanup(monsters *monster) if (you.pet_target == monster_killed) you.pet_target = MHITNOT; -} // end monster_cleanup() +} static bool _jelly_divide(monsters * parent) { @@ -1330,10 +1330,10 @@ static bool _jelly_divide(monsters * parent) if (!mons_class_flag( parent->type, M_SPLITS ) || parent->hit_points == 1) return (false); - // first, find a suitable spot for the child {dlb}: + // First, find a suitable spot for the child {dlb}: for (jex = -1; jex < 3; jex++) { - // loop moves beyond those tiles contiguous to parent {dlb}: + // Loop moves beyond those tiles contiguous to parent {dlb}: if (jex > 1) return (false); @@ -1351,7 +1351,7 @@ static bool _jelly_divide(monsters * parent) if (foundSpot) break; - } // end of for jex + } // end of for jex int k = 0; // must remain outside loop that follows {dlb} @@ -1366,7 +1366,7 @@ static bool _jelly_divide(monsters * parent) return (false); } - // handle impact of split on parent {dlb}: + // Handle impact of split on parent {dlb}: parent->max_hit_points /= 2; if (parent->hit_points > parent->max_hit_points) @@ -1375,11 +1375,11 @@ static bool _jelly_divide(monsters * parent) parent->init_experience(); parent->experience = parent->experience * 3 / 5 + 1; - // create child {dlb}: - // this is terribly partial and really requires + // Create child {dlb}: + // This is terribly partial and really requires // more thought as to generation ... {dlb} *child = *parent; - child->max_hit_points = child->hit_points; + child->max_hit_points = child->hit_points; child->speed_increment = 70 + random2(5); child->x = parent->x + jex; child->y = parent->y + jey; @@ -1395,7 +1395,7 @@ static bool _jelly_divide(monsters * parent) return (true); } // end jelly_divide() -// if you're invis and throw/zap whatever, alerts menv to your position +// If you're invis and throw/zap whatever, alerts menv to your position. void alert_nearby_monsters(void) { monsters *monster = 0; // NULL {dlb} @@ -2028,6 +2028,9 @@ void behaviour_event( monsters *mon, int event, int src, // interesting for a moment. -- bwr if (!isSmart || mon->foe == MHITNOT || mon->behaviour == BEH_WANDER) { + if (mon->is_patrolling()) + break; + mon->target_x = src_x; mon->target_y = src_y; } @@ -2035,13 +2038,13 @@ void behaviour_event( monsters *mon, int event, int src, case ME_WHACK: case ME_ANNOY: - // will turn monster against <src>, unless they + // Will turn monster against <src>, unless they // are BOTH friendly or good neutral AND stupid, // or else fleeing anyway. Hitting someone over // the head, of course, always triggers this code. if (event == ME_WHACK || ((wontAttack != sourceWontAttack || isSmart) - && mon->behaviour != BEH_FLEE && mon->behaviour != BEH_PANIC)) + && mon->behaviour != BEH_FLEE && mon->behaviour != BEH_PANIC)) { // (plain) plants and fungi cannot flee or fight back if (mon->type == MONS_FUNGUS || mon->type == MONS_PLANT) @@ -2059,16 +2062,19 @@ void behaviour_event( monsters *mon, int event, int src, } } - // now set target x,y so that monster can whack - // back (once) at an invisible foe + // Now set target x,y so that monster can whack + // back (once) at an invisible foe. if (event == ME_WHACK) setTarget = true; break; case ME_ALERT: - // will alert monster to <src> and turn them + if (mon->is_patrolling()) + break; + + // Will alert monster to <src> and turn them // against them, unless they have a current foe. - // it won't turn friends hostile either. + // It won't turn friends hostile either. if (mon->behaviour != BEH_CORNERED && mon->behaviour != BEH_PANIC && mon->behaviour != BEH_FLEE) { @@ -2108,7 +2114,7 @@ void behaviour_event( monsters *mon, int event, int src, break; } - // Just set behaviour.. foe doesn't change. + // Just set behaviour... foe doesn't change. if (mon->behaviour != BEH_CORNERED) simple_monster_message(mon, " turns to fight!"); @@ -2135,14 +2141,45 @@ void behaviour_event( monsters *mon, int event, int src, } } - // now, break charms if appropriate + // Now, break charms if appropriate. if (breakCharm) mon->del_ench(ENCH_CHARM); - // do any resultant foe or state changes + // Do any resultant foe or state changes. _handle_behaviour( mon ); } +static bool _choose_random_target_grid_in_los(monsters *mon) +{ + int pos_x, pos_y; + int count_grids = 0; + for (int j = -LOS_RADIUS; j < LOS_RADIUS; j++) + for (int k = -LOS_RADIUS; k < LOS_RADIUS; k++) + { + if (j == 0 && k == 0) + continue; + + pos_x = mon->x + j; + pos_y = mon->y + k; + + if (!in_bounds(pos_x, pos_y)) + continue; + if (!mon->mon_see_grid(pos_x, pos_y)) + continue; + if (!mon->can_pass_through_feat(grd[pos_x][pos_y])) + continue; + + if (one_chance_in(++count_grids)) + { + mon->target_x = pos_x; + mon->target_y = pos_y; + } + } + + return (count_grids); +} + + //--------------------------------------------------------------- // // handle_behaviour @@ -2164,11 +2201,12 @@ static void _handle_behaviour(monsters *mon) bool wontAttack = mons_wont_attack(mon); bool proxPlayer = mons_near(mon); bool proxFoe; - bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1); - bool isHealthy = (mon->hit_points > mon->max_hit_points / 2); - bool isSmart = (mons_intel(mon->type) > I_ANIMAL); - bool isScared = mon->has_ench(ENCH_FEAR); - bool isMobile = !mons_is_stationary(mon); + bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1); + bool isHealthy = (mon->hit_points > mon->max_hit_points / 2); + bool isSmart = (mons_intel(mon->type) > I_ANIMAL); + bool isScared = mon->has_ench(ENCH_FEAR); + bool isMobile = !mons_is_stationary(mon); + bool patrolling = mon->is_patrolling(); // check for confusion -- early out. if (mon->has_ench(ENCH_CONFUSION)) @@ -2178,7 +2216,7 @@ static void _handle_behaviour(monsters *mon) return; } - // validate current target exists + // Validate current target exists. if (mon->foe != MHITNOT && mon->foe != MHITYOU && menv[mon->foe].type == -1) { @@ -2197,15 +2235,15 @@ static void _handle_behaviour(monsters *mon) proxPlayer = false; const int intel = mons_intel(mon->type); - // now, the corollary to that is that sometimes, if a - // player is right next to a monster, they will 'see' + // Now, the corollary to that is that sometimes, if a + // player is right next to a monster, they will 'see'. if (grid_distance( you.x_pos, you.y_pos, mon->x, mon->y ) == 1 && one_chance_in(3)) { proxPlayer = true; } - // [dshaligram] Very smart monsters have a chance of cluing in to + // [dshaligram] Very smart monsters have a chance of clueing in to // invisible players in various ways. else if (intel == I_NORMAL && one_chance_in(13) || intel == I_HIGH && one_chance_in(6)) @@ -2239,7 +2277,7 @@ static void _handle_behaviour(monsters *mon) if (isNeutral && mon->foe == MHITNOT) _set_nearest_monster_foe(mon); - // monsters do not attack themselves {dlb} + // Monsters do not attack themselves. {dlb} if (mon->foe == monster_index(mon)) mon->foe = MHITNOT; @@ -2280,7 +2318,7 @@ static void _handle_behaviour(monsters *mon) int foe_x = you.x_pos; int foe_y = you.y_pos; - // evaluate these each time; they may change + // Evaluate these each time; they may change. if (mon->foe == MHITNOT) proxFoe = false; else @@ -2303,12 +2341,12 @@ static void _handle_behaviour(monsters *mon) } } - // track changes to state; attitude never changes here. - beh_type new_beh = mon->behaviour; + // Track changes to state; attitude never changes here. + beh_type new_beh = mon->behaviour; unsigned int new_foe = mon->foe; // take care of monster state changes - switch(mon->behaviour) + switch (mon->behaviour) { case BEH_SLEEP: // default sleep state @@ -2321,7 +2359,7 @@ static void _handle_behaviour(monsters *mon) // no foe? then wander or seek the player if (mon->foe == MHITNOT) { - if (!proxPlayer || isNeutral) + if (!proxPlayer || isNeutral || patrolling) new_beh = BEH_WANDER; else { @@ -2329,13 +2367,19 @@ static void _handle_behaviour(monsters *mon) mon->target_x = you.x_pos; mon->target_y = you.y_pos; } - break; } // foe gone out of LOS? if (!proxFoe) { + if (patrolling) + { + new_foe = MHITNOT; + new_beh = BEH_WANDER; + break; + } + if (isFriendly) { new_foe = MHITYOU; @@ -2410,11 +2454,11 @@ static void _handle_behaviour(monsters *mon) break; // switch/case BEH_SEEK } - // monster can see foe: continue 'tracking' - // by updating target x,y + // Monster can see foe: continue 'tracking' + // by updating target x,y. if (mon->foe == MHITYOU) { - // sometimes, your friends will wander a bit. + // Sometimes, your friends will wander a bit. if (isFriendly && one_chance_in(8)) { mon->target_x = 10 + random2(GXM - 10); @@ -2439,7 +2483,7 @@ static void _handle_behaviour(monsters *mon) break; case BEH_WANDER: - // is our foe in LOS? + // Is our foe in LOS? // Batty monsters don't automatically reseek so that // they'll flitter away, we'll reset them just before // they get movement in handle_monsters() instead. -- bwr @@ -2462,14 +2506,25 @@ static void _handle_behaviour(monsters *mon) || one_chance_in(20) || testbits( mon->flags, MF_BATTY )) { - mon->target_x = 10 + random2(GXM - 10); - mon->target_y = 10 + random2(GYM - 10); + if (patrolling) + { + if (mon->patrol_point != coord_def(mon->x, mon->y) + || !_choose_random_target_grid_in_los(mon)) + { + mon->target_x = mon->patrol_point.x; + mon->target_y = mon->patrol_point.y; + } + } + else + { + mon->target_x = 10 + random2(GXM - 10); + mon->target_y = 10 + random2(GYM - 10); + } } - // during their wanderings, monsters will - // eventually relax their guard (stupid - // ones will do so faster, smart monsters - // have longer memories + // During their wanderings, monsters will eventually relax their + // guard (stupid ones will do so faster, smart monsters have + // longer memories. if (!proxFoe && mon->foe != MHITNOT && one_chance_in( isSmart ? 60 : 20 )) { @@ -2482,11 +2537,9 @@ static void _handle_behaviour(monsters *mon) if (isHealthy && !isScared) new_beh = BEH_SEEK; - // Smart monsters flee until they can - // flee no more... possible to get a - // 'CORNERED' event, at which point - // we can jump back to WANDER if the foe - // isn't present. + // Smart monsters flee until they can flee no more... + // possible to get a 'CORNERED' event, at which point + // we can jump back to WANDER if the foe isn't present. // XXX: If a monster can move through solid grids, then it // should preferentially flee towards the nearest solid grid @@ -2497,13 +2550,13 @@ static void _handle_behaviour(monsters *mon) if (isFriendly) { - // Special-cased below so that it will flee *towards* you + // Special-cased below so that it will flee *towards* you. mon->target_x = you.x_pos; mon->target_y = you.y_pos; } else if (proxFoe) { - // try to flee _from_ the correct position + // Try to flee _from_ the correct position. mon->target_x = foe_x; mon->target_y = foe_y; } @@ -2516,7 +2569,7 @@ static void _handle_behaviour(monsters *mon) // foe gone out of LOS? if (!proxFoe) { - if ((isFriendly || proxPlayer) && !isNeutral) + if ((isFriendly || proxPlayer) && !isNeutral && !patrolling) new_foe = MHITYOU; else new_beh = BEH_WANDER; @@ -2571,8 +2624,7 @@ static bool _mons_check_set_foe(monsters *mon, int x, int y, return (false); } -// choose nearest monster as a foe -// (used for berserking monsters) +// Choose nearest monster as a foe. (Used for berserking monsters.) void _set_nearest_monster_foe(monsters *mon) { const bool friendly = mons_friendly(mon); @@ -3579,7 +3631,7 @@ static bool _handle_reaching(monsters *monster) { int foe_x = menv[monster->foe].x; int foe_y = menv[monster->foe].y; - // same comments as to invisibility as above. + // Same comments as to invisibility as above. if (monster->target_x == foe_x && monster->target_y == foe_y && monster->mon_see_grid(foe_x, foe_y, true)) { @@ -4526,7 +4578,7 @@ static bool _handle_throw(monsters *monster, bolt & beem) if (one_chance_in(archer? 9 : 5)) return (false); - // don't allow offscreen throwing for now. + // Don't allow offscreen throwing for now. if (monster->foe == MHITYOU && !mons_near(monster)) return (false); @@ -4900,63 +4952,87 @@ static void _handle_monster_move(int i, monsters *monster) } else { - // calculates mmov_x, mmov_y based on monster target. + // Calculates mmov_x, mmov_y based on monster target. _handle_movement(monster); brkk = false; - if (mons_is_confused(monster) - || monster->type == MONS_AIR_ELEMENTAL - && monster->has_ench(ENCH_SUBMERGED)) - { - std::vector<coord_def> moves; - - int pfound = 0; - for (int yi = -1; yi <= 1; ++yi) - for (int xi = -1; xi <= 1; ++xi) - { - coord_def c = monster->pos() + coord_def(xi, yi); - if (in_bounds(c) && monster->can_pass_through(c) - && one_chance_in(++pfound)) - { - mmov_x = xi; - mmov_y = yi; - } - } - - if (random2(2 + pfound) < 2) - mmov_x = mmov_y = 0; - - // Bounds check: don't let confused monsters try to run - // off the map. - if (monster->x + mmov_x < 0 || monster->x + mmov_x >= GXM) - mmov_x = 0; - - if (monster->y + mmov_y < 0 || monster->y + mmov_y >= GYM) - mmov_y = 0; - - if (!monster->can_pass_through(monster->x + mmov_x, - monster->y + mmov_y)) - { - mmov_x = mmov_y = 0; - } - - if (mgrd[monster->x + mmov_x][monster->y + mmov_y] != NON_MONSTER - && !is_sanctuary(monster->x, monster->y) - && (mmov_x != 0 || mmov_y != 0)) - { - monsters_fight(i, - mgrd[monster->x + mmov_x][monster->y + mmov_y]); - - brkk = true; - mmov_x = 0; - mmov_y = 0; - DEBUG_ENERGY_USE("monsters_fight()"); - } - } + if (mons_is_confused(monster) + || monster->type == MONS_AIR_ELEMENTAL + && monster->has_ench(ENCH_SUBMERGED)) + { + std::vector<coord_def> moves; - if (brkk) - continue; + int pfound = 0; + for (int yi = -1; yi <= 1; ++yi) + for (int xi = -1; xi <= 1; ++xi) + { + coord_def c = monster->pos() + coord_def(xi, yi); + if (in_bounds(c) && monster->can_pass_through(c) + && one_chance_in(++pfound)) + { + mmov_x = xi; + mmov_y = yi; + } + } + + if (random2(2 + pfound) < 2) + mmov_x = mmov_y = 0; + + // Bounds check: don't let confused monsters try to run + // off the map. + if (monster->x + mmov_x < 0 || monster->x + mmov_x >= GXM) + mmov_x = 0; + + if (monster->y + mmov_y < 0 || monster->y + mmov_y >= GYM) + mmov_y = 0; + + if (!monster->can_pass_through(monster->x + mmov_x, + monster->y + mmov_y)) + { + mmov_x = mmov_y = 0; + } + + int enemy = mgrd[monster->x + mmov_x][monster->y + mmov_y]; + if (enemy != NON_MONSTER + && !is_sanctuary(monster->x, monster->y) + && (mmov_x != 0 || mmov_y != 0)) + { + if (monsters_fight(i, enemy)) + { + brkk = true; + mmov_x = 0; + mmov_y = 0; + DEBUG_ENERGY_USE("monsters_fight()"); + } + else + { + // FIXME: None of these work! + // Instead run away! + if (monster->add_ench(mon_enchant(ENCH_FEAR))) + { + behaviour_event(monster, ME_SCARE, MHITNOT, + monster->x + mmov_x, + monster->y + mmov_y); + } + break; +/* + if (monster->foe == enemy || mons_friendly(monster) + && monster->foe == MHITYOU) + { + monster->foe = MHITNOT; + monster->behaviour = BEH_WANDER; + } + + monster->target_x = 10 + random2(GXM - 10); + monster->target_y = 10 + random2(GYM - 10); +*/ + } + } + } + + if (brkk) + continue; } _handle_nearby_ability( monster ); @@ -5027,7 +5103,7 @@ static void _handle_monster_move(int i, monsters *monster) && targmon != i && !mons_aligned(i, targmon)) { - // figure out if they fight + // Figure out if they fight. if (monsters_fight(i, targmon)) { if (testbits(monster->flags, MF_BATTY)) @@ -5102,7 +5178,7 @@ static void _handle_monster_move(int i, monsters *monster) } update_beholders(monster); - // reevaluate behaviour, since the monster's + // Reevaluate behaviour, since the monster's // surroundings have changed (it may have moved, // or died for that matter. Don't bother for // dead monsters. :) @@ -5883,13 +5959,13 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x, return false; } - // smacking the player is always a good move if we're - // hostile (even if we're heading somewhere else) - // also friendlies want to keep close to the player - // so it's okay as well + // Smacking the player is always a good move if we're + // hostile (even if we're heading somewhere else). + // Also friendlies want to keep close to the player + // so it's okay as well. - // smacking another monster is good, if the monsters - // are aligned differently + // Smacking another monster is good, if the monsters + // are aligned differently. if (mgrd[targ_x][targ_y] != NON_MONSTER) { if (just_check) @@ -5902,6 +5978,7 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x, const int thismonster = monster_index(monster), targmonster = mgrd[targ_x][targ_y]; + if (mons_aligned(thismonster, targmonster) && targmonster != MHITNOT && targmonster != MHITYOU diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 076405a1ad..8610f3fd9c 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -1770,6 +1770,7 @@ static void marshall_monster(writer &th, const monsters &m) marshallByte(th, m.y); marshallByte(th, m.target_x); marshallByte(th, m.target_y); + marshallCoord(th, m.patrol_point); marshallLong(th, m.flags); marshallLong(th, m.experience); @@ -2030,6 +2031,10 @@ static void unmarshall_monster(reader &th, monsters &m) m.y = unmarshallByte(th); m.target_x = unmarshallByte(th); m.target_y = unmarshallByte(th); + + if (_tag_minor_version >= TAG_MINOR_MPATROL) + unmarshallCoord(th, m.patrol_point); + m.flags = unmarshallLong(th); m.experience = static_cast<unsigned long>(unmarshallLong(th)); diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h index 5b30de1779..ae16aef150 100644 --- a/crawl-ref/source/tags.h +++ b/crawl-ref/source/tags.h @@ -56,7 +56,8 @@ enum tag_minor_version TAG_MINOR_MONNAM = 5, // Monsters get individual names TAG_MINOR_MONBASE = 6, // Zombie base monster gets its own field. TAG_MINOR_FPICKUP = 7, // Added pickup option for allied monsters. - TAG_MINOR_VERSION = 7 // Current version + TAG_MINOR_MPATROL = 8, // Added monster patrol points. + TAG_MINOR_VERSION = 8 // Current version }; diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index e3b8ebe2f7..8be9d2ecc7 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -523,8 +523,8 @@ void init_travel_terrain_check(bool check_race_equip) _set_pass_feature(DNGN_DEEP_WATER, water); // Permanently levitating players can cross most hostile terrain. - const signed char trav = you.permanent_levitation() ? - TRAVERSABLE : IMPASSABLE; + const signed char trav = (you.permanent_levitation() ? TRAVERSABLE + : IMPASSABLE); if (water != TRAVERSABLE) _set_pass_feature(DNGN_DEEP_WATER, trav); |