- [+] better body part handling

- [+] bodypart_t[MAXBODYPARTS]
        - [+] enum BODYPART id
        - [+] char *name
    - [+] add defs to all races
    - [+] fix quadrapeds - not all have tails!
    - [+] remove f_bodypartname - use addbodypart instead
    - [+] update hasbp
    - [+] remove  occurences of F_NOBODYPART in races
    - [+] fix up getrandombodypart functions
        - [+] getrandomonbodypart
        - [+] getcrithitpos
        - [+] copy with null returns
    - [+] check all occurences of MAXBODYPARTS, change to "for each
          bodypart of this lf/race"
    - [+] show nobodypart differently in io.c 
    - [+] criticals:  hindlegs / frontlegs -> legs
    - [+] makeunusual shaped be part of the body part. then remove 
          F_NOARMOURON
- [+] critical hits on new body parts
    - [+] wing crits
        - [+] bash - wings are bruised - reduced flight speed
        - [+] slash
            - [+] - wings are torn - can't fly. implement in cancast.
            - [+] bleeding - flying hurts
        - [+] explosive
            - [+] destroyed - can't fly!
    - [+] tail crits
        - [+] slash
            - [+] bleeding
        - [+] bash
            - [+] bruised - accuracy lowered
            - [+] fractured - randomly move the wrong way like
                  drunkenness
        - [+] explosive
            - [+] lacerated - randomly fall like hamstrung
- [+] don't prompt for moving into dangerous cells f moving randomly
      due to drunkenness etc
- [+] bug: double criticals?
    - [+] You flatten the kobold!  The kobold loses consciousness.
          The kobold's hand is swollen!  The kobold's leg is broken!
- [+] all f_flying races should have f_canwill ot_s_fly with no
      spellcasttext
This commit is contained in:
Rob Pearce 2011-11-22 21:32:10 +00:00
parent c596623603
commit c9fcd90a2c
10 changed files with 706 additions and 555 deletions

11
ai.c
View File

@ -1098,9 +1098,11 @@ void aiturn(lifeform_t *lf) {
// flying monsters not flying?
if (!isprone(lf)) {
if (hasflag(lf->race->flags, F_FLYING) && !lfhasflag(lf, F_FLYING)) {
copyflag(lf->flags, lf->race->flags, F_FLYING);
taketime(lf, getmovespeed(lf));
return;
if (cancast(lf, OT_S_FLIGHT, NULL)) {
if (!castspell(lf, OT_S_FLIGHT, lf, NULL, lf->cell, NULL, NULL)) {
return;
}
}
}
if (hasflag(lf->race->flags, F_LEVITATING) && !lfhasflag(lf, F_LEVITATING)) {
copyflag(lf->flags, lf->race->flags, F_LEVITATING);
@ -1321,8 +1323,9 @@ void aiturn(lifeform_t *lf) {
}
// do we have better armour?
for (bp = BP_RIGHTFINGER ; bp < MAXBODYPARTS; bp++) {
for (i = 0; i < lf->race->nbodyparts; i++) {
object_t *curarm;
bp = lf->race->bodypart[i].id;
curarm = getarmour(lf, bp);
// do we have a better one?
for (o = lf->pack->first ; o ; o = o->next) {

View File

@ -645,20 +645,22 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
object_t *armour;
char noun[BUFLEN];
critpos = getrandomcorebp(victim);
armour = getequippedob(victim->pack, critpos);
if (armour) {
char armname[BUFLEN];
real_getobname(armour, armname, 1, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE);
sprintf(noun, "%s", noprefix(armname));
} else {
sprintf(noun, "%s", getbodypartname(victim, critpos));
}
// replace victicname to include body part
if ((lf == victim) && !isplayer(lf)) {
snprintf(victimbpname, BUFLEN, "its %s", noun);
} else {
getlfname(victim, buf);
snprintf(victimbpname, BUFLEN, "%s%s %s", buf, getpossessive(buf), noun);
if (critpos != BP_NONE) {
armour = getequippedob(victim->pack, critpos);
if (armour) {
char armname[BUFLEN];
real_getobname(armour, armname, 1, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE);
sprintf(noun, "%s", noprefix(armname));
} else {
sprintf(noun, "%s", getbodypartname(victim, critpos));
}
// replace victicname to include body part
if ((lf == victim) && !isplayer(lf)) {
snprintf(victimbpname, BUFLEN, "its %s", noun);
} else {
getlfname(victim, buf);
snprintf(victimbpname, BUFLEN, "%s%s %s", buf, getpossessive(buf), noun);
}
}
} else {
strcpy(victimbpname, "");
@ -1421,6 +1423,9 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int d
object_t *o,*armour;
int protected = B_FALSE;
char lfname[BUFLEN],victimname[BUFLEN];
if (hitpos == BP_NONE) return;
// replace some dam types
if (damtype == DT_UNARMED) damtype = DT_BASH;
if (damtype == DT_BITE) damtype = DT_SLASH;

754
data.c

File diff suppressed because it is too large Load Diff

64
defs.h
View File

@ -1741,21 +1741,27 @@ enum OBTYPE {
#define BP_NONE (-1)
enum BODYPART {
// humanoid parts
BP_WEAPON = 0,
BP_SECWEAPON,
BP_EARS,
BP_EYES,
BP_HEAD,
BP_SHOULDERS,
BP_BODY,
BP_HANDS,
BP_WAIST,
BP_LEGS,
BP_FEET,
BP_RIGHTFINGER,
BP_LEFTFINGER,
BP_SECWEAPON = 1,
BP_EARS = 2,
BP_EYES = 3,
BP_HEAD = 4,
BP_SHOULDERS = 5,
BP_BODY = 6,
BP_HANDS = 7,
BP_WAIST = 8,
BP_LEGS = 9,
BP_FEET = 10,
BP_RIGHTFINGER = 11,
BP_LEFTFINGER = 12,
// others...
BP_BACKLEGS = 13,
BP_FRONTLEGS = 14,
BP_WINGS = 15,
BP_TAIL = 16,
};
#define MAXBODYPARTS (13)
#define MAXBODYPARTS (17)
// depth on a human
@ -2464,7 +2470,7 @@ enum FLAG {
F_SPELLCASTTEXT, // text is announcement for spellcast
// if text is empty, then don't announce
// this lf's spell casting at all.
// if v0 is set, only use text for spellid v0
// if v0 != OT_NONE, only use text for spellid v0
// if v2 is 'appendyou' " at xxx" will
// be appended.
F_NODEATHANNOUNCE, // don't say 'the xx dies' if this lf dies
@ -2517,16 +2523,12 @@ enum FLAG {
F_DOESNTMOVE, // this race doesn't move (but can still attack)
F_AQUATIC, // this race can attack normally in water and suffers no
// movement penalties
F_BODYPARTNAME, // for this race, bodypart v0 is called 'text'
F_AVIAN, // this race is an avian
F_CANINE, // this race is a canine
F_HUMANOID, // this race can wear armour / use weapons
F_INSECT, // this race is classed as an insect
F_UNDEAD, // this race is classed as undead
F_COLDBLOOD, // this race is coldblooded
F_NOARMOURON, // this race can't wear armour on bodypart v0
// obviously doesn't make sense to have both this
// and f_nobodypart for the same body part.
F_NOBODYPART, // this race doesn't have bodypart val0
// if v0 is true or b_frominjury, you can regrow it
// via a healing potion.
@ -2820,10 +2822,13 @@ enum INJURY {
IJ_RIBBROKEN, // can be from explosive too
IJ_RIBCRACKED, // can be from explosive too
IJ_SHOULDERDISLOCATED,
IJ_TAILBRUISED,
IJ_TAILBROKEN,
IJ_TORSOBRUISED,
IJ_TORSOBRUISEDBAD,
IJ_WINDED,
IJ_WINDPIPECRUSHED,
IJ_WINGBRUISED,
// slashing
IJ_ARTERYPIERCE,
IJ_CHESTBLEED,
@ -2834,10 +2839,15 @@ enum INJURY {
IJ_FINGERMISSING,
IJ_EYELIDSCRAPED,
IJ_EYEDESTROYED,
IJ_TAILBLEED,
IJ_WINGBLEED,
IJ_WINGTORN,
// explosive
IJ_EARSRINGING,
IJ_HANDMISSING,
IJ_LUNGCOLLAPSED,
IJ_TAILLACERATED,
IJ_WINGDESTROYED,
};
@ -3002,6 +3012,21 @@ typedef struct coord_s {
int x,y;
} coord_t;
enum BODYTYPE {
BT_BIRD,
BT_FISH,
BT_HUMANOID,
BT_QUADRAPED,
BT_SNAKE,
BT_SPIDER,
};
typedef struct bodypart_s {
enum BODYPART id;
char *name;
int armourok;
} bodypart_t;
// command types
typedef struct command_s {
enum COMMAND id;
@ -3246,6 +3271,9 @@ typedef struct race_s {
struct glyph_s glyph;
float weight;
struct flagpile_s *flags;
struct bodypart_s bodypart[MAXBODYPARTS];
int nbodyparts;
// speed modifiers
// hit dice
struct race_s *next, *prev;

64
io.c
View File

@ -31,6 +31,8 @@ WINDOW *statwin;
int statdirty = B_TRUE;
int inaskcoords = B_FALSE; // are we inside this function?
int hascolour = B_TRUE;
int noredraw = B_FALSE;
@ -546,6 +548,11 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
int nretflags;
flag_t *retflag[MAXCANDIDATES];
// rememebr that we're in this function. the main use for this is to ensure
// that when adding a fake corpse for lfs who are feigning death, that we don't
// do a screen update (due to adding an object in sight of the player)
inaskcoords = B_TRUE;
iqb = getattrbracket(getattr(player, A_IQ), A_IQ, NULL);
// remember previously targetted lifeforms
@ -1027,19 +1034,27 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
startlf = c->lf->id;
}
restoregamewindows();
inaskcoords = B_FALSE;
return c;
} else if (ch == 'v') { // view
// todo: show obpile or view lf
if (c->lf && cansee(player, c->lf)) {
if (c->lf && cansee(player, c->lf) && (isplayer(c->lf) || !lfhasflag(c->lf, F_FEIGNINGDEATH))) {
showlfstats(c->lf, B_FALSE);
} else if (haslos(player, c)) {
object_t *o;
object_t *o,*tempob = NULL;
// lf feigning death here? put down a fake corpse.
if (c->lf && lfhasflag(c->lf, F_FEIGNINGDEATH) && !isplayer(c->lf)) {
char obname[BUFLEN];
sprintf(obname, "%s corpse", c->lf->race->name);
tempob = addob(c->obpile, obname);
}
// show objects
o = doaskobject(c->obpile, "Describe which object", NULL, B_FALSE, B_FALSE, '\0', AO_NONE, F_NONE);
while (o) {
describeob(o);
o = doaskobject(c->obpile, "Describe which object", NULL, B_FALSE, B_FALSE, '\0', AO_NONE, F_NONE);
}
if (tempob) killob(tempob);
}
} else if (ch == 27) { // esc - cancel
finished = B_TRUE;
@ -1062,6 +1077,8 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
}
}
inaskcoords = B_FALSE;
clearmsg();
restoregamewindows();
return NULL;
@ -9031,7 +9048,7 @@ void showlfarmour(lifeform_t *lf) {
// default
strcpy(rhs, "");
if (!lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
if (hasbp(lf, bp)) {
object_t *outerob;
snprintf(buf, BUFLEN, "%13s:%1s",getbodypartname(lf, bp), " ");
o = getequippedob(lf->pack, bp);
@ -9908,29 +9925,29 @@ void showlfstats(lifeform_t *lf, int showall) {
}
nmissingbp = 0;
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
if (lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
if (bp == BP_RIGHTFINGER) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else if (bp == BP_LEFTFINGER) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL) &&
!lfhasflagval(lf, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL)
) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else if (bp == BP_SECWEAPON) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else {
getflags(lf->flags, retflag, &nretflags, F_NOBODYPART, F_NONE);
for (i = 0; i < nretflags; i++) {
bp = retflag[i]->val[0];
if (bp == BP_RIGHTFINGER) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else if (bp == BP_LEFTFINGER) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL) &&
!lfhasflagval(lf, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL)
) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else if (bp == BP_SECWEAPON) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
}
@ -9986,7 +10003,6 @@ void showlfstats(lifeform_t *lf, int showall) {
mt = findmaterial(getlfmaterial(lf));
wrapprint(mainwin, &y, &x, "%s %s made out of %s. ",you(lf), is(lf), mt->name);
}
} else if (mode == 'a') {
centre(mainwin, C_WHITE, 0, "ABILITIES");
y = 2;

281
lf.c
View File

@ -217,6 +217,17 @@ int bleedfrom(lifeform_t *lf, enum BODYPART bp, int splatter) {
return B_TRUE;
}
int bpcantakearmour(lifeform_t *lf, enum BODYPART bp) {
int i;
// unnaturally shaped limbs?
for (i = 0; i < lf->race->nbodyparts; i++) {
if ((lf->race->bodypart[i].id == bp) && !lf->race->bodypart[i].armourok) {
return B_FALSE;
}
}
return B_TRUE;
}
void breakgrabs(lifeform_t *lf, int fromme, int tome) {
flag_t *f;
lifeform_t *alf;
@ -547,6 +558,17 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
if (f) {
int needgrab = B_FALSE;
// flying with broken/destroyed wings?
if ((oid == OT_S_FLIGHT) && (f->lifetime == FROMRACE)) {
if (lfhasflagval(lf, F_INJURY, IJ_WINGTORN, NA, NA, NULL)) {
reason = E_INJURED;
return B_FALSE;
} else if (lfhasflagval(lf, F_NOBODYPART, BP_WINGS, NA, NA, NULL)) {
reason = E_INJURED;
return B_FALSE;
}
}
// get canwill opts
texttospellopts(f->text, "needgrab:", &needgrab, NULL);
@ -845,12 +867,8 @@ int canmakerecipe(lifeform_t *lf, recipe_t *rec) {
int canopendoors(lifeform_t *lf) {
if (lf) {
if (!lfhasflag(lf, F_HUMANOID)) {
return B_FALSE;
}
if (lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
return B_FALSE;
}
if (!lfhasflag(lf, F_HUMANOID)) return B_FALSE;
if (!hasbp(lf, BP_HANDS)) return B_FALSE;
}
return B_TRUE;
@ -1138,7 +1156,8 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) {
if (!hasbp(lf, where)) {
reason = E_NOBP;
return B_FALSE;
} else if (lfhasflagval(lf, F_NOARMOURON, where, NA, NA, NULL)) {
}
if (!bpcantakearmour(lf, where)) {
reason = E_DOESNTFIT;
return B_FALSE;
}
@ -1327,7 +1346,7 @@ int canweild(lifeform_t *lf, object_t *o) {
}
} else if (f->id == F_TWOHANDED) {
// need both hands free...
if (lfhasflagval(lf, F_NOBODYPART, otherloc, NA, NA, NULL)) {
if (!hasbp(lf, otherloc)) {
reason = E_NOHANDS;
return B_FALSE;
}
@ -1417,6 +1436,9 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
case E_NOMP:
msg("You don't have enough mana to cast that.");
break;
case E_INJURED:
msg("Your injury prevents you from doing that.");
break;
case E_LOWIQ:
msg("You are not smart enough to cast spells.");
break;
@ -1563,7 +1585,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
// special case
f = lfhasflagval(lf, F_SPELLCASTTEXT, sid, NA, NA, NULL); // specific text for this spell
if (!f) {
f = lfhasflag(lf, F_SPELLCASTTEXT); // generic spellcast
f = lfhasflagval(lf, F_SPELLCASTTEXT, OT_NONE, NA, NA, NULL); // generic spellcast
}
if (f) {
if (strlen(f->text)) {
@ -4702,8 +4724,10 @@ enum ALLEGIENCE getallegiance(lifeform_t *lf) {
int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs) {
object_t *o;
enum BODYPART bp;
int i;
*nobs = 0;
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
for (i = 0; i < lf->race->nbodyparts; i++) {
bp = lf->race->bodypart[i].id;
o = getouterequippedob(lf, bp);
if (o) {
int n,found = B_FALSE;
@ -5297,26 +5321,40 @@ object_t *getbestweapon(lifeform_t *lf) {
int getbodyparthitchance(enum BODYPART bp) {
switch (bp) {
case BP_WEAPON: return 0;
case BP_SECWEAPON: return 0;
case BP_EYES: return 1;
case BP_HEAD: return 2;
case BP_WAIST: return 3;
case BP_HANDS: return 3;
case BP_FEET: return 3;
case BP_TAIL: return 3;
case BP_FRONTLEGS: return 4;
case BP_BACKLEGS: return 4;
case BP_LEGS: return 4;
case BP_SHOULDERS: return 4;
case BP_WINGS: return 4;
case BP_BODY: return 6;
default: break;
case BP_EARS:
case BP_RIGHTFINGER:
case BP_LEFTFINGER:
break;
}
return 0; // ie rings, ears, weapon
}
char *getbodypartname(lifeform_t *lf, enum BODYPART bp) {
flag_t *f;
if (lf) {
f = lfhasflagval(lf, F_BODYPARTNAME, bp, NA, NA, NULL);
if (f) {
return f->text;
int i;
// does this bodypart have a special name?
for (i = 0; i < lf->race->nbodyparts; i++) {
if (lf->race->bodypart[i].id == bp) {
if (strlen(lf->race->bodypart[i].name)) {
return lf->race->bodypart[i].name;
}
}
}
}
@ -5343,10 +5381,18 @@ char *getbodypartname(lifeform_t *lf, enum BODYPART bp) {
return "shoulders";
case BP_WAIST:
return "waist";
case BP_FRONTLEGS:
return "front legs";
case BP_BACKLEGS:
return "back legs";
case BP_LEGS:
return "legs";
case BP_FEET:
return "feet";
case BP_TAIL:
return "tail";
case BP_WINGS:
return "wings";
}
return "unknown";
}
@ -5362,8 +5408,12 @@ char *getbodypartequipname(enum BODYPART bp) {
case BP_HANDS:
case BP_HEAD:
case BP_BODY:
case BP_FRONTLEGS:
case BP_BACKLEGS:
case BP_LEGS:
case BP_FEET:
case BP_WINGS:
case BP_TAIL:
return "on";
case BP_EYES:
case BP_SHOULDERS:
@ -5708,6 +5758,7 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) {
case IJ_SHOULDERDISLOCATED:
acc -= 20; break;
case IJ_RIBBROKEN:
case IJ_TAILBROKEN:
acc -= 30; break;
}
}
@ -6444,8 +6495,14 @@ int getmovespeed(lifeform_t *lf) {
}
// flying in low gravity?
if (lfhasflag(lf, F_GRAVLESSENED) && lfhasflag(lf, F_FLYING)) {
speed -= 5;
f = lfhasflag(lf, F_FLYING);
if (f) {
if (lfhasflag(lf, F_GRAVLESSENED)) {
speed -= 5;
}
if ((f->lifetime == FROMRACE) && lfhasflagval(lf, F_INJURY, IJ_WINGBRUISED, NA, NA, NULL)) {
speed += 10;
}
}
switch (isburdened(lf)) {
@ -6928,8 +6985,15 @@ enum BODYPART getrandomcorebp(lifeform_t *lf) {
enum BODYPART bp[4],selbp = BP_NONE;
if (hasbp(lf, BP_BODY)) bp[nparts++] = BP_BODY;
if (hasbp(lf, BP_HANDS)) bp[nparts++] = BP_HANDS;
if (hasbp(lf, BP_LEGS)) bp[nparts++] = BP_LEGS;
if (hasbp(lf, BP_HEAD)) bp[nparts++] = BP_HEAD;
if (hasbp(lf, BP_LEGS) || hasbp(lf, BP_FRONTLEGS) || hasbp(lf, BP_BACKLEGS)) {
bp[nparts++] = BP_LEGS;
}
if (!nparts) {
return BP_NONE;
}
for (i = 0;i < nparts; i++) {
if (i == 0) {
cutoff[i] = getbodyparthitchance(bp[i]);
@ -8633,8 +8697,21 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
object_t *wep = NULL;
int howlong;
if (where == BP_NONE) return B_TRUE;
if (!hasbp(lf, where)) return B_TRUE;
if (!hasbp(lf, where)) {
if (where == BP_LEGS) {
// adjust bp_legs into bp_frontlegs/bp_backelgs
if (hasbp(lf, BP_FRONTLEGS) || hasbp(lf, BP_BACKLEGS)) {
// ok.
} else {
return B_TRUE;
}
} else {
return B_TRUE;
}
}
if (lfhasflag(lf, F_NOINJURIES)) return B_TRUE;
if (lfhasflagval(lf, F_INJURY, NA, where, NA, NULL)) return B_TRUE;
@ -8702,6 +8779,21 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
desc = strdup("ankle is swollen^cannot wear/remove boots"); break;
}
}
break;
case BP_TAIL:
switch (rnd(1,2)) {
case 1:
inj = IJ_TAILBRUISED;
desc = strdup("tail is bruised^accuracy penalty"); break;
case 2:
inj = IJ_TAILBROKEN;
desc = strdup("tail is fractured^occasional random movement"); break;
}
break;
case BP_WINGS:
inj = IJ_WINGBRUISED;
desc = strdup("wings are bruised^flight speed lowered"); break;
break;
default: break;
}
} else if (damtype == DT_SLASH) {
@ -8787,6 +8879,22 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
inj = IJ_HAMSTRUNG; desc = strdup("left hamstring is torn^lower move speed, chance of falling");
break;
}
break;
case BP_TAIL:
inj = IJ_TAILBLEED;
desc = strdup("tail is bleeding^no additional effects");
break;
case BP_WINGS:
switch (rnd(1,2)) {
case 1:
inj = IJ_WINGTORN;
desc = strdup("wings are torn^cannot fly");
break;
case 2:
inj = IJ_WINGBLEED;
desc = strdup("wings are bleeding^flying causes damage");
break;
}
default: break;
}
} else if (damtype == DT_EXPLOSIVE) {
@ -8851,6 +8959,16 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
case BP_LEGS:
// lose limb
break;
case BP_TAIL:
inj = IJ_TAILLACERATED;
desc = strdup("tail is lacerated^chance of falling during movement");
howlong = PERMENANT;
break;
case BP_WINGS:
inj = IJ_WINGDESTROYED;
desc = strdup("wings are destroyed^cannot fly");
howlong = PERMENANT;
break;
default:
break;
}
@ -8884,6 +9002,12 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
wep = getweapon(lf);
if (wep) drop(wep, wep->amt);
break;
case IJ_WINGTORN:
killflagsofid(lf->flags, F_FLYING);
break;
case IJ_WINGDESTROYED:
addflag(lf->flags, F_NOBODYPART, BP_WINGS, B_FROMINJURY, NA, NULL);
break;
case IJ_WINDED:
lf->stamina = 0;
if (isplayer(lf)) statdirty = B_TRUE;
@ -9094,10 +9218,14 @@ void loseobflags(lifeform_t *lf, object_t *o, int kind) {
}
int hasbp(lifeform_t *lf, enum BODYPART bp) {
int i;
if (lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
return B_FALSE;
}
return B_TRUE;
for (i = 0; i < lf->race->nbodyparts; i++) {
if (lf->race->bodypart[i].id == bp) return B_TRUE;
}
return B_FALSE;
}
flag_t *hasactivespell(lifeform_t *lf, enum OBTYPE sid) {
@ -9666,6 +9794,8 @@ int isfullyhealed(lifeform_t *lf) {
healed = B_FALSE;
} else if (getstamina(lf) < getmaxstamina(lf)) {
healed = B_FALSE;
} else if (hashealableinjuries(lf)) {
healed = B_FALSE;
}
return healed;
}
@ -9967,6 +10097,17 @@ job_t *addjob(enum JOB id, char *name, char *desc) {
return a;
}
void addbodypart(race_t *r, enum BODYPART bp, char *name) {
r->bodypart[r->nbodyparts].id = bp;
if (name) {
r->bodypart[r->nbodyparts].name = strdup(name);
} else {
r->bodypart[r->nbodyparts].name = strdup("");
}
r->bodypart[r->nbodyparts].armourok = B_TRUE;
r->nbodyparts++;
}
lifeform_t *addlf(cell_t *cell, enum RACE rid, int level) {
return real_addlf(cell, rid, level, C_AI);
}
@ -10074,7 +10215,7 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) {
// set race - this will inherit race flags and material
a->race = NULL;
setrace(a, rid, B_FALSE);
// set stamina AFTER setrace as it depends on your attribs
@ -10130,6 +10271,8 @@ race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcol
a->glyph.ch = glyph;
a->glyph.colour = glyphcolour;
a->nbodyparts = 0;
a->flags = addflagpile(NULL, NULL);
return a;
}
@ -10641,6 +10784,7 @@ int armourfits(lifeform_t *lf, object_t *o, enum ERROR *reason) {
return B_TRUE;
}
int askforpayment(lifeform_t *shk, lifeform_t *lf) {
char saybuf[BUFLEN];
int totcost = 0;
@ -11939,6 +12083,16 @@ int needstorest(lifeform_t *lf, char *validchars) {
return need;
}
void noarmouron(race_t *r, enum BODYPART bp) {
int i;
for (i = 0; i < r->nbodyparts; i++) {
if (r->bodypart[i].id == bp) {
r->bodypart[i].armourok = B_FALSE;
break;
}
}
}
// returns TRUE if the player heard it.
int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, char *text, char *seetext) {
lifeform_t *l;
@ -13376,6 +13530,61 @@ void setattr(lifeform_t *lf, enum ATTRIB attr, int val) {
}
}
void setbodypartname(race_t *r, enum BODYPART bp, char *name) {
int i;
for (i = 0; i < r->nbodyparts; i++) {
if (r->bodypart[i].id == bp) {
free(r->bodypart[i].name);
r->bodypart[i].name = strdup(name);
break;
}
}
}
void setbodytype(race_t *r, enum BODYTYPE bt) {
int i;
switch (bt) {
case BT_BIRD:
addbodypart(r, BP_EYES, NULL);
addbodypart(r, BP_HEAD, NULL);
addbodypart(r, BP_BODY, NULL);
addbodypart(r, BP_LEGS, NULL);
addbodypart(r, BP_FEET, "talons");
addbodypart(r, BP_WINGS, NULL);
break;
case BT_HUMANOID:
for (i = BP_WEAPON; i <= BP_LEFTFINGER; i++) {
addbodypart(r, i, NULL);
}
break;
case BT_QUADRAPED:
addbodypart(r, BP_EYES, NULL);
addbodypart(r, BP_HEAD, NULL);
addbodypart(r, BP_BODY, NULL);
addbodypart(r, BP_BACKLEGS, "back legs");
addbodypart(r, BP_FRONTLEGS, "front legs");
addbodypart(r, BP_FEET, "paws");
break;
case BT_FISH:
addbodypart(r, BP_EYES, NULL);
addbodypart(r, BP_HEAD, NULL);
addbodypart(r, BP_BODY, NULL);
addbodypart(r, BP_TAIL, NULL);
break;
case BT_SNAKE:
addbodypart(r, BP_EYES, NULL);
addbodypart(r, BP_HEAD, NULL);
addbodypart(r, BP_TAIL, NULL);
break;
case BT_SPIDER:
addbodypart(r, BP_EYES, NULL);
addbodypart(r, BP_HEAD, "cephalothorax");
addbodypart(r, BP_BODY, "abdomen");
addbodypart(r, BP_LEGS, NULL);
break;
}
}
int setfacing(lifeform_t *lf, int dir) {
if (isclimbing(lf)) { // can't change dir while climbing
return B_TRUE;
@ -13634,22 +13843,20 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
}
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
if (lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
for (o = lf->pack->first; o ; o = nexto ) {
nexto = o->next;
if (hasflagval(o->flags, F_EQUIPPED, bp, NA, NA, NULL)) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
// drop it!
if (isplayer(lf)) {
msg("Your %s drops to the ground!",noprefix(obname));
} else if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s%s %s drop to the ground!",buf, getpossessive(buf),
noprefix(obname));
}
moveob(o, lf->cell->obpile, o->amt);
if (!hasbp(lf, bp)) {
o = getequippedob(lf->pack, bp);
if (o) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
// drop it!
if (isplayer(lf)) {
msg("Your %s drops to the ground!",noprefix(obname));
} else if (cansee(player, lf)) {
getlfname(lf, buf);
msg("%s%s %s drop to the ground!",buf, getpossessive(buf),
noprefix(obname));
}
moveob(o, lf->cell->obpile, o->amt);
}
}
}

5
lf.h
View File

@ -1,5 +1,6 @@
#include "defs.h"
void addbodypart(race_t *r, enum BODYPART bp, char *name);
lifeform_t *addlf(cell_t *cell, enum RACE rid, int level);
lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller);
job_t *addjob(enum JOB id, char *name, char *desc);
@ -25,6 +26,7 @@ int appearsrandomly(enum RACE rid);
void awardxpfor(lifeform_t *killed, float pct);
void bleed(lifeform_t *lf, int splatter);
int bleedfrom(lifeform_t *lf, enum BODYPART bp, int splatter);
int bpcantakearmour(lifeform_t *lf, enum BODYPART bp);
void breakgrabs(lifeform_t *lf, int fromme, int tome);
void breakaitargets(lifeform_t *lf, int onlylowerlev);
long calcscore(lifeform_t *lf);
@ -334,6 +336,7 @@ void modmorale(lifeform_t *lf, int howmuch);
void modstamina(lifeform_t *lf, float howmuch);
int movecausesnoise(lifeform_t *lf);
int needstorest(lifeform_t *lf, char *validchars);
void noarmouron(race_t *r, enum BODYPART bp);
int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext);
enum NOISECLASS noisetypetoclass(enum NOISETYPE nt);
void outfitlf(lifeform_t *lf);
@ -362,6 +365,8 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t
int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus);
//int setammo(lifeform_t *lf, object_t *o);
void setattr(lifeform_t *lf, enum ATTRIB attr, int val);
void setbodypartname(race_t *r, enum BODYPART bp, char *name);
void setbodytype(race_t *r, enum BODYTYPE bt);
int setfacing(lifeform_t *lf, int dir);
void setfollowdistance(lifeform_t *lf, int min, int max);
void setguntarget(lifeform_t *lf, lifeform_t *targ);

42
move.c
View File

@ -1000,6 +1000,10 @@ int moveeffects(lifeform_t *lf) {
if (isplayer(lf)) didmsg = B_TRUE;
}
}
if (onein(10) && lfhasflagval(lf, F_INJURY, IJ_TAILLACERATED, NA, NA, NULL)) {
fall(lf, NULL, B_TRUE);
if (isplayer(lf)) didmsg = B_TRUE;
}
if (isbleeding(lf)) {
if (hasbleedinginjury(lf, BP_LEGS)) {
@ -1013,6 +1017,19 @@ int moveeffects(lifeform_t *lf) {
}
}
if (lfhasflagval(lf, F_INJURY, IJ_WINGBLEED, NA, NA, NULL)) {
flag_t *retflag[MAXCANDIDATES];
int nretflags,i;
getflags(lf->flags, retflag, &nretflags, F_FLYING, F_NONE);
for (i = 0; i < nretflags; i++) {
if (retflag[i]->lifetime == FROMRACE) {
if (!bleedfrom(lf, BP_WINGS, B_FALSE)) {
losehp(lf, 1, DT_DIRECT, NULL, "blood loss");
}
}
}
}
f = lfhasflag(lf, F_PAIN);
if (f) {
if (!lfhasflag(lf, F_DRUNK)) {
@ -1634,8 +1651,8 @@ int movetowards(lifeform_t *lf, cell_t *dst, int dirtype, int strafe) {
}
int move_will_hurt(lifeform_t *lf) {
flag_t *retflag[MAXCANDIDATES];
int nretflags,i;
flag_t *retflag[MAXCANDIDATES],*retflag2[MAXCANDIDATES];
int nretflags,nretflags2,i,n;
getflags(lf->flags, retflag, &nretflags, F_INJURY, F_PAIN, F_NONE);
for (i = 0; i < nretflags; i++) {
@ -1645,14 +1662,23 @@ int move_will_hurt(lifeform_t *lf) {
if (f->id == F_INJURY) {
switch (f->val[0]) {
case IJ_LEGBLEED:
return B_TRUE;
if (!isairborne(lf)) return B_TRUE;
break;
case IJ_WINGBLEED:
getflags(lf->flags, retflag2, &nretflags2, F_FLYING, F_NONE);
for (n = 0; n < nretflags2; n++) {
if (retflag[n]->lifetime == FROMRACE) {
return B_TRUE;
}
}
break;
default:
break;
}
}
}
if (hasbleedinginjury(lf, BP_LEGS)) {
if (hasbleedinginjury(lf, BP_LEGS) && !isairborne(lf)) {
return B_TRUE;
}
return B_FALSE;
@ -1910,7 +1936,7 @@ int closedoor(lifeform_t *lf, object_t *o) {
return B_TRUE;
}
if (lf && lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
if (lf && !canopendoors(lf)) {
if (isplayer(lf)) {
msg("You have no hands with which to close the door!");
}
@ -2491,10 +2517,14 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
}
} else if (iswoozy(lf)) {
rndmove = B_TRUE;
} else if (lfhasflagval(lf, F_INJURY, IJ_TAILBRUISED, NA, NA, NULL) && onein(6)) {
rndmove = B_TRUE;
}
if (rndmove) {
dir = rnd(DC_N, DC_NW);
strafe = B_TRUE;
}
cell = getcellindir(lf->cell, dir);
@ -2509,7 +2539,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
*/
// warn before moving onto dangerous cells
if (onpurpose && isplayer(lf) && !lfhasflag(lf, F_SNEAK)) {
if (onpurpose && isplayer(lf) && !lfhasflag(lf, F_SNEAK) && !rndmove) {
char ques[BUFLEN];
char ch;
if (cell && celldangerous(lf, cell, B_TRUE, &errcode)) {

View File

@ -28,6 +28,8 @@ extern material_t *material,*lastmaterial;
extern recipe_t *firstrecipe,*lastrecipe;
extern skill_t *firstskill, *lastskill;
extern int inaskcoords;
void (*precalclos)(lifeform_t *);
extern object_t *retobs[MAXPILEOBS+1];
@ -1651,8 +1653,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
}
}
if (gamemode == GM_GAMESTARTED) {
if ((gamemode == GM_GAMESTARTED) && !inaskcoords) {
if (o && where->where && !hasflag(o->flags, F_NOGLYPH) && haslos(player, where->where) ) {
needredraw = B_TRUE;
}

2
text.c
View File

@ -771,7 +771,7 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d
}
if (damtype == DT_BITE) return "gore";
if (damtype == DT_SLASH) {
if (lfhasflagval(victim, F_NOBODYPART, BP_HEAD, NA, NA, NULL)) {
if (!hasbp(victim, BP_HEAD)) {
return "bisect";
} else {
if ((getlfsize(victim) >= SZ_MEDIUM) && onein(3)) {