- [+] add autopop to playerstart vaults

- [+] rename magic skills:  Magic:Cold
- [+] bug: infinite loop in poison arrow trap - make sure the arrow
      always dies.
- [+] bug: c4 didn't kill iron door
- [+] implement stamina (float). max is Fit/2
    * [+] in startlfturn:
    - [+] sprinting drains this.
    - [+] ...then stop using f_sprinting for exhausted
    - [+] ...and remove f_tired
    - [+] if exhausted, stop sprinting. (in modstamina)
    - [+] change crushed windpipe
    - [+] f_stamcost for abilities.
        - [+] modify cancast.
    - [+] tumbling
    - [+] jumping
    - [+] rage
    - [+] swimming
        - [+] drains stamina like sprinting
        - [+] if stamina drops to 0, you start drowning.
    - [+] new spell:  lethargy (sets stamina to 0)
    - [+] if a sleep spell fails, use lethergy instead.
    - [+] no attacking while stam = 0 ???
- [+] need to update statbar right away when casting ongoing spells.
- [+] bug: reading an awareness scroll counting as an active spell!
- [+] genericise magic resistance check into a function
- [+] "disorient" - l1 mental spell which randomly turns lf, someitmes
      makes them dizzy
- [+] change stun - just means you can't attack, cast spell, use abils
* [+] AI shouldn't look for targets if stunned or no stamina
* [+] why do mosnters end up facing -1 (d_none) ??
- [+] turn undead problem.
    - [+] The skeleton turns to flee from you!  The skeleton bites you.
- [+] crit which spins you around (bash to body)
- [+] say "you attack xxx from behind" when you ar ebehidn them and
      they can't see you
    - [+] or "you attack the helpless xxx" when thye just can't see you 
- [+] genericise sacrifice text
- [+] fix up weight of heads (8% of body mass)
- [+] make attribss do more:
    - [+] iq:  determine how soon you learn new skills (ie. modify
          SKILLXPPERPOINT)
    - [+] fit: determines stamina points.
    - [+] wisdom >= AT_HIGH
        - [+] warn before wearing/eating/drinking/weilding unknown
              bad/cursed objects (low chance)
        - [+] use isbadobject()
        - [+] chance:
            - [+] high = 10%
            - [+] vhigh = 30%
            - [+] exhigh =  50%
- [-] idea:  sacrifice to gods to make them happier
    - [+] mercy: weapons
    - [+] death: any corpses
    - [+] thieves: gold
This commit is contained in:
Rob Pearce 2011-09-14 22:42:54 +00:00
parent 7370b60375
commit da656dfa52
28 changed files with 881 additions and 501 deletions

81
ai.c
View File

@ -36,6 +36,10 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
db = B_TRUE; db = B_TRUE;
} }
if (!canattack(lf)) {
return B_FALSE;
}
// mindless? // mindless?
if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) == IQ_MINDLESS) { if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) == IQ_MINDLESS) {
if (!isundead(lf)) { if (!isundead(lf)) {
@ -1331,19 +1335,8 @@ void aiturn(lifeform_t *lf) {
// to attack, etc) // to attack, etc)
/////////////////////////////////////////////// ///////////////////////////////////////////////
// look for any object which we want
/*
if (!isinbattle(lf)) {
if (db) dblog(".oO { looking for any ob which i want. }");
if (lookforobs(lf, B_ANY)) {
if (db) dblog(".oO { found ob that i want. returning. }");
return;
}
}
*/
// not attacking anyone in particular // not attacking anyone in particular
if (db) dblog(".oO { i do not have a target or can't move towards it. looking for one. }"); if (db) dblog(".oO { i do not have a target or can't move towards it. }");
// shopkeepers will return to their shops // shopkeepers will return to their shops
if (hasjob(lf, J_SHOPKEEPER)) { if (hasjob(lf, J_SHOPKEEPER)) {
@ -1364,33 +1357,36 @@ void aiturn(lifeform_t *lf) {
} }
} }
// look for any race which we hate if (!lfhasflag(lf, F_STUNNED)) {
newtarget = NULL; if (db) dblog(".oO { looking for a target . }");
for (n = 0; n < lf->nlos; n++) { // look for any race which we hate
lifeform_t *who; newtarget = NULL;
if (lf->los[n] != lf->cell) { for (n = 0; n < lf->nlos; n++) {
who = lf->los[n]->lf; lifeform_t *who;
if (who && cansee(lf, who)) { if (lf->los[n] != lf->cell) {
if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) || who = lf->los[n]->lf;
lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) { if (who && cansee(lf, who)) {
if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name); if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) ||
newtarget = who; lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) {
break; if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name);
newtarget = who;
break;
}
} }
} }
} }
} if (!newtarget) {
if (!newtarget) { // now look for enemies
// now look for enemies for (n = 0; n < lf->nlos; n++) {
for (n = 0; n < lf->nlos; n++) { if (lf->los[n] != lf->cell) {
if (lf->los[n] != lf->cell) { lifeform_t *who;
lifeform_t *who; who = lf->los[n]->lf;
who = lf->los[n]->lf; if (who && cansee(lf, who)) {
if (who && cansee(lf, who)) { if (areenemies(lf, who)) {
if (areenemies(lf, who)) { if (db) dblog(".oO { found an enemy target - lfid %d (%s) ! }",who->id, who->race->name);
if (db) dblog(".oO { found an enemy target - lfid %d (%s) ! }",who->id, who->race->name); newtarget = who;
newtarget = who; break;
break; }
} }
} }
} }
@ -1483,8 +1479,6 @@ void aiturn(lifeform_t *lf) {
dorandommove(lf, B_NOBADMOVES, B_TRUE); // this function will call rest() if we cant move dorandommove(lf, B_NOBADMOVES, B_TRUE); // this function will call rest() if we cant move
} }
// is the spell 'spellid' okay for AI lifeform 'lf' to cast at 'victim', for given purpose. // is the spell 'spellid' okay for AI lifeform 'lf' to cast at 'victim', for given purpose.
// purpose could be F_AICASTTOFLEE or F_ATCASTTOATTACK // purpose could be F_AICASTTOFLEE or F_ATCASTTOATTACK
int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG purpose) { int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG purpose) {
@ -1529,6 +1523,8 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
char why[BUFLEN]; char why[BUFLEN];
if (reason == E_NOMP) { if (reason == E_NOMP) {
strcpy(why, "not enough mp"); strcpy(why, "not enough mp");
} else if (reason == E_NOSTAM) {
strcpy(why, "not enough stamina");
} else if (reason == E_TOOPOWERFUL) { } else if (reason == E_TOOPOWERFUL) {
strcpy(why, "spell too powerful"); strcpy(why, "spell too powerful");
} else if (reason == E_NOTREADY) { } else if (reason == E_NOTREADY) {
@ -1756,7 +1752,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if ((ot->id == OT_S_SMITEEVIL) && (getalignment(victim) != AL_EVIL)) { if ((ot->id == OT_S_SMITEEVIL) && (getalignment(victim) != AL_EVIL)) {
specificcheckok = B_FALSE; specificcheckok = B_FALSE;
} }
if ((ot->id == OT_A_SPRINT) && lfhasflag(lf, F_SPRINTING)) { if ((ot->id == OT_A_SPRINT) && (lfhasflag(lf, F_SPRINTING) || !lf->stamina)) {
specificcheckok = B_FALSE; specificcheckok = B_FALSE;
} }
if ((ot->id == OT_A_STEAL) || (ot->id == OT_S_CONFISCATE)) { if ((ot->id == OT_A_STEAL) || (ot->id == OT_S_CONFISCATE)) {
@ -2073,6 +2069,13 @@ int lookforobs(lifeform_t *lf) {
return B_FALSE; return B_FALSE;
} }
int loseaitargets(lifeform_t *lf) {
int donesomething = B_FALSE;
if (killflagsofid(lf->flags, F_TARGETLF)) donesomething = B_TRUE;
if (killflagsofid(lf->flags, F_TARGETCELL)) donesomething = B_TRUE;
return donesomething;
}
void makewantedoblist(lifeform_t *lf, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet) { void makewantedoblist(lifeform_t *lf, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet) {
int i; int i;
flag_t *f; flag_t *f;

1
ai.h
View File

@ -23,5 +23,6 @@ lifeform_t *gettargetlf(lifeform_t *lf);
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op); object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op);
object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op); object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op);
int lookforobs(lifeform_t *lf); int lookforobs(lifeform_t *lf);
int loseaitargets(lifeform_t *lf);
void makewantedoblist(lifeform_t *lf, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet); void makewantedoblist(lifeform_t *lf, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet);
int useitemwithflag(lifeform_t *lf, enum FLAG whichflag); int useitemwithflag(lifeform_t *lf, enum FLAG whichflag);

View File

@ -17,6 +17,8 @@
extern lifeform_t *player; extern lifeform_t *player;
extern enum ERROR reason;
int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) { int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) {
object_t *armour = NULL; object_t *armour = NULL;
int damtaken = 0; int damtaken = 0;
@ -163,7 +165,6 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
int maxattacks = ALL; int maxattacks = ALL;
int attacksdone = 0; int attacksdone = 0;
int lastweaponidx = -1; int lastweaponidx = -1;
flag_t *sf;
int saysorry = B_FALSE; int saysorry = B_FALSE;
flag_t *retflag[MAXCANDIDATES]; flag_t *retflag[MAXCANDIDATES];
int nretflags = 0; int nretflags = 0;
@ -243,12 +244,24 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
} }
} }
// stop sprinting // can you actually attack?
sf = lfhasflag(lf, F_SPRINTING); if (!canattack(lf)) {
if (sf && sf->val[0]) { if (isplayer(lf)) {
killflag(sf); switch (reason) {
case E_NOSTAM: msg("You are too tired to fight at the moment."); break;
case E_STUNNED: msg("You are too stunned to fight at the moment."); break;
default: msg("For some reason, you cannot attack."); break;
}
}
return B_TRUE;
} }
// lose a tiny bit of stamina
modstamina(lf, -0.2);
// stop sprinting
stopsprinting(lf);
// ai code... // ai code...
if (lfhasflag(lf, F_DEMANDSBRIBE)) { if (lfhasflag(lf, F_DEMANDSBRIBE)) {
if (!isplayer(lf) && (attacktype == AT_LF) && isplayer((lifeform_t *)attacktarget)) { if (!isplayer(lf) && (attacktype == AT_LF) && isplayer((lifeform_t *)attacktarget)) {
@ -312,10 +325,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
innateattacks = countinnateattacks(lf); innateattacks = countinnateattacks(lf);
// stop sprinting // stop sprinting
f = lfhasflag(lf, F_SPRINTING); stopsprinting(lf);
if (f && f->val[0]) {
killflag(f);
}
// take time // take time
attacktime = getattackspeed(lf); attacktime = getattackspeed(lf);
@ -377,7 +387,6 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
} }
} }
// remember initial cells
attacksdone = 0; attacksdone = 0;
while (attacksdone < maxattacks) { while (attacksdone < maxattacks) {
@ -387,11 +396,26 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
if (!isdead((lifeform_t *)attacktarget)) { if (!isdead((lifeform_t *)attacktarget)) {
lifeform_t *victim; lifeform_t *victim;
victim = (lifeform_t *)attacktarget; victim = (lifeform_t *)attacktarget;
// did we just attack someone by accident? if (i == 0) {
if (!isplayer(lf) && !areenemies(lf, victim) && (lf->race->raceclass->id == RC_HUMANOID) && // did we just attack someone by accident?
(getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= A_LOW) ) { if (!isplayer(lf) && !areenemies(lf, victim) && (lf->race->raceclass->id == RC_HUMANOID) &&
saysorry = B_TRUE; (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= A_LOW) ) {
saysorry = B_TRUE;
}
// announce helpless attcaks
if (isplayer(lf) && attackedhelpless) {
char vname[BUFLEN];
getlfname(victim, vname);
if (isbehind(lf, victim)) {
msg("You attack %s from behind!", vname);
} else {
msg("You attack the helpless %s!", vname);
}
}
} }
if (attacklf(lf, victim, wep[i], damflag[i])) { if (attacklf(lf, victim, wep[i], damflag[i])) {
// failed // failed
attacksdone = maxattacks; attacksdone = maxattacks;
@ -1370,6 +1394,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) {
void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum DAMTYPE damtype) { void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum DAMTYPE damtype) {
object_t *o; object_t *o;
char lfname[BUFLEN],victimname[BUFLEN];
// replace some dam types // replace some dam types
if (damtype == DT_UNARMED) damtype = DT_BASH; if (damtype == DT_UNARMED) damtype = DT_BASH;
if (damtype == DT_BITE) damtype = DT_SLASH; if (damtype == DT_BITE) damtype = DT_SLASH;
@ -1380,7 +1405,20 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum
switch (hitpos) { switch (hitpos) {
default: default:
case BP_BODY: case BP_BODY:
if (pctchance(40)) fall(victim, lf, B_TRUE); if (pctchance(40)) {
// some kind of non-injury effect
switch (rnd(1,2)) {
case 1: fall(victim, lf, B_TRUE); break;
case 2:
if (cansee(player, lf) || cansee(player, victim)) {
getlfname(lf, lfname);
getlfname(victim, victimname);
setfacing(victim, getrandomdirexcept(DT_COMPASS, victim->facing));
msg("%s%s blow spins %s around!", lfname, getpossessive(lfname),victimname);
}
break;
}
}
if (!getarmour(victim, BP_BODY)) injure(victim, BP_BODY, damtype); if (!getarmour(victim, BP_BODY)) injure(victim, BP_BODY, damtype);
break; break;
case BP_HEAD: case BP_HEAD:

Binary file not shown.

28
defs.h
View File

@ -266,6 +266,7 @@ enum RELATIVEDIR {
#define CH_TURN_NE (21) // ctrl-u #define CH_TURN_NE (21) // ctrl-u
#define CH_TURN_SW (2) // ctrl-b #define CH_TURN_SW (2) // ctrl-b
#define CH_TURN_SE (14) // ctrl-n #define CH_TURN_SE (14) // ctrl-n
#define CH_HISTORY (16) // ctrl-p
// SPECIAL NUMBERS/CONSTANTS // SPECIAL NUMBERS/CONSTANTS
#define DUMMYCELLTYPE 0xabcd #define DUMMYCELLTYPE 0xabcd
@ -1157,9 +1158,11 @@ enum OBTYPE {
// -- mental / psionic // -- mental / psionic
OT_S_BAFFLE, OT_S_BAFFLE,
OT_S_CHARM, OT_S_CHARM,
OT_S_DISORIENT,
OT_S_HUNGER, OT_S_HUNGER,
OT_S_MINDSCAN, OT_S_LETHARGY,
OT_S_LOWERMETAB, OT_S_LOWERMETAB,
OT_S_MINDSCAN,
OT_S_PACIFY, OT_S_PACIFY,
OT_S_PSYARMOUR, OT_S_PSYARMOUR,
OT_S_SLEEP, OT_S_SLEEP,
@ -1681,6 +1684,8 @@ enum FLAG {
F_NEWWATERDEPTH, // temp flag for the spread of f_deepwater obs. F_NEWWATERDEPTH, // temp flag for the spread of f_deepwater obs.
// v0+1 are x/y, v2 is new depth. // v0+1 are x/y, v2 is new depth.
// object flags // object flags
F_BADOBJECT, // this object is dangerous. ie. potion of poison,
// potion of sleep, etc.
F_BEINGUSED, // this object is currently being used F_BEINGUSED, // this object is currently being used
F_DEAD, // object will be removed F_DEAD, // object will be removed
F_ONEPERCELL, // only one of these objects can exist per cell F_ONEPERCELL, // only one of these objects can exist per cell
@ -1985,7 +1990,8 @@ enum FLAG {
// for spells with this flag, the MP cost goes up // for spells with this flag, the MP cost goes up
// based on the power level. // based on the power level.
F_MAXPOWER, // val0 = max power of this spell (1-10) F_MAXPOWER, // val0 = max power of this spell (1-10)
F_MPCOST, // v0=mp cost of spell. if missing, mpcost if splev^2 F_MPCOST, // v0=mp cost of spell. if missing, mpcost is splev^2
F_STAMCOST, // v0=stamina cost of ability. default is 0.
F_ONGOING, // this spell has an ongoing cost F_ONGOING, // this spell has an ongoing cost
F_CASTINGTIME, // this spell takes v0 turns to cast F_CASTINGTIME, // this spell takes v0 turns to cast
F_EXTRADESC, // extra descriptions for this object F_EXTRADESC, // extra descriptions for this object
@ -2209,6 +2215,16 @@ enum FLAG {
// if v0 is b_true, means this is a goddess // if v0 is b_true, means this is a goddess
F_GODLIKES, // text = something this god likes (ie. incs piety) F_GODLIKES, // text = something this god likes (ie. incs piety)
F_GODDISLIKES, // text = something this god likes (ie. decs piety) F_GODDISLIKES, // text = something this god likes (ie. decs piety)
// for all sacrifice flags:
// v2: amt of piety for each sacrifice
// text: "the xxx disappears in yyyy"
// (yyyy is text)
// IS is replaced with "is" or "are"
// OB is replace with object name
F_SACRIFICEOBWITHFLAG, // v0 = can sacrifice obs with flag v0 to this go
F_SACRIFICEOB, // v0 = can sacrifice obtype v0 to this god
F_SACRIFICEOBCLASS, // v0 = can sacrifice obclass v0 to this god
F_NAME, // text = lf's name F_NAME, // text = lf's name
F_XPMOD, // add/subtract this much from calculated xpval F_XPMOD, // add/subtract this much from calculated xpval
F_BLOODOB, // text = type of object to drop for blood F_BLOODOB, // text = type of object to drop for blood
@ -2362,6 +2378,7 @@ enum FLAG {
F_SILENTMOVE, // lf makes no noise when walking/flying F_SILENTMOVE, // lf makes no noise when walking/flying
F_STABILITY, // doesn't slip over F_STABILITY, // doesn't slip over
F_STENCH, // creatures within v0 gain f_nauseated = v1 F_STENCH, // creatures within v0 gain f_nauseated = v1
F_STUNNED, // cannot attack or cast spells
F_TREMORSENSE, // doesn't need eyes to see, can see in dark with v0 F_TREMORSENSE, // doesn't need eyes to see, can see in dark with v0
F_TRUESTRIKE, // your attacks ALWAYS hit. turnsleft=v0 F_TRUESTRIKE, // your attacks ALWAYS hit. turnsleft=v0
F_PRODUCESLIGHT, // produces light of val0 radius. F_PRODUCESLIGHT, // produces light of val0 radius.
@ -2374,8 +2391,7 @@ enum FLAG {
F_SLOWACTMOVE, // modifier for move and action speed F_SLOWACTMOVE, // modifier for move and action speed
F_XRAYVIS, //val0=num of walls we can see through F_XRAYVIS, //val0=num of walls we can see through
F_CANSEETHROUGHMAT, //val0=kind of material you can see through F_CANSEETHROUGHMAT, //val0=kind of material you can see through
F_SPRINTING, // v0=true: you are sprinting. false=you are tired F_SPRINTING, // you are sprinting.
F_TIRED, // you are too tired to sprint, rage, etc
F_WINDSHIELD,// has a windshield protecting against missiles of speed F_WINDSHIELD,// has a windshield protecting against missiles of speed
// v0 or lower. // v0 or lower.
F_DODGES, // you dodge missed attacks F_DODGES, // you dodge missed attacks
@ -2580,6 +2596,7 @@ enum ERROR {
E_NOAMMO, E_NOAMMO,
E_GRAVBOOSTED, E_GRAVBOOSTED,
E_NOMP, E_NOMP,
E_NOSTAM,
E_AVOIDOB, E_AVOIDOB,
E_FROZEN, E_FROZEN,
E_TOOBIG, E_TOOBIG,
@ -2600,6 +2617,7 @@ enum ERROR {
E_LOWWIS, E_LOWWIS,
E_WONT, E_WONT,
E_OFFMAP, E_OFFMAP,
E_STUNNED,
// charm failure reasons // charm failure reasons
// LOWIQ // LOWIQ
E_UNDEAD, E_UNDEAD,
@ -2640,6 +2658,7 @@ enum COMMAND {
CMD_MAGIC, CMD_MAGIC,
CMD_MEMMAGIC, CMD_MEMMAGIC,
CMD_MSGHIST, CMD_MSGHIST,
CMD_OFFER,
CMD_OPERATE, CMD_OPERATE,
CMD_PICKLOCK, CMD_PICKLOCK,
CMD_PICKUP, CMD_PICKUP,
@ -2910,6 +2929,7 @@ typedef struct lifeform_s {
int skillpoints; int skillpoints;
int hp,maxhp; int hp,maxhp;
int mp,maxmp; int mp,maxmp;
float stamina;
int alive; int alive;
char *lastdam; char *lastdam;
struct material_s *material; struct material_s *material;

View File

@ -1,3 +1,7 @@
NOTE:
- make sure god names all start with different letters
- keep addlf() calls for gods in alphabetical order
In defs.h In defs.h
Add R_GODxxxx Add R_GODxxxx
update MAXGODS update MAXGODS

View File

@ -43,8 +43,8 @@ hybrid human animal?
---------- ----------
~ = deep liquid (water / lava) ~ = deep liquid (water / lava)
[ = tool ] = tool
] = armour [ = armour
} = gas } = gas
, = small puddle , = small puddle
{ = large puddle/pool { = large puddle/pool

49
flag.c
View File

@ -392,7 +392,6 @@ int flagcausesredraw(lifeform_t *lf, enum FLAG fid) {
case F_AWARENESS: case F_AWARENESS:
case F_SPRINTING: case F_SPRINTING:
case F_SLOWMOVE: case F_SLOWMOVE:
case F_TIRED:
return B_TRUE; return B_TRUE;
default: default:
break; break;
@ -436,7 +435,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) {
case F_RAGE: case F_RAGE:
case F_SPRINTING: case F_SPRINTING:
case F_SLOWMOVE: case F_SLOWMOVE:
case F_TIRED: case F_STUNNED:
case F_TRAINING: case F_TRAINING:
return B_TRUE; return B_TRUE;
default: default:
@ -982,18 +981,6 @@ void timeeffectsflag(flag_t *f, int howlong) {
break; break;
} }
} }
} else if (f->lifetime == 3) {
if (isplayer(f->pile->owner)) {
switch (f->id) {
case F_SPRINTING:
if (f->val[0]) {
warn("You will have to stop sprinting soon...");
}
break;
default:
break;
}
}
} else if (f->lifetime == 2) { } else if (f->lifetime == 2) {
if (isplayer(f->pile->owner)) { if (isplayer(f->pile->owner)) {
switch (f->id) { switch (f->id) {
@ -1042,40 +1029,6 @@ void timeeffectsflag(flag_t *f, int howlong) {
break; break;
} }
} }
// sprinting is special
if (f->id == F_SPRINTING) {
if (f->val[0]) {
enum SKILLLEVEL slev;
lifeform_t *who;
int tiredtime;
who = f->pile->owner;
// now you get slow
// you get tired when you finish sprinting
tiredtime = 15;
// adjust for athletics skill. -2 per level.
slev = getskill(who, SK_ATHLETICS);
if (slev != PR_INEPT) {
tiredtime -= (2*slev);
}
// adjust for constitution
tiredtime = tiredtime - (int) ((float)tiredtime * (getstatmod(who, A_CON) / 100) );
// enforce minimum
if (tiredtime < 1) tiredtime = 1;
f->val[0] = B_FALSE;
f->lifetime = tiredtime;
if (isplayer(who)) {
msg("You are exhausted.");
} else if (cansee(player, who)) {
char lfname[BUFLEN];
getlfname(who, lfname);
msg("%s looks exhausted.",lfname);
}
needredraw = B_TRUE;
statdirty = B_TRUE;
}
}
} }
} }

292
io.c
View File

@ -1586,13 +1586,9 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
msg("%s %s sprinting!",lfname, isplayer(lf) ? "start" : "starts"); msg("%s %s sprinting!",lfname, isplayer(lf) ? "start" : "starts");
donesomething = B_TRUE; donesomething = B_TRUE;
break; break;
case F_STUNNED:
case F_TIRED: msg("%s %s stunned!",lfname, is(lf));
if (isplayer(lf)) { donesomething = B_TRUE;
msg("You are exhausted.");
} else if (cansee(player, lf)) {
msg("%s looks exhausted.",lfname);
}
break; break;
case F_TREMORSENSE: case F_TREMORSENSE:
if (isplayer(lf)) { // don't know if monsters get it if (isplayer(lf)) { // don't know if monsters get it
@ -2131,25 +2127,13 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE; donesomething = B_TRUE;
break; break;
case F_SPRINTING: case F_SPRINTING:
if (f->val[0]) { if (isplayer(lf)) { // don't know if monsters lose it (but you'll see them get exhausted)
if (isplayer(lf)) { // don't know if monsters lose it (but you'll see them get exhausted) msg("You stop sprinting.");
msg("You stop sprinting."); donesomething = B_TRUE;
donesomething = B_TRUE;
}
} else {
if (isplayer(lf)) { // don't know if monsters get it
msg("You are no longer exhausted.");
} else {
msg("%s looks less exhausted.",lfname);
}
} }
break; break;
case F_TIRED: case F_STUNNED:
if (isplayer(lf)) { // don't know if monsters get it msg("%s %s no longer stunned.",lfname, is(lf));
msg("You are no longer exhausted.");
} else {
msg("%s looks less exhausted.",lfname);
}
donesomething = B_TRUE; donesomething = B_TRUE;
break; break;
case F_TREMORSENSE: case F_TREMORSENSE:
@ -2317,6 +2301,35 @@ void announceobflagloss(object_t *o, flag_t *f) {
} }
int confirm_badfeeling(void) {
char ch;
ch = askchar("You have a bad feeling about this. Continue?", "yn", "n", B_TRUE);
if (ch == 'y') return B_TRUE;
return B_FALSE;
}
lifeform_t *askgod(char *prompttext) {
lifeform_t *lf = NULL;
int i;
initprompt(&prompt, prompttext);
prompt.maycancel = B_TRUE;
for (i = 0 ; i < ngodlfs; i++) {
flag_t *f;
char godof[BUFLEN],buf[BUFLEN];
lf = godlf[i];
real_getlfname(lf, buf, B_FALSE);
f = hasflag(lf->flags, F_GODOF);
snprintf(godof, BUFLEN, " (%s of %s)", (f->val[0] == B_FEMALE) ? "Goddess" : "God", f->text);
strcat(buf, godof);
addchoice(&prompt, tolower(buf[0]), buf, NULL, lf);
}
getchoice(&prompt);
lf = (lifeform_t *)prompt.result;
return lf;
}
object_t *askobject(obpile_t *op, char *prompt, int *count, long opts) { object_t *askobject(obpile_t *op, char *prompt, int *count, long opts) {
return doaskobject(op, prompt, count, B_TRUE, B_FALSE, opts, F_NONE); return doaskobject(op, prompt, count, B_TRUE, B_FALSE, opts, F_NONE);
} }
@ -3062,10 +3075,10 @@ void describegod(lifeform_t *god) {
char godname[BUFLEN]; char godname[BUFLEN];
char goddesc[BUFLEN]; char goddesc[BUFLEN];
int i; int i;
flag_t *f; flag_t *f, *retflag[MAXCANDIDATES];
flag_t *retflag[MAXCANDIDATES];
int nretflags; int nretflags;
cls(); cls();
assert(god);
f = hasflag(god->flags, F_GODOF); f = hasflag(god->flags, F_GODOF);
real_getlfname(god, godname, B_FALSE); real_getlfname(god, godname, B_FALSE);
@ -3105,6 +3118,28 @@ void describegod(lifeform_t *god) {
} }
wprintw(mainwin, ".\n\n"); wprintw(mainwin, ".\n\n");
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_SACRIFICEOBCLASS, F_NONE);
if (nretflags == 0) {
wprintw(mainwin, "%s does not accept sacrifices.\n", godname);
} else {
int i;
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOBCLASS, F_NONE);
for (i = 0; i < nretflags; i++) {
objectclass_t *oc;
oc = findoc(retflag[i]->val[0]);
wprintw(mainwin, "%s accepts the sacrifice of all %s.\n",godname, oc->name);
}
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_NONE);
for (i = 0; i < nretflags; i++) {
objecttype_t *ot;
if (i == 0) {
wprintw(mainwin, "%s accepts the sacrifice of:\n", godname);
}
ot = findot(retflag[i]->val[0]);
wprintw(mainwin, "- %s\n", ot->name);
}
}
wrefresh(mainwin); wrefresh(mainwin);
// wait for key // wait for key
@ -3879,9 +3914,6 @@ void describeob(object_t *o) {
case F_WINDSHIELD: case F_WINDSHIELD:
mvwprintw(mainwin, y, 0, "%s will surround you with a cyclonic shield.", buf); y++; mvwprintw(mainwin, y, 0, "%s will surround you with a cyclonic shield.", buf); y++;
break; break;
case F_TIRED:
mvwprintw(mainwin, y, 0, "%s make you tired.", buf); y++;
break;
case F_VISRANGEMOD: case F_VISRANGEMOD:
mvwprintw(mainwin, y, 0, "%s %s your vision range.", buf, (f->val[1] > 0) ? "increases" : "descreases"); y++; mvwprintw(mainwin, y, 0, "%s %s your vision range.", buf, (f->val[1] > 0) ? "increases" : "descreases"); y++;
break; break;
@ -4677,7 +4709,7 @@ void dodrop(obpile_t *op, int wantmulti, obpile_t *dst) {
} }
void doeat(obpile_t *op) { void doeat(obpile_t *op) {
object_t *o; object_t *o,*eatob = NULL;
char ch; char ch;
char buf[BUFLEN]; char buf[BUFLEN];
char obname[BUFLEN]; char obname[BUFLEN];
@ -4698,20 +4730,27 @@ void doeat(obpile_t *op) {
(o->amt == 1) ? "it" : "one"); (o->amt == 1) ? "it" : "one");
ch = askchar(buf, "yn","n", B_TRUE); ch = askchar(buf, "yn","n", B_TRUE);
if (ch == 'y') { if (ch == 'y') {
eat(player, o); eatob = o;
return;
} }
} }
} }
if (!hasedibleob(player->pack)) { if (!eatob) {
msg("You have nothing to eat!"); if (!hasedibleob(player->pack)) {
return; msg("You have nothing to eat!");
} return;
}
o = askobject(op, "Eat what", NULL, AO_EDIBLE); eatob = askobject(op, "Eat what", NULL, AO_EDIBLE);
if (o) { }
eat(player, o); if (eatob) {
if (isunknownbadobject(eatob) && skillcheck(player, A_WIS, 26, 0)) {
if (!confirm_badfeeling()) {
msg("Cancelled.");
return;
}
}
eat(player, eatob);
} }
} }
@ -4824,6 +4863,12 @@ int dowear(obpile_t *op) {
int rv; int rv;
o = askobject(op, "Wear what", NULL, AO_WEARABLE); o = askobject(op, "Wear what", NULL, AO_WEARABLE);
if (o) { if (o) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, 26, 0)) {
if (!confirm_badfeeling()) {
msg("Cancelled.");
return B_TRUE;
}
}
wear(player, o); wear(player, o);
} else { } else {
msg("Cancelled."); msg("Cancelled.");
@ -4840,6 +4885,12 @@ int doweild(obpile_t *op) {
int rv; int rv;
o = askobject(op, "Weild what", &count, AO_WEILDABLE | AO_INCLUDENOTHING); o = askobject(op, "Weild what", &count, AO_WEILDABLE | AO_INCLUDENOTHING);
if (o) { if (o) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, 26, 0)) {
if (!confirm_badfeeling()) {
msg("Cancelled.");
return B_TRUE;
}
}
rv = weild(player, o); rv = weild(player, o);
} else if (reason == E_SELNOTHING) { } else if (reason == E_SELNOTHING) {
// ie. unweild // ie. unweild
@ -5301,6 +5352,71 @@ void domsghist(void) {
restoregamewindows(); restoregamewindows();
} }
void dooffer(void) {
object_t *o, *nexto;
lifeform_t *god;
flag_t *retflag[MAXCANDIDATES];
int nretflags,pietyplus = 0;
// which god?
god = askgod("To whom will you sacrifice?");
if (!god) {
msg("Cancelled.");
return;
}
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_SACRIFICEOBCLASS, F_SACRIFICEOBWITHFLAG, F_NONE);
if (nretflags == 0) {
msg("%s does not accept sacrifices.", god->race->name);
return;
}
// anything here to offer?
for (o = player->cell->obpile->first ; o ; o = nexto) {
nexto = o->next;
// does the god want this?
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_SACRIFICEOBCLASS, F_SACRIFICEOBWITHFLAG, F_NONE);
int i;
for (i = 0; i < nretflags; i++) {
int ok = B_FALSE;
int thispiety = 0;
flag_t *f;
f = retflag[i];
if ((f->id == F_SACRIFICEOB) && (f->val[0] == o->type->id)) {
ok = B_TRUE;
thispiety = f->val[2];
} else if ((f->id == F_SACRIFICEOBCLASS) && (f->val[0] == o->type->obclass->id)) {
ok = B_TRUE;
thispiety = f->val[2];
} else if ((f->id == F_SACRIFICEOBWITHFLAG) && hasflag(o->flags, f->val[0])) {
ok = B_TRUE;
thispiety = f->val[2];
}
if (ok) {
char *p;
char obname[BUFLEN];
getobname(o, obname, ALL);
p = strdup(f->text);
p = strrep(p, "OB", obname, NULL);
if (o->amt == 1) {
p = strrep(p, "IS", "is", NULL);
} else {
p = strrep(p, "IS", "are", NULL);
}
msg("%s", p);
free(p);
removeob(o, ALL);
pietyplus += thispiety;
}
}
}
if (pietyplus) {
pleasegod(god->race->id, pietyplus);
} else {
nothinghappens();
}
taketime(player, getactspeed(player));
}
void dooperate(obpile_t *op) { void dooperate(obpile_t *op) {
object_t *o; object_t *o;
@ -5542,32 +5658,14 @@ void dohelp(char helpmode) {
describeskill(sk->id); describeskill(sk->id);
} }
} else if (helpmode == 'g') { } else if (helpmode == 'g') {
int i; lifeform_t *god;
centre(mainwin,C_WHITE, 0, "GOD REFERENCE"); centre(mainwin,C_WHITE, 0, "GOD REFERENCE");
y = 2; y = 2;
initprompt(&prompt, "Describe which god (ESC when done)?"); god = askgod("Describe which god (ESC when done)?");
for (i = 0 ; i < ngodlfs; i++) { if (!god) {
lifeform_t *lf;
flag_t *f;
char buf[BUFLEN];
char godof[BUFLEN];
lf = godlf[i];
real_getlfname(lf, buf, B_FALSE);
f = hasflag(lf->flags, F_GODOF);
snprintf(godof, BUFLEN, " (%s of %s)", (f->val[0] == B_FEMALE) ? "Goddess" : "God", f->text);
strcat(buf, godof);
addchoice(&prompt, 'a', buf, NULL, lf);
}
addchoice(&prompt, '\0', "(done)", NULL, NULL);
prompt.maycancel = B_TRUE;
ch = getchoicestr(&prompt, B_FALSE, B_TRUE);
if (!ch) {
done = B_TRUE; done = B_TRUE;
} else { } else {
lifeform_t *god;
god = (lifeform_t *)prompt.result;
describegod(god); describegod(god);
} }
} }
@ -5629,7 +5727,14 @@ void doquaff(obpile_t *op) {
} }
if (liquid) { if (liquid) {
if (canquaff(player, liquid)) { if (canquaff(player, liquid)) {
if (isunknownbadobject(liquid) && skillcheck(player, A_WIS, 26, 0)) {
if (!confirm_badfeeling()) {
msg("Cancelled.");
return;
}
}
quaff(player, liquid); quaff(player, liquid);
} else { } else {
switch (reason) { switch (reason) {
case E_INSUBSTANTIAL: case E_INSUBSTANTIAL:
@ -6359,7 +6464,7 @@ void dumpspells(void) {
for (ot = objecttype ; ot ; ot = ot->next) { for (ot = objecttype ; ot ; ot = ot->next) {
if (ot->obclass->id == OC_SPELL) { if (ot->obclass->id == OC_SPELL) {
// matches the current school & level? // matches the current school & level?
if ((getspellschool(ot->id) == ss) && (getspelllevel(ot->id) == lev)) { if (hasflagval(ot->flags, F_SPELLSCHOOL, ss, NA, NA, NULL) && (getspelllevel(ot->id) == lev)) {
dblog("\t\t%s", ot->name); dblog("\t\t%s", ot->name);
} }
} }
@ -7093,7 +7198,8 @@ void handleinput(void) {
case ':': // look at what's here case ':': // look at what's here
dolook(player->cell, B_TRUE); dolook(player->cell, B_TRUE);
break; break;
case '|': // msg history - TODO: replace with ctrl-p case CH_HISTORY:
case '|': // msg history
domsghist(); domsghist();
break; break;
case '/': // explain object case '/': // explain object
@ -7190,6 +7296,9 @@ void handleinput(void) {
addflag(player->flags, F_LASTCMD, NA, NA, NA, temp); addflag(player->flags, F_LASTCMD, NA, NA, NA, temp);
dooperate(player->pack); dooperate(player->pack);
break; break;
case 'O':
dooffer();
break;
// GAME FUNCTIONS // GAME FUNCTIONS
case 'Q': // quit case 'Q': // quit
doquit(); doquit();
@ -7481,6 +7590,13 @@ void drawstatus(void) {
wprintw(statwin, "- "); wprintw(statwin, "- ");
} }
// stamina
wattron(statwin, A_BOLD); wprintw(statwin, "SP:"); wattroff(statwin, A_BOLD);
setcol(statwin, getpctcol((int)player->stamina, (int)getmaxstamina(player)));
wprintw(statwin, "%d",(int)player->stamina);
unsetcol(statwin, getpctcol((int)player->stamina, (int)getmaxstamina(player)));
wprintw(statwin, "/%d ",(int)getmaxstamina(player));
wattron(statwin, A_BOLD); wprintw(statwin, "Xp:"); wattroff(statwin, A_BOLD); wattron(statwin, A_BOLD); wprintw(statwin, "Xp:"); wattroff(statwin, A_BOLD);
snprintf(buf, BUFLEN, "%d", player->level); snprintf(buf, BUFLEN, "%d", player->level);
@ -7547,6 +7663,11 @@ void drawstatus(void) {
wprintw(statwin, " Woozy"); wprintw(statwin, " Woozy");
unsetcol(statwin, C_YELLOW); unsetcol(statwin, C_YELLOW);
} }
if (lfhasflag(player, F_STUNNED)) {
setcol(statwin, C_YELLOW);
wprintw(statwin, " Stunned");
unsetcol(statwin, C_YELLOW);
}
// paralysed somehow? // paralysed somehow?
if (isresting(player)) { if (isresting(player)) {
@ -8126,10 +8247,17 @@ void showlfstats(lifeform_t *lf, int showall) {
if (showall || if (showall ||
(getseenlfconditioncutoff(player) == C_HEALTHY) || (getseenlfconditioncutoff(player) == C_HEALTHY) ||
(lorelev >= PR_ADEPT)) { (lorelev >= PR_ADEPT)) {
doheadingsmall(mainwin, y, 0, ftext, "Hit Points"); int xx,yy;
doheadingsmall(mainwin, y, 0, ftext, "HP");
if (lorelev >= PR_ADEPT) setcol(mainwin, lorecol); if (lorelev >= PR_ADEPT) setcol(mainwin, lorecol);
wprintw(mainwin, "%d / %d", lf->hp , lf->maxhp); y++; wprintw(mainwin, "%d/%d ", lf->hp , lf->maxhp);
if (lorelev >= PR_ADEPT) unsetcol(mainwin, lorecol); if (lorelev >= PR_ADEPT) unsetcol(mainwin, lorecol);
getyx(mainwin, yy, xx);
doheadingsmall(mainwin, y, xx, "%5s:", "Stam");
wprintw(mainwin, " %d/%d", (int)lf->stamina , (int)getmaxstamina(lf));
y++;
} else { } else {
char hpinfo[BUFLEN]; char hpinfo[BUFLEN];
snprintf(hpinfo, BUFLEN, "%s",getseenlfconditionname(lf, player)); snprintf(hpinfo, BUFLEN, "%s",getseenlfconditionname(lf, player));
@ -8137,10 +8265,10 @@ void showlfstats(lifeform_t *lf, int showall) {
doheadingsmall(mainwin, y, 0, ftext, "Hit Points"); doheadingsmall(mainwin, y, 0, ftext, "Hit Points");
wprintw(mainwin, "%s", hpinfo); y++; wprintw(mainwin, "%s", hpinfo); y++;
} }
} }
if (showall) { if (showall) {
char maxmpstr[BUFLEN]; char maxmpstr[BUFLEN];
if (getmaxmp(lf) == lf->maxmp) { if (getmaxmp(lf) == lf->maxmp) {
strcpy(maxmpstr, ""); strcpy(maxmpstr, "");
} else { } else {
@ -8148,7 +8276,8 @@ void showlfstats(lifeform_t *lf, int showall) {
} }
doheadingsmall(mainwin, y, 0, ftext, "Mana"); doheadingsmall(mainwin, y, 0, ftext, "Mana");
wprintw(mainwin, "%d / %d%s", lf->mp , lf->maxmp,maxmpstr); y++; wprintw(mainwin, "%d / %d%s ", lf->mp , lf->maxmp,maxmpstr);
y++;
} }
if (showall) { if (showall) {
if (isplayer(lf)) { if (isplayer(lf)) {
@ -8166,7 +8295,7 @@ void showlfstats(lifeform_t *lf, int showall) {
int attpoints; int attpoints;
int pct; int pct;
attpoints = getattpoints(lf); attpoints = getattpoints(lf);
doheadingsmall(mainwin, y, 0, ftext, "Training"); doheadingsmall(mainwin, y, 0, ftext, "Skill Pts");
pct = ((float)lf->skillxp / (float)SKILLXPPERPOINT) * 100.0; pct = ((float)lf->skillxp / (float)SKILLXPPERPOINT) * 100.0;
limit(&pct, 0, 100); limit(&pct, 0, 100);
if (lf->skillpoints || attpoints ) { if (lf->skillpoints || attpoints ) {
@ -8176,7 +8305,7 @@ void showlfstats(lifeform_t *lf, int showall) {
attpoints, attpoints,
(attpoints == 1) ? "" : "s"); (attpoints == 1) ? "" : "s");
*/ */
wprintw(mainwin, "%d skill point%s, ", lf->skillpoints, wprintw(mainwin, "%d point%s, ", lf->skillpoints,
(lf->skillpoints == 1) ? "" : "s"); (lf->skillpoints == 1) ? "" : "s");
} }
wprintw(mainwin, "%d%%", pct); wprintw(mainwin, "%d%%", pct);
@ -8420,6 +8549,7 @@ void showlfstats(lifeform_t *lf, int showall) {
// ARMOUR STUFF // ARMOUR STUFF
if (showall || (lorelev >= PR_NOVICE)) { if (showall || (lorelev >= PR_NOVICE)) {
int min,max;
//int min,max; //int min,max;
arating = getarmourrating(lf, NULL, NULL, NULL); arating = getarmourrating(lf, NULL, NULL, NULL);
//min = pctof(25, arating); //min = pctof(25, arating);
@ -8434,11 +8564,10 @@ void showlfstats(lifeform_t *lf, int showall) {
} }
*/ */
if (lorelev >= PR_NOVICE) setcol(mainwin, lorecol); if (lorelev >= PR_NOVICE) setcol(mainwin, lorecol);
if (arating == 0) { getarrange(arating, &min, &max);
if (max <= 0) {
wprintw(mainwin, "%d (no dmgreduce)", arating); y2++; wprintw(mainwin, "%d (no dmgreduce)", arating); y2++;
} else { } else {
int min,max;
getarrange(arating, &min, &max);
wprintw(mainwin, "%d (dmgreduce %d-%d)", arating, min, max); y2++; wprintw(mainwin, "%d (dmgreduce %d-%d)", arating, min, max); y2++;
} }
if (lorelev >= PR_NOVICE) unsetcol(mainwin, lorecol); if (lorelev >= PR_NOVICE) unsetcol(mainwin, lorecol);
@ -8689,11 +8818,11 @@ void showlfstats(lifeform_t *lf, int showall) {
} }
f = lfhasknownflag(lf, F_SPRINTING); f = lfhasknownflag(lf, F_SPRINTING);
if (f) { if (f) {
if (f->val[0]) { wrapprint(mainwin, &y, &x, "%s %s sprinting.", you(lf), is(lf));
wrapprint(mainwin, &y, &x, "%s %s sprinting.", you(lf), is(lf)); }
} else {
wrapprint(mainwin, &y, &x, "%s %s exhausted.", you(lf), is(lf)); if (lf->stamina == 0) {
} wrapprint(mainwin, &y, &x, "%s %s exhausted.", you(lf), is(lf));
} }
f = lfhasknownflag(lf, F_UNDEAD); f = lfhasknownflag(lf, F_UNDEAD);
@ -9549,12 +9678,6 @@ void showlfstats(lifeform_t *lf, int showall) {
} }
y++; y++;
} }
f = lfhasknownflag(lf, F_TIRED);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s tired.", you(lf), is(lf));
y++;
}
f = lfhasflag(lf, F_RISEASGHOST); f = lfhasflag(lf, F_RISEASGHOST);
if (f && (f->known)) { if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s will rise as a ghost after death.", you(lf)); mvwprintw(mainwin, y, 0, "%s will rise as a ghost after death.", you(lf));
@ -9578,6 +9701,11 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, "%s smell%s terrible.", you(lf), isplayer(lf) ? "" : "s"); mvwprintw(mainwin, y, 0, "%s smell%s terrible.", you(lf), isplayer(lf) ? "" : "s");
y++; y++;
} }
f = lfhasflag(lf, F_STUNNED);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s stunned and cannot attack, cast spells or use abilities.", you(lf), is(lf));
y++;
}
if (!isblind(lf)) { if (!isblind(lf)) {
f = lfhasknownflag(lf, F_SEEINDARK); f = lfhasknownflag(lf, F_SEEINDARK);

3
io.h
View File

@ -16,6 +16,8 @@ int announceflaggain(lifeform_t *lf, flag_t *f);
int announceflagloss(lifeform_t *lf, flag_t *f); int announceflagloss(lifeform_t *lf, flag_t *f);
int announceobflaggain(object_t *o, flag_t *f); int announceobflaggain(object_t *o, flag_t *f);
void announceobflagloss(object_t *o, flag_t *f); void announceobflagloss(object_t *o, flag_t *f);
int confirm_badfeeling(void);
lifeform_t *askgod(char *prompt);
object_t *askobject(obpile_t *op, char *title, int *count, long opts); object_t *askobject(obpile_t *op, char *title, int *count, long opts);
object_t *askobjectwithflag(obpile_t *op, char *title, int *count, long opts, enum FLAG withflag); object_t *askobjectwithflag(obpile_t *op, char *title, int *count, long opts, enum FLAG withflag);
object_t *doaskobject(obpile_t *op, char *title, int *count, int forpickup, int showpoints, long opts, ...); object_t *doaskobject(obpile_t *op, char *title, int *count, int forpickup, int showpoints, long opts, ...);
@ -53,6 +55,7 @@ void dolook(cell_t *where, int onpurpose);
void domagic(enum OBTYPE spellid, int cellx, int celly); void domagic(enum OBTYPE spellid, int cellx, int celly);
void domemmagic(void); void domemmagic(void);
void domsghist(void); void domsghist(void);
void dooffer(void);
void dooperate(obpile_t *op); void dooperate(obpile_t *op);
int dopickup(obpile_t *op, int forceask); int dopickup(obpile_t *op, int forceask);
void dolockpick(obpile_t *op); void dolockpick(obpile_t *op);

381
lf.c
View File

@ -487,12 +487,27 @@ void callguards(lifeform_t *caller, lifeform_t *victim) {
} }
} }
int canattack(lifeform_t *lf) {
if (!lf->stamina) {
reason = E_NOSTAM;
return B_FALSE;
} else if (lfhasflag(lf, F_STUNNED)) {
reason = E_STUNNED;
return B_FALSE;
}
return B_TRUE;
}
int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
int castable = B_FALSE; int castable = B_FALSE;
flag_t *f; flag_t *f;
objecttype_t *ot; objecttype_t *ot;
// TODO: check for mute? // TODO: check for mute?
if (lfhasflag(lf, F_STUNNED)) {
reason = E_STUNNED;
return B_FALSE;
}
if (isprone(lf)) { if (isprone(lf)) {
reason = E_PRONE; reason = E_PRONE;
return B_FALSE; return B_FALSE;
@ -559,6 +574,12 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
} }
f = hasflag(ot->flags, F_STAMCOST);
if (f && (lf->stamina < f->val[0])) {
reason = E_NOSTAM;
return B_FALSE;
}
return castable; return castable;
} }
@ -1198,6 +1219,9 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
case E_SWIMMING: case E_SWIMMING:
msg("You can't cast spells while swimming."); msg("You can't cast spells while swimming.");
break; break;
case E_STUNNED:
msg("You can't cast spells while stunned.");
break;
default: default:
msg("For some reason, you can't cast that."); msg("For some reason, you can't cast that.");
break; break;
@ -1516,7 +1540,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) {
} }
losehp(lf, roll("6d6"), DT_DIRECT, NULL, "running water"); losehp(lf, roll("6d6"), DT_DIRECT, NULL, "running water");
} }
if (!slev && !lfhasflag(lf, F_BREATHWATER)) { if ((!slev || !lf->stamina) && !lfhasflag(lf, F_BREATHWATER) ) {
int damamt; int damamt;
// take drowning damage. generally you'll die // take drowning damage. generally you'll die
@ -3008,7 +3032,7 @@ void enhanceskills(lifeform_t *lf) {
cost = getskilllevcost(f->val[1] + 1); cost = getskilllevcost(f->val[1] + 1);
if (lf->skillpoints >= cost) { if (lf->skillpoints >= cost) {
char buf[BUFLEN]; char buf[BUFLEN];
snprintf(buf, BUFLEN, "%s (%s, %d points)", getskillname(f->val[0]), snprintf(buf, BUFLEN, "%s (%s, cost:%d points)", getskillname(f->val[0]),
getskilllevelname(f->val[1] + 1), cost); getskilllevelname(f->val[1] + 1), cost);
addchoice(&prompt, ch++, getskillname(f->val[0]), buf, f); addchoice(&prompt, ch++, getskillname(f->val[0]), buf, f);
} }
@ -3378,10 +3402,12 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) {
} }
// turn to face our attacker // turn to face our attacker
if (isadjacent(lf->cell, attacker->cell)) { if (!lfhasflag(lf, F_STUNNED)) {
turntoface(lf, attacker->cell); if (isadjacent(lf->cell, attacker->cell)) {
turntoface(lf, attacker->cell);
}
aiattack(lf, attacker, DEF_AIFOLLOWTIME);
} }
aiattack(lf, attacker, DEF_AIFOLLOWTIME);
// any nearby monsters which will help out? // any nearby monsters which will help out?
if (getallegiance(lf) != AL_FRIENDLY) { if (getallegiance(lf) != AL_FRIENDLY) {
@ -3570,13 +3596,15 @@ int flee(lifeform_t *lf) {
real_getlfname(lf, lfname, B_FALSE); real_getlfname(lf, lfname, B_FALSE);
// mindless?
if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) == IQ_MINDLESS) {
return B_FALSE;
}
// are we fleeing? // are we fleeing?
getflags(lf->flags, retflag, &nretflags, F_FLEEFROM, F_NONE); getflags(lf->flags, retflag, &nretflags, F_FLEEFROM, F_NONE);
// mindless?
if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) == IQ_MINDLESS) {
if (!nretflags) return B_FALSE;
}
for (i = 0; i < nretflags; i++) { for (i = 0; i < nretflags; i++) {
f = retflag[i]; f = retflag[i];
if (f->id == F_FLEEFROM) { if (f->id == F_FLEEFROM) {
@ -3717,8 +3745,7 @@ void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong, int onpurpose) {
} }
// stop targetting anyone or going anywhere // stop targetting anyone or going anywhere
killflagsofid(lf->flags, F_TARGETLF); loseaitargets(lf);
killflagsofid(lf->flags, F_TARGETCELL);
} }
int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong) { int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong) {
@ -3905,11 +3932,17 @@ void gainxp(lifeform_t *lf, long amt) {
// skill xp // skill xp
if (isplayer(lf)) { if (isplayer(lf)) {
int amtneeded;
int mod;
mod = getstatmod(lf, A_IQ);
amtneeded = pctof(100 + mod, SKILLXPPERPOINT);
lf->skillxp += amt; lf->skillxp += amt;
assert(lf->skillxp >= 0); assert(lf->skillxp >= 0);
while (lf->skillxp >= SKILLXPPERPOINT) { while (lf->skillxp >= amtneeded) {
newskillpoints++; newskillpoints++;
lf->skillxp -= SKILLXPPERPOINT; lf->skillxp -= amtneeded;
if (isplayer(lf)) statdirty = B_TRUE; if (isplayer(lf)) statdirty = B_TRUE;
} }
} }
@ -5679,6 +5712,10 @@ float getmaxpushweight(lifeform_t *lf) {
return max; return max;
} }
float getmaxstamina(lifeform_t *lf) {
return (getattr(lf, A_CON) / 2);
}
int getmr(lifeform_t *lf) { int getmr(lifeform_t *lf) {
int amt = 0; int amt = 0;
@ -5756,7 +5793,7 @@ int getmovespeed(lifeform_t *lf) {
// modifier? // modifier?
getflags(lf->flags, retflag, &nretflags, F_FASTMOVE, F_FASTACTMOVE, F_INJURY, F_SLOWMOVE, getflags(lf->flags, retflag, &nretflags, F_FASTMOVE, F_FASTACTMOVE, F_INJURY, F_SLOWMOVE,
F_SLOWACTMOVE, F_SPRINTING, F_TIRED, F_NONE); F_SLOWACTMOVE, F_SPRINTING, F_NONE);
for (i = 0; i < nretflags; i++) { for (i = 0; i < nretflags; i++) {
f = retflag[i]; f = retflag[i];
if ((f->id == F_SLOWMOVE) || (f->id == F_SLOWACTMOVE)) { if ((f->id == F_SLOWMOVE) || (f->id == F_SLOWACTMOVE)) {
@ -5772,13 +5809,7 @@ int getmovespeed(lifeform_t *lf) {
speed += 5; break; speed += 5; break;
} }
} else if (f->id == F_SPRINTING) { } else if (f->id == F_SPRINTING) {
if (f->val[0]) { speed -= 10;
speed -= 10;
} else {
speed += 5;
}
} else if (f->id == F_TIRED) {
speed += 5;
} }
} }
@ -7010,6 +7041,9 @@ void givejob(lifeform_t *lf, enum JOB jobid) {
} }
} }
// reset max stamina if required.
lf->stamina = getmaxstamina(lf);
if ((gamemode != GM_GAMESTARTED)) { if ((gamemode != GM_GAMESTARTED)) {
autoweild(lf); autoweild(lf);
} }
@ -7701,7 +7735,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
break; break;
case 3: case 3:
inj = IJ_WINDPIPECRUSHED; inj = IJ_WINDPIPECRUSHED;
desc = strdup("windpipe is crushed^fitness penalty, cannot sprint"); desc = strdup("windpipe is crushed^fitness penalty");
break; break;
case 4: case 4:
inj = IJ_NOSEBROKEN; inj = IJ_NOSEBROKEN;
@ -7835,9 +7869,6 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
wep = getweapon(lf); wep = getweapon(lf);
if (wep) drop(wep, wep->amt); if (wep) drop(wep, wep->amt);
break; break;
case IJ_WINDPIPECRUSHED:
stopsprinting(lf);
break;
default: default:
break; break;
} }
@ -9317,6 +9348,8 @@ void initrace(void) {
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "purchasing items"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "purchasing items");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "giving away or discarding money"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "giving away or discarding money");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "opening locked objects through force"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "opening locked objects through force");
// sacrifices
addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_MONEY, NA, 2, "OB IS consumed in a swirl of shadowy blackness");
addrace(R_GODDEATH, "Hecta", 100, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); addrace(R_GODDEATH, "Hecta", 100, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD);
@ -9361,8 +9394,8 @@ void initrace(void) {
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "magical healing"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "magical healing");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "bestowing blessings"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "bestowing blessings");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "casting holy spells"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "casting holy spells");
// sacrifices
addflag(lastrace->flags, F_SACRIFICEOB, OT_CORPSE, NA, 2, "Bony claws rise up and drag OB underground.");
addrace(R_GODMERCY, "Yumi", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); addrace(R_GODMERCY, "Yumi", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD);
addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL);
@ -9401,6 +9434,8 @@ void initrace(void) {
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "sneak attacks"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "sneak attacks");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of poison"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of poison");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the destruction of healing potions"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the destruction of healing potions");
// sacrifices
addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_WEAPON, NA, 2, "OB IS destroyed in a flash of power.");
// monsters // monsters
@ -11521,7 +11556,7 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 90, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, ""); addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, "");
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+1"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+1");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
@ -11963,6 +11998,16 @@ int isaquatic(lifeform_t *lf) {
return B_FALSE; return B_FALSE;
} }
// is lf behind otherlf?
int isbehind(lifeform_t *lf, lifeform_t *otherlf) {
int dir;
dir = getdirtowards(otherlf->cell, lf->cell, NULL, B_FALSE, DT_ORTH);
if (getrelativedir(otherlf, dir) == RD_BACKWARDS) {
return B_TRUE;
}
return B_FALSE;
}
// returns B_FALSE, B_TRUE, or B_FROMINJURY // returns B_FALSE, B_TRUE, or B_FROMINJURY
int isbleeding(lifeform_t *lf) { int isbleeding(lifeform_t *lf) {
float hppct; float hppct;
@ -12522,6 +12567,8 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) {
setrace(a, rid, B_FALSE); setrace(a, rid, B_FALSE);
// set stamina AFTER setrace as it depends on your attribs
a->stamina = getmaxstamina(a);
// update other things // update other things
cell->lf = a; cell->lf = a;
@ -12816,8 +12863,7 @@ void makepeaceful(lifeform_t *who) {
addflag(who->flags, F_XPVAL, 0, NA, NA, NULL); addflag(who->flags, F_XPVAL, 0, NA, NA, NULL);
killflagsofid(who->flags, F_HOSTILE); killflagsofid(who->flags, F_HOSTILE);
killflagsofid(who->flags, F_TARGETLF); // stop targetting anyone loseaitargets(who);
} }
lifeform_t *makezombie(object_t *o) { lifeform_t *makezombie(object_t *o) {
@ -13730,14 +13776,16 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
} }
void losemp(lifeform_t *lf, int amt) { void losemp(lifeform_t *lf, int amt) {
if (isplayer(lf)) {
statdirty = B_TRUE;
}
lf->mp -= amt; lf->mp -= amt;
if (lf->mp < 0) { if (lf->mp < 0) {
lf->mp = 0; lf->mp = 0;
} }
if (isplayer(lf)) {
statdirty = B_TRUE;
drawstatus();
updatestatus();
}
} }
@ -13756,7 +13804,7 @@ void makefriendly(lifeform_t *who, int howlong) {
if (!hasflag(who->flags, F_FRIENDLY)) { if (!hasflag(who->flags, F_FRIENDLY)) {
addtempflag(who->flags, F_FRIENDLY, B_TRUE, NA, NA, NULL, howlong); addtempflag(who->flags, F_FRIENDLY, B_TRUE, NA, NA, NULL, howlong);
} }
killflagsofid(who->flags, F_TARGETLF); // stop targetting anyone loseaitargets(who);
} }
@ -14119,6 +14167,31 @@ float modifybystat(float num, lifeform_t *lf, enum ATTRIB att) {
return newnum; return newnum;
} }
void modstamina(lifeform_t *lf, float howmuch) {
float orig;
orig = lf->stamina;
lf->stamina += howmuch;
limitf(&(lf->stamina), 0, getmaxstamina(lf));
if (lf->stamina != orig) {
if (isplayer(lf)) {
statdirty = B_TRUE;
drawstatus();
updatestatus();
if (lf->stamina == 0) msg("You are exhausted.");
} else if (cansee(player, lf)) {
if (lf->stamina == 0) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s looks exhausted.", lfname);
}
}
}
if (lf->stamina == 0) {
stopsprinting(lf);
}
}
// if validchars is set, we will populate it with a list of valid // if validchars is set, we will populate it with a list of valid
// choice letters for asking the player how to rest. // choice letters for asking the player how to rest.
int needstorest(lifeform_t *lf, char *validchars) { int needstorest(lifeform_t *lf, char *validchars) {
@ -14335,26 +14408,32 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
isplayer(l) ? "" : "s", isplayer(l) ? "" : "s",
isplayer(l) ? "your" : "its"); isplayer(l) ? "your" : "its");
} }
} } else { // not asleep, but can hear it.
} else { // not alseep // monsters will turn to face the sound, as long as they're
// monsters will turn to face the sound, as long as they're // not attacking something
// not attacking something if (!isplayer(l)) {
if (!isplayer(l)) { flag_t *f;
flag_t *f; int willrespond = B_FALSE;
int willrespond = B_FALSE; f = aihastarget(l);
f = aihastarget(l); if (f) {
if (f) { // will probably ignore the sound...
// will probably ignore the sound... if ((volume >= 5) && onein(2)) {
if ((volume >= 5) && onein(2)) { willrespond = B_TRUE;
willrespond = B_TRUE; }
} } else willrespond = B_TRUE;
} else willrespond = B_TRUE;
if (willrespond) { if (willrespond) {
// turn to face the sound // turn to face the sound
turntoface(l, c); turntoface(l, c);
if (isplayer(noisemaker) && cansee(player, l)) {
char lfname[BUFLEN];
getlfname(l, lfname);
msg("%s turns to face you.", lfname);
}
}
} }
} }
} else { // can't hear the sound.
} }
} // end for each lf on map } // end for each lf on map
return rv; return rv;
@ -15394,6 +15473,9 @@ void setattr(lifeform_t *lf, enum ATTRIB attr, int val) {
} }
int setfacing(lifeform_t *lf, int dir) { int setfacing(lifeform_t *lf, int dir) {
if (dir == D_NONE) {
dblog("xxx");
}
if (lf->facing == dir) { // already facing that way if (lf->facing == dir) { // already facing that way
return B_TRUE; return B_TRUE;
} }
@ -15686,8 +15768,7 @@ void initskills(void) {
addskilldesc(SK_ARMOUR, PR_SKILLED, "^gReduces armour evasion penalties by 40%.", B_FALSE); addskilldesc(SK_ARMOUR, PR_SKILLED, "^gReduces armour evasion penalties by 40%.", B_FALSE);
addskilldesc(SK_ARMOUR, PR_EXPERT, "^gReduces armour evasion penalties by 50%.", B_FALSE); addskilldesc(SK_ARMOUR, PR_EXPERT, "^gReduces armour evasion penalties by 50%.", B_FALSE);
addskilldesc(SK_ARMOUR, PR_MASTER, "^gReduces armour evasion penalties by 60%.", B_FALSE); addskilldesc(SK_ARMOUR, PR_MASTER, "^gReduces armour evasion penalties by 60%.", B_FALSE);
addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery.", 50); addskill(SK_ATHLETICS, "Athletics", "Grants various athletic abilities.", 50);
addskilldesc(SK_ATHLETICS, PR_INEPT, "- Determines how far you can sprint before tiring.", B_FALSE);
addskilldesc(SK_ATHLETICS, PR_NOVICE, "^gYou gain the 'sprint' ability.", B_FALSE); addskilldesc(SK_ATHLETICS, PR_NOVICE, "^gYou gain the 'sprint' ability.", B_FALSE);
addskilldesc(SK_ATHLETICS, PR_ADEPT, "^gYou gain the 'tumble' ability.", B_FALSE); addskilldesc(SK_ATHLETICS, PR_ADEPT, "^gYou gain the 'tumble' ability.", B_FALSE);
addskilldesc(SK_ATHLETICS, PR_EXPERT, "^gYou gain the 'jump' ability.", B_FALSE); addskilldesc(SK_ATHLETICS, PR_EXPERT, "^gYou gain the 'jump' ability.", B_FALSE);
@ -15848,69 +15929,6 @@ void initskills(void) {
addskilldesc(SK_SS_ALLOMANCY, PR_SKILLED, "Allows you to cast Allomancy spells up to level 4.", B_FALSE); addskilldesc(SK_SS_ALLOMANCY, PR_SKILLED, "Allows you to cast Allomancy spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_ALLOMANCY, PR_EXPERT, "Allows you to cast Allomancy spells up to level 5.", B_FALSE); addskilldesc(SK_SS_ALLOMANCY, PR_EXPERT, "Allows you to cast Allomancy spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_ALLOMANCY, PR_MASTER, "Allows you to cast Allomancy spells up to level 6.", B_FALSE); addskilldesc(SK_SS_ALLOMANCY, PR_MASTER, "Allows you to cast Allomancy spells up to level 6.", B_FALSE);
addskill(SK_SS_AIR, "Air Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_AIR, PR_NOVICE, "Allows you to cast Air Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_BEGINNER, "Allows you to cast Air Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_ADEPT, "Allows you to cast Air Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_SKILLED, "Allows you to cast Air Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_EXPERT, "Allows you to cast Air Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_MASTER, "Allows you to cast Air Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_DEATH, "Necromancy", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_DEATH, PR_NOVICE, "Allows you to cast Necromancy spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_BEGINNER, "Allows you to cast Necromancy spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_ADEPT, "Allows you to cast Necromancy spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_SKILLED, "Allows you to cast Necromancy spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_EXPERT, "Allows you to cast Necromancy spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_MASTER, "Allows you to cast Necromancy spells up to level 6.", B_FALSE);
addskill(SK_SS_DIVINATION, "Divination", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_DIVINATION, PR_NOVICE, "Allows you to cast Divination spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_BEGINNER, "Allows you to cast Divination spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_ADEPT, "Allows you to cast Divination spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_SKILLED, "Allows you to cast Divination spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_EXPERT, "Allows you to cast Divination spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_MASTER, "Allows you to cast Divination spells up to level 6.", B_FALSE);
addskill(SK_SS_ENCHANTMENT, "Enchantment", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_ENCHANTMENT, PR_NOVICE, "Allows you to cast Enchantment spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_BEGINNER, "Allows you to cast Enchantment spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_ADEPT, "Allows you to cast Enchantment spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_SKILLED, "Allows you to cast Enchantment spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_EXPERT, "Allows you to cast Enchantment spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_MASTER, "Allows you to cast Enchantment spells up to level 6.", B_FALSE);
addskill(SK_SS_FIRE, "Fire Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_FIRE, PR_NOVICE, "Allows you to cast Fire Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_BEGINNER, "Allows you to cast Fire Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_ADEPT, "Allows you to cast Fire Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_SKILLED, "Allows you to cast Fire Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_EXPERT, "Allows you to cast Fire Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_MASTER, "Allows you to cast Fire Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_COLD, "Cold Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_COLD, PR_NOVICE, "Allows you to cast Cold Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_BEGINNER, "Allows you to cast Cold Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_ADEPT, "Allows you to cast Cold Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_SKILLED, "Allows you to cast Cold Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_EXPERT, "Allows you to cast Cold Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_MASTER, "Allows you to cast Cold Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_GRAVITY, "Gravitation Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_GRAVITY, PR_NOVICE, "Allows you to cast Gravitation Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_BEGINNER, "Allows you to cast Gravitation Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_ADEPT, "Allows you to cast Gravitation Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_SKILLED, "Allows you to cast Gravitation Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_EXPERT, "Allows you to cast Gravitation Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_MASTER, "Allows you to cast Gravitation Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_LIFE, "Life Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_LIFE, PR_NOVICE, "Allows you to cast Life Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_BEGINNER, "Allows you to cast Life Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_ADEPT, "Allows you to cast Life Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_SKILLED, "Allows you to cast Life Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_EXPERT, "Allows you to cast Life Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_MASTER, "Allows you to cast Life Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_MODIFICATION, "Modification", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_MODIFICATION, PR_NOVICE, "Allows you to cast Modification spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_BEGINNER, "Allows you to cast Modification spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_ADEPT, "Allows you to cast Modification spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_SKILLED, "Allows you to cast Modification spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_EXPERT, "Allows you to cast Modification spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_MASTER, "Allows you to cast Modification spells up to level 6.", B_FALSE);
addskill(SK_SS_MENTAL, "Psionics", "Boosts casting of spells from this school.", 50); addskill(SK_SS_MENTAL, "Psionics", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_MENTAL, PR_INEPT, "- Each rank gives you a 10%% chance to learn a new psionic ability when levelling up.", B_FALSE); addskilldesc(SK_SS_MENTAL, PR_INEPT, "- Each rank gives you a 10%% chance to learn a new psionic ability when levelling up.", B_FALSE);
addskilldesc(SK_SS_MENTAL, PR_NOVICE, "Allows you to cast Psionic spells up to level 1.", B_FALSE); addskilldesc(SK_SS_MENTAL, PR_NOVICE, "Allows you to cast Psionic spells up to level 1.", B_FALSE);
@ -15919,28 +15937,91 @@ void initskills(void) {
addskilldesc(SK_SS_MENTAL, PR_SKILLED, "Allows you to cast Psionic spells up to level 4.", B_FALSE); addskilldesc(SK_SS_MENTAL, PR_SKILLED, "Allows you to cast Psionic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_MENTAL, PR_EXPERT, "Allows you to cast Psionic spells up to level 5.", B_FALSE); addskilldesc(SK_SS_MENTAL, PR_EXPERT, "Allows you to cast Psionic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_MENTAL, PR_MASTER, "Allows you to cast Psionic spells up to level 6.", B_FALSE); addskilldesc(SK_SS_MENTAL, PR_MASTER, "Allows you to cast Psionic spells up to level 6.", B_FALSE);
addskill(SK_SS_NATURE, "Nature Magic", "Boosts casting of spells from this school.", 50); addskill(SK_SS_NATURE, "Enviromancy", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_NATURE, PR_NOVICE, "Allows you to cast Nature spells up to level 1.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_NOVICE, "Allows you to cast Nature spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_NATURE, PR_BEGINNER, "Allows you to cast Nature spells up to level 2.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_BEGINNER, "Allows you to cast Nature spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_NATURE, PR_ADEPT, "Allows you to cast Nature spells up to level 3.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_ADEPT, "Allows you to cast Nature spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_NATURE, PR_SKILLED, "Allows you to cast Nature spells up to level 4.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_SKILLED, "Allows you to cast Nature spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_NATURE, PR_EXPERT, "Allows you to cast Nature spells up to level 5.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_EXPERT, "Allows you to cast Nature spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_NATURE, PR_MASTER, "Allows you to cast Nature spells up to level 6.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_MASTER, "Allows you to cast Nature spells up to level 6.", B_FALSE);
addskill(SK_SS_SUMMONING, "Summoning", "Boosts casting of spells from this school.", 50); addskill(SK_SS_AIR, "Magic:Air Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_AIR, PR_NOVICE, "Allows you to cast Air Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_BEGINNER, "Allows you to cast Air Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_ADEPT, "Allows you to cast Air Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_SKILLED, "Allows you to cast Air Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_EXPERT, "Allows you to cast Air Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_AIR, PR_MASTER, "Allows you to cast Air Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_DEATH, "Magic:Necromancy", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_DEATH, PR_NOVICE, "Allows you to cast Necromancy spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_BEGINNER, "Allows you to cast Necromancy spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_ADEPT, "Allows you to cast Necromancy spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_SKILLED, "Allows you to cast Necromancy spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_EXPERT, "Allows you to cast Necromancy spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_DEATH, PR_MASTER, "Allows you to cast Necromancy spells up to level 6.", B_FALSE);
addskill(SK_SS_DIVINATION, "Magic:Divination", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_DIVINATION, PR_NOVICE, "Allows you to cast Divination spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_BEGINNER, "Allows you to cast Divination spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_ADEPT, "Allows you to cast Divination spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_SKILLED, "Allows you to cast Divination spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_EXPERT, "Allows you to cast Divination spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_DIVINATION, PR_MASTER, "Allows you to cast Divination spells up to level 6.", B_FALSE);
addskill(SK_SS_ENCHANTMENT, "Magic:Enchantment", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_ENCHANTMENT, PR_NOVICE, "Allows you to cast Enchantment spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_BEGINNER, "Allows you to cast Enchantment spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_ADEPT, "Allows you to cast Enchantment spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_SKILLED, "Allows you to cast Enchantment spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_EXPERT, "Allows you to cast Enchantment spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_ENCHANTMENT, PR_MASTER, "Allows you to cast Enchantment spells up to level 6.", B_FALSE);
addskill(SK_SS_FIRE, "Magic:Fire Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_FIRE, PR_NOVICE, "Allows you to cast Fire Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_BEGINNER, "Allows you to cast Fire Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_ADEPT, "Allows you to cast Fire Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_SKILLED, "Allows you to cast Fire Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_EXPERT, "Allows you to cast Fire Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_FIRE, PR_MASTER, "Allows you to cast Fire Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_COLD, "Magic:Cold Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_COLD, PR_NOVICE, "Allows you to cast Cold Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_BEGINNER, "Allows you to cast Cold Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_ADEPT, "Allows you to cast Cold Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_SKILLED, "Allows you to cast Cold Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_EXPERT, "Allows you to cast Cold Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_COLD, PR_MASTER, "Allows you to cast Cold Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_GRAVITY, "Magic:Gravitation Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_GRAVITY, PR_NOVICE, "Allows you to cast Gravitation Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_BEGINNER, "Allows you to cast Gravitation Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_ADEPT, "Allows you to cast Gravitation Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_SKILLED, "Allows you to cast Gravitation Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_EXPERT, "Allows you to cast Gravitation Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_GRAVITY, PR_MASTER, "Allows you to cast Gravitation Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_LIFE, "Magic:Life Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_LIFE, PR_NOVICE, "Allows you to cast Life Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_BEGINNER, "Allows you to cast Life Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_ADEPT, "Allows you to cast Life Magic spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_SKILLED, "Allows you to cast Life Magic spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_EXPERT, "Allows you to cast Life Magic spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_LIFE, PR_MASTER, "Allows you to cast Life Magic spells up to level 6.", B_FALSE);
addskill(SK_SS_MODIFICATION, "Magic:Modification", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_MODIFICATION, PR_NOVICE, "Allows you to cast Modification spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_BEGINNER, "Allows you to cast Modification spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_ADEPT, "Allows you to cast Modification spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_SKILLED, "Allows you to cast Modification spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_EXPERT, "Allows you to cast Modification spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_MODIFICATION, PR_MASTER, "Allows you to cast Modification spells up to level 6.", B_FALSE);
addskill(SK_SS_SUMMONING, "Magic:Summoning", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_SUMMONING, PR_NOVICE, "Allows you to cast Summoning spells up to level 1.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_NOVICE, "Allows you to cast Summoning spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_SUMMONING, PR_BEGINNER, "Allows you to cast Summoning spells up to level 2.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_BEGINNER, "Allows you to cast Summoning spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_SUMMONING, PR_ADEPT, "Allows you to cast Summoning spells up to level 3.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_ADEPT, "Allows you to cast Summoning spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_SUMMONING, PR_SKILLED, "Allows you to cast Summoning spells up to level 4.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_SKILLED, "Allows you to cast Summoning spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_SUMMONING, PR_EXPERT, "Allows you to cast Summoning spells up to level 5.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_EXPERT, "Allows you to cast Summoning spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_SUMMONING, PR_MASTER, "Allows you to cast Summoning spells up to level 6.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_MASTER, "Allows you to cast Summoning spells up to level 6.", B_FALSE);
addskill(SK_SS_TRANSLOCATION, "Translocation", "Boosts casting of spells from this school.", 50); addskill(SK_SS_TRANSLOCATION, "Magic:Translocation", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_TRANSLOCATION, PR_NOVICE, "Allows you to cast Translocation spells up to level 1.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_NOVICE, "Allows you to cast Translocation spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_TRANSLOCATION, PR_BEGINNER, "Allows you to cast Translocation spells up to level 2.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_BEGINNER, "Allows you to cast Translocation spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_TRANSLOCATION, PR_ADEPT, "Allows you to cast Translocation spells up to level 3.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_ADEPT, "Allows you to cast Translocation spells up to level 3.", B_FALSE);
addskilldesc(SK_SS_TRANSLOCATION, PR_SKILLED, "Allows you to cast Translocation spells up to level 4.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_SKILLED, "Allows you to cast Translocation spells up to level 4.", B_FALSE);
addskilldesc(SK_SS_TRANSLOCATION, PR_EXPERT, "Allows you to cast Translocation spells up to level 5.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_EXPERT, "Allows you to cast Translocation spells up to level 5.", B_FALSE);
addskilldesc(SK_SS_TRANSLOCATION, PR_MASTER, "Allows you to cast Translocation spells up to level 6.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_MASTER, "Allows you to cast Translocation spells up to level 6.", B_FALSE);
addskill(SK_SS_WILD, "Wild Magic", "Boosts casting of spells from this school.", 50); addskill(SK_SS_WILD, "Magic:Wild Magic", "Boosts casting of spells from this school.", 50);
addskilldesc(SK_SS_WILD, PR_NOVICE, "Allows you to cast Wild Magic spells up to level 1.", B_FALSE); addskilldesc(SK_SS_WILD, PR_NOVICE, "Allows you to cast Wild Magic spells up to level 1.", B_FALSE);
addskilldesc(SK_SS_WILD, PR_BEGINNER, "Allows you to cast Wild Magic spells up to level 2.", B_FALSE); addskilldesc(SK_SS_WILD, PR_BEGINNER, "Allows you to cast Wild Magic spells up to level 2.", B_FALSE);
addskilldesc(SK_SS_WILD, PR_ADEPT, "Allows you to cast Wild Magic spells up to level 3.", B_FALSE); addskilldesc(SK_SS_WILD, PR_ADEPT, "Allows you to cast Wild Magic spells up to level 3.", B_FALSE);
@ -16635,6 +16716,41 @@ void startlfturn(lifeform_t *lf) {
} }
} }
// either use up stamina, or gain it
if (lfhasflag(lf, F_SPRINTING)) {
modstamina(lf, -1);
} else if (isswimming(lf)) {
int lossamt;
// lose stamina based on swimming skill
switch (getskill(lf, SK_SWIMMING)) {
case PR_INEPT: lossamt = 3; break;
case PR_NOVICE: lossamt = 1; break;
case PR_BEGINNER: lossamt = 1; break;
case PR_ADEPT: lossamt = 0.5; break;
case PR_SKILLED: lossamt = 0; break;
case PR_EXPERT: lossamt = 0; break;
case PR_MASTER: lossamt = 0; break;
}
if (lossamt) modstamina(lf, -lossamt);
} else {
if (lf->stamina < getmaxstamina(lf)) {
float regenrate = 0.5;
if (lfhasflagval(lf, F_INJURY, IJ_WINDPIPECRUSHED, NA, NA, NULL)) {
regenrate = 0.2; // override everything else
} else {
if (lfhasflag(lf, F_ASLEEP)) {
regenrate = pctof(200, regenrate);
}
if (ispoisoned(lf)) {
regenrate = pctof(50, regenrate);
}
}
limitf(&regenrate, 0, NA);
modstamina(lf, regenrate);
}
}
// god piety gets restored over time // god piety gets restored over time
if (isplayer(lf)) { if (isplayer(lf)) {
@ -17446,17 +17562,11 @@ void stopsprinting(lifeform_t *lf) {
} }
int stun(lifeform_t *lf, int nturns) { int stun(lifeform_t *lf, int nturns) {
if (lfhasflag(lf, F_ASLEEP)) { if (lfhasflag(lf, F_ASLEEP) || lfhasflag(lf, F_STUNNED)) {
return B_TRUE; return B_TRUE;
} }
if (isplayer(lf)) { addtempflag(lf->flags, F_STUNNED, B_TRUE, NA, NA, NULL, nturns);
msg("You are stunned!"); loseaitargets(lf);
} else if (cansee(player, lf)) {
char buf[BUFLEN];
getlfname(lf, buf);
msg("%s is stunned!", buf);
}
taketime(lf, getactspeed(lf)*nturns);
return B_FALSE; return B_FALSE;
} }
@ -17880,7 +17990,10 @@ int touch(lifeform_t *lf, object_t *o) {
} }
void turntoface(lifeform_t *lf, cell_t *dstcell) { void turntoface(lifeform_t *lf, cell_t *dstcell) {
setfacing(lf, getdirtowards(lf->cell, dstcell, lf, B_FALSE, DT_COMPASS) ); // not providing srclf, since this will make getdirtowards() not include
// directions in which the next cell is unwalkable. in this case we're
// not actually walking there, so we don't care.
setfacing(lf, getdirtowards(lf->cell, dstcell, NULL, B_FALSE, DT_ORTH) );
} }
@ -17997,6 +18110,12 @@ int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where)
case E_NOTREADY: case E_NOTREADY:
msg("This ability is not recharged yet."); msg("This ability is not recharged yet.");
break; break;
case E_NOSTAM:
msg("You are too tired to do that.");
break;
case E_STUNNED:
msg("You can't use abilities while stunned.");
break;
default: default:
msg("For some reason, you can't use this ability."); msg("For some reason, you can't use this ability.");
break; break;

4
lf.h
View File

@ -28,6 +28,7 @@ long calcscore(lifeform_t *lf);
int calcxp(lifeform_t *lf); int calcxp(lifeform_t *lf);
int calcxprace(enum RACE rid); int calcxprace(enum RACE rid);
void callguards(lifeform_t *caller, lifeform_t *victim); void callguards(lifeform_t *caller, lifeform_t *victim);
int canattack(lifeform_t *lf);
int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost); int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost);
int candrink(lifeform_t *lf, object_t *o); int candrink(lifeform_t *lf, object_t *o);
int caneat(lifeform_t *lf, object_t *o); int caneat(lifeform_t *lf, object_t *o);
@ -157,6 +158,7 @@ float getmaxcarryweight(lifeform_t *lf);
float getmaxliftweight(lifeform_t *lf); float getmaxliftweight(lifeform_t *lf);
int getmaxmp(lifeform_t *lf); int getmaxmp(lifeform_t *lf);
float getmaxpushweight(lifeform_t *lf); float getmaxpushweight(lifeform_t *lf);
float getmaxstamina(lifeform_t *lf);
int getmr(lifeform_t *lf); int getmr(lifeform_t *lf);
int getvisrange(lifeform_t *lf, int useambient); int getvisrange(lifeform_t *lf, int useambient);
void idxtoxy(lifeform_t *lf, int idx, int *x, int *y); void idxtoxy(lifeform_t *lf, int idx, int *x, int *y);
@ -240,6 +242,7 @@ void initskills(void);
void interrupt(lifeform_t *lf); void interrupt(lifeform_t *lf);
int isairborne(lifeform_t *lf); int isairborne(lifeform_t *lf);
int isaquatic(lifeform_t *lf); int isaquatic(lifeform_t *lf);
int isbehind(lifeform_t *lf, lifeform_t *otherlf);
int isbleeding(lifeform_t *lf); int isbleeding(lifeform_t *lf);
int isblind(lifeform_t *lf); int isblind(lifeform_t *lf);
enum BURDENED isburdened(lifeform_t *lf); enum BURDENED isburdened(lifeform_t *lf);
@ -295,6 +298,7 @@ int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o);
int modattr(lifeform_t *lf, enum ATTRIB attr, int amt); int modattr(lifeform_t *lf, enum ATTRIB attr, int amt);
void modhunger(lifeform_t *lf, int amt); void modhunger(lifeform_t *lf, int amt);
float modifybystat(float num, lifeform_t *lf, enum ATTRIB att); float modifybystat(float num, lifeform_t *lf, enum ATTRIB att);
void modstamina(lifeform_t *lf, float howmuch);
int needstorest(lifeform_t *lf, char *validchars); int needstorest(lifeform_t *lf, char *validchars);
int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext); int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext);
void outfitlf(lifeform_t *lf); void outfitlf(lifeform_t *lf);

20
map.c
View File

@ -3579,8 +3579,12 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int
} else if ((dirtype == DT_ORTH) && (getcelldistorth(c,cc) <= range)) { } else if ((dirtype == DT_ORTH) && (getcelldistorth(c,cc) <= range)) {
inrange = B_TRUE; inrange = B_TRUE;
} }
if (inrange && haslof(c, cc, LOF_WALLSTOP, NULL)) { if (inrange) {
explodesinglecell(cc, dam, killwalls, o, c); cell_t *stopcell = NULL;
// if a door stops the explosion, the door will
// take the damage.
haslof(c, cc, LOF_WALLSTOP, &stopcell);
explodesinglecell(stopcell, dam, killwalls, o, c);
} }
} }
} }
@ -4221,6 +4225,18 @@ int getrandomdir(int dirtype) {
} }
} }
int getrandomdirexcept(int dirtype, int exception) {
int dir;
dir = exception;
while (dir == exception) {
if (dirtype == DT_ORTH) {
dir = rnd(D_N, D_W);
} else { // ie. DT_COMPASS
dir = rnd(DC_N, DC_NW);
}
}
return dir;
}
cell_t *getrandomroomcell(map_t *map, int roomid) { cell_t *getrandomroomcell(map_t *map, int roomid) {
int npossible = 0; int npossible = 0;

1
map.h
View File

@ -86,6 +86,7 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LO
cell_t *getrandomcell(map_t *map); cell_t *getrandomcell(map_t *map);
cell_t *getrandomcelloftype(map_t *map, enum CELLTYPE id); cell_t *getrandomcelloftype(map_t *map, enum CELLTYPE id);
int getrandomdir(int dirtype); int getrandomdir(int dirtype);
int getrandomdirexcept(int dirtype, int exception);
cell_t *getrandomroomcell(map_t *map, int roomid); cell_t *getrandomroomcell(map_t *map, int roomid);
void getroomcells(map_t *m, int roomid, cell_t **retcell, int *ncells); void getroomcells(map_t *m, int roomid, cell_t **retcell, int *ncells);
int getslipperyness(cell_t *c, object_t **slipob); int getslipperyness(cell_t *c, object_t **slipob);

25
move.c
View File

@ -1488,6 +1488,8 @@ int movetowards(lifeform_t *lf, cell_t *dst, int dirtype, int strafe) {
dblog(".oO { dir from %d,%d -> %d,%d is %s }", lf->cell->x, lf->cell->y, dst->x, dst->y, getdirname(dir)); dblog(".oO { dir from %d,%d -> %d,%d is %s }", lf->cell->x, lf->cell->y, dst->x, dst->y, getdirname(dir));
} }
rv = trymove(lf, dir, B_TRUE, strafe); rv = trymove(lf, dir, B_TRUE, strafe);
} else {
if (db) dblog(".oO { dir from %d,%d -> %d,%d is DT_NONE ! }", lf->cell->x, lf->cell->y, dst->x, dst->y);
} }
return rv; return rv;
} }
@ -1559,6 +1561,8 @@ int opendoor(lifeform_t *lf, object_t *o) {
} else { } else {
if (lf) { if (lf) {
if (isplayer(lf)) { if (isplayer(lf)) {
int dir;
cell_t *pastdoorcell;
// has known trap? // has known trap?
if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) { if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) {
if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) {
@ -1572,15 +1576,14 @@ int opendoor(lifeform_t *lf, object_t *o) {
} }
} }
// hear water behind it? // hear water behind it?
if (getskill(lf, SK_LISTEN)) { dir = getdirtowards(doorcell, lf->cell, NULL, B_FALSE, DT_ORTH);
int dir; pastdoorcell = getcellindir(doorcell, dir);
cell_t *pastdoorcell; if (pastdoorcell && getcellwaterdepth(pastdoorcell, NULL)) {
dir = getdirtowards(doorcell, lf->cell, NULL, B_FALSE, DT_ORTH); if (getskill(lf, SK_LISTEN) || haslos(lf, pastdoorcell)) {
pastdoorcell = getcellindir(doorcell, dir);
if (pastdoorcell && getcellwaterdepth(pastdoorcell, NULL)) {
if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) {
char ch; char ch;
snprintf(buf, BUFLEN,"Your hear running water behind %s. Really open it?", obname); snprintf(buf, BUFLEN,"%s running water behind %s. Really open it?",
haslos(lf, pastdoorcell) ? "There is" : "You can hear", obname);
ch = askchar(buf,"yn","n", B_TRUE); ch = askchar(buf,"yn","n", B_TRUE);
if (ch != 'y') { if (ch != 'y') {
msg("Cancelled."); msg("Cancelled.");
@ -1596,12 +1599,6 @@ int opendoor(lifeform_t *lf, object_t *o) {
// stop sprinting // stop sprinting
stopsprinting(lf); stopsprinting(lf);
/*
sf = lfhasflag(lf, F_SPRINTING);
if (sf && sf->val[0]) {
killflag(sf);
}
*/
} }
// trapped? // trapped?
@ -2206,7 +2203,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
cell = getcellindir(lf->cell, dir); cell = getcellindir(lf->cell, dir);
if (isplayer(lf) && !lfhasflag(lf, F_SNEAK)) { if (onpurpose && isplayer(lf) && !lfhasflag(lf, F_SNEAK)) {
if (cell && celldangerous(lf, cell, B_TRUE, &errcode)) { if (cell && celldangerous(lf, cell, B_TRUE, &errcode)) {
char ques[BUFLEN]; char ques[BUFLEN];
char ch; char ch;

View File

@ -980,6 +980,7 @@ void initcommands(void) {
addcommand(CMD_EAT, 'E', "Enhance your skills."); addcommand(CMD_EAT, 'E', "Enhance your skills.");
addcommand(CMD_MAGIC, 'm', "Use magic or abilities."); addcommand(CMD_MAGIC, 'm', "Use magic or abilities.");
addcommand(CMD_MEMMAGIC, 'M', "Memorise a magic shortcut"); addcommand(CMD_MEMMAGIC, 'M', "Memorise a magic shortcut");
addcommand(CMD_OFFER, 'O', "Offer a sacrifice to the gods.");
addcommand(CMD_OPERATE, 'o', "Operate a tool/wand/device."); addcommand(CMD_OPERATE, 'o', "Operate a tool/wand/device.");
addcommand(CMD_PICKLOCK, 'p', "Pick a lock."); addcommand(CMD_PICKLOCK, 'p', "Pick a lock.");
addcommand(CMD_POUR, 'P', "Pour a potion onto something."); addcommand(CMD_POUR, 'P', "Pour a potion onto something.");

View File

@ -1312,7 +1312,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
assert(corpserace); assert(corpserace);
o->weight = corpserace->weight; o->weight = pctof(8, corpserace->weight);
limitf(&o->weight, 0.01, NA);
o->material = corpserace->material; o->material = corpserace->material;
// remember the race type // remember the race type
@ -4318,7 +4319,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
} }
// override corpse name // override corpse name
if (o->type->id == OT_CORPSE) { if ((o->type->id == OT_CORPSE) || (o->type->id == OT_HEAD)) {
f = hasflag(o->flags, F_CORPSEOF); f = hasflag(o->flags, F_CORPSEOF);
if (f) { if (f) {
race_t *corpserace; race_t *corpserace;
@ -4326,10 +4327,10 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
corpserace = findrace(f->val[0]); corpserace = findrace(f->val[0]);
ff = hasflag(corpserace->flags, F_NAME); ff = hasflag(corpserace->flags, F_NAME);
if (ff) { if (ff) {
snprintf(basename, BUFLEN, "%s%s corpse",ff->text, getpossessive(ff->text)); snprintf(basename, BUFLEN, "%s%s %s",ff->text, getpossessive(ff->text), o->type->name);
no_a = B_TRUE; no_a = B_TRUE;
} else { } else {
snprintf(basename, BUFLEN, "%s corpse",corpserace->name); snprintf(basename, BUFLEN, "%s %s",corpserace->name, o->type->name);
} }
} }
} else if (o->type->id == OT_FOUNTAIN) { } else if (o->type->id == OT_FOUNTAIN) {
@ -5440,7 +5441,7 @@ object_t *hasobwithflagval(obpile_t *op, enum FLAG flagid, int val0, int val1, i
} }
object_t *hasobid(obpile_t *op, int id) { object_t *hasobid(obpile_t *op, long id) {
object_t *o; object_t *o;
for (o = op->first ; o ; o = o->next) { for (o = op->first ; o ; o = o->next) {
if (o->id == id) return o; if (o->id == id) return o;
@ -5831,7 +5832,7 @@ void initobjects(void) {
addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_MASTERWORK, 17, NA, NULL); addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_MASTERWORK, 17, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_SHODDY, 34, NA, NULL); addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_SHODDY, 34, NA, NULL);
addoc(OC_ARMOUR, "Armour/Clothing", "Protective gear.", ']', C_GREY); addoc(OC_ARMOUR, "Armour/Clothing", "Protective gear.", '[', C_GREY);
addocnoun(lastobjectclass, "armour"); addocnoun(lastobjectclass, "armour");
addocnoun(lastobjectclass, "clothing"); addocnoun(lastobjectclass, "clothing");
addocnoun(lastobjectclass, "clothes"); addocnoun(lastobjectclass, "clothes");
@ -5874,7 +5875,7 @@ void initobjects(void) {
addocnoun(lastobjectclass, "tech"); addocnoun(lastobjectclass, "tech");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_TOOLS, "Tools", "Useful items, from the common to the obscure.", '[', C_GREY); addoc(OC_TOOLS, "Tools", "Useful items, from the common to the obscure.", ']', C_GREY);
addocnoun(lastobjectclass, "tool"); addocnoun(lastobjectclass, "tool");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -6484,11 +6485,13 @@ void initobjects(void) {
addflag(lastot->flags, F_FLAMMABLE, 1, NA, NA, "medium fire"); addflag(lastot->flags, F_FLAMMABLE, 1, NA, NA, "medium fire");
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "2d6"); addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "2d6");
addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL);
addot(OT_POT_RESTORATION, "potion of restoration", "Restores lost abilities to the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY); addot(OT_POT_RESTORATION, "potion of restoration", "Restores lost abilities to the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addot(OT_POT_SLEEP, "potion of sleep", "Puts the drinker into a deep sleep.", MT_GLASS, 1, OC_POTION, SZ_TINY); addot(OT_POT_SLEEP, "potion of sleep", "Puts the drinker into a deep sleep.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL);
addot(OT_POT_SPEED, "potion of haste", "Temporarily increasees the drinker's speed.", MT_GLASS, 1, OC_POTION, SZ_TINY); addot(OT_POT_SPEED, "potion of haste", "Temporarily increasees the drinker's speed.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL);
@ -6507,10 +6510,12 @@ void initobjects(void) {
addot(OT_POT_POISON, "potion of poison", "Poisons the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY); addot(OT_POT_POISON, "potion of poison", "Poisons the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL);
addot(OT_POT_ACID, "flask of battery acid", "Causes massive internal burning if ingested.", MT_GLASS, 1, OC_POTION, SZ_TINY); addot(OT_POT_ACID, "flask of battery acid", "Causes massive internal burning if ingested.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of acid"); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of acid");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL);
addot(OT_POT_ELEMENTIMMUNE, "potion of elemental immunity", "Grants the imbiber temporary immunity to both fire and cold.", MT_GLASS, 1, OC_POTION, SZ_TINY); addot(OT_POT_ELEMENTIMMUNE, "potion of elemental immunity", "Grants the imbiber temporary immunity to both fire and cold.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addot(OT_POT_BLOOD, "potion of blood", "A small quantity of blood.", MT_GLASS, 1, OC_POTION, SZ_TINY); addot(OT_POT_BLOOD, "potion of blood", "A small quantity of blood.", MT_GLASS, 1, OC_POTION, SZ_TINY);
@ -6552,7 +6557,6 @@ void initobjects(void) {
// scrolls // scrolls
addot(OT_SCR_AWARENESS, "scroll of awareness", "Mimics the effects of a 'heightened awareness' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addot(OT_SCR_AWARENESS, "scroll of awareness", "Mimics the effects of a 'heightened awareness' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_AWARENESS, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addot(OT_SCR_CANINETRACKING, "scroll of canine tracking", "Mimics the effects of a 'canine tracking' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addot(OT_SCR_CANINETRACKING, "scroll of canine tracking", "Mimics the effects of a 'canine tracking' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
@ -6619,6 +6623,7 @@ void initobjects(void) {
addot(OT_SCR_FREEZEOB, "scroll of freezing touch", "Permenantly changes the next object touched into solid ice.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addot(OT_SCR_FREEZEOB, "scroll of freezing touch", "Permenantly changes the next object touched into solid ice.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_FREEZEOB, NA, NA, NULL); addflag(lastot->flags, F_LINKSPELL, OT_S_FREEZEOB, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_RARE, NULL);
addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL);
addot(OT_SCR_KNOCK, "scroll of knock", "Magically opens a barrier.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addot(OT_SCR_KNOCK, "scroll of knock", "Magically opens a barrier.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_KNOCK, NA, NA, NULL); addflag(lastot->flags, F_LINKSPELL, OT_S_KNOCK, NA, NA, NULL);
@ -7421,6 +7426,12 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, 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_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_DISORIENT, "disorient", "Spins the target around to face a different direction. This will sometimes also make them dizzy.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 10, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_S_STUN, "stun", "Stuns the target, preventing them from taking action for a few seconds.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_STUN, "stun", "Stuns the target, preventing them from taking action for a few seconds.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
@ -7440,13 +7451,11 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_BAFFLE, "baffle", "Confuses the target, causing them to lose control of their movement.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_LETHARGY, "lethargy", "Reduces the target's stamina by ^bpower^n*2.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The target will be confused for ^bpower^n*4 turns.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l3 // l3
addot(OT_S_PSYARMOUR, "psychic armour", "Mentally block incoming attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_PSYARMOUR, "psychic armour", "Mentally block incoming attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The psychic armour's Armour Rating is ^bpower*4^n."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The psychic armour's Armour Rating is ^bpower*4^n.");
@ -7456,11 +7465,19 @@ void initobjects(void) {
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
// TODO: hardcode how ai casts this // TODO: hardcode how ai casts this
addot(OT_S_PACIFY, "pacify", "Induces calmness in another, preventing them from attacking.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_BAFFLE, "baffle", "Confuses the target, causing them to lose control of their movement.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The target will be confused for ^bpower^n*4 turns.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SLEEP, "sleep", "Puts the target creature to sleep.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the sleep effect will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_HUNGER, "hunger", "Causes the target to become ravenously hungry.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_HUNGER, "hunger", "Causes the target to become ravenously hungry.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
@ -7469,18 +7486,17 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l4 // l4
addot(OT_S_PACIFY, "pacify", "Induces calmness in another, preventing them from attacking.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_STUNMASS, "mass stun", "Stuns all creatures within sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_STUNMASS, "mass stun", "Stuns all creatures within sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_S_SLEEP, "sleep", "Puts the target creature to sleep.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the sleep effect will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l5 // l5
addot(OT_S_CHARM, "charm", "Causes another lifeform to temporary become friendly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_CHARM, "charm", "Causes another lifeform to temporary become friendly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability and duration."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability and duration.");
@ -7778,6 +7794,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_JUMP, "jump", "You can leap large distances.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_JUMP, "jump", "You can leap large distances.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_STAMCOST, 3, NA, NA, NULL);
addot(OT_A_POLYREVERT, "revertform", "Revert to your original form.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_POLYREVERT, "revertform", "Revert to your original form.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL);
@ -7789,11 +7806,13 @@ void initobjects(void) {
addot(OT_A_RAGE, "rage", "Enter a state of berzerker rage, gaining attack and defence bonuses.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_RAGE, "rage", "Enter a state of berzerker rage, gaining attack and defence bonuses.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addflag(lastot->flags, F_STAMCOST, 5, NA, NA, NULL);
addot(OT_A_REPAIR, "repair equipment", "Repair damage done to your equipment.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_REPAIR, "repair equipment", "Repair damage done to your equipment.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); 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, SZ_TINY); addot(OT_A_SPRINT, "sprint", "You can run at high speed over short distances.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_STAMCOST, 1, NA, NA, NULL);
addot(OT_A_STEAL, "steal", "Try to steal an item from an enemy.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_STEAL, "steal", "Try to steal an item from an enemy.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
@ -7813,6 +7832,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_TUMBLE, "tumble", "You can tumble across the ground.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_TUMBLE, "tumble", "You can tumble across the ground.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_STAMCOST, 2, NA, NA, NULL);
addot(OT_A_WARCRY, "warcry", "Inspire fear in your enemies with a mighty war cry.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_WARCRY, "warcry", "Inspire fear in your enemies with a mighty war cry.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
@ -8216,7 +8236,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addot(OT_C4, "block of c4", "A highly explosive plastic which explodes a medium time after activation.", MT_PLASTIC, 1, OC_TECH, SZ_TINY); addot(OT_C4, "block of c4", "An extremely explosive plastic which explodes a medium time after activation.", MT_PLASTIC, 1, OC_TECH, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 76, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 76, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
@ -8227,7 +8247,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RECHARGEWHENOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RECHARGEWHENOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDEATH, NA, B_BIG, B_IFACTIVATED, "15d2"); addflag(lastot->flags, F_EXPLODEONDEATH, NA, B_BIG, B_IFACTIVATED, "90d2"); // 90 - 180 damage
addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
@ -9306,7 +9326,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ATTACKVERB, 16, 30, NA, "tear"); addflag(lastot->flags, F_ATTACKVERB, 16, 30, NA, "tear");
addflag(lastot->flags, F_ATTACKVERB, 31, 40, NA, "rake"); addflag(lastot->flags, F_ATTACKVERB, 31, 40, NA, "rake");
addflag(lastot->flags, F_ATTACKVERB, 41, 50, NA, "gouge"); addflag(lastot->flags, F_ATTACKVERB, 41, 50, NA, "gouge");
addflag(lastot->flags, F_ATTACKVERB, 51, NA, NA, "eviscerate"); addflag(lastot->flags, F_ATTACKVERB, 51, NA, NA, "shred");
addflag(lastot->flags, F_KILLVERB, 70, NA, NA, "disembowel"); addflag(lastot->flags, F_KILLVERB, 70, NA, NA, "disembowel");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
@ -10005,6 +10025,18 @@ int isbadfood(object_t *o) {
return B_FALSE; return B_FALSE;
} }
int isunknownbadobject(object_t *o) {
if (iscursed(o) && !o->blessknown) {
return B_TRUE;
}
if (isbadfood(o) && (getskill(player, SK_COOKING) < PR_BEGINNER)) {
return B_TRUE;
}
if (hasflag(o->flags, F_BADOBJECT) && !isknown(o)) {
return B_TRUE;
}
return B_FALSE;
}
// is armour 'a' better than armour 'b'? // is armour 'a' better than armour 'b'?
int isbetterarmourthan(object_t *a, object_t *b) { int isbetterarmourthan(object_t *a, object_t *b) {
@ -13636,6 +13668,8 @@ int readsomething(lifeform_t *lf, object_t *o) {
msg("You need to be outside to get your bearings first."); msg("You need to be outside to get your bearings first.");
} }
} }
} else if (o->type->id == OT_SCR_AWARENESS) {
addtempflag(lf->flags, F_AWARENESS, B_TRUE, NA, NA, NULL, getspellduration(30,60,o->blessed));
} else if (o->type->id == OT_SCR_NOTHING) { } else if (o->type->id == OT_SCR_NOTHING) {
if (isplayer(lf)) { if (isplayer(lf)) {
msg("The scroll crumbles to dust."); msg("The scroll crumbles to dust.");
@ -15729,9 +15763,14 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) {
o = addob(src->obpile, "arrow"); o = addob(src->obpile, "arrow");
} }
if (o) { if (o) {
long oid;
// remember its id
oid = o->id;
// dodge check will happen in fireat(). ignore results of the // dodge check will happen in fireat(). ignore results of the
// one above. // one above.
fireat(NULL, o, 1, c, 5, NULL); fireat(NULL, o, 1, c, 5, NULL);
o = hasobid(c->obpile, oid);
if (o) removeob(o, 1);
} else { } else {
msg("ERROR: arrow trap failed."); msg("ERROR: arrow trap failed.");
dblog("ERROR: arrow trap failed."); dblog("ERROR: arrow trap failed.");

View File

@ -140,7 +140,7 @@ int hasobmod(object_t *o, obmod_t *om);
object_t *hasobmulti(obpile_t *op, enum OBTYPE *oid, int noids); object_t *hasobmulti(obpile_t *op, enum OBTYPE *oid, int noids);
object_t *hasobwithflag(obpile_t *op, enum FLAG flagid); object_t *hasobwithflag(obpile_t *op, enum FLAG flagid);
object_t *hasobwithflagval(obpile_t *op, enum FLAG flagid, int val0, int val1, int val2, char *text); object_t *hasobwithflagval(obpile_t *op, enum FLAG flagid, int val0, int val1, int val2, char *text);
object_t *hasobid(obpile_t *op, int id); object_t *hasobid(obpile_t *op, long id);
void identify(object_t *o); void identify(object_t *o);
void ignite(object_t *o); void ignite(object_t *o);
void initobjects(void); void initobjects(void);
@ -148,6 +148,7 @@ flag_t *isarmour(object_t *o);
int isactivated(object_t *o); int isactivated(object_t *o);
int isammofor(objecttype_t *ammo, object_t *gun); int isammofor(objecttype_t *ammo, object_t *gun);
int isbadfood(object_t *o); int isbadfood(object_t *o);
int isunknownbadobject(object_t *o);
int isbetterarmourthan(object_t *a, object_t *b); int isbetterarmourthan(object_t *a, object_t *b);
int isbetterwepthan(object_t *a, object_t *b); int isbetterwepthan(object_t *a, object_t *b);
int isblessed(object_t *o); int isblessed(object_t *o);

2
save.c
View File

@ -203,6 +203,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
fscanf(f, "contr: %d\n",&l->controller); fscanf(f, "contr: %d\n",&l->controller);
fscanf(f, "hp: %d/%d\n",&l->hp, &l->maxhp); fscanf(f, "hp: %d/%d\n",&l->hp, &l->maxhp);
fscanf(f, "mp: %d/%d\n",&l->mp, &l->maxmp); fscanf(f, "mp: %d/%d\n",&l->mp, &l->maxmp);
fscanf(f, "stamina: %f\n",&l->stamina);
fscanf(f, "alive: %d\n",&l->alive); fscanf(f, "alive: %d\n",&l->alive);
fscanf(f, "lastdamtype: %d\n",(int *)&l->lastdamtype); fscanf(f, "lastdamtype: %d\n",(int *)&l->lastdamtype);
@ -790,6 +791,7 @@ int savelf(FILE *f, lifeform_t *l) {
fprintf(f, "contr: %d\n",l->controller); fprintf(f, "contr: %d\n",l->controller);
fprintf(f, "hp: %d/%d\n",l->hp, l->maxhp); fprintf(f, "hp: %d/%d\n",l->hp, l->maxhp);
fprintf(f, "mp: %d/%d\n",l->mp, l->maxmp); fprintf(f, "mp: %d/%d\n",l->mp, l->maxmp);
fprintf(f, "stamina: %f\n", l->stamina);
fprintf(f, "alive: %d\n",l->alive); fprintf(f, "alive: %d\n",l->alive);
fprintf(f, "lastdamtype: %d\n",l->lastdamtype); fprintf(f, "lastdamtype: %d\n",l->lastdamtype);
fprintf(f, "lastdam: %s\n",l->lastdam); fprintf(f, "lastdam: %s\n",l->lastdam);

317
spell.c
View File

@ -55,6 +55,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
char buf[BUFLEN]; char buf[BUFLEN];
int power = 0,needgrab = B_FALSE, range = 0; int power = 0,needgrab = B_FALSE, range = 0;
char damstr[BUFLEN],racestr[BUFLEN]; char damstr[BUFLEN],racestr[BUFLEN];
float stamcost = 0;
objecttype_t *ot; objecttype_t *ot;
flag_t *f; flag_t *f;
@ -94,6 +95,20 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} }
f = hasflag(ot->flags, F_STAMCOST);
if (f) stamcost = f->val[0];
if (stamcost) {
if (user->stamina < stamcost) {
if (isplayer(user)) {
msg("You are too tired to do that right now.");
}
return B_TRUE;
}
modstamina(user, -stamcost);
}
if (abilid == OT_A_CHARGE) { if (abilid == OT_A_CHARGE) {
cell_t *adjcell = NULL,*origcell; cell_t *adjcell = NULL,*origcell;
char targetname[BUFLEN]; char targetname[BUFLEN];
@ -786,12 +801,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} }
return B_TRUE; return B_TRUE;
} }
if (lfhasflag(user, F_TIRED)) {
if (isplayer(user)) {
msg("You are too tired to enter a rage right now.");
}
return B_TRUE;
}
howlong = 10; howlong = 10;
addtempflag(user->flags, F_RAGE, B_TRUE, NA, NA, NULL, howlong); addtempflag(user->flags, F_RAGE, B_TRUE, NA, NA, NULL, howlong);
if (isplayer(user)) { if (isplayer(user)) {
@ -922,8 +931,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// TODO: make this like eating/resting/etc ? // TODO: make this like eating/resting/etc ?
taketime(user, getactspeed(user)); taketime(user, getactspeed(user));
} else if (abilid == OT_A_SPRINT) { } else if (abilid == OT_A_SPRINT) {
int howlong;
int slev;
flag_t *f; flag_t *f;
if (lfhasflagval(user, F_INJURY, IJ_WINDPIPECRUSHED, NA, NA, NULL)) { if (lfhasflagval(user, F_INJURY, IJ_WINDPIPECRUSHED, NA, NA, NULL)) {
if (isplayer(user)) msg("You can't sprint with a crushed windpipe."); if (isplayer(user)) msg("You can't sprint with a crushed windpipe.");
@ -937,20 +944,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
f = lfhasflag(user, F_SPRINTING); f = lfhasflag(user, F_SPRINTING);
if (f) { if (f) {
if (f->val[0]) {
if (isplayer(user)) {
msg("You are already sprinting!");
}
} else {
if (isplayer(user)) {
msg("You are too tired to sprint right now.");
}
}
return B_TRUE;
}
if (lfhasflag(user, F_TIRED)) {
if (isplayer(user)) { if (isplayer(user)) {
msg("You are too tired to sprint right now."); msg("You are already sprinting!");
} }
return B_TRUE; return B_TRUE;
} }
@ -961,26 +956,19 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_TRUE; return B_TRUE;
} }
howlong = 2; if (isplayer(user)) {
// +2 for each athletics skill level int dir,dirch;
slev = getskill(user, SK_ATHLETICS); dirch = askchar("Sprint in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE);
if (slev > PR_INEPT) { if (dirch == '.') {
howlong += (2*slev); msg("Cancelled.");
} return B_TRUE;
// modify for constitution
howlong = modifybystat(howlong, user, A_CON);
if (howlong <= 0) {
if (isplayer(user)) {
msg("You are too unfit to sprint.");
} }
return B_TRUE; dir = chartodir(dirch);
setfacing(user, dir);
} }
addtempflag(user->flags, F_SPRINTING, B_TRUE, NA, NA, NULL, howlong); addflag(user->flags, F_SPRINTING, B_TRUE, NA, NA, NULL);
practice(user, SK_ATHLETICS, 1); practice(user, SK_ATHLETICS, 1);
// get hungry heaps!
modhunger(user, 50);
} else if (abilid == OT_A_STINGACID) { } else if (abilid == OT_A_STINGACID) {
validateabillf(user, abilid, &target); validateabillf(user, abilid, &target);
if (!target) return B_TRUE; if (!target) return B_TRUE;
@ -1340,26 +1328,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
setrace(user, f->val[0], B_TRUE); setrace(user, f->val[0], B_TRUE);
} else if (abilid == OT_A_PRAY) { } else if (abilid == OT_A_PRAY) {
lifeform_t *lf; lifeform_t *lf;
char buf[BUFLEN];
int i;
if (!isplayer(user)) return B_FALSE; if (!isplayer(user)) return B_FALSE;
// ask for which god // ask for which god
initprompt(&prompt, "To whom will you pray?"); initprompt(&prompt, "To whom will you pray?");
prompt.maycancel = B_TRUE; prompt.maycancel = B_TRUE;
for (i = 0 ; i < ngodlfs; i++) { lf = askgod("To whom will you pray?");
flag_t *f;
char godof[BUFLEN];
lf = godlf[i];
real_getlfname(lf, buf, B_FALSE);
f = hasflag(lf->flags, F_GODOF);
snprintf(godof, BUFLEN, " (%s of %s)", (f->val[0] == B_FEMALE) ? "Goddess" : "God", f->text);
strcat(buf, godof);
addchoice(&prompt, 'a', buf, NULL, lf);
}
getchoicestr(&prompt, B_FALSE, B_TRUE);
lf = (lifeform_t *)prompt.result;
if (!lf) { if (!lf) {
msg("Cancelled."); msg("Cancelled.");
return B_TRUE; return B_TRUE;
@ -1987,6 +1962,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} }
// returns TRUE on error // returns TRUE on error
int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer, int frompot) { int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer, int frompot) {
char buf[BUFLEN]; char buf[BUFLEN];
@ -2153,7 +2130,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
removedeadobs(targcell->obpile); removedeadobs(targcell->obpile);
if (targcell->lf && !skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (targcell->lf && !spellresisted(targcell->lf, caster, spellid, power, seenbyplayer, B_TRUE)) {
// destroy only WORN metal objects, not CARRIED ones // destroy only WORN metal objects, not CARRIED ones
for (o = targcell->lf->pack->first ; o ; o = o->next) { for (o = targcell->lf->pack->first ; o ; o = o->next) {
if (isequipped(o) && ismetal(o->material->id)) { if (isequipped(o) && ismetal(o->material->id)) {
@ -2391,15 +2368,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE; return B_TRUE;
} }
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
if (isplayer(target)) {
msg("You shrug off a mental attack.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, target->cell)) {
getlfname(target, buf);
msg("%s shrugs off %s mental attack.", buf, isplayer(caster) ? "your" : "a");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE; return B_FALSE;
} else { } else {
confuse(target, power*4); confuse(target, power*4);
@ -2459,7 +2428,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_FALSE; return B_FALSE;
} }
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
failed = B_TRUE; failed = B_TRUE;
} }
@ -2942,11 +2911,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_FALSE; return B_FALSE;
} }
if (skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
if (isplayer(caster) || cansee(player, target)) {
msg("%s resists.",targetname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// they get angry! // they get angry!
if (!isplayer(target) && cansee(target, caster)) { if (!isplayer(target) && cansee(target, caster)) {
fightback(target, caster); fightback(target, caster);
@ -3161,13 +3126,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
// saving throw // saving throw
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
if (isplayer(caster) || cansee(player, target)) {
char tname[BUFLEN];
getlfname(target, tname);
msg("%s resists.",tname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// they get angry! // they get angry!
if (!isplayer(target) && cansee(target, caster)) { if (!isplayer(target) && cansee(target, caster)) {
fightback(target, caster); fightback(target, caster);
@ -3550,6 +3509,43 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (ndigs == 0) { } else if (ndigs == 0) {
if (isplayer(caster)) nothinghappens(); if (isplayer(caster)) nothinghappens();
} }
} else if (spellid == OT_S_DISORIENT) {
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (lfhasflag(target, F_ASLEEP) || !ischarmable(target)) {
fizzle(caster);
return B_TRUE;
}
if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
return B_FALSE;
} else {
int newdir;
// make them face a random (different) direction
newdir = getrandomdirexcept(DT_COMPASS, target->facing);
setfacing(target, newdir);
// ai loses target info
killflagsofid(target->flags, F_TARGETLF);
killflagsofid(target->flags, F_TARGETCELL);
// announce
if (isplayer(target)) {
msg("You spin around to face %s.", getdirname(target->facing));
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) {
char tname[BUFLEN];
getlfname(target, tname);
msg("%s spins around to face %s.", tname, getdirname(target->facing));
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// make them dizzy?
if (pctchance(power*10)) {
confuse(target, 2);
}
}
} else if (spellid == OT_S_DETECTLIFE) { } else if (spellid == OT_S_DETECTLIFE) {
target = caster; target = caster;
if (isplayer(caster)) { if (isplayer(caster)) {
@ -3734,11 +3730,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// flag. // flag.
// other people get a check anyway. // other people get a check anyway.
if (targcell->lf == caster) { if (targcell->lf == caster) {
if (getmr(targcell->lf) && skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (getmr(targcell->lf) && spellresisted(targcell->lf, caster, spellid, power, seenbyplayer, B_FALSE)) {
resisted = B_TRUE; resisted = B_TRUE;
} }
} else { } else {
if (skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(targcell->lf, caster, spellid, power, seenbyplayer, B_FALSE)) {
resisted = B_TRUE; resisted = B_TRUE;
} }
} }
@ -3905,7 +3901,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf; target = targcell->lf;
if ((getattr(target, A_IQ) <= 3) || skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if ((getattr(target, A_IQ) <= 3) || spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (cansee(player, target)) { if (cansee(player, target)) {
getlfname(target, buf); getlfname(target, buf);
msg("%s %s momentarily foolish.", buf, isplayer(target) ? "feel" : "looks"); msg("%s %s momentarily foolish.", buf, isplayer(target) ? "feel" : "looks");
@ -4472,7 +4468,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_GASEOUSFORM) { } else if (spellid == OT_S_GASEOUSFORM) {
if (!target) target = caster; if (!target) target = caster;
if (getmr(target) && (target->race->id != R_VAMPIRE) && skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (getmr(target) && (target->race->id != R_VAMPIRE) && spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target)) { if (isplayer(target)) {
msg("You feel momentarily insubstantial."); msg("You feel momentarily insubstantial.");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -4599,7 +4595,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
if (getmr(target) && skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (getmr(target) && spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target) || haslos(player, target->cell)) { if (isplayer(target) || haslos(player, target->cell)) {
getlfname(target, buf); getlfname(target, buf);
msg("%s blur%s for a moment.",buf, isplayer(target) ? "" : "s"); msg("%s blur%s for a moment.",buf, isplayer(target) ? "" : "s");
@ -4902,7 +4898,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
for (l = caster->cell->map->lf ; l ; l = l->next) { for (l = caster->cell->map->lf ; l ; l = l->next) {
if (l != caster) { if (l != caster) {
if (isimmuneto(l->flags, DT_NECROTIC) || skillcheck(l, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isimmuneto(l->flags, DT_NECROTIC) ||
spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(l)) { if (isplayer(l)) {
msg("Luckily, the evil doesn't seem to harm you."); msg("Luckily, the evil doesn't seem to harm you.");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -4918,7 +4915,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
// now hit the caster! // now hit the caster!
if (isimmuneto(caster->flags, DT_NECROTIC) || skillcheck(caster, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (isimmuneto(caster->flags, DT_NECROTIC) || spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(caster)) { if (isplayer(caster)) {
msg("Luckily, the evil doesn't seem to harm you."); msg("Luckily, the evil doesn't seem to harm you.");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -5067,7 +5064,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
// destroy objects right away // destroy objects right away
removedeadobs(targcell->obpile); removedeadobs(targcell->obpile);
if (targcell->lf && !skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (targcell->lf && !spellresisted(targcell->lf, caster, spellid, power, seenbyplayer, B_TRUE)) {
// destroy only WORN metal objects, not CARRIED ones // destroy only WORN metal objects, not CARRIED ones
for (o = targcell->lf->pack->first ; o ; o = o->next) { for (o = targcell->lf->pack->first ; o ; o = o->next) {
if (isequipped(o) && ismetal(o->material->id)) { if (isequipped(o) && ismetal(o->material->id)) {
@ -5207,7 +5204,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
saved = B_TRUE; saved = B_TRUE;
} else if (skillcheck(target, SC_STR, 20 + power, 0)) { } else if (skillcheck(target, SC_STR, 20 + power, 0)) {
saved = B_TRUE; saved = B_TRUE;
@ -5241,8 +5238,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_FALSE; return B_FALSE;
} }
// make this a constitution skill check ? if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) {
failed = B_TRUE; failed = B_TRUE;
} else if (skillcheck(target, SC_CON, 20 + power, 0)) { } else if (skillcheck(target, SC_CON, 20 + power, 0)) {
failed = B_TRUE; failed = B_TRUE;
@ -5282,7 +5278,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
// savingthrow // savingthrow
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0) || skillcheck(target, SC_CON, 30 + power, 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE) || skillcheck(target, SC_CON, 30 + power, 0)) {
if (haslos(player, target->cell)) { if (haslos(player, target->cell)) {
char lfname[BUFLEN]; char lfname[BUFLEN];
getlfname(target, lfname); getlfname(target, lfname);
@ -5378,10 +5374,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
// saving throw.... // saving throw....
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
if (isplayer(caster) && cansee(player, target)) {
msg("%s%s mind fights off your intrusion!", targname, getpossessive(targname));
}
return B_FALSE; return B_FALSE;
} }
@ -6063,7 +6056,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_FALSE; return B_FALSE;
} }
if (lfhasflag(target, F_GRAVBOOSTED) || skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (lfhasflag(target, F_GRAVBOOSTED) || spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target)) { if (isplayer(target)) {
msg("You feel momentarily heavier."); msg("You feel momentarily heavier.");
} else if (cansee(player, target)) { } else if (cansee(player, target)) {
@ -6242,7 +6235,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f->val[0] += (rnd(1,6) + power); f->val[0] += (rnd(1,6) + power);
if (f->val[0] >= f->val[1]) { if (f->val[0] >= f->val[1]) {
if (isplayer(caster) || cansee(player, caster)) msg("%s is completely repaied!", fullobname); if (isplayer(caster) || cansee(player, caster)) msg("%s is completely repaired!", fullobname);
f->val[0] = f->val[1]; f->val[0] = f->val[1];
} else { } else {
if (isplayer(caster) || cansee(player, caster)) msg("%s is repaired a little!", fullobname); if (isplayer(caster) || cansee(player, caster)) msg("%s is repaired a little!", fullobname);
@ -6283,11 +6276,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getlfname(target, targetname); getlfname(target, targetname);
if (skillcheck(targcell->lf, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
if (isplayer(caster) || cansee(player, target)) {
msg("%s resists.",targetname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else { } else {
int donesomething = B_FALSE; int donesomething = B_FALSE;
@ -6334,7 +6323,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE; return B_TRUE;
} }
if ((target != caster) && skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if ((target != caster) && spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target)) { if (isplayer(target)) {
msg("You feel momentarily different."); msg("You feel momentarily different.");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -6582,6 +6571,27 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (ndone && isplayer(caster) && !frompot) { if (ndone && isplayer(caster) && !frompot) {
pleasegodmaybe(R_GODMERCY, 3); pleasegodmaybe(R_GODMERCY, 3);
} }
} else if (spellid == OT_S_LETHARGY) {
int amttolose;
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_FALSE;
}
amttolose = power*2;
// only announce if the target will have some stamina left.
// if they drop to 0, modstamina will handle the announce.
if (target->stamina >= amttolose) {
if (isplayer(target)) {
msg("You suddenly feel very lethargic!");
} else if (cansee(player, target)) {
char targname[BUFLEN];
getlfname(target, targname);
msg("%s looks very lethargic!", targname);
}
}
modstamina(target, -amttolose);
} else if (spellid == OT_S_REPELINSECTS) { } else if (spellid == OT_S_REPELINSECTS) {
// just announce // just announce
if (isplayer(caster)) { if (isplayer(caster)) {
@ -6732,14 +6742,27 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE; return B_TRUE;
} }
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target)) { // 1st skill check passed. make another one.
msg("You yawn."); if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (seenbyplayer) *seenbyplayer = B_TRUE; // 2nd one passed - no effect..
} else if (haslos(player, target->cell)) { if (isplayer(target)) {
getlfname(target, buf); msg("You yawn.");
msg("%s yawns.", buf); if (seenbyplayer) *seenbyplayer = B_TRUE;
if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (cansee(player, target)) {
getlfname(target, buf);
msg("%s yawns.", buf);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else {
// 2nd one failed - lose all stamina instead
modstamina(target, -(target->stamina));
if (isplayer(target)) {
msg("You suddenly feel very lethargic!");
} else if (cansee(player, target)) {
getlfname(target, buf);
msg("%s looks very lethargic!", buf);
}
} }
return B_FALSE; return B_FALSE;
} }
@ -6798,7 +6821,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf; target = targcell->lf;
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target)) { if (isplayer(target)) {
msg("You feel momentarily slower."); msg("You feel momentarily slower.");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -6842,13 +6865,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = haslf(targcell); target = haslf(targcell);
if (target) { if (target) {
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(caster) || cansee(player, target)) {
char tname[BUFLEN];
getlfname(target, tname);
msg("%s resists.",tname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// they get angry! // they get angry!
if (!isplayer(target) && cansee(target, caster)) { if (!isplayer(target) && cansee(target, caster)) {
fightback(target, caster); fightback(target, caster);
@ -7039,7 +7056,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE; return B_TRUE;
} }
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target)) { if (isplayer(target)) {
msg("You feel momentarily nauseated."); msg("You feel momentarily nauseated.");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -7195,15 +7212,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE; return B_TRUE;
} }
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
if (isplayer(target)) {
msg("You shrug off a mental attack.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, target->cell)) {
getlfname(target, buf);
msg("%s shrugs off %s mental attack.", buf, isplayer(caster) ? "your" : "a");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE; return B_FALSE;
} else { } else {
stun(target, (power/5)+2); stun(target, (power/5)+2);
@ -7226,16 +7235,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster); fizzle(caster);
return B_TRUE; return B_TRUE;
} }
if (skillcheck(thistarg, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(thistarg, caster, spellid, power, seenbyplayer, B_TRUE)) {
donesomething = B_TRUE;
if (isplayer(thistarg)) {
msg("You shrug off a mental attack.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, thistarg->cell)) {
getlfname(thistarg, buf);
msg("%s shrugs off %s mental attack.", buf, isplayer(caster) ? "your" : "a");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else { } else {
donesomething = B_TRUE; donesomething = B_TRUE;
stun(thistarg, (power/5)+2); stun(thistarg, (power/5)+2);
@ -7257,7 +7257,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (target) { if (target) {
int failed = B_FALSE; int failed = B_FALSE;
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
failed = B_TRUE; failed = B_TRUE;
} else { } else {
// they get pulled towards caster // they get pulled towards caster
@ -7289,7 +7289,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
target = caster; target = caster;
if (getmr(target) && skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target)) { if (isplayer(target)) {
msg("You flicker."); msg("You flicker.");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -7966,7 +7966,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf; target = targcell->lf;
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) { if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (cansee(player, target)) { if (cansee(player, target)) {
getlfname(target, buf); getlfname(target, buf);
msg("%s %s momentarily weaker.", buf, isplayer(target) ? "feel" : "looks"); msg("%s %s momentarily weaker.", buf, isplayer(target) ? "feel" : "looks");
@ -8999,6 +8999,47 @@ void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYP
} }
} }
int spellisfromschool(int spellid, enum SPELLSCHOOL school) {
objecttype_t *sp;
sp = findot(spellid);
if (hasflagval(sp->flags, F_SPELLSCHOOL, school, NA, NA, NULL)) {
return B_TRUE;
}
return B_FALSE;
}
// returns true if the spell was resisted.
int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power, int *seenbyplayer, int announce) {
char text[BUFLEN],buf[BUFLEN];
if (announce) {
getlfname(target, buf);
if (spellisfromschool(spellid, SS_MENTAL)) {
if (isplayer(target)) {
strcpy(text, "You shrug off a mental attack.");
} else {
sprintf(text, "%s shrugs off %s mental attack.", buf, isplayer(caster) ? "your" : "a");
}
} else {
if (isplayer(target)) {
strcpy(text, "You resist the effects of a spell.");
} else {
sprintf(text, "%s resists %s spell.", buf, isplayer(caster) ? "your" : "a");
}
}
}
if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), 0)) {
if (isplayer(target) || haslos(player, target->cell)) {
if (announce) {
msg("%s",text);
}
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_TRUE;
}
return B_FALSE;
}
void stopspell(lifeform_t *caster, enum OBTYPE spellid) { void stopspell(lifeform_t *caster, enum OBTYPE spellid) {
flag_t *f,*nextf; flag_t *f,*nextf;
object_t *o, *nexto; object_t *o, *nexto;

View File

@ -26,6 +26,8 @@ char *getvarpowerspelldesc(enum OBTYPE spellid, int power, char *buf);
void pullobto(object_t *o, lifeform_t *lf); void pullobto(object_t *o, lifeform_t *lf);
int schoolappearsinbooks(enum SPELLSCHOOL ss); 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 spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot);
int spellisfromschool(int spellid, enum SPELLSCHOOL school);
int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power, int *seenbyplayer, int announce);
void stopspell(lifeform_t *caster, enum OBTYPE spellid); void stopspell(lifeform_t *caster, enum OBTYPE spellid);
void stopallspells(lifeform_t *lf); void stopallspells(lifeform_t *lf);
void stopallspellsexcept(lifeform_t *lf, ...); void stopallspellsexcept(lifeform_t *lf, ...);

View File

@ -20,5 +20,6 @@ goesin:dungeon
playerstart playerstart
atoneof(8,1)(8,3)(8,5) ob:playerstart atoneof(8,1)(8,3)(8,5) ob:playerstart
mayrotate mayrotate
autopop
@end @end

View File

@ -22,5 +22,6 @@ x:exit
goesin:dungeon goesin:dungeon
playerstart playerstart
mayrotate mayrotate
autopop
@end @end

View File

@ -21,5 +21,6 @@ goesin:dungeon
autodoors:50 autodoors:50
playerstart playerstart
mayrotate mayrotate
autopop
@end @end

View File

@ -20,5 +20,6 @@ x:exit
goesin:dungeon goesin:dungeon
playerstart playerstart
mayrotate mayrotate
autopop
@end @end

View File

@ -17,5 +17,6 @@ x:exit
goesin:dungeon goesin:dungeon
playerstart playerstart
mayrotate mayrotate
autopop
@end @end

View File

@ -19,5 +19,6 @@ x:exit
goesin:dungeon goesin:dungeon
playerstart playerstart
mayrotate mayrotate
autopop
@end @end

View File

@ -22,5 +22,6 @@ f:ob:fountain
goesin:dungeon goesin:dungeon
playerstart playerstart
mayrotate mayrotate
autopop
@end @end