- [+] BUG: trying to go down stairs from L7 (6?)

- [+] You walk down the staircase...
          ERROR - can't find opposite end of stairs/portal!
    - [+] You walk down the staircase...  ERROR - unlinked stairs!
    - [+] This is related to the fact that all the staircases came from
          Jimbo's vault
    - [+] For some reason we're not linking them when they come for ma
          vault!!!
    - [+] "joining unliked stairs" section not working???
        - [+] it calls getstairdestination, but this DOESNT call
              linkstairs!
        - [+] maby: call autolink everytime i add stairs ?  or only do
              this during createvault ?
- [+] automatically remove useless doors (ie. ones where all adjacent
      walkable cells are in the same room)
- [+] in fix_reachability i'm drawing a corridor through vault/room
      walls. <- probably this one.
    - [+] don't allow auto reachability to enter rooms through the
          wrong side wall.
    - [+] TEST during regular playtests, see if maps look better.
- [+] quality on doors.
    - [+] sturdy / plain / shoddy doors. this impacts the hp
    - [+] stone doors (solid / plain /crumbling)
    - [+] metal ( reinforced / plain / rusty)
    - [+] only show this if perception >= beginner
- [+] dungeon shapes
    - [+] new cell attribute - locked.
    - [+] calcroompos can't make rooms on locked cells.
    - [+] normal
    - [+] cross
    - [+] circle
    - [+] turret
    - [+] - premask out blocked cells before generation!
- [+] minion code - if leader dies,
    - [+] minions drop morale
    - [+] and might either immediately flee 
    - [+] need lastdamlf
- [+] if wisdom >= gtaverage, automatically turn off lamps when you go
      to sleep 
- [+] "scratch"/"gnaw" etc should be based on actual damage hp amount,
      not percentage.
    - [+] change getattackverb()
    - [+] 1-2
    - [+] 3-6
    - [+] 8-12
    - [+] 12-18
    - [+] 18+
- [+] shop objects should start with all flags known.
- [+] allow usage of godstones without id'ing them first.  this will id
      them.
- [+] weapon/armour shop should resize armour for you for a cost.
- [+] chanelling bonus
    - [+] novice
        - [+] tell you when wand is low on charges (0-3)
    - [+] beginner
        - [+] let you determine exact remaining charges in wands once
              it is == 1!
    - [+] adept
        - [+] let you determine exact remaining charges in wands once
              it is <= 3!
    - [+] skilled:
        - [+] let you determine exact remaining charges in wands once
              it is <= 6!
    - [+] master
        - [+] lets you always see full amount of want charges.
        - [+] lets you convert your mp into wand charges? "imbue item"
This commit is contained in:
Rob Pearce 2012-01-09 04:02:26 +00:00
parent 6d57f7ebe3
commit e1b569f306
15 changed files with 801 additions and 289 deletions

36
data.c
View File

@ -1246,6 +1246,7 @@ void initobjects(void) {
addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastobjectclass->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addoc(OC_CORPSE, "Corpses", "Dead flesh which was once living.", '%', C_GREY, RR_NEVER);
@ -1296,6 +1297,8 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_BASH, NA, NA, NULL);
addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_MASTERWORK, 25, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_SHODDY, 25, NA, NULL);
addot(OT_DOORIRON, "iron door", "A strong iron door.", MT_METAL, 300, OC_DFEATURE, SZ_LARGE);
// GLYPH here is a special case in getglyph
@ -1457,7 +1460,8 @@ void initobjects(void) {
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SHOPMENU, 0, MA_GOTOMENU, SM_PURCHASEITEMS, "a:buy something");
addflag(lastot->flags, F_SHOPMENU, 1, MA_GOTOMENU, SM_DONATE, "d:donate something");
addflag(lastot->flags, F_SHOPMENU, 2, MA_QUIT, NA, "q:leave");
addflag(lastot->flags, F_SHOPMENU, 2, MA_GOTOMENU, SM_RESIZE, "r:resize equipment");
addflag(lastot->flags, F_SHOPMENU, 3, MA_QUIT, NA, "q:leave");
for (i = 0; i < 10; i++) {
addflag(lastot->flags, F_STARTOBCLASS, 100, OC_ARMOUR, RANDOM, NULL);
}
@ -1523,7 +1527,8 @@ void initobjects(void) {
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SHOPMENU, 0, MA_GOTOMENU, SM_PURCHASEITEMS, "a:buy something");
addflag(lastot->flags, F_SHOPMENU, 1, MA_GOTOMENU, SM_DONATE, "d:donate something");
addflag(lastot->flags, F_SHOPMENU, 2, MA_QUIT, NA, "q:leave");
addflag(lastot->flags, F_SHOPMENU, 2, MA_GOTOMENU, SM_RESIZE, "r:resize equipment");
addflag(lastot->flags, F_SHOPMENU, 3, MA_QUIT, NA, "q:leave");
for (i = 0; i < 10; i++) {
addflag(lastot->flags, F_STARTOBCLASS, 100, OC_WEAPON, RANDOM, NULL);
}
@ -5831,9 +5836,9 @@ void initobjects(void) {
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_UNARMED, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ATTACKVERB, NA, 5, NA, "scratch");
addflag(lastot->flags, F_ATTACKVERB, 6, 15, NA, "scrape");
addflag(lastot->flags, F_ATTACKVERB, 16, NA, NA, "rake");
addflag(lastot->flags, F_ATTACKVERB, NA, 2, NA, "scratch");
addflag(lastot->flags, F_ATTACKVERB, 3, 6, NA, "scrape");
addflag(lastot->flags, F_ATTACKVERB, 7, NA, NA, "rake");
addot(OT_TEETH, "teeth", "teeth object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
@ -5865,12 +5870,12 @@ void initobjects(void) {
addot(OT_CLAWS, "claws", "claws object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_SLASH, 2, NA, NULL);
addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ATTACKVERB, NA, 5, NA, "scratch");
addflag(lastot->flags, F_ATTACKVERB, 6, 15, NA, "claw");
addflag(lastot->flags, F_ATTACKVERB, 16, 30, NA, "tear");
addflag(lastot->flags, F_ATTACKVERB, 31, 40, NA, "rake");
addflag(lastot->flags, F_ATTACKVERB, 41, 50, NA, "gouge");
addflag(lastot->flags, F_ATTACKVERB, 51, NA, NA, "shred");
addflag(lastot->flags, F_ATTACKVERB, NA, 2, NA, "scratch");
addflag(lastot->flags, F_ATTACKVERB, 3, 6, NA, "claw");
addflag(lastot->flags, F_ATTACKVERB, 7, 12, NA, "tear");
addflag(lastot->flags, F_ATTACKVERB, 13, 18, NA, "rake");
addflag(lastot->flags, F_ATTACKVERB, 19, 24, NA, "gouge");
addflag(lastot->flags, F_ATTACKVERB, 25, NA, NA, "shred");
addflag(lastot->flags, F_KILLVERB, 70, NA, NA, "disembowel");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
@ -5880,7 +5885,8 @@ void initobjects(void) {
addot(OT_HOOF, "hooves", "hoof object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_BASH, 2, NA, NULL);
addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "kick");
addflag(lastot->flags, F_ATTACKVERB, NA, 11, NA, "kick");
addflag(lastot->flags, F_ATTACKVERB, 12, NA, NA, "trample");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
@ -11365,11 +11371,17 @@ void initskills(void) {
addskilldesc(SK_CARTOGRAPHY, PR_MASTER, "^gEvery 50 turns, you can intuitively map a small area around you.^n", B_FALSE);
addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items.", 0); // untrainable
addskilldesc(SK_CHANNELING, PR_NOVICE, "^gThe power level of wands and scrolls is increased by 1.^n", B_FALSE);
addskilldesc(SK_CHANNELING, PR_NOVICE, "^gYou can now recognise when objects are low on charges.^n", B_TRUE);
addskilldesc(SK_CHANNELING, PR_BEGINNER, "^gThe power level of wands and scrolls is increased by 2.^n", B_FALSE);
addskilldesc(SK_CHANNELING, PR_BEGINNER, "^gYou now know when objects have a single charge remaining.^n", B_TRUE);
addskilldesc(SK_CHANNELING, PR_ADEPT, "^gThe power level of wands and scrolls is increased by 4.^n", B_FALSE);
addskilldesc(SK_CHANNELING, PR_ADEPT, "^gYou now know when objects have less than four charges left.^n", B_TRUE);
addskilldesc(SK_CHANNELING, PR_SKILLED, "^gThe power level of wands and scrolls is increased by 6.^n", B_FALSE);
addskilldesc(SK_CHANNELING, PR_SKILLED, "^gYou now know when objects have less than seven charges left.^n", B_TRUE);
addskilldesc(SK_CHANNELING, PR_EXPERT, "^gThe power level of wands and scrolls is increased by 8.^n", B_FALSE);
addskilldesc(SK_CHANNELING, PR_EXPERT, "^gUsing any object will now reveal its remaining charges.^n", B_TRUE);
addskilldesc(SK_CHANNELING, PR_MASTER, "^gThe power level of wands and scrolls is increased by 10.^n", B_FALSE);
addskilldesc(SK_CHANNELING, PR_MASTER, "^gYou now always know remaining charges for all objects.^n", B_TRUE);
addskill(SK_CLIMBING, "Climbing", "Helps you to climb walls, mountains or other terrain.", 50);
addskilldesc(SK_CLIMBING, PR_INEPT, "Increases your chances of successfully climbing by 10% per level.", B_FALSE);
addskilldesc(SK_CLIMBING, PR_NOVICE, "You gain the 'climb walls' ability. Cannot attack while climbing.", B_FALSE);

26
defs.h
View File

@ -5,6 +5,7 @@
// MACROS
#define MAXOF(a,b) (a > b ? a : b)
#define MINOF(a,b) (a < b ? a : b)
#define OB1(o,one,many) (o->amt == 1) ? one : many
#define OBS1(o) (o->amt == 1) ? "s" : ""
#define OBNOS1(o) (o->amt == 1) ? "" : "s"
@ -1986,6 +1987,7 @@ enum FLAG {
F_NONE = 0, // dummy flag
// map flags
F_MAPCOORDS, // v0+v1 are x/y coords for this map area
F_MAPSHAPE, // v0 = enum MAPSHAPE
F_ROOMEXIT, // there is an exit from room v0 at x=v1,y=v2
F_NEWWATERDEPTH, // temp flag for the spread of f_deepwater obs.
// v0+1 are x/y, v2 is new depth.
@ -2272,11 +2274,11 @@ enum FLAG {
F_SHODDY, // weps do less damage, armour protects less.
// weapon flags
F_ATTACKVERB, // text=verb for attacking. ie. "hit" "slash" "sting" etc
// if v0/v1 are set, only use this text if dam pct is
// if v0/v1 are set, only use this text if dam AMOUNT (not pct) is
// between v0 and v1.
// should always be singular
F_KILLVERB, // text=verb for a fatal attacking. ie. "kill" "behead"
// if v0/v1 are set, only use this text if dam pct is
// if v0/v1 are set, only use this text if dam PCT (not amount) is
// between v0 and v1.
// should always be singular
F_OBATTACKDELAY, // how long weapon takes to attack
@ -2753,6 +2755,7 @@ enum FLAG {
// if v2 is set, means we are sleeping on
// purpose and will wake up when at full hp/mp/etc.
// ie. "resting"
// text = obid of light source which you turned off.
F_ATTACHEDTO, // you are attached to lf id v0, and will move with it
F_AWARENESS, // you can see 360 degrees around yourself
F_BEINGSTONED,// turn to stone when v0 drops to zero. (drops 1/turn)
@ -3438,6 +3441,19 @@ typedef struct hiddennamewithcol_s {
enum COLOUR col;
} hiddennamewithcol_t;
enum MAPSHAPE {
MS_NORMAL,
MS_CROSS,
MS_CIRCLE,
MS_TURRET,
};
#define MAXMAPSHAPES (4)
enum CORRIDORTYPE {
CDT_NORMAL, // make corridors, remove deadends, add rooms, autolink
CDT_SIMPLE, // add rooms, autolink
};
typedef struct cell_s {
map_t *map; // pointer back to map
int x,y; // map coords
@ -3455,12 +3471,15 @@ typedef struct cell_s {
char *writing;
int writinglifetime;
int locked; // cannot make rooms on top of this.
// lifeform pile
struct lifeform_s *lf;
// known to player?
int known;
struct glyph_s knownglyph;
int knowntime;
int isroomwall;
// FOR CONSTRUCTION
int visited;
@ -3527,6 +3546,7 @@ typedef struct lifeform_s {
int mp,maxmp;
float stamina;
int alive;
int lastdamlf; // id of lf who just hurt us
char *lastdam;
char *killverb;
struct material_s *material;
@ -3852,6 +3872,8 @@ enum SHOPMENU {
SM_MIRACLE = -6,
// motels
SM_REST = -7,
// weapon/armour shops
SM_RESIZE = -8,
};
enum SHOPRETURN {

2
flag.c
View File

@ -240,6 +240,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
case F_RUNNING:
case F_TRAINING:
case F_AUTOCMD:
case F_PRODUCESLIGHT:
break;
case F_ASLEEP:
if (f->val[2] == NA) { // ie. sleeping, not resting
@ -972,6 +973,7 @@ void killflag(flag_t *f) {
case F_RUNNING:
case F_TRAINING:
case F_AUTOCMD:
case F_PRODUCESLIGHT:
break;
case F_ASLEEP:
if (f->val[2] != NA) { // ie. resting

73
io.c
View File

@ -5357,42 +5357,6 @@ char *makedesc_ob(object_t *o, char *retbuf) {
strncat(retbuf, buf, HUGEBUFLEN);
}
// charges remaining
if ((o->type->obclass->id == OC_WAND) || (o->type->id == OT_BATTERY)) {
if (isidentified(o)) {
int charges;
charges = getcharges(o);
if (charges) {
sprintf(buf, "It has %d charges left.\n",charges);
} else {
sprintf(buf, "It has no charges left.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
}
} else if (o->type->obclass->id == OC_GODSTONE) {
if (isidentified(o)) {
int charges,max;
getchargeinfo(o, &charges, &max);
if (charges == max) {
sprintf(buf, "It is fully charged.\n");
} else {
sprintf(buf, "It is depleted.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
}
} else if (o->type->id == OT_CREDITCARD) {
if (isidentified(o)) {
int charges;
charges = getcharges(o);
if (charges) {
sprintf(buf, "It has $%d remaining until its limit.\n",charges);
} else {
sprintf(buf, "It is maxed out.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
}
}
f = hasflag(o->flags, F_PICKLOCKS);
if (f) {
sprintf(buf, "You can use it to pick locks.\n");
@ -5506,6 +5470,43 @@ char *makedesc_ob(object_t *o, char *retbuf) {
}
} // end if isknown
// charges remaining
if ((o->type->obclass->id == OC_WAND) || (o->type->id == OT_BATTERY)) {
if (isidentified(o) || chargesknown(o)) {
int charges;
charges = getcharges(o);
if (charges) {
sprintf(buf, "It has %d charge%s left.\n",charges, (charges == 1) ? "" : "s");
} else {
sprintf(buf, "It has no charges left.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
}
} else if (o->type->obclass->id == OC_GODSTONE) {
if (isidentified(o)) {
int charges,max;
getchargeinfo(o, &charges, &max);
if (charges == max) {
sprintf(buf, "It is fully charged.\n");
} else {
sprintf(buf, "It is depleted.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
}
} else if (o->type->id == OT_CREDITCARD) {
if (isidentified(o)) {
int charges;
charges = getcharges(o);
if (charges) {
sprintf(buf, "It has $%d remaining until its limit.\n",charges);
} else {
sprintf(buf, "It is maxed out.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
}
}
// skip line
strncat(retbuf, "\n", HUGEBUFLEN);

84
lf.c
View File

@ -2290,6 +2290,11 @@ void die(lifeform_t *lf) {
flag_t *retflag[MAXCANDIDATES];
int nretflags;
cell_t *corpsecell;
lifeform_t *killer = NULL;
if (lf->lastdamlf != -1) {
killer = findlf(lf->cell->map, lf->lastdamlf);
}
if (cansee(player, lf)) {
needredraw = B_TRUE;
@ -2416,6 +2421,8 @@ void die(lifeform_t *lf) {
}
}
} else {
lifeform_t *minion[MAXCANDIDATES];
int nminions = 0;
// intelligent monsters will say something
if (!hasflag(lf->flags, F_NODEATHSPEECH)) {
if (ispetof(lf, player)) {
@ -2473,6 +2480,19 @@ void die(lifeform_t *lf) {
// mercy god doesn't like killing
//angergodmaybe(R_GODMERCY, 1, GA_MURDER);
}
// minions drop morale, and might flee
getminions(lf, minion, &nminions);
for (i = 0; i < nminions; i++) {
f = lfhasflag(minion[i], F_MORALE);
if (f) {
f->val[0] -= 10;
// might flee?
if (killer && (f->val[0] <= 0)) {
scare(minion[i], killer, PERMENANT, 10);
}
}
}
}
// determine where to drop objects
@ -4270,7 +4290,6 @@ int flee(lifeform_t *lf) {
real_getlfname(lf, lfname, B_FALSE);
// are we fleeing?
getflags(lf->flags, retflag, &nretflags, F_FLEEFROM, F_NONE);
@ -8723,9 +8742,11 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
addflag(lf->flags, F_PHOTOMEM, B_TRUE, NA, NA, NULL);
}
if (f->val[1] == PR_MASTER) {
if (!hasflagval(lf->flags, F_CANWILL, OT_S_MAPPING, NA, NA, NULL)) {
newf = addflag(lf->flags, F_CANWILL, OT_S_MAPPING, 50, 50, "pw:1;");
newf->lifetime = FROMSKILL;
}
}
} else if (id == SK_COOKING) {
if (f->val[1] == PR_ADEPT) {
if (isplayer(lf)) {
@ -9053,8 +9074,6 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) {
case RANDOM: depthmod = rnd(0,MAXDEPTH); break;
default: break;
}
// if (getrandomobofsize(targmap, buf, maxobsize)) {
if (real_getrandomob(targmap, buf, targmap->depth + depthmod, NA, maxobsize, SK_NONE, B_TRUE, OC_NONE, DT_NONE)) {
if (isshop && strstr(buf, "gold coin")) strcpy(buf, "potion of water");
o = addob(op, buf);
@ -9103,7 +9122,6 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) {
} else {
if (db) snprintf(buf2, BUFLEN, "finished startobwepsk, failed.");
}
//assert(strlen(buf) > 0);
}
} else if (id == F_STARTOBCLASS) {
if (rnd(1,100) <= val[0]) {
@ -9120,7 +9138,6 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) {
}
//obdb = B_TRUE;
//if (getrandomobwithclass(targmap, val[1], buf, val[2])) {
if (real_getrandomob(targmap, buf, getmapdifficulty(targmap) + depthmod, NA, maxobsize, SK_NONE, B_TRUE,
val[1], OC_NONE, DT_NONE)) {
if (db) snprintf(buf2, BUFLEN, "finished startobclass, success.");
@ -9130,9 +9147,8 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) {
//obdb = B_FALSE;
if (db) snprintf(buf2, BUFLEN, "finished startobclass. couldnt find an object.");
}
//if (strlen(buf) <= 0);
}
}
} // end what is fid?
// TODO: maybe add object to temp cell, then MOVE it to the destination pile.
// this will make sure the right checks happen.
@ -9162,9 +9178,15 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) {
// not worth any points
addflag(o->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL);
}
} else if (isshop) {
flag_t *f2;
// all flags are known
for (f2 = o->flags->first ; f2; f2 = f2->next) {
f2->known = B_TRUE;
}
}
}
} // end if o
} // end foreach container flag
// now remove startob flags so we don't get them again!
@ -9216,14 +9238,36 @@ void givestartskills(lifeform_t *lf, flagpile_t *fp) {
}
int gotosleep(lifeform_t *lf, int onpurpose) {
char lightid[BUFLEN];
strcpy(lightid, "");
if (lfhasflag(lf, F_CAFFEINATED)) {
if (isplayer(lf)) {
msg("Your caffeine high prevents you from sleeping.");
}
return B_TRUE;
}
if (onpurpose) taketime(lf, getactspeed(lf));
addflag(lf->flags, F_ASLEEP, B_TRUE, lfhasflag(lf, F_MEDITATES) ? ST_MEDITATING : ST_ASLEEP, onpurpose ? B_TRUE : NA, NULL);
if (onpurpose) {
taketime(lf, getactspeed(lf));
if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_GTAVERAGE) {
object_t *o;
// turn off light sources first
for (o = lf->pack->first ; o ; o = o->next) {
if (hasflag(o->flags, F_LIGHTSOURCE) && hasflag(o->flags, F_ACTIVATED)) {
if (!strlen(lightid)) {
// first one.
if (isplayer(lf)) {
char ch;
ch = askchar("Turn off your light sources before resting?", "yn","y", B_TRUE, B_FALSE);
if (ch != 'y') break;
}
sprintf(lightid, "%ld", o->id);
}
turnoff(lf, o);
}
}
}
}
addflag(lf->flags, F_ASLEEP, B_TRUE, lfhasflag(lf, F_MEDITATES) ? ST_MEDITATING : ST_ASLEEP, onpurpose ? B_TRUE : NA, lightid);
return B_FALSE;
}
@ -10908,6 +10952,7 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) {
a->alive = B_TRUE;
a->lastdam = strdup("nothing");
a->lastdamtype = DT_NONE;
a->lastdamlf = -1;
a->damlastturn = 0;
a->mplastturn = 0;
a->stamlastturn = 0;
@ -12305,6 +12350,12 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
// fill in lastdam...
lf->lastdamtype = damtype;
if (fromlf) {
lf->lastdamlf = fromlf->id;
} else {
lf->lastdamlf = -1;
}
// if they died
if (lf->hp <= 0) {
//if (!fromlf || (fromlf == player)) {
@ -18167,7 +18218,18 @@ int rest(lifeform_t *lf, int onpurpose) {
killflagsofid(lf->flags, F_TRAINING);
rf = isresting(lf);
if (rf) killflag(rf);
if (rf) {
// since you've woken up normally, turn your light source back on.
if (strlen(rf->text)) {
object_t *light;
light = hasobid(lf->pack, atol(rf->text));
if (light) {
turnon(lf, light);
}
}
// kill sleeping flag
killflag(rf);
}
wantclearmsg = B_FALSE;
}
}

341
map.c
View File

@ -69,6 +69,7 @@ cell_t *addcell(map_t *m, int x, int y) {
setcelltype(cell, cell->habitat->solidcelltype);
cell->lf = NULL;
cell->room = NULL;
cell->locked = B_FALSE;
cell->lit = L_NOTLIT;
cell->origlit = L_NOTLIT;
cell->littimer = 0;
@ -81,6 +82,7 @@ cell_t *addcell(map_t *m, int x, int y) {
cell->knownglyph.colour = C_GREY;
cell->visited = B_FALSE;
cell->filled = B_FALSE;
cell->isroomwall = D_NONE;
return cell;
}
@ -1536,7 +1538,8 @@ object_t *gettopobject(cell_t *where, int forglyph) {
for (o = where->obpile->first ; o ; o = o->next) {
flag_t *f;
// ignore hidden traps, but not secret doors
if (hasflag(o->flags, F_SECRET) && !isdoor(o, NULL)) {
if (isdeadob(o)) {
} else if (hasflag(o->flags, F_SECRET) && !isdoor(o, NULL)) {
} else if (hasflag(o->flags, F_INVISOB)) {
} else if (hasflag(o->flags, F_TRAIL) && !canseeob(player, o)) {
} else if (forglyph && hasflag(o->flags, F_NOGLYPH)) {
@ -1560,7 +1563,8 @@ object_t *gettopobject(cell_t *where, int forglyph) {
// appear first.
for (o = where->obpile->last ; o ; o = o->prev) {
if (o->type->obclass->id == sortorder[c]) {
if (hasflag(o->flags, F_SECRET)) {
if (isdeadob(o)) {
} else if (hasflag(o->flags, F_SECRET)) {
} else if (hasflag(o->flags, F_INVISOB)) {
} else if (hasflag(o->flags, F_TRAIL) && !canseeob(player, o)) {
} else if (forglyph && hasflag(o->flags, F_NOGLYPH)) {
@ -1719,6 +1723,11 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int
if (cell->room) {
valid = B_FALSE;
}
// - overlap a 'locked' cell
if (cell->locked) {
valid = B_FALSE;
}
// is this cell adjacent to an empty cell and not a
// corner (ie. a valid door location)
@ -2074,13 +2083,14 @@ void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *
void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) {
int wantrooms = B_TRUE;
int d;
int x,y;
int x,y,w,h;
enum MAPSHAPE shape = MS_NORMAL;
int i;
int done,unused;
int dir;
int lastdir;
int numrooms = 0;
cell_t *cell, *c;
cell_t *c,*centre;
//object_t *o;
int db = B_TRUE;
int digdb = B_FALSE;
@ -2091,10 +2101,12 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
int looppct = DEF_LOOPPCT;
int minrooms = MINROOMS;
int maxrooms = MAXROOMS;
enum CORRIDORTYPE corridortype = CDT_NORMAL;
int moved = 0;
enum CELLTYPE emptycell,solidcell;
char buf[BUFLEN];
// fill entire maze with walls
for (y = 0; y < map->h; y++) {
@ -2103,6 +2115,110 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
}
}
// select dungeon shape.
if (onein(3)) {
shape = rnd(0,MAXMAPSHAPES-1);
} else {
shape = MS_NORMAL;
}
switch (shape) {
case MS_NORMAL:// normal
break;
case MS_CROSS: // cross
// ## ##
// ## ##
//
// ## ##
// ## ##
for (y = 0; y < map->h/3; y++) {
for (x = 0; x < map->w/3; x++) {
c = getcellat(map, x, y); c->locked = B_TRUE;
}
for (x = map->w - (map->w/3); x < map->w; x++) {
c = getcellat(map, x, y); c->locked = B_TRUE;
}
}
for (y = map->h-(map->h/3); y < map->h; y++) {
for (x = 0; x < map->w/3; x++) {
c = getcellat(map, x, y); c->locked = B_TRUE;
}
for (x = map->w - (map->w/3); x < map->w; x++) {
c = getcellat(map, x, y); c->locked = B_TRUE;
}
}
break;
case MS_TURRET: // kind of a reverse cross
// ##########
// # #
// # ## #
// # ###### #
// # ###### #
// # ###### #
// # ## #
// # #
// ##########
for (y = (map->h/4); y < map->h/3; y++) {
for (x = map->w/3; x < map->w - (map->w/3); x++) {
c = getcellat(map, x, y); c->locked = B_TRUE;
}
}
for (y = map->h/3; y < map->h - (map->h/3); y++) {
for (x = map->w/4; x < map->w - (map->w/4); x++) {
c = getcellat(map, x, y); c->locked = B_TRUE;
}
}
for (y = map->h-(map->h/3); y < map->h - (map->h/4); y++) {
for (x = map->w/3; x < map->w - (map->w/3); x++) {
c = getcellat(map, x, y); c->locked = B_TRUE;
}
}
break;
case MS_CIRCLE: // circle / ellipse
centre = getcellat(map, map->w/2, map->h/2);
w = map->w - 5;
h = map->h - 4;
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
float val;
val = (pow(x - centre->x, 2) / pow(w/2, 2)) +
(pow(y - centre->y, 2) / pow(h/2, 2));
if (val > 1) {
c = getcellat(map, x, y);
c->locked = B_TRUE;
}
}
}
break;
}
addflag(map->flags, F_MAPSHAPE, shape, NA, NA, NULL);
for (y = 0; y < map->h; y++) {
strcpy(buf, "");
for (x = 0; x < map->w; x++) {
c = getcellat(map, x, y);
if (c->locked) {
c->visited = B_TRUE;
}
if (c->locked) {
strcat(buf, "X");
} else {
strcat(buf, " ");
}
}
dblog("%s",buf);
}
// randomise dungeon parameters
turnpct += (rnd(0,40)-20); // (-20 to +20)%
sparseness += (rnd(0,20)-10); // -10 to +10
looppct -= (rnd(0,10)); // subtrace 0 - 10
if (shape == MS_NORMAL) {
if (onein(2)) {
corridortype = CDT_SIMPLE;
}
}
// is the map lit?
if (depth <= 5) {
@ -2122,10 +2238,11 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
solidcell = map->habitat->solidcelltype;
// pick initial random spot
cell = getrandomcell(map);
setcelltype(cell, emptycell);
cell->visited = B_TRUE;
if (digdb) printf("- Starting (%d,%d)\n",cell->x, cell->y);
if (corridortype == CDT_NORMAL) {
c = getrandomcell(map);
setcelltype(c, emptycell);
c->visited = B_TRUE;
if (digdb) printf("- Starting (%d,%d)\n",c->x, c->y);
lastdir = D_UNKNOWN;
done = B_FALSE;
@ -2135,11 +2252,11 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
while (!done) {
// get random direction based on turnpct
dir = D_NONE;
while (dir == D_NONE) {
while ((dir == D_NONE) && !done) {
int badcount;
if (digdb) printf("- At (%d,%d), moved %d, finding new direction...\n",cell->x, cell->y, moved);
if (digdb) printf("- At (%d,%d), moved %d, finding new direction...\n",c->x, c->y, moved);
dir = getnewdigdir(cell, lastdir, (moved < 2) ? 0 : turnpct, &moved);
dir = getnewdigdir(c, lastdir, (moved < 2) ? 0 : turnpct, &moved);
badcount = 0;
while (dir == D_NONE) {
@ -2151,32 +2268,32 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
}
// pick new EMPTY random spot
cell = getrandomcell(map);
while (!isempty(cell)) {
cell = getrandomcell(map);
c = getrandomcell(map);
while (!isempty(c)) {
c = getrandomcell(map);
}
if (digdb) printf("--- Couldn't find a valid direction. Jumped to (%d,%d).\n",cell->x, cell->y);
if (digdb) printf("--- Couldn't find a valid direction. Jumped to (%d,%d).\n",c->x, c->y);
// pick a new random dir
dir = getnewdigdir(cell, lastdir, turnpct, &moved);
dir = getnewdigdir(c, lastdir, turnpct, &moved);
}
if (!done) {
if (digdb) printf("- Digging %s from (%d,%d).\n",getdirname(dir),cell->x, cell->y);
if (digdb) printf("- Digging %s from (%d,%d).\n",getdirname(dir),c->x, c->y);
}
}
if (!done) {
// move to adjacent cell in the given direction
cell = getcellindir(cell, dir);
if (digdb) printf("- Now at (%d,%d)\n",cell->x, cell->y);
c = getcellindir(c, dir);
if (digdb) printf("- Now at (%d,%d)\n",c->x, c->y);
moved++;
// blank it
setcelltype(cell,emptycell);
cell->visited = B_TRUE;
setcelltype(c,emptycell);
c->visited = B_TRUE;
// mark surrounding cells as visited
for (d = DC_N; d < MAXDIR_COMPASS; d++) {
cell_t *thiscell;
thiscell = getcellindir(cell, d);
thiscell = getcellindir(c, d);
if (thiscell) {
if (digdb) printf("* Marking surrounding cell in dir %d (%d,%d) as visited.\n",d, thiscell->x, thiscell->y);
thiscell->visited = B_TRUE;
@ -2214,8 +2331,8 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
// introduce loops
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
cell = getcellat(map, x, y);
if (!cell->type->solid && countcellexits(cell, DT_ORTH) == 1) {
c = getcellat(map, x, y);
if (!c->type->solid && countcellexits(c, DT_ORTH) == 1) {
// dead end - maybe make loop from here
if (rnd(1,100) <= looppct) {
int connected = B_FALSE;
@ -2223,7 +2340,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
int dir;
// pick a random directory
dir = getnewdigdir(cell, D_UNKNOWN,100, &moved);
dir = getnewdigdir(c, D_UNKNOWN,100, &moved);
if (dir == D_NONE) {
// can't make a loop from here.
@ -2232,7 +2349,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
int tries = 0;
// if we go this dir, will we hit a
// corridor?
while (!isloopdirok(cell, dir)) {
while (!isloopdirok(c, dir)) {
tries++;
// tried every direction?
if (tries >= MAXDIR_ORTH) {
@ -2251,7 +2368,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
while (!connected) {
cell_t *newcell;
// find adjacent cell in the given direction
newcell = getcellindir(cell, dir);
newcell = getcellindir(c, dir);
if (!newcell) {
connected = B_TRUE;
} else {
@ -2263,7 +2380,8 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
setcelltype(newcell, emptycell);
newcell->visited = B_TRUE;
}
cell = newcell;
c = newcell;
}
}
}
}
@ -2301,8 +2419,10 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
}
}
if (corridortype == CDT_NORMAL) {
// now clear up dead ends again.
remove_deadends(map, sparseness);
}
// link up room exits
for (i = 0; i < map->nrooms; i++) {
@ -2339,11 +2459,10 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
if (db) dblog("--> Will add %d pillars",numpillars);
for (n = 0; n < numpillars;n++ ) {
//dblog("----> Adding pillar %d/%d",n+1,numpillars);
cell_t *c;
c = getrandomroomcell(map, i);
if (c && isempty(c) && !countobs(c->obpile, B_TRUE)) {
setcelltype(cell, CT_WALL);
setcelltype(c, CT_WALL);
}
}
}
@ -2362,7 +2481,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
for (n = 0 ; n < numobs; n++) {
int ntries = 0;
int nmonsters = 0;
cell_t *c;
done = B_FALSE;
while (!done) {
c = getrandomroomcell(map, i);
@ -3556,6 +3674,8 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r
addvaultcellcontents(cell, v, x-minx,y-miny, rotation);
}
}
markroomwalls(map, thisroom);
}
if (retw) *retw = w;
@ -3687,7 +3807,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
if ((roomid >= 0) && getroomid(c) == roomid) { // same room
//if (wantfilled && c->type->solid) {
if (c->type->solid) {
// EXCEPTION:
// This is an exception:
// if startcell is a cell _inside_ the room as opposed to
// a cell inside the room's walls.
// in this case, we ARE allowed to travel through the room's walls.
@ -3698,6 +3818,13 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
if (db) dblog(" going %s hits same room. invalid.", getdirname(d));
break;
}
} else if (isroom(c) && (getroomid(c) != roomid) && (c->isroomwall != diropposite(d))) {
// cell is in a different room, but not the correct edge
// mark dir as invalid
dist[d] = 999;
sameroom[d] = B_FALSE;
if (db) dblog(" going %s hits wrong wall of different room. invalid.", getdirname(d));
break;
} else if (cellwalkable(NULL, c, NULL)) {
if (!wantfilled || c->filled) {
// walkable and not in this vault. finished.
@ -3715,8 +3842,11 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
for (n = 0; n <= 1; n++) {
pcell = getcellindir(c, perpdir[n]);
if (pcell) {
if (((roomid == -1 ) || (getroomid(pcell) != roomid)) &&
cellwalkable(NULL, pcell, NULL)) {
int proomid;
proomid = getroomid(pcell);
if (((roomid == -1 ) || (proomid != roomid)) && cellwalkable(NULL, pcell, NULL)) {
if ((proomid >= 0) && (pcell->isroomwall != diropposite(perpdir[n]))) {
} else {
if (!wantfilled || c->filled) {
// finished.
directendcell[d] = c;
@ -3727,6 +3857,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
}
}
}
}
// check next cell
c = getcellindir(c, d); // getting the same cell!
}
@ -3797,17 +3928,15 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
int n;
cell_t *c2;
startdist++;
// check left/right from this door for rooms
// check left/right from this cell for rooms
for (n = 0; n <= 1; n++) {
int turndist = 0;
c2 = getcellindir(c, perpdir[n]);
while (c2) {
int gotsolution = B_FALSE;
turndist++;
perpcell[nperpcells] = c2; // this will be used if we need to make 2 turns
perpturncell1[nperpcells] = c;
perpturndir1[nperpcells] = perpdir[n];
@ -3825,6 +3954,13 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
if (db) dblog(" Got to an empty cell here.");
gotsolution = B_TRUE;
}
} else if (isroom(c2) && (c2->isroomwall != diropposite(perpdir[n]))) {
// wrong wall of room
// mark dir as invalid
dist[d] = 999;
sameroom[d] = B_FALSE;
if (db) dblog(" going %s hits wrong wall of different room. invalid.", getdirname(d));
break;
} else if (turndist > 1) {
// check l/r too
int perpdir2[2],nn;
@ -3834,8 +3970,12 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
for (nn = 0; nn <= 1; nn++) {
pcell = getcellindir(c2, perpdir2[nn]);
if (pcell) {
if ( ((roomid == -1) || (getroomid(pcell) != roomid)) &&
int proomid;
proomid = getroomid(pcell);
if ( ((roomid == -1) || (proomid != roomid)) &&
cellwalkable(NULL, pcell, NULL)) {
if ((proomid >= 0) && (pcell->isroomwall != diropposite(perpdir2[n]))) {
} else {
if (!wantfilled || pcell->filled) {
// finished.
if (db) dblog(" Got to an empty cell next to us.");
@ -3846,6 +3986,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
}
}
}
}
if (gotsolution) {
if (db) dblog(" Solution found: Walk %d %s, then %d %s.",
startdist, getdirname(startdir),
@ -3919,6 +4060,13 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
if (db) dblog(" Got to an empty cell here.");
gotsolution = B_TRUE;
}
} else if (isroom(c2) && (c2->isroomwall != diropposite(dir3[n]))) {
// wrong wall of room
// mark dir as invalid
dist[d] = 999;
sameroom[d] = B_FALSE;
if (db) dblog(" going %s hits wrong wall of different room. invalid.", getdirname(d));
break;
} else if (turndist > 1) {
// check l/r too
int perpdir2[2],nn;
@ -3928,8 +4076,13 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
for (nn = 0; nn <= 1; nn++) {
pcell = getcellindir(c2, perpdir2[nn]);
if (pcell) {
if ( ((roomid == -1) || (getroomid(pcell) != roomid)) &&
int proomid;
proomid = getroomid(pcell);
if ( ((roomid == -1) || (proomid != roomid)) &&
cellwalkable(NULL, pcell, NULL)) {
if ((proomid >= 0) && (pcell->isroomwall != diropposite(perpdir2[nn]))) {
// different room and hits wrong wall.
} else {
if (!wantfilled || pcell->filled) {
// finished.
if (db) dblog(" Got to an empty cell next to us.");
@ -3940,6 +4093,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
}
}
}
}
if (gotsolution) {
turncell = perpturncell1[i];
turndir = perpturndir1[i];
@ -3959,7 +4113,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
if (turncell2) break;
} // end foreach perpcell
// TODO: if we find a solution, fill in turncell2 and make path.
// if we find a solution, fill in turncell2 and make path.
if (turncell2) {
if (db) dblog(" Twoturn solution found: Walk %s, then %s, then %s.",
getdirname(startdir), getdirname(turndir), getdirname(turndir2));
@ -4287,6 +4441,7 @@ void createroom(map_t *map, int roomid, int x1, int y1, int x2, int y2, int forc
}
}
}
markroomwalls(map, thisroom);
}
// room w/h are returned in *w and *h if given.
@ -4588,13 +4743,14 @@ void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *c
void finalisemap(map_t *map, object_t *entryob) {
enum OBTYPE upstairtype, downstairtype;
int i,d;
int i,d,x,y;
int linkedentry = B_FALSE;
cell_t *c;
object_t *o;
// add staircases.
// first dungeon level has 1 up stairs, 3 down.
// subsequent levels always have 3 up and down stairs
object_t *o,*nexto;
// make sure this map has sufficient up/down staircases as defined by its
// region type.
//
// first dungeon level is a special case. it has 1 up stairs, 3 down.
switch (map->habitat->id) {
case H_CAVE:
upstairtype = OT_TUNNELUP;
@ -4686,6 +4842,37 @@ void finalisemap(map_t *map, object_t *entryob) {
}
}
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
c = getcellat(map, x, y);
for (o = c->obpile->first ; o ; o = nexto) {
nexto = o->next;
// doors which go nowhere?
if (isdoor(o, NULL)) {
int dir, ok = B_FALSE;
cell_t *c2;
// check all directions for a cell which isn't
// part of this room.
for (dir = DC_N; dir <= DC_NW; dir++) {
c2 = getcellindir(c, dir);
if (c2 && cellwalkable(NULL, c2, NULL) && getroomid(c2) != getroomid(c)) {
ok = B_TRUE;
break;
}
}
if (!ok) {
killob(o);
continue;
}
}
// unlinked stairs? ie ones added from vaults. if so, link them.
if (hasflag(o->flags, F_CLIMBABLE) && !hasflag(o->flags, F_MAPLINK)) {
linkstairs(o, NULL);
}
}
}
}
}
celltype_t *findcelltype(enum CELLTYPE cid) {
@ -5488,8 +5675,8 @@ cell_t *getstairdestination(object_t *o, int *madenewmap) {
// is there already a level of the correct depth?
newmap = findregionmap(newregion->id, newdepth);
if (newmap) {
dblog("ERROR - unlinked stairs!\n");
msg("ERROR - unlinked stairs!\n");
dblog("ERROR - unlinked stairs! should have been linked during map creation.\n");
msg("ERROR - unlinked stairs! should have been linked during map creation.\n");
return NULL;
} else {
// generate a new map! this will fill in the destination of our stairs
@ -5918,9 +6105,12 @@ int isloopdirok(cell_t *cell, int dir) {
}
int isnewcellok(cell_t *cell, char *err) {
if ( !cell) { // can't go that way
if ( !cell ) { // can't go that way
if (err) snprintf(err, BUFLEN,"goes off the map.");
return B_FALSE;
} else if ( cell->locked ) { // locked
if (err) snprintf(err, BUFLEN,"locked.");
return B_FALSE;
} else if ( !cell->type->solid) { // already an empty space there
if (err) snprintf(err, BUFLEN,"goes to an empty space (%d,%d)",cell->x,cell->y);
return B_FALSE;
@ -6071,7 +6261,7 @@ object_t *linkportal(object_t *srcportal, int wantdepth) {
}
// link the staircase 'o' to a free one in adjacent maps.
// o2 is optional. if not probided, we will try to find
// o2 is optional. if o2 isn't provided, we will try to find
// something to link to ourself.
// returns TRUE if it failed because othermap doesn't exist.
int linkstairs(object_t *o, object_t *o2) {
@ -6276,6 +6466,59 @@ void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong) {
}
}
void markroomwalls(map_t *m, room_t *r) {
int x,y;
cell_t *c,*c2;
// N edge
for (x = r->x1+1; x <= r->x2-1; x++) {
for (y = r->y1; y <= r->y2; y++) {
c = getcellat(m, x, y);
if (c->type->solid) {
c2 = getcellindir(c, DC_S);
if (c2 && !c2->type->solid) {
c->isroomwall = DC_N;
}
}
}
}
// W edge
for (y = r->y1+1; y <= r->y2-1; y++) {
for (x = r->x2; x >= r->x1; x--) {
c = getcellat(m, x, y);
if (c->type->solid) {
c2 = getcellindir(c, DC_W);
if (c2 && !c2->type->solid) {
c->isroomwall = DC_E;
}
}
}
}
// S edge
for (x = r->x1+1; x <= r->x2-1; x++) {
for (y = r->y2; y >= r->y1; y--) {
c = getcellat(m, x, y);
if (c->type->solid) {
c2 = getcellindir(c, DC_N);
if (c2 && !c2->type->solid) {
c->isroomwall = DC_S;
}
}
}
}
// W edge
for (y = r->y1+1; y <= r->y2-1; y++) {
for (x = r->x1; x <= r->x2; x++) {
c = getcellat(m, x, y);
if (c->type->solid) {
c2 = getcellindir(c, DC_E);
if (c2 && !c2->type->solid) {
c->isroomwall = DC_W;
}
}
}
}
}
void mapentereffects(map_t *m) {
int i;
cell_t *c;

1
map.h
View File

@ -145,6 +145,7 @@ int linkstairs(object_t *o, object_t *o2);
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 markroomwalls(map_t *m, room_t *r);
void mapentereffects(map_t *m);
void moveobtoclearcell(object_t *o);
enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob);

View File

@ -1636,7 +1636,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
}
break;
case OM_MASTERWORK:
if (isweapon(o) || isarmour(o)) {
if (isweapon(o) || isarmour(o) || isdoor(o, NULL)) {
flag_t *f;
f = hasflag(o->flags, F_OBHP);
if (f) {
@ -1646,7 +1646,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
}
break;
case OM_SHODDY:
if (isweapon(o) || isarmour(o)) {
if (isweapon(o) || isarmour(o) || isdoor(o, NULL)) {
flag_t *f;
f = hasflag(o->flags, F_OBHP);
if (f) {
@ -4504,7 +4504,13 @@ char *getobextrainfo(object_t *o, char *buf) {
// charges
f = hasflag(o->flags, F_CHARGES);
if (f && f->known) {
if (f) {
int flagknown = B_FALSE;
if (f->known) {
flagknown = B_TRUE;
} else if (ismagical(o) && (getskill(player, SK_CHANNELING) >= PR_MASTER)) {
flagknown = B_TRUE;
}
if (!hasflag(o->flags, F_DONTSHOWCHARGES)) {
char chargestr[BUFLEN];
if (o->type->obclass->id == OC_GODSTONE) {
@ -4991,7 +4997,11 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
obmod_t *om;
for (om = firstobmod ; om; om = om->next) {
if (hasobmod(o, om)) {
strcat(localbuf, om->prefix);
char *p;
p = getobmodprefix(o, om);
if (p && strlen(p)) {
strcat(localbuf, p);
}
}
}
}
@ -8275,17 +8285,55 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
// objects with charges...
if (hasflag(o->flags, F_OPERUSECHARGE)) { // operating toggles on/off
if (usecharge(o) == -1) {
if (isplayer(lf)) {
nothinghappens();
int chargesleft;
chargesleft = usecharge(o);
f = hasflag(o->flags, F_CHARGES); // should always be true!
if (chargesleft == -1) {
if (f) f->known = B_TRUE;
msg("Nothing happens - this item is empty.");
// you know it's out
f = hasflag(o->flags, F_CHARGES);
f->known = B_TRUE;
taketime(lf, getactspeed(lf));
return B_FALSE;
} else if (ismagical(o) && (o->pile->owner == lf)) {
enum SKILLLEVEL slev;
// depending on your channeling skill, you might
// find out that it is running low.
slev = getskill(lf, SK_CHANNELING);
if (slev == PR_EXPERT) {
if (f) f->known = B_TRUE;
}
if (slev && (chargesleft == 0)) {
if (f) f->known = B_TRUE;
msg("Your %s is now empty.", noprefix(obname));
} else if (slev && chargesknown(o)) {
if (f) f->known = B_TRUE;
if (chargesleft == 1) {
msg("Your %s only has one charge remaining.", noprefix(obname));
} else {
msg("Your %s now has %d charges remaining.", noprefix(obname), chargesleft);
}
} else {
switch (slev) {
case PR_INEPT:
break;
case PR_NOVICE: // notify when 1-3 charges left
if (chargesleft <= 3) {
msg("Your %s is running low on charges.", noprefix(obname));
}
break;
case PR_BEGINNER: // charges known at 1, notify at 1-3
if (chargesleft <= 3) {
msg("Your %s is running low on charges.", noprefix(obname));
}
break;
default:
break;
}
} // end if slev& chargesleft is 0
} // end if chargesleft== -1 / ismagical
} // end if isplayer
} // end if hasflag operusecharge
// TODO: change to be based on item type
// TODO: move this to the end in case 'operate' fails
@ -10616,6 +10664,16 @@ int removeob(object_t *o,int howmany) {
return rv;
}
void resizeobject(object_t *o, enum LFSIZE wantsize) {
flag_t *f;
f = hasflag(o->flags, F_ARMOURSIZE);
if (f) {
f->val[0] = wantsize;
} else {
addflag(o->flags, F_ARMOURSIZE, wantsize, NA, NA, NULL);
}
}
void rrtorarity(enum RARITY r, int *minr, int *maxr) {
switch (r) {
case RR_UNIQUE:
@ -12815,7 +12873,6 @@ void turnon(lifeform_t *lf, object_t *o) {
held = B_TRUE;
}
f = hasflag(o->flags, F_ACTIVATED);
if (f) {
// already on
@ -13203,6 +13260,28 @@ int getcritchance(lifeform_t *lf, object_t *o, lifeform_t *victim) {
return chance;
}
int chargesknown(object_t *o) {
flag_t *f;
int cutoff = -2;
f = hasflag(o->flags, F_CHARGES);
if (f) {
if (f->known) return B_TRUE;
switch (getskill(player, SK_CHANNELING)) {
case PR_BEGINNER: cutoff = 1; break;
case PR_ADEPT: cutoff = 3; break;
case PR_SKILLED: cutoff = 6; break;
case PR_EXPERT: break; // f->known will be set after use.
case PR_MASTER: cutoff = 9999; break;
default: break;
}
}
if (f->val[0] <= cutoff) {
return B_TRUE;
}
return B_FALSE;
}
int getcritprotection(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_CRITPROTECTION);

View File

@ -34,6 +34,7 @@ int canseeob(lifeform_t *lf, object_t *o);
object_t *canstackob(obpile_t *op, object_t *match);
object_t *canstacknewot(obpile_t *op, objecttype_t *match);
int changemat(object_t *o, enum MATERIAL mat);
int chargesknown(object_t *o);
int getcritprotection(object_t *o);
int checkobnames(char *haystack, char *needle);
void colourmatchob(object_t *o, lifeform_t *lf);
@ -249,6 +250,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 resizeobject(object_t *o, enum LFSIZE wantsize);
void rrtorarity(enum RARITY r, int *minr, int *maxr);
void setblessed(object_t *o, enum BLESSTYPE wantbless);
int sethiddenname(objecttype_t *o, char *text);

8
save.c
View File

@ -382,8 +382,8 @@ map_t *loadmap(char *basefile) {
c = addcell(m, x, y);
// cell info
fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
&roomid, &celltypeid, &c->known, &c->knowntime, &c->knownglyph.ch, &c->knownglyph.colour, &c->visited, &c->lit, &c->origlit, &c->littimer,&temphab);
fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
&roomid, &celltypeid, &c->known, &c->knowntime, &c->knownglyph.ch, &c->knownglyph.colour, &c->visited, &c->lit, &c->origlit, &c->littimer,&c->locked, &temphab, &c->isroomwall);
c->habitat = findhabitat(temphab);
c->room = findroom(m, roomid);
@ -948,8 +948,8 @@ int savemap(map_t *m) {
cell_t *c;
c = getcellat(m, x, y);
// cell info
fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
c->room ? c->room->id : -1, c->type->id, c->known, c->knowntime, c->knownglyph.ch, c->knownglyph.colour, c->visited,c->lit,c->origlit,c->littimer,c->habitat->id );
fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
c->room ? c->room->id : -1, c->type->id, c->known, c->knowntime, c->knownglyph.ch, c->knownglyph.colour, c->visited,c->lit,c->origlit,c->littimer,c->locked, c->habitat->id, c->isroomwall );
// cell objects
for (o = c->obpile->first ; o ; o = o->next) {
fprintf(f, "ob:%ld\n",o->id);

55
shops.c
View File

@ -21,6 +21,7 @@
#define DEF_REMCURSECOST 60
#define DEF_BLESSCOST 50
#define DEF_SURCHARGE 15
#define DEF_RESIZECOST 80
extern enum GAMEMODE gamemode;
extern prompt_t prompt;
@ -158,6 +159,9 @@ void shop(lifeform_t *lf, object_t *vm) {
} else if (curmenu == SM_REST) {
shopfunc = shoprest;
shoparg = &ndonated;
} else if (curmenu == SM_RESIZE) {
shopfunc = shopresize;
shoparg = &ndonated;
}
if (shopfunc) {
@ -747,6 +751,57 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top
return SR_CONTINUE;
}
enum SHOPRETURN shopresize(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) {
object_t *o;
char ch,buf[BUFLEN];
int y;
int resizecost;
y = starty;
resizecost = applyshoppricemod(pctof(75, DEF_RESIZECOST), lf);
mvwprintw(mainwin, y, 0, "For just $%d per item, we can resize weapons or armour to fit you.", resizecost); y ++;
mvwprintw(mainwin, y, 0, "(item quality will not be affected)"); y += 2;
if (countmoney(player->pack) < resizecost) {
msg("Sadly, you cannot afford the resizing fee.", resizecost);
getch();
return SR_BACK;
} else {
mvwprintw(mainwin, y, 0, "Pay to resize an item (you have $%d) [yn]? ", countmoney(lf->pack));
}
ch = getch();
if (ch != 'y') {
return SR_BACK;
}
// ask which object
sprintf(buf, "Resize which object (you have $%d)?", countmoney(lf->pack));
initprompt(&prompt, buf);
for (o = player->pack->first ; o ; o = o->next) {
if (hasflag(o->flags, F_MULTISIZE) && !armourfits(player, o, NULL)) {
char costbuf[BUFLEN];
getobname(o, buf, o->amt);
sprintf(costbuf, "%-60s($%d)", buf, resizecost);
addchoice(&prompt, o->letter, costbuf, costbuf, o, NULL);
}
}
addchoice(&prompt, '-', "(nothing)", NULL, NULL, NULL);
ch = getchoice(&prompt);
o = (object_t *)prompt.result;
if (o) {
msg("You hand over $%d.", resizecost); more();
givemoney(player, NULL, resizecost);
resizeobject(o, getlfsize(player)); // always go to player's size
getobname(o, buf, 1);
msgnocap("%c - %s", o->letter, buf);
more();
}
return SR_CONTINUE;
}
enum SHOPRETURN shoprest(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) {
char ch,obid[BUFLENSMALL],buf[BUFLEN];
int y,i;

View File

@ -9,5 +9,6 @@ enum SHOPRETURN shopdonate(lifeform_t *lf, object_t *vm, int starty, char *topte
enum SHOPRETURN shopdetectcurse(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased);
enum SHOPRETURN shopmiracle(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased);
enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased);
enum SHOPRETURN shopresize(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased);
enum SHOPRETURN shoprest(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased);

View File

@ -1613,12 +1613,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
// resize it!
f = hasflag(o->flags, F_ARMOURSIZE);
if (f) {
f->val[0] = wantsize;
} else {
addflag(o->flags, F_ARMOURSIZE, wantsize, NA, NA, NULL);
}
resizeobject(o, wantsize);
f = hasflag(o->flags, F_OBHP);
if (f) {

100
text.c
View File

@ -18,6 +18,8 @@ extern long curtime;
extern lifeform_t *player;
extern enum GAMEMODE gamemode;
int needan(char *text) {
if (isvowel(tolower(text[0]))) {
return B_TRUE;
@ -360,7 +362,7 @@ int getaccuracynum(int accpct) {
// returns a const char *
char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp) {
float pct;
//float pct;
enum LFSIZE ownersize = SZ_HUMAN;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
@ -369,7 +371,11 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
ownersize = getlfsize(lf);
}
pct = (int)(((float) dam / (float) maxhp) * 100.0);
//pct = (int)(((float) dam / (float) maxhp) * 100.0);
// base verb on amount of damage, not percentage of target.
// reasoning: just because a monster has lots of hp, doesn't mean
// you can only "scratch" it rather than "slice" it.
//pct = (int)(((float) dam / 50.0) * 100.0);
if (wep) {
int i;
@ -380,15 +386,15 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
if ((f->val[0] == NA) && (f->val[1] == NA)) {
return f->text;
} else if (f->val[0]) {
if (pct >= f->val[0]) {
if (dam >= f->val[0]) {
if (f->val[1] == NA) {
return f->text;
} else if (pct <= f->val[1]) {
} else if (dam <= f->val[1]) {
return f->text;
}
}
} else if (f->val[1]) {
if (pct <= f->val[1]) {
if (dam <= f->val[1]) {
return f->text;
}
}
@ -398,47 +404,49 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
if (damtype == DT_ACID) {
return "burn";
} else if (damtype == DT_BASH) {
if (pct <= 5) {
if (dam <= 2) {
return "whack";
} else if (pct <= 15) {
} else if (dam <= 6) {
if (onein(2)) {
return "hit";
} else {
return "bash";
}
} else if (pct <= 25) {
} else if (dam <= 12) {
return "pummel";
} else if (pct <= 35) {
} else if (dam <= 18) {
if (onein(2)) {
return "slam";
} else {
return "clobber";
}
}
} else if (damtype == DT_BITE) {
if (lf && (ownersize <= SZ_SMALL)) {
if (pct <= 5) {
if (dam <= 2) {
return "nip";
} else {
return "bite";
}
} else {
if (pct <= 5) {
if (dam <= 4) {
return "gnaw";
} else if (pct <= 30) {
} else if (dam <= 8) {
return "bite";
} else {
return "savage";
}
}
} else if (damtype == DT_CHOP) {
if (pct <= 5) {
if (dam <= 4) {
return "chop";
} else if (pct <= 15) {
} else if (dam <= 8) {
return "hack";
} else {
return "cleave";
}
} else if (damtype == DT_COLD) {
if (pct <= 10) {
if (dam <= 4) {
return "chill";
} else {
return "freeze";
@ -446,23 +454,25 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
} else if (damtype == DT_CRUSH) {
return "crush";
} else if (damtype == DT_ELECTRIC) {
if (pct <= 5) {
if (dam <= 2) {
return "zap";
} else if (pct <= 15) {
} else if (dam <= 6) {
return "jolt";
} else if (pct <= 20) {
} else if (dam <= 12) {
return "shock";
} else if (pct <= 30) {
} else if (dam <= 18) {
return "electrify";
} else {
return "electrocute";
}
} else if ((damtype == DT_FIRE) || (damtype == DT_HEAT)) {
if (pct <= 5) {
if (dam <= 2) {
return "scorch";
} else if (pct <= 20) {
} else if (dam <= 6) {
return "singe";
} else if (dam <= 12) {
return "burn";
} else if (pct <= 40) {
} else if (dam <= 18) {
return "scald";
} else {
return "incinerate";
@ -477,21 +487,21 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
return "purify";
}
} else if (damtype == DT_MAGIC) {
if (pct <= 5) {
if (dam <= 2) {
return "zap";
} else if (pct <= 15) {
} else if (dam <= 6) {
return "sear";
} else if (pct <= 40) {
} else {
return "blast";
}
} else if (damtype == DT_PIERCE) {
if (pct <= 5) {
if (dam <= 2) {
return "poke";
} else if (pct <= 15) {
} else if (dam <= 6) {
return "stab";
} else if (pct <= 30) {
} else if (dam <= 12) {
return "pierce";
} else if (pct <= 40) {
} else if (dam <= 18) {
return "spear";
} else {
return "deeply stab";
@ -501,11 +511,11 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
} else if (damtype == DT_PROJECTILE) {
return "hit";
} else if (damtype == DT_SLASH) {
if (pct <= 5) {
if (dam <= 2) {
return "scratch";
} else if (pct <= 15) {
} else if (dam <= 6) {
return "hit";
} else if (pct <= 30) {
} else if (dam <= 12) {
return "slash";
} else {
return "slice";
@ -909,6 +919,32 @@ char *getinjurydesc(enum BODYPART where, enum DAMTYPE dt) {
return "";
}
char *getobmodprefix(object_t *o, obmod_t *om) {
// masterwork/shoddy doors have names based on material.
if (isdoor(o, NULL)) {
// player perceptive enough to notice?
if (om->id == OM_MASTERWORK) {
if ((gamemode == GM_GAMESTARTED) && (getskill(player, SK_PERCEPTION) < PR_BEGINNER)) {
return NULL;
}
switch (o->material->id) {
case MT_STONE: return "reinforced ";
case MT_METAL: return "reinforced ";
default: return "sturdy ";
}
} else if (om->id == OM_SHODDY) {
if ((gamemode == GM_GAMESTARTED) && (getskill(player, SK_PERCEPTION) < PR_BEGINNER)) {
return NULL;
}
switch (o->material->id) {
case MT_STONE: return "crumbling ";
case MT_METAL: return "rusted ";
default: return "rotted ";
}
}
}
return om->prefix;
}
char *getrarityname(enum RARITY rr) {
switch (rr) {

1
text.h
View File

@ -26,6 +26,7 @@ char *getdrunktext(flag_t *drunkflag);
char *getinjuredbpname(enum BODYPART bp);
char *getinjuryname(enum DAMTYPE dt);
char *getinjurydesc(enum BODYPART bp, enum DAMTYPE dt);
char *getobmodprefix(object_t *o, obmod_t *om);
char *getrarityname(enum RARITY rr);
char *getregionname(char *buf, map_t *m, region_t *r, int withlevel);
char *getreldirname(int reldir);