summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/Kills.cc1
-rw-r--r--crawl-ref/source/acr.cc6
-rw-r--r--crawl-ref/source/beam.cc75
-rw-r--r--crawl-ref/source/dat/altar.des52
-rw-r--r--crawl-ref/source/debug.cc16
-rw-r--r--crawl-ref/source/decks.cc2
-rw-r--r--crawl-ref/source/describe.cc38
-rw-r--r--crawl-ref/source/direct.cc2
-rw-r--r--crawl-ref/source/dungeon.cc6
-rw-r--r--crawl-ref/source/effects.cc32
-rw-r--r--crawl-ref/source/enum.h33
-rw-r--r--crawl-ref/source/externs.h44
-rw-r--r--crawl-ref/source/fight.cc82
-rw-r--r--crawl-ref/source/fight.h4
-rw-r--r--crawl-ref/source/files.cc73
-rw-r--r--crawl-ref/source/ghost.cc216
-rw-r--r--crawl-ref/source/ghost.h52
-rw-r--r--crawl-ref/source/itemname.cc16
-rw-r--r--crawl-ref/source/itemprop.h5
-rw-r--r--crawl-ref/source/libunix.cc7
-rw-r--r--crawl-ref/source/message.cc5
-rw-r--r--crawl-ref/source/misc.cc2
-rw-r--r--crawl-ref/source/mon-data.h4
-rw-r--r--crawl-ref/source/mon-util.cc270
-rw-r--r--crawl-ref/source/mon-util.h71
-rw-r--r--crawl-ref/source/monplace.cc41
-rw-r--r--crawl-ref/source/monplace.h2
-rw-r--r--crawl-ref/source/monspeak.cc3
-rw-r--r--crawl-ref/source/monstuff.cc132
-rw-r--r--crawl-ref/source/ouch.cc25
-rw-r--r--crawl-ref/source/player.cc21
-rw-r--r--crawl-ref/source/tags.cc124
-rw-r--r--crawl-ref/source/view.cc3
33 files changed, 849 insertions, 616 deletions
diff --git a/crawl-ref/source/Kills.cc b/crawl-ref/source/Kills.cc
index 02c3decb20..380f4c33fd 100644
--- a/crawl-ref/source/Kills.cc
+++ b/crawl-ref/source/Kills.cc
@@ -14,6 +14,7 @@
#include "mon-util.h"
#include "monstuff.h"
#include "files.h"
+#include "ghost.h"
#include "itemname.h"
#include "place.h"
#include "travel.h"
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 89e6d0aad1..a5c7e4ed7b 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -974,7 +974,7 @@ static void handle_wizard_command( void )
if (testbits(env.level_flags, LFLAG_NOT_MAPPABLE)
|| testbits(get_branch_flags(), BFLAG_NOT_MAPPABLE))
{
- if (!yesno("Force level to be mappable? "))
+ if (!yesno("Force level to be mappable? ", true, 'n'))
{
canned_msg( MSG_OK );
return;
@@ -1069,7 +1069,7 @@ static bool recharge_rod( item_def &rod, bool wielded )
const int charge = rod.plus / ROD_CHARGE_MULT;
int rate = ((charge + 1) * ROD_CHARGE_MULT) / 10;
-
+
rate *= (10 + skill_bump( SK_EVOCATIONS ));
rate = div_rand_round( rate, 100 );
@@ -1240,7 +1240,7 @@ static bool cmd_is_repeatable(command_type cmd, bool is_again = false)
case CMD_MOVE_DOWN_RIGHT:
if (!i_feel_safe())
return yesno("Really repeat movement command while monsters "
- "are nearby?");
+ "are nearby?", false, 'n');
return true;
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 15d3f68a85..29719a3886 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -39,6 +39,7 @@
#include "delay.h"
#include "effects.h"
#include "enum.h"
+#include "fight.h"
#include "item_use.h"
#include "it_use2.h"
#include "items.h"
@@ -1591,28 +1592,28 @@ int mons_adjust_flavoured( monsters *monster, bolt &pbolt,
// if we're not doing flavored effects, must be preliminary
// damage check only; do not print messages or apply any side
// effects!
- int resist;
+ int resist = 0;
+ int original = hurted;
switch (pbolt.flavour)
{
case BEAM_FIRE:
case BEAM_STEAM:
- resist = mons_res_fire(monster);
- if (resist > 1)
+ hurted = resist_adjust_damage(monster,
+ monster->res_fire(),
+ hurted,
+ true);
+ if (!hurted)
{
if (doFlavouredEffects)
simple_monster_message(monster, " appears unharmed.");
-
- hurted = 0;
}
- else if (resist == 1)
+ else if (original > hurted)
{
if (doFlavouredEffects)
simple_monster_message(monster, " resists.");
-
- hurted /= 3;
}
- else if (resist < 0)
+ else if (original < hurted)
{
if (mons_is_icy(monster))
{
@@ -1624,75 +1625,70 @@ int mons_adjust_flavoured( monsters *monster, bolt &pbolt,
if (doFlavouredEffects)
simple_monster_message(monster, " is burned terribly!");
}
-
- hurted *= 15;
- hurted /= 10;
}
break;
-
case BEAM_COLD:
- resist = mons_res_cold(monster);
- if (resist > 1)
+ hurted = resist_adjust_damage(monster, monster->res_cold(),
+ hurted, true);
+ if (!hurted)
{
if (doFlavouredEffects)
simple_monster_message(monster, " appears unharmed.");
-
- hurted = 0;
}
- else if (resist == 1)
+ else if (original > hurted)
{
if (doFlavouredEffects)
simple_monster_message(monster, " resists.");
-
- hurted /= 3;
}
- else if (resist < 0)
+ else if (original < hurted)
{
if (doFlavouredEffects)
simple_monster_message(monster, " is frozen!");
-
- hurted *= 15;
- hurted /= 10;
}
break;
case BEAM_ELECTRICITY:
- if (mons_res_elec(monster) > 0)
+ hurted = resist_adjust_damage(monster, monster->res_elec(),
+ hurted, true);
+ if (!hurted)
{
if (doFlavouredEffects)
simple_monster_message(monster, " appears unharmed.");
-
- hurted = 0;
}
break;
case BEAM_ACID:
- if (mons_res_acid(monster))
+ hurted = resist_adjust_damage(monster, mons_res_acid(monster),
+ hurted, true);
+ if (!hurted)
{
if (doFlavouredEffects)
simple_monster_message(monster, " appears unharmed.");
-
- hurted = 0;
}
break;
case BEAM_POISON:
- if (mons_res_poison(monster) > 0)
+ {
+ int res = mons_res_poison(monster);
+ hurted = resist_adjust_damage(monster, res, hurted, true);
+ if (!hurted)
{
if (doFlavouredEffects)
simple_monster_message( monster, " appears unharmed." );
-
- hurted = 0;
}
- else if (doFlavouredEffects && !one_chance_in(3))
+ else if (res <= 0 && doFlavouredEffects && !one_chance_in(3))
{
poison_monster( monster, whose_kill(pbolt) );
}
break;
+ }
case BEAM_POISON_ARROW:
- if (mons_res_poison(monster) > 0)
+ hurted = resist_adjust_damage(monster,
+ std::min(mons_res_poison(monster), 1),
+ hurted);
+ if (hurted < original)
{
if (doFlavouredEffects)
{
@@ -1703,8 +1699,6 @@ int mons_adjust_flavoured( monsters *monster, bolt &pbolt,
if (mons_has_lifeforce(monster))
poison_monster( monster, whose_kill(pbolt), 2, true );
}
-
- hurted /= 2;
}
else if (doFlavouredEffects)
{
@@ -1730,7 +1724,8 @@ int mons_adjust_flavoured( monsters *monster, bolt &pbolt,
pbolt.obvious_effect = true;
if (YOU_KILL(pbolt.thrower))
- did_god_conduct(DID_NECROMANCY, 2 + random2(3), pbolt.effect_known);
+ did_god_conduct(DID_NECROMANCY, 2 + random2(3),
+ pbolt.effect_known);
if (one_chance_in(5))
{
@@ -2237,12 +2232,12 @@ void sticky_flame_monster( int mn, kill_category who, int levels )
if (!monster->alive())
return;
- if (mons_res_fire(monster) > 0)
+ if (mons_res_sticky_flame(monster))
return;
if (monster->add_ench(mon_enchant(ENCH_STICKY_FLAME, levels, who)))
simple_monster_message(monster, " is covered in liquid fire!");
-} // end sticky_flame_monster
+}
/*
* Used by monsters in "planning" which spell to cast. Fires off a "tracer"
diff --git a/crawl-ref/source/dat/altar.des b/crawl-ref/source/dat/altar.des
index 2fb39ee218..440960e7b6 100644
--- a/crawl-ref/source/dat/altar.des
+++ b/crawl-ref/source/dat/altar.des
@@ -20,7 +20,6 @@ TAGS: allow_dup
CHANCE: 20
MAP
cccccccccc
-cccccccccc
cBcBcBcBcc
G.c.c.c.Bc
@.......Bc
@@ -28,7 +27,6 @@ G.c.c.c.Bc
G.c.c.c.Bc
cBcBcBcBcc
cccccccccc
-cccccccccc
ENDMAP
NAME: jmf_multi_god_temple
@@ -124,15 +122,15 @@ TAGS: no_monster_gen
TAGS: no_monster_gen no_pool_fixup
: end
MAP
- .........
- ...wwwww...
-..wwwwwwwww..
-.wwwwwwwwwww..
-wwwwwwwwwwwww.
-wwwwwwCwwwwww.
-wwwwwwwwwwwww.
-.wwwwwwwwwww..
-..wwwwwwwww..
+ .........
+ ...wwwww...
+ ..wwwwwwwww..
+..wwwwwwwwwww..
+.wwwwwwwwwwwww.
+.wwwwwwCwwwwww.
+.wwwwwwwwwwwww.
+..wwwwwwwwwww..
+ .wwwwwwwww..
...wwwww...
........
ENDMAP
@@ -228,14 +226,19 @@ MAP
ENDMAP
NAME: lemuel_statue_altar
-DEPTH: 2-18, !Lair, !Hive, !Slime
+
+# Increased depth from 2-18 because getting a hostile statue can
+# instakill a low-level character.
+
+DEPTH: 10-18, !Lair, !Hive, !Slime
+
MAP
.....
.cFc.
.c.c.
.c.c.
.c.c.
-.c.c.
+.c>c.
.cCc.
.ccc.
.....
@@ -249,7 +252,7 @@ MAP
xxxxxxxxxxxxxxxxxxxx
...................x
c...c...c...c...c..x
-..................Cx
+@.................Cx
c...c...c...c...c..x
...................x
xxxxxxxxxxxxxxxxxxxx
@@ -281,20 +284,25 @@ ENDMAP
######################################
NAME: lemuel_angel_altar
-DEPTH: 2-18, !Lair, !Orc, !Hive, !Slime
+
+# Moved deeper since being teleported next to the Angel will be a
+# quick death at shallow levels.
+
+DEPTH: 9-18, !Lair, !Orc, !Hive, !Slime
MONS: angel
KFEAT: C = altar_elyvilon / altar_zin / altar_shining_one
MAP
.....
..xmx..
- ..xx.xx..
+ ..xx>xx..
..xxx.xxx..
.xxxx1xxxx.
-.m...C...m.
+.m>..C..>m.
.xxxx.xxxx.
..xxx.xxx..
- ..xx.xx..
- ..xmx..
+ ..xx>xx..
+ ..xmx..
+ .....
ENDMAP
NAME: lemuel_hellish_altar
@@ -340,13 +348,13 @@ ENDMAP
NAME: lemuel_blue_sif_altar
DEPTH: 2-18, !Lair, !Hive, !Slime, !Orc
-TAGS: no_monster_gen
+TAGS: no_monster_gen mini_float
COLOUR: . = blue
KFEAT: C = altar_sif_muna
MAP
xxxxxxxxxxxxxx
...........xxx
-...........+Cx
+@..........+Cx
...........xxx
xxxxxxxxxxxxxx
ENDMAP
@@ -361,7 +369,7 @@ MAP
xxxxxxxxxxxxxxxx
xxxx11111111xxxx
xxxxwwwwwwwwxxxx
-..............Cx
+@.............Cx
xxxxwwwwwwwwxxxx
xxxx11111111xxxx
xxxxxxxxxxxxxxxx
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index df323e2c23..a0eac1d559 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -48,6 +48,7 @@
#include "fight.h"
#include "files.h"
#include "food.h"
+#include "ghost.h"
#ifdef DEBUG_DIAGNOSTICS
#include "initfile.h"
@@ -469,7 +470,6 @@ void create_spec_monster_name(int x, int y)
ghost_demon ghost;
ghost.name = "John Doe";
- ghost.values.init(0);
char class_str[80];
mpr( "Make player ghost which class? ", MSGCH_PROMPT );
@@ -485,7 +485,7 @@ void create_spec_monster_name(int x, int y)
mpr("No such class, making it a Fighter.");
class_id = JOB_FIGHTER;
}
- ghost.values[GVAL_CLASS] = class_id;
+ ghost.job = static_cast<job_type>(class_id);
mon.set_ghost(ghost);
@@ -1412,7 +1412,7 @@ void stethoscope(int mwh)
// print behaviour information
- const habitat_type hab = mons_habitat( menv[i].type );
+ const habitat_type hab = mons_habitat( &menv[i] );
mprf(MSGCH_DIAGNOSTICS,
"hab=%s beh=%s(%d) foe=%s(%d) mem=%d target=(%d,%d)",
@@ -1453,8 +1453,8 @@ void stethoscope(int mwh)
ASSERT(menv[i].ghost.get());
const ghost_demon &ghost = *menv[i].ghost;
mprf( MSGCH_DIAGNOSTICS,
- "Ghost damage: %d; brand: %d",
- ghost.values[ GVAL_DAMAGE ], ghost.values[ GVAL_BRAND ] );
+ "Ghost damage: %d; brand: %d",
+ ghost.damage, ghost.brand );
}
} // end stethoscope()
#endif
@@ -2295,14 +2295,14 @@ bool debug_add_mutation(void)
else
msg = "You are resistant to mutations, remove resistance?";
- if (yesno(msg))
+ if (yesno(msg, true, 'n'))
{
you.mutation[MUT_MUTATION_RESISTANCE] = 0;
crawl_state.cancel_cmd_repeat();
}
}
- bool force = yesno("Force mutation to happen?");
+ bool force = yesno("Force mutation to happen?", true, 'n');
if (you.mutation[MUT_MUTATION_RESISTANCE] == 3 && !force)
{
@@ -3262,7 +3262,7 @@ static void debug_load_map_by_name(std::string name)
std::string prompt = "Only match is '";
prompt += matches[0];
prompt += "', use that?";
- if (!yesno(prompt.c_str()))
+ if (!yesno(prompt.c_str(), true, 'y'))
return;
map = find_map_by_name(matches[0]);
diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc
index a37728d045..6ed7a2f148 100644
--- a/crawl-ref/source/decks.cc
+++ b/crawl-ref/source/decks.cc
@@ -683,7 +683,7 @@ static bool check_buggy_deck(item_def& deck)
you.wield_change = true;
if (!yesno("Problems might not have been completely fixed; "
- "still use deck?"))
+ "still use deck?", true, 'n'))
{
crawl_state.zero_turns_taken();
return true;
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 72382883b4..b53d77ac3b 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -40,6 +40,7 @@
#include "decks.h"
#include "fight.h"
#include "food.h"
+#include "ghost.h"
#include "it_use2.h"
#include "itemname.h"
#include "itemprop.h"
@@ -589,17 +590,17 @@ static std::string describe_demon(const monsters &mons)
description << "A powerful demon, " << ghost.name << " has a"
<< RANDOM_ELEMENT(body_descs) << "body";
- switch (ghost.values[GVAL_DEMONLORD_FLY])
+ switch (ghost.fly)
{
- case 1:
+ case FL_FLY:
description << RANDOM_ELEMENT(wing_names);
break;
- case 2: // levitation
+ case FL_LEVITATE:
description << RANDOM_ELEMENT(lev_names);
break;
- default: // does not fly
+ case FL_NONE: // does not fly
if ( !one_chance_in(4) )
description << RANDOM_ELEMENT(nonfly_names);
break;
@@ -2171,8 +2172,7 @@ std::string ghost_description(const monsters &mons, bool concise)
const ghost_demon &ghost = *(mons.ghost);
- const species_type gspecies =
- static_cast<species_type>(ghost.values[GVAL_SPECIES]);
+ const species_type gspecies = ghost.species;
// We're fudging stats so that unarmed combat gets based off
// of the ghost's species, not the player's stats... exact
@@ -2207,28 +2207,28 @@ std::string ghost_description(const monsters &mons, bool concise)
}
gstr << ghost.name << " the "
- << skill_title( ghost.values[GVAL_BEST_SKILL],
- ghost.values[GVAL_SKILL_LEVEL],
+ << skill_title( ghost.best_skill,
+ ghost.best_skill_level,
gspecies,
str, dex, GOD_NO_GOD )
<< ", a"
- << ((ghost.values[GVAL_EXP_LEVEL] < 4) ? " weakling" :
- (ghost.values[GVAL_EXP_LEVEL] < 7) ? "n average" :
- (ghost.values[GVAL_EXP_LEVEL] < 11) ? "n experienced" :
- (ghost.values[GVAL_EXP_LEVEL] < 16) ? " powerful" :
- (ghost.values[GVAL_EXP_LEVEL] < 22) ? " mighty" :
- (ghost.values[GVAL_EXP_LEVEL] < 26) ? " great" :
- (ghost.values[GVAL_EXP_LEVEL] < 27) ? "n awesomely powerful"
- : " legendary")
+ << ((ghost.xl < 4) ? " weakling" :
+ (ghost.xl < 7) ? "n average" :
+ (ghost.xl < 11) ? "n experienced" :
+ (ghost.xl < 16) ? " powerful" :
+ (ghost.xl < 22) ? " mighty" :
+ (ghost.xl < 26) ? " great" :
+ (ghost.xl < 27) ? "n awesomely powerful"
+ : " legendary")
<< " ";
if ( concise )
gstr << get_species_abbrev(gspecies)
- << get_class_abbrev(ghost.values[GVAL_CLASS]);
+ << get_class_abbrev(ghost.job);
else
gstr << species_name(gspecies,
- ghost.values[GVAL_EXP_LEVEL])
+ ghost.xl)
<< " "
- << get_class_name(ghost.values[GVAL_CLASS]);
+ << get_class_name(ghost.job);
return gstr.str();
}
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index 8430d326fb..5e77792713 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -872,7 +872,7 @@ void direction(dist& moves, targeting_type restricts,
}
// Ask for confirmation if we're quitting for some odd reason
else if ( moves.isValid || moves.isCancel ||
- yesno("Are you sure you want to fizzle?") )
+ yesno("Are you sure you want to fizzle?", false, 'n') )
{
// Finalize whatever is inside the loop
// (moves-internal finalizations can be done later)
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index d2b0331ca1..566ba7f665 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -3384,13 +3384,9 @@ static bool build_minivaults(int level_number, int force_vault,
bool building_level, bool clobber,
bool make_no_exits, const coord_def &where)
{
- // for some weird reason can't put a vault on level 1, because monster equip
- // isn't generated.
int altar_count = 0;
FixedVector < object_class_type, 7 > acq_item_class;
- // hack - passing chars through '...' promotes them to ints, which
- // barfs under gcc in fixvec.h. So don't.
acq_item_class[0] = OBJ_WEAPONS;
acq_item_class[1] = OBJ_ARMOUR;
acq_item_class[2] = OBJ_WEAPONS;
@@ -4329,7 +4325,7 @@ bool dgn_place_monster(mons_spec &mspec,
if (mons_is_unique(mid) && you.unique_creatures[mid])
return (false);
- const habitat_type habitat = mons_habitat(mid);
+ const habitat_type habitat = mons_habitat_by_type(mid);
if (habitat != HT_LAND)
grd[vx][vy] = habitat2grid(habitat);
}
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 4658ddb393..5d0a72054e 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -1689,6 +1689,18 @@ bool recharge_wand(void)
return (true);
} // end recharge_wand()
+// Sets foe target of friendly monsters.
+static void set_friendly_foes()
+{
+ for (int i = 0; i < MAX_MONSTERS; ++i)
+ {
+ monsters *mon(&menv[i]);
+ if (!mon->alive() || !mons_near(mon) || !mons_friendly(mon))
+ continue;
+ mon->foe = you.pet_target;
+ }
+}
+
void yell(bool force)
{
bool targ_prev = false;
@@ -1723,10 +1735,12 @@ void yell(bool force)
if (force)
{
if (shout_verb == "__NONE" || you.paralysed())
- mprf("You feel a strong urge to %s, but you are unable to make a sound!",
+ mprf("You feel a strong urge to %s, but "
+ "you are unable to make a sound!",
shout_verb == "__NONE" ? "scream" : shout_verb.c_str());
else
- mprf("You feel a %s rip itself from your throat, but you make no sound!",
+ mprf("You feel a %s rip itself from your throat, "
+ "but you make no sound!",
shout_verb.c_str());
}
else
@@ -1751,9 +1765,9 @@ void yell(bool force)
if (!(you.prev_targ == MHITNOT || you.prev_targ == MHITYOU))
{
- struct monsters *target = &menv[you.prev_targ];
-
- if (mons_near(target) && player_monster_visible(target))
+ monsters *target = &menv[you.prev_targ];
+ if (target->alive() && mons_near(target)
+ && player_monster_visible(target))
{
mpr(" p - Order allies to attack your previous target");
targ_prev = true;
@@ -1818,7 +1832,11 @@ void yell(bool force)
return;
}
- you.pet_target = mons_targd;
+ if (mons_targd != MHITNOT)
+ {
+ you.pet_target = mons_targd;
+ set_friendly_foes();
+ }
noisy( 10, you.x_pos, you.y_pos );
mpr("Attack!");
@@ -2452,7 +2470,7 @@ void update_level( double elapsedTime )
continue;
// Don't move non-land or stationary monsters around
- if (mons_habitat( mon->type ) != HT_LAND
+ if (mons_habitat( mon ) != HT_LAND
|| mons_is_stationary( mon ))
{
continue;
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 28369c77ac..476bd92e88 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -1180,39 +1180,6 @@ enum flush_reason_type
NUM_FLUSH_REASONS
};
-enum ghost_value_type
-{
- GVAL_MAX_HP, // 0
- GVAL_EV,
- GVAL_AC,
- GVAL_SEE_INVIS,
- GVAL_RES_FIRE,
- GVAL_RES_COLD, // 5
- GVAL_RES_ELEC,
- GVAL_DAMAGE,
- GVAL_BRAND,
- GVAL_SPECIES,
- GVAL_BEST_SKILL, // 10
- GVAL_SKILL_LEVEL,
- GVAL_EXP_LEVEL,
- GVAL_CLASS,
- GVAL_SPELL_1, // 14
- GVAL_SPELL_2,
- GVAL_SPELL_3,
- GVAL_SPELL_4,
- GVAL_SPELL_5,
- GVAL_SPELL_6, // 19
- GVAL_SPEED,
- NUM_GHOST_VALUES, // should always be last value
-
- // these values are for demonlords, which override the above:
- GVAL_DEMONLORD_SPELLCASTER = 9,
- GVAL_DEMONLORD_FLY, // 10
- GVAL_DEMONLORD_UNUSED, // 11
- GVAL_DEMONLORD_HIT_DICE, // 12
- GVAL_DEMONLORD_CYCLE_COLOUR // 13
-};
-
// The order of this enum must match the order of DNGN_ALTAR_FOO.
enum god_type
{
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index f936981c99..dd382f2aa4 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -93,6 +93,8 @@ public:
virtual bool submerged() const = 0;
virtual bool floundering() const = 0;
+ virtual int get_experience_level() const = 0;
+
virtual bool can_pass_through(const dungeon_feature_type grid) const = 0;
virtual bool can_pass_through(const int x, const int y) const = 0;
virtual bool can_pass_through(const coord_def &c) const = 0;
@@ -107,6 +109,11 @@ public:
virtual item_def *weapon(int which_attack = -1) = 0;
virtual item_def *shield() = 0;
virtual item_def *slot_item(equipment_type eq) = 0;
+ virtual const item_def *slot_item(equipment_type eq) const
+ {
+ return const_cast<actor*>(this)->slot_item(eq);
+ }
+ virtual bool has_equipped(equipment_type eq, int sub_type) const;
virtual int hunger_level() const { return HS_ENGORGED; }
virtual void make_hungry(int nutrition, bool silent = true)
@@ -175,6 +182,7 @@ public:
virtual mon_holy_type holiness() const = 0;
virtual int res_fire() const = 0;
+ virtual int res_steam() const = 0;
virtual int res_cold() const = 0;
virtual int res_elec() const = 0;
virtual int res_poison() const = 0;
@@ -784,16 +792,16 @@ public:
size_type transform_size(int psize = PSIZE_TORSO) const;
std::string shout_verb() const;
- const item_def *slot_item(equipment_type eq) const;
item_def *slot_item(equipment_type eq);
// actor
int id() const;
+ int get_experience_level() const;
actor_type atype() const { return ACT_PLAYER; }
god_type deity() const;
bool alive() const;
-
+
coord_def pos() const;
bool swimming() const;
bool submerged() const;
@@ -849,6 +857,7 @@ public:
mon_holy_type holiness() const;
int res_fire() const;
+ int res_steam() const;
int res_cold() const;
int res_elec() const;
int res_poison() const;
@@ -984,6 +993,7 @@ class monsters : public actor
public:
monsters();
monsters(const monsters &other);
+ ~monsters();
monsters &operator = (const monsters &other);
@@ -1076,6 +1086,7 @@ public:
// actor interface
int id() const;
+ int get_experience_level() const;
god_type deity() const;
bool alive() const;
coord_def pos() const;
@@ -1146,6 +1157,7 @@ public:
mon_holy_type holiness() const;
int res_fire() const;
+ int res_steam() const;
int res_cold() const;
int res_elec() const;
int res_poison() const;
@@ -1379,34 +1391,6 @@ public:
extern struct crawl_environment env;
-struct ghost_demon
-{
-public:
- std::string name;
- FixedVector< short, NUM_GHOST_VALUES > values;
-
-public:
- ghost_demon();
- void reset();
- void init_random_demon();
- void init_player_ghost();
-
-public:
- static std::vector<ghost_demon> find_ghosts();
-
-private:
- static int n_extra_ghosts();
- static void find_extra_ghosts(std::vector<ghost_demon> &ghosts, int n);
- static void find_transiting_ghosts(std::vector<ghost_demon> &gs, int n);
- static void announce_ghost(const ghost_demon &g);
-
-private:
- void add_spells();
- int translate_spell(int playerspell) const;
-};
-
-extern std::vector<ghost_demon> ghosts;
-
struct message_filter
{
int channel; // Use -1 to match any channel.
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 09fa35a48f..632a606213 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -1654,17 +1654,16 @@ bool melee_attack::player_monattk_hit_effects(bool mondied)
return (false);
}
-int melee_attack::resist_adjust_damage(int res, int rawdamage)
+int resist_adjust_damage(actor *defender, int res, int rawdamage,
+ bool ranged)
{
+ if (defender->atype() == ACT_MONSTER && res >= 3)
+ return (0);
+
if (res > 0)
- {
- if (defender->atype() == ACT_MONSTER)
- rawdamage = 0;
- else
- rawdamage /= 1 + res * res;
- }
+ rawdamage /= 1 + res * res;
else if (res < 0)
- rawdamage *= 2;
+ rawdamage = rawdamage * (ranged? 15 : 20) / 10;
if (rawdamage < 0)
rawdamage = 0;
@@ -1676,7 +1675,8 @@ void melee_attack::calc_elemental_brand_damage(
int res,
const char *verb)
{
- special_damage = resist_adjust_damage(res, random2(damage_done) / 2 + 1);
+ special_damage =
+ resist_adjust_damage(defender, res, random2(damage_done) / 2 + 1);
if (special_damage > 0 && verb && needs_message)
{
@@ -2075,28 +2075,32 @@ bool melee_attack::apply_damage_brand()
case SPWPN_CONFUSE:
{
- // FIXME: Generalise.
- if (defender->atype() != ACT_MONSTER || attacker->atype() != ACT_PLAYER)
- break;
-
emit_nodmg_hit_message();
// FIXME Currently Confusing Touch is the *only* way to get
// here. Generalise.
const int hdcheck =
(defender->holiness() == MH_NATURAL? random2(30) : random2(22));
- if (hdcheck >= def->hit_dice)
+ if (hdcheck >= defender->get_experience_level())
{
// declaring these just to pass to the enchant function
bolt beam_temp;
- beam_temp.thrower = KILL_YOU;
- beam_temp.flavour = BEAM_CONFUSION;
+ beam_temp.thrower =
+ attacker->atype() == ACT_PLAYER? KILL_YOU : KILL_MON;
+ beam_temp.flavour = BEAM_CONFUSION;
+ beam_temp.beam_source =
+ attacker->atype() == ACT_PLAYER? MHITYOU
+ : monster_index(atk);
mons_ench_f2( def, beam_temp );
}
- you.duration[DUR_CONFUSING_TOUCH] -= roll_dice(3, 5);
+
+ if (attacker->atype() == ACT_PLAYER)
+ {
+ you.duration[DUR_CONFUSING_TOUCH] -= roll_dice(3, 5);
- if (you.duration[DUR_CONFUSING_TOUCH] < 1)
- you.duration[DUR_CONFUSING_TOUCH] = 1;
+ if (you.duration[DUR_CONFUSING_TOUCH] < 1)
+ you.duration[DUR_CONFUSING_TOUCH] = 1;
+ }
break;
}
}
@@ -2231,7 +2235,6 @@ void melee_attack::player_apply_staff_damage()
return;
const int staff_cost = 2;
-
if (you.magic_points < staff_cost
|| random2(15) > you.skills[SK_EVOCATIONS])
{
@@ -2244,10 +2247,10 @@ void melee_attack::player_apply_staff_damage()
if (damage_done + you.skills[SK_AIR_MAGIC] <= random2(20))
break;
- if (mons_res_elec(def))
- break;
-
- special_damage = player_staff_damage(SK_AIR_MAGIC);
+ special_damage =
+ resist_adjust_damage(defender,
+ defender->res_elec(),
+ player_staff_damage(SK_AIR_MAGIC));
if (special_damage)
special_damage_message =
@@ -2257,13 +2260,10 @@ void melee_attack::player_apply_staff_damage()
break;
case STAFF_COLD:
- if (mons_res_cold(def) > 0)
- break;
-
- special_damage = player_staff_damage(SK_ICE_MAGIC);
-
- if (mons_res_cold(def) < 0)
- special_damage += player_staff_damage(SK_ICE_MAGIC);
+ special_damage =
+ resist_adjust_damage(defender,
+ defender->res_cold(),
+ player_staff_damage(SK_ICE_MAGIC));
if (special_damage)
{
@@ -2287,13 +2287,10 @@ void melee_attack::player_apply_staff_damage()
break;
case STAFF_FIRE:
- if (mons_res_fire(def) > 0)
- break;
-
- special_damage = player_staff_damage(SK_FIRE_MAGIC);
-
- if (mons_res_fire(def) < 0)
- special_damage += player_staff_damage(SK_FIRE_MAGIC);
+ special_damage =
+ resist_adjust_damage(defender,
+ defender->res_fire(),
+ player_staff_damage(SK_FIRE_MAGIC));
if (special_damage)
{
@@ -2357,8 +2354,6 @@ void melee_attack::player_apply_staff_damage()
if (special_damage > 0)
{
- dec_mp(staff_cost);
-
if (!item_type_known(*weapon))
{
set_ident_flags( *weapon, ISFLAG_KNOW_TYPE );
@@ -3279,7 +3274,8 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
atk->hit_points = -10;
special_damage =
- resist_adjust_damage(defender->res_fire(),
+ resist_adjust_damage(defender,
+ defender->res_fire(),
atk->hit_dice + random2(atk->hit_dice));
if (needs_message && special_damage)
mprf("%s %s engulfed in flames%s",
@@ -3292,7 +3288,8 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
case AF_COLD:
special_damage =
- resist_adjust_damage(defender->res_cold(),
+ resist_adjust_damage(defender,
+ defender->res_cold(),
atk->hit_dice + random2( 2 * atk->hit_dice ));
if (needs_message && special_damage)
mprf("%s %s %s!",
@@ -3304,6 +3301,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
case AF_ELEC:
special_damage =
resist_adjust_damage(
+ defender,
defender->res_elec(),
atk->hit_dice + random2( atk->hit_dice / 2 ));
diff --git a/crawl-ref/source/fight.h b/crawl-ref/source/fight.h
index 03984b03b9..1a62c70b41 100644
--- a/crawl-ref/source/fight.h
+++ b/crawl-ref/source/fight.h
@@ -36,6 +36,9 @@ struct mon_attack_def;
* *********************************************************************** */
int effective_stat_bonus( int wepType = -1 );
+int resist_adjust_damage(actor *defender, int res, int rawdamage,
+ bool ranged = false);
+
// added Sept 18, 2000 -- bwr
/* ***********************************************************************
* called from: describe.cc
@@ -164,7 +167,6 @@ private:
bool attack_shield_blocked(bool verbose);
bool apply_damage_brand();
void calc_elemental_brand_damage(int res, const char *verb);
- int resist_adjust_damage(int res, int rawdamage);
int fire_res_apply_cerebov_downgrade(int res);
void drain_defender();
void drain_player();
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index 78d8edb5ef..932c0a6a2c 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -63,6 +63,7 @@
#include "direct.h"
#include "dungeon.h"
#include "effects.h"
+#include "ghost.h"
#include "initfile.h"
#include "itemname.h"
#include "itemprop.h"
@@ -107,6 +108,8 @@ void save_level(int level_saved, level_area_type lt,
#define LEVEL_MINOR_VERSION 1
#define YOU_MINOR_VERSION 1
+const short GHOST_SIGNATURE = static_cast<short>( 0xDC55 );
+
static void redraw_all(void)
{
you.redraw_hit_points = 1;
@@ -601,8 +604,41 @@ std::string make_filename( const char *prefix, int level, branch_type where,
isGhost );
}
+static void write_version( FILE *dataFile, int majorVersion, int minorVersion,
+ bool extended_version )
+{
+ // write version
+ tagHeader versionTag;
+ versionTag.offset = 0;
+ versionTag.tagID = TAG_VERSION;
+
+ marshallByte(versionTag, majorVersion);
+ marshallByte(versionTag, minorVersion);
+
+ // extended_version just pads the version out to four 32-bit words.
+ // This makes the bones file compatible with Hearse with no extra
+ // munging needed.
+ if (extended_version)
+ {
+ // Use a single signature 16-bit word to indicate that this is
+ // Stone Soup and to disambiguate this (unmunged) bones file
+ // from the munged bones files offered by the old Crawl-aware
+ // hearse.pl. Crawl-aware hearse.pl will prefix the bones file
+ // with the first 16-bits of the Crawl version, and the following
+ // 7 16-bit words set to 0.
+ marshallShort(versionTag, GHOST_SIGNATURE);
+
+ // Write the three remaining 32-bit words of padding.
+ for (int i = 0; i < 3; ++i)
+ marshallLong(versionTag, 0);
+ }
+
+ tag_write(versionTag, dataFile);
+}
+
static void write_tagged_file( FILE *dataFile, char majorVersion,
- char minorVersion, int fileType )
+ char minorVersion, int fileType,
+ bool extended_version = false )
{
struct tagHeader th;
@@ -610,13 +646,7 @@ static void write_tagged_file( FILE *dataFile, char majorVersion,
char tags[NUM_TAGS];
tag_set_expected(tags, fileType);
- // write version
- struct tagHeader versionTag;
- versionTag.offset = 0;
- versionTag.tagID = TAG_VERSION;
- marshallByte(versionTag, majorVersion);
- marshallByte(versionTag, minorVersion);
- tag_write(versionTag, dataFile);
+ write_version( dataFile, majorVersion, minorVersion, extended_version );
// all other tags
for(int i=1; i<NUM_TAGS; i++)
@@ -1606,21 +1636,23 @@ static bool determine_ghost_version( FILE *ghostFile,
if (read2(ghostFile, buf, 2) != 2)
return false; // empty file?
- // check for pre-v4 -- simply started right in with ghost name.
- if (isprint(buf[0]) && buf[0] > 4)
- {
- majorVersion = 0;
- minorVersion = 0;
- rewind(ghostFile);
- return true;
- }
-
// otherwise, read version and validate.
majorVersion = buf[0];
minorVersion = buf[1];
- if (majorVersion == SAVE_MAJOR_VERSION)
- return true;
+ // check for the DCSS ghost signature.
+ if (readShort(ghostFile) != GHOST_SIGNATURE)
+ return (false);
+
+ if (majorVersion == SAVE_MAJOR_VERSION
+ && minorVersion <= GHOST_MINOR_VERSION)
+ {
+ // Discard three more 32-bit words of padding.
+ for (int i = 0; i < 3; ++i)
+ readLong(ghostFile);
+
+ return !feof(ghostFile);
+ }
return false; // if its not SAVE_MAJOR_VERSION, no idea!
}
@@ -1669,7 +1701,8 @@ void save_ghost( bool force )
}
write_tagged_file( gfile, SAVE_MAJOR_VERSION,
- GHOST_MINOR_VERSION, TAGTYPE_GHOST );
+ GHOST_MINOR_VERSION, TAGTYPE_GHOST,
+ true );
lk_close(gfile, "wb", cha_fil);
diff --git a/crawl-ref/source/ghost.cc b/crawl-ref/source/ghost.cc
index 2ddde666ff..b5075aaccf 100644
--- a/crawl-ref/source/ghost.cc
+++ b/crawl-ref/source/ghost.cc
@@ -8,6 +8,8 @@
#include "AppHdr.h"
+#include "ghost.h"
+
#include "externs.h"
#include "itemname.h"
#include "itemprop.h"
@@ -98,7 +100,7 @@ static spell_type search_order_misc[] = {
/* Last slot (emergency) can only be teleport self or blink. */
-ghost_demon::ghost_demon() : name(), values()
+ghost_demon::ghost_demon()
{
reset();
}
@@ -106,8 +108,22 @@ ghost_demon::ghost_demon() : name(), values()
void ghost_demon::reset()
{
name.clear();
- values.init(0);
- values[GVAL_SPEED] = 10;
+ species = SP_UNKNOWN;
+ job = JOB_UNKNOWN;
+ best_skill = SK_FIGHTING;
+ best_skill_level = 0;
+ xl = 0;
+ max_hp = 0;
+ ev = 0;
+ ac = 0;
+ damage = 0;
+ speed = 10;
+ see_invis = false;
+ brand = SPWPN_NORMAL;
+ resists = mon_resist_def();
+ spellcaster = false;
+ cycle_colours = false;
+ fly = FL_NONE;
}
void ghost_demon::init_random_demon()
@@ -115,172 +131,166 @@ void ghost_demon::init_random_demon()
name = make_name(random_int(), false);
// hp - could be defined below (as could ev, AC etc). Oh well, too late:
- values[ GVAL_MAX_HP ] = 100 + roll_dice( 3, 50 );
+ max_hp = 100 + roll_dice( 3, 50 );
- values[ GVAL_EV ] = 5 + random2(20);
- values[ GVAL_AC ] = 5 + random2(20);
+ ev = 5 + random2(20);
+ ac = 5 + random2(20);
- values[ GVAL_SEE_INVIS ] = (one_chance_in(10) ? 0 : 1);
+ see_invis = !one_chance_in(10);
if (!one_chance_in(3))
- values[ GVAL_RES_FIRE ] = (coinflip() ? 2 : 3);
+ resists.fire = random_range(1, 2);
else
{
- values[ GVAL_RES_FIRE ] = 0; /* res_fire */
+ resists.fire = 0; /* res_fire */
if (one_chance_in(10))
- values[ GVAL_RES_FIRE ] = -1;
+ resists.fire = -1;
}
if (!one_chance_in(3))
- values[ GVAL_RES_COLD ] = 2;
+ resists.cold = random_range(1, 2);
else
{
- values[ GVAL_RES_COLD ] = 0; /* res_cold */
-
+ resists.cold = 0;
if (one_chance_in(10))
- values[ GVAL_RES_COLD ] = -1;
+ resists.cold = -1;
}
// demons, like ghosts, automatically get poison res. and life prot.
// resist electricity:
- values[ GVAL_RES_ELEC ] = !one_chance_in(3);
+ resists.elec = one_chance_in(3);
// HTH damage:
- values[ GVAL_DAMAGE ] = 20 + roll_dice( 2, 20 );
+ damage = 20 + roll_dice( 2, 20 );
// special attack type (uses weapon brand code):
- values[ GVAL_BRAND ] = SPWPN_NORMAL;
+ brand = SPWPN_NORMAL;
if (!one_chance_in(3))
{
do {
- values[ GVAL_BRAND ] = random2(17);
+ brand = static_cast<brand_type>( random2(MAX_PAN_LORD_BRANDS) );
/* some brands inappropriate (e.g. holy wrath) */
- } while (values[ GVAL_BRAND ] == SPWPN_HOLY_WRATH
- || (values[ GVAL_BRAND ] == SPWPN_ORC_SLAYING
+ } while (brand == SPWPN_HOLY_WRATH
+ || (brand == SPWPN_ORC_SLAYING
&& you.mons_species() != MONS_ORC)
- || (values[ GVAL_BRAND ] == SPWPN_DRAGON_SLAYING
+ || (brand == SPWPN_DRAGON_SLAYING
&& you.mons_species() != MONS_DRACONIAN)
- || values[ GVAL_BRAND ] == SPWPN_PROTECTION
- || values[ GVAL_BRAND ] == SPWPN_FLAME
- || values[ GVAL_BRAND ] == SPWPN_FROST);
+ || brand == SPWPN_PROTECTION
+ || brand == SPWPN_FLAME
+ || brand == SPWPN_FROST);
}
// is demon a spellcaster?
// upped from one_chance_in(3)... spellcasters are more interesting
// and I expect named demons to typically have a trick or two -- bwr
- values[GVAL_DEMONLORD_SPELLCASTER] = !one_chance_in(10);
-
- // does demon fly? (0 = no, 1 = fly, 2 = levitate)
- values[GVAL_DEMONLORD_FLY] = (one_chance_in(3) ? 0 :
- one_chance_in(5) ? 2 : 1);
-
- // vacant <ghost best skill level>:
- values[GVAL_DEMONLORD_UNUSED] = 0;
+ spellcaster = !one_chance_in(10);
+ // does demon fly?
+ fly = (one_chance_in(3)? FL_NONE :
+ one_chance_in(5)? FL_LEVITATE : FL_FLY);
+
// hit dice:
- values[GVAL_DEMONLORD_HIT_DICE] = 10 + roll_dice(2, 10);
+ xl = 10 + roll_dice(2, 10);
// does demon cycle colours?
- values[GVAL_DEMONLORD_CYCLE_COLOUR] = (one_chance_in(10) ? 1 : 0);
+ cycle_colours = one_chance_in(10);
- for (int i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
- values[i] = SPELL_NO_SPELL;
+ spells.init(SPELL_NO_SPELL);
/* This bit uses the list of player spells to find appropriate spells
for the demon, then converts those spells to the monster spell indices.
Some special monster-only spells are at the end. */
- if (values[ GVAL_DEMONLORD_SPELLCASTER ] == 1)
+ if (spellcaster)
{
if (coinflip())
- values[GVAL_SPELL_1] = RANDOM_ELEMENT(search_order_conj);
+ spells[0] = RANDOM_ELEMENT(search_order_conj);
// Might duplicate the first spell, but that isn't a problem.
if (coinflip())
- values[GVAL_SPELL_2] = RANDOM_ELEMENT(search_order_conj);
+ spells[1] = RANDOM_ELEMENT(search_order_conj);
if (!one_chance_in(4))
- values[GVAL_SPELL_3] = RANDOM_ELEMENT(search_order_third);
+ spells[2] = RANDOM_ELEMENT(search_order_third);
if (coinflip())
{
- values[GVAL_SPELL_4] = RANDOM_ELEMENT(search_order_misc);
- if ( values[GVAL_SPELL_4] == SPELL_DIG )
- values[GVAL_SPELL_4] = SPELL_NO_SPELL;
+ spells[3] = RANDOM_ELEMENT(search_order_misc);
+ if ( spells[3] == SPELL_DIG )
+ spells[3] = SPELL_NO_SPELL;
}
if (coinflip())
- values[GVAL_SPELL_5] = RANDOM_ELEMENT(search_order_misc);
-
+ spells[4] = RANDOM_ELEMENT(search_order_misc);
if (coinflip())
- values[ GVAL_SPELL_6 ] = SPELL_BLINK;
+ spells[5] = SPELL_BLINK;
if (coinflip())
- values[ GVAL_SPELL_6 ] = SPELL_TELEPORT_SELF;
+ spells[5] = SPELL_TELEPORT_SELF;
/* Converts the player spell indices to monster spell ones */
- for (int i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
- values[i] = translate_spell( values[i] );
+ for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; i++)
+ spells[i] = translate_spell( spells[i] );
/* give demon a chance for some monster-only spells: */
/* and demon-summoning should be fairly common: */
if (one_chance_in(25))
- values[GVAL_SPELL_1] = SPELL_HELLFIRE_BURST;
+ spells[0] = SPELL_HELLFIRE_BURST;
if (one_chance_in(25))
- values[GVAL_SPELL_1] = SPELL_METAL_SPLINTERS;
+ spells[0] = SPELL_METAL_SPLINTERS;
if (one_chance_in(25))
- values[GVAL_SPELL_1] = SPELL_ENERGY_BOLT; /* eye of devas */
+ spells[0] = SPELL_ENERGY_BOLT; /* eye of devas */
if (one_chance_in(25))
- values[GVAL_SPELL_2] = SPELL_STEAM_BALL;
+ spells[1] = SPELL_STEAM_BALL;
if (one_chance_in(25))
- values[GVAL_SPELL_2] = SPELL_ISKENDERUNS_MYSTIC_BLAST;
+ spells[1] = SPELL_ISKENDERUNS_MYSTIC_BLAST;
if (one_chance_in(25))
- values[GVAL_SPELL_2] = SPELL_HELLFIRE;
+ spells[1] = SPELL_HELLFIRE;
if (one_chance_in(25))
- values[GVAL_SPELL_3] = SPELL_SMITING;
+ spells[2] = SPELL_SMITING;
if (one_chance_in(25))
- values[GVAL_SPELL_3] = SPELL_HELLFIRE_BURST;
+ spells[2] = SPELL_HELLFIRE_BURST;
if (one_chance_in(12))
- values[GVAL_SPELL_3] = SPELL_SUMMON_GREATER_DEMON;
+ spells[2] = SPELL_SUMMON_GREATER_DEMON;
if (one_chance_in(12))
- values[GVAL_SPELL_3] = SPELL_SUMMON_DEMON;
+ spells[2] = SPELL_SUMMON_DEMON;
if (one_chance_in(20))
- values[GVAL_SPELL_4] = SPELL_SUMMON_GREATER_DEMON;
+ spells[3] = SPELL_SUMMON_GREATER_DEMON;
if (one_chance_in(20))
- values[GVAL_SPELL_4] = SPELL_SUMMON_DEMON;
+ spells[3] = SPELL_SUMMON_DEMON;
/* at least they can summon demons */
- if (values[GVAL_SPELL_4] == SPELL_NO_SPELL)
- values[GVAL_SPELL_4] = SPELL_SUMMON_DEMON;
+ if (spells[3] == SPELL_NO_SPELL)
+ spells[3] = SPELL_SUMMON_DEMON;
if (one_chance_in(15))
- values[GVAL_SPELL_5] = SPELL_DIG;
+ spells[4] = SPELL_DIG;
}
}
void ghost_demon::init_player_ghost()
{
name = you.your_name;
- values[ GVAL_MAX_HP ] = ((you.hp_max >= 400) ? 400 : you.hp_max);
- values[ GVAL_EV ] = player_evasion();
- values[ GVAL_AC ] = player_AC();
+ max_hp = ((you.hp_max >= 400) ? 400 : you.hp_max);
+ ev = player_evasion();
+ ac = player_AC();
- if (values[GVAL_EV] > 40)
- values[GVAL_EV] = 40;
-
- values[ GVAL_SEE_INVIS ] = player_see_invis();
- values[ GVAL_RES_FIRE ] = player_res_fire();
- values[ GVAL_RES_COLD ] = player_res_cold();
- values[ GVAL_RES_ELEC ] = player_res_electricity();
- values[ GVAL_SPEED ] = player_ghost_base_movement_speed();
+ if (ev > 60)
+ ev = 60;
+
+ see_invis = player_see_invis();
+ resists.fire = player_res_fire();
+ resists.cold = player_res_cold();
+ resists.elec = player_res_electricity();
+ speed = player_ghost_base_movement_speed();
int d = 4;
- int e = 0;
+ int e = SPWPN_NORMAL;
const int wpn = you.equip[EQ_WEAPON];
if (wpn != -1)
@@ -320,19 +330,18 @@ void ghost_demon::init_player_ghost()
if (d > 50)
d = 50;
- values[ GVAL_DAMAGE ] = d;
- values[ GVAL_BRAND ] = e;
- values[ GVAL_SPECIES ] = you.species;
- values[ GVAL_BEST_SKILL ] = best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99);
- values[ GVAL_SKILL_LEVEL ] =
- you.skills[best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99)];
- values[ GVAL_EXP_LEVEL ] = you.experience_level;
- values[ GVAL_CLASS ] = you.char_class;
+ damage = d;
+ brand = static_cast<brand_type>( e );
+ species = you.species;
+ best_skill = ::best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99);
+ best_skill_level = you.skills[best_skill];
+ xl = you.experience_level;
+ job = you.char_class;
add_spells();
}
-static int search_first_list(int ignore_spell)
+static spell_type search_first_list(int ignore_spell)
{
for (unsigned i = 0;
i < sizeof(search_order_conj) / sizeof(*search_order_conj); i++)
@@ -350,7 +359,7 @@ static int search_first_list(int ignore_spell)
return SPELL_NO_SPELL;
} // end search_first_list()
-static int search_second_list(int ignore_spell)
+static spell_type search_second_list(int ignore_spell)
{
for (unsigned i = 0;
i < sizeof(search_order_third) / sizeof(*search_order_third); i++)
@@ -368,7 +377,7 @@ static int search_second_list(int ignore_spell)
return SPELL_NO_SPELL;
} // end search_second_list()
-static int search_third_list(int ignore_spell)
+static spell_type search_third_list(int ignore_spell)
{
for (unsigned i = 0;
i < sizeof(search_order_misc) / sizeof(*search_order_misc); i++)
@@ -394,44 +403,43 @@ void ghost_demon::add_spells( )
{
int i = 0;
- for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
- values[i] = SPELL_NO_SPELL;
+ spells.init(SPELL_NO_SPELL);
- values[ GVAL_SPELL_1 ] = search_first_list(SPELL_NO_SPELL);
- values[ GVAL_SPELL_2 ] = search_first_list(values[GVAL_SPELL_1]);
- values[ GVAL_SPELL_3 ] = search_second_list(SPELL_NO_SPELL);
- values[ GVAL_SPELL_4 ] = search_third_list(SPELL_DIG);
+ spells[ 0 ] = search_first_list(SPELL_NO_SPELL);
+ spells[ 1 ] = search_first_list(spells[0]);
+ spells[ 2 ] = search_second_list(SPELL_NO_SPELL);
+ spells[ 3 ] = search_third_list(SPELL_DIG);
- if (values[ GVAL_SPELL_4 ] == SPELL_NO_SPELL)
- values[ GVAL_SPELL_4 ] = search_first_list(SPELL_NO_SPELL);
+ if (spells[ 3 ] == SPELL_NO_SPELL)
+ spells[ 3 ] = search_first_list(SPELL_NO_SPELL);
- values[ GVAL_SPELL_5 ] = search_third_list(values[GVAL_SPELL_4]);
+ spells[ 4 ] = search_third_list(spells[3]);
- if (values[ GVAL_SPELL_5 ] == SPELL_NO_SPELL)
- values[ GVAL_SPELL_5 ] = search_first_list(values[GVAL_SPELL_4]);
+ if (spells[ 4 ] == SPELL_NO_SPELL)
+ spells[ 4 ] = search_first_list(spells[3]);
if (player_has_spell( SPELL_DIG ))
- values[ GVAL_SPELL_5 ] = SPELL_DIG;
+ spells[ 4 ] = SPELL_DIG;
/* Looks for blink/tport for emergency slot */
if (player_has_spell( SPELL_CONTROLLED_BLINK )
|| player_has_spell( SPELL_BLINK ))
{
- values[ GVAL_SPELL_6 ] = SPELL_CONTROLLED_BLINK;
+ spells[ 5 ] = SPELL_CONTROLLED_BLINK;
}
if (player_has_spell( SPELL_TELEPORT_SELF ))
- values[ GVAL_SPELL_6 ] = SPELL_TELEPORT_SELF;
+ spells[ 5 ] = SPELL_TELEPORT_SELF;
- for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
- values[i] = translate_spell( values[i] );
+ for (i = 0; i < NUM_MONSTER_SPELL_SLOTS; i++)
+ spells[i] = translate_spell( spells[i] );
} // end add_spells()
/*
When passed the number for a player spell, returns the equivalent monster
spell. Returns SPELL_NO_SPELL on failure (no equiv).
*/
-int ghost_demon::translate_spell(int spel) const
+spell_type ghost_demon::translate_spell(spell_type spel) const
{
switch (spel)
{
diff --git a/crawl-ref/source/ghost.h b/crawl-ref/source/ghost.h
new file mode 100644
index 0000000000..b4f861ca3d
--- /dev/null
+++ b/crawl-ref/source/ghost.h
@@ -0,0 +1,52 @@
+#ifndef GHOST_H
+#define GHOST_H
+
+#include "externs.h"
+#include "enum.h"
+#include "itemprop.h"
+#include "mon-util.h"
+
+struct ghost_demon
+{
+public:
+ std::string name;
+
+ species_type species;
+ job_type job;
+ skill_type best_skill;
+ short best_skill_level;
+ short xl;
+
+ short max_hp, ev, ac, damage, speed;
+ bool see_invis;
+ brand_type brand;
+ mon_resist_def resists;
+
+ bool spellcaster, cycle_colours;
+ flight_type fly;
+
+ monster_spells spells;
+
+public:
+ ghost_demon();
+ void reset();
+ void init_random_demon();
+ void init_player_ghost();
+
+public:
+ static std::vector<ghost_demon> find_ghosts();
+
+private:
+ static int n_extra_ghosts();
+ static void find_extra_ghosts(std::vector<ghost_demon> &ghosts, int n);
+ static void find_transiting_ghosts(std::vector<ghost_demon> &gs, int n);
+ static void announce_ghost(const ghost_demon &g);
+
+private:
+ void add_spells();
+ spell_type translate_spell(spell_type playerspell) const;
+};
+
+extern std::vector<ghost_demon> ghosts;
+
+#endif
diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc
index b018483cb6..afb978dfa1 100644
--- a/crawl-ref/source/itemname.cc
+++ b/crawl-ref/source/itemname.cc
@@ -987,7 +987,7 @@ std::string item_def::name_aux( description_level_type desc,
const bool know_brand =
!basename && !qualname && !dbname
&& !testbits(ignore_flags, ISFLAG_KNOW_TYPE)
- && (ident || item_ident(*this, ISFLAG_KNOW_TYPE));
+ && (ident || item_type_known(*this));
const bool know_ego = know_brand;
@@ -1068,9 +1068,9 @@ std::string item_def::name_aux( description_level_type desc,
buff << racial_description_string(*this, terse);
if (know_brand && !terse &&
- (get_weapon_brand(*this) == SPWPN_VAMPIRICISM))
+ (get_weapon_brand(*this) == SPWPN_VAMPIRICISM))
{
- buff << "vampiric ";
+ buff << "vampiric ";
}
buff << item_base_name(*this);
@@ -1649,9 +1649,17 @@ bool item_type_known( const item_def& item )
// Artefacts have different descriptions from other items,
// so we can't use general item knowledge for them.
- if ( is_artefact(item) )
+ if (is_artefact(item))
return false;
+ // Poisoned missiles are always identified.
+ if (item.base_type == OBJ_MISSILES)
+ {
+ int ammo_brand = get_ammo_brand(item);
+ if (ammo_brand == SPMSL_POISONED || ammo_brand == SPMSL_CURARE)
+ return (true);
+ }
+
const item_type_id_type idt = objtype_to_idtype(item.base_type);
if ( idt != NUM_IDTYPE && item.sub_type < 50 )
return ( type_ids[idt][item.sub_type] == ID_KNOWN_TYPE );
diff --git a/crawl-ref/source/itemprop.h b/crawl-ref/source/itemprop.h
index 70057a19d8..1c680e69c5 100644
--- a/crawl-ref/source/itemprop.h
+++ b/crawl-ref/source/itemprop.h
@@ -96,7 +96,10 @@ enum brand_type // equivalent to (you.inv[].special or mitm[].special) % 30
SPWPN_PAIN, // 15
SPWPN_DISTORTION,
SPWPN_REACHING, // 17
- SPWPN_RETURNING,
+
+ MAX_PAN_LORD_BRANDS, // 18
+
+ SPWPN_RETURNING = MAX_PAN_LORD_BRANDS,
SPWPN_CONFUSE,
SPWPN_RANDART_I = 25, // 25
SPWPN_RANDART_II,
diff --git a/crawl-ref/source/libunix.cc b/crawl-ref/source/libunix.cc
index a2f1cc2fbc..93ce48d10a 100644
--- a/crawl-ref/source/libunix.cc
+++ b/crawl-ref/source/libunix.cc
@@ -290,7 +290,10 @@ static int raw_m_getch()
}
#endif
default:
- return (c);
+ // getch() returns -1 on EOF, convert that into an Escape. Evil hack,
+ // but the alternative is to explicitly check for -1 everywhere where
+ // we might otherwise spin in a tight keyboard input loop.
+ return (c == -1? ESCAPE : c);
}
}
@@ -301,7 +304,7 @@ int m_getch()
c = raw_m_getch();
while ((c == CK_MOUSE_MOVE || c == CK_MOUSE_CLICK)
&& !crawl_state.mouse_enabled);
-
+
return (c);
}
diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc
index 1f36b305db..9c919f1fe5 100644
--- a/crawl-ref/source/message.cc
+++ b/crawl-ref/source/message.cc
@@ -746,7 +746,7 @@ void more(void)
if (Options.show_more_prompt && !suppress_messages)
{
- char keypress = 0;
+ int keypress = 0;
if (Options.tutorial_left)
message_out(crawl_view.msgsz.y - 1,
@@ -764,7 +764,8 @@ void more(void)
do
keypress = getch();
- while (keypress != ' ' && keypress != '\r' && keypress != '\n');
+ while (keypress != ' ' && keypress != '\r' && keypress != '\n'
+ && keypress != -1);
}
mesclr(true);
} // end more()
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 7111bc8881..b6df1ef8d5 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -656,7 +656,7 @@ void up_stairs(dungeon_feature_type force_stair,
mpr("Warning: level annotation for next level is:", MSGCH_PROMPT);
mpr(get_level_annotation(next_level_id).c_str(), MSGCH_PROMPT);
- if (!yesno("Enter next level anyways?", true, 0, true, false))
+ if (!yesno("Enter next level anyway?", true, 0, true, false))
{
interrupt_activity( AI_FORCE_INTERRUPT );
return;
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index 100d7edd66..5a094e8c72 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -1433,7 +1433,7 @@
{
MONS_MOTTLED_DRAGON, 'D', MAGENTA, "mottled dragon",
M_SPELLCASTER | M_FLIES,
- MR_RES_POISON | MR_RES_FIRE,
+ MR_RES_POISON | MR_RES_FIRE | MR_RES_STICKY_FLAME,
1100, 10, MONS_DRAGON, MONS_MOTTLED_DRAGON, MH_NATURAL, -3,
{ {AT_BITE, AF_PLAIN, 15}, {AT_CLAW, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK },
{ 5, 3, 5, 0 },
@@ -3480,7 +3480,7 @@
{
MONS_MOTTLED_DRACONIAN, 'd', LIGHTMAGENTA, "mottled draconian",
M_HUMANOID | M_COLD_BLOOD,
- MR_RES_FIRE,
+ MR_RES_FIRE | MR_RES_STICKY_FLAME,
900, 10, MONS_DRACONIAN, MONS_MOTTLED_DRACONIAN, MH_NATURAL, -2,
{ {AT_HIT, AF_PLAIN, 20}, {AT_HIT, AF_PLAIN, 0}, {AT_HIT, AF_PLAIN, 0} },
{ 14, 5, 4, 0 },
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 8fad0cfef9..8a9eef2355 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -34,6 +34,8 @@
#include "debug.h"
#include "delay.h"
#include "dgnevent.h"
+#include "fight.h"
+#include "ghost.h"
#include "insult.h"
#include "itemname.h"
#include "itemprop.h"
@@ -256,14 +258,18 @@ void init_monster_symbols()
}
}
-unsigned long get_mons_class_resists(int mc)
+const mon_resist_def &get_mons_class_resists(int mc)
{
- return (smc->resists);
+ const monsterentry *me = get_monster_data(mc);
+ return (me? me->resists : get_monster_data(MONS_PROGRAM_BUG)->resists);
}
-unsigned long get_mons_resists(const monsters *mon)
+mon_resist_def get_mons_resists(const monsters *mon)
{
- unsigned long resists = get_mons_class_resists(mon->type);
+ if (mon->type == MONS_PLAYER_GHOST || mon->type == MONS_PANDEMONIUM_DEMON)
+ return (mon->ghost->resists);
+
+ mon_resist_def resists = get_mons_class_resists(mon->type);
if ((mons_genus(mon->type) == MONS_DRACONIAN &&
mon->type != MONS_DRACONIAN) ||
mon->type == MONS_TIAMAT)
@@ -290,11 +296,6 @@ int mons_piety(const monsters *mon)
return (mon->hit_dice * 14);
}
-unsigned long mons_resist(const monsters *mon, unsigned long flags)
-{
- return (get_mons_resists(mon) & flags);
-}
-
bool mons_class_flag(int mc, int bf)
{
const monsterentry *me = smc;
@@ -394,7 +395,7 @@ bool mons_class_is_slowable(int mc)
bool mons_is_wall_shielded(int mc)
{
- return (mons_habitat(mc) == HT_ROCK);
+ return (mons_habitat_by_type(mc) == HT_ROCK);
}
// returns whether a monster is non-solid
@@ -605,7 +606,7 @@ bool mons_sense_invis(const monsters *mon)
bool mons_see_invis(const monsters *mon)
{
if (mon->type == MONS_PLAYER_GHOST || mon->type == MONS_PANDEMONIUM_DEMON)
- return (mon->ghost->values[ GVAL_SEE_INVIS ]);
+ return (mon->ghost->see_invis);
else if (mons_class_flag(mon->type, M_SEE_INVIS))
return (true);
else if (scan_mon_inv_randarts( mon, RAP_EYESIGHT ) > 0)
@@ -739,7 +740,7 @@ mon_attack_def mons_attack_spec(const monsters *mons, int attk_number)
if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
{
if (attk_number == 0)
- return mon_attack_def::attk(mons->ghost->values[GVAL_DAMAGE]);
+ return mon_attack_def::attk(mons->ghost->damage);
else
return mon_attack_def::attk(0, AT_NONE);
}
@@ -852,14 +853,10 @@ int mons_res_elec( const monsters *mon )
{
int mc = mon->type;
- if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
- return (mon->ghost->values[ GVAL_RES_ELEC ]);
-
/* this is a variable, not a player_xx() function, so can be above 1 */
int u = 0;
- if (mons_resist(mon, MR_RES_ELEC))
- u++;
+ u += get_mons_resists(mon).elec;
// don't bother checking equipment if the monster can't use it
if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
@@ -885,26 +882,19 @@ bool mons_res_asphyx( const monsters *mon )
|| holiness == MH_DEMONIC
|| holiness == MH_NONLIVING
|| holiness == MH_PLANT
- || mons_resist(mon, MR_RES_ASPHYX));
+ || get_mons_resists(mon).asphyx > 0);
}
int mons_res_acid( const monsters *mon )
{
- const unsigned long f = get_mons_resists(mon);
- return ((f & MR_RES_ACID) != 0);
+ return get_mons_resists(mon).acid;
}
int mons_res_poison( const monsters *mon )
{
int mc = mon->type;
- unsigned long u = 0, f = get_mons_resists(mon);
-
- if (f & MR_RES_POISON)
- u++;
-
- if (f & MR_VUL_POISON)
- u--;
+ int u = get_mons_resists(mon).poison;
if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
{
@@ -930,26 +920,27 @@ int mons_res_poison( const monsters *mon )
return (u);
} // end mons_res_poison()
+bool mons_res_sticky_flame( const monsters *mon )
+{
+ return (get_mons_resists(mon).sticky_flame
+ || mon->has_equipped(EQ_BODY_ARMOUR, ARM_MOTTLED_DRAGON_ARMOUR));
+}
+
+int mons_res_steam( const monsters *mon )
+{
+ int res = get_mons_resists(mon).steam;
+ if (mon->has_equipped(EQ_BODY_ARMOUR, ARM_STEAM_DRAGON_ARMOUR))
+ res += 3;
+ return (res + mons_res_fire(mon) / 2);
+}
+
int mons_res_fire( const monsters *mon )
{
int mc = mon->type;
- if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
- return (mon->ghost->values[ GVAL_RES_FIRE ]);
-
- int u = 0, f = get_mons_resists(mon);
-
- // no Big Prize (tm) here either if you set all three flags. It's a pity uh?
- //
- // Note that natural monster resistance is two levels, this is duplicate
- // the fact that having this flag used to be a lot better than armour
- // for monsters (it used to make them immune in a lot of cases) -- bwr
- if (f & MR_RES_HELLFIRE)
- u += 3;
- else if (f & MR_RES_FIRE)
- u += 2;
- else if (f & MR_VUL_FIRE)
- u--;
+ const mon_resist_def res = get_mons_resists(mon);
+
+ int u = std::min(res.fire + res.hellfire * 3, 3);
if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
{
@@ -982,18 +973,7 @@ int mons_res_cold( const monsters *mon )
{
int mc = mon->type;
- if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
- return (mon->ghost->values[ GVAL_RES_COLD ]);
-
- int u = 0, f = get_mons_resists(mon);
-
- // Note that natural monster resistance is two levels, this is duplicate
- // the fact that having this flag used to be a lot better than armour
- // for monsters (it used to make them immune in a lot of cases) -- bwr
- if (f & MR_RES_COLD)
- u += 2;
- else if (f & MR_VUL_COLD)
- u--;
+ int u = get_mons_resists(mon).cold;
if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
{
@@ -1104,9 +1084,9 @@ flight_type mons_class_flies(int mc)
flight_type mons_flies(const monsters *mon)
{
if (mon->type == MONS_PANDEMONIUM_DEMON
- && mon->ghost->values[ GVAL_DEMONLORD_FLY ])
+ && mon->ghost->fly)
{
- return (FL_FLY);
+ return (mon->ghost->fly);
}
const flight_type ret = mons_class_flies( mon->type );
@@ -1686,9 +1666,16 @@ mon_intel_type mons_intel(int mc)
return (smc->intel);
}
-habitat_type mons_habitat(int mc)
+habitat_type mons_habitat_by_type(int mc)
+{
+ const monsterentry *me = get_monster_data(mc);
+ return (me? me->habitat : HT_LAND);
+}
+
+habitat_type mons_habitat(const monsters *m)
{
- return (smc->habitat);
+ return mons_habitat_by_type(
+ mons_is_zombified(m)? mons_zombie_base(m) : m->type );
}
bool intelligent_ally(const monsters *monster)
@@ -1761,7 +1748,7 @@ int mons_offhand_weapon_index(const monsters *m)
int mons_base_damage_brand(const monsters *m)
{
if (m->type == MONS_PLAYER_GHOST || m->type == MONS_PANDEMONIUM_DEMON)
- return m->ghost->values[ GVAL_BRAND ];
+ return m->ghost->brand;
return (SPWPN_NORMAL);
}
@@ -1986,6 +1973,15 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
int intel, est_magic_resist, power, diff;
const actor *foe = mon->get_foe();
+
+ // Keep friendly summoners from spamming summons constantly.
+ if (mons_friendly(mon)
+ && (!foe || foe == &you)
+ && spell_typematch(monspell, SPTYP_SUMMONING))
+ {
+ return (true);
+ }
+
// Eventually, we'll probably want to be able to have monsters
// learn which of their elemental bolts were resisted and have those
// handled here as well. -- bwr
@@ -2337,6 +2333,11 @@ monsters::monsters()
{
}
+// Empty destructor to keep auto_ptr happy with incomplete ghost_demon type.
+monsters::~monsters()
+{
+}
+
monsters::monsters(const monsters &mon)
{
init_with(mon);
@@ -2395,7 +2396,7 @@ coord_def monsters::target_pos() const
bool monsters::swimming() const
{
const dungeon_feature_type grid = grd[x][y];
- return (grid_is_watery(grid) && mons_habitat(type) == HT_WATER);
+ return (grid_is_watery(grid) && mons_habitat(this) == HT_WATER);
}
bool monsters::submerged() const
@@ -2409,7 +2410,7 @@ bool monsters::floundering() const
return (grid_is_water(grid)
// Can't use monster_habitable_grid because that'll return true
// for non-water monsters in shallow water.
- && mons_habitat(type) != HT_WATER
+ && mons_habitat(this) != HT_WATER
&& !mons_amphibious(type)
&& !mons_flies(this));
}
@@ -2693,6 +2694,10 @@ bool monsters::can_use_missile(const item_def &item) const
// grabbing missiles.
if (has_spell_of_type(SPTYP_CONJURATION | SPTYP_SUMMONING))
return (false);
+
+ // Blademasters don't want to throw stuff.
+ if (type == MONS_DEEP_ELF_BLADEMASTER)
+ return (false);
if (item.base_type == OBJ_WEAPONS)
return (is_throwable(item));
@@ -3392,6 +3397,11 @@ int monsters::id() const
return (type);
}
+int monsters::get_experience_level() const
+{
+ return (hit_dice);
+}
+
bool monsters::fumbles_attack(bool verbose)
{
if (floundering() && one_chance_in(4))
@@ -3434,7 +3444,7 @@ void monsters::go_berserk(bool /* intentional */)
simple_monster_message(
this,
make_stringf(" shakes off %s lethargy.",
- name(DESC_NOCAP_YOUR).c_str()).c_str());
+ pronoun(PRONOUN_NOCAP_POSSESSIVE).c_str()).c_str());
}
del_ench(ENCH_HASTE);
del_ench(ENCH_FATIGUE, true); // give no additional message
@@ -3556,6 +3566,11 @@ int monsters::res_fire() const
return (mons_res_fire(this));
}
+int monsters::res_steam() const
+{
+ return (mons_res_steam(this));
+}
+
int monsters::res_cold() const
{
return (mons_res_cold(this));
@@ -3707,12 +3722,12 @@ void monsters::set_ghost(const ghost_demon &g)
void monsters::pandemon_init()
{
- hit_dice = ghost->values[ GVAL_DEMONLORD_HIT_DICE ];
- hit_points = ghost->values[ GVAL_MAX_HP ];
- max_hit_points = ghost->values[ GVAL_MAX_HP ];
- ac = ghost->values[ GVAL_AC ];
- ev = ghost->values[ GVAL_EV ];
- speed = (one_chance_in(3) ? 10 : 6 + roll_dice(2, 9));
+ hit_dice = ghost->xl;
+ hit_points = ghost->max_hp;
+ max_hit_points = ghost->max_hp;
+ ac = ghost->ac;
+ ev = ghost->ev;
+ speed = (one_chance_in(3) ? 10 : 8 + roll_dice(2, 9));
speed_increment = 70;
if (you.char_direction == GDT_ASCENDING && you.level_type == LEVEL_DUNGEON)
colour = LIGHTRED;
@@ -3724,12 +3739,12 @@ void monsters::pandemon_init()
void monsters::ghost_init()
{
type = MONS_PLAYER_GHOST;
- hit_dice = ghost->values[ GVAL_EXP_LEVEL ];
- hit_points = ghost->values[ GVAL_MAX_HP ];
- max_hit_points = ghost->values[ GVAL_MAX_HP ];
- ac = ghost->values[ GVAL_AC];
- ev = ghost->values[ GVAL_EV ];
- speed = ghost->values[ GVAL_SPEED ];
+ hit_dice = ghost->xl;
+ hit_points = ghost->max_hp;
+ max_hit_points = ghost->max_hp;
+ ac = ghost->ac;
+ ev = ghost->ev;
+ speed = ghost->speed;
speed_increment = 70;
attitude = ATT_HOSTILE;
behaviour = BEH_WANDER;
@@ -3896,16 +3911,7 @@ void monsters::load_spells(mon_spellbook_type book)
#endif
if (book == MST_GHOST)
- {
- for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; i++)
- {
- spells[i] =
- static_cast<spell_type>( ghost->values[ GVAL_SPELL_1 + i ] );
-#if DEBUG_DIAGNOSTICS
- mprf( MSGCH_DIAGNOSTICS, "spell #%d: %d", i, spells[i] );
-#endif
- }
- }
+ spells = ghost->spells;
else
{
for (unsigned int i = 0; i < ARRAYSIZE(mspell_list); ++i)
@@ -3918,6 +3924,11 @@ void monsters::load_spells(mon_spellbook_type book)
}
}
}
+#if DEBUG_DIAGNOSTICS
+ for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; i++)
+ mprf( MSGCH_DIAGNOSTICS, "Spell #%d: %d (%s)",
+ i, spells[i], spell_title(spells[i]) );
+#endif
}
bool monsters::has_ench(enchant_type ench) const
@@ -4588,12 +4599,12 @@ void monsters::apply_enchantment(const mon_enchant &me)
}
// Now we handle the others:
- int grid = grd[x][y];
+ const dungeon_feature_type grid = grd[x][y];
// Badly injured monsters prefer to stay submerged...
// electrical eels and lava snakes have ranged attacks
// and are more likely to surface. -- bwr
- if (!monster_can_submerge(type, grid))
+ if (!monster_can_submerge(this, grid))
del_ench(ENCH_SUBMERGED); // forced to surface
else if (hit_points <= max_hit_points / 2)
break;
@@ -4658,10 +4669,8 @@ void monsters::apply_enchantment(const mon_enchant &me)
// assumption: mons_res_fire has already been checked
case ENCH_STICKY_FLAME:
{
- int dam = roll_dice( 2, 4 ) - 1;
-
- if (mons_res_fire( this ) < 0)
- dam += roll_dice( 2, 5 ) - 1;
+ int dam =
+ resist_adjust_damage(this, res_fire(), roll_dice( 2, 4 ) - 1);
if (dam > 0)
{
@@ -5002,7 +5011,7 @@ void monsters::apply_location_effects()
mons_check_pool(this);
if (alive() && has_ench(ENCH_SUBMERGED)
- && !monster_can_submerge(type, grd[x][y]))
+ && !monster_can_submerge(this, grd[x][y]))
{
del_ench(ENCH_SUBMERGED);
}
@@ -5430,7 +5439,7 @@ std::string do_mon_str_replacements(const std::string &in_msg,
if (mons_shouts(monster->type) >= NUM_SHOUTS)
{
mpr("Invalid @says@ type.", MSGCH_DIAGNOSTICS);
- msg = replace_all(msg, "@says@", "bugilly says");
+ msg = replace_all(msg, "@says@", "buggily says");
}
else
msg = replace_all(msg, "@says@",
@@ -5448,7 +5457,7 @@ static mon_body_shape get_ghost_shape(const monsters *mon)
{
const ghost_demon &ghost = *(mon->ghost);
- switch(ghost.values[GVAL_SPECIES])
+ switch (ghost.species)
{
case SP_NAGA:
return (MON_SHAPE_NAGA);
@@ -5472,9 +5481,10 @@ static mon_body_shape get_ghost_shape(const monsters *mon)
case SP_UNK1_DRACONIAN:
case SP_BASE_DRACONIAN:
return (MON_SHAPE_HUMANOID_TAILED);
- }
- return (MON_SHAPE_HUMANOID);
+ default:
+ return (MON_SHAPE_HUMANOID);
+ }
}
mon_body_shape get_mon_shape(const monsters *mon)
@@ -5706,3 +5716,71 @@ std::string get_mon_shape_str(const mon_body_shape shape)
return (shape_names[shape]);
}
+
+/////////////////////////////////////////////////////////////////////////
+// mon_resist_def
+
+mon_resist_def::mon_resist_def()
+ : elec(0), poison(0), fire(0), steam(0), cold(0), hellfire(0),
+ asphyx(0), acid(0), sticky_flame(false), pierce(0),
+ slice(0), bludgeon(0)
+{
+}
+
+mon_resist_def::mon_resist_def(int flags, short level)
+ : elec(0), poison(0), fire(0), steam(0), cold(0), hellfire(0),
+ asphyx(0), acid(0), sticky_flame(false), pierce(0),
+ slice(0), bludgeon(0)
+{
+ for (int i = 0; i < 32; ++i)
+ {
+ switch (flags & (1 << i))
+ {
+ case MR_RES_STEAM: steam = 3; break;
+ case MR_RES_ELEC: elec = level; break;
+ case MR_RES_POISON: poison = level; break;
+ case MR_RES_FIRE: fire = level; break;
+ case MR_RES_HELLFIRE: hellfire = level; break;
+ case MR_RES_COLD: cold = level; break;
+ case MR_RES_ASPHYX: asphyx = level; break;
+ case MR_RES_ACID: acid = level; break;
+ case MR_VUL_ELEC: elec = -level; break;
+ case MR_VUL_POISON: poison = -level; break;
+ case MR_VUL_FIRE: fire = -level; break;
+ case MR_VUL_COLD: cold = -level; break;
+
+ case MR_RES_PIERCE: pierce = level; break;
+ case MR_RES_SLICE: slice = level; break;
+ case MR_RES_BLUDGEON: bludgeon = level; break;
+ case MR_VUL_PIERCE: pierce = -level; break;
+ case MR_VUL_SLICE: slice = -level; break;
+ case MR_VUL_BLUDGEON: bludgeon = -level; break;
+
+ case MR_RES_STICKY_FLAME: sticky_flame = true; break;
+
+ default: break;
+ }
+ }
+}
+
+const mon_resist_def &mon_resist_def::operator |= (const mon_resist_def &o)
+{
+ elec += o.elec;
+ poison += o.poison;
+ fire += o.fire;
+ cold += o.cold;
+ hellfire += o.hellfire;
+ asphyx += o.asphyx;
+ acid += o.acid;
+ pierce += o.pierce;
+ slice += o.slice;
+ bludgeon += o.bludgeon;
+ sticky_flame = sticky_flame || o.sticky_flame;
+ return (*this);
+}
+
+mon_resist_def mon_resist_def::operator | (const mon_resist_def &o) const
+{
+ mon_resist_def c(*this);
+ return (c |= o);
+}
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 4877271260..9aaccb551e 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -201,7 +201,11 @@ enum mon_resist_flags
MR_VUL_PIERCE = (1<<14),
MR_VUL_SLICE = (1<<15),
- MR_VUL_BLUDGEON = (1<<16)
+ MR_VUL_BLUDGEON = (1<<16),
+
+ // immune to stickiness of sticky flame.
+ MR_RES_STICKY_FLAME = (1 << 17),
+ MR_RES_STEAM = (1 << 18)
};
enum shout_type
@@ -275,6 +279,37 @@ struct mon_energy_usage
char pickup_percent;
};
+struct mon_resist_def
+{
+ // All values are actually saved as single-bytes, so practical
+ // range is -128 - 127, and the game only distinguishes values in
+ // the range -1 to 3.
+
+ short elec;
+ short poison;
+ short fire;
+ short steam;
+ short cold;
+ short hellfire;
+ short asphyx;
+ short acid;
+
+ bool sticky_flame;
+
+ // Physical damage resists (currently unused)
+ short pierce;
+ short slice;
+ short bludgeon;
+
+ mon_resist_def();
+ mon_resist_def(int flags, short level = 1);
+
+ mon_resist_def operator | (const mon_resist_def &other) const;
+ const mon_resist_def &operator |= (const mon_resist_def &other);
+};
+
+typedef mon_resist_def mrd;
+
struct monsterentry
{
short mc; // monster number
@@ -283,7 +318,7 @@ struct monsterentry
const char *name;
unsigned long bitfields;
- unsigned long resists;
+ mon_resist_def resists;
short weight;
// [Obsolete] Experience used to be calculated like this:
@@ -446,35 +481,18 @@ bool mons_is_summoned(const monsters *m);
* *********************************************************************** */
mon_intel_type mons_intel(int mc);
-habitat_type mons_habitat(int mc);
+// Use mons_habitat(const monster *) wherever possible since the other
+// variant does not handle zombies correctly.
+habitat_type mons_habitat(const monsters *m);
+habitat_type mons_habitat_by_type(int mc);
bool intelligent_ally(const monsters *mon);
-// last updated 12may2000 {dlb}
-/* ***********************************************************************
- * called from: beam - fight - monstuff
- * *********************************************************************** */
+bool mons_res_sticky_flame( const monsters *mon );
int mons_res_cold( const monsters *mon );
-
-
-// last updated 12may2000 {dlb}
-/* ***********************************************************************
- * called from: beam - fight - spells4
- * *********************************************************************** */
int mons_res_elec( const monsters *mon );
-
-
-// last updated 12may2000 {dlb}
-/* ***********************************************************************
- * called from: beam - fight - monstuff
- * *********************************************************************** */
int mons_res_fire( const monsters *mon );
-
-
-// last updated 12may2000 {dlb}
-/* ***********************************************************************
- * called from: beam - monstuff - spells4
- * *********************************************************************** */
+int mons_res_steam( const monsters *mon );
int mons_res_poison( const monsters *mon );
int mons_res_acid( const monsters *mon );
int mons_res_negative_energy( const monsters *mon );
@@ -509,7 +527,8 @@ int mons_speed(int mclass);
* called from: dungeon - mon-util - spells2
* *********************************************************************** */
int mons_zombie_size(int mc);
-
+int mons_zombie_base(const monsters *monster);
+bool mons_is_zombified(const monsters *monster);
// last updated 12may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index c2485d3824..ceec4e4890 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -15,6 +15,7 @@
#include "branch.h"
#include "externs.h"
+#include "ghost.h"
#include "lev-pand.h"
#include "makeitem.h"
#include "monstuff.h"
@@ -77,7 +78,9 @@ bool grid_compatible(dungeon_feature_type grid_wanted,
bool monster_habitable_grid(const monsters *m,
dungeon_feature_type actual_grid)
{
- return (monster_habitable_grid(m->type, actual_grid, mons_flies(m),
+ // Zombified monsters enjoy the same habitat as their original.
+ const int type = mons_is_zombified(m)? mons_zombie_base(m) : m->type;
+ return (monster_habitable_grid(type, actual_grid, mons_flies(m),
m->paralysed()));
}
@@ -101,7 +104,7 @@ bool monster_habitable_grid(int monster_class,
bool paralysed)
{
const dungeon_feature_type preferred_habitat =
- habitat2grid( mons_habitat(monster_class) );
+ habitat2grid( mons_habitat_by_type(monster_class) );
return (grid_compatible(preferred_habitat, actual_grid)
// [dshaligram] Flying creatures are all DNGN_FLOOR, so we
// only have to check for the additional valid grids of deep
@@ -124,22 +127,20 @@ bool monster_habitable_grid(int monster_class,
}
// Returns true if the monster can submerge in the given grid
-bool monster_can_submerge(int monster_class, int grid)
+bool monster_can_submerge(const monsters *mons, dungeon_feature_type grid)
{
- const habitat_type habitat = mons_habitat(monster_class);
-
- if (habitat == HT_WATER &&
- (grid == DNGN_DEEP_WATER || grid == DNGN_BLUE_FOUNTAIN))
+ switch (mons_habitat(mons))
{
- return true;
- }
+ case HT_WATER:
+ // Monsters can submerge in shallow water - this is intentional.
+ return grid_is_watery(grid);
- if (habitat == HT_LAVA && grid == DNGN_LAVA)
- {
- return true;
- }
+ case HT_LAVA:
+ return (grid == DNGN_LAVA);
- return false;
+ default:
+ return false;
+ }
}
static bool need_super_ood(int lev_mons)
@@ -485,7 +486,8 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
// a) not occupied
// b) compatible
// c) in the 'correct' proximity to the player
- dungeon_feature_type grid_wanted = habitat2grid( mons_habitat(mon_type) );
+ dungeon_feature_type grid_wanted =
+ habitat2grid( mons_habitat_by_type(mon_type) );
while(true)
{
// handled above, won't change anymore
@@ -689,7 +691,7 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target,
}
else
{
- grid_wanted = habitat2grid( mons_habitat(mon_type) );
+ grid_wanted = habitat2grid( mons_habitat_by_type(mon_type) );
// we'll try 1000 times for a good spot
for (i = 0; i < 1000; i++)
@@ -773,7 +775,7 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target,
menv[id].flags |= MF_BATTY;
}
- if (monster_can_submerge(mon_type, grd[fx][fy])
+ if (monster_can_submerge(&menv[id], grd[fx][fy])
&& !one_chance_in(5))
menv[id].add_ench(ENCH_SUBMERGED);
@@ -1570,8 +1572,9 @@ coord_def find_newmons_square(int mons_class, int x, int y)
if (mons_class == WANDERING_MONSTER)
mons_class = RANDOM_MONSTER;
- dungeon_feature_type spcw = ((mons_class == RANDOM_MONSTER) ? DNGN_FLOOR
- : habitat2grid( mons_habitat(mons_class) ));
+ dungeon_feature_type spcw =
+ ((mons_class == RANDOM_MONSTER) ? DNGN_FLOOR
+ : habitat2grid( mons_habitat_by_type(mons_class) ));
// 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
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index 2b318710ef..0bf912b5d5 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -180,7 +180,7 @@ bool monster_habitable_grid(int monster_class,
dungeon_feature_type actual_grid,
int flies = -1,
bool paralysed = false);
-bool monster_can_submerge(int monster_class, int grid);
+bool monster_can_submerge(const monsters *mons, dungeon_feature_type grid);
coord_def find_newmons_square(int mons_class, int x, int y);
void spawn_random_monsters();
diff --git a/crawl-ref/source/monspeak.cc b/crawl-ref/source/monspeak.cc
index f1230a6fbd..dbf428ed2a 100644
--- a/crawl-ref/source/monspeak.cc
+++ b/crawl-ref/source/monspeak.cc
@@ -26,6 +26,7 @@
#include "database.h"
#include "debug.h"
#include "fight.h"
+#include "ghost.h"
#include "insult.h"
#include "itemname.h"
#include "message.h"
@@ -127,7 +128,7 @@ static std::string player_ghost_speak_str(const monsters *monster,
const std::vector<std::string> prefixes)
{
const ghost_demon &ghost = *(monster->ghost);
- std::string ghost_class = get_class_name(ghost.values[GVAL_CLASS]);
+ std::string ghost_class = get_class_name(ghost.job);
std::string prefix = "";
for (int i = 0, size = prefixes.size(); i < size; i++)
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index cf8ddec129..7dce081e7a 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -38,6 +38,7 @@
#include "describe.h"
#include "dgnevent.h"
#include "fight.h"
+#include "ghost.h"
#include "hiscores.h"
#include "it_use2.h"
#include "itemname.h"
@@ -1885,7 +1886,7 @@ static void handle_behaviour(monsters *mon)
mon->foe = you.pet_target;
}
- // instead berserkers attack nearest monsters
+ // instead berserkers attack nearest monsters.
if (mon->has_ench(ENCH_BERSERK)
&& (mon->foe == MHITNOT || isFriendly && mon->foe == MHITYOU))
{
@@ -2431,7 +2432,7 @@ static void handle_nearby_ability(monsters *monster)
mons_speaks(monster);
}
- if (monster_can_submerge(monster->type, grd[monster->x][monster->y])
+ if (monster_can_submerge(monster, grd[monster->x][monster->y])
&& ( !player_beheld_by(monster) // no submerging if player entranced
&& (one_chance_in(5)
|| ((grid_distance( monster->x, monster->y,
@@ -2492,7 +2493,7 @@ static void handle_nearby_ability(monsters *monster)
break;
case MONS_PANDEMONIUM_DEMON:
- if (monster->ghost->values[ GVAL_DEMONLORD_CYCLE_COLOUR ])
+ if (monster->ghost->cycle_colours)
monster->colour = random_colour();
break;
@@ -3676,7 +3677,7 @@ static bool handle_spell( monsters *monster, bolt & beem )
return (false);
}
else if (monster->type == MONS_PANDEMONIUM_DEMON
- && !monster->ghost->values[ GVAL_DEMONLORD_SPELLCASTER ])
+ && !monster->ghost->spellcaster)
{
return (false);
}
@@ -4134,7 +4135,7 @@ static void monster_regenerate(monsters *monster)
return;
// Non-land creatures out of their element cannot regenerate.
- if (mons_habitat(monster->type) != HT_LAND
+ if (mons_habitat(monster) != HT_LAND
&& !monster_habitable_grid(monster, grd(monster->pos())))
{
return;
@@ -4324,7 +4325,7 @@ static void handle_monster_move(int i, monsters *monster)
handle_behaviour(monster);
// submerging monsters will hide from clouds
- if (monster_can_submerge(monster->type, grd[monster->x][monster->y])
+ if (monster_can_submerge(monster, grd[monster->x][monster->y])
&& env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
{
monster->add_ench(ENCH_SUBMERGED);
@@ -4988,7 +4989,7 @@ void mons_check_pool(monsters *mons, killer_type killer, int killnum)
mons->name(DESC_CAP_THE).c_str(),
(grid == DNGN_LAVA ? "lava" : "water"));
- if (grid == DNGN_LAVA && mons_res_fire(mons) > 0)
+ if (grid == DNGN_LAVA && mons_res_fire(mons) >= 2)
grid = DNGN_DEEP_WATER;
// Even fire resistant monsters perish in lava, but undead can survive
@@ -5025,68 +5026,45 @@ void mons_check_pool(monsters *mons, killer_type killer, int killnum)
// returns true for monsters that obviously (to the player) feel
// "thematically at home" in a branch
// currently used for native monsters recognizing traps
-static bool is_native_in_branch(const monsters *monster, const branch_type branch)
+static bool is_native_in_branch(const monsters *monster,
+ const branch_type branch)
{
switch (branch)
{
- case BRANCH_ELVEN_HALLS:
- if (mons_species(monster->type) == MONS_ELF)
- return true;
- return false;
+ case BRANCH_ELVEN_HALLS:
+ return (mons_species(monster->type) == MONS_ELF);
- case BRANCH_ORCISH_MINES:
- if (mons_species(monster->type) == MONS_ORC)
- return true;
- return false;
+ case BRANCH_ORCISH_MINES:
+ return (mons_species(monster->type) == MONS_ORC);
- case BRANCH_SHOALS:
- if (mons_species(monster->type) == MONS_CYCLOPS
+ case BRANCH_SHOALS:
+ return (mons_species(monster->type) == MONS_CYCLOPS
|| mons_species(monster->type) == MONS_MERFOLK
- || mons_species(monster->type) == MONS_MERMAID)
- {
- return true;
- }
- return false;
+ || mons_species(monster->type) == MONS_MERMAID);
- case BRANCH_SLIME_PITS:
- if (mons_species(monster->type) == MONS_JELLY)
- return true;
- return false;
+ case BRANCH_SLIME_PITS:
+ return (mons_species(monster->type) == MONS_JELLY);
- case BRANCH_SNAKE_PIT:
- if (mons_species(monster->type) == MONS_NAGA
- || mons_species(monster->type) == MONS_SNAKE)
- {
- return true;
- }
- return false;
+ case BRANCH_SNAKE_PIT:
+ return (mons_species(monster->type) == MONS_NAGA
+ || mons_species(monster->type) == MONS_SNAKE);
- case BRANCH_HALL_OF_ZOT:
- if (mons_species(monster->type) == MONS_DRACONIAN)
- return true;
- return false;
+ case BRANCH_HALL_OF_ZOT:
+ return (mons_species(monster->type) == MONS_DRACONIAN);
- case BRANCH_TOMB:
- if (mons_species(monster->type) == MONS_MUMMY)
- return true;
- return false;
+ case BRANCH_TOMB:
+ return (mons_species(monster->type) == MONS_MUMMY);
- case BRANCH_HIVE:
- if (monster->type == MONS_KILLER_BEE_LARVA
+ case BRANCH_HIVE:
+ return (monster->type == MONS_KILLER_BEE_LARVA
|| monster->type == MONS_KILLER_BEE
- || monster->type == MONS_QUEEN_BEE)
- {
- return true;
- }
- return false;
+ || monster->type == MONS_QUEEN_BEE);
- case BRANCH_HALL_OF_BLADES:
- if (monster->type == MONS_DANCING_WEAPON)
- return true;
- return false;
+ case BRANCH_HALL_OF_BLADES:
+ return (monster->type == MONS_DANCING_WEAPON);
- default:
- return false;
+ default:
+ return false;
}
}
@@ -5268,7 +5246,7 @@ bool mon_can_move_to_pos(const monsters *monster, const int count_x,
}
const dungeon_feature_type target_grid = grd[targ_x][targ_y];
- const habitat_type habitat = mons_habitat(monster->type);
+ const habitat_type habitat = mons_habitat(monster);
// effectively slows down monster movement across water.
// Fire elementals can't cross at all.
@@ -5405,7 +5383,7 @@ bool mon_can_move_to_pos(const monsters *monster, const int count_x,
return (mons_res_miasma(monster) > 0);
case CLOUD_FIRE:
- if (mons_res_fire(monster) > 0)
+ if (mons_res_fire(monster) > 1)
return true;
if (monster->hit_points >= 15 + random2avg(46, 5))
@@ -5422,7 +5400,7 @@ bool mon_can_move_to_pos(const monsters *monster, const int count_x,
break;
case CLOUD_COLD:
- if (mons_res_cold(monster) > 0)
+ if (mons_res_cold(monster) > 1)
return true;
if (monster->hit_points >= 15 + random2avg(46, 5))
@@ -5469,7 +5447,7 @@ static bool monster_move(monsters *monster)
int count_x, count_y, count;
int okmove = DNGN_SHALLOW_WATER; // what does this actually do?
- const habitat_type habitat = mons_habitat(monster->type);
+ const habitat_type habitat = mons_habitat(monster);
bool deep_water_available = false;
// Berserking monsters make a lot of racket
@@ -5917,15 +5895,11 @@ static void mons_in_cloud(monsters *monster)
simple_monster_message(monster, " is engulfed in flame!");
- if (mons_res_fire(monster) > 0)
- return;
-
- hurted += ((random2avg(16, 3) + 6) * 10) / speed;
-
- if (mons_res_fire(monster) < 0)
- hurted += (random2(15) * 10) / speed;
+ hurted +=
+ resist_adjust_damage( monster,
+ monster->res_fire(),
+ ((random2avg(16, 3) + 6) * 10) / speed );
- // remember that the above is in addition to the other you.damage.
hurted -= random2(1 + monster->ac);
break; // to damage routine at end {dlb}
@@ -5949,15 +5923,11 @@ static void mons_in_cloud(monsters *monster)
case CLOUD_COLD:
simple_monster_message(monster, " is engulfed in freezing vapours!");
- if (mons_res_cold(monster) > 0)
- return;
-
- hurted += ((6 + random2avg(16, 3)) * 10) / speed;
+ hurted +=
+ resist_adjust_damage( monster,
+ monster->res_cold(),
+ ((6 + random2avg(16, 3)) * 10) / speed );
- if (mons_res_cold(monster) < 0)
- hurted += (random2(15) * 10) / speed;
-
- // remember that the above is in addition to the other damage.
hurted -= random2(1 + monster->ac);
break; // to damage routine at end {dlb}
@@ -5987,14 +5957,12 @@ static void mons_in_cloud(monsters *monster)
simple_monster_message(monster, " is engulfed in steam!");
- if (mons_res_fire(monster) > 0)
- return;
-
const int steam_base_damage = steam_cloud_damage(cloud);
- hurted += (random2avg(steam_base_damage, 2) * 10) / speed;
-
- if (mons_res_fire(monster) < 0)
- hurted += (random2(steam_base_damage / 2 + 1) * 10) / speed;
+ hurted +=
+ resist_adjust_damage(
+ monster,
+ monster->res_steam(),
+ (random2avg(steam_base_damage, 2) * 10) / speed);
hurted -= random2(1 + monster->ac);
break; // to damage routine at end {dlb}
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index 2d28cd9465..2740c81c40 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -923,11 +923,18 @@ static std::string morgue_name(time_t when_crawl_got_even)
#endif // SHORT_FILE_NAMES
}
-void end_game( struct scorefile_entry &se )
+void end_game( scorefile_entry &se )
{
- int i;
bool dead = true;
+ if (!dump_char( morgue_name(se.death_time), !dead, true, &se ))
+ {
+ mpr("Char dump unsuccessful! Sorry about that.");
+ if (!crawl_state.seen_hups)
+ more();
+ clrscr();
+ }
+
if (se.death_type == KILLED_BY_LEAVING ||
se.death_type == KILLED_BY_QUITTING ||
se.death_type == KILLED_BY_WINNING)
@@ -975,7 +982,7 @@ void end_game( struct scorefile_entry &se )
const int num_suffixes = sizeof(suffixes) / sizeof(const char*);
- for ( i = 0; i < num_suffixes; ++i ) {
+ for (int i = 0; i < num_suffixes; ++i) {
std::string tmpname = basename + suffixes[i];
unlink( tmpname.c_str() );
}
@@ -1000,10 +1007,10 @@ void end_game( struct scorefile_entry &se )
if (!crawl_state.seen_hups)
more();
- for (i = 0; i < ENDOFPACK; i++)
+ for (int i = 0; i < ENDOFPACK; i++)
set_ident_flags( you.inv[i], ISFLAG_IDENT_MASK );
- for (i = 0; i < ENDOFPACK; i++)
+ for (int i = 0; i < ENDOFPACK; i++)
{
if (you.inv[i].base_type != 0)
{
@@ -1016,14 +1023,6 @@ void end_game( struct scorefile_entry &se )
textcolor( LIGHTGREY );
clrscr();
- if (!dump_char( morgue_name(se.death_time), !dead, true, &se ))
- {
- mpr("Char dump unsuccessful! Sorry about that.");
- if (!crawl_state.seen_hups)
- more();
- clrscr();
- }
-
clrscr();
cprintf( "Goodbye, %s.", you.your_name );
cprintf( EOL EOL " " ); // Space padding where # would go in list format
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index bb2c592c7d..bc8348e39f 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -5152,6 +5152,12 @@ actor::~actor()
{
}
+bool actor::has_equipped(equipment_type eq, int sub_type) const
+{
+ const item_def *item = slot_item(eq);
+ return (item && item->sub_type == sub_type);
+}
+
bool actor::will_trigger_shaft() const
{
return (!airborne() && total_weight() > 0 && is_valid_shaft_level());
@@ -5674,11 +5680,6 @@ item_def *player::slot_item(equipment_type eq)
return (item == -1? NULL : &inv[item]);
}
-const item_def *player::slot_item(equipment_type eq) const
-{
- return const_cast<player*>(this)->slot_item(eq);
-}
-
// Returns the item in the player's weapon slot.
item_def *player::weapon(int /* which_attack */)
{
@@ -5718,6 +5719,11 @@ int player::id() const
return (-1);
}
+int player::get_experience_level() const
+{
+ return (experience_level);
+}
+
bool player::alive() const
{
// Simplistic, but if the player dies the game is over anyway, so
@@ -5941,6 +5947,11 @@ int player::res_fire() const
return (player_res_fire());
}
+int player::res_steam() const
+{
+ return (player_res_steam());
+}
+
int player::res_cold() const
{
return (player_res_cold());
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index c962301856..041429135a 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -75,6 +75,7 @@
#include "enum.h"
#include "externs.h"
#include "files.h"
+#include "ghost.h"
#include "itemname.h"
#include "itemprop.h"
#include "mapmark.h"
@@ -132,6 +133,13 @@ static void tag_read_ghost(tagHeader &th, char minorVersion);
static void marshallGhost(tagHeader &th, const ghost_demon &ghost);
static ghost_demon unmarshallGhost( tagHeader &th );
+
+static void marshallResists(tagHeader &, const mon_resist_def &);
+static void unmarshallResists(tagHeader &, mon_resist_def &);
+
+static void marshallSpells(tagHeader &, const monster_spells &);
+static void unmarshallSpells(tagHeader &, monster_spells &);
+
static void marshall_monster(tagHeader &th, const monsters &m);
static void unmarshall_monster(tagHeader &th, monsters &m);
@@ -1757,9 +1765,7 @@ static void marshall_monster(tagHeader &th, const monsters &m)
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]);
-
+ marshallSpells(th, m.spells);
marshallByte(th, m.god);
if (m.type == MONS_PLAYER_GHOST || m.type == MONS_PANDEMONIUM_DEMON)
@@ -2022,8 +2028,7 @@ static void unmarshall_monster(tagHeader &th, monsters &m)
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] = static_cast<spell_type>( unmarshallShort(th) );
+ unmarshallSpells(th, m.spells);
m.god = (god_type) unmarshallByte(th);
@@ -2210,24 +2215,74 @@ static void tag_missing_level_tiles()
// ------------------------------- ghost tags ---------------------------- //
-static void marshallGhost(tagHeader &th, const ghost_demon &ghost)
+static void marshallResists(tagHeader &th, const mon_resist_def &res)
{
- marshallString(th, ghost.name.c_str(), 20);
+ marshallByte(th, res.elec);
+ marshallByte(th, res.poison);
+ marshallByte(th, res.fire);
+ marshallByte(th, res.steam);
+ marshallByte(th, res.cold);
+ marshallByte(th, res.hellfire);
+ marshallByte(th, res.asphyx);
+ marshallByte(th, res.acid);
+ marshallByte(th, res.sticky_flame);
+ marshallByte(th, res.pierce);
+ marshallByte(th, res.slice);
+ marshallByte(th, res.bludgeon);
+}
- // how many ghost values?
- marshallByte(th, NUM_GHOST_VALUES);
+static void unmarshallResists(tagHeader &th, mon_resist_def &res)
+{
+ res.elec = unmarshallByte(th);
+ res.poison = unmarshallByte(th);
+ res.fire = unmarshallByte(th);
+ res.steam = unmarshallByte(th);
+ res.cold = unmarshallByte(th);
+ res.hellfire = unmarshallByte(th);
+ res.asphyx = unmarshallByte(th);
+ res.acid = unmarshallByte(th);
+ res.sticky_flame = unmarshallByte(th);
+ res.pierce = unmarshallByte(th);
+ res.slice = unmarshallByte(th);
+ res.bludgeon = unmarshallByte(th);
+}
- for (int i = 0; i < NUM_GHOST_VALUES; i++)
- marshallShort( th, ghost.values[i] );
+static void marshallSpells(tagHeader &th, const monster_spells &spells)
+{
+ for (int j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j)
+ marshallShort(th, spells[j]);
}
-static void tag_construct_ghost(tagHeader &th)
+static void unmarshallSpells(tagHeader &th, monster_spells &spells)
{
- // How many ghosts?
- marshallShort(th, ghosts.size());
+ for (int j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j)
+ spells[j] = static_cast<spell_type>( unmarshallShort(th) );
+}
- for (int i = 0, size = ghosts.size(); i < size; ++i)
- marshallGhost(th, ghosts[i]);
+static void marshallGhost(tagHeader &th, const ghost_demon &ghost)
+{
+ marshallString(th, ghost.name.c_str(), 20);
+
+ marshallShort(th, ghost.species);
+ marshallShort(th, ghost.job);
+ marshallShort(th, ghost.best_skill);
+ marshallShort(th, ghost.best_skill_level);
+ marshallShort(th, ghost.xl);
+ marshallShort(th, ghost.max_hp);
+ marshallShort(th, ghost.ev);
+ marshallShort(th, ghost.ac);
+ marshallShort(th, ghost.damage);
+ marshallShort(th, ghost.speed);
+ marshallByte(th, ghost.see_invis);
+ marshallShort(th, ghost.brand);
+
+ marshallResists(th, ghost.resists);
+
+ marshallByte(th, ghost.spellcaster);
+ marshallByte(th, ghost.cycle_colours);
+ marshallShort(th, ghost.fly);
+
+ marshallSpells(th, ghost.spells);
}
static ghost_demon unmarshallGhost( tagHeader &th )
@@ -2236,18 +2291,39 @@ static ghost_demon unmarshallGhost( tagHeader &th )
ghost.name = unmarshallString(th, 20);
- // how many ghost values?
- int count_c = unmarshallByte(th);
-
- if (count_c > NUM_GHOST_VALUES)
- count_c = NUM_GHOST_VALUES;
+ ghost.species = static_cast<species_type>( unmarshallShort(th) );
+ ghost.job = static_cast<job_type>( unmarshallShort(th) );
+ ghost.best_skill = static_cast<skill_type>( unmarshallShort(th) );
+ ghost.best_skill_level = unmarshallShort(th);
+ ghost.xl = unmarshallShort(th);
+ ghost.max_hp = unmarshallShort(th);
+ ghost.ev = unmarshallShort(th);
+ ghost.ac = unmarshallShort(th);
+ ghost.damage = unmarshallShort(th);
+ ghost.speed = unmarshallShort(th);
+ ghost.see_invis = unmarshallByte(th);
+ ghost.brand = static_cast<brand_type>( unmarshallShort(th) );
+
+ unmarshallResists(th, ghost.resists);
+
+ ghost.spellcaster = unmarshallByte(th);
+ ghost.cycle_colours = unmarshallByte(th);
+ ghost.fly = static_cast<flight_type>( unmarshallShort(th) );
+
+ unmarshallSpells(th, ghost.spells);
- for (int i = 0; i < count_c; i++)
- ghost.values[i] = unmarshallShort(th);
-
return (ghost);
}
+static void tag_construct_ghost(tagHeader &th)
+{
+ // How many ghosts?
+ marshallShort(th, ghosts.size());
+
+ for (int i = 0, size = ghosts.size(); i < size; ++i)
+ marshallGhost(th, ghosts[i]);
+}
+
static void tag_read_ghost(tagHeader &th, char minorVersion)
{
int nghosts = unmarshallShort(th);
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index cf22365b0a..f1a3deb2bc 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -48,6 +48,7 @@
#include "direct.h"
#include "dungeon.h"
#include "format.h"
+#include "ghost.h"
#include "initfile.h"
#include "itemprop.h"
#include "luadgn.h"
@@ -912,7 +913,7 @@ void handle_monster_shouts(monsters* monster, bool force)
else if (monster->type == MONS_PLAYER_GHOST)
{
const ghost_demon &ghost = *(monster->ghost);
- std::string ghost_class = get_class_name(ghost.values[GVAL_CLASS]);
+ std::string ghost_class = get_class_name(ghost.job);
key = ghost_class + " player ghost";