- [+] adjust damage for size

* [+] repair armour
* [+] armour "hardness" to reduce damage?
- [+] fix resting while poisoned.
- [+] shouldn't be able to attack while ethereal
- [+] cursed scroll of mending should damage stuff
- [+] spark should light unactivated candles/torches instead of
      igniting.
* [+] askcoords:  add a subprompt param:
* [+] xp levels:
- [+] stealing skill
* [+] alarm spell - level 1 wild magic
- [+] reduce damage when drunk (-1d3)
* [+] better armour material damage immunities
* [+] bug - lots of mosnters on same square - bug with f_numappear
- [+] chat-> "go to x,y" (they must have los to there)
- [+] reduce # objects in rooms again!!!!
* [+] put gatekeeper on DLEV 6
- [+] bug: when doing a heavy blow, don't use weapon effects liek trip.
- [+] don't show "[magic]" or [inspected] at end of game
- [+] knockback bug: You flatten the kobold!  The kobold slams into a
      rock floor!
- [+] warn before dulling blade.... (if pretty high iq)
- [+] monstesr should not start eating when enemies are nearby!
- [+] increase weight of weapons
- [+] fix up what counts as a heavy wep
- [+] check throwing - i can throw a 6.5 javelin 6 squares with a str
      of 7!!
- [+] eat blinkdog corpse for instant blink ability

- [+] true strike (???, next xx attacks alway hits).  xx is power/3
- [+] floating disc (summon)
- [+] obscuring mist spell fixes
This commit is contained in:
Rob Pearce 2011-06-20 03:16:30 +00:00
parent 27d22df11d
commit 9db5f3aeec
16 changed files with 1287 additions and 492 deletions

34
ai.c
View File

@ -33,6 +33,11 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
db = B_TRUE;
}
// mindless?
if (getiqname(getattr(lf, A_IQ), NULL) == IQ_MINDLESS) {
return;
}
// already targetting this lf?
f = lfhasflagval(lf, F_TARGETLF, victim->id, NA, NA, NULL);
if (f) {
@ -723,7 +728,7 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y);
c = getcellat(lf->cell->map, x, y);
if (c) {
// target cell adjacent and something in the way?
// try to move towards the cll
if (movetowards(lf, c, DT_ORTH)) {
// couldn't move towards it for some reason.
// so stop trying.
@ -765,7 +770,7 @@ int aipickup(lifeform_t *lf, object_t *o) {
int aipickupok(lifeform_t *lf, object_t *o) {
int ok = B_FALSE;
if (isedible(o)) {
if (caneat(lf, o)) {
if (caneat(lf, o) && !isinbattle(lf)) {
ok = B_TRUE;
}
} else if (canpickup(lf, o, 1)) {
@ -992,8 +997,6 @@ void aiturn(lifeform_t *lf) {
///////////////////////////////////////////////
// attacks
///////////////////////////////////////////////
target = gettargetlf(lf);
// do we already have a target we are attacking?
if (target) {
@ -1036,7 +1039,6 @@ void aiturn(lifeform_t *lf) {
///////////////////////////////////////////////
// movement
///////////////////////////////////////////////
// do we have a target cell?
f = hasflag(lf->flags, F_TARGETCELL);
if (f) {
@ -1064,6 +1066,9 @@ void aiturn(lifeform_t *lf) {
} else if (haslos(lf, c) && (what->pile->where != c)) {
// if you can see the cell and object isn't there anymore
valid = B_FALSE;
} else if (c->lf && !areenemies(lf, c->lf) && haslos(lf, c) && (getcelldist(lf->cell, c) == 1)) {
// can see a non-enemy on top of the object, and we are adjacent
valid = B_FALSE;
}
}
@ -1091,8 +1096,6 @@ 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. }");
@ -1211,6 +1214,20 @@ void aiturn(lifeform_t *lf) {
}
}
// do we have armour which needs repairing?
if (getskill(lf, SK_ARMOUR) >= PR_SKILLED) {
if (db) dblog(".oO { do i have any armour to repair? }");
// just try to use the ability - it'll fail if we have nothing
// which we can repair.
if (!useability(lf, OT_A_REPAIR, NULL, NULL)) {
if (db) dblog(".oO { yes - done. }");
// success
return;
} else {
if (db) dblog(".oO { no armour to repair. }");
}
}
// pet movement - note that pets will only rest if their
// master is resting. the normal rest code underneath this section
// will never be called.
@ -1823,6 +1840,9 @@ int useitemwithflag(lifeform_t *lf, enum FLAG whichflag) {
if (!operate(lf, o, lf->cell)) {
return B_FALSE;
}
// here on are special cases
} else if (o->type->id == OT_ASHCONCEAL) {
throwat(lf, o, lf->cell);
}
}
}

235
attack.c
View File

@ -39,45 +39,46 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty
if (armour) {
int actualdam;
flag_t *rust;
int ar = 0;
flag_t *rust, *f;
f = hasflag(armour->flags, F_ARMOURRATING);
if (f) {
ar = f->val[0];
}
rust = hasflag(armour->flags, F_RUSTED);
actualdam = dam;
// adjust how much damage to do to armour
if ( ((armour->type->id == OT_FLAKJACKET) && (damtype == DT_PROJECTILE)) ||
(damtype == DT_ACID) ||
hasflag(wep->flags, F_ARMOURPIERCE)) {
hasflag(wep->flags, F_ARMOURPIERCE) ||
rust ) {
// ALL of damage reduction goes towards armour
actualdam = dam;
} else {
switch (getskill(lf, SK_ARMOUR)) {
default:
case PR_INEPT:
actualdam = dam;
break;
case PR_NOVICE: actualdam = pctof(90, dam); break;
case PR_BEGINNER: actualdam = pctof(80, dam); break;
case PR_ADEPT: actualdam = pctof(70, dam); break;
case PR_SKILLED: actualdam = pctof(60, dam); break;
case PR_EXPERT: actualdam = pctof(50, dam); break;
case PR_MASTER: actualdam = pctof(40, dam); break;
// SOME of the damage reduction goes towards the armour
if (ar) {
actualdam -= rnd(0,ar);
limit(&actualdam, 0, NA);
}
limit(&actualdam, 1, NA);
}
// modify for rust
rust = hasflag(armour->flags, F_RUSTED);
if (rust) {
int multiplier = 1;
switch (rust->val[0]) {
case R_RUSTY:
multiplier = 2;
case R_VRUSTY:
multiplier = 6;
multiplier = 3;
case R_TRUSTY:
multiplier = 10;
multiplier = 4;
}
actualdam *= multiplier;
}
// actually apply the damage to the armour
damtaken = takedamage(armour,actualdam, damtype);
}
@ -106,7 +107,7 @@ void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int *
}
int attackcell(lifeform_t *lf, cell_t *c) {
int attackcell(lifeform_t *lf, cell_t *c, int force) {
int validwep[MAXCANDIDATES];
object_t *wep[MAXCANDIDATES];
flag_t *damflag[MAXCANDIDATES], *f;
@ -128,7 +129,7 @@ int attackcell(lifeform_t *lf, cell_t *c) {
// anyone there? if so just attack.
if (c->lf) {
if (isplayer(lf) && !areenemies(lf,c->lf) && (getraceclass(c->lf) != RC_PLANT)) {
if (!force && isplayer(lf) && !areenemies(lf,c->lf) && (getraceclass(c->lf) != RC_PLANT)) {
char ch;
char victimname[BUFLEN];
char buf[BUFLEN];
@ -158,10 +159,30 @@ int attackcell(lifeform_t *lf, cell_t *c) {
// has an impassable object?
o = hasobwithflag(c->obpile, F_IMPASSABLE);
if (o) {
object_t *priwep;
attacktype = AT_OB;
attacktarget = o;
priwep = getweapon(lf);
// confirm ?
if (!force && isplayer(lf) && wepdullable(priwep) && (getiqname(getattr(player, A_IQ), NULL) >= IQ_SMART) ) {
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);
getobname(priwep, wepname, priwep->amt);
sprintf(buf, "Attacking %s might damage your %s. Proceed?", obname, noprefix(wepname));
ch = askchar(buf, "yn","n", B_TRUE);
if (ch == 'n') {
// cancel.
return B_TRUE;
}
};
} else {
// TODO: attack wall?
if (isplayer(lf)) {
msg("There is nothing there to attack!");
}
return B_TRUE;
}
}
@ -335,6 +356,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
char victimname[BUFLEN];
int fatal = B_FALSE;
int deflected = B_FALSE;
int weppassthrough = B_FALSE;
int firstisbackstab = B_FALSE;
int hit = B_FALSE;
int critical = 0;
@ -346,6 +368,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
int isunarmed = B_FALSE;
int aidb = B_FALSE;
flag_t *f;
if (lfhasflag(lf, F_DEBUG)) {
@ -394,10 +417,41 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
}
for (f = lf->flags->first ; f ; f = f->next) {
// 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);
} else if (cansee(player, lf)) {
msg("%s%s attack passes straight through %s!", attackername, getpossessive(attackername), victimname);
}
taketime(lf, getattackspeed(lf));
return B_FALSE;
}
}
// did you hit?
ndam = 0;
hit = rolltohit(lf, victim, wep, &critical);
// weapon passing through ghosts etc?
if (hit) {
if (lfhasflag(victim, F_NONCORPOREAL) &&
!lfhasflag(lf, F_NONCORPOREAL) ) {
// using a magical or blessed weapon? if so you're ok.
if (wep && (ismagical(wep) || isblessed(wep)) ) {
} else {
weppassthrough = B_TRUE;
hit = B_FALSE;
ndam = 0;
}
}
}
// deflection?
if (hit) {
object_t *dwep;
@ -469,6 +523,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) {
dam[0] = (int)((float)dam[0] * getstrdammod(lf));
}
// modify for size
modifyforsize(&dam[0], lf, victim, 5, M_PCT);
// backstab?
if ((damtype[0] == DT_PIERCE) && // using a stabbing weapon
getskill(lf, SK_BACKSTAB) && // able to backstab
@ -519,7 +577,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (ndam > 0) {
flag_t *f;
for (i = 0; i < ndam; i++) {
int reduceamt;
int reduceamt = 0;
int backstab = B_FALSE;
flag_t *rust;
@ -686,8 +744,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
} // end foreach damtype
// special weapon effects
// special weapon effects, as long as you're not doing a heavy blow
if (!lfhasflag(lf, F_HEAVYBLOW)) {
wepeffects(wep->flags, victim->cell, damflag, dam[0]);
}
// other effects
if (!isdead(victim)) {
@ -796,7 +856,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} else { // miss!
if (aidb) dblog(".oO { i missed! }");
// announce it
if (deflected) {
if (weppassthrough) {
if (cansee(player, lf)) {
msg("%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));
}
@ -982,8 +1046,10 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) {
} // end foreach damtype
// special weapon effects
// special weapon effects, as long as you're not doing a heavy blow
if (!lfhasflag(lf, F_HEAVYBLOW)) {
wepeffects(wep->flags, obloc, damflag, dam[0]);
}
if (isunarmed) {
// touch effects
@ -991,14 +1057,9 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) {
} else {
// weapon gets damaged ?
if (wep && (ndam > 0)) {
switch (damtype[0]) {
case DT_PIERCE:
case DT_SLASH:
if (wepdullable(wep)) {
// weapon gets duller
if (rnd(1,2)) makeduller(wep, 1);
break;
default:
break;
}
}
}
@ -1630,19 +1691,83 @@ int isphysicaldam(enum DAMTYPE damtype) {
return B_FALSE;
}
// 'howmuch' is the numerical amount to adjust 'val' by for every size bracket
// difference.
//
// if lf is bigger than victim, ADD howmuch.
// if lf is smaller than victim, SUBTRACT howmuch.
void modifyforsize(int *val, lifeform_t *lf, lifeform_t *victim, int howmuch, enum MODTYPE how) {
enum LFSIZE szlf,szvictim;
assert(val);
szlf = getlfsize(lf);
szvictim = getlfsize(victim);
if (szvictim < szlf) {
// if defender is smaller...
if (how == M_VAL) {
// +howmuch per size difference
*val += (howmuch * (szlf - szvictim));
} else {
// +(howmuch*sizediff)% of original value
*val += (pctof(howmuch * (szlf - szvictim), *val));
}
} else if (szvictim > szlf) {
// if defender is bigger...
if (how == M_VAL) {
// -howmuch per size difference
*val -= (howmuch * (szvictim - szlf));
} else {
// +(howmuch*sizediff)% of original value
*val -= (pctof(howmuch * (szlf - szvictim), *val));
}
}
}
// returns true if we hit
int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) {
int acc,ev;
int gothit;
enum LFSIZE szlf,szvictim;
enum SKILLLEVEL slev;
int myroll;
flag_t *f;
// base 5% critical chance - check this first.
if (critical) {
int critroll;
critroll = rnd(1,100);
// default
*critical = 0;
// modify for lore
if (slev != PR_INEPT) {
myroll += (slev*5); // ie. up to 30% bonus
}
if (critroll >= 95) *critical = 1;
}
f = lfhasflag(lf, F_TRUESTRIKE);
if (f) {
if (f->val[0] > 1) {
f->val[0]--;
} else {
killflag(f);
}
gothit = B_TRUE;
} else if (critical) {
gothit = B_TRUE;
} else {
// actually roll...
acc = getlfaccuracy(lf, wep);
// size difference (penalty for attacking smaller ones)
modifyforsize(&acc, lf, victim, -5, M_VAL);
// easier to hit victims who are prone.
if (isprone(victim)) {
acc += 30;
}
@ -1651,7 +1776,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
slev = getlorelevel(lf, victim->race->raceclass->id);
// modify for defender's evasion
if (isprone(victim)) {
if (isprone(victim) || !cansee(victim, lf)) {
ev = 0;
} else {
ev = getevasion(victim);
@ -1659,29 +1784,6 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
acc -= ev;
// special case
if (lfhasflag(victim, F_NONCORPOREAL) &&
!lfhasflag(lf, F_NONCORPOREAL) ) {
// using a magical or blessed weapon?
if (wep && (ismagical(wep) || isblessed(wep)) ) {
} else {
return B_FALSE; // automatic miss
}
}
// size difference
szlf = getlfsize(lf);
szvictim = getlfsize(victim);
if (szvictim < szlf) {
// if defender is smaller...
// -7% per size difference
acc -= (7 * (szlf - szvictim));
} else if (szvictim > szlf) {
// if defender is bigger...
// +7% per size difference
acc += (7 * (szvictim - szlf));
}
// modify if we can't see the victim
if (!cansee(lf, victim)) {
@ -1698,23 +1800,11 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
acc += 50;
}
// base 5% critical chance
if (critical) {
int critroll;
critroll = rnd(1,100);
// modify for lore
if (slev != PR_INEPT) {
myroll += (slev*5); // ie. up to 30% bonus
}
if (critroll >= 95) *critical = 1;
}
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);
@ -1723,14 +1813,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
// modify for lore
if (myroll <= acc) {
gothit = B_TRUE;
} else {
if (critical && *critical) {
// turn a miss into a hit
gothit = B_TRUE;
} else {
gothit = B_FALSE;
}
}
return gothit;

View File

@ -2,7 +2,7 @@
int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype);
void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int *dam, enum DAMTYPE damtype);
int attackcell(lifeform_t *lf, cell_t *c);
int attackcell(lifeform_t *lf, cell_t *c, int force);
int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag);
int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag);
void confereffects(flagpile_t *fp, lifeform_t *victim);
@ -22,5 +22,6 @@ float getstrdammod(lifeform_t *lf);
//obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag);
int ismeleedam(enum DAMTYPE damtype);
int isphysicaldam(enum DAMTYPE damtype);
void modifyforsize(int *val, lifeform_t *lf, lifeform_t *victim, int howmuch, enum MODTYPE how);
int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical);
void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam);

27
defs.h
View File

@ -54,6 +54,7 @@ enum SKILL {
SK_STEALTH,
SK_SWIMMING,
SK_TECHUSAGE,
SK_THIEVERY,
SK_TRACKING,
SK_TRAPS,
SK_TWOWEAPON,
@ -87,7 +88,7 @@ enum SKILL {
SK_SS_TRANSLOCATION,
SK_SS_WILD,
};
#define MAXSKILLS 46
#define MAXSKILLS 47
// proficiency levels
enum SKILLLEVEL {
@ -240,6 +241,11 @@ enum SENSE {
// it will take to go from 'normal' to 'hungry' etc
#define HUNGERCONST 200
enum MODTYPE {
M_PCT,
M_VAL,
};
// LIMITS
@ -610,8 +616,10 @@ enum RACECLASS {
enum RACE {
R_NONE, R_RANDOM,
R_HUMAN,
// unique monstesr
R_JAILER,
// human monsters
R_HUMAN,
R_BANDIT,
// monsters
R_BEHOLDER,
@ -705,8 +713,9 @@ enum RACE {
R_SKELETON,
R_ZOMBIE,
// special
R_GASCLOUD,
R_DANCINGWEAPON,
R_FLOATINGDISC,
R_GASCLOUD,
};
enum JOB {
@ -935,6 +944,7 @@ enum OBTYPE {
OT_S_ICICLE,
OT_S_WALLOFICE,
// -- gravity
OT_S_TRUESTRIKE,
OT_S_GRAVLOWER,
OT_S_GRAVBOOST,
OT_S_HASTE,
@ -1000,6 +1010,7 @@ enum OBTYPE {
OT_S_WARPWOOD,
OT_S_WATERJET,
// -- summoning
OT_S_FLOATINGDISC,
OT_S_CREATEMONSTER,
OT_S_SUMMONWEAPON,
// -- translocation
@ -1010,6 +1021,7 @@ enum OBTYPE {
OT_S_TELEPORT,
OT_S_TWIDDLE,
// -- wild
OT_S_ALARM,
OT_S_MANASPIKE,
OT_S_DETONATE,
OT_S_ENERGYBOLT,
@ -1033,6 +1045,7 @@ enum OBTYPE {
OT_A_CRUSH,
OT_A_JUMP,
OT_A_RAGE,
OT_A_REPAIR,
OT_A_SPRINT,
OT_A_STINGACID, // need to define dam in f_canwill
OT_A_SUCKBLOOD,
@ -1043,6 +1056,7 @@ enum OBTYPE {
OT_A_INSPECT,
OT_A_HURRICANESTRIKE,
OT_A_POLYREVERT,
OT_A_STEAL,
OT_A_WARCRY, // uses F_NOISETEXT -> N_WARCRY if it is there.
// otherwise 'shouts a blood-curdling war cry'
// wands
@ -1061,6 +1075,8 @@ enum OBTYPE {
OT_WAND_SLOW,
OT_WAND_WEAKNESS,
OT_WAND_WONDER,
// tools - unique
OT_ORBDUNGEONEXIT,
// tools
OT_BLANKET,
OT_BLINDFOLD,
@ -1467,6 +1483,8 @@ enum FLAG {
F_HASBRAND, // has the object mod v0 (ie. OM_FLAMESTRIKE)
F_HOLDCONFER, // gives flag v0+v1 when carried. v2 specifies if it must be id'd.
F_EQUIPCONFER, // gives flag v0+v1 when weilded/worn. v2 specifies if it must be id'd.
F_ACTIVATEPREFIX, // when activated, prefix this objects name with
// text
F_ACTIVATECONFER, // gives flag v0+v1 when activated. v2 specifies if it must be id'd.
F_CRITKNOCKDOWN, // lf knocks down victims on a critical hit
@ -1771,6 +1789,8 @@ enum FLAG {
F_NOFLEE, // lf will not run away
F_ATTACKRANGE, // v0/v1 = min/max celldist to stay away
// from f_targetlf (ie. lf we are attacking)
F_FOLLOWRANGE, // v0/v1 = min/max celldist to stay away
// from pet's master
F_TARGETLF, // lf will attack lfid v0. lastknown x/y is v1/v2
// optional text is last known movement dir.
F_IGNORECELL, // won't accept targetcells of v0=x v1=y
@ -1931,6 +1951,7 @@ enum FLAG {
F_RISEASGHOST, // become a ghost when you die.
F_SEEINDARK, // nightvis range is val0
F_TREMORSENSE, // doesn't need eyes to see, can see in dark with v0
F_TRUESTRIKE, // your attacks ALWAYS hit. turnsleft=v0
F_SEEINVIS, // can see invisible things
F_STABILITY, // doesn't slip over
F_STENCH, // creatures within v0 gain f_nauseated = v1

8
flag.c
View File

@ -36,6 +36,12 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
known = B_KNOWN;
}
if (id == F_INTERRUPTED) {
if (fp->owner == player) {
dblog("player got interrupted");
}
}
if ((id == F_POISONED) && isimmuneto(fp, DT_POISON)) {
return NULL;
}
@ -186,7 +192,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
float pct;
switch (f->id) {
case F_ASLEEP:
stopallspells(f->pile->owner);
stopallspellsexcept(f->pile->owner, OT_S_ALARM, OT_NONE);
break;
case F_NONCORPOREAL:
killflagsofid(f->pile->owner->flags, F_BEINGSTONED);

249
io.c
View File

@ -507,7 +507,7 @@ char askchar(char *prompt, char *validchars, char *def, int showchars) {
return ch;
}
cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail) {
cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail) {
static int startlf = -1;
int finished = B_FALSE;
int moved = B_FALSE;
@ -849,7 +849,11 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange,
wclear(msgwin);
if (subprompt) {
mvwprintw(msgwin, 0, 0, "%s%s", subprompt, buf);
} else {
mvwprintw(msgwin, 0, 0, "%s",buf);
}
wrefresh(msgwin);
// show our line of fire
@ -1443,6 +1447,16 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
}
break;
case F_TRUESTRIKE:
if (isplayer(lf)) { // don't know if monsters get it
if (f->val[0] > 1) {
msg("Your next %d attacks will automatically hit.", f->val[0]);
} else {
msg("Your next attack will automatically hit.");
}
donesomething = B_TRUE;
}
break;
case F_WINDSHIELD:
if (isplayer(lf)) {
msg("You are surrounded by a whirling cyclone!");
@ -1928,6 +1942,9 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
}
break;
case F_TRUESTRIKE:
// no message when you lose this.
break;
case F_WINDSHIELD:
if (isplayer(lf) || cansee(player, lf)) {
msg("%s%s cyclonic shield vanishes.", lfname, getpossessive(lfname));
@ -2804,48 +2821,105 @@ void describeob(object_t *o) {
flag_t *f;
int obknown;
int i;
int throwrange;
cls();
obknown = isknown(o);
// title
getobname(o, buf,o->amt);
wattron(mainwin, A_BOLD);
mvwprintw(mainwin, 0, 0, buf);
wattroff(mainwin, A_BOLD);
// description
getobdesc(o, buf);
mvwprintw(mainwin, 2, 0, buf);
// append masterwork etc onto description
f = hasflag(o->flags, F_MASTERWORK);
if (f && f->known) {
wprintw(mainwin, " It is extremely well crafted.");
}
f = hasflag(o->flags, F_SHODDY);
if (f && f->known) {
wprintw(mainwin, " It is very poorly crafted.");
}
// properties
// weight
y = 4;
if (o->material->id != MT_FOOD) {
mvwprintw(mainwin, y, 0, "%s made from %s.",(o->amt == 1) ? "It is" : "They are", o->material->name); y++;
if (o->material->id == MT_FOOD) {
sprintf(buf, "%s food product%s, ",(o->amt == 1) ? "It is a" : "They are",
(o->amt == 1) ? "" : "s");
} else {
sprintf(buf, "%s made from %s, ",(o->amt == 1) ? "It is" : "They are", o->material->name);
}
if (o->amt == 1) {
char wbuf[BUFLEN];
getweighttext(getobweight(o), wbuf);
sprintf(buf2, "and weighs %s.",wbuf);
strcat(buf, buf2);
} else {
char wbuf[BUFLEN];
char wbuf2[BUFLEN];
getweighttext(getobweight(o), wbuf);
getweighttext(getobunitweight(o), wbuf2);
sprintf(buf2, "and weigh %s (%s each).",wbuf, wbuf2);
strcat(buf, buf2);
}
mvwprintw(mainwin, y, 0, "%s",buf);
y++;
throwrange = getmaxthrowrange(player, o);
if (throwrange >= 1) {
mvwprintw(mainwin, y, 0, " You could throw %s %d metres.",(o->amt == 1) ? "it" : "one", throwrange);
} else {
mvwprintw(mainwin, y, 0, " It is too heavy for you to throw.");
}
y++;
f = hasflag(o->flags, F_THROWMISSILE);
if (f) {
if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT)) {
int dam;
dam = getthrowdam(o);
mvwprintw(mainwin, y, 0, " %s good for throwing [base damage %d].",(o->amt == 1) ? "It is" : "They are", dam);
} else {
mvwprintw(mainwin, y, 0, " %s good for throwing.", (o->amt == 1) ? "It is" : "They are");
}
y++;
}
if (isedible(o)) {
int basenutr;
basenutr = getnutritionbase(o);
mvwprintw(mainwin, y, 0, "%s edible.",(o->amt == 1) ? "It is" : "They are"); y++;
mvwprintw(mainwin, y, 0, "%s %s.",(o->amt == 1) ? "It is" : "They are each", getfillingname(basenutr)); y++;
}
if (o->amt == 1) {
getweighttext(getobweight(o), buf);
mvwprintw(mainwin, y, 0, "It weighs %s.",buf);
} else {
getweighttext(getobweight(o), buf);
getweighttext(getobunitweight(o), buf2);
mvwprintw(mainwin, y, 0, "They weigh %s (%s each).",buf, buf2);
}
mvwprintw(mainwin, y, 0, "%s edible, and %s %s.",
(o->amt == 1) ? "It is" : "They are",
(o->amt == 1) ? "is" : "are each",
getfillingname(basenutr));
y++;
if (hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL)) {
// don't show "it will rot" if it's already rotten (and you know this)
if (isrotting(o) && ( (getiqname(getattr(player, A_IQ), NULL) >= IQ_SMART) || getskill(player, SK_COOKING)) ) {
} else {
mvwprintw(mainwin, y, 0, "%s will decay and go bad over time.", (o->amt == 1) ? "It" : "They" );
y++;
}
}
}
// weapons?
if (o->type->obclass->id == OC_WEAPON) {
int delay;
mvwprintw(mainwin, y, 0, "It is a weapon.");
y++;
if (hasflag(o->flags, F_DAM)) {
int bonus = 0;
f = hasflag(o->flags, F_BONUS);
if (f && f->known) {
// only tell player about bonuses if they are known.!
@ -2865,9 +2939,9 @@ void describeob(object_t *o) {
if (maxdam < 0) maxdam = 0;
if (mindam == maxdam) {
sprintf(buf, "It inflicts %d %s damage",maxdam, getdamname(damtype));
sprintf(buf, " It inflicts %d %s damage",maxdam, getdamname(damtype));
} else {
sprintf(buf, "It inflicts %d-%d %s damage",mindam,maxdam, getdamname(damtype));
sprintf(buf, " It inflicts %d-%d %s damage",mindam,maxdam, getdamname(damtype));
}
//dicetotext(f->val[0], f->val[1], f->val[2], NULL, NULL, dicebuf, NULL);
@ -2879,7 +2953,6 @@ void describeob(object_t *o) {
mvwprintw(mainwin, y, 0, "%s",buf);
y++;
}
}
// other extra damage or effects?
f = hasflag(o->flags, F_ONFIRE);
@ -2891,44 +2964,68 @@ void describeob(object_t *o) {
}
y++;
}
}
delay = 100;
f = hasflag(o->flags, F_OBATTACKDELAY);
if (f) {
delay = f->val[0];
}
mvwprintw(mainwin, y, 0, "Its attack delay is %d%%.",delay - 100);
mvwprintw(mainwin, y, 0, " Its attack delay is %d%%.",delay - 100);
y++;
f = hasflag(o->flags, F_ACCURACY);
if (f) {
int acc;
acc = getobaccuracy(o, NULL);
mvwprintw(mainwin, y, 0, "It has %s accuracy.",getaccuracyname(acc));
mvwprintw(mainwin, y, 0, " It has %s accuracy.",getaccuracyname(acc));
y++;
}
f = hasflag(o->flags, F_DISARMATTACK);
if (f) {
mvwprintw(mainwin, y, 0, "A skilled weilder can disarm opponents with it.");
mvwprintw(mainwin, y, 0, " A skilled weilder can disarm opponents with it.");
y++;
}
f = hasflag(o->flags, F_TRIPATTACK);
if (f) {
mvwprintw(mainwin, y, 0, "A skilled weilder can trip opponents with it.");
mvwprintw(mainwin, y, 0, " A skilled weilder can trip opponents with it.");
y++;
}
f = hasflag(o->flags, F_ARMOURPIERCE);
if (f && f->known) {
mvwprintw(mainwin, y, 0, " Armour will not reduce %s damage.",(o->amt == 1) ? "its" : "their");
y++;
}
}
// damage
if (isarmour(o)) {
f = hasflag(o->flags, F_GOESON);
if (f) {
mvwprintw(mainwin, y, 0, "It is worn %s your %s.",getbodypartequipname(f->val[0]), getbodypartname(f->val[0]));
y++;
sprintf(buf, "It is worn %s your %s, ",getbodypartequipname(f->val[0]), getbodypartname(f->val[0]));
} else {
strcpy(buf, "");
}
f = hasflag(o->flags, F_ARMOURRATING);
if (f) {
mvwprintw(mainwin, y, 0, "It has an Armour Rating of %d.",f->val[0] + getobbonus(o));
if (strlen(buf)) {
sprintf(buf2, "and has an Armour Rating of %d.",f->val[0] + getobbonus(o));
strcat(buf, buf2);
} else {
sprintf(buf, "It has an Armour Rating of %d.",f->val[0] + getobbonus(o));
}
} else {
if (strlen(buf)) {
sprintf(buf2, "and provides no protection.");
strcat(buf, buf2);
}
}
mvwprintw(mainwin, y, 0, "%s",buf);
y++;
f = hasflag(o->flags, F_SCARY);
if (f) {
mvwprintw(mainwin, y, 0, " It may unnerve others when worn.");
y++;
}
}
@ -2946,36 +3043,12 @@ void describeob(object_t *o) {
}
}
f = hasflag(o->flags, F_THROWMISSILE);
if (f) {
if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT)) {
int dam;
dam = getthrowdam(o);
mvwprintw(mainwin, y, 0, "%s good for throwing [base damage %d].",(o->amt == 1) ? "It is" : "They are", dam);
} else {
mvwprintw(mainwin, y, 0, "%s good for throwing.", (o->amt == 1) ? "It is" : "They are");
}
y++;
}
f = hasflag(o->flags, F_ARMOURPIERCE);
if (f && f->known) {
mvwprintw(mainwin, y, 0, "Armour will not reduce %s damage.",(o->amt == 1) ? "its" : "their");
y++;
}
f = hasflag(o->flags, F_PICKLOCKS);
if (f) {
mvwprintw(mainwin, y, 0, "You can use it to pick locks.");
y++;
}
f = hasflag(o->flags, F_SCARY);
if (f) {
mvwprintw(mainwin, y, 0, "It may unnerve others when worn.");
y++;
}
// skip line
y++;
@ -3061,9 +3134,8 @@ void describeob(object_t *o) {
y++;
}
// been made invulnerable ?
if (hasflag(o->type->flags, F_DAMAGABLE) && !hasflag(o->flags, F_DAMAGABLE)) {
if (hasflag(o->type->flags, F_INVULNERABLE) && !hasflag(o->flags, F_DAMAGABLE)) {
mvwprintw(mainwin, y, 0, "It has been rendered invulnerable to most damage.");
y++;
}
@ -3081,16 +3153,6 @@ void describeob(object_t *o) {
// physical properties
f = hasflag(o->flags, F_MASTERWORK);
if (f && f->known) {
mvwprintw(mainwin, y, 0, "It is extremely well crafted.");
y++;
}
f = hasflag(o->flags, F_SHODDY);
if (f && f->known) {
mvwprintw(mainwin, y, 0, "It is very poorly crafted.");
y++;
}
f = hasflag(o->flags, F_ONFIRE);
if (f) {
@ -3311,6 +3373,9 @@ void describeob(object_t *o) {
case F_TREMORSENSE:
mvwprintw(mainwin, y, 0, "%s allows you to 'see' by sensing vibrations around you.", buf); y++;
break;
case F_TRUESTRIKE:
mvwprintw(mainwin, y, 0, "%s makes your attacks automatically hit.", buf); y++;
break;
case F_WINDSHIELD:
mvwprintw(mainwin, y, 0, "%s will surround you with a cyclonic shield.", buf); y++;
break;
@ -3350,7 +3415,6 @@ void describeob(object_t *o) {
y++;
}
// requirements
i = B_FALSE;
for (f = o->flags->first ; f ; f = f->next) {
@ -3499,10 +3563,7 @@ void doattackcell(char dirch) {
f->val[2] = dirch;
}
if (attackcell(player, c)) {
// failed
msg("There is nothing there to attack!");
}
attackcell(player, c, B_FALSE);
}
}
@ -3561,9 +3622,11 @@ void docomms(void) {
char buf[BUFLEN];
char lfname[BUFLEN];
char ch;
enum IQBRACKET iqb;
flag_t *f;
where = askcoords("Talk to who?", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
where = askcoords("Talk to who?", "Talk->", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf && cansee(player, where->lf)) {
lf = where->lf;
}
@ -3576,22 +3639,33 @@ void docomms(void) {
sprintf(buf, "What will you say to %s?",lfname);
initprompt(&prompt, buf);
prompt.maycancel = B_TRUE;
iqb = getiqname(getattr(lf, A_IQ), NULL);
// are they friendly?
if (ispetof(lf, player)) {
if (iqb >= IQ_ANIMAL) {
addchoice(&prompt, 'a', "Attack something", NULL, NULL);
}
if (!isadjacent(lf->cell, player->cell)) {
addchoice(&prompt, 'c', "Come here", NULL, NULL);
}
addchoice(&prompt, 'g', "Go somewhere", NULL, NULL);
if (isadjacent(lf->cell, player->cell) && !lfhasflag(lf, F_NOPACK)) {
addchoice(&prompt, 't', "Trade items with me", NULL, NULL);
}
if (iqb >= IQ_ANIMAL) {
f = isresting(lf);
if (f) {
addchoice(&prompt, 'r', "Stop resting.", NULL, NULL);
} else {
addchoice(&prompt, 'r', "Rest until you are healed.", NULL, NULL);
}
}
} else {
addchoice(&prompt, 'y', "Yeeeeeaaaargh!", NULL, NULL);
}
@ -3602,10 +3676,12 @@ void docomms(void) {
cell_t *c;
lifeform_t *lf2 = NULL;
char lfname2[BUFLEN];
char buf2[BUFLEN];
case 'a':
sprintf(buf, "Tell %s to attack who?",lfname);
c = askcoords(buf, TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && c->lf && cansee(player, c->lf)) {
sprintf(buf2, "%s->Attack->",lfname);
c = askcoords(buf, buf2, TT_MONSTER, lf, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && c->lf && cansee(lf, c->lf)) {
lf2 = c->lf;
}
@ -3629,6 +3705,18 @@ void docomms(void) {
aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME);
}
break;
case 'g':
sprintf(buf, "Tell %s to go where?",lfname);
sprintf(buf2, "%s->Goto->",lfname);
c = askcoords(buf, buf2, TT_NONE, lf, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && cellwalkable(lf, c, NULL) && cansee(lf, c->lf)) {
} else {
msg("Cancelled.");
return;
}
msg("You say \"Go over there!\" to %s.", lfname);
aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME);
break;
case 'n':
msg("Cancelled.");
return;
@ -4549,7 +4637,7 @@ void doenter(lifeform_t *lf) {
}
void doexplain(char *question) {
askcoords(question, TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
askcoords(question, "", TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
restoregamewindows();
msg("Done.");
}
@ -4901,7 +4989,7 @@ void dorest(void) {
void doselguntarget(void) {
object_t *gun;
cell_t *where;
char buf[BUFLEN];
char buf[BUFLEN],buf2[BUFLEN];
char gunname[BUFLEN];
gun = getfirearm(player);
if (!gun) {
@ -4911,7 +4999,8 @@ void doselguntarget(void) {
getobname(gun, gunname, 1);
sprintf(buf, "Aim %s where?",gunname);
where = askcoords(buf, TT_MONSTER, player, UNLIMITED, LOF_NEED, B_TRUE);
sprintf(buf2, "%s->Target->",gunname);
where = askcoords(buf, buf2, TT_MONSTER, player, UNLIMITED, LOF_NEED, B_TRUE);
if (where) {
if (where->lf && haslof(player->cell, where, LOF_NEED, NULL)) {
setguntarget(player, where->lf);
@ -4968,6 +5057,7 @@ void dothrow(obpile_t *op) {
o = askobject(op, "Throw what", NULL, AO_NONE);
if (o) {
int maxdist;
char subprompt[BUFLEN];
cell_t *where;
flag_t *f;
getobname(o, buf, 1);
@ -4983,7 +5073,8 @@ void dothrow(obpile_t *op) {
// ask where to throw it
sprintf(buf2, "Throw %s where?",buf);
where = askcoords(buf2, TT_MONSTER, player, maxdist, LOF_NEED, B_TRUE);
sprintf(subprompt, "%s->Throw->",buf);
where = askcoords(buf2, subprompt, TT_MONSTER, player, maxdist, LOF_NEED, B_TRUE);
if (where) {
cell_t *newwhere = NULL;
@ -8196,6 +8287,11 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, "%s can 'see' by sensing vibrations around %s.", you(lf), you(lf));
y++;
}
f = lfhasknownflag(lf, F_TREMORSENSE);
if (f) {
mvwprintw(mainwin, y, 0, "%s%s attacks will automatically hit.", you(lf), getpossessive(you(lf)));
y++;
}
f = lfhasknownflag(lf, F_WINDSHIELD);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s protected from missiles by a cyclonic shield", you(lf), is(lf));
@ -8326,9 +8422,6 @@ void tombstone(lifeform_t *lf) {
int y;
char *p, *dummy;
gamemode = GM_GAMEOVER;
getplayernamefull(pname);
// clear screen

2
io.h
View File

@ -21,7 +21,7 @@ object_t *askobjectwithflag(obpile_t *op, char *title, int *count, long opts, en
object_t *doaskobject(obpile_t *op, char *title, int *count, int forpickup, int showpoints, long opts, ...);
int askobjectmulti(obpile_t *op, char *prompt, long opts);
char askchar(char *prompt, char *validchars, char *def, int showchars);
cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail);
cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail);
char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def);
vault_t *askvault(char *prompttext);
void centre(WINDOW *win, int y, char *format, ... );

309
lf.c
View File

@ -1912,6 +1912,7 @@ int eat(lifeform_t *lf, object_t *o) {
int fullyeaten = B_FALSE;
flag_t *alreadyeating;
enum HUNGER hlev,posthlev;
int stopeating = B_FALSE;
if (hasflag(o->flags, F_DRINKABLE)) {
drinking = B_TRUE;
@ -2139,20 +2140,16 @@ int eat(lifeform_t *lf, object_t *o) {
}
taketime(lf, amt);
if (fullyeaten) {
// remove object
removeob(o, 1);
} else {
// mark how much we ate
f = hasflag(o->flags, F_EDIBLE);
if (f) {
f->val[2] = (int)(startpcteaten + pcteaten);
}
// special cases even if not fully eaten
if (hasflagval(o->flags, F_CORPSEOF, R_DOGBLINK, NA, NA, NULL)) {
// blink!
dospelleffects(lf, OT_S_BLINK, 1, lf, NULL, NULL, B_UNCURSED, NULL, B_TRUE);
stopeating = B_TRUE;
}
// stop eating if we are full
if (!fullyeaten && (posthlev != hlev) && (posthlev <= H_FULL)) {
int stopeating = B_FALSE;
if (!stopeating && !fullyeaten && (posthlev != hlev) && (posthlev <= H_FULL)) {
if (isplayer(lf)) {
int ch;
more();
@ -2163,9 +2160,20 @@ int eat(lifeform_t *lf, object_t *o) {
} else {
stopeating = B_TRUE;
}
}
if (stopeating) {
killflagsofid(lf->flags, F_EATING);
}
if (fullyeaten) {
// remove object
removeob(o, 1);
} else {
// mark how much we ate
f = hasflag(o->flags, F_EDIBLE);
if (f) {
f->val[2] = (int)(startpcteaten + pcteaten);
}
}
if (isplayer(lf)) {
@ -2187,9 +2195,10 @@ void enhancerandomskill(lifeform_t *lf) {
nposs++;
}
}
if (nposs > 0) {
sel = rnd(0,nposs-1);
giveskill(lf, poss[sel]);
}
}
void enhanceskills(lifeform_t *lf) {
@ -2657,6 +2666,11 @@ int flee(lifeform_t *lf) {
flag_t *f, *nextf;
lifeform_t *fleefrom = NULL;
// mindless?
if (getiqname(getattr(lf, A_IQ), NULL) == IQ_MINDLESS) {
return B_FALSE;
}
// are we fleeing?
for (f = lf->flags->first ; f ; f = nextf) {
nextf = f->next;
@ -3414,6 +3428,8 @@ int getevasion(lifeform_t *lf) {
if (ev < 0) ev = 0;
// modify for blindness
// PLUS if you're blind, your evasion is 0 anyway for anyone
// attacking you.
if (isblind(lf)) {
ev -= 15;
}
@ -4336,15 +4352,19 @@ char *getlfname(lifeform_t *lf, char *buf) {
char *real_getlfname(lifeform_t *lf, char *buf, int usevis) {
char descstring[BUFLEN];
char jobstring[BUFLEN];
char the[5];
char the[6];
job_t *j;
flag_t *f;
// 'the' or 'your' ?
if (ispetof(lf, player)) {
strcpy(the, "your");
if (lfhasflag(lf, F_UNIQUE)) {
strcpy(the, "");
} else {
strcpy(the, "the");
if (ispetof(lf, player)) {
strcpy(the, "your ");
} else {
strcpy(the, "the ");
}
}
// construct description string
@ -4379,9 +4399,9 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis) {
if (wep) {
char obname[BUFLEN];
real_getobname(wep, obname, 1, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_FALSE);
sprintf(buf, "%s %s%s",the,descstring,noprefix(obname));
sprintf(buf, "%s%s%s",the,descstring,noprefix(obname));
} else {
sprintf(buf, "%s %s%s%s",the,descstring,lf->race->name,jobstring);
sprintf(buf, "%s%s%s%s",the,descstring,lf->race->name,jobstring);
}
} else {
char zombiestring[BUFLEN];
@ -4392,7 +4412,7 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis) {
sprintf(zombiestring, " %s", f->text);
}
sprintf(buf, "%s %s%s%s%s",the,descstring,lf->race->name,jobstring,zombiestring);
sprintf(buf, "%s%s%s%s%s",the,descstring,lf->race->name,jobstring,zombiestring);
}
}
}
@ -4408,22 +4428,28 @@ char *real_getlfnamea(lifeform_t *lf, char *buf, int usevis) {
sprintf(buf, "you");
} else {
char buf2[BUFLEN];
char the[5];
char the[6];
real_getlfname(lf, buf2, usevis);
if (lfhasflag(lf, F_UNIQUE)) {
strcpy(the, "");
} else {
if (ispetof(lf, player)) {
strcpy(the, "your");
strcpy(the, "your ");
} else {
if (isvowel(lf->race->name[0])) {
strcpy(the, "an");
strcpy(the, "an ");
} else {
strcpy(the, "a");
strcpy(the, "a ");
}
}
}
sprintf(buf, "%s %s", the, noprefix(buf2));
sprintf(buf, "%s%s", the, noprefix(buf2));
}
return buf;
}
@ -5127,8 +5153,14 @@ void getwantdistance(lifeform_t *lf, int *min, int *max, int attacking) {
*max = f->val[1];
}
} else {
// default - stay with 1-3 cells
*min = 1;
*max = 3;
f = lfhasflag(lf, F_FOLLOWRANGE);
if (f) {
*min = f->val[0];
*max = f->val[1];
}
}
}
@ -5150,8 +5182,8 @@ object_t *getweapon(lifeform_t *lf) {
long getxpforlev(int level) {
long needxp = 0;
// 2.8
float multiplier = 10;
float constant = 3.1;
float multiplier = 13;
float constant = 2.8;
// no xp needed for level 1
/*
@ -5427,11 +5459,14 @@ int giveskill(lifeform_t *lf, enum SKILL id) {
if (id == SK_ATHLETICS) {
newf = addflag(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL);
newf->lifetime = FROMJOB;
} else if (id == SK_ATHLETICS) {
} else if (id == SK_COOKING) {
makeknown(OT_POT_WATER);
} else if (id == SK_LORE_ARCANA) {
newf = addflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL);
newf->lifetime = FROMJOB;
} else if (id == SK_THIEVERY) {
newf = addflag(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL);
newf->lifetime = FROMJOB;
} else if (id == SK_TRAPS) {
newf = addflag(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL);
newf->lifetime = FROMJOB;
@ -5447,6 +5482,11 @@ int giveskill(lifeform_t *lf, enum SKILL id) {
newf = addflag(lf->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL);
newf->lifetime = FROMJOB;
}
} else if (id == SK_ARMOUR) {
if (f->val[1] == PR_SKILLED) {
newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
newf->lifetime = FROMJOB;
}
} else if (id == SK_CARTOGRAPHY) {
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
if (f->val[1] == PR_NOVICE) {
@ -5548,6 +5588,20 @@ int giveskill(lifeform_t *lf, enum SKILL id) {
}
}
}
} else if (id == SK_THIEVERY) {
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
if (f->val[1] == PR_BEGINNER) {
msg("Your accuracy penalty when stealing is reduced.");
} else if (f->val[1] == PR_ADEPT) {
msg("You can now steal specific items.");
} else if (f->val[1] == PR_SKILLED) {
msg("You can now steal heavy items.");
} else if (f->val[1] == PR_EXPERT) {
msg("You can now steal multiple items.");
} else if (f->val[1] == PR_MASTER) {
msg("You can now steal equipped items.");
}
}
} else if (id == SK_TRACKING) {
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
if (f->val[1] == PR_NOVICE) {
@ -6612,6 +6666,7 @@ void initjobs(void) {
addjob(J_PIRATE, "Pirate");
// stats
addflag(lastjob->flags, F_STARTATT, A_STR, NA, NA, "8-15");
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
addflag(lastjob->flags, F_STARTATT, A_CON, CN_HEALTHY, NA, NULL);
// abilities
@ -6643,6 +6698,8 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LORE_ARCANA, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_THIEVERY, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_TRACKING, NA, NA, NULL);
addjob(J_ROGUE, "Rogue");
@ -6653,6 +6710,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "dagger");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "50-100 gold coins");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "5 lockpicks");
addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_BEGINNER, NA, NULL);
@ -6661,6 +6719,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_BEGINNER, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_SPOTHIDDEN, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_THIEVERY, PR_BEGINNER, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_BEGINNER, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
@ -6764,6 +6823,37 @@ void initrace(void) {
addraceclass(RC_SLIME, "slime", "slimes", SK_NONE);
addraceclass(RC_UNDEAD, "undead", "the undead", SK_LORE_UNDEAD);
// unique monsters
addrace(R_JAILER, "Jimbo", 110, '@', C_MAGENTA, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, NA, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 5, 2, NA, NULL);
//addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
//addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d4");
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "11-13");
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_STUPID, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, CN_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "50-100 gold coins");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "+2 halberd");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "gas mask");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "great armour");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "good armour");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "good armour");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "armour");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "dungeon exit orb");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "concealing powder");
addflag(lastrace->flags, F_FLEEONHPPCT, 40, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_POLEARMS, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_ARMOUR, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, 2, 2, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_HURRICANESTRIKE, 2, 2, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_RAGE, 20, 20, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
// races / monsters
addrace(R_HUMAN, "human", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
@ -6784,7 +6874,6 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL);
// TODO: humans start with a random job sometimes?
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
// addflag(lastrace->flags, F_RESTHEALMPAMT, 1, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
// human monsters...
@ -7833,7 +7922,7 @@ void initrace(void) {
addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 1, 0, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
@ -8104,6 +8193,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "0d1+4");
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addrace(R_ANTS, "giant soldier ant", 25, 'a', C_BROWN, MT_FLESH, RC_ANIMAL);
@ -8127,6 +8217,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANWILL, OT_A_STINGACID, NA, NA, "dam:1d6+3;needgrab:1;");
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "giant worker ant");
addrace(R_ANTLION, "giant antlion", 30, 'a', C_YELLOW, MT_FLESH, RC_ANIMAL);
lastrace->baseid = R_ANT;
@ -8149,6 +8240,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:2d4;");
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars");
addrace(R_DOGBLINK, "blink dog", 35, 'd', C_YELLOW, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_NUMAPPEAR, 2, 8, NA, "");
@ -8961,6 +9053,31 @@ void initrace(void) {
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addrace(R_FLOATINGDISC, "floating disc", 0, '_', C_BOLDGREEN, MT_METAL, RC_OTHER);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_HITDICE, 1, NA, NA, "");
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
addflag(lastrace->flags, F_FOLLOWRANGE, 1, 1, NA, NULL); // stay right next to master
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_BODY, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
}
int isairborne(lifeform_t *lf) {
@ -9041,6 +9158,10 @@ int ischarmable(lifeform_t *lf) {
reason = E_DRUNK;
return B_FALSE;
}
if (hasflag(lf->flags, F_UNIQUE)) {
reason = E_NOEFFECT; // generic error
return B_FALSE;
}
return B_TRUE;
}
@ -9759,7 +9880,11 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) {
// adjust for lifeform material
//adjustdammaterial(amt, damtype, getlfmaterial(lf));
if (*amt < 0) *amt = 0;
if (isdrunk(lf)) {
*amt -= rnd(0,3);
}
limit(amt, 0, NA);
}
void makepeaceful(lifeform_t *who) {
@ -10790,15 +10915,23 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete
if ((l != noisemaker) && (l->cell)) {
int difficulty;
int lbonus;
//if (canhear(l, c) && haslos(l, c)) {
// listen check difficulty is based on sound distance vs max hearing distance
difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20);
// listen bonus is the sound volume
// listen bonus is the sound volume
if (lfhasflag(l, F_ASLEEP)) {
lbonus = 0;
} else {
lbonus = volume;
}
// skillcheck to hear this
if (canhear(l, c) &&
(haslos(l, c) ||
((dist <= sounddist) && skillcheck(l, SC_LISTEN, difficulty, volume)))) {
((dist <= sounddist) && skillcheck(l, SC_LISTEN, difficulty, lbonus)))) {
flag_t *f;
// announce?
if (isplayer(l) && !lfhasflag(l, F_ASLEEP)) {
@ -10894,12 +11027,17 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete
}
killflag(f);
} else {
// ie resting on purpose via 'r'
// ie resting on purpose via 'R'
// only wake up if the sound if very close
if (getcelldist(c, l->cell) == 1) {
//if (getcelldist(c, l->cell) == 1) {
if (volume >= getcelldist(c, l->cell)) {
// wake up!
if (isplayer(l)) {
msg("A nearby noise awakens you!");
char wakenoise[BUFLEN];
strcpy(wakenoise, text);
wakenoise[strlen(wakenoise)-1] = '\0'; // omit punctuation
//msg("A nearby noise awakens you!");
msg("The sound of %s awakens you!", wakenoise);
rv = B_TRUE;
}
killflag(f);
@ -11959,7 +12097,7 @@ void setlastdam(lifeform_t *lf, char *buf) {
}
void initskills(void) {
addskill(SK_ARMOUR, "Armour", "Helps maintain armour, reducing evasion penalties and armour damage.");
addskill(SK_ARMOUR, "Armour", "Lets you repair armour, and reduces evasion penalties from armour.");
addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery.");
addskill(SK_BACKSTAB, "Backstab", "Lets you inflict massive damage with stabs when unseen.");
addskill(SK_CARTOGRAPHY, "Cartography", "Your ability to create and interpret maps.");
@ -11975,6 +12113,7 @@ void initskills(void) {
addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.");
addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water.");
addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items.");
addskill(SK_THIEVERY, "Thievery", "Your ability to pick pockets and steal items.");
addskill(SK_TRACKING, "Tracking", "Allows you to track enemies by their footprints.");
addskill(SK_TRAPS, "Traps", "Affects your ability to locate and disarm traps.");
addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once.");
@ -12504,6 +12643,38 @@ void stopsprinting(lifeform_t *lf) {
}
// very much like addmonster(), but announce that it appears
// and make it worth zero xp.
lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, int randomjobsok, job_t *forcejob, int lifetime, int wantfriendly) {
lifeform_t *newlf = NULL;
char buf[BUFLEN];
newlf = addmonster(c, rid, randomjobsok, 1, B_FALSE, NULL);
if (newlf) {
// assign job if required
if (forcejob) {
givejob(newlf, forcejob->id);
}
if (haslos(player, c)) {
//char *newbuf;
getlfnamea(newlf, buf);
capitalise(buf);
msg("%s appears!", buf);
}
// summoned
addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL);
if (wantfriendly) {
addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL);
if (areallies(player, caster)) {
makefriendly(newlf, PERMENANT);
}
}
// not worth any xp
killflagsofid(newlf->flags, F_XPVAL);
addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL);
}
return newlf;
}
// if this object is ammo, and we are using a gun
// with no ammo, then equip it.
int testammo(lifeform_t *lf, object_t *o) {
@ -13014,28 +13185,8 @@ void turneffectslf(lifeform_t *lf) {
}
if (willvanish) {
if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s%s vanishes.",
(creator == player) ? "Your " : "",
(creator == player) ? noprefix(lfname) : lfname
);
}
// all objects vanish
while (lf->pack->first) {
killob(lf->pack->first);
}
// lf dies.
lf->hp = 0;
addflag(lf->flags, F_DEAD, B_TRUE, NA, NA, NULL);
addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
// puff
addob(lf->cell->obpile, "puff of smoke");
unsummon(lf, B_TRUE);
}
}
if (isdead(lf)) return;
@ -13056,7 +13207,11 @@ void turneffectslf(lifeform_t *lf) {
// chance of losing hp
if (rnd(1,100) <= getpoisondamchance(f->val[0])) {
char buf[BUFLEN];
if (!hasflag(lf->flags, F_ASLEEP)) {
flag_t *asleep;
// being asleep helps.
asleep = hasflag(lf->flags, F_ASLEEP);
if (!asleep) {
if (isplayer(lf)) {
msg("You %s violently.", getpoisondamverb(f->val[0]));
} else if (cansee(player, lf)) {
@ -13070,14 +13225,13 @@ void turneffectslf(lifeform_t *lf) {
sprintf(buf, "poisoning^from %s",f->text);
losehp(lf, f->val[1], DT_DIRECT, NULL, buf);
if (!hasflag(lf->flags, F_ASLEEP)) {
if (!asleep) {
if (poisoncausesvomit(f->val[0])) {
addob(lf->cell->obpile, "pool of vomit");
}
}
loseconcentration(lf);
}
}
// extra effects
if (f->val[0] == P_COLD) {
@ -13425,6 +13579,37 @@ int touch(lifeform_t *lf, object_t *o) {
return B_FALSE;
}
void unsummon(lifeform_t *lf, int vanishobs) {
lifeform_t *creator = NULL;
flag_t *f;
f = hasflag(lf->flags, F_SUMMONEDBY);
if (f) {
creator = findlf(NULL, f->val[0]);
}
if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s%s vanishes.",
(creator && (creator == player)) ? "Your " : "",
(creator && (creator == player)) ? noprefix(lfname) : lfname
);
}
if (vanishobs) {
// all objects vanish
while (lf->pack->first) {
killob(lf->pack->first);
}
}
lf->hp = 0;
addflag(lf->flags, F_DEAD, B_TRUE, NA, NA, NULL);
addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
addob(lf->cell->obpile, "puff of smoke");
}
int unweild(lifeform_t *lf, object_t *o) {
flag_t *f;
char obname[BUFLEN];

2
lf.h
View File

@ -284,6 +284,7 @@ void stopeating(lifeform_t *lf);
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 takeoff(lifeform_t *lf, object_t *o);
void taketime(lifeform_t *lf, long howlong);
@ -292,6 +293,7 @@ void timeeffectslf(lifeform_t *lf);
void turneffectslf(lifeform_t *lf);
int touch(lifeform_t *lf, object_t *o);
void unpoison(lifeform_t *lf);
void unsummon(lifeform_t *lf, int vanishobs);
int unweild(lifeform_t *lf, object_t *o);
int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where);
int useringofmiracles(lifeform_t *lf, int charges);

9
map.c
View File

@ -208,7 +208,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
// did we find one?
if (!adjcell) break;
newlf = addlf(c, r->id, getrandommonlevel(r, adjcell->map));
newlf = addlf(adjcell, r->id, getrandommonlevel(r, adjcell->map));
if (!newlf) {
break;
}
@ -523,8 +523,8 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in
int sel;
d = dodoor[i];
getroomedge(map, roomid, minx, miny, maxx, maxy, d, cell, &ncells, B_TRUE);
if (ncells) {
sel = rnd(0,ncells-1);
if (rnd(1,100) <= doorpct) {
makedoor(cell[sel]);
doorsadded++;
@ -534,6 +534,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in
}
}
}
}
if (db) dblog("autodoors() added %d doors to roomid %d", doorsadded, roomid);
return doorsadded;
}
@ -1465,8 +1466,8 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
}
numobsmin = 0;
//numobsmax = MAXOF(roomw[i],roomh[i]) / 2;
numobsmax = MAXOF(roomw[i],roomh[i]);
numobsmax = MAXOF(roomw[i],roomh[i]) / 2;
//numobsmax = MAXOF(roomw[i],roomh[i]);
// then objects/monsters
if (numobsmax <= numobsmin) {

30
move.c
View File

@ -250,7 +250,8 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
// ok
} else if (cell->lf && (cell->lf != lf)) { // someone (else) in the wall?
if (error) *error = E_LFINWAY; // ok but still set reason
return B_FALSE;
//return B_FALSE;
// ok
} else {
if (error) *error = E_WALLINWAY;
return B_FALSE;
@ -623,6 +624,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
}
if (reason != E_OK) {
char buf[BUFLEN];
char thing[BUFLEN];
cell_t *newcell;
newcell = getcellindir(lf->cell, dir);
// failed to move
@ -636,9 +638,16 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
}
// fall through
case E_WALLINWAY:
if (seen) msg("%s slam%s into a %s!",lfname,isplayer(lf) ? "" : "s",
newcell ? newcell->type->name : "wall");
sprintf(buf, "slamming into a %s", newcell ? newcell->type->name : "wall");
case E_OBINWAY:
case E_DOORINWAY:
if (reason == E_WALLINWAY) {
if (newcell) strcpy(thing, newcell->type->name);
else strcpy(thing, "wall");
} else { // ie door or object
getobname(rdata, thing, 1);
}
if (seen) msg("%s slam%s into %s!",lfname,isplayer(lf) ? "" : "s", thing);
sprintf(buf, "slamming into %s", thing);
losehp(lf, rnd(1,6), DT_BASH, pusher, buf);
// stop moving
i = howfar;
@ -1054,6 +1063,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
if ((gamemode == GM_GAMESTARTED)) {
for (l = newcell->map->lf ; l ; l = l->next) {
if (l != lf) {
flag_t *alarm;
if (haslos(l, newcell)) {
int dointerrupt = B_FALSE;
@ -1083,6 +1093,16 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
interrupt(l);
}
}
alarm = hasactivespell(l, OT_S_ALARM);
if (alarm && areenemies(lf, l) && haslof(lf->cell, l->cell, LOF_WALLSTOP, NULL) ) {
// in range of alarm? range is 3 * spell power cells.
if (getcelldist(lf->cell, l->cell) <= (alarm->val[2]*3)) {
// alarm goes off
noise(l->cell, NULL, 50, "a blaring siren!", NULL);
killflag(alarm);
}
}
}
}
}
@ -2125,7 +2145,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
}
} else {
// attack!
return attackcell(lf, cell);
return attackcell(lf, cell, B_FALSE);
}
break;
case E_CANTMOVE:

View File

@ -465,6 +465,7 @@ void checkdeath(void) {
void checkendgame(void) {
if (!player->alive) {
gamemode = GM_GAMEOVER;
gameover = B_TRUE;
}
}

358
objects.c
View File

@ -2763,67 +2763,19 @@ void genhiddennames(void) {
for (ot = objecttype ; ot ; ot = ot->next) {
f = hasflag(ot->flags, F_HASHIDDENNAME);
if (f) {
int n;
int gotcolour = B_FALSE;
char *thisname;
if (strlen(f->text)) {
thisname = strdup(f->text);
} else {
thisname = genhiddenname(ot->obclass->id);
}
addknowledge(ot->id, thisname, B_UNKNOWN);
// some descriptions confer other effecst too...
if (strstr(thisname, "glowing")) {
addflag(ot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
} else if (strstr(thisname, "flourescent")) {
addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
} else if (strstr(thisname, "luminous")) {
addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
}
// set colour based on hiddenname
for (n = 0; strlen(colour[n].name); n++) {
if (strstr(thisname, colour[n].name)) {
flag_t *gf;
gf = hasflag(ot->flags, F_GLYPH);
if (gf) {
gf->val[0] = colour[n].col;
} else {
char buf[2];
buf[0] = ot->obclass->glyph.ch;
buf[1] = '\0';
addflag(ot->flags, F_GLYPH, colour[n].col, NA, NA, buf);
gotcolour = B_TRUE;
//dblog("assigning colour %s to %s (%s)",colour[n].name, thisname, ot->name);
break;
}
}
}
if (!gotcolour) {
for (n = 0; strlen(gemtype[n].name); n++) {
if (strstr(thisname, gemtype[n].name)) {
flag_t *gf;
gf = hasflag(ot->flags, F_GLYPH);
if (gf) {
gf->val[0] = gemtype[n].col;
} else {
char buf[2];
buf[0] = ot->obclass->glyph.ch;
buf[1] = '\0';
addflag(ot->flags, F_GLYPH, gemtype[n].col, NA, NA, buf);
break;
}
}
}
}
sethiddenname(ot, thisname);
free(thisname);
}
}
}
// get the first hidden name for this objectclass
char *genhiddenname(enum OBCLASS id) {
hiddenname_t *hn;
@ -3419,23 +3371,23 @@ int getmaterialvalue(enum MATERIAL mat) {
int getmaxthrowrange(lifeform_t *lf, object_t *o) {
int maxdist;
float strmod;
float modobweight;
float str;
float obweight;
// adjust for lifeform strength
// mighty = div by 10
// this will give us a number in range -44 - 50
strmod = getstatmod(lf, A_STR);
// this will give us a number in range 1 - 10
strmod /= 5;
if (strmod < 1) strmod = 1;
// mighty = can throw 1kilo 10 metres
// mighty = can throw 10kilos 1 metre
// 11 - kilos = distance
modobweight = getobunitweight(o) / 2;
modobweight /= strmod;
str = getattr(lf, A_STR); // ie. 1 - 18
str -= 2;
limitf(&str, 1, NA); // ie. 1 to 16
maxdist = 10 - modobweight;
obweight = getobunitweight(o);
if (maxdist < 0) maxdist = 0;
maxdist = ceil(str - obweight);
if (maxdist < 1) maxdist = 0;
return maxdist;
}
@ -3669,10 +3621,12 @@ char *getobextrainfo(object_t *o, char *buf) {
}
// activated
if (!hasflag(o->flags, F_ACTIVATEPREFIX)) {
f = hasflag(o->flags, F_ACTIVATED);
if (f) {
strcat(buf, " [activated]");
}
}
return buf;
}
@ -3795,10 +3749,15 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
} else if (o->type->id == OT_WATERDEEP) {
sprintf(basename, "%s water", getwaterdepthname(getobdepth(o, player)));
} else {
strcpy(basename, "");
if (isactivated(o) && hasflag(o->flags, F_ACTIVATEPREFIX)) {
f = hasflag(o->flags, F_ACTIVATEPREFIX);
sprintf(basename, "%s ", f->text);
}
if (showall) {
strcpy(basename,o->type->name);
strcat(basename,o->type->name);
} else {
strcpy(basename,gethiddenname(o));
strcat(basename,gethiddenname(o));
}
}
@ -4927,8 +4886,6 @@ void initobjects(void) {
addhiddenname(OC_SCROLL, "scroll titled YES");
addhiddenname(OC_SCROLL, "scroll titled ZAREL NOR");
addhiddenname(OC_POTION, "clear potion");
for (n = 0; strlen(colour[n].name); n++) {
char buf[BUFLEN];
// add it without an adjective
@ -5092,6 +5049,7 @@ void initobjects(void) {
addmaterial(MT_CLOTH, "cloth", 3);
addflag(lastmaterial->flags, F_FLAMMABLE, 3, NA, NA, NULL);
addflag(lastmaterial->flags, F_CANGETWET, B_TRUE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL);
addmaterial(MT_FOOD, "food", 3);
addmaterial(MT_PLASTIC, "plastic", 3);
addflag(lastmaterial->flags, F_HARD, B_TRUE, NA, NA, NULL);
@ -5102,6 +5060,7 @@ void initobjects(void) {
addmaterial(MT_RUBBER, "rubber", 4);
addmaterial(MT_LEATHER, "leather", 4);
addflag(lastmaterial->flags, F_CANGETWET, B_TRUE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL);
addmaterial(MT_BONE, "bone", 5);
addflag(lastmaterial->flags, F_HARD, B_TRUE, NA, NA, NULL);
addmaterial(MT_OIL, "oil", 5);
@ -5133,6 +5092,7 @@ void initobjects(void) {
addflag(lastmaterial->flags, F_DTRESIST, DT_PROJECTILE, NA, NA, NULL);
addmaterial(MT_GLASS, "glass", 13);
addflag(lastmaterial->flags, F_HARD, B_TRUE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTVULN, DT_BASH, NA, NA, NULL);
addmaterial(MT_GOLD, "gold", 16);
addflag(lastmaterial->flags, F_HARD, B_TRUE, NA, NA, NULL);
//addmaterial(MT_GOLD, "gold", 16);
@ -5477,6 +5437,7 @@ void initobjects(void) {
addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pile of ash");
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some ash");
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_ASHSLEEP, "pile of sleeping powder", "A pile of ash.", MT_STONE, 0.1, OC_ROCK);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
@ -5625,6 +5586,8 @@ void initobjects(void) {
addot(OT_POT_WATER, "potion of water", "Plain, regular water.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small puddle of water");
sethiddenname(lastot, "clear potion");
addot(OT_POT_HEALING, "potion of healing", "Restores 10-20 health to whoever drinks it.", MT_GLASS, 1, OC_POTION);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL);
@ -6262,6 +6225,12 @@ void initobjects(void) {
///////////////////
// gravity
///////////////////
// l1
addot(OT_S_TRUESTRIKE, "true strike", "Gives the target unerring accuracy, making their attacks always hit.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL);
// l3
addot(OT_S_GRAVLOWER, "lessen gravity", "Causes the caster to fall very slowly.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
@ -6425,6 +6394,12 @@ void initobjects(void) {
// summoning
///////////////////
// l1
addot(OT_S_FLOATINGDISC, "floating disc", "Creates a disc of energy to carry your equipment.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SUMMONWEAPON, "summon weapon", "Summons a blade of pure magic into your hands. Deals 1-power damage.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
@ -6493,6 +6468,11 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addot(OT_S_ALARM, "alarm", "Creates a passive alarm which goes off when an enemy is nearby.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
// l3
addot(OT_S_ENERGYBLAST, "energy blast", "Causes a ring of energy to expand from the caster (radius based on power), causing 2-6 damage to anything in sight.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
@ -6573,9 +6553,14 @@ void initobjects(void) {
addot(OT_A_RAGE, "rage", "Enter a state of berzerker rage, gaining attack and defence bonuses.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addot(OT_A_REPAIR, "repair armour", "Repair damage done to your armour.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_SPRINT, "sprint", "You can run at high speed over short distances.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addot(OT_A_STEAL, "steal", "Try to steal an item from an enemy.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addot(OT_A_STINGACID, "sting (acid)", "You can sting your enemies.", MT_NOTHING, 0, OC_ABILITY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
@ -6670,6 +6655,12 @@ void initobjects(void) {
addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// tools - unique
addot(OT_ORBDUNGEONEXIT, "dungeon exit orb", "When operated, this magical key will disable the barriers around the dungeon exit stairs.", MT_STONE, 2, OC_TOOLS);
addflag(lastot->flags, F_GLYPH, C_MAGENTA, NA, NA, "[");
addflag(lastot->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
// tools
addot(OT_BLANKET, "wool blanket", "A warm wool blanket for those cold winter nights.", MT_CLOTH, 2, OC_TOOLS);
addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL);
@ -6691,6 +6682,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit");
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 1, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 1, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 5, 10, NA, NULL);
@ -6751,6 +6743,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit");
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 2, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 50, 100, NA, NULL);
@ -7762,7 +7755,7 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_UNARMED, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
// this one if for the pirate
// this one is for the pirate
addot(OT_HOOKHAND, "hook", "hook", MT_METAL, 0, OC_WEAPON);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
@ -7879,7 +7872,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_JAVELIN, "javelin", "A long, sharp missile weapon.", MT_METAL, 6.5, OC_MISSILE);
addot(OT_JAVELIN, "javelin", "A long, sharp missile weapon.", MT_METAL, 6, OC_MISSILE);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_MISSILEDAM, 3, NA, NA, "");
@ -7888,7 +7881,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHP, 3, 3, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.5, OC_MISSILE);
addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.25, OC_MISSILE);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
@ -7898,7 +7891,7 @@ void initobjects(void) {
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 1, OC_MISSILE);
addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 0.5, OC_MISSILE);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
@ -7915,7 +7908,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addot(OT_RUBBERBULLET, "rubber bullet", "A rubber gun bullet - does not do much damage.", MT_STONE, 0.1, OC_MISSILE);
addot(OT_RUBBERBULLET, "rubber bullet", "A rubber gun bullet - does not do much damage.", MT_STONE, 0.05, OC_MISSILE);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
@ -7926,20 +7919,20 @@ void initobjects(void) {
// axes
addot(OT_AXE, "axe", "A short pole with a heavy, wedge-shaped blade for chopping.", MT_METAL, 4, OC_WEAPON);
addot(OT_AXE, "axe", "A short pole with a heavy, wedge-shaped blade for chopping.", MT_METAL, 5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 5, OC_WEAPON);
addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 8, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+1");
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addot(OT_GREATAXE, "greataxe", "An enormous axe made designed for combat.", MT_METAL, 8, OC_WEAPON);
addot(OT_GREATAXE, "greataxe", "An enormous axe made designed for combat.", MT_METAL, 10, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d9+1");
@ -7947,14 +7940,14 @@ void initobjects(void) {
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 16, NA, NULL);
addot(OT_HANDAXE, "hand axe", "A fast one-handed axe, ideal for throwing.", MT_METAL, 2, OC_WEAPON);
addot(OT_HANDAXE, "hand axe", "A fast one-handed axe, ideal for throwing.", MT_METAL, 2.5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d7");
addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addot(OT_WARAXE, "war axe", "An axe made for combat.", MT_METAL, 4, OC_WEAPON);
addot(OT_WARAXE, "war axe", "An axe made for combat.", MT_METAL, 7, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d7+1");
addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL);
@ -7980,7 +7973,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addot(OT_KNIFE, "knife", "A moderately sharp stabbing tool.", MT_METAL, 1, OC_WEAPON);
addot(OT_KNIFE, "knife", "A moderately sharp stabbing tool.", MT_METAL, 0.5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d3");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
@ -7997,32 +7990,32 @@ void initobjects(void) {
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addot(OT_QUICKBLADE, "quickblade", "A short blade of exceptional quality, which somehow allows its bearer to attack faster.", MT_METAL, 1, OC_WEAPON);
addot(OT_QUICKBLADE, "quickblade", "A short blade of exceptional quality, which somehow allows its bearer to attack faster.", MT_METAL, 3.0, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 75, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addot(OT_RAPIER, "rapier", "A long, narrow French sword lacking a cutting edge. Made for stabbing.", MT_METAL, 2.5, OC_WEAPON);
addot(OT_RAPIER, "rapier", "A long, narrow French sword lacking a cutting edge. Made for stabbing.", MT_METAL, 3.5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d8");
addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL);
addot(OT_SAI, "sai", "A dagger with two long prongs on either side, made to trap opponents' weapons.", MT_METAL, 1, OC_WEAPON);
addot(OT_SAI, "sai", "A dagger with two long prongs on either side, made to trap opponents' weapons.", MT_METAL, 1.5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 81, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4");
addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 10, NA, NULL);
addot(OT_SHORTSWORD, "short sword", "A short blade for fighting. Better for stabbing.", MT_METAL, 2.5, OC_WEAPON);
addot(OT_SHORTSWORD, "short sword", "A short blade for fighting. Better for stabbing.", MT_METAL, 4, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL);
addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 0.5, OC_WEAPON);
addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 1, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 60, NA, NA, NULL);
@ -8037,7 +8030,7 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL);
// long blades
addot(OT_FALCHION, "falchion", "A single-edged heavy sword made for chopping.", MT_METAL, 4.5, OC_WEAPON);
addot(OT_FALCHION, "falchion", "A single-edged heavy sword made for chopping.", MT_METAL, 6.5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 61, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+3");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
@ -8051,26 +8044,26 @@ void initobjects(void) {
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addot(OT_LONGSWORD, "longsword", "Standard issue long slashing weapon.", MT_METAL, 3, OC_WEAPON);
addot(OT_LONGSWORD, "longsword", "Standard issue long slashing weapon.", MT_METAL, 5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d8+4");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL);
addot(OT_ORNSWORD, "ornamental sword", "A gleaming (but quite blunt) blade.", MT_METAL, 2, OC_WEAPON);
addot(OT_ORNSWORD, "ornamental sword", "A gleaming (but quite blunt) blade.", MT_METAL, 6, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addot(OT_SCIMITAR, "scimitar", "A fast, sharp, curved blade.", MT_METAL, 2, OC_WEAPON);
addot(OT_SCIMITAR, "scimitar", "A fast, sharp, curved blade.", MT_METAL, 5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 90, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 8, NA, NULL);
addot(OT_CUTLASS, "cutlass", "An accurate, light-weight pirate blade.", MT_METAL, 1, OC_WEAPON);
addot(OT_CUTLASS, "cutlass", "An accurate, light-weight pirate blade.", MT_METAL, 4, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7");
addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL);
@ -8078,7 +8071,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ATTREQ, A_STR, 8, NA, NULL);
// polearms
addot(OT_GLAIVE, "glaive", "A single-edged blade attached to a long pole.", MT_METAL, 4, OC_WEAPON);
addot(OT_GLAIVE, "glaive", "A single-edged blade attached to a long pole.", MT_METAL, 10, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7+3");
@ -8086,7 +8079,7 @@ void initobjects(void) {
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addot(OT_GUISARME, "guisarme", "A hooked polearm, made by attaching a hook to a spear shaft.", MT_METAL, 4, OC_WEAPON);
addot(OT_GUISARME, "guisarme", "A hooked polearm, made by attaching a hook to a spear shaft.", MT_METAL, 10, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL);
addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
@ -8096,7 +8089,7 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL);
addot(OT_HALBERD, "halberd", "A spiked axe blade mounted on a long shaft, with a hook on the back.", MT_METAL, 4, OC_WEAPON);
addot(OT_HALBERD, "halberd", "A spiked axe blade mounted on a long shaft, with a hook on the back.", MT_METAL, 12, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 71, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL);
addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL);
@ -8106,7 +8099,7 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL);
addot(OT_LANCE, "lance", "A pole weapon designed for use while mounted.", MT_METAL, 4, OC_WEAPON);
addot(OT_LANCE, "lance", "A pole weapon designed for use while mounted.", MT_METAL, 12, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL);
@ -8114,7 +8107,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addot(OT_RANSEUR, "ranseur", "A long spear and cross hilt, resembling a pole-mounted sai. Good for disarming.", MT_METAL, 1, OC_WEAPON);
addot(OT_RANSEUR, "ranseur", "A long spear and cross hilt, resembling a pole-mounted sai. Good for disarming.", MT_METAL, 12, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL);
addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
@ -8124,14 +8117,14 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL);
addot(OT_SCYTHE, "scythe", "An agricultural hand tool for mowing grass, or reaping crops.", MT_METAL, 3, OC_WEAPON);
addot(OT_SCYTHE, "scythe", "An agricultural hand tool for mowing grass, or reaping crops.", MT_METAL, 6, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4");
addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addot(OT_SPEAR, "spear", "A long pole with a sharpened head.", MT_METAL, 4, OC_WEAPON);
addot(OT_SPEAR, "spear", "A long pole with a sharpened head.", MT_METAL, 9, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL);
@ -8142,7 +8135,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addot(OT_TRIDENT, "trident", "A three-pronged stabbing weapon.", MT_METAL, 3, OC_WEAPON);
addot(OT_TRIDENT, "trident", "A three-pronged stabbing weapon.", MT_METAL, 5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d10");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
@ -8150,7 +8143,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
// staves
addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 2, OC_WEAPON);
addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 4, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d8");
addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL);
@ -8160,7 +8153,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_BAMBOOSTAFF, "bamboo staff", "A long hard pole made from bamboo.", MT_WOOD, 1.5, OC_WEAPON);
addot(OT_BAMBOOSTAFF, "bamboo staff", "A long hard pole made from bamboo.", MT_WOOD, 3, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d4");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
@ -8169,7 +8162,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_BLADEDSTAFF, "bladed staff", "A long wooden pole with blades on either end.", MT_WOOD, 2, OC_WEAPON);
addot(OT_BLADEDSTAFF, "bladed staff", "A long wooden pole with blades on either end.", MT_WOOD, 5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4+3");
@ -8180,7 +8173,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_IRONSTAFF, "iron staff", "A long, stout metal pole.", MT_METAL, 4, OC_WEAPON);
addot(OT_IRONSTAFF, "iron staff", "A long, stout metal pole.", MT_METAL, 8, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "3d4+1");
@ -8192,13 +8185,13 @@ void initobjects(void) {
// clubs (bashing)
addot(OT_CLUB, "club", "A heavy, blunt wooden instrument to hit things with.", MT_WOOD, 3, OC_WEAPON);
addot(OT_CLUB, "club", "A heavy, blunt wooden instrument to hit things with.", MT_WOOD, 8, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d6");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL);
addot(OT_FLAIL, "flail", "A flexible chain attached to a heavy weight.", MT_METAL, 6, OC_WEAPON);
addot(OT_FLAIL, "flail", "A flexible chain attached to a heavy weight.", MT_METAL, 9, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d4");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
@ -8211,7 +8204,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 5, OC_WEAPON);
addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 15, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d10+5");
@ -8219,13 +8212,13 @@ void initobjects(void) {
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 16, NA, NULL);
addot(OT_MACE, "mace", "A weapon with a heavy head on a solid shaft used to bludgeon opponents.", MT_METAL, 3, OC_WEAPON);
addot(OT_MACE, "mace", "A weapon with a heavy head on a solid shaft used to bludgeon opponents.", MT_METAL, 10, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d7+1");
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 3.5, OC_WEAPON);
addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 12, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d9+3");
@ -8233,7 +8226,7 @@ void initobjects(void) {
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
addot(OT_NUNCHAKU, "nunchaku", "Two stout sticks connected with a short or rope. Good for disarming.", MT_WOOD, 1.5, OC_WEAPON);
addot(OT_NUNCHAKU, "nunchaku", "Two stout sticks connected with a short or rope. Good for disarming.", MT_WOOD, 4.5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d6+1");
@ -8258,7 +8251,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
// projectile weapons
addot(OT_BOW, "bow", "A weapon which projects arrows via its elasticity.", MT_WOOD, 3, OC_WEAPON);
addot(OT_BOW, "bow", "A weapon which projects arrows via its elasticity.", MT_WOOD, 5, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
@ -8269,7 +8262,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but needs high strength to use.", MT_WOOD, 5, OC_WEAPON);
addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but needs high strength to use.", MT_WOOD, 8, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
@ -8288,7 +8281,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL);
addot(OT_LONGBOW, "longbow", "A very large (human-sized) bow, capable of firing arrows with great power.", MT_WOOD, 6, OC_WEAPON);
addot(OT_LONGBOW, "longbow", "A very large (human-sized) bow, capable of firing arrows with great power.", MT_WOOD, 7, OC_WEAPON);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
@ -8321,7 +8314,6 @@ void initobjects(void) {
// special weapons
addot(OT_ENERGYBLADE, "energy blade", "A summoned weapon made of pure magical energy.", MT_MAGIC, 0, OC_WEAPON);
addflag(lastot->flags, F_DAM, DT_MAGIC, NA, NA, "1d4"); // will be replaced when summoned
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
@ -9765,11 +9757,13 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
}
if (isplayer(lf)) {
char subprompt[BUFLEN];
sprintf(subprompt, "%s->Aim->", obname);
if (strlen(f->text) > 0) {
where = askcoords(f->text, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE);
where = askcoords(f->text, subprompt, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE);
} else {
sprintf(buf, "Where will you aim %s?",obname);
where = askcoords(buf, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE);
where = askcoords(buf, subprompt, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE);
if (!haslos(lf, where)) {
// exception - wand of digging doesn't need los
if (isknown(o) && (o->type->id == OT_WAND_DIGGING)) {
@ -9851,9 +9845,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
*/
if (hasflag(o->flags, F_OPERONOFF)) { // operating toggles on/off
flag_t *f;
f = hasflag(o->flags, F_ACTIVATED);
if (f) {
if (isactivated(o)) {
turnoff(lf, o);
} else {
turnon(lf, o);
@ -10129,6 +10121,27 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
msg("There is nothing here to fill your %s from.",noprefix(obname));
}
}
} else if (o->type->id == OT_ORBDUNGEONEXIT) {
map_t *m;
m = lf->cell->map;
if ((m->region == RG_FIRSTDUNGEON) && (m->depth == 1)) {
cell_t *cell[MAXCANDIDATES];
int ncells,i;
getradiuscells(lf->cell, 1, DT_COMPASS, B_FALSE, B_TRUE, cell, &ncells);
for (i = 0; i < ncells; i++) {
if (hasob(cell[i]->obpile, OT_STAIRSUP)) {
object_t *o;
o = hasob(cell[i]->obpile, OT_MAGICBARRIER);
if (o) {
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
}
}
}
} else {
if (isplayer(lf)) {
nothinghappens();
}
}
} else if (o->type->id == OT_POCKETWATCH) {
if (isplayer(lf)) {
if (haslos(lf, lf->cell)) {
@ -10848,20 +10861,12 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
if (!modattr(lf, A_STR, amt)) failed = B_FALSE;
if (!modattr(lf, A_DEX, amt)) failed = B_FALSE;
if (!modattr(lf, A_IQ, amt)) failed = B_FALSE;
if (!modattr(lf, A_CON, amt)) failed = B_FALSE;
} else {
enum ATTRIB a;
// modify just one attribute
i = rnd(1,3);
switch (i) {
case 1:
if (!modattr(lf, A_STR, amt)) failed = B_FALSE;
break;
case 2:
if (!modattr(lf, A_DEX, amt)) failed = B_FALSE;
break;
case 3:
if (!modattr(lf, A_IQ, amt)) failed = B_FALSE;
break;
}
a = rnd(0,MAXATTS);
if (!modattr(lf, a, amt)) failed = B_FALSE;
}
if (failed) {
if (isplayer(lf)) {
@ -11591,6 +11596,64 @@ void setblessed(object_t *o, enum BLESSTYPE wantbless) {
}
}
int sethiddenname(objecttype_t *ot, char *text) {
int n;
int gotcolour = B_FALSE;
// add knowledge for it
addknowledge(ot->id, text, B_UNKNOWN);
// some descriptions confer other effecst too...
if (strstr(text, "glowing")) {
addflag(ot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
} else if (strstr(text, "flourescent")) {
addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
} else if (strstr(text, "luminous")) {
addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
}
// set colour based on hiddenname
for (n = 0; strlen(colour[n].name); n++) {
if (strstr(text, colour[n].name)) {
flag_t *gf;
gf = hasflag(ot->flags, F_GLYPH);
if (gf) {
gf->val[0] = colour[n].col;
} else {
char buf[2];
buf[0] = ot->obclass->glyph.ch;
buf[1] = '\0';
addflag(ot->flags, F_GLYPH, colour[n].col, NA, NA, buf);
gotcolour = B_TRUE;
//dblog("assigning colour %s to %s (%s)",colour[n].name, text, ot->name);
break;
}
}
}
if (!gotcolour) {
for (n = 0; strlen(gemtype[n].name); n++) {
if (strstr(text, gemtype[n].name)) {
flag_t *gf;
gf = hasflag(ot->flags, F_GLYPH);
if (gf) {
gf->val[0] = gemtype[n].col;
} else {
char buf[2];
buf[0] = ot->obclass->glyph.ch;
buf[1] = '\0';
addflag(ot->flags, F_GLYPH, gemtype[n].col, NA, NA, buf);
break;
}
}
}
}
return B_FALSE;
}
void setinscription(object_t *o, char *text) {
if (o->inscription) {
free(o->inscription);
@ -11905,6 +11968,20 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno
// catches on fire?
if (damtype == DT_FIRE) {
if ( ((o->type->id == OT_CANDLE) || (o->type->id == OT_TORCH)) &&
!isactivated(o)) {
cell_t *c;
c = getoblocation(o);
if (haslos(player, c)) {
char buf[BUFLEN];
getobname(o, buf, o->amt);
msg("%s %s lit.", buf, (o->amt == 1) ? "is" : "are");
}
turnon(NULL, o);
// reduce damage a tiny bit
howmuch--;
}
if (isflammable(o)) {
ignite(o);
if (isdeadob(o)) {
@ -12245,7 +12322,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
// announce it ("xx throws xx" "at yy")
if (thrower && isplayer(thrower)) {
// player is throwing something
if (target) {
if (target && !hasflag(o->flags, F_POWDER)) {
msg("You %s %s %s %s.", throwverbpres, obname, willcatch ? "to" : "at", targetname);
} else {
msg("You %s %s.",throwverbpres, obname);
@ -12257,7 +12334,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
sprintf(throwstring, "%s %ss %s", throwername, throwverbpres,
obname);
if (target && haslos(player, where)) {
if (target && haslos(player, where) && !hasflag(o->flags, F_POWDER)) {
strcat(throwstring, willcatch ? " to " : " at ");
strcat(throwstring, targetname);
}
@ -13208,7 +13285,7 @@ void turnon(lifeform_t *lf, object_t *o) {
f = hasflag(o->flags, F_ACTIVATED);
if (f) {
// already on
if (isplayer(lf)) {
if (lf && isplayer(lf)) {
msg("Your %s is already activated!\n", noprefix(obname));
}
return;
@ -13218,13 +13295,14 @@ void turnon(lifeform_t *lf, object_t *o) {
f = hasflag(o->flags, F_CHARGES);
if (f && (f->val[0] <= 0)) {
// out of power
if (isplayer(lf)) {
if (lf && isplayer(lf)) {
nothinghappens();
}
return;
}
getobname(o, obname, 1);
if (lf) {
if (isplayer(lf)) {
msg("You activate your %s.",noprefix(obname));
} else if (cansee(player, lf)) {
@ -13232,6 +13310,7 @@ void turnon(lifeform_t *lf, object_t *o) {
getlfname(lf, lfname);
msg("%s activates %s.",lfname, obname);
}
}
// for grenades, give a new object which is activated
if (hasflag(o->flags, F_GRENADE)) {
@ -13254,7 +13333,9 @@ void turnon(lifeform_t *lf, object_t *o) {
addflag(o->flags, F_ACTIVATED, B_TRUE, NA, NA, NULL);
}
if (lf) {
giveobflags(lf, o, F_ACTIVATECONFER);
}
}
@ -13427,6 +13508,23 @@ int validateobs(void) {
return goterror;
}
int wepdullable(object_t *o) {
enum DAMTYPE dt;
if (!o) return B_FALSE;
dt = getdamtype(o);
switch (dt) {
case DT_PIERCE:
case DT_SLASH:
return B_TRUE;
default:
break;
}
return B_FALSE;
}
int willshatter(enum MATERIAL mat) {
switch (mat) {
case MT_GLASS:

View File

@ -201,6 +201,7 @@ int removeob(object_t *o, int howmany);
object_t *relinkob(object_t *src, obpile_t *dst);
void rrtorarity(enum RARITY r, int *minr, int *maxr);
void setblessed(object_t *o, enum BLESSTYPE wantbless);
int sethiddenname(objecttype_t *o, char *text);
void setinscription(object_t *o, char *text);
void setobcreatedby(object_t *o, lifeform_t *lf);
void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf);
@ -216,6 +217,7 @@ void turnon(lifeform_t *lf, object_t *o);
int uncurseob(object_t *o, int *seen);
int usecharge(object_t *o);
int validateobs(void);
int wepdullable(object_t *o);
int willshatter(enum MATERIAL mat);
#endif

357
spell.c
View File

@ -115,7 +115,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (isplayer(user)) {
sprintf(buf, "Charge who (max range %d)?",range);
// TODO: ask for direction
targcell = askcoords(buf, TT_MONSTER, user, range, LOF_NEED, B_TRUE);
targcell = askcoords(buf, "Charge->", TT_MONSTER, user, range, LOF_NEED, B_TRUE);
if (!targcell) {
msg("Cancelled.");
return TRUE;
@ -196,7 +196,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
addflag(target->flags, F_GRABBEDBY, user->id, NA, NA, NULL);
} else {
// attack
attackcell(user, targcell);
attackcell(user, targcell, B_TRUE);
}
} else if (abilid == OT_A_COOK) {
object_t *water,*o;
@ -267,7 +267,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} else {
sprintf(buf, "Darkwalk to where?");
}
targcell = askcoords(buf, TT_NONE, user, range, LOF_DONTNEED, B_FALSE);
targcell = askcoords(buf, "Darkwalk->", TT_NONE, user, range, LOF_DONTNEED, B_FALSE);
} else {
return B_TRUE;
}
@ -437,7 +437,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
// now attack them
attackcell(user, target->cell);
attackcell(user, target->cell, B_TRUE);
} else if (abilid == OT_A_GRAB) {
char dirch;
flag_t *f;
@ -569,7 +569,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
sprintf(buf, "Jump where (max distance 2)?");
while (!targcell) {
// ask where
targcell = askcoords(buf, TT_NONE, user, 2, LOF_DONTNEED, B_TRUE);
targcell = askcoords(buf, "Jump->", TT_NONE, user, 2, LOF_DONTNEED, B_TRUE);
if (!targcell) {
return B_TRUE;
} else if (getcelldist(user->cell, targcell) > 2) {
@ -690,6 +690,78 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
howlong = 10;
addtempflag(user->flags, F_RAGE, B_TRUE, NA, NA, NULL, howlong);
} else if (abilid == OT_A_REPAIR) {
enum SKILLLEVEL slev;
object_t *o;
int cutoffpct = 0;
slev = getskill(user, SK_ARMOUR);
switch (slev) {
default:
if (isplayer(user)) {
msg("You are too unskilled to repair your armour.");
}
return B_TRUE;
case PR_SKILLED: cutoffpct = 50; break;
case PR_EXPERT: cutoffpct = 75; break;
case PR_MASTER: cutoffpct = 100; break;
}
// 1.compile a list of repairable objects
// sk_armour lets you repair armour up to xx% (depends on skill)
initprompt(&prompt, "Repair which object?");
addchoice(&prompt, '-', "Cancel", buf, o);
for (o = user->pack->first ; o ; o = o->next) {
if (isarmour(o) && isdamaged(o)) {
float pct;
f = hasflag(o->flags, F_OBHP);
pct = ((float)f->val[0] /(float) f->val[1]) * 100;
if (pct < cutoffpct) {
char buf[BUFLEN];
getobname(o, buf, o->amt);
// we can repair this object
addchoice(&prompt, o->letter, buf, buf, o);
}
}
}
if (prompt.nchoices <= 1) {
if (isplayer(user)) {
msg("You don't have anything which you are able to repair.");
}
return B_TRUE;
}
// 2. ask which ones to repair (or ALL)
if (isplayer(user)) {
getchoice(&prompt);
o = (object_t *) prompt.result;
} else {
// pick a random one
o = (object_t *) prompt.choice[rnd(0,prompt.nchoices-1)].data;
}
// in case it's on fire, etc
if (touch(user, o)) {
taketime(user, getactspeed(user));
return B_TRUE;
}
// repair it!
f = hasflag(o->flags, F_OBHP);
f->val[0] = pctof(cutoffpct, f->val[1]);
if (isplayer(user)) {
char buf[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));
} else {
char buf[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);
}
// TODO: make this like eating/resting/etc ?
taketime(user, getactspeed(user));
} else if (abilid == OT_A_SPRINT) {
int howlong;
int slev;
@ -837,7 +909,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (isplayer(user)) {
sprintf(buf, "Swoop who (max range %d)?",srange);
// TODO: ask for direction
targcell = askcoords(buf, TT_MONSTER, user, srange, LOF_NEED, B_TRUE);
targcell = askcoords(buf, "Swoop->", TT_MONSTER, user, srange, LOF_NEED, B_TRUE);
if (!targcell) {
msg("Cancelled.");
return TRUE;
@ -899,7 +971,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
// attack
attackcell(user, targcell);
attackcell(user, targcell, B_TRUE);
// teleport back to initial pos
movelf(user, origcell);
@ -971,13 +1043,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_FALSE;
} else if (abilid == OT_A_DEBUG) {
cell_t *where;
where = askcoords("Debug who?", TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
where = askcoords("Debug who?", "Debug->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf) {
debug(where->lf);
}
} else if (abilid == OT_A_EMPLOY) {
cell_t *where;
where = askcoords("Assign job to who?", TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
where = askcoords("Assign job to who?", "Assignjob->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf) {
char question[BUFLEN];
char lfname[BUFLEN];
@ -1001,7 +1073,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
} else if (abilid == OT_A_ENHANCE) {
cell_t *where;
where = askcoords("Enhance stats of who?", TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
where = askcoords("Enhance stats of who?", "Enhancestats->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf) {
char ch;
enum ATTRIB att;
@ -1041,7 +1113,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
wep = getweapon(user);
if (!wep || !ismeleeweapon(wep) || (getobunitweight(wep) < 3)) {
if (!wep || !ismeleeweapon(wep) || (getobunitweight(wep) < 8)) { // ie. 8 is weight of a mace
if (isplayer(user)) msg("You need a heavy weapon to perform a heavy blow!");
return B_TRUE;
}
@ -1072,8 +1144,122 @@ 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);
attackcell(user, targcell);
attackcell(user, targcell, B_TRUE);
killflag(f);
} else if (abilid == OT_A_STEAL) {
enum SKILLLEVEL slev;
char dirch;
object_t *wep;
char targetname[BUFLEN];
flag_t *penalty = NULL;
int failed = B_TRUE;
// ask for direction
if (!targcell) {
dirch = askchar("Steal in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE);
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 steal from!");
return B_TRUE;
}
taketime(user, getactspeed(user));
slev = getskill(user, SK_THIEVERY);
if (slev == PR_INEPT) {
if (isplayer(user)) msg("You are too unskilled to steal anything!");
return B_TRUE;
}
getlfname(target, targetname);
if (slev == PR_NOVICE) {
penalty = addflag(user->flags, F_ACCURACYMOD, -14, NA, NA, NULL);
} else if (slev == PR_BEGINNER) {
penalty = addflag(user->flags, F_ACCURACYMOD, -7, NA, NA, NULL);
}
// use empty handed attack accuracy
wep = getweapon(user);
if (rolltohit(user, target, wep, NULL)) {
object_t *o;
int i,nsteals;
//
if (slev >= PR_EXPERT) {
nsteals = 2;
} else {
nsteals = 1;
}
// what do we steal?
for (i = 0; i < nsteals; i++) {
sprintf(buf, "Steal what (%d of %d)?", i+1, nsteals);
initprompt(&prompt, buf);
addchoice(&prompt, '-', "Nothing", NULL, NULL);
for (o = target->pack->first ; o ; o = o->next) {
int ok = B_TRUE;
if ((slev < PR_SKILLED) && (getobunitweight(o) >= 3)) {
// too heavy to steal
ok = B_FALSE;
} else if ((slev < PR_MASTER) && isequipped(o)) {
// equipped
ok = B_FALSE;
} else if (!canpickup(user, o, 1)) {
// can't pick it up
ok = B_FALSE;
}
if (ok) {
getobname(o, buf, 1);
addchoice(&prompt, o->letter, buf, NULL, o);
}
}
if (prompt.nchoices > 1) {
if (slev >= PR_ADEPT) {
// pick what you want
getchoice(&prompt);
o = (object_t *)prompt.result;
} else {
// random
o = (object_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data;
}
if (o) {
o = moveob(o, user->pack, 1);
if (o) {
getobname(o, buf, 1);
if (isplayer(user)) {
msg("You steal %s from %s!", buf, targetname);
} else if (cansee(player, user)) {
msg("%s steals %s from %s!", username, buf, targetname);
}
failed = B_FALSE;
}
}
} else {
break;
}
}
}
if (penalty) {
killflag(penalty);
}
if (failed) {
if (isplayer(user)) {
msg("You try to steal from %s, but fail.", targetname);
} else if (cansee(player, user)) {
msg("%s tries to steal from %s, but fails.", username, targetname);
}
}
} else if (abilid == OT_A_WARCRY) {
// announce
if (isplayer(user)) {
@ -1115,7 +1301,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
for (dir = DC_N; dir <= DC_NW; dir++) {
c = getcellindir(user->cell, dir);
if (c) {
attackcell(user, c);
attackcell(user, c, B_TRUE);
}
}
// remove temporary flags
@ -1430,6 +1616,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
}
} else if (spellid == OT_S_ALARM) {
if (isplayer(caster)) {
msg("You create a alarm field around yourself.");
}
} else if (spellid == OT_S_ANIMATEDEAD) {
int i;
object_t *o,*nexto;
@ -2154,7 +2344,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
if (!targcell) {
fizzle(caster);
return B_TRUE;
@ -2203,30 +2392,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
// add the monster
newlf = addmonster(targcell, r->id, randomjobsok, 1, B_FALSE, NULL);
newlf = summonmonster(caster, targcell, r->id, randomjobsok, forcejob, PERMENANT, B_FALSE);
if (newlf) {
// assign job if required
if (forcejob) {
givejob(newlf, forcejob->id);
}
if (haslos(player, targcell)) {
char *newbuf;
getlfname(newlf, buf);
newbuf = strdup(buf);
// newbuf will be "the xxx"
if (isvowel(newbuf[4])) {
newbuf = strrep(newbuf, "the ", "an ", NULL);
} else {
newbuf = strrep(newbuf, "the ", "a ", NULL);
}
capitalise(newbuf);
msg("%s appears!", newbuf);
free(newbuf);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// not worth any xp
killflagsofid(newlf->flags, F_XPVAL);
addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL);
rv = B_FALSE;
} else {
// didn't work for some reason
@ -2766,6 +2936,27 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
brightflash(caster->cell, 2 + (power/4), player);
} else if (spellid == OT_S_FLOATINGDISC) {
lifeform_t *newlf;
// get random adjacent cell
targcell = getrandomadjcell(caster->cell, WE_EMPTY, B_ALLOWEXPAND);
if (!targcell) {
fizzle(caster);
return B_TRUE;
}
// add it
newlf = summonmonster(caster, targcell, R_FLOATINGDISC, B_FALSE, NULL, PERMENANT, B_TRUE);
if (newlf) {
if (haslos(player, targcell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// set carrying capacity
setattr(newlf, A_STR, 8 + power);
} else {
// didn't work for some reason
fizzle(caster);
return B_TRUE;
}
} else if (spellid == OT_S_FLOOD) {
int failed = B_FALSE;
// ask for a target cell
@ -4359,7 +4550,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (caster->race->id == R_GHOST) {
targcell = caster->cell;
} else {
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (!validatespellcell(caster, &targcell,TT_PLAYER, spellid, power, frompot)) return B_TRUE;
}
target = targcell->lf;
@ -4873,6 +5064,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
char obname[BUFLEN];
getobname(o, obname, o->amt);
if (blessed) {
f->val[0] += (rnd(1,6) + power);
if (f->val[0] >= f->val[1]) {
@ -4881,6 +5073,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else {
msg("Your %s is repaired a little!", noprefix(obname));
}
} else {
msg("Your %s deteriorates!", noprefix(obname));
takedamage(o, rnd(1,6) + power, DT_DIRECT);
}
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
@ -5401,12 +5597,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else {
for (o = targcell->obpile->first ; o ; o = nexto) {
nexto = o->next;
if (isflammable(o)) {
takedamage(o, rnd(1,3), DT_FIRE);
}
// special cases
if (isflammable(o) || (o->type->id == OT_CANDLE) || (o->type->id == OT_TORCH)) {
takedamage(o, 1, DT_FIRE);
donesomething = B_TRUE;
}
}
}
} else if (spellid == OT_S_STENCH) {
int howlong;
if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, spellid, power, frompot)) return B_TRUE;
@ -5597,7 +5794,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
sprintf(buf, "Where will you teleport to?");
while (!c) {
int ch;
c = askcoords(buf, TT_NONE, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
c = askcoords(buf, "Teleport->",TT_NONE, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (!c) {
fizzle(caster);
return B_FALSE;
@ -5762,7 +5959,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!targob) {
// ask for a target cell (to take objects from)
sprintf(buf, "Where will you focus your telekinetic power?");
where = askcoords(buf, TT_OBJECT | TT_DOOR, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
where = askcoords(buf, "Telekinesis->", TT_OBJECT | TT_DOOR, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && haslos(caster, where)) {
if (where->obpile->first) {
// select object from cell...
@ -5792,11 +5989,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// if no target cell, ask where to throw object
if (!targcell) {
char obname[BUFLEN];
char obname[BUFLEN],buf2[BUFLEN];
getobname(targob, obname, 1);
sprintf(buf, "Where will you move %s to?", obname);
sprintf(buf, "Where will you throw %s to?", obname);
// TODO: start trail from the object
targcell = askcoords(buf, TT_MONSTER | TT_PLAYER, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
sprintf(buf2, "Telekinesis->%s->",obname);
targcell = askcoords(buf, buf2,TT_MONSTER | TT_PLAYER, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
}
// not liftable?
@ -5855,6 +6053,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = addtempflag(caster->flags, F_RETALIATE, 1, 4, DT_PIERCE, "sharp thorns", FROMSPELL);
f->obfrom = spellid;
} else if (spellid == OT_S_TRUESTRIKE) {
if (!validatespellcell(caster, &targcell, TT_PLAYER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_FALSE;
}
addflag(caster->flags, F_TRUESTRIKE, power, NA, NA, NULL);
} else if (spellid == OT_S_TURNUNDEAD) {
int i;
// works on all undead in sight
@ -6778,6 +6984,13 @@ char *getvarpowerspelldesc(enum OBTYPE spellid, int power, char *buf) {
case OT_S_SUMMONWEAPON:
sprintf(buf, "Create a 2d%d damage magical weapon",power);
break;
case OT_S_TRUESTRIKE:
if (power == 1) {
sprintf(buf, "Next attack automatically hits");
} else {
sprintf(buf, "Next %d attacks automatically hit",power);
}
break;
case OT_S_WINDSHIELD:
sprintf(buf, "Protection from missiles <= %d km/h",speedtokph(power));
break;
@ -6852,6 +7065,38 @@ void stopallspells(lifeform_t *lf) {
}
}
void stopallspellsexcept(lifeform_t *lf, ...) {
flag_t *f,*nextf;
va_list args;
enum OBTYPE exception[MAXCANDIDATES];
int nexceptions = 0;
va_start(args, lf);
exception[nexceptions] = va_arg(args, enum OBTYPE);
while (exception[nexceptions] != OT_NONE) {
nexceptions++;
exception[nexceptions] = va_arg(args, enum OBTYPE);
}
va_end(args);
for (f = lf->flags->first ; f ; f = nextf) {
nextf = f->next;
if (f->id == F_BOOSTSPELL) {
int stopthis = B_TRUE;
int n;
for (n = 0; n < nexceptions; n++) {
if (exception[n] == f->val[0]) {
stopthis = B_FALSE;
break;
}
}
if (stopthis) {
stopspell(lf, f->val[0]);
}
}
}
}
int schoolappearsinbooks(enum SPELLSCHOOL ss) {
switch (ss) {
case SS_DIVINE:
@ -6915,6 +7160,19 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) {
killob(o);
}
}
if (spellid == OT_S_FLOATINGDISC) {
map_t *m;
lifeform_t *lf;
for (m = firstmap ; m ; m = m->next) {
for (lf = m->lf ; lf ; lf = lf->next) {
if (lf->race->id == R_FLOATINGDISC) {
if (lfhasflagval(lf, F_SUMMONEDBY, caster->id, NA, NA, NULL)) {
unsummon(lf, B_FALSE);
}
}
}
}
}
}
@ -6997,9 +7255,10 @@ lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **targe
// ask for a target lifeform
if (isplayer(user)) {
cell_t *where;
char buf[BUFLEN];
char buf[BUFLEN],buf2[BUFLEN];
sprintf(buf, "Where will you target your %s?",ot->name);
where = askcoords(buf, TT_MONSTER, user, maxrange, LOF_DONTNEED, B_FALSE);
sprintf(buf2, "%s->",ot->name);
where = askcoords(buf, buf2, TT_MONSTER, user, maxrange, LOF_DONTNEED, B_FALSE);
if (where) {
if (!haslf(where)) {
msg("There is nobody there!");
@ -7123,14 +7382,16 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, e
// ask for a target cell
if (isplayer(caster)) {
char buf[BUFLEN];
if (maxrange == UNLIMITED) {
char buf2[BUFLEN];
objecttype_t *ot;
ot = findot(spellid);
if (maxrange == UNLIMITED) {
sprintf(buf, "Where will you target your %s?", ot->name);
} else {
sprintf(buf, "Where will you target your spell [max range %d]?",maxrange);
sprintf(buf, "Where will you target your %s [max range %d]?",ot->name, maxrange);
}
where = askcoords(buf, targtype, caster, maxrange, needlof, needlof ? B_TRUE : B_FALSE);
sprintf(buf2, "%s->",ot->name);
where = askcoords(buf, buf2, targtype, caster, maxrange, needlof, needlof ? B_TRUE : B_FALSE);
if (!where) {
int ch;
ch = askchar("Abandon your spell?","yn","n", B_TRUE);

View File

@ -25,6 +25,7 @@ int schoolappearsinbooks(enum SPELLSCHOOL ss);
void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot);
void stopspell(lifeform_t *caster, enum OBTYPE spellid);
void stopallspells(lifeform_t *lf);
void stopallspellsexcept(lifeform_t *lf, ...);
int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime);
lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target);
cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power, int frompot);