- [+] young hawk moving very slowly? was healing.

- [+] make monsters heal faster when resting
- [+] make pet rest when you do
- [+] allow 'R' to heal allies
    - [+] F_RESTUNTILALLIES
- [+] mindless/animal mosnters won't throw things
- [+] announceflag for attrset not working
* [+] feeblemind spell - reduces intelligence to ANIMAL.
- [+] ai: if we are carrying too much, drop something
      (non-weapons/armour first)
- [+] teleport spell should teleport any adjacent allies too.
* [+] new 'C'hat commands:
* [+] change 'resist elements' potion to 'rum'
* [+] notify when pet is low on hp
- [+] why could a pirate use a biuckler?
* [+] genericise usage of canhaveobmod!
- [+] armour mod: blooodstained.  adds scary.
- [+] CRASH when you have two weapons and catch a glowbug in your flask.
* [+] potion of restoration onto frozen axe:
- [+] slow spell repeated message: The brown snake looks sluggish.  The
      brown snake is now moving slower.
- [+] make you only hear one thing each turn ?
- [+] always draw impassable objects on top
- [+] special ash
    - [+] exploding powder - explode in radius 1 around player
          (including player)
    - [+] concealing powder - create smoke cloud radius 3 around player
- [+] redo levelup logic.
    - [+] trigger LevUp when you have 'newskillready'
        - [+] announce when you gain level.
    - [+] can't gain more experience when LevUp!
    - [+] only update maxhp/mp from new level after you train
- [+] diety can't use abilities. fixed.
* [+] when i exit from@S output, statbar isn't redrawn
* [+] make SKILLS page show which skills you can learn.
- [+] In @s, downline isn't showing the title on the second page of
      SKILLS...
- [+] show POWER in @M spells page
    - [+] ###---
- [+] show cost RANGE in @M for varpower ones
    - [+] need getspellcosttext(spellid, power, buf) function
    - [+] 25-62MP
- [+] leftover rubbish chars at end of ---- in doheading()
- [+] mosnters should follow you up/down stairs
* [+] different poison types
- [+] implement tremorsense (like darkvision butrun can't be blinded
      etc)
* [+] implement HIDE ability
* [+] Thief job
- [+] if you walk into a room and every cell is lit, reveal it all.
- [+] auto-learn jump ability with high athletics skill
* [+] secret doors
- [+] items to spot secret doors
    - [+] gem of seeing
        - [+] ENHANCESEARCH
        - [+] F_SEEINVIS
    - [+] spell:  "reveal hidden" 
        - [+] shows secret doors
        - [+] removes invisibility
    - [+] wand of detect hidden
        - [+] ... casts the spell
This commit is contained in:
Rob Pearce 2011-04-13 23:44:29 +00:00
parent c32f93294c
commit 4f54fc0ef9
26 changed files with 5624 additions and 1406 deletions

295
ai.c
View File

@ -70,8 +70,6 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
// no longer a pet
f = lfhasflagval(lf, F_PETOF, victim->id, NA, NA, NULL);
if (f) killflag(f);
f = lfhasflagval(lf, F_ALLYOF, victim->id, NA, NA, NULL);
if (f) killflag(f);
}
enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) {
@ -277,7 +275,78 @@ void aigoto(lifeform_t *lf, cell_t *c, int timelimit) {
}
}
void aimove(lifeform_t *lf) {
void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
int x,y;
cell_t *c;
int db = B_FALSE;
if (lfhasflag(lf, F_DEBUG)) {
db = B_TRUE;
}
x = f->val[0];
y = f->val[1];
if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y);
c = getcellat(lf->cell->map, x, y);
if (c) {
// target cell adjacent and something in the way?
if (movetowards(lf, c, DT_ORTH)) {
// couldn't move towards it for some reason.
// so stop trying.
if (db) dblog(".oO { couldn't walk towards f_targetcell. abandoning it. }");
killflag(f);
// remember NOT to target this one.
lf->ignorecell = c;
} else {
if (db) dblog(".oO { successfully walked towards f_targetcell. arrived at %d,%d }",lf->cell->x, lf->cell->y);
// moved towards it.
// reset lifetime
f->lifetime = AI_FOLLOWTIME;
// are we there yet?
if (lf->cell == c) {
if (db) dblog(".oO { arrived at f_targetcell. removing. }");
killflag(f);
}
}
} else {
if (db) dblog(".oO { f_targetcell doesn't exist. abandoning. }");
// destination doesn't exist!
killflag(f);
// remember NOT to target this one.
lf->ignorecell = c;
}
}
int aipickup(lifeform_t *lf, object_t *o) {
if (isedible(o)) {
return eat(lf, o);
} else {
return pickup(lf, o, o->amt, B_TRUE);
}
return B_FALSE;
}
int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target) {
switch (o->type->id) {
case OT_POT_INVIS:
case OT_WAND_INVIS:
if (lfhasflag(target, F_INVISIBLE)) {
return B_FALSE;
}
break;
case OT_POT_INVULN:
if (lfhasflag(target, F_INVULNERABLE)) {
return B_FALSE;
}
break;
default:
break;
}
return B_TRUE;
}
void aiturn(lifeform_t *lf) {
int db = B_FALSE;
object_t *curwep,*bestwep, *o;
int icanattack = B_FALSE;
@ -288,8 +357,10 @@ void aimove(lifeform_t *lf) {
// lifeform_t *fleefrom = NULL;
lifeform_t *target;
enum BODYPART bp;
int x,y;
cell_t *c;
lifeform_t *master = NULL;
enum IQBRACKET iqb;
/*
if (wantdb && haslos(player, lf->cell)) {
@ -320,8 +391,68 @@ void aimove(lifeform_t *lf) {
}
*/
///////////////////////////////////////////
// info gathering
///////////////////////////////////////////
// remember our intelligence
iqb = getiqname(getattr(lf, A_IQ), NULL);
// are we a pet?
mf = lfhasflagval(lf, F_PETOF, NA, NA, NA, NULL);
if (mf && (getallegiance(lf) == AL_FRIENDLY)) {
master = findlf(lf->cell->map, mf->val[0]);
}
///////////////////////////////////////////////
// housekeeping - weapon changes, drop/pickup,
// use items, etc
///////////////////////////////////////////////
///////////////////////////////////////////////
// healing
///////////////////////////////////////////////
// need to heal?
if (lf->hp < (lf->maxhp/2)) {
if (!useitemwithflag(lf, F_AIHEALITEM)) {
return;
}
}
// burdened?
if (isburdened(lf)) {
object_t *o,*heaviest = NULL;
float hevweight = 0;
if (db) dblog(".oO { i am burdened }");
// drop our heaviest non-equipped object
for (o = lf->pack->first ; o ; o = o->next) {
if (!isequipped(o)) {
float thisweight;
thisweight = getobweight(o);
if (thisweight > hevweight) {
hevweight = thisweight;
heaviest = o;
}
}
}
if (heaviest) {
if (db) {
char obname[BUFLEN];
getobname(o, obname, ALL);
dblog(".oO { i will drop %s to lower my burden }", obname);
}
if (!drop(heaviest, ALL)) {
return;
}
if (db) dblog(".oO { drop failed! }");
}
if (db) dblog(".oO { couldn't drop anything }");
}
// do we have a better weapon we could use?
curwep = getweapon(lf);
bestwep = getbestweapon(lf);
@ -383,6 +514,10 @@ void aimove(lifeform_t *lf) {
return;
}
///////////////////////////////////////////////
// attacks
///////////////////////////////////////////////
// do we already have a target we are attacking?
f = hasflag(lf->flags, F_TARGET);
if (f) {
@ -490,7 +625,10 @@ void aimove(lifeform_t *lf) {
}
// if not adjacent, check for guns, wands, throwing
if (goingtomove && (getcelldist(lf->cell, target->cell) > 1) && haslof(lf->cell, target->cell, LOF_NEED, NULL)) {
if (goingtomove && // if we are still planning on moving
(getcelldist(lf->cell, target->cell) > 1) && // and we're not adjacent to target
haslof(lf->cell, target->cell, LOF_NEED, NULL) && // and we have line of fire to them
(iqb > IQ_ANIMAL) ) { // and we are smarter than an animal
// can we attack by firing a weapon?
gun = getfirearm(lf);
if (goingtomove && gun && getammo(lf)) {
@ -602,45 +740,22 @@ void aimove(lifeform_t *lf) {
}
}
///////////////////////////////////////////////
// movement
///////////////////////////////////////////////
// do we have a target cell?
f = hasflag(lf->flags, F_TARGETCELL);
if (f) {
// if so, move towards it
x = f->val[0];
y = f->val[1];
if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y);
c = getcellat(lf->cell->map, x, y);
if (c) {
// target cell adjacent and something in the way?
if (movetowards(lf, c, DT_ORTH)) {
// couldn't move towards it for some reason.
// so stop trying.
if (db) dblog(".oO { couldn't walk towards f_targetcell. abandoning it. }");
killflag(f);
// remember NOT to target this one.
lf->ignorecell = c;
} else {
if (db) dblog(".oO { successfully walked towards f_targetcell. arrived at %d,%d }",lf->cell->x, lf->cell->y);
// moved towards it.
// reset lifetime
f->lifetime = AI_FOLLOWTIME;
// are we there yet?
if (lf->cell == c) {
if (db) dblog(".oO { arrived at f_targetcell. removing. }");
killflag(f);
}
}
} else {
if (db) dblog(".oO { f_targetcell doesn't exist. abandoning. }");
// destination doesn't exist!
killflag(f);
// remember NOT to target this one.
lf->ignorecell = c;
}
aimovetotargetcell(lf, f);
return;
}
///////////////////////////////////////////////
// look for something to do (objects, things
// to attack, etc)
///////////////////////////////////////////////
// look for any object which we want
if (db) dblog(".oO { looking for any ob which i want. }");
if (lookforobs(lf, B_ANY)) {
@ -708,23 +823,13 @@ void aimove(lifeform_t *lf) {
break;
}
// need to heal?
if ((lf->hp < lf->maxhp) ||
((lf->mp < getmaxmp(lf)) && lfhasflag(lf, F_RESTHEALMPAMT)) ) {
if (lf->hp < (lf->maxhp/2)) {
if (!useitemwithflag(lf, F_AIHEALITEM)) {
return;
}
}
if (db) dblog(".oO { resting }");
rest(lf, B_TRUE);
}
///////////////////////////////////////////////
// training
///////////////////////////////////////////////
// need to train skills?
if (lf->skillpoints || getattpoints(lf)) {
if (canrest(lf)) {
if (readytotrain(lf)) {
if (safetorest(lf)) {
// special case - monsters don't need to actually rest to gain
// skills, although they DO still need to wait until the player
// is out of sight.
@ -732,20 +837,23 @@ void aimove(lifeform_t *lf) {
}
}
// just try to move in a random direction
mf = lfhasflagval(lf, F_PETOF, NA, NA, NA, NULL);
if (!mf) {
mf = lfhasflagval(lf, F_ALLYOF, NA, NA, NA, NULL);
}
if (mf && (getallegiance(lf) == AL_FRIENDLY)) {
// pet movement - note that pets will only rest if their
// master is resting. the normal rest code underneath this section
// will never be called.
if (master) {
lifeform_t *master;
master = findlf(lf->cell->map, mf->val[0]);
if (master && cansee(lf, master)) {
// can see my master - either move towards them or randomly
// can see my master
if (lfhasflag(master, F_RESTING)) {
// rest as well.
rest(lf, B_TRUE);
return;
}
// - either move towards them or randomly
if (isadjacent(lf->cell, master->cell)) {
if (db) dblog(".oO { i can see my master - moving randomly }");
dorandommove(lf, B_NOBADMOVES);
return;
} else {
// move towards master if not adjacent
if (db) dblog(".oO { i can see my master - moving towards them }");
@ -753,63 +861,43 @@ void aimove(lifeform_t *lf) {
// failed
if (db) dblog(".oO { failed. moving randomly }");
dorandommove(lf, B_NOBADMOVES);
return;
} else {
// success
if (db) dblog(".oO { success. }");
}
return;
}
return;
} else {
// try to move towards master's last known loc
if (mf->val[1] != NA) {
if (db) dblog(".oO { cannot see my master - adding F_TARGETCELL for last known loc }");
addflag(lf->flags, F_TARGETCELL, mf->val[1], mf->val[2], NA, NULL);
f = addflag(lf->flags, F_TARGETCELL, mf->val[1], mf->val[2], NA, NULL);
aimovetotargetcell(lf, f);
} else {
if (db) dblog(".oO { cannot see my master and dont have a last known location. randommove. }");
dorandommove(lf, B_NOBADMOVES);
return;
}
// exit the function without moving - next time we will do a move due to f_targetcell code.
return;
}
} else {
if (db) dblog(".oO { default - moving randomly }");
dorandommove(lf, B_NOBADMOVES);
}
///////////////////////////////////////////////
// resting / healing
///////////////////////////////////////////////
// need to heal?
if (needstorest(lf, NULL) && safetorest(lf)) {
if (db) dblog(".oO { resting to heal }");
rest(lf, B_TRUE);
return;
}
// if we get this far, just wait
rest(lf, B_TRUE);
// DEFAULT - try to move in a random direction
if (db) dblog(".oO { default - moving randomly }");
dorandommove(lf, B_NOBADMOVES); // this function will call rest() if we cant move
}
int aipickup(lifeform_t *lf, object_t *o) {
if (isedible(o)) {
return eat(lf, o);
} else {
return pickup(lf, o, o->amt, B_TRUE);
}
return B_FALSE;
}
int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target) {
switch (o->type->id) {
case OT_POT_INVIS:
case OT_WAND_INVIS:
if (lfhasflag(target, F_INVISIBLE)) {
return B_FALSE;
}
break;
case OT_POT_INVULN:
if (lfhasflag(target, F_INVULNERABLE)) {
return B_FALSE;
}
break;
default:
break;
}
return B_TRUE;
}
// is the spell 'spellid' okay for AI lifeform 'lf' to cast at 'victim', for given purpose.
// purpose could be F_AICASTTOFLEE or F_ATCASTTOATTACK
@ -983,9 +1071,16 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
specificcheckok = B_FALSE;
}
}
if ((ot->id == OT_S_HASTE) && lfhasflag(lf, F_FASTACT)) {
if ((ot->id == OT_S_HASTE) && (lfhasflag(victim, F_FASTACT) || lfhasflag(victim, F_FASTACTMOVE)) ) {
specificcheckok = B_FALSE;
}
if (ot->id == OT_A_HIDE) {
if (lfhasflag(victim, F_HIDING)) {
specificcheckok = B_FALSE;
} else if (!safetorest(victim)) {
specificcheckok = B_FALSE;
}
}
if ((ot->id == OT_S_INVISIBILITY) && lfhasflag(victim, F_INVISIBLE)) {
specificcheckok = B_FALSE;
}
@ -1004,7 +1099,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if ((ot->id == OT_S_SLEEP) && lfhasflag(victim, F_ASLEEP)) {
specificcheckok = B_FALSE;
}
if ((ot->id == OT_S_SLOW) && lfhasflag(victim, F_SLOWACT)) {
if ((ot->id == OT_S_SLOW) && (lfhasflag(victim, F_SLOWACT) || lfhasflag(victim, F_SLOWACTMOVE)) ) {
specificcheckok = B_FALSE;
}
if ((ot->id == OT_A_SPRINT) && lfhasflag(lf, F_SPRINTING)) {
@ -1249,3 +1344,5 @@ int useitemwithflag(lifeform_t *lf, enum FLAG whichflag) {
// failed to use an item
return B_TRUE;
}

3
ai.h
View File

@ -6,10 +6,11 @@ enum OBTYPE aigetfleespell(lifeform_t *lf);
void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose);
object_t * aigetwand(lifeform_t *lf, enum FLAG purpose);
void aigoto(lifeform_t *lf, cell_t *c, int timelimit);
void aimove(lifeform_t *lf);
void aimovetotargetcell(lifeform_t *lf, flag_t *f);
int aipickup(lifeform_t *lf, object_t *o);
int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target);
int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG purpose);
void aiturn(lifeform_t *lf);
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op);
object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op);
int lookforobs(lifeform_t *lf, int covetsonly);

View File

@ -254,10 +254,10 @@ int attackcell(lifeform_t *lf, cell_t *c) {
if (validwep[i]) {
if (attacktype == AT_LF) {
if (!isdead((lifeform_t *)attacktarget)) {
attacklf(lf, (lifeform_t *)attacktarget, wep[i], damflag[i]);
if (attacklf(lf, (lifeform_t *)attacktarget, wep[i], damflag[i])) break;
}
} else if (attacktype == AT_OB) {
attackob(lf, (object_t *)attacktarget, wep[i], damflag[i]);
if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) break;
}
}
}
@ -350,7 +350,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
msg("%s drops to the ground.", buf);
}
}
return B_FALSE;
// stop all further attacks
return B_TRUE;
}
}
@ -644,8 +645,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// first saving throw...
if (skillcheck(victim, SC_CON, 25, 0)) {
// slowed
addtempflag(victim->flags, F_SLOWMOVE, 15, NA, NA, NULL, 2);
addtempflag(victim->flags, F_SLOWACT, 15, NA, NA, NULL, 2);
addtempflag(victim->flags, F_SLOWACTMOVE, 15, NA, NA, NULL, 2);
} else {
// second saving throw...
if (skillcheck(victim, SC_CON, 25, 0)) {
@ -713,7 +713,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// induction of fear?
if (!isdead(victim)) {
if (lfhasflag(victim, F_INDUCEFEAR)) {
scare(lf, victim, rnd(2,3));
if (cansee(lf, victim)) {
scare(lf, victim, rnd(2,3));
}
}
}
@ -1670,6 +1672,9 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
if (fid == F_POISONED) {
// need to fill in the name of what poisoned us
char frombuf[BUFLEN];
flag_t *typeflag;
enum POISONTYPE ptype;
int ppower;
if (wep) {
if (owner) {
char lfname[BUFLEN];
@ -1687,7 +1692,21 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
} else {
strcpy(frombuf, "something unknown");
}
poison(victim, howlong, frombuf);
typeflag = hasflag(f->pile, F_HITPOISONTYPE);
if (typeflag) {
ptype = typeflag->val[0];
if (typeflag->val[1] == NA) {
ppower = 1;
} else {
ppower = typeflag->val[1];
}
} else {
// should never happen.
ptype = P_VENOM;
ppower = 1;
}
poison(victim, howlong, ptype, ppower, frombuf);
} else {
addtempflag(victim->flags, fid, NA, NA, NA, NULL, howlong);
}

78
defs.h
View File

@ -7,9 +7,12 @@
#define PRACTICETIME 50 // #attempts it takes to learn new skill
#define WETTIME 10 // how long it takes for things to dry
#define DRUNKTIME 10 // how long it takes for alcohol to wear off
/*
#define POISONDAMCHANCE 33 // chance of vomitting when poisoned
#define POISONDAM 2 // damage taken from vomiting when poisoned
*/
// ncurses colours
enum COLOUR {
@ -76,6 +79,7 @@ enum CHECKTYPE {
SC_OPENLOCKS,
SC_POISON,
SC_RESISTMAG,
SC_SEARCH,
SC_STEALTH,
SC_WILL,
};
@ -120,7 +124,9 @@ enum LFCONDITION {
#define FROMBRAND (-9865)
#define FROMOBMOD (-9864)
#define FROMSPELL (-9863)
#define FROMPOISON (-9862)
#define LEVABILITYDONE (-8000)
#define IFKNOWN (-9772) // used by f_xxconfer. only confer a flag if item is known.
#define IFACTIVE (-9771) // used by f_prodeuceslight. only does so if object is activated
@ -521,6 +527,7 @@ enum RACE {
R_WOLF,
// insects
R_BUTTERFLY,
R_CENTIPEDE,
R_GLOWBUG,
R_GIANTFLY,
R_GIANTBLOWFLY,
@ -545,6 +552,7 @@ enum JOB {
J_PIRATE,
J_PLUMBER,
J_PRINCE,
J_ROGUE,
J_WIZARD,
};
@ -601,6 +609,8 @@ enum OBTYPE {
OT_GOLD,
OT_STONE,
OT_ASH,
OT_ASHEXPLODE,
OT_ASHCONCEAL,
OT_GEMOFSEEING,
// food
OT_BERRY,
@ -639,7 +649,6 @@ enum OBTYPE {
OT_POT_BLOOD,
OT_POT_BLOODC,
OT_POT_COMPETENCE,
OT_POT_ELEMENTENDURE,
OT_POT_ELEMENTIMMUNE,
OT_POT_ETHEREALNESS,
OT_POT_EXPERIENCE,
@ -653,6 +662,7 @@ enum OBTYPE {
OT_POT_POISON,
OT_POT_POLYMORPH,
OT_POT_RESTORATION,
OT_POT_RUM,
OT_POT_SANCTUARY,
OT_POT_SPEED,
OT_POT_WATER,
@ -690,6 +700,7 @@ enum OBTYPE {
OT_MAN_RESEARCH,
OT_MAN_SHIELDS,
OT_MAN_SPELLCASTING,
OT_MAN_SPOTHIDDEN,
OT_MAN_STEALTH,
OT_MAN_TECHUSAGE,
// manuals of weaponry
@ -705,6 +716,7 @@ enum OBTYPE {
OT_MAN_SS_AIR,
OT_MAN_SS_DEATH,
OT_MAN_SS_DIVINATION,
OT_MAN_SS_EARTH,
OT_MAN_SS_FIRE,
OT_MAN_SS_ICE,
OT_MAN_SS_GRAVITY,
@ -724,11 +736,13 @@ enum OBTYPE {
OT_SB_POISONBOLT,
OT_SB_INFINITEDEATH,
OT_SB_WEAKEN,
OT_SB_FEEBLEMIND,
OT_SB_BLINDNESS,
// -- divination
OT_SB_DETECTAURA,
OT_SB_DETECTLIFE,
OT_SB_DETECTOBS,
OT_SB_REVEALHIDDEN,
OT_SB_IDENTIFY,
OT_SB_MAPPING,
// -- elemental - air
@ -799,6 +813,7 @@ enum OBTYPE {
OT_S_PARALYZE,
OT_S_INFINITEDEATH,
OT_S_WEAKEN,
OT_S_FEEBLEMIND,
OT_S_BLINDNESS,
OT_S_POISONBOLT,
OT_S_POSSESSION,
@ -807,6 +822,7 @@ enum OBTYPE {
OT_S_DETECTLIFE,
OT_S_DETECTOBS,
OT_S_DETECTMAGIC,
OT_S_REVEALHIDDEN,
OT_S_IDENTIFY,
OT_S_MAPPING,
// -- elemental - air
@ -885,6 +901,7 @@ enum OBTYPE {
OT_A_SWOOP,
OT_A_EMPLOY,
OT_A_HEAVYBLOW,
OT_A_HIDE,
OT_A_INSPECT,
OT_A_HURRICANESTRIKE,
OT_A_POLYREVERT,
@ -903,6 +920,7 @@ enum OBTYPE {
OT_WAND_KNOCK,
OT_WAND_LIGHT,
OT_WAND_POLYMORPH,
OT_WAND_REVEALHIDDEN,
OT_WAND_SLOW,
OT_WAND_WEAKNESS,
OT_WAND_WONDER,
@ -1159,6 +1177,13 @@ enum ALLEGIENCE {
AL_FRIENDLY, // will help you fight
};
enum POISONTYPE {
P_FOOD,
P_GAS,
P_VENOM,
P_WEAKNESS,
};
enum FLAG {
F_NONE, // dummy flag
// object flags
@ -1216,12 +1241,15 @@ enum FLAG {
F_HITCONFER, // hitting with this gives flagid=v0
// unless you pass a val1 skillcheck, diff val2
// with timeleft = text ("min-max")
F_HITPOISONTYPE, // used when you have f_hitconfer->f_poisoned.
// v0 is type of poison.
// v1 is power (NA means 1)
F_ACTIVATED, // val0 = is this object turned on?
F_GRENADE, // this obkejct will drain charge when activated, then die
F_EXPLODEONDEATH, // explodes when it dies, deals val0 vamage.
F_EXPLODEONDEATH, // explodes when it dies, deals TEXT damage.
// val1 = BIG means hit surrounding cells
// val2 = ifactivated, only explodes if activated.
F_EXPLODEONDAM, // explodes when it is damaged, deals val0 vamage.
F_EXPLODEONDAM, // explodes when it is damaged, deals TEXT damage.
// val1 = BIG means hit surrounding cells
// val2 = ifactivated, only explodes if activated.
F_FLASHONDEATH, // produce a bright flash when it dies,v0=range
@ -1257,6 +1285,8 @@ enum FLAG {
F_OPEN, // is this door open?
F_LOCKED,// door is locked
F_JAMMED, // is this door jammed?
F_SECRETDOOR, // this door is secret. v0 is sc_search difficulty
// to find it.
// stairs / teleporters / portals
F_CLIMBABLE, // this is a stiarcase, v0 = up/down/in
// also use this for portals
@ -1270,6 +1300,8 @@ enum FLAG {
// ob interaction flags
F_HARD, // object is hard (ie. punching it will hurt!)
F_SHARP, // does damage when you step on it. v0/1 are min/max dam
F_SCARY, // gives other lfs a penalty to morale checks against you,
// v0 = penalty amt.
F_SLIPPERY, // you might slip when stepping on it. v0 is amt
F_SLIPMOVE, // if someone slips on this, it will move to an adj cell
F_FLAMMABLE, // object will catch alight if burnt (ie fire damage)
@ -1295,6 +1327,7 @@ enum FLAG {
F_OBATTACKDELAY, // how long weapon takes to attack
F_USESSKILL, // weapon needs skill sk_v0
F_CANHAVEOBMOD, // weapon can have obmod om_v0 applied
// optional: v1 is chance of randomly having it
F_ATTREQ, // requires attrib v0 to be at least bracket v1
//F_DAMTYPE, // val0 = damage type
//F_DAM, // val0 = ndice, val1 = nsidesondie, val2 = mod
@ -1372,6 +1405,7 @@ enum FLAG {
// using their strength
// player only flags
F_DONEDARKMSG, // tells the game not to say 'it is very dark here'
F_DONELISTEN, // supress further 'you hear xx' messages this turn.
// lifeform flags / lf flags
F_DEBUG, // debugging enabled
F_ACCURACYMOD, // modify your accuracy by val0
@ -1415,17 +1449,11 @@ enum FLAG {
// MONSTER AI FLAGS
F_XPVAL, // force xp val for killing this lf to v0
// ...OR if applied to an ability...
// monsters with this abil are worth
// monsters with this abil/spell are worth
// v0 more xp.
F_XPMULTIPLY, // multiply xp val for killing this lf by v0
F_PETOF, // this lf is a pet of lfid v0
// v1/2 = last known location of my owner.
F_ALLYOF, // this lf is a ally of lfid v0
// v1/2 = last known location of my owner.
// difference between this an 'petof' will be that
// you don't get alignment penalties etc for your
// ally dying.
F_HOSTILE, // lf will attack the player if in sight
F_FRIENDLY, // lf will attack all non-players if in sight
F_WANTS, // lf will try to pick up object type val0. if
@ -1491,6 +1519,7 @@ enum FLAG {
// to the victim
F_PHALANX, // gain v0 AR if v2 or more adj monsters matching f->text
F_MORALE, // gain +v0 in morale checks.
F_SPOTTED, // you have spotted hiding lf id v0
// INTRINSICS
F_MAGICARMOUR,// armour is magically boosted. f->text is the description
// ie 'magic armour', 'force field'
@ -1518,6 +1547,8 @@ enum FLAG {
F_DETECTMAGIC, // autodetect magic/special objects
F_DETECTMETAL, // autodetect nearby metal
F_DETECTOBS, // autodetect nearby obs in orthog dist v0
F_DRUNK, // v1 is drunknness - 1-5.
F_ENHANCESEARCH, // gives v0 bonus on search checks.
F_EXTRADAM, // do 'text' extra damage of damtype v0 when you hit
// if v1 is TRUE, also deal extra damage based on
// the flagpile's F_BONUS flag.
@ -1527,11 +1558,15 @@ enum FLAG {
F_FLYING, // lf is flying
F_FASTACT, // modifier for action speed
F_FASTMOVE, // modifier for move speed
F_POISONED, // has food poisoning. text = what from.eg'a bad egg'
F_FASTACTMOVE, // modifier for action and move speed
F_POISONED, // has poisoning. v0 = poison type,
// v1 = power
// text = what from.eg'a bad egg'
F_FREEZINGTOUCH,// next thing touched turns to ice!
F_GRABBEDBY,// you've been grabbed by lf id v0
F_GRABBING, // you are grabbing lf id v0
F_HEAVYBLOW, // next attack is a heavy blow
F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks.
F_INVISIBLE, // lifeform is invisible
F_INVULNERABLE,// immune to most damage
F_QUICKBITE, // deals v0 d d1 + d2 damage when you hit a bleeding victim
@ -1551,8 +1586,8 @@ enum FLAG {
F_MPREGEN, // regenerate MP at val0 per turn
F_RISEASGHOST, // become a ghost when you die.
F_SEEINDARK, // nightvis range is val0
F_TREMORSENSE, // doesn't need eyes to see, can see in dark with v0
F_SEEINVIS, // can see invisible things
F_SEEWITHOUTEYES, // doesn't need eyes to see
F_STABILITY, // doesn't slip over
F_STENCH, // creatures within v0 gain f_nauseated = v1
F_PRODUCESLIGHT, // produces light of val0 radius.
@ -1561,6 +1596,7 @@ enum FLAG {
// is activated!
F_SLOWACT, // modifier for action speed
F_SLOWMOVE, // modifier for move speed
F_SLOWACTMOVE, // modifier for move and action speed
F_XRAYVIS, //val0=num of walls we can see through
F_CANSEETHROUGHMAT, //val0=kind of material you can see through
F_SPRINTING, // v0=true: you are sprinting. false=you are tired
@ -1580,6 +1616,7 @@ enum FLAG {
F_EVASION, // % chance of evading an attack
// healing/resting/training
F_HASNEWLEVEL, // we have a new xp lev, but haven't trained yet.
F_STATGAINREADY, // ready to increase str/int etc. v2 is how many times
// we can do it.
F_INTERRUPTED, // somethign interrupted our rest. stop!
@ -1588,6 +1625,7 @@ enum FLAG {
// when it hits 0, you finish trainign.
F_RESTUNTILHP, // resting until we have full hp
F_RESTUNTILMP, // resting until we have full mp
F_RESTUNTILALLIES, // resting until allies have full hp
//
F_RUNNING, // are we running?
// nutrition
@ -1606,6 +1644,10 @@ enum FLAG {
// v2 = how often you can do it (or NA for unlimited)
// text = options
F_LEVSPELL, // at level v0, this job gains f_cancast v1.
F_LEVSPELLSCHOOL, // at level v0, this job gains f_cancast for a spell
// of their choice from school v1. if v1 is SS_NONE, they can
// pick form any school they are skilled in.
// if v0 is >100, this triggers every (v0-100) levels.
F_LEVFLAG, // at level v0, this job gains flagid v1, flagval0=v2,
// flagtext = text
@ -1752,6 +1794,9 @@ enum ERROR {
// charm failure reasons
// LOWIQ = 42
E_UNDEAD = 46,
E_DRUNK = 47,
//
E_NOBP = 48,
};
@ -1881,6 +1926,7 @@ typedef struct lifeform_s {
int controller;
struct race_s *race;
int level;
int newlevel;
long xp;
int skillpoints;
int hp,maxhp;
@ -1964,9 +2010,9 @@ typedef struct material_s {
} material_t;
#define SK_NONE -1
enum SKILL {
SK_ARMOUR,
SK_NONE = 0,
SK_ARMOUR = 1,
SK_ATHLETICS,
SK_BACKSTAB,
SK_FIRSTAID,
@ -1976,6 +2022,7 @@ enum SKILL {
SK_RESEARCH,
SK_SHIELDS,
SK_SPELLCASTING,
SK_SPOTHIDDEN,
SK_STEALTH,
SK_TECHUSAGE,
// weaponry
@ -2002,7 +2049,7 @@ enum SKILL {
SK_SS_TRANSLOCATION,
SK_SS_WILD,
};
#define MAXSKILLS 33
#define MAXSKILLS 35
// proficiency levels
enum SKILLLEVEL {
@ -2100,6 +2147,7 @@ enum RUSTINESS {
};
enum OBMOD {
OM_BLOODSTAINED,
OM_FLAMING,
OM_FROZEN,
OM_HEADLESS,

7
doc/add_levelabil.txt Normal file
View File

@ -0,0 +1,7 @@
defs.h:
Add flag F_LEVxxx
lf.c:
Update enhanceskills()
Update refreshlevelabilities()
Update levelabilityready()

9
doc/add_poisontype.txt Normal file
View File

@ -0,0 +1,9 @@
defs.h:
add enum POISONTYPE
lf.c:
update getpoisondam()
update getpoisondamchance()
update getpoisonverb()
update getpoisonname()
update poison()

View File

@ -20,7 +20,6 @@ spell.c:
blindness if the effect is vision-based
ai.c
update aigetspelltarget();
update aigetattackspell();
update aigetspelltarget(); (if we have target ST_SPECIAL)
update aispellok();

View File

@ -5,6 +5,7 @@ defs.h:
objects.c:
update getschoolname
update getschoolnameshort
spell.c:
update getschoolskill to return the skill for this school

1
flag.c
View File

@ -200,6 +200,7 @@ int flagcausesredraw(lifeform_t *lf, enum FLAG fid) {
case F_DETECTLIFE:
case F_DETECTOBS:
case F_FASTMOVE:
case F_HIDING:
case F_INVISIBLE:
case F_SEEINDARK:
case F_SEEINVIS:

497
io.c
View File

@ -248,7 +248,7 @@ void animradial(cell_t *src, int radius, char ch, int colour) {
for (y = src->y - radius ; y <= src->y + radius ; y++) {
for (x = src->x - radius ; x <= src->x + radius ; x++) {
c = getcellat(src->map, x, y);
if (c && haslos(player, c) && (getcelldistorth(src, c) <= i)) {
if (c && haslos(player, c) && (getcelldist(src, c) <= i)) {
// draw char & cursor at its current pos...
//mvwprintw(gamewin, c->y - viewy, c->x - viewx, "%c", ch);
drawglyph(&gl, c->x - viewx, c->y - viewy);
@ -287,7 +287,7 @@ void animradialorth(cell_t *src, int radius, char ch,int colour) {
for (y = src->y - radius ; y <= src->y + radius ; y++) {
for (x = src->x - radius ; x <= src->x + radius ; x++) {
c = getcellat(src->map, x, y);
if (c && haslos(player, c) && (getcelldist(src, c) <= i)) {
if (c && haslos(player, c) && (getcelldistorth(src, c) <= i)) {
// draw char & cursor at its current pos...
//mvwprintw(gamewin, c->y - viewy, c->x - viewx, "%c", ch);
drawglyph(&gl, c->x - viewx, c->y - viewy);
@ -386,8 +386,13 @@ cell_t *askcoords(char *prompt, int targettype) {
valid = B_TRUE;
} else if ((targettype & TT_OBJECT) && hasobject(c)) {
valid = B_TRUE;
} else if ((targettype & TT_DOOR) && hasobwithflag(c->obpile, F_DOOR)) {
valid = B_TRUE;
}
if (targettype & TT_DOOR) {
object_t *o;
o = hasobwithflag(c->obpile, F_DOOR);
if (o && !hasflag(o->flags, F_SECRETDOOR)) {
valid = B_TRUE;
}
}
if (valid) {
@ -402,7 +407,6 @@ cell_t *askcoords(char *prompt, int targettype) {
// start prompting
if (curtarget == -1) {
c = player->cell;
} else {
@ -453,10 +457,12 @@ cell_t *askcoords(char *prompt, int targettype) {
case AL_FRIENDLY:
if (!isplayer(c->lf)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
if (lfhasflagval(c->lf, F_ALLYOF, player->id, NA, NA, NULL)) {
strcat(extrainfo, "ally");
} else if (lfhasflagval(c->lf, F_PETOF, player->id, NA, NA, NULL)) {
strcat(extrainfo, "pet");
if (lfhasflagval(c->lf, F_PETOF, player->id, NA, NA, NULL)) {
if (lfhasflag(c->lf, F_ANIMAL)) {
strcat(extrainfo, "pet");
} else {
strcat(extrainfo, "ally");
}
} else {
strcat(extrainfo, "friendly");
}
@ -474,6 +480,10 @@ cell_t *askcoords(char *prompt, int targettype) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "fleeing");
}
if (lfhasflag(c->lf, F_RESTING)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "resting");
}
if (lfhasflag(c->lf, F_ASLEEP)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "asleep");
@ -726,9 +736,9 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
break;
case F_ATTRSET:
if (f->val[1] != getattr(lf, f->val[0])) {
if (f->val[1] != real_getattr(lf, f->val[0], B_TRUE)) {
int myatt;
myatt = getattr(lf, f->val[0]);
myatt = real_getattr(lf, f->val[0], B_TRUE);
switch (f->val[0]) {
case A_STR:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < myatt) ? "weak" : "strong");
@ -864,6 +874,16 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
}
break;
case F_HIDING:
if (isplayer(lf)) { // don't know if monsters get it
if (f->val[0] < 0) {
msg("You are now trying to hide.");
} else {
msg("You are now hiding.");
}
donesomething = B_TRUE;
}
break;
case F_INVISIBLE:
if (isplayer(lf)) {
if (lfhasflag(player, F_SEEINVIS)) {
@ -905,6 +925,16 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
msg("%s %s very sick.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
break;
case F_ENHANCESEARCH:
if (isplayer(lf)) {
msg("You feel very perceptive!");
}
donesomething = B_TRUE;
break;
case F_DRUNK:
msg("%s %s tipsy.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
break;
case F_EXTRADAM:
if (isplayer(lf)) { // don't know if monsters get it
msg("You feel more dangerous!");
@ -931,6 +961,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
msg("%s %s faster.",lfname, isplayer(lf) ? "feel yourself moving" : "is now moving");
donesomething = B_TRUE;
break;
case F_FASTACTMOVE:
msg("%s %s",lfname, isplayer(lf) ? "feel faster and quicker!" : "looks faster and quicker.");
donesomething = B_TRUE;
break;
case F_FLYING:
msg("%s begin%s to fly!",lfname, isplayer(lf) ? "" : "s");
donesomething = B_TRUE;
@ -1034,6 +1068,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
msg("%s %s slower.",lfname, isplayer(lf) ? "feel yourself moving" : "is now moving");
donesomething = B_TRUE;
break;
case F_SLOWACTMOVE:
msg("%s %s",lfname, isplayer(lf) ? "feel slow and sluggish." : "looks slow and sluggish.");
donesomething = B_TRUE;
break;
case F_SPRINTING:
msg("%s %s sprinting!",lfname, isplayer(lf) ? "start" : "starts");
donesomething = B_TRUE;
@ -1046,6 +1084,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
msg("%s looks exhausted.",lfname);
}
break;
case F_TREMORSENSE:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can 'see' by sensing vibrations around you.");
donesomething = B_TRUE;
}
break;
case F_WINDSHIELD:
if (isplayer(lf)) {
msg("You are surrounded by a whirling cyclone!");
@ -1134,9 +1178,9 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
break;
case F_ATTRSET:
if (f->val[1] != getattr(lf, f->val[0])) {
if (f->val[1] != real_getattr(lf, f->val[0], B_TRUE)) {
int myatt;
myatt = getattr(lf, f->val[0]);
myatt = real_getattr(lf, f->val[0], B_TRUE);
switch (f->val[0]) {
case A_STR:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "less strong" : "less weak");
@ -1223,6 +1267,16 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
}
break;
case F_ENHANCESEARCH:
if (isplayer(lf)) {
msg("You no longer feel so perceptive!");
}
donesomething = B_TRUE;
break;
case F_DRUNK:
msg("%s %s more steady now.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
break;
case F_EXTRADAM:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You no longer feel more dangerous.");
@ -1249,6 +1303,10 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
msg("%s %s slower.",lfname, isplayer(lf) ? "feel yourself moving" : "is now moving");
donesomething = B_TRUE;
break;
case F_FASTACTMOVE:
msg("%s %s",lfname, isplayer(lf) ? "slow down back to normal speed." : "slows down to its normal speed.");
donesomething = B_TRUE;
break;
case F_FLEEFROM:
msg("%s stop%s fleeing.", lfname, isplayer(lf) ? "" : "s");
donesomething = B_TRUE;
@ -1266,6 +1324,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
}
break;
case F_HIDING:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You are no longer hidden.");
donesomething = B_TRUE;
}
break;
case F_INVISIBLE:
if (isplayer(lf)) {
msg("Your are no longer invisible.");
@ -1431,6 +1495,10 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
msg("%s %s faster.",lfname, isplayer(lf) ? "feel yourself moving" : "is now moving");
donesomething = B_TRUE;
break;
case F_SLOWACTMOVE:
msg("%s %s",lfname, isplayer(lf) ? "speed back up." : "speeds back up.");
donesomething = B_TRUE;
break;
case F_SPRINTING:
if (f->val[0]) {
if (isplayer(lf)) { // don't know if monsters lose it (but you'll see them get exhausted)
@ -1453,6 +1521,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
}
donesomething = B_TRUE;
break;
case F_TREMORSENSE:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You no longer sense vibrations around you.");
donesomething = B_TRUE;
}
break;
case F_WINDSHIELD:
if (isplayer(lf) || cansee(player, lf)) {
msg("%s%s cyclonic shield vanishes.", lfname, getpossessive(lfname));
@ -2133,12 +2207,15 @@ void centre(WINDOW *win, int y, char *format, ... ) {
int w;
char buf[BUFLEN];
va_list args;
int startx;
va_start(args, format);
vsprintf( buf, format, args );
va_end(args);
w = getmaxx(win);
startx = (w/2) - (strlen(buf)/2);
if (startx < 0) startx = 0;
mvwprintw(win, y, (w/2) - (strlen(buf)/2), buf);
}
@ -2425,14 +2502,18 @@ void describeob(object_t *o) {
y++;
}
f = hasflag(o->flags, F_PICKLOCKS);
if (f) {
mvwprintw(mainwin, y, 0, "You can use it to pick locks.");
y++;
}
f = hasflag(o->flags, F_SCARY);
if (f) {
mvwprintw(mainwin, y, 0, "It may unnerve others when worn.");
y++;
}
// immunities
for (i = 0; i < MAXDAMTYPE; i++) {
if (isimmuneto(o->flags, i)) {
@ -2508,7 +2589,6 @@ void describeob(object_t *o) {
// if known, show what it confers
y++;
for (f = o->flags->first ; f ; f = f->next) {
if ((f->id == F_HOLDCONFER) || (f->id == F_EQUIPCONFER) || (f->id == F_ACTIVATECONFER)) {
if (obknown) {
@ -2549,6 +2629,12 @@ void describeob(object_t *o) {
case F_DETECTMETAL:
mvwprintw(mainwin, y, 0, "%s will detect nearby metal.", buf); y++;
break;
case F_ENHANCESEARCH:
mvwprintw(mainwin, y, 0, "%s enhances your searching ability.", buf); y++;
break;
case F_DRUNK:
mvwprintw(mainwin, y, 0, "%s makes you tipsy.", buf); y++;
break;
case F_EXTRAINFO:
mvwprintw(mainwin, y, 0, "%s provides enhanced knowledge to you.", buf); y++;
break;
@ -2668,6 +2754,9 @@ void describeob(object_t *o) {
case F_SLOWMOVE:
mvwprintw(mainwin, y, 0, "%s will slow down your movement.", buf); y++;
break;
case F_TREMORSENSE:
mvwprintw(mainwin, y, 0, "%s allows you to 'see' by sensing vibrations around you.", buf); y++;
break;
case F_WINDSHIELD:
mvwprintw(mainwin, y, 0, "%s will surround you with a cyclonic shield.", buf); y++;
break;
@ -2712,7 +2801,8 @@ void describeob(object_t *o) {
// skill type?
f = hasflag(o->flags, F_USESSKILL);
if (f) {
mvwprintw(mainwin, y, 0, "It falls into the '%s' category of weapons.",getskillname(f->val[0]));
mvwprintw(mainwin, y, 0, "It falls into the '%s' category (your skill: %s).",getskillname(f->val[0]),
getskilllevelname(getskill(player, f->val[0])) );
y++;
}
@ -2907,7 +2997,7 @@ void docomms(void) {
initprompt(&prompt, buf);
prompt.maycancel = B_TRUE;
// are they friendly?
if (areallies(player, lf)) {
if (ispetof(lf, player)) {
addchoice(&prompt, 'a', "Attack something", NULL, NULL);
if (!isadjacent(lf->cell, player->cell)) {
addchoice(&prompt, 'c', "Come here", NULL, NULL);
@ -2915,6 +3005,11 @@ void docomms(void) {
if (isadjacent(lf->cell, player->cell) && !lfhasflag(lf, F_NOPACK)) {
addchoice(&prompt, 't', "Trade items with me", NULL, NULL);
}
if (lfhasflag(lf, F_RESTING)) {
addchoice(&prompt, 'r', "Stop resting.", NULL, NULL);
} else {
addchoice(&prompt, 'r', "Rest until you are healed.", NULL, NULL);
}
} else {
addchoice(&prompt, 'y', "Yeeeeeaaaargh!", NULL, NULL);
}
@ -2937,8 +3032,12 @@ void docomms(void) {
return;
}
getlfname(lf2, lfname2);
msg("You say \"Attack %s!\" to %s.",lfname2, lfname);
aiattack(lf, lf2, AI_FOLLOWTIME);
msg("You say \"Attack %s!\" to %s.",isplayer(lf2) ? "me" : lfname2, lfname);
if (isplayer(lf)) {
msg("%s looks confused at your command.", lfname);
} else {
aiattack(lf, lf2, AI_FOLLOWTIME);
}
break;
case 'c':
msg("You say \"Come here!\" to %s.",lfname);
@ -2951,6 +3050,22 @@ void docomms(void) {
case 'n':
msg("Cancelled.");
return;
case 'r':
if (lfhasflag(lf, F_RESTING)) {
stopresting(lf);
} else {
if (needstorest(lf, NULL)) {
if (safetorest(lf)) {
addflag(lf->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
startresting(lf, B_FALSE);
} else {
msg("%s is too nervous to rest (perhaps there are monsters nearby).", lfname);
}
} else {
msg("%s doesn't need to rest at the moment.", lfname);
}
}
return;
case 't':
// ask whtehr to give/take
initprompt(&prompt, "How will you trade?");
@ -3420,7 +3535,9 @@ void dolook(cell_t *where) {
}
}
void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2) {
// if wantunknown is set, lsit spells we DONT know.
// otherwise list spells we DO know.
void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, enum SPELLSCHOOL wantschool, int wantunknown) {
char ch;
flag_t *f;
char buf[BUFLEN];
@ -3438,11 +3555,21 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2)
nposs = 0;
for (i = SS_NONE+1; i < SS_LAST; i++) {
// school doesn't match the one we're asking for?
if ((wantschool != SS_NONE) && (i != wantschool)) {
continue;
}
// we can't cast spells from this school?
if (getschoolskill(i) != SK_NONE) {
if (!getskill(lf, getschoolskill(i))) {
continue;
}
}
// get list of spells/abilities we can cast at will
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == OC_SPELL) || (ot->obclass->id == OC_ABILITY)) {
f = lfhasflagval(lf, F_CANWILL, ot->id, NA, NA, NULL);
if (f) {
if (!wantunknown && f) {
if (hasflagval(ot->flags, F_SPELLSCHOOL, i, NA, NA, NULL)) {
poss[nposs] = ot->id;
deactspell[nposs] = B_FALSE; // default
@ -3470,11 +3597,12 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2)
if (!lfhasflag(lf, F_NOSPELLS)) {
// get list of spells we can cast using mp
for (ot = objecttype ; ot ; ot = ot->next) {
if (ot->obclass->id == OC_SPELL) {
if (hasflagval(ot->flags, F_SPELLSCHOOL, i, NA, NA, NULL)) {
if (ot->obclass->id == OC_SPELL) { // is it a spell?
if (hasflagval(ot->flags, F_SPELLSCHOOL, i, NA, NA, NULL)) { // from the current school?
// not using 'cancast' here because we want to list spells
// even if we don't have enough mp
if (lfhasflagval(lf, F_CANCAST, ot->id, NA, NA, NULL)) {
f = lfhasflagval(lf, F_CANCAST, ot->id, NA, NA, NULL);
if ((f && !wantunknown) || (!f && wantunknown)) {
int cost;
int found = B_FALSE;
cost = getmpcost(lf, ot->id);
@ -3498,18 +3626,7 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2)
strcpy(mpdesc[nposs], "(Deactivate, at will)");
deactspell[nposs] = B_TRUE;
} else {
int ongoing = B_FALSE;
if (hasflag(ot->flags, F_ONGOING)) ongoing = B_TRUE;
if (hasflag(ot->flags, F_VARPOWER)) {
sprintf(mpdesc[nposs], "(%d-%d MP%s)", mpcost[nposs],
mpcost[nposs] * power,
ongoing ? ", ongoing" : "");
} else {
sprintf(mpdesc[nposs], "(%d MP%s)", mpcost[nposs],
ongoing ? ", ongoing" : "");
}
getspellcosttext(lf, ot->id, power, mpdesc[nposs]);
}
if (lf->mp >= mpcost[nposs]) {
validspell[nposs] = B_TRUE;
@ -3591,7 +3708,7 @@ void domagic(enum OBTYPE spellid, int cellx, int celly) {
// init the prompt if required.
if (spellid == OT_NONE) {
makespellchoicelist(&prompt, player, "Use which spell/ability:","Describe which spell/ability:");
makespellchoicelist(&prompt, player, "Use which spell/ability:","Describe which spell/ability:", SS_NONE, B_FALSE);
}
finished = B_FALSE;
@ -3659,7 +3776,7 @@ void domemmagic(void) {
char ch;
int slot;
objecttype_t *ot;
makespellchoicelist(&prompt, player, "Memorise which spell/ability:","Describe which spell/ability");
makespellchoicelist(&prompt, player, "Memorise which spell/ability:","Describe which spell/ability",SS_NONE, B_FALSE);
if (prompt.nchoices <= 0) {
msg("You don't have any spells or abilities!");
return;
@ -4091,9 +4208,9 @@ void doread(obpile_t *op) {
void dorest(void) {
// can we rest?
if (canrest(player)) {
if (safetorest(player)) {
int willtrain = B_FALSE;
if (player->skillpoints || lfhasflag(player, F_STATGAINREADY)) {
if (lfhasflag(player, F_HASNEWLEVEL)) {
int ch;
ch = askchar("Would you like to train your skills?","yn","y", B_TRUE);
if (ch == 'y') {
@ -4105,44 +4222,48 @@ void dorest(void) {
char validchars[BUFLEN];
char ques[BUFLEN];
char ch;
strcpy(validchars, "");
if (player->hp < player->maxhp) {
strcat(validchars, "h");
}
if ((getmaxmp(player) > 0) && (player->mp < getmaxmp(player))) {
strcat(validchars, "m");
}
if (strchr(validchars, 'h') && strchr(validchars, 'm')) {
strcat(validchars, "bn");
strcpy(ques, "Rest until full HP, Mana, Both or none");
ch = askchar(ques, validchars, "b", B_TRUE);
if (ch == 'b') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
} else if (ch == 'h') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
} else if (ch == 'm') {
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
}
} else if (strchr(validchars, 'h')) {
strcpy(ques, "Rest until full HP");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
}
} else if (strchr(validchars, 'm')) {
strcpy(ques, "Rest until full Mana");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
if (needstorest(player, validchars)) {
if (strchr(validchars, 'h') && strchr(validchars, 'm')) {
strcat(validchars, "bn");
strcpy(ques, "Rest until full HP, Mana, Both, or none");
ch = askchar(ques, validchars, "b", B_TRUE);
if (ch == 'b') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
} else if (ch == 'h') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
} else if (ch == 'm') {
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
}
} else if (strchr(validchars, 'h')) {
strcpy(ques, "Rest until full HP");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
}
} else if (strchr(validchars, 'm')) {
strcpy(ques, "Rest until full Mana");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
}
}
} else {
msg("You don't need to rest at the moment.");
return;
if (countnearbyallies(player)) {
strcpy(ques, "Rest until nearby allies are healed?");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILALLIES, B_TRUE, NA, NA, NULL);
}
} else {
msg("You don't need to rest at the moment.");
return;
}
}
if (!lfhasflag(player, F_RESTUNTILHP) && !lfhasflag(player, F_RESTUNTILMP)) {
if (!lfhasflag(player, F_RESTUNTILHP) &&
!lfhasflag(player, F_RESTUNTILMP) &&
!lfhasflag(player, F_RESTUNTILALLIES)) {
msg("Cancelled.");
return;
}
@ -4313,7 +4434,10 @@ void drawscannedcell(cell_t *cell, int x, int y) {
int downline(int *y, int h, char *heading, char *subheading, char *bottomstring, char *cmdchars, char *retchar) {
char headbuf[BUFLEN];
int ch;
sprintf(headbuf, "%s (continued)", heading);
int w;
w = getmaxx(mainwin);
snprintf(headbuf, w-1, "%s (continued)", heading);
(*y)++;
if (*y >= (h-3)) {
centre(mainwin, h-2, MORESTRING);
@ -4331,6 +4455,7 @@ int downline(int *y, int h, char *heading, char *subheading, char *bottomstring,
cls(); *y = 0;
centre(mainwin, *y, headbuf);
*y += 2;
wmove(mainwin, *y, 0);
if (subheading) {
@ -4478,7 +4603,8 @@ void doheading(WINDOW *win, int *y, int x, char *what) {
char *buf;
len = strlen(what) + 1;
buf = malloc(len * sizeof(char));
memset(buf, '-', (size_t)len);
memset(buf, '-', (size_t)(len-1));
buf[len] = '\0';
mvwprintw(win, *y, x, what); (*y)++;
mvwprintw(win, *y, x, buf); (*y)++;
free(buf);
@ -4552,6 +4678,9 @@ int drop(object_t *o, int count) {
op = o->pile;
assert(op->owner);
// in case we get burduned
if (isplayer(op->owner)) statdirty = B_TRUE;
getobname(o, obname, count);
origid = o->type->id;
@ -5491,12 +5620,12 @@ void drawstatus(void) {
player->level);
mvwprintw(statwin, 0, 0, buf);
if ((player->skillpoints == 0) && (getattpoints(player) == 0)) {
wprintw(statwin, " Next:%ld",xpleft);
} else {
if (lfhasflag(player, F_HASNEWLEVEL)) {
setcol(statwin, C_BOLDGREEN);
wprintw(statwin, " LevUp",xpleft);
unsetcol(statwin, C_BOLDGREEN);
} else {
wprintw(statwin, " Next:%ld",xpleft);
}
// blinded?
if (isblind(player)) {
@ -5581,10 +5710,24 @@ void drawstatus(void) {
break;
}
// show certain flags
if (lfhasflag(player, F_POISONED)) {
f = isdrunk(player);
if (f) {
char dstring[BUFLEN];
strcpy(dstring, getdrunktext(f));
capitalise(dstring);
setcol(statwin, C_BROWN);
//wprintw(statwin, " %s(%d)", dstring,f->lifetime);
wprintw(statwin, " %s", dstring);
unsetcol(statwin, C_BROWN);
}
f = ispoisoned(player);
if (f) {
// find highest amount of poison
if (getskill(player, SK_FIRSTAID) >= PR_ADEPT) {
if (poisonthreatenslife(player)) {
if (poisonthreatenslife(player, f)) {
setcol(statwin, C_GREEN);
wprintw(statwin, " Poison(bad)");
unsetcol(statwin, C_GREEN);
@ -5622,6 +5765,18 @@ void drawstatus(void) {
unsetcol(statwin, C_BROWN);
}
// good effects
f = lfhasflag(player, F_HIDING);
if (f) {
setcol(statwin, C_BLUE);
if (f->val[0] < 0) {
wprintw(statwin, " Hiding--");
} else {
wprintw(statwin, " Hiding");
}
unsetcol(statwin, C_BLUE);
}
// construct waiting string
strcpy(waitbuf, "");
/*
@ -5644,6 +5799,7 @@ void drawstatus(void) {
wprintw(statwin, " (%s)",waitbuf);
}
// SECOND LINE
for (a = 0; a < MAXATTS; a++) {
@ -5946,7 +6102,7 @@ void showlfstats(lifeform_t *lf, int showall) {
if (showall) {
sprintf(prompt, "[@=stats S=skills/abilities M=magic E=effects %sESC=quit]", isplayer(lf) ? "" : "I=items " );
sprintf(cmdchars, "@ase%s",isplayer(lf) ? "" : "i");
sprintf(cmdchars, "@asme%s",isplayer(lf) ? "" : "i");
} else {
sprintf(prompt, "%s", "[ESC=quit]");
sprintf(cmdchars, "%s", "@");
@ -6380,6 +6536,11 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, buf);
y++;
}
f = lfhasknownflag(lf, F_HIDING);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s hiding.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasknownflag(lf, F_INVISIBLE);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s invisible.", you(lf), isplayer(lf) ? "are" : "is");
@ -6649,22 +6810,42 @@ void showlfstats(lifeform_t *lf, int showall) {
y++;
if (!exitnow) {
if (hasflag(lf->flags, F_HASSKILL)) {
centre(mainwin, y, "SKILLS"); y += 2;
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_HASSKILL) {
mvwprintw(mainwin, y, 0, "%c %s (%s%s)",
ismaxedskill(lf, f->val[0]) ? '*' : '-',
getskillname(f->val[0]),
getskilllevelname(f->val[1]),
ismaxedskill(lf, f->val[0]) ? "/MAX" : "");
if (downline(&y, h, "SKILLS", NULL, prompt, cmdchars, &ch)) {
exitnow = B_TRUE;
break;
}
char skilltitle[BUFLEN];
flag_t *known[MAXSKILLS], *available[MAXSKILLS];
int numknown = 0, numavailable = 0;
int n;
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_HASSKILL) {
known[numknown++] = f;
} else if (f->id == F_CANLEARN) {
if (!getskill(lf, f->val[0])) {
available[numavailable++] = f;
}
}
}
//centre(mainwin, y, "SKILLS"); y ++;
sprintf(skilltitle, "%-40s%-40s","AVAILABLE SKILLS", "KNOWN SKILLS");
doheading(mainwin, &y, 0, skilltitle);
for (n = 0; n < MAXOF(numknown,numavailable); n++) {
if (n < numavailable) {
mvwprintw(mainwin, y, 0, "- %s",
getskillname(available[n]->val[0]) );
}
if (n < numknown) {
mvwprintw(mainwin, y, 40, "%c %s (%s%s)",
ismaxedskill(lf, known[n]->val[0]) ? '*' : '-',
getskillname(known[n]->val[0]),
getskilllevelname(known[n]->val[1]),
ismaxedskill(lf, known[n]->val[0]) ? "/MAX" : "");
}
if (downline(&y, h, "SKILLS", skilltitle, prompt, cmdchars, &ch)) {
exitnow = B_TRUE;
break;
}
}
}
} else if (mode == 'm') {
char subheading[BUFLEN];
@ -6672,9 +6853,9 @@ void showlfstats(lifeform_t *lf, int showall) {
int anyfound;
int exitnow = B_FALSE;
sprintf(subheading, " %-4s%-25s%-22s%s","Lv","Spell", "School", "Cost");
sprintf(subheading, " %-4s%-26s%-15s%-13s%s","Lv","Spell", "School", "Power", "Cost");
centre(mainwin, y, "SPELLS"); y += 2;
centre(mainwin, y, "MAGIC"); y += 2;
doheading(mainwin, &y, 0, subheading);
//if (!isplayer(lf)) {
// show spells monster can cast using mp
@ -6691,8 +6872,23 @@ void showlfstats(lifeform_t *lf, int showall) {
if (f && (f->known)) {
char spellname[BUFLEN];
char mpbuf[BUFLEN];
char powerbuf[BUFLEN];
int power;
int mpcost;
// power
power = getspellpower(lf, ot->id);
sprintf(powerbuf, "[");
for (i = 0; i < power; i++) {
strcat(powerbuf, "#");
}
for (i = 0; i < (getspellmaxpower(ot->id) - power); i++) {
strcat(powerbuf, "-");
}
strcat(powerbuf, "]");
// mp cost
if (f->id == F_CANWILL) {
mpcost = 0;
@ -6703,26 +6899,20 @@ void showlfstats(lifeform_t *lf, int showall) {
(f->val[2] == 1) ? "" : "s");
}
} else {
mpcost = getmpcost(lf, ot->id);
if (mpcost) {
if (hasflag(ot->flags, F_ONGOING)) {
sprintf(mpbuf, "%d MP ongoing", mpcost);
} else {
sprintf(mpbuf, "%d MP", mpcost);
}
getspellcosttext(lf, ot->id, power, mpbuf);
} else {
sprintf(mpbuf, "At will");
}
}
power = getspellpower(lf, ot->id);
getspellname(ot->id, lf, spellname);
sprintf(buf, " %-4d%-25s%-22s%s",thislev, spellname, getschoolname(getspellschool(ot->id)), mpbuf);
sprintf(buf, " %-4d%-26s%-15s%-13s%s",thislev, spellname, getschoolnameshort(getspellschool(ot->id)), powerbuf, mpbuf);
mvwprintw(mainwin, y, 0, "%s\n", buf);
anyfound = B_TRUE;
if (downline(&y, h, "SPELLS", subheading, prompt, cmdchars, &ch)) {
if (downline(&y, h, "MAGIC", subheading, prompt, cmdchars, &ch)) {
exitnow = B_TRUE;
break;
}
@ -6743,15 +6933,15 @@ void showlfstats(lifeform_t *lf, int showall) {
// ready to gain a level?
if (lfhasflag(lf, F_STATGAINREADY)) {
mvwprintw(mainwin, y, 0, "%s are ready for training.", you(lf));
mvwprintw(mainwin, y, 0, "%s are ready to train your attributes.", you(lf));
y++;
}
if (lf->skillpoints >= 2) {
if (lf->skillpoints) {
mvwprintw(mainwin, y, 0, "%s are ready to learn a new skill.", you(lf));
y++;
} else if (lf->skillpoints) {
mvwprintw(mainwin, y, 0, "%s are ready to enhance %s existing skills.", you(lf),
isplayer(lf) ? "your" : "its");
}
if (levelabilityready(lf)) {
mvwprintw(mainwin, y, 0, "%s are ready to learn a new job-based ability.", you(lf));
y++;
}
@ -6768,6 +6958,13 @@ void showlfstats(lifeform_t *lf, int showall) {
}
// show racial effects
if (hasjob(lf, J_PIRATE)) {
mvwprintw(mainwin, y, 0, "%s can hold %s liquor well.", you(lf), isplayer(lf) ? "your" : "its");
y++;
mvwprintw(mainwin, y, 0, "%s %s missing one eye.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
// show intrinsics
f = lfhasknownflag(lf, F_ATTRSET);
@ -6853,7 +7050,18 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, "%s automatically detect nearby objects.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_ENHANCESEARCH);
if (f) {
mvwprintw(mainwin, y, 0, "%s searching ability is enhanced.", you(lf), isplayer(lf) ? "Your" : "Its");
y++;
}
f = lfhasknownflag(lf, F_DRUNK);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s %s.", you(lf),
isplayer(lf) ? "are" : "is", getdrunktext(f));
y++;
}
// extra dam - can have it multiple times
for (f = lf->flags->first ; f; f = f->next) {
@ -6913,27 +7121,30 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, "%s receive enhanced knowledge about the world.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_POISONED);
if (f && (f->known)) {
int knownfatal = B_FALSE;
for (f = lf->flags->first ; f ; f = f->next ){
if (f->known && (f->id == F_POISONED)) {
int knownfatal = B_FALSE;
if (getskill(player, SK_FIRSTAID) >= PR_ADEPT) {
if (poisonthreatenslife(lf)) {
knownfatal = B_TRUE;
if (getskill(player, SK_FIRSTAID) >= PR_ADEPT) {
if (poisonthreatenslife(lf, f)) {
knownfatal = B_TRUE;
}
}
}
sprintf(buf, "%s %s poisoned%s.", you(lf), isplayer(lf) ? "are" : "is",
knownfatal ? ", potentially fatally" : "");
if (lfhasflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT) ||
(getskill(player, SK_FIRSTAID) >= PR_ADEPT) ) {
char buf2[BUFLEN];
sprintf(buf2, " [max %d turns left]", f->lifetime);
strcat(buf, buf2);
sprintf(buf, "%s %s sick with %s%s.", you(lf), isplayer(lf) ? "are" : "is",
getpoisonname(f->val[0]),
knownfatal ? ", potentially fatally" : "");
if (lfhasflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT) ||
(getskill(player, SK_FIRSTAID) >= PR_ADEPT) ) {
char buf2[BUFLEN];
sprintf(buf2, " [max %d turns left]", f->lifetime);
strcat(buf, buf2);
}
mvwprintw(mainwin, y, 0, buf);
y++;
}
mvwprintw(mainwin, y, 0, buf);
y++;
}
f = lfhasflag(lf, F_NAUSEATED);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s nauseated.", you(lf), isplayer(lf) ? "are" : "is");
@ -6999,7 +7210,11 @@ void showlfstats(lifeform_t *lf, int showall) {
f = lfhasflag(lf, F_PAIN);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s in extreme pain, and movement will cause %s damage.", you(lf), isplayer(lf) ? "are" : "is", isplayer(lf) ? "you" : "it");
if (isdrunk(lf)) {
mvwprintw(mainwin, y, 0, "%s %s in extreme pain, somewhat mitigated by %s inebriation.", you(lf), isplayer(lf) ? "are" : "is", isplayer(lf) ? "your" : "its");
} else {
mvwprintw(mainwin, y, 0, "%s %s in extreme pain, and movement will cause %s damage.", you(lf), isplayer(lf) ? "are" : "is", isplayer(lf) ? "you" : "it");
}
y++;
}
@ -7047,6 +7262,11 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, "%s %s %s resistant to magic.", you(lf), isplayer(lf) ? "are" : "is", adjective);
y++;
}
f = lfhasknownflag(lf, F_TREMORSENSE);
if (f) {
mvwprintw(mainwin, y, 0, "%s can 'see' by sensing vibrations around you.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_WINDSHIELD);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s protected from missiles by a cyclonic shield", you(lf), isplayer(lf) ? "are" : "is");
@ -7105,8 +7325,16 @@ void showlfstats(lifeform_t *lf, int showall) {
cls();
centre(mainwin, 0, "INVENTORY");
y = 2;
if (countobs(lf->pack)) {
mvwprintw(mainwin, y, 0, "It is carrying:");
if (lfhasflag(lf, F_NOPACK)) {
mvwprintw(mainwin, y, 0, "It cannot carry anything.");
} else if (countobs(lf->pack)) {
char invtitle[BUFLEN];
float packweight,maxweight,pct;
packweight = getobpileweight(lf->pack);
maxweight = getmaxcarryweight(lf);
pct = (packweight / maxweight) * 100;
sprintf(invtitle, "It is carrying: (%0.0f/%0.0f kg, %0.0f%%)", packweight, maxweight, pct);
mvwprintw(mainwin, y, 0, "%s", invtitle);
y += 2;
for (o = lf->pack->first ; o ; o = o->next) {
getobname(o, buf,o->amt);
@ -7148,7 +7376,14 @@ void showlfstats(lifeform_t *lf, int showall) {
}
} // end while !done
statdirty = B_TRUE;
needredraw = B_TRUE;
cls(); wrefresh(mainwin);
drawscreen();
wrefresh(gamewin);
wrefresh(statwin);
real_clearmsg(B_TRUE);
//redraw();
}

2
io.h
View File

@ -80,7 +80,7 @@ void initgfx(void);
void initprompt(prompt_t *p, char *q1);
int keycodetokey(int keycode);
void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int firstob, int *counter, int lastline, int *y, char *myletters);
void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2);
void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, enum SPELLSCHOOL wantschool, int wantunknown);
void more(void);
void warn(char *format, ... );
void msg(char *format, ... );

1046
lf.c

File diff suppressed because it is too large Load Diff

19
lf.h
View File

@ -24,7 +24,6 @@ int canpickup(lifeform_t *lf, object_t *o, int amt);
int canpolymorphto(enum RACE rid);
int canpush(lifeform_t *lf, object_t *o, int dir);
int canquaff(lifeform_t *lf, object_t *o);
int canrest(lifeform_t *lf);
int cansee(lifeform_t *viewer, lifeform_t *viewee);
int canwear(lifeform_t *lf, object_t *o, enum BODYPART where);
int canweild(lifeform_t *lf, object_t *o);
@ -32,6 +31,7 @@ int cantakeoff(lifeform_t *lf, object_t *o);
int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell);
void checkxp(enum RACE rid);
int countmoney(lifeform_t *lf);
int countnearbyallies(lifeform_t *lf);
void debug(lifeform_t *lf);
void die(lifeform_t *lf);
void dumplf(void);
@ -64,6 +64,7 @@ int getarmourrating(lifeform_t *lf);
int getattackspeed(lifeform_t *lf);
int getattpoints(lifeform_t *lf);
int getattr(lifeform_t *lf, enum ATTRIB attr);
int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset);
int getevasion(lifeform_t *lf);
object_t *getbestthrowmissile(lifeform_t *lf);
object_t *getbestweapon(lifeform_t *lf);
@ -109,6 +110,9 @@ float getlfweight(lifeform_t *lf, int withobs);
int getspellspeed(lifeform_t *lf);
char *getplayername(char *buf);
char *getplayernamefull(char *buf);
int getpoisondamchance(enum POISONTYPE ptype);
char *getpoisondamverb(enum POISONTYPE ptype);
char *getpoisonname(enum POISONTYPE ptype);
int getracerarity(enum RACE rid);
object_t *getrandomarmour(lifeform_t *lf);
//int getrandommonlevel(int depth);
@ -157,6 +161,7 @@ int isblind(lifeform_t *lf);
enum BURDENED isburdened(lifeform_t *lf);
int ischarmable(lifeform_t *lf);
int isdead(lifeform_t *lf);
flag_t *isdrunk(lifeform_t *lf);
int isfleeing(lifeform_t *lf);
int isfreebp(lifeform_t *lf, enum BODYPART bp);
int isfriendly(lifeform_t *lf);
@ -166,13 +171,16 @@ flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt);
int isingunrange(lifeform_t *lf, cell_t *where);
int ismaxedskill(lifeform_t *lf, enum SKILL skid);
int ispeaceful(lifeform_t *lf);
int ispetof(lifeform_t *lf, lifeform_t *owner);
int isplayer(lifeform_t *lf);
flag_t *ispoisoned(lifeform_t *lf);
int ispolymorphed(lifeform_t *lf);
flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt);
flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt);
void killjob(job_t *job);
void killlf(lifeform_t *lf);
void killrace(race_t *race);
flag_t *levelabilityready(lifeform_t *lf);
void loseconcentration(lifeform_t *lf);
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc);
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam);
@ -185,14 +193,17 @@ void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how);
int modattr(lifeform_t *lf, enum ATTRIB attr, int amt);
void modhunger(lifeform_t *lf, int amt);
float modifybystat(float num, lifeform_t *lf, enum ATTRIB att);
int needstorest(lifeform_t *lf, char *validchars);
void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext);
void outfitlf(lifeform_t *lf);
int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground);
void poison(lifeform_t *lf, int howlong, char *fromwhat);
int poisonthreatenslife(lifeform_t *lf);
void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat);
int poisonthreatenslife(lifeform_t *lf, flag_t *f);
void practice(lifeform_t *lf, enum SKILL skid);
void precalclos(lifeform_t *lf);
int push(lifeform_t *lf, object_t *o, int dir);
int readytotrain(lifeform_t *lf);
void refreshlevelabilities(lifeform_t *lf);
void relinklf(lifeform_t *src, map_t *dst);
int rest(lifeform_t *lf, int onpurpose);
void startresting(lifeform_t *lf, int willtrain);
@ -201,6 +212,7 @@ int rolldex(enum DEXBRACKET bracket);
int rolliq(enum IQBRACKET bracket);
int rollstr(enum STRBRACKET bracket);
int rollstat(lifeform_t *lf, enum ATTRIB attr);
int safetorest(lifeform_t *lf);
int scare(lifeform_t *lf, lifeform_t *scarer, int howlong);
int setammo(lifeform_t *lf, object_t *o);
void setattr(lifeform_t *lf, enum ATTRIB attr, int val);
@ -224,6 +236,7 @@ int throwat(lifeform_t *thrower, object_t *o, cell_t *where);
void timeeffectslf(lifeform_t *lf);
void turneffectslf(lifeform_t *lf);
int touch(lifeform_t *lf, object_t *o);
void unpoison(lifeform_t *lf);
int unweild(lifeform_t *lf, object_t *o);
int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where);
int useringofmiracles(lifeform_t *lf, int charges);

4081
log.txt

File diff suppressed because it is too large Load Diff

95
map.c
View File

@ -14,6 +14,7 @@
#include "text.h"
extern map_t *firstmap,*lastmap;
extern celltype_t *firstcelltype, *lastcelltype;
extern int viewx,viewy,vieww,viewh;
extern lifeform_t *player;
@ -408,7 +409,12 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) {
// draw highest object in sort order
o = gettopobject(c);
if (o) {
if (hasobwithflag(c->obpile, F_SECRETDOOR)) {
celltype_t *ct;
ct = findcelltype(getwallcelltype(c->map->habitat));
*g = ct->glyph;
} else if (o) {
// return the object's glyph
*g = *(getglyph(o));
} else {
// should never happen. if it does, just show the
@ -468,10 +474,31 @@ enum CELLTYPE getemptycelltype(enum HABITAT hab) {
return CT_CORRIDOR;
}
enum CELLTYPE getwallcelltype(enum HABITAT hab) {
switch (hab) {
case H_DUNGEON:
return CT_WALL;
default:
break;
}
return CT_WALL;
}
object_t *gettopobject(cell_t *where) {
object_t *o;
int c;
// draw highest object in sort order
// draw impassable objects first...
o = hasobwithflag(where->obpile, F_IMPASSABLE);
if (o) {
// ignore secret doors
if (issecretdoor(o)) {
return NULL;
} else {
return o;
}
}
// otherwise draw highest object in sort order
c = 0;
while (sortorder[c] != OC_NULL) {
// check each object against this ob class
@ -479,7 +506,11 @@ object_t *gettopobject(cell_t *where) {
// appear first.
for (o = where->obpile->last ; o ; o = o->prev) {
if (o->type->obclass->id == sortorder[c]) {
return o;
if (issecretdoor(o)) {
return NULL;
} else {
return o;
}
}
}
c++;
@ -1584,10 +1615,16 @@ printf("dump of map '%s' (%d x %d):\n",map->name, map->w, map->h);
}
}
void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int wantannounce) {
// dirtype of DT_COMPASS will give a square explosion
// dirtype of DT_COMPASS will give a circular explosion
void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int dirtype, int wantannounce) {
int x,y;
animradial(c, range, '}', C_RED);
if (dirtype == DT_COMPASS) {
animradial(c, range, '}', C_RED);
} else { // ie. DT_ORTH
animradialorth(c, range, '}', C_RED);
}
if (haslos(player, c)) {
if (wantannounce) {
@ -1599,10 +1636,18 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int
for (y = c->y - range ; y <= c->y + range ; y++) {
for (x = c->x - range ; x <= c->x + range ; x++) {
int inrange = B_FALSE;
cell_t *cc;
cc = getcellat(c->map, x,y);
if (cc && (getcelldist(c, cc) <= range)) {
explodesinglecell(cc, dam, killwalls, o, c);
if (cc) {
if ((dirtype == DT_COMPASS) && (getcelldist(c,cc) <= range)) {
inrange = B_TRUE;
} else if ((dirtype == DT_ORTH) && (getcelldistorth(c,cc) <= range)) {
inrange = B_TRUE;
}
if (inrange && haslof(c, cc, LOF_WALLSTOP, NULL)) {
explodesinglecell(cc, dam, killwalls, o, c);
}
}
}
}
@ -1654,6 +1699,14 @@ void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *c
}
}
celltype_t *findcelltype(enum CELLTYPE cid) {
celltype_t *ct;
for (ct = firstcelltype ; ct ; ct = ct->next) {
if (ct->id == cid) return ct;
}
return NULL;
}
map_t *findmap(int mid) {
map_t *m;
for (m = firstmap ; m ; m = m->next) {
@ -2011,6 +2064,20 @@ cell_t *getrandomroomcell(map_t *map, int roomid) {
return c;
}
// popuplates retcell[] with all cells from room
void getroomcells(map_t *m, int roomid, cell_t **retcell, int *ncells) {
int i;
cell_t *c;
*ncells = 0;
for (i = 0; i < m->w*m->h; i++) {
c = m->cell[i];
if (c && (c->roomid == roomid)) {
retcell[*ncells] = c;
(*ncells)++;
}
}
}
// returns how slippery this cell is
int getslipperyness(cell_t *c, object_t **slipob) {
object_t *o;
@ -2383,17 +2450,27 @@ void makedoor(cell_t *cell) {
} else {
int chance;
// door is closed - lock it?
chance = rolldie(1,6); // ie. 1 in 6
// ie. at dungeon lev 10, chance is 2 in 6
// at dungeon lev 20, chance is 3 in 6
// ...
// at dungeon lev 50, chance is 5 in 6
chance -= (m->depth / 10);
chance = rolldie(1,6) - (m->depth / 10);
if (chance <= 1) {
addflag(o->flags, F_LOCKED, B_TRUE, NA, NA, NULL);
}
// make it secret?
chance = rolldie(1,6) - (m->depth / 10);
// difficulty:
// l1 = 20
// l10 = 25
// l20 = 30
if (chance <= 1) {
addflag(o->flags, F_SECRETDOOR, 20 + (m->depth / 2), NA, NA, NULL);
}
}
}

5
map.h
View File

@ -11,6 +11,7 @@ int getcelldist(cell_t *src, cell_t *dst);
int getcelldistorth(cell_t *src, cell_t *dst);
void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer);
enum CELLTYPE getemptycelltype(enum HABITAT hab);
enum CELLTYPE getwallcelltype(enum HABITAT hab);
object_t *gettopobject(cell_t *where);
void calclight(map_t *map);
int calcroompos(map_t *map, int w, int h, int *bx, int *by);
@ -23,7 +24,8 @@ int dirtox(int dt, int dir);
int dirtoy(int dt, int dir);
void dumpmap(map_t *map);
void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *centre);
void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int wantannounce);
void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int dirtype, int wantannounce);
celltype_t *findcelltype(enum CELLTYPE cid);
map_t *findmap(int mid);
map_t *findmapofdepth(int depth);
object_t *findobidinmap(map_t *m, long id);
@ -37,6 +39,7 @@ cell_t *getrandomcell(map_t *map);
cell_t *getrandomcelloftype(map_t *map, int id);
int getrandomdir(int dirtype);
cell_t *getrandomroomcell(map_t *map, int roomid);
void getroomcells(map_t *m, int roomid, cell_t **retcell, int *ncells);
int getslipperyness(cell_t *c, object_t **slipob);
cell_t *getstairdestination(object_t *o);
object_t *hasenterableobject(cell_t *c);

101
move.c
View File

@ -121,13 +121,15 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err
for (o = cell->obpile->first ; o ; o = o->next) {
f = hasflag(o->flags, F_WALKDAM);
if (f) {
// are we immune to this?
if (!lfhasflagval(lf, F_DTIMMUNE, f->val[0], NA, NA, NULL)) {
if (error) {
*error = E_AVOIDOB;
rdata = o;
if ((f->val[0] != DT_WATER) || isvulnto(lf->flags, DT_WATER)) {
// are we immune to this?
if (!lfhasflagval(lf, F_DTIMMUNE, f->val[0], NA, NA, NULL)) {
if (error) {
*error = E_AVOIDOB;
rdata = o;
}
return B_TRUE;
}
return B_TRUE;
}
}
}
@ -203,7 +205,11 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
rdata = o;
if (error) {
if (isdoor(o, NULL)) {
*error = E_DOORINWAY;
if (hasflag(o->flags, F_SECRETDOOR)) {
*error = E_WALLINWAY;
} else {
*error = E_DOORINWAY;
}
} else {
*error = E_OBINWAY;
}
@ -555,14 +561,16 @@ void moveeffects(lifeform_t *lf) {
f = lfhasflag(lf, F_PAIN);
if (f) {
if (isplayer(lf)) {
msg("Your body is wracked with pain!");
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s convulses in pain!",lfname);
if (!isdrunk(lf)) {
if (isplayer(lf)) {
msg("Your body is wracked with pain!");
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s convulses in pain!",lfname);
}
losehp(lf, roll(f->text), f->val[0], NULL, "extreme pain");
}
losehp(lf, roll(f->text), f->val[0], NULL, "extreme pain");
}
if (isdead(lf)) return;
@ -577,6 +585,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
int didmsg = B_FALSE;
flag_t *f;
int changedlev = B_FALSE;
int preroom = -1, postroom = -1;
getlfname(lf, lfname);
@ -584,8 +593,9 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
changedlev = B_TRUE;
}
// update current cell
// update current cell + room id
lf->cell->lf = NULL;
preroom = lf->cell->roomid;
// if required, relink lifeform to new map
if (newcell->map != lf->cell->map) {
@ -601,6 +611,9 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
// nothing should be in new cell..
assert(!newcell->lf);
// remember new room...
postroom = lf->cell->roomid;
// update new cell
newcell->lf = lf;
@ -611,6 +624,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
moveeffects(lf);
killflagsofid(lf->flags, F_HIDING);
// remove grabs
f = lfhasflag(lf, F_GRABBING);
if (f) {
@ -686,6 +701,37 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
// (but without a map you will then slowly forget it)
if (isplayer(lf)) {
updateknowncells();
// TODO: not sure about this next bit yet...
// it definitely won't work for non-square rooms
// or rooms with pillars. would be better to fix
// haslos() code to handle looking along walls
// instead.
// if you walked into a new fully lit room, reveal it
if ((postroom > 0) && (postroom != preroom)) {
cell_t *c[MAXRETCELLS];
int ncells;
int i,alllit = B_TRUE,allknown = B_TRUE;
// is the whole room lit?
getroomcells(lf->cell->map, postroom, c, &ncells);
for (i = 0; i < ncells; i++) {
if (!islit(c[i])) {
alllit = B_FALSE;
}
if (!c[i]->known) {
allknown = B_FALSE;
}
}
if (alllit && !allknown) {
// make the all known
for (i = 0; i < ncells; i++) {
c[i]->known = B_TRUE;
}
}
}
}
// does anyone else see you?
@ -707,7 +753,6 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
}
} else {
if (isplayer(lf) && areallies(lf, l)) {
// remember player's last known loc
f = lfhasflag(l, F_PETOF);
if (f) {
@ -715,7 +760,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
f->val[2] = player->cell->y;
}
}
dointerrupt = B_TRUE;
//dointerrupt = B_TRUE;
}
if (dointerrupt) {
interrupt(l);
@ -752,6 +797,9 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose) {
}
}
if (lfhasflag(lf, F_HIDING)) {
dontclearmsg = B_TRUE;
}
// actually do the move
didmsg = movelf(lf, newcell);
@ -1178,6 +1226,17 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
cell_t *cell;
enum ERROR errcode;
char buf[BUFLEN];
flag_t *f;
f = isdrunk(lf);
if (f) {
if (!hasjob(lf, J_PIRATE)) {
if (rnd(1,6) <= ((f->lifetime/DRUNKTIME)+1)) {
// randomize move
dir = rnd(DC_N, DC_NW);
}
}
}
cell = getcellindir(lf->cell, dir);
if (canandwillmove(lf, dir, &errcode)) {
@ -1273,7 +1332,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
if (!haslos(lf, cell)) {
if (isplayer(lf)) {
// only take damage if we didn't know about this
if (!cell->known) {
if (!cell->known || isdrunk(lf)) {
sprintf(buf, "%sing into a wall", getmoveverb(lf));
losehp(lf, 1, DT_BASH, NULL, buf);
// we now know there is a wall there.
@ -1441,15 +1500,21 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
enum IQBRACKET iq;
object_t *o;
char buf[BUFLEN];
//object_t *o;
iq = getiqname(getattr(lf, A_IQ), NULL);
// default
if (error) {
*error = E_OK;
rdata = NULL;
}
if (isdrunk(lf)) {
return B_TRUE;
}
cell = getcellindir(lf->cell, dir);
if (celldangerous(lf, cell, B_TRUE, error)) {
if (error) *error = E_WONT;

31
nexus.c
View File

@ -128,6 +128,7 @@ int main(int argc, char **argv) {
job_t *j = NULL;
char ch;
cell_t *where;
int dir;
flag_t *f;
// read from input file if required
@ -196,6 +197,15 @@ int main(int argc, char **argv) {
// player needs hunger
addflag(player->flags, F_HUNGER, 0, NA, NA, NULL);
// kill any other lifeforms around the caster, to make room for pets.
for (dir = DC_N; dir <= DC_NW; dir++) {
cell_t *c;
c = getcellindir(player->cell, dir);
if (c && c->lf) {
killlf(c->lf);
}
}
// pet / npc / follower
f = lfhasflag(player, F_HASPET);
if (f) {
@ -211,11 +221,7 @@ int main(int argc, char **argv) {
pet = addlf(c, r->id, 1);
makefriendly(pet, PERMENANT);
// mark us as its master
if (lfhasflag(pet, F_ANIMAL) || lfhasflag(pet, F_INSECT)) {
addflag(pet->flags, F_PETOF, player->id, player->cell->x, player->cell->y, NULL);
} else {
addflag(pet->flags, F_ALLYOF, player->id, player->cell->x, player->cell->y, NULL);
}
addflag(pet->flags, F_PETOF, player->id, player->cell->x, player->cell->y, NULL);
}
getplayernamefull(pname);
@ -486,7 +492,7 @@ void donextturn(map_t *map) {
handleinput();
} else {
// do ai move
aimove(who);
aiturn(who);
}
}
}
@ -515,17 +521,6 @@ void donextturn(map_t *map) {
}
celltype_t *findcelltype(int id) {
celltype_t *ct;
for (ct = firstcelltype; ct ; ct = ct->next) {
if (ct->id == id) {
return ct;
}
}
return NULL;
}
char *getdirname(int dir) {
switch (dir) {
case D_N:
@ -590,7 +585,7 @@ void getrarity(int depth, int *min, int *max, int range) {
//*max = mid + range; if (*max > 100) *max = 100;
*max = 100;
if (*min > 85) *min = 85;
//if (*min > 85) *min = 85;
if (*max < 25) *max = 25;
}

View File

@ -7,7 +7,6 @@ void checkendgame(void);
void cleanup(void);
void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, int dinc2, int *xinc, int *yinc, int *dinc);
void donextturn(map_t *map);
celltype_t *findcelltype(int id);
char *getdirname(int dir);
enum COLOUR getpctcol(float num, float max);
void getrarity(int depth, int *min, int *max, int range);

435
objects.c
View File

@ -170,6 +170,8 @@ hiddennamewithcol_t colour[] = {
hiddennamewithcol_t gemtype[] = {
{ "agate", C_MAGENTA, },
{ "amethyst", C_MAGENTA, }, // should be purple
{ "brass",C_BROWN },
{ "bronze",C_BROWN },
{ "copper",C_BROWN },
{ "diamond",C_BOLDCYAN },
@ -177,6 +179,7 @@ hiddennamewithcol_t gemtype[] = {
{ "flourite",C_GREY },
{ "garnet",C_ORANGE },
{ "gold",C_YELLOW },
{ "iridium",C_WHITE },
{ "jade",C_GREEN },
{ "lapis lazuli",C_BOLDBLUE },
{ "malachite",C_BOLDCYAN },
@ -185,7 +188,8 @@ hiddennamewithcol_t gemtype[] = {
{ "pearl",C_WHITE },
{ "quartz",C_GREY },
{ "ruby",C_RED },
{ "sapphire",C_CYAN },
{ "sapphire",C_BLUE },
{ "zinc",C_GREY },
{ "",C_GREY },
};
@ -1123,6 +1127,33 @@ obpile_t *addobpile(lifeform_t *owner, cell_t *where) {
}
void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes) {
int x,y;
objecttype_t *ot;
ot = findotn(name);
if (!ot) return;
for (y = centre->y - radius ; y <= centre->y + radius; y++) {
for (x = centre->x - radius ; x <= centre->x + radius; x++) {
int valid = B_FALSE;
cell_t *c;
c = getcellat(centre->map, x, y);
if (c && !c->type->solid && haslof(centre, c, LOF_WALLSTOP, NULL)) {
if (allowdupes || !hasob(c->obpile, ot->id)) {
if ((dirtype == DT_COMPASS) && (getcelldist(centre, c) <= radius)) {
valid = B_TRUE;
} else if ((dirtype == DT_ORTH) && (getcelldistorth(centre, c) <= radius)) {
valid = B_TRUE;
}
}
}
if (valid) {
addob(c->obpile, name);
}
}
}
}
objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid) {
objecttype_t *a, *ot;
//flag_t *f;
@ -1459,7 +1490,7 @@ void applyobmod(object_t *o, obmod_t *om) {
}
// ...but they do melt!
addflag(o->flags, F_OBHPDRAIN, 1, DT_MELT, NA, NULL);
f = addtempflag(o->flags, F_OBHPDRAIN, 1, DT_MELT, NA, NULL, FROMOBMOD);
// it needs HP to melt
if (!hasflag(o->flags, F_OBHP)) {
@ -1468,14 +1499,10 @@ void applyobmod(object_t *o, obmod_t *om) {
myhp = getobweight(o) * 20;
if (myhp <= 0) myhp = 2;
// TODO: not sure about using FROMMAT here...
// but i wnat restoration to still work.
addtempflag(o->flags, F_OBHP, myhp, myhp, NA, NULL, FROMMAT);
addtempflag(o->flags, F_OBHP, myhp, myhp, NA, NULL, FROMOBMOD);
}
if (!hasflag(o->flags, F_DAMAGABLE)) {
// TODO: not sure about using FROMMAT here...
// but i wnat restoration to still work.
addtempflag(o->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL, FROMMAT);
addtempflag(o->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL, FROMOBMOD);
}
}
copyflags(o->flags, om->flags, FROMOBMOD);
@ -1534,6 +1561,7 @@ void brightflash(cell_t *centre, int range, lifeform_t *immunelf) {
// announce
if (haslos(player, centre) && !isblind(player)) {
msg("You see an intense flash of light!");
more();
}
/*
if (getcelldist(player->cell, centre) <= range) {
@ -1690,13 +1718,10 @@ int changemat(object_t *o, enum MATERIAL mat) {
// it stops burning
extinguish(o);
// it will melt...
// note that it is frozen
om = findobmod(OM_FROZEN);
applyobmod(o, om);
// make it melt
//addtempflag(o->flags, F_OBHPDRAIN, 1, DT_MELT, NA, NULL, FROMMAT);
}
return B_FALSE;
}
@ -1873,7 +1898,7 @@ void explodeob(object_t *o, flag_t *f, int bigness) {
int dam;
char obname[BUFLEN];
dam = f->val[0];
dam = roll(f->text);
c = getoblocation(o);
getobname(o, obname, o->amt);
@ -1889,7 +1914,7 @@ void explodeob(object_t *o, flag_t *f, int bigness) {
} else if (haslos(player, c)) {
msg("%s explode%s!", obname, (o->amt == 1) ? "s" : "");
}
explodecells(c, dam * o->amt, bigness ? B_TRUE : B_FALSE, o, bigness ? 1 : 0, B_FALSE);
explodecells(c, dam * o->amt, bigness ? B_TRUE : B_FALSE, o, bigness ? 1 : 0, DT_COMPASS, B_FALSE);
// hurt everything!
/*
@ -3211,6 +3236,10 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
}
}
if (issecretdoor(o)) {
strcat(buf, "secret ");
}
// object name
strcat(buf, pluralname);
free(pluralname);
@ -3443,6 +3472,9 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth
int raritymin,raritymax;
int depth;
int done = B_FALSE;
obmod_t *om;
flag_t *omposs[MAXCANDIDATES];
int noms = 0;
if (forcedepth != NA) {
@ -3593,29 +3625,24 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth
strcat(cursestr, buf2);
}
// weapons/armour have random chance of various obmods
if ((ot->obclass->id == OC_WEAPON) ||
(ot->obclass->id == OC_ARMOUR)) {
obmod_t *om;
// random chance of having an obmod
for (om = firstobmod ; om ; om = om->next) {
if (!hasflag(ot->flags, F_NOQUALITY)) {
// 1 in 6 of masterwork
if (rnd(1,6) == 1) {
om = findobmod(OM_MASTERWORK);
strcat(cursestr, om->prefix);
} else if (rnd(1,3) == 1) { // 1 in 3 of shoddy
om = findobmod(OM_SHODDY);
strcat(cursestr, om->prefix);
f = hasflagval(ot->flags, F_CANHAVEOBMOD, om->id, NA, NA, NULL);
if (f && (f->val[1] != NA)) {
omposs[noms] = f;
noms++;
}
}
}
if (canbepoisoned(ot->id)) {
// random chance of being poisoned
if (rnd(1,6) == 1) {
obmod_t *om;
om = findobmod(OM_POISONED);
strcat(cursestr, om->prefix);
if (noms) {
// pick a random one to maybe apply
f = omposs[rnd(0,noms-1)];
if (rnd(1,100) <= f->val[1]) {
om = findobmod(f->val[0]);
if (om) {
strcat(cursestr, om->prefix);
}
}
}
@ -3928,6 +3955,31 @@ char *getschoolname(enum SPELLSCHOOL sch) {
return "unknown school";
}
char *getschoolnameshort(enum SPELLSCHOOL sch) {
switch (sch) {
case SS_ABILITY: return "Abilities";
case SS_ALLOMANCY: return "Allomancy";
case SS_DIVINE: return "Divine Powers";
case SS_WILD: return "Wild Magic";
case SS_MENTAL: return "Psionic Powers";
case SS_AIR: return "Air Magic";
case SS_EARTH: return "Earth Magic";
case SS_FIRE: return "Fire Magic";
case SS_ICE: return "Ice Magic";
case SS_MODIFICATION: return "Modification";
case SS_DEATH: return "Necromancy";
case SS_LIFE: return "Life Magic";
case SS_DIVINATION: return "Divination";
case SS_TRANSLOCATION: return "Translocation";
case SS_SUMMONING: return "Summoning";
case SS_GRAVITY: return "Gravitation";
case SS_LAST: return "!invalid school!";
default:
break;
}
return "unknown school";
}
int getshatterdam(object_t *o) {
int shatterdam = 0;
if (willshatter(o->material->id)) {
@ -4195,20 +4247,12 @@ void initobjects(void) {
}
}
addhiddenname(OC_WAND, "amethyst wand");
addhiddenname(OC_WAND, "brass wand");
addhiddenname(OC_WAND, "copper wand");
addhiddenname(OC_WAND, "diamond wand");
addhiddenname(OC_WAND, "emerald wand");
addhiddenname(OC_WAND, "flourescent wand");
addhiddenname(OC_WAND, "gold wand");
addhiddenname(OC_WAND, "humming wand");
addhiddenname(OC_WAND, "iridium wand");
addhiddenname(OC_WAND, "luminous wand");
addhiddenname(OC_WAND, "ruby wand");
addhiddenname(OC_WAND, "zinc wand");
addhiddenname(OC_WAND, "sapphire wand");
addhiddenname(OC_WAND, "wooden wand");
for (n = 0; strlen(gemtype[n].name); n++) {
char buf[BUFLEN];
// add it without an adjective
sprintf(buf, "%s wand", gemtype[n].name);
addhiddenname(OC_WAND, buf);
}
for (n = 0; strlen(gemtype[n].name); n++) {
char buf[BUFLEN];
@ -4232,6 +4276,8 @@ void initobjects(void) {
// object modifiers - flags can be either known or not, depending on if it's obvious
addobmod(OM_BLOODSTAINED,"bloodstained");
addflag_real(lastobmod->flags, F_SCARY, 2, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_FLAMING,"flaming");
addflag_real(lastobmod->flags, F_ONFIRE, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_FROZEN,"frozen");
@ -4243,7 +4289,7 @@ void initobjects(void) {
addobmod(OM_SHODDY,"shoddy");
addflag_real(lastobmod->flags, F_SHODDY, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_POISONED,"poisoned");
addflag_real(lastobmod->flags, F_HITCONFER, F_POISONED, SC_POISON, 25, "2-8", PERMENANT, B_KNOWN, -1);
addflag_real(lastobmod->flags, F_HITCONFER, F_POISONED, SC_POISON, 25, "15-30", PERMENANT, B_KNOWN, -1);
addobmod(OM_WET1,"damp");
addflag_real(lastobmod->flags, F_WET, W_DAMP, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
addobmod(OM_WET2,"wet");
@ -4390,9 +4436,14 @@ void initobjects(void) {
addoc(OC_WEAPON, "Weapons", "An instrument used for the purpose of causing harm or death.", ')', C_GREY);
addflag(lastobjectclass->flags, F_DAMAGABLE, 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_SHODDY, 34, NA, NULL);
addoc(OC_ARMOUR, "Armour/Clothing", "Protective gear.", ']', C_GREY);
addflag(lastobjectclass->flags, F_DAMAGABLE, 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_SHODDY, 34, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_BLOODSTAINED, 17, NA, NULL);
addoc(OC_MISSILE, "Missiles/Ammunition", "An instrument used for the purpose of causing harm or death.", ';', C_GREY);
addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
@ -4516,14 +4567,31 @@ void initobjects(void) {
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addot(OT_ASH, "pile of ash", "A pile of ash", MT_STONE, 0.1, OC_ROCK);
addot(OT_ASH, "pile of ash", "A pile of ash.", MT_STONE, 0.1, OC_ROCK);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addot(OT_ASHEXPLODE, "pile of exploding powder", "A pile of ash.", MT_STONE, 0.1, OC_ROCK);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_EXPLODEONDAM, NA, NA, NA, "1d6");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pile of ash");
addot(OT_ASHCONCEAL, "pile of concealing powder", "A pile of ash.", MT_STONE, 0.1, OC_ROCK);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, "");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pile of ash");
addot(OT_GEMOFSEEING, "gem of seeing", "Magically enhances your eyesight.", MT_STONE, 1, OC_ROCK);
addflag(lastot->flags, F_HOLDCONFER, F_XRAYVIS, 2, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_SEEINVIS, B_TRUE, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_ENHANCESEARCH, 20, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_DETECTAURAS, B_TRUE, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_DETECTMAGIC, B_TRUE, NA, NULL);
addflag(lastot->flags, F_VALUE, 1000, NA, NA, NULL);
@ -4597,17 +4665,19 @@ void initobjects(void) {
// potions (sorted by rarity)
addot(OT_POT_JUICE, "potion of fruit juice", "Tasty (but not very fresh) fruit juice!", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addot(OT_POT_WATER, "potion of water", "Plain, regular water.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small puddle of water");
addot(OT_POT_HEALINGMIN, "potion of minor healing", "Restores 1-8 health to whoever drinks it.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL);
addot(OT_POT_WATER, "potion of water", "Plain, regular water.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small puddle of water");
addot(OT_POT_HEALING, "potion of healing", "Restores 10-20 health to whoever drinks it.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL);
addot(OT_POT_OIL, "potion of oil", "A bottle of cooking oil.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addot(OT_POT_RUM, "potion of rum", "String liqour which is sure to make you tipsy.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addot(OT_POT_RESTORATION, "potion of restoration", "Restores lost abilities to the drinker.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addot(OT_POT_SPEED, "potion of haste", "Temporarily increasees the drinker's speed.", MT_GLASS, 1, OC_POTION);
@ -4619,8 +4689,6 @@ void initobjects(void) {
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addot(OT_POT_ACROBATICS, "potion of acrobatics", "Allows the drinker to leap large distances.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addot(OT_POT_ELEMENTENDURE, "potion of endure elements", "Grants the imbiber temporary resistance to both fire and cold.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addot(OT_POT_INVIS, "potion of invisibility", "Temporarily renders the drinker invisible.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL);
@ -4636,7 +4704,6 @@ void initobjects(void) {
addot(OT_POT_BLOOD, "potion of blood", "A small quantity of blood.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "splash of blood");
addot(OT_POT_SANCTUARY, "potion of sanctuary", "Creates a temporary magical barrier abour the drinker.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
@ -4814,10 +4881,6 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
// TODO: should be "castnearob ot_corpse"
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_WEAKEN, "weaken", "Temporarily lowers the target's muscle strength.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_S_DRAINLIFE, "drain life", "Draws life force from the victim in order to heal the caster.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
@ -4827,10 +4890,19 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// l4
addot(OT_S_WEAKEN, "weaken", "Temporarily lowers the target's muscle strength.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_S_PARALYZE, "paralyze", "Disables the target's muscles, leaving them unable to move.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// l5
addot(OT_S_FEEBLEMIND, "feeblemind", "Temporarily lowers the target's intelligence to that of an animal.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// l7
addot(OT_S_POSSESSION, "possession", "Completely possess an enemy, moving your consciousness into their body.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
@ -4844,7 +4916,7 @@ void initobjects(void) {
// divination
///////////////////
// l1
addot(OT_S_DETECTLIFE, "detect life", "Senses life near the caster.", MT_NOTHING, 0, OC_SPELL);
addot(OT_S_DETECTLIFE, "detect life", "Senses the size of creatures near the caster. At Power V, it will detect exact creature types.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
// l2
@ -4862,6 +4934,10 @@ void initobjects(void) {
addot(OT_S_DETECTMAGIC, "detect magic", "Allows the caster to detect magical enchantments.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
// l4
addot(OT_S_REVEALHIDDEN, "reveal hidden", "Reveals hidden doors or invisible creatures in the caster's line of sight.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
// l8
addot(OT_S_IDENTIFY, "identification", "Completely identifies any one item.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL);
@ -5026,10 +5102,10 @@ void initobjects(void) {
addot(OT_S_INSCRIBE, "inscribe", "Creates a magical inscription viewable to anyone standing nearby.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addot(OT_S_KNOCK, "knock", "Magically opens doors or other such barriers.", MT_NOTHING, 0, OC_SPELL);
addot(OT_S_KNOCK, "knock", "Magically opens doors or other such barriers.\nAt Power VII, this spell will also knock back living creatures.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addot(OT_S_LIGHT, "light", "Creates a permenant light source centred on the caster.", MT_NOTHING, 0, OC_SPELL);
addot(OT_S_LIGHT, "light", "Creates a temporary light source centred on the caster.\nAt Power III, you can control where the light appears.\nAt Power VIII, the light becomes permenant.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
@ -5043,6 +5119,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_XPVAL, 50, NA, NA, NULL);
addot(OT_S_PASSWALL, "passwall", "Allows the caster to temporarily walk through walls.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
@ -5056,7 +5133,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_S_POLYMORPH, "polymorph", "Transmutes the target into a new living race. Becomes controlled at high power.", MT_NOTHING, 0, OC_SPELL);
addot(OT_S_POLYMORPH, "polymorph", "Transmutes the target into a new living race.\nBecomes semi-controlled at Power V, and fully-controlled at power VIII.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
// l7
@ -5069,7 +5146,7 @@ void initobjects(void) {
// summoning
///////////////////
// l2
addot(OT_S_CREATEMONSTER, "create monster", "Summons a (probably hostile) monster to a nearby location.", MT_NOTHING, 0, OC_SPELL);
addot(OT_S_CREATEMONSTER, "create monster", "Summons a (probably hostile) monster to a nearby location.\nAt Power V you can control where the monster appears.\nAt Power VII, you can control the type of monster created.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
@ -5087,7 +5164,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// l4
addot(OT_S_TELEPORT, "teleportation", "Causes the caster to teleport to a new location within the same level. Becomes controlled at high power.", MT_NOTHING, 0, OC_SPELL);
addot(OT_S_TELEPORT, "teleportation", "Teleports the caster (and Power-1 adjacent allies) to a new location within the same level.\nBecomes semi-controlled at Power V, and fully controlled at Power VII.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
@ -5165,11 +5242,14 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addot(OT_A_JUMP, "jump", "You can leap large distances.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_HIDE, "hide", "You can hide in the shadows.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addot(OT_A_INSPECT, "inspect", "Try to identify an unknown object from your pack.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_HURRICANESTRIKE, "hurricane strike", "A sweeping attack aginst everything nearby.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addot(OT_A_INSPECT, "inspect", "Try to identify an unknown object from your pack.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_POLYREVERT, "revertform", "Revert to your original form.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL);
@ -5209,6 +5289,8 @@ void initobjects(void) {
addflag(lastot->flags, F_MANUALOF, SK_SHIELDS, NA, NA, NULL);
addot(OT_MAN_SPELLCASTING, "manual of spellcasting", "Teaches you the skill 'spellcasting'.", MT_PAPER, 3, OC_BOOK);
addflag(lastot->flags, F_MANUALOF, SK_SPELLCASTING, NA, NA, NULL);
addot(OT_MAN_SPOTHIDDEN, "manual of searching", "Teaches you the skill 'searching'.", MT_PAPER, 3, OC_BOOK);
addflag(lastot->flags, F_MANUALOF, SK_SPOTHIDDEN, NA, NA, NULL);
addot(OT_MAN_STEALTH, "manual of stealth", "Teaches you the skill 'stealth'.", MT_PAPER, 3, OC_BOOK);
addflag(lastot->flags, F_MANUALOF, SK_STEALTH, NA, NA, NULL);
addot(OT_MAN_TECHUSAGE, "manual of technology", "Teaches you the skill 'technology'.", MT_PAPER, 3, OC_BOOK);
@ -5237,6 +5319,8 @@ void initobjects(void) {
addflag(lastot->flags, F_MANUALOF, SK_SS_DEATH, NA, NA, NULL);
addot(OT_MAN_SS_DIVINATION, "manual of divination", "Teaches you the skill 'divination'.", MT_PAPER, 3, OC_BOOK);
addflag(lastot->flags, F_MANUALOF, SK_SS_DIVINATION, NA, NA, NULL);
addot(OT_MAN_SS_EARTH, "manual of earth magic", "Teaches you the skill 'earth magic'.", MT_PAPER, 3, OC_BOOK);
addflag(lastot->flags, F_MANUALOF, SK_SS_EARTH, NA, NA, NULL);
addot(OT_MAN_SS_FIRE, "manual of fire magic", "Teaches you the skill 'fire magic'.", MT_PAPER, 3, OC_BOOK);
addflag(lastot->flags, F_MANUALOF, SK_SS_FIRE, NA, NA, NULL);
addot(OT_MAN_SS_ICE, "manual of ice magic", "Teaches you the skill 'ice magic'.", MT_PAPER, 3, OC_BOOK);
@ -5261,6 +5345,8 @@ void initobjects(void) {
addflag(lastot->flags, F_LINKSPELL, OT_S_ANIMATEDEAD, NA, NA, NULL);
addot(OT_SB_DRAINLIFE, "spellbook of drain life", "Teaches the spell 'drain life'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_DRAINLIFE, NA, NA, NULL);
addot(OT_SB_FEEBLEMIND, "spellbook of feeblemind", "Teaches the spell 'feeblemind'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_FEEBLEMIND, NA, NA, NULL);
addot(OT_SB_PAIN, "spellbook of pain", "Teaches the spell 'pain'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_PAIN, NA, NA, NULL);
addot(OT_SB_PARALYZE, "spellbook of paralyze", "Teaches the spell 'paralyze'.", MT_PAPER, 1.5, OC_BOOK);
@ -5282,6 +5368,8 @@ void initobjects(void) {
addflag(lastot->flags, F_LINKSPELL, OT_S_MAPPING, NA, NA, NULL);
addot(OT_SB_DETECTAURA, "spellbook of detect aura", "Teaches the spell 'detect aura'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTAURA, NA, NA, NULL);
addot(OT_SB_REVEALHIDDEN, "spellbook of reveal hidden", "Teaches the spell 'reveal hidden'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_REVEALHIDDEN, NA, NA, NULL);
addot(OT_SB_IDENTIFY, "spellbook of identification", "Teaches the spell 'identification'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_IDENTIFY, NA, NA, NULL);
// elemental - air
@ -5418,6 +5506,9 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_LIGHT, 3, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addot(OT_WAND_REVEALHIDDEN, "wand of reveal hidden", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_REVEALHIDDEN, NA, NA, NULL);
addot(OT_WAND_SLOW, "wand of slowness", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_SLOW, NA, NA, NULL);
@ -5510,7 +5601,7 @@ void initobjects(void) {
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDAM, 15, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDAM, NA, NA, NA, "8d2");
addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "2d6");
addflag(lastot->flags, F_FLAMMABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
@ -5636,8 +5727,8 @@ void initobjects(void) {
addflag(lastot->flags, F_RECHARGEWHENOFF, 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_EXPLODEONDEATH, 15, NA, B_IFACTIVATED, NULL);
addflag(lastot->flags, F_EXPLODEONDAM, 10, NA, B_IFACTIVATED, NULL);
addflag(lastot->flags, F_EXPLODEONDEATH, NA, NA, B_IFACTIVATED, "8d2");
addflag(lastot->flags, F_EXPLODEONDAM, NA, NA, B_IFACTIVATED, "5d2");
addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
@ -5652,7 +5743,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RECHARGEWHENOFF, 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_EXPLODEONDEATH, 30, B_BIG, B_IFACTIVATED, NULL);
addflag(lastot->flags, F_EXPLODEONDEATH, NA, B_BIG, B_IFACTIVATED, "15d2");
addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
@ -5678,6 +5769,7 @@ void initobjects(void) {
addot(OT_INFOVISOR, "infovisor", "Sleek looking metal visor which displays info directly into the retina.", MT_METAL, 0.2, OC_TECH);
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_EXTRAINFO, B_TRUE, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ENHANCESEARCH, 10, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_SKILLED, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
@ -6204,6 +6296,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
addflag(lastot->flags, F_SCARY, 2, NA, NA, NULL);
addot(OT_CAP, "cap", "Close-fitting headwear with a short shade visor at the front.", MT_CLOTH, 1, OC_ARMOUR);
addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
@ -6243,6 +6336,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_EVASION, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_SCARY, 4, NA, NA, NULL);
@ -6259,6 +6353,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SCARY, 2, NA, NA, NULL);
addot(OT_NVGOGGLES, "nightvis goggles", "Special goggles which allow the wear to see in the dark.", MT_METAL, 1.5, OC_ARMOUR);
addflag(lastot->flags, F_RARITY, H_ALL, 25, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
@ -6302,7 +6397,7 @@ void initobjects(void) {
addot(OT_RING_SIGHT, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINVIS, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 5, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 3, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, 1, NA, NULL);
addot(OT_RING_MANA, "ring of mana", "Increases the wearer's MP pool.", MT_METAL, 0.1, OC_RING);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
@ -6458,7 +6553,7 @@ void initobjects(void) {
addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_NANODART, "nanodart", "A metal dart with a laser-sharpened point.", MT_METAL, 0.5, OC_MISSILE);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
@ -6467,7 +6562,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_JAVELIN, "javelin", "A long, sharp missile weapon.", MT_METAL, 1.5, OC_MISSILE);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
@ -6476,7 +6571,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, "");
addflag(lastot->flags, F_OBHP, 3, 3, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.5, OC_MISSILE);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
@ -6485,14 +6580,14 @@ void initobjects(void) {
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 1, OC_MISSILE);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_BULLET, "bullet", "A regular gun bullet.", MT_STONE, 0.1, OC_MISSILE);
@ -6667,7 +6762,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL);
// polearms
addot(OT_GLAIVE, "glaive", "A long pole with a sharpened head.", MT_METAL, 4, OC_WEAPON);
addot(OT_GLAIVE, "glaive", "A single-edged blade attached to a long pole.", MT_METAL, 4, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7+3");
@ -6675,7 +6770,7 @@ void initobjects(void) {
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL);
addot(OT_GUISARME, "guisarme", "A hooked polearm.", MT_METAL, 4, OC_WEAPON);
addot(OT_GUISARME, "guisarme", "A hooked polearm, made by attaching a hook to a spear shaft.", MT_METAL, 4, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
@ -7209,6 +7304,7 @@ int ismagical(object_t *o) {
case OT_POT_OIL:
case OT_POT_WATER:
case OT_POT_BLOOD:
case OT_POT_RUM:
case OT_POT_JUICE:
// these potions are non-magical
break;
@ -7372,6 +7468,13 @@ int isrotting(object_t *o) {
return B_FALSE;
}
flag_t *issecretdoor(object_t *o) {
if (isdoor(o, NULL)) {
return hasflag(o->flags, F_SECRETDOOR);
}
return NULL;
}
// returns the 'shield' flag
flag_t *isshield(object_t *o) {
return hasflag(o->flags, F_SHIELD);
@ -8227,29 +8330,38 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
ttype = f->val[0];
}
if (strlen(f->text) > 0) {
where = askcoords(f->text, ttype);
} else {
sprintf(buf, "Where will you aim %s?",obname);
where = askcoords(buf, ttype);
if (!haslos(lf, where)) {
// exception - wand of digging doesn't need los
if (isknown(o) && (o->type->id == OT_WAND_DIGGING)) {
} else {
msg("You can't see there!");
return B_TRUE;
if (isplayer(lf)) {
if (strlen(f->text) > 0) {
where = askcoords(f->text, ttype);
} else {
sprintf(buf, "Where will you aim %s?",obname);
where = askcoords(buf, ttype);
if (!haslos(lf, where)) {
// exception - wand of digging doesn't need los
if (isknown(o) && (o->type->id == OT_WAND_DIGGING)) {
} else {
msg("You can't see there!");
return B_TRUE;
}
}
}
} else {
char lfname[BUFLEN];
getlfname(lf, lfname);
dblog("BUG - ai (%s, id %d) using wand (%s) without target.",
lfname, lf->id, obname);
where = NULL;
}
if (!where) {
// cancel.
msg("Cancelled.");
if (isplayer(lf)) msg("Cancelled.");
return B_TRUE;
} else {
if (f->val[1] != NA) {
cell_t *newwhere = NULL;
if ((f->val[1] & TR_NEEDLOS) && !haslos(lf, where)) {
msg("You can't see there!");
if (isplayer(lf)) msg("You can't see there!");
return B_TRUE;
}
if ((f->val[1] & TR_NEEDLOF) && !haslof(lf->cell, where, B_TRUE, &newwhere)) {
@ -8257,7 +8369,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
// update destination
where = newwhere;
} else {
msg("You have no line of fire to there!");
if (isplayer(lf)) msg("You have no line of fire to there!");
return B_TRUE;
}
}
@ -8995,11 +9107,13 @@ int pour(lifeform_t *lf, object_t *o) {
dst->blessknown = B_TRUE;
// remove bonuses
killflagsofid(dst->flags, F_BONUS);
// remove temporary flags and modify some others
// remove temporary flags, obmod flags and modify some others
for (f = dst->flags->first ; f ; f = nextf) {
nextf = f->next;
if (f->lifetime > 0) {
killflag(f);
} else if (f->lifetime == FROMOBMOD) {
killflag(f);
} else if (f->id == F_FROZEN) {
killflag(f);
} else if (f->id == F_ONFIRE) {
@ -9009,11 +9123,12 @@ int pour(lifeform_t *lf, object_t *o) {
} else if (f->id == F_OBHP) {
f->val[0] = f->val[1];
}
}
// restore hp
if (!isknown(dst)) makeknown(dst->type->id);
// we now know what the potion was
if (!isknown(o)) makeknown(o->type->id);
//if (!isknown(dst)) makeknown(dst->type->id);
} else if (o->type->id == OT_POT_ACID) {
// damage destinaiton
msg("You pour %s onto %s.", obname,dstname);
@ -9103,21 +9218,12 @@ void quaff(lifeform_t *lf, object_t *o) {
willid = B_FALSE;
if (playercansee) {
switch (o->type->id) {
enum ATTRIB a;
case OT_POT_HEALING:
case OT_POT_HEALINGMIN:
if (lf->hp < lf->maxhp) {
willid = B_TRUE;
}
break;
case OT_POT_RESTORATION:
for (a = 0; a < (MAXATTS-1); a++) {
if (getattr(lf,a) < lf->baseatt[a]) {
willid = B_TRUE;
break;
}
}
break;
default:
willid = B_TRUE;
break;
@ -9167,13 +9273,14 @@ void quaff(lifeform_t *lf, object_t *o) {
}
void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, int *seen) {
char buf[BUFLEN];
char lfname[BUFLEN];
unsigned int dam;
int i;
int first,dir;
int amt;
int failed;
int seenbyplayer;
int hpheal,mpheal;
flag_t *f;
if (isplayer(lf)) {
@ -9188,6 +9295,8 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i
*seen = seenbyplayer;
}
getlfname(lf, lfname);
switch (oid) {
case OT_POT_ACID:
dam = rnd(5,10);
@ -9195,9 +9304,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i
if (isplayer(lf)) {
msg("Your suffer massive internal burning!");
} else if (cansee(player, lf)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s writhes in agony!", buf);
msg("%s writhes in agony!", lfname);
}
break;
case OT_POT_ACROBATICS:
@ -9231,8 +9338,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i
if (isplayer(lf)) {
msg("You feel completely healed!");
} else if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s looks completely healed!", buf);
msg("%s looks completely healed!", lfname);
}
} else {
if (isplayer(lf)) {
@ -9283,22 +9389,27 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i
if (seen) *seen = B_TRUE;
}
break;
case OT_POT_ELEMENTENDURE:
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) {
if (isplayer(lf)) {
msg("You feel momentarily resistant to the elements.");
}
break;
}
case OT_POT_RUM:
// how long for?
i = geteffecttime(15,25,potblessed);
f = lfhasflag(lf, F_DRUNK);
if (f) {
if (isplayer(lf)) {
msg("You feel more tipsy.");
} else if (cansee(player, lf)) {
msg("%s looks more tipsy.", lfname);
}
f->lifetime += DRUNKTIME;
} else {
addtempflag(lf->flags, F_DRUNK, 1, NA, NA, NULL, DRUNKTIME);
}
/*
if (!lfhasflagval(lf, F_DTRESIST, DT_FIRE, NA, NA, NULL)) {
addtempflag(lf->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL, i);
}
if (!lfhasflagval(lf, F_DTRESIST, DT_COLD, NA, NA, NULL)) {
addtempflag(lf->flags, F_DTRESIST, DT_COLD, NA, NA, NULL, i);
}
*/
break;
case OT_POT_ELEMENTIMMUNE:
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) {
@ -9389,7 +9500,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i
}
break;
case OT_POT_POISON:
poison(lf, rnd(10,20), "a potion of poison");
poison(lf, rnd(10,20), P_FOOD, 1, "a potion of poison");
break;
case OT_POT_POLYMORPH:
if (potblessed == B_BLESSED) {
@ -9408,26 +9519,48 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i
}
break;
}
if (getattr(lf,A_STR) < lf->baseatt[A_STR]) {
setattr(lf, A_STR, lf->baseatt[A_STR]);
if (isplayer(lf)) msg("Your strength is restored!");
failed = B_FALSE;
}
if (getattr(lf,A_DEX) < lf->baseatt[A_DEX]) {
setattr(lf, A_DEX, lf->baseatt[A_DEX]);
if (isplayer(lf)) msg("Your dexterity is restored!");
failed = B_FALSE;
}
if (getattr(lf,A_IQ) < lf->baseatt[A_IQ]) {
setattr(lf, A_IQ, lf->baseatt[A_IQ]);
if (isplayer(lf)) msg("Your intelligence is restored!");
failed = B_FALSE;
}
if (potblessed == B_BLESSED) {
hpheal = lf->maxhp;
mpheal = getmaxmp(lf);
} else if (potblessed == B_CURSED) {
hpheal = lf->maxhp / 3;
mpheal = getmaxmp(lf) / 3;
} else {
hpheal = lf->maxhp / 2;
mpheal = getmaxmp(lf) / 2;
}
// blessed restores hp/mp to full
if (lf->hp < hpheal) {
gainhp(lf, hpheal - lf->hp);
if (!isplayer(lf) && cansee(player, lf)) {
msg("%s%s health has been restored!", lfname, getpossessive(lfname));
}
failed = B_FALSE;
}
if (lf->mp < mpheal) {
gainmp(lf, mpheal - lf->mp);
failed = B_FALSE;
}
if (failed) {
if (isplayer(lf)) {
msg("You feel momentarily restored.");
}
if (isplayer(lf)) msg("You feel momentarily restored.");
} else {
if (isplayer(lf)) msg("You feel restored!");
}
break;
case OT_POT_SANCTUARY:
@ -9475,8 +9608,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i
if (isplayer(lf)) {
msg("This tastes like water, but burns like acid!");
} else if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s writhes in agony!", buf);
msg("%s writhes in agony!", lfname);
}
losehp(lf, rnd(5,15), DT_HOLY, NULL, "drinking holy water");
} else {
@ -10344,8 +10476,38 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
// some obejcts will die when thrown.
if (hasflag(o->flags, F_POWDER)) {
if (haslos(player, srcloc)) {
msg("%s dispers%s into the air.", obname, (amt == 1) ? "es" : "e");
// special cases first
if (o->type->id == OT_ASHCONCEAL) {
int radius;
// make smoke
if (haslos(player, srcloc)) {
msg("%s dispers%s into a thick cloud of smoke!", obname,
(amt == 1) ? "es" : "e",
(amt == 1) ? "es" : "e" );
if (!isknown(o)) makeknown(o->type->id);
}
radius = o->amt * 2;
if (radius > 10) radius = 10;
addobsinradius(thrower->cell, radius, DT_COMPASS, "cloud of smoke", B_FALSE);
} else if (o->type->id == OT_ASHEXPLODE) {
char diebuf[BUFLEN];
// explosion!
sprintf(diebuf, "%dd6",o->amt);
if (haslos(player, srcloc)) {
msg("%s dispers%s and explod%s!", obname,
(amt == 1) ? "es" : "e",
(amt == 1) ? "es" : "e" );
if (!isknown(o)) makeknown(o->type->id);
}
explodecells(thrower->cell, roll(diebuf), B_FALSE, o, 1, DT_COMPASS, B_FALSE);
} else {
if (haslos(player, srcloc)) {
msg("%s dispers%s into the air.", obname, (amt == 1) ? "es" : "e");
if (!isknown(o)) makeknown(o->type->id);
}
}
removeob(o, amt);
return B_FALSE;
@ -10595,7 +10757,6 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
}
}
break;
case OT_POT_ELEMENTENDURE:
case OT_POT_ELEMENTIMMUNE:
case OT_POT_ETHEREALNESS:
case OT_POT_GASEOUSFORM:
@ -11263,6 +11424,16 @@ int validateobs(void) {
goterror = B_TRUE;
}
}
f = hasflag(ot->flags, F_EXPLODEONDAM);
if (f && !strlen(f->text)) {
printf("ERROR in object '%s' - F_EXPLODEONDAM does not have damage string.\n", ot->name);
goterror = B_TRUE;
}
f = hasflag(ot->flags, F_EXPLODEONDEATH);
if (f && !strlen(f->text)) {
printf("ERROR in object '%s' - F_EXPLODEONDEATH does not have damage string.\n", ot->name);
goterror = B_TRUE;
}
}
for (sk = firstskill ; sk ; sk = sk->next) {

View File

@ -13,6 +13,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack);
int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fromlf);
obmod_t *addobmod(enum OBMOD id, char *prefix);
obpile_t *addobpile(lifeform_t *owner, cell_t *where);
void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes);
objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid);
void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat);
void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype);
@ -97,6 +98,7 @@ char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf);
int getobrarity(object_t *o);
enum SPELLSCHOOL getschool(enum OBTYPE sid);
char *getschoolname(enum SPELLSCHOOL sch);
char *getschoolnameshort(enum SPELLSCHOOL sch);
int getshatterdam(object_t *o);
enum SKILLLEVEL gettechlevel(object_t *o);
int getthrowdam(object_t *o);
@ -143,6 +145,7 @@ int ispourable(object_t *o);
int ispushable(object_t *o);
int isreadable(object_t *o);
int isrotting(object_t *o);
flag_t *issecretdoor(object_t *o);
flag_t *isshield(object_t *o);
int isthrownmissile(object_t *o);
int istried(object_t *o);

5
save.c
View File

@ -142,7 +142,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
int obcount;
int mapid;
map_t *m;
int x,y,level;
int x,y,level,newlevel;
int db = B_TRUE;
if (db) dblog("--> Loading lifeform...\n");
@ -153,6 +153,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
fscanf(f, "map: %d\n",&mapid);
fscanf(f, "pos: %d,%d\n",&x, &y);
fscanf(f, "level: %d\n",&level);
fscanf(f, "newlevel: %d\n",&newlevel);
// find the map
m = findmap(mapid);
@ -172,6 +173,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
l->id = lfid;
l->x = x;
l->y = y;
l->newlevel = newlevel;
// load rest of this lf
fscanf(f, "str: %d/%d\n",&l->att[A_STR],&l->baseatt[A_STR]);
@ -630,6 +632,7 @@ int savelf(FILE *f, lifeform_t *l) {
fprintf(f, "map: %d\n",l->cell->map->id);
fprintf(f, "pos: %d,%d\n",l->cell->x, l->cell->y);
fprintf(f, "level: %d\n",l->level);
fprintf(f, "newlevel: %d\n",l->newlevel);
// liefform will be created after loading the above.
fprintf(f, "str: %d/%d\n",l->att[A_STR],l->baseatt[A_STR]);
fprintf(f, "dex: %d/%d\n",l->att[A_DEX],l->baseatt[A_DEX]);

250
spell.c
View File

@ -650,6 +650,35 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// remove temporary flags
killflag(f);
killflag(f2);
} else if (abilid == OT_A_HIDE) {
int penalty = 0;
if (lfhasflag(user, F_HIDING)) {
if (isplayer(user)) msg("You are already hiding!");
return B_TRUE;
}
if (!safetorest(user)) {
if (getskill(user, SK_STEALTH) == PR_EXPERT) {
// can still hide, but with a penalty
penalty = -4;
} else if (getskill(user, SK_STEALTH) == PR_MASTER) {
// can still hide, but with a penalty
penalty = -2;
} else {
if (isplayer(user)) msg("You can't hide - there are monsters around!");
return B_TRUE;
}
}
// no stealth skill?
if (!getskill(user, SK_STEALTH)) {
penalty = -5;
}
// start hiding
addflag(user->flags, F_HIDING, penalty, NA, NA, NULL);
taketime(user, getactspeed(user));
} else if (abilid == OT_A_INSPECT) {
object_t *o;
int difficulty;
@ -1087,6 +1116,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!ischarmable(target)) {
if (isplayer(caster)) {
switch (reason) {
case E_DRUNK:
msg("%s%s mind is too alcohol-impaired for you to charm.",targetname,getpossessive(targetname));
break;
case E_LOWIQ:
msg("%s%s intellect is too simple for you to charm.",targetname,getpossessive(targetname));
break;
@ -1101,12 +1133,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_FALSE;
}
if (getallegiance(caster) == AL_PEACEFUL) {
fizzle(caster);
return B_FALSE;
}
if (getallegiance(target) == getallegiance(caster)) {
if (ispetof(target, caster)) {
if (isplayer(caster)) {
msg("%s is already allied with you!",targetname);
}
@ -1130,7 +1161,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
howlong = getspellduration(20,30,blessed) + (power*10);
//
addtempflag(target->flags, F_CHARMEDBY, caster->id, NA, NA, NULL, howlong);
addtempflag(target->flags, F_PETOF, caster->id, NA, NA, NULL, howlong);
}
} else if (spellid == OT_S_COLDBURST) {
int range = 1;
@ -1386,6 +1419,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
(numseen == 1) ? "s" : ""
);
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else {
if (isplayer(caster)) nothinghappens();
}
} else if (spellid == OT_S_DETECTLIFE) {
target = caster;
@ -1431,7 +1466,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// don't need line of fire!
if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_DOOR, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE;
explodecells(targcell, 20, B_TRUE, NULL, power / 4, B_TRUE);
explodecells(targcell, 20, B_TRUE, NULL, power / 4, DT_ORTH, B_TRUE);
if (haslos(player, targcell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -1459,9 +1494,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// announce
if (totalmass < 10) {
// little one
explodecells(targcell, totalmass*5, B_FALSE, NULL, 0, B_TRUE);
explodecells(targcell, totalmass*5, B_FALSE, NULL, 0, DT_COMPASS, B_TRUE);
} else {
explodecells(targcell, totalmass*5, B_TRUE, NULL, 1, B_TRUE);
explodecells(targcell, totalmass*5, B_TRUE, NULL, 1, DT_COMPASS, B_TRUE);
}
} else {
fizzle(caster);
@ -1619,6 +1654,44 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
}
} else if (spellid == OT_S_FEEBLEMIND) {
// ask for target
if (!validatespelllf(caster, &target)) return B_TRUE;
if ((getattr(target, A_IQ) <= 3) || skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (cansee(player, target)) {
getlfname(target, buf);
msg("%s %s momentarily foolish.", buf, isplayer(target) ? "feel" : "looks");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
}
if (target) {
int howlong = 15;
flag_t *f;
// already feebleminded?
for (f = target->flags->first; f ; f = f->next) {
if ((f->id == F_ATTRMOD) && (f->val[0] == A_IQ) && (f->obfrom == OT_S_FEEBLEMIND)) {
if (cansee(player, target)) {
getlfname(target, buf);
msg("%s %s momentarily more foolish.", buf, isplayer(target) ? "feel" : "looks");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
}
}
howlong = getspellduration(5,10,blessed) + power;
// always set to 3 (ie. animal)
f = addtempflag(target->flags, F_ATTRSET, A_IQ, 3, NA, NULL, howlong);
f->obfrom = OT_S_FEEBLEMIND;
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else {
fizzle(caster);
}
} else if (spellid == OT_S_FLASH) {
if (isplayer(caster) || cansee(player, caster)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -1900,7 +1973,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
char obname[BUFLEN];
char ch;
getobname(o, obname, o->amt);
msg("Your %s start%s glowing bright blue!", obname, (o->amt == 1) ? "s" : "");
msg("%s %s start%s glowing bright blue!",
(o->pile->owner == caster) ? "Your" : "",
(o->pile->owner == caster) ? noprefix(obname) : obname,
(o->amt == 1) ? "s" : "");
more();
ch = askchar("Abort your spell?", "yn","y", B_TRUE);
if (ch == 'y') {
@ -1924,18 +2000,31 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
if (!o) {
if (isplayer(caster)) {
msg("Your hands feel freezing cold for a moment.");
}
fizzle(caster);
return B_TRUE;
}
// object will turn to ice immediately...
if (isplayer(caster)) {
msg("Your hands feel freezing cold!");
}
if (o->material->id == MT_ICE) { // already made of ice?
if (isplayer(caster)) {
nothinghappens();
cell_t *loc;
flag_t *f;
loc = getoblocation(o);
// announce
if (haslos(caster, loc)) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
msg("%s %s freeze%s some more.",
(o->pile->owner == caster) ? "Your" : "",
(o->pile->owner == caster) ? noprefix(obname) : obname,
(o->amt == 1) ? "s" : "");
}
// restore it
f = hasflag(o->flags, F_OBHP);
if (f) {
f->val[0] = f->val[1];
}
return B_TRUE;
} else {
@ -2020,12 +2109,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
} else {
howlong = getspellduration(5,25,blessed) + power;
addtempflag(target->flags, F_FASTACT, 10, NA, NA, NULL, howlong);
addtempflag(target->flags, F_FASTMOVE, 10, NA, NA, NULL, howlong);
addtempflag(target->flags, F_FASTACTMOVE, 10, NA, NA, NULL, howlong);
}
} else if (spellid == OT_S_HEALING) {
int donesomething = B_FALSE;
flag_t *f;
target = caster;
// cure certain bad effects
@ -2059,9 +2146,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
donesomething = B_TRUE;
}
f = lfhasflag(target, F_POISONED);
if (f) {
killflag(f);
if (killflagsofid(target->flags, F_POISONED)) {
donesomething = B_TRUE;
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
@ -2073,7 +2158,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
} else if (spellid == OT_S_HEALINGMIN) {
int donesomething = B_FALSE;
flag_t *f;
target = caster;
// cure bad effects instead of healing
@ -2104,9 +2188,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
donesomething = B_TRUE;
}
f = lfhasflag(target, F_POISONED);
if (f) {
killflag(f);
if (killflagsofid(target->flags, F_POISONED)) {
donesomething = B_TRUE;
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
@ -2538,9 +2620,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (cansee(caster, target)) {
msg("A glob of venom hits %s.",lfname);
}
losehp(target, rnd(1,4), DT_POISON, caster, "a glob of poison");
if (!isimmuneto(target->flags, DT_POISON)) {
addtempflag(target->flags, F_POISONED, NA, NA, NA, castername, power*3);
poison(target, power*3, P_VENOM, power, "a glob of venom");
}
}
} else {
@ -2586,6 +2667,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!ischarmable(target)) {
if (isplayer(caster)) {
switch (reason) {
case E_DRUNK:
msg("%s%s mind is too alcohol-impaired for you to possess.",targname,getpossessive(targname));
break;
case E_LOWIQ:
msg("%s%s intellect is too simple for you to possess.",targname,getpossessive(targname));
break;
@ -2944,6 +3028,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
addtempflag(target->flags, F_INVISIBLE, B_TRUE, NA, NA, NULL, howlong);
if (willannounce && !lfhasflag(player, F_SEEINVIS)) {
msg("%s flicker%s then vanishes!",targname, isplayer(target) ? "" : "s");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_KNOCK) {
object_t *o;
@ -2983,6 +3068,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = addtempflag(caster->flags, F_LEVITATING, B_TRUE, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
if (cansee(player, target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_LIGHT) {
lifeform_t *l;
@ -3063,15 +3152,20 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (target) {
int howlong = 15;
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (lfhasflag(target, F_GRAVBOOSTED) || skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (isplayer(target)) {
msg("You feel momentarily heavier.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) {
char targname[BUFLEN];
getlfname(target, targname);
msg("%s looks momentarily heavier.", targname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
}
howlong = getspellduration(2,10,blessed) + (power/2);
howlong = getspellduration(3,10,blessed) + (power/2);
addtempflag(target->flags, F_GRAVBOOSTED, B_TRUE, NA, NA, NULL, howlong);
} else {
fizzle(caster);
@ -3253,6 +3347,54 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
return B_TRUE;
}
} else if (spellid == OT_S_REVEALHIDDEN) {
int i;
int seen = B_FALSE;
for (i = 0 ; i < caster->nlos; i++ ){
targcell = caster->los[i];
if (targcell) {
object_t *o;
if (isplayer(caster)) {
// reveal secret doors
for (o = targcell->obpile->first ; o ; o = o->next) {
flag_t *f;
f = hasflag(o->flags, F_SECRETDOOR);
if (f) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
msg("%s is magically revealed!", obname);
killflag(f);
seen = B_TRUE;
}
}
}
// remove invisibility
if (targcell->lf) {
flag_t *f, *nextf;
for (f = targcell->lf->flags->first ; f ; f = nextf) {
nextf = f->next;
if (f->id == F_INVISIBLE) {
if ((f->lifetime > 0) || (f->lifetime == PERMENANT)) {
killflag(f);
// player can see whoever just appeared, and the caster?
if (cansee(player, targcell->lf) && cansee(player, caster)) {
seen = B_TRUE;
}
}
}
}
}
}
}
if (seen) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else {
if (isplayer(caster)) {
nothinghappens();
}
}
} else if (spellid == OT_S_SLEEP) {
int howlong;
if (!validatespelllf(caster, &target)) return B_TRUE;
@ -3295,8 +3437,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
howlong = rnd(5,25) + power;
addtempflag(target->flags, F_SLOWACT, 10, NA, NA, NULL, howlong);
addtempflag(target->flags, F_SLOWMOVE, 10, NA, NA, NULL, howlong);
addtempflag(target->flags, F_SLOWACTMOVE, 10, NA, NA, NULL, howlong);
if (isplayer(target) || haslos(player, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
@ -3322,6 +3463,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
} else if (spellid == OT_S_TELEPORT) {
cell_t *c = NULL;
lifeform_t *ally[8];
int nallies = 0;
// target is always the caster
target = caster;
@ -3471,10 +3614,35 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
targcell = c;
// we can take up to 'power-1' allies with us.
if (caster == target) {
int dir;
for (dir = DC_N; (dir <= DC_NW) && (nallies < power); dir++) {
c = getcellindir(target->cell, dir);
if (c && c->lf && areallies(c->lf, caster)) {
ally[nallies] = c->lf;
nallies++;
}
}
}
if (isplayer(target) || haslos(player, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
teleportto(target, targcell, B_TRUE);
// now do allies
if (nallies) {
int i;
for (i = 0; i < nallies; i++) {
c = getrandomadjcell(targcell, WE_WALKABLE, B_ALLOWEXPAND);
if (c) {
teleportto(ally[i], c, B_TRUE);
}
}
}
rv = B_FALSE;
} else if (spellid == OT_S_TELEKINESIS) {
cell_t *where;
@ -3752,6 +3920,32 @@ enum SKILL getschoolskill(enum SPELLSCHOOL ss) {
return SK_NONE;
}
// returns "x MP" or "x-y MP", or "x-y MP, ongoing" ect
char *getspellcosttext(lifeform_t *lf, enum OBTYPE spellid, int power, char *buf) {
objecttype_t *ot;
int ongoing = B_FALSE;
int cost;
ot = findot(spellid);
if (!ot) {
strcpy(buf, "?invalidspellid?");
return buf;
}
cost = getmpcost(lf, spellid);
if (hasflag(ot->flags, F_ONGOING)) ongoing = B_TRUE;
if (hasflag(ot->flags, F_VARPOWER)) {
sprintf(buf, "%d-%d MP%s", cost,
cost * power, ongoing ? ", ongoing" : "");
} else {
sprintf(buf, "%d MP%s", cost, ongoing ? ", ongoing" : "");
}
return buf;
}
// returns a number between min & max
// if blessed, always the max
// if cursed, always the min

View File

@ -8,6 +8,7 @@ void fizzle(lifeform_t *caster);
//int getiqreq(enum OBTYPE oid);
int getmpcost(lifeform_t *lf, enum OBTYPE oid);
enum SKILL getschoolskill(enum SPELLSCHOOL ss);
char *getspellcosttext(lifeform_t *lf, enum OBTYPE spellid, int power, char *buf);
int getspellduration(int min,int max,int blessed);
int getspelllevel(enum OBTYPE spellid);
int getspellmaxpower(enum OBTYPE spellid);

24
text.c
View File

@ -24,6 +24,7 @@ char *capitalise(char *text) {
return text;
}
// capitalise all words
char *capitaliseall(char *text) {
if (strlen(text) > 0) {
char *p;
@ -128,6 +129,19 @@ char *getpossessive(char *text) {
return "'s";
}
char *getdrunktext(flag_t *drunkflag) {
int bracket;
bracket = (drunkflag->lifetime / DRUNKTIME) + 1;
if (bracket == 1) {
return "tipsy";
} else if (bracket == 2) {
return "drunk";
} else {
return "very drunk";
}
return "??drunk??";
}
char *getsizetext(enum LFSIZE sz) {
switch (sz) {
case SZ_ENORMOUS:
@ -289,6 +303,16 @@ char *makeplural(char *text) {
return newtext;
}
char *makeuppercase(char *text) {
if (strlen(text) > 0) {
char *p;
for (p = text ; *p; p++) {
*p = toupper(*p);
}
}
return text;
}
int needses(char *text) {
if (text[strlen(text)-1] == 's') {
return B_TRUE;

2
text.h
View File

@ -7,12 +7,14 @@ char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dic
char *getattrabbrev(enum ATTRIB att);
char *getattrname(enum ATTRIB att);
char *getpossessive(char *text);
char *getdrunktext(flag_t *drunkflag);
char *getsizetext(enum LFSIZE sz);
char *gettimetext(char *retbuf);
char *gettimetextfuzzy(char *retbuf, int wantpm);
char *getweighttext(float weight, char *buf);
int isvowel(char c);
char *makeplural(char *text);
char *makeuppercase(char *text);
int needses(char *text);
char *noprefix(char *obname);
char *numtotext(int num, char *buf);