- Fixed heaps of memory leaks and bad memory usage. This should finally fix the flagpile corruption from 6 years ago!

- forgot to initialise brand->description
- door displaying as "leaf" - definition of knowledge->id was OBCLASS instead of OBTYPE.
- Repeated text:
        Minimum agility to use effectively: 50 to use.Minimum agility to use
        effectively: 50 to use. (bonus at 70).
- change wish text to be more meaningful
- fix failure when loading objects with a bonus from vaults/bones (eg. blessed '+5' sword)
- when raging, don't prompt to really attack when you won't gain xp
- disable flagpile checks
- Use 'interact' to use shops, not 'operate'
- Bad text: You are resistant to: projectiles[-7870t], explosives[-7870t].
- scorpions shouldn't follow you up stairs. (but giant scorpions can)
- make failed relinkob() calls return the original object rather than null, otherwise we get situations where an object becomes NULL and causes a crash.
- make cooking skill description show what size corpses you can cook.
- bug: potion of growth caused instadeath when reverting.
- bug: not showing monster abilites properly
- show raceclass in descriptions (/ v)
- make evasion only work if you're not exhausted
- Felix should be pleased by attacking people while hidden
- Not seeing felix angered messages when donating items
- Holes in roof - you now need to climb to inspect them.
- Fixed crash when hitting @ while producing light.
This commit is contained in:
Robert Pearce 2016-05-31 00:21:12 +10:00
parent 2f80d6ba05
commit e9a2ccb2c8
28 changed files with 1012 additions and 345 deletions

View File

@ -1,62 +1,62 @@
#all: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h data.c data.h flag.c flag.h god.c god.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 shops.c shops.h spell.c spell.h vault.c vault.h
# gcc -Wall -g -pg -o nexus nexus.c ai.c attack.c data.c flag.c god.c io.c lf.c map.c move.c objects.c text.c save.c spell.c shops.c vault.c -lncurses -lsqlite3
# gcc -Werror -Wall -g -pg -o nexus nexus.c ai.c attack.c data.c flag.c god.c io.c lf.c map.c move.c objects.c text.c save.c spell.c shops.c vault.c -lncurses -lsqlite3
nexus: ai.o astar.o attack.o data.o findleak.o flag.o god.o io.o lf.o map.o move.o nexus.o objects.o save.o shops.o spell.o text.o vault.o ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h nexus.h objects.h save.h shops.h spell.h text.h vault.h
gcc -g -pg -Wall -o nexus ai.o astar.o attack.o data.o findleak.o flag.o god.o io.o lf.o map.o move.o nexus.o objects.o save.o shops.o spell.o text.o vault.o -lncurses -lsqlite3
nexus: ai.o astar.o attack.o data.o flag.o god.o io.o lf.o map.o move.o nexus.o objects.o save.o shops.o spell.o text.o vault.o ai.h attack.h data.h defs.h flag.h god.h io.h lf.h map.h move.h nexus.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -g -pg -Wall -o nexus ai.o astar.o attack.o data.o flag.o god.o io.o lf.o map.o move.o nexus.o objects.o save.o shops.o spell.o text.o vault.o -lncurses -lsqlite3
ai.o: ai.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h ai.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o ai.o ai.c
ai.o: ai.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h ai.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o ai.o ai.c
attack.o: attack.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h attack.h astar.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o attack.o attack.c
attack.o: attack.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h attack.h astar.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o attack.o attack.c
astar.o: astar.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h attack.h astar.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o astar.o astar.c
astar.o: astar.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h attack.h astar.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o astar.o astar.c
data.o: data.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h data.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o data.o data.c
data.o: data.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h data.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o data.o data.c
findleak.o: findleak.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h findleak.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o findleak.o findleak.c
: ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o
flag.o: flag.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h flag.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o flag.o flag.c
flag.o: flag.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h flag.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o flag.o flag.c
god.o: god.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h god.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o god.o god.c
god.o: god.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h god.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o god.o god.c
io.o: io.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h io.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o io.o io.c
io.o: io.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h io.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o io.o io.c
lf.o: lf.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h lf.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o lf.o lf.c
lf.o: lf.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h lf.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o lf.o lf.c
map.o: map.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h map.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o map.o map.c
map.o: map.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h map.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o map.o map.c
move.o: move.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h move.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o move.o move.c
move.o: move.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h move.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o move.o move.c
nexus.o: nexus.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h nexus.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o nexus.o nexus.c
nexus.o: nexus.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h nexus.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o nexus.o nexus.c
objects.o: objects.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h objects.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o objects.o objects.c
objects.o: objects.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h objects.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o objects.o objects.c
save.o: save.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h save.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o save.o save.c
save.o: save.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h save.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o save.o save.c
shops.o: shops.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h shops.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o shops.o shops.c
shops.o: shops.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h shops.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o shops.o shops.c
spell.o: spell.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h spell.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o spell.o spell.c
spell.o: spell.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h spell.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o spell.o spell.c
text.o: text.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h text.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o text.o text.c
text.o: text.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h text.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o text.o text.c
vault.o: vault.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h vault.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Wall -c -g -pg -o vault.o vault.c
vault.o: vault.c ai.h attack.h astar.h data.h defs.h flag.h god.h io.h lf.h map.h move.h vault.h objects.h save.h shops.h spell.h text.h vault.h
gcc -Werror -Wall -c -g -pg -o vault.o vault.c
######################

71
ai.c
View File

@ -1,4 +1,5 @@
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -190,6 +191,8 @@ flag_t *ai_createpathto(lifeform_t *lf, cell_t *targcell) {
char lfname[BUFLEN];
flag_t *newf;
checkflagpile(lf->flags); // debug
if (!db && lfhasflag(lf, F_DEBUG)) db = B_TRUE;
real_getlfname(lf, lfname, NULL, B_SHOWALL, B_CURRACE);
@ -353,6 +356,7 @@ if (db) dblog("%s pathfind - finding path from %d,%d to %d,%d\n",lfname, lf->cel
}
}
}
checkflagpile(lf->flags); // debug
// work backwards from node[cur] (ie. targcell) following parents.
// populate path and return
@ -366,10 +370,13 @@ if (db) dblog("%s pathfind - finding path from %d,%d to %d,%d\n",lfname, lf->cel
cur = cur->parent;
}
checkflagpile(lf->flags); // debug
pathbuf = malloc(pathlen*6*sizeof(char));
strcpy(pathbuf, "");
checkflagpile(lf->flags); // debug
for (i = pathlen-1; i >= 0 ; i--) {
char smallbuf[BUFLENTINY];
// don't include starting cell
@ -381,8 +388,10 @@ if (db) dblog("%s pathfind - finding path from %d,%d to %d,%d\n",lfname, lf->cel
}
if (db) dblog("* %s - path takes %d steps. ", lfname, pathlen);
if (db) dblog("* %s - pathbuf: [%s] ", lfname, pathbuf);
checkflagpile(lf->flags); // debug
newf = addflag(lf->flags, F_AIPATH, targcell->x, targcell->y, NA, pathbuf);
free(pathbuf);
checkflagpile(lf->flags); // debug
return newf;
}
@ -1701,8 +1710,8 @@ int ai_housekeeping(lifeform_t *lf, lifeform_t *master) {
int ai_inventory_mgt(lifeform_t *lf, int *canattack) {
int db = B_FALSE,i;
object_t *curwep,*bestwep, *o;
object_t *curgun,*bestgun;
object_t *curwep = NULL,*bestwep = NULL, *o = NULL;
object_t *curgun = NULL,*bestgun = NULL;
enum BODYPART bp;
int icanattack = B_FALSE;
enum ATTRBRACKET iqb;
@ -1746,7 +1755,6 @@ int ai_inventory_mgt(lifeform_t *lf, int *canattack) {
// do we have a better weapon we could use?
if (iqb >= AT_AVERAGE) {
curwep = getweapon(lf);
bestwep = getbestweapon(lf);
@ -1977,6 +1985,9 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
// see if we have a ranged attack. if so, adjust wantdist
// to maintain distance.
rangedob = aigetrangedattack(lf, target, &rangedattack, &shootrange);
// how far away is my target ?
dist = getcelldist(lf->cell, target->cell);
// try spells first.
// can we attack with spells (ie. ones which target the victim)?
@ -1986,6 +1997,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
f = lfhasflag(lf, F_CASTCHANCE);
if (f) spellchance = f->val[0];
else spellchance = 30;
// some attacks can always happen
if (cancast(lf, OT_A_THRUST, NULL) && (dist == 2) && haslofknown(lf->cell, target->cell, LOF_NEED, NULL)) {
@ -2013,8 +2025,6 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
// otherwise fall through to below movement code.
}
// how far away is my target ?
dist = getcelldist(lf->cell, target->cell);
// how far away do i _want_ to be?
getwantdistance(lf,target, &wantdistmin,&wantdistmax, wantattack);
@ -2345,10 +2355,14 @@ int aimovetotargetcell(lifeform_t *lf, flag_t *f) {
enum ATTRBRACKET iqb;
iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
checkflagpile_maplfs(lf->cell->map);
if (lfhasflag(lf, F_DEBUG)) {
db = B_TRUE;
}
checkflagpile(lf->flags); // debug
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);
@ -2401,16 +2415,22 @@ int aimovetotargetcell(lifeform_t *lf, flag_t *f) {
if (pathf && (lf->cell == c)) {
ai_popnextcellinpath(lf);
}
assert(f->id <= F_LAST);
// moved towards it.
// reset lifetime
f->lifetime = aigetchasetime(lf);
assert(f->id <= F_LAST);
// are we there yet?
if (lf->cell == targetc) {
enum MOVEREASON mr;
// yes. remove target cell
if (db) dblog(".oO { arrived at f_targetcell. removing. }");
if (f->val[2] == MR_LF) {
assert(f->id <= F_LAST);
mr = f->val[2];
if ((mr == MR_LF) && f->text) {
lifeform_t *targlf;
// if we were chasing someone, keep looking
// for them.
@ -2421,7 +2441,7 @@ int aimovetotargetcell(lifeform_t *lf, flag_t *f) {
}
}
killflag(f);
killflag(f);
} else {
if (!turned && (c != lf->cell)) {
turntoface(lf, c);
@ -2442,6 +2462,8 @@ int aimovetotargetcell(lifeform_t *lf, flag_t *f) {
// move randomly now.
dorandommove(lf, B_NOBADMOVES, B_TRUE, B_FALSE); // this function will call rest() if we cant move
}
checkflagpile(lf->flags); // debug
checkflagpile_maplfs(lf->cell->map);
// success
return B_TRUE;
}
@ -2516,8 +2538,7 @@ void aiturn(lifeform_t *lf) {
lifeform_t *master = NULL;
enum ATTRBRACKET iqb;
checkflagpile(lf->flags);
checkflagpile_maplfs(lf->cell->map);
/*
if (wantdb && haslos(player, lf->cell)) {
@ -2544,6 +2565,9 @@ void aiturn(lifeform_t *lf) {
if (isdead(lf)) {
if (db) dblog(".oO { i am not alive, skipping turn. }");
taketime(lf, SPEED_DEAD);
checkflagpile_maplfs(lf->cell->map);
return;
}
// if game has just started and player hasn't had their turn yet,
@ -2551,6 +2575,7 @@ void aiturn(lifeform_t *lf) {
if (!playerhasmoved) {
if (db) dblog(".oO { player hasn't had their initial turn yet, skipping turn. }");
taketime(lf, SPEED_DEAD);
checkflagpile_maplfs(lf->cell->map);
return;
}
@ -2566,14 +2591,19 @@ void aiturn(lifeform_t *lf) {
master = findlf(lf->cell->map, f->val[0]);
}
checkflagpile_maplfs(lf->cell->map);
ailoscheck(lf);
checkflagpile_maplfs(lf->cell->map);
///////////////////////////////////////////////
// emergencies / fixing up
///////////////////////////////////////////////
if (ai_handle_emergencies(lf, iqb)) return;
checkflagpile_maplfs(lf->cell->map);
ailoscheck(lf);
///////////////////////////////////////////////
@ -2589,6 +2619,8 @@ void aiturn(lifeform_t *lf) {
///////////////////////////////////////////////
if (ai_healing(lf)) return;
checkflagpile_maplfs(lf->cell->map);
ailoscheck(lf);
///////////////////////////////////////////////
@ -2596,6 +2628,7 @@ void aiturn(lifeform_t *lf) {
///////////////////////////////////////////////
if (ai_inventory_mgt(lf, &icanattack)) return;
checkflagpile_maplfs(lf->cell->map);
ailoscheck(lf);
///////////////////////////////////////////////
@ -2603,6 +2636,7 @@ void aiturn(lifeform_t *lf) {
///////////////////////////////////////////////
if (ai_attack_existing_target(lf)) return;
checkflagpile_maplfs(lf->cell->map);
ailoscheck(lf);
///////////////////////////////////////////////
@ -2610,12 +2644,14 @@ void aiturn(lifeform_t *lf) {
///////////////////////////////////////////////
if (ai_premovement(lf)) return;
checkflagpile_maplfs(lf->cell->map);
ailoscheck(lf);
///////////////////////////////////////////////
// movement
///////////////////////////////////////////////
if (ai_movement(lf)) return;
checkflagpile_maplfs(lf->cell->map);
ailoscheck(lf);
///////////////////////////////////////////////
@ -2623,17 +2659,22 @@ void aiturn(lifeform_t *lf) {
// to attack, etc)
///////////////////////////////////////////////
if (ai_bored(lf, master, icanattack)) return;
checkflagpile_maplfs(lf->cell->map);
ailoscheck(lf);
// DEFAULT - try to move in a random direction
if (db) dblog(".oO { default - moving randomly }");
checkflagpile_maplfs(lf->cell->map);
dorandommove(lf, B_NOBADMOVES, B_TRUE, B_FALSE); // this function will call rest() if we cant move
checkflagpile_maplfs(lf->cell->map);
ailoscheck(lf);
// somehow still here?
if (!lf->timespent) {
taketime(lf, getmovespeed(lf));
}
checkflagpile_maplfs(lf->cell->map);
}
// is the spell 'spellid' okay for AI lifeform 'lf' to cast at 'victim', for given purpose.
@ -3057,7 +3098,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
}
if (ot->id == OT_S_BLINKASS) {
cell_t *targcell;
targcell = getcellindir(targcell, diropposite(victim->facing));
targcell = getcellindir(victim->cell, diropposite(victim->facing));
if (!cellwalkable(lf, targcell, NULL)) {
specificcheckok = B_FALSE;
}
@ -3310,7 +3351,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
specificcheckok = B_FALSE;
}
if ((ot->id == OT_S_WARPWOOD)) {
if (ot->id == OT_S_WARPWOOD) {
specificcheckok = B_FALSE;
if (victim) {
object_t *oo;
@ -3322,7 +3363,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
}
}
}
if ((ot->id == OT_S_WEAKEN)) {
if (ot->id == OT_S_WEAKEN) {
flag_t *lff;
for (lff = lf->flags->first; lff ; lff = lff->next) {
if ((lff->id == F_ATTRMOD) && (lff->val[0] == A_STR) && (lff->obfrom == OT_S_WEAKEN)) {
@ -3719,6 +3760,9 @@ void makewantedoblist(lifeform_t *lf, int *noids, enum OBTYPE *oid, int *oidcove
wantflagcovet[*nwantflags] = (f->val[1] == B_COVETS) ? B_TRUE : B_FALSE;
(*nwantflags)++;
}
if (*nwantflags >= MAXCANDIDATES) {
raise(SIGINT);
}
}
if (hasflag(lf->flags, F_HUNGER)) {
@ -3727,6 +3771,9 @@ void makewantedoblist(lifeform_t *lf, int *noids, enum OBTYPE *oid, int *oidcove
wantflag[*nwantflags] = F_EDIBLE;
wantflagcovet[*nwantflags] = B_TRUE;
(*nwantflags)++;
if (*nwantflags >= MAXCANDIDATES) {
raise(SIGINT);
}
}
}

2
ai.h
View File

@ -33,7 +33,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
void aiturn(lifeform_t *lf);
int aiwants(lifeform_t *lf, object_t *o, int *covets);
int aiwants_real(lifeform_t *lf, object_t *o, int *covets, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet);
void clearnode(node_t *n;);
void clearnode(node_t *n);
lifeform_t *gettargetlf(lifeform_t *lf);
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op);
object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op);

130
astar.c Normal file
View File

@ -0,0 +1,130 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "astar.h"
#include "defs.h"
#include "flag.h"
#include "move.h"
#include "nexus.h"
#include "lf.h"
#include "map.h"
#include "objects.h"
#include "text.h"
int calcg(lifeform_t *lf, cell_t *thiscell, node_t *parent, int dirfromparent) {
int fromstart;
object_t *o;
int dooropen;
enum ATTRBRACKET wis = AT_EXHIGH;
if (lf) {
wis = getattrbracket(getattr(lf, A_WIS), A_WIS, NULL);
}
if (isorthogonal(dirfromparent)) {
fromstart = parent->fromstart + 10;
} else {
fromstart = parent->fromstart + 14;
}
// closed doors count for more.
if (wis >= AT_AVERAGE) {
o = hasdoor(thiscell);
if (o && isdoor(o, &dooropen) && !dooropen) {
fromstart += 10;
}
}
// lf's wisdom will affect what is the "best" path
if (wis >= AT_GTAVERAGE) {
// avoid mud, etc
o = hasobwithflag(thiscell->obpile, F_REDUCEMOVEMENT);
if (o) {
int howmuch;
sumflags(o->flags, F_REDUCEMOVEMENT, &howmuch, NULL, NULL);
if (howmuch > 0) {
fromstart += (10*howmuch);
}
}
}
return fromstart;
}
int calcg_map(cell_t *thiscell, node_t *parent, int dirfromparent) {
int fromstart;
/*
if (isorthogonal(dirfromparent)) {
fromstart = parent->fromstart + 10;
} else {
fromstart = parent->fromstart + 14;
}
*/
fromstart = parent->fromstart + 10;
return fromstart;
}
int calcheuristic(cell_t *c, cell_t *end) {
int h,xd,yd;
xd = abs(c->x - end->x);
yd = abs(c->y - end->y);
if (xd > yd) {
h = (14*yd) + 10*(xd - yd);
} else {
h = (14*xd) + 10*(yd - xd);
}
return h;
}
//
int calch_map(cell_t *c, int destroomid) {
int h,xd,yd;
cell_t *end = NULL;
end = getroommidcell(c->map, destroomid);
// returns distance to centre of given roomid
xd = abs(c->x - end->x);
yd = abs(c->y - end->y);
if (xd > yd) {
h = (14*yd) + 10*(xd - yd);
} else {
h = (14*xd) + 10*(yd - xd);
}
return h;
}
void clearnode(node_t *n) {
n->c = NULL;
n->parent = NULL;
n->dirfromparent = D_NONE;
n->fromstart = -1;
n->heur = -1;
n->cost = -1;
}
// inserts node 'n' into list 'list' (sorted by cost)
// returns index of insert position.
int insert(node_t *n, node_t *list, int *listcount) {
int pos,i;
// add it to open list, with parent = node[cur]
pos = -1;
for (pos = 0; pos < *listcount; pos++) {
if (n->cost <= list[pos].cost) {
// add here.
break;
}
}
// shuffle others up
for (i = *listcount; i > pos; i--) {
list[i] = list[i-1];
}
(*listcount)++;
// fill in .
list[pos] = *n;
return pos;
}

8
astar.h Normal file
View File

@ -0,0 +1,8 @@
#include "defs.h"
int calcg(lifeform_t *lf, cell_t *thiscell, node_t *parent, int dirfromparent);
int calcg_map(cell_t *thiscell, node_t *parent, int dirfromparent);
int calcheuristic(cell_t *c, cell_t *end);
int calch_map(cell_t *c, int destroomid);
void clearnode(node_t *n);
int insert(node_t *n, node_t *list, int *listcount);

View File

@ -1053,7 +1053,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} else {
critpos = getrandomcorebp(victim, lf);
}
if (critpos == BP_NONE) {
if ((int)critpos == BP_NONE) {
strcpy(victimbpname, victimname);
} else {
armour = getouterequippedob(victim, critpos);
@ -1570,8 +1570,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (backstab) {
practice(lf, SK_BACKSTAB, 1);
pleasegodmaybe(R_GODTHIEVES, 10);
} else if (lfhasflagval(lf, F_UNSEENATTACKER, victim->id, NA, NA, NULL)) {
pleasegodmaybe(R_GODTHIEVES, 8);
}
// now handle the extra hp loss effects which we postponed above.
losehpeffects(victim, dam[i], damtype[i], lf, wep, B_NORETALIATE, waskod,
@ -1736,9 +1739,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
msg("%s %smisses %s.", buf, missamt, victimname);
}
}
// victim trains evasion
practice(victim, SK_EVASION, 1);
if (canevade(victim, lf)) {
// victim trains evasion
practice(victim, SK_EVASION, 1);
}
// chance to fumble attack.
if (fumble) {
@ -2293,7 +2298,7 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, objec
int protected = B_FALSE;
char lfname[BUFLEN],victimname[BUFLEN];
if (hitpos == BP_NONE) return;
if ((int)hitpos == BP_NONE) return;
// replace some dam types
if (damtype == DT_UNARMED) damtype = DT_BASH;
@ -3126,14 +3131,14 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical,
}
// modify for defender's evasion
if (isprone(victim) || !cansee(victim, lf)) {
ev = 0;
} else {
if (canevade(victim, lf)) {
ev = getevasion(victim);
} else {
ev = 0;
}
acc -= ev;
if (db) dblog("%s: minus victim's evasion (%d) -> %d", lfname, ev, acc);
if (db) dblog("%s: minus victim's modified evasion (%d) -> %d", lfname, ev, acc);
// modify if victim is flying and we're not
if (isairborne(victim,&vicheight)) {
@ -3451,18 +3456,16 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isu
valflag = hasflag(f->pile, F_HITCONFERVALS);
if (fid == F_POISONED) {
// need to fill in the name of what poisoned us
enum POISONTYPE ptype;
int ppower;
// defaults - need to fill in the name of what poisoned us
enum POISONTYPE ptype = P_VENOM;
int ppower = 1;
assert(valflag);
if (valflag) {
ptype = valflag->val[0];
if (valflag->val[1] == NA) {
ppower = 1;
} else {
ppower = valflag->val[1];
}
ptype = valflag->val[0];
if (valflag->val[1] == NA) {
ppower = 1;
} else {
ppower = valflag->val[1];
}
if (!wep && strlen(ftext)) {

20
data.c
View File

@ -2684,7 +2684,7 @@ void initobjects(void) {
addflag(lastot->flags, F_REPELBLESSED, B_CURSED, B_BLESSED, NA, NULL);
addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL);
addot(OT_PENTAGRAM, "pentagram", "A area imbued with evil.", MT_NOTHING, 0, OC_DFEATURE, SZ_LARGE);
addot(OT_PENTAGRAM, "pentagram", "A area imbued with evil. It will repel any blessed objects which enter.", MT_NOTHING, 0, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, "");
addflag(lastot->flags, F_GLYPH, C_DARKRED, '_', NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
@ -4059,7 +4059,8 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
// TODO: should be "castnearob ot_corpse"
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_PLEASESGOD, R_GODDEATH, 1, NA, NULL);
// l2
addot(OT_S_STENCH, "stench of death", "Nauseates the target with the smell of dying flesh.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
@ -6023,7 +6024,7 @@ void initobjects(void) {
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
addot(OT_A_TRAIN, "training", "Start training to gain a new experience level or enhance skill.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_TUMBLE, "tumble", "You can tumble across the ground.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addot(OT_A_TUMBLE, "tumble", "You can tumble two metres across the ground.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_STAMCOST, 2, NA, NA, NULL);
addot(OT_A_WARCRY, "warcry", "Inspire fear in your enemies with a mighty war cry.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
@ -8704,7 +8705,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, "");
addflag(lastot->flags, F_EQUIPCONFER, F_MPREGEN, 1, NA, NULL);
addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL);
addot(OT_RING_MEDITATION, "ring of meditation", "Allows the wearer to rest by entering a state of meditation.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addot(OT_RING_MEDITATION, "ring of meditation", "Allows the wearer to remain aware while resting, by entering a state of meditation.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, "");
addflag(lastot->flags, F_EQUIPCONFER, F_MEDITATES, B_TRUE, NA, NULL);
addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL);
@ -11667,6 +11668,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANCAST, OT_S_BLINKASS, NA, NA, "pw:10;");
//addflag(lastrace->flags, F_CANCAST, OT_S_HUNGER, NA, NA, "pw:1;");
// likes/dislikes
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "sneak attacks");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "backstabbing");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "stealing items");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "lockpicking");
@ -15469,7 +15471,7 @@ void initrace(void) {
addflag(lastrace->flags, F_TR, 2, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addrace(R_FUNGUSDREAM, "dreamfungus", 0.5, 'F', C_MAGENTA, MT_PLANT, RC_PLANT, "A huge, spotty, purple mold which releases speed-inducing spores on the slightest contact.");
addrace(R_FUNGUSDREAM, "dreamfungus", 0.5, 'F', C_MAGENTA, MT_PLANT, RC_PLANT, "A huge, spotty, purple mold which releases sleep-inducing spores on the slightest contact.");
addbodypart(lastrace, BP_BODY, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL);
@ -17203,6 +17205,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_EXLOW, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 1, NA, NA, NULL);
addflag(lastrace->flags, F_NOSTAIRS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 3, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
@ -20699,10 +20702,15 @@ void initskills(void) {
addskillabil(SK_COOKING, PR_NOVICE, OT_A_COOK, NA, NULL, B_TRUE);
addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou now recognise bad food.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou can now cook recipes using up to 2 ingredients.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou can now cook up to Small sized corpses.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_ADEPT, "^gYou can now cook recipes using up to 3 ingredients.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_ADEPT, "^gYou can now cook up to Medium sized corpses.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_SKILLED, "^gYou can now cook recipes using up to 4 ingredients.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_SKILLED, "^gYou can now cook up to Human sized corpses.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_EXPERT, "^gYou can now cook recipes using up to 5 ingredients.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_EXPERT, "^gYou can now cook up to Large sized corpses.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_MASTER, "^gYou can now cook all recipes.^n", B_TRUE);
addskilldesc(SK_COOKING, PR_MASTER, "^gYou can now cook up to Huge sized corpses.^n", B_TRUE);
addskill(SK_EVASION, "Evasion", "Your ability to dodge blows or traps.", 50);
addskilldesc(SK_EVASION, PR_NOVICE, "^gIncreases your EV by 12%.^n", B_FALSE);
addskilldesc(SK_EVASION, PR_BEGINNER, "^gIncreases your EV by 24%.^n", B_FALSE);
@ -20813,7 +20821,7 @@ void initskills(void) {
addskilldesc(SK_PERCEPTION, PR_MASTER, "^gYou field of vision now extends behind you.^n", B_TRUE);
addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable?
addskillabil(SK_STEALTH, PR_NOVICE, OT_A_HIDE, NA, NULL, B_TRUE);
addskilldesc(SK_STEALTH, PR_BEGINNER, "^gYou can now move while hiding.^n", B_TRUE);
addskilldesc(SK_STEALTH, PR_BEGINNER, "^gYou can now move (slowly) while hiding.^n", B_TRUE);
addskilldesc(SK_STEALTH, PR_SKILLED, "^gYou can now peek down staircases.^n", B_TRUE);
addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water.", 50);
addskilldesc(SK_SWIMMING, PR_NOVICE, "^gYou can now swim.^n", B_TRUE);

9
defs.h
View File

@ -160,8 +160,8 @@
#define B_UNKNOWN (0)
#define B_NOVIS (-1)
#define B_KEEPLOF (-1)
#define B_MALE (0)
#define B_FEMALE (-1)
//#define B_MALE (0)
//#define B_FEMALE (-1)
#define B_MAYCHASE (-1)
#define B_NODOORS (0)
#define B_DONTKILL (-1)
@ -2693,8 +2693,9 @@ enum OBTYPE {
#define MAXBUILDINGTYPES (11)
#define BP_NONE (-1)
//#define BP_NONE (-1)
enum BODYPART {
BP_NONE = -1,
// humanoid parts
BP_WEAPON = 0,
BP_SECWEAPON = 1,
@ -3649,6 +3650,7 @@ enum FLAG {
F_SIZETIMER, // lf weill resize to LFSIZE val0 in val1 turns.
// v2 = B_FALSE = don't resize armour.
// B_TRUE = resize armour too
// text = "origSTR,origMAXHP"
F_UNSEENATTACKER, // this lf attacked lfid v0 while lfid v0 couldn't
// see them. used to mark 'X' on the player's map
// for unseen attackers.
@ -4433,6 +4435,7 @@ enum FLAG {
// just a normal random room
F_KEEPMARGIN, // this vault must be at least v0 from e/w of map
// and at least v1 from n/s of map
F_LAST,
F_NULL = -1
};

52
flag.c
View File

@ -1,4 +1,5 @@
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -22,6 +23,8 @@ extern int ngodlfs;
extern lifeform_t *player;
extern int flagcheck;
int flagdb = B_FALSE;
altflagval_t *addaltval(flag_t *f, enum FLAG id, int val1, int val2, int val3, char *text) {
@ -66,7 +69,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
int rv;
enum { NONE, FIRST, FIRST2, MIDDLE, LAST } fml = NONE;
//checkflagpile(fp);
checkflagpile(fp);
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
// identified things mean all new flags are autmaticlaly known.
@ -74,6 +77,13 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
known = B_KNOWN;
}
// debug
if (id == F_DOOR) {
if (fp->ob && fp->ob->type->id == OT_LEAF) {
raise(SIGINT);
}
}
if (fp->owner && (id == F_VAULTISPLAYERSTART)) {
dblog("added vaultisplayerstart");
}
@ -444,6 +454,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
}
//checkflagpile(fp);
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
checkflagpile(fp);
return f;
}
@ -497,7 +508,7 @@ void changeflagtext(flag_t *f, char *newtext) {
}
}
void checkmapflags(map_t *m) {
void checkflagpile_mapobs(map_t *m) {
cell_t *c;
object_t *o;
int nbad = 0,x,y;
@ -522,7 +533,16 @@ void checkmapflags(map_t *m) {
}
}
void checkflagpile_maplfs(map_t *m) {
lifeform_t *l;
if (!flagcheck) return;
for (l = m->lf ; l ; l = l->next) {
checkflagpile(l->flags);
}
}
void checkflagpile(flagpile_t *fp) {
if (!flagcheck) return;
if (fpisbad(fp)) {
assert("flagpile is corrupt!" == 0);
}
@ -530,8 +550,18 @@ void checkflagpile(flagpile_t *fp) {
int fpisbad(flagpile_t *fp) {
flag_t *f;
if (!flagcheck) return B_FALSE;
for (f = fp->first ; f ; f = f->next) {
if (f->next) {
if(f->next->prev != f) {
dblog("flag after %d is bad! its prev = 0x%x, should be this flag (0x%x)",f->id, f->next->prev, f);
return B_TRUE;
}
}
if (fp->ob && fp->owner) {
dblog("flag %d has both ob and owner",f->id);
return B_TRUE;
}
}
@ -1100,8 +1130,6 @@ void real_killflag(flag_t *f, int wantannounce) {
int i,dopleasegod[MAXGODS];
flagpile_t *newflags = NULL;
//checkflagpile(f->pile);
// remember the pile so that we can re-index
pile = f->pile;
@ -1141,7 +1169,7 @@ void real_killflag(flag_t *f, int wantannounce) {
fleefrom = findlf(lf->cell->map, f->val[0]);
// ie. this lf was fleeing from the player, and
// got away.
if (isplayer(fleefrom) && !cansee(lf, fleefrom)) {
if (fleefrom && isplayer(fleefrom) && !cansee(lf, fleefrom)) {
for (i = 0; i < ngodlfs; i++) {
if (godlf[i] && (godlf[i]->race->id == R_GODMERCY)) dopleasegod[i] += 5;
}
@ -1149,6 +1177,7 @@ void real_killflag(flag_t *f, int wantannounce) {
}
}
}
checkflagpile(pile);
if (gamemode == GM_GAMESTARTED) {
// flags which cause a redraw
@ -1159,6 +1188,7 @@ void real_killflag(flag_t *f, int wantannounce) {
redolos = getflagpilelocation(f->pile);
}
}
checkflagpile(pile);
// notify
if (gamemode == GM_GAMESTARTED) {
@ -1225,6 +1255,7 @@ void real_killflag(flag_t *f, int wantannounce) {
}
}
}
checkflagpile(pile);
/////////////////////////////////////////////
// now we are actually removing the flag.
@ -1269,8 +1300,10 @@ void real_killflag(flag_t *f, int wantannounce) {
//////////////////////////////////////////
f = NULL;
checkflagpile(pile);
// re-index the pile
updatefpindex(pile);
checkflagpile(pile);
if (gamemode == GM_GAMESTARTED) {
for (i = 0; i < ngodlfs; i++) {
@ -1529,9 +1562,8 @@ void timeeffectsflag(flag_t *f, int howlong) {
if (stone(f->pile->owner)) {
// stoning failed
killflag(f);
} else {
return;
}
return;
} else {
// announce
if (isplayer(f->pile->owner)) {
@ -1721,12 +1753,16 @@ void sumflags(flagpile_t *fp, enum FLAG id, int *val0, int *val1, int *val2) {
void timeeffectsflags(flagpile_t *fp) {
flag_t *f,*nextf;
enum FLAG thisid;
//checkflagpile(fp);
for (f = fp->first ; f ; f = nextf) {
nextf = f->next;
thisid = f->id;
timeeffectsflag(f, 1);
// if this checkflag() crashes, we know there we a bug during processing of
// flag 'thisid'
checkflagpile(fp);
}
//checkflagpile(fp);
}

4
flag.h
View File

@ -11,9 +11,11 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
flagpile_t *addflagpile(lifeform_t *owner, object_t *o);
int canbemadepermenant(enum FLAG id);
void changeflagtext(flag_t *f, char *newtext);
void checkmapflags(map_t *m);
int fpisbad(flagpile_t *fp);
void checkflagpile(flagpile_t *fp);
void checkflagpile_maplfs(map_t *m);
void checkflagpile_mapobs(map_t *m);
int copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id);
void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime);
int countflags(flagpile_t *fp);

2
god.c
View File

@ -503,7 +503,7 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) {
checkgodbonus(rid,plev, oldplev);
}
// anger the god if you are worshippin them.
// anger the god if you are worshipping them.
// returns TRUE if someone got angry
int angergodmaybe(enum RACE rid, int amt, enum GODANGERREASON why) {
lifeform_t *god;

159
io.c
View File

@ -982,7 +982,9 @@ cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t
// two different weapons with the same name?
if (secwep && (secwep != wep) && streq(obname, obname2)) {
char *plur;
plur = makeplural(noprefix(obname));
//plur = makeplural(noprefix(obname));
plur = strdup(obname);
makeplural(&plur);
snprintf(buf2, BUFLEN, "weilding two %s",plur);
free(plur);
donesec = B_TRUE;
@ -3856,13 +3858,13 @@ int askobjectmulti(obpile_t *op, char *prompt, condset_t *cs, int includenothing
mvwprintw(mainwin, y, 0, MORESTRING);
}
if (descmode) {
snprintf(pbuf, BUFLEN,"%s (ESC to quit): ", altprompt);
snprintf(pbuf, BUFLEN,"%s (?=sel/ESC=quit): ", altprompt);
} else if (strlen(numstring) > 0) {
snprintf(pbuf, BUFLEN,"%s (%s','=all, ESC to quit) [%s]: ", prompt,
snprintf(pbuf, BUFLEN,"%s (%s','=all, ?=desc/ESC=quit) [%s]: ", prompt,
includenothing ? "- for nothing, " : "",
numstring);
} else {
snprintf(pbuf, BUFLEN,"%s (%sESC to quit): ", prompt,
snprintf(pbuf, BUFLEN,"%s (%s?=desc/ESC=quit): ", prompt,
includenothing ? "- for nothing, " : "");
}
@ -4008,6 +4010,34 @@ int askobjectmulti(obpile_t *op, char *prompt, condset_t *cs, int includenothing
return B_FALSE;
}
int asktoclimb(object_t *o, char *promptformat) {
char buf[BUFLEN];
char ch,question[BUFLEN],obname[BUFLEN];
cell_t *obcell;
obcell = getoblocation(o);
assert(strstr(promptformat, "%s"));
// confirm...
getobname(o, obname, o->amt);
sprintf(question, promptformat, obname);
ch = askchar(question, "yn","n", B_TRUE, B_FALSE);
if (ch != 'y') {
msg("Cancelled.");
return B_TRUE;
}
snprintf(buf, BUFLEN, "the %s", noprefix(obname));
if (tryclimb(player, obcell, buf, B_ONPURPOSE)) {
// failed
return B_TRUE;
}
// success
return B_FALSE;
}
vault_t *askvault(char *prompttext) {
vault_t *v;
@ -4200,6 +4230,14 @@ void clearretobs(void) {
nretobs = 0;
}
char cmdtochar(enum COMMAND cmd) {
command_t *c;
for (c = firstcommand ; c ; c = c->next) {
if (c->id == cmd) return c->ch;
}
return '\0';
}
// clears the screen
void cls(void) {
wclear(mainwin);
@ -4311,7 +4349,7 @@ void describerace(enum RACE rid) {
if (gamemode == GM_GAMESTARTED) {
enum SKILLLEVEL slev;
slev = getlorelevel(player, r->raceclass->id);
snprintf(buf, BUFLEN, "Race::%s (%s level lore)",r->name, getskilllevelname(slev));
snprintf(buf, BUFLEN, "Race::%s (%s) - %s level lore",r->name, r->raceclass->name, getskilllevelname(slev));
} else {
snprintf(buf, BUFLEN, "Race::%s",r->name);
}
@ -5518,7 +5556,7 @@ void doeat(obpile_t *op) {
eatob = askobject(op, "Eat what", "You have nothing to eat!", NULL, 'e', &cs, B_FALSE);
}
if (eatob) {
if (isunknownbadobject(eatob) && skillcheck(player, A_WIS, D_BADFEELING, 0)) {
if (isunknownbadobject(eatob) && skillcheck(player, SC_WIS, D_BADFEELING, 0)) {
if (!confirm_badfeeling(eatob)) {
msg("Cancelled.");
return;
@ -5530,13 +5568,13 @@ void doeat(obpile_t *op) {
int dowear(obpile_t *op) {
object_t *o;
int rv;
int rv = B_FALSE;
condset_t cs;
initcondv(&cs, CC_WEARABLE, B_TRUE, NA,
CC_NONE);
o = askobject(op, "Wear what", "You have nothing to wear!", NULL, '\0', &cs, B_FALSE);
if (o) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, D_BADFEELING, 0)) {
if (isunknownbadobject(o) && skillcheck(player, SC_WIS, D_BADFEELING, 0)) {
if (!confirm_badfeeling(o)) {
msg("Cancelled.");
return B_TRUE;
@ -5562,7 +5600,7 @@ int doweild(obpile_t *op) {
CC_NONE);
o = askobject(op, "Weild what", "You have nothing to weild.", &count, 'w', &cs, B_TRUE);
if (o) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, D_BADFEELING, 0)) {
if (isunknownbadobject(o) && skillcheck(player, SC_WIS, D_BADFEELING, 0)) {
if (!confirm_badfeeling(o)) {
msg("Cancelled.");
return B_TRUE;
@ -5879,7 +5917,8 @@ char *makedesc_god(lifeform_t *god, char *retbuf) {
objecttype_t *ot;
char *text;
ot = findot(retflag[i]->val[0]);
text = makeplural(ot->name);
text = strdup(ot->name);
makeplural(&text);
sprintf(thisline, "- %s", text);
free(text);
if ((god->race->id == R_GODPURITY) && (retflag[i]->val[0] == OT_CORPSE)){
@ -7470,9 +7509,8 @@ char *makedesc_ob(object_t *o, char *retbuf) {
col = C_GREY;
}
if (f->val[1] != NA) {
sprintf(buf, "^%dMinimum %s to use%s: %d to use.", col, getattrname(f->val[0]),
sprintf(buf, "^%dMinimum %s to use%s: %d", col, getattrname(f->val[0]),
strlen(f->text) ? " effectively" : "", f->val[1]);
strncat(retbuf, buf, HUGEBUFLEN);
}
if (f->val[2] != NA) {
char addon[BUFLEN];
@ -7646,6 +7684,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel
lorelev = getlorelevel(player, r->raceclass->id);
}
// TODO: add this to doco.
// Your Lore skill for this race will determine how much information is shown.
//
// NOVICE:
@ -7741,6 +7780,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel
spellorabil[1] = OC_SPELL;
getflags(r->flags, retflag, &nretflags, F_CANWILL, F_NONE);
for (n = 0; n <= 1; n++) {
int nfound = 0;
strcpy(buf, "");
for (i = 0; i < nretflags; i++) {
objecttype_t *ot;
@ -7748,11 +7788,14 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel
f = retflag[i];
ot = findot(f->val[0]);
if (ot && (ot->obclass->id == spellorabil[n])) {
if (i == 0) {
sprintf(buf, "Innate %s: %s", (spellorabil[n] == OC_ABILITY) ? "Ability" : "Spell",
char templine[BUFLEN];
if (nfound == 0) {
sprintf(templine, "Innate %s: %s", (spellorabil[n] == OC_ABILITY) ? "Ability" : "Spell",
ot->name);
strcat(buf, templine);
} else {
sprintf(buf, ", %s", ot->name);
sprintf(templine, ", %s", ot->name);
strcat(buf, templine);
}
texttospellopts(f->text, "pw:", &power, NULL);
if (power) {
@ -7760,6 +7803,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel
strcat(buf, roman(power));
strcat(buf, ")");
}
nfound++;
}
}
if (strlen(buf)) {
@ -7800,7 +7844,8 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel
switch (f->id) {
case F_AUTOCREATEOB:
if (lorelev >= PR_NOVICE) {
p = makeplural(f->text);
p = strdup(f->text);
makeplural(&p);
sprintf(buf, "Automatically creates %s around itself.", p);
free(p);
}
@ -8109,7 +8154,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel
strncat(retbuf, "^n@None known.\n", HUGEBUFLEN);
}
}
free(doneflags);
killflagpile(doneflags);
return retbuf;
}
@ -8279,7 +8324,7 @@ char *makedesc_spell(objecttype_t *ot, char *retbuf) {
god = findgod(retflag[i]->val[0]);
f = lfhasflag(god, F_GODOF);
sprintf(buf, "Successfully casting this spell will please %s (%s of %s).\n",god->race->name,
(getgender(god) == B_FEMALE) ? "Goddess" : "God", f->text);
(getgender(god) == G_FEMALE) ? "Goddess" : "God", f->text);
strncat(retbuf, buf, BUFLEN);
}
@ -8674,28 +8719,6 @@ void dooperate(obpile_t *op) {
object_t *o;
condset_t cs;
// operable objects here?
for (o = player->cell->obpile->first; o ; o = o->next) {
//if (isoperable(o) && canpickup(player, o, 1)) {
if (isoperable(o)) {
char obname[BUFLEN],buf[BUFLEN];
char verb[BUFLEN];
int ch;
getobname(o, obname, o->amt);
strcpy(verb, getoperateverb(o));
capitalise(verb);
snprintf(buf, BUFLEN, "There %s %s here. %s %s",
OB1(o,"is","are"),
obname, verb,
OB1(o,"it","one"));
ch = askchar(buf, "yn","n", B_TRUE, B_FALSE);
if (ch == 'y') {
operate(player, o, NULL);
return;
}
}
}
// ask which object to read
initcondv(&cs, CC_OPERABLE, B_TRUE, NA,
CC_NONE);
@ -9058,6 +9081,28 @@ void dointeract(void) {
int opened = B_FALSE;
int nobs,n;
// operable objects here?
for (o = player->cell->obpile->first; o ; o = o->next) {
if (isoperable(o)) {
char obname[BUFLEN],buf[BUFLEN];
char verb[BUFLEN];
int ch;
getobname(o, obname, o->amt);
strcpy(verb, getoperateverb(o));
capitalise(verb);
snprintf(buf, BUFLEN, "There %s %s here. %s %s",
OB1(o,"is","are"),
obname, verb,
OB1(o,"it","one"));
ch = askchar(buf, "yn","n", B_TRUE, B_FALSE);
if (ch == 'y') {
operate(player, o, NULL);
return;
}
}
}
// nothing on our space - ask to interact elsewhere
dir = askdir("Interact in which direction (- to cancel)", B_TRUE, B_TRUE);
if ((dir == D_MYSELF) || (dir == D_NONE)) {
msg("Cancelled.");
@ -9180,7 +9225,7 @@ void doquaff(obpile_t *op) {
}
if (liquid) {
if (candrink(player, liquid)) {
if (isunknownbadobject(liquid) && skillcheck(player, A_WIS, D_BADFEELING, 0)) {
if (isunknownbadobject(liquid) && skillcheck(player, SC_WIS, D_BADFEELING, 0)) {
if (!confirm_badfeeling(liquid)) {
msg("Cancelled.");
return;
@ -10260,7 +10305,7 @@ char getchoice(prompt_t *prompt) {
prompt->selection = i;
}
if ((gamemode == GM_GAMESTARTED)) {
if (gamemode == GM_GAMESTARTED) {
needredraw = B_TRUE;
drawscreen();
} else {
@ -10595,7 +10640,7 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) {
prompt->selection = i;
}
if ((gamemode == GM_GAMESTARTED)) {
if (gamemode == GM_GAMESTARTED) {
needredraw = B_TRUE;
drawscreen();
} else {
@ -10603,7 +10648,7 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) {
wrefresh(mainwin);
}
curs_set(0);
if ((gamemode == GM_GAMESTARTED)) {
if (gamemode == GM_GAMESTARTED) {
restoregamewindows();
}
@ -11319,7 +11364,7 @@ void msg_real(char *format, ... ) {
//drawcursor();
}
int needsbold(enum COLOUR col) {
int needsbold(int col) {
if (col >= REDBG) col -= REDBG;
if (col >= GREENBG) col -= GREENBG;
if (col >= BLUEBG) col -= BLUEBG;
@ -11372,7 +11417,10 @@ void drawstatus(void) {
// gun target ?
f = hasflag(player->flags, F_GUNTARGET);
if (f) {
wprintw(statwin, "Aim: ");
char aimname[11];
wprintw(statwin, "Aim:");
// limit
snprintf(aimname,11,"%s",f->text);
textwithcol(statwin, f->text);
}
@ -11885,11 +11933,10 @@ int screenglyphmatches(int x, int y, glyph_t *g) {
// prompts the player to learn a new spell from school 'ss' (ss_none means any)
void select_new_spell(enum SPELLSCHOOL ss, int lev) {
int done = B_FALSE;
flag_t *f;
char qbuf[BUFLEN];
sprintf(qbuf, "Learn which new spell (maxmp=%d):", getmaxmp(player));
while (!done) {
makespellchoicelist(&prompt, player, qbuf, "Describe which spell:", f->val[1], B_TRUE, B_FALSE, B_FALSE, player->maxmp);
makespellchoicelist(&prompt, player, qbuf, "Describe which spell:", ss, B_TRUE, B_FALSE, B_FALSE, player->maxmp);
if (prompt.nchoices > 0) {
objecttype_t *ot;
getchoicestr(&prompt, B_TRUE, B_TRUE);
@ -12003,10 +12050,11 @@ int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname) {
} else {
wprintw(mainwin, "\n");
}
free(score);
free(name);
free(job);
free(killer);
if (rank) free(rank);
if (job) free(job);
if (name) free(name);
if (score) free(score);
if (killer) free(killer);
return B_FALSE;
}
@ -13038,7 +13086,7 @@ void showlfstats(lifeform_t *lf, int showall) {
} else {
sprintf(youstr, "%s",you(lf));
}
wrapprint(mainwin, &y, &x, 0, "%s produce%s light (minimum vision range: %d). %s", youstr,
wrapprint(mainwin, &y, &x, 0, "%s produce%s light (minimum vision range: %d).", youstr,
isplayer(lf) ? "" : "s", amt);
}
f = lfhasknownflag(lf, F_SLOWMETAB);
@ -13935,7 +13983,7 @@ void showlfstats(lifeform_t *lf, int showall) {
if (lfhasknownflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT)) {
if (f->lifetime != PERMENANT) {
if ((f->lifetime != PERMENANT) && (f->lifetime > 0)) {
char buf3[BUFLEN];
snprintf(buf3, BUFLEN, "[%dt]",f->lifetime);
strcat(buf2, buf3);
@ -14040,7 +14088,8 @@ void showlfstats(lifeform_t *lf, int showall) {
char *pname;
objecttype_t *ot;
ot = findot(f->val[0]);
pname = makeplural(ot->name);
pname = strdup(ot->name);
makeplural(&pname);
mvwprintw(mainwin, y, 0, 0, "It %s %s.", (f->val[1] == B_COVETS) ? "covets" : "wants", pname);
y++;
free(pname);

2
io.h
View File

@ -32,6 +32,7 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int minrange, int maxrange, enum LOFTYPE loftype, int wanttrail, cell_t **spectarg, int nspectargs);
char askdir(char *prompt, int maycancel, int usedrunk);
char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def);
int asktoclimb(object_t *o, char *promptformat);
vault_t *askvault(char *prompttext);
void centre(WINDOW *win, enum COLOUR col, int y, char *format, ... );
enum COMMAND chartocmd(char ch);
@ -42,6 +43,7 @@ void clearmsg(void);
void real_clearmsg(int force);
void clearretobs(void);
void cls(void);
char cmdtochar(enum COMMAND cmd);
int contains(enum OBCLASS *array, int nargs, enum OBCLASS want);
void describegod(lifeform_t *god);
void describejob(enum JOB jid);

120
lf.c
View File

@ -1019,6 +1019,16 @@ int caneat(lifeform_t *lf, object_t *o) {
return B_TRUE;
}
// can lf try to evade attacker (or anything, if attacker isn't given)
int canevade(lifeform_t *lf, lifeform_t *attacker) {
if (isprone(lf)) return B_FALSE;
if (isexhausted(lf)) return B_FALSE;
if (attacker && !cansee(lf, attacker)) {
return B_FALSE;
}
return B_TRUE;
}
int canexorcise(lifeform_t *lf, lifeform_t *target, int modifier) {
int maxlevel;
if (lfhasflag(target, F_UNIQUE)) return B_FALSE;
@ -1348,6 +1358,7 @@ int canreachbp(lifeform_t *lf, lifeform_t *victim, enum BODYPART bp) {
case BP_LEFTFINGER:
bpheight = vicfeet + pctof(75, getlfsize(victim));
break;
case BP_NONE: // this counts as body
case BP_BODY:
case BP_WAIST:
case BP_WINGS:
@ -1381,6 +1392,16 @@ int canreachbp(lifeform_t *lf, lifeform_t *victim, enum BODYPART bp) {
return B_TRUE;
}
int canreachroof(lifeform_t *lf) {
if (getlfsize(lf) >= SZ_HUGE) {
return B_TRUE;
}
if (lfhasflag(lf, F_LEVITATING) || lfhasflag(lf, F_FLYING) || lfhasflag(lf, F_CLIMBING)) {
return B_TRUE;
}
return B_FALSE;
}
int cansee(lifeform_t *viewer, lifeform_t *viewee) {
return cansee_real(viewer, viewee, B_TRUE);
}
@ -4451,7 +4472,7 @@ int genalignmentlist(flagpile_t *fp, char *buf) {
void generatealignment(lifeform_t *lf) {
int nposs,i;
char possbuf[BUFLEN],buf[BUFLEN],buf2[BUFLEN],ch;
enum FLAG wantalignment = AL_NONE;
enum ALIGNMENT wantalignment = AL_NONE;
// get a list of all possible alignments
nposs = genalignmentlist(lf->flags, possbuf);
@ -5741,7 +5762,7 @@ void enhanceskills(lifeform_t *lf) {
if (skillstolearn) {
char buf[BUFLEN];
if (skillstoenhance) {
snprintf(buf, BUFLEN, "(E)nhance skills, (L)earn skills, or (N)either (%d points left)?",lf->skillpoints);
snprintf(buf, BUFLEN, "(E)nhance skills, (L)earn skills, or (N)one (%d points left)?",lf->skillpoints);
eorl = askchar(buf,"eln","e", B_TRUE, B_FALSE);
} else {
snprintf(buf, BUFLEN,"Learn a new skill (%d points left)?",lf->skillpoints);
@ -6533,8 +6554,10 @@ race_t *findracebyname(char *name, condset_t *cs) {
char searchfor[BUFLEN];
// first check for exact matches
for (r = firstrace; r ; r = r->next) {
if (!strcmp(r->name, name) && racemeets(r->id, cs)) {
return r;
if (!strcmp(r->name, name)) {
if (racemeets(r->id, cs)) {
return r;
}
}
}
@ -8087,11 +8110,15 @@ int getevasion(lifeform_t *lf) {
slev = getskill(lf, SK_EVASION);
// no evasion if you can't move!
// no evasion if you can't move or are exhausted!
if (isimmobile(lf)) {
return 0;
}
if (isexhausted(lf)) {
return 0;
}
// no evasion if you're holding someone, or someone is holding you
if (lfhasflag(lf, F_GRABBEDBY) || lfhasflag(lf, F_GRABBING)) {
return 0;
@ -8111,7 +8138,6 @@ int getevasion(lifeform_t *lf) {
ev += level_ev;
// dexterity mod
if (slev) {
ev += (getattr(lf, A_AGI)/5);
} else {
@ -8303,6 +8329,7 @@ object_t *getbestweapon(lifeform_t *lf) {
int getbodyparthitchance(enum BODYPART bp) {
switch (bp) {
case BP_NONE: return 0;
case BP_WEAPON: return 0;
case BP_SECWEAPON: return 0;
case BP_EYES: return 1;
@ -8344,6 +8371,8 @@ char *getbodypartname(lifeform_t *lf, enum BODYPART bp) {
}
switch (bp) {
case BP_NONE:
return "__bp_none__";
case BP_WEAPON:
return "right hand";
case BP_SECWEAPON:
@ -8407,6 +8436,7 @@ char *getbodypartequipname(enum BODYPART bp) {
case BP_FEET:
case BP_WINGS:
case BP_TAIL:
case BP_NONE:
return "on";
case BP_EYES:
case BP_SHOULDERS:
@ -11416,6 +11446,7 @@ int gettr(lifeform_t *lf) {
return lf->level;
}
f = hasflag(lf->flags, F_TR);
assert(f);
return f->val[0];
//return (lf->maxhp / 4);
}
@ -14591,7 +14622,7 @@ void killlf(lifeform_t *lf) {
map_t *m;
flag_t *f;
if ((gamemode == GM_GAMESTARTED)) {
if (gamemode == GM_GAMESTARTED) {
if (cansee(player, lf)) {
needredraw = B_TRUE;
}
@ -14613,6 +14644,12 @@ void killlf(lifeform_t *lf) {
// shouldn't need this...
lf->cell = NULL;
// remove line of sight data
if (lf->los) {
free(lf->los);
lf->los = NULL;
}
// remove impossible stuff
if (getstamina(lf) > getmaxstamina(lf)) {
setstamina(lf, getmaxstamina(lf));
@ -14623,7 +14660,7 @@ void killlf(lifeform_t *lf) {
// we are dead.
// also: does anyone have us as a master?
// TODO: check on all maps?
if ((gamemode == GM_GAMESTARTED)) {
if (gamemode == GM_GAMESTARTED) {
for (l = m->lf ; l ; l = l->next) {
f = lfhasflagval(l, F_TARGETLF, lf->id, NA, NA, NULL);
if (f) killflag(f);
@ -14655,6 +14692,8 @@ void killlf(lifeform_t *lf) {
free(lf->polypack);
lf->polypack = NULL;
// kill flags
killflagpile(lf->flags);
lf->flags = NULL;
@ -15709,6 +15748,8 @@ object_t *addtrail(lifeform_t *lf, cell_t *where, int dir, int doprints, int dos
object_t *footprint, *scent,*retob = NULL;
flag_t *fpflag = NULL;
checkflagpile_maplfs(lf->cell->map);
// no tracks at all?
if (where->type->solid) {
return NULL;
@ -15734,6 +15775,8 @@ object_t *addtrail(lifeform_t *lf, cell_t *where, int dir, int doprints, int dos
fpdir = dir;
}
checkflagpile_maplfs(lf->cell->map);
footprint = hastrailof(where->obpile, lf, OT_FOOTPRINT, &fpflag, NULL);
if (footprint) {
assert(fpflag);
@ -15742,8 +15785,16 @@ object_t *addtrail(lifeform_t *lf, cell_t *where, int dir, int doprints, int dos
} else {
char buf[BUFLENTINY];
snprintf(buf, BUFLENTINY, "%d", lf->id);
checkflagpile_maplfs(lf->cell->map);
footprint = addobfast(where->obpile, OT_FOOTPRINT);
checkflagpile_maplfs(lf->cell->map);
addtempflag(footprint->flags, F_TRAIL, lf->race->id, fpdir, S_SIGHT, buf, getfootprinttime(lf));
checkflagpile_maplfs(lf->cell->map);
}
retob = footprint;
}
@ -15758,11 +15809,20 @@ object_t *addtrail(lifeform_t *lf, cell_t *where, int dir, int doprints, int dos
} else {
char buf[BUFLENTINY];
snprintf(buf, BUFLENTINY, "%d", lf->id);
checkflagpile_maplfs(lf->cell->map);
scent = addobfast(where->obpile, OT_SCENT);
assert(scent);
checkflagpile_maplfs(lf->cell->map);
addtempflag(scent->flags, F_TRAIL, lf->race->id, dir, S_SMELL, buf, TM_SCENT);
checkflagpile_maplfs(lf->cell->map);
}
retob = scent;
}
checkflagpile_maplfs(lf->cell->map);
return retob;
}
@ -16668,7 +16728,7 @@ void autospells(lifeform_t *lf, int howmany) {
// power = 0 means select it based on depth
for (i = 0 ; i < nposs; i++) {
if (powerposs[nposs] == 0) {
if (powerposs[nposs] == 0) { // ooo TODO: use of unit value here ??
powerposs[nposs] = mapdiff;
limit(&(powerposs[nposs]), 1, getspellmaxpower(poss[nposs]));
}
@ -16956,10 +17016,15 @@ void killpoisontype(poisontype_t *pt) {
void killrace(race_t *r) {
race_t *nextone, *lastone;
int i;
// free mem
free(r->name);
free(r->desc);
killflagpile(r->flags);
for (i = 0; i < r->nbodyparts; i++) {
free(r->bodypart[i].name);
}
// remove from list
nextone = r->next;
@ -20561,7 +20626,7 @@ int say(lifeform_t *lf, char *text, int volume) {
char verb[BUFLEN];
char noun[BUFLEN];
char *localtext;
int rv;
int rv = B_FALSE;
if (lf && lfhasflag(lf, F_SILENCED)) {
return B_FALSE;
@ -21437,7 +21502,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
f = lfhasflag(lf, F_GODOF);
if (f) {
msg("^w%s transforms into %s, the %s of %s!", buf, newrace->name,
(getgender(lf) == B_FEMALE) ? "Goddess" : "God", f->text);
(getgender(lf) == G_FEMALE) ? "Goddess" : "God", f->text);
} else {
msg("^w%s transforms into %s %s!", buf, isvowel(newrace->name[0]) ? "an" : "a", newrace->name);
}
@ -21621,7 +21686,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
// new race can hold objects (F_NOPACK xx)
// TODO: new race can use magic (F_NOSPELLS)
// new race can still hold all the items which you have
if ((gamemode == GM_GAMESTARTED)) {
if (gamemode == GM_GAMESTARTED) {
object_t *o,*nexto;
int donemeldmsg = B_FALSE;
@ -23101,7 +23166,7 @@ void startlfturn(lifeform_t *lf) {
if (lfhasflag(lf, F_SPRINTING)) {
modstamina(lf, -1.5);
} else if (isswimming(lf) && isplayer(lf)) {
int lossamt;
double lossamt;
// players lose stamina based on swimming skill
// monsters don't.
switch (getskill(lf, SK_SWIMMING)) {
@ -23116,7 +23181,7 @@ void startlfturn(lifeform_t *lf) {
}
if (lossamt) modstamina(lf, -lossamt);
} else if (isclimbing(lf) && !lfhasflag(lf, F_SPIDERCLIMB)) {
int lossamt;
double lossamt;
// players lose stamina based on climbing skill
// monsters don't lose stamina to climb.
switch (getskill(lf, SK_CLIMBING)) {
@ -24960,7 +25025,7 @@ int takeoff(lifeform_t *lf, object_t *o) {
killflagsofid(o->flags, F_EQUIPPED);
taketime(lf, getactspeed(lf));
if ((gamemode == GM_GAMESTARTED)) {
if (gamemode == GM_GAMESTARTED) {
if (isplayer(lf)) {
msg("You take off %s.", obname);
statdirty = B_TRUE;
@ -25521,7 +25586,7 @@ int real_touch(lifeform_t *lf, object_t *o, int onpurpose) {
}
}
} else {
enum DAMTYPE dt;
enum DAMTYPE dt = DT_HEAT;
int dam = 3;
// otherwise YOU get damaged.
f->known = B_TRUE;
@ -25965,26 +26030,11 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) {
return B_TRUE;
}
} else if (dir == D_UP) {
if (hasflagval(o->flags, F_PIT, D_UP, NA, NA, NULL) || (o->type->id == OT_GRATINGROOF)) {
// can only go up if you have a rope or are flying/levitating
if (lfhasflag(lf, F_LEVITATING) || lfhasflag(lf, F_FLYING)) {
if (isinroof(o)) {
if (canreachroof(lf)) {
// ok.
} else {
char buf[BUFLEN];
if (isplayer(lf)) {
char ch,buf2[BUFLEN],obname[BUFLEN];
// confirm...
getobname(o, obname, o->amt);
sprintf(buf2, "Climb up %s", obname);
ch = askchar(buf2, "yn","n", B_TRUE, B_FALSE);
if (ch != 'y') {
msg("Cancelled.");
return B_TRUE;
}
}
snprintf(buf, BUFLEN, "the %s", noprefix(obname));
if (tryclimb(lf, obcell, buf, onpurpose)) {
if (asktoclimb(o, "Climb up %s")) {
// failed
return B_TRUE;
} else {
@ -26634,7 +26684,7 @@ int resizelf(lifeform_t *lf, enum LFSIZE newsize, int doobs) {
}
// resizing an lf might change its glyph...
if (cansee(player, lf)) {
if (cansee(player, lf) || isplayer(lf)) {
needredraw = B_TRUE;
}

2
lf.h
View File

@ -53,6 +53,7 @@ int cancook(lifeform_t *lf, recipe_t *rec, enum ERROR *reason);
int canclimb(lifeform_t *lf, enum ERROR *reason);
int candrink(lifeform_t *lf, object_t *o);
int caneat(lifeform_t *lf, object_t *o);
int canevade(lifeform_t *lf, lifeform_t *attacker);
int canexorcise(lifeform_t *lf, lifeform_t *target, int modifier);
int canhaverandombehaviour(lifeform_t *lf);
int canhear(lifeform_t *lf, cell_t *c, int volume, int *numwalls);
@ -65,6 +66,7 @@ int canpolymorphto(enum RACE rid);
int canpush(lifeform_t *lf, object_t *o, int dir);
int canreach(lifeform_t *lf, lifeform_t *victim, int *reachpenalty);
int canreachbp(lifeform_t *lf, lifeform_t *victim, enum BODYPART bp);
int canreachroof(lifeform_t *lf);
int cansee(lifeform_t *viewer, lifeform_t *viewee);
int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos);
int canshoot(lifeform_t *lf, enum ERROR *why);

76
map.c
View File

@ -67,7 +67,8 @@ cell_t *addcell(map_t *m, int x, int y) {
cell = m->cell[(y*m->w)+x];
if (cell) {
clearcell(cell);
free(cell);
killcell(&cell);
//free(cell);
}
m->cell[(y*m->w)+x] = malloc(sizeof(cell_t));
@ -1669,6 +1670,28 @@ enum CELLTYPE celltypefromvault(cell_t *c) {
return B_FALSE;
}
// clear and deallocate cell strings
void clearcellstrings(cell_t *c) {
if (c->writing) {
free(c->writing);
c->writing = NULL;
}
if (c->reason) {
free(c->reason);
c->reason = NULL;
}
if (c->lockedreason) {
free(c->lockedreason);
c->lockedreason = NULL;
}
if (gamemode == GM_GAMESTARTED) {
c->known = B_FALSE;
c->knownglyph.ch = ' ';
c->knownglyph.colour = C_GREY;
}
}
// kill everything in the given cell (lifeforms && objects)
// but DONT remove the cell itself.
void clearcell(cell_t *c) {
@ -1678,12 +1701,9 @@ void clearcell(cell_t *c) {
while (c->obpile->first) {
killob(c->obpile->first);
}
if (gamemode == GM_GAMESTARTED) {
c->known = B_FALSE;
c->knownglyph.ch = ' ';
c->knownglyph.colour = C_GREY;
}
clearcellstrings(c);
}
void clearcell_exceptflags(cell_t *c, ... ) {
va_list args;
enum FLAG exception[MAXCANDIDATES];
@ -1729,7 +1749,6 @@ int delve(map_t *map, int neighbourmin, int neighbourmax, int connchance, int ch
int cellsdone = 0;
int wantcells;
int x,y;
int totcells;
int ngroups,ncount;
int changed = B_FALSE;
@ -1873,7 +1892,7 @@ int delve(map_t *map, int neighbourmin, int neighbourmax, int connchance, int ch
dblog("DELVE DEBUG:");
dblog(" PATTERN: ngb_min=%d, ngb_max=%d, connchance=%d", neighbourmin, neighbourmax, connchance);
dblog(" wanted cells: %d / %d (%d%%)", wantcells, totcells, (int) (((double)wantcells / (double)totcells)*(double)100) );
dblog(" wanted cells: %d", wantcells);
dblog(" dug cells: %d", cellsdone);
dblog("generated map:");
dumpmap(map, B_FALSE, NULL);
@ -4618,6 +4637,8 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
int db = B_TRUE;
char dbtag[BUFLEN],dbbuf[BUFLEN];
snprintf(dbtag, BUFLEN, "[createmap.c]");
// don't redraw screen during level change calculations
redrawpause();
@ -4874,7 +4895,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
// place forced vaults.
if (db) {
dblog(" adding forced things first...");
//dblog(" adding forced things first...");
dblog(" adding forced things first...");
}
@ -5028,6 +5049,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
c = map->cell[i];
if (c->lockedreason && streq(c->lockedreason, TEMPVAULTLOCK)) {
free(c->lockedreason);
c->lockedreason = NULL;
c->locked = B_FALSE;
}
}
@ -5826,9 +5848,13 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r
return B_FALSE;
}
void killcell(cell_t *c) {
killobpile(c->obpile);
if (c->writing) free(c->writing);
void killcell(cell_t **c) {
// if (c) {
clearcell(*c);
killobpile((*c)->obpile);
free(*c);
*c = NULL;
// }
}
void killcelltype(celltype_t *ct) {
@ -5867,11 +5893,12 @@ void killmap(map_t *m) {
// free mem
while (m->lf) killlf(m->lf);
free(m->name);
killflagpile(m->flags);
m->flags = NULL;
for (i = 0; i < (m->w*m->h); i++){
killcell(m->cell[i]);
for (i = 0; i < (m->w*m->h); i++) {
killcell(&(m->cell[i]));
}
// remove from list
@ -8729,7 +8756,7 @@ vault_t *maphasvault(map_t *m, char *id) {
return NULL;
}
object_t *hastrailof(obpile_t *op, lifeform_t *lf, enum OBTYPE oid, flag_t **tflag, lifeform_t *viewer) {
object_t *hastrailof(obpile_t *op, lifeform_t *lf, int oid, flag_t **tflag, lifeform_t *viewer) {
object_t *o;
flag_t *f;
// default
@ -8880,6 +8907,7 @@ void initmaplayout(void) {
//vx = 0; vy = -1;
*/
// *************** MAP OUTLINE ***************
addregionoutline(BH_MAINDUNGEON);
addregionthing(lastregionoutline, 1, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISPLAYERSTART, NULL);
// l2-4: sylvan woods
@ -9694,6 +9722,10 @@ void makedoor(cell_t *cell, int openchance) {
// don't open it!
o = addob(cell->obpile, doorbuf);
if (o) {
if (o->type->id == OT_LEAF) {
raise(SIGINT);
}
if (!hasflag(o->flags, F_LOCKED) && (rnd(1,100) <= openchance)) {
opendoor(NULL, o);
} else {
@ -10419,7 +10451,10 @@ void setcelllocked(cell_t *c, char *why, ...) {
c->locked = B_TRUE;
if (c->lockedreason) free(c->lockedreason);
if (c->lockedreason) {
free(c->lockedreason);
c->lockedreason = NULL;
}
va_start(args, why);
vsnprintf( buf, BUFLEN, why, args );
@ -10433,7 +10468,10 @@ void setcellreason(cell_t *c, char *why, ...) {
char buf[BUFLEN];
va_list args;
if (c->reason) free(c->reason);
if (c->reason) {
free(c->reason);
c->reason = NULL;
}
va_start(args, why);
vsnprintf( buf, BUFLEN, why, args );
@ -10671,9 +10709,7 @@ void unmakemap(map_t *map) {
if (db) dblog(" %d linked regions removed.", nreg);
// free cells on this map
for (i = 0; i < (map->w*map->h); i++){
killcell(map->cell[i]);
free(map->cell[i]);
map->cell[i] = NULL;
killcell(&(map->cell[i]));
}
}

5
map.h
View File

@ -21,6 +21,7 @@ int cellmeetscondition(cell_t *c, enum CELLCONDITION cond, int arg, int value);
int cellmeets(cell_t *c, condset_t *cs);
int cellokforreachability(cell_t *startcell, cell_t *c, int srcroomid, int dir, int wantfilled, int *insameroom, char *why);
enum CELLTYPE celltypefromvault(cell_t *c);
void clearcellstrings(cell_t *c);
void clearcell(cell_t *c);
void clearcell_exceptflags(cell_t *c, ...);
int delve(map_t *map, int neighbourmin, int neighbourmax, int connchance, int chancepct, int newneighbourmin, int newneighbourmax, int newconnchance, enum CELLTYPE empty, enum CELLTYPE solid);
@ -164,7 +165,7 @@ lifeform_t *haslf(cell_t *c);
int hasknownobject(cell_t *c);
int hasobject(cell_t *c);
vault_t *maphasvault(map_t *m, char *id);
object_t *hastrailof(obpile_t *op, lifeform_t *lf, enum OBTYPE oid, flag_t **tflag, lifeform_t *viewer);
object_t *hastrailof(obpile_t *op, lifeform_t *lf, int oid, flag_t **tflag, lifeform_t *viewer);
void initmap(void);
void initmaplayout(void);
int isadjacent(cell_t *src, cell_t *dst);
@ -183,7 +184,7 @@ int isoutdoors(map_t *m);
int isroom(cell_t *c);
int issolid(cell_t *c);
int iswallindir(cell_t *cell, int dir);
void killcell(cell_t *c);
void killcell(cell_t **c);
void killcelltype(celltype_t *ct);
void killfakes(map_t *map, cell_t *cell);
void killmap(map_t *m);

25
move.c
View File

@ -574,6 +574,7 @@ int dorandommove(lifeform_t *lf, int badmovesok, int restonfail, int strafe) {
if (lfhasflag(lf, F_DOESNTMOVE)) {
rest(lf, B_TRUE);
return B_TRUE;
}
@ -582,6 +583,7 @@ int dorandommove(lifeform_t *lf, int badmovesok, int restonfail, int strafe) {
moveok = canandwillmove(lf, dir, &why);
if (!moveok && badmovesok) {
switch (why) {
// actually okay to move into someone
@ -619,6 +621,7 @@ int dorandommove(lifeform_t *lf, int badmovesok, int restonfail, int strafe) {
origtimespent = lf->timespent;
rv = trymove(lf, dir, B_TRUE, strafe);
if (restonfail && (rv || (lf->timespent == origtimespent))) {
// ie move failed
rest(lf, B_TRUE);
@ -639,7 +642,7 @@ int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int d
int dist[MAXDIR_COMPASS];
int poss[MAXDIR_COMPASS];
int nposs;
enum ERROR error;
enum ERROR error = E_OK;
if (dirtype == DT_ORTH) {
maxdist = getcelldistorth(src, dst);
@ -960,8 +963,11 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
case E_OBINWAY:
case E_DOORINWAY:
if (reason == E_WALLINWAY) {
if (newcell) strcpy(thing, newcell->type->name);
else strcpy(thing, "wall");
if (newcell) {
snprintf(thing, BUFLEN, "%s %s", needan(newcell->type->name) ? "an" : "a",newcell->type->name);
} else {
strcpy(thing, "a wall");
}
} else { // ie door or object
getobname(rdata, thing, 1);
}
@ -1486,7 +1492,8 @@ int movelf(lifeform_t *lf, cell_t *newcell, int onpurpose) {
char *newname;
// we want 'xx steps on some pieces of broken glass'
// not 'xx steps on 5 pieces of broken glass'
newname = makeplural(obname);
newname = strdup(obname);
makeplural(&newname);
strrep(&newname, "a ", "some ", NULL);
strcpy(obname, newname);
free(newname);
@ -1655,7 +1662,7 @@ int movelf(lifeform_t *lf, cell_t *newcell, int onpurpose) {
lf->race->known = B_TRUE;
rc = findraceclass(lf->race->raceclass->id);
if (rc) {
practice(lf, getskill(lf, rc->skill), 2);
practice(lf, rc->skill, 2);
}
}
}
@ -1910,7 +1917,6 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
}
}
// maybe make some noise
// (stealth check to avoid this)
willmakenoise = B_TRUE;
@ -3502,7 +3508,11 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
taketime(lf, getmovespeed(lf));
} else {
if (!onpurpose || canandwillmove(lf, dir, &errcode)) {
return attackcell(lf, cell, B_FALSE);
int forceattack = B_FALSE;
if (lfhasflag(lf, F_RAGE)) {
forceattack = B_TRUE;
}
return attackcell(lf, cell, forceattack);
} else {
// won't attack for some reason.
return B_TRUE;
@ -3561,7 +3571,6 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
}
}
// purposely moving away from money?
if (onpurpose && isplayer(lf) && srcmoney) {
angergodmaybe(R_GODTHIEVES, srcmoney, GA_MONEY);

51
nexus.c
View File

@ -128,6 +128,8 @@ extern int statdirty;
int needredraw = B_TRUE;
int numdraws = 0;
int flagcheck = B_FALSE;
// for xp list debugging
extern race_t **raceposs;
extern int *xpposs;
@ -844,7 +846,7 @@ void checkendgame(void) {
}
void cleanup(void) {
//int i;
int i;
gamemode = GM_CLEANUP;
free(xpposs);
@ -875,13 +877,11 @@ void cleanup(void) {
while (firstpoisontype) killpoisontype(firstpoisontype);
// free celltypes
while (firstcelltype) killcelltype(firstcelltype);
/*
// free npcname strings
for (i = 0; i < numnpcnames; i++) {
// free npcnames
free(npcname[i].name);
free(&npcname[i]);
}
*/
// free npcname structures
free(npcname);
// free hidden names
while (firsthiddenname) killhiddenname(firsthiddenname);
@ -960,7 +960,7 @@ void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, in
void donextturn(map_t *map) {
lifeform_t *who;
lifeform_t *who,*l;
int db = B_FALSE;
map_t *oldpmap;
@ -968,8 +968,10 @@ void donextturn(map_t *map) {
who = map->lf;
if (who) {
if (db) dblog("**** donextturn for: id %d %s", who->id, who->race->name);
checkflagpile(who->flags);
if (who->timespent > 0) {
// shuffling lf times...
@ -1355,8 +1357,13 @@ void donextturn(map_t *map) {
if (getoption(OPT_TIMEDEBUG)) {
dbtimeendlf(who);
}
checkflagpile(who->flags);
} // end 'if (who)'
for (l = map->lf ; l ; l = l->next) {
checkflagpile(l->flags);
}
if (isplayer(who)) {
// in order to force the player's turn to be first,
// monsters will not take any actions until
@ -1367,6 +1374,7 @@ void donextturn(map_t *map) {
// check for death etc
checkdeath();
//////////////////////////////////
// effects which happen every GAME TICK
// ie. object hp drain etc
@ -1378,6 +1386,7 @@ void donextturn(map_t *map) {
//timeeffectsworld(player->cell->map);
timeeffectsworld(map, B_TRUE);
// the previous call to timeeffectsworld might cause the player to
// change levels (ie. falling down through one or more pits).
//
@ -1836,10 +1845,12 @@ int loadnpcnames(void) {
if (!f) return B_TRUE;
// count lines...
fgets(buf, BUFLEN, f);
fgets(buf, BUFLEN, f); // VALGRIND: memleak here
numnpcnames = 0;
while (!feof(f)) {
buf[strlen(buf)-1] = '\0'; // strip newline
if (strlen(buf)) {
buf[strlen(buf)-1] = '\0'; // strip newline
}
if (strlen(buf)) {
numnpcnames++;
}
@ -1847,7 +1858,8 @@ int loadnpcnames(void) {
}
// alloc mem
npcname = malloc(numnpcnames * sizeof(npcname_t));
//npcname = malloc(numnpcnames * sizeof(npcname_t));
npcname = calloc(numnpcnames, sizeof(npcname_t));
// back to start
fseek(f, 0, SEEK_SET);
@ -1855,7 +1867,9 @@ int loadnpcnames(void) {
// now read in names
fgets(buf, BUFLEN, f);
while (!feof(f)) {
buf[strlen(buf)-1] = '\0'; // strip newline
if (strlen(buf)) {
buf[strlen(buf)-1] = '\0'; // strip newline
}
if (strlen(buf)) {
capitalise(buf);
npcname[i].name = strdup(buf);
@ -2165,7 +2179,7 @@ void setcurtime(int hours, int minutes) {
void timeeffectsworld(map_t *map, int updategametime) {
flag_t *retflag[MAXCANDIDATES];
int nretflags;
lifeform_t *l;
lifeform_t *l,*nextl;
int db = B_FALSE;
object_t *o,*nexto;
int x,y;
@ -2192,6 +2206,13 @@ void timeeffectsworld(map_t *map, int updategametime) {
//if (db) dblog("timespent = %d\n", timespent);
if (db) dblog("firstlftime = %d\n", firstlftime);
/*
for (l = map->lf ; l ; l = nextl) {
nextl = l->next;
checkflagpile(l->flags);
}
*/
if (firstlftime > 0) {
if (db) dblog("making firstlf timespent = 0 (currently %d):", firstlftime);
@ -2253,7 +2274,6 @@ void timeeffectsworld(map_t *map, int updategametime) {
obsfallthrough(c, pit);
}
// go through each object in the cell...
for (o = c->obpile->first ; o ; o = nexto) {
nexto = o->next;
@ -2301,11 +2321,12 @@ void timeeffectsworld(map_t *map, int updategametime) {
killflagsofid(map->flags, F_NEWWATERDEPTH);
redrawresume();
// now handle effects on lifeforms and/or their objects
for (l = map->lf ; l ; l = l->next) {
checkflagpile(l->flags);
for (l = map->lf ; l ; l = nextl) {
nextl = l->next;
checkflagpile(l->flags);
timeeffectslf(l);
checkflagpile(l->flags);
}
// time out warnings

183
objects.c
View File

@ -282,6 +282,7 @@ brand_t *addbrand(enum BRAND id, char *suffix, enum BODYPART bp, enum BLESSTYPE
// props
a->id = id;
a->bp = bp;
a->description = NULL;
snprintf(buf, BUFLEN, " %s",suffix);
a->suffix = strdup(buf);
a->blessed = blessed;
@ -356,7 +357,7 @@ hiddenname_t *addhiddenname(enum OBCLASS obclass, char *text) {
return a;
}
knowledge_t *addknowledge(enum OBCLASS id, char *hiddenname, int known) {
knowledge_t *addknowledge(enum OBTYPE id, char *hiddenname, int known) {
knowledge_t *a;
// add to the end of the list
@ -522,6 +523,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
int jamchance = 0;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
lifeform_t *firstlf;
if (player) firstlf = player->cell->map->lf;
else firstlf = NULL;
// just in case we don't add any
addedob[0] = NULL;
@ -675,8 +680,14 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
// might not be the case if it was part of the object name
// eg. "waist-deep water"
if (bonus) {
int charsremoved;
while (*bonusend == ' ') bonusend++; // go past spaces
strcpy(bonusstart, bonusend);
// using memmove instead
//strcpy(bonusstart, bonusend);
memmove(bonusstart, bonusend, strlen(bonusend));
charsremoved = strlen(bonusstart) - strlen(bonusend);
// NUL out remainder of buffer
p[strlen(p) - charsremoved] = '\0';
}
}
@ -980,9 +991,19 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
char racename[BUFLEN];
p2 = strstr(p, "corpse");
len = p2 - p;
snprintf(racename, len, "%s",p);
assert (len >= 0);
corpserace = findracebyname(racename, NULL);
if (len == 0) {
// eg. "corpse"
cell_t *c;
c = getobpilelocation(where);
corpserace = getrandomrace(c, NA, NULL);
} else {
// eg. "goblin corpse"
snprintf(racename, len, "%s",p);
assert(strlen(racename) > 0);
corpserace = findracebyname(racename, NULL);
}
ot = findot(OT_CORPSE);
} else if (strstr(p, "map to ")) {
branch_t *rt;
@ -1053,6 +1074,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
}
} else {
killflagpile(wantflags);
if (localname) free(localname);
return NULL;
}
@ -1065,16 +1087,25 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
pp = p + strlen("generator \"");
pp = readuntil(tempbuf, pp, ',');
if (pp) strcpy(whattomake, tempbuf);
else return NULL;
if (!pp) {
if (localname) free(localname);
return NULL;
}
strcpy(whattomake, tempbuf);
pp = readuntil(tempbuf, pp, ',');
if (pp) radius = atoi(tempbuf);
else return NULL;
if (!pp) {
if (localname) free(localname);
return NULL;
}
radius = atoi(tempbuf);
pp = readuntil(tempbuf, pp, '"');
if (pp) pct = atoi(tempbuf);
else return NULL;
if (!pp) {
if (localname) free(localname);
return NULL;
}
pct = atoi(tempbuf);
addflag(wantflags, F_GENERATES, pct, radius, NA, whattomake);
@ -1236,6 +1267,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
if (db) dblog("DB: No match for object name '%s'", p );
nretobs = 0;
killflagpile(wantflags);
if (localname) free(localname);
return NULL;
}
}
@ -1292,6 +1325,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
if (db) dblog("DB: trying to add >1 ONEPERCELL object to a cell. (%s) bailing out.", ot->name);
nretobs = 0;
killflagpile(wantflags);
if (localname) free(localname);
return NULL;
}
}
@ -1311,6 +1346,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
if (db) dblog("DB: Cannot give a spell object to a player, or a cell! object name '%s'", ot->name );
nretobs = 0;
killflagpile(wantflags);
if (localname) free(localname);
return NULL;
}
}
@ -1340,6 +1377,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
if (db) dblog("DB: trying to give NOPICKUP object '%s' to a lifeform ('%s').", ot->name, where->owner->race->name );
nretobs = 0;
killflagpile(wantflags);
if (localname) free(localname);
return NULL;
}
@ -1367,6 +1406,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
if (db) dblog("DB: Unique ob %s already exists!", ot->name );
nretobs = 0;
killflagpile(wantflags);
if (localname) free(localname);
return NULL;
}
@ -1401,11 +1442,13 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
for (i = 0; i < howmany; i++) {
int added = B_FALSE;
if (canstack) {
object_t *existob;
if (db) dblog("DB: Looking for stacks...");
// TODO: if object is stackable
// TODO: if (hasflag(ob,stackable) && hasobject(where, ot)) {
// TODO: if (hasflag(ob,stackable) && hasobject(where, ot)) brace
// does the pile already contain one?
existob = canstacknewot(where, ot);
if (existob) {
@ -3796,15 +3839,6 @@ void explodeob(object_t *o, flag_t *f, int bigness, lifeform_t *causedby) {
char obname[BUFLEN];
object_t *outerob;
// override causedby
if (!causedby) {
flag_t *f;
f = hasflag(o->flags, F_THROWNBY);
if (f) {
causedby = findlf(c->map, f->val[0]);
}
}
dam = roll(f->text);
// inside a container? if so, it's the container
@ -3816,6 +3850,15 @@ void explodeob(object_t *o, flag_t *f, int bigness, lifeform_t *causedby) {
}
c = getoblocation(outerob);
// override causedby
if (!causedby) {
flag_t *f;
f = hasflag(o->flags, F_THROWNBY);
if (f) {
causedby = findlf(c->map, f->val[0]);
}
}
getobname(outerob, obname, outerob->amt);
// announce
@ -3925,6 +3968,7 @@ objecttype_t *findotn(char *name) {
knowledge_t *k;
char *modname;
char *p;
char *tempstr;
int db = B_FALSE;
brand_t *om;
@ -3966,17 +4010,21 @@ objecttype_t *findotn(char *name) {
// skip past bonusses
p = strchr(modname, '+');
if (p) {
while (!isalpha(*p)) {
while (*p && !isalpha(*p)) {
p++;
}
strcpy(modname, p);
tempstr = strdup(p);
strcpy(modname, tempstr);
free(tempstr);
}
p = strchr(modname, '-');
if (p) {
while (!isalpha(*p)) {
p++;
}
strcpy(modname, p);
tempstr = strdup(p);
strcpy(modname, tempstr);
free(tempstr);
}
if (db) dblog("findotn(): modname is '%s'",modname);
@ -6264,10 +6312,9 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
pluralname = strdup(basename);
} else {
// multiple objects?
if (hasflag(o->flags, F_NO_PLURAL)) {
pluralname = strdup(basename);
} else {
pluralname = makeplural(basename);
pluralname = strdup(basename);
if (!hasflag(o->flags, F_NO_PLURAL)) {
makeplural(&pluralname);
}
}
@ -6409,8 +6456,9 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
} else if (where) {
celltype_t *ct;
ct = findcelltype(getmapsolid(where->map));
free(pluralname);
// solid cell description
strcpy(pluralname, ct->name);
pluralname = strdup(ct->name);
}
}
@ -6852,7 +6900,7 @@ objecttype_t *real_getrandomob(cell_t *cell, char *buf, int forcedepth, int forc
flag_t *f;
int db = B_FALSE;
int partdb = B_FALSE;
char *pluralname;
char *pluralname = NULL;
char brandname[BUFLEN];
char cursestr[BUFLEN];
int raritymin,raritymax;
@ -6866,7 +6914,7 @@ objecttype_t *real_getrandomob(cell_t *cell, char *buf, int forcedepth, int forc
char habname[BUFLEN];
int rrmoddir = -1;
int brandchance;
enum OBTYPE wantcl = OC_NONE;
enum OBCLASS wantcl = OC_NONE;
int multiwantcl = B_FALSE;
if (!db) db = obdb;
@ -6885,8 +6933,7 @@ objecttype_t *real_getrandomob(cell_t *cell, char *buf, int forcedepth, int forc
strcpy(habname, "(any)");
}
//if (forcedepth != NA) {
if (forcedepth >= 0) {
if (forcedepth >= 0) { // WAS: if (forcedepth != NA)
depth = forcedepth;
} else if (cell) {
depth = getmapdifficulty(cell->map);
@ -6997,8 +7044,12 @@ objecttype_t *real_getrandomob(cell_t *cell, char *buf, int forcedepth, int forc
if ((rarnum >= raritymin) && (rarnum <= raritymax)) {
// now check common, rare, etc
enum RARITY thisrr;
thisrr = rarflag->val[2];
if (thisrr == NA) thisrr = RR_FREQUENT;
if (rarflag->val[2] == NA) {
thisrr = RR_FREQUENT;
} else {
thisrr = rarflag->val[2];
}
if (thisrr == wantrr) {
rarok = B_TRUE;
@ -7090,12 +7141,6 @@ objecttype_t *real_getrandomob(cell_t *cell, char *buf, int forcedepth, int forc
amt = 1;
}
if (amt > 1) {
pluralname = makeplural(ot->name);
} else {
pluralname = strdup(ot->name);
}
// chance to be blessed or cursed? 15% chance each way
strcpy(cursestr, "");
if (!hasflag(ot->flags, F_NOBLESS) && !hasflag(ot->flags, F_STARTSPLAIN)) {
@ -7178,6 +7223,12 @@ objecttype_t *real_getrandomob(cell_t *cell, char *buf, int forcedepth, int forc
if (br) strcpy(brandname, br->suffix);
}
pluralname = strdup(ot->name);
if (amt > 1) {
makeplural(&pluralname);
}
snprintf(buf, BUFLEN, "%d %s%s%s", amt, cursestr, pluralname,brandname);
if (db || partdb) dblog("random ob for %s: %d x %s ('%s')", habname, amt, ot->name,pluralname);
@ -8054,7 +8105,7 @@ int isimpassableob(object_t *o, lifeform_t *lf, enum LFSIZE forcesize) {
}
if (lf) {
if ((lf->race->raceclass->id == RC_UNDEAD)) {
if (lf->race->raceclass->id == RC_UNDEAD) {
if (hasflagval(o->flags, F_REPELBLESSED, B_CURSED, NA, NA, NULL)) {
return B_TRUE;
}
@ -8216,6 +8267,13 @@ int isvalidoverridemat(enum MATERIAL mat) {
return B_FALSE;
}
int isinroof(object_t *o) {
if (hasflagval(o->flags, F_PIT, D_UP, NA, NA, NULL) || (o->type->id == OT_GRATINGROOF)) {
return B_TRUE;
}
return B_FALSE;
}
int isoperable(object_t *o) {
if (hasflag(o->flags, F_OPERABLE)) return B_TRUE;
//if (o->type->obclass->id == OC_TECH) return B_TRUE;
@ -8558,9 +8616,13 @@ void killob(object_t *o) {
void killobmod(obmod_t *om) {
obmod_t *nextone, *lastone;
int i;
// free mem
if (om->prefix) free(om->prefix);
for (i = 0; i < om->naltprefix; i++) {
free(om->altprefix[i]);
}
killflagpile(om->flags);
// remove from list
@ -12221,7 +12283,7 @@ void quaff(lifeform_t *lf, object_t *o) {
int willid = B_FALSE;
int playercansee;
int forcedrop = B_FALSE;
int seen;
int seen = B_FALSE;
int killobwhendone = B_TRUE;
flag_t *drinkflag;
enum OBTYPE realobid = OT_NONE;
@ -12385,6 +12447,7 @@ void quaff(lifeform_t *lf, object_t *o) {
// o can be NULL if we're just doing potion EFFECTS, not actually drinking one.
void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE potblessed, int *seen) {
char lfname[BUFLEN];
char origstats[BUFLEN];
int dam;
int i;
int first,dir;
@ -12620,13 +12683,15 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
break;
case OT_POT_GROWTH:
i = getlfsize(lf);
sprintf(origstats, "%d,%d", lf->att[A_STR], lf->maxhp);
if (iscursed(o)) {
dospelleffects(lf, OT_S_SIZEDOWN, 1, lf, NULL, lf->cell, B_UNCURSED, seen, B_TRUE, NULL);
} else {
dospelleffects(lf, OT_S_SIZEUP, 1, lf, NULL, lf->cell, B_UNCURSED, seen, B_TRUE, NULL);
}
// revert in a little while...
addflag(lf->flags, F_SIZETIMER, i, rnd(10,20), NA, NULL);
addflag(lf->flags, F_SIZETIMER, i, rnd(10,20), NA, origstats);
break;
case OT_POT_HEALING:
dospelleffects(lf, OT_S_HEALING,potblessed ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE, NULL);
@ -12744,7 +12809,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
cell_t *c;
c = getcellindir(lf->cell, dir);
if (c && !c->type->solid) {
object_t *newob;
object_t *newob = NULL;
// get lifeforms out of the way
if (c->lf) {
@ -12754,17 +12819,19 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
if (!c->lf) {
newob = addob(c->obpile, "magical barrier");
if (first && haslos(player, c)) {
msg("A magical barrier appears!");
first = B_FALSE;
if (newob) {
if (first && haslos(player, c)) {
msg("A magical barrier appears!");
first = B_FALSE;
}
// it will disappear eventually
//addflag(newob->flags, F_OBHP, i, i, NA, NULL);
//addflag(newob->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
//addflag(newob->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(newob->flags, F_CREATEDBY, lf->id, NA, NA, NULL);
}
}
// it will disappear eventually
//addflag(newob->flags, F_OBHP, i, i, NA, NULL);
//addflag(newob->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
//addflag(newob->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(newob->flags, F_CREATEDBY, lf->id, NA, NA, NULL);
}
}
break;
@ -13581,8 +13648,12 @@ int readsomething(lifeform_t *lf, object_t *o) {
}
object_t *relinkob(object_t *src, obpile_t *dst) {
/*
if (!obfits(src, dst)) return NULL;
if (isdeadob(src)) return NULL;
*/
if (!obfits(src, dst)) return src;
if (isdeadob(src)) return src;
if (src->pile->owner) {
// previous owner loses all flags conferred by this object
@ -13605,7 +13676,7 @@ object_t *relinkob(object_t *src, obpile_t *dst) {
// this might have killed the object - eg. unequipping
// a summoned energy blade.
if (isdeadob(src)) {
return NULL;
return src; // was null
}
}
@ -13620,8 +13691,6 @@ object_t *relinkob(object_t *src, obpile_t *dst) {
src->letter = getnextletter(dst, &src->letter);
}
// unlink this object from the current list
if (src->prev == NULL) {
// first
@ -13652,7 +13721,6 @@ object_t *relinkob(object_t *src, obpile_t *dst) {
aa->next = src;
}
dst->last = src;
src->pile = dst;
src->next = NULL;
@ -13831,6 +13899,7 @@ int setcolfromhiddenname(flagpile_t *fp, char *text, int defaultglyph) {
int sethiddenname(objecttype_t *ot, char *text) {
// add knowledge for it (unless it's a book)
if (ot->obclass->id != OC_BOOK) {
//addknowledge(ot->obclass->id, text, B_UNKNOWN);
addknowledge(ot->id, text, B_UNKNOWN);
}
@ -16302,7 +16371,7 @@ void timeeffectsob(object_t *o) {
contagious = B_TRUE;
}
// turn into a zombified version of itself.
lf = makezombie(o, 10, revivetext, lf); // this will do the announcement
lf = makezombie(o, 10, revivetext, NULL); // this will do the announcement
if (lf && contagious) {
addflag(lf->flags, F_HITCONFER, F_REVIVETIMER, SC_POISON, 165, NULL);
addflag(lf->flags, F_HITCONFERVALS, 0, 1, R_ZOMBIECON, "rises up as a zombie!");

View File

@ -5,7 +5,7 @@
brand_t *addbrand(enum BRAND id, char *suffix, enum BODYPART bp, enum BLESSTYPE blessed, int blesschance);
object_t *addemptyob(obpile_t *where, object_t *o);
hiddenname_t *addhiddenname(enum OBCLASS obclass, char *text);
knowledge_t *addknowledge(enum OBCLASS id, char *hiddenname, int known);
knowledge_t *addknowledge(enum OBTYPE id, char *hiddenname, int known);
material_t *addmaterial(enum MATERIAL id, char *name, float weightrating);
objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, int glyph, int glyphcolour, enum RARITY rarity);
void addocnoun(objectclass_t *oc, char *text);
@ -217,6 +217,7 @@ int ismeleeweapon(object_t *o);
int ismetal(enum MATERIAL mat);
int isthrowmissile(object_t *o);
int isvalidoverridemat(enum MATERIAL mat);
int isinroof(object_t *o);
int isoperable(object_t *o);
int isplainob(object_t *o);
int ispourable(object_t *o);

View File

@ -578,6 +578,7 @@ enum SHOPRETURN shopdonate(lifeform_t *lf, object_t *vm, int starty, char *topte
return SR_BACK;
}
angergodmaybe(R_GODTHIEVES, 10, GA_MONEY);
more();
return SR_CONTINUE;
}

109
spell.c
View File

@ -216,7 +216,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (npossible >= 2) {
char ptext[BUFLEN],buf[BUFLEN];
char *p;
p = makeplural(tempot->name);
p = strdup(tempot->name);
makeplural(&p);
sprintf(ptext, "How many %s will you build (max %d)", p, npossible);
free(p);
askstring(ptext, '?', buf, BUFLEN, "1");
@ -392,7 +393,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
lifeform_t *inway = NULL, *movedlf = NULL;
cell_t *c;
object_t *stairs;
int stairdir;
int stairdir, needsclimb = B_FALSE;
char climbprompt[BUFLEN];
if (!isplayer(user)) {
return B_FALSE;
@ -411,6 +413,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_TRUE;
}
// are stairs on the roof?
if (isinroof(stairs) && !canreachroof(user)) {
needsclimb = B_TRUE;
snprintf(climbprompt, BUFLEN, "Climb to check %%s");
}
// how can we check the stairs?
getobname(stairs, obname, 1);
sprintf(buf, "How will you check %s", obname);
@ -423,10 +432,21 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
addchoice(&prompt, 'l', "Listen for sounds", NULL, NULL, NULL);
}
if ((getskill(user, SK_PERCEPTION)) && !isblind(user)) {
addchoice(&prompt, 'f', "Check for footprints", NULL, NULL, NULL);
if (needsclimb) {
addchoice(&prompt, 'f', "Check for footprints (requires climbing)", NULL, NULL, NULL);
snprintf(climbprompt, BUFLEN, "Climb to check %%s for footprints");
} else {
addchoice(&prompt, 'f', "Check for footprints", NULL, NULL, NULL);
}
}
if (getskill(user, SK_STEALTH) >= PR_SKILLED) {
addchoice(&prompt, 'p', "Peek at the other end", NULL, NULL, NULL);
if (needsclimb) {
addchoice(&prompt, 'p', "Peek at the other end (requires climbing)", NULL, NULL, NULL);
snprintf(climbprompt, BUFLEN, "Climb to peek through %%s");
} else {
addchoice(&prompt, 'p', "Peek at the other end", NULL, NULL, NULL);
}
}
if (lfhasflag(user, F_ENHANCESMELL)) {
addchoice(&prompt, 's', "Sniff for scents", NULL, NULL, NULL);
@ -444,6 +464,14 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_TRUE;
}
if (needsclimb) {
// must try to climb first.
if (asktoclimb(stairs, climbprompt)) {
// failed
return B_TRUE;
}
}
// announce the check, so that the player has feedback
// if map generation takes a while.
if (ch == 'd') {
@ -625,7 +653,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (slev >= PR_EXPERT) {
char *newtext;
if (movetextcount[n] > 1) {
newtext = makeplural(movetext[n]);
newtext = strdup(movetext[n]);
makeplural(&newtext);
msg("You can hear %s%s.", amttext, noprefix(newtext));
free(newtext);
} else {
@ -637,6 +666,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// free this mem
free(movetext[n]);
}
} else {
msg("You don't hear anything unusual.");
}
@ -699,7 +729,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
if (smellcount[n] > 1) {
newtext = makeplural(smellrace[n]->name);
newtext = strdup(smellrace[n]->name);
makeplural(&newtext);
msg("You can smell %s%s.", amttext, newtext);
free(newtext);
} else {
@ -816,7 +847,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (ch == 'p') {
// if we peeked, then we have to redraw now.
setlosdirty(user);
msg("You return to your original position.");
if (needsclimb) {
msg("You drop to the ground.");
} else {
msg("You return to your original position.");
}
} else if (needsclimb) {
msg("You drop to the ground.");
}
taketime(user, getactspeed(user)*2);
@ -3939,11 +3976,14 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// skillcheck...
f = hasflag(o->flags, F_RARITY);
if (f) {
rarity = f->val[2];
if (f->val[2] == NA) {
rarity = RR_COMMON;
} else {
rarity = f->val[2];
}
} else {
rarity = 0;
}
if (rarity == NA) rarity = RR_COMMON;
difficulty = 120 + (rarity*10);
/*
switch (o->type->obclass->id) {
@ -6514,7 +6554,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
// use direct damage rather than holy, because otherwise it might be increased
// due to vulnerabilities
losehp(target, roll("3d6" + power), DT_DIRECT, caster, "disruption");
losehp(target, roll("3d6") + power, DT_DIRECT, caster, "disruption");
} else if (spellid == OT_S_DISORIENT) {
target = targcell->lf;
@ -6949,7 +6989,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("^%cYou blast %s%s brain cells!", getlfcol(target, CC_VBAD),
lfname, getpossessive(lfname));
}
if (!ischarmable(target) && (reason != F_CHARMEDBY) && (reason != E_LOWIQ)) {
if (!ischarmable(target) && (reason != E_ALREADYUSING) && (reason != E_LOWIQ)) {
if (isplayer(caster)) {
char tname[BUFLEN];
getlfname(target, tname);
@ -8815,7 +8855,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
if (getattrbracket(getattr(target, A_IQ), A_IQ, NULL) <= AT_VLOW) {
fail = B_TRUE;
} else if (!ischarmable(target) && (reason != F_CHARMEDBY)) {
} else if (!ischarmable(target) && (reason != E_ALREADYUSING)) {
fail = B_TRUE;
}
if (fail) {
@ -9072,7 +9112,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
enum OBTYPE newoid = OT_NONE;
enum LFSIZE newsize = SZ_ANY;
enum CELLTYPE newcelltype = CT_NONE;
skill_t *obsk = SK_NONE;
skill_t *obsk = NULL;
char obname[BUFLEN],newobname[BUFLEN];
int seen;
@ -9161,7 +9201,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
char obtocreate[BUFLEN];
enum LFSIZE newsize = SZ_ANY;
enum CELLTYPE newcelltype = CT_NONE;
skill_t *obsk = SK_NONE;
skill_t *obsk = NULL;
char obname[BUFLEN],newobname[BUFLEN];
int seen;
@ -9790,7 +9830,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// not smart enough
if (iqb <= AT_EXLOW) {
fail = B_TRUE;
} else if (!ischarmable(target) && (reason != F_CHARMEDBY)) {
} else if (!ischarmable(target) && (reason != E_ALREADYUSING)) {
fail = B_TRUE;
}
@ -12514,7 +12554,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
*/
// for each cell we can see... (including our own)
// for each cell we can see... (including our own, but don't affect our own weapon)
for (i = 0; i < caster->nlos; i++) {
c = caster->los[i];
if (c->lf && cansee(caster, c->lf) && (c->lf != caster)) {
@ -13102,7 +13142,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
lifeform_t *lf;
if (caster && !isplayer(caster) && cansee(player, caster)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
getlfname(caster, lfname);
msg("%s glows brightly with the essense of life!", lfname);
}
if (!target) {
@ -13308,7 +13348,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (ngot == 1) {
msg("%s %s appears near %s!", needan(r->name) ? "An" : "A", r->name, castername);
} else {
msg("%s appear around %s!", makeplural(r->name), castername);
char *plur;
plur = strdup(r->name);
makeplural(&plur);
msg("%s appear around %s!", plur, castername);
free(plur);
}
} else {
raceclass_t *rc;
@ -13316,7 +13360,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (ngot == 1) {
msg("%s %s appears near %s!", needan(rc->name) ? "An" : "A", rc->name, castername);
} else {
msg("%s appear around %s!", makeplural(rc->name), castername);
char *plur;
plur = strdup(rc->name);
makeplural(&plur);
msg("%s appear around %s!", plur, castername);
free(plur);
}
}
}
@ -13938,12 +13986,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int appearonground = B_FALSE;
if (!target) target = caster;
initprompt(&prompt, "For what do you wish?");
addchoice(&prompt, 'a', "Wealth", NULL, NULL, NULL);
addchoice(&prompt, 'b', "Power", NULL, NULL, NULL);
addchoice(&prompt, 'c', "Protection", NULL, NULL, NULL);
addchoice(&prompt, 'd', "Fame", NULL, NULL, NULL);
addchoice(&prompt, 'e', "Knowledge", NULL, NULL, NULL);
addchoice(&prompt, 'f', "Magic", NULL, NULL, NULL);
addchoice(&prompt, 'a', "Wealth (riches beyond your imagination)", NULL, NULL, NULL);
addchoice(&prompt, 'b', "Power (an item with which to smite your foes)", NULL, NULL, NULL);
addchoice(&prompt, 'c', "Protection (an item to defend against harm)", NULL, NULL, NULL);
addchoice(&prompt, 'd', "Fame (followers to obey your every whim)", NULL, NULL, NULL);
addchoice(&prompt, 'e', "Knowledge (identify everything and more)", NULL, NULL, NULL);
addchoice(&prompt, 'f', "Magic (books full of arcane writings)", NULL, NULL, NULL);
addchoice(&prompt, '-', "(nothing)", NULL, NULL, NULL);
if (isplayer(target)) {
ch = getchoice(&prompt);
@ -14088,7 +14136,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
strcpy(buf, "");
} else if (ch == 'e') { // knowledge (makeknown everything you have plus 5-10 others. bad: insanity)
} else if (ch == 'e') { // knowledge (makeknown everything you have plus 10% chance for everything else. bad: insanity)
// only possible for the player!
strcpy(buf, "");
if (isplayer(target)) {
@ -14115,6 +14163,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
makeknown(k->id);
}
}
msg("(check '%c' to see your knowledge)", cmdtochar(CMD_INFOKNOWLEDGE));
}
}
} else if (ch == 'f') { // magic (spellbooks), bad: gain 'explode self' magic
@ -14795,7 +14844,7 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) {
// player can only ever cast spells up to your level.
if (!hasjob(lf, J_GOD)) limit(&maxspelllevel, NA, lf->level);
if (spelllev > maxspelllevel) {
if (!willflag && (spelllev > maxspelllevel)) {
if (db) dblog("-->power = 0 (no skilled enough in spell school)");
return 0;
}
@ -14816,8 +14865,10 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) {
// plus god modifier
power += getspellpowergodmod(lf, school, NULL);
// plus any extra school levels beyond what you need
power += (schoolskill - spelllev);
if (!willflag) {
// plus any extra school levels beyond what you need
power += ((int)schoolskill - spelllev);
}
} else {
// for monsters, just based on hitdice:
power = gettr(lf)/2;

74
text.c
View File

@ -2355,39 +2355,64 @@ char *makelowercase(char *text) {
return text;
}
// allocates and returns new string
char *makeplural(char *text) {
// deallocates string, allocates a new one
char *makeplural(char **text) {
char lastlet;
char *newtext;
int rv;
int rv,len,done = B_FALSE;
plural_t *pl;
newtext = strdup(text);
assert(*text != NULL);
len = strlen(*text);
assert(len > 0);
newtext = strdup(*text); // make copy
for (pl = firstplural ; pl ; pl = pl->next) {
strrep(&newtext, pl->singular, pl->plural, &rv);
if (rv && pl->stopafter) return newtext;
if (rv && pl->stopafter) {
done = B_TRUE;
break;
}
}
// default
lastlet = text[strlen(text)-1];
switch (lastlet) {
char *temptext;
case 'y': // change to 'ies'
temptext = strdup(text);
temptext[strlen(temptext)-1] = '\0';
asprintf(&newtext, "%sies",temptext);
free(temptext);
break;
case 's':
case 'o': // append "es"
asprintf(&newtext, "%ses",text);
break;
default: // append "s"
asprintf(&newtext, "%ss",text);
break;
if (!done) {
// default
//lastlet = (*text)[len-1];
lastlet = newtext[len-1];
switch (lastlet) {
char *temptext;
case 'y': // change to 'ies'
temptext = strdup(newtext);
temptext[strlen(temptext)-1] = '\0';
free(newtext);
asprintf(&newtext, "%sies",temptext);
free(temptext);
break;
case 's':
case 'o': // append "es"
asprintf(&temptext, "%ses",newtext);
free(newtext);
newtext = strdup(temptext);
free(temptext);
break;
default: // append "s"
asprintf(&temptext, "%ss",newtext);
free(newtext);
newtext = strdup(temptext);
free(temptext);
break;
}
}
return newtext;
// 'newtext' now holdes the pluralized version of '*text'
// make original pointer large enough to hold the new version + NUL.
*text = realloc(*text, strlen(newtext)+1);
snprintf(*text, strlen(newtext)+1, "%s", newtext);
free(newtext);
return *text;
}
// throwflag should be either a F_THROWING or a F_FIRING flag.
@ -2775,9 +2800,10 @@ char *do_strrep(const char *s1, const char *s2, const char *s3) {
return 0;
char *newstr = (char *)malloc(newstr_len + 1); /* w/ terminator */
if (!newstr)
if (!newstr) {
/* ENOMEM, but no good way to signal it. */
return 0;
}
char *dst = newstr;
const char *start_substr = s1;

2
text.h
View File

@ -67,7 +67,7 @@ void killplural(plural_t *w);
void makegunaimstring(lifeform_t *lf, int lfid, char *retbuf);
char *makekillertext(char *retbuf, char *killverb, char *lastdam, map_t *where, int wantextra, int wantlocation);
char *makelowercase(char *text);
char *makeplural(char *text);
char *makeplural(char **text);
char *makethrowaccstring(lifeform_t *lf, cell_t *c, flag_t *throwflag, char *retbuf);
char *makeuppercase(char *text);
char *makewearstring(lifeform_t *lf, object_t *o, int wantyour, char *posbuf);

104
todo Normal file
View File

@ -0,0 +1,104 @@
*Fix double free and use after free in aimovetotargetcell() - this MIGHT be what's causing all my flagpile corruption.
*Fix a bunch of cases where I use a variable uninitialised.
*forgot to initialised brand->description
*free bodypart names
*free om->altprefix[]
*Invalid free / delete / realloc in clearcell()
*fix makeplural memleaks
*door displaying as "leaf" - definition of knowledge->id was OBCLASS instead of OBTYPE.
*Bad text:
* Minimum agility to use effectively: 50 to use.Minimum agility to use
* effectively: 50 to use. (bonus at 70).
*change wish text to be more meaningful
*fix bug when creating objects with a bonus (eg. blessed '+5' sword)
*when raging, don't prompt to really attack when you won't gain xp
*disable flagpile checks now.
*Use 'interact' to use shops, not 'operate'
*You are resistant to: projectiles[-7870t], explosives[-7870t].
*scorpions shouldn't follow up stairs. (but giant scorpions can)
*make failed relinkob() calls return the original object rather than null, otherwise we get situations where an object becomes NULL and causes a crash.
*make cooking skill description cover what size corpses you can cook.
*bug: potion of growth caused instadeath when reverting.
*bug in description of monster abilities
*show raceclass in descriptions
*bug: not showing monster abilites properly
*make evasion only work if you're not exhausetd
*Felix shoudl like attacking while hidden
*Not seeing felix angered messages when donating items
*holes in roof - shouldn't be able to inspect a hole in the roof if you can't reach it!
*crash when hitting @ while producing light.
Set up a GIT server on slime.
clone svn first ?
stunned mosnters shuld stop flying.
glorana sohuld get VERY happy from offering healing potions - too hard to level up right now
make it easier to slip if your'e sprinting.
no critical hits when exhausted
spiders shouldn't slip (insects in general shoudln't)
Trn:0/103% <- huh?
safety goggles should PROTECT from eye burning from light
even if you're a delver etc
more things to build!
door.
is tumble skill too hard to use ?? always seems to fail.
say in skill description whether it might fail or not.
HELP
Stunned
Prone
Poison
help on types of poison?
god help
don't worry about choosing - will approach you when the time is right.
Attack/Defense calc
Spell power calc
level of spells castable is determined by your skill inthe spell's school.
inept = 0
master = 6
power = 1
+ (level / 3)
+ modifier based on INT/WIS/STR
+ 1 per skill level beyond what you need
Help text for str, agi, fitness, etc
find proper font to use.
can wyrmspawn possible win ?
better 'inspect item' help - show which skills help
Skills screen
with --More--, have a special key to go up/down, rather than the
next keypress.
Don't show --More-- on skills screen if we're at the last one.

3
valrun Executable file
View File

@ -0,0 +1,3 @@
#valgrind --track-origins=yes --leak-check=yes --dsymutil=yes --log-file=valout ./nexus
valgrind --leak-check=yes --dsymutil=yes --log-file=valout ./nexus

21
vault.c
View File

@ -1670,17 +1670,22 @@ vault_t *loadvault(char *dir, char *filename) {
// read a line
fgets(line, BUFLEN, f);
while (!feof(f)) {
// strip newline
line[strlen(line)-1] = '\0';
// strip trailing spaces
while (line[strlen(line)-1] == ' ') {
if (strlen(line)) {
// strip newline
line[strlen(line)-1] = '\0';
// strip trailing spaces
while (strlen(line) && line[strlen(line)-1] == ' ') {
line[strlen(line)-1] = '\0';
}
}
// handle it
if (handleline(v, line)) {
goterrors = B_TRUE;
break;
// anything left?
if (strlen(line)) {
// handle it
if (handleline(v, line)) {
goterrors = B_TRUE;
break;
}
}
// read next line
fgets(line, BUFLEN, f);