- [+] askchar - default isnt working.

* [+] implement regions
- [+] new vaultflag:  norandom (doesn't rnadomly appear)
* [+] jimbo's lair
* [+] implememnt skill training
* [+] still a bug with flooded rooms having no doors!
* [+] change f_impassable to be a size _range_ which can't pass it.
- [+] metal armour should add to walking volume!
- [+] sewing/metalwork skill to repair cloth/metal armour, instead of
      "armour" skill?
- [+] moveob() onto a pit - they fall through!
vault options:
- [+] dlevmin/max:xx appears at this depth/difficulty
- [+] goesin appears in habitat xx (if none of these, can be anywhere)
    - [+] habitat has to be a struct first, with a name.
- [+] norandom (don't randomly generate - only from outline)
- [+] pits
    - [+] only one can exist in a cell
- [+] replace getemptycelltype() with entries in habitat_t
- [+] make map->habitat a link.
* [+] update linkstairs to do pits
SPELLS:
- [+] shatter (grav/air, break glass, break potions. damage to anyone
      nearby)
This commit is contained in:
Rob Pearce 2011-06-22 06:01:48 +00:00
parent 1ab3bd3620
commit 6cd743b9f9
31 changed files with 1710 additions and 494 deletions

4
ai.c
View File

@ -35,7 +35,9 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
// mindless?
if (getiqname(getattr(lf, A_IQ), NULL) == IQ_MINDLESS) {
return;
if (!isundead(lf)) {
return;
}
}
// already targetting this lf?

View File

@ -742,6 +742,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// victim's armour loses hp
if (reduceamt) {
applyarmourdamage(victim, wep, reduceamt, damtype[i]);
// train armour
practice(victim, SK_ARMOUR, 1);
}
if (backstab) {
practice(lf, SK_BACKSTAB, 1);
}
}
} // end foreach damtype
@ -903,8 +908,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
// practice?
if (wepsk && !getskill(lf, wepsk->id)) {
practice(lf, wepsk->id, hit ? 2 : 1);
if (hit) {
if (wepsk) {
practice(lf, wepsk->id, 1);
}
if (isdualweilding(lf)) {
practice(lf, SK_TWOWEAPON, 1);
}
}
// induction of fear?

103
defs.h
View File

@ -6,7 +6,7 @@
// MACROS
#define MAXOF(a,b) (a > b ? a : b)
#define PRACTICETIME 15 // #attempts it takes to learn new weapon skill
// #define PRACTICETIME 15 // #attempts it takes to learn new weapon skill
#define WETTIME 10 // how long it takes for things to dry
#define DRUNKTIME 10 // how long it takes for alcohol to wear off
@ -47,7 +47,9 @@ enum SKILL {
SK_FIRSTAID,
SK_LISTEN,
SK_LOCKPICKING,
SK_METALWORK,
SK_RANGED,
SK_SEWING,
SK_SHIELDS,
SK_SPELLCASTING,
SK_SPOTHIDDEN,
@ -88,7 +90,7 @@ enum SKILL {
SK_SS_TRANSLOCATION,
SK_SS_WILD,
};
#define MAXSKILLS 47
#define MAXSKILLS 49
// proficiency levels
enum SKILLLEVEL {
@ -572,12 +574,6 @@ enum BLESSTYPE {
B_CURSED = -1
};
enum HABITAT {
H_DUNGEON = 1,
H_FOREST = 2,
H_ALL = 999
};
#define RARITYVARIANCELF (5)
#define RARITYVARIANCEOB (10)
@ -780,11 +776,14 @@ enum OBTYPE {
OT_STATUE,
OT_DOORWOOD,
OT_DOORIRON,
OT_IRONGATE,
OT_WOODENTABLE,
OT_WOODENBARREL,
OT_WOODENSTOOL,
OT_HOLYCIRCLE,
OT_PENTAGRAM,
OT_HOLEINGROUND,
OT_HOLEINROOF,
OT_STAIRSDOWN,
OT_STAIRSUP,
OT_VENDINGMACHINE,
@ -896,6 +895,7 @@ enum OBTYPE {
OT_S_METALHEAL,
// -- death
OT_S_ANIMATEDEAD,
OT_S_COMMANDUNDEAD,
OT_S_DRAINLIFE,
OT_S_FEAR,
OT_S_PAIN,
@ -925,6 +925,7 @@ enum OBTYPE {
OT_S_CLOUDKILL,
OT_S_GUSTOFWIND,
OT_S_MIST,
OT_S_SHATTER,
OT_S_WINDSHIELD,
// -- elemental - fire
OT_S_BLADEBURN,
@ -1370,7 +1371,8 @@ enum NOISETYPE {
};
enum LFSIZE {
SZ_ANY = -1,
SZ_ANY = -2,
SZ_MIN = -1,
SZ_MINI = 0, // ie. fly
SZ_TINY = 1, // ie. mouse
SZ_SMALL = 2, // ie. cat
@ -1415,6 +1417,7 @@ enum FLAG {
F_ONEPERCELL, // only one of these objects can exist per cell
F_CREATEDBY, // object was made by lf id v0, text=real lfname
F_ENCHANTABLE, // object can get +1/-1 ect
F_NOSHATTER, // object will not shatter, even if it's material should.
F_STACKABLE, // can stack multiple objects togethr
F_NO_PLURAL, // this obname doesn't need an 's' for plurals (eg. gold, money)
F_NO_A, // this obname doesn't need to start with 'a' for singular (eg. gold)
@ -1447,7 +1450,8 @@ enum FLAG {
F_NOGLYPH, // this object doesn't appear normally
F_COSMETIC, // this object is mostly cosmetic, don't say 'you see xx'
F_NOPICKUP, // cannot pick this up
F_IMPASSABLE, // cannot walk past this if your size if v0 or smaller
F_IMPASSABLE, // cannot walk past this if your size is between v0 and v1
// (inclusive)
F_CRUSHABLE, // if you are bigger than size v0, walking on this crushes it
F_CAUSESCOUGH, // being in this ob's cell will make you cough unless
// immune to gas.
@ -1537,6 +1541,7 @@ enum FLAG {
// v2 = sc_dodge difficulty
// doors
F_DOOR, // this object is a door - ie. can open it
// v0 and v1 are like F_IMPASSABLE
F_OPEN, // is this door open?
F_LOCKED,// door is locked
// v1 is difficulty to disarm
@ -1547,6 +1552,9 @@ enum FLAG {
// stairs / teleporters / portals
F_CLIMBABLE, // this is a stiarcase, v0 = up/down/in
// also use this for portals
// OPTIONAL v1 = id of region to link to.
F_PIT, // this is a pit which we can fall down.
// v0 = up/down
//F_STAIRDIR//, // val0 = direcion
F_OPPOSITESTAIRS, // val0 = opposite kind of stairs
F_MAPLINK, // val0 = map to link to.
@ -2022,11 +2030,17 @@ enum FLAG {
// v0 is pct chance of door (as opposed to empty
// doorway with no door).
F_AUTOPOPULATE, // fill this vault with obs/mons/pillars like normal rooms
F_NORANDOM, // this vault does not randomly appear
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_VAULTDLEVMIN, // v0 = mininum map depth/difficulty for this vault
F_VAULTDLEVMAX, // v0 = maximum map depth/difficulty for this vault
F_VAULTEXIT, // v0/1=x,y for exit.
F_VAULTGOESIN, // this vault randomly appears in habitat type v0.
// can be repeated multiple times
// if a vault doesnt have this flag, it can go anywhere
F_VAULTSCATTER, // v0=thingtype, v1=pctchance
// text=x1,y1,x2,y2,mincount-maxcount,thingname
// if maxcount is PCT, mincount is a percentage
@ -2067,6 +2081,8 @@ enum HUNGER {
#define B_FALSE (0)
#define B_TRUE (-1)
#define B_NODOORS (0)
#define B_DONTKILL (-1)
#define FALLTHRU (-8765)
@ -2248,16 +2264,74 @@ typedef struct command_s {
struct command_s *next, *prev;
} command_t;
#define RG_WORLDMAP 0
#define RG_FIRSTDUNGEON 1
enum REGIONTYPE {
RG_WORLDMAP,
RG_FIRSTDUNGEON,
RG_PIT,
};
enum HABITAT {
H_DUNGEON = 1,
H_FOREST = 2,
H_PIT = 3,
H_ALL = 999
};
typedef struct regiontype_s {
enum REGIONTYPE id;
enum HABITAT defaulthabitat;
int maxdepth;
int stairsperlev;
int deeperdir;
struct regiontype_s *next, *prev;
} regiontype_t;
enum REGIONTHING {
RT_HABITAT, // val is habitat
RT_REGIONLINK, // val is enum regiontype to link to.
// what is stair object type
RT_VAULT, // what is vaultname
};
typedef struct regionthing_s {
int depth; // only need depth OR x,y
int x,y;
enum REGIONTHING whatkind;
int value;
char *what;
} regionthing_t;
#define MAXOUTLINETHINGS 20
typedef struct regionoutline_s {
regiontype_t *rtype;
regionthing_t thing[MAXOUTLINETHINGS];
int nthings;
struct regionoutline_s *next, *prev;
} regionoutline_t;
typedef struct region_s {
int id;
regiontype_t *rtype;
regionoutline_t *outline;
struct region_s *parentregion;
int nthings;
struct region_s *next, *prev;
} region_t;
typedef struct habitat_s {
enum HABITAT id;
char *name;
enum CELLTYPE emptycelltype,solidcelltype;
struct habitat_s *next, *prev;
} habitat_t;
typedef struct map_s {
int id;
int region;
region_t *region;
int depth;
int nrooms; // how many rooms on this map
char *name; // name of this map
enum HABITAT habitat; // eg. dungeon, forest, etc
habitat_t *habitat;
unsigned int seed;
int w,h; // width/height of this map
struct cell_s *cell[MAX_MAPW*MAX_MAPH]; // list of cells in this map
@ -2476,6 +2550,7 @@ typedef struct skill_s {
enum SKILL id;
char *name;
char *desc;
int traintime;
struct skill_s *next, *prev;
} skill_t;

View File

@ -2,4 +2,7 @@ defs.h:
add H_xx enum
map.c:
update getemptycelltype()
initmap: define via addhabitat()
make a new function to create this kind of habitat

10
doc/add_regiontype.txt Normal file
View File

@ -0,0 +1,10 @@
defs.h:
add new RG_xxx entry to enum REGIONTYPE
map.c:
initmap(): define via new "addregiontype()" call
OPTIONAL: initmap(): define at least one regionoutline
create new habitats if required.
update getregionname()

View File

@ -44,12 +44,24 @@ Flags can be:
- 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
autodoors:pct // automatically add at least one door to the edges of
// this room.
// pct is chance of the exit being a door as opposed
// to jsut an opening.
autopop // automatically add obs/mons/pillars to this room
dlevmin:xxx // can only randomly appear at or below dungeon
// level xxx (or map difficulty xxx for world map)
dlevmax:xxx // can only randomly appear at or before dungeon
// levle xxx
goesin:xxx // can only randomly appear in habitat xxx
norandom // this vault doesn't appear randomly. it will only
// appear when specifically requested via a region's
// outline.
NOTES:
when adding lfs/objects, "random" creates a random one.

48
io.c
View File

@ -501,7 +501,7 @@ char askchar(char *prompt, char *validchars, char *def, int showchars) {
}
curs_set(0);
clearmsg();
if ((ch == 13) && def) {
if ((ch == 10) && def) {
return def[0];
}
return ch;
@ -986,7 +986,7 @@ void announcearrival(lifeform_t *lf, map_t *newmap) {
} else {
msg("You arrive at the surface.");
}
} else if (newmap->habitat == H_DUNGEON) {
} else if (newmap->habitat->id == H_DUNGEON) {
msg("You arrive at dungeon level %d.", newmap->depth);
}
}
@ -3616,8 +3616,7 @@ void doclose(void) {
}
}
void docomms(void) {
lifeform_t *lf = NULL;
void docomms(lifeform_t *lf) {
cell_t *where;
char buf[BUFLEN];
char lfname[BUFLEN];
@ -3626,9 +3625,11 @@ void docomms(void) {
flag_t *f;
where = askcoords("Talk to who?", "Talk->", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf && cansee(player, where->lf)) {
lf = where->lf;
if (!lf) {
where = askcoords("Talk to who?", "Talk->", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf && cansee(player, where->lf)) {
lf = where->lf;
}
}
if (!lf) {
msg("Cancelled.");
@ -3644,7 +3645,7 @@ void docomms(void) {
// are they friendly?
if (ispetof(lf, player)) {
if (iqb >= IQ_ANIMAL) {
if ((iqb >= IQ_ANIMAL) || isundead(lf)) {
addchoice(&prompt, 'a', "Attack something", NULL, NULL);
}
@ -3694,6 +3695,8 @@ void docomms(void) {
if (isplayer(lf)) {
msg("%s looks confused at your command.", lfname);
} else {
// stop attacking all current targets first...
killflagsofid(lf->flags, F_TARGETLF);
aiattack(lf, lf2, AI_FOLLOWTIME);
}
break;
@ -3709,11 +3712,13 @@ void docomms(void) {
sprintf(buf, "Tell %s to go where?",lfname);
sprintf(buf2, "%s->Goto->",lfname);
c = askcoords(buf, buf2, TT_NONE, lf, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && cellwalkable(lf, c, NULL) && cansee(lf, c->lf)) {
if (c && cellwalkable(lf, c, NULL) ) {
} else {
msg("Cancelled.");
return;
}
// stop attacking all current targets first...
killflagsofid(lf->flags, F_TARGETLF);
msg("You say \"Go over there!\" to %s.", lfname);
aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME);
break;
@ -4627,7 +4632,7 @@ void doenter(lifeform_t *lf) {
}
enterob = hasob(lf->cell->obpile, OT_PORTAL);
if (enterob) {
usestairs(lf, enterob);
usestairs(lf, enterob, B_TRUE);
return;
}
@ -5014,7 +5019,7 @@ void dostairs(int dir) {
object_t *o;
o = hasobwithflagval(player->cell->obpile, F_CLIMBABLE, dir, NA, NA, NULL);
if (o) {
usestairs(player, o);
usestairs(player, o, B_TRUE);
} else {
msg("There are no stairs going %s here!", getdirname(dir));
}
@ -6107,7 +6112,7 @@ void handleinput(void) {
doclose();
break;
case 'C': // communicate
docomms();
docomms(NULL);
break;
case 'e': // eat
doeat(player->pack);
@ -6653,7 +6658,12 @@ void drawstatus(void) {
}
}
wprintw(statwin, "DLev:%d", player->cell->map->depth);
//wprintw(statwin, "DLev:%d", player->cell->map->depth);
setcol(statwin, C_BROWN);
getregionname(buf, player->cell->map, B_TRUE);
capitalise(buf);
wprintw(statwin, "%s", buf);
unsetcol(statwin, C_BROWN);
}
void drawmsg(void) {
@ -8245,7 +8255,7 @@ void showlfstats(lifeform_t *lf, int showall) {
}
f = lfhasflag(lf, F_RAGE);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s enraged.", you(lf), is(lf));
mvwprintw(mainwin, y, 0, "%s %s enraged, gaining temporary strength and hit points.", you(lf), is(lf));
y++;
}
f = lfhasknownflag(lf, F_REGENERATES);
@ -8419,6 +8429,7 @@ void showlfstats(lifeform_t *lf, int showall) {
void tombstone(lifeform_t *lf) {
char pname[BUFLEN];
char buf[BUFLEN];
int y;
char *p, *dummy;
@ -8431,10 +8442,13 @@ void tombstone(lifeform_t *lf) {
centre(mainwin, y, "R.I.P."); y++;
//printf("%s\n",lf->name);
centre(mainwin, y, "%s (%ld points)",pname, calcscore(lf)); y++;
if (lf->cell->map->region == RG_WORLDMAP) {
centre(mainwin, y, "Died in the forest.");
if (player->cell->map->region->rtype->id == RG_WORLDMAP) {
getregionname(buf, player->cell->map, B_TRUE);
centre(mainwin, y, "Died on %s.", buf); y++;
} else {
centre(mainwin, y, "Died on level %d of the dungeon.", lf->cell->map->depth); y++;
getregionname(buf, player->cell->map, B_FALSE);
centre(mainwin, y, "Died on level %d of %s.", player->cell->map->depth, buf); y++;
}
p = strtok_r(lf->lastdam,"^", &dummy);

2
io.h
View File

@ -37,7 +37,7 @@ void describeob(object_t *o);
void describespell(objecttype_t *ot);
void doattackcell(char dirch);
void doclose(void);
void docomms(void);
void docomms(lifeform_t *target);
void dodrop(obpile_t *op, int wantmulti, obpile_t *dst);
void doeat(obpile_t *op);
void doenter(lifeform_t *lf);

528
lf.c
View File

@ -1161,6 +1161,11 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
// stop hiding
killflagsofid(lf->flags, F_HIDING);
// successful cast?
if (!rv) {
practice(lf, SK_SPELLCASTING, 1);
}
return rv;
}
@ -1815,6 +1820,159 @@ void dumpxp(void) {
}
}
int digcell(lifeform_t *lf, cell_t *c, object_t *o) {
char obname[BUFLEN];
getobname(o, obname, 1);
if (!c) {
return B_TRUE;
}
if (c->type->solid) {
if (isdiggable(c)) {
// replace wall
setcelltype(c, c->map->habitat->id);
if (isplayer(lf)) {
msg("You dig through the wall.");
needredraw = B_TRUE;
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s digs through a wall.",lfname);
needredraw = B_TRUE;
}
//drawscreen();
// takes extra time
taketime(lf, getactspeed(lf)*9);
} else {
// fail
if (isplayer(lf)) {
msg("This wall is too hard to dig.");
}
}
} else { // not solid
int failed = B_FALSE;
object_t *door;
door = hasobwithflag(c->obpile, F_DOOR);
if (door) {
int dooropen;
// only closed doors!
isdoor(door, &dooropen);
if (dooropen) {
door = NULL;
}
}
if (door) {
// TODO: metal doors are immune to CHOP damage
if (!isimmuneto(door->flags, DT_CHOP)) {
taketime(lf, getactspeed(lf));
removeob(door, door->amt);
if (isplayer(lf)) {
msg("You smash open a door!");
needredraw = B_TRUE;
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s smashes open a door.",lfname);
needredraw = B_TRUE;
}
drawscreen();
failed = B_FALSE;
}
} else if (hasob(c->obpile, OT_STATUE)) {
int dam;
object_t *so;
char statname[BUFLEN];
flag_t *f;
so = hasob(c->obpile, OT_STATUE);
getobname(so, statname, so->amt);
taketime(lf, getactspeed(lf));
// statue takes 1/2 damage
f = hasflag(so->flags, F_OBHP);
if (f) {
dam = (f->val[1] / 2); // ie. half max hp
} else {
dam = 1;
}
// statue ?
if (isplayer(lf)) {
msg("You hit %s with your %s.", statname, noprefix(obname));
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s hits %s with %s.", lfname, statname, obname);
}
takedamage(so, dam, DT_CHOP);
} else {
if (isplayer(lf)) {
msg("You swing your %s through the air.",noprefix(obname));
}
taketime(lf, getactspeed(lf));
}
}
return B_FALSE;
}
int digdown(lifeform_t *lf, object_t *o) {
char lfname[BUFLEN];
getlfname(lf, lfname);
// TODO: check if the floor is solid?
if (isplayer(lf)) {
msg("You dig a hole in the floor.");
} else if (cansee(player, lf)) {
msg("%s digs a hole in the floor.");
}
addob(lf->cell->obpile, "hole in the ground");
// takes a lot of time
taketime(lf, getactspeed(lf) * 9);
return B_FALSE;
}
int digup(lifeform_t *lf, object_t *o) {
char lfname[BUFLEN];
getlfname(lf, lfname);
// no roof?
if (lf->cell->map->region->rtype->id == RG_WORLDMAP) {
if (isplayer(lf)) {
msg("There is no roof above you to dig into!");
}
return B_TRUE;
}
// TODO: check if the roof is solid?
if (!isairborne(lf)) {
if (isplayer(lf)) {
msg("You can't reach the roof!");
}
return B_TRUE;
}
if (isplayer(lf)) {
msg("You dig a hole in the roof.");
} else if (cansee(player, lf)) {
msg("%s digs a hole in the roof.");
}
// add some stones here
addob(lf->cell->obpile, "20-50 stones");
addob(lf->cell->obpile, "hole in the roof");
// takes a LOT of time since gravity is against us
taketime(lf, getactspeed(lf) * 18);
return B_FALSE;
}
// dump which level random things will appear at
void dumplev(void) {
int i;
@ -2728,7 +2886,7 @@ int flee(lifeform_t *lf) {
// can we flee via stairs?
stairs = hasobwithflag(lf->cell->obpile, F_CLIMBABLE);
if (stairs) {
if (!usestairs(lf, stairs)) {
if (!usestairs(lf, stairs, B_TRUE)) {
return B_TRUE;
}
}
@ -3082,6 +3240,24 @@ object_t *getarmour(lifeform_t *lf, enum BODYPART bp) {
return NULL;
}
int getarmournoise(lifeform_t *lf) {
object_t *o;
int volmod = 0;
for (o = lf->pack->first ; o ; o = o->next) {
if (isarmour(o) && isequipped(o)) {
// heavy metal armour makes noise
if (ismetal(o->material->id) && (getobweight(o) >= 4)) {
volmod++;
}
}
}
volmod -= getskill(lf, SK_ARMOUR);
limit(&volmod, 0, NA);
return volmod;
}
int getarmourrating(lifeform_t *lf) {
object_t *o;
flag_t *f;
@ -3288,25 +3464,28 @@ int getavgdam(lifeform_t *lf, int forxp) {
o = addob(op2, f->text);
getdamrange(hasflag(o->flags, F_DAM), &min,&max);
thisavg = ((float)min + (float)max) / 2.0;
if (o) {
getdamrange(hasflag(o->flags, F_DAM), &min,&max);
thisavg = ((float)min + (float)max) / 2.0;
// confers anything?
for (of = o->flags->first ; of ; of = of->next) {
if (of->id == F_HITCONFER) {
thisavg += 10;
// confers anything?
for (of = o->flags->first ; of ; of = of->next) {
if (of->id == F_HITCONFER) {
thisavg += 10;
}
}
}
// modify for accuracy
acc = getlfaccuracy(lf, o);
thisavg = pctof(acc, thisavg);
// modify for accuracy
acc = getlfaccuracy(lf, o);
thisavg = pctof(acc, thisavg);
avgdam += thisavg;
if (db) {
char obname[BUFLEN];
getobname(o,obname,1);
if (db) dblog("getavgdam: %s: == %d-%d dam, avg is %0.1f",obname, min, max, thisavg);
avgdam += thisavg;
if (db) {
char obname[BUFLEN];
getobname(o,obname,1);
if (db) dblog("getavgdam: %s: == %d-%d dam, avg is %0.1f",obname, min, max, thisavg);
}
}
killobpile(op2);
@ -4345,6 +4524,30 @@ lifeform_t *getnearbypeaceful(lifeform_t *lf) {
return NULL;
}
char *getpitverb(lifeform_t *lf, int dir, int onpurpose) {
if (lfhasflag(lf, F_FLYING)) {
if (isplayer(lf)) return "fly";
else return "flies";
} else if (onpurpose) { // TODO: check if we are using a rope
if (dir == D_DOWN) {
if (isplayer(lf)) return "jump";
else return "jumps";
} else {
if (isplayer(lf)) return "climb";
else return "climbs";
}
} else {
if (dir == D_DOWN) {
if (isplayer(lf)) return "fall";
else return "falls";
} else {
if (isplayer(lf)) return "rise";
else return "rises";
}
}
return "?unkonwnmoveverb?";
}
char *getlfname(lifeform_t *lf, char *buf) {
return real_getlfname(lf, buf, B_TRUE);
}
@ -4622,7 +4825,7 @@ int getracerarity(map_t *map, enum RACE rid) {
f = hasflagval(r->flags, F_RARITY, H_ALL, NA, NA, NULL);
if (!f) {
if (map) {
f = hasflagval(r->flags, F_RARITY, map->habitat, NA, NA, NULL);
f = hasflagval(r->flags, F_RARITY, map->habitat->id, NA, NA, NULL);
} else {
f = hasflagval(r->flags, F_RARITY, NA, NA, NA, NULL);
}
@ -4744,7 +4947,7 @@ race_t *getrandomrace(cell_t *c, int forcedepth) {
rarflag = hasflagval(r->flags, F_RARITY, H_ALL, NA, NA, NULL);
if (!rarflag) {
if (c) {
rarflag = hasflagval(r->flags, F_RARITY, c->map->habitat, NA, NA, NULL);
rarflag = hasflagval(r->flags, F_RARITY, c->map->habitat->id, NA, NA, NULL);
} else {
rarflag = hasflagval(r->flags, F_RARITY, NA, NA, NA, NULL);
}
@ -5464,6 +5667,18 @@ int giveskill(lifeform_t *lf, enum SKILL id) {
} else if (id == SK_LORE_ARCANA) {
newf = addflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL);
newf->lifetime = FROMJOB;
} else if (id == SK_METALWORK) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
newf->lifetime = FROMJOB;
}
} else if (id == SK_SEWING) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
newf->lifetime = FROMJOB;
}
} else if (id == SK_THIEVERY) {
newf = addflag(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL);
newf->lifetime = FROMJOB;
@ -5482,11 +5697,6 @@ int giveskill(lifeform_t *lf, enum SKILL id) {
newf = addflag(lf->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL);
newf->lifetime = FROMJOB;
}
} else if (id == SK_ARMOUR) {
if (f->val[1] == PR_SKILLED) {
newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
newf->lifetime = FROMJOB;
}
} else if (id == SK_CARTOGRAPHY) {
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
if (f->val[1] == PR_NOVICE) {
@ -6109,6 +6319,8 @@ int lockpick(lifeform_t *lf, object_t *target, object_t *device) {
gainxp(lf, difficulty/3);
}
}
// training
practice(lf, SK_LOCKPICKING, 1);
} else {
// failed!
if (faileffect == B_DIEONFAIL) {
@ -6553,6 +6765,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LONGBLADES, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL);
@ -6591,6 +6804,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_METALWORK, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL);
@ -6636,6 +6850,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_METALWORK, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SPELLCASTING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SS_FIRE, NA, NA, NULL);
@ -6659,7 +6874,9 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_METALWORK, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LORE_ARCANA, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_TRACKING, NA, NA, NULL);
@ -6698,6 +6915,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LORE_ARCANA, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_THIEVERY, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_TRACKING, NA, NA, NULL);
@ -8243,6 +8461,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars");
addrace(R_DOGBLINK, "blink dog", 35, 'd', C_YELLOW, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NUMAPPEAR, 2, 8, NA, "");
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
@ -8250,7 +8469,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 77, NA, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, 77, NA, "");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 4, 0, NA, "");
addflag(lastrace->flags, F_HITDICE, 2, 3, NA, "");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6");
addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
@ -9710,7 +9929,7 @@ raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum
return a;
}
skill_t *addskill(enum SKILL id, char *name, char *desc) {
skill_t *addskill(enum SKILL id, char *name, char *desc, int traintime) {
skill_t *a;
assert(!findskill(id));
@ -9735,6 +9954,7 @@ skill_t *addskill(enum SKILL id, char *name, char *desc) {
a->id = id;
a->name = strdup(name);
a->desc = strdup(desc);
a->traintime = traintime;
return a;
}
@ -10606,6 +10826,9 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) {
}
sprintf(noisetext, "%s.",noun);
if (nid == N_WALK) {
volume += getarmournoise(lf);
}
noise(lf->cell, lf, volume, noisetext, verb);
} else {
// some defaults
@ -10647,6 +10870,7 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) {
default:
break;
}
volume += getarmournoise(lf);
if (strlen(movetext)) {
noise(lf->cell, lf, volume, movetext, NULL);
}
@ -11011,6 +11235,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete
}
// only hear one thing per turn.
addflag(l->flags, F_DONELISTEN, B_TRUE, NA, NA, NULL);
practice(l, SK_LISTEN, 1);
}
}
// wake up a little
@ -11279,24 +11504,39 @@ int poisonthreatenslife(lifeform_t *lf, flag_t *f) {
return B_FALSE;
}
// maybe practice a skill
void practice(lifeform_t *lf, enum SKILL skid, int amt) {
flag_t *f;
skill_t *sk;
enum SKILLLEVEL slev;
int timeneeded;
// already got the skill?
if (getskill(lf, skid)) {
return;
}
// practice a little bit...
f = lfhasflagval(lf, F_PRACTICINGSKILL, skid, NA, NA, NULL);
if (f) {
f->val[1] += amt;
if (f->val[1] >= PRACTICETIME) {
// learnt it!
sk = findskill(skid);
if (!sk) return;
slev = getskill(lf, skid);
timeneeded = sk->traintime * (getskill(lf, skid)+1);
if (!timeneeded) return;
// can only practice skills which you're capable of learning
if (!canlearn(lf, skid)) return;
if (!slev || onein(slev)) {
// practice a little bit...
f = lfhasflagval(lf, F_PRACTICINGSKILL, skid, NA, NA, NULL);
if (f) {
f->val[1] += amt;
} else {
f = addflag(lf->flags, F_PRACTICINGSKILL, skid, amt, NA, NULL);
}
if (f->val[1] >= timeneeded) {
// learnt the next rank
giveskill(lf, skid);
killflag(f);
}
} else {
addflag(lf->flags, F_PRACTICINGSKILL, skid, amt, NA, NULL);
}
}
@ -12098,55 +12338,57 @@ void setlastdam(lifeform_t *lf, char *buf) {
}
void initskills(void) {
addskill(SK_ARMOUR, "Armour", "Lets you repair armour, and reduces evasion penalties from armour.");
addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery.");
addskill(SK_BACKSTAB, "Backstab", "Lets you inflict massive damage with stabs when unseen.");
addskill(SK_CARTOGRAPHY, "Cartography", "Your ability to create and interpret maps.");
addskill(SK_COOKING, "Cooking", "Your ability to combine foods into nutritious meals.");
addskill(SK_FIRSTAID, "First Aid", "Increases your healing rate and reduces duration of poison.");
addskill(SK_LISTEN, "Listen", "How good you are at hearing and interpreting sounds.");
addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.");
addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items.");
addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun.");
addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block projectiles.");
addskill(SK_SPELLCASTING, "Sorcery", "Determines your ability to cast spells from all schools.");
addskill(SK_SPOTHIDDEN, "Searching", "Helps you to spot hidden traps or creatures.");
addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.");
addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water.");
addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items.");
addskill(SK_THIEVERY, "Thievery", "Your ability to pick pockets and steal items.");
addskill(SK_TRACKING, "Tracking", "Allows you to track enemies by their footprints.");
addskill(SK_TRAPS, "Traps", "Affects your ability to locate and disarm traps.");
addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once.");
addskill(SK_ARMOUR, "Armour", "Reduces evasion and stealth penalties from wearing armour.", 100);
addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery.", 50);
addskill(SK_BACKSTAB, "Backstab", "Lets you inflict massive damage with stabs when unseen.", 50);
addskill(SK_CARTOGRAPHY, "Cartography", "Your ability to create and interpret maps.", 0); // untrainable
addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items.", 0); // untrainable
addskill(SK_COOKING, "Cooking", "Your ability to combine foods into nutritious meals.", 50);
addskill(SK_FIRSTAID, "First Aid", "Increases your healing rate and reduces duration of poison.", 0); // untrainable
addskill(SK_LISTEN, "Listen", "How good you are at hearing and interpreting sounds.", 100);
addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.", 50);
addskill(SK_METALWORK, "Metalwork", "Lets you repair metal objects.", 100);
addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun.", 50);
addskill(SK_SEWING, "Sewing", "Lets you repair cloth or leather objects.", 100);
addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block projectiles.", 50);
addskill(SK_SPELLCASTING, "Sorcery", "Determines your ability to cast spells from all schools.", 50);
addskill(SK_SPOTHIDDEN, "Searching", "Helps you to spot hidden traps or creatures.", 50);
addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable?
addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water.", 50);
addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items.", 0); // untrain
addskill(SK_THIEVERY, "Thievery", "Your ability to pick pockets and steal items.", 50);
addskill(SK_TRACKING, "Tracking", "Allows you to track enemies by their footprints.", 0); // untrain
addskill(SK_TRAPS, "Traps", "Affects your ability to locate and disarm traps.", 25);
addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once.", 50);
// knowledge
addskill(SK_LORE_ARCANA, "Lore:Arcana", "Allows you a chance of recognising magical objects and creatures.");
addskill(SK_LORE_DEMONS, "Lore:Demonology", "Determines your knowledge about demons.");
addskill(SK_LORE_HUMANOID, "Lore:Humanoid", "Determines your knowledge about humanoid (bipedal) creatures.");
addskill(SK_LORE_NATURE, "Lore:Nature", "Determines your knowledge of plants, animals and insects.");
addskill(SK_LORE_UNDEAD, "Lore:Undead", "Determines your knowledge of the undead.");
addskill(SK_LORE_ARCANA, "Lore:Arcana", "Allows you a chance of recognising magical objects and creatures.", 0);
addskill(SK_LORE_DEMONS, "Lore:Demonology", "Determines your knowledge about demons.", 0);
addskill(SK_LORE_HUMANOID, "Lore:Humanoid", "Determines your knowledge about humanoid (bipedal) creatures.", 0);
addskill(SK_LORE_NATURE, "Lore:Nature", "Determines your knowledge of plants, animals and insects.", 0);
addskill(SK_LORE_UNDEAD, "Lore:Undead", "Determines your knowledge of the undead.", 0);
// weaponry
addskill(SK_AXES, "Axes", "Helps you use chopping weapons like axes.");
addskill(SK_CLUBS, "Clubs", "Helps you use bashing weapons like maces or clubs.");
addskill(SK_LONGBLADES, "Long Blades", "Helps you use long swords, scimitars, etc.");
addskill(SK_POLEARMS, "Polearms", "Helps you use long bladed weapons like halberds.");
addskill(SK_SHORTBLADES, "Short Blades", "Helps you use daggers, short swords, etc.");
addskill(SK_STAVES, "Staves", "Helps you use quarterstaffs, staffs, etc.");
addskill(SK_UNARMED, "Unarmed Combat", "Helps you fight using your bare hands.");
addskill(SK_AXES, "Axes", "Helps you use chopping weapons like axes.", 50);
addskill(SK_CLUBS, "Clubs", "Helps you use bashing weapons like maces or clubs.", 50);
addskill(SK_LONGBLADES, "Long Blades", "Helps you use long swords, scimitars, etc.", 50);
addskill(SK_POLEARMS, "Polearms", "Helps you use long bladed weapons like halberds.", 50);
addskill(SK_SHORTBLADES, "Short Blades", "Helps you use daggers, short swords, etc.", 50);
addskill(SK_STAVES, "Staves", "Helps you use quarterstaffs, staffs, etc.", 50);
addskill(SK_UNARMED, "Unarmed Combat", "Helps you fight using your bare hands.", 50);
// spell schools
addskill(SK_SS_ALLOMANCY, "Allomancy", "Boosts casting of spells from this school.");
addskill(SK_SS_AIR, "Air Magic", "Boosts casting of spells from this school.");
addskill(SK_SS_DEATH, "Necromancy", "Boosts casting of spells from this school.");
addskill(SK_SS_DIVINATION, "Divination", "Boosts casting of spells from this school.");
addskill(SK_SS_FIRE, "Fire Magic", "Boosts casting of spells from this school.");
addskill(SK_SS_COLD, "Cold Magic", "Boosts casting of spells from this school.");
addskill(SK_SS_GRAVITY, "Gravitation Magic", "Boosts casting of spells from this school.");
addskill(SK_SS_LIFE, "Life Magic", "Boosts casting of spells from this school.");
addskill(SK_SS_MODIFICATION, "Modification", "Boosts casting of spells from this school.");
addskill(SK_SS_MENTAL, "Psionics", "Boosts casting of spells from this school.");
addskill(SK_SS_NATURE, "Nature Magic", "Boosts casting of spells from this school.");
addskill(SK_SS_SUMMONING, "Summoning", "Boosts casting of spells from this school.");
addskill(SK_SS_TRANSLOCATION, "Translocation", "Boosts casting of spells from this school.");
addskill(SK_SS_WILD, "Wild Magic", "Boosts casting of spells from this school.");
addskill(SK_SS_ALLOMANCY, "Allomancy", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_AIR, "Air Magic", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_DEATH, "Necromancy", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_DIVINATION, "Divination", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_FIRE, "Fire Magic", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_COLD, "Cold Magic", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_GRAVITY, "Gravitation Magic", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_LIFE, "Life Magic", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_MODIFICATION, "Modification", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_MENTAL, "Psionics", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_NATURE, "Nature Magic", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_SUMMONING, "Summoning", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_TRANSLOCATION, "Translocation", "Boosts casting of spells from this school.", 50);
addskill(SK_SS_WILD, "Wild Magic", "Boosts casting of spells from this school.", 50);
}
void interrupt(lifeform_t *lf) {
@ -12882,6 +13124,20 @@ void timeeffectslf(lifeform_t *lf) {
timeeffectsob(o);
}
// holes in the floor/roof
o = hasobwithflagval(lf->cell->obpile, F_PIT, D_DOWN, NA, NA, NULL);
if (o) {
if (!isairborne(lf)) {
usestairs(lf, o, B_FALSE);
}
}
o = hasobwithflagval(lf->cell->obpile, F_PIT, D_UP, NA, NA, NULL);
if (o) {
if (lfhasflag(lf, F_LEVITATING)) {
usestairs(lf, o, B_FALSE);
}
}
}
//////////////////////////////////
@ -13132,6 +13388,7 @@ void turneffectslf(lifeform_t *lf) {
getlfname(lf, lfname);
msg("You think %s has spotted you!", lfname);
}
practice(lf, SK_SPOTHIDDEN, 1);
}
}
}
@ -13162,6 +13419,11 @@ void turneffectslf(lifeform_t *lf) {
killflag(f);
needredraw = B_TRUE;
drawscreen();
// train skills
practice(lf, SK_SPOTHIDDEN, 1);
if (hasflag(o->flags, F_TRAP)) {
practice(lf, SK_TRAPS, 1);
}
}
}
}
@ -13703,7 +13965,7 @@ int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where)
}
int usestairs(lifeform_t *lf, object_t *o) {
int usestairs(lifeform_t *lf, object_t *o, int onpurpose) {
flag_t *f;
map_t *curmap;
map_t *newmap;
@ -13715,6 +13977,8 @@ int usestairs(lifeform_t *lf, object_t *o) {
int isportal = B_FALSE;
lifeform_t *adjally[8];
int nadjallies = 0;
int falling = B_FALSE;
region_t *newregion = NULL;
// need up update 'dlev:'
if (isplayer(lf)) {
@ -13734,6 +13998,12 @@ int usestairs(lifeform_t *lf, object_t *o) {
f = hasflag(o->flags, F_CLIMBABLE);
assert(f);
dir = f->val[0];
if (f->val[1] == NA) {
// use same region
newregion = lf->cell->map->region;
} else {
newregion = findregion(f->val[1]);
}
// depth of new level?
if (dir == D_UP) {
@ -13747,6 +14017,10 @@ int usestairs(lifeform_t *lf, object_t *o) {
isportal = B_TRUE;
}
if (!onpurpose) {
falling = B_TRUE;
}
// check...
if (dir == D_DOWN) {
if (lfhasflag(lf, F_LEVITATING)) {
@ -13755,6 +14029,18 @@ int usestairs(lifeform_t *lf, object_t *o) {
}
return B_TRUE;
}
} else if (dir == D_UP) {
if (hasflagval(o->flags, F_PIT, D_UP, NA, NA, NULL)) {
// can only go up if you have a rope or are flying/levitating
if (lfhasflag(lf, F_LEVITATING) || lfhasflag(lf, F_FLYING)) {
// ok.
} else { // TODO: if has rope???
if (isplayer(lf)) {
msg("You can't reach the roof!");
}
return B_TRUE;
}
}
}
// announce
@ -13767,18 +14053,27 @@ int usestairs(lifeform_t *lf, object_t *o) {
} else if (cansee(player, lf)) {
msg("%s enters %s...", lfname, obname);
}
} else if (hasflag(o->flags, F_PIT)) {
f = hasflag(o->flags, F_PIT);
if (isplayer(lf) || cansee(player, lf)) {
msg("%s %s %s the %s...", lfname, getpitverb(lf, dir,onpurpose), getdirname(dir), noprefix(obname));
// move cursor to msgwindow while we create the new level...
if (isplayer(lf)) wrefresh(msgwin);
}
} else {
if (isplayer(lf)) {
msg("You %s %s the staircase...", getmoveverb(lf), getdirname(dir));
// move cursor to msgwindow while we create the new level...
wrefresh(msgwin);
} else if (cansee(player, lf)) {
msg("%s %s %s the staircase...", lfname, getmoveverbother(lf), getdirname(dir));
msg("%s %s %s the staircase.", lfname, getmoveverbother(lf), getdirname(dir));
}
}
// find adjacent allies or enemies which will follow you
if (isplayer(lf)) {
// (but not into/out of pits)
if (isplayer(lf) || !hasflag(o->flags, F_PIT)) {
getadjallies(lf, adjally, &nadjallies);
}
@ -13790,27 +14085,27 @@ int usestairs(lifeform_t *lf, object_t *o) {
if (isplayer(lf)) msg("This portal doesn't seem to go anywhere.");
} else {
// is there already a level of the correct depth?
newmap = findregionmap(lf->cell->map->region, newdepth);
newmap = findregionmap(newregion->id, newdepth);
if (newmap) {
dblog("ERROR - unlinked stairs!\n");
msg("ERROR - unlinked stairs!\n");
} else {
enum HABITAT newhabitat;
int newregion;
// generate a new map! this will fill in the destination of our stairs
newmap = addmap();
if (newdepth == 0) {
newregion = RG_WORLDMAP;
newhabitat = AUTO;
} else {
newregion = lf->cell->map->region;
newhabitat = AUTO;
// first map of a newly created region?
if (newregion->id != curmap->region->id) {
newdepth = 1;
}
createmap(newmap, newdepth, newregion, newhabitat, curmap, dir);
// link our stairs to the new map.
//linkstairs(o);
createmap(newmap, newdepth, newregion, curmap, dir);
// if we stayed within the same region, our stairs should
// now have a destination, since createmap() will automatically check
// previous/next levels in the same region.
// NOW our stairs should have a destination
// if not, we need to call linkstairs() on the staircase first.
if (newmap->region->id != curmap->region->id) {
linkstairs(o);
}
// at this point, stairs should have a destination
newcell = getstairdestination(o);
}
}
@ -13841,12 +14136,14 @@ int usestairs(lifeform_t *lf, object_t *o) {
if (f) f->known = B_KNOWN;
}
// move player to new map
moveto(lf, newcell, B_TRUE, B_TRUE);
moveto(lf, newcell, onpurpose, B_TRUE);
// take time
if ((dir == D_UP) && !isairborne(lf)) {
stopsprinting(lf); // you can sprint down stairs, but not up
taketime(lf, getmovespeed(lf)*2); // takes longer to climb
if (onpurpose) taketime(lf, getmovespeed(lf)*2); // takes longer to climb
} else {
taketime(lf, getmovespeed(lf));
if (onpurpose) taketime(lf, getmovespeed(lf));
}
// move adjacent allies/monsters too
@ -13858,9 +14155,9 @@ int usestairs(lifeform_t *lf, object_t *o) {
stopsprinting(adjally[n]);
movelf(adjally[n], c);
if ((dir == D_UP) && !isairborne(adjally[n])) {
taketime(adjally[n], getmovespeed(adjally[n])*2); // takes longer to climb
if (onpurpose) taketime(adjally[n], getmovespeed(adjally[n])*2); // takes longer to climb
} else {
taketime(adjally[n], getmovespeed(adjally[n]));
if (onpurpose) taketime(adjally[n], getmovespeed(adjally[n]));
}
}
}
@ -13871,6 +14168,29 @@ int usestairs(lifeform_t *lf, object_t *o) {
return B_TRUE;
}
if (falling) {
if (dir == D_DOWN) {
if (isplayer(lf)) {
msg("You slam into the ground!");
} else if (cansee(player, lf)){
msg("%s slams into the ground!", lfname);
}
// take fall damage
losehp(lf, roll("2d6"), DT_FALL, NULL, "falling");
// fall over
fall(lf, NULL, B_FALSE);
} else {
// TODO: if you are outside, DIE!
if (isplayer(lf)) {
msg("You slam into the roof!");
} else if (cansee(player, lf)){
msg("%s slams into the roof!", lfname);
}
// take hitting roof damage
losehp(lf, roll("1d4"), DT_FALL, NULL, "slamming into the roof");
}
}
if (isplayer(lf)) {
statdirty = B_TRUE;
needredraw = B_TRUE;

9
lf.h
View File

@ -5,7 +5,7 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller);
job_t *addjob(enum JOB id, char *name);
race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcolour, enum MATERIAL mat, enum RACECLASS raceclass);
raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill);
skill_t *addskill(enum SKILL id, char *name, char *desc);
skill_t *addskill(enum SKILL id, char *name, char *desc, int traintime);
void addtrail(lifeform_t *lf, int dir);
void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype);
void adjustspeedforwater(lifeform_t *lf, int *speed);
@ -48,6 +48,9 @@ int countnearbyhurtallies(lifeform_t *lf);
void debug(lifeform_t *lf);
int demandbribe(lifeform_t *lf);
void die(lifeform_t *lf);
int digcell(lifeform_t *lf, cell_t *c, object_t *o);
int digdown(lifeform_t *lf, object_t *o);
int digup(lifeform_t *lf, object_t *o);
void dumplev(void);
void dumplf(void);
void dumpxp(void);
@ -80,6 +83,7 @@ void getadjallies(lifeform_t *lf, lifeform_t **adjally, int *nadjallies);
enum ALLEGIENCE getallegiance(lifeform_t *lf);
int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs);
object_t *getarmour(lifeform_t *lf, enum BODYPART bp);
int getarmournoise(lifeform_t *lf);
int getarmourrating(lifeform_t *lf);
int getattackspeed(lifeform_t *lf);
int getattpoints(lifeform_t *lf);
@ -131,6 +135,7 @@ int getmovespeed(lifeform_t *lf);
char *getmoveverb(lifeform_t *lf);
char *getmoveverbother(lifeform_t *lf);
lifeform_t *getnearbypeaceful(lifeform_t *lf);
char *getpitverb(lifeform_t *lf, int dir, int onpurpose);
char *getlfname(lifeform_t *lf, char *buf);
char *real_getlfname(lifeform_t *lf, char *buf, int usevis);
char *getlfnamea(lifeform_t *lf, char *buf);
@ -297,7 +302,7 @@ void unsummon(lifeform_t *lf, int vanishobs);
int unweild(lifeform_t *lf, object_t *o);
int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where);
int useringofmiracles(lifeform_t *lf, int charges);
int usestairs(lifeform_t *lf, object_t *o);
int usestairs(lifeform_t *lf, object_t *o, int onpurpose);
int validateraces(void);
int wear(lifeform_t *lf, object_t *o);
int weild(lifeform_t *lf, object_t *o);

849
map.c

File diff suppressed because it is too large Load Diff

34
map.h
View File

@ -1,12 +1,17 @@
#include "defs.h"
cell_t *addcell(map_t *map, int x, int y);
habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell);
void addhomeobs(lifeform_t *lf);
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);
int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, int doorpct);
region_t *addregion(enum REGIONTYPE rtype, region_t *parent);
regionoutline_t *addregionoutline(enum REGIONTYPE rtype);
regionthing_t *addregionthing(regionoutline_t *ro, int depth, int x, int y, enum REGIONTHING whatkind, int value, char *what);
regiontype_t *addregiontype(enum REGIONTYPE id, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir);
int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, int doorpct, int dooropenchance);
int cellhaslos(cell_t *c1, cell_t *dest);
void clearcell(cell_t *c);
int dowaterspread(cell_t *c);
@ -17,21 +22,22 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer);
enum DEPTH getcellwaterdepth(cell_t *c, lifeform_t *lf);
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 getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlof, int wantcentre, cell_t **retcell, int *ncells);
void getroomedge(map_t *m, int roomid, int minx, int miny, int maxx, int maxy, int whichside, cell_t **retcell, int *ncells, int onlywantsolid);
object_t *gettopobject(cell_t *where, int forglyph);
void calclight(map_t *map);
int calcroompos(map_t *map, int w, int h, int *bx, int *by);
int calcroompos(map_t *map, int w, int h, int *bx, int *by, int force);
int countadjcellsoftype(cell_t *cell, int id);
int countadjcellswithflag(cell_t *cell, enum FLAG fid);
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 createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir);
void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int exitdir);
void createpit(map_t *map, int depth, map_t *parentmap, int exitdir);
void createregionlink(map_t *m, cell_t *c, object_t *o, char *obname, enum REGIONTYPE newregiontype, region_t *parent);
int createroom(map_t *map, int roomid, int overrideminw, int overrideminh, int *retx, int *rety, int *retw, int *reth, int doorpct, int forcewalls);
int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth);
int dirtox(int dt, int dir);
@ -41,16 +47,23 @@ void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *c
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);
habitat_t *findhabitat(enum HABITAT id);
habitat_t *findhabitatbyname(char *name);
map_t *findmap(int mid);
map_t *findmapofdepth(int depth);
cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf);
object_t *findobidinmap(map_t *m, long id);
cell_t *findobinmap(map_t *m, enum OBCLASS oid);
map_t *findregionmap(int region, int depth);
region_t *findregion(int regionid);
region_t *findregionbytype(enum REGIONTYPE rtid);
map_t *findregionmap(int regionid, int depth);
regiontype_t *findregiontype(enum REGIONTYPE rtype);
map_t *findsurfaceexitmap(map_t *m);
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);
char *getregionname(char *buf, map_t *m, int withlevel);
int getvaultchance(map_t *m);
char getvaultchar(vault_t *v, int x, int y);
int getthingchance(int habitat);
@ -69,6 +82,7 @@ lifeform_t *haslf(cell_t *c);
int hasknownobject(cell_t *c);
int hasobject(cell_t *c);
object_t *hastrailof(obpile_t *op, lifeform_t *lf, enum OBTYPE oid, flag_t **tflag, lifeform_t *viewer);
void initmap(void);
int isadjacent(cell_t *src, cell_t *dst);
int isdark(cell_t *c);
int isdiggable(cell_t *c);
@ -82,11 +96,15 @@ int isonmap(map_t *map, int x, int y);
int isoutdoors(map_t *m);
int iswallindir(cell_t *cell, int dir);
int linkexits(map_t *m, int roomid, int minx, int miny, int maxx, int maxy);
void linkholes(map_t *map);
int linkstairs(object_t *o);
void makedoor(cell_t *cell);
void makedoor(cell_t *cell, int openchance);
void makelit(cell_t *c, enum LIGHTLEV how, int howlong);
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 setcelltype(cell_t *cell, enum CELLTYPE id);
int shattercell(cell_t *c, lifeform_t *fromlf, char *damstring);
void updateknowncells(void);
int validateregions(void);
int validateregionthing(regionthing_t *thing);
int wallstoleftright(cell_t *c, int dir);

21
move.c
View File

@ -1202,7 +1202,9 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
// just clear the message buffer
if (!didmsg) clearmsg();
} else { // tell player what is here
dolook(newcell, B_FALSE);
if (onpurpose) {
dolook(newcell, B_FALSE);
}
}
}
}
@ -1348,7 +1350,7 @@ int opendoor(lifeform_t *lf, object_t *o) {
// locked?
if (hasflag(o->flags, F_LOCKED)) {
if (lf && isplayer(lf)) {
msg("The door is locked.");
msg("The %s is locked.", noprefix(obname));
}
return B_TRUE;
} else {
@ -1361,9 +1363,9 @@ int opendoor(lifeform_t *lf, object_t *o) {
if (lf && isplayer(lf)) {
if (amt > 0) {
msg("The door moves slightly but seems jammed.");
msg("The %s moves slightly but seems jammed.", noprefix(obname));
} else {
msg("The door is jammed.");
msg("The %s is jammed.", noprefix(obname));
}
}
// loosen a bit
@ -1491,7 +1493,9 @@ int closedoor(lifeform_t *lf, object_t *o) {
} else {
// close it
killflag(f);
addflag(o->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL);
f = hasflag(o->flags, F_DOOR);
addflag(o->flags, F_IMPASSABLE, f->val[0], f->val[1], f->val[2], f->text);
addflag(o->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
if (lf) {
@ -2009,6 +2013,11 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
}
}
}
// train
if (isswimming(lf)) {
practice(lf, SK_SWIMMING, 1);
}
} else {
object_t *inway = NULL;
int door, dooropen;
@ -2236,7 +2245,7 @@ int walkoffmap(lifeform_t *lf, int dir, int onpurpose) {
if (!adjmap) {
// make one
adjmap = addmap();
createmap(adjmap, thismap->depth, thismap->region, AUTO, thismap, dir);
createmap(adjmap, thismap->depth, thismap->region, thismap, dir);
}
if (adjmap) {

36
nexus.c
View File

@ -30,7 +30,11 @@ race_t *firstrace = NULL,*lastrace = NULL;
raceclass_t *firstraceclass = NULL,*lastraceclass = NULL;
job_t *firstjob = NULL,*lastjob = NULL;
skill_t *firstskill = NULL,*lastskill = NULL;
habitat_t *firsthabitat = NULL,*lasthabitat = NULL;
map_t *firstmap = NULL,*lastmap = NULL;
region_t *firstregion = NULL,*lastregion = NULL;
regionoutline_t *firstregionoutline = NULL,*lastregionoutline = NULL;
regiontype_t *firstregiontype = NULL,*lastregiontype = NULL;
knowledge_t *knowledge = NULL, *lastknowledge = NULL;
hiddenname_t *firsthiddenname = NULL, *lasthiddenname = NULL;
@ -145,6 +149,7 @@ int main(int argc, char **argv) {
cell_t *where;
int dir;
flag_t *f;
map_t *dmap;
// read from input file if required
if (playerfile) {
@ -178,13 +183,21 @@ int main(int argc, char **argv) {
// if no maps (ie. ALWAYS now that maps aren't persistent),
// make the initial level
if (!firstmap) {
region_t *wregion, *dregion;
newworld = B_TRUE;
// create world map.
wregion = addregion(RG_WORLDMAP, NULL);
addmap();
createmap(firstmap, 1, RG_FIRSTDUNGEON, H_DUNGEON, NULL, D_NONE);
createmap(firstmap, 1, wregion, NULL, D_NONE);
//createmap(firstmap, 1, RG_FIRSTDUNGEON, H_DUNGEON, NULL, D_NONE);
// create first dungeon
dregion = findregionbytype(RG_FIRSTDUNGEON);
dmap = addmap();
createmap(dmap, 1, dregion, NULL, D_NONE);
}
// find staircase
where = findobinmap(firstmap, OT_STAIRSUP);
where = findobinmap(dmap, OT_STAIRSUP);
assert(where);
// make sure no lifeforms are there
if (where->lf) {
@ -752,17 +765,7 @@ int init(void) {
initjobs();
initrace();
// cell types
addcelltype(CT_WALL, "rock wall", '#', C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0);
addcelltype(CT_WALLGLASS, "glass wall", '#', C_CYAN, B_SOLID, B_TRANS, MT_GLASS, 0);
addcelltype(CT_WALLMETAL, "metal wall", '#', C_WHITE, B_SOLID, B_OPAQUE, MT_METAL, 0);
addcelltype(CT_ROOMWALL, "rock wall", '#', C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0);
addcelltype(CT_CORRIDOR, "rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0);
addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0);
addcelltype(CT_ROOM, "rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0);
addcelltype(CT_GRASS, "grass", '.', C_GREEN, B_EMPTY, B_TRANS, MT_PLANT, 0);
addcelltype(CT_DIRT, "dirt", '.', C_BROWN, B_EMPTY, B_TRANS, MT_STONE, 0);
addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -1);
initmap();
gamemode = GM_VALIDATION;
if (validateobs()) {
@ -779,6 +782,12 @@ int init(void) {
// load in vaults
loadvaults();
// validate regions
if (validateregions()) {
printf("Errors found in map outlines - check log for details. Bailing out.");
exit(1);
}
return B_FALSE;
}
@ -927,6 +936,7 @@ int limitf(float *what, float min, float max) {
}
int onein(int howmany) {
if (howmany <= 0) return B_FALSE;
if (rnd(1,howmany) == 1) return B_TRUE;
return B_FALSE;
}

358
objects.c
View File

@ -982,6 +982,57 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
}
// link holes to adjacent maps
if (o && hasflag(o->flags, F_PIT)) {
cell_t *c;
map_t *adjmap = NULL;
f = hasflag(o->flags, F_PIT);
c = getoblocation(o);
if ((c->map->region->rtype->id == RG_WORLDMAP) && (f->val[0] == D_DOWN)) {
// ie. going down from the surface. MUST be down because holes
// going up make no sense!
createregionlink(c->map, c, o, NULL, RG_PIT, c->map->region);
} else {
// create linked holes on any existing adjacent maps
if (f->val[0] == D_DOWN) {
adjmap = findregionmap(c->map->region->id, c->map->depth+1);
} else if (f->val[0] == D_UP) {
if ((c->map->region->rtype->id != RG_WORLDMAP) &&
(c->map->depth == 1) &&
(c->map->region->rtype->deeperdir == D_DOWN)) {
cell_t *newcell;
object_t *newob;
char buf[BUFLEN];
// ie. digging up to the surface
adjmap = findsurfaceexitmap(c->map);
// make a hole here. don't use linkholes since it can't
// cross regions.
newcell = getcellat(adjmap, c->x, c->y);
if (newcell->type->solid) {
newcell = real_getrandomadjcell(newcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_DONTNEED, &(o->type->id));
}
newob = addob(newcell->obpile, "hole in the ground");
sprintf(buf, "%ld", o->id);
addflag(newob->flags, F_MAPLINK, c->map->id, NA, NA, buf);
sprintf(buf, "%ld", newob->id);
addflag(o->flags, F_MAPLINK, adjmap->id, NA, NA, buf);
// don't call linkholes
adjmap = NULL;
} else {
adjmap = findregionmap(c->map->region->id, c->map->depth-1);
}
}
if (adjmap) {
linkholes(adjmap);
}
}
}
// other special changes we need to make based on what was
// asked for
if ((gamemode != GM_LOADING) && o) {
@ -1064,7 +1115,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
if (f) {
rf = hasflag(corpserace->flags, F_SIZE);
if (rf) {
f->val[0] = rf->val[0];
f->val[0] = SZ_MIN;
f->val[1] = rf->val[0];
} else {
killflag(f);
}
@ -2666,7 +2718,7 @@ glyph_t *getglyph(object_t *o) {
if (isdoor(o, &isopen)) {
if (issecretdoor(o)) {
return &(findcelltype(getwallcelltype(obloc->map->habitat))->glyph);
return &(findcelltype(obloc->map->habitat->solidcelltype)->glyph);
} else {
if (isopen) {
g = '-';
@ -4017,13 +4069,24 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
// show portal/stair destination
f = hasflag(o->flags, F_MAPLINK);
if (f && f->known) {
if (f && f->known && !hasflag(o->flags, F_PIT)) {
cell_t *thiscell;
map_t *thismap;
map_t *newmap;
thiscell = getoblocation(o);
thismap = thiscell->map;
newmap = findmap(f->val[0]);
if (newmap) {
char buf2[BUFLEN];
sprintf(buf2, " to level %d", newmap->depth);
strcat(localbuf, buf2);
if (newmap->region == thismap->region) {
char buf2[BUFLEN];
sprintf(buf2, " to level %d", newmap->depth);
strcat(localbuf, buf2);
} else {
char buf2[BUFLEN];
strcat(localbuf, " to ");
getregionname(buf2, newmap, B_FALSE);
strcat(localbuf, buf2);
}
}
}
@ -4300,7 +4363,7 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth
rarflag = hasflagval(ot->flags, F_RARITY, H_ALL, NA, NA, NULL);
if (!rarflag) {
if (map) {
rarflag = hasflagval(ot->flags, F_RARITY, map->habitat, NA, NA, NULL);
rarflag = hasflagval(ot->flags, F_RARITY, map->habitat->id, NA, NA, NULL);
} else {
rarflag = hasflagval(ot->flags, F_RARITY, NA, NA, NA, NULL);
}
@ -4479,7 +4542,7 @@ int getobrarity(object_t *o, enum RARITY *rr) {
m = c->map;
}
if (m) {
f = hasflagval(o->flags, F_RARITY,m->habitat, NA, NA, NULL);
f = hasflagval(o->flags, F_RARITY,m->habitat->id, NA, NA, NULL);
if (f) {
if (rr) {
*rr = (f->val[2] == NA) ? RR_COMMON : f->val[2];
@ -5197,8 +5260,8 @@ void initobjects(void) {
// dungeon features
addot(OT_DOORWOOD, "wooden door", "A sturdy wooden door.", MT_WOOD, 150, OC_DFEATURE);
// GLYPH here is a special case in getglyph
addflag(lastot->flags, F_DOOR, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL);
addflag(lastot->flags, F_DOOR, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -5210,8 +5273,8 @@ void initobjects(void) {
addot(OT_DOORIRON, "iron door", "A strong iron door.", MT_METAL, 300, OC_DFEATURE);
// GLYPH here is a special case in getglyph
addflag(lastot->flags, F_DOOR, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL);
addflag(lastot->flags, F_DOOR, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -5222,11 +5285,25 @@ void initobjects(void) {
addflag(lastot->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL);
addflag(lastot->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL);
// blocks movement, but you can see and fire through them.
addot(OT_IRONGATE, "iron gate", "A gate comprised of a series of vertical iron bars.", MT_METAL, 0, OC_DFEATURE);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "|");
addflag(lastot->flags, F_DOOR, SZ_MEDIUM, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MEDIUM, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 120, 120, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL);
addflag(lastot->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL);
addot(OT_BOULDER, "boulder", "A massive stone boulder.", MT_STONE, 80, OC_ROCK);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL);
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
@ -5237,9 +5314,10 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "50-100 stones");
addot(OT_ICICLE, "huge icicle", "A massive ice stalacmite.", MT_ICE, 200, OC_ROCK);
addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -5249,7 +5327,7 @@ void initobjects(void) {
addot(OT_STATUE, "statue", "A stone statue of a monster.", MT_STONE, 80, OC_ROCK);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL); // will be overridden
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -5258,6 +5336,25 @@ void initobjects(void) {
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "20-50 stones");
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "a statue");
addot(OT_HOLEINGROUND, "hole in the ground", "A gaping hole in the ground.", MT_NOTHING, 0, OC_DFEATURE);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "^");
addflag(lastot->flags, F_CLIMBABLE, D_DOWN, NA, NA, NULL);
addflag(lastot->flags, F_PIT, D_DOWN, NA, NA, NULL);
addflag(lastot->flags, F_OPPOSITESTAIRS, OT_HOLEINROOF, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL);
addot(OT_HOLEINROOF, "hole in the roof", "A gaping hole in the roof.", MT_NOTHING, 0, OC_DFEATURE);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "<");
addflag(lastot->flags, F_CLIMBABLE, D_UP, NA, NA, NULL);
addflag(lastot->flags, F_PIT, D_UP, NA, NA, NULL);
addflag(lastot->flags, F_OPPOSITESTAIRS, OT_HOLEINGROUND, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL);
addot(OT_STAIRSDOWN, "staircase going down", "A stone staircase winding downwards.", MT_STONE, 3000, OC_DFEATURE);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ">");
addflag(lastot->flags, F_CLIMBABLE, D_DOWN, NA, NA, NULL);
@ -5472,7 +5569,7 @@ void initobjects(void) {
addot(OT_SHRUB, "shrub", "A small but dense shrub.", MT_PLANT, 40, OC_FLORA);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, "");
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%");
addflag(lastot->flags, F_IMPASSABLE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MEDIUM, NA, NULL);
addflag(lastot->flags, F_REDUCEMOVEMENT, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -5482,7 +5579,7 @@ void initobjects(void) {
addot(OT_STUMP, "stump", "A large tree stump.", MT_WOOD, 150, OC_FLORA);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, "");
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_HUMAN, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_HUMAN, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
@ -5491,7 +5588,7 @@ void initobjects(void) {
addot(OT_TREE, "tree", "A tree.", MT_WOOD, 200, OC_FLORA);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, "");
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -5814,6 +5911,10 @@ void initobjects(void) {
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_COMMANDUNDEAD, "command undead", "Compels an undead creature to follow a single simple command.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_FEAR, "cause fear", "Causes intense fear in the target.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
@ -5943,6 +6044,12 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
addot(OT_S_SHATTER, "shatter", "Instantly shatters all glass in the target location.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l3
addot(OT_S_AIRBLAST, "airblast", "Knocks enemies back with a powerful blast of air.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
@ -6553,7 +6660,7 @@ void initobjects(void) {
addot(OT_A_RAGE, "rage", "Enter a state of berzerker rage, gaining attack and defence bonuses.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addot(OT_A_REPAIR, "repair armour", "Repair damage done to your armour.", MT_NOTHING, 0, OC_ABILITY);
addot(OT_A_REPAIR, "repair equipment", "Repair damage done to your equipment.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_SPRINT, "sprint", "You can run at high speed over short distances.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
@ -6931,6 +7038,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SHARP, 1, 2, NA, NULL);
addflag(lastot->flags, F_CRUSHABLE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastot->flags, F_NOSHATTER, B_TRUE, NA, NA, NULL);
addot(OT_CALTROP, "caltrop", "Connected metal spikes arranged such that one will always point upwards.", MT_METAL, 0.2, OC_MISC);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, NULL);
@ -6963,6 +7071,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOSHATTER, B_TRUE, NA, NA, NULL);
addot(OT_MELTEDWAX, "lump of melted wax", "A useless lump of melted wax.", MT_WAX, 0.1, OC_MISC);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
@ -7167,7 +7276,7 @@ void initobjects(void) {
addot(OT_WOODENBARREL, "wooden barrel", "A solid wooden barrel.", MT_WOOD, 20, OC_MISC);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "(");
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL);
addflag(lastot->flags, F_CRUSHABLE, SZ_HUGE, NA, NA, NULL);
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
@ -7178,7 +7287,7 @@ void initobjects(void) {
addot(OT_WOODENTABLE, "wooden table", "A waist-height wooden table.", MT_WOOD, 25, OC_MISC);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "\\");
addflag(lastot->flags, F_IMPASSABLE, SZ_HUMAN, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_HUMAN, NA, NULL);
addflag(lastot->flags, F_CRUSHABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
//addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
@ -7376,14 +7485,15 @@ void initobjects(void) {
addot(OT_ICEWALL, "wall of ice", "A wall made of solid ice.", MT_ICE, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 100, 100, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addot(OT_MAGICBARRIER, "magical barrier", "A glowing, impassable barrier of magical energy.", MT_MAGIC, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "vanishes");
@ -7589,7 +7699,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL);
addflag(lastot->flags, F_EVASION, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
addot(OT_GASMASK, "gas mask", "A full face mask which protects the wearer from toxic gasses.", MT_METAL, 1, OC_ARMOUR);
addot(OT_GASMASK, "gas mask", "A full face mask which protects the wearer from toxic gasses.", MT_METAL, 3.5, OC_ARMOUR);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
@ -8639,14 +8749,15 @@ int isimpassableob(object_t *o, lifeform_t *lf) {
f = hasflag(o->flags, F_IMPASSABLE);
if (f) {
enum LFSIZE lfsize;
enum LFSIZE blocksize;
enum LFSIZE blockmin, blockmax;
if (!lf) return B_TRUE;
lfsize = getlfsize(lf);
blocksize = f->val[0];
if (lfsize <= blocksize) {
blockmin = f->val[0];
blockmax = f->val[1];
if ((lfsize >= blockmin) && (lfsize <= blockmax)) {
return B_TRUE;
}
}
@ -9274,6 +9385,18 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) {
reason = E_OK;
// adjust destination for pits
if (dst->where) {
object_t *pit;
pit = hasobwithflagval(dst->where->obpile, F_PIT, D_DOWN, NA, NA, NULL);
if (pit) {
cell_t *newcell;
newcell = getstairdestination(pit);
if (newcell) {
dst = newcell->obpile;
}
}
}
if (db) dblog("DB: moveob() - moving %d x %s",howmany, src->type->name);
if (stackok) {
@ -9354,6 +9477,7 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) {
killflagsofid(o->flags, F_SECRET);
if (!hasflag(o->flags, F_OPEN)) {
addflag(o->flags, F_OPEN, B_TRUE, NA, NA, NULL);
killflagsofid(o->flags, F_IMPASSABLE);
}
}
}
@ -10124,7 +10248,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
} else if (o->type->id == OT_ORBDUNGEONEXIT) {
map_t *m;
m = lf->cell->map;
if ((m->region == RG_FIRSTDUNGEON) && (m->depth == 1)) {
if ((m->region->rtype->id == RG_FIRSTDUNGEON) && (m->depth == 1)) {
cell_t *cell[MAXCANDIDATES];
int ncells,i;
getradiuscells(lf->cell, 1, DT_COMPASS, B_FALSE, B_TRUE, cell, &ncells);
@ -10255,101 +10379,30 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
} else if (o->type->id == OT_PICKAXE) {
int ch,dir;
cell_t *c;
ch = askchar("Dig in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE);
dir = chartodir(ch);
c = getcellindir(player->cell, dir);
if (!c) {
ch = askchar("Dig in which direction (- to cancel)", "yuhjklbn><-","-", B_FALSE);
if (ch == '-') {
// cancel
clearmsg();
return B_TRUE;
}
if (c->type->solid) {
if (isdiggable(c)) {
// replace wall
setcelltype(c, getemptycelltype(c->map->habitat));
if (isplayer(lf)) {
msg("You dig through the wall.");
needredraw = B_TRUE;
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s digs through a wall.",lfname);
needredraw = B_TRUE;
}
//drawscreen();
// takes extra time
taketime(lf, getactspeed(lf)*9);
} else {
// fail
if (isplayer(lf)) {
msg("This wall is too hard to dig.");
}
} else if (ch == '>') {
if (digdown(lf, o)) {
// failed
return B_TRUE;
}
} else { // not solid
int failed = B_FALSE;
object_t *door;
door = hasobwithflag(c->obpile, F_DOOR);
if (door) {
int dooropen;
// only closed doors!
isdoor(door, &dooropen);
if (dooropen) {
door = NULL;
}
} else if (ch == '<') {
if (digup(lf, o)) {
// failed
return B_TRUE;
}
} else {
dir = chartodir(ch);
c = getcellindir(lf->cell, dir);
if (door) {
// TODO: metal doors are immune to CHOP damage
if (!isimmuneto(door->flags, DT_CHOP)) {
taketime(lf, getactspeed(lf));
removeob(door, door->amt);
if (isplayer(lf)) {
msg("You smash open a door!");
needredraw = B_TRUE;
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s smashes open a door.",lfname);
needredraw = B_TRUE;
}
drawscreen();
failed = B_FALSE;
}
} else if (hasob(c->obpile, OT_STATUE)) {
int dam;
object_t *so;
char statname[BUFLEN];
so = hasob(c->obpile, OT_STATUE);
getobname(so, statname, so->amt);
taketime(lf, getactspeed(lf));
// statue takes 1/2 damage
f = hasflag(so->flags, F_OBHP);
if (f) {
dam = (f->val[1] / 2); // ie. half max hp
} else {
dam = 1;
}
// statue ?
if (isplayer(lf)) {
msg("You hit %s with your %s.", statname, noprefix(obname));
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s hits %s with %s.", lfname, statname, obname);
}
takedamage(so, dam, DT_CHOP);
} else {
if (isplayer(lf)) {
msg("You swing your %s through the air.",noprefix(obname));
}
taketime(lf, getactspeed(lf));
if (digcell(lf, c, o)) {
// failed
return B_TRUE;
}
}
} // end if ch is a direction
} else if (o->type->id == OT_SPANNER) {
int donesomething = B_FALSE;
if (!where) {
@ -11671,7 +11724,8 @@ void setobcreatedby(object_t *o, lifeform_t *lf) {
}
void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
// returns TRUE if it did shatter
int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
int shatterdam;
cell_t *where = NULL;
lifeform_t *target = NULL;
@ -11680,6 +11734,10 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
char targetname[BUFLEN];
int seen = B_FALSE;
if (hasflag(o->flags, F_NOSHATTER)) {
return B_FALSE;
}
getobname(o,obname,o->amt);
where = getoblocation(o);
@ -11695,13 +11753,20 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
// announce
if (haslos(player, where)) {
char *obcaps;
obcaps = strdup(obname);
capitalise(obcaps);
obcaps = strrep(obcaps, "An ", "The ", NULL);
obcaps = strrep(obcaps, "A ", "The ", NULL);
msg("%s shatter%s!",obcaps, (o->amt == 1) ? "s" : "");
free(obcaps);
char prefix[BUFLEN];
if (o->pile->owner) {
char lfname[BUFLEN];
getlfname(o->pile->owner, lfname);
sprintf(prefix, "%s%s ", lfname, getpossessive(lfname));
// ie. "the kobold's"
} else {
strcpy(prefix, "");
}
msg("%s%s shatter%s!",prefix, strlen(prefix) ? noprefix(obname) : obname,
(o->amt == 1) ? "s" : "");
seen = B_TRUE;
} else {
@ -11873,6 +11938,8 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
// object is dead.
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
addflag(o->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
return B_TRUE;
}
// randomizes hidden names
@ -12101,14 +12168,14 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno
// special cases....
if (damtype == DT_FIRE) {
if (o->material->id == MT_FLESH) { // fire roasts flesh
if ((o->material->id == MT_FLESH) && rnd(1,3)) { // fire sometimes roasts flesh
object_t *meat;
meat = addob(o->pile, "chunk of roast meat");
// purposely don't use getweight!
meat->weight = o->weight;
} else { // fire turns other things to ash
addob(o->pile, "pile of ash");
}
// fire turns things to ash
addob(o->pile, "pile of ash");
} else if (damtype == DT_BASH) {
if (o->material->id == MT_GLASS) { // bashing damage breaks glass
int nshards;
@ -12194,7 +12261,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
char throwverbpast[BUFLEN];
char throwverbpres[BUFLEN];
int acc;
int youhit;
int youhit = B_FALSE;
object_t *newob;
cell_t *newloc;
int db = B_TRUE;
@ -12537,6 +12604,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
dam = (int)((float)throwdam * multiplier);
takedamage(shield, dam, DT_PROJECTILE);
youhit = B_FALSE;
practice(target, SK_SHIELDS, 1);
}
}
}
@ -12640,6 +12708,10 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
}
wepeffects(o->flags, target->cell, hasflag(o->flags, F_DAM), dam);
if (firearm) {
practice(thrower, SK_RANGED, 1);
}
}
} else { // ie. if !youhit
if (!announcedmiss) {
@ -12672,8 +12744,11 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
sprintf(dambuf, "%s (%s by %s)",obname,throwverbpast, realthrowernamea);
shatter(newob, youhit, dambuf, thrower);
} else {
// don't announce damage to the thrown object
real_takedamage(newob, speed-1, DT_BASH, B_FALSE);
// object only gets damaged if it hit someone
if (youhit) {
// don't announce damage to the thrown object
real_takedamage(newob, speed-1, DT_BASH, B_FALSE);
}
}
return B_FALSE;
@ -13154,7 +13229,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf) {
} else if (oid == OT_TRAPTELEPORT) {
cell_t *newc;
// move somewhere else!
newc = getrandomcelloftype(lf->cell->map, getemptycelltype(lf->cell->map->habitat));
newc = getrandomcelloftype(lf->cell->map, lf->cell->map->habitat->id);
if (newc) {
teleportto(lf, newc, B_TRUE);
}
@ -13486,6 +13561,25 @@ int validateobs(void) {
printf("ERROR in object '%s' - has f_thereishere but no ->text.\n", ot->name);
goterror = B_TRUE;
}
f = hasflag(ot->flags, F_IMPASSABLE);
if (f && ((f->val[0] == NA) || (f->val[1] == NA)) ) {
printf("ERROR in object '%s' - f_impassable missing either min or max.\n", ot->name);
goterror = B_TRUE;
}
f = hasflag(ot->flags, F_DOOR);
if (f) {
flag_t *f2;
f2 = hasflag(ot->flags, F_IMPASSABLE);
if (f2) {
if ((f->val[0] != f2->val[0]) || (f->val[1] != f2->val[1])) {
printf("ERROR in object '%s' - f_door vals don't match f_impassable vals.\n", ot->name);
goterror = B_TRUE;
}
} else {
printf("ERROR in object '%s' - has f_door but not f_impassable.\n", ot->name);
goterror = B_TRUE;
}
}
}
/*

View File

@ -204,7 +204,7 @@ void setblessed(object_t *o, enum BLESSTYPE wantbless);
int sethiddenname(objecttype_t *o, char *text);
void setinscription(object_t *o, char *text);
void setobcreatedby(object_t *o, lifeform_t *lf);
void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf);
int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf);
void shufflehiddennames(void);
object_t *splitob(object_t *o);
int takedamage(object_t *o, unsigned int howmuch, int damtype);

6
save.c
View File

@ -256,6 +256,7 @@ map_t *loadmap(char *basefile) {
int i;
int x,y;
int db = B_TRUE;
enum HABITAT habitatid;
lifeform_t *l;
object_t *o;
map_t *m;
@ -284,7 +285,8 @@ map_t *loadmap(char *basefile) {
fgets(buf, BUFLEN, f); // map name
buf[strlen(buf)-1] = '\0'; // strip newline
m->name = strdup(buf + 5); // after 'name:'
fscanf(f, "habitat:%d\n",(int *)&m->habitat); // habitat
fscanf(f, "habitat:%d\n",(int *)habitatid); // habitat
m->habitat = findhabitat(habitatid);
fscanf(f, "seed:%d\n",&m->seed); // seed
fscanf(f, "dims:%d,%d\n",&m->w, &m->h); // map dimensons
fscanf(f, "nextmaps:\n");
@ -724,7 +726,7 @@ int savemap(map_t *m) {
fprintf(f, "id:%d\n",m->id); // map id
fprintf(f, "depth:%d\n",m->depth); // map depth
fprintf(f, "name:%s\n",m->name); // map name
fprintf(f, "habitat:%d\n",m->habitat); // habitat
fprintf(f, "habitat:%d\n",m->habitat->id); // habitat
fprintf(f, "seed:%d\n",m->seed); // seed
fprintf(f, "dims:%d,%d\n",m->w, m->h); // map dimensons
fprintf(f, "nextmaps:\n");

138
spell.c
View File

@ -249,6 +249,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
getobname(o, buf, o->amt);
msgnocap("%c - %s", o->letter, buf);
practice(user, SK_COOKING, 1);
} else {
msg("Your cooking attempt fails (maybe your pack was too full?).");
}
@ -371,6 +372,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (isplayer(user) && hasjob(user, J_ROGUE)) {
gainxp(user, trapflag->val[0]);
}
practice(user, SK_TRAPS, 1);
} else {
// failed. another check to see if it goes off
if ((trapflag->val[1] == B_TRUE) && !skillcheck(user, SC_DISARM, trapflag->val[0], 0)) {
@ -693,29 +695,69 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} else if (abilid == OT_A_REPAIR) {
enum SKILLLEVEL slev;
object_t *o;
int cutoffpct = 0;
slev = getskill(user, SK_ARMOUR);
switch (slev) {
default:
if (isplayer(user)) {
msg("You are too unskilled to repair your armour.");
}
return B_TRUE;
case PR_SKILLED: cutoffpct = 50; break;
case PR_EXPERT: cutoffpct = 75; break;
case PR_MASTER: cutoffpct = 100; break;
enum MATERIAL repairablemats[MAXCANDIDATES];
int repaircutoff = 0;
int cutoffpct[MAXCANDIDATES];
int nmats = 0;
int i;
// get list of repairable materials
slev = getskill(user, SK_METALWORK);
if (slev) {
int cutoff;
switch (slev) {
case PR_NOVICE: cutoff = 33; break;
case PR_BEGINNER: cutoff = 40; break;
case PR_ADEPT: cutoff = 50; break;
case PR_SKILLED: cutoff = 65; break;
case PR_EXPERT: cutoff = 80; break;
case PR_MASTER: cutoff = 100; break;
default: cutoff = 0; break;
}
repairablemats[nmats] = MT_METAL;
cutoffpct[nmats] = cutoff;
nmats++;
}
slev = getskill(user, SK_SEWING);
if (slev) {
int cutoff;
switch (slev) {
case PR_NOVICE: cutoff = 33; break;
case PR_BEGINNER: cutoff = 40; break;
case PR_ADEPT: cutoff = 50; break;
case PR_SKILLED: cutoff = 65; break;
case PR_EXPERT: cutoff = 80; break;
case PR_MASTER: cutoff = 100; break;
default: cutoff = 0; break;
}
repairablemats[nmats] = MT_CLOTH;
cutoffpct[nmats] = cutoff;
nmats++;
repairablemats[nmats] = MT_LEATHER;
cutoffpct[nmats] = cutoff;
nmats++;
}
// 1.compile a list of repairable objects
// sk_armour lets you repair armour up to xx% (depends on skill)
initprompt(&prompt, "Repair which object?");
addchoice(&prompt, '-', "Cancel", buf, o);
addchoice(&prompt, '-', "Cancel", "Cancel", o);
for (o = user->pack->first ; o ; o = o->next) {
if (isarmour(o) && isdamaged(o)) {
int ok = B_FALSE;
int cutoff = 0;
for (i = 0; i < nmats; i++) {
if (o->material->id == repairablemats[i]) {
ok = B_TRUE;
cutoff = cutoffpct[i];
break;
}
}
if (ok && isdamaged(o)) {
float pct;
f = hasflag(o->flags, F_OBHP);
pct = ((float)f->val[0] /(float) f->val[1]) * 100;
if (pct < cutoffpct) {
if (pct < cutoff) {
char buf[BUFLEN];
getobname(o, buf, o->amt);
// we can repair this object
@ -747,9 +789,19 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_TRUE;
}
// select cutoff hp
repaircutoff = 0;
for (i = 0; i < nmats; i++) {
if (o->material->id == repairablemats[i]) {
repaircutoff = cutoffpct[i];
break;
}
}
assert(repaircutoff != 0);
// repair it!
f = hasflag(o->flags, F_OBHP);
f->val[0] = pctof(cutoffpct, f->val[1]);
f->val[0] = pctof(repaircutoff, f->val[1]);
if (isplayer(user)) {
char buf[BUFLEN];
real_getobname(o, buf, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE);
@ -815,6 +867,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
addtempflag(user->flags, F_SPRINTING, B_TRUE, NA, NA, NULL, howlong);
practice(user, SK_ATHLETICS, 1);
} else if (abilid == OT_A_STINGACID) {
validateabillf(user, abilid, &target);
if (!target) return B_TRUE;
@ -1259,6 +1312,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} else if (cansee(player, user)) {
msg("%s tries to steal from %s, but fails.", username, targetname);
}
} else {
practice(user, SK_THIEVERY, 1);
}
} else if (abilid == OT_A_WARCRY) {
// announce
@ -2324,6 +2379,43 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
damageallobs(NULL, retcell[i]->obpile, 0, DT_COLD);
}
}
} else if (spellid == OT_S_COMMANDUNDEAD) {
// mosnters won't cast this.
if (!isplayer(caster)) {
fizzle(caster);
return B_TRUE;
}
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (!target || !isundead(target)) {
fizzle(caster);
return B_TRUE;
}
// saving throw
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (isplayer(caster) || cansee(player, target)) {
char tname[BUFLEN];
getlfname(target, tname);
msg("%s resists.",tname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// they get angry!
if (!isplayer(target) && cansee(target, caster)) {
fightback(target, caster);
}
} else {
flag_t *f;
if (isplayer(caster) || cansee(player, target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// it worked. temporarily make them a pet so that you
// can command them.
f = addflag(target->flags, F_PETOF, caster->id, NA, NA, NULL);
docomms(target);
killflag(f);
}
} else if (spellid == OT_S_CREATEMONSTER) {
lifeform_t *newlf;
job_t *forcejob = NULL;
@ -2512,7 +2604,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
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));
setcelltype(retcell[i], retcell[i]->map->habitat->emptycelltype);
if (seenthiscell) {
ndigs++;
numseen++;
@ -2700,7 +2792,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
// destroy objects right away
removedeadobs(targcell->lf->pack);
removedeadobs(targcell->obpile);
// explosion, based on size...
if (totalmass > 0) {
@ -4118,7 +4210,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else {
int howlong = 7;
howlong = getspellduration(3,5,blessed) + (power/2);
addtempflag(target->flags, F_PAIN, DT_MAGIC, NA, NA, "2d4+2", howlong);
addtempflag(target->flags, F_PAIN, DT_MAGIC, NA, NA, "1d3", howlong);
}
} else {
fizzle(caster);
@ -4467,7 +4559,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!newmap) {
// create new map
newmap = addmap();
createmap(newmap, newdepth, caster->cell->map->region, AUTO, NULL, D_NONE);
createmap(newmap, newdepth, caster->cell->map->region, NULL, D_NONE);
}
@ -5461,6 +5553,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = addtempflag(caster->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
} else if (spellid == OT_S_SHATTER) {
char buf[BUFLEN];
if (!validatespellcell(caster, &targcell,TT_NONE, spellid, power, frompot)) return B_TRUE;
sprintf(buf, "%s%s shatter spell", castername, getpossessive(castername));
if (!shattercell(targcell, caster, buf)) {
fizzle(caster);
}
} else if (spellid == OT_S_SLEEP) {
int howlong;
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;

View File

@ -8,6 +8,7 @@ random(4,4)
@end
@flags
goesin:dungeon
autodoors:25
autopop
scatter(1,1,-2,-2) ob:boulder:25%

View File

@ -17,6 +17,7 @@
@end
@flags
goesin:dungeon
autodoors:50
autopop
@end

View File

@ -8,6 +8,7 @@ random(4,4)
@end
@flags
goesin:dungeon
autodoors:75
autopop
! tables & chairs

View File

@ -9,6 +9,7 @@ random(5,5)
@end
@flags
goesin:dungeon
! 100% chance of doors - don't want the water escaping
autodoors:100
autopop

View File

@ -8,6 +8,7 @@ random(5,5)
@end
@flags
goesin:dungeon
autodoors:50
autopop
fill(2,2,-3,-3) cell:low rock floor:100

View File

@ -24,6 +24,7 @@ m:mon:minotaur
@end
@flags
goesin:dungeon
! the reward
at(7,7) ob:200-450 gold
at(7,7) ob:good weapon

View File

@ -8,6 +8,7 @@ random(5,5)
@end
@flags
goesin:dungeon
! don't want cockatrice escaping
autodoors:100
scatter(1,1,-2,-2) ob:statue:25%

View File

@ -9,6 +9,7 @@ random(4,4)
@flags
autodoors:100
goesin:dungeon
! every cell in here has 1-3 objects and a monster
scatter(1,1,-2,-2) mon:random:100%
scatter(1,1,-2,-2) ob:random:100%

View File

@ -10,6 +10,7 @@ random(4,4)
@flags
autodoors:50
autopop
goesin:dungeon
! add mud to 50% of room cells
scatter(1,1,-2,-2) ob:pool of mud:50%
@end

View File

@ -7,6 +7,7 @@ random(5,5)
@end
@flags
goesin:dungeon
autodoors:50
autopop
scatter(1,1,-2,-2) cell:rock wall:25%

View File

@ -8,6 +8,7 @@ random(5,5)
@end
@flags
goesin:dungeon
autodoors:50
autopop
scatter(1,1,-2,-2) cell:glass wall:25%

View File

@ -8,6 +8,7 @@ random(3,3)
@end
@flags
goesin:dungeon
autodoors:100
! half the cells are trapped!
scatter(1,1,-2,-2) ob:random trap:50%

View File

@ -15,6 +15,7 @@ $:ob:25-200 gold
@end
@flags
goesin:dungeon
! no auto doors. ie this can be in the middle of nowhere.
@end