This commit is contained in:
Rob Pearce 2011-01-31 19:16:13 +00:00
parent 014d591109
commit 86ee482ce3
37 changed files with 43787 additions and 16512 deletions

View File

@ -1,2 +1,2 @@
nexus: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h flag.c flag.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h spell.c spell.h
gcc -g -o nexus nexus.c ai.c attack.c flag.c io.c lf.c map.c move.c objects.c text.c save.c spell.c -lncurses
gcc -Wall -g -o nexus nexus.c ai.c attack.c flag.c io.c lf.c map.c move.c objects.c text.c save.c spell.c -lncurses

561
ai.c
View File

@ -1,22 +1,36 @@
#include <stdio.h>
#include <stdlib.h>
#include "ai.h"
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "io.h"
#include "lf.h"
#include "map.h"
#include "move.h"
#include "nexus.h"
#include "objects.h"
#include "spell.h"
#include "text.h"
extern lifeform_t *player;
extern enum ERROR reason;
void aimove(lifeform_t *lf) {
int dir;
int wantdb = B_TRUE;
int db = B_FALSE;
object_t *curwep,*bestwep;
object_t *curwep,*bestwep, *o;
object_t *curgun,*bestgun;
flag_t *f;
//flag_t *nextf;
// lifeform_t *fleefrom = NULL;
lifeform_t *target;
char buf[BUFLEN];
enum BODYPART bp;
int x,y;
cell_t *c;
obpile_t *unarmedpile = NULL;
flag_t *unarmedflag = NULL;
if (wantdb && haslos(player, lf->cell)) {
@ -25,16 +39,21 @@ void aimove(lifeform_t *lf) {
db = B_FALSE;
}
if (db) dblog("AIMOVE: %s", lf->race->name);
if (db) {
char lfname[BUFLEN];
getlfname(lf, lfname);
dblog("AIMOVE: %s", lfname);
}
/*
// if lifeform isn't alive, skip turn
if (isdead(lf)) {
if (db) dblog(".oO { i am not alive, skipping turn. }");
taketime(lf, SPEED_DEAD);
return;
}
*/
// do we have a better weapon we could use?
@ -44,43 +63,260 @@ void aimove(lifeform_t *lf) {
if (curwep != bestwep) {
if (db) dblog(".oO { i have a better weapon than my current one (%s > %s) }",bestwep->type->name, curwep ? curwep->type->name : "nothing");
// weild better one
weild(lf, bestwep);
return;
if (!weild(lf, bestwep)) return;
}
// do we have a better firearm ?
curgun = getfirearm(lf);
bestgun = getbestfirearm(lf);
if (curgun != bestgun) {
if (db) dblog(".oO { i have a better gun than my current one (%s > %s) }",bestgun->type->name, curgun ? curgun->type->name : "nothing");
// weild better one
if (!weild(lf, bestgun)) return;
}
// do we have better armour?
for (bp = BP_RIGHTHAND ; bp < MAXBODYPARTS; bp++) {
object_t *curarm;
curarm = getarmour(lf, bp);
// do we have a better one?
for (o = lf->pack->first ; o ; o = o->next) {
if (isbetterarmourthan(o, curarm)) {
// wear this armour instead
if (!wear(lf, o)) return;
}
}
}
// now check whetehr we have ANY weapon
curwep = getattackwep(lf, &unarmedpile, &unarmedflag);
if (unarmedpile) killobpile(unarmedpile);
// before attacking targets,
// look for any object which we _covet_.
// ie. if we covet something, we will pick it up
// instead of attacking our target.
if (db) dblog(".oO { looking for covetted objects... }");
if (lookforobs(lf, B_COVETS)) {
if (db) dblog(".oO { found covetted object. returning. }");
return;
}
// do we already have a target we are attacking?
f = hasflag(lf->flags, F_TARGET);
if (f) {
int targid;
int lastx,lasty;
if (db) dblog(".oO { i have a target... }");
targid = f->val[0];
lastx = f->val[1];
lasty = f->val[2];
target = findlf(lf->cell->map, targid);
if (target) {
if (db) dblog(".oO { my target is lfid %d (%s). }", targid, target->race->name);
if (haslos(lf, target->cell)) {
if (db) dblog(".oO { i can see my target. will move towards it. }");
movetowards(lf, target->cell);
int goingtomove = B_TRUE;
enum OBTYPE spell;
object_t *gun;
// reset F_TARGET lifetime to full.
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);
// remember last known loc
f->val[1] = target->cell->x;
f->val[2] = target->cell->y;
goingtomove = B_TRUE;
// can we attack with spells (ie. ones which target the victim)?
spell = getattackspell(lf);
if (spell != OT_NONE) {
int spellfailed = B_FALSE;
lifeform_t *spelllf = NULL;
cell_t *spellcell = NULL;
object_t *spellob = NULL;
if (db) {
objecttype_t *st;
st = findot(spell);
dblog(".oO { will cast attack spell: %s }", st->name);
}
// special cases: eg. spells like telekenesis
if (spell == OT_S_TELEKINESIS) {
float maxweight;
object_t *poss[MAXPILEOBS];
int nposs;
int i;
// find nearest object which can be picked up
// this is copied out of the telekenesis spell code!
maxweight = getlfweight(lf, B_NOOBS) +
(getlfweight(lf, B_NOOBS) * (getstatmod(lf, A_IQ) / 100));
nposs = 0;
for (i = 0; i < lf->nlos; i++) {
object_t *o;
for (o = lf->los[i]->obpile->first ; o ; o = o->next) {
if (!hasflag(o->flags, F_NOPICKUP) &&
getobweight(o) <= maxweight) {
poss[nposs] = o;
nposs++;
if (nposs >= MAXPILEOBS) break;
}
}
if (nposs >= MAXPILEOBS) break;
}
if (nposs > 0) {
spellob = poss[rnd(0,nposs-1)];
} else {
spellfailed = B_TRUE;
}
// cast spell at the player
spelllf = target;
spellcell = target->cell;
} else {
spelllf = target;
spellcell = target->cell;
spellob = NULL;
}
if (!spellfailed && !castspell(lf, spell, spelllf, spellob, spellcell)) {
// spell succesful
return;
} else {
if (db) dblog(".oO { i cannot see my target }");
// TODO: move towards last known location
if (db) dblog(".oO { cast spell failed! }");
}
}
// can we attack by firing something?
gun = getfirearm(lf);
if (goingtomove && gun && getammo(lf)) {
setguntarget(lf, target);
if (!shoot(lf)) {
// succesful
return;
} else {
if (db) dblog(".oO { shoot gun failed! }");
}
}
// can we attack by throwing something?
if (goingtomove && getcelldist(lf->cell, target->cell) > 1) {
// TODO: or firing! check if we have a firearm first.
o = getbestmissile(lf);
if (o) {
if (db) dblog(".oO { will throw %s at my target instead of moving }", o->type->name);
// try to throw it!
if (!throwat(lf, o, target->cell)) {
// succesful
goingtomove = B_FALSE;
} else {
if (db) dblog(".oO { throw failed! }");
}
}
}
// do we have a valid melee attack?
if (!curwep) {
if (db) dblog(".oO { won't move towards target - i have no weapon. }");
goingtomove = B_FALSE;
}
if (goingtomove) {
if (!movetowards(lf, target->cell)) {
// success
return;
} else {
if (db) dblog(".oO { move towards failed! - reason = %d }",reason);
}
}
} else {
if (db) dblog(".oO { i cannot see my target. moving to last known loc %d/%d }",lastx,lasty);
// can't see target.
// move towards their last known location instead
addflag(lf->flags, F_TARGETCELL, lastx, lasty, NA, NULL);
// remove f_target
killflag(f);
/*
// just try to move in a random direction
if (db) dblog(".oO { will move randomly }");
// dorandommove will call taketime() if it fails,
// so it's safe to just return
dorandommove(lf, B_NOBADMOVES);
return;
*/
}
}
}
/*
if (lookforobs(lf, B_COVETS)) {
if (db) dblog(".oO { found covetted object. returning. }");
return;
}
*/
// do we have a target cell?
f = hasflag(lf->flags, F_TARGETCELL);
if (f) {
// if so, move towards it
x = f->val[0];
y = f->val[1];
if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y);
c = getcellat(lf->cell->map, x, y);
if (c) {
if (movetowards(lf, c)) {
// couldn't move towards it for some reason.
// so stop trying.
if (db) dblog(".oO { couldn't walk towards f_targetcell. abandoning it. }");
killflag(f);
// remember NOT to target this one.
lf->ignorecell = c;
} else {
if (db) dblog(".oO { successfully walked towards f_targetcell. }");
// moved towards it.
// reset lifetime
f->lifetime = AI_FOLLOWTIME;
// are we there yet?
if (lf->cell == c) {
if (db) dblog(".oO { arrived at f_targetcell. removing. }");
killflag(f);
}
}
} else {
// not attacking anyone in particular
if (db) dblog(".oO { f_targetcell doesn't exist. abandoning. }");
// destination doesn't exist!
killflag(f);
// remember NOT to target this one.
lf->ignorecell = c;
}
return;
}
if (db) dblog(".oO { i do not have a target. }");
// TODO: are we hostile? if so, look for a target
// look for any object which we want
if (db) dblog(".oO { looking for any ob which i want. }");
if (lookforobs(lf, B_ANY)) {
if (db) dblog(".oO { found ob that i want. returning. }");
return;
}
// not attacking anyone in particular
if (db) dblog(".oO { i do not have a target or can't move towards it. }");
// are we hostile? if so, look for a target
f = hasflag(lf->flags, F_HOSTILE);
if (f) {
int x,y;
cell_t *c;
if (db) dblog(".oO { i am hostile. looking for a target. }");
// look around for a target
// TODO: use our vis rang einstead of 10!
@ -90,71 +326,294 @@ void aimove(lifeform_t *lf) {
// cell exists and we can see it?
if (c && haslos(lf, c)) {
// player there?
if (c->lf && c->lf->controller == C_PLAYER) {
if (c->lf && (c->lf != lf) && isplayer(c->lf)) {
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
// target them!
addflag(lf->flags, F_TARGET, c->lf->id, -1, -1, "");
addtempflag(lf->flags, F_TARGET, c->lf->id, NA, NA, NULL, AI_FOLLOWTIME);
// tell the player
if (haslos(player, lf->cell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s sees you!", buf);
makenoise(lf, N_GETANGRY);
}
// then move towards them...
if (db) dblog(".oO { moving towards my new target }");
movetowards(lf, c);
return;
if (curwep) {
if (!movetowards(lf, c)) return;
} else {
if (db) dblog(".oO { won't move towards target - i have no weapon. }");
}
}
}
}
}
}
// are we friendly? if so, look for a target
f = hasflag(lf->flags, F_FRIENDLY);
if (f) {
int x,y;
if (db) dblog(".oO { i am friendly to the player. looking for a target. }");
// look around for a target
// TODO: use our vis rang einstead of 10!
for (y = lf->cell->y - 10; y <= lf->cell->y + 10; y++) {
for (x = lf->cell->x - 10; x <= lf->cell->x + 10; x++) {
c = getcellat(lf->cell->map, x, y);
// cell exists and we can see it?
if (c && haslos(lf, c)) {
// player there?
if (c->lf && (c->lf != lf) && !isplayer(c->lf)) {
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
// target them!
addtempflag(lf->flags, F_TARGET, c->lf->id, NA, NA, NULL, AI_FOLLOWTIME);
// then move towards them...
if (db) dblog(".oO { moving towards my new target }");
if (!movetowards(lf, c)) return;
}
}
}
}
}
// just try to move in a random direction
if (db) dblog(".oO { default - moving randomly }");
dorandommove(lf, B_NOBADMOVES);
return;
}
// if we get this far, just wait
dowait(lf);
rest(lf, B_TRUE);
}
int getdirtowards(lifeform_t *lf, cell_t *dst) {
int d;
int aipickup(lifeform_t *lf, object_t *o) {
if (isedible(o)) {
return eat(lf, o);
} else {
return pickup(lf, o, o->amt);
}
return B_FALSE;
}
enum OBTYPE getattackspell(lifeform_t *lf) {
flag_t *f;
enum OBTYPE poss[MAXPILEOBS];
int nposs = 0;
int db = B_TRUE;
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_CANWILL) {
poss[nposs] = f->val[0];
nposs++;
} else if (f->id == F_CANCAST) {
objecttype_t *ot;
ot = findot(f->val[0]);
if (cancast(lf, f->val[0], NULL)) {
if (db) {
dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?");
}
poss[nposs] = f->val[0];
nposs++;
} else {
if (db) {
if (ot) {
dblog(".oO { can't cast %s right now (mpcost=%d, i have %d) }",
ot ? ot->name : "?unkownspell?",
getmpcost(ot->id), lf->mp);
} else {
dblog(".oO { can't cast ?unknownspell? right now }");
}
}
}
}
}
// select a random one
if (nposs > 0) {
int sel;
sel = rnd(0,nposs-1);
return poss[sel];
}
return OT_NONE;
}
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if (isarmour(o)) {
object_t *curarm;
enum BODYPART bp;
flag_t *f;
// where does it go?
f = hasflag(o->flags, F_GOESON);
bp = f->val[0];
// is it better than what we have in that position?
curarm = getarmour(lf, bp);
if (isbetterwepthan(o, curarm)) {
return o;
}
}
}
return NULL;
}
object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op) {
object_t *bestwep, *o;
bestwep = getbestweapon(lf);
for (o = op->first ; o ; o = o->next) {
if (isweapon(o) && isbetterwepthan(o, bestwep) && canweild(lf, o)) {
return o;
}
}
return NULL;
}
// returns B_TRUE if we did something
int lookforobs(lifeform_t *lf, int covetsonly) {
object_t *o;
enum OBTYPE oid[MAXPILEOBS];
int noids = 0;
enum FLAG wantflag[MAXPILEOBS];
int nwantflags = 0;
int db = B_TRUE;
flag_t *f;
cell_t *c;
int mindist=9999,bestdir=D_NONE;
int n;
int i;
for (d = DC_N; d <= DC_NW; d++) {
c = getcellindir(lf->cell, d);
if (!c) continue;
if (c == dst) {
// destination is adjacent!
bestdir = d;
break;
// construct a list of objects which we want
noids = 0;
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_WANTS) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
oid[noids] = f->val[0];
noids++;
}
if (canmove(lf, d)) {
int thisdist;
thisdist = getcelldist(c, dst);
if (thisdist < mindist) {
mindist = thisdist;
bestdir = d;
} else if (f->id == F_WANTSOBFLAG) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
wantflag[nwantflags] = f->val[0];
nwantflags++;
}
}
}
// TODO: handle ties
return bestdir;
// current cell has an object we want?
o = hasobmulti(lf->cell->obpile, oid, noids);
if (o && (canpickup(lf, o) || caneat(lf,o)) ) {
if (db) dblog(".oO { current cell has ob i want (%s) }",o->type->name);
// try to pick it up
if (!aipickup(lf, o)) return B_TRUE;
if (db) dblog(".oO { pickup of %s failed, trying to eat! }",o->type->name);
if (!eat(lf, o)) return B_TRUE;
if (db) dblog(".oO { eating %s failed }",o->type->name);
}
// has an object with a flag we want?
for (n = 0; n < nwantflags; n++) {
o = hasobwithflag(lf->cell->obpile, wantflag[n]);
if (o && (canpickup(lf, o) || caneat(lf,o)) ) {
if (db) dblog(".oO { current cell has ob with flag i want (%s) }",o->type->name);
// try to pick it up
if (!aipickup(lf, o)) return B_TRUE;
if (db) dblog(".oO { pickup of %s with wantflag failed, trying to eat! }",o->type->name);
if (!eat(lf, o)) return B_TRUE;
if (db) dblog(".oO { eating %s with wantflag failed }",o->type->name);
void movetowards(lifeform_t *lf, cell_t *dst) {
int dir;
// move towards them
dir = getdirtowards(lf, dst);
if (dir != D_NONE) {
trymove(lf, dir);
}
}
// current cell has better weapon?
f = hasflag(lf->flags, F_WANTSBETTERWEP);
if (f ) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
o = hasbetterweapon(lf, lf->cell->obpile);
if (o && canpickup(lf, o)) {
if (db) dblog(".oO { current cell has better weapon (%s) }",o->type->name);
// try to pick it up
if (!aipickup(lf, o)) return B_TRUE;
if (db) dblog(".oO { pickup of better wep %s failed! }",o->type->name);
}
}
}
// current cell has better armour?
f = hasflag(lf->flags, F_WANTSBETTERARM);
if (f ) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
o = hasbetterarmour(lf, lf->cell->obpile);
if (o && canpickup(lf, o)) {
if (db) dblog(".oO { current cell has better armour (%s) }",o->type->name);
// try to pick it up
if (!aipickup(lf, o)) return B_TRUE;
if (db) dblog(".oO { pickup of better armour %s failed! }",o->type->name);
}
}
}
// look around for objects which we want, if we don't already have a targetcell.
if (!hasflag(lf->flags, F_TARGETCELL)) {
if (db) dblog(".oO { no targetcell, so looking for remote objects }");
for (i = 0 ; i < lf->nlos; i++) {
int gothere = B_FALSE;
c = lf->los[i];
if (c != lf->ignorecell) {
o = hasobmulti(c->obpile, oid, noids);
if (o && (canpickup(lf, o) || caneat(lf,o)) ) {
if (db) dblog(".oO { remote cell has ob i want (%s). setting f_targetcell. }",o->type->name);
gothere = B_TRUE;
}
if (!gothere) {
// has an object with a flag we want?
for (n = 0; n < nwantflags; n++) {
o = hasobwithflag(c->obpile, wantflag[n]);
if (o && (canpickup(lf, o) || caneat(lf, o)) ) {
if (db) dblog(".oO { remote cell has ob with flag i want (%s) }", o->type->name);
gothere = B_TRUE;
}
}
}
if (!gothere) {
// remote cell has better weapon?
f = hasflag(lf->flags, F_WANTSBETTERWEP);
if (f) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
o = hasbetterweapon(lf, c->obpile);
if (o && canpickup(lf, o)) {
if (db) dblog(".oO { remote cell has better weapon (%s). setting f_targetcell }",o->type->name);
gothere = B_TRUE;
}
}
}
}
if (!gothere) {
// remote cell has better armour?
f = hasflag(lf->flags, F_WANTSBETTERARM);
if (f) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
o = hasbetterarmour(lf, c->obpile);
if (o && canpickup(lf, o)) {
if (db) dblog(".oO { remote cell has better armour (%s). setting f_targetcell }",o->type->name);
gothere = B_TRUE;
}
}
}
}
if (gothere) {
// start walking towards target cell
addtempflag(lf->flags, F_TARGETCELL, c->x, c->y, NA, NULL, AI_FOLLOWTIME);
// forget about people we are attacking
killflagsofid(lf->flags, F_TARGET);
return B_TRUE;
}
}
}
}
return B_FALSE;
}

7
ai.h
View File

@ -1,5 +1,8 @@
#include "defs.h"
void aimove(lifeform_t *lf);
int getdirtowards(lifeform_t *lf, cell_t *dst);
void movetowards(lifeform_t *lf, cell_t *dst);
int aipickup(lifeform_t *lf, object_t *o);
enum OBTYPE getattackspell(lifeform_t *lf);
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op);
object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op);
int lookforobs(lifeform_t *lf, int covetsonly);

782
attack.c
View File

@ -1,147 +1,228 @@
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "io.h"
#include "lf.h"
#include "nexus.h"
#include "objects.h"
#include "text.h"
extern lifeform_t *player;
int doattack(lifeform_t *lf, lifeform_t *victim) {
int dam;
int attackcell(lifeform_t *lf, cell_t *c) {
// anyone there? if so just attack.
if (c->lf) {
attacklf(lf, c->lf);
} else {
object_t *o;
// has an mpassable object?
o = hasobwithflag(c->obpile, F_IMPASSABLE);
if (o) {
attackob(lf, o);
} else {
// TODO: attack wall?
return B_TRUE;
}
}
return B_FALSE;
}
int attacklf(lifeform_t *lf, lifeform_t *victim) {
unsigned int dam[100];
enum DAMTYPE damtype[100];
int ndam = 0;
char buf[BUFLEN];
char attackername[BUFLEN];
char victimname[BUFLEN];
int fatal = B_FALSE;
flag_t *f;
flag_t *unarmedflag = NULL;
object_t *wep;
enum DAMTYPE damtype;
obpile_t *op;
obpile_t *op = NULL;
int attacktime;
int acc;
int hit = B_FALSE;
double dampct;
int unarmed = B_FALSE;
char wepname[BUFLEN];
int ev;
int i;
int aidb = B_TRUE;
if (aidb) {
if (isplayer(lf)) {
aidb = B_FALSE;
} else if (!haslos(player, lf->cell)) {
aidb = B_FALSE;
}
}
// get names
getlfname(lf, attackername);
getlfname(victim, victimname);
if (aidb) dblog(".oO { trying to attack %s }", victimname);
// get weapon
op = addobpile(lf, NULL); // for use if we are unarmed
wep = getweapon(lf);
//wep = getweapon(lf);
wep = getattackwep(lf, &op, &unarmedflag);
if (!wep) {
unarmed = B_TRUE;
// ie. unarmed
getunarmedweapon(lf, op);
if (op->first) {
wep = op->first;
} else {
// cannot attack!
if (lf->controller == C_PLAYER) {
if (isplayer(lf)) {
msg("You cannot attack!");
} else if (haslos(player, lf->cell)) {
sprintf(buf, "%s",attackername);
capitalise(buf);
msg("%s looks like it wants to attack!",buf);
//msg("%s looks like it wants to attack!",attackername);
}
if (lf->controller != C_PLAYER) {
// take some time to avoid infinite loops!
taketime(lf, 1);
/*
if (!isplayer(lf)) {
// if ai, take some time to avoid infinite loops!
taketime(lf, getmovespeed(lf));
}
free(op);
*/
if (op) killobpile(op);
return B_TRUE;
}
}
getobname(wep, wepname, 1);
f = hasflag(wep->flags, F_DAMTYPE);
if (f) {
damtype = f->val[0];
} else {
// default - you are just bashing with whatever
// you weilded.
damtype = DT_BASH;
}
if (aidb) dblog(".oO { my weapon is %s %s }", wepname, unarmedflag ? "(unarmed)" : "");
// depends on weapon, race attackspeed modifier flag, etc
attacktime = getobattackspeed(wep) + getlfattackspeed(lf);
attacktime = getattackspeed(lf);
taketime(lf, attacktime);
// TODO: figure out if you hit
// TODO: figure out if you do damage, and how much
acc = 100; // base accuracy of 100%
// modify for weapon's (lack of) accuracy
f = hasflag(wep->flags, F_ACCURACY);
if (f) {
// ie. accuracy of 100% means no penalty
// ie. accuracy of 75% means 25% penalty
// etc
acc -= (100 - f->val[0]);
}
acc = getlfaccuracy(lf);
// modify for defender's evasion
ev = getevasion(victim);
acc -= ev;
// modify for attacker's level
acc += (lf->level * 2);
// 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?
ndam = 0;
if (rnd(1,100) <= acc) {
hit = B_TRUE;
if (aidb) dblog(".oO { i hit! }");
// special case
if (isplayer(lf) && (victim->race->id == R_GLOWBUG)) {
if ((wep->type->id == OT_EMPTYFLASK) || (wep->type->id == OT_EMPTYVIAL)) {
object_t *o;
// catch the glowbug!
msg("You catch %s in your %s.", victimname, noprefix(wepname));
removeob(wep, 1);
killlf(victim); // don't leave a corpse
o = addob(lf->pack, "glowing flask");
if (o) {
getobname(o, buf, o->amt);
msglower("%c - %s.",o->letter, buf);
} else {
hit = B_FALSE;
// add to the ground
o = addob(lf->cell->obpile, "glowing flask");
if (o) {
getobname(o, buf, o->amt);
msg("%s drops to the ground.", buf);
}
}
if (op) {
killobpile(op);
}
return B_FALSE;
}
}
if (hit) {
int reducepct;
// determine base damage
// determine damage
//if (unarmed && (unarmedflag->val[0] != NA)) {
if (unarmedflag) {
// this mosnter's unarmed attack will
// override normal damage calculation
dam[ndam] = getdamrollfromflag(unarmedflag);
} else {
dam[ndam] = getdamroll(wep);
}
dblog("rolled dam[%d] = %d",ndam,dam[ndam]);
// modify for strength
dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf));
// damtype?
damtype[ndam] = getdamtype(wep);
if (aidb) dblog(".oO { dealing %d %s damage }", dam[ndam], getdamname(damtype[ndam]));
ndam++;
// blessed vs undead etc?
if (isblessed(wep) && lfhasflagval(victim, F_DTVULN, DT_HOLY, NA, NA, NULL)) {
// a little extra damage
dam[ndam] = (int) ( (float)dam[ndam] * 1.25 );
}
// determine extra damage
getextradam(wep, &dam[ndam], &damtype[ndam]);
} else {
hit = B_FALSE;
ndam = 0;
}
if (ndam > 0) {
for (i = 0; i < ndam; i++) {
float reducepct;
int ar;
int reduceamt;
// determine damage
dam = getdamroll(wep);
// modify for attacker's armour
ar = getarmour(victim);
reducepct = ar * 2;
reduceamt = (int)(((float)reducepct / 100.0) * (float)dam);
dblog("initial dam[%d] = %d",i,dam[i]);
dam -= reduceamt;
if (dam < 0) dam = 0;
// modify based on resistances
adjustdamlf(victim, &dam[i], damtype[i]);
dblog("adjusted for lf to dam[%d] = %d",i,dam[i]);
// TODO: armour gets damaged
// modify for defender's armour
ar = getarmourrating(victim);
reducepct = getdamreducepct(ar);
reduceamt = (int) ceil((reducepct / 100.0) * (float)dam[i]);
losehp(victim, dam, damtype, lf, attackername);
dam[i] -= reduceamt;
if (dam[i] < 0) dam[i] = 0;
dblog("reduced by armour to dam[%d] = %d",i,dam[i]);
if (victim->hp <= 0) {
// will this hit be fatal?
if (dam[i] >= victim->hp) {
fatal = B_TRUE;
}
// announce it
if (lf->controller == C_PLAYER) {
msg("You %s %s%s%s",
fatal ? getkillverb(damtype, dam) : getattackverb(damtype, dam),
victimname,
(dam == 0) ? " but do no damage" : "",
if (isplayer(lf)) {
char extradambuf[BUFLEN];
if (dam[i] == 0) {
strcpy(extradambuf, " but do no damage");
} else if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) {
sprintf(extradambuf, " [%d dmg]",dam[i]);
} else {
strcpy(extradambuf, "");
}
warn("You %s %s%s%s",
fatal ? getkillverb(damtype[i], dam[i], victim->maxhp) : getattackverb(damtype[i], dam[i], victim->maxhp),
victimname, extradambuf,
fatal ? "!" : ".");
if (fatal && !hasflag(victim->flags, F_NODEATHANNOUNCE)) {
@ -149,131 +230,398 @@ int doattack(lifeform_t *lf, lifeform_t *victim) {
addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
}
} else {
if (haslos(player, lf->cell)) {
if (haslos(player, lf->cell) || isplayer(victim)) {
char withwep[BUFLEN];
char attackverb[BUFLEN];
char nodamstr[BUFLEN];
// capitalise first letter
sprintf(buf, "%s",attackername);
capitalise(buf);
if (wep && !unarmed) {
if (wep && !unarmedflag && (lf->race->id != R_DANCINGWEAPON)) {
sprintf(withwep, " with %s", wepname);
} else {
strcpy(withwep, "");
}
msg("%s %ss %s%s%s.", buf, getattackverb(damtype,dam), victimname,withwep,
(dam == 0) ? " but does no damage" : "" );
strcpy(attackverb, getattackverb(damtype[i],dam[i],victim->maxhp));
if ((dam[i] == 0) && (damtype[i] != DT_TOUCH)) {
strcpy(nodamstr, " but does no damage");
} else {
strcpy(nodamstr, "");
}
// TODO: else {if (haslineofhearing() etc
warn("%s %s%s %s%s%s.", buf, attackverb,
attackverb[strlen(attackverb)-1] == 's' ? "es" : "s",
victimname,withwep, nodamstr);
} else {
youhear(lf->cell, "sounds of fighting");
}
}
// victim loses hp
// don't adjust damage - we've already done that
if (wep && !unarmedflag) {
char wepname[BUFLEN];
getobname(wep, wepname, 1);
sprintf(buf, "%s^weilding %s",attackername, wepname);
} else {
strcpy(buf, attackername);
}
// check
/*
if (dam[i] >= 120) {
// potential bug
msg("DB: potential bug: huge dam=%d",dam[i]);
assert(1 == 2);
}
*/
losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE);
// victim's armour loses hp
if (reduceamt) {
object_t *armour;
int adam;
// 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
// special weapon effects
wepeffects(wep, victim->cell);
} else { // miss!
if (aidb) dblog(".oO { i missed! }");
// announce it
if (lf->controller == C_PLAYER) {
if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) {
if (isplayer(lf) || haslos(player, lf->cell)) {
sprintf(buf, "%s",attackername);
msg("%s%s magnetic shield repels %s%s attack.", victimname, getpossessive(victimname),
buf, getpossessive(buf));
}
} else {
if (isplayer(lf)) {
msg("You miss %s.", victimname);
} else {
if (haslos(player, lf->cell)) {
// capitalise first letter
sprintf(buf, "%s",attackername);
capitalise(buf);
msg("%s misses %s.", buf, victimname);
}
}
}
fightback(victim, lf);
}
// get rid of temp unarmed object
if (op->first) {
killob(op->first);
// get rid of temp unarmed object pile
if (op) {
killobpile(op);
}
// induction of fear?
if (!isdead(victim)) {
if (lfhasflag(victim, F_INDUCEFEAR)) {
scare(lf, victim, rnd(2,3));
}
}
if (aidb) dblog(".oO { doattack about to return B_FALSE }");
return B_FALSE;
}
int attackob(lifeform_t *lf, object_t *o) {
unsigned int dam[100];
enum DAMTYPE damtype[100];
int ndam = 0;
char attackername[BUFLEN];
char obname[BUFLEN];
flag_t *f;
flag_t *unarmedflag = NULL;
object_t *wep;
obpile_t *op = NULL;
cell_t *obloc = NULL;
int attacktime;
int unarmed = B_FALSE;
char wepname[BUFLEN];
int i;
//int aidb = B_TRUE;
int maxhp;
// get names
getlfname(lf, attackername);
getobname(o, obname, o->amt);
// get target object details
obloc = o->pile->where;
f = hasflag(o->flags, F_OBHP);
if (f) {
maxhp = f->val[1];
} else {
maxhp = 1;
}
// get weapon
wep = getattackwep(lf, &op, &unarmedflag);
if (!wep) {
if (isplayer(lf)) {
msg("You cannot attack!");
} else if (haslos(player, lf->cell)) {
//msg("%s looks like it wants to attack!",attackername);
}
if (!isplayer(lf)) {
// if ai, take some time to avoid infinite loops!
taketime(lf, getmovespeed(lf));
}
if (op) killobpile(op);
return B_TRUE;
}
getobname(wep, wepname, 1);
// depends on weapon, race attackspeed modifier flag, etc
attacktime = getattackspeed(lf);
taketime(lf, attacktime);
// don't need to figure out accuracy - we always hit.
// determine damage
ndam = 0;
//if (unarmedflag && (unarmedflag->val[0] != NA)) {
if (unarmedflag) {
// this mosnter's unarmed attack will
// override normal damage calculation
dam[ndam] = getdamrollfromflag(unarmedflag);
} else {
dam[ndam] = getdamroll(wep);
}
// damtype?
damtype[ndam] = getdamtype(wep);
ndam++;
// don't need to check for blessed vs mosnters
// determine extra damage
getextradam(wep, &dam[ndam], &damtype[ndam]);
for (i = 0; i < ndam; i++) {
// announce the hit
if (isplayer(lf)) {
char extradambuf[BUFLEN];
if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) {
sprintf(extradambuf, " [%d dmg]",dam[i]);
} else {
strcpy(extradambuf, "");
}
msg("You %s %s.", getattackverb(damtype[i], dam[i], maxhp),
obname, extradambuf);
} else if (haslos(player, lf->cell)) {
char withwep[BUFLEN];
if (wep && !unarmed && !isblind(player)) { // announce weapon used
sprintf(withwep, " with %s", wepname);
} else {
strcpy(withwep, "");
}
msg("%s %ss %s%s.", attackername,
getattackverb(damtype[i],dam[i],maxhp), obname,withwep);
} else {
youhear(lf->cell, "sounds of fighting");
}
// object loses hp
takedamage(o, dam[i], damtype[i]);
} // end foreach damtype
// special weapon effects
wepeffects(wep, obloc);
// get rid of temp unarmed object pile
if (op) {
killobpile(op);
}
free(op);
return B_FALSE;
}
char *getattackverb(enum DAMTYPE damtype, int dam) {
// returns a const char *
const char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp) {
float pct;
pct = (int)(((float) dam / (float) maxhp) * 100.0);
if (damtype == DT_PROJECTILE) {
return "hit";
} else if (damtype == DT_HOLY) {
switch (rnd(1,2)) {
case 1:
return "smite";
case 2:
return "cleanse";
}
} else if (damtype == DT_PIERCE) {
if (dam == 0) {
if (pct <= 5) {
return "poke";
} else if (dam <= 5) {
return "nick";
} else if (dam <= 10) {
} else if (pct <= 15) {
return "stab";
} else if (dam <= 15) {
} else if (pct <= 30) {
return "pierce";
} else if (dam <= 20) {
} else if (pct <= 40) {
return "spear";
} else {
return "deeply stab";
}
} else if (damtype == DT_POISONGAS) {
return "poison";
} else if (damtype == DT_ELECTRIC) {
if (pct <= 5) {
return "zap";
} else if (pct <= 15) {
return "jolt";
} else if (pct <= 20) {
return "shock";
} else if (pct <= 30) {
return "electrify";
} else {
return "electrocute";
}
} else if (damtype == DT_CLAW) {
if (dam == 0) {
if (pct <= 5) {
return "scratch";
} else if (dam <= 5) {
} else if (pct <= 15) {
return "claw";
} else if (dam <= 15) {
} else if (pct <= 30) {
return "rake";
} else if (dam <= 30) {
} else if (pct <= 50) {
return "gouge";
} else {
return "eviscerate";
}
} else if (damtype == DT_SLASH) {
if (dam == 0) {
if (pct <= 5) {
return "scratch";
} else if (dam <= 10) {
} else if (pct <= 15) {
return "hit";
} else if (dam <= 20) {
} else if (pct <= 30) {
return "slash";
} else {
return "slice";
}
} else if (damtype == DT_CHOP) {
if (dam == 0) {
if (pct <= 5) {
return "hit";
} else if (dam <= 10) {
} else if (pct <= 15) {
return "hack";
} else {
return "chop";
}
} else if (damtype == DT_BASH) {
if (dam == 0) {
if (pct <= 5) {
return "whack";
} else if (dam <= 5) {
} else if (pct <= 20) {
if (rnd(1,2) == 1) {
return "hit";
} else if (dam <= 10) {
return "bash";
} else if (dam <= 15) {
return "pummel";
} else if (dam <= 20) {
return "pound";
} else {
return "flatten";
return "bash";
}
} else {
return "pummel";
}
} else if (damtype == DT_BITE) {
if (dam == 0) {
if (pct <= 5) {
return "gnaw";
} else if (dam <= 15) {
} else if (pct <= 30) {
return "bite";
} else {
return "savage";
}
} else if (damtype == DT_FIRE) {
if (pct <= 5) {
return "scorch";
} else if (pct <= 20) {
return "burn";
} else if (pct <= 40) {
return "scald";
} else {
return "incinerate";
}
} else if (damtype == DT_COLD) {
if (pct <= 10) {
return "chill";
} else {
return "freeze";
}
} else if (damtype == DT_TOUCH) {
return "touch";
}
return "hit";
}
char *getkillverb(enum DAMTYPE damtype, int dam) {
object_t *getattackwep(lifeform_t *lf, obpile_t **unarmedpile, flag_t **unarmedflag) {
object_t *wep;
wep = getweapon(lf);
if (!wep) {
// ie. unarmed
*unarmedpile = getunarmedweapon(lf, unarmedflag);
if ((*unarmedpile)->first) {
wep = (*unarmedpile)->first;
} else {
wep = NULL;
}
}
return wep;
}
enum DAMTYPE getdamtype(object_t *wep) {
flag_t *f;
enum DAMTYPE dt = DT_NONE;
f = hasflag(wep->flags, F_DAMTYPE);
if (f) {
dt = f->val[0];
} else {
// default - you are just bashing with whatever
// you weilded.
dt = DT_BASH;
}
return dt;
}
int getextradam(object_t *wep, unsigned int *dam, enum DAMTYPE *damtype) {
flag_t *f;
for (f = wep->flags->first ; f ; f = f->next) {
if (f->id == F_ONFIRE) {
*dam = rnd(5,10); // TODO: don't hardcode?
*damtype = DT_FIRE;
}
}
return *dam;
}
char *getkillverb(enum DAMTYPE damtype, int dam, int maxhp) {
float pct;
pct = (int)(((float) dam / (float) maxhp) * 100.0);
if (damtype == DT_HOLY) {
return "smite";
}
if (dam >= 50) {
if (damtype == DT_PIERCE) return "fatally stab";
if (pct >= 70) {
if (damtype == DT_PIERCE) return "impale";
if (damtype == DT_BASH) return "flatten";
if (damtype == DT_BITE) return "gore";
if (damtype == DT_CLAW) return "disembowel";
if (damtype == DT_SLASH) return "behead"; // TODO: only if they have a head! otherwise "bisect"
@ -285,12 +633,11 @@ char *getkillverb(enum DAMTYPE damtype, int dam) {
// return TRUE if no damage
int getdamrange(object_t *o, int *min, int *max) {
void getdamrange(flagpile_t *fp, int *min, int *max) {
int mindam,maxdam;
flag_t *f;
f = hasflag(o->flags, F_DAM);
f = hasflag(fp, F_DAM);
if (f) {
int mod,ndice,sides;
ndice = f->val[0];
@ -304,6 +651,7 @@ int getdamrange(object_t *o, int *min, int *max) {
mindam = (ndice * 1) + mod;
maxdam = (ndice * sides) + mod;
} else {
// TODO wepaon does damage based on weight
mindam = 0;
maxdam = 0;
}
@ -315,53 +663,219 @@ int getdamrange(object_t *o, int *min, int *max) {
// roll for damage
int getdamroll(object_t *o) {
int dam;
int ndice, sides, mod;
flag_t *f;
f = hasflag(o->flags, F_DAM);
if (f) {
ndice = f->val[0];
sides = f->val[1];
if (f->val[2] != NA) {
mod = f->val[2];
} else {
mod = 0;
dam = getdamrollfromflag(f);
if (isblessed(o)) {
int dam2;
// blessed weapons get two rolls, and take the best
dam2 = getdamrollfromflag(f);
if (dam2 > dam) dam = dam2;
} else if (iscursed(o)) {
int dam2;
// cursed weapons get two rolls, and take the worst
dam2 = getdamrollfromflag(f);
if (dam2 < dam) dam = dam2;
}
dam = rolldie(ndice, sides) + mod;
} else {
// TODO wepaon does damage based on weight
// weapon does no damage
dam = 0;
}
// modify for bonus
f = hasflag(o->flags, F_BONUS);
if (f) {
dam += f->val[0];
}
if (dam < 0) dam = 0;
return dam;
}
float getdamreducepct(float armourrating) {
float reducepct;
reducepct = (armourrating * 1.5);
return reducepct;
}
int getdamrollfromflag(flag_t *f) {
objecttype_t *ot;
int dam;
int ndice, sides, mod;
flag_t *damflag = NULL;
ot = findotn(f->text);
if (ot) {
damflag = hasflag(ot->flags, F_DAM);
}
// how many dice?
ndice = f->val[0];
if (ndice == NA) {
// get it from weapon definition
if (damflag && (damflag->val[0] != NA)) {
ndice = damflag->val[0];
} else {
ndice = 1;
}
}
sides = f->val[1];
if (sides == NA) {
// get it from weapon definition
if (damflag && (damflag->val[1] != NA)) {
sides = damflag->val[1];
} else {
sides = 1;
}
}
mod = f->val[2];
if (mod == NA) {
// get it from weapon definition
if (damflag && (damflag->val[2] != NA)) {
mod = damflag->val[2];
} else {
mod = 0;
}
}
dam = rolldie(ndice, sides) + mod;
assert(dam < 1000);
assert(dam >= 0);
return dam;
}
// returns a multiplier
float getstrdammod(lifeform_t *lf) {
float mod = 0;
float base;
// <9 = penalty
// 9,10,11,12 = average
// >12 = bonus
base = getattr(lf, A_STR);
if ((base >= 9) && (base <= 12)) {
mod = 1;
} else if (base > 12) {
base -= 12; // ie. 1 - 6
// 13 = 1 = 1.1
// 14 = 2 = 1.2
// 15 = 3 = 1.3
// 16 = 4 = 1.4
// 17 = 5 = 1.6
// 18 = 6 = 1.5
mod = 1 + (base / 10.0);
} else { // ie. 0 through 8
// 0 = 0.1
// 1 = 0.2
// 2 = 0.3
// 3 = 0.4
// 4 = 0.5
// 5 = 0.6
// 6 = 0.7
// 7 = 0.8
// 8 = 0.9
mod = (base * 0.1); // ie. 8 -> 0.8 or 4 -> 0.4
mod += 0.1; // ie. 8 -> 0.9 or 4 -> 0.5
}
return mod;
}
// determine attack type for lifeform.
// add an object of this kind to the pile 'op'
// return its type;
objecttype_t *getunarmedweapon(lifeform_t *lf,obpile_t *op) {
// allocate a pile and add weapon to it.
// return the pile. remember to free it!
obpile_t *getunarmedweapon(lifeform_t *lf,flag_t **uflag) {
int nposs;
flag_t *f;
int sel;
char poss[MAXPILEOBS][BUFLEN];
obpile_t *op;
flag_t *possflag[MAXPILEOBS];
op = addobpile(NULL, NULL);
// pick a random attack type.
nposs = 0;
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_UNARMEDATTACKOB) {
if (f->id == F_HASATTACK) {
strcpy(poss[nposs],f->text);
possflag[nposs] = f;
nposs++;
}
}
if (nposs > 0) {
object_t *uob;
sel = rnd(0,nposs-1);
addob(op, poss[sel]);
uob = addob(op, poss[sel]);
assert(uob);
if (uflag) *uflag = possflag[sel];
}
if (op->first) {
return op->first->type;
if (!op->first) {
if (uflag) *uflag = NULL;
}
return op;
}
void wepeffects(object_t *wep, cell_t *where) {
flag_t *f;
lifeform_t *victim;
victim = where->lf;
if (!where) return;
for (f = wep->flags->first ; f ; f = f->next) {
if (f->id == F_FLAMESTRIKE) {
if (!hasob(where->obpile, OT_FIRESMALL)) {
// ignite!
addob(where->obpile, "small fire");
// announce
if (haslos(player, where)) {
msg("A column of fire erupts from the ground!");
f->known = B_KNOWN;
}
}
} else if ((f->id == F_HITCONFER) && victim) {
enum FLAG fid;
int val0,val1;
int min,max,howlong;
fid = f->val[0];
if (!lfhasflag(victim, fid)) {
val0 = f->val[1];
val1 = f->val[2];
if (f->text) {
char loctext[BUFLEN];
char *word, *dummy;
strcpy(loctext,f->text);
word = strtok_r(loctext, "-", &dummy);
if (word) {
min = atoi(word);
word = strtok_r(NULL, "-", &dummy);
if (word) {
max = atoi(word);
howlong = rnd(min,max);
} else {
return NULL;
howlong = PERMENANT;
}
} else {
howlong = PERMENANT;
}
} else {
howlong = PERMENANT;
}
addtempflag(victim->flags, fid, val0, val1, NA, NULL, howlong);
}
}
}
}

View File

@ -1,8 +1,17 @@
#include "defs.h"
int doattack(lifeform_t *lf, lifeform_t *victim);
char *getattackverb(enum DAMTYPE damtype, int dam);
char *getkillverb(enum DAMTYPE damtype, int dam);
int getdamrange(object_t *o, int *min, int *max);
int attackcell(lifeform_t *lf, cell_t *c);
int attacklf(lifeform_t *lf, lifeform_t *victim);
int attackob(lifeform_t *lf, object_t *o);
const char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp);
object_t *getattackwep(lifeform_t *lf, obpile_t **unarmedpile, flag_t **unarmedflag);
enum DAMTYPE getdamtype(object_t *wep);
int getextradam(object_t *wep, unsigned int *dam, enum DAMTYPE *damtype);
char *getkillverb(enum DAMTYPE damtype, int dam, int maxhp);
void getdamrange(flagpile_t *fp, int *min, int *max);
float getdamreducepct(float armourrating);
int getdamroll(object_t *o);
objecttype_t *getunarmedweapon(lifeform_t *lf, obpile_t *op);
int getdamrollfromflag(flag_t *f);
float getstrdammod(lifeform_t *lf);
obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag);
void wepeffects(object_t *wep, cell_t *where);

939
defs.h

File diff suppressed because it is too large Load Diff

8
doc/add_bodypart.txt Normal file
View File

@ -0,0 +1,8 @@
in defs.h:
add a new BODYPART enum entry
increment MAXBODYPARTS
in lf.c:
update getbodypartname
update getbodypartequipname
update getbodyparthitchance

10
doc/add_damtype.txt Normal file
View File

@ -0,0 +1,10 @@
in defs.h:
add enum
increment MAXDAMTYPE
in objcets.c:
update getdamname() - eg. you take 5 "electrical" damage
update getdamnamenoun() - eg. you are immune to "electricity"
in attack.c
update getattackverb if required
update getkillverb if required

5
doc/add_habitat.txt Normal file
View File

@ -0,0 +1,5 @@
defs.h:
add H_xx enum
map.c:
update getemptycelltype()

13
doc/add_intrinsic.txt Normal file
View File

@ -0,0 +1,13 @@
defs.h:
add F_WHATEVER
io.c:
update describeob() for when an object confers this property
update showlfstats() to describe the property
update announceflaggain() to describe adding it
update announceflagloss() to describe losing it
then make it do something!

8
doc/add_material.txt Normal file
View File

@ -0,0 +1,8 @@
defs.h:
define the MT_* enum
objects.c:
add an addmaterial() line
update adjustdammaterial() as required

View File

@ -6,7 +6,11 @@ In defs.h:
In objects.c:
define the class with addoc()
add the class to sortorder[] at the top
findotn() must know how to un-pluralise the name
findotn() must know how to un-pluralise the name (eg. potions)
update genhiddenname() if this class isn't known
also add hidden names up the top
also update numXXXnames count in initobjects()
In text.c:
makeplural() must know about the name
makeplural() must know about the name (eg. potion -> potions)

5
doc/add_spellschool.txt Normal file
View File

@ -0,0 +1,5 @@
defs.h:
update enum SPELLSCHOOL
objects.c:
update getschoolname

19
doc/adding_spells.txt Normal file
View File

@ -0,0 +1,19 @@
defs.h:
add the OT_xxx enum
(optional) add a scroll to do the same effect
(optional) add a potion to do the same effect
objects.c:
define the spell
remember to have spelllevle
(optional) add a scroll to do the same effect, use F_LINKSPELL
(optional) add a potion to do the same effect
spell.c:
implement the effects
remember to fill in *seenbyplayer if there is a scroll version
cope with:
blessed/cursed
target having antimagic - use hasmr(victim)
blindness if the effect is vision-based

12
doc/throwdist.txt Normal file
View File

@ -0,0 +1,12 @@
baesball (0.14 kg) can be thrown 100 metres
so let's say:
1 kg = 10 metres (cells)
10 kg = 5m
20 kg = 1m
distance = 10m - (weight/2)

281
flag.c
View File

@ -3,12 +3,42 @@
#include <string.h>
#include "defs.h"
#include "flag.h"
#include "io.h"
#include "lf.h"
#include "objects.h"
#include "text.h"
extern int gamestarted;
flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text) {
return addflag_real(fp, id, val1, val2, val3, text, PERMENANT, B_KNOWN);
}
flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int timeleft) {
return addflag_real(fp, id, val1, val2, val3, text, timeleft, B_KNOWN);
}
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known) {
flag_t *f;
int i;
// identified things mean all new flags are autmaticlaly known.
if (hasflag(fp, F_IDENTIFIED)) {
known = B_KNOWN;
}
// certain flags stack...
if (flagstacks(id)) {
f = hasflag(fp, id);
if (f) {
// add values!
f->val[0] += val1;
f->val[1] += val2;
f->val[2] += val3;
// TODO: how to handle text??
return f;
}
}
if (fp->first == NULL) {
fp->first = malloc(sizeof(flag_t));
f = fp->first;
@ -25,7 +55,10 @@ flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char
f->next = NULL;
// fill in props
f->id = id; // increment next ob id
f->id = id;
f->lifetime = lifetime;
f->known = known;
f->obfrom = -1;
// first blank values
for (i = 0; i < 3; i++) {
@ -50,34 +83,88 @@ flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char
f->pile = fp;
// notify
if (gamestarted) {
if (f->pile->owner) {
if (announceflaggain(f->pile->owner, f)) {
f->known = B_TRUE;
}
if (isplayer(f->pile->owner)) {
switch (f->id) {
case F_BLIND:
case F_SEEINDARK:
drawscreen();
break;
default:
break;
}
}
} else if (f->pile->ob) {
if (announceobflaggain(f->pile->ob, f)) {
f->known = B_TRUE;
}
}
}
return f;
}
flagpile_t *addflagpile(void) {
flagpile_t *addflagpile(lifeform_t *owner, object_t *ob) {
flagpile_t *fp;
fp = malloc(sizeof(flagpile_t));
fp->first = NULL;
fp->last = NULL;
fp->owner = owner;
fp->ob = ob;
return fp;
}
flag_t *hasflag(flagpile_t *fp, int id) {
void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime) {
flag_t *f;
for (f = fp->first ; f ; f = f->next) {
if (f->id == id) return f;
for (f = src->first ; f ; f = f->next) {
addflag_real(dst, f->id, f->val[0], f->val[1], f->val[2], f->text,
(lifetime == NA) ? f->lifetime : lifetime, f->known);
}
return NULL;
}
flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *text) {
int flagstacks(enum FLAG fid) {
int res = B_FALSE;
switch (fid) {
case F_EVASION:
case F_BONUS:
res = B_TRUE;
break;
default:
res = B_FALSE;
break;
}
return res;
}
flag_t *hasflag(flagpile_t *fp, int id) {
return hasflag_real(fp, id, NA);
}
flag_t *hasflagknown(flagpile_t *fp, int id) {
return hasflag_real(fp, id, B_TRUE);
}
flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown) {
flag_t *f;
lifeform_t *owner;
owner = fp->owner;
for (f = fp->first ; f ; f = f->next) {
if (f->id == id) {
if ( ((val1 == NA) || (f->val[0] == val1)) &&
((val2 == NA) || (f->val[1] == val2)) &&
((val3 == NA) || (f->val[2] == val3)) &&
((text == NULL) || strstr(f->text, text))) {
int valid = B_TRUE;
if ((wantknown != NA) && (f->known != wantknown)) valid = B_FALSE;
if (owner && (f->lifetime == FROMJOB) && !getjob(owner)) {
valid = B_FALSE;
}
if (valid) {
return f;
}
}
@ -85,9 +172,79 @@ flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *t
return NULL;
}
flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *text) {
return hasflagval_real(fp, id, val1, val2, val3, text, B_FALSE); // doesn't have to be known
}
flag_t *hasflagvalknown(flagpile_t *fp, int id, int val1, int val2, int val3, char *text) {
return hasflagval_real(fp, id, val1, val2, val3, text, B_TRUE); // must be known
}
flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, char *text, int wantknown) {
flag_t *f;
lifeform_t *owner;
owner = fp->owner;
for (f = fp->first ; f ; f = f->next) {
if (f->id == id) {
if (owner && (f->lifetime == FROMJOB) && !getjob(owner)) {
// invalid
} else {
if ( ((val1 == NA) || (f->val[0] == val1)) &&
((val2 == NA) || (f->val[1] == val2)) &&
((val3 == NA) || (f->val[2] == val3)) &&
((text == NULL) || strstr(f->text, text))) {
if (!wantknown || f->known) {
return f;
}
}
}
}
}
return NULL;
}
void killflagsofid(flagpile_t *fp, enum FLAG fid) {
flag_t *f,*nextf;
for (f = fp->first ; f ; f = nextf) {
nextf = f->next;
if (f->id == fid) {
killflag(f);
}
}
}
void killflag(flag_t *f) {
int i;
flag_t *nextone, *lastone;
lifeform_t *lf;
int needredraw = B_FALSE;
lf = f->pile->owner;
if (isplayer(lf)) {
switch (f->id) {
case F_BLIND:
case F_SEEINDARK:
needredraw = B_TRUE;
break;
default:
break;
}
}
// notify
if (gamestarted) {
if (f->pile->owner) {
announceflagloss(f->pile->owner, f);
} else if (f->pile->ob) {
announceobflagloss(f->pile->ob, f);
}
}
// we will revert to our original form at the end of timeeffectslf().
if (lf && (f->id == F_POLYMORPHED)) {
lf->polyrevert = B_TRUE;
}
// free mem
@ -109,6 +266,10 @@ void killflag(flag_t *f) {
free (lastone->next );
lastone->next = nextone;
}
if (gamestarted && needredraw) {
drawscreen();
}
}
void killflagpile(flagpile_t *fp) {
@ -118,3 +279,99 @@ void killflagpile(flagpile_t *fp) {
free(fp);
}
void timeeffectsflag(flag_t *f) {
if ((f->lifetime != PERMENANT) && (f->lifetime > 0)) {
f->lifetime--;
if (f->lifetime <= 0) {
killflag(f);
return;
} else if (f->lifetime == 5) {
// warn about certain flags......
if (isplayer(f->pile->owner)) {
switch (f->id) {
case F_CANWILL:
switch (f->val[0]) {
case OT_A_JUMP:
warn("Your ability to jump is starting to run out...");;
break;
default:
break;
}
break;
case F_DTIMMUNE:
warn("Your %s immunity is starting to run out...", getdamname(f->val[0]));
break;
case F_DTRESIST:
warn("Your %s resistance is starting to run out...", getdamname(f->val[0]));
break;
case F_DTVULN:
warn("You feel a little less vulnerable to %s...", getdamname(f->val[0]));
break;
case F_MAGSHIELD:
warn("Your magnetic shield is weakening...");
break;
case F_POLYMORPHED:
warn("You are starting to revert to your original form...");
break;
default: // no message
break;
}
}
} else if (f->lifetime == 1) {
// warn about certain flags......
if (isplayer(f->pile->owner)) {
switch (f->id) {
case F_CANWILL:
switch (f->val[0]) {
case OT_A_JUMP:
warn("Your ability to jump is about to expire!");;
break;
default:
break;
}
break;
case F_DTIMMUNE:
warn("Your %s immunity is about to expire!", getdamname(f->val[0]));
break;
case F_DTRESIST:
warn("Your %s resistance is about to expire!", getdamname(f->val[0]));
break;
case F_DTVULN:
warn("You feel a little less vulnerable to %s...", getdamname(f->val[0]));
break;
case F_MAGSHIELD:
warn("Your magnetic shield is about to expire!");
break;
case F_POLYMORPHED:
warn("You are about to revert to your original form!");
break;
default: // no message
break;
}
}
}
}
}
void sumflags(flagpile_t *fp, int id, int *val0, int *val1, int *val2) {
flag_t *f;
if (val0) *val0 = 0;
if (val1) *val1 = 0;
if (val2) *val2 = 0;
for (f = fp->first ; f ; f = f->next) {
if (f->id == id) {
if (val0) *val0 = *val0 + f->val[0];
if (val1) *val1 = *val1 + f->val[1];
if (val2) *val2 = *val2 + f->val[2];
}
}
}
void timeeffectsflags(flagpile_t *fp) {
flag_t *f,*nextf;
for (f = fp->first ; f ; f = nextf) {
nextf = f->next;
timeeffectsflag(f);
}
}

15
flag.h
View File

@ -3,8 +3,21 @@
// functions
flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text);
flagpile_t *addflagpile(void);
flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int timeleft);
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known);
flagpile_t *addflagpile(lifeform_t *owner, object_t *o);
void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime);
int flagstacks(enum FLAG fid);
flag_t *hasflag(flagpile_t *fp, int id);
flag_t *hasflagknown(flagpile_t *fp, int id);
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 *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);
void killflagsofid(flagpile_t *fp, enum FLAG fid);
void killflag(flag_t *f);
void killflagpile(flagpile_t *fp);
void makeflagknown(flagpile_t *fp);
void sumflags(flagpile_t *fp, int id, int *val0, int *val1, int *val2);
void timeeffectsflag(flag_t *f);
void timeeffectsflags(flagpile_t *fp);

4341
io.c

File diff suppressed because it is too large Load Diff

59
io.h
View File

@ -1,23 +1,58 @@
#include <ncurses.h>
#include "defs.h"
void addchoice(prompt_t *p, char ch, char *text, char *desc, void *data);
void addheading(prompt_t *p, char *text);
void addmsghist(char *text);
void anim(cell_t *src, cell_t *dst, char ch);
void animradial(cell_t *src, int radius, char ch);
//void announceob(enum OBTYPE oid);
int announceflaggain(lifeform_t *lf, flag_t *f);
void announceflagloss(lifeform_t *lf, flag_t *f);
int announceobflaggain(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 *askobjectwithflag(obpile_t *op, char *title, int *count, int opts, enum FLAG withflag);
object_t *askobjectofclass(obpile_t *op, char *title, int *count, int opts, enum OBCLASS obclass);
object_t *doaskobject(obpile_t *op, char *title, int *count, int opts, enum OBCLASS obclass);
cell_t *askcoords(char *prompt);
object_t *doaskobject(obpile_t *op, char *title, int *count, int opts, enum OBCLASS obclass, enum FLAG withflag);
int askobjectmulti(obpile_t *op, char *prompt, int opts);
char askchar(char *prompt, char *validchars, char *def, int showchars);
cell_t *askcoords(char *prompt, int targettype);
char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def);
void centre(WINDOW *win, int y, char *format, ... );
int chartodir(char ch);
int cleanupgfx(void);
void clearmsg(void);
void real_clearmsg(int force);
void clearretobs(void);
void cls(void);
void describeob(object_t *o);
void dodrop(obpile_t *op);
void doattackcell(char dirch);
void doclose(void);
void dodrop(obpile_t *op, int wantmulti);
void doeat(obpile_t *op);
void doenter(lifeform_t *lf);
void doexplain(void);
void dofinaloblist(obpile_t *op);
void dofire(void);
void doinventory(obpile_t *op);
void doknowledgelist(void);
void dolook(cell_t *where);
void domagic(enum OBTYPE spellid, int cellx, int celly);
void domsghist(void);
void dooperate(obpile_t *op);
int dopickup(obpile_t *op);
void dolockpick(obpile_t *op);
void donextguntarget(void);
void dopour(obpile_t *op);
void doquit(void);
void doquaff(obpile_t *op);
void doread(obpile_t *op);
void dorest(void);
void doselguntarget(void);
void dostairs(int dir);
int dotakeoff(obpile_t *op);
void dothrow(obpile_t *op);
void dovendingmachine(lifeform_t *lf, object_t *vm);
int dowear(obpile_t *op);
int doweild(obpile_t *op);
void drawunviscell(cell_t *cell, int x, int y);
@ -27,17 +62,25 @@ void drawlevelfor(lifeform_t *lf);
void drawmsg(void);
void drawscreen(void);
void drawstatus(void);
int drop(object_t *o, int count);
char getchoice(prompt_t *prompt);
char getchoicestr(prompt_t *prompt);
int getkey(void);
void handleinput(void);
void initgfx(void);
void initprompt(prompt_t *p, char *q1);
int keycodetokey(int keycode);
void more(void);
void warn(char *format, ... );
void msg(char *format, ... );
int pickup(lifeform_t *lf, object_t *what, int howmany);
void msglower(char *format, ... );
void msg_real(char *format, ... );
void nothinghappens(void);
void dblog(char *format, ... );
void redraw(void);
int savequit(void);
int takeoff(lifeform_t *lf, object_t *o);
void showlfarmour(lifeform_t *lf);
void showlfstats(lifeform_t *lf, int showall);
void tombstone(lifeform_t *lf);
void updatestatus(void);
void updateviewfor(cell_t *cell);
int wear(lifeform_t *lf, object_t *o);
int weild(lifeform_t *lf, object_t *o);

5367
lf.c

File diff suppressed because it is too large Load Diff

144
lf.h
View File

@ -1,34 +1,162 @@
#include "defs.h"
lifeform_t *addlf(cell_t *cell, enum RACE rid, int level);
race_t *addrace(enum RACE id, char *name, char glyph);
lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller);
job_t *addjob(enum JOB id, char *name);
race_t *addrace(enum RACE id, char *name, float weight, char glyph, enum MATERIAL mat);
void adjustdamlf(lifeform_t *lf, unsigned int *amt, enum DAMTYPE damtype);
void autotarget(lifeform_t *lf);
void autoweild(lifeform_t *lf);
int appearsrandomly(enum RACE rid);
void bleed(lifeform_t *lf);
int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost);
int caneat(lifeform_t *lf, object_t *o);
int canhear(lifeform_t *lf, cell_t *c);
int canpickup(lifeform_t *lf, object_t *o);
int canwear(lifeform_t *lf, object_t *o);
int canpush(lifeform_t *lf, object_t *o, int dir);
int canquaff(lifeform_t *lf, object_t *o);
int canrest(lifeform_t *lf);
int canwear(lifeform_t *lf, object_t *o, enum BODYPART where);
int canweild(lifeform_t *lf, object_t *o);
int cantakeoff(lifeform_t *lf, object_t *o);
int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell);
void die(lifeform_t *lf);
void dumplf(void);
int eat(lifeform_t *lf, object_t *o);
object_t *eyesshaded(lifeform_t *lf);
void fightback(lifeform_t *lf, lifeform_t *attacker);
job_t *findjob(enum JOB jobid);
lifeform_t *findlf(map_t *m, int lfid);
race_t *findrace(enum RACE id);
race_t *findracebyname(char *name);
int flee(lifeform_t *lf);
void gainhp(lifeform_t *lf, int amt);
int getarmour(lifeform_t *lf);
void gainlevel(lifeform_t *lf);
void gainmp(lifeform_t *lf, int amt);
void gainxp(lifeform_t *lf, long amt);
object_t *getarmour(lifeform_t *lf, enum BODYPART bp);
int getarmourrating(lifeform_t *lf);
int getattackspeed(lifeform_t *lf);
int getattr(lifeform_t *lf, enum ATTRIB attr);
int getdexmod(lifeform_t *lf);
int getevasion(lifeform_t *lf);
object_t *getbestmissile(lifeform_t *lf);
object_t *getbestweapon(lifeform_t *lf);
object_t *getbestfirearm(lifeform_t *lf);
int getbodyparthitchance(enum BODYPART bp);
char *getbodypartname(enum BODYPART bp);
char *getbodypartequipname(enum BODYPART bp);
object_t *getequippedob(obpile_t *op, enum BODYPART bp);
int getlfattackspeed(lifeform_t *lf);
object_t *getfirearm(lifeform_t *lf);
lifeform_t *getguntarget(lifeform_t *lf);
int getguntargetid(lifeform_t *lf);
//int gethealtime(lifeform_t *lf);
int gethearingrange(lifeform_t *lf);
enum HUNGER gethungerlevel(int hunger);
char * gethungername(enum HUNGER hunger, char *buf);
int gethungerval(lifeform_t *lf);
job_t *getjob(lifeform_t *lf);
int getlfaccuracy(lifeform_t *lf);
enum LFCONDITION getlfcondition(lifeform_t *lf);
int getnightvisrange(lifeform_t *lf);
char *getlfconditionname(enum LFCONDITION cond);
char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer);
enum MATERIAL getlfmaterial(lifeform_t *lf);
float getmaxcarryweight(lifeform_t *lf);
float getmaxliftweight(lifeform_t *lf);
float getmaxpushweight(lifeform_t *lf);
int getvisrange(lifeform_t *lf);
int getmovespeed(lifeform_t *lf);
char *getmoveverb(lifeform_t *lf);
char *getlfname(lifeform_t *lf, char *buf);
race_t *getrandomlf(map_t *map, int *level);
char *getlfnamea(lifeform_t *lf, char *buf);
enum LFSIZE getlfsize(lifeform_t *lf);
float getlfweight(lifeform_t *lf, int withobs);
int getspellspeed(lifeform_t *lf);
char *getplayername(char *buf);
char *getplayernamefull(char *buf);
object_t *getrandomarmour(lifeform_t *lf);
//int getrandommonlevel(int depth);
race_t *getrandomrace(map_t *map);
race_t *getreallyrandomrace(void);
char *getspeedname(int speed, char *buf);
float getstatmod(lifeform_t *lf, enum ATTRIB att);
enum STRBRACKET getstrname(int str, char *buf);
enum DEXBRACKET getdexname(int dex, char *buf);
enum IQBRACKET getiqname(int iq, char *buf);
int getthrowspeed(int str);
int getunarmedattackspeed(lifeform_t *lf);
object_t *getweapon(lifeform_t *lf);
long getxpforlev(int level);
void givejob(lifeform_t *lf, enum JOB jobid);
void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype);
void givestartobs(lifeform_t *lf, flagpile_t *fp);
map_t *gotolev(lifeform_t *lf, int depth, object_t *fromstairs);
job_t *hasjob(lifeform_t *lf, enum JOB job);
flag_t *lfhasflag(lifeform_t *lf, enum FLAG fid);
flag_t *lfhasflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, char *text);
flag_t *lfhasknownflag(lifeform_t *lf, enum FLAG fid);
flag_t *lfhasknownflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, char *text);
int lockpick(lifeform_t *lf, object_t *target, object_t *device);
void loseobflags(lifeform_t *lf, object_t *o, int kind);
int haslof(lifeform_t *viewer, cell_t *dest);
int haslos(lifeform_t *viewer, cell_t *dest);
int hasmr(lifeform_t *lf);
void initjobs(void);
void initrace(void);
void interrupt(lifeform_t *lf);
int isbleeding(lifeform_t *lf);
int isblind(lifeform_t *lf);
enum BURDENED isburdened(lifeform_t *lf);
int isdead(lifeform_t *lf);
int isfleeing(lifeform_t *lf);
int isfreebp(lifeform_t *lf, enum BODYPART bp);
int isgenius(lifeform_t *lf);
int isingunrange(lifeform_t *lf, cell_t *where);
int isimmobile(lifeform_t *lf);
int ispeaceful(lifeform_t *lf);
int isplayer(lifeform_t *lf);
int ispolymorphed(lifeform_t *lf);
void killjob(job_t *job);
void killlf(lifeform_t *lf);
void killrace(race_t *race);
void losehp(lifeform_t *lf, int amt, int damtype, lifeform_t *fromlf, char *damsrc);
int losehp(lifeform_t *lf, unsigned int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc);
int losehp_real(lifeform_t *lf, unsigned int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam);
void makenoise(lifeform_t *lf, enum NOISETYPE nid);
void maycastspellschool(flagpile_t *fp, enum SPELLSCHOOL ss);
int modattr(lifeform_t *lf, enum ATTRIB attr, int amt);
void modhunger(lifeform_t *lf, int amt);
void outfitlf(lifeform_t *lf);
void taketime(lifeform_t *lf, int howlong);
int pickup(lifeform_t *lf, object_t *what, int howmany);
void precalclos(lifeform_t *lf);
int push(lifeform_t *lf, object_t *o, int dir);
void relinklf(lifeform_t *src, map_t *dst);
int rest(lifeform_t *lf, int onpurpose);
void startresting(lifeform_t *lf);
int rolldex(enum DEXBRACKET bracket);
int rolliq(enum IQBRACKET bracket);
int rollstr(enum STRBRACKET bracket);
int savingthrow(lifeform_t *lf, enum ATTRIB attr);
int scare(lifeform_t *lf, lifeform_t *scarer, int howlong);
int setammo(lifeform_t *lf, object_t *o);
void setattr(lifeform_t *lf, enum ATTRIB attr, int val);
void setguntarget(lifeform_t *lf, lifeform_t *targ);
void setrace(lifeform_t *lf, enum RACE rid);
void setlastdam(lifeform_t *lf, char *buf);
int shoot(lifeform_t *lf);
void sortlf(map_t *map, lifeform_t *lf);
void stopresting(lifeform_t *lf);
void stoprunning(lifeform_t *lf);
int takeoff(lifeform_t *lf, object_t *o);
void taketime(lifeform_t *lf, long howlong);
int throwat(lifeform_t *thrower, object_t *o, cell_t *where);
void timeeffectslf(lifeform_t *lf);
void turneffectslf(lifeform_t *lf);
int touch(lifeform_t *lf, object_t *o);
int unweild(lifeform_t *lf, object_t *o);
int useability(lifeform_t *lf, enum OBTYPE aid);
int usestairs(lifeform_t *lf, object_t *o);
int validateraces(void);
int wear(lifeform_t *lf, object_t *o);
int weild(lifeform_t *lf, object_t *o);
int youhear(cell_t *c, char *text);

36784
log.txt

File diff suppressed because it is too large Load Diff

703
map.c
View File

@ -4,15 +4,21 @@
#include <stdio.h>
#include <string.h>
#include "defs.h"
#include "flag.h"
#include "io.h"
#include "move.h"
#include "nexus.h"
#include "lf.h"
#include "map.h"
#include "objects.h"
#include "text.h"
extern map_t *firstmap,*lastmap;
extern int viewx,viewy,vieww,viewh;
extern lifeform_t *player;
extern enum OBCLASS sortorder[];
cell_t *addcell(map_t *m, int x, int y) {
cell_t *cell;
m->cell[(y*m->w)+x] = malloc(sizeof(cell_t));
@ -25,6 +31,9 @@ cell_t *addcell(map_t *m, int x, int y) {
cell->obpile = addobpile(NOOWNER, cell);
cell->lf = NULL;
cell->roomid = -1;
cell->lit = B_FALSE;
cell->writing = NULL;
return cell;
}
map_t *addmap(void) {
@ -56,33 +65,214 @@ map_t *addmap(void) {
// props
a->id = id;
a->lf = NULL;
a->nextlfid = 0;
for (i = 0; i < MAXDIR_ORTH; i++) {
a->nextmap[i] = -1;
}
return a;
}
void addrandomthing(cell_t *c) {
char buf[BUFLEN];
int level;
lifeform_t *addmonster(cell_t *c, enum RACE raceid) {
lifeform_t *lf = NULL;
race_t *r;
// ie. don't create mosnters on closed doors!
if (!cellwalkable(NULL, c, NULL)) {
return NULL;
}
if ((raceid == R_NONE) || (raceid == R_RANDOM)) {
r = getrandomrace(c->map);
} else {
r = findrace(raceid);
}
assert(r);
dblog("adding rand lf %s to cell %d,%d",r->name,c->x,c->y);
if (r) {
//lf = addlf(c, r->id, getrandommonlevel(c->map->depth));
lf = addlf(c, r->id, 1);
if (lf) {
int amt;
flag_t *f;
// appears in groups?
f = hasflag(lf->flags, F_NUMAPPEAR);
if (f) {
amt = rnd(f->val[0], f->val[1]);
} else {
amt = 1;
}
if (amt > 1) {
cell_t *adjcell;
amt--; // we've already added one
adjcell = c;
for ( ; amt > 0; amt--) {
// add more in adjacent cells
adjcell = getrandomadjcell(adjcell, WE_NOTSOLID);
if (!adjcell) break;
//lf = addlf(adjcell, r->id, getrandommonlevel(adjcell->map->depth));
lf = addlf(adjcell, r->id, 1);
if (!lf) break;
}
}
}
}
return lf;
}
void addrandomob(cell_t *c) {
char buf[BUFLEN];
if (c->type->solid) {
return;
}
if (getrandomob(c->map, buf)) {
dblog("adding rand obj %s to cell %d,%d",buf,c->x,c->y);
addob(c->obpile, buf);
}
}
void addrandomthing(cell_t *c) {
// if there's already someone there,
// then add an object.
if (c->lf || (rnd(1,2) == 1)) {
// object
if (getrandomob(c->map, buf)) {
dblog("adding %s to cell %d,%d",buf,c->x,c->y);
addob(c->obpile, buf);
}
addrandomob(c);
} else {
r = getrandomlf(c->map, &level);
if (r) {
dblog("adding %s to cell %d,%d",buf,c->x,c->y);
addlf(c, r->id, level);
// monster
addmonster(c, R_RANDOM);
}
}
int cellhaslos(cell_t *c1, cell_t *dest) {
int deltax, deltay;
int numpixels;
int d;
int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
int xinc,yinc,dinc;
int i;
int x1,y1;
int x;
int y;
//int wentuphill = B_FALSE;
//int origheight;
//int shopwall;
int x2,y2;
map_t *map;
if (!dest) return B_FALSE;
// let the player see when dead, otherwise the screen wil
// go black when "You die" appears.
map = c1->map;
x1 = c1->x;
y1 = c1->y;
x2 = dest->x;
y2 = dest->y;
deltax = (x2 - x1);
if (deltax < 0) deltax = -deltax;
deltay = (y2 - y1);
if (deltay < 0) deltay = -deltay;
// can always see your own cell
if ((deltax == 0) && (deltay == 0)) {
//if (viewer->controller == C_HUMAN) wreck->mazelev[z].maze[y2*MAZEW+x2].known = B_PERM;
return B_TRUE;
}
if (deltax >= deltay) {
numpixels = deltax + 1;
d = (deltay*2) - deltax;
dinc1 = deltay << 1;
dinc2 = (deltay-deltax) << 1;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
} else {
numpixels = deltay + 1;
d = (deltax*2) - deltay;
dinc1 = deltax << 1;
dinc2 = (deltax - deltay) << 1;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
}
if (x1 > x2) {
xinc1 = - xinc1;
xinc2 = - xinc2;
}
if (y1 > y2) {
yinc1 = - yinc1;
yinc2 = - yinc2;
}
x = x1; y = y1;
for (i = 0; i < numpixels ; i++) {
cell_t *cell;
// don't need to move out of the last one
if ((x == x2) && (y == y2)) {
break;
}
if (d < 0) {
xinc = xinc1;
yinc = yinc1;
dinc = dinc1;
} else {
xinc = xinc2;
yinc = yinc2;
dinc = dinc2;
}
// you can always see your own cell
if (i != 0) {
// solid cells stop los - but if you are standing on a solid
// cell you can still see out.
cell = getcellat(map, x, y);
if (!cell->type->transparent) {
return B_FALSE;
}
/*
// check for smoke
if ((x != x1) || (y != y1)) { // if not in first cell
if (hasopaqueobject(viewer, x,y,z) && (getheight(x,y,z) >= origheight)) {
if (!hasproplf(viewer, P_SEEINSMOKE)) {
return B_FALSE;
}
}
}
*/
// check for objects which block view
if (hasobwithflag(cell->obpile, F_BLOCKSVIEW)) {
return B_FALSE;
}
}
// move to next cell
d += dinc;
x += xinc;
y += yinc;
}
// made it to the target cell!
return B_TRUE;
}
cell_t *getcellat(map_t *map, int x, int y) {
@ -98,6 +288,87 @@ int getcelldist(cell_t *src, cell_t *dst) {
return (int)sqrt(xd*xd + yd*yd);
}
int getcelldistorth(cell_t *src, cell_t *dst) { // add x/y
return abs(dst->x - src->x) + abs(dst->y - src->y);
}
enum CELLTYPE getemptycelltype(enum HABITAT hab) {
switch (hab) {
case H_DUNGEON:
return CT_CORRIDOR;
default:
break;
}
return CT_CORRIDOR;
}
object_t *gettopobject(cell_t *where) {
object_t *o;
int c;
// draw highest object in sort order
c = 0;
while (sortorder[c] != OC_NULL) {
// check each object against this ob class
// count backwards so more recently dropped objects
// appear first.
for (o = where->obpile->last ; o ; o = o->prev) {
if (o->type->obclass->id == sortorder[c]) {
return o;
}
}
c++;
}
return NULL;
}
void calclight(map_t *map) {
int x,y;
cell_t *c;
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
c = getcellat(map, x,y);
if (c && (c->lit != B_PERM)) c->lit = B_FALSE;
}
}
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
c = getcellat(map, x,y);
if (c) {
int radius;
object_t *o;
// lit based on depth
if (map->depth <= 5) {
c->lit = B_PERM;
}
// has lightproducing lf? (ie.hasflag f_produceslight)
if (c->lf) {
if (lfhasflag(c->lf, F_PRODUCESLIGHT)) {
sumflags(c->lf->flags, F_PRODUCESLIGHT, &radius, NULL, NULL);
makelitradius(c, radius, B_TEMP);
}
// objects in hands or on body...
for (o = c->lf->pack->first ; o ; o = o->next) {
if (obproduceslight(o) && isequipped(o)) {
sumflags(o->flags, F_PRODUCESLIGHT, &radius, NULL, NULL);
makelitradius(c, radius, B_TEMP);
}
}
}
// has light-producing object on ground?
for (o = c->obpile->first ; o ; o = o->next) {
if (obproduceslight(o)) {
sumflags(o->flags, F_PRODUCESLIGHT, &radius, NULL, NULL);
makelitradius(c, radius, B_TEMP);
}
}
}
}
}
}
int calcroompos(map_t *map, int w, int h, int *bx, int *by) {
int x,y;
int bestx = -1, besty = -1;
@ -159,6 +430,19 @@ int calcroompos(map_t *map, int w, int h, int *bx, int *by) {
return B_FALSE;
}
int countadjcellswithflag(cell_t *cell, enum FLAG fid) {
int d;
int count = 0;
cell_t *newcell;
for (d = D_N; d < MAXDIR_ORTH; d++) {
newcell = getcellindir(cell, d);
if (newcell && hasobwithflag(cell->obpile, fid)) {
count++;
}
}
return count;
}
int countadjcellsoftype(cell_t *cell, int id) {
int d;
int count = 0;
@ -193,11 +477,10 @@ int countcellexits(cell_t *cell) {
looppct = percentage change of turning dead-end into loop
maxrooms = max # of rooms
*/
void createmap(map_t *map, int habitat) {
lifeform_t *lf;
void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_t *returnstairtype) {
char buf[BUFLEN];
int wantrooms = B_TRUE;
int x,y,newx,newy;
int x,y;
int d;
int i;
int done,unused;
@ -212,9 +495,10 @@ void createmap(map_t *map, int habitat) {
int maxroomh = MAX_ROOMH;
int bestx,besty;
int w,h;
int startdir,forcex,forcey,ntries;
cell_t *cell;
//object_t *o;
objecttype_t *ot;
//int startdir,forcex,forcey,ntries;
cell_t *cell, *c;
object_t *o;
// parameters
int turnpct = DEF_TURNPCT;
@ -225,7 +509,9 @@ void createmap(map_t *map, int habitat) {
int moved = 0;
int db = B_TRUE;
enum CELLTYPE emptycell;
//int db = B_TRUE;
sprintf(buf, "Map %d",map->id);
map->name = strdup(buf);
@ -238,8 +524,13 @@ void createmap(map_t *map, int habitat) {
map->w = MAX_MAPW;
map->h = MAX_MAPH;
// map depth?
map->depth = depth;
// rememebr seed
//map->seed = 11734;
map->seed = rand() % 65535;
srand(map->seed);
// fill entire maze with walls
for (y = 0; y < map->h; y++) {
@ -248,9 +539,14 @@ void createmap(map_t *map, int habitat) {
}
}
// what kind of cells will 'empty' ones be?
emptycell = getemptycelltype(map->habitat);
// pick initial random spot
cell = getrandomcell(map);
setcelltype(cell, CT_CORRIDOR);
setcelltype(cell, emptycell);
cell->visited = B_TRUE;
//if (db) printf("- Starting (%d,%d)\n",cell->x, cell->y);
@ -279,7 +575,7 @@ void createmap(map_t *map, int habitat) {
// pick new EMPTY random spot
cell = getrandomcell(map);
while (cell->type->solid) {
while (!isempty(cell)) {
cell = getrandomcell(map);
}
//if (db) printf("--- Couldn't find a valid direction. Jumped to (%d,%d).\n",cell->x, cell->y);
@ -298,7 +594,7 @@ void createmap(map_t *map, int habitat) {
moved++;
// blank it
setcelltype(cell,CT_CORRIDOR);
setcelltype(cell,emptycell);
cell->visited = B_TRUE;
// mark surrounding cells as visited
for (d = DC_N; d < MAXDIR_COMPASS; d++) {
@ -399,7 +695,7 @@ void createmap(map_t *map, int habitat) {
connected = B_TRUE;
} else {
// blank adjacent cell
setcelltype(newcell, CT_CORRIDOR);
setcelltype(newcell, emptycell);
newcell->visited = B_TRUE;
}
cell = newcell;
@ -454,6 +750,29 @@ void createmap(map_t *map, int habitat) {
}
// add return staircase to previous map
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile)) {
c = getrandomroomcell(map, ANYROOM);
}
o = addob(c->obpile, returnstairtype->name);
if (parentmap) {
addflag(o->flags, F_MAPLINK, parentmap->id, NA, NA, NULL);
}
// add staircase continuing on (normally this will be down)
if ((map->depth >= MAXDEPTH) && (returnstairtype->id == OT_STAIRSUP)) {
// no need for a down staircase on the last level!
} else {
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile)) {
c = getrandomroomcell(map, ANYROOM);
}
ot = getoppositestairs(returnstairtype);
addob(c->obpile, ot->name);
}
/* void around map
// N
@ -627,9 +946,8 @@ void createmap(map_t *map, int habitat) {
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
cell_t *c;
int obchance;
c = getcellat(map, x, y);
if (c && !c->type->solid) {
if (c && isempty(c)) {
if (rnd(1,100) <= getobchance(map->habitat)) {
addrandomthing(c);
}
@ -641,7 +959,6 @@ void createmap(map_t *map, int habitat) {
// add pillars & objects & monsters to rooms
for (i = 0; i < numrooms; i++) {
int numobsmin,numobsmax,numobs,n;
int x,y;
int maxpillars;
//dblog("Adding obs to room %d/%d",i+1,numrooms);
@ -657,7 +974,7 @@ void createmap(map_t *map, int habitat) {
cell_t *c;
c = getrandomroomcell(map, i);
if (c && !c->type->solid && !countobs(c->obpile)) {
if (c && isempty(c) && !countobs(c->obpile)) {
setcelltype(cell, CT_WALL);
}
}
@ -671,7 +988,7 @@ void createmap(map_t *map, int habitat) {
} else {
*/
numobsmin = 0;
numobsmax = MAXOF(roomw[i],roomh[i]);
numobsmax = MAXOF(roomw[i],roomh[i]) / 2;
//}
@ -689,7 +1006,7 @@ void createmap(map_t *map, int habitat) {
while (!done) {
c = getrandomroomcell(map, i);
// if nothing there
if (c && !countobs(c->obpile)) {
if (c && isempty(c) && !countobs(c->obpile)) {
/*
if (roomspecial[i]) {
if (getrand(1,4) == 1) { // less chance of monster
@ -901,8 +1218,7 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
if (newcell && !newcell->type->solid) {
int doorcount;
doorcount = countadjcellsoftype(cell, CT_DOOROPEN) +
countadjcellsoftype(cell, CT_DOORCLOSED);
doorcount = countadjcellswithflag(cell, F_DOOR);
if (doorcount == 0) {
if ((countcellexits(newcell) == 1) &&
@ -934,8 +1250,7 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
if (newcell && !newcell->type->solid) {
int doorcount;
doorcount = countadjcellsoftype(cell, CT_DOOROPEN) +
countadjcellsoftype(cell, CT_DOORCLOSED);
doorcount = countadjcellswithflag(cell, F_DOOR);
if (doorcount == 0) {
if ((countcellexits(newcell) == 1) &&
@ -966,8 +1281,7 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
newcell = getcellindir(cell, D_W);
if (newcell && !newcell->type->solid) {
int doorcount;
doorcount = countadjcellsoftype(cell, CT_DOOROPEN) +
countadjcellsoftype(cell, CT_DOORCLOSED);
doorcount = countadjcellswithflag(cell, F_DOOR);
if (doorcount == 0) {
if ((countcellexits(newcell) == 1) &&
(iswallindir(newcell,D_N)) &&
@ -997,8 +1311,7 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
newcell = getcellindir(cell, D_E);
if (newcell && !newcell->type->solid) {
int doorcount;
doorcount = countadjcellsoftype(cell, CT_DOOROPEN) +
countadjcellsoftype(cell, CT_DOORCLOSED);
doorcount = countadjcellswithflag(cell, F_DOOR);
if (doorcount == 0) {
if ((countcellexits(newcell) == 1) &&
(iswallindir(newcell,D_N)) &&
@ -1072,6 +1385,7 @@ int dirtoy(int dt, int dir) {
return 0;
}
}
return 0;
}
@ -1088,6 +1402,54 @@ printf("dump of map '%s' (%d x %d):\n",map->name, map->w, map->h);
}
}
void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int wantannounce) {
int x,y;
animradial(c, range, '}');
if (haslos(player, c)) {
if (wantannounce) {
msg("You see %s explosion!", (range > 0) ? "a huge" : "an");
}
} else {
youhear(c, "an explosion!");
}
for (y = c->y - range ; y <= c->y + range ; y++) {
for (x = c->x - range ; x <= c->x + range ; x++) {
cell_t *cc;
cc = getcellat(c->map, x,y);
if (cc && (getcelldist(c, cc) <= range)) {
explodesinglecell(cc, dam, killwalls, o);
}
}
}
}
void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o) {
char obname[BUFLEN];
if (c->lf) {
char buf[BUFLEN];
if (o) {
getobname(o, obname, 1);
sprintf(buf, "an exploding %s",strchr(obname, ' ')+1);
} else {
sprintf(buf, "an explosion");
}
losehp(c->lf, dam, DT_EXPLOSIVE, NULL, buf);
}
damageallobs(o, c->obpile, dam, DT_EXPLOSIVE);
if (killwalls) {
if (c->type->solid) {
// make it empty!
setcelltype(c, getemptycelltype(c->map->habitat));
// add some rubble
addob(c->obpile, "10-50 stones");
}
}
}
map_t *findmap(int mid) {
map_t *m;
for (m = firstmap ; m ; m = m->next) {
@ -1096,6 +1458,29 @@ map_t *findmap(int mid) {
return NULL;
}
map_t *findmapofdepth(int depth) {
map_t *m;
for (m = firstmap ; m ; m = m->next) {
if (m->depth == depth) return m;
}
return NULL;
}
// find the cell in 'map' which contains object oid
cell_t *findobinmap(map_t *m, enum OBCLASS oid) {
cell_t *c;
int x,y;
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
c = getcellat(m, x, y);
if (hasob(c->obpile, oid)) {
return c;
}
}
}
return NULL;
}
void forgetcells(map_t *map, int amt) {
int amtleft;
//int totcells;
@ -1155,6 +1540,8 @@ cell_t *getcellindir(cell_t *cell, int dir) {
case DC_NW:
dt = DT_COMPASS;
break;
default:
return NULL;
}
newx = cell->x + dirtox(dt, dir);
newy = cell->y + dirtoy(dt, dir);
@ -1181,8 +1568,6 @@ int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved) {
}
while (!foundvaliddir) { // keep going until we get a valid direction
int newx,newy;
if (numtries >= MAXDIR_ORTH) { // no valid dirs
return D_NONE; // (pick a new random spot and refresh tried dirs and current dir)
}
@ -1225,6 +1610,10 @@ int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved) {
newcell1 = getcellindir(newcell,D_N);
newcell2 = getcellindir(newcell,D_S);
break;
default: // should never happen
newcell1 = NULL;
newcell2 = NULL;
break;
}
} else {
newcell1 = NULL;
@ -1275,6 +1664,37 @@ int getobchance(int habitat) {
return 0;
}
cell_t *getrandomadjcell(cell_t *c, int wantempty) {
int dir;
int ntries = 0;
cell_t *new;
dir = getrandomdir(DT_COMPASS);
while (ntries < 8) {
new = getcellindir(c, dir);
if (new) {
if (wantempty == WE_EMPTY) {
// make sure it's empty
if (isempty(new)) {
return new;
}
} else if (wantempty == WE_NOTSOLID) {
if (cellwalkable(NULL, new, NULL)) {
return new;
}
} else {
// always ok
return new;
}
}
// not found yet...
dir++;
if (dir > DC_NW) dir = DC_N;
ntries++;
}
return NULL;
}
cell_t *getrandomcell(map_t *map) {
int x,y;
cell_t *cell;
@ -1317,12 +1737,23 @@ cell_t *getrandomroomcell(map_t *map, int roomid) {
for (x = 0; x < map->w; x++) {
c = getcellat(map, x, y);
// is this cell in the correct room and not a wall?
if (c && !c->type->solid && (c->roomid == roomid)) {
if (c && isempty(c)) {
int ok = B_FALSE;
if (c->roomid == roomid) {
ok = B_TRUE;
} else if (roomid == ANYROOM) {
if (c->roomid != -1) {
ok = B_TRUE;
}
}
if (ok) {
poss[npossible] = c;
npossible++;
}
}
}
}
if (npossible <= 0) {
return NULL;
}
@ -1333,6 +1764,143 @@ cell_t *getrandomroomcell(map_t *map, int roomid) {
return c;
}
lifeform_t *haslf(cell_t *c) {
if (c->lf && !isdead(c->lf)) {
return c->lf;
}
return NULL;
}
int hasobject(cell_t *c) {
if (c->obpile->first) {
return B_TRUE;
}
return B_FALSE;
}
int isadjacent(cell_t *src, cell_t *dst) {
if (getcelldist(src, dst) == 1) {
return B_TRUE;
}
return B_FALSE;
}
int isdiggable(cell_t *c) {
switch (c->type->id) {
case CT_WALL: return B_TRUE;
case CT_ROOMWALL: return B_TRUE;
}
return B_FALSE;
}
// if isopen provided, returns whether or not the door is opened
int isdoor(object_t *o, int *isopen) {
int isdoor = B_FALSE;
if (hasflag(o->flags, F_DOOR)) {
isdoor = B_TRUE;
} else {
isdoor = B_FALSE;
}
if (isdoor) {
if (isopen) {
if (hasflag(o->flags, F_OPEN)) {
*isopen = B_TRUE;
} else {
*isopen = B_FALSE;
}
}
}
return isdoor;
}
int isempty(cell_t *c) {
if (!c) return B_FALSE;
if (c->type->solid) return B_FALSE;
if (c->lf) return B_FALSE;
if (!cellwalkable(NULL, c, NULL)) return B_FALSE;
return B_TRUE;
}
//returns TT_ based on what you can scan there
int isinscanrange(cell_t *c, void **thing, char *desc, char *glyph) {
flag_t *f;
// handle scanner
f = lfhasflag(player, F_DETECTLIFE);
if (f) {
if (c->lf) {
if (getcelldistorth(player->cell, c) <= f->val[0]) {
*thing = c->lf;
if (desc) {
char *p;
p = getsizetext(getlfsize(c->lf));
sprintf(desc, "%s %s monster", isvowel(*p) ? "an" : "a", p);
}
if (glyph) {
// select glyph based on size
switch(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;
}
}
}
f = lfhasflag(player, F_DETECTMETAL);
if (f) {
if (getcelldistorth(player->cell, c) <= f->val[0]) {
if (c->lf && ismetal(c->lf->race->material->id) ) {
*thing = c->lf;
if (glyph) *glyph = '*';
if (desc) sprintf(desc, "something metallic");
return TT_MONSTER;
} else {
object_t *o;
for (o = c->obpile->first ; o ; o = o->next) {
if (ismetal(o->material->id)) {
*thing = o;
if (glyph) *glyph = '*';
if (desc) sprintf(desc, "something metallic");
return TT_OBJECT;
}
}
}
}
}
return B_FALSE;
}
int islit(cell_t *c) {
if (c->lit) {
return B_TRUE;
}
return B_FALSE;
}
int isloopdirok(cell_t *cell, int dir) {
int dirok = B_FALSE;
cell_t *newcell;
@ -1393,12 +1961,47 @@ int iswallindir(cell_t *cell, int dir) {
}
void makedoor(cell_t *cell) {
setcelltype(cell, CT_DOORCLOSED);
object_t *o;
setcelltype(cell, getemptycelltype(cell->map->habitat));
o = addob(cell->obpile, "wooden door");
if (o && (rnd(1,2) == 1)) {
opendoor(NULL, o);
} else {
// door is closed - lock it?
if (rnd(1,3) == 1) {
addflag(o->flags, F_LOCKED, B_TRUE, NA, NA, NULL);
}
}
}
void makelit(cell_t *c, int how) {
if (how == B_FALSE) {
c->lit = how;
} else if (c->lit != B_PERM) { // don't override permenant light with temp light!
c->lit = how;
}
}
void makelitradius(cell_t *c, int radius, int how) {
int x,y;
cell_t *c2;
if (radius <= 0) return;
for (y = c->y - radius ; y <= c->y + radius; y++) {
for (x = c->x - radius ; x <= c->x + radius; x++) {
c2 = getcellat(c->map, x, y);
if (c2 && (getcelldistorth(c, c2) <= radius)) {
if (cellhaslos(c,c2)) {
makelit(c2, how);
}
}
}
}
}
void setcelltype(cell_t *cell, int id) {
int i;
assert(cell);
cell->type = findcelltype(id);
assert(cell->type);
@ -1409,16 +2012,28 @@ void setcelltype(cell_t *cell, int id) {
void updateknowncells(void) {
int x,y;
map_t *map;
object_t *wep;
int seenundead = B_FALSE;
map = player->cell->map;
wep = getweapon(player);
for (y = viewy; y < viewy + viewh; y++) {
for (x = viewx; x < viewx + vieww; x++) {
cell_t *cell;
cell = getcellat(map, x, y);
if (cell && !cell->known && haslos(player, cell)) {
if (cell) {
//if ((player->cell == cell) || haslos(player, cell)) {
if (haslos(player, cell)) {
if (!cell->known) {
cell->known = B_TRUE;
}
if (cell->lf && lfhasflag(cell->lf, F_UNDEAD)) {
seenundead = B_TRUE;
}
}
}
}
}
}

25
map.h
View File

@ -2,30 +2,53 @@
cell_t *addcell(map_t *map, int x, int y);
map_t *addmap(void);
lifeform_t *addmonster(cell_t *c, enum RACE raceid);
void addrandomob(cell_t *c);
void addrandomthing(cell_t *c);
int cellhaslos(cell_t *c1, cell_t *dest);
cell_t *getcellat(map_t *map, int x, int y);
int getcelldist(cell_t *src, cell_t *dst);
int getcelldistorth(cell_t *src, cell_t *dst);
enum CELLTYPE getemptycelltype(enum HABITAT hab);
object_t *gettopobject(cell_t *where);
void calclight(map_t *map);
int calcroompos(map_t *map, int w, int h, int *bx, int *by);
int countadjcellsoftype(cell_t *cell, int id);
int countadjcellswithflag(cell_t *cell, enum FLAG fid);
int countcellexits(cell_t *cell);
void createmap(map_t *map, int habitat);
void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_t *returnstairtype);
void createroom(map_t *map, int minx, int miny, int w, int h, int roomid);
int dirtox(int dt, int dir);
int dirtoy(int dt, int dir);
void dumpmap(map_t *map);
void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o);
void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int wantannounce);
map_t *findmap(int mid);
map_t *findmapofdepth(int depth);
cell_t *findobinmap(map_t *m, enum OBCLASS oid);
void forgetcells(map_t *map, int amt);
cell_t *getcellindir(cell_t *cell, int dir);
int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved);
int getobchance(int habitat);
cell_t *getrandomadjcell(cell_t *c, int wantempty);
cell_t *getrandomcell(map_t *map);
cell_t *getrandomcelloftype(map_t *map, int id);
int getrandomdir(int dirtype);
cell_t *getrandomroomcell(map_t *map, int roomid);
lifeform_t *haslf(cell_t *c);
int hasobject(cell_t *c);
int isadjacent(cell_t *src, cell_t *dst);
int isdiggable(cell_t *c);
int isdoor(object_t *o, int *isopen);
int isempty(cell_t *c);
int isinscanrange(cell_t *c, void **thing, char *desc, char *glyph);
int islit(cell_t *c);
int isloopdirok(cell_t *cell, int dir);
int isnewcellok(cell_t *cell, char *err);
int isonmap(map_t *map, int x, int y);
int iswallindir(cell_t *cell, int dir);
void makedoor(cell_t *cell);
void makelit(cell_t *c, int how);
void makelitradius(cell_t *c, int radius, int how);
void setcelltype(cell_t *cell, int id);
void updateknowncells(void);

715
move.c
View File

@ -1,32 +1,97 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "io.h"
#include "lf.h"
#include "map.h"
#include "move.h"
#include "nexus.h"
#include "objects.h"
#include "text.h"
extern lifeform_t *player;
extern int statdirty;
extern enum ERROR reason;
extern void *rdata;
int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error) {
if (isplayer(lf)) {
if (canmove(lf, dir, error)) {
return B_TRUE;
}
} else {
if (canmove(lf, dir, error) && willmove(lf, dir, error)) {
return B_TRUE;
}
}
return B_FALSE;
}
int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell;
// default
if (error) {
*error = E_OK;
rdata = NULL;
}
if (lfhasflag(lf, F_GRAVBOOSTED)) {
if (error) *error = E_GRAVBOOSTED;
return B_FALSE;
}
// TODO: check if we are burdened, paralyzed, etc
cell = getcellindir(lf->cell, dir);
return cellwalkable(lf, cell, error);
}
int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
object_t *o;
// default
if (error) {
*error = E_OK;
rdata = NULL;
}
if (!cell || cell->type->solid) {
if (error) *error = E_WALLINWAY;
return B_FALSE;
}
if (cell->lf) {
for (o = cell->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_IMPASSABLE)) {
if (lf) {
if ((lf->race->material->id != MT_GAS) &&
(lf->race->material->id != MT_SLIME)) {
rdata = o;
if (error) *error = E_OBINWAY;
return B_FALSE;
}
} else {
rdata = o;
if (error) *error = E_OBINWAY;
return B_FALSE;
}
}
}
if (cell->lf && (cell->lf != lf)) {
if (error) *error = E_LFINWAY;
return B_FALSE;
}
return B_TRUE;
}
void dorandommove(lifeform_t *lf, int badmovesok) {
int dir;
int tries = 0;
@ -36,64 +101,190 @@ void dorandommove(lifeform_t *lf, int badmovesok) {
// find a valid direction
dir = getrandomdir(DT_COMPASS);
moveok = canmove(lf, dir, &why);
moveok = canandwillmove(lf, dir, &why);
if (!moveok && badmovesok) {
switch (why) {
// actually okay to move into someone
case E_WALLINWAY:
case E_LFINWAY:
moveok = B_TRUE;
break;
default:
break;
}
}
while (!moveok) {
// try next direction...
if (++dir > DC_NW) dir = DC_N;
if (++tries >= MAXDIR_COMPASS) {
dowait(lf);
rest(lf, B_TRUE);
return;
}
// check this direction...
moveok = canmove(lf, dir, &why);
moveok = canandwillmove(lf, dir, &why);
if (!moveok && badmovesok) {
switch (why) {
case E_WALLINWAY:
case E_LFINWAY:
moveok = B_TRUE;
break;
default:
break;
}
}
}
trymove(lf, dir);
}
int dowait(lifeform_t *lf) {
taketime(lf, SPEED_WAIT);
if (lf->controller == C_PLAYER) {
// clear msg bar
clearmsg();
int getdiraway(cell_t *src, cell_t *dst, int wantcheck) {
int d;
cell_t *c;
int maxdist=-1,bestdir=D_NONE;
for (d = DC_N; d <= DC_NW; d++) {
int thisdist = -1;
int ok = B_FALSE;
c = getcellindir(src, d);
if (!c) continue;
if (c == dst) {
// destination is the thing we're fleeing from!
thisdist = -1;
} else {
if (wantcheck) {
if (src->lf && canandwillmove(src->lf, d, NULL)) {
ok = B_TRUE;
} else if (!src->lf) {
ok = B_TRUE;
}
return B_FALSE;
} else {
if (src->lf && cellwalkable(src->lf, c, NULL)) {
ok = B_TRUE;
} else if (!src->lf) {
ok = B_TRUE;
}
}
if (ok) {
thisdist = getcelldist(c, dst);
} else {
thisdist = -1;
}
void movelf(lifeform_t *lf, cell_t *newcell) {
if (thisdist > maxdist) {
maxdist = thisdist;
bestdir = d;
}
}
}
// TODO: handle ties
return bestdir;
}
int getdirtowards(cell_t *src, cell_t *dst, int wantcheck) {
int d;
cell_t *c;
int mindist=9999,bestdir=D_NONE;
for (d = DC_N; d <= DC_NW; d++) {
int ok = B_FALSE;
c = getcellindir(src, d);
if (!c) continue;
if (c == dst) {
// destination is adjacent!
bestdir = d;
break;
}
if (wantcheck) {
if (src->lf && canandwillmove(src->lf, d, NULL)) {
ok = B_TRUE;
} else if (!src->lf) {
ok = B_TRUE;
}
} else {
if (src->lf && cellwalkable(src->lf, c, NULL)) {
ok = B_TRUE;
} else if (!src->lf) {
ok = B_TRUE;
}
}
if (ok) {
int thisdist;
thisdist = getcelldist(c, dst);
if (thisdist < mindist) {
mindist = thisdist;
bestdir = d;
}
}
}
// TODO: handle ties
return bestdir;
}
int moveawayfrom(lifeform_t *lf, cell_t *dst) {
int dir;
int rv = B_TRUE;
// move towards them
dir = getdiraway(lf->cell, dst, B_TRUE);
if (dir != D_NONE) {
rv = trymove(lf, dir);
}
return rv;
}
// returns TRUE if something happened
int movelf(lifeform_t *lf, cell_t *newcell) {
object_t *o,*nexto;
char obname[BUFLEN],lfname[BUFLEN],buf[BUFLEN];
lifeform_t *l;
int didmsg = B_FALSE;
flag_t *f;
// update current cell
lf->cell->lf = NULL;
// if required, relink lifeform to new map
if (newcell->map != lf->cell->map) {
if (isplayer(lf)) {
statdirty = B_TRUE;
}
relinklf(lf, newcell->map);
}
// update lifeform
lf->cell = newcell;
// nothing should be in new cell..
assert(!newcell->lf);
// update new cell
newcell->lf = lf;
if (isbleeding(lf)) {
if (rnd(1,2) == 1) {
bleed(lf);
}
}
// check ground objects
if (!hasflag(lf->flags, F_FLYING)) {
if (!lfhasflag(lf, F_FLYING)) {
for (o = newcell->obpile->first ; o ; o = nexto ) {
nexto = o->next;
if (hasflag(o->flags, F_SHARP)) {
f = hasflag(o->flags, F_SHARP);
if (f) {
object_t *boots;
// has boots on?
boots = getequippedob(lf->pack, BP_FEET);
@ -106,16 +297,18 @@ void movelf(lifeform_t *lf, cell_t *newcell) {
// we want 'xx steps on some pieces of broken glass'
// not 'xx steps on 5 pieces of broken glass'
newname = makeplural(obname);
strrep(newname, "a ", "some ");
newname = strrep(newname, "a ", "some ", NULL);
strcpy(obname, newname);
free(newname);
}
if (lf->controller == C_PLAYER) {
msg("You crush %s underfoot.",obname);
didmsg = B_TRUE;
} else if (haslos(player, newcell)) {
getlfname(lf, lfname);
capitalise(lfname);
msg("%s crushes %s.",lfname, obname);
didmsg = B_TRUE;
}
// kill object
removeob(o, o->amt);
@ -124,13 +317,15 @@ void movelf(lifeform_t *lf, cell_t *newcell) {
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(1,2), DT_SLASH, NULL, buf);
losehp(lf, rnd(f->val[0],f->val[1]), DT_SLASH, NULL, buf);
}
}
} // end foreach object in cell
@ -138,100 +333,474 @@ void movelf(lifeform_t *lf, cell_t *newcell) {
// update where player knows
// (but without a map you will then slowly forget it)
if (lf->controller == C_PLAYER) {
if (isplayer(lf)) {
updateknowncells();
}
// does anyone else see you?
for (l = newcell->map->lf ; l ; l = l->next) {
if (l != lf) {
if (haslos(l, newcell)) {
interrupt(lf);
}
}
}
return didmsg;
}
// basically this is a warpper for 'movelf' which
// does other game things like telling the player
// what is here.
int moveto(lifeform_t *lf, cell_t *newcell) {
char lfname[BUFLEN];
int didmsg;
getlfname(lf, lfname);
// actually do the move
movelf(lf, newcell);
didmsg = movelf(lf, newcell);
// tell player about things
if (!isdead(lf) && (lf->controller == C_PLAYER)) {
int numobs;
char buf[BUFLEN];
numobs = countobs(newcell->obpile);
if (numobs == 1) {
getobname(newcell->obpile->first, buf, newcell->obpile->first->amt);
msg("You see %s here.", buf);
} else if ((numobs > 1) && (numobs <= 3)) {
msg("You see a few objects here.");
} else if ((numobs > 3) && (numobs <= 6)) {
msg("You see some objects here.");
} else if (numobs > 6) {
msg("You see many objects here.");
} else {
// just clear the message buffer
clearmsg();
if (!isdead(lf)) {
// some lifeforms can go through things
if (lf->race->material->id == MT_GAS) {
object_t *o;
char obname[BUFLEN];
for (o = newcell->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_IMPASSABLE)) {
getobname(o, obname, o->amt);
if (isplayer(lf)) {
msg("You seep around %s.", obname);
} else if (haslos(player, newcell)) {
msg("%s seeps around %s.", lfname, obname);
}
}
}
} else if (lf->race->material->id == MT_SLIME) {
object_t *o;
char obname[BUFLEN];
for (o = newcell->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_IMPASSABLE)) {
getobname(o, obname, o->amt);
if (isplayer(lf)) {
msg("You seep under %s.", obname);
} else if (haslos(player, newcell)) {
msg("%s seeps under %s.", lfname, obname);
}
}
}
}
int opendoor(lifeform_t *lf, cell_t *cell) {
char buf[BUFLEN];
if (cell->type->id == CT_DOORCLOSED) {
// open it
setcelltype(cell, CT_DOOROPEN);
if (lf->controller == C_PLAYER) {
msg("You open a door.");
// see objects on ground
if (isplayer(lf)) {
int numobs;
numobs = countobs(newcell->obpile);
if ((numobs == 0) && !newcell->writing) {
// just clear the message buffer
if (!didmsg) clearmsg();
} else { // tell player what is here
dolook(newcell);
}
}
}
return B_FALSE;
}
int movetowards(lifeform_t *lf, cell_t *dst) {
int dir;
int rv = B_TRUE;
// move towards them
dir = getdirtowards(lf->cell, dst, B_TRUE);
if (dir != D_NONE) {
rv = trymove(lf, dir);
}
return rv;
}
int opendoorat(lifeform_t *lf, cell_t *c) {
object_t *o;
int rv;
o = hasobwithflag(c->obpile, F_DOOR);
if (o) {
rv = opendoor(lf, o);
} else {
// TODO: only announce if player can see it
if (haslos(player, cell)) {
rv = B_TRUE;
}
return rv;
}
int opendoor(lifeform_t *lf, object_t *o) {
cell_t *doorcell;
char buf[BUFLEN];
char obname[BUFLEN];
flag_t *f;
doorcell = o->pile->where;
assert(doorcell);
getobname(o, obname, 1);
if (!isdoor(o, NULL)) {
return B_TRUE;
}
if (lf && lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
if (isplayer(lf)) {
msg("You have no hands with which to open the door!");
}
return B_TRUE;
}
f = hasflag(o->flags, F_OPEN);
if (f) {
if (lf && isplayer(lf)) {
msg("It is already open!");
}
return B_TRUE;
} else {
// locked?
if (hasflag(o->flags, F_LOCKED)) {
if (lf && isplayer(lf)) {
msg("The door is locked.");
}
return B_TRUE;
} else {
// open it
addflag(o->flags, F_OPEN, B_TRUE, NA, NA, NULL);
f = hasflag(o->flags, F_IMPASSABLE);
if (f) killflag(f);
f = hasflag(o->flags, F_BLOCKSVIEW);
if (f) killflag(f);
if (lf) {
if (lf->controller == C_PLAYER) {
msg("You open %s.",obname);
} else {
if (haslos(player, lf->cell) && isadjacent(lf->cell, doorcell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s opens a door.",buf);
msg("%s opens %s.",buf, obname);
} else if (haslos(player, doorcell)) {
capitalise(obname);
msg("%s opens.",obname);
}
}
taketime(lf, getmovespeed(lf));
touch(lf, o);
}
}
}
return B_FALSE;
}
int closedoorat(lifeform_t *lf, cell_t *c) {
object_t *o;
int rv;
o = hasobwithflag(c->obpile, F_DOOR);
if (o) {
rv = closedoor(lf, o);
} else {
rv = B_TRUE;
}
return rv;
}
int closedoor(lifeform_t *lf, object_t *o) {
cell_t *cell;
char buf[BUFLEN];
char obname[BUFLEN];
flag_t *f;
getobname(o, obname, 1);
if (!isdoor(o, NULL)) {
if (isplayer(lf)) {
msg("There is nothing to close there!");
}
return B_TRUE;
}
if (lf && lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
if (isplayer(lf)) {
msg("You have no hands with which to close the door!");
}
return B_TRUE;
}
f = hasflag(o->flags, F_OPEN);
if (!f) {
if (lf && (lf->controller == C_PLAYER)) {
msg("It is already closed!");
}
return B_TRUE;
} else {
// close it
killflag(f);
addflag(o->flags, F_IMPASSABLE, B_TRUE, NA, NA, NULL);
addflag(o->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
if (lf) {
if (lf->controller == C_PLAYER) {
msg("You close %s.", obname);
} else {
if (haslos(player, lf->cell) && isadjacent(lf->cell, cell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s closes %s.",buf, obname);
} else if (haslos(player, cell)) {
capitalise(obname);
msg("%s closes.",obname);
}
}
taketime(lf, getmovespeed(lf));
touch(lf, o);
}
}
return B_FALSE;
}
int tryrun(lifeform_t *lf, int dir) {
// continue moving until we fail
while (canmove(lf, dir, NULL)) {
trymove(lf,dir);
if (!trymove(lf, dir)) {
addflag(lf->flags, F_RUNNING, dir, NA, NA, NULL);
}
return B_FALSE;
}
int trymove(lifeform_t *lf, int dir) {
cell_t *cell;
enum ERROR errcode;
char buf[BUFLEN], buf2[BUFLEN];
// try to pull lifeform towards cell c (or next to it)
int pullnextto(lifeform_t *lf, cell_t *c) {
int dir;
cell_t *dst = NULL;
cell = getcellindir(lf->cell, dir);
if (canmove(lf, dir, &errcode)) {
moveto(lf, cell);
taketime(lf, getmovespeed(lf));
} else {
switch (errcode) {
case E_WALLINWAY:
// is it a door in the way?
if (cell->type->id == CT_DOORCLOSED) {
// try to open it
opendoor(lf, cell);
} else {
if (lf->controller == C_PLAYER) {
msg("Ouch! You walk into a wall.");
}
}
break;
case E_LFINWAY:
// attack!
doattack(lf, cell->lf);
break;
}
dst = c;
while (dst->lf) {
dir = getdirtowards(dst, lf->cell, B_FALSE);
if (dir == D_NONE) {
return B_TRUE;
} else {
dst = getcellindir(dst, dir);
if (dst == lf->cell) {
return B_TRUE;
}
}
}
// is the path clear?
if (!dst || !haslof(lf, dst)) {
return B_TRUE;
}
if (isplayer(lf) || haslos(player, lf->cell)) {
char buf[BUFLEN];
getlfname(lf, buf);
msg("%s %s pulled %s!", buf, isplayer(lf) ? "are" : "is",
lfhasflag(lf, F_FLYING) ? "through the air" :
"along the ground");
}
movelf(lf, dst);
return B_FALSE;
}
// teleport somewhere, along with puffs of smoke etc
int teleportto(lifeform_t *lf, cell_t *c) {
char buf[BUFLEN];
if (!isplayer(lf) && haslos(player, lf->cell)) {
getlfname(lf, buf);
msg("%s disappears in a puff of smoke!", buf);
}
addob(lf->cell->obpile, "puff of smoke");
movelf(lf, c);
addob(lf->cell->obpile, "cloud of smoke");
if (isplayer(lf)) {
msg("Suddenly, your surroundings appear different!");
} else if (haslos(player, lf->cell)) {
getlfname(lf, buf);
msg("%s appears in a cloud of smoke!", buf);
}
// show any objects here, just like if we moved.
// BUT don't let dolook() clear the msg bar if there are
// no objects here.
if (isplayer(lf) && countobs(lf->cell->obpile)) {
dolook(lf->cell);
}
return B_FALSE;
}
int trymove(lifeform_t *lf, int dir) {
cell_t *cell;
enum ERROR errcode;
char buf[BUFLEN];
cell = getcellindir(lf->cell, dir);
if (canandwillmove(lf, dir, &errcode)) {
reason = E_OK;
moveto(lf, cell);
taketime(lf, getmovespeed(lf));
} else {
object_t *inway;
int door, dooropen;
reason = errcode;
switch (errcode) {
case E_WALLINWAY:
if (isplayer(lf)) {
msg("Ouch! You %s into a wall.", getmoveverb(lf));
} else if (haslos(player, lf->cell)) {
getlfname(lf, buf);
msg("%s %ss into a wall.", buf, getmoveverb(lf));
}
if (isblind(lf)) {
if (isplayer(lf)) {
// only take damage if we didn't know about this
if (!cell->known) {
sprintf(buf, "%sing into a wall", getmoveverb(lf));
losehp(lf, 1, DT_BASH, NULL, buf);
cell->known = B_TRUE;
taketime(lf, getmovespeed(lf));
}
} else {
sprintf(buf, "%sing into a wall", getmoveverb(lf));
losehp(lf, 1, DT_BASH, NULL, buf);
taketime(lf, getmovespeed(lf));
}
}
break;
case E_OBINWAY:
inway = (object_t *)rdata;
door = isdoor(inway, &dooropen);
if (door && !dooropen) {
if (isblind(lf)) {
// run into it
if (isplayer(lf)) {
if (cell->known) {
// try to open it
opendoor(lf, inway);
} else {
msg("Ouch! You %s into a door.", getmoveverb(lf));
cell->known = B_TRUE;
sprintf(buf, "%sing into a door", getmoveverb(lf));
losehp(lf, 1, DT_BASH, NULL, buf);
taketime(lf, getmovespeed(lf));
}
} else {
if (haslos(player, lf->cell)) {
getlfname(lf, buf);
msg("%s %ss into a wall.", buf, getmoveverb(lf));
}
sprintf(buf, "%sing into a door", getmoveverb(lf));
losehp(lf, 1, DT_BASH, NULL, buf);
taketime(lf, getmovespeed(lf));
}
} else {
// try to open it
opendoor(lf, inway);
}
} else {
// can we push this?
if (ispushable(inway)) {
if (canpush(lf, inway, dir)) {
// push it!
push(lf, inway, dir);
} else {
if (lf->controller == C_PLAYER) {
char obname[BUFLEN];
getobname(inway, obname, 1);
switch (reason) {
case E_TOOHEAVY:
msg("The %s is too heavy to move.",strchr(obname, ' ')+1);
break;
case E_INSUBSTANTIAL:
msg("You cannot push %s without a physical body!",strchr(obname, ' ')+1);
break;
default:
msg("The %s won't move for some reason.",strchr(obname, ' ')+1);
break;
}
}
}
} else { // object is in the way
if (lf->controller == C_PLAYER) {
char obname[BUFLEN];
getobname(inway, obname, 1);
msg("There is %s in your way.",obname);
}
}
}
break;
case E_LFINWAY:
// attack!
return attacklf(lf, cell->lf);
break;
case E_GRAVBOOSTED:
if (isplayer(lf)) {
msg("You try to move but are unable to lift your feet!");
taketime(lf, getmovespeed(lf));
}
break;
default:
break;
}
if (reason == E_OK) {
return B_FALSE;
} else {
return B_TRUE;
}
}
return B_FALSE;
}
int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell;
object_t *o;
enum IQBRACKET iq;
// default
if (error) {
*error = E_OK;
rdata = NULL;
}
cell = getcellindir(lf->cell, dir);
// check for cursed objects + animals
for (o = cell->obpile->first ; o ; o = o->next) {
if (!isplayer(lf)) {
if (o->blessed == B_CURSED) {
if (lfhasflag(lf, F_ANIMAL)) {
if (!lfhasflag(lf, F_FLYING)) {
return B_FALSE;
}
}
}
}
}
// check for dangerous objects
iq = getiqname(getattr(lf, A_IQ), NULL);
if (iq >= IQ_AVERAGE) {
flag_t *f;
object_t *o;
for (o = cell->obpile->first ; o ; o = o->next) {
// don't walk on sharp objects without boots
if (hasflag(o->flags, F_SHARP)) {
if (!getequippedob(lf->pack, BP_FEET)) {
return B_FALSE;
}
}
f = hasflag(o->flags, F_WALKDAM);
if (f) {
// are we immune to this?
if (!lfhasflagval(lf, F_DTIMMUNE, f->val[1], NA, NA, NULL)) {
return B_FALSE;
}
}
}
}
return B_TRUE;
}

17
move.h
View File

@ -1,8 +1,21 @@
#include "defs.h"
int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error);
int canmove(lifeform_t *lf, int dir, enum ERROR *error);
int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error);
int closedoorat(lifeform_t *lf, cell_t *c);
int closedoor(lifeform_t *lf, object_t *o);
void dorandommove(lifeform_t *lf, int badmovesok);
int dowait(lifeform_t *lf);
void movelf(lifeform_t *lf, cell_t *newcell);
int getdiraway(cell_t *src, cell_t *dst, int wantcheck);
int getdirtowards(cell_t *src, cell_t *dst, int wantcheck);
int moveawayfrom(lifeform_t *lf, cell_t *dst);
int movelf(lifeform_t *lf, cell_t *newcell);
int moveto(lifeform_t *lf, cell_t *newcell);
int movetowards(lifeform_t *lf, cell_t *dst);
int opendoorat(lifeform_t *lf, cell_t *c);
int opendoor(lifeform_t *lf, object_t *o);
int pullnextto(lifeform_t *lf, cell_t *c);
int teleportto(lifeform_t *lf, cell_t *c);
int trymove(lifeform_t *lf, int dir);
int tryrun(lifeform_t *lf, int dir);
int willmove(lifeform_t *lf, int dir, enum ERROR *error);

513
nexus.c
View File

@ -1,38 +1,77 @@
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ai.h"
#include "attack.h"
#include "io.h"
#include "flag.h"
#include "lf.h"
#include "map.h"
#include "move.h"
#include "nexus.h"
#include "objects.h"
#include "save.h"
#include "text.h"
material_t *material = NULL,*lastmaterial = NULL;
objectclass_t *objectclass = NULL,*lastobjectclass = NULL;
objecttype_t *objecttype = NULL,*lastobjecttype = NULL;
celltype_t *firstcelltype = NULL,*lastcelltype = NULL;
race_t *firstrace = NULL,*lastrace = NULL;
job_t *firstjob = NULL,*lastjob = NULL;
map_t *firstmap = NULL,*lastmap = NULL;
knowledge_t *knowledge = NULL, *lastknowledge = NULL;
// maintains unique lifeform ID numbers
long nextlfid = 0;
int SCREENW = DEF_SCREENW;
int SCREENH = DEF_SCREENH;
// object return list
object_t *retobs[MAXPILEOBS+1];
int retobscount[MAXPILEOBS+1];
int nretobs = 0;
FILE *logfile;
prompt_t prompt;
char msghist[MAXHISTORY][BUFLEN];
int nmsghist = 0;
enum ERROR reason; // global for returning errors
void *rdata; // globel for returning data
lifeform_t *player = NULL;
int gameover;
int gamestarted = B_FALSE;
int main(char **argv, int argc) {
long curtime = 0;
long timeleft = 0;
extern int statdirty;
int needredraw = B_TRUE;
int numdraws = 0;
int main(int argc, char **argv) {
int newworld = B_FALSE;
object_t *o;
atexit(cleanup);
// init params
init();
if (init()) {
exit(1);
}
// load whatever maps are available
loadall();
@ -44,25 +83,60 @@ int main(char **argv, int argc) {
if (!firstmap) {
newworld = B_TRUE;
addmap();
createmap(firstmap, H_DUNGEON);
createmap(firstmap, 1, H_DUNGEON, NULL, findot(OT_STAIRSUP));
}
if (!knowledge) {
// populate scroll names
// populate scroll, potion, etc names
genhiddennames();
}
// if no player (ie. didn't load a game), add them
if (!player) {
char *user;
char pname[BUFLEN];
job_t *j;
char ch;
cell_t *where;
// ask for race
initprompt(&prompt, "Select your race:");
ch = 'a';
for (j = firstjob ; j ; j = j->next) {
addchoice(&prompt, ch++, j->name, NULL, j);
}
j = NULL;
while (!j) {
getchoice(&prompt);
j = prompt.result;
}
// find staircase
where = findobinmap(firstmap, OT_STAIRSUP);
assert(where);
// add player
player = addlf(getrandomcelloftype(firstmap, CT_ROOM), R_HUMAN, 1);
player->controller = C_PLAYER;
real_addlf(where, R_HUMAN, 1, C_PLAYER); // this will assign 'player'
user = getenv("USER");
if (user) {
addflag(player->flags, F_NAME, NA, NA, NA, getenv("USER"));
} else {
addflag(player->flags, F_NAME, NA, NA, NA, "Anonymous");
}
givejob(player, j->id);
// player needs hunger
addflag(player->flags, F_HUNGER, 0, NA, NA, NULL);
drawscreen();
msg("Welcome to %snexus!", newworld ? "the new " : "");
getplayernamefull(pname);
msg("Greetings %s, welcome to %snexus!", pname, newworld ? "the new " : "");
more();
// XXX testing
//addlf(getcellindir(player->cell, D_N), R_GOBLIN, 1);
// 00:00 - 23:59
curtime = rnd(0,86399);
} else {
drawscreen();
msg("Welcome back!");
@ -73,38 +147,71 @@ int main(char **argv, int argc) {
// start game - this will cause debug messages to now
// go to the log file instead of stdout.
gamestarted = B_TRUE;
timeleft = 0; // reset game timer
// calculate initial light
calclight(player->cell->map);
// pre-calc line-of-sight for player
precalclos(player);
// show level
drawscreen();
// MAIN LOOP
// basic flow is:
//
// donextturn() - process a turn for a lifeform
// turneffectslf() Rest effects, Damage from floor objects, etc
// lifeform takes action
// checkdeath() - check for object/player death. remove dead things.
// timeeffectsworld() Fires burn out, ice melts, etc
// Also keeps lf->timespent values under control.
//
//
// redraw screen
//
// checkendgame() - has the game ended yet?
gameover = B_FALSE;
while (!gameover) {
map_t *curmap;
curmap = player->cell->map;
// default to no redraw - donextturn() will change this if needed.
needredraw = B_FALSE;
numdraws = 0;
// someone has a turn - this will then call taketime -> timehappens();
donextturn(curmap);
// someone has a turn
donextturn(player->cell->map);
// update lifeform structue to figure out who goes next
sortlf(player->cell->map);
//timehappens(curmap);
// TODO: monsters move etc
// check for death etc
doeffects();
// show level
// show level (if required)
//if (haslos(player, curmap->lf->cell)) {
drawscreen();
//dblog("**** END of turn, numdraws = %d", numdraws);
// check end of game
checkendgame();
}
// identify all objects
for (o = player->pack->first ; o ; o = o->next) {
identify(o);
}
// show possessions
dofinaloblist(player->pack);
// print tombstone
tombstone(player);
return B_FALSE;
}
celltype_t *addcelltype(int id, char glyph, int solid, int transparent) {
celltype_t *addcelltype(int id, char *name, char glyph, int solid, int transparent, enum MATERIAL mat) {
celltype_t *a;
// add to the end of the list
@ -124,11 +231,47 @@ celltype_t *addcelltype(int id, char glyph, int solid, int transparent) {
// set props
a->id = id;
a->name = strdup(name);
a->glyph = glyph;
a->solid = solid;
a->transparent = transparent;
a->material = findmaterial(mat);
a->flags = addflagpile(NULL, NULL);
return a;
}
void checkdeath(void) {
lifeform_t *lf, *nextlf;
int x,y;
for (lf = player->cell->map->lf; lf ; lf = nextlf) {
nextlf = lf->next;
// check for death
if (lf->hp <= 0) {
// die!
die(lf);
continue;
}
// check for object death
removedeadobs(lf->pack);
}
// check for object death on map
for (y = 0; y < player->cell->map->h; y++) {
for (x = 0; x < player->cell->map->w; x++) {
cell_t *c;
c = getcellat(player->cell->map, x, y);
if (c) {
removedeadobs(c->obpile);
}
}
}
}
void checkendgame(void) {
if (!player->alive) {
gameover = B_TRUE;
@ -141,38 +284,94 @@ void cleanup(void) {
}
void doeffects(void) {
lifeform_t *lf;
// check for death
for (lf = player->cell->map->lf; lf ; lf = lf->next) {
if (lf->hp <= 0) {
// die!
die(lf);
}
}
}
void donextturn(map_t *map) {
lifeform_t *who;
// show messages to plaeyr
drawmsg();
who = map->lf;
if (who->controller == C_PLAYER) {
dblog("**** donextturn for: id %d %s", who->id, who->race->name);
turneffectslf(who);
// calculate light
calclight(map);
// pre-calculate line of sight for this lifeform
precalclos(who);
if (isplayer(who) || haslos(player, who->cell)) {
needredraw = B_TRUE;
}
// update gun targets
autotarget(who);
assert(who->timespent == 0);
// keep looping until they actually do something or are dead!
while (who->timespent == 0) {
if (isdead(who)) {
// skip turn
taketime(who, SPEED_DEAD);
} else {
// do we need to run away from something?
if (!flee(who)) {
int donormalmove = B_TRUE;
flag_t *f;
if (donormalmove) {
// paralyzed?
f = hasflag(who->flags, F_PARALYZED);
if (f) {
rest(who, B_FALSE);
donormalmove = B_FALSE;
}
}
// resting?
if (donormalmove) {
f = hasflag(who->flags, F_RESTING);
if (f) {
if (who->hp < who->maxhp) {
rest(who, B_TRUE);
donormalmove = B_FALSE;
} else {
killflag(f);
if (isplayer(who)) msg("You finish resting.");
}
}
}
if (donormalmove) {
if (isplayer(who)) {
drawcursor();
// find out what player wants to do
handleinput();
} else {
// TODO: do ai move
// do ai move
aimove(who);
}
}
}
}
}
if (isdead(who) || haslos(player, who->cell)) {
needredraw = B_TRUE;
}
// check for death etc
checkdeath();
//////////////////////////////////
// effects which happen every GAME TICK
// ie. object hp drain etc
//////////////////////////////////
timeeffectsworld(map);
// everyone else's time goes down by 1
for (who = map->lf->next ; who ; who = who->next ){
if (who->timespent > 0) who->timespent--;
}
//for (who = map->lf->next ; who ; who = who->next ){
// if (who->timespent > 0) who->timespent--;
//}
}
celltype_t *findcelltype(int id) {
@ -196,6 +395,10 @@ char *getdirname(int dir) {
return "South";
case D_W:
return "West";
case D_UP:
return "up";
case D_DOWN:
return "down";
case D_UNKNOWN:
return "D_UNKNOWN";
case D_NONE:
@ -204,27 +407,45 @@ char *getdirname(int dir) {
return "?errordir?";
}
void getrarity(int depth, int *min, int *max, int range) {
int mid;
mid = 100 - (depth * 3);
*min = mid - range; if (*min < 0) *min = 0;
*max = mid + range; if (*max > 100) *max = 100;
if (*min > 75) *min = 75;
if (*max < 25) *max = 25;
}
int init(void) {
// random numbers
srand(time(NULL));
initobjects();
initjobs();
initrace();
// cell types
addcelltype(CT_WALL, "rock wall", '#', B_SOLID, B_OPAQUE, MT_STONE);
addcelltype(CT_ROOMWALL, "rock wall", '#', B_SOLID, B_OPAQUE, MT_STONE);
addcelltype(CT_CORRIDOR, "rock floor", '.', B_EMPTY, B_TRANS, MT_STONE);
addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', B_EMPTY, B_TRANS, MT_STONE);
addcelltype(CT_ROOM, "rock floor", '.', B_EMPTY, B_TRANS, MT_STONE);
//addcelltype(CT_DOOROPEN, "wooden door", '-', B_EMPTY, B_TRANS, MT_WOOD);
//addcelltype(CT_DOORCLOSED, "wooden door", '+', B_SOLID, B_OPAQUE, MT_WOOD);
if (validateobs()) {
return B_TRUE;
}
if (validateraces()) {
return B_TRUE;
}
// open log file
logfile = fopen("log.txt","wt");
fprintf(logfile, "\n\n\n====== NEW LOGFILE ====\n");
// cell types
addcelltype(CT_WALL, '#', B_SOLID, B_OPAQUE);
addcelltype(CT_ROOMWALL, '#', B_SOLID, B_OPAQUE);
addcelltype(CT_CORRIDOR, '.', B_EMPTY, B_TRANS);
addcelltype(CT_LOOPCORRIDOR, 'L', B_EMPTY, B_TRANS);
addcelltype(CT_ROOM, '.', B_EMPTY, B_TRANS);
addcelltype(CT_DOOROPEN, '-', B_EMPTY, B_TRANS);
addcelltype(CT_DOORCLOSED, '+', B_SOLID, B_OPAQUE);
initobjects();
initrace();
return B_FALSE;
}
@ -237,6 +458,10 @@ int isplayerturn(void) {
return B_FALSE;
}
float pctof(float pct, float num) {
return ((pct / 100.0) * num);
}
// get a random number between min and max
int rnd(int min, int max) {
int res;
@ -254,70 +479,220 @@ int rolldie(int ndice, int sides) {
return res;
}
// sort map's lifeform list by time spent
int rollhitdice(lifeform_t *lf) {
flag_t *f;
int ndice, plus;
int roll;
f = hasflag(lf->flags, F_HITDICE);
if (f) {
ndice = f->val[0];
if (f->val[1] == NA) plus = 0;
else plus = f->val[1];
} else {
ndice = 1;
plus = 0;
}
roll = rolldie(ndice, 4) + plus;
return roll;
}
int rollmpdice(lifeform_t *lf) {
flag_t *f;
int ndice, plus;
int roll;
f = hasflag(lf->flags, F_MPDICE);
if (f) {
ndice = f->val[0];
if (f->val[1] == NA) plus = 0;
else plus = f->val[1];
} else {
return 0;
}
roll = rolldie(ndice, 4) + plus;
return roll;
}
/*
void sortlf(map_t *map) {
int donesomething;
lifeform_t *l;
int adjustby;
int db = B_TRUE;
int db = B_FALSE;
lifeform_t *l,*nextl;
int iter = 0;
// bubblesort
/*
donesomething = B_TRUE;
dblog("doing sort...");
while (donesomething) {
donesomething = B_FALSE;
//dblog("ITER %d",iter++);
if (db) {
dblog("BEFORE sortlf():");
dblog("ITER %d",iter++);
for (l = map->lf ; l ; l = l->next) {
dblog("- %s (timespent= %d) (sorted=%d)", (l == player) ? "player" : l->race->name, l->timespent,l->sorted);
}
}
*/
donesomething = B_TRUE;
while (donesomething) {
donesomething = B_FALSE;
for (l = map->lf ; l ; l = l->next) {
if (!l->sorted && l->next && (l->timespent > l->next->timespent) ) {
for (l = map->lf ; l->next ; l = nextl) {
nextl = l->next;
//if (!l->sorted && (l->timespent >= l->next->timespent) ) {
if (l->sorted) {
//dblog("skipping id %d %s, already sorted ",l->id, l->race->name);
continue;
}
if (l->timespent >= l->next->timespent) {
lifeform_t *temp;
//dblog("moving id %d %s upwards",l->id, l->race->name);
// remember next element
temp = l->next;
// remove this element from list
// don't bother checking if (l->next == NULL) as we know
// this won't be true due to the for loop condition
if (l->prev == NULL) {
// first
map->lf = l->next;
l->next->prev = NULL;
} else {
// not first
l->prev->next = l->next;
}
// don't bother checking for next - we know ther eis one.
l->next->prev = l->prev;
}
// TESTING: re-add at correct position.
while (temp->next && (temp->next->timespent <= l->timespent)) {
//dblog("moving past %d %s (timespend=%d)...",temp->next->id, temp->next->race->name, temp->next->timespent);
temp = temp->next;
}
// re-add element afterwards
l->next = temp->next;
l->prev = temp;
temp->next = l;
if (l->next == NULL) map->lastlf = l;
if (l->next == NULL) {
map->lastlf = l;
} else {
l->next->prev = l;
}
l->sorted = B_TRUE;
donesomething = B_TRUE;
break;
} else {
l->sorted = B_TRUE;
}
}
}
//dblog("finished sort.");
// reset sorted var for next time
for (l = map->lf ; l->next ; l = l->next) {
l->sorted = B_FALSE;
}
// sanity check
if (player->next) {
assert(player->next->prev == player);
}
if (player->prev) {
assert(player->prev->next == player);
}
if (db) {
dblog("AFTER SORT:");
for (l = map->lf ; l ; l = l->next) {
if (haslos(player, l->cell)) {
// if (haslos(player, l->cell)) {
dblog("- %s (timespent= %d) (sorted=%d)", (l == player) ? "player" : l->race->name, l->timespent,l->sorted);
// }
}
}
}
*/
void timeeffectsworld(map_t *map) {
lifeform_t *l;
int db = B_TRUE;
object_t *o,*nexto;
int x,y;
long firstlftime;
// now go through the list and make the first element be 0
adjustby = map->lf->timespent;
l = map->lf;
if (l) {
// if (db) dblog("first lf is: %s (id %ld)\n",l->race->name, l->id);
firstlftime = l->timespent;
assert(firstlftime >= 0);
} else {
dblog("no lifeforms on map!\n");
// no first lf!
firstlftime = 0;
}
//if (db) dblog("timespent = %d\n", timespent);
dblog("firstlftime = %d\n", firstlftime);
if (firstlftime > 0) {
dblog("making firstlf timespent = 0 (currently %d):", firstlftime);
//dumplf();
for (l = map->lf ; l ; l = l->next) {
l->timespent -= adjustby;
l->sorted = B_FALSE;
//dblog("shuffling id %d %s timespent=%d -> %d",l->id,l->race->name, l->timespent, l->timespent - firstlftime);
l->timespent -= firstlftime;
assert(l->timespent >= 0);
if (isplayer(l)) {
statdirty = B_TRUE;
}
}
//dblog("after shuffle:");
//dumplf();
} else {
dblog("firstlf timespent is not greater than 0. no shuffle.");
}
timeleft += firstlftime;
// now do effects based on time...
while (timeleft >= TICK_INTERVAL) {
timeleft -= TICK_INTERVAL;
// global time-based effects on map or map objects
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
cell_t *c;
c = getcellat(map, x, y);
if (c) {
// go through each object in the cell...
for (o = c->obpile->first ; o ; o = nexto) {
nexto = o->next;
timeeffectsob(o);
} // end foreach object here
}
}
} // end for (y...
// now handle effects on lifeforms and/or their objects
for (l = map->lf ; l ; l = l->next) {
timeeffectslf(l);
for (o = l->pack->first ; o ; o = nexto) {
nexto = o->next;
timeeffectsob(o);
}
}
//dblog("AFTER SORT AND ADJUST.....");
//dumplf();
} // end if timespent
// inc game time
curtime += firstlftime;
if (db) dblog("cur time is %ld\n",curtime);
}

11
nexus.h
View File

@ -1,14 +1,19 @@
#include "defs.h"
celltype_t *addcelltype(int id, char glyph, int solid, int transparent);
celltype_t *addcelltype(int id, char *name, char glyph, int solid, int transparent, enum MATERIAL mat);
void checkdeath(void);
void checkendgame(void);
void cleanup(void);
void doeffects(void);
void donextturn(map_t *map);
celltype_t *findcelltype(int id);
char *getdirname(int dir);
void getrarity(int depth, int *min, int *max, int range);
int init(void);
int isplayerturn(void);
float pctof(float pct, float num);
int rnd(int min, int max);
int rolldie(int ndice, int sides);
void sortlf(map_t *map);
int rollhitdice(lifeform_t *lf);
int rollmpdice(lifeform_t *lf);
//void sortlf(map_t *map);
void timeeffectsworld(map_t *map);

9
object_ideas.txt Normal file
View File

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

5897
objects.c

File diff suppressed because it is too large Load Diff

100
objects.h
View File

@ -2,57 +2,151 @@
#define __OBJECTS_H
#include "defs.h"
object_t *addemptyob(obpile_t *where, object_t *o);
knowledge_t *addknowledge(enum OBCLASS id, char *hiddenname, int known);
material_t *addmaterial(enum MATERIAL id, char *name);
material_t *addmaterial(enum MATERIAL id, char *name, float weightrating);
objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph);
object_t *addob(obpile_t *where, char *name);
object_t *addobject(obpile_t *where, char *name, int canstack);
obpile_t *addobpile(lifeform_t *owner, cell_t *where);
objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid);
void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat);
void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype);
//void adjustprice(objecttype_t *ot, float *price );
void appendinscription(object_t *o, char *text);
int blessob(object_t *o);
void brightflash(cell_t *centre, int range, lifeform_t *immunelf);
object_t *canstackob(obpile_t *op, object_t *match);
object_t *canstacknewot(obpile_t *op, objecttype_t *match);
int changemat(object_t *o, enum MATERIAL mat);
void copyobprops(object_t *dst, object_t *src);
int countnames(char **list);
int countobs(obpile_t *op);
int curseob(object_t *o);
void damageallobs(object_t *exception, obpile_t *op, int howmuch, int damtype);
void explodeob(object_t *o, flag_t *f, int bigness);
void extinguish(object_t *o);
material_t *findmaterial(int id);
objectclass_t *findoc(int id);
object_t *findobl(obpile_t *op, char let); // find object by letter
objecttype_t *findot(enum OBTYPE id);
objecttype_t *findotn(char *name); // find objecttype by name
void genhiddennames(void);
int getcharges(object_t *o);
int geteffecttime(int min, int max, enum BLESSTYPE isblessed);
int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt);
int getobaccuracy(object_t *wep);
int getobvalue(object_t *o);
//int getobtypevalue(objecttype_t *ot);
char *getaccuracyname(int accpct);
object_t *getammo(lifeform_t *lf);
object_t *getrandomammo(lifeform_t *lf);
char *getdamname(enum DAMTYPE damtype);
char *getdamnamenoun(enum DAMTYPE damtype);
char *getfillingname(int nutrition);
int getfirearmrange(object_t *o);
int getfirearmspeed(object_t *o);
char getglyph(object_t *o);
char *genhiddenname(enum OBCLASS id);
char *gethiddenname(object_t *o);
int getobattackspeed(object_t *o);
int getletindex(char let);
int getmaterialvalue(enum MATERIAL mat );
int getmaxthrowrange(lifeform_t *lf, object_t *o);
char getnextletter(obpile_t *op, char *wantletter);
int getnumshards(object_t *o);
int getnutritionbase(object_t *o);
int getnutrition(object_t *o);
char *getobdesc(object_t *o, char *buf);
cell_t *getoblocation(object_t *o);
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);
float getobpileweight(obpile_t *op);
char *getobconditionname(object_t *o, char *buf);
char *getobhurtname(object_t *o, enum DAMTYPE damtype);
float getobweight(object_t *o);
float getobunitweight(object_t *o);
objecttype_t *getoppositestairs(objecttype_t *ot);
char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth);
char *getrandomob(map_t *map, char *buf);
char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf);
char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf);
char *getschoolname(enum SPELLSCHOOL sch);
int getshatterdam(object_t *o);
int getthrowdam(object_t *o);
int hasedibleob(obpile_t *op);
object_t *hasknownob(obpile_t *op, enum OBTYPE oid);
object_t *hasob(obpile_t *op, enum OBTYPE oid);
object_t *hasobofclass(obpile_t *op, enum OBCLASS cid);
object_t *hasobmulti(obpile_t *op, enum OBTYPE *oid, int noids);
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 *hasobid(obpile_t *op, int id);
void identify(object_t *o);
void initobjects(void);
flag_t *isarmour(object_t *o);
int isactivated(object_t *o);
int isammofor(object_t *ammo, object_t *gun);
int isbetterarmourthan(object_t *a, object_t *b);
int isbetterwepthan(object_t *a, object_t *b);
int isblessed(object_t *o);
int isblessknown(object_t *o);
int iscorpse(object_t *o);
int iscursed(object_t *o);
int isdrinkable(object_t *o);
int isedible(object_t *o);
flag_t *isequipped(object_t *o);
int isequippedon(object_t *o, enum BODYPART bp);
int isfirearm(object_t *o);
int isflammable(object_t *o);
int isknown(object_t *o);
int isidentified(object_t *o);
int ismetal(enum MATERIAL mat);
int ismissile(object_t *o);
int isoperable(object_t *o);
int isplainob(object_t *o);
int ispourable(object_t *o);
int ispushable(object_t *o);
int isreadable(object_t *o);
int isrotting(object_t *o);
int isweapon(object_t *o);
int iswearable(object_t *o);
void killmaterial(material_t *m);
void killob(object_t *o);
void killobpile(obpile_t *o);
void killoc(objectclass_t *oc);
void killot(objecttype_t *ot);
lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level);
void makeknown(enum OBTYPE otid);
object_t *moveob(object_t *src, obpile_t *dst, int howmany);
object_t *newobeffects(object_t *o);
void obaction(object_t *o, char *text);
object_t *obexists(enum OBTYPE obid);
void obdie(object_t *o);
int obfits(object_t *o, obpile_t *op);
enum DAMTYPE oblastdamtype(object_t *o);
flag_t *obproduceslight(object_t *o);
int obpropsmatch(object_t *a, object_t *b);
int obotpropsmatch(object_t *a, objecttype_t *b);
int operate(lifeform_t *lf, object_t *o);
int pilehasletter(obpile_t *op, char let);
void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE isblessed, int *seen);
int pour(lifeform_t *lf, object_t *o);
void quaff(lifeform_t *lf, object_t *o);
void read(lifeform_t *lf, object_t *o);
void readsomething(lifeform_t *lf, object_t *o);
void removedeadobs(obpile_t *op);
int removeob(object_t *o, int howmany);
object_t *relinkob(object_t *src, obpile_t *dst);
void throwat(lifeform_t *thrower, object_t *o, cell_t *where);
void setblessed(object_t *o, enum BLESSTYPE wantbless);
void setinscription(object_t *o, char *text);
object_t *splitob(object_t *o);
int takedamage(object_t *o, unsigned int howmuch, int damtype);
int fireat(lifeform_t *thrower, object_t *o, cell_t *where, int speed, object_t *firearm);
void timeeffectsob(object_t *o);
void turnoff(lifeform_t *lf, object_t *o);
void turnon(lifeform_t *lf, object_t *o);
int usecharge(object_t *o);
int validateobs(void);
int willshatter(enum MATERIAL mat);
#endif

208
save.c
View File

@ -3,7 +3,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "defs.h"
#include "flag.h"
#include "io.h"
#include "lf.h"
#include "map.h"
#include "move.h"
@ -11,6 +14,8 @@
#include "objects.h"
#include "save.h"
extern long curtime;
extern lifeform_t *player;
extern map_t *firstmap;
extern knowledge_t *knowledge;
@ -20,8 +25,6 @@ int loading = B_FALSE;
int loadall(void) {
DIR *dir;
struct dirent *ent;
char *filename;
FILE *f;
loading = B_TRUE;
@ -52,6 +55,42 @@ int loadall(void) {
return B_FALSE;
}
int loadflagpile(FILE *f, flagpile_t *fp) {
flag_t tempflag;
flag_t *fl;
char buf[BUFLEN];
int rv;
int db = B_TRUE;
rv = fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%ld\n",
&tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2],&tempflag.lifetime, &tempflag.known,&tempflag.obfrom);
while (tempflag.id != -1) {
dblog("got flag id=%d\n",tempflag.id);
// get flag text
fgets(buf, BUFLEN, f);
buf[strlen(buf)-1] = '\0'; // strip newline
fl = addflag_real(fp, tempflag.id,
tempflag.val[0],
tempflag.val[1],
tempflag.val[2], strcmp(buf, "^^^") ? buf : NULL, tempflag.lifetime, tempflag.known);
fl->obfrom = tempflag.obfrom;
if (db) {
dblog("--> added flag id=%d. v0=%d, v1=%d, v2=%d, text=%s, lifetime=%d, known=%d, obfrom=%ld\n",fl->id,
fl->val[0], fl->val[1], fl->val[2], fl->text ? fl->text : "(null)", fl->lifetime, fl->known,fl->obfrom);
}
// load next one
rv = fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%ld\n",
&tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2],&tempflag.lifetime, &tempflag.known,&tempflag.obfrom);
//dblog("fscanf returned %d\n",rv);
}
return B_FALSE;
}
int loadknowledge(FILE *f) {
int db = B_FALSE;
char buf[BUFLEN];
@ -74,6 +113,16 @@ int loadknowledge(FILE *f) {
return B_FALSE;
}
int loadvars(FILE *f) {
int db = B_FALSE;
if (db) dblog("--> Loading knowledge...\n");
fscanf(f, "startvars\n");
fscanf(f, "curtime:%ld\n",&curtime);
fscanf(f, "endvars\n");
return B_FALSE;
}
// load and allocate one lifeform from given file
lifeform_t *loadlf(FILE *f, cell_t *where) {
lifeform_t *l;
@ -117,9 +166,15 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
l->y = y;
// load rest of this lf
fscanf(f, "str: %d/%d\n",&l->att[A_STR],&l->baseatt[A_STR]);
fscanf(f, "dex: %d/%d\n",&l->att[A_DEX],&l->baseatt[A_DEX]);
fscanf(f, "int: %d/%d\n",&l->att[A_IQ],&l->baseatt[A_IQ]);
fscanf(f, "xp: %ld\n",&l->xp);
fscanf(f, "contr: %d\n",&l->controller);
fscanf(f, "hp: %d/%d\n",&l->hp, &l->maxhp);
fscanf(f, "mp: %d/%d\n",&l->mp, &l->maxmp);
fscanf(f, "alive: %d\n",&l->alive);
fscanf(f, "lastdamtype: %d\n",(int *)&l->lastdamtype);
fgets(buf, BUFLEN, f); // lastdam
buf[strlen(buf)-1] = '\0'; // strip newline
@ -128,9 +183,15 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
fscanf(f, "timespent: %d\n",&l->timespent);
fscanf(f, "sorted: %d\n",&l->sorted);
fscanf(f, "polyrevert: %d\n",&l->polyrevert);
fscanf(f, "forgettimer: %f\n",&l->forgettimer);
if (db) dblog("--> Got hp=%d/%d. timespend=%d. sorted=%d. Now loading ob list.",l->hp,l->maxhp,l->timespent,l->sorted);
if (db) dblog("--> Got hp=%d/%d. timespend=%d. sorted=%d. Now loading flags.",l->hp,l->maxhp,l->timespent,l->sorted);
// lf flags
loadflagpile(f, l->flags);
if (db) dblog("--> now loading objects");
// load object list
obcount = 0;
@ -165,6 +226,9 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
if (l->controller == C_PLAYER) {
player = l;
}
sortlf(l->cell->map, l);
return l;
}
@ -173,13 +237,12 @@ map_t *loadmap(char *basefile) {
FILE *f;
char filename[BUFLEN];
char buf[BUFLEN];
char buf2[BUFLEN];
int obcount;
int i;
int x,y;
int db = B_TRUE;
lifeform_t *l;
object_t *o,*nexto;
object_t *o;
map_t *m;
cell_t *dummycell;
@ -202,13 +265,13 @@ map_t *loadmap(char *basefile) {
// load map info
if (db) dblog("--> Loading map info...\n");
fscanf(f, "id:%d\n",&m->id); // map id
fscanf(f, "depth:%d\n",&m->depth); // map depth
fgets(buf, BUFLEN, f); // map name
buf[strlen(buf)-1] = '\0'; // strip newline
m->name = strdup(buf + 5); // after 'name:'
fscanf(f, "habitat:%d\n",(int *)&m->habitat); // habitat
fscanf(f, "seed:%d\n",&m->seed); // seed
fscanf(f, "dims:%d,%d\n",&m->w, &m->h); // map dimensons
fscanf(f, "nextlfid:%ld\n",&m->nextlfid);
fscanf(f, "nextmaps:\n");
for (i = 0; i < MAXDIR_ORTH; i++) {
fscanf(f, "%d\n",&m->nextmap[i]); // map dimensons
@ -253,8 +316,8 @@ map_t *loadmap(char *basefile) {
*/
// cell info
fscanf(f, "%d,%d,%d,%d\n",
&c->roomid, &celltypeid, &c->known, &c->visited);
fscanf(f, "%d,%d,%d,%d,%d\n",
&c->roomid, &celltypeid, &c->known, &c->visited, &c->lit);
ct = findcelltype(celltypeid);
@ -286,7 +349,6 @@ map_t *loadmap(char *basefile) {
// create all objects in a dummy cell
for (i = 0; i < obcount; i++) {
int n;
long thisid;
if (db) dblog("-----> loading into dummycell: mapob %d/%d...\n",i+1,obcount);
if (loadob(f, dummycell->obpile, &thisid)) {
@ -398,9 +460,6 @@ int loadob(FILE *f, obpile_t *op, long *id) {
long obid;
int otid,matid;
char buf[BUFLEN];
int flagid;
flag_t tempflag;
int rv;
int db = B_TRUE;
fscanf(f, "id:%ld\n",&obid);
@ -413,7 +472,7 @@ int loadob(FILE *f, obpile_t *op, long *id) {
ot = findot(otid);
if (!ot) {
dblog("ERROR loading objects - can't find obtype id %ld\n",obid);
dblog("ERROR loading objects - can't find obtype id %d (obj id %ld)\n",otid,obid);
return B_TRUE;
}
// create the object
@ -442,29 +501,20 @@ int loadob(FILE *f, obpile_t *op, long *id) {
fscanf(f, "bless:%d\n",&o->blessed);
fscanf(f, "blessknown:%d\n",&o->blessknown);
fscanf(f, "amt:%d\n",&o->amt);
fscanf(f, "birthtime:%ld\n",&o->birthtime);
// now remove ALL obejct flags (which were inherited
// from the obtype during addobject() ). these will be
// loaded in instead.
while (o->flags->first) {
killflag(o->flags->first);
}
fscanf(f, "flags:\n");
dblog("About to start loading object flags...");
rv = fscanf(f, "%d,%d,%d,%d,%d\n",
&tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2]);
while (tempflag.id != -1) {
dblog("got flag id=%d\n",tempflag.id);
// get flag text
fgets(buf, BUFLEN, f);
buf[strlen(buf)-1] = '\0'; // strip newline
addflag(o->flags, tempflag.id,
tempflag.val[0],
tempflag.val[1],
tempflag.val[2], strcmp(buf, "^^^") ? buf : NULL);
// load next one
rv = fscanf(f, "%d,%d,%d,%d,%d\n",
&tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2]);
//dblog("fscanf returned %d\n",rv);
}
loadflagpile(f, o->flags);
fscanf(f, "endob\n");
return B_FALSE;
}
@ -504,6 +554,10 @@ int loadsavegame(void) {
printf("Error loading knowledge from file '%s'",ent->d_name);
exit(1);
}
if (loadvars(f)) {
printf("Error loading game variables from file '%s'",ent->d_name);
exit(1);
}
fclose(f);
// successful load - kill the savegame now
@ -512,14 +566,38 @@ int loadsavegame(void) {
}
}
closedir(dir);
return B_FALSE;
}
int savevars(FILE *f) {
int db = B_FALSE;
if (db) dblog("--> Saving knowledge...\n");
fprintf(f, "startvars\n");
fprintf(f, "curtime:%ld\n",curtime);
fprintf(f, "endvars\n");
return B_FALSE;
}
int saveflagpile(FILE *f, flagpile_t *fp) {
flag_t *fl;
fprintf(f, "flags:\n");
for (fl = fp->first ; fl ; fl = fl->next) {
fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%ld\n",
fl->id, fl->nvals, fl->val[0], fl->val[1], fl->val[2],fl->lifetime,fl->known,fl->obfrom);
if (!fl->text || !strcmp(fl->text, "")) {
fprintf(f, "%s\n","^^^");
} else {
fprintf(f, "%s\n",fl->text);
}
}
fprintf(f, "-1,-1,-1,-1,-1,-1,-1,-1\n");
return B_FALSE;
}
int saveknowledge(FILE *f) {
int db = B_FALSE;
char buf[BUFLEN];
int otid,known;
char hiddenname[BUFLEN];
knowledge_t *k;
if (db) dblog("--> Saving knowledge...\n");
fprintf(f, "startknowledge\n");
@ -542,14 +620,25 @@ int savelf(FILE *f, lifeform_t *l) {
fprintf(f, "map: %d\n",l->cell->map->id);
fprintf(f, "pos: %d,%d\n",l->cell->x, l->cell->y);
fprintf(f, "level: %d\n",l->level);
// liefform will be cfeated after loading the above.
// liefform will be created after loading the above.
fprintf(f, "str: %d/%d\n",l->att[A_STR],l->baseatt[A_STR]);
fprintf(f, "dex: %d/%d\n",l->att[A_DEX],l->baseatt[A_DEX]);
fprintf(f, "int: %d/%d\n",l->att[A_IQ],l->baseatt[A_IQ]);
fprintf(f, "xp: %ld\n",l->xp);
fprintf(f, "contr: %d\n",l->controller);
fprintf(f, "hp: %d/%d\n",l->hp, l->maxhp);
fprintf(f, "mp: %d/%d\n",l->mp, l->maxmp);
fprintf(f, "alive: %d\n",l->alive);
fprintf(f, "lastdamtype: %d\n",l->lastdamtype);
fprintf(f, "lastdam: %s\n",l->lastdam);
fprintf(f, "timespent: %d\n",l->timespent);
fprintf(f, "sorted: %d\n",l->sorted);
fprintf(f, "polyrevert: %d\n",l->polyrevert);
fprintf(f, "forgettimer: %f\n",l->forgettimer);
// lf flags
saveflagpile(f, l->flags);
// lifeform objects
obcount = 0;
for (o = l->pack->first ; o ; o = o->next) {
@ -568,6 +657,33 @@ int savelf(FILE *f, lifeform_t *l) {
return B_FALSE;
}
int savegame(void) {
map_t *m;
FILE *f;
char buf[BUFLEN];
int rv;
for (m = firstmap; m ; m = m->next) {
// save world
rv = savemap(m);
if (rv) {
msg("Could not save map '%s'",m->name);
return B_TRUE;
}
// save player + their objects
sprintf(buf, "%s/game.sav",SAVEDIR);
f = fopen(buf, "wt");
if (!f) {
msg("Could not open save file!");
return B_TRUE;
}
savelf(f, player);
saveknowledge(f);
savevars(f);
fclose(f);
}
return B_FALSE;
}
int savemap(map_t *m) {
FILE *f;
@ -584,11 +700,11 @@ int savemap(map_t *m) {
// save map info
fprintf(f, "id:%d\n",m->id); // map id
fprintf(f, "depth:%d\n",m->depth); // map depth
fprintf(f, "name:%s\n",m->name); // map name
fprintf(f, "habitat:%d\n",m->habitat); // habitat
fprintf(f, "seed:%d\n",m->seed); // seed
fprintf(f, "dims:%d,%d\n",m->w, m->h); // map dimensons
fprintf(f, "nextlfid:%ld\n",m->nextlfid);
fprintf(f, "nextmaps:\n");
for (i = 0; i < MAXDIR_ORTH; i++) {
fprintf(f, "%d\n",m->nextmap[i] ); // map dimensons
@ -610,8 +726,8 @@ int savemap(map_t *m) {
cell_t *c;
c = getcellat(m, x, y);
// cell info
fprintf(f, "%d,%d,%d,%d\n",
c->roomid, c->type->id, c->known, c->visited);
fprintf(f, "%d,%d,%d,%d,%d\n",
c->roomid, c->type->id, c->known, c->visited,c->lit);
// cell objects
for (o = c->obpile->first ; o ; o = o->next) {
fprintf(f, "ob:%ld\n",o->id);
@ -641,7 +757,6 @@ int savemap(map_t *m) {
int saveob(FILE *f, object_t *o) {
flag_t *fl;
fprintf(f, "id:%ld\n",o->id);
fprintf(f, "type:%d\n",o->type->id);
fprintf(f, "material:%d\n",o->material->id);
@ -651,17 +766,8 @@ int saveob(FILE *f, object_t *o) {
fprintf(f, "bless:%d\n",o->blessed);
fprintf(f, "blessknown:%d\n",o->blessknown);
fprintf(f, "amt:%d\n",o->amt);
fprintf(f, "flags:\n");
for (fl = o->flags->first ; fl ; fl = fl->next) {
fprintf(f, "%d,%d,%d,%d,%d\n",
fl->id, fl->nvals, fl->val[0], fl->val[1], fl->val[2]);
if (!fl->text || !strcmp(fl->text, "")) {
fprintf(f, "%s\n","^^^");
} else {
fprintf(f, "%s\n",fl->text);
}
}
fprintf(f, "-1,-1,-1,-1,-1\n");
fprintf(f, "birthtime:%ld\n",o->birthtime);
saveflagpile(f, o->flags);
fprintf(f, "endob\n");
return B_FALSE;
}

3
save.h
View File

@ -1,12 +1,15 @@
#include "defs.h"
int loadall(void);
int loadflagpile(FILE *f, flagpile_t *fp);
int loadknowledge(FILE *f);
lifeform_t *loadlf(FILE *f, cell_t *where);
map_t *loadmap(char *basefile);
int loadob(FILE *f, obpile_t *op, long *id);
int loadsavegame(void);
int saveflagpile(FILE *f, flagpile_t *fp);
int saveknowledge(FILE *f);
int savelf(FILE *f, lifeform_t *l);
int savegame(void);
int savemap(map_t *m);
int saveob(FILE *f, object_t *o);

1800
spell.c

File diff suppressed because it is too large Load Diff

10
spell.h
View File

@ -2,7 +2,13 @@
#define __SPELLS_H
#include "defs.h"
void dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target);
int abilityeffects(lifeform_t *user, enum OBTYPE abilid);
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);
int getmpcost(enum OBTYPE oid);
void pullobto(object_t *o, lifeform_t *lf);
cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlof);
lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf);
#endif

281
text.c
View File

@ -1,14 +1,131 @@
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "defs.h"
#include "lf.h"
#include "objects.h"
#include "text.h"
extern long curtime;
char *capitalise(char *text) {
if (strlen(text) > 0) {
text[0] = toupper(text[0]);
}
return text;
}
char *getattrname(enum ATTRIB att) {
switch (att) {
case A_STR:
return "strength";
case A_IQ:
return "intelligence";
case A_DEX:
return "dexterity";
default:
break;
}
return "?unknown?";
}
char *getpossessive(char *text) {
char lastchar;
// you -> your
if (!strcmp(text, "you")) {
return "r";
}
// xxxs -> xxxs'
lastchar = text[strlen(text)-1];
if (tolower(lastchar) == 's') {
return "'";
}
// default: 's
return "'s";
}
char *getsizetext(enum LFSIZE sz) {
switch (sz) {
case SZ_ENORMOUS:
return "enormous";
case SZ_HUGE:
return "huge";
case SZ_LARGE:
return "large";
case SZ_HUMAN:
return "human-sized";
case SZ_MEDIUM:
return "medium";
case SZ_SMALL:
return "small";
case SZ_MINI:
case SZ_TINY:
return "extremely small";
default:
return "unknown-sized";
}
return "unknown-sized";
}
char *gettimetext(char *retbuf) {
int hours,mins,secs;
splittime(&hours, &mins, &secs);
sprintf(retbuf, "%02d:%02d:%02d",hours,mins,secs);
return retbuf;
}
char *gettimetextfuzzy(char *retbuf, int wantpm) {
int hours,mins,secs;
int pm = B_FALSE;
splittime(&hours, &mins, &secs);
if (hours > 12) {
hours -= 12;
pm = B_TRUE;
}
if (mins == 0) {
sprintf(retbuf, "exactly %d o'clock", hours);
} else if (mins <= 15) {
sprintf(retbuf, "a little after %d o'clock", hours);
} else if (mins <= 25) {
sprintf(retbuf, "nearly half past %d", hours);
} else if (mins <= 35) {
sprintf(retbuf, "around half past %d", hours);
} else if (mins <= 45) {
sprintf(retbuf, "comung up to %d o'clock", (hours == 12) ? 1 : (hours+1));
} else {
sprintf(retbuf, "nearly %d o'clock", (hours == 12) ? 1 : (hours+1));
}
if (wantpm) {
strcat(retbuf, " in the ");
if (pm) {
strcat(retbuf, "afternoon");
} else {
strcat(retbuf, "morning");
}
}
return retbuf;
}
char *getweighttext(float weight, char *buf) {
if (weight >= 1) {
if ((int)weight == weight) { // ie. is weight an integer?
sprintf(buf, "%0.0f kg",weight);
} else {
sprintf(buf, "%0.1f kg",weight);
}
} else {
sprintf(buf, "%0.0f grams", weight * 1000);
}
return buf;
}
int isvowel (char c) {
switch (c) {
case 'a':
@ -23,23 +140,47 @@ int isvowel (char c) {
// allocates and returns new string
char *makeplural(char *text) {
int newlen;
char lastlet;
char *newtext;
char *p;
int rv;
newtext = strdup(text);
// scrolls
rv = strrep(newtext, "scroll ", "scrolls ");
newtext = strrep(newtext, "berry ", "berries ", &rv);
if (rv) return newtext;
rv = strrep(newtext, "potion ", "potions ");
newtext = strrep(newtext, "block ", "blocks ", &rv);
if (rv) return newtext;
rv = strrep(newtext, "piece ", "pieces ");
newtext = strrep(newtext, "can ", "cans ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "chunk ", "chunks ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "gem ", "gems ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "loaf ", "loaves ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "lump ", "lumps ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "piece ", "pieces ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "pile ", "piles ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "pool ", "pools ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "potion ", "potions ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "puddle ", "puddles ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "ring ", "rings ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "scroll ", "scrolls ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "vial ", "vials ", &rv);
if (rv) return newtext;
rv = strrep(newtext, "pair ", "pairs ");
//
newtext = strrep(newtext, "pair ", "pairs ", &rv);
// don't return
// default
@ -56,27 +197,50 @@ char *makeplural(char *text) {
return newtext;
}
int strrep(char *text, char *oldtok, char *newtok) {
char *noprefix(char *obname) {
char *p;
p = strchr(obname, ' ');
if (p) {
p++;
return p;
} else {
return obname;
}
}
void splittime(int *hours, int *mins, int *secs) {
long left;
left = curtime;
*hours = left / 3600;
left -= (*hours * 3600);
*mins = left / 60;
left -= (*mins * 60);
*secs = left;
}
char *strrep(char *text, char *oldtok, char *newtok, int *rv) {
char *temp;
int rv;
temp = strdup(" ");
rv = dostrrep(text, &temp, oldtok, newtok);
temp = strdup(" "); // ooooooo is this bad??
dostrrep(text, &temp, oldtok, newtok, rv);
// swap
text = realloc(text, strlen(temp));
text = realloc(text, strlen(temp)+1); // extra space for NUL
strcpy(text, temp);
free(temp);
return rv;
return text;
}
// returns TRUE if any replacements made
int dostrrep(char* in, char** out, char* oldtok, char* newtok) {
char *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv) {
char *temp;
char *found = strstr(in, oldtok);
int idx;
if(!found) {
*out = realloc(*out, strlen(in) + 1);
*out = realloc(*out, strlen(in) + 1); // oooooooo crashing in realloc
strcpy(*out, in);
return B_FALSE;
if (rv) *rv = B_FALSE;
return *out;
}
idx = found - in;
@ -90,13 +254,96 @@ int dostrrep(char* in, char** out, char* oldtok, char* newtok) {
strncpy(temp,*out,idx+strlen(newtok));
temp[idx + strlen(newtok)] = '\0';
dostrrep(found + strlen(oldtok), out, oldtok, newtok);
dostrrep(found + strlen(oldtok), out, oldtok, newtok, rv);
temp = realloc(temp, strlen(temp) + strlen(*out) + 1);
strcat(temp,*out);
free(*out);
*out = temp;
return B_TRUE;
if (rv) *rv = B_TRUE;
return *out;
}
int strpixmatch(char *haystack, char *needle) {
int matched = B_FALSE;
char *hword, *nword, *hcont,*ncont;
if (strchr(needle, ' ') || strchr(haystack, ' ')) {
char lochaystack[BUFLEN], locneedle[BUFLEN];
strcpy(lochaystack, haystack);
strcpy(locneedle, needle);
// match word for word
nword = strtok_r(locneedle, " ", &ncont);
hword = strtok_r(lochaystack, " ", &hcont);
while (nword && hword) {
// all typed words must match
if (strcasestr(hword, nword)) {
matched = B_TRUE;
} else {
matched = B_FALSE;
break;
}
nword = strtok_r(NULL, " ", &ncont);
hword = strtok_r(NULL, " ", &hcont);
if (nword && !hword) {
matched = B_FALSE;
}
}
/*
if (!matched && !strchr(needle, ' ')) {
// now try matching typed word against second word in spellname
strcpy(lochaystack, haystack);
hword = strtok_r(lochaystack, " ", &hcont);
while (hword) {
if (strcasestr(hword, needle)) {
matched = B_TRUE;
break;
} else {
matched = B_FALSE;
}
hword = strtok_r(NULL, " ", &hcont);
if (!hword) {
matched = B_FALSE;
}
}
}
*/
} else {
if (strcasestr(haystack, needle)) {
matched = B_TRUE;
}
}
return matched;
}
char *you(lifeform_t *lf) {
if (isplayer(lf)) {
return "You";
}
return "It";
}
char *you_l(lifeform_t *lf) {
if (isplayer(lf)) {
return "you";
}
return "it";
}
char *your(lifeform_t *lf) {
if (isplayer(lf)) {
return "Your";
}
return "Its";
}
char *your_l(lifeform_t *lf) {
if (isplayer(lf)) {
return "your";
}
return "its";
}

18
text.h
View File

@ -1,8 +1,20 @@
#include "defs.h"
char *capitalise(char *text);
char *getattrname(enum ATTRIB att);
char *getpossessive(char *text);
char *getsizetext(enum LFSIZE sz);
char *gettimetext(char *retbuf);
char *gettimetextfuzzy(char *retbuf, int wantpm);
char *getweighttext(float weight, char *buf);
int isvowel(char c);
char *makeplural(char *text);
int strrep(char *text, char *oldtok, char *newtok);
int dostrrep(char* in, char** out, char* oldtok, char* newtok);
char *noprefix(char *obname);
void splittime(int *hours, int *mins, int *secs);
char *strrep(char *text, char *oldtok, char *newtok, int *rv);
char *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv);
int strpixmatch(char *haystack, char *needle);
char *you(lifeform_t *lf);
char *you_l(lifeform_t *lf);
char *your(lifeform_t *lf);
char *your_l(lifeform_t *lf);