diff --git a/ai.c b/ai.c index 25c3db3..fa902db 100644 --- a/ai.c +++ b/ai.c @@ -2475,6 +2475,21 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) { specificcheckok = B_FALSE; } + if ((ot->id == OT_S_DANCINGFLAME) || (ot->id == OT_S_CLEANSINGFIRE)) { + int i; + int found = B_FALSE; + // any fire in sight? + for (i = 0; i < lf->nlos; i++) { + if (hasobofmaterial(lf->los[i]->obpile, MT_FIRE) || + (hasobwithflag(lf->los[i]->obpile, F_ONFIRE))) { + found = B_TRUE; + break; + } + } + if (!found) { + specificcheckok = B_FALSE; + } + } if (ot->id == OT_A_DISARM) { if (!getweapon(victim)) { specificcheckok = B_FALSE; diff --git a/attack.c b/attack.c index ada1143..57739da 100644 --- a/attack.c +++ b/attack.c @@ -1789,9 +1789,9 @@ int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE da getlfname(victim, victimname); // announce real_getobname(shield[i], shname, 1, B_PREMODS, B_NOCONDITION, B_BLINDADJUST, B_NOBLESSINGS, B_NOUSED, B_NOSHOWALL); - if (isplayer(lf)) { // player is atatcking + if (lf && isplayer(lf)) { // player is atatcking msg("%s blocks %s with %s.", victimname, attackname, shname); - } else if (cansee(player, lf) || cansee(player, victim)) { // monster is attacking + } else if ((lf && cansee(player, lf)) || cansee(player, victim)) { // monster is attacking msg("%s block%s %s with %s.", victimname, isplayer(victim) ? "" : "s", attackname, shname); } diff --git a/data.c b/data.c index 3ebf127..a17fcf1 100644 --- a/data.c +++ b/data.c @@ -196,7 +196,7 @@ void initjobs(void) { addsubjob(SJ_PALADIN, "Paladin", "Paladins are holy warriors dedicated to the Goddess of Life. They gain powerful abilities and have access to healing magics, but these powers are dependant upon their goddess' approval. Paladins must take holy vows to only ever use battle equipiment which has first been blessed.", 'p'); addsubjob(SJ_SCOURGE, "Scourge", "Scourges have dedicated their life to ridding the world of magic. Strict training has granted them an innate immunity to magic, but this immunity also extends to beneficial effects.", 's'); addsubjob(SJ_AIRMAGE, "Skymage", "Initially the weakest of the mages, higher level Skymages become both extremely versatile and extremely power.", 's'); - addsubjob(SJ_WILDMAGE, "Wizard", "", 'w'); + addsubjob(SJ_WILDMAGE, "Wild Mage", "Wild mages specialise in the random power of wild magic.", 'w'); // job definitions @@ -904,7 +904,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_LORE_UNDEAD, NA, NA, NULL); // abilities addflag(lastjob->flags, F_NEEDOBFORSPELLS, OT_WIZARDSTAFF, NA, NA, NULL); - addflag(lastjob->flags, F_MAXHPMOD, 50, NA, NA, NULL); // low hp + addflag(lastjob->flags, F_MAXHPMOD, 80, NA, NA, NULL); // low hp addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); addflag(lastjob->flags, F_RESTHEALTIME, 6, NA, NA, NULL); // wizard heals slowly, but regenerates mp addflag(lastjob->flags, F_LEVFLAG, 3, F_DETECTMAGIC, B_TRUE, NULL); @@ -3238,18 +3238,13 @@ void initobjects(void) { // elemental - fire magic /////////////////// // l1 - addot(OT_S_BURNINGFEET, "hotfoot", "Heats the soles of the target's feet to an uncomfortable level, dealing 1 fire damage each turn they remain still.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "If the target is wearing metal footwear, damage is inceased to 2 per turn."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines its duration (maximum 6 turns)."); + addot(OT_S_DANCINGFLAME, "dancing flame", "Causes all fires in sight to 'dance' to adjacent creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); 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, 3, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); - addflag(lastot->flags, F_MAXPOWER, 3, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODFIRE, 1, NA, NULL); - addot(OT_S_SPARK, "flambe", "Creates very hot but short lived burst of flame around the target, dealing 2d2 fire damage to creatures and objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_SPARK, "flambe", "Creates very hot but short lived burst of flame around the target, dealing 2d3 fire damage to creatures and objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); 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); @@ -3264,14 +3259,21 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODFIRE, 1, NA, NULL); - // l2 addot(OT_S_BLADEBURN, "bladeburn", "Ignites the caster's weapon, causing it to temporarily deal fire damage. The spell's power determines how long it will last.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines its duration."); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODFIRE, 2, NA, NULL); + // l2 + addot(OT_S_CLEANSINGFIRE, "cleansing fire", "Draws power from nearby fires to heal the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell will affect up to ^bpower^n fires, healing 30% hit points from each."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_ANYWHERE, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_FIREDART, "flame dart", "Fires a medium-sized dart of fire, dealing 1d6+^bpower^n fire damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -3280,6 +3282,17 @@ void initobjects(void) { addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODFIRE, 2, NA, NULL); + addot(OT_S_BURNINGFEET, "hotfoot", "Heats the soles of the target's feet to an uncomfortable level, dealing 1 fire damage each turn they remain still.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "If the target is wearing metal footwear, damage is inceased to 2 per turn."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines its duration (maximum 6 turns)."); + 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, 3, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 3, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_PLEASESGOD, R_GODFIRE, 1, NA, NULL); addot(OT_S_IMMOLATE, "immolate", "If the caster can successfully touch the target, they are instantly engulfed in flames.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -3324,6 +3337,13 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODFIRE, 4, NA, NULL); + addot(OT_S_QUICKENFIRE, "quicken fire", "Forms nearby fire into powerful fire primalities.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how many creatures will be created."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level VI, stronger creatures will be created."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 8, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); // l5 addot(OT_S_BURNINGWAVE, "burning wave", "Fire bursts from the ground in a line towards the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's range is based on its power."); @@ -3348,7 +3368,7 @@ void initobjects(void) { addot(OT_S_METEOR, "meteor", "Launches a white-hot meteorite towards the target location, dealing up to ^bpower^nd6+30 damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The damage is lower for enemies further away from the ball's centre."); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); // TODO: should be "near victim" addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); @@ -3357,7 +3377,7 @@ void initobjects(void) { // elemental - cold /////////////////// // l1 - addot(OT_S_CHILL, "chill", "Deals minor (1d3) cold damage to a single target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_CHILL, "chill", "Deals 1 cold damage to the target per exposed body part.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -3738,7 +3758,8 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODLIFE, 1, NA, NULL); // l2 - addot(OT_S_SPEAKDEAD, "speak with dead", "Temporarily allow a corpse to answer questions about its former life.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_SPEAKDEAD, "speak with dead", "When one stands upon a corpse and casts this spell, the corpse will temporarily be able to answer questions about its former life.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell will only function correctly on races capable of speech."); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); @@ -4039,7 +4060,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); - addot(OT_S_QUICKENSTONE, "quicken stone", "Crafts nearby stone into powerful rock primalities.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_QUICKENSTONE, "quicken stone", "Crafts nearby stone into powerful stone primalities.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how many creatures will be created."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level VI, stronger creatures will be created."); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); @@ -4217,7 +4238,7 @@ void initobjects(void) { // wild /////////////////// // l1 - addot(OT_S_MANASPIKE, "mana spike", "Fires a small bolt of wild magic, dealing 1d2 magical damage per power level.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_MANASPIKE, "mana spike", "Fires a small bolt of wild magic, dealing 1d4 magical damage per power level.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); @@ -4479,7 +4500,13 @@ void initobjects(void) { addot(OT_MANUAL, "manual", "Teaches you one level of its subject matter.", MT_PAPER, 1.5, OC_BOOK, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_VERYRARE, NULL); - addot(OT_SPELLBOOK, "spellbook", "Teaches you the spells contained within.", MT_PAPER, 1.5, OC_BOOK, SZ_SMALL); + addot(OT_SPELLBOOK, "spellbook", "Spellbooks contain a selection of spells from a single school.", MT_PAPER, 1.5, OC_BOOK, SZ_SMALL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_VERYRARE, NULL); + + + addot(OT_GRIMOIRE, "grimoire", "Grimoires contain spells from a variety of schools.", MT_PAPER, 2, OC_BOOK, SZ_SMALL); + addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_VERYRARE, NULL); @@ -5634,7 +5661,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_WALKDAM,DT_FIRE, NA, NA, "3d4"); + addflag(lastot->flags, F_WALKDAM,DT_FIRE, NA, NA, "4d6"); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 10, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); @@ -5646,7 +5673,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "2d4"); + addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "2d6"); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 7, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); @@ -5657,7 +5684,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "1d4"); + addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "1d6"); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 5, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); @@ -5672,7 +5699,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSVIEW, 3, NA, NA, NULL); - addflag(lastot->flags, F_WALKDAM, DT_HEAT, NA, NA, "1d2"); + addflag(lastot->flags, F_WALKDAM, DT_HEAT, NA, NA, "1d4"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addot(OT_STEAMPUFF, "puff of steam", "A small puff of scalding steam.", MT_GAS, 0, OC_EFFECT, SZ_MEDIUM); @@ -5683,7 +5710,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSVIEW, 1, NA, NA, NULL); - addflag(lastot->flags, F_WALKDAM, DT_HEAT, NA, NA, "1d1+1"); + addflag(lastot->flags, F_WALKDAM, DT_HEAT, NA, NA, "1d4"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addot(OT_SLEETSTORM, "storm of sleet", "An intense storm of sleet. Hampers movement and deals minor cold damage.", MT_GAS, 0, OC_EFFECT, SZ_LARGE); @@ -5781,8 +5808,8 @@ void initobjects(void) { addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); - addflag(lastot->flags, F_WALKDAM, DT_COLD, NA, NA, "1d6"); - addflag(lastot->flags, F_WALKDAM, DT_PROJECTILE, NA, NA, "1d5"); + addflag(lastot->flags, F_WALKDAM, DT_COLD, NA, NA, "2d3"); + addflag(lastot->flags, F_WALKDAM, DT_PROJECTILE, NA, NA, "2d3"); addflag(lastot->flags, F_WALKDAMBP, BP_HEAD, DT_WATER, NA, "1d2"); addflag(lastot->flags, F_WALKDAMBP, BP_SHOULDERS, DT_WATER, NA, "1d2"); addflag(lastot->flags, F_WALKDAMBP, BP_BODY, DT_WATER, NA, "1d2"); @@ -5797,7 +5824,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_KNOCKAWAY, 4, 40, 12, "4d6"); + addflag(lastot->flags, F_KNOCKAWAY, 4, 40, 12, "12d3"); addflag(lastot->flags, F_OBMOVESRANDOMLY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); @@ -5826,7 +5853,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_KNOCKAWAY, 2, 35, 10, "3d6"); + addflag(lastot->flags, F_KNOCKAWAY, 2, 35, 10, "8d3"); addflag(lastot->flags, F_OBMOVESRANDOMLY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); @@ -6567,7 +6594,6 @@ void initobjects(void) { // DAMTYPE _cannot_ be overridden (yet)! addot(OT_FISTS, "fists", "human fists", MT_FLESH, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_BASH, 2, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_UNARMED, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 1, NA, NA, NULL); @@ -6583,7 +6609,6 @@ void initobjects(void) { // this one is for the pirate addot(OT_HOOKHAND, "hook", "hook", MT_METAL, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_SLASH, 4, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_UNARMED, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, 2, NA, "scratch"); @@ -6593,7 +6618,6 @@ void initobjects(void) { addot(OT_TEETH, "teeth", "teeth object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_BITE, 2, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); @@ -6602,7 +6626,6 @@ void initobjects(void) { addot(OT_TRAMPLE, "trample", "trample object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_CRUSH, 2, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "trample"); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); @@ -6610,7 +6633,6 @@ void initobjects(void) { addot(OT_BEAK, "beak", "beak object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_BITE, 2, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); @@ -6621,7 +6643,6 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_SLASH, 2, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "drill"); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); @@ -6635,7 +6656,6 @@ void initobjects(void) { addflag(lastot->flags, F_ATTACKVERB, 19, 24, NA, "gouge"); addflag(lastot->flags, F_ATTACKVERB, 25, NA, NA, "shred"); addflag(lastot->flags, F_KILLVERB, 70, NA, NA, "disembowel"); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); @@ -6650,7 +6670,6 @@ void initobjects(void) { addflag(lastot->flags, F_ATTACKVERB, 19, 24, NA, "gouge"); addflag(lastot->flags, F_ATTACKVERB, 25, NA, NA, "shred"); addflag(lastot->flags, F_KILLVERB, 70, NA, NA, "disembowel"); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); @@ -6660,7 +6679,6 @@ void initobjects(void) { addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, 11, NA, "kick"); addflag(lastot->flags, F_ATTACKVERB, 12, NA, NA, "trample"); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); @@ -6669,7 +6687,6 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_BASH, 2, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "butt"); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); @@ -6678,7 +6695,6 @@ void initobjects(void) { addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "sting"); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_ACID, 2, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); @@ -6687,7 +6703,6 @@ void initobjects(void) { addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "tailslap"); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 4, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); @@ -6696,7 +6711,6 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_BASH, 10, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "slap"); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); @@ -6704,13 +6718,11 @@ void initobjects(void) { addot(OT_TONGUE, "tongue", "tongue object", MT_FLESH, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_PIERCE, 10, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 110, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addot(OT_ZAPPER, "zapper", "zapper object", MT_NOTHING, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_ELECTRIC, 2, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); @@ -6718,7 +6730,6 @@ void initobjects(void) { // monster weapons addot(OT_ACIDATTACK, "acidattack", "acid attack object", MT_WATER, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_ACID, 2, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "sting"); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); @@ -6726,20 +6737,17 @@ void initobjects(void) { addot(OT_TOUCHBURN, "burning touch", "burning touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_FIRE, 1, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "burn"); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addot(OT_TOUCHCHILL, "chilling touch", "chilling touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_COLD, 1, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "freeze"); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addot(OT_TOUCHCONFUSE, "confusing touch", "confusing touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_BASH, 1, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "touch"); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); @@ -6748,14 +6756,12 @@ void initobjects(void) { addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL); addot(OT_TOUCHHOLY, "holy touch", "holy touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_HOLY, 1, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "smite"); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addot(OT_TOUCHNECROTIC, "necrotic touch", "generic undead touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_NECROTIC, 1, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "drain"); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); @@ -6764,7 +6770,6 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURPIERCE, 90, NA, NA, ""); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "touch"); addflag(lastot->flags, F_DAM, DT_TOUCH, 1, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 22, "1-2"); addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); @@ -6774,7 +6779,6 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURPIERCE, 90, NA, NA, ""); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "touch"); addflag(lastot->flags, F_DAM, DT_TOUCH, 1, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 30, "3-5"); addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); @@ -8755,6 +8759,7 @@ void initrace(void) { // 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!"); + addflag(lastrace->flags, F_SACRIFICEOB, OT_GRIMOIRE, NA, 10, "OB explode#S into a shower of blood!"); addrace(R_GODNATURE, "Ekrub", 200, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Ekrub is goddess of nature and creation. She appears as a female figure dressed in farming clothes. Ekrub has a burning hatred of all dragonkind, who she views as abhorrent due to their destructive nature."); setbodytype(lastrace, BT_HUMANOID); @@ -11077,7 +11082,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); - addrace(R_PRIMALSTONE, "rock primality", 200, 'E', C_GREY, MT_STONE, RC_MAGIC, "A living mass of stone, animated by powerful magic."); + addrace(R_PRIMALSTONE, "stone primality", 200, 'E', C_GREY, MT_STONE, RC_MAGIC, "A living mass of stone, animated by powerful magic."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_NONE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_CAVE, 72, RR_RARE, NULL); @@ -11103,7 +11108,7 @@ void initrace(void) { addflag(lastrace->flags, F_UNSUMMONOB, NA, NA, NA, "boulder"); addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); - addrace(R_PRIMALSTONEL, "lesser rock primality", 120, 'E', C_GREY, MT_STONE, RC_MAGIC, "A living mass of stone, animated by powerful magic."); + addrace(R_PRIMALSTONEL, "lesser stone primality", 120, 'E', C_GREY, MT_STONE, RC_MAGIC, "A living mass of stone, animated by powerful magic."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_NONE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_CAVE, 72, RR_RARE, NULL); @@ -15001,8 +15006,8 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 5, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RANDOMTALKPCT, 20, NA, NA, NULL); diff --git a/data/hiscores.db b/data/hiscores.db index 1c144fc..4d0a84c 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 06de22e..7c1c2e4 100644 --- a/defs.h +++ b/defs.h @@ -517,7 +517,8 @@ enum NOISECLASS { NC_MOVEMENT = 1, NC_SPEECH = 2, NC_FIGHTING = 3, - NC_OTHER = 4, + NC_SPELLEFFECT = 4, + NC_OTHER = 5, }; enum QUADRANT { @@ -1479,6 +1480,7 @@ enum OBTYPE { OT_SCR_TURNUNDEAD, OT_SCR_WISH, // BOOKS + OT_GRIMOIRE, OT_MANUAL, OT_SPELLBOOK, // spells @@ -1545,6 +1547,8 @@ enum OBTYPE { OT_S_BLADEBURN, OT_S_BURNINGFEET, OT_S_BURNINGWAVE, + OT_S_CLEANSINGFIRE, + OT_S_DANCINGFLAME, OT_S_FIREDART, OT_S_FIREBALL, OT_S_FLAMEPILLAR, @@ -1552,6 +1556,7 @@ enum OBTYPE { OT_S_IMMOLATE, OT_S_METEOR, OT_S_PYROMANIA, + OT_S_QUICKENFIRE, OT_S_SPARK, OT_S_SUPERHEAT, OT_S_WALLOFFIRE, @@ -2809,6 +2814,7 @@ enum FLAG { // f_rndspellposs. F_RNDSPELLSCHOOL, // monster's random spells can come from // school v0, between level v1 and v2. + // if v0 is SS_NONE, pick a random school. // (optional) text = "pw:xxx;" to show spell // power. if not given, power comes from depth. F_RNDSPELLPOSS, // monster's random spells can be spellid v0. @@ -3166,6 +3172,7 @@ enum FLAG { F_SACRIFICEOBBLESSED, // v0 = can sacrifice obs with ->blessed=v0 and blessknown! F_NAME, // text = lf's name. ie. lfname = "Fred" + // also used for names of OT_GRIMOIRE objects F_NAMED, // text = lf's name. ie. lfname = "xat named Fred" F_XPMOD, // add/subtract this much from calculated xpval F_BLOODOB, // text = type of object to drop for blood diff --git a/io.c b/io.c index 1f1120a..81ad0af 100644 --- a/io.c +++ b/io.c @@ -2785,7 +2785,9 @@ lifeform_t *askgod(char *prompttext, int onlyprayed) { while (!done) { getchoice(&prompt); lf = (lifeform_t *)prompt.result; - if (prompt.whichq == 0) { + if (!lf) { + break; + } else if (prompt.whichq == 0) { break; } else { describegod(lf); @@ -3255,6 +3257,7 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { char myletters[MAXPILEOBS+1]; char msghistbuf[BUFLEN],numstring[BUFLEN]; char pbuf[BUFLEN]; + char altprompt[BUFLEN]; int firstob = 0; int nextpage = -1; int lastline = SCREENH-4; @@ -3262,10 +3265,13 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { int count = ALL; char nextlet = 'a'; int useobletters; + int descmode = B_FALSE; objectclass_t *wantoc = NULL; clearretobs(); + sprintf(altprompt, "Describe what"); + if (countobs(op, B_FALSE) <= 0) { // no objects in pack cls(); @@ -3357,8 +3363,10 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { if (nextpage != -1) { mvwprintw(mainwin, y, 0, MORESTRING); } - if (strlen(numstring) > 0) { - snprintf(pbuf, BUFLEN,"%s (%s','=all, ESC to quit) [%s]: ",prompt, + if (descmode) { + snprintf(pbuf, BUFLEN,"%s (ESC to quit): ", altprompt); + } else if (strlen(numstring) > 0) { + snprintf(pbuf, BUFLEN,"%s (%s','=all, ESC to quit) [%s]: ", prompt, (opts & AO_INCLUDENOTHING) ? "- for nothing, " : "", numstring); } else { @@ -3418,20 +3426,24 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { } } if (which != -1) { - int val; - if (selected[i]) val = B_FALSE; - else val = B_TRUE; - - selected[i] = val; - if (val == B_TRUE) { - selcount[i] = count; - if (selcount[i] > mylist[i]->amt) selcount[i] = mylist[i]->amt; + if (descmode) { + describeob(mylist[i]); } else { - selcount[i] = 0; + int val; + if (selected[i]) val = B_FALSE; + else val = B_TRUE; + + selected[i] = val; + if (val == B_TRUE) { + selcount[i] = count; + if (selcount[i] > mylist[i]->amt) selcount[i] = mylist[i]->amt; + } else { + selcount[i] = 0; + } + // reset count + strcpy(numstring, ""); + count = ALL; } - // reset count - strcpy(numstring, ""); - count = ALL; } } else if ((ch == '-') && (opts & AO_INCLUDENOTHING)) { // select nothing reason = E_SELNOTHING; @@ -3441,6 +3453,9 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { addmsghist(msghistbuf); restoregamewindows(); return B_TRUE; + } else if (ch == '?') { // toggle select/describe + if (descmode) descmode = B_FALSE; + else descmode = B_TRUE; } else if (ch == ',') { // toggle all/none int val; if (selected[0]) { // deselect all @@ -4343,7 +4358,7 @@ void docomms(lifeform_t *lf) { if (cantalk(lf)) { char *p = NULL; if (lf->race->raceclass->id == RC_HUMANOID) { - p = assignnpcname(lf); + p = assignnpcname(lf->flags); } sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p); } @@ -6844,23 +6859,33 @@ char *makedesc_ob(object_t *o, char *retbuf) { object_t *oo; int showcontents = B_TRUE; - if ((o->type->id == OT_SPELLBOOK) && !isknown(o)) { - showcontents = B_FALSE; + if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { + if (!isknown(o)) { + showcontents = B_FALSE; + } } if (showcontents) { - if (o->type->id == OT_SPELLBOOK) { + if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { sprintf(buf, "\n%s contain%s the following spells:\n", OB1(o,"It","They"), OBS1(o)); } else { sprintf(buf, "\n%s currently contain%s:\n", OB1(o,"It","They"), OBS1(o)); } strncat(retbuf, buf, HUGEBUFLEN); + for (oo = o->contents->first ;oo ; oo = oo->next) { char contentname[BUFLEN]; + // don't show spells from schools we don't know + if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { + if (getspellschoolknown(player, oo->type->id) == SS_NONE) { + continue; + } + } + getobname(oo, contentname, oo->amt); sprintf(buf, " - %s", contentname); - if (o->type->id == OT_SPELLBOOK) { + if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { char lbuf[BUFLEN]; sprintf(lbuf, " (Lv %d)%s", getspelllevel(oo->type->id), lfhasflagval(player, F_CANCAST, oo->type->id, NA, NA, NULL) ? @@ -12243,7 +12268,7 @@ void showlfstats(lifeform_t *lf, int showall) { } strcat(thisline, ")"); - mvwprintw(mainwin, y, 0, "%s", desc); + mvwprintw(mainwin, y, 0, "%s", thisline); y++; nfound++; } diff --git a/lf.c b/lf.c index 08a88c3..9d0b164 100644 --- a/lf.c +++ b/lf.c @@ -910,6 +910,10 @@ int canhear(lifeform_t *lf, cell_t *dest, int volume) { if (cell->type->solid) { sounddist--; } + // magic barriers stop all sound + if (hasob(cell->obpile, OT_MAGICBARRIER)) { + return B_FALSE; + } // hearing range decreases by one sounddist--; @@ -2121,7 +2125,7 @@ int charmedaction(lifeform_t *lf, flag_t *charmflag) { getlfname(lf, lfname); getobname(o, obname, o->amt); msg("^w%s hands over %s to %s.", lfname, obname, - cansee(lf, charmer) ? charmername : "someone"); + cansee(player, charmer) ? charmername : "someone"); } moveob(o, charmer->pack, o->amt); } @@ -3158,7 +3162,7 @@ void die(lifeform_t *lf) { if (lf->race->id == R_BLASTBUG) { flag_t *hpflag; hpflag = hasflag(corpse->flags, F_OBHP); - if (hpflag) hpflag->val[0] = rnd(4,5); + if (hpflag) hpflag->val[0] = rnd(5,6); } // corpse of a player pet? @@ -7351,12 +7355,21 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) { int acc = 0,i; flag_t *retflag[MAXCANDIDATES]; int nretflags; + int unarmed = B_FALSE; // get weapon if (wep) { acc = getobaccuracy(wep, lf, B_FALSE); + if (hasflag(wep->flags, F_UNARMEDWEP)) { + unarmed = B_TRUE; + } else { + unarmed = B_FALSE; + } } else { - acc = 100; // innate attack + unarmed = B_TRUE; + // for unarmed attacks, accuracy is based on agility + acc = getattr(lf, A_AGI) + 20; + limit(&acc, 20, 100); } // dual weilding? @@ -7422,6 +7435,7 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) { } */ + // modify for blindness if (isblind(lf)) { acc -= 50; @@ -8938,7 +8952,7 @@ enum BODYPART getrandomcorebp(lifeform_t *lf, lifeform_t *attacker) { race_t *getrandomcorpserace(cell_t *c) { race_t *r = NULL; - while (!r || (hasflag(r->flags, F_NOCORPSE))) { + while (!r || hasflag(r->flags, F_NOCORPSE) || hasflag(r->flags, F_CORPSETYPE) || hasflag(r->flags, F_EXTRACORPSE)) { if (c) r = getrandomrace(c, NA); else r = getreallyrandomrace(RC_ANY); } @@ -9898,42 +9912,60 @@ void givejob(lifeform_t *lf, enum JOB jobid) { } givesubjob(lf, sj); + + + if (j->id == J_WIZARD) { object_t *sb2; skill_t *sk; - // wizards now get a secondary school - initprompt(&prompt, "Select your secondary spell school:"); - addchoice(&prompt, 'd', getskillname(SK_SS_DIVINATION), NULL, findskill(SK_SS_DIVINATION), NULL); - addchoice(&prompt, 'm', getskillname(SK_SS_MODIFICATION), NULL, findskill(SK_SS_MODIFICATION), NULL); - addchoice(&prompt, 's', getskillname(SK_SS_SUMMONING), NULL, findskill(SK_SS_SUMMONING), NULL); - addchoice(&prompt, 't', getskillname(SK_SS_TRANSLOCATION), NULL, findskill(SK_SS_TRANSLOCATION), NULL); - getchoice(&prompt); - sk = (skill_t *) prompt.result; - switch (sk->id) { - case SK_SS_DIVINATION: - sb2 = addob(lf->pack, "spellbook of divination magic"); - break; - case SK_SS_MODIFICATION: - sb2 = addob(lf->pack, "spellbook of modification magic"); - break; - case SK_SS_SUMMONING: - sb2 = addob(lf->pack, "spellbook of summoning magic"); - break; - case SK_SS_TRANSLOCATION: - sb2 = addob(lf->pack, "spellbook of translocation magic"); - break; - default: - sb2 = NULL; - break; + // wizards with no subjob: + if (sj == SJ_NONE) { + object_t *sb1; + // start with a grimoire of spells + sb1 = addob(lf->pack, "grimoire"); + identify(sb1); + + // monsters get spells from a random school + addflag(lf->flags, F_RNDSPELLCOUNT, rnd(2,4), NA, NA, NULL); + addflag(lf->flags, F_RNDSPELLSCHOOL, SS_NONE, 1, lf->level, NULL); + } - if (sb2) { - addflag(lf->flags, F_CANCAST, sb2->contents->first->type->id, NA, NA, NULL); - if (isplayer(lf)) { - addflag(lf->flags, F_SHORTCUT, getnextshortcut(lf), NA, NA, sb2->contents->first->type->name); - addflag(sb2->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); + + if (sj != SJ_NONE) { + // wizards with sub-jobs now get a secondary school + initprompt(&prompt, "Select your secondary spell school:"); + addchoice(&prompt, 'd', getskillname(SK_SS_DIVINATION), NULL, findskill(SK_SS_DIVINATION), NULL); + addchoice(&prompt, 'm', getskillname(SK_SS_MODIFICATION), NULL, findskill(SK_SS_MODIFICATION), NULL); + addchoice(&prompt, 's', getskillname(SK_SS_SUMMONING), NULL, findskill(SK_SS_SUMMONING), NULL); + addchoice(&prompt, 't', getskillname(SK_SS_TRANSLOCATION), NULL, findskill(SK_SS_TRANSLOCATION), NULL); + getchoice(&prompt); + sk = (skill_t *) prompt.result; + switch (sk->id) { + case SK_SS_DIVINATION: + sb2 = addob(lf->pack, "spellbook of divination magic"); + break; + case SK_SS_MODIFICATION: + sb2 = addob(lf->pack, "spellbook of modification magic"); + break; + case SK_SS_SUMMONING: + sb2 = addob(lf->pack, "spellbook of summoning magic"); + break; + case SK_SS_TRANSLOCATION: + sb2 = addob(lf->pack, "spellbook of translocation magic"); + break; + default: + sb2 = NULL; + break; } + if (sb2) { + addflag(lf->flags, F_CANCAST, sb2->contents->first->type->id, NA, NA, NULL); + if (isplayer(lf)) { + addflag(lf->flags, F_SHORTCUT, getnextshortcut(lf), NA, NA, sb2->contents->first->type->name); + addflag(sb2->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); + } + } + identify(sb2); } - identify(sb2); } } @@ -9998,25 +10030,10 @@ void givesubjob(lifeform_t *lf, enum SUBJOB sj) { break; // warrior types case SJ_BATTLEMAGE: - // starts off skilled in one school - switch (rnd(1,2)) { - case 1: - giveskilllev(lf, SK_SS_FIRE, PR_NOVICE); - sb1 = addob(lf->pack, "spellbook of fire magic"); - if (!isplayer(lf)) { - addflag(lf->flags, F_RNDSPELLCOUNT, rnd(1,2), NA, NA, NULL); - addflag(lf->flags, F_RNDSPELLSCHOOL, SS_FIRE, 1, 3, NULL); - } - break; - case 2: - giveskilllev(lf, SK_SS_COLD, PR_NOVICE); - sb1 = addob(lf->pack, "spellbook of cold magic"); - if (!isplayer(lf)) { - addflag(lf->flags, F_RNDSPELLCOUNT, rnd(1,2), NA, NA, NULL); - addflag(lf->flags, F_RNDSPELLSCHOOL, SS_COLD, 1, 3, NULL); - } - break; - } + // starts off with a grimoire (special code in objects.c will restrict this + // to only have 3 spells) + sb1 = addob(lf->pack, "grimoire"); + identify(sb1); // can learn some spell schools, but only up to adept level addtempflag(lf->flags, F_CANLEARN, SK_SS_FIRE, PR_ADEPT, NA, NULL, FROMJOB); addtempflag(lf->flags, F_CANLEARN, SK_SS_COLD, PR_ADEPT, NA, NULL, FROMJOB); @@ -10036,6 +10053,12 @@ void givesubjob(lifeform_t *lf, enum SUBJOB sj) { killflagsofid(lf->flags, F_MAXHPMOD); // remove warrior's level abilities killflagsofid(lf->flags, F_LEVABIL); + // make sure we have the right skills + for (o = sb1->contents->first ; o ; o = o->next) { + giveskill(lf, getschoolskill(getspellschool(o->type->id))); + } + // un-set sb1 so we don't automatically learn the first spell + sb1 = NULL; break; case SJ_PALADIN: // extra skills - healing magic & speech @@ -10714,7 +10737,10 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { object_t *o; // give that weapon o = addobfast(lf->pack, ot->id); - if (isplayer(lf)) addflag(o->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); + if (isplayer(lf)) { + addflag(o->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); + identify(o); + } // give one extra rank of skill in this weapon sk = getobskill(o->flags); @@ -12376,7 +12402,9 @@ int isinbattle(lifeform_t *lf, int 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; + if (!lfhasflag(l, F_DOESNTMOVE)) { + return B_TRUE; + } } } } else { @@ -12385,7 +12413,9 @@ int isinbattle(lifeform_t *lf, int includedistant) { cell_t *c; c = getcellindir(lf->cell, dir); if (c && c->lf && areenemies(lf, c->lf) && cansee(lf, c->lf)) { - return B_TRUE; + if (!lfhasflag(c->lf, F_DOESNTMOVE)) { + return B_TRUE; + } } } } @@ -13557,7 +13587,7 @@ int askforinfo(lifeform_t *lf, int diffmod) { askingprice = 0; // passed - free! } else { - if (!greedy && (difficulty - result >= 10)) { + if (!greedy && (result <= 40)) { // will not help! askingprice = -1; } else { @@ -13643,28 +13673,31 @@ int askforpayment(lifeform_t *shk, lifeform_t *lf) { } */ -char *assignnpcname(lifeform_t *lf) { - npcname_t *poss,*sel; +char *assignnpcname(flagpile_t *fp) { + npcname_t *sel; + int *poss; int nposs = 0,i; - poss = malloc(numnpcnames * sizeof(npcname_t *)); + poss = malloc(numnpcnames * sizeof(int)); // already got one? - if (lfhasflag(lf, F_NAME)) { + if (hasflag(fp, F_NAME)) { return NULL; } // count possibilities for (i = 0;i < numnpcnames; i++) { if (npcname[i].valid) { - poss[nposs++] = npcname[i]; + poss[nposs++] = i; } } // get random name - i = rnd(0,nposs); + i = poss[rnd(0,nposs-1)]; sel = &npcname[i]; // none else can use this name now sel->valid = B_FALSE; - addflag(lf->flags, F_NAME, NA, NA, NA, sel->name); + addflag(fp, F_NAME, NA, NA, NA, sel->name); + + free(poss); return sel->name; } @@ -13786,6 +13819,9 @@ void autospells(lifeform_t *lf, int howmany) { int thispower; objecttype_t *sp; ss = retflag[i]->val[0]; + if (ss == SS_NONE) { + ss = getrandomspellschool(NULL, B_FALSE); + } min = retflag[i]->val[1]; max = retflag[i]->val[2]; texttospellopts(retflag[i]->text, "pw:", &thispower, NULL); @@ -14291,6 +14327,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml char buf2[BUFLEN]; char lfname[BUFLEN]; int prelowhp = B_FALSE,ko = B_FALSE; + int murder = B_FALSE; flag_t *f; if (gamemode < GM_GAMESTARTED) return 0; @@ -14305,6 +14342,10 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml prelowhp = B_TRUE; } + if (fromlf && areallies(lf, fromlf)) { + murder = B_TRUE; + } + // adjust for source object's material if (fromob) { @@ -14528,7 +14569,19 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml case DT_MELT: setkillverb(lf, "Melted"); break; case DT_PIERCE: setkillverb(lf, "Impaled"); break; case DT_EXPLOSIVE: setkillverb(lf, "Vaporised"); break; - default: break; + default: + if (fromlf) { + if (murder) { + setkillverb(lf, "Murdered"); + } else if (amt >= lf->maxhp) { + setkillverb(lf, "Slaughtered"); + } else { + setkillverb(lf, "Slain"); + } + } else { + setkillverb(lf, "Killed"); + } + break; } } @@ -15350,6 +15403,7 @@ void noarmouron(race_t *r, enum BODYPART bp) { int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, char *text, char *seetext) { lifeform_t *l; int sounddist; + int alwayshear = B_FALSE; int rv = B_FALSE; assert(text); @@ -15358,6 +15412,10 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, return B_FALSE; } + if (nclass == NC_SPELLEFFECT) { + alwayshear = B_TRUE; + } + // sound will travel 3*volume cells sounddist = getsounddist(volume); @@ -15400,7 +15458,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, // skillcheck to hear this if ( (isplayer(l) && haslos(l, c)) || // only player can "hear by seeing" - (canhear(l, c, volume) && skillcheck(l, SC_LISTEN, difficulty, lbonus)) ) { + (canhear(l, c, volume) && (alwayshear || skillcheck(l, SC_LISTEN, difficulty, lbonus)) ) ) { flag_t *f; // announce? if (isplayer(l) && !lfhasflag(l, F_ASLEEP)) { @@ -15621,6 +15679,9 @@ enum NOISECLASS noisetypetoclass(enum NOISETYPE nt) { case N_WALK: case N_FLY: return NC_MOVEMENT; + case N_SONICBOLT: + case N_WARCRY: + return NC_SPELLEFFECT; default: break; } @@ -16287,20 +16348,20 @@ int push(lifeform_t *lf, object_t *o, int dir) { int racecantalk(enum RACE rid) { race_t *r; - switch (rid) { - case RC_DEMON: - case RC_DRAGON: - case RC_GOD: - case RC_HUMANOID: - // these ones can talk - return B_TRUE; - break; - default: - break; - } - r = findrace(rid); if (r) { + switch (r->raceclass->id) { + case RC_DEMON: + case RC_DRAGON: + case RC_GOD: + case RC_HUMANOID: + // these ones can talk + return B_TRUE; + break; + default: + break; + } + if (hasflag(r->flags, F_CANTALK)) return B_TRUE; } return B_FALSE; @@ -16353,7 +16414,7 @@ int recruit(lifeform_t *lf) { maxmult = 20; // passed } else { - if (difficulty - result >= 10) { + if (result <= 30) { // very expensive minmult = 20; maxmult = 30; @@ -16403,7 +16464,7 @@ int recruit(lifeform_t *lf) { // give them a name //if (getjob(lf)) { if (lf->race->raceclass->id == RC_HUMANOID) { - p = assignnpcname(lf); + p = assignnpcname(lf->flags); } sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p); } else { @@ -17764,6 +17825,14 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging + if (lfhasflag(lf, F_NATURALFLIGHT) && !isairborne(lf)) { + if (cancast(lf, OT_S_FLIGHT, NULL)) { + notime = B_TRUE; + castspell(lf, OT_S_FLIGHT, lf, NULL, lf->cell, NULL, NULL); + notime = B_FALSE; + } + } + if (isplayer(lf)) { needredraw = B_TRUE; statdirty = B_TRUE; @@ -17771,6 +17840,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { needredraw = B_TRUE; } //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging + } // end if gamestarted if (reverting) { @@ -17917,32 +17987,23 @@ int shoot(lifeform_t *lf) { return B_FALSE; } - -int skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod) { - return real_skillcheck(lf, ct, diff, mod, NULL); -} - -// positive mod makes it easier, negative makes it harder -int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *result) { +int getskillcheckchance(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod) { int attrib; int levmod; int othermod = 0; int db = B_FALSE; - int roll; - int modroll; int luckmod = 0; char mbuf[BUFLEN]; flag_t *retflag[MAXCANDIDATES]; int nretflags,i; flag_t *f; + int pct; - /* if (lfhasflag(lf, F_DEBUG)) { - //if (ct != SC_STEALTH) { // dont show debug info for stealth checks + if (ct != SC_STEALTH) { // dont show debug info for stealth checks db = B_TRUE; - //} + } } - */ switch (ct) { case SC_STR: @@ -18142,19 +18203,45 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r sumflags(lf->flags, F_EXTRALUCK, &luckmod, NULL, NULL); othermod += luckmod; - roll = rolldie(1, 20); + pct = 100 - (diff*5); // ie. diff 20 = 100%, 10 = 50% + pct += (attrib*5); + pct += (mod*5); + pct += (levmod*5); + pct += (othermod*5); if (db) { - snprintf(mbuf, BUFLEN, "%s skillcheck (%d) - need %d, got %d(rll)+%d(attr)+%d(lvm)+%d(othmod)+%d(mod)=",lf->race->name, - ct, diff, roll, attrib,levmod, othermod,mod); + snprintf(mbuf, BUFLEN, "%s skcheck (%d): diff=%d, %d(attr)+%d(lvm)+%d(othmod)+%d(mod),pct=%d%%", + lf->race->name, + ct, diff, attrib,levmod, othermod,mod,pct); + msg(mbuf); more(); } - modroll = roll; - modroll += attrib; - modroll += mod; - modroll += levmod; - modroll += othermod; + limit(&pct, 0, 100); + return pct; +} + +int skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod) { + return real_skillcheck(lf, ct, diff, mod, NULL); +} + +// positive mod makes it easier, negative makes it harder +// "result" will be filled with difference between our pct chance and what you rolled. +// positive "result" means you rolled higher than what you need. +// negative "result" means you rolled lower. +int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *result) { + int roll,db = B_FALSE, pct; + + if (lfhasflag(lf, F_DEBUG)) { + if (ct != SC_STEALTH) { // dont show debug info for stealth checks + db = B_TRUE; + } + } + + pct = getskillcheckchance(lf, ct, diff, mod); + + roll = rnd(1,100); + if (db) { - msg("%s%d.",mbuf,modroll); + msg("rolled %d, need <= %d.",roll,pct); } // auto-fail some things @@ -18163,31 +18250,29 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r case SC_CLIMB: case SC_DODGE: case SC_SHIELDBLOCK: - roll = 0; - modroll = 0; + roll = 9999; break; default: break; } } if (lfhasflag(lf, F_RAGE) && (ct == SC_STEALTH)) { - roll = 0; - modroll = 0; + roll = 9999; } // auto pass some things if (lfhasflag(lf, F_RAGE) && (ct == SC_MORALE)) { - modroll = diff; + roll = 0; } // natural 20 will pass some checks - if (roll == 20) { + if (roll <= 5) { switch (ct) { case SC_DODGE: case SC_STEALTH: if (db) { msg("%s skillcheck passed with natural 20.", lf->race->name); } - modroll = diff; + roll = 0; break; default: break; @@ -18195,10 +18280,10 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r } if (result) { - *result = modroll; + *result = roll - pct; } - if (modroll >= diff) { + if (roll <= pct) { // passed! // some checks will train skills when passed. switch (ct) { @@ -22071,7 +22156,7 @@ int wear(lifeform_t *lf, object_t *o) { } else if (penalty >= 10) { strcpy(howmuch, "quite"); } else { - strcpy(howmuch, "slightly "); + strcpy(howmuch, "slightly"); } msg("^wYou find this shield %s cumbersome to use.", howmuch); } diff --git a/lf.h b/lf.h index d8bf40e..95a73aa 100644 --- a/lf.h +++ b/lf.h @@ -22,7 +22,7 @@ int areenemies(lifeform_t *lf1, lifeform_t *lf2); int armourfits(lifeform_t *lf, object_t *o, enum ERROR *reason); int askforinfo(lifeform_t *lf, int diffmod); //int askforpayment(lifeform_t *shk, lifeform_t *lf); -char *assignnpcname(lifeform_t *lf); +char *assignnpcname(flagpile_t *fp); void autoshortcut(lifeform_t *lf, enum OBTYPE spellid); void autoskill(lifeform_t *lf); void autospells(lifeform_t *lf, int howmany); @@ -434,6 +434,7 @@ int setlfmaterial(lifeform_t *lf, enum MATERIAL id, int wantannounce); void setlosdirty(lifeform_t *lf); void setstamina(lifeform_t *lf, float howmuch); int shoot(lifeform_t *lf); +int getskillcheckchance(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod) ; int skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod); int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *result); int skillcheckvs(lifeform_t *lf1, enum CHECKTYPE ct1, int mod1, lifeform_t *lf2, enum CHECKTYPE ct2, int mod2); diff --git a/map.c b/map.c index 89669c1..ecb1121 100644 --- a/map.c +++ b/map.c @@ -5243,7 +5243,7 @@ void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *c if (c->lf) { char buf[BUFLEN]; if (o) { - getobname(o, obname, 1); + getobnametrue(o, obname, 1); snprintf(buf, BUFLEN, "an exploding %s",strchr(obname, ' ')+1); } else { snprintf(buf, BUFLEN, "an explosion"); @@ -7625,7 +7625,7 @@ void setcellknown(cell_t *cell, int forcelev) { if (hasflag(player->flags, F_PHOTOMEM)) { cell->knowntime = PERMENANT; } else if (slev == PR_INEPT) { - cell->knowntime = getattr(player, A_IQ); + cell->knowntime = getattr(player, A_IQ)*2; } else { cell->knowntime = PERMENANT; } diff --git a/move.c b/move.c index 81c776d..39c3bdd 100644 --- a/move.c +++ b/move.c @@ -1524,7 +1524,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (!preseenbyplayer) { // TODO: also check for isresting(l), if we have allies standing watch getlfnamea(lf, lfname); - msg("%s comes into view.", lfname); + msg("%s %ss into view.", lfname, getmoveverb(lf)); } dointerrupt = B_TRUE; // mark the observed race as known. @@ -3156,14 +3156,50 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { } } } else { // somethign random is in the way - if (isplayer(lf) && inway) { - char obname[BUFLEN]; - if (haslos(lf, cell)) { - getobname(inway, obname, 1); + if (inway) { + // walking into your own magic barrier? + if ((inway->type->id == OT_MAGICBARRIER) && + hasflagval(inway->flags, F_CREATEDBY, lf->id, NA, NA, NULL)) { + enum OBTYPE barriertype; + int x,y; + cell_t *cc; + barriertype = inway->type->id; + // vanish this and any other magical barriers we made. + for (y = 0; y < cell->map->h; y++) { + for (x = 0; x < cell->map->w; x++) { + cc = getcellat(cell->map, x,y); + if (cc) { + object_t *oo,*nextoo; + int ndone = 0; + for (oo = cc->obpile->first ; oo ; oo = nextoo) { + nextoo = oo->next; + if ((oo->type->id == barriertype) && + hasflagval(oo->flags, F_CREATEDBY, lf->id, NA, NA, NULL)) { + takedamage(oo, 999, DT_DIRECT); + ndone++; + } + } + if (ndone) { + removedeadobs(cc->obpile); + } + } + } + } + // NOW is the move possible? + if (moveclear(lf, dir, &errcode)) { + moveto(lf, cell, B_TRUE, B_TRUE); + } } else { - strcpy(obname, "something"); + if (isplayer(lf)) { + char obname[BUFLEN]; + if (haslos(lf, cell)) { + getobname(inway, obname, 1); + } else { + strcpy(obname, "something"); + } + msg("There is %s in your way.",obname); + } } - msg("There is %s in your way.",obname); } } break; diff --git a/nexus.c b/nexus.c index c5b3b23..7489054 100644 --- a/nexus.c +++ b/nexus.c @@ -411,15 +411,22 @@ int main(int argc, char **argv) { player->facing = D_ALL; setlosdirty(player); - // don't want any mosnters starting within los/lof of player + // changes for anything within los/lof of player's starting pos: + // - don't want any mosnters starting here + // - don't want any locked doors slev = getskill(player, SK_CARTOGRAPHY); for (y = 0; y < player->cell->map->h; y++) { for (x = 0; x < player->cell->map->w; x++) { c = getcellat(player->cell->map, x, y); if (c && (haslos(player, c) || haslof(player->cell, c, LOF_WALLSTOP, NULL))) { + object_t *o,*nexto; if (c->lf && !isplayer(c->lf) && !ispetof(c->lf, player)) { killlf(c->lf); } + for (o = c->obpile->first ; o ; o = nexto) { + nexto = o->next; + killflagsofid(o->flags, F_LOCKED); + } } } } diff --git a/objects.c b/objects.c index dcc1857..aadc1cd 100644 --- a/objects.c +++ b/objects.c @@ -1549,15 +1549,20 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum // remember the book's school (used for description) addflag(o->flags, F_LINKSCHOOL, bookcontents, NA, NA, NULL); // add contents to the book - if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { - enum OBTYPE firstspell; + if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { // giving to player at start of game - nspells = 5; - firstlev = 2; + if (hasjob(where->owner, J_WIZARD)) { + enum OBTYPE firstspell; + nspells = 5; + firstlev = 2; - // fixed first spell - firstspell = getfirstwizspell(bookcontents); - assert(addobfast(o->contents, firstspell)); + // fixed first spell + firstspell = getfirstwizspell(bookcontents); + assert(addobfast(o->contents, firstspell)); + } else { + nspells = 5; + firstlev = 1; + } } else { nspells = rnd(2,5); firstlev = rnd(1,4); @@ -1572,7 +1577,100 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum assert(addobfast(o->contents, oid)); } } - } else { + } else if (o->type->id == OT_GRIMOIRE) { + // 1 spell from each school + int i; + int nschools = -1; + enum SPELLSCHOOL school[MAXCANDIDATES]; + + if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { + if (hassubjob(where->owner, SJ_BATTLEMAGE)) { + nschools = 3; + } else if (hasjob(where->owner, J_WIZARD)) { + nschools = 6; + } + } + + if (nschools == -1) { + enum SPELLSCHOOL ss; + nschools = 0; + // one spell from each school + for (ss = SS_NONE; ss <= SS_LAST; ss++) { + if (schoolappearsinbooks(ss) && !streq(getschoolname(ss), "badschool")) { + school[nschools] = ss; + nschools++; + } + } + } else { + // select actual random schools to use. + for (i = 0; i < nschools; i++) { + if (where->owner && hassubjob(where->owner, SJ_BATTLEMAGE)) { + switch (rnd(1,6)) { + case 1: school[i] = SS_FIRE; break; + case 2: school[i] = SS_COLD; break; + case 3: school[i] = SS_AIR; break; + case 4: school[i] = SS_MODIFICATION; break; + case 5: school[i] = SS_TRANSLOCATION; break; + case 6: school[i] = SS_WILD; break; + } + } else if (where->owner && hasjob(where->owner, J_WIZARD)) { + school[i] = getrandomspellschool(where->owner, B_TRUE); + } else { + // should never happen? + school[i] = getrandomspellschool(NULL, B_FALSE); + } + } + } + + // now select the actual spells to give. + for (i = 0; i < nschools; i++) { + enum SPELLSCHOOL ss; + enum OBTYPE oid; + int wantlev = 1; + ss = school[i]; + + // giving to player at start of game? limit levels to + // 1-3. + if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { + if (hasjob(where->owner, J_WIZARD)) { + switch (rnd(1,10)) { + case 1: case 2: case 3: + case 4: case 5: case 6: + wantlev = 1; + break; + case 7: case 8: case 9: + wantlev = 2; + break; + case 10: + wantlev = 3; + break; + } + } else if (hassubjob(where->owner, SJ_BATTLEMAGE)) { + wantlev = 1; + } else { + wantlev = getrandomgrimoirelev(); + } + } else { // not going to the player + wantlev = getrandomgrimoirelev(); + } + // add a random spell from this school + oid = getrandomspellfromschool(ss,wantlev); + if (oid == OT_NONE) { + dblog("couldnt find grimoire contents for school=%s, lev=%d", getschoolname(ss), wantlev); + msg("couldnt find grimoire contents for school=%s, lev=%d", getschoolname(ss), wantlev); + } else if (!hasob(o->contents, oid)) { + assert(addobfast(o->contents, oid)); + } + } + // now assign the grimoire a name + if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { + char buf[BUFLEN]; + getplayername(buf); + addflag(o->flags, F_NAME, NA, NA, NA, buf); + } else { + assignnpcname(o->flags); + } + } else { // ie. manual assert(findskill(bookcontents)); addflag(o->flags, F_MANUALOF, bookcontents, NA, NA, NULL); } @@ -3850,11 +3948,9 @@ int getcharges(object_t *o) { // return the base accuracy for the weapon 'wep', or for a throw/unarmed attack if wep is null. // (ie. the accuracy for a range of 0). int getobaccuracy(object_t *wep, lifeform_t *weilder, int forthrow) { - int acc; + int acc = -1; flag_t *f; - acc = 100; // default accuracy of 100% - if (wep) { // override with weapon's (lack of) accuracy f = hasflag(wep->flags, F_ACCURACY); @@ -3863,14 +3959,29 @@ int getobaccuracy(object_t *wep, lifeform_t *weilder, int forthrow) { // ie. accuracy of 75% means 25% penalty // etc acc = f->val[0]; + } else { + // if weapon doesn't have F_accuracy flag, use lifeform's agility. + acc = -1; } + } + if (acc == -1) { + if (weilder) { + // initial accuracy is based on your agility. + acc = getattr(weilder, A_AGI) + 20; + limit(&acc, 20, 100); + } else { + acc = 100; + } + } + + + if (wep) { // blessed weapons have better base accuracy if (wep->blessed == B_BLESSED) acc += 10; //bonusses? acc += (getobbonus(wep, B_FALSE)*10); - } if (weilder && !forthrow) { @@ -4037,6 +4148,8 @@ int real_getobvalue(object_t *o, int amt) { if (o->type->id == OT_SPELLBOOK) { price += (89*countobs(o->contents, B_FALSE)); + } else if (o->type->id == OT_GRIMOIRE) { + price += (59*countobs(o->contents, B_FALSE)); } getflags(o->flags, retflag, &nretflags, F_ARMOURRATING, F_ARMOURSIZE, F_BONUS, F_DAM, F_EDIBLE, F_LINKSPELL, F_MANUALOF, F_NONE); @@ -4267,6 +4380,29 @@ brand_t *getrandombrandfor(objecttype_t *ot) { return result; } +int getrandomgrimoirelev(void) { + int wantlev = 1; + switch (rnd(1,10)) { + case 1: + case 2: + case 3: + case 4: + case 5: + wantlev = rnd(1,2); + break; + case 6: + case 7: + case 8: + wantlev = rnd(3,4); + break; + case 9: + case 10: + wantlev = rnd(5,6); + break; + } + return wantlev; +} + objecttype_t *getrandomobofclass(enum OBCLASS ocid, int minrarity, int maxrarity, lifeform_t *forlf) { objecttype_t *ot; int count = 0,sel,n; @@ -4397,7 +4533,7 @@ char *gethiddennameot(enum OBTYPE otid) { ot = findot(otid); // otherwise special case for unidentified books... - if (ot->id == OT_SPELLBOOK) { + if ((ot->id == OT_SPELLBOOK) || (ot->id == OT_GRIMOIRE)) { flag_t *f; f = hasflag(ot->flags, F_HASHIDDENNAME); if (f) { @@ -5090,6 +5226,12 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan strcat(basename, " of "); strcat(basename, getschoolname(f->val[0])); } + } else if (o->type->id == OT_GRIMOIRE) { + // check F_NAME field + f = hasflag(o->flags, F_NAME); + if (f) { + sprintf(basename, "%s%s grimoire", f->text, getpossessive(f->text)); + } } else { f = hasflag(o->flags, F_MANUALOF); if (f) { @@ -5602,7 +5744,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan // apply prefix now! if (count == 1) { - if (hasflag(o->flags, F_NO_A)) { + if (hasflag(o->flags, F_NO_A) && isknown(o)) { no_a = B_TRUE; } @@ -10561,9 +10703,10 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } // it will disappear eventually - addflag(newob->flags, F_OBHP, i, i, NA, NULL); - addflag(newob->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(newob->flags, F_OBHPDRAIN, 1, NA, NA, NULL); + //addflag(newob->flags, F_OBHP, i, i, NA, NULL); + //addflag(newob->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + //addflag(newob->flags, F_OBHPDRAIN, 1, NA, NA, NULL); + addflag(newob->flags, F_CREATEDBY, lf->id, NA, NA, NULL); } } break; @@ -10783,7 +10926,7 @@ int readsomething(lifeform_t *lf, object_t *o) { if (playercansee) { if (o->type->obclass->id == OC_BOOK) { // is this a spellbook? - if (o->type->id == OT_SPELLBOOK) { + if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { // if so, only id it if we can understand it. willid = B_FALSE; } else { @@ -11232,19 +11375,42 @@ int readsomething(lifeform_t *lf, object_t *o) { } } else if (o->type->obclass->id == OC_BOOK) { // is this a spellbook? - if (o->type->id == OT_SPELLBOOK) { + if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { object_t *oo; char ch = 'a'; enum SPELLSCHOOL school; enum SKILLLEVEL slev; - f = hasflag(o->flags, F_LINKSCHOOL); - school = f->val[0]; - slev = getskill(lf, getschoolskill(school)); + if (o->type->id == OT_SPELLBOOK) { + f = hasflag(o->flags, F_LINKSCHOOL); + school = f->val[0]; + slev = getskill(lf, getschoolskill(school)); - if (!slev) { - if (isplayer(lf)) msg("You cannot comprehend the contents of this book."); - maketried(o->type->id, NULL); - return B_FALSE; + if (!slev) { + if (isplayer(lf)) { + msg("You cannot comprehend the contents of this book."); + maketried(o->type->id, NULL); + } + return B_FALSE; + } + } else { // ie. grimoire + object_t *oo; + enum SPELLSCHOOL ss; + int found = B_FALSE; + // grimoire - do you know ANY spell school? + for (oo = o->contents->first; oo ; oo = oo->next) { + ss = getspellschoolknown(lf, oo->type->id); + if ((ss != SS_NONE) && getskill(lf, getschoolskill(ss))) { + found = B_TRUE; + break; + } + } + if (!found) { + if (isplayer(lf)) { + msg("You cannot comprehend the contents of this book."); + maketried(o->type->id, NULL); + } + return B_FALSE; + } } // player now knows what it is - id it! @@ -11261,7 +11427,10 @@ int readsomething(lifeform_t *lf, object_t *o) { // we are skilled in the right school. now ask which spell to learn. initprompt(&prompt, "Which spell will you try to learn?"); for (oo = o->contents->first ;oo ; oo = oo->next) { - if (!hasflagval(lf->flags, F_CANCAST, oo->type->id, NA, NA, NULL)) { + // do you know _this_ spell's school? + // is it one you can't already cast? + if ((getspellschoolknown(lf, oo->type->id) != SS_NONE) && + !hasflagval(lf->flags, F_CANCAST, oo->type->id, NA, NA, NULL)) { char *longdesc; char shortdesc[BUFLEN]; longdesc = malloc(HUGEBUFLEN * sizeof(char)); @@ -11284,7 +11453,7 @@ int readsomething(lifeform_t *lf, object_t *o) { ch = getchoicestr(&prompt, B_FALSE, B_TRUE); if ((ch == '\0') || (ch == '-')) { // not 'cancelled' because we still took time - msg("You close the spellbook without reading it."); + msg("You close the %s without reading it.", o->type->name); maketried(o->type->id, NULL); return B_FALSE; } @@ -11617,11 +11786,19 @@ int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { char obname[BUFLEN]; char targetname[BUFLEN]; int seen = B_FALSE; + flag_t *f; if (hasflag(o->flags, F_NOSHATTER)) { return B_FALSE; } + f = hasflag(o->flags, F_EXPLODEONDEATH); + if (!f) f = hasflag(o->flags, F_EXPLODEONDAM); + if (f) { + explodeob(o, f, f->val[1]); + return B_FALSE; + } + getobname(o,obname,o->amt); where = getoblocation(o); @@ -13008,8 +13185,9 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp } } - if (thrower && hasactivespell(thrower, OT_S_WHATGOESUP)) { - if (newob && !isdeadob(newob)) { + + if (newob && !isdeadob(newob)) { + if (thrower && hasactivespell(thrower, OT_S_WHATGOESUP)) { // on the ground? if ((newob->pile->where == where) && haslof(newob->pile->where, thrower->cell, LOF_NEED, NULL)) { if (isplayer(thrower)) { @@ -13021,10 +13199,9 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp } moveob(newob, thrower->pack, newob->amt); } - } + } } - /* if (firearm && outofammo && isplayer(thrower)) { char buf[BUFLEN]; diff --git a/objects.h b/objects.h index 931a889..5444e3e 100644 --- a/objects.h +++ b/objects.h @@ -101,6 +101,7 @@ objecttype_t *getbasicweaponforskill(enum SKILL skid); object_t *getrandomammo(lifeform_t *lf); objecttype_t *getrandomammofor(object_t *o); brand_t *getrandombrandfor(objecttype_t *ot); +int getrandomgrimoirelev(void); objecttype_t *getrandomobofclass(enum OBCLASS ocid, int minrarity, int maxrarity, lifeform_t *forlf); enum OBTYPE getrandomtrapforob(void); int getfirearmrange(object_t *o); diff --git a/shops.c b/shops.c index 3a2cae9..c191b78 100644 --- a/shops.c +++ b/shops.c @@ -22,7 +22,7 @@ #define DEF_BLESSCOST 50 #define DEF_SURCHARGE 15 #define DEF_RESIZECOST 80 -#define DEF_REPAIRCOSTPERHP 5 +#define DEF_REPAIRCOSTPERHP 2 extern enum GAMEMODE gamemode; extern prompt_t prompt; @@ -579,7 +579,13 @@ enum SHOPRETURN shopbless(lifeform_t *lf, object_t *vm, int starty, char *toptex sprintf(buf, "Bless which object (you have $%d)?", countmoney(lf->pack)); initprompt(&prompt, buf); for (o = player->pack->first ; o ; o = o->next) { + int ok = B_FALSE; if (o->blessknown && (o->blessed != B_BLESSED) && !hasflag(o->flags, F_NOBLESS)) { + ok = B_TRUE; + } else if (!o->blessknown && !hasflag(o->flags, F_NOBLESS)) { + ok = B_TRUE; + } + if (ok) { char costbuf[BUFLEN]; getobname(o, buf, o->amt); sprintf(costbuf, "%-60s($%d)", buf, getshopblessprice(o, vm)); @@ -599,8 +605,23 @@ enum SHOPRETURN shopbless(lifeform_t *lf, object_t *vm, int starty, char *toptex } else { msg("You hand over $%d to the priest.", cost); more(); givemoney(player, NULL, cost); + // already blessed? msg("The priest raise his hands in supplication."); more(); - blessob(o); + if (isblessed(o)) { + msg("\"Hey, this item is already blessed!\""); more(); + o->blessknown = B_TRUE; + // chance to get your money back. + if (skillcheck(player, SC_SPEECH, 20, 0)) { + char goldbuf[BUFLEN]; + msg("\"...so I will return your payment.\""); more(); + sprintf(goldbuf, "%d gold coins", cost); + addob(player->pack, goldbuf); + } else { + msg("\"Unfortunately, we do not offer refunds.\""); more(); + } + } else { + blessob(o); + } more(); } } diff --git a/spell.c b/spell.c index 4b2fe73..19fa7e3 100644 --- a/spell.c +++ b/spell.c @@ -1857,15 +1857,19 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // ask what to inspect initprompt(&prompt, "Study which scroll?"); + prompt.maycancel = B_TRUE; for (o = user->pack->first ; o ; o = o->next) { if ((o->type->obclass->id == OC_SCROLL) && isknown(o)) { f = hasflag(o->flags, F_LINKSPELL); if (f && !cancast(user, f->val[0], NULL)) { char buf2[BUFLEN]; + int pct; getobname(o, buf, o->amt); difficulty = 20 + (getspelllevel(f->val[0])*3); - sprintf(buf2, "%s (%d%% success chance)", buf, difficulty); - addchoice(&prompt, o->letter, buf, NULL, f, NULL); + mod = getspellskill(user, f->val[0]) * 3; + pct = getskillcheckchance(user, SC_LEARNMAGIC, difficulty, mod); + sprintf(buf2, "%s (%d%% success chance)", buf, pct); + addchoice(&prompt, o->letter, buf2, NULL, f, NULL); } } } @@ -1884,8 +1888,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // try to transcribe it... difficulty = 20 + (getspelllevel(f->val[0])*3); - - mod = getspellskill(user, f->val[0]) * 2; + mod = getspellskill(user, f->val[0]) * 3; if (skillcheck(user, SC_LEARNMAGIC, difficulty, mod)) { addflag(user->flags, F_CANCAST, f->val[0], NA, NA, NULL); @@ -4550,6 +4553,52 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("The electricity arcs!"); } } // end while narccells + } else if (spellid == OT_S_CLEANSINGFIRE) { + int i; + int pct = 0; + int ndone = 0; + object_t *o,*nexto; + if (!target) target = caster; + // find all fires within los + for (i = 0; i < target->nlos; i++) { + for (o = target->los[i]->obpile->first ; o ; o = nexto) { + nexto = o->next; + if (ndone >= power) break; + if (o->material->id == MT_FIRE) { + char obname[BUFLEN]; + int oamt; + getobname(o, obname, o->amt); + oamt = o->amt; + killob(o); + pct += 30; + if (haslos(player, target->los[i])) { + msg("%s %s out!", obname, (oamt == 1) ? "goes" : "go"); + } + ndone++; + continue; + } + if (killflagsofid(o->flags, F_ONFIRE)) { + pct += 20; + ndone++; + continue; + } + } + } + + limit(&pct, 0, 100); + if (pct) { + if (isplayer(target)) { + msg("Your wounds are healed!"); + } else if (cansee(player, target)) { + char lfname[BUFLEN]; + getlfname(target, lfname); + msg("%s%s wounds are healed!", lfname, getpossessive(lfname)); + } + gainhp(target, pctof(pct, target->maxhp)); + } else { + fizzle(caster); + return B_TRUE; + } } else if (spellid == OT_S_CLONE) { // duplicate the caster targcell = getrandomadjcell(caster->cell, WE_WALKABLE, B_NOEXPAND); @@ -5200,6 +5249,49 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ fizzle(caster); return B_TRUE; } + } else if (spellid == OT_S_DANCINGFLAME) { + int i; + int ndone = 0; + object_t *o; + if (!target) target = caster; + // find all fires within los + for (i = 0; i < target->nlos; i++) { + enum OBTYPE fireid = OT_NONE; + o = hasobofmaterial(target->los[i]->obpile, MT_FIRE); + if (o) { + fireid = o->type->id; + } else { + o = hasobwithflag(target->los[i]->obpile, F_ONFIRE); + if (o) { + fireid = OT_FIRESMALL; + } + } + + if (fireid != OT_NONE) { + int dir; + cell_t *c; + // any nearby lfs? + for (dir = DC_N; dir <= DC_NW; dir++) { + c = getcellindir(target->los[i], dir); + if (c && c->lf) { + object_t *newob; + newob = addobfast(c->obpile, OT_FIRESMALL); + if (newob) { + ndone++; + if (haslos(player, c)) { + char obname[BUFLEN]; + getobname(newob, obname, 1); + msg("%s spreads!", obname); + } + } + } + } + } + } + if (!ndone) { + fizzle(caster); + return B_TRUE; + } } else if (spellid == OT_S_DARKNESS) { if (!targcell) targcell = caster->cell; // centre on the caster @@ -7162,7 +7254,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("%s", buf); if (seenbyplayer) *seenbyplayer = B_TRUE; msg("%s is engulfed in roaring flames!", targname); - addobfast(target->cell->obpile, OT_FIRESMALL); + addobfast(target->cell->obpile, OT_FIREMED); } } else { if (isplayer(caster)) { @@ -8446,12 +8538,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (cansee(player, target)) { char lfname[BUFLEN]; getlfname(target, lfname); + getobname(o, obname, o->amt); if (haslos(player, newcell)) { msg("%s%s %s suddenly appears next to it!", lfname, getpossessive(lfname), - noprefix(buf)); + noprefix(obname)); } else { msg("%s%s %s suddenly vanishes!", lfname, getpossessive(lfname), - noprefix(buf)); + noprefix(obname)); } } } else { @@ -9530,6 +9623,54 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ fizzle(caster); return B_TRUE; } + } else if (spellid == OT_S_QUICKENFIRE) { + int howmany,i,n,sel,nposs = 0,nseen = 0; + cell_t *c; + object_t *o,*poss[MAXCANDIDATES]; + howmany = (power / 2) + 1; + // get a list of all fire cells near caster + for (i = DC_N; i <= DC_NW; i++) { + c = getcellindir(caster->cell, i); + if (c) { + o = hasobofmaterial(c->obpile, MT_FIRE); + if (o) { + poss[nposs++] = o; + } + } + } + limit(&howmany, NA, nposs); + if (!howmany) { + fizzle(caster); + return B_TRUE; + } + // now change them + for (i = 0; i < howmany; i++) { + lifeform_t *lf; + enum RACE rid; + // pick a random one + sel = rnd(0,nposs-1); + o = poss[sel]; + // turn it into a golem + c = getoblocation(o); + killob(o); + if (power < 6) { + rid = R_PRIMALFIREL; + } else { + rid = R_PRIMALFIRE; + } + lf = summonmonster(caster, c, rid, NULL, 30, B_TRUE); + if (haslos(player, c)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + nseen++; + } + // remove it from the list + for (n = sel ; n < (nposs-1); n++) { + poss[n] = poss[n+1]; + } + nposs--; + } + // set dirty line of sight for caster, as walls have vanished + caster->losdirty = B_TRUE; } else if (spellid == OT_S_QUICKENSTONE) { int howmany,i,n,sel,nposs = 0,nseen = 0; cell_t *c,*poss[MAXCANDIDATES]; @@ -9560,7 +9701,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { rid = R_PRIMALSTONE; } - lf = summonmonster(caster, c, R_PRIMALSTONE, NULL, 30, B_TRUE); + lf = summonmonster(caster, c, rid, NULL, 30, B_TRUE); if (haslos(player, c)) { if (seenbyplayer) *seenbyplayer = B_TRUE; nseen++; @@ -10234,7 +10375,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (targcell->lf) { - losehp(targcell->lf, roll("2d2"), DT_FIRE, caster, "a burst of flame"); + losehp(targcell->lf, roll("2d3"), DT_FIRE, caster, "a burst of flame"); } for (o = targcell->obpile->first ; o ; o = nexto) { nexto = o->next; @@ -10298,6 +10439,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { strcpy(weapon, ""); } + snprintf(buf, BUFLEN, "\"I was killed by %s", killer); if (strlen(weapon)) { strcat(buf, ", "); @@ -11821,7 +11963,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ petify(lf, target); if (isplayer(target)) { - p = assignnpcname(lf); + p = assignnpcname(lf->flags); sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p); } @@ -12962,6 +13104,7 @@ int schoolappearsinbooks(enum SPELLSCHOOL ss) { case SS_ABILITY: case SS_ALLOMANCY: case SS_MENTAL: + case SS_NATURE: return B_FALSE; default: break;