* [+] calcxp

- [+] more low power rings
- [+] don't think book names are being randomized - always 'azure'
- [+] charm moidifications
- [+] possession modifications
- [+] troglodyte being made with 180180108180180 mp!!
* [+] gain skills on level up for some jobs
- [+] only magic/blessed weapons can hit noncorporeal things.
- [+] monsters shouldn't walk into walls to attack things there.
- [+] The skeleton slams you with a boulder.--More--Innate Attack:
      boulder . was a bug in HASATTACK
- [+] no polymorphing into undead.
- [+] missiles shoudl always miss noncorporeal things!
- [+] need OFFMAP as well as WALLINWAY
- [+] can't possess undead
- [+] less charges in wands
- [+] when a thrown potion misses, "xx is destroyed" rather than "xx
      shatters!"
- [+] instead of "act:slow mv: slow", just "slow"
- [+] sprinting:  "you are exhausted" isn't triggering statdirty
- [+] On status, use 'v.fast' 'ex.fast' usbtead if "Very" etc
- [+] allies shouldn't attack peaceful things.
- [+] make fleeing lfs use stairs
- [+] undead can't start with blessed objects.
- [+] undead can't touch blessed objects
* [+] GHOST
* [+] PET code
- [+] can't trade items if your ally has NOPACK
- [+] make sure shared xp is working
* [+] firstaid skill shows extra mosnter hp info
* [+] more low power wands - at the moment it's always light or pwoer
- [+] pets: say 'your xxx' instead of 'the xxx'
* [+] pets: dancing weapons should be pets
- [+] need f_allyof as well so that allies will stay close.
    - [+] difference is that allies aren't called "your"
    - [+] AND no alignment penalty for attacking allies?
- [+] in lfstats, move physical stuff BACK to first page!!!
- [+] remove ally/pet flag when you die
* [+] pirate job
* [+] let firearms go into primary hand. test with PIRATE.
- [+] when fighting with a non-weapon: "you whack the xxx with xxx"
- [+] add specific attack verbs to weapons
    - [+] F_ATTACKVERB, dampct between v0 and v1, "stabs"
- [+] make showlfarmour() use colours
This commit is contained in:
Rob Pearce 2011-04-11 05:05:45 +00:00
parent 975d3c6e4f
commit c32f93294c
17 changed files with 2273 additions and 991 deletions

56
ai.c
View File

@ -67,6 +67,11 @@ 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) {
@ -278,6 +283,7 @@ void aimove(lifeform_t *lf) {
int icanattack = B_FALSE;
object_t *curgun,*bestgun;
flag_t *f;
flag_t *mf;
//flag_t *nextf;
// lifeform_t *fleefrom = NULL;
lifeform_t *target;
@ -403,14 +409,11 @@ void aimove(lifeform_t *lf) {
goingtomove = B_TRUE;
// drink boost potions
if (!useitemwithflag(lf, F_AIBOOSTITEM)) {
return;
}
if (goingtomove && (getcelldist(lf->cell, target->cell) == 1)) {
}
@ -688,7 +691,8 @@ void aimove(lifeform_t *lf) {
// cell exists and we can see it?
if (c && c->lf && (c->lf != lf) && cansee(lf, c->lf)) {
// player there?
if (!isplayer(c->lf)) {
//if (!isplayer(c->lf) && !ispeaceful(c->lf)) {
if (areenemies(lf, c->lf)) {
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
// target them!
addtempflag(lf->flags, F_TARGET, c->lf->id, c->x, c->y, NULL, AI_FOLLOWTIME);
@ -719,7 +723,7 @@ void aimove(lifeform_t *lf) {
}
// need to train skills?
if (lf->skillpoints || lfhasflag(lf, F_STATGAINREADY)) {
if (lf->skillpoints || getattpoints(lf)) {
if (canrest(lf)) {
// special case - monsters don't need to actually rest to gain
// skills, although they DO still need to wait until the player
@ -729,9 +733,51 @@ 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)) {
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
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 }");
if (movetowards(lf, master->cell, DT_ORTH)) {
// failed
if (db) dblog(".oO { failed. moving randomly }");
dorandommove(lf, B_NOBADMOVES);
return;
} else {
// success
if (db) dblog(".oO { success. }");
}
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);
} 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);
return;
}
// if we get this far, just wait
rest(lf, B_TRUE);

137
attack.c
View File

@ -108,9 +108,11 @@ int attackcell(lifeform_t *lf, cell_t *c) {
} attacktype = AT_NONE;
void *attacktarget;
int nweps = 0;
int innateattacks = 0;
int i;
int attacktime;
int gotweapon = B_FALSE;
int maxattacks = ALL;
// anyone there? if so just attack.
if (c->lf) {
@ -176,6 +178,7 @@ int attackcell(lifeform_t *lf, cell_t *c) {
validwep[nweps] = B_TRUE;
damflag[nweps] = f;
nweps++;
innateattacks++;
}
}
}
@ -184,35 +187,58 @@ int attackcell(lifeform_t *lf, cell_t *c) {
attacktime = getattackspeed(lf);
taketime(lf, attacktime);
if (nweps <= 0) {
if (isplayer(lf)) {
msg("You cannot attack!");
}
return B_TRUE;
}
maxattacks = nweps; // ie. all
f = lfhasflag(lf, F_MAXATTACKS);
if (f) {
maxattacks = f->val[0];
} else {
maxattacks = innateattacks;
}
/*
// if we have a weapon, this takes the place of one of our
// attacks.
// for monsters, pick which one to replace randomly.
// for players, never pick the weapon which one to replace randomly.
if (gotweapon && (nweps > 1)) {
// for players, never pick the weapon to replace randomly.
if (gotweapon && (nweps >= 2)) {
if (isplayer(lf)) {
validwep[rnd(1,nweps-1)] = B_FALSE;
} else {
validwep[rnd(0,nweps-1)] = B_FALSE;
}
}
*/
// # valid attacks higher than our allowed attacks?
f = lfhasflag(lf, F_MAXATTACKS);
if (f) {
int max = f->val[0];
if (nweps > maxattacks) {
int nvalid;
int first;
// player never invalidates their weapon
if (isplayer(lf) && gotweapon) {
first = 1;
} else {
first = 0;
}
nvalid = 0;
for (i = 0; i < nweps; i++) {
if (validwep[i]) nvalid++;
}
while (nvalid > max) {
while (nvalid > maxattacks) {
int sel;
// mark a random one as invalid
sel = rnd(0,nweps-1);
sel = rnd(first,nweps-1);
while (!validwep[sel]) {
sel = rnd(0,nweps-1);
sel = rnd(first,nweps-1);
}
validwep[sel] = B_FALSE;
@ -227,7 +253,9 @@ int attackcell(lifeform_t *lf, cell_t *c) {
for (i = 0; i < nweps; i++) {
if (validwep[i]) {
if (attacktype == AT_LF) {
if (!isdead((lifeform_t *)attacktarget)) {
attacklf(lf, (lifeform_t *)attacktarget, wep[i], damflag[i]);
}
} else if (attacktype == AT_OB) {
attackob(lf, (object_t *)attacktarget, wep[i], damflag[i]);
}
@ -299,7 +327,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// did you hit?
ndam = 0;
if (rolltohit(lf, victim, wep, &critical)) {
int n;
hit = B_TRUE;
if (aidb) dblog(".oO { i hit! }");
@ -331,8 +358,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// determine base damage
// determine damage
dam[0] = 0;
for (n = 0; n < critical+1; n++) {
dam[0] = getdamroll(wep, victim, damflag);
if (critical) {
// critical hit means an extra damage roll.
dam[0] += getdamroll(wep, victim, damflag);
}
if (aidb) dblog("rolled dam[%d] = %d",0,dam[0]);
@ -451,7 +479,17 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// announce it
if (isplayer(lf)) {
char extradambuf[BUFLEN];
char withwep[BUFLEN];
char *verb;
strcpy(extradambuf, "");
if (wep && !ismeleeweapon(wep)) {
sprintf(withwep, " with %s", wepname);
} else {
strcpy(withwep, "");
}
if (dam[i] == 0) {
strcpy(extradambuf, " but do no damage");
} else if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) {
@ -463,13 +501,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (backstab && (i == 0)) {
verb = strdup("backstab");
} else if (fatal) {
verb = getkillverb(victim, damtype[i], dam[i], victim->maxhp);
verb = getkillverb(victim, wep, damtype[i], dam[i], victim->maxhp);
} else {
verb = getattackverb(lf, wep, damtype[i], dam[i], victim->maxhp);
}
warn("You %s %s%s%s",
warn("You %s %s%s%s%s",
verb,
victimname, extradambuf,
victimname, withwep,extradambuf,
(fatal || backstab) ? "!" : ".");
if (fatal && strstr(verb, "behead")) {
@ -843,9 +881,24 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
if (wep) {
flag_t *f;
f = hasflag(wep->flags, F_ATTACKVERB);
if (f) {
for (f = wep->flags->first ; f ; f = f->next) {
if (f->id == F_ATTACKVERB) {
if ((f->val[0] == NA) && (f->val[1] == NA)) {
return f->text;
} else if (f->val[0]) {
if (pct >= f->val[0]) {
if (f->val[1] == NA) {
return f->text;
} else if (pct <= f->val[1]) {
return f->text;
}
}
} else if (f->val[1]) {
if (pct <= f->val[1]) {
return f->text;
}
}
}
}
}
@ -881,20 +934,6 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
return "savage";
}
}
} else if (damtype == DT_CLAW) {
if (pct <= 5) {
return "scratch";
} else if (pct <= 15) {
return "claw";
} else if (pct <= 30) {
return "tear";
} else if (pct <= 40) {
return "rake";
} else if (pct <= 50) {
return "gouge";
} else {
return "eviscerate";
}
} else if (damtype == DT_CHOP) {
if (pct <= 5) {
return "hit";
@ -1071,7 +1110,7 @@ int getextradamwep(object_t *wep, int *dam, enum DAMTYPE *damtype, int *ndam) {
return *dam;
}
char *getkillverb(lifeform_t *victim, enum DAMTYPE damtype, int dam, int maxhp) {
char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp) {
float pct;
pct = (int)(((float) dam / (float) maxhp) * 100.0);
@ -1079,6 +1118,29 @@ char *getkillverb(lifeform_t *victim, enum DAMTYPE damtype, int dam, int maxhp)
return "defeat";
}
if (wep) {
flag_t *f;
for (f = wep->flags->first ; f ; f = f->next) {
if (f->id == F_KILLVERB) {
if ((f->val[0] == NA) && (f->val[1] == NA)) {
return f->text;
} else if (f->val[0]) {
if (pct >= f->val[0]) {
if (f->val[1] == NA) {
return f->text;
} else if (pct <= f->val[1]) {
return f->text;
}
}
} else if (f->val[1]) {
if (pct <= f->val[1]) {
return f->text;
}
}
}
}
}
if ((damtype == DT_BASH) && lfhasflag(victim, F_FROZEN)) {
return "shatter";
}
@ -1095,7 +1157,6 @@ char *getkillverb(lifeform_t *victim, enum DAMTYPE damtype, int dam, int maxhp)
if (damtype == DT_PIERCE) return "impale";
if (damtype == DT_BASH) return "flatten";
if (damtype == DT_BITE) return "gore";
if (damtype == DT_CLAW) return "disembowel";
if (damtype == DT_SLASH) {
if (lfhasflagval(victim, F_NOBODYPART, BP_HEAD, NA, NA, NULL)) {
return "bisect";
@ -1341,7 +1402,6 @@ int isphysicaldam(enum DAMTYPE damtype) {
case DT_BASH:
case DT_BITE:
case DT_CHOP:
case DT_CLAW:
case DT_COLD:
case DT_CRUSH:
case DT_ELECTRIC:
@ -1375,6 +1435,17 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
ev = getevasion(victim);
acc -= ev;
// special case
if (lfhasflag(victim, F_NONCORPOREAL) &&
!lfhasflag(lf, F_NONCORPOREAL) ) {
// using a magical or blessed weapon?
if (wep && (ismagical(wep) || isblessed(wep)) ) {
} else {
return B_FALSE; // automatic miss
}
}
// size difference
szlf = getlfsize(lf);
szvictim = getlfsize(victim);

View File

@ -12,7 +12,7 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
enum DAMTYPE getdamtype(object_t *wep);
int getextradamlf(lifeform_t *lf, int *dam, enum DAMTYPE *damtype, int *ndam);
int getextradamwep(object_t *wep, int *dam, enum DAMTYPE *damtype, int *ndam);
char *getkillverb(lifeform_t *victim, enum DAMTYPE damtype, int dam, int maxhp);
char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp);
void getdamrange(flag_t *f, int *min, int *max);
//void getdamrangeunarmed(flag_t *f, int *min, int *max);
float getdamreducepct(float armourrating);

99
defs.h
View File

@ -320,6 +320,7 @@ enum SPELLSCHOOL {
SS_AIR,
SS_DEATH,
SS_DIVINATION,
SS_EARTH,
SS_FIRE,
SS_ICE,
SS_GRAVITY,
@ -392,32 +393,31 @@ enum DAMTYPE {
DT_SLASH = 1,
DT_FIRE = 2,
DT_COLD = 3,
DT_CLAW = 4,
DT_BASH = 5,
DT_BITE = 6,
DT_CHOP = 7,
DT_PROJECTILE = 8,
DT_HOLY = 9,
DT_WATER = 10,
DT_ACID = 11,
DT_MELT = 12,
DT_DIRECT = 13, // eg. from f_obhpdrain flag
DT_ELECTRIC = 14,
DT_EXPLOSIVE = 15,
DT_DECAY = 16,
DT_MAGIC = 17,
DT_TOUCH = 18,
DT_POISONGAS = 19,
DT_UNARMED = 20,
DT_LIGHT = 21,
DT_CRUSH = 22,
DT_FALL = 23,
DT_PETRIFY = 24,
DT_POISON = 25,
DT_NECROTIC = 26,
DT_NONE = 27, // for direclty dealt damage, not really any type
DT_BASH = 4,
DT_BITE = 5,
DT_CHOP = 6,
DT_PROJECTILE = 7,
DT_HOLY = 8,
DT_WATER = 9,
DT_ACID = 10,
DT_MELT = 11,
DT_DIRECT = 12, // eg. from f_obhpdrain flag
DT_ELECTRIC = 13,
DT_EXPLOSIVE = 14,
DT_DECAY = 15,
DT_MAGIC = 16,
DT_TOUCH = 17,
DT_POISONGAS = 18,
DT_UNARMED = 19,
DT_LIGHT = 20,
DT_CRUSH = 21,
DT_FALL = 22,
DT_PETRIFY = 23,
DT_POISON = 24,
DT_NECROTIC = 25,
DT_NONE = 26, // for direclty dealt damage, not really any type
};
#define MAXDAMTYPE 28
#define MAXDAMTYPE 27
// Object Classes
enum OBCLASS {
@ -511,6 +511,8 @@ enum RACE {
R_ANT,
R_ANTS,
R_BAT,
R_HAWK,
R_HAWKYOUNG,
R_HAWKBLOOD,
R_HAWKFROST,
R_NEWT,
@ -524,6 +526,7 @@ enum RACE {
R_GIANTBLOWFLY,
// undead
R_GHAST,
R_GHOST,
R_GHOUL,
R_SKELETON,
R_ZOMBIE,
@ -539,6 +542,7 @@ enum JOB {
J_ALLOMANCER,
J_BARBARIAN,
J_COMMANDO,
J_PIRATE,
J_PLUMBER,
J_PRINCE,
J_WIZARD,
@ -740,6 +744,9 @@ enum OBTYPE {
// -- elemental - ice
OT_SB_CONECOLD,
OT_SB_FREEZEOB,
OT_SB_COLDBURST,
// -- elemental - earth
OT_SB_DIG,
// -- gravity
OT_SB_GRAVLOWER,
OT_SB_GRAVBOOST,
@ -817,6 +824,8 @@ enum OBTYPE {
OT_S_COLDBURST,
OT_S_CONECOLD,
OT_S_FREEZEOB,
// -- elemental - earth
OT_S_DIG,
// -- gravity
OT_S_GRAVLOWER,
OT_S_GRAVBOOST,
@ -885,6 +894,7 @@ enum OBTYPE {
// wands
OT_WAND_COLD,
OT_WAND_DETONATION,
OT_WAND_DIGGING,
OT_WAND_DISPERSAL,
OT_WAND_FIRE,
OT_WAND_FIREBALL,
@ -989,6 +999,7 @@ enum OBTYPE {
OT_GAUNTLETS,
// armour - head
OT_SUNHAT,
OT_PIRATEHAT,
OT_CAP,
OT_HELM,
OT_GASMASK,
@ -997,6 +1008,7 @@ enum OBTYPE {
OT_HELMFOOTBALL,
// armour - eyes
OT_SUNGLASSES,
OT_EYEPATCH,
// armour - shields
OT_BUCKLER,
OT_SHIELD,
@ -1020,9 +1032,10 @@ enum OBTYPE {
OT_RING_RESISTMAG,
OT_RING_SIGHT,
OT_RING_WOUNDING,
// animal weapons
// innate / animal weapons
OT_CLAWS,
OT_FISTS,
OT_HOOKHAND, // for pirate
OT_STING,
OT_TAIL,
OT_TEETH,
@ -1063,6 +1076,7 @@ enum OBTYPE {
OT_LONGSWORD,
OT_ORNSWORD,
OT_SCIMITAR,
OT_CUTLASS,
// polearms
OT_GLAIVE,
OT_GUISARME,
@ -1244,7 +1258,8 @@ enum FLAG {
F_LOCKED,// door is locked
F_JAMMED, // is this door jammed?
// stairs / teleporters / portals
F_CLIMBABLE, // this is a stiarcase, v0 = up/down
F_CLIMBABLE, // this is a stiarcase, v0 = up/down/in
// also use this for portals
//F_STAIRDIR//, // val0 = direcion
F_OPPOSITESTAIRS, // val0 = opposite kind of stairs
F_MAPLINK, // val0 = map to link to.
@ -1270,6 +1285,13 @@ enum FLAG {
F_SHODDY, // weps do less damage, armour protects less.
// weapon flags
F_ATTACKVERB, // text=verb for attacking. ie. "hit" "slash" "sting" etc
// if v0/v1 are set, only use this text if dam pct is
// between v0 and v1.
// should always be singular
F_KILLVERB, // text=verb for a fatal attacking. ie. "kill" "behead"
// if v0/v1 are set, only use this text if dam pct is
// between v0 and v1.
// should always be singular
F_OBATTACKDELAY, // how long weapon takes to attack
F_USESSKILL, // weapon needs skill sk_v0
F_CANHAVEOBMOD, // weapon can have obmod om_v0 applied
@ -1355,6 +1377,8 @@ enum FLAG {
F_ACCURACYMOD, // modify your accuracy by val0
F_SHIELDPENALTY, // lower your accuracy by val0 due to a cumbersome
// shield
F_LEVRACE, // at level v0, this race is promoted to race v1
// must apply this to the BASE race.
F_ATTRMOD, // modify attribute val0 by val1. ie. 0=A_STR,1=-3
F_ATTRSET, // forces attribute val0 to be val1. ie. 0=A_STR,1=18
F_SIZE, // val0 = lf size (enum LFSIZE)
@ -1373,6 +1397,8 @@ enum FLAG {
F_STARTJOB, // val0 = %chance of starting with it, v1 = jobid
F_STARTATT, // val0 = A_xxx, val0 = start bracket (ie. IQ_GENIUS)
F_CORPSETYPE, // text field specifies what corpse obtype to leave
F_MYCORPSE, // text field contains obid of my corpse.
// (for ghosts)
F_NOCORPSE, // monster's body crumbles to dust after death
F_LFSUFFIX, // text = suffix. eg. "skeleton"
F_VISRANGE, // how far you can see (in the light)
@ -1388,8 +1414,18 @@ enum FLAG {
F_SWOOPRANGE, // v0 = how far a flying creature can swoop
// MONSTER AI FLAGS
F_XPVAL, // force xp val for killing this lf to v0
// ...OR... monsters with this abil are worth
// ...OR if applied to an ability...
// monsters with this abil 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
@ -1513,6 +1549,7 @@ enum FLAG {
F_REGENERATES, // regenerate HP at val0 per turn
F_RESISTMAG, // immunity to magic effects. v0=amt (1-20)
F_MPREGEN, // regenerate MP at val0 per turn
F_RISEASGHOST, // become a ghost when you die.
F_SEEINDARK, // nightvis range is val0
F_SEEINVIS, // can see invisible things
F_SEEWITHOUTEYES, // doesn't need eyes to see
@ -1557,6 +1594,7 @@ enum FLAG {
F_HUNGER, // val0 = hunger, higher = hungrier
// for jobs
F_HASPET, // this job starts with a pet of race f->text
F_IFPCT, // only add the NEXT job flag if rnd(1,100) <= v0.
F_ELSE,
F_IFPLAYER,
@ -1710,6 +1748,10 @@ enum ERROR {
E_LOWIQ = 42,
E_LOWSTR = 43,
E_WONT = 44,
E_OFFMAP = 45,
// charm failure reasons
// LOWIQ = 42
E_UNDEAD = 46,
};
@ -1949,6 +1991,7 @@ enum SKILL {
SK_SS_AIR,
SK_SS_DEATH,
SK_SS_DIVINATION,
SK_SS_EARTH,
SK_SS_FIRE,
SK_SS_ICE,
SK_SS_GRAVITY,

4
flag.c
View File

@ -430,7 +430,7 @@ void timeeffectsflag(flag_t *f, int howlong) {
break;
}
}
} else if (f->lifetime == 5) {
} else if (f->lifetime == 3) {
if (isplayer(f->pile->owner)) {
switch (f->id) {
case F_SPRINTING:
@ -514,6 +514,8 @@ void timeeffectsflag(flag_t *f, int howlong) {
getlfname(who, lfname);
msg("%s looks exhausted.",lfname);
}
needredraw = B_TRUE;
statdirty = B_TRUE;
}
}
}

303
io.c
View File

@ -453,7 +453,13 @@ 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");
} else {
strcat(extrainfo, "friendly");
}
}
break;
case AL_PEACEFUL:
@ -473,7 +479,7 @@ cell_t *askcoords(char *prompt, int targettype) {
strcat(extrainfo, "asleep");
}
// hp
if (isgenius(player)) {
if (isgenius(player) || (getseenlfconditioncutoff(player) == C_HEALTHY) ) {
char buf2[BUFLEN];
// show actual hp
sprintf(buf2, "hp %d/%d",c->lf->hp, c->lf->maxhp);
@ -490,7 +496,7 @@ cell_t *askcoords(char *prompt, int targettype) {
}
wep = getweapon(c->lf);
if (wep) {
if (wep && (c->lf->race->id != R_DANCINGWEAPON)) {
object_t *secwep;
char obname[BUFLEN];
char buf2[BUFLEN];
@ -785,7 +791,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
}
strcat(buf, ".");
*/
msg(buf, ot->name);
msg(buf, ot->name); more();
donesomething = B_TRUE;
}
}
@ -1002,6 +1008,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
}
break;
case F_RISEASGHOST:
if (isplayer(lf)) { // don't know if monsters get it
msg("You will rise as a ghost after death.");
donesomething = B_TRUE;
}
break;
case F_SEEINVIS:
if (isplayer(lf)) { // don't know if monsters get it
msg("You vision seems enhanced.");
@ -1089,6 +1101,9 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
lifeform_t *lf2;
int donesomething = B_FALSE;
if (!lf->born) {
return B_FALSE;
}
if (lf->race->id == R_DANCINGWEAPON) {
return B_FALSE;
}
@ -1390,6 +1405,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
}
break;
*/
case F_RISEASGHOST:
if (isplayer(lf)) { // don't know if monsters get it
msg("You will no longer rise as a ghost after death.");
donesomething = B_TRUE;
}
break;
case F_SEEINVIS:
if (isplayer(lf)) { // don't know if monsters get it
msg("You vision returns to normal.");
@ -1640,25 +1661,14 @@ void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int fi
sprintf(buf, "%c %c - %s", selchar, useobletters ? mylist[i]->letter : myletters[i],
obname);
if (mylist[i]->blessknown) {
if (iscursed(mylist[i])) {
setcol(win, C_RED);
} else if (isblessed(mylist[i])) {
setcol(win, C_CYAN);
}
}
setobcolour(win, mylist[i]);
getobextrainfo(mylist[i], infobuf);
getobequipinfo(mylist[i], equipbuf);
mvwprintw(win, *y, 0, "%s%s", buf, infobuf);
if (mylist[i]->blessknown) {
if (iscursed(mylist[i])) {
unsetcol(win, C_RED);
} else if (isblessed(mylist[i])) {
unsetcol(win, C_CYAN);
}
}
unsetobcolour(win, mylist[i]);
if (strlen(equipbuf)) {
setcol(win, C_BROWN);
@ -2643,6 +2653,9 @@ void describeob(object_t *o) {
mvwprintw(mainwin, y, 0, "%s grants you %s immunity to magic.", buf,
(f->val[0] >= 10) ? "strong" : "minor"); y++;
break;
case F_RISEASGHOST:
mvwprintw(mainwin, y, 0, "%s cause you to rise as a ghost after death.", buf); y++;
break;
case F_SEEINVIS:
mvwprintw(mainwin, y, 0, "%s allows you to see invisible things.", buf); y++;
break;
@ -2899,7 +2912,7 @@ void docomms(void) {
if (!isadjacent(lf->cell, player->cell)) {
addchoice(&prompt, 'c', "Come here", NULL, NULL);
}
if (isadjacent(lf->cell, player->cell)) {
if (isadjacent(lf->cell, player->cell) && !lfhasflag(lf, F_NOPACK)) {
addchoice(&prompt, 't', "Trade items with me", NULL, NULL);
}
} else {
@ -5498,9 +5511,26 @@ void drawstatus(void) {
wprintw(statwin, " Immobile");
unsetcol(statwin, C_RED);
} else {
char actbuf[BUFLEN],movebuf[BUFLEN];
getspeednameshort(getactspeed(player), actbuf);
getspeednameshort(getmovespeed(player), movebuf);
// both action and movement speed the same, and not "normal" ?
if (!strcmp(actbuf, movebuf) && strcmp(actbuf, "normal")) {
// show combiner action/movement speed
enum COLOUR col;
if (getactspeed(player) < SP_NORMAL) {
col = C_GREEN;
} else {
col = C_RED;
}
setcol(statwin, col);
capitaliseall(actbuf);
wprintw(statwin, " %s", actbuf);
unsetcol(statwin, col);
} else {
// show action/movement speed seperately
// show player action speed
getspeedname(getactspeed(player), buf2);
if (strcmp(buf2, "normal")) {
if (strcmp(actbuf, "normal")) {
enum COLOUR col;
if (getactspeed(player) < SP_NORMAL) {
col = C_GREEN;
@ -5509,13 +5539,12 @@ void drawstatus(void) {
}
setcol(statwin, col);
wprintw(statwin, " Act:");
capitaliseall(buf2);
wprintw(statwin, "%s", buf2);
capitaliseall(actbuf);
wprintw(statwin, "%s", actbuf);
unsetcol(statwin, col);
}
// show player movement speed
getspeedname(getmovespeed(player), buf2);
if (strcmp(buf2, "normal")) {
if (strcmp(movebuf, "normal")) {
enum COLOUR col;
if (getmovespeed(player) < SP_NORMAL) {
col = C_GREEN;
@ -5524,11 +5553,12 @@ void drawstatus(void) {
}
setcol(statwin, col);
wprintw(statwin, " Mv:");
capitaliseall(buf2);
wprintw(statwin, "%s", buf2);
capitaliseall(movebuf);
wprintw(statwin, "%s", movebuf);
unsetcol(statwin, col);
}
}
}
// burdened somehow?
switch (isburdened(player)) {
@ -5778,6 +5808,7 @@ void setcol(WINDOW *win, enum COLOUR col) {
}
wattron(win, COLOR_PAIR(col));
}
void unsetcol(WINDOW *win, enum COLOUR col) {
wattroff(win, COLOR_PAIR(col));
if (needsbold(col)) {
@ -5785,6 +5816,28 @@ void unsetcol(WINDOW *win, enum COLOUR col) {
}
}
void setobcolour(WINDOW *win, object_t *o) {
if (!o) return;
if (o->blessknown) {
if (iscursed(o)) {
setcol(win, C_RED);
} else if (isblessed(o)) {
setcol(win, C_CYAN);
}
}
}
void unsetobcolour(WINDOW *win, object_t *o) {
if (!o) return;
if (o->blessknown) {
if (iscursed(o)) {
unsetcol(win, C_RED);
} else if (isblessed(o)) {
unsetcol(win, C_CYAN);
}
}
}
void showlfarmour(lifeform_t *lf) {
enum BODYPART bp;
object_t *o;
@ -5799,19 +5852,30 @@ void showlfarmour(lifeform_t *lf) {
}
y = 2;
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
char rhs[BUFLEN];
// default
sprintf(rhs, "-");
if (!lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
sprintf(buf, "%15s:%3s",getbodypartname(bp), " ");
o = hasobwithflagval(lf->pack, F_EQUIPPED, bp, NA, NA, NULL);
if (o) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
strcat(buf, obname);
strcpy(rhs, obname);
} else {
strcat(buf, "-");
strcpy(rhs, "-");
}
mvwprintw(mainwin, y, 0, "%s", buf);
setobcolour(mainwin, o);
wprintw(mainwin, "%s", rhs);
unsetobcolour(mainwin, o);
y++;
}
}
y = getmaxy(mainwin);
centre(mainwin, y-1, "[Press any key]");
@ -5939,7 +6003,7 @@ void showlfstats(lifeform_t *lf, int showall) {
if (showall) {
if (showall || (getseenlfconditioncutoff(player) == C_HEALTHY)) {
mvwprintw(mainwin, y, 0, ftext, "Hit Points");
wprintw(mainwin, "%d / %d", lf->hp , lf->maxhp); y++;
} else {
@ -6256,7 +6320,7 @@ void showlfstats(lifeform_t *lf, int showall) {
capitalise(buf);
mvwprintw(mainwin, y2, x2, ftext, "Hunger");
wprintw(mainwin, "%-14s", buf); y++;
wprintw(mainwin, "%-14s", buf); y2++;
/*
if (showall) {
wprintw(mainwin, "%-14s (%d)", buf, f->val[0]); y++;
@ -6266,11 +6330,87 @@ void showlfstats(lifeform_t *lf, int showall) {
*/
}
}
y++; // skip line
// back to first column
y++;
// obvious physical effects here.
f = lfhasknownflag(lf, F_ASLEEP);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s sleeping.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasknownflag(lf, F_FLYING);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s flying.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasflag(lf, F_FROZEN);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s been turned to ice, and %s slowly melting.", you(lf), isplayer(lf) ? "have" : "has",
isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasknownflag(lf, F_GRABBEDBY);
if (f && (f->known)) {
lifeform_t *lf2;
char grabbername[BUFLEN];
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, grabbername);
} else {
strcpy(grabbername, "something");
}
sprintf(buf,"%s %s being held by %s.",you(lf), isplayer(lf) ? "are" : "is", grabbername);
mvwprintw(mainwin, y, 0, buf);
y++;
}
f = lfhasknownflag(lf, F_GRABBING);
if (f && (f->known)) {
lifeform_t *lf2;
char grabeename[BUFLEN];
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, grabeename);
} else {
strcpy(grabeename, "something");
}
sprintf(buf,"%s %s holding on to %s.",you(lf), isplayer(lf) ? "are" : "is", grabeename);
mvwprintw(mainwin, y, 0, buf);
y++;
}
f = lfhasknownflag(lf, F_INVISIBLE);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s invisible.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasknownflag(lf, F_LEVITATING);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s levitating.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasflag(lf, F_NONCORPOREAL);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s noncorporeal and can walk through walls.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasflag(lf, F_PRODUCESLIGHT);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s produce%s light.", you(lf), isplayer(lf) ? "" : "s");
y++;
}
f = lfhasknownflag(lf, F_SPRINTING);
if (f) {
if (f->val[0]) {
mvwprintw(mainwin, y, 0, "%s %s sprinting.", you(lf), isplayer(lf) ? "are" : "is");
y++;
} else {
mvwprintw(mainwin, y, 0, "%s %s exhausted.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
}
f = lfhasknownflag(lf, F_UNDEAD);
@ -6298,7 +6438,7 @@ void showlfstats(lifeform_t *lf, int showall) {
}
nmissingbp = 0;
for (bp = BP_RIGHTHAND; bp < MAXBODYPARTS; bp++) {
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
if (lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
if (bp == BP_RIGHTHAND) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
@ -6306,6 +6446,13 @@ void showlfstats(lifeform_t *lf, int showall) {
nmissingbp++;
}
} else if (bp == BP_LEFTHAND) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL) &&
!lfhasflagval(lf, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL)
) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else if (bp == BP_SECWEAPON) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
missingbp[nmissingbp] = bp;
nmissingbp++;
@ -6318,7 +6465,7 @@ void showlfstats(lifeform_t *lf, int showall) {
}
if (nmissingbp) {
sprintf(buf, "%s have no %s",you(lf),getbodypartname(missingbp[0]));
sprintf(buf, "%s %s no %s",you(lf), isplayer(lf) ? "have" : "has", getbodypartname(missingbp[0]));
if (nmissingbp > 1) {
// construct list of missing body parts
for (i = 1; i < nmissingbp ; i++) {
@ -6336,11 +6483,6 @@ void showlfstats(lifeform_t *lf, int showall) {
y++;
}
if (eyesshaded(lf)) {
mvwprintw(mainwin, y, 0, "%s eyes are shaded.", your(lf), buf);
y++;
}
// fleeing?
if (showall) {
for (f = lf->flags->first ; f ; f = f->next) {
@ -6614,86 +6756,16 @@ void showlfstats(lifeform_t *lf, int showall) {
}
// obvious physical effects first.
f = lfhasknownflag(lf, F_ASLEEP);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s sleeping.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasknownflag(lf, F_BEINGSTONED);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s being turning to stone.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasknownflag(lf, F_FLYING);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s flying.", you(lf), isplayer(lf) ? "are" : "is");
if (eyesshaded(lf)) {
mvwprintw(mainwin, y, 0, "%s eyes are shaded.", your(lf), buf);
y++;
}
f = lfhasflag(lf, F_FROZEN);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s been turned to ice, and %s slowly melting.", you(lf), isplayer(lf) ? "have" : "has",
isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasknownflag(lf, F_GRABBEDBY);
if (f && (f->known)) {
lifeform_t *lf2;
char grabbername[BUFLEN];
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, grabbername);
} else {
strcpy(grabbername, "something");
}
sprintf(buf,"%s %s being held by %s.",you(lf), isplayer(lf) ? "are" : "is", grabbername);
mvwprintw(mainwin, y, 0, buf);
y++;
}
f = lfhasknownflag(lf, F_GRABBING);
if (f && (f->known)) {
lifeform_t *lf2;
char grabeename[BUFLEN];
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, grabeename);
} else {
strcpy(grabeename, "something");
}
sprintf(buf,"%s %s holding on to %s.",you(lf), isplayer(lf) ? "are" : "is", grabeename);
mvwprintw(mainwin, y, 0, buf);
y++;
}
f = lfhasknownflag(lf, F_INVISIBLE);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s invisible.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasknownflag(lf, F_LEVITATING);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s levitating.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasflag(lf, F_NONCORPOREAL);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s noncorporeal and can walk through walls.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
f = lfhasflag(lf, F_PRODUCESLIGHT);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s produce%s light.", you(lf), isplayer(lf) ? "" : "s");
y++;
}
f = lfhasknownflag(lf, F_SPRINTING);
if (f) {
if (f->val[0]) {
mvwprintw(mainwin, y, 0, "%s %s sprinting.", you(lf), isplayer(lf) ? "are" : "is");
y++;
} else {
mvwprintw(mainwin, y, 0, "%s %s exhausted.", you(lf), isplayer(lf) ? "are" : "is");
y++;
}
}
@ -6992,6 +7064,12 @@ void showlfstats(lifeform_t *lf, int showall) {
y++;
}
f = lfhasflag(lf, F_RISEASGHOST);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s will rise as a ghost after death.", you(lf));
y++;
}
f = lfhasflag(lf, F_STABILITY);
if (f && (f->known)) {
@ -7127,6 +7205,3 @@ void tombstone(lifeform_t *lf) {
endwin();
}

2
io.h
View File

@ -93,6 +93,8 @@ void redraw(void);
int savequit(void);
void setcol(WINDOW *win, enum COLOUR col);
void unsetcol(WINDOW *win, enum COLOUR col);
void setobcolour(WINDOW *win, object_t *o);
void unsetobcolour(WINDOW *win, object_t *o);
void showlfarmour(lifeform_t *lf);
void showlfstats(lifeform_t *lf, int showall);
void tombstone(lifeform_t *lf);

804
lf.c

File diff suppressed because it is too large Load Diff

9
lf.h
View File

@ -21,6 +21,7 @@ int caneat(lifeform_t *lf, object_t *o);
int canhear(lifeform_t *lf, cell_t *c);
int canlearn(lifeform_t *lf, enum SKILL skid);
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);
@ -29,7 +30,9 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where);
int canweild(lifeform_t *lf, object_t *o);
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);
void debug(lifeform_t *lf);
void die(lifeform_t *lf);
void dumplf(void);
void dumpxp(void);
@ -53,6 +56,7 @@ void gainhp(lifeform_t *lf, int amt);
void gainlevel(lifeform_t *lf);
void gainmp(lifeform_t *lf, int amt);
void gainxp(lifeform_t *lf, long amt);
void genxplist(void);
int getactspeed(lifeform_t *lf);
enum ALLEGIENCE getallegiance(lifeform_t *lf);
object_t *getarmour(lifeform_t *lf, enum BODYPART bp);
@ -82,6 +86,7 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep);
enum LFCONDITION getlfcondition(lifeform_t *lf);
int getnightvisrange(lifeform_t *lf);
char *getlfconditionname(enum LFCONDITION cond);
enum LFCONDITION getseenlfconditioncutoff(lifeform_t *lf);
char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer);
glyph_t *getlfglyph(lifeform_t *lf);
enum MATERIAL getlfmaterial(lifeform_t *lf);
@ -111,6 +116,7 @@ race_t *getrandomrace(map_t *map, int forcedepth);
race_t *getreallyrandomrace(void);
enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id);
char *getspeedname(int speed, char *buf);
char *getspeednameshort(int speed, char *buf);
float getstatmod(lifeform_t *lf, enum ATTRIB att);
enum CONBRACKET getconname(int str, char *buf);
enum STRBRACKET getstrname(int str, char *buf);
@ -149,6 +155,7 @@ int isairborne(lifeform_t *lf);
int isbleeding(lifeform_t *lf);
int isblind(lifeform_t *lf);
enum BURDENED isburdened(lifeform_t *lf);
int ischarmable(lifeform_t *lf);
int isdead(lifeform_t *lf);
int isfleeing(lifeform_t *lf);
int isfreebp(lifeform_t *lf, enum BODYPART bp);
@ -198,7 +205,7 @@ 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);
void setguntarget(lifeform_t *lf, lifeform_t *targ);
void setrace(lifeform_t *lf, enum RACE rid);
void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph);
void setlastdam(lifeform_t *lf, char *buf);
//void setlftarget(lifeform_t *lf, lifeform_t *victim);
int shoot(lifeform_t *lf);

1137
log.txt

File diff suppressed because it is too large Load Diff

11
map.c
View File

@ -2093,6 +2093,17 @@ int isadjacent(cell_t *src, cell_t *dst) {
return B_FALSE;
}
int isdark(cell_t *c) {
switch (c->lit) {
case L_PERMDARK:
case L_NOTLIT:
return B_TRUE;
default:
break;
}
return B_FALSE;
}
int isdiggable(cell_t *c) {
switch (c->type->id) {
case CT_WALL: return B_TRUE;

1
map.h
View File

@ -43,6 +43,7 @@ object_t *hasenterableobject(cell_t *c);
lifeform_t *haslf(cell_t *c);
int hasobject(cell_t *c);
int isadjacent(cell_t *src, cell_t *dst);
int isdark(cell_t *c);
int isdiggable(cell_t *c);
int isdoor(object_t *o, int *isopen);
int isempty(cell_t *c);

27
move.c
View File

@ -169,12 +169,15 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
rdata = NULL;
}
if (!cell) {
if (error) *error = E_WALLINWAY;
if (error) *error = E_OFFMAP;
return B_FALSE;
}
if (cell->type->solid) {
// mover is noncorporeal?
if (lf && lfhasflag(lf, F_NONCORPOREAL)) {
// ok
} else if (cell->lf && (cell->lf != lf)) { // someone (else) in the wall?
// ok
} else {
if (error) *error = E_WALLINWAY;
return B_FALSE;
@ -504,6 +507,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher) {
// failed to move
switch (reason) {
case E_WALLINWAY:
case E_OFFMAP:
msg("%s slam%s into a wall!",lfname,isplayer(lf) ? "" : "s");
losehp(lf, rnd(1,6), DT_BASH, pusher, "slamming into a wall");
// stop moving
@ -538,6 +542,8 @@ int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype ) {
}
// IMPORTANT: don't modify lf's flagpile during this code!
// particularly don't remove flags...
void moveeffects(lifeform_t *lf) {
flag_t *f;
@ -558,6 +564,7 @@ void moveeffects(lifeform_t *lf) {
}
losehp(lf, roll(f->text), f->val[0], NULL, "extreme pain");
}
if (isdead(lf)) return;
}
@ -685,7 +692,6 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
if ((gamemode == GM_GAMESTARTED)) {
for (l = newcell->map->lf ; l ; l = l->next) {
if (l != lf) {
// cope with swapping locations with someone!
if (haslos(l, newcell)) {
int dointerrupt = B_FALSE;
@ -700,6 +706,15 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
dointerrupt = B_TRUE;
}
} else {
if (isplayer(lf) && areallies(lf, l)) {
// remember player's last known loc
f = lfhasflag(l, F_PETOF);
if (f) {
f->val[1] = player->cell->x;
f->val[2] = player->cell->y;
}
}
dointerrupt = B_TRUE;
}
if (dointerrupt) {
@ -1239,6 +1254,14 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
int door, dooropen;
reason = errcode;
switch (errcode) {
case E_OFFMAP:
if (isplayer(lf)) {
msg("You can't go any further in that direction.");
} else if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s %ss around randomly.", buf, getmoveverb(lf));
}
break;
case E_WALLINWAY:
if (isplayer(lf)) {
msg("Ouch! You %s into a wall.", getmoveverb(lf));

45
nexus.c
View File

@ -67,6 +67,9 @@ extern int statdirty;
int needredraw = B_TRUE;
int numdraws = 0;
// for xp list debugging
extern race_t **raceposs;
extern int *xpposs;
int main(int argc, char **argv) {
int newworld = B_FALSE;
@ -125,6 +128,7 @@ int main(int argc, char **argv) {
job_t *j = NULL;
char ch;
cell_t *where;
flag_t *f;
// read from input file if required
if (playerfile) {
@ -172,23 +176,50 @@ int main(int argc, char **argv) {
addflag(player->flags, F_NAME, NA, NA, NA, "Anonymous");
}
givejob(player, j->id);
// special case:
if (j->id == J_PIRATE) {
flag_t *f;
f = lfhasflagval(player, F_HASATTACK, OT_FISTS, NA, NA, NULL);
assert(f);
f->val[0] = OT_HOOKHAND;
sprintf(f->text, "1d4");
}
// read cheat info from player file
if (playerfile) {
if (parseplayerfile(playerfile, player)) {
// error!
exit(0);
}
fclose(playerfile);
// TODO: note that we're cheaing
}
// player needs hunger
addflag(player->flags, F_HUNGER, 0, NA, NA, NULL);
// pet / npc / follower
f = lfhasflag(player, F_HASPET);
if (f) {
cell_t *c;
race_t *r;
lifeform_t *pet;
r = findracebyname(f->text);
assert(r);
// create it
c = getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND);
assert(c);
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);
}
}
getplayernamefull(pname);
sprintf(welcomemsg, "Greetings %s, welcome to %snexus!", pname, newworld ? "the new " : "");
// XXX testing
//addlf(getcellindir(player->cell, D_N), R_GOBLIN, 1);
// 00:00 - 23:59
curtime = rnd(0,86399);
} else {
@ -360,6 +391,10 @@ void checkendgame(void) {
}
void cleanup(void) {
free(xpposs);
free(raceposs);
fclose(logfile);
cleanupgfx();

316
objects.c
View File

@ -1805,10 +1805,10 @@ int curseob(object_t *o) {
int rv = B_FALSE;
lifeform_t *lf;
// announce
lf = o->pile->owner;
// announce
if (gamemode == GM_GAMESTARTED) {
if (lf) {
if (cansee(player, lf)) {
char lfname[BUFLEN];
@ -1826,6 +1826,7 @@ int curseob(object_t *o) {
msg("A black aura surrounds %s.",obname);
}
}
}
switch (o->blessed) {
case B_BLESSED: // uncurse it
@ -2581,7 +2582,6 @@ char *getdamname(enum DAMTYPE damtype) {
case DT_BASH: return "bludgeoning";
case DT_BITE: return "bite";
case DT_CHOP: return "chopping";
case DT_CLAW: return "claw";
case DT_COLD: return "cold";
case DT_CRUSH: return "crushing";
case DT_DIRECT: return "direct";
@ -2619,7 +2619,6 @@ char *getdamnamenoun(enum DAMTYPE damtype) {
case DT_POISONGAS: return "poison gas";
case DT_POISON: return "poison";
case DT_SLASH: return "slashing damage";
case DT_CLAW: return "claw damage";
case DT_ELECTRIC: return "electricity";
case DT_EXPLOSIVE: return "explosives";
case DT_FIRE: return "fire";
@ -3285,56 +3284,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
// detect magic - append [magic]
if (lfhasflag(player, F_DETECTMAGIC)) {
int ismagic = B_FALSE;
if (hasunknownmod) {
ismagic = B_TRUE;
}
switch (o->type->obclass->id) {
case OC_SCROLL:
switch (o->type->id) {
case OT_MAP:
case OT_SCR_NOTHING:
// these scrolls are non-magical
break;
default:
ismagic = B_TRUE;
break;
}
break;
case OC_RING:
case OC_WAND:
// all rings/wands are magical
ismagic = B_TRUE;
break;
case OC_POTION:
switch (o->type->id) {
case OT_POT_ACID:
case OT_POT_OIL:
case OT_POT_WATER:
case OT_POT_BLOOD:
case OT_POT_JUICE:
// these potions are non-magical
break;
default:
ismagic = B_TRUE;
break;
}
break;
case OC_BOOK:
if (hasflag(o->flags, F_LINKSPELL)) {
// ie. spellbooks
ismagic = B_TRUE;
}
break;
default:
break;
}
if (hasflag(o->flags, F_ENCHANTABLE) && hasflag(o->flags, F_BONUS)) {
ismagic = B_TRUE;
}
if (ismagic) {
if (ismagical(o)) {
strcat(buf, " [magic]");
}
}
@ -3961,6 +3911,7 @@ char *getschoolname(enum SPELLSCHOOL sch) {
case SS_WILD: return "Wild Magic";
case SS_MENTAL: return "Psionic Powers";
case SS_AIR: return "Elemental/Air Magic";
case SS_EARTH: return "Elemental/Earth Magic";
case SS_FIRE: return "Elemental/Fire Magic";
case SS_ICE: return "Elemental/Ice Magic";
case SS_MODIFICATION: return "Modification Magic";
@ -4046,6 +3997,39 @@ int getthrowdam(object_t *o) {
return (int)dam;
}
enum BODYPART getweildloc(object_t *o, enum BODYPART *otherloc, int *twohanded) {
enum BODYPART weildloc;
if (o) {
if (hasflag(o->flags, F_FIREARM)) {
weildloc = BP_SECWEAPON;
} else {
weildloc = BP_WEAPON;
}
if (twohanded) {
if (hasflag(o->flags, F_TWOHANDED)) {
*twohanded = B_TRUE;
} else {
*twohanded = B_FALSE;
}
}
} else {
// ie. unarmed
weildloc = BP_WEAPON;
if (twohanded) *twohanded = B_FALSE;
}
if (otherloc) {
if (weildloc == BP_WEAPON) {
*otherloc = BP_SECWEAPON;
} else {
*otherloc = BP_WEAPON;
}
}
return weildloc;
}
int hasedibleob(obpile_t *op) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
@ -4391,7 +4375,7 @@ void initobjects(void) {
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERUSECHARGE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_RNDCHARGES, 2, 12, NA, NULL);
addflag(lastobjectclass->flags, F_RNDCHARGES, 1, 8, NA, NULL);
addoc(OC_POTION, "Potions", "A strange concoction contained within a small flask.", '!', C_GREY);
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
@ -4949,6 +4933,13 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
///////////////////
// elemental - earth
///////////////////
// l4
addot(OT_S_DIG, "dig", "Blasts away earth to create passages.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_EARTH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
///////////////////
// gravity
///////////////////
// l3
@ -5165,7 +5156,6 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addflag(lastot->flags, F_NEEDSGRAB, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_XPVAL, 30, NA, NA, NULL);
addot(OT_A_GRAB, "grab", "You can grab hold of nearby enemies to prevent their escape.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
@ -5358,6 +5348,10 @@ void initobjects(void) {
addflag(lastot->flags, F_LINKSPELL, OT_S_DARKNESS, NA, NA, NULL);
addot(OT_SB_FREEZEOB, "spellbook of freezing touch", "Teaches the spell 'freezing touch'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_FREEZEOB, NA, NA, NULL);
addot(OT_SB_COLDBURST, "spellbook of cold burst", "Teaches the spell 'cold burst'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_COLDBURST, NA, NA, NULL);
addot(OT_SB_DIG, "spellbook of dig", "Teaches the spell 'dig'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_DIG, NA, NA, NULL);
addot(OT_SB_GASEOUSFORM, "spellbook of gaseous form", "Teaches the spell 'gaseous form'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_GASEOUSFORM, NA, NA, NULL);
@ -5416,15 +5410,46 @@ void initobjects(void) {
// wands
addot(OT_WAND_KNOCK, "wand of opening", "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_KNOCK, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_DOOR, NA, NA, NULL);
addot(OT_WAND_LIGHT, "wand of light", "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_LIGHT, 3, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, 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);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_DIGGING, "wand of digging", "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_DIG, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_NONE, NA, NA, NULL);
addot(OT_WAND_COLD, "wand of cold", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_CONECOLD, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_DETONATION, "wand of detonation", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_DETONATE, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER|TT_DOOR, NA, NA, NULL);
addot(OT_WAND_FIRE, "wand of fire", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_FIREDART, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_HASTE, "wand of haste", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_HASTE, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addot(OT_WAND_WEAKNESS, "wand of enfeeblement", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_WEAKEN, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_WONDER, "wand of wonder", "Produces random effects.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_NONE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_INVIS, "wand of invisibility", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
@ -5442,43 +5467,16 @@ void initobjects(void) {
addflag(lastot->flags, F_LINKSPELL, OT_S_FIREBALL, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_FIRE, "wand of fire", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_FIREDART, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addot(OT_WAND_DETONATION, "wand of detonation", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_DETONATE, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER|TT_DOOR, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_HASTE, "wand of haste", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_HASTE, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addot(OT_WAND_KNOCK, "wand of opening", "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_KNOCK, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_DOOR, NA, NA, NULL);
addot(OT_WAND_LIGHT, "wand of light", "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_LIGHT, 3, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addot(OT_WAND_POLYMORPH, "wand of polymorph", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_POLYMORPH, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, 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, 70, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_SLOW, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_WEAKNESS, "wand of enfeeblement", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_WEAKEN, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_WONDER, "wand of wonder", "Produces random effects.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_NONE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// tools
addot(OT_BLINDFOLD, "blindfold", "Short length of wide cloth, used for blocking eyesight.", MT_CLOTH, 0.01, OC_TOOLS);
@ -5887,8 +5885,9 @@ void initobjects(void) {
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 1, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "blood stain");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dries up");
addflag(lastot->flags, F_DIECONVERTTEXTPL, NA, NA, NA, "dry up");
//addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dries up");
//addflag(lastot->flags, F_DIECONVERTTEXTPL, NA, NA, NA, "dry up");
addflag(lastot->flags, F_NODIECONVERTTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
@ -6200,6 +6199,11 @@ void initobjects(void) {
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_EVASION, -5, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
addot(OT_PIRATEHAT, "tricorne", "A three cornered hat with a skull and crossbones emblem.", MT_CLOTH, 1, OC_ARMOUR);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL);
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);
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);
@ -6251,6 +6255,10 @@ void initobjects(void) {
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -4, NA, NULL);
addflag(lastot->flags, F_TINTED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addot(OT_EYEPATCH, "eyepatch", "A small patch of black material which covers one eye. Scary looking.", MT_CLOTH, 0.01, OC_ARMOUR);
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);
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);
@ -6362,6 +6370,17 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_UNARMED, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
// this one if for the pirate
addot(OT_HOOKHAND, "hook", "hook", MT_METAL, 0, OC_WEAPON);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_UNARMED, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ATTACKVERB, NA, 5, NA, "scratch");
addflag(lastot->flags, F_ATTACKVERB, 6, 15, NA, "scrape");
addflag(lastot->flags, F_ATTACKVERB, 16, NA, NA, "rake");
addot(OT_TEETH, "teeth", "teeth object", MT_BONE, 0, OC_WEAPON);
addflag(lastot->flags, F_DAM, DT_BITE, NA, NA, "1d2");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
@ -6370,7 +6389,14 @@ void initobjects(void) {
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addot(OT_CLAWS, "claws", "claws object", MT_BONE, 0, OC_WEAPON);
addflag(lastot->flags, F_DAM, DT_CLAW, NA, NA, "1d2");
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d2");
addflag(lastot->flags, F_ATTACKVERB, NA, 5, NA, "scratch");
addflag(lastot->flags, F_ATTACKVERB, 6, 15, NA, "claw");
addflag(lastot->flags, F_ATTACKVERB, 16, 30, NA, "tear");
addflag(lastot->flags, F_ATTACKVERB, 31, 40, NA, "rake");
addflag(lastot->flags, F_ATTACKVERB, 41, 50, NA, "gouge");
addflag(lastot->flags, F_ATTACKVERB, 51, NA, NA, "eviscerate");
addflag(lastot->flags, F_KILLVERB, 70, NA, NA, "disembowel");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
@ -6384,6 +6410,7 @@ void initobjects(void) {
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addot(OT_TAIL, "tail", "tail object", MT_FLESH, 0, OC_WEAPON);
addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "tailslap");
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
@ -6448,7 +6475,7 @@ void initobjects(void) {
addflag(lastot->flags, F_MISSILEDAM, 3, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, "");
addflag(lastot->flags, F_OBHP, 5, 5, NA, "");
addflag(lastot->flags, F_OBHP, 3, 3, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL);
addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.5, OC_MISSILE);
@ -6632,6 +6659,12 @@ void initobjects(void) {
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL);
addot(OT_CUTLASS, "cutlass", "An accuracte, light-weight pirate blade.", MT_METAL, 1, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7");
addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
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);
@ -7017,6 +7050,12 @@ int isdangerousob(object_t *o, lifeform_t *lf, int onlyifknown) {
}
}
}
// undead won't touch blessed things - don't worry about
// onlyifknown, they can sense this.
if (hasflag(lf->flags, F_UNDEAD) && isblessed(o)) {
return B_TRUE;
}
return B_FALSE;
}
@ -7143,6 +7182,65 @@ int isimpassableob(object_t *o, lifeform_t *lf) {
return B_FALSE;
}
int ismagical(object_t *o) {
if (hasflag(o->flags, F_HASBRAND)) {
return B_TRUE;
}
switch (o->type->obclass->id) {
case OC_SCROLL:
switch (o->type->id) {
case OT_MAP:
case OT_SCR_NOTHING:
// these scrolls are non-magical
break;
default:
return B_TRUE;
break;
}
break;
case OC_RING:
case OC_WAND:
// all rings/wands are magical
return B_TRUE;
break;
case OC_POTION:
switch (o->type->id) {
case OT_POT_ACID:
case OT_POT_OIL:
case OT_POT_WATER:
case OT_POT_BLOOD:
case OT_POT_JUICE:
// these potions are non-magical
break;
default:
return B_TRUE;
break;
}
break;
case OC_BOOK:
if (hasflag(o->flags, F_LINKSPELL)) {
// ie. spellbooks
return B_TRUE;
}
break;
default:
break;
}
if (hasflag(o->flags, F_ENCHANTABLE) && hasflag(o->flags, F_BONUS)) {
return B_TRUE;
}
return B_FALSE;
}
int ismeleeweapon(object_t *o) {
if (hasflag(o->flags, F_DAM)) {
return B_TRUE;
}
return B_FALSE;
}
int ismetal(enum MATERIAL mat) {
int metal = B_FALSE;
switch (mat) {
@ -7482,7 +7580,7 @@ lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level) {
addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
o = relinkob(o, newlf->pack);
weild(lf, o);
weild(newlf, o);
f = hasflag(o->flags, F_OBHP);
if (f) {
@ -7499,6 +7597,9 @@ lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level) {
addflag(newlf->flags, F_MOVESPEED, newspeed, NA, NA, NULL);
}
}
if (newlf) {
addflag(newlf->flags, F_PETOF, lf->id, NA, NA, NULL);
}
return newlf;
}
@ -8132,10 +8233,14 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
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 (!where) {
// cancel.
msg("Cancelled.");
@ -8239,13 +8344,14 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
enum OBTYPE spelltocast;
int power;
spelltocast = f->val[0];
power = f->val[1];
if (power == NA) power = 1;
if (isblessed(o)) power += 4;
power += (getskill(lf, SK_MAGITEMUSAGE)*2);
// certain wands always used the blessed version of spells
// certain wands have different effects when cursed
switch (o->type->id) {
@ -10331,6 +10437,15 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
}
if (youhit && lfhasflag(target, F_NONCORPOREAL)) {
youhit = B_FALSE;
willcatch = B_FALSE;
if (seen) {
msg("%s passes straight through %s.", obname, targetname);
announcedmiss = B_TRUE;
}
}
// if someone is there, they take damage and the object might die
// this should be "if target && youhit"
if (youhit) {
@ -10419,7 +10534,10 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
announcedmiss = B_TRUE;
}
}
} else { // no target
}
if (!target || !youhit) {
// will it shatter on the ground?
if (willshatter(o->material->id)) {
if (haslos(player, where)) {
char *obcaps;
@ -10454,8 +10572,8 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
addob(where->obpile, buf);
}
// potion effects?
if (shattered) {
// potion effects (only if you hit)?
if (shattered && youhit) {
if (o->type->obclass->id == OC_POTION) {
int observed;
// some potions have special effects...

View File

@ -100,6 +100,7 @@ char *getschoolname(enum SPELLSCHOOL sch);
int getshatterdam(object_t *o);
enum SKILLLEVEL gettechlevel(object_t *o);
int getthrowdam(object_t *o);
enum BODYPART getweildloc(object_t *o, enum BODYPART *otherloc, int *twohanded);
int hasedibleob(obpile_t *op);
object_t *hasknownob(obpile_t *op, enum OBTYPE oid);
object_t *hasob(obpile_t *op, enum OBTYPE oid);
@ -132,6 +133,8 @@ int isknown(object_t *o);
int isknownot(objecttype_t *ot);
int isidentified(object_t *o);
int isimpassableob(object_t *o, lifeform_t *lf);
int ismagical(object_t *o);
int ismeleeweapon(object_t *o);
int ismetal(enum MATERIAL mat);
int isthrowmissile(object_t *o);
int isoperable(object_t *o);

154
spell.c
View File

@ -27,6 +27,8 @@ extern WINDOW *msgwin;
extern job_t *firstjob;
extern enum ERROR reason;
int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifeform_t *target, flag_t *cwflag) {
char username[BUFLEN];
char killername[BUFLEN];
@ -255,9 +257,15 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
} else {
int str;
// fixed damage?
if (strlen(damstr)) {
dam = roll(damstr);
} else {
// determine damage baesd on crusher's strength
str = getattr(user, A_STR);
dam = modifybystat((str/2), user, A_STR);
}
// announce
if (cansee(player, target)) {
@ -450,7 +458,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
// this call will also remove this ability...
setrace(user, f->val[0]);
setrace(user, f->val[0], B_TRUE);
} else if (abilid == OT_A_LEARN) {
skill_t *sk;
@ -502,23 +510,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} else if (abilid == OT_A_DEBUG) {
cell_t *where;
where = askcoords("Debug who?", TT_MONSTER);
if (where) {
lifeform_t *victim;
victim = where->lf;
if (victim) {
char lfname[BUFLEN];
flag_t *f;
getlfname(victim, lfname);
f = hasflag(victim->flags, F_DEBUG);
if (f) {
killflag(f);
msg("%s - debugging is DISABLED.", lfname);
} else {
addflag(victim->flags, F_DEBUG, B_TRUE, NA, NA, NULL);
msg("%s - debugging is ON.", lfname);
}
}
if (where && where->lf) {
debug(where->lf);
}
} else if (abilid == OT_A_EMPLOY) {
cell_t *where;
@ -1083,6 +1076,32 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
getlfname(target, targetname);
// only animals/humanoids
if (!lfhasflag(target, F_ANIMAL) && !lfhasflag(target, F_HUMANOID)) {
if (isplayer(caster)) {
msg("%s%s mind is too alien for you to charm.",targetname,getpossessive(targetname));
}
return B_FALSE;
}
if (!ischarmable(target)) {
if (isplayer(caster)) {
switch (reason) {
case E_LOWIQ:
msg("%s%s intellect is too simple for you to charm.",targetname,getpossessive(targetname));
break;
case E_UNDEAD:
msg("The undead are immune to possession.");
break;
default:
msg("You cannot possesss %s.", targetname);
break;
}
}
return B_FALSE;
}
if (getallegiance(caster) == AL_PEACEFUL) {
fizzle(caster);
return B_FALSE;
@ -1099,6 +1118,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("%s resists.",targetname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// they get angry!
if (!isplayer(target) && cansee(target, caster)) {
fightback(target, caster);
}
} else {
int howlong;
if (isplayer(caster) || cansee(player, target)) {
@ -1332,6 +1355,38 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else {
// monsters can't use this
}
} else if (spellid == OT_S_DIG) {
int numseen = 0;
int maxrange;
cell_t *retcell[MAXRETCELLS];
int nretcell,i;
// don't need line of fire OR sight!
if (!validatespellcell(caster, &targcell, TT_NONE, B_FALSE, LOF_DONTNEED, spellid, power)) return B_TRUE;
// calculate a line from caster to the target cell
calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y,
targcell->x, targcell->y, retcell, &nretcell);
maxrange = power;
// get rid of rock in the cells...
for (i = 0; i < nretcell && (i <= maxrange); i++) {
if (retcell[i]->type->solid) {
setcelltype(retcell[i], getemptycelltype(retcell[i]->map->habitat));
if (haslos(player, retcell[i])) numseen++;
}
}
// announce if any seen
if (numseen) {
msg("The wall%s crumble%s to dust!",
(numseen == 1) ? "" : "s",
(numseen == 1) ? "s" : ""
);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_DETECTLIFE) {
target = caster;
if (isplayer(caster)) {
@ -1940,7 +1995,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
addflag(target->flags, F_ORIGRACE, target->race->id, NA, NA, NULL);
// polymorph is always will be temporary
addtempflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL, 10);
setrace(target, R_GASCLOUD);
setrace(target, R_GASCLOUD, B_TRUE);
}
} else if (spellid == OT_S_HASTE) {
int howlong = 15;
@ -2527,8 +2582,26 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
// charmable?
if (!ischarmable(target)) {
if (isplayer(caster)) {
switch (reason) {
case E_LOWIQ:
msg("%s%s intellect is too simple for you to possess.",targname,getpossessive(targname));
break;
case E_UNDEAD:
msg("The undead are immune to possession.");
break;
default:
msg("You cannot possesss %s.", targname);
break;
}
}
return B_FALSE;
}
// saving throw....
if (skillcheck(target, SC_RESISTMAG, 20 + power*2, 0)) {
if (skillcheck(target, SC_RESISTMAG, 16 + power*2, 0)) {
if (isplayer(caster) && cansee(player, target)) {
msg("%s%s mind fights off your intrusion!", targname, getpossessive(targname));
}
@ -2545,6 +2618,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
// remove 'become a ghost' flag fro mcaster
killflagsofid(caster->flags, F_RISEASGHOST);
// possess!
if (isplayer(caster)) {
// player name
@ -2556,7 +2633,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
player->controller = C_AI;
player = target;
target->controller = C_PLAYER;
// now kill the caster!
die(caster);
// if they survived somehow...
if (!isdead(caster)) {
// ... they will be hostile!
fightback(caster, player);
}
} else {
switch (getallegiance(caster)) {
case AL_HOSTILE:
@ -2571,10 +2654,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
makefriendly(target, PERMENANT);
break;
}
}
// now kill the caster!
die(caster);
}
} else if (spellid == OT_S_PSYARMOUR) {
flag_t *f;
// always targetted at caster
@ -2836,7 +2919,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int willannounce = B_FALSE;
char targname[BUFLEN];
// special case for ghosts...
if (caster->race->id == R_GHOST) {
targcell = caster->cell;
} else {
if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE;
}
target = targcell->lf;
if (!target) {
@ -3104,26 +3192,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// make sure race is valid:
// - can't turn into monsters which aren't randomly generated.
// - can't turn into unique monsters
if (r && !appearsrandomly(r->id)) {
r = NULL;
}
} else {
// - can't turn into undead monsters
if (r && !canpolymorphto(r->id)) r = NULL;
} else { // random
if (isplayer(target) && lfhasflag(target, F_CONTROL)) {
askstring("What will you become", '?', buf, BUFLEN, NULL);
r = findracebyname(buf);
// make sure race is valid:
// - can't turn into monsters which aren't randomly generated.
// - can't turn into unique monsters
if (r && !appearsrandomly(r->id)) {
r = NULL;
}
if (r && !canpolymorphto(r->id)) r = NULL;
}
if (!r) {
// random race, but not the same!
r = target->race;
while (r == target->race) {
while ((r == target->race) || !canpolymorphto(r->id)) {
r = getrandomrace(NULL, 0);
}
}
@ -3156,7 +3239,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// become the new race!
setrace(target, r->id);
setrace(target, r->id, B_TRUE);
// if someone cast the spell at themself, they can change back at will.
if (target == caster) {
@ -3643,6 +3726,8 @@ enum SKILL getschoolskill(enum SPELLSCHOOL ss) {
return SK_SS_DEATH;
case SS_DIVINATION:
return SK_SS_DIVINATION;
case SS_EARTH:
return SK_SS_EARTH;
case SS_FIRE:
return SK_SS_FIRE;
case SS_ICE:
@ -3876,6 +3961,7 @@ int getspellrange(enum OBTYPE spellid, int power) {
case OT_S_BURNINGWAVE:
// base range for this spell is 3
range += (power/3);
break;
default:
break;
}