- [+] prevent ALL overlapping rooms!

- [+] stop running for any non-cosmetic object.
- [ ] echoing?
- [+] OPTIONS 
    - [+] option_t
        - [+] id
        - [+] letter
        - [+] text
        - [+] int enabled
        - [+] int default
        - [+] next/prev
    - [+] addoption()
    - [+] getoption()
    - [+] dooptions()
        - [+] list them all (with 'more' for multipages)
        - [+] pressing a letter toggles it.
    - [+] "display trails"
- [+] make scents be "cosmetic"!
- [+] increaes skeleton's vulnerability to falling
- [+] missing announcement for bleed()
- [+] let rapid ivy cast entangle
- [+] caves
    - [+] new regiontype
    - [+] new link
    - [+] new habitat
    - [+] objectlass rarities
    - [+] assign obs/mons to habitat
    - [+] code to dig caves
    - [+] stairs linking to cave region
- [+] when learning random skills:
    - [+] prefer lower-level skills
    - [+] onyl learn up to adept level 
- [+] animate dead crashes if there is no space to place the lifeform!
- [+] increase range of charge ability
- [+] when you gain techusage, check held objects for conferred flags.
- [+] bug: motion scanner working even though i have no tech usage!
- [+] warn player before climbing without climb skill (if wisdom is >=
      average)
- [+] regions should have depthmod.
- [+] regionthings should be based on DEPTH, not difficulty!
- [+] rename firstdungeon to maindungeon
- [+] announcearrival broken -always saying 'new area'
- [+] don't use ranged attacks when feigning death if target is adjacent
- [+] don't say 'argh' if you were beheaded.
- [+] The bear cub bites a wooden door with a teeth.--More--
- [+] random levelup skills - only select from skills which we have
      used?
    - [+] need to chance f_hasskill to use f->val[2] = used_this_level
    - [+] when you gain a skill, set f>val[2] = b_false or NA
    - [+] add setskillused for all skills!
    - [+] make random levleup only pick from used skills.
    - [+] TEST
- [+] knowledge skills - practice them when you see a new lf of this
      type.
- [+] slithering shoudl hardly ever awaken you - make listen check
      harder.
- [+] don't put fireplaces in corridors.  F_ONLYINROOM ?
- [+] bug: acid trails from slug disappearing or never appearing?
- [+] snails/slugs
    - [+] killed by salt
    - [+] vslow
    - [+] snails have vhigh armourrating
    - [+] slugs have lots of hp and do more damage
    - [+] brown/grey  'j' ?
    - [+] leave slime/acid trails?
This commit is contained in:
Rob Pearce 2012-01-03 01:21:22 +00:00
parent 8d0d14b8dc
commit adb066d31a
22 changed files with 957 additions and 211 deletions

5
ai.c
View File

@ -302,6 +302,11 @@ object_t *aigetrangedattack(lifeform_t *lf, lifeform_t *target, enum RANGEATTACK
if (ra) *ra = RA_NONE;
return NULL;
}
if (lfhasflag(lf, F_FEIGNINGDEATH) && target && (getcelldist(lf->cell, target->cell) == 1)) {
if (db) dblog(".oO { no ranged attack because i am feigning death and adj to my target }");
if (ra) *ra = RA_NONE;
return NULL;
}
iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
if (iqb <= IQ_ANIMAL) {

View File

@ -881,7 +881,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// blocked by defender's shield?
sprintf(attackname, "%s%s attack", attackername, getpossessive(attackername));
//difficulty = 20 + ((gethitdice(lf) - gethitdice(victim)) );
difficulty = 20 + gethitdice(lf);
//difficulty = 20 + gethitdice(lf);
difficulty = 20 + (gethitdice(lf)*2) - gethitdice(victim);
if (check_for_block(lf, victim, dam[i], damtype[i], difficulty, attackname)) {
blocked = B_TRUE;
break; // stop processing damage now.
@ -1283,6 +1284,9 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) {
maxhp = 1;
}
if (hasflag(wep->flags, F_UNARMEDWEP)) {
isunarmed = B_TRUE;
}
getobname(wep, wepname, 1);

361
data.c

File diff suppressed because it is too large Load Diff

3
data.h
View File

@ -1,12 +1,15 @@
#include "defs.h"
void addbonustext(flagpile_t *fp, enum FLAG fid, char *text);
option_t *addoption(enum OPTION id, char *text, int def);
command_t *addcommand(enum COMMAND id, char c, char *desc);
void initcommands(void);
void initjobs(void);
void initobjects(void);
void initoptions(void);
void initrace(void);
void initskills(void);
void killcommand(command_t *cmd);
void killoption(option_t *o);
void make_basic_shop(flagpile_t *fp);
void sortcommands(void);

Binary file not shown.

48
defs.h
View File

@ -17,6 +17,7 @@
// Text
#define TEXT_WARN_ATTACK_NOXP "You will not gain experience until you train. Really attack?"
#define TEXT_WARN_CLIMB "Really attempt to climb without Climbing skill?"
// Defaults
#define DEF_AIFOLLOWTIME (50) // if target lf is out of view
@ -663,6 +664,7 @@ enum CELLTYPE {
CT_NONE = 0,
// walls
CT_WALL,
CT_WALLDIRT,
CT_WALLFLESH,
CT_WALLGLASS,
CT_WALLMETAL,
@ -1087,6 +1089,8 @@ enum OBTYPE {
OT_HOLEINROOF,
OT_STAIRSDOWN,
OT_STAIRSUP,
OT_TUNNELDOWN,
OT_TUNNELUP,
OT_PORTAL,
OT_STOMACHEXIT,
// buildings - rememebr to update MAXBUILDINGTYPES!
@ -1980,6 +1984,7 @@ enum FLAG {
F_BEINGUSED, // this object is currently being used
F_DEAD, // object will be removed
F_ONEPERCELL, // only one of these objects can exist per cell
F_ONLYINROOM, // object nay only appear in rooms (not corridors)
F_CREATEDBY, // object was made by lf id v0, text=real lfname
F_CREATEDBYSPELL, // object was made by spell id v0
F_ENCHANTABLE, // object can get +1/-1 ect
@ -2078,9 +2083,9 @@ enum FLAG {
F_HASBRAND, // has the object mod v0 (ie. OM_FLAMESTRIKE)
F_HOLDCONFER, // gives flag v0+v1 when carried. v2 specifies if it must be id'd.
F_EQUIPCONFER, // gives flag v0+v1 when weilded/worn. v2 specifies if it must be id'd.
F_ACTIVATECONFER, // gives flag v0+v1 when activated. v2 specifies if it must be id'd.
F_ACTIVATEPREFIX, // when activated, prefix this objects name with
// text
F_ACTIVATECONFER, // gives flag v0+v1 when activated. v2 specifies if it must be id'd.
F_CRITKNOCKDOWN, // lf knocks down victims on a critical hit
F_HITCONFER, // hitting with this gives flagid=v0
@ -2859,7 +2864,11 @@ enum FLAG {
F_NOTIME, // this lf's actions don't take time
// skills
F_HASSKILL, // lf has skill v0 at level v1
F_PRACTICINGSKILL, // lf is pract skill v0
// if v2 is B_TRUE, it means we've used this
// skill since gaining/increasing it.
// (ie. it's a candidate for a random increase
// at levelup)
F_PRACTICINGSKILL, // lf is practicing skill v0
// COMBAT
F_MAXATTACKS, // v0 = min # attacks this lf can make per round
// v1 = max # attacks this lf can make per round
@ -3209,9 +3218,23 @@ typedef struct warning_s {
struct warning_s *next, *prev;
} warning_t;
enum OPTION {
OPT_ALWAYSSHOWTRAILS,
};
typedef struct option_s {
enum OPTION id;
char *text;
int letter;
int enabled;
int def;
struct option_s *next, *prev;
} option_t;
enum REGIONTYPE {
RG_CAVE,
RG_WORLDMAP,
RG_FIRSTDUNGEON,
RG_MAINDUNGEON,
RG_HEAVEN,
RG_PIT,
RG_SEWER,
@ -3219,14 +3242,15 @@ enum REGIONTYPE {
};
enum HABITAT {
H_DUNGEON = 1,
H_FOREST = 2,
H_HEAVEN = 3,
H_PIT = 4,
H_VILLAGE = 5,
H_SEWER = 6,
H_STOMACH = 7,
H_SWAMP = 8,
H_CAVE = 1,
H_DUNGEON = 2,
H_FOREST = 3,
H_HEAVEN = 4,
H_PIT = 5,
H_VILLAGE = 6,
H_SEWER = 7,
H_STOMACH = 8,
H_SWAMP = 9,
H_ALL = 999
};
@ -3238,6 +3262,7 @@ typedef struct regiontype_s {
int stairsperlev;
int deeperdir;
int majorbranch;
int depthmod;
struct regiontype_s *next, *prev;
} regiontype_t;
@ -3274,6 +3299,7 @@ typedef struct region_s {
regionoutline_t *outline;
struct region_s *parentregion;
int nthings; // is this used???
int depthmod;
struct region_s *next, *prev;
} region_t;

View File

@ -4,5 +4,12 @@ defs.h:
map.c:
initmap: define via addhabitat()
make a new function to create this kind of habitat
text.c:
update getregionname()
io.c:
update announcearrival()

103
io.c
View File

@ -71,6 +71,7 @@ extern objectclass_t *objectclass;
extern knowledge_t *knowledge;
extern objecttype_t *objecttype;
extern command_t *firstcommand;
extern option_t *firstoption,*lastoption;
extern vault_t *firstvault;
extern skill_t *firstskill;
@ -1121,8 +1122,8 @@ char *askstring(char *prompt, char punc, char *retbuf, int retBUFLEN, char *def)
void announcearrival(lifeform_t *lf, map_t *newmap) {
if (isplayer(lf)) {
if (newmap->region == RG_WORLDMAP) {
if (lf->cell->map->region == RG_WORLDMAP) {
if (newmap->region->rtype->id == RG_WORLDMAP) {
if (lf->cell->map->region->rtype->id == RG_WORLDMAP) {
msg("You arrive in a new area.");
} else {
msg("You arrive at the surface.");
@ -1135,6 +1136,15 @@ void announcearrival(lifeform_t *lf, map_t *newmap) {
(newmap->lastplayervisit == -1) ? "" : "back ",
newmap->depth);
break;
case H_CAVE:
if ((newmap->depth == 1) && (newmap->lastplayervisit == -1)) {
msg("You arrive at the goblin caves.");
} else {
msg("You arrive %sat level %d of the goblin caves.",
(newmap->lastplayervisit == -1) ? "" : "back ",
newmap->depth);
}
break;
case H_SWAMP:
msg("You arrive %sat a swamp.",
(newmap->lastplayervisit == -1) ? "" : "back ");
@ -2321,7 +2331,7 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
break;
case F_SPIDERCLIMB:
if (isplayer(lf)) {
msg("Your skin is no longet adhesive.");
msg("Your skin is no longer adhesive.");
donesomething = B_TRUE;
}
break;
@ -4375,21 +4385,28 @@ void dolook(cell_t *where, int onpurpose) {
numobs = 0;
numtrails = 0;
// first search for any non-trail objects.
for (o = where->obpile->first ; o ; o = o->next) {
if (!canseeob(player, o)) continue;
if (hasflag(o->flags, F_COSMETIC)) continue;
if (hasflag(o->flags, F_COSMETIC) && !onpurpose) continue;
// footprints/scents only count if there are no other obs here
if (!hasflag(o->flags, F_TRAIL)) {
// found a non-trail object
includetrails = B_FALSE;
break;
}
}
// now go through eech object...
for (o = where->obpile->first ; o ; o = o->next) {
if (!canseeob(player, o)) continue;
//if (hasflag(o->flags, F_SECRET)) continue;
if (hasflag(o->flags, F_COSMETIC)) continue;
if (!includetrails && hasflag(o->flags, F_TRAIL)) continue;
if (hasflag(o->flags, F_COSMETIC) && !onpurpose) continue;
if (hasflag(o->flags, F_TRAIL)) {
if (!includetrails) continue;
// ignore it if we're have 'show trails' turned off
if (!onpurpose && !getoption(OPT_ALWAYSSHOWTRAILS)) continue;
//if (!onpurpose) continue;
}
f = hasflag(o->flags, F_THEREISHERE);
if (f) {
@ -4473,7 +4490,7 @@ void dolook(cell_t *where, int onpurpose) {
seensomething = B_TRUE;
}
if (!seensomething) {
if (!seensomething && onpurpose) {
// just clear the message buffer
//clearmsg();
if (isblind(player)) {
@ -6698,6 +6715,65 @@ void dooperate(obpile_t *op) {
}
}
void dooptions(void) {
char buf[BUFLEN];
char part1[BUFLEN];
char promptstr[BUFLEN],cmdchars[BUFLENSMALL];
char ch;
int y,h,done = B_FALSE;
option_t *opt;
h = getmaxy(mainwin);
sprintf(promptstr, "Press letters to toggle options or ESC when done");
strcpy(cmdchars, "");
for (opt = firstoption ; opt ; opt = opt->next) {
char thislet[2];
sprintf(thislet, "%c", opt->letter);
strcat(cmdchars, thislet);
}
curs_set(0);
while (!done) {
cls();
centre(mainwin,C_WHITE, 0, "OPTIONS");
y = 2;
ch = '\0';
for (opt = firstoption ; opt ; opt = opt->next) {
sprintf(part1, "%c - %s", opt->letter, opt->text);
sprintf(buf, "%-40s%s", part1, opt->enabled ? " ^gEnabled^n" : " ^BDisabled^n");
if (opt->enabled == opt->def) strcat(buf, " (default)");
wmove(mainwin, y, 0);
textwithcol(mainwin, buf);
if (opt->next && downline(&y, h, "INVENTORY", NULL, promptstr, cmdchars, &ch)) {
break;
}
}
if (!ch) {
centre(mainwin, C_WHITE, h-1, promptstr);
ch = getch();
}
if (ch == 27) {
done = B_TRUE;
} else {
// find option with this letter
for (opt = firstoption ; opt ; opt = opt->next) {
if (opt->letter == ch) {
// toggle it.
if (opt->enabled) opt->enabled = B_FALSE;
else opt->enabled = B_TRUE;
break;
}
}
}
}
curs_set(1);
restoregamewindows();
}
int dopickup(obpile_t *op, int forceask) {
int obcount;
//object_t *o = NULL;
@ -8356,9 +8432,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_NOPICKUP) ||
hasflag(o->flags, F_SHOP) ||
hasflag(o->flags, F_CLIMBABLE) ) {
if ( !hasflag(o->flags, F_COSMETIC)) {
stopnow = B_TRUE;
break;
}
@ -8738,6 +8812,9 @@ void handleinput(void) {
dooffer();
break;
// GAME FUNCTIONS
case '=': // options
dooptions();
break;
case 'Q': // quit
doquit();
break;
@ -10265,7 +10342,7 @@ void showlfstats(lifeform_t *lf, int showall) {
unsetcol(mainwin, lorecol);
} else {
setcol(mainwin, lorecol);
wrapprint(mainwin, &y, &x, "You would never be able to kill it. ");
wrapprint(mainwin, &y, &x, "You probably couldn't kill it. ");
unsetcol(mainwin, lorecol);
}
if (hitstokillyou) {
@ -10275,7 +10352,7 @@ void showlfstats(lifeform_t *lf, int showall) {
unsetcol(mainwin, lorecol);
} else {
setcol(mainwin, lorecol);
wrapprint(mainwin, &y, &x, "It would never be able to kill you. ");
wrapprint(mainwin, &y, &x, "It probably couldn't kill you. ");
unsetcol(mainwin, lorecol);
}
}

1
io.h
View File

@ -59,6 +59,7 @@ void domemmagic(void);
void domsghist(void);
void dooffer(void);
void dooperate(obpile_t *op);
void dooptions(void);
int dopickup(obpile_t *op, int forceask);
void donextguntarget(void);
void dopour(obpile_t *op);

99
lf.c
View File

@ -1410,6 +1410,10 @@ int cantalk(lifeform_t *lf) {
if (getattr(lf, A_IQ) <= AT_VLOW) {
return B_FALSE;
}
// beheaded?
if (lfhasflag(lf, F_BEHEADED)) {
return B_FALSE;
}
return B_TRUE;
}
@ -3407,15 +3411,25 @@ void enhancerandomskill(lifeform_t *lf) {
enum SKILL poss[MAXSKILLS];
int nposs = 0;
int sel;
enum SKILLLEVEL wantlev;
// enhance lower level skills first, and only up to PR_ADEPT.
for (wantlev = PR_NOVICE; wantlev <= PR_BEGINNER; wantlev++) {
for (f = lf->flags->first ; f ; f = f->next) {
if ((f->id == F_HASSKILL) && !ismaxedskill(lf, f->val[0])) {
if ((f->id == F_HASSKILL) && !ismaxedskill(lf, f->val[0]) && (f->val[1] == wantlev)) {
if (isplayer(lf) && (f->val[2] != B_TRUE)) {
// for player - select only from skills which we have used since last levelup.
} else {
poss[nposs] = f->val[0];
nposs++;
}
}
}
if (nposs > 0) {
sel = rnd(0,nposs-1);
giveskill(lf, poss[sel]);
break;
}
}
}
@ -3673,13 +3687,13 @@ void enhanceskills(lifeform_t *lf) {
f = levelabilityready(lf);
while (f) {
if (f->id == F_LEVABIL) {
addflag(lf->flags, F_CANWILL, f->val[1], f->val[2], f->val[2], f->text);
addtempflag(lf->flags, F_CANWILL, f->val[1], f->val[2], f->val[2], f->text, FROMJOB);
} else if (f->id == F_LEVFLAG) {
addflag(lf->flags, f->val[1], f->val[2], NA, NA, f->text);
addtempflag(lf->flags, f->val[1], f->val[2], NA, NA, f->text, FROMJOB);
} else if (f->id == F_LEVSKILL) {
giveskill(lf, f->val[1]);
} else if (f->id == F_LEVSPELL) {
addflag(lf->flags, F_CANCAST, f->val[1], NA, NA, NULL);
addtempflag(lf->flags, F_CANCAST, f->val[1], NA, NA, NULL, FROMJOB);
} else if (f->id == F_LEVSPELLSCHOOL) { // select a spell from school
if (isplayer(lf)) {
int done = B_FALSE;
@ -3693,7 +3707,7 @@ void enhanceskills(lifeform_t *lf) {
ot = prompt.result;
if (ot) {
if (prompt.whichq == 0) { // learn the spell
addflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL);
addtempflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL, FROMJOB);
done = B_TRUE;
} else {
describespell(ot);
@ -3712,7 +3726,7 @@ void enhanceskills(lifeform_t *lf) {
// pick one randomly
ot = (objecttype_t *)prompt.choice[rnd(0,prompt.nchoices)].data;
if (ot) {
addflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL);
addtempflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL, FROMJOB);
}
}
}
@ -8312,6 +8326,10 @@ void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype) {
int held = B_FALSE, equipped = B_FALSE,activated = B_FALSE;
int lifetimeval;
if (gettechlevel(o->type->id) > getskill(lf, SK_TECHUSAGE)) {
return;
}
if (o->pile->owner == lf) held = B_TRUE;
if (held) {
@ -8404,6 +8422,17 @@ void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype) {
flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
flag_t *f = NULL, *newf;
skill_t *sk;
int markasused = B_FALSE;
switch (id) {
case SK_CARTOGRAPHY:
case SK_PERCEPTION:
markasused = B_TRUE;
break;
default:
break;
}
if (lfhasflagval(lf, F_NOSKILL, id, NA, NA, NULL)) {
return NULL;
@ -8419,6 +8448,7 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
// already have the skill - make it better
if (f->val[1] < PR_MASTER) {
f->val[1]++;
f->val[2] = markasused;
}
if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) {
msg("^gYou have learned the %s %s skill!", getskilllevelname(f->val[1]), getskillname(sk->id));
@ -8427,7 +8457,7 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
statdirty = B_TRUE; // in case skill changes your stats
} else {
// gaining a new skill
f = addflag(lf->flags, F_HASSKILL, id, PR_NOVICE, NA, NULL);
f = addflag(lf->flags, F_HASSKILL, id, PR_NOVICE, markasused, NULL);
if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) {
msg("^gYou have learned the %s %s skill!", getskilllevelname(PR_NOVICE), getskillname(sk->id));
more();
@ -8628,16 +8658,25 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
// if objecttype has a tech level , and it is
// lower (or equal to) our tech knowledge...
if (tf && !isknownot(ot) && (tf->val[0] <= f->val[1])) {
object_t *o;
// then make it known!
makeknown(ot->id);
for (o = lf->pack->first ; o ; o = o->next) {
if (o->type->id == ot->id) {
if (isplayer(lf)) {
object_t *o;
o = hasob(lf->pack, ot->id);
if (o) {
char buf[BUFLEN];
getobname(o, buf, o->amt);
msgnocap("%c - %s", o->letter, buf);
}
// now confer effects...
giveobflags(lf, o, F_HOLDCONFER);
if (isactivated(o)) {
giveobflags(lf, o, F_ACTIVATECONFER);
}
if (isequipped(o)) {
giveobflags(lf, o, F_EQUIPCONFER);
}
}
}
}
}
@ -9661,7 +9700,6 @@ int lockpick(lifeform_t *lf, cell_t *targcell, object_t *target, object_t *devic
// take time
taketime(lf, getactspeed(lf) );
if (skillcheck(lf, SC_OPENLOCKS, difficulty, bonus )) {
// success!
// announce
@ -9705,8 +9743,10 @@ int lockpick(lifeform_t *lf, cell_t *targcell, object_t *target, object_t *devic
msg("%s fail%s to unlock %s.",lfname, isplayer(lf) ? "" : "s", obname);
}
}
practice(lf, SK_LOCKPICKING, 1);
return B_TRUE;
}
practice(lf, SK_LOCKPICKING, 1);
return B_FALSE;
}
@ -11148,6 +11188,7 @@ lifeform_t *makezombie(object_t *o) {
if (!cellwalkable(NULL, where, NULL)) {
where = getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND);
}
if (!where) return NULL;
lf = addlf(where, r->id, 1);
addflag(lf->flags, F_LFSUFFIX, B_TRUE, NA, NA, "zombie");
@ -12814,7 +12855,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume,
if (f) {
// can't hear while unconscious
if (f->val[1] == ST_KO) continue;
lbonus -= 4;
lbonus -= 6;
limit(&lbonus, 0, NA);
}
@ -12934,7 +12975,8 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume,
if (f->lifetime > 0) { // ie. temporary
timeeffectsflag(f, volume + rnd(1,3));
} else if (f->lifetime == PERMENANT) {
if (f->val[2] == NA) { // ie asleep rather than 'resting'
if (f->val[2] == NA) {
// ie asleep rather than 'resting'
// wake up!
if (isplayer(l)) {
msg("^wA nearby noise awakens you!");
@ -13275,6 +13317,10 @@ void practice(lifeform_t *lf, enum SKILL skid, int amt) {
sk = findskill(skid);
if (!sk) return;
// do this even if the skill is not 'trainable'
setskillused(lf, skid);
slev = getskill(lf, skid);
timeneeded = sk->traintime * (getskill(lf, skid)+1);
@ -13284,7 +13330,6 @@ void practice(lifeform_t *lf, enum SKILL skid, int amt) {
if (!canlearn(lf, skid)) return;
if (!slev || onein(slev)) {
// practice a little bit...
f = lfhasflagval(lf, F_PRACTICINGSKILL, skid, NA, NA, NULL);
if (f) {
@ -13747,6 +13792,14 @@ void relinklf(lifeform_t *src, map_t *dst) {
sortlf(dst, src);
}
void setskillused(lifeform_t *lf, enum SKILL skid) {
flag_t *f;
f = lfhasflagval(lf, F_HASSKILL, skid, NA, NA, NULL);
if (f) {
f->val[2] = B_TRUE;
}
}
int startclimbing(lifeform_t *lf) {
cell_t *where;
char lfname[BUFLEN];
@ -13816,9 +13869,11 @@ int startclimbing(lifeform_t *lf) {
} else if (cansee(player, lf)) {
msg("%s tries to start climbing, but fails.", lfname);
}
practice(lf, SK_CLIMBING, 1);
return B_TRUE;
}
}
practice(lf, SK_CLIMBING, 1);
return B_FALSE;
}
@ -16753,7 +16808,22 @@ int tryclimb(lifeform_t *lf, cell_t *where, char *towhat) {
// to climb up
int adjwalls;
char lfname[BUFLEN];
// climbing without climb skill?
if (isplayer(lf) &&
!getskill(lf, SK_CLIMBING) &&
!lfhasflag(lf, F_SPIDERCLIMB) &&
!hasobwithflag(lf->pack, F_HELPSCLIMB)) {
// you are about to do something foolish!
if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) {
if (!warnabout(TEXT_WARN_CLIMB)) {
return B_TRUE;
}
}
}
getlfname(lf, lfname);
adjwalls = countadjwalls(where);
if (adjwalls || hasobwithflag(lf->pack, F_HELPSCLIMB)) {
if (isplayer(lf)) {
@ -17704,6 +17774,7 @@ int rest(lifeform_t *lf, int onpurpose) {
if (isplayer(lf)) {
pleasegodmaybe(R_GODMERCY, 1);
}
practice(lf, SK_FIRSTAID, 1);
}
}

1
lf.h
View File

@ -365,6 +365,7 @@ int recruit(lifeform_t *lf);
void refreshlevelabilities(lifeform_t *lf);
void relinklf(lifeform_t *src, map_t *dst);
int rest(lifeform_t *lf, int onpurpose);
void setskillused(lifeform_t *lf, enum SKILL skid);
int startclimbing(lifeform_t *lf);
int startresting(lifeform_t *lf, int willtrain);
int rollattr(enum ATTRBRACKET bracket);

327
map.c
View File

@ -676,7 +676,7 @@ void getroomedge(map_t *map, int roomid, int minx, int miny, int maxx, int maxy,
}
// if outlineid is -1, it's automatically assigned
region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid) {
region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid, int depthmod) {
region_t *a;
regionoutline_t *ro,*poss[MAXCANDIDATES];
int nposs = 0;
@ -707,6 +707,7 @@ region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid) {
a->id = id;
a->rtype = findregiontype(rtype);
a->parentregion = parent;
a->depthmod = depthmod;
if (outlineid == -1) {
// randomly assign a regionoutline
@ -781,7 +782,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) {
regiontype_t *addregiontype(enum REGIONTYPE id, char *name, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major, int depthmod) {
regiontype_t *a;
// add to the end of the list
@ -807,6 +808,7 @@ regiontype_t *addregiontype(enum REGIONTYPE id, char *name, enum HABITAT default
a->stairsperlev = stairsperlev;
a->deeperdir = deeperdir;
a->majorbranch = major;
a->depthmod = depthmod;
return a;
}
@ -1496,6 +1498,7 @@ flag_t *getmapcoords(map_t *m, int *x, int *y) {
int getmapdifficulty(map_t *m) {
int diff = 1;
if (m) {
if (isoutdoors(m)) {
int x,y;
@ -1505,6 +1508,10 @@ int getmapdifficulty(map_t *m) {
} else {
diff = m->depth;
}
if (m->region) {
diff += m->region->rtype->depthmod;
diff += m->region->depthmod;
}
} else {
diff = rnd(1,MAXDEPTH);
}
@ -1653,7 +1660,7 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int
int nposs = 0;
cell_t *cell;
int sel;
int db = B_TRUE;
int db = B_FALSE;
int foundvalid = B_FALSE;
// init coords list
@ -1692,6 +1699,7 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int
if (hasobwithflag(cell->obpile, F_CLIMBABLE)) {
valid = B_FALSE;
}
/*
// - overlap the inside of an existing room
if (cellwalkable(NULL, cell, NULL) && isroom(cell)) {
valid = B_FALSE;
@ -1700,6 +1708,11 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int
if (cell->room && cell->room->vault) {
valid = B_FALSE;
}
*/
// - overlap any part of an existing room/vault
if (cell->room) {
valid = B_FALSE;
}
// is this cell adjacent to an empty cell and not a
// corner (ie. a valid door location)
@ -1897,6 +1910,153 @@ int countmapobs(map_t *m, enum OBTYPE oid) {
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 db = B_TRUE;
enum CELLTYPE emptycell,solidcell;
// parameters
int minrooms = 0;
int maxrooms = 3;
int numstartpos = 5;
int numpasses = 50;
// fill entire maze with walls
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
addcell(map, x, y);
}
}
// is the map lit?
if (depth == 1) {
map->lit = B_TRUE;
} else {
int darkchance;
darkchance = depth*15; // ie. level 2 = 30% chance of being dark, level 6 = 90% chance
if (pctchance(darkchance)) {
map->lit = B_FALSE;
} else {
map->lit = B_TRUE;
}
}
// what kind of cells will 'empty' ones be?
emptycell = map->habitat->emptycelltype;
solidcell = map->habitat->solidcelltype;
// pick initial random points
for (i = 0; i < numstartpos; i++) {
c = getrandomcell(map);
setcelltype(c, emptycell);
}
expand_cave(map, numpasses);
// adjust min/maxrooms based on fixed vaults
minrooms -= map->nfixedrooms;
maxrooms -= map->nfixedrooms;
limit(&minrooms, 0, NA);
limit(&maxrooms, 0, NA);
// create rooms
if (wantrooms && (maxrooms > 0)) {
numrooms = rnd(minrooms, maxrooms);
for (i = 0; i < numrooms; i++) {
// maybe make it a special room
if (rnd(1,100) <= map->habitat->randvaultpct) {
vault_t *v;
v = getvaulttype(map);
if (!createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) {
// success
continue;
}
}
// just do a normal room
calcposandmakeroom(map, map->nrooms, NA, NA, DEF_VAULTMARGIN, DEF_VAULTMARGIN, NULL, NULL, NULL, NULL, 50, B_FALSE);
//roomvault[i] = B_FALSE;
}
}
// link up room exits
/*
for (i = 0; i < map->nrooms; i++) {
int wantlink = B_FALSE;
if (!map->room[i].exitslinked) {
if (map->room[i].vault && hasflag(map->room[i].vault->flags, F_VAULTNOLINK)) {
} else {
wantlink = B_TRUE;
}
}
if (wantlink) {
linkexits(map, map->room[i].id);
}
}
*/
// 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++) {
// n
c = getcellat(map, x, 0);
clearcell(c);
setcelltype(c,solidcell);
// s
c = getcellat(map, x, map->h-1);
clearcell(c);
setcelltype(c,solidcell);
}
for (y = 1; y < map->h-1; y++) {
// w
c = getcellat(map, 0, y);
clearcell(c);
setcelltype(c,solidcell);
// e
c = getcellat(map, map->w-1, y);
clearcell(c);
setcelltype(c,solidcell);
}
}
//
void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) {
int wantrooms = B_TRUE;
@ -2158,13 +2318,17 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
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_FIRSTDUNGEON) {
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
@ -2177,7 +2341,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
} else {
for (i = 0; i < map->region->rtype->stairsperlev; i++) {
c = NULL;
while (!isempty(c) || countobs(c->obpile, B_TRUE)) {
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.
@ -2288,10 +2452,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
// river?
// TODO FIX
//if ((depth >= 4) && pctchance(20)) {
//if (depth > 1) {
if (0) {
if ((depth >= 4) && pctchance(20)) {
createriver(map);
}
@ -2416,6 +2577,9 @@ void createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir, object_
case H_DUNGEON:
createdungeon(map, depth, parentmap, exitdir, entryob);
break;
case H_CAVE:
createcave(map, depth, parentmap, exitdir, entryob);
break;
case H_FOREST:
createforest(map, depth, parentmap, exitdir, entryob, rnd(0,5));
break;
@ -2683,7 +2847,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
matched = B_TRUE;
}
} else { // match on depth
if (region->outline->thing[i].depth == getmapdifficulty(map)) {
if (region->outline->thing[i].depth == map->depth) {
matched = B_TRUE;
}
}
@ -2795,6 +2959,12 @@ 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);
}
// special cases
// village - add town walls and clear it out
if (db) dblog(" finalising village creation...");
@ -2967,18 +3137,31 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
}
//if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging
// add random objects and monsters
// add random objects and monsters , and remove
// bad objects
if (db) dblog(" adding random objects+monsters");
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
cell_t *c;
c = getcellat(map, x, y);
// no random obs in vaults
if (c && isempty(c) && !getcellvault(c)) {
if (c) {
// add random obs, but not in vaults
if (isempty(c) && !getcellvault(c)) {
if (rnd(1,100) <= c->habitat->randthingpct) {
addrandomthing(c, c->habitat->randobpct, NULL);
}
}
// remove bad objects
if (!c->room) {
object_t *o,*nexto;
for (o = c->obpile->first ; o ; o = nexto) {
nexto = o->next;
if (hasflag(o->flags, F_ONLYINROOM)) {
killob(o);
}
}
}
}
}
}
//if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging
@ -3257,7 +3440,6 @@ void createsewer(map_t *map, int depth, map_t *parentmap, int exitdir, object_t
assert(f);
f->val[1] = map->region->parentregion->id;
linkstairs(o, entryob);
}
void createstomach(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) {
@ -4013,8 +4195,12 @@ void createpit(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *e
void createregionlink(map_t *m, cell_t *c, object_t *o, char *obname, enum REGIONTYPE newregiontype, region_t *parent) {
flag_t *f;
region_t *r;
// create a new region
r = addregion(newregiontype, m->region, -1);
int basedepth = 0;
if (newregiontype != RG_MAINDUNGEON) {
basedepth = getmapdifficulty(m);
}
// create a new region.
r = addregion(newregiontype, m->region, -1, basedepth);
// add stairs going to the new region, if required
if (!c) {
c = NULL;
@ -4298,7 +4484,7 @@ void dumpoutlines(void) {
if (rt->whatkind == RT_REGIONLINK) {
regiontype_t *rtype;
rtype = findregiontype(rt->value);
dblog(" at %s: link to %s",loctext, rtype->name);
dblog(" at %s: link to %s (%s)",loctext, rtype->name, rt->what);
} else if (rt->whatkind == RT_HABITAT) {
habitat_t *h;
h = findhabitat(rt->value);
@ -4380,6 +4566,31 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int
}
}
void expand_cave(map_t *map, int numpasses) {
int n,x,y,dir;
cell_t *c;
for (n = 0; n < numpasses; n++) {
// for each dug map cell, 25% chance of clearing each adjacent cell
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
c = getcellat(map, x, y);
if (!c->type->solid && !c->visited) { // cell is empty and not processed already?
cell_t *c2;
// check for surrounding solid cells
for (dir = DC_N; dir <= DC_NW; dir++) {
c2 = getcellindir(c, dir);
if (c2 && c2->type->solid && pctchance(25)) {
setcelltype(c2, map->habitat->emptycelltype);
}
}
// mark cell as processed
c->visited = B_TRUE;
}
}
}
}
}
// this should never be called directly - only from explodecells().
// (otherwise knockback effect won't happen)
void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *centre) {
@ -4827,66 +5038,6 @@ int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved) {
}
char *getregionname(char *buf, map_t *m, int withlevel) {
region_t *r;
r = m->region;
if (withlevel) {
flag_t *f;
int x,y;
f = hasflag(m->flags, F_MAPCOORDS);
if (f) {
x = f->val[0];
y = f->val[1];
} else {
x = NA;
y = NA;
}
switch (r->rtype->id) {
case RG_WORLDMAP:
snprintf(buf, BUFLEN, "the surface(%d,%d)",x,y);
break;
case RG_FIRSTDUNGEON:
snprintf(buf, BUFLEN, "dungeon L%d", m->depth);
break;
case RG_HEAVEN:
snprintf(buf, BUFLEN, "the realm of gods");
break;
case RG_PIT:
snprintf(buf, BUFLEN, "a pit L%d", m->depth);
break;
case RG_SEWER:
snprintf(buf, BUFLEN, "a sewer L%d", m->depth);
break;
case RG_STOMACH:
snprintf(buf, BUFLEN, "a stomach");
break;
}
} else {
switch (r->rtype->id) {
case RG_WORLDMAP:
strcpy(buf, "the surface");
break;
case RG_FIRSTDUNGEON:
strcpy(buf, "the dungeon");
break;
case RG_HEAVEN:
snprintf(buf, BUFLEN, "the realm of gods");
break;
case RG_PIT:
snprintf(buf, BUFLEN, "a pit");
break;
case RG_SEWER:
snprintf(buf, BUFLEN, "a sewer");
break;
case RG_STOMACH:
snprintf(buf, BUFLEN, "a stomach");
break;
}
}
return buf;
}
cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand) {
return real_getrandomadjcell(c, wantempty, allowexpand, LOF_NEED, NULL, NULL);
@ -5270,6 +5421,7 @@ void initmap(void) {
// habitats
// thingchance, obchance, vaultchance, maxvisrange
addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 30, 6);
addhabitat(H_CAVE, "cave", CT_DIRT, CT_WALLDIRT, 5, 60, 10, 6);
addhabitat(H_FOREST, "forest", CT_GRASS, CT_WALL, 3, 75, 0, MAXVISRANGE);
addhabitat(H_HEAVEN, "heaven", CT_CORRIDOR, CT_WALL, 0, 0, 0, MAXVISRANGE);
addhabitat(H_PIT, "pit", CT_CORRIDOR, CT_WALL, 0, 0, 0, 5);
@ -5281,6 +5433,7 @@ 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);
addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, B_SOLID, B_TRANS, MT_GLASS, 0, 150);
@ -5299,18 +5452,19 @@ void initmap(void) {
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);
addregiontype(RG_FIRSTDUNGEON, "First Dungeon", H_DUNGEON, 25, 3, D_DOWN, B_TRUE);
addregiontype(RG_HEAVEN, "Realm of Gods", H_HEAVEN, 1, 0, D_NONE, B_FALSE);
addregiontype(RG_PIT, "Pit", H_PIT, 1, 1, D_DOWN, B_FALSE);
addregiontype(RG_SEWER, "Sewer", H_SEWER, 1, 0, D_NONE, B_FALSE);
addregiontype(RG_STOMACH, "Stomach", H_STOMACH, 1, 0, D_NONE, B_FALSE);
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);
// MAPMAPMAPMAP
// region definitions (outlines)
addregionoutline(RG_WORLDMAP);
// link to first dungeon
addregionthing(lastregionoutline, NA, 0, 0, RT_REGIONLINK, RG_FIRSTDUNGEON, "staircase going down");
addregionthing(lastregionoutline, NA, 0, 0, RT_REGIONLINK, RG_MAINDUNGEON, "staircase going down");
// four villages
for (i = 0; i < 4; i++) {
vx[i] = 0; vy[i] = 0;
@ -5337,8 +5491,10 @@ void initmap(void) {
//vx = 0; vy = -1;
addregionoutline(RG_FIRSTDUNGEON);
addregionoutline(RG_MAINDUNGEON);
addregionthing(lastregionoutline, 1, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISPLAYERSTART, NULL);
// l2-4: goblin caves
addregionthing(lastregionoutline, rnd(2,4), NA, NA, RT_REGIONLINK, RG_CAVE, "tunnel leading down");
// l6: jimbo's lair
addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair");
// l7 - 10: swamp
@ -5355,6 +5511,7 @@ void initmap(void) {
addregionthing(lastregionoutline, rnd(17,19), NA, NA, RT_OBJECT, NA, "random building");
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);
}
int isadjacent(cell_t *src, cell_t *dst) {

7
map.h
View File

@ -7,10 +7,10 @@ map_t *addmap(void);
lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int amt, int autogen, int *nadded);
object_t *addrandomob(cell_t *c);
int addrandomthing(cell_t *c, int obchance, int *nadded);
region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid);
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);
regiontype_t *addregiontype(enum REGIONTYPE id, char *name, 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,7 @@ 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);
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);
void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob, int nclearings);
@ -65,6 +66,7 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r
int dirtox(int dt, int dir);
int dirtoy(int dt, int dir);
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);
celltype_t *findcelltype(enum CELLTYPE cid);
@ -89,7 +91,6 @@ vault_t *getcellvault(cell_t *c);
cell_t *getclosestroomcell(lifeform_t *lf, int roomid);
int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved);
int getobchance(int habitat);
char *getregionname(char *buf, map_t *m, int withlevel);
int getthingchance(int habitat);
cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand);
cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob, lifeform_t *preferlos);

15
move.c
View File

@ -72,7 +72,7 @@ int ispossiblemove(lifeform_t *lf, int dir) {
object_t *inway = NULL;
switch (error) {
case E_OFFMAP:
if (lf->cell->map->region == RG_WORLDMAP) {
if (lf->cell->map->region->id == RG_WORLDMAP) {
return B_TRUE;
}
break;
@ -852,7 +852,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
// failed to move
switch (reason) {
case E_OFFMAP:
if (lf->cell->map->region == RG_WORLDMAP) {
if (lf->cell->map->region->id == RG_WORLDMAP) {
if (!walkoffmap(lf, dir, B_FALSE)) {
// successful
break;
@ -1021,7 +1021,7 @@ int moveeffects(lifeform_t *lf) {
int didmsg = B_FALSE;
if (lfhasflagval(lf, F_INJURY, IJ_HAMSTRUNG, NA, NA, NULL)) {
if (!skillcheck(lf, SC_FALL, 20, 0)) {
if (!skillcheck(lf, SC_FALL, 18, 0)) {
fall(lf, NULL, B_TRUE);
if (isplayer(lf)) didmsg = B_TRUE;
}
@ -1034,6 +1034,7 @@ int moveeffects(lifeform_t *lf) {
if (isbleeding(lf)) {
if (hasbleedinginjury(lf, BP_LEGS)) {
if (!bleedfrom(lf, BP_LEGS, B_FALSE)) {
if (isplayer(lf)) msg("^BYou bleed!");
losehp(lf, 1, DT_DIRECT, NULL, "blood loss");
}
} else {
@ -1050,6 +1051,7 @@ int moveeffects(lifeform_t *lf) {
for (i = 0; i < nretflags; i++) {
if (retflag[i]->lifetime == FROMRACE) {
if (!bleedfrom(lf, BP_WINGS, B_FALSE)) {
if (isplayer(lf)) msg("^BYou bleed!");
losehp(lf, 1, DT_DIRECT, NULL, "blood loss");
}
}
@ -1415,7 +1417,14 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
}
dointerrupt = B_TRUE;
// mark the observed race as known.
if (!lf->race->known) {
raceclass_t *rc;
lf->race->known = B_TRUE;
rc = findraceclass(lf->race->raceclass->id);
if (rc) {
practice(lf, getskill(lf, rc->skill), 2);
}
}
}
} else if (isplayer(lf)) {
if (areallies(lf, l)) {

21
nexus.c
View File

@ -48,6 +48,7 @@ buildingusage_t buildingusage[MAXBUILDINGTYPES];
int nbuildingusage = 0;
warning_t *firstwarning = NULL,*lastwarning = NULL;
option_t *firstoption = NULL,*lastoption = NULL;
int maxmonhitdice = 0; // highest number of hitdice for any monster
@ -244,17 +245,17 @@ int main(int argc, char **argv) {
newworld = B_TRUE;
// create world map.
wregion = addregion(RG_WORLDMAP, NULL, -1);
wregion = addregion(RG_WORLDMAP, NULL, -1, 0);
assert(wregion);
addmap();
createmap(firstmap, 1, wregion, NULL, D_NONE, NULL);
// create first dungeon
dregion = findregionbytype(RG_FIRSTDUNGEON);
dregion = findregionbytype(RG_MAINDUNGEON);
assert(dregion);
dmap = addmap();
createmap(dmap, 1, dregion, firstmap, D_DOWN, NULL);
// create heaven
hregion = addregion(RG_HEAVEN, NULL, -1);
hregion = addregion(RG_HEAVEN, NULL, -1, 0);
assert(hregion);
heaven = addmap();
createmap(heaven, 1, hregion, NULL, D_NONE, NULL);
@ -656,8 +657,9 @@ void cleanup(void) {
fclose(logfile);
cleanupgfx();
// free commands
// free commands & options
while (firstcommand) killcommand(firstcommand);
while (firstoption) killoption(firstoption);
// free maps (this will kill its lifeforms & obs & cells too)
while (firstmap) killmap(firstmap);
// free knowledge
@ -998,6 +1000,16 @@ void gethitdicerange(int depth, int *min, int *max, int range, int oodok) {
*max = mid + range; limit(max, *min, maxmonhitdice);
}
int getoption(enum OPTION id) {
option_t *opt;
for (opt = firstoption ; opt ; opt = opt->next) {
if (opt->id == id) {
if (opt->enabled) return B_TRUE;
}
}
return B_FALSE;
}
enum COLOUR getpctcol(float num, float max) {
float pct;
pct = (num / max) * 100;
@ -1084,6 +1096,7 @@ int init(void) {
// load npc names
loadnpcnames();
initoptions();
initcommands();
initobjects();
initskills();

View File

@ -12,6 +12,7 @@ void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, in
void donextturn(map_t *map);
warning_t *findwarning(char *text);
void gethitdicerange(int depth, int *min, int *max, int range, int oodok);
int getoption(enum OPTION id);
enum COLOUR getpctcol(float num, float max);
char getpctletter(float num, float max);
void getrarityrange(int depth, int *min, int *max, int range, int oodok);

View File

@ -1861,7 +1861,7 @@ void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int all
ot = findotn(name);
if (!ot) return;
getradiuscells(centre, radius, DT_ORTH, B_FALSE, LOF_WALLSTOP, B_FALSE, cell, &ncells, B_FALSE);
getradiuscells(centre, radius, DT_ORTH, B_FALSE, LOF_WALLSTOP, (radius == 0) ? B_TRUE : B_FALSE, cell, &ncells, B_FALSE);
for (i = 0; i < ncells; i++) {
c = cell[i];
@ -3538,6 +3538,7 @@ int getobspellpower(object_t *o, lifeform_t *lf) {
slev = getskill(lf, SK_CHANNELING);
power += slev;
if (slev >= PR_ADEPT) power += (slev - 2);
setskillused(lf, SK_CHANNELING);
}
// blessed objects are more powerful
if (isblessed(o)) power += 4;
@ -8211,6 +8212,9 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
}
} // end if techtype affected by gremlins
if (o->type->obclass->id == OC_TECH) {
setskillused(lf, SK_TECHUSAGE);
}
// mark obejct as tried
if (isplayer(lf)) maketried(o->type->id);
@ -8317,6 +8321,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
// increase based on your magic item usage skill
chanlev = getskill(lf, SK_CHANNELING);
setskillused(lf, SK_CHANNELING);
power += chanlev;
if (chanlev >= PR_ADEPT) power += (chanlev - 2);
@ -8661,7 +8666,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
} else if (o->type->id == OT_ORBDUNGEONEXIT) {
map_t *m;
m = lf->cell->map;
if ((m->region->rtype->id == RG_FIRSTDUNGEON) && (m->depth == 1)) {
if ((m->region->rtype->id == RG_MAINDUNGEON) && (m->depth == 1)) {
cell_t *cell[MAXCANDIDATES];
int ncells,i;
getradiuscells(lf->cell, 1, DT_COMPASS, B_FALSE, LOF_DONTNEED, B_TRUE, cell, &ncells, B_FALSE);
@ -11716,6 +11721,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
}
announcedmiss = B_TRUE;
}
practice(target, SK_EVASION, 1);
}
}
}
@ -11787,7 +11793,6 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
}
}
// special case
if (o->type->id == OT_RUBBERBULLET) {
dam = 1;

5
save.c
View File

@ -625,6 +625,7 @@ int loadregions(void) {
int rtid,nthings,i,n;
int numoutlines,numregions;
int db = B_FALSE;
int depthmod;
// TODO: check that map dir exists
snprintf(filename, BUFLEN, "%s/regions.dat",MAPDIR);
@ -674,8 +675,9 @@ int loadregions(void) {
fscanf(f, " outline:%d\n",&outlineid);
fscanf(f, " parentregion:%d\n",&parentid);
fscanf(f, " nthings:%d\n",&nthings);
fscanf(f, " depthmod:%d\n",&depthmod);
fscanf(f, "endregion\n");
r = addregion(rtid, (parentid == -1) ? NULL : findregion(parentid), outlineid);
r = addregion(rtid, (parentid == -1) ? NULL : findregion(parentid), outlineid, depthmod);
r->nthings = nthings;
if (db) dblog("Loaded region #%d / %d",n+1, numregions);
}
@ -1059,6 +1061,7 @@ int saveregions(void) {
fprintf(f, " outline:%d\n",r->outline ? r->outline->id : -1);
fprintf(f, " parentregion:%d\n",r->parentregion ? r->parentregion->id : -1);
fprintf(f, " nthings:%d\n",r->nthings);
fprintf(f, " depthmod:%d\n",r->depthmod);
fprintf(f, "endregion\n");
}
fclose(f);

View File

@ -362,6 +362,7 @@ enum SHOPRETURN shopdonate(lifeform_t *lf, object_t *vm, int starty, char *topte
newob = moveob(o, vm->contents, count);
newob->letter = let;
(*ndonated)++;
practice(player, SK_SPEECH, 1);
}
if ((vm->type->id == OT_TEMPLE) && goldgiven) {
@ -698,6 +699,7 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top
getobname(o, obname, shopamt);
snprintf(toptext, BUFLEN, "Purchased: %c - %s", o->letter, obname);
if (npurchased) (*npurchased)++;
practice(player, SK_SPEECH, 1);
} else {
msg("You don't seem to have any money..."); more();
o = NULL;
@ -724,6 +726,7 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top
getobname(o, obname, shopamt);
snprintf(toptext, BUFLEN, "Stolen: %c - %s", o->letter, obname);
practice(player, SK_THIEVERY, 1);
pleasegodmaybe(R_GODTHIEVES, (value/50));
o = NULL;
} else {

28
spell.c
View File

@ -128,12 +128,14 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
if (!range) {
int movespeed;
// get max range - based on speed.
range = (int) (((float)SP_NORMAL / (float)getmovespeed(user)) * 2.5);
if (range <= 1) {
movespeed = getmovespeed(user);
if (movespeed > SP_NORMAL) {
if (isplayer(user)) msg("You are too slow to charge!");
return B_TRUE;
}
range = 3 + ((SP_NORMAL - movespeed)/5);
}
if (!targcell) {
@ -636,6 +638,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// takes longer
taketime(user, getactspeed(user) * (ncooked-1));
}
practice(user, SK_COOKING, 1);
return B_FALSE;
}
@ -694,9 +697,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
msgnocap("%c - %s", o->letter, obname);
// take some time
taketime(user, getactspeed(user));
practice(user, SK_COOKING, 1);
} else {
// pack full?
msg("You have space to cook!");
msg("You have no space to cook!");
}
}
} else if (abilid == OT_A_DARKWALK) {
@ -1398,6 +1402,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
fall(user, NULL, B_TRUE);
}
}
practice(user, SK_ATHLETICS, 1);
} else if (abilid == OT_A_PICKLOCK) {
lockpick(user, NULL, NULL, NULL);
} else if (abilid == OT_A_RAGE) {
@ -1513,6 +1518,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
buf, withbuf);
}
practice(user, SK_METALWORK, 1);
practice(user, SK_SEWING, 1);
// TODO: make this like eating/resting/etc ?
taketime(user, getactspeed(user));
} else if (abilid == OT_A_RESIZE) {
@ -1624,7 +1631,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
more();
msgnocap("%c - %s", o->letter, obname);
practice(user, SK_METALWORK, 1);
practice(user, SK_SEWING, 1);
// TODO: make this like eating/resting/etc ?
taketime(user, getactspeed(user));
} else if (abilid == OT_A_SHIELDBASH) {
@ -2036,7 +2044,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// this map will be destroyed when you leave it.
r = findregionbytype(RG_STOMACH);
if (!r) {
r = addregion(RG_STOMACH, NULL, -1);
r = addregion(RG_STOMACH, NULL, -1, 0);
}
// create stomach map
newmap = addmap();
@ -2501,6 +2509,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_FALSE;
}
}
practice(user, SK_ATHLETICS, 1);
} else if (abilid == OT_A_POLYREVERT) {
flag_t *f;
if (!target) target = user;
@ -2928,6 +2937,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
getobname(o, obname, o->amt);
msgnocap("%c - %s", o->letter, obname);
practice(user, SK_METALWORK, 1);
practice(user, SK_SEWING, 1);
taketime(user, getactspeed(user));
} else if (abilid == OT_A_EXPOSEDSTRIKE) {
flag_t *f;
@ -3248,6 +3260,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// start hiding
addflag(user->flags, F_HIDING, penalty, NA, NA, NULL);
// even though it's untrainable - this will
// still mark it as used.
practice(user, SK_STEALTH, 1);
taketime(user, getactspeed(user));
} else if (abilid == OT_A_INSPECT) {
object_t *o;
@ -5943,7 +5959,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
getlfname(target, targname);
if (cansee(player, target)) {
msg("Magical vines grasp %s!",targname);
msg("Entangling vines rise up and grasp %s!",targname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}

67
text.c
View File

@ -925,6 +925,73 @@ char *getrarityname(enum RARITY rr) {
return "?unknownrarity?";
}
char *getregionname(char *buf, map_t *m, int withlevel) {
region_t *r;
r = m->region;
if (withlevel) {
flag_t *f;
int x,y;
f = hasflag(m->flags, F_MAPCOORDS);
if (f) {
x = f->val[0];
y = f->val[1];
} else {
x = NA;
y = NA;
}
switch (r->rtype->id) {
case RG_CAVE:
snprintf(buf, BUFLEN, "goblin caves L%d", m->depth);
break;
case RG_WORLDMAP:
snprintf(buf, BUFLEN, "the surface(%d,%d)",x,y);
break;
case RG_MAINDUNGEON:
snprintf(buf, BUFLEN, "dungeon L%d", m->depth);
break;
case RG_HEAVEN:
snprintf(buf, BUFLEN, "the realm of gods");
break;
case RG_PIT:
snprintf(buf, BUFLEN, "a pit L%d", m->depth);
break;
case RG_SEWER:
snprintf(buf, BUFLEN, "a sewer L%d", m->depth);
break;
case RG_STOMACH:
snprintf(buf, BUFLEN, "a stomach");
break;
}
} else {
switch (r->rtype->id) {
case RG_CAVE:
strcpy(buf, "the goblin caves");
break;
case RG_WORLDMAP:
strcpy(buf, "the surface");
break;
case RG_MAINDUNGEON:
strcpy(buf, "the dungeon");
break;
case RG_HEAVEN:
snprintf(buf, BUFLEN, "the realm of gods");
break;
case RG_PIT:
snprintf(buf, BUFLEN, "a pit");
break;
case RG_SEWER:
snprintf(buf, BUFLEN, "a sewer");
break;
case RG_STOMACH:
snprintf(buf, BUFLEN, "a stomach");
break;
}
}
return buf;
}
char *getreldirname(int reldir) {
switch (reldir) {
case RD_FORWARDS:

1
text.h
View File

@ -27,6 +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 *getreldirname(int reldir);
char *getsizetext(enum LFSIZE sz);
char *gettimetext(char *retbuf);