diff options
-rw-r--r-- | crawl-ref/source/abyss.cc | 63 | ||||
-rw-r--r-- | crawl-ref/source/abyss.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/acr.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 9 | ||||
-rw-r--r-- | crawl-ref/source/fight.cc | 11 | ||||
-rw-r--r-- | crawl-ref/source/files.cc | 105 | ||||
-rw-r--r-- | crawl-ref/source/items.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/makefile.obj | 1 | ||||
-rw-r--r-- | crawl-ref/source/misc.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 92 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 11 | ||||
-rw-r--r-- | crawl-ref/source/mtransit.cc | 159 | ||||
-rw-r--r-- | crawl-ref/source/mtransit.h | 39 | ||||
-rw-r--r-- | crawl-ref/source/spells1.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/spells4.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/spl-cast.cc | 12 | ||||
-rw-r--r-- | crawl-ref/source/tags.cc | 358 | ||||
-rw-r--r-- | crawl-ref/source/travel.h | 9 |
19 files changed, 604 insertions, 287 deletions
diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc index ac82243fff..eb00207c74 100644 --- a/crawl-ref/source/abyss.cc +++ b/crawl-ref/source/abyss.cc @@ -21,6 +21,7 @@ #include "cloud.h" #include "misc.h" #include "monplace.h" +#include "mtransit.h" #include "dungeon.h" #include "items.h" #include "lev-pand.h" @@ -190,35 +191,27 @@ static void generate_area(unsigned char gx1, unsigned char gy1, } } +static void abyss_lose_monster(monsters &mons) +{ + if (mons.needs_transit()) + mons.set_transit( level_id(LEVEL_ABYSS) ); + + mons.reset(); +} void area_shift(void) /*******************/ { for (unsigned int i = 0; i < MAX_MONSTERS; i++) { - if (menv[i].type == -1) - { + monsters &m = menv[i]; + + if (!m.alive()) continue; - } // remove non-nearby monsters - if (menv[i].x < you.x_pos - 10 - || menv[i].x >= you.x_pos + 11 - || menv[i].y < you.y_pos - 10 || menv[i].y >= you.y_pos + 11) - { - menv[i].type = -1; - - mgrd[menv[i].x][menv[i].y] = NON_MONSTER; - - for (unsigned int j = 0; j < NUM_MONSTER_SLOTS; j++) - { - if (menv[i].inv[j] != NON_ITEM) - { - destroy_item( menv[i].inv[j] ); - menv[i].inv[j] = NON_ITEM; - } - } - } + if (grid_distance(m.x, m.y, you.x_pos, you.y_pos) > 10) + abyss_lose_monster(m); } for (int i = 5; i < (GXM - 5); i++) @@ -226,17 +219,17 @@ void area_shift(void) for (int j = 5; j < (GYM - 5); j++) { // don't modify terrain by player - if (i >= you.x_pos - 10 && i < you.x_pos + 11 - && j >= you.y_pos - 10 && j < you.y_pos + 11) - { + if (grid_distance(i, j, you.x_pos, you.y_pos) <= 10) continue; - } // nuke terrain otherwise grd[i][j] = DNGN_UNSEEN; // nuke items destroy_item_stack( i, j ); + + if (mgrd[i][j] != NON_MONSTER) + abyss_lose_monster( menv[ mgrd[i][j] ] ); } } @@ -298,8 +291,20 @@ void area_shift(void) mons_place( RANDOM_MONSTER, BEH_HOSTILE, MHITNOT, false, 1, 1, LEVEL_ABYSS, PROX_AWAY_FROM_PLAYER ); // PROX_ANYWHERE? } + + // And allow monsters in transit another chance to return. + place_transiting_monsters(); } +void save_abyss_uniques() +{ + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters &m = menv[i]; + if (m.alive() && m.needs_transit()) + m.set_transit( level_id(LEVEL_ABYSS) ); + } +} void abyss_teleport( bool new_area ) /**********************************/ @@ -336,6 +341,12 @@ void abyss_teleport( bool new_area ) init_pandemonium(); // get new monsters set_colours_from_monsters(); // and new colours + for (i = 0; i < MAX_MONSTERS; i++) + { + if (menv[i].alive()) + abyss_lose_monster(menv[i]); + } + // Orbs and fixed artefacts are marked as "lost in the abyss" for (k = 0; k < MAX_ITEMS; k++) { @@ -356,9 +367,6 @@ void abyss_teleport( bool new_area ) } } - for (i = 0; i < MAX_MONSTERS; i++) - menv[i].type = -1; - for (i = 0; i < MAX_CLOUDS; i++) delete_cloud( i ); @@ -384,4 +392,5 @@ void abyss_teleport( bool new_area ) if ( one_chance_in(5) ) grd[you.x_pos + 1][you.y_pos] = DNGN_ALTAR_LUCY; + place_transiting_monsters(); } diff --git a/crawl-ref/source/abyss.h b/crawl-ref/source/abyss.h index 9ecef56114..d25770473f 100644 --- a/crawl-ref/source/abyss.h +++ b/crawl-ref/source/abyss.h @@ -33,5 +33,6 @@ void area_shift(void); * *********************************************************************** */ void abyss_teleport( bool new_area ); +void save_abyss_uniques(); #endif diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index f92c3747b3..a3a1bebe24 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -2981,8 +2981,7 @@ static void move_player(int move_x, int move_y) ig2++; } - snprintf( info, INFO_SIZE, "Number of items present: %d", ig2 ); - mpr( info, MSGCH_DIAGNOSTICS ); + mprf( MSGCH_DIAGNOSTICS, "Number of items present: %d", ig2 ); ig2 = 0; for (igly = 0; igly < MAX_MONSTERS; igly++) diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index efce88b640..70b41f74d6 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -2374,8 +2374,9 @@ enum monster_flag_type MF_SEEN = 0x40, // Player already seen monster MF_DIVINE_PROTECTION = 0x80, // Monster has divine protection. - MF_KNOWN_MIMIC = 0x100 // Mimic that has taken a swing at the PC, + MF_KNOWN_MIMIC = 0x100, // Mimic that has taken a swing at the PC, // or that the player has inspected with ? + MF_BANISHED = 0x200 // Monster that has been banished. }; enum mon_dam_level_type @@ -3624,6 +3625,7 @@ enum tag_type // used during save/load process to identify data blocks TAG_LEVEL_MONSTERS, // monsters TAG_GHOST, // ghost TAG_LEVEL_ATTITUDE, // monster attitudes + TAG_LOST_MONSTERS, // monsters in transit NUM_TAGS }; diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index cd7002855c..e2083c1c3a 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -816,6 +816,7 @@ struct mon_attack_def }; class ghost_demon; +class level_id; class monsters : public actor { @@ -857,9 +858,17 @@ public: std::auto_ptr<ghost_demon> ghost; // Ghost information. public: + bool needs_transit() const; + void set_transit(level_id destination); + bool find_place_to_live(bool near_player = false); + bool find_place_near_player(); + bool find_home_in(coord_def s, coord_def e); + bool find_home_anywhere(); + void set_ghost(const ghost_demon &ghost); void ghost_init(); void pandemon_init(); + void destroy_inventory(); void reset(); void load_spells(int spellbook); diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index 7b46f788d3..0d741668c5 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -495,6 +495,8 @@ bool melee_attack::player_attack() if (cancel_attack) return (false); + coord_def where = defender->pos(); + if (player_hits_monster()) { did_hit = true; @@ -533,11 +535,14 @@ bool melee_attack::player_attack() const bool did_primary_hit = did_hit; - if (unarmed_ok && player_aux_unarmed()) + if (unarmed_ok && where == defender->pos() && player_aux_unarmed()) return (true); - if ((did_primary_hit || did_hit) && def->type != -1) + if ((did_primary_hit || did_hit) && def->alive() + && where == defender->pos()) + { print_wounds(def); + } return (did_primary_hit || did_hit); } @@ -1691,7 +1696,7 @@ bool melee_attack::apply_damage_brand() break; } - if (coinflip()) + if (you.level_type != LEVEL_ABYSS && coinflip()) { emit_nodmg_hit_message(); defender->banish(); diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index 5e73131373..3beb2d137e 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -68,6 +68,7 @@ #include "monstuff.h" #include "mon-util.h" #include "mstuff2.h" +#include "mtransit.h" #include "notes.h" #include "player.h" #include "randart.h" @@ -540,14 +541,6 @@ bool travel_load_map( char branch, int absdepth ) return true; } -struct follower { - monsters mons; - std::vector<item_def> items; - - follower() : mons(), items() { } - follower(const monsters &m) : mons(m), items() { } -}; - void load( unsigned char stair_taken, int load_mode, bool was_a_labyrinth, char old_level, char where_were_you2 ) { @@ -623,21 +616,8 @@ void load( unsigned char stair_taken, int load_mode, bool was_a_labyrinth, #endif follower f(*fmenv); - - for (int minvc = 0; minvc < NUM_MONSTER_SLOTS; ++minvc) - { - const int item = fmenv->inv[minvc]; - if (item == NON_ITEM) - { - f.items.push_back(item_def()); - continue; - } - - f.items.push_back(mitm[item]); - destroy_item( item ); - } - followers.push_back(f); + fmenv->destroy_inventory(); monster_cleanup(fmenv); } } // end of grabbing followers @@ -887,88 +867,22 @@ found_stair: if (mgrd[you.x_pos][you.y_pos] != NON_MONSTER) monster_teleport(&menv[mgrd[you.x_pos][you.y_pos]], true); - int following = 0; - // actually "move" the followers if applicable if ((you.level_type == LEVEL_DUNGEON || you.level_type == LEVEL_PANDEMONIUM) && load_mode == LOAD_ENTER_LEVEL) { - for (int ic = 0; ic < 2; ic++) + while (!followers.empty()) { - for (count_x = you.x_pos - 6; count_x < you.x_pos + 7; - count_x++) - { - for (count_y = you.y_pos - 6; count_y < you.y_pos + 7; - count_y++) - { - if (ic == 0 - && ((count_x < you.x_pos - 1) - || (count_x > you.x_pos + 1) - || (count_y < you.y_pos - 1) - || (count_y > you.y_pos + 1))) - { - continue; - } - - if (count_x == you.x_pos && count_y == you.y_pos) - continue; - - if (mgrd[count_x][count_y] != NON_MONSTER - || grd[count_x][count_y] < DNGN_FLOOR) - { - continue; - } - - while (menv[following].type != -1) - { - following++; - - if (following >= MAX_MONSTERS) - goto out_of_foll; - } - - if (followers.size()) - { - follower f = followers.front(); - followers.erase(followers.begin()); - - menv[following] = f.mons; - menv[following].x = count_x; - menv[following].y = count_y; - menv[following].target_x = 0; - menv[following].target_y = 0; - menv[following].flags |= MF_JUST_SUMMONED; - - for (int minvc = 0; minvc < NUM_MONSTER_SLOTS; minvc++) - { - menv[following].inv[minvc] = NON_ITEM; - - const item_def &minvitem = f.items[minvc]; - if (minvitem.base_type != OBJ_UNASSIGNED) - { - int itmf = get_item_slot(0); - if (itmf == NON_ITEM) - { - menv[following].inv[minvc] = NON_ITEM; - continue; - } - - mitm[itmf] = minvitem; - mitm[itmf].x = 0; - mitm[itmf].y = 0; - mitm[itmf].link = NON_ITEM; - menv[following].inv[minvc] = itmf; - } - } - mgrd[count_x][count_y] = following; - } // followers.size() - } - } + follower f = followers.front(); + followers.erase(followers.begin()); + f.place(true); } } // end of moving followers - out_of_foll: + // Load monsters in transit. + place_transiting_monsters(); + redraw_all(); // Sanity forcing of monster inventory items (required?) @@ -1253,7 +1167,6 @@ void load_ghost(void) } } - void restore_game(void) { std::string charFile = get_savedir_filename(you.your_name, "", "sav"); diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index 98a2c732e2..eb62d1fc99 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -2182,12 +2182,16 @@ static void update_enchantments( struct monsters *mon, int levels ) case ENCH_ABJ_VI: if (remove_enchant_levels( mon, i, ENCH_ABJ_I, levels )) { + // Re-add ABJ_I so that monster_die doesn't try to send the + // monster to the Abyss on KILL_RESET. + mons_add_ench( mon, ENCH_ABJ_I ); monster_die( mon, KILL_RESET, 0 ); } break; case ENCH_SHORT_LIVED: + mons_add_ench( mon, ENCH_ABJ_I ); monster_die( mon, KILL_RESET, 0 ); break; diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index c192363222..a1bea5253a 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -45,6 +45,7 @@ monstuff.o \ monspeak.o \ mon-util.o \ mstuff2.o \ +mtransit.o \ mutation.o \ newgame.o \ notes.o \ diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 19da6b667e..4dc7bc2544 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -35,6 +35,7 @@ #include "externs.h" +#include "abyss.h" #include "branch.h" #include "cloud.h" #include "delay.h" @@ -834,6 +835,10 @@ void down_stairs( bool remove_stairs, int old_level, int force_stair ) if (collect_travel_data) old_level_info.update(); + // Preserve abyss uniques now, since this Abyss level will be deleted. + if (you.level_type == LEVEL_ABYSS) + save_abyss_uniques(); + if (you.level_type == LEVEL_PANDEMONIUM && stair_find == DNGN_TRANSIT_PANDEMONIUM) { diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 243b8f03e4..9b61ec053c 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -32,10 +32,12 @@ #include "debug.h" #include "itemname.h" #include "itemprop.h" +#include "items.h" #include "Kills.h" #include "misc.h" #include "monplace.h" #include "mstuff2.h" +#include "mtransit.h" #include "player.h" #include "randart.h" #include "stuff.h" @@ -2781,8 +2783,6 @@ void monsters::expose_to_element(beam_type, int) void monsters::banish() { - // [dshaligram] FIXME: We should really put these monsters on a - // queue and load them when the player enters the Abyss. monster_die(this, KILL_RESET, 0); } @@ -3041,19 +3041,84 @@ void monsters::ghost_init() inv.init(NON_ITEM); enchantment.init(ENCH_NONE); + find_place_to_live(); +} + +bool monsters::find_home_in(coord_def s, coord_def e) +{ + for (int iy = s.y; iy <= e.y; ++iy) + { + for (int ix = s.x; ix <= e.x; ++ix) + { + if (!in_bounds(ix, iy)) + continue; + + if (ix == you.x_pos && iy == you.y_pos) + continue; + + if (mgrd[ix][iy] != NON_MONSTER || grd[ix][iy] < DNGN_FLOOR) + continue; + + x = ix; + y = iy; + return (true); + } + } + + return (false); +} + +bool monsters::find_place_near_player() +{ + return (find_home_in( you.pos() - coord_def(1, 1), + you.pos() + coord_def(1, 1) ) + || find_home_in( you.pos() - coord_def(6, 6), + you.pos() + coord_def(6, 6) )); +} + +bool monsters::find_home_anywhere() +{ + int tries = 600; do { - x = random2(GXM - 20) + 10; - y = random2(GYM - 20) + 10; + x = random_range(6, GXM - 7); + y = random_range(6, GYM - 7); } - while ((grd[x][y] != DNGN_FLOOR) - || (mgrd[x][y] != NON_MONSTER)); + while ((grd[x][y] != DNGN_FLOOR + || mgrd[x][y] != NON_MONSTER) + && tries-- > 0); - mgrd[x][y] = monster_index(this); + return (tries >= 0); +} + +bool monsters::find_place_to_live(bool near_player) +{ + if ((near_player && find_place_near_player()) + || find_home_anywhere()) + { + mgrd[x][y] = monster_index(this); + return (true); + } + + return (false); +} + +void monsters::destroy_inventory() +{ + for (int j = 0; j < NUM_MONSTER_SLOTS; j++) + { + if (inv[j] != NON_ITEM) + { + destroy_item( inv[j] ); + inv[j] = NON_ITEM; + } + } } void monsters::reset() { + destroy_inventory(); + enchantment.init(ENCH_NONE); inv.init(NON_ITEM); @@ -3076,6 +3141,19 @@ void monsters::reset() ghost.reset(NULL); } +bool monsters::needs_transit() const +{ + return ((mons_is_unique(type) + || (flags & MF_BANISHED) + || (you.level_type == LEVEL_DUNGEON && hit_dice > 8 + random2(25))) + && !mons_has_ench(this, ENCH_ABJ_I, ENCH_ABJ_VI)); +} + +void monsters::set_transit(level_id dest) +{ + add_monster_to_transit(dest, *this); +} + void monsters::load_spells(int book) { spells.init(MS_NO_SPELL); diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index bf34d15dc1..eb8c5915a4 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -338,6 +338,7 @@ void monster_die(monsters *monster, char killer, int i, bool silent) int monster_killed = monster_index(monster); bool death_message = !silent && mons_near(monster) && player_monster_visible(monster); + bool in_transit = false; // From time to time Trog gives you a little bonus if (killer == KILL_YOU && you.berserker) @@ -660,6 +661,13 @@ void monster_die(monsters *monster, char killer, int i, bool silent) place_cloud( CLOUD_GREY_SMOKE_MON + random2(3), monster->x, monster->y, 1 + random2(3) ); + if (monster->needs_transit()) + { + monster->flags |= MF_BANISHED; + monster->set_transit( level_id(LEVEL_ABYSS) ); + in_transit = true; + } + // fall-through case KILL_DISMISSED: @@ -697,7 +705,7 @@ void monster_die(monsters *monster, char killer, int i, bool silent) random2avg(88, 3), 100, "a mummy death curse" ); } } - else if (monster->type == MONS_BORIS) + else if (monster->type == MONS_BORIS && !in_transit) { // XXX: actual blood curse effect for Boris? -- bwr @@ -2091,6 +2099,7 @@ static bool handle_enchantment(struct monsters *monster) if (monster->enchantment[p] < ENCH_ABJ_I) { + monster->enchantment[p] = ENCH_ABJ_I; monster_die(monster, KILL_RESET, 0); died = true; } diff --git a/crawl-ref/source/mtransit.cc b/crawl-ref/source/mtransit.cc new file mode 100644 index 0000000000..bb58f68909 --- /dev/null +++ b/crawl-ref/source/mtransit.cc @@ -0,0 +1,159 @@ +/* + * File: mtransit.cc + * Summary: Tracks monsters that are in suspended animation between levels. + * Written by: Darshan Shaligram + * + * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-03-15T20:10:20.648083Z $ + */ + +#include "AppHdr.h" + +#include "mtransit.h" +#include "items.h" +#include "mon-util.h" +#include "stuff.h" + +#define MAX_LOST 100 + +monsters_in_transit the_lost_ones; + +static void place_lost_monsters(m_transit_list &m); + +static void cull_lost(m_transit_list &mlist, int how_many) +{ + // First pass, drop non-uniques. + m_transit_list::iterator i = mlist.begin(); + + for ( ; i != mlist.end(); ) + { + m_transit_list::iterator finger = i++; + if (!mons_is_unique(finger->mons.type)) + { + mlist.erase(finger); + + if (--how_many <= 0) + return; + } + } + + // If we're still over the limit (unlikely), just lose + // the old ones. + while (how_many-- > MAX_LOST && !mlist.empty()) + mlist.erase( mlist.begin() ); +} + +void add_monster_to_transit(level_id lid, const monsters &m) +{ + m_transit_list &mlist = the_lost_ones[lid]; + mlist.push_back(m); + +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Monster in transit: %s", + m.name(DESC_PLAIN).c_str()); +#endif + + const int how_many = mlist.size(); + if (how_many > MAX_LOST) + cull_lost(mlist, how_many); +} + +void place_transiting_monsters() +{ + level_id c = level_id::current(); + + monsters_in_transit::iterator i = the_lost_ones.find(c); + if (i == the_lost_ones.end()) + return; + + place_lost_monsters(i->second); + if (i->second.empty()) + the_lost_ones.erase(i); +} + +static bool place_lost_monster(follower &f) +{ + return (f.place(false)); +} + +static void place_lost_monsters(m_transit_list &m) +{ + for (m_transit_list::iterator i = m.begin(); + i != m.end(); ) + { + m_transit_list::iterator mon = i++; + + // Transiting monsters have a 50% chance of being placed. + if (coinflip()) + continue; + + if (place_lost_monster(*mon)) + m.erase(mon); + } +} + +////////////////////////////////////////////////////////////////////////// +// follower + +follower::follower(const monsters &m) : mons(m), items() +{ + load_mons_items(); +} + +void follower::load_mons_items() +{ + for (int i = 0; i < NUM_MONSTER_SLOTS; ++i) + if (mons.inv[i] != NON_ITEM) + items[i] = mitm[ mons.inv[i] ]; + else + items[i].clear(); +} + +bool follower::place(bool near_player) +{ + for (int i = 0; i < MAX_MONSTERS - 5; ++i) + { + monsters &m = menv[i]; + if (m.alive()) + continue; + + m = mons; + if (m.find_place_to_live(near_player)) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Placed follower: %s", + m.name(DESC_PLAIN).c_str()); +#endif + m.target_x = m.target_y = 0; + m.flags |= MF_JUST_SUMMONED; + + restore_mons_items(m); + return (true); + } + + m.reset(); + break; + } + + return (false); +} + +void follower::restore_mons_items(monsters &m) +{ + for (int i = 0; i < NUM_MONSTER_SLOTS; ++i) + { + if (items[i].base_type == OBJ_UNASSIGNED) + m.inv[i] = NON_ITEM; + else + { + const int islot = get_item_slot(0); + m.inv[i] = islot; + if (islot == NON_ITEM) + continue; + + item_def &it = mitm[islot]; + it = items[i]; + it.x = it.y = 0; + it.link = NON_ITEM; + } + } +} diff --git a/crawl-ref/source/mtransit.h b/crawl-ref/source/mtransit.h new file mode 100644 index 0000000000..3ffc0adfc8 --- /dev/null +++ b/crawl-ref/source/mtransit.h @@ -0,0 +1,39 @@ +/* + * File: mtransit.h + * Summary: Tracking monsters in transit between levels. + * Written by: Darshan Shaligram + * + * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-03-15T20:10:20.648083Z $ + */ + +#ifndef MTRANSIT_H +#define MTRANSIT_H + +#include "AppHdr.h" +#include "travel.h" +#include <map> +#include <list> + +struct follower +{ + monsters mons; + FixedVector<item_def, NUM_MONSTER_SLOTS> items; + + follower() : mons(), items() { } + follower(const monsters &m); + bool place(bool near_player = false); + void load_mons_items(); + void restore_mons_items(monsters &m); +}; + +typedef std::list<follower> m_transit_list; +typedef std::map<level_id, m_transit_list> monsters_in_transit; + +extern monsters_in_transit the_lost_ones; + +void add_monster_to_transit(level_id dest, const monsters &m); + +// Places (some of the) monsters eligible to be placed on this level. +void place_transiting_monsters(); + +#endif diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc index 127f932915..ae7546c451 100644 --- a/crawl-ref/source/spells1.cc +++ b/crawl-ref/source/spells1.cc @@ -667,7 +667,10 @@ void abjuration(int pow) abjLevel -= 1 + (random2(pow) / 8); if (abjLevel < ENCH_ABJ_I) + { + mons_add_ench(monster, ENCH_ABJ_I); monster_die(monster, KILL_RESET, 0); + } else { simple_monster_message(monster, " shudders."); diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc index 17b6b4518a..341bc90502 100644 --- a/crawl-ref/source/spells4.cc +++ b/crawl-ref/source/spells4.cc @@ -1417,7 +1417,7 @@ static int distortion_monsters(int x, int y, int pow, int message) } else if (one_chance_in(3)) { - monster_die(defender, KILL_RESET, 0); + defender->banish(); return 1; } else if (message) diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index ec0873abde..0eade5c58e 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -249,7 +249,7 @@ static int apply_vehumet_wizardry_boost(int spell, int chance) { int wizardry = player_mag_abil(false); int fail_reduce = 100; - int wiz_factor = 86; + int wiz_factor = 87; if (you.religion == GOD_VEHUMET && you.duration[DUR_PRAYER] @@ -258,8 +258,8 @@ static int apply_vehumet_wizardry_boost(int spell, int chance) || spell_typematch(spell, SPTYP_SUMMONING))) { // [dshaligram] Fail rate multiplier used to be .5, scaled - // back to 60%. - fail_reduce = fail_reduce * 60 / 100; + // back to 67%. + fail_reduce = fail_reduce * 67 / 100; } // [dshaligram] Apply wizardry factor here, rather than mixed into the @@ -267,12 +267,12 @@ static int apply_vehumet_wizardry_boost(int spell, int chance) while (wizardry-- > 0) { fail_reduce = fail_reduce * wiz_factor / 100; - wiz_factor += (100 - wiz_factor) / 5; + wiz_factor += (100 - wiz_factor) / 3; } // Hard cap on fail rate reduction. - if (fail_reduce < 40) - fail_reduce = 40; + if (fail_reduce < 50) + fail_reduce = 50; return (chance * fail_reduce / 100); } diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 63fe4fc70b..ebf7587c2c 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -76,6 +76,7 @@ #include "itemprop.h" #include "monstuff.h" #include "mon-util.h" +#include "mtransit.h" #include "randart.h" #include "skills.h" #include "skills2.h" @@ -99,9 +100,11 @@ FixedArray < bool, MAX_LEVELS, NUM_BRANCHES > tmp_file_pairs; static void tag_construct_you(struct tagHeader &th); static void tag_construct_you_items(struct tagHeader &th); static void tag_construct_you_dungeon(struct tagHeader &th); +static void tag_construct_lost_monsters(tagHeader &th); static void tag_read_you(struct tagHeader &th, char minorVersion); static void tag_read_you_items(struct tagHeader &th, char minorVersion); static void tag_read_you_dungeon(struct tagHeader &th); +static void tag_read_lost_monsters(tagHeader &th, int minorVersion); static void tag_construct_level(struct tagHeader &th); static void tag_construct_level_items(struct tagHeader &th); @@ -118,6 +121,10 @@ static void tag_read_ghost(struct tagHeader &th, char minorVersion); static void marshallGhost(tagHeader &th, const ghost_demon &ghost); static ghost_demon unmarshallGhost( tagHeader &th ); +static void marshall_monster(tagHeader &th, const monsters &m); +static void unmarshall_monster(tagHeader &th, monsters &m); +static void marshall_item(tagHeader &th, const item_def &item); +static void unmarshall_item(tagHeader &th, item_def &item); // provide a wrapper for file writing, just in case. int write2(FILE * file, const char *buffer, unsigned int count) @@ -219,10 +226,11 @@ void marshallMap(struct tagHeader &th, const std::map<key,value>& data, } } -void marshall_level_id( struct tagHeader& th, const level_id& id ) +void marshall_level_id( tagHeader& th, const level_id& id ) { marshallByte(th, id.branch ); marshallLong(th, id.depth ); + marshallByte(th, id.level_type); } void marshall_level_pos( struct tagHeader& th, const level_pos& lpos ) @@ -234,17 +242,15 @@ void marshall_level_pos( struct tagHeader& th, const level_pos& lpos ) template<typename key, typename value> void unmarshallMap(struct tagHeader& th, std::map<key,value>& data, - key (*key_unmarshall) (struct tagHeader&), - value (*value_unmarshall)(struct tagHeader&) ) + key (*key_unmarshall) (tagHeader&), + value (*value_unmarshall)(tagHeader&) ) { long i, len = unmarshallLong(th); key k; - value v; for ( i = 0; i < len; ++i ) { k = key_unmarshall(th); - v = value_unmarshall(th); - data[k] = v; + data[k] = value_unmarshall(th); } } @@ -254,12 +260,13 @@ T unmarshall_long_as( struct tagHeader& th ) return static_cast<T>(unmarshallLong(th)); } -level_id unmarshall_level_id( struct tagHeader& th ) +level_id unmarshall_level_id( tagHeader& th ) { level_id id; id.branch = unmarshallByte(th); id.depth = unmarshallLong(th); - return id; + id.level_type = unmarshallByte(th); + return (id); } level_pos unmarshall_level_pos( struct tagHeader& th ) @@ -267,7 +274,7 @@ level_pos unmarshall_level_pos( struct tagHeader& th ) level_pos lpos; lpos.pos.x = unmarshallLong(th); lpos.pos.y = unmarshallLong(th); - lpos.id = unmarshall_level_id(th); + lpos.id = unmarshall_level_id(th); return lpos; } @@ -459,6 +466,9 @@ void tag_construct(struct tagHeader &th, int tagID) case TAG_GHOST: tag_construct_ghost(th); break; + case TAG_LOST_MONSTERS: + tag_construct_lost_monsters(th); + break; default: // I don't know how to make that! break; @@ -557,6 +567,9 @@ int tag_read(FILE *fp, char minorVersion) case TAG_GHOST: tag_read_ghost(th, minorVersion); break; + case TAG_LOST_MONSTERS: + tag_read_lost_monsters(th, minorVersion); + break; default: // I don't know how to read that! return 0; @@ -602,8 +615,11 @@ void tag_set_expected(char tags[], int fileType) switch(fileType) { case TAGTYPE_PLAYER: - if (i >= TAG_YOU && i <=TAG_YOU_DUNGEON) + if ((i >= TAG_YOU && i <=TAG_YOU_DUNGEON) + || i == TAG_LOST_MONSTERS) + { tags[i] = 1; + } break; case TAGTYPE_PLAYER_NAME: if (i == TAG_YOU) @@ -910,6 +926,53 @@ static void tag_construct_you_dungeon(struct tagHeader &th) marshall_level_pos, marshall_as_long<portal_type>); } +static void marshall_follower(tagHeader &th, const follower &f) +{ + marshall_monster(th, f.mons); + for (int i = 0; i < NUM_MONSTER_SLOTS; ++i) + marshall_item(th, f.items[i]); +} + +static void unmarshall_follower(tagHeader &th, follower &f) +{ + unmarshall_monster(th, f.mons); + for (int i = 0; i < NUM_MONSTER_SLOTS; ++i) + unmarshall_item(th, f.items[i]); +} + +static void marshall_follower_list(tagHeader &th, const m_transit_list &mlist) +{ + marshallShort( th, mlist.size() ); + + for (m_transit_list::const_iterator mi = mlist.begin(); + mi != mlist.end(); ++mi) + { + marshall_follower( th, *mi ); + } +} + +static m_transit_list unmarshall_follower_list(tagHeader &th) +{ + m_transit_list mlist; + + const int size = unmarshallShort(th); + + for (int i = 0; i < size; ++i) + { + follower f; + unmarshall_follower(th, f); + mlist.push_back(f); + } + + return (mlist); +} + +static void tag_construct_lost_monsters(tagHeader &th) +{ + marshallMap( th, the_lost_ones, marshall_level_id, + marshall_follower_list ); +} + static void tag_read_you(struct tagHeader &th, char minorVersion) { char buff[20]; // For birth date @@ -1200,7 +1263,8 @@ static void tag_read_you_dungeon(struct tagHeader &th) } unmarshallMap(th, stair_level, - unmarshall_long_as<branch_type>, unmarshall_level_id); + unmarshall_long_as<branch_type>, + unmarshall_level_id); unmarshallMap(th, shops_present, unmarshall_level_pos, unmarshall_long_as<shop_type>); unmarshallMap(th, altars_present, @@ -1209,6 +1273,14 @@ static void tag_read_you_dungeon(struct tagHeader &th) unmarshall_level_pos, unmarshall_long_as<portal_type>); } +static void tag_read_lost_monsters(tagHeader &th, int minorVersion) +{ + the_lost_ones.clear(); + + unmarshallMap(th, the_lost_ones, + unmarshall_level_id, unmarshall_follower_list); +} + // ------------------------------- level tags ---------------------------- // static void tag_construct_level(struct tagHeader &th) @@ -1262,6 +1334,62 @@ static void tag_construct_level(struct tagHeader &th) } } +static void marshall_item(tagHeader &th, const item_def &item) +{ + marshallByte(th, item.base_type); + marshallByte(th, item.sub_type); + marshallShort(th, item.plus); + marshallShort(th, item.plus2); + marshallLong(th, item.special); + marshallShort(th, item.quantity); + + marshallByte(th, item.colour); + marshallShort(th, item.x); + marshallShort(th, item.y); + marshallLong(th, item.flags); + + marshallShort(th, item.link); // unused + marshallShort(th, igrd[item.x][item.y]); // unused + + marshallByte(th, item.slot); + + marshallShort(th, item.orig_place); + marshallShort(th, item.orig_monnum); + marshallString(th, item.inscription.c_str(), 80); +} + +static void unmarshall_item(tagHeader &th, item_def &item) +{ + item.base_type = (unsigned char) unmarshallByte(th); + item.sub_type = (unsigned char) unmarshallByte(th); + item.plus = unmarshallShort(th); + item.plus2 = unmarshallShort(th); + item.special = unmarshallLong(th); + item.quantity = unmarshallShort(th); + item.colour = (unsigned char) unmarshallByte(th); + item.x = unmarshallShort(th); + item.y = unmarshallShort(th); + item.flags = (unsigned long) unmarshallLong(th); + + // [dshaligram] FIXME, remove this kludge when ARM_CAP is fully + // integrated. + if (item.base_type == OBJ_ARMOUR && item.sub_type == ARM_CAP) + item.sub_type = ARM_HELMET; + + unmarshallShort(th); // mitm[].link -- unused + unmarshallShort(th); // igrd[item.x][item.y] -- unused + + item.slot = unmarshallByte(th); + item.inscription.clear(); + + item.orig_place = unmarshallShort(th); + item.orig_monnum = unmarshallShort(th); + + char insstring[80]; + unmarshallString(th, insstring, 80); + item.inscription = std::string(insstring); +} + static void tag_construct_level_items(struct tagHeader &th) { int i; @@ -1278,37 +1406,53 @@ static void tag_construct_level_items(struct tagHeader &th) // how many items? marshallShort(th, MAX_ITEMS); for (i = 0; i < MAX_ITEMS; ++i) + marshall_item(th, mitm[i]); +} + +static void marshall_monster(tagHeader &th, const monsters &m) +{ + marshallByte(th, m.ac); + marshallByte(th, m.ev); + marshallByte(th, m.hit_dice); + marshallByte(th, m.speed); + marshallByte(th, m.speed_increment); + marshallByte(th, m.behaviour); + marshallByte(th, m.x); + marshallByte(th, m.y); + marshallByte(th, m.target_x); + marshallByte(th, m.target_y); + marshallLong(th, m.flags); + + for (int j = 0; j < NUM_MON_ENCHANTS; j++) + marshallByte(th, m.enchantment[j]); + + marshallShort(th, m.type); + marshallShort(th, m.hit_points); + marshallShort(th, m.max_hit_points); + marshallShort(th, m.number); + marshallShort(th, m.colour); + + for (int j = 0; j < NUM_MONSTER_SLOTS; j++) + marshallShort(th, m.inv[j]); + + for (int j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j) + marshallShort(th, m.spells[j]); + + marshallByte(th, m.god); + + if (m.type == MONS_PLAYER_GHOST || m.type == MONS_PANDEMONIUM_DEMON) { - marshallByte(th, mitm[i].base_type); - marshallByte(th, mitm[i].sub_type); - marshallShort(th, mitm[i].plus); - marshallShort(th, mitm[i].plus2); - marshallLong(th, mitm[i].special); - marshallShort(th, mitm[i].quantity); - - marshallByte(th, mitm[i].colour); - marshallShort(th, mitm[i].x); - marshallShort(th, mitm[i].y); - marshallLong(th, mitm[i].flags); - - marshallShort(th, mitm[i].link); // unused - marshallShort(th, igrd[mitm[i].x][mitm[i].y]); // unused - - marshallByte(th, mitm[i].slot); - - marshallShort(th, mitm[i].orig_place); - marshallShort(th, mitm[i].orig_monnum); - marshallString(th, mitm[i].inscription.c_str(), 80); + // *Must* have ghost field set. + ASSERT(m.ghost.get()); + marshallGhost(th, *m.ghost); } } static void tag_construct_level_monsters(struct tagHeader &th) { - int i,j; - // how many mons_alloc? marshallByte(th, 20); - for (i = 0; i < 20; ++i) + for (int i = 0; i < 20; ++i) marshallShort(th, env.mons_alloc[i]); // how many monsters? @@ -1318,46 +1462,8 @@ static void tag_construct_level_monsters(struct tagHeader &th) // how many monster inventory slots? marshallByte(th, NUM_MONSTER_SLOTS); - for (i = 0; i < MAX_MONSTERS; i++) - { - const monsters &m = menv[i]; - - marshallByte(th, m.ac); - marshallByte(th, m.ev); - marshallByte(th, m.hit_dice); - marshallByte(th, m.speed); - marshallByte(th, m.speed_increment); - marshallByte(th, m.behaviour); - marshallByte(th, m.x); - marshallByte(th, m.y); - marshallByte(th, m.target_x); - marshallByte(th, m.target_y); - marshallLong(th, m.flags); - - for (j = 0; j < NUM_MON_ENCHANTS; j++) - marshallByte(th, m.enchantment[j]); - - marshallShort(th, m.type); - marshallShort(th, m.hit_points); - marshallShort(th, m.max_hit_points); - marshallShort(th, m.number); - marshallShort(th, m.colour); - - for (j = 0; j < NUM_MONSTER_SLOTS; j++) - marshallShort(th, m.inv[j]); - - for (j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j) - marshallShort(th, m.spells[j]); - - marshallByte(th, m.god); - - if (m.type == MONS_PLAYER_GHOST || m.type == MONS_PANDEMONIUM_DEMON) - { - // *Must* have ghost field set. - ASSERT(m.ghost.get()); - marshallGhost(th, *m.ghost); - } - } + for (int i = 0; i < MAX_MONSTERS; i++) + marshall_monster(th, menv[i]); } void tag_construct_level_attitude(struct tagHeader &th) @@ -1450,41 +1556,49 @@ static void tag_read_level_items(struct tagHeader &th, char minorVersion) // how many items? count = unmarshallShort(th); for (i = 0; i < count; ++i) - { - mitm[i].base_type = (unsigned char) unmarshallByte(th); - mitm[i].sub_type = (unsigned char) unmarshallByte(th); - mitm[i].plus = unmarshallShort(th); - mitm[i].plus2 = unmarshallShort(th); - mitm[i].special = unmarshallLong(th); - mitm[i].quantity = unmarshallShort(th); - mitm[i].colour = (unsigned char) unmarshallByte(th); - mitm[i].x = unmarshallShort(th); - mitm[i].y = unmarshallShort(th); - mitm[i].flags = (unsigned long) unmarshallLong(th); - - // [dshaligram] FIXME, remove this kludge when ARM_CAP is fully - // integrated. - if (mitm[i].base_type == OBJ_ARMOUR && mitm[i].sub_type == ARM_CAP) - mitm[i].sub_type = ARM_HELMET; - - unmarshallShort(th); // mitm[].link -- unused - unmarshallShort(th); // igrd[mitm[i].x][mitm[i].y] -- unused - - mitm[i].slot = unmarshallByte(th); - mitm[i].inscription.clear(); + unmarshall_item(th, mitm[i]); +} - mitm[i].orig_place = unmarshallShort(th); - mitm[i].orig_monnum = unmarshallShort(th); - - char insstring[80]; - unmarshallString(th, insstring, 80); - mitm[i].inscription = std::string(insstring); - } +static void unmarshall_monster(tagHeader &th, monsters &m) +{ + m.ac = unmarshallByte(th); + m.ev = unmarshallByte(th); + m.hit_dice = unmarshallByte(th); + m.speed = unmarshallByte(th); + // Avoid sign extension when loading files (Elethiomel's hang) + m.speed_increment = (unsigned char) unmarshallByte(th); + m.behaviour = unmarshallByte(th); + m.x = unmarshallByte(th); + m.y = unmarshallByte(th); + m.target_x = unmarshallByte(th); + m.target_y = unmarshallByte(th); + m.flags = unmarshallLong(th); + + for (int j = 0; j < NUM_MON_ENCHANTS; j++) + m.enchantment[j] = unmarshallByte(th); + + m.type = unmarshallShort(th); + m.hit_points = unmarshallShort(th); + m.max_hit_points = unmarshallShort(th); + m.number = unmarshallShort(th); + + m.colour = unmarshallShort(th); + + for (int j = 0; j < NUM_MONSTER_SLOTS; j++) + m.inv[j] = unmarshallShort(th); + + for (int j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j) + m.spells[j] = unmarshallShort(th); + + m.god = (god_type) unmarshallByte(th); + + if (m.type == MONS_PLAYER_GHOST || m.type == MONS_PANDEMONIUM_DEMON) + m.set_ghost( unmarshallGhost(th) ); } static void tag_read_level_monsters(struct tagHeader &th, char minorVersion) { - int i,j; + int i; int count, ecount, icount; // how many mons_alloc? @@ -1502,41 +1616,7 @@ static void tag_read_level_monsters(struct tagHeader &th, char minorVersion) for (i = 0; i < count; i++) { monsters &m = menv[i]; - - m.ac = unmarshallByte(th); - m.ev = unmarshallByte(th); - m.hit_dice = unmarshallByte(th); - m.speed = unmarshallByte(th); - // Avoid sign extension when loading files (Elethiomel's hang) - m.speed_increment = (unsigned char) unmarshallByte(th); - m.behaviour = unmarshallByte(th); - m.x = unmarshallByte(th); - m.y = unmarshallByte(th); - m.target_x = unmarshallByte(th); - m.target_y = unmarshallByte(th); - m.flags = unmarshallLong(th); - - for (j = 0; j < ecount; j++) - m.enchantment[j] = unmarshallByte(th); - - m.type = unmarshallShort(th); - m.hit_points = unmarshallShort(th); - m.max_hit_points = unmarshallShort(th); - m.number = unmarshallShort(th); - - m.colour = unmarshallShort(th); - - for (j = 0; j < icount; j++) - m.inv[j] = unmarshallShort(th); - - for (j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j) - m.spells[j] = unmarshallShort(th); - - m.god = (god_type) unmarshallByte(th); - - if (m.type == MONS_PLAYER_GHOST || m.type == MONS_PANDEMONIUM_DEMON) - m.set_ghost( unmarshallGhost(th) ); - + unmarshall_monster(th, m); // place monster if (m.type != -1) mgrd[m.x][m.y] = i; diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h index c8bca8e0c6..1490f9df56 100644 --- a/crawl-ref/source/travel.h +++ b/crawl-ref/source/travel.h @@ -169,14 +169,15 @@ public: bool operator == ( const level_id &id ) const { - return branch == id.branch && depth == id.depth - && level_type == id.level_type; + return (level_type == LEVEL_DUNGEON? + branch == id.branch && depth == id.depth + && level_type == id.level_type + : level_type == id.level_type); } bool operator != ( const level_id &id ) const { - return branch != id.branch || depth != id.depth - || level_type != id.level_type; + return !operator == (id); } bool operator <( const level_id &id ) const |