- [+] bones file error:" the lazy minotaur"

- [+] parserace needs to cope with lazy etc.
        - [+] make enum BEHAVIOUR
        - [+] make behaviour_t
            - [+] id
            - [+] name
            - [+] flags
        - [+] killbehaviours()
        - [+] addbehaviour() calls to define them
        - [+] cleanup callsk illbehaviours
        - [+] givebehaviour(lf, enum behaviour)
        - [+] getrandombehaviour()
        - [+] instead of checking f_behaviour->text, use
              findbehaviour(f->behaviour->val[0])->name
        - [+] parserace should handle these and populate wantflags
              appropriately.
- [+] add disease incubation times (instead of getting them right away)
- [+] OT_A_TRIP should be a lot harder on anything with more than 2 legs
- [+] monster fleeing up/down stairs should anger hecta
- [+] reduce short bow damage.
- [+] add composite bow (between short & long)
- [+] need magic/silver weapons to hurt MT_MAGIC things
    - [+] spirits should no lnoger be made of "MAGIC" - make them
          something else. flesh will do.
    - [+] in attack.c, noncorporeal check should also check for silver
          / magic weapons
    - [+] describe noncorporeal in io.c if knowledge is high enough.
- [+] new spell casttype: ct_sounbased. deafness protects.
- [+] Banshee (7hd, spirit, death keen at night) - blue / red 'p'
    - [+] death keen = sonic damage"midnight dirge"
    - [+] but only at night. 
- [+] harpy: 7hd - orange 'A'
    - [+] charm (via sound, so sonic prevents)
    - [+] 50% chance of bone club
    - [+] bite, claw
This commit is contained in:
Rob Pearce 2012-03-30 03:34:24 +00:00
parent 984999d912
commit 53ada31364
15 changed files with 487 additions and 127 deletions

3
ai.c
View File

@ -2475,6 +2475,9 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) { if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) {
specificcheckok = B_FALSE; specificcheckok = B_FALSE;
} }
if (ot->id == OT_S_DEATHKEEN) {
if (!isnighttime()) specificcheckok = B_FALSE;
}
if ((ot->id == OT_S_DANCINGFLAME) || (ot->id == OT_S_CLEANSINGFIRE)) { if ((ot->id == OT_S_DANCINGFLAME) || (ot->id == OT_S_CLEANSINGFIRE)) {
int i; int i;
int found = B_FALSE; int found = B_FALSE;

View File

@ -824,7 +824,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (lfhasflag(victim, F_NONCORPOREAL) && if (lfhasflag(victim, F_NONCORPOREAL) &&
!lfhasflag(lf, F_NONCORPOREAL) ) { !lfhasflag(lf, F_NONCORPOREAL) ) {
// using a magical or blessed weapon? if so you're ok. // using a magical or blessed weapon? if so you're ok.
if (wep && (ismagical(wep) || isblessed(wep)) ) { if (wep && (ismagical(wep) || isblessed(wep) || (wep->material->id == MT_SILVER)) ) {
} else { } else {
weppassthrough = B_TRUE; weppassthrough = B_TRUE;
hit = B_FALSE; hit = B_FALSE;

204
data.c
View File

@ -10,6 +10,7 @@
#include "objects.h" #include "objects.h"
#include "spell.h" #include "spell.h"
extern behaviour_t *firstbehaviour,*lastbehaviour;
extern command_t *firstcommand,*lastcommand; extern command_t *firstcommand,*lastcommand;
extern option_t *firstoption,*lastoption; extern option_t *firstoption,*lastoption;
extern map_t *firstmap; extern map_t *firstmap;
@ -81,6 +82,34 @@ option_t *addoption(enum OPTION id, char *text, int def) {
return a; return a;
} }
behaviour_t *addbehaviour(enum BEHAVIOUR id, char *name) {
behaviour_t *a;
assert(!findbehaviour(id));
// add to the end of the list
if (firstbehaviour == NULL) {
firstbehaviour = malloc(sizeof(behaviour_t));
a = firstbehaviour;
a->prev = NULL;
} else {
// go to end of list
a = lastbehaviour;
a->next = malloc(sizeof(behaviour_t));
a->next->prev = a;
a = a->next;
}
lastbehaviour = a;
a->next = NULL;
// set props
a->id = id;
a->name = strdup(name);
a->flags = addflagpile(NULL, NULL);
return a;
}
command_t *addcommand(enum COMMAND id, char ch, char *desc) { command_t *addcommand(enum COMMAND id, char ch, char *desc) {
command_t *a; command_t *a;
@ -2969,6 +2998,13 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addflag(lastot->flags, F_PLEASESGOD, R_GODDEATH, 4, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODDEATH, 4, NA, NULL);
// l5 // l5
addot(OT_S_DEATHKEEN, "midnight dirge", "Emits a dreadful wailing keen which instantly slays any who hear it.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell will only function at night.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addflag(lastot->flags, F_PLEASESGOD, R_GODDEATH, 5, NA, NULL);
addot(OT_S_HECTASSERVANT, "hecta's hand", "Summons an enormous skeletal hand to drag foes to their doom. BEWARE: the hand will attack anything living, including the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_HECTASSERVANT, "hecta's hand", "Summons an enormous skeletal hand to drag foes to their doom. BEWARE: the hand will attack anything living, including the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
@ -7689,6 +7725,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ATTREQ, A_STR, 50, 60, "10"); addflag(lastot->flags, F_ATTREQ, A_STR, 50, 60, "10");
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_BONE, 33, NA, NULL);
addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 15, OC_WEAPON, SZ_MEDIUM); addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 15, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
addflag(lastot->flags, F_RARITY, H_CAVE, 50, NA, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 50, NA, NULL);
@ -7813,7 +7850,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_SWAMP, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_SWAMP, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 4, NA, NA, NULL); addflag(lastot->flags, F_FIRESPEED, 2, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_DART, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_DART, NA, NA, NULL);
@ -7828,14 +7865,28 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 4, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 4, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 45, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_COMPOSITEBOW, "composite bow", "A short bow, smaller than a longbow but more powerful than a shortbow.", MT_WOOD, 7, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 6, NA, NA, NULL); addflag(lastot->flags, F_FIRESPEED, 6, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 45, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 65, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but slow to reload and needs high strength to use.", MT_WOOD, 8, OC_WEAPON, SZ_MEDIUM); addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but slow to reload and needs high strength to use.", MT_WOOD, 8, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
@ -7844,7 +7895,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 10, NA, NA, NULL); addflag(lastot->flags, F_FIRESPEED, 10, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 6, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 2, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 2, NA, NA, NULL);
@ -7857,7 +7908,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 5, NA, NA, NULL); addflag(lastot->flags, F_FIRESPEED, 5, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 7, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 3, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 3, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL);
@ -7869,7 +7920,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 8, NA, NA, NULL); addflag(lastot->flags, F_FIRESPEED, 8, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 8, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL);
@ -7898,7 +7949,7 @@ void initobjects(void) {
addflag(lastot->flags, F_TWOHANDED, SZ_HUMAN, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, SZ_HUMAN, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 20, NA, NA, NULL); addflag(lastot->flags, F_FIRESPEED, 20, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 3, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 2, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_BULLET, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BULLET, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 2, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 2, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 3, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 3, NA, NA, NULL);
@ -7910,7 +7961,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FIRESPEED, 4, NA, NA, NULL); addflag(lastot->flags, F_FIRESPEED, 4, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 4, NA, NA, NULL);
addflag(lastot->flags, F_AMMOOB, OT_STONE, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_STONE, NA, NA, NULL);
addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL); addflag(lastot->flags, F_AMMOCAPACITY, 1, NA, NA, NULL);
addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL); addflag(lastot->flags, F_RELOADTURNS, 1, NA, NA, NULL);
@ -8069,6 +8120,28 @@ void initrace(void) {
skill_t *sk; skill_t *sk;
int i; int i;
// behaviours
addbehaviour(BH_INSANE, "insane");
addflag(lastbehaviour->flags, F_TERRITORIAL, 2, NA , NA, NULL);
addbehaviour(BH_HUNGRY, "hungry");
addflag(lastbehaviour->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS , NA, NULL);
addbehaviour(BH_TIMID, "timid");
// givebehaviour() will also halve morale
addflag(lastbehaviour->flags, F_FLEEONDAM, B_TRUE, NA , NA, NULL);
addbehaviour(BH_DRUGGED, "drugged");
// givebehaviour() will also remove fleeonxxx flags
addflag(lastbehaviour->flags, F_NOFLEE, B_TRUE, NA , NA, NULL);
addbehaviour(BH_DRUNK, "drunk");
// givebehaviour() will add f_drunk rnd(2,5)
addbehaviour(BH_DETERMINED, "determined");
addflag(lastbehaviour->flags, F_FOLLOWTIME, (DEF_AIFOLLOWTIME*2), NA, NA, NULL);
addbehaviour(BH_LAZY, "lazy");
addflag(lastbehaviour->flags, F_FOLLOWTIME, (DEF_AIFOLLOWTIME/4), NA, NA, NULL);
addbehaviour(BH_MUSCLED, "muscled");
// givebehaviour() will modify maxhp
addbehaviour(BH_SCRAWNY, "scrawny");
// givebehaviour() will modify maxhp
// unique monsters // unique monsters
addrace(R_JAILER, "jailer", 110, '@', C_MAGENTA, MT_FLESH, RC_HUMANOID, "Jailers are generally known for their surplus of brawn and utter lack of brains. This one is no different."); addrace(R_JAILER, "jailer", 110, '@', C_MAGENTA, MT_FLESH, RC_HUMANOID, "Jailers are generally known for their surplus of brawn and utter lack of brains. This one is no different.");
setbodytype(lastrace, BT_HUMANOID); setbodytype(lastrace, BT_HUMANOID);
@ -9237,7 +9310,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANCAST, OT_S_PARALYZE, NA, NA, "pw:2;"); addflag(lastrace->flags, F_CANCAST, OT_S_PARALYZE, NA, NA, "pw:2;");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 8, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 8, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "gazes"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "gazes");
addflag(lastrace->flags, F_CASTTYPE, CT_GAZE, NA, NA, NULL); addflag(lastrace->flags, F_CASTTYPE, OT_NONE, CT_GAZE, NA, NULL);
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL);
@ -9476,9 +9549,10 @@ void initrace(void) {
addflag(lastrace->flags, F_CANCAST, OT_S_PLANTWALK, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_PLANTWALK, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, "pw:1;"); addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, "pw:1;");
addflag(lastrace->flags, F_CASTCHANCE, 70, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 70, NA, NA, NULL);
addflag(lastrace->flags, F_CASTTYPE, OT_S_CHARM, CT_GAZE, NA, NULL);
//addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, 10, 10, NULL); //addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, 10, 10, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_PLANTWALK, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_PLANTWALK, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_CHARM, NA, B_APPENDYOU, "beckons"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_CHARM, NA, B_APPENDYOU, "smiles seductively and beckons");
addflag(lastrace->flags, F_WANTSOBFLAG, F_GEM, B_COVETS, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_GEM, B_COVETS, NA, NULL);
addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
@ -9591,7 +9665,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CASTCHANCE, 50, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 50, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_DISPERSAL, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_DISPERSAL, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_GRAVBOOST, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_GRAVBOOST, NA, NA, NULL);
addflag(lastrace->flags, F_CASTTYPE, CT_GAZE, NA, NA, NULL); addflag(lastrace->flags, F_CASTTYPE, OT_NONE, CT_GAZE, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "gazes"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "gazes");
addflag(lastrace->flags, F_TREMORSENSE, 5, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 5, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
@ -9628,7 +9702,7 @@ void initrace(void) {
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow");
addflag(lastrace->flags, F_CANCAST, OT_S_STUN, 5, 5, "pw:1;"); addflag(lastrace->flags, F_CANCAST, OT_S_STUN, 5, 5, "pw:1;");
addflag(lastrace->flags, F_CASTTYPE, CT_GAZE, NA, NA, NULL); addflag(lastrace->flags, F_CASTTYPE, OT_NONE, CT_GAZE, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_STUN, NA, B_APPENDYOU, "gazes"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_STUN, NA, B_APPENDYOU, "gazes");
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL);
@ -10244,6 +10318,7 @@ void initrace(void) {
addrace(R_GRIFFON, "griffon", 220, 'f', C_YELLOW, MT_FLESH, RC_ANIMAL, "Griffons have a lion's body and the head, torso and forelegs of an eagle."); addrace(R_GRIFFON, "griffon", 220, 'f', C_YELLOW, MT_FLESH, RC_ANIMAL, "Griffons have a lion's body and the head, torso and forelegs of an eagle.");
setbodytype(lastrace, BT_QUADRAPED); setbodytype(lastrace, BT_QUADRAPED);
addbodypart(lastrace, BP_TAIL, NULL); addbodypart(lastrace, BP_TAIL, NULL);
addbodypart(lastrace, BP_WINGS, NULL);
addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
@ -10286,6 +10361,7 @@ void initrace(void) {
addrace(R_HIPPOGRIFF, "hippogriff", 500, 'u', C_YELLOW, MT_FLESH, RC_ANIMAL, "Hippogriffs are fierce hybrids of a horse and an eagle. Their head, wings and claws take the form of the latter."); addrace(R_HIPPOGRIFF, "hippogriff", 500, 'u', C_YELLOW, MT_FLESH, RC_ANIMAL, "Hippogriffs are fierce hybrids of a horse and an eagle. Their head, wings and claws take the form of the latter.");
setbodytype(lastrace, BT_QUADRAPED); setbodytype(lastrace, BT_QUADRAPED);
addbodypart(lastrace, BP_TAIL, NULL); addbodypart(lastrace, BP_TAIL, NULL);
addbodypart(lastrace, BP_WINGS, NULL);
addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, "");
@ -10611,6 +10687,7 @@ void initrace(void) {
addrace(R_MANTICORE, "manticore", 80, 'm', C_RED, MT_FLESH, RC_MAGIC, "Horrific beasts with the body of a lion, bat-like winds and a human head. The tip of their tail contains a mass of iron spikes."); addrace(R_MANTICORE, "manticore", 80, 'm', C_RED, MT_FLESH, RC_MAGIC, "Horrific beasts with the body of a lion, bat-like winds and a human head. The tip of their tail contains a mass of iron spikes.");
setbodytype(lastrace, BT_QUADRAPED); setbodytype(lastrace, BT_QUADRAPED);
addbodypart(lastrace, BP_TAIL, NULL); addbodypart(lastrace, BP_TAIL, NULL);
addbodypart(lastrace, BP_WINGS, NULL);
addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
@ -13139,6 +13216,42 @@ void initrace(void) {
addflag(lastrace->flags, F_CASTCHANCE, 100, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 100, NA, NA, NULL);
addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "hop"); addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "hop");
addrace(R_HARPY, "harpy", 60, 'A', C_ORANGE, MT_FLESH, RC_HUMANOID, "Hideous humanoid females, with the lower body and wings of a vulture."); // 'A' for Avian
setbodytype(lastrace, BT_HUMANOID);
addbodypart(lastrace, BP_WINGS, NULL);
setbodypartname(lastrace, BP_HANDS, "talons");
setbodypartname(lastrace, BP_RIGHTFINGER, "right claw");
setbodypartname(lastrace, BP_LEFTFINGER, "left claw");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_NATURALFLIGHT, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_CANWILL, OT_S_FLIGHT, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FLIGHT, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 7, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 7, NA, NA, NULL);
addflag(lastrace->flags, F_MAXATTACKS, 2, 2, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 6, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain");
addflag(lastrace->flags, F_AVIAN, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "bone club");
addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, 15, 15, "pw:5;");
addflag(lastrace->flags, F_CASTTYPE, OT_S_CHARM, CT_SOUNDBASED, NA, NULL);
addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_CHARM, NA, B_APPENDYOU, "sings a seductive song");
addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL, "A young baby hawk."); // 'A' for Avian addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL, "A young baby hawk."); // 'A' for Avian
setbodytype(lastrace, BT_BIRD); setbodytype(lastrace, BT_BIRD);
lastrace->baseid = R_HAWK; lastrace->baseid = R_HAWK;
@ -13796,7 +13909,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^slithering"); addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^slithering");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "hisses^hissing"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "hisses^hissing");
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "spits"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "spits");
addflag(lastrace->flags, F_CASTTYPE, CT_EYESPIT, NA, NA, NULL); addflag(lastrace->flags, F_CASTTYPE, OT_NONE, CT_EYESPIT, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_S_BLINDNESS, 4, 4, "pw:3;range:2;"); addflag(lastrace->flags, F_CANWILL, OT_S_BLINDNESS, 4, 4, "pw:3;range:2;");
@ -14213,7 +14326,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANINE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANINE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addrace(R_WORMGLUT, "glutwyrm", 25, 'W', C_MAGENTA, MT_FLESH, RC_DRAGON, "Gigantic wyrms who have become so obese over the centuries that they have evolved without wings. They swallow their prey whole, slowly digesting their still living bodies."); addrace(R_WORMGLUT, "glutwyrm", 25, 'W', C_MAGENTA, MT_FLESH, RC_DRAGON, "Gigantic wyrms who have become so obese over the centuries that they have evolved to be wingless. They swallow their prey whole, slowly digesting their still living bodies.");
addbodypart(lastrace, BP_HEAD, NULL); addbodypart(lastrace, BP_HEAD, NULL);
addbodypart(lastrace, BP_TAIL, NULL); addbodypart(lastrace, BP_TAIL, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -15529,6 +15642,37 @@ void initrace(void) {
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_COLD, NA, "15"); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_COLD, NA, "15");
addrace(R_BANSHEE, "banshee", 50, 'p', C_BLUE, MT_FLESH, RC_UNDEAD, "A floating phantom, with wild unbrushed hair.");
setbodytype(lastrace, BT_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_HIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL);
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_VERYRARE, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 7, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 7, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_HASATTACK, OT_TOUCHNECROTIC, 8, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_S_DEATHKEEN, 100, 100, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_DEATHKEEN, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_INDUCEFEAR, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL);
addrace(R_GHAST, "ghast", 50, 'Z', C_BOLDGREEN, MT_FLESH, RC_UNDEAD, "A more slender and ghost-like form of ghoul. Ghasts are cunning and deadly, and possess a paralyzing touch."); addrace(R_GHAST, "ghast", 50, 'Z', C_BOLDGREEN, MT_FLESH, RC_UNDEAD, "A more slender and ghost-like form of ghoul. Ghasts are cunning and deadly, and possess a paralyzing touch.");
setbodytype(lastrace, BT_HUMANOID); setbodytype(lastrace, BT_HUMANOID);
setbodypartname(lastrace, BP_HANDS, "claws"); setbodypartname(lastrace, BP_HANDS, "claws");
@ -15559,7 +15703,7 @@ void initrace(void) {
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addrace(R_GHOST, "ghost", 50, 'p', C_GREY, MT_MAGIC, RC_UNDEAD, "Wispy spirits formed when a soul refuses to depart the earthly realm after death, ghosts exist part way between dimensions. The sight of a ghost can cause fear in all who behold it, and their ethereal nature makes them immune to most attacks."); // p for sPirit addrace(R_GHOST, "ghost", 50, 'p', C_GREY, MT_FLESH, RC_UNDEAD, "Wispy spirits formed when a soul refuses to depart the earthly realm after death, ghosts exist part way between dimensions. The sight of a ghost can cause fear in all who behold it, and their ethereal nature makes them immune to most attacks."); // p for sPirit
setbodytype(lastrace, BT_HUMANOID); setbodytype(lastrace, BT_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL);
@ -15691,7 +15835,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HITCONFERVALS, P_ROT, 3, NA, NULL); // strong! addflag(lastrace->flags, F_HITCONFERVALS, P_ROT, 3, NA, NULL); // strong!
addflag(lastrace->flags, F_CANCAST, OT_S_FEAR, 50, 50, "pw:3;"); addflag(lastrace->flags, F_CANCAST, OT_S_FEAR, 50, 50, "pw:3;");
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FEAR, NA, B_APPENDYOU, "gazes"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FEAR, NA, B_APPENDYOU, "gazes");
addflag(lastrace->flags, F_CASTTYPE, CT_GAZE, NA, NA, NULL); addflag(lastrace->flags, F_CASTTYPE, OT_NONE, CT_GAZE, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
@ -16306,7 +16450,7 @@ void initskills(void) {
addskilldesc(SK_FIRSTAID, PR_INEPT, "- Determines how long poison effects will last.", B_FALSE); addskilldesc(SK_FIRSTAID, PR_INEPT, "- Determines how long poison effects will last.", B_FALSE);
addskilldesc(SK_FIRSTAID, PR_NOVICE, "+2 hit points per level.", B_FALSE); addskilldesc(SK_FIRSTAID, PR_NOVICE, "+2 hit points per level.", B_FALSE);
addskilldesc(SK_FIRSTAID, PR_BEGINNER, "+4 hit points per level.", B_FALSE); addskilldesc(SK_FIRSTAID, PR_BEGINNER, "+4 hit points per level.", B_FALSE);
addskilldesc(SK_FIRSTAID, PR_BEGINNER, "You now notice the onset of poison.", B_TRUE); addskilldesc(SK_FIRSTAID, PR_BEGINNER, "You now recognise the onset of poison or sickness.", B_TRUE);
addskilldesc(SK_FIRSTAID, PR_ADEPT, "+6 hit points per level.", B_FALSE); addskilldesc(SK_FIRSTAID, PR_ADEPT, "+6 hit points per level.", B_FALSE);
addskilldesc(SK_FIRSTAID, PR_ADEPT, "^gYou can now recognise when poison is potentially fatal.^n", B_TRUE); addskilldesc(SK_FIRSTAID, PR_ADEPT, "^gYou can now recognise when poison is potentially fatal.^n", B_TRUE);
addskilldesc(SK_FIRSTAID, PR_SKILLED, "+8 hit points per level.", B_FALSE); addskilldesc(SK_FIRSTAID, PR_SKILLED, "+8 hit points per level.", B_FALSE);
@ -16619,6 +16763,32 @@ void killoption(option_t *w) {
} }
} }
void killbehaviour(behaviour_t *b) {
behaviour_t *nextone, *lastone;
// free mem
if (b->name) free(b->name);
killflagpile(b->flags);
// remove from list
nextone = b->next;
if (nextone != NULL) {
nextone->prev = b->prev;
} else { /* last */
lastbehaviour = b->prev;
}
if (b->prev == NULL) {
/* first */
nextone = b->next;
free(firstbehaviour);
firstbehaviour = nextone;
} else {
lastone = b->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void killcommand(command_t *cmd) { void killcommand(command_t *cmd) {
command_t *nextone, *lastone; command_t *nextone, *lastone;

2
data.h
View File

@ -2,6 +2,7 @@
void addbonustext(flagpile_t *fp, enum FLAG fid, char *text); void addbonustext(flagpile_t *fp, enum FLAG fid, char *text);
option_t *addoption(enum OPTION id, char *text, int def); option_t *addoption(enum OPTION id, char *text, int def);
behaviour_t *addbehaviour(enum BEHAVIOUR id, char *name);
command_t *addcommand(enum COMMAND id, char c, char *desc); command_t *addcommand(enum COMMAND id, char c, char *desc);
void initcommands(void); void initcommands(void);
void initjobs(void); void initjobs(void);
@ -10,6 +11,7 @@ void initoptions(void);
void initrace(void); void initrace(void);
void initraceclasses(void); void initraceclasses(void);
void initskills(void); void initskills(void);
void killbehaviour(behaviour_t *b);
void killcommand(command_t *cmd); void killcommand(command_t *cmd);
void killoption(option_t *o); void killoption(option_t *o);
void make_basic_shop(flagpile_t *fp); void make_basic_shop(flagpile_t *fp);

35
defs.h
View File

@ -322,6 +322,19 @@
#define MAXDIR_MAP 15 #define MAXDIR_MAP 15
enum BEHAVIOUR {
BH_NONE = 0,
BH_INSANE,
BH_HUNGRY,
BH_TIMID,
BH_DRUGGED,
BH_DRUNK,
BH_DETERMINED,
BH_LAZY,
BH_MUSCLED,
BH_SCRAWNY,
};
// relative directions // relative directions
enum RELATIVEDIR { enum RELATIVEDIR {
RD_FORWARDS, RD_FORWARDS,
@ -489,7 +502,8 @@ enum COLOUR {
enum CASTTYPE { enum CASTTYPE {
CT_NORMAL = 0, CT_NORMAL = 0,
CT_GAZE, CT_GAZE,
CT_EYESPIT CT_EYESPIT,
CT_SOUNDBASED,
}; };
enum DRAINTYPE { enum DRAINTYPE {
@ -1123,6 +1137,7 @@ enum RACE {
R_DOGWAR, R_DOGWAR,
R_ELEPHANT, R_ELEPHANT,
R_GYRFALCON, R_GYRFALCON,
R_HARPY,
R_HAWK, R_HAWK,
R_HAWKYOUNG, R_HAWKYOUNG,
R_HAWKBLOOD, R_HAWKBLOOD,
@ -1191,6 +1206,7 @@ enum RACE {
R_LINGTRAPPER, R_LINGTRAPPER,
R_QUASIT, R_QUASIT,
// undead // undead
R_BANSHEE,
R_GHAST, R_GHAST,
R_GHOST, R_GHOST,
R_GHOUL, R_GHOUL,
@ -1514,6 +1530,7 @@ enum OBTYPE {
OT_S_BLIGHT, OT_S_BLIGHT,
OT_S_COMMANDUNDEAD, OT_S_COMMANDUNDEAD,
OT_S_CURSE, OT_S_CURSE,
OT_S_DEATHKEEN,
OT_S_DRAINLIFE, OT_S_DRAINLIFE,
OT_S_FEAR, OT_S_FEAR,
OT_S_FLAYFLESH, OT_S_FLAYFLESH,
@ -2162,6 +2179,7 @@ enum OBTYPE {
// projectile weapons // projectile weapons
OT_BLOWGUN, OT_BLOWGUN,
OT_BOW, OT_BOW,
OT_COMPOSITEBOW,
OT_CROSSBOW, OT_CROSSBOW,
OT_CROSSBOWHAND, OT_CROSSBOWHAND,
OT_LONGBOW, OT_LONGBOW,
@ -2243,6 +2261,7 @@ enum DEPTH {
}; };
enum NOISETYPE { enum NOISETYPE {
N_DEATHKEEN,
N_GETANGRY, N_GETANGRY,
N_WALK, N_WALK,
N_FLY, N_FLY,
@ -2835,8 +2854,7 @@ enum FLAG {
// if you won by becoming a god, v1 = godid // if you won by becoming a god, v1 = godid
// if you won by becoming a demigod, v1 = godid // if you won by becoming a demigod, v1 = godid
// text = copied F_GODFLAG text from god. // text = copied F_GODFLAG text from god.
F_BEHAVIOUR, // textual field describing special behaviour for this F_BEHAVIOUR, // v0 = enum behaviour.
// lf
F_RNDSPELLCOUNT, // this monster starts with v0 random spells. F_RNDSPELLCOUNT, // this monster starts with v0 random spells.
// needs to also have either f_rndspellschool OR // needs to also have either f_rndspellschool OR
// f_rndspellposs. // f_rndspellposs.
@ -3300,8 +3318,8 @@ enum FLAG {
F_CONFUSED, // move randomly about F_CONFUSED, // move randomly about
F_DEAF, // cannot hear F_DEAF, // cannot hear
F_NEEDOBFORSPELLS, // lf can only cast spells if it has object v0 F_NEEDOBFORSPELLS, // lf can only cast spells if it has object v0
F_CASTTYPE, // lf uses enum CASTTYPE v0 for spells F_CASTTYPE, // lf uses enum CASTTYPE v1 for spellid v0. (ot_none=all)
// optional v1 is colour for casttype-based animations // optional v2 is colour for casttype-based animations
// (ie. spit spells) // (ie. spit spells)
F_CAFFEINATED, // can't sleep. F_CAFFEINATED, // can't sleep.
F_CANEATRAW, // lf can eat raw food with no issues F_CANEATRAW, // lf can eat raw food with no issues
@ -3822,6 +3840,13 @@ enum COMMAND {
}; };
typedef struct behaviour_s {
enum BEHAVIOUR id;
char *name;
struct flagpile_s *flags;
struct behaviour_s *next, *prev;
} behaviour_t;
typedef struct npcname_s { typedef struct npcname_s {
char *name; char *name;
int valid; int valid;

13
io.c
View File

@ -1613,11 +1613,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
case F_POISONED: case F_POISONED:
pt = findpoisontype(f->val[0]); pt = findpoisontype(f->val[0]);
if (isplayer(lf)) { if (isplayer(lf)) {
if (streq(pt->desc, "Sick")) { if (streq(pt->desc, "Sick") || (pt->id == P_FOOD) || (pt->id == P_FOODBAD)) {
msg("^%cYou have contracted %s.", getlfcol(lf, CC_VBAD), pt->name); msg("^%cYou have contracted %s.", getlfcol(lf, CC_VBAD), pt->name);
} else { } else {
msg("^%cYou are sick with %s.", getlfcol(lf, CC_VBAD), pt->name); msg("^%cYou are sick with %s.", getlfcol(lf, CC_VBAD), pt->name);
} }
more();
} else { } else {
msg("^%c%s looks very sick.", getlfcol(lf, CC_VBAD), lfname); msg("^%c%s looks very sick.", getlfcol(lf, CC_VBAD), lfname);
} }
@ -2266,15 +2267,6 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
case F_FRIENDLY: case F_FRIENDLY:
msg("%s no longer looks quite so friendly!", lfname); msg("%s no longer looks quite so friendly!", lfname);
break; break;
case F_INCUBATING:
if (isplayer(lf)) {
poisontype_t *pt;
pt = findpoisontype(f->val[0]);
if (pt) {
msg("^%cYour body has fought off %s.", getlfcol(lf, CC_GOOD), pt->name);
}
}
break;
case F_POISONED: case F_POISONED:
msg("^%c%s %s less sick now.^n", getlfcol(lf, CC_VGOOD), lfname, isplayer(lf) ? "feel" : "looks"); msg("^%c%s %s less sick now.^n", getlfcol(lf, CC_VGOOD), lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE; donesomething = B_TRUE;
@ -7174,6 +7166,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel
case F_LEVITATING: if (lorelev >= PR_NOVICE) sprintf(buf, "Can levitate at will"); break; case F_LEVITATING: if (lorelev >= PR_NOVICE) sprintf(buf, "Can levitate at will"); break;
case F_MEDITATES: if (lorelev >= PR_ADEPT) sprintf(buf, "Meditates to retain awareness while sleeping."); break; case F_MEDITATES: if (lorelev >= PR_ADEPT) sprintf(buf, "Meditates to retain awareness while sleeping."); break;
case F_MPMOD: if (f->val[0] > 0) sprintf(buf, "+%d Mana", f->val[0]); break; case F_MPMOD: if (f->val[0] > 0) sprintf(buf, "+%d Mana", f->val[0]); break;
case F_NONCORPOREAL: if (lorelev >= PR_NOVICE) sprintf(buf, "Only affected by blessed, magic or silver weapons"); break;
case F_NOSLEEP: if (lorelev >= PR_BEGINNER) sprintf(buf, "Does not sleep"); break; case F_NOSLEEP: if (lorelev >= PR_BEGINNER) sprintf(buf, "Does not sleep"); break;
case F_PHALANX: if (lorelev >= PR_ADEPT) sprintf(buf, "Gains extra defence when in a pack."); break; case F_PHALANX: if (lorelev >= PR_ADEPT) sprintf(buf, "Gains extra defence when in a pack."); break;
case F_PHOTOMEM: sprintf(buf, "Photographic memory"); break; case F_PHOTOMEM: sprintf(buf, "Photographic memory"); break;

205
lf.c
View File

@ -32,6 +32,7 @@ extern int enteringmap;
extern map_t *firstmap; extern map_t *firstmap;
extern race_t *firstrace, *lastrace; extern race_t *firstrace, *lastrace;
extern raceclass_t *firstraceclass, *lastraceclass; extern raceclass_t *firstraceclass, *lastraceclass;
extern behaviour_t *firstbehaviour, *lastbehaviour;
extern job_t *firstjob, *lastjob; extern job_t *firstjob, *lastjob;
extern skill_t *firstskill, *lastskill; extern skill_t *firstskill, *lastskill;
extern poisontype_t *firstpoisontype,*lastpoisontype; extern poisontype_t *firstpoisontype,*lastpoisontype;
@ -835,6 +836,7 @@ int caneat(lifeform_t *lf, object_t *o) {
int canhaverandombehaviour(lifeform_t *lf) { int canhaverandombehaviour(lifeform_t *lf) {
if (lfhasflag(lf, F_BEHAVIOUR)) return B_FALSE;
if (isundead(lf)) return B_FALSE; if (isundead(lf)) return B_FALSE;
if (isgod(lf)) return B_FALSE; if (isgod(lf)) return B_FALSE;
if (getraceclass(lf) == RC_HUMANOID) { if (getraceclass(lf) == RC_HUMANOID) {
@ -1609,11 +1611,14 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
int power; int power;
int spellblessed = B_UNCURSED; int spellblessed = B_UNCURSED;
objecttype_t *sp; objecttype_t *sp;
enum CASTTYPE casttype = CT_NORMAL;
if (fromob) { if (fromob) {
spellblessed = fromob->blessed; spellblessed = fromob->blessed;
power = getobspellpower(fromob, lf); power = getobspellpower(fromob, lf);
} else { } else {
flag_t *ctf;
spellblessed = B_UNCURSED; spellblessed = B_UNCURSED;
power = getspellpower(lf, sid); power = getspellpower(lf, sid);
// check whether we _can_ cast it. // check whether we _can_ cast it.
@ -1682,6 +1687,14 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
return B_TRUE; return B_TRUE;
} }
} }
ctf = lfhasflagval(lf, F_CASTTYPE, sid, NA, NA, NULL);
if (!ctf) {
ctf = lfhasflagval(lf, F_CASTTYPE, OT_NONE, NA, NA, NULL);
}
if (ctf) {
casttype = ctf->val[1];
}
} }
sp = findot(sid); sp = findot(sid);
@ -1808,7 +1821,14 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
// announce // announce
if (!isplayer(lf) && !fromob) { if (!isplayer(lf) && !fromob) {
int doannounce = B_FALSE;
if (cansee(player, lf)) { if (cansee(player, lf)) {
doannounce = B_TRUE;
} else if ((casttype == CT_SOUNDBASED) && canhear(player, lf->cell, SV_TALK)) {
doannounce = B_TRUE;
}
if (doannounce) {
char lfname[BUFLEN]; char lfname[BUFLEN];
char whattosay[BUFLEN]; char whattosay[BUFLEN];
getlfname(lf, lfname); getlfname(lf, lfname);
@ -1851,23 +1871,28 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
// eye protection will stop some spells! // eye protection will stop some spells!
if (targcell && targcell->lf) { if (targcell && targcell->lf) {
flag_t *casttype;
lifeform_t *victim; lifeform_t *victim;
victim = targcell->lf; victim = targcell->lf;
casttype = lfhasflag(lf, F_CASTTYPE); int protected = B_FALSE;
if (casttype) { object_t *protob = NULL;
object_t *protob = NULL; switch (casttype) {
switch (casttype->val[0]) { case CT_EYESPIT:
case CT_EYESPIT: protob = getarmour(victim, BP_EYES);
protob = getarmour(victim, BP_EYES); if (protob) protected = B_TRUE;
break; break;
case CT_GAZE: case CT_GAZE:
protob = eyesshaded(victim); protob = eyesshaded(victim);
break; if (protob) protected = B_TRUE;
default: break;
protob = NULL; case CT_SOUNDBASED:
break; if (isdeaf(victim)) protected = B_TRUE;
} break;
default:
protob = NULL;
protected = B_FALSE;
break;
}
if (protected) {
if (protob) { if (protob) {
if (isplayer(victim)) { if (isplayer(victim)) {
char gbuf[BUFLEN]; char gbuf[BUFLEN];
@ -1879,8 +1904,16 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
getlfname(victim, lfname); getlfname(victim, lfname);
msg("%s%s %s protects it.", lfname, getpossessive(lfname), noprefix(gbuf) ); msg("%s%s %s protects it.", lfname, getpossessive(lfname), noprefix(gbuf) );
} }
return B_FALSE; } else {
if (isplayer(victim)) {
msg("You are unaffected.");
} else if (cansee(player, victim)) {
char lfname[BUFLEN];
getlfname(victim, lfname);
msg("%s is unaffected.", lfname);
}
} }
return B_FALSE;
} }
} }
@ -2549,6 +2582,24 @@ int countinnateattacks(lifeform_t *lf) {
} }
int countlegs(lifeform_t *lf) {
enum BODYPART bp;
int legs = 0;
for (bp = 0; bp <= MAXBODYPARTS; bp++) {
if (hasbp(lf, bp)) {
switch (bp) {
case BP_LEGS:
case BP_FRONTLEGS:
case BP_BACKLEGS:
legs += 2;
break;
default: break;
}
}
}
return legs;
}
int countnearbyallies(lifeform_t *lf) { int countnearbyallies(lifeform_t *lf) {
lifeform_t *l; lifeform_t *l;
int count = 0; int count = 0;
@ -5341,6 +5392,14 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) {
} }
} }
behaviour_t *findbehaviour(enum BEHAVIOUR bid) {
behaviour_t *b;
for (b = firstbehaviour ; b ; b = b->next) {
if (b->id == bid) return b;
}
return NULL;
}
job_t *findjob(enum JOB jobid) { job_t *findjob(enum JOB jobid) {
job_t *j; job_t *j;
for (j = firstjob ; j ; j = j->next) { for (j = firstjob ; j ; j = j->next) {
@ -5613,7 +5672,8 @@ int flee(lifeform_t *lf) {
if (isplayer(thisone)) { if (isplayer(thisone)) {
pleasegodmaybe(R_GODMERCY, 5); pleasegodmaybe(R_GODMERCY, 5);
if ((lf->lastdamlf == player->id) || cansee(player, lf)) { if ((lf->lastdamlf == player->id) || cansee(player, lf)) {
// ie. only if the player // ie. only if the player saw them run away, or has already
// attacked them.
angergodmaybe(R_GODDEATH, 10, GA_MERCY); angergodmaybe(R_GODDEATH, 10, GA_MERCY);
} }
} }
@ -5684,6 +5744,15 @@ int flee(lifeform_t *lf) {
if (stairs && !lfhasflag(lf, F_NOSTAIRS)) { if (stairs && !lfhasflag(lf, F_NOSTAIRS)) {
if (db) dblog("%s - trying to flee via %s", lfname, stairs->type->name); if (db) dblog("%s - trying to flee via %s", lfname, stairs->type->name);
if (!usestairs(lf, stairs, B_TRUE, B_TRUE)) { if (!usestairs(lf, stairs, B_TRUE, B_TRUE)) {
// success
if (isplayer(fleefrom)) {
pleasegodmaybe(R_GODMERCY, 5);
if ((lf->lastdamlf == player->id) || cansee(player, lf)) {
// ie. only if the player saw them run away, or has already
// attacked them.
angergodmaybe(R_GODDEATH, 10, GA_MERCY);
}
}
return B_TRUE; return B_TRUE;
} }
if (db) dblog("%s - failed to flee via %s", lfname, stairs->type->name); if (db) dblog("%s - failed to flee via %s", lfname, stairs->type->name);
@ -7833,6 +7902,11 @@ int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, flag_t *noiseflag,
} }
return B_FALSE; return B_FALSE;
} }
} else if (nid == N_DEATHKEEN) {
if (volume) *volume = SV_TALK;
if (heartext) strcpy(heartext, "the dread wailing of death!");
if (seetext) strcpy(seetext, "wails with the power of death!");
return B_FALSE;
} else if (nid == N_SONICBOLT) { } else if (nid == N_SONICBOLT) {
if (volume) *volume = 5; if (volume) *volume = 5;
if (heartext) strcpy(heartext, "a ear-splitting burst of sound!"); if (heartext) strcpy(heartext, "a ear-splitting burst of sound!");
@ -8543,8 +8617,12 @@ char *real_getlfname(lifeform_t *lf, char *buf, lifeform_t *usevis, int showall,
if (dobehaviour) { if (dobehaviour) {
f = lfhasflag(lf, F_BEHAVIOUR); f = lfhasflag(lf, F_BEHAVIOUR);
if (f) { if (f) {
strcat(descstring, f->text); behaviour_t *b;
strcat(descstring, " "); b = findbehaviour(f->val[0]);
if (b) {
strcat(descstring, b->name);
strcat(descstring, " ");
}
} }
} }
@ -8961,6 +9039,29 @@ object_t *getrandomarmour(lifeform_t *lf, lifeform_t *attacker) {
return o; return o;
} }
enum BEHAVIOUR getrandombehaviour(void) {
behaviour_t *b;
int numb = 0,sel;
enum BEHAVIOUR selb = BH_NONE;
for (b = firstbehaviour ; b ; b = b->next) {
numb++;
}
sel = rnd(0,numb-1);
numb = 0;
for (b = firstbehaviour ; b ; b = b->next) {
if (numb == sel) {
selb = b->id;
break;
}
numb++;
}
if (selb == BH_NONE) {
// should never happen!
assert("getrandombehaviour() failed!" == 0);
}
return selb;
}
// pick a random major body part // pick a random major body part
// ie. head, body, arms/hands, legs, wings, tail // ie. head, body, arms/hands, legs, wings, tail
enum BODYPART getrandomcorebp(lifeform_t *lf, lifeform_t *attacker) { enum BODYPART getrandomcorebp(lifeform_t *lf, lifeform_t *attacker) {
@ -9758,6 +9859,39 @@ long getxpforlev(int level) {
return needxp; return needxp;
} }
void givebehaviour(lifeform_t *lf, enum BEHAVIOUR bid) {
behaviour_t *b;
flag_t *f;
b = findbehaviour(bid);
if (!b) return;
addflag(lf->flags, F_BEHAVIOUR, bid, NA, NA, NULL);
copyflags(lf->flags, b->flags, FROMRACE);
switch (bid) {
case BH_TIMID:
f = lfhasflag(lf, F_MORALE);
if (f) {
f->val[0] /= 2;
}
break;
case BH_DRUGGED:
killflagsofid(lf->flags, F_FLEEONDAM);
killflagsofid(lf->flags, F_FLEEONHPPCT);
break;
case BH_DRUNK:
addflag(lf->flags, F_DRUNK, rnd(2,5), NA, NA, NULL);
case BH_MUSCLED:
lf->maxhp = pctof(rnd(125,200), lf->maxhp); // 25-100% more hp
lf->hp = lf->maxhp;
break;
case BH_SCRAWNY:
lf->maxhp = pctof(rnd(50,75), lf->maxhp); // 25-50% less hp
limit(&(lf->maxhp), 1, NA);
lf->hp = lf->maxhp;
break;
default: break;
}
}
void givejob(lifeform_t *lf, enum JOB jobid) { void givejob(lifeform_t *lf, enum JOB jobid) {
job_t *j; job_t *j;
flag_t *f; flag_t *f;
@ -11601,11 +11735,13 @@ flag_t *lfhasknownflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int
} }
// returns radius of light produces // returns radius of light produces
int lfproduceslight(lifeform_t *lf) { int lfproduceslight(lifeform_t *lf, object_t **fromwhat) {
int temp = 0; int temp = 0;
int radius = 0; int radius = 0;
object_t *o; object_t *o;
if (fromwhat) *fromwhat = NULL;
// lf producing light itself? // lf producing light itself?
sumflags(lf->flags, F_PRODUCESLIGHT, &temp, NULL, NULL); sumflags(lf->flags, F_PRODUCESLIGHT, &temp, NULL, NULL);
if (temp) radius = temp; if (temp) radius = temp;
@ -11616,6 +11752,7 @@ int lfproduceslight(lifeform_t *lf) {
temp = obproduceslight(o); temp = obproduceslight(o);
if (temp > radius) { if (temp > radius) {
radius = temp; radius = temp;
if (fromwhat) *fromwhat = o;
} }
} }
} }
@ -15585,7 +15722,8 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume,
if (isdead(noisemaker)) { if (isdead(noisemaker)) {
msg("The dying %s %s.", noprefix(lfname), realseetext); msg("The dying %s %s.", noprefix(lfname), realseetext);
} else { } else {
msg("%s %s.", lfname, realseetext); msg("%s %s%s", lfname, realseetext,
(realseetext[strlen(realseetext)-1] == '!') ? "" : ".");
} }
rv = B_TRUE; rv = B_TRUE;
} }
@ -15785,6 +15923,7 @@ enum NOISECLASS noisetypetoclass(enum NOISETYPE nt) {
case N_FLY: case N_FLY:
return NC_MOVEMENT; return NC_MOVEMENT;
case N_SONICBOLT: case N_SONICBOLT:
case N_DEATHKEEN:
case N_WARCRY: case N_WARCRY:
return NC_SPELLEFFECT; return NC_SPELLEFFECT;
default: default:
@ -16061,16 +16200,18 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char
if (ii->val[2] < 1) ii->val[2] = 1; if (ii->val[2] < 1) ii->val[2] = 1;
if (getskill(lf, SK_FIRSTAID) >= PR_BEGINNER) { if (getskill(lf, SK_FIRSTAID) >= PR_BEGINNER) {
ii->known = B_TRUE; ii->known = B_TRUE;
msg("You feel %s coming on more quickly.", pt->name); msg("^BYou feel %s coming on more quickly.", pt->name);
} }
} else { } else {
char ftext[BUFLEN]; char ftext[BUFLEN];
sprintf(ftext, "%d^%s", power, fromwhat); sprintf(ftext, "%d^%s", power, fromwhat);
ii = addflag(lf->flags, F_INCUBATING, ptype, power, pt->incubationtime, ftext); ii = addflag(lf->flags, F_INCUBATING, ptype, pt->incubationtime, howlong, ftext);
ii->obfrom = srcrace ? srcrace->id : NA; ii->obfrom = srcrace ? srcrace->id : NA;
if (getskill(lf, SK_FIRSTAID) >= PR_BEGINNER) { if (getskill(lf, SK_FIRSTAID) >= PR_BEGINNER) {
ii->known = B_TRUE; ii->known = B_TRUE;
msg("You feel %s coming on.", pt->name); msg("^BYou feel %s coming on.", pt->name);
} else {
ii->known = B_FALSE;
} }
} }
} else { } else {
@ -19485,8 +19626,9 @@ void startlfturn(lifeform_t *lf) {
} else if (f->val[0] == P_MIGRAINE) { } else if (f->val[0] == P_MIGRAINE) {
// sleeping will avoid all migraine effects // sleeping will avoid all migraine effects
if (!asleep && !ko) { if (!asleep && !ko) {
object_t *lamp = NULL;
int amt; int amt;
amt = lfproduceslight(lf); amt = lfproduceslight(lf, &lamp);
if (amt) { if (amt) {
int dam; int dam;
// note: amt will be doubled due to light vulnerability, // note: amt will be doubled due to light vulnerability,
@ -19495,7 +19637,13 @@ void startlfturn(lifeform_t *lf) {
limit(&dam, 1, NA); limit(&dam, 1, NA);
losehp(lf, amt, DT_LIGHT, NULL, "a migraine"); losehp(lf, amt, DT_LIGHT, NULL, "a migraine");
if (isplayer(lf)) { if (isplayer(lf)) {
msg("Your head explodes in pain at your light!"); char obname[BUFLEN];
if (lamp) {
getobname(lamp, obname, lamp->amt);
} else {
strcpy(obname, "a body"); // noprefix will strip the 'a '
}
msg("Your head explodes in pain at the light from your %s!", noprefix(obname));
} }
} }
} }
@ -21439,6 +21587,11 @@ int validateraces(void) {
printf("ERROR in race '%s' - duplicate f_startatt flags detected.\n", r->name); printf("ERROR in race '%s' - duplicate f_startatt flags detected.\n", r->name);
goterror = B_TRUE; goterror = B_TRUE;
} }
if (strstr(r->desc, "wings") && !hasbp(lf, BP_WINGS)) {
printf("ERROR in race '%s' - description refers to wings but race has no bp_wings.\n", r->name);
goterror = B_TRUE;
}
if (!hasflag(r->flags, F_SIZE)) { if (!hasflag(r->flags, F_SIZE)) {

6
lf.h
View File

@ -79,6 +79,7 @@ void copycorpseflags(flagpile_t *dst, flagpile_t *src);
int continuedigging(lifeform_t *lf); int continuedigging(lifeform_t *lf);
int continuerepairing(lifeform_t *lf, flag_t *repairflag); int continuerepairing(lifeform_t *lf, flag_t *repairflag);
int countinnateattacks(lifeform_t *lf); int countinnateattacks(lifeform_t *lf);
int countlegs(lifeform_t *lf);
int countnearbyallies(lifeform_t *lf); int countnearbyallies(lifeform_t *lf);
int countnearbyhurtallies(lifeform_t *lf); int countnearbyhurtallies(lifeform_t *lf);
int countplantsinsight(lifeform_t *lf); int countplantsinsight(lifeform_t *lf);
@ -104,6 +105,7 @@ int fall(lifeform_t *lf, lifeform_t *fromlf, int announce);
int fallasleep(lifeform_t *lf, enum SLEEPTYPE how, int howlong); int fallasleep(lifeform_t *lf, enum SLEEPTYPE how, int howlong);
int fall_from_air(lifeform_t *lf); int fall_from_air(lifeform_t *lf);
void fightback(lifeform_t *lf, lifeform_t *attacker); void fightback(lifeform_t *lf, lifeform_t *attacker);
behaviour_t *findbehaviour(enum BEHAVIOUR bid);
job_t *findjob(enum JOB jobid); job_t *findjob(enum JOB jobid);
job_t *findjobbyname(char *name); job_t *findjobbyname(char *name);
lifeform_t *findlf(map_t *m, int lfid); lifeform_t *findlf(map_t *m, int lfid);
@ -241,6 +243,7 @@ enum POISONSEVERITY getpoisonseverity(enum POISONTYPE ptype);
int getraceclass(lifeform_t *lf); int getraceclass(lifeform_t *lf);
int getracerarity(map_t *map, enum RACE rid, enum RARITY *rr); int getracerarity(map_t *map, enum RACE rid, enum RARITY *rr);
object_t *getrandomarmour(lifeform_t *lf, lifeform_t *attacker); object_t *getrandomarmour(lifeform_t *lf, lifeform_t *attacker);
enum BEHAVIOUR getrandombehaviour(void);
enum BODYPART getrandomcorebp(lifeform_t *lf, lifeform_t *attacker); enum BODYPART getrandomcorebp(lifeform_t *lf, lifeform_t *attacker);
race_t *getrandomcorpserace(cell_t *c); race_t *getrandomcorpserace(cell_t *c);
job_t *getrandomjob(int onlyplayerjobs); job_t *getrandomjob(int onlyplayerjobs);
@ -269,6 +272,7 @@ object_t *getweapon(lifeform_t *lf);
int getweapons(lifeform_t *lf, int meleeonly, object_t **wep, flag_t **damflag, int *lastweaponidx, obpile_t **op, int *nweps); int getweapons(lifeform_t *lf, int meleeonly, object_t **wep, flag_t **damflag, int *lastweaponidx, obpile_t **op, int *nweps);
enum SKILLLEVEL getweaponskill(lifeform_t *lf, object_t *o); enum SKILLLEVEL getweaponskill(lifeform_t *lf, object_t *o);
long getxpforlev(int level); long getxpforlev(int level);
void givebehaviour(lifeform_t *lf, enum BEHAVIOUR bid);
void givejob(lifeform_t *lf, enum JOB jobid); void givejob(lifeform_t *lf, enum JOB jobid);
void givesubjob(lifeform_t *lf, enum SUBJOB sj); void givesubjob(lifeform_t *lf, enum SUBJOB sj);
int givemoney(lifeform_t *from, lifeform_t *to, int amt); int givemoney(lifeform_t *from, lifeform_t *to, int amt);
@ -293,7 +297,7 @@ flag_t *lfhasflag(lifeform_t *lf, enum FLAG fid);
flag_t *lfhasflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, char *text); flag_t *lfhasflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, char *text);
flag_t *lfhasknownflag(lifeform_t *lf, enum FLAG fid); flag_t *lfhasknownflag(lifeform_t *lf, enum FLAG fid);
flag_t *lfhasknownflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, /*@null@*/ char *text); flag_t *lfhasknownflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, /*@null@*/ char *text);
int lfproduceslight(lifeform_t *lf); int lfproduceslight(lifeform_t *lf, object_t **fromwhat);
int lockpick(lifeform_t *lf, cell_t *targcell, object_t *target, object_t *device); int lockpick(lifeform_t *lf, cell_t *targcell, object_t *target, object_t *device);
void loseobflags(lifeform_t *lf, object_t *o, int kind); void loseobflags(lifeform_t *lf, object_t *o, int kind);
int hasbp(lifeform_t *lf, enum BODYPART bp); int hasbp(lifeform_t *lf, enum BODYPART bp);

89
map.c
View File

@ -23,6 +23,7 @@ int enteringmap = B_FALSE;
extern habitat_t *firsthabitat,*lasthabitat; extern habitat_t *firsthabitat,*lasthabitat;
extern job_t *firstjob; extern job_t *firstjob;
extern map_t *firstmap,*lastmap; extern map_t *firstmap,*lastmap;
extern behaviour_t *firstbehaviour,*lastbehaviour;
extern region_t *firstregion,*lastregion; extern region_t *firstregion,*lastregion;
extern regionoutline_t *firstregionoutline,*lastregionoutline; extern regionoutline_t *firstregionoutline,*lastregionoutline;
extern regiontype_t *firstregiontype,*lastregiontype; extern regiontype_t *firstregiontype,*lastregiontype;
@ -223,6 +224,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok
flagpile_t *wantflags = NULL; flagpile_t *wantflags = NULL;
enum JOB wantjob = J_NONE; enum JOB wantjob = J_NONE;
enum SUBJOB wantsubjob = SJ_NONE; enum SUBJOB wantsubjob = SJ_NONE;
enum BEHAVIOUR wantbehaviour = BH_NONE;
if (nadded) *nadded = 0; if (nadded) *nadded = 0;
@ -249,7 +251,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok
} else { } else {
//if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging
rid = parserace(racename, wantflags, &wantjob, &wantsubjob); rid = parserace(racename, wantflags, &wantjob, &wantsubjob, &wantbehaviour);
//if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging
if (rid == R_RANDOM) { if (rid == R_RANDOM) {
@ -394,7 +396,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok
} }
} }
finalisemonster(lf, NULL, wantflags, 0); finalisemonster(lf, NULL, wantflags, wantbehaviour, 0);
// NOTE: because the initial maps (world, heaven, dungeon lev1) are created BEFORE the player, // NOTE: because the initial maps (world, heaven, dungeon lev1) are created BEFORE the player,
// monsters on these maps will not have their hostility adjusted! // monsters on these maps will not have their hostility adjusted!
@ -465,7 +467,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok
newlf->born = B_FALSE; newlf->born = B_FALSE;
finalisemonster(newlf, lf, wantflags, idx); finalisemonster(newlf, lf, wantflags, idx, BH_NONE);
newlf->born = B_TRUE; newlf->born = B_TRUE;
@ -506,7 +508,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok
adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL); adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL);
if (!adjcell) break; if (!adjcell) break;
newrid = parserace(f->text, NULL, NULL, NULL); newrid = parserace(f->text, NULL, NULL, NULL, NULL);
newr = findrace(newrid); newr = findrace(newrid);
if (!newr) break; if (!newr) break;
@ -515,7 +517,8 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok
if (nadded) (*nadded)++; if (nadded) (*nadded)++;
finalisemonster(newlf, lf, wantflags, 0); // wantbehaviour only applies to initial monster
finalisemonster(newlf, lf, wantflags, 0, BH_NONE);
newlf->born = B_TRUE; newlf->born = B_TRUE;
} }
@ -2039,7 +2042,7 @@ void calclight(map_t *map) {
// has lightproducing lf? (ie.hasflag f_produceslight) // has lightproducing lf? (ie.hasflag f_produceslight)
if (c->lf) { if (c->lf) {
radius = lfproduceslight(c->lf); radius = lfproduceslight(c->lf, NULL);
if (radius) { if (radius) {
makelitradius(c, radius, L_TEMP, -1); makelitradius(c, radius, L_TEMP, -1);
} }
@ -5463,7 +5466,7 @@ void finalisemap(map_t *map, object_t *entryob) {
} }
void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags, int idx) { void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags, enum BEHAVIOUR wantbehaviour, int idx) {
flag_t *f; flag_t *f;
enum FLAG noflag[MAXCANDIDATES]; enum FLAG noflag[MAXCANDIDATES];
int nnoflags = 0,i; int nnoflags = 0,i;
@ -5506,56 +5509,10 @@ void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags,
} }
// random monster behaviours // random monster behaviours
if (canhaverandombehaviour(lf) && onein(6)) { if ((wantbehaviour == BH_NONE) && canhaverandombehaviour(lf) && onein(6)) {
switch (rnd(0,8)) { wantbehaviour = getrandombehaviour();
case 0: // insane
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "insane");
addflag(lf->flags, F_TERRITORIAL, 2, NA, NA, NULL); // attack anything within 1 cells
break;
case 1: // hungry
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "hungry");
addflag(lf->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
break;
case 2: // timid
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "timid");
f = lfhasflag(lf, F_MORALE);
if (f) {
f->val[0] /= 2;
} else {
addflag(lf->flags, F_FLEEONDAM, B_TRUE, NA, NA, NULL);
}
break;
case 3: // drugged
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "drugged");
killflagsofid(lf->flags, F_FLEEONDAM);
killflagsofid(lf->flags, F_FLEEONHPPCT);
addflag(lf->flags, F_NOFLEE, B_TRUE, NA, NA, NULL);
break;
case 4: // drunk
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "drunk");
addflag(lf->flags, F_DRUNK, rnd(2,5), NA, NA, NULL);
break;
case 5: // determined
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "determined");
addflag(lf->flags, F_FOLLOWTIME, (DEF_AIFOLLOWTIME*2), NA, NA, NULL);
break;
case 6: // lazy
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "lazy");
addflag(lf->flags, F_FOLLOWTIME, (DEF_AIFOLLOWTIME/4), NA, NA, NULL);
break;
case 7: // extra hp
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "muscled");
lf->maxhp = pctof(rnd(125,200), lf->maxhp); // 25-100% more hp
lf->hp = lf->maxhp;
break;
case 8: // less hp
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "scrawny");
lf->maxhp = pctof(rnd(50,75), lf->maxhp); // 25-50% less hp
limit(&(lf->maxhp), 1, NA);
lf->hp = lf->maxhp;
break;
}
} }
givebehaviour(lf, wantbehaviour);
if (wantflags) { if (wantflags) {
copyflags(lf->flags, wantflags, NA); copyflags(lf->flags, wantflags, NA);
@ -7392,17 +7349,20 @@ int orthdir(int compassdir) {
return D_NONE; return D_NONE;
} }
enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum SUBJOB *wantsubjob) { enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum SUBJOB *wantsubjob, enum BEHAVIOUR *wantbehaviour) {
int donesomething; int donesomething;
char *p,*suff; char *p,*suff;
job_t *j; job_t *j;
char named[BUFLEN]; char named[BUFLEN];
char *localname; char *localname;
char *namestart; char *namestart;
behaviour_t *b;
// get params // get params
donesomething = B_TRUE; donesomething = B_TRUE;
if (wantbehaviour) *wantbehaviour = BH_NONE;
// take a local copy so we can strip suffixes off it // take a local copy so we can strip suffixes off it
if (strstarts(name, "the ")) { if (strstarts(name, "the ")) {
@ -7425,8 +7385,23 @@ enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum S
if (wantflags) addflag(wantflags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL); if (wantflags) addflag(wantflags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL);
donesomething = B_TRUE; donesomething = B_TRUE;
} }
if (wantbehaviour && (*wantbehaviour != BH_NONE)) {
} else {
// try removing prefixes for behaviours
for (b = firstbehaviour ; b; b = b->next) {
char lookfor[BUFLEN];
sprintf(lookfor, "%s ", b->name);
if (strstarts(p, lookfor)) {
p += strlen(lookfor);
if (wantbehaviour) *wantbehaviour = b->id;
break;
}
}
}
} }
// try removing suffixes for "named xxx" // try removing suffixes for "named xxx"
strcpy(named, ""); strcpy(named, "");
suff = strends(localname, " named "); suff = strends(localname, " named ");

4
map.h
View File

@ -87,7 +87,7 @@ void expand_cave(map_t *map, int numpasses);
void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *centre); void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *centre);
void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int dirtype, int wantannounce); void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int dirtype, int wantannounce);
void finalisemap(map_t *map, object_t *entryob); void finalisemap(map_t *map, object_t *entryob);
void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags, int idx); void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags, enum BEHAVIOUR wantbehaviour, int idx);
celltype_t *findcelltype(enum CELLTYPE cid); celltype_t *findcelltype(enum CELLTYPE cid);
celltype_t *findcelltypebyname(char *name); celltype_t *findcelltypebyname(char *name);
habitat_t *findhabitat(enum HABITAT id); habitat_t *findhabitat(enum HABITAT id);
@ -167,7 +167,7 @@ void markroomwalls(map_t *m, room_t *r);
void mapentereffects(map_t *m); void mapentereffects(map_t *m);
void moveobtoclearcell(object_t *o); void moveobtoclearcell(object_t *o);
int orthdir(int compassdir); int orthdir(int compassdir);
enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum SUBJOB *wantsubjob); enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum SUBJOB *wantsubjob, enum BEHAVIOUR *wantbehaviour);
int remove_deadends(map_t *m, int howmuch); int remove_deadends(map_t *m, int howmuch);
void set_scanned_glyph(int targettype, void *what, char *descappend, char *desc, glyph_t *glyph); void set_scanned_glyph(int targettype, void *what, char *descappend, char *desc, glyph_t *glyph);
void setcellknown(cell_t *cell, int forcelev); void setcellknown(cell_t *cell, int forcelev);

2
move.c
View File

@ -1280,7 +1280,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
if (gamemode == GM_GAMESTARTED) { if (gamemode == GM_GAMESTARTED) {
// update light // update light
if ((isplayer(lf) && changedlev) || lfproduceslight(lf)) { if ((isplayer(lf) && changedlev) || lfproduceslight(lf, NULL)) {
calclight(lf->cell->map); calclight(lf->cell->map);
setlosdirty(lf); setlosdirty(lf);
} }

View File

@ -28,6 +28,7 @@ objecttype_t *objecttype = NULL,*lastobjecttype = NULL;
brand_t *firstbrand = NULL,*lastbrand = NULL; brand_t *firstbrand = NULL,*lastbrand = NULL;
obmod_t *firstobmod = NULL,*lastobmod = NULL; obmod_t *firstobmod = NULL,*lastobmod = NULL;
celltype_t *firstcelltype = NULL,*lastcelltype = NULL; celltype_t *firstcelltype = NULL,*lastcelltype = NULL;
behaviour_t *firstbehaviour = NULL,*lastbehaviour = NULL;
command_t *firstcommand = NULL,*lastcommand = NULL; command_t *firstcommand = NULL,*lastcommand = NULL;
race_t *firstrace = NULL,*lastrace = NULL; race_t *firstrace = NULL,*lastrace = NULL;
raceclass_t *firstraceclass = NULL,*lastraceclass = NULL; raceclass_t *firstraceclass = NULL,*lastraceclass = NULL;
@ -661,6 +662,8 @@ void cleanup(void) {
free(npcname); free(npcname);
// free hidden names // free hidden names
while (firsthiddenname) killhiddenname(firsthiddenname); while (firsthiddenname) killhiddenname(firsthiddenname);
// behaviours
while (firstbehaviour) killbehaviour(firstbehaviour);
//WriteMemLeak(); //WriteMemLeak();
} }

View File

@ -2375,6 +2375,7 @@ void adjustdammaterial(int *dam, enum DAMTYPE damtype, enum MATERIAL mat) {
if (mat == MT_MAGIC) { if (mat == MT_MAGIC) {
switch (damtype) { switch (damtype) {
case DT_DIRECT: case DT_DIRECT:
case DT_MAGIC:
case DT_NONE: case DT_NONE:
break; break;
default: default:

43
spell.c
View File

@ -1808,7 +1808,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} }
losehp(target, roll(damstr), DT_SONIC, user, "a bolt of sound"); losehp(target, roll(damstr), DT_SONIC, user, "a bolt of sound");
} }
} else if (abilid == OT_A_SPRINT) { } else if (abilid == OT_A_SPRINT) {
flag_t *f; flag_t *f;
f = lfhasflag(user, F_SPRINTING); f = lfhasflag(user, F_SPRINTING);
@ -2331,6 +2330,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} else if (abilid == OT_A_TRIPLF) { } else if (abilid == OT_A_TRIPLF) {
object_t *wep; object_t *wep;
int skillmod = 0; int skillmod = 0;
int legs;
// ask for direction // ask for direction
if (!targcell) { if (!targcell) {
char dirch; char dirch;
@ -2365,6 +2365,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_TRUE; return B_TRUE;
} }
legs = countlegs(target);
if (legs == 0) {
if (isplayer(user)) msg("You can't trip something which has no legs!");
return B_TRUE;
}
getlfname(target, targetname); getlfname(target, targetname);
@ -2380,7 +2387,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
skillmod = getskill(user, SK_UNARMED); skillmod = getskill(user, SK_UNARMED);
} }
if (skillcheckvs(user, SC_DEX, skillmod, target, SC_SLIP, 0)) { if (skillcheckvs(user, SC_DEX, skillmod, target, SC_SLIP, (legs > 2) ? 5 : 0)) {
if (cansee(player, user)) { if (cansee(player, user)) {
msg("^w%s trip%s %s.",username, isplayer(user) ? "" : "s", targetname); msg("^w%s trip%s %s.",username, isplayer(user) ? "" : "s", targetname);
} }
@ -3555,12 +3562,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// special: spit attacks need an animation // special: spit attacks need an animation
casttype = lfhasflag(caster, F_CASTTYPE); casttype = lfhasflag(caster, F_CASTTYPE);
if (casttype && (casttype->val[0] == CT_EYESPIT)) { if (casttype && (casttype->val[1] == CT_EYESPIT)) {
enum COLOUR col; enum COLOUR col;
if (casttype->val[1] == NA) { if (casttype->val[2] == NA) {
col = C_GREEN; col = C_GREEN;
} else { } else {
col = casttype->val[1]; col = casttype->val[2];
} }
anim(caster->cell, targcell, '}', col); anim(caster->cell, targcell, '}', col);
} }
@ -5417,6 +5424,28 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
needredraw = B_TRUE; needredraw = B_TRUE;
drawscreen(); drawscreen();
} }
} else if (spellid == OT_S_DEATHKEEN) {
if (!isnighttime()) {
fizzle(caster);
return B_TRUE;
}
if (isplayer(caster)) {
msg("You wail with the power of death!");
}
noise(caster->cell, NULL, NC_OTHER, SV_TALK, "the dread wail of a banshee", NULL);
makenoise(caster, N_DEATHKEEN);
// all in range must pass a magic resistance check or die
for (target = caster->cell->map->lf ; target ; target = target->next) {
if (target != caster) {
if (canhear(target, caster->cell, SV_TALK)) {
if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
} else {
losehp(target, target->hp, DT_SONIC, caster, "a banshee's wail");
}
}
}
}
} else if (spellid == OT_S_DETECTAURA) { } else if (spellid == OT_S_DETECTAURA) {
if (isplayer(caster)) { if (isplayer(caster)) {
object_t *o; object_t *o;
@ -5668,6 +5697,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_DETECTPOISON) { } else if (spellid == OT_S_DETECTPOISON) {
if (isplayer(caster)) { if (isplayer(caster)) {
int npoisoned = 0; int npoisoned = 0;
int selfpoisoned = B_FALSE;
int n,i; int n,i;
flag_t *retflag[MAXCANDIDATES]; flag_t *retflag[MAXCANDIDATES];
int nretflags; int nretflags;
@ -5679,6 +5709,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
pt = findpoisontype(f->val[0]); pt = findpoisontype(f->val[0]);
msg("You detect %s in your body.", pt->name); msg("You detect %s in your body.", pt->name);
f->known = B_TRUE; f->known = B_TRUE;
selfpoisoned = B_TRUE;
} }
for (n = 0; n < caster->nlos; n++) { for (n = 0; n < caster->nlos; n++) {
@ -5739,7 +5770,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} }
if (!npoisoned) { if (!npoisoned) {
msg("You can't detect any poison nearby."); msg("You can't detect any %spoison nearby.", selfpoisoned ? "other " : "");
} }
} // end if isplayer } // end if isplayer
} else if (spellid == OT_S_DETONATE) { } else if (spellid == OT_S_DETONATE) {

View File

@ -1676,7 +1676,7 @@ int vaultthingok(enum VAULTTHING vt, char *what) {
if (r) { if (r) {
return B_TRUE; return B_TRUE;
} else { } else {
if (parserace(what, NULL, NULL, NULL)) { if (parserace(what, NULL, NULL, NULL, NULL)) {
return B_TRUE; return B_TRUE;
} }
} }