* [+] shallow water / deep water

- [+] copy getmovespeed() water code into getactspeed too.
- [+] CAN throw missiles or fire guns while swimming, but you have an
      accuracy penalty, and they go slower. 
* [+] can't cast spells while in the water
* [+] sk_swimming
- [+] new obclass - terrain - goes baove everythign
- [+] remember tarrain like dfeatures
- [+] replace cone of cold with cold ray which hits all objects in the
      path, but stops at the first lf.
- [+] towel - dries things off.
- [+] f_needswater - suffocate if you aren't in water.
- [+] l6 nature - FLOOD.
- [+] make water jet leave a water trail
* [+] water monsters ( non-grey ;)
- [+] add aquatic mosnters to flooded rooms. addmonsters needs to check
      for water.
* [+] SPEED UP the game. running very slowly now. switched ncusrses
      draw func.
- [+] fix crash when moving off forest map with DC_xx instead of D_xx
This commit is contained in:
Rob Pearce 2011-05-27 00:41:34 +00:00
parent 69982623ed
commit f4cdcae146
14 changed files with 2210 additions and 479 deletions

18
ai.c
View File

@ -565,6 +565,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
// see if we have a ranged attack. if so, adjust wantdist
// to maintain distance.
rangedob = aigetrangedattack(lf, &rangedattack);
if (rangedattack != RA_NONE) {
if (wantdistmin < 2) wantdistmin = 2;
if (wantdistmax < wantdistmin) wantdistmax = wantdistmin;
@ -575,7 +576,9 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
// try to get to our ideal range from them.
if (db) dblog(".oO { i am at distance %d, want to be at %d-%d }", dist, wantdistmin, wantdistmax);
if (dist > wantdistmax) {
if (db) dblog(".oO { moving towards target. }");
if (db) {
dblog(".oO { moving towards target. }");
}
if (!movetowards(lf, target->cell, DT_ORTH)) {
// success
return B_FALSE;
@ -813,6 +816,7 @@ void aiturn(lifeform_t *lf) {
}
*/
if (wantdb && lfhasflag(lf, F_DEBUG)) {
db = B_TRUE;
} else {
@ -1000,6 +1004,17 @@ void aiturn(lifeform_t *lf) {
target = findlf(lf->cell->map, targid);
if (target) {
if (db) dblog(".oO { my target is lfid %d (%s). }", targid, target->race->name);
// aquatic grabbers will try to drag their prey into the water
if (lfhasflagval(lf, F_GRABBING, target->id, NA, NA, NULL) && isaquatic(lf) ) {
if ( hasobwithflag(lf->cell->obpile, F_DEEPWATER) &&
!hasobwithflag(target->cell->obpile, F_DEEPWATER)) {
// move away!
if (!moveawayfrom(lf, target->cell, DT_ORTH)) {
return;
}
}
}
// try to move towards them.
if (!aimovetolf(lf, target, B_TRUE)) {
// success
return;
@ -1082,6 +1097,7 @@ void aiturn(lifeform_t *lf) {
}
// not attacking anyone in particular
if (db) dblog(".oO { i do not have a target or can't move towards it. looking for one. }");

View File

@ -647,7 +647,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (willheal) {
if (cansee(player, victim)) {
flag_t *f;
msg("%s is healed!",victimname);
msg("%s %s healed!",victimname, isplayer(victim) ? "are" : "is");
f = hasflag(wep->flags, F_BALANCE);
if (f) {
f->known = B_TRUE;

27
defs.h
View File

@ -419,6 +419,11 @@ enum CELLTYPE {
CT_ROOM,
};
enum SPECIALROOMTYPE {
RT_NONE = 0,
RT_FLOODED,
};
enum SPELLSCHOOL {
SS_NONE,
@ -529,6 +534,7 @@ enum DAMTYPE {
// Object Classes
enum OBCLASS {
OC_TERRAIN,
OC_MONEY,
OC_WEAPON,
OC_ARMOUR,
@ -582,6 +588,7 @@ enum RARITY {
enum RACECLASS {
RC_ANY, // not actually ever defined
RC_ANIMAL,
RC_AQUATIC,
RC_DEMON,
RC_HUMANOID,
RC_INSECT,
@ -635,6 +642,12 @@ enum RACE {
R_TROGLODYTE,
R_TROLL,
R_XAT,
// fish
R_CRAB,
R_PIRANHA,
R_PIRANHAKING,
R_EELELEC,
R_EELGIANT,
// plants
R_CACTUS,
R_DREAMFUNGUS,
@ -662,6 +675,7 @@ enum RACE {
R_SNAKECOBRA,
R_SNAKECONSTRICTOR,
R_SNAKETREE,
R_SNAKEWATER,
R_SPIDER,
R_SPIDERFUNNELWEB,
R_SPIDERREDBACK,
@ -756,6 +770,9 @@ enum OBTYPE {
OT_STAIRSUP,
OT_VENDINGMACHINE,
OT_PORTAL,
// terrain
OT_WATERSHALLOW,
OT_WATERDEEP,
// traps
OT_TRAPROCK,
OT_TRAPARROW,
@ -1024,6 +1041,7 @@ enum OBTYPE {
OT_S_IDENTIFY,
OT_S_MAPPING,
// -- elemental - air
OT_S_JOLT,
OT_S_AIRBLAST,
OT_S_CLOUDKILL,
OT_S_GUSTOFWIND,
@ -1040,7 +1058,7 @@ enum OBTYPE {
// -- elemental - ice
OT_S_CHILL,
OT_S_COLDBURST,
OT_S_CONECOLD,
OT_S_COLDRAY,
OT_S_FREEZEOB,
OT_S_FROSTBITE,
OT_S_ICEEDGE,
@ -1093,6 +1111,7 @@ enum OBTYPE {
OT_S_WEB,
OT_S_ENDUREELEMENTS,
OT_S_ENTANGLE,
OT_S_FLOOD,
OT_S_HAILSTORM,
OT_S_LIGHTNINGBOLT,
OT_S_LIGHTNINGSTORM,
@ -1182,6 +1201,7 @@ enum OBTYPE {
OT_PANPIPES,
OT_PICKAXE,
OT_TORCH,
OT_TOWEL,
// tech
OT_POCKETWATCH,
OT_C4,
@ -1214,8 +1234,6 @@ enum OBTYPE {
OT_SPLASHWATER,
OT_PUDDLEWATER,
OT_PUDDLEWATERL,
OT_WATERSHALLOW,
OT_WATERDEEP,
OT_ACIDSPLASH,
OT_ACIDPUDDLE,
OT_ACIDPOOL,
@ -1511,6 +1529,7 @@ enum FLAG {
F_UNIQUE, // only one may appear
F_GLYPH, // override the glyph with the first char of text.
// v0 is either NA (white) or colourid (C_xxx).
F_NOGLYPH, // this object doesn't appear normally
F_COSMETIC, // this object is mostly cosmetic, don't say 'you see xx'
F_NOPICKUP, // cannot pick this up
F_IMPASSABLE, // cannot walk past this if your size if v0 or smaller
@ -1979,6 +1998,7 @@ enum FLAG {
F_QUICKBITE, // deals v0 d d1 + d2 damage when you hit a bleeding victim
// (bypasses armour)
F_GRAVBOOSTED,// cannot walk or throw stuff
F_NEEDSWATER, // cannot survive out of deep water
F_PAIN, // take damage if you walk. v0=damtype,text is damage (xdy+z).
// if text not set, default dam is 1d2
F_PARALYZED,// cannot do anything
@ -2232,6 +2252,7 @@ enum ERROR {
E_PRONE = 54,
E_PENTAGRAM = 55,
E_SWIMMING = 56,
E_DANGEROUS = 57,
};

33
flag.c
View File

@ -24,6 +24,7 @@ flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
}
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known, long obfromid) {
lifeform_t *lf;
flag_t *f;
map_t *redolight = NULL;
int i;
@ -37,19 +38,26 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
return NULL;
}
lf = fp->owner;
if (gamemode == GM_GAMESTARTED) {
if ((id == F_PRODUCESLIGHT) || (id == F_ASLEEP) ) {
if (fp->owner && fp->owner->cell) {
if (fp->owner->cell->map == player->cell->map) {
redolight = fp->owner->cell->map;
}
if (id == F_PRODUCESLIGHT) {
if (lf && lf->cell && (lf->cell->map == player->cell->map)) {
// someone started producing light
redolight = lf->cell->map;
} else if (fp->ob) {
cell_t *obloc;
obloc = getoblocation(fp->ob);
if (obloc && (obloc->map == player->cell->map)) {
// an object started producing light
redolight = obloc->map;
}
}
} else if (id == F_ASLEEP) {
// someone fell asleep - ie their glyph will turn upsidedown
if (lf && (isplayer(lf) || cansee(player, lf))) {
redolight = lf->cell->map;
}
}
}
@ -195,10 +203,12 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
if ((gamemode == GM_GAMESTARTED) && (needredraw || statdirty || redolight)) {
if (redolight) {
dblog("CALCINGLIGHT from flag\n");
needredraw = B_TRUE;
calclight(redolight);
precalclos(player);
}
dblog("DRAWINGSCREEN from flag\n");
drawscreen();
}
return f;
@ -423,18 +433,23 @@ void killflag(flag_t *f) {
lf = f->pile->owner;
if (gamemode == GM_GAMESTARTED) {
if ((f->id == F_PRODUCESLIGHT) || (f->id == F_ASLEEP) ) {
if (lf && lf->cell) {
if (lf->cell->map == player->cell->map) {
if (f->id == F_PRODUCESLIGHT) {
if (lf && lf->cell && (lf->cell->map == player->cell->map)) {
// someone stopped producing light
redolight = lf->cell->map;
}
} else if (f->pile->ob) {
cell_t *obloc;
obloc = getoblocation(f->pile->ob);
if (obloc && (obloc->map == player->cell->map)) {
// an object stopped producing light
redolight = obloc->map;
}
}
} else if (f->id == F_ASLEEP) {
// someone woke up - ie their glyph will turn upsidedown
if (lf && (isplayer(lf) || cansee(player, lf))) {
redolight = lf->cell->map;
}
}
}

119
io.c
View File

@ -595,6 +595,10 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange,
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "prone");
}
if (isswimming(c->lf)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "swimming");
}
f = lfhasflag(c->lf, F_ATTACHEDTO);
if (lfhasflag(c->lf, F_ATTACHEDTO)) {
@ -821,6 +825,7 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange,
// move cursor selected position
wmove(gamewin, c->y - viewy, c->x - viewx);
curs_set(1);
redraw();
// get input
@ -936,6 +941,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
char buf[BUFLEN];
char *buf2;
if (isdead(player)) {
return B_FALSE;
}
if (!lf->born) {
return B_FALSE;
}
@ -1037,7 +1046,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
break;
case F_BREATHWATER:
if (isplayer(lf)) {
msg("%s can now breath underwater.",lfname);
msg("%s can now breath normally underwater.",lfname);
donesomething = B_TRUE;
}
break;
@ -1439,6 +1448,10 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
lifeform_t *lf2;
int donesomething = B_FALSE;
if (isdead(player)) {
return B_FALSE;
}
if (!lf->born) {
return B_FALSE;
}
@ -2009,7 +2022,7 @@ void announceobflagloss(object_t *o, flag_t *f) {
msg("%s %s no longer glowing.",prefix,isare);
break;
case F_WET:
msg("%s %s out.",prefix, (o->amt == 1) ? "dries" : "dry");
msg("%s %s now dry.",prefix, (o->amt == 1) ? "is" : "are");
break;
default: // no message
break;
@ -2673,6 +2686,7 @@ int updateviewfor(cell_t *cell) {
void drawscreen(void) {
int didstatus = B_FALSE;
int didredraw = B_FALSE;
if (gamemode < GM_GAMESTARTED) {
return;
}
@ -2688,9 +2702,10 @@ void drawscreen(void) {
updateviewfor(player->cell);
drawlevelfor(player);
//drawcursor(); // this will call redraw gamewin
didredraw = B_TRUE;
}
if (didstatus && !needredraw) {
if (didstatus && !didredraw) {
drawcursor();
}
}
@ -5023,7 +5038,8 @@ void drawglyph(glyph_t *g, int x, int y) {
col = g->colour;
}
setcol(gamewin, col);
mvwprintw(gamewin, y, x, "%lc", g->ch);
//mvwprintw(gamewin, y, x, "%lc", g->ch);
mvwaddch(gamewin, y, x, g->ch);
unsetcol(gamewin, col);
}
@ -5042,11 +5058,13 @@ void drawlevelfor(lifeform_t *lf) {
int ndrawn = 0;
int db = B_FALSE;
int w,h;
char buf[BUFLEN];
if (noredraw) {
return;
}
dbtimestart("drawscreen");
map = lf->cell->map;
needredraw = B_FALSE;
@ -5094,9 +5112,14 @@ void drawlevelfor(lifeform_t *lf) {
dblog("last x,y checked was %d,%d",x+viewx,y+viewy);
}
if (db) dblog("ending DRAWLEVEL");
sprintf(buf, "end. ndrawn was %d",ndrawn);
dbtimeend(buf);
// move cursor to the player's position and blit
if (ndrawn) {
drawcursor();
}
}
void doheading(WINDOW *win, int *y, int x, char *what) {
int len;
@ -6135,8 +6158,7 @@ void msg_real(char *format, ... ) {
// update msg window
drawmsg();
drawcursor();
//drawcursor();
}
int needsbold(enum COLOUR col) {
@ -6455,19 +6477,6 @@ void drawmsg(void) {
if (db) dblog("drawmsg called");
/*
if ( !strcmp(msgbuf, "") ) {
return;
}
if (!isplayerturn() && !msgmod) {
return;
}
*/
//dblog("calling drawmsg");
// is msgbuf has changed...
if (strcmp(msgbuf, lastmsgbuf) || msgmod) {
wclear(msgwin);
@ -6479,69 +6488,6 @@ void drawmsg(void) {
}
// drawcursor();
/*
// TODO: if it's a monster's turn, always do a more?
nexttok = strstr(msgbuf, "^");
if (!nexttok) {
// just update msg with current text
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s", msgbuf);
wrefresh(msgwin);
} else {
while (nexttok) {
char thistok[BUFLEN];
int thistoklen;
// print up to just before the "^" current token
// remember this token
thistoklen = nexttok - msgbuf;
strncpy(thistok, msgbuf, thistoklen);
thistok[thistoklen] = '\0';
if (db) dblog("drawmsg: thistok is [%s]",thistok);
// is there another token?
nexttok = strstr(msgbuf, "^");
if (nexttok) {
nexttok++; // go forward past the ^
if (db) dblog("drawmsg: nexttok is [%s]",nexttok);
// print with '--more--' added to the end
if (db) dblog("drawmsg: displaying thistok [%s]",thistok);
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s%s", thistok,MORESTRING);
wrefresh(msgwin);
// ...wait for spacebar before showing next bit...
while (getch() != ' ');
// we now know the player has read this
if (db) dblog("prompting for --more--");
// now clear msgstring up to end of where
// 'thistok' appears!
strcpy(msgbuf, nexttok);
if (db) dblog(" reduced msgbuf to: [%s]",msgbuf);
} else {
if (db) dblog("drawmsg: no nexttok");
// just print this bit
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s", thistok);
wrefresh(msgwin);
}
}
}
// clear message buffer
if (isplayerturn()) {
strcpy(msgbuf, "");
if (db) dblog("clearing msg buf");
}
*/
//msgmod = B_FALSE;
}
void redraw(void) {
@ -7886,8 +7832,7 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, buf);
y++;
}
f = lfhasknownflag(lf, F_BREATHWATER);
if (f) {
if (lfhasknownflag(lf, F_BREATHWATER) || lfhasknownflag(lf, F_AQUATIC)) {
mvwprintw(mainwin, y, 0, "%s can breath normally while underwater.", you(lf));
y++;
}
@ -8084,6 +8029,12 @@ void showlfstats(lifeform_t *lf, int showall) {
y++;
}
f = lfhasflag(lf, F_NEEDSWATER);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s will suffocate without water.", you(lf), is(lf));
y++;
}
f = lfhasflag(lf, F_PAIN);
if (f && (f->known)) {
if (isdrunk(lf)) {

382
lf.c
View File

@ -422,6 +422,10 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
reason = E_PRONE;
return B_FALSE;
}
if (isswimming(lf) && (getskill(lf, SK_SWIMMING) < PR_EXPERT)) {
reason = E_SWIMMING;
return B_FALSE;
}
reason = E_OK;
@ -1021,6 +1025,9 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
case E_PRONE:
msg("You can't cast spells while prone.");
break;
case E_SWIMMING:
msg("You can't cast spells while swimming.");
break;
default:
msg("For some reason, you can't cast that.");
break;
@ -1149,11 +1156,33 @@ int checkfordrowning(lifeform_t *lf, object_t *o) {
int depth,i;
int didsomething = B_FALSE;
flag_t *f;
enum SKILLLEVEL slev;
i = getskill(lf, SK_SWIMMING) - isburdened(lf);
limit(&i, 0, NA);
slev = i;
depth = getobdepth(o, lf);
// apply water damage (ie rust etc) to armour.
for (i = 0; i <= depth; i++) {
object_t *armour = NULL;
if (i == DP_FEET) {
armour = getouterequippedob(lf, BP_FEET); if (armour) takedamage(armour, 4, DT_WATER);
} else if (i == DP_WAIST) {
armour = getouterequippedob(lf, BP_LEGS); if (armour) takedamage(armour, 4, DT_WATER);
armour = getouterequippedob(lf, BP_WAIST); if (armour) takedamage(armour, 4, DT_WATER);
} else if (i == DP_SHOULDERS) {
armour = getouterequippedob(lf, BP_BODY); if (armour) takedamage(armour, 4, DT_WATER);
armour = getouterequippedob(lf, BP_SHOULDERS); if (armour) takedamage(armour, 4, DT_WATER);
} else if (i == DP_HEAD) {
armour = getouterequippedob(lf, BP_HEAD); if (armour) takedamage(armour, 4, DT_WATER);
}
}
// will you drown?
if (depth >= DP_HEAD) {
if (!getskill(lf, SK_SWIMMING) && !lfhasflag(lf, F_BREATHWATER)) {
if (!slev && !lfhasflag(lf, F_BREATHWATER)) {
// you drown.
if (isplayer(lf)) {
msg("You drown.");
@ -1170,22 +1199,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) {
}
}
// apply damage to armour now.
for (i = 0; i <= depth; i++) {
object_t *armour = NULL;
if (i == DP_FEET) {
armour = getouterequippedob(lf, BP_FEET); if (armour) takedamage(armour, 4, DT_WATER);
} else if (i == DP_WAIST) {
armour = getouterequippedob(lf, BP_LEGS); if (armour) takedamage(armour, 4, DT_WATER);
armour = getouterequippedob(lf, BP_WAIST); if (armour) takedamage(armour, 4, DT_WATER);
} else if (i == DP_SHOULDERS) {
armour = getouterequippedob(lf, BP_BODY); if (armour) takedamage(armour, 4, DT_WATER);
armour = getouterequippedob(lf, BP_SHOULDERS); if (armour) takedamage(armour, 4, DT_WATER);
} else if (i == DP_HEAD) {
armour = getouterequippedob(lf, BP_HEAD); if (armour) takedamage(armour, 4, DT_WATER);
}
}
if (!isdead(lf)) {
f = isvulnto(lf->flags, DT_WATER);
if (f) {
int dam;
@ -1196,6 +1210,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) {
}
applywalkdam(lf, dam, DT_WATER, o);
}
}
return didsomething;
}
@ -2927,6 +2942,8 @@ int getactspeed(lifeform_t *lf) {
break;
}
adjustspeedforwater(lf, &speed);
if (speed < 1) speed = 1;
return speed;
@ -3723,6 +3740,7 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) {
}
}
for (f = lf->flags->first ;f ; f = f->next) {
if (f->id == F_ACCURACYMOD) {
acc += f->val[0];
@ -3756,6 +3774,16 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) {
if (isprone(lf)) {
acc -= 30;
}
// modify for swimming
if (isswimming(lf) && !isaquatic(lf)) {
switch (getskill(lf, SK_SWIMMING)) {
// you can't attack until you are at
// expert or better.
default: acc = 0; break;
case PR_EXPERT: acc -= 20; break;
case PR_MASTER: break; // no penalty
}
}
// modify for drunkenness
f = isdrunk(lf);
@ -4141,7 +4169,6 @@ int getvisrange(lifeform_t *lf) {
int getmovespeed(lifeform_t *lf) {
int speed = 0;
object_t *o;
flag_t *f;
f = lfhasflag(lf, F_MOVESPEED);
@ -4182,36 +4209,7 @@ int getmovespeed(lifeform_t *lf) {
if (speed < 1) speed = 1;
if (!isairborne(lf)) {
for (o = lf->cell->obpile->first ; o ; o = o->next) {
f = hasflag(o->flags, F_REDUCEMOVEMENT);
if (f) {
if (hasflag(o->flags, F_DEEPWATER)) {
int modamt = 0;
// water
if (lfhasflag(lf, F_AQUATIC)) {
modamt = 0;
} else {
switch (getskill(lf, SK_SWIMMING)) {
default:
case PR_NOVICE:
case PR_INEPT: modamt = f->val[0]; break; // normal penalty
case PR_BEGINNER: modamt = f->val[0] - 2; break;
case PR_ADEPT: modamt = 0; break;
case PR_SKILLED: modamt = -1; break;
case PR_EXPERT: modamt = -2; break;
case PR_MASTER: modamt = -2; break;
}
}
limit(&modamt, 0, 5);
speed += (modamt * SPEEDUNIT);
} else {
// something else
speed += (f->val[0] * SPEEDUNIT);
}
}
}
}
adjustspeedforwater(lf, &speed);
return speed;
}
@ -4222,10 +4220,12 @@ char *getmoveverb(lifeform_t *lf) {
} else if (lfhasflag(lf, F_LEVITATING)) {
return "float";
}
if (lfhasflag(lf, F_FLEEFROM)) {
return "flee";
}
if (isswimming(lf)) {
return "swim";
}
return "walk";
}
@ -4608,7 +4608,7 @@ int getrandommonlevel(race_t *r, map_t *m) {
return wantlev;
}
race_t *getrandomrace(map_t *map, int forcedepth) {
race_t *getrandomrace(cell_t *c, int forcedepth) {
//int rarity;
race_t *r;
race_t *poss[MAXRANDOMLFCANDIDATES];
@ -4622,7 +4622,7 @@ race_t *getrandomrace(map_t *map, int forcedepth) {
if (forcedepth != NA) {
depth = forcedepth;
} else {
depth = getmapdifficulty(map);
depth = getmapdifficulty(c ? c->map : NULL);
}
getrarity(depth, &raritymin, &raritymax, RARITYVARIANCELF, B_TRUE);
@ -4641,8 +4641,8 @@ race_t *getrandomrace(map_t *map, int forcedepth) {
// correct rarity?
rarflag = hasflagval(r->flags, F_RARITY, H_ALL, NA, NA, NULL);
if (!rarflag) {
if (map) {
rarflag = hasflagval(r->flags, F_RARITY, map->habitat, NA, NA, NULL);
if (c) {
rarflag = hasflagval(r->flags, F_RARITY, c->map->habitat, NA, NA, NULL);
} else {
rarflag = hasflagval(r->flags, F_RARITY, NA, NA, NA, NULL);
}
@ -4654,6 +4654,21 @@ race_t *getrandomrace(map_t *map, int forcedepth) {
}
}
if (valid && c) {
// can it go into the cell?
if (hasobwithflag(c->obpile, F_DEEPWATER)) {
// water
if (!hasflag(r->flags, F_AQUATIC) && (r->raceclass->id != RC_AQUATIC)) {
// not aquatic
valid = B_FALSE;
}
} else {
// no water
if (hasflag(r->flags, F_NEEDSWATER)) {
valid = B_FALSE;
}
}
}
if (valid) {
if (db) dblog("-> possibility: %s, rarity=%d",r->name, rarflag->val[1]);
@ -5416,6 +5431,18 @@ int giveskill(lifeform_t *lf, enum SKILL id) {
msg("You can now hide even when monsters are nearby.");
}
}
} else if (id == SK_SWIMMING) {
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
if (f->val[1] == PR_NOVICE) {
msg("You can now swim.");
} else if ((f->val[1] >= PR_BEGINNER) && (f->val[1] <= PR_SKILLED)) {
msg("You can now swim a bit faster.");
} else if (f->val[1] == PR_EXPERT) {
msg("You can now attack awkwardly and cast spells while swimming.");
} else if (f->val[1] == PR_MASTER) {
msg("You can now attack while swimming with no penalty.");
}
}
} else if (id == SK_TECHUSAGE) {
objecttype_t *ot;
// automatically make known all tech <= our skill level
@ -5541,7 +5568,6 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) {
if (db) {
sprintf(buf2, "calling givestartobs for %s",lf->race->name);
dbtimestart(buf2);
}
// give start objects and id them
@ -5582,7 +5608,6 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) {
if (f->id == F_STARTOB) {
assert(strlen(f->text) > 0);
if (db) dbtime(f->text);
if (rnd(1,100) <= f->val[0]) {
o = addob(lf->pack, f->text);
}
@ -5591,14 +5616,12 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) {
int counter = 0;
if (db) {
sprintf(buf2, "calling startobdt");
dbtime(buf2);
}
while (!getrandomobwithdt(lf->cell->map, f->val[1], buf)) {
counter++;
}
if (db) {
sprintf(buf2, "finished startobdt (needed %d tries)", counter);
dbtime(buf2);
}
//assert(strlen(buf) > 0);
o = addob(lf->pack, buf);
@ -5608,7 +5631,6 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) {
int counter = 0;
if (db) {
sprintf(buf2, "calling startobclass");
dbtime(buf2);
}
//obdb = B_TRUE;
while (!getrandomobwithclass(lf->cell->map, f->val[1], buf, f->val[2])) {
@ -5617,7 +5639,6 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) {
//obdb = B_FALSE;
if (db) {
sprintf(buf2, "finished startobclass (needed %d tries)", counter);
dbtime(buf2);
}
//if (strlen(buf) <= 0);
o = addob(lf->pack, buf);
@ -5641,17 +5662,14 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) {
}
// now remove startob flags so we don't get them again!
if (db) dbtime("killing startflags");
killflagsofid(fp, F_STARTOB);
killflagsofid(fp, F_STARTOBDT);
killflagsofid(fp, F_STARTOBCLASS);
if (db) dbtime("finished killing startflags");
// make sure lf doesn't start off burdened!
while (isburdened(lf)) {
modattr(lf, A_STR, 1); // get stronger
}
if (db) dbtimeend("done.");
}
void givestartskills(lifeform_t *lf, flagpile_t *fp) {
@ -6382,6 +6400,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LOCKPICKING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_AXES, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LONGBLADES, NA, NA, NULL);
@ -6412,9 +6431,10 @@ void initjobs(void) {
addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL);
addflag(lastjob->flags, F_STARTATT, A_CON, CN_HEALTHY, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_ADEPT, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_FIRSTAID, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_BEGINNER, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_TRACKING, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, NA, NA, NULL);
@ -6442,6 +6462,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL);
// gained skills
@ -6463,8 +6484,10 @@ void initjobs(void) {
addflag(lastjob->flags, F_EVASION, 30, NA, NA, NULL);
addflag(lastjob->flags, F_OBESE, B_TRUE, NA, NA, NULL);
addflag(lastjob->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SPELLCASTING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SS_FIRE, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SS_COLD, NA, NA, NULL);
@ -6482,6 +6505,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_BEGINNER, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
@ -6515,6 +6539,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_UNARMED, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_ADEPT, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
@ -6542,6 +6567,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_TRACKING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL);
@ -6610,7 +6636,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_IFPCT, 50, NA, NA, NULL);
addflag(lastjob->flags, F_CANCAST, OT_S_FIREDART, NA, NA, NULL);
addflag(lastjob->flags, F_IFPCT, 50, NA, NA, NULL);
addflag(lastjob->flags, F_CANCAST, OT_S_CONECOLD, NA, NA, NULL);
addflag(lastjob->flags, F_CANCAST, OT_S_COLDRAY, NA, NA, NULL);
addflag(lastjob->flags, F_IFPCT, 33, NA, NA, NULL);
addflag(lastjob->flags, F_CANCAST, OT_S_HEALINGMIN, NA, NA, NULL);
addflag(lastjob->flags, F_IFPCT, 33, NA, NA, NULL);
@ -6628,6 +6654,7 @@ void initrace(void) {
// race classes
addraceclass(RC_OTHER, "misc. creature", "miscellaneous creatures", SK_NONE);
addraceclass(RC_ANIMAL, "animal", "animals and insects", SK_LORE_NATURE);
addraceclass(RC_AQUATIC, "aquatic creature", "aquatic creatures", SK_LORE_NATURE);
addraceclass(RC_DEMON, "demon", "demons", SK_LORE_DEMONS);
addraceclass(RC_HUMANOID, "humanoid", "humanoid creatures", SK_LORE_HUMANOID);
addraceclass(RC_INSECT, "insect", "insects and animals", SK_LORE_NATURE);
@ -7679,7 +7706,104 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
// end monsters
// fish
addrace(R_CRAB, "giant crab", 250, ';', C_ORANGE, MT_FLESH, RC_AQUATIC);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
addflag(lastrace->flags, F_ARMOURRATING, 20, NA, NA, NULL); // very high armour
addflag(lastrace->flags, F_HITDICE, 4, 4, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_VERYSLOW, NA, NA, "");
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d4");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d4");
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WAIST, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
addrace(R_PIRANHA, "piranha", 0.5, ';', C_GREEN, MT_FLESH, RC_AQUATIC);
addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_TINY, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 1, -2, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, "");
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WAIST, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2");
addrace(R_PIRANHAKING, "king piranha", 1, ';', C_GREEN, MT_FLESH, RC_AQUATIC);
addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_TINY, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 2, 2, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, "");
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WAIST, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6");
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;");
addrace(R_EELELEC, "electric eel", 120, ';', C_CYAN, MT_FLESH, RC_AQUATIC);
addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 2, 0, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WAIST, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, NA, NA, "1d6");
addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL);
addrace(R_EELGIANT, "giant eel", 150, ';', C_BLUE, MT_FLESH, RC_AQUATIC);
addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 5, 0, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WAIST, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;");
// plants
addrace(R_CACTUS, "cactus", 30, 'F', C_YELLOW, MT_PLANT, RC_PLANT);
@ -8069,6 +8193,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain");
addrace(R_LEECH, "giant leech", 10, 'j', C_MAGENTA, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
@ -8263,6 +8388,31 @@ void initrace(void) {
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;");
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addrace(R_SNAKEWATER, "water snake", 3, 's', C_BLUE, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, 85, NA, "");
addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, "");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4+1");
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing");
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addrace(R_SPIDER, "giant spider", 5, 'S', C_GREY, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, 87, NA, "");
@ -8674,6 +8824,7 @@ void initrace(void) {
}
int isairborne(lifeform_t *lf) {
if (!lf) return B_FALSE;
if (lfhasflag(lf, F_FLYING)) {
return B_TRUE;
} else if (lfhasflag(lf, F_LEVITATING)) {
@ -8682,6 +8833,15 @@ int isairborne(lifeform_t *lf) {
return B_FALSE;
}
int isaquatic(lifeform_t *lf) {
if (lf->race->raceclass->id == RC_AQUATIC) {
return B_TRUE;
} else if (lfhasflag(lf, F_AQUATIC)) {
return B_TRUE;
}
return B_FALSE;
}
int isbleeding(lifeform_t *lf) {
float hppct;
hppct = ((float)lf->hp / (float) lf->maxhp) * 100;
@ -9115,14 +9275,13 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) {
map_t *m;
lifeform_t *a;
int i;
int db = B_FALSE;
//int db = B_FALSE;
assert(cell);
if (cell->type != (celltype_t *) DUMMYCELLTYPE) {
assert(!cell->type->solid);
}
if (db) dbtimestart("startime addlf");
m = cell->map;
@ -9203,9 +9362,7 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) {
// set race - this will inherit race flags
a->race = NULL;
if (db) dbtime("before setrace done.");
setrace(a, rid, B_FALSE);
if (db) dbtime("setrace done.");
// update other things
@ -9213,16 +9370,13 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) {
// give start objetcs
if ((gamemode != GM_LOADING) && (gamemode != GM_VALIDATION)) {
if (db) dbtime("about to outfitlf.");
outfitlf(a);
if (db) dbtime("done outfitlf.");
}
a->created = B_TRUE;
a->born = B_TRUE; // now finished creating it.
if ((gamemode == GM_GAMESTARTED) && cansee(player, a)) {
needredraw = B_TRUE;
}
if (db) dbtimeend("addlf");
return a;
}
@ -9374,6 +9528,41 @@ void addtrail(lifeform_t *lf, int dir) {
}
}
void adjustspeedforwater(lifeform_t *lf, int *speed) {
object_t *o;
flag_t *f;
if (!isairborne(lf)) {
for (o = lf->cell->obpile->first ; o ; o = o->next) {
f = hasflag(o->flags, F_REDUCEMOVEMENT);
if (f) {
if (hasflag(o->flags, F_DEEPWATER)) {
int modamt = 0;
// water
if (isaquatic(lf)) {
modamt = 0;
} else {
switch (getskill(lf, SK_SWIMMING)) {
default:
case PR_NOVICE:
case PR_INEPT: modamt = f->val[0]; break; // normal penalty
case PR_BEGINNER: modamt = f->val[0] - 2; break;
case PR_ADEPT: modamt = 0; break;
case PR_SKILLED: modamt = -1; break;
case PR_EXPERT: modamt = -2; break;
case PR_MASTER: modamt = -2; break;
}
}
limit(&modamt, 0, 5);
*speed += (modamt * SPEEDUNIT);
} else {
// something else
*speed += (f->val[0] * SPEEDUNIT);
}
}
}
}
}
void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) {
flag_t *f;
if (isimmuneto(lf->flags, damtype)) {
@ -9745,6 +9934,10 @@ void autotarget(lifeform_t *lf) {
}
int isswimming(lifeform_t *lf) {
if (!lf) return B_FALSE;
if (gamemode != GM_GAMESTARTED) {
return B_FALSE;
}
if (!isairborne(lf) &&
hasobwithflag(lf->cell->obpile, F_DEEPWATER) &&
getskill(lf, SK_SWIMMING)) {
@ -10602,19 +10795,13 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete
// give initial equiment / skills to a lifeform
void outfitlf(lifeform_t *lf) {
int db = B_FALSE;
if (db) dbtimestart("outfitlf");
//int db = B_FALSE;
givestartobs(lf, lf->flags);
if (db) dbtime("finished giveobs");
givestartskills(lf, lf->flags);
if (db) dbtime("finished givestartskills");
autoskill(lf);
if (db) dbtime("finished autoskill");
// weild/wear stuff
autoweild(lf);
if (db) dbtime("finished autoweild");
if (db) dbtimeend("outfitlf done");
}
@ -12147,6 +12334,11 @@ void stoprunning(lifeform_t *lf) {
if (f) {
killflag(f);
}
f = lfhasflag(lf, F_SPRINTING);
if (f && f->val[0]) {
killflag(f);
}
}
// if this object is ammo, and we are using a gun
@ -12236,6 +12428,7 @@ void taketime(lifeform_t *lf, long howlong) {
int db = B_FALSE;
map_t *map;
if (lfhasflag(lf, F_NOTIME)) {
return;
}
@ -12409,6 +12602,21 @@ void turneffectslf(lifeform_t *lf) {
if (isdead(lf)) return;
}
}
// suffocate?
if (lfhasflag(lf, F_NEEDSWATER) && !hasobwithflag(lf->cell->obpile, F_DEEPWATER)) {
if (isplayer(lf)) {
msg("You are suffocating without water to breath!");
} else if (cansee(player, lf)) {
int dam;
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s is suffocating!", lfname);
dam = lf->maxhp / 3;
limit(&dam, 1, NA);
losehp(lf, dam, DT_DIRECT, NULL, "suffocation");
if (isdead(lf)) return;
}
}
// get more hungry
modhunger(lf, 1);
@ -13233,13 +13441,18 @@ int usestairs(lifeform_t *lf, object_t *o) {
dblog("ERROR - unlinked stairs!\n");
msg("ERROR - unlinked stairs!\n");
} else {
enum HABITAT newhabitat;
int newregion;
// generate a new map! this will fill in the destination of our stairs
newmap = addmap();
if (newdepth == 0) {
createmap(newmap, newdepth, RG_WORLDMAP, AUTO, curmap, dir);
newregion = RG_WORLDMAP;
newhabitat = AUTO;
} else {
createmap(newmap, newdepth, lf->cell->map->region, AUTO, curmap, dir);
newregion = lf->cell->map->region;
newhabitat = AUTO;
}
createmap(newmap, newdepth, newregion, newhabitat, curmap, dir);
// link our stairs to the new map.
//linkstairs(o);
@ -13356,7 +13569,12 @@ int validateraces(void) {
// add flags based on raceclass
for (r = firstrace ; r ; r = r->next) {
if (r->raceclass->id == RC_UNDEAD) {
if (r->raceclass->id == RC_AQUATIC) {
addflag(r->flags, F_HASSKILL, SK_SWIMMING, PR_MASTER, NA, NULL);
addflag(r->flags, F_AQUATIC, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL);
} else if (r->raceclass->id == RC_UNDEAD) {
addflag(r->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL);
addflag(r->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
addflag(r->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL);

4
lf.h
View File

@ -8,6 +8,7 @@ raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum
skill_t *addskill(enum SKILL id, char *name, char *desc);
void addtrail(lifeform_t *lf, int dir);
void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype);
void adjustspeedforwater(lifeform_t *lf, int *speed);
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);
@ -147,7 +148,7 @@ int getraceclass(lifeform_t *lf);
int getracerarity(map_t *map, enum RACE rid);
object_t *getrandomarmour(lifeform_t *lf);
int getrandommonlevel(race_t *r, map_t *m);
race_t *getrandomrace(map_t *map, int forcedepth);
race_t *getrandomrace(cell_t *c, int forcedepth);
race_t *getreallyrandomrace(void);
enum SKILL getrandomskill(void);
object_t *getrestob(lifeform_t *lf);
@ -191,6 +192,7 @@ void initrace(void);
void initskills(void);
void interrupt(lifeform_t *lf);
int isairborne(lifeform_t *lf);
int isaquatic(lifeform_t *lf);
int isbleeding(lifeform_t *lf);
int isblind(lifeform_t *lf);
enum BURDENED isburdened(lifeform_t *lf);

1498
log.txt

File diff suppressed because it is too large Load Diff

71
map.c
View File

@ -125,7 +125,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
}
if ((raceid == R_NONE) || (raceid == R_RANDOM)) {
r = getrandomrace(c->map, 0);
r = getrandomrace(c, 0);
} else {
r = findrace(raceid);
}
@ -537,7 +537,7 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) {
// draw highest object in sort order
o = gettopobject(c);
if (o) {
if (o && !hasflag(o->flags, F_NOGLYPH)) {
// return the object's glyph
*g = *(getglyph(o));
} else {
@ -1089,7 +1089,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
createroom(map, bestx,besty, w,h, i);
/*
// maybe make it a special room
if (getrand(1,100) <= CH_SPECIALROOM) {
int curpos;
int roomid;
@ -1700,6 +1699,41 @@ void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) {
makedoor(cell);
}
// maybe make it a special room
if (rnd(1,100) <= getspecialroomchance(map)) {
enum SPECIALROOMTYPE rt;
rt = getspecialroomtype(map);
if (rt == RT_FLOODED) {
int sx,sy,ex,ey;
char wtype[BUFLEN];
switch (rnd(1,2)) {
case 1: strcpy(wtype, "deep water"); break;
case 2: strcpy(wtype, "shallow water"); break;
}
switch (rnd(1,2)) {
case 1: // entire room flooded
sx = minx+1;
sy = miny+1;
ex = maxx-1;
ey = maxy-1;
break;
case 2: // small walkway around the edge
sx = minx+2;
sy = miny+2;
ex = maxx-2;
ey = maxy-2;
if (sx > ex) sx = ex;
if (sy > ey) sy = ey;
break;
}
for (y = sy; y <= ey; y++) {
for (x = sx; x <= ex; x++) {
cell = getcellat(map, x, y);
addob(cell->obpile, wtype);
}
}
}
}
}
int dirtox(int dt, int dir) {
@ -1888,6 +1922,7 @@ cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf) {
// oooooo TODO handle side being diagonal
switch (side) {
case D_N:
case DC_N:
x = 0;
y = 0;
xinc = 1;
@ -1895,6 +1930,7 @@ cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf) {
bestcell = getcellat(m, lf->cell->x, 0);
break;
case D_E:
case DC_E:
x = m->w-1;
y = 0;
xinc = 0;
@ -1902,6 +1938,7 @@ cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf) {
bestcell = getcellat(m, m->w - 1, lf->cell->y);
break;
case D_S:
case DC_S:
x = 0;
y = m->h - 1;
xinc = 1;
@ -1909,6 +1946,7 @@ cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf) {
bestcell = getcellat(m, lf->cell->x, m->h - 1);
break;
case D_W:
case DC_W:
x = 0;
y = 0;
xinc = 0;
@ -2160,6 +2198,31 @@ int getobchance(int habitat) {
// default of no objects
return 0;
}
// chance that a room is a 'special' one
int getspecialroomchance(map_t *m) {
switch (m->habitat) {
case H_DUNGEON:
return 5;
default:
return 0;
}
// default of no chance
return 0;
}
enum SPECIALROOMTYPE getspecialroomtype(map_t *m) {
if (m->habitat == H_DUNGEON) {
/*
switch (rnd(1,1)) {
}
*/
return RT_FLOODED;
}
return RT_NONE;
}
// chance of each empty cell in a map has of getting an object/monster
int getthingchance(int habitat) {
switch (habitat) {
@ -2875,7 +2938,7 @@ void setcellknown(cell_t *cell, int forcelev) {
}
if (slev >= PR_ADEPT) {
for (o = cell->obpile->first ; o ; o = o->next) {
if (o->type->obclass->id == OC_DFEATURE) {
if ((o->type->obclass->id == OC_DFEATURE) || (o->type->obclass->id == OC_TERRAIN)) {
if (!issecretdoor(o)) {
cell->knownglyph = *(getglyph(o));
}

4
map.h
View File

@ -23,7 +23,7 @@ int countadjcellswithflag(cell_t *cell, enum FLAG fid);
int countcellexits(cell_t *cell);
void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir);
void createforest(map_t *map, int depth, map_t *parentmap, int exitdir);
void createmap(map_t *map, int dungeonid, int depth, int habitat, map_t *parentmap, int exitdir);
void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap, int exitdir);
void createroom(map_t *map, int minx, int miny, int w, int h, int roomid);
int dirtox(int dt, int dir);
int dirtoy(int dt, int dir);
@ -41,6 +41,8 @@ void forgetcells(map_t *map, int amt);
cell_t *getcellindir(cell_t *cell, int dir);
int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved);
int getobchance(int habitat);
int getspecialroomchance(map_t *m);
enum SPECIALROOMTYPE getspecialroomtype(map_t *m);
int 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);

100
move.c
View File

@ -135,12 +135,20 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err
rdata = NULL;
}
// never dangerous if there's someone there, since we'll
// attack them instead of moving!
if (cell->lf) {
return B_FALSE;
}
// obvious things that you can see
if (!onlyifknown || (haslos(lf, cell) && !lfhasflag(lf, F_UNDEAD))) {
for (o = cell->obpile->first ; o ; o = o->next) {
f = hasflag(o->flags, F_DEEPWATER);
if (f) {
if (!isairborne(lf) && (getobdepth(o, lf) >= DP_HEAD) && !getskill(lf, SK_SWIMMING)) {
// non swimming creature in water?
if (!isairborne(lf) && (getobdepth(o, lf) >= DP_HEAD)) {
if (getskill(lf, SK_SWIMMING) - isburdened(lf) <= 0) {
if (error) {
*error = E_AVOIDOB;
rdata = o;
@ -148,6 +156,15 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err
return B_TRUE;
}
}
} else {
// water needing creature out of water?
if (lfhasflag(lf, F_NEEDSWATER)) {
if (error) {
*error = E_DANGEROUS;
}
return B_TRUE;
}
}
f = hasflag(o->flags, F_WALKDAM);
if (f) {
if ((f->val[0] != DT_WATER) || isvulnto(lf->flags, DT_WATER)) {
@ -221,7 +238,7 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
// so that we are able to attack monsters embedded in walls.
if (cell->lf && (cell->lf != lf)) {
// usually can't attack while swimming
if (isswimming(lf) && (getskill(lf, SK_SWIMMING) <= PR_EXPERT)) {
if (lf && isswimming(lf) && (getskill(lf, SK_SWIMMING) <= PR_EXPERT)) {
if (!lfhasflag(lf, F_AQUATIC)) {
if (error) *error = E_SWIMMING;
return B_FALSE;
@ -836,13 +853,17 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
killflagsofid(lf->flags, F_HIDING);
// remove grabs (but not attached things)
f = lfhasflag(lf, F_GRABBING);
// Note: only remove this from the person _being grabbed_.
// if the grabb_er_ moves away, they'll drag the grabee with them.
f = lfhasflag(lf, F_GRABBEDBY);
if (f) {
lifeform_t *grabee;
grabee = findlf(NULL, f->val[0]);
assert(grabee);
killflagsofid(grabee->flags, F_GRABBEDBY);
killflagsofid(lf->flags, F_GRABBING);
lifeform_t *grabber;
grabber = findlf(NULL, f->val[0]);
assert(grabber);
if (getcelldist(lf->cell, grabber->cell) > 1) {
killflagsofid(grabber->flags, F_GRABBING);
killflagsofid(lf->flags, F_GRABBEDBY);
}
}
// passwall ends when you walk onto a non-solid cell.
@ -889,6 +910,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
msg("%s starts swimming.", lfname);
didmsg = B_TRUE;
}
// stop sprinting
stoprunning(lf);
}
}
}
@ -1260,15 +1283,17 @@ int opendoor(lifeform_t *lf, object_t *o) {
return B_TRUE;
} else {
if (lf) {
flag_t *sf;
taketime(lf, getactspeed(lf));
touch(lf, o);
// stop sprinting
stoprunning(lf);
/*
sf = lfhasflag(lf, F_SPRINTING);
if (sf && sf->val[0]) {
killflag(sf);
}
*/
}
// locked?
@ -1417,6 +1442,9 @@ int closedoor(lifeform_t *lf, object_t *o) {
addflag(o->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
if (lf) {
// stop sprinting
stoprunning(lf);
if (isplayer(lf)) {
msg("You close %s.", obname);
} else {
@ -1767,15 +1795,19 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
cell = getcellindir(lf->cell, dir);
if (celldangerous(lf, cell, B_TRUE, &errcode)) {
if ((errcode == E_AVOIDOB) && rdata) {
char obname[BUFLEN];
if (isplayer(lf)) {
if (cell && celldangerous(lf, cell, B_TRUE, &errcode)) {
char ques[BUFLEN];
char ch;
if ((errcode == E_AVOIDOB) && rdata) {
char obname[BUFLEN];
object_t *avoidob;
avoidob = (object_t *)rdata;
getobname(avoidob, obname, avoidob->amt);
sprintf(ques, "Really %s into %s?", getmoveverb(lf), obname);
} else {
sprintf(ques, "Really %s there?", getmoveverb(lf));
}
ch = askchar(ques, "yn","n", B_TRUE);
if (ch != 'y') {
return B_TRUE;
@ -1814,10 +1846,11 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) {
lifeform_t *l;
for (l = lf->cell->map->lf ; l ; l = l->next) {
if (cansee(l, lf)) {
flag_t *tf;
if (isplayer(lf)) {
tf = ispetortarget(l, lf);
if (tf) {
if (cansee(l, lf)) {
// update text field
free(tf->text);
asprintf(&(tf->text), "%d", dir);
@ -1825,6 +1858,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
}
}
}
}
// now move to new cell
moveto(lf, cell, drunk ? B_FALSE : onpurpose, dontclearmsg);
@ -1832,9 +1866,21 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
taketime(lf, getmovespeed(lf));
}
// attached things will move the same direction if they can
// attached lfs or lfs you have grabbed will move the same direction if they can
for (alf = cell->map->lf ; alf ; alf = alf->next) {
int willdrag = B_FALSE;
int attached = B_FALSE;
int grabbed = B_FALSE;
if (lfhasflagval(alf, F_ATTACHEDTO, lf->id, NA, NA, NULL)) {
willdrag = B_TRUE;
attached = B_TRUE;
grabbed = B_FALSE;
} else if (lfhasflagval(lf, F_GRABBING, alf->id, NA, NA, NULL)) {
willdrag = B_TRUE;
attached = B_FALSE;
grabbed = B_TRUE;
}
if (willdrag) {
// if the lifeform we were attached to just moved away from us,
// try to stay with them.
if (getcelldist(alf->cell,lf->cell) > 1) {
@ -1842,10 +1888,30 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
newdir = getdirtowards(alf->cell, lf->cell, alf, B_FALSE, DT_ORTH);
// do a manual canmove check here first, to avoid 'the stirge flies into a wall'
// if the move fails.
if ((newdir != D_NONE) && moveclear(alf, newdir, NULL)) {
trymove(alf, newdir, B_FALSE);
//
// but DONT do the check if you're dragging someone you grabbed. otherwise
// moveclear() will say "can't move because someone is holding you"
if (newdir != D_NONE) {
cell_t *nc;
nc = getcellindir(alf->cell, newdir);
if (nc && cellwalkable(alf, nc, NULL)) {
if (isplayer(lf)) {
char alfname[BUFLEN];
getlfname(alf, alfname);
msg("You drag %s along.", alfname);
} else if (isplayer(alf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s drags you along.", lfname);
} else if (cansee(player, lf) || cansee(player, alf)) {
char lfname[BUFLEN],alfname[BUFLEN];
getlfname(lf, lfname);
getlfname(alf, alfname);
msg("%s drags %s along.", lfname, alfname);
}
movelf(alf, nc);
}
}
}
}
}

View File

@ -513,6 +513,7 @@ void donextturn(map_t *map) {
who = map->lf;
if (db) dblog("**** donextturn for: id %d %s", who->id, who->race->name);
assert(who->timespent == 0);
turneffectslf(who);
@ -1019,6 +1020,8 @@ int rollhitdice(lifeform_t *lf) {
}
if (db) dblog("TOTAL: %d",roll);
roll = roll + (int)((float)roll * (mod/100));
// must be at least 1!!
limit(&roll, 1, NA);
if (db) dblog(" -> modified to: %d",roll);
return roll;
}

109
objects.c
View File

@ -56,6 +56,7 @@ objecttype_t *lastot = NULL;
enum OBCLASS sortorder[] = {
OC_EFFECT,
OC_TERRAIN,
OC_MONEY,
OC_WEAPON,
OC_MISSILE,
@ -831,7 +832,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
where = getoblocation(o);
// select random race
if (where) {
corpserace = getrandomrace(where->map, 0);
corpserace = getrandomrace(where, 0);
} else {
// ie. vending machine
corpserace = getrandomrace(NULL, 0);
@ -1130,7 +1131,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
}
if (gamemode == GM_GAMESTARTED) {
if (where->where && haslos(player, where->where)) {
if (o && where->where && !hasflag(o->flags, F_NOGLYPH) && haslos(player, where->where) ) {
needredraw = B_TRUE;
}
}
@ -4694,6 +4695,7 @@ void initobjects(void) {
// object classes
addoc(OC_DFEATURE, "Dungeon Features", "Doors, etc.", '\\', C_GREY);
addoc(OC_TERRAIN, "Terrain", "Water, etc.", '\\', C_GREY);
addoc(OC_MONEY, "Money", "The standard currency of Nexus.", '$', C_GREY);
addoc(OC_SCROLL, "Scrolls", "An arcane roll of parchment, inscribed with many magical glyphs.", '?', C_GREY);
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
@ -4872,7 +4874,8 @@ void initobjects(void) {
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addot(OT_WATERSHALLOW, "shallow water", "Waist-deep water.", MT_WATER, 150, OC_DFEATURE);
// terrain
addot(OT_WATERSHALLOW, "shallow water", "Waist-deep water.", MT_WATER, 150, OC_TERRAIN);
addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "{");
@ -4884,7 +4887,7 @@ void initobjects(void) {
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
addflag(lastot->flags, F_REDUCEMOVEMENT, 3, NA, NA, NULL);
addot(OT_WATERDEEP, "deep water", "Very deep water.", MT_WATER, 300, OC_DFEATURE);
addot(OT_WATERDEEP, "deep water", "Very deep water.", MT_WATER, 300, OC_TERRAIN);
addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BOLDBLUE, NA, NA, "{");
@ -5478,6 +5481,13 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
addot(OT_S_JOLT, "jolt", "Jolts an adjacent enemy with a short pulse of electricity.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 4, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
// l2
addot(OT_S_GUSTOFWIND, "gust of wind", "Causes a gust of wind to blow the target's objects away.", MT_NOTHING, 0, OC_SPELL);
@ -5570,7 +5580,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CONECOLD, "cone of cold", "Shoots a blast of ice cold air, dealing 2-10 cold damage.", MT_NOTHING, 0, OC_SPELL);
addot(OT_S_COLDRAY, "cold ray", "Shoots a blast of ice cold air, dealing 2-10 cold damage.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
@ -5752,6 +5762,10 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_FLOOD, "flood", "Converts the earth directly into water, creating a deep pool.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
///////////////////
// gravity
///////////////////
@ -6263,8 +6277,8 @@ void initobjects(void) {
// elemental - ice
addot(OT_SB_CHILL, "spellbook of chill", "Teaches the spell 'chill'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_CHILL, NA, NA, NULL);
addot(OT_SB_CONECOLD, "spellbook of cone of cold", "Teaches the spell 'cone of cold'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_CONECOLD, NA, NA, NULL);
addot(OT_SB_COLDRAY, "spellbook of cone of cold", "Teaches the spell 'cone of cold'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_COLDRAY, NA, NA, NULL);
addot(OT_SB_FROSTBITE, "spellbook of frostbite", "Teaches the spell 'frostbite'.", MT_PAPER, 1.5, OC_BOOK);
addflag(lastot->flags, F_LINKSPELL, OT_S_FROSTBITE, NA, NA, NULL);
addot(OT_SB_FREEZEOB, "spellbook of freezing touch", "Teaches the spell 'freezing touch'.", MT_PAPER, 1.5, OC_BOOK);
@ -6404,7 +6418,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OPERNEEDTARGET, TT_NONE, NA, NA, NULL);
addot(OT_WAND_COLD, "wand of cold", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_CONECOLD, NA, NA, NULL);
addflag(lastot->flags, F_LINKSPELL, OT_S_COLDRAY, NA, NA, NULL);
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_WAND_FIRE, "wand of fire", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND);
@ -6467,12 +6481,10 @@ void initobjects(void) {
addot(OT_BUGLAMP, "glowing flask", "A glass flask with a glowbug corpse inside.", MT_GLASS, 0.3, OC_TOOLS);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "!");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
addflag(lastot->flags, F_HOLDCONFER, F_PRODUCESLIGHT, 2, IFKNOWN, NULL);
addot(OT_CANDLE, "candle", "A short wax candle.", MT_WAX, 0.2, OC_TOOLS);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
@ -6486,7 +6498,6 @@ void initobjects(void) {
addot(OT_GUNPOWDER, "pile of gunpowder", "A black metallic powder.", MT_METAL, 0.5, OC_TOOLS);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pile of black powder");
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -6496,7 +6507,6 @@ void initobjects(void) {
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addot(OT_LAMPOIL, "oil lamp", "An oil-powered lamp which produces light.", MT_METAL, 1, OC_TOOLS);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
@ -6509,7 +6519,6 @@ void initobjects(void) {
addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out");
addot(OT_LANTERNOIL, "oil lantern", "An oil-powered lantern which produces a lot of light.", MT_METAL, 1, OC_TOOLS);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 55, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
@ -6523,7 +6532,6 @@ void initobjects(void) {
addot(OT_LOCKPICK, "lockpick", "An angled piece of metal, used to open locks.", MT_METAL, 0.05, OC_TOOLS);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 10, B_DIEONFAIL, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
@ -6537,7 +6545,6 @@ void initobjects(void) {
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addot(OT_TORCH, "torch", "A metre-long wooden rod with a flammable end.", MT_WOOD, 2, OC_TOOLS);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
@ -6548,9 +6555,12 @@ void initobjects(void) {
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_FIRE, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addot(OT_TOWEL, "towel", "An large absorbent cloth used for drawing off moisture.", MT_CLOTH, 1.5, OC_TOOLS);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
// tech - l0
addot(OT_CREDITCARD, "credit card", "A rectangular plastic card.", MT_PLASTIC, 0.01, OC_TECH);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
@ -6746,7 +6756,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 15, NA, NA, NULL);
addflag(lastot->flags, F_SLIPPERY, 14, NA, NA, NULL);
addot(OT_ICECHUNK, "chunk of ice", "A chunk of ice.", MT_ICE, 0.5, OC_MISC);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 3, NA, NULL);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
@ -7003,7 +7013,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NO_PLURAL, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "."); // ie not really visible
addflag(lastot->flags, F_NOGLYPH, NA, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
// NOTE: must add F_TRAIL when creating this object.
addot(OT_SCENT, "scent", "The scent of a creature, only perceivable to those with an enhanced sense of smell.", MT_NOTHING, 0, OC_MISC);
@ -7011,7 +7021,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NO_PLURAL, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "."); // ie not really visible
addflag(lastot->flags, F_NOGLYPH, NA, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
// NOTE: must add F_TRAIL when creating this object.
@ -8715,7 +8725,7 @@ void killob(object_t *o) {
// remove flags conferred by this object
if (o->pile->owner) {
loseobflags(o->pile->owner, o, ALLCONFERRED);
} else if (o->pile->where && !o->pile->where->lf && haslos(player, o->pile->where)) {
} else if (o->pile->where && !o->pile->where->lf && !hasflag(o->flags, F_NOGLYPH) && haslos(player, o->pile->where)) {
needredraw = B_TRUE;
}
@ -9020,7 +9030,7 @@ void makewet(object_t *o, int amt) {
}
} else {
// rust
if (haslos(player, loc)) {
if (haslos(player, loc) && !isdead(player)) {
msg("%s rust%s.",obnamefull, (o->amt == 1) ? "s" : "");
}
f = addflag(o->flags, F_RUSTED, amt, NA, NA, NULL);
@ -9047,7 +9057,7 @@ void makewet(object_t *o, int amt) {
} else {
// get wet
if (haslos(player, loc)) {
if (haslos(player, loc) && !isdead(player)) {
msg("%s get%s wet.",obnamefull, (o->amt == 1) ? "s" : "");
}
f = addflag(o->flags, F_WET, amt, WETTIME, NA, NULL);
@ -9151,7 +9161,7 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) {
}
}
if (dst->where && !dst->where->lf && haslos(player, dst->where)) {
if (o && dst->where && !dst->where->lf && !hasflag(o->flags, F_NOGLYPH) && haslos(player, dst->where)) {
needredraw = B_TRUE;
drawscreen();
}
@ -10040,18 +10050,18 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
}
if (c->type->solid) {
if (isdiggable(c)) {
// replace wall
setcelltype(c, getemptycelltype(c->map->habitat));
if (isplayer(lf)) {
msg("You dig through the wall.");
needredraw = B_TRUE;
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s digs through a wall.",lfname);
}
// replace wall
setcelltype(c, getemptycelltype(c->map->habitat));
// redraw screen
needredraw = B_TRUE;
drawscreen();
}
//drawscreen();
// takes extra time
taketime(lf, getactspeed(lf)*9);
} else {
@ -10078,15 +10088,16 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
// TODO: metal doors are immune to CHOP damage
if (!isimmuneto(door->flags, DT_CHOP)) {
taketime(lf, getactspeed(lf));
removeob(door, door->amt);
if (isplayer(lf)) {
msg("You smash open a door!");
needredraw = B_TRUE;
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s smashes open a door.",lfname);
}
removeob(door, door->amt);
needredraw = B_TRUE;
}
drawscreen();
failed = B_FALSE;
}
@ -10195,6 +10206,22 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
nothinghappens();
}
}
} else if (o->type->id == OT_TOWEL) {
object_t *oo;
if (isplayer(lf)) {
msg("You dry yourself off with %s.", obname);
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s dries itself off with %s.", lfname, obname);
}
// make objects dry
for (oo = lf->pack->first ;oo ; oo = oo->next) {
if (isequipped(oo)) {
killflagsofid(oo->flags, F_WET);
}
}
taketime(lf, getactspeed(lf));
}
return B_FALSE;
}
@ -11836,6 +11863,12 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
reason = E_OK;
// you can't throw with as much force while swimming.
if (isswimming(thrower) && !firearm) {
speed /= 2;
limit(&speed, 1, NA);
}
multiplier = speed / 2;
if (firearm) {
@ -12097,6 +12130,21 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
acc = 100;
}
// adjust for swimming
if (isswimming(thrower)) {
switch (getskill(thrower, SK_SWIMMING)) {
default:
case PR_INEPT: acc -= 40; break;
case PR_NOVICE: acc -= 30; break;
case PR_BEGINNER: acc -= 20; break;
case PR_ADEPT: acc -= 10; break;
case PR_SKILLED:
case PR_EXPERT:
case PR_MASTER:
break;
}
}
// roll for hit
youhit = B_FALSE;
// metal weapon versus magnetic shield?
@ -12437,7 +12485,6 @@ void timeeffectsob(object_t *o) {
// player now knows that this is blessed
o->blessknown = B_TRUE;
}
//if (needredraw) drawlevelfor(player);
// update location
//if (inv) killflag(inv);

211
spell.c
View File

@ -92,6 +92,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (isplayer(user)) msg("You can't move!");
return B_TRUE;
}
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You can't charge while swimming!");
return B_TRUE;
}
if (!range) {
// get max range - based on speed.
@ -164,6 +168,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
case R_CREEPINGCLAW:
case R_LEECH:
case R_SNAKETREE:
case R_PIRANHAKING:
strcpy(verb, "leap");
break;
default:
@ -196,6 +201,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (!isplayer(user)) {
return B_TRUE;
}
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You can't cook while swimming!");
return B_TRUE;
}
water = hasob(user->pack, OT_POT_WATER);
if (!water || !isknown(water)) {
msg("You need some water before you can cook.");
@ -290,6 +299,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
object_t *o,*trapob = NULL;
flag_t *trapflag = NULL;
char buf[BUFLEN];
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You can't disarm traps while swimming!");
return B_TRUE;
}
// ask for direction
if (!targcell) {
int dirch;
@ -372,6 +387,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} else if (abilid == OT_A_FLURRY) {
int dir;
int dirch;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You can't make an attack flurry traps while swimming!");
return B_TRUE;
}
if (!isdualweilding(user)) {
if (isplayer(user)) msg("You need two be dual-weilding to perform an attack flurry!");
return B_TRUE;
@ -534,6 +555,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
char victimname[BUFLEN];
int dodged = B_FALSE;
cell_t *origcell;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You can't jump while swimming!");
return B_TRUE;
}
if (!targcell) {
sprintf(buf, "Jump where (max distance 2)?");
while (!targcell) {
@ -664,6 +691,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
int slev;
flag_t *f;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You can't sprint while swimming!");
return B_TRUE;
}
f = lfhasflag(user, F_SPRINTING);
if (f) {
if (f->val[0]) {
@ -999,6 +1031,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
char targetname[BUFLEN];
flag_t *f;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You lack the stability for a heavy blow while swimming.");
return B_TRUE;
}
wep = getweapon(user);
if (!wep || !ismeleeweapon(wep) || (getobunitweight(wep) < 3)) {
if (isplayer(user)) msg("You need a heavy weapon to perform a heavy blow!");
@ -1056,6 +1093,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
int dir;
cell_t *c;
flag_t *f,*f2;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You cannot do that while swimming.");
return B_TRUE;
}
// take time
// - NOTE: purposely using action speed, not weapon speed.
taketime(user, getactspeed(user));
@ -1076,6 +1119,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
killflag(f2);
} else if (abilid == OT_A_HIDE) {
int penalty = 0;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You can't hide while swimming!");
return B_TRUE;
}
if (lfhasflag(user, F_HIDING)) {
if (isplayer(user)) msg("You are already hiding!");
return B_TRUE;
@ -1102,6 +1151,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (!isplayer(user)) {
return B_TRUE;
}
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("That wouldn't be a good idea while swimming.");
return B_TRUE;
}
if (!haslos(user, user->cell)) {
msg("You can't inspect anything, since you can't see!");
return B_TRUE;
@ -1933,8 +1986,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
for (y = caster->cell->y - range ; y <= caster->cell->y + range; y++) {
for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) {
targcell = getcellat(caster->cell->map, x,y);
if (targcell && (getcelldistorth(caster->cell, targcell) <= range)) {
if (targcell->lf && (targcell->lf != caster) && haslof(caster->cell, targcell, B_FALSE, NULL)) {
if (targcell && (getcelldistorth(caster->cell, targcell) <= range) &&
haslof(caster->cell, targcell, B_FALSE, NULL)) {
if (targcell->lf) {
if (targcell->lf != caster) {
char lfname[BUFLEN];
// automatic hit
getlfname(targcell->lf, lfname);
@ -1943,42 +1998,50 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
losehp(targcell->lf, rolldie(1,8)+3, DT_COLD, caster, "a burst of coldness");
}
} else {
// noone there, hit objects.
damageallobs(NULL, targcell->obpile, 0, DT_COLD);
}
}
}
} else if (spellid == OT_S_CONECOLD) {
}
} else if (spellid == OT_S_COLDRAY) {
char lfname[BUFLEN];
cell_t *retcell[MAXRETCELLS];
int nretcell,i;
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
// animation
anim(caster->cell, targcell, '}', C_GREY);
if (isplayer(caster) || cansee(player, caster)) {
msg("%s shoot%s a blast of coldness.",castername,isplayer(caster) ? "" : "s");
msg("%s shoot%s a ray of coldness.",castername,isplayer(caster) ? "" : "s");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
target = haslf(targcell);
calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y,
targcell->x, targcell->y, retcell, &nretcell);
for (i = 1; i < nretcell; i++) {
target = haslf(retcell[i]);
if (target) {
getlfname(target, lfname);
// target takes magical damage
if (skillcheck(target, SC_DODGE, 20 + (power*2), 0)) {
// miss
if (cansee(caster, target)) {
msg("A blast of coldness misses %s.",lfname);
if (cansee(player, target)) {
msg("A ray of coldness misses %s.",lfname);
}
} else {
// hit
if (cansee(caster, target)) {
msg("A blast of coldness ray hits %s.",lfname);
if (cansee(player, target)) {
msg("A ray of coldness ray hits %s.",lfname);
}
losehp(target, rnd(2,5), DT_COLD, caster, "a blast of coldness");
// ray stops here.
break;
}
} else {
object_t *o, *nexto;
for (o = targcell->obpile->first; o ; o = nexto) {
nexto = o->next;
takedamage(o, 0, DT_COLD);
damageallobs(NULL, retcell[i]->obpile, 0, DT_COLD);
}
}
} else if (spellid == OT_S_CREATEMONSTER) {
@ -2557,6 +2620,45 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
brightflash(caster->cell, 2 + (power/4), player);
} else if (spellid == OT_S_FLOOD) {
int failed = B_FALSE;
// ask for a target cell
if (!validatespellcell(caster, &targcell, TT_NONE, spellid, power)) return B_TRUE;
if (targcell) {
if (!targcell->type->solid) {
// create water there
object_t *o;
o = addob(targcell->obpile, "deep water");
if (o) {
enum OBTYPE badoid[2];
int i,amt;
amt = ((power+1) * (power+1)) - 1;
badoid[0] = OT_WATERDEEP;
badoid[1] = OT_NONE;
for (i = 0; i < amt; i++) {
cell_t *c;
c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_WALLSTOP, badoid);
if (c) {
addob(c->obpile, "deep water");
} else {
break;
}
}
}
if (haslos(player, targcell)) {
msg("A huge pool of water appears!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else {
failed = B_TRUE;
}
} else {
failed = B_TRUE;
}
if (failed) {
fizzle(caster);
}
} else if (spellid == OT_S_ENERGYBOLT) {
char lfname[BUFLEN];
char numbuf[BUFLEN];
@ -2579,7 +2681,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getlfname(target, lfname);
// target takes magical damage
// ALWAYS hits.
if (cansee(caster, target)) {
if (cansee(player, target)) {
if (power == 1) {
msg("A bolt of energy hits %s.",lfname);
} else {
@ -2701,17 +2803,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("A dart of flame misses %s.",lfname);
} else {
// hit
if (cansee(caster, target)) {
if (cansee(player, target)) {
msg("A dart of flame hits %s.",lfname);
}
losehp(target, rnd(1,6) + power, DT_FIRE, caster, "a dart of flame");
}
} else {
object_t *o, *nexto;
for (o = targcell->obpile->first; o ; o = nexto) {
nexto = o->next;
takedamage(o, 0, DT_FIRE);
}
damageallobs(NULL, targcell->obpile, 0, DT_FIRE);
}
} else if (spellid == OT_S_FLAMEBURST) {
int range = 1;
@ -3402,7 +3500,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getlfname(target, lfname);
// target takes magical damage
// always hit
if (cansee(caster, target)) {
if (cansee(player, target)) {
if (power == 1) {
msg("A spike of mana hits %s.",lfname);
} else {
@ -3719,12 +3817,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// target gets saving throw to avoid...
if (skillcheck(target, SC_DODGE, 20 + (power*2), 0)) {
// miss
if (cansee(caster, target)) {
if (cansee(player, target)) {
msg("A glob of venom misses %s.",lfname);
}
} else {
// hit
if (cansee(caster, target)) {
if (cansee(player, target)) {
msg("A glob of venom hits %s.",lfname);
}
if (!isimmuneto(target->flags, DT_POISON)) {
@ -3732,11 +3830,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
} else {
object_t *o, *nexto;
for (o = targcell->obpile->first; o ; o = nexto) {
nexto = o->next;
takedamage(o, 0, DT_FIRE);
}
damageallobs(NULL, targcell->obpile, 0, DT_FIRE);
}
} else if (spellid == OT_S_POSSESSION) {
char targname[BUFLEN];
@ -4132,6 +4226,25 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("%s flicker%s then vanishes!",targname, isplayer(target) ? "" : "s");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_JOLT) {
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE;
target = haslf(targcell);
if (target) {
int dam;
// hit
if (isplayer(target)) {
msg("A pulse of electricity shocks you!");
} else if (cansee(player, target)) {
char lfname[BUFLEN];
getlfname(target, lfname);
msg("A pulse of electricity shocks %s!",lfname);
}
dam = rolldie(1, power);
losehp(target, dam, DT_ELECTRIC, caster, "a jolt of electricity");
} else {
fizzle(caster);
}
} else if (spellid == OT_S_KNOCK) {
object_t *o;
if (!validatespellcell(caster, &targcell,TT_DOOR, spellid, power)) return B_TRUE;
@ -4264,7 +4377,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, targcell->x, targcell->y, retcell, &nretcells);
animcells(caster->cell, &retcell[1], nretcells-1, B_FALSE, '/', '\\', C_WHITE);
if (cansee(player, caster)) {
msg("%s shoot%s a bolt of lightning!",castername, isplayer(caster) ? "" : "s");
msg("%s shoot%s a bolt of electricity!",castername, isplayer(caster) ? "" : "s");
}
// don't hit the caster cell on fire!
@ -4273,7 +4386,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
c = retcell[i];
if (c->lf) {
// hit with lightning
losehp(c->lf, roll("2d6"), DT_ELECTRIC, caster, "a lightning bolt");
losehp(c->lf, roll("2d6"), DT_ELECTRIC, caster, "an electricity bolt");
nhits--;
}
if (haslos(player, c)) {
@ -5316,7 +5429,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
while (!c) {
int ch;
c = askcoords(buf, TT_NONE, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (!c->known) {
if (!c) {
fizzle(caster);
return B_FALSE;
} else if (!c->known) {
// confirm
ch = askchar("Are you sure to want to teleport into the unknown?", "yn", "n", B_TRUE);
if (ch != 'y') c = NULL;
@ -5798,24 +5914,27 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_WATERJET) {
char lfname[BUFLEN];
cell_t *retcell[MAXRETCELLS];
int nretcell,i;
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
// animation
anim(caster->cell, targcell, '}', C_BLUE);
//anim(caster->cell, targcell, '}', C_BLUE);
if (isplayer(caster) || cansee(player, caster)) {
msg("%s fire%s a jet of high-pressure water.",castername,isplayer(caster) ? "" : "s");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
target = haslf(targcell);
calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, targcell->x, targcell->y, retcell, &nretcell);
for (i = 1; i < nretcell; i++) {
target = haslf(retcell[i]);
if (target) {
getlfname(target, lfname);
int dir,amt;
int dir,amt, i;
object_t *arm[MAXBODYPARTS];
int narm = 0;
int i;
getlfname(target, lfname);
// hit
if (cansee(caster, target)) {
if (cansee(player, target)) {
msg("%s %s hit by a jet of water!",lfname, is(target));
}
// water damage will generally be turn to zero unless people are specifically
@ -5823,7 +5942,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
losehp(target, roll("3d4"), DT_WATER, caster, "a high-pressure jet of water");
losehp(target, roll("3d4"), DT_BASH, caster, "a high-pressure jet of water");
// knock backwards
dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS);
dir = getdirtowards(caster->cell, target->cell, target, B_FALSE, DT_COMPASS);
amt = (power/3); if (amt < 2) amt = 2;
knockback(target, dir, amt, caster, 0);
// rust
@ -5831,11 +5950,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
for (i = 0; i < narm; i++) {
takedamage(arm[i], R_TRUSTY, DT_WATER);
}
// add water object
addob(retcell[i]->obpile, "large puddle of water");
break;
} else {
object_t *o, *nexto;
for (o = targcell->obpile->first; o ; o = nexto) {
nexto = o->next;
takedamage(o, 0, DT_COLD);
damageallobs(NULL, retcell[i]->obpile, 0, DT_WATER);
// add water object
addob(retcell[i]->obpile, "large puddle of water");
}
}
} else if (spellid == OT_S_WARPWOOD) {