Skip to content

Commit

Permalink
Balloon Yak: new Zot monster
Browse files Browse the repository at this point in the history
A yak-themed chaos construction found in the realm of Zot. On death it
explodes with a wind blast and a spread of chaotic clouds (based on old
plague shambler code) to pressure the player to move.

Spawns in rather small packs or in random single bands; the clouds would
get completely over the top in typical yak band sizes.

For placeholder tiles, I've recoloured the plain yak tile into red,
blue, yellow and green variants; I couldn't decide which was the best
balloon colour so why not use all of them (I went with red in console as
it was available on "Y").
  • Loading branch information
chucksellick committed Feb 13, 2025
1 parent 67a5789 commit c6fa3b6
Show file tree
Hide file tree
Showing 22 changed files with 114 additions and 7 deletions.
4 changes: 4 additions & 0 deletions crawl-ref/source/dat/database/monspell.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,10 @@ wretched star cast

@The_monster@ glows turbulently.
%%%%
blink other close balloon yak cast

@The_monster@ sucks in a gale of air pulling @target@ towards it!
%%%%
########################################################################
# Monster species and genus messages.
########################################################################
Expand Down
8 changes: 8 additions & 0 deletions crawl-ref/source/dat/database/shout.txt
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,14 @@ __SQUEAK seen

SOUND:@The_monster@ squeaks loudly.
%%%%
__RASPBERRY unseen

SOUND:You hear a loud raspberry.
%%%%
__RASPBERRY seen

SOUND:@The_monster@ blows a very loud wet raspberry.
%%%%
############################################
# End of default shouts
############################################
Expand Down
6 changes: 6 additions & 0 deletions crawl-ref/source/dat/descript/monsters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,12 @@ A fast, gas-filled floating spore released by a ballistomycete when it senses a
threat. After seeking out its foe, the spore will explode, damaging anything
caught in the blast and further confusing living creatures.
%%%%
balloon yak

A cartoonish caricature of a living beast, twisted together by some insane street
performer and given life with a breath of chaos. On death will create a rapid
expulsion of air followed by a slower release of clouds of chaos.
%%%%
balrug

A huge and very powerful demon, wreathed in fire and shadows.
Expand Down
8 changes: 8 additions & 0 deletions crawl-ref/source/dat/descript/quotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2695,6 +2695,14 @@ arcanist

<occultist>
%%%%
balloon yak

“I suppose even a simple slogan can be twisted into whatever shape we want,
like a balloon animal – we can even make it loop back around on itself,
becoming a noose. In the end, the measure of who we are can be seen in
the shapes of our balloon animals.”
-Neal Shusterman
%%%%
basilisk

“Be thou like the imperial Basilisk
Expand Down
19 changes: 19 additions & 0 deletions crawl-ref/source/dat/mons/balloon-yak.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: "balloon yak"
glyph: {char: "Y", colour: red}
flags: [flies, herd, unbreathing]
xp_mult: 15
genus: yak
will: 100
attacks:
- {type: gore, damage: 42}
hd: 18
hp_10x: 1200
ac: 12
ev: 4
spells: balloon_yak
has_corpse: false
shout: raspberry
intelligence: animal
size: large
shape: quadruped
tile_variance: mod
1 change: 1 addition & 0 deletions crawl-ref/source/mgen-enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ enum band_type
BAND_YAKTAUR_CLERIC,
BAND_VAULTS_YAKTAURS,
BAND_SPIRIT_YAK,
BAND_BALLOON_YAKS,
NUM_BANDS // always last
};

Expand Down
26 changes: 26 additions & 0 deletions crawl-ref/source/mon-death.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "dgn-overview.h"
#include "english.h"
#include "env.h"
#include "evoke.h" // Windblast death effect
#include "fineff.h"
#include "god-abil.h"
#include "god-blessing.h"
Expand Down Expand Up @@ -3156,6 +3157,31 @@ item_def* monster_die(monster& mons, killer_type killer,
env.markers.clear_need_activate();
}
}
else if (mons.type == MONS_BALLOON_YAK && real_death && !mons.pacified())
{
if (you.can_see(mons))
{
mprf(MSGCH_WARN, "The %s ruptures with a %s and chaos begins "
"spilling from the puncture!", mons.name(DESC_PLAIN).c_str(),
silenced(you.pos()) ? "rush of air" : "loud pop");
}
else if (!silenced(you.pos()))
mprf(MSGCH_WARN, "You hear a loud pop and a rush of air!");

// Wind blast their foe or otherwise you. The real spell power
// would knock you well out of reach of the clouds, 50 is about right.
auto foe = mons.get_foe();
wind_blast(&mons, 50, foe ? foe->pos() : you.pos());

map_cloud_spreader_marker *marker =
new map_cloud_spreader_marker(mons.pos(), CLOUD_CHAOS, 8,
40 + random2(25), LOS_DEFAULT_RANGE,
8, &mons);
// Start the cloud at radius 1, regardless of the speed of the killing blow
marker->speed_increment -= you.time_taken;
env.markers.add(marker);
env.markers.clear_need_activate();
}
else if (!mons.is_summoned() && mummy_curse_power(mons.type) > 0)
{
// TODO: set attacker better? (Player attacker is handled by checking
Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/mon-enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ enum shout_type
S_LOUD_ROAR, // dragons, &c. loud!
S_RUSTLE, // books
S_SQUEAK, // rats and similar
S_RASPBERRY, // balloon yaks
NUM_SHOUTS,

// Loudness setting for shouts that are only defined in dat/shout.txt
Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/mon-pick-data.h
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,7 @@ POP_DEPTHS,
{ -4, 5, 515, RISE, MONS_STORM_DRAGON },
{ 1, 11, 365, SEMI, MONS_GOLDEN_DRAGON },
{ 1, 5, 112, FLAT, MONS_PROTEAN_PROGENITOR },
{ 2, 8, 89, SEMI, MONS_BALLOON_YAK },
{ 2, 8, 52, SEMI, MONS_KILLER_KLOWN },
{ 2, 8, 52, SEMI, MONS_ANACHROBAT },
{ 1, 5, 335, FLAT, MONS_DEATH_COB },
Expand Down
6 changes: 6 additions & 0 deletions crawl-ref/source/mon-place.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1833,6 +1833,11 @@ static const map<monster_type, band_set> bands_by_leader = {
{ MONS_YAKTAUR_CLERIC, { {2}, {{ BAND_YAKTAUR_CLERIC, {4, 8} }}}},
{ MONS_DEATH_YAK, { {}, {{ BAND_DEATH_YAKS, {2, 6} }}}},
{ MONS_SPIRIT_YAK, { {}, {{ BAND_SPIRIT_YAK, {1, 3} }}}},
{ MONS_BALLOON_YAK, { {2, 0, []() {
return branch_has_monsters(you.where_are_you)
|| !vault_mon_types.empty();
}}, {{ BAND_BALLOON_YAKS, {1, 2} },
{ BAND_RANDOM_SINGLE, {1, 3} }}}},
{ MONS_OGRE_MAGE, { {}, {{ BAND_OGRE_MAGE, {4, 8} }}}},
{ MONS_LODUL, { {}, {{ BAND_OGRES, {6, 10}, true }}}},
{ MONS_BALRUG, { {0, 0, []() { return !player_in_hell(); }},
Expand Down Expand Up @@ -2312,6 +2317,7 @@ static const map<band_type, vector<member_possibilities>> band_membership = {
{ BAND_ALLIGATOR, {{{MONS_ALLIGATOR, 1}}}},
{ BAND_JELLYFISH, {{{MONS_FORMLESS_JELLYFISH, 1}}}},
{ BAND_DEATH_YAKS, {{{MONS_DEATH_YAK, 1}}}},
{ BAND_BALLOON_YAKS, {{{MONS_BALLOON_YAK, 1}}}},
{ BAND_GREEN_RATS, {{{MONS_RIVER_RAT, 1}}}},
{ BAND_BRAIN_WORMS, {{{MONS_BRAIN_WORM, 1}}}},
{ BAND_BLINK_FROGS, {{{MONS_BLINK_FROG, 1}}}},
Expand Down
6 changes: 6 additions & 0 deletions crawl-ref/source/mon-spell.h
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,12 @@ static const mon_spellbook mspell_list[] =
}
},

{ MST_BALLOON_YAK,
{
{ SPELL_BLINK_OTHER_CLOSE, 7, MON_SPELL_NATURAL | MON_SPELL_BREATH },
}
},

// ('5') Minor demons.
{ MST_WHITE_IMP,
{
Expand Down
5 changes: 4 additions & 1 deletion crawl-ref/source/mon-util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,7 @@ int get_shout_noise_level(const shout_type shout)
case S_SOFT:
return 6;
case S_LOUD:
case S_RASPBERRY:
return 10;
case S_LOUD_ROAR:
case S_VERY_LOUD:
Expand Down Expand Up @@ -1367,11 +1368,12 @@ static bool _shout_fits_monster(monster_type mc, int shout)

switch (shout)
{
// Bees, books, cherubs and two-headed ogres never fit.
// Bees, books, cherubs, two-headed ogres and balloon yaks never fit.
case S_SHOUT2:
case S_BUZZ:
case S_CHERUB:
case S_RUSTLE:
case S_RASPBERRY:
// The beast cannot speak.
case S_DEMON_TAUNT:
return false;
Expand Down Expand Up @@ -4920,6 +4922,7 @@ string do_mon_str_replacements(const string &in_msg, const monster& mons,
"roars",
"rustles", // dubious
"squeaks",
"wetly raspberries", // balloon yak
"buggily says", // NUM_SHOUTS
"breathes", // S_VERY_SOFT
"whispers", // S_SOFT
Expand Down
2 changes: 2 additions & 0 deletions crawl-ref/source/monster-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ enum monster_type // env.mons[].type
MONS_DEATH_YAK,
#if TAG_MAJOR_VERSION > 34
MONS_SPIRIT_YAK,
MONS_BALLOON_YAK,
#endif
MONS_CATOBLEPAS,
MONS_ELEPHANT,
Expand Down Expand Up @@ -1355,6 +1356,7 @@ enum monster_type // env.mons[].type
MONS_YAKTAUR_FUSILIER,
MONS_SPIRIT_YAK,
MONS_ANACHROBAT,
MONS_BALLOON_YAK,
#endif

NUM_MONSTERS, // used for polymorph
Expand Down
3 changes: 2 additions & 1 deletion crawl-ref/source/monster.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2427,7 +2427,8 @@ string monster::foot_name(bool plural, bool *can_plural) const
str = "paw";
else if (ch == 'l' || ch == 'D')
str = "talon";
else if (type == MONS_YAK || type == MONS_DEATH_YAK)
else if (type == MONS_YAK || type == MONS_DEATH_YAK
|| type == MONS_BALLOON_YAK)
str = "hoof";
else if (ch == 'H')
{
Expand Down
1 change: 1 addition & 0 deletions crawl-ref/source/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ class player : public actor
// Move the player during an abyss shift.
void shiftto(const coord_def &c);
bool blink_to(const coord_def& c, bool quiet = false) override;
bool blink_to(const coord_def& c, bool quiet, bool jump);

void set_level_visited(const level_id &level);
bool level_visited(const level_id &level);
Expand Down
4 changes: 4 additions & 0 deletions crawl-ref/source/rltiles/dc-mon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ polar_bear MONS_POLAR_BEAR
dream_sheep MONS_DREAM_SHEEP
yak MONS_YAK
death_yak MONS_DEATH_YAK
balloon_yak1 MONS_BALLOON_YAK
balloon_yak2
balloon_yak3
balloon_yak4
catoblepas MONS_CATOBLEPAS
elephant MONS_ELEPHANT
elephant_dire MONS_DIRE_ELEPHANT
Expand Down
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
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.
1 change: 1 addition & 0 deletions crawl-ref/source/shout.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static const map<shout_type, string> default_msg_keys = {
{ S_LOUD_ROAR, "__LOUD_ROAR" },
{ S_RUSTLE, "__RUSTLE" },
{ S_SQUEAK, "__SQUEAK" },
{ S_RASPBERRY, "__RASPBERRY" },
};

/**
Expand Down
19 changes: 14 additions & 5 deletions crawl-ref/source/teleport.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "coord.h"
#include "coordit.h"
#include "delay.h"
#include "english.h"
#include "env.h"
#include "fprop.h"
#include "libutil.h"
Expand All @@ -25,6 +26,12 @@
#include "view.h"

bool player::blink_to(const coord_def& dest, bool quiet)
{
// Players aren't normally jumping
return blink_to(dest, quiet, false);
}

bool player::blink_to(const coord_def& dest, bool quiet, bool jump)
{
// We rely on the non-generalized move_player_to_cell.
ASSERT(is_player());
Expand All @@ -47,7 +54,7 @@ bool player::blink_to(const coord_def& dest, bool quiet)
const coord_def origin = pos();
move_player_to_grid(dest, false);

if (!cell_is_solid(origin))
if (!jump && !cell_is_solid(origin))
place_cloud(CLOUD_TLOC_ENERGY, origin, 1 + random2(3), this);

return true;
Expand All @@ -72,7 +79,7 @@ bool monster::blink_to(const coord_def& dest, bool quiet, bool jump)
if (is_constricted())
{
was_constricted = true;
stop_being_constricted(false, "blinks");
stop_being_constricted(false, conj_verb(verb));
}

if (!quiet)
Expand Down Expand Up @@ -374,11 +381,13 @@ void blink_other_close(actor* victim, const coord_def &target)
coord_def dest = random_space_weighted(victim, caster, true);
if (!in_bounds(dest))
return;
// If it's a monster, force them to "blink" rather than "jump"

// Balloon yaks are sucking in air, so treat like a jump
bool quiet = caster->type == MONS_BALLOON_YAK;
if (victim->is_monster())
victim->as_monster()->blink_to(dest, false, false);
victim->as_monster()->blink_to(dest, quiet, quiet);
else
victim->blink_to(dest);
victim->as_player()->blink_to(dest, quiet, quiet);
}

// Blink the player away from a given monster
Expand Down

0 comments on commit c6fa3b6

Please sign in to comment.