- [+] don't place draininge grates on low floor!!

- [+] gate spell should always take you to a location wihtout water!!
- [+] enhance speak with dead spell (SPEAKDEAD)
    - [+] may ask "how did you die" plus one of the below:
    - [+] tell me about the area
        - [+] mark stairs on the map
        - [+] mark shops on the map
        - [+] tell about very rare objects 
    - [+] tell me about nearby dangers
        - [+] tell about odd monsters
        - [+] tell about traps
    - [+] test
- [+] let you ask peaceful lfs about the surroundings too
    - [+] move code into io.c "askaboutarea(char *who)"
    - [+] test
- [+] the first time you ask someone for info, randomly determine
      whether they know about:
    - [+] stairs (high chance)
    - [+] shops (medium chance)
    - [+] traps (low chance)
- [+] areacomms_danger should include out of depth monsters - need
      isoutofdepth(lf)
- [+] room floors should take the entry type from the habitat, NOT just
      use ct_room!!!!
- [+] sometimes generate fixed SEWER regionthings
    - [+] done
- [+] BUG: canT enter goblin caves again!!!!
    - [+] getting "ERROR - can't find opposite end of stairs/portal!"
    - [+]   FAILED to link stiars: 'tunnel leading up'
- [+] make maps direct you to regionthings.
    - [+] region things need unique IDs !!!
    - [+] change F_MAPTO
        - [+] v0 = src region  id
        - [+] v1 = src depth
        - [+] v2 = regionthing with whatkind = RT_REGIONLINK
    - [+] when generating map objects, fill in a random branch entry
    - [+] fix getobname code for unknown maps.
    - [+] TEST
        - [+] with "map to the goblin caves"
        - [+] with "map"
        - [+] with "map to"
    - [+] use "the goblin caves are to the north", not "is to the north"
        - [+] is
        - [+] isn't
    - [+] test reading a map when on the wrong branch
    - [+] test reading a map when on the wrong level
    - [+] test reading a map when on the right level
- [+] move staircase generation to END of map create
    - [+] finalisemap()
    - [+] countobswithflagval(obpile, flagid, val0...)
    - [+] countmapobswithflagval(map, flagid, v0...)
- [+] jimbo's map should lead you to one of the major branches.  
- [+] crit pos shouldn't be higher than you can reach!
    - [+] same size or bigger = can reach anything
    - [+] 1 size smaller = you can't reach the head
    - [+] 2 sizes smaller = can't reach head or hands
    - [+] 3 sizes smaller = can't reach head, hands or body 
- [+] jimbo's room should contain all the staircases
- [+] make you have to pass a speech check before people will tell you
      about the area
- [+] bug in recruitment skillchecks - using wrong attribute, and too
      easy.
- [+] rename dwarf to delver
- [+] somtimes say "dons" instead of "puts on"
This commit is contained in:
Rob Pearce 2012-01-04 15:54:28 +00:00
parent c9a8866870
commit 040b9bf052
18 changed files with 1141 additions and 380 deletions

View File

@ -672,7 +672,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (critical) {
object_t *armour;
char noun[BUFLEN];
critpos = getrandomcorebp(victim);
critpos = getrandomcorebp(victim, lf);
if (critpos != BP_NONE) {
armour = getequippedob(victim->pack, critpos);
if (armour) {

8
data.c
View File

@ -2340,6 +2340,9 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL);
addot(OT_MAP, "map", "A visual representation of the area.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_VALUE, 100, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addot(OT_SCR_CREATEMONSTER, "scroll of create monster", "Summons a (probably hostile) monster to a nearby location.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_CREATEMONSTER, 4, NA, NULL);
@ -6973,7 +6976,8 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "good armour");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "good armour");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "armour");
//addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "dungeon exit orb");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "map");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "dungeon exit orb");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "concealing powder");
addflag(lastrace->flags, F_FLEEONHPPCT, 40, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_POLEARMS, PR_ADEPT, NA, NULL);
@ -7154,7 +7158,7 @@ void initrace(void) {
addflag(lastrace->flags, F_TAMABLE, 25, NA, NA, NULL);
addrace(R_DWARF, "dwarf", 60, 'h', C_BROWN, MT_FLESH, RC_HUMANOID, "Dwarves are short, hardy creatures who generally spend their entire lives mining underground. As such they have great fitness and enhanced low-light vision, but generally lack great reasoning skills and magical ability.");
addrace(R_DWARF, "delver", 60, 'h', C_BROWN, MT_FLESH, RC_HUMANOID, "Delvers are short, hardy creatures who generally spend their entire lives mining underground. As such they have great fitness and enhanced low-light vision, but generally lack great reasoning skills and magical ability.");
setbodytype(lastrace, BT_HUMANOID);
addflag(lastrace->flags, F_PLAYABLE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL);

44
defs.h
View File

@ -132,7 +132,11 @@
#define B_BIG (-1)
// Limits
#define MAXCANDIDATES 400 // must be >= max # of spells/abilities
// must be >= max # of spells/abilities AND
// >= max # of cells on the map
#define MAXCANDIDATES 2048
#define MAXCHOICES 400
#define MAXDEPTH 25 // max dungeon depth
#define MAXDIR_ORTH 4
@ -456,6 +460,11 @@ enum SAYPHRASE {
SP_DIE,
SP_DRUNK,
SP_MERCYACCEPT,
SP_INFO_ACCEPT,
SP_INFO_ASKPRICE,
SP_INFO_REFUSE,
SP_INFO_REFUSE_AGAIN,
SP_INFO_DECLINE_WONTPAY,
SP_PAYWARN,
SP_PAYTHREAT,
SP_PAYTHANKS,
@ -1859,20 +1868,20 @@ enum BODYPART {
BP_SECWEAPON = 1,
BP_EARS = 2,
BP_EYES = 3,
BP_HEAD = 4,
BP_HEAD = 4, // <- core bodypart
BP_SHOULDERS = 5,
BP_BODY = 6,
BP_HANDS = 7,
BP_BODY = 6, // <- core bodypart
BP_HANDS = 7, // <- core bodypart
BP_WAIST = 8,
BP_LEGS = 9,
BP_LEGS = 9, // <- core bodypart
BP_FEET = 10,
BP_RIGHTFINGER = 11,
BP_LEFTFINGER = 12,
// others...
BP_BACKLEGS = 13,
BP_FRONTLEGS = 14,
BP_WINGS = 15,
BP_TAIL = 16,
BP_WINGS = 15, // <- core bodypart
BP_TAIL = 16, // <- core bodypart
};
#define MAXBODYPARTS (17)
@ -1995,9 +2004,11 @@ enum FLAG {
F_NO_A, // this obname doesn't need to start with 'a' for singular (eg. gold)
F_CONTAINSOB, // for vending machiens. v0 is ob letter
// text is an object it contains.
F_MAPTO, // this object is a map to the world map at xy=v0/v1.
// optional v2 = obtypeid of target
// text = what this is a map to ie. "the nearest village"
F_MAPTO, // this object is a map to a regionlink.:
// v0=region containing entrance
// v1=depth of entrance
// v2=regionthing ID of RT_REGIONLINK thing
// text = what this is a map to ie. "the goblin caves"
F_SIGNTEXT, // for 'sign' objects. f->text is what is says.
F_IDWHENUSED, // fully identify an object when worn/weilded/operated/etc
F_STARTBLESSED, // v0 = b_blessed or b_cursed
@ -2211,8 +2222,7 @@ enum FLAG {
// stairs / teleporters / portals
F_CLIMBABLE, // this is a stiarcase, v0 = up/down/in
// also use this for portals
// OPTIONAL v1 = id of regiontype to link to.
// (ie. RG_xxx)
// 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
@ -2564,6 +2574,13 @@ enum FLAG {
// must pass SC_SPEECH of difficulty v0
F_HIREPRICE, // how much it costs to hire this lf.
F_NOHIRE, // this lf will not be hired.
F_INFOPRICE, // v0=price this lf wants to share info
F_NOINFO, // this lf will NOT share info
F_KNOWSABOUT, // text is a list of things this lf knows about:
// e = exits
// s = shops
// t = traps
// eg: text=="st" means they know of shops+traps
F_NOJOBTEXT, // this lf's name is 'a xxx', not 'a xxx wizard' etc
F_LASTDIR, // this is the last direction we moved.
//F_OWNERLASTDIR, // for pets, this it the last dir our owner moved
@ -3258,6 +3275,7 @@ typedef struct regiontype_s {
enum REGIONTYPE id;
enum HABITAT defaulthabitat;
char *name;
int pluralname;
int maxdepth;
int stairsperlev;
int deeperdir;
@ -3276,6 +3294,8 @@ enum REGIONTHING {
};
typedef struct regionthing_s {
struct regionoutline_s *parent;
int id;
int depth; // only need depth OR x,y
int x,y;
enum REGIONTHING whatkind;

178
io.c
View File

@ -3712,6 +3712,14 @@ void docomms(lifeform_t *lf) {
}
}
// TODO: allow you to ask this of allies, but only on the level they started on.
if (!areallies(player, lf)) {
if (ispeaceful(lf) && cantalk(lf)) {
addchoice(&prompt, 'i', "What can you tell me about this area?", NULL, NULL, NULL);
addchoice(&prompt, 'x', "Any dangers nearby that I should look out for?", NULL, NULL, NULL);
}
}
if (areenemies(player, lf)) {
addchoice(&prompt, 'm', "Have mercy!", NULL, NULL, NULL);
}
@ -3945,6 +3953,13 @@ void docomms(lifeform_t *lf) {
}
aigoto(lf, c, MR_OTHER, NULL, DEF_AIFOLLOWTIME);
break;
case 'i':
msg("You say \"What can you tell me about this area?\" to %s.", lfname);
if (askforinfo(lf)) {
genareaknowledge(lf->flags, 0);
docomms_areainfo(lfname, lf->flags, lf);
}
break;
case 'j':
// charisma check to see if they'll join you.
msg("You say \"Join me on my quest!\" to %s.", lfname);
@ -4069,6 +4084,13 @@ void docomms(lifeform_t *lf) {
return;
}
break;
case 'x':
msg("You say \"Any dangers nearby that I should look out for?\" to %s.", lfname);
if (askforinfo(lf)) {
genareaknowledge(lf->flags, 0);
docomms_areadangers(lfname, lf->flags, lf);
}
break;
case 'y':
msg("You shout at %s!", lfname);
noise(where, player, NC_OTHER, 3, "someone shouting!", NULL);
@ -4093,6 +4115,154 @@ void docomms(lifeform_t *lf) {
taketime(player, getactspeed(player));
}
// lf is the person (if any) who you are talking to
void docomms_areainfo(char *who, flagpile_t *fp, lifeform_t *lf) {
int x,y,ndone;
object_t *o;
cell_t *c;
flag_t *f,*knowflag;
knowflag = hasflag(fp, F_KNOWSABOUT);
if (!knowflag) {
// should never happen
msg("\"I don't know anything about that!\"");
return;
}
// shops
if (strchr(knowflag->text, 's')) {
ndone = 0;
for (y = 0; y < player->cell->map->h ; y++) {
for (x = 0; x < player->cell->map->w; x++) {
c = getcellat(player->cell->map, x,y);
if (hasobwithflag(c->obpile, F_SHOP)) {
setcellknownradius(c, PR_BEGINNER, 3, DT_ORTH);
ndone++;
}
}
}
if (ndone) {
needredraw = B_TRUE;
msg("\"There are some shops nearby...\""); more();
}
}
// veryrare objects
ndone = 0;
for (y = 0; y < player->cell->map->h ; y++) {
for (x = 0; x < player->cell->map->w; x++) {
c = getcellat(player->cell->map, x,y);
for (o = c->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_SHOP)) continue; // shops were already handled
f = hasflag(o->type->flags, F_RARITY);
if (f && (f->val[2] == RR_VERYRARE)) {
msg("\"I hear there is a rare %s nearby...\"", o->type->name); more();
setcellknown(c, PR_MASTER);
ndone++;
}
}
}
}
if (ndone) needredraw = B_TRUE;
// staircases
if (strchr(knowflag->text, 'e')) {
ndone = 0;
for (y = 0; y < player->cell->map->h ; y++) {
for (x = 0; x < player->cell->map->w; x++) {
c = getcellat(player->cell->map, x,y);
if (hasobwithflag(c->obpile, F_CLIMBABLE)) {
setcellknownradius(c, PR_BEGINNER, 3, DT_ORTH);
ndone++;
}
}
}
if (ndone) {
needredraw = B_TRUE;
msg("\"I can show you the ways out of this level...\""); more();
}
}
msg("\"That's all I know about this area.\"");
}
// lf is the person (if any) who you are talking to
void docomms_areadangers(char *who, flagpile_t *fp, lifeform_t *lf) {
int ndone = 0;
int totdone = 0;
int x,y,min,max;
cell_t *c;
flag_t *f,*knowflag;
object_t *o;
knowflag = hasflag(fp, F_KNOWSABOUT);
if (!knowflag) {
// should never happen
msg("\"I don't know anything about that!\"");
return;
}
// traps or trapped objects
if (strchr(knowflag->text, 't')) {
ndone = 0;
for (y = 0; y < player->cell->map->h ; y++) {
for (x = 0; x < player->cell->map->w; x++) {
c = getcellat(player->cell->map, x,y);
for (o = c->obpile->first ; o ; o = o->next) {
if (killflagsofid(o->flags, F_TRAP)) {
setcellknown(c, PR_MASTER);
ndone++;
} else {
f = hasflag(o->flags, F_TRAPPED);
if (f && (f->val[2] != B_TRUE)) {
f->val[2] = B_TRUE;
setcellknown(c, PR_MASTER);
ndone++;
}
}
}
}
}
if (ndone) {
needredraw = B_TRUE;
msg("\"There are hidden traps nearby...\""); more();
}
totdone += ndone;
}
// veryrare monsters
gethitdicerange(getmapdifficulty(player->cell->map), &min,&max, RARITYVARIANCELF, B_FALSE);
ndone = 0;
for (y = 0; y < player->cell->map->h ; y++) {
for (x = 0; x < player->cell->map->w; x++) {
c = getcellat(player->cell->map, x,y);
if (c->lf && !isplayer(c->lf) && (c->lf != lf) && areenemies(c->lf, player)) {
int showit = B_FALSE;
enum RARITY rr;
getracerarity(NULL, c->lf->race->id, &rr);
if (rr == RR_VERYRARE) {
showit = B_TRUE;
} else {
// out of depth monsters?
int hd;
hd = gethitdicerace(c->lf->race);
if (hd > max) {
showit = B_TRUE;
}
}
if (showit) {
char lfname[BUFLEN];
real_getlfnamea(c->lf, lfname, B_FALSE);
msg("\"There is %s living nearby...\"", lfname); more();
ndone++;
}
}
}
}
totdone += ndone;
msg("\"I know of no %sdangers in this area.\"", (totdone) ? "other " : "");
}
void dodrop(obpile_t *op, int wantmulti, obpile_t *dst) {
object_t *o;
char buf[BUFLEN];
@ -8432,7 +8602,7 @@ void handleinput(void) {
// certain objects in the current cell will stop us from running.
for (o = player->cell->obpile->first ; o ; o = o->next) {
if ( !hasflag(o->flags, F_COSMETIC)) {
if ( !hasflag(o->flags, F_COSMETIC) && !hasflag(o->flags, F_TRAIL)) {
stopnow = B_TRUE;
break;
}
@ -9461,7 +9631,7 @@ void drawstatus(void) {
//wprintw(statwin, "DLev:%d", player->cell->map->depth);
setcol(statwin, C_BROWN);
getregionname(buf, player->cell->map, B_TRUE);
getregionname(buf, player->cell->map, NULL, B_TRUE);
capitalise(buf);
wprintw(statwin, "%s", buf);
unsetcol(statwin, C_BROWN);
@ -11773,10 +11943,10 @@ void tombstone(lifeform_t *lf) {
centre(mainwin, C_GREY, y, "%s (%ld points)",pname, playerscore); y++;
if (player->cell->map->region->rtype->id == RG_WORLDMAP) {
getregionname(buf, player->cell->map, B_TRUE);
getregionname(buf, player->cell->map, NULL, B_TRUE);
centre(mainwin, C_GREY, y, "Died on %s.", buf); y++;
} else {
getregionname(buf, player->cell->map, B_FALSE);
getregionname(buf, player->cell->map, NULL, B_FALSE);
centre(mainwin, C_GREY, y, "Died on level %d of %s.", player->cell->map->depth, buf); y++;
}

2
io.h
View File

@ -44,6 +44,8 @@ void describespell(objecttype_t *ot);
void doattackcell(char dirch);
void doclose(void);
void docomms(lifeform_t *target);
void docomms_areainfo(char *who, flagpile_t *fp, lifeform_t *lf);
void docomms_areadangers(char *who, flagpile_t *fp, lifeform_t *lf);
void dodrop(obpile_t *op, int wantmulti, obpile_t *dst);
void doeat(obpile_t *op);
void doenter(lifeform_t *lf);

337
lf.c
View File

@ -994,6 +994,8 @@ int canquaff(lifeform_t *lf, object_t *o) {
return B_TRUE;
}
// can lf reach victim to attack them?
int canreach(lifeform_t *lf, lifeform_t *victim, int *reachpenalty) {
enum LFSIZE sizetoreach = SZ_ANY;
// harder to hit flying/levitating enemies, unless you are
@ -1030,6 +1032,71 @@ int canreach(lifeform_t *lf, lifeform_t *victim, int *reachpenalty) {
return B_FALSE;
}
// can lf reach victim's bodypart bp?
int canreachbp(lifeform_t *lf, lifeform_t *victim, enum BODYPART bp) {
int howmuchsmaller;
int lfsize, victimsize;
// can't reach them at all!
if (!canreach(lf, victim, NULL)) {
return B_FALSE;
}
lfsize = getlfsize(lf);
switch (isairborne(lf)) {
case F_FLYING: lfsize += 2; break;
case F_LEVITATING: lfsize++; break;
default: break;
}
victimsize = getlfsize(victim);
switch (isairborne(victim)) {
case F_FLYING: victimsize += 2; break;
case F_LEVITATING: victimsize++; break;
default: break;
}
howmuchsmaller = victimsize - lfsize;
if (howmuchsmaller <= 0) return B_TRUE;
switch (bp) {
// upper
case BP_EYES:
case BP_HEAD:
case BP_EARS:
case BP_SHOULDERS:
if (howmuchsmaller >= 1) {
return B_FALSE;
}
break;
case BP_WEAPON:
case BP_SECWEAPON:
case BP_HANDS:
case BP_RIGHTFINGER:
case BP_LEFTFINGER:
if (howmuchsmaller >= 2) {
return B_FALSE;
}
break;
case BP_BODY:
case BP_WAIST:
case BP_WINGS:
case BP_TAIL:
if (howmuchsmaller >= 3) {
return B_FALSE;
}
break;
case BP_LEGS:
case BP_FEET:
case BP_BACKLEGS:
case BP_FRONTLEGS:
if (howmuchsmaller >= 4) {
return B_FALSE;
}
break;
}
return B_TRUE;
}
int cansee(lifeform_t *viewer, lifeform_t *viewee) {
return cansee_real(viewer, viewee, B_TRUE);
}
@ -1449,6 +1516,9 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
case E_LOWIQ:
msg("You are not smart enough to cast spells.");
break;
case E_NOTREADY:
msg("This ability is not recharged yet.");
break;
case E_PRONE:
msg("You can't cast spells while prone.");
break;
@ -2499,6 +2569,9 @@ void die(lifeform_t *lf) {
colourmatchob(corpse, lf);
}
// inherit lifeform knowledge in case we raise it
copyflag(corpse->flags, lf->flags, F_KNOWSABOUT);
// corpse of a player pet?
if (ispetof(lf, player)) {
addflag(corpse->flags, F_PETOF, player->id, NA, NA, NULL);
@ -2622,6 +2695,28 @@ void dumpmonsters(void) {
dblog("END MONSTER DUMP (%d found)",count);
}
void genareaknowledge(flagpile_t *fp, int chancemod) {
char knownstuff[BUFLENSMALL];
if (hasflag(fp, F_KNOWSABOUT)) return;
strcpy(knownstuff, "");
// determine what someone knows about
// stairs? (high chance)
if (pctchance(75 + chancemod)) {
strcat(knownstuff, "e");
}
// shops? (med chance)
if (pctchance(50 + chancemod)) {
strcat(knownstuff, "s");
}
// traps? (low chance)
if (pctchance(25 + chancemod)) {
strcat(knownstuff, "t");
}
addflag(fp, F_KNOWSABOUT, NA, NA, NA, knownstuff);
}
void genxplist(void) {
race_t *r;
race_t *racetemp;
@ -2673,7 +2768,7 @@ void dumpxp(void) {
// dump
dblog("%-10s%-30s%s","XP", "Race", "Rarity");
for (i = 0; i < xplistlen; i++) {
dblog("%-10d%-30s%d",xpposs[i], raceposs[i]->name,getracerarity(NULL, raceposs[i]->id));
dblog("%-10d%-30s%d",xpposs[i], raceposs[i]->name,getracerarity(NULL, raceposs[i]->id, NULL));
}
// free mem
@ -3920,7 +4015,7 @@ int fall_from_air(lifeform_t *lf) {
}
}
if (willfall) fall(lf, NULL, B_TRUE);
if (willinjure) injure(lf, getrandomcorebp(lf), DT_BASH);
if (willinjure) injure(lf, getrandomcorebp(lf, NULL), DT_BASH);
if (willfall || willinjure) {
return B_TRUE;
}
@ -7230,9 +7325,13 @@ int getraceclass(lifeform_t *lf) {
return lf->race->raceclass->id;
}
int getracerarity(map_t *map, enum RACE rid) {
// returns rarity number. if optional rr is passed, this is will be returned too.
int getracerarity(map_t *map, enum RACE rid, enum RARITY *rr) {
race_t *r;
int rarity = -1;
if (rr) *rr = RR_NONE;
r = findrace(rid);
if (r) {
flag_t *f = NULL;
@ -7253,10 +7352,10 @@ int getracerarity(map_t *map, enum RACE rid) {
if (f) {
// ignore habitat for now!
rarity = f->val[1];
if (rr) *rr = f->val[2];
}
}
return rarity;
}
@ -7297,16 +7396,47 @@ object_t *getrandomarmour(lifeform_t *lf) {
}
// pick a random major body part
// ie. head, body, arms/hands, legs
enum BODYPART getrandomcorebp(lifeform_t *lf) {
// ie. head, body, arms/hands, legs, wings, tail
enum BODYPART getrandomcorebp(lifeform_t *lf, lifeform_t *attacker) {
int cutoff[4],nparts = 0,i,max = 0,num;
enum BODYPART bp[4],selbp = BP_NONE;
if (hasbp(lf, BP_BODY)) bp[nparts++] = BP_BODY;
if (hasbp(lf, BP_HANDS)) bp[nparts++] = BP_HANDS;
if (hasbp(lf, BP_HEAD)) bp[nparts++] = BP_HEAD;
if (hasbp(lf, BP_BODY)) {
if (attacker && !canreachbp(attacker, lf, BP_BODY)) {
} else {
bp[nparts++] = BP_BODY;
}
}
if (hasbp(lf, BP_HANDS)) {
if (attacker && !canreachbp(attacker, lf, BP_HANDS)) {
} else {
bp[nparts++] = BP_HANDS;
}
}
if (hasbp(lf, BP_HEAD)) {
if (attacker && !canreachbp(attacker, lf, BP_HEAD)) {
} else {
bp[nparts++] = BP_HEAD;
}
}
if (hasbp(lf, BP_LEGS) || hasbp(lf, BP_FRONTLEGS) || hasbp(lf, BP_BACKLEGS)) {
if (attacker && !canreachbp(attacker, lf, BP_LEGS)) {
} else {
bp[nparts++] = BP_LEGS;
}
}
if (hasbp(lf, BP_WINGS)) {
if (attacker && !canreachbp(attacker, lf, BP_WINGS)) {
} else {
bp[nparts++] = BP_WINGS;
}
}
if (hasbp(lf, BP_TAIL)) {
if (attacker && !canreachbp(attacker, lf, BP_TAIL)) {
} else {
bp[nparts++] = BP_TAIL;
}
}
if (!nparts) {
return BP_NONE;
@ -9018,30 +9148,12 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) {
killflagsofid(fp, F_STARTOBCLASS);
killflagsofid(fp, F_STARTOBWEPSK);
// SPECIAL CASES
if (lf) {
/*
// SPECIAL CASES GO HERE.
if (lf->race->id == R_JAILER) {
regionoutline_t *ro;
region_t *r;
regionthing_t *rt = NULL;
int i;
o = addobfast(lf->pack, OT_MAP);
o = addob(lf->pack, "map to the goblin caves");
assert(o);
// find first worldmap village
r = findregion(RG_WORLDMAP);
ro = r->outline;
for (i = 0; i < ro->nthings; i++) {
regionthing_t *thisthing;
thisthing = &ro->thing[i];
if ((thisthing->whatkind == RT_HABITAT) && (thisthing->value == H_VILLAGE)) {
rt = thisthing;
break;
}
}
addflag(o->flags, F_MAPTO, rt->x, rt->y, OT_GATEWOOD, "a village");
}
*/
// make sure lf doesn't start off burdened!
while (isburdened(lf)) {
@ -11415,6 +11527,96 @@ int armourfits(lifeform_t *lf, object_t *o, enum ERROR *reason) {
return B_TRUE;
}
// returns TRUE if 'lf' agrees to share knowledge with the player
int askforinfo(lifeform_t *lf) {
if (lfhasflag(lf, F_NOINFO)) {
// refusing to give info
sayphrase(lf, SP_INFO_REFUSE_AGAIN, SV_TALK, NA, NULL);
return B_FALSE;
} else {
int doinfo = B_FALSE;
int askingprice = -1;
char lfname[BUFLEN];
char buf[BUFLEN];
flag_t *f;
getlfname(lf, lfname);
if (areallies(player, lf)) {
askingprice = 0;
} else {
// they will consider it - now negotiate a price
f = lfhasflag(lf, F_INFOPRICE);
if (f) {
askingprice = f->val[0];
} else {
int result;
int difficulty;
difficulty = 20 + ((gethitdice(player) - gethitdice(lf))*2);
if (real_skillcheck(player, SC_SPEECH, difficulty, 0, &result)) {
askingprice = 0;
// passed - free!
} else {
if (difficulty - result >= 10) {
// will not help!
askingprice = -1;
} else {
// will help for gold
askingprice = rnd(gethitdice(lf)*5, gethitdice(lf)*15 );
}
}
if (askingprice == -1) {
addflag(lf->flags, F_NOINFO, B_TRUE, NA, NA, NULL);
sayphrase(lf, SP_INFO_REFUSE, SV_TALK, NA, NULL);
return B_FALSE;
} else {
addflag(lf->flags, F_INFOPRICE, askingprice, NA, NA, NULL);
}
}
}
if (askingprice != 0) {
// modify for same job
if (getjob(player) == getjob(lf)) {
askingprice = pctof(50, askingprice);
} else if (player->race->baseid == lf->race->baseid) { // modify for same race
askingprice = pctof(80, askingprice);
}
// modify by charisma
askingprice = pctof(100 - getstatmod(player, A_CHA), askingprice);
limit(&askingprice, 0, NA);
}
if (askingprice > 0) {
char ch;
sayphrase(lf, SP_INFO_ASKPRICE, SV_TALK, askingprice, NULL);
more();
if (askingprice > countmoney(player->pack)) {
msg("You can't afford to pay $%d.", askingprice);
return B_FALSE;
} else {
snprintf(buf, BUFLEN, "Pay $%d for information", askingprice);
ch = askchar(buf, "yn","n", B_TRUE, B_FALSE);
if (ch == 'y') {
doinfo = B_TRUE;
}
}
} else {
doinfo = B_TRUE;
}
if (doinfo) {
sayphrase(lf, SP_INFO_ACCEPT, SV_TALK, NA, NULL);
return B_TRUE;
} else {
sayphrase(lf, SP_INFO_DECLINE_WONTPAY, SV_TALK, askingprice, NULL);
}
} // end if !nohire
return B_FALSE;
}
int askforpayment(lifeform_t *shk, lifeform_t *lf) {
char saybuf[BUFLEN];
@ -13080,6 +13282,8 @@ void petify(lifeform_t *lf, lifeform_t *owner) {
makefriendly(lf, PERMENANT);
addflag(lf->flags, F_PETOF, owner->id, owner->cell->x, owner->cell->y, NULL);
killflagsofid(lf->flags, F_STAYINROOM);
killflagsofid(lf->flags, F_NOINFO);
killflagsofid(lf->flags, F_INFOPRICE);
}
@ -13651,8 +13855,8 @@ int recruit(lifeform_t *lf) {
int result;
int difficulty;
int minmult,maxmult;
difficulty = 20 + ((gethitdice(player) - gethitdice(lf))*2);
if (real_skillcheck(player, A_CHA, difficulty, 0, &result)) {
difficulty = 25 + ((gethitdice(player) - gethitdice(lf))*2);
if (real_skillcheck(player, SC_SPEECH, difficulty, 0, &result)) {
minmult = 10;
maxmult = 20;
// passed
@ -14200,6 +14404,69 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t
}
rv = say(lf, buf, volume);
break;
case SP_INFO_ACCEPT:
switch (rnd(1,2)) {
case 1: snprintf(buf, BUFLEN, "Okay, here's what I know..."); break;
case 2: snprintf(buf, BUFLEN, "Listen carefully..."); break;
}
rv = say(lf, buf, volume);
break;
case SP_INFO_ASKPRICE:
switch (rnd(1,3)) {
case 1:
snprintf(buf, BUFLEN, "I'll tell you for $%d...",val0);
break;
case 2:
snprintf(buf, BUFLEN, "Is the info worth $%d to you?",val0);
break;
case 3:
snprintf(buf, BUFLEN, "$%d and I'll tell you...",val0);
break;
}
rv = say(lf, buf, volume);
break;
case SP_INFO_REFUSE:
switch (rnd(1,4)) {
case 1:
snprintf(buf, BUFLEN, "What do you think I am, a library?");
break;
case 2:
snprintf(buf, BUFLEN, "Can't help, sorry.");
break;
case 3:
snprintf(buf, BUFLEN, "Get lost!");
break;
case 4:
snprintf(buf, BUFLEN, "No time to talk!");
break;
}
rv = say(lf, buf, volume);
break;
case SP_INFO_REFUSE_AGAIN:
switch (rnd(1,3)) {
case 1:
snprintf(buf, BUFLEN, "Asking twice isn't going to change the answer!");
break;
case 2:
snprintf(buf, BUFLEN, "Still can't help, sorry.");
break;
case 3:
snprintf(buf, BUFLEN, "I already told you to go away!");
break;
case 4:
snprintf(buf, BUFLEN, "Stop pestering me!");
break;
}
rv = say(lf, buf, volume);
break;
case SP_INFO_DECLINE_WONTPAY:
switch (rnd(1,3)) {
case 1: snprintf(buf, BUFLEN, "Cheapskate."); break;
case 2: snprintf(buf, BUFLEN, "Well, I'll be here if you change your mind."); break;
case 3: snprintf(buf, BUFLEN, "Your loss."); break;
}
rv = say(lf, buf, volume);
break;
case SP_PAYWARN:
switch (rnd(1,3)) {
case 1: snprintf(buf, BUFLEN, "Hey! Where do you think you're going?"); break;
@ -16793,6 +17060,7 @@ void timeeffectslf(lifeform_t *lf) {
if (willfall) {
usestairs(lf, o, B_FALSE, B_FALSE);
taketime(lf, getactspeed(lf)); // to avoid infinte loops
donesomething = B_TRUE;
o = hasobwithflagval(lf->cell->obpile, F_PIT, dir, NA, NA, NULL);
}
@ -18163,9 +18431,14 @@ int wear(lifeform_t *lf, object_t *o) {
msg("You are now wearing %s.", obname);
}
} else if (cansee(player, lf)) {
char verb[BUFLEN];
getlfname(lf, buf);
capitalise(buf);
msg("%s puts on %s.", buf, obname);
switch (rnd(1,2)) {
case 1: strcpy(verb, "puts on"); break;
case 2: strcpy(verb, "dons"); break;
}
msg("%s %s %s.", buf, obname);
}

7
lf.h
View File

@ -17,6 +17,7 @@ void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o);
int areallies(lifeform_t *lf1, lifeform_t *lf2);
int areenemies(lifeform_t *lf1, lifeform_t *lf2);
int armourfits(lifeform_t *lf, object_t *o, enum ERROR *reason);
int askforinfo(lifeform_t *lf);
int askforpayment(lifeform_t *shk, lifeform_t *lf);
char *assignnpcname(lifeform_t *lf);
void autoskill(lifeform_t *lf);
@ -48,6 +49,7 @@ int canpolymorphto(enum RACE rid);
int canpush(lifeform_t *lf, object_t *o, int dir);
int canquaff(lifeform_t *lf, object_t *o);
int canreach(lifeform_t *lf, lifeform_t *victim, int *reachpenalty);
int canreachbp(lifeform_t *lf, lifeform_t *victim, enum BODYPART bp);
int cansee(lifeform_t *viewer, lifeform_t *viewee);
int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos);
int cansleep(lifeform_t *lf);
@ -110,6 +112,7 @@ void gainhp(lifeform_t *lf, int amt);
void gainlevel(lifeform_t *lf, int autotrain);
void gainmp(lifeform_t *lf, int amt);
void gainxp(lifeform_t *lf, long amt);
void genareaknowledge(flagpile_t *fp, int chancemod);
void genxplist(void);
int get_adjacent_quadrants(int dir, enum QUADRANT *start, enum QUADRANT *end);
int get_circular_fov_endpoints(lifeform_t *lf, int maxvisrange, int *endx, int *endy, int *nendcells);
@ -214,9 +217,9 @@ char *getpoisondesc(enum POISONTYPE ptype);
char *getpoisonname(enum POISONTYPE ptype);
enum POISONSEVERITY getpoisonseverity(enum POISONTYPE ptype);
int getraceclass(lifeform_t *lf);
int getracerarity(map_t *map, enum RACE rid);
int getracerarity(map_t *map, enum RACE rid, enum RARITY *rr);
object_t *getrandomarmour(lifeform_t *lf);
enum BODYPART getrandomcorebp(lifeform_t *lf);
enum BODYPART getrandomcorebp(lifeform_t *lf, lifeform_t *attacker);
race_t *getrandomcorpserace(cell_t *c);
job_t *getrandomjob(int onlyplayerjobs);
int getrandommonlevel(race_t *r, map_t *m);

400
map.c
View File

@ -31,6 +31,8 @@ extern race_t *firstrace;
extern int viewx,viewy,vieww,viewh;
extern lifeform_t *player;
extern int nextregionthingid;
extern lifeform_t *godlf[];
extern int ngodlfs;
@ -761,6 +763,9 @@ 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) {
regionthing_t *rt;
rt = &(ro->thing[ro->nthings]);
rt->id = nextregionthingid;
nextregionthingid++;
rt->parent = ro;
rt->depth = depth;
rt->x = x;
rt->y = y;
@ -782,7 +787,7 @@ regionthing_t *addregionthing(regionoutline_t *ro, int depth, int x, int y, enum
return rt;
}
regiontype_t *addregiontype(enum REGIONTYPE id, char *name, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major, int depthmod) {
regiontype_t *addregiontype(enum REGIONTYPE id, char *name, int pluralname, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major, int depthmod) {
regiontype_t *a;
// add to the end of the list
@ -803,6 +808,7 @@ regiontype_t *addregiontype(enum REGIONTYPE id, char *name, enum HABITAT default
// props
a->id = id;
a->name = strdup(name);
a->pluralname = pluralname;
a->defaulthabitat = defaulthabitat;
a->maxdepth = maxdepth;
a->stairsperlev = stairsperlev;
@ -1910,14 +1916,51 @@ int countmapobs(map_t *m, enum OBTYPE oid) {
return count;
}
int countmapobswithflag(map_t *m, enum FLAG flagid) {
cell_t *c;
int count = 0,x,y;
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
c = getcellat(m, x, y);
if (c) {
count += countobswithflag(c->obpile, flagid);
}
}
}
return count;
}
int countmapobswithflagval(map_t *m, enum FLAG flagid, int val0, int val1, int val2, char *text) {
cell_t *c;
int count = 0,x,y;
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
c = getcellat(m, x, y);
if (c) {
count += countobswithflagval(c->obpile, flagid, val0, val1, val2, text);
}
}
}
return count;
}
int countstairs(map_t *m, int dir) {
int count;
count = countmapobswithflagval(m, F_CLIMBABLE, dir, NA, NA, NULL);
// don't include pits
count -= countmapobswithflagval(m, F_PIT, dir, NA, NA, NULL);
return count;
}
void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) {
int wantrooms = B_TRUE;
int x,y,i;
int numrooms = 0;
int entrylinked = B_FALSE;
cell_t *c;
object_t *o;
//int entrylinked = B_FALSE;
//object_t *o;
//int db = B_TRUE;
enum CELLTYPE emptycell,solidcell;
@ -2003,37 +2046,6 @@ void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *
}
*/
// UP STAIRS
for (i = 0; i < map->region->rtype->stairsperlev; i++) {
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomcell(map);
}
o = addobfast(c->obpile, OT_TUNNELUP);
assert(o);
if (entryob && !entrylinked) { // first cave level
linkstairs(o, entryob);
entrylinked = B_TRUE;
} else {
linkstairs(o, NULL);
}
}
// make sure we have at least one up stairs
assert(findobinmap(map, OT_TUNNELUP));
// DOWN STAIRS
if (map->depth < map->region->rtype->maxdepth) {
for (i = 0; i < map->region->rtype->stairsperlev; i++) {
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomcell(map);
}
o = addobfast(c->obpile, OT_TUNNELDOWN);
assert(o);
linkstairs(o, NULL);
}
}
// now do a border
y = 0;
for (x = 0; x < map->w; x++) {
@ -2068,7 +2080,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
int lastdir;
int numrooms = 0;
cell_t *cell, *c;
object_t *o;
//object_t *o;
int db = B_TRUE;
int digdb = B_FALSE;
@ -2305,70 +2317,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
}
}
// add staircases.
// first dungeon level has 1 up stairs, 3 down.
// subsequent levels always have 3 up and down stairs
// UP STAIRS
if (map->depth == 1) {
flag_t *f;
// first region level. just one exit stairs
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM);
}
o = addobfast(c->obpile, OT_STAIRSUP);
if (entryob) {
linkstairs(o, entryob);
} else {
// have to force these stairs to go back to a different region.
f = hasflag(o->flags, F_CLIMBABLE);
f->val[1] = map->region->parentregion->id;
linkstairs(o, NULL);
}
// special case: first dungeon level has barriers over the exit stairs
if (map->region->rtype->id == RG_MAINDUNGEON) {
if (c->lf) killlf(c->lf);
addobfast(c->obpile, OT_MAGICBARRIER);
// also clear all the cells around it to prevent reachability errors
for (d = DC_N; d <= DC_NW; d++) {
cell_t *c2;
c2 = getcellindir(c, d);
if (c2) setcelltype(c2, map->habitat->emptycelltype);
}
}
} else {
for (i = 0; i < map->region->rtype->stairsperlev; i++) {
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM);
if (!c) {
// ANY cell at all, doesn't have to be a room.
c = getrandomcell(map);
}
}
o = addobfast(c->obpile, OT_STAIRSUP);
assert(o);
linkstairs(o, NULL);
}
}
// make sure we have at least one up stairs
assert(findobinmap(map, OT_STAIRSUP));
// DOWN STAIRS
if (map->depth < map->region->rtype->maxdepth) {
for (i = 0; i < map->region->rtype->stairsperlev; i++) {
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM);
}
o = addobfast(c->obpile, OT_STAIRSDOWN);
assert(o);
linkstairs(o, NULL);
}
}
// add pillars & objects & monsters to rooms
if (wantrooms && (numrooms > 0)) {
for (i = 0; i < map->nrooms; i++) {
@ -2683,7 +2631,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
map->region = region;
if (db) {
getregionname(buf, map, B_FALSE);
getregionname(buf, map, NULL, B_FALSE);
dblog("Creating new map of region '%s'",buf);
}
map->habitat = findhabitat(habitat);
@ -2821,7 +2769,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
//if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging
// we now have the map name!
getregionname(buf2, map, B_TRUE);
getregionname(buf2, map, NULL, B_TRUE);
snprintf(buf, BUFLEN, "%s (id #%d)",buf2, map->id);
map->name = strdup(buf);
@ -2959,12 +2907,16 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
}
//if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging
if (map->habitat->id == H_CAVE) {
// expand the cave a little more now that we've fixed reachability.
// this will help make any new corridors look more 'cave-like'.
expand_cave(map, 2);
}
// add any required stairs
finalisemap(map, entryob);
// special cases
// village - add town walls and clear it out
if (db) dblog(" finalising village creation...");
@ -3119,7 +3071,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
}
} else {
if (db) {
dblog(" FAILED to link stiars: '%s'",o->type->name);
dblog(" FAILED to link stairs: '%s'",o->type->name);
}
}
@ -4199,12 +4151,13 @@ void createregionlink(map_t *m, cell_t *c, object_t *o, char *obname, enum REGIO
if (newregiontype != RG_MAINDUNGEON) {
basedepth = getmapdifficulty(m);
}
// does the new region exist yet ?
// create a new region.
r = addregion(newregiontype, m->region, -1, basedepth);
// add stairs going to the new region, if required
if (!c) {
c = NULL;
while (!c || !cellwalkable(NULL, c, NULL)) {
while (!c || !cellwalkable(NULL, c, NULL) || getcellwaterdepth(c, NULL)) {
c = getrandomcell(m);
}
}
@ -4290,6 +4243,7 @@ void createroom(map_t *map, int roomid, int x1, int y1, int x2, int y2, int forc
int x,y;
room_t *thisroom = NULL;
cell_t *cell;
map->room[map->nrooms].id = roomid;
map->room[map->nrooms].x1 = x1;
map->room[map->nrooms].y1 = y1;
@ -4312,11 +4266,11 @@ void createroom(map_t *map, int roomid, int x1, int y1, int x2, int y2, int forc
// ie. if you haven't forced walls then if this room overlaps
// with another one, no walls will be created.
if (forcewalls || (!forcewalls && cell->type->solid)) {
setcelltype(cell, CT_ROOMWALL);
setcelltype(cell, cell->habitat->solidcelltype);
}
//}
} else {
setcelltype(cell, CT_ROOM);
setcelltype(cell, cell->habitat->emptycelltype);
}
cell->room = thisroom;
}
@ -4554,7 +4508,6 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int
// critical hit? 100% chance in middle, 60 at one cell, 20 at two cells
critchance = 100 - (mydist*40);
if (pctchance(critchance)) {
//criticalhit(NULL, cc->lf, getrandomcorebp(cc->lf), DT_EXPLOSION);
criticalhit(NULL, cc->lf, BP_HANDS, pctof(critchance, dam), DT_EXPLOSIVE);
}
@ -4622,6 +4575,108 @@ 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 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
switch (map->habitat->id) {
case H_CAVE:
upstairtype = OT_TUNNELUP;
downstairtype = OT_TUNNELDOWN;
break;
case H_DUNGEON:
upstairtype = OT_STAIRSUP;
downstairtype = OT_STAIRSDOWN;
break;
default:
upstairtype = OT_NONE;
downstairtype = OT_NONE;
break;
}
// UP STAIRS
if (upstairtype != OT_NONE) {
if ((map->habitat->id == H_DUNGEON) && (map->depth == 1)) {
flag_t *f;
// first dungeon level. just one exit stairs
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM);
}
o = addobfast(c->obpile, upstairtype);
if (entryob) {
linkstairs(o, entryob);
} else {
// have to force these stairs to go back to a different region.
f = hasflag(o->flags, F_CLIMBABLE);
f->val[1] = map->region->parentregion->id;
linkstairs(o, NULL);
}
// special case: first dungeon level has barriers over the exit stairs
if (map->region->rtype->id == RG_MAINDUNGEON) {
if (c->lf) killlf(c->lf);
addobfast(c->obpile, OT_MAGICBARRIER);
// also clear all the cells around it to prevent reachability errors
for (d = DC_N; d <= DC_NW; d++) {
cell_t *c2;
c2 = getcellindir(c, d);
if (c2) setcelltype(c2, map->habitat->emptycelltype);
}
}
} else {
// up stairs on all other levels
int nneeded;
nneeded = map->region->rtype->stairsperlev - countstairs(map, D_UP);
for (i = 0; i < nneeded; i++) {
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM);
if (!c) {
// ANY cell at all, doesn't have to be a room.
c = getrandomcell(map);
}
}
o = addobfast(c->obpile, upstairtype);
assert(o);
if (entryob && !linkedentry) {
linkstairs(o, entryob);
linkedentry = B_TRUE;
} else {
linkstairs(o, NULL);
}
}
}
// make sure we have at least one up stairs
assert(findobinmap(map, upstairtype));
}
// DOWN STAIRS
if ((downstairtype != OT_NONE) && (map->depth < map->region->rtype->maxdepth)) {
int nneeded;
nneeded = map->region->rtype->stairsperlev - countstairs(map, D_DOWN);
for (i = 0; i < nneeded; i++) {
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM);
if (!c) {
// ANY cell at all, doesn't have to be a room.
c = getrandomcell(map);
}
}
o = addobfast(c->obpile, downstairtype);
assert(o);
linkstairs(o, NULL);
}
}
}
celltype_t *findcelltype(enum CELLTYPE cid) {
celltype_t *ct;
for (ct = firstcelltype ; ct ; ct = ct->next) {
@ -4670,6 +4725,40 @@ map_t *findmapofdepth(int depth) {
return NULL;
}
object_t *findmapobwithflag(map_t *m, enum FLAG flagid) {
cell_t *c;
object_t *o;
int x,y;
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
c = getcellat(m, x, y);
if (c) {
o = hasobwithflag(c->obpile, flagid);
if (o) return o;
}
}
}
return NULL;
}
object_t *findmapobwithflagval(map_t *m, enum FLAG flagid, int val0, int val1, int val2, char *text) {
cell_t *c;
object_t *o;
int x,y;
for (y = 0; y < m->h; y++) {
for (x = 0; x < m->w; x++) {
c = getcellat(m, x, y);
if (c) {
o = hasobwithflagval(c->obpile, flagid, val0, val1, val2, text);
if (o) return o;
}
}
}
return NULL;
}
cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf) {
int x,y,xinc,yinc;
@ -4774,6 +4863,21 @@ regionoutline_t *findoutline(int id) {
return NULL;
}
regiontype_t *findrandomregiontypewithname(char *name) {
regiontype_t *rt,*poss[MAXCANDIDATES];
int nposs = 0;
char buf[BUFLEN];
for (rt = firstregiontype ; rt ; rt = rt->next) {
if (streq(buf, rt->name)) {
poss[nposs++] = rt;
}
}
if (nposs) {
return poss[rnd(0,nposs-1)];
}
return NULL;
}
region_t *findregion(int regionid) {
region_t *r;
for (r = firstregion ; r ; r = r->next) {
@ -4792,7 +4896,6 @@ region_t *findregionbytype(enum REGIONTYPE rtid) {
return NULL;
}
map_t *findregionmap(int regionid, int depth) {
map_t *m;
for (m = firstmap ; m ; m = m->next) {
@ -4801,6 +4904,42 @@ map_t *findregionmap(int regionid, int depth) {
return NULL;
}
// returns the RT_REGIONLINK regionthing which links to region type rtid (eg. RG_CAVE)
regionthing_t *findregionlink(enum REGIONTYPE rtid) {
region_t *r;
regionthing_t *rt;
int i;
for (r = firstregion ; r ; r = r->next) {
if (!r->outline) continue;
for (i = 0; i < r->outline->nthings; i++ ){
rt = &r->outline->thing[i];
if ((rt->whatkind == RT_REGIONLINK) && (rt->value == rtid)) {
return rt;
}
}
}
return NULL;
}
// find the region thing with the given id.
// if optional 'retregion' is supplied, fill it in with the region which contains the thing.
regionthing_t *findregionthing(int id, region_t **retregion) {
region_t *r;
regionthing_t *rt;
int i;
for (r = firstregion ; r ; r = r->next) {
if (!r->outline) continue;
for (i = 0; i < r->outline->nthings; i++ ){
rt = &r->outline->thing[i];
if (rt->id == id) {
if (retregion) *retregion = r;
return rt;
}
}
}
return NULL;
}
regiontype_t *findregiontype(enum REGIONTYPE rtype) {
regiontype_t *rt;
for (rt = firstregiontype ; rt ; rt = rt->next) {
@ -4809,6 +4948,14 @@ regiontype_t *findregiontype(enum REGIONTYPE rtype) {
return NULL;
}
regiontype_t *findregiontypebyname(char *name) {
regiontype_t *rt;
for (rt = firstregiontype ; rt ; rt = rt->next) {
if (!strcasecmp(rt->name, name)) return rt;
}
return NULL;
}
room_t *findroom(map_t *m, int roomid) {
int i;
for (i = 0; i < m->nrooms; i++) {
@ -5432,7 +5579,6 @@ void initmap(void) {
// cell types - solid
addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0, 100);
addcelltype(CT_ROOMWALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0, 100);
addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEDARK, C_BROWN, B_SOLID, B_OPAQUE, MT_STONE, 0, 50);
addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, B_SOLID, B_OPAQUE, MT_WOOD, 0, 50);
addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, B_SOLID, B_OPAQUE, MT_FLESH, 0, 50);
@ -5445,20 +5591,19 @@ void initmap(void) {
addcelltype(CT_FLOORWOOD, "wood floor", '.', C_BROWN, B_EMPTY, B_TRANS, MT_WOOD, 0, -1);
addcelltype(CT_FLOORFLESH, "flesh floor", '.', C_RED, B_EMPTY, B_TRANS, MT_FLESH, 0, -1);
addcelltype(CT_FLOORSHOP, "shop floor", '.', C_BROWN, B_EMPTY, B_TRANS, MT_WOOD, 0, -1);
addcelltype(CT_ROOM, "rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0, -1);
addcelltype(CT_GRASS, "grass", '.', C_GREEN, B_EMPTY, B_TRANS, MT_PLANT, 0, -1);
addcelltype(CT_DIRT, "dirt", '.', C_BROWN, B_EMPTY, B_TRANS, MT_STONE, 0, -1);
addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -1, -1);
addcelltype(CT_VLOWFLOOR, "very low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -2, -1);
// region types
addregiontype(RG_WORLDMAP, "World map", H_FOREST, 10, 0, D_NONE, B_TRUE, 0);
addregiontype(RG_MAINDUNGEON, "First Dungeon", H_DUNGEON, 25, 3, D_DOWN, B_TRUE, 0);
addregiontype(RG_CAVE, "Goblin Caves", H_CAVE, 6, 1, D_DOWN, B_TRUE, 5);
addregiontype(RG_HEAVEN, "Realm of Gods", H_HEAVEN, 1, 0, D_NONE, B_FALSE, 0);
addregiontype(RG_PIT, "Pit", H_PIT, 1, 1, D_DOWN, B_FALSE, 0);
addregiontype(RG_SEWER, "Sewer", H_SEWER, 1, 0, D_NONE, B_FALSE, 2);
addregiontype(RG_STOMACH, "Stomach", H_STOMACH, 1, 0, D_NONE, B_FALSE, 0);
addregiontype(RG_WORLDMAP, "The Surface", B_FALSE, H_FOREST, 10, 0, D_NONE, B_TRUE, 0);
addregiontype(RG_MAINDUNGEON, "The Main Dungeon", B_FALSE, H_DUNGEON, 25, 3, D_DOWN, B_TRUE, 0);
addregiontype(RG_CAVE, "The Goblin Caves", B_TRUE, H_CAVE, 6, 1, D_DOWN, B_TRUE, 5);
addregiontype(RG_HEAVEN, "The Realm of Gods", B_FALSE, H_HEAVEN, 1, 0, D_NONE, B_FALSE, 0);
addregiontype(RG_PIT, "A Pit", B_FALSE, H_PIT, 1, 1, D_DOWN, B_FALSE, 0);
addregiontype(RG_SEWER, "A Sewer", B_FALSE, H_SEWER, 1, 0, D_NONE, B_FALSE, 2);
addregiontype(RG_STOMACH, "A Stomach", B_FALSE, H_STOMACH, 1, 0, D_NONE, B_FALSE, 0);
// MAPMAPMAPMAP
// region definitions (outlines)
@ -5502,6 +5647,15 @@ void initmap(void) {
// l25: last level
addregionthing(lastregionoutline, 25, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISSHRINE, NULL); // godstone on last floor
// 1-3 fixed sewers
addregionthing(lastregionoutline, rnd(1,25), NA, NA, RT_REGIONLINK, RG_SEWER, "drainage grate");
for (i = 0; i < 2; i++) {
if (onein(2)) {
addregionthing(lastregionoutline, rnd(1,25), NA, NA, RT_REGIONLINK, RG_SEWER, "drainage grate");
}
}
// forced shops:
addregionthing(lastregionoutline, rnd(2,4), NA, NA, RT_OBJECT, NA, "random building");
addregionthing(lastregionoutline, rnd(5,7), NA, NA, RT_OBJECT, NA, "random building");
@ -5512,6 +5666,10 @@ void initmap(void) {
addregionthing(lastregionoutline, rnd(20,22), NA, NA, RT_OBJECT, NA, "random building");
addregionthing(lastregionoutline, rnd(23,25), NA, NA, RT_OBJECT, NA, "random building");
addregionoutline(RG_CAVE);
// add initial regions
addregion(RG_WORLDMAP, NULL, -1, 0);
addregion(RG_HEAVEN, NULL, -1, 0);
}
int isadjacent(cell_t *src, cell_t *dst) {
@ -5534,8 +5692,12 @@ int isdark(cell_t *c) {
int isdiggable(cell_t *c) {
switch (c->type->id) {
case CT_WALL: return B_TRUE;
case CT_ROOMWALL: return B_TRUE;
case CT_WALLFLESH:
case CT_WALLDIRT:
case CT_WALL:
return B_TRUE;
default:
break;
}
return B_FALSE;
}
@ -5879,7 +6041,7 @@ object_t *linkportal(object_t *srcportal, int wantdepth) {
// find a random cell there
newcell = getrandomcell(newmap);
while (!cellwalkable(NULL, newcell, NULL) || hasenterableobject(newcell)) {
while (!cellwalkable(NULL, newcell, NULL) || hasenterableobject(newcell) || getcellwaterdepth(newcell, NULL)) {
newcell = getrandomcell(newmap);
}
// add the dst portal

12
map.h
View File

@ -10,7 +10,7 @@ int addrandomthing(cell_t *c, int obchance, int *nadded);
region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid, int depthmod);
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, char *name, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major, int depthmod);
regiontype_t *addregiontype(enum REGIONTYPE id, char *name, int pluralname, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major, int depthmod);
void adjustcellglyphforlight(cell_t *c, glyph_t *col);
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);
@ -46,6 +46,9 @@ int countadjwalls(cell_t *cell);
int countcellexits(cell_t *cell, int dirtype);
int countcellexitsfor(lifeform_t *lf);
int countmapobs(map_t *m, enum OBTYPE oid);
int countmapobswithflag(map_t *m, enum FLAG flagid);
int countmapobswithflagval(map_t *m, enum FLAG flagid, int val0, int val1, int val2, char *text);
int countstairs(map_t *m, int dir);
void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob);
void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob);
void createfakes(map_t *map, cell_t *cell);
@ -69,20 +72,27 @@ void dumpmap(map_t *map, int showrooms);
void expand_cave(map_t *map, int numpasses);
void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *centre);
void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int dirtype, int wantannounce);
void finalisemap(map_t *map, object_t *entryob);
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);
object_t *findmapobwithflag(map_t *m, enum FLAG flagid);
object_t *findmapobwithflagval(map_t *m, enum FLAG flagid, int val0, int val1, int val2, char *text);
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 OBTYPE oid);
regionoutline_t *findoutline(int id);
regiontype_t *findrandomregiontypewithname(char *name);
region_t *findregion(int regionid);
region_t *findregionbytype(enum REGIONTYPE rtid);
regionthing_t *findregionlink(enum REGIONTYPE rtid);
map_t *findregionmap(int regionid, int depth);
regionthing_t *findregionthing(int id, region_t **retregion);
regiontype_t *findregiontype(enum REGIONTYPE rtype);
regiontype_t *findregiontypebyname(char *name);
room_t *findroom(map_t *m, int roomid);
map_t *findsurfaceexitmap(map_t *m);
void forgetcells(map_t *map, int amt);

2
move.c
View File

@ -876,7 +876,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
i = howfar;
// don't fall
mightfall = B_FALSE;
if (onein(3)) criticalhit(NULL, lf, getrandomcorebp(lf), dam, DT_BASH);
if (onein(3)) criticalhit(NULL, lf, getrandomcorebp(lf, NULL), dam, DT_BASH);
break;
case E_SWIMMING:
case E_LFINWAY:

View File

@ -44,6 +44,8 @@ hiddenname_t *firsthiddenname = NULL, *lasthiddenname = NULL;
npcname_t *npcname;
int numnpcnames;
int nextregionthingid = 0;
buildingusage_t buildingusage[MAXBUILDINGTYPES];
int nbuildingusage = 0;
@ -245,7 +247,7 @@ int main(int argc, char **argv) {
newworld = B_TRUE;
// create world map.
wregion = addregion(RG_WORLDMAP, NULL, -1, 0);
wregion = findregionbytype(RG_WORLDMAP);
assert(wregion);
addmap();
createmap(firstmap, 1, wregion, NULL, D_NONE, NULL);
@ -255,7 +257,7 @@ int main(int argc, char **argv) {
dmap = addmap();
createmap(dmap, 1, dregion, firstmap, D_DOWN, NULL);
// create heaven
hregion = addregion(RG_HEAVEN, NULL, -1, 0);
hregion = findregionbytype(RG_HEAVEN);
assert(hregion);
heaven = addmap();
createmap(heaven, 1, hregion, NULL, D_NONE, NULL);

338
objects.c
View File

@ -27,6 +27,7 @@ extern obmod_t *firstobmod,*lastobmod;
extern material_t *material,*lastmaterial;
extern recipe_t *firstrecipe,*lastrecipe;
extern skill_t *firstskill, *lastskill;
extern region_t *firstregion;
extern buildingusage_t buildingusage[];
extern int nbuildingusage;
@ -453,6 +454,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
brand_t *br;
obmod_t *om;
obmod_t *wantom[MAXOBMODS];
regionthing_t *wantregionthing = NULL;
int bonus = 0;
int nom = 0;
int n;
@ -766,6 +768,22 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
corpserace = findracebyname(racename);
ot = findot(OT_CORPSE);
} else if (strstr(p, "map to ")) {
regiontype_t *rt;
char regionname[BUFLEN];
p2 = strstr(p, "map to ");
p2 += strlen("map to");
p2++; // go past the space
// grab name of region this map leads to
strcpy(regionname, p2);
// find the regiontype which matches this.
// if not found, it'll be randoml selected later.
rt = findregiontypebyname(regionname);
if (rt) {
// find the regionthing ID of the RT_REGIONLINK entrance
wantregionthing = findregionlink(rt->id);
}
ot = findot(OT_MAP);
} else if (strstr(p, "statue of ")) {
char racename[BUFLEN];
@ -931,6 +949,13 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
}
}
// don't put floor gratings on low floors
if (ot->id == OT_GRATINGFLOOR) {
if (where->where && (where->where->type->id == CT_LOWFLOOR)) {
setcelltype(where->where, where->where->map->habitat->emptycelltype);
}
}
if (gamemode != GM_LOADING) {
if (hasflag(ot->flags, F_ONEPERCELL)) {
if (hasob(where, ot->id)) {
@ -1429,6 +1454,49 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
cf->val[1] = sizetonutrition(rf->val[0]);
}
}
} else if (o->type->id == OT_MAP) {
region_t *srcregion;
regiontype_t *dstrt = NULL;
int srcdepth;
char buf[BUFLEN];
// fill in map destination.
if (!wantregionthing) {
region_t *r;
regionthing_t *rthing,*poss[MAXCANDIDATES];
int nposs = 0,i;
for (r = firstregion ; r ; r = r->next) {
if (!r->outline) continue;
for (i = 0; i < r->outline->nthings; i++ ){
// pick a random regionlink thing.
rthing = &r->outline->thing[i];
if (rthing->whatkind == RT_REGIONLINK) {
regiontype_t *rtype;
rtype = findregiontype(rthing->value);
if ( (rtype->id != RG_MAINDUNGEON) &&
(rtype->id != RG_WORLDMAP)) {
poss[nposs++] = rthing;
}
}
}
}
if (nposs) {
wantregionthing = poss[rnd(0,nposs-1)];
}
}
assert(wantregionthing);
// we now have the destination regionlink thing which the
// map will lead to.
// just using this to fill in srcregion
findregionthing(wantregionthing->id, &srcregion);
srcdepth = wantregionthing->depth;
dstrt = findregiontype(wantregionthing->value);
strcpy(buf, dstrt->name);
makelowercase(buf);
addflag(o->flags, F_MAPTO, srcregion->id, srcdepth, wantregionthing->id, buf);
} else if (o->type->id == OT_STATUE) {
flag_t *f, *rf;
float ratio;
@ -2724,6 +2792,24 @@ int countobsoftype(obpile_t *op, enum OBTYPE oid) {
return count;
}
int countobswithflag(obpile_t *op, enum FLAG flagid) {
object_t *o;
int count = 0;
for (o = op->first ; o ; o = o->next) {
if (hasflag(o->flags, flagid)) count++;
}
return count;
}
int countobswithflagval(obpile_t *op, enum FLAG flagid, int val0, int val1, int val2, char *text) {
object_t *o;
int count = 0;
for (o = op->first ; o ; o = o->next) {
if (hasflagval(o->flags, flagid, val0, val1, val2, text)) count++;
}
return count;
}
int countnoncosmeticobs(obpile_t *op, int onlyifknown) {
object_t *o;
@ -4597,7 +4683,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
} // end if sight/smell
} else if ((o->type->id == OT_SIGN) && !hasflag(o->flags, F_SIGNTEXT)) {
strcpy(basename, "blank sign");
} else if (o->type->id == OT_MAP) {
} else if ((o->type->id == OT_MAP) && isknown(o)) {
flag_t *f;
f = hasflag(o->flags, F_MAPTO);
if (f && getskill(player, SK_CARTOGRAPHY)) {
@ -5008,7 +5094,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
} else {
char buf2[BUFLEN];
strcat(localbuf, " to ");
getregionname(buf2, newmap, B_FALSE);
getregionname(buf2, newmap, NULL, B_FALSE);
strcat(localbuf, buf2);
}
}
@ -10056,162 +10142,146 @@ int readsomething(lifeform_t *lf, object_t *o) {
}
} else if (o->type->id == OT_MAP) {
if (isplayer(lf)) {
if (!getskill(lf, SK_CARTOGRAPHY)) {
msg("You can't comprehend this map.");
} else if (lf->cell->map->region->rtype->id == RG_WORLDMAP) {
int lfmx,lfmy,tmx,tmy;
int dist;
cell_t *c;
enum SKILLLEVEL slev;
region_t *srcregion = NULL;
regionthing_t *destthing = NULL;
regiontype_t *destregiontype = NULL;
int srcdepth = -1, plural = B_FALSE;
char isare[BUFLENSMALL];
f = hasflag(o->flags, F_MAPTO);
getmapcoords(lf->cell->map, &lfmx, &lfmy);
tmx = f->val[0];
tmy = f->val[1];
dist = abs(tmx - lfmx) + abs(tmy - lfmy);
if (f) {
srcregion = findregion(f->val[0]);
srcdepth = f->val[1];
destthing = findregionthing(f->val[2], NULL);
destregiontype = findregiontype(destthing->value);
plural = destregiontype->pluralname;
if (plural) {
strcpy(isare, "are");
} else {
strcpy(isare, "is");
}
}
if (f && srcregion) {
enum SKILLLEVEL slev;
slev = getskill(lf, SK_CARTOGRAPHY);
switch (slev) {
default:
if (!slev) {
msg("You can't comprehend this map.");
break;
} else {
if (lf->cell->map->region == srcregion) {
if (lf->cell->map->depth == srcdepth) {
// on the correct map. at this point the f_climbable flag should
// have been filled in correctly, and the destination region created.
cell_t *destcell;
object_t *destob;
char distbuf[BUFLEN],distbufbad[BUFLEN];
char dirbuf[BUFLEN];
region_t *destregion = NULL;
int dist;
destregion = findregionbytype(destthing->value);
destob = findmapobwithflagval(lf->cell->map, F_CLIMBABLE, NA, destregion->id, NA, NULL);
destcell = getoblocation(destob);
dist = getcelldist(lf->cell, destcell);
getdisttext(lf->cell, destcell, distbuf, distbufbad, dirbuf);
switch (slev) {
default: break; // should never happen
case PR_NOVICE:
// here/not here
if (dist == 0) {
msg("%s is in this area!", f->text);
} else {
msg("%s isn't in this area.", f->text);
}
msg("%s %s in this area!", f->text, isare);
break;
case PR_BEGINNER:
// near/far dist to that map
if (dist == 0) {
msg("%s is in this area!", f->text);
} else if (dist == 1) {
msg("%s is very nearby.", f->text);
} else {
msg("%s isn't nearby.", f->text);
}
// direction to cell
msg("%s %s to the %s.", f->text, isare, dirbuf);
break;
case PR_ADEPT:
// x areas away
if (dist == 0) {
msg("%s is in this area!", f->text);
} else if (dist == 1) {
msg("%s is one area away.", f->text);
// direction +
// near/far dist to cell
msg("%s %s %s to the %s.", f->text, isare, distbufbad, dirbuf);
break;
case PR_SKILLED:
// direction +
// good dist to cell
msg("%s %s %s to the %s.", f->text, isare, distbuf, dirbuf);
break;
case PR_EXPERT:
// direction +
// exact dist to cell
msg("%s %s %d metres away to the %s.", f->text, isare, dist, dirbuf);
break;
case PR_MASTER:
// reveal it
msg("You have located %s in this area.", f->text);
setcellknownradius(destcell, PR_MASTER, 5, DT_ORTH);
needredraw = B_TRUE;
break;
}
} else {
msg("%s is %d areas away.", f->text, dist);
// correct region, wrong map
int dist;
char buf[BUFLEN];
dist = abs(lf->cell->map->depth - srcdepth);
switch (slev) {
default: break; // should never happen
case PR_NOVICE:
case PR_BEGINNER:
// here/not here
msg("%s %s in this area.", f->text, plural ? "aren't" : "isn't");
break;
case PR_ADEPT:
// up/down
if (lf->cell->map->depth > srcdepth) {
msg("%s %s somewhere above you.", f->text, isare);
} else {
msg("%s %s somewhere below you.", f->text, isare);
}
break;
case PR_SKILLED:
// x areas away
// plus direction.
if (dist == 0) {
msg("%s is in this area!", f->text);
} else {
char dirbuf[BUFLEN];
// up/down and how far
if (dist == 1) {
snprintf(buf, BUFLEN, "%s is one area away to the ", f->text);
strcpy(buf, "just");
} else if (dist <= 3) {
strcpy(buf, "somewhere");
} else {
snprintf(buf, BUFLEN, "%s is %d areas away to the ", f->text, dist);
}
strcpy(dirbuf, "");
if (tmy < lfmy) {
strcpy(dirbuf, "north");
} else if (tmy > lfmy) {
strcpy(dirbuf, "south");
}
if (tmx > lfmx) {
strcat(dirbuf, "east");
} else if (tmx < lfmx) {
strcat(dirbuf, "west");
}
strcat(buf, dirbuf);
strcat(buf, ".");
msg("%s", buf);
strcpy(buf, "very far");
}
msg("%s %s %s %s you.", f->text, isare, buf,
(lf->cell->map->depth > srcdepth) ? "above" : "below");
break;
case PR_EXPERT:
// x areas away
// plus direction.
// plus distance within area.
if (dist == 0) {
int dist2;
char distbuf[BUFLEN];
c = findobinmap(lf->cell->map, f->val[2]);
dist2 = getcelldist(lf->cell, c);
if (dist2 >= 20) {
strcpy(distbuf, "(very far away)");
} else if (dist2 >= 10) {
strcpy(distbuf, "(far away)");
} else if (dist2 >= 5) {
strcpy(distbuf, "(nearby)");
} else {
strcpy(distbuf, "(very nearby)");
}
msg("%s is in this area %s!", f->text, distbuf);
} else {
char dirbuf[BUFLEN];
if (dist == 1) {
snprintf(buf, BUFLEN, "%s is one area away to the ", f->text);
} else {
snprintf(buf, BUFLEN, "%s is %d areas away to the ", f->text, dist);
}
strcpy(dirbuf, "");
if (tmy < lfmy) {
strcpy(dirbuf, "north");
} else if (tmy > lfmy) {
strcpy(dirbuf, "south");
}
if (tmx > lfmx) {
strcat(dirbuf, "east");
} else if (tmx < lfmx) {
strcat(dirbuf, "west");
}
strcat(buf, dirbuf);
strcat(buf, ".");
msg("%s", buf);
}
break;
case PR_MASTER:
// x,y coords.
// plus direction.
// plus show on map if in area.
if (dist == 0) {
msg("You have located %s in this area.", f->text);
c = findobinmap(lf->cell->map, f->val[2]);
setcellknownradius(c, slev, 5, DT_ORTH);
} else {
char dirbuf[BUFLEN];
char buf2[BUFLEN];
snprintf(buf, BUFLEN, "%s is at %d,%d",f->text, tmx,tmy);
if (dist == 1) {
snprintf(buf2, BUFLEN, " (one area away to the ");
} else {
snprintf(buf2, BUFLEN, " (%d areas away to the ", dist);
}
strcpy(dirbuf, "");
if (tmy < lfmy) {
strcpy(dirbuf, "north");
} else if (tmy > lfmy) {
strcpy(dirbuf, "south");
}
if (tmx > lfmx) {
strcat(dirbuf, "east");
} else if (tmx < lfmx) {
strcat(dirbuf, "west");
}
strcat(buf2, dirbuf);
strcat(buf2, ")");
msg("%s%s", buf, buf2);
}
// level number
msg("%s %s on level %d.", f->text, isare, srcdepth);
break;
}
} // end correct map or not?
} else {
msg("You need to be outside to get your bearings first.");
// wrong region and wrong map
switch (slev) {
default: break; // should never happen
case PR_NOVICE:
case PR_BEGINNER:
// here/not here
msg("%s %s in this area.", f->text, plural ? "aren't" : "isn't");
break;
case PR_ADEPT:
case PR_SKILLED:
// tell which area it is in (without level)
getregionname(buf, NULL, srcregion, B_FALSE);
msg("%s %s somewhere within %s.", f->text, isare, buf);
break;
case PR_EXPERT:
case PR_MASTER:
// which area it is in, plus which floor
getregionname(buf, NULL, srcregion, B_TRUE);
msg("%s %s in %s.", f->text, isare, buf);
break;
}
} // end if correct region etc
} // if slev
} else {
msg("This map doesn't seem to be finished.");
}
} //end if isplayer
} else if (o->type->id == OT_SCR_AWARENESS) {
addtempflag(lf->flags, F_AWARENESS, B_TRUE, NA, NA, NULL, getspellduration(30,60,o->blessed));
if (isplayer(lf)) msg("The scroll crumbles to dust.");

View File

@ -42,6 +42,8 @@ int countmoney(obpile_t *op);
int countnames(char **list);
int countobs(obpile_t *op, int onlyifknown);
int countobsoftype(obpile_t *op, enum OBTYPE oid);
int countobswithflag(obpile_t *op, enum FLAG flagid);
int countobswithflagval(obpile_t *op, enum FLAG flagid, int val0, int val1, int val2, char *text);
int countnoncosmeticobs(obpile_t *op, int onlyifknown);
int curseob(object_t *o);
void damageallobs(object_t *srcob, obpile_t *op, int howmuch, int damtype);

8
save.c
View File

@ -637,16 +637,18 @@ int loadregions(void) {
fscanf(f, "numoutlines:%d\n",&numoutlines);
if (db) dblog("Found %d region outlines.\n",numoutlines);
for (n = 0; n < numoutlines; n++) {
regionthing_t *thing;
fscanf(f, "startro\n");
fscanf(f, "rtypeid:%d\n",&rtid); // region type id
addregionoutline(rtid);
fscanf(f, "nthings:%d\n",&nthings);
for (i = 0; i < nthings; i++) {
int depth,x,y,val;
int depth,x,y,val,id;
enum REGIONTHING whatkind;
char buf[BUFLEN],*p;
fscanf(f, "startthing\n");
fscanf(f, " thingid:%d\n",&id);
fscanf(f, " thingdepth:%d,%d,%d\n",&depth, &x, &y);
fscanf(f, " thingkind:%d\n",(int *)&whatkind);
fscanf(f, " thingval:%d\n",&val);
@ -657,7 +659,8 @@ int loadregions(void) {
for (p = buf ; *p; p++) {
if (*p == '^') *p = ' ';
}
addregionthing(lastregionoutline, depth, x, y, whatkind, val, streq(buf, "NULL") ? NULL : buf);
thing = addregionthing(lastregionoutline, depth, x, y, whatkind, val, streq(buf, "NULL") ? NULL : buf);
thing->id = id;
}
fscanf(f, "endro\n");
if (db) dblog("Loaded regionoutline #%d / %d",n+1, numoutlines);
@ -1028,6 +1031,7 @@ int saveregions(void) {
fprintf(f, "nthings:%d\n",ro->nthings);
for (i = 0; i < ro->nthings; i++) {
fprintf(f, "startthing\n");
fprintf(f, " thingid:%d\n",(int)ro->thing[i].id);
fprintf(f, " thingdepth:%d,%d,%d\n",ro->thing[i].depth, ro->thing[i].x, ro->thing[i].y);
fprintf(f, " thingkind:%d\n",(int)ro->thing[i].whatkind);
fprintf(f, " thingval:%d\n",(int)ro->thing[i].value);

33
spell.c
View File

@ -5537,7 +5537,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getlfname(target, targetname);
msg("Unseen forces rip into %s%s flesh!", targetname, getpossessive(targetname));
}
criticalhit(caster, target, getrandomcorebp(target), rnd(1,6), DT_SLASH);
criticalhit(caster, target, getrandomcorebp(target, NULL), rnd(1,6), DT_SLASH);
pleasegodmaybe(R_GODDEATH, 3);
} else if (spellid == OT_S_GLYPHWARDING) {
char buf[BUFLEN];
@ -7829,7 +7829,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
char ch = 'a';
char mapname[BUFLEN];
getregionname(mapname, m, B_TRUE);
getregionname(mapname, m, NULL, B_TRUE);
capitalise(mapname);
if (m->habitat->id == H_HEAVEN) continue;
@ -9038,20 +9038,28 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (corpse) {
char buf[BUFLEN],corpsename[BUFLEN];
char ch;
int done = B_FALSE;
getobname(corpse, corpsename, 1);
msg("An ghostly spirit rises from %s!", corpsename); more();
while (!done) {
snprintf(buf, BUFLEN, "What will you ask %s?", corpsename);
initprompt(&prompt, buf);
addchoice(&prompt, 'a', "How did you die?", NULL, NULL, NULL);
addchoice(&prompt, 'b', "Tell me about this area", NULL, NULL, NULL);
addchoice(&prompt, 'c', "Are there any hidden dangers nearby?", NULL, NULL, NULL);
addchoice(&prompt, '-', "(nothing)", NULL, NULL, NULL);
prompt.maycancel = B_TRUE;
ch = getchoice(&prompt);
if ((ch != '\0') && (ch != '-')) {
snprintf(buf, BUFLEN, "%s whispers:", corpsename);
msg(buf);
}
if (ch == 'a') {
flag_t *f;
char *p;
snprintf(buf, BUFLEN, "%s whispers:", corpsename);
msg(buf);
f = hasflag(corpse->flags, F_CORPSEOF);
if (f && strlen(f->text)) {
char killer[BUFLEN];
@ -9072,7 +9080,22 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else {
msg("\"I do not know what killed me.\"");
}
} else if (ch == 'b') {
genareaknowledge(corpse->flags, 50);
docomms_areainfo(corpsename, corpse->flags, NULL);
done = B_TRUE;
} else if (ch == 'c') {
genareaknowledge(corpse->flags, 50);
docomms_areadangers(corpsename, corpse->flags, NULL);
done = B_TRUE;
} else {
done = B_TRUE;
}
} // end while !done
// destroy the corpse.
msg("%s crumbles to dust.", corpsename);
removeob(corpse, ALL);
}
} else if (spellid == OT_S_STENCH) {
int howlong;

21
text.c
View File

@ -925,12 +925,15 @@ char *getrarityname(enum RARITY rr) {
return "?unknownrarity?";
}
char *getregionname(char *buf, map_t *m, int withlevel) {
region_t *r;
// pass in EITHER m or r, not both.
//
// if withlevel is TRUE, "m" should be passed.
char *getregionname(char *buf, map_t *m, region_t *r, int withlevel) {
if (!r) {
r = m->region;
}
if (withlevel) {
if (withlevel && m) {
flag_t *f;
int x,y;
f = hasflag(m->flags, F_MAPCOORDS);
@ -1187,6 +1190,16 @@ char *makekillertext(char *retbuf, char *killverb, char *lastdam, int wantextra)
return retbuf;
}
char *makelowercase(char *text) {
if (strlen(text) > 0) {
char *p;
for (p = text ; *p; p++) {
*p = tolower(*p);
}
}
return text;
}
// allocates and returns new string
char *makeplural(char *text) {
char lastlet;

3
text.h
View File

@ -27,7 +27,7 @@ char *getinjuredbpname(enum BODYPART bp);
char *getinjuryname(enum DAMTYPE dt);
char *getinjurydesc(enum BODYPART bp, enum DAMTYPE dt);
char *getrarityname(enum RARITY rr);
char *getregionname(char *buf, map_t *m, int withlevel);
char *getregionname(char *buf, map_t *m, region_t *r, int withlevel);
char *getreldirname(int reldir);
char *getsizetext(enum LFSIZE sz);
char *gettimetext(char *retbuf);
@ -38,6 +38,7 @@ char *is(lifeform_t *lf);
int isvowel(char c);
void makegunaimstring(lifeform_t *lf, int lfid, char *retbuf);
char *makekillertext(char *retbuf, char *killverb, char *lastdam, int wantextra);
char *makelowercase(char *text);
char *makeplural(char *text);
char *makethrowaccstring(lifeform_t *lf, cell_t *c, flag_t *throwflag, char *retbuf);
char *makeuppercase(char *text);

View File

@ -3,11 +3,11 @@
@map
############
#....c...|,#
#....-/-.###
+......@.|,#
#..-/-...###
#....c...|,#
#>+..c...|,#
###..-/-.###
X......@>|,#
###-/-...###
#>+..c...|,#
############
@end
@ -16,8 +16,10 @@
|:ob:locked iron gate
,:ob:1-4 bones:50
,:mon:prisoner:50
X:ob:wooden door
X:exit
>:ob:staircase going down
+:ob:wooden door
+:exit
/:ob:wooden table
-:ob:wooden footstool
c:ob:lit candelabrum