This commit is contained in:
Rob Pearce 2011-03-04 01:22:36 +00:00
parent 4f89ab33f8
commit 020f47b808
30 changed files with 7675 additions and 1084 deletions

127
ai.c
View File

@ -18,7 +18,8 @@ extern enum ERROR reason;
int wantdb = B_TRUE; int wantdb = B_TRUE;
enum OBTYPE aigetattackspell(lifeform_t *lf) {
enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) {
flag_t *f; flag_t *f;
enum OBTYPE poss[MAXPILEOBS]; enum OBTYPE poss[MAXPILEOBS];
int nposs = 0; int nposs = 0;
@ -29,25 +30,51 @@ enum OBTYPE aigetattackspell(lifeform_t *lf) {
} }
for (f = lf->flags->first ; f ; f = f->next) { for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_CANWILL) { if ((f->id == F_CANCAST) || (f->id == F_CANWILL)) {
poss[nposs] = f->val[0];
nposs++;
} else if (f->id == F_CANCAST) {
objecttype_t *ot; objecttype_t *ot;
ot = findot(f->val[0]); ot = findot(f->val[0]);
if (cancast(lf, f->val[0], NULL)) { if (cancast(lf, f->val[0], NULL)) {
if (hasflag(ot->flags, F_AICASTATVICTIM) || hasflag(ot->flags, F_AICASTATSELF) || hasflag(ot->flags, F_AICASTANYWHERE)) { int ok = B_FALSE;
if (hasflag(ot->flags, F_AICASTATVICTIM)) {
int range;
range = getspellrange(f->val[0]);
if ((range == UNLIMITED) || (getcelldist(lf->cell, victim->cell) <= range)) {
if (db) { if (db) {
dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?"); dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?");
} }
//TODO :ooo only add if we have an AICAST flag! ok = B_TRUE;
poss[nposs] = f->val[0]; }
nposs++; } else if (hasflag(ot->flags, F_AICASTATSELF) || hasflag(ot->flags, F_AICASTANYWHERE)) {
if (db) {
dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?");
}
ok = B_TRUE;
} else if (hasflag(ot->flags, F_AICASTATADJVICTIM) &&
(getcelldist(lf->cell,victim->cell) == 1)) {
if (ot->id == OT_A_GRAB) {
if (lfhasflag(lf, F_GRABBING) || lfhasflag(lf, F_GRABBEDBY) ||
lfhasflag(victim, F_GRABBING) || lfhasflag(victim, F_GRABBEDBY)) {
} else {
ok = B_TRUE;
}
} else {
ok = B_TRUE;
}
} else if (hasflag(ot->flags, F_AICASTNEXTTOVICTIM) &&
(getcelldist(lf->cell,victim->cell) == 1)) {
ok = B_TRUE;
} else { } else {
if (db) { if (db) {
dblog(".oO { cant cast %s - dont know where to target it }", ot ? ot->name : "?unkownspell?"); dblog(".oO { cant cast %s - dont know where to target it }", ot ? ot->name : "?unkownspell?");
} }
} }
if (ok) {
if (aispellok(lf, ot, victim)) {
poss[nposs] = f->val[0];
nposs++;
}
}
} else { } else {
if (db) { if (db) {
if (ot) { if (ot) {
@ -77,6 +104,18 @@ void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victi
if (spelllf) *spelllf = victim; if (spelllf) *spelllf = victim;
if (spellcell) *spellcell = victim->cell; if (spellcell) *spellcell = victim->cell;
if (spellob) *spellob = NULL; if (spellob) *spellob = NULL;
} else if (hasflag(spelltype->flags, F_AICASTNEXTTOVICTIM)) {
if (getcelldist(lf->cell, victim->cell) <= 1) {
if (spelllf) *spelllf = NULL;
if (spellcell) *spellcell = lf->cell;
if (spellob) *spellob = NULL;
}
} else if (hasflag(spelltype->flags, F_AICASTATADJVICTIM)) {
if (getcelldist(lf->cell, victim->cell) <= 1) {
if (spelllf) *spelllf = victim;
if (spellcell) *spellcell = victim->cell;
if (spellob) *spellob = NULL;
}
} else if (hasflag(spelltype->flags, F_AICASTATSELF)) { } else if (hasflag(spelltype->flags, F_AICASTATSELF)) {
if (spelllf) *spelllf = lf; if (spelllf) *spelllf = lf;
if (spellcell) *spellcell = lf->cell; if (spellcell) *spellcell = lf->cell;
@ -181,6 +220,18 @@ void aimove(lifeform_t *lf) {
if (!weild(lf, bestgun)) return; if (!weild(lf, bestgun)) return;
} }
// do we have better ammo?
if (curgun) {
object_t *curammo;
curammo = getammo(lf);
if (!curammo) {
for (o = lf->pack->first ; o ; o = o->next) {
testammo(lf, o); // doesn't take any time.
if (getammo(lf)) break;
}
}
}
// do we have better armour? // do we have better armour?
for (bp = BP_RIGHTHAND ; bp < MAXBODYPARTS; bp++) { for (bp = BP_RIGHTHAND ; bp < MAXBODYPARTS; bp++) {
object_t *curarm; object_t *curarm;
@ -228,7 +279,7 @@ void aimove(lifeform_t *lf) {
// reset F_TARGET lifetime to full. // reset F_TARGET lifetime to full.
f->lifetime = AI_FOLLOWTIME; f->lifetime = AI_FOLLOWTIME;
if (db) dblog(".oO { i can see my target (at %d,%d). will move towards it. }",target->cell->x,target->cell->y); if (db) dblog(".oO { i can see my target (at %d,%d). might move towards it. }",target->cell->x,target->cell->y);
// remember last known loc // remember last known loc
f->val[1] = target->cell->x; f->val[1] = target->cell->x;
f->val[2] = target->cell->y; f->val[2] = target->cell->y;
@ -236,8 +287,13 @@ void aimove(lifeform_t *lf) {
goingtomove = B_TRUE; goingtomove = B_TRUE;
// drink boost potions
if (!useitemwithflag(lf, F_AIBOOSTITEM)) {
return;
}
// can we attack with spells (ie. ones which target the victim)? // can we attack with spells (ie. ones which target the victim)?
spell = aigetattackspell(lf); spell = aigetattackspell(lf, target);
if (spell != OT_NONE) { if (spell != OT_NONE) {
int spellfailed = B_FALSE; int spellfailed = B_FALSE;
lifeform_t *spelllf = NULL; lifeform_t *spelllf = NULL;
@ -288,27 +344,42 @@ void aimove(lifeform_t *lf) {
aigetspelltarget(lf, st, target, &spelllf, &spellcell, &spellob); aigetspelltarget(lf, st, target, &spelllf, &spellcell, &spellob);
} }
if (spellfailed) {
if (!spellfailed && !castspell(lf, spell, spelllf, spellob, spellcell)) { if (db) dblog(".oO { cast spell/ability failed (1)! }");
} else {
if (getschool(spell) == SS_ABILITY) {
spellfailed = useability(lf, spell, spelllf, spellcell);
} else {
spellfailed = castspell(lf, spell, spelllf, spellob, spellcell);
}
}
if (spellfailed) {
if (db) dblog(".oO { cast spell/ability tried but failed (2)! }");
} else {
// spell succesful // spell succesful
return; return;
} else {
if (db) dblog(".oO { cast spell failed! }");
} }
} }
// if not adjacent, check for guns, wands, throwing // if not adjacent, check for guns, wands, throwing
if (goingtomove && (getcelldist(lf->cell, target->cell) > 1)) { if (goingtomove && (getcelldist(lf->cell, target->cell) > 1) && haslof(lf, target->cell)) {
// can we attack by firing something? // can we attack by firing something?
gun = getfirearm(lf); gun = getfirearm(lf);
if (goingtomove && gun && getammo(lf)) { if (goingtomove && gun && getammo(lf)) {
if (db) {
char gunname[BUFLEN];
getobname(gun, gunname, gun->amt);
dblog(".oO { will fire my gun (%s) at target. }",gunname);
}
setguntarget(lf, target); setguntarget(lf, target);
if (!shoot(lf)) { if (!shoot(lf)) {
// succesful // succesful
return; return;
} else { } else {
if (db) dblog(".oO { shoot gun failed! }"); if (db) dblog(".oO { shoot gun failed! reason = %d }", reason);
} }
} else {
if (db) dblog(".oO { not firing out gun }");
} }
// can we attack by throwing something? // can we attack by throwing something?
@ -500,6 +571,12 @@ void aimove(lifeform_t *lf) {
// need to heal? // need to heal?
if ((lf->hp < lf->maxhp) || if ((lf->hp < lf->maxhp) ||
((lf->mp < lf->maxmp) && lfhasflag(lf, F_RESTHEALMPAMT)) ) { ((lf->mp < lf->maxmp) && lfhasflag(lf, F_RESTHEALMPAMT)) ) {
if (lf->hp < (lf->maxhp/2)) {
if (!useitemwithflag(lf, F_AIHEALITEM)) {
return;
}
}
if (db) dblog(".oO { resting }"); if (db) dblog(".oO { resting }");
rest(lf, B_TRUE); rest(lf, B_TRUE);
} }
@ -523,6 +600,21 @@ int aipickup(lifeform_t *lf, object_t *o) {
} }
int aispellok(lifeform_t *lf, objecttype_t *st, lifeform_t *victim) {
if ((st->id == OT_S_BLINDNESS) && isblind(victim)) {
return B_FALSE;
}
if ((st->id == OT_S_PAIN) && lfhasflag(victim, F_PAIN)) {
return B_FALSE;
}
if ((st->id == OT_A_SPRINT) && lfhasflag(lf, F_SPRINTING)) {
return B_FALSE;
}
return B_TRUE;
}
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op) { object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op) {
object_t *o; object_t *o;
@ -709,4 +801,3 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
return B_FALSE; return B_FALSE;
} }

3
ai.h
View File

@ -1,10 +1,11 @@
#include "defs.h" #include "defs.h"
enum OBTYPE aigetattackspell(lifeform_t *lf); enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim);
void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob); void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob);
object_t * aigetwand(lifeform_t *lf); object_t * aigetwand(lifeform_t *lf);
void aimove(lifeform_t *lf); void aimove(lifeform_t *lf);
int aipickup(lifeform_t *lf, object_t *o); int aipickup(lifeform_t *lf, object_t *o);
int aispellok(lifeform_t *lf, objecttype_t *st, lifeform_t *victim);
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op); object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op);
object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op); object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op);
int lookforobs(lifeform_t *lf, int covetsonly); int lookforobs(lifeform_t *lf, int covetsonly);

293
attack.c
View File

@ -8,6 +8,8 @@
#include "flag.h" #include "flag.h"
#include "io.h" #include "io.h"
#include "lf.h" #include "lf.h"
#include "map.h"
#include "move.h"
#include "nexus.h" #include "nexus.h"
#include "objects.h" #include "objects.h"
#include "text.h" #include "text.h"
@ -15,6 +17,47 @@
extern lifeform_t *player; extern lifeform_t *player;
int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) {
object_t *armour;
int adam;
int damtaken = 0;
if ((damtype == DT_ACID) || hasflag(wep->flags, F_ARMOURPIERCE)) {
// ALL of damage reduction goes towards armour
adam = dam;
} else {
// some of damage reduction goes towards armour
adam = (dam / 2);
}
// pick a random piece of armour
armour = getrandomarmour(lf);
if (armour) {
damtaken = takedamage(armour,adam, damtype);
}
return damtaken;
}
void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int *dam, enum DAMTYPE damtype) {
int db = B_FALSE;
// armour can't stop armour-piercing weapons
if (hasflag(wep->flags, F_ARMOURPIERCE)) {
reduceamt = 0;
}
if (db) {
if (reduceamt > 0) {
dblog("Armour reduces dam by %d to %d.",reduceamt,dam);
} else {
dblog("No armour dam reduction.");
}
}
if (dam && (reduceamt >= 0)) {
*dam -= reduceamt;
if (*dam < 0) *dam = 0;
}
}
int attackcell(lifeform_t *lf, cell_t *c) { int attackcell(lifeform_t *lf, cell_t *c) {
// anyone there? if so just attack. // anyone there? if so just attack.
if (c->lf) { if (c->lf) {
@ -45,10 +88,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
object_t *wep; object_t *wep;
obpile_t *op = NULL; obpile_t *op = NULL;
int attacktime; int attacktime;
int acc;
int hit = B_FALSE; int hit = B_FALSE;
int critical = 0;
char wepname[BUFLEN]; char wepname[BUFLEN];
int ev; //int acc;
//int ev;
int i; int i;
int willheal = B_FALSE; int willheal = B_FALSE;
@ -61,7 +105,16 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
// get names // get names
getlfname(lf, attackername); getlfname(lf, attackername);
if (lf == victim) {
if (isplayer(lf)) {
strcpy(victimname, "yourself");
} else {
strcpy(victimname, "itself");
}
} else {
getlfname(victim, victimname); getlfname(victim, victimname);
}
if (aidb) dblog(".oO { trying to attack %s }", victimname); if (aidb) dblog(".oO { trying to attack %s }", victimname);
@ -89,25 +142,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
taketime(lf, attacktime); taketime(lf, attacktime);
acc = getlfaccuracy(lf);
// modify for defender's evasion
ev = getevasion(victim);
acc -= ev;
// metal weapon versus magnetic shield?
if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) {
acc -= 45;
}
if (acc < 0) acc = 0;
if (acc > 100) acc = 100;
if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc);
// did you hit? // did you hit?
ndam = 0; ndam = 0;
if (rnd(1,100) <= acc) { if (rolltohit(lf, victim, &critical)) {
int n;
hit = B_TRUE; hit = B_TRUE;
if (aidb) dblog(".oO { i hit! }"); if (aidb) dblog(".oO { i hit! }");
@ -122,7 +160,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
o = addob(lf->pack, "glowing flask"); o = addob(lf->pack, "glowing flask");
if (o) { if (o) {
getobname(o, buf, o->amt); getobname(o, buf, o->amt);
msglower("%c - %s.",o->letter, buf); msgnocap("%c - %s.",o->letter, buf);
} else { } else {
// add to the ground // add to the ground
o = addob(lf->cell->obpile, "glowing flask"); o = addob(lf->cell->obpile, "glowing flask");
@ -143,12 +181,18 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
// determine damage // determine damage
//if (unarmed && (unarmedflag->val[0] != NA)) { //if (unarmed && (unarmedflag->val[0] != NA)) {
// ie. if critical is 0, do this once.
// if critical is 1, do this twice.
// etc.
dam[ndam] = 0;
for (n = 0; n < critical+1; n++) {
if (unarmedflag) { if (unarmedflag) {
// this mosnter's unarmed attack will // this mosnter's unarmed attack will
// override normal damage calculation // override normal damage calculation
dam[ndam] = getdamrollfromflag(unarmedflag); dam[ndam] += getdamrollfromflag(unarmedflag);
} else { } else {
dam[ndam] = getdamroll(wep, victim); dam[ndam] += getdamroll(wep, victim);
}
} }
if (aidb) dblog("rolled dam[%d] = %d",ndam,dam[ndam]); if (aidb) dblog("rolled dam[%d] = %d",ndam,dam[ndam]);
@ -175,7 +219,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
} }
// determine extra damage // determine extra damage
getextradam(wep, &dam[ndam], &damtype[ndam]); getextradam(wep, &dam[0], &damtype[0], &ndam);
} }
} else { } else {
hit = B_FALSE; hit = B_FALSE;
@ -185,24 +229,26 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
if (ndam > 0) { if (ndam > 0) {
flag_t *f;
for (i = 0; i < ndam; i++) { for (i = 0; i < ndam; i++) {
float reducepct;
int ar;
int reduceamt; int reduceamt;
dblog("initial dam[%d] = %d",i,dam[i]); dblog("initial dam[%d] = %d",i,dam[i]);
if (lfhasflag(lf, F_HEAVYBLOW)) {
dam[i] = (int)((float)dam[i] * 1.5);
dblog("heavy blow makes dam[%d] = %d",i,dam[i]);
}
// modify based on resistances // modify based on resistances
adjustdamlf(victim, &dam[i], damtype[i]); adjustdamlf(victim, &dam[i], damtype[i]);
dblog("adjusted for lf to dam[%d] = %d",i,dam[i]); dblog("adjusted for lf to dam[%d] = %d",i,dam[i]);
// modify for defender's armour // modify for defender's armour
ar = getarmourrating(victim); reduceamt = getarmourdamreduction(victim, wep, dam[i], damtype[i]);
reducepct = getdamreducepct(ar);
reduceamt = (int) ceil((reducepct / 100.0) * (float)dam[i]); applyarmourdamreduction(victim, wep, reduceamt, &dam[i], damtype[i]);
dam[i] -= reduceamt;
if (dam[i] < 0) dam[i] = 0;
dblog("reduced by armour to dam[%d] = %d",i,dam[i]); dblog("reduced by armour to dam[%d] = %d",i,dam[i]);
// will this hit be fatal? // will this hit be fatal?
@ -287,7 +333,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
if (wep && !unarmedflag) { if (wep && !unarmedflag) {
char wepname[BUFLEN]; char wepname[BUFLEN];
getobname(wep, wepname, 1); getobname(wep, wepname, 1);
sprintf(buf, "%s^weilding %s",attackername, wepname); sprintf(buf, "%s^%s %s",attackername,
(lf == victim) ? "using" : "weilding",
wepname);
} else { } else {
strcpy(buf, attackername); strcpy(buf, attackername);
} }
@ -296,20 +344,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
// victim's armour loses hp // victim's armour loses hp
if (reduceamt) { if (reduceamt) {
object_t *armour; applyarmourdamage(victim, wep, reduceamt, damtype[i]);
int adam;
if (damtype[i] == DT_ACID) {
// ALL of damage reduction goes towards armour
adam = reduceamt;
} else {
// some of damage reduction goes towards armour
adam = (reduceamt / 2);
}
// pick a random piece of armour
armour = getrandomarmour(victim);
if (armour) {
takedamage(armour,adam, damtype[i]);
}
} }
} }
} // end foreach damtype } // end foreach damtype
@ -319,7 +354,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
if (!isdead(victim)) { if (!isdead(victim)) {
if (unarmedflag) { if (unarmedflag) {
flag_t *f;
f = lfhasflag(lf, F_FREEZINGTOUCH); f = lfhasflag(lf, F_FREEZINGTOUCH);
if (f) { if (f) {
// victim turns to ice for a while! // victim turns to ice for a while!
@ -327,6 +361,45 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
killflag(f); killflag(f);
} }
} }
f = lfhasflag(lf, F_QUICKBITE);
if (f) {
if (isbleeding(victim)) {
int dam;
char lfname[BUFLEN];
dam = rolldie(f->val[0], f->val[1]) + f->val[2];
getlfname(lf, lfname);
losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE);
if (isplayer(victim) || haslos(player, victim->cell)) {
msg("%s bites %s!", lfname, victimname);
}
}
}
f = lfhasflag(lf, F_PACKATTACK);
if (f) {
int dir;
cell_t *c;
int nmatched = 0;
// count adjacent allies of name xx
for (dir = DC_N; dir <= DC_NW; dir++) {
c = getcellindir(victim->cell, dir);
if (c && c->lf) {
if (strcasestr(c->lf->race->name, f->text)) {
nmatched++;
}
}
}
if (nmatched >= f->val[2]) {
char damstring[BUFLEN];
sprintf(damstring, "a %s pack", f->text);
losehp(victim, f->val[0], f->val[1], lf, damstring);
if (isplayer(victim) || haslos(player, victim->cell)) {
msg("The %s pack attacks %s!", f->text, victimname);
}
}
}
} }
} else { // miss! } else { // miss!
if (aidb) dblog(".oO { i missed! }"); if (aidb) dblog(".oO { i missed! }");
@ -349,6 +422,18 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
msg("%s misses %s.", buf, victimname); msg("%s misses %s.", buf, victimname);
} }
} }
if (lfhasflag(victim, F_DODGES)) {
flag_t *f;
cell_t *adj;
f = addflag(victim->flags, F_NOTIME, B_TRUE, NA, NA, NULL);
adj = getrandomadjcell(victim->cell, WE_NOTSOLID);
moveto(lf, adj);
msg("%s dodge%s!",victimname,isplayer(victim) ? "" : "s");
killflag(f);
}
} }
fightback(victim, lf); fightback(victim, lf);
} }
@ -445,7 +530,8 @@ int attackob(lifeform_t *lf, object_t *o) {
// don't need to check for blessed vs mosnters // don't need to check for blessed vs mosnters
// determine extra damage // determine extra damage
getextradam(wep, &dam[ndam], &damtype[ndam]); getextradam(wep, &dam[0], &damtype[0], &ndam);
for (i = 0; i < ndam; i++) { for (i = 0; i < ndam; i++) {
// announce the hit // announce the hit
@ -473,6 +559,16 @@ int attackob(lifeform_t *lf, object_t *o) {
youhear(lf->cell, "sounds of fighting"); youhear(lf->cell, "sounds of fighting");
} }
if ((i == 0) && unarmedflag) {
char buf[BUFLEN];
sprintf(buf, "punching %s", obname);
if ( losehp(lf, 1, DT_BASH, lf, buf)) {
if (isplayer(lf)) {
msg("Ow!");
}
}
}
// object loses hp // object loses hp
takedamage(o, dam[i], damtype[i]); takedamage(o, dam[i], damtype[i]);
@ -481,6 +577,21 @@ int attackob(lifeform_t *lf, object_t *o) {
// special weapon effects // special weapon effects
wepeffects(wep, obloc); wepeffects(wep, obloc);
// weapon gets damaged ?
if (!unarmedflag && wep && (ndam > 0)) {
switch (damtype[0]) {
case DT_PIERCE:
case DT_SLASH:
// weapon gets duller
if (rnd(1,2)) makeduller(wep, 1);
break;
default:
break;
}
}
// hitting an object with our hands will hurt
// get rid of temp unarmed object pile // get rid of temp unarmed object pile
if (op) { if (op) {
killobpile(op); killobpile(op);
@ -489,6 +600,20 @@ int attackob(lifeform_t *lf, object_t *o) {
return B_FALSE; return B_FALSE;
} }
// returns the amount of damage the armour blocked...
int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) {
int reduceamt = 0;
float reducepct;
int ar;
ar = getarmourrating(lf);
reducepct = getdamreducepct(ar);
reduceamt = (int) ceil((reducepct / 100.0) * (float)dam);
if (reduceamt < 0) reduceamt = 0;
return reduceamt;
}
// returns a const char * // returns a const char *
char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp) { char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp) {
@ -597,6 +722,12 @@ char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp) {
} else { } else {
return "freeze"; return "freeze";
} }
} else if (damtype == DT_UNARMED) {
if (rnd(1,2) == 1) {
return "punch";
} else {
return "hit";
}
} else if (damtype == DT_TOUCH) { } else if (damtype == DT_TOUCH) {
return "touch"; return "touch";
} }
@ -635,12 +766,13 @@ enum DAMTYPE getdamtype(object_t *wep) {
return dt; return dt;
} }
int getextradam(object_t *wep, int *dam, enum DAMTYPE *damtype) { int getextradam(object_t *wep, int *dam, enum DAMTYPE *damtype, int *ndam) {
flag_t *f; flag_t *f;
for (f = wep->flags->first ; f ; f = f->next) { for (f = wep->flags->first ; f ; f = f->next) {
if (f->id == F_ONFIRE) { if (f->id == F_ONFIRE) {
*dam = rnd(5,10); // TODO: don't hardcode? *(dam + *ndam) = rolldie(2,8);
*damtype = DT_FIRE; *(damtype + *ndam) = DT_FIRE;
(*ndam)++;
} }
} }
return *dam; return *dam;
@ -667,7 +799,7 @@ char *getkillverb(lifeform_t *victim, enum DAMTYPE damtype, int dam, int maxhp)
if (lfhasflagval(victim, F_NOBODYPART, BP_HEAD, NA, NA, NULL)) { if (lfhasflagval(victim, F_NOBODYPART, BP_HEAD, NA, NA, NULL)) {
return "bisect"; return "bisect";
} else { } else {
if (rnd(1,3)) { if (rnd(1,3) == 1) {
return "behead"; return "behead";
} else { } else {
return "bisect"; return "bisect";
@ -771,9 +903,8 @@ int getdamroll(object_t *o, lifeform_t *victim) {
} }
} else { } else {
// TODO wepaon does damage based on weight // TODO wepaon does bashing damage based on weight
// weapon does no damage dam = rnd(1,2);
dam = 0;
} }
// modify for bonus // modify for bonus
@ -938,10 +1069,58 @@ obpile_t *getunarmedweapon(lifeform_t *lf,flag_t **uflag) {
return op; return op;
} }
int rolltohit(lifeform_t *lf, lifeform_t *victim, int *critical) {
int acc,ev;
object_t *wep;
obpile_t *op = NULL;
int gothit;
if (critical) {
*critical = 0;
}
acc = getlfaccuracy(lf);
wep = getattackwep(lf, &op, NULL);
// modify for defender's evasion
ev = getevasion(victim);
acc -= ev;
// metal weapon versus magnetic shield?
if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) {
acc -= 45;
}
if (critical) {
if (rnd(1,20) == 20) *critical = 1;
}
if (acc < 0) acc = 0;
if (acc > 100) acc = 100;
//if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc);
if (rnd(1,100) <= acc) {
gothit = B_TRUE;
} else {
if (critical && *critical) {
// turn a miss into a hit
gothit = B_TRUE;
} else {
gothit = B_FALSE;
}
}
if (op) killobpile(op);
return gothit;
}
void wepeffects(object_t *wep, cell_t *where) { void wepeffects(object_t *wep, cell_t *where) {
flag_t *f; flag_t *f;
lifeform_t *victim; lifeform_t *victim;
lifeform_t *owner;
owner = wep->pile->owner;
victim = where->lf; victim = where->lf;
if (!where) return; if (!where) return;
@ -1024,6 +1203,12 @@ void wepeffects(object_t *wep, cell_t *where) {
} }
} // end if dampct > 50 } // end if dampct > 50
} }
} else if ((f->id == F_HEAVYBLOW) && victim && owner) {
int dir;
// knock back victim
dir = getdirtowards(owner->cell, victim->cell, victim, B_FALSE);
knockback(victim, dir , 2, owner);
f->known = B_TRUE;
} }
} }
} }

View File

@ -1,12 +1,15 @@
#include "defs.h" #include "defs.h"
int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype);
void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int *dam, enum DAMTYPE damtype);
int attackcell(lifeform_t *lf, cell_t *c); int attackcell(lifeform_t *lf, cell_t *c);
int attacklf(lifeform_t *lf, lifeform_t *victim); int attacklf(lifeform_t *lf, lifeform_t *victim);
int attackob(lifeform_t *lf, object_t *o); int attackob(lifeform_t *lf, object_t *o);
int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype);
char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp); char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp);
object_t *getattackwep(lifeform_t *lf, obpile_t **unarmedpile, flag_t **unarmedflag); object_t *getattackwep(lifeform_t *lf, obpile_t **unarmedpile, flag_t **unarmedflag);
enum DAMTYPE getdamtype(object_t *wep); enum DAMTYPE getdamtype(object_t *wep);
int getextradam(object_t *wep, int *dam, enum DAMTYPE *damtype); int getextradam(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, enum DAMTYPE damtype, int dam, int maxhp);
void getdamrange(flagpile_t *fp, int *min, int *max); void getdamrange(flagpile_t *fp, int *min, int *max);
void getdamrangeunarmed(flag_t *f, int *min, int *max); void getdamrangeunarmed(flag_t *f, int *min, int *max);
@ -15,4 +18,5 @@ int getdamroll(object_t *o, lifeform_t *victim);
int getdamrollfromflag(flag_t *f); int getdamrollfromflag(flag_t *f);
float getstrdammod(lifeform_t *lf); float getstrdammod(lifeform_t *lf);
obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag); obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag);
int rolltohit(lifeform_t *lf, lifeform_t *victim, int *critical);
void wepeffects(object_t *wep, cell_t *where); void wepeffects(object_t *wep, cell_t *where);

278
defs.h
View File

@ -25,6 +25,16 @@ enum ATTRIB {
}; };
#define MAXATTS 3 #define MAXATTS 3
enum CHECKTYPE {
SC_STR,
SC_DEX,
SC_IQ,
//////////
SC_DODGE,
SC_SLIP,
SC_MORALE,
};
enum BURDENED { enum BURDENED {
BR_NONE = 0, BR_NONE = 0,
BR_BURDENED = 1, BR_BURDENED = 1,
@ -68,6 +78,7 @@ enum LFCONDITION {
#define IFKNOWN (-9772) // used by f_xxconfer. only confer a flag if item is known. #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 #define IFACTIVE (-9771) // used by f_prodeuceslight. only does so if object is activated
#define NOCONDITION (0)
#define IFMONSTER (-9769) // used in v2 of f_ifpct job flags #define IFMONSTER (-9769) // used in v2 of f_ifpct job flags
#define IFPLAYER (-9768) // used in v2 of f_ifpct job flags #define IFPLAYER (-9768) // used in v2 of f_ifpct job flags
@ -102,7 +113,7 @@ enum LFCONDITION {
#define MAXRANDOMOBCANDIDATES 100 #define MAXRANDOMOBCANDIDATES 100
#define MAXRANDOMLFCANDIDATES 100 #define MAXRANDOMLFCANDIDATES 100
#define MAXCANDIDATES 50 #define MAXCANDIDATES 200
//#define MAX_MAPW 80 //#define MAX_MAPW 80
//#define MAX_MAPH 50 //#define MAX_MAPH 50
@ -128,7 +139,7 @@ enum LFCONDITION {
#define DEF_SPARSENESS 20 #define DEF_SPARSENESS 20
//#define DEF_SPARSENESS 0 //#define DEF_SPARSENESS 0
//#define DEF_LOOPPCT 70 //#define DEF_LOOPPCT 70
#define DEF_LOOPPCT 85 #define DEF_LOOPPCT 95
//#define DEF_LOOPPCT 0 //#define DEF_LOOPPCT 0
#define MINROOMS 5 #define MINROOMS 5
#define MAXROOMS 10 #define MAXROOMS 10
@ -240,21 +251,25 @@ enum CELLTYPE {
CT_LOOPCORRIDOR, CT_LOOPCORRIDOR,
}; };
enum SPELLSCHOOL { enum SPELLSCHOOL {
SS_DIVINE = 2, SS_NONE,
SS_ABILITY = 0, SS_DIVINE,
SS_ALLOMANCY = 1, SS_ABILITY,
SS_DEATH = 3, SS_ALLOMANCY,
SS_ELEMENTAL = 4, SS_AIR,
SS_DIVINATION = 5, SS_DEATH,
SS_GRAVITY = 6, SS_DIVINATION,
SS_LIFE = 7, SS_FIRE,
SS_MODIFICATION = 8, SS_ICE,
SS_MENTAL = 9, SS_GRAVITY,
SS_SUMMONING = 10, SS_LIFE,
SS_TRANSLOCATION = 11, SS_MODIFICATION,
SS_WILD = 12, SS_MENTAL,
SS_LAST = 13, SS_SUMMONING,
SS_TRANSLOCATION,
SS_WILD,
SS_LAST,
}; };
enum STRBRACKET { enum STRBRACKET {
@ -318,15 +333,17 @@ enum DAMTYPE {
DT_MAGIC = 17, DT_MAGIC = 17,
DT_TOUCH = 18, DT_TOUCH = 18,
DT_POISONGAS = 19, DT_POISONGAS = 19,
DT_NONE = 20, // for direclty dealt damage, not really any type DT_UNARMED = 20,
DT_NONE = 21, // for direclty dealt damage, not really any type
}; };
#define MAXDAMTYPE 21 #define MAXDAMTYPE 22
// Object Classes // Object Classes
enum OBCLASS { enum OBCLASS {
OC_MONEY, OC_MONEY,
OC_WEAPON, OC_WEAPON,
OC_ARMOUR, OC_ARMOUR,
OC_MISSILE,
OC_RING, OC_RING,
OC_SCROLL, OC_SCROLL,
OC_POTION, OC_POTION,
@ -374,21 +391,33 @@ enum RACE {
// monsters // monsters
R_BUGBEAR, R_BUGBEAR,
R_EYEBAT, R_EYEBAT,
R_GIANT, R_GIANTHILL,
R_GIANTFIRE,
R_GIANTFIREFC,
R_GIANTFIRETITAN,
R_GNOLL, R_GNOLL,
R_GNOLLHM,
R_GNOLLMR,
R_GOBLIN, R_GOBLIN,
R_GOBLINGUARD, R_GOBLINWAR,
R_GOBLINCHAMP, R_GOBLINSHOOTER,
R_GOBLINHEXER,
R_HOBGOBLIN, R_HOBGOBLIN,
R_HOBGOBLINWAR,
R_KOBOLD,
R_LIZARDMAN, R_LIZARDMAN,
R_LURKINGHORROR, R_LURKINGHORROR,
R_OGRE, R_OGRE,
R_OGRESAVAGE,
R_OGREWARHULK,
R_OOZEGREY,
R_ORC, R_ORC,
R_ORCWARRIOR,
R_ORK, R_ORK,
R_POLTERGEIST, R_POLTERGEIST,
R_SHADOWCAT, R_SHADOWCAT,
R_SLIME,
R_SPRITEFIRE, R_SPRITEFIRE,
R_TROGLODYTE,
R_TROLL, R_TROLL,
R_XAT, R_XAT,
// small animals // small animals
@ -397,6 +426,7 @@ enum RACE {
R_RAT, R_RAT,
R_WOLF, R_WOLF,
// insects // insects
R_BUTTERFLY,
R_GLOWBUG, R_GLOWBUG,
R_GIANTFLY, R_GIANTFLY,
R_GIANTBLOWFLY, R_GIANTBLOWFLY,
@ -452,6 +482,7 @@ enum OBTYPE {
OT_NONE, OT_NONE,
// dungeon features // dungeon features
OT_BOULDER, OT_BOULDER,
OT_STATUE,
OT_WOODENDOOR, OT_WOODENDOOR,
OT_WOODENTABLE, OT_WOODENTABLE,
OT_WOODENBARREL, OT_WOODENBARREL,
@ -469,6 +500,7 @@ enum OBTYPE {
OT_BERRY, OT_BERRY,
OT_NUT, OT_NUT,
OT_BANANA, OT_BANANA,
OT_BANANASKIN, // not really food
OT_APPLE, OT_APPLE,
OT_MUSHROOM, OT_MUSHROOM,
OT_BREADSTALE, OT_BREADSTALE,
@ -501,6 +533,7 @@ enum OBTYPE {
OT_POT_ELEMENTENDURE, OT_POT_ELEMENTENDURE,
OT_POT_ELEMENTIMMUNE, OT_POT_ELEMENTIMMUNE,
OT_POT_ETHEREALNESS, OT_POT_ETHEREALNESS,
OT_POT_EXPERIENCE,
OT_POT_GASEOUSFORM, OT_POT_GASEOUSFORM,
OT_POT_HEALING, OT_POT_HEALING,
OT_POT_HEALINGMIN, OT_POT_HEALINGMIN,
@ -521,6 +554,7 @@ enum OBTYPE {
OT_SCR_DETECTLIFE, OT_SCR_DETECTLIFE,
OT_SCR_DETECTMAGIC, OT_SCR_DETECTMAGIC,
OT_SCR_FLAMEPILLAR, OT_SCR_FLAMEPILLAR,
OT_SCR_FLAMEBURST,
OT_SCR_IDENTIFY, OT_SCR_IDENTIFY,
OT_SCR_KNOCK, OT_SCR_KNOCK,
OT_SCR_LIGHT, OT_SCR_LIGHT,
@ -535,18 +569,28 @@ enum OBTYPE {
// SPELLBOOKS // SPELLBOOKS
// allomancy can't be learned from books // allomancy can't be learned from books
// -- death // -- death
OT_SB_ANIMATEDEAD,
OT_SB_PAIN,
OT_SB_INFINITEDEATH, OT_SB_INFINITEDEATH,
OT_SB_WEAKEN, OT_SB_WEAKEN,
OT_SB_BLINDNESS,
// -- divination // -- divination
OT_SB_DETECTAURA, OT_SB_DETECTAURA,
OT_SB_DETECTLIFE, OT_SB_DETECTLIFE,
OT_SB_IDENTIFY, OT_SB_IDENTIFY,
OT_SB_MAPPING, OT_SB_MAPPING,
// -- elemental // -- elemental - air
OT_SB_CLOUDKILL,
// -- elemental - fire
OT_SB_SPARK,
OT_SB_FIREDART, OT_SB_FIREDART,
OT_SB_CONECOLD,
OT_SB_FIREBALL, OT_SB_FIREBALL,
OT_SB_FLAMEPILLAR, OT_SB_FLAMEPILLAR,
OT_SB_FLAMEBURST,
OT_SB_BURNINGWAVE,
// -- elemental - ice
OT_SB_CONECOLD,
OT_SB_FREEZEOB,
// -- gravity // -- gravity
OT_SB_GRAVBOOST, OT_SB_GRAVBOOST,
OT_SB_HASTE, OT_SB_HASTE,
@ -559,12 +603,13 @@ enum OBTYPE {
OT_SB_MINDSCAN, OT_SB_MINDSCAN,
OT_SB_TELEKINESIS, OT_SB_TELEKINESIS,
// -- modification // -- modification
OT_SB_FREEZEOB,
OT_SB_GASEOUSFORM, OT_SB_GASEOUSFORM,
OT_SB_KNOCK, OT_SB_KNOCK,
OT_SB_INSCRIBE, OT_SB_INSCRIBE,
OT_SB_LIGHT, OT_SB_LIGHT,
OT_SB_DARKNESS,
OT_SB_PASSWALL, OT_SB_PASSWALL,
OT_SB_PETRIFY,
OT_SB_POLYMORPH, OT_SB_POLYMORPH,
OT_SB_POLYMORPHRND, OT_SB_POLYMORPHRND,
// -- summoning // -- summoning
@ -586,19 +631,29 @@ enum OBTYPE {
OT_S_MAGSHIELD, OT_S_MAGSHIELD,
OT_S_METALHEAL, OT_S_METALHEAL,
// -- death // -- death
OT_S_ANIMATEDEAD,
OT_S_PAIN,
OT_S_INFINITEDEATH, OT_S_INFINITEDEATH,
OT_S_WEAKEN, OT_S_WEAKEN,
OT_S_BLINDNESS,
// -- divination // -- divination
OT_S_DETECTAURA, OT_S_DETECTAURA,
OT_S_DETECTLIFE, OT_S_DETECTLIFE,
OT_S_DETECTMAGIC, OT_S_DETECTMAGIC,
OT_S_IDENTIFY, OT_S_IDENTIFY,
OT_S_MAPPING, OT_S_MAPPING,
// -- elemental // -- elemental - air
OT_S_CLOUDKILL,
// -- elemental - fire
OT_S_SPARK,
OT_S_FIREDART, OT_S_FIREDART,
OT_S_CONECOLD,
OT_S_FIREBALL, OT_S_FIREBALL,
OT_S_FLAMEPILLAR, OT_S_FLAMEPILLAR,
OT_S_FLAMEBURST,
OT_S_BURNINGWAVE,
// -- elemental - ice
OT_S_CONECOLD,
OT_S_FREEZEOB,
// -- gravity // -- gravity
OT_S_GRAVBOOST, OT_S_GRAVBOOST,
OT_S_HASTE, OT_S_HASTE,
@ -609,15 +664,17 @@ enum OBTYPE {
OT_S_TURNUNDEAD, OT_S_TURNUNDEAD,
// -- mental // -- mental
OT_S_MINDSCAN, OT_S_MINDSCAN,
OT_S_SLEEP,
OT_S_TELEKINESIS, OT_S_TELEKINESIS,
// -- modification // -- modification
OT_S_ENCHANT, OT_S_ENCHANT,
OT_S_FREEZEOB,
OT_S_GASEOUSFORM, OT_S_GASEOUSFORM,
OT_S_INSCRIBE, OT_S_INSCRIBE,
OT_S_KNOCK, OT_S_KNOCK,
OT_S_LIGHT, OT_S_LIGHT,
OT_S_DARKNESS,
OT_S_PASSWALL, OT_S_PASSWALL,
OT_S_PETRIFY,
OT_S_POLYMORPH, OT_S_POLYMORPH,
OT_S_POLYMORPHRND, OT_S_POLYMORPHRND,
// -- summoning // -- summoning
@ -638,10 +695,12 @@ enum OBTYPE {
OT_S_WISH, OT_S_WISH,
OT_S_GIFT, OT_S_GIFT,
// abilities // abilities
OT_A_GRAB,
OT_A_JUMP, OT_A_JUMP,
OT_A_SPRINT, OT_A_SPRINT,
OT_A_DEBUG, OT_A_DEBUG,
OT_A_EMPLOY, OT_A_EMPLOY,
OT_A_HEAVYBLOW,
// wands // wands
OT_WAND_COLD, OT_WAND_COLD,
OT_WAND_DETONATION, OT_WAND_DETONATION,
@ -653,6 +712,7 @@ enum OBTYPE {
OT_WAND_POLYMORPH, OT_WAND_POLYMORPH,
OT_WAND_SLOW, OT_WAND_SLOW,
OT_WAND_WEAKNESS, OT_WAND_WEAKNESS,
OT_WAND_WONDER,
// tech/tools // tech/tools
OT_BLINDFOLD, OT_BLINDFOLD,
OT_POCKETWATCH, OT_POCKETWATCH,
@ -682,11 +742,13 @@ enum OBTYPE {
OT_CALTROP, OT_CALTROP,
OT_BROKENGLASS, OT_BROKENGLASS,
OT_ICECHUNK, OT_ICECHUNK,
OT_ICESHEET,
OT_PUDDLEWATER, OT_PUDDLEWATER,
OT_PUDDLEWATERL, OT_PUDDLEWATERL,
OT_SLIMEPOOL, OT_SLIMEPOOL,
OT_VOMITPOOL, OT_VOMITPOOL,
OT_BLOODSTAIN, OT_BLOODSTAIN,
OT_BLOODSPLASH,
OT_BLOODPOOL, OT_BLOODPOOL,
OT_SOGGYPAPER, OT_SOGGYPAPER,
OT_FLESHCHUNK, OT_FLESHCHUNK,
@ -701,6 +763,11 @@ enum OBTYPE {
OT_POISONPUFF, OT_POISONPUFF,
// armour - body // armour - body
OT_ARMOURLEATHER, OT_ARMOURLEATHER,
OT_ARMOURRING,
OT_ARMOURSCALE,
OT_ARMOURCHAIN,
OT_ARMOURSPLINT,
OT_ARMOURPLATE,
OT_FLAKJACKET, OT_FLAKJACKET,
OT_OVERALLS, OT_OVERALLS,
OT_COTTONSHIRT, OT_COTTONSHIRT,
@ -720,6 +787,7 @@ enum OBTYPE {
OT_SHOESLEATHER, OT_SHOESLEATHER,
OT_BOOTSLEATHER, OT_BOOTSLEATHER,
OT_BOOTSRUBBER, OT_BOOTSRUBBER,
OT_BOOTSSPIKED,
// armour - hands // armour - hands
OT_GLOVESCLOTH, OT_GLOVESCLOTH,
OT_GLOVESLEATHER, OT_GLOVESLEATHER,
@ -736,6 +804,8 @@ enum OBTYPE {
OT_SUNGLASSES, OT_SUNGLASSES,
// armour - shields // armour - shields
OT_BUCKLER, OT_BUCKLER,
OT_SHIELD,
OT_SHIELDLARGE,
// rings // rings
OT_RING_INVULN, OT_RING_INVULN,
OT_RING_MPREGEN, OT_RING_MPREGEN,
@ -752,6 +822,14 @@ enum OBTYPE {
OT_ACIDATTACK, OT_ACIDATTACK,
OT_TOUCHPARALYZE, OT_TOUCHPARALYZE,
OT_TOUCHPARALYZE2, OT_TOUCHPARALYZE2,
// missiles / ammo
OT_ARROW,
OT_BOLT,
OT_DART,
OT_NANODART,
OT_JAVELIN,
OT_BULLET,
OT_RUBBERBULLET,
// stabbing weapons // stabbing weapons
OT_DAGGER, OT_DAGGER,
OT_COMBATKNIFE, OT_COMBATKNIFE,
@ -761,6 +839,7 @@ enum OBTYPE {
OT_QUICKBLADE, OT_QUICKBLADE,
// chopping weapons // chopping weapons
OT_AXE, OT_AXE,
OT_HANDAXE,
OT_BATTLEAXE, OT_BATTLEAXE,
OT_GREATAXE, OT_GREATAXE,
// slashing weapons // slashing weapons
@ -770,6 +849,7 @@ enum OBTYPE {
OT_SHORTSWORD, OT_SHORTSWORD,
OT_SCIMITAR, OT_SCIMITAR,
OT_LONGSWORD, OT_LONGSWORD,
OT_GREATSWORD,
OT_ORNSWORD, OT_ORNSWORD,
// polearms // polearms
OT_SPEAR, OT_SPEAR,
@ -778,6 +858,8 @@ enum OBTYPE {
OT_STICK, OT_STICK,
OT_SPANNER, OT_SPANNER,
OT_CLUB, OT_CLUB,
OT_FLAIL,
OT_FLAILHEAVY,
OT_MACE, OT_MACE,
OT_MORNINGSTAR, OT_MORNINGSTAR,
OT_GREATCLUB, OT_GREATCLUB,
@ -785,9 +867,9 @@ enum OBTYPE {
// projectile weapons // projectile weapons
OT_REVOLVER, OT_REVOLVER,
OT_SLING, OT_SLING,
// ammo OT_BOW,
OT_BULLET, OT_LONGBOW,
OT_RUBBERBULLET, OT_CROSSBOWHAND,
// holy weapons // holy weapons
OT_HANDOFGOD, OT_HANDOFGOD,
@ -822,14 +904,15 @@ enum NOISETYPE {
}; };
enum LFSIZE { enum LFSIZE {
SZ_MINI, // ie. fly SZ_MINI = 0, // ie. fly
SZ_TINY, // ie. mouse SZ_TINY = 1, // ie. mouse
SZ_SMALL, // ie. cat SZ_SMALL = 2, // ie. cat
SZ_MEDIUM, // ie. wolf/dog SZ_MEDIUM = 3, // ie. wolf/dog
SZ_HUMAN, // ie. human-sized SZ_HUMAN = 4, // ie. human-sized
SZ_LARGE, // ie. bear/horse SZ_LARGE = 5, // ie. bear/horse
SZ_HUGE, // ie. elephant, dragon SZ_HUGE = 6, // ie. elephant, dragon, giant
SZ_ENORMOUS, // ie. ??? kraken? SZ_ENORMOUS = 7, // ie. ??? kraken, titan
SZ_MAX = 100
}; };
@ -854,7 +937,8 @@ enum FLAG {
F_UNIQUE, // only one may appear F_UNIQUE, // only one may appear
F_GLYPH, // override the glyph with the first char of text F_GLYPH, // override the glyph with the first char of text
F_NOPICKUP, // cannot pick this up F_NOPICKUP, // cannot pick this up
F_IMPASSABLE, // cannot walk past this F_IMPASSABLE, // cannot walk past this if your size if v0 or smaller
F_CRUSHABLE, // if you are bigger than size v0, walking on this crushes it
F_BLOCKSVIEW, // cannot see past this F_BLOCKSVIEW, // cannot see past this
F_BLOCKSTHROW, // cannot throw past this F_BLOCKSTHROW, // cannot throw past this
F_DIETEXT, // text when the object dies F_DIETEXT, // text when the object dies
@ -918,15 +1002,22 @@ enum FLAG {
F_STAIRDIR, // val0 = direcion F_STAIRDIR, // val0 = direcion
F_OPPOSITESTAIRS, // val0 = opposite kind of stairs F_OPPOSITESTAIRS, // val0 = opposite kind of stairs
F_MAPLINK, // val0 = map to link to. optional v1/v2 = x/y F_MAPLINK, // val0 = map to link to. optional v1/v2 = x/y
// ob interaction flags
F_SHARP, // does damage when you step on it. v0/1 are min/max dam
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 F_FLAMMABLE, // object will catch alight if burnt
// object mods/effects // object mods/effects
F_ONFIRE, // burning, also deals extra fire damage F_ONFIRE, // burning, also deals extra fire damage
F_HEADLESS, // for corpses F_HEADLESS, // for corpses. can go on LFs too.
// weapon flags // weapon flags
F_OBATTACKDELAY, // how long weapon takes to attack F_OBATTACKDELAY, // how long weapon takes to attack
F_DAMTYPE, // val0 = damage type F_DAMTYPE, // val0 = damage type
F_DAM, // val0 = ndice, val1 = nsidesondie, val2 = mod F_DAM, // val0 = ndice, val1 = nsidesondie, val2 = mod
F_MISSILEDAM, // val0 = dam if it hits (without speed multiplier)
F_ACCURACY, // 100 - val0 = penalty to tohit% (ie. higher is better) F_ACCURACY, // 100 - val0 = penalty to tohit% (ie. higher is better)
F_ARMOURPIERCE, // goes through armour
F_TWOHANDED, // weapon uses two hands to weild F_TWOHANDED, // weapon uses two hands to weild
F_FIREARM, // this weapon is equipped in bp_secweapon, not _weapon. F_FIREARM, // this weapon is equipped in bp_secweapon, not _weapon.
F_FIRESPEED, // how fast this weapon shoots projectimes F_FIRESPEED, // how fast this weapon shoots projectimes
@ -934,7 +1025,7 @@ enum FLAG {
F_RANGE, // range of projectile firing weapon F_RANGE, // range of projectile firing weapon
F_FLAMESTRIKE, // causes fires where you hit F_FLAMESTRIKE, // causes fires where you hit
F_BALANCE, // heals target if their maxhp < your maxhp F_BALANCE, // heals target if their maxhp < your maxhp
F_REVENGE, // causes damage based on your max hp F_REVENGE, // causes damage based on your hp
// tech flags // tech flags
F_RNDCHARGES, // ob starts with between val0 and val1 charges F_RNDCHARGES, // ob starts with between val0 and val1 charges
// this will cause F_CHARGES to be filled in // this will cause F_CHARGES to be filled in
@ -944,7 +1035,6 @@ enum FLAG {
F_REFILLWITH, // pour obj id val0 onto this to refill its charges F_REFILLWITH, // pour obj id val0 onto this to refill its charges
// ob appearance flags // ob appearance flags
F_SHINY, F_SHINY,
F_SHARP, // does damage when you step on it. v0/1 are min/max dam
// armour flags // armour flags
F_ARMOURRATING, // val0 * 2 = pct of damage reduced F_ARMOURRATING, // val0 * 2 = pct of damage reduced
F_SHIELD, // this is a shield - use special bodyhitchance code F_SHIELD, // this is a shield - use special bodyhitchance code
@ -967,8 +1057,13 @@ enum FLAG {
F_MPCOST, // v0=mp cost of spell. if missing, mpcost if splev^2 F_MPCOST, // v0=mp cost of spell. if missing, mpcost if splev^2
//F_SPELLLETTER, // text[0] = letter to cast this spell //F_SPELLLETTER, // text[0] = letter to cast this spell
F_AICASTATVICTIM, // hints for AI to cast spells F_AICASTATVICTIM, // hints for AI to cast spells
F_AICASTATADJVICTIM, // hints for AI to cast spells
F_AICASTATSELF, // hints for AI to cast spells F_AICASTATSELF, // hints for AI to cast spells
F_AICASTNEXTTOVICTIM, // hints for AI to cast spells
F_AICASTANYWHERE, // hints for AI to cast spells F_AICASTANYWHERE, // hints for AI to cast spells
F_AIBOOSTITEM, // ai will use this item to boost/buff itself
F_AIHEALITEM, // ai will use this item when low on hp
F_AIFLEEITEM, // ai will use this item when fleeing
// lifeform flags // lifeform flags
F_DEBUG, // debugging enabled F_DEBUG, // debugging enabled
F_ATTRMOD, // modify attribute val0 by val1. ie. 0=A_STR,1=-3 F_ATTRMOD, // modify attribute val0 by val1. ie. 0=A_STR,1=-3
@ -990,6 +1085,7 @@ enum FLAG {
F_STARTSTR, // val0 = start str bracket (ie. STR_STRONG) F_STARTSTR, // val0 = start str bracket (ie. STR_STRONG)
F_CORPSETYPE, // text field specifies what corpse obtype to leave F_CORPSETYPE, // text field specifies what corpse obtype to leave
F_NOCORPSE, // monster's body crumbles to dust after death 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) F_VISRANGE, // how far you can see (in the light)
F_VISRANGEMOD, // modifications to visrange F_VISRANGEMOD, // modifications to visrange
F_GUNTARGET, // current projectile weapon target F_GUNTARGET, // current projectile weapon target
@ -1005,6 +1101,8 @@ enum FLAG {
F_WANTSBETTERWEP, // lf will look for better weapons, val1=covets F_WANTSBETTERWEP, // lf will look for better weapons, val1=covets
F_WANTSBETTERARM, // lf will look for better armour, val1=covets F_WANTSBETTERARM, // lf will look for better armour, val1=covets
F_FLEEONDAM, // lf will run away instead of counterattacking F_FLEEONDAM, // lf will run away instead of counterattacking
F_FLEEONHPPCT, // lf will run away if its hp drop to v0% or lower
F_NOFLEE, // lf will not run away
F_TARGET, // lf will attack lfid v0. lastknown x/y is v1/v2 F_TARGET, // lf will attack lfid v0. lastknown x/y is v1/v2
F_TARGETCELL, // lf will go towards this place. val0=x,val1=y F_TARGETCELL, // lf will go towards this place. val0=x,val1=y
F_FLEEFROM, // lf will run away from this lf id F_FLEEFROM, // lf will run away from this lf id
@ -1044,10 +1142,18 @@ enum FLAG {
F_INDUCEFEAR, // causes fear when you attack it F_INDUCEFEAR, // causes fear when you attack it
F_AUTOCREATEOB, // produces obtype 'text' wherever it walks, v0=radius F_AUTOCREATEOB, // produces obtype 'text' wherever it walks, v0=radius
// (only if ob of that type not already there) // (only if ob of that type not already there)
F_PACKATTACK, // deal v0 extra damage of type v1 if there are
// v2 or more monsters matching f->text next
// to the victim
F_PHALANX, // gain v0 AR if v2 or more adj monsters matching f->text
// INTRINSICS // INTRINSICS
F_ASLEEP, // is asleep
F_BLIND, // cannot see anything F_BLIND, // cannot see anything
F_CANCAST, // can cast the spell val0 (need MP) F_CANCAST, // can cast the spell val0 (need MP)
F_CANWILL, // can cast the spell val0 without using MP F_CANWILL, // can cast the spell val0 without using MP
// v1 is counter untiluse
// v2 is what you need to use it
// ie. when v1 == v2, ability is ready.
F_DETECTAURAS, // autodetect bless/curse F_DETECTAURAS, // autodetect bless/curse
F_DETECTLIFE, // autodetect nearby lifeforms in orthogonal dist v0 F_DETECTLIFE, // autodetect nearby lifeforms in orthogonal dist v0
F_DETECTMAGIC, // autodetect magic/special objects F_DETECTMAGIC, // autodetect magic/special objects
@ -1058,12 +1164,19 @@ enum FLAG {
F_FASTMOVE, // modifier for move speed F_FASTMOVE, // modifier for move speed
F_FOODPOISONED, // has food poisoning F_FOODPOISONED, // has food poisoning
F_FREEZINGTOUCH,// next thing touched turns to ice! 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_QUICKBITE, // deals v0 d d1 + d2 damage when you hit a bleeding victim
// (bypasses armour)
F_GRAVBOOSTED,// cannot walk or throw stuff F_GRAVBOOSTED,// cannot walk or throw stuff
F_PAIN, // take damage if you walk
F_PARALYZED,// cannot do anything F_PARALYZED,// cannot do anything
F_FROZEN, // made of ice F_FROZEN, // made of ice
F_INVULNERABLE,// immune to most damage F_INVULNERABLE,// immune to most damage
F_LEVITATING, // like flying but uncontrolled F_LEVITATING, // like flying but uncontrolled
F_MAGSHIELD,// magnetic shield F_MAGSHIELD,// magnetic shield
F_NAUSEATED, // lf has a stench penalty of v0 (-v0*10 to hit).
F_NONCORPOREAL,// can walk through walls F_NONCORPOREAL,// can walk through walls
F_OMNIPOTENT, // knows extra info F_OMNIPOTENT, // knows extra info
F_PHOTOMEM, // you don't forget your surroundings F_PHOTOMEM, // you don't forget your surroundings
@ -1071,6 +1184,9 @@ enum FLAG {
F_RESISTMAG, // immune to most magic effects F_RESISTMAG, // immune to most magic effects
F_MPREGEN, // regenerate MP at val0 per turn F_MPREGEN, // regenerate MP at val0 per turn
F_SEEINDARK, // nightvis range is val0 F_SEEINDARK, // nightvis range is val0
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. F_PRODUCESLIGHT, // produces light of val0 radius.
// (but not for obs in pack) // (but not for obs in pack)
// if val2 is true, will only make light if ob // if val2 is true, will only make light if ob
@ -1081,6 +1197,8 @@ enum FLAG {
F_CANSEETHROUGHMAT, //val0=kind of material you can see through F_CANSEETHROUGHMAT, //val0=kind of material you can see through
F_SPRINTING, // you are sprinting F_SPRINTING, // you are sprinting
F_TIRED, // you are too tired to sprint F_TIRED, // you are too tired to sprint
F_DODGES, // you dodge missed attacks
F_NOTIME, // this lf's actions don't take time
// COMBAT // COMBAT
F_HASATTACK, // objecttype id to use when attacking unarmed F_HASATTACK, // objecttype id to use when attacking unarmed
// if val0-3 are filled in, they override the object's // if val0-3 are filled in, they override the object's
@ -1096,8 +1214,11 @@ enum FLAG {
// for jobs // for jobs
F_IFPCT, // only add the NEXT job flag if rnd(1,100) <= v0. F_IFPCT, // only add the NEXT job flag if rnd(1,100) <= v0.
// if v2=IFMONSTER, also only add the next one for non-players F_ELSE,
// if v2=IFPLAYER, also only add the next one for players F_IFPLAYER,
F_IFMONSTER,
F_ENDIFPLAYER,
F_ENDIFMONSTER,
// //
F_NULL = -1 F_NULL = -1
@ -1126,8 +1247,16 @@ enum HUNGER {
#define B_FALSE (0) #define B_FALSE (0)
#define B_TRUE (-1) #define B_TRUE (-1)
#define B_TEMP (-1) //#define B_TEMP (-1)
#define B_PERM (-2) //#define B_PERM (-2)
//#define B_NOT (-3)
enum LIGHTLEV {
L_DARK = -1,
L_NOTLIT = 0,
L_TEMP = 1,
L_PERM = 2,
};
#define B_DIEONFAIL (-1) #define B_DIEONFAIL (-1)
#define B_BLUNTONFAIL (-2) #define B_BLUNTONFAIL (-2)
@ -1200,8 +1329,58 @@ enum ERROR {
E_NOMP = 27, E_NOMP = 27,
E_AVOIDOB = 28, E_AVOIDOB = 28,
E_FROZEN = 29, E_FROZEN = 29,
E_TOOBIG = 30,
E_NOTREADY = 31,
E_BLIND = 32,
E_GRABBEDBY = 33,
E_CANTMOVE = 34,
}; };
enum COMMAND {
CMD_AIM,
CMD_CLOSE,
CMD_DOWN,
CMD_DROP,
CMD_DROPMULTI,
CMD_EAT,
CMD_FIRE,
CMD_FIRENEW,
CMD_FORCEATTACK,
CMD_HELP,
CMD_INFOARMOUR,
CMD_INFOKNOWLEDGE,
CMD_INFOPLAYER,
CMD_INV,
CMD_LOOKAROUND,
CMD_LOOKHERE,
CMD_MAGIC,
CMD_MSGHIST,
CMD_OPERATE,
CMD_PICKLOCK,
CMD_PICKUP,
CMD_POUR,
CMD_QUAFF,
CMD_QUIT,
CMD_READ,
CMD_REST,
CMD_RESTFULL,
CMD_SAVEQUIT,
CMD_TAKEOFF,
CMD_UP,
CMD_WEAR,
CMD_WEILD,
};
// command types
typedef struct command_s {
enum COMMAND id;
char ch;
char *desc;
struct command_s *next, *prev;
} command_t;
typedef struct map_s { typedef struct map_s {
int id; int id;
int depth; int depth;
@ -1223,7 +1402,7 @@ typedef struct cell_s {
int roomid; int roomid;
struct celltype_s *type; struct celltype_s *type;
struct obpile_s *obpile; struct obpile_s *obpile;
int lit; enum LIGHTLEV lit;
char *writing; char *writing;
@ -1252,6 +1431,7 @@ typedef struct celltype_s {
typedef struct race_s { typedef struct race_s {
enum RACE id; enum RACE id;
enum RACE baseid;
struct material_s *material; struct material_s *material;
char *name; char *name;
char glyph; char glyph;
@ -1409,10 +1589,12 @@ enum OBMOD {
OM_FEEBLENESS, OM_FEEBLENESS,
OM_FLIGHT, OM_FLIGHT,
OM_GIANTSTRENGTH, OM_GIANTSTRENGTH,
OM_IMPACT,
OM_INTELLIGENCE, OM_INTELLIGENCE,
OM_KNOWLEDGE, OM_KNOWLEDGE,
OM_LEVITATION, OM_LEVITATION,
OM_MAGRESIST, OM_MAGRESIST,
OM_SHARPNESS,
OM_PYROMANIA, OM_PYROMANIA,
OM_REVENGE, OM_REVENGE,
OM_SLOTH, OM_SLOTH,

View File

@ -8,3 +8,8 @@ in objcets.c:
in attack.c in attack.c
update getattackverb if required update getattackverb if required
update getkillverb if required update getkillverb if required
update attackob() to say whether dealing this damtype to an object
will dull a weapon.
ie. hitting a door with DT_CHOP won't damage the weapon
ie. hitting a door with DT_SLASH _will_ damage the weapon

6
doc/add_potions.txt Normal file
View File

@ -0,0 +1,6 @@
1. add it normally.
2. if monsters should drink it, add a flag:
f_aiboostitem
f_aihealitem
f_aifleeitem

View File

@ -9,6 +9,7 @@ objects.c:
(optional) add a scroll to do the same effect, use F_LINKSPELL (optional) add a scroll to do the same effect, use F_LINKSPELL
(optional) add a potion to do the same effect (optional) add a potion to do the same effect
(optional) add a spellbook to learn it (optional) add a spellbook to learn it
assign AI hint flags so it knows how to cast it
spell.c: spell.c:
implement the effects implement the effects
@ -18,3 +19,7 @@ spell.c:
target having antimagic - use hasmr(victim) target having antimagic - use hasmr(victim)
blindness if the effect is vision-based blindness if the effect is vision-based
ai.c
update aigetspelltarget();
update aigetattackspell();

3
doc/dnd.txt Normal file
View File

@ -0,0 +1,3 @@
Converting dndv4 monsters:
hp / 8
ac / 2 (sometimes use evasion instead though)

9
doc/object_ideas.txt Normal file
View File

@ -0,0 +1,9 @@
hay
pebbles
torch
boulder / monolith / statue
shackles
chain
bone
skeleton
scrap of material

10
doc/throwspeeds.txt Normal file
View File

@ -0,0 +1,10 @@
helpless/feeble = 0
weak/vweak = 1
avg/strong = 2
mighty = 3
titanic = 4
gun = 10
only apply damage to armour if speed >= 3
(or armour piercing)

24
doc/wandwondereffects Normal file
View File

@ -0,0 +1,24 @@
#Slow the target down
#Summon a cloud of toxic gas
#Summon huge swarm of butterflies
#Turn target to stone
#Cause darkness
#Fireball
swap places ?
Make all inanimate objects in range vanish
Makes leaves grow from target
Shoots forth semi-precious gems (this is actually an attack, they shoot out really fast)
Cause a funky light show
Turn target into a giant
+ str?
Shrink wand user to halfling size
+ acc?
Makes user invisible
Summon a mouse, elephant, or rhino
Cause grass to grow
Lightning Bolt
Summon a great wind (ie. airblast spellO)
Cause heavy rainfall
Make the wand wielder believe that something else happened

11
flag.c
View File

@ -92,6 +92,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
if (gamestarted) { if (gamestarted) {
if (f->pile->owner) { if (f->pile->owner) {
if (announceflaggain(f->pile->owner, f)) { if (announceflaggain(f->pile->owner, f)) {
interrupt(f->pile->owner);
f->known = B_TRUE; f->known = B_TRUE;
if (f->obfrom) { // ooooooo it's getting -1 ?!?!?!? if (f->obfrom) { // ooooooo it's getting -1 ?!?!?!?
object_t *ob; object_t *ob;
@ -238,14 +239,18 @@ flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, ch
return NULL; return NULL;
} }
void killflagsofid(flagpile_t *fp, enum FLAG fid) { // returns true if we did something
int killflagsofid(flagpile_t *fp, enum FLAG fid) {
flag_t *f,*nextf; flag_t *f,*nextf;
int donesomething = B_FALSE;
for (f = fp->first ; f ; f = nextf) { for (f = fp->first ; f ; f = nextf) {
nextf = f->next; nextf = f->next;
if (f->id == fid) { if (f->id == fid) {
killflag(f); killflag(f);
donesomething = B_TRUE;
} }
} }
return donesomething;
} }
void killflag(flag_t *f) { void killflag(flag_t *f) {
@ -273,7 +278,9 @@ void killflag(flag_t *f) {
// notify // notify
if (gamestarted) { if (gamestarted) {
if (f->pile->owner) { if (f->pile->owner) {
announceflagloss(f->pile->owner, f); if (announceflagloss(f->pile->owner, f)) {
interrupt(f->pile->owner);
}
} else if (f->pile->ob) { } else if (f->pile->ob) {
announceobflagloss(f->pile->ob, f); announceobflagloss(f->pile->ob, f);
} }

2
flag.h
View File

@ -14,7 +14,7 @@ flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown);
flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *text); flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *text);
flag_t *hasflagvalknown(flagpile_t *fp, int id, int val1, int val2, int val3, char *text); flag_t *hasflagvalknown(flagpile_t *fp, int id, int val1, int val2, int val3, char *text);
flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, char *text, int wantknown); flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, char *text, int wantknown);
void killflagsofid(flagpile_t *fp, enum FLAG fid); int killflagsofid(flagpile_t *fp, enum FLAG fid);
void killflag(flag_t *f); void killflag(flag_t *f);
void killflagpile(flagpile_t *fp); void killflagpile(flagpile_t *fp);
void makeflagknown(flagpile_t *fp); void makeflagknown(flagpile_t *fp);

703
io.c

File diff suppressed because it is too large Load Diff

8
io.h
View File

@ -6,9 +6,10 @@ void addmsghist(char *text);
void addpromptq(prompt_t *p, char *q); void addpromptq(prompt_t *p, char *q);
void anim(cell_t *src, cell_t *dst, char ch); void anim(cell_t *src, cell_t *dst, char ch);
void animradial(cell_t *src, int radius, char ch); void animradial(cell_t *src, int radius, char ch);
void animradialorth(cell_t *src, int radius, char ch);
//void announceob(enum OBTYPE oid); //void announceob(enum OBTYPE oid);
int announceflaggain(lifeform_t *lf, flag_t *f); int announceflaggain(lifeform_t *lf, flag_t *f);
void announceflagloss(lifeform_t *lf, flag_t *f); int announceflagloss(lifeform_t *lf, flag_t *f);
int announceobflaggain(object_t *o, flag_t *f); int announceobflaggain(object_t *o, flag_t *f);
void announceobflagloss(object_t *o, flag_t *f); void announceobflagloss(object_t *o, flag_t *f);
object_t *askobject(obpile_t *op, char *title, int *count, int opts); object_t *askobject(obpile_t *op, char *title, int *count, int opts);
@ -36,6 +37,7 @@ void doenter(lifeform_t *lf);
void doexplain(void); void doexplain(void);
void dofinaloblist(obpile_t *op); void dofinaloblist(obpile_t *op);
void dofire(void); void dofire(void);
void dohelp(void);
void doinventory(obpile_t *op); void doinventory(obpile_t *op);
void doknowledgelist(void); void doknowledgelist(void);
void dolook(cell_t *where); void dolook(cell_t *where);
@ -57,6 +59,7 @@ void dothrow(obpile_t *op);
void dovendingmachine(lifeform_t *lf, object_t *vm); void dovendingmachine(lifeform_t *lf, object_t *vm);
int dowear(obpile_t *op); int dowear(obpile_t *op);
int doweild(obpile_t *op); int doweild(obpile_t *op);
void downline(int *y, int h, char *heading, char *subheading);
void drawunviscell(cell_t *cell, int x, int y); void drawunviscell(cell_t *cell, int x, int y);
void drawcellwithcontents(cell_t *cell, int x, int y); void drawcellwithcontents(cell_t *cell, int x, int y);
void drawcursor(void); void drawcursor(void);
@ -69,13 +72,14 @@ char getchoice(prompt_t *prompt);
char getchoicestr(prompt_t *prompt); char getchoicestr(prompt_t *prompt);
int getkey(void); int getkey(void);
void handleinput(void); void handleinput(void);
void doheading(WINDOW *win, int *y, int x, char *what);
void initgfx(void); void initgfx(void);
void initprompt(prompt_t *p, char *q1); void initprompt(prompt_t *p, char *q1);
int keycodetokey(int keycode); int keycodetokey(int keycode);
void more(void); void more(void);
void warn(char *format, ... ); void warn(char *format, ... );
void msg(char *format, ... ); void msg(char *format, ... );
void msglower(char *format, ... ); void msgnocap(char *format, ... );
void msg_real(char *format, ... ); void msg_real(char *format, ... );
void nothinghappens(void); void nothinghappens(void);
void dblog(char *format, ... ); void dblog(char *format, ... );

1441
lf.c

File diff suppressed because it is too large Load Diff

16
lf.h
View File

@ -14,7 +14,6 @@ int calcxprace(enum RACE rid);
int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost); int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost);
int caneat(lifeform_t *lf, object_t *o); int caneat(lifeform_t *lf, object_t *o);
int canhear(lifeform_t *lf, cell_t *c); int canhear(lifeform_t *lf, cell_t *c);
int cannotmove(lifeform_t *lf);
int canpickup(lifeform_t *lf, object_t *o, int amt); int canpickup(lifeform_t *lf, object_t *o, int amt);
int canpush(lifeform_t *lf, object_t *o, int dir); int canpush(lifeform_t *lf, object_t *o, int dir);
int canquaff(lifeform_t *lf, object_t *o); int canquaff(lifeform_t *lf, object_t *o);
@ -45,7 +44,6 @@ object_t *getarmour(lifeform_t *lf, enum BODYPART bp);
int getarmourrating(lifeform_t *lf); int getarmourrating(lifeform_t *lf);
int getattackspeed(lifeform_t *lf); int getattackspeed(lifeform_t *lf);
int getattr(lifeform_t *lf, enum ATTRIB attr); int getattr(lifeform_t *lf, enum ATTRIB attr);
int getdexmod(lifeform_t *lf);
int getevasion(lifeform_t *lf); int getevasion(lifeform_t *lf);
object_t *getbestmissile(lifeform_t *lf); object_t *getbestmissile(lifeform_t *lf);
object_t *getbestweapon(lifeform_t *lf); object_t *getbestweapon(lifeform_t *lf);
@ -59,6 +57,7 @@ lifeform_t *getguntarget(lifeform_t *lf);
int getguntargetid(lifeform_t *lf); int getguntargetid(lifeform_t *lf);
//int gethealtime(lifeform_t *lf); //int gethealtime(lifeform_t *lf);
int gethearingrange(lifeform_t *lf); int gethearingrange(lifeform_t *lf);
int gethppct(lifeform_t *lf);
enum HUNGER gethungerlevel(int hunger); enum HUNGER gethungerlevel(int hunger);
char * gethungername(enum HUNGER hunger, char *buf); char * gethungername(enum HUNGER hunger, char *buf);
int gethungerval(lifeform_t *lf); int gethungerval(lifeform_t *lf);
@ -68,6 +67,7 @@ enum LFCONDITION getlfcondition(lifeform_t *lf);
int getnightvisrange(lifeform_t *lf); int getnightvisrange(lifeform_t *lf);
char *getlfconditionname(enum LFCONDITION cond); char *getlfconditionname(enum LFCONDITION cond);
char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer); char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer);
char getlfglyph(lifeform_t *lf);
enum MATERIAL getlfmaterial(lifeform_t *lf); enum MATERIAL getlfmaterial(lifeform_t *lf);
float getmaxcarryweight(lifeform_t *lf); float getmaxcarryweight(lifeform_t *lf);
float getmaxliftweight(lifeform_t *lf); float getmaxliftweight(lifeform_t *lf);
@ -119,6 +119,7 @@ enum BURDENED isburdened(lifeform_t *lf);
int isdead(lifeform_t *lf); int isdead(lifeform_t *lf);
int isfleeing(lifeform_t *lf); int isfleeing(lifeform_t *lf);
int isfreebp(lifeform_t *lf, enum BODYPART bp); int isfreebp(lifeform_t *lf, enum BODYPART bp);
int isfriendly(lifeform_t *lf);
int isgenius(lifeform_t *lf); int isgenius(lifeform_t *lf);
int isimmobile(lifeform_t *lf); int isimmobile(lifeform_t *lf);
flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt); flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt);
@ -133,7 +134,10 @@ void killlf(lifeform_t *lf);
void killrace(race_t *race); void killrace(race_t *race);
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc); 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); int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam);
void makefriendly(lifeform_t *lf);
void makenauseated(lifeform_t *lf, int amt, int howlong);
void makenoise(lifeform_t *lf, enum NOISETYPE nid); void makenoise(lifeform_t *lf, enum NOISETYPE nid);
lifeform_t *makezombie(object_t *o);
void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how); void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how);
int modattr(lifeform_t *lf, enum ATTRIB attr, int amt); int modattr(lifeform_t *lf, enum ATTRIB attr, int amt);
void modhunger(lifeform_t *lf, int amt); void modhunger(lifeform_t *lf, int amt);
@ -148,7 +152,6 @@ int rolldex(enum DEXBRACKET bracket);
int rolliq(enum IQBRACKET bracket); int rolliq(enum IQBRACKET bracket);
int rollstr(enum STRBRACKET bracket); int rollstr(enum STRBRACKET bracket);
int rollstat(lifeform_t *lf, enum ATTRIB attr); int rollstat(lifeform_t *lf, enum ATTRIB attr);
int savingthrow(lifeform_t *lf, enum ATTRIB attr, int mod);
int scare(lifeform_t *lf, lifeform_t *scarer, int howlong); int scare(lifeform_t *lf, lifeform_t *scarer, int howlong);
int setammo(lifeform_t *lf, object_t *o); int setammo(lifeform_t *lf, object_t *o);
void setattr(lifeform_t *lf, enum ATTRIB attr, int val); void setattr(lifeform_t *lf, enum ATTRIB attr, int val);
@ -156,7 +159,10 @@ void setguntarget(lifeform_t *lf, lifeform_t *targ);
void setrace(lifeform_t *lf, enum RACE rid); void setrace(lifeform_t *lf, enum RACE rid);
void setlastdam(lifeform_t *lf, char *buf); void setlastdam(lifeform_t *lf, char *buf);
int shoot(lifeform_t *lf); int shoot(lifeform_t *lf);
int skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod);
int slipon(lifeform_t *lf, object_t *o);
void sortlf(map_t *map, lifeform_t *lf); void sortlf(map_t *map, lifeform_t *lf);
int stone(lifeform_t *lf);
void stopresting(lifeform_t *lf); void stopresting(lifeform_t *lf);
void stoprunning(lifeform_t *lf); void stoprunning(lifeform_t *lf);
int testammo(lifeform_t *lf, object_t *o); int testammo(lifeform_t *lf, object_t *o);
@ -167,9 +173,11 @@ void timeeffectslf(lifeform_t *lf);
void turneffectslf(lifeform_t *lf); void turneffectslf(lifeform_t *lf);
int touch(lifeform_t *lf, object_t *o); int touch(lifeform_t *lf, object_t *o);
int unweild(lifeform_t *lf, object_t *o); int unweild(lifeform_t *lf, object_t *o);
int useability(lifeform_t *lf, enum OBTYPE aid); int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where);
int useitemwithflag(lifeform_t *lf, enum FLAG whichflag);
int usestairs(lifeform_t *lf, object_t *o); int usestairs(lifeform_t *lf, object_t *o);
int validateraces(void); int validateraces(void);
int wear(lifeform_t *lf, object_t *o); int wear(lifeform_t *lf, object_t *o);
int weild(lifeform_t *lf, object_t *o); int weild(lifeform_t *lf, object_t *o);
int willflee(lifeform_t *lf);
int youhear(cell_t *c, char *text); int youhear(cell_t *c, char *text);

3041
log.txt

File diff suppressed because it is too large Load Diff

133
map.c
View File

@ -31,7 +31,7 @@ cell_t *addcell(map_t *m, int x, int y) {
cell->obpile = addobpile(NOOWNER, cell); cell->obpile = addobpile(NOOWNER, cell);
cell->lf = NULL; cell->lf = NULL;
cell->roomid = -1; cell->roomid = -1;
cell->lit = B_FALSE; cell->lit = L_NOTLIT;
cell->writing = NULL; cell->writing = NULL;
cell->known = B_FALSE; cell->known = B_FALSE;
return cell; return cell;
@ -73,7 +73,7 @@ map_t *addmap(void) {
} }
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok) { lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) {
lifeform_t *lf = NULL; lifeform_t *lf = NULL;
race_t *r; race_t *r;
int db = B_FALSE; int db = B_FALSE;
@ -96,7 +96,6 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok) {
//lf = addlf(c, r->id, getrandommonlevel(c->map->depth)); //lf = addlf(c, r->id, getrandommonlevel(c->map->depth));
lf = addlf(c, r->id, 1); lf = addlf(c, r->id, 1);
if (lf) { if (lf) {
int amt;
flag_t *f; flag_t *f;
if (jobok) { if (jobok) {
@ -112,23 +111,41 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok) {
// appears in groups? // appears in groups?
f = hasflag(lf->flags, F_NUMAPPEAR); f = hasflag(lf->flags, F_NUMAPPEAR);
if (f) { if (f) {
// override amount
amt = rnd(f->val[0], f->val[1]); amt = rnd(f->val[0], f->val[1]);
} else {
amt = 1;
} }
if (amt > 1) { if (amt > 1) {
cell_t *adjcell; cell_t *adjcell;
cell_t **moncell;
int nmoncells = 1;
moncell = malloc( amt * sizeof(cell_t *));
moncell[0] = c;
nmoncells = 1;
amt--; // we've already added one amt--; // we've already added one
adjcell = c;
//adjcell = c;
for ( ; amt > 0; amt--) { for ( ; amt > 0; amt--) {
// add more in adjacent cells int n;
adjcell = getrandomadjcell(adjcell, WE_NOTSOLID); // find an adjacent cell to one of the newly added monsters,
// starting with the first one
adjcell = NULL;
for (n = 0; n < nmoncells; n++) {
adjcell = getrandomadjcell(moncell[n], WE_NOTSOLID);
if (adjcell) break;
}
// did we find one?
if (!adjcell) break; if (!adjcell) break;
//lf = addlf(adjcell, r->id, getrandommonlevel(adjcell->map->depth)); //lf = addlf(adjcell, r->id, getrandommonlevel(adjcell->map->depth));
lf = addlf(adjcell, r->id, 1); if (!addlf(adjcell, r->id, 1)) {
if (!lf) break; break;
} }
moncell[nmoncells] = adjcell;
nmoncells++;
}
free(moncell);
} }
} }
} }
@ -157,7 +174,7 @@ void addrandomthing(cell_t *c) {
addrandomob(c); addrandomob(c);
} else { } else {
// monster // monster
addmonster(c, R_RANDOM, B_TRUE); addmonster(c, R_RANDOM, B_TRUE, 1);
} }
} }
@ -341,7 +358,7 @@ void calclight(map_t *map) {
for (y = 0; y < map->h; y++) { for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) { for (x = 0; x < map->w; x++) {
c = getcellat(map, x,y); c = getcellat(map, x,y);
if (c && (c->lit != B_PERM)) c->lit = B_FALSE; if (c && (c->lit == L_PERM) && (c->lit != L_DARK)) c->lit = B_FALSE;
} }
} }
for (y = 0; y < map->h; y++) { for (y = 0; y < map->h; y++) {
@ -351,22 +368,22 @@ void calclight(map_t *map) {
int radius; int radius;
object_t *o; object_t *o;
// lit based on depth // lit based on depth
if (map->depth <= 5) { if ((map->depth <= 5) && (c->lit != L_DARK)) {
c->lit = B_PERM; c->lit = L_PERM;
} }
// has lightproducing lf? (ie.hasflag f_produceslight) // has lightproducing lf? (ie.hasflag f_produceslight)
if (c->lf) { if (c->lf) {
if (lfhasflag(c->lf, F_PRODUCESLIGHT)) { if (lfhasflag(c->lf, F_PRODUCESLIGHT)) {
sumflags(c->lf->flags, F_PRODUCESLIGHT, &radius, NULL, NULL); sumflags(c->lf->flags, F_PRODUCESLIGHT, &radius, NULL, NULL);
makelitradius(c, radius, B_TEMP); makelitradius(c, radius, L_TEMP);
} }
// objects in hands or on body... // objects in hands or on body...
for (o = c->lf->pack->first ; o ; o = o->next) { for (o = c->lf->pack->first ; o ; o = o->next) {
if (obproduceslight(o) && isequipped(o)) { if (obproduceslight(o) && isequipped(o)) {
sumflags(o->flags, F_PRODUCESLIGHT, &radius, NULL, NULL); sumflags(o->flags, F_PRODUCESLIGHT, &radius, NULL, NULL);
makelitradius(c, radius, B_TEMP); makelitradius(c, radius, L_TEMP);
} }
} }
} }
@ -374,7 +391,7 @@ void calclight(map_t *map) {
for (o = c->obpile->first ; o ; o = o->next) { for (o = c->obpile->first ; o ; o = o->next) {
if (obproduceslight(o)) { if (obproduceslight(o)) {
sumflags(o->flags, F_PRODUCESLIGHT, &radius, NULL, NULL); sumflags(o->flags, F_PRODUCESLIGHT, &radius, NULL, NULL);
makelitradius(c, radius, B_TEMP); makelitradius(c, radius, L_TEMP);
} }
} }
@ -404,11 +421,20 @@ int calcroompos(map_t *map, int w, int h, int *bx, int *by) {
for (ry = y; (ry < y+h) && (!notpossible); ry++) { for (ry = y; (ry < y+h) && (!notpossible); ry++) {
for (rx = x; (rx < x+w) && (!notpossible); rx++) { for (rx = x; (rx < x+w) && (!notpossible); rx++) {
cell = getcellat(map, rx,ry); cell = getcellat(map, rx,ry);
// is this cell adjacent to an empty cell? // is this cell adjacent to an empty cell and not a
// corner (ie. a valid door location)
if (countcellexits(cell)) { if (countcellexits(cell)) {
score++; score++;
if ( ((ry == y) && (rx == x)) ||
((ry == y) && (rx == (x+w-1))) ||
((ry == y+h-1) && (rx == x)) ||
((ry == y+h-1) && (rx == (x+w-1))) ) {
// corner.
} else {
// not corner
valid = B_TRUE; valid = B_TRUE;
} }
}
// is this cell empty itself? // is this cell empty itself?
if (!cell->type->solid) score += 3; if (!cell->type->solid) score += 3;
// avoid being adjacent to other room walls // avoid being adjacent to other room walls
@ -1235,7 +1261,7 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
// N // N
npossible = 0; npossible = 0;
y = miny; y = miny;
for (x = minx; x <= maxx; x++) { for (x = minx+1; x <= maxx-1; x++) {
cell = getcellat(map, x, y); cell = getcellat(map, x, y);
newcell = getcellindir(cell, D_N); newcell = getcellindir(cell, D_N);
if (newcell && !newcell->type->solid) { if (newcell && !newcell->type->solid) {
@ -1267,7 +1293,7 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
// S // S
npossible = 0; npossible = 0;
y = maxy; y = maxy;
for (x = minx; x <= maxx; x++) { for (x = minx+1; x <= maxx-1; x++) {
cell = getcellat(map, x, y); cell = getcellat(map, x, y);
newcell = getcellindir(cell, D_S); newcell = getcellindir(cell, D_S);
if (newcell && !newcell->type->solid) { if (newcell && !newcell->type->solid) {
@ -1299,7 +1325,7 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
// W // W
npossible = 0; npossible = 0;
x = minx; x = minx;
for (y = miny; y <= maxy; y++) { for (y = miny+1; y <= maxy-1; y++) {
cell = getcellat(map, x, y); cell = getcellat(map, x, y);
newcell = getcellindir(cell, D_W); newcell = getcellindir(cell, D_W);
if (newcell && !newcell->type->solid) { if (newcell && !newcell->type->solid) {
@ -1329,7 +1355,7 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
// E // E
npossible = 0; npossible = 0;
x = maxx; x = maxx;
for (y = miny; y <= maxy; y++) { for (y = miny+1; y <= maxy-1; y++) {
cell = getcellat(map, x, y); cell = getcellat(map, x, y);
newcell = getcellindir(cell, D_E); newcell = getcellindir(cell, D_E);
if (newcell && !newcell->type->solid) { if (newcell && !newcell->type->solid) {
@ -1793,6 +1819,25 @@ cell_t *getrandomroomcell(map_t *map, int roomid) {
return c; return c;
} }
// returns how slippery this cell is
int getslipperyness(cell_t *c, object_t **slipob) {
object_t *o;
int totalslip = 0;
if (slipob) *slipob = NULL;
for (o = c->obpile->first ; o ; o = o->next) {
int thisslip;
sumflags(o->flags, F_SLIPPERY, &thisslip, NULL, NULL);
if (thisslip > 0) {
if (slipob && (*slipob == NULL)) {
*slipob = o;
}
}
thisslip *= o->amt;
totalslip += thisslip;
}
return totalslip;
}
object_t *hasenterableobject(cell_t *c) { object_t *hasenterableobject(cell_t *c) {
return hasobwithflag(c->obpile, F_CLIMBABLE); return hasobwithflag(c->obpile, F_CLIMBABLE);
} }
@ -1872,31 +1917,7 @@ int isinscanrange(cell_t *c, void **thing, char *desc, char *glyph) {
} }
if (glyph) { if (glyph) {
// select glyph based on size // select glyph based on size
switch(getlfsize(c->lf)) { *glyph = '0' + ((int) getlfsize(c->lf));
case SZ_ENORMOUS:
*glyph = '6';
break;
case SZ_HUGE:
*glyph = '5';
break;
case SZ_LARGE:
*glyph = '4';
break;
case SZ_HUMAN:
*glyph = '3';
break;
case SZ_MEDIUM:
*glyph = '2';
break;
case SZ_SMALL:
*glyph = '1';
break;
case SZ_MINI:
case SZ_TINY:
default:
*glyph = '0';
break;
}
} }
return TT_MONSTER; return TT_MONSTER;
} }
@ -1928,8 +1949,12 @@ int isinscanrange(cell_t *c, void **thing, char *desc, char *glyph) {
} }
int islit(cell_t *c) { int islit(cell_t *c) {
if (c->lit) { switch (c->lit) {
case L_TEMP:
case L_PERM:
return B_TRUE; return B_TRUE;
default:
break;
} }
return B_FALSE; return B_FALSE;
} }
@ -2009,16 +2034,16 @@ void makedoor(cell_t *cell) {
} }
void makelit(cell_t *c, int how) { void makelit(cell_t *c, enum LIGHTLEV how) {
if (how == B_FALSE) { // don't override permenant light with temp light!
c->lit = how; if ((c->lit == L_PERM) && (how == L_TEMP)) {
} else if (c->lit != B_PERM) { // don't override permenant light with temp light! return;
} else {
c->lit = how; c->lit = how;
} }
} }
void makelitradius(cell_t *c, int radius, int how) { void makelitradius(cell_t *c, int radius, enum LIGHTLEV how) {
int x,y; int x,y;
cell_t *c2; cell_t *c2;

7
map.h
View File

@ -2,7 +2,7 @@
cell_t *addcell(map_t *map, int x, int y); cell_t *addcell(map_t *map, int x, int y);
map_t *addmap(void); map_t *addmap(void);
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok); lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt);
void addrandomob(cell_t *c); void addrandomob(cell_t *c);
void addrandomthing(cell_t *c); void addrandomthing(cell_t *c);
int cellhaslos(cell_t *c1, cell_t *dest); int cellhaslos(cell_t *c1, cell_t *dest);
@ -35,6 +35,7 @@ cell_t *getrandomcell(map_t *map);
cell_t *getrandomcelloftype(map_t *map, int id); cell_t *getrandomcelloftype(map_t *map, int id);
int getrandomdir(int dirtype); int getrandomdir(int dirtype);
cell_t *getrandomroomcell(map_t *map, int roomid); cell_t *getrandomroomcell(map_t *map, int roomid);
int getslipperyness(cell_t *c, object_t **slipob);
object_t *hasenterableobject(cell_t *c); object_t *hasenterableobject(cell_t *c);
lifeform_t *haslf(cell_t *c); lifeform_t *haslf(cell_t *c);
int hasobject(cell_t *c); int hasobject(cell_t *c);
@ -49,7 +50,7 @@ int isnewcellok(cell_t *cell, char *err);
int isonmap(map_t *map, int x, int y); int isonmap(map_t *map, int x, int y);
int iswallindir(cell_t *cell, int dir); int iswallindir(cell_t *cell, int dir);
void makedoor(cell_t *cell); void makedoor(cell_t *cell);
void makelit(cell_t *c, int how); void makelit(cell_t *c, enum LIGHTLEV how);
void makelitradius(cell_t *c, int radius, int how); void makelitradius(cell_t *c, int radius, enum LIGHTLEV how);
void setcelltype(cell_t *cell, int id); void setcelltype(cell_t *cell, int id);
void updateknowncells(void); void updateknowncells(void);

314
move.c
View File

@ -36,6 +36,7 @@ int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error) {
int canmove(lifeform_t *lf, int dir, enum ERROR *error) { int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell; cell_t *cell;
flag_t *f;
// default // default
if (error) { if (error) {
@ -53,9 +54,27 @@ int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
return B_FALSE; return B_FALSE;
} }
// TODO: check if we are burdened, paralyzed, etc // check if we are paralyzed, frozen, etc
if (isimmobile(lf)) {
if (error) *error = E_CANTMOVE;
return B_FALSE;
}
cell = getcellindir(lf->cell, dir); cell = getcellindir(lf->cell, dir);
f = lfhasflag(lf, F_GRABBEDBY);
if (f) {
lifeform_t *lf2;
lf2 = findlf(NULL, f->val[0]);
if (lf2 && (lf2 != cell->lf)) {
if (error) {
rdata = lf2;
*error = E_GRABBEDBY;
}
return B_FALSE;
}
}
return cellwalkable(lf, cell, error); return cellwalkable(lf, cell, error);
} }
@ -69,9 +88,9 @@ int celldangerous(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
rdata = NULL; rdata = NULL;
} }
// check for dangerous objects // check for _known_ dangerous objects
iq = getiqname(getattr(lf, A_IQ), NULL); iq = getiqname(getattr(lf, A_IQ), NULL);
if (iq >= IQ_AVERAGE) { if ((iq >= IQ_AVERAGE) && !isblind(lf)) {
flag_t *f; flag_t *f;
object_t *o; object_t *o;
for (o = cell->obpile->first ; o ; o = o->next) { for (o = cell->obpile->first ; o ; o = o->next) {
@ -121,8 +140,15 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
} }
} }
// must check for lf before checking for impassable objects,
// so that we are able to attack monsters embedded in walls.
if (cell->lf && (cell->lf != lf)) {
if (error) *error = E_LFINWAY;
return B_FALSE;
}
for (o = cell->obpile->first ; o ; o = o->next) { for (o = cell->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_IMPASSABLE)) { if (isimpassableob(o, lf)) {
if (lf) { if (lf) {
if ((lf->race->material->id == MT_GAS) || if ((lf->race->material->id == MT_GAS) ||
(lf->race->material->id == MT_SLIME)) { (lf->race->material->id == MT_SLIME)) {
@ -142,13 +168,40 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
} }
} }
if (cell->lf && (cell->lf != lf)) {
if (error) *error = E_LFINWAY;
return B_FALSE;
}
return B_TRUE; return B_TRUE;
} }
int diropposite(int dir) {
switch (dir) {
case D_N:
return D_S;
case D_E:
return D_W;
case D_S:
return D_N;
case D_W:
return D_E;
case DC_N:
return DC_S;
case DC_NE:
return DC_SW;
case DC_E:
return DC_W;
case DC_SE:
return DC_NW;
case DC_S:
return DC_N;
case DC_SW:
return DC_NE;
case DC_W:
return DC_E;
case DC_NW:
return DC_SE;
}
// should never happen!
return dir;
}
void dorandommove(lifeform_t *lf, int badmovesok) { void dorandommove(lifeform_t *lf, int badmovesok) {
int dir; int dir;
int tries = 0; int tries = 0;
@ -226,7 +279,7 @@ int getdiraway(cell_t *src, cell_t *dst, int wantcheck) {
} }
} }
if (ok) { if (ok) {
thisdist = getcelldist(c, dst); thisdist = getcelldistorth(c, dst);
} else { } else {
thisdist = -1; thisdist = -1;
} }
@ -239,12 +292,14 @@ int getdiraway(cell_t *src, cell_t *dst, int wantcheck) {
} }
// TODO: handle ties // TODO: handle ties
if (bestdir != D_NONE) {
reason = E_OK;
}
return bestdir; return bestdir;
} }
int getdirtowards(cell_t *src, cell_t *dst, int wantcheck) { int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck) {
int d; int d;
cell_t *c; cell_t *c;
int mindist=9999,bestdir=D_NONE; int mindist=9999,bestdir=D_NONE;
@ -260,21 +315,21 @@ int getdirtowards(cell_t *src, cell_t *dst, int wantcheck) {
} }
if (wantcheck) { if (wantcheck) {
if (src->lf && canandwillmove(src->lf, d, NULL)) { if (srclf && canandwillmove(srclf, d, NULL)) {
ok = B_TRUE; ok = B_TRUE;
} else if (!src->lf) { } else if (!srclf) {
ok = B_TRUE; ok = B_TRUE;
} }
} else { } else {
if (src->lf && cellwalkable(src->lf, c, NULL)) { if (srclf && cellwalkable(srclf, c, NULL)) {
ok = B_TRUE; ok = B_TRUE;
} else if (!src->lf) { } else if (!srclf) {
ok = B_TRUE; ok = B_TRUE;
} }
} }
if (ok) { if (ok) {
int thisdist; int thisdist;
thisdist = getcelldist(c, dst); thisdist = getcelldistorth(c, dst);
if (thisdist < mindist) { if (thisdist < mindist) {
mindist = thisdist; mindist = thisdist;
bestdir = d; bestdir = d;
@ -287,13 +342,66 @@ int getdirtowards(cell_t *src, cell_t *dst, int wantcheck) {
return bestdir; return bestdir;
} }
int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher) {
int i;
char lfname[BUFLEN];
int seen;
int moveawayfrom(lifeform_t *lf, cell_t *dst) { getlfname(lf,lfname);
if (haslos(player, lf->cell)) {
seen = B_TRUE;
} else {
seen = B_FALSE;
}
if (dir == D_NONE) {
// failed!
return B_TRUE;
}
// if levitating (not flying), knocked back further.
if (lfhasflag(lf, F_LEVITATING)) {
howfar *= 2;
}
for (i = 0; i < howfar; i++) {
if (canmove(lf, dir, &reason)) {
if ((i == 0) && seen) {
msg("%s %s knocked backwards!",lfname,isplayer(lf) ? "are" : "is");
}
trymove(lf, dir);
}
if (reason != E_OK) {
// failed to move
switch (reason) {
case E_WALLINWAY:
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
i = howfar;
break;
default:
break;
}
}
}
return B_FALSE;
}
int moveawayfrom(lifeform_t *lf, cell_t *dst ) {
int dir; int dir;
int rv = B_TRUE; int rv = B_TRUE;
if (isblind(lf)) {
dorandommove(lf, B_TRUE);
return B_FALSE;
}
// move towards them // move towards them
dir = getdiraway(lf->cell, dst, B_TRUE); dir = getdiraway(lf->cell, dst, B_TRUE);
if (dir != D_NONE) { if (dir == D_NONE) {
rv = B_TRUE;
} else {
rv = trymove(lf, dir); rv = trymove(lf, dir);
} }
return rv; return rv;
@ -310,6 +418,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
int didmsg = B_FALSE; int didmsg = B_FALSE;
flag_t *f; flag_t *f;
getlfname(lf, lfname);
// update current cell // update current cell
lf->cell->lf = NULL; lf->cell->lf = NULL;
@ -335,6 +445,14 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
bleed(lf); bleed(lf);
} }
} }
if (lfhasflag(lf, F_PAIN)) {
losehp(lf, rolldie(2,4)+2, DT_DIRECT, NULL, "extreme pain");
if (isplayer(lf)) {
msg("Your body is wracked with pain!");
} else if (haslos(player, lf->cell)) {
msg("%s convulses in pain!",lfname);
}
}
// check ground objects // check ground objects
@ -346,10 +464,32 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
object_t *boots; object_t *boots;
// has boots on? // has boots on?
boots = getequippedob(lf->pack, BP_FEET); boots = getequippedob(lf->pack, BP_FEET);
if (boots) { if (!boots) {
// crunch the broken glass // take damage
getobname(o, obname, 1);
if (lf->controller == C_PLAYER) {
msg("Ow - you step on %s!",obname);
didmsg = B_TRUE;
} else if (haslos(player, newcell)) {
msg("%s steps on %s!",lfname, obname);
didmsg = B_TRUE;
}
sprintf(buf, "stepping on %s", obname);
losehp(lf, rnd(f->val[0],f->val[1]), DT_SLASH, NULL, buf);
}
}
f = hasflag(o->flags, F_CRUSHABLE);
if (f) {
enum LFSIZE crushsize;
crushsize = f->val[0];
if (getlfsize(lf) >= crushsize) {
// crunch it broken glass
getobname(o, obname, 1); getobname(o, obname, 1);
// special case
if (o->type->id == OT_BROKENGLASS) {
if (o->amt > 1) { if (o->amt > 1) {
char *newname; char *newname;
// we want 'xx steps on some pieces of broken glass' // we want 'xx steps on some pieces of broken glass'
@ -359,33 +499,19 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
strcpy(obname, newname); strcpy(obname, newname);
free(newname); free(newname);
} }
if (lf->controller == C_PLAYER) { }
if (isplayer(lf)) {
msg("You crush %s underfoot.",obname); msg("You crush %s underfoot.",obname);
didmsg = B_TRUE; didmsg = B_TRUE;
} else if (haslos(player, newcell)) { } else if (haslos(player, newcell)) {
getlfname(lf, lfname);
capitalise(lfname);
msg("%s crushes %s.",lfname, obname); msg("%s crushes %s.",lfname, obname);
didmsg = B_TRUE; didmsg = B_TRUE;
} }
// kill object // kill object
removeob(o, o->amt); removeob(o, o->amt);
} else {
// take damage
getobname(o, obname, 1);
if (lf->controller == C_PLAYER) {
msg("Ow - you step on %s!",obname);
didmsg = B_TRUE;
} else if (haslos(player, newcell)) {
getlfname(lf, lfname);
capitalise(lfname);
msg("%s steps on %s!",lfname, obname);
didmsg = B_TRUE;
}
sprintf(buf, "stepping on %s", obname);
losehp(lf, rnd(f->val[0],f->val[1]), DT_SLASH, NULL, buf);
}
} }
} // end if crushable
} // end foreach object in cell } // end foreach object in cell
} // end if !flying } // end if !flying
@ -434,7 +560,7 @@ int moveto(lifeform_t *lf, cell_t *newcell) {
object_t *o; object_t *o;
char obname[BUFLEN]; char obname[BUFLEN];
for (o = newcell->obpile->first ; o ; o = o->next) { for (o = newcell->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_IMPASSABLE)) { if (isimpassableob(o, lf)) {
getobname(o, obname, o->amt); getobname(o, obname, o->amt);
if (isplayer(lf)) { if (isplayer(lf)) {
msg("You seep around %s.", obname); msg("You seep around %s.", obname);
@ -447,7 +573,7 @@ int moveto(lifeform_t *lf, cell_t *newcell) {
object_t *o; object_t *o;
char obname[BUFLEN]; char obname[BUFLEN];
for (o = newcell->obpile->first ; o ; o = o->next) { for (o = newcell->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_IMPASSABLE)) { if (isimpassableob(o, lf)) {
getobname(o, obname, o->amt); getobname(o, obname, o->amt);
if (isplayer(lf)) { if (isplayer(lf)) {
msg("You seep under %s.", obname); msg("You seep under %s.", obname);
@ -476,8 +602,14 @@ int moveto(lifeform_t *lf, cell_t *newcell) {
int movetowards(lifeform_t *lf, cell_t *dst) { int movetowards(lifeform_t *lf, cell_t *dst) {
int dir; int dir;
int rv = B_TRUE; int rv = B_TRUE;
if (isblind(lf)) {
dorandommove(lf, B_TRUE);
return B_FALSE;
}
// move towards them // move towards them
dir = getdirtowards(lf->cell, dst, B_TRUE); dir = getdirtowards(lf->cell, dst, lf, B_TRUE);
if (dir != D_NONE) { if (dir != D_NONE) {
rv = trymove(lf, dir); rv = trymove(lf, dir);
} }
@ -606,8 +738,11 @@ int closedoor(lifeform_t *lf, object_t *o) {
cell_t *cell; cell_t *cell;
char buf[BUFLEN]; char buf[BUFLEN];
char obname[BUFLEN]; char obname[BUFLEN];
object_t *oo;
flag_t *f; flag_t *f;
cell = getoblocation(o);
getobname(o, obname, 1); getobname(o, obname, 1);
if (!isdoor(o, NULL)) { if (!isdoor(o, NULL)) {
@ -624,6 +759,29 @@ int closedoor(lifeform_t *lf, object_t *o) {
return B_TRUE; return B_TRUE;
} }
if (cell->lf) {
if (lf && isplayer(lf)) {
char inwayname[BUFLEN];
getlfname(cell->lf, inwayname);
msg("%s is in the way!", haslos(lf, cell) ? inwayname : "Something");
}
return B_TRUE;
}
// impassable object other than the door?
for (oo = cell->obpile->first ; oo ; oo = oo->next) {
if (oo != o) {
if (hasflag(oo->flags, F_IMPASSABLE)) {
if (lf && isplayer(lf)) {
char inwayname[BUFLEN];
getobname(oo, inwayname, oo->amt);
msg("%s is in the way!", haslos(lf, cell) ? inwayname : "Something");
}
return B_TRUE;
}
}
}
f = hasflag(o->flags, F_OPEN); f = hasflag(o->flags, F_OPEN);
if (!f) { if (!f) {
if (lf && (lf->controller == C_PLAYER)) { if (lf && (lf->controller == C_PLAYER)) {
@ -672,7 +830,7 @@ int pullnextto(lifeform_t *lf, cell_t *c) {
dst = c; dst = c;
while (dst->lf) { while (dst->lf) {
dir = getdirtowards(dst, lf->cell, B_FALSE); dir = getdirtowards(dst, lf->cell, lf, B_FALSE);
if (dir == D_NONE) { if (dir == D_NONE) {
return B_TRUE; return B_TRUE;
} else { } else {
@ -701,6 +859,15 @@ int pullnextto(lifeform_t *lf, cell_t *c) {
// teleport somewhere, along with puffs of smoke etc // teleport somewhere, along with puffs of smoke etc
int teleportto(lifeform_t *lf, cell_t *c) { int teleportto(lifeform_t *lf, cell_t *c) {
char buf[BUFLEN]; char buf[BUFLEN];
// can't teleport on top of something else
if (c->lf) {
if (isplayer(lf)) {
msg("You feel a wrenching sensation.");
}
return B_TRUE;
}
if (!isplayer(lf) && haslos(player, lf->cell)) { if (!isplayer(lf) && haslos(player, lf->cell)) {
getlfname(lf, buf); getlfname(lf, buf);
msg("%s disappears in a cloud of smoke!", buf); msg("%s disappears in a cloud of smoke!", buf);
@ -731,7 +898,8 @@ int trymove(lifeform_t *lf, int dir) {
cell = getcellindir(lf->cell, dir); cell = getcellindir(lf->cell, dir);
if (canandwillmove(lf, dir, &errcode)) { if (canandwillmove(lf, dir, &errcode)) {
object_t *o; object_t *o,*slipob;
int slip;
// check for cursed objects + animals // check for cursed objects + animals
for (o = cell->obpile->first ; o ; o = o->next) { for (o = cell->obpile->first ; o ; o = o->next) {
@ -743,12 +911,11 @@ int trymove(lifeform_t *lf, int dir) {
char lfname[BUFLEN]; char lfname[BUFLEN];
getlfname(lf,lfname); getlfname(lf,lfname);
getobname(o, buf, o->amt); getobname(o, buf, o->amt);
msg("%s shies away from %s!", lfname, buf); msg("%s %s away from %s!", lfname, isplayer(lf) ? "shy" : "shies", buf);
o->blessknown = B_TRUE; o->blessknown = B_TRUE;
}
taketime(lf, getmovespeed(lf)); taketime(lf, getmovespeed(lf));
reason = E_OK; reason = E_OK;
}
return B_FALSE; return B_FALSE;
} }
} }
@ -756,9 +923,28 @@ int trymove(lifeform_t *lf, int dir) {
} }
} }
// slipping on blood before moving?
slip = getslipperyness(lf->cell, &slipob);
if (slip && !skillcheck(lf, SC_SLIP, slip, 0)) {
slipon(lf, slipob);
// don't move
reason = E_OK;
return B_FALSE;
}
// move to new cell
reason = E_OK; reason = E_OK;
moveto(lf, cell); moveto(lf, cell);
taketime(lf, getmovespeed(lf)); taketime(lf, getmovespeed(lf));
// slip on blood in new cell?
slip = getslipperyness(cell, &slipob);
if (slip && !skillcheck(lf, SC_SLIP, slip, 0)) {
slipon(lf, slipob);
// don't move
reason = E_OK;
return B_FALSE;
}
} else { } else {
object_t *inway; object_t *inway;
int door, dooropen; int door, dooropen;
@ -855,18 +1041,39 @@ int trymove(lifeform_t *lf, int dir) {
case E_LFINWAY: case E_LFINWAY:
// attack! // attack!
return attacklf(lf, cell->lf); return attacklf(lf, cell->lf);
break;
case E_GRAVBOOSTED: case E_GRAVBOOSTED:
if (isplayer(lf)) { if (isplayer(lf)) {
msg("You try to move but are unable to lift your feet!"); msg("You try to move but are unable to lift your feet!");
taketime(lf, getmovespeed(lf)); } else if (haslos(player, lf->cell)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s tries to move but is unable to lift its feet!",lfname);
} }
taketime(lf, getmovespeed(lf));
break;
case E_CANTMOVE:
if (isplayer(lf)) {
msg("You cannot move!");
}
taketime(lf, getmovespeed(lf));
break;
case E_GRABBEDBY:
if (isplayer(lf)) {
char lfname[BUFLEN];
if (rdata) {
getlfname((lifeform_t *)rdata, lfname);
} else {
sprintf(lfname, "whatever is holding you");
}
msg("You cannot get away from %s!",lfname);
}
taketime(lf, getmovespeed(lf));
break; break;
case E_TOOHEAVY: case E_TOOHEAVY:
if (isplayer(lf)) { if (isplayer(lf)) {
msg("Your load is too heavy to move with!"); msg("Your load is too heavy to move with!");
taketime(lf, getmovespeed(lf));
} }
taketime(lf, getmovespeed(lf));
break; break;
default: default:
break; break;
@ -895,6 +1102,15 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
if (celldangerous(lf, cell, error)) { if (celldangerous(lf, cell, error)) {
return B_FALSE; return B_FALSE;
} }
// don't attack other monsters
if (cell->lf) {
if (!isplayer(lf)) {
if (!isplayer(cell->lf) && !isfriendly(cell->lf)) {
return B_FALSE;
}
}
}
return B_TRUE; return B_TRUE;
} }

4
move.h
View File

@ -6,9 +6,11 @@ int celldangerous(lifeform_t *lf, cell_t *cell, enum ERROR *error);
int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error); int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error);
int closedoorat(lifeform_t *lf, cell_t *c); int closedoorat(lifeform_t *lf, cell_t *c);
int closedoor(lifeform_t *lf, object_t *o); int closedoor(lifeform_t *lf, object_t *o);
int diropposite(int dir);
void dorandommove(lifeform_t *lf, int badmovesok); void dorandommove(lifeform_t *lf, int badmovesok);
int getdiraway(cell_t *src, cell_t *dst, int wantcheck); int getdiraway(cell_t *src, cell_t *dst, int wantcheck);
int getdirtowards(cell_t *src, cell_t *dst, int wantcheck); int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck);
int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher);
int moveawayfrom(lifeform_t *lf, cell_t *dst); int moveawayfrom(lifeform_t *lf, cell_t *dst);
int movelf(lifeform_t *lf, cell_t *newcell); int movelf(lifeform_t *lf, cell_t *newcell);
int moveto(lifeform_t *lf, cell_t *newcell); int moveto(lifeform_t *lf, cell_t *newcell);

138
nexus.c
View File

@ -21,6 +21,7 @@ objectclass_t *objectclass = NULL,*lastobjectclass = NULL;
objecttype_t *objecttype = NULL,*lastobjecttype = NULL; objecttype_t *objecttype = NULL,*lastobjecttype = NULL;
obmod_t *firstobmod = NULL,*lastobmod = NULL; obmod_t *firstobmod = NULL,*lastobmod = NULL;
celltype_t *firstcelltype = NULL,*lastcelltype = NULL; celltype_t *firstcelltype = NULL,*lastcelltype = NULL;
command_t *firstcommand = NULL,*lastcommand = NULL;
race_t *firstrace = NULL,*lastrace = NULL; race_t *firstrace = NULL,*lastrace = NULL;
job_t *firstjob = NULL,*lastjob = NULL; job_t *firstjob = NULL,*lastjob = NULL;
map_t *firstmap = NULL,*lastmap = NULL; map_t *firstmap = NULL,*lastmap = NULL;
@ -144,7 +145,6 @@ int main(int argc, char **argv) {
more(); more();
} }
// start game - this will cause debug messages to now // start game - this will cause debug messages to now
// go to the log file instead of stdout. // go to the log file instead of stdout.
gamestarted = B_TRUE; gamestarted = B_TRUE;
@ -243,6 +243,32 @@ celltype_t *addcelltype(int id, char *name, char glyph, int solid, int transpare
return a; return a;
} }
command_t *addcommand(enum COMMAND id, char ch, char *desc) {
command_t *a;
// add to the end of the list
if (firstcommand == NULL) {
firstcommand = malloc(sizeof(command_t));
a = firstcommand;
a->prev = NULL;
} else {
// go to end of list
a = lastcommand;
a->next = malloc(sizeof(command_t));
a->next->prev = a;
a = a->next;
}
lastcommand = a;
a->next = NULL;
// set props
a->id = id;
a->ch = ch;
a->desc = strdup(desc);
return a;
}
void checkdeath(void) { void checkdeath(void) {
lifeform_t *lf, *nextlf; lifeform_t *lf, *nextlf;
int x,y; int x,y;
@ -330,7 +356,7 @@ void donextturn(map_t *map) {
if (donormalmove) { if (donormalmove) {
// paralyzed etc? // paralyzed etc?
if (cannotmove(who)) { if (isimmobile(who)) {
rest(who, B_FALSE); rest(who, B_FALSE);
donormalmove = B_FALSE; donormalmove = B_FALSE;
} }
@ -359,7 +385,10 @@ void donextturn(map_t *map) {
} }
} }
if (isdead(who) || haslos(player, who->cell)) { if (hasflag(player->flags, F_RESTING)) {
// ooo is this right ?
needredraw = B_FALSE;
} else if (isdead(who) || haslos(player, who->cell)) {
needredraw = B_TRUE; needredraw = B_TRUE;
} }
@ -415,7 +444,8 @@ void getrarity(int depth, int *min, int *max, int range) {
int mid; int mid;
mid = 100 - (depth * 3); mid = 100 - (depth * 3);
*min = mid - range; if (*min < 0) *min = 0; *min = mid - range; if (*min < 0) *min = 0;
*max = mid + range; if (*max > 100) *max = 100; //*max = mid + range; if (*max > 100) *max = 100;
*max = 100;
if (*min > 75) *min = 75; if (*min > 75) *min = 75;
if (*max < 25) *max = 25; if (*max < 25) *max = 25;
@ -426,6 +456,8 @@ int init(void) {
srand(time(NULL)); srand(time(NULL));
initcommands();
initobjects(); initobjects();
initjobs(); initjobs();
initrace(); initrace();
@ -453,6 +485,47 @@ int init(void) {
return B_FALSE; return B_FALSE;
} }
void initcommands(void) {
// Actions
addcommand(CMD_UP, '<', "Go up stairs.");
addcommand(CMD_DOWN, '>', "Go down stairs, enter a shop/portal.");
addcommand(CMD_REST, '.', "Rest once.");
addcommand(CMD_PICKUP, ',', "Pick up something from the ground.");
addcommand(CMD_CLOSE, 'c', "Close a door.");
addcommand(CMD_DROP, 'd', "Drop an item.");
addcommand(CMD_DROPMULTI, 'D', "Drop multiple items.");
addcommand(CMD_EAT, 'e', "Eat something.");
addcommand(CMD_MAGIC, 'm', "Use magic or abilities.");
addcommand(CMD_OPERATE, 'o', "Operate a tool/wand/device.");
addcommand(CMD_PICKLOCK, 'p', "Pick a lock.");
addcommand(CMD_POUR, 'P', "Pour a potion onto something.");
addcommand(CMD_QUAFF, 'q', "Quaff (drink) a potion.");
addcommand(CMD_READ, 'r', "Read a scroll/book.");
addcommand(CMD_RESTFULL, 'R', "Rest until healed.");
addcommand(CMD_TAKEOFF, 'T', "Take off an item of clothing/jewelery.");
addcommand(CMD_WEILD, 'w', "Weild a weapon.");
addcommand(CMD_WEAR, 'W', "Wear an item of clothing/jewelery.");
// Firearms
addcommand(CMD_FIRE, 'f', "Fire your firearm/bow at your current target.");
addcommand(CMD_FIRENEW, 'F', "Fire your firearm/bow at a new target.");
addcommand(CMD_AIM, 'a', "Aim your current firearm/bow at a new target.");
// Information
addcommand(CMD_HELP, '?', "Display this text.");
addcommand(CMD_INFOPLAYER, '@', "Display player stats.");
addcommand(CMD_INFOARMOUR, ']', "Display player armour.");
addcommand(CMD_FORCEATTACK, 'A', "Force an attack in a given direction.");
addcommand(CMD_LOOKHERE, ':', "Look at current cell.");
addcommand(CMD_LOOKAROUND, '/', "Look at a remote cell.");
addcommand(CMD_INFOKNOWLEDGE, '\\', "Display known items.");
addcommand(CMD_MSGHIST, '|', "Display message history.");
addcommand(CMD_INV, 'i', "Display your inventory.");
// GAME FUNCTIONS
addcommand(CMD_QUIT, 'Q', "Quit the game.");
addcommand(CMD_SAVEQUIT, 'S', "Save and quit the game.");
sortcommands();
}
int isplayerturn(void) { int isplayerturn(void) {
if (!player) return B_FALSE; if (!player) return B_FALSE;
@ -462,6 +535,19 @@ int isplayerturn(void) {
return B_FALSE; return B_FALSE;
} }
int limit(int *what, int min, int max) {
int limited = B_FALSE;
if (*what < min) {
*what = min;
limited = B_TRUE;
}
if (*what > max) {
*what = max;
limited = B_TRUE;
}
return limited;
}
float pctof(float pct, float num) { float pctof(float pct, float num) {
return ((pct / 100.0) * num); return ((pct / 100.0) * num);
} }
@ -619,6 +705,50 @@ dblog("doing sort...");
} }
*/ */
void sortcommands(void) {
command_t *c;
int donesomething = B_TRUE;
while (donesomething) {
donesomething = B_FALSE;
for (c = firstcommand ; c->next ; c = c->next) {
// move up one position if required.
if (c->ch > c->next->ch) {
command_t *temp;
// remember next element
temp = c->next;
// remove this element from list
if (c->prev == NULL) {
// first
firstcommand = c->next;
c->next->prev = NULL;
} else {
// not first
c->prev->next = c->next;
c->next->prev = c->prev;
}
// re-add element afterwards
c->next = temp->next;
c->prev = temp;
temp->next = c;
if (c->next == NULL) {
lastcommand = c;
} else {
c->next->prev = c;
}
// mark as done.
donesomething = B_TRUE;
break;
}
}
}
}
void timeeffectsworld(map_t *map) { void timeeffectsworld(map_t *map) {
lifeform_t *l; lifeform_t *l;
int db = B_FALSE; int db = B_FALSE;

View File

@ -1,6 +1,7 @@
#include "defs.h" #include "defs.h"
celltype_t *addcelltype(int id, char *name, char glyph, int solid, int transparent, enum MATERIAL mat); celltype_t *addcelltype(int id, char *name, char glyph, int solid, int transparent, enum MATERIAL mat);
command_t *addcommand(enum COMMAND id, char c, char *desc);
void checkdeath(void); void checkdeath(void);
void checkendgame(void); void checkendgame(void);
void cleanup(void); void cleanup(void);
@ -9,11 +10,14 @@ celltype_t *findcelltype(int id);
char *getdirname(int dir); char *getdirname(int dir);
void getrarity(int depth, int *min, int *max, int range); void getrarity(int depth, int *min, int *max, int range);
int init(void); int init(void);
void initcommands(void);
int isplayerturn(void); int isplayerturn(void);
int limit(int *what, int min, int max);
float pctof(float pct, float num); float pctof(float pct, float num);
int rnd(int min, int max); int rnd(int min, int max);
int rolldie(int ndice, int sides); int rolldie(int ndice, int sides);
int rollhitdice(lifeform_t *lf); int rollhitdice(lifeform_t *lf);
int rollmpdice(lifeform_t *lf); int rollmpdice(lifeform_t *lf);
//void sortlf(map_t *map); //void sortlf(map_t *map);
void sortcommands(void);
void timeeffectsworld(map_t *map); void timeeffectsworld(map_t *map);

1256
objects.c

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@ material_t *addmaterial(enum MATERIAL id, char *name, float weightrating);
objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph); objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph);
object_t *addob(obpile_t *where, char *name); object_t *addob(obpile_t *where, char *name);
object_t *addobject(obpile_t *where, char *name, int canstack); object_t *addobject(obpile_t *where, char *name, int canstack);
int addobburst(cell_t *where, int range, int dirtype, char *name);
obmod_t *addobmod(enum OBMOD id, char *suffix, enum BODYPART bp); obmod_t *addobmod(enum OBMOD id, char *suffix, enum BODYPART bp);
obpile_t *addobpile(lifeform_t *owner, cell_t *where); obpile_t *addobpile(lifeform_t *owner, cell_t *where);
objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid); objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid);
@ -20,6 +21,7 @@ void brightflash(cell_t *centre, int range, lifeform_t *immunelf);
object_t *canstackob(obpile_t *op, object_t *match); object_t *canstackob(obpile_t *op, object_t *match);
object_t *canstacknewot(obpile_t *op, objecttype_t *match); object_t *canstacknewot(obpile_t *op, objecttype_t *match);
int changemat(object_t *o, enum MATERIAL mat); int changemat(object_t *o, enum MATERIAL mat);
objecttype_t *checkobnames(char *haystack, char *needle);
void copyobprops(object_t *dst, object_t *src); void copyobprops(object_t *dst, object_t *src);
int countnames(char **list); int countnames(char **list);
int countobs(obpile_t *op); int countobs(obpile_t *op);
@ -41,6 +43,7 @@ int geteffecttime(int min, int max, enum BLESSTYPE isblessed);
objecttype_t *getlinkspell(object_t *o); objecttype_t *getlinkspell(object_t *o);
int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt); int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt);
int getobaccuracy(object_t *wep); int getobaccuracy(object_t *wep);
int getobbonus(object_t *o);
int getobvalue(object_t *o); int getobvalue(object_t *o);
//int getobtypevalue(objecttype_t *ot); //int getobtypevalue(objecttype_t *ot);
char *getaccuracyname(int accpct); char *getaccuracyname(int accpct);
@ -55,6 +58,7 @@ char getglyph(object_t *o);
char *genhiddenname(enum OBCLASS id); char *genhiddenname(enum OBCLASS id);
char *gethiddenname(object_t *o); char *gethiddenname(object_t *o);
int getobattackdelay(object_t *o); int getobattackdelay(object_t *o);
float getobhppct(object_t *o);
int getletindex(char let); int getletindex(char let);
int getmaterialvalue(enum MATERIAL mat ); int getmaterialvalue(enum MATERIAL mat );
int getmaxthrowrange(lifeform_t *lf, object_t *o); int getmaxthrowrange(lifeform_t *lf, object_t *o);
@ -63,9 +67,10 @@ int getnumshards(object_t *o);
int getnutritionbase(object_t *o); int getnutritionbase(object_t *o);
int getnutrition(object_t *o); int getnutrition(object_t *o);
char *getobdesc(object_t *o, char *buf); char *getobdesc(object_t *o, char *buf);
char *getobextrainfo(object_t *o, char *buf);
cell_t *getoblocation(object_t *o); cell_t *getoblocation(object_t *o);
char *getobname(object_t *o, char *buf, int count); char *getobname(object_t *o, char *buf, int count);
char *real_getobname(object_t *o, char *buf, int count, int wantcondition, int adjustforblind, int wantblesscurse); char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wantcondition, int adjustforblind, int wantblesscurse);
float getobpileweight(obpile_t *op); float getobpileweight(obpile_t *op);
char *getobconditionname(object_t *o, char *buf); char *getobconditionname(object_t *o, char *buf);
char *getobhurtname(object_t *o, enum DAMTYPE damtype); char *getobhurtname(object_t *o, enum DAMTYPE damtype);
@ -76,6 +81,7 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth
char *getrandomob(map_t *map, char *buf); char *getrandomob(map_t *map, char *buf);
char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf); char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf);
char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf); char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf);
enum SPELLSCHOOL getschool(enum OBTYPE sid);
char *getschoolname(enum SPELLSCHOOL sch); char *getschoolname(enum SPELLSCHOOL sch);
int getshatterdam(object_t *o); int getshatterdam(object_t *o);
int getthrowdam(object_t *o); int getthrowdam(object_t *o);
@ -88,6 +94,7 @@ object_t *hasobwithflag(obpile_t *op, enum FLAG flagid);
object_t *hasobwithflagval(obpile_t *op, enum FLAG flagid, int val0, int val1, int val2, char *text); object_t *hasobwithflagval(obpile_t *op, enum FLAG flagid, int val0, int val1, int val2, char *text);
object_t *hasobid(obpile_t *op, int id); object_t *hasobid(obpile_t *op, int id);
void identify(object_t *o); void identify(object_t *o);
void ignite(object_t *o);
void initobjects(void); void initobjects(void);
flag_t *isarmour(object_t *o); flag_t *isarmour(object_t *o);
int isactivated(object_t *o); int isactivated(object_t *o);
@ -107,6 +114,7 @@ int isfirearm(object_t *o);
int isflammable(object_t *o); int isflammable(object_t *o);
int isknown(object_t *o); int isknown(object_t *o);
int isidentified(object_t *o); int isidentified(object_t *o);
int isimpassableob(object_t *o, lifeform_t *lf);
int ismetal(enum MATERIAL mat); int ismetal(enum MATERIAL mat);
int ismissile(object_t *o); int ismissile(object_t *o);
int isoperable(object_t *o); int isoperable(object_t *o);
@ -123,6 +131,7 @@ void killobpile(obpile_t *o);
void killoc(objectclass_t *oc); void killoc(objectclass_t *oc);
void killot(objecttype_t *ot); void killot(objecttype_t *ot);
lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level); lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level);
void makeduller(object_t *o, int howmuch);
void makeknown(enum OBTYPE otid); void makeknown(enum OBTYPE otid);
object_t *moveob(object_t *src, obpile_t *dst, int howmany); object_t *moveob(object_t *src, obpile_t *dst, int howmany);
void modbonus(object_t *o, int amt); void modbonus(object_t *o, int amt);
@ -141,7 +150,7 @@ int pilehasletter(obpile_t *op, char let);
void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE isblessed, int *seen); void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE isblessed, int *seen);
int pour(lifeform_t *lf, object_t *o); int pour(lifeform_t *lf, object_t *o);
void quaff(lifeform_t *lf, object_t *o); void quaff(lifeform_t *lf, object_t *o);
void readsomething(lifeform_t *lf, object_t *o); int readsomething(lifeform_t *lf, object_t *o);
void removedeadobs(obpile_t *op); void removedeadobs(obpile_t *op);
int removeob(object_t *o, int howmany); int removeob(object_t *o, int howmany);
object_t *relinkob(object_t *src, obpile_t *dst); object_t *relinkob(object_t *src, obpile_t *dst);

570
spell.c
View File

@ -4,6 +4,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "attack.h"
#include "defs.h" #include "defs.h"
#include "flag.h" #include "flag.h"
#include "io.h" #include "io.h"
@ -21,30 +22,79 @@ extern WINDOW *msgwin;
extern job_t *firstjob; extern job_t *firstjob;
int abilityeffects(lifeform_t *user, enum OBTYPE abilid) { int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifeform_t *target) {
char username[BUFLEN]; char username[BUFLEN];
char buf[BUFLEN]; char buf[BUFLEN];
flag_t *f;
getlfname(user, username); getlfname(user, username);
if (abilid == OT_A_JUMP) { if (abilid == OT_A_GRAB) {
char dirch;
flag_t *f;
f = lfhasflag(user, F_GRABBING);
if (f) {
if (isplayer(user)) msg("You are already holding someone!");
return B_TRUE;
}
f = lfhasflag(user, F_GRABBEDBY);
if (f) {
if (isplayer(user)) msg("You are already being held by someone!");
return B_TRUE;
}
// ask for direction
if (!targcell) {
dirch = askchar("Grab in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE);
if (dirch == '.') {
if (isplayer(user)) msg("You can't grab yourself!");
return B_TRUE;
} else {
int dir;
dir = chartodir(dirch);
if (dir == D_NONE) {
if (isplayer(user)) msg("Cancelled.");
return B_TRUE ;
} else {
targcell = getcellindir(user->cell, dir);
}
}
}
target = targcell->lf;
if (!target) {
if (isplayer(user)) msg("There is nobody there to grab!");
return B_TRUE;
}
addflag(user->flags, F_GRABBING, target->id, NA, NA, NULL);
addflag(target->flags, F_GRABBEDBY, user->id, NA, NA, NULL);
} else if (abilid == OT_A_JUMP) {
lifeform_t *victim = NULL; lifeform_t *victim = NULL;
char victimname[BUFLEN]; char victimname[BUFLEN];
int dodged = B_FALSE; int dodged = B_FALSE;
cell_t *where = NULL, *origcell; cell_t *origcell;
if (!targcell) {
sprintf(buf, "Jump where (max distance 2)?"); sprintf(buf, "Jump where (max distance 2)?");
while (!where) { while (!targcell) {
// ask where // ask where
where = askcoords(buf, TT_NONE); targcell = askcoords(buf, TT_NONE);
if (!where) { if (!targcell) {
return B_TRUE; return B_TRUE;
} else if (getcelldist(user->cell, where) > 2) { } else if (getcelldist(user->cell, targcell) > 2) {
where = NULL; targcell = NULL;
if (isplayer(user)) {
sprintf(buf, "You can't jump that far! Jump where (max distance 2)?"); sprintf(buf, "You can't jump that far! Jump where (max distance 2)?");
} else if (!haslos(user, where)) { }
where = NULL; } else if (!haslos(user, targcell)) {
targcell = NULL;
if (isplayer(user)) {
sprintf(buf, "You can't see where to land! Jump where (max distance 2)?"); sprintf(buf, "You can't see where to land! Jump where (max distance 2)?");
} }
} }
}
}
if (isburdened(user)) { if (isburdened(user)) {
if (isplayer(user)) { if (isplayer(user)) {
@ -63,7 +113,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid) {
origcell = user->cell; origcell = user->cell;
// did you land on anyone? // did you land on anyone?
victim = haslf(where); victim = haslf(targcell);
if (victim) { if (victim) {
cell_t *c; cell_t *c;
int acc; int acc;
@ -86,7 +136,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid) {
dodged = B_TRUE; dodged = B_TRUE;
} }
} }
movelf(user, where); movelf(user, targcell);
// announce // announce
if (isplayer(user)) { if (isplayer(user)) {
@ -140,11 +190,16 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid) {
msg("You are too tired to sprint right now."); msg("You are too tired to sprint right now.");
} }
return B_TRUE; return B_TRUE;
} else if (lfhasflag(user, F_SPRINTING)) {
if (isplayer(user)) {
msg("You are already sprinting!");
}
return B_TRUE;
} }
// TODO: calculate time based on: // TODO: calculate time based on:
// constitution (or max hp?) // constitution (or max hp?)
// running speed // running speed
howlong = 3; howlong = 5;
addtempflag(user->flags, F_SPRINTING, B_TRUE, NA, NA, NULL, howlong); addtempflag(user->flags, F_SPRINTING, B_TRUE, NA, NA, NULL, howlong);
} else if (abilid == OT_A_DEBUG) { } else if (abilid == OT_A_DEBUG) {
cell_t *where; cell_t *where;
@ -191,7 +246,60 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid) {
} else { } else {
msg("There is nobody there!"); msg("There is nobody there!");
} }
} else if (abilid == OT_A_HEAVYBLOW) {
object_t *wep;
char dirch;
char targetname[BUFLEN];
flag_t *f;
wep = getweapon(user);
if (!wep) {
if (isplayer(user)) msg("You need a bashing weapon to perform a heavy blow!");
return B_TRUE;
} else if (getdamtype(wep) != DT_BASH) {
if (isplayer(user)) msg("You need a bashing weapon to perform a heavy blow!");
return B_TRUE;
} }
// ask for direction
if (!targcell) {
dirch = askchar("Attack in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE);
if (dirch == '.') {
// yourself!
targcell = user->cell;
} else {
int dir;
dir = chartodir(dirch);
if (dir == D_NONE) {
if (isplayer(user)) msg("Cancelled.");
return B_TRUE ;
} else {
targcell = getcellindir(user->cell, dir);
}
}
}
target = targcell->lf;
if (!target) {
if (isplayer(user)) msg("There is nobody there to attack!");
return B_TRUE;
}
getlfname(target, targetname);
f = addflag(wep->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL);
attackcell(user, targcell);
killflag(f);
}
// expire ability
f = lfhasflagval(user, F_CANWILL, abilid, NA, NA, NULL);
if (f) {
if (f->val[2] != NA) {
// ie. it will go to 0 next turn.
f->val[1] = -1;
}
}
return B_FALSE; return B_FALSE;
} }
@ -207,6 +315,19 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
// default to unseen // default to unseen
if (seenbyplayer) *seenbyplayer = B_FALSE; if (seenbyplayer) *seenbyplayer = B_FALSE;
// reverse some spells if cursed
if (blessed == B_CURSED) {
switch (spellid) {
case OT_S_LIGHT:
spellid = OT_S_DARKNESS;
break;
default:
break;
}
}
if (spellid == OT_S_ABSORBMETAL) { if (spellid == OT_S_ABSORBMETAL) {
int i; int i;
float totalmass = 0; float totalmass = 0;
@ -290,6 +411,33 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else { } else {
fizzle(caster); fizzle(caster);
} }
} else if (spellid == OT_S_ANIMATEDEAD) {
int i;
object_t *o,*nexto;
int donesomething = B_FALSE;
// animate corpses within los of caster
for (i = 0; i < caster->nlos; i++) {
targcell = caster->los[i];
for (o = targcell->obpile->first ; o ; o = nexto) {
nexto = o->next;
if (o->type->id == OT_CORPSE) {
lifeform_t *newlf;
newlf = makezombie(o);
if (newlf) {
if (isplayer(caster) && skillcheck(caster, A_IQ, 20, 0)) {
makefriendly(newlf);
}
donesomething = B_TRUE;
}
}
}
}
if (donesomething) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else {
fizzle(caster);
}
} else if (spellid == OT_S_ANIMATEMETAL) { } else if (spellid == OT_S_ANIMATEMETAL) {
object_t *o; object_t *o;
o = getweapon(caster); o = getweapon(caster);
@ -331,6 +479,40 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else { } else {
fizzle(caster); fizzle(caster);
} }
} else if (spellid == OT_S_BLINDNESS) {
int failed = B_FALSE;
// ask for target
if (!validatespelllf(caster, &target)) return B_TRUE;
if (isblind(target)) {
fizzle(caster);
return B_FALSE;
}
if (hasmr(target) || skillcheck(caster, A_IQ, 24, 0)) {
failed = B_TRUE;
}
if (target) {
if (failed) {
if (isplayer(target)) {
msg("Your vision darkens for a moment.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, target->cell)) {
char targetname[BUFLEN];
getlfname(target, targetname);
msg("%s seems to lose its vision for a moment.", targetname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
} else {
int howlong = 7;
howlong = getspellduration(5,10,blessed);
addtempflag(target->flags, F_BLIND, B_TRUE, NA, NA, NULL, howlong);
}
} else {
fizzle(caster);
}
} else if (spellid == OT_S_BLINK) { } else if (spellid == OT_S_BLINK) {
if (hasmr(caster)) { if (hasmr(caster)) {
if (isplayer(caster)) { if (isplayer(caster)) {
@ -356,10 +538,50 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} }
teleportto(caster, targcell); teleportto(caster, targcell);
} }
} else if (spellid == OT_S_BURNINGWAVE) {
cell_t *c;
if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid)) return B_TRUE;
if (haslos(player, caster->cell)) {
msg("%s shoots a wave of fire!",castername);
}
// create a line of fire towards the target cell
c = caster->cell;
while (c != targcell) {
int dir;
dir = getdirtowards(c, targcell, NULL, B_FALSE);
c = getcellindir(c, dir);
if (!c) break;
if (c->type->solid) break;
// set on fire
addob(c->obpile, "medium fire");
if (c->lf) {
char buf[BUFLEN];
getlfname(c->lf,buf);
msg("%s burn%s!",buf,isplayer(c->lf) ? "" : "s");
losehp(c->lf, rolldie(2,10), DT_FIRE, caster, "a wave of fire");
}
}
} else if (spellid == OT_S_CLOUDKILL) {
if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, spellid)) return B_TRUE;
if (targcell->type->solid) {
fizzle(caster);
return B_FALSE;
}
addobburst(targcell, 1, DT_COMPASS, "cloud of gas");
if (haslos(player, targcell)) {
msg("A cloud of poison gas appears!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_CONECOLD) { } else if (spellid == OT_S_CONECOLD) {
char lfname[BUFLEN]; char lfname[BUFLEN];
int acc; int acc;
if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid)) return B_TRUE;
// animation // animation
anim(caster->cell, targcell, '}'); anim(caster->cell, targcell, '}');
if (isplayer(caster) || haslos(player, caster->cell)) { if (isplayer(caster) || haslos(player, caster->cell)) {
@ -385,6 +607,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
msg("A blast of coldness misses %s.",lfname); msg("A blast of coldness misses %s.",lfname);
} }
} }
} else {
object_t *o, *nexto;
for (o = targcell->obpile->first; o ; o = nexto) {
nexto = o->next;
takedamage(o, 0, DT_COLD);
}
} }
} else if (spellid == OT_S_CREATEMONSTER) { } else if (spellid == OT_S_CREATEMONSTER) {
cell_t *where; cell_t *where;
@ -445,9 +673,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
if (blessed) { if (blessed) {
//newlf = addlf(where, r->id, getrandommonlevel(where->map->depth)); //newlf = addlf(where, r->id, getrandommonlevel(where->map->depth));
newlf = addmonster(where, r->id, randomjobsok); newlf = addmonster(where, r->id, randomjobsok, 1);
} else { } else {
newlf = addmonster(where, R_RANDOM, randomjobsok); newlf = addmonster(where, R_RANDOM, randomjobsok, 1);
} }
if (newlf) { if (newlf) {
// assign job if required // assign job if required
@ -477,6 +705,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} }
return B_TRUE; return B_TRUE;
} }
} else if (spellid == OT_S_DARKNESS) {
// centre on the caster
if (isplayer(caster) || haslos(player, caster->cell)) {
msg("A cloud of darkness descends!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
makelitradius(caster->cell, 10, L_DARK);
} else if (spellid == OT_S_DETECTAURA) { } else if (spellid == OT_S_DETECTAURA) {
if (isplayer(caster)) { if (isplayer(caster)) {
object_t *o; object_t *o;
@ -552,7 +787,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
*/ */
} else if (spellid == OT_S_DETONATE) { } else if (spellid == OT_S_DETONATE) {
// don't need line of fire! // don't need line of fire!
if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_DOOR, B_FALSE)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_DOOR, B_FALSE, spellid)) return B_TRUE;
explodecells(targcell, 20, B_TRUE, NULL, 0, B_TRUE); explodecells(targcell, 20, B_TRUE, NULL, 0, B_TRUE);
@ -563,7 +798,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
float totalmass = 0; float totalmass = 0;
object_t *o, *nexto; object_t *o, *nexto;
if (!validatespellcell(caster, &targcell, TT_OBJECT, B_FALSE)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_OBJECT, B_FALSE, spellid)) return B_TRUE;
// how much metal is there? // how much metal is there?
for (o = targcell->obpile->first ; o ; o = nexto) { for (o = targcell->obpile->first ; o ; o = nexto) {
@ -686,7 +921,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else if (spellid == OT_S_ENERGYBOLT) { } else if (spellid == OT_S_ENERGYBOLT) {
char lfname[BUFLEN]; char lfname[BUFLEN];
int acc; int acc;
if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid)) return B_TRUE;
// animation // animation
anim(caster->cell, targcell, '}'); anim(caster->cell, targcell, '}');
if (isplayer(caster) || haslos(player, caster->cell)) { if (isplayer(caster) || haslos(player, caster->cell)) {
@ -716,7 +951,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else if (spellid == OT_S_FIREBALL) { } else if (spellid == OT_S_FIREBALL) {
int failed = B_FALSE; int failed = B_FALSE;
// ask for a target cell // ask for a target cell
if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE)) return B_TRUE; if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, spellid)) return B_TRUE;
if (targcell && haslof(caster, targcell)) { // need line of FIRE for this, not just sight if (targcell && haslof(caster, targcell)) { // need line of FIRE for this, not just sight
if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) { if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) {
int dir; int dir;
@ -783,7 +1018,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else if (spellid == OT_S_FIREDART) { } else if (spellid == OT_S_FIREDART) {
char lfname[BUFLEN]; char lfname[BUFLEN];
int acc; int acc;
if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE)) return B_TRUE; if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, spellid)) return B_TRUE;
// animation // animation
anim(caster->cell, targcell, '}'); anim(caster->cell, targcell, '}');
if (isplayer(caster) || haslos(player, caster->cell)) { if (isplayer(caster) || haslos(player, caster->cell)) {
@ -809,11 +1044,44 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
msg("A dart of flame misses %s.",lfname); msg("A dart of flame misses %s.",lfname);
} }
} }
} else {
object_t *o, *nexto;
for (o = targcell->obpile->first; o ; o = nexto) {
nexto = o->next;
takedamage(o, 0, DT_FIRE);
}
}
} else if (spellid == OT_S_FLAMEBURST) {
int range = 1;
int x,y;
// announce
if (isplayer(caster) || haslos(player, caster->cell)) {
msg("%s emit%s a blast of fire!",castername,isplayer(caster) ? "" : "s");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
animradialorth(caster->cell, range, '}');
for (y = caster->cell->y - range ; y <= caster->cell->y + range; y++) {
for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) {
targcell = getcellat(caster->cell->map, x,y);
if (targcell && (getcelldistorth(caster->cell, targcell) <= range)) {
if (targcell->lf && (targcell->lf != caster) && haslof(caster, targcell)) {
char lfname[BUFLEN];
// automatic hit
getlfname(targcell->lf, lfname);
if (haslos(caster, targcell)) {
msg("%s burn%s!",lfname,isplayer(targcell->lf) ? "" : "s");
}
losehp(targcell->lf, rolldie(2,8)+3, DT_MAGIC, caster, "a burst of fire");
}
}
}
} }
} else if (spellid == OT_S_FLAMEPILLAR) { } else if (spellid == OT_S_FLAMEPILLAR) {
int failed = B_FALSE; int failed = B_FALSE;
// ask for a target cell // ask for a target cell
if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid)) return B_TRUE;
if (targcell && haslos(caster, targcell)) { if (targcell && haslos(caster, targcell)) {
if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) { if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) {
// create flame there // create flame there
@ -853,14 +1121,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else { } else {
int amt; int amt;
char obname[BUFLEN]; char obname[BUFLEN];
getobname(o, obname, o->amt);
msg("Your %s glows %s for a moment.", noprefix(obname), (blessed == B_CURSED) ? "black" : "green");
if (seenbyplayer) *seenbyplayer = B_TRUE;
if (blessed == B_CURSED) { if (blessed == B_CURSED) {
amt = -1; amt = -1;
} else { } else {
amt = 1; amt = 1;
} }
modbonus(o, amt); modbonus(o, amt);
getobname(o, obname, o->amt);
msg("Your %s glows %s for a moment.", noprefix(obname), (blessed == B_CURSED) ? "black" : "green");
} }
} else { } else {
// monsters can't id things! // monsters can't id things!
@ -976,7 +1245,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} }
} else if (spellid == OT_S_HASTE) { } else if (spellid == OT_S_HASTE) {
int howlong = 15; int howlong = 15;
if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid)) return B_TRUE;
target = targcell->lf; target = targcell->lf;
@ -1001,6 +1270,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
addtempflag(target->flags, F_FASTMOVE, 5, NA, NA, NULL, howlong); addtempflag(target->flags, F_FASTMOVE, 5, NA, NA, NULL, howlong);
} }
} else if (spellid == OT_S_HEALING) { } else if (spellid == OT_S_HEALING) {
int donesomething = B_FALSE;
flag_t *f;
target = caster; target = caster;
if (hasmr(target)) { if (hasmr(target)) {
@ -1011,6 +1282,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} }
return B_FALSE; return B_FALSE;
} }
// cure certain bad effects
if (killflagsofid(target->flags, F_PAIN)) {
donesomething = B_TRUE;
}
if (target->hp < target->maxhp) { if (target->hp < target->maxhp) {
switch (blessed) { switch (blessed) {
case B_BLESSED: case B_BLESSED:
@ -1035,12 +1312,23 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
msg("%s looks healthier!", buf); msg("%s looks healthier!", buf);
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
} else { donesomething = B_TRUE;
}
f = lfhasflag(target, F_FOODPOISONED);
if (f) {
killflag(f);
donesomething = B_TRUE;
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
if (!donesomething) {
if (isplayer(target)) { if (isplayer(target)) {
nothinghappens(); nothinghappens();
} }
} }
} else if (spellid == OT_S_HEALINGMIN) { } else if (spellid == OT_S_HEALINGMIN) {
int donesomething = B_FALSE;
flag_t *f;
target = caster; target = caster;
if (hasmr(target)) { if (hasmr(target)) {
if (isplayer(target) || haslos(player, target->cell)) { if (isplayer(target) || haslos(player, target->cell)) {
@ -1050,6 +1338,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} }
return B_FALSE; return B_FALSE;
} }
// cure bad effects instead of healing
if (killflagsofid(target->flags, F_PAIN)) {
return B_FALSE;
}
if (target->hp < target->maxhp) { if (target->hp < target->maxhp) {
switch (blessed) { switch (blessed) {
case B_BLESSED: case B_BLESSED:
@ -1071,7 +1365,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
msg("%s looks a little healthier!", buf); msg("%s looks a little healthier!", buf);
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
} else { donesomething = B_TRUE;
}
f = lfhasflag(target, F_FOODPOISONED);
if (f) {
killflag(f);
donesomething = B_TRUE;
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
if (!donesomething) {
if (isplayer(target)) { if (isplayer(target)) {
nothinghappens(); nothinghappens();
} }
@ -1102,9 +1405,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
// charges // charges
charges = getcharges(o); charges = getcharges(o);
if (charges == -1) { if (charges == -1) {
msglower("%c - %s.",o->letter, buf); msgnocap("%c - %s.",o->letter, buf);
} else { } else {
msglower("%c - %s (%d charges left).",o->letter, buf, charges); msgnocap("%c - %s (%d charges left).",o->letter, buf, charges);
} }
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
@ -1140,7 +1443,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
char lfname[BUFLEN]; char lfname[BUFLEN];
int acc; int acc;
if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE)) return B_TRUE; if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, spellid)) return B_TRUE;
// animation // animation
anim(caster->cell, targcell, '}'); anim(caster->cell, targcell, '}');
if (isplayer(caster) || haslos(player, caster->cell)) { if (isplayer(caster) || haslos(player, caster->cell)) {
@ -1339,12 +1642,71 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
return B_TRUE; return B_TRUE;
} }
if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid)) return B_TRUE;
// 4 is the same as ST_TITANIC strength // 4 is the same as ST_TITANIC strength
fireat(caster, targob, targcell, 4 , NULL); fireat(caster, targob, targcell, 4 , NULL);
} else if (spellid == OT_S_PAIN) {
int failed = B_FALSE;
// ask for target
if (!validatespelllf(caster, &target)) return B_TRUE;
if (lfhasflag(target, F_PAIN)) {
fizzle(caster);
return B_FALSE;
}
// make this a constitution skill check ?
//if (hasmr(target) || skillcheck(caster, A_IQ, -5)) {
if (hasmr(target)) {
failed = B_TRUE;
}
if (target) {
if (failed) {
if (isplayer(target)) {
msg("Your skin hurts for a moment.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, target->cell)) {
char targetname[BUFLEN];
getlfname(target, targetname);
msg("%s winces in pain, then recovers.", targetname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
} else {
int howlong = 7;
howlong = getspellduration(3,5,blessed);
addtempflag(target->flags, F_PAIN, B_TRUE, NA, NA, NULL, howlong);
}
} else {
fizzle(caster);
}
} else if (spellid == OT_S_PETRIFY) {
if (!validatespelllf(caster, &target)) return B_TRUE;
// savingthrow
if (skillcheck(target, SC_IQ, 30, 0)) {
if (haslos(player, target->cell)) {
char lfname[BUFLEN];
getlfname(target, lfname);
msg("%s glows grey momentarily.", lfname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_TRUE;
}
if (!stone(target)) {
// successful
if (haslos(player, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else {
// failed!
fizzle(caster);
}
} else if (spellid == OT_S_PULLMETAL) { } else if (spellid == OT_S_PULLMETAL) {
if (!validatespellcell(caster, &targcell,TT_OBJECT, B_TRUE)) return B_TRUE; if (!validatespellcell(caster, &targcell,TT_OBJECT, B_TRUE, spellid)) return B_TRUE;
if (targcell->lf) { if (targcell->lf) {
object_t *o; object_t *o;
@ -1378,7 +1740,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
if (hasmr(target)) { if (hasmr(target)) {
failed = B_TRUE; failed = B_TRUE;
} else if (metalweight <= getmaxliftweight(caster)) { } else if (getobpileweight(caster->pack) + metalweight <= getmaxcarryweight(caster)) {
// they get pulled towards caster // they get pulled towards caster
failed = pullnextto(target, caster->cell); failed = pullnextto(target, caster->cell);
} else { } else {
@ -1419,7 +1781,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else if (haslos(player, caster->cell)) { } else if (haslos(player, caster->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
if (getobweight(targob) < getmaxliftweight(caster) ) { if (getobpileweight(caster->pack) + getobweight(targob) <= getmaxcarryweight(caster)) {
// move it to the player // move it to the player
pullobto(targob, caster); pullobto(targob, caster);
} else { } else {
@ -1551,7 +1913,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} }
} else if (spellid == OT_S_KNOCK) { } else if (spellid == OT_S_KNOCK) {
object_t *o; object_t *o;
if (!validatespellcell(caster, &targcell,TT_DOOR, B_FALSE)) return B_TRUE; if (!validatespellcell(caster, &targcell,TT_DOOR, B_FALSE, spellid)) return B_TRUE;
o = hasobwithflag(targcell->obpile, F_DOOR); o = hasobwithflag(targcell->obpile, F_DOOR);
if (o) { if (o) {
int dooropen; int dooropen;
@ -1566,6 +1928,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
takedamage(o, 999, DT_DIRECT); takedamage(o, 999, DT_DIRECT);
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
} else if (targcell->lf && (targcell->lf != caster)) {
int dir;
target = targcell->lf;
dir = getdirtowards(caster->cell, targcell, target, B_FALSE);
knockback(target, dir, 2, caster);
if (haslos(caster, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else { } else {
fizzle(caster); fizzle(caster);
} }
@ -1576,7 +1946,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
msg("The area is lit by a magical light!"); msg("The area is lit by a magical light!");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
makelitradius(caster->cell, 10, B_PERM); makelitradius(caster->cell, 10, L_PERM);
// blind anyone with nightvis who sees it // blind anyone with nightvis who sees it
// (player last) // (player last)
@ -1585,8 +1955,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
if (lfhasflag(l, F_SEEINDARK)) { if (lfhasflag(l, F_SEEINDARK)) {
// if you don't have eyes, your'e safe! // if you don't have eyes, your'e safe!
if (!lfhasflagval(l, F_NOBODYPART, BP_EYES, NA, NA, NULL)) { if (!lfhasflagval(l, F_NOBODYPART, BP_EYES, NA, NA, NULL)) {
// blind for 5-10 turns // blind for 1-3 turns
addtempflag(l->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(5,10)); addtempflag(l->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(1,3));
} }
} }
// undead will flee from light // undead will flee from light
@ -1724,10 +2094,34 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
// become the new race! // become the new race!
setrace(target, r->id); setrace(target, r->id);
if (haslos(player, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else { } else {
fizzle(caster); fizzle(caster);
return B_TRUE; return B_TRUE;
} }
} else if (spellid == OT_S_SLEEP) {
int howlong;
if (!validatespelllf(caster, &target)) return B_TRUE;
if (hasmr(target)) {
if (isplayer(target)) {
msg("You yawn.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, target->cell)) {
getlfname(target, buf);
msg("%s yawns.", buf);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
}
howlong = getspellduration(5,15,blessed);
addtempflag(target->flags, F_ASLEEP, B_TRUE, NA, NA, NULL, howlong);
if (isplayer(target) || haslos(player, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_SLOW) { } else if (spellid == OT_S_SLOW) {
int howlong = 15; int howlong = 15;
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespelllf(caster, &target)) return B_TRUE;
@ -1747,12 +2141,29 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
howlong = rnd(5,25); howlong = rnd(5,25);
addtempflag(target->flags, F_SLOWACT, 5, NA, NA, NULL, howlong); addtempflag(target->flags, F_SLOWACT, 5, NA, NA, NULL, howlong);
addtempflag(target->flags, F_SLOWMOVE, 5, NA, NA, NULL, howlong); addtempflag(target->flags, F_SLOWMOVE, 5, NA, NA, NULL, howlong);
/* if (isplayer(target) || haslos(player, target->cell)) {
if (!isplayer(target) && haslos(player, target->cell)) { if (seenbyplayer) *seenbyplayer = B_TRUE;
getlfname(target, buf); }
msg("%s seems to slow down.",buf); } else if (spellid == OT_S_SPARK) {
object_t *o,*nexto;
int donesomething = B_FALSE;
if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, B_FALSE, spellid)) return B_TRUE;
if (haslos(player, targcell)) {
msg("A small spark appears.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
for (o = targcell->obpile->first ; o ; o = nexto) {
nexto = o->next;
if (isflammable(o)) {
takedamage(o, 0, DT_FIRE);
donesomething = B_TRUE;
}
}
if (targcell->lf) {
losehp(targcell->lf, 0, DT_FIRE, caster, "a spark");
} }
*/
} else if (spellid == OT_S_TELEPORT) { } else if (spellid == OT_S_TELEPORT) {
cell_t *c = NULL; cell_t *c = NULL;
@ -1981,7 +2392,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
if (!hasflag(o->flags, F_IMPASSABLE) && canpickup(target, o, ALL)) { if (!hasflag(o->flags, F_IMPASSABLE) && canpickup(target, o, ALL)) {
relinkob(o, target->pack); // move to pack relinkob(o, target->pack); // move to pack
if (isplayer(target)) { if (isplayer(target)) {
msglower("%c - %s.", o->letter, obname); msgnocap("%c - %s.", o->letter, obname);
} else { } else {
msg("%s is gifted with %s.", lfname, obname); msg("%s is gifted with %s.", lfname, obname);
} }
@ -2051,6 +2462,49 @@ int getspellduration(int min,int max,int blessed) {
return howlong; return howlong;
} }
int getspelllevel(enum OBTYPE spellid) {
flag_t *f;
objecttype_t *ot;
int level = 0;
ot = findot(spellid);
if (!ot) {
return 0;
}
f = hasflag(ot->flags, F_SPELLLEVEL);
if (f) {
level = f->val[0];
}
return level;
}
enum SPELLSCHOOL getspellschool(enum OBTYPE spellid) {
flag_t *f;
objecttype_t *ot;
ot = findot(spellid);
if (!ot) {
return SS_NONE;
}
f = hasflag(ot->flags, F_SPELLSCHOOL);
if (f) {
return f->val[0];
}
return SS_NONE;
}
int getspellrange(enum OBTYPE spellid) {
objecttype_t *st;
int range = UNLIMITED;
st = findot(spellid);
if (st) {
flag_t *f;
f = hasflag(st->flags, F_RANGE);
if (f) {
range = f->val[0];
}
}
return range;
}
// magically propel an object into lf's hands. // magically propel an object into lf's hands.
// if it's too big it'll hit them! // if it's too big it'll hit them!
void pullobto(object_t *o, lifeform_t *lf) { void pullobto(object_t *o, lifeform_t *lf) {
@ -2079,7 +2533,7 @@ void pullobto(object_t *o, lifeform_t *lf) {
} }
// where does it end up? // where does it end up?
obloc = getoblocation(o); obloc = getoblocation(o);
dir = getdirtowards(lf->cell, obloc, B_FALSE); dir = getdirtowards(lf->cell, obloc, NULL, B_FALSE);
newcell = getcellindir(lf->cell, dir); newcell = getcellindir(lf->cell, dir);
if (newcell) { if (newcell) {
// move next to player // move next to player
@ -2101,26 +2555,37 @@ void pullobto(object_t *o, lifeform_t *lf) {
} }
} }
cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlof) { cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlof, enum OBTYPE spellid) {
int maxrange = UNLIMITED;
maxrange = getspellrange(spellid);
if (*targcell == NULL) { if (*targcell == NULL) {
// ask for a target cell // ask for a target cell
if (isplayer(caster)) { if (isplayer(caster)) {
cell_t *where; cell_t *where;
char buf[BUFLEN]; char buf[BUFLEN];
if (maxrange == UNLIMITED) {
sprintf(buf, "Where will you target your spell?"); sprintf(buf, "Where will you target your spell?");
where = askcoords(buf, targtype);
if (where && haslos(caster, where)) {
if (needlof) {
if (haslof(caster, where)) {
*targcell = where;
} else { } else {
sprintf(buf, "Where will you target your spell [max range %d]?",maxrange);
}
where = askcoords(buf, targtype);
if (where && haslos(caster, where)) {
if (needlof && !haslof(caster, where)) {
// no line of sight
fizzle(caster);
return NULL;
} else if ((maxrange != UNLIMITED) && (getcelldist(caster->cell, where) > maxrange)) {
// out of range
fizzle(caster); fizzle(caster);
return NULL; return NULL;
}
} else { } else {
*targcell = where; *targcell = where;
} }
} else { } else {
// no line of sight or invalid cell
fizzle(caster); fizzle(caster);
return NULL; return NULL;
} }
@ -2183,6 +2648,7 @@ int getmpcost(enum OBTYPE oid) {
return cost; return cost;
} }
lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **target) { lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **target) {
if (*target) { if (*target) {
return *target; return *target;

View File

@ -2,14 +2,17 @@
#define __SPELLS_H #define __SPELLS_H
#include "defs.h" #include "defs.h"
int abilityeffects(lifeform_t *user, enum OBTYPE abilid); int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifeform_t *target);
int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer); int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer);
void fizzle(lifeform_t *caster); void fizzle(lifeform_t *caster);
int getiqreq(enum OBTYPE oid); int getiqreq(enum OBTYPE oid);
int getmpcost(enum OBTYPE oid); int getmpcost(enum OBTYPE oid);
int getspellduration(int min,int max,int blessed); int getspellduration(int min,int max,int blessed);
int getspelllevel(enum OBTYPE spellid);
enum SPELLSCHOOL getspellschool(enum OBTYPE spellid);
int getspellrange(enum OBTYPE spellid);
void pullobto(object_t *o, lifeform_t *lf); void pullobto(object_t *o, lifeform_t *lf);
cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlof); cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlof, enum OBTYPE spellid);
lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf); lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf);
#endif #endif

10
text.c
View File

@ -110,7 +110,7 @@ char *gettimetextfuzzy(char *retbuf, int wantpm) {
} else if (mins <= 35) { } else if (mins <= 35) {
sprintf(retbuf, "around half past %d", hours); sprintf(retbuf, "around half past %d", hours);
} else if (mins <= 45) { } else if (mins <= 45) {
sprintf(retbuf, "comung up to %d o'clock", (hours == 12) ? 1 : (hours+1)); sprintf(retbuf, "coming up to %d o'clock", (hours == 12) ? 1 : (hours+1));
} else { } else {
sprintf(retbuf, "nearly %d o'clock", (hours == 12) ? 1 : (hours+1)); sprintf(retbuf, "nearly %d o'clock", (hours == 12) ? 1 : (hours+1));
} }
@ -189,6 +189,10 @@ char *makeplural(char *text) {
if (rv) return newtext; if (rv) return newtext;
newtext = strrep(newtext, "scroll ", "scrolls ", &rv); newtext = strrep(newtext, "scroll ", "scrolls ", &rv);
if (rv) return newtext; if (rv) return newtext;
newtext = strrep(newtext, "splash ", "splashes ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "suit ", "suits ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "vial ", "vials ", &rv); newtext = strrep(newtext, "vial ", "vials ", &rv);
if (rv) return newtext; if (rv) return newtext;
@ -200,6 +204,10 @@ char *makeplural(char *text) {
// default // default
lastlet = text[strlen(text)-1]; lastlet = text[strlen(text)-1];
switch (lastlet) { switch (lastlet) {
case 'y': // change to 'ies'
text[strlen(text)-1] = '\0';
asprintf(&newtext, "%sies",text);
break;
case 's': case 's':
case 'o': // append "es" case 'o': // append "es"
asprintf(&newtext, "%ses",text); asprintf(&newtext, "%ses",text);