* [+] vaiultlegend_t
* [+] vaultdef_t
- [+] implement addlegend()
- [+] implement addvault()
- [+] function to read in a vault from a data file
    - [+] vs_noid
    - [+] vs_loadingmap
    - [+] vs_loadinglegend
    - [+] vs_loadingflags
    - [+] vs_loading
- [+] load all vaultdefs in at start
- [+] change createroom to calculate the posistion
- [+] for each room, give a %chance of haivng a vault. (based on
      habitat?)
* [+] createvault(map_t, roomid?, char *vaultid)
- [+] mapdata with letters
* [+] MSG up vault errors on load.
- [+] Select job _before_ generating first map.
* [+] make addob() handle door flags:
* [+] addob() improvements
* [+] wish bug: first object goes in pack, rest on ground.
- [+] genericise getroomedge()
- [+] finish 'autodoors' (at the end, add doors if none already done)
- [+] at(x,y):type:what:pct -> f_vaultob / vaultlf / vaultcell, v0=x,
      v1=y, v2=pct text=what
* [+] "what" can be:
* [+] scatter:y1:x2:y2:what:chance%:howmany
* [+] some way to make the @map bit just say 'random room at least 2x4'
- [+] make "scatter" able to take range instead of count.
- [+] make "scatter"able to take x% instead of count.
- [+] upsidedown chars no longer working with winch()
- [+] ensure no DUPE ids
- [+] make legend take percentages (optional)
- [+] make "at" take negative values...
OPTIONS
- [+] autodoors - put doors on edges like with normal dungeon rooms.
* [+] autopop - fill with obs/monsters like normal rooms
VAULT FILES
- [+] flooded room
- [+] labyrinth
- [+] vault (lots of money, locked secret doors)
- [+] monster zoos (money and monsters)
- [+] diningroom - lots of tables and chairs
- [+] circleroom
- [+] pillared room
- [+] glass pillared room
- [+] cockatrice lair (statues)
- [+] traproom - need "random trap".  need OC_TRAP.
- [+] BUG: piranhas walking out of water sometimes.......
- [+] add startatt x-y rather than just a bracket. use text field.
- [+] make teleport auto move away form lfs
- [+] add minotaur
This commit is contained in:
Rob Pearce 2011-06-02 08:34:44 +00:00
parent af0d8f244d
commit 11c03d71cf
14 changed files with 1629 additions and 821 deletions

View File

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

104
defs.h
View File

@ -1,6 +1,8 @@
#ifndef __DEFS_H
#define __DEFS_H
// MACROS
#define MAXOF(a,b) (a > b ? a : b)
@ -102,6 +104,7 @@ enum SKILLLEVEL {
// save/load
#define MAPDIR "data/maps"
#define SAVEDIR "data/save"
#define VAULTDIR "vaults"
#define DUMMYCELLTYPE 0xabcd
// SPECIAL NUMBERS/CONSTANTS
@ -110,10 +113,10 @@ enum SKILLLEVEL {
#define NA (-9874)
#define NOBODY (-1)
#define ALLCONFERRED (-9873)
#define PCT (65432) // must be POSITIVE
#define AUTO (-7654)
enum GAMEMODE {
GM_FIRST,
GM_INIT,
@ -407,8 +410,11 @@ enum LOFTYPE {
// Cell types
enum CELLTYPE {
CT_NONE = 0,
// walls
CT_WALL,
CT_WALLGLASS,
CT_WALLMETAL,
CT_ROOMWALL,
// empty
CT_CORRIDOR,
@ -419,12 +425,6 @@ enum CELLTYPE {
CT_ROOM,
};
enum SPECIALROOMTYPE {
RT_NONE = 0,
RT_FLOODED,
};
enum SPELLSCHOOL {
SS_NONE,
SS_DIVINE,
@ -573,17 +573,24 @@ enum HABITAT {
#define RARITYVARIANCELF (5)
#define RARITYVARIANCEOB (10)
/*
enum RARITY {
RR_UNIQUE = 7,
RR_NEVER = 6,
RR_VERYRARE = 5,
RR_RARE = 4,
RR_UNCOMMON = 3,
RR_COMMON = 2,
RR_FREQUENT = 1,
RR_UNIQUE = 6,
RR_NEVER = 5,
RR_VERYRARE = 4,
RR_RARE = 3,
RR_UNCOMMON = 2,
RR_COMMON = 1,
RR_NONE = 0,
};
// for genericising weapons, etc
enum GOODNESS {
G_NA = 0,
G_AVERAGE,
G_GOOD,
G_GREAT,
G_EXCELLENT,
};
*/
enum RACECLASS {
RC_ANY, // not actually ever defined
@ -627,6 +634,7 @@ enum RACE {
R_KOBOLD,
R_LIZARDMAN,
R_LURKINGHORROR,
R_MINOTAUR,
R_OGRE,
R_OGRESAVAGE,
R_OGREWARHULK,
@ -1735,7 +1743,7 @@ enum FLAG {
F_HASHIDDENNAME, // whether this object class has a hidden name
F_IDENTIFIED, // whether this object is fully identified
// bad flags
F_DEEPWATER, // v0 = depth.oooooooooooo
F_DEEPWATER, // v0 = depth.
F_WALKDAM, // val0 = damtype, text = dam per sec
F_WALKDAMBP, // v0 = bodypart, v1 = damtype, text = dam per sec
// if v2 == FALLTHRU, damage falls through to lf if
@ -1805,6 +1813,10 @@ enum FLAG {
// calculation
F_STARTJOB, // val0 = %chance of starting with it, v1 = jobid
F_STARTATT, // val0 = A_xxx, val0 = start bracket (ie. IQ_GENIUS)
// if text is set, it overrides val0.
// text can be:
// x (single number)
// x-y (range)
F_STARTHIDDENPCT, // val0 = pct chance auto-generated monster will
// start off hidden
F_CORPSETYPE, // text field specifies what corpse obtype to leave
@ -2088,7 +2100,20 @@ enum FLAG {
F_LEVFLAG, // at level v0, this job gains flagid v1, flagval0=v2,
// flagtext = text
//
// vault flags
F_AUTODOORS, // automatically create at least one door
F_AUTOPOPULATE, // fill this vault with obs/mons/pillars like normal rooms
F_VAULTATOB, // v0/1=x/y, v1=pctchance, text=obname
F_VAULTATLF, // v0/1=x/y, v1=pctchance, text=lfname
F_VAULTATCELL, // v0/1=x/y, v1=pctchance, text=cellname
F_VAULTBOX, // v0=thingtype, v1=pctchance, v2=fill?, text=x1,y1,x2,y2,thingname
F_VAULTSCATTER, // v0=thingtype, v1=pctchance
// text=x1,y1,x2,y2,mincount-maxcount,thingname
// if maxcount is PCT, mincount is a percentage
// of the total space.
F_VAULTRANDOMMAP, // v0=minwidth, v1=minheight. this vault's map is
// v0/1 can be NA.
// just a normal random room
F_NULL = -1
};
@ -2325,6 +2350,46 @@ typedef struct map_s {
struct map_s *next, *prev;
} map_t; //////////////// remember to modify save/load for new props!!
#define MAXVAULTARGS 10
enum VAULTSTATE {
VS_ALLOCATED,
VS_NOID,
VS_LOADING,
VS_LOADINGMAP,
VS_LOADINGLEGEND,
VS_LOADINGFLAGS,
};
enum VAULTTHING {
VT_NONE,
VT_OB,
VT_LF,
VT_CELL,
};
typedef struct vlegend_s {
char ch;
enum VAULTTHING tt;
char *what;
int pct;
struct vault_s *vault;
struct vlegend_s *next, *prev;
} vlegend_t;
typedef struct vault_s {
char *filename;
char *id;
int valid;
int state;
char map[MAX_MAPW*MAX_MAPH];
int mlen;
int w,h;
struct vlegend_s *legend, *lastlegend;
struct vault_s *next, *prev;
struct flagpile_s *flags;
} vault_t;
typedef struct glyph_s {
int ch;
int colour;
@ -2513,10 +2578,13 @@ typedef struct job_s {
struct job_s *next, *prev;
} job_t;
#define MAXOCNOUNS 5
typedef struct objectclass_s {
enum OBCLASS id;
char *name;
char *desc;
char *noun[MAXOCNOUNS];
int nnouns;
glyph_t glyph;
struct flagpile_s *flags;
struct objectclass_s *next, *prev;

53
doc/vaults.txt Normal file
View File

@ -0,0 +1,53 @@
General format:
@id:textual_name
@map
EITHER
map definition
OR
random(minw,minh)
@end
@legend
k:mon:kobold
s:ob:50:short sword
#:cell:stone wall
@end
@flags
...
@end
Legend is:
c:type:what[:pct]
c = any letter
type = ob, mon or cell
pct = optional pct chance of appearing
what = text of what this letter represents
Flags can be:
at(x,y) type:what[:pct] // put what at position x,y
'type' can be: ob, mon, cell
coords can be negative ("count back from right/bottom")
box(x,y,x2,y2) type:what[:pct] // outline box with what
fill(x,y,x2,y2) type:what[:pct] // filled box with what
coords can be negative ("count back from right/bottom")
scatter(x,y,x2,y2) type:what:howmany[:pct] // scatter what within region
howmany can be:
- a number (x)
- a range (x-y)
- a pct of the total region cells (x%)
coords can be negative ("count back from right/bottom")
autodoors // automatically add at least one door to the edges of
// this room.
autopop // automatically add obs/mons/pillars to this room
NOTES:
when adding lfs/objects, "random" creates a random one.

6
io.c
View File

@ -5038,8 +5038,12 @@ void drawglyph(glyph_t *g, int x, int y) {
col = g->colour;
}
setcol(gamewin, col);
//mvwprintw(gamewin, y, x, "%lc", g->ch);
if (g->ch > 255) {
// note: much slower
mvwprintw(gamewin, y, x, "%lc", g->ch);
} else {
mvwaddch(gamewin, y, x, g->ch);
}
unsetcol(gamewin, col);
}

55
lf.c
View File

@ -6875,7 +6875,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings");
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addrace(R_GIANTHILL, "hill giant", 160, 'H', C_BROWN, MT_FLESH, RC_HUMANOID);
addrace(R_GIANTHILL, "hill giant", 160, 'H', C_GREY, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 55, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL);
@ -7348,6 +7348,34 @@ void initrace(void) {
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addrace(R_MINOTAUR, "minotaur", 130, 'H', C_BROWN, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 62, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HATESRACE, R_GNOLL, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 6, 3, NA, NULL);
addflag(lastrace->flags, F_ARMOURRATING, 12, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "5-7");
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, ST_TITANIC, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_BUTT, NA, NA, "2d4");
addflag(lastrace->flags, F_HASATTACK, OT_BUTT, NA, NA, "2d4");
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "+2 heavy flail");
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "greataxe");
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_EXPERT, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roar");
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addrace(R_OGRE, "ogre", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
@ -11391,7 +11419,27 @@ int rollstat(lifeform_t *lf, enum ATTRIB attr) {
f = hasflagval(lf->flags, F_STARTATT, attr, NA, NA, NULL);
if (f) {
if (strlen(f->text)) {
int val;
if (strchr(f->text, '-')) {
int min,max;
char *p;
char buf[BUFLENSMALL];
// text is a range
p = readuntil(buf, f->text, '-');
min = atoi(buf);
p = readuntil(buf, p, '-');
max = atoi(buf);
val = rnd(min,max);
} else {
val = atoi(f->text);
}
lf->att[attr] = val;
return B_FALSE;
} else {
bracket = f->val[1];
}
} else {
switch (attr) {
case A_STR:
@ -13686,6 +13734,11 @@ int validateraces(void) {
printf("ERROR in race '%s' - F_HITCONFER, but no HITCONFERVALS defined.\n", r->name);
goterror = B_TRUE;
}
} else if (f->id == F_STARTATT) {
if (strlen(f->text) && (f->val[1] != NA)) {
printf("ERROR in race '%s' - F_STARTATT has both text range and val1.", r->name);
goterror = B_TRUE;
}
} else if (f->id == F_NOISETEXT) {
if (f->val[0] == N_FLY) {
if (!hasflag(r->flags, F_FLYING) && !hasflag(r->flags, F_LEVITATING)) {

615
map.c
View File

@ -12,6 +12,7 @@
#include "map.h"
#include "objects.h"
#include "text.h"
#include "vault.h"
extern map_t *firstmap,*lastmap;
extern celltype_t *firstcelltype, *lastcelltype;
@ -169,12 +170,6 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
if (autogen) {
// sometimes start off asleep in new maps
if (!lfhasflag(lf, F_DEAF) && cansleep(lf)) {
// TODO: base this on the time, and whether monster is nocturnal
if (rnd(1,2) == 1) {
addflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL);
}
}
f = lfhasflag(lf, F_STARTHIDDENPCT);
if (f) {
if (rnd(1,100) <= f->val[0]) {
@ -184,6 +179,12 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
addflag(lf->flags, F_HIDING, 0, NA, NA, NULL);
}
}
if (!lfhasflag(lf, F_HIDING) && !lfhasflag(lf, F_DEAF) && cansleep(lf)) {
// TODO: base this on the time, and whether monster is nocturnal
if (rnd(1,2) == 1) {
addflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL);
}
}
}
// appears in groups?
@ -358,6 +359,134 @@ int addrandomthing(cell_t *c, int obchance, int *nadded) {
return rv;
}
// whichside should be D_ORTH
// for now, this function will NOT include room corners
void getroomedge(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, int whichside, cell_t **retcell, int *ncells) {
int x,y;
*ncells = 0;
if (whichside == D_N) {
y = miny;
for (x = minx+1; x <= maxx-1; x++) {
retcell[*ncells] = getcellat(map, x, y);
(*ncells)++;
}
} else if (whichside == D_S) {
y = maxy;
for (x = minx+1; x <= maxx-1; x++) {
retcell[*ncells] = getcellat(map, x, y);
(*ncells)++;
}
} else if (whichside == D_W) {
x = minx;
for (y = miny+1; y <= maxy-1; y++) {
retcell[*ncells] = getcellat(map, x, y);
(*ncells)++;
}
} else if (whichside == D_E) {
x = maxx;
for (y = miny+1; y <= maxy-1; y++) {
retcell[*ncells] = getcellat(map, x, y);
(*ncells)++;
}
}
}
void autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy) {
int i,d;
cell_t *poss[MAXCANDIDATES], *cell[MAXCANDIDATES]; // TODO: should this be maxroomw * maxroomh ?
int ncells = 0, npossible = 0;
int doorsadded = 0;
// for each side, make list of all possible door locations
// then pick one randomly.
// BUT if the nearby corridor only has one exit, always
// place a door.
for (d = D_N; d <= D_W; d++) {
npossible = 0;
getroomedge(map, roomid, minx, miny, maxx, maxy, d, cell, &ncells);
for (i = 0; i < ncells; i++) {
cell_t *newcell;
// is there empty space on the other side of this wall segment?
newcell = getcellindir(cell[i], d);
if (newcell && !newcell->type->solid) {
int doorcount;
// if so, make sure there are no other adjacent doors
doorcount = countadjcellswithflag(cell[i], F_DOOR);
if (doorcount == 0) {
// if there is only one way out of the adjacent empty cell, and
// walls to either side of the potential door location, then
// always add a door
if ((countcellexits(newcell) == 1) && wallstoleftright(newcell, d)) {
if (onein(2)) {
makedoor(cell[i]);
} else {
setcelltype(cell[i], getemptycelltype(map->habitat));
}
} else {
// otherwise mark this as a _potential_ door location.
poss[npossible] = cell[i];
npossible++;
}
}
}
}
// if we have potential door locations, add one somewhere along this wall.
if (npossible > 0) {
int sel;
sel = rnd(0,npossible-1);
makedoor(poss[sel]);
doorsadded++;
}
} // end foreach direction
if (doorsadded == 0) {
int i,d,used[MAXDIR_ORTH],poss[MAXDIR_ORTH];
int dodoor[MAXDIR_ORTH];
int ndodoors = 0;
int ndoors,nposs = 0;
int sel;
//
for (d = D_N; d <= D_W; d++) {
used[d] = B_FALSE;
}
// no possible door locations - add a random number
ndoors = rnd(1,4);
for (i = 0; i < ndoors; i++) {
// find a dir we haven't already used
nposs = 0;
for (d = D_N; d <= D_W; d++) {
if (!used[d]) poss[nposs++] = d;
}
if (nposs <= 0) {
break;
}
sel = rnd(0,nposs-1);
used[poss[sel]] = B_TRUE;
dodoor[ndodoors++] = poss[sel];
}
// actually make the doors
for (i = 0; i < ndodoors; i++) {
int sel;
d = dodoor[i];
getroomedge(map, roomid, minx, miny, maxx, maxy, d, cell, &ncells);
sel = rnd(0,ncells-1);
if (onein(2)) {
makedoor(cell[sel]);
} else {
setcelltype(cell[sel], getemptycelltype(map->habitat));
}
}
}
}
int cellhaslos(cell_t *c1, cell_t *dest) {
int deltax, deltay;
int numpixels;
@ -579,6 +708,13 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) {
}
}
int getdoorlockdiff(int depth) {
return 19 + depth;
}
int getdoorsecretdiff(int depth) {
return 20 + (depth / 2);
}
enum CELLTYPE getemptycelltype(enum HABITAT hab) {
switch (hab) {
case H_DUNGEON:
@ -870,13 +1006,10 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
int lastdir;
int numrooms = 0;
int roomw[MAXROOMS],roomh[MAXROOMS];
vault_t *roomvault[MAXROOMS];
//int roomspecial[MAX_MAPROOMS];
int minroomw = MIN_ROOMW;
int minroomh = MIN_ROOMH;
int maxroomw = MAX_ROOMW;
int maxroomh = MAX_ROOMH;
int bestx,besty;
int w,h;
//int bestx,besty;
//int w,h;
//int startdir,forcex,forcey,ntries;
cell_t *cell, *c;
object_t *o;
@ -1075,40 +1208,24 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
//printf("using %d rooms\n",numrooms);
//dblog("Adding %d rooms...\n",numrooms);
for (i = 0; i < numrooms; i++) {
// select random width/height
w = rnd(minroomw, maxroomw);
h = rnd(minroomh, maxroomh);
roomw[i] = w;
roomh[i] = h;
if (calcroompos(map, w, h, &bestx, &besty)) {
//printf("** couldn't make room!\n");
} else {
// we now have the room position - fill it in
createroom(map, bestx,besty, w,h, i);
/*
if (getrand(1,100) <= CH_SPECIALROOM) {
int curpos;
int roomid;
roomid = getrandomspecialroom(wreck->mazelev[curz].type);
for (y = besty; y <= (besty + (h-1)); y++) {
for (x = bestx; x <= (bestx + (w-1)); x++) {
curpos = y*MAZEW+x;
wreck->mazelev[curz].maze[curpos].floorver = roomid;
// maybe make it a special room
roomvault[i] = NULL;
if (rnd(1,100) <= getvaultchance(map)) {
vault_t *v;
v = getvaulttype(map);
if (!createvault(map, i, v, &roomw[i],&roomh[i])) {
// success
roomvault[i] = v;
}
}
roomspecial[i] = roomid;
} else {
roomspecial[i] = B_FALSE;
}
*/
if (!roomvault[i]) {
// just do a normal room
createroom(map, i, NA, NA, NULL, NULL, &roomw[i],&roomh[i]);
roomvault[i] = B_FALSE;
}
}
}
// add staircases - dungeons always have an up and down stairs
for (i = 0; i < 3; i++) {
// add up stairs
@ -1150,6 +1267,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
// add pillars & objects & monsters to rooms
if (wantrooms && (numrooms > 0)) {
for (i = 0; i < numrooms; i++) {
if (!roomvault[i] || hasflag(roomvault[i]->flags, F_AUTOPOPULATE)) {
int numobsmin,numobsmax,numobs,n;
int maxpillars;
@ -1172,19 +1290,10 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
}
}
/*
if (roomspecial[i]) {
// chance is increased
numobsmin = (roomw[i]*roomh[i]) / 4 ;
numobsmax = (roomw[i]*roomh[i]) / 2 ;
} else {
*/
numobsmin = 0;
//numobsmax = MAXOF(roomw[i],roomh[i]) / 2;
numobsmax = MAXOF(roomw[i],roomh[i]);
//}
// then objects/monsters
if (numobsmax <= numobsmin) {
numobs = numobsmin;
@ -1225,9 +1334,9 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
}
}
}
}
}
} // end if !vault
} // end foreach room
} // end if wantrooms & nrooms>0
if (db) dblog("Finished adding objects.");
}
@ -1541,12 +1650,194 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap,
map->beingcreated = B_FALSE;
}
void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth) {
int w,h,x,y;
int minx,miny,maxx,maxy;
flag_t *f;
if (!v) {
return B_TRUE;
}
f = hasflag(v->flags, F_VAULTRANDOMMAP);
if (f) {
// just make a normal room to start with.
if (createroom(map, roomid, f->val[0], f->val[1], &minx, &miny, &w, &h)) {
return B_TRUE;
}
maxx = minx + w - 1;
maxy = miny + h - 1;
} else {
// get width/height from vault
w = v->w;
h = v->h;
if (retw) *retw = w;
if (reth) *reth = h;
// find vault position
if (calcroompos(map, w, h, &minx, &miny)) {
dblog("** couldn't make vault room!\n");
return B_TRUE;
}
maxx = minx + (w-1);
maxy = miny + (h-1);
// now make it
for (y = miny; y <= maxy; y++) {
for (x = minx; x <= maxx; x++) {
cell_t *cell;
celltype_t *ct;
cell = getcellat(map, x, y);
// set cell type
ct = getvaultcelltype(v, x-minx,y-miny);
setcelltype(cell, ct ? ct->id : getemptycelltype(cell->map->habitat));
// set roomid
cell->roomid = roomid;
// add objects
addvaultcellcontents(cell, v, x-minx,y-miny);
}
}
}
// add other stuff to the vault
addvaultcontents(map, v, minx, miny, maxx, maxy);
// auto add doors if required
if (hasflag(v->flags, F_AUTODOORS)) {
autodoors(map, roomid, minx, miny, maxx, maxy);
}
linkdoors(map, roomid, minx, miny, maxx,maxy);
return B_FALSE;
}
// make sure doors in a given room link up to the rest of the map.
void linkdoors(map_t *m, int roomid, int minx, int miny, int maxx, int maxy) {
int x,y,i;
cell_t *poss[MAXCANDIDATES],*c;
int nposs = 0;
int db = B_FALSE;
if (db) dblog("linkdoors for roomid %d", roomid);
// find all doors // TODO: ...or "exits"
for (y = miny; y <= maxy; y++) {
for (x = minx; x <= maxx; x++) {
c = getcellat(m, x, y);
if (!c) continue;
if (hasobwithflag(c->obpile, F_DOOR)) {
if (db) dblog("found door at %d,%d",x,y);
poss[nposs++] = c;
}
}
}
if (db) dblog("%d doors found.",nposs);
// for each door, make sure it links to at least one cell which isn't
// part of this room
for (i = 0; i < nposs; i++) {
int d;
int ncorridors = 0;
for (d = DC_N; d <= DC_NW; d++) {
c = getcellindir(poss[i], d);
if (c && cellwalkable(NULL, c, NULL) && (c->roomid != roomid)) {
ncorridors++;
}
}
if (db) dblog("Door #%d leads to %d corridors. ",i, ncorridors);
// no corridors?
if (ncorridors == 0) {
int poss2[MAXCANDIDATES],nposs2;
int dist[MAXDIR_ORTH];
int bestdist = 999;
if (db) dblog(" Need to link.");
// link it. starting from the door, count the number of cells in
// each direction until we hit an empty (walkable) cell not of this room.
// if we hit a cell of this roomid, mark this dir as invalid.
for (d = D_N; d <= D_W; d++) {
dist[d] = 0;
c = getcellindir(poss[i], d);
while (c) {
dist[d]++;
if (c->roomid == roomid) {
// mark dir as invalid
dist[d] = 999;
break;
} else if (cellwalkable(NULL, c, NULL)) {
// walkable and not in this vault. finished.
break;
}
// check next cell
c = getcellindir(c, d); // getting the same cell!
}
if (dist[d] < bestdist) bestdist = dist[d];
}
if (bestdist != 999) {
int whichway,sel;
// now pick the shortest one
// get list of all the maximums and randomly tie-break
nposs2 = 0;
for (d = D_N; d <= D_W; d++) {
if (dist[d] == bestdist) {
poss2[nposs2++] = d;
}
}
sel = rnd(0,nposs2-1);
whichway = poss2[sel];
// now create a path
if (db) dblog(" Linking %s (distance %d).", getdirname(whichway), bestdist);
c = getcellindir(poss[i], whichway);
while (c && !cellwalkable(NULL, c, NULL)) {
setcelltype(c, getemptycelltype(c->map->habitat));
c = getcellindir(poss[i], whichway);
}
}
} // end if ncorridors = 0
} // end for each door
if (db) dblog("linkdoors complete.");
}
// room w/h are returned in *w and *h if given.
int createroom(map_t *map, int roomid, int overrideminw, int overrideminh, int *retx, int *rety, int *retw, int *reth) {
int x,y;
int poss[MAXOF(MAX_MAPW,MAX_MAPH)];
int npossible;
cell_t *cell, *newcell;
cell_t *cell;
int minx,miny;
int maxx,maxy;
int w,h;
int minroomw = MIN_ROOMW;
int minroomh = MIN_ROOMH;
int maxroomw = MAX_ROOMW;
int maxroomh = MAX_ROOMH;
if (overrideminw != NA) {
minroomw = overrideminw;
}
if (overrideminh != NA) {
minroomh = overrideminh;
}
// select random width/height
w = rnd(minroomw, maxroomw);
h = rnd(minroomh, maxroomh);
if (retw) *retw = w;
if (reth) *reth = h;
// find room position
if (calcroompos(map, w, h, &minx, &miny)) {
dblog("** couldn't make room!\n");
return B_TRUE;
}
if (retx) *retx = minx;
if (rety) *rety = miny;
// we now have the room position - fill it in
//printf("trying to create room at (%d,%d) w=%d,h=%d\n", minx, miny, w, h);
@ -1556,7 +1847,6 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
for (y = miny; y <= maxy; y++) {
for (x = minx; x <= maxx; x++) {
cell = getcellat(map, x, y);
// make it a border or room
if ((y == miny) || (y == maxy) ||
(x == minx) || (x == maxx)) {
@ -1570,171 +1860,12 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
}
}
// add doors
autodoors(map, roomid, minx, miny, maxx, maxy);
// for each side, make list of all possible door locations
// then pick one randomly.
// BUT if the nearby corridor only has one exit, always
// place a door.
// N
npossible = 0;
y = miny;
for (x = minx+1; x <= maxx-1; x++) {
cell = getcellat(map, x, y);
newcell = getcellindir(cell, D_N);
if (newcell && !newcell->type->solid) {
int doorcount;
doorcount = countadjcellswithflag(cell, F_DOOR);
if (doorcount == 0) {
if ((countcellexits(newcell) == 1) &&
(iswallindir(newcell,D_E)) &&
(iswallindir(newcell,D_W))) { // always add door
makedoor(cell);
} else {
poss[npossible] = x;
npossible++;
}
}
}
return B_FALSE;
}
if (npossible > 0) {
int sel = rand() % npossible;
//printf("adding N door at %d\n",poss[sel]);
cell = getcellat(map, poss[sel], y);
makedoor(cell);
}
// S
npossible = 0;
y = maxy;
for (x = minx+1; x <= maxx-1; x++) {
cell = getcellat(map, x, y);
newcell = getcellindir(cell, D_S);
if (newcell && !newcell->type->solid) {
int doorcount;
doorcount = countadjcellswithflag(cell, F_DOOR);
if (doorcount == 0) {
if ((countcellexits(newcell) == 1) &&
(iswallindir(newcell,D_E)) &&
(iswallindir(newcell,D_W))) { // always add door
makedoor(cell);
} else {
poss[npossible] = x;
npossible++;
}
}
}
}
if (npossible > 0) {
int sel = rand() % npossible;
//printf("adding S door at %d\n",poss[sel]);
cell = getcellat(map, poss[sel], y);
makedoor(cell);
}
// W
npossible = 0;
x = minx;
for (y = miny+1; y <= maxy-1; y++) {
cell = getcellat(map, x, y);
newcell = getcellindir(cell, D_W);
if (newcell && !newcell->type->solid) {
int doorcount;
doorcount = countadjcellswithflag(cell, F_DOOR);
if (doorcount == 0) {
if ((countcellexits(newcell) == 1) &&
(iswallindir(newcell,D_N)) &&
(iswallindir(newcell,D_S))) { // always add door
makedoor(cell);
} else {
poss[npossible] = y;
npossible++;
}
}
}
}
if (npossible > 0) {
int sel = rand() % npossible;
//printf("adding W door at %d\n",poss[sel]);
cell = getcellat(map, x, poss[sel]);
makedoor(cell);
}
// E
npossible = 0;
x = maxx;
for (y = miny+1; y <= maxy-1; y++) {
cell = getcellat(map, x, y);
newcell = getcellindir(cell, D_E);
if (newcell && !newcell->type->solid) {
int doorcount;
doorcount = countadjcellswithflag(cell, F_DOOR);
if (doorcount == 0) {
if ((countcellexits(newcell) == 1) &&
(iswallindir(newcell,D_N)) &&
(iswallindir(newcell,D_S))) { // always add door
makedoor(cell);
} else {
poss[npossible] = y;
npossible++;
}
}
}
}
if (npossible > 0) {
int sel = rand() % npossible;
//printf("adding E door at %d\n",poss[sel]);
cell = getcellat(map, x, poss[sel]);
makedoor(cell);
}
// maybe make it a special room
if (rnd(1,100) <= getspecialroomchance(map)) {
enum SPECIALROOMTYPE rt;
rt = getspecialroomtype(map);
if (rt == RT_FLOODED) {
int sx,sy,ex,ey;
char wtype[BUFLEN];
switch (rnd(1,2)) {
case 1: strcpy(wtype, "deep water"); break;
case 2: strcpy(wtype, "shallow water"); break;
}
switch (rnd(1,2)) {
case 1: // entire room flooded
sx = minx+1;
sy = miny+1;
ex = maxx-1;
ey = maxy-1;
break;
case 2: // small walkway around the edge
sx = minx+2;
sy = miny+2;
ex = maxx-2;
ey = maxy-2;
if (sx > ex) sx = ex;
if (sy > ey) sy = ey;
break;
}
for (y = sy; y <= ey; y++) {
for (x = sx; x <= ex; x++) {
cell = getcellat(map, x, y);
addob(cell->obpile, wtype);
}
}
}
}
}
int dirtox(int dt, int dir) {
if (dt == DT_ORTH) {
@ -1897,6 +2028,14 @@ celltype_t *findcelltype(enum CELLTYPE cid) {
return NULL;
}
celltype_t *findcelltypebyname(char *name) {
celltype_t *ct;
for (ct = firstcelltype ; ct ; ct = ct->next) {
if (!strcmp(ct->name, name)) return ct;
}
return NULL;
}
map_t *findmap(int mid) {
map_t *m;
for (m = firstmap ; m ; m = m->next) {
@ -2199,10 +2338,10 @@ int getobchance(int habitat) {
return 0;
}
// chance that a room is a 'special' one
int getspecialroomchance(map_t *m) {
int getvaultchance(map_t *m) {
switch (m->habitat) {
case H_DUNGEON:
return 5;
return 10;
default:
return 0;
}
@ -2210,17 +2349,6 @@ int getspecialroomchance(map_t *m) {
return 0;
}
enum SPECIALROOMTYPE getspecialroomtype(map_t *m) {
if (m->habitat == H_DUNGEON) {
/*
switch (rnd(1,1)) {
}
*/
return RT_FLOODED;
}
return RT_NONE;
}
// chance of each empty cell in a map has of getting an object/monster
@ -2844,7 +2972,7 @@ void makedoor(cell_t *cell) {
chance = rolldie(1,6) - (m->depth / 10);
if (chance <= 1) {
addflag(o->flags, F_LOCKED, B_TRUE, 19 + (m->depth), NA, NULL);
addflag(o->flags, F_LOCKED, B_TRUE, getdoorlockdiff(m->depth), NA, NULL);
}
// make it secret?
@ -2855,7 +2983,7 @@ void makedoor(cell_t *cell) {
// l10 = 25
// l20 = 30
if (chance <= 1) {
addflag(o->flags, F_SECRET, 20 + (m->depth / 2), NA, NA, NULL);
addflag(o->flags, F_SECRET, getdoorsecretdiff(m->depth), NA, NA, NULL);
}
}
}
@ -2960,6 +3088,9 @@ void setcelltype(cell_t *cell, int id) {
cell->type = findcelltype(id);
assert(cell->type);
cell->roomid = 0;
if ((gamemode == GM_GAMESTARTED) && haslos(player, cell)) {
needredraw = B_TRUE;
}
}
@ -2989,3 +3120,19 @@ void updateknowncells(void) {
}
}
}
int wallstoleftright(cell_t *c, int dir) {
int d1,d2;
switch (dir) {
case D_N:
case D_S:
d1 = D_E; d2 = D_W; break;
case D_E:
case D_W:
d1 = D_N; d2 = D_S; break;
}
if (iswallindir(c,d1) && iswallindir(c,d2)) {
return B_TRUE;
}
return B_FALSE;
}

14
map.h
View File

@ -6,15 +6,19 @@ map_t *addmap(void);
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int autogen, int *nadded);
object_t *addrandomob(cell_t *c);
int addrandomthing(cell_t *c, int obchance, int *nadded);
void autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy);
int cellhaslos(cell_t *c1, cell_t *dest);
cell_t *getcellat(map_t *map, int x, int y);
int getcelldist(cell_t *src, cell_t *dst);
int getcelldistorth(cell_t *src, cell_t *dst);
void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer);
int getdoorlockdiff(int depth);
int getdoorsecretdiff(int depth);
enum CELLTYPE getemptycelltype(enum HABITAT hab);
enum CELLTYPE getwallcelltype(enum HABITAT hab);
flag_t *getmapcoords(map_t *m, int *x, int *y);
int getmapdifficulty(map_t *m);
void getroomedge(map_t *m, int roomid, int minx, int miny, int maxx, int maxy, int whichside, cell_t **retcell, int *ncells);
object_t *gettopobject(cell_t *where);
void calclight(map_t *map);
int calcroompos(map_t *map, int w, int h, int *bx, int *by);
@ -24,13 +28,15 @@ int countcellexits(cell_t *cell);
void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir);
void createforest(map_t *map, int depth, map_t *parentmap, int exitdir);
void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap, int exitdir);
void createroom(map_t *map, int minx, int miny, int w, int h, int roomid);
int createroom(map_t *map, int roomid, int overrideminw, int overrideminh, int *retx, int *rety, int *retw, int *reth);
int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth);
int dirtox(int dt, int dir);
int dirtoy(int dt, int dir);
void dumpmap(map_t *map);
void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *centre);
void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int dirtype, int wantannounce);
celltype_t *findcelltype(enum CELLTYPE cid);
celltype_t *findcelltypebyname(char *name);
map_t *findmap(int mid);
map_t *findmapofdepth(int depth);
cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf);
@ -41,8 +47,8 @@ void forgetcells(map_t *map, int amt);
cell_t *getcellindir(cell_t *cell, int dir);
int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved);
int getobchance(int habitat);
int getspecialroomchance(map_t *m);
enum SPECIALROOMTYPE getspecialroomtype(map_t *m);
int getvaultchance(map_t *m);
char getvaultchar(vault_t *v, int x, int y);
int getthingchance(int habitat);
cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand);
cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob);
@ -70,6 +76,7 @@ int isnewcellok(cell_t *cell, char *err);
int isonmap(map_t *map, int x, int y);
int isoutdoors(map_t *m);
int iswallindir(cell_t *cell, int dir);
void linkdoors(map_t *m, int roomid, int minx, int miny, int maxx, int maxy);
int linkstairs(object_t *o);
void makedoor(cell_t *cell);
void makelit(cell_t *c, enum LIGHTLEV how, int howlong);
@ -77,3 +84,4 @@ void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong);
void setcellknown(cell_t *cell, int forcelev);
void setcelltype(cell_t *cell, int id);
void updateknowncells(void);
int wallstoleftright(cell_t *c, int dir);

58
move.c
View File

@ -143,6 +143,16 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err
// obvious things that you can see
if (!onlyifknown || (haslos(lf, cell) && !lfhasflag(lf, F_UNDEAD))) {
// water needing creature out of water?
if (lfhasflag(lf, F_NEEDSWATER)) {
if (!hasobwithflag(cell->obpile, F_DEEPWATER)) {
if (error) {
*error = E_DANGEROUS;
}
return B_TRUE;
}
}
for (o = cell->obpile->first ; o ; o = o->next) {
f = hasflag(o->flags, F_DEEPWATER);
if (f) {
@ -156,14 +166,6 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err
return B_TRUE;
}
}
} else {
// water needing creature out of water?
if (lfhasflag(lf, F_NEEDSWATER)) {
if (error) {
*error = E_DANGEROUS;
}
return B_TRUE;
}
}
f = hasflag(o->flags, F_WALKDAM);
if (f) {
@ -566,7 +568,6 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
char newlfname[BUFLEN];
int seen;
int mightfall = B_TRUE;
cell_t *newcell;
lifeform_t *newlf;
// calculate chance of falling
@ -600,6 +601,9 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
trymove(lf, dir, B_FALSE);
}
if (reason != E_OK) {
char buf[BUFLEN];
cell_t *newcell;
newcell = getcellindir(lf->cell, dir);
// failed to move
switch (reason) {
case E_OFFMAP:
@ -611,8 +615,10 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
}
// fall through
case E_WALLINWAY:
if (seen) msg("%s slam%s into a wall!",lfname,isplayer(lf) ? "" : "s");
losehp(lf, rnd(1,6), DT_BASH, pusher, "slamming into a wall");
if (seen) msg("%s slam%s into a %s!",lfname,isplayer(lf) ? "" : "s",
newcell ? newcell->type->name : "wall");
sprintf(buf, "slamming into a %s", newcell ? newcell->type->name : "wall");
losehp(lf, rnd(1,6), DT_BASH, pusher, buf);
// stop moving
i = howfar;
// don't fall
@ -1313,7 +1319,11 @@ int opendoor(lifeform_t *lf, object_t *o) {
if (amt < 0) amt = 0;
if (lf && isplayer(lf)) {
msg("You yank on the door but it holds fast.");
if (amt > 0) {
msg("The door moves slightly but seems jammed.");
} else {
msg("The door is jammed.");
}
}
// loosen a bit
if (amt) {
@ -1758,11 +1768,15 @@ int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke) {
// can't teleport on top of something else
if (c->lf) {
// go somewhere nearby
c = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND);
if (!c) {
if (isplayer(lf)) {
msg("You feel a wrenching sensation.");
}
return B_TRUE;
}
}
if (!isplayer(lf) && cansee(player, lf)) {
getlfname(lf, buf);
@ -1953,25 +1967,31 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
// otherwise fall through...
case E_WALLINWAY:
if (isplayer(lf)) {
msg("Ouch! You %s into a wall.", getmoveverb(lf));
msg("Ouch! You %s into a %s.", getmoveverb(lf),
cell ? cell->type->name : "wall");
} else if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s %ss into a wall.", buf, getmoveverb(lf));
msg("%s %ss into a %s.", buf, getmoveverb(lf),
cell ? cell->type->name : "wall");
}
//if (isblind(lf) || !haslos(lf, cell)) {
if (!haslos(lf, cell)) {
if (!cell || !haslos(lf, cell)) {
if (isplayer(lf)) {
// only take damage if we didn't know about this
if (!cell->known || isdrunk(lf)) {
sprintf(buf, "%sing into a wall", getmoveverb(lf));
if ((cell && !cell->known) || isdrunk(lf)) {
sprintf(buf, "%sing into a %s", getmoveverb(lf),
cell ? cell->type->name : "wall");
losehp(lf, 1, DT_BASH, NULL, buf);
if (cell) {
// we now know there is a wall there.
setcellknown(cell, B_FALSE);
}
if (onpurpose) taketime(lf, getmovespeed(lf));
}
} else {
sprintf(buf, "%sing into a wall", getmoveverb(lf));
sprintf(buf, "%sing into a %s", getmoveverb(lf),
cell ? cell->type->name : "wall");
losehp(lf, 1, DT_BASH, NULL, buf);
if (onpurpose) taketime(lf, getmovespeed(lf));
}
@ -1997,7 +2017,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
} else {
if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s %ss into a wall.", buf, getmoveverb(lf));
msg("%s %ss into a door.", buf, getmoveverb(lf));
}
sprintf(buf, "%sing into a door", getmoveverb(lf));
losehp(lf, 1, DT_BASH, NULL, buf);

26
nexus.c
View File

@ -17,6 +17,7 @@
#include "objects.h"
#include "save.h"
#include "text.h"
#include "vault.h"
material_t *material = NULL,*lastmaterial = NULL;
objectclass_t *objectclass = NULL,*lastobjectclass = NULL;
@ -33,6 +34,8 @@ map_t *firstmap = NULL,*lastmap = NULL;
knowledge_t *knowledge = NULL, *lastknowledge = NULL;
hiddenname_t *firsthiddenname = NULL, *lasthiddenname = NULL;
extern vault_t *firstvault;
glyph_t playerglyph,tempglyph;
double startticks,lastticks;
@ -86,6 +89,7 @@ int main(int argc, char **argv) {
FILE *playerfile = NULL;
int x,y;
cell_t *c;
vault_t *v;
atexit(cleanup);
@ -117,11 +121,11 @@ int main(int argc, char **argv) {
// init graphics
initgfx();
// if no maps, make the initial level
if (!firstmap) {
newworld = B_TRUE;
addmap();
createmap(firstmap, 1, RG_FIRSTDUNGEON, H_DUNGEON, NULL, D_NONE);
// warn about vault problems.
for (v = firstvault ; v ; v = v->next) {
if (!v->valid) {
msg("warning: invalid vaultfile '%s'",v->filename); more();
}
}
if (!knowledge) {
@ -169,6 +173,13 @@ int main(int argc, char **argv) {
}
}
// if no maps (ie. ALWAYS now that maps aren't persistent),
// make the initial level
if (!firstmap) {
newworld = B_TRUE;
addmap();
createmap(firstmap, 1, RG_FIRSTDUNGEON, H_DUNGEON, NULL, D_NONE);
}
// find staircase
where = findobinmap(firstmap, OT_STAIRSUP);
@ -740,6 +751,8 @@ int init(void) {
// cell types
addcelltype(CT_WALL, "rock wall", '#', C_GREY, B_SOLID, B_OPAQUE, MT_STONE);
addcelltype(CT_WALLGLASS, "glass wall", '#', C_CYAN, B_SOLID, B_TRANS, MT_GLASS);
addcelltype(CT_WALLMETAL, "metal wall", '#', C_WHITE, B_SOLID, B_OPAQUE, MT_METAL);
addcelltype(CT_ROOMWALL, "rock wall", '#', C_GREY, B_SOLID, B_OPAQUE, MT_STONE);
addcelltype(CT_CORRIDOR, "rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE);
addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', C_GREY, B_EMPTY, B_TRANS, MT_STONE);
@ -759,6 +772,9 @@ int init(void) {
logfile = fopen("log.txt","wt");
fprintf(logfile, "\n\n\n====== NEW LOGFILE ====\n");
// load in vaults
loadvaults();
return B_FALSE;
}

483
objects.c
View File

@ -73,6 +73,7 @@ enum OBCLASS sortorder[] = {
OC_ROCK,
OC_FLORA,
OC_DFEATURE,
OC_TRAP,
OC_MISC,
// omitting OC_SPELL and OC_JUMP because it shouldn't ever be displayed
OC_NULL
@ -370,6 +371,7 @@ objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph, int gl
// props
a->id = id;
a->name = strdup(name);
a->nnouns = 0;
a->desc = strdup(desc);
a->glyph.ch = glyph;
a->glyph.colour = glyphcolour;
@ -378,6 +380,12 @@ objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph, int gl
return a;
}
void addocnoun(objectclass_t *oc, char *text) {
assert (oc->nnouns < MAXOCNOUNS);
oc->noun[oc->nnouns] = strdup(text);
oc->nnouns++;
}
// create a new object, stacking ok
@ -402,17 +410,27 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
char *localname;
int wantblessed = B_UNCURSED;
race_t *corpserace = NULL;
int dorandombrand = B_FALSE;
brand_t *wantbrand = NULL;
brand_t *br;
obmod_t *om;
obmod_t *wantom[MAXOBMODS];
int nom = 0;
int n;
int bookcontents = -1;
int wantrarity = RR_NONE;
int wantgoodness = G_NA;
int donesomething;
object_t *addedob[MAXPILEOBS];
int nadded = 0;
// for doors
enum FLAG doorflag[5];
int ndoorflags = 0;
addedob[0] = NULL; // just in case we don't add any
localname = strdup(name);
// check for premods. eg. "flaming xxx" "frozen xxx" etc
for (om = firstobmod ; om ; om = om->next) {
if (db) dblog("DB: checking for '%s' in '%s'",om->prefix, localname);
@ -431,6 +449,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
if (where->owner && hasflag(where->owner->flags, F_NOPACK)) {
if (db) dblog("error giving ob '%s' - owner isn't allowed to carry objects!", name);
nretobs = 0;
return NULL;
}
@ -485,23 +504,94 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
howmany = 1;
}
// new objects after the game starts have unknown
// blessed/cursed status, so we can never stack them
// if (gamestarted && !hasflag(player->flags, F_DETECTAURAS)) {
if (strstr(p, "blessed") || strstr(p, "holy water")) {
// handle prefixes. strip them off as we go.
donesomething = B_TRUE;
while (donesomething) {
donesomething = B_FALSE;
if (strstarts(p, "blessed ")) {
if (db) dblog("DB: ob is blessed (%s)",p);
wantblessed = B_BLESSED;
//canstack = B_FALSE;
} else if (strstr(p, "uncursed")) {
p += strlen("blessed ");
donesomething = B_TRUE;
} else if (strstarts(p, "uncursed ")) {
if (db) dblog("DB: ob is uncursed (%s)",p);
wantblessed = B_UNCURSED;
} else if (strstr(p, "cursed") || strstr(p, "incompetence")) {
p += strlen("uncursed ");
donesomething = B_TRUE;
} else if (strstarts(p, "cursed ")) {
if (db) dblog("DB: ob is cursed (%s)",p);
wantblessed = B_CURSED;
//canstack = B_FALSE;
p += strlen("cursed ");
donesomething = B_TRUE;
// door flags
} else if (strstarts(p, "locked ")) {
doorflag[ndoorflags++] = F_LOCKED;
p += strlen("locked ");
donesomething = B_TRUE;
} else if (strstarts(p, "jammed ")) {
doorflag[ndoorflags++] = F_JAMMED;
p += strlen("jammed ");
donesomething = B_TRUE;
} else if (strstarts(p, "secret ")) {
doorflag[ndoorflags++] = F_SECRET;
p += strlen("secret ");
donesomething = B_TRUE;
// rarity
} else if (strstarts(p, "common ")) {
wantrarity = RR_COMMON;
p += strlen("common ");
donesomething = B_TRUE;
} else if (strstarts(p, "uncommon ")) {
wantrarity = RR_UNCOMMON;
p += strlen("uncommon ");
donesomething = B_TRUE;
} else if (strstarts(p, "rare ")) {
wantrarity = RR_RARE;
p += strlen("rare ");
donesomething = B_TRUE;
} else if (strstarts(p, "very rare ")) {
wantrarity = RR_VERYRARE;
p += strlen("very rare ");
donesomething = B_TRUE;
// weapon "goodness"
} else if (strstarts(p, "average ")) {
wantgoodness = G_AVERAGE;
p += strlen("average ");
donesomething = B_TRUE;
} else if (strstarts(p, "good ")) {
wantgoodness = G_GOOD;
if (onein(4)) wantblessed = B_BLESSED;
p += strlen("good ");
donesomething = B_TRUE;
} else if (strstarts(p, "great ")) {
wantgoodness = G_GREAT;
if (onein(3)) wantblessed = B_BLESSED;
if (onein(10)) dorandombrand = B_TRUE;
p += strlen("great ");
donesomething = B_TRUE;
} else if (strstarts(p, "excellent ")) {
wantgoodness = G_EXCELLENT;
if (onein(2)) wantblessed = B_BLESSED;
if (onein(4)) dorandombrand = B_TRUE;
p += strlen("excellent ");
donesomething = B_TRUE;
// brands
} else if (strstarts(p, "branded ")) {
dorandombrand = B_TRUE;
p += strlen("branded ");
donesomething = B_TRUE;
}
}
// }
if (strstr(p, "holy water") || strstr(p, "incompetence")) {
if (db) dblog("DB: ob is blessed (%s)",p);
wantblessed = B_BLESSED;
}
////////////////////////////////////
// handle special object names
////////////////////////////////////
if (strstr(p, "corpse")) {
int len;
char racename[BUFLEN];
@ -556,8 +646,41 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
}
}
ot = findot(OT_MANUAL);
////////////////////////////////////
// also handle generic names
////////////////////////////////////
} else {
// make sure we can find the requested object type
objectclass_t *oc;
char tempname[BUFLEN];
int found = B_FALSE;
// check for things like "weapon" or "random ring"
for (oc = objectclass; oc ; oc = oc->next) {
int i;
int matched = B_FALSE;
for (i = 0; i < oc->nnouns; i++) {
sprintf(tempname, "random %s", oc->noun[i]);
if (strstarts(p, tempname) || streq(p, oc->noun[i])) {
matched = B_TRUE;
}
if (matched) {
int minrarity,maxrarity;
// want a specific rarity?
rrtorarity(wantrarity, &minrarity, &maxrarity);
ot = getrandomobofclass(oc->id, minrarity, maxrarity);
if (ot) {
found = B_TRUE;
break;
}
}
}
if (found) break;
}
if (!found) {
// look up the object name
if (db) dblog("DB: Looking for object name '%s'", p );
ot = findotn(p);
if (!ot) {
@ -566,8 +689,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
return NULL;
}
}
}
if (db) dblog("DB: FOUND: ot->name = '%s'", ot->name );
// we now have the objecttype.
// override blessed status from flags...
f = hasflag(ot->flags, F_STARTBLESSED);
if (f) {
@ -576,11 +702,13 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
// don't give nopickup objects to lifeforms
if (hasflag(ot->flags, F_NOPICKUP) && where->owner) {
nretobs = 0;
return NULL;
}
if (ot->obclass->id == OC_SPELL) {
if (db) dblog("DB: Cannot give a spell object! object name '%s'", p );
nretobs = 0;
return NULL;
}
@ -595,6 +723,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
// does this unique ob already exist?
if (obexists(ot->id)) {
if (db) dblog("DB: Unique ob %s already exists!", p );
nretobs = 0;
return NULL;
}
@ -615,10 +744,22 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
// does the pile already contain one?
existob = canstacknewot(where, ot);
if (existob) {
int n,found = B_FALSE;
if (db) dblog("DB: STACK FOUND (%d x %s). Adding %d obs to existing stack.",existob->amt, existob->type->name, howmany);
existob->amt++;
added = B_TRUE;
o = existob;
// if this isn't already in our list of added obs, add it
for (n = 0; n < nadded; n++) {
if (addedob[n] == o) {
found = B_TRUE;
break;
}
}
if (!found) {
addedob[nadded++] = o;
}
} else {
if (db) dblog("DB: No stacks found.");
}
@ -715,6 +856,9 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
setblessed(o, wantblessed);
}
o->blessknown = B_FALSE;
addedob[nadded++] = o;
if (canstack) {
// stop looping through
break;
@ -722,6 +866,43 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
}
}
/*
need to do the below for _all_ objects added!
*/
for (i = 0; i < nadded; i++) {
o = addedob[i];
// fill in door flags
if (ndoorflags && isdoor(o, NULL)) {
int n;
for (n = 0; n < ndoorflags; n++) {
cell_t *c;
int val[3];
c = getoblocation(o);
// fill in flag vals
switch (doorflag[n]) {
case F_LOCKED:
val[0] = B_TRUE;
val[1] = getdoorlockdiff(c->map->depth);
val[2] = NA;
break;
case F_JAMMED:
val[0] = rnd(1,c->map->depth+3);
val[1] = NA;
val[2] = NA;
break;
case F_SECRET:
val[0] = getdoorsecretdiff(c->map->depth);
val[1] = NA;
val[2] = NA;
break;
default: break;
}
addflag(o->flags, doorflag[n], val[0], val[1], val[2], NULL);
}
}
// fill in book types
if (o && (o->type->obclass->id == OC_BOOK)) {
hiddenname_t *hn,*selhn = NULL;
@ -916,6 +1097,20 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
}
// chance of masterwork based on wantgoodness
switch (wantgoodness) {
case G_GREAT:
if (onein(6)) {
wantom[nom++] = findobmod(OM_MASTERWORK);
}
break;
case G_EXCELLENT:
if (onein(3)) {
wantom[nom++] = findobmod(OM_MASTERWORK);
}
break;
}
for (n = 0; n < nom; n++) {
// add flags from obmod
applyobmod(o, wantom[n]);
@ -1033,6 +1228,30 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
bonus -= atoi(numbuf);
}
// if no bonus yet, get one based on 'wantgoodness'
if (!bonus) {
switch (wantgoodness) {
case G_GOOD: // 1 - 2
bonus = 1;
if (onein(2)) bonus++;
break;
case G_GREAT: // 1 - 3
bonus = 1;
while (onein(2) && (bonus < 3)) {
bonus++;
}
break;
case G_EXCELLENT: // 1 - 4
bonus = 1;
while (onein(2) && (bonus < 4)) {
bonus++;
}
break;
default: // no bonus
break;
}
}
if (bonus) {
if (hasflag(o->flags, F_ENCHANTABLE)) {
// for swords, armour etc
@ -1076,24 +1295,31 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
if (o->blessed == B_CURSED) f->val[2] *= -1;
}
// check for postmods. eg. "xxx of pyromania"
// now apply a random brand if we wanted one
if (dorandombrand) {
wantbrand = getrandombrandfor(ot);
}
// check for specific brands. eg. "xxx of pyromania"
// NOTE: this will override any random brands from "branded"
for (br = firstbrand ; br ; br = br->next) {
if (strstr(name, br->suffix)) {
// does this brand apply to this objecttype?
if (brandappliesto(br, o->type)) {
copyflags(o->flags, br->flags, FROMBRAND);
addflag(o->flags, F_HASBRAND, br->id, NA, NA, NULL);
} else {
// doesn't exist!
return NULL;
wantbrand = br;
break;
}
}
}
if (wantbrand) {
if (brandappliesto(wantbrand, o->type)) {
copyflags(o->flags, wantbrand->flags, FROMBRAND);
addflag(o->flags, F_HASBRAND, wantbrand->id, NA, NA, NULL);
}
}
free(localname);
}
if (where->owner) {
// new owner gains "hold confer" flags conferred by this object
@ -1135,9 +1361,22 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
needredraw = B_TRUE;
}
}
} // end foreach added object
// return the last object given
return o;
// don't need the name anymore.
free(localname);
// populate retobs
for (i = 0; i < nadded; i++) {
if (addedob[i]) {
retobs[i] = addedob[i];
retobscount[i] = addedob[i]->amt;
}
}
nretobs = nadded;
// return the first object given
return addedob[0];
}
@ -1225,7 +1464,6 @@ obpile_t *addobpile(lifeform_t *owner, cell_t *where) {
return op;
}
void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes) {
int x,y;
objecttype_t *ot;
@ -2082,6 +2320,29 @@ void damageallobs(object_t *srcob, obpile_t *op, int howmuch, int damtype) {
}
}
void dumpobrarity(void) {
enum RARITY rr;
objecttype_t *ot;
flag_t *f;
int min,max;
for (rr = RR_COMMON; rr <= RR_VERYRARE; rr++) {
rrtorarity(rr, &min, &max);
dblog("Obs with rarity %s:", getrarityname(rr));
for (ot = objecttype ; ot ; ot = ot->next) {
if (ot->obclass->id == OC_ARMOUR) {
int thisrar;
f = hasflag(ot->flags, F_RARITY);
if (!f) continue;
thisrar = f->val[1];
if ((thisrar >= min) && (thisrar <= max)) {
dblog("\t%s", ot->name);
}
}
}
}
}
void explodeob(object_t *o, flag_t *f, int bigness) {
cell_t *c;
@ -2672,15 +2933,15 @@ int getobvalue(object_t *o) {
}
// one-off magical effects (linkspell) - use spell price
if (f->id == F_LINKSPELL) {
// spelllevel^2 * 20
price += (pow(getspelllevel(f->val[0]), 2) * 20);
// ...and spellbooks then cost triple
if (o->type->obclass->id == OC_BOOK) {
price *= 3;
price += (pow(getspelllevel(f->val[0]), 2) * 30);
} else if (o->type->obclass->id == OC_SCROLL) {
// do nothing
price += (pow(getspelllevel(f->val[0]), 2) * 2);
} else if (o->type->obclass->id == OC_POTION) {
price += (pow(getspelllevel(f->val[0]), 2) * 15);
} else if (o->type->obclass->id == OC_WAND) {
price *= 2.25;
price += (pow(getspelllevel(f->val[0]), 2) * 22);
}
} else if (f->id == F_MANUALOF) {
price *= 124;
@ -2756,6 +3017,8 @@ int getobvalue(object_t *o) {
// minimum
if (price < 1) price = 1;
price = ((int)price * o->amt);
return (int) price;
}
@ -2828,6 +3091,72 @@ object_t *getrandomammo(lifeform_t *lf) {
return NULL;
}
brand_t *getrandombrandfor(objecttype_t *ot) {
brand_t *br, **poss;
brand_t *result = NULL;
int numbr;
int nposs = 0;
// count number of brands
numbr = 0;
for (br = firstbrand ; br ; br = br->next) {
numbr++;
}
poss = malloc(numbr * sizeof(brand_t *));
for (br = firstbrand ; br ; br = br->next) {
if (brandappliesto(br, ot)) {
poss[nposs] = br;
nposs++;
}
}
if (nposs > 0) {
result = poss[rnd(0,nposs-1)];
}
free(poss);
return result;
}
objecttype_t *getrandomobofclass(enum OBCLASS ocid, int minrarity, int maxrarity) {
objecttype_t *ot;
int count = 0,sel,n;
flag_t *f;
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == ocid) && !hasflag(ot->flags, F_UNIQUE)) {
f = hasflag(ot->flags, F_RARITY);
if (f) {
if ( ((minrarity == NA) || (f->val[1] >= minrarity)) &&
((maxrarity == NA) || (f->val[1] <= maxrarity)) ) {
count++;
}
}
}
}
if (count <= 0) {
return NULL;
}
sel = rnd(1,count);
n = 0;
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == ocid) && !hasflag(ot->flags, F_UNIQUE)) {
f = hasflag(ot->flags, F_RARITY);
if (f) {
if ( ((minrarity == NA) || (f->val[1] >= minrarity)) &&
((maxrarity == NA) || (f->val[1] <= maxrarity)) ) {
n++;
if (n == sel) {
return ot;
}
}
}
}
}
return NULL;
}
char *getdamname(enum DAMTYPE damtype) {
switch (damtype) {
case DT_ALL: return "all damage";
@ -4041,29 +4370,9 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth
// if so...
strcpy(brandname, "");
if (rnd(1,100) <= depth) {
brand_t *om, **poss;
int numom;
int nposs = 0;
// count number of brands
numom = 0;
for (om = firstbrand ; om ; om = om->next) {
numom++;
}
poss = malloc(numom * sizeof(brand_t *));
for (om = firstbrand ; om ; om = om->next) {
if (brandappliesto(om, ot)) {
poss[nposs] = om;
nposs++;
}
}
if (nposs > 0) {
om = poss[rnd(0,nposs-1)];
strcpy(brandname, om->suffix);
}
free(poss);
brand_t *br;
br = getrandombrandfor(ot);
if (br) strcpy(brandname, br->suffix);
}
@ -4101,13 +4410,13 @@ int getobrarity(object_t *o) {
if (m) {
f = hasflagval(o->flags, F_RARITY,m->habitat, NA, NA, NULL);
if (f) {
return f->val[0];
return f->val[1];
}
}
// any rarity value at all?
f = hasflag(o->flags, F_RARITY);
if (f) {
return f->val[0];
return f->val[1];
}
// ie. doesn't randomly appear
return 0;
@ -4696,8 +5005,11 @@ void initobjects(void) {
// object classes
addoc(OC_DFEATURE, "Dungeon Features", "Doors, etc.", '\\', C_GREY);
addoc(OC_TERRAIN, "Terrain", "Water, etc.", '\\', C_GREY);
addoc(OC_TRAP, "Trap", "Fiendish traps.", '^', C_GREY);
addocnoun(lastobjectclass, "trap");
addoc(OC_MONEY, "Money", "The standard currency of Nexus.", '$', C_GREY);
addoc(OC_SCROLL, "Scrolls", "An arcane roll of parchment, inscribed with many magical glyphs.", '?', C_GREY);
addocnoun(lastobjectclass, "scroll");
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -4707,6 +5019,7 @@ void initobjects(void) {
//addflag(lastobjectclass->flags, F_MATCONVERTTEXTPL, MT_WATER, NA, NA, "go soggy");
addoc(OC_WAND, "Wands", "A limited-use magical wand which casts the imbued spell.", '/', C_GREY);
addocnoun(lastobjectclass, "wand");
addflag(lastobjectclass->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
@ -4714,34 +5027,45 @@ void initobjects(void) {
addflag(lastobjectclass->flags, F_RNDCHARGES, 1, 8, NA, NULL);
addoc(OC_POTION, "Potions", "A strange concoction contained within a small flask.", '!', C_GREY);
addocnoun(lastobjectclass, "potion");
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_POURABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL);
addoc(OC_RING, "Rings", "A circular band, worn on the finger.", '=', C_GREY);
addocnoun(lastobjectclass, "ring");
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_GOESON, BP_RIGHTHAND, NA, NA, NULL);
addflag(lastobjectclass->flags, F_GOESON, BP_LEFTHAND, NA, NA, NULL);
addoc(OC_WEAPON, "Weapons", "An instrument used for the purpose of causing harm or death.", ')', C_GREY);
addocnoun(lastobjectclass, "weapon");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_MASTERWORK, 17, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_SHODDY, 34, NA, NULL);
addoc(OC_ARMOUR, "Armour/Clothing", "Protective gear.", ']', C_GREY);
addocnoun(lastobjectclass, "armour");
addocnoun(lastobjectclass, "clothing");
addocnoun(lastobjectclass, "clothes");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_MASTERWORK, 17, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_SHODDY, 34, NA, NULL);
addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_BLOODSTAINED, 17, NA, NULL);
addoc(OC_MISSILE, "Missiles/Ammunition", "An instrument used for the purpose of causing harm or death.", ';', C_GREY);
addocnoun(lastobjectclass, "missile");
addocnoun(lastobjectclass, "ammo");
addocnoun(lastobjectclass, "ammunition");
addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addoc(OC_FLORA, "Plants", "All kinds of plants and foliage", ',', C_GREEN);
addocnoun(lastobjectclass, "plant");
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_ROCK, "Rocks/Gems", "Boring (or not so boring) rocks or plants.", '*', C_GREY);
addoc(OC_FOOD, "Food", "Yum!", '%', C_GREY);
addocnoun(lastobjectclass, "food");
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_CORPSE, "Corpses", "Dead flesh which was once living.", '%', C_GREY);
@ -4751,9 +5075,12 @@ void initobjects(void) {
addflag(lastobjectclass->flags, F_OBHP, 50, 50, NA, NULL);
addflag(lastobjectclass->flags, F_OBHPDRAIN, 1, DT_DECAY, NA, NULL); // ie. corpses last for 50 turns
addoc(OC_TECH, "Technology", "A strange piece of futuristic technology.", '~', C_GREY);
addocnoun(lastobjectclass, "technology");
addocnoun(lastobjectclass, "tech");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_TOOLS, "Tools", "Useful items, from the common to the obscure.", '[', C_GREY);
addocnoun(lastobjectclass, "tool");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_MISC, "Miscellaneous", "This could be anything.", '\\', C_GREY);
@ -4761,6 +5088,9 @@ void initobjects(void) {
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addoc(OC_BOOK, "Books", "Spellbooks, tomes or manuals.", '+', C_GREY);
addocnoun(lastobjectclass, "spellbook");
addocnoun(lastobjectclass, "book");
addocnoun(lastobjectclass, "tome");
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_SPELL, "Spells", "A magical spell", '&', C_GREY); // this is a "virtual" object class
@ -4900,7 +5230,7 @@ void initobjects(void) {
addflag(lastot->flags, F_REDUCEMOVEMENT, 4, NA, NA, NULL);
// traps
addot(OT_TRAPTRIP, "tripwire", "A thin wire at ankle height.", MT_NOTHING, 0, OC_MISC);
addot(OT_TRAPTRIP, "tripwire", "A thin wire at ankle height.", MT_NOTHING, 0, OC_TRAP);
addflag(lastot->flags, F_TRAP, 10, B_FALSE, 20, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
@ -4908,7 +5238,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 25, NA, NA, NULL);
addot(OT_TRAPROCK, "falling rock trap", "A pressure plate which causes heavy rocks to drop from the ceiling.", MT_NOTHING, 0, OC_MISC);
addot(OT_TRAPROCK, "falling rock trap", "A pressure plate which causes heavy rocks to drop from the ceiling.", MT_NOTHING, 0, OC_TRAP);
addflag(lastot->flags, F_TRAP, 20, B_TRUE, 22, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^");
@ -4916,7 +5246,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 25, NA, NA, NULL);
addot(OT_TRAPARROW, "arrow trap", "A pressure plate which causes arrows to shoot at you.", MT_NOTHING, 0, OC_MISC);
addot(OT_TRAPARROW, "arrow trap", "A pressure plate which causes arrows to shoot at you.", MT_NOTHING, 0, OC_TRAP);
addflag(lastot->flags, F_TRAP, 25, B_TRUE, NA, NULL);
addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 76, NA, NULL);
@ -4925,7 +5255,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addot(OT_TRAPARROWP, "poison arrow trap", "A pressure plate which causes poisoned arrows to shoot at you.", MT_NOTHING, 0, OC_MISC);
addot(OT_TRAPARROWP, "poison arrow trap", "A pressure plate which causes poisoned arrows to shoot at you.", MT_NOTHING, 0, OC_TRAP);
addflag(lastot->flags, F_TRAP, 25, B_TRUE, NA, NULL);
addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 69, NA, NULL);
@ -4934,7 +5264,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addot(OT_TRAPGAS, "gas trap", "A pressure plate which releases poisonous gas.", MT_NOTHING, 0, OC_MISC);
addot(OT_TRAPGAS, "gas trap", "A pressure plate which releases poisonous gas.", MT_NOTHING, 0, OC_TRAP);
addflag(lastot->flags, F_TRAP, 27, B_TRUE, NA, NULL);
addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 69, NA, NULL);
@ -4943,7 +5273,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addot(OT_TRAPFIRE, "fire trap", "A pressure plate which fires a pillar of flame.", MT_NOTHING, 0, OC_MISC);
addot(OT_TRAPFIRE, "fire trap", "A pressure plate which fires a pillar of flame.", MT_NOTHING, 0, OC_TRAP);
addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL);
addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 59, NA, NULL);
@ -4952,7 +5282,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL);
addot(OT_TRAPMINE, "landmine trap", "A buried, pressure-sensitive explosive device.", MT_NOTHING, 0, OC_MISC);
addot(OT_TRAPMINE, "landmine trap", "A buried, pressure-sensitive explosive device.", MT_NOTHING, 0, OC_TRAP);
addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL);
addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
@ -8761,11 +9091,15 @@ void killobpile(obpile_t *op) {
void killoc(objectclass_t *oc) {
objectclass_t *nextone, *lastone;
int i;
// free mem
free(oc->name);
free(oc->desc);
if (oc->flags) killflagpile(oc->flags);
for (i = 0; i < oc->nnouns; i++) {
free(oc->noun[i]);
}
// remove from list
nextone = oc->next;
@ -11313,6 +11647,37 @@ int removeob(object_t *o,int howmany) {
return o->amt;
}
void rrtorarity(enum RARITY r, int *minr, int *maxr) {
switch (r) {
case RR_UNIQUE:
case RR_NEVER:
if (minr) *minr = 0;
if (maxr) *maxr = 0;
break;
case RR_VERYRARE:
if (minr) *minr = 0;
if (maxr) *maxr = 49;
break;
case RR_RARE:
if (minr) *minr = 50;
if (maxr) *maxr = 64;
break;
case RR_UNCOMMON:
if (minr) *minr = 65;
if (maxr) *maxr = 79;
break;
case RR_COMMON:
if (minr) *minr = 80;
if (maxr) *maxr = 100;
break;
default:
if (minr) *minr = 0;
if (maxr) *maxr = 100; // ie. rarity can be anything
break;
}
}
void setblessed(object_t *o, enum BLESSTYPE wantbless) {
o->blessed = wantbless;
if (wantbless != B_BLESSED) {

View File

@ -8,6 +8,7 @@ hiddenname_t *addhiddenname(enum OBCLASS obclass, char *text);
knowledge_t *addknowledge(enum OBCLASS 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, char glyph, int glyphcolour);
void addocnoun(objectclass_t *oc, char *text);
object_t *addob(obpile_t *where, char *name);
object_t *addobject(obpile_t *where, char *name, int canstack);
int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fromlf, enum LOFTYPE needlof);
@ -38,6 +39,7 @@ int countnoncosmeticobs(obpile_t *op, int onlyifknown);
int curseob(object_t *o);
void damageallobs(object_t *srcob, obpile_t *op, int howmuch, int damtype);
void dumprandomobs(int amt);
void dumpobrarity(void);
void explodeob(object_t *o, flag_t *f, int bigness);
void extinguish(object_t *o);
material_t *findmaterial(int id);
@ -64,6 +66,8 @@ int getobvalue(object_t *o);
char *getaccuracyname(int accpct);
object_t *getammo(lifeform_t *lf);
object_t *getrandomammo(lifeform_t *lf);
brand_t *getrandombrandfor(objecttype_t *ot);
objecttype_t *getrandomobofclass(enum OBCLASS ocid, int minrarity, int maxrarity);
char *getdamname(enum DAMTYPE damtype);
char *getdamnamenoun(enum DAMTYPE damtype);
char *getfillingname(int nutrition);
@ -193,6 +197,7 @@ int readsomething(lifeform_t *lf, object_t *o);
void removedeadobs(obpile_t *op);
int removeob(object_t *o, int howmany);
object_t *relinkob(object_t *src, obpile_t *dst);
void rrtorarity(enum RARITY r, int *minr, int *maxr);
void setblessed(object_t *o, enum BLESSTYPE wantbless);
void setinscription(object_t *o, char *text);
void setobcreatedby(object_t *o, lifeform_t *lf);

39
spell.c
View File

@ -31,6 +31,10 @@ extern objecttype_t *objecttype;
extern map_t *firstmap;
extern object_t *retobs[MAXPILEOBS+1];
extern int retobscount[MAXPILEOBS+1];
extern int nretobs;
extern enum ERROR reason;
extern int needredraw, statdirty;
@ -2238,12 +2242,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int seenthiscell = B_FALSE;
if (haslos(player, retcell[i])) seenthiscell = B_TRUE;
if (retcell[i]->type->solid) {
// can dig through stone, but nothing else.
if (retcell[i]->type->material->id == MT_STONE) {
setcelltype(retcell[i], getemptycelltype(retcell[i]->map->habitat));
if (seenthiscell) {
ndigs++;
numseen++;
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else {
// stop.
break;
}
} else {
object_t *o;
for (o = retcell[i]->obpile->first ; o ; o = o->next) {
@ -5436,7 +5446,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// confirm
ch = askchar("Are you sure to want to teleport into the unknown?", "yn", "n", B_TRUE);
if (ch != 'y') c = NULL;
} else if (!cellwalkable(caster, c, NULL)) {
} else if (c->type->solid) {
// confirm
ch = askchar("Are you sure to want to teleport into solid rock?", "yn", "n", B_TRUE);
if (ch != 'y') c = NULL;
@ -5544,10 +5554,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
targcell = c;
if (!cellwalkable(caster, c, NULL)) {
if (c->type->solid) {
// ok, but you'll die!
} else if (!cellwalkable(caster, c, NULL)) {
// go somewhere nearby...
c = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND);
if (!c) {
fizzle(caster);
return B_FALSE;
}
}
// we can take up to 'power-1' allies with us.
if (caster == target) {
@ -6104,6 +6120,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (isplayer(caster)) {
char lfname[BUFLEN];
char question[BUFLEN];
int i;
if (seenbyplayer) *seenbyplayer = B_TRUE;
// ask for target
if (spellid == OT_S_GIFT) {
@ -6121,11 +6138,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
sprintf(question, "For what do you wish");
}
askstring(question, '?', buf, BUFLEN, NULL);
o = addob(target->cell->obpile, buf);
if (o) {
addob(target->cell->obpile, buf);
if (nretobs) {
for (i = 0; i < nretobs; i++) {
char obname[BUFLEN];
o = retobs[i];
getobname(o, obname, o->amt);
if (!hasflag(o->flags, F_IMPASSABLE) && canpickup(target, o, ALL)) {
// you gain it.
relinkob(o, target->pack); // move to pack
if (isplayer(target)) {
msgnocap("%c - %s.", o->letter, obname);
@ -6133,12 +6153,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("%s is gifted with %s.", lfname, obname);
}
} else {
// couldn't pick it up - try to place on ground!
// impassable?
// can't pick this up...
// impassable? goes in a nearby cell instead of at your feet.
if (hasflag(o->flags, F_IMPASSABLE)) {
cell_t *newloc;
// if so, don't put it where the player is!
newloc = getrandomadjcell(target->cell, WE_WALKABLE, B_ALLOWEXPAND);
newloc = real_getrandomadjcell(target->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL);
o = relinkob(o, newloc->obpile);
}
if (o) {
@ -6147,8 +6168,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("%s appear%s on the ground!", obname, (o->amt == 1) ? "s" : "");
}
} else {
// couldn't make it appear
// ob exists but couldn't make it appear
msg("The air in front of %s seems to ripple for a moment.", lfname);
break; // don't process any more.
}
}
}
} else {

42
text.c
View File

@ -208,6 +208,20 @@ char *getdrunktext(flag_t *drunkflag) {
return "??drunk??";
}
char *getrarityname(enum RARITY rr) {
switch (rr) {
case RR_UNIQUE: return "Unique";
case RR_NEVER: return "Never";
case RR_VERYRARE: return "Very Rare";
case RR_RARE: return "Rare";
case RR_UNCOMMON: return "Uncommon";
case RR_COMMON: return "Common";
case RR_NONE: return "None";
}
return "?unknownrarity?";
}
char *getsizetext(enum LFSIZE sz) {
switch (sz) {
case SZ_ENORMOUS:
@ -458,6 +472,19 @@ char *numtotext(int num, char *buf) {
return buf;
}
// returns posiiton AFTER end of copied text, or NULL on failure.
char *readuntil(char *retbuf, char *src, char delim) {
char *bp,*p;
bp = retbuf;
for (p=src; *p && (*p != delim); p++) {
*bp = *p;
bp++;
}
p++; // go past delimiter
*bp = '\0'; // nul-terminate buffer
return p;
}
// convert number to roman numerals
// only copes with 1-10
char *roman(int num) {
@ -546,6 +573,21 @@ char *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv) {
return *out;
}
int streq(char *a, char *b) {
if (!a || !b) return B_FALSE;
return !strcmp(a,b);
}
char *strstarts(char *a, char *prefix) {
if (!a || !prefix) return NULL;
if (strstr(a, prefix) == a) {
return a;
}
return NULL;
}
int strpixmatch(char *haystack, char *needle) {
int matched = B_FALSE;
char *hword, *nword, *hcont,*ncont;

4
text.h
View File

@ -10,6 +10,7 @@ char *getattrname(enum ATTRIB att);
int gethitconferlifetime(char *text, int *min, int *max);
char *getpossessive(char *text);
char *getdrunktext(flag_t *drunkflag);
char *getrarityname(enum RARITY rr);
char *getsizetext(enum LFSIZE sz);
char *gettimetext(char *retbuf);
char *gettimetextfuzzy(char *retbuf, int wantpm);
@ -21,11 +22,14 @@ char *makeuppercase(char *text);
int needses(char *text);
char *noprefix(char *obname);
char *numtotext(int num, char *buf);
char *readuntil(char *retbuf, char *src, char delim);
char *roman(int num);
int speedtokph(int speed);
void splittime(int *hours, int *mins, int *secs);
char *strrep(char *text, char *oldtok, char *newtok, int *rv);
char *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv);
int streq(char *a, char *b);
char *strstarts(char *a, char *prefix);
int strpixmatch(char *haystack, char *needle);
int texttodice(char *text, int *ndice, int *nsides, int *bonus);
void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range);