discussion in October/November.
Zin effects:
Zin restrictions:
Zin invocations:
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3164 c06c8d41-db1a-0410-9941-cceddc491573
CGYTZT5QWIEGYKUOLOK7MFXSLJKLYRZONER5ZCDZO5XYWSLG475QC
VTOAGJSPELAK6F253GZOWSHPIVECXSDQQQ2APUTFQXZFG5V6H4LQC
EWFP6RFDHTEGD6SX36LYRLQB3APIKGAHNBKWPD56RGYBUE4FWJUQC
YX2LDGNQNB6AQRKAVXNYQ473X6EVPQEBT5AJKBIIWFIMS3U2BNQQC
PM65H4V4GNPVIJFUQW57DC3VDB7TRUUNXKVZONQKEFZSK3AXX5GQC
MDU5W4IEH6B47SYDORGGI7ZD73DMO6DYEP3XJF6ZJ5G5PNNJDGXQC
AS2IQQJNNCEQNXXKTGYHLB7RO3ZKCF4F7GK6FJH66BOOKDDRGNIQC
CA6ZG6P2CE5EPAOQSB3P7NBDKTNFFHQP4CPOUFZL32ON6N32GSSQC
6PAG7GHXHIYXJPPTEK4KZQZT4CL2SJDAGTVIUDB4KK66PVSTWUMAC
475LL4U4ND6PTNV4XKC7WQAOJC7RF2VCCVX3DRILP2PKIBFYWE6QC
HIRKGUMNJPWKSVTR6TVBPD3MWNA63CEHCLCIPWEMGDFHVB3NPLDQC
D27U7RT2C77NEUBP6JCSQJ2DRCJVHOXUO2PFZ45VFYMEVMKI4TSAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC
PL6I2CMSTHY5ZHWVMIQE5YTM5S5VPKBNZM6QJVHZSSKOJGIJ5W4AC
RCLZVH5IZLUUJU3XDIW4GUDJ5G73DOI3EEMRKNMCNPSSEDBU5YFAC
IVVTHLTTLOP5TSULXJWUSSXHOKYWVU3OWKYVK45A7RIB6V34MYQAC
L4RYVF46EQKMVOEADGRG4WMPVTQ6NNFGYMU4SHAH6XJIKWVHT77QC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
LS3DAZVRDCXVN2BKBC6RGCKO3R43Z7HKG4GXJWLBK4AKBL2G6QDQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
JW2KRJHES33W7UTWZ6NDO4TLMK4EFU4HKZXBWR2UJOMPCCOTR4CQC
2H32CFFM2FNS63JJPNM2S6HMO543EX72GMPOU5GI6HTMQYPL6I3AC
WHY6LRRJ5T2NSBE3IUCR4X3TOAH7TTK5NPUPUIFT7TPNJ6J4HBDAC
LOJYD6QZRNLNDDZJKVBMKQIBPTKSRN2ETCYGNVV47M7L3QLUJUJAC
SWOYPTHJAWFEDBMB3ROT33VQZIXGZD5UOXEV456DDUENW2HGA66QC
L4PKJZERR7WADKWHY3MR6J6OZFREVPL3CB43I6MLJ2BVKWCUTE7AC
7NDXS36TE7QVXTXJWMYSVG5UHCCLPIO4VL6NXFGTDK3ZNKE3A2IAC
4BSWRAIA7TLRFRZ4RMLOVDHWDWBGJCAQZUOPXPJYW6OJY6B3HPLQC
AQ36MO7VNGSGQ5KK7JCQA2WEHUELAFLSU2QBUWROVJFOTPMGFGMQC
BUSA7O6EFBZVAG2RL5T7MD2WTWKOEKKIAAZ2VS4Y3L6ECT4HQR6QC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
QS3ZRS3E6KL3YJHPKYEWCWJYRBJSXD5OOYF6Y25HZVECGPJRDB5QC
DS2GZKISEP2DM2VU6EJ525Q7W3WVOKJXG5PY2OY4VNFCLBHVVOTAC
4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC
E5DMZFW6WCFAKTKKOQPYTQXZ2CGLWMVH64LRXDUI2UIG4VYUHIVQC
R325RPUV26YH65VIJKYEFZ2XCVXQHO5N3ELPX6RNQ5TSI3JJNQGQC
DTO3EUKWHZ5RJNGNCFYXSOVTIPVXPP637F2W7WFGYKJ7JK7VNKNQC
CMNLYUECIMEZSOYG4KOSINOPER5OM7PPCGIHCM7LQVWEO77XFUYQC
3KAINFIXO7WNWGUGZB43EUNFRS2ZPBLQZDTY456QACMRHYIJ7WDAC
5ZG33P3GHTV45HM5STF23BNSV7T4Z6MGCLPRGCNHIVCQUTHDPOTQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
MLZSEZWNNZMSIDQNAAIOJJR4K7VSVJICL5SAGHD3ROM7SYDVZABAC
52W74WXL5XIH6YFJBQRVAO47YHCS3CPMUUZS4Q3AZ3HAPDWMT54AC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC
GTPAKUU3R5AS3LQNCCZIP3BWV473RM4EB2AIS4FXAJRXHEOVH2PAC
KEYK3CH5J46U6TTOKTWRNMYTZXMQXFVEAZUC4ZQ4QCOSJHVIBDRQC
ODNAIEJW732NG7USKQKCIP4R4DAEYXXJQX6LY7TIN32NKE75454QC
PIGVTTBAQGNHOCX6IXJLGVVURBAT77SD6FQUVTTI5SFTV563GMZQC
LJK4ZQATLSB4MKZG3ARZX5V6RFGTN3NLCN6GTCUGJQKU26SOXMUAC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
WXSNNK2RXP3DQFAEQGQUZJHFWXJC7ZKG2WURZGL566UDM4YXFSWQC
if (object < NUM_REAL_FEATURES
&& is_sanctuary(x,y) && object >= DNGN_MINMOVE)
{
if (env.map[x][y].property == FPROP_SANCTUARY_1)
*colour = YELLOW | colmask;
else if (env.map[x][y].property == FPROP_SANCTUARY_2)
{
if (!one_chance_in(3))
*colour = WHITE | colmask;
else if (one_chance_in(3))
*colour = LIGHTCYAN | colmask;
else
*colour = LIGHTGRAY | colmask;
}
}
else
bool remove_sanctuary(bool did_attack)
{
if (env.sanctuary_time)
env.sanctuary_time = 0;
if (env.sanctuary_x < 0 || env.sanctuary_y < 0)
return false;
const int radius = 5;
bool seen_change = false;
for (int x=-radius; x<=radius; x++)
for (int y=-radius; y<=radius; y++)
{
int posx = env.sanctuary_x + x;
int posy = env.sanctuary_y + y;
if (posx <= 0 || posx > GXM || posy <= 0 || posy > GYM)
continue;
if (is_sanctuary(posx, posy))
{
env.map[posx][posy].property = FPROP_NONE;
if (see_grid(coord_def(posx,posy)))
seen_change = true;
}
}
// do not reset so as to allow monsters to see if their fleeing source
// used to be the centre of a sanctuary
// env.sanctuary_x = env.sanctuary_y = -1;
if (did_attack)
{
if (seen_change)
simple_god_message(" revokes the gift of sanctuary.", GOD_ZIN);
did_god_conduct(DID_FRIEND_DIES, 3);
}
else if (seen_change)
{
mpr("The air around you flickers and hums.");
if (is_resting())
stop_running();
}
return true;
}
bool cast_sanctuary(const int power)
{
// first get rid of old sanctuary
remove_sanctuary();
if (!silenced(you.x_pos, you.y_pos))
mpr("You hear a choir sing!");
else
mpr("You are suddenly bathed in radiance!");
you.flash_colour = WHITE;
viewwindow( true, false );
holy_word( 100, true );
delay(1000);
env.sanctuary_x = you.x_pos;
env.sanctuary_y = you.y_pos;
env.sanctuary_time = 15;
const int radius = 5;
const int pattern = random2(4);
int count = 0;
int monster = -1;
for (int x=-radius; x<=radius; x++)
for (int y=-radius; y<=radius; y++)
{
int posx = you.x_pos + x;
int posy = you.y_pos + y;
if (posx <= 0 || posx > GXM || posy <= 0 || posy > GYM)
continue;
int dist = distance(posx, posy, you.x_pos, you.y_pos);
if (dist > radius*radius)
continue;
// scare all hostile monsters inside sanctuary
if (mgrd[posx][posy] != NON_MONSTER)
{
monster = mgrd[posx][posy];
monsters *mon = &menv[monster];
if (!mons_friendly(mon)
&& mon->add_ench(mon_enchant(ENCH_FEAR, 0, KC_YOU)))
{
behaviour_event(mon, ME_SCARE, MHITYOU);
count++;
}
}
// forming patterns
if (pattern == 0
&& (x == 0 || y == 0 || x == y || x == -y)
|| pattern == 1
&& (dist >= (radius-1)*(radius-1) && dist <= radius*radius)
|| pattern == 2
&& (x%2 == 0 || y%2 == 0)
|| pattern == 3
&& (abs(x)+abs(y) < 5 && x != y && x != -y))
{
env.map[posx][posy].property = FPROP_SANCTUARY_1;
}
else
env.map[posx][posy].property = FPROP_SANCTUARY_2;
}
if (count == 1)
simple_monster_message(&menv[monster], " turns to flee the light!");
else if (count > 0)
mpr("The monsters scatter in all directions!");
return (true);
}
case DID_DELIBERATE_MUTATING:
if (you.religion == GOD_ZIN)
{
if (!known)
{
simple_god_message(" did not appreciate that!");
break;
}
piety_change = -level;
ret = true;
}
break;
case DID_EAT_SOULED_BEING:
if (you.religion == GOD_ZIN)
{
piety_change = -level;
penance = level * 5;
ret = true;
}
break;
(you.religion == GOD_SHINING_ONE || you.religion == GOD_ZIN ||
you.religion == GOD_LUGONU) && you.num_gifts[you.religion] == 0 )
(you.religion == GOD_SHINING_ONE || you.religion == GOD_LUGONU)
&& you.num_gifts[you.religion] == 0 )
(you.religion == GOD_SHINING_ONE || you.religion == GOD_ZIN ||
you.religion == GOD_LUGONU) && you.num_gifts[you.religion] == 0)
(you.religion == GOD_SHINING_ONE || you.religion == GOD_LUGONU)
&& you.num_gifts[you.religion] == 0)
const int how_many = 1 + (you.experience_level / 10) + random2(3);
for (int i = 0; i < how_many; i++)
if (create_monster(MONS_ANGEL, 0, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250) != -1)
success = true;
simple_god_message( success ?
" sends the divine host to punish you "
"for your evil ways!" :
"'s divine host fails to appear.",
god);
}
else
case 0: // remove good mutations (25%)
case 1:
// god_gift == false gives unfriendly
success = summon_swarm( you.experience_level * 20, true, false );
simple_god_message(success ?
" sends a plague down upon you!" :
"'s plague fails to arrive.",
god);
simple_god_message(" draws some chaos from your body!", god);
bool success = false;
for (int i = 0; i < 7; i++)
if (random2(10) > i
&& delete_mutation(RANDOM_MUTATION, true, true))
{
success = true;
}
if (success && !count_mutations())
simple_god_message(" rids your body of chaos!");
break;
for (int i = 0; i < how_many; i++)
if (create_monster(MONS_ANGEL, 0, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250) != -1)
success = true;
simple_god_message( success ?
" sends the divine host to punish you "
"for your evil ways!" :
"'s divine host fails to appear.",
god);
}
else
{
// god_gift == false gives unfriendly
bool success = summon_swarm( you.experience_level * 20, true, false );
simple_god_message(success ?
" sends a plague down upon you!" :
"'s plague fails to arrive.",
god);
}
break;
case 5:
case 6: // famine, 25%
simple_god_message(" sends a famine down upon you!", god);
make_hungry( you.hunger/2, false );
break;
case 7: // noisiness, 12.5%
simple_god_message(" booms out: \"Return to the light! REPENT!\"", god);
noisy( 25, you.x_pos, you.y_pos ); // same as scroll of noise
break;
}
}
}
// Zin blesses maces with disruption
if (you.religion == GOD_ZIN
&& !you.num_gifts[GOD_ZIN]
&& !player_under_penance()
&& you.piety > 160)
{
const int wpn = get_player_wielded_weapon();
if (wpn != -1
&& (you.inv[wpn].base_type == OBJ_WEAPONS
&& (you.inv[wpn].sub_type == WPN_MACE
|| you.inv[wpn].sub_type == WPN_GREAT_MACE))
&& get_weapon_brand( you.inv[wpn] ) != SPWPN_DISRUPTION)
{
bless_weapon( GOD_ZIN, SPWPN_DISRUPTION, WHITE );
static bool is_good_mutation( mutation_type which_mutation )
{
switch (which_mutation)
{
case MUT_TOUGH_SKIN:
case MUT_STRONG:
case MUT_CLEVER:
case MUT_AGILE:
case MUT_POISON_RESISTANCE:
case MUT_TELEPORT_CONTROL:
case MUT_MAGIC_RESISTANCE:
case MUT_TELEPORT_AT_WILL:
case MUT_MAPPING:
case MUT_CLARITY:
case MUT_MUTATION_RESISTANCE:
case MUT_FAST:
case MUT_BLINK:
case MUT_BREATHE_FLAMES:
case MUT_SPIT_POISON:
case MUT_BREATHE_POISON:
case MUT_STINGER:
case MUT_FANGS:
return true;
default:
return false;
}
}
if (failMsg)
mpr("You feel odd for a moment.", MSGCH_MUTATION);
if (wearing_amulet(AMU_RESIST_MUTATION) && !one_chance_in(10)
|| you.religion == GOD_ZIN && you.piety > random2(200)
|| you.mutation[MUT_MUTATION_RESISTANCE] == 3
|| you.mutation[MUT_MUTATION_RESISTANCE] && !one_chance_in(3))
{
if (failMsg)
mpr("You feel odd for a moment.", MSGCH_MUTATION);
bool delete_mutation(mutation_type which_mutation, bool force)
int count_mutations()
{
int count = 0;
for (int i = 0; i < NUM_MUTATIONS; i++)
if (you.mutation[i] && you.demon_pow[i] < you.mutation[i])
count++;
return count;
}
bool delete_mutation(mutation_type which_mutation, bool force, bool good)
// monsters will try to flee out of a sanctuary
if (is_sanctuary(monster->x, monster->y) && !mons_friendly(monster)
&& !mons_is_fleeing(monster)
&& monster->add_ench(mon_enchant(ENCH_FEAR, 0, KC_YOU)))
{
behaviour_event(monster, ME_SCARE, MHITNOT, monster->x, monster->y);
}
else if (mons_is_fleeing(monster) && env.sanctuary_x != -1
&& !is_sanctuary(monster->x, monster->y)
&& monster->target_x == env.sanctuary_x
&& monster->target_y == env.sanctuary_y)
{ // once outside there's a chance they'll regain their courage
if (random2(5) > 2)
monster->del_ench(ENCH_FEAR);
}
if (ms_direct_nasty(spell_cast)
&& mons_aligned(monster_index(monster), monster->foe))
if (is_sanctuary(you.x_pos, you.y_pos)
|| is_sanctuary(monster->x, monster->y))
{
spellOK = false;
}
else if (ms_direct_nasty(spell_cast)
&& mons_aligned(monster_index(monster), monster->foe))
spell_cast = (coinflip() ? hspell_pass[2] : SPELL_NO_SPELL);
{
if (is_sanctuary(you.x_pos, you.y_pos)
|| is_sanctuary(monster->x, monster->y))
{
spell_cast = SPELL_NO_SPELL;
}
else
spell_cast = (coinflip() ? hspell_pass[2] : SPELL_NO_SPELL);
}
// hostile monsters won't enter sanctuaries
if (!mons_friendly(monster)
&& is_sanctuary(targ_x, targ_y)
&& !is_sanctuary(monster->x, monster->y))
{
return (false);
}
// inside a sanctuary don't attack anything!
if (is_sanctuary(monster->x, monster->y)
&& (targ_x == you.x_pos && targ_y == you.y_pos
|| mgrd[targ_x][targ_y] != NON_MONSTER))
{
return (false);
}
if (is_good_god(you.religion) && is_player_same_species(item.plus))
if (you.religion == GOD_ZIN && mons_intel(item.plus) >= I_NORMAL)
simple_god_message(" demands a ceremonial burial for a corpse "
"like this!");
else if (is_good_god(you.religion) && is_player_same_species(item.plus))
// you can swap places with a friendly monster if you're not confused
// or if both of you are inside a sanctuary
const bool can_swap_places = targ_monst != NON_MONSTER
&& (mons_friendly(&menv[targ_monst])
&& !you.duration[DUR_CONF]
|| is_sanctuary(you.x_pos, you.y_pos)
&& is_sanctuary(targ_x, targ_y));
{ ABIL_ZIN_REPEL_UNDEAD, "Repel Undead", 1, 0, 100, 0, ABFLAG_NONE },
{ ABIL_ZIN_HEALING, "Minor Healing", 2, 0, 50, 1, ABFLAG_NONE },
{ ABIL_ZIN_PESTILENCE, "Pestilence", 3, 0, 100, 2, ABFLAG_NONE },
{ ABIL_ZIN_HOLY_WORD, "Holy Word", 6, 0, 150, 3, ABFLAG_NONE },
{ ABIL_ZIN_SUMMON_GUARDIAN, "Summon Guardian", 7, 0, 150, 4, ABFLAG_NONE },
{ ABIL_ZIN_SMITING, "Smiting",
3, 0, 50, generic_cost::fixed(2), ABFLAG_NONE },
{ ABIL_ZIN_REVITALISATION, "Revitalisation", 0, 0, 100, 3, ABFLAG_NONE },
{ ABIL_ZIN_SANCTUARY, "Sanctuary", 7, 0, 150, 10, ABFLAG_NONE },
case ABIL_ZIN_REVITALISATION:
if (cast_revitalisation( 3 + (you.skills[SK_INVOCATIONS] / 6) ))
exercise(SK_INVOCATIONS, 1 + random2(3));
break;
case ABIL_ZIN_SANCTUARY:
if (cast_sanctuary(you.skills[SK_INVOCATIONS] * 4))
exercise(SK_INVOCATIONS, 5 + random2(8));
break;
case ABIL_ZIN_SMITING: