- [+] fire spells:

- [+] gather flame - l1: nearby fire boosts next spell's power.
          casttimme 2
    - [+] boil blood - l2:  when monster dies, it explodes (like a
          fireball?)
- [+] maybe: create player lf BEFORE creating maps
    - [+] then move player to start pos and add pets etc
    - [+] then kill mons in los
    - [+] this will let us correctly adjust hostility even on dlev 1
- [+] goat (yellow 'q', 1hd)
    - [+] charge
    - [+] horn attack
    - [+] eats anything!
        - [+] f_caneatmaterial
        - [+] calculate nutrition based on weight...
- [+] chimera(9hd, 9tr, mutant) - purple 'm' - goat/lion/wyrm, 3 headed.
    - [+] LARGE
    - [+] Morale 13-14
    - [+] EVIL
    - [+] Hostile
    - [+] swoop
    - [+] can breath fire - use burning wave
    - [+] melee attacks:
        - [+] bite (lion head) (3)
        - [+] bite (dragon head) (5:w)
        - [+] gore (horns) (3)
        - [+] 2 x claw (4)
        - [+] TOTAL 18
        - [+] but... do maxattacks = 4, not 5.
    - [+] slash attack: chance to remove a head.
        - [+] this makes it lose one bite attack and (maybe) its breath
              weapon.
- [+] hydra
    - [+] 5-12 heads
    - [+] each head has bite attack
    - [+] hit dice / tr based on heads
    - [+] regenerate 2 heads each time one is severed
This commit is contained in:
Rob Pearce 2012-04-09 21:52:39 +00:00
parent acd641ebc0
commit 4d5fa3c4e7
12 changed files with 609 additions and 68 deletions

36
ai.c
View File

@ -1950,7 +1950,8 @@ int aipickup(lifeform_t *lf, object_t *o) {
if ((o->type->id == OT_COFFIN) && (lf->race->id == R_GASCLOUD) && lfhasflagval(lf, F_ORIGRACE, R_VAMPIRE, NA, NA, NULL)) {
return rest(lf, B_TRUE);
}
if (isedible(o)) {
// if (isedible(o)) {
if (caneat(lf, o)) {
return eat(lf, o);
} else {
return pickup(lf, o, o->amt, B_TRUE, B_TRUE);
@ -2474,6 +2475,11 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) {
specificcheckok = B_FALSE;
}
if (ot->id == OT_S_BLOODBOIL) {
if (lfhasflag(victim, F_BLOODBOIL)) {
specificcheckok = B_FALSE;
}
}
if (ot->id == OT_S_DEATHKEEN) {
if (!isnighttime()) specificcheckok = B_FALSE;
}
@ -2503,6 +2509,28 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if ((ot->id == OT_S_DRAINLIFE) && isimmuneto(victim->flags, DT_NECROTIC, B_FALSE)) {
specificcheckok = B_FALSE;
}
if (ot->id == OT_S_GATHERFLAME) {
int i,found=B_FALSE;
// don't cast if we're made of fire!
if ((lf->material->id == MT_FIRE) && (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE)) {
specificcheckok = B_FALSE;
} else {
// must be fire nearby
for (i = 0; i < lf->nlos; i++) {
if (lf->los[i]->lf && (lf->los[i]->lf->material->id == MT_FIRE)) {
found = B_TRUE;
break;
}
if (hasobofmaterial(lf->los[i]->obpile, MT_FIRE)) {
found = B_TRUE;
break;
}
}
if (!found) {
specificcheckok = B_FALSE;
}
}
}
if (ot->id == OT_A_FLIP) {
if (getlfsize(victim) > getlfsize(lf)) {
specificcheckok = B_FALSE;
@ -2713,6 +2741,12 @@ int aiwants_real(lifeform_t *lf, object_t *o, int *covets, int *noids, enum OBTY
}
}
for (i = 0; i < *nwantflags; i++) {
// special case to cope with eating objects that aren't normally edible.
// eg. goats eating wood due to F_CANEATMATERIAL
if ((wantflag[i] == F_EDIBLE) && caneat(lf, o)) {
if (covets) *covets = wantflagcovet[i];
return B_TRUE;
}
if (hasflag(o->flags, wantflag[i])) {
if ((wantflag[i] == F_EDIBLE) && !caneat(lf, o)) { // special case
} else {

View File

@ -21,6 +21,7 @@ extern lifeform_t *player;
extern lifeform_t *godlf[];
extern int needredraw;
extern int statdirty;
extern enum ERROR reason;
@ -795,7 +796,22 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (critical && !lfhasflag(lf, F_PHANTASM)) {
object_t *armour;
char noun[BUFLEN];
if (lfhasflag(victim, F_CANSEVER) && wep && (getdamtype(wep) == DT_SLASH)) {
flag_t *retflag[MAXCANDIDATES],*poss[MAXCANDIDATES],*f;
int nretflags = 0,nposs = 0;
// select a random sever-able body part
getflags(victim->flags, retflag, &nretflags, F_CANSEVER, F_NONE);
for (i = 0; i < nretflags; i++) {
if (hasbp(victim, retflag[i]->val[0])) {
poss[nposs++] = retflag[i];
}
}
f = poss[rnd(0,nposs-1)];
critpos = f->val[0];
} else {
critpos = getrandomcorebp(victim, lf);
}
if (critpos == BP_NONE) {
strcpy(victimbpname, victimname);
} else {
@ -1829,6 +1845,65 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int d
if (damtype == DT_PIERCE) damtype = DT_SLASH;
if (damtype == DT_CHOP) damtype = DT_SLASH;
// special case - beheading multiheaded monsters
if (lf && victim && (damtype == DT_SLASH)) {
flag_t *selflag;
selflag = lfhasflagval(victim, F_CANSEVER, hitpos, NA, NA, NULL);
if (selflag) {
int i,nretflags,num;
char dambuf[BUFLEN];
char bpname[BUFLEN];
flag_t *retflag[MAXCANDIDATES];
strcpy(bpname, getbodypartname(victim, hitpos));
// special case
if (!victim->race->id == R_HYDRA) {
// remove it
addflag(victim->flags, F_NOBODYPART, hitpos, NA, NA, NULL);
// remove hasattack flags
getflags(victim->flags, retflag, &nretflags, F_CANCAST, F_HASATTACK, F_NONE);
for (i = 0; i < nretflags; i++) {
if (retflag[i]->id == F_CANCAST) {
if (retflag[i]->val[0] == selflag->val[2]) {
killflag(retflag[i]);
continue;
}
} else if (retflag[i]->id == F_HASATTACK) {
if (retflag[i]->val[2] == selflag->val[1]) {
killflag(retflag[i]);
continue;
}
}
}
}
if (cansee(player, victim)) {
char lfname[BUFLEN],vname[BUFLEN];
getlfname(victim, vname);
if (lf && cansee(player, lf)) { // can see who did it
getlfname(lf, lfname);
} else {
strcpy(lfname, "Something");
}
msg("^%c%s slice%s off %s%s %s!", getlfcol(victim, CC_VBAD),
lfname, isplayer(lf) ? "" : "s", vname, getpossessive(vname), bpname);
}
// take extra damage based on number of severable limbs
num = countflagsofid(victim->race->flags, F_CANSEVER);
if (victim->race->id == R_HYDRA) {
growhydrahead(victim, B_TRUE);
} else {
sprintf(dambuf, "a severed %s", bpname);
losehp(victim, pctof(100/num, victim->maxhp), DT_DIRECT, lf, dambuf);
}
// drop the head
if (strlen(selflag->text)) {
addob(victim->cell->obpile, selflag->text);
}
return;
}
}
if (damtype == DT_BASH) {
switch (hitpos) {
default:
@ -2572,8 +2647,6 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
}
}
getflags(fp, retflag, &nretflags, F_FLAMESTRIKE, F_HEAVYBLOW, F_HITCONFER, F_RACESLAY, F_REVENGE, F_RUSTED, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];

149
data.c
View File

@ -3420,6 +3420,14 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_PLEASESGOD, R_GODFIRE, 1, NA, NULL);
addot(OT_S_GATHERFLAME, "harvest flame", "Draws all nearby fire into the caster, boosting the power of their next spell.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Your next spell's power will be boosted by the amount of fire consumed.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the maximum amount of fire consumed.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SPARK, "flambe", "Creates very hot but short lived burst of flame around the target, dealing 2d3 fire damage to creatures and objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
@ -3443,6 +3451,13 @@ void initobjects(void) {
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_PLEASESGOD, R_GODFIRE, 2, NA, NULL);
// l2
addot(OT_S_BLOODBOIL, "bloodboil", "Energised the molecules of the target's blood, causing them to explode into flames upon death.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CLEANSINGFIRE, "cleansing fire", "Draws power from nearby fires to heal the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell will affect up to ^bpower^n fires, healing 30% hit points from each.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
@ -4021,7 +4036,7 @@ void initobjects(void) {
// mental/psionic
///////////////////
// l1
addot(OT_S_BOOSTCONFIDENCE, "boost confidence", "Instils the target with infinite courage, allowing them to (perhaps foolishly) continue fighting even when all seems lost.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addot(OT_S_BOOSTCONFIDENCE, "ego boost", "Instils the target with boundless courage, allowing them to (perhaps foolishly) continue fighting even when all seems lost.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
@ -9683,6 +9698,54 @@ void initrace(void) {
addflag(lastrace->flags, F_MINIONS, 20, 1, 3, "goblin warrior");
addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL);
addrace(R_CHIMERA, "chimera", 300, 'm', C_MAGENTA, MT_FLESH, RC_MAGIC, "A monstrous hybrid where a goat's rear has been magically attached to a lion's front. It has three heads - a goat's, a lion's and a wyrm's - and a pair of bat-like wings.");
setbodytype(lastrace, BT_QUADRAPED);
setbodypartname(lastrace, BP_HEAD, "lion's head");
addbodypart(lastrace, BP_HEAD2, "dragon's head");
addbodypart(lastrace, BP_HEAD3, "goat's head");
addbodypart(lastrace, BP_TAIL, NULL);
addbodypart(lastrace, BP_WINGS, NULL);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_ALL, NA, RR_VERYRARE, NULL);
addflag(lastrace->flags, F_HITDICE, 9, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 9, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VLOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_VLOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_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_HASATTACK, OT_TEETH, 4, BP_HEAD, NULL); // lion head
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, BP_HEAD2, NULL); // dragon head
addflag(lastrace->flags, F_HASATTACK, OT_HORN, 5, BP_HEAD3, NULL); // goat horns
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); // front lion claws
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); // front lion claws
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, SV_CAR, NA, "roars^a roar");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, SV_SHOUT, NA, "bleats^an angry bleating");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain");
addflag(lastrace->flags, F_CANSEVER, BP_HEAD, BP_HEAD, NA, "lion head");
addflag(lastrace->flags, F_CANSEVER, BP_HEAD2, BP_HEAD2, OT_S_BURNINGWAVE, "red wyrm head");
addflag(lastrace->flags, F_CANSEVER, BP_HEAD3, BP_HEAD3, NA, "goat head");
addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, NA, NA, "range:2;");
addflag(lastrace->flags, F_CANCAST, OT_S_BURNINGWAVE, NA, NA, "pw:6;");
addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "unleashes its fiery breath");
addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 14, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_FELINE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_AVIAN, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_EATCONFER, F_MUTABLE, B_TRUE, NA, "100");
addrace(R_CENTAUR, "centaur", 500, 'u', C_GREY, MT_FLESH, RC_ANIMAL, "Centaurs look like horses with their neck upwards replaced by a human torso and arms.");
setbodytype(lastrace, BT_QUADRAPED);
addbodypart(lastrace, BP_TAIL, NULL);
@ -10778,6 +10841,43 @@ void initrace(void) {
addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 7, NA, NA, NULL);
addrace(R_HYDRA, "hydra", 300, 'W', C_BLUE, MT_FLESH, RC_DRAGON, "A four legged serpentine reptile, resembling a wyrm except for its many extra heads.");
setbodytype(lastrace, BT_QUADRAPED);
addbodypart(lastrace, BP_TAIL, NULL);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_ALL, NA, RR_VERYRARE, NULL);
addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 11, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, 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_VLOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL);
// note: addlf() will add extra teeth attacks based on heads.
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, SV_CAR, NA, "hisses^a loud hissing");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "roars in pain^roars of pain");
addflag(lastrace->flags, F_CANSEVER, BP_HEAD, BP_HEAD, NA, "hydra head");
//addflag(lastrace->flags, F_CANCAST, OT_S_BURNINGWAVE, NA, NA, "pw:6;");
//addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL);
//addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "unleashes its fiery breath");
addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addrace(R_KOBOLD, "kobold", 18, 'k', C_BROWN, MT_FLESH, RC_HUMANOID, "An evil humanoid race with doglike features, kobolds are known for their cowardace and prefer to attack from a distance if at all possible.");
setbodytype(lastrace, BT_HUMANOID);
setbodypartname(lastrace, BP_HANDS, "paws");
@ -13806,6 +13906,42 @@ void initrace(void) {
addflag(lastrace->flags, F_DTVULN, DT_SONIC, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL);
addrace(R_GOAT, "goat", 37, 'q', C_YELLOW, MT_FLESH, RC_ANIMAL, "Small, horned livestocks animals known for their appetite.");
setbodytype(lastrace, BT_QUADRAPED);
addbodypart(lastrace, BP_TAIL, NULL);
addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL);
addflag(lastrace->flags, F_TERRITORIAL, 3, NA , NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, 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_HITDICE, 1, 2, NA, NULL);
addflag(lastrace->flags, F_TR, 1, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_HORN, 3, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL);
addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:3;");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 4, NA, "bleats in pain^bleating");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, SV_SHOUT, NA, "bleats^an angry bleating");
addflag(lastrace->flags, F_FLEEONHPPCT, 80, NA, NA, "");
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATMATERIAL, MT_WOOD, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATMATERIAL, MT_CLOTH, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATMATERIAL, MT_LEATHER, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATMATERIAL, MT_PAPER, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATMATERIAL, MT_PLASTIC, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATMATERIAL, MT_WETPAPER, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATMATERIAL, MT_RUBBER, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATMATERIAL, MT_SILK, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATMATERIAL, MT_PLANT, NA, NA, NULL);
addrace(R_GYRFALCON, "gyrfalcon", 1, 'A', C_WHITE, MT_FLESH, RC_ANIMAL, "An enormous falcon, commonly found in arctic climates."); // 'A' for Avian
setbodytype(lastrace, BT_BIRD);
@ -14817,7 +14953,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addrace(R_DRAGONBLUE, "blue wyrm", 400, 'W', C_BLUE, MT_FLESH, RC_DRAGON, "Blue wyrms are massive reptilian creatures who can (and will) consume almost any living creature.");
addrace(R_DRAGONBLUE, "blue wyrm", 400, 'W', C_CYAN, MT_FLESH, RC_DRAGON, "Blue wyrms are massive reptilian creatures who can (and will) consume almost any living creature.");
setbodytype(lastrace, BT_HUMANOID);
addbodypart(lastrace, BP_WINGS, NULL);
addbodypart(lastrace, BP_TAIL, NULL);
@ -14868,7 +15004,7 @@ void initrace(void) {
addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_ELECTRIC, NA, "100");
addflag(lastrace->flags, F_EATCONFER, F_ATTRMOD, A_STR, 5, "50");
addrace(R_DRAGONBLUEY, "blue wyrmling", 150, 'w', C_BLUE, MT_FLESH, RC_DRAGON, "Blue wyrms are massive reptilian creatures who can (and will) consume almost any living creature.");
addrace(R_DRAGONBLUEY, "blue wyrmling", 150, 'w', C_CYAN, MT_FLESH, RC_DRAGON, "Blue wyrms are massive reptilian creatures who can (and will) consume almost any living creature.");
setbodytype(lastrace, BT_HUMANOID);
addbodypart(lastrace, BP_WINGS, NULL);
addbodypart(lastrace, BP_TAIL, NULL);
@ -14919,7 +15055,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_ELECTRIC, NA, "50");
addflag(lastrace->flags, F_EATCONFER, F_ATTRMOD, A_STR, 5, "25");
addrace(R_DRAGONBLUEA, "ancient blue wyrm", 600, 'W', C_BLUE, MT_FLESH, RC_DRAGON, "Blue wyrms are massive reptilian creatures who can (and will) consume almost any living creature.");
addrace(R_DRAGONBLUEA, "ancient blue wyrm", 600, 'W', C_CYAN, MT_FLESH, RC_DRAGON, "Blue wyrms are massive reptilian creatures who can (and will) consume almost any living creature.");
setbodytype(lastrace, BT_HUMANOID);
addbodypart(lastrace, BP_WINGS, NULL);
addbodypart(lastrace, BP_TAIL, NULL);
@ -16657,6 +16793,11 @@ void initrace(void) {
addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL);
} else if (r->raceclass->id == RC_DRAGON) {
// wyrms hate hydras
if (r->id != R_HYDRA) {
addflag(r->flags, F_HATESRACE, R_HYDRA, NA, NA, NULL);
}
} else if (r->raceclass->id == RC_GOD) {
addflag(r->flags, F_PIETY, 100, NA, NA, NULL);
addflag(r->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);

22
defs.h
View File

@ -1021,6 +1021,7 @@ enum RACE {
R_BOGGART,
R_BUGBEAR,
R_CENTAUR,
R_CHIMERA,
R_COCKATRICE,
R_CREEPINGCLAW,
R_CRYMIDIA,
@ -1045,6 +1046,7 @@ enum RACE {
R_HIPPOGRIFF,
R_HOBGOBLIN,
R_HOBGOBLINWAR,
R_HYDRA,
R_KOBOLD,
R_LEPRECHAUN,
R_LESHY,
@ -1142,6 +1144,7 @@ enum RACE {
R_DOGDEATH,
R_DOGWAR,
R_ELEPHANT,
R_GOAT,
R_GYRFALCON,
R_HARPY,
R_HAWK,
@ -1589,8 +1592,9 @@ enum OBTYPE {
OT_S_TORNADO,
OT_S_WHIRLWIND,
OT_S_WINDSHIELD,
// -- elemental - fire
// -- elemental - fire magic
OT_S_BLADEBURN,
OT_S_BLOODBOIL,
OT_S_BURNINGFEET,
OT_S_BURNINGWAVE,
OT_S_CLEANSINGFIRE,
@ -1599,6 +1603,7 @@ enum OBTYPE {
OT_S_FIREBALL,
OT_S_FLAMEPILLAR,
OT_S_FLAMEBURST,
OT_S_GATHERFLAME,
OT_S_IMMOLATE,
OT_S_METEOR,
OT_S_PYROMANIA,
@ -2249,8 +2254,10 @@ enum BODYPART {
BP_FRONTLEGS = 15,
BP_WINGS = 16, // <- core bodypart
BP_TAIL = 17, // <- core bodypart
BP_HEAD2 = 18,
BP_HEAD3 = 19,
};
#define MAXBODYPARTS (18)
#define MAXBODYPARTS (20)
// depth on a human
@ -2723,6 +2730,7 @@ enum FLAG {
F_OBATTACKDELAY, // how long weapon takes to attack
F_USESSKILL, // weapon needs skill sk_v0
F_MAGICBOOST, // boost power of all spells by v0
F_TEMPMAGICBOOST, // boost power of next spell cast (only) by v0
F_WHIP, // this weapon is a whip - use different damtext.
F_CANHAVEOBMOD, // weapon can have obmod om_v0 applied
// optional: v1 is chance of randomly having it
@ -2874,6 +2882,13 @@ enum FLAG {
// f_armourrating is used for innate armour.
// f_arboost is used by objects "of protection" which
// enhance your armour rating.
F_BLOODBOIL, // lf will explode into flames upon death
F_CANSEVER, // critical slash attacks might sever bodypart v0
// v1: (optional) this will also remove HASATTACK
// flags with v2=this.
// v2: (optional) will also remove flags of CANCAST
// with v0 = this.
// text: object name of severed limb to drop
F_DONEPICKUP, // lf has used their free pickup/drop for this turn.
F_DONEKNOWLEDGETRADE, // you've already traded knowledge with this
// person.
@ -3164,6 +3179,7 @@ enum FLAG {
F_WANTS, // lf will try to pick up object type val0.
// if val1 = B_COVETS, will even abandon attacks
// for it!
F_WANTSOBMAT, // lf will look for obs of material v0. val1=covets
F_WANTSOBFLAG, // lf will look for obs with this flag. val1=covets
F_WANTSBETTERWEP, // lf will look for better weapons, val1=covets
F_WANTSBETTERARM, // lf will look for better armour, val1=covets
@ -3295,6 +3311,8 @@ enum FLAG {
// try to change its facing.
F_CANTALK, // this lf can talk, even if its raceclass normally
// wouldn't be able to.
F_CANEATMATERIAL, // this lf can eat objects with material v0,
// even if it's not normally edible.
F_AQUATIC, // this race can attack normally in water and suffers no
// movement penalties. they can also swim at master
// level.

57
io.c
View File

@ -1450,6 +1450,13 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
}
donesomething = B_TRUE;
break;
case F_BLOODBOIL:
if (isplayer(lf)) {
msg("A malignant red nimbus surrounds you.");
} else if (cansee(player, lf)) {
msg("A malignant red nimbus surrounds %s.", lfname);
}
break;
case F_BREATHWATER:
if (isplayer(lf)) {
msg("You can now breath normally underwater.");
@ -1947,6 +1954,13 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
msg("%s %s stunned!",lfname, is(lf));
donesomething = B_TRUE;
break;
case F_TEMPMAGICBOOST:
// don't know if monsters get it
// also we only announce GAINING this flag, not losing it
if (isplayer(lf)) {
msg("Your magical power feels temporarily boosted!");
}
break;
case F_TREMORSENSE:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can now 'see' by sensing vibrations around you.");
@ -2168,6 +2182,13 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
msg("%s can see again.",lfname);
donesomething = B_TRUE;
break;
case F_BLOODBOIL:
if (isplayer(lf)) {
msg("A calming blue nimbus surrounds you.");
} else if (cansee(player, lf)) {
msg("A calming blue nimbus surrounds %s.", lfname);
}
break;
case F_BREATHWATER:
if (isplayer(lf)) {
msg("%s can no longer breath underwater.",lfname);
@ -11552,10 +11573,23 @@ void showlfstats(lifeform_t *lf, int showall) {
// unarmed attacks
op = addobpile(NULL, NULL, NULL);
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_HASATTACK) {
getflags(lf->flags, retflag, &nretflags, F_HASATTACK, F_NONE);
for (i = 0; i < nretflags; i++) {
object_t *o;
objecttype_t *ot;
int instances = 1;
int n;
f = retflag[i];
for (n = i+1 ; n < nretflags; n++) {
if ((retflag[n]->val[0] == f->val[0]) &&
(retflag[n]->val[1] == f->val[1]) &&
(retflag[n]->val[2] == f->val[2]) &&
streq(retflag[n]->text, f->text)) {
instances++;
}
}
ot = findot(f->val[0]);
o = addobfast(op, ot->id);
if (o) {
@ -11581,7 +11615,12 @@ void showlfstats(lifeform_t *lf, int showall) {
}
doheadingsmall(mainwin, y2, x2, ftext, "Innate Attack");
// add '2 x whatever' for multiples.
if (instances == 1) {
wprintw(mainwin, "%s", buf);
} else {
wprintw(mainwin, "%d x %s", instances, buf);
}
if (strlen(dambuf)) {
if (lorelev >= PR_BEGINNER) setcol(mainwin, lorecol);
wprintw(mainwin, "%s", dambuf);
@ -11589,9 +11628,13 @@ void showlfstats(lifeform_t *lf, int showall) {
}
y2++;
} // end if o
} // end if fid == hasattack
// now skip over multiple instances of the same flag
if (instances >= 2) {
i += (instances-1);
}
} // end for each flag
// no attacks at all?
if ((nweps == 0) && !op->first) {
snprintf(buf, BUFLEN, "N/A");
@ -12849,6 +12892,14 @@ void showlfstats(lifeform_t *lf, int showall) {
isplayer(lf) ? "your" : "its", boost);
y++;
}
f = lfhasknownflag(lf, F_TEMPMAGICBOOST);
if (f && (f->known)) {
int boost;
sumflags(lf->flags, F_TEMPMAGICBOOST, &boost, NULL, NULL);
mvwprintw(mainwin, y, 0, "The power of %s next spell will be boosted by %d.",
isplayer(lf) ? "your" : "its", boost);
y++;
}
f = lfhasknownflag(lf, F_MINDSHIELD);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s are protected from psionic attacks.", you(lf));

131
lf.c
View File

@ -768,6 +768,11 @@ int caneat(lifeform_t *lf, object_t *o) {
return B_FALSE;
}
// note: must do this check _before_ call to isedible()!
if (lfhasflagval(lf, F_CANEATMATERIAL, o->material->id, NA, NA, NULL)) {
return B_TRUE;
}
if (!isedible(o)) {
reason = E_WRONGOBTYPE;
return B_FALSE;
@ -1145,6 +1150,8 @@ int canreachbp(lifeform_t *lf, lifeform_t *victim, enum BODYPART bp) {
// upper
case BP_EYES:
case BP_HEAD:
case BP_HEAD2:
case BP_HEAD3:
case BP_EARS:
case BP_NECK:
case BP_SHOULDERS:
@ -1768,12 +1775,27 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
}
}
if (isplayer(lf)) {
if ((sid == OT_S_GATHERFLAME) && (lf->material->id == MT_FIRE)) {
if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) {
char ch;
ch = askchar("Casting this while made of flame will harm you, continue?","yn", "n", B_TRUE, B_FALSE);
if (ch != 'y') {
msg("Cancelled.");
return B_TRUE;
}
}
}
}
// stop hiding
killflagsofid(lf->flags, F_HIDING);
// take time
taketime(lf, getspellspeed(lf));
if (!fromob) {
flag_t *retflag[MAXCANDIDATES];
int nretflags,tempboost = 0,i;
// lose mp
losemp(lf, cost);
@ -1806,6 +1828,20 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
power += countplantsinsight(lf);
limit(&power, NA, 10);
}
tempboost = 0;
getflags(lf->flags, retflag, &nretflags, F_TEMPMAGICBOOST, F_NONE);
for (i = 0; i < nretflags; i++) {
tempboost += retflag[i]->val[0];
killflag(retflag[i]);
}
if (tempboost) {
power += tempboost;
if (isplayer(lf)) {
msg("^gYour spell's power is boosted!^n");
}
}
if (!willflag && real_getmr(lf, B_ONLYEXTERNAL) && skillcheck(lf, SC_RESISTMAG, 20 + power, 0) && !isgod(lf)) {
if (power > 1) {
// half strength
@ -2581,18 +2617,11 @@ int continuerepairing(lifeform_t *lf, flag_t *repairflag) {
}
int countinnateattacks(lifeform_t *lf) {
int count = 0,i;
flag_t *f;
flag_t *retflag[MAXCANDIDATES];
int nretflags;
getflags(lf->flags, retflag, &nretflags, F_HASATTACK, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->id == F_HASATTACK) count++;
return nretflags;
}
return count;
}
int countlegs(lifeform_t *lf) {
enum BODYPART bp;
@ -3257,8 +3286,18 @@ void die(lifeform_t *lf) {
amt = pctof( rnd(1,soulflag->val[0]), lf->maxhp);
limit(&amt, 1, NA);
gainhp(souleater, amt);
// copy some flags
copyflag(souleater->flags, lf->flags, F_BLOODBOIL);
// drop bones
addob(corpsecell->obpile, "pile of ash");
} else if (lfhasflag(lf, F_BLOODBOIL)) {
if (haslos(player, corpsecell)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s explodes into flames!", lfname);
}
// explode into flames
addobsinradius(corpsecell, 1, DT_COMPASS, "medium fire", B_TRUE, NULL);
} else if ((lf->lastdamtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) {
// shattered
fragments(corpsecell, "chunk of ice", 2, UNLIMITED);
@ -4237,16 +4276,20 @@ int eat(lifeform_t *lf, object_t *o) {
// get total nutrition
nutrition = getnutrition(o);
if (nutrition == 0) {
// this might happen if you purposely try to eat a potion.
// technically a potion will pass above checks because you can
// drink it.
// this might happen if you purposely try to eat something non-edible but drinkable
// (eg. a potion). also when you have f_caneatmaterial and you something which
// isn't normally edible (ie. a goat eating wood).
if (lfhasflagval(lf, F_CANEATMATERIAL, o->material->id, NA, NA, NULL)) {
// nutrition based on object weight
nutrition = getobweight(o)*5;
} else {
if (isplayer(lf)) {
msg("That doesn't seem very nutritious...");
}
return B_TRUE;
}
}
// only do this check for the player - basically it should
@ -4342,7 +4385,7 @@ int eat(lifeform_t *lf, object_t *o) {
sprintf(taste, "The raw meat tastes disgusting!");
} else if (hasflagval(o->flags, F_CORPSEOF, R_CHICKEN, NA, NA, NULL)) {
sprintf(taste, "Tastes like chicken!");
} else if (f->val[1] >= 20) {
} else if (f && (f->val[1] >= 20)) {
sprintf(taste, "Yum!");
} else {
strcpy(taste, "");
@ -7183,6 +7226,8 @@ int getbodyparthitchance(enum BODYPART bp) {
case BP_SECWEAPON: return 0;
case BP_EYES: return 1;
case BP_HEAD: return 2;
case BP_HEAD2: return 2;
case BP_HEAD3: return 2;
case BP_WAIST: return 3;
case BP_HANDS: return 3;
case BP_FEET: return 3;
@ -7234,6 +7279,10 @@ char *getbodypartname(lifeform_t *lf, enum BODYPART bp) {
return "eyes";
case BP_HEAD:
return "head";
case BP_HEAD2:
return "second head";
case BP_HEAD3:
return "third head";
case BP_NECK:
return "neck";
case BP_BODY:
@ -7268,6 +7317,8 @@ char *getbodypartequipname(enum BODYPART bp) {
case BP_LEFTFINGER:
case BP_HANDS:
case BP_HEAD:
case BP_HEAD2:
case BP_HEAD3:
case BP_BODY:
case BP_FRONTLEGS:
case BP_BACKLEGS:
@ -8302,6 +8353,7 @@ int getattacks(lifeform_t *lf, int *min, int *max) {
if (f) {
minattacks = f->val[0];
maxattacks = f->val[1];
} else {
minattacks = countinnateattacks(lf);
maxattacks = countinnateattacks(lf);
@ -8786,6 +8838,15 @@ char *real_getlfname(lifeform_t *lf, char *buf, lifeform_t *usevis, int showall,
strcat(descstring, " ");
}
if (lf->race->id == R_HYDRA) {
int nheads;
char numbuf[BUFLEN];
nheads = countflagsofid(lf->flags, F_HASATTACK);
numtotext(nheads, numbuf);
strcat(descstring, numbuf);
strcat(descstring, "-headed ");
}
// need a certain amount of race knowledge to recognise ai traits
if (lorelev < PR_SKILLED) {
dobehaviour = B_FALSE;
@ -11436,6 +11497,40 @@ int gotosleep(lifeform_t *lf, int onpurpose) {
return B_FALSE;
}
void growhydrahead(lifeform_t *lf, int announce) {
flag_t *f;
char vname[BUFLEN];
int dr = 0;
f = lfhasflagval(lf, F_HASATTACK, OT_TEETH, NA, NA, NULL);
dr = f->val[1]; // remember dr
if (announce) {
// remove one hasattack flag so that the name string
// is correct.
killflag(f);
getlfname(lf, vname);
// regrow
if (cansee(player, lf)) {
msg("^%c%s grow%s two more heads!", getlfcol(lf, CC_GOOD), vname, isplayer(lf) ? "" : "s");
}
}
if (announce) {
// add two more attack flags, since we removed one before.
addtempflag(lf->flags, F_HASATTACK, OT_TEETH, dr, NA, NULL, FROMRACE);
addtempflag(lf->flags, F_HASATTACK, OT_TEETH, dr, NA, NULL, FROMRACE);
} else {
// just add one
addtempflag(lf->flags, F_HASATTACK, OT_TEETH, dr, NA, NULL, FROMRACE);
}
// also add extra hp
lf->maxhp += HITDIESIDES;
gainhp(lf, HITDIESIDES);
if (isplayer(lf)) statdirty = B_TRUE;
// adjust TR
f = hasflag(lf->flags, F_TR);
f->val[0]++;
}
flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp) {
flag_t *f, *retflag[MAXCANDIDATES];
int nretflags,i;
@ -11960,6 +12055,16 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
break;
}
if (where == BP_TAIL) {
if (lf->race->id == R_MANTICORE) {
flag_t *f;
// can't use spike volley
f = hasflagval(lf->flags, F_CANWILL, OT_S_SPIKEVOLLEY, NA, NA, NULL);
if (f) killflag(f);
}
}
return B_FALSE;
}

1
lf.h
View File

@ -286,6 +286,7 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp);
void givestartskills(lifeform_t *lf, flagpile_t *fp);
map_t *gotolev(lifeform_t *lf, int depth, object_t *fromstairs);
int gotosleep(lifeform_t *lf, int onpurpose);
void growhydrahead(lifeform_t *lf, int announce);
flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp);
int hasfreeaction(lifeform_t *lf);
int real_hasfreeaction(lifeform_t *lf, enum FLAG exception);

10
map.c
View File

@ -6148,6 +6148,16 @@ void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags,
copyflags(lf->flags, v->flags, F_STAYINROOM);
}
if (lf->race->id == R_HYDRA) {
int nextra,i;
// they always have at least 5 heads. add more...
// grow extra heads
nextra = rnd(0,7);
for (i = 0; i < nextra; i++) {
growhydrahead(lf, B_FALSE);
}
}
/*
getflags(lf->flags, retflag, &nretflags, F_LIFEOB, F_NONE);
for (i = 0; i < nretflags; i++) {

23
nexus.c
View File

@ -131,6 +131,8 @@ int main(int argc, char **argv) {
enum SKILLLEVEL slev;
flag_t *retflag[MAXCANDIDATES];
int nretflags;
map_t fakemap;
cell_t fakecell;
atexit(cleanup);
@ -256,6 +258,15 @@ int main(int argc, char **argv) {
}
}
// add player in fake cell
createfakes(&fakemap, &fakecell);
real_addlf(&fakecell, startrace->id, 1, C_PLAYER); // this will assign 'player'
// give them basic abilities
addflag(player->flags, F_CANWILL, OT_A_CHECKSTAIRS, NA, NA, NULL);
addflag(player->flags, F_CANWILL, OT_A_PRAY, NA, NA, NULL);
addflag(player->flags, F_CANWILL, OT_A_TRAIN, NA, NA, NULL);
addflag(player->flags, F_CANWILL, OT_A_DEBUG, NA, NA, NULL); /////////
// make the initial level
newworld = B_TRUE;
@ -288,6 +299,7 @@ int main(int argc, char **argv) {
}
// add player in the starting position
//where = real_getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL);
where = findobinmap(dmap, OT_PLAYERSTART);
if (!where) {
@ -296,19 +308,16 @@ int main(int argc, char **argv) {
more();
exit(1);
}
movelf(player, where);
// new remove fakes
killfakes(&fakemap, &fakecell);
// this is the hole which you fell down to get here.
addobfast(where->obpile, OT_HOLEINROOF);
// kill any objects which were already there, or which fell down the hole
killallobsexcept(where->obpile, OT_HOLEINROOF, OT_NONE);
// now add the player
real_addlf(where, startrace->id, 1, C_PLAYER); // this will assign 'player'
// give them basic abilities
addflag(player->flags, F_CANWILL, OT_A_CHECKSTAIRS, NA, NA, NULL);
addflag(player->flags, F_CANWILL, OT_A_PRAY, NA, NA, NULL);
addflag(player->flags, F_CANWILL, OT_A_TRAIN, NA, NA, NULL);
addflag(player->flags, F_CANWILL, OT_A_DEBUG, NA, NA, NULL); /////////
/*o = hasob(where->obpile, OT_PLAYERSTART);
killob(o);*/

View File

@ -14736,6 +14736,13 @@ int getcritchance(lifeform_t *lf, object_t *o, lifeform_t *victim) {
chance *= 2;
}
// extra crit chance if you can sever victim's limbs
if (victim && lfhasflag(victim, F_CANSEVER)) {
if (o && (getdamtype(o) == DT_SLASH)) {
chance += 30;
}
}
return chance;
}

57
spell.c
View File

@ -4280,6 +4280,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
teleportto(caster, targcell, B_TRUE);
setfacing(caster, target->facing);
} else if (spellid == OT_S_BLOODBOIL) {
if (!target) {
target = targcell->lf;
}
if (!target || lfhasflag(target, F_BLOODBOIL)) {
fizzle(caster);
return B_TRUE;
}
addflag(target->flags, F_BLOODBOIL, B_TRUE, NA, NA, NULL);
} else if (spellid == OT_S_LOWERMETAB) {
flag_t *f;
// ie. 2 - 4
@ -6919,6 +6928,54 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
polymorphto(target, R_GASCLOUD, howlong);
}
} else if (spellid == OT_S_GATHERFLAME) {
cell_t *c;
int amt = 0,i;
if (!target) target = caster;
// override castername
getlfname(target, castername);
// all flame in sight
for (i = 0; i < target->nlos; i++) {
c = target->los[i];
if (c->lf && (c->lf->material->id == MT_FIRE)) {
if (gettr(c->lf) <= power) {
char buf[BUFLEN];
// instadeath
sprintf(buf, "being sucked into %s", castername);
losehp(c->lf, c->lf->maxhp, DT_DIRECT, target, buf);
if (isplayer(c->lf)) {
msg("Your essence is sucked into %s!", castername);
} else if (cansee(player, c->lf)) {
char lfname[BUFLEN];
getlfname(c->lf, lfname);
msg("%s%s essence is sucked into %s!", lfname, getpossessive(lfname), castername);
}
amt++;
}
}
}
if (isdead(target)) { // consumed yourself?
return B_FALSE;
}
// now gather flame from cells in los
for (i = 0; (i < target->nlos) && (amt < power); i++) {
object_t *o, *nexto;
for (o = target->los[i]->obpile->first ; o ; o = nexto) {
nexto = o->next;
if (o->material->id == MT_FIRE) {
removeob(o, ALL);
amt++;
}
break;
}
}
if (amt) {
// boost spells...
addflag(target->flags, F_TEMPMAGICBOOST, amt, NA, NA, NULL);
} else {
fizzle(caster);
return B_TRUE;
}
} else if (spellid == OT_S_GLACIATE) {
object_t *o,*nexto;
int donesomething = B_FALSE;

35
text.c
View File

@ -1142,6 +1142,11 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d
canbehead = B_FALSE;
}
}
// can't behead multiheaded things at the moment...
if (victim && hasbp(victim, BP_HEAD) && hasbp(victim, BP_HEAD2)) {
canbehead = B_FALSE;
}
if (canbehead) {
if (victim && (victim->race->id == R_EARTHWYRM)) {
return "bisect";
@ -2006,6 +2011,36 @@ char *numtotext(int num, char *buf) {
case 10:
snprintf(buf, BUFLEN, "ten");
break;
case 11:
snprintf(buf, BUFLEN, "eleven");
break;
case 12:
snprintf(buf, BUFLEN, "twelve");
break;
case 13:
snprintf(buf, BUFLEN, "thirteen");
break;
case 14:
snprintf(buf, BUFLEN, "fourteen");
break;
case 15:
snprintf(buf, BUFLEN, "fifteen");
break;
case 16:
snprintf(buf, BUFLEN, "sixteen");
break;
case 17:
snprintf(buf, BUFLEN, "seventeen");
break;
case 18:
snprintf(buf, BUFLEN, "eighteen");
break;
case 19:
snprintf(buf, BUFLEN, "nineteen");
break;
case 20:
snprintf(buf, BUFLEN, "twenty");
break;
default:
snprintf(buf, BUFLEN, "%d",num);
break;