From 9f751c796fa4ca1c22e66d4f31f293c0ea1955b6 Mon Sep 17 00:00:00 2001 From: dolorous Date: Fri, 18 Sep 2009 06:52:42 +0000 Subject: Implement part of [2837033]: Randomize colors, resistances, and attack types/flavors for ugly things. They now use the ghost_demon struct, expanded to account for these characteristics. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@10709 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/dat/descript/monsters.txt | 4 +- crawl-ref/source/debug.cc | 5 +- crawl-ref/source/describe.cc | 5 +- crawl-ref/source/externs.h | 3 +- crawl-ref/source/ghost.cc | 196 +++++++++++++++++++++++++++++ crawl-ref/source/ghost.h | 6 + crawl-ref/source/mgrow.cc | 11 ++ crawl-ref/source/mon-data.h | 12 +- crawl-ref/source/mon-util.cc | 35 +++++- crawl-ref/source/monplace.cc | 12 +- crawl-ref/source/stuff.cc | 16 +++ crawl-ref/source/stuff.h | 2 + crawl-ref/source/tags.cc | 13 ++ crawl-ref/source/tags.h | 3 +- 14 files changed, 301 insertions(+), 22 deletions(-) (limited to 'crawl-ref/source') diff --git a/crawl-ref/source/dat/descript/monsters.txt b/crawl-ref/source/dat/descript/monsters.txt index 75fa132592..0e288ad2c7 100644 --- a/crawl-ref/source/dat/descript/monsters.txt +++ b/crawl-ref/source/dat/descript/monsters.txt @@ -1416,7 +1416,7 @@ A chattering and shrieking minor demon. %%%% ugly thing -An ugly thing. Yuck. +An ugly thing. According to legend, this mutated creature is the spawn of an otherworldly wizard's breeding experiment. Yuck. %%%% unseen horror @@ -1444,7 +1444,7 @@ A heavily armed and armoured guardian of the Vaults. %%%% very ugly thing -A very ugly thing. Double yuck. +A very ugly thing. According to legend, this hideously mutated creature is the spawn of an otherworldly wizard's breeding experiment. Double yuck. %%%% wandering mushroom diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index 44911b0945..0077837804 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -2722,8 +2722,9 @@ void debug_stethoscope(int mon) { ASSERT(mons.ghost.get()); const ghost_demon &ghost = *mons.ghost; - mprf(MSGCH_DIAGNOSTICS, "Ghost damage: %d; brand: %d", - ghost.damage, ghost.brand); + mprf(MSGCH_DIAGNOSTICS, "Ghost damage: %d; brand: %d; att_type: %d; " + "att_flav: %d", + ghost.damage, ghost.brand, ghost.att_type, ghost.att_flav); } } diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index c738b23d72..d5c8a27200 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -2705,8 +2705,9 @@ static std::string _monster_stat_description(const monsters& mon) } // Can the monster levitate/fly? - // This doesn't give anything away since all ghosts can fly, and - // for demons it's already mentioned in their flavour description. + // This doesn't give anything away since no (very) ugly things can + // fly, all ghosts can fly, and for demons it's already mentioned in + // their flavour description. const flight_type fly = mons_flies(&mon, false); if (fly != FL_NONE) diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 4b53327a4c..c310ce8d7c 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -1361,9 +1361,10 @@ public: bool find_home_around(const coord_def &c, int radius); bool find_home_anywhere(); - void set_ghost(const ghost_demon &ghost); + void set_ghost(const ghost_demon &ghost, bool has_name = true); void ghost_init(); void pandemon_init(); + void uglything_init(); void destroy_inventory(); void load_spells(mon_spellbook_type spellbook); diff --git a/crawl-ref/source/ghost.cc b/crawl-ref/source/ghost.cc index 52fd438f26..8197b89c21 100644 --- a/crawl-ref/source/ghost.cc +++ b/crawl-ref/source/ghost.cc @@ -24,6 +24,7 @@ REVISION("$Rev$"); #include "place.h" #include "player.h" #include "religion.h" +#include "view.h" #include #define MAX_GHOST_DAMAGE 50 @@ -138,9 +139,12 @@ void ghost_demon::reset() speed = 10; see_invis = false; brand = SPWPN_NORMAL; + att_type = AT_HIT; + att_flav = AF_PLAIN; resists = mon_resist_def(); spellcaster = false; cycle_colours = false; + colour = BLACK; fly = FL_NONE; } @@ -219,6 +223,8 @@ void ghost_demon::init_random_demon() // Does demon cycle colours? cycle_colours = one_chance_in(10); + colour = random_colour(); + spells.init(SPELL_NO_SPELL); // This bit uses the list of player spells to find appropriate @@ -387,11 +393,201 @@ void ghost_demon::init_player_ghost() best_skill_level = you.skills[best_skill]; xl = you.experience_level; + colour = mons_class_colour(MONS_PLAYER_GHOST); fly = mons_class_flies(MONS_PLAYER_GHOST); add_spells(); } +static unsigned char _ugly_thing_random_colour() +{ + const unsigned char colours[] = + { + CYAN, GREEN, RED, LIGHTGREY, BROWN, MAGENTA + }; + + return (colours[random2(sizeof(colours) / sizeof(*colours))]); +} + +static mon_attack_flavour _ugly_thing_colour_to_flavour(unsigned char u_colour) +{ + mon_attack_flavour u_att_flav = AF_PLAIN; + + switch (u_colour) + { + case CYAN: + u_att_flav = AF_ELEC; + break; + + case GREEN: + u_att_flav = AF_POISON; + break; + + case RED: + u_att_flav = AF_FIRE; + break; + + case LIGHTGREY: + u_att_flav = AF_COLD; + break; + + case BROWN: + u_att_flav = AF_ACID; + break; + + case MAGENTA: + u_att_flav = AF_DISEASE; + break; + + default: + break; + } + + return (u_att_flav); +} + +static mon_attack_flavour _ugly_thing_flavour_upgrade(mon_attack_flavour u_att_flav) +{ + switch (u_att_flav) + { + case AF_POISON: + u_att_flav = AF_POISON_MEDIUM; + break; + + case AF_FIRE: + u_att_flav = AF_NAPALM; + break; + + case AF_DISEASE: + u_att_flav = AF_ROT; + break; + + default: + break; + } + + return (u_att_flav); +} + +void ghost_demon::init_ugly_thing(bool very_ugly) +{ + // Midpoint: 10, as in mon-data.h. + speed = 9 + random2(3); + + // Midpoint: 10, as in mon-data.h. + ev = 9 + random2(3); + + // Midpoint: 3, as in mon-data.h. + ac = 2 + random2(3); + + // Midpoint: 12, as in mon-data.h. + damage = 11 + random2(3); + + // Experience level: 8, the same as in mon-data.h. + xl = 8; + + // Hit dice: {8, 3, 5, 0}, the same as in mon-data.h. + max_hp = hit_points(xl, 3, 5); + + resists.elec = 0; + resists.poison = 0; + resists.fire = 0; + resists.cold = 0; + resists.acid = 0; + resists.sticky_flame = false; + + // An ugly thing gets one random resistance. + ugly_thing_add_resistance(); + + const mon_attack_type att_types[] = + { + AT_BITE, AT_STING, AT_CLAW, AT_PUNCH, AT_KICK, AT_TENTACLE_SLAP, + AT_TAIL_SLAP, AT_BUTT + }; + + att_type = att_types[random2(sizeof(att_types) / sizeof(*att_types))]; + + // An ugly thing always gets a low-intensity colour. + colour = _ugly_thing_random_colour(); + + // Pick a compatible attack flavour for this colour. + att_flav = _ugly_thing_colour_to_flavour(colour); + + // If this is a very ugly thing, upgrade it properly. + if (very_ugly) + ugly_thing_to_very_ugly_thing(); +} + +void ghost_demon::ugly_thing_to_very_ugly_thing() +{ + // Midpoint when added to an ugly thing: 4, as in mon-data.h. + ac++; + + // Midpoint when added to an ugly thing: 17, as in mon-data.h. + damage += 5; + + // Experience level when added to an ugly thing: 12, the same as in + // mon-data.h. + xl += 4; + + // Hit dice when added to an ugly thing: {12, 3, 5, 0}, the same as + // in mon-data.h. + max_hp += hit_points(4, 3, 5); + + // A very ugly thing always gets a high-intensity colour. + colour = make_high_colour(colour); + + // A very ugly thing sometimes gets a stronger attack flavour. + if (one_chance_in(3)) + att_flav = _ugly_thing_flavour_upgrade(att_flav); + + // A very ugly thing gets one more random resistance, and another + // possible resistance based on its stronger attack flavour. + ugly_thing_add_resistance(); +} + +void ghost_demon::ugly_thing_add_resistance() +{ + int base_rand = 6; + if (resists.sticky_flame) + base_rand--; + + switch (random2(base_rand)) + { + case 0: + resists.elec++; + break; + + case 1: + resists.poison++; + break; + + case 2: + resists.fire++; + break; + + case 3: + resists.cold++; + break; + + case 4: + resists.acid++; + break; + + case 5: + resists.sticky_flame = true; + break; + } + + // Guarantee certain resistances for stronger attack flavours. + if (att_flav == AF_POISON_MEDIUM && !resists.poison) + resists.poison++; + else if (att_flav == AF_ACID && !resists.acid) + resists.acid++; + else if (att_flav == AF_NAPALM && !resists.sticky_flame) + resists.sticky_flame = true; +} + static spell_type search_first_list(int ignore_spell) { for (unsigned i = 0; diff --git a/crawl-ref/source/ghost.h b/crawl-ref/source/ghost.h index d10a664c68..f7f9dafb96 100644 --- a/crawl-ref/source/ghost.h +++ b/crawl-ref/source/ghost.h @@ -31,9 +31,12 @@ public: short max_hp, ev, ac, damage, speed; bool see_invis; brand_type brand; + mon_attack_type att_type; + mon_attack_flavour att_flav; mon_resist_def resists; bool spellcaster, cycle_colours; + unsigned char colour; flight_type fly; monster_spells spells; @@ -43,6 +46,8 @@ public: void reset(); void init_random_demon(); void init_player_ghost(); + void init_ugly_thing(bool very_ugly); + void ugly_thing_to_very_ugly_thing(); public: static std::vector find_ghosts(); @@ -56,6 +61,7 @@ private: private: void add_spells(); spell_type translate_spell(spell_type playerspell) const; + void ugly_thing_add_resistance(); }; bool debug_check_ghosts(); diff --git a/crawl-ref/source/mgrow.cc b/crawl-ref/source/mgrow.cc index a1bd83cc4d..490c1ec308 100644 --- a/crawl-ref/source/mgrow.cc +++ b/crawl-ref/source/mgrow.cc @@ -10,6 +10,7 @@ REVISION("$Rev$"); #include "enum.h" +#include "ghost.h" #include "mgrow.h" #include "mon-util.h" #include "monstuff.h" @@ -138,6 +139,16 @@ void monsters::upgrade_type(monster_type after, bool adjust_hd, hit_points = std::min(hit_points, max_hit_points); } } + + // An ugly thing is the only ghost demon monster that can level up. + // If one has leveled up to a very ugly thing, upgrade it properly. + // + // XXX: There should be a better way to do this! + if (type == MONS_VERY_UGLY_THING) + { + ghost->ugly_thing_to_very_ugly_thing(); + uglything_init(); + } } bool monsters::level_up_change() diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index 342ad16205..0d46a78547 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -1357,9 +1357,9 @@ static monsterentry mondata[] = { // ugly things ('u') { - MONS_UGLY_THING, 'u', BROWN, "ugly thing", + MONS_UGLY_THING, 'u', BLACK, "ugly thing", M_WARM_BLOOD, - mrd(MR_RES_COLD, 2), + MR_NO_FLAGS, 600, 10, MONS_UGLY_THING, MONS_UGLY_THING, MH_NATURAL, -3, { {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 8, 3, 5, 0 }, @@ -1368,14 +1368,14 @@ static monsterentry mondata[] = { }, { - MONS_VERY_UGLY_THING, 'u', RED, "very ugly thing", + MONS_VERY_UGLY_THING, 'u', BLACK, "very ugly thing", M_WARM_BLOOD, - mrd(MR_RES_COLD, 2), + MR_NO_FLAGS, 750, 10, MONS_UGLY_THING, MONS_VERY_UGLY_THING, MH_NATURAL, -3, { {AT_HIT, AF_PLAIN, 17}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 12, 3, 5, 0 }, - 4, 8, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_BIG, S_ROAR, I_ANIMAL, - HT_AMPHIBIOUS_LAND, 8, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, MONEAT_NOTHING, SIZE_LARGE + 4, 10, MST_NO_SPELLS, CE_MUTAGEN_RANDOM, Z_BIG, S_ROAR, I_ANIMAL, + HT_AMPHIBIOUS_LAND, 10, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, MONEAT_NOTHING, SIZE_LARGE }, // vortices ('v') diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 0b59250376..14721142ff 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -588,6 +588,9 @@ bool mons_is_chaotic(const monsters *mon) if (mons_is_shapeshifter(mon)) return (true); + if (mon->type == MONS_UGLY_THING || mon->type == MONS_VERY_UGLY_THING) + return (true); + if (mon->has_spell(SPELL_POLYMORPH_OTHER)) return (true); @@ -869,7 +872,9 @@ shout_type mons_shouts(int mc, bool demon_shout) bool mons_is_ghost_demon(int mc) { - return (mc == MONS_PLAYER_GHOST + return (mc == MONS_UGLY_THING + || mc == MONS_VERY_UGLY_THING + || mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON); } @@ -1151,7 +1156,11 @@ mon_attack_def mons_attack_spec(const monsters *mon, int attk_number) if (mons_is_ghost_demon(mc)) { if (attk_number == 0) - return (mon_attack_def::attk(mon->ghost->damage)); + { + return (mon_attack_def::attk(mon->ghost->damage, + mon->ghost->att_type, + mon->ghost->att_flav)); + } return (mon_attack_def::attk(0, AT_NONE)); } @@ -6261,10 +6270,12 @@ void monsters::slow_down(actor *atk, int strength) enchant_monster_with_flavour(this, atk, BEAM_SLOW, strength); } -void monsters::set_ghost(const ghost_demon &g) +void monsters::set_ghost(const ghost_demon &g, bool has_name) { ghost.reset(new ghost_demon(g)); - mname = ghost->name; + + if (has_name) + mname = ghost->name; } void monsters::pandemon_init() @@ -6287,7 +6298,7 @@ void monsters::pandemon_init() if (you.char_direction == GDT_ASCENDING && you.level_type == LEVEL_DUNGEON) colour = LIGHTRED; else - colour = random_colour(); // demon's colour + colour = ghost->colour; load_spells(MST_GHOST); } @@ -6308,7 +6319,7 @@ void monsters::ghost_init() flags = MF_INTERESTING; foe = MHITNOT; foe_memory = 0; - colour = mons_class_colour(MONS_PLAYER_GHOST); + colour = ghost->colour; number = MONS_PROGRAM_BUG; load_spells(MST_GHOST); @@ -6319,6 +6330,18 @@ void monsters::ghost_init() find_place_to_live(); } +void monsters::uglything_init() +{ + 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; + colour = ghost->colour; +} + bool monsters::check_set_valid_home(const coord_def &place, coord_def &chosen, int &nvalid) const diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index a3022f0d4c..a3d1c326af 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -1237,8 +1237,16 @@ static int _place_monster_aux(const mgen_data &mg, } menv[id].foe = mg.foe; - // Initialise pandemonium demons. - if (menv[id].type == MONS_PANDEMONIUM_DEMON) + // Initialise (very) ugly things and pandemonium demons. + if (menv[id].type == MONS_UGLY_THING + || menv[id].type == MONS_VERY_UGLY_THING) + { + ghost_demon ghost; + ghost.init_ugly_thing(menv[id].type == MONS_VERY_UGLY_THING); + menv[id].set_ghost(ghost, false); + menv[id].uglything_init(); + } + else if (menv[id].type == MONS_PANDEMONIUM_DEMON) { ghost_demon ghost; ghost.init_random_demon(); diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index b9b55300eb..89ac13703f 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -1340,6 +1340,22 @@ unsigned char random_uncommon_colour() return (result); } +unsigned char make_low_colour(unsigned char colour) +{ + if (colour >= 8 && colour <= 15) + return (colour - 8); + + return (colour); +} + +unsigned char make_high_colour(unsigned char colour) +{ + if (colour >= 0 && colour <= 7) + return (colour + 8); + + return (colour); +} + // returns if a colour is one of the special element colours (ie not regular) bool is_element_colour( int col ) { diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h index 11a6cff013..aa3d51916e 100644 --- a/crawl-ref/source/stuff.h +++ b/crawl-ref/source/stuff.h @@ -194,6 +194,8 @@ bool player_can_hear(const coord_def& p); unsigned char random_colour(); unsigned char random_uncommon_colour(); +unsigned char make_low_colour(unsigned char colour); +unsigned char make_high_colour(unsigned char colour); bool is_element_colour( int col ); int element_colour( int element, bool no_random = false ); diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 5db90d707d..4d133247f1 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -2453,11 +2453,14 @@ static void marshallGhost(writer &th, const ghost_demon &ghost) marshallShort(th, ghost.speed); marshallByte(th, ghost.see_invis); marshallShort(th, ghost.brand); + marshallShort(th, ghost.att_type); + marshallShort(th, ghost.att_flav); marshallResists(th, ghost.resists); marshallByte(th, ghost.spellcaster); marshallByte(th, ghost.cycle_colours); + marshallByte(th, ghost.colour); marshallShort(th, ghost.fly); marshallSpells(th, ghost.spells); @@ -2486,10 +2489,20 @@ static ghost_demon unmarshallGhost(reader &th, char minorVersion) ghost.see_invis = unmarshallByte(th); ghost.brand = static_cast( unmarshallShort(th) ); + if (minorVersion >= TAG_MINOR_UGLY) + { + ghost.att_type = static_cast( unmarshallShort(th) ); + ghost.att_flav = static_cast( unmarshallShort(th) ); + } + unmarshallResists(th, ghost.resists); ghost.spellcaster = unmarshallByte(th); ghost.cycle_colours = unmarshallByte(th); + + if (minorVersion >= TAG_MINOR_UGLY) + ghost.colour = unmarshallByte(th); + ghost.fly = static_cast( unmarshallShort(th) ); unmarshallSpells(th, ghost.spells); diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h index 0535dbefad..4828196753 100644 --- a/crawl-ref/source/tags.h +++ b/crawl-ref/source/tags.h @@ -70,7 +70,8 @@ enum tag_minor_version TAG_MINOR_ZOT_OPEN = 18, // Remember whether Zot was opened. TAG_MINOR_JELLY = 19, // Remember whether the royal jelly is dead. TAG_ANNOTATE_EXCL = 20, // Store exclusion information for annotations. - TAG_MINOR_VERSION = 20 // Current version. (Keep equal to max.) + TAG_MINOR_UGLY = 21, // More ghost bits for (very) ugly things. + TAG_MINOR_VERSION = 21 // Current version. (Keep equal to max.) }; -- cgit v1.2.3-54-g00ecf