diff options
39 files changed, 1227 insertions, 1068 deletions
diff --git a/crawl-ref/source/Kills.cc b/crawl-ref/source/Kills.cc index 6402e82f62..7831568323 100644 --- a/crawl-ref/source/Kills.cc +++ b/crawl-ref/source/Kills.cc @@ -612,7 +612,8 @@ kill_monster_desc::kill_monster_desc(const monsters *mon) break; default: break; } - if (modifier != M_NORMAL) monnum = mon->number; + if (modifier != M_NORMAL) + monnum = mon->base_monster; if (mon->has_ench(ENCH_SHAPESHIFTER) || mon->has_ench(ENCH_GLOWING_SHAPESHIFTER)) diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc index 0f97a557a9..1ab70b9a0f 100644 --- a/crawl-ref/source/abl-show.cc +++ b/crawl-ref/source/abl-show.cc @@ -1544,7 +1544,9 @@ static bool _do_ability(const ability_def& abil) case ABIL_MAKHLEB_LESSER_SERVANT_OF_MAKHLEB: summon_ice_beast_etc( 20 + you.skills[SK_INVOCATIONS] * 3, - MONS_NEQOXEC + random2(5), true ); + static_cast<monster_type>( + MONS_NEQOXEC + random2(5)), + true ); exercise(SK_INVOCATIONS, 2 + random2(3)); break; @@ -1601,7 +1603,8 @@ static bool _do_ability(const ability_def& abil) case ABIL_MAKHLEB_GREATER_SERVANT_OF_MAKHLEB: summon_ice_beast_etc( 20 + you.skills[SK_INVOCATIONS] * 3, - MONS_EXECUTIONER + random2(5), + static_cast<monster_type>( + MONS_EXECUTIONER + random2(5)), true ); exercise(SK_INVOCATIONS, 6 + random2(6)); diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc index b1e2741ef5..b53669672a 100644 --- a/crawl-ref/source/abyss.cc +++ b/crawl-ref/source/abyss.cc @@ -433,11 +433,12 @@ void area_shift(void) xom_check_nearness(); + mgen_data mons; + mons.level_type = LEVEL_ABYSS; + mons.proximity = PROX_AWAY_FROM_PLAYER; + for (unsigned int mcount = 0; mcount < 15; mcount++) - { - mons_place( RANDOM_MONSTER, BEH_HOSTILE, MHITNOT, false, 1, 1, - LEVEL_ABYSS, PROX_AWAY_FROM_PLAYER ); // PROX_ANYWHERE? - } + mons_place(mons); // And allow monsters in transit another chance to return. place_transiting_monsters(); @@ -599,8 +600,7 @@ static bool spawn_corrupted_servant_near(const coord_def &pos) one_chance_in(5 + you.skills[SK_INVOCATIONS] / 4)? BEH_HOSTILE : BEH_NEUTRAL; const int mid = - create_monster( mons, 5, beh, p.x, p.y, MHITNOT, MONS_PROGRAM_BUG ); - + create_monster( mgen_data( mons, beh, 5, p ) ); return (mid != -1); } return (false); diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 6244ecea12..9041ba1232 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -2989,7 +2989,9 @@ static void _affect_place_explosion_clouds(bolt &beam, int x, int y) if (grd[x][y] == DNGN_FLOOR && mgrd[x][y] == NON_MONSTER && one_chance_in(4)) { - mons_place( MONS_FIRE_VORTEX, BEH_HOSTILE, MHITNOT, true, x, y ); + mons_place( + mgen_data::hostile_at( + MONS_FIRE_VORTEX, coord_def(x, y))); } } } diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index 247cbfe1f4..527907745b 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -927,10 +927,10 @@ static bool do_description(std::string key, std::string footer = "") case MONS_RED_DRACONIAN: case MONS_WHITE_DRACONIAN: case MONS_PALE_DRACONIAN: - mon.number = mon_num; + mon.base_monster = mon_num; break; default: - mon.number = 0; + mon.base_monster = MONS_PROGRAM_BUG; break; } diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 25c355d1be..6ab2eb2a63 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -394,9 +394,12 @@ void create_spec_monster(void) if (mon == -1) canned_msg( MSG_OK ); else - create_monster( mon, 0, BEH_SLEEP, - you.x_pos, you.y_pos, MHITNOT, MONS_PROGRAM_BUG, - true ); + { + create_monster( + mgen_data::sleeper_at( + static_cast<monster_type>(mon), + you.pos())); + } } // end create_spec_monster() #endif @@ -435,7 +438,7 @@ void create_spec_monster_name(int x, int y) mons_spec mspec = mlist.get_monster(0); if (!force_place && mspec.mid != -1) { - coord_def place = find_newmons_square(mspec.mid, x, y); + coord_def place = find_newmons_square(mspec.mid, coord_def(x, y)); if (in_bounds(place)) { x = place.x; @@ -1431,13 +1434,16 @@ void stethoscope(int mwh) // print stats and other info mprf(MSGCH_DIAGNOSTICS, "HD=%d (%lu) HP=%d/%d AC=%d EV=%d MR=%d SP=%d " - "energy=%d num=%d flags=%04lx", + "energy=%d%s%s num=%d flags=%04lx", menv[i].hit_dice, menv[i].experience, menv[i].hit_points, menv[i].max_hit_points, menv[i].ac, menv[i].ev, mons_resist_magic( &menv[i] ), menv[i].speed, menv[i].speed_increment, + menv[i].base_monster != MONS_PROGRAM_BUG ? " base=" : "", + menv[i].base_monster != MONS_PROGRAM_BUG ? + get_monster_data(menv[i].base_monster)->name : "", menv[i].number, menv[i].flags ); // print behaviour information @@ -2516,8 +2522,10 @@ void error_message_to_player(void) static int create_fsim_monster(int mtype, int hp) { const int mi = - create_monster( mtype, 0, BEH_HOSTILE, you.x_pos, you.y_pos, - MHITNOT, MONS_PROGRAM_BUG ); + create_monster( + mgen_data::hostile_at( + static_cast<monster_type>(mtype), + you.pos() ) ); if (mi == -1) return (mi); diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc index 14c67f1a8e..ceb76498d7 100644 --- a/crawl-ref/source/decks.cc +++ b/crawl-ref/source/decks.cc @@ -2307,9 +2307,9 @@ static bool _trowel_card(int power, deck_rarity_type rarity) MONS_ORANGE_STATUE, MONS_SILVER_STATUE, MONS_ICE_STATUE }; - if ( create_monster(RANDOM_ELEMENT(statues), 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG) != -1 ) + if (create_monster( + mgen_data(RANDOM_ELEMENT(statues), + BEH_HOSTILE, 0, you.pos(), MHITYOU)) != -1) { mpr("A menacing statue appears!"); num_made++; @@ -2320,9 +2320,10 @@ static bool _trowel_card(int power, deck_rarity_type rarity) MONS_IRON_GOLEM, MONS_CRYSTAL_GOLEM, MONS_TOENAIL_GOLEM }; - if ( create_monster(RANDOM_ELEMENT(golems), 5, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG) != -1 ) + if (create_monster( + mgen_data( RANDOM_ELEMENT(golems), + BEH_FRIENDLY, 5, you.pos(), + you.pet_target )) != -1) { mpr("You construct a golem!"); num_made++; @@ -2489,9 +2490,10 @@ static void _summon_demon_card(int power, deck_rarity_type rarity) else dct = DEMON_LESSER; - create_monster( summon_any_demon(dct), std::min(power/50,6), - BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data( summon_any_demon(dct), BEH_FRIENDLY, + std::min(power / 50, 6), + you.pos(), you.pet_target )); } static void _summon_any_monster(int power, deck_rarity_type rarity) @@ -2539,11 +2541,11 @@ static void _summon_any_monster(int power, deck_rarity_type rarity) const bool friendly = (power_level > 0 || !one_chance_in(4)); - create_monster( mon_chosen, 3, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - chosen_x, chosen_y, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data( mon_chosen, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, + 3, coord_def(chosen_x, chosen_y), + MHITYOU ) ); } static void _summon_dancing_weapon(int power, deck_rarity_type rarity) @@ -2551,12 +2553,12 @@ static void _summon_dancing_weapon(int power, deck_rarity_type rarity) const int power_level = get_power_level(power, rarity); const bool friendly = (power_level > 0 || !one_chance_in(4)); - const int mon = create_monster( MONS_DANCING_WEAPON, power_level + 3, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - you.x_pos, you.y_pos, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG, false, false, false, - true ); + const int mon = + create_monster( + mgen_data( MONS_DANCING_WEAPON, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, + power_level + 3, you.pos(), + friendly ? you.pet_target : MHITYOU )); // Given the abundance of Nemelex decks, not setting hard reset // leaves a trail of weapons behind, most of which just get @@ -2624,11 +2626,12 @@ static void _summon_flying(int power, deck_rarity_type rarity) for ( int i = 0; i < power_level * 5 + 2; ++i ) { - create_monster(result, std::min(power/50, 6), + create_monster( + mgen_data( result, friendly ? BEH_FRIENDLY : BEH_HOSTILE, - you.x_pos, you.y_pos, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG); + std::min(power/50, 6), + you.pos(), + friendly ? you.pet_target : MHITYOU )); } } @@ -2640,11 +2643,13 @@ static void _summon_skeleton(int power, deck_rarity_type rarity) MONS_SKELETON_LARGE, MONS_SKELETAL_WARRIOR, MONS_SKELETAL_DRAGON }; - create_monster(skeltypes[power_level], std::min(power/50,6), - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - you.x_pos, you.y_pos, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG); + create_monster( + mgen_data( + skeltypes[power_level], + friendly ? BEH_FRIENDLY : BEH_HOSTILE, + std::min(power/50,6), + you.pos(), + friendly ? you.pet_target : MHITYOU )); } static void _summon_ugly(int power, deck_rarity_type rarity) @@ -2659,11 +2664,12 @@ static void _summon_ugly(int power, deck_rarity_type rarity) else ugly = MONS_UGLY_THING; - create_monster(ugly, std::min(power/50,6), + create_monster( + mgen_data( ugly, friendly ? BEH_FRIENDLY : BEH_HOSTILE, - you.x_pos, you.y_pos, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG); + std::min(power/50,6), + you.pos(), + friendly ? you.pet_target : MHITYOU)); } static int _card_power(deck_rarity_type rarity) diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc index e1ef6b8547..18ff4e67d2 100644 --- a/crawl-ref/source/directn.cc +++ b/crawl-ref/source/directn.cc @@ -2073,11 +2073,11 @@ static void describe_monster(const monsters *mon) if (player_beheld_by(mon)) mpr("You are beheld by her song.", MSGCH_EXAMINE); - if (mon->type == MONS_HYDRA) - { + // XXX: Not strictly correct if we add any other monster with a + // variable number of attacks. + if (mon->has_hydra_multi_attack()) mprf(MSGCH_EXAMINE, "It has %d head%s.", mon->number, (mon->number > 1? "s" : "")); - } print_wounds(mon); diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index e2db1acb61..f7a1c55901 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -79,7 +79,7 @@ struct pit_mons_def { - int type; + monster_type type; int rare; }; @@ -759,7 +759,7 @@ static void _reset_level() menv[i].type = -1; for (int i = 0; i < 20; i++) - env.mons_alloc[i] = -1; + env.mons_alloc[i] = MONS_PROGRAM_BUG; mgrd.init(NON_MONSTER); igrd.init(NON_ITEM); @@ -2773,7 +2773,7 @@ static bool _make_room(int sx,int sy,int ex,int ey,int max_doors, int doorlevel) return true; } //end make_room() -static int _pick_unique(int lev) +static monster_type _pick_unique(int lev) { int which_unique = ((lev > 19) ? random_range(MONS_LOUISE, MONS_BORIS) : @@ -2796,7 +2796,7 @@ static int _pick_unique(int lev) which_unique = MONS_POLYPHEMUS; } - return (which_unique); + return static_cast<monster_type>(which_unique); } // Place uniques on the level. @@ -2817,14 +2817,15 @@ static int _place_uniques(int level_number, char level_type) while (one_chance_in(3)) { - int which_unique = -1; // 30 in total + monster_type which_unique = MONS_PROGRAM_BUG; // 30 in total - while (which_unique < 0 || you.unique_creatures[which_unique]) + while (which_unique == MONS_PROGRAM_BUG + || you.unique_creatures[which_unique]) { // sometimes, we just quit if a unique is already placed. - if (which_unique >= 0 && !one_chance_in(3)) + if (which_unique != MONS_PROGRAM_BUG && !one_chance_in(3)) { - which_unique = -1; + which_unique = MONS_PROGRAM_BUG; break; } @@ -2833,13 +2834,16 @@ static int _place_uniques(int level_number, char level_type) // usually, we'll have quit after a few tries. Make sure we don't // create unique[-1] by accident. - if (which_unique == -1) + if (which_unique == MONS_PROGRAM_BUG) break; - // note: unique_creatures 40 + used by unique demons - if (place_monster( not_used, which_unique, level_number, - BEH_SLEEP, MHITNOT, false, 1, 1, true, - PROX_ANYWHERE, MONS_PROGRAM_BUG, 0, MMT_NO_MONS )) + mgen_data mg( which_unique, BEH_SLEEP, 0, + coord_def(), MHITNOT, MG_PERMIT_BANDS, + MONS_PROGRAM_BUG, 0, BLACK, + level_number, PROX_ANYWHERE ); + mg.map_mask = MMT_NO_MONS; + + if (place_monster(mg) != -1) { #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Placed %s", @@ -2851,19 +2855,23 @@ static int _place_uniques(int level_number, char level_type) return num_placed; } -static int _place_monster_vector(std::vector<int> montypes, +static int _place_monster_vector(std::vector<monster_type> montypes, int level_number, int num_to_place) { int result = 0; - int not_used = 0; + + mgen_data mg; + mg.power = level_number; + mg.behaviour = BEH_SLEEP; + mg.flags |= MG_PERMIT_BANDS; + mg.map_mask |= MMT_NO_MONS; + for (int i = 0; i < num_to_place; i++) - if (place_monster( not_used, montypes[random2(montypes.size())], - level_number, BEH_SLEEP, MHITNOT, - false, 1, 1, true, PROX_ANYWHERE, - MONS_PROGRAM_BUG, 0, MMT_NO_MONS )) - { + { + mg.cls = montypes[random2(montypes.size())]; + if (place_monster(mg) != -1) ++result; - } + } return result; } @@ -2872,7 +2880,7 @@ static int _place_monster_vector(std::vector<int> montypes, static void _place_aquatic_monsters(int level_number, char level_type) { int lava_spaces = 0, water_spaces = 0; - std::vector<int> swimming_things(4u, NON_MONSTER); + std::vector<monster_type> swimming_things(4u, MONS_PROGRAM_BUG); // count the number of lava and water tiles {dlb}: for (int x = 0; x < GXM; x++) @@ -2888,21 +2896,24 @@ static void _place_aquatic_monsters(int level_number, char level_type) { for (int i = 0; i < 4; i++) { - swimming_things[i] = MONS_LAVA_WORM + random2(3); + swimming_things[i] = + static_cast<monster_type>( + MONS_LAVA_WORM + random2(3) ); if (one_chance_in(30)) swimming_things[i] = MONS_SALAMANDER; } _place_monster_vector(swimming_things, level_number, std::min(random2avg(9, 2) - + (random2(lava_spaces) / 10), 15)); + + (random2(lava_spaces) / 10), 15)); } if (water_spaces > 49) { for (int i = 0; i < 4; i++) { - swimming_things[i] = MONS_BIG_FISH + random2(4); + swimming_things[i] = + static_cast<monster_type>(MONS_BIG_FISH + random2(4)); if (player_in_branch( BRANCH_SWAMP ) && !one_chance_in(3)) swimming_things[i] = MONS_SWAMP_WORM; else if (player_in_branch( BRANCH_SHOALS )) @@ -2929,7 +2940,6 @@ static void _place_aquatic_monsters(int level_number, char level_type) static void _builder_monsters(int level_number, char level_type, int mon_wanted) { - int not_used = 0; if (level_type == LEVEL_PANDEMONIUM || player_in_branch(BRANCH_ECUMENICAL_TEMPLE)) { @@ -2938,9 +2948,12 @@ static void _builder_monsters(int level_number, char level_type, int mon_wanted) for (int i = 0; i < mon_wanted; i++) { - place_monster( not_used, RANDOM_MONSTER, level_number, BEH_SLEEP, - MHITNOT, false, 1, 1, true, PROX_ANYWHERE, - MONS_PROGRAM_BUG, 0, MMT_NO_MONS ); + mgen_data mg; + mg.power = level_number; + mg.flags |= MG_PERMIT_BANDS; + mg.map_mask |= MMT_NO_MONS; + + place_monster(mg); } _place_uniques(level_number, level_type); @@ -2950,10 +2963,10 @@ static void _builder_monsters(int level_number, char level_type, int mon_wanted) else { if (one_chance_in(3)) - mons_place( MONS_CURSE_SKULL, BEH_SLEEP, MHITNOT, false, 0, 0 ); + mons_place( mgen_data( MONS_CURSE_SKULL, BEH_SLEEP ) ); if (one_chance_in(7)) - mons_place( MONS_CURSE_SKULL, BEH_SLEEP, MHITNOT, false, 0, 0 ); + mons_place( mgen_data( MONS_CURSE_SKULL, BEH_SLEEP ) ); } } @@ -3127,7 +3140,7 @@ static void _specr_2(spec_room &sr) // then place a "lord of the pit" of lord_type at (lordx, lordy). static void _fill_monster_pit( spec_room &sr, FixedVector<pit_mons_def, MAX_PIT_MONSTERS> &pit_list, int density, - int lord_type, int lordx, int lordy ) + monster_type lord_type, int lordx, int lordy ) { int i, x, y; @@ -3163,7 +3176,15 @@ static void _fill_monster_pit( spec_room &sr, FixedVector<pit_mons_def, // put the boss monster down if (lord_type != MONS_PROGRAM_BUG) - mons_place( lord_type, BEH_SLEEP, MHITNOT, true, lordx, lordy ); + { + mgen_data mg; + mg.cls = lord_type; + mg.behaviour = BEH_SLEEP; + mg.pos = coord_def(lordx, lordy); + + mons_place( + mgen_data::sleeper_at(lord_type, coord_def(lordx, lordy))); + } // place monsters and give them items {dlb}: for (x = sr.x1; x <= sr.x2; x++) @@ -3183,8 +3204,10 @@ static void _fill_monster_pit( spec_room &sr, FixedVector<pit_mons_def, for (i = 0; i < num_types; i++) if (roll < pit_list[i].rare) { - mons_place( pit_list[i].type, BEH_SLEEP, MHITNOT, - true, x, y ); + mons_place( + mgen_data::sleeper_at( + pit_list[i].type, + coord_def(x, y))); break; } } @@ -3201,7 +3224,7 @@ static void _special_room(int level_number, spec_room &sr) unsigned char i; // general purpose loop variable {dlb} int temp_rand = 0; // probability determination {dlb} - FixedVector < int, 10 > mons_alloc; // was [20] {dlb} + FixedVector < monster_type, 10 > mons_alloc; // was [20] {dlb} char lordx = 0, lordy = 0; @@ -3299,8 +3322,10 @@ static void _special_room(int level_number, spec_room &sr) if (one_chance_in(4)) continue; - mons_place( mons_alloc[random2(10)], BEH_SLEEP, MHITNOT, - true, x, y ); + mons_place( + mgen_data::sleeper_at( + mons_alloc[random2(10)], + coord_def(x, y))); } break; @@ -3333,13 +3358,16 @@ static void _special_room(int level_number, spec_room &sr) if (x == lordx && y == lordy) continue; - mons_place( mons_alloc[random2(10)], BEH_SLEEP, MHITNOT, - true, x, y ); + mons_place( + mgen_data::sleeper_at( + mons_alloc[random2(10)], + coord_def(x, y) )); } // put the boss monster down - mons_place( MONS_BIG_KOBOLD, BEH_SLEEP, MHITNOT, true, lordx, lordy ); - + mons_place( + mgen_data::sleeper_at( MONS_BIG_KOBOLD, + coord_def(lordx, lordy) )); break; case SROOM_TREASURY: @@ -3372,9 +3400,11 @@ static void _special_room(int level_number, spec_room &sr) } // place guardian {dlb}: - mons_place( MONS_GUARDIAN_NAGA, BEH_SLEEP, MHITNOT, true, - sr.x1 + random2( sr.x2 - sr.x1 ), - sr.y1 + random2( sr.y2 - sr.y1 ) ); + mons_place( + mgen_data::sleeper_at( + MONS_GUARDIAN_NAGA, + coord_def(sr.x1 + random2( sr.x2 - sr.x1 ), + sr.y1 + random2( sr.y2 - sr.y1 )) )); break; case SROOM_BEEHIVE: @@ -3427,13 +3457,18 @@ static void _beehive(spec_room &sr) // the hive is chock full of bees! - mons_place( one_chance_in(7) ? MONS_KILLER_BEE_LARVA - : MONS_KILLER_BEE, - BEH_SLEEP, MHITNOT, true, x, y ); + mons_place( + mgen_data::sleeper_at( + one_chance_in(7) ? + MONS_KILLER_BEE_LARVA : MONS_KILLER_BEE, + coord_def(x, y))); } - mons_place( MONS_QUEEN_BEE, BEH_SLEEP, MHITNOT, true, queenx, queeny ); -} // end beehive() + mons_place( + mgen_data::sleeper_at( + MONS_QUEEN_BEE, + coord_def(queenx, queeny ))); +} // used for placement of vaults static bool _may_overwrite_feature(const dungeon_feature_type grid, @@ -4490,22 +4525,21 @@ bool dgn_place_monster(mons_spec &mspec, grd[vx][vy] = habitat2grid(habitat); } - int mindex = NON_MONSTER; - const bool placed - = place_monster( mindex, mid, monster_level, - m_generate_awake ? BEH_WANDER : BEH_SLEEP, - MHITNOT, true, vx, vy, false, - PROX_ANYWHERE, mspec.monnum); + mgen_data mg(static_cast<monster_type>(mid)); + 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); - if (placed && mindex != -1 && mindex != NON_MONSTER) + const int mindex = place_monster(mg); + if (mindex != -1) { - if (mspec.colour != BLACK) - menv[mindex].colour = mspec.colour; - if (mspec.items.size() > 0) _dgn_give_mon_spec_items(mspec, mindex, mid, monster_level); } - return (placed); + return (mindex != -1); } return (false); } @@ -4618,8 +4652,6 @@ static int _vault_grid( vault_placement &place, int rune_subst, bool following ) { - int not_used; - keyed_mapspec *mapsp = following? NULL : place.map.mapspec_for_key(vgrid); if (mapsp) { @@ -4661,8 +4693,8 @@ static int _vault_grid( vault_placement &place, if (vgrid == 'F' && one_chance_in(100)) { vgrid = '.'; - place_monster( not_used, _random_evil_statue(), 30, BEH_HOSTILE, - MHITNOT, true, vx, vy, false); + create_monster( + mgen_data::hostile_at( _random_evil_statue(), coord_def(vx, vy) )); } // first, set base tile for grids {dlb}: @@ -4831,13 +4863,13 @@ static int _vault_grid( vault_placement &place, if (vgrid == 'S' || vgrid == 'H') { - const int 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; - place_monster( not_used, mtype, 30, BEH_HOSTILE, - MHITNOT, true, vx, vy, false); + create_monster( + mgen_data::hostile_at( mtype, coord_def(vx, vy) )); } // finally, handle grids that place monsters {dlb}: @@ -6241,7 +6273,10 @@ static void _labyrinth_place_items(const coord_def &end) static void _labyrinth_place_exit(const coord_def &end) { _labyrinth_place_items(end); - mons_place( MONS_MINOTAUR, BEH_SLEEP, MHITNOT, true, end.x, end.y ); + mons_place( + mgen_data::sleeper_at( + MONS_MINOTAUR, + end)); grd(end) = DNGN_ESCAPE_HATCH_UP; } @@ -7115,16 +7150,18 @@ static void _morgue(spec_room &sr) for (y = sr.y1; y <= sr.y2; y++) if (grd[x][y] == DNGN_FLOOR || grd[x][y] == DNGN_BUILDER_SPECIAL_FLOOR) { - int mon_type; temp_rand = random2(24); - mon_type = ((temp_rand > 11) ? MONS_ZOMBIE_SMALL : // 50.0% - (temp_rand > 7) ? MONS_WIGHT : // 16.7% - (temp_rand > 3) ? MONS_NECROPHAGE : // 16.7% - (temp_rand > 0) ? MONS_WRAITH // 12.5% - : MONS_VAMPIRE); // 4.2% + const monster_type mon_type = + ((temp_rand > 11) ? MONS_ZOMBIE_SMALL : // 50.0% + (temp_rand > 7) ? MONS_WIGHT : // 16.7% + (temp_rand > 3) ? MONS_NECROPHAGE : // 16.7% + (temp_rand > 0) ? MONS_WRAITH // 12.5% + : MONS_VAMPIRE); // 4.2% - mons_place( mon_type, BEH_SLEEP, MHITNOT, true, x, y ); + mons_place( + mgen_data::sleeper_at( + mon_type, coord_def(x, y) )); } } // end morgue() @@ -7205,203 +7242,6 @@ bool place_specific_trap(int spec_x, int spec_y, trap_type spec_type) return false; } // end place_specific_trap() -void define_zombie( int mid, int ztype, int cs, int power ) -{ - int mons_sec2 = 0; - int zombie_size = 0; - bool ignore_rarity = false; - int test, cls; - - if (power > 27) - power = 27; - - // set size based on zombie class (cs) - switch(cs) - { - case MONS_ZOMBIE_SMALL: - case MONS_SIMULACRUM_SMALL: - case MONS_SKELETON_SMALL: - zombie_size = Z_SMALL; - break; - - case MONS_ZOMBIE_LARGE: - case MONS_SIMULACRUM_LARGE: - case MONS_SKELETON_LARGE: - zombie_size = Z_BIG; - break; - - case MONS_SPECTRAL_THING: - zombie_size = -1; - break; - - default: - // this should NEVER happen. - perror("\ncreate_zombie() got passed incorrect zombie type!\n"); - end(0); - break; - } - - // that is, random creature from which to fashion undead - if (ztype == MONS_PROGRAM_BUG) - { - // how OOD this zombie can be. - int relax = 5; - - // pick an appropriate creature to make a zombie out of, - // levelwise. The old code was generating absolutely - // incredible OOD zombies. - while (true) - { - // this limit can be updated if mons->number goes >8 bits.. - test = random2(182); // not guaranteed to be valid, so.. - cls = mons_species(test); - if (cls == MONS_PROGRAM_BUG) - continue; - - // on certain branches, zombie creation will fail if we use - // the mons_rarity() functions, because (for example) there - // are NO zombifiable "native" abyss creatures. Other branches - // where this is a problem are hell levels and the crypt. - // we have to watch for summoned zombies on other levels, too, - // such as the Temple, HoB, and Slime Pits. - if (you.level_type != LEVEL_DUNGEON - || player_in_hell() - || player_in_branch( BRANCH_HALL_OF_ZOT ) - || player_in_branch( BRANCH_VESTIBULE_OF_HELL ) - || player_in_branch( BRANCH_ECUMENICAL_TEMPLE ) - || player_in_branch( BRANCH_CRYPT ) - || player_in_branch( BRANCH_TOMB ) - || player_in_branch( BRANCH_HALL_OF_BLADES ) - || player_in_branch( BRANCH_SNAKE_PIT ) - || player_in_branch( BRANCH_SLIME_PITS ) - || one_chance_in(1000)) - { - ignore_rarity = true; - } - - // don't make out-of-rarity zombies when we don't have to - if (!ignore_rarity && mons_rarity(cls) == 0) - continue; - - // monster class must be zombifiable - if (!mons_zombie_size(cls)) - continue; - - // if skeleton, monster must have a skeleton - if ((cs == MONS_SKELETON_SMALL || cs == MONS_SKELETON_LARGE) - && !mons_skeleton(cls)) - { - continue; - } - - // size must match, but you can make a spectral thing out of anything. - if (mons_zombie_size(cls) != zombie_size && zombie_size != -1) - continue; - - // hack -- non-dungeon zombies are always made out of nastier - // monsters - if (you.level_type != LEVEL_DUNGEON && mons_power(cls) > 8) - break; - - // check for rarity.. and OOD - identical to mons_place() - int level, diff, chance; - - level = mons_level( cls ) - 4; - diff = level - power; - - chance = (ignore_rarity) ? 100 - : mons_rarity(cls) - (diff * diff) / 2; - - if (power > level - relax && power < level + relax - && random2avg(100, 2) <= chance) - { - break; - } - - // every so often, we'll relax the OOD restrictions. Avoids - // infinite loops (if we don't do this, things like creating - // a large skeleton on level 1 may hang the game!) - if (one_chance_in(5)) - relax++; - } - - // set type and secondary appropriately - menv[mid].number = cls; - mons_sec2 = cls; - } - else - { - menv[mid].number = mons_species(ztype); - mons_sec2 = menv[mid].number; - } - - menv[mid].type = menv[mid].number; - - define_monster(mid); - - menv[mid].hit_points = hit_points( menv[mid].hit_dice, 6, 5 ); - menv[mid].max_hit_points = menv[mid].hit_points; - - menv[mid].ac -= 2; - - if (menv[mid].ac < 0) - menv[mid].ac = 0; - - menv[mid].ev -= 5; - - if (menv[mid].ev < 0) - menv[mid].ev = 0; - - menv[mid].speed -= 2; - - if (menv[mid].speed < 3) - menv[mid].speed = 3; - - menv[mid].speed_increment = 70; - - if (cs == MONS_ZOMBIE_SMALL || cs == MONS_ZOMBIE_LARGE) - { - menv[mid].type = ((mons_zombie_size(menv[mid].number) == Z_BIG) - ? MONS_ZOMBIE_LARGE : MONS_ZOMBIE_SMALL); - } - else if (cs == MONS_SKELETON_SMALL || cs == MONS_SKELETON_LARGE) - { - menv[mid].hit_points = hit_points( menv[mid].hit_dice, 5, 4 ); - menv[mid].max_hit_points = menv[mid].hit_points; - - menv[mid].ac -= 4; - - if (menv[mid].ac < 0) - menv[mid].ac = 0; - - menv[mid].ev -= 2; - - if (menv[mid].ev < 0) - menv[mid].ev = 0; - - menv[mid].type = ((mons_zombie_size( menv[mid].number ) == Z_BIG) - ? MONS_SKELETON_LARGE : MONS_SKELETON_SMALL); - } - else if (cs == MONS_SIMULACRUM_SMALL || cs == MONS_SIMULACRUM_LARGE) - { - // Simulacrum aren't tough, but you can create piles of them. -- bwr - menv[mid].hit_points = hit_points( menv[mid].hit_dice, 1, 4 ); - menv[mid].max_hit_points = menv[mid].hit_points; - menv[mid].type = ((mons_zombie_size( menv[mid].number ) == Z_BIG) - ? MONS_SIMULACRUM_LARGE : MONS_SIMULACRUM_SMALL); - } - else if (cs == MONS_SPECTRAL_THING) - { - menv[mid].hit_points = hit_points( menv[mid].hit_dice, 4, 4 ); - menv[mid].max_hit_points = menv[mid].hit_points; - menv[mid].ac += 4; - menv[mid].type = MONS_SPECTRAL_THING; - } - - menv[mid].number = mons_sec2; - menv[mid].colour = mons_class_colour(cs); -} // end define_zombie() - static void _build_river( dungeon_feature_type river_type ) //mv { int i,j; diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index d5da281228..b1fe5f3c59 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -311,7 +311,6 @@ bool dgn_place_map(int map, bool generating_level, bool clobber, const coord_def &pos = coord_def(-1, -1)); void level_clear_vault_memory(); void level_welcome_messages(); -void define_zombie(int mid, int ztype, int cs, int power); bool is_wall(int feature); bool place_specific_trap(int spec_x, int spec_y, trap_type spec_type); void place_spec_shop(int level_number, int shop_x, int shop_y, diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index e5cf28d11c..b68dda8cd7 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -2232,8 +2232,8 @@ static void hell_effects() if (summon_instead) { - create_monster( which_beastie, 0, BEH_HOSTILE, you.x_pos, - you.y_pos, MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data( which_beastie, BEH_HOSTILE, 0, you.pos(), MHITYOU )); } else { @@ -2250,18 +2250,14 @@ static void hell_effects() // try to summon at least one and up to five random monsters {dlb} if (one_chance_in(3)) { - create_monster( RANDOM_MONSTER, 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, MONS_PROGRAM_BUG ); + mgen_data mg; + mg.pos = you.pos(); + mg.foe = MHITYOU; + create_monster(mg); for (int i = 0; i < 4; i++) - { if (one_chance_in(3)) - { - create_monster( RANDOM_MONSTER, 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG ); - } - } + create_monster(mg); } } diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index d0d3349e4e..da0067ad31 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -1037,6 +1037,7 @@ public: unsigned long flags; // bitfield of boolean flags unsigned long experience; + monster_type base_monster; // zombie base monster, draconian colour unsigned int number; // #heads (hydra), etc. int colour; @@ -1076,6 +1077,9 @@ public: int foe_distance() const; bool needs_berserk(bool check_spells = true) const; + // Has a hydra-like variable number of attacks based on mons->number. + bool has_hydra_multi_attack() const; + bool has_ench(enchant_type ench) const; bool has_ench(enchant_type ench, enchant_type ench2) const; mon_enchant get_ench(enchant_type ench, @@ -1414,7 +1418,7 @@ public: FixedVector< shop_struct, MAX_SHOPS > shop; // shop list FixedVector< trap_struct, MAX_TRAPS > trap; // trap list - FixedVector< int, 20 > mons_alloc; + FixedVector< monster_type, 20 > mons_alloc; map_markers markers; double elapsed_time; // used during level load diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index 0002593197..d371ec79a9 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -2343,16 +2343,20 @@ bool melee_attack::chop_hydra_head( int dam, def_name(DESC_NOCAP_THE).c_str() ); } - if (wpn_brand == SPWPN_FLAMING) + // Only living hydras get to regenerate heads. + if (defender->holiness() == MH_NATURAL) { - if (defender_visible) - mpr( "The flame cauterises the wound!" ); - } - else if (def->number < 19) - { - simple_monster_message( def, " grows two more!" ); - def->number += 2; - heal_monster( def, 8 + random2(8), true ); + if (wpn_brand == SPWPN_FLAMING) + { + if (defender_visible) + mpr( "The flame cauterises the wound!" ); + } + else if (def->number < 19) + { + simple_monster_message( def, " grows two more!" ); + def->number += 2; + heal_monster( def, 8 + random2(8), true ); + } } } @@ -2364,7 +2368,7 @@ bool melee_attack::chop_hydra_head( int dam, bool melee_attack::decapitate_hydra(int dam, int damage_type) { - if (defender->id() == MONS_HYDRA) + if (defender->atype() == ACT_MONSTER && def->has_hydra_multi_attack()) { const int dam_type = (damage_type != -1) ? damage_type : attacker->damage_type(); @@ -3723,7 +3727,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk) void melee_attack::mons_perform_attack_rounds() { - const int nrounds = atk->type == MONS_HYDRA? atk->number : 4; + const int nrounds = atk->has_hydra_multi_attack()? atk->number : 4; const coord_def pos = defender->pos(); // Melee combat, tell attacker to wield its melee weapon. diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc index fdce0be304..d9521e419c 100644 --- a/crawl-ref/source/hiscores.cc +++ b/crawl-ref/source/hiscores.cc @@ -788,7 +788,7 @@ void scorefile_entry::init_death_cause(int dam, int dsrc, if (monster->type >= 0 && monster->type < NUM_MONSTERS) { death_source = monster->type; - mon_num = monster->number; + mon_num = monster->base_monster; // Previously the weapon was only used for dancing weapons, // but now we pass it in as a string through the scorefile diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc index 7ca11eb85b..f3e63901b0 100644 --- a/crawl-ref/source/it_use3.cc +++ b/crawl-ref/source/it_use3.cc @@ -225,9 +225,9 @@ void special_wielded() if (random2(8) <= player_spec_death()) { did_god_conduct( DID_NECROMANCY, 1 ); - create_monster( MONS_SHADOW, 2, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data(MONS_SHADOW, BEH_FRIENDLY, + 2, you.pos(), you.pet_target)); } show_green = DARKGREY; @@ -370,10 +370,9 @@ static bool evoke_horn_of_geryon() else { mpr("You produce a hideous howling noise!"); - create_monster( MONS_BEAST, 4, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG, - false, false, false, true ); + create_monster( + mgen_data( MONS_BEAST, BEH_HOSTILE, + 4, you.pos(), MHITYOU )); } return rc; } @@ -389,9 +388,9 @@ static bool evoke_sceptre_of_asmodeus() const monster_type mtype = (one_chance_in(4) ? MONS_FIEND : summon_any_demon(DEMON_COMMON)); const bool good_summon = - (create_monster( mtype, 6, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG) != -1); + create_monster( + mgen_data( mtype, BEH_HOSTILE, + 6, you.pos(), MHITYOU )) != -1; if (good_summon) { @@ -699,9 +698,10 @@ static bool efreet_flask(void) mpr("You open the flask..."); - const int efreet = create_monster( MONS_EFREET, 0, beha, - you.x_pos, you.y_pos, hitting, - MONS_PROGRAM_BUG ); + const int efreet = + create_monster( + mgen_data( MONS_EFREET, beha, 0, you.pos(), hitting ) ); + if (efreet != -1) { monsters *mon = &menv[efreet]; @@ -883,9 +883,9 @@ void tome_of_power(int slot) } else if (one_chance_in(36)) { - if (create_monster( MONS_ABOMINATION_SMALL, 6, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG ) != -1) + if (create_monster( + mgen_data( MONS_ABOMINATION_SMALL, BEH_HOSTILE, 6, + you.pos(), MHITYOU )) != -1) { mpr("A horrible Thing appears!"); mpr("It doesn't look too friendly."); @@ -950,7 +950,7 @@ void skill_manual(int slot) static bool box_of_beasts() { - int beasty = MONS_PROGRAM_BUG; // error trapping {dlb} + monster_type beasty = MONS_PROGRAM_BUG; int temp_rand = 0; // probability determination {dlb} int ret = false; @@ -982,9 +982,9 @@ static bool box_of_beasts() hitting = MHITYOU; } - if (create_monster( beasty, 2 + random2(4), beha, - you.x_pos, you.y_pos, hitting, - MONS_PROGRAM_BUG ) != -1) + if (create_monster( + mgen_data( beasty, beha, 2 + random2(4), + you.pos(), hitting ) ) != -1) { mpr("...and something leaps out!"); xom_is_stimulated(14); diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index a6c10853d4..ca537e4443 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -4213,9 +4213,9 @@ void read_scroll( int slot ) break; case SCR_SUMMONING: - if (create_monster( MONS_ABOMINATION_SMALL, 6, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG ) != -1) + if (create_monster( + mgen_data( MONS_ABOMINATION_SMALL, BEH_FRIENDLY, 6, + you.pos(), you.pet_target )) != -1) { mpr("A horrible Thing appears!"); } diff --git a/crawl-ref/source/lev-pand.cc b/crawl-ref/source/lev-pand.cc index 4e4308de08..9efabf1e9b 100644 --- a/crawl-ref/source/lev-pand.cc +++ b/crawl-ref/source/lev-pand.cc @@ -116,7 +116,8 @@ void init_pandemonium(void) } if (one_chance_in(10)) - env.mons_alloc[pc] = MONS_HELLION + random2(10); + env.mons_alloc[pc] = + static_cast<monster_type>(MONS_HELLION + random2(10)); if (one_chance_in(30)) env.mons_alloc[pc] = MONS_RED_DEVIL; @@ -125,17 +126,21 @@ void init_pandemonium(void) env.mons_alloc[pc] = MONS_IMP; if (one_chance_in(20)) - env.mons_alloc[pc] = MONS_DEMONIC_CRAWLER + random2(5); + env.mons_alloc[pc] = + static_cast<monster_type>(MONS_DEMONIC_CRAWLER + random2(5)); } if (one_chance_in(8)) - env.mons_alloc[7] = MONS_EXECUTIONER + random2(5); + env.mons_alloc[7] = + static_cast<monster_type>(MONS_EXECUTIONER + random2(5)); if (one_chance_in(5)) - env.mons_alloc[8] = MONS_EXECUTIONER + random2(5); + env.mons_alloc[8] = + static_cast<monster_type>(MONS_EXECUTIONER + random2(5)); if (one_chance_in(3)) - env.mons_alloc[9] = MONS_EXECUTIONER + random2(5); + env.mons_alloc[9] = + static_cast<monster_type>(MONS_EXECUTIONER + random2(5)); if (one_chance_in(10)) env.mons_alloc[7 + random2(3)] = MONS_FIEND; @@ -170,6 +175,8 @@ void pandemonium_mons(void) } while (!mons_pan(pan_mons)); } - mons_place(pan_mons, BEH_HOSTILE, MHITNOT, false, 50,50, - LEVEL_PANDEMONIUM); + mgen_data mg(static_cast<monster_type>(pan_mons)); + mg.level_type = LEVEL_PANDEMONIUM; + + mons_place(mg); } // end pandemonium_mons() diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc index 26fb4f78aa..35c95428b8 100644 --- a/crawl-ref/source/mapdef.cc +++ b/crawl-ref/source/mapdef.cc @@ -1988,7 +1988,8 @@ mons_list::mons_spec_slot mons_list::parse_mons_spec(std::string spec) } mspec.mid = nspec.mid; - mspec.monnum = nspec.monnum; + mspec.monbase = nspec.monbase; + mspec.number = nspec.number; } if (mspec.items.size() > 0) @@ -2072,8 +2073,8 @@ void mons_list::get_zombie_type(std::string s, mons_spec &spec) const { s = s.substr(spectre.length()); spec.mid = MONS_SPECTRAL_THING; - spec.monnum = get_monster_by_name(s, true); - if (!mons_zombie_size(spec.monnum)) + spec.monbase = get_monster_by_name(s, true); + if (!mons_zombie_size(spec.monbase)) spec.mid = MONS_PROGRAM_BUG; return; } @@ -2084,9 +2085,9 @@ void mons_list::get_zombie_type(std::string s, mons_spec &spec) const s = s.substr(0, s.length() - strlen(zombie_types[mod - 1])); trim_string(s); - spec.monnum = get_monster_by_name(s, true); + spec.monbase = get_monster_by_name(s, true); - const int zombie_size = mons_zombie_size(spec.monnum); + const int zombie_size = mons_zombie_size(spec.monbase); if (!zombie_size) { spec.mid = MONS_PROGRAM_BUG; @@ -2104,7 +2105,7 @@ mons_spec mons_list::get_hydra_spec(const std::string &name) const else if (nheads > 19) nheads = 19; - return mons_spec(MONS_HYDRA, nheads); + return mons_spec(MONS_HYDRA, MONS_PROGRAM_BUG, nheads); } // Handle draconians specified as: @@ -2156,7 +2157,7 @@ mons_spec mons_list::drac_monspec(std::string name) const const monster_type colour = get_monster_by_name(name, true); if (colour != MONS_PROGRAM_BUG) { - spec.monnum = colour; + spec.monbase = colour; return (spec); } @@ -2166,7 +2167,7 @@ mons_spec mons_list::drac_monspec(std::string name) const return (MONS_PROGRAM_BUG); std::string scolour = name.substr(0, wordend); - if ((spec.monnum = draconian_colour_by_name(scolour)) == MONS_PROGRAM_BUG) + if ((spec.monbase = draconian_colour_by_name(scolour)) == MONS_PROGRAM_BUG) return (MONS_PROGRAM_BUG); name = trimmed_string(name.substr(wordend + 1)); diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h index 822b811b5c..c6fcd7cef3 100644 --- a/crawl-ref/source/mapdef.h +++ b/crawl-ref/source/mapdef.h @@ -397,20 +397,22 @@ class mons_spec { public: int mid; - int monnum; // The zombified monster for zombies, or head - // count for hydras, or colour for draconians. + monster_type monbase; // Base monster for zombies and dracs. + int number; // Head count for hydras int genweight, mlevel; bool fix_mons; bool generate_awake; - int colour; + int colour; item_list items; - mons_spec(int id = RANDOM_MONSTER, int num = MONS_PROGRAM_BUG, + mons_spec(int id = RANDOM_MONSTER, + monster_type base = MONS_PROGRAM_BUG, + int num = 0, int gw = 10, int ml = 0, bool _fixmons = false, bool awaken = false) - : mid(id), monnum(num), genweight(gw), mlevel(ml), fix_mons(_fixmons), - generate_awake(awaken), colour(BLACK), items() + : mid(id), monbase(base), number(num), genweight(gw), mlevel(ml), + fix_mons(_fixmons), generate_awake(awaken), colour(BLACK), items() { } }; diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index 8a71d38485..f9b2366b84 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -1453,7 +1453,7 @@ 220, 12, MONS_YELLOW_WASP, MONS_YELLOW_WASP, MH_NATURAL, -3, { {AT_STING, AF_PARALYSE, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 4, 3, 5, 0 }, - 5, 14, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_INSECT, + 5, 14, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT, I_INSECT, HT_LAND, 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY }, @@ -1464,7 +1464,7 @@ 100, 10, MONS_GIANT_MOSQUITO, MONS_GIANT_MOSQUITO, MH_NATURAL, -3, { {AT_BITE, AF_DISEASE, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 1, 3, 5, 0 }, - 0, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_WHINE, I_PLANT, + 0, 13, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_WHINE, I_PLANT, HT_LAND, 12, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY }, @@ -1475,7 +1475,7 @@ 200, 10, MONS_GIANT_BLOWFLY, MONS_GIANT_BLOWFLY, MH_NATURAL, -3, { {AT_BITE, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 5, 3, 5, 0 }, - 2, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_BUZZ, I_PLANT, + 2, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_BUZZ, I_PLANT, HT_LAND, 19, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY }, @@ -1486,7 +1486,7 @@ 400, 14, MONS_YELLOW_WASP, MONS_RED_WASP, MH_NATURAL, -3, { {AT_STING, AF_PARALYSE, 23}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 8, 3, 5, 0 }, - 7, 14, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_BUZZ, I_PLANT, + 7, 14, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_BUZZ, I_PLANT, HT_LAND, 15, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY }, @@ -1756,7 +1756,7 @@ 1800, 11, MONS_HYDRA, MONS_HYDRA, MH_NATURAL, -3, { {AT_BITE, AF_PLAIN, 18}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 13, 3, 5, 0 }, - 0, 5, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_ROAR, I_INSECT, + 0, 5, MST_NO_SPELLS, CE_POISONOUS, Z_BIG, S_ROAR, I_INSECT, HT_LAND, 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG }, diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 438a31f08e..0358b23b1d 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -554,7 +554,7 @@ monster_type draco_subspecies( const monsters *mon ) monster_type ret = mons_species( mon->type ); if (ret == MONS_DRACONIAN && mon->type != MONS_DRACONIAN) - ret = static_cast<monster_type>( mon->number ); + ret = static_cast<monster_type>( mon->base_monster ); return (ret); } @@ -665,9 +665,9 @@ int mons_colour(const monsters *monster) return (monster->colour); } -int mons_zombie_base(const monsters *monster) +monster_type mons_zombie_base(const monsters *monster) { - return (monster->number); + return (monster->base_monster); } bool mons_class_is_zombified(int mc) @@ -1368,6 +1368,7 @@ void define_monster(monsters &mons) int mcls = mons.type; int hd, hp, hp_max, ac, ev, speed; int monnumber = mons.number; + monster_type monbase = mons.base_monster; const monsterentry *m = get_monster_data(mcls); int col = mons_class_colour(mons.type); mon_spellbook_type spells = MST_NO_SPELLS; @@ -1389,9 +1390,7 @@ void define_monster(monsters &mons) hd = 4 + random2(4); ac = 3 + random2(7); ev = 7 + random2(6); - - if (monnumber == MONS_PROGRAM_BUG) // ?? - col = random_colour(); + col = random_colour(); break; case MONS_ZOMBIE_SMALL: @@ -1406,9 +1405,7 @@ void define_monster(monsters &mons) hd = 8 + random2(4); ac = 5 + random2avg(9, 2); ev = 3 + random2(5); - - if (monnumber == MONS_PROGRAM_BUG) - col = random_colour(); + col = random_colour(); break; case MONS_BEAST: @@ -1492,10 +1489,9 @@ void define_monster(monsters &mons) // White draconians will never be draconian scorchers, but // apart from that, anything goes. do - { - monnumber = MONS_BLACK_DRACONIAN + random2(8); - } - while (drac_colour_incompatible(mcls, monnumber)); + monbase = + static_cast<monster_type>(MONS_BLACK_DRACONIAN + random2(8)); + while (drac_colour_incompatible(mcls, monbase)); break; } case MONS_DRACONIAN_KNIGHT: @@ -1510,7 +1506,7 @@ void define_monster(monsters &mons) spells = (coinflip() ? MST_DEEP_ELF_CONJURER_I : MST_DEEP_ELF_CONJURER_II); - monnumber = MONS_BLACK_DRACONIAN + random2(8); + monbase = static_cast<monster_type>(MONS_BLACK_DRACONIAN + random2(8)); break; } case MONS_HUMAN: @@ -1544,7 +1540,10 @@ void define_monster(monsters &mons) mons.speed = speed; mons.speed_increment = 70; - if (mons.number == MONS_PROGRAM_BUG) + if (mons.base_monster == MONS_PROGRAM_BUG) + mons.base_monster = monbase; + + if (mons.number == 0) mons.number = monnumber; mons.flags = 0L; @@ -1669,13 +1668,13 @@ static std::string _str_monam(const monsters& mon, description_level_type desc, { case MONS_SPECTRAL_THING: result += "spectral "; - nametype = mon.number; + nametype = mon.base_monster; break; case MONS_ZOMBIE_SMALL: case MONS_ZOMBIE_LARGE: case MONS_SKELETON_SMALL: case MONS_SKELETON_LARGE: case MONS_SIMULACRUM_SMALL: case MONS_SIMULACRUM_LARGE: - nametype = mon.number; + nametype = mon.base_monster; break; case MONS_DRACONIAN_CALLER: @@ -1685,11 +1684,8 @@ static std::string _str_monam(const monsters& mon, description_level_type desc, case MONS_DRACONIAN_ANNIHILATOR: case MONS_DRACONIAN_KNIGHT: case MONS_DRACONIAN_SCORCHER: - if (mon.number != 0) // database search - { - result += draconian_colour_name( - static_cast<monster_type>( mon.number ) ) + " "; - } + if (mon.base_monster != MONS_PROGRAM_BUG) // database search + result += draconian_colour_name(mon.base_monster) + " "; break; default: @@ -2572,6 +2568,7 @@ void monsters::reset() flags = 0; experience = 0L; type = -1; + base_monster = MONS_PROGRAM_BUG; hit_points = 0; max_hit_points = 0; hit_dice = 0; @@ -2594,6 +2591,7 @@ void monsters::init_with(const monsters &mon) { mname = mon.mname; type = mon.type; + base_monster = mon.base_monster; hit_points = mon.hit_points; max_hit_points = mon.max_hit_points; hit_dice = mon.hit_dice; @@ -4503,6 +4501,12 @@ void monsters::load_spells(mon_spellbook_type book) #endif } +bool monsters::has_hydra_multi_attack() const +{ + return (type == MONS_HYDRA || + (mons_is_zombified(this) && base_monster == MONS_HYDRA)); +} + bool monsters::has_ench(enchant_type ench) const { return (enchantments.find(ench) != enchantments.end()); @@ -5768,9 +5772,9 @@ void monsters::react_to_damage(int damage) continue; const int nmons = - mons_place( jelly, sbehaviour, foe, true, jpos.x, jpos.y, - you.level_type, PROX_ANYWHERE, MONS_PROGRAM_BUG, - 0, false ); + mons_place( + mgen_data( jelly, sbehaviour, 0, jpos, + foe, true ) ); if (nmons != -1 && nmons != NON_MONSTER) { @@ -6245,7 +6249,7 @@ mon_body_shape get_mon_shape(const monsters *mon) if (mon->type == MONS_PLAYER_GHOST) return _get_ghost_shape(mon); else if (mons_is_zombified(mon)) - return get_mon_shape(mon->number); + return get_mon_shape(mon->base_monster); else return get_mon_shape(mon->type); } diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index fc1715ba8b..042cf1b12a 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -537,7 +537,7 @@ int mons_speed(int mclass); * called from: dungeon - mon-util - spells2 * *********************************************************************** */ int mons_zombie_size(int mc); -int mons_zombie_base(const monsters *monster); +monster_type mons_zombie_base(const monsters *monster); bool mons_class_is_zombified(int mc); bool mons_is_zombified(const monsters *monster); diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index c74d4cdb2a..2bcc8bc2a2 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -44,11 +44,16 @@ #define BIG_BAND 20 -static int band_member(band_type band, int power); +static void _define_zombie( int mid, monster_type ztype, + monster_type cs, int power ); +static monster_type _band_member(band_type band, int power); static band_type choose_band(int mon_type, int power, int &band_size ); -static int place_monster_aux(int mon_type, beh_type behaviour, int target, - int px, int py, int power, int extra, - bool first_band_member, int dur = 0); +// static int _place_monster_aux(int mon_type, beh_type behaviour, int target, +// int px, int py, int power, int extra, +// bool first_band_member, int dur = 0); + +static int _place_monster_aux(const mgen_data &mg, + bool first_band_member); // Returns whether actual_grid is compatible with grid_wanted for monster // movement (or for monster generation, if generation is true). @@ -181,10 +186,10 @@ static void hell_spawn_random_monsters() if (one_chance_in(genodds)) { - proximity_type prox = + mgen_data mg(WANDERING_MONSTER); + mg.proximity = (one_chance_in(10) ? PROX_NEAR_STAIRS : PROX_AWAY_FROM_PLAYER); - mons_place( WANDERING_MONSTER, BEH_HOSTILE, MHITNOT, false, - 50, 50, LEVEL_DUNGEON, prox ); + mons_place(mg); viewwindow(true, false); } } @@ -209,16 +214,16 @@ void spawn_random_monsters() if (you.char_direction == GDT_ASCENDING) prox = (one_chance_in(6) ? PROX_CLOSE_TO_PLAYER : PROX_ANYWHERE); - mons_place( WANDERING_MONSTER, BEH_HOSTILE, MHITNOT, false, - 50, 50, LEVEL_DUNGEON, prox ); + mgen_data mg(WANDERING_MONSTER); + mg.proximity = prox; + mons_place( mg ); viewwindow(true, false); } // place Abyss monsters. if (you.level_type == LEVEL_ABYSS && one_chance_in(5)) { - mons_place( WANDERING_MONSTER, BEH_HOSTILE, MHITNOT, false, - 50, 50, LEVEL_ABYSS, PROX_ANYWHERE ); + mons_place(mgen_data(WANDERING_MONSTER)); viewwindow(true, false); } @@ -356,28 +361,37 @@ bool drac_colour_incompatible(int drac, int colour) return (drac == MONS_DRACONIAN_SCORCHER && colour == MONS_WHITE_DRACONIAN); } -static int resolve_monster_type(int mon_type, proximity_type proximity, - int num, int px, int py, unsigned mmask, - dungeon_char_type *stair_type, - int *lev_mons) +static monster_type resolve_monster_type(monster_type mon_type, + proximity_type proximity, + monster_type base_type, + coord_def &pos, + unsigned mmask, + dungeon_char_type *stair_type, + int *lev_mons) { if (mon_type == RANDOM_DRACONIAN) { // Pick any random drac, constrained by colour if requested. do mon_type = - random_range(MONS_BLACK_DRACONIAN, MONS_DRACONIAN_SCORCHER); - while (num != MONS_PROGRAM_BUG - && mon_type != num + static_cast<monster_type>( + random_range(MONS_BLACK_DRACONIAN, + MONS_DRACONIAN_SCORCHER)); + while (base_type != MONS_PROGRAM_BUG + && mon_type != base_type && (mons_species(mon_type) == mon_type - || drac_colour_incompatible(mon_type, num))); + || drac_colour_incompatible(mon_type, base_type))); } else if (mon_type == RANDOM_BASE_DRACONIAN) - mon_type = random_range(MONS_BLACK_DRACONIAN, MONS_PALE_DRACONIAN); + mon_type = + static_cast<monster_type>( + random_range(MONS_BLACK_DRACONIAN, MONS_PALE_DRACONIAN)); else if (mon_type == RANDOM_NONBASE_DRACONIAN) - mon_type = random_range(MONS_DRACONIAN_CALLER, MONS_DRACONIAN_SCORCHER); + mon_type = + static_cast<monster_type>( + random_range(MONS_DRACONIAN_CALLER, MONS_DRACONIAN_SCORCHER)); - // (2) take care of random monsters + // (2) take care of non-drac random monsters if (mon_type == RANDOM_MONSTER) { level_id place = level_id::current(); @@ -388,21 +402,17 @@ static int resolve_monster_type(int mon_type, proximity_type proximity, int pval = 0; while (++tries <= 320) { - px = 5 + random2(GXM - 10); - py = 5 + random2(GYM - 10); + pos = random_in_bounds(); - if (mgrd[px][py] != NON_MONSTER - || (px == you.x_pos && py == you.y_pos)) - { + if (mgrd(pos) != NON_MONSTER || pos == you.pos()) continue; - } // Is the grid verboten? - if (!unforbidden( coord_def(px, py), mmask )) + if (!unforbidden( pos, mmask )) continue; // don't generate monsters on top of teleport traps - int trap = trap_at_xy(px, py); + int trap = trap_at_xy(pos.x, pos.y); if (trap >= 0) { if (!can_place_on_trap(mon_type, env.trap[trap].type)) @@ -411,7 +421,7 @@ static int resolve_monster_type(int mon_type, proximity_type proximity, // check whether there's a stair // and whether it leads to another branch - pval = near_stairs(coord_def(px, py), 1, + pval = near_stairs(pos, 1, *stair_type, place.branch); // no monsters spawned in the Temple @@ -455,57 +465,49 @@ static int resolve_monster_type(int mon_type, proximity_type proximity, return (mon_type); } -bool place_monster(int &id, int mon_type, int power, beh_type behaviour, - int target, bool summoned, int px, int py, bool allow_bands, - proximity_type proximity, int extra, int dur, - unsigned mmask) +int place_monster(mgen_data mg) { int band_size = 0; - int band_monsters[BIG_BAND]; // band monster types - int lev_mons = power; // final 'power' - int i; + monster_type band_monsters[BIG_BAND]; // band monster types int tries = 0; int pval = 0; dungeon_char_type stair_type = NUM_DCHAR_TYPES; - - // set initial id to -1 (unsuccessful create) - id = -1; + int id = -1; // (1) early out (summoned to occupied grid) - if (summoned && mgrd[px][py] != NON_MONSTER) + if (mg.use_position() && mgrd(mg.pos) != NON_MONSTER) return (false); - mon_type = - resolve_monster_type(mon_type, proximity, extra, - px, py, mmask, &stair_type, - &lev_mons); + mg.cls = + resolve_monster_type(mg.cls, mg.proximity, mg.base_type, + mg.pos, mg.map_mask, + &stair_type, &mg.power); - if (mon_type == MONS_PROGRAM_BUG || mon_type == -1) + if (mg.cls == MONS_PROGRAM_BUG) return (false); // (3) decide on banding (good lord!) band_size = 1; - band_monsters[0] = mon_type; + band_monsters[0] = mg.cls; - if (allow_bands) + if (mg.permit_bands()) { - const band_type band = choose_band(mon_type, power, band_size); + const band_type band = choose_band(mg.cls, mg.power, band_size); band_size ++; - - for (i = 1; i < band_size; i++) - band_monsters[i] = band_member( band, power ); + for (int i = 1; i < band_size; i++) + band_monsters[i] = _band_member( band, mg.power ); } - if (proximity == PROX_NEAR_STAIRS) + if (mg.proximity == PROX_NEAR_STAIRS) { // for some cases disallow monsters on stairs - if (mons_class_is_stationary( mon_type ) - || pval == 2 - && (mons_speed(mon_type) == 0 || grd[px][py] == DNGN_LAVA - || grd[px][py] == DNGN_DEEP_WATER)) + if (mons_class_is_stationary( mg.cls ) + || (pval == 2 + && (mons_speed(mg.cls) == 0 || grd(mg.pos) == DNGN_LAVA + || grd(mg.pos) == DNGN_DEEP_WATER))) { - proximity = PROX_AWAY_FROM_PLAYER; + mg.proximity = PROX_AWAY_FROM_PLAYER; } } @@ -516,7 +518,7 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour, // player shoved out of the way? bool shoved = false; - if (!summoned) + if (!mg.use_position()) { tries = 0; @@ -525,104 +527,90 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour, // b) compatible // c) in the 'correct' proximity to the player dungeon_feature_type grid_wanted = - habitat2grid( mons_habitat_by_type(mon_type) ); + habitat2grid( mons_habitat_by_type(mg.cls) ); while (true) { - // handled above, won't change anymore - if (proximity == PROX_NEAR_STAIRS && tries) - { - proximity = PROX_AWAY_FROM_PLAYER; - tries = 0; - } // Dropped number of tries from 60. - else if (tries >= 45) + if (tries++ >= 45) return (false); - tries ++; - // placement already decided for PROX_NEAR_STAIRS - if (proximity != PROX_NEAR_STAIRS) - { - px = 5 + random2(GXM - 10); - py = 5 + random2(GYM - 10); - } + if (mg.proximity != PROX_NEAR_STAIRS) + mg.pos = random_in_bounds(); // Let's recheck these even for PROX_NEAR_STAIRS, just in case - // occupied? - if (mgrd[px][py] != NON_MONSTER - || px == you.x_pos && py == you.y_pos) - { + if (mgrd(mg.pos) != NON_MONSTER || mg.pos == you.pos()) continue; - } // Is the monster happy where we want to put it? - if (!grid_compatible(grid_wanted, grd[px][py], true)) + if (!grid_compatible(grid_wanted, grd(mg.pos), true)) continue; // Is the grid verboten? - if (!unforbidden( coord_def(px, py), mmask )) + if (!unforbidden( mg.pos, mg.map_mask )) continue; // don't generate monsters on top of teleport traps // (how did they get there?) - int trap = trap_at_xy(px, py); + int trap = trap_at_xy(mg.pos.x, mg.pos.y); if (trap >= 0) { - if (!can_place_on_trap(mon_type, env.trap[trap].type)) + if (!can_place_on_trap(mg.cls, env.trap[trap].type)) continue; } // check proximity to player proxOK = true; - switch (proximity) + switch (mg.proximity) { - case PROX_ANYWHERE: - if (grid_distance( you.x_pos, you.y_pos, px, py ) < 2 + random2(3)) - { - proxOK = false; - } - break; + case PROX_ANYWHERE: + if (grid_distance( you.x_pos, you.y_pos, + mg.pos.x, mg.pos.y ) < 2 + random2(3)) + { + proxOK = false; + } + break; - case PROX_CLOSE_TO_PLAYER: - case PROX_AWAY_FROM_PLAYER: - close_to_player = (distance(you.x_pos, you.y_pos, px, py) < 64); + case PROX_CLOSE_TO_PLAYER: + case PROX_AWAY_FROM_PLAYER: + close_to_player = + (distance(you.x_pos, you.y_pos, + mg.pos.x, mg.pos.y) < 64); + + if (mg.proximity == PROX_CLOSE_TO_PLAYER && !close_to_player + || mg.proximity == PROX_AWAY_FROM_PLAYER && close_to_player) + { + proxOK = false; + } + break; - if (proximity == PROX_CLOSE_TO_PLAYER && !close_to_player - || proximity == PROX_AWAY_FROM_PLAYER && close_to_player) + case PROX_NEAR_STAIRS: + if (pval == 2) // player on stairs + { + // 0 speed monsters can't shove player out of their way. + if (mons_speed(mg.cls) == 0) { proxOK = false; + break; } - break; - - case PROX_NEAR_STAIRS: - if (pval == 2) // player on stairs + // swap the monster and the player spots, unless the + // monster was generated in lava or deep water. + if (grd(mg.pos) == DNGN_LAVA || + grd(mg.pos) == DNGN_DEEP_WATER) { - // 0 speed monsters can't shove player out of their way. - if (mons_speed(mon_type) == 0) - { - proxOK = false; - break; - } - // swap the monster and the player spots, unless the - // monster was generated in lava or deep water. - if (grd[px][py] == DNGN_LAVA || grd[px][py] == DNGN_DEEP_WATER) - { - proxOK = false; - break; - } - shoved = true; - int tpx = px; - int tpy = py; - px = you.x_pos; - py = you.y_pos; - you.moveto(tpx, tpy); + proxOK = false; + break; } - - proxOK = (pval > 0); - break; + shoved = true; + coord_def mpos = mg.pos; + mg.pos = you.pos(); + you.moveto(mpos); + } + proxOK = (pval > 0); + break; } if (!proxOK) @@ -633,16 +621,14 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour, } // end while.. place first monster } - id = place_monster_aux( mon_type, behaviour, target, px, py, lev_mons, - extra, true); + id = _place_monster_aux(mg, true); - // now, forget about banding if the first placement failed, or there's too - // many monsters already, or we successfully placed by stairs - if (id < 0 || id+30 > MAX_MONSTERS) - return false; + // Bail out now if we failed. + if (id == -1) + return (id); // message to player from stairwell/gate appearance? - if (see_grid(px, py) && proximity == PROX_NEAR_STAIRS) + if (see_grid(mg.pos) && mg.proximity == PROX_NEAR_STAIRS) { std::string msg; @@ -672,41 +658,43 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour, } // special case: must update the view for monsters created in player LOS - viewwindow(1, false); + viewwindow(true, false); } - // monsters placed by stairs don't bring the whole band up/down/through - // with them - if (proximity == PROX_NEAR_STAIRS) - return (true); + // now, forget about banding if the first placement failed, or there's too + // many monsters already, or we successfully placed by stairs + if (id >= MAX_MONSTERS - 30 || mg.proximity == PROX_NEAR_STAIRS) + return (id); // Not PROX_NEAR_STAIRS, so will it will be part of a band, if there // is any. if (band_size > 1) menv[id].flags |= MF_BAND_MEMBER; + mgen_data band_template = mg; // (5) for each band monster, loop call to place_monster_aux(). - for (i = 1; i < band_size; i++) + for (int i = 1; i < band_size; i++) { + if (band_monsters[i] == MONS_PROGRAM_BUG) + break; + + band_template.cls = band_monsters[i]; const int band_id = - place_monster_aux( band_monsters[i], behaviour, target, px, py, - lev_mons, extra, false, dur); - + _place_monster_aux( band_template, false ); if (band_id != -1 && band_id != NON_MONSTER) menv[band_id].flags |= MF_BAND_MEMBER; } // placement of first monster, at least, was a success. - return (true); + return (id); } -static int place_monster_aux( int mon_type, beh_type behaviour, int target, - int px, int py, int power, int extra, - bool first_band_member, int dur ) +static int _place_monster_aux( const mgen_data &mg, + bool first_band_member ) { - int id, i; + int id = -1; dungeon_feature_type grid_wanted = DNGN_UNSEEN; - int fx = 0, fy = 0; // final x,y + coord_def fpos; // gotta be able to pick an ID for (id = 0; id < MAX_MONSTERS; id++) @@ -714,42 +702,39 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target, break; if (id == MAX_MONSTERS) - return -1; + return (-1); menv[id].reset(); // setup habitat and placement // If the space is occupied, try some neighbouring square instead. - if (first_band_member && mgrd[px][py] == NON_MONSTER - && (px != you.x_pos || py != you.y_pos)) + if (first_band_member && mgrd(mg.pos) == NON_MONSTER + && mg.pos != you.pos()) { - fx = px; - fy = py; + fpos = mg.pos; } else { - grid_wanted = habitat2grid( mons_habitat_by_type(mon_type) ); + grid_wanted = habitat2grid( mons_habitat_by_type(mg.cls) ); + int i = 0; // we'll try 1000 times for a good spot - for (i = 0; i < 1000; i++) + for ( ; i < 1000; i++) { - fx = px + random2(7) - 3; - fy = py + random2(7) - 3; + fpos = mg.pos + coord_def( random_range(-3, 3), + random_range(-3, 3) ); // occupied? - if (mgrd[fx][fy] != NON_MONSTER - || fx == you.x_pos && fy == you.y_pos) - { + if (mgrd(fpos) != NON_MONSTER || fpos == you.pos()) continue; - } - if (!grid_compatible(grid_wanted, grd[fx][fy], true)) + if (!grid_compatible(grid_wanted, grd(fpos), true)) continue; // don't generate monsters on top of teleport traps // (how do they get there?) - int trap = trap_at_xy(fx, fy); - if (trap >= 0 && !can_place_on_trap(mon_type, env.trap[trap].type)) + int trap = trap_at_xy(fpos.x, fpos.y); + if (trap >= 0 && !can_place_on_trap(mg.cls, env.trap[trap].type)) continue; // cool.. passes all tests @@ -762,47 +747,48 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target, } // now, actually create the monster (wheeee!) - menv[id].type = mon_type; + menv[id].type = mg.cls; + menv[id].base_monster = mg.base_type; - menv[id].number = extra; + menv[id].number = mg.number; - menv[id].x = fx; - menv[id].y = fy; + menv[id].x = fpos.x; + menv[id].y = fpos.y; // link monster into monster grid - mgrd[fx][fy] = id; + mgrd(fpos) = id; // generate a brand shiny new monster, or zombie - if (mons_class_is_zombified(mon_type)) - define_zombie( id, extra, mon_type, power ); + if (mons_class_is_zombified(mg.cls)) + _define_zombie( id, mg.base_type, mg.cls, mg.power ); else define_monster(id); // The return of Boris is now handled in monster_die()... // not setting this for Boris here allows for multiple Borises // in the dungeon at the same time. -- bwr - if (mons_is_unique(mon_type)) - you.unique_creatures[mon_type] = true; + if (mons_is_unique(mg.cls)) + you.unique_creatures[mg.cls] = true; - if (mons_class_flag(mon_type, M_INVIS)) + if (mons_class_flag(mg.cls, M_INVIS)) menv[id].add_ench(ENCH_INVIS); - if (mons_class_flag(mon_type, M_CONFUSED)) + if (mons_class_flag(mg.cls, M_CONFUSED)) menv[id].add_ench(ENCH_CONFUSION); - if (mon_type == MONS_SHAPESHIFTER) + if (mg.cls == MONS_SHAPESHIFTER) menv[id].add_ench(ENCH_SHAPESHIFTER); - if (mon_type == MONS_GLOWING_SHAPESHIFTER) + if (mg.cls == MONS_GLOWING_SHAPESHIFTER) menv[id].add_ench(ENCH_GLOWING_SHAPESHIFTER); - if (mon_type == MONS_GIANT_BAT || mon_type == MONS_UNSEEN_HORROR - || mon_type == MONS_GIANT_BLOWFLY) + if (mg.cls == MONS_GIANT_BAT || mg.cls == MONS_UNSEEN_HORROR + || mg.cls == MONS_GIANT_BLOWFLY) { menv[id].flags |= MF_BATTY; } - if (monster_can_submerge(&menv[id], grd[fx][fy]) + if (monster_can_submerge(&menv[id], grd(fpos)) && !one_chance_in(5)) { menv[id].add_ench(ENCH_SUBMERGED); @@ -810,34 +796,33 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target, menv[id].flags |= MF_JUST_SUMMONED; - if (mon_type == MONS_DANCING_WEAPON && extra != 1) // ie not from spell + if (mg.cls == MONS_DANCING_WEAPON && mg.number != 1) // ie not from spell { - give_item( id, power ); + give_item( id, mg.power ); if (menv[id].inv[MSLOT_WEAPON] != NON_ITEM) menv[id].colour = mitm[ menv[id].inv[MSLOT_WEAPON] ].colour; } - else if (mons_itemuse(mon_type) >= MONUSE_STARTING_EQUIPMENT) + else if (mons_itemuse(mg.cls) >= MONUSE_STARTING_EQUIPMENT) { - give_item( id, power ); + give_item( id, mg.power ); // Give these monsters a second weapon -- bwr - if (mons_wields_two_weapons(static_cast<monster_type>(mon_type))) - give_item( id, power ); + if (mons_wields_two_weapons(mg.cls)) + give_item( id, mg.power ); unwind_var<int> save_speedinc(menv[id].speed_increment); menv[id].wield_melee_weapon(false); } // give manticores 8 to 16 spike volleys. - // they're not spellcasters so this doesn't screw anything up. - if (mon_type == MONS_MANTICORE) + if (mg.cls == MONS_MANTICORE) menv[id].number = 8 + random2(9); // set attitude, behaviour and target menv[id].attitude = ATT_HOSTILE; - menv[id].behaviour = behaviour; + menv[id].behaviour = mg.behaviour; - if (mons_is_statue(mon_type)) + if (mons_is_statue(mg.cls)) menv[id].behaviour = BEH_WANDER; menv[id].foe_memory = 0; @@ -846,22 +831,22 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target, // monster wander.. if you want sleeping // hostiles, use BEH_SLEEP since the default // attitude is hostile. - if (behaviour > NUM_BEHAVIOURS) + if (mg.behaviour > NUM_BEHAVIOURS) { - if (behaviour == BEH_FRIENDLY || behaviour == BEH_GOD_GIFT) + if (mg.behaviour == BEH_FRIENDLY || mg.behaviour == BEH_GOD_GIFT) menv[id].attitude = ATT_FRIENDLY; - if (behaviour == BEH_NEUTRAL) + if (mg.behaviour == BEH_NEUTRAL) menv[id].attitude = ATT_NEUTRAL; menv[id].behaviour = BEH_WANDER; } // dur should always be 1-6 for monsters that can be abjured. - if (dur >= 1 && dur <= 6) - menv[id].mark_summoned( dur, true ); + if (mg.abjuration_duration >= 1 && mg.abjuration_duration <= 6) + menv[id].mark_summoned( mg.abjuration_duration, true ); - menv[id].foe = target; + menv[id].foe = mg.foe; // Initialise pandemonium demons if (menv[id].type == MONS_PANDEMONIUM_DEMON) @@ -872,14 +857,224 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target, menv[id].pandemon_init(); } - mark_interesting_monst(&menv[id], behaviour); + mark_interesting_monst(&menv[id], mg.behaviour); if (player_monster_visible(&menv[id]) && mons_near(&menv[id])) seen_monster(&menv[id]); return (id); -} // end place_monster_aux() +} + +static monster_type _pick_random_zombie() +{ + static std::vector<monster_type> zombifiable; + if (zombifiable.empty()) + { + for (int i = 0; i < NUM_MONSTERS; ++i) + { + if (mons_species(i) != i || i == MONS_PROGRAM_BUG) + continue; + + const monster_type mcls = static_cast<monster_type>(i); + if (!mons_zombie_size(mcls)) + continue; + + zombifiable.push_back(mcls); + } + } + return (zombifiable[ random2(zombifiable.size()) ]); +} + +static void _define_zombie( int mid, monster_type ztype, + monster_type cs, int power ) +{ + monster_type mons_sec2 = MONS_PROGRAM_BUG; + int zombie_size = 0; + bool ignore_rarity = false; + monster_type cls = MONS_PROGRAM_BUG; + + if (power > 27) + power = 27; + + // set size based on zombie class (cs) + switch (cs) + { + case MONS_ZOMBIE_SMALL: + case MONS_SIMULACRUM_SMALL: + case MONS_SKELETON_SMALL: + zombie_size = Z_SMALL; + break; + + case MONS_ZOMBIE_LARGE: + case MONS_SIMULACRUM_LARGE: + case MONS_SKELETON_LARGE: + zombie_size = Z_BIG; + break; + + case MONS_SPECTRAL_THING: + zombie_size = -1; + break; + + default: + // this should NEVER happen. + perror("\ncreate_zombie() got passed incorrect zombie type!\n"); + end(0); + break; + } + + // that is, random creature from which to fashion undead + if (ztype == MONS_PROGRAM_BUG) + { + // how OOD this zombie can be. + int relax = 5; + + // pick an appropriate creature to make a zombie out of, + // levelwise. The old code was generating absolutely + // incredible OOD zombies. + while (true) + { + cls = _pick_random_zombie(); + + // on certain branches, zombie creation will fail if we use + // the mons_rarity() functions, because (for example) there + // are NO zombifiable "native" abyss creatures. Other branches + // where this is a problem are hell levels and the crypt. + // we have to watch for summoned zombies on other levels, too, + // such as the Temple, HoB, and Slime Pits. + if (you.level_type != LEVEL_DUNGEON + || player_in_hell() + || player_in_branch( BRANCH_HALL_OF_ZOT ) + || player_in_branch( BRANCH_VESTIBULE_OF_HELL ) + || player_in_branch( BRANCH_ECUMENICAL_TEMPLE ) + || player_in_branch( BRANCH_CRYPT ) + || player_in_branch( BRANCH_TOMB ) + || player_in_branch( BRANCH_HALL_OF_BLADES ) + || player_in_branch( BRANCH_SNAKE_PIT ) + || player_in_branch( BRANCH_SLIME_PITS ) + || one_chance_in(1000)) + { + ignore_rarity = true; + } + + // don't make out-of-rarity zombies when we don't have to + if (!ignore_rarity && mons_rarity(cls) == 0) + continue; + + // if skeleton, monster must have a skeleton + if ((cs == MONS_SKELETON_SMALL || cs == MONS_SKELETON_LARGE) + && !mons_skeleton(cls)) + { + continue; + } + + // size must match, but you can make a spectral thing out + // of anything. + if (mons_zombie_size(cls) != zombie_size && zombie_size != -1) + continue; + + // hack -- non-dungeon zombies are always made out of nastier + // monsters + if (you.level_type != LEVEL_DUNGEON && mons_power(cls) > 8) + break; + + // check for rarity.. and OOD - identical to mons_place() + int level, diff, chance; + + level = mons_level( cls ) - 4; + diff = level - power; + + chance = (ignore_rarity) ? 100 + : mons_rarity(cls) - (diff * diff) / 2; + + if (power > level - relax && power < level + relax + && random2avg(100, 2) <= chance) + { + break; + } + + // every so often, we'll relax the OOD restrictions. Avoids + // infinite loops (if we don't do this, things like creating + // a large skeleton on level 1 may hang the game!) + if (one_chance_in(5)) + relax++; + } + + // set type and secondary appropriately + menv[mid].base_monster = cls; + mons_sec2 = cls; + } + else + { + menv[mid].base_monster = mons_species(ztype); + mons_sec2 = menv[mid].base_monster; + } + + menv[mid].type = menv[mid].base_monster; + + define_monster(mid); + + menv[mid].hit_points = hit_points( menv[mid].hit_dice, 6, 5 ); + menv[mid].max_hit_points = menv[mid].hit_points; + + menv[mid].ac -= 2; + + if (menv[mid].ac < 0) + menv[mid].ac = 0; + + menv[mid].ev -= 5; + + if (menv[mid].ev < 0) + menv[mid].ev = 0; + menv[mid].speed -= 2; + + if (menv[mid].speed < 3) + menv[mid].speed = 3; + + menv[mid].speed_increment = 70; + + if (cs == MONS_ZOMBIE_SMALL || cs == MONS_ZOMBIE_LARGE) + { + menv[mid].type = ((mons_zombie_size(menv[mid].base_monster) == Z_BIG) + ? MONS_ZOMBIE_LARGE : MONS_ZOMBIE_SMALL); + } + else if (cs == MONS_SKELETON_SMALL || cs == MONS_SKELETON_LARGE) + { + menv[mid].hit_points = hit_points( menv[mid].hit_dice, 5, 4 ); + menv[mid].max_hit_points = menv[mid].hit_points; + + menv[mid].ac -= 4; + + if (menv[mid].ac < 0) + menv[mid].ac = 0; + + menv[mid].ev -= 2; + + if (menv[mid].ev < 0) + menv[mid].ev = 0; + + menv[mid].type = ((mons_zombie_size( menv[mid].base_monster ) == Z_BIG) + ? MONS_SKELETON_LARGE : MONS_SKELETON_SMALL); + } + else if (cs == MONS_SIMULACRUM_SMALL || cs == MONS_SIMULACRUM_LARGE) + { + // Simulacrum aren't tough, but you can create piles of them. -- bwr + menv[mid].hit_points = hit_points( menv[mid].hit_dice, 1, 4 ); + menv[mid].max_hit_points = menv[mid].hit_points; + menv[mid].type = ((mons_zombie_size( menv[mid].base_monster ) == Z_BIG) + ? MONS_SIMULACRUM_LARGE : MONS_SIMULACRUM_SMALL); + } + else if (cs == MONS_SPECTRAL_THING) + { + menv[mid].hit_points = hit_points( menv[mid].hit_dice, 4, 4 ); + menv[mid].max_hit_points = menv[mid].hit_points; + menv[mid].ac += 4; + menv[mid].type = MONS_SPECTRAL_THING; + } + + menv[mid].base_monster = mons_sec2; + menv[mid].colour = mons_class_colour(cs); +} static band_type choose_band( int mon_type, int power, int &band_size ) { @@ -1177,13 +1372,13 @@ static band_type choose_band( int mon_type, int power, int &band_size ) return (band); } -static int band_member(band_type band, int power) +static monster_type _band_member(band_type band, int power) { - int mon_type = -1; + monster_type mon_type = MONS_PROGRAM_BUG; int temp_rand; if (band == BAND_NO_BAND) - return -1; + return (MONS_PROGRAM_BUG); switch (band) { @@ -1281,14 +1476,16 @@ static int band_member(band_type band, int power) case BAND_PANDEMONIUM_DEMON: if (one_chance_in(7)) - mon_type = random_choose_weighted(50, MONS_LICH, - 10, MONS_ANCIENT_LICH, - 0); + mon_type = static_cast<monster_type>( + random_choose_weighted(50, MONS_LICH, + 10, MONS_ANCIENT_LICH, + 0)); else if (one_chance_in(6)) - mon_type = random_choose_weighted(50, MONS_ABOMINATION_SMALL, - 40, MONS_ABOMINATION_LARGE, - 10, MONS_TENTACLED_MONSTROSITY, - 0); + mon_type = static_cast<monster_type>( + random_choose_weighted(50, MONS_ABOMINATION_SMALL, + 40, MONS_ABOMINATION_LARGE, + 10, MONS_TENTACLED_MONSTROSITY, + 0)); else mon_type = summon_any_demon( @@ -1493,7 +1690,7 @@ void mark_interesting_monst(struct monsters* monster, beh_type behaviour) // PUBLIC FUNCTION -- mons_place(). -static int pick_zot_exit_defender() +static monster_type pick_zot_exit_defender() { if (one_chance_in(11)) return (MONS_PANDEMONIUM_DEMON); @@ -1508,12 +1705,13 @@ static int pick_zot_exit_defender() (temp_rand > 13) ? MONS_RED_DEVIL // 7.25% : MONS_PIT_FIEND); // 5.07% - return (mon_type); + return static_cast<monster_type>(mon_type); } -int mons_place( int mon_type, beh_type behaviour, int target, bool summoned, - int px, int py, int level_type, proximity_type proximity, - int extra, int dur, bool permit_bands ) +int mons_place( mgen_data mg ) + // int mon_type, beh_type behaviour, int target, bool summoned, + // int px, int py, int level_type, proximity_type proximity, + // int extra, int dur, bool permit_bands ) { int mon_count = 0; for (int il = 0; il < MAX_MONSTERS; il++) @@ -1522,85 +1720,80 @@ int mons_place( int mon_type, beh_type behaviour, int target, bool summoned, mon_count++; } - if (mon_type == WANDERING_MONSTER) + if (mg.cls == WANDERING_MONSTER) { - if (mon_count > 150) + if (mon_count > MAX_MONSTERS - 50) return (-1); - mon_type = RANDOM_MONSTER; + mg.cls = RANDOM_MONSTER; } // all monsters have been assigned? {dlb} - if (mon_count > MAX_MONSTERS - 2) + if (mon_count >= MAX_MONSTERS - 1) return (-1); // this gives a slight challenge to the player as they ascend the // dungeon with the Orb - if (you.char_direction == GDT_ASCENDING && mon_type == RANDOM_MONSTER - && you.level_type == LEVEL_DUNGEON && !summoned) + if (you.char_direction == GDT_ASCENDING && mg.cls == RANDOM_MONSTER + && you.level_type == LEVEL_DUNGEON && !mg.summoned()) { - mon_type = pick_zot_exit_defender(); - permit_bands = true; + mg.cls = pick_zot_exit_defender(); + mg.flags |= MG_PERMIT_BANDS; } - if (mon_type == RANDOM_MONSTER - || level_type == LEVEL_PANDEMONIUM) - { - permit_bands = true; - } + if (mg.cls == RANDOM_MONSTER || mg.level_type == LEVEL_PANDEMONIUM) + mg.flags |= MG_PERMIT_BANDS; int mid = -1; // translate level_type - int power; - - switch (level_type) + switch (mg.level_type) { case LEVEL_PANDEMONIUM: - power = 52; // sigh.. + mg.power = 52; // sigh.. break; case LEVEL_ABYSS: - power = 51; + mg.power = 51; break; - case LEVEL_DUNGEON: // intentional fallthrough + case LEVEL_DUNGEON: default: - power = you.your_level; + mg.power = you.your_level; break; } - if (!place_monster( mid, mon_type, power, behaviour, target, summoned, - px, py, permit_bands, proximity, extra, dur )) - { + mid = place_monster(mg); + if (mid == -1) return (-1); - } + + monsters *creation = &menv[mid]; - if (mid != -1) + // look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT + // alert summoned being to player's presence + if (mg.behaviour > NUM_BEHAVIOURS) { - struct monsters *const creation = &menv[mid]; - - // look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT - // alert summoned being to player's presence - if (behaviour > NUM_BEHAVIOURS) - { - if (behaviour == BEH_FRIENDLY || behaviour == BEH_GOD_GIFT) - creation->flags |= MF_CREATED_FRIENDLY; + if (mg.behaviour == BEH_FRIENDLY || mg.behaviour == BEH_GOD_GIFT) + creation->flags |= MF_CREATED_FRIENDLY; - if (behaviour == BEH_GOD_GIFT) - creation->flags |= MF_GOD_GIFT; + if (mg.behaviour == BEH_GOD_GIFT) + creation->flags |= MF_GOD_GIFT; - if (behaviour == BEH_CHARMED) - { - creation->attitude = ATT_HOSTILE; - creation->add_ench(ENCH_CHARM); - } + if (!(mg.flags & MG_FORCE_BEH) && player_angers_monster(creation)) + creation->attitude = ATT_HOSTILE; - // make summoned being aware of player's presence - behaviour_event(creation, ME_ALERT, MHITYOU); + if (mg.behaviour == BEH_CHARMED) + { + creation->attitude = ATT_HOSTILE; + creation->add_ench(ENCH_CHARM); } - } + // make summoned being aware of player's presence + behaviour_event(creation, ME_ALERT, MHITYOU); + + if (creation->type == MONS_RAKSHASA_FAKE && !one_chance_in(3)) + creation->add_ench(ENCH_INVIS); + } return (mid); -} // end mons_place() +} static dungeon_feature_type _monster_habitat_feature(int mtype) { @@ -1680,7 +1873,7 @@ coord_def find_newmons_square_contiguous(monster_type mons_class, return (in_bounds(p)? p : coord_def(-1, -1)); } -coord_def find_newmons_square(int mons_class, int x, int y) +coord_def find_newmons_square(int mons_class, const coord_def &p) { FixedVector < char, 2 > empty; coord_def pos(-1, -1); @@ -1696,7 +1889,7 @@ coord_def find_newmons_square(int mons_class, int x, int y) // Might be better if we chose a space and tried to match the monster // to it in the case of RANDOM_MONSTER, that way if the target square // is surrounded by water of lava this function would work. -- bwr - if (empty_surrounds( x, y, spcw, 2, true, empty )) + if (empty_surrounds( p.x, p.y, spcw, 2, true, empty )) { pos.x = empty[0]; pos.y = empty[1]; @@ -1727,81 +1920,28 @@ bool player_angers_monster(monsters *creation) return (false); } -int create_monster( int cls, int dur, beh_type beha, int cr_x, int cr_y, - int hitting, int zsec, bool permit_bands, - bool force_place, bool force_behaviour, - bool player_made ) +int create_monster( mgen_data mg ) { int summd = -1; - coord_def pos; - if (force_place && mons_class_can_pass(cls, grd[cr_x][cr_y]) - && mgrd[cr_x][cr_y] == NON_MONSTER - && (cr_x != you.x_pos || cr_y != you.y_pos)) - { - pos.x = cr_x; - pos.y = cr_y; - } - else - pos = find_newmons_square(cls, cr_x, cr_y); + if (!(mg.force_place() + && in_bounds(mg.pos) + && mons_class_can_pass(mg.cls, grd(mg.pos)) + && mgrd(mg.pos) == NON_MONSTER + && mg.pos != you.pos())) + mg.pos = find_newmons_square(mg.cls, mg.pos); - if (pos.x != -1 && pos.y != -1) - { - summd = mons_place( cls, beha, hitting, true, pos.x, pos.y, - you.level_type, PROX_ANYWHERE, zsec, - dur, permit_bands ); - } + if (in_bounds(mg.pos)) + summd = mons_place( mg ); // determine whether creating a monster is successful (summd != -1) {dlb}: // then handle the outcome {dlb}: - if (summd == -1) - { - if (see_grid( cr_x, cr_y )) - mpr("You see a puff of smoke."); - } - else - { - monsters *const creation = &menv[summd]; - - // dur should always be ENCH_ABJ_xx - if (dur >= 1 && dur <= 6) - creation->mark_summoned( dur, true ); - - // player summons do not give XP or other bonuses - // (you can still train skills on them though) - if ( player_made ) - creation->flags |= MF_CREATED_FRIENDLY; - - // look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT - // alert summoned being to player's presence - if (beha > NUM_BEHAVIOURS) - { - if (beha == BEH_FRIENDLY || beha == BEH_GOD_GIFT) - creation->flags |= MF_CREATED_FRIENDLY; - - if (beha == BEH_GOD_GIFT) - creation->flags |= MF_GOD_GIFT; - - if (!force_behaviour && player_angers_monster(creation)) - beha = BEH_HOSTILE; - - if (beha == BEH_CHARMED) - { - creation->attitude = ATT_HOSTILE; - creation->add_ench(ENCH_CHARM); - } - - // make summoned being aware of player's presence - behaviour_event(creation, ME_ALERT, MHITYOU); - } - - if (creation->type == MONS_RAKSHASA_FAKE && !one_chance_in(3)) - creation->add_ench(ENCH_INVIS); - } + if (summd == -1 && see_grid( mg.pos )) + mpr("You see a puff of smoke."); // the return value is either -1 (failure of some sort) // or the index of the monster placed (if I read things right) {dlb} return (summd); -} // end create_monster() +} bool empty_surrounds(int emx, int emy, dungeon_feature_type spc_wanted, diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h index daf972dfa9..13e1320922 100644 --- a/crawl-ref/source/monplace.h +++ b/crawl-ref/source/monplace.h @@ -92,6 +92,127 @@ enum proximity_type // proximity to player to create monster PROX_NEAR_STAIRS }; +enum mgen_flag_type +{ + MG_PERMIT_BANDS = 0x1, + MG_FORCE_PLACE = 0x2, + MG_FORCE_BEH = 0x4, + MG_PLAYER_MADE = 0x8 +}; + +// A structure with all the data needed to whip up a new monster. +struct mgen_data +{ + // Monster type. + monster_type cls; + + // If the monster is zombie-like, or a specialised draconian, this + // is the base monster that the monster is based on - should be + // set to MONS_PROGRAM_BUG when not used. + monster_type base_type; + + // Determines the behaviour of the monster after it is generated. This + // behaviour is an unholy combination of monster attitude + // (friendly, hostile) and monster initial state (asleep, wandering). + // XXX: Could use splitting up these aspects. + beh_type behaviour; + + // For summoned monsters, this is a measure of how long the summon will + // hang around, on a scale of 1-6, 6 being longest. Use 0 for monsters + // that aren't summoned. + int abjuration_duration; + + // Where the monster will be created. + coord_def pos; + + // The monster's foe, i.e. which monster it will want to attack. foe + // may be an index into the monster array (0 - (MAX_MONSTERS-1)), or + // it may be MHITYOU to indicate that the monster wants to attack the + // player, or MHITNOT, to indicate that the monster has no foe and is + // just wandering around. + int foe; + + // Generation flags from mgen_flag_type. + unsigned flags; + + // The number of hydra heads or manticore attack volleys. Note: + // in older version this field was used for both this and for base_type. + int number; + + // The colour of the monster + int colour; + + // A measure of how powerful the generated monster should be (for + // randomly chosen monsters), usually equal to the absolute depth + // that the player is in the dungeon. + int power; + + // How close to or far from the player the monster should be created. + // Is usually used only when the initial position (pos) is unspecified. + proximity_type proximity; + + // What place we're in, or pretending to be in, usually the place + // the player is actually in. + level_area_type level_type; + + // Some predefined vaults (aka maps) include flags to suppress random + // generation of monsters. When generating monsters, this is a mask of + // map flags to honour (such as MMT_NO_MONS to specify that we shouldn't + // randomly generate a monster inside a map that doesn't want it). These + // map flags are usually respected only when a dungeon level is being + // constructed, since at future points vault information may no longer + // be available (vault metadata is not preserved across game saves). + unsigned map_mask; + + mgen_data(monster_type mt = RANDOM_MONSTER, + beh_type beh = BEH_HOSTILE, + int abj = 0, + const coord_def &p = coord_def(-1, -1), + int mfoe = MHITNOT, + unsigned monflags = 0, + monster_type base = MONS_PROGRAM_BUG, + int monnumber = 0, + int moncolour = BLACK, + int monpower = you.your_level, + proximity_type prox = PROX_ANYWHERE, + level_area_type ltype = you.level_type) + + : cls(mt), base_type(base), behaviour(beh), + abjuration_duration(abj), pos(p), foe(mfoe), flags(monflags), + number(monnumber), colour(moncolour), power(monpower), + proximity(prox), level_type(ltype), map_mask(0) + { + } + + bool permit_bands() const { return (flags & MG_PERMIT_BANDS); } + bool force_place() const { return (flags & MG_FORCE_PLACE); } + + // Is there a valid position set on this struct that we want to use + // when placing the monster? + bool use_position() const { return in_bounds(pos); } + + bool summoned() const { return (abjuration_duration > 0); } + + static mgen_data sleeper_at(monster_type what, + const coord_def &where) + { + return mgen_data(what, BEH_SLEEP, 0, where); + } + + static mgen_data hostile_at(monster_type what, + const coord_def &where) + { + return mgen_data(what, BEH_HOSTILE, 0, where); + } + + static mgen_data alert_hostile_at(monster_type what, + const coord_def &where, + int abj_deg = 0) + { + return mgen_data(what, BEH_HOSTILE, abj_deg, where, MHITYOU); + } +}; + // last updated 13mar2001 {gdl} /* *********************************************************************** * called from: acr - lev-pand - monplace - dungeon @@ -111,11 +232,16 @@ enum proximity_type // proximity to player to create monster * 2 = don't place the monster near the player * 3 = place the monster near stairs (regardless of player pos) * *********************************************************************** */ -int mons_place( int mon_type, beh_type behaviour, int target, bool summoned, - int px, int py, int level_type = LEVEL_DUNGEON, - proximity_type proximity = PROX_ANYWHERE, - int extra = MONS_PROGRAM_BUG, - int dur = 0, bool permit_bands = false ); + +int mons_place( mgen_data mg ); + +/* int mons_place( int mon_type, beh_type behaviour, int target, bool summoned, */ +/* int px, int py, int level_type = LEVEL_DUNGEON, */ +/* proximity_type proximity = PROX_ANYWHERE, */ +/* int extra = MONS_PROGRAM_BUG, */ +/* int dur = 0, bool permit_bands = false ); */ + +int create_monster( mgen_data mg ); // last updated 12may2000 {dlb} /* *********************************************************************** @@ -123,10 +249,10 @@ int mons_place( int mon_type, beh_type behaviour, int target, bool summoned, * items - monstuff - mstuff2 - religion - spell - spells - * spells2 - spells3 - spells4 * *********************************************************************** */ -int create_monster( int cls, int dur, beh_type beha, int cr_x, int cr_y, - int hitting, int zsec, bool permit_bands = false, - bool force_place = false, bool force_behaviour = false, - bool player_made = false ); +/* int create_monster( int cls, int dur, beh_type beha, int cr_x, int cr_y, */ +/* int hitting, int zsec, bool permit_bands = false, */ +/* bool force_place = false, bool force_behaviour = false, */ +/* bool player_made = false ); */ class level_id; monster_type pick_random_monster(const level_id &place, @@ -160,11 +286,13 @@ monster_type summon_any_demon( demon_class_type demon_class ); * mons_place(). If you need to put a monster somewhere, use mons_place(). * Summoned creatures can be created with create_monster(). * *********************************************************************** */ -bool place_monster( int &id, int mon_type, int power, beh_type behaviour, - int target, bool summoned, int px, int py, bool allow_bands, - proximity_type proximity = PROX_ANYWHERE, - int extra = MONS_PROGRAM_BUG, int dur = 0, - unsigned mmask = 0 ); +int place_monster( mgen_data mg ); + + // int &id, int mon_type, int power, beh_type behaviour, + // int target, bool summoned, int px, int py, bool allow_bands, + // proximity_type proximity = PROX_ANYWHERE, + // int extra = MONS_PROGRAM_BUG, int dur = 0, + // unsigned mmask = 0 ); monster_type rand_dragon( dragon_class_type type ); bool drac_colour_incompatible(int drac, int colour); @@ -185,7 +313,7 @@ bool monster_habitable_grid(int monster_class, int flies = -1, bool paralysed = false); bool monster_can_submerge(const monsters *mons, dungeon_feature_type grid); -coord_def find_newmons_square(int mons_class, int x, int y); +coord_def find_newmons_square(int mons_class, const coord_def &p); coord_def find_newmons_square_contiguous(monster_type mons_class, const coord_def &start, int maxdistance = 3); diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 0d3f6d01bb..ec4f265c00 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -1003,9 +1003,10 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) && mons_holiness(monster) == MH_NATURAL && mons_weight(mons_species(monster->type))) { - if (create_monster( MONS_SPECTRAL_THING, 0, BEH_FRIENDLY, - monster->x, monster->y, you.pet_target, - mons_species(monster->type)) != -1) + if (create_monster( + mgen_data( MONS_SPECTRAL_THING, BEH_FRIENDLY, + 0, monster->pos(), you.pet_target, + 0, mons_species(monster->type) )) != -1) { if (death_message) mpr("A glowing mist starts to gather..."); @@ -1441,7 +1442,7 @@ static bool _valid_morph( monsters *monster, int new_mclass ) || new_mclass == MONS_SHAPESHIFTER || new_mclass == MONS_GLOWING_SHAPESHIFTER - // These require manual setting of mons.number to indicate + // These require manual setting of mons.base_monster to indicate // what they are a skeleton/zombie/simulacrum/spectral thing of, // which we currently aren't smart enough to handle. || mons_class_is_zombified(new_mclass) @@ -1582,8 +1583,9 @@ bool monster_polymorph( monsters *monster, monster_type targetc, const char old_ench_countdown = monster->ench_countdown; // deal with mons_sec - monster->type = targetc; - monster->number = MONS_PROGRAM_BUG; + monster->type = targetc; + monster->base_monster = MONS_PROGRAM_BUG; + monster->number = 0; mon_enchant abj = monster->get_ench(ENCH_ABJ); mon_enchant charm = monster->get_ench(ENCH_CHARM); @@ -3637,9 +3639,9 @@ static bool _handle_scroll(monsters *monster) if (mons_near(monster)) { simple_monster_message(monster, " reads a scroll."); - create_monster( MONS_ABOMINATION_SMALL, 2, - SAME_ATTITUDE(monster), monster->x, monster->y, - monster->foe, MONS_PROGRAM_BUG ); + create_monster( + mgen_data(MONS_ABOMINATION_SMALL, SAME_ATTITUDE(monster), + 2, monster->pos(), monster->foe) ); read = true; ident = ID_KNOWN_TYPE; } @@ -6069,14 +6071,14 @@ static bool _monster_move(monsters *monster) { if (mons_is_zombified(monster)) { - // for zombies, monster type is kept in mon->number - if (mons_itemuse(monster->number) >= MONUSE_OPEN_DOORS) + // for zombies, monster type is kept in mon->base_monster + if (mons_itemuse(monster->base_monster) >= MONUSE_OPEN_DOORS) { _mons_open_door(monster, newpos); return true; } } - else if (mons_itemuse(monster->type) >= MONUSE_OPEN_DOORS) + else if (mons_itemuse(monster->base_monster) >= MONUSE_OPEN_DOORS) { _mons_open_door(monster, newpos); return true; diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc index a4d2a3dec1..53efe61242 100644 --- a/crawl-ref/source/mstuff2.cc +++ b/crawl-ref/source/mstuff2.cc @@ -488,9 +488,9 @@ static void _do_high_level_summon(monsters *monster, bool monsterNearby, const monster_type which_mons = mpicker(); if (which_mons == MONS_PROGRAM_BUG) continue; - create_monster( which_mons, duration, - SAME_ATTITUDE(monster), monster->x, monster->y, - monster->foe, MONS_PROGRAM_BUG ); + create_monster( + mgen_data( which_mons, SAME_ATTITUDE(monster), duration, + monster->pos(), monster->foe )); } } @@ -577,9 +577,9 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) } } - create_monster( mons, 5, SAME_ATTITUDE(monster), - monster->x, monster->y, monster->foe, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data( mons, SAME_ATTITUDE(monster), 5, + monster->pos(), monster->foe ) ); } return; @@ -591,9 +591,9 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) for (sumcount = 0; sumcount < sumcount2; sumcount++) { - create_monster( RANDOM_MONSTER, 5, SAME_ATTITUDE(monster), - monster->x, monster->y, monster->foe, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data( RANDOM_MONSTER, SAME_ATTITUDE(monster), 5, + monster->pos(), monster->foe ) ); } return; @@ -602,9 +602,9 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) for (sumcount = 0; sumcount < sumcount2; sumcount++) { - create_monster( MONS_RAKSHASA_FAKE, 3, - SAME_ATTITUDE(monster), monster->x, monster->y, - monster->foe, MONS_PROGRAM_BUG ); + create_monster( + mgen_data( MONS_RAKSHASA_FAKE, SAME_ATTITUDE(monster), 3, + monster->pos(), monster->foe ) ); } return; @@ -631,9 +631,9 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) MONS_VERY_UGLY_THING : MONS_UGLY_THING; } - create_monster( mons, duration, SAME_ATTITUDE(monster), - monster->x, monster->y, - monster->foe, MONS_PROGRAM_BUG ); + create_monster( + mgen_data( mons, SAME_ATTITUDE(monster), duration, + monster->pos(), monster->foe ) ); } return; @@ -649,9 +649,11 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) duration = std::min(2 + monster->hit_dice / 5, 6); for (sumcount = 0; sumcount < sumcount2; sumcount++) { - create_monster( summon_any_demon(DEMON_LESSER), duration, - SAME_ATTITUDE(monster), monster->x, monster->y, - monster->foe, MONS_PROGRAM_BUG ); + create_monster( + mgen_data( summon_any_demon(DEMON_LESSER), + SAME_ATTITUDE(monster), + duration, monster->pos(), + monster->foe )); } return; @@ -662,22 +664,22 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) for (sumcount = 0; sumcount < sumcount2; sumcount++) { - create_monster( MONS_UFETUBUS, duration, SAME_ATTITUDE(monster), - monster->x, monster->y, monster->foe, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data(MONS_UFETUBUS, SAME_ATTITUDE(monster), duration, + monster->pos(), monster->foe)); } return; case SPELL_SUMMON_BEAST: // Geryon - create_monster( MONS_BEAST, 4, SAME_ATTITUDE(monster), - monster->x, monster->y, monster->foe, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data(MONS_BEAST, SAME_ATTITUDE(monster), 4, + monster->pos(), monster->foe)); return; case SPELL_SUMMON_ICE_BEAST: - create_monster( MONS_ICE_BEAST, 5, SAME_ATTITUDE(monster), - monster->x, monster->y, monster->foe, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data(MONS_ICE_BEAST, SAME_ATTITUDE(monster), 5, + monster->pos(), monster->foe)); return; case SPELL_SUMMON_MUSHROOMS: // Summon swarms of icky crawling fungi. @@ -689,11 +691,12 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) duration = std::min(2 + monster->hit_dice / 5, 6); for (int i = 0; i < sumcount2; ++i) { - create_monster(MONS_WANDERING_MUSHROOM, duration, - SAME_ATTITUDE(monster), - monster->x, monster->y, - monster->foe, - MONS_PROGRAM_BUG); + create_monster( + mgen_data(MONS_WANDERING_MUSHROOM, + SAME_ATTITUDE(monster), + duration, + monster->pos(), + monster->foe)); } return; @@ -731,9 +734,12 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) duration = std::min(2 + monster->hit_dice / 10, 6); for (sumcount = 0; sumcount < sumcount2; sumcount++) { - create_monster( summon_any_demon(DEMON_GREATER), duration, - SAME_ATTITUDE(monster), monster->x, monster->y, - monster->foe, MONS_PROGRAM_BUG ); + create_monster( + mgen_data(summon_any_demon(DEMON_GREATER), + SAME_ATTITUDE(monster), + duration, + monster->pos(), + monster->foe)); } return; @@ -747,7 +753,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) duration = std::min(2 + monster->hit_dice / 10, 6); { - std::vector<int> monsters; + std::vector<monster_type> monsters; for (sumcount = 0; sumcount < sumcount2; sumcount++) { @@ -763,10 +769,9 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast) for (int i = 0, size = monsters.size(); i < size; ++i) { - create_monster( monsters[i], duration, - SAME_ATTITUDE(monster), - monster->x, monster->y, monster->foe, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data(monsters[i], SAME_ATTITUDE(monster), duration, + monster->pos(), monster->foe)); } } return; @@ -2309,11 +2314,11 @@ bool silver_statue_effects(monsters *mons) "'s eyes glow " + weird_glow_colour() + '.'; simple_monster_message(mons, msg.c_str(), MSGCH_WARN); - create_monster( summon_any_demon((coinflip() ? DEMON_COMMON - : DEMON_LESSER)), - 5, BEH_HOSTILE, - you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data( + summon_any_demon((coinflip() ? DEMON_COMMON + : DEMON_LESSER)), + BEH_HOSTILE, 5, you.pos(), MHITYOU )); return (true); } return (false); diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index 7ab5ce1ce7..8a623f9bcd 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -1047,9 +1047,10 @@ static bool _beogh_blessing_reinforcement() else follower_type = RANDOM_ELEMENT(followers); - int monster = create_monster(follower_type, 0, BEH_GOD_GIFT, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG); + int monster = + create_monster( + mgen_data(follower_type, BEH_GOD_GIFT, 0, + you.pos(), you.pet_target)); if (monster != -1) { monsters *mon = &menv[monster]; @@ -1467,9 +1468,9 @@ static void _do_god_gift(bool prayed_for) monster_type thing_called = _random_servant(GOD_YREDELEMNUL); - if (create_monster(thing_called, 0, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MAKE_ITEM_RANDOM_RACE) != -1) + if (create_monster( + mgen_data(thing_called, BEH_FRIENDLY, 0, + you.pos(), you.pet_target)) != -1) { simple_god_message(" grants you an undead servant!"); more(); @@ -2873,9 +2874,9 @@ static bool _tso_retribution() int how_many = 1 + random2(you.experience_level / 5) + random2(3); for (int i = 0; i < how_many; i++) - if (create_monster( MONS_DAEVA, 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG ) != -1) + if (create_monster( + mgen_data(MONS_DAEVA, BEH_HOSTILE, 0, + you.pos(), MHITYOU )) != -1) { success = true; } @@ -2972,9 +2973,9 @@ static bool _zin_retribution() bool success = false; for (int i = 0; i < how_many; i++) - if (create_monster(MONS_ANGEL, 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data(MONS_ANGEL, BEH_HOSTILE, 0, + you.pos(), MHITYOU)) != -1) { success = true; } @@ -3119,9 +3120,13 @@ static bool _makhleb_retribution() if (random2(you.experience_level) > 7 && !one_chance_in(5)) { - const bool success = create_monster(MONS_EXECUTIONER + random2(5), 0, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG) != -1; + const bool success = + create_monster( + mgen_data( + static_cast<monster_type>( + MONS_EXECUTIONER + random2(5)), + BEH_HOSTILE, 0, + you.pos(), MHITYOU)) != -1; simple_god_message(success ? " sends a greater servant after you!" : "'s greater servant is unavoidably detained.", @@ -3133,9 +3138,12 @@ static bool _makhleb_retribution() int how_many = 1 + (you.experience_level / 7); for (int i = 0; i < how_many; i++) - if (create_monster(MONS_NEQOXEC + random2(5), 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data( + static_cast<monster_type>( + MONS_NEQOXEC + random2(5)), + BEH_HOSTILE, 0, + you.pos(), MHITYOU)) != -1) success = true; simple_god_message(success ? @@ -3158,8 +3166,9 @@ static bool _kikubaaqudgha_retribution() int how_many = 1 + (you.experience_level / 5) + random2(3); for (int i = 0; i < how_many; i++) - if (create_monster(MONS_REAPER, 0, BEH_HOSTILE, you.x_pos, - you.y_pos, MHITYOU, MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data(MONS_REAPER, BEH_HOSTILE, 0, you.pos(), + MHITYOU)) != -1) success = true; if (success) @@ -3193,9 +3202,9 @@ static bool _yredelemnul_retribution() { monster_type punisher = _random_servant(GOD_YREDELEMNUL); - if (create_monster(punisher, 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data(punisher, BEH_HOSTILE, 0, + you.pos(), MHITYOU)) != -1) count++; } @@ -3355,9 +3364,11 @@ static bool _beogh_retribution() set_ident_flags( item, ISFLAG_KNOW_TYPE ); // now create monster - int mons = create_monster( MONS_DANCING_WEAPON, 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG ); + int mons = + create_monster( + mgen_data::alert_hostile_at( + MONS_DANCING_WEAPON, + you.pos() )); // hand item information over to monster if (mons != -1) @@ -3411,9 +3422,10 @@ static bool _beogh_retribution() punisher = MONS_ORC; bool success = - (create_monster(punisher, 0, BEH_HOSTILE, you.x_pos, - you.y_pos, MHITYOU, - MONS_PROGRAM_BUG, true) != -1); + (create_monster( + mgen_data::alert_hostile_at( + punisher, + you.pos())) != -1); simple_god_message(success ? " sends forth an army of orcs." : @@ -3437,9 +3449,9 @@ static bool _okawaru_retribution() { monster_type punisher = _random_servant(GOD_OKAWARU); - if (create_monster(punisher, 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data::alert_hostile_at( + punisher, you.pos())) != -1) { success = true; } @@ -3529,9 +3541,10 @@ static bool _lugonu_retribution() if (random2(you.experience_level) > 7 && !one_chance_in(5)) { bool success = false; - if (create_monster(MONS_GREEN_DEATH + random2(3), 0, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data::alert_hostile_at( + static_cast<monster_type>(MONS_GREEN_DEATH + random2(3)), + you.pos())) != -1) { success = true; } @@ -3548,9 +3561,10 @@ static bool _lugonu_retribution() for (int loopy = 0; loopy < how_many; loopy++) { - if (create_monster(MONS_NEQOXEC + random2(5), 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data::alert_hostile_at( + static_cast<monster_type>(MONS_NEQOXEC + random2(5)), + you.pos())) != -1) { success = true; } diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc index 11f69b5836..7c19f33153 100644 --- a/crawl-ref/source/spells2.cc +++ b/crawl-ref/source/spells2.cc @@ -439,7 +439,7 @@ static int raise_corpse( int corps, int corx, int cory, returnVal = 0; else if (actual != 0) { - int type; + monster_type type = MONS_PROGRAM_BUG; if (mitm[corps].sub_type == CORPSE_BODY) { if (mons_zombie_size(mitm[corps].plus) == Z_SMALL) @@ -455,8 +455,11 @@ static int raise_corpse( int corps, int corx, int cory, type = MONS_SKELETON_LARGE; } - create_monster( type, 0, corps_beh, corx, cory, corps_hit, - mitm[corps].plus ); + create_monster( + mgen_data( + type, corps_beh, 0, + coord_def(corx, cory), corps_hit, + 0, static_cast<monster_type>(mitm[corps].plus))); destroy_item(corps); } @@ -468,7 +471,7 @@ void cast_twisted(int power, beh_type corps_beh, int corps_hit) { int total_mass = 0; int num_corpses = 0; - int type_resurr = MONS_ABOMINATION_SMALL; + monster_type type_resurr = MONS_ABOMINATION_SMALL; char colour; unsigned char rotted = 0; @@ -535,8 +538,11 @@ void cast_twisted(int power, beh_type corps_beh, int corps_hit) else colour = LIGHTRED; - int mon = create_monster( type_resurr, 0, corps_beh, you.x_pos, you.y_pos, - corps_hit, colour ); + mgen_data mg( type_resurr, corps_beh, 0, + you.pos(), corps_hit, 0, MONS_PROGRAM_BUG, 0, + colour ); + + int mon = create_monster(mg); if (mon == -1) mpr("The corpses collapse into a pulpy mess."); @@ -1240,7 +1246,7 @@ char burn_freeze(int pow, beam_type flavour) bool summon_elemental(int pow, int restricted_type, unsigned char unfriendly) { - int type_summoned = MONS_PROGRAM_BUG; // error trapping {dlb} + monster_type type_summoned = MONS_PROGRAM_BUG; struct dist smove; int dir_x; @@ -1347,12 +1353,12 @@ bool summon_elemental(int pow, int restricted_type, && random2(100) >= unfriendly); - if (create_monster( type_summoned, numsc, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - targ_x, targ_y, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG, false, false, - false, true ) == -1) + if (create_monster( + mgen_data( type_summoned, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, + numsc, + coord_def(targ_x, targ_y), + friendly ? you.pet_target : MHITYOU )) != -1) { return (false); } @@ -1409,11 +1415,11 @@ void summon_small_mammals(int pow) break; } - create_monster( thing_called, 3, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG, false, false, false, true); + create_monster( + mgen_data( thing_called, BEH_FRIENDLY, 3, + you.pos(), you.pet_target )); } -} // end summon_small_mammals() +} void summon_animals(int pow) { @@ -1451,11 +1457,11 @@ void summon_animals(int pow) bool friendly = (random2(pow) > 4); - create_monster( mon_chosen, 4, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - you.x_pos, you.y_pos, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG, false, false, false, true); + create_monster( + mgen_data( mon_chosen, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, 4, + you.pos(), + friendly ? you.pet_target : MHITYOU )); } } @@ -1469,12 +1475,12 @@ void summon_scorpions(int pow) { bool friendly = (random2(pow) > 3); - if (create_monster( MONS_SCORPION, 3, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - you.x_pos, you.y_pos, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG, false, false, - false, true) != -1) + if (create_monster( + mgen_data(MONS_SCORPION, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, + 3, + you.pos(), + friendly ? you.pet_target : MHITYOU)) != -1) { mprf("A scorpion appears.%s", friendly ? "" : " It doesn't look very happy."); @@ -1493,12 +1499,12 @@ void summon_ugly_thing(int pow) bool friendly = (random2(pow) > 3); - if (create_monster(ugly, numsc, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - you.x_pos, you.y_pos, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG, false, false, - false, true) != -1) + if (create_monster( + mgen_data(ugly, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, + numsc, + you.pos(), + friendly ? you.pet_target : MHITYOU)) != -1) { const char *prefix = (ugly == MONS_VERY_UGLY_THING) ? " very " : "n "; @@ -1507,7 +1513,7 @@ void summon_ugly_thing(int pow) } } // end summon_ugly_thing() -void summon_ice_beast_etc(int pow, int ibc, bool divine_gift) +void summon_ice_beast_etc(int pow, monster_type ibc, bool divine_gift) { int numsc = std::min(2 + (random2(pow) / 4), 6); beh_type beha = divine_gift ? BEH_GOD_GIFT : BEH_FRIENDLY; @@ -1555,10 +1561,10 @@ void summon_ice_beast_etc(int pow, int ibc, bool divine_gift) } } - int monster = create_monster( ibc, numsc, beha, - you.x_pos, you.y_pos, hitting, - MONS_PROGRAM_BUG, false, false, - false, true ); + int monster = + create_monster( + mgen_data(ibc, beha, numsc, + you.pos(), hitting)); if (monster != -1) { if (ibc == MONS_DAEVA) @@ -1626,9 +1632,11 @@ bool summon_berserker(int pow, bool god_gift) mon = MONS_STONE_GIANT; } - int mons = create_monster( mon, numsc, beha, you.x_pos, you.y_pos, - god_gift ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG ); + int mons = + create_monster( + mgen_data( mon, beha, numsc, + you.pos(), + god_gift ? you.pet_target : MHITYOU )); if (mons != -1) { @@ -1653,7 +1661,7 @@ bool summon_berserker(int pow, bool god_gift) bool summon_swarm( int pow, bool unfriendly, bool god_gift ) { - int thing_called = MONS_PROGRAM_BUG; // error trapping {dlb} + monster_type thing_called = MONS_PROGRAM_BUG; int numsc = 2 + random2(pow) / 10 + random2(pow) / 25; bool summoned = false; @@ -1718,11 +1726,10 @@ bool summon_swarm( int pow, bool unfriendly, bool god_gift ) else if (!unfriendly && random2(pow) > 7) behaviour = BEH_FRIENDLY; - if (create_monster( thing_called, 3, behaviour, - you.x_pos, you.y_pos, - !unfriendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG, false, false, - false, true ) != -1) + if (create_monster( + mgen_data( thing_called, behaviour, 3, + you.pos(), + !unfriendly ? you.pet_target : MHITYOU )) != -1) { summoned = true; } @@ -1734,7 +1741,7 @@ bool summon_swarm( int pow, bool unfriendly, bool god_gift ) void summon_undead(int pow) { int temp_rand = 0; - int thing_called = MONS_PROGRAM_BUG; // error trapping {dlb} + monster_type thing_called = MONS_PROGRAM_BUG; int numsc = 1 + random2(pow) / 30 + random2(pow) / 30; numsc = stepdown_value(numsc, 2, 2, 6, 8); //see stuff.cc {dlb} @@ -1751,12 +1758,11 @@ void summon_undead(int pow) bool friendly = (random2(pow) > 5); - if (create_monster( thing_called, 5, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - you.x_pos, you.y_pos, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG, false, false, - false, true ) != -1) + if (create_monster( + mgen_data(thing_called, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, 5, + you.pos(), + friendly ? you.pet_target : MHITYOU)) != -1) { if (friendly) mpr("An insubstantial figure forms in the air."); @@ -1807,17 +1813,17 @@ void summon_things( int pow ) while (big_things > 0) { - create_monster( MONS_TENTACLED_MONSTROSITY, 6, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG, false, false, false, true ); + create_monster( + mgen_data(MONS_TENTACLED_MONSTROSITY, BEH_FRIENDLY, 6, + you.pos(), you.pet_target)); big_things--; } while (numsc > 0) { - create_monster( MONS_ABOMINATION_LARGE, 6, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG, false, false, false, true ); + create_monster( + mgen_data(MONS_ABOMINATION_LARGE, BEH_FRIENDLY, 6, + you.pos(), you.pet_target )); numsc--; } diff --git a/crawl-ref/source/spells2.h b/crawl-ref/source/spells2.h index 98a969c0b1..8efb768298 100644 --- a/crawl-ref/source/spells2.h +++ b/crawl-ref/source/spells2.h @@ -132,7 +132,7 @@ bool restore_stat(unsigned char which_stat, unsigned char stat_gain, /* *********************************************************************** * called from: ability - spell * *********************************************************************** */ -void summon_ice_beast_etc(int pow, int ibc, bool divine_gift = false); +void summon_ice_beast_etc(int pow, monster_type ibc, bool divine_gift = false); // last updated 24may2000 {dlb} diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index 36dd8baf38..a1ab61f9e3 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -432,7 +432,8 @@ void simulacrum(int power) || (you.inv[ chunk ].base_type == OBJ_FOOD && you.inv[ chunk ].sub_type == FOOD_CHUNK))) { - const int mons_type = you.inv[ chunk ].plus; + const monster_type mons_type = + static_cast<monster_type>(you.inv[ chunk ].plus); // Can't create more than the available chunks if (you.inv[ chunk ].quantity < max_num) @@ -444,9 +445,11 @@ void simulacrum(int power) for (int i = 0; i < max_num; i++) { - if (create_monster( MONS_SIMULACRUM_SMALL, 6, - BEH_FRIENDLY, you.x_pos, you.y_pos, - you.pet_target, mons_type ) != -1) + if (create_monster( + mgen_data(MONS_SIMULACRUM_SMALL, + BEH_FRIENDLY, 6, + you.pos(), you.pet_target, + 0, mons_type)) != -1) { summoned++; } @@ -503,9 +506,10 @@ bool dancing_weapon(int pow, bool force_hostile, bool silent) hitting = MHITYOU; } - summs = create_monster(MONS_DANCING_WEAPON, numsc, beha, - you.x_pos, you.y_pos, hitting, - MONS_PROGRAM_BUG); + summs = + create_monster( + mgen_data(MONS_DANCING_WEAPON, beha, numsc, + you.pos(), hitting)); if (summs == -1) failed = true; } diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc index e2ff3ab3c1..0150125569 100644 --- a/crawl-ref/source/spells4.cc +++ b/crawl-ref/source/spells4.cc @@ -426,10 +426,9 @@ void cast_summon_butterflies(int pow) for (int scount = 1; scount < num; scount++) { - create_monster( MONS_BUTTERFLY, 3, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG, false, false, - false, true ); + create_monster( + mgen_data(MONS_BUTTERFLY, BEH_FRIENDLY, 3, + you.pos(), you.pet_target)); } } @@ -466,15 +465,14 @@ void cast_summon_large_mammal(int pow) } } - create_monster( mon, 3, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG, false, false, - false, true ); + create_monster( + mgen_data( mon, BEH_FRIENDLY, 3, + you.pos(), you.pet_target )); } void cast_sticks_to_snakes(int pow) { - int mon; + monster_type mon = MONS_PROGRAM_BUG; int how_many = 0; int max = 1 + random2( 1 + you.skills[SK_TRANSMIGRATION] ) / 4; int dur = std::min(3 + random2(pow) / 20, 5); @@ -511,10 +509,9 @@ void cast_sticks_to_snakes(int pow) mon = MONS_SMALL_SNAKE; } - if (create_monster( mon, dur, beha, - you.x_pos, you.y_pos, hitting, - MONS_PROGRAM_BUG, false, false, - false, true ) != -1) + if (create_monster( + mgen_data( mon, beha, dur, + you.pos(), hitting )) != -1) { how_many++; } @@ -557,10 +554,9 @@ void cast_sticks_to_snakes(int pow) if (pow > 20 && one_chance_in(3)) mon = MONS_BROWN_SNAKE; - if (create_monster( mon, dur, beha, - you.x_pos, you.y_pos, hitting, - MONS_PROGRAM_BUG, false, false, - false, true ) != -1) + if (create_monster( + mgen_data( mon, beha, dur, + you.pos(), hitting )) != -1) { how_many++; } @@ -593,12 +589,11 @@ void cast_summon_dragon(int pow) // a very high level spell so it might be okay). -- bwr const bool friendly = (random2(pow) > 5); - if (create_monster( MONS_DRAGON, 3, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - you.x_pos, you.y_pos, - friendly ? you.pet_target : MHITYOU, - MONS_PROGRAM_BUG, false, false, - false, true ) != -1) + if (create_monster( + mgen_data( MONS_DRAGON, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, 3, + you.pos(), + friendly ? you.pet_target : MHITYOU )) != -1) { mprf("A dragon appears.%s", friendly ? "" : " It doesn't look very happy."); @@ -638,11 +633,10 @@ void cast_conjure_ball_lightning( int pow ) ty = you.y_pos; } - int mon = mons_place( MONS_BALL_LIGHTNING, BEH_FRIENDLY, MHITNOT, - true, tx, ty ); - - // int mon = create_monster( MONS_BALL_LIGHTNING, 0, BEH_FRIENDLY, - // tx, ty, MHITNOT, MONS_PROGRAM_BUG ); + int mon = + mons_place( + mgen_data( MONS_BALL_LIGHTNING, BEH_FRIENDLY, 0, + coord_def(tx, ty) )); if (mon != -1) { @@ -1826,21 +1820,6 @@ void cast_fulsome_distillation( int powc ) } } -void make_shuggoth(int x, int y, int hp) -{ - int mon = create_monster( MONS_SHUGGOTH, 100 + random2avg(58, 3), - BEH_HOSTILE, x, y, MHITNOT, MONS_PROGRAM_BUG, - false, false, false, true ); - - if (mon != -1) - { - menv[mon].hit_points = hp; - menv[mon].max_hit_points = hp; - } - - return; -} // end make_shuggoth() - static int rot_living(int x, int y, int pow, int message) { UNUSED( message ); diff --git a/crawl-ref/source/spells4.h b/crawl-ref/source/spells4.h index d3b0bf36d1..937bdabe13 100644 --- a/crawl-ref/source/spells4.h +++ b/crawl-ref/source/spells4.h @@ -57,9 +57,6 @@ void cast_dispersal(int pow); void cast_snake_charm(int pow); void cast_stoneskin(int pow); -void cast_shuggoth_seed(int powc); -void make_shuggoth(int x, int y, int hp); - int cast_semi_controlled_blink(int pow); bool cast_portal_projectile(int pow, bolt& beam); diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index 8d96ab7d45..77d9b034f7 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -1581,8 +1581,9 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail ) if (dem_beh == BEH_CHARMED) mpr("You don't feel so good about this..."); - create_monster( summon_any_demon(DEMON_GREATER), 5, dem_beh, - you.x_pos, you.y_pos, MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data( summon_any_demon(DEMON_GREATER), dem_beh, 5, + you.pos(), MHITYOU )); } break; @@ -1796,9 +1797,9 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail ) case SPELL_SHADOW_CREATURES: { mpr( "Wisps of shadow whirl around you..." ); - create_monster( RANDOM_MONSTER, 2, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data( RANDOM_MONSTER, BEH_FRIENDLY, 2, + you.pos(), you.pet_target )); break; } @@ -2358,8 +2359,9 @@ static void _miscast_translocation(int severity, const char* cause) break; case 5: mpr("Space twists in upon itself!"); - create_monster( MONS_SPATIAL_VORTEX, 3, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data( MONS_SPATIAL_VORTEX, BEH_HOSTILE, 3, + you.pos(), MHITYOU )); break; } break; @@ -2391,9 +2393,9 @@ static void _miscast_translocation(int severity, const char* cause) const int count = 2 + random2(3); for (int i = 0; i < count; ++i) { - create_monster( MONS_SPATIAL_VORTEX, 3, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data(MONS_SPATIAL_VORTEX, BEH_HOSTILE, 3, + you.pos(), MHITYOU)); } } break; @@ -2485,15 +2487,16 @@ static void _miscast_summoning(int severity, const char* cause) case 3: mpr("Space twists in upon itself!"); - create_monster( MONS_SPATIAL_VORTEX, 3, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data(MONS_SPATIAL_VORTEX, BEH_HOSTILE, 3, + you.pos(), MHITYOU)); break; case 4: case 5: - if (create_monster( summon_any_demon(DEMON_LESSER), 5, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ) != -1) + if (create_monster( + mgen_data(summon_any_demon(DEMON_LESSER), + BEH_HOSTILE, 5, you.pos(), MHITYOU)) != -1) { mpr("Something appears in a flash of light!"); } @@ -2510,18 +2513,20 @@ static void _miscast_summoning(int severity, const char* cause) const int count = 2 + random2(3); for (int i = 0; i < count; ++i) { - create_monster( MONS_SPATIAL_VORTEX, 3, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data(MONS_SPATIAL_VORTEX, + BEH_HOSTILE, 3, + you.pos(), MHITYOU)); } } break; case 1: case 2: - if (create_monster( summon_any_demon(DEMON_COMMON), 5, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data(summon_any_demon(DEMON_COMMON), + BEH_HOSTILE, 5, + you.pos(), MHITYOU)) != -1) { mpr("Something forms out of thin air!"); } @@ -2531,27 +2536,23 @@ static void _miscast_summoning(int severity, const char* cause) case 4: case 5: mpr("A chorus of chattering voices calls out to you!"); - create_monster( summon_any_demon(DEMON_LESSER), 5, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data(summon_any_demon(DEMON_LESSER), + BEH_HOSTILE, 5, you.pos(), MHITYOU)); - create_monster( summon_any_demon(DEMON_LESSER), 5, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data(summon_any_demon(DEMON_LESSER), + BEH_HOSTILE, 5, you.pos(), MHITYOU)); if (coinflip()) - { - create_monster( summon_any_demon(DEMON_LESSER), 5, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ); - } - + create_monster( + mgen_data(summon_any_demon(DEMON_LESSER), + BEH_HOSTILE, 5, you.pos(), MHITYOU)); + if (coinflip()) - { - create_monster( summon_any_demon(DEMON_LESSER), 5, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ); - } + create_monster( + mgen_data(summon_any_demon(DEMON_LESSER), + BEH_HOSTILE, 5, you.pos(), MHITYOU)); break; } break; @@ -2560,18 +2561,20 @@ static void _miscast_summoning(int severity, const char* cause) switch (random2(4)) { case 0: - if (create_monster( MONS_ABOMINATION_SMALL, 0, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG ) != -1) + if (create_monster( + mgen_data::alert_hostile_at( + MONS_ABOMINATION_SMALL, + you.pos())) != -1) { mpr("Something forms out of thin air."); } break; case 1: - if (create_monster( summon_any_demon(DEMON_GREATER), 0, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ) != -1) + if (create_monster( + mgen_data::alert_hostile_at( + summon_any_demon(DEMON_GREATER), + you.pos())) != -1) { mpr("You sense a hostile presence."); } @@ -2580,20 +2583,18 @@ static void _miscast_summoning(int severity, const char* cause) case 2: mpr("Something turns its malign attention towards you..."); - create_monster( summon_any_demon(DEMON_COMMON), 3, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data::alert_hostile_at( + summon_any_demon(DEMON_COMMON), you.pos(), 3)); - create_monster( summon_any_demon(DEMON_COMMON), 3, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG ); + create_monster( + mgen_data::alert_hostile_at( + summon_any_demon(DEMON_COMMON), you.pos(), 3)); if (coinflip()) - { - create_monster(summon_any_demon(DEMON_COMMON), 3, - BEH_HOSTILE, you.x_pos, you.y_pos, - MHITYOU, MONS_PROGRAM_BUG); - } + create_monster( + mgen_data::alert_hostile_at( + summon_any_demon(DEMON_COMMON), you.pos(), 3)); break; case 3: @@ -2797,23 +2798,19 @@ static void _miscast_necromancy(int severity, const char* cause) case 0: mpr("Flickering shadows surround you."); - create_monster( MONS_SHADOW, 2, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG ); + create_monster( + mgen_data::alert_hostile_at( + MONS_SHADOW, you.pos(), 2)); if (coinflip()) - { - create_monster( MONS_SHADOW, 2, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG ); - } + create_monster( + mgen_data::alert_hostile_at( + MONS_SHADOW, you.pos(), 2)); if (coinflip()) - { - create_monster( MONS_SHADOW, 2, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG ); - } + create_monster( + mgen_data::alert_hostile_at( + MONS_SHADOW, you.pos(), 2)); break; case 1: @@ -2866,18 +2863,18 @@ static void _miscast_necromancy(int severity, const char* cause) break; case 4: - if (create_monster( MONS_SOUL_EATER, 4, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data::alert_hostile_at( + MONS_SOUL_EATER, you.pos(), 4)) != -1) { mpr("Something reaches out for you..."); } break; case 5: - if (create_monster( MONS_REAPER, 4, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, - MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data::alert_hostile_at( + MONS_REAPER, you.pos(), 4)) != -1) { mpr("Death has come for you..."); } diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index 099f0b81f5..fb9ea9b870 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -1101,6 +1101,12 @@ bool map_bounds( int x, int y ) && y >= Y_BOUND_1 && y <= Y_BOUND_2); } +coord_def random_in_bounds() +{ + return coord_def( random_range(MAPGEN_BORDER, GXM - MAPGEN_BORDER - 1), + random_range(MAPGEN_BORDER, GYM - MAPGEN_BORDER - 1) ); +} + // Returns a random location in (x_pos, y_pos)... the grid will be // DNGN_FLOOR if clear, and NON_MONSTER if empty. Exclusive tells // if we're using in_bounds() or map_bounds() restriction. diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h index 8d07f41206..08eba87624 100644 --- a/crawl-ref/source/stuff.h +++ b/crawl-ref/source/stuff.h @@ -109,6 +109,7 @@ int yesnoquit( const char* str, bool safe = true, int safeanswer = 0, bool in_bounds( int x, int y ); bool map_bounds( int x, int y ); +coord_def random_in_bounds(); inline bool in_bounds(const coord_def &p) { diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 92b4c994ee..4a3f586a66 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -1784,6 +1784,7 @@ static void marshall_monster(writer &th, const monsters &m) marshallShort(th, m.hit_points); marshallShort(th, m.max_hit_points); marshallShort(th, m.number); + marshallShort(th, m.base_monster); marshallShort(th, m.colour); for (int j = 0; j < NUM_MONSTER_SLOTS; j++) @@ -2047,6 +2048,10 @@ static void unmarshall_monster(reader &th, monsters &m) m.hit_points = unmarshallShort(th); m.max_hit_points = unmarshallShort(th); m.number = unmarshallShort(th); + if (_tag_minor_version >= TAG_MINOR_MONBASE) + m.base_monster = static_cast<monster_type>(unmarshallShort(th)); + else + m.base_monster = static_cast<monster_type>(m.number); m.colour = unmarshallShort(th); @@ -2071,7 +2076,7 @@ static void tag_read_level_monsters(reader &th, char minorVersion) // how many mons_alloc? count = unmarshallByte(th); for (i = 0; i < count; ++i) - env.mons_alloc[i] = unmarshallShort(th); + env.mons_alloc[i] = static_cast<monster_type>( unmarshallShort(th) ); // how many monsters? count = unmarshallShort(th); diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h index b7ff700e69..3b96dec779 100644 --- a/crawl-ref/source/tags.h +++ b/crawl-ref/source/tags.h @@ -54,7 +54,8 @@ enum tag_minor_version TAG_MINOR_QUIVER = 3, // Added quiver TAG_MINOR_MAPMARK = 4, // Added sizes to map markers TAG_MINOR_MONNAM = 5, // Monsters get individual names - TAG_MINOR_VERSION = 5 // Current version + TAG_MINOR_MONBASE = 6, // Zombie base monster gets its own field. + TAG_MINOR_VERSION = 6 // Current version }; diff --git a/crawl-ref/source/tile1.cc b/crawl-ref/source/tile1.cc index b8ed61ebad..2d1909fece 100644 --- a/crawl-ref/source/tile1.cc +++ b/crawl-ref/source/tile1.cc @@ -299,12 +299,8 @@ static int _tileidx_monster_base(int mon_idx, bool detected) return TILE_MONS_GRIFFON; case MONS_HYDRA: - { - // Number of heads - int heads = mon->number; - if (heads > 7) heads = 7; - return TILE_MONS_HYDRA + heads - 1; - } + // Number of heads + return TILE_MONS_HYDRA + std::min(mon->number, 7) - 1; case MONS_SKELETON_SMALL: return TILE_MONS_SKELETON_SMALL; diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc index 617517fd7e..ca1c9635fb 100644 --- a/crawl-ref/source/xom.cc +++ b/crawl-ref/source/xom.cc @@ -523,9 +523,10 @@ static bool xom_is_good(int sever) if (!is_demonic) numdifferent++; - summons[i] = create_monster(mon, 3, BEH_GOD_GIFT, - you.x_pos, you.y_pos, - you.pet_target, MONS_PROGRAM_BUG); + summons[i] = + create_monster( + mgen_data(mon, BEH_GOD_GIFT, 3, + you.pos(), you.pet_target)); if (summons[i] != -1) success = true; @@ -606,8 +607,8 @@ static bool xom_is_good(int sever) beh_type beh = (different && hostiletype) ? BEH_HOSTILE : BEH_GOD_GIFT; - if (create_monster(mon, 6, beh, you.x_pos, you.y_pos, - you.pet_target, MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data(mon, beh, 6, you.pos(), you.pet_target)) != -1) { if (different) god_speaks(GOD_XOM, _get_xom_speech("single holy summon")); @@ -686,9 +687,9 @@ static bool xom_is_good(int sever) beh_type beh = (different && hostiletype) ? BEH_HOSTILE : BEH_GOD_GIFT; - if (create_monster(xom_random_demon(sever, one_chance_in(8)), - 0, beh, you.x_pos, you.y_pos, - you.pet_target, MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data(xom_random_demon(sever, one_chance_in(8)), + beh, 0, you.pos(), you.pet_target)) != -1) { if (different) god_speaks(GOD_XOM, _get_xom_speech("single major holy summon")); @@ -853,9 +854,9 @@ static bool xom_is_bad(int sever) for (int i = 0; i < numdemons; i++) { - if (create_monster(xom_random_punishment_demon(sever), - 4, BEH_HOSTILE, you.x_pos, you.y_pos, - MHITNOT, MONS_PROGRAM_BUG) != -1) + if (create_monster( + mgen_data(xom_random_punishment_demon(sever), + BEH_HOSTILE, 4, you.pos())) != -1) { success = true; } |