Skip to content

Commit

Permalink
Spirit Yak: new monster WIP
Browse files Browse the repository at this point in the history
Still to do:
- Reduce initial damage of spirit arrow to maybe 2/3
- Remove brands from spirit arrow too?
- Needs a more detailed descript of the status somewhere
- Rename spirit bolt -> spirit arrow
- Adjust yaml stats (based on death yak too closely)
- Review monster desc
- Overlay icon
- Remove debugs
- Different arrow loading message for invis mons
- Bands tailored to different places (like torpor snail)
  • Loading branch information
chucksellick committed Sep 28, 2024
1 parent 7cc9653 commit 0951d35
Show file tree
Hide file tree
Showing 37 changed files with 130 additions and 18 deletions.
4 changes: 2 additions & 2 deletions crawl-ref/source/actor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,8 @@ int actor::apply_ac(int damage, int max_damage, ac_type ac_rule, bool for_real)
die("invalid AC rule");
}

// We only support GDR for normal melee attacks at the moment.
// EVIL HACK: other callers of this function always pass 0 for max_damage,
// We only support GDR for normal melee or ranged monster attacks.
// EVIL HACK: other callers of this function pass 0 for max_damage,
// hence disabling GDR. This is very silly! We should do this better!
if (ac_rule == ac_type::normal)
saved = max(saved, min(gdr * max_damage / 100, div_rand_round(ac, 2)));
Expand Down
6 changes: 3 additions & 3 deletions crawl-ref/source/attack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,7 @@ int attack::adjusted_weapon_damage() const
return brand_adjust_weapon_damage(weapon_damage(), damage_brand, true);
}

int attack::calc_damage()
int attack::calc_damage(ac_type ac_rule)
{
if (stat_source().is_monster())
{
Expand Down Expand Up @@ -1003,7 +1003,7 @@ int attack::calc_damage()
damage = apply_damage_modifiers(damage);

set_attack_verb(damage);
return apply_defender_ac(damage, damage_max);
return apply_defender_ac(damage, damage_max, ac_rule);
}
else
{
Expand Down Expand Up @@ -1031,7 +1031,7 @@ int attack::calc_damage()
if (!defender->alive())
return 0;
damage = player_apply_final_multipliers(damage);
damage = apply_defender_ac(damage);
damage = apply_defender_ac(damage, 0, ac_rule);
damage = player_apply_postac_multipliers(damage);

damage = max(0, damage);
Expand Down
2 changes: 1 addition & 1 deletion crawl-ref/source/attack.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class attack
virtual int calc_mon_to_hit_base() = 0;
virtual int apply_damage_modifiers(int damage) = 0;
int apply_rev_penalty(int damage) const;
virtual int calc_damage();
virtual int calc_damage(ac_type ac_rule = ac_type::normal);
int lighting_effects();
int test_hit(int to_hit, int ev, bool randomise_ev);
int apply_defender_ac(int damage, int damage_max = 0,
Expand Down
8 changes: 8 additions & 0 deletions crawl-ref/source/colour.cc
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,14 @@ void init_element_colours()
{20, LIGHTGREEN},
{100, LIGHTGREY},
}));
add_element_colour(new random_element_colour_calc(
ETC_SPIRIT, "spirit",
{ {50, LIGHTCYAN},
{40, WHITE},
{30, CYAN},
{30, LIGHTBLUE},
{10, LIGHTGREY},
}));
// redefined by Lua later
add_element_colour(new element_colour_calc(
ETC_DISCO, "disco", _etc_random
Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/colour.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ enum element_type
ETC_CANDLES, // Ignis flickering candles
ETC_STEEL, // a brighter iron
ETC_GLITTER, // Klown pie decoration, all the bright colours
ETC_SPIRIT, // spirit yak and spirit arrow
ETC_DISCO = 96,
ETC_FIRST_LUA = ETC_DISCO, // colour indices have to be <128

Expand Down
10 changes: 10 additions & 0 deletions crawl-ref/source/dat/descript/monsters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2668,6 +2668,16 @@ sphinx
A fearsome hybrid with a woman's head, a lion's body and the wings of an eagle,
able to cloud the minds of its foes and wield fell magics.
%%%%
spirit yak

The ghostly apparition of a yak custodian known to guide its fallen kin on
their journey into the afterlife.

It manifests from time to time in this world to aid the living, bringing
with it a gift from the ancestors: bolts whittled from the wood of the Spirit
Tree, which will follow up any ranged hit and are able to partially ignore
the defences of the target.
%%%%
spriggan

A small humanoid, resembling a human or elf except for the size. It moves at a
Expand Down
17 changes: 17 additions & 0 deletions crawl-ref/source/dat/mons/spirit-yak.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: "spirit yak"
glyph: {char: "Y", colour: etc_spirit}
flags: [flies, insubstantial, herd, has_aura]
xp_mult: 18
genus: yak
holiness: [undead]
will: 120
attacks:
- {type: gore, damage: 30}
hd: 14
hp_10x: 770
ac: 9
ev: 5
shout: bellow
intelligence: animal
size: large
shape: quadruped
1 change: 1 addition & 0 deletions crawl-ref/source/enchant-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ enum enchant_type
ENCH_AMNESIA,
ENCH_CHARMER,
ENCH_REMOTE_CONTROL,
ENCH_SPIRIT_BOLT,
// Update enchant_names[] in mon-ench.cc when adding or removing
// enchantments.
NUM_ENCHANTMENTS
Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/item-prop-enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ enum missile_type
MI_BOOMERANG,

MI_SLUG,
MI_SPIRIT_ARROW,

NUM_MISSILES,
MI_NONE // was MI_EGGPLANT... used for launch type detection
Expand Down
3 changes: 3 additions & 0 deletions crawl-ref/source/item-prop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,7 @@ static const missile_def Missile_prop[] =
{ MI_ARROW, "arrow", 0, 1, 2 },
{ MI_BOLT, "bolt", 0, 1, 2 },
{ MI_SLUG, "slug", 0, 1, 2 },
{ MI_SPIRIT_ARROW, "spirit arrow", 0, 1, 2 },
{ MI_LARGE_ROCK, "large rock", 20, 25, 15 },
{ MI_SLING_BULLET, "sling bullet", 0, 1, 5 },
{ MI_JAVELIN, "javelin", 10, 20, 30 },
Expand Down Expand Up @@ -1056,6 +1057,7 @@ const set<pair<object_class_type, int> > removed_items =
{ OBJ_MISSILES, MI_BOLT },
{ OBJ_MISSILES, MI_SLING_BULLET },
{ OBJ_MISSILES, MI_SLUG },
{ OBJ_MISSILES, MI_SPIRIT_ARROW },
{ OBJ_GEMS, GEM_ORC },
#endif
{ OBJ_JEWELLERY, AMU_NOTHING }, // These should only spawn as uniques
Expand Down Expand Up @@ -2252,6 +2254,7 @@ bool is_launcher_ammo(const item_def &wpn)
case MI_BOLT:
case MI_SLING_BULLET:
case MI_SLUG:
case MI_SPIRIT_ARROW:
return true;
default:
return false;
Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/items.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3564,6 +3564,7 @@ colour_t item_def::missile_colour() const
case MI_BOLT: // removed as an item, but don't crash
case MI_SLING_BULLET: // removed as an item, but don't crash
case MI_SLUG: // never existed as an item
case MI_SPIRIT_ARROW: // never existed as an item
case MI_DART:
return WHITE;
case MI_JAVELIN:
Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/known-items.cc
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ void check_item_knowledge(bool unknown_items)
case MI_BOLT:
case MI_SLING_BULLET:
case MI_SLUG:
case MI_SPIRIT_ARROW:
continue;
}
#endif
Expand Down
4 changes: 2 additions & 2 deletions crawl-ref/source/melee-attack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4294,13 +4294,13 @@ int melee_attack::apply_damage_modifiers(int damage)
return damage;
}

int melee_attack::calc_damage()
int melee_attack::calc_damage(ac_type ac_rule)
{
// Constriction deals damage over time, not when grabbing.
if (attk_flavour == AF_CRUSH)
return 0;

return attack::calc_damage();
return attack::calc_damage(ac_rule);
}

/* TODO: This code is only used from melee_attack methods, but perhaps it
Expand Down
2 changes: 1 addition & 1 deletion crawl-ref/source/melee-attack.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class melee_attack : public attack
int weapon_damage() const override;
int calc_mon_to_hit_base() override;
int apply_damage_modifiers(int damage) override;
int calc_damage() override;
int calc_damage(ac_type ac_rule = ac_type::normal) override;
bool apply_damage_brand(const char *what = nullptr) override;

/* Attack effects */
Expand Down
24 changes: 22 additions & 2 deletions crawl-ref/source/mon-act.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,7 @@ static bool _handle_wand(monster& mons)
return true;
}

bool handle_throw(monster* mons, bolt & beem, bool teleport, bool check_only)
bool handle_throw(monster* mons, bolt& beem, bool teleport, bool check_only)
{
// Yes, there is a logic to this ordering {dlb}:
if (mons->incapacitated()
Expand Down Expand Up @@ -1439,7 +1439,27 @@ bool handle_throw(monster* mons, bolt & beem, bool teleport, bool check_only)
mons->swap_weapons();

beem.name.clear();
return mons_throw(mons, beem, teleport);
bool result = mons_throw(mons, beem, teleport);
// Spirit arrow grants a free shot with a special ammo type
if (!mons->has_ench(ENCH_SPIRIT_BOLT) || !mons->alive() || check_only
|| !using_launcher || !result || beem.hit_verb.empty())
{
mprf("Spirit arrow debug: %i %i %s", using_launcher, result,
beem.hit_verb.c_str());
return result;
}
mprf("A ghostly arrow loads itself in %s %s.",
apostrophise(mons->name(DESC_THE)).c_str(),
mons->launcher()->name(DESC_PLAIN).c_str());
beem.name.clear();
// Set the custom ammo type and slow down the animation a bit
missile->sub_type = MI_SPIRIT_ARROW;
beem.draw_delay = 30;
// Reassign as it gets unassigned during first mons_throw
beem.item = missile;
mons_throw(mons, beem, teleport, false);
// First throw was successful already so always true
return true;
}

return false;
Expand Down
7 changes: 7 additions & 0 deletions crawl-ref/source/mon-aura.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ static const vector<mon_aura_data> aura_map =
ENCH_DOUBLED_VIGOUR, 1, false,
NUM_DURATIONS, "",
[](const actor& targ) { return targ.type != MONS_APIS ;}},

{MONS_SPIRIT_YAK,
ENCH_SPIRIT_BOLT, 1, false,
NUM_DURATIONS, "",
[](const actor& targ)
{ return targ.is_monster() && targ.as_monster()->launcher();
}},
};

static mon_aura_data _get_aura_for(const monster& mon)
Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/mon-ench.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2176,6 +2176,7 @@ static const char *enchant_names[] =
"temporary_amnesia",
"charmer",
"remote_controlled",
"spirit_bolts",
"buggy", // NUM_ENCHANTMENTS
};

Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/mon-info-flag-name.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,5 @@ static const vector<monster_info_flag_name> monster_info_flag_names = {
{ MB_AMNESIA, "amnesiac", "temporary amnesia", "amnesiac"},
{ MB_CHARMER, "charmer", "has charmed you", "charmers"},
{ MB_REMOTE_CONTROL, "puppet", "remote controlled", "puppets"},
{ MB_SPIRIT_BOLT, "spirit bolt", "armed with spirit bolts", "spirit bolts"},
};
1 change: 1 addition & 0 deletions crawl-ref/source/mon-info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ static map<enchant_type, monster_info_flags> trivial_ench_mb_mappings = {
{ ENCH_AMNESIA, MB_AMNESIA },
{ ENCH_CHARMER, MB_CHARMER },
{ ENCH_REMOTE_CONTROL, MB_REMOTE_CONTROL },
{ ENCH_SPIRIT_BOLT, MB_SPIRIT_BOLT },
};

static monster_info_flags ench_to_mb(const monster& mons, enchant_type ench)
Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/mon-info.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ enum monster_info_flags
MB_AMNESIA,
MB_CHARMER,
MB_REMOTE_CONTROL,
MB_SPIRIT_BOLT,
NUM_MB_FLAGS
};

Expand Down
22 changes: 19 additions & 3 deletions crawl-ref/source/mon-place.cc
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ static bool _is_random_monster(monster_type mt)
return mt == RANDOM_MONSTER || mt == RANDOM_MOBILE_MONSTER
|| mt == RANDOM_COMPATIBLE_MONSTER
|| mt == RANDOM_BANDLESS_MONSTER
|| mt == RANDOM_RANGED_MONSTER
|| mt == WANDERING_MONSTER;
}

Expand All @@ -353,6 +354,11 @@ static bool _is_banded_monster(monster_type mt)
return _choose_band(mt) != BAND_NO_BAND;
}

static bool _is_unranged_monster(monster_type mt)
{
return _choose_band(mt) != BAND_NO_BAND;
}

// Caller must use !invalid_monster_type to check if the return value
// is a real monster.
monster_type pick_random_monster(level_id place,
Expand Down Expand Up @@ -386,6 +392,8 @@ monster_type pick_random_monster(level_id place,
return pick_monster(place, _is_incompatible_monster);
else if (kind == RANDOM_BANDLESS_MONSTER)
return pick_monster(place, _is_banded_monster);
else if (kind == RANDOM_RANGED_MONSTER)
return pick_monster(place, _is_unranged_monster);
else if (crawl_state.game_is_sprint())
return pick_monster(place, _has_big_aura);
else
Expand Down Expand Up @@ -2032,8 +2040,6 @@ static band_type _choose_band(monster_type mon_type, int *band_size_p,

case MONS_YAKTAUR:
case MONS_YAKTAUR_CAPTAIN:
case MONS_YAKTAUR_FUSILIER:
case MONS_YAKTAUR_SCRIBE:
if (player_in_branch(BRANCH_VAULTS))
band = BAND_VAULTS_YAKTAURS;
break;
Expand Down Expand Up @@ -2167,7 +2173,8 @@ static const map<band_type, vector<member_possibilities>> band_membership = {
{MONS_UNDYING_ARMOURY, 1},
{MONS_YAKTAUR, 1}},
{{MONS_YAKTAUR, 1}}}},
{ BAND_YAKTAUR_CLERIC, {{{MONS_YAKTAUR_FUSILIER, 1}, // Maybe another special yaktaur
{ BAND_YAKTAUR_CLERIC, {{{MONS_SPIRIT_YAK, 6}, // Roll another special yak/yaktaur
{MONS_YAKTAUR_FUSILIER, 1},
{MONS_YAKTAUR_SCRIBE, 1},
{MONS_SKELETON, 2}, // XX: Force skeleton to yaktaur
{MONS_YAKTAUR, 2}},
Expand Down Expand Up @@ -2616,6 +2623,15 @@ static monster_type _band_member(band_type band, int which,
&parent_place, nullptr, allow_ood);
}

case BAND_RANDOM_RANGED:
{
monster_type tmptype = MONS_PROGRAM_BUG;
coord_def tmppos;
return resolve_monster_type(RANDOM_RANGED_MONSTER, tmptype,
PROX_ANYWHERE, &tmppos, 0,
&parent_place, nullptr, allow_ood);
}

default:
return NUM_MONSTERS;
}
Expand Down
5 changes: 5 additions & 0 deletions crawl-ref/source/monster-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ enum monster_type // env.mons[].type
#endif
MONS_YAK,
MONS_DEATH_YAK,
#if TAG_MAJOR_VERSION > 34
MONS_SPIRIT_YAK,
#endif
MONS_CATOBLEPAS,
MONS_ELEPHANT,
MONS_DIRE_ELEPHANT,
Expand Down Expand Up @@ -1284,6 +1287,7 @@ enum monster_type // env.mons[].type
MONS_YAKTAUR_CLERIC,
MONS_SHIELD_WALL,
MONS_YAKTAUR_FUSILIER,
MONS_SPIRIT_YAK,
#endif

NUM_MONSTERS, // used for polymorph
Expand All @@ -1297,6 +1301,7 @@ enum monster_type // env.mons[].type
RANDOM_COMPATIBLE_MONSTER, // used for player shadow creatures (prevents repulsing summons)
RANDOM_BANDLESS_MONSTER,
RANDOM_POLYMORPH_MONSTER, // choose from a per-monster set
RANDOM_RANGED_MONSTER,

// A random draconian, either base coloured drac or specialised.
RANDOM_DRACONIAN,
Expand Down
3 changes: 2 additions & 1 deletion crawl-ref/source/ranged-attack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,8 @@ bool ranged_attack::handle_phase_hit()
}
else
{
damage_done = calc_damage();
damage_done = calc_damage(projectile->is_type(OBJ_MISSILES, MI_SPIRIT_ARROW)
? ac_type::half : ac_type::normal);
if (damage_done > 0)
{
if (!handle_phase_damaged())
Expand Down
9 changes: 9 additions & 0 deletions crawl-ref/source/rltiles/dc-item.txt
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,15 @@ effect/arrow5 MI_ARROW5
effect/arrow6 MI_ARROW6
effect/arrow7 MI_ARROW7

effect/spirit_arrow0 MI_SPIRIT_ARROW0
effect/spirit_arrow1 MI_SPIRIT_ARROW1
effect/spirit_arrow2 MI_SPIRIT_ARROW2
effect/spirit_arrow3 MI_SPIRIT_ARROW3
effect/spirit_arrow4 MI_SPIRIT_ARROW4
effect/spirit_arrow5 MI_SPIRIT_ARROW5
effect/spirit_arrow6 MI_SPIRIT_ARROW6
effect/spirit_arrow7 MI_SPIRIT_ARROW7

crossbow_bolt1 MI_BOLT
crossbow_bolt2
steel_crossbow_bolt1 MI_BOLT_STEEL
Expand Down
2 changes: 2 additions & 0 deletions crawl-ref/source/rltiles/dc-mon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,8 @@ yaktaur_fusilier MONS_YAKTAUR_FUSILIER
yaktaur_fusilier-melee MONS_YAKTAUR_FUSILIER_MELEE
yaktaur_scribe MONS_YAKTAUR_SCRIBE
yaktaur_scribe-melee MONS_YAKTAUR_SCRIBE_MELEE
%sdir mon/undead
spirit_yak MONS_SPIRIT_YAK
%sdir mon/demihumanoids
faun MONS_FAUN
satyr MONS_SATYR
Expand Down
Binary file added crawl-ref/source/rltiles/effect/spirit_arrow0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added crawl-ref/source/rltiles/effect/spirit_arrow1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added crawl-ref/source/rltiles/effect/spirit_arrow3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added crawl-ref/source/rltiles/effect/spirit_arrow4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added crawl-ref/source/rltiles/effect/spirit_arrow5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added crawl-ref/source/rltiles/effect/spirit_arrow7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 0951d35

Please sign in to comment.