From 965fcdd4c060d31c971f3fe3a601a39eac09529c Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Tue, 1 Nov 2011 20:35:50 +0000 Subject: [PATCH] - [+] monsters should automatically attack locked doors if they're chasing the plaeyr - [+] if a monster tries to open a jammed door, make a noise * [+] glyph of warding spell - monsters won't walk on it - [+] ice crust not working? fixed. - [+] seal entrance should close doors too - [+] more kinds of wizard staff * [+] replace 'freezing touch' with something more useful. - [+] in askcoords, writing:xxx, use colours - [+] replace poisongas damtype name with 'gas' * [+] redo skill screen - [+] make ash clouds (sleeping etc) not affect thrower's square? - [+] There is a magical inscription here: "" * [+] rename some spells * [+] poltergeist spell keeps missing. - [+] reduce fire damage from burning objects in pack, or equipped - [+] first spell in beginner spellbook should be the one we know. - [+] fix bug with item inspect ability * [+] stamina food * [+] locate object issues - [+] still got a wrapprint bug when showing spell descriptions. --- ai.c | 2 +- attack.c | 64 +++++++++++------- data.c | 133 ++++++++++++++++++++++++++++---------- data/hiscores.db | Bin 11264 -> 11264 bytes defs.h | 19 +++++- io.c | 162 +++++++++++++++++++++++++++++++++++----------- lf.c | 66 +++++++++++++------ lf.h | 1 + map.c | 34 +++++++++- map.h | 1 + move.c | 87 ++++++++++++++++++++++--- nexus.c | 32 ++++++--- objects.c | 93 +++++++++++++++----------- objects.h | 2 +- spell.c | 165 ++++++++++++++++++++++++++++++----------------- spell.h | 1 + text.c | 43 +++++++++++- text.h | 1 + 18 files changed, 666 insertions(+), 240 deletions(-) diff --git a/ai.c b/ai.c index d799b44..3d59889 100644 --- a/ai.c +++ b/ai.c @@ -811,7 +811,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { if (db) dblog(".oO { i don't know my target's last known movement dir. }"); } else { // try going in last known dir - if (db) dblog(".oO { trying my master's last known move dir (%s) }",getdirname(lastdir)); + if (db) dblog(".oO { trying target's last known move dir (%s) }",getdirname(lastdir)); if (!trymove(lf, lastdir, B_TRUE, B_FALSE)) { if (db) dblog(".oO { ...successfully }"); // we now don't know their last known dir. diff --git a/attack.c b/attack.c index 70ad12e..5859e2b 100644 --- a/attack.c +++ b/attack.c @@ -1259,35 +1259,49 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { construct_hit_string(lf, NULL, attackername, obname, NULL, wep, damtype[i], dam[i], maxhp, i, B_FALSE, B_FALSE, B_FALSE, isunarmed, buf); - /* - if (isplayer(lf)) { - char extradambuf[BUFLEN]; - if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) { - snprintf(extradambuf, BUFLEN, " [%d dmg]",dam[i]); - } else { - strcpy(extradambuf, ""); - } - msg("You %s %s.", getattackverb(lf, wep, damtype[i], dam[i], maxhp), - obname, extradambuf); - } else if (cansee(player, lf)) { - char withwep[BUFLEN]; - - if (wep && !isunarmed && !isblind(player)) { // announce weapon used - snprintf(withwep, BUFLEN, " with %s", wepname); - } else { - strcpy(withwep, ""); - } - msg("%s %ss %s%s.", attackername, - getattackverb(lf, wep, damtype[i],dam[i],maxhp), obname,withwep); - } else { - noise(lf->cell, NULL, NC_OTHER, 3, "sounds of fighting.", NULL); - } - */ if (strlen(buf)) { msg("%s", buf); } if (!isplayer(lf) && !cansee(player, lf)) { - noise(lf->cell, lf, NC_OTHER, 3, "sounds of fighting.", NULL); + char noisebuf[BUFLEN]; + int vol; + switch (o->material->id) { + case MT_METAL: + strcpy(noisebuf, "a metallic clanging."); + vol = 4; + break; + case MT_GLASS: + strcpy(noisebuf, "cracking glass."); + vol = 4; + break; + case MT_WOOD: + case MT_DRAGONWOOD: + strcpy(noisebuf, "splintering wood."); + vol = 4; + break; + case MT_BONE: + case MT_STONE: + strcpy(noisebuf, "a dull thumping."); + vol = 3; + break; + case MT_GOLD: + case MT_SILVER: + case MT_LEATHER: + strcpy(noisebuf, "a dull thumping."); + vol = 2; + break; + case MT_PAPER: + case MT_WETPAPER: + case MT_RUBBER: + strcpy(noisebuf, "a dull thumping."); + vol = 1; + break; + default: + strcpy(noisebuf, "something being hit."); + vol = 3; + break; + } + noise(obloc, NULL, NC_OTHER, vol, noisebuf, NULL); } if ((i == 0) && (wep->type->id == OT_FISTS) && hasflag(o->flags, F_HARDNESS)) { diff --git a/data.c b/data.c index eadb3cb..2f83dab 100644 --- a/data.c +++ b/data.c @@ -408,6 +408,7 @@ void initjobs(void) { // initial skills addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); 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_UNARMED, PR_BEGINNER, NA, NULL); @@ -419,7 +420,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_BEGINNER, NA, NULL); // learnable skills addflag(lastjob->flags, F_CANLEARN, SK_ARMOUR, PR_NOVICE, NA, NULL); // limit - addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, PR_BEGINNER, NA, NULL); // limit addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); @@ -621,7 +622,7 @@ void initjobs(void) { addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 4, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -3, NA, NULL); // initial objects - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "enchanted wizard staff"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "neophyte staff"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "wizard hat"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 potions of magic"); @@ -635,6 +636,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, 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); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_NOVICE, NA, NULL); @@ -928,6 +930,7 @@ void initobjects(void) { addmaterial(MT_DRAGONWOOD, "dragonwood", 3); addflag(lastmaterial->flags, F_HARDNESS, 5, NA, NA, NULL); addflag(lastmaterial->flags, F_CANGETWET, B_TRUE, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); addmaterial(MT_RUBBER, "rubber", 4); addmaterial(MT_LEATHER, "leather", 4); addflag(lastmaterial->flags, F_CANGETWET, B_TRUE, NA, NA, NULL); @@ -2180,7 +2183,7 @@ void initobjects(void) { // elemental - fire /////////////////// // l1 - addot(OT_S_SPARK, "spark", "Creates a tiny spark of flame, dealing 1-3 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 1-6 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_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); @@ -2264,6 +2267,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_NORANDOM, B_TRUE, NA, NA, NULL); addot(OT_S_ICECRUST, "ice crust", "Enrusts your bladed weapon with a layer of ice.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the enchantment will remain."); addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); @@ -2272,14 +2276,23 @@ void initobjects(void) { addflag(lastot->flags, F_TARGETTEDSPELL, TT_ALLY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); - addot(OT_S_CRYSTALSHIELD, "crystalline shield", "Summons a shield of ice crystals to protect you from missiles.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how effective the shield is."); + addot(OT_S_CRYSTALARM, "crystalline armour", "Summons ice crystal armour to protect you from damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 1-3: one piece of armour is created."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 4-6: two pieces of armour are created."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 7-9: three pieces of armour are created."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 10: four pieces of armour are created."); addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); - addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); // l3 + addot(OT_S_CRYSTALSHIELD, "crystalline shield", "Summons a shield of ice crystals to protect you from missiles.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how effective the shield is."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); addot(OT_S_COLDRAY, "cold ray", "Shoots a blast of ice cold air, dealing 3d6 cold damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how difficult the ray is to dodge."); addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); @@ -2323,15 +2336,6 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); - addot(OT_S_CRYSTALARM, "crystalline armour", "Summons ice crystal armour to protect you from damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 1-3: one piece of armour is created."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 4-6: two pieces of armour are created."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 7-9: three pieces of armour are created."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 10: four pieces of armour are created."); - addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); - addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); addot(OT_S_SHARDSHOT, "shard shot", "Fires a scattered burst of small, fast moving ice shards. The shot will pass through multiple creatures, but damage is reduced with range.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's range is determined by its power."); addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); @@ -2782,7 +2786,7 @@ void initobjects(void) { // modification /////////////////// // l1 - addot(OT_S_HOLDPORTAL, "seal entrance", "Prevents a door from opening.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_HOLDPORTAL, "seal entrance", "Magically closes and jams a door, preventing it from opening.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_DOOR, NA, NA, NULL); @@ -2870,6 +2874,13 @@ void initobjects(void) { // summoning /////////////////// // l1 + addot(OT_S_GLYPHWARDING, "glyph of warding", "Inscribes a magical glyph in the ground which wards off monsters.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The glyph will stop monsters up to ^bpower^n/2 hit dice."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The glyph will last for ^bpower^n*5 turns."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 10, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_FLOATINGDISC, "floating disc", "Creates a disc of energy to carry your equipment.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power level determines how much wight the disc can carry."); addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); @@ -5314,13 +5325,69 @@ void initobjects(void) { addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 8, NA, NA, NULL); - addot(OT_WIZARDSTAFF, "wizard staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addot(OT_WIZARDSTAFF, "neophyte staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 4, 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_STAVES, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_LORE_ARCANA, NA, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_IQ, 10, NA, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); + + addot(OT_WIZARDSTAFF2, "enchanter staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 4, 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); + addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_MAGICBOOST, 1, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_IQ, 12, NA, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); + + addot(OT_WIZARDSTAFF3, "sorcerer staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 4, 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); + addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_MAGICBOOST, 2, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_IQ, 14, NA, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); + + addot(OT_WIZARDSTAFF4, "spellbinder staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 4, 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); + addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_MAGICBOOST, 3, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_IQ, 16, NA, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); + + addot(OT_WIZARDSTAFF5, "warlock staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 4, 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); + addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_MAGICBOOST, 4, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_IQ, 17, NA, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); + + addot(OT_WIZARDSTAFF6, "archmagi staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 4, 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); + addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_MAGICBOOST, 5, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_IQ, 18, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); // clubs (bashing) @@ -5600,7 +5667,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+2"); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d3+4"); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 2, NA, NULL); @@ -5625,6 +5692,7 @@ void initrace(void) { // penalties addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_ELECTRIC, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+3"); // other special stuff addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "screechs^a screech"); addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "talons"); @@ -5634,7 +5702,6 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+3"); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 75, J_RANDOM, NA, NULL); @@ -5695,7 +5762,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+3"); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d3+4"); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 2, NA, NULL); @@ -5721,7 +5788,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+3"); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d2+4"); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 2, NA, NULL); @@ -6936,7 +7003,7 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_SPELLSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_CANCAST, OT_S_TELEKINESIS, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_TELEKINESIS, NA, NA, "pw:5;"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "gestures"); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); @@ -7371,7 +7438,7 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, ""); addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+2"); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+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_MAXATTACKS, 1, 1, NA, NULL); @@ -8093,7 +8160,7 @@ void initrace(void) { addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); - addrace(R_SPIDER, "giant spider", 5, 'S', C_GREY, MT_FLESH, RC_ANIMAL, "An eight legged beast who is the central feature in many nightmares."); + addrace(R_SPIDER, "giant spider", 5, 'S', C_GREY, MT_FLESH, RC_ANIMAL, "An eight legged beast which features prominently in many nightmares."); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); @@ -9036,13 +9103,13 @@ void initskills(void) { addskilldesc(SK_SS_COLD, PR_SKILLED, "Allows you to cast Cold Magic spells up to level 4.", B_FALSE); addskilldesc(SK_SS_COLD, PR_EXPERT, "Allows you to cast Cold Magic spells up to level 5.", B_FALSE); addskilldesc(SK_SS_COLD, PR_MASTER, "Allows you to cast Cold Magic spells up to level 6.", B_FALSE); - addskill(SK_SS_GRAVITY, "Sorcery:Gravitation Magic", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_GRAVITY, PR_NOVICE, "Allows you to cast Gravitation Magic spells up to level 1.", B_FALSE); - addskilldesc(SK_SS_GRAVITY, PR_BEGINNER, "Allows you to cast Gravitation Magic spells up to level 2.", B_FALSE); - addskilldesc(SK_SS_GRAVITY, PR_ADEPT, "Allows you to cast Gravitation Magic spells up to level 3.", B_FALSE); - addskilldesc(SK_SS_GRAVITY, PR_SKILLED, "Allows you to cast Gravitation Magic spells up to level 4.", B_FALSE); - addskilldesc(SK_SS_GRAVITY, PR_EXPERT, "Allows you to cast Gravitation Magic spells up to level 5.", B_FALSE); - addskilldesc(SK_SS_GRAVITY, PR_MASTER, "Allows you to cast Gravitation Magic spells up to level 6.", B_FALSE); + addskill(SK_SS_GRAVITY, "Sorcery:Gravitation", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_GRAVITY, PR_NOVICE, "Allows you to cast Gravitation spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_BEGINNER, "Allows you to cast Gravitation spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_ADEPT, "Allows you to cast Gravitation spells up to level 3.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_SKILLED, "Allows you to cast Gravitation spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_EXPERT, "Allows you to cast Gravitation spells up to level 5.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_MASTER, "Allows you to cast Gravitation spells up to level 6.", B_FALSE); addskill(SK_SS_LIFE, "Sorcery:Life Magic", "Boosts casting of spells from this school.", 50); addskilldesc(SK_SS_LIFE, PR_NOVICE, "Allows you to cast Life Magic spells up to level 1.", B_FALSE); addskilldesc(SK_SS_LIFE, PR_BEGINNER, "Allows you to cast Life Magic spells up to level 2.", B_FALSE); diff --git a/data/hiscores.db b/data/hiscores.db index 0af721ac7e43abf5b75c92cb01c9f922af394fca..25bca16c52d31592973265109cd6992ef708914e 100644 GIT binary patch delta 698 zcmXYsT}YF06vodv|M%VZnziZjATT1B*c#RBYts>DaI#Fr(_#$;}%bwe66%3zKRW;$61`h37W)lEa6owil>;x1zg6@ zIJEcpqiM<}3m}-&Im1Qsv7Wp7d{gHQo%bXGSkzF!Pax;DX;i~C4LLG`r2A%h%N#LS z2FV99H(0*8Ye9}_mZ*ky4G|Fl3)fp`l)cEbwsdINC*J-)QxZRT)#{f3KvsWRT~dP; zQXoEv36Y=)N>O+9YZ>?g%aBq%HM3-Rj7}vac+=qK_XiS=YA}S(V9cJ+4V=Cb<^4tv zC!C9t9Y%pIF0b0+S|VKFjk*3GXqXLUisLByO9C$@I&f9?pl30PG>aFJEWaz3^fDV4w(&4dV9K@QK z6KN5pU0R_@I!{M%2j3uLyfPX^OK-W}0O$;zImf+iiocLaj*JXv)4t(sG3U$Y1~2=@ zl9^06Qa-5J+IqMWQ20fQ-4ZRk^m+K5b&R{3pX7nh0z1eIDmuod! nu&Ym7xzfYQY|%H6EQUj6mo9YHXo9(r982eug+f@JY%SnF^#`LT delta 494 zcmW;FKWI~N5C`!4^WN{hmpoH#VnWlzv=FgXOJ4HSAtH1TTpbiT6v1k6DV3OrONUfN zQ4&y3p$dva2N5ckAFY#ga0p@sgMS85+M$CL2OV?~i~hpFhx^{aU1Op#acdCYFJ-?x6yTsfOcgnbX%uAAwo4A3Wr0EVRT%cuKk!NmFVf}wK(qM-slng~f(Ay0} z?`0#r3JPwR+-HdKYp{Cn8UXSpI&7J#{t-=BX&)-UAGpbrT%aaZsEqSC4QsHXcWs|1 zHH-1=7|Xg!$-DkZDL9MrIX 1. val[0] = min, val[1] = max @@ -2393,6 +2401,9 @@ enum FLAG { F_COMBOSTRIKE, // lf is performing a combination strike F_HEAVYBLOW, // next attack is a heavy blow F_QUIVERINGPALM, // your next strike will be a quivpalm attack + F_TKTHROW, // when you throw an object, use your + // attrib = v0 and skilltype = v1 + // rather than AGI and SK_THROWING like normal F_TRUESTRIKE, // your attacks ALWAYS hit. turnsleft=v0 F_HURRICANESTRIKE, // lf is performing a hurricane strike // INTRINSICS @@ -2587,6 +2598,7 @@ enum FLAG { // doorway with no door). F_AUTOPOPULATE, // fill this vault with obs/mons/pillars like normal rooms F_NORANDOM, // this vault does not randomly appear + // OR this spell doesn't apear in books F_VAULTATOB, // v0/1=x/y, v2=pctchance, text=obname F_VAULTATLF, // v0/1=x/y, v2=pctchance, text=lfname F_VAULTATCELL, // v0/1=x/y, v2=pctchance, text=cellname @@ -3013,6 +3025,7 @@ typedef struct cell_s { int littimer; char *writing; + int writinglifetime; // lifeform pile struct lifeform_s *lf; diff --git a/io.c b/io.c index 7c8abde..b943d4c 100644 --- a/io.c +++ b/io.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -939,9 +940,13 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src wclear(msgwin); if (subprompt) { - mvwprintw(msgwin, 0, 0, "%s%s", subprompt, buf); + char fullline[BUFLEN]; + wmove(msgwin, 0, 0); + sprintf(fullline, "%s%s", subprompt, buf); + textwithcol(msgwin, fullline); } else { - mvwprintw(msgwin, 0, 0, "%s",buf); + wmove(msgwin, 0, 0); + textwithcol(msgwin, buf); } wrefresh(msgwin); @@ -1162,6 +1167,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s %s forms around %s!",needan(f->text) ? "an" : "a", f->text, lfname); donesomething = B_TRUE; break; + case F_MAGICBOOST: + if (isplayer(lf)) { + msg("Your magical ability feels boosted!"); + donesomething = B_TRUE; + } + break; case F_ASLEEP: if (isplayer(lf) && (f->val[2] != NA)) { // ie. resting, not forced asleep object_t *restob; @@ -1761,6 +1772,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { msg("%s%s %s vanishes.",lfname,getpossessive(lfname), f->text); donesomething = B_TRUE; break; + case F_MAGICBOOST: + if (isplayer(lf)) { + msg("Your magical ability no longer feels boosted."); + donesomething = B_TRUE; + } + break; case F_ATTACHEDTO: lf2 = findlf(NULL, f->val[0]); if (lf2 && !isdead(lf2)) { @@ -5417,7 +5434,9 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf, " - %s", contentname); if (o->type->id == OT_SPELLBOOK) { char lbuf[BUFLEN]; - sprintf(lbuf, " (Lv %d)", getspelllevel(oo->type->id)); + sprintf(lbuf, " (Lv %d)%s", getspelllevel(oo->type->id), + lfhasflagval(player, F_CANCAST, oo->type->id, NA, NA, NULL) ? + " [known]" : ""); strcat(buf, lbuf); } strcat(buf, "\n"); @@ -5549,8 +5568,8 @@ char *makedesc_spell(objecttype_t *ot, char *retbuf) { f = hasflag(ot->flags, F_STAMCOST); if (f) { sprintf(buf, "It costs %d stamina to use.\n",f->val[0]); + strncat(retbuf, buf, HUGEBUFLEN); } - strncat(retbuf, buf, HUGEBUFLEN); f = hasflag(ot->flags, F_CASTINGTIME); @@ -6606,10 +6625,10 @@ int downline(int *y, int h, char *heading, char *subheading, char *bottomstring, centre(mainwin, C_WHITE, h-1, bottomstring); } ch = getch(); - if (cmdchars && strchr(cmdchars, ch)) { + if (ch == 27) { // ESC if (retchar) *retchar = ch; return B_TRUE; - } else if (ch == 27) { // ESC + } else if (cmdchars && strchr(cmdchars, ch)) { if (retchar) *retchar = ch; return B_TRUE; } @@ -6758,18 +6777,20 @@ void drawlevelfor(lifeform_t *lf) { void doheading(WINDOW *win, int *y, int x, char *what) { int len,i; - char *buf; + char *underline; len = strlen(what) + 1; - buf = malloc(len * sizeof(char)); + underline = malloc(len * sizeof(char)); for (i = 0; i < len; i++) { - buf[i] = '-'; + underline[i] = '-'; } - buf[i] = '\0'; + underline[i] = '\0'; + //mvwprintw(win, *y, x, what); (*y)++; + wmove(win, *y, x); + textwithcol(win, what); (*y)++; setcol(win, C_WHITE); - mvwprintw(win, *y, x, what); (*y)++; - mvwprintw(win, *y, x, buf); (*y)++; + mvwprintw(win, *y, x, underline); (*y)++; unsetcol(win, C_WHITE); - free(buf); + free(underline); } void doheadingsmall(WINDOW *win, int y, int x, char *format, char *heading) { @@ -7465,11 +7486,11 @@ enum COLOUR getskilllevelcolour(enum SKILLLEVEL slev) { case PR_ADEPT: return C_GREEN; case PR_SKILLED: - return C_BOLDGREEN; + return C_BLUE; case PR_EXPERT: - return C_BOLDCYAN; + return C_CYAN; case PR_MASTER: - return C_BOLDMAGENTA; + return C_MAGENTA; } return C_GREY; } @@ -9680,9 +9701,12 @@ void showlfstats(lifeform_t *lf, int showall) { int numknown = 0, numavailable = 0; int n; enum SKILLLEVEL slev; + skill_t *sk; + int finished = B_FALSE,dounknown; centre(mainwin, C_WHITE, 0, "SKILLS"); + /* // get available skills for (f = lf->flags->first ; f ; f = f->next) { if (f->id == F_CANLEARN) { @@ -9699,30 +9723,86 @@ void showlfstats(lifeform_t *lf, int showall) { } } } + */ - //centre(mainwin, y, "SKILLS"); y ++; - snprintf(skilltitle, BUFLEN, "%-40s%-40s","AVAILABLE SKILLS", "KNOWN SKILLS (*=maxed)"); + y = 2; + + snprintf(skilltitle, BUFLEN, "%-21s"," "); + for (i = PR_NOVICE; i <= PR_MASTER; i++) { + char toadd[BUFLEN], *sn; + int prepad,postpad,n; + // construct "|xxxxxxxx" + // ie "|Beginner" + // ie "| Inept " + sn = getskilllevelname(i); + prepad = (8 - strlen(sn))/2; + postpad = 8 - strlen(sn) - prepad; + limit(&postpad, 0, NA); + sprintf(toadd, "|^%d", getskilllevelcolour(i)); + for (n = 0;n < prepad; n++) strcat(toadd, " "); + strcat(toadd, sn); + for (n = 0;n < postpad; n++) strcat(toadd, " "); + strcat(toadd, "^n"); + strcat(skilltitle, toadd); + } doheading(mainwin, &y, 0, skilltitle); - for (n = 0; n < MAXOF(numknown,numavailable); n++) { - if (n < numavailable) { - setcol(mainwin, C_RED); - mvwprintw(mainwin, y, 0, "- %s", - getskillname(available[n]->val[0]) ); - unsetcol(mainwin, C_RED); - } - if (n < numknown) { - setcol(mainwin, getskilllevelcolour(known[n]->val[1])); - mvwprintw(mainwin, y, 40, "%c %s (%s)%s", - ismaxedskill(lf, known[n]->val[0]) ? '*' : '-', - getskillname(known[n]->val[0]), - getskilllevelname(known[n]->val[1]), - //ismaxedskill(lf, known[n]->val[0]) ? "/MAX" : "", - (known[n]->lifetime == FROMSPELL) ? "[spell]" : ""); - unsetcol(mainwin, getskilllevelcolour(known[n]->val[1])); - } - if (downline(&y, h, "SKILLS", skilltitle, promptstr, cmdchars, &ch)) { - break; + + // for each skill... + for (dounknown = 0; dounknown <= 1; dounknown++) { + for (sk = firstskill ; sk ; sk = sk->next) { + char thisline[BUFLEN]; + int printed = B_FALSE; + + slev = getskill(lf, sk->id); + if (!dounknown && (slev != PR_INEPT)) { + // known skill + sprintf(thisline, "%-21s[^%d", sk->name, getskilllevelcolour(slev)); + for (i = PR_NOVICE; i <= PR_MASTER; i++) { + char toadd[BUFLEN]; + + if (i == slev) { + if (i == getmaxskilllevel(player, sk->id)) { + // draw bar right up to the end + sprintf(toadd, "========|"); + } else { + // leave a small gap at the end of the bar + sprintf(toadd, "=======| "); + } + } else if (i < slev) { + sprintf(toadd, "========="); + } else { + sprintf(toadd, "^n "); + } + strcat(thisline, toadd); + if (i == getmaxskilllevel(player, sk->id)) { + break; + } + } + strcat(thisline, "]^n"); + wmove(mainwin, y, 0); + textwithcol(mainwin, thisline); + printed = B_TRUE; + } else if (dounknown && !slev && lfhasflagval(lf, F_CANLEARN, sk->id, NA, NA, NULL)) { + // learnable skill + setcol(mainwin, C_RED); + mvwprintw(mainwin, y, 0, "%-21s", sk->name, " " ); + unsetcol(mainwin, C_RED); + wprintw(mainwin, "["); + for (i = PR_NOVICE; i < PR_MASTER+1; i++) { + wprintw(mainwin, " "); + } + wprintw(mainwin, "]"); + unsetcol(mainwin, C_RED); + printed = B_TRUE; + } + + if (printed) { + if (downline(&y, h, "SKILLS", skilltitle, promptstr, cmdchars, &ch)) { + finished = B_TRUE; + break; + } + } } } } else if (mode == 'm') { @@ -10252,6 +10332,14 @@ void showlfstats(lifeform_t *lf, int showall) { } y++; } + f = lfhasknownflag(lf, F_MAGICBOOST); + if (f && (f->known)) { + int boost; + sumflags(lf->flags, F_MAGICBOOST, &boost, NULL, NULL); + mvwprintw(mainwin, y, 0, "The power of %s spells is boosted by %d.", + isplayer(lf) ? "your" : "its", boost); + y++; + } f = lfhasflag(lf, F_OMNIPOTENT); if (f && (f->known)) { diff --git a/lf.c b/lf.c index 4edfa42..a358825 100644 --- a/lf.c +++ b/lf.c @@ -2958,6 +2958,15 @@ int eat(lifeform_t *lf, object_t *o) { } if (fullyeaten) { + + // special cases only when eaten + switch (o->type->id) { + case OT_CHOCOLATE: + setstamina(lf, getmaxstamina(lf)); + break; + default: + break; + } // remove object removeob(o, 1); } else { @@ -4622,6 +4631,8 @@ int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, int *narms } } + limit(&ar, 0, NA); + return ar; } @@ -10899,11 +10910,15 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // elemental effects on held objects if ((damtype == DT_FIRE) && !fromob) { object_t *o, *nexto; + int nburnt = 0; + // up to dam/5 objects might be burnt // fire: dam*10 chance of burning each object which is vulnerable to fire for (o = lf->pack->first ; o ; o = nexto) { nexto = o->next; if (isvulnto(o->flags, DT_FIRE) && pctchance(amt*10)) { int newdam; + nburnt++; + if (nburnt >= (amt/5)) break; // object takes 1/4 of damage newdam = pctof(25, amt); limit(&newdam, 1, NA); @@ -11472,29 +11487,10 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, char lfname[BUFLEN]; char distbuf[BUFLEN],distbufbad[BUFLEN]; char dirbuf[BUFLEN]; - int dir; real_getlfnamea(noisemaker, lfname, B_FALSE); - if (dist >= 20) { // 20+ - strcpy(distbuf, " very far away"); - strcpy(distbufbad, " far away"); - } else if (dist >= 10) { // 10 - 19 - strcpy(distbuf, " far away"); - } else if (dist >= 5) { // 5 - 9 - strcpy(distbuf, " nearby"); - strcpy(distbufbad, " nearby"); - } else if (dist >= 2) { // 2 - 4 - strcpy(distbuf, " very nearby"); - strcpy(distbufbad, " nearby"); - } else { // 1 - strcpy(distbuf, " right beside you"); - strcpy(distbufbad, " nearby"); - } + getdisttext(l->cell, c, distbuf, distbufbad, dirbuf); - dir = getdirtowards(l->cell, c, NULL, B_FALSE, DT_COMPASS); - strcpy(dirbuf, getdirname(dir)); - dirbuf[0] = tolower(dirbuf[0]); - slev = getskill(l, SK_LISTEN); // // high listen skill lets you know more info. @@ -13005,6 +13001,36 @@ void setlosdirty(lifeform_t *lf) { } } +void setstamina(lifeform_t *lf, float howmuch) { + float orig; + orig = getstamina(lf); + lf->stamina = howmuch; + limitf(&(lf->stamina), 0, getmaxstamina(lf)); + if (getstamina(lf) != orig) { + if (isplayer(lf)) { + statdirty = B_TRUE; + drawstatus(); + updatestatus(); + if (getstamina(lf) == 0) { + msg("^BYou are exhausted."); + } else if (orig == 0) { + msg("You feel less exhausted now."); + } + } + /*else if (cansee(player, lf)) { + if (getstamina(lf) == 0) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s looks exhausted.", lfname); + } + }*/ + } + + if (getstamina(lf) == 0) { + stopsprinting(lf); + } +} + int shoot(lifeform_t *lf) { object_t *gun,*ammo; lifeform_t *targ; diff --git a/lf.h b/lf.h index 06ff3e4..6ff0539 100644 --- a/lf.h +++ b/lf.h @@ -357,6 +357,7 @@ void setlastdam(lifeform_t *lf, char *buf); //void setlftarget(lifeform_t *lf, lifeform_t *victim); int setlfmaterial(lifeform_t *lf, enum MATERIAL id); void setlosdirty(lifeform_t *lf); +void setstamina(lifeform_t *lf, float howmuch); int shoot(lifeform_t *lf); 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); diff --git a/map.c b/map.c index daf740b..7c2a37b 100644 --- a/map.c +++ b/map.c @@ -71,6 +71,7 @@ cell_t *addcell(map_t *m, int x, int y) { cell->littimer = 0; cell->origlittimer = 0; cell->writing = NULL; + cell->writinglifetime = -1; cell->known = B_FALSE; cell->knowntime = 0; cell->knownglyph.ch = ' '; @@ -5738,7 +5739,36 @@ int wallstoleftright(cell_t *c, int dir) { return B_FALSE; } +void writetextonground(lifeform_t *lf, cell_t *c, char *buf, int howlong) { + char *p; + if (lf && isblind(lf)) { + // if blind, garble text somewhat + for (p = buf ; *p; p++) { + if (*p != ' ') { + if (onein(4)) { + if (onein(2)) { + *p = rnd('a','z'); + } else { + *p = rnd('A','Z'); + } + } + } + } + } + if (c->writing) { + free(c->writing); + } + c->writing = strdup(buf); + c->writinglifetime = howlong; - - + if (haslos(player, c)) { + if (c == player->cell) { + msg("Magical writing appears around you!"); + } else { + msg("Magical writing appears nearby!"); + } + } else if (c == player->cell) { + msg("You feel something stirring in the air around you."); + } +} diff --git a/map.h b/map.h index 3ee6dc5..87c8559 100644 --- a/map.h +++ b/map.h @@ -139,3 +139,4 @@ void updateknowncells(void); int validateregions(void); int validateregionthing(regionthing_t *thing); int wallstoleftright(cell_t *c, int dir); +void writetextonground(lifeform_t *lf, cell_t *c, char *buf, int howlong); diff --git a/move.c b/move.c index 905ad99..659bd4e 100644 --- a/move.c +++ b/move.c @@ -82,9 +82,11 @@ int ispossiblemove(lifeform_t *lf, int dir) { case E_LFINWAY: return B_TRUE; case E_DOORINWAY: - if (canopendoors(lf)) { + // if ai lifeforms CANT open doors, they will attack them + if (canopendoors(lf) || !isplayer(lf)) { return B_TRUE; } + //} break; case E_OBINWAY: inway = (object_t *)rdata; @@ -1609,6 +1611,12 @@ int opendoor(lifeform_t *lf, object_t *o) { if (!canopendoors(lf)) { if (isplayer(lf)) { msg("You have no hands with which to open the door!"); + } else { + // ai will try to break down doors + if (gettargetlf(lf)) { + attackcell(lf, doorcell, B_TRUE); + return B_FALSE; + } } return B_TRUE; } @@ -1670,8 +1678,21 @@ int opendoor(lifeform_t *lf, object_t *o) { } // locked? if (hasflag(o->flags, F_LOCKED)) { - if (lf && isplayer(lf)) { - msg("The %s is locked.", noprefix(obname)); + if (lf) { + if (isplayer(lf)) { + msg("The %s is locked.", noprefix(obname)); + } else { + if (gettargetlf(lf)) { + // ai will automatically attack locked doors to + // get at the player + attackcell(lf, doorcell, B_TRUE); + return B_FALSE; + } else { + noise(doorcell, NULL, NC_OTHER, 2, "a door handle rattling", NULL); + } + } + taketime(lf, getactspeed(lf)); + touch(lf, o); } return B_TRUE; } else { @@ -1682,11 +1703,32 @@ int opendoor(lifeform_t *lf, object_t *o) { amt = getattr(lf, A_STR) - 10; if (amt < 0) amt = 0; - if (lf && isplayer(lf)) { - if (amt > 0) { - msg("The %s moves slightly but seems jammed.", noprefix(obname)); + if (lf) { + if (isplayer(lf)) { + if (amt > 0) { + msg("The %s moves slightly but seems jammed.", noprefix(obname)); + } else { + msg("The %s is jammed.", noprefix(obname)); + } } else { - msg("The %s is jammed.", noprefix(obname)); + // ai chasing someone and not strong enough to unjam the door? + if ((amt == 0) && gettargetlf(lf)) { + attackcell(lf, doorcell, B_TRUE); + return B_FALSE; + } else { + // try to force it + if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s tries to open %s, but fails.", lfname, obname); + } else if (haslos(player, doorcell)) { + msg("Something tries to open %s.", obname); + } else { + char noisebuf[BUFLEN]; + sprintf(noisebuf, "%s jiggling against its hinges.", obname); + noise(doorcell, NULL, NC_OTHER, 3, noisebuf, NULL); + } + } } } // loosen a bit @@ -1710,15 +1752,19 @@ int opendoor(lifeform_t *lf, object_t *o) { if (lf) { if (isplayer(lf)) { - msg("You open %s.",obname); + msg("You force %s open!",obname); } else { if (cansee(player, lf) && isadjacent(lf->cell, doorcell)) { getlfname(lf, buf); capitalise(buf); - msg("%s opens %s.",buf, obname); + msg("%s forces %s open!",buf, obname); } else if (haslos(player, doorcell)) { capitalise(obname); - msg("%s opens.",obname); + msg("%s bursts open!",obname); + } else { + char noisebuf[BUFLEN]; + sprintf(noisebuf, "%s bursting open.", obname); + noise(doorcell, NULL, NC_OTHER, 4, noisebuf, NULL); } } @@ -2859,6 +2905,27 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { return B_FALSE; } + // glyph of warding? + if (cell->writing && strstr(cell->writing, "*WARD")) { + char buf[BUFLEN]; + char *bp, *p; + int power; + // extract number + bp = buf; + for (p = cell->writing; *p; p++) { + if (isdigit(*p)) { + *bp = *p; + bp++; + } + } + *bp = '\0'; + power = atoi(buf); + if ( gethitdice(lf) <= power) { + if (error) *error = E_WONT; + return B_FALSE; + } + } + // some lfs will only leave their rooms if they have a target // ie. shopkeepers f = lfhasflag(lf, F_STAYINROOM); diff --git a/nexus.c b/nexus.c index f8dce1d..ac6fe5b 100644 --- a/nexus.c +++ b/nexus.c @@ -297,29 +297,27 @@ int main(int argc, char **argv) { giveskilllev(player, sk->id, PR_NOVICE); switch (sk->id) { case SK_SS_AIR: - addflag(player->flags, F_CANCAST, OT_S_MIST, NA, NA, NULL); addflag(player->flags, F_CANSEETHROUGHMAT, MT_GAS, NA, NA, NULL); sb1 = addob(player->pack, "spellbook of air magic"); break; case SK_SS_COLD: - addflag(player->flags, F_CANCAST, OT_S_CHILL, NA, NA, NULL); sb1 = addob(player->pack, "spellbook of cold magic"); break; case SK_SS_FIRE: - addflag(player->flags, F_CANCAST, OT_S_SPARK, NA, NA, NULL); sb1 = addob(player->pack, "spellbook of fire magic"); break; case SK_SS_DEATH: - addflag(player->flags, F_CANCAST, OT_S_STENCH, NA, NA, NULL); sb1 = addob(player->pack, "spellbook of necromancy"); break; case SK_SS_WILD: - addflag(player->flags, F_CANCAST, OT_S_MANASPIKE, NA, NA, NULL); sb1 = addob(player->pack, "spellbook of wild magic"); break; default: break; } + if (sb1) { + addflag(player->flags, F_CANCAST, sb1->contents->first->type->id, NA, NA, NULL); + } initprompt(&prompt, "Select your secondary spell school:"); addchoice(&prompt, 'd', getskillname(SK_SS_DIVINATION), NULL, findskill(SK_SS_DIVINATION), NULL); @@ -332,28 +330,26 @@ int main(int argc, char **argv) { giveskilllev(player, sk->id, PR_NOVICE); switch (sk->id) { case SK_SS_DIVINATION: - addflag(player->flags, F_CANCAST, OT_S_SIXTHSENSE, NA, NA, NULL); sb2 = addob(player->pack, "spellbook of divination magic"); break; case SK_SS_GRAVITY: - addflag(player->flags, F_CANCAST, OT_S_TRUESTRIKE, NA, NA, NULL); sb2 = addob(player->pack, "spellbook of gravitation magic"); break; case SK_SS_MODIFICATION: - addflag(player->flags, F_CANCAST, OT_S_HOLDPORTAL, NA, NA, NULL); sb2 = addob(player->pack, "spellbook of modification magic"); break; case SK_SS_SUMMONING: - addflag(player->flags, F_CANCAST, OT_S_FLOATINGDISC, NA, NA, NULL); sb2 = addob(player->pack, "spellbook of summoning magic"); break; case SK_SS_TRANSLOCATION: - addflag(player->flags, F_CANCAST, OT_S_APPORTATION, NA, NA, NULL); sb2 = addob(player->pack, "spellbook of translocation magic"); break; default: break; } + if (sb2) { + addflag(player->flags, F_CANCAST, sb2->contents->first->type->id, NA, NA, NULL); + } identify(sb1); identify(sb2); } @@ -1468,6 +1464,22 @@ void timeeffectsworld(map_t *map, int updategametime) { } } + // writing fading? + if (c->writing && (c->writinglifetime > 0)) { + c->writinglifetime--; + if (c->writinglifetime <= 0) { + free(c->writing); + c->writing = NULL; + if (haslos(player, c)) { + if (c == player->cell) { + msg("The magical inscription beneath you vanishes."); + } else { + msg("A magical inscription nearby vanishes."); + } + } + } + } + pit = hasobwithflagval(c->obpile, F_PIT, D_DOWN, NA, NA, NULL); if (pit) { obsfallthrough(c, pit); diff --git a/objects.c b/objects.c index 833888b..c6d5b10 100644 --- a/objects.c +++ b/objects.c @@ -1193,9 +1193,15 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes // 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) { // giving to a lifeform? - nspells = 6; - firstlev = 1; + if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { + enum OBTYPE firstspell; + // giving to player at start of game + nspells = 5; + firstlev = 2; + + // fixed first spell + firstspell = getfirstwizspell(bookcontents); + assert(addobfast(o->contents, firstspell)); } else { nspells = rnd(2,5); firstlev = rnd(1,4); @@ -1685,28 +1691,18 @@ obpile_t *addobpile(lifeform_t *owner, cell_t *where, object_t *parentob) { } void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes) { - int x,y; + cell_t *cell[MAXCANDIDATES],*c; + int ncells,i; objecttype_t *ot; + ot = findotn(name); if (!ot) return; + getradiuscells(centre, radius, DT_ORTH, B_FALSE, LOF_WALLSTOP, B_FALSE, cell, &ncells, B_FALSE); - for (y = centre->y - radius ; y <= centre->y + radius; y++) { - for (x = centre->x - radius ; x <= centre->x + radius; x++) { - int valid = B_FALSE; - cell_t *c; - c = getcellat(centre->map, x, y); - if (c && !c->type->solid && haslof(centre, c, LOF_WALLSTOP, NULL)) { - if (allowdupes || !hasob(c->obpile, ot->id)) { - if ((dirtype == DT_COMPASS) && (getcelldist(centre, c) <= radius)) { - valid = B_TRUE; - } else if ((dirtype == DT_ORTH) && (getcelldistorth(centre, c) <= radius)) { - valid = B_TRUE; - } - } - } - if (valid) { - addob(c->obpile, name); - } + for (i = 0; i < ncells; i++) { + c = cell[i]; + if (allowdupes || !hasob(c->obpile, ot->id)) { + addob(c->obpile, name); } } } @@ -3668,7 +3664,7 @@ char *getdamname(enum DAMTYPE damtype) { case DT_PETRIFY: return "petrification"; case DT_PIERCE: return "piercing"; case DT_POISON: return "poison"; - case DT_POISONGAS: return "poison gas"; + case DT_POISONGAS: return "gas"; case DT_PROJECTILE: return "projectile"; case DT_SLASH: return "slashing"; case DT_SONIC: return "sonic"; @@ -3687,7 +3683,7 @@ char *getdamnamenoun(enum DAMTYPE damtype) { case DT_MELT: return "melting"; case DT_PETRIFY: return "petrification"; case DT_PIERCE: return "piercing damage"; - case DT_POISONGAS: return "poison gas"; + case DT_POISONGAS: return "gas"; case DT_POISON: return "poison"; case DT_SLASH: return "slashing damage"; case DT_ELECTRIC: return "electricity"; @@ -5381,7 +5377,7 @@ int getthrowdam(object_t *o) { break; } - return (int)dam; + return (int)ceil(dam); } // get either name of top object, or cell type @@ -5417,6 +5413,10 @@ char *gettopobname(cell_t *c, char *retbuf) { // just print the cell's name strcat(retbuf, c->type->name); } + if (c->writing) { + strcat(retbuf, ", writing:"); + strcat(retbuf, c->writing); + } return retbuf; } @@ -10015,12 +10015,12 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno // no damage from equipped _weapons_ if ((f->val[0] != BP_WEAPON) || (f->val[0] != BP_SECWEAPON)) { } else { - // equipped clothes/armour? 1.5x damage. - lfdam = pctof(150,howmuch); + // equipped clothes/armour? full damage. + lfdam = howmuch; } } else { - // otherwise normal. - lfdam = howmuch; + // objects in your pack? just a little bit of damage + lfdam = pctof(25,howmuch); } if (lfdam) { // announce @@ -10261,7 +10261,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, int shattered = B_FALSE; char throwverbpast[BUFLEN]; char throwverbpres[BUFLEN]; - int acc; + int acc,myroll; int youhit = B_FALSE; int missiledam = 0; object_t *newob = NULL; @@ -10548,13 +10548,12 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (willcatch) { acc = 100; } else { - acc = getmissileaccuracy(thrower, where, o, firearm, A_AGI); + acc = getmissileaccuracy(thrower, where, o, firearm, lfhasflag(thrower, F_TKTHROW)) ; } } else { // purely based on saving throw... acc = 100; } - // adjust for swimming if (isswimming(thrower)) { switch (getskill(thrower, SK_SWIMMING)) { @@ -10569,9 +10568,13 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, break; } } + if (db && thrower) { + dblog("%s is throwing %s - acc = %d, speed = %d\n", realthrowername, obname, acc, speed); + } // roll for hit youhit = B_FALSE; + myroll = rnd(1,100); // metal projectile versus magnetic shield? if (target && lfhasflag(target, F_MAGSHIELD) && ismetal(o->material->id)) { // announce @@ -10580,9 +10583,12 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, announcedmiss = B_TRUE; } youhit = B_FALSE; - } else if (rnd(1,100) <= acc) { + } else if (myroll <= acc) { youhit = B_TRUE; } + if (db && thrower) { + dblog("roll = %d, youhit = %s", myroll, youhit ? "YES" : "no"); + } if (youhit && target) { @@ -10664,6 +10670,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, willcatch = B_TRUE; } else if (!lfhasflag(target, F_CASTINGSPELL) && skillcheck(target, SC_DODGE, 7*speed, dodgemod)) { // then check if we dodge it... + if (db) dblog("target passed dodge check."); youhit = B_FALSE; } } @@ -10718,13 +10725,15 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, throwdam = getthrowdam(o); dam = (int)((float)throwdam * multiplier); - if (db) dblog("fireat(): dam = throwdam(%d) * speed(%d)/2 = %d",throwdam, speed, dam); // special case if (o->type->id == OT_RUBBERBULLET) { dam = 1; } + if (db) dblog("fireat(): dam = throwdam(%d) * multi(%d)",throwdam, multiplier); + if (db) dblog("dealing %d damage", dam); + // deal extra cutting damage afterwards? if (willshatter(o->material->id)) { shattered = B_TRUE; @@ -11928,9 +11937,11 @@ enum MATSTATE getmaterialstate(enum MATERIAL mat) { return MS_OTHER; // should never happen } -int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt) { +int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, flag_t *tkthrow) { int acc,maxrange,howfar; enum SKILLLEVEL slev; + enum SKILL whichskill; + enum ATTRIB whichatt; // figure out if you miss or not, based on distance and // dexterity // base: @@ -11942,6 +11953,14 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob // then modify using dexterity/int/whatever // then penalise for throwing non-missiles + if (tkthrow) { + whichatt = tkthrow->val[0]; + whichskill = tkthrow->val[1]; + } else { + whichatt = A_AGI; + whichskill = SK_THROWING; + } + // base accuracy if (firearm) { @@ -11950,8 +11969,8 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob // ie. inept = -30%, adept = 0%, master = +30% acc += ((slev - PR_ADEPT) * 10); } else { - slev = getskill(thrower, SK_THROWING); - acc = 40; + slev = getskill(thrower, whichskill); + acc = 60; // ie. inept = -30%, adept = 0%, master = +30% acc += ((slev - PR_ADEPT) * 10); // acc will now be 10 - 70 @@ -11984,7 +12003,7 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob } // penalty for throwing non-missiles - if (missile && !firearm && !isthrowmissile(missile)) { + if (missile && !firearm && !isthrowmissile(missile) && !tkthrow) { acc -= 20; } // modify for prone throwers diff --git a/objects.h b/objects.h index eeefa8f..747f2a6 100644 --- a/objects.h +++ b/objects.h @@ -69,7 +69,7 @@ int geteffecttime(int min, int max, enum BLESSTYPE isblessed); objecttype_t *getlinkspell(object_t *o); enum COLOUR getmaterialcolour(enum MATERIAL mat ); enum MATSTATE getmaterialstate(enum MATERIAL mat); -int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt); +int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, flag_t *tkthrow); int getobaccuracy(object_t *wep, lifeform_t *weilder); int getobbonus(object_t *o, int onlyknown); int getobpoints(object_t *o); diff --git a/spell.c b/spell.c index 5639f92..3aa1f73 100644 --- a/spell.c +++ b/spell.c @@ -2642,7 +2642,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } else if (abilid == OT_A_INSPECT) { object_t *o; int difficulty; - int rarity; + enum RARITY rarity; int mod; enum SKILLLEVEL slev; flag_t *f; @@ -2704,11 +2704,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // skillcheck... f = hasflag(o->flags, F_RARITY); if (f) { - rarity = f->val[1]; + rarity = f->val[2]; } else { rarity = 0; } - difficulty = 25 + ((100 - rarity) / 5); + difficulty = 20 + (rarity*5); switch (o->type->obclass->id) { case OC_SCROLL: difficulty += 2; break; @@ -4712,6 +4712,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } brightflash(caster->cell, 2 + (power/4), caster); + } else if (spellid == OT_S_GLYPHWARDING) { + char buf[BUFLEN]; + sprintf(buf, "^g*WARD%d*^n", power/2); + writetextonground(caster, caster->cell, buf, power*5); } else if (spellid == OT_S_FLOATINGDISC) { lifeform_t *newlf; // get random adjacent cell @@ -5551,7 +5555,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } } else if (spellid == OT_S_HOLDPORTAL) { - object_t *o; + object_t *o,*oo; + cell_t *c; o = hasobwithflag(targcell->obpile, F_DOOR); if (!o) { @@ -5559,8 +5564,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } + // move any objects which are in the way (but not lfs) + for (oo = targcell->obpile->first ; oo ; oo = oo->next) { + if ((oo != o) && (getmaterialstate(oo->material->id) == MS_SOLID)) { + c = getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND); + if (c) moveob(oo, c->obpile, ALL); + } + } + closedoor(NULL, o); - addflag(o->flags, F_JAMMED, 100, NA, NA, NULL); + addflag(o->flags, F_JAMMED, power*2, NA, NA, NULL); if (haslos(player, targcell)) { char buf[BUFLEN]; @@ -5608,7 +5621,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } - // does caster have a bladed weapon? + // does caster have a weapon? wep = getweapon(target); if (!wep) { fizzle(caster); @@ -5618,16 +5631,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ getobname(wep, obname, wep->amt); if (isplayer(target)) { - msg("Your %s%s is covered with ice!", obname, getpossessive(obname)); + msg("Your %s is covered with ice!", noprefix(obname)); if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (cansee(player, target)) { char lfname[BUFLEN]; getlfname(target, lfname); - msg("%s%s %s is covered with ice!", lfname, getpossessive(lfname), lfname); + msg("%s%s %s is covered with ice!", lfname, getpossessive(lfname), noprefix(obname)); if (seenbyplayer) *seenbyplayer = B_TRUE; } - addtempflag(wep->flags, F_EXTRADAM, DT_COLD, NA, NA, "1d6", 10 + power*3); + addtempflag(wep->flags, F_FROZEN, B_TRUE, NA, NA, NULL, 10 + power*3); } else if (spellid == OT_S_ICICLE) { object_t *o; @@ -6425,29 +6438,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; // ask what to inscribe askstring("What will you inscribe here", '?', buf, BUFLEN, NULL); - if (strlen(buf) > 0) { - char *p; - if (isblind(caster)) { - // if blind, garble text somewhat - for (p = buf ; *p; p++) { - if (*p != ' ') { - if (onein(4)) { - if (onein(2)) { - *p = rnd('a','z'); - } else { - *p = rnd('A','Z'); - } - } - } - } - msg("You feel something stirring in the air around you."); - } else { - msg("Magical writing appears before you!"); - } - if (caster->cell->writing) { - free(caster->cell->writing); - } - caster->cell->writing = strdup(buf); + if (strchr(buf, '*') || strchr(buf, '^')) { + // prevent glyphs / colours + fizzle(caster); + } else if (strlen(buf) > 0) { + writetextonground(caster, caster->cell, buf, power*50); } else { fizzle(caster); } @@ -6789,42 +6784,51 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ prompt.maycancel = B_TRUE; for (m = firstmap ; m ; m = m->next) { int x,y; - char ch = 'b'; - // on the ground? + char ch = 'a'; + char mapname[BUFLEN]; + + getregionname(mapname, m, B_TRUE); + capitalise(mapname); + + if (m->habitat->id == H_HEAVEN) continue; for (y = 0; y < m->h; y++) { for (x = 0; x < m->w; x++) { cell_t *c; c = getcellat(m, x, y); if (c) { + // on the ground? for (o = c->obpile->first ; o ; o = o->next) { char obname[BUFLEN]; real_getobname(o, obname, o->amt, B_TRUE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); if (strcasestr(obname, wantname)) { - addchoice(&prompt, ch++, obname, NULL, o, NULL); + char ptext[BUFLEN]; + char distbuf[BUFLEN],dirbuf[BUFLEN]; + getdisttext(caster->cell, c, distbuf, NULL, dirbuf); + sprintf(ptext, "%s: %s (%s to the %s)", mapname, obname, distbuf, dirbuf); + addchoice(&prompt, ch++, ptext, NULL, o, NULL); } } - } - } - } - // carried by someone? - for (y = 0; y < m->h; y++) { - for (x = 0; x < m->w; x++) { - cell_t *c; - c = getcellat(m, x, y); - if (c && c->lf) { - for (o = c->lf->pack->first ; o ; o = o->next) { - char obname[BUFLEN]; - real_getobname(o, obname, o->amt, B_TRUE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); - if (strcasestr(obname, wantname)) { - char lfname[BUFLEN]; - real_getlfnamea(c->lf, lfname, B_FALSE); - strcat(obname, " (held by "); - strcat(obname, lfname); - strcat(obname, ")"); - addchoice(&prompt, ch++, obname, NULL, o, NULL); + // carried by someone? + if (c->lf) { + for (o = c->lf->pack->first ; o ; o = o->next) { + char obname[BUFLEN]; + real_getobname(o, obname, o->amt, B_TRUE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); + if (strcasestr(obname, wantname)) { + char ptext[BUFLEN]; + char distbuf[BUFLEN],dirbuf[BUFLEN]; + char lfname[BUFLEN]; + + real_getlfnamea(c->lf, lfname, B_FALSE); + getdisttext(caster->cell, c, distbuf, NULL, dirbuf); + sprintf(ptext, "%s: %s (%s to the %s, held by %s)", + mapname, obname, distbuf, dirbuf, lfname); + + addchoice(&prompt, ch++, ptext, NULL, o, NULL); + } } } + } } } @@ -7822,15 +7826,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (targcell->lf && cansee(player, targcell->lf)) { char lfname[BUFLEN]; getlfname(targcell->lf, lfname); - msg("A small spark of flame singes %s.", lfname); + msg("A small burst of flame singes %s.", lfname); } else { - msg("A small spark of flame appears."); + msg("A small burst of flame appears."); } if (seenbyplayer) *seenbyplayer = B_TRUE; } if (targcell->lf) { - losehp(targcell->lf, rnd(1,3), DT_FIRE, caster, "a spark"); + losehp(targcell->lf, rnd(1,6), DT_FIRE, caster, "a spark"); } else { for (o = targcell->obpile->first ; o ; o = nexto) { nexto = o->next; @@ -8422,7 +8426,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { // otherwise throw it there - but speed is based on // caster's INTELLIGENCE, not strength like normal. + addflag(caster->flags, F_TKTHROW, A_IQ, SK_SS_MENTAL, NA, NULL); fireat(caster, targob, targob->amt, targcell, power, NULL); + killflagsofid(caster->flags, F_TKTHROW); // note that we use fireat() rather than throwat() to avoid // calling taketime() twice. } @@ -9218,6 +9224,24 @@ void fizzle(lifeform_t *caster) { } } +enum OBTYPE getfirstwizspell(enum SPELLSCHOOL school) { + enum OBTYPE firstspell = OT_S_MANASPIKE; + switch (school) { + case SS_AIR: firstspell = OT_S_MIST; break; + case SS_COLD: firstspell = OT_S_CHILL; break; + case SS_FIRE: firstspell = OT_S_SPARK; break; + case SS_DEATH: firstspell = OT_S_STENCH; break; + case SS_DIVINATION: firstspell = OT_S_SIXTHSENSE; break; + case SS_GRAVITY: firstspell = OT_S_TRUESTRIKE; break; + case SS_MODIFICATION: firstspell = OT_S_HOLDPORTAL; break; + case SS_TRANSLOCATION: firstspell = OT_S_APPORTATION; break; + case SS_SUMMONING: firstspell = OT_S_GLYPHWARDING; break; + default: + case SS_WILD: firstspell = OT_S_MANASPIKE; break; + } + return firstspell; +} + char *getforcedspellrace(lifeform_t *lf, enum OBTYPE spellid, char *racestr) { flag_t *f; // forced? @@ -9314,8 +9338,10 @@ enum OBTYPE getrandomspellfromschool(enum SPELLSCHOOL school, int wantlev) { // get list of all spells of this school for (ot = objecttype ; ot ; ot = ot->next) { if ((ot->obclass->id == OC_SPELL) && spellisfromschool(ot->id, school)) { - if ((wantlev == 0) || (getspelllevel(ot->id) == wantlev)) { - poss[nposs++] = ot; + if (!hasflag(ot->flags, F_NORANDOM)) { + if ((wantlev == 0) || (getspelllevel(ot->id) == wantlev)) { + poss[nposs++] = ot; + } } } } @@ -9511,18 +9537,22 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { enum SKILLLEVEL schoolskill; enum SPELLSCHOOL school; int db = B_FALSE; + int boost; flag_t *f; + if (db) { objecttype_t *ot; ot = findot(spellid); if (db) dblog("getspellpower for lf %s, spell %s", lf->race->name, ot->name); } + sumflags(lf->flags, F_MAGICBOOST, &boost, NULL, NULL); + //////////////////////////////////// // CAN WE CAST THIS AT ALL //////////////////////////////////// - // If we can _will_ this to occur then we might have a set + // If we can will/cast this then we might have a set // spellpower f = lfhasflagval(lf, F_CANWILL, spellid, NA, NA, NULL); if (f && strlen(f->text)) { @@ -9532,8 +9562,22 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { dblog("-->power = %d (from canwill)", power); } // note that this power _can_ override max spell power + power += boost; return power; } + } else { + f = lfhasflagval(lf, F_CANCAST, spellid, NA, NA, NULL); + if (f && strlen(f->text)) { + texttospellopts(f->text, "pw:", &power, NULL ); + if (power > 0) { + if (db) { + dblog("-->power = %d (from cancast)", power); + } + // note that this power _can_ override max spell power + power += boost; + return power; + } + } } // get spell details @@ -9598,6 +9642,7 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { power = gethitdice(lf); } + power += boost; limit(&power, 0, getspellmaxpower(spellid)); return power; } diff --git a/spell.h b/spell.h index d667dc4..89fa335 100644 --- a/spell.h +++ b/spell.h @@ -8,6 +8,7 @@ objecttype_t *findspelln(char *buf); enum SPELLSCHOOL findspellschoolbyname(char *buf); void fizzle(lifeform_t *caster); //int getiqreq(enum OBTYPE oid); +enum OBTYPE getfirstwizspell(enum SPELLSCHOOL school); char *getforcedspellrace(lifeform_t *lf, enum OBTYPE spellid, char *racestr); int getmpcost(lifeform_t *lf, enum OBTYPE oid); int getmrdiff(enum OBTYPE spellid, int power); diff --git a/text.c b/text.c index f3940fe..7e3973d 100644 --- a/text.c +++ b/text.c @@ -8,6 +8,8 @@ #include "defs.h" #include "flag.h" #include "lf.h" +#include "map.h" +#include "move.h" #include "nexus.h" #include "objects.h" #include "text.h" @@ -86,6 +88,9 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam int usecrittext = B_FALSE; char wepname[BUFLEN],buf[BUFLEN]; + // default + strcpy(retbuf, ""); + getobname(wep, wepname, 1); // initial hit... @@ -190,7 +195,7 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam } else if (fatal) { // fatal switch (damtype) { case DT_COLD: - snprintf(retbuf, BUFLEN, "^%c%s %s chilled to the bone", getlfcol(victim, CC_BAD), victimname, is(victim)); + snprintf(retbuf, BUFLEN, "^%c%s %s chilled to the bone!", getlfcol(victim, CC_BAD), victimname, is(victim)); break; case DT_HEAT: case DT_FIRE: @@ -455,7 +460,13 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam return "purify"; } } else if (damtype == DT_MAGIC) { + if (pct <= 5) { + return "zap"; + } else if (pct <= 15) { + return "sear"; + } else if (pct <= 40) { return "blast"; + } } else if (damtype == DT_PIERCE) { if (pct <= 5) { return "poke"; @@ -614,6 +625,36 @@ char *getdirnameshort(int dir) { return "?"; } +void getdisttext(cell_t *src, cell_t *dst,char *distbuf, char *distbufapprox, char *dirbuf) { + int dist; + int dir; + dist = getcelldist(src, dst); + dir = getdirtowards(src, dst, NULL, B_FALSE, DT_COMPASS); + + if (dirbuf) { + strcpy(dirbuf, getdirname(dir)); + dirbuf[0] = tolower(dirbuf[0]); + } + + if (dist >= 20) { // 20+ + if (distbuf) strcpy(distbuf, " very far away"); + if (distbufapprox) strcpy(distbufapprox, " far away"); + } else if (dist >= 10) { // 10 - 19 + if (distbuf) strcpy(distbuf, " far away"); + if (distbufapprox) strcpy(distbufapprox, " far away"); + } else if (dist >= 5) { // 5 - 9 + if (distbuf) strcpy(distbuf, " nearby"); + if (distbufapprox) strcpy(distbufapprox, " nearby"); + } else if (dist >= 2) { // 2 - 4 + if (distbuf) strcpy(distbuf, " very nearby"); + if (distbufapprox) strcpy(distbufapprox, " nearby"); + } else { // 1 + if (distbuf) strcpy(distbuf, " right beside you"); + if (distbufapprox) strcpy(distbufapprox, " nearby"); + } + +} + int gethitconferlifetime(char *text, int *min, int *max) { int howlong; int localmin = -1,localmax = -1; diff --git a/text.h b/text.h index d7091b8..473c2ac 100644 --- a/text.h +++ b/text.h @@ -15,6 +15,7 @@ char *getattrabbrev(enum ATTRIB att); char *getattrname(enum ATTRIB att); char *getdirname(int dir); char *getdirnameshort(int dir); +void getdisttext(cell_t *src, cell_t *dst,char *distbuf, char *distbufapprox, char *dirbuf); int gethitconferlifetime(char *text, int *min, int *max); char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp); char *getpoisondamverb(enum POISONTYPE ptype);