diff --git a/ai.c b/ai.c index 810e225..ed08558 100644 --- a/ai.c +++ b/ai.c @@ -1787,7 +1787,7 @@ int aipickupok(lifeform_t *lf, object_t *o) { } if (isedible(o)) { - if (caneat(lf, o) && !isinbattle(lf)) { + if (caneat(lf, o) && !isinbattle(lf, B_FALSE)) { ok = B_TRUE; } } else if (canpickup(lf, o, 1)) { @@ -2363,6 +2363,12 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG } } + if (ot->id == OT_A_TRIPLF) { + if (isairborne(victim)) { + specificcheckok = B_FALSE; + } + } + if ((ot->id == OT_A_TUMBLE) || (ot->id == OT_A_JUMP)) { if (lfhasflag(lf, F_GRABBING) || lfhasflag(lf, F_GRABBEDBY) || isairborne(lf)) { specificcheckok = B_FALSE; diff --git a/attack.c b/attack.c index 496dd81..08bb47c 100644 --- a/attack.c +++ b/attack.c @@ -515,6 +515,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { killflagsofid(lf->flags, F_USEDPOISON); angergodmaybe(R_GODPURITY, 100, GA_POISON); angergodmaybe(R_GODMERCY, 25, GA_POISON); + angergodmaybe(R_GODBATTLE, 25, GA_POISON); pleasegodmaybe(R_GODDEATH, 3); } } diff --git a/data.c b/data.c index 2298c60..a242429 100644 --- a/data.c +++ b/data.c @@ -206,9 +206,9 @@ void initjobs(void) { // gods may use all abilities and cast any spell at will for (i = SS_NONE+1; i < SS_LAST; i++) { if ((i == SS_ABILITY) || (i == SS_DIVINE)) { - mayusespellschool(lastjob->flags, i, F_CANWILL); + mayusespellschool(lastjob->flags, i, F_CANWILL, B_FALSE); } else { - mayusespellschool(lastjob->flags, i, F_CANCAST); + mayusespellschool(lastjob->flags, i, F_CANCAST, B_FALSE); //mayusespellschool(lastjob->flags, i, F_CANWILL); } } @@ -369,6 +369,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 sprigs of mistletoe"); // initial skills addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_EVASION, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_SKILLED, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); @@ -566,7 +567,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); // limit addflag(lastjob->flags, F_STARTSKILL, SK_EVASION, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_UNARMED, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_EXOTICWEPS, PR_NOVICE, NA, NULL); @@ -805,6 +806,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_LORE_UNDEAD, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_DEMONS, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); // learnable skills addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, PR_ADEPT, NA, NULL); @@ -813,7 +815,6 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SPEECH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); // limit addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_AIR, NA, NA, NULL); @@ -2384,6 +2385,7 @@ void initobjects(void) { addot(OT_SCR_REMOVECURSE, "scroll of remove curse", "Removes curses from all weilded equipment.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_VALUE, 50, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_FREQUENT, NULL); addot(OT_SCR_IDENTIFY, "scroll of identify", "Completely identifies any one item.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); @@ -2858,6 +2860,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); @@ -3487,9 +3490,9 @@ void initobjects(void) { addflag(lastot->flags, F_TARGETTEDSPELL, TT_DOOR, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); - addot(OT_S_INSCRIBE, "inscribe", "Creates a magical inscription viewable to anyone standing nearby.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + //addot(OT_S_INSCRIBE, "inscribe", "Creates a magical inscription viewable to anyone standing nearby.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + //addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); + //addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addot(OT_S_KNOCK, "knock", "Magically opens doors or other such barriers.\n", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VII, this spell will also knock back living creatures."); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); @@ -6641,7 +6644,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_RARE, NULL); - addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 2, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LORE_ARCANA, NA, NA, NULL); @@ -6654,7 +6657,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_RARE, NULL); - addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 2, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LORE_ARCANA, NA, NA, NULL); @@ -6668,7 +6671,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_RARE, NULL); - addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 2, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LORE_ARCANA, NA, NA, NULL); @@ -6681,7 +6684,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_VERYRARE, NULL); - addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 2, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LORE_ARCANA, NA, NA, NULL); @@ -6695,7 +6698,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_VERYRARE, NULL); - addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 2, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LORE_ARCANA, NA, NA, NULL); @@ -6709,7 +6712,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_VERYRARE, NULL); - addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 2, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LORE_ARCANA, NA, NA, NULL); @@ -7085,6 +7088,8 @@ void initrace(void) { race_t *r; flag_t *f; objecttype_t *ot; + skill_t *sk; + int i; // unique monsters addrace(R_JAILER, "jailer", 110, '@', C_MAGENTA, MT_FLESH, RC_HUMANOID, "Jailers are generally known for their surplus of brawn and utter lack of brains. This one is no different."); @@ -7597,6 +7602,60 @@ void initrace(void) { addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "eating pets"); + addrace(R_GODBATTLE, "Bjorn", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Bjorn the Battlelord is the god of honourable combat. He appears as a heavily built, bearded warrior clad in well-used armour."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); + addflag(lastrace->flags, F_FLEEONHPPCT, 95, NA, NA, ""); + addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "100"); + addflag(lastrace->flags, F_STARTATT, A_AGI, NA, NA, "90"); + addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "50"); + addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "50"); + addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "100"); + addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "70"); + addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "50d4"); + addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 8, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed +5 helmet"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed bloodstained +5 plate mail"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed bloodstained +5 set of greaves"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed +2 tower shield of reflection"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed bloodstained +3 pair of gauntlets of power"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed +5 battleaxe of penetration"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed bloodstained +2 pair of metal boots"); + // master of all weapons + for (sk = firstskill ; sk ; sk = sk->next) { + if (isweaponskill(sk->id) || (sk->id == SK_UNARMED)) { + addflag(lastrace->flags, F_STARTSKILL, sk->id, PR_MASTER, NA, NULL); + } + } + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_ARMOUR, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SHIELDS, PR_MASTER, NA, NULL); + // god abilities + addflag(lastrace->flags, F_GODOF, B_MALE, NA, NA, "Battle"); + addflag(lastrace->flags, F_STAMREGEN, NA, NA, NA, "10"); // ie. basically infinite + addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_WARCRY, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_RAGE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_AIMEDSTRIKE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_HURRICANESTRIKE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_FLURRY, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SHIELDBASH, NA, NA, NULL); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "victory in battle"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "prolonged peace"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of poison"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of magic"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "cowardice"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "dishonourable combat"); + // sacrifices + addflag(lastrace->flags, F_SACRIFICEOBWITHFLAG, F_BATTLESPOILS, NA, 3, "OB explode#S into a shower of blood!"); + addflag(lastrace->flags, F_SACRIFICEOB, OT_SPELLBOOK, NA, 10, "OB explode#S into a shower of blood!"); + + + addrace(R_GODTHIEVES, "Felix", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Felix is the god of Thieves, Greed and Trickery. He generally appears as an overweight glutton carrying his contraband loot around in huge sacks. Despite this, he is amazingly agile and is said to be able to steal one's soul right out of their body."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); @@ -7694,6 +7753,52 @@ void initrace(void) { // sacrifices addflag(lastrace->flags, F_SACRIFICEOB, OT_CORPSE, NA, 2, "Bony claws rise up and drag OB underground."); + + addrace(R_GODMAGIC, "Lumara", 55, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Lumara is the goddess of magic. She appears as a slender elderly woman, her expression wise with age."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); + addflag(lastrace->flags, F_FLEEONHPPCT, 95, NA, NA, ""); + addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "50"); + addflag(lastrace->flags, F_STARTATT, A_AGI, NA, NA, "50"); + addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "100"); + addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "100"); + addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "55"); + addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "60"); + addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "25d4"); + addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 4, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "+5 wizard hat of knowledge"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed robe"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "pair of sandals"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "pair of spectacles"); + + // can cast all spells and master of all spell skills + for (i = SS_NONE+1; i < SS_LAST; i++) { + if ((i != SS_ABILITY) && (i != SS_DIVINE)) { + enum SKILL skid; + skid = getschoolskill(i); + if (skid != SK_NONE) { + addflag(lastrace->flags, F_STARTSKILL, skid, PR_MASTER, NA, NULL); + } + mayusespellschool(lastjob->flags, i, F_CANWILL, 10); + } + } + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); + // god abilities + addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Magic"); + addflag(lastrace->flags, F_MPREGEN, NA, NA, NA, "100"); // ie. basically infinite + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "the use of magic"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of missile or ranged weapons"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of technology"); + // sacrifices + addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_POTION, NA, 2, "OB disappear#S in a swirl of multicoloured lights."); + addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_SCROLL, NA, 2, "OB disappear#S in a swirl of multicoloured lights."); + addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_WAND, NA, 5, "OB disappear#S in a swirl of multicoloured lights."); + addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_RING, NA, 10, "OB disappear#S in a swirl of multicoloured lights."); + + addrace(R_GODMERCY, "Yumi", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Yumi is the goddess of Mercy and Healing. She has a calm, serene face and wears simple clothing."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); @@ -7741,6 +7846,7 @@ void initrace(void) { addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_WEAPON, NA, 2, "OB IS destroyed in a flash of power."); + // monsters addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC, "A floating orb of flesh with a large mouth, single central eye, and numerous smaller eyestalks."); addbodypart(lastrace, BP_BODY, NULL); @@ -9430,7 +9536,7 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FLIGHT, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "0d4+2"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 1, NA, NULL); addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); @@ -11818,9 +11924,10 @@ void initskills(void) { addskilldesc(SK_PERCEPTION, PR_NOVICE, "^gYou can now see footprints.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_NOVICE, "^gYou can now check for trails on staircases before descending.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_BEGINNER, "^gYou can now determine the depth and direction of footprints.^n", B_TRUE); + addskilldesc(SK_PERCEPTION, PR_BEGINNER, "^gYou now have perception of your blind spots.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_ADEPT, "^gYour field of vision is now wider.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_EXPERT, "^gYou can now move without leaving footprints.^n", B_TRUE); - addskilldesc(SK_PERCEPTION, PR_MASTER, "^gYou now have perception of your blind spots.^n", B_TRUE); + addskilldesc(SK_PERCEPTION, PR_MASTER, "^gYou field of vision now extends behind you.^n", B_TRUE); addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable? addskilldesc(SK_STEALTH, PR_NOVICE, "^gYou gain the 'hide' ability.^n", B_FALSE); addskilldesc(SK_STEALTH, PR_BEGINNER, "^gYou can now move while hiding.^n", B_TRUE); diff --git a/data/hiscores.db b/data/hiscores.db index bc2a317..e229a72 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 7b56c32..41cbc1b 100644 --- a/defs.h +++ b/defs.h @@ -281,6 +281,11 @@ enum RELATIVEDIR { RD_SIDEWAYS, }; +enum TURNDIR { + TD_RIGHT, + TD_LEFT +}; + enum TRADEINFOTYPE { TI_SKILL, TI_SPELL, @@ -431,6 +436,7 @@ enum GODANGERREASON { GA_ATTACKHELPLESS, // attacked someone who was sleeping etc GA_ATTACKOBJECT, // attacked or broke an object GA_ASSAULT, // attacked someone peaceful + GA_COWARD, // acted in a cowardly manner GA_EAT, // ate something the god doesn't like GA_HERESY, // blessed or cursed an object GA_MERCY, // allowed something to flee @@ -870,7 +876,7 @@ enum RACECLASS { }; #define R_GODFIRST R_GODPURITY -#define MAXGODS 4 +#define MAXGODS 6 enum RACE { R_NONE = 0, @@ -897,6 +903,8 @@ enum RACE { R_GODTHIEVES, // felix R_GODDEATH, // hecta R_GODMERCY, // yumi + R_GODBATTLE, // bjorn + R_GODMAGIC, // lumara // monsters R_BEHOLDER, R_BUGBEAR, @@ -1416,7 +1424,7 @@ enum OBTYPE { OT_S_GASEOUSFORM, OT_S_GREASE, OT_S_HOLDPORTAL, - OT_S_INSCRIBE, + //OT_S_INSCRIBE, OT_S_INVISIBILITY, OT_S_KNOCK, OT_S_LIGHT, @@ -2037,6 +2045,8 @@ enum FLAG { // object flags F_BADOBJECT, // this object is dangerous. ie. potion of poison, // potion of sleep, etc. + F_BATTLESPOILS, // this obejct was dropped by a monster which the + // player killed, and has not yet been touched. F_BEINGUSED, // this object is currently being used F_DEAD, // object will be removed F_ONEPERCELL, // only one of these objects can exist per cell @@ -2526,6 +2536,7 @@ enum FLAG { F_ARMOURPENALTY, // lower your acc/ev by val0 due to cumbersome // armour. lowered by sk_armour skill. // v0 is accuracy penalty, v1 is evasion penalty. + F_MISCASTCHANCE, // lf has +v0% chance of spell failure F_LEVRACE, // at level v0, this race is promoted to race v1 // must apply this to the BASE race. F_JOBATTRMOD, // add v1 to attr v0. only used in jobs. diff --git a/doc/add_god b/doc/add_god index ecea681..65f43f8 100644 --- a/doc/add_god +++ b/doc/add_god @@ -16,6 +16,10 @@ In god.c: angergod() - add angry effects (minor). angergod() - add angry effects (major). + pleasegod() - add in text for your feeling + + godsay() - add in text + update getopposinggod() In shops.c: diff --git a/flag.c b/flag.c index aaf2155..8f7eb12 100644 --- a/flag.c +++ b/flag.c @@ -15,7 +15,6 @@ extern enum GAMEMODE gamemode; extern int needredraw; extern int statdirty; -extern void (*precalclos)(lifeform_t *); extern lifeform_t *godlf[]; extern int ngodlfs; diff --git a/god.c b/god.c index 4c13031..06ec7ca 100644 --- a/god.c +++ b/god.c @@ -18,6 +18,8 @@ #include "spell.h" #include "text.h" +extern int statdirty; + extern map_t *firstmap; extern map_t *heaven; extern race_t *firstrace, *lastrace; @@ -60,6 +62,8 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { } case GA_ASSAULT: godsay(rid, B_TRUE, "You dare attack one of my innocent servants?"); break; + case GA_COWARD: + godsay(rid, B_TRUE, "Coward!"); break; case GA_EAT: godsay(rid, B_TRUE, "That is NOT acceptable for consumption!"); break; case GA_HERESY: @@ -67,7 +71,7 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { case GA_MERCY: godsay(rid, B_TRUE, "You allowed your foe to escape!"); break; case GA_MONEY: - godsay(rid, B_TRUE, "Giving away money offends me..."); break; + godsay(rid, B_TRUE, "Where is your sense of greed?"); break; case GA_MURDER: godsay(rid, B_TRUE, "You have taken a life!"); break; case GA_PRAY: dosay = B_TRUE; break; @@ -126,9 +130,30 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { // then... if (piety > -100) { int i,n; + flag_t *retflag[MAXCANDIDATES]; + int nretflags; lifeform_t *l; // minor bad stuff switch (rid) { + case R_GODBATTLE: + // rust your armour + for (o = player->pack->first ; o ; o = o->next) { + if (isarmour(o) && (o->type->material->id == MT_METAL)) { + poss[nposs++] = o; + } + } + if (nposs) { + o = poss[rnd(0,nposs-1)]; + msg("\"Let your armour reflect your actions!\""); + makewet(o, R_TRUSTY); + } else { + o = getweapon(player); + if (o) { + msg("\"Let your weapon reflect your actions!\""); + makeduller(o, 2); + } + } + break; case R_GODDEATH: castspell(god, OT_S_PAIN, player, NULL, player->cell, NULL, NULL); castspell(god, OT_S_DRAINLIFE, player, NULL, player->cell, NULL, NULL); @@ -141,10 +166,21 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { } } break; - case R_GODTHIEVES: - // take a random object - msg("\"Yoink!\""); - castspell(god, OT_S_CONFISCATE, player, NULL, player->cell, NULL, NULL); + case R_GODMAGIC: + msg("\"You can live without my gifts for a while...\""); + losemp(player, player->mp); + // get random spell + getflags(player->flags, retflag, &nretflags, F_CANCAST, F_NONE); + nposs = 0; + for (i = 0; i < nretflags; i++) { + if (retflag[i]->lifetime != FROMJOB) { + poss[nposs++] = retflag[i]; + } + } + if (nposs) { + f = poss[rnd(0,nposs-1)]; + killflag(f); + } break; case R_GODMERCY: // lower one attribute @@ -178,6 +214,11 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { dospelleffects(NULL, OT_S_GUSTOFWIND, 10, NULL, NULL, player->cell, B_UNCURSED, NULL, B_TRUE); } break; + case R_GODTHIEVES: + // take a random object + msg("\"Yoink!\""); + castspell(god, OT_S_CONFISCATE, player, NULL, player->cell, NULL, NULL); + break; default: break; } @@ -185,8 +226,43 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { object_t *o; lifeform_t *l; int n,i; + int rollagain = B_TRUE; // major bad stuff switch (god->race->id) { + case R_GODBATTLE: + switch (rnd(1,3)) { + case 1: // bad weapon + msg("\"A fool deserves a fool's weapon!\""); + // forcibly drop player's weapon + o = getweapon(player); + if (o) { + killflagsofid(o->flags, F_EQUIPPED); + drop(o, o->amt); + } + o = addob(player->pack, "cursed -1 stick"); + if (o) { + identify(o); + weild(player, o); + } + break; + case 2: // bad armour + msg("\"A fool deserves a fool's armour!\""); + // remove all player's armour + dospelleffects(god, OT_S_INSTANTDISROBE, 10, NULL, NULL, player->cell, B_BLESSED, NULL, B_TRUE); + // give them cursed armour + o = addob(player->pack, "cursed -5 cotton shirt"); + if (o) { + resizeobject(o, getlfsize(player)); + identify(o); + wear(player, o); + } + break; + case 3: // summon monsters + msg("\"Fight for your life, knave!\""); + summonlfs(player, player->cell, R_NONE, RC_HUMANOID, SZ_HUMAN, AL_NONE, 8, PERMENANT, B_FALSE); + break; + } + break; case R_GODDEATH: castspell(god, OT_S_PAIN, player, NULL, player->cell, NULL, NULL); castspell(god, OT_S_DRAINLIFE, player, NULL, player->cell, NULL, NULL); @@ -226,6 +302,39 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { } } break; + case R_GODMAGIC: + rollagain = B_TRUE; + while (rollagain) { + flag_t *retflag[MAXCANDIDATES]; + int nretflags; + rollagain = B_FALSE; + switch (rnd(1,3)) { + case 1: // lose all spells + msg("\"I forbid you my gifts!\""); + nposs = 0; + getflags(player->flags, retflag, &nretflags, F_CANCAST, F_NONE); + nposs = 0; + for (i = 0; i < nretflags; i++) { + if (retflag[i]->lifetime != FROMJOB) { + killflag(retflag[i]); + } + } + break; + case 2: // spells usually fail + msg("\"You will find my gifts far less reliable in future!\""); + addtempflag(player->flags, F_MISCASTCHANCE, 85, NA, NA, NULL, 200); + break; + case 3: // become a newt + if (ispolymorphed(player)) { + rollagain = B_TRUE; + } else { + msg("\"Maybe this will teach you some humility!\""); + setrace(player, R_NEWT, B_TRUE); // ie. don't set origrace! + } + break; + } + } // end while rollagain + break; case R_GODMERCY: msg("\"Even my mercy has its limits!\""); // age @@ -290,6 +399,8 @@ void dooffer(void) { lifeform_t *god; flag_t *retflag[MAXCANDIDATES]; int nretflags,pietyplus = 0; + char splatterob[BUFLEN]; + strcpy(splatterob, ""); // which god? god = askgod("To whom will you sacrifice?", B_TRUE); if (!god) { @@ -355,13 +466,22 @@ void dooffer(void) { } removeob(o, ALL); pietyplus += thispiety; + // special effect + if (god->race->id == R_GODBATTLE) { + strcpy(splatterob, "splash of blood"); + } break; } } // end for each f_sacrificexxx flag } // end foreach ob + if (pietyplus) { pleasegod(god->race->id, pietyplus); + if (strlen(splatterob)) { + addob(player->cell->obpile, splatterob); + addobsinradius(player->cell, 1, DT_COMPASS, splatterob, B_TRUE); + } } else { nothinghappens(); } @@ -386,6 +506,8 @@ enum RACE getopposinggod(enum RACE rid) { case R_GODTHIEVES: return R_GODPURITY; case R_GODDEATH: return R_GODMERCY; case R_GODMERCY: return R_GODDEATH; + case R_GODBATTLE: return R_GODMAGIC; + case R_GODMAGIC: return R_GODBATTLE; default: break; } return R_NONE; @@ -538,6 +660,7 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { if (pctchance(chance)) { // if this is true, you get a gift. char obtogive[BUFLEN]; int rollagain = B_TRUE; + enum SPELLSCHOOL school; gotgift = B_TRUE; killflagsofid(player->flags, F_ASLEEP); @@ -545,6 +668,139 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { godsay(god->race->id, B_TRUE, "I bestow a gift upon you, mortal!"); strcpy(obtogive, ""); switch (god->race->id) { + case R_GODBATTLE: + while (rollagain) { + rollagain = B_FALSE; + switch (rnd(1,2)) { + case 1: + snprintf(obtogive, BUFLEN, "excellent branded weapon"); + break; + case 2: + snprintf(obtogive, BUFLEN, "excellent branded armour"); + break; + } + } + break; + case R_GODDEATH: + while (rollagain) { + flag_t *f; + object_t *wep; + rollagain = B_FALSE; + switch (rnd(1,6)) { + case 1: + if (lfhasflag(player, F_SEEINDARK)) { + rollagain = B_TRUE; + } else { + msg("\"Henceforth the night shall be your ally!\""); + f = addtempflag(player->flags, F_SEEINDARK, 4, NA, NA, NULL, FROMGODGIFT); + f->obfrom = god->race->id; + } + break; + case 2: + snprintf(obtogive, BUFLEN, "cursed branded weapon"); + break; + case 3: // poison your weapon + wep = getweapon(player); + if (wep && canbepoisoned(wep->type->id)) { + applyobmod(wep, findobmod(OM_POISONED)); + msg("A layer of venom covers your weapon!"); + } else { + rollagain = B_TRUE; + } + break; + case 4: // resistant/immune to necrotic + if (lfhasflagval(player, F_DTRESIST, DT_NECROTIC, NA, NA, NULL)) { + if (lfhasflagval(player, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL)) { + rollagain = B_TRUE; + } else { + f = addtempflag(player->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL, FROMGODGIFT); + f->obfrom = god->race->id; + } + } else { + f = addtempflag(player->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL, FROMGODGIFT); + f->obfrom = god->race->id; + } + break; + case 5: // become a vampire + if (player->race->id == R_VAMPIRE) { + rollagain = B_TRUE; + } else { + msg("\"Go forth and kill in my name!\""); + setrace(player, R_VAMPIRE, B_FALSE); // ie. don't set origrace! + } + break; + case 6: // necromancy spells + if (!getskill(player, SK_SS_DEATH)) { + giveskill(player, SK_SS_DEATH); + } else { + snprintf(obtogive, BUFLEN, "spellbook of necromancy"); + } + break; + } + } + break; + case R_GODMAGIC: + while (rollagain) { + rollagain = B_FALSE; + switch (rnd(1,3)) { + case 1: // spellbook for a known school + school = getrandomspellschool(player, B_TRUE); + if (school == SS_NONE) { + rollagain = B_TRUE; + } else { + snprintf(obtogive, BUFLEN, "spellbook of %s", getschoolname(school)); + } + break; + case 2: // manual for an unknown spell school + school = getrandomspellschool(player, B_FALSE); + if (school == SS_NONE) { + rollagain = B_TRUE; + } else { + enum SKILL skid; + skill_t *sk; + skid = getschoolskill(school); + sk = findskill(skid); + snprintf(obtogive, BUFLEN, "manual of %s", sk->name); + } + break; + case 3: + msg("\"I grant you additional magical reserves!\""); + player->maxmp += rnd(2,4); + statdirty = B_TRUE; + break; + } + } + break; + case R_GODMERCY: + while (rollagain) { + flag_t *f; + rollagain = B_FALSE; + switch (rnd(1,4)) { + case 1: + snprintf(obtogive, BUFLEN, "3 vials of ambrosia"); + break; + case 2: + snprintf(obtogive, BUFLEN, "ring of regeneration"); + break; + case 3: + snprintf(obtogive, BUFLEN, "ring of miracles"); + break; + case 4: // immune to disease / poison + if (lfhasflag(player, F_DISEASEIMMUNE)) { + if (lfhasflagval(player, F_DTIMMUNE, DT_POISON, NA, NA, NULL)) { + rollagain = B_TRUE; + } else { + f = addtempflag(player->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL, FROMGODGIFT); + f->obfrom = god->race->id; + } + } else { + f = addtempflag(player->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL, FROMGODGIFT); + f->obfrom = god->race->id; + } + break; + } + } + break; case R_GODPURITY: while (rollagain) { int n,nposs,i; @@ -600,64 +856,6 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { } } break; - case R_GODDEATH: - while (rollagain) { - flag_t *f; - object_t *wep; - rollagain = B_FALSE; - switch (rnd(1,6)) { - case 1: - if (lfhasflag(player, F_SEEINDARK)) { - rollagain = B_TRUE; - } else { - msg("\"Henceforth the night shall be your ally!\""); - f = addtempflag(player->flags, F_SEEINDARK, 4, NA, NA, NULL, FROMGODGIFT); - f->obfrom = god->race->id; - } - break; - case 2: - snprintf(obtogive, BUFLEN, "cursed branded weapon"); - break; - case 3: // poison your weapon - wep = getweapon(player); - if (wep && canbepoisoned(wep->type->id)) { - applyobmod(wep, findobmod(OM_POISONED)); - msg("A layer of venom covers your weapon!"); - } else { - rollagain = B_TRUE; - } - break; - case 4: // resistant/immune to necrotic - if (lfhasflagval(player, F_DTRESIST, DT_NECROTIC, NA, NA, NULL)) { - if (lfhasflagval(player, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL)) { - rollagain = B_TRUE; - } else { - f = addtempflag(player->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL, FROMGODGIFT); - f->obfrom = god->race->id; - } - } else { - f = addtempflag(player->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL, FROMGODGIFT); - f->obfrom = god->race->id; - } - break; - case 5: // become a vampire - if (player->race->id == R_VAMPIRE) { - rollagain = B_TRUE; - } else { - msg("\"Go forth and kill in my name!\""); - setrace(player, R_VAMPIRE, B_TRUE); // ie. don't set origrace! - } - break; - case 6: // necromancy spells - if (!getskill(lf, SK_SS_DEATH)) { - giveskill(lf, SK_SS_DEATH); - } else { - snprintf(obtogive, BUFLEN, "spellbook of necromancy"); - } - break; - } - } - break; case R_GODTHIEVES: while (rollagain) { rollagain = B_FALSE; @@ -694,36 +892,6 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { } } break; - case R_GODMERCY: - while (rollagain) { - flag_t *f; - rollagain = B_FALSE; - switch (rnd(1,4)) { - case 1: - snprintf(obtogive, BUFLEN, "3 vials of ambrosia"); - break; - case 2: - snprintf(obtogive, BUFLEN, "ring of regeneration"); - break; - case 3: - snprintf(obtogive, BUFLEN, "ring of miracles"); - break; - case 4: // immune to disease / poison - if (lfhasflag(player, F_DISEASEIMMUNE)) { - if (lfhasflagval(player, F_DTIMMUNE, DT_POISON, NA, NA, NULL)) { - rollagain = B_TRUE; - } else { - f = addtempflag(player->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL, FROMGODGIFT); - f->obfrom = god->race->id; - } - } else { - f = addtempflag(player->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL, FROMGODGIFT); - f->obfrom = god->race->id; - } - break; - } - } - break; default: break; } // end switch @@ -773,12 +941,18 @@ void godsay(enum RACE rid, int says, char *format, ...) { real_getlfname(god, godname, B_FALSE, B_FALSE); switch (rid) { + case R_GODBATTLE: + strcpy(voiceverb, "rings out from the heavens"); + break; case R_GODDEATH: strcpy(voiceverb, "grates against your mind"); break; case R_GODTHIEVES: strcpy(voiceverb, "whispers in your ear"); break; + case R_GODMAGIC: + strcpy(voiceverb, "enters your thoughts"); + break; case R_GODMERCY: strcpy(voiceverb, "washes over you"); break; @@ -821,9 +995,15 @@ void pleasegod(enum RACE rid, int amt) { if (hasflag(lf->flags, F_PRAYEDTO)) { if (!isasleep(lf)) { switch (rid) { + case R_GODBATTLE: + msg("You feel triumphant."); + break; case R_GODDEATH: msg("You feel a thrill of unholy ecstasy."); break; + case R_GODMAGIC: + msg("You feel Lumara's presense nearby."); + break; case R_GODMERCY: msg("You feel a sense of peace."); break; @@ -904,6 +1084,79 @@ int prayto(lifeform_t *lf, lifeform_t *god) { object_t *o; object_t *oposs[MAXPILEOBS]; int noposs = 0, n; + case R_GODBATTLE: + if (isinbattle(player, B_TRUE)) { + int redo = B_TRUE; + object_t *o; + while (redo) { + redo = B_FALSE; + switch (rnd(1,4)) { + case 1: // bless weapon + msg("\"Fight in my name!\""); + o = getweapon(player); + if (o && !isblessed(o)) { + blessob(o); + } else { + redo = B_TRUE; + } + break; + case 2: // bezerk + if (lfhasflag(player, F_RAGE)) { + redo = B_TRUE; + } else { + msg("\"Rage like a badger!\""); + player->stamina = getmaxstamina(player); + abilityeffects(player, OT_A_RAGE, player->cell, player, NULL); + } + break; + case 3: // + msg("\"I will guide your blade!\""); + dospelleffects(god, OT_S_TRUESTRIKE, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); + break; + case 4: // + msg("\"Your blows will be as lightning!\""); + dospelleffects(god, OT_S_HASTE, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); + break; + } // end switch + }// end while redo + } else { + // not in battle... + int redo = B_TRUE,i; + object_t *o; + while (redo) { + redo = B_FALSE; + switch (rnd(1,3)) { + case 1: // detect life + msg("\"Seek out battle in my name!\""); + dospelleffects(god, OT_S_DETECTLIFE, 10, lf, NULL, lf->cell, B_BLESSED, NULL, B_TRUE); + break; + case 2: // bless weapon + msg("\"Fight in my name!\""); + o = getweapon(player); + if (o && !isblessed(o)) { + blessob(o); + } else { + redo = B_TRUE; + } + break; + case 3: // repair armour + i = 0; + for (o = lf->pack->first ; o ; o = o->next) { + if (isdamaged(o)) { + dospelleffects(lf, OT_S_MENDING, 10, NULL, o, NULL, B_BLESSED, NULL, B_FALSE); + i++; + } + } + if (i) { + msg("\"Keep fighting, warrior!\""); + } else { + redo = B_TRUE; + } + break; + } // end switch + }// end while redo + } + break; case R_GODPURITY: msg("\"Witness the holy radiance of purity!\""); c = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND); @@ -962,7 +1215,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { who = lf->los[i]->lf; if (who && !areallies(lf, who)) { if (isundead(who)) { - makepeaceful(who); + makepeaceful(who, god); } else { castspell(god, n, who, NULL, who->cell, NULL, NULL); break; @@ -973,7 +1226,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { dospelleffects(god, OT_S_ANIMATEDEAD, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); break; case R_GODTHIEVES: - if (isinbattle(lf)) { + if (isinbattle(lf, B_TRUE)) { lifeform_t *l; int donesomething = B_FALSE; if (islowhp(lf)) { @@ -1025,9 +1278,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { object_t *possob[MAXPILEOBS]; int npossob,i,first; while (redo) { - redo = B_FALSE; - switch (rnd(1,2)) { case 1: msg("\"Allow me to reveal your surroundings...\""); @@ -1078,6 +1329,40 @@ int prayto(lifeform_t *lf, lifeform_t *god) { }// end while redo } break; + case R_GODMAGIC: + if (player->mp <= (getmaxmp(player)/2)) { + gainmp(lf, getmaxmp(lf)); + msg("\"I have replenished your magical reserves!\""); + } else { + object_t *toid[MAXPILEOBS],*touncurse[MAXPILEOBS]; + int idnum = 0, uncursenum = 0; + // any unid'd scrolls/books? + for (o = player->pack->first ; o ; o = o->next) { + if ((o->type->obclass->id == OC_SCROLL) || (o->type->obclass->id == OC_BOOK)) { + if (!isknown(o)) { + toid[idnum++] = o; + } + if (isequipped(o) && iscursed(o)) { + touncurse[uncursenum++] = o; + } + } + } + + if (idnum) { + msg("\"I grant you the favour of knowledge!\""); + o = toid[rnd(0,idnum-1)]; + dospelleffects(god, OT_S_IDENTIFY, 10, NULL, o, NULL, B_UNCURSED, NULL, B_FALSE); + } else if (uncursenum) { + msg("\"I grant you the favour of redemption!\""); + o = touncurse[rnd(0,uncursenum-1)]; + uncurseob(o, NULL); + } else { + // just regain mana. + gainmp(lf, getmaxmp(lf)); + msg("\"I have replenished your magical reserves!\""); + } + } + break; case R_GODMERCY: if (ispoisoned(lf)) { msg("\"Let thy body be purged of toxins.\""); diff --git a/io.c b/io.c index f071c09..53dc355 100644 --- a/io.c +++ b/io.c @@ -52,8 +52,6 @@ extern enum ERROR reason; extern char msghist[MAXHISTORY][BUFLEN]; extern int nmsghist; -extern void (*precalclos)(lifeform_t *); - extern lifeform_t *godlf[]; extern int ngodlfs; @@ -1267,6 +1265,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_MISCASTCHANCE: + if (isplayer(lf)) { + msg("Your magical ability feels unreliable..."); + donesomething = B_TRUE; + } + break; case F_ASLEEP: if (isplayer(lf) && (f->val[2] != NA)) { // ie. resting, not forced asleep object_t *restob; @@ -1926,6 +1930,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_MISCASTCHANCE: + if (isplayer(lf)) { + msg("Your magical ability no longer feels unreliable."); + donesomething = B_TRUE; + } + break; case F_ATTACHEDTO: lf2 = findlf(NULL, f->val[0]); if (lf2 && !isdead(lf2)) { @@ -3950,7 +3960,7 @@ void docomms(lifeform_t *lf) { // if humanoid+intelligent, say thanks. if (cantalk(lf)) sayphrase(lf, SP_THANKS, SV_TALK, NA, NULL); // calm down - makepeaceful(lf); + makepeaceful(lf, player); // chance of becoming a pet if you gave something other than // money if (givenob->type->id != OT_GOLD) { @@ -4836,6 +4846,9 @@ char *makedesc_god(lifeform_t *god, char *retbuf) { case F_GEM: sprintf(thisline, "- gems\n"); break; + case F_BATTLESPOILS: + sprintf(thisline, "- untouched battle spoils\n"); + break; default: break; } @@ -5937,6 +5950,10 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf2, "%s boosts the power of your spells by %d.\n", buf, f->val[1]); strncat(retbuf, buf2, HUGEBUFLEN); break; + case F_MISCASTCHANCE: + sprintf(buf2, "%s causes your spells to become unreliable.\n", buf); + strncat(retbuf, buf2, HUGEBUFLEN); + break; case F_MEDITATES: sprintf(buf2, "%s allows you to retain awareness while resting.", buf); strncat(retbuf, buf2, HUGEBUFLEN); @@ -11702,6 +11719,14 @@ void showlfstats(lifeform_t *lf, int showall) { isplayer(lf) ? "your" : "its", boost); y++; } + f = lfhasknownflag(lf, F_MISCASTCHANCE); + if (f && (f->known)) { + int chance; + sumflags(lf->flags, F_MISCASTCHANCE, &chance, NULL, NULL); + mvwprintw(mainwin, y, 0, "%s spells have a %d%% chance of failure.", + isplayer(lf) ? "Your" : "Its", chance); + y++; + } f = lfhasflag(lf, F_OMNIPOTENT); if (f && (f->known)) { @@ -12088,7 +12113,9 @@ void showlfstats(lifeform_t *lf, int showall) { strcat(pietybuf, colbuf); for (n = PIETY_MIN; n <= PIETY_MAX; n += 25) { - if ((piety >= n) && (piety < n+25)){ + if (blocked) { + strcat(pietybuf, " "); + } else if ((piety >= n) && (piety < n+25)){ strcat(pietybuf, "+"); } else { strcat(pietybuf, "-"); diff --git a/lf.c b/lf.c index 23ce0a4..036f4d5 100644 --- a/lf.c +++ b/lf.c @@ -24,8 +24,6 @@ extern double precos[]; extern FILE *logfile; -extern void (*precalclos)(lifeform_t *); - extern int noredraw; extern int enteringmap; @@ -1800,6 +1798,10 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar } } if (isplayer(lf)) { + pleasegodmaybe(R_GODMAGIC, getspelllevel(sid)); + if (!fromob) { + angergodmaybe(R_GODBATTLE, 25, GA_SPELL); + } switch (school) { case SS_DEATH: pleasegodmaybe(R_GODDEATH, getspelllevel(sid)); @@ -2289,11 +2291,11 @@ int demandbribe(lifeform_t *lf) { if (satisfied) { int nminions; lifeform_t *minion[MAXCANDIDATES]; - makepeaceful(lf); + makepeaceful(lf, player); // also make any of its minions peaceful getminions(lf, minion, &nminions); for (i = 0; i < nminions; i++) { - makepeaceful(minion[i]); + makepeaceful(minion[i], player); } } @@ -2424,6 +2426,9 @@ void die(lifeform_t *lf) { god = getrandomprayedgod(); if (god && !godisangry(god->race->id)) { switch (god->race->id) { + case R_GODBATTLE: + godsay(god->race->id, B_TRUE, "Rest in peace, brave warrior!"); more(); + break; case R_GODDEATH: godsay(god->race->id, B_TRUE, "Come to me, my servant..."); more(); msg("Bony claws rise up and drag your corpse underground."); more(); break; @@ -2554,7 +2559,13 @@ void die(lifeform_t *lf) { if (vaporised) { killob(lf->pack->first); } else { - if (!moveob(lf->pack->first, corpsecell->obpile, ALL)) { + object_t *droppedob; + droppedob = moveob(lf->pack->first, corpsecell->obpile, ALL); + if (droppedob) { + if (killer && isplayer(killer)) { + addflag(droppedob->flags, F_BATTLESPOILS, B_TRUE, NA, NA, NULL); + } + } else { killob(lf->pack->first); } } @@ -2716,6 +2727,21 @@ void die(lifeform_t *lf) { } } // end if corpsecell + // player killed last monster? + if (killer && isplayer(killer) && !isplayer(lf)) { + lifeform_t *l; + int battledone = B_TRUE; + for (l = lf->cell->map->lf ; l ; l = l->next) { + if (!isplayer(l) && areenemies(l, player) && haslof(l->cell, player->cell, LOF_WALLSTOP, NULL)) { + battledone = B_FALSE; + break; + } + } + if (battledone) { + pleasegodmaybe(R_GODBATTLE, 5); + } + } + if (willbecomeghost) { flag_t *f, *nextf; @@ -4483,10 +4509,11 @@ int flee(lifeform_t *lf) { // can we flee via stairs? stairs = hasobwithflag(lf->cell->obpile, F_CLIMBABLE); if (stairs) { + if (db) dblog("%s - trying to flee via %s", lfname, stairs->type->name); if (!usestairs(lf, stairs, B_TRUE, B_TRUE)) { - if (db) dblog("%s - fleeing via %s", stairs->type->name); return B_TRUE; } + if (db) dblog("%s - failed to flee via %s", lfname, stairs->type->name); } // move away from them if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH, B_FALSE, B_FALSE)) { @@ -6394,6 +6421,9 @@ int getmiscastchance(lifeform_t *lf) { flag_t *retflag[MAXCANDIDATES]; int nretflags,i; int chance = 0; + + sumflags(lf->flags, F_MISCASTCHANCE, &chance, NULL, NULL); + getflags(lf->flags, retflag, &nretflags, F_ARMOURPENALTY, F_SHIELDPENALTY, F_NONE); for (i = 0; i < nretflags; i++) { int (*adjustfunc)(lifeform_t *, float) = NULL; @@ -9123,7 +9153,7 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { } } else if (id == SK_SS_ALLOMANCY) { // give all allomantic spells - mayusespellschool(lf->flags, SS_ALLOMANCY, F_CANCAST); + mayusespellschool(lf->flags, SS_ALLOMANCY, F_CANCAST , B_FALSE); } else if (id == SK_SS_MENTAL) { // give a spell /* @@ -10886,17 +10916,22 @@ flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt, int onlytemp) { } -int isinbattle(lifeform_t *lf) { - int dir; - if (isblind(lf)) { - return B_FALSE; - } - - for (dir = DC_N; dir <= DC_NW; dir++) { - cell_t *c; - c = getcellindir(lf->cell, dir); - if (c && c->lf && areenemies(lf, c->lf)) { - return B_TRUE; +int isinbattle(lifeform_t *lf, int includedistant) { + if (includedistant) { + lifeform_t *l; + for (l = lf->cell->map->lf ; l ;l = l->next) { + if ((l != lf) && areenemies(l, lf) && cansee(lf, l)) { + return B_TRUE; + } + } + } else { + int dir; + for (dir = DC_N; dir <= DC_NW; dir++) { + cell_t *c; + c = getcellindir(lf->cell, dir); + if (c && c->lf && areenemies(lf, c->lf) && cansee(lf, c->lf)) { + return B_TRUE; + } } } return B_FALSE; @@ -11300,7 +11335,7 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { a->created = B_FALSE; a->pack = addobpile(a, NOLOC, NOOB); - a->polypack = addobpile(a, NOLOC, NOOB); + a->polypack = addobpile(NOOWNER, NOLOC, NOOB); a->turnsskipped = 0; @@ -11642,7 +11677,7 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { } } -void makepeaceful(lifeform_t *who) { +void makepeaceful(lifeform_t *who, lifeform_t *causedby) { char lfname[BUFLEN]; getlfname(who, lfname); @@ -11658,6 +11693,10 @@ void makepeaceful(lifeform_t *who) { } } + if (causedby && isplayer(causedby)) { + angergodmaybe(R_GODBATTLE, 5, GA_COWARD); + } + addflag(who->flags, F_XPVAL, 0, NA, NA, NULL); killflagsofid(who->flags, F_HOSTILE); @@ -12998,7 +13037,7 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) { } } -void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how) { +void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how, int overridepower) { objecttype_t *ot; skill_t *sk; @@ -13014,7 +13053,13 @@ void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how) { //if (ot->obclass->id == OC_SPELL) { if (hasflagval(ot->flags, F_SPELLSCHOOL, ss, NA, NA, NULL)) { if (!hasflagval(fp, how, ot->id, NA, NA, NULL)) { - addflag(fp, how, ot->id, NA, NA, NULL); + char text[BUFLEN]; + if (overridepower) { + sprintf(text, "pw:%d;",overridepower); + } else { + strcpy(text, ""); + } + addflag(fp, how, ot->id, NA, NA, text); } } //} @@ -14050,7 +14095,7 @@ void practice(lifeform_t *lf, enum SKILL skid, int amt) { } } -void precalclos_new(lifeform_t *lf) { +void precalclos(lifeform_t *lf) { cell_t *c; int startxray,rangemod; int maxvisrange,nightvisrange; @@ -14124,8 +14169,11 @@ void precalclos_new(lifeform_t *lf) { if (!get_adjacent_quadrants(lf->facing, &startq, &endq)) { if (missingeye) endq = startq; // ie. lose the right hand one - if (plev >= PR_MASTER) inc_quad_range(&startq, missingeye ? NULL : &endq, 2); - else if (plev >= PR_ADEPT) inc_quad_range(&startq, missingeye ? NULL : &endq, 1); + if (plev >= PR_MASTER) { + inc_quad_range(&startq, missingeye ? NULL : &endq, 2); + } else if (plev >= PR_ADEPT) { + inc_quad_range(&startq, missingeye ? NULL : &endq, 1); + } curq = startq; get_fov_quad_endpoints(lf, curq, maxvisrange, endx, endy, &nendcells); @@ -14134,6 +14182,22 @@ void precalclos_new(lifeform_t *lf) { else curq++; get_fov_quad_endpoints(lf, curq, maxvisrange, endx, endy, &nendcells); } + + if (plev >= PR_BEGINNER) { + enum TURNDIR turndir; + cell_t *adjcell; + // include cells immediately to the lifeform's left and right. + for (turndir = missingeye ? TD_LEFT : TD_RIGHT; turndir <= TD_LEFT; turndir++) { + int dir; + dir = rotatedir(lf->facing, turndir, 2); + adjcell = getcellindir(lf->cell, dir); + if (adjcell) { + endx[nendcells] = adjcell->x; + endy[nendcells] = adjcell->y; + nendcells++; + } + } + } } } // end if facing == all @@ -16715,14 +16779,14 @@ void startlfturn(lifeform_t *lf) { // calming strong enough? maxhitdice = asp->val[2] + 1; if (gethitdice(lf) <= maxhitdice) { - makepeaceful(lf); + makepeaceful(lf, l); } } } // they are hiding, and you haven't spotted them yet f = ishidingfrom(l, lf); - if (f && !isinbattle(lf)) { + if (f && !isinbattle(lf, B_FALSE)) { // can you see their cell? if (!lfhasflag(lf, F_TRAINING) && haslos(lf, l->cell)) { int bonus = 0; @@ -16746,7 +16810,7 @@ void startlfturn(lifeform_t *lf) { } // secret doors, traps, etc? - if (isplayer(lf) && !isinbattle(lf) && !isblind(lf) && !lfhasflag(lf, F_TRAINING)) { + if (isplayer(lf) && !isinbattle(lf, B_TRUE) && !isblind(lf) && !lfhasflag(lf, F_TRAINING)) { for (i = 0; i < lf->nlos; i++) { if (!lf->los[i]->lf || (lf->los[i]->lf == lf)) { object_t *o; @@ -17900,6 +17964,8 @@ int touch(lifeform_t *lf, object_t *o) { if ((gamemode != GM_GAMESTARTED)) return B_FALSE; + touch_battle_spoils(o); + getlfname(lf, lfname); getobname(o, obname, o->amt); @@ -18217,7 +18283,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { if (hasflag(o->flags, F_LOCKED)) { if (isplayer(lf)) msg("The %s seems to be locked.", noprefix(obname)); if (onpurpose) taketime(lf, getmovespeed(lf)); - return B_FALSE; + return B_TRUE; } curmap = obcell->map; diff --git a/lf.h b/lf.h index e274dc2..08c1443 100644 --- a/lf.h +++ b/lf.h @@ -305,7 +305,7 @@ flag_t *ishidingfrom(lifeform_t *hider, lifeform_t *seeker); int ishirable(lifeform_t *lf); int isimmobile(lifeform_t *lf); flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt, int onlytemp); -int isinbattle(lifeform_t *lf); +int isinbattle(lifeform_t *lf, int includedistant); int isingunrange(lifeform_t *lf, cell_t *where); int isloreskill(enum SKILL skid); int islowhp(lifeform_t *lf); @@ -344,9 +344,9 @@ void losemp(lifeform_t *lf, int amt); void makefriendly(lifeform_t *lf, int howlong); int makenauseated(lifeform_t *lf, int amt, int howlong); void makenoise(lifeform_t *lf, enum NOISETYPE nid); -void makepeaceful(lifeform_t *lf); +void makepeaceful(lifeform_t *lf, lifeform_t *causedby); lifeform_t *makezombie(object_t *o); -void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how); +void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how, int overridepower); int meetsallattreqs(lifeform_t *lf, object_t *o); int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o, int *modpct); int mightflee(lifeform_t *lf); @@ -367,8 +367,8 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char int poisoncausesvomit(enum POISONTYPE ptype); int poisonthreatenslife(lifeform_t *lf, flag_t *f); void practice(lifeform_t *lf, enum SKILL skid, int amt); -void precalclos_old(lifeform_t *lf); -void precalclos_new(lifeform_t *lf); +//void precalclos_old(lifeform_t *lf); +void precalclos(lifeform_t *lf); void preparecorpse(lifeform_t *lf, object_t *corpse); int push(lifeform_t *lf, object_t *o, int dir); int readytotrain(lifeform_t *lf); diff --git a/move.c b/move.c index 72a3f46..8378eca 100644 --- a/move.c +++ b/move.c @@ -24,8 +24,6 @@ extern int needredraw; extern enum GAMEMODE gamemode; -extern void (*precalclos)(lifeform_t *); - extern enum ERROR reason; extern void *rdata; @@ -1556,6 +1554,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { getlfname(lf, lfname); + // is current cell dark? if (isplayer(lf)) { if (!haslos(lf, lf->cell) && !isblind(lf)) { @@ -2439,6 +2438,22 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int onpurpose, int *didmsg) { return B_FALSE; } +int rotatedir(int origdir, enum TURNDIR whichway, int amt) { + int newdir,mod,i; + newdir = origdir; + if (whichway == TD_RIGHT) { + mod = 1; + } else { + mod = -1; + } + for (i = 0; i < amt; i++) { + newdir += mod; + if (newdir > DC_NW) newdir = DC_N; + if (newdir < DC_N) newdir = DC_NW; + } + return newdir; +} + void standup(lifeform_t *lf) { if (isplayer(lf)) { msg("You stand up."); @@ -2584,7 +2599,10 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { int howlong; int reldir; int srcmoney = 0; + int prebattle = B_FALSE; flag_t *f; + // are we next to an enemy who we can see? + prebattle = isinbattle(lf, B_FALSE); howlong = getmovespeed(lf); @@ -2609,6 +2627,12 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { } } taketime(lf, getturnspeed(lf)); + // check for fleeing... + if (isplayer(lf) && !isdead(lf)) { + if (prebattle && !isinbattle(lf, B_FALSE) && onpurpose) { + angergodmaybe(R_GODBATTLE, 15, GA_COWARD); + } + } return B_FALSE; } else { // player can't strafe while stuck. @@ -3057,11 +3081,18 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { } - // purposely moving away fmor money? + // purposely moving away from money? if (onpurpose && isplayer(lf) && srcmoney) { angergodmaybe(R_GODTHIEVES, srcmoney, GA_MONEY); } + // check for fleeing... + if (isplayer(lf) && !isdead(lf)) { + if (prebattle && !isinbattle(lf, B_FALSE) && onpurpose) { + angergodmaybe(R_GODBATTLE, 10, GA_COWARD); + } + } + if (reason != E_OK) { return B_TRUE; } diff --git a/move.h b/move.h index 111632d..3661ae6 100644 --- a/move.h +++ b/move.h @@ -28,6 +28,7 @@ int pullnextto(lifeform_t *lf, cell_t *c); int initiatemove(lifeform_t *lf, cell_t *cell, int onpurpose, int *didmsg); int isorthogonal(int dir); int ispossiblemove(lifeform_t *lf, int dir); +int rotatedir(int origdir, enum TURNDIR whichway, int amt); void standup(lifeform_t *lf); void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int changedir, int onpurpose); int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke); diff --git a/nexus.c b/nexus.c index 3a3f93a..0b6c9e4 100644 --- a/nexus.c +++ b/nexus.c @@ -57,8 +57,6 @@ int maxmonhitdice = 0; // highest number of hitdice for any monster double presin[360]; double precos[360]; -void (*precalclos)(lifeform_t *) = NULL; - extern vault_t *firstvault; extern flag_t *retflag[]; @@ -125,6 +123,8 @@ int main(int argc, char **argv) { cell_t *c,*targc; vault_t *v; enum SKILLLEVEL slev; + flag_t *retflag[MAXCANDIDATES]; + int nretflags; atexit(cleanup); @@ -437,11 +437,13 @@ int main(int argc, char **argv) { } // pet / npc / follower - f = lfhasflag(player, F_HASPET); - if (f) { + getflags(player->flags, retflag, &nretflags, F_HASPET, F_NONE); + for (i = 0; i < nretflags; i++) { cell_t *c; race_t *r; lifeform_t *pet; + + f = retflag[i]; r = findracebyname(f->text); assert(r); @@ -1116,8 +1118,6 @@ int init(void) { precos[i] = cos(rads); } - precalclos = precalclos_new; - gamemode = GM_INIT; playerglyph.ch = '@'; diff --git a/objects.c b/objects.c index e3d8038..9361916 100644 --- a/objects.c +++ b/objects.c @@ -36,8 +36,6 @@ extern int nbuildingusage; extern int inaskcoords; -void (*precalclos)(lifeform_t *); - extern object_t *retobs[MAXPILEOBS+1]; extern int retobscount[MAXPILEOBS+1]; extern int nretobs; @@ -1363,7 +1361,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes if (bookcontents == -1) { if (o->type->id == OT_SPELLBOOK) { // pick a random school - bookcontents = getrandomspellschool(); + bookcontents = getrandomspellschool(NULL, B_FALSE); //bookcontents = getrandomspell(maxlev); //while (!schoolappearsinbooks(getspellschool(bookcontents))) { // bookcontents = getrandomspell(maxlev); @@ -7650,6 +7648,7 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { return NULL; } + touch_battle_spoils(src); // object being taken from an unconscious lf? if (src->pile->owner && isunconscious(src->pile->owner)) { @@ -8313,6 +8312,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { int playercansee; flag_t *f; int willid = B_FALSE; + int wastech = B_FALSE; if (!lfhasflag(lf, F_HUMANOID) || !hasbp(lf, BP_HANDS)) { // only humanoids can zap things @@ -8337,6 +8337,9 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { playercansee = B_FALSE; } + if (o->type->obclass->id == OC_TECH) { + wastech = B_TRUE; + } // if not a wand, must know what a tool is before you can use it @@ -8770,6 +8773,12 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } } } + + // bjorn doesn't like magic, even from wands + angergodmaybe(R_GODBATTLE, 25, GA_SPELL); + // lumara does. + pleasegodmaybe(R_GODMAGIC, 2); + // FROM HERE ON ARE INDIVIDUAL ONES } else if (o->type->id == OT_BUTANETORCH) { int seen = B_FALSE; @@ -9274,6 +9283,12 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } else if (hasflag(o->flags, F_SHOP)) { shop(lf, o); } + + + if (wastech && isplayer(lf)) { + angergodmaybe(R_GODMAGIC, 10, GA_HERESY); + } + return B_FALSE; } @@ -9894,6 +9909,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE case OT_POT_FURY: lf->stamina = getmaxstamina(lf); abilityeffects(lf, OT_A_RAGE, lf->cell, lf, NULL); + pleasegodmaybe(R_GODBATTLE, 15); break; case OT_POT_GASEOUSFORM: dospelleffects(lf, OT_S_GASEOUSFORM, (potblessed) ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE); @@ -10189,6 +10205,7 @@ int readsomething(lifeform_t *lf, object_t *o) { int needsob = B_FALSE; objecttype_t *linkspell; int readtime; + int pleasemagicgod = B_FALSE; if (!haslos(lf, lf->cell)) { if (isplayer(lf)) { @@ -10318,6 +10335,13 @@ int readsomething(lifeform_t *lf, object_t *o) { } } + if (ismagical(o)) { + pleasemagicgod = B_TRUE; + ///... we might change this back to false later + // if a scroll causes us to cast a spell, so that we + // dont double up the god bonus. + } + // special scrolls if ((o->type->id == OT_SCR_IDENTIFY) && isblessed(o)) { int seen = B_FALSE; @@ -10360,6 +10384,8 @@ int readsomething(lifeform_t *lf, object_t *o) { int seen = B_FALSE; int noeffect = B_FALSE; + pleasemagicgod = B_FALSE; + // for unidentified scrolls which target an object, // let player select ANY object (even if it won't // work). @@ -10542,7 +10568,11 @@ int readsomething(lifeform_t *lf, object_t *o) { } } //end if isplayer } else if (o->type->id == OT_SCR_AWARENESS) { - addtempflag(lf->flags, F_AWARENESS, B_TRUE, NA, NA, NULL, getspellduration(30,60,o->blessed)); + if (iscursed(o)) { + addtempflag(lf->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(20,30)); + } else { + addtempflag(lf->flags, F_AWARENESS, B_TRUE, NA, NA, NULL, getspellduration(30,60,o->blessed)); + } if (isplayer(lf)) msg("The scroll crumbles to dust."); // removeob one of the object removeob(o, 1); @@ -10712,6 +10742,11 @@ int readsomething(lifeform_t *lf, object_t *o) { removeob(o, 1); } } + + if (pleasemagicgod && isplayer(lf)) { + pleasegodmaybe(R_GODMAGIC, 2); + } + return B_FALSE; } @@ -12347,6 +12382,9 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp msg("Your %s is now out of ammo.", noprefix(buf)); } */ + if (thrower && isplayer(thrower)) { + angergodmaybe(R_GODMAGIC, 10, GA_HERESY); + } return B_FALSE; } @@ -12502,7 +12540,7 @@ void timeeffectsob(object_t *o) { sg = hasobwithflagval(location->obpile, F_REPELBLESSED, NA, o->blessed, NA, NULL); if (sg && !o->blessknown) { // announce - msg("Your %s feels very %s!", noprefix(obname), (o->blessed == B_BLESSED) ? "warm" : "cold"); + msg("Your %s feel%s very %s!", noprefix(obname), (o->amt == 1) ? "s" : "", (o->blessed == B_BLESSED) ? "warm" : "cold"); // player now knows that this is blessed/cursed o->blessknown = B_TRUE; } @@ -12879,6 +12917,18 @@ void timeeffectsob(object_t *o) { checkflagpile(o->flags); } +int touch_battle_spoils(object_t *o) { + int ndone = 0; + ndone = killflagsofid(o->flags, F_BATTLESPOILS); + if (o->pile->where) { + object_t *oo; + for (oo = o->pile->first; oo ; oo = oo->next) { + ndone += killflagsofid(oo->flags, F_BATTLESPOILS); + } + } + return ndone; +} + // both trapob and oid are passed, because trapob might be NULL if // coming from a door/chest trap. void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) { @@ -13061,9 +13111,6 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) { } if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards } else if (oid == OT_TRAPLIGHTNING) { - if (haslos(player, c)) { - msg("A blast of lightning shoots from the ceiling!"); - } // can't be dodged dospelleffects(NULL, OT_S_CHAINLIGHTNING, 3, NULL, NULL, c, B_UNCURSED, NULL, B_TRUE); if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards diff --git a/objects.h b/objects.h index cd4e2e6..945fbe5 100644 --- a/objects.h +++ b/objects.h @@ -271,6 +271,7 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce); int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, object_t *firearm); int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, object_t *firearm, int announcethrow); void timeeffectsob(object_t *o); +int touch_battle_spoils(object_t *o); void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c); void turnoff(lifeform_t *lf, object_t *o); void turnon(lifeform_t *lf, object_t *o); diff --git a/save.c b/save.c index 224d779..636fca6 100644 --- a/save.c +++ b/save.c @@ -26,6 +26,8 @@ extern knowledge_t *knowledge; extern region_t *firstregion,*lastregion; extern regionoutline_t *firstregionoutline,*lastregionoutline; +extern map_t *heaven; + extern long curtime, gamedays, gamesecs; extern enum GAMEMODE gamemode; @@ -34,6 +36,7 @@ int loadall(void) { DIR *dir; struct dirent *ent; int db = B_FALSE; + region_t *heavenregion; gamemode = GM_LOADING; @@ -69,6 +72,10 @@ int loadall(void) { } closedir(dir); + // update fixed region pointers + heavenregion = findregionbytype(RG_HEAVEN); + heaven = findregionmap(heavenregion->id, 1); + loadsavegame(); gamemode = GM_LOADED; @@ -702,8 +709,10 @@ int loadregions(void) { for (n = 0; n < numregions; n++) { region_t *r; enum REGIONTYPE rtid; + int rid; int outlineid,parentid,nthings; fscanf(f, "startregion\n"); + fscanf(f, " id:%d\n",(int *)&rid); fscanf(f, " rtypeid:%d\n",(int *)&rtid); fscanf(f, " outline:%d\n",&outlineid); fscanf(f, " parentregion:%d\n",&parentid); @@ -711,6 +720,7 @@ int loadregions(void) { fscanf(f, " depthmod:%d\n",&depthmod); fscanf(f, "endregion\n"); r = addregion(rtid, (parentid == -1) ? NULL : findregion(parentid), outlineid, depthmod); + r->id = rid; r->nthings = nthings; if (db) dblog("Loaded region #%d / %d",n+1, numregions); } @@ -719,7 +729,7 @@ int loadregions(void) { // successful load - kill the file now unlink(filename); - + return B_FALSE; } @@ -1104,6 +1114,7 @@ int saveregions(void) { fprintf(f, "numregions:%d\n",numregions); for (r = firstregion ; r; r = r->next) { fprintf(f, "startregion\n"); + fprintf(f, " rid:%d\n",r->id); fprintf(f, " rtypeid:%d\n",r->rtype->id); fprintf(f, " outline:%d\n",r->outline ? r->outline->id : -1); fprintf(f, " parentregion:%d\n",r->parentregion ? r->parentregion->id : -1); diff --git a/spell.c b/spell.c index 27523b2..facc61c 100644 --- a/spell.c +++ b/spell.c @@ -49,8 +49,6 @@ extern int ngodlfs; extern enum ERROR reason; -extern void (*precalclos)(lifeform_t *); - extern int needredraw, statdirty; // return value of FALSE means that stamina costs should be charged. @@ -494,7 +492,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (lf == user) continue; // within lof of stairs? if (haslof(lf->cell, c, LOF_WALLSTOP, NULL)) { - trailob = addtrail(lf, c, lf->facing, B_TRUE, B_FALSE); + int dirtolf; + dirtolf = getdirtowards(c, lf->cell, NULL, B_FALSE, DT_ORTH); + trailob = addtrail(lf, c, dirtolf, B_TRUE, B_FALSE); if (trailob) { if (canseeob(user, trailob)) { int found = B_FALSE; @@ -1939,7 +1939,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (num >= satedat) { // sated. killflagsofid(user->flags, F_ATTACHEDTO); - makepeaceful(user); + makepeaceful(user, NULL); addflag(user->flags, F_FLEEONDAM, B_TRUE, NA, NA, NULL); addflag(user->flags, F_DIESPLATTER, 3, NA, NA, "splash of blood"); // counter will keep ticking up. @@ -2294,6 +2294,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) msg("There is nobody there to trip!"); return B_TRUE; } + if (isairborne(target)) { + if (isplayer(user)) msg("You can't trip someone in the air!"); + return B_TRUE; + } + + getlfname(target, targetname); wep = getweapon(user); @@ -4219,7 +4225,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (c->lf && (c->lf != caster) && (c->lf->race->raceclass->id == RC_ANIMAL) && lfhasflag(c->lf, F_HOSTILE)) { if (gethitdice(c->lf) <= powerleft) { powerleft -= gethitdice(c->lf); - makepeaceful(c->lf); + makepeaceful(c->lf, caster); ncalmed++; @@ -5140,8 +5146,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_DETECTLIFE) { - target = caster; - if (isplayer(caster)) { + if (!target) { + if (targcell) { + target = targcell->lf; + } else { + target = caster; + } + } + if (isplayer(target)) { int howlong,radius; howlong = getspellduration(40,80,blessed) + (power*2); radius = power * 10; @@ -6449,7 +6461,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ iqb = getattrbracket(getattr(target, A_IQ), A_IQ, NULL); if ((iqb >= IQ_ANIMAL) && cansee(target, caster)) { if (skillcheckvs(caster, SC_MORALE, 3, target, SC_MORALE, 0)) { - makepeaceful(target); + makepeaceful(target, caster); } } } @@ -7501,7 +7513,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } - } else if (spellid == OT_S_INSCRIBE) { + /*} else if (spellid == OT_S_INSCRIBE) { char buf[BUFLEN]; if (isplayer(caster)) { if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -7518,6 +7530,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { // monsters can't cast } + */ } else if (spellid == OT_S_INSTANTDISROBE) { cell_t *newcell = NULL; int howmany = (power / 4)+1,ndone = 0; @@ -7532,8 +7545,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // find cell next to caster newcell = getrandomadjcell(targcell, WE_WALKABLE, B_NOEXPAND); if (!newcell) { - fizzle(caster); - return B_TRUE; + newcell = targcell; } for (i = 0; i < howmany; i++) { // pick armour @@ -9083,15 +9095,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (targcell->lf) { - losehp(targcell->lf, rnd(2,2), DT_FIRE, caster, "a spark"); - } else { - for (o = targcell->obpile->first ; o ; o = nexto) { - nexto = o->next; - // special cases - if (isflammable(o) || (o->type->id == OT_CANDLE) || (o->type->id == OT_TORCH)) { - takedamage(o, 1, DT_FIRE); - donesomething = B_TRUE; - } + losehp(targcell->lf, roll("2d2"), DT_FIRE, caster, "a burst of flame"); + } + for (o = targcell->obpile->first ; o ; o = nexto) { + nexto = o->next; + // special cases + if (isflammable(o) || (o->type->id == OT_CANDLE) || (o->type->id == OT_TORCH)) { + takedamage(o, 1, DT_FIRE); + donesomething = B_TRUE; } } } else if (spellid == OT_S_SPEAKDEAD) { @@ -10691,16 +10702,31 @@ enum OBTYPE getrandomspellfromschool(enum SPELLSCHOOL school, int wantlev) { return ot->id; } -enum SPELLSCHOOL getrandomspellschool(void) { +// if wantknowntolf isn't passed, then wantknown is ignored. +enum SPELLSCHOOL getrandomspellschool(lifeform_t *wantknowntolf, int wantknown) { enum SPELLSCHOOL poss[MAXCANDIDATES],ss; int nposs = 0; // count valid schools for (ss = SS_NONE; ss <= SS_LAST; ss++) { if (schoolappearsinbooks(ss) && !streq(getschoolname(ss), "badschool")) { - poss[nposs++] = ss; + int valid = B_FALSE; + if (wantknowntolf) { + enum SKILLLEVEL slev; + slev = getskill(wantknowntolf, getschoolskill(ss)); + if ((slev && wantknown) || (!slev && !wantknown)) { + valid = B_TRUE; + } + } else { + valid = B_TRUE; + } + if (valid) { + poss[nposs++] = ss; + } } } - // make + if (!nposs) { + return SS_NONE; + } return poss[rnd(0,nposs-1)]; } diff --git a/spell.h b/spell.h index 34e39ec..f3557a5 100644 --- a/spell.h +++ b/spell.h @@ -14,7 +14,7 @@ int getmpcost(lifeform_t *lf, enum OBTYPE oid); int getmrdiff(enum OBTYPE spellid, int power); enum OBTYPE getrandomspell(int maxlev); enum OBTYPE getrandomspellfromschool(enum SPELLSCHOOL school, int wantlev); -enum SPELLSCHOOL getrandomspellschool(void); +enum SPELLSCHOOL getrandomspellschool(lifeform_t *wantknowntolf, int wantknown); enum SKILL getschoolskill(enum SPELLSCHOOL ss); enum SPELLSCHOOL getskillschool(enum SKILL skid); char *getspellcosttext(lifeform_t *lf, enum OBTYPE spellid, int power, char *buf); diff --git a/vaults/labyrinth.vlt b/vaults/labyrinth.vlt index fb8705f..2999d79 100644 --- a/vaults/labyrinth.vlt +++ b/vaults/labyrinth.vlt @@ -1,21 +1,21 @@ ! swirly spiral @id:spiral @map -############### -+.............# -#############.# -#...........#.# -#.#########.#.# -#.#.......#.#.# -#.#.#####.#.#.# -#.#.#..m#.#.#.# -#.#.#.###.#.#.# -#.#.#.....#.#.# -#.#.#######.#.# -#.#.........#.# -#.###########.# -#.............# -############### +############# ++...........# +###########.# +#.........#.# +#.#######.#.# +#.#.....#.#.# +#.#.###.#.#.# +#.#.#.m.#.#.# +#.#.#.###.#.# +#.#.#.....#.# +#.#.#######.# +#.#.........# +#.########### +#...........+ +############# @end @legend @@ -44,4 +44,3 @@ mayrotate rarity:rare maintainedge @end -