- [+] job abilities can now generally happen as often as you like,

since they're ilmited by stamina.
- [+] rename dexterity to agility
- [+] The leprechaun steals an uncursed ring of miracles from you!
      The leprechaun cowers away from you!
    - [+] should FLEE , not cower!
- [+] should set blessknown after reading a scroll
- [+] cursed mending scroll not working on non-damaged objects
- [+] spanner helps metal repair
- [+] needle boosts sewing ability
- [+] when resting in a tent, monstesr have very low chance of noticing
      you (5%)
- [+] move display of resistances to 'effects' section.
- [+] show what a mosnter wants in effects (if you have >= beginner
      knowledge)
- [+] prevent running into monsters with shift+dir
- [+] infinite loop when creating a map, constant getrandomroomcell()
      calls failing
- [+] monstesr will steal objects they WANT rather than always random
- [+] monster:
    - [+] leprechaun
        - [+] lucky
        - [+] covets gold
        - [+] shillelagh ? or just a club?
        - [+] blink
        - [+] steal
        - [+] dodge
- [+] at the moment attack doesn't seem to be draining stamina...
    - [+] it is, but i'm getting it right back due to attack speed.
    - [+] make stamina take longer to regen. - 1 per 3 turns rather
          than 1 per 2.
    - [+] stamina loss must be MORE than basic regen rate (0.3)
    - [+] make stamina loss for attack depend on atatck speed!
        - [+] instead of "you feel sick", say "you have contracted
              weakening poison" or "you have been infected with xxx"
    - [+] store stamina as a float, but getstamina() should return an
          int.
- [+] sprinting - use 1.5 stamina per cell instead of 1?
- [+] modify accuracy text
- [+] fork
- [+] showing f_entertext should set didmsg
- [+] instead of printing 100% accuracy, show "Acc:0"  (ie 100),
      "Acc:-1" (ie -10) etc
    - [+] do this in @@
    - [+] do this in describeob
- [+] nocturnal monsters
    - [+] base monsters initially being asleep  on time and whether
          mosnter is nocturnal
    - [+] also during aiturn(), if they have nothing to do and it's
          their sleeping time, goto sleep
    - [+] add flags
- [+] flies should always move towards corpses if possible
    - [+] maybe F_WANTSOB corpse, covet?
    - [+] but thye can't pick it up so they'll just hover nearby?
    - [+] now they can be hostile too
- [+] when we're picking a random corpse, try again if we get something
      with nocorpse like a ghost
    - [+] getrandomcorpserace()
- [+] lower stamina max - currently at lv1+ft:11 i have 7 stam. should
      be more like 5
- [+] severed finger shoudn't count as making you bleed when you attack
- [+] in askcoords, always show cell name
- [+] monsters with no melee attacks can always cast spells while
      adjacent
- [+] resting issues
    - [+] having a temporary injury means oyu need to rest, so don't
          say "you don't need to rest"!
    - [+] also don't stop resting until all temporary injuries are
          healed 
- [+] show comparative weights / armour ratings
- [+] make price for npcs to join be lower
- [+] assertion failure with who->timespent == 0 when a mosnter falls
      through a hole
    - [+] (after I follow by falling down the pit)
    - [+] make taketime() not work when not on the player's map
- [+] bug - monsters never waking up
- [+] "tailwind" spell (fast movement speed but forwards only)
- [+] now that i have Hardness, _all_ reduced damage should go towards
      armour. 
- [+] earthquake - pits open up around you (but not under you)
- [+] force sphere - radial blast outwards, knocks back lfs + obs +
      doors etc
This commit is contained in:
Rob Pearce 2011-10-04 03:24:53 +00:00
parent ad18cf2398
commit 25db5b0da7
19 changed files with 1490 additions and 745 deletions

70
ai.c
View File

@ -68,7 +68,7 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
penalty = (getcelldist(lf->cell, victim->cell)-1);
if (penalty < 0) penalty = 0;
penalty *= 3;
if (!skillcheckvs(lf, SC_WILL, -penalty, victim, SC_WILL, 5)) {
if (!skillcheckvs(lf, SC_WILL, -penalty, victim, SC_WILL, 5+gethitdice(victim))) {
dblog(".oO { attempted target fooled me with feign death. ignoring. }");
return B_TRUE;
}
@ -602,6 +602,8 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
if ( (spell != OT_NONE) && // found a valid spell/ability to use
((dist != 1) || // there is distance between us and target
(st->obclass->id == OC_ABILITY) || // OR this works from adjacent
(st->obclass->id == OC_ABILITY) || // OR we have no melee attack
!countinnateattacks(lf) ||
(rnd(1,3) == 1)) // OR random chance of using anyway...
) {
int spellfailed = B_FALSE;
@ -669,8 +671,8 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
// spell succesful
if ((spell == OT_A_STEAL) && !lfhasflag(lf, F_NOFLEE)) {
// run away for a few turns
fleefrom(lf, spelllf, rnd(3,7), B_TRUE);
// run away for a while
fleefrom(lf, spelllf, rnd(10,20), B_TRUE);
}
return B_FALSE;
}
@ -1031,7 +1033,6 @@ void aiturn(lifeform_t *lf) {
// housekeeping - weapon changes, drop/pickup,
// use items, talk,etc
///////////////////////////////////////////////
if (lfhasflag(lf, F_ISPRISONER) && master && isplayer(master) && cansee(lf, master)) {
if (isoutdoors(lf->cell->map) && pctchance(20)) {
object_t *o;
@ -1096,10 +1097,14 @@ void aiturn(lifeform_t *lf) {
int vol;
f = poss[rnd(0,nposs-1)];
vol = rnd(f->val[1], f->val[2]);
if (f->text) {
say(lf, f->text, vol);
} else {
sayphrase(lf, f->val[0], vol, NA, NULL);
}
}
}
}
///////////////////////////////////////////////
// healing
@ -1144,6 +1149,17 @@ void aiturn(lifeform_t *lf) {
if (lf->hp < (lf->maxhp/2)) {
if (!useitemwithflag(lf, F_AIHEALITEM)) {
return;
} else {
// don't have or can't use our healing items
// no enemies in sight?
if (safetorest(lf)) {
// if it's "night time" for us, sleep forever.
// otehrwise just sleep until we're healed
if (!gotosleep(lf, issleepingtimefor(lf) ? B_TRUE : B_FALSE)) {
taketime(lf, getactspeed(lf)); // to make sure our turn ends
return; // success
}
}
}
}
@ -1393,40 +1409,50 @@ void aiturn(lifeform_t *lf) {
}
if (!lfhasflag(lf, F_STUNNED)) {
lifeform_t *hateposs[MAXCANDIDATES],*poss[MAXCANDIDATES];
int nposs = 0, nhateposs = 0;
if (db) dblog(".oO { looking for a target . }");
// look for any race which we hate
// look for any hated lfs or enemies
newtarget = NULL;
for (n = 0; n < lf->nlos; n++) {
lifeform_t *who;
if (lf->los[n] != lf->cell) {
if (lf->los[n] != lf->cell) { // not ourself
who = lf->los[n]->lf;
if (who && !isdead(who) && !isunconscious(who) && cansee(lf, who)) {
int chance = 100;
// targets sleeping in a tent will probably be ignored
if (isresting(lf)) {
object_t *restob;
restob = getrestob(who);
if (restob && (restob->type->id == OT_TENT)) {
chance = 5;
}
}
if (pctchance(chance)) {
if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) ||
lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) {
if (nhateposs < MAXCANDIDATES) {
if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name);
newtarget = who;
hateposs[nhateposs++] = who;
}
break;
}
}
}
}
if (!newtarget) {
// now look for enemies
for (n = 0; n < lf->nlos; n++) {
if (lf->los[n] != lf->cell) {
lifeform_t *who;
who = lf->los[n]->lf;
if (who && cansee(lf, who) && !isdead(who) && !isunconscious(who)) {
if (areenemies(lf, who)) {
} else if (!nhateposs && areenemies(lf, who)) { // dont check if we've already found a hated target
if (nposs < MAXCANDIDATES) {
if (db) dblog(".oO { found an enemy target - lfid %d (%s) ! }",who->id, who->race->name);
newtarget = who;
break;
poss[nposs++] = who;
}
}
}
}
}
}
if (nhateposs) {
newtarget = hateposs[rnd(0,nhateposs-1)];
} else if (nposs) {
newtarget = poss[rnd(0,nposs-1)];
}
}
if (newtarget) {
if (aiattack(lf, newtarget, DEF_AIFOLLOWTIME)) {
@ -1788,7 +1814,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if ((ot->id == OT_S_SMITEEVIL) && (getalignment(victim) != AL_EVIL)) {
specificcheckok = B_FALSE;
}
if ((ot->id == OT_A_SPRINT) && (lfhasflag(lf, F_SPRINTING) || !lf->stamina)) {
if ((ot->id == OT_A_SPRINT) && (lfhasflag(lf, F_SPRINTING) || !getstamina(lf))) {
specificcheckok = B_FALSE;
}
if ((ot->id == OT_A_STEAL) || (ot->id == OT_S_CONFISCATE)) {

View File

@ -175,7 +175,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
int attackedpeaceful = B_FALSE;
// warn if attacking will cause injury
if (!force && isplayer(lf)) {
if (!force && isplayer(lf) && haslos(lf, c)) {
if (!confirm_injury_action(BP_HANDS, DT_SLASH, "attack")) {
return B_TRUE;
}
@ -268,12 +268,6 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
return B_TRUE;
}
// lose a tiny bit of stamina
modstamina(lf, -0.2);
// stop sprinting
stopsprinting(lf);
// ai code...
if (lfhasflag(lf, F_DEMANDSBRIBE)) {
if (!isplayer(lf) && (attacktype == AT_LF) && isplayer((lifeform_t *)attacktarget)) {
@ -336,9 +330,6 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
innateattacks = countinnateattacks(lf);
// stop sprinting
stopsprinting(lf);
// take time
attacktime = getattackspeed(lf);
@ -467,7 +458,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
sayphrase(lf, SP_SORRY, -1, NA, NULL);
}
if (lfhasflagval(lf, F_INJURY, NA, BP_HANDS, DT_SLASH, NULL)) {
if (hasbleedinginjury(lf, BP_HANDS)) {
if (!bleedfrom(lf, BP_HANDS, B_FALSE)) {
losehp(lf, 1, DT_DIRECT, NULL, "blood loss");
}
@ -517,6 +508,11 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
}
}
// lose a bit of stamina
modstamina(lf, -getattackstamloss(lf));
// stop sprinting
stopsprinting(lf);
return B_FALSE;
}
@ -2070,7 +2066,7 @@ int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag) {
}
if (victim) {
if (lfhasflagval(victim, F_INJURY, NA, BP_BODY, DT_SLASH, NULL)) {
if (hasbleedinginjury(victim, BP_BODY)) {
if (willbleedfrom(victim, BP_BODY)) {
// extra damage
dam += rnd(1,2);
@ -2236,7 +2232,7 @@ void modifyforsize(int *val, lifeform_t *lf, lifeform_t *victim, int howmuch, en
}
}
// returns true if we hit
// returns true if we hit. also sets 'critical' if passed
int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) {
int acc,ev;
int gothit = B_FALSE;
@ -2286,6 +2282,10 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
acc += 30;
}
if (lfhasflag(lf, F_AIMEDSTRIKE)) {
acc -= 50;
}
// modify for defender's evasion
if (isprone(victim) || !cansee(victim, lf)) {
ev = 0;
@ -2310,6 +2310,10 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
if (pctchance(acc)) gothit = B_TRUE;
}
if (gothit && lfhasflag(lf, F_AIMEDSTRIKE) && critical) {
*critical = 1;
}
return gothit;
}

370
data.c

File diff suppressed because it is too large Load Diff

Binary file not shown.

41
defs.h
View File

@ -294,6 +294,8 @@ enum RELATIVEDIR {
// ... try to make this roughly 4 hours (check TIMECONST.
#define HUNGERCONST 500
#define STAMREGEN (0.3) // base amount of stamina to regain each turn
// Time periods
#define TM_DRUNKTIME (10) // how long it takes for alcohol to wear off
#define TM_WETTIME (10) // how long it takes for things to dry
@ -497,7 +499,7 @@ enum GAMEMODE {
enum ATTRIB {
A_NONE = -1,
A_STR = 0,
A_DEX = 1,
A_AGI = 1,
A_WIS = 2,
A_IQ = 3,
A_CON = 4,
@ -802,6 +804,7 @@ enum RACE {
R_HOBGOBLIN,
R_HOBGOBLINWAR,
R_KOBOLD,
R_LEPRECHAUN,
R_LIZARDMAN,
R_MINOTAUR,
R_OGRE,
@ -1157,13 +1160,14 @@ enum OBTYPE {
OT_S_SNOWBALL,
OT_S_WALLOFICE,
// -- gravity
OT_S_TRUESTRIKE,
OT_S_FLIGHT,
OT_S_FORCESPHERE,
OT_S_GRAVLOWER,
OT_S_GRAVBOOST,
OT_S_HASTE,
OT_S_SLOW,
OT_S_LEVITATION,
OT_S_FLIGHT,
OT_S_SLOW,
OT_S_TRUESTRIKE,
// -- life / cleric
OT_S_HEALING,
OT_S_HEALINGMIN,
@ -1201,7 +1205,7 @@ enum OBTYPE {
OT_S_PETRIFY,
OT_S_POLYMORPH,
OT_S_POLYMORPHRND,
// nature
// nature / enviromancy
OT_S_BARKSKIN,
OT_S_CALLLIGHTNING,
OT_S_CALLWIND,
@ -1211,6 +1215,7 @@ enum OBTYPE {
OT_S_CUREPOISON,
OT_S_DETECTPOISON,
OT_S_DIG,
OT_S_EARTHQUAKE,
OT_S_EVAPORATE,
OT_S_WEB,
OT_S_ENDUREELEMENTS,
@ -1268,6 +1273,7 @@ enum OBTYPE {
OT_A_LEARN,
OT_A_LEVELUP,
// abilities
OT_A_AIMEDSTRIKE,
OT_A_COOK,
OT_A_DARKWALK,
OT_A_DISARM,
@ -1407,6 +1413,8 @@ enum OBTYPE {
OT_FOOTPRINT,
OT_SCENT,
// effects
OT_DUSTCLOUD,
OT_DUSTPUFF,
OT_FIRELARGE,
OT_FIREMED,
OT_FIRESMALL,
@ -1532,6 +1540,7 @@ enum OBTYPE {
// short blades
OT_COMBATKNIFE,
OT_DAGGER,
OT_FORK,
OT_KNIFE,
OT_ORNDAGGER,
OT_QUICKBLADE,
@ -1569,6 +1578,7 @@ enum OBTYPE {
OT_MACE,
OT_MORNINGSTAR,
OT_NUNCHAKU,
OT_SHILLELAGH,
OT_SPANNER,
OT_STICK,
// projectile weapons
@ -2049,7 +2059,7 @@ enum FLAG {
// player only flags
F_DONEDARKMSG, // tells the game not to say 'it is very dark here'
F_DONELISTEN, // supress further 'you hear xx' messages this turn.
// lifeform flags / lf flags
// lifeform flags / lf flags / monster flags
F_ALIGNMENT, // v0 = al_good, al_neutral, al_evil. default neutral.
F_PIETY, // for god lifeforms - tracks player's piety with them
F_PRAYEDTO, // player has prayed to this god before.
@ -2077,10 +2087,15 @@ enum FLAG {
F_SIZE, // val0 = lf size (enum LFSIZE)
F_USEDPOISON, // this lf used a poisoned weapon to attack
F_RANDOMTALKPCT, // v0 = chance of randomly saying something each turn
F_RANDOMTALK, // v0 = sp_xxx for what to say when we randomly talk.
F_RANDOMTALK, // EITHER:
// v0 = sp_xxx for what to say when we randomly talk.
// v1/v2 are min/max volume
// OR
// text = what to say
// v1/v2 are min/max volume
//
// can have multiple of these flags, if so then
// randomly eslect one each time.
// randomly select 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
@ -2124,6 +2139,8 @@ enum FLAG {
F_MYCORPSE, // text field contains obid of my corpse.
// (for ghosts)
F_NOCORPSE, // monster's body crumbles to dust after death
F_NOCTURNAL, // monster sleeps during the day
F_DIURNAL, // monster sleeps at night
F_LFSUFFIX, // text = suffix. eg. "skeleton"
F_VISRANGE, // how far you can see (in the light)
F_VISRANGEMOD, // modifications to visrange
@ -2231,6 +2248,8 @@ enum FLAG {
// val1 is the volume of the noise
// text is "verb^noun"
// eg. "shouts^a shout"
// if this flag occurs more than once with
// the same v0, a random one is selected.
F_SPELLCASTTEXT, // text is announcement for spellcast
// if text is empty, then don't announce
// this lf's spell casting at all.
@ -2311,9 +2330,12 @@ enum FLAG {
F_SPOTTED, // you have spotted hiding lf id v0. you lsoe this if they
// go out of sight.
// special attack flags
F_AIMEDSTRIKE, // next attack is an aimed strike
F_COMBOSTRIKE, // lf is performing a combination strike
F_HEAVYBLOW, // next attack is a heavy blow
F_QUIVERINGPALM, // your next strike will be a quivpalm attack
F_TRUESTRIKE, // your attacks ALWAYS hit. turnsleft=v0
F_HURRICANESTRIKE, // lf is performing a hurricane strike
// INTRINSICS
F_MAGICARMOUR,// armour is magically boosted. f->text is the description
// ie 'magic armour', 'force field'
@ -2322,6 +2344,7 @@ enum FLAG {
// v1 is enum sleeptype st_xxx
// if v2 is set, means we are sleeping on
// purpose and will wake up when at full hp/mp/etc.
// ie. "resting"
F_ATTACHEDTO, // you are attached to lf id v0, and will move with it
F_AWARENESS, // you can see 360 degrees around yourself
F_BEINGSTONED,// turn to stone when v0 drops to zero. (drops 1/turn)
@ -2383,7 +2406,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_HURRICANESTRIKE, // lf is performing a hurricane strike
F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks.
F_ICESLIDE, // lf has "slide" spell active.
// v0 = timeleft (since 'lifetime' is used for FROMSPELL)
@ -2428,7 +2450,6 @@ enum FLAG {
F_STENCH, // creatures within v0 gain f_nauseated = v1
F_STUNNED, // cannot attack or cast spells
F_TREMORSENSE, // doesn't need eyes to see, can see in dark with v0
F_TRUESTRIKE, // your attacks ALWAYS hit. turnsleft=v0
F_PRODUCESLIGHT, // produces light of val0 radius.
// (but not for obs in pack)
// if val2 is true, will only make light if ob

857
io.c

File diff suppressed because it is too large Load Diff

327
lf.c
View File

@ -492,7 +492,7 @@ void callguards(lifeform_t *caller, lifeform_t *victim) {
}
int canattack(lifeform_t *lf) {
if (!lf->stamina) {
if (!getstamina(lf)) {
reason = E_NOSTAM;
return B_FALSE;
} else if (lfhasflag(lf, F_STUNNED)) {
@ -583,7 +583,7 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
}
f = hasflag(ot->flags, F_STAMCOST);
if (f && (lf->stamina < f->val[0])) {
if (f && (getstamina(lf) < f->val[0])) {
reason = E_NOSTAM;
return B_FALSE;
}
@ -696,12 +696,13 @@ int canhear(lifeform_t *lf, cell_t *dest, int volume) {
// can't hear noises from other maps
if (lf->cell->map != dest->map) return B_FALSE;
celldist = getcelldist(lf->cell, dest);
// for player only:
// can't hear if you have a hostile mosnter next to you
// and you're not blind.
// (you're too engrossed in the battle)
/*
celldist = getcelldist(lf->cell, dest);
if (isplayer(lf) && isinbattle(lf)) {
if (celldist != 1) return B_FALSE;
}
@ -1300,7 +1301,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
losemp(lf, cost);
// miscast chance?
if (isplayer(lf)) {
if (isplayer(lf) && !hasjob(lf, J_GOD)) {
if (pctchance(getmiscastchance(lf))) {
msg("^WYour cumbersome armour makes you miscast your spell!");
return B_FALSE;
@ -1353,10 +1354,12 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
}
} else { // player can't see them
if ((targlf == player) || (targcell = player->cell)) {
if (!lfhasflag(player, F_ASLEEP)) {
msg("Something casts a spell at you.");
}
}
}
}
// boost power?
if (hasjob(lf, J_DRUID)) {
@ -1576,7 +1579,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) {
}
losehp(lf, roll("6d6"), DT_DIRECT, NULL, "running water");
}
if ((!slev || !lf->stamina) && !lfhasflag(lf, F_BREATHWATER) ) {
if ((!slev || !getstamina(lf)) && !lfhasflag(lf, F_BREATHWATER) ) {
int damamt;
// take drowning damage. generally you'll die
@ -1707,17 +1710,6 @@ int countinnateattacks(lifeform_t *lf) {
}
int countmoney(lifeform_t *lf) {
object_t *o;
int amt = 0;
for (o = lf->pack->first ; o ; o = o->next) {
if (o->type->id == OT_GOLD) {
amt += o->amt;
}
}
return amt;
}
int countnearbyallies(lifeform_t *lf) {
lifeform_t *l;
int count = 0;
@ -1785,7 +1777,7 @@ int demandbribe(lifeform_t *lf) {
hd = gethitdice(lf);
gold = hasob(player->pack, OT_GOLD);
if (gold) {
totmoney = countmoney(player);
totmoney = countmoney(player->pack);
} else {
totmoney = 0;
}
@ -2737,6 +2729,14 @@ int eat(lifeform_t *lf, object_t *o) {
// announce
if (turnstoeat <= 1) {
char taste[BUFLEN];
if (hasflagval(o->flags, F_CORPSEOF, R_CHICKEN, NA, NA, NULL)) {
sprintf(taste, " Tastes like chicken!");
} else if (f->val[1] >= 20) {
sprintf(taste, " Yum!");
} else {
strcpy(taste, "");
}
if (alreadyeating) {
if (isplayer(lf)) {
msg("You finish %s.%s", drinking ? "drinking" : "eating",
@ -2988,10 +2988,10 @@ void enhanceskills(lifeform_t *lf) {
if (isplayer(lf)) {
char ch;
more();
ch = askchar("Increase your Strength, Dexterity, Fitness, IQ or Wisdom?", "sdfiw",NULL, B_TRUE);
ch = askchar("Increase your Strength, Agility, Fitness, IQ or Wisdom?", "safiw",NULL, B_TRUE);
switch (ch) {
case 's': att = A_STR; break;
case 'd': att = A_DEX; break;
case 'a': att = A_AGI; break;
case 'f': att = A_CON; break;
case 'i': att = A_IQ; break;
case 'w': att = A_WIS; break;
@ -4512,7 +4512,7 @@ int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, int *narms
ar += thisar;
ar += getobbonus(o);
ar += getobbonus(o, B_FALSE);
if (hitob) {
hitob[*narms] = o;
hitchance[*narms] = getbodyparthitchance(isshield ? BP_BODY : eqflag->val[0]);
@ -4526,7 +4526,6 @@ int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, int *narms
}
// how far away should we be before attacking?
int getattackspeed(lifeform_t *lf) {
object_t *w;
float speed;
@ -4542,6 +4541,22 @@ int getattackspeed(lifeform_t *lf) {
return (int)speed;
}
float getattackstamloss(lifeform_t *lf) {
object_t *w;
float loss;
loss = ((float)STAMREGEN+0.2);
w = getweapon(lf);
if (w) {
int del;
del = getobattackdelay(w);
loss = pctof(del, loss);
}
return loss;
}
int getattpoints(lifeform_t *lf) {
flag_t *f;
int attpoints = 0;
@ -4583,7 +4598,7 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) {
val += f->val[1];
}
if (f->id == F_DRUNK) {
if (attr == A_DEX) {
if (attr == A_AGI) {
if (hasjob(lf, J_PIRATE)) {
val += f->val[0];
} else {
@ -4807,7 +4822,7 @@ int getevasion(lifeform_t *lf) {
ev += level_ev;
// dexterity mod
ev += getattr(lf, A_DEX);
ev += getattr(lf, A_AGI);
// you are easier to hit if you're glowing
if (hasflag(lf->flags, F_PRODUCESLIGHT)) {
@ -5318,7 +5333,7 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) {
} else {
int dexmod;
// modify with dexterity
dexmod = getstatmod(lf, A_DEX);
dexmod = getstatmod(lf, A_AGI);
// double dex penalties when dual weilding
if (isdualweilding(lf) && (dexmod < 0)) {
dexmod *= 2;
@ -5369,7 +5384,7 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) {
}
}
if (acc < 0) acc = 0;
//if (acc < 0) acc = 0;
return acc;
}
@ -5772,7 +5787,7 @@ float getmaxstamina(lifeform_t *lf) {
if (lfhasflagval(lf, F_INJURY, IJ_LUNGCOLLAPSED, NA, NA, NULL)) {
return 0;
}
stam = (getattr(lf, A_CON) / 2);
stam = (getattr(lf, A_CON) / 3);
stam += (getskill(lf, SK_ATHLETICS)*2);
return stam;
}
@ -6174,6 +6189,11 @@ int getspellspeed(lifeform_t *lf) {
return speed;
}
// note: stamina is stored as a float, but we treat it as an int.
int getstamina(lifeform_t *lf) {
return (int)floor(lf->stamina);
}
char *getplayername(char *buf) {
flag_t *f;
f = hasflag(player->flags, F_NAME);
@ -6219,52 +6239,6 @@ int getpoisondamchance(enum POISONTYPE ptype) {
return chance;
}
char *getpoisondamverb(enum POISONTYPE ptype) {
switch (ptype) {
case P_FOOD:
case P_VENOM:
return "vomit";
case P_GAS:
case P_COLD:
return "cough";
default:
break;
}
return "";
}
char *getpoisondesc(enum POISONTYPE ptype) {
switch (ptype) {
case P_FOOD:
case P_VENOM:
case P_GAS:
case P_WEAKNESS:
return "Poisoned";
case P_COLD:
return "Sick";
default:
break;
}
return "Poisoned";
}
char *getpoisonname(enum POISONTYPE ptype) {
switch (ptype) {
case P_COLD:
return "hypothermia";
case P_FOOD:
return "food poisoning";
case P_GAS:
return "gas inhalation";
case P_VENOM:
return "venom poisoning";
case P_WEAKNESS:
return "weakening poison";
default:
break;
}
return "";
}
enum POISONSEVERITY getpoisonseverity(enum POISONTYPE ptype) {
switch (ptype) {
@ -6374,6 +6348,16 @@ enum BODYPART getrandomcorebp(lifeform_t *lf) {
return selbp;
}
race_t *getrandomcorpserace(cell_t *c) {
race_t *r;
r = getrandomrace(c, NA);
while (hasflag(r->flags, F_NOCORPSE)) {
r = getrandomrace(c, NA);
}
return r;
}
job_t *getrandomjob(int onlyplayerjobs) {
job_t *j;
int njobs = 0;
@ -6687,7 +6671,7 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) {
strcpy(buf, "hideous"); break;
case A_CON:
strcpy(buf, "frail"); break;
case A_DEX:
case A_AGI:
strcpy(buf, "uncoordinated"); break;
case A_IQ:
strcpy(buf, "vegetable"); break;
@ -6707,7 +6691,7 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) {
strcpy(buf, "repulsive"); break;
case A_CON:
strcpy(buf, "sickly"); break;
case A_DEX:
case A_AGI:
strcpy(buf, "oafish"); break;
case A_IQ:
strcpy(buf, "animal"); break;
@ -6727,7 +6711,7 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) {
strcpy(buf, "ugly"); break;
case A_CON:
strcpy(buf, "unhealthy"); break;
case A_DEX:
case A_AGI:
strcpy(buf, "clumsy"); break;
case A_IQ:
strcpy(buf, "dim-witted"); break;
@ -6747,7 +6731,7 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) {
strcpy(buf, "unattractive"); break;
case A_CON:
strcpy(buf, "unfit"); break;
case A_DEX:
case A_AGI:
strcpy(buf, "awkward"); break;
case A_IQ:
strcpy(buf, "dopey"); break;
@ -6765,7 +6749,7 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) {
switch (whichatt) {
case A_CHA:
case A_CON:
case A_DEX:
case A_AGI:
case A_STR:
case A_IQ:
case A_WIS:
@ -6782,7 +6766,7 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) {
strcpy(buf, "attractive"); break;
case A_CON:
strcpy(buf, "healthy"); break;
case A_DEX:
case A_AGI:
strcpy(buf, "dextrous"); break;
case A_IQ:
strcpy(buf, "smart"); break;
@ -6802,7 +6786,7 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) {
strcpy(buf, "alluring"); break;
case A_CON:
strcpy(buf, "very fit"); break;
case A_DEX:
case A_AGI:
strcpy(buf, "nimble"); break;
case A_IQ:
strcpy(buf, "enlightened"); break;
@ -6822,7 +6806,7 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) {
strcpy(buf, "beautiful"); break;
case A_CON:
strcpy(buf, "hardy"); break;
case A_DEX:
case A_AGI:
strcpy(buf, "agile"); break;
case A_IQ:
strcpy(buf, "genius"); break;
@ -6842,7 +6826,7 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) {
strcpy(buf, "stunning"); break;
case A_CON:
strcpy(buf, "very hardy"); break;
case A_DEX:
case A_AGI:
strcpy(buf, "very agile"); break;
case A_IQ:
strcpy(buf, "supergenius"); break;
@ -7786,8 +7770,22 @@ int gotosleep(lifeform_t *lf, int onpurpose) {
return B_FALSE;
}
flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp) {
flag_t *f, *retflag[MAXCANDIDATES];
int nretflags,i;
getflags(player->flags, retflag, &nretflags, F_INJURY, F_NONE);
for (i = 0;i < nretflags; i++) {
f = retflag[i];
// only temporary flags count - not permenant ones
if ((f->lifetime > 0) && (f->val[1] == bp) && (f->val[2] == DT_SLASH)) {
return f;
}
}
return NULL;
}
int hasfreeaction(lifeform_t *lf) {
if (isdead(lf)) return B_FALSE;
if (isimmobile(lf)) return B_FALSE;
if (lfhasflag(lf, F_CASTINGSPELL)) return B_FALSE;
if (lfhasflag(lf, F_EATING)) return B_FALSE;
@ -7802,6 +7800,17 @@ job_t *hasjob(lifeform_t *lf, enum JOB job) {
return j;
}
int hastempinjuries(lifeform_t *lf) {
flag_t *retflag[MAXCANDIDATES];
int nretflags,i,count = 0;
getflags(lf->flags, retflag, &nretflags, F_INJURY, F_NONE);
for (i = 0; i < nretflags; i++) {
if (retflag[i]->lifetime > 0) count++;
}
return count;
}
void inc_quad_range(enum QUADRANT *start, enum QUADRANT *end, int howmuch) {
int i;
for (i = 0; i < abs(howmuch); i++) {
@ -9005,6 +9014,16 @@ flag_t *isresting(lifeform_t *lf) {
return NULL;
}
int issleepingtimefor(lifeform_t *lf) {
if (lfhasflag(lf, F_NOCTURNAL) && !isnighttime()) {
return B_TRUE;
} else if (lfhasflag(lf, F_DIURNAL) && isnighttime()) {
return B_TRUE;
}
return B_FALSE;
}
object_t *isstuck(lifeform_t *lf) {
object_t *o;
@ -10306,6 +10325,22 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
snprintf(buf2, BUFLEN, "^%d damage",amt);
strcat(buf, buf2);
// unseen?
if (fromlf && !cansee(lf, fromlf)) {
strcat(buf2, "^unseen");
}
// "while xxx"
strcpy(buf2, "");
if ((countcellexits(lf->cell) == 1) && fromlf && (getcelldist(fromlf->cell, lf->cell) == 1)) {
strcat(buf2, "^while cornered");
}
if (!hasfreeaction(lf)) {
if (strlen(buf2)) strcat(buf2, " and helpless");
else strcat(buf2, "^while helpless");
}
if (strlen(buf2)) strcat(buf, buf2);
setlastdam(lf, buf);
@ -10459,19 +10494,28 @@ int makenauseated(lifeform_t *lf, int amt, int howlong) {
}
void makenoise(lifeform_t *lf, enum NOISETYPE nid) {
flag_t *f;
flag_t *retflag[MAXCANDIDATES],*nflag[MAXCANDIDATES];
int nretflags, volume = 1, i,nnflags = 0;
char *verb = NULL, *noun = NULL;
int volume = 1;
if (lfhasflag(lf, F_FROZEN)) {
// can't make noise if frozen!
return;
}
f = hasflagval(lf->flags, F_NOISETEXT, nid, NA, NA, NULL);
if (f) {
getflags(lf->flags, retflag, &nretflags, F_NOISETEXT, F_NONE);
for (i = 0; i < nretflags; i++) {
if (retflag[i]->id == nid) {
nflag[nnflags++] = retflag[i];
}
}
if (nnflags) {
flag_t *f;
char *dummy;
char noisetext[BUFLEN];
f = nflag[rnd(0,nnflags-1)];
volume = f->val[1];
@ -10585,7 +10629,7 @@ int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o) {
if (myval < valneeded) {
switch (att) {
case A_DEX:
case A_AGI:
reason = E_LOWDEX;
break;
case A_CHA:
@ -10651,7 +10695,7 @@ int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) {
case A_CON:
strcpy(adverb, "healthier");
break;
case A_DEX:
case A_AGI:
strcpy(adverb, "more agile");
break;
case A_IQ:
@ -10674,7 +10718,7 @@ int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) {
case A_CON:
strcpy(adverb, "frail");
break;
case A_DEX:
case A_AGI:
strcpy(adverb, "sluggish");
break;
case A_IQ:
@ -10800,17 +10844,17 @@ float modifybystat(float num, lifeform_t *lf, enum ATTRIB att) {
void modstamina(lifeform_t *lf, float howmuch) {
float orig;
orig = lf->stamina;
orig = getstamina(lf);
lf->stamina += howmuch;
limitf(&(lf->stamina), 0, getmaxstamina(lf));
if (lf->stamina != orig) {
if (getstamina(lf) != orig) {
if (isplayer(lf)) {
statdirty = B_TRUE;
drawstatus();
updatestatus();
if (lf->stamina == 0) msg("You are exhausted.");
if (getstamina(lf) == 0) msg("You are exhausted.");
} else if (cansee(player, lf)) {
if (lf->stamina == 0) {
if (getstamina(lf) == 0) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s looks exhausted.", lfname);
@ -10818,7 +10862,7 @@ void modstamina(lifeform_t *lf, float howmuch) {
}
}
if (lf->stamina == 0) {
if (getstamina(lf) == 0) {
stopsprinting(lf);
}
}
@ -10832,6 +10876,9 @@ int needstorest(lifeform_t *lf, char *validchars) {
if (lf->hp < lf->maxhp) {
if (validchars) strcat(validchars, "h");
need = B_TRUE;
} else if (hastempinjuries(lf)) {
if (validchars) strcat(validchars, "h");
need = B_TRUE;
}
if ((getmaxmp(lf) > 0) && (lf->mp < getmaxmp(lf))) {
if (validchars) strcat(validchars, "m");
@ -11589,16 +11636,16 @@ int recruit(lifeform_t *lf) {
difficulty = 20 + ((gethitdice(player) - gethitdice(lf))*2);
if (real_skillcheck(player, A_CHA, difficulty, 0, &result)) {
// passed
askingprice = rnd(gethitdice(lf)*50, gethitdice(lf)*100 );
askingprice = rnd(gethitdice(lf)*5, gethitdice(lf)*20 );
addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL);
} else {
if (difficulty - result >= 10) {
// very expensive
askingprice = rnd(gethitdice(lf)*250, gethitdice(lf)*300 );
askingprice = rnd(gethitdice(lf)*20, gethitdice(lf)*30 );
addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL);
} else {
// expensive
askingprice = rnd(gethitdice(lf)*100, gethitdice(lf)*200 );
askingprice = rnd(gethitdice(lf)*10, gethitdice(lf)*25 );
addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL);
}
}
@ -11606,12 +11653,15 @@ int recruit(lifeform_t *lf) {
if (askingprice != 0) {
// modify by charisma
askingprice = pctof(100 + getstatmod(player, A_CHA), askingprice);
askingprice = pctof(100 - getstatmod(player, A_CHA), askingprice);
limit(&askingprice, 0, NA);
}
if (askingprice > 0) {
sayphrase(lf, SP_RECRUIT_ASKPRICE, SV_TALK, askingprice, NULL);
more();
if (askingprice > countmoney(player)) {
if (askingprice > countmoney(player->pack)) {
} else {
char ch;
snprintf(buf, BUFLEN, "Pay $%d to hire %s", askingprice, lfname);
@ -11635,7 +11685,7 @@ int recruit(lifeform_t *lf) {
}
sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p);
} else {
if (askingprice > countmoney(player)) {
if (askingprice > countmoney(player->pack)) {
sayphrase(lf, SP_RECRUIT_DECLINE_CANTPAY, SV_TALK, askingprice, NULL);
} else {
sayphrase(lf, SP_RECRUIT_DECLINE_WONTPAY, SV_TALK, askingprice, NULL);
@ -12499,7 +12549,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r
attrib = getattr(lf, A_CON);
break;
case SC_DEX:
attrib = getattr(lf, A_DEX);
attrib = getattr(lf, A_AGI);
break;
case SC_IQ:
attrib = getattr(lf, A_IQ);
@ -12516,7 +12566,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r
break;
///////////////
case SC_OPENLOCKS:
attrib = getattr(lf, A_DEX);
attrib = getattr(lf, A_AGI);
break;
case SC_WILL:
attrib = getattr(lf, A_WIS);
@ -12535,10 +12585,10 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r
break;
case SC_SLIP:
case SC_FALL:
attrib = getattr(lf, A_DEX);
attrib = getattr(lf, A_AGI);
break;
case SC_SHIELDBLOCK:
attrib = (getattr(lf, A_DEX) / 4);
attrib = (getattr(lf, A_AGI) / 4);
break;
case SC_POISON:
attrib = getattr(lf, A_CON);
@ -12546,7 +12596,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r
case SC_DISARM:
attrib = (getskill(lf, SK_TRAPS)*3);
if (attrib) {
attrib += (getattr(lf, A_DEX)/4);
attrib += (getattr(lf, A_AGI)/4);
}
break;
case SC_CLIMB:
@ -12628,14 +12678,14 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r
slev = PR_INEPT;
}
switch (slev) {
case PR_NOVICE: othermod = 4; break;
case PR_BEGINNER: othermod = 7; break;
case PR_ADEPT: othermod = 10; break;
case PR_SKILLED: othermod = 13; break;
case PR_EXPERT: othermod = 16; break;
case PR_MASTER: othermod = 20; break;
case PR_NOVICE: othermod = 0; break;
case PR_BEGINNER: othermod = 4; break;
case PR_ADEPT: othermod = 7; break;
case PR_SKILLED: othermod = 10; break;
case PR_EXPERT: othermod = 13; break;
case PR_MASTER: othermod = 16; break;
default:
othermod = 0;
othermod = -4;
break;
}
} else if (ct == SC_MORALE) {
@ -12664,7 +12714,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r
} else if (ct == SC_STEAL) {
if (attrib > 0) {
// ie. -3 to 3
othermod += (getstatmod(lf, A_DEX) / 15);
othermod += (getstatmod(lf, A_AGI) / 15);
}
} else if (ct == SC_STEALTH) {
if (attrib > 0) {
@ -12680,7 +12730,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r
levmod *= 2;
} else if (ct == SC_TUMBLE) {
// ie. -3 to 3
othermod += (getstatmod(lf, A_DEX) / 15);
othermod += (getstatmod(lf, A_AGI) / 15);
}
@ -13044,7 +13094,7 @@ void startlfturn(lifeform_t *lf) {
// either use up stamina, or gain it
if (lfhasflag(lf, F_SPRINTING)) {
modstamina(lf, -1);
modstamina(lf, -1.5);
} else if (isswimming(lf)) {
int lossamt;
// lose stamina based on swimming skill
@ -13059,8 +13109,8 @@ void startlfturn(lifeform_t *lf) {
}
if (lossamt) modstamina(lf, -lossamt);
} else {
if (lf->stamina < getmaxstamina(lf)) {
float regenrate = 0.5;
if (getstamina(lf) < getmaxstamina(lf)) {
float regenrate = STAMREGEN;
if (lfhasflagval(lf, F_INJURY, IJ_WINDPIPECRUSHED, NA, NA, NULL)) {
regenrate = 0.2; // override everything else
} else {
@ -13094,7 +13144,7 @@ void startlfturn(lifeform_t *lf) {
if (f) {
cell_t *retcell[MAXCANDIDATES];
int nretcells;
getradiuscells(lf->cell, 2, DT_COMPASS, LOF_WALLSTOP, B_FALSE, retcell, &nretcells, 0);
getradiuscells(lf->cell, 2, DT_COMPASS, B_FALSE, LOF_WALLSTOP, B_FALSE, retcell, &nretcells, 0);
for (i = 0; i < nretcells; i++) {
if (retcell[i]->lf && areenemies(lf, retcell[i]->lf)) {
int dir,reldir;
@ -13752,11 +13802,33 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) {
}
}
if (prompt.nchoices > 1) {
if (isplayer(lf) && (slev >= PR_ADEPT)) {
if (slev >= PR_ADEPT) {
if (isplayer(lf)) {
addchoice(&prompt, '-', "Nothing", NULL, NULL, NULL);
// pick what you want
getchoice(&prompt);
o = (object_t *)prompt.result;
} else {
int nn,nposs = 0;
object_t *poss[MAXCHOICES*2];
// get something we want
for (nn = 0; nn < prompt.nchoices; nn++) {
int cov;
if (aiwants(lf, (object_t *)prompt.choice[nn].data, &cov)) {
if (cov) { // add twice
poss[nposs++] = o;
poss[nposs++] = o;
} else {
poss[nposs++] = o;
}
}
}
if (nposs) {
o = poss[rnd(0,nposs-1)];
} else {
o = (object_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data;
}
}
} else {
// random
o = (object_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data;
@ -14016,11 +14088,20 @@ void taketime(lifeform_t *lf, long howlong) {
map = lf->cell->map;
assert(howlong > 0);
if (db && (gamemode == GM_GAMESTARTED) && cansee(player, lf)) {
if (gamemode == GM_GAMESTARTED) {
if (map != player->cell->map) {
// lfs not on the player's map don't take time.
// this avoids the assertion below failing when
// (for example) a monster falls through a pit.
return;
}
if (db && cansee(player, lf)) {
dblog("lfid %d (%s) spending %d time\n",lf->id,lf->race->name, howlong);
}
}
assert(howlong > 0);
// inc timespent
lf->timespent += howlong;
assert(lf->timespent >= 0);
@ -15082,7 +15163,7 @@ int rest(lifeform_t *lf, int onpurpose) {
wantclearmsg = B_FALSE;
// resting
if (lf->hp >= lf->maxhp) {
if ((lf->hp >= lf->maxhp) && !hastempinjuries(lf)) {
hf = lfhasflag(lf, F_RESTUNTILHP);
if (hf) killflag(hf);
}

9
lf.h
View File

@ -54,7 +54,6 @@ int check_rest_ok(lifeform_t *lf);
float comparelfs(lifeform_t *lf1, lifeform_t *lf2);
int confuse(lifeform_t *lf, int howlong);
int countinnateattacks(lifeform_t *lf);
int countmoney(lifeform_t *lf);
int countnearbyallies(lifeform_t *lf);
int countnearbyhurtallies(lifeform_t *lf);
int countplantsinsight(lifeform_t *lf);
@ -110,6 +109,8 @@ object_t *getarmour(lifeform_t *lf, enum BODYPART bp);
int getarmournoise(lifeform_t *lf);
int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, int *narms);
int getattackspeed(lifeform_t *lf);
float getattackstamloss(lifeform_t *lf);
float getattackstamloss(lifeform_t *lf);
int getattpoints(lifeform_t *lf);
int getattr(lifeform_t *lf, enum ATTRIB attr);
enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, /*@null@*/char *buf);
@ -182,6 +183,7 @@ float getlfweight(lifeform_t *lf, int withobs);
object_t *getsecmeleeweapon(lifeform_t *lf);
object_t *getshield(lifeform_t *lf);
int getspellspeed(lifeform_t *lf);
int getstamina(lifeform_t *lf);
char *getplayername(char *buf);
char *getplayernamefull(char *buf);
int getpoisondamchance(enum POISONTYPE ptype);
@ -193,6 +195,7 @@ int getraceclass(lifeform_t *lf);
int getracerarity(map_t *map, enum RACE rid);
object_t *getrandomarmour(lifeform_t *lf);
enum BODYPART getrandomcorebp(lifeform_t *lf);
race_t *getrandomcorpserace(cell_t *c);
job_t *getrandomjob(int onlyplayerjobs);
int getrandommonlevel(race_t *r, map_t *m);
race_t *getrandomrace(cell_t *c, int forcedepth);
@ -224,13 +227,14 @@ 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);
flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp);
int hasfreeaction(lifeform_t *lf);
job_t *hasjob(lifeform_t *lf, enum JOB job);
void inc_quad_range(enum QUADRANT *start, enum QUADRANT *end, int howmuch);
int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype);
int lfcanbestoned(lifeform_t *lf);
flag_t *lfhasflag(lifeform_t *lf, enum FLAG fid);
flag_t *lfhasflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, /*@null@*/ char *text);
flag_t *lfhasflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, char *text);
flag_t *lfhasknownflag(lifeform_t *lf, enum FLAG fid);
flag_t *lfhasknownflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, /*@null@*/ char *text);
int lfproduceslight(lifeform_t *lf);
@ -274,6 +278,7 @@ int ispolymorphed(lifeform_t *lf);
int isprone(lifeform_t *lf);
flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt);
flag_t *isresting(lifeform_t *lf);
int issleepingtimefor(lifeform_t *lf);
object_t *isstuck(lifeform_t *lf);
int issmellablelf(lifeform_t *lf);
int isswimming(lifeform_t *lf);

36
map.c
View File

@ -285,6 +285,11 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int
// TODO: base this on the time, and whether monster is nocturnal
if (pctchance(asleepchance)) {
addflag(lf->flags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL);
} else {
// might be asleep based on time.
if (issleepingtimefor(lf)) {
addflag(lf->flags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL);
}
}
}
// monsters who on dark levels can always see in the dark
@ -535,7 +540,7 @@ int getmapmaxvisrange(map_t *m) {
// populates retcell[] with all cells within given radius of centre
// if 'scatter' is >0, then not all cells will be returned - as you approach the edge of the radius,
// chances of getting the cells are lowered
void getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlof, int wantcentre, cell_t **retcell, int *ncells, int scatterdensity) {
void getradiuscells(cell_t *centre, int radius, int dirtype, int outsideonly, enum LOFTYPE needlof, int wantcentre, cell_t **retcell, int *ncells, int scatterdensity) {
int (*distfunc)(cell_t *, cell_t *);
int x,y;
cell_t *c;
@ -554,10 +559,14 @@ void getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlo
for (x = centre->x - radius; x <= centre->x + radius; x++) {
c = getcellat(centre->map, x,y);
if (c) {
int distance;
int distance,distmatch = B_FALSE;
distance = distfunc(centre, c);
if (haslof(centre, c, needlof, NULL) && (distance <= radius) &&
(wantcentre || (c != centre)) ) {
if (outsideonly) {
if (distance == radius) distmatch = B_TRUE;
} else {
if (distance <= radius) distmatch = B_TRUE;
}
if (distmatch && haslof(centre, c, needlof, NULL) && (wantcentre || (c != centre)) ) {
int chance;
if (scatterdensity) {
chance = 100 - (((float)distance / (float)radius) * scatterdensity);
@ -2035,8 +2044,12 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
} else {
for (i = 0; i < map->region->rtype->stairsperlev; i++) {
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
while (!isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM);
if (!c) {
// ANY cell at all, doesn't have to be a room.
c = getrandomcell(map);
}
}
o = addobfast(c->obpile, OT_STAIRSUP);
linkstairs(o, NULL);
@ -2213,14 +2226,14 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t
c = getrandomcell(map);
w = rnd(MINCLEARINGRADIUS,MAXCLEARINGRADIUS);
// clear obs in all clearing cells
getradiuscells(c, w, DT_ORTH, LOF_DONTNEED, B_TRUE, retcell, &nretcells, B_FALSE);
getradiuscells(c, w, DT_ORTH, B_FALSE, LOF_DONTNEED, B_TRUE, retcell, &nretcells, B_FALSE);
for (n = 0; n < nretcells; n++) {
// kill all obs here
while (retcell[n]->obpile->first) killob(retcell[n]->obpile->first);
}
// fill some cells with dirt
getradiuscells(c, w, DT_ORTH, LOF_DONTNEED, B_TRUE, retcell, &nretcells, 70);
getradiuscells(c, w, DT_ORTH,B_FALSE, LOF_DONTNEED, B_TRUE, retcell, &nretcells, 70);
for (n = 0; n < nretcells; n++) {
setcelltype(retcell[n], CT_DIRT);
}
@ -2235,7 +2248,7 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t
w = rnd(MINCLEARINGRADIUS,MAXCLEARINGRADIUS);
getradiuscells(c, w, DT_ORTH, LOF_DONTNEED, B_TRUE, retcell, &nretcells, 80);
getradiuscells(c, w, DT_ORTH, B_FALSE, LOF_DONTNEED, B_TRUE, retcell, &nretcells, 80);
for (n = 0; n < nretcells; n++) {
switch (rnd(0,1)) {
default: case 0: strcpy(buf, "tree"); break;
@ -3280,7 +3293,10 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
}
} else {
if (db) dblog(" Cannot find a way to link up.");
assert(0 == 1); // for debugging
// debugging - a failure here during fix_reachability is fatal.
if (wantfilled) {
assert(0 == 1);
}
}
return B_TRUE;
}
@ -5295,7 +5311,7 @@ void setcellknown(cell_t *cell, int forcelev) {
void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype) {
cell_t *cell[MAXCANDIDATES];
int ncells,i;
getradiuscells(centre, radius, dirtype, LOF_DONTNEED, B_TRUE, cell, &ncells, B_FALSE);
getradiuscells(centre, radius, dirtype, B_FALSE, LOF_DONTNEED, B_TRUE, cell, &ncells, B_FALSE);
for (i = 0; i < ncells; i++) {
cell_t *c;
c = cell[i];

2
map.h
View File

@ -32,7 +32,7 @@ flag_t *getmapcoords(map_t *m, int *x, int *y);
int getmapdifficulty(map_t *m);
map_t *getmapindir(map_t *src, int dir);
int getmapmaxvisrange(map_t *m);
void getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlof, int wantcentre, cell_t **retcell, int *ncells, int scatterdensity);
void getradiuscells(cell_t *centre, int radius, int dirtype, int outsideonly, enum LOFTYPE needlof, int wantcentre, cell_t **retcell, int *ncells, int scatterdensity);
int getroomid(cell_t *c);
void getroomedge(map_t *m, int roomid, int minx, int miny, int maxx, int maxy, int whichside, cell_t **retcell, int *ncells, int onlywantsolid);
object_t *gettopobject(cell_t *where, int forglyph);

47
move.c
View File

@ -7,6 +7,7 @@
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
@ -476,6 +477,7 @@ int dorandommove(lifeform_t *lf, int badmovesok, int restonfail) {
// src is where something is
// dst is what we are going away from
// if srclf is set, it is used for cellwalkable() checks. ie. if move will be involuntary, don't set this!
// wantcheck is whether to check for dangerous things before considering a direction valid
int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype, int keepinlof) {
int d;
@ -931,7 +933,7 @@ int moveeffects(lifeform_t *lf) {
}
if (isbleeding(lf)) {
if (lfhasflagval(lf, F_INJURY, NA, BP_LEGS, DT_SLASH, NULL)) {
if (hasbleedinginjury(lf, BP_LEGS)) {
if (!bleedfrom(lf, BP_LEGS, B_FALSE)) {
losehp(lf, 1, DT_DIRECT, NULL, "blood loss");
}
@ -1265,6 +1267,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
f = hasflag(postroom->vault->flags, F_VAULTENTERTEXT);
if (f) {
msg("%s", f->text);
didmsg = B_TRUE;
}
}
}
@ -1530,9 +1533,6 @@ int move_will_hurt(lifeform_t *lf) {
flag_t *retflag[MAXCANDIDATES];
int nretflags,i;
if (lfhasflag(lf, F_PAIN)) {
return B_TRUE;
}
getflags(lf->flags, retflag, &nretflags, F_INJURY, F_PAIN, F_NONE);
for (i = 0; i < nretflags; i++) {
flag_t *f;
@ -1547,6 +1547,10 @@ int move_will_hurt(lifeform_t *lf) {
}
}
}
if (hasbleedinginjury(lf, BP_LEGS)) {
return B_TRUE;
}
return B_FALSE;
}
@ -1819,11 +1823,17 @@ int closedoor(lifeform_t *lf, object_t *o) {
}
int tryrun(lifeform_t *lf, int dir) {
if (!trymove(lf, dir, B_TRUE, B_TRUE)) {
// success!
int willrun = B_TRUE,rv;
if (!moveclear(lf, dir, NULL)) {
// don't double move into monsters, etc
willrun = B_FALSE;
}
rv = trymove(lf, dir, B_TRUE, B_TRUE);
if (!rv && willrun) {
// successful move
addflag(lf->flags, F_RUNNING, dir, B_FALSE, NA, NULL);
}
return B_FALSE;
return rv;
}
int trysneak(lifeform_t *lf, int dir) {
@ -2206,13 +2216,18 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
int rndmove = B_FALSE;
int howlong;
int reldir;
int srcmoney = 0;
flag_t *f;
howlong = getmovespeed(lf);
reldir = getrelativedir(lf, dir);
if (onpurpose) {
if (isplayer(lf)) {
srcmoney = countmoney(lf->cell->obpile);
}
if ((reldir != RD_FORWARDS) && !lfhasflag(lf, F_AWARENESS)) {
// if the given dir is behind us, just turn.
if (!strafe) {
@ -2248,8 +2263,8 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
cell = getcellindir(lf->cell, dir);
// warn if moving will cause injury
if (onpurpose && isplayer(lf)) {
// warn if moving will cause damage
if (cell && !cell->lf && onpurpose && isplayer(lf) ) {
if (!confirm_injury_action(BP_LEGS, DT_SLASH, "move")) {
return B_TRUE;
}
@ -2536,6 +2551,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
char lfname[BUFLEN];
getlfname(lfinway, lfname);
msg("You swap places with %s.", lfname);
dontclearmsg = B_TRUE;
}
swapplaces(lf, lfinway, B_FALSE, onpurpose);
@ -2600,11 +2616,16 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
default:
break;
}
if (reason == E_OK) {
return B_FALSE;
} else {
return B_TRUE;
}
// purposely moving away fmor money?
if (onpurpose && isplayer(lf) && srcmoney) {
angergodmaybe(R_GODTHIEVES, srcmoney);
}
if (reason != E_OK) {
return B_TRUE;
}
return B_FALSE;
}

105
objects.c
View File

@ -1222,9 +1222,9 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
if (o->type->id == OT_CORPSE) {
flag_t *rf, *cf;
if (!corpserace) {
if (!corpserace || hasflag(corpserace->flags, F_NOCORPSE)) {
// random one.
corpserace = getrandomrace(NULL, NA);
corpserace = getrandomcorpserace(NULL);
}
o->weight = corpserace->weight;
@ -1250,11 +1250,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
where = getoblocation(o);
// select random race
if (where) {
corpserace = getrandomrace(where, NA);
corpserace = getrandomcorpserace(where);
}
if (!corpserace) {
// ie. vending machine, or inside another object/fake cell?
corpserace = getrandomrace(NULL, NA);
corpserace = getrandomcorpserace(NULL);
}
}
@ -1311,9 +1311,9 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
} else if (o->type->id == OT_ROASTMEAT) {
flag_t *rf, *cf;
if (!corpserace) {
if (!corpserace || hasflag(corpserace->flags, F_NOCORPSE)) {
// random one.
corpserace = getrandomrace(NULL, NA);
corpserace = getrandomcorpserace(NULL);
}
o->weight = corpserace->weight / 2;
@ -1468,7 +1468,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
if (o->blessed == B_CURSED) f->val[2] *= -1;
} else if (o->type->id == OT_RING_DEX) {
flag_t *f;
f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_DEX, NA, NULL);
f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_AGI, NA, NULL);
if (f) {
if (bonus) f->val[2] = bonus;
else f->val[2] = rnd(1,3);
@ -1592,7 +1592,7 @@ int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fr
redrawpause();
getradiuscells(where, range, dirtype, needlof, B_TRUE, cell, &ncells, B_FALSE);
getradiuscells(where, range, dirtype, B_FALSE, needlof, B_TRUE, cell, &ncells, B_FALSE);
for (i = 0; i < ncells; i++) {
cell_t *c;
c = cell[i];
@ -2390,6 +2390,18 @@ void copyobprops(object_t *dst, object_t *src) {
}
int countmoney(obpile_t *op) {
object_t *o;
int amt = 0;
for (o = op->first ; o ; o = o->next) {
if (o->type->id == OT_GOLD) {
amt += o->amt;
}
}
return amt;
}
int countnames(char **list) {
int count;
for (count = 0; list[count]; count++);
@ -3042,9 +3054,10 @@ int getobaccuracy(object_t *wep, lifeform_t *weilder) {
}
// blessed weapons have better base accuracy
if (wep->blessed == B_BLESSED) acc += 50;
if (wep->blessed == B_BLESSED) acc += 10;
//bonusses?
acc += (getobbonus(wep)*5);
acc += (getobbonus(wep, B_FALSE)*10);
if (weilder) {
enum SKILLLEVEL slev;
@ -3085,15 +3098,18 @@ int getobaccuracy(object_t *wep, lifeform_t *weilder) {
return acc;
}
int getobbonus(object_t *o) {
int getobbonus(object_t *o, int onlyknown) {
int bonus = 0,i;
flag_t *retflag[MAXCANDIDATES];
int nretflags = 0;
getflags(o->flags, retflag, &nretflags, F_BONUS, F_NONE);
for (i = 0; i < nretflags; i++) {
if (onlyknown && !retflag[i]->known) {
} else {
bonus += retflag[i]->val[0];
}
}
return bonus;
}
@ -3326,29 +3342,6 @@ object_t *getoutercontainerop(obpile_t *op) {
return o;
}
// ie. "it has xxx accuracy"
char *getaccuracyname(int accpct) {
if (accpct >= 200) {
return "godlike";
} else if (accpct >= 150) {
return "incredible";
} else if (accpct >= 100) {
return "very good";
} else if (accpct >= 70) {
return "good";
} else if (accpct >= 50) {
return "average";
} else if (accpct >= 30) {
return "poor";
} else if (accpct >= 20) {
return "very poor";
} else if (accpct >= 0) {
return "incredibly poor";
} else {
return "a complete lack of";
}
}
object_t *getammo(object_t *gun) {
object_t *o;
@ -4547,7 +4540,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
}
if (hasflag(o->flags, F_KNOWNBAD)) {
strcat(localbuf, " [bad]");
strcat(localbuf, " [badfeeling]");
}
if (getskill(player, SK_COOKING) >= PR_BEGINNER) {
@ -5212,12 +5205,15 @@ int getthrowdam(object_t *o) {
return (int)dam;
}
// get either name of top object, or cell type if solid
// get either name of top object, or cell type
char *gettopobname(cell_t *c, char *retbuf) {
char buf[BUFLEN];
int nother;
strcpy(retbuf, "");
/*
if (c->type->solid) {
strcpy(retbuf, c->type->name);
nother = countnoncosmeticobs(c->obpile, B_TRUE);
if (nother) {
snprintf(buf, BUFLEN, " (+%d other thing%s)", nother, (nother == 1) ? "" : "s");
@ -5225,6 +5221,8 @@ char *gettopobname(cell_t *c, char *retbuf) {
}
return retbuf;
} else {
}
*/
object_t *o;
o = gettopobject(c, B_FALSE);
if (o) {
@ -5236,10 +5234,11 @@ char *gettopobname(cell_t *c, char *retbuf) {
snprintf(buf, BUFLEN, " (+%d other thing%s)", nother, (nother == 1) ? "" : "s");
strcat(retbuf, buf);
}
} else {
// just print the cell's name
strcat(retbuf, c->type->name);
}
return retbuf;
}
}
return NULL;
}
enum BODYPART getweildloc(object_t *o, enum BODYPART *otherloc, int *twohanded) {
@ -5825,6 +5824,9 @@ int ismagical(object_t *o) {
if (hasflag(o->flags, F_ENCHANTABLE) && hasflag(o->flags, F_BONUS)) {
return B_TRUE;
}
if (o->type->id == OT_SHILLELAGH) {
return B_TRUE;
}
return B_FALSE;
}
@ -6245,9 +6247,9 @@ int makeduller(object_t *o, int howmuch) {
// get object name before changing the bonus
getobname(o,obname, 1);
oldbonus = getobbonus(o);
oldbonus = getobbonus(o, B_FALSE);
modbonus(o, -howmuch);
newbonus = getobbonus(o);
newbonus = getobbonus(o, B_FALSE);
if (newbonus < oldbonus) {
if (o->pile->owner) {
@ -7641,7 +7643,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
if ((m->region->rtype->id == RG_FIRSTDUNGEON) && (m->depth == 1)) {
cell_t *cell[MAXCANDIDATES];
int ncells,i;
getradiuscells(lf->cell, 1, DT_COMPASS, B_FALSE, B_TRUE, cell, &ncells, B_FALSE);
getradiuscells(lf->cell, 1, DT_COMPASS, B_FALSE, LOF_DONTNEED, B_TRUE, cell, &ncells, B_FALSE);
for (i = 0; i < ncells; i++) {
if (hasob(cell[i]->obpile, OT_STAIRSUP)) {
object_t *o;
@ -8594,8 +8596,8 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
setattr(lf, A_STR, lf->baseatt[A_STR]);
failed = B_FALSE;
}
if (getattr(lf,A_DEX) < lf->baseatt[A_DEX]) {
setattr(lf, A_DEX, lf->baseatt[A_DEX]);
if (getattr(lf,A_AGI) < lf->baseatt[A_AGI]) {
setattr(lf, A_AGI, lf->baseatt[A_AGI]);
failed = B_FALSE;
}
if (getattr(lf,A_IQ) < lf->baseatt[A_IQ]) {
@ -8872,6 +8874,7 @@ int readsomething(lifeform_t *lf, object_t *o) {
} else {
makeknown(o->type->id);
}
o->blessknown = B_TRUE;
real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_TRUE, B_FALSE); // don't adjust for blindness
if (isplayer(lf)) {
// tell the player
@ -8893,7 +8896,9 @@ int readsomething(lifeform_t *lf, object_t *o) {
}
}
}
if (seen) makeknown(o->type->id);
if (seen) {
makeknown(o->type->id); o->blessknown = B_TRUE;
}
} else if ((o->type->id == OT_SCR_MENDING) && isblessed(o)) {
int seen = B_FALSE;
object_t *oo;
@ -8906,7 +8911,7 @@ int readsomething(lifeform_t *lf, object_t *o) {
}
}
if (seen) {
makeknown(o->type->id);
makeknown(o->type->id); o->blessknown = B_TRUE;
} else {
if (isplayer(lf) || cansee(player, lf)) nothinghappens();
}
@ -8936,7 +8941,7 @@ int readsomething(lifeform_t *lf, object_t *o) {
dospelleffects(lf, f->val[0], power, NULL, targob, NULL, o->blessed, &seen, B_FALSE);
if (seen) {
// id the scroll now
makeknown(o->type->id);
makeknown(o->type->id); o->blessknown = B_TRUE;
}
// removeob one of the object
@ -9152,7 +9157,7 @@ int readsomething(lifeform_t *lf, object_t *o) {
if (seen) {
// id the scroll now
makeknown(o->type->id);
makeknown(o->type->id); o->blessknown = B_TRUE;
} else {
if (isplayer(lf)) {
nothinghappens();
@ -10350,7 +10355,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
if (willcatch) {
acc = 100;
} else {
acc = getmissileaccuracy(thrower, where, o, firearm, A_DEX);
acc = getmissileaccuracy(thrower, where, o, firearm, A_AGI);
}
} else {
// purely based on saving throw...
@ -11609,6 +11614,8 @@ int getcritchance(lifeform_t *lf, object_t *o, lifeform_t *victim) {
f = hasflag(o->flags, F_CRITCHANCE);
if (f) {
chance += f->val[0];
} else {
return 0;
}
if (lf) {

View File

@ -36,6 +36,7 @@ int changemat(object_t *o, enum MATERIAL mat);
int checkobnames(char *haystack, char *needle);
void colourmatchob(object_t *o, lifeform_t *lf);
void copyobprops(object_t *dst, object_t *src);
int countmoney(obpile_t *op);
int countnames(char **list);
int countobs(obpile_t *op, int onlyifknown);
int countobsoftype(obpile_t *op, enum OBTYPE oid);
@ -66,7 +67,7 @@ enum COLOUR getmaterialcolour(enum MATERIAL mat );
enum MATSTATE getmaterialstate(enum MATERIAL mat);
int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt);
int getobaccuracy(object_t *wep, lifeform_t *weilder);
int getobbonus(object_t *o);
int getobbonus(object_t *o, int onlyknown);
int getobpoints(object_t *o);
skill_t *getobskill(object_t *o);
enum LFSIZE getobsize(object_t *o);
@ -76,7 +77,6 @@ char *getoperateverb(object_t *o);
object_t *getoutercontainer(object_t *o);
object_t *getoutercontainerop(obpile_t *op);
//int getobtypevalue(objecttype_t *ot);
char *getaccuracyname(int accpct);
object_t *getammo(object_t *gun);
objecttype_t *getbasicweaponforskill(enum SKILL skid);
object_t *getrandomammo(lifeform_t *lf);

4
save.c
View File

@ -196,7 +196,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) {
// load rest of this lf
fscanf(f, "str: %d/%d\n",&l->att[A_STR],&l->baseatt[A_STR]);
fscanf(f, "dex: %d/%d\n",&l->att[A_DEX],&l->baseatt[A_DEX]);
fscanf(f, "dex: %d/%d\n",&l->att[A_AGI],&l->baseatt[A_AGI]);
fscanf(f, "int: %d/%d\n",&l->att[A_IQ],&l->baseatt[A_IQ]);
fscanf(f, "xp: %ld\n",&l->xp);
fscanf(f, "skp: %d\n",&l->skillpoints);
@ -784,7 +784,7 @@ int savelf(FILE *f, lifeform_t *l) {
fprintf(f, "newlevel: %d\n",l->newlevel);
// liefform will be created after loading the above.
fprintf(f, "str: %d/%d\n",l->att[A_STR],l->baseatt[A_STR]);
fprintf(f, "dex: %d/%d\n",l->att[A_DEX],l->baseatt[A_DEX]);
fprintf(f, "dex: %d/%d\n",l->att[A_AGI],l->baseatt[A_AGI]);
fprintf(f, "int: %d/%d\n",l->att[A_IQ],l->baseatt[A_IQ]);
fprintf(f, "xp: %ld\n",l->xp);
fprintf(f, "skp: %d\n",l->skillpoints);

164
spell.c
View File

@ -99,7 +99,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (f) stamcost = f->val[0];
if (stamcost) {
if (user->stamina < stamcost) {
if (getstamina(user) < stamcost) {
if (isplayer(user)) {
msg("You are too tired to do that right now.");
}
@ -580,7 +580,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
// victim gets a skilcheck to avoid being grabbed
if (skillcheck(target, SC_DODGE, getattr(user, A_DEX)+11, 0)) {
if (skillcheck(target, SC_DODGE, getattr(user, A_AGI)+11, 0)) {
if (cansee(player, user)) {
msg("%s evade%s %s%s grasp.", targetname, isplayer(target) ? "" : "s",
username, getpossessive(username));
@ -800,12 +800,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
} else if (abilid == OT_A_REPAIR) {
enum SKILLLEVEL slev;
object_t *o;
object_t *o,*helpob = NULL;
enum MATERIAL repairablemats[MAXCANDIDATES];
int repaircutoff = 0;
int cutoffpct[MAXCANDIDATES];
int nmats = 0;
int i;
char helpobname[BUFLEN];
// get list of repairable materials
slev = getskill(user, SK_METALWORK);
@ -820,6 +821,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
case PR_MASTER: cutoff = 100; break;
default: cutoff = 0; break;
}
helpob = hasob(user->pack, OT_SPANNER);
if (helpob) cutoff += 15;
repairablemats[nmats] = MT_METAL;
cutoffpct[nmats] = cutoff;
nmats++;
@ -836,6 +839,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
case PR_MASTER: cutoff = 100; break;
default: cutoff = 0; break;
}
helpob = hasob(user->pack, OT_NEEDLE);
if (helpob) cutoff += 15;
repairablemats[nmats] = MT_CLOTH;
cutoffpct[nmats] = cutoff;
nmats++;
@ -844,6 +849,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
nmats++;
}
if (helpob) {
real_getobname(helpob, helpobname, helpob->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE);
} else {
strcpy(helpobname, "");
}
// 1.compile a list of repairable objects
// sk_armour lets you repair armour up to xx% (depends on skill)
@ -864,10 +874,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
f = hasflag(o->flags, F_OBHP);
pct = ((float)f->val[0] /(float) f->val[1]) * 100;
if (pct < cutoff) {
char buf[BUFLEN];
char buf[BUFLEN],desc[BUFLEN];
getobname(o, buf, o->amt);
sprintf(desc, "%s (-> %d%%)",buf, cutoff);
// we can repair this object
addchoice(&prompt, o->letter, buf, buf, o, NULL);
addchoice(&prompt, o->letter, desc, desc, o, NULL);
}
}
}
@ -909,13 +920,21 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
f = hasflag(o->flags, F_OBHP);
f->val[0] = pctof(repaircutoff, f->val[1]);
if (isplayer(user)) {
char buf[BUFLEN];
char buf[BUFLEN],withbuf[BUFLEN];
real_getobname(o, buf, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE);
msg("You %srepair your %s.", (f->val[0] == f->val[1]) ? "" : "partially ", noprefix(buf));
if (helpob) sprintf(withbuf, " (with %s)", helpobname);
else strcpy(withbuf, "");
msg("You %srepair your %s%s.", (f->val[0] == f->val[1]) ? "" : "partially ",
noprefix(buf), withbuf);
} else {
char buf[BUFLEN];
char buf[BUFLEN],withbuf[BUFLEN];
real_getobname(o, buf, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE);
msg("%s %s repairs %s.", username, (f->val[0] == f->val[1]) ? "completely" : "partially", buf);
if (helpob) sprintf(withbuf, " with %s", helpobname);
else strcpy(withbuf, "");
msg("%s %s repairs %s%s.", username, (f->val[0] == f->val[1]) ? "completely" : "partially",
buf, withbuf);
}
// TODO: make this like eating/resting/etc ?
@ -1416,6 +1435,47 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
msg("all blinded!");
return B_FALSE;
} else if (abilid == OT_A_AIMEDSTRIKE) {
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 control for an aimed strike while swimming.");
return B_TRUE;
}
wep = getweapon(user);
// ask for direction
if (!targcell) {
dirch = askchar("Aimed strike 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_AIMEDSTRIKE, B_TRUE, NA, NA, NULL);
attackcell(user, targcell, B_TRUE);
killflag(f);
} else if (abilid == OT_A_COMBOSTRIKE) {
object_t *wep;
skill_t *wepsk = NULL;
@ -1537,10 +1597,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (where && where->lf) {
char ch;
enum ATTRIB att;
ch = askchar("Enhance which stat (n for none)?", "sdcin",NULL, B_TRUE);
ch = askchar("Enhance which stat (n for none)?", "sacin",NULL, B_TRUE);
switch (ch) {
case 's': att = A_STR; break;
case 'd': att = A_DEX; break;
case 'a': att = A_AGI; break;
case 'c': att = A_CON; break;
case 'i': att = A_IQ; break;
default: att = A_NONE; break;
@ -2094,7 +2154,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("%s unleashes a freezing blast!", castername, getpossessive(castername));
}
// freeze lfs, obs in most cells
getradiuscells(caster->cell, 7, DT_ORTH, LOF_WALLSTOP, B_FALSE, retcell, &nretcells, 90);
getradiuscells(caster->cell, 7, DT_ORTH, B_FALSE, LOF_WALLSTOP, B_FALSE, retcell, &nretcells, 90);
for (i = 0; i < nretcells; i++) {
object_t *o, *nexto;
if (retcell[i]->lf) {
@ -3688,7 +3748,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// don't need line of fire!
if (!validatespellcell(caster, &targcell, TT_OBJECT, spellid, power, frompot)) return B_TRUE;
getradiuscells(targcell, power, DT_ORTH, LOF_NEED, B_TRUE, cell, &ncells, B_FALSE);
getradiuscells(targcell, power, DT_ORTH, B_FALSE, LOF_NEED, B_TRUE, cell, &ncells, B_FALSE);
for (i = 0; i < ncells; i++) {
object_t *o,*nexto;
for (o = cell[i]->obpile->first ; o ; o = nexto) {
@ -4051,6 +4111,32 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (failed) {
fizzle(caster);
}
} else if (spellid == OT_S_FORCESPHERE) {
cell_t *retcell[MAXRETCELLS];
int radius,nretcells,n,i;
if (!target) target = caster;
targcell = target->cell;
radius = power/3;
if (isplayer(target)) {
msg("You unleash a mighty shockwave!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) {
char tname[BUFLEN];
getlfname(target, tname);
msg("%s unleashes a mighty shockwave!", tname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// start at outside.
for (n = radius; n >= 1; n--) {
getradiuscells(targcell, n, DT_COMPASS, B_TRUE, LOF_WALLSTOP, B_FALSE, retcell, &nretcells, 0);
for (i = 0; i < nretcells; i++) {
if (retcell[i]->lf) {
knockback(retcell[i]->lf,
getdiraway(retcell[i], targcell, NULL, B_FALSE, DT_COMPASS, B_FALSE),
2, target, 27+power);
}
}
}
} else if (spellid == OT_S_ENERGYBOLT) {
char lfname[BUFLEN];
char numbuf[BUFLEN];
@ -4265,6 +4351,50 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (failed) {
fizzle(caster);
}
} else if (spellid == OT_S_EARTHQUAKE) {
cell_t *retcell[MAXRETCELLS],*c;
int nretcells,i,radius,seenwalls = 0, seenpits = 0;
radius = 3 + power;
getradiuscells(caster->cell, radius, DT_ORTH, B_FALSE, LOF_DONTNEED, B_FALSE, retcell, &nretcells, 80);
for (i = 0; i < nretcells; i++) {
c = retcell[i];
if (c->type->solid) {
if (haslos(player, c)) seenwalls++;
setcelltype(c, c->map->habitat->emptycelltype);
addob(c->obpile, "50-100 stones");
} else {
// it collapses
addobfast(c->obpile, OT_HOLEINGROUND);
if (haslos(player, c)) seenpits++;
}
}
getradiuscells(caster->cell, radius, DT_ORTH, B_FALSE, LOF_WALLSTOP, B_FALSE, retcell, &nretcells, 80);
for (i = 0; i < nretcells; i++) {
c = retcell[i];
if (!c->type->solid) {
addobfast(c->obpile, OT_DUSTCLOUD);
}
}
if (seenpits || seenwalls || cansee(player, caster)) {
msg("The earth below you shudders and shakes violently!");
setlosdirty(player);
}
if (seenpits) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
if (seenwalls == 1) {
msg("A huge rent opens up in the ground!");
} else {
msg("Huge rents open up in the ground!");
}
}
if (seenwalls) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
if (seenwalls == 1) {
msg("A nearby wall collapse into the ground!");
} else {
msg("Nearby walls collapse into the ground!");
}
}
} else if (spellid == OT_S_ENCHANT) {
object_t *o;
@ -6271,12 +6401,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
f = hasflag(o->flags, F_OBHP);
if (f && isdamaged(o)) {
if (f) {
if (blessed == B_CURSED) {
if (isplayer(caster) || cansee(player, caster)) msg("%s deteriorates!", fullobname);
takedamage(o, rnd(1,6) + power, DT_DIRECT);
donesomething = B_TRUE;
} else {
} else if (isdamaged(o)) {
f->val[0] += (rnd(1,6) + power);
if (f->val[0] >= f->val[1]) {
@ -6630,7 +6760,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
amttolose = power*2;
// only announce if the target will have some stamina left.
// if they drop to 0, modstamina will handle the announce.
if (target->stamina >= amttolose) {
if (getstamina(target) >= amttolose) {
if (isplayer(target)) {
msg("You suddenly feel very lethargic!");
} else if (cansee(player, target)) {
@ -6804,7 +6934,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
} else {
// 2nd one failed - lose all stamina instead
modstamina(target, -(target->stamina));
modstamina(target, -(getstamina(target)));
if (isplayer(target)) {
msg("You suddenly feel very lethargic!");
} else if (cansee(player, target)) {

82
text.c
View File

@ -153,6 +153,33 @@ int flip(int ch) {
return ch;
}
// ie. "it has xxx accuracy"
char *getaccuracyname(int accpct) {
if (accpct >= 200) {
return "incredible";
} else if (accpct >= 150) {
return "very good";
} else if (accpct >= 100) {
return "good";
} else if (accpct >= 70) {
return "average";
} else if (accpct >= 50) {
return "poor";
} else if (accpct >= 30) {
return "very poor";
} else if (accpct >= 20) {
return "extremely poor";
} else {
return "a complete lack of";
}
}
int getaccuracynum(int accpct) {
int num;
num = (accpct - 100) / 5; //
return num;
}
char *getattrabbrev(enum ATTRIB att) {
switch (att) {
case A_NONE:
@ -161,8 +188,8 @@ char *getattrabbrev(enum ATTRIB att) {
return "Ch";
case A_CON:
return "Ft";
case A_DEX:
return "Dx";
case A_AGI:
return "Ag";
case A_IQ:
return "Iq";
case A_STR:
@ -181,8 +208,8 @@ char *getattrname(enum ATTRIB att) {
return "charisma";
case A_CON:
return "fitness";
case A_DEX:
return "dexterity";
case A_AGI:
return "agility";
case A_IQ:
return "intelligence";
case A_STR:
@ -301,6 +328,53 @@ int gethitconferlifetime(char *text, int *min, int *max) {
return howlong;
}
char *getpoisondamverb(enum POISONTYPE ptype) {
switch (ptype) {
case P_FOOD:
case P_VENOM:
return "vomit";
case P_GAS:
case P_COLD:
return "cough";
default:
break;
}
return "";
}
char *getpoisondesc(enum POISONTYPE ptype) {
switch (ptype) {
case P_FOOD:
case P_VENOM:
case P_GAS:
case P_WEAKNESS:
return "Poisoned";
case P_COLD:
return "Sick";
default:
break;
}
return "Poisoned";
}
char *getpoisonname(enum POISONTYPE ptype) {
switch (ptype) {
case P_COLD:
return "hypothermia";
case P_FOOD:
return "food poisoning";
case P_GAS:
return "gas inhalation";
case P_VENOM:
return "venom poisoning";
case P_WEAKNESS:
return "weakening poison";
default:
break;
}
return "";
}
char *getpossessive(char *text) {
char lastchar;
// you -> your

5
text.h
View File

@ -6,11 +6,16 @@ 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 *getaccuracyname(int accpct);
int getaccuracynum(int accpct);
char *getattrabbrev(enum ATTRIB att);
char *getattrname(enum ATTRIB att);
char *getdirname(int dir);
char *getdirnameshort(int dir);
int gethitconferlifetime(char *text, int *min, int *max);
char *getpoisondamverb(enum POISONTYPE ptype);
char *getpoisondesc(enum POISONTYPE ptype);
char *getpoisonname(enum POISONTYPE ptype);
char *getpossessive(char *text);
char *getdrunktext(flag_t *drunkflag);
char *getinjuredbpname(enum BODYPART bp);

View File

@ -1,21 +1,19 @@
@id:playerstart_2
@map
###x###
#m|.|m#
#.-.-.#
###.###
#m|.-p#
#.-.-p#
###.###
#m|.|m#
#.-.-.#
###.###
#m|.|m#
#.-.-.#
###x###
@end
@legend
#:cell:rock wall
|:ob:locked iron gate
-:ob:iron gate
p:ob:playerstart
m:mon:humanoid
x:exit
@end
@flags

View File

@ -1,12 +1,14 @@
@id:playerstart_4
@map
###x###
#ww_ww#
#ww.ww#
x_.p._x
#ww.ww#
#ww_ww#
###x###
####x####
#.......#
#.ww_ww.#
#.ww.ww.#
x._.p._.x
#.ww.ww.#
#.ww_ww.#
#.......#
####x####
@end
@legend
#:cell:rock wall