From 9db5f3aeecb9969ddc2a189d48c7a1988170601a Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Mon, 20 Jun 2011 03:16:30 +0000 Subject: [PATCH] - [+] adjust damage for size * [+] repair armour * [+] armour "hardness" to reduce damage? - [+] fix resting while poisoned. - [+] shouldn't be able to attack while ethereal - [+] cursed scroll of mending should damage stuff - [+] spark should light unactivated candles/torches instead of igniting. * [+] askcoords: add a subprompt param: * [+] xp levels: - [+] stealing skill * [+] alarm spell - level 1 wild magic - [+] reduce damage when drunk (-1d3) * [+] better armour material damage immunities * [+] bug - lots of mosnters on same square - bug with f_numappear - [+] chat-> "go to x,y" (they must have los to there) - [+] reduce # objects in rooms again!!!! * [+] put gatekeeper on DLEV 6 - [+] bug: when doing a heavy blow, don't use weapon effects liek trip. - [+] don't show "[magic]" or [inspected] at end of game - [+] knockback bug: You flatten the kobold! The kobold slams into a rock floor! - [+] warn before dulling blade.... (if pretty high iq) - [+] monstesr should not start eating when enemies are nearby! - [+] increase weight of weapons - [+] fix up what counts as a heavy wep - [+] check throwing - i can throw a 6.5 javelin 6 squares with a str of 7!! - [+] eat blinkdog corpse for instant blink ability - [+] true strike (???, next xx attacks alway hits). xx is power/3 - [+] floating disc (summon) - [+] obscuring mist spell fixes --- ai.c | 34 ++++- attack.c | 301 +++++++++++++++++++++++++++---------------- attack.h | 3 +- defs.h | 27 +++- flag.c | 8 +- io.c | 277 ++++++++++++++++++++++++++------------- io.h | 2 +- lf.c | 321 ++++++++++++++++++++++++++++++++++++---------- lf.h | 2 + map.c | 23 ++-- move.c | 30 ++++- nexus.c | 1 + objects.c | 378 ++++++++++++++++++++++++++++++++++-------------------- objects.h | 2 + spell.c | 369 ++++++++++++++++++++++++++++++++++++++++++++-------- spell.h | 1 + 16 files changed, 1287 insertions(+), 492 deletions(-) diff --git a/ai.c b/ai.c index 1ddc0a4..1e66f36 100644 --- a/ai.c +++ b/ai.c @@ -33,6 +33,11 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { db = B_TRUE; } + // mindless? + if (getiqname(getattr(lf, A_IQ), NULL) == IQ_MINDLESS) { + return; + } + // already targetting this lf? f = lfhasflagval(lf, F_TARGETLF, victim->id, NA, NA, NULL); if (f) { @@ -723,7 +728,7 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) { if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y); c = getcellat(lf->cell->map, x, y); if (c) { - // target cell adjacent and something in the way? + // try to move towards the cll if (movetowards(lf, c, DT_ORTH)) { // couldn't move towards it for some reason. // so stop trying. @@ -765,7 +770,7 @@ int aipickup(lifeform_t *lf, object_t *o) { int aipickupok(lifeform_t *lf, object_t *o) { int ok = B_FALSE; if (isedible(o)) { - if (caneat(lf, o)) { + if (caneat(lf, o) && !isinbattle(lf)) { ok = B_TRUE; } } else if (canpickup(lf, o, 1)) { @@ -992,8 +997,6 @@ void aiturn(lifeform_t *lf) { /////////////////////////////////////////////// // attacks /////////////////////////////////////////////// - - target = gettargetlf(lf); // do we already have a target we are attacking? if (target) { @@ -1036,7 +1039,6 @@ void aiturn(lifeform_t *lf) { /////////////////////////////////////////////// // movement /////////////////////////////////////////////// - // do we have a target cell? f = hasflag(lf->flags, F_TARGETCELL); if (f) { @@ -1064,6 +1066,9 @@ void aiturn(lifeform_t *lf) { } else if (haslos(lf, c) && (what->pile->where != c)) { // if you can see the cell and object isn't there anymore valid = B_FALSE; + } else if (c->lf && !areenemies(lf, c->lf) && haslos(lf, c) && (getcelldist(lf->cell, c) == 1)) { + // can see a non-enemy on top of the object, and we are adjacent + valid = B_FALSE; } } @@ -1091,8 +1096,6 @@ void aiturn(lifeform_t *lf) { } */ - - // not attacking anyone in particular if (db) dblog(".oO { i do not have a target or can't move towards it. looking for one. }"); @@ -1211,6 +1214,20 @@ void aiturn(lifeform_t *lf) { } } + // do we have armour which needs repairing? + if (getskill(lf, SK_ARMOUR) >= PR_SKILLED) { + if (db) dblog(".oO { do i have any armour to repair? }"); + // just try to use the ability - it'll fail if we have nothing + // which we can repair. + if (!useability(lf, OT_A_REPAIR, NULL, NULL)) { + if (db) dblog(".oO { yes - done. }"); + // success + return; + } else { + if (db) dblog(".oO { no armour to repair. }"); + } + } + // pet movement - note that pets will only rest if their // master is resting. the normal rest code underneath this section // will never be called. @@ -1823,6 +1840,9 @@ int useitemwithflag(lifeform_t *lf, enum FLAG whichflag) { if (!operate(lf, o, lf->cell)) { return B_FALSE; } + // here on are special cases + } else if (o->type->id == OT_ASHCONCEAL) { + throwat(lf, o, lf->cell); } } } diff --git a/attack.c b/attack.c index 9c8f6ce..f3600a9 100644 --- a/attack.c +++ b/attack.c @@ -39,45 +39,46 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty if (armour) { int actualdam; - flag_t *rust; + int ar = 0; + flag_t *rust, *f; + + f = hasflag(armour->flags, F_ARMOURRATING); + if (f) { + ar = f->val[0]; + } + + rust = hasflag(armour->flags, F_RUSTED); + + actualdam = dam; + // adjust how much damage to do to armour if ( ((armour->type->id == OT_FLAKJACKET) && (damtype == DT_PROJECTILE)) || (damtype == DT_ACID) || - hasflag(wep->flags, F_ARMOURPIERCE)) { + hasflag(wep->flags, F_ARMOURPIERCE) || + rust ) { // ALL of damage reduction goes towards armour - actualdam = dam; } else { - switch (getskill(lf, SK_ARMOUR)) { - default: - case PR_INEPT: - actualdam = dam; - break; - case PR_NOVICE: actualdam = pctof(90, dam); break; - case PR_BEGINNER: actualdam = pctof(80, dam); break; - case PR_ADEPT: actualdam = pctof(70, dam); break; - case PR_SKILLED: actualdam = pctof(60, dam); break; - case PR_EXPERT: actualdam = pctof(50, dam); break; - case PR_MASTER: actualdam = pctof(40, dam); break; + // SOME of the damage reduction goes towards the armour + if (ar) { + actualdam -= rnd(0,ar); + limit(&actualdam, 0, NA); } - limit(&actualdam, 1, NA); } // modify for rust - rust = hasflag(armour->flags, F_RUSTED); if (rust) { int multiplier = 1; switch (rust->val[0]) { case R_RUSTY: multiplier = 2; case R_VRUSTY: - multiplier = 6; + multiplier = 3; case R_TRUSTY: - multiplier = 10; + multiplier = 4; } actualdam *= multiplier; } - // actually apply the damage to the armour damtaken = takedamage(armour,actualdam, damtype); } @@ -106,7 +107,7 @@ void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int * } -int attackcell(lifeform_t *lf, cell_t *c) { +int attackcell(lifeform_t *lf, cell_t *c, int force) { int validwep[MAXCANDIDATES]; object_t *wep[MAXCANDIDATES]; flag_t *damflag[MAXCANDIDATES], *f; @@ -128,7 +129,7 @@ int attackcell(lifeform_t *lf, cell_t *c) { // anyone there? if so just attack. if (c->lf) { - if (isplayer(lf) && !areenemies(lf,c->lf) && (getraceclass(c->lf) != RC_PLANT)) { + if (!force && isplayer(lf) && !areenemies(lf,c->lf) && (getraceclass(c->lf) != RC_PLANT)) { char ch; char victimname[BUFLEN]; char buf[BUFLEN]; @@ -158,10 +159,30 @@ int attackcell(lifeform_t *lf, cell_t *c) { // has an impassable object? o = hasobwithflag(c->obpile, F_IMPASSABLE); if (o) { + object_t *priwep; attacktype = AT_OB; attacktarget = o; + + priwep = getweapon(lf); + + // confirm ? + if (!force && isplayer(lf) && wepdullable(priwep) && (getiqname(getattr(player, A_IQ), NULL) >= IQ_SMART) ) { + char obname[BUFLEN],wepname[BUFLEN],buf[BUFLEN]; + char ch; + real_getobname(o, obname, o->amt, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE); + getobname(priwep, wepname, priwep->amt); + sprintf(buf, "Attacking %s might damage your %s. Proceed?", obname, noprefix(wepname)); + ch = askchar(buf, "yn","n", B_TRUE); + if (ch == 'n') { + // cancel. + return B_TRUE; + } + }; } else { // TODO: attack wall? + if (isplayer(lf)) { + msg("There is nothing there to attack!"); + } return B_TRUE; } } @@ -335,6 +356,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) char victimname[BUFLEN]; int fatal = B_FALSE; int deflected = B_FALSE; + int weppassthrough = B_FALSE; int firstisbackstab = B_FALSE; int hit = B_FALSE; int critical = 0; @@ -346,6 +368,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) int isunarmed = B_FALSE; int aidb = B_FALSE; + flag_t *f; if (lfhasflag(lf, F_DEBUG)) { @@ -393,11 +416,42 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) return B_FALSE; } } + + + for (f = lf->flags->first ; f ; f = f->next) { + // ie. you have been made noncorporeal + if ((f->id == F_NONCORPOREAL) && (f->lifetime != FROMRACE)) { + if (isplayer(lf)) { + msg("Your attack passes straight through %s.", victimname); + } else if (cansee(player, lf)) { + msg("%s%s attack passes straight through %s!", attackername, getpossessive(attackername), victimname); + } + taketime(lf, getattackspeed(lf)); + return B_FALSE; + } + } // did you hit? ndam = 0; + + + hit = rolltohit(lf, victim, wep, &critical); + // weapon passing through ghosts etc? + if (hit) { + if (lfhasflag(victim, F_NONCORPOREAL) && + !lfhasflag(lf, F_NONCORPOREAL) ) { + // using a magical or blessed weapon? if so you're ok. + if (wep && (ismagical(wep) || isblessed(wep)) ) { + } else { + weppassthrough = B_TRUE; + hit = B_FALSE; + ndam = 0; + } + } + } + // deflection? if (hit) { object_t *dwep; @@ -469,6 +523,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { dam[0] = (int)((float)dam[0] * getstrdammod(lf)); } + + // modify for size + modifyforsize(&dam[0], lf, victim, 5, M_PCT); + // backstab? if ((damtype[0] == DT_PIERCE) && // using a stabbing weapon getskill(lf, SK_BACKSTAB) && // able to backstab @@ -519,7 +577,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (ndam > 0) { flag_t *f; for (i = 0; i < ndam; i++) { - int reduceamt; + int reduceamt = 0; int backstab = B_FALSE; flag_t *rust; @@ -686,8 +744,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } // end foreach damtype - // special weapon effects - wepeffects(wep->flags, victim->cell, damflag, dam[0]); + // special weapon effects, as long as you're not doing a heavy blow + if (!lfhasflag(lf, F_HEAVYBLOW)) { + wepeffects(wep->flags, victim->cell, damflag, dam[0]); + } // other effects if (!isdead(victim)) { @@ -796,7 +856,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } else { // miss! if (aidb) dblog(".oO { i missed! }"); // announce it - if (deflected) { + if (weppassthrough) { + if (cansee(player, lf)) { + msg("%s%s attack passes straight through %s!", attackername, getpossessive(attackername), victimname); + } + } else if (deflected) { if (cansee(player, lf)) { msg("%s deflect%s %s%s attack.", victimname, isplayer(victim) ? "" : "s",attackername, getpossessive(attackername)); } @@ -982,8 +1046,10 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { } // end foreach damtype - // special weapon effects - wepeffects(wep->flags, obloc, damflag, dam[0]); + // special weapon effects, as long as you're not doing a heavy blow + if (!lfhasflag(lf, F_HEAVYBLOW)) { + wepeffects(wep->flags, obloc, damflag, dam[0]); + } if (isunarmed) { // touch effects @@ -991,14 +1057,9 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { } else { // weapon gets damaged ? if (wep && (ndam > 0)) { - switch (damtype[0]) { - case DT_PIERCE: - case DT_SLASH: - // weapon gets duller - if (rnd(1,2)) makeduller(wep, 1); - break; - default: - break; + if (wepdullable(wep)) { + // weapon gets duller + if (rnd(1,2)) makeduller(wep, 1); } } } @@ -1630,79 +1691,56 @@ int isphysicaldam(enum DAMTYPE damtype) { return B_FALSE; } -// returns true if we hit -int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) { - int acc,ev; - int gothit; +// 'howmuch' is the numerical amount to adjust 'val' by for every size bracket +// difference. +// +// if lf is bigger than victim, ADD howmuch. +// if lf is smaller than victim, SUBTRACT howmuch. +void modifyforsize(int *val, lifeform_t *lf, lifeform_t *victim, int howmuch, enum MODTYPE how) { enum LFSIZE szlf,szvictim; - enum SKILLLEVEL slev; - int myroll; - if (critical) { - *critical = 0; - } + assert(val); - acc = getlfaccuracy(lf, wep); - if (isprone(victim)) { - acc += 30; - } - - // remember lore about victim... - slev = getlorelevel(lf, victim->race->raceclass->id); - - // modify for defender's evasion - if (isprone(victim)) { - ev = 0; - } else { - ev = getevasion(victim); - } - - acc -= ev; - - // special case - if (lfhasflag(victim, F_NONCORPOREAL) && - !lfhasflag(lf, F_NONCORPOREAL) ) { - - // using a magical or blessed weapon? - if (wep && (ismagical(wep) || isblessed(wep)) ) { - } else { - return B_FALSE; // automatic miss - } - } - - // size difference szlf = getlfsize(lf); szvictim = getlfsize(victim); if (szvictim < szlf) { // if defender is smaller... - // -7% per size difference - acc -= (7 * (szlf - szvictim)); + if (how == M_VAL) { + // +howmuch per size difference + *val += (howmuch * (szlf - szvictim)); + } else { + // +(howmuch*sizediff)% of original value + *val += (pctof(howmuch * (szlf - szvictim), *val)); + } } else if (szvictim > szlf) { // if defender is bigger... - // +7% per size difference - acc += (7 * (szvictim - szlf)); + if (how == M_VAL) { + // -howmuch per size difference + *val -= (howmuch * (szvictim - szlf)); + } else { + // +(howmuch*sizediff)% of original value + *val -= (pctof(howmuch * (szlf - szvictim), *val)); + } } +} + +// returns true if we hit +int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) { + int acc,ev; + int gothit; + enum SKILLLEVEL slev; + int myroll; + flag_t *f; + - // modify if we can't see the victim - if (!cansee(lf, victim)) { - acc -= 50; - } - - // metal weapon versus magnetic shield? - if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) { - acc -= 45; - } - - // victim immobile or asleep? - if (isimmobile(victim) || lfhasflag(victim, F_EATING)) { - acc += 50; - } - - // base 5% critical chance + // base 5% critical chance - check this first. if (critical) { int critroll; critroll = rnd(1,100); + // default + *critical = 0; + // modify for lore if (slev != PR_INEPT) { myroll += (slev*5); // ie. up to 30% bonus @@ -1712,25 +1750,70 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) if (critroll >= 95) *critical = 1; } - limit(&acc, 0, 100); - - //if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc); - myroll = rnd(1,100); - if (slev != PR_INEPT) { - myroll += (slev*10); - } - - // modify for lore - if (myroll <= acc) { + f = lfhasflag(lf, F_TRUESTRIKE); + if (f) { + if (f->val[0] > 1) { + f->val[0]--; + } else { + killflag(f); + } + gothit = B_TRUE; + } else if (critical) { gothit = B_TRUE; } else { - if (critical && *critical) { - // turn a miss into a hit - gothit = B_TRUE; - } else { - gothit = B_FALSE; - } + // actually roll... + acc = getlfaccuracy(lf, wep); + + // size difference (penalty for attacking smaller ones) + modifyforsize(&acc, lf, victim, -5, M_VAL); + // easier to hit victims who are prone. + if (isprone(victim)) { + acc += 30; + } + + // remember lore about victim... + slev = getlorelevel(lf, victim->race->raceclass->id); + + // modify for defender's evasion + if (isprone(victim) || !cansee(victim, lf)) { + ev = 0; + } else { + ev = getevasion(victim); + } + + acc -= ev; + + + // modify if we can't see the victim + if (!cansee(lf, victim)) { + acc -= 50; + } + + // metal weapon versus magnetic shield? + if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) { + acc -= 45; + } + + // victim immobile or asleep? + if (isimmobile(victim) || lfhasflag(victim, F_EATING)) { + acc += 50; + } + + + limit(&acc, 0, 100); + + //if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc); + + myroll = rnd(1,100); + if (slev != PR_INEPT) { + myroll += (slev*10); + } + + // modify for lore + if (myroll <= acc) { + gothit = B_TRUE; + } } return gothit; diff --git a/attack.h b/attack.h index c57c5c4..627b392 100644 --- a/attack.h +++ b/attack.h @@ -2,7 +2,7 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype); void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int *dam, enum DAMTYPE damtype); -int attackcell(lifeform_t *lf, cell_t *c); +int attackcell(lifeform_t *lf, cell_t *c, int force); int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag); int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag); void confereffects(flagpile_t *fp, lifeform_t *victim); @@ -22,5 +22,6 @@ float getstrdammod(lifeform_t *lf); //obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag); int ismeleedam(enum DAMTYPE damtype); int isphysicaldam(enum DAMTYPE damtype); +void modifyforsize(int *val, lifeform_t *lf, lifeform_t *victim, int howmuch, enum MODTYPE how); int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical); void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam); diff --git a/defs.h b/defs.h index 3f70948..f5abad9 100644 --- a/defs.h +++ b/defs.h @@ -54,6 +54,7 @@ enum SKILL { SK_STEALTH, SK_SWIMMING, SK_TECHUSAGE, + SK_THIEVERY, SK_TRACKING, SK_TRAPS, SK_TWOWEAPON, @@ -87,7 +88,7 @@ enum SKILL { SK_SS_TRANSLOCATION, SK_SS_WILD, }; -#define MAXSKILLS 46 +#define MAXSKILLS 47 // proficiency levels enum SKILLLEVEL { @@ -240,6 +241,11 @@ enum SENSE { // it will take to go from 'normal' to 'hungry' etc #define HUNGERCONST 200 +enum MODTYPE { + M_PCT, + M_VAL, +}; + // LIMITS @@ -610,8 +616,10 @@ enum RACECLASS { enum RACE { R_NONE, R_RANDOM, - R_HUMAN, + // unique monstesr + R_JAILER, // human monsters + R_HUMAN, R_BANDIT, // monsters R_BEHOLDER, @@ -705,8 +713,9 @@ enum RACE { R_SKELETON, R_ZOMBIE, // special - R_GASCLOUD, R_DANCINGWEAPON, + R_FLOATINGDISC, + R_GASCLOUD, }; enum JOB { @@ -935,6 +944,7 @@ enum OBTYPE { OT_S_ICICLE, OT_S_WALLOFICE, // -- gravity + OT_S_TRUESTRIKE, OT_S_GRAVLOWER, OT_S_GRAVBOOST, OT_S_HASTE, @@ -1000,6 +1010,7 @@ enum OBTYPE { OT_S_WARPWOOD, OT_S_WATERJET, // -- summoning + OT_S_FLOATINGDISC, OT_S_CREATEMONSTER, OT_S_SUMMONWEAPON, // -- translocation @@ -1010,6 +1021,7 @@ enum OBTYPE { OT_S_TELEPORT, OT_S_TWIDDLE, // -- wild + OT_S_ALARM, OT_S_MANASPIKE, OT_S_DETONATE, OT_S_ENERGYBOLT, @@ -1033,6 +1045,7 @@ enum OBTYPE { OT_A_CRUSH, OT_A_JUMP, OT_A_RAGE, + OT_A_REPAIR, OT_A_SPRINT, OT_A_STINGACID, // need to define dam in f_canwill OT_A_SUCKBLOOD, @@ -1043,6 +1056,7 @@ enum OBTYPE { OT_A_INSPECT, OT_A_HURRICANESTRIKE, OT_A_POLYREVERT, + OT_A_STEAL, OT_A_WARCRY, // uses F_NOISETEXT -> N_WARCRY if it is there. // otherwise 'shouts a blood-curdling war cry' // wands @@ -1061,6 +1075,8 @@ enum OBTYPE { OT_WAND_SLOW, OT_WAND_WEAKNESS, OT_WAND_WONDER, + // tools - unique + OT_ORBDUNGEONEXIT, // tools OT_BLANKET, OT_BLINDFOLD, @@ -1467,6 +1483,8 @@ enum FLAG { F_HASBRAND, // has the object mod v0 (ie. OM_FLAMESTRIKE) F_HOLDCONFER, // gives flag v0+v1 when carried. v2 specifies if it must be id'd. F_EQUIPCONFER, // gives flag v0+v1 when weilded/worn. v2 specifies if it must be id'd. + F_ACTIVATEPREFIX, // when activated, prefix this objects name with + // text F_ACTIVATECONFER, // gives flag v0+v1 when activated. v2 specifies if it must be id'd. F_CRITKNOCKDOWN, // lf knocks down victims on a critical hit @@ -1771,6 +1789,8 @@ enum FLAG { F_NOFLEE, // lf will not run away F_ATTACKRANGE, // v0/v1 = min/max celldist to stay away // from f_targetlf (ie. lf we are attacking) + F_FOLLOWRANGE, // v0/v1 = min/max celldist to stay away + // from pet's master F_TARGETLF, // lf will attack lfid v0. lastknown x/y is v1/v2 // optional text is last known movement dir. F_IGNORECELL, // won't accept targetcells of v0=x v1=y @@ -1931,6 +1951,7 @@ enum FLAG { F_RISEASGHOST, // become a ghost when you die. F_SEEINDARK, // nightvis range is val0 F_TREMORSENSE, // doesn't need eyes to see, can see in dark with v0 + F_TRUESTRIKE, // your attacks ALWAYS hit. turnsleft=v0 F_SEEINVIS, // can see invisible things F_STABILITY, // doesn't slip over F_STENCH, // creatures within v0 gain f_nauseated = v1 diff --git a/flag.c b/flag.c index a9f13e6..cb6ef08 100644 --- a/flag.c +++ b/flag.c @@ -36,6 +36,12 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, known = B_KNOWN; } + if (id == F_INTERRUPTED) { + if (fp->owner == player) { + dblog("player got interrupted"); + } + } + if ((id == F_POISONED) && isimmuneto(fp, DT_POISON)) { return NULL; } @@ -186,7 +192,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, float pct; switch (f->id) { case F_ASLEEP: - stopallspells(f->pile->owner); + stopallspellsexcept(f->pile->owner, OT_S_ALARM, OT_NONE); break; case F_NONCORPOREAL: killflagsofid(f->pile->owner->flags, F_BEINGSTONED); diff --git a/io.c b/io.c index 4738bef..1464feb 100644 --- a/io.c +++ b/io.c @@ -507,7 +507,7 @@ char askchar(char *prompt, char *validchars, char *def, int showchars) { return ch; } -cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail) { +cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail) { static int startlf = -1; int finished = B_FALSE; int moved = B_FALSE; @@ -849,7 +849,11 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange, wclear(msgwin); - mvwprintw(msgwin, 0, 0, "%s",buf); + if (subprompt) { + mvwprintw(msgwin, 0, 0, "%s%s", subprompt, buf); + } else { + mvwprintw(msgwin, 0, 0, "%s",buf); + } wrefresh(msgwin); // show our line of fire @@ -1443,6 +1447,16 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_TRUESTRIKE: + if (isplayer(lf)) { // don't know if monsters get it + if (f->val[0] > 1) { + msg("Your next %d attacks will automatically hit.", f->val[0]); + } else { + msg("Your next attack will automatically hit."); + } + donesomething = B_TRUE; + } + break; case F_WINDSHIELD: if (isplayer(lf)) { msg("You are surrounded by a whirling cyclone!"); @@ -1928,6 +1942,9 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_TRUESTRIKE: + // no message when you lose this. + break; case F_WINDSHIELD: if (isplayer(lf) || cansee(player, lf)) { msg("%s%s cyclonic shield vanishes.", lfname, getpossessive(lfname)); @@ -2804,48 +2821,105 @@ void describeob(object_t *o) { flag_t *f; int obknown; int i; + int throwrange; cls(); obknown = isknown(o); // title getobname(o, buf,o->amt); + wattron(mainwin, A_BOLD); mvwprintw(mainwin, 0, 0, buf); + wattroff(mainwin, A_BOLD); + // description getobdesc(o, buf); mvwprintw(mainwin, 2, 0, buf); + // append masterwork etc onto description + f = hasflag(o->flags, F_MASTERWORK); + if (f && f->known) { + wprintw(mainwin, " It is extremely well crafted."); + } + f = hasflag(o->flags, F_SHODDY); + if (f && f->known) { + wprintw(mainwin, " It is very poorly crafted."); + } - // properties + + // weight y = 4; - if (o->material->id != MT_FOOD) { - mvwprintw(mainwin, y, 0, "%s made from %s.",(o->amt == 1) ? "It is" : "They are", o->material->name); y++; + if (o->material->id == MT_FOOD) { + sprintf(buf, "%s food product%s, ",(o->amt == 1) ? "It is a" : "They are", + (o->amt == 1) ? "" : "s"); + } else { + sprintf(buf, "%s made from %s, ",(o->amt == 1) ? "It is" : "They are", o->material->name); + } + + if (o->amt == 1) { + char wbuf[BUFLEN]; + getweighttext(getobweight(o), wbuf); + sprintf(buf2, "and weighs %s.",wbuf); + strcat(buf, buf2); + } else { + char wbuf[BUFLEN]; + char wbuf2[BUFLEN]; + getweighttext(getobweight(o), wbuf); + getweighttext(getobunitweight(o), wbuf2); + sprintf(buf2, "and weigh %s (%s each).",wbuf, wbuf2); + strcat(buf, buf2); + } + mvwprintw(mainwin, y, 0, "%s",buf); + y++; + + throwrange = getmaxthrowrange(player, o); + if (throwrange >= 1) { + mvwprintw(mainwin, y, 0, " You could throw %s %d metres.",(o->amt == 1) ? "it" : "one", throwrange); + } else { + mvwprintw(mainwin, y, 0, " It is too heavy for you to throw."); + } + y++; + + f = hasflag(o->flags, F_THROWMISSILE); + if (f) { + if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT)) { + int dam; + dam = getthrowdam(o); + mvwprintw(mainwin, y, 0, " %s good for throwing [base damage %d].",(o->amt == 1) ? "It is" : "They are", dam); + } else { + mvwprintw(mainwin, y, 0, " %s good for throwing.", (o->amt == 1) ? "It is" : "They are"); + } + y++; } if (isedible(o)) { int basenutr; basenutr = getnutritionbase(o); - mvwprintw(mainwin, y, 0, "%s edible.",(o->amt == 1) ? "It is" : "They are"); y++; - mvwprintw(mainwin, y, 0, "%s %s.",(o->amt == 1) ? "It is" : "They are each", getfillingname(basenutr)); y++; + mvwprintw(mainwin, y, 0, "%s edible, and %s %s.", + (o->amt == 1) ? "It is" : "They are", + (o->amt == 1) ? "is" : "are each", + getfillingname(basenutr)); + y++; + if (hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL)) { + // don't show "it will rot" if it's already rotten (and you know this) + if (isrotting(o) && ( (getiqname(getattr(player, A_IQ), NULL) >= IQ_SMART) || getskill(player, SK_COOKING)) ) { + } else { + mvwprintw(mainwin, y, 0, "%s will decay and go bad over time.", (o->amt == 1) ? "It" : "They" ); + y++; + } + } } - if (o->amt == 1) { - getweighttext(getobweight(o), buf); - mvwprintw(mainwin, y, 0, "It weighs %s.",buf); - } else { - getweighttext(getobweight(o), buf); - getweighttext(getobunitweight(o), buf2); - mvwprintw(mainwin, y, 0, "They weigh %s (%s each).",buf, buf2); - } - y++; - // weapons? if (o->type->obclass->id == OC_WEAPON) { int delay; + mvwprintw(mainwin, y, 0, "It is a weapon."); + y++; if (hasflag(o->flags, F_DAM)) { int bonus = 0; + f = hasflag(o->flags, F_BONUS); if (f && f->known) { // only tell player about bonuses if they are known.! @@ -2865,9 +2939,9 @@ void describeob(object_t *o) { if (maxdam < 0) maxdam = 0; if (mindam == maxdam) { - sprintf(buf, "It inflicts %d %s damage",maxdam, getdamname(damtype)); + sprintf(buf, " It inflicts %d %s damage",maxdam, getdamname(damtype)); } else { - sprintf(buf, "It inflicts %d-%d %s damage",mindam,maxdam, getdamname(damtype)); + sprintf(buf, " It inflicts %d-%d %s damage",mindam,maxdam, getdamname(damtype)); } //dicetotext(f->val[0], f->val[1], f->val[2], NULL, NULL, dicebuf, NULL); @@ -2879,17 +2953,17 @@ void describeob(object_t *o) { mvwprintw(mainwin, y, 0, "%s",buf); y++; } - } - // other extra damage or effects? - f = hasflag(o->flags, F_ONFIRE); - if (f) { - if (f->text) { - mvwprintw(mainwin, y, 0, " It also inflicts %s extra burning damage.", f->text); - } else { - mvwprintw(mainwin, y, 0, " It also inflicts extra burning damage."); + // other extra damage or effects? + f = hasflag(o->flags, F_ONFIRE); + if (f) { + if (f->text) { + mvwprintw(mainwin, y, 0, " It also inflicts %s extra burning damage.", f->text); + } else { + mvwprintw(mainwin, y, 0, " It also inflicts extra burning damage."); + } + y++; } - y++; } delay = 100; @@ -2897,38 +2971,61 @@ void describeob(object_t *o) { if (f) { delay = f->val[0]; } - mvwprintw(mainwin, y, 0, "Its attack delay is %d%%.",delay - 100); + mvwprintw(mainwin, y, 0, " Its attack delay is %d%%.",delay - 100); y++; f = hasflag(o->flags, F_ACCURACY); if (f) { int acc; acc = getobaccuracy(o, NULL); - mvwprintw(mainwin, y, 0, "It has %s accuracy.",getaccuracyname(acc)); + mvwprintw(mainwin, y, 0, " It has %s accuracy.",getaccuracyname(acc)); y++; } f = hasflag(o->flags, F_DISARMATTACK); if (f) { - mvwprintw(mainwin, y, 0, "A skilled weilder can disarm opponents with it."); + mvwprintw(mainwin, y, 0, " A skilled weilder can disarm opponents with it."); y++; } f = hasflag(o->flags, F_TRIPATTACK); if (f) { - mvwprintw(mainwin, y, 0, "A skilled weilder can trip opponents with it."); + mvwprintw(mainwin, y, 0, " A skilled weilder can trip opponents with it."); y++; } + f = hasflag(o->flags, F_ARMOURPIERCE); + if (f && f->known) { + mvwprintw(mainwin, y, 0, " Armour will not reduce %s damage.",(o->amt == 1) ? "its" : "their"); + y++; + } + } // damage if (isarmour(o)) { f = hasflag(o->flags, F_GOESON); if (f) { - mvwprintw(mainwin, y, 0, "It is worn %s your %s.",getbodypartequipname(f->val[0]), getbodypartname(f->val[0])); - y++; + sprintf(buf, "It is worn %s your %s, ",getbodypartequipname(f->val[0]), getbodypartname(f->val[0])); + } else { + strcpy(buf, ""); } f = hasflag(o->flags, F_ARMOURRATING); if (f) { - mvwprintw(mainwin, y, 0, "It has an Armour Rating of %d.",f->val[0] + getobbonus(o)); + if (strlen(buf)) { + sprintf(buf2, "and has an Armour Rating of %d.",f->val[0] + getobbonus(o)); + strcat(buf, buf2); + } else { + sprintf(buf, "It has an Armour Rating of %d.",f->val[0] + getobbonus(o)); + } + } else { + if (strlen(buf)) { + sprintf(buf2, "and provides no protection."); + strcat(buf, buf2); + } + } + mvwprintw(mainwin, y, 0, "%s",buf); + y++; + f = hasflag(o->flags, F_SCARY); + if (f) { + mvwprintw(mainwin, y, 0, " It may unnerve others when worn."); y++; } } @@ -2946,36 +3043,12 @@ void describeob(object_t *o) { } } - - f = hasflag(o->flags, F_THROWMISSILE); - if (f) { - if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT)) { - int dam; - dam = getthrowdam(o); - mvwprintw(mainwin, y, 0, "%s good for throwing [base damage %d].",(o->amt == 1) ? "It is" : "They are", dam); - } else { - mvwprintw(mainwin, y, 0, "%s good for throwing.", (o->amt == 1) ? "It is" : "They are"); - } - y++; - } - - f = hasflag(o->flags, F_ARMOURPIERCE); - if (f && f->known) { - mvwprintw(mainwin, y, 0, "Armour will not reduce %s damage.",(o->amt == 1) ? "its" : "their"); - y++; - } - f = hasflag(o->flags, F_PICKLOCKS); if (f) { mvwprintw(mainwin, y, 0, "You can use it to pick locks."); y++; } - f = hasflag(o->flags, F_SCARY); - if (f) { - mvwprintw(mainwin, y, 0, "It may unnerve others when worn."); - y++; - } // skip line y++; @@ -3061,9 +3134,8 @@ void describeob(object_t *o) { y++; } - // been made invulnerable ? - if (hasflag(o->type->flags, F_DAMAGABLE) && !hasflag(o->flags, F_DAMAGABLE)) { + if (hasflag(o->type->flags, F_INVULNERABLE) && !hasflag(o->flags, F_DAMAGABLE)) { mvwprintw(mainwin, y, 0, "It has been rendered invulnerable to most damage."); y++; } @@ -3081,16 +3153,6 @@ void describeob(object_t *o) { // physical properties - f = hasflag(o->flags, F_MASTERWORK); - if (f && f->known) { - mvwprintw(mainwin, y, 0, "It is extremely well crafted."); - y++; - } - f = hasflag(o->flags, F_SHODDY); - if (f && f->known) { - mvwprintw(mainwin, y, 0, "It is very poorly crafted."); - y++; - } f = hasflag(o->flags, F_ONFIRE); if (f) { @@ -3311,6 +3373,9 @@ void describeob(object_t *o) { case F_TREMORSENSE: mvwprintw(mainwin, y, 0, "%s allows you to 'see' by sensing vibrations around you.", buf); y++; break; + case F_TRUESTRIKE: + mvwprintw(mainwin, y, 0, "%s makes your attacks automatically hit.", buf); y++; + break; case F_WINDSHIELD: mvwprintw(mainwin, y, 0, "%s will surround you with a cyclonic shield.", buf); y++; break; @@ -3350,7 +3415,6 @@ void describeob(object_t *o) { y++; } - // requirements i = B_FALSE; for (f = o->flags->first ; f ; f = f->next) { @@ -3499,10 +3563,7 @@ void doattackcell(char dirch) { f->val[2] = dirch; } - if (attackcell(player, c)) { - // failed - msg("There is nothing there to attack!"); - } + attackcell(player, c, B_FALSE); } } @@ -3561,9 +3622,11 @@ void docomms(void) { char buf[BUFLEN]; char lfname[BUFLEN]; char ch; + enum IQBRACKET iqb; flag_t *f; - where = askcoords("Talk to who?", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE); + + where = askcoords("Talk to who?", "Talk->", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE); if (where && where->lf && cansee(player, where->lf)) { lf = where->lf; } @@ -3576,21 +3639,32 @@ void docomms(void) { sprintf(buf, "What will you say to %s?",lfname); initprompt(&prompt, buf); prompt.maycancel = B_TRUE; + + iqb = getiqname(getattr(lf, A_IQ), NULL); + // are they friendly? if (ispetof(lf, player)) { - addchoice(&prompt, 'a', "Attack something", NULL, NULL); + if (iqb >= IQ_ANIMAL) { + addchoice(&prompt, 'a', "Attack something", NULL, NULL); + } + if (!isadjacent(lf->cell, player->cell)) { addchoice(&prompt, 'c', "Come here", NULL, NULL); } + + addchoice(&prompt, 'g', "Go somewhere", NULL, NULL); + if (isadjacent(lf->cell, player->cell) && !lfhasflag(lf, F_NOPACK)) { addchoice(&prompt, 't', "Trade items with me", NULL, NULL); } - f = isresting(lf); - if (f) { - addchoice(&prompt, 'r', "Stop resting.", NULL, NULL); - } else { - addchoice(&prompt, 'r', "Rest until you are healed.", NULL, NULL); + if (iqb >= IQ_ANIMAL) { + f = isresting(lf); + if (f) { + addchoice(&prompt, 'r', "Stop resting.", NULL, NULL); + } else { + addchoice(&prompt, 'r', "Rest until you are healed.", NULL, NULL); + } } } else { addchoice(&prompt, 'y', "Yeeeeeaaaargh!", NULL, NULL); @@ -3602,10 +3676,12 @@ void docomms(void) { cell_t *c; lifeform_t *lf2 = NULL; char lfname2[BUFLEN]; + char buf2[BUFLEN]; case 'a': sprintf(buf, "Tell %s to attack who?",lfname); - c = askcoords(buf, TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE); - if (c && c->lf && cansee(player, c->lf)) { + sprintf(buf2, "%s->Attack->",lfname); + c = askcoords(buf, buf2, TT_MONSTER, lf, UNLIMITED, LOF_DONTNEED, B_FALSE); + if (c && c->lf && cansee(lf, c->lf)) { lf2 = c->lf; } @@ -3629,6 +3705,18 @@ void docomms(void) { aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME); } break; + case 'g': + sprintf(buf, "Tell %s to go where?",lfname); + sprintf(buf2, "%s->Goto->",lfname); + c = askcoords(buf, buf2, TT_NONE, lf, UNLIMITED, LOF_DONTNEED, B_FALSE); + if (c && cellwalkable(lf, c, NULL) && cansee(lf, c->lf)) { + } else { + msg("Cancelled."); + return; + } + msg("You say \"Go over there!\" to %s.", lfname); + aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME); + break; case 'n': msg("Cancelled."); return; @@ -4549,7 +4637,7 @@ void doenter(lifeform_t *lf) { } void doexplain(char *question) { - askcoords(question, TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE); + askcoords(question, "", TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE); restoregamewindows(); msg("Done."); } @@ -4901,7 +4989,7 @@ void dorest(void) { void doselguntarget(void) { object_t *gun; cell_t *where; - char buf[BUFLEN]; + char buf[BUFLEN],buf2[BUFLEN]; char gunname[BUFLEN]; gun = getfirearm(player); if (!gun) { @@ -4911,7 +4999,8 @@ void doselguntarget(void) { getobname(gun, gunname, 1); sprintf(buf, "Aim %s where?",gunname); - where = askcoords(buf, TT_MONSTER, player, UNLIMITED, LOF_NEED, B_TRUE); + sprintf(buf2, "%s->Target->",gunname); + where = askcoords(buf, buf2, TT_MONSTER, player, UNLIMITED, LOF_NEED, B_TRUE); if (where) { if (where->lf && haslof(player->cell, where, LOF_NEED, NULL)) { setguntarget(player, where->lf); @@ -4968,6 +5057,7 @@ void dothrow(obpile_t *op) { o = askobject(op, "Throw what", NULL, AO_NONE); if (o) { int maxdist; + char subprompt[BUFLEN]; cell_t *where; flag_t *f; getobname(o, buf, 1); @@ -4983,7 +5073,8 @@ void dothrow(obpile_t *op) { // ask where to throw it sprintf(buf2, "Throw %s where?",buf); - where = askcoords(buf2, TT_MONSTER, player, maxdist, LOF_NEED, B_TRUE); + sprintf(subprompt, "%s->Throw->",buf); + where = askcoords(buf2, subprompt, TT_MONSTER, player, maxdist, LOF_NEED, B_TRUE); if (where) { cell_t *newwhere = NULL; @@ -8196,6 +8287,11 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s can 'see' by sensing vibrations around %s.", you(lf), you(lf)); y++; } + f = lfhasknownflag(lf, F_TREMORSENSE); + if (f) { + mvwprintw(mainwin, y, 0, "%s%s attacks will automatically hit.", you(lf), getpossessive(you(lf))); + y++; + } f = lfhasknownflag(lf, F_WINDSHIELD); if (f) { mvwprintw(mainwin, y, 0, "%s %s protected from missiles by a cyclonic shield", you(lf), is(lf)); @@ -8326,9 +8422,6 @@ void tombstone(lifeform_t *lf) { int y; char *p, *dummy; - - gamemode = GM_GAMEOVER; - getplayernamefull(pname); // clear screen diff --git a/io.h b/io.h index 85876e7..b09d320 100644 --- a/io.h +++ b/io.h @@ -21,7 +21,7 @@ object_t *askobjectwithflag(obpile_t *op, char *title, int *count, long opts, en object_t *doaskobject(obpile_t *op, char *title, int *count, int forpickup, int showpoints, long opts, ...); int askobjectmulti(obpile_t *op, char *prompt, long opts); char askchar(char *prompt, char *validchars, char *def, int showchars); -cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail); +cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail); char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def); vault_t *askvault(char *prompttext); void centre(WINDOW *win, int y, char *format, ... ); diff --git a/lf.c b/lf.c index 7073778..ec0b4c9 100644 --- a/lf.c +++ b/lf.c @@ -1912,6 +1912,7 @@ int eat(lifeform_t *lf, object_t *o) { int fullyeaten = B_FALSE; flag_t *alreadyeating; enum HUNGER hlev,posthlev; + int stopeating = B_FALSE; if (hasflag(o->flags, F_DRINKABLE)) { drinking = B_TRUE; @@ -2139,20 +2140,16 @@ int eat(lifeform_t *lf, object_t *o) { } taketime(lf, amt); - if (fullyeaten) { - // remove object - removeob(o, 1); - } else { - // mark how much we ate - f = hasflag(o->flags, F_EDIBLE); - if (f) { - f->val[2] = (int)(startpcteaten + pcteaten); - } + // special cases even if not fully eaten + if (hasflagval(o->flags, F_CORPSEOF, R_DOGBLINK, NA, NA, NULL)) { + // blink! + dospelleffects(lf, OT_S_BLINK, 1, lf, NULL, NULL, B_UNCURSED, NULL, B_TRUE); + + stopeating = B_TRUE; } // stop eating if we are full - if (!fullyeaten && (posthlev != hlev) && (posthlev <= H_FULL)) { - int stopeating = B_FALSE; + if (!stopeating && !fullyeaten && (posthlev != hlev) && (posthlev <= H_FULL)) { if (isplayer(lf)) { int ch; more(); @@ -2163,8 +2160,19 @@ int eat(lifeform_t *lf, object_t *o) { } else { stopeating = B_TRUE; } - if (stopeating) { - killflagsofid(lf->flags, F_EATING); + } + if (stopeating) { + killflagsofid(lf->flags, F_EATING); + } + + if (fullyeaten) { + // remove object + removeob(o, 1); + } else { + // mark how much we ate + f = hasflag(o->flags, F_EDIBLE); + if (f) { + f->val[2] = (int)(startpcteaten + pcteaten); } } @@ -2187,9 +2195,10 @@ void enhancerandomskill(lifeform_t *lf) { nposs++; } } - sel = rnd(0,nposs-1); - - giveskill(lf, poss[sel]); + if (nposs > 0) { + sel = rnd(0,nposs-1); + giveskill(lf, poss[sel]); + } } void enhanceskills(lifeform_t *lf) { @@ -2657,6 +2666,11 @@ int flee(lifeform_t *lf) { flag_t *f, *nextf; lifeform_t *fleefrom = NULL; + // mindless? + if (getiqname(getattr(lf, A_IQ), NULL) == IQ_MINDLESS) { + return B_FALSE; + } + // are we fleeing? for (f = lf->flags->first ; f ; f = nextf) { nextf = f->next; @@ -3414,6 +3428,8 @@ int getevasion(lifeform_t *lf) { if (ev < 0) ev = 0; // modify for blindness + // PLUS if you're blind, your evasion is 0 anyway for anyone + // attacking you. if (isblind(lf)) { ev -= 15; } @@ -4336,15 +4352,19 @@ char *getlfname(lifeform_t *lf, char *buf) { char *real_getlfname(lifeform_t *lf, char *buf, int usevis) { char descstring[BUFLEN]; char jobstring[BUFLEN]; - char the[5]; + char the[6]; job_t *j; flag_t *f; // 'the' or 'your' ? - if (ispetof(lf, player)) { - strcpy(the, "your"); + if (lfhasflag(lf, F_UNIQUE)) { + strcpy(the, ""); } else { - strcpy(the, "the"); + if (ispetof(lf, player)) { + strcpy(the, "your "); + } else { + strcpy(the, "the "); + } } // construct description string @@ -4379,9 +4399,9 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis) { if (wep) { char obname[BUFLEN]; real_getobname(wep, obname, 1, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_FALSE); - sprintf(buf, "%s %s%s",the,descstring,noprefix(obname)); + sprintf(buf, "%s%s%s",the,descstring,noprefix(obname)); } else { - sprintf(buf, "%s %s%s%s",the,descstring,lf->race->name,jobstring); + sprintf(buf, "%s%s%s%s",the,descstring,lf->race->name,jobstring); } } else { char zombiestring[BUFLEN]; @@ -4392,7 +4412,7 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis) { sprintf(zombiestring, " %s", f->text); } - sprintf(buf, "%s %s%s%s%s",the,descstring,lf->race->name,jobstring,zombiestring); + sprintf(buf, "%s%s%s%s%s",the,descstring,lf->race->name,jobstring,zombiestring); } } } @@ -4408,22 +4428,28 @@ char *real_getlfnamea(lifeform_t *lf, char *buf, int usevis) { sprintf(buf, "you"); } else { char buf2[BUFLEN]; - char the[5]; + char the[6]; real_getlfname(lf, buf2, usevis); - - if (ispetof(lf, player)) { - strcpy(the, "your"); + if (lfhasflag(lf, F_UNIQUE)) { + strcpy(the, ""); } else { - if (isvowel(lf->race->name[0])) { - strcpy(the, "an"); + if (ispetof(lf, player)) { + strcpy(the, "your "); } else { - strcpy(the, "a"); + if (isvowel(lf->race->name[0])) { + strcpy(the, "an "); + } else { + strcpy(the, "a "); + } } } - sprintf(buf, "%s %s", the, noprefix(buf2)); + + + + sprintf(buf, "%s%s", the, noprefix(buf2)); } return buf; } @@ -5127,8 +5153,14 @@ void getwantdistance(lifeform_t *lf, int *min, int *max, int attacking) { *max = f->val[1]; } } else { + // default - stay with 1-3 cells *min = 1; *max = 3; + f = lfhasflag(lf, F_FOLLOWRANGE); + if (f) { + *min = f->val[0]; + *max = f->val[1]; + } } } @@ -5150,8 +5182,8 @@ object_t *getweapon(lifeform_t *lf) { long getxpforlev(int level) { long needxp = 0; // 2.8 - float multiplier = 10; - float constant = 3.1; + float multiplier = 13; + float constant = 2.8; // no xp needed for level 1 /* @@ -5427,11 +5459,14 @@ int giveskill(lifeform_t *lf, enum SKILL id) { if (id == SK_ATHLETICS) { newf = addflag(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); newf->lifetime = FROMJOB; - } else if (id == SK_ATHLETICS) { + } else if (id == SK_COOKING) { makeknown(OT_POT_WATER); } else if (id == SK_LORE_ARCANA) { newf = addflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL); newf->lifetime = FROMJOB; + } else if (id == SK_THIEVERY) { + newf = addflag(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL); + newf->lifetime = FROMJOB; } else if (id == SK_TRAPS) { newf = addflag(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL); newf->lifetime = FROMJOB; @@ -5447,6 +5482,11 @@ int giveskill(lifeform_t *lf, enum SKILL id) { newf = addflag(lf->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL); newf->lifetime = FROMJOB; } + } else if (id == SK_ARMOUR) { + if (f->val[1] == PR_SKILLED) { + newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL); + newf->lifetime = FROMJOB; + } } else if (id == SK_CARTOGRAPHY) { if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { if (f->val[1] == PR_NOVICE) { @@ -5548,6 +5588,20 @@ int giveskill(lifeform_t *lf, enum SKILL id) { } } } + } else if (id == SK_THIEVERY) { + if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { + if (f->val[1] == PR_BEGINNER) { + msg("Your accuracy penalty when stealing is reduced."); + } else if (f->val[1] == PR_ADEPT) { + msg("You can now steal specific items."); + } else if (f->val[1] == PR_SKILLED) { + msg("You can now steal heavy items."); + } else if (f->val[1] == PR_EXPERT) { + msg("You can now steal multiple items."); + } else if (f->val[1] == PR_MASTER) { + msg("You can now steal equipped items."); + } + } } else if (id == SK_TRACKING) { if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { if (f->val[1] == PR_NOVICE) { @@ -6612,6 +6666,7 @@ void initjobs(void) { addjob(J_PIRATE, "Pirate"); // stats + addflag(lastjob->flags, F_STARTATT, A_STR, NA, NA, "8-15"); addflag(lastjob->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_CON, CN_HEALTHY, NA, NULL); // abilities @@ -6643,6 +6698,8 @@ void initjobs(void) { 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_LORE_ARCANA, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_THIEVERY, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TRACKING, NA, NA, NULL); addjob(J_ROGUE, "Rogue"); @@ -6653,6 +6710,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "dagger"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "50-100 gold coins"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "5 lockpicks"); addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_BEGINNER, NA, NULL); @@ -6661,6 +6719,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SPOTHIDDEN, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_THIEVERY, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); @@ -6764,6 +6823,37 @@ void initrace(void) { addraceclass(RC_SLIME, "slime", "slimes", SK_NONE); addraceclass(RC_UNDEAD, "undead", "the undead", SK_LORE_UNDEAD); + // unique monsters + addrace(R_JAILER, "Jimbo", 110, '@', C_MAGENTA, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_UNIQUE, NA, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, NA, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 5, 2, NA, NULL); + //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, NA, NA, "1d4"); + addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "11-13"); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_STUPID, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, CN_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "50-100 gold coins"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "+2 halberd"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "gas mask"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "great armour"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "good armour"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "good armour"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "armour"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "dungeon exit orb"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "concealing powder"); + addflag(lastrace->flags, F_FLEEONHPPCT, 40, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_POLEARMS, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_ARMOUR, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, 2, 2, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_HURRICANESTRIKE, 2, 2, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_RAGE, 20, 20, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + // races / monsters addrace(R_HUMAN, "human", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); @@ -6784,7 +6874,6 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL); // TODO: humans start with a random job sometimes? addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); -// addflag(lastrace->flags, F_RESTHEALMPAMT, 1, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); // human monsters... @@ -7833,7 +7922,7 @@ void initrace(void) { addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, NULL); addflag(lastrace->flags, F_HITDICE, 1, 0, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -8104,6 +8193,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "0d1+4"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addrace(R_ANTS, "giant soldier ant", 25, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); @@ -8127,6 +8217,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_STINGACID, NA, NA, "dam:1d6+3;needgrab:1;"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "giant worker ant"); addrace(R_ANTLION, "giant antlion", 30, 'a', C_YELLOW, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_ANT; @@ -8149,6 +8240,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:2d4;"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars"); addrace(R_DOGBLINK, "blink dog", 35, 'd', C_YELLOW, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 8, NA, ""); @@ -8961,6 +9053,31 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + + addrace(R_FLOATINGDISC, "floating disc", 0, '_', C_BOLDGREEN, MT_METAL, RC_OTHER); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); + addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, 1, NA, NA, ""); + addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); + addflag(lastrace->flags, F_FOLLOWRANGE, 1, 1, NA, NULL); // stay right next to master + addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_BODY, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); } int isairborne(lifeform_t *lf) { @@ -9041,6 +9158,10 @@ int ischarmable(lifeform_t *lf) { reason = E_DRUNK; return B_FALSE; } + if (hasflag(lf->flags, F_UNIQUE)) { + reason = E_NOEFFECT; // generic error + return B_FALSE; + } return B_TRUE; } @@ -9759,7 +9880,11 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { // adjust for lifeform material //adjustdammaterial(amt, damtype, getlfmaterial(lf)); - if (*amt < 0) *amt = 0; + if (isdrunk(lf)) { + *amt -= rnd(0,3); + } + + limit(amt, 0, NA); } void makepeaceful(lifeform_t *who) { @@ -10790,15 +10915,23 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete if ((l != noisemaker) && (l->cell)) { int difficulty; + int lbonus; //if (canhear(l, c) && haslos(l, c)) { // listen check difficulty is based on sound distance vs max hearing distance difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20); - // listen bonus is the sound volume + // listen bonus is the sound volume + if (lfhasflag(l, F_ASLEEP)) { + lbonus = 0; + } else { + lbonus = volume; + } + + // skillcheck to hear this if (canhear(l, c) && (haslos(l, c) || - ((dist <= sounddist) && skillcheck(l, SC_LISTEN, difficulty, volume)))) { + ((dist <= sounddist) && skillcheck(l, SC_LISTEN, difficulty, lbonus)))) { flag_t *f; // announce? if (isplayer(l) && !lfhasflag(l, F_ASLEEP)) { @@ -10894,12 +11027,17 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete } killflag(f); } else { - // ie resting on purpose via 'r' + // ie resting on purpose via 'R' // only wake up if the sound if very close - if (getcelldist(c, l->cell) == 1) { + //if (getcelldist(c, l->cell) == 1) { + if (volume >= getcelldist(c, l->cell)) { // wake up! if (isplayer(l)) { - msg("A nearby noise awakens you!"); + char wakenoise[BUFLEN]; + strcpy(wakenoise, text); + wakenoise[strlen(wakenoise)-1] = '\0'; // omit punctuation + //msg("A nearby noise awakens you!"); + msg("The sound of %s awakens you!", wakenoise); rv = B_TRUE; } killflag(f); @@ -11959,7 +12097,7 @@ void setlastdam(lifeform_t *lf, char *buf) { } void initskills(void) { - addskill(SK_ARMOUR, "Armour", "Helps maintain armour, reducing evasion penalties and armour damage."); + addskill(SK_ARMOUR, "Armour", "Lets you repair armour, and reduces evasion penalties from armour."); addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery."); addskill(SK_BACKSTAB, "Backstab", "Lets you inflict massive damage with stabs when unseen."); addskill(SK_CARTOGRAPHY, "Cartography", "Your ability to create and interpret maps."); @@ -11975,6 +12113,7 @@ void initskills(void) { addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently."); addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water."); addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items."); + addskill(SK_THIEVERY, "Thievery", "Your ability to pick pockets and steal items."); addskill(SK_TRACKING, "Tracking", "Allows you to track enemies by their footprints."); addskill(SK_TRAPS, "Traps", "Affects your ability to locate and disarm traps."); addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once."); @@ -12504,6 +12643,38 @@ void stopsprinting(lifeform_t *lf) { } +// very much like addmonster(), but announce that it appears +// and make it worth zero xp. +lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, int randomjobsok, job_t *forcejob, int lifetime, int wantfriendly) { + lifeform_t *newlf = NULL; + char buf[BUFLEN]; + newlf = addmonster(c, rid, randomjobsok, 1, B_FALSE, NULL); + if (newlf) { + // assign job if required + if (forcejob) { + givejob(newlf, forcejob->id); + } + if (haslos(player, c)) { + //char *newbuf; + getlfnamea(newlf, buf); + capitalise(buf); + msg("%s appears!", buf); + } + // summoned + addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL); + if (wantfriendly) { + addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL); + if (areallies(player, caster)) { + makefriendly(newlf, PERMENANT); + } + } + // not worth any xp + killflagsofid(newlf->flags, F_XPVAL); + addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); + } + return newlf; +} + // if this object is ammo, and we are using a gun // with no ammo, then equip it. int testammo(lifeform_t *lf, object_t *o) { @@ -13014,28 +13185,8 @@ void turneffectslf(lifeform_t *lf) { } if (willvanish) { - if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("%s%s vanishes.", - (creator == player) ? "Your " : "", - (creator == player) ? noprefix(lfname) : lfname - ); - } - - // all objects vanish - while (lf->pack->first) { - killob(lf->pack->first); - } - // lf dies. - lf->hp = 0; - addflag(lf->flags, F_DEAD, B_TRUE, NA, NA, NULL); - addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); - addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); - - // puff - addob(lf->cell->obpile, "puff of smoke"); + unsummon(lf, B_TRUE); } } if (isdead(lf)) return; @@ -13056,7 +13207,11 @@ void turneffectslf(lifeform_t *lf) { // chance of losing hp if (rnd(1,100) <= getpoisondamchance(f->val[0])) { char buf[BUFLEN]; - if (!hasflag(lf->flags, F_ASLEEP)) { + flag_t *asleep; + // being asleep helps. + + asleep = hasflag(lf->flags, F_ASLEEP); + if (!asleep) { if (isplayer(lf)) { msg("You %s violently.", getpoisondamverb(f->val[0])); } else if (cansee(player, lf)) { @@ -13070,13 +13225,12 @@ void turneffectslf(lifeform_t *lf) { sprintf(buf, "poisoning^from %s",f->text); losehp(lf, f->val[1], DT_DIRECT, NULL, buf); - if (!hasflag(lf->flags, F_ASLEEP)) { + if (!asleep) { if (poisoncausesvomit(f->val[0])) { addob(lf->cell->obpile, "pool of vomit"); } + loseconcentration(lf); } - - loseconcentration(lf); } // extra effects @@ -13425,6 +13579,37 @@ int touch(lifeform_t *lf, object_t *o) { return B_FALSE; } +void unsummon(lifeform_t *lf, int vanishobs) { + lifeform_t *creator = NULL; + flag_t *f; + f = hasflag(lf->flags, F_SUMMONEDBY); + if (f) { + creator = findlf(NULL, f->val[0]); + } + + if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s%s vanishes.", + (creator && (creator == player)) ? "Your " : "", + (creator && (creator == player)) ? noprefix(lfname) : lfname + ); + } + + if (vanishobs) { + // all objects vanish + while (lf->pack->first) { + killob(lf->pack->first); + } + } + + lf->hp = 0; + addflag(lf->flags, F_DEAD, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addob(lf->cell->obpile, "puff of smoke"); +} + int unweild(lifeform_t *lf, object_t *o) { flag_t *f; char obname[BUFLEN]; diff --git a/lf.h b/lf.h index dad1e0c..813f9a6 100644 --- a/lf.h +++ b/lf.h @@ -284,6 +284,7 @@ void stopeating(lifeform_t *lf); void stopresting(lifeform_t *lf); void stoprunning(lifeform_t *lf); void stopsprinting(lifeform_t *lf); +lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, int randomjobsok, job_t *forcejob, int lifetime, int wantfriendly); int testammo(lifeform_t *lf, object_t *o); int takeoff(lifeform_t *lf, object_t *o); void taketime(lifeform_t *lf, long howlong); @@ -292,6 +293,7 @@ void timeeffectslf(lifeform_t *lf); void turneffectslf(lifeform_t *lf); int touch(lifeform_t *lf, object_t *o); void unpoison(lifeform_t *lf); +void unsummon(lifeform_t *lf, int vanishobs); int unweild(lifeform_t *lf, object_t *o); int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where); int useringofmiracles(lifeform_t *lf, int charges); diff --git a/map.c b/map.c index d967a35..50e3baf 100644 --- a/map.c +++ b/map.c @@ -208,7 +208,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto // did we find one? if (!adjcell) break; - newlf = addlf(c, r->id, getrandommonlevel(r, adjcell->map)); + newlf = addlf(adjcell, r->id, getrandommonlevel(r, adjcell->map)); if (!newlf) { break; } @@ -523,14 +523,15 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in int sel; d = dodoor[i]; getroomedge(map, roomid, minx, miny, maxx, maxy, d, cell, &ncells, B_TRUE); - sel = rnd(0,ncells-1); - - if (rnd(1,100) <= doorpct) { - makedoor(cell[sel]); - doorsadded++; - } else { - setcelltype(cell[sel], getemptycelltype(map->habitat)); - doorsadded++; + if (ncells) { + sel = rnd(0,ncells-1); + if (rnd(1,100) <= doorpct) { + makedoor(cell[sel]); + doorsadded++; + } else { + setcelltype(cell[sel], getemptycelltype(map->habitat)); + doorsadded++; + } } } } @@ -1465,8 +1466,8 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) { } numobsmin = 0; - //numobsmax = MAXOF(roomw[i],roomh[i]) / 2; - numobsmax = MAXOF(roomw[i],roomh[i]); + numobsmax = MAXOF(roomw[i],roomh[i]) / 2; + //numobsmax = MAXOF(roomw[i],roomh[i]); // then objects/monsters if (numobsmax <= numobsmin) { diff --git a/move.c b/move.c index 2ab13d9..8813ab9 100644 --- a/move.c +++ b/move.c @@ -250,7 +250,8 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) { // ok } else if (cell->lf && (cell->lf != lf)) { // someone (else) in the wall? if (error) *error = E_LFINWAY; // ok but still set reason - return B_FALSE; + //return B_FALSE; + // ok } else { if (error) *error = E_WALLINWAY; return B_FALSE; @@ -623,6 +624,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc } if (reason != E_OK) { char buf[BUFLEN]; + char thing[BUFLEN]; cell_t *newcell; newcell = getcellindir(lf->cell, dir); // failed to move @@ -636,9 +638,16 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc } // fall through case E_WALLINWAY: - if (seen) msg("%s slam%s into a %s!",lfname,isplayer(lf) ? "" : "s", - newcell ? newcell->type->name : "wall"); - sprintf(buf, "slamming into a %s", newcell ? newcell->type->name : "wall"); + case E_OBINWAY: + case E_DOORINWAY: + if (reason == E_WALLINWAY) { + if (newcell) strcpy(thing, newcell->type->name); + else strcpy(thing, "wall"); + } else { // ie door or object + getobname(rdata, thing, 1); + } + if (seen) msg("%s slam%s into %s!",lfname,isplayer(lf) ? "" : "s", thing); + sprintf(buf, "slamming into %s", thing); losehp(lf, rnd(1,6), DT_BASH, pusher, buf); // stop moving i = howfar; @@ -1054,6 +1063,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if ((gamemode == GM_GAMESTARTED)) { for (l = newcell->map->lf ; l ; l = l->next) { if (l != lf) { + flag_t *alarm; if (haslos(l, newcell)) { int dointerrupt = B_FALSE; @@ -1082,6 +1092,16 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (dointerrupt) { interrupt(l); } + } + + alarm = hasactivespell(l, OT_S_ALARM); + if (alarm && areenemies(lf, l) && haslof(lf->cell, l->cell, LOF_WALLSTOP, NULL) ) { + // in range of alarm? range is 3 * spell power cells. + if (getcelldist(lf->cell, l->cell) <= (alarm->val[2]*3)) { + // alarm goes off + noise(l->cell, NULL, 50, "a blaring siren!", NULL); + killflag(alarm); + } } } } @@ -2125,7 +2145,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { } } else { // attack! - return attackcell(lf, cell); + return attackcell(lf, cell, B_FALSE); } break; case E_CANTMOVE: diff --git a/nexus.c b/nexus.c index a45fd27..bfdd542 100644 --- a/nexus.c +++ b/nexus.c @@ -465,6 +465,7 @@ void checkdeath(void) { void checkendgame(void) { if (!player->alive) { + gamemode = GM_GAMEOVER; gameover = B_TRUE; } } diff --git a/objects.c b/objects.c index 51325e6..53b60a4 100644 --- a/objects.c +++ b/objects.c @@ -2763,67 +2763,19 @@ void genhiddennames(void) { for (ot = objecttype ; ot ; ot = ot->next) { f = hasflag(ot->flags, F_HASHIDDENNAME); if (f) { - int n; - int gotcolour = B_FALSE; char *thisname; if (strlen(f->text)) { thisname = strdup(f->text); } else { thisname = genhiddenname(ot->obclass->id); } - addknowledge(ot->id, thisname, B_UNKNOWN); - // some descriptions confer other effecst too... - if (strstr(thisname, "glowing")) { - addflag(ot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); - } else if (strstr(thisname, "flourescent")) { - addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL); - } else if (strstr(thisname, "luminous")) { - addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL); - } - - // set colour based on hiddenname - for (n = 0; strlen(colour[n].name); n++) { - if (strstr(thisname, colour[n].name)) { - flag_t *gf; - gf = hasflag(ot->flags, F_GLYPH); - if (gf) { - gf->val[0] = colour[n].col; - } else { - char buf[2]; - - buf[0] = ot->obclass->glyph.ch; - buf[1] = '\0'; - addflag(ot->flags, F_GLYPH, colour[n].col, NA, NA, buf); - gotcolour = B_TRUE; - //dblog("assigning colour %s to %s (%s)",colour[n].name, thisname, ot->name); - break; - } - } - } - - if (!gotcolour) { - for (n = 0; strlen(gemtype[n].name); n++) { - if (strstr(thisname, gemtype[n].name)) { - flag_t *gf; - gf = hasflag(ot->flags, F_GLYPH); - if (gf) { - gf->val[0] = gemtype[n].col; - } else { - char buf[2]; - - buf[0] = ot->obclass->glyph.ch; - buf[1] = '\0'; - addflag(ot->flags, F_GLYPH, gemtype[n].col, NA, NA, buf); - break; - } - } - } - } + sethiddenname(ot, thisname); free(thisname); } } } +// get the first hidden name for this objectclass char *genhiddenname(enum OBCLASS id) { hiddenname_t *hn; @@ -3419,23 +3371,23 @@ int getmaterialvalue(enum MATERIAL mat) { int getmaxthrowrange(lifeform_t *lf, object_t *o) { int maxdist; - float strmod; - float modobweight; + float str; + float obweight; // adjust for lifeform strength - // mighty = div by 10 - // this will give us a number in range -44 - 50 - strmod = getstatmod(lf, A_STR); - // this will give us a number in range 1 - 10 - strmod /= 5; - if (strmod < 1) strmod = 1; + // mighty = can throw 1kilo 10 metres + // mighty = can throw 10kilos 1 metre + // 11 - kilos = distance - modobweight = getobunitweight(o) / 2; - modobweight /= strmod; + str = getattr(lf, A_STR); // ie. 1 - 18 + str -= 2; + limitf(&str, 1, NA); // ie. 1 to 16 - maxdist = 10 - modobweight; + obweight = getobunitweight(o); - if (maxdist < 0) maxdist = 0; + maxdist = ceil(str - obweight); + + if (maxdist < 1) maxdist = 0; return maxdist; } @@ -3669,9 +3621,11 @@ char *getobextrainfo(object_t *o, char *buf) { } // activated - f = hasflag(o->flags, F_ACTIVATED); - if (f) { - strcat(buf, " [activated]"); + if (!hasflag(o->flags, F_ACTIVATEPREFIX)) { + f = hasflag(o->flags, F_ACTIVATED); + if (f) { + strcat(buf, " [activated]"); + } } return buf; @@ -3795,10 +3749,15 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan } else if (o->type->id == OT_WATERDEEP) { sprintf(basename, "%s water", getwaterdepthname(getobdepth(o, player))); } else { + strcpy(basename, ""); + if (isactivated(o) && hasflag(o->flags, F_ACTIVATEPREFIX)) { + f = hasflag(o->flags, F_ACTIVATEPREFIX); + sprintf(basename, "%s ", f->text); + } if (showall) { - strcpy(basename,o->type->name); + strcat(basename,o->type->name); } else { - strcpy(basename,gethiddenname(o)); + strcat(basename,gethiddenname(o)); } } @@ -4927,8 +4886,6 @@ void initobjects(void) { addhiddenname(OC_SCROLL, "scroll titled YES"); addhiddenname(OC_SCROLL, "scroll titled ZAREL NOR"); - addhiddenname(OC_POTION, "clear potion"); - for (n = 0; strlen(colour[n].name); n++) { char buf[BUFLEN]; // add it without an adjective @@ -5092,6 +5049,7 @@ void initobjects(void) { addmaterial(MT_CLOTH, "cloth", 3); addflag(lastmaterial->flags, F_FLAMMABLE, 3, NA, NA, NULL); addflag(lastmaterial->flags, F_CANGETWET, B_TRUE, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); addmaterial(MT_FOOD, "food", 3); addmaterial(MT_PLASTIC, "plastic", 3); addflag(lastmaterial->flags, F_HARD, B_TRUE, NA, NA, NULL); @@ -5102,6 +5060,7 @@ void initobjects(void) { addmaterial(MT_RUBBER, "rubber", 4); addmaterial(MT_LEATHER, "leather", 4); addflag(lastmaterial->flags, F_CANGETWET, B_TRUE, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); addmaterial(MT_BONE, "bone", 5); addflag(lastmaterial->flags, F_HARD, B_TRUE, NA, NA, NULL); addmaterial(MT_OIL, "oil", 5); @@ -5133,6 +5092,7 @@ void initobjects(void) { addflag(lastmaterial->flags, F_DTRESIST, DT_PROJECTILE, NA, NA, NULL); addmaterial(MT_GLASS, "glass", 13); addflag(lastmaterial->flags, F_HARD, B_TRUE, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTVULN, DT_BASH, NA, NA, NULL); addmaterial(MT_GOLD, "gold", 16); addflag(lastmaterial->flags, F_HARD, B_TRUE, NA, NA, NULL); //addmaterial(MT_GOLD, "gold", 16); @@ -5477,6 +5437,7 @@ void initobjects(void) { addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pile of ash"); addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some ash"); + addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); addot(OT_ASHSLEEP, "pile of sleeping powder", "A pile of ash.", MT_STONE, 0.1, OC_ROCK); addflag(lastot->flags, F_GLYPH, NA, NA, NA, ","); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); @@ -5625,6 +5586,8 @@ void initobjects(void) { addot(OT_POT_WATER, "potion of water", "Plain, regular water.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small puddle of water"); + sethiddenname(lastot, "clear potion"); + addot(OT_POT_HEALING, "potion of healing", "Restores 10-20 health to whoever drinks it.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); @@ -6262,6 +6225,12 @@ void initobjects(void) { /////////////////// // gravity /////////////////// + // l1 + addot(OT_S_TRUESTRIKE, "true strike", "Gives the target unerring accuracy, making their attacks always hit.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL); // l3 addot(OT_S_GRAVLOWER, "lessen gravity", "Causes the caster to fall very slowly.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL); @@ -6425,6 +6394,12 @@ void initobjects(void) { // summoning /////////////////// // l1 + addot(OT_S_FLOATINGDISC, "floating disc", "Creates a disc of energy to carry your equipment.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, 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_SUMMONWEAPON, "summon weapon", "Summons a blade of pure magic into your hands. Deals 1-power damage.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -6493,6 +6468,11 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); + addot(OT_S_ALARM, "alarm", "Creates a passive alarm which goes off when an enemy is nearby.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); // l3 addot(OT_S_ENERGYBLAST, "energy blast", "Causes a ring of energy to expand from the caster (radius based on power), causing 2-6 damage to anything in sight.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); @@ -6573,9 +6553,14 @@ void initobjects(void) { addot(OT_A_RAGE, "rage", "Enter a state of berzerker rage, gaining attack and defence bonuses.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL); + addot(OT_A_REPAIR, "repair armour", "Repair damage done to your armour.", MT_NOTHING, 0, OC_ABILITY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_SPRINT, "sprint", "You can run at high speed over short distances.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); + addot(OT_A_STEAL, "steal", "Try to steal an item from an enemy.", MT_NOTHING, 0, OC_ABILITY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addot(OT_A_STINGACID, "sting (acid)", "You can sting your enemies.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); @@ -6670,6 +6655,12 @@ void initobjects(void) { addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + // tools - unique + addot(OT_ORBDUNGEONEXIT, "dungeon exit orb", "When operated, this magical key will disable the barriers around the dungeon exit stairs.", MT_STONE, 2, OC_TOOLS); + addflag(lastot->flags, F_GLYPH, C_MAGENTA, NA, NA, "["); + addflag(lastot->flags, F_UNIQUE, NA, NA, NA, NULL); + addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); // tools addot(OT_BLANKET, "wool blanket", "A warm wool blanket for those cold winter nights.", MT_CLOTH, 2, OC_TOOLS); addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); @@ -6691,6 +6682,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit"); addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 1, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 1, NA, IFACTIVE, NULL); addflag(lastot->flags, F_RNDCHARGES, 5, 10, NA, NULL); @@ -6751,6 +6743,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit"); addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 2, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, IFACTIVE, NULL); addflag(lastot->flags, F_RNDCHARGES, 50, 100, NA, NULL); @@ -7762,7 +7755,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_UNARMED, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); - // this one if for the pirate + // this one is for the pirate addot(OT_HOOKHAND, "hook", "hook", MT_METAL, 0, OC_WEAPON); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4"); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); @@ -7879,7 +7872,7 @@ void initobjects(void) { addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); - addot(OT_JAVELIN, "javelin", "A long, sharp missile weapon.", MT_METAL, 6.5, OC_MISSILE); + addot(OT_JAVELIN, "javelin", "A long, sharp missile weapon.", MT_METAL, 6, OC_MISSILE); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_MISSILEDAM, 3, NA, NA, ""); @@ -7888,7 +7881,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 3, 3, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); - addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.5, OC_MISSILE); + addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.25, OC_MISSILE); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); @@ -7898,7 +7891,7 @@ void initobjects(void) { addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); - addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 1, OC_MISSILE); + addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 0.5, OC_MISSILE); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); @@ -7915,7 +7908,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); - addot(OT_RUBBERBULLET, "rubber bullet", "A rubber gun bullet - does not do much damage.", MT_STONE, 0.1, OC_MISSILE); + addot(OT_RUBBERBULLET, "rubber bullet", "A rubber gun bullet - does not do much damage.", MT_STONE, 0.05, OC_MISSILE); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); @@ -7926,20 +7919,20 @@ void initobjects(void) { // axes - addot(OT_AXE, "axe", "A short pole with a heavy, wedge-shaped blade for chopping.", MT_METAL, 4, OC_WEAPON); + addot(OT_AXE, "axe", "A short pole with a heavy, wedge-shaped blade for chopping.", MT_METAL, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d6"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); - addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 5, OC_WEAPON); + addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 8, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+1"); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); - addot(OT_GREATAXE, "greataxe", "An enormous axe made designed for combat.", MT_METAL, 8, OC_WEAPON); + addot(OT_GREATAXE, "greataxe", "An enormous axe made designed for combat.", MT_METAL, 10, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d9+1"); @@ -7947,14 +7940,14 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 16, NA, NULL); - addot(OT_HANDAXE, "hand axe", "A fast one-handed axe, ideal for throwing.", MT_METAL, 2, OC_WEAPON); + addot(OT_HANDAXE, "hand axe", "A fast one-handed axe, ideal for throwing.", MT_METAL, 2.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d7"); addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); - addot(OT_WARAXE, "war axe", "An axe made for combat.", MT_METAL, 4, OC_WEAPON); + addot(OT_WARAXE, "war axe", "An axe made for combat.", MT_METAL, 7, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d7+1"); addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); @@ -7980,7 +7973,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addot(OT_KNIFE, "knife", "A moderately sharp stabbing tool.", MT_METAL, 1, OC_WEAPON); + addot(OT_KNIFE, "knife", "A moderately sharp stabbing tool.", MT_METAL, 0.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d3"); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); @@ -7997,32 +7990,32 @@ void initobjects(void) { addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addot(OT_QUICKBLADE, "quickblade", "A short blade of exceptional quality, which somehow allows its bearer to attack faster.", MT_METAL, 1, OC_WEAPON); + addot(OT_QUICKBLADE, "quickblade", "A short blade of exceptional quality, which somehow allows its bearer to attack faster.", MT_METAL, 3.0, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 75, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4"); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addot(OT_RAPIER, "rapier", "A long, narrow French sword lacking a cutting edge. Made for stabbing.", MT_METAL, 2.5, OC_WEAPON); + addot(OT_RAPIER, "rapier", "A long, narrow French sword lacking a cutting edge. Made for stabbing.", MT_METAL, 3.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d8"); addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL); - addot(OT_SAI, "sai", "A dagger with two long prongs on either side, made to trap opponents' weapons.", MT_METAL, 1, OC_WEAPON); + addot(OT_SAI, "sai", "A dagger with two long prongs on either side, made to trap opponents' weapons.", MT_METAL, 1.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 81, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4"); addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 10, NA, NULL); - addot(OT_SHORTSWORD, "short sword", "A short blade for fighting. Better for stabbing.", MT_METAL, 2.5, OC_WEAPON); + addot(OT_SHORTSWORD, "short sword", "A short blade for fighting. Better for stabbing.", MT_METAL, 4, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d6"); addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL); - addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 0.5, OC_WEAPON); + addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 1, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d6"); addflag(lastot->flags, F_ACCURACY, 60, NA, NA, NULL); @@ -8037,7 +8030,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); // long blades - addot(OT_FALCHION, "falchion", "A single-edged heavy sword made for chopping.", MT_METAL, 4.5, OC_WEAPON); + addot(OT_FALCHION, "falchion", "A single-edged heavy sword made for chopping.", MT_METAL, 6.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 61, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+3"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); @@ -8051,26 +8044,26 @@ void initobjects(void) { addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); - addot(OT_LONGSWORD, "longsword", "Standard issue long slashing weapon.", MT_METAL, 3, OC_WEAPON); + addot(OT_LONGSWORD, "longsword", "Standard issue long slashing weapon.", MT_METAL, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d8+4"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL); - addot(OT_ORNSWORD, "ornamental sword", "A gleaming (but quite blunt) blade.", MT_METAL, 2, OC_WEAPON); + addot(OT_ORNSWORD, "ornamental sword", "A gleaming (but quite blunt) blade.", MT_METAL, 6, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d6"); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); - addot(OT_SCIMITAR, "scimitar", "A fast, sharp, curved blade.", MT_METAL, 2, OC_WEAPON); + addot(OT_SCIMITAR, "scimitar", "A fast, sharp, curved blade.", MT_METAL, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 90, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 8, NA, NULL); - addot(OT_CUTLASS, "cutlass", "An accurate, light-weight pirate blade.", MT_METAL, 1, OC_WEAPON); + addot(OT_CUTLASS, "cutlass", "An accurate, light-weight pirate blade.", MT_METAL, 4, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7"); addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); @@ -8078,7 +8071,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 8, NA, NULL); // polearms - addot(OT_GLAIVE, "glaive", "A single-edged blade attached to a long pole.", MT_METAL, 4, OC_WEAPON); + addot(OT_GLAIVE, "glaive", "A single-edged blade attached to a long pole.", MT_METAL, 10, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7+3"); @@ -8086,7 +8079,7 @@ void initobjects(void) { addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); - addot(OT_GUISARME, "guisarme", "A hooked polearm, made by attaching a hook to a spear shaft.", MT_METAL, 4, OC_WEAPON); + addot(OT_GUISARME, "guisarme", "A hooked polearm, made by attaching a hook to a spear shaft.", MT_METAL, 10, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL); addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); @@ -8096,7 +8089,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL); - addot(OT_HALBERD, "halberd", "A spiked axe blade mounted on a long shaft, with a hook on the back.", MT_METAL, 4, OC_WEAPON); + addot(OT_HALBERD, "halberd", "A spiked axe blade mounted on a long shaft, with a hook on the back.", MT_METAL, 12, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 71, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL); @@ -8106,7 +8099,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL); - addot(OT_LANCE, "lance", "A pole weapon designed for use while mounted.", MT_METAL, 4, OC_WEAPON); + addot(OT_LANCE, "lance", "A pole weapon designed for use while mounted.", MT_METAL, 12, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); @@ -8114,7 +8107,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); - addot(OT_RANSEUR, "ranseur", "A long spear and cross hilt, resembling a pole-mounted sai. Good for disarming.", MT_METAL, 1, OC_WEAPON); + addot(OT_RANSEUR, "ranseur", "A long spear and cross hilt, resembling a pole-mounted sai. Good for disarming.", MT_METAL, 12, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL); addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); @@ -8124,14 +8117,14 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL); - addot(OT_SCYTHE, "scythe", "An agricultural hand tool for mowing grass, or reaping crops.", MT_METAL, 3, OC_WEAPON); + addot(OT_SCYTHE, "scythe", "An agricultural hand tool for mowing grass, or reaping crops.", MT_METAL, 6, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4"); addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); - addot(OT_SPEAR, "spear", "A long pole with a sharpened head.", MT_METAL, 4, OC_WEAPON); + addot(OT_SPEAR, "spear", "A long pole with a sharpened head.", MT_METAL, 9, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); @@ -8142,7 +8135,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); - addot(OT_TRIDENT, "trident", "A three-pronged stabbing weapon.", MT_METAL, 3, OC_WEAPON); + addot(OT_TRIDENT, "trident", "A three-pronged stabbing weapon.", MT_METAL, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d10"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); @@ -8150,7 +8143,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); // staves - addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 2, OC_WEAPON); + addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 4, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d8"); addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); @@ -8160,7 +8153,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); - addot(OT_BAMBOOSTAFF, "bamboo staff", "A long hard pole made from bamboo.", MT_WOOD, 1.5, OC_WEAPON); + addot(OT_BAMBOOSTAFF, "bamboo staff", "A long hard pole made from bamboo.", MT_WOOD, 3, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d4"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); @@ -8169,7 +8162,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); - addot(OT_BLADEDSTAFF, "bladed staff", "A long wooden pole with blades on either end.", MT_WOOD, 2, OC_WEAPON); + addot(OT_BLADEDSTAFF, "bladed staff", "A long wooden pole with blades on either end.", MT_WOOD, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4+3"); @@ -8180,7 +8173,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); - addot(OT_IRONSTAFF, "iron staff", "A long, stout metal pole.", MT_METAL, 4, OC_WEAPON); + addot(OT_IRONSTAFF, "iron staff", "A long, stout metal pole.", MT_METAL, 8, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "3d4+1"); @@ -8192,13 +8185,13 @@ void initobjects(void) { // clubs (bashing) - addot(OT_CLUB, "club", "A heavy, blunt wooden instrument to hit things with.", MT_WOOD, 3, OC_WEAPON); + addot(OT_CLUB, "club", "A heavy, blunt wooden instrument to hit things with.", MT_WOOD, 8, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d6"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); - addot(OT_FLAIL, "flail", "A flexible chain attached to a heavy weight.", MT_METAL, 6, OC_WEAPON); + addot(OT_FLAIL, "flail", "A flexible chain attached to a heavy weight.", MT_METAL, 9, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d4"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); @@ -8211,7 +8204,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); - addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 5, OC_WEAPON); + addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 15, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d10+5"); @@ -8219,13 +8212,13 @@ void initobjects(void) { addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 16, NA, NULL); - addot(OT_MACE, "mace", "A weapon with a heavy head on a solid shaft used to bludgeon opponents.", MT_METAL, 3, OC_WEAPON); + addot(OT_MACE, "mace", "A weapon with a heavy head on a solid shaft used to bludgeon opponents.", MT_METAL, 10, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d7+1"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); - addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 3.5, OC_WEAPON); + addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 12, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d9+3"); @@ -8233,7 +8226,7 @@ void initobjects(void) { addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); - addot(OT_NUNCHAKU, "nunchaku", "Two stout sticks connected with a short or rope. Good for disarming.", MT_WOOD, 1.5, OC_WEAPON); + addot(OT_NUNCHAKU, "nunchaku", "Two stout sticks connected with a short or rope. Good for disarming.", MT_WOOD, 4.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d6+1"); @@ -8258,7 +8251,7 @@ void initobjects(void) { addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); // projectile weapons - addot(OT_BOW, "bow", "A weapon which projects arrows via its elasticity.", MT_WOOD, 3, OC_WEAPON); + addot(OT_BOW, "bow", "A weapon which projects arrows via its elasticity.", MT_WOOD, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); @@ -8269,7 +8262,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); - addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but needs high strength to use.", MT_WOOD, 5, OC_WEAPON); + addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but needs high strength to use.", MT_WOOD, 8, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); @@ -8288,7 +8281,7 @@ void initobjects(void) { addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); - addot(OT_LONGBOW, "longbow", "A very large (human-sized) bow, capable of firing arrows with great power.", MT_WOOD, 6, OC_WEAPON); + addot(OT_LONGBOW, "longbow", "A very large (human-sized) bow, capable of firing arrows with great power.", MT_WOOD, 7, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); @@ -8321,7 +8314,6 @@ void initobjects(void) { // special weapons - addot(OT_ENERGYBLADE, "energy blade", "A summoned weapon made of pure magical energy.", MT_MAGIC, 0, OC_WEAPON); addflag(lastot->flags, F_DAM, DT_MAGIC, NA, NA, "1d4"); // will be replaced when summoned addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); @@ -9765,11 +9757,13 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } if (isplayer(lf)) { + char subprompt[BUFLEN]; + sprintf(subprompt, "%s->Aim->", obname); if (strlen(f->text) > 0) { - where = askcoords(f->text, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE); + where = askcoords(f->text, subprompt, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE); } else { sprintf(buf, "Where will you aim %s?",obname); - where = askcoords(buf, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE); + where = askcoords(buf, subprompt, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE); if (!haslos(lf, where)) { // exception - wand of digging doesn't need los if (isknown(o) && (o->type->id == OT_WAND_DIGGING)) { @@ -9851,9 +9845,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { */ if (hasflag(o->flags, F_OPERONOFF)) { // operating toggles on/off - flag_t *f; - f = hasflag(o->flags, F_ACTIVATED); - if (f) { + if (isactivated(o)) { turnoff(lf, o); } else { turnon(lf, o); @@ -10129,6 +10121,27 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { msg("There is nothing here to fill your %s from.",noprefix(obname)); } } + } else if (o->type->id == OT_ORBDUNGEONEXIT) { + map_t *m; + m = lf->cell->map; + if ((m->region == RG_FIRSTDUNGEON) && (m->depth == 1)) { + cell_t *cell[MAXCANDIDATES]; + int ncells,i; + getradiuscells(lf->cell, 1, DT_COMPASS, B_FALSE, B_TRUE, cell, &ncells); + for (i = 0; i < ncells; i++) { + if (hasob(cell[i]->obpile, OT_STAIRSUP)) { + object_t *o; + o = hasob(cell[i]->obpile, OT_MAGICBARRIER); + if (o) { + addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); + } + } + } + } else { + if (isplayer(lf)) { + nothinghappens(); + } + } } else if (o->type->id == OT_POCKETWATCH) { if (isplayer(lf)) { if (haslos(lf, lf->cell)) { @@ -10848,20 +10861,12 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE if (!modattr(lf, A_STR, amt)) failed = B_FALSE; if (!modattr(lf, A_DEX, amt)) failed = B_FALSE; if (!modattr(lf, A_IQ, amt)) failed = B_FALSE; + if (!modattr(lf, A_CON, amt)) failed = B_FALSE; } else { + enum ATTRIB a; // modify just one attribute - i = rnd(1,3); - switch (i) { - case 1: - if (!modattr(lf, A_STR, amt)) failed = B_FALSE; - break; - case 2: - if (!modattr(lf, A_DEX, amt)) failed = B_FALSE; - break; - case 3: - if (!modattr(lf, A_IQ, amt)) failed = B_FALSE; - break; - } + a = rnd(0,MAXATTS); + if (!modattr(lf, a, amt)) failed = B_FALSE; } if (failed) { if (isplayer(lf)) { @@ -11591,6 +11596,64 @@ void setblessed(object_t *o, enum BLESSTYPE wantbless) { } } +int sethiddenname(objecttype_t *ot, char *text) { + int n; + int gotcolour = B_FALSE; + + // add knowledge for it + addknowledge(ot->id, text, B_UNKNOWN); + + // some descriptions confer other effecst too... + if (strstr(text, "glowing")) { + addflag(ot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); + } else if (strstr(text, "flourescent")) { + addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL); + } else if (strstr(text, "luminous")) { + addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL); + } + + // set colour based on hiddenname + for (n = 0; strlen(colour[n].name); n++) { + if (strstr(text, colour[n].name)) { + flag_t *gf; + gf = hasflag(ot->flags, F_GLYPH); + if (gf) { + gf->val[0] = colour[n].col; + } else { + char buf[2]; + + buf[0] = ot->obclass->glyph.ch; + buf[1] = '\0'; + addflag(ot->flags, F_GLYPH, colour[n].col, NA, NA, buf); + gotcolour = B_TRUE; + //dblog("assigning colour %s to %s (%s)",colour[n].name, text, ot->name); + break; + } + } + } + + if (!gotcolour) { + for (n = 0; strlen(gemtype[n].name); n++) { + if (strstr(text, gemtype[n].name)) { + flag_t *gf; + gf = hasflag(ot->flags, F_GLYPH); + if (gf) { + gf->val[0] = gemtype[n].col; + } else { + char buf[2]; + + buf[0] = ot->obclass->glyph.ch; + buf[1] = '\0'; + addflag(ot->flags, F_GLYPH, gemtype[n].col, NA, NA, buf); + break; + } + } + } + } + + return B_FALSE; +} + void setinscription(object_t *o, char *text) { if (o->inscription) { free(o->inscription); @@ -11905,6 +11968,20 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno // catches on fire? if (damtype == DT_FIRE) { + if ( ((o->type->id == OT_CANDLE) || (o->type->id == OT_TORCH)) && + !isactivated(o)) { + cell_t *c; + c = getoblocation(o); + if (haslos(player, c)) { + char buf[BUFLEN]; + getobname(o, buf, o->amt); + msg("%s %s lit.", buf, (o->amt == 1) ? "is" : "are"); + } + turnon(NULL, o); + + // reduce damage a tiny bit + howmuch--; + } if (isflammable(o)) { ignite(o); if (isdeadob(o)) { @@ -12245,7 +12322,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, // announce it ("xx throws xx" "at yy") if (thrower && isplayer(thrower)) { // player is throwing something - if (target) { + if (target && !hasflag(o->flags, F_POWDER)) { msg("You %s %s %s %s.", throwverbpres, obname, willcatch ? "to" : "at", targetname); } else { msg("You %s %s.",throwverbpres, obname); @@ -12257,7 +12334,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, sprintf(throwstring, "%s %ss %s", throwername, throwverbpres, obname); - if (target && haslos(player, where)) { + if (target && haslos(player, where) && !hasflag(o->flags, F_POWDER)) { strcat(throwstring, willcatch ? " to " : " at "); strcat(throwstring, targetname); } @@ -13208,7 +13285,7 @@ void turnon(lifeform_t *lf, object_t *o) { f = hasflag(o->flags, F_ACTIVATED); if (f) { // already on - if (isplayer(lf)) { + if (lf && isplayer(lf)) { msg("Your %s is already activated!\n", noprefix(obname)); } return; @@ -13218,19 +13295,21 @@ void turnon(lifeform_t *lf, object_t *o) { f = hasflag(o->flags, F_CHARGES); if (f && (f->val[0] <= 0)) { // out of power - if (isplayer(lf)) { + if (lf && isplayer(lf)) { nothinghappens(); } return; } getobname(o, obname, 1); - if (isplayer(lf)) { - msg("You activate your %s.",noprefix(obname)); - } else if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("%s activates %s.",lfname, obname); + if (lf) { + if (isplayer(lf)) { + msg("You activate your %s.",noprefix(obname)); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s activates %s.",lfname, obname); + } } // for grenades, give a new object which is activated @@ -13254,7 +13333,9 @@ void turnon(lifeform_t *lf, object_t *o) { addflag(o->flags, F_ACTIVATED, B_TRUE, NA, NA, NULL); } - giveobflags(lf, o, F_ACTIVATECONFER); + if (lf) { + giveobflags(lf, o, F_ACTIVATECONFER); + } } @@ -13427,6 +13508,23 @@ int validateobs(void) { return goterror; } +int wepdullable(object_t *o) { + enum DAMTYPE dt; + + if (!o) return B_FALSE; + + dt = getdamtype(o); + switch (dt) { + case DT_PIERCE: + case DT_SLASH: + return B_TRUE; + default: + break; + } + return B_FALSE; +} + + int willshatter(enum MATERIAL mat) { switch (mat) { case MT_GLASS: diff --git a/objects.h b/objects.h index b7539a5..fc155e5 100644 --- a/objects.h +++ b/objects.h @@ -201,6 +201,7 @@ int removeob(object_t *o, int howmany); object_t *relinkob(object_t *src, obpile_t *dst); void rrtorarity(enum RARITY r, int *minr, int *maxr); void setblessed(object_t *o, enum BLESSTYPE wantbless); +int sethiddenname(objecttype_t *o, char *text); void setinscription(object_t *o, char *text); void setobcreatedby(object_t *o, lifeform_t *lf); void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf); @@ -216,6 +217,7 @@ void turnon(lifeform_t *lf, object_t *o); int uncurseob(object_t *o, int *seen); int usecharge(object_t *o); int validateobs(void); +int wepdullable(object_t *o); int willshatter(enum MATERIAL mat); #endif diff --git a/spell.c b/spell.c index 6c3d13b..afa6e91 100644 --- a/spell.c +++ b/spell.c @@ -115,7 +115,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) { sprintf(buf, "Charge who (max range %d)?",range); // TODO: ask for direction - targcell = askcoords(buf, TT_MONSTER, user, range, LOF_NEED, B_TRUE); + targcell = askcoords(buf, "Charge->", TT_MONSTER, user, range, LOF_NEED, B_TRUE); if (!targcell) { msg("Cancelled."); return TRUE; @@ -196,7 +196,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef addflag(target->flags, F_GRABBEDBY, user->id, NA, NA, NULL); } else { // attack - attackcell(user, targcell); + attackcell(user, targcell, B_TRUE); } } else if (abilid == OT_A_COOK) { object_t *water,*o; @@ -267,7 +267,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } else { sprintf(buf, "Darkwalk to where?"); } - targcell = askcoords(buf, TT_NONE, user, range, LOF_DONTNEED, B_FALSE); + targcell = askcoords(buf, "Darkwalk->", TT_NONE, user, range, LOF_DONTNEED, B_FALSE); } else { return B_TRUE; } @@ -437,7 +437,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } // now attack them - attackcell(user, target->cell); + attackcell(user, target->cell, B_TRUE); } else if (abilid == OT_A_GRAB) { char dirch; flag_t *f; @@ -569,7 +569,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef sprintf(buf, "Jump where (max distance 2)?"); while (!targcell) { // ask where - targcell = askcoords(buf, TT_NONE, user, 2, LOF_DONTNEED, B_TRUE); + targcell = askcoords(buf, "Jump->", TT_NONE, user, 2, LOF_DONTNEED, B_TRUE); if (!targcell) { return B_TRUE; } else if (getcelldist(user->cell, targcell) > 2) { @@ -690,6 +690,78 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } howlong = 10; addtempflag(user->flags, F_RAGE, B_TRUE, NA, NA, NULL, howlong); + } else if (abilid == OT_A_REPAIR) { + enum SKILLLEVEL slev; + object_t *o; + int cutoffpct = 0; + slev = getskill(user, SK_ARMOUR); + switch (slev) { + default: + if (isplayer(user)) { + msg("You are too unskilled to repair your armour."); + } + return B_TRUE; + case PR_SKILLED: cutoffpct = 50; break; + case PR_EXPERT: cutoffpct = 75; break; + case PR_MASTER: cutoffpct = 100; break; + } + + // 1.compile a list of repairable objects + // sk_armour lets you repair armour up to xx% (depends on skill) + initprompt(&prompt, "Repair which object?"); + addchoice(&prompt, '-', "Cancel", buf, o); + for (o = user->pack->first ; o ; o = o->next) { + if (isarmour(o) && isdamaged(o)) { + float pct; + f = hasflag(o->flags, F_OBHP); + pct = ((float)f->val[0] /(float) f->val[1]) * 100; + if (pct < cutoffpct) { + char buf[BUFLEN]; + getobname(o, buf, o->amt); + // we can repair this object + addchoice(&prompt, o->letter, buf, buf, o); + } + } + } + + if (prompt.nchoices <= 1) { + if (isplayer(user)) { + msg("You don't have anything which you are able to repair."); + } + return B_TRUE; + } + + // 2. ask which ones to repair (or ALL) + if (isplayer(user)) { + getchoice(&prompt); + o = (object_t *) prompt.result; + } else { + // pick a random one + o = (object_t *) prompt.choice[rnd(0,prompt.nchoices-1)].data; + } + + + // in case it's on fire, etc + if (touch(user, o)) { + taketime(user, getactspeed(user)); + return B_TRUE; + } + + // repair it! + f = hasflag(o->flags, F_OBHP); + f->val[0] = pctof(cutoffpct, f->val[1]); + if (isplayer(user)) { + char buf[BUFLEN]; + real_getobname(o, buf, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE); + msg("You %srepair your %s.", (f->val[0] == f->val[1]) ? "" : "partially ", noprefix(buf)); + } else { + char buf[BUFLEN]; + real_getobname(o, buf, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE); + msg("%s %s repairs %s.", username, (f->val[0] == f->val[1]) ? "completely" : "partially", buf); + } + + // TODO: make this like eating/resting/etc ? + taketime(user, getactspeed(user)); } else if (abilid == OT_A_SPRINT) { int howlong; int slev; @@ -837,7 +909,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) { sprintf(buf, "Swoop who (max range %d)?",srange); // TODO: ask for direction - targcell = askcoords(buf, TT_MONSTER, user, srange, LOF_NEED, B_TRUE); + targcell = askcoords(buf, "Swoop->", TT_MONSTER, user, srange, LOF_NEED, B_TRUE); if (!targcell) { msg("Cancelled."); return TRUE; @@ -899,7 +971,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } // attack - attackcell(user, targcell); + attackcell(user, targcell, B_TRUE); // teleport back to initial pos movelf(user, origcell); @@ -971,13 +1043,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef return B_FALSE; } else if (abilid == OT_A_DEBUG) { cell_t *where; - where = askcoords("Debug who?", TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE); + where = askcoords("Debug who?", "Debug->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE); if (where && where->lf) { debug(where->lf); } } else if (abilid == OT_A_EMPLOY) { cell_t *where; - where = askcoords("Assign job to who?", TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE); + where = askcoords("Assign job to who?", "Assignjob->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE); if (where && where->lf) { char question[BUFLEN]; char lfname[BUFLEN]; @@ -1001,7 +1073,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } else if (abilid == OT_A_ENHANCE) { cell_t *where; - where = askcoords("Enhance stats of who?", TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE); + where = askcoords("Enhance stats of who?", "Enhancestats->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE); if (where && where->lf) { char ch; enum ATTRIB att; @@ -1041,7 +1113,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } wep = getweapon(user); - if (!wep || !ismeleeweapon(wep) || (getobunitweight(wep) < 3)) { + if (!wep || !ismeleeweapon(wep) || (getobunitweight(wep) < 8)) { // ie. 8 is weight of a mace if (isplayer(user)) msg("You need a heavy weapon to perform a heavy blow!"); return B_TRUE; } @@ -1072,8 +1144,122 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef getlfname(target, targetname); f = addflag(wep->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL); - attackcell(user, targcell); + attackcell(user, targcell, B_TRUE); killflag(f); + } else if (abilid == OT_A_STEAL) { + enum SKILLLEVEL slev; + char dirch; + object_t *wep; + char targetname[BUFLEN]; + flag_t *penalty = NULL; + int failed = B_TRUE; + + // ask for direction + if (!targcell) { + dirch = askchar("Steal in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE); + int dir; + dir = chartodir(dirch); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE ; + } else { + targcell = getcellindir(user->cell, dir); + } + } + + target = targcell->lf; + if (!target) { + if (isplayer(user)) msg("There is nobody there to steal from!"); + return B_TRUE; + } + + taketime(user, getactspeed(user)); + + slev = getskill(user, SK_THIEVERY); + if (slev == PR_INEPT) { + if (isplayer(user)) msg("You are too unskilled to steal anything!"); + return B_TRUE; + } + + getlfname(target, targetname); + + if (slev == PR_NOVICE) { + penalty = addflag(user->flags, F_ACCURACYMOD, -14, NA, NA, NULL); + } else if (slev == PR_BEGINNER) { + penalty = addflag(user->flags, F_ACCURACYMOD, -7, NA, NA, NULL); + } + + // use empty handed attack accuracy + wep = getweapon(user); + if (rolltohit(user, target, wep, NULL)) { + object_t *o; + int i,nsteals; + // + if (slev >= PR_EXPERT) { + nsteals = 2; + } else { + nsteals = 1; + } + // what do we steal? + for (i = 0; i < nsteals; i++) { + sprintf(buf, "Steal what (%d of %d)?", i+1, nsteals); + initprompt(&prompt, buf); + addchoice(&prompt, '-', "Nothing", NULL, NULL); + for (o = target->pack->first ; o ; o = o->next) { + int ok = B_TRUE; + if ((slev < PR_SKILLED) && (getobunitweight(o) >= 3)) { + // too heavy to steal + ok = B_FALSE; + } else if ((slev < PR_MASTER) && isequipped(o)) { + // equipped + ok = B_FALSE; + } else if (!canpickup(user, o, 1)) { + // can't pick it up + ok = B_FALSE; + } + if (ok) { + getobname(o, buf, 1); + addchoice(&prompt, o->letter, buf, NULL, o); + } + } + if (prompt.nchoices > 1) { + if (slev >= PR_ADEPT) { + // pick what you want + getchoice(&prompt); + o = (object_t *)prompt.result; + } else { + // random + o = (object_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data; + } + if (o) { + o = moveob(o, user->pack, 1); + if (o) { + getobname(o, buf, 1); + if (isplayer(user)) { + msg("You steal %s from %s!", buf, targetname); + } else if (cansee(player, user)) { + msg("%s steals %s from %s!", username, buf, targetname); + } + failed = B_FALSE; + } + } + } else { + break; + } + } + } + + if (penalty) { + killflag(penalty); + } + + if (failed) { + if (isplayer(user)) { + msg("You try to steal from %s, but fail.", targetname); + } else if (cansee(player, user)) { + msg("%s tries to steal from %s, but fails.", username, targetname); + } + } } else if (abilid == OT_A_WARCRY) { // announce if (isplayer(user)) { @@ -1115,7 +1301,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef for (dir = DC_N; dir <= DC_NW; dir++) { c = getcellindir(user->cell, dir); if (c) { - attackcell(user, c); + attackcell(user, c, B_TRUE); } } // remove temporary flags @@ -1430,6 +1616,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } } + } else if (spellid == OT_S_ALARM) { + if (isplayer(caster)) { + msg("You create a alarm field around yourself."); + } } else if (spellid == OT_S_ANIMATEDEAD) { int i; object_t *o,*nexto; @@ -2154,7 +2344,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } - if (!targcell) { fizzle(caster); return B_TRUE; @@ -2203,30 +2392,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // add the monster - newlf = addmonster(targcell, r->id, randomjobsok, 1, B_FALSE, NULL); + newlf = summonmonster(caster, targcell, r->id, randomjobsok, forcejob, PERMENANT, B_FALSE); if (newlf) { - // assign job if required - if (forcejob) { - givejob(newlf, forcejob->id); - } if (haslos(player, targcell)) { - char *newbuf; - getlfname(newlf, buf); - newbuf = strdup(buf); - // newbuf will be "the xxx" - if (isvowel(newbuf[4])) { - newbuf = strrep(newbuf, "the ", "an ", NULL); - } else { - newbuf = strrep(newbuf, "the ", "a ", NULL); - } - capitalise(newbuf); - msg("%s appears!", newbuf); - free(newbuf); if (seenbyplayer) *seenbyplayer = B_TRUE; } - // not worth any xp - killflagsofid(newlf->flags, F_XPVAL); - addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); rv = B_FALSE; } else { // didn't work for some reason @@ -2766,6 +2936,27 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } brightflash(caster->cell, 2 + (power/4), player); + } else if (spellid == OT_S_FLOATINGDISC) { + lifeform_t *newlf; + // get random adjacent cell + targcell = getrandomadjcell(caster->cell, WE_EMPTY, B_ALLOWEXPAND); + if (!targcell) { + fizzle(caster); + return B_TRUE; + } + // add it + newlf = summonmonster(caster, targcell, R_FLOATINGDISC, B_FALSE, NULL, PERMENANT, B_TRUE); + if (newlf) { + if (haslos(player, targcell)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + // set carrying capacity + setattr(newlf, A_STR, 8 + power); + } else { + // didn't work for some reason + fizzle(caster); + return B_TRUE; + } } else if (spellid == OT_S_FLOOD) { int failed = B_FALSE; // ask for a target cell @@ -4359,7 +4550,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (caster->race->id == R_GHOST) { targcell = caster->cell; } else { - if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_PLAYER, spellid, power, frompot)) return B_TRUE; } target = targcell->lf; @@ -4873,13 +5064,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ char obname[BUFLEN]; getobname(o, obname, o->amt); - f->val[0] += (rnd(1,6) + power); + if (blessed) { + f->val[0] += (rnd(1,6) + power); - if (f->val[0] >= f->val[1]) { - msg("Your %s is completely repaired!", noprefix(obname)); - f->val[0] = f->val[1]; + if (f->val[0] >= f->val[1]) { + msg("Your %s is completely repaired!", noprefix(obname)); + f->val[0] = f->val[1]; + } else { + msg("Your %s is repaired a little!", noprefix(obname)); + } } else { - msg("Your %s is repaired a little!", noprefix(obname)); + msg("Your %s deteriorates!", noprefix(obname)); + takedamage(o, rnd(1,6) + power, DT_DIRECT); } if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -5401,10 +5597,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { for (o = targcell->obpile->first ; o ; o = nexto) { nexto = o->next; - if (isflammable(o)) { - takedamage(o, rnd(1,3), DT_FIRE); + // special cases + if (isflammable(o) || (o->type->id == OT_CANDLE) || (o->type->id == OT_TORCH)) { + takedamage(o, 1, DT_FIRE); + donesomething = B_TRUE; } - donesomething = B_TRUE; } } } else if (spellid == OT_S_STENCH) { @@ -5597,7 +5794,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ sprintf(buf, "Where will you teleport to?"); while (!c) { int ch; - c = askcoords(buf, TT_NONE, caster, UNLIMITED, LOF_DONTNEED, B_FALSE); + c = askcoords(buf, "Teleport->",TT_NONE, caster, UNLIMITED, LOF_DONTNEED, B_FALSE); if (!c) { fizzle(caster); return B_FALSE; @@ -5762,7 +5959,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!targob) { // ask for a target cell (to take objects from) sprintf(buf, "Where will you focus your telekinetic power?"); - where = askcoords(buf, TT_OBJECT | TT_DOOR, caster, UNLIMITED, LOF_DONTNEED, B_FALSE); + where = askcoords(buf, "Telekinesis->", TT_OBJECT | TT_DOOR, caster, UNLIMITED, LOF_DONTNEED, B_FALSE); if (where && haslos(caster, where)) { if (where->obpile->first) { // select object from cell... @@ -5792,11 +5989,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // if no target cell, ask where to throw object if (!targcell) { - char obname[BUFLEN]; + char obname[BUFLEN],buf2[BUFLEN]; getobname(targob, obname, 1); - sprintf(buf, "Where will you move %s to?", obname); + sprintf(buf, "Where will you throw %s to?", obname); // TODO: start trail from the object - targcell = askcoords(buf, TT_MONSTER | TT_PLAYER, caster, UNLIMITED, LOF_DONTNEED, B_FALSE); + sprintf(buf2, "Telekinesis->%s->",obname); + targcell = askcoords(buf, buf2,TT_MONSTER | TT_PLAYER, caster, UNLIMITED, LOF_DONTNEED, B_FALSE); } // not liftable? @@ -5855,6 +6053,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ f = addtempflag(caster->flags, F_RETALIATE, 1, 4, DT_PIERCE, "sharp thorns", FROMSPELL); f->obfrom = spellid; + } else if (spellid == OT_S_TRUESTRIKE) { + if (!validatespellcell(caster, &targcell, TT_PLAYER, spellid, power, frompot)) return B_TRUE; + target = targcell->lf; + if (!target) { + fizzle(caster); + return B_FALSE; + } + addflag(caster->flags, F_TRUESTRIKE, power, NA, NA, NULL); } else if (spellid == OT_S_TURNUNDEAD) { int i; // works on all undead in sight @@ -6778,6 +6984,13 @@ char *getvarpowerspelldesc(enum OBTYPE spellid, int power, char *buf) { case OT_S_SUMMONWEAPON: sprintf(buf, "Create a 2d%d damage magical weapon",power); break; + case OT_S_TRUESTRIKE: + if (power == 1) { + sprintf(buf, "Next attack automatically hits"); + } else { + sprintf(buf, "Next %d attacks automatically hit",power); + } + break; case OT_S_WINDSHIELD: sprintf(buf, "Protection from missiles <= %d km/h",speedtokph(power)); break; @@ -6852,6 +7065,38 @@ void stopallspells(lifeform_t *lf) { } } +void stopallspellsexcept(lifeform_t *lf, ...) { + flag_t *f,*nextf; + va_list args; + enum OBTYPE exception[MAXCANDIDATES]; + int nexceptions = 0; + + va_start(args, lf); + exception[nexceptions] = va_arg(args, enum OBTYPE); + while (exception[nexceptions] != OT_NONE) { + nexceptions++; + exception[nexceptions] = va_arg(args, enum OBTYPE); + } + va_end(args); + + for (f = lf->flags->first ; f ; f = nextf) { + nextf = f->next; + if (f->id == F_BOOSTSPELL) { + int stopthis = B_TRUE; + int n; + for (n = 0; n < nexceptions; n++) { + if (exception[n] == f->val[0]) { + stopthis = B_FALSE; + break; + } + } + if (stopthis) { + stopspell(lf, f->val[0]); + } + } + } +} + int schoolappearsinbooks(enum SPELLSCHOOL ss) { switch (ss) { case SS_DIVINE: @@ -6915,6 +7160,19 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) { killob(o); } } + if (spellid == OT_S_FLOATINGDISC) { + map_t *m; + lifeform_t *lf; + for (m = firstmap ; m ; m = m->next) { + for (lf = m->lf ; lf ; lf = lf->next) { + if (lf->race->id == R_FLOATINGDISC) { + if (lfhasflagval(lf, F_SUMMONEDBY, caster->id, NA, NA, NULL)) { + unsummon(lf, B_FALSE); + } + } + } + } + } } @@ -6997,9 +7255,10 @@ lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **targe // ask for a target lifeform if (isplayer(user)) { cell_t *where; - char buf[BUFLEN]; + char buf[BUFLEN],buf2[BUFLEN]; sprintf(buf, "Where will you target your %s?",ot->name); - where = askcoords(buf, TT_MONSTER, user, maxrange, LOF_DONTNEED, B_FALSE); + sprintf(buf2, "%s->",ot->name); + where = askcoords(buf, buf2, TT_MONSTER, user, maxrange, LOF_DONTNEED, B_FALSE); if (where) { if (!haslf(where)) { msg("There is nobody there!"); @@ -7123,14 +7382,16 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, e // ask for a target cell if (isplayer(caster)) { char buf[BUFLEN]; + char buf2[BUFLEN]; + objecttype_t *ot; + ot = findot(spellid); if (maxrange == UNLIMITED) { - objecttype_t *ot; - ot = findot(spellid); sprintf(buf, "Where will you target your %s?", ot->name); } else { - sprintf(buf, "Where will you target your spell [max range %d]?",maxrange); + sprintf(buf, "Where will you target your %s [max range %d]?",ot->name, maxrange); } - where = askcoords(buf, targtype, caster, maxrange, needlof, needlof ? B_TRUE : B_FALSE); + sprintf(buf2, "%s->",ot->name); + where = askcoords(buf, buf2, targtype, caster, maxrange, needlof, needlof ? B_TRUE : B_FALSE); if (!where) { int ch; ch = askchar("Abandon your spell?","yn","n", B_TRUE); diff --git a/spell.h b/spell.h index 2f0b6c0..651ae0c 100644 --- a/spell.h +++ b/spell.h @@ -25,6 +25,7 @@ int schoolappearsinbooks(enum SPELLSCHOOL ss); void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot); void stopspell(lifeform_t *caster, enum OBTYPE spellid); void stopallspells(lifeform_t *lf); +void stopallspellsexcept(lifeform_t *lf, ...); int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime); lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target); cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power, int frompot);