summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/abl-show.cc92
-rw-r--r--crawl-ref/source/acr.cc3
-rw-r--r--crawl-ref/source/beam.cc75
-rw-r--r--crawl-ref/source/dat/descript/gods.txt4
-rw-r--r--crawl-ref/source/debug.cc11
-rw-r--r--crawl-ref/source/describe.cc16
-rw-r--r--crawl-ref/source/directn.cc5
-rw-r--r--crawl-ref/source/dungeon.cc9
-rw-r--r--crawl-ref/source/effects.cc52
-rw-r--r--crawl-ref/source/enum.h21
-rw-r--r--crawl-ref/source/externs.h2
-rw-r--r--crawl-ref/source/luadgn.cc2
-rw-r--r--crawl-ref/source/message.cc3
-rw-r--r--crawl-ref/source/misc.cc41
-rw-r--r--crawl-ref/source/misc.h1
-rw-r--r--crawl-ref/source/mon-util.cc39
-rw-r--r--crawl-ref/source/mon-util.h3
-rw-r--r--crawl-ref/source/monplace.cc8
-rw-r--r--crawl-ref/source/monstuff.cc137
-rw-r--r--crawl-ref/source/monstuff.h9
-rw-r--r--crawl-ref/source/newgame.cc19
-rw-r--r--crawl-ref/source/ouch.cc66
-rw-r--r--crawl-ref/source/output.cc17
-rw-r--r--crawl-ref/source/player.cc56
-rw-r--r--crawl-ref/source/player.h2
-rw-r--r--crawl-ref/source/religion.cc307
-rw-r--r--crawl-ref/source/religion.h3
-rw-r--r--crawl-ref/source/rltiles/dc-dngn.txt1
-rw-r--r--crawl-ref/source/rltiles/dc-dngn/altars/dngn_altar_jiyva.pngbin0 -> 524 bytes
-rw-r--r--crawl-ref/source/spl-mis.cc1
-rw-r--r--crawl-ref/source/tags.cc10
-rw-r--r--crawl-ref/source/tags.h3
-rw-r--r--crawl-ref/source/tilepick.cc6
-rw-r--r--crawl-ref/source/view.cc32
-rw-r--r--crawl-ref/source/view.h1
35 files changed, 1001 insertions, 56 deletions
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc
index 520cd54255..7e99813338 100644
--- a/crawl-ref/source/abl-show.cc
+++ b/crawl-ref/source/abl-show.cc
@@ -41,6 +41,7 @@ REVISION("$Rev$");
#include "mon-util.h"
#include "monplace.h"
#include "monstuff.h"
+#include "mutation.h"
#include "notes.h"
#include "ouch.h"
#include "player.h"
@@ -142,7 +143,10 @@ ability_type god_abilities[MAX_NUM_GODS][MAX_GOD_ABILITIES] =
ABIL_LUGONU_CORRUPT, ABIL_LUGONU_ABYSS_ENTER },
// Beogh
{ ABIL_NON_ABILITY, ABIL_BEOGH_SMITING, ABIL_NON_ABILITY,
- ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS, ABIL_NON_ABILITY }
+ ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS, ABIL_NON_ABILITY },
+ // Jiyva
+ { ABIL_JIYVA_CALL_JELLY, ABIL_NON_ABILITY, ABIL_NON_ABILITY,
+ ABIL_JIYVA_SLIMIFY, ABIL_JIYVA_BAD_MUT_REMOVE }
};
// The description screen was way out of date with the actual costs.
@@ -316,6 +320,13 @@ static const ability_def Ability_List[] =
{ ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS, "Recall Orcish Followers",
2, 0, 50, 0, ABFLAG_NONE },
+ // Jiyva
+ { ABIL_JIYVA_CALL_JELLY, "Request Jelly", 2, 0, 20, 1, ABFLAG_NONE },
+ { ABIL_JIYVA_JELLY_SHIELD, "Jelly Shield", 0, 0, 0, 0, ABFLAG_PIETY },
+ { ABIL_JIYVA_SLIMIFY, "Slimify", 4, 0, 100, 3, ABFLAG_NONE },
+ { ABIL_JIYVA_BAD_MUT_REMOVE, "Mutation Removal",
+ 8, 0, 200, 15, ABFLAG_NONE },
+
{ ABIL_HARM_PROTECTION, "Protection From Harm", 0, 0, 0, 0, ABFLAG_NONE },
{ ABIL_HARM_PROTECTION_II, "Reliable Protection From Harm",
0, 0, 0, 0, ABFLAG_PIETY },
@@ -658,6 +669,7 @@ static talent _get_talent(ability_type ability, bool check_confused)
case ABIL_ELYVILON_LESSER_HEALING_SELF:
case ABIL_ELYVILON_LESSER_HEALING_OTHERS:
case ABIL_LUGONU_ABYSS_EXIT:
+ case ABIL_JIYVA_CALL_JELLY:
invoc = true;
failure = 30 - (you.piety / 20) - (6 * you.skills[SK_INVOCATIONS]);
break;
@@ -705,6 +717,7 @@ static talent _get_talent(ability_type ability, bool check_confused)
case ABIL_ELYVILON_GREATER_HEALING_SELF:
case ABIL_ELYVILON_GREATER_HEALING_OTHERS:
case ABIL_LUGONU_BEND_SPACE:
+ case ABIL_JIYVA_SLIMIFY:
invoc = true;
failure = 40 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]);
break;
@@ -745,6 +758,7 @@ static talent _get_talent(ability_type ability, bool check_confused)
case ABIL_YRED_ENSLAVE_SOUL:
case ABIL_ELYVILON_DIVINE_VIGOUR:
case ABIL_LUGONU_ABYSS_ENTER:
+ case ABIL_JIYVA_BAD_MUT_REMOVE:
invoc = true;
failure = 80 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
break;
@@ -1885,6 +1899,82 @@ static bool _do_ability(const ability_def& abil)
}
break;
+ case ABIL_JIYVA_CALL_JELLY:
+ {
+ mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, you.pos(),
+ MHITNOT, 0, GOD_JIYVA);
+
+ if (create_monster(mg) == -1)
+ return (false);
+
+ exercise(SK_INVOCATIONS, 1 + random2(3));
+ break;
+ }
+ case ABIL_JIYVA_JELLY_SHIELD:
+ // Prayer effect
+ break;
+
+ case ABIL_JIYVA_SLIMIFY:
+ beam.range = LOS_RADIUS;
+ if (!spell_direction(spd, beam))
+ return (false);
+
+ if (beam.target == you.pos())
+ {
+ mpr("You cannot slime yourself!");
+ return (false);
+ }
+ if (!zapping(ZAP_SLIME, 16 + you.skills[SK_INVOCATIONS] * 8, beam,
+ true))
+ {
+ return (false);
+ }
+ exercise(SK_INVOCATIONS, 3 + random2(5));
+ break;
+
+ case ABIL_JIYVA_BAD_MUT_REMOVE:
+ {
+ // Removes a bad mutation from the player.
+ // delete_mutation(RANDOM_BAD_MUTATION) defaults to removing
+ // a random mutation if the player has no bad mutations
+ // so any newly added bad mutations need to be included here.
+
+ const mutation_type bad[] = {
+ MUT_HERBIVOROUS, MUT_CARNIVOROUS,
+ MUT_FRAIL, MUT_SLOW_HEALING,
+ MUT_FAST_METABOLISM, MUT_WEAK, MUT_DOPEY,
+ MUT_CLUMSY, MUT_DEFORMED, MUT_TELEPORT,
+ MUT_SCREAM, MUT_BERSERK, MUT_BLURRY_VISION,
+ MUT_LOW_MAGIC, MUT_DETERIORATION
+ };
+
+ if (!how_mutated())
+ {
+ mpr("You have no mutations to remove.");
+ return (false);
+ }
+
+ bool done = false;
+ for (int tries = 0; !done && tries < 100; tries++)
+ {
+ mutation_type mutat = RANDOM_ELEMENT(bad);
+ if (you.mutation[mutat] > 0)
+ done = delete_mutation(mutat);
+ }
+
+
+ if (done)
+ {
+ mpr("You feel cleansed.");
+ exercise(SK_INVOCATIONS, 5 + random2(5));
+ }
+ else
+ {
+ mpr("Nothing seems to happen.");
+ return (false);
+ }
+ break;
+ }
case ABIL_HARM_PROTECTION:
case ABIL_HARM_PROTECTION_II:
// Activated via prayer elsewhere.
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index f4de428b41..a8e12ad76f 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -382,6 +382,9 @@ static void _god_greeting_message(bool game_start)
case GOD_BEOGH:
simple_god_message(" says: Drown the unbelievers in a sea of blood!");
break;
+ case GOD_JIYVA:
+ god_speaks(you.religion, "Slime for the Slime God!");
+ break;
case GOD_NO_GOD:
case NUM_GODS:
case GOD_RANDOM:
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 8a7df4e6e6..c4eaf856eb 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -1265,6 +1265,21 @@ const zap_info zap_data[] = {
false,
false,
false
+ },
+
+ {
+ ZAP_SLIME,
+ "0",
+ 100,
+ NULL,
+ NULL,
+ GREEN,
+ true,
+ BEAM_SLIME,
+ DCHAR_SPACE,
+ false,
+ false,
+ false
}
};
@@ -4699,6 +4714,11 @@ bool _ench_flavour_affects_monster(beam_type flavour, const monsters* mon)
|| (mons_holiness(mon) == MH_NATURAL && mon->type != MONS_HOG);
break;
+ case BEAM_SLIME:
+ rc = (mons_holiness(mon) == MH_NATURAL
+ || mons_holiness(mon) == MH_UNDEAD);
+ break;
+
default:
break;
}
@@ -4868,6 +4888,58 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon)
behaviour_event(mon, ME_ALERT, MHITNOT);
return (MON_AFFECTED);
+ case BEAM_SLIME:
+ if (mon->hit_dice * 8 / 2 >= random2(ench_power))
+ return (MON_RESIST);
+
+ obvious_effect = true;
+
+ if (mons_holiness(mon) == MH_UNDEAD)
+ {
+ monster_polymorph(mon, MONS_DEATH_OOZE);
+ mon->attitude = ATT_STRICT_NEUTRAL;
+ }
+ else
+ {
+ const int x = mon->hit_dice + (coinflip() ? 1 : -1) * random2(5);
+
+ if (x < 3)
+ {
+ monster_polymorph(mon, MONS_OOZE);
+ mon->add_ench(ENCH_EATS_ITEMS);
+ }
+ else if (x >= 3 && x < 5)
+ {
+ monster_polymorph(mon, MONS_JELLY);
+ }
+ else if (x >= 5 && x < 7)
+ {
+ monster_polymorph(mon, MONS_BROWN_OOZE);
+ }
+ else if (x >= 7 && x <= 11)
+ {
+ if (coinflip())
+ {
+ monster_polymorph(mon, MONS_SLIME_CREATURE);
+ mon->add_ench(ENCH_EATS_ITEMS);
+ }
+ else
+ {
+ monster_polymorph(mon, MONS_GIANT_AMOEBA);
+ mon->add_ench(ENCH_EATS_ITEMS);
+ }
+ }
+ else
+ {
+ if (coinflip())
+ monster_polymorph(mon, MONS_ACID_BLOB);
+ else
+ monster_polymorph(mon, MONS_AZURE_JELLY);
+ }
+ mon->attitude = ATT_STRICT_NEUTRAL;
+ }
+ return(MON_AFFECTED);
+
case BEAM_PAIN: // pain/agony
if (simple_monster_message(mon, " convulses in agony!"))
obvious_effect = true;
@@ -5735,13 +5807,14 @@ std::string beam_type_name(beam_type type)
case BEAM_PETRIFY: return("petrify");
case BEAM_BACKLIGHT: return("backlight");
case BEAM_SLEEP: return("sleep");
+ case BEAM_SLIME: return("slime");
case BEAM_PORKALATOR: return("porkalator");
case BEAM_POTION_BLACK_SMOKE: return("black smoke");
case BEAM_POTION_GREY_SMOKE: return("grey smoke");
case BEAM_POTION_BLUE_SMOKE: return("blue smoke");
case BEAM_POTION_PURP_SMOKE: return("purple smoke");
case BEAM_POTION_RANDOM: return("random potion");
- case BEAM_VISUAL: return ("visual effects");
+ case BEAM_VISUAL: return("visual effects");
case BEAM_TORMENT_DAMAGE: return("torment damage");
case BEAM_STEAL_FOOD: return("steal food");
diff --git a/crawl-ref/source/dat/descript/gods.txt b/crawl-ref/source/dat/descript/gods.txt
index f935e18a34..84840ef344 100644
--- a/crawl-ref/source/dat/descript/gods.txt
+++ b/crawl-ref/source/dat/descript/gods.txt
@@ -70,6 +70,10 @@ Beogh
Beogh is the deity worshipped by the cave orcs native to parts of the dungeon. Only orcs may devote their service to Beogh, and must prove their devotion by bloodshed and the blessing of dead orcs. Devout followers of Beogh can smite their foes, and especially fervent devotees of Beogh may even gain followers of their own, for the orcs still look for their Messiah.
%%%%
+Jiyva
+
+Jiyva is the ancient deity of the slimes.
+%%%%
Zin powers
Zin grants followers the ability to preach to the unenlightened masses. With sufficient piety, a starving follower can pray for nutrition. Later, followers will gain powers to purify and strengthen their bodies, and can eventually find temporary safety in a divine refuge. As piety grows, followers will be protected from mutations. Apart from that, Zin may occasionally directly intervene to save a follower's life.
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index f563134ecf..5758a05bc3 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -2601,11 +2601,12 @@ void debug_stethoscope(int mon)
mprf(MSGCH_DIAGNOSTICS, "%s (id #%d; type=%d loc=(%d,%d) align=%s)",
mons.name(DESC_CAP_THE, true).c_str(),
i, mons.type, mons.pos().x, mons.pos().y,
- ((mons.attitude == ATT_HOSTILE) ? "hostile" :
- (mons.attitude == ATT_FRIENDLY) ? "friendly" :
- (mons.attitude == ATT_NEUTRAL) ? "neutral" :
- (mons.attitude == ATT_GOOD_NEUTRAL) ? "good neutral"
- : "unknown alignment") );
+ ((mons.attitude == ATT_HOSTILE) ? "hostile" :
+ (mons.attitude == ATT_FRIENDLY) ? "friendly" :
+ (mons.attitude == ATT_NEUTRAL) ? "neutral" :
+ (mons.attitude == ATT_GOOD_NEUTRAL) ? "good neutral":
+ (mons.attitude == ATT_STRICT_NEUTRAL) ? "strictly neutral"
+ : "unknown alignment") );
// Print stats and other info.
mprf(MSGCH_DIAGNOSTICS,
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 21803a8328..25c5a0784a 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -3207,7 +3207,11 @@ const char *divine_title[NUM_GODS][8] =
// Beogh -- messiah theme
{"Apostate", "Messenger", "Proselytiser", "Priest",
- "Missionary", "Evangelist", "Apostle", "Messiah"}
+ "Missionary", "Evangelist", "Apostle", "Messiah"},
+
+ // Jiyva -- slime and jelly theme
+ {"Scum", "Jelly", "Squelcher", "Dissolver",
+ "Putrid Slime", "Consuming %s", "Archjelly", "Royal Jelly"}
};
static int _piety_level()
@@ -3541,6 +3545,16 @@ void describe_god( god_type which_god, bool give_title )
ABIL_YRED_INJURY_MIRROR);
}
}
+ else if (which_god == GOD_JIYVA)
+ {
+ if (jiyva_grant_jelly(false))
+ {
+ have_any = true;
+ std::string buf = "You can pray to create a jelly shield.";
+ _print_final_god_abil_desc(which_god, buf,
+ ABIL_JIYVA_JELLY_SHIELD);
+ }
+ }
// mv: No abilities (except divine protection) under penance
if (!player_under_penance())
diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc
index 53652e78a5..642f92eb5d 100644
--- a/crawl-ref/source/directn.cc
+++ b/crawl-ref/source/directn.cc
@@ -1504,6 +1504,9 @@ void direction(dist& moves, targeting_type restricts,
m->flags |= MF_WAS_NEUTRAL;
break;
case ATT_GOOD_NEUTRAL:
+ m->attitude = ATT_STRICT_NEUTRAL;
+ break;
+ case ATT_STRICT_NEUTRAL:
m->attitude = ATT_NEUTRAL;
break;
case ATT_NEUTRAL:
@@ -2763,6 +2766,8 @@ static std::string _base_feature_desc(dungeon_feature_type grid,
return ("corrupted altar of Lugonu");
case DNGN_ALTAR_BEOGH:
return ("roughly hewn altar of Beogh");
+ case DNGN_ALTAR_JIYVA:
+ return ("viscous altar of Jiyva");
case DNGN_FOUNTAIN_BLUE:
return ("fountain of clear blue water");
case DNGN_FOUNTAIN_SPARKLING:
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 3dba2c23a0..ee7488db82 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -4681,6 +4681,9 @@ int dgn_place_monster(mons_spec &mspec,
case ATT_GOOD_NEUTRAL:
mg.behaviour = BEH_GOOD_NEUTRAL;
break;
+ case ATT_STRICT_NEUTRAL:
+ mg.behaviour = BEH_STRICT_NEUTRAL;
+ break;
default:
break;
}
@@ -5341,7 +5344,7 @@ static dungeon_feature_type _pick_an_altar()
|| player_in_branch( BRANCH_ECUMENICAL_TEMPLE )
|| you.level_type == LEVEL_LABYRINTH)
{
- // No extra altars in Temple, none at all in Slime Pits or Labyrinth.
+ // No extra altars in Temple, none at all in Labyrinth.
altar_type = DNGN_FLOOR;
}
else if (you.level_type == LEVEL_DUNGEON && !one_chance_in(5))
@@ -5388,6 +5391,10 @@ static dungeon_feature_type _pick_an_altar()
: DNGN_ALTAR_MAKHLEB);
break;
+ case BRANCH_SLIME_PITS:
+ altar_type = DNGN_ALTAR_JIYVA;
+ break;
+
case BRANCH_TOMB:
altar_type = DNGN_ALTAR_KIKUBAAQUDGHA;
break;
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index ac4055d830..646e007207 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -3460,6 +3460,58 @@ void handle_time(long time_delta)
if (one_chance_in(10))
change_labyrinth();
}
+
+ if (you.religion == GOD_JIYVA && !player_under_penance()
+ && one_chance_in(10))
+ {
+ int total_jellies = 1 + random2(5);
+ bool success = false;
+ int created;
+ for (int num_jellies = total_jellies; num_jellies > 0; num_jellies--)
+ {
+ //Spread jellies around the level
+ coord_def newpos;
+ do
+ {
+ newpos.set( random_range(X_BOUND_1 + 1, X_BOUND_2 - 1),
+ random_range(Y_BOUND_1 + 1, Y_BOUND_2 - 1) );
+ }
+ while (grd(newpos) != DNGN_FLOOR
+ && grd(newpos) != DNGN_SHALLOW_WATER
+ || monster_at(newpos)
+ || env.cgrid(newpos) != EMPTY_CLOUD);
+
+ mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, newpos,
+ MHITNOT, 0, GOD_JIYVA);
+
+ if (create_monster(mg) != -1)
+ success = true;
+ }
+
+ if (success && !silenced(you.pos()))
+ {
+ switch (random2(3))
+ {
+ case 0:
+ simple_god_message(" gurgles merrily.");
+ break;
+ case 1:
+ mprf(MSGCH_SOUND, "You hear %s splatter%s.",
+ total_jellies > 1 ? "a series of" : "a",
+ total_jellies > 1 ? "s" : "");
+ break;
+ case 2:
+ simple_god_message(" says: Divide and consume!");
+ break;
+ }
+ }
+ }
+
+ if (you.religion == GOD_JIYVA && x_chance_in_y(you.piety / 4, MAX_PIETY)
+ && !player_under_penance())
+ {
+ jiyva_stat_action();
+ }
}
// Move monsters around to fake them walking around while player was
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 84fe2900c5..ff484524ae 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -103,10 +103,14 @@ enum ability_type
ABIL_NEMELEX_STACK_FIVE,
ABIL_BEOGH_SMITING,
ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS,
+ ABIL_JIYVA_CALL_JELLY,
+ ABIL_JIYVA_JELLY_SHIELD, // 240
+ ABIL_JIYVA_SLIMIFY,
+ ABIL_JIYVA_BAD_MUT_REMOVE,
- ABIL_TRAN_BAT = 240,
+ ABIL_TRAN_BAT = 244,
ABIL_HARM_PROTECTION,
- ABIL_HARM_PROTECTION_II, // 242
+ ABIL_HARM_PROTECTION_II, // 246
ABIL_RENOUNCE_RELIGION = 250 // 250
};
@@ -237,6 +241,7 @@ enum beam_type // beam[].flavour
BEAM_PETRIFY,
BEAM_BACKLIGHT,
BEAM_PORKALATOR, // 45
+ BEAM_SLIME,
BEAM_SLEEP,
BEAM_LAST_ENCHANTMENT = BEAM_SLEEP,
@@ -732,6 +737,7 @@ enum conduct_type
DID_DESECRATE_ORCISH_REMAINS, // Beogh
DID_DESTROY_ORCISH_IDOL, // Beogh
DID_CREATE_LIFE, // unused
+ DID_KILL_SLIME, // Jiyva
NUM_CONDUCTS
};
@@ -1097,7 +1103,8 @@ enum dungeon_feature_type
DNGN_ALTAR_ELYVILON, // 191
DNGN_ALTAR_LUGONU,
DNGN_ALTAR_BEOGH,
- DNGN_ALTAR_LAST_GOD = DNGN_ALTAR_BEOGH,
+ DNGN_ALTAR_JIYVA,
+ DNGN_ALTAR_LAST_GOD = DNGN_ALTAR_JIYVA,
DNGN_FOUNTAIN_BLUE = 200, // 200
DNGN_FOUNTAIN_SPARKLING, // aka 'Magic Fountain' {dlb}
@@ -1245,6 +1252,7 @@ enum enchant_type
ENCH_LOWERED_MR,
ENCH_SOUL_RIPE,
ENCH_SLOWLY_DYING,
+ ENCH_EATS_ITEMS,
// Update enchantment names in mon-util.cc when adding or removing
// enchantments.
@@ -1336,6 +1344,7 @@ enum god_type
GOD_ELYVILON,
GOD_LUGONU,
GOD_BEOGH,
+ GOD_JIYVA,
NUM_GODS, // always after last god
GOD_RANDOM = 100,
@@ -2063,6 +2072,7 @@ enum beh_type
BEH_CHARMED, // hostile-but-charmed; creation only
BEH_FRIENDLY, // used during creation only
BEH_GOOD_NEUTRAL, // creation only
+ BEH_STRICT_NEUTRAL,
BEH_NEUTRAL, // creation only
BEH_HOSTILE, // creation only
BEH_GUARD // creation only - monster is guard
@@ -2073,6 +2083,7 @@ enum mon_attitude_type
ATT_HOSTILE, // 0, default in most cases
ATT_NEUTRAL, // neutral
ATT_GOOD_NEUTRAL, // neutral, but won't attack friendlies
+ ATT_STRICT_NEUTRAL, // neutral, won't attack player. Used by Jiyva.
ATT_FRIENDLY // created friendly (or tamed?)
};
@@ -2095,7 +2106,8 @@ enum monster_flag_type
MF_ATT_CHANGE_ATTEMPT = 0x400, // Saw player and attitude changed (or
// not); currently used for holy beings
// (good god worshippers -> neutral)
- // and orcs (Beogh worshippers -> friendly)
+ // orcs (Beogh worshippers -> friendly),
+ // and slimes (Jiyva worshippers -> neutral)
MF_WAS_IN_VIEW = 0x800, // Was in view during previous turn.
MF_BAND_MEMBER = 0x1000, // Created as a member of a band
@@ -3070,6 +3082,7 @@ enum zap_type
ZAP_PETRIFY,
ZAP_ENSLAVE_SOUL,
ZAP_CHAOS,
+ ZAP_SLIME,
NUM_ZAPS
};
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 3b5157309d..e92533690a 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -793,6 +793,7 @@ public:
char max_strength;
char max_intel;
char max_dex;
+ stat_type last_chosen;
char hunger_state;
@@ -915,6 +916,7 @@ public:
FixedVector<unsigned char, 30> branch_stairs;
god_type religion;
+ std::string second_god_name; // Random second name of Jiyva
unsigned char piety;
unsigned char piety_hysteresis; // amount of stored-up docking
unsigned char gift_timeout;
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index daab16491d..b894a6be66 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -1395,7 +1395,7 @@ const char *dngn_feature_names[] =
"altar_yredelemnul", "altar_xom", "altar_vehumet",
"altar_okawaru", "altar_makhleb", "altar_sif_muna", "altar_trog",
"altar_nemelex_xobeh", "altar_elyvilon", "altar_lugonu",
- "altar_beogh", "", "", "", "", "", "", "fountain_blue",
+ "altar_beogh", "altar_jiyva", "", "", "", "", "", "fountain_blue",
"fountain_sparkling", "fountain_blood", "dry_fountain_blue",
"dry_fountain_sparkling", "dry_fountain_blood", "permadry_fountain",
"abandoned_shop"
diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc
index e5606cd39c..f39fbd89ab 100644
--- a/crawl-ref/source/message.cc
+++ b/crawl-ref/source/message.cc
@@ -238,6 +238,9 @@ static char god_message_altar_colour( god_type god )
case GOD_LUGONU:
return (LIGHTRED);
+ case GOD_JIYVA:
+ return (coinflip() ? GREEN : LIGHTGREEN);
+
case GOD_NO_GOD:
case NUM_GODS:
case GOD_RANDOM:
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 90d89d074f..d4e63f1186 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1157,6 +1157,21 @@ static void _spatter_neighbours(const coord_def& where, int chance)
}
}
+bool slime_vault_to_floor()
+{
+ bool success = false;
+
+ for (rectangle_iterator ri(1); ri; ++ri)
+ {
+ if (grd(*ri) == DNGN_STONE_WALL)
+ {
+ grd(*ri) = DNGN_FLOOR;
+ success = true;
+ }
+ }
+ return (success);
+}
+
void generate_random_blood_spatter_on_level()
{
int startprob;
@@ -2419,6 +2434,31 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
new_level();
+ static int times_entered = 0;
+
+ if (level_id::current() == level_id(BRANCH_SLIME_PITS, 6)
+ && you.religion == GOD_JIYVA)
+ {
+ const level_id target(BRANCH_SLIME_PITS, 6);
+ if (times_entered == 0)
+ {
+ if (apply_to_level(target, true, slime_vault_to_floor))
+ {
+ if (!silenced(you.pos()))
+ {
+ mpr("You hear the sound of toppling stones.",
+ MSGCH_MONSTER_ENCHANT);
+ }
+ else
+ {
+ mpr("An unexplained breeze blows through the dungeon.",
+ MSGCH_MONSTER_ENCHANT);
+ }
+ }
+ times_entered++;
+ }
+ }
+
// Clear list of beholding monsters.
if (you.duration[DUR_MESMERISED])
{
@@ -3095,6 +3135,7 @@ bool stop_attack_prompt(const monsters *mon, bool beam_attack,
prompt = true;
}
else if (inSanctuary || wontAttack
+ || (you.religion == GOD_JIYVA && mons_is_slime(mon))
|| (isNeutral || isHoly) && is_good_god(you.religion)
|| isUnchivalric
&& you.religion == GOD_SHINING_ONE
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index e15bce8eb1..7d28f45a22 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -34,6 +34,7 @@ bool maybe_coagulate_blood_potions_inv( item_def &blood );
long remove_oldest_blood_potion( item_def &stack );
void remove_newest_blood_potion( item_def &stack, int quant = -1 );
void merge_blood_potion_stacks(item_def &source, item_def &dest, int quant);
+bool slime_vault_to_floor();
bool can_bottle_blood_from_corpse( int mons_type );
int num_blood_potions_from_corpse( int mons_class, int chunk_type = -1 );
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index f9f7f2bdcd..109d4c60a7 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -628,6 +628,24 @@ bool mons_is_icy(int mc)
|| mc == MONS_ICE_STATUE);
}
+// Monsters consider as "slime" for Jiyva.
+bool mons_is_slime(const monsters *mon)
+{
+ if (mons_genus(mon->type) == MONS_JELLY
+ || mons_genus(mon->type) == MONS_GIANT_EYEBALL
+ || mons_genus(mon->type) == MONS_GIANT_ORANGE_BRAIN)
+ {
+ return (true);
+ }
+ return (false);
+}
+
+bool mons_eats_items(const monsters *mon)
+{
+ return (mons_itemuse(mon) == MONUSE_EATS_ITEMS
+ || mon->has_ench(ENCH_EATS_ITEMS));
+}
+
bool mons_is_skeletal(int mc)
{
return (mc == MONS_SKELETON_SMALL
@@ -2558,7 +2576,8 @@ bool mons_friendly_real(const monsters *m)
bool mons_neutral(const monsters *m)
{
return (m->attitude == ATT_NEUTRAL || m->has_ench(ENCH_NEUTRAL)
- || m->attitude == ATT_GOOD_NEUTRAL);
+ || m->attitude == ATT_GOOD_NEUTRAL
+ || m->attitude == ATT_STRICT_NEUTRAL);
}
bool mons_good_neutral(const monsters *m)
@@ -2566,6 +2585,11 @@ bool mons_good_neutral(const monsters *m)
return (m->attitude == ATT_GOOD_NEUTRAL);
}
+bool mons_strict_neutral(const monsters *m)
+{
+ return (m->attitude == ATT_STRICT_NEUTRAL);
+}
+
bool mons_is_pacified(const monsters *m)
{
return (m->attitude == ATT_NEUTRAL && testbits(m->flags, MF_GOT_HALF_XP));
@@ -2573,17 +2597,17 @@ bool mons_is_pacified(const monsters *m)
bool mons_wont_attack(const monsters *m)
{
- return (mons_friendly(m) || mons_good_neutral(m));
+ return (mons_friendly(m) || mons_good_neutral(m) || mons_strict_neutral(m));
}
bool mons_wont_attack_real(const monsters *m)
{
- return (mons_friendly_real(m) || mons_good_neutral(m));
+ return (mons_friendly_real(m) || mons_good_neutral(m) || mons_strict_neutral(m));
}
bool mons_att_wont_attack(mon_attitude_type fr)
{
- return (fr == ATT_FRIENDLY || fr == ATT_GOOD_NEUTRAL);
+ return (fr == ATT_FRIENDLY || fr == ATT_GOOD_NEUTRAL || fr == ATT_STRICT_NEUTRAL);
}
mon_attitude_type mons_attitude(const monsters *m)
@@ -2592,6 +2616,8 @@ mon_attitude_type mons_attitude(const monsters *m)
return ATT_FRIENDLY;
else if (mons_good_neutral(m))
return ATT_GOOD_NEUTRAL;
+ else if (mons_strict_neutral(m))
+ return ATT_STRICT_NEUTRAL;
else if (mons_neutral(m))
return ATT_NEUTRAL;
else
@@ -7541,6 +7567,9 @@ void monsters::apply_enchantment(const mon_enchant &me)
del_ench(ENCH_SLEEPY);
break;
+ case ENCH_EATS_ITEMS:
+ break;
+
default:
break;
}
@@ -8254,7 +8283,7 @@ static const char *enchant_names[] =
"gloshifter", "shifter", "tp", "wary", "submerged",
"short-lived", "paralysis", "sick", "sleep", "fatigue", "held",
"blood-lust", "neutral", "petrifying", "petrified", "magic-vulnerable",
- "soul-ripe", "decay", "bug"
+ "soul-ripe", "decay", "hungry", "bug"
};
static const char *_mons_enchantment_name(enchant_type ench)
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index b3d3ec32ce..1c374d8ab2 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -749,6 +749,7 @@ bool mons_friendly(const monsters *m);
bool mons_friendly_real(const monsters *m);
bool mons_neutral(const monsters *m);
bool mons_good_neutral(const monsters *m);
+bool mons_strict_neutral(const monsters *m);
bool mons_is_pacified(const monsters *m);
bool mons_wont_attack(const monsters *m);
bool mons_wont_attack_real(const monsters *m);
@@ -783,6 +784,8 @@ bool mons_is_unholy(const monsters *mon);
bool mons_is_evil_or_unholy(const monsters *mon);
bool mons_is_icy(int mc);
bool mons_is_skeletal(int mc);
+bool mons_is_slime(const monsters *mon);
+bool mons_eats_items(const monsters *mon);
bool mons_has_lifeforce(const monsters *mon);
bool mons_eats_corpses(const monsters *m);
monster_type mons_genus(int mc);
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index da3f64f1e5..d5a682c4b9 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -1197,6 +1197,9 @@ static int _place_monster_aux(const mgen_data &mg,
if (mg.behaviour == BEH_NEUTRAL)
menv[id].attitude = ATT_NEUTRAL;
+ if (mg.behaviour == BEH_STRICT_NEUTRAL)
+ menv[id].attitude = ATT_STRICT_NEUTRAL;
+
menv[id].behaviour = BEH_WANDER;
}
@@ -2230,8 +2233,11 @@ int mons_place(mgen_data mg)
if (mg.behaviour == BEH_FRIENDLY)
creation->flags |= MF_CREATED_FRIENDLY;
- if (mg.behaviour == BEH_NEUTRAL || mg.behaviour == BEH_GOOD_NEUTRAL)
+ if (mg.behaviour == BEH_NEUTRAL || mg.behaviour == BEH_GOOD_NEUTRAL
+ || mg.behaviour == BEH_STRICT_NEUTRAL)
+ {
creation->flags |= MF_WAS_NEUTRAL;
+ }
if (mg.behaviour == BEH_CHARMED)
{
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index a6c288e72a..46716b0437 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -47,6 +47,7 @@ REVISION("$Rev$");
#include "monspeak.h"
#include "mon-pick.h"
#include "mon-util.h"
+#include "mutation.h"
#include "mstuff2.h"
#include "notes.h"
#include "player.h"
@@ -78,6 +79,7 @@ static bool _is_trap_safe(const monsters *monster, const coord_def& where,
bool just_check = false);
static bool _monster_move(monsters *monster);
static spell_type _map_wand_to_mspell(int wand_type);
+static bool _is_item_jelly_edible(const item_def &item);
static bool _try_pathfind(monsters *mon, const dungeon_feature_type can_move,
bool potentially_blocking);
@@ -759,6 +761,21 @@ static bool _monster_avoided_death(monsters *monster, killer_type killer, int i)
return (false);
}
+static bool _remove_jiyva_altars()
+{
+ bool success = false;
+ for (rectangle_iterator ri(1); ri; ++ri)
+ {
+ if (grd(*ri) == DNGN_ALTAR_JIYVA)
+ {
+ grd(*ri) = DNGN_FLOOR;
+ success = true;
+ }
+ }
+
+ return (success);
+}
+
static bool _slime_pit_unlock(bool silent)
{
unset_level_flags(LFLAG_NO_TELE_CONTROL, silent);
@@ -793,6 +810,9 @@ static bool _slime_pit_unlock(bool silent)
}
}
+ apply_to_all_dungeons(_remove_jiyva_altars);
+ mpr("With infernal noise, the power ruling this place vanishes!");
+
return (true);
}
@@ -1372,6 +1392,12 @@ int monster_die(monsters *monster, killer_type killer,
did_god_conduct(DID_KILL_HOLY, monster->hit_dice,
true, monster);
}
+
+ if (mons_is_slime(monster))
+ {
+ did_god_conduct(DID_KILL_SLIME, monster->hit_dice,
+ true, monster);
+ }
}
// Divine health and mana restoration doesn't happen when
@@ -2043,6 +2069,19 @@ bool monster_polymorph(monsters *monster, monster_type targetc,
str_polymon = " changes into ";
else if (targetc == MONS_PULSATING_LUMP)
str_polymon = " degenerates into ";
+ else if (you.religion == GOD_JIYVA
+ && (targetc == MONS_OOZE
+ || targetc == MONS_JELLY
+ || targetc == MONS_BROWN_OOZE
+ || targetc == MONS_ACID_BLOB
+ || targetc == MONS_GIANT_AMOEBA
+ || targetc == MONS_SLIME_CREATURE
+ || targetc == MONS_DEATH_OOZE
+ || targetc == MONS_AZURE_JELLY))
+ {
+ // Message used for the Slimify ability.
+ str_polymon = " quivers uncontrollably and liquefies into ";
+ }
else
str_polymon = " evaporates and reforms as ";
@@ -2337,6 +2376,34 @@ static void _set_random_target(monsters* mon)
}
}
+static void _set_random_slime_target(monsters* mon)
+{
+ // Strictly neutral slimes will go for the nearest item
+ int item_idx;
+ coord_def orig_target = mon->target;
+
+ for (radius_iterator ri(mon->pos(), LOS_RADIUS, true, false); ri; ++ri)
+ {
+ item_idx = igrd(*ri);
+ if (item_idx != NON_ITEM)
+ {
+ for (stack_iterator si(*ri); si; ++si)
+ {
+ item_def& item(*si);
+
+ if (_is_item_jelly_edible(item))
+ {
+ mon->target = *ri;
+ break;
+ }
+ }
+ }
+ }
+
+ if (mon->target == mon->pos() || mon->target == you.pos())
+ _set_random_target(mon);
+}
+
// allow_adjacent: allow target to be adjacent to origin.
// restrict_LOS: restrict target to be within PLAYER line of sight.
bool random_near_space(const coord_def& origin, coord_def& target,
@@ -4360,6 +4427,12 @@ static void _handle_behaviour(monsters *mon)
return;
}
+ if (mons_strict_neutral(mon) && mons_is_slime(mon)
+ && you.religion == GOD_JIYVA)
+ {
+ _set_random_slime_target(mon);
+ }
+
// Is our foe in LOS?
// Batty monsters don't automatically reseek so that
// they'll flitter away, we'll reset them just before
@@ -7323,11 +7396,12 @@ static void _handle_monster_move(monsters *monster)
if (igrd(monster->pos()) != NON_ITEM
&& (mons_itemuse(monster) == MONUSE_WEAPONS_ARMOUR
- || mons_itemuse(monster) == MONUSE_EATS_ITEMS))
+ || mons_eats_items(monster)))
{
// Keep neutral and charmed monsters from picking up stuff.
// Same for friendlies if friendly_pickup is set to "none".
if (!mons_neutral(monster) && !monster->has_ench(ENCH_CHARM)
+ || (you.religion == GOD_JIYVA && mons_is_slime(monster))
&& (!mons_friendly(monster)
|| you.friendly_pickup > FRIENDLY_PICKUP_NONE))
{
@@ -7662,10 +7736,10 @@ static bool _handle_pickup(monsters *monster)
const bool monster_nearby = mons_near(monster);
- if (mons_itemuse(monster) == MONUSE_EATS_ITEMS)
+ if (mons_eats_items(monster))
{
- // Friendly jellies won't eat.
- if (monster->attitude != ATT_HOSTILE)
+ // Friendly jellies won't eat (unless worshiping Jiyva).
+ if (monster->attitude != ATT_HOSTILE && you.religion != GOD_JIYVA)
return (false);
int hps_gained = 0;
@@ -7714,6 +7788,61 @@ static bool _handle_pickup(monsters *monster)
eaten++;
}
+ if (you.religion == GOD_JIYVA)
+ {
+ const item_def& item = *si;
+ const int value = item_value(item) / item.quantity;
+ const int quantity = item.quantity;
+
+ int pg = 0;
+ int timeout = 0;
+ for (int m = 0; m < quantity; m++)
+ {
+ if (x_chance_in_y(value/2 + 1, 30 + you.piety/4))
+ {
+ if (timeout <= 0)
+ pg += random2(item_value(item)/6);
+ else
+ timeout -= value/5;
+ }
+ }
+
+ if (pg > 0)
+ {
+ mprf(MSGCH_GOD, "Jiyva appreciates your sacrifice.");
+ gain_piety(pg);
+ }
+
+ if (you.piety > 80
+ && random2(you.piety) > 50
+ && one_chance_in(4))
+ {
+ bool success = false;
+ if (!you.is_undead)
+ {
+ simple_god_message(" alters your body.");
+ more();
+
+ const int rand = random2(100);
+ if (rand < 40)
+ success = mutate(RANDOM_MUTATION);
+ else if (rand < 60)
+ success = delete_mutation(RANDOM_MUTATION);
+ else
+ success = mutate(RANDOM_GOOD_MUTATION);
+ }
+
+ if (success)
+ {
+ timeout = (100 + roll_dice(2, 4));
+ you.num_gifts[you.religion]++;
+ take_note(Note(NOTE_GOD_GIFT, you.religion));
+ }
+ else
+ mpr("You feel as though nothing has changed.");
+ }
+ }
+
if (quant >= si->quantity)
item_was_destroyed(*si, monster->mindex());
diff --git a/crawl-ref/source/monstuff.h b/crawl-ref/source/monstuff.h
index 899e304abd..6f8e3bab95 100644
--- a/crawl-ref/source/monstuff.h
+++ b/crawl-ref/source/monstuff.h
@@ -51,10 +51,11 @@ public:
#define MON_KILL(x) ((x) == KILL_MON || (x) == KILL_MON_MISSILE)
// useful macro
-#define SAME_ATTITUDE(x) (mons_friendly_real(x) ? BEH_FRIENDLY : \
- mons_good_neutral(x) ? BEH_GOOD_NEUTRAL : \
- mons_neutral(x) ? BEH_NEUTRAL \
- : BEH_HOSTILE)
+#define SAME_ATTITUDE(x) (mons_friendly_real(x) ? BEH_FRIENDLY : \
+ mons_good_neutral(x) ? BEH_GOOD_NEUTRAL : \
+ mons_strict_neutral(x) ? BEH_STRICT_NEUTRAL : \
+ mons_neutral(x) ? BEH_NEUTRAL \
+ : BEH_HOSTILE)
#define MONST_INTERESTING(x) (x->flags & MF_INTERESTING)
diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc
index c5c65c21b5..87a8cdad14 100644
--- a/crawl-ref/source/newgame.cc
+++ b/crawl-ref/source/newgame.cc
@@ -95,6 +95,7 @@ static void _give_random_secondary_armour(int slot);
static bool _give_wanderer_weapon(int slot, int wpn_skill);
static void _create_wanderer(void);
static bool _give_items_skills(void);
+static void _fix_up_god_name(void);
////////////////////////////////////////////////////////////////////////
// Remember player's startup options
@@ -1378,6 +1379,9 @@ game_start:
_initialise_branch_depths();
init_level_connectivity();
+ //Generate the second name of Jiyva
+ _fix_up_god_name();
+
_save_newgame_options();
return (true);
}
@@ -2860,6 +2864,10 @@ static void _jobs_stat_init(job_type which_job)
modify_all_stats( s, i, d );
+ // Used for Jiyva's stat swapping if the player has not reached
+ // experience level 3.
+ you.last_chosen = (stat_type) random2(NUM_STATS);
+
set_hp( hp, true );
set_mp( mp, true );
}
@@ -4295,6 +4303,17 @@ bool _needs_butchering_tool()
return (true);
}
+static void _fix_up_god_name()
+{
+ do
+ you.second_god_name = make_name(random_int(), false, 8, 'J');
+ while (strncmp(you.second_god_name.c_str(), "J", 1) != 0);
+
+ you.second_god_name = replace_all(you.second_god_name, " ", "");
+}
+
+
+
static startup_wand_type _wand_to_start(int wand, bool is_rod)
{
if (!is_rod)
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index 2bb95ce7d6..ac3d8bc96d 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -39,6 +39,7 @@ REVISION("$Rev$");
#include "artefact.h"
#include "chardump.h"
#include "delay.h"
+#include "effects.h"
#include "files.h"
#include "fight.h"
#include "hiscores.h"
@@ -50,6 +51,7 @@ REVISION("$Rev$");
#include "message.h"
#include "misc.h"
#include "mon-util.h"
+#include "monplace.h"
#include "monstuff.h"
#include "notes.h"
#include "output.h"
@@ -259,6 +261,7 @@ void splash_with_acid(int acid_strength, bool corrode_items)
_item_corrode(you.equip[slot]);
}
+
if (dam > 0)
{
const int post_res_dam = dam * player_acid_resist_factor() / 100;
@@ -310,6 +313,9 @@ void _item_corrode(int slot)
return;
}
+ if (you.religion == GOD_JIYVA && x_chance_in_y(you.piety, MAX_PIETY))
+ return;
+
int how_rusty = ((item.base_type == OBJ_WEAPONS) ? item.plus2 : item.plus);
// Already very rusty.
if (how_rusty < -5)
@@ -828,6 +834,65 @@ static void _yred_mirrors_injury(int dam, int death_source)
}
}
+static void _maybe_spawn_jellies(int dam, const char* aux,
+ kill_method_type death_type, int death_source)
+{
+ // We need to exclude acid damage and similar things or this function
+ // will crash later.
+ if (death_source == NON_MONSTER)
+ return;
+
+ monster_type mons;
+ const monster_type jellies[] = {
+ MONS_ACID_BLOB, MONS_AZURE_JELLY,
+ MONS_DEATH_OOZE
+ };
+
+ // Exclude torment damage
+ char *ptr = strstr(aux, "torment");
+ if (you.religion == GOD_JIYVA && you.piety >= 160 && ptr == NULL)
+ {
+ int how_many = 0;
+ if (dam >= you.hp_max * 0.75)
+ how_many = random2(4) + 2;
+ else if(dam >= you.hp_max / 2)
+ how_many = random2(2) + 2;
+ else if(dam >= you.hp_max / 4)
+ how_many = random2(1) + 1;
+
+ if (how_many > 0)
+ {
+ if (x_chance_in_y(how_many, 8)
+ && !lose_stat(STAT_STRENGTH, 1, true, "spawning slimes"))
+ {
+ canned_msg(MSG_NOTHING_HAPPENS);
+ return;
+ }
+
+ int count_created = 0;
+ for (int i = 0; i < how_many; ++i)
+ {
+ mons = RANDOM_ELEMENT(jellies);
+ mgen_data mg (mons, BEH_STRICT_NEUTRAL, 0, 0, you.pos(),
+ MHITNOT, 0, GOD_JIYVA);
+
+ if (create_monster(mg) != -1)
+ count_created++;
+ }
+
+ if (count_created > 0)
+ {
+ mprf("You shudder from the %s and a %s!",
+ death_type == KILLED_BY_MONSTER ? "blow" : "blast",
+ count_created > 1 ? "flood of jellies pours out from you"
+ : "jelly pops out");
+ }
+ }
+ }
+}
+
+
+
static void _wizard_restore_life()
{
if (you.hp <= 0)
@@ -932,6 +997,7 @@ void ouch(int dam, int death_source, kill_method_type death_type,
Note(NOTE_HP_CHANGE, you.hp, you.hp_max, damage_desc.c_str()) );
_yred_mirrors_injury(dam, death_source);
+ _maybe_spawn_jellies(dam, aux, death_type, death_source);
return;
} // else hp <= 0
diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc
index 81cc4a51ac..d2d5eb7cd4 100644
--- a/crawl-ref/source/output.cc
+++ b/crawl-ref/source/output.cc
@@ -1029,7 +1029,12 @@ void redraw_skill(const std::string &your_name, const std::string &class_name)
nowrap_eol_cprintf("Level %d %s", you.experience_level,
species_name(you.species,you.experience_level).c_str());
if (you.religion != GOD_NO_GOD)
- nowrap_eol_cprintf(" of %s", god_name(you.religion).c_str());
+ {
+ nowrap_eol_cprintf(" of %s",
+ you.religion == GOD_JIYVA ? god_name_jiyva(true).c_str()
+ : god_name(you.religion).c_str());
+ }
+
clear_to_end_of_line();
textcolor( LIGHTGREY );
@@ -1319,8 +1324,12 @@ static std::string _verbose_info(const monsters* m)
else
return(" (sleeping)");
}
- if (mons_is_wandering(m) && !mons_is_batty(m))
+ if (mons_is_wandering(m) && !mons_is_batty(m)
+ && !(m->attitude == ATT_STRICT_NEUTRAL))
+ {
+ // Labeling strictly neutral monsters as fellow slimes is more important.
return(" (wandering)");
+ }
if (m->foe == MHITNOT && !mons_is_batty(m) && !mons_neutral(m)
&& !mons_friendly(m))
{
@@ -1409,6 +1418,10 @@ void monster_pane_info::to_string( int count, std::string& desc,
//out << " (neutral)";
desc_color = BROWN;
break;
+ case ATT_STRICT_NEUTRAL:
+ out << " (fellow slime)";
+ desc_color = BROWN;
+ break;
case ATT_HOSTILE:
// out << " (hostile)";
desc_color = LIGHTGREY;
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 853da7983e..09c925f2d2 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -21,6 +21,7 @@ REVISION("$Rev$");
#include <ctype.h>
#include <sstream>
+#include <algorithm>
#include "externs.h"
@@ -1554,6 +1555,9 @@ int player_res_acid(bool calc_unid, bool items)
res++;
}
+ if (you.religion == GOD_JIYVA && x_chance_in_y(you.piety, MAX_PIETY))
+ res++;
+
return (res);
}
@@ -3770,21 +3774,65 @@ static void _attribute_increase()
case 's':
case 'S':
modify_stat(STAT_STRENGTH, 1, false, "level gain");
+ you.last_chosen = STAT_STRENGTH;
return;
case 'i':
case 'I':
modify_stat(STAT_INTELLIGENCE, 1, false, "level gain");
+ you.last_chosen = STAT_INTELLIGENCE;
return;
case 'd':
case 'D':
modify_stat(STAT_DEXTERITY, 1, false, "level gain");
+ you.last_chosen = STAT_DEXTERITY;
return;
}
}
}
+// Rearrange stats, biased towards the stat chosen last at level up.
+void jiyva_stat_action()
+{
+ char* max_statp[] = { &you.max_strength, &you.max_intel, &you.max_dex };
+ char* base_statp[] = { &you.strength, &you.intel, &you.dex };
+ int incremented_weight[] = {1, 1, 1};
+ int decremented_weight[3];
+ int stat_up_choice;
+ int stat_down_choice;
+
+ incremented_weight[you.last_chosen] = 2;
+
+ for (int x = 0; x < 3; ++x)
+ decremented_weight[x] = std::min(10, std::max(0, *max_statp[x] - 7));
+
+ stat_up_choice = choose_random_weighted(incremented_weight,
+ incremented_weight + 3);
+ stat_down_choice = choose_random_weighted(decremented_weight,
+ decremented_weight + 3);
+
+ if (stat_up_choice != stat_down_choice)
+ {
+ // We have a stat change noticeable to the player at this point.
+ // This could be lethal if the player currently has 1 in a stat
+ // but has a max stat of something higher -- perhaps we should
+ // check for that?
+
+ (*max_statp[stat_up_choice])++;
+ (*max_statp[stat_down_choice])--;
+ (*base_statp[stat_up_choice])++;
+ (*base_statp[stat_down_choice])--;
+
+ mprf(MSGCH_GOD, "Jiyva's power touches on your attributes.");
+ you.redraw_strength = true;
+ you.redraw_intelligence = true;
+ you.redraw_dexterity = true;
+
+ burden_change();
+ }
+}
+
static const char * _get_rotting_how()
{
ASSERT(you.rotting > 0 || you.species == SP_GHOUL);
@@ -4417,6 +4465,9 @@ bool extrinsic_amulet_effect(jewellery_type amulet)
case AMU_CLARITY:
return (player_mutation_level(MUT_CLARITY) > 0);
case AMU_RESIST_CORROSION:
+ if (you.religion == GOD_JIYVA && you.piety > piety_breakpoint(2))
+ return (true);
+ // else fall-through
case AMU_CONSERVATION:
return (player_equip_ego_type(EQ_CLOAK, SPARM_PRESERVATION) > 0);
case AMU_THE_GOURMAND:
@@ -6057,6 +6108,7 @@ player_save_info player_save_info::operator=(const player& rhs)
species = rhs.species;
class_name = rhs.class_name;
religion = rhs.religion;
+ second_god_name = rhs.second_god_name;
#ifdef USE_TILE
held_in_net = false;
#endif
@@ -6077,7 +6129,9 @@ std::string player_save_info::short_desc() const
<< species_name(species, experience_level) << ' '
<< class_name;
- if (religion != GOD_NO_GOD)
+ if (religion == GOD_JIYVA)
+ desc << " of " << god_name_jiyva(true);
+ else if (religion != GOD_NO_GOD)
desc << " of " << god_name(religion);
#ifdef WIZARD
diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h
index 308d20572f..d88baf8747 100644
--- a/crawl-ref/source/player.h
+++ b/crawl-ref/source/player.h
@@ -36,6 +36,7 @@ struct player_save_info
species_type species;
std::string class_name;
god_type religion;
+ std::string second_god_name;
#ifdef USE_TILE
dolls_data doll;
bool held_in_net;
@@ -285,6 +286,7 @@ bool player_knows_spell(int spell);
* called from: effects
* *********************************************************************** */
int player_sust_abil(bool calc_unid = true);
+void jiyva_stat_action();
/* ***********************************************************************
diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc
index 893853c075..303acc7774 100644
--- a/crawl-ref/source/religion.cc
+++ b/crawl-ref/source/religion.cc
@@ -191,6 +191,12 @@ static const char *_Sacrifice_Messages[NUM_GODS][NUM_PIETY_GAIN] =
" slowly crumble% into the ground.",
" crumble% into the ground.",
" disintegrate% into the ground.",
+ },
+ // Jiyva
+ {
+ " slowly dissolve% into ooze.",
+ " dissolve% into ooze .",
+ " disappear% with a satisfied slurp.",
}
};
@@ -277,7 +283,14 @@ const char* god_gain_power_messages[NUM_GODS][MAX_GOD_ABILITIES] =
"smite your foes",
"gain orcish followers",
"recall your orcish followers",
- "walk on water" }
+ "walk on water" },
+ // Jiyva
+ { "request a jelly",
+ "",
+ "",
+ "turn your enemies to slime",
+ "call upon Jiyva to remove your harmful mutations"
+ }
};
const char* god_lose_power_messages[NUM_GODS][MAX_GOD_ABILITIES] =
@@ -363,7 +376,14 @@ const char* god_lose_power_messages[NUM_GODS][MAX_GOD_ABILITIES] =
"smite your foes",
"gain orcish followers",
"recall your orcish followers",
- "walk on water" }
+ "walk on water" },
+ // Jiyva
+ { "request a jelly",
+ "summon a protective jelly shield via prayer",
+ "",
+ "turn your foes to slime",
+ "call upon Jiyva to remove bad mutations"
+ }
};
static bool _holy_beings_attitude_change();
@@ -448,7 +468,8 @@ bool is_chaotic_god(god_type god)
{
return (god == GOD_XOM
|| god == GOD_MAKHLEB
- || god == GOD_LUGONU);
+ || god == GOD_LUGONU
+ || god == GOD_JIYVA);
}
bool is_priest_god(god_type god)
@@ -509,6 +530,14 @@ std::string get_god_likes(god_type which_god, bool verbose)
likes.push_back(info);
break;
+ case GOD_JIYVA:
+ snprintf(info, INFO_SIZE, "you sacrifice items%s",
+ verbose ? " by allowing slimes to consume them"
+ : "");
+
+ likes.push_back(info);
+ break;
+
default:
break;
}
@@ -742,6 +771,10 @@ std::string get_god_dislikes(god_type which_god, bool /*verbose*/)
dislikes.push_back("you attack allied orcs");
break;
+ case GOD_JIYVA:
+ dislikes.push_back("you attack your fellow slimes");
+ break;
+
default:
break;
}
@@ -789,6 +822,10 @@ std::string get_god_dislikes(god_type which_god, bool /*verbose*/)
dislikes.push_back("you destroy orcish idols");
break;
+ case GOD_JIYVA:
+ dislikes.push_back("you kill slimes");
+ break;
+
default:
break;
}
@@ -886,6 +923,13 @@ static bool _need_water_walking()
&& grd(you.pos()) == DNGN_DEEP_WATER);
}
+bool jiyva_grant_jelly(bool actual)
+{
+ return (you.religion == GOD_JIYVA && !player_under_penance()
+ && you.piety >= piety_breakpoint(2)
+ && (!actual || you.duration[DUR_PRAYER]));
+}
+
static void _inc_penance(god_type god, int val)
{
if (you.penance[god] == 0 && val > 0)
@@ -1295,6 +1339,21 @@ bool is_orcish_follower(const monsters* mon)
&& mons_is_god_gift(mon, GOD_BEOGH));
}
+bool _has_jelly()
+{
+ ASSERT(you.religion == GOD_JIYVA);
+
+ for (int i = 0; i < MAX_MONSTERS; ++i)
+ {
+ monsters *monster = &menv[i];
+ if (mons_is_god_gift(monster, GOD_JIYVA))
+ return (true);
+ }
+
+ return (false);
+}
+
+
bool is_good_lawful_follower(const monsters* mon)
{
return (mon->alive() && !mons_is_evil_or_unholy(mon)
@@ -1880,9 +1939,9 @@ static void _do_god_gift(bool prayed_for)
{
ASSERT(you.religion != GOD_NO_GOD);
- // Zin worshippers are the only ones who can pray to ask Zin for
- // stuff.
- if (prayed_for != (you.religion == GOD_ZIN))
+ // Zin and Jiyva worshippers are the only ones who can pray to ask their
+ // god for stuff.
+ if (prayed_for != (you.religion == GOD_ZIN || you.religion == GOD_JIYVA))
return;
god_acting gdact;
@@ -1894,7 +1953,7 @@ static void _do_god_gift(bool prayed_for)
// Consider a gift if we don't have a timeout and weren't already
// praying when we prayed.
if (!player_under_penance() && !you.gift_timeout
- || (prayed_for && you.religion == GOD_ZIN))
+ || (prayed_for && you.religion == GOD_ZIN || you.religion == GOD_JIYVA))
{
bool success = false;
@@ -1978,6 +2037,50 @@ static void _do_god_gift(bool prayed_for)
}
break;
+ case GOD_JIYVA:
+ if (prayed_for && jiyva_grant_jelly())
+ {
+ int jelly_count = 0;
+ for (radius_iterator ri(you.pos(), 9); ri; ++ri)
+ {
+ int item = igrd(*ri);
+
+ if (item != NON_ITEM)
+ {
+ for (stack_iterator si(*ri); si; ++si)
+ if (si != NON_ITEM && one_chance_in(7))
+ jelly_count++;
+ }
+ }
+
+ if (jelly_count >= 1)
+ {
+ int count_created = 0;
+ for (; jelly_count > 0; --jelly_count)
+ {
+ mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0,
+ you.pos(), MHITNOT, 0, GOD_JIYVA);
+
+ if (create_monster(mg) != -1)
+ count_created++;
+
+ // Sanity check: Stop if spawning further jellies
+ // would excommunicate us.
+ if (you.piety - (count_created+1) * 5 <= 0)
+ break;
+ }
+
+ if (count_created > 0)
+ {
+ mprf(MSGCH_PRAY, "%s!",
+ count_created > 1 ? "Some jellies appear"
+ : "A jelly appears");
+ }
+ you.piety -= 5 * count_created;
+ }
+ }
+ break;
+
case GOD_KIKUBAAQUDGHA:
case GOD_SIF_MUNA:
case GOD_VEHUMET:
@@ -2152,6 +2255,9 @@ static bool _god_accepts_prayer(god_type god)
case GOD_YREDELEMNUL:
return (yred_injury_mirror(false));
+ case GOD_JIYVA:
+ return (jiyva_grant_jelly(false));
+
case GOD_BEOGH:
case GOD_NEMELEX_XOBEH:
return (true);
@@ -2251,7 +2357,7 @@ void pray()
}
if (you.religion == GOD_ZIN || you.religion == GOD_BEOGH
- || you.religion == GOD_NEMELEX_XOBEH)
+ || you.religion == GOD_NEMELEX_XOBEH || you.religion == GOD_JIYVA)
{
you.duration[DUR_PRAYER] = 1;
}
@@ -2301,6 +2407,12 @@ std::string god_name( god_type which_god, bool long_name )
case GOD_ELYVILON: return (long_name ? "Elyvilon the Healer" : "Elyvilon");
case GOD_LUGONU: return (long_name ? "Lugonu the Unformed" : "Lugonu");
case GOD_BEOGH: return (long_name ? "Beogh the Brigand" : "Beogh");
+ case GOD_JIYVA:
+ if (long_name)
+ {
+ return god_name_jiyva(true) + " the Shapeless";
+ }
+ return god_name_jiyva(false);
case GOD_XOM:
if (!long_name)
@@ -2327,6 +2439,15 @@ std::string god_name( god_type which_god, bool long_name )
return ("");
}
+std::string god_name_jiyva(bool second_name)
+{
+ std::string name = "Jiyva";
+ if (second_name)
+ name += " " + you.second_god_name;
+
+ return (name);
+}
+
god_type string_to_god(const char *_name, bool exact)
{
std::string target(_name);
@@ -2535,6 +2656,15 @@ bool did_god_conduct(conduct_type thing_done, int level, bool known,
}
break;
+ case DID_KILL_SLIME:
+ if (you.religion == GOD_JIYVA)
+ {
+ retval = true;
+ piety_change = -level;
+ penance = level * 2;
+ }
+ break;
+
case DID_ATTACK_NEUTRAL:
switch (you.religion)
{
@@ -2559,6 +2689,15 @@ bool did_god_conduct(conduct_type thing_done, int level, bool known,
retval = true;
break;
+ case GOD_JIYVA:
+ if (mons_is_slime(victim))
+ {
+ piety_change = -(level/2 + 3);
+ penance = level/2 + 3;
+ retval = true;
+ }
+ break;
+
default:
break;
}
@@ -3167,7 +3306,7 @@ bool did_god_conduct(conduct_type thing_done, int level, bool known,
"Drink Blood", "Cannibalism", "Eat Meat", "Eat Souled Being",
"Deliberate Mutation", "Cause Glowing", "Use Chaos",
"Desecrate Orcish Remains", "Destroy Orcish Idol",
- "Create Life"
+ "Create Life", "Kill Slime"
};
COMPILE_CHECK(ARRAYSZ(conducts) == NUM_CONDUCTS, c1);
@@ -4974,6 +5113,51 @@ static bool _nemelex_retribution()
return (true);
}
+static bool _jiyva_retribution()
+{
+ const god_type god = GOD_JIYVA;
+
+ if (you.is_undead || one_chance_in(4)
+ || player_mutation_level(MUT_MUTATION_RESISTANCE) == 3)
+ {
+ const monster_type slimes[] = {
+ MONS_GIANT_EYEBALL, MONS_EYE_OF_DRAINING,
+ MONS_EYE_OF_DEVASTATION, MONS_GREAT_ORB_OF_EYES,
+ MONS_GIANT_SPORE, MONS_SHINING_EYE, MONS_GIANT_ORANGE_BRAIN,
+ MONS_JELLY, MONS_BROWN_OOZE, MONS_ACID_BLOB, MONS_AZURE_JELLY,
+ MONS_DEATH_OOZE, MONS_SLIME_CREATURE
+ };
+
+ const int how_many = 1 + (you.experience_level / 10) + random2(3);
+
+ bool success = false;
+ for (int i = 0; i < how_many; ++i)
+ {
+ const monster_type mon = RANDOM_ELEMENT(slimes);
+
+ if (create_monster(
+ mgen_data::hostile_at( static_cast<monster_type>(mon),
+ you.pos(), 0, 0, true, god)) != -1)
+ {
+ success = true;
+ }
+ }
+
+ if (success)
+ god_speaks(god, "Some slimes ooze up out of the ground!");
+ else
+ simple_god_message("The ground quivers slightly.");
+ }
+ else
+ {
+ const int mutat = 1 + random2(4);
+ god_speaks(god, "You feel Jiyva alter your body.");
+ for (int i = 0; i < mutat; ++i)
+ mutate(RANDOM_BAD_MUTATION, true, true, true);
+ }
+ return (true);
+}
+
bool divine_retribution( god_type god )
{
ASSERT(god != GOD_NO_GOD);
@@ -5008,6 +5192,7 @@ bool divine_retribution( god_type god )
case GOD_NEMELEX_XOBEH: do_more = _nemelex_retribution(); break;
case GOD_SIF_MUNA: do_more = _sif_muna_retribution(); break;
case GOD_ELYVILON: do_more = _elyvilon_retribution(); break;
+ case GOD_JIYVA: do_more = _jiyva_retribution(); break;
default:
#if DEBUG_DIAGNOSTICS || DEBUG_RELIGION
@@ -5934,6 +6119,38 @@ void beogh_convert_orc(monsters *orc, bool emergency,
behaviour_event(orc, ME_ALERT, MHITNOT);
}
+void jiyva_convert_slime(monsters* slime)
+{
+ ASSERT(mons_is_slime(slime));
+
+ if (you.can_see(slime))
+ {
+ if (mons_genus(slime->type) == MONS_GIANT_EYEBALL)
+ {
+ mprf(MSGCH_GOD, "%s stares at you suspiciously for a moment, "
+ "then relaxes.",
+ slime->name(DESC_CAP_THE).c_str());
+ }
+ else
+ {
+ mprf(MSGCH_GOD, "%s trembles before you.",
+ slime->name(DESC_CAP_THE).c_str());
+ }
+ }
+ slime->attitude = ATT_STRICT_NEUTRAL;
+ slime->flags |= MF_WAS_NEUTRAL;
+ slime->god = GOD_JIYVA;
+
+ if (mons_itemuse(slime) != MONUSE_EATS_ITEMS)
+ {
+ slime->add_ench(ENCH_EATS_ITEMS);
+ mprf(MSGCH_MONSTER_ENCHANT, "%s looks hungrier.",
+ slime->name(DESC_CAP_THE).c_str());
+ }
+
+ mons_make_god_gift(slime, GOD_JIYVA);
+}
+
void excommunication(god_type new_god)
{
const god_type old_god = you.religion;
@@ -6101,6 +6318,14 @@ void excommunication(god_type new_god)
}
break;
+ case GOD_JIYVA:
+ for (int i = 0; i < 3; i++)
+ mutate(RANDOM_BAD_MUTATION);
+
+ _make_god_gifts_hostile(false);
+ _inc_penance(old_god, 30);
+ break;
+
default:
_inc_penance(old_god, 25);
break;
@@ -6309,7 +6534,12 @@ bool god_hates_attacking_friend(god_type god, int species)
case GOD_OKAWARU:
return (true);
case GOD_BEOGH: // added penance to avoid killings for loot
- return (species == MONS_ORC);
+ return (mons_genus(species) == MONS_ORC);
+ case GOD_JIYVA:
+ return (mons_genus(species) == MONS_JELLY
+ || mons_genus(species) == MONS_GIANT_EYEBALL
+ || species == MONS_GIANT_SPORE
+ || species == MONS_GIANT_ORANGE_BRAIN);
default:
return (false);
@@ -6804,6 +7034,33 @@ void god_pitch(god_type which_god)
if (you.religion == GOD_LUGONU && you.worshipped[GOD_LUGONU] == 1)
gain_piety(20); // allow instant access to first power
+ // Complimentary jelly upon joining
+ if (you.religion == GOD_JIYVA && !_has_jelly())
+ {
+ monster_type mon = MONS_JELLY;
+ mgen_data mg(mon, BEH_STRICT_NEUTRAL, 0, 0, you.pos(), MHITNOT, 0,
+ GOD_JIYVA);
+
+ _delayed_monster(mg);
+ simple_god_message(" grants you a jelly!");
+
+ if (level_id::current() == level_id(BRANCH_SLIME_PITS, 6))
+ {
+ const level_id target(BRANCH_SLIME_PITS, 6);
+ bool done = apply_to_level(target, true, slime_vault_to_floor);
+ if (done)
+ {
+ if (silenced(you.pos()))
+ {
+ mpr("An unexplained breeze blows through the dungeon.",
+ MSGCH_GOD);
+ }
+ else
+ mpr("You hear the sound of toppling stones.", MSGCH_GOD);
+ }
+ }
+ }
+
redraw_skill(you.your_name, player_title());
learned_something_new(TUT_CONVERT);
@@ -7050,31 +7307,30 @@ void handle_god_time()
{
case GOD_XOM:
xom_tick();
- break;
+ return;
// These gods like long-standing worshippers.
case GOD_ELYVILON:
if (_need_free_piety() && one_chance_in(20))
gain_piety(1);
- break;
+ return;
case GOD_SHINING_ONE:
if (_need_free_piety() && one_chance_in(15))
gain_piety(1);
- break;
+ return;
case GOD_ZIN:
if (_need_free_piety() && one_chance_in(12))
gain_piety(1);
- break;
+ return;
+ // All the rest will excommunicate you if piety goes below 1.
case GOD_YREDELEMNUL:
case GOD_KIKUBAAQUDGHA:
case GOD_VEHUMET:
if (one_chance_in(17))
lose_piety(1);
- if (you.piety < 1)
- excommunication();
break;
// These gods accept corpses, so they time-out faster.
@@ -7082,8 +7338,6 @@ void handle_god_time()
case GOD_TROG:
if (one_chance_in(14))
lose_piety(1);
- if (you.piety < 1)
- excommunication();
break;
case GOD_MAKHLEB:
@@ -7091,8 +7345,6 @@ void handle_god_time()
case GOD_LUGONU:
if (one_chance_in(16))
lose_piety(1);
- if (you.piety < 1)
- excommunication();
break;
case GOD_SIF_MUNA:
@@ -7101,8 +7353,6 @@ void handle_god_time()
// it's practically impossible to get Master of Arcane status.
if (one_chance_in(100))
lose_piety(1);
- if (you.piety < 1)
- excommunication();
break;
case GOD_NEMELEX_XOBEH:
@@ -7111,13 +7361,19 @@ void handle_god_time()
lose_piety(1);
if (you.attribute[ATTR_CARD_COUNTDOWN] > 0 && coinflip())
you.attribute[ATTR_CARD_COUNTDOWN]--;
- if (you.piety < 1)
- excommunication();
+ break;
+
+ case GOD_JIYVA:
+ if (one_chance_in(20))
+ lose_piety(1);
break;
default:
DEBUGSTR("Bad god, no bishop!");
+ return;
}
+ if (you.piety < 1)
+ excommunication();
}
}
@@ -7157,6 +7413,9 @@ int god_colour(god_type god) // mv - added
case GOD_SIF_MUNA:
return(LIGHTBLUE);
+ case GOD_JIYVA:
+ return(GREEN);
+
case GOD_NO_GOD:
case NUM_GODS:
case GOD_RANDOM:
diff --git a/crawl-ref/source/religion.h b/crawl-ref/source/religion.h
index 80b26db688..433bf4c636 100644
--- a/crawl-ref/source/religion.h
+++ b/crawl-ref/source/religion.h
@@ -58,6 +58,7 @@ bool is_priest_god(god_type god);
void simple_god_message(const char *event, god_type which_deity = you.religion);
int piety_breakpoint(int i);
std::string god_name(god_type which_god, bool long_name = false);
+std::string god_name_jiyva(bool second_name = false);
god_type string_to_god(const char *name, bool exact = true);
std::string get_god_powers(god_type which_god);
@@ -102,6 +103,7 @@ bool divine_retribution(god_type god);
bool zin_sustenance(bool actual = true);
bool zin_remove_all_mutations();
bool yred_injury_mirror(bool actual = true);
+bool jiyva_grant_jelly(bool actual = true);
bool beogh_water_walk();
void good_god_holy_attitude_change(monsters *holy);
void good_god_holy_fail_attitude_change(monsters *holy);
@@ -109,6 +111,7 @@ void yred_make_enslaved_soul(monsters *mon, bool force_hostile = false,
bool quiet = false, bool unrestricted = false);
void beogh_convert_orc(monsters *orc, bool emergency,
bool converted_by_follower = false);
+void jiyva_convert_slime(monsters* slime);
bool is_holy_item(const item_def& item);
bool is_evil_item(const item_def& item);
bool is_chaotic_item(const item_def& item);
diff --git a/crawl-ref/source/rltiles/dc-dngn.txt b/crawl-ref/source/rltiles/dc-dngn.txt
index e28e83fb74..9ee9c62db5 100644
--- a/crawl-ref/source/rltiles/dc-dngn.txt
+++ b/crawl-ref/source/rltiles/dc-dngn.txt
@@ -451,6 +451,7 @@ dngn_altar_nemelex_xobeh DNGN_ALTAR_NEMELEX_XOBEH
dngn_altar_elyvilon DNGN_ALTAR_ELYVILON
dngn_altar_lugonu DNGN_ALTAR_LUGONU
dngn_altar_beogh DNGN_ALTAR_BEOGH
+dngn_altar_jiyva DNGN_ALTAR_JIYVA
%sdir dc-dngn
dngn_blue_fountain DNGN_BLUE_FOUNTAIN
diff --git a/crawl-ref/source/rltiles/dc-dngn/altars/dngn_altar_jiyva.png b/crawl-ref/source/rltiles/dc-dngn/altars/dngn_altar_jiyva.png
new file mode 100644
index 0000000000..bf17f44143
--- /dev/null
+++ b/crawl-ref/source/rltiles/dc-dngn/altars/dngn_altar_jiyva.png
Binary files differ
diff --git a/crawl-ref/source/spl-mis.cc b/crawl-ref/source/spl-mis.cc
index 747c80f09b..b729adddec 100644
--- a/crawl-ref/source/spl-mis.cc
+++ b/crawl-ref/source/spl-mis.cc
@@ -700,6 +700,7 @@ bool MiscastEffect::_create_monster(monster_type what, int abj_deg,
case ATT_HOSTILE: data.behaviour = BEH_FRIENDLY; break;
case ATT_GOOD_NEUTRAL:
case ATT_NEUTRAL:
+ case ATT_STRICT_NEUTRAL:
data.behaviour = BEH_NEUTRAL;
break;
}
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 7c804299b6..1ec80784d6 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -826,6 +826,7 @@ static void tag_construct_you(writer &th)
marshallString(th, you.your_name, 30);
marshallByte(th, you.religion);
+ marshallString(th, you.second_god_name);
marshallByte(th, you.piety);
marshallByte(th, you.rotting);
marshallByte(th, you.symbol);
@@ -867,6 +868,7 @@ static void tag_construct_you(writer &th)
marshallByte(th, you.strength);
marshallByte(th, you.intel);
marshallByte(th, you.dex);
+ marshallByte(th, you.last_chosen);
marshallByte(th, you.hit_points_regeneration);
marshallByte(th, you.magic_points_regeneration);
@@ -1236,6 +1238,10 @@ static void tag_read_you(reader &th, char minorVersion)
unmarshallCString(th, you.your_name, 30);
you.religion = static_cast<god_type>(unmarshallByte(th));
+
+ if (minorVersion >= TAG_MINOR_JIYVA)
+ you.second_god_name = unmarshallString(th);
+
you.piety = unmarshallByte(th);
you.rotting = unmarshallByte(th);
you.symbol = unmarshallByte(th);
@@ -1282,6 +1288,10 @@ static void tag_read_you(reader &th, char minorVersion)
you.strength = unmarshallByte(th);
you.intel = unmarshallByte(th);
you.dex = unmarshallByte(th);
+
+ if (minorVersion >= TAG_MINOR_JIYVA)
+ you.last_chosen = (stat_type) unmarshallByte(th);
+
you.hit_points_regeneration = unmarshallByte(th);
you.magic_points_regeneration = unmarshallByte(th);
diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h
index 41de2ed824..24f4f9f41d 100644
--- a/crawl-ref/source/tags.h
+++ b/crawl-ref/source/tags.h
@@ -64,7 +64,8 @@ enum tag_minor_version
TAG_MINOR_PORTEXT = 14, // Keep track of portal vault extensions.
TAG_MINOR_RELIGION = 15, // Keep track of ghosts' religions.
TAG_MINOR_ARTEFACT = 16, // Turned fixed arts into unrandarts.
- TAG_MINOR_VERSION = 16 // Current version. (Keep equal to max.)
+ TAG_MINOR_JIYVA = 17, // Addes some player bits for Jiyva.
+ TAG_MINOR_VERSION = 17 // Current version. (Keep equal to max.)
};
diff --git a/crawl-ref/source/tilepick.cc b/crawl-ref/source/tilepick.cc
index f5e31512fd..f47f0a44de 100644
--- a/crawl-ref/source/tilepick.cc
+++ b/crawl-ref/source/tilepick.cc
@@ -2456,6 +2456,7 @@ int tileidx_feature(int object, int gx, int gy)
case DNGN_ENTER_SWAMP:
case DNGN_ENTER_SHOALS:
return TILE_DNGN_ENTER;
+
case DNGN_RETURN_FROM_ORCISH_MINES:
case DNGN_RETURN_FROM_HIVE:
case DNGN_RETURN_FROM_LAIR:
@@ -2474,6 +2475,8 @@ int tileidx_feature(int object, int gx, int gy)
case DNGN_ENTER_PORTAL_VAULT:
case DNGN_EXIT_PORTAL_VAULT:
return TILE_DNGN_PORTAL;
+
+ // altars
case DNGN_ALTAR_ZIN:
return TILE_DNGN_ALTAR_ZIN;
case DNGN_ALTAR_SHINING_ONE:
@@ -2502,6 +2505,9 @@ int tileidx_feature(int object, int gx, int gy)
return TILE_DNGN_ALTAR_LUGONU;
case DNGN_ALTAR_BEOGH:
return TILE_DNGN_ALTAR_BEOGH;
+ case DNGN_ALTAR_JIYVA:
+ return TILE_DNGN_ALTAR_JIYVA;
+
case DNGN_FOUNTAIN_BLUE:
return TILE_DNGN_BLUE_FOUNTAIN;
case DNGN_FOUNTAIN_SPARKLING:
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 6deca847e6..433c882c66 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -965,6 +965,27 @@ void beogh_follower_convert(monsters *monster, bool orc_hit)
}
}
+void slime_conversion(monsters* monster)
+{
+ if (you.religion == GOD_JIYVA && mons_is_slime(monster)
+ && !mons_is_summoned(monster)
+ && !mons_is_shapeshifter(monster)
+ && !mons_neutral(monster)
+ && !mons_friendly(monster)
+ && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT)
+ && mons_player_visible(monster) && !mons_is_sleeping(monster)
+ && !mons_is_confused(monster) && !mons_is_paralysed(monster))
+
+ {
+ monster->flags |= MF_ATT_CHANGE_ATTEMPT;
+ if (!player_under_penance())
+ {
+ jiyva_convert_slime(monster);
+ stop_running();
+ }
+ }
+}
+
void handle_seen_interrupt(monsters* monster)
{
if (mons_is_unknown_mimic(monster))
@@ -1312,6 +1333,7 @@ void monster_grid(bool do_updates)
_good_god_follower_attitude_change(monster);
beogh_follower_convert(monster);
+ slime_conversion(monster);
}
}
}
@@ -2997,6 +3019,7 @@ bool is_feature(int feature, const coord_def& where)
case DNGN_ALTAR_ELYVILON:
case DNGN_ALTAR_LUGONU:
case DNGN_ALTAR_BEOGH:
+ case DNGN_ALTAR_JIYVA:
return (true);
default:
return (false);
@@ -4705,6 +4728,15 @@ void init_feature_table( void )
Feature[i].minimap = MF_FEATURE;
break;
+ case DNGN_ALTAR_JIYVA:
+ Feature[i].colour = ETC_SLIME;
+ Feature[i].dchar = DCHAR_ALTAR;
+ Feature[i].flags |= FFT_NOTABLE;
+ Feature[i].map_colour = DARKGREY;
+ Feature[i].seen_colour = ETC_SLIME;
+ Feature[i].minimap = MF_FEATURE;
+ break;
+
case DNGN_FOUNTAIN_BLUE:
Feature[i].colour = BLUE;
Feature[i].dchar = DCHAR_FOUNTAIN;
diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h
index 2d7b495696..d597bad0df 100644
--- a/crawl-ref/source/view.h
+++ b/crawl-ref/source/view.h
@@ -64,6 +64,7 @@ void init_feature_table();
void init_monsters_seens();
void beogh_follower_convert(monsters *monster, bool orc_hit = false);
+void slime_conversion(monsters *monster);
bool mons_near(const monsters *monster, unsigned short foe = MHITYOU);
bool mon_enemies_around(const monsters *monster);