* [+] make vending machines use this container code instead.

- [+] don't say "you see a few things" if one of them is footsteps
* [+] IFMONSTER code failing....because flags are now SORTED!!!
- [+] tumble - askcoords is letting us pick a cell we don't have lof to.
* [+] assign a name to lfs once you hire them
* [+] coloured msgtext
- [+] make min dam reduction from AR be AR/5.
- [+] safebox
- [+] if intelligent, prompt before walking into RESTRICTMOVEMENT with
      no getsweaker (val1)
* [+] make fire / ice damage mor elike netheck
- [+] towns should have gates on EVERY side
- [+] forest cells outside town gates need to be CLEARED. (maybe turn
      to dirt)
- [+] fix up knock targetting to include magical barriers
- [+] say "open a bag?" not "operate a bag?"
* [+] implement immunetodisease
- [+] sort known skills in @s.
- [+] better damage bonus when attacking someone who is asleep
- [+] practive firearms/throwing
* [+] need objecttype->size
* [+] containers
* [+] change guns so you have to reload them. ("operate")
- [+] crash when loading map with water
- [+] SAVE OBJECT CONTENTSk
- [+] monsters with jobs aren't getting start items
- [+] shopkeeper has shotgun
- [+] bug: monster keeps swapping between shotgun and flail
- [+] when hiring, remember failure.
* [+] Inn
- [+] bug: pets fighting!!! then they all turn on you. never make
      allies get angry unless the attacker is the player
* [+] hiring npcs
- [+] chat to pet: "stay close" or "keep your distance"
- [+] new 'furniture' obclass
- [+] allow for 'randomshop' regiontype
* [+] add enchantment school
- [+] cast a scroll of mending on itself. CRASH.
* [+] lessengravity should make you jump better and get knocked back
      further
- [+] boostgrav/lessengrav cancel out each other.
* [+] CRASH when you fall down a hole and die.
- [+] problem: master gravitation doesn't let us cast levitat.
      getspellschoolknown() should return the HIGHEST known skill, not
      the first.
* [+] bug: dregion is null?!??!
* [+] dig a pit, if you cleared out land below, you just stay down
      there.
- [+] potion of leveitation
- [+] warning msg when levitate is about to expire
* [+] if you fall upwards to the surface...
* [+] if you are ever on the surface while levitating....
- [+] BUG: cna't go up stairs to surface anymore!!!!!
- [+] get hungry LOTS more quickly when you start sprinting
* [+] monk slow metabolism psionic pell.
- [+] fix buf with lore giving LESS accuracy instead of more.
- [+] food shop
- [+] wand of digging not identified if you dig upwards
* [+] when you make ah ole in the roof, objects above should fall
      through right away
* [+] all towns should have:
- [+] give monks more  psionics spells.
- [+] sk_throwing skill
- [+] make calm animals use spellpower
* [+] add wisdom
* [+] need to save region data along with maps
* [+] COMBINE armour evasion and accuracy penalty!!!
* [+] make armour reduce accuracy as well (unless you have 'armour'
      skill)
- [+] landmine trap
* [+] make friendly monsters of same raceclass swap ammo
- [+] rename 'pull' to 'suck' to avoid confusion with pull metal
* [+] food to fix blindness
- [+] potion of coffee
* [+] genericise statbrackets
* [+] tumble ability
* [+] simplify spell power
* [+] shopkeeprs should be allowed to pursue targets outside of the
      shop.
- [+] give shopkeepers a shotgun
* [+] make F_RNDHOSTILE be able to ahve a random chance. 
* [+] if you randomly generate food in a shop, still give it a price.
- [+] if peaceful humanoid walks into you, "sorry!"
- [+] sayphrase(lf, SP_SORRY, vol)
- [+] only let you recruit jobs with j_recruitable
- [+] CRASH - summon "monk"
- [+] dogs,
- [+] chickens,
- [+] drunks,
* [+] village objects
- [+] change armourrating AGAIN. instead of a percentage, make it a
      number.
- [+] rename inn to "pub", since you can't sleep there.
* [+] random speech code
* [+] genericise sayphrase text based on lf's job
* [+] monks - add rest of abliities
- [+] add fiengdeath ability to some monsters
This commit is contained in:
Rob Pearce 2011-07-13 21:40:28 +00:00
parent 14eb81566c
commit 7c86e87f4a
26 changed files with 5750 additions and 3103 deletions

220
ai.c
View File

@ -25,7 +25,8 @@ void addignorecell(lifeform_t *lf, cell_t *c) {
}
}
void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
// returns true on failure
int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
int db = B_FALSE;
flag_t *f;
@ -34,9 +35,9 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
}
// mindless?
if (getiqname(getattr(lf, A_IQ), NULL) == IQ_MINDLESS) {
if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) == IQ_MINDLESS) {
if (!isundead(lf)) {
return;
return B_TRUE;
}
}
@ -46,7 +47,19 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
if ((f->lifetime > 0) && (f->lifetime < timelimit)) {
f->lifetime = timelimit;
}
return;
return B_TRUE;
}
// feigning death?
if (lfhasflag(victim, F_FEIGNINGDEATH)) {
int penalty;
penalty = (getcelldist(lf->cell, victim->cell)-1);
if (penalty < 0) penalty = 0;
penalty *= 3;
if (!skillcheckvs(lf, SC_WILL, -penalty, victim, SC_WILL, 0)) {
dblog(".oO { attempted target fooled me with feign death. ignoring. }");
return B_TRUE;
}
}
if (db) {
@ -84,6 +97,7 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
// no longer a pet
f = lfhasflagval(lf, F_PETOF, victim->id, NA, NA, NULL);
if (f) killflag(f);
return B_FALSE;
}
enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) {
@ -225,7 +239,7 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra) {
if (lfhasflag(lf, F_DEBUG)) db = B_TRUE;
o = getfirearm(lf);
if (o && getammo(lf)) {
if (o && getammo(o)) {
if (db) {
char gunname[BUFLEN];
getobname(o, gunname, o->amt);
@ -423,6 +437,14 @@ flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int t
return f;
}
flag_t *aihastarget(lifeform_t *lf) {
flag_t *f;
f = lfhasflag(lf, F_TARGETLF);
if (f) return f;
f = lfhasflag(lf, F_TARGETCELL);
if (f) return f;
return NULL;
}
// returns B_FALSE if we did something.
// returns B_TRUE if we failed (ie. did nothing)
@ -486,6 +508,8 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
attackok = B_TRUE;
} else if (!lfhasflag(lf, F_HIDING)) {
attackok = B_TRUE;
} else if (!lfhasflag(lf, F_FEIGNINGDEATH)) {
attackok = B_TRUE;
}
}
@ -609,8 +633,8 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
// if we got here, we're either at the correct distance or couldn't
// move.
if (attackok) {
enum IQBRACKET iqb;
iqb = getiqname(getattr(lf, A_IQ), NULL);
enum ATTRBRACKET iqb;
iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
// if not adjacent, check for guns, wands, throwing
if ( (rangedattack != RA_NONE) &&
@ -774,7 +798,6 @@ int aipickupok(lifeform_t *lf, object_t *o) {
int ok = B_FALSE;
if (hasflag(o->flags, F_SHOPITEM)) {
// && (getiqname(getattr(lf, A_IQ), NULL) > IQ_ANIMAL)) {
return B_FALSE;
}
@ -819,8 +842,8 @@ void aiturn(lifeform_t *lf) {
enum BODYPART bp;
//cell_t *c;
lifeform_t *master = NULL;
enum IQBRACKET iqb;
int n;
enum ATTRBRACKET iqb;
int n,i;
/*
@ -857,8 +880,7 @@ void aiturn(lifeform_t *lf) {
// info gathering
///////////////////////////////////////////
// remember our intelligence
iqb = getiqname(getattr(lf, A_IQ), NULL);
iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
// are we a pet?
f = lfhasflagval(lf, F_PETOF, NA, NA, NA, NULL);
@ -869,7 +891,7 @@ void aiturn(lifeform_t *lf) {
///////////////////////////////////////////////
// emergencies
///////////////////////////////////////////////
if (iqb >= IQ_AVERAGE) {
if (iqb >= AT_AVERAGE) {
if (celldangerous(lf, lf->cell, B_TRUE, NULL)) {
// if our cell is dangerous, move away!
if (!dorandommove(lf, B_NOBADMOVES, B_FALSE)) {
@ -881,9 +903,29 @@ void aiturn(lifeform_t *lf) {
///////////////////////////////////////////////
// housekeeping - weapon changes, drop/pickup,
// use items, etc
// use items, talk,etc
///////////////////////////////////////////////
// talking
f = lfhasflag(lf, F_RANDOMTALKPCT);
if (f) {
if (pctchance(f->val[0])) {
flag_t *poss[MAXCANDIDATES];
int nposs = 0;
for (f = lf->flags->first ;f ; f = f->next) {
if (f->id == F_RANDOMTALK) {
poss[nposs++] = f;
}
}
if (nposs) {
int vol;
f = poss[rnd(0,nposs-1)];
vol = rnd(f->val[1], f->val[2]);
sayphrase(lf, f->val[0], vol, NA, NULL);
}
}
}
///////////////////////////////////////////////
// healing
///////////////////////////////////////////////
@ -894,12 +936,25 @@ void aiturn(lifeform_t *lf) {
int sleepval = 18;
if (modcounter(lf->flags, 1) >= sleepval) {
// we say that this ISNT on purpose, because otherwise
// we'll wake up as soon as we're healed. in this case
// we actually want to sleep forever (or until woken).
if (!gotosleep(lf, B_FALSE)) {
// force this since when not on purpose, gotosleep wont
// take time.
taketime(lf, getactspeed(lf));
return; // success
}
}
}
}
// feigning death with enemies in sight?
if (lfhasflag(lf, F_FEIGNINGDEATH) && !safetorest(lf)) {
// just wait...
taketime(lf, getactspeed(lf));
addflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL);
return;
}
}
}
// need to heal?
if (lf->hp < (lf->maxhp/2)) {
@ -944,16 +999,18 @@ void aiturn(lifeform_t *lf) {
curwep = getweapon(lf);
bestwep = getbestweapon(lf);
if (curwep != bestwep) {
if ((curwep != bestwep) && !isfirearm(curwep)) {
if (db) dblog(".oO { i have a better weapon than my current one (%s > %s) }",bestwep->type->name, curwep ? curwep->type->name : "nothing");
// weild better one
if (!weild(lf, bestwep)) return;
}
// do we have a better firearm ?
if (curwep && hasflag(curwep->flags, F_TWOHANDED)) {
} else {
curgun = getfirearm(lf);
if (curwep && hasflag(curwep->flags, F_TWOHANDED)) {
// we are using a two handed weapon. don't
// check for guns.
} else {
bestgun = getbestfirearm(lf);
if (curgun != bestgun) {
@ -963,14 +1020,15 @@ void aiturn(lifeform_t *lf) {
}
}
// do we have better ammo?
// do we have ammo for an empty gun?
if (curgun) {
object_t *curammo;
curammo = getammo(lf);
curammo = getammo(curgun);
if (!curammo) {
for (o = lf->pack->first ; o ; o = o->next) {
testammo(lf, o); // doesn't take any time.
if (getammo(lf)) break;
o = getrandomammo(lf);
if (o && !loadfirearm(lf, curgun, o)) {
// success
return;
}
}
}
@ -998,7 +1056,7 @@ void aiturn(lifeform_t *lf) {
// look for any object which we _covet_.
// ie. if we covet something, we will pick it up
// instead of attacking our target.
if (!lfhasflag(lf, F_HIDING)) {
if (!lfhasflag(lf, F_HIDING) && !lfhasflag(lf, F_FEIGNINGDEATH)) {
if (db) dblog(".oO { looking for covetted objects... }");
if (lookforobs(lf)) {
if (db) dblog(".oO { found covetted object. returning. }");
@ -1034,6 +1092,7 @@ void aiturn(lifeform_t *lf) {
///////////////////////////////////////////////
// generic pre-movement actions.
///////////////////////////////////////////////
// need light?
if (!haslos(lf, lf->cell)) {
object_t *lamp;
lamp = hasobwithflagval(lf->pack, F_ACTIVATECONFER, F_PRODUCESLIGHT, NA, NA, NULL);
@ -1047,6 +1106,29 @@ void aiturn(lifeform_t *lf) {
}
}
}
// ally needs ammo?
for (i = 0; i < lf->nlos; i++) {
cell_t *c;
c = lf->los[i];
if (c->lf && (c->lf != lf) && areallies(lf, c->lf)) {
object_t *gun;
gun = getfirearm(c->lf);
if (gun && !getammo(gun)) {
object_t *o;
for (o = lf->pack->first ; o ; o = o->next) {
if (isammofor(o->type, gun) ) {
if (getcelldist(lf->cell, c) <= getmaxthrowrange(lf, o)) {
// throw it to them!
if (!throwat(lf, o, c)) {
// success
return;
}
}
}
}
}
}
}
///////////////////////////////////////////////
// movement
@ -1111,6 +1193,26 @@ 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. }");
// shopkeepers will return to their shops
if (hasjob(lf, J_SHOPKEEPER)) {
f = lfhasflag(lf, F_OWNSSHOP);
if (f) {
int myshop;
cell_t *where;
myshop = f->val[0];
// find the closest cell of my shop
where = getclosestroomcell(lf, myshop);
// move towards my shop. note that if the player leaves then
// re-enters this map, they will find that we have instantly
// teleported there (see mapentereffects).
if (aigoto(lf, where, MR_OTHER, NULL, PERMENANT)) {
// success
return;
}
}
}
// look for any race which we hate
newtarget = NULL;
for (n = 0; n < lf->nlos; n++) {
@ -1141,7 +1243,10 @@ void aiturn(lifeform_t *lf) {
}
if (newtarget) {
aiattack(lf, newtarget, AI_FOLLOWTIME);
if (aiattack(lf, newtarget, AI_FOLLOWTIME)) {
// failed for some reason. maybe target was feigning
// death?
} else {
// then move towards them...
if (db) dblog(".oO { moving towards my new target }");
@ -1151,66 +1256,7 @@ void aiturn(lifeform_t *lf) {
if (db) dblog(".oO { won't move towards target - i have no weapon. }");
}
}
/*
// look for a target to attack based on our allegiance
switch (getallegiance(lf)) {
int i;
int x,y;
case AL_HOSTILE:
if (db) dblog(".oO { i am hostile. looking for a target. }");
// look around for a target
for (i = 0; i < lf->nlos; i++) {
cell_t *c;
c = lf->los[i];
if (c->lf && cansee(lf, c->lf)) {
if (isplayer(c->lf)) { // TODO: change to if isenemy ?
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
aiattack(lf, c->lf, AI_FOLLOWTIME);
// then move towards them...
if (db) dblog(".oO { moving towards my new target }");
if (icanattack) {
if (!movetowards(lf, c, DT_ORTH)) return;
} else {
if (db) dblog(".oO { won't move towards target - i have no weapon. }");
}
break;
}
}
}
break;
case AL_FRIENDLY: // are we friendly? if so, look for a target
if (db) dblog(".oO { i am friendly to the player. looking for a target. }");
// look around for a target
// TODO: use our vis rang einstead of 10!
for (y = lf->cell->y - 10; y <= lf->cell->y + 10; y++) {
for (x = lf->cell->x - 10; x <= lf->cell->x + 10; x++) {
c = getcellat(lf->cell->map, x, y);
// cell exists and we can see it?
if (c && c->lf && (c->lf != lf) && cansee(lf, c->lf)) {
// player there?
//if (!isplayer(c->lf) && !ispeaceful(c->lf)) {
if (areenemies(lf, c->lf)) {
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
// target them!
addtempflag(lf->flags, F_TARGET, c->lf->id, c->x, c->y, NULL, AI_FOLLOWTIME);
// then move towards them...
if (db) dblog(".oO { moving towards my new target }");
if (!movetowards(lf, c, DT_ORTH)) return;
}
}
}
}
break;
default:
break;
}
*/
///////////////////////////////////////////////
// training
@ -1484,6 +1530,8 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if (ot->id == OT_A_HIDE) {
if (lfhasflag(victim, F_HIDING)) {
specificcheckok = B_FALSE;
} else if (lfhasflag(victim, F_FEIGNINGDEATH)) {
specificcheckok = B_FALSE;
} else if (!safetorest(victim)) {
specificcheckok = B_FALSE;
}

3
ai.h
View File

@ -1,7 +1,7 @@
#include "defs.h"
void addignorecell(lifeform_t *lf, cell_t *c);
void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit);
int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit);
enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim);
enum OBTYPE aigetfleespell(lifeform_t *lf);
cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *lasty, int *lastdir);
@ -9,6 +9,7 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra);
void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose);
object_t *aigetwand(lifeform_t *lf, enum FLAG purpose);
flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int timelimit);
flag_t *aihastarget(lifeform_t *lf);
int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack);
void aimovetotargetcell(lifeform_t *lf, flag_t *f);
int aipickup(lifeform_t *lf, object_t *o);

210
attack.c
View File

@ -61,10 +61,10 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty
// SOME of the damage reduction goes towards the armour
// damage taken by armour is reduced by half its armour rating
if (ar) {
int max;
max = ar/2;
if (max >= 1) {
actualdam -= rnd(0,max);
int maxreduction;
maxreduction = ar/2;
if (maxreduction >= 1) {
actualdam -= rnd(0,maxreduction);
limit(&actualdam, 0, NA);
}
}
@ -132,6 +132,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
int attacksdone = 0;
int lastweaponidx = -1;
flag_t *sf;
int saysorry = B_FALSE;
// anyone there? if so just attack.
if (c->lf) {
@ -172,7 +173,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
priwep = getweapon(lf);
// confirm ?
if (!force && isplayer(lf) && wepdullable(priwep) && (getiqname(getattr(player, A_IQ), NULL) >= IQ_SMART) ) {
if (!force && isplayer(lf) && wepdullable(priwep) && (getattrbracket(getattr(player, A_IQ), A_IQ, NULL) >= AT_GTAVERAGE) ) {
char obname[BUFLEN],wepname[BUFLEN],buf[BUFLEN];
char ch;
real_getobname(o, obname, o->amt, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE);
@ -244,7 +245,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
objecttype_t *ot;
if (!op) {
op = addobpile(NULL, NULL);
op = addobpile(NULL, NULL, NULL);
}
ot = findot(f->val[0]);
@ -330,7 +331,14 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
if (validwep[i]) {
if (attacktype == AT_LF) {
if (!isdead((lifeform_t *)attacktarget)) {
if (attacklf(lf, (lifeform_t *)attacktarget, wep[i], damflag[i])) break;
lifeform_t *victim;
victim = (lifeform_t *)attacktarget;
// did we just attack someone by accident?
if (!isplayer(lf) && !areenemies(lf, victim) && (lf->race->raceclass->id == RC_HUMANOID) &&
(getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= A_LOW) ) {
saysorry = B_TRUE;
}
if (attacklf(lf, victim, wep[i], damflag[i])) break;
}
} else if (attacktype == AT_OB) {
if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) break;
@ -356,6 +364,11 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
// now stop hiding
killflagsofid(lf->flags, F_HIDING);
if (saysorry) {
sayphrase(lf, SP_SORRY, -1, NA, NULL);
}
return B_FALSE;
}
@ -367,6 +380,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
char attackername[BUFLEN];
char victimname[BUFLEN];
int fatal = B_FALSE;
int feigneddeath = B_FALSE;
int deflected = B_FALSE;
int weppassthrough = B_FALSE;
int firstisbackstab = B_FALSE;
@ -424,9 +438,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (lf->race->raceclass->id == RC_INSECT) {
if (hasactivespell(victim, OT_S_REPELINSECTS)) {
if (isplayer(lf)) {
msg("Something prevents you from attacking %s!", victimname);
msg("^wSomething prevents you from attacking %s!", victimname);
} else if (cansee(player, lf)) {
msg("Something prevents %s from attacking %s!", attackername, victimname);
msg("^wSomething prevents %s from attacking %s!", attackername, victimname);
}
taketime(lf, getattackspeed(lf));
return B_FALSE;
@ -438,9 +452,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// ie. you have been made noncorporeal
if ((f->id == F_NONCORPOREAL) && (f->lifetime != FROMRACE)) {
if (isplayer(lf)) {
msg("Your attack passes straight through %s.", victimname);
msg("^wYour attack passes straight through %s.", victimname);
} else if (cansee(player, lf)) {
msg("%s%s attack passes straight through %s!", attackername, getpossessive(attackername), victimname);
msg("^w%s%s attack passes straight through %s!", attackername, getpossessive(attackername), victimname);
}
taketime(lf, getattackspeed(lf));
return B_FALSE;
@ -450,8 +464,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// did you hit?
ndam = 0;
hit = rolltohit(lf, victim, wep, &critical);
// weapon passing through ghosts etc?
@ -563,6 +575,12 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
}
// target asleep?
if (lfhasflag(victim, F_ASLEEP)) {
dam[0] *= 2;
}
// bonus for knowledge about the other lf's race? applied LAST.
slev = getlorelevel(lf, victim->race->raceclass->id);
if (slev == PR_INEPT) {
@ -598,6 +616,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (firstisbackstab && (i == 0)) backstab = B_TRUE;
//dblog("initial dam[%d] = %d",i,dam[i]);
// slightly more damage for heavy blows
if (lfhasflag(lf, F_HEAVYBLOW) || hasflag(wep->flags, F_HEAVYBLOW)) {
dam[i] = (int)pctof(110,dam[i]);
//dblog("heavy blow makes dam[%d] = %d",i,dam[i]);
@ -635,12 +654,31 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
//dblog("reduced by armour to dam[%d] = %d",i,dam[i]);
}
if (lfhasflag(lf, F_QUIVERINGPALM)) {
// make sure damage isn't fatal
if (dam[i] >= victim->hp) {
dam[i] = victim->hp - 1;
}
}
// will this hit be fatal?
if (dam[i] >= victim->hp) {
fatal = B_TRUE;
}
// monsters feigning death?
if (lfhasflag(victim, F_FEIGNINGDEATH)) {
killflagsofid(victim->flags, F_FEIGNINGDEATH);
} else if (!fatal && !isplayer(victim) && cancast(victim, OT_A_FEIGNDEATH, NULL)) {
if (onein(6) || isbleeding(victim)) {
// do it!
useability(victim, OT_A_FEIGNDEATH, lf, lf->cell);
feigneddeath = B_TRUE;
}
}
// announce it
if (!feigneddeath) {
if (isplayer(lf)) {
char extradambuf[BUFLEN];
char withwep[BUFLEN];
@ -678,7 +716,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
verb = getattackverb(lf, wep, damtype[i], pctof(10, victim->maxhp), victim->maxhp);
}
}
warn("You %s %s%s%s%s",
warn("^%cYou %s %s%s%s%s", fatal ? 'g' : 'n',
verb,
victimname, withwep,extradambuf,
(fatal || backstab) ? "!" : ".");
@ -699,6 +737,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
char withwep[BUFLEN];
char attackverb[BUFLEN];
char nodamstr[BUFLEN];
int nodam = B_FALSE;
// capitalise first letter
strcpy(buf, attackername);
@ -712,28 +751,37 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
strcpy(attackverb, getattackverb(lf, wep, damtype[i],dam[i],victim->maxhp));
if ((dam[i] == 0) && (damtype[i] != DT_TOUCH)) {
nodam = B_TRUE;
strcpy(nodamstr, " but does no damage");
} else {
strcpy(nodamstr, "");
}
warn("%s %s%s %s%s%s.", buf, attackverb,
warn("^%c%s %s%s %s%s%s.", (isplayer(victim) && !nodam) ? 'b' : 'n', buf, attackverb,
needses(attackverb) ? "es" : "s",
victimname,withwep, nodamstr);
}
noise(lf->cell, lf, NC_OTHER, 3, "sounds of fighting.", NULL);
}
}
if (willheal) {
if (cansee(player, victim)) {
flag_t *f;
msg("%s %s healed!",victimname, isplayer(victim) ? "are" : "is");
if (areallies(player, victim)) {
msg("^g%s %s healed!",victimname, isplayer(victim) ? "are" : "is");
} else {
msg("^w%s %s healed!",victimname, isplayer(victim) ? "are" : "is");
}
f = hasflag(wep->flags, F_BALANCE);
if (f) {
f->known = B_TRUE;
}
gainhp(victim, dam[i]);
}
} else if (lfhasflag(lf, F_QUIVERINGPALM)) {
// victim explodes!
losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE);
} else {
char attackername2[BUFLEN];
real_getlfname(lf, attackername2, B_FALSE);
@ -796,7 +844,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
real_getlfname(lf, lfname, B_FALSE);
losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE);
if (isplayer(victim) || cansee(player, victim)) {
msg("%s bites %s!", lfname, victimname);
msg("^%c%s bites %s!", isplayer(victim) ? 'b' : 'n', lfname, victimname);
}
}
}
@ -822,7 +870,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
sprintf(damstring, "%s pack", lfname);
losehp(victim, f->val[0], f->val[1], lf, damstring);
if (isplayer(victim) || cansee(player, victim)) {
msg("%s pack attacks %s!", lfname, victimname);
msg("%c%s pack attacks %s!", isplayer(victim) ? 'b' : 'c', lfname, victimname);
}
}
}
@ -870,7 +918,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
char damstring[BUFLEN];
rdam = rolldie(f->val[0], f->val[1]);
if (cansee(player, victim)) {
msg("%s%s %s %s %s!", victimname, getpossessive(victimname),
msg("^%c%s%s %s %s %s!", isplayer(victim) ? 'b' : 'n', victimname, getpossessive(victimname),
noprefix(f->text),
getattackverb(victim, NULL, f->val[2], rdam, lf->maxhp),
attackername);
@ -885,17 +933,17 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// announce it
if (weppassthrough) {
if (cansee(player, lf)) {
msg("%s%s attack passes straight through %s!", attackername, getpossessive(attackername), victimname);
msg("^w%s%s attack passes straight through %s!", attackername, getpossessive(attackername), victimname);
}
} else if (deflected) {
if (cansee(player, lf)) {
msg("%s deflect%s %s%s attack.", victimname, isplayer(victim) ? "" : "s",attackername, getpossessive(attackername));
msg("^w%s deflect%s %s%s attack.", victimname, isplayer(victim) ? "" : "s",attackername, getpossessive(attackername));
}
} else if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) {
if (isplayer(lf) || cansee(player, lf)) {
sprintf(buf, "%s",attackername);
msg("%s%s magnetic shield repels %s%s attack.", victimname, getpossessive(victimname),
msg("^w%s%s magnetic shield repels %s%s attack.", victimname, getpossessive(victimname),
buf, getpossessive(buf));
}
} else {
@ -921,7 +969,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
flag_t *f;
f = addflag(victim->flags, F_NOTIME, B_TRUE, NA, NA, NULL);
moveto(victim, adj, B_FALSE, B_FALSE);
msg("%s dodge%s!",victimname,isplayer(victim) ? "" : "s");
msg("^w%s dodge%s!",victimname,isplayer(victim) ? "" : "s");
killflag(f);
}
@ -1054,7 +1102,6 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) {
} else {
strcpy(withwep, "");
}
msg("%s %ss %s%s.", attackername,
getattackverb(lf, wep, damtype[i],dam[i],maxhp), obname,withwep);
} else {
@ -1066,7 +1113,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) {
sprintf(buf, "punching %s", obname);
if ( losehp(lf, 1, DT_BASH, lf, buf)) {
if (isplayer(lf)) {
msg("Ow!");
msg("^bOw!");
}
}
}
@ -1118,21 +1165,21 @@ int damtypecausesbleed(enum DAMTYPE dt) {
// returns the amount of damage the armour blocked...
int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) {
int reduceamt = 0;
int ar;
int pctrange;
int ar,min;
//int pctrange;
object_t *o;
ar = getarmourrating(lf, NULL, NULL, NULL);
//reducepct = getdamreducepct(ar);
//reduceamt = (int) ceil((reducepct / 100.0) * (float)dam);
//reduceamt = ar/2;
// between 25% and 75% of AR.
// ie. with AR of 20, all damage is reduced by 5-15.
pctrange = rnd(25,75);
reduceamt = pctof(pctrange, ar);
//pctrange = rnd(25,75);
//reduceamt = pctof(pctrange, ar);
// between ar/5 and AR
min = ar/5;
reduceamt = rnd(min, ar);
// special case
if (damtype == DT_PROJECTILE) {
@ -1486,46 +1533,6 @@ void getdamrange(flag_t *f, int *min, int *max) {
if (max) *max = maxdam;
}
/*
void getdamrangeunarmed(flag_t *f, int *min, int *max) {
obpile_t *op = NULL;
object_t *o = NULL;
flag_t *damflag = NULL;
if (strlen(f->text)) {
damflag = f;
} else {
objecttype_t *ot;
ot = findot(f->val[0]);
op = addobpile(NULL, NULL);
// create the fake weapon
o = addob(op, ot->name);
if (o) {
damflag = hasflag(o->flags, F_DAM);
}
}
if (damflag) {
int ndice,nsides,mod;
texttodice(damflag->text, &ndice, &nsides, &mod);
if (min) *min = (ndice * 1) + mod;
if (max) *max = (ndice * nsides) + mod;
} else {
if (min) *min = 0;
if (max) *max = 0;
}
if (o) {
killob(o);
}
if (op) {
free(op);
}
}
*/
// roll for damage
int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag) {
@ -1660,44 +1667,6 @@ float getstrdammod(lifeform_t *lf) {
}
// determine attack type for lifeform.
// allocate a pile and add weapon to it.
// return the pile. remember to free it!
/*
obpile_t *getunarmedweapon(lifeform_t *lf,flag_t **uflag) {
int nposs;
flag_t *f;
int sel;
char poss[MAXPILEOBS][BUFLEN];
obpile_t *op;
flag_t *possflag[MAXPILEOBS];
op = addobpile(NULL, NULL);
// pick a random attack type.
nposs = 0;
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_HASATTACK) {
strcpy(poss[nposs],f->text);
possflag[nposs] = f;
nposs++;
}
}
if (nposs > 0) {
object_t *uob;
sel = rnd(0,nposs-1);
uob = addob(op, poss[sel]);
assert(uob);
if (uflag) *uflag = possflag[sel];
}
if (!op->first) {
if (uflag) *uflag = NULL;
}
return op;
}
*/
// ie. caused by hitting something with a melee weapon
int ismeleedam(enum DAMTYPE damtype) {
switch (damtype) {
@ -1848,15 +1817,16 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
acc += 50;
}
// modify for lore level
if (slev != PR_INEPT) {
acc += (slev*10);
}
limit(&acc, 0, 100);
//if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc);
myroll = rnd(1,100);
if (slev != PR_INEPT) {
myroll += (slev*10);
}
// modify for lore
if (myroll <= acc) {
@ -1894,7 +1864,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
addob(where->obpile, "small fire");
// announce
if (haslos(player, where)) {
msg("A column of fire erupts from the ground!");
msg("^wA column of fire erupts from the ground!");
f->known = B_KNOWN;
}
}
@ -1927,10 +1897,10 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
// announce
if (isplayer(owner)) {
msg("Your %s blasts %s!",noprefix(obname),victimname);
msg("^wYour %s blasts %s!",noprefix(obname),victimname);
f->known = B_TRUE;
} else if (cansee(player, owner)) {
msg("%s%s %s blasts %s!",buf, getpossessive(buf),noprefix(obname),victimname);
msg("^w%s%s %s blasts %s!",buf, getpossessive(buf),noprefix(obname),victimname);
f->known = B_TRUE;
}
@ -1961,7 +1931,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
getlfname(owner,lfname);
getlfname(victim, victimname);
if (cansee(player, owner)) {
msg("%s disarm%s %s!",lfname, isplayer(owner) ? "" : "s", victimname);
msg("^w%s disarm%s %s!",lfname, isplayer(owner) ? "" : "s", victimname);
}
drop(victimwep, ALL);
}
@ -1983,7 +1953,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
getlfname(owner,lfname);
getlfname(victim, victimname);
if (cansee(player, owner)) {
msg("%s trip%s %s.",lfname, isplayer(owner) ? "" : "s", victimname);
msg("^w%s trip%s %s.",lfname, isplayer(owner) ? "" : "s", victimname);
}
fall(victim, NULL, B_TRUE);
}

301
data/npcnames.txt Normal file
View File

@ -0,0 +1,301 @@
james
john
robert
michael
william
david
richard
charles
joseph
thomas
christopher
daniel
paul
mark
donald
george
kenneth
steven
edward
brian
ronald
anthony
kevin
jason
matthew
gary
timothy
jose
larry
jeffrey
frank
scott
eric
stephen
andrew
raymond
gregory
joshua
jerry
dennis
walter
patrick
peter
harold
douglas
henry
carl
arthur
ryan
roger
joe
juan
jack
albert
jonathan
justin
terry
gerald
keith
samuel
willie
ralph
lawrence
nicholas
roy
benjamin
bruce
brandon
adam
harry
fred
wayne
billy
steve
louis
jeremy
aaron
randy
howard
eugene
carlos
russell
bobby
victor
martin
ernest
phillip
todd
jesse
craig
alan
shawn
clarence
sean
philip
chris
johnny
earl
jimmy
antonio
danny
bryan
tony
luis
mike
stanley
leonard
nathan
dale
manuel
rodney
curtis
norman
allen
marvin
vincent
glenn
jeffery
travis
jeff
chad
jacob
lee
melvin
alfred
kyle
francis
bradley
jesus
herbert
frederick
ray
joel
edwin
don
eddie
ricky
troy
randall
barry
alexander
bernard
mario
leroy
francisco
marcus
micheal
theodore
clifford
miguel
oscar
jay
jim
tom
calvin
alex
jon
ronnie
bill
lloyd
tommy
leon
derek
warren
darrell
jerome
floyd
leo
alvin
tim
wesley
gordon
dean
greg
jorge
dustin
pedro
derrick
dan
lewis
zachary
corey
herman
maurice
vernon
roberto
clyde
glen
hector
shane
ricardo
sam
rick
lester
brent
ramon
charlie
tyler
gilbert
gene
marc
reginald
ruben
brett
angel
nathaniel
rafael
leslie
edgar
milton
raul
ben
chester
cecil
duane
franklin
andre
elmer
brad
gabriel
ron
mitchell
roland
arnold
harvey
jared
adrian
karl
cory
claude
erik
darryl
jamie
neil
jessie
christian
javier
fernando
clinton
ted
mathew
tyrone
darren
lonnie
lance
cody
julio
kelly
kurt
allan
nelson
guy
clayton
hugh
max
dwayne
dwight
armando
felix
jimmie
everett
jordan
ian
wallace
ken
bob
jaime
casey
alfredo
alberto
dave
ivan
johnnie
sidney
byron
julian
isaac
morris
clifton
willard
daryl
ross
virgil
andy
marshall
salvador
perry
kirk
sergio
marion
tracy
seth
kent
terrance
rene
eduardo
terrence
enrique
freddie
wade

277
defs.h
View File

@ -17,7 +17,7 @@
*/
// ncurses colours
#define C_NONE -1
#define C_NONE (-1)
enum COLOUR {
C_BLACK = 0,
C_RED = 1,
@ -45,6 +45,18 @@ enum NOISECLASS {
NC_OTHER = 2,
};
enum SAYPHRASE {
SP_DRUNK,
SP_PAYWARN,
SP_PAYTHREAT,
SP_RECRUIT_ACCEPT,
SP_RECRUIT_ASKPRICE,
SP_RECRUIT_DECLINE,
SP_RECRUIT_DECLINE_CANTPAY,
SP_RECRUIT_DECLINE_WONTPAY,
SP_SORRY
};
enum SPEECHVOL {
SV_SILENT = 0,
SV_WHISPER = 1,
@ -78,6 +90,7 @@ enum SKILL {
SK_SWIMMING,
SK_TECHUSAGE,
SK_THIEVERY,
SK_THROWING,
SK_TRACKING,
SK_TRAPS,
SK_TWOWEAPON,
@ -100,6 +113,7 @@ enum SKILL {
SK_SS_AIR,
SK_SS_DEATH,
SK_SS_DIVINATION,
SK_SS_ENCHANTMENT,
SK_SS_FIRE,
SK_SS_COLD,
SK_SS_GRAVITY,
@ -111,7 +125,7 @@ enum SKILL {
SK_SS_TRANSLOCATION,
SK_SS_WILD,
};
#define MAXSKILLS 52
#define MAXSKILLS 54
// proficiency levels
enum SKILLLEVEL {
@ -138,6 +152,7 @@ enum SKILLLEVEL {
#define NOBODY (-1)
#define ALLCONFERRED (-9873)
#define PCT (65432) // must be POSITIVE
#define RANDOM (-2610)
#define AUTO (-7654)
@ -155,11 +170,12 @@ enum ATTRIB {
A_NONE = -1,
A_STR = 0,
A_DEX = 1,
A_IQ = 2,
A_CON = 3,
A_CHA = 4,
A_WIS = 2,
A_IQ = 3,
A_CON = 4,
A_CHA = 5,
};
#define MAXATTS 5
#define MAXATTS 6
enum CHECKTYPE {
SC_STR,
@ -167,6 +183,7 @@ enum CHECKTYPE {
SC_IQ,
SC_CON,
SC_CHA,
SC_WIS,
//////////
SC_CLIMB,
SC_DISARM,
@ -182,6 +199,7 @@ enum CHECKTYPE {
SC_SEARCH,
SC_STEAL,
SC_STEALTH,
SC_TUMBLE,
SC_WILL,
};
@ -213,7 +231,7 @@ enum SENSE {
// AI defs
// if target lf is out of view for this many turns, abandon chase
#define AI_FOLLOWTIME (10)
#define AI_FOLLOWTIME (30)
#define DEFAULTRESTHEALTIME (3)
@ -222,29 +240,40 @@ enum SENSE {
#define RO_NONE 0
#define RO_DAMTYPE 1
#define RO_OBCLASS 2
#define RO_HOLDABLE 3
// for flags
// flag lifetimes
#define PERMENANT (-9873)
#define FROMRACE (-9872)
#define FROMJOB (-9871)
#define FROMOBEQUIP (-9870)
#define FROMOBHOLD (-9869)
#define FROMOBACTIVATE (-9868)
#define FROMMAT (-9867)
#define FROMBLESSING (-9866)
#define FROMBRAND (-9865)
#define FROMOBMOD (-9864)
#define FROMSPELL (-9863)
#define FROMPOISON (-9862)
// external sources (ie. don't kill them)
#define FROMEXTERNAL_HIGH (-7000)
#define FROMRACE (-7872)
#define FROMJOB (-7871)
#define FROMOBEQUIP (-7870)
#define FROMOBHOLD (-7869)
#define FROMOBACTIVATE (-7868)
#define FROMMAT (-7867)
#define FROMBLESSING (-9866)
#define FROMBRAND (-7865)
#define FROMOBMOD (-7864)
#define FROMEXTERNAL_LOW (-7999)
#define LEVABILITYDONE (-8000)
#define IFKNOWN (-9772) // used by f_xxconfer. only confer a flag if item is known.
#define IFACTIVE (-9771) // used by f_prodeuceslight. only does so if object is activated
#define NOCONDITION (0)
#define IFMONSTER (-9769) // used in v2 of f_ifpct job flags
#define IFPLAYER (-9768) // used in v2 of f_ifpct job flags
enum FLAGCONDITION {
FC_NOCONDITION = 0,
FC_IFPLAYER,
FC_IFMONSTER,
};
//#define NOCONDITION (0)
//#define IFMONSTER (-9769) // used in v2 of f_ifpct job flags
//#define IFPLAYER (-9768) // used in v2 of f_ifpct job flags
#define ANYROOM (-9770)
@ -262,8 +291,17 @@ enum SENSE {
#define MORESTRING "--More--"
#define MSGMORESTRING "^n--More--"
#define SOLDOUTSTRING "--SOLD OUT--"
enum MSGCHARCOL {
CC_VBAD,
CC_BAD,
CC_NORMAL,
CC_GOOD,
CC_VGOOD,
};
// hunger constant - this is how many turns
// it will take to go from 'normal' to 'hungry' etc
#define HUNGERCONST 200
@ -361,6 +399,7 @@ enum MODTYPE {
#define TT_DOOR 4
#define TT_PLAYER 8
#define TT_ALLY 16
#define TT_IMPASSABLE 32
// target requirements
#define TR_NONE 0
@ -473,6 +512,7 @@ enum SPELLSCHOOL {
SS_AIR,
SS_DEATH,
SS_DIVINATION,
SS_ENCHANTMENT,
SS_FIRE,
SS_COLD,
SS_GRAVITY,
@ -486,70 +526,21 @@ enum SPELLSCHOOL {
SS_LAST,
};
enum CHABRACKET {
CH_RANDOM = -1,
CH_HIDEOUS = 0,
CH_REPULSIVE,
CH_UGLY,
CH_UNATTRACTIVE,
CH_AVERAGE,
CH_ATTRACTIVE,
CH_ALLURING,
CH_BEAUTIFUL,
enum ATTRBRACKET {
AT_RANDOM = -99,
AT_EXLOW = -4,
AT_VLOW = -3,
AT_LOW = -2,
AT_LTAVERAGE = -1,
AT_AVERAGE = 0,
AT_GTAVERAGE = 1,
AT_HIGH = 2,
AT_VHIGH = 3,
AT_EXHIGH = 4,
};
enum STRBRACKET {
ST_RANDOM = -1,
ST_HELPLESS = 0,
ST_FEEBLE = 1,
ST_VWEAK = 2,
ST_WEAK = 3,
ST_AVERAGE = 4,
ST_STRONG = 5,
ST_MIGHTY = 6,
ST_TITANIC = 7,
};
enum DEXBRACKET {
DX_RANDOM = -1,
DX_INCOMPETENT = 0,
DX_OAFISH = 1,
DX_INEPT = 2,
DX_CLUMSY = 3,
DX_AWKWARD = 4,
DX_AVERAGE = 5,
DX_DEXTROUS = 6,
DX_NIMBLE = 7,
DX_AGILE = 8,
DX_SWIFT = 9,
DX_SUPERSONIC = 10,
};
enum IQBRACKET {
IQ_RANDOM = -1,
IQ_MINDLESS = 0,
IQ_VEGETABLE = 1,
IQ_ANIMAL = 2,
IQ_STUPID = 3,
IQ_DIMWITTED = 4,
IQ_DOPEY = 5,
IQ_AVERAGE = 6,
IQ_SMART = 7,
IQ_ENLIGHTENED = 8,
IQ_GENIUS = 9,
};
enum CONBRACKET {
CN_RANDOM = -1,
CN_FRAIL = 0,
CN_SICKLY = 1,
CN_UNHEALTHY = 2,
CN_UNFIT = 3,
CN_AVERAGE = 4,
CN_HEALTHY = 5,
CN_FIT = 6,
CN_HARDY = 7,
};
#define IQ_MINDLESS AT_EXLOW
#define IQ_ANIMAL AT_VLOW
// damage type
enum DAMTYPE {
@ -594,6 +585,7 @@ enum OBCLASS {
OC_EFFECT,
OC_FLORA,
OC_FOOD,
OC_FURNITURE,
OC_MISC,
OC_MISSILE,
OC_MONEY,
@ -660,6 +652,7 @@ enum RACE {
// human monsters
R_HUMAN,
R_BANDIT,
R_DRUNK,
R_TOWNGUARD,
// monsters
R_BEHOLDER,
@ -717,6 +710,8 @@ enum RACE {
R_BAT,
R_BEAR,
R_BEARGRIZZLY,
R_CHICKEN,
R_DOG,
R_DOGBLINK,
R_DOGDEATH,
R_DOGWAR,
@ -774,6 +769,7 @@ enum JOB {
J_SHOPKEEPER,
J_WIZARD,
};
#define J_RANDOM J_NONE
enum MATSTATE {
MS_SOLID,
@ -822,13 +818,11 @@ enum OBTYPE {
OT_STATUE,
OT_DOORWOOD,
OT_DOORIRON,
OT_FENCEWOOD,
OT_FOUNTAIN,
OT_GATEIRON,
OT_GATEWOOD,
OT_FENCEWOOD,
OT_SIGN,
OT_WOODENTABLE,
OT_WOODENBARREL,
OT_WOODENSTOOL,
OT_HOLYCIRCLE,
OT_PENTAGRAM,
OT_HOLEINGROUND,
@ -876,6 +870,7 @@ enum OBTYPE {
OT_JERKY,
OT_ROASTMEAT,
OT_BREADFRESH,
OT_CARROT,
OT_CHOCOLATE,
OT_CLOVER,
// corpses
@ -887,6 +882,7 @@ enum OBTYPE {
OT_POT_AMBROSIA,
OT_POT_BLOOD,
OT_POT_BLOODC,
OT_POT_COFFEE,
OT_POT_COMPETENCE,
OT_POT_ELEMENTIMMUNE,
OT_POT_ETHEREALNESS,
@ -897,6 +893,7 @@ enum OBTYPE {
OT_POT_HEALINGMAJ,
OT_POT_INVIS,
OT_POT_INVULN,
OT_POT_LEVITATION,
OT_POT_MAGIC,
OT_POT_OIL,
OT_POT_POISON,
@ -1009,6 +1006,7 @@ enum OBTYPE {
OT_S_HEALINGMAJ,
OT_S_TURNUNDEAD,
// -- mental / psionic
OT_S_BODYCONTROL,
OT_S_MINDSCAN,
OT_S_SLEEP,
OT_S_TELEKINESIS,
@ -1068,9 +1066,9 @@ enum OBTYPE {
OT_S_SUMMONWEAPON,
// -- translocation
OT_S_BLINK,
OT_S_PULL,
OT_S_DISPERSAL,
OT_S_GATE,
OT_S_SUCK,
OT_S_TELEPORT,
OT_S_TWIDDLE,
// -- wild
@ -1093,6 +1091,7 @@ enum OBTYPE {
OT_A_COOK,
OT_A_DARKWALK,
OT_A_DISARM,
OT_A_FEIGNDEATH,
OT_A_FLURRY,
OT_A_GRAB,
OT_A_CHARGE,
@ -1110,7 +1109,9 @@ enum OBTYPE {
OT_A_INSPECT,
OT_A_HURRICANESTRIKE,
OT_A_POLYREVERT,
OT_A_QUIVERINGPALM,
OT_A_STEAL,
OT_A_TUMBLE,
OT_A_WARCRY, // uses F_NOISETEXT -> N_WARCRY if it is there.
// otherwise 'shouts a blood-curdling war cry'
// wands
@ -1135,7 +1136,6 @@ enum OBTYPE {
OT_BLANKET,
OT_BLINDFOLD,
OT_BUGLAMP,
OT_CANDELABRUM,
OT_CANDLE,
OT_GUNPOWDER,
OT_LAMPOIL,
@ -1144,6 +1144,8 @@ enum OBTYPE {
OT_PANPIPES,
OT_PICKAXE,
OT_ROPE,
OT_SACK,
OT_SAFEBOX,
OT_TORCH,
OT_TOWEL,
// tech
@ -1166,8 +1168,16 @@ enum OBTYPE {
OT_TELEPAD,
OT_TENT,
OT_XRAYGOGGLES,
// furniture
OT_CANDELABRUM,
OT_FIREPLACE,
OT_WEAPONRACK,
OT_WOODENTABLE,
OT_WOODENBARREL,
OT_WOODENSTOOL,
// misc objects
OT_BONE,
OT_CHEST,
OT_EMPTYFLASK,
OT_EMPTYVIAL,
OT_CALTROP,
@ -1356,6 +1366,7 @@ enum OBTYPE {
OT_CROSSBOWHAND,
OT_LONGBOW,
OT_REVOLVER,
OT_SHOTGUN,
OT_SLING,
// special weapons
OT_ENERGYBLADE,
@ -1447,6 +1458,11 @@ enum ALLEGIENCE {
AL_FRIENDLY, // will help you fight
};
enum POISONSEVERITY {
PS_DISEASE,
PS_POISON,
};
enum POISONTYPE {
P_COLD,
P_FOOD,
@ -1455,6 +1471,7 @@ enum POISONTYPE {
P_WEAKNESS,
};
enum RANGEATTACK {
RA_NONE = 0,
RA_GUN,
@ -1505,7 +1522,6 @@ enum FLAG {
F_VALUE, // how much an item is worth (over its base weight+material)
// weapon/armour flags
F_EQUIPPED, // val0 = where it is equipped. CLEAR WHEN OB MOVED!
F_CURAMMO, // currently equipped ammo
F_GOESON, // val0 = where it can be equipped.
F_BONUS, // val0=bonus/penalty to damage/armour. ie. +1 sword
F_THROWMISSILE, // weapon would make a good thrown missle - used by AI
@ -1684,10 +1700,15 @@ enum FLAG {
F_TWOHANDED, // weapon uses two hands to weild
F_TRIPATTACK, // weapon can trip the victim
F_DISARMATTACK, // weapon can disarm the victim
// gun flags
F_FIREARM, // this weapon is equipped in bp_secweapon, not _weapon.
F_FIRESPEED, // how fast this weapon shoots projectiles
F_AMMOOB, // what object this weapon fires
F_AMMOOB, // v0 = what object this weapon fires. can have multiple types.
F_AMMOCAPACITY, // v0 = max ammo that can be loaded
F_RANGE, // range of projectile firing weapon
F_FIRETURNS, // # actions it takes to fire this gun
F_RELOADTURNS, // # actions it takes to reload this gun
// end gun flags
F_FLAMESTRIKE, // causes fires where you hit
F_BALANCE, // heals target if their maxhp < your maxhp
F_REVENGE, // causes damage based on your hp
@ -1718,6 +1739,7 @@ enum FLAG {
F_NODIECONVERTTEXT, // don't anounce when this object changes
// misc flags
F_LINKOB, // val0 = linked object id
// for fountains: v2 = ifknown
F_LINKRACE, // val0 = linked race id
// scroll flags
F_LINKSPELL, // val0 = spell this scroll will cast when read
@ -1770,13 +1792,22 @@ enum FLAG {
F_VEGETARIAN, // this lf will not eat meat.
F_PARTVEGETARIAN,// this lf will only eat if hunger >= 'hungry'
F_CARNIVORE, // this lf will only eat meat.
F_SHIELDPENALTY, // lower your accuracy by val0 due to a cumbersome
// shield
F_SHIELDPENALTY, // lower your acc/ev by val0 due to a cumbersome
// shield. lowered by sk_shield skill.
// v0 is accuracy penalty, v1 is evasion penalty.
F_ARMOURPENALTY, // lower your acc/ev by val0 due to cumbersome
// armour. lowered by sk_armour skill.
// v0 is accuracy penalty, v1 is evasion penalty.
F_LEVRACE, // at level v0, this race is promoted to race v1
// must apply this to the BASE race.
F_ATTRMOD, // modify attribute val0 by val1. ie. 0=A_STR,1=-3
F_ATTRSET, // forces attribute val0 to be val1. ie. 0=A_STR,1=18
F_SIZE, // val0 = lf size (enum LFSIZE)
F_RANDOMTALKPCT, // v0 = chance of randomly saying something each turn
F_RANDOMTALK, // v0 = sp_xxx for what to say when we randomly talk.
// v1/v2 are min/max volume
// can have multiple of these flags, if so then
// randomly eslect one each time.
F_RESTCOUNT, // val0 = how long you've been resting for
F_RESTHEALTIME, // val0 = how long to rest before healing hp
F_RESTHEALAMT, // val0 = how many hp to gain after resting x turns
@ -1793,12 +1824,16 @@ enum FLAG {
F_CANLEARN, // lf is able to learn skill val0
F_STARTOB, // val0 = %chance of starting with it, text = ob name
// val1,2 = min/max amounts. if NA, min=max=1.
F_STARTSKILL, // val0 = skill id
F_STARTOBDT, // val0 = %chance of starting with damtype val1
F_STARTOBCLASS, // val0 = %chance of starting with obclass val1
// option val2 = addition to map depth for rarity
// calculation
F_STARTOBRND, // val0 = %chance of starting with a random ob
// v1 = depth modifier. can use 'RANDOM'
F_CONTAINER, // this object is a container - you can use 'o'
// to take stuff out or put it in.
F_STARTJOB, // val0 = %chance of starting with it, v1 = jobid
F_STARTSKILL, // val0 = skill id
F_STARTATT, // val0 = A_xxx, val0 = start bracket (ie. IQ_GENIUS)
// if text is set, it overrides val0.
// text can be:
@ -1830,6 +1865,7 @@ enum FLAG {
// (text is a long)
F_STAYINHABITAT, // lf will not walk onto a cell of a different
// habitat
F_STAYINROOM, // lf will not walk out of roomid v0
F_FALLDISTANCE, // how many floors this lf has fallen through.
// ABILITY/SPELL FLAGS / ability flags / spell flags
F_FAILEDINSPECT, // lf has failed an inspect check for item id v0
@ -1850,6 +1886,9 @@ enum FLAG {
// monsters with this abil/spell are worth
// v0 more xp.
F_XPMULTIPLY, // multiply xp val for killing this lf by v0
F_HIRABLE, // this job/lf can be recruited
F_HIREPRICE, // how much it costs to hire this lf.
F_NOHIRE, // this lf will not be hired.
F_NOJOBTEXT, // this lf's name is 'a xxx', not 'a xxx wizard' etc
F_LASTDIR, // this is the last direction we moved.
//F_OWNERLASTDIR, // for pets, this it the last dir our owner moved
@ -1866,6 +1905,7 @@ enum FLAG {
F_HATESRACE, // lf will attack lfs with race=v0 or baseid=v0 on
// sight
F_HARMLESS, // it is safe to rest around this lf
F_RNDHOSTILE, // v0% chance of being hostile.
F_HOSTILE, // lf will attack the player if in sight
F_FRIENDLY, // lf will attack all non-players if in sight
F_WANTS, // lf will try to pick up object type val0. if
@ -1916,7 +1956,7 @@ enum FLAG {
F_HITDICE, // val0: # d4 to roll for maxhp per level. val1: +xx
F_MPDICE, // val0: # d4 to roll for maxmp per level. val1: +xx
F_JOB, // val0 = player's class/job
F_NAME, // text = player's name
F_NAME, // text = lf's name
F_XPMOD, // add/subtract this much from calculated xpval
F_BLOODOB, // text = type of object to drop for blood
F_DIESPLATTER, // this lf will splatter objcets of type 'text'
@ -1952,6 +1992,8 @@ enum FLAG {
F_MORALE, // gain +v0 in morale checks.
F_SPOTTED, // you have spotted hiding lf id v0. you lsoe this if they
// go out of sight.
F_HEAVYBLOW, // next attack is a heavy blow
F_QUIVERINGPALM, // your next strike will be a quivpalm attack
// INTRINSICS
F_MAGICARMOUR,// armour is magically boosted. f->text is the description
// ie 'magic armour', 'force field'
@ -1963,6 +2005,7 @@ enum FLAG {
F_BLIND, // cannot see anything
F_DEAF, // cannot hear
F_NEEDOBFORSPELLS, // lf can only cast spells if it has object v0
F_CAFFEINATED, // can't sleep.
F_CANCAST, // can cast the spell val0 (need MP)
F_CANHEARLF, // you can hear lifeform id v0 (show their glyph)
// this flag does not get announced.
@ -1987,6 +2030,7 @@ enum FLAG {
F_DETECTMAGIC, // autodetect magic/special objects
F_DETECTMETAL, // autodetect nearby metal
F_DETECTOBS, // autodetect nearby obs in orthog dist v0
F_DISEASEIMMUNE, // lf can't be diseased
F_DRUNK, // v1 is drunknness - 1-5.
F_ENHANCESEARCH, // gives v0 bonus on search checks.
F_ENHANCESMELL, // can 'see' scents.
@ -1996,6 +2040,7 @@ enum FLAG {
F_EXTRAINFO, // knows extra info
F_EXTRALUCK, // lf gets +v0 to all skill checks!
F_EXTRAMP, // lf has +v0 % extra maxmp
F_FEIGNINGDEATH, // lf is pretending to be dead
F_FLYING, // lf is flying
F_FASTACT, // modifier for action speed
F_FASTMETAB, // hunger counter increases faster, poison cures faster.
@ -2009,7 +2054,6 @@ enum FLAG {
// v2 is save difficulty
F_GRABBEDBY,// you've been grabbed by lf id v0
F_GRABBING, // you are grabbing lf id v0
F_HEAVYBLOW, // next attack is a heavy blow
F_HURRICANESTRIKE, // lf is performing a hurricane strike
F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks.
F_INVISIBLE, // lifeform is invisible
@ -2018,6 +2062,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_GRAVLESSENED,// knockback maeks you go further, can jump further
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
@ -2052,6 +2097,7 @@ enum FLAG {
// if val2 is true, will only make light if ob
// is activated!
F_SLOWACT, // modifier for action speed
F_SLOWMETAB, // hunger counter increases slower, poison cures slower.
F_SLOWMOVE, // modifier for move speed
F_SLOWACTMOVE, // modifier for move and action speed
F_XRAYVIS, //val0=num of walls we can see through
@ -2096,12 +2142,12 @@ enum FLAG {
F_SELECTWEAPON, // this job gets to pick their starting weapon
F_NOPLAYER, // players can't pick this job
F_HASPET, // this job starts with a pet of race f->text
F_IFPCT, // only add the NEXT job flag if rnd(1,100) <= v0.
F_ELSE,
F_IFPLAYER,
F_IFMONSTER,
F_ENDIFPLAYER,
F_ENDIFMONSTER,
//F_IFPCT, // only add the NEXT job flag if rnd(1,100) <= v0.
//F_ELSE,
//F_IFPLAYER,
//F_IFMONSTER,
//F_ENDIFPLAYER,
//F_ENDIFMONSTER,
F_LEVSKILL, // at level v0, this job gains 1 point in skill v1
F_LEVABIL, // at level v0, this job gains f_canwill v1.
// v2 = how often you can do it (or NA for unlimited)
@ -2230,6 +2276,7 @@ enum SPELLTARGET {
#define NOOWNER (NULL)
#define NOLOC (NULL)
#define NOOB (NULL)
#define B_NOTSOLID (0)
#define B_EMPTY (0)
@ -2293,6 +2340,7 @@ enum ERROR {
E_LOWIQ,
E_LOWSTR,
E_LOWCHA,
E_LOWWIS,
E_WONT,
E_OFFMAP,
// charm failure reasons
@ -2352,6 +2400,11 @@ enum COMMAND {
};
typedef struct npcname_s {
char *name;
int valid;
} npcname_t;
typedef struct coord_s {
int x,y;
} coord_t;
@ -2393,6 +2446,7 @@ enum REGIONTHING {
RT_REGIONLINK, // val is enum regiontype to link to.
// what is stair object type
RT_VAULT, // what is vaultname
RT_RNDVAULTWITHFLAG, // val is wantedflag
};
typedef struct regionthing_s {
@ -2405,6 +2459,7 @@ typedef struct regionthing_s {
#define MAXOUTLINETHINGS 20
typedef struct regionoutline_s {
int id;
regiontype_t *rtype;
regionthing_t thing[MAXOUTLINETHINGS];
int nthings;
@ -2416,7 +2471,7 @@ typedef struct region_s {
regiontype_t *rtype;
regionoutline_t *outline;
struct region_s *parentregion;
int nthings;
int nthings; // is this used???
struct region_s *next, *prev;
} region_t;
@ -2623,8 +2678,9 @@ typedef struct lifeform_s {
typedef struct obpile_s {
lifeform_t *owner;// } Only one of these
cell_t *where; // } should be filled in
lifeform_t *owner;// } Only one of
cell_t *where; // } these should be
struct object_s *parentob; // } filled in
struct object_s *first,*last;
// for loading
@ -2641,11 +2697,20 @@ typedef struct flagpile_s {
int nitems;
} flagpile_t;
typedef struct altflagval_s {
enum FLAG id;
int val[3];
char *text;
} altflagval_t;
typedef struct flag_s {
enum FLAG id;
int nvals;
int val[3];
char *text;
struct altflagval_s *altval; // don't need to save this.
enum FLAGCONDITION condition;
int chance;
long obfrom; // for conferred flags, link to object->id. -1 if not conferred.
@ -2657,6 +2722,7 @@ typedef struct flag_s {
struct flag_s *next, *prev;
} flag_t;
typedef struct material_s {
enum MATERIAL id;
char *name;
@ -2714,6 +2780,7 @@ typedef struct objecttype_s {
char *desc;
struct objectclass_s *obclass;
material_t *material;
enum LFSIZE size;
float weight; // in kilograms
struct flagpile_s *flags;
struct objecttype_s *next, *prev;
@ -2737,6 +2804,8 @@ typedef struct object_s {
long birthtime;
flagpile_t *flags;
struct obpile_s *contents;
struct object_s *next, *prev;
} object_t;

View File

@ -2,20 +2,24 @@ defs.h:
add A_xxx
inc MAXATTS
add E_LOWxxx
add CHECKTYPE (SC_xxx)
add xxxBRACKET
lf.c:
add getxxxname()
update rollstat()
add rollxxx()
update getattrbracket()
update skillcheck()
update enhanceskills() question if you can up this at levelup
update modattr()
update meetsattreq()
update weild() E_xxx error message
update jobs
io.c:
update announceflaggain() and loss() for this stat
text.c:
add getattrabbrev()
add getattrname()

View File

@ -3,7 +3,8 @@
{ = water
} = gas
^ = trap / dangerous thing
) = dancing weapon
) = weapon
ooo
A = avian / bird
a = ant
B = bat
@ -46,5 +47,5 @@ hybrid human animal?
} = gas
, = small puddle
{ = large puddle/pool
( = barrel
( = barrel/container
\ = furniture

90
flag.c
View File

@ -16,6 +16,25 @@ extern int statdirty;
extern lifeform_t *player;
altflagval_t *addaltval(flag_t *f, enum FLAG id, int val1, int val2, int val3, char *text) {
f->altval = malloc(sizeof(altflagval_t));
f->altval->id = id;
f->altval->val[0] = val1;
f->altval->val[1] = val2;
f->altval->val[2] = val3;
if (text) {
f->altval->text = strdup(text);
} else {
f->altval->text = strdup("");
}
return f->altval;
}
void addcondition(flag_t *f, enum FLAGCONDITION fc, int chance) {
f->condition = fc;
f->chance = chance;
}
flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text) {
return addflag_real(fp, id, val1, val2, val3, text, PERMENANT, B_KNOWN, -1);
}
@ -148,6 +167,10 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
f->known = known;
f->obfrom = obfromid;
f->altval = NULL;
f->condition = FC_NOCONDITION;
f->chance = 100;
// first blank values
for (i = 0; i < 3; i++) {
f->val[i] = NA;
@ -357,9 +380,11 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) {
case F_BLIND:
case F_EATING:
case F_FASTMOVE:
case F_FLYING:
case F_HASNEWLEVEL:
case F_HIDING:
case F_INVISIBLE:
case F_LEVITATING:
case F_PARALYZED:
case F_POISONED:
case F_PRODUCESLIGHT:
@ -601,6 +626,15 @@ flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, ch
*/
}
int istransitoryflag(flag_t *f) {
if ((f->lifetime >= FROMEXTERNAL_LOW) && (f->lifetime <= FROMEXTERNAL_HIGH)) {
return B_FALSE;
}
return B_TRUE;
}
// returns true if we did something
int killflagsofid(flagpile_t *fp, enum FLAG fid) {
flag_t *f,*nextf;
@ -705,6 +739,11 @@ void killflag(flag_t *f) {
}
// free mem
if (f->text) free(f->text);
if (f->altval) {
if (f->altval->text) free(f->altval->text);
free(f->altval);
}
// remove from list
nextone = f->next;
@ -751,6 +790,45 @@ void killflagpile(flagpile_t *fp) {
free(fp);
}
int killtransitoryflags(flagpile_t *fp, enum FLAG fid) {
flag_t *f,*nextf;
int nkilled = 0;
for (f = fp->first ; f ; f = nextf) {
nextf = f->next;
// gone past the requrested id's number - ie. it's not there.
if (f->id > fid) break;
if (istransitoryflag(f) && (f->id == fid)) {
killflag(f);
nkilled++;
}
}
return nkilled;
}
int killtransitoryflagvals(flagpile_t *fp, enum FLAG fid, int val1, int val2, int val3, char *text) {
flag_t *f, *nextf;
int nkilled = 0;
for (f = fp->first ; f ; f = nextf) {
nextf = f->next;
// gone past the requrested id's number - ie. it's not there.
if (f->id > fid) break;
if (istransitoryflag(f) && (f->id == fid)) {
if ( ((val1 == NA) || (f->val[0] == val1)) &&
((val2 == NA) || (f->val[1] == val2)) &&
((val3 == NA) || (f->val[2] == val3)) &&
((text == NULL) || strstr(f->text, text))) {
killflag(f);
nkilled++;
}
}
}
return nkilled;
}
void timeeffectsflag(flag_t *f, int howlong) {
// special case:
if (f->id == F_TRAIL) {
@ -800,6 +878,12 @@ void timeeffectsflag(flag_t *f, int howlong) {
case F_POLYMORPHED:
warn("You are starting to revert to your original form...");
break;
case F_LEVITATING:
warn("Your levitation is starting to expire...");
break;
case F_FLYING:
warn("Your ability to fly is starting to expire...");
break;
default: // no message
break;
}
@ -851,9 +935,15 @@ void timeeffectsflag(flag_t *f, int howlong) {
case F_MAGSHIELD:
warn("Your magnetic shield is about to expire!");
break;
case F_LEVITATING:
warn("Your levitation is about to expire!");
break;
case F_POLYMORPHED:
warn("You are about to revert to your original form!");
break;
case F_FLYING:
warn("Your ability to fly is about to expire!");
break;
default: // no message
break;
}

5
flag.h
View File

@ -2,6 +2,8 @@
// functions
altflagval_t *addaltval(flag_t *f, enum FLAG id, int val1, int val2, int val3, char *text);
void addcondition(flag_t *f, enum FLAGCONDITION fc, int chance);
flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text);
flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int timeleft);
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known, long obfromid);
@ -19,9 +21,12 @@ flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown, flag_t *exception);
flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *text);
flag_t *hasflagvalknown(flagpile_t *fp, int id, int val1, int val2, int val3, char *text);
flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, char *text, int wantknown);
int istransitoryflag(flag_t *f);
int killflagsofid(flagpile_t *fp, enum FLAG fid);
void killflag(flag_t *f);
void killflagpile(flagpile_t *fp);
int killtransitoryflags(flagpile_t *fp, enum FLAG fid);
int killtransitoryflagvals(flagpile_t *fp, enum FLAG fid, int val1, int val2, int val3, char *text);
void makeflagknown(flagpile_t *fp);
int modcounter(flagpile_t *fp, int amt);
void sumflags(flagpile_t *fp, int id, int *val0, int *val1, int *val2);

879
io.c

File diff suppressed because it is too large Load Diff

6
io.h
View File

@ -52,7 +52,7 @@ void domagic(enum OBTYPE spellid, int cellx, int celly);
void domemmagic(void);
void domsghist(void);
void dooperate(obpile_t *op);
int dopickup(obpile_t *op);
int dopickup(obpile_t *op, int forceask);
void dolockpick(obpile_t *op);
void donextguntarget(void);
void dopour(obpile_t *op);
@ -60,7 +60,7 @@ void doquit(void);
void doquaff(obpile_t *op);
void doread(obpile_t *op);
void dorest(void);
void doselguntarget(void);
int doselguntarget(void);
void dostairs(int dir);
int dotakeoff(obpile_t *op);
void dothrow(obpile_t *op);
@ -78,6 +78,7 @@ void drawscreen(void);
void drawstatus(void);
int drop(object_t *o, int count);
void dumpspells(void);
enum COLOUR getattrcolour(enum ATTRBRACKET brack);
char getchoice(prompt_t *prompt);
char getchoicestr(prompt_t *prompt, int useshortcuts, int showlallatstart);
int getkey(void);
@ -108,6 +109,7 @@ void unsetcol(WINDOW *win, enum COLOUR col);
void setobcolour(WINDOW *win, object_t *o, int set);
void showlfarmour(lifeform_t *lf);
void showlfstats(lifeform_t *lf, int showall);
void textwithcol(WINDOW *win, char *buf);
void tombstone(lifeform_t *lf);
void updatestatus(void);
int updateviewfor(cell_t *cell);

2651
lf.c

File diff suppressed because it is too large Load Diff

33
lf.h
View File

@ -13,6 +13,7 @@ void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o);
int areallies(lifeform_t *lf1, lifeform_t *lf2);
int areenemies(lifeform_t *lf1, lifeform_t *lf2);
int askforpayment(lifeform_t *shk, lifeform_t *lf);
char *assignnpcname(lifeform_t *lf);
void autoskill(lifeform_t *lf);
void autotarget(lifeform_t *lf);
void autoweild(lifeform_t *lf);
@ -91,6 +92,7 @@ int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, int *narms
int getattackspeed(lifeform_t *lf);
int getattpoints(lifeform_t *lf);
int getattr(lifeform_t *lf, enum ATTRIB attr);
enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf);
int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset);
int getavgdam(lifeform_t *lf, int forxp);
float getequippedweight(lifeform_t *lf);
@ -102,6 +104,7 @@ int getbodyparthitchance(enum BODYPART bp);
char *getbodypartname(enum BODYPART bp);
char *getbodypartequipname(enum BODYPART bp);
object_t *getequippedob(obpile_t *op, enum BODYPART bp);
int getexposedlimbs(lifeform_t *lf);
object_t *getfirearm(lifeform_t *lf);
int getfootprinttime(lifeform_t *lf);
lifeform_t *getguntarget(lifeform_t *lf);
@ -117,6 +120,7 @@ int gethungerval(lifeform_t *lf);
job_t *getjob(lifeform_t *lf);
int getlastdir(lifeform_t *lf);
int getlfaccuracy(lifeform_t *lf, object_t *wep);
char getlfcol(lifeform_t *lf, enum MSGCHARCOL cc);
enum LFCONDITION getlfcondition(lifeform_t *lf);
int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions);
int getnightvisrange(lifeform_t *lf);
@ -155,9 +159,11 @@ int getpoisondamchance(enum POISONTYPE ptype);
char *getpoisondamverb(enum POISONTYPE ptype);
char *getpoisondesc(enum POISONTYPE ptype);
char *getpoisonname(enum POISONTYPE ptype);
enum POISONSEVERITY getpoisonseverity(enum POISONTYPE ptype);
int getraceclass(lifeform_t *lf);
int getracerarity(map_t *map, enum RACE rid);
object_t *getrandomarmour(lifeform_t *lf);
job_t *getrandomjob(int onlyplayerjobs);
int getrandommonlevel(race_t *r, map_t *m);
race_t *getrandomrace(cell_t *c, int forcedepth);
race_t *getreallyrandomrace(enum RACECLASS wantrc);
@ -168,11 +174,6 @@ int getsounddist(int volume);
char *getspeedname(int speed, char *buf);
char *getspeednameshort(int speed, char *buf);
float getstatmod(lifeform_t *lf, enum ATTRIB att);
enum CHABRACKET getchaname(int cha, char *buf);
enum CONBRACKET getconname(int con, char *buf);
enum STRBRACKET getstrname(int str, char *buf);
enum DEXBRACKET getdexname(int dex, char *buf);
enum IQBRACKET getiqname(int iq, char *buf);
char *getskilldesc(enum SKILL id );
char *getskillname(enum SKILL id );
char *getskilllevelname(enum SKILLLEVEL sl);
@ -185,9 +186,10 @@ int givemoney(lifeform_t *from, lifeform_t *to, int amt);
void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype);
int giveskill(lifeform_t *lf, enum SKILL id);
int giveskilllev(lifeform_t *lf, enum SKILL id, enum SKILLLEVEL slev);
void givestartobs(lifeform_t *lf, flagpile_t *fp);
void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp);
void givestartskills(lifeform_t *lf, flagpile_t *fp);
map_t *gotolev(lifeform_t *lf, int depth, object_t *fromstairs);
int gotosleep(lifeform_t *lf, int onpurpose);
int hasfreeaction(lifeform_t *lf);
job_t *hasjob(lifeform_t *lf, enum JOB job);
int lfcanbestoned(lifeform_t *lf);
@ -219,6 +221,7 @@ int isfleeing(lifeform_t *lf);
int isfreebp(lifeform_t *lf, enum BODYPART bp);
int isfriendly(lifeform_t *lf);
int isgenius(lifeform_t *lf);
int ishirable(lifeform_t *lf);
int isimmobile(lifeform_t *lf);
flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt);
int isinbattle(lifeform_t *lf);
@ -244,6 +247,8 @@ void killjob(job_t *job);
void killlf(lifeform_t *lf);
void killrace(race_t *race);
flag_t *levelabilityready(lifeform_t *lf);
int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo);
int loadfirearmfast(lifeform_t *lf);
void loseconcentration(lifeform_t *lf);
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc);
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam);
@ -261,6 +266,7 @@ float modifybystat(float num, lifeform_t *lf, enum ATTRIB att);
int needstorest(lifeform_t *lf, char *validchars);
int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext);
void outfitlf(lifeform_t *lf);
void petify(lifeform_t *lf, lifeform_t *owner);
int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground);
void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat);
int poisoncausesvomit(enum POISONTYPE ptype);
@ -269,21 +275,20 @@ void practice(lifeform_t *lf, enum SKILL skid, int amt);
void precalclos(lifeform_t *lf);
int push(lifeform_t *lf, object_t *o, int dir);
int readytotrain(lifeform_t *lf);
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 startresting(lifeform_t *lf, int willtrain);
int rollcha(enum CHABRACKET bracket);
int rollcon(enum CONBRACKET bracket);
int rolldex(enum DEXBRACKET bracket);
int rolliq(enum IQBRACKET bracket);
int rollstr(enum STRBRACKET bracket);
int startresting(lifeform_t *lf, int willtrain);
int rollattr(enum ATTRBRACKET bracket);
int rollstat(lifeform_t *lf, enum ATTRIB attr);
int safetorest(lifeform_t *lf);
int say(lifeform_t *lf, char *text, int volume);
int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *text);
int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus);
int setammo(lifeform_t *lf, object_t *o);
//int setammo(lifeform_t *lf, object_t *o);
void setattr(lifeform_t *lf, enum ATTRIB attr, int val);
void setfollowdistance(lifeform_t *lf, int min, int max);
void setguntarget(lifeform_t *lf, lifeform_t *targ);
void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph);
void setlastdam(lifeform_t *lf, char *buf);
@ -302,7 +307,7 @@ void stopresting(lifeform_t *lf);
void stoprunning(lifeform_t *lf);
void stopsprinting(lifeform_t *lf);
lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, int randomjobsok, job_t *forcejob, int lifetime, int wantfriendly);
int testammo(lifeform_t *lf, object_t *o);
//int testammo(lifeform_t *lf, object_t *o);
int takeoff(lifeform_t *lf, object_t *o);
void taketime(lifeform_t *lf, long howlong);
int throwat(lifeform_t *thrower, object_t *o, cell_t *where);

297
map.c
View File

@ -44,7 +44,7 @@ cell_t *addcell(map_t *m, int x, int y) {
cell->habitat = m->habitat;
setcelltype(cell, cell->habitat->solidcelltype);
cell->visited = B_FALSE;
cell->obpile = addobpile(NOOWNER, cell);
cell->obpile = addobpile(NOOWNER, cell, NOOB);
cell->lf = NULL;
cell->roomid = -1;
cell->vault = NULL;
@ -196,7 +196,15 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
// has a job?
if (f->id == F_STARTJOB) {
if (rnd(1,100) <= f->val[0]) {
givejob(lf, f->val[1]);
enum JOB wantjob;
if (f->val[1] == J_RANDOM) {
job_t *j;
j = getrandomjob(B_TRUE);
wantjob = j->id;
} else {
wantjob = f->val[1];
}
givejob(lf, wantjob);
break;
}
}
@ -367,7 +375,7 @@ object_t *addrandomob(cell_t *c) {
return NULL;
}
if (real_getrandomob(c->map, buf, RO_NONE, NA, NA, c->habitat->id)) {
if (real_getrandomob(c->map, buf, RO_NONE, NA, NA, c->habitat->id, SZ_MAX)) {
if (db) dblog("adding rand obj %s to cell %d,%d",buf,c->x,c->y);
o = addob(c->obpile, buf);
}
@ -483,7 +491,8 @@ void getroomedge(map_t *map, int roomid, int minx, int miny, int maxx, int maxy,
}
}
region_t *addregion(enum REGIONTYPE rtype, region_t *parent) {
// if outlineid is -1, it's automatically assigned
region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid) {
region_t *a;
regionoutline_t *ro,*poss[MAXCANDIDATES];
int nposs = 0;
@ -515,6 +524,7 @@ region_t *addregion(enum REGIONTYPE rtype, region_t *parent) {
a->rtype = findregiontype(rtype);
a->parentregion = parent;
if (outlineid == -1) {
// randomly assign a regionoutline
for (ro = firstregionoutline; ro ; ro = ro->next) {
if (ro->rtype->id == rtype) {
@ -527,6 +537,10 @@ region_t *addregion(enum REGIONTYPE rtype, region_t *parent) {
} else {
a->outline = NULL;
}
} else {
a->outline = findoutline(outlineid);
assert(a->outline);
}
return a;
}
@ -549,6 +563,11 @@ regionoutline_t *addregionoutline(enum REGIONTYPE rtype) {
a->next = NULL;
// props
if (a == firstregionoutline) {
a->id = 0;
} else {
a->id = lastregionoutline->id + 1;
}
a->rtype = findregiontype(rtype);
a->nthings = 0;
return a;
@ -838,7 +857,7 @@ int cellhaslos(cell_t *c1, cell_t *dest) {
}
void clearcell(cell_t *c) {
// kill everything there
// kill everything there - (lifeforms && objects)
if (c->lf && !isplayer(c->lf)) {
killlf(c->lf);
}
@ -1898,11 +1917,12 @@ void createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir, object_
void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int exitdir, object_t *entryob) {
lifeform_t *lf;
map_t *m;
char buf[BUFLEN];
char buf[BUFLEN],buf2[BUFLEN];
int i,x,y;
enum HABITAT habitat;
regionthing_t *thing[MAXOUTLINETHINGS];
int nthings = 0;
int db = B_TRUE;
// determine habitat based on region
// note: we might override this later based on our region outline
@ -1918,8 +1938,10 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
map->depth = depth;
map->region = region;
sprintf(buf, "RegionID %d (#%d)",map->region->id, map->id);
map->name = strdup(buf);
if (db) {
getregionname(buf, map, B_FALSE);
dblog("Creating new map of region '%s'",buf);
}
map->habitat = findhabitat(habitat);
map->nrooms = 0;
@ -1934,6 +1956,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
}
// look for adjacent maps above/below this one
if (db) dblog(" look for adjacent maps above/below this one");
for (i = depth-1; i <= depth+1; i += 2) {
map_t *othermap;
othermap = findregionmap(map->region->id, i);
@ -1941,8 +1964,10 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
if (othermap) {
if (i == (depth-1)) {
map->nextmap[D_UP] = othermap->id;
if (db) dblog(" found mapin dir d_up: %s", othermap->name);
} else {
map->nextmap[D_DOWN] = othermap->id;
if (db) dblog(" found mapin dir d_down: %s", othermap->name);
}
}
}
@ -1952,6 +1977,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
if (parentmap) {
if ((parentmap->region->id == map->region->id) ||
(map->region->rtype->majorbranch)) {
if (db) dblog(" linking to parentmap %s in dir %s", parentmap->name, getdirname(diropposite(exitdir)));
parentmap->nextmap[exitdir] = map->id;
map->nextmap[diropposite(exitdir)] = parentmap->id;
}
@ -1985,12 +2011,16 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
// set map coords
// first world map??
if (map == firstmap) {
if (db) dblog(" map is the first world map. setting coords to 0,0.");
addflag(map->flags, F_MAPCOORDS, 0, 0, NA, NULL);
x = 0;
y = 0;
} else {
// set mapcoords if not already done.
if (!hasflag(map->flags, F_MAPCOORDS)) {
x = -999;
y = -999;
// set mapcoords based on parent map
if (parentmap) {
getmapcoords(parentmap, &x, &y);
assert((x != -999) && (y != -999));
@ -2011,16 +2041,18 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
// no change
break;
}
addflag(map->flags, F_MAPCOORDS, x, y, NA, NULL);
if (db) dblog(" setting map coords to %d,%d (based on parent map)",x,y);
} else {
// set it based on something else...
if (region->rtype->id == RG_WORLDMAP) {
// TODO: is this right???????????
// find another map of this region and set it.
for (m = firstmap ; m ; m = m->next) {
if ((m != map) && (m->region == region)) {
flag_t *ff;
ff = hasflag(m->flags, F_MAPCOORDS);
if (ff) {
if (db) dblog(" setting map coords to %d,%d (based on other region map)",x,y);
x = ff->val[0];
y = ff->val[1];
break;
@ -2038,10 +2070,15 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
}
}
// we now have the map name!
getregionname(buf2, map, B_TRUE);
sprintf(buf, "%s (id #%d)",buf2, map->id);
map->name = strdup(buf);
// get a list of what things are here based on the region's outline
nthings = 0;
if (region->outline) {
if (db) dblog(" checking region outline for things...");
for (i = 0; i < region->outline->nthings; i++) {
int matched = B_FALSE;
if ((region->rtype->id == RG_WORLDMAP) &&
@ -2058,27 +2095,36 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
if (matched) {
// override region
if (region->outline->thing[i].whatkind == RT_HABITAT) {
map->habitat = findhabitat(region->outline->thing[i].value);
habitat_t *h;
h = findhabitat(region->outline->thing[i].value);
if (db) dblog(" setting map habitat to %s based on outlinething.",h->name);
map->habitat = h;
} else {
if (db) dblog(" remembering region thing for later.");
// remember this thing
thing[nthings] = &region->outline->thing[i];
nthings++;
}
}
}
} else {
if (db) dblog(" region has no outline.");
}
// build it...
if (db) dblog(" creating map habitat.");
createhabitat(map, depth, parentmap, exitdir, entryob);
// add home objects
if (db) dblog(" adding home objects.");
for (lf = map->lf ; lf ; lf = lf->next) {
addhomeobs(lf);
}
// add outline things
if (db) dblog(" adding remembered region outline things...");
for (i = 0; i < nthings ;i++) {
vault_t *v;
// add this thing
@ -2086,26 +2132,38 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
case RT_HABITAT: // already handled above
break;
case RT_REGIONLINK:
if (db) dblog(" adding regionlink");
createregionlink(map, NULL, NULL, thing[i]->what, thing[i]->value, map->region);
// ... don't need to do this since we know there won't be anywhere to link to.
//linkstairs(o);
break;
case RT_VAULT:
if (db) dblog(" adding vault");
v = findvault(thing[i]->what);
assert(v);
if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) {
dblog("ERROR - couldn't create vault %s on map %s", v->id, map->name);
}
break;
case RT_RNDVAULTWITHFLAG:
if (db) dblog(" adding rndvaultwithflag");
v = findvaultwithflag(thing[i]->value);
assert(v);
if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) {
dblog("ERROR - couldn't create rndvaultwithflag %s on map %s", v->id, map->name);
}
break;
}
}
// special cases
// village - add town walls and clear it out
if (db) dblog(" finalising village creation...");
if (map->habitat->id == H_VILLAGE) {
int x1 = 999,y1 = 999,x2 = -1,y2 = -1,x,y;
int gx,gy;
int guardx[2], guardy[2];
int gx[MAXDIR_ORTH],gy[MAXDIR_ORTH];
int guardx[MAXDIR_ORTH][2], guardy[MAXDIR_ORTH][2];
int dir;
cell_t *c;
// find outermost dimensions of shops
for (y = 0; y < map->h; y++) {
@ -2131,40 +2189,42 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
limit(&y2, 0, map->h-1);
// decide where the gate will be (not the corner)
switch (rnd(D_N, D_W)) {
for (dir = D_N; dir <= D_W; dir++) {
switch (dir) {
case D_N:
gx = rnd(x1+2,x2-2);
gy = y1;
guardx[0] = gx-1;
guardy[0] = gy+1;
guardx[1] = gx+1;
guardy[1] = gy+1;
gx[dir] = rnd(x1+2,x2-2);
gy[dir] = y1;
guardx[dir][0] = gx[dir]-1;
guardy[dir][0] = gy[dir]+1;
guardx[dir][1] = gx[dir]+1;
guardy[dir][1] = gy[dir]+1;
break;
case D_E:
gx = x2;
gy = rnd(y1+2,y2-2);
guardx[0] = gx-1;
guardy[0] = gy-1;
guardx[1] = gx-1;
guardy[1] = gy+1;
gx[dir] = x2;
gy[dir] = rnd(y1+2,y2-2);
guardx[dir][0] = gx[dir]-1;
guardy[dir][0] = gy[dir]-1;
guardx[dir][1] = gx[dir]-1;
guardy[dir][1] = gy[dir]+1;
break;
case D_S:
gx = rnd(x1+2,x2-2);
gy = y2;
guardx[0] = gx-1;
guardy[0] = gy-1;
guardx[1] = gx+1;
guardy[1] = gy-1;
gx[dir] = rnd(x1+2,x2-2);
gy[dir] = y2;
guardx[dir][0] = gx[dir]-1;
guardy[dir][0] = gy[dir]-1;
guardx[dir][1] = gx[dir]+1;
guardy[dir][1] = gy[dir]-1;
break;
case D_W:
gx = x1;
gy = rnd(y1+2,y2-2);
guardx[0] = gx+1;
guardy[0] = gy-1;
guardx[1] = gx+1;
guardy[1] = gy+1;
gx[dir] = x1;
gy[dir] = rnd(y1+2,y2-2);
guardx[dir][0] = gx[dir]+1;
guardy[dir][0] = gy[dir]-1;
guardx[dir][1] = gx[dir]+1;
guardy[dir][1] = gy[dir]+1;
break;
}
}
// fill in town walls and clearing
for (y = 0; y <= map->h; y++) {
@ -2179,13 +2239,14 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
// mark as different habitat to outside
c->habitat = findhabitat(H_VILLAGE);
if ((c->x == gx) && (c->y == gy)) {
// town gate location
clearcell(c);
if (!isroom(c)) {
// get rid of objects (ie. trees) here
killallobs(c->obpile);
// make the ground dirt
setcelltype(c, CT_DIRT);
addob(c->obpile, "wooden gate");
} else if ((c->x == x1) || (c->y == y1) ||
}
if ((c->x == x1) || (c->y == y1) ||
(c->x == x2) || (c->y == y2)) {
// town perimeter (walls)
if (!isroom(c)) {
@ -2193,21 +2254,33 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
setcelltype(c, CT_DIRT);
addob(c->obpile, "wooden fence");
}
} else { // elsewhere within the town grounds
if (!isroom(c)) {
// get rid of objects (ie. trees) here
killallobs(c->obpile);
// make the ground dirt
}
for (dir = D_N; dir <= D_W; dir++) {
// town gate location
if ((c->x == gx[dir]) && (c->y == gy[dir])) {
int d2;
cell_t *c2;
clearcell(c);
setcelltype(c, CT_DIRT);
addob(c->obpile, "wooden gate");
// also make surrounding forest cells be dirt and no trees,
for (d2 = DC_N; d2 <= DC_NW; d2++) {
c2 = getcellindir(c, d2);
if (c2 && (c2->habitat->id != H_VILLAGE)) {
clearcell(c2);
setcelltype(c2, CT_DIRT);
}
}
}
// village guards
for (i = 0; i < 1; i++) {
if ((c->x == guardx[i]) && (c->y == guardy[i])) {
if ((c->x == guardx[dir][i]) && (c->y == guardy[dir][i])) {
addmonster(c, R_TOWNGUARD, B_FALSE, 1, B_TRUE, NULL);
}
}
}
}
} else {
// not within the village
c->habitat = findhabitat(H_FOREST);
@ -2218,6 +2291,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
}
// try to join up any unlinked staircases in this map.
if (db) dblog(" joining unlinked stairs...");
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
cell_t *c;
@ -2227,7 +2301,18 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
if (o && !getstairdestination(o)) {
// this will join these stairs to existing ones on
// existing adjacent maps
linkstairs(o, NULL);
if (!linkstairs(o, NULL)) {
if (db) {
cell_t *dst;
dst = getstairdestination(o);
dblog(" linked '%s' to map %s",o->type->name, dst->map->name);
}
} else {
if (db) {
dblog(" FAILED to link stiars: '%s'",o->type->name);
}
}
}
}
}
@ -2235,9 +2320,13 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
// link up holes - this will create NEW holes in THIS map connecting to
// EXISTING unlinked holes in adjacent maps
linkholes(map);
i = linkholes(map);
if (db) {
if (db) dblog(" autolinked to %d holes in adjacent maps.",i);
}
// add random objects and monsters
if (db) dblog(" adding random objects+monsters");
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
cell_t *c;
@ -2252,6 +2341,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
}
// look for adjacent maps
if (db) dblog(" linking to adjacent maps");
getmapcoords(map, &x, &y);
assert(x != -999);
assert(y != -999);
@ -2260,21 +2350,34 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
int thisx,thisy;
getmapcoords(m, &thisx, &thisy);
if (map->nextmap[D_N] == -1) {
if (thisy == (y - 1)) map->nextmap[D_N] = m->id;
if (thisy == (y - 1)) {
map->nextmap[D_N] = m->id;
if (db) dblog(" linked to map %d (dir N)",m->id);
}
}
if (map->nextmap[D_E] == -1) {
if (thisx == (x + 1)) map->nextmap[D_E] = m->id;
if (thisx == (x + 1)) {
map->nextmap[D_E] = m->id;
if (db) dblog(" linked to map %d (dir E)",m->id);
}
}
if (map->nextmap[D_S] == -1) {
if (thisy == (y + 1)) map->nextmap[D_S] = m->id;
if (thisy == (y + 1)) {
map->nextmap[D_S] = m->id;
if (db) dblog(" linked to map %d (dir S)",m->id);
}
}
if (map->nextmap[D_W] == -1) {
if (thisx == (x - 1)) map->nextmap[D_W] = m->id;
if (thisx == (x - 1)) {
map->nextmap[D_W] = m->id;
if (db) dblog(" linked to map %d (dir W)",m->id);
}
}
}
}
map->beingcreated = B_FALSE;
if (db) dblog(" Map creation finished.");
}
int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *retx, int *rety) {
@ -2496,7 +2599,7 @@ void createregionlink(map_t *m, cell_t *c, object_t *o, char *obname, enum REGIO
flag_t *f;
region_t *r;
// create a new region
r = addregion(newregiontype, m->region);
r = addregion(newregiontype, m->region, -1);
// add stairs to new region
if (!c) {
c = NULL;
@ -2887,6 +2990,14 @@ cell_t *findobinmap(map_t *m, enum OBTYPE oid) {
return NULL;
}
regionoutline_t *findoutline(int id) {
regionoutline_t *ro;
for (ro = firstregionoutline ;ro ; ro = ro->next) {
if (ro->id == id) return ro;
}
return NULL;
}
region_t *findregion(int regionid) {
region_t *r;
for (r = firstregion ; r ; r = r->next) {
@ -3015,6 +3126,21 @@ cell_t *getcellindir(cell_t *cell, int dir) {
return newcell;
}
cell_t *getclosestroomcell(lifeform_t *lf, int roomid) {
int i;
cell_t *c,*best = NULL;
int closest = 9999;
for (i = 0; i < lf->cell->map->w * lf->cell->map->h; i++) {
c = lf->cell->map->cell[i];
if ((c->roomid == roomid) & cellwalkable(lf, c, NULL)) {
if (getcelldist(lf->cell, c) < closest) {
best = c;
}
}
}
return best;
}
// select a new direction (random chance of turnung)
int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved) {
int foundvaliddir = B_FALSE;
@ -3495,7 +3621,7 @@ void initmap(void) {
addregiontype(RG_WORLDMAP, H_FOREST, 10, 0, D_NONE, B_TRUE);
addregiontype(RG_FIRSTDUNGEON, H_DUNGEON, 30, 3, D_DOWN, B_TRUE);
addregiontype(RG_PIT, H_PIT, 1, 1, D_DOWN, B_FALSE);
// region outlines
// region definitions (outlines)
addregionoutline(RG_WORLDMAP);
// link to first dungeon
addregionthing(lastregionoutline, NA, 0, 0, RT_REGIONLINK, RG_FIRSTDUNGEON, "staircase going down");
@ -3509,9 +3635,11 @@ void initmap(void) {
*/
vx = 0; vy = -1;
addregionthing(lastregionoutline, NA, vx, vy, RT_HABITAT, H_VILLAGE, NULL);
addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "potion_shop");
addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "weapon_shop");
addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "armour_shop");
addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "food_shop");
addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "pub");
addregionthing(lastregionoutline, NA, vx, vy, RT_RNDVAULTWITHFLAG, F_VAULTISSHOP, NULL);
addregionthing(lastregionoutline, NA, vx, vy, RT_RNDVAULTWITHFLAG, F_VAULTISSHOP, NULL);
addregionthing(lastregionoutline, NA, vx, vy, RT_RNDVAULTWITHFLAG, F_VAULTISSHOP, NULL);
addregionoutline(RG_FIRSTDUNGEON);
addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair");
}
@ -3754,12 +3882,14 @@ int iswallindir(cell_t *cell, int dir) {
// search for unlinked pits/holes in roof in ADJACENT maps
// if we find any, add a matching end as close as we can in THIS map.
void linkholes(map_t *map) {
// returns then umber of holes linked.
int linkholes(map_t *map) {
map_t *adjmap;
cell_t *c;
object_t *o, *newob;
int x,y;
int dir;
int nlinked = 0;
for (dir = D_UP ; dir <= D_DOWN; dir++) {
adjmap = getmapindir(map, dir);
@ -3792,6 +3922,14 @@ void linkholes(map_t *map) {
newob = addobject(c2->obpile, ot->name, B_FALSE, B_FALSE);
// link holes manually now.
linkstairs(newob, o);
// objects above fall down
if (dir == D_UP) {
obsfallthrough(c, o);
} else {
obsfallthrough(c2, newob);
}
nlinked++;
}
}
}
@ -3799,6 +3937,7 @@ void linkholes(map_t *map) {
}
}
}
return nlinked;
}
// link the staircase 'o' to a free one in adjacent maps.
@ -3990,6 +4129,36 @@ void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong) {
}
}
void mapentereffects(map_t *m) {
int i;
cell_t *c;
flag_t *f;
for (i = 0; i < m->w * m->h; i++) {
// teleport shopkeepers back to their shops
c = m->cell[i];
if (c->lf && hasjob(c->lf, J_SHOPKEEPER) && !isplayer(c->lf)) {
f = lfhasflag(c->lf, F_OWNSSHOP);
if (f) {
cell_t *where;
int myshop;
myshop = f->val[0];
// find the closest cell of my shop
where = getclosestroomcell(c->lf, myshop);
if (where) {
movelf(c->lf, where);
}
}
}
// replace people in the Inn
if (c->vault && streq(c->vault->id, "inn") && c->lf && (c->lf->race->id == R_HUMAN)) {
lifeform_t *lf;
killlf(c->lf);
lf = addmonster(c, R_HUMAN, B_TRUE, 1, B_FALSE, NULL);
addflag(lf->flags, F_STAYINROOM, c->roomid, NA, NA, NULL);
}
}
}
void setcellknown(cell_t *cell, int forcelev) {
enum SKILLLEVEL slev;
object_t *o;
@ -4188,6 +4357,12 @@ int validateregionthing(regionthing_t *thing) {
return B_TRUE;
}
break;
case RT_RNDVAULTWITHFLAG:
if (!findvaultwithflag(thing->value)) {
dblog("Invalid rt_rndvaultwithflag specified in regionthing.");
return B_TRUE;
}
break;
}
return B_FALSE;
}

7
map.h
View File

@ -7,7 +7,7 @@ map_t *addmap(void);
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int autogen, int *nadded);
object_t *addrandomob(cell_t *c);
int addrandomthing(cell_t *c, int obchance, int *nadded);
region_t *addregion(enum REGIONTYPE rtype, region_t *parent);
region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid);
regionoutline_t *addregionoutline(enum REGIONTYPE rtype);
regionthing_t *addregionthing(regionoutline_t *ro, int depth, int x, int y, enum REGIONTHING whatkind, int value, char *what);
regiontype_t *addregiontype(enum REGIONTYPE id, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major);
@ -58,6 +58,7 @@ map_t *findmapofdepth(int depth);
cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf);
object_t *findobidinmap(map_t *m, long id);
cell_t *findobinmap(map_t *m, enum OBTYPE oid);
regionoutline_t *findoutline(int id);
region_t *findregion(int regionid);
region_t *findregionbytype(enum REGIONTYPE rtid);
map_t *findregionmap(int regionid, int depth);
@ -65,6 +66,7 @@ regiontype_t *findregiontype(enum REGIONTYPE rtype);
map_t *findsurfaceexitmap(map_t *m);
void forgetcells(map_t *map, int amt);
cell_t *getcellindir(cell_t *cell, int dir);
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);
@ -99,11 +101,12 @@ int isoutdoors(map_t *m);
int isroom(cell_t *c);
int iswallindir(cell_t *cell, int dir);
int linkexits(map_t *m, int roomid, int minx, int miny, int maxx, int maxy);
void linkholes(map_t *map);
int linkholes(map_t *map);
int linkstairs(object_t *o, object_t *o2);
void makedoor(cell_t *cell, int openchance);
void makelit(cell_t *c, enum LIGHTLEV how, int howlong);
void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong);
void mapentereffects(map_t *m);
void setcellknown(cell_t *cell, int forcelev);
void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype);
void setcelltype(cell_t *cell, enum CELLTYPE id);

100
move.c
View File

@ -138,7 +138,7 @@ int canswapwith(lifeform_t *lf, lifeform_t *lf2) {
// onlyifknown = true means "check for _known_ dangerous objects"
// onlyifknown = false means "check for _any dangerous objects, doesn't matter if we know about them"
int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *error) {
enum IQBRACKET iq;
enum ATTRBRACKET iq;
int include_nonobvious = B_FALSE;
flag_t *f;
object_t *o;
@ -200,6 +200,15 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err
}
}
}
f = obrestrictsmovement(o, lf);
if (f) {
// always avoid if possible
if (error) {
*error = E_AVOIDOB;
rdata = o;
}
return B_TRUE;
}
f = hasflag(o->flags, F_WALKDAM);
if (f) {
if ((f->val[0] != DT_WATER) || isvulnto(lf->flags, DT_WATER)) {
@ -220,8 +229,8 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err
if (!onlyifknown) {
include_nonobvious = B_TRUE;
} else {
iq = getiqname(getattr(lf, A_IQ), NULL);
if ((iq >= IQ_AVERAGE) && haslos(lf, cell)) {
iq = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
if ((iq >= AT_AVERAGE) && haslos(lf, cell)) {
if (!lfhasflag(lf, F_UNDEAD)) {
include_nonobvious = B_TRUE;
}
@ -644,6 +653,13 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
int mightfall = B_TRUE;
lifeform_t *newlf;
if (lfhasflag(lf, F_GRAVLESSENED)) {
howfar *= 2;
} else if (lfhasflag(lf, F_GRAVBOOSTED)) {
howfar /= 2;
if (howfar < 0) howfar = 0;
}
// calculate chance of falling
if (fallcheckdiff == 0) {
// chance based on distance
@ -962,6 +978,11 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
needredraw = B_TRUE;
}
// special effects when the player moves to a new map
if (changedlev && isplayer(lf)) {
mapentereffects(newcell->map);
}
didmsg = moveeffects(lf);
killflagsofid(lf->flags, F_HIDING);
@ -1193,18 +1214,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
shk = findshopkeeper(lf->cell->map, preshop);
// do you have any unpaid items from that shop?
if (shk && getowing(lf, preshop, &nitems)) {
char saybuf[BUFLEN];
// warning...
switch (rnd(1,3)) {
case 1: sprintf(saybuf, "Hey! Where do you think you're going?");
break;
case 2: sprintf(saybuf, "AHEM!");
break;
case 3: sprintf(saybuf, "I hope you are going to pay for %s!",
(nitems == 1) ? "that" : "those" );
break;
}
say(shk, saybuf, SV_SHOUT);
sayphrase(shk, SP_PAYWARN, SV_SHOUT, NA, (nitems == 1) ? "that" : "those" );
didmsg = B_TRUE;
}
} else if (lf->cell->roomid != preshop) {
@ -1212,17 +1223,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
lifeform_t *shk;
shk = findshopkeeper(lf->cell->map, preshop);
if (shk && getowing(lf, preshop, NULL)) {
char saybuf[BUFLEN];
// call the guards
switch (rnd(1,3)) {
case 1: sprintf(saybuf, "Stop thief!");
break;
case 2: sprintf(saybuf, "GUARDS!");
break;
case 3: sprintf(saybuf, "I've been robbed!");
break;
}
say(shk, saybuf, SV_ROAR);
sayphrase(shk, SP_PAYTHREAT, SV_ROAR, NA, NULL);
didmsg = B_TRUE;
fightback(shk, lf); // shopkeeper attacks
callguards(shk, lf); // guards come running
@ -1369,19 +1371,13 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
msg("%s trigger%s %s!", lfname, isplayer(lf) ? "" : "s", trapname);
if (isplayer(lf)) more();
}
trapeffects(o, o->type->id, lf);
interrupt(lf);
if (haslos(player, newcell)) {
// no longer hidden
killflagsofid(o->flags, F_SECRET);
}
switch (o->type->id) {
case OT_TRAPGAS:
removeob(o, o->amt);
break;
default:
break;
}
// NOTE: after trapeffects(), o might be killed.
trapeffects(o, o->type->id, lf);
interrupt(lf);
}
}
}
@ -1775,30 +1771,17 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) {
nexto = o->next;
if ((o->type->id == OT_WEB) && (lf->race->baseid == R_SPIDER)) {
continue;
}
if ((o->type->id == OT_VINE) && hasjob(lf, J_DRUID)) {
continue;
}
f = hasflag(o->flags, F_RESTRICTMOVEMENT);
f = obrestrictsmovement(o, lf);
if (f) {
char lfname[BUFLEN];
int diff;
int checkmod = 0;
int getsweaker;
if (isairborne(lf) && (f->val[2] != B_TRUE)) {
continue;
}
if ((o->type->id == OT_WEB) && isairborne(lf)) {
checkmod -= 5;
}
getlfname(lf,lfname);
getobname(o, buf, o->amt);
@ -1859,6 +1842,7 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) {
msg("%s stands up.",lfname);
}
killflagsofid(lf->flags, F_PRONE);
killflagsofid(lf->flags, F_FEIGNINGDEATH);
// time to get up depends on armour
// 1*movespeed for every 1/4 of maxcarryweight being worn.
quartermax = getmaxcarryweight(lf) / 4;
@ -2440,12 +2424,13 @@ int walkoffmap(lifeform_t *lf, int dir, int onpurpose) {
int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell;
enum IQBRACKET iq;
enum ATTRBRACKET iq;
object_t *o;
char buf[BUFLEN];
flag_t *f;
//object_t *o;
iq = getiqname(getattr(lf, A_IQ), NULL);
iq = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
// default
if (error) {
@ -2468,10 +2453,19 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
return B_FALSE;
}
if (!isroom(cell) && hasjob(lf, J_SHOPKEEPER)) {
// shopkeepers will only leave their shops if they have a target
f = lfhasflag(lf, F_STAYINROOM);
if (f) {
int roomid;
roomid = f->val[0];
// if moving out of my room..
if ((lf->cell->roomid == roomid) && (lf->cell->roomid != cell->roomid)) {
if (!aihastarget(lf)) {
if (error) *error = E_WONT;
return B_FALSE;
}
}
}
if (lfhasflag(lf, F_STAYINHABITAT) && (cell->habitat->id != lf->cell->habitat->id)) {
if (error) *error = E_WONT;
@ -2501,7 +2495,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
}
// for at least average iq things...
if (iq >= IQ_AVERAGE) {
if (iq >= AT_AVERAGE) {
// don't move if in pain
if (lfhasflag(lf, F_PAIN)) {
if (error) *error = E_WONT;
@ -2528,13 +2522,13 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
if (hasflag(o->flags, F_TRAP)) {
if (hasflag(o->flags, F_SECRET)) {
// hidden traps?
if (iq >= IQ_SMART) {
if (iq >= AT_GTAVERAGE) {
if (error) *error = E_WONT;
return B_FALSE;
}
} else {
// non-hidden traps?
if (iq >= IQ_AVERAGE) {
if (iq >= AT_AVERAGE) {
if (error) *error = E_WONT;
return B_FALSE;
}

85
nexus.c
View File

@ -38,6 +38,8 @@ regionoutline_t *firstregionoutline = NULL,*lastregionoutline = NULL;
regiontype_t *firstregiontype = NULL,*lastregiontype = NULL;
knowledge_t *knowledge = NULL, *lastknowledge = NULL;
hiddenname_t *firsthiddenname = NULL, *lasthiddenname = NULL;
npcname_t *npcname;
int numnpcnames;
extern vault_t *firstvault;
@ -177,7 +179,7 @@ int main(int argc, char **argv) {
}
j = NULL;
while (!j) {
getchoice(&prompt);
getchoicestr(&prompt, B_FALSE, B_TRUE);
j = prompt.result;
}
}
@ -188,12 +190,14 @@ int main(int argc, char **argv) {
region_t *wregion, *dregion;
newworld = B_TRUE;
// create world map.
wregion = addregion(RG_WORLDMAP, NULL);
wregion = addregion(RG_WORLDMAP, NULL, -1);
assert(wregion);
addmap();
createmap(firstmap, 1, wregion, NULL, D_NONE, NULL);
//createmap(firstmap, 1, RG_FIRSTDUNGEON, H_DUNGEON, NULL, D_NONE);
// create first dungeon
dregion = findregionbytype(RG_FIRSTDUNGEON);
assert(dregion);
dmap = addmap();
createmap(dmap, 1, dregion, firstmap, D_DOWN, NULL);
}
@ -278,9 +282,8 @@ int main(int argc, char **argv) {
c = getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND);
assert(c);
pet = addlf(c, r->id, 1);
makefriendly(pet, PERMENANT);
// mark us as its master
addflag(pet->flags, F_PETOF, player->id, player->cell->x, player->cell->y, NULL);
petify(pet, player);
}
getplayernamefull(pname);
@ -533,6 +536,9 @@ void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, in
void donextturn(map_t *map) {
lifeform_t *who;
int db = B_FALSE;
map_t *oldpmap;
oldpmap = player->cell->map;
who = map->lf;
if (db) dblog("**** donextturn for: id %d %s", who->id, who->race->name);
@ -738,8 +744,19 @@ void donextturn(map_t *map) {
//////////////////////////////////
// note: can't use 'who->' below since 'who' might have died
// and been de-alloced during checkdeath() above.
timeeffectsworld(player->cell->map); // in case the player changed levels!
// and been de-alloced during checkdeath() above if they
// died.
timeeffectsworld(player->cell->map);
// the previous call to timeeffectsworld might cause the player to
// change levels (ie. falling down through one or more pits).
//
// if this happens, we need to call it again to make sure that ->timespent
// values don't get out of whack.
while (player->cell->map != oldpmap) {
oldpmap = player->cell->map;
timeeffectsworld(player->cell->map);
}
}
char *getdirname(int dir) {
@ -834,6 +851,9 @@ int init(void) {
tempglyph.ch = '@';
tempglyph.colour = C_GREY;
// load npc names
loadnpcnames();
initcommands();
initobjects();
initskills();
@ -1010,6 +1030,45 @@ int limitf(float *what, float min, float max) {
return limited;
}
int loadnpcnames(void) {
FILE *f;
char buf[BUFLEN];
int i = 0;
f = fopen("data/npcnames.txt", "rt");
if (!f) return B_TRUE;
// count lines...
fgets(buf, BUFLEN, f);
numnpcnames = 0;
while (!feof(f)) {
buf[strlen(buf)-1] = '\0'; // strip newline
if (strlen(buf)) {
numnpcnames++;
}
fgets(buf, BUFLEN, f);
}
// alloc mem
npcname = malloc(numnpcnames * sizeof(npcname_t));
// back to start
fseek(f, 0, SEEK_SET);
// now read in names
fgets(buf, BUFLEN, f);
while (!feof(f)) {
buf[strlen(buf)-1] = '\0'; // strip newline
if (strlen(buf)) {
capitalise(buf);
npcname[i].name = strdup(buf);
npcname[i].valid = B_TRUE;
i++;
}
fgets(buf, BUFLEN, f);
}
return B_FALSE;
}
int onein(int howmany) {
if (howmany <= 0) return B_FALSE;
if (rnd(1,howmany) == 1) return B_TRUE;
@ -1067,6 +1126,13 @@ int parseplayerfile(FILE *f, lifeform_t *lf) {
return goterror;
}
int pctchance(int pct) {
if (rnd(1,100) <= pct) {
return B_TRUE;
}
return B_FALSE;
}
float pctof(float pct, float num) {
return ((pct / 100.0) * num);
}
@ -1372,6 +1438,13 @@ void timeeffectsworld(map_t *map) {
cell_t *c;
c = getcellat(map, x, y);
if (c) {
object_t *pit;
pit = hasobwithflagval(c->obpile, F_PIT, D_DOWN, NA, NA, NULL);
if (pit) {
obsfallthrough(c, pit);
}
// go through each object in the cell...
for (o = c->obpile->first ; o ; o = nexto) {
nexto = o->next;

View File

@ -20,8 +20,10 @@ void initcommands(void);
int isplayerturn(void);
int limit(int *what, int min, int max);
int limitf(float *what, float min, float max);
int loadnpcnames(void);
int onein(int howmany);
int parseplayerfile(FILE *f, lifeform_t *lf);
int pctchance(int pct);
float pctof(float pct, float num);
int rnd(int min, int max);
int roll(char *string);

1875
objects.c

File diff suppressed because it is too large Load Diff

View File

@ -13,9 +13,9 @@ object_t *addob(obpile_t *where, char *name);
object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes);
int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fromlf, enum LOFTYPE needlof);
obmod_t *addobmod(enum OBMOD id, char *prefix);
obpile_t *addobpile(lifeform_t *owner, cell_t *where);
obpile_t *addobpile(lifeform_t *owner, cell_t *where, object_t *parentob);
void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes);
objecttype_t *addot(enum OBTYPE id, char *name, char *description, int material, float weight, int obclassid);
objecttype_t *addot(enum OBTYPE id, char *name, char *description, int material, float weight, int obclassid, enum LFSIZE size);
void adjustdamhardness(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat);
void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat);
void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype);
@ -63,11 +63,14 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob
int getobaccuracy(object_t *wep, lifeform_t *weilder);
int getobbonus(object_t *o);
skill_t *getobskill(object_t *o);
enum LFSIZE getobsize(object_t *o);
int getobspellpower(object_t *o, lifeform_t *lf);
int getobvalue(object_t *o);
char *getoperateverb(object_t *o);
object_t *getoutercontainer(object_t *o);
//int getobtypevalue(objecttype_t *ot);
char *getaccuracyname(int accpct);
object_t *getammo(lifeform_t *lf);
object_t *getammo(object_t *gun);
objecttype_t *getbasicweaponforskill(enum SKILL skid);
object_t *getrandomammo(lifeform_t *lf);
objecttype_t *getrandomammofor(object_t *o);
@ -104,8 +107,9 @@ char *getobhurtname(object_t *o, enum DAMTYPE damtype);
float getobweight(object_t *o);
float getobunitweight(object_t *o);
objecttype_t *getoppositestairs(objecttype_t *ot);
char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth, int forcehabitat);
char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth, int forcehabitat, enum LFSIZE maxsize);
char *getrandomob(map_t *map, char *buf);
char *getrandomobofsize(map_t *map, char *buf, enum LFSIZE maxsize);
char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf);
char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf, int depthmod);
int getobrarity(object_t *o, enum RARITY *rr);
@ -196,6 +200,8 @@ int obmatchescondition(object_t *o, long opts);
int obproduceslight(object_t *o);
int obpropsmatch(object_t *a, object_t *b);
int obotpropsmatch(object_t *a, objecttype_t *b);
flag_t *obrestrictsmovement(object_t *o, lifeform_t *lf);
int obsfallthrough(cell_t *c, object_t *pit);
int operate(lifeform_t *lf, object_t *o, cell_t *where);
int pilehasletter(obpile_t *op, char let);
void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE potlessed, int *seen);

203
save.c
View File

@ -13,6 +13,7 @@
#include "nexus.h"
#include "objects.h"
#include "save.h"
#include "text.h"
#include "vault.h"
extern long curtime;
@ -20,6 +21,8 @@ extern long curtime;
extern lifeform_t *player;
extern map_t *firstmap;
extern knowledge_t *knowledge;
extern region_t *firstregion,*lastregion;
extern regionoutline_t *firstregionoutline,*lastregionoutline;
extern enum GAMEMODE gamemode;
@ -34,6 +37,14 @@ int loadall(void) {
dblog("Could not open map directory '%s'",MAPDIR);
return B_TRUE;
}
// load region outlines first.
if (loadregions()) {
// this isn't an error - just means no savegames
dblog("No region data found.");
return B_FALSE;
}
// for each map file in directory
while ((ent = readdir(dir)) != NULL) {
char *p;
@ -61,7 +72,7 @@ int loadflagpile(FILE *f, flagpile_t *fp) {
flag_t *fl;
char buf[BUFLEN];
int rv;
int db = B_TRUE;
int db = B_FALSE;
rv = fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%ld\n",
&tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2],&tempflag.lifetime, &tempflag.known,&tempflag.obfrom);
@ -265,6 +276,7 @@ map_t *loadmap(char *basefile) {
object_t *o;
map_t *m;
cell_t *dummycell;
int regionid;
if (db) dblog("Loading map from %s...",basefile);
sprintf(filename, "%s/%s",MAPDIR,basefile);
@ -273,7 +285,7 @@ map_t *loadmap(char *basefile) {
// create map
m = addmap();
dummycell = malloc(sizeof(cell_t));
dummycell->obpile = addobpile(NULL, dummycell);
dummycell->obpile = addobpile(NULL, dummycell, NULL);
dummycell->map = m;
dummycell->type = (celltype_t *)DUMMYCELLTYPE; // for debugging
@ -285,11 +297,13 @@ map_t *loadmap(char *basefile) {
// load map info
if (db) dblog("--> Loading map info...\n");
fscanf(f, "id:%d\n",&m->id); // map id
fscanf(f, "region:%d\n",&regionid); // region id
m->region = findregion(regionid);
fscanf(f, "depth:%d\n",&m->depth); // map depth
fgets(buf, BUFLEN, f); // map name
buf[strlen(buf)-1] = '\0'; // strip newline
m->name = strdup(buf + 5); // after 'name:'
fscanf(f, "habitat:%d\n",(int *)habitatid); // habitat
fscanf(f, "habitat:%d\n",(int *)&habitatid); // habitat
m->habitat = findhabitat(habitatid);
fscanf(f, "seed:%d\n",&m->seed); // seed
fscanf(f, "dims:%d,%d\n",&m->w, &m->h); // map dimensons
@ -549,7 +563,105 @@ int loadob(FILE *f, obpile_t *op, long *id) {
dblog("About to start loading object flags...");
loadflagpile(f, o->flags);
fscanf(f, "endob\n");
fgets(buf, BUFLEN, f);// either 'obcontents:xx' or 'endob'
if (strstarts(buf, "obcontents")) {
// load this object's contents...
char *p;
char buf2[BUFLEN];
int ncontents;
int i;
//dblog("got obcontents");
// strip newline
buf[strlen(buf)-1] = '\0';
p = readuntil(buf2, buf, ':'); // ignore bit before :
p = readuntil(buf2, p, ')'); // ) will really be eol
ncontents = atoi(buf2);
for (i = 0 ; i < ncontents; i++) {
loadob(f, o->contents, NULL);
}
fgets(buf, BUFLEN, f);// 'endobcontents'
//dblog("want endobcontents, got: '%s'", buf);
fgets(buf, BUFLEN, f);// 'endob'
//dblog("want endob, got: '%s'", buf);
}
if (strstarts(buf, "endob")) {
// we got 'endob'
} else {
dblog("ERROR loading objects - expecting 'endob' but got '%s'\n",buf);
exit(1);
}
//fscanf(f, "endob\n");
return B_FALSE;
}
int loadregions(void) {
FILE *f;
char filename[BUFLEN];
int rtid,nthings,i,n;
int numoutlines,numregions;
int db = B_FALSE;
// TODO: check that map dir exists
sprintf(filename, "%s/regions.dat",MAPDIR);
f = fopen(filename, "rt");
if (!f) {
return B_TRUE;
}
fscanf(f, "numoutlines:%d\n",&numoutlines);
if (db) dblog("Found %d region outlines.\n",numoutlines);
for (n = 0; n < numoutlines; n++) {
fscanf(f, "startro\n");
fscanf(f, "rtypeid:%d\n",&rtid); // region type id
addregionoutline(rtid);
fscanf(f, "nthings:%d\n",&nthings);
for (i = 0; i < nthings; i++) {
int depth,x,y,val;
enum REGIONTHING whatkind;
char buf[BUFLEN],*p;
fscanf(f, "startthing\n");
fscanf(f, " thingdepth:%d,%d,%d\n",&depth, &x, &y);
fscanf(f, " thingkind:%d\n",(int *)&whatkind);
fscanf(f, " thingval:%d\n",&val);
fscanf(f, " thingwhat:%s\n",buf);
fscanf(f, "endthing\n");
// replace ^ with ' ' in thingwhat
for (p = buf ; *p; p++) {
if (*p == '^') *p = ' ';
}
addregionthing(lastregionoutline, depth, x, y, whatkind, val, streq(buf, "NULL") ? NULL : buf);
}
fscanf(f, "endro\n");
if (db) dblog("Loaded regionoutline #%d / %d",n+1, numoutlines);
}
// now save out the actual region->outline mappings
fscanf(f, "numregions:%d\n",&numregions);
if (db) dblog("Found %d regions.\n",numregions);
for (n = 0; n < numregions; n++) {
region_t *r;
enum REGIONTYPE rtid;
int outlineid,parentid,nthings;
fscanf(f, "startregion\n");
fscanf(f, " rtypeid:%d\n",(int *)&rtid);
fscanf(f, " outline:%d\n",&outlineid);
fscanf(f, " parentregion:%d\n",&parentid);
fscanf(f, " nthings:%d\n",&nthings);
fscanf(f, "endregion\n");
r = addregion(rtid, (parentid == -1) ? NULL : findregion(parentid), outlineid);
r->nthings = nthings;
if (db) dblog("Loaded region #%d / %d",n+1, numregions);
}
fclose(f);
// successful load - kill the file now
unlink(filename);
return B_FALSE;
}
@ -581,7 +693,7 @@ int loadsavegame(void) {
exit(1);
}
if (!loadlf(f, NULL)) {
printf("Error loading savegame from file '%s'",ent->d_name);
printf("Error loading player from file '%s'",ent->d_name);
exit(1);
}
if (loadknowledge(f)) {
@ -699,6 +811,12 @@ int savegame(void) {
FILE *f;
char buf[BUFLEN];
int rv;
rv = saveregions();
if (rv) {
msg("Could not save region data.");
return B_TRUE;
}
for (m = firstmap; m ; m = m->next) {
// save world
rv = savemap(m);
@ -737,6 +855,7 @@ int savemap(map_t *m) {
// save map info
fprintf(f, "id:%d\n",m->id); // map id
fprintf(f, "region:%d\n",m->region->id); // map region id
fprintf(f, "depth:%d\n",m->depth); // map depth
fprintf(f, "name:%s\n",m->name); // map name
fprintf(f, "habitat:%d\n",m->habitat->id); // habitat
@ -797,6 +916,8 @@ int savemap(map_t *m) {
int saveob(FILE *f, object_t *o) {
object_t *oo;
int ncontents;
fprintf(f, "id:%ld\n",o->id);
fprintf(f, "type:%d\n",o->type->id);
fprintf(f, "material:%d\n",o->material->id);
@ -808,6 +929,78 @@ int saveob(FILE *f, object_t *o) {
fprintf(f, "amt:%d\n",o->amt);
fprintf(f, "birthtime:%ld\n",o->birthtime);
saveflagpile(f, o->flags);
// object contents...
ncontents = countobs(o->contents, B_FALSE);
if (ncontents) {
fprintf(f, "obcontents:%d\n",ncontents);
for (oo = o->contents->first ; oo ; oo = oo->next) {
saveob(f, oo);
}
fprintf(f, "endobcontents\n");
}
fprintf(f, "endob\n");
return B_FALSE;
}
int saveregions(void) {
FILE *f;
char filename[BUFLEN];
int i;
regionoutline_t *ro;
region_t *r;
int numoutlines = 0,numregions = 0;
// TODO: check that map dir exists
sprintf(filename, "%s/regions.dat",MAPDIR);
f = fopen(filename, "wt");
for (ro = firstregionoutline ; ro ; ro = ro->next) {
numoutlines++;
}
fprintf(f, "numoutlines:%d\n",numoutlines);
for (ro = firstregionoutline ; ro ; ro = ro->next) {
// save this outline
fprintf(f, "startro\n");
fprintf(f, "rtypeid:%d\n",ro->rtype->id); // region type id
fprintf(f, "nthings:%d\n",ro->nthings);
for (i = 0; i < ro->nthings; i++) {
fprintf(f, "startthing\n");
fprintf(f, " thingdepth:%d,%d,%d\n",ro->thing[i].depth, ro->thing[i].x, ro->thing[i].y);
fprintf(f, " thingkind:%d\n",(int)ro->thing[i].whatkind);
fprintf(f, " thingval:%d\n",(int)ro->thing[i].value);
if (strlen(ro->thing[i].what)) {
char localwhat[BUFLEN],*p;
strcpy(localwhat,ro->thing[i].what);
for (p = localwhat ; *p; p++) {
if (*p == ' ') *p = '^';
}
fprintf(f, " thingwhat:%s\n",localwhat);
} else {
fprintf(f, " thingwhat:NULL\n");
}
fprintf(f, "endthing\n");
}
fprintf(f, "endro\n");
}
// now save out the actual region->outline mappings
numregions = 0;
for (r = firstregion ; r; r = r->next) {
numregions++;
}
fprintf(f, "numregions:%d\n",numregions);
for (r = firstregion ; r; r = r->next) {
fprintf(f, "startregion\n");
fprintf(f, " rtypeid:%d\n",r->rtype->id);
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, "endregion\n");
}
fclose(f);
return B_FALSE;
}

2
save.h
View File

@ -6,6 +6,7 @@ int loadknowledge(FILE *f);
lifeform_t *loadlf(FILE *f, cell_t *where);
map_t *loadmap(char *basefile);
int loadob(FILE *f, obpile_t *op, long *id);
int loadregions(void);
int loadsavegame(void);
int saveflagpile(FILE *f, flagpile_t *fp);
int saveknowledge(FILE *f);
@ -13,3 +14,4 @@ int savelf(FILE *f, lifeform_t *l);
int savegame(void);
int savemap(map_t *m);
int saveob(FILE *f, object_t *o);
int saveregions(void);

553
spell.c
View File

@ -390,6 +390,41 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
}
}
} else if (abilid == OT_A_FEIGNDEATH) {
lifeform_t *lf;
if (hasflag(user->flags, F_FEIGNINGDEATH)) {
if (isplayer(user)) msg("You are already feigning death!");
return B_TRUE;
}
taketime(user, getactspeed(user));
if (isplayer(user)) {
msg("You drop to the ground.");
} else if (cansee(player, user)) {
if (target) {
char targname[BUFLEN];
getlfname(target, targname);
msg("%s kill%s %s.", targname, isplayer(target) ? "" : "s", username);
} else {
msg("%s dies.", username);
}
}
addflag(user->flags, F_PRONE, B_TRUE, NA, NA, NULL);
addflag(user->flags, F_FEIGNINGDEATH, B_TRUE, NA, NA, NULL);
// anyone attacking you stops
for (lf = user->cell->map->lf ; lf ; lf = lf->next) {
flag_t *f;
char buf[BUFLENTINY];
f = hasflagval(lf->flags, F_TARGETLF, user->id, NA, NA, NULL);
if (f) killflag(f);
f = hasflagval(lf->flags, F_TARGETCELL, user->cell->x, user->cell->y, NA, NULL);
if (f) killflag(f);
sprintf(buf, "%d\n",user->id);
f = hasflagval(lf->flags, F_TARGETCELL, NA, NA, MR_LF, buf);
if (f) killflag(f);
}
needredraw = B_TRUE;
statdirty = B_TRUE;
} else if (abilid == OT_A_FLURRY) {
int dir;
int dirch;
@ -399,7 +434,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_TRUE;
}
if (!isdualweilding(user)) {
if (hasjob(user, J_MONK)) {
if (getweapon(user)) {
if (isplayer(user)) msg("You need be unarmed to perform an attack flurry!");
}
return B_TRUE;
} else if (!isdualweilding(user)) {
if (isplayer(user)) msg("You need two be dual-weilding to perform an attack flurry!");
return B_TRUE;
}
@ -561,28 +601,40 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
char victimname[BUFLEN];
int dodged = B_FALSE;
cell_t *origcell;
int maxrange = 2;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You can't jump while swimming!");
return B_TRUE;
} else if (isairborne(user)) {
if (isplayer(user)) msg("You can't jump while airbourne!");
return B_TRUE;
} else if (hasflag(user->flags, F_GRAVBOOSTED)) {
if (isplayer(user)) msg("You can't jump with gravity boosted around you!");
return B_TRUE;
}
if (hasflag(user->flags, F_GRAVLESSENED)) {
maxrange++;
}
if (!targcell) {
sprintf(buf, "Jump where (max distance 2)?");
sprintf(buf, "Jump where (max distance %d)?", maxrange);
while (!targcell) {
// ask where
targcell = askcoords(buf, "Jump->", TT_NONE, user, 2, LOF_DONTNEED, B_TRUE);
targcell = askcoords(buf, "Jump->", TT_NONE, user, maxrange, LOF_DONTNEED, B_TRUE);
if (!targcell) {
return B_TRUE;
} else if (getcelldist(user->cell, targcell) > 2) {
} else if (getcelldist(user->cell, targcell) > maxrange) {
targcell = NULL;
if (isplayer(user)) {
sprintf(buf, "You can't jump that far! Jump where (max distance 2)?");
sprintf(buf, "You can't jump that far! Jump where (max distance %d)?", maxrange);
}
} else if (!haslos(user, targcell)) {
targcell = NULL;
if (isplayer(user)) {
sprintf(buf, "You can't see where to land! Jump where (max distance 2)?");
sprintf(buf, "You can't see where to land! Jump where (max distance %d)?", maxrange);
}
}
}
@ -707,10 +759,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
int cutoff;
switch (slev) {
case PR_NOVICE: cutoff = 33; break;
case PR_BEGINNER: cutoff = 40; break;
case PR_ADEPT: cutoff = 50; break;
case PR_SKILLED: cutoff = 65; break;
case PR_EXPERT: cutoff = 80; break;
case PR_BEGINNER: cutoff = 50; break;
case PR_ADEPT: cutoff = 60; break;
case PR_SKILLED: cutoff = 70; break;
case PR_EXPERT: cutoff = 85; break;
case PR_MASTER: cutoff = 100; break;
default: cutoff = 0; break;
}
@ -723,10 +775,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
int cutoff;
switch (slev) {
case PR_NOVICE: cutoff = 33; break;
case PR_BEGINNER: cutoff = 40; break;
case PR_ADEPT: cutoff = 50; break;
case PR_SKILLED: cutoff = 65; break;
case PR_EXPERT: cutoff = 80; break;
case PR_BEGINNER: cutoff = 50; break;
case PR_ADEPT: cutoff = 60; break;
case PR_SKILLED: cutoff = 70; break;
case PR_EXPERT: cutoff = 85; break;
case PR_MASTER: cutoff = 100; break;
default: cutoff = 0; break;
}
@ -868,6 +920,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
addtempflag(user->flags, F_SPRINTING, B_TRUE, NA, NA, NULL, howlong);
practice(user, SK_ATHLETICS, 1);
// get hungry heaps!
modhunger(user, 50);
} else if (abilid == OT_A_STINGACID) {
validateabillf(user, abilid, &target);
if (!target) return B_TRUE;
@ -1031,6 +1085,109 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (haslos(player, origcell)) {
redraw();
}
} else if (abilid == OT_A_TUMBLE) {
cell_t *origcell,*c;
cell_t *retcell[MAXRETCELLS];
int i,nretcell = 0;
object_t *stopob = NULL;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You can't tumble while swimming!");
return B_TRUE;
} else if (isairborne(user)) {
if (isplayer(user)) msg("You can't tumble while airbourne!");
return B_TRUE;
}
if (!targcell) {
sprintf(buf, "Tumble where (max distance 2)?");
while (!targcell) {
// ask where
targcell = askcoords(buf, "Tumble->", TT_NONE, user, 2, LOF_NEED, B_TRUE);
if (!targcell) {
if (isplayer(user)) msg("Cancelled.");
return B_TRUE;
} else if (!haslos(user, targcell)) {
targcell = NULL;
if (isplayer(user)) {
sprintf(buf, "You can't see where to land! Tumble where (max distance 2)?");
}
} else if (!haslof(user->cell, targcell, LOF_NEED, NULL)) {
targcell = NULL;
if (isplayer(user)) {
sprintf(buf, "You don't have a clear line of fire to there!");
}
}
}
}
if (isburdened(user)) {
if (isplayer(user)) {
msg("Your load is too heavy to tumble with!");
}
return B_TRUE;
} else if (lfhasflag(user, F_GRAVBOOSTED)) {
if (isplayer(user)) {
msg("Gravity around you is too strong to tumble!");
}
return B_TRUE;
}
origcell = user->cell;
taketime(user, getactspeed(user));
// will you be interrupted on the way?
calcbresnham(origcell->map, origcell->x, origcell->y, targcell->x, targcell->y, retcell, &nretcell);
for (i = 0; i < nretcell; i++) {
c = retcell[i];
if (getcellwaterdepth(c, user)) {
// stop here.
targcell = c;
stopob = hasobwithflag(c->obpile, F_DEEPWATER);
break;
} else if (hasobwithflagval(c->obpile, F_PIT, D_DOWN, NA, NA, NULL)) {
// stop here.
targcell = c;
stopob = hasobwithflagval(c->obpile, F_PIT, D_DOWN, NA, NA, NULL);
break;
}
}
// skillcheck...
if (!skillcheck(user, SC_TUMBLE, 10, 0)) {
// fail!
if (isplayer(user)) {
msg("You fumble and fall.");
} else if (cansee(player, user)) {
msg("%s fumbles and falls.", username);
}
fall(user, NULL, B_FALSE);
return B_FALSE;
}
// go there!
movelf(user, targcell);
// announce
if (isplayer(user)) {
msg("You tumble across the ground!");
} else if (cansee(player, user)) {
msg("%s tumbles across the ground!", username);
}
// pits/water?
if (stopob) {
char obname[BUFLEN];
getobname(stopob, obname, 1);
if (isplayer(user)) {
msg("Your tumble is interrupted by %s!",obname);
} else if (cansee(player, user)) {
msg("%s%s tumble is interrupted by %s!",username,getpossessive(username), obname);
}
}
} else if (abilid == OT_A_POLYREVERT) {
flag_t *f;
if (!target) target = user;
@ -1170,6 +1327,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
char targetname[BUFLEN];
flag_t *f;
int heavyamt = 8;
int badweapon = B_FALSE;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You lack the stability for a heavy blow while swimming.");
@ -1177,7 +1335,15 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
wep = getweapon(user);
if (!wep || !ismeleeweapon(wep) || (getobunitweight(wep) < heavyamt)) { // ie. 8 is weight of a mace
if (!wep) {
if (!hasjob(user, J_MONK)) {
badweapon = B_TRUE;
}
} else if (!ismeleeweapon(wep) || (getobunitweight(wep) < heavyamt)) { // ie. 8 is weight of a mace
badweapon = B_TRUE;
}
if (badweapon) {
if (isplayer(user)) msg("You need a heavy weapon (%dkg or more) to perform a heavy blow!", heavyamt);
return B_TRUE;
}
@ -1207,7 +1373,52 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
getlfname(target, targetname);
f = addflag(wep->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL);
f = addflag(user->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL);
attackcell(user, targcell, B_TRUE);
killflag(f);
} else if (abilid == OT_A_QUIVERINGPALM) {
object_t *wep;
char dirch;
char targetname[BUFLEN];
flag_t *f;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You lack the stability to use this ability while swimming.");
return B_TRUE;
}
wep = getweapon(user);
if (wep) {
if (isplayer(user)) msg("You must be unarmed to make a quivering palm strike.");
return B_TRUE;
}
// ask for direction
if (!targcell) {
dirch = askchar("Attack in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE);
if (dirch == '.') {
// yourself!
targcell = user->cell;
} else {
int dir;
dir = chartodir(dirch);
if (dir == D_NONE) {
if (isplayer(user)) msg("Cancelled.");
return B_TRUE ;
} else {
targcell = getcellindir(user->cell, dir);
}
}
}
target = targcell->lf;
if (!target) {
if (isplayer(user)) msg("There is nobody there to attack!");
return B_TRUE;
}
getlfname(target, targetname);
f = addflag(user->flags, F_QUIVERINGPALM, B_TRUE, NA, NA, NULL);
attackcell(user, targcell, B_TRUE);
killflag(f);
} else if (abilid == OT_A_STEAL) {
@ -1895,6 +2106,19 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
teleportto(caster, targcell, B_TRUE);
}
} else if (spellid == OT_S_BODYCONTROL) {
flag_t *f;
// ie. 2 - 4
f = addtempflag(caster->flags, F_SLOWMETAB, 2+(power/4), NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
// you move more slowly too.
if (power < 3) {
f = addtempflag(caster->flags, F_SLOWMOVE, 10, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
} else if (power < 5) {
f = addtempflag(caster->flags, F_SLOWMOVE, 5, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
}
} else if (spellid == OT_S_BURNINGWAVE) {
cell_t *retcell[MAXRETCELLS];
int nretcell;
@ -2037,7 +2261,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int powerleft;
int donesomething = B_FALSE;
cell_t *c;
powerleft = rolldie(power+1, 4);
//powerleft = rolldie(power+1, 4);
powerleft = power;
for (i = 0; i < caster->nlos; i++) {
c = caster->los[i];
if (c->lf && (c->lf->race->raceclass->id == RC_ANIMAL) && (gethitdice(c->lf) <= powerleft)) {
@ -2328,13 +2553,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getlfname(target, lfname);
// how many body parts are impacted?
exposedlimbs = 0;
if (!getouterequippedob(target, BP_HEAD)) exposedlimbs += 1;
if (!getouterequippedob(target, BP_SHOULDERS)) exposedlimbs += 1;
if (!getouterequippedob(target, BP_BODY)) exposedlimbs += 2;
if (!getouterequippedob(target, BP_HANDS)) exposedlimbs += 1;
if (!getouterequippedob(target, BP_LEGS)) exposedlimbs += 2;
if (!getouterequippedob(target, BP_FEET)) exposedlimbs += 1;
exposedlimbs = getexposedlimbs(target);
dam = rolldie(exposedlimbs, 3);
@ -2358,9 +2577,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// always hit
if (!isimmuneto(target->flags, DT_COLD)) {
losehp(target, dam, DT_COLD, caster, "a chill spell");
if (!skillcheck(target, SC_CON, 20+(exposedlimbs*3), 0)) {
poison(target, 20+(power*3), P_COLD, 0, "a chill spell");
}
}
} else if (spellid == OT_S_COLDBURST) {
int range = 1;
@ -2515,6 +2731,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
jobname[0] = tolower(jobname[0]);
p = strstr(buf, jobname);
if (p) {
if (p == buf) {
// just asked for the job name
// fail.
break;
} else {
char newbuf[BUFLEN];
strncpy(newbuf, buf, (p - buf) - 1);
r = findracebyname(newbuf);
@ -2525,6 +2746,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
}
}
if (!r) {
fizzle(caster);
return B_TRUE;
@ -2691,8 +2913,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
return B_TRUE;
} else if (ch == '<') {
if (seenbyplayer && haslos(player, caster->cell)) *seenbyplayer = B_TRUE;
return digup(caster, NULL);
} else if (ch == '>') {
if (seenbyplayer && haslos(player, caster->cell)) *seenbyplayer = B_TRUE;
return digdown(caster, NULL);
} else {
dir = chartodir(ch);
@ -3503,6 +3727,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = hasflag(o->flags, F_RESTRICTMOVEMENT);
if (f) {
f->val[0] = 30 + (power/2);
f->val[1] = B_FALSE; // struggling doesn't damage the vine
}
/// remmeber creator. if they don't have los to us, spell
// is broken and vines will vanish.
@ -4261,7 +4486,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
// 4 is the same as ST_TITANIC strength
// 5 is the same as AT_VHIGH strength
// 10 = gun speed
fireat(caster, targob, 1, targcell, 8 + (power / 2) , NULL);
} else if (spellid == OT_S_PARALYZE) {
@ -4512,37 +4737,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = addtempflag(caster->flags, F_MAGICARMOUR, power*4, NA, NA, "psychic barrier", FROMSPELL);
f->obfrom = spellid;
} else if (spellid == OT_S_PULL) {
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (target) {
int failed = B_FALSE;
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
failed = B_TRUE;
} else {
// they get pulled towards caster
failed = pullnextto(target, caster->cell);
}
if (isplayer(target) || cansee(player, target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
if (failed) {
if (isplayer(target) || cansee(player, target)) {
char buf[BUFLEN];
getlfname(target, buf);
msg("%s %s pulled forward slightly.", buf, is(target));
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
}
} else {
fizzle(caster);
}
} else if (spellid == OT_S_PULLMETAL) {
int donesomething = B_FALSE;
if (!validatespellcell(caster, &targcell,TT_OBJECT, spellid, power, frompot)) return B_TRUE;
@ -4811,7 +5005,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
} else if (spellid == OT_S_KNOCK) {
object_t *o;
if (!validatespellcell(caster, &targcell,TT_DOOR, spellid, power, frompot)) return B_TRUE;
if (!validatespellcell(caster, &targcell,TT_DOOR|TT_IMPASSABLE, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
@ -5136,18 +5330,36 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_GRAVBOOST) {
// ask for target
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (target) {
int howlong = 15;
flag_t *f;
int i;
if (isplayer(target) || cansee(player, target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
f = hasactivespell(target, OT_S_GRAVLOWER);
if (f) {
stopspell(target, OT_S_GRAVLOWER);
return B_FALSE;
}
i = 0;
i += killtransitoryflags(target->flags, F_GRAVLESSENED);
i += killtransitoryflagvals(target->flags, F_DTIMMUNE, DT_FALL, NA, NA, NULL);
if (i) {
return B_FALSE;
}
if (lfhasflag(target, F_GRAVBOOSTED) || skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (isplayer(target)) {
msg("You feel momentarily heavier.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) {
char targname[BUFLEN];
getlfname(target, targname);
msg("%s looks momentarily heavier.", targname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
}
@ -5163,8 +5375,19 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
targcell = caster->cell;
target = caster;
f = lfhasflag(target, F_GRAVBOOSTED);
if (f) {
killflag(f);
if (isplayer(target) || cansee(player, target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
}
f = addtempflag(caster->flags, F_DTIMMUNE, DT_FALL, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
f = addtempflag(caster->flags, F_GRAVLESSENED, B_TRUE, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
} else if (spellid == OT_S_GUSTOFWIND) {
obpile_t *op;
object_t *o, *nexto;
@ -5263,15 +5486,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
flag_t *f;
char fullobname[BUFLEN];
char obname[BUFLEN];
getobname(o, obname, o->amt);
if (isplayer(caster)) {
sprintf(fullobname, "Your %s", noprefix(obname));
} else if (cansee(player, caster)) {
sprintf(fullobname, "%s%s %s", castername, getpossessive(castername), noprefix(obname));
} else {
strcpy(fullobname, "");
}
if (targob) {
o = targob;
@ -5284,6 +5498,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE;
}
getobname(o, obname, o->amt);
if (isplayer(caster)) {
sprintf(fullobname, "Your %s", noprefix(obname));
} else if (cansee(player, caster)) {
sprintf(fullobname, "%s%s %s", castername, getpossessive(castername), noprefix(obname));
} else {
strcpy(fullobname, "");
}
f = hasflag(o->flags, F_OBHP);
if (f && isdamaged(o)) {
if (blessed == B_CURSED) {
@ -6001,6 +6225,37 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else {
fizzle(caster);
}
} else if (spellid == OT_S_SUCK) {
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (target) {
int failed = B_FALSE;
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
failed = B_TRUE;
} else {
// they get pulled towards caster
failed = pullnextto(target, caster->cell);
}
if (isplayer(target) || cansee(player, target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
if (failed) {
if (isplayer(target) || cansee(player, target)) {
char buf[BUFLEN];
getlfname(target, buf);
msg("%s %s pulled forward slightly.", buf, is(target));
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
}
} else {
fizzle(caster);
}
} else if (spellid == OT_S_TELEPORT) {
cell_t *c = NULL;
lifeform_t *ally[8];
@ -6860,6 +7115,8 @@ enum SKILL getschoolskill(enum SPELLSCHOOL ss) {
return SK_SS_DEATH;
case SS_DIVINATION:
return SK_SS_DIVINATION;
case SS_ENCHANTMENT:
return SK_SS_ENCHANTMENT;
case SS_NATURE:
return SK_SS_NATURE;
case SS_FIRE:
@ -7013,6 +7270,118 @@ char *getspellname(enum OBTYPE spellid, lifeform_t *lf, char *buf) {
return buf;
}
int getspellpower(lifeform_t *lf, enum OBTYPE spellid) {
int power = 0;
int spelllev;
enum SKILLLEVEL spellcastskill,schoolskill;
enum SPELLSCHOOL school;
int db = B_FALSE;
int usesorcery = B_FALSE;
flag_t *f;
if (db) {
objecttype_t *ot;
ot = findot(spellid);
if (db) dblog("getspellpower for lf %s, spell %s", lf->race->name, ot->name);
}
////////////////////////////////////
// CAN WE CAST THIS AT ALL
////////////////////////////////////
// If we can _will_ this to occur then we might have a set
// spellpower
f = lfhasflagval(lf, F_CANWILL, spellid, NA, NA, NULL);
if (f && strlen(f->text)) {
texttospellopts(f->text, &power, NULL, NULL, NULL);
if (power > 0) {
if (db) {
dblog("-->power = %d (from canwill)", power);
}
return power;
}
}
// get spell details
school = getspellschoolknown(lf, spellid);
schoolskill = getskill(lf, getschoolskill(school));
spellcastskill = getskill(lf, SK_SPELLCASTING);
spelllev = getspelllevel(spellid);
// for most spell schools, your skill in the school determines which
// spells you can cast.
//
// this check doesn't apply for monsters.
if (isplayer(lf)) {
if (hasjob(lf, J_DRUID) && (school == SS_NATURE)) {
// always okay
} else if ((school == SS_ALLOMANCY) || (school == SS_MENTAL)) {
// dont need spellcasting skill for mental/allomancy
} else {
int maxspelllevel;
usesorcery = B_TRUE;
switch (schoolskill) {
case PR_INEPT: maxspelllevel = 0; break;
case PR_NOVICE: maxspelllevel = 1; break;
case PR_BEGINNER: maxspelllevel = 2; break;
case PR_ADEPT: maxspelllevel = 4; break;
case PR_SKILLED: maxspelllevel = 6; break;
case PR_EXPERT: maxspelllevel = 8; break;
case PR_MASTER: maxspelllevel = 9; break;
}
// player can only ever cast spells up to your level.
if (!hasjob(lf, J_GOD)) {
limit(&maxspelllevel, NA, lf->level);
}
if (spelllev > maxspelllevel) {
if (db) dblog("-->power = 0 (no skilled enough in spell school)");
return 0;
}
}
}
////////////////////////////////////
// HOW POWERFUL IS THIS SPELL?
////////////////////////////////////
if (hasjob(lf, J_DRUID) && (school == SS_NATURE)) {
// always okay
usesorcery = B_FALSE;
} else if ((school == SS_ALLOMANCY) || (school == SS_MENTAL)) {
// dont need spellcasting skill for mental/allomancy
usesorcery = B_FALSE;
} else {
usesorcery = B_TRUE;
}
power = 1; // base power of 1.
// plus either your hitdice/3 OR your sorcery skill
if (usesorcery) {
power += spellcastskill;
} else {
power += (gethitdice(lf)/3);
}
// plus intelligence modifier
if (school == SS_MENTAL) {
// +/- 2 for iq
power += (getstatmod(lf, A_IQ) / 25);
} else if (school == SS_NATURE) {
// +/- 1 for wisdom
power += (getstatmod(lf, A_WIS) / 50);
// TODO: clerical +/- 2 for wisdom
} else {
// +/- 1 for iq
power += (getstatmod(lf, A_IQ) / 50);
}
limit(&power, 0, getspellmaxpower(spellid));
return power;
}
/*
ooooooo old oooooooo
int getspellpower(lifeform_t *lf, enum OBTYPE spellid) {
int power = 0;
int statmod;
@ -7134,6 +7503,7 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) {
if (db) dblog("==> final power: %d", power);
return power;
}
*/
enum SPELLSCHOOL getspellschool(enum OBTYPE spellid) {
flag_t *f;
@ -7152,10 +7522,15 @@ enum SPELLSCHOOL getspellschool(enum OBTYPE spellid) {
return SS_NONE;
}
// return the school which the given spell belongs to, HOWEVER if it
// belongs to multiple ones, prefer ones which the given lifeform
// is skilled in.
enum SPELLSCHOOL getspellschoolknown(lifeform_t *lf, enum OBTYPE spellid) {
flag_t *f;
enum SPELLSCHOOL thisschool;
objecttype_t *ot;
enum SPELLSCHOOL poss[MAXCANDIDATES];
int nposs = 0;
ot = findot(spellid);
if (!ot) {
@ -7166,24 +7541,46 @@ enum SPELLSCHOOL getspellschoolknown(lifeform_t *lf, enum OBTYPE spellid) {
return SS_ABILITY;
}
// find a school which we know about!
// make a list of all schools which this spell belongs to, and which we know.
thisschool = SS_NONE;
for (f = ot->flags->first ; f ; f = f->next) {
if ((f->id == F_SPELLSCHOOL) && getskill(lf, getschoolskill(f->val[0]))) {
thisschool = f->val[0];
break;
poss[nposs++] = f->val[0];
}
}
if (nposs) {
int i;
enum SPELLSCHOOL poss2[MAXCANDIDATES];
int nposs2 = 0;
enum SKILLLEVEL highestskill = PR_INEPT;
// find the school which we are most skilled in
for (i = 0; i < nposs; i++) {
enum SKILLLEVEL thisslev;
thisslev = getskill(lf, getschoolskill(poss[i]));
if (thisslev > highestskill) {
highestskill = thisslev;
}
}
// now only select from these ones...
for (i = 0; i < nposs; i++) {
enum SKILLLEVEL thisslev;
thisslev = getskill(lf, getschoolskill(poss[i]));
if (thisslev == highestskill) {
poss2[nposs2++] = poss[i];
}
}
// pick one randomly
thisschool = poss2[rnd(0,nposs2-1)];
} else {
// if we don't know any of the schools...
if (thisschool == SS_NONE) {
// just pick the first one.
f = hasflag(ot->flags, F_SPELLSCHOOL);
assert(f);
thisschool = f->val[0];
}
return thisschool;
}
@ -7599,7 +7996,7 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, e
if (!frompot && where && where->lf && haslos(caster, where) && isplayer(caster) && areallies(caster, where->lf)) {
// warn before targetting yourself!
if (getiqname(getattr(caster, A_IQ), NULL) >= IQ_AVERAGE) {
if (getattrbracket(getattr(caster, A_IQ), A_IQ, NULL) >= AT_AVERAGE) {
objecttype_t *sp;
sp = findot(spellid);
if (sp) {

50
text.c
View File

@ -19,8 +19,16 @@ int needan(char *text) {
}
char *capitalise(char *text) {
if (strlen(text) > 0) {
text[0] = toupper(text[0]);
if (strlen(text)) {
char *p;
p = text;
while (*p == '^') {
p++; // go past the ^
if (!(*p)) return text; // do nothing
p++; // go past the colour char
if (!(*p)) return text; // do nothing
}
*p = toupper(*p);
}
return text;
}
@ -40,6 +48,27 @@ char *capitaliseall(char *text) {
return text;
}
enum COLOUR chartocol(char ch) {
switch (ch) {
case 'w': // warning
return C_YELLOW;
case 'W': // extra warning
return C_BOLDMAGENTA;
case 'b': // bad
return C_BROWN;
case 'B': // v.bad
return C_RED;
case 'g': // good
return C_GREEN;
case 'G': // v.good
return C_CYAN;
case 'n': // normal
default:
break;
}
return C_GREY;
}
char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dicebuf, char *minmaxbuf) {
int localmin, localmax;
@ -122,13 +151,15 @@ char *getattrabbrev(enum ATTRIB att) {
case A_CHA:
return "Ch";
case A_CON:
return "Fi";
return "Ft";
case A_DEX:
return "Dx";
case A_IQ:
return "Iq";
case A_STR:
return "St";
case A_WIS:
return "Wi";
}
return "??";
}
@ -147,6 +178,8 @@ char *getattrname(enum ATTRIB att) {
return "intelligence";
case A_STR:
return "strength";
case A_WIS:
return "wisdom";
}
return "?badattrib?";
}
@ -186,7 +219,7 @@ int gethitconferlifetime(char *text, int *min, int *max) {
char *getpossessive(char *text) {
char lastchar;
// you -> your
if (!strcmp(text, "you")) {
if (!strcasecmp(text, "you")) {
return "r";
}
@ -235,14 +268,15 @@ char *getsizetext(enum LFSIZE sz) {
case SZ_LARGE:
return "large";
case SZ_HUMAN:
return "human-sized";
return "human";
case SZ_MEDIUM:
return "medium";
case SZ_SMALL:
return "small";
case SZ_MINI:
case SZ_TINY:
return "extremely small";
return "tiny";
case SZ_MINI:
return "miniscule";
default:
return "unknown-sized";
}
@ -550,7 +584,7 @@ char *roman(int num) {
}
int speedtokph(int speed) {
return speed * speed * speed;
return speed * speed;
}
void splittime(int *hours, int *mins, int *secs) {

1
text.h
View File

@ -3,6 +3,7 @@
int needan(char *text);
char *capitalise(char *text);
char *capitaliseall(char *text);
enum COLOUR chartocol(char ch);
char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dicebuf, char *minmaxbuf);
int flip(int ch);
char *getattrabbrev(enum ATTRIB att);

View File

@ -19,7 +19,7 @@
/:ob:wooden table
-:ob:wooden footstool
c:ob:lit candelabrum
@:mon:Jimbo
@:mon:jailer
@end
@flags