nexus/vault.c

1738 lines
42 KiB
C
Raw Normal View History

2011-11-30 13:07:19 +11:00
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "defs.h"
#include "flag.h"
#include "io.h"
#include "move.h"
#include "nexus.h"
#include "lf.h"
#include "map.h"
#include "objects.h"
#include "text.h"
#include "vault.h"
vault_t *firstvault = NULL, *lastvault = NULL;
extern enum GAMEMODE gamemode;
vlegend_t *addlegend(vault_t *v, int ch, enum VAULTTHING tt, int pct, char *what) {
vlegend_t *l;
// add to the end of the list
if (v->legend == NULL) {
v->legend = malloc(sizeof(vlegend_t));
l = v->legend;
l->prev = NULL;
} else {
// go to end of list
l = v->lastlegend;
l->next = malloc(sizeof(vlegend_t));
l->next->prev = l;
l = l->next;
}
v->lastlegend = l;
l->next = NULL;
l->vault = v;
// props
l->ch = ch;
l->tt = tt;
l->pct = pct;
l->what = strdup(what);
return l;
}
vault_t *addvault(void) {
vault_t *v;
if (firstvault == NULL) {
firstvault = malloc(sizeof(vault_t));
v = firstvault;
v->prev = NULL;
} else {
// go to end of list
v = lastvault;
v->next = malloc(sizeof(vault_t));
v->next->prev = v;
v = v->next;
}
lastvault = v;
v->next = NULL;
// props
v->filename = NULL; // will be filled in during load.
v->id = NULL;
if (v == firstvault) {
v->numid = 0;
} else {
v->numid = lastvault->numid+1;
}
v->valid = B_TRUE;
v->state = VS_ALLOCATED;
v->flags = addflagpile(NULL, NULL);
* [+] let credit cards be used at some shops? * [+] bug with adding obejcts to shops - [+] issue with objects dying and killing their flagpiles - [+] A medium fire dies down a little. A medium fire is no longer glowing. - [+] shouldn't say "is no longer glowing" when we're changing the type... ? - [+] put a breakpoint on "is no longer glowing" * [+] let you bless objects using a holy circle somehow (but it might make the circle disappear?). - [+] darness bug - need to recalc light for anyone who sees a cell's lightlevel change. - [+] call more() after showing vaultentertext() - [+] remove "inspected" when you ident or makeknown an object. - [+] BUG - no objects in inventory!!!! - [+] listobs failing? mylist[0] = null. MEMLEAK - [+] finish implementing CLEANUP() - [+] crash in cleanup() -> killot() -> findleak.c_stuff while freeing STACKABLE flag from cactus fruit??? - [+] better now? - [+] now a crash freeing hiddennames! - [+] forgot to free obmods - [+] leaking approx. 1 meg per turn! - [+] where am i leaking?! maybe try valgrind or findleak.c - [+] findleak.c now finds nothing. - [+] but i am sitll leaking????? - [+] related to lifeform count. killing all but player dramatically slows it. - [+] check calclos()... looks okay. - [+] setcellknown() ?no. - [+] startlfturn?? no. - [+] remove unused "lf->viscell" - [+] when there are 2 things in a cell, say "you see x and x here." - [+] restore original stast when polymorphing back to original form!!! - [+] when making shops, pick new ones more often. - [+] change to maps: don't let vaults overlap. - [+] HARDCODE object values - [+] potions - [+] tech - [+] tools - [+] rings - [+] increase evasion skill effects - [+] changes to animradial... and animradialorth - [+] combine into one function - [+] move msg into here - [+] refs to spellcloud() - [+] refs to animradial() - [+] fire should spread onto flammable lifeforms - [+] bug: attack flurry doesn't work for monk - [+] let monsters climb even when not facing a wall? - [+] set their facing first. - [+] CRASH when you die while climbing (or on a solid cell) - [+] rings - [+] stench - [+] breath water - [+] detect life - [+] deceleration - [+] meditation - [+] reflection - [+] boost magic power - [+] education - gain xpskills more quickly - [+] crit protection - [+] greed - detect obs - [+] ivy - grows! - [+] ragefungus - bezerk spores - [+] nutter - drops peanuts - [+] dish which slightly increases maxhp (beginner level) - [+] stuffed mushroom. shiitake mushroom + bread
2011-12-08 13:55:14 +11:00
v->legend = NULL;
v->lastlegend = NULL;
2011-11-30 13:07:19 +11:00
v->map[0].mlen = 0;
v->map[0].w = 0;
v->map[0].h = 0;
v->nmaps = 0;
return v;
}
// add content to vault based on legend
void addvaultcellcontents(cell_t *c, vault_t *v, int x, int y, int rotation) {
char ch;
vlegend_t *l;
// set cell's vault id before adding anything
// this is needed for things like shopkeepers
// and shop items.
c->room->vault = v;
ch = getvaultchar(v, x, y, rotation, NULL);
// does this char give us a monster/object?
for (l = v->legend ; l ; l = l->next) {
if (l->ch == ch) {
if (rnd(1,100) <= l->pct) {
addvaultthing(c, v, l->tt, l->what);
}
}
}
}
void addvaultcontents(map_t *m, vault_t *v, int minx, int miny, int maxx, int maxy, int rotation) {
flag_t *f;
char buf[BUFLEN];
int db = B_FALSE;
int x,y;
cell_t *c;
if (db) dblog("addvaultcontenets started for vaulttype %s, version %d",v->id, rotation);
for (f = v->flags->first ; f ; f = f->next) {
if ((f->id == F_VAULTATOB) || (f->id == F_VAULTATLF) || (f->id == F_VAULTATCELL)) {
if (rnd(1,100) <= f->val[2]) {
cell_t *c;
int x,y;
getadjustedcoords(v, f->val[0], f->val[1], minx, miny, maxx, maxy, rotation, &x, &y);
c = getcellat(m, x, y);
if (c) {
enum VAULTTHING vt;
switch (f->id) {
default:
case F_VAULTATOB: vt = VT_OB; break;
case F_VAULTATLF: vt = VT_LF; break;
case F_VAULTATCELL: vt = VT_CELL; break;
}
addvaultthing(c, v, vt, f->text);
}
}
} else if (f->id == F_VAULTATONEOF) {
if (rnd(1,100) <= f->val[1]) {
int x[10],y[10];
int nposs = 0,sel;
int selx,sely;
char *p;
enum VAULTTHING vt;
// get a list of all of the possible locations for this object
p = f->text;
while (*p == '(') {
// go past '('
p++;
// get x
p = readuntil(buf, p, ',');
x[nposs] = atoi(buf);
// get y
p = readuntil(buf, p, ')');
y[nposs] = atoi(buf);
nposs++;
}
// go past whitespace - we'll end up on the thing name
while (isspace(*p)) p++;
// select random position
sel = rnd(0,nposs-1);
getadjustedcoords(v, x[sel], y[sel], minx, miny, maxx, maxy, rotation, &selx, &sely);
c = getcellat(m, selx, sely);
// get thing type
vt = f->val[0];
// add thing
addvaultthing(c, v, vt, p);
}
} else if (f->id == F_VAULTEXIT) {
cell_t *c;
int x,y;
getadjustedcoords(v, f->val[0], f->val[1], minx, miny, maxx, maxy, rotation, &x, &y);
c = getcellat(m, x, y);
if (c) {
addflag(c->map->flags, F_ROOMEXIT, getroomid(c), c->x, c->y, "from f_vaultexit");
}
} else if ( (f->id == F_VAULTBOX) && (rnd(1,100) <= f->val[1]) ) {
char *p;
char thingname[BUFLEN];
int x1,y1,x2,y2,x,y;
// get relative range
p = f->text;
p = readuntil(buf, p, ',');
x1 = atoi(buf);
p = readuntil(buf, p, ',');
y1 = atoi(buf);
/*
if (x1 < 0) x1 = maxx + x1 + 1;
else x1 += minx;
if (y1 < 0) y1 = maxy + y1 + 1;
else y1 += miny;
*/
getadjustedcoords(v, x1, y1, minx, miny, maxx, maxy, rotation, &x1, &y1);
p = readuntil(buf, p, ',');
x2 = atoi(buf);
p = readuntil(buf, p, ',');
y2 = atoi(buf);
/*
if (x2 < 0) x2 = maxx + x2 + 1;
else x2 += minx;
if (y2 < 0) y2 = maxy + y2 + 1;
else y2 += miny;
*/
getadjustedcoords(v, x2, y2, minx, miny, maxx, maxy, rotation, &x2, &y2);
// now figure out the top left and bottom right.....
getboundingbox(x1, y1, x2, y2, &x1, &y1, &x2, &y2);
p = readuntil(buf, p, ',');
strcpy(thingname,buf);
// fill in
for (y = y1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
int doit = B_FALSE;
if (f->val[2] == B_TRUE) { // ie. fill
doit = B_TRUE;
} else { // ie. box
if ((x == x1) || (x == x2) || (y == y1) || (y == y2)) {
doit = B_TRUE;
}
}
if (doit) {
cell_t *c;
c = getcellat(m, x, y);
if (c) {
// add the thing
addvaultthing(c, v, f->val[0], thingname);
}
}
}
} // end foreach x/y
} else if ( (f->id == F_VAULTSCATTER) && (rnd(1,100) <= f->val[1]) ) {
char *p;
char thingname[BUFLEN];
cell_t *poss[MAXCANDIDATES]; // TODO: should be maxroomsize
int nposs = 0;
int totcells = 0;
int i,nplaced;
int x1,y1,x2,y2,x,y;
int countmin,countmax,count;
if (db) dblog("room is %d,%d-%d,%d (%dx%d)",minx,miny,maxx,maxy,maxx-minx,maxy-miny);
// get relative range
p = f->text;
p = readuntil(buf, p, ',');
x1 = atoi(buf);
p = readuntil(buf, p, ',');
y1 = atoi(buf);
/*
if (x1 < 0) x1 = maxx + x1 + 1;
else x1 += minx;
if (y1 < 0) y1 = maxy + y1 + 1;
else y1 += miny;
*/
getadjustedcoords(v, x1, y1, minx, miny, maxx, maxy, rotation, &x1, &y1);
p = readuntil(buf, p, ',');
x2 = atoi(buf);
p = readuntil(buf, p, ',');
y2 = atoi(buf);
/*
if (x2 < 0) x2 = maxx + x2 + 1;
else x2 += minx;
if (y2 < 0) y2 = maxy + y2 + 1;
else y2 += miny;
*/
getadjustedcoords(v, x2, y2, minx, miny, maxx, maxy, rotation, &x2, &y2);
p = readuntil(buf, p, '-');
countmin = atoi(buf);
p = readuntil(buf, p, ',');
countmax = atoi(buf);
p = readuntil(buf, p, ',');
strcpy(thingname,buf);
// now figure out the top left and bottom right.....
getboundingbox(x1, y1, x2, y2, &x1, &y1, &x2, &y2);
if (db) dblog("subregion is %d,%d-%d,%d (%dx%d)",x1,y1,x2,y2,x2-x1,y2-y1);
// get list of cells
nposs = 0;
totcells = 0;
for (y = y1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
cell_t *c;
c = getcellat(m, x, y);
if (c) {
int valid = B_TRUE;
totcells++;
if (f->val[0] == VT_LF) {
// make sure it's walkable
if (!cellwalkable(NULL, c, NULL)) valid = B_FALSE;
} else if (f->val[0] == VT_OB) {
// make sure it's not solid
if (c->type->solid) valid = B_FALSE;
}
if (valid) {
poss[nposs++] = c;
}
}
}
} // end foreach x/y
if (db) dblog("cells counted=%d",totcells);
if (totcells == 0) {
dblog("PROBLEM: couldn't find place to put vaultscatter thing!");
msg("PROBLEM: couldn't find place to put vaultscatter thing!");
}
// figure out how many to place
if (countmax == PCT) {
count = pctof(countmin, nposs);
} else {
count = rnd(countmin, countmax);
}
if (db) dblog("nposs=%d, count=%d\n", nposs,count);
// now fill in the right amount
nplaced = 0;
for (i = 0; (i < count) && (nposs > 0); i++) {
cell_t *c;
int sel,n;
// get random cell
sel = rnd(0,nposs-1);
c = poss[sel];
// put the thing there
addvaultthing(c, v, f->val[0], thingname);
nplaced++;
// remove this cell
for (n = sel; n < nposs-1; n++) {
poss[n] = poss[n+1];
}
nposs--;
}
if (db) dblog("placed %d\n", nplaced);
}
}
// set vault id for each cell
for (y = miny; y <= maxy; y++) {
for (x = minx; x <= maxx; x++) {
c = getcellat(m, x, y);
if (c) {
c->room->vault = v;
}
}
}
}
int addvaultthing(cell_t *c, vault_t *v, enum VAULTTHING vt, char *what) {
celltype_t *ct;
object_t *o;
lifeform_t *lf;
int rv = B_FALSE;
switch (vt) {
case VT_EXIT:
// mark this position as a room exit
addflag(c->map->flags, F_ROOMEXIT, getroomid(c), c->x, c->y, "from addvaultthing");
break;
case VT_OB:
if (streq(what, "random")) {
o = addrandomob(c);
if (!o) {
rv = B_TRUE;
}
} else {
int placeob = B_TRUE;
// special case: ot_playerstart will only be placed if:
// - game is not already in progress
// - there isn't currently one on the level
if (streq(what, "playerstart")) {
if ((gamemode == GM_GAMESTARTED) || findobinmap(c->map, OT_PLAYERSTART)) {
placeob = B_FALSE;
}
}
if (placeob) {
o = addob(c->obpile, what);
if (!o) {
rv = B_TRUE;
}
}
}
break;
case VT_LF:
- [+] ai shuldn't want its home/life objects. - [+] lich - [+] lifeob = ornate glass jar - [+] can walk up to 12 away - [+] chilling touch - [+] mindshield - [+] teleport back to jar on death - [+] monster ghosts have lifeob = corpse, which we generate. - [+] but DONT let them possess the player ? or dont let them possess anyhting ? - [+] mosnters should say noooo! if their lifeob is destroyed - [+] lifeobs need a link back to owner f_lifeobfor xxx - [+] lifeob check wasn't including the lf's cell itself. - [+] spellcasttext for dryad - "Charm" = beckons - [+] poltergeist should be invisible - [+] troll should covet food - [+] avian - birds should be friendly - [+] scroll of permenance should make armour invulnerable - [+] amulet of mind sheild - immune to psionics - [+] parserace() shouhld handle "random _baseid_" ie. random ant, random troll etc - [+] vault: troll cave (very rare) - [+] trolls - [+] bones - [+] cooked corpses - [+] bug: minions not being created in vaults. - [+] vault: ant nest - [+] queen ant - [+] dirt floor - [+] lots of ants - [+] LOTS of food. - [+] reduce flame volume - [+] vault maintainedge not working. slightly fixed now? - [+] vampires are turning into gas clouds but then trying to attack. - [+] new amulets - [+] Of evolution (turn into a merman in deep water, aviad instead of falling, (fireres humanoid) in fire, (coldred human) in cold) - [+] in deep water and can't swim? turn into merman - [+] about to fall through a hole? turn into a flying aviad - [+] in fire and not resistant? turn into a Lavax - [+] in cold and not resistant? turn into sasquatch - [+] all polymorphs are TEMPORARY (5 turns or so). - [+] no autoid - [+] of bloodthirst - walking over blood heals you! - [+] no autoid - [+] Of graceful swimming (auto turn into a swan when you enter water) - [+] no autoid - [+] paranoia (5% chance per turn to create monsters out of sight, but in lof) - [+] they will make a "walk" noise right away - [+] or something just "you hear xxx right behind you!"
2012-03-09 06:42:25 +11:00
lf = addmonster(c, R_SPECIFIED, what, B_TRUE, 1, B_TRUE, NULL);
2011-11-30 13:07:19 +11:00
if (!lf) {
dblog("invalid racename '%s' in vault", what);
rv = B_TRUE;
}
// first lifeform in a shop is the shopkeeper
/*
2011-11-30 13:07:19 +11:00
if (lf && hasflag(v->flags, F_VAULTISSHOP)) {
if (!findshopkeeper(c->map, getroomid(c))) {
givejob(lf, J_SHOPKEEPER);
}
}
*/
if (lf && hasflag(v->flags, F_MONSTERSSTAY)) {
2011-11-30 13:07:19 +11:00
addflag(lf->flags, F_STAYINROOM, getroomid(c), NA, NA, NULL);
}
break;
case VT_CELL:
if (streq(what, "EMPTY")) {
ct = findcelltype(getmapempty(c->map));
} else if (streq(what, "SOLID")) {
ct = findcelltype(getmapsolid(c->map));
} else {
ct = findcelltypebyname(what);
}
setcelltype(c, ct ? ct->id : getmapempty(c->map));
2011-11-30 13:07:19 +11:00
break;
default:
break;
}
return rv;
}
void dumpvault(char *name, int rotation) {
int x,y;
char buf[BUFLEN];
char *p;
vault_t *v;
v = findvault(name);
if (v) {
if (rotation >= v->nmaps) {
dblog("vault dump for '%s' failed. vault exists but no such rotation %d (nmaps=%d).",name, rotation, v->nmaps);
}
dblog("start vault dump(%s,rot=%d):",v->id, rotation);
/*
// build up a temp map
for (y = 0; y < v->map[0].h; y++) {
for (x = 0; x < v->map[0].w; x++) {
int offset;
int ch;
ch = getvaultchar(v, x, y, rotation, &offset);
temp[offset] = ch;
}
}
// dump the temp map
x = 0;
y = 0;
strcpy(buf, "");
p = buf;
for (i = 0; i < v->map[rotation].mlen; i++) {
*p = temp[i];
x++;
p++;
if (x >= v->map[rotation].w) {
x = 0;
y++;
*p = '\0';
dblog("%s",buf);
strcpy(buf, "");
p = buf;
}
}
*/
strcpy(buf, "");
p = buf;
for (y = 0; y < v->map[rotation].h; y++) {
for (x = 0; x < v->map[rotation].w; x++) {
*p = getvaultchar(v, x, y, rotation, NULL);
p++;
}
*p = '\0';
dblog("%s",buf);
strcpy(buf, "");
p = buf;
}
dblog("end vault dump");
} else {
dblog("vault dump for '%s' failed. no such vault.",name);
}
}
vault_t *findvault(char *id) {
vault_t *v;
for (v = firstvault ; v ; v = v->next) {
if (!v->valid) continue;
if (streq(v->id, id)) return v;
}
return NULL;
}
vault_t *findvaultbyid(int id) {
vault_t *v;
for (v = firstvault ; v ; v = v->next) {
if (!v->valid) continue;
if (v->numid == id) return v;
}
return NULL;
}
// return a random vault with the given flag.
// don't care about rarity.
vault_t *findvaultwithflag(enum FLAG fid) {
vault_t *v;
vault_t *poss[MAXCANDIDATES];
int nposs = 0;
for (v = firstvault ; v ; v = v->next) {
if (!v->valid) continue;
if (hasflag(v->flags, fid)) poss[nposs++] = v;
}
if (nposs) {
v = poss[rnd(0,nposs-1)];
} else {
v = NULL;
}
return v;
}
- [+] allies should always give out info without payment - [+] ....but only about their home level! - [+] f_startmapid - [+] cave entrances should make noise - [+] drip - [+] echoing - [+] cope with multiple f_makesnoise flags on objects (pick one randomly) - [+] showlfstats skill display bug - "MORE" keystroke doesn't fall through. - [+] You impale the chicken! The chicken turns to face you. - [+] shouldn't turn to face if your'e dead! - [+] nulllify spell not populating seenbyplayer - [+] crash in createfakes() - [+] animals hsould still walk onto SHARP objects. - [+] secret doors showing up as empty remembered cells when you look away from them (and have lowish cartography) - [+] don't call remove_deadends on vaults. - [+] when walking down stairs to level 3: - [+] ERROR - stairs link to existing map 3('dungeon L2 (id #3)', depth 2), but it has no free stairs - [+] ie. Level 3 has too many up staircases ? no. 3 on all of them. - [+] FIXED. countstairs() was including too much. now using countmapobs(map, stairtype) instead. - [+] The goblin rogue a half-sized leather armour (null). - [+] fixed crash when you cast rage on someone who is eating. - [+] crash when catching a glowbug in a flask - [+] use canreachbp code when selecting armour to damage as well.... ie newt can't hit your helmet! - [+] BUG: "tunnel doing up" went down! - [+] for monsters:auto raise lf stats to match starting weapons - [+] crash in aigetspelltarget() for CLIMB - [+] should deactiveate all spells on polymorph - [+] allow usage of FEIGNDEATH while prone. - [+] make coprses non-stackable - [+] CRASH in animatedead - [+] shouldn't say 'you attack x from behind' if x has awareness
2012-01-06 11:20:57 +11:00
// return a random vault with the given tag (ie. f_vaulttag "xxx").
// don't care about rarity.
vault_t *findvaultwithtag(char *tag) {
vault_t *v;
vault_t *poss[MAXCANDIDATES];
int nposs = 0;
for (v = firstvault ; v ; v = v->next) {
if (!v->valid) continue;
if (hasflagval(v->flags, F_VAULTTAG, NA, NA, NA, tag)) poss[nposs++] = v;
}
if (nposs) {
v = poss[rnd(0,nposs-1)];
} else {
v = NULL;
}
return v;
}
// generate vault map 1 as x-flipped map0.
// remember offsets into map[0]
void generatevaultflipsx(vault_t *v) {
int x,y;
v->map[1].mlen = 0;
for (y = 0 ; y < v->map[0].h; y++) {
for (x = v->map[0].w-1; x >= 0; x--) {
int offset;
getvaultchar(v, x, y, 0, &offset);
v->map[1].data[v->map[1].mlen] = offset;
v->map[1].mlen++;
}
}
v->map[1].w = v->map[0].w;
v->map[1].h = v->map[0].h;
v->nmaps = 2;
}
// generate vault map 1 as y-flipped map0.
// remember offsets into map[0]
void generatevaultflipsy(vault_t *v) {
int x,y;
v->map[1].mlen = 0;
for (y = v->map[0].h-1; y >= 0; y--) {
for (x = 0 ; x < v->map[0].w; x++) {
int offset;
getvaultchar(v, x, y, 0, &offset);
v->map[1].data[v->map[1].mlen] = offset;
v->map[1].mlen++;
}
}
v->map[1].w = v->map[0].w;
v->map[1].h = v->map[0].h;
v->nmaps = 2;
}
2011-11-30 13:07:19 +11:00
// generate vault maps 1-3 with offsets into map[0]
void generatevaultrotations(vault_t *v) {
int i;
int x,y;
for (i = 1; i <= 3; i++) {
// rotate 90degrees from previous
v->map[i].mlen = 0;
for (x = 0; x < v->map[i-1].w; x++) {
for (y = v->map[i-1].h-1; y >= 0; y--) {
if (i == 1) { // ie. first rotation
int offset;
getvaultchar(v, x, y, 0, &offset);
v->map[i].data[v->map[i].mlen] = offset;
} else {
v->map[i].data[v->map[i].mlen] = v->map[i-1].data[ y * v->map[i-1].w + x ];
}
v->map[i].mlen++;
}
}
v->map[i].w = v->map[i-1].h;
v->map[i].h = v->map[i-1].w;
v->nmaps++;
}
assert(v->nmaps == 4);
}
void getadjustedcoords(vault_t *v, int origx, int origy, int minx, int miny, int maxx, int maxy, int rotation, int *retx, int *rety) {
int x,y;
int db = B_FALSE;
int w,h;
if (v->map[0].w) {
w = v->map[0].w;
} else {
w = maxx - minx + 1;
}
if (v->map[0].h) {
h = v->map[0].h;
} else {
h = maxy - miny + 1;
}
if (db) dblog("adjustcoords: %d,%d with mapcoord base %d,%d",origx,origy,minx,miny);
// first get coords if this was map #0 (unrotated).
if (origx >= 0) {
x = origx;
} else {
// offset from right. -1 is rightmost.
x = w + origx;
}
if (origy >= 0) {
y = origy;
} else {
// offset from bottom. -1 is bottommost.
y = h + origy;
}
if (db) dblog("adjustcoords: %d,%d translates to vaultcoords %d,%d (vault w=%d,h=%d)",origx,origy,x,y, w, h);
// now rotate them
rotatecoords(&x, &y, v, rotation, NULL);
if (db) dblog("adjustcoords: -> rotated to vaultcoords %d,%d (rotation=%d)",x, y,rotation );
// now change them to map coords rather than vault coords
x += minx;
y += miny;
if (db) dblog("adjustcoords: -> translated to mapcoords %d,%d",x, y);
// return values
*retx = x;
*rety = y;
}
void getboundingbox(int x1, int y1, int x2, int y2, int *retleft, int *rettop, int *retright, int *retbottom) {
int left,right,top,bottom;
if (x1 < x2) {
left = x1;
right = x2;
} else {
left = x2;
right = x1;
}
if (y1 < y2) {
top = y1;
bottom = y2;
} else {
top = y2;
bottom = y1;
}
if (retleft) *retleft = left;
if (retright) *retright = right;
if (rettop) *rettop = top;
if (retbottom) *retbottom = bottom;
}
enum RARITY getvaultrarity(vault_t *v) {
flag_t *f;
f = hasflag(v->flags, F_VAULTRARITY);
if (f) {
return f->val[0];
}
return RR_COMMON;
}
void getvaultwh(vault_t *v, int *w, int *h, int rotation) {
assert(rotation < v->nmaps);
*w = v->map[rotation].w;
*h = v->map[rotation].h;
}
char *getvstatename(enum VAULTSTATE vs) {
switch (vs) {
case VS_ALLOCATED:
return "allocated";
case VS_NOID:
return "no ID";
case VS_LOADING:
return "loading (toplevel)";
case VS_LOADINGMAP:
return "loading map";
case VS_LOADINGLEGEND:
return "loading legend";
case VS_LOADINGFLAGS:
return "loading flags";
default:
break;
}
return "?unknown?";
}
celltype_t *getvaultcelltype(vault_t *v, int x, int y, int rotation) {
char ch;
celltype_t *ct = NULL;
vlegend_t *l;
ch = getvaultchar(v, x, y, rotation, NULL);
// does this char give us a cell?
for (l = v->legend ; l ; l = l->next) {
if ((l->ch == ch) && (l->tt == VT_CELL)) {
ct = findcelltypebyname(l->what);
break;
}
}
return ct;
}
// return that character at position x/y on give map rotation
char getvaultchar(vault_t *v, int x, int y, int rotation, int *map0offset) {
char ch;
int offset;
//rotatecoords(&x, &y, v, rotation, &offset);
assert(rotation < v->nmaps);
offset = y * v->map[rotation].w + x;
if (rotation == 0) {
ch = v->map[0].data[offset];
} else {
ch = v->map[0].data[v->map[rotation].data[offset]];
}
if (map0offset) *map0offset = offset;
return ch;
}
// select a random vault type for the given map
vault_t *getvaulttype(map_t *m) {
vault_t *v;
vault_t *poss[MAXCANDIDATES];
int nposs = 0;
enum RARITY rr = RR_COMMON;
// select random rarity
rr = pickrr(TT_NONE);
while (!nposs) {
for (v = firstvault ; v ; v = v->next) {
if (!v->valid) continue;
if (hasflag(v->flags, F_NORANDOM)) continue;
if (getvaultrarity(v) != rr) continue;
// can this vault go in this map?
if (vaultokformap(v, m)) {
poss[nposs++] = v;
}
}
if (nposs > 0) {
return poss[rnd(0,nposs-1)];
}
// if we have no possibilities, lower rarity and try again
if (rr == RR_COMMON) {
// give up.
break;
2011-11-30 13:07:19 +11:00
} else {
rr--;
}
}
return NULL;
}
int handleline(vault_t *v, char *line) {
int ok = B_FALSE;
char localline[BUFLEN];
char *command = NULL,*temp;
char *dummy;
char *arg[MAXVAULTARGS];
int nargs = 0;
int i;
if (!strlen(line)) return B_FALSE;
if (line[0] == '!') return B_FALSE;
strcpy(localline, line);
if (v->state == VS_LOADINGMAP) {
if (streq(localline, "@end")) {
// go to toplevel loading state
v->state = VS_LOADING;
ok = B_TRUE;
} else if (strstarts(localline, "random(")) {
char *p;
int minw,minh;
p = localline + 7;
if (*p) {
char buf[BUFLEN];
p = readuntil(buf, p, ',');
minw = atoi(buf);
p = readuntil(buf, p, ')');
minh = atoi(buf);
addflag(v->flags, F_VAULTRANDOMMAP, minw, minh, NA, NULL);
} else {
dblog("error - random() map data is missing minw/minh values.");
return B_TRUE;
}
addflag(v->flags, F_VAULTRANDOMMAP, minw, minh, NA, NULL);
ok = B_TRUE;
} else {
// map line definition
if (hasflag(v->flags, F_VAULTRANDOMMAP)) {
dblog("error - map data found after randommap.");
return B_TRUE;
}
// check length
if ((v->map[0].w != 0) && (strlen(localline) != v->map[0].w)) {
dblog("incorrect map line length! %d != %d", strlen(localline), v->map[0].w);
} else {
char *p;
// read a new map line. we already read into map[0].
// the others will be populated automatically if/when we
// add f_vaultmayrotate
for (p = localline ; *p; p++) {
v->map[0].data[v->map[0].mlen] = *p;
v->map[0].mlen++;
}
ok = B_TRUE;
// increase width/height
if (!v->map[0].w) {
v->map[0].w = strlen(localline);
}
v->map[0].h++;
}
}
} else {
// split into command and args
if (strchr(localline, ':')) {
temp = strtok_r(localline, ":", &dummy);
command = strdup(temp);
temp = strtok_r(NULL, ":", &dummy);
while (temp) {
arg[nargs] = strdup(temp);
nargs++;
temp = strtok_r(NULL, ":", &dummy);
}
} else {
command = strdup(localline);
nargs = 0;
}
// process command and args
if (v->state == VS_NOID) { // haven't for our id yet
if (streq(command, "@id")) {
if (!v->id) {
if (nargs == 1) {
if (findvault(arg[0])) {
dblog("Duplicate vault id %s", arg[0]);
return B_TRUE;
}
v->id = strdup(arg[0]);
v->state = VS_LOADING;
ok = B_TRUE;
} else {
dblog("invalid syntax for @id");
}
} else {
dblog("@id command found but we already have an id");
}
}
} else if (v->state == VS_LOADING) { // toplevel
if (streq(line, "@map")) {
v->nmaps = 1;
v->state = VS_LOADINGMAP;
ok = B_TRUE;
} else if (streq(line, "@legend")) {
v->state = VS_LOADINGLEGEND;
ok = B_TRUE;
} else if (streq(line, "@flags")) {
v->state = VS_LOADINGFLAGS;
ok = B_TRUE;
}
} else if (v->state == VS_LOADINGLEGEND) {
if (streq(line, "@end")) {
v->state = VS_LOADING;
ok = B_TRUE;
} else {
// legend definition
if (nargs >= 2) {
int pct;
enum VAULTTHING tt;
char what[BUFLEN];
if (streq(arg[0], "ob")) {
tt = VT_OB;
} else if (streq(arg[0], "mon")) {
tt = VT_LF;
} else if (streq(arg[0], "cell")) {
tt = VT_CELL;
} else {
tt = VT_NONE;
}
strcpy(what, arg[1]);
if (nargs == 3) { // ie have a percentage
pct = atoi(arg[2]);
} else {
pct = 100;
}
if (tt == VT_NONE) {
dblog("invalid type in legend definition");
} else if (vaultthingok(tt, what)) {
// validated ok.
addlegend(v, command[0], tt, pct, what);
ok = B_TRUE;
} else {
dblog("invalid legend definition: '%s'", line);
}
} else { // special legend...
if (streq(arg[0], "exit")) {
addlegend(v, command[0], VT_EXIT, 100, "");
ok = B_TRUE;
} else {
dblog("invalid syntax for legend value");
}
}
}
} else if (v->state == VS_LOADINGFLAGS) {
if (streq(line, "@end")) {
v->state = VS_LOADING;
ok = B_TRUE;
} else {
// handle flags
if (strstarts(line, "at(")) {
// at(x,y) type:what[:pct]
int x,y;
enum FLAG flagtype;
char *p;
char buf[BUFLEN];
char thingname[BUFLEN];
enum VAULTTHING vt = VT_NONE;
int pct;
// get x
p = line + 3;
p = readuntil(buf, p, ',');
x = atoi(buf);
// get y
p = readuntil(buf, p, ')');
y = atoi(buf);
// go past whitespace
while (isspace(*p)) p++;
// get type
p = readuntil(buf, p, ':');
if (streq(buf, "ob")) {
vt = VT_OB;
flagtype = F_VAULTATOB;
} else if (streq(buf, "mon") || streq(buf, "lf")) {
vt = VT_LF;
flagtype = F_VAULTATLF;
} else { // ie. cell
vt = VT_CELL;
flagtype = F_VAULTATCELL;
}
// get thing name
p = readuntil(buf, p, ':');
strcpy(thingname, buf);
// optional percent chance
if (*p) {
p = readuntil(buf, p, ':');
pct = atoi(buf);
} else {
pct = 100;
}
if (vaultthingok(vt, thingname)) {
addflag(v->flags, flagtype, x, y, pct, thingname);
ok = B_TRUE;
} else {
dblog("invalid at() definition: '%s'", line);
}
} else if (strstarts(line, "atoneof(")) {
// atoneof(x,y)(x,y)(x,y)...(x,y) type:what[:pct]
// can have up to 10 x,y pairs.
int x[10],y[10];
int nposs = 0;
char *p;
char buf[BUFLEN];
char thingname[BUFLEN];
enum VAULTTHING vt = VT_NONE;
int pct;
p = line + 7;
while (*p == '(') {
// go past '('
p++;
// get x
p = readuntil(buf, p, ',');
x[nposs] = atoi(buf);
// get y
p = readuntil(buf, p, ')');
y[nposs] = atoi(buf);
nposs++;
}
// go past whitespace
while (isspace(*p)) p++;
// get type
p = readuntil(buf, p, ':');
if (streq(buf, "ob")) {
vt = VT_OB;
} else if (streq(buf, "mon") || streq(buf, "lf")) {
vt = VT_LF;
} else { // ie. cell
vt = VT_CELL;
}
// get thing name
p = readuntil(buf, p, ':');
strcpy(thingname, buf);
// optional percent chance
if (*p) {
p = readuntil(buf, p, ':');
pct = atoi(buf);
} else {
pct = 100;
}
if (nposs) {
if (vaultthingok(vt, thingname)) {
int i;
char locbuf[BUFLEN];
// construct string for all the possible positions
strcpy(buf, "");
for (i = 0; i < nposs; i++) {
snprintf(locbuf, BUFLEN, "(%d,%d)",x[i],y[i]);
strcat(buf, locbuf);
}
snprintf(locbuf, BUFLEN, " %s",thingname);
strcat(buf, locbuf);
addflag(v->flags, F_VAULTATONEOF, vt, pct, NA, buf);
ok = B_TRUE;
} else {
dblog("invalid vaultthing in atoneof() definition: '%s'", line);
}
} else {
dblog("no x/y coords found in atoneof() definition: '%s'", line);
}
} else if (strstarts(line, "exitat(")) { // mark a vault exit
// exitat(x,y)
int x,y;
char *p;
char buf[BUFLEN];
// get x
p = line + 3;
p = readuntil(buf, p, ',');
x = atoi(buf);
// get y
p = readuntil(buf, p, ')');
y = atoi(buf);
addflag(v->flags, F_VAULTEXIT, x, y, NA, NULL);
ok = B_TRUE;
} else if (strstarts(line, "box(")) { // outline region
// box(x,y,x2,y2) type:what[:pct]
// if x2/y2 are negative, count back from w/h. ie x=-1 means 'rightmost cell'
int x1,y1,x2,y2;
enum VAULTTHING thingtype;
char *p;
char buf[BUFLEN];
char thingname[BUFLEN];
int pct;
p = line + 4;
// get x/y
p = readuntil(buf, p, ',');
x1 = atoi(buf);
p = readuntil(buf, p, ',');
y1 = atoi(buf);
// get x2/y2
p = readuntil(buf, p, ',');
x2 = atoi(buf);
p = readuntil(buf, p, ')');
y2 = atoi(buf);
// go past whitespace
while (isspace(*p)) p++;
// get type
p = readuntil(buf, p, ':');
if (streq(buf, "ob")) {
thingtype = VT_OB;
} else if (streq(buf, "mon") || streq(buf, "lf")) {
thingtype = VT_LF;
} else { // ie. cell
thingtype = VT_CELL;
}
// get thing name
p = readuntil(buf, p, ':');
strcpy(thingname, buf);
// optional percent chance
if (*p) {
p = readuntil(buf, p, ':');
pct = atoi(buf);
} else {
pct = 100;
}
if (vaultthingok(thingtype, thingname)) {
snprintf(buf, BUFLEN, "%d,%d,%d,%d,%s",x1,y1,x2,y2,thingname);
addflag(v->flags, F_VAULTBOX, thingtype, pct, B_FALSE, buf);
ok = B_TRUE;
} else {
dblog("invalid box() definition: '%s'", line);
}
} else if (strstarts(line, "fill(")) { // fill region
// fill(x,y,x2,y2) type:what[:pct]
// if x2/y2 are negative, count back from w/h. ie x=-1 means 'rightmost cell'
int x1,y1,x2,y2;
enum VAULTTHING thingtype;
char *p;
char buf[BUFLEN];
char thingname[BUFLEN];
int pct;
p = line + 5;
// get x/y
p = readuntil(buf, p, ',');
x1 = atoi(buf);
p = readuntil(buf, p, ',');
y1 = atoi(buf);
// get x2/y2
p = readuntil(buf, p, ',');
x2 = atoi(buf);
p = readuntil(buf, p, ')');
y2 = atoi(buf);
// go past whitespace
while (isspace(*p)) p++;
// get type
p = readuntil(buf, p, ':');
if (streq(buf, "ob")) {
thingtype = VT_OB;
} else if (streq(buf, "mon") || streq(buf, "lf")) {
thingtype = VT_LF;
} else { // ie. cell
thingtype = VT_CELL;
}
// get thing name
p = readuntil(buf, p, ':');
strcpy(thingname, buf);
// optional percent chance
if (*p) {
p = readuntil(buf, p, ':');
pct = atoi(buf);
} else {
pct = 100;
}
if (vaultthingok(thingtype, thingname)) {
snprintf(buf, BUFLEN, "%d,%d,%d,%d,%s",x1,y1,x2,y2,thingname);
addflag(v->flags, F_VAULTBOX, thingtype, pct, B_TRUE, buf);
ok = B_TRUE;
} else {
dblog("invalid box() definition: '%s'", line);
}
} else if (strstarts(line, "scatter(")) { // fill region
// scatter(x,y,x2,y2) type:what:howmany[:pct]
// if x2/y2 are negative, count back from w/h. ie x=-1 means 'rightmost cell'
int x1,y1,x2,y2;
enum VAULTTHING thingtype;
char *p;
char buf[BUFLEN];
char thingname[BUFLEN];
int pct;
int countmin,countmax;
p = line + 8;
// get x/y
p = readuntil(buf, p, ',');
x1 = atoi(buf);
p = readuntil(buf, p, ',');
y1 = atoi(buf);
// get x2/y2
p = readuntil(buf, p, ',');
x2 = atoi(buf);
p = readuntil(buf, p, ')');
y2 = atoi(buf);
// go past whitespace
while (isspace(*p)) p++;
// get type
p = readuntil(buf, p, ':');
if (streq(buf, "ob")) {
thingtype = VT_OB;
} else if (streq(buf, "mon") || streq(buf, "lf")) {
thingtype = VT_LF;
} else { // ie. cell
thingtype = VT_CELL;
}
// get thing name
p = readuntil(buf, p, ':');
strcpy(thingname, buf);
// get count
p = readuntil(buf, p, ':');
// is this a range?
if (strchr(buf, '-') && strchr(buf, '%')) {
dblog("error - scatter() count contains both range and percentage.");
return B_TRUE;
} else if (strchr(buf, '-')) {
char *p2;
char buf2[BUFLENSMALL];
p2 = readuntil(buf2, buf, '-');
countmin = atoi(buf2);
p2 = readuntil(buf2, p2, ':');
countmax = atoi(buf2);
} else if (strchr(buf, '%')) {
char *p2;
p2 = strchr(buf, '%'); // replace % with nul
*p2 = '\0';
countmin = atoi(buf);
countmax = PCT;
} else {
countmin = atoi(buf);
countmax = countmin;
}
// optional percent chance
if (*p) {
p = readuntil(buf, p, ':');
pct = atoi(buf);
} else {
pct = 100;
}
if (vaultthingok(thingtype, thingname)) {
snprintf(buf, BUFLEN, "%d,%d,%d,%d,%d-%d,%s",x1,y1,x2,y2,countmin,countmax,thingname);
addflag(v->flags, F_VAULTSCATTER, thingtype, pct, NA, buf);
ok = B_TRUE;
} else {
dblog("invalid scatter() definition: '%s'", line);
}
} else if (strstarts(line, "autodoors")) {
char *p;
int pct = 100;
p = line + 9;
if (*p == ':') {
char buf[BUFLEN];
p++;
p = readuntil(buf, p, ','); // really jsut want EOL
pct = atoi(buf);
}
addflag(v->flags, F_AUTODOORS, pct, NA, NA, NULL);
ok = B_TRUE;
} else if (streq(line, "autopop")) {
addflag(v->flags, F_AUTOPOPULATE, B_TRUE, NA, NA, NULL);
ok = B_TRUE;
} else if (strstarts(line, "dlevmax")) {
// dlevmax:max
char *p;
p = line + 7;
if (*p == ':') {
int lev;
char buf[BUFLEN];
p++;
p = readuntil(buf, p, ','); // eol
lev = atoi(buf);
addflag(v->flags, F_VAULTDLEVMAX, lev, NA, NA, NULL);
ok = B_TRUE;
} else {
dblog("invalid dlevmax definition: '%s'", line);
}
} else if (strstarts(line, "dlevmin")) {
// dlevmin:min
char *p;
p = line + 7;
if (*p == ':') {
int lev;
char buf[BUFLEN];
p++;
p = readuntil(buf, p, ','); // eol
lev = atoi(buf);
addflag(v->flags, F_VAULTDLEVMIN, lev, NA, NA, NULL);
ok = B_TRUE;
} else {
dblog("invalid dlevmin definition: '%s'", line);
}
} else if (strstarts(line, "entertext")) {
char *p;
p = line + 9;
if (*p == ':') {
char buf[BUFLEN];
p++;
p = readuntil(buf, p, ','); // really jsut want EOL
if (strlen(buf)) {
addflag(v->flags, F_VAULTENTERTEXT, NA, NA, NA, buf);
ok = B_TRUE;
} else {
dblog("invalid entertext definition: '%s' (arglen is 0)",line);
}
} else {
dblog("missing entertext definition: '%s'", line);
}
} else if (strstarts(line, "goesin")) {
char *p;
p = line + 6;
if (*p == ':') {
habitat_t *h;
char buf[BUFLEN];
p++;
p = readuntil(buf, p, ','); // really jsut want EOL
h = findhabitatbyname(buf);
if (h) {
addflag(v->flags, F_VAULTGOESIN, h->id, NA, NA, NULL);
ok = B_TRUE;
} else {
dblog("invalid goesin() definition: '%s' [BAD HABITAT]", line);
}
} else {
dblog("invalid goesin() definition: '%s'", line);
}
} else if (streq(line, "maintainedge")) {
addflag(v->flags, F_MAINTAINEDGE, B_TRUE, NA, NA, NULL);
ok = B_TRUE;
2011-11-30 13:07:19 +11:00
} else if (strstarts(line, "margin")) {
char *p;
p = line + 6;
if (*p == ':') {
char buf[BUFLEN];
int xmargin,ymargin;
p++;
p = readuntil(buf, p, ',');
xmargin = atoi(buf);
p = readuntil(buf, p, ','); // really EOL
ymargin = atoi(buf);
addflag(v->flags, F_KEEPMARGIN, xmargin, ymargin, NA, NULL);
ok = B_TRUE;
} else {
dblog("invalid margin flag: '%s'", line);
}
} else if (streq(line, "mayrotate")) {
if (hasflag(v->flags, F_VAULTMAYFLIPX) || hasflag(v->flags, F_VAULTMAYFLIPY)) {
dblog("vault can only have one of mayrotate / mayflipx / mayflipy.");
} else if (v->nmaps == 1) {
2011-11-30 13:07:19 +11:00
addflag(v->flags, F_VAULTMAYROTATE, B_TRUE, NA, NA, NULL);
// now generate rotated versions
generatevaultrotations(v);
ok = B_TRUE;
} else {
dblog("vault flag mayrotate isnt valid for vaults with random maps.");
}
} else if (streq(line, "mayflipx")) {
if (hasflag(v->flags, F_VAULTMAYROTATE) || hasflag(v->flags, F_VAULTMAYFLIPY)) {
dblog("vault can only have one of mayrotate / mayflipx / mayflipy.");
} else if (v->nmaps == 1) {
addflag(v->flags, F_VAULTMAYFLIPX, B_TRUE, NA, NA, NULL);
// now generate rotated versions
generatevaultflipsx(v);
ok = B_TRUE;
} else {
dblog("vault flag mayflipx isnt valid for vaults with random maps.");
}
} else if (streq(line, "mayflipy")) {
if (hasflag(v->flags, F_VAULTMAYROTATE) || hasflag(v->flags, F_VAULTMAYFLIPX)) {
dblog("vault can only have one of mayrotate / mayflipx / mayflipy.");
} else if (v->nmaps == 1) {
addflag(v->flags, F_VAULTMAYFLIPY, B_TRUE, NA, NA, NULL);
// now generate rotated versions
generatevaultflipsy(v);
ok = B_TRUE;
} else {
dblog("vault flag mayflipy isnt valid for vaults with random maps.");
}
} else if (streq(line, "monstersstay")) {
addflag(v->flags, F_MONSTERSSTAY, B_TRUE, NA, NA, NULL);
ok = B_TRUE;
2011-11-30 13:07:19 +11:00
} else if (streq(line, "nolink")) {
addflag(v->flags, F_VAULTNOLINK, B_TRUE, NA, NA, NULL);
ok = B_TRUE;
} else if (streq(line, "norandom")) {
addflag(v->flags, F_NORANDOM, B_TRUE, NA, NA, NULL);
addflag(v->flags, F_VAULTRARITY, RR_NEVER, NA, NA, NULL);
ok = B_TRUE;
} else if (strstarts(line, "rarity")) {
char *p;
p = line + 6;
if (*p == ':') {
char buf[BUFLEN];
p++;
p = readuntil(buf, p, ','); // really EOL
if (streq(buf, "frequent")) {
addflag(v->flags, F_VAULTRARITY, RR_FREQUENT, NA, NA, NULL);
ok = B_TRUE;
} else if (streq(buf, "common")) {
addflag(v->flags, F_VAULTRARITY, RR_COMMON, NA, NA, NULL);
ok = B_TRUE;
} else if (streq(buf, "uncommon")) {
addflag(v->flags, F_VAULTRARITY, RR_UNCOMMON, NA, NA, NULL);
ok = B_TRUE;
} else if (streq(buf, "rare")) {
addflag(v->flags, F_VAULTRARITY, RR_RARE, NA, NA, NULL);
ok = B_TRUE;
} else if (streq(buf, "vrare") || streq(buf, "veryrare")) {
addflag(v->flags, F_VAULTRARITY, RR_VERYRARE, NA, NA, NULL);
ok = B_TRUE;
} else if (streq(buf, "never")) {
addflag(v->flags, F_VAULTRARITY, RR_NEVER, NA, NA, NULL);
ok = B_TRUE;
} else {
dblog("invalid rarity value: '%s'", line);
}
} else {
dblog("invalid rarity flag: '%s'", line);
}
} else if (streq(line, "playerstart")) {
addflag(v->flags, F_VAULTISPLAYERSTART, B_TRUE, NA, NA, NULL);
ok = B_TRUE;
/*
2011-11-30 13:07:19 +11:00
} else if (streq(line, "shop")) {
addflag(v->flags, F_VAULTISSHOP, B_TRUE, NA, NA, NULL);
ok = B_TRUE;
*/
- [+] allies should always give out info without payment - [+] ....but only about their home level! - [+] f_startmapid - [+] cave entrances should make noise - [+] drip - [+] echoing - [+] cope with multiple f_makesnoise flags on objects (pick one randomly) - [+] showlfstats skill display bug - "MORE" keystroke doesn't fall through. - [+] You impale the chicken! The chicken turns to face you. - [+] shouldn't turn to face if your'e dead! - [+] nulllify spell not populating seenbyplayer - [+] crash in createfakes() - [+] animals hsould still walk onto SHARP objects. - [+] secret doors showing up as empty remembered cells when you look away from them (and have lowish cartography) - [+] don't call remove_deadends on vaults. - [+] when walking down stairs to level 3: - [+] ERROR - stairs link to existing map 3('dungeon L2 (id #3)', depth 2), but it has no free stairs - [+] ie. Level 3 has too many up staircases ? no. 3 on all of them. - [+] FIXED. countstairs() was including too much. now using countmapobs(map, stairtype) instead. - [+] The goblin rogue a half-sized leather armour (null). - [+] fixed crash when you cast rage on someone who is eating. - [+] crash when catching a glowbug in a flask - [+] use canreachbp code when selecting armour to damage as well.... ie newt can't hit your helmet! - [+] BUG: "tunnel doing up" went down! - [+] for monsters:auto raise lf stats to match starting weapons - [+] crash in aigetspelltarget() for CLIMB - [+] should deactiveate all spells on polymorph - [+] allow usage of FEIGNDEATH while prone. - [+] make coprses non-stackable - [+] CRASH in animatedead - [+] shouldn't say 'you attack x from behind' if x has awareness
2012-01-06 11:20:57 +11:00
} else if (strstarts(line, "tag:")) {
char *p;
p = line + 4;
addflag(v->flags, F_VAULTTAG, B_TRUE, NA, NA, p);
ok = B_TRUE;
2011-11-30 13:07:19 +11:00
} else if (streq(line, "shrine")) { // a godstone shrine
addflag(v->flags, F_VAULTISSHRINE, B_TRUE, NA, NA, NULL);
ok = B_TRUE;
}
}
}
}
// free args
if (command) free(command);
for (i = 0; i < nargs; i++) {
free(arg[i]);
}
if (!ok) {
dblog("[vault:%s/%s] Invalid line: [%s]",
(v->state == VS_NOID) ? "no_id" : v->id,
getvstatename(v->state), line);
return B_TRUE;
}
return B_FALSE;
}
void killlegend(vlegend_t *l) {
vlegend_t *nextone,*lastone;
if (l->what) free(l->what);
// deallocate
nextone = l->next;
if (nextone != NULL) {
nextone->prev = l->prev;
} else { /* last */
l->vault->lastlegend = l->prev;
}
if (l->prev == NULL) {
/* first */
nextone = l->next;
l->vault->legend = nextone;
free(l);
} else {
lastone = l->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killvault(vault_t *v) {
vault_t *nextone,*lastone;
if (!v) return;
if (v->id) free(v->id);
- [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking)
2012-03-05 21:31:21 +11:00
if (v->filename) free(v->filename);
2011-11-30 13:07:19 +11:00
while (v->legend) {
killlegend(v->legend);
}
killflagpile(v->flags);
- [+] weapon skill of sk_skilled or high gives you a chance to block some damtypes - [+] BUT each weapon can only block certain damtypes (whereas shields can block all melee damtypes) - [+] add f_canblock to some weapons - [+] add f_canblock to shields - [+] check_for_block() should be a function - [+] getallshields() - [+] move othermod in SC_SHIELDBLOCK out of skillcheck(). calculate the bonus beforehand instead?? - [+] update descriptions for weapon skills - [+] can only block if you have full attrib requirements for this weapon - [+] update io.c to show what weapons/shields can block. "it can block xx, xx and xx damage" - [+] weapons can't ever block projectiles - [+] make pickup/drop actions heaps faster - [+] better description of agi/str affecting weapon accuracy/dam - [+] stinkbeetle should be hostile, and should have bite attack ,not zapper - [+] don't recover stamina while training - [+] add seetext for "a blaring siren" - [+] draw up a matrix for weapon types - [+] draw it up for: - [+] accuracy - [+] damage - [+] attack speed - [+] crit chance - [+] then adjust weapon stats - [+] in shops, "?" now lets you examine an object - [+] add canwill option for abilities: "stamcost:" (to override stamina cost) - [+] add it. - [+] bug: pickaxe not working - [+] "you start digging". but nothign more. - [+] salt kills: - [+] frog - [+] impaler frog - [+] canwill jump - [+] ranged tongue attack - [+] killed by salt - [+] BUG; getting manuals with no contents - [+] odd-sized armour should cost more. - [+] need to set statdirty when we change armour. - [+] when we say "you see x and y here", don't include obs we can't see
2011-12-13 03:40:17 +11:00
v->flags = NULL;
2011-11-30 13:07:19 +11:00
// deallocate
nextone = v->next;
if (nextone != NULL) {
nextone->prev = v->prev;
} else { /* last */
lastvault = v->prev;
}
if (v->prev == NULL) {
/* first */
nextone = v->next;
firstvault = nextone;
free(v);
} else {
lastone = v->prev;
free (lastone->next );
lastone->next = nextone;
}
}
- [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking)
2012-03-05 21:31:21 +11:00
vault_t *loadvault(char *dir, char *filename) {
2011-11-30 13:07:19 +11:00
FILE *f;
vault_t *v;
char line[BUFLEN];
char fullname[BUFLEN];
int goterrors = B_FALSE;
- [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking)
2012-03-05 21:31:21 +11:00
snprintf(fullname, BUFLEN, "%s/%s", dir, filename);
2011-11-30 13:07:19 +11:00
dblog("Loading vault file '%s'", fullname);
f = fopen(fullname,"rt");
if (!f) {
- [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking)
2012-03-05 21:31:21 +11:00
dblog("error opening vault file '%s/%s'", dir,fullname);
2011-11-30 13:07:19 +11:00
return NULL;
}
v = addvault();
if (!v) {
dblog("error allocating new vault");
return NULL;
}
- [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking)
2012-03-05 21:31:21 +11:00
asprintf(&v->filename, "%s/%s",dir,filename);
2011-11-30 13:07:19 +11:00
v->state = VS_NOID;
// read a line
fgets(line, BUFLEN, f);
while (!feof(f)) {
// strip newline
line[strlen(line)-1] = '\0';
// handle it
if (handleline(v, line)) {
goterrors = B_TRUE;
break;
}
// read next line
fgets(line, BUFLEN, f);
}
fclose(f);
if (goterrors && v) {
// mark vault as invalid
v->valid = B_FALSE;
v = NULL;
} else {
//dumpvault(v);
}
return v;
}
void loadvaults(void) {
- [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking)
2012-03-05 21:31:21 +11:00
char *vaultdir[2];
int i;
2011-11-30 13:07:19 +11:00
//
- [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking)
2012-03-05 21:31:21 +11:00
vaultdir[0] = strdup(VAULTDIR);
vaultdir[1] = strdup(BONESDIR);
for (i = 0; i < 2; i++) {
int nvaults = 0;
DIR *dir;
struct dirent *ent;
dir = opendir(vaultdir[i]);
if (!dir) {
dblog("Could not open vault directory '%s'",vaultdir[i]);
return;
}
nvaults = 0;
while ((ent = readdir(dir)) != NULL) {
char *p;
// ie. start of 4 char prefix
p = ent->d_name + strlen(ent->d_name) - 4;
if (!strcmp(p, ".vlt") ) {
if (loadvault(vaultdir[i], ent->d_name)) {
nvaults++;
} else {
dblog("Errors found in vaultfile %s - loading cancelled.",ent->d_name);
}
2011-11-30 13:07:19 +11:00
}
}
- [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking)
2012-03-05 21:31:21 +11:00
closedir(dir);
if (nvaults) {
dblog("Successfully loaded %d %s definition%s.", nvaults,
(i == 0) ? "fixed vault" : "bones vault",
(nvaults == 1) ? "" : "s");
} else {
dblog("No (valid) vault definitions found.", nvaults);
}
2011-11-30 13:07:19 +11:00
}
- [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking)
2012-03-05 21:31:21 +11:00
free(vaultdir[0]);
free(vaultdir[1]);
2011-11-30 13:07:19 +11:00
// debugging
//dumpvault("jimbos_lair", 0);
//dumpvault("jimbos_lair", 1);
//dumpvault("jimbos_lair", 2);
//dumpvault("jimbos_lair", 3);
}
// translate coords on map0 into coords of the same position on map1-3
void rotatecoords(int *x, int *y, vault_t *v, int rotation, int *retoffset) {
int offset,newoffset;
// get offset in map 0
offset = (*y * (v->map[0].w) + *x);
if (hasflag(v->flags, F_VAULTRANDOMMAP)) {
// don't need to rotate in random maps
if (retoffset) *retoffset = offset;
return;
}
if (rotation == 0) {
// leave offset (and therefore x/y) unchanged
newoffset = offset;
} else {
int i;
newoffset = -1;
// find translated offset
for (i = 0; i < v->map[rotation].mlen; i++) {
if (v->map[rotation].data[i] == offset) {
newoffset = i;
break;
}
}
assert(newoffset != -1);
}
// get new x/y
*x = newoffset % v->map[rotation].w;
*y = newoffset / v->map[rotation].w;
if (retoffset) *retoffset = newoffset;
}
int vaultthingok(enum VAULTTHING vt, char *what) {
celltype_t *ct;
object_t *o;
race_t *r;
obpile_t *op;
switch (vt) {
case VT_LF:
if (streq(what, "random")) {
return B_TRUE;
} else {
r = findracebyname(what);
if (r) {
return B_TRUE;
} else {
- [+] allow user to DISABLE auto dodge fatal attacks ?. enable through "reflexive dodging" ability - [+] first rotation in a turn takes no time - [+] exploit: if you walk diagonally next to a monster, it moves to your previous space! - [+] fix: aigetlastknownpos should return the cell that trails point to, not the cell _with_ the trails. - [+] only recognise weapon quality (masterwork etc) if you are skilled in that weapon or perception - [+] cope with mosnter necromancers, etc - [+] parserace should look for necromancer etc. - [+] if so, set "wantsubjob" to SJ_NECROMANCER etc - [+] move specialty mage code into "givejobspecialty" - [+] Make wizard's job name depend on primary spell school. - [+] "Demonologist", "Firemage", "Icemage", "Necromancer", "Skymage", "Wizard" (wild) - [+] instead of getjob() then j->name, use "getjobname(lf)" - [+] f_jobname - [+] i should never "hear voices chanting" from an abandoned temple - [+] for monsters, show "its bite inflicts poison" in io.c racial knowledge - [+] casting healing on myself pleased Glorana twice! - [+] one from casting a life spell - [+] one from casting healing. - [+] move ones from spell.c to castspell() - [+] new flag: f_pleasesgod v0=godid, v1=howmuch - [+] add to other spell objects: - [+] f_pleasesgod - [+] GODFIRE - spelllevel * 2 - [+] GODDEATH = spelllevel - [+] GODLIFE = spelllevel*2 - [+] GODNATURE: spelllevle*2 - [+] show this in describespell - [+] for god healing effects, use gainhp() so that it says "Your HP is fully restored." - [+] change F_RESISTMAG to be percentage rather than 1-20 - [+] make some gods' pleasure boost power of related spells - [+] 1 per each positive levle of getpietylev() - [+] glorana: life - [+] hecta: death - [+] only apply auto shortcuts for players. - [+] subjob_t - [+] addsubjob() - [+] killsubjob() - [+] show subjobs in job descriptions. - [+] data.c: addsubjob(.... - [+] in job defs: - [+] f_canhavesubjob sj_xxx - [+] use this to determine whether to ask about them - [+] redo getjobname - [+] remove f_job->Text - [+] speak with dead should only work on corpses of races which can talk. - [+] warrior subclasses - [+] "Scourge" - [+] gains magic resistance as you level up - [+] == 5 + (level * 3) % - [+] nospells - [+] no mana - [+] paladin - [+] blessed gear - [+] can will turn undead - [+] healing magic - [+] god = glorana. - [+] cannot use spells if glorana is angry. - [+] battlemage - [+] starts with one spell school (fire/ice/air) - [+] canlearn fire/ice/air spell schools - [+] limited to adept in all schools - [+] slightly less hp - [+] no warrior abilities
2012-02-24 17:45:23 +11:00
if (parserace(what, NULL, NULL, NULL)) {
2011-11-30 13:07:19 +11:00
return B_TRUE;
}
}
}
break;
case VT_OB:
if (streq(what, "random")) {
return B_TRUE;
} else {
op = addobpile(NULL, NULL, NULL);
- [+] vaults - [+] oval - [+] chasm - [+] room split in 4 by glass - [+] concentricroom - [+] Crash when a vault uses the object 'hole in the ground' - [+] better method of giving spells to monsters - [+] f_randomspellcount v0=amt - [+] f_randomspellschool v0=ss_xxx v1=minlevel v2=maxlevle, text = pw:xxx or null - [+] if power not given: - [+] castig power is (starting depth / 2) - [+] limited by spell's max level. - [+] OR - [+] f_randomspellcount v0=amt - [+] f_randomspellposs v0=spellid, optional text = power. - [+] include these in validateraces - [+] populate monsters... - [+] TEST! (with fire sprite, check if it casts a spell other then fire dart) - [+] if monster is randomly given the job "j_wizard", you MUST pick a subjob too! - [+] go back to using CANCAST for monster spells, so that they show up properly in a mind scan. - [+] druid should start with sickle as secondary weapon. - [+] healing not hurting undead - should be fixed now. - [+] add description of spell powe calculation to spell skills - [+] increase obhp of armour - [+] i was a druid, levelled up to l4, and didn't get a new spell! FIXED. wasn't refreshing LEVSPELLSCHOOLFROMX. - [+] make it a lot harder to get "beheaded" etc. - [+] show real object name in "killed by a thrown xxx" even if you didn't see it - [+] short blades shouldn't be able to behead. - [+] monster threat calc should take #attacks into account! - [+] CTRL-DIR to turn isn't working agian. fixed. - [+] make peasoup have range 1, rather than just going straight in front of you. - [+] power 1 glyph of wardning useless. fixed. - [+] reduce zombie maxattacks to 1. - [+] bug: Are alcohol no longer covered in (null).--More-- - [+] make merlochs much more rare. - [+] light recalc is MASSIVELY slow on some levels. - [+] for now: remove dark levels completely? - [+] "You see 2 sheet of ices here." - [+] remove F_FROZEN when you cook something. - [+] frostbite should do a little more damage. d4 instead of d3.
2012-02-29 17:05:14 +11:00
// disable linking of holes
o = addobject(op, what, B_TRUE, B_FALSE, OT_NONE);
2011-11-30 13:07:19 +11:00
if (o) {
killobpile(op);
return B_TRUE;
}
killobpile(op);
}
break;
case VT_CELL:
if (streq(what, "EMPTY") || streq(what, "SOLID")) {
return B_TRUE;
}
2011-11-30 13:07:19 +11:00
ct = findcelltypebyname(what);
if (ct) return B_TRUE;
break;
default:
return B_TRUE;
break;
}
return B_FALSE;
}
int vaultokformap(vault_t *v, map_t *m) {
flag_t *f;
// check HABITAT
if (hasflag(v->flags, F_VAULTGOESIN)) {
int ok = B_FALSE;
// check which habitats are valid
for (f = v->flags->first ; f ; f = f->next) {
if (f->id == F_VAULTGOESIN) {
if (f->val[0] == m->habitat->id) {
ok = B_TRUE;
break;
}
}
}
if (!ok) return B_FALSE;
}
f = hasflag(v->flags, F_VAULTDLEVMIN);
if (f && (getmapdifficulty(m) < f->val[0])) {
return B_FALSE;
}
f = hasflag(v->flags, F_VAULTDLEVMAX);
if (f && (getmapdifficulty(m) > f->val[0])) {
return B_FALSE;
}
return B_TRUE;
}