- [+] vampire gas cloud not working for player

- [+] monsters should only weild weapons if they are better than their
      inbuilt attcaks!
- [+] show dtected obkects in bold green
- [+] bug: can blink into impassable objects
- [+] infinite loop in ai turn for porcupine.
    - [+] movetowards()
* [+] vampires
- [+] vampire changes back to its original form.  CRASH.
This commit is contained in:
Rob Pearce 2011-08-05 21:34:35 +00:00
parent 81c7f37eff
commit 00f9d4e0bf
15 changed files with 427 additions and 159 deletions

15
ai.c
View File

@ -711,9 +711,16 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
} // end if attackok
// if we could see our traget, but everything we tried failed (spells, moving and ranged attack),
// just rest.
// either rest or move randomly.
if (movefailed) {
makenoise(lf, N_FRUSTRATED);
if (onein(2)) {
rest(lf, B_TRUE);
} else {
if (dorandommove(lf, B_NOBADMOVES, B_FALSE)) {
rest(lf, B_TRUE);
}
}
return B_FALSE;
}
} else {
@ -1494,6 +1501,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
f = hasflag(ot->flags, purpose);
if (f) {
if ((f->val[1] == NA) || pctchance(f->val[1])) {
int range;
switch (f->val[0]) {
case ST_VICTIM:
@ -1561,7 +1569,10 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
default:
break;
}
} else { // failed pctchance for spell
if (db) dblog(".oO { failed pct check for casting %s }", ot ? ot->name : "?unkownspell?");
return B_FALSE;
}
} else {
// invalid spell for this purpose
if (db) dblog(".oO { cant cast %s - not valid for given purpose }", ot ? ot->name : "?unkownspell?");

View File

@ -255,7 +255,6 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
}
// then use all our innate attacks..
getflags(lf->flags, F_HASATTACK, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
@ -2160,4 +2159,24 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
} // end if (fid == hitconfer)
}
if (wep && owner && victim) {
if ((wep->type->id == OT_TEETH) && lfhasflag(owner, F_VAMPIRIC) && isbleeding(victim)) {
// drain life!
gainhp(owner, dam);
if (isplayer(owner)) {
char lfname[BUFLEN];
char victimname[BUFLEN];
getlfname(owner,lfname);
getlfname(victim, victimname);
msg("You suck %s%s blood!", victimname, getpossessive(victimname));
} else if (cansee(player, owner)) {
char lfname[BUFLEN];
char victimname[BUFLEN];
getlfname(owner,lfname);
getlfname(victim, victimname);
msg("%s sucks %s%s blood!", lfname, victimname, getpossessive(victimname));
}
}
}
}

17
defs.h
View File

@ -735,6 +735,7 @@ enum RACE {
R_ANTS,
R_ANTLION,
R_BAT,
R_BATVAMPIRE,
R_BEAR,
R_BEARCUB,
R_BEARGRIZZLY,
@ -895,6 +896,7 @@ enum OBTYPE {
OT_TREE,
// food
OT_BERRY,
OT_GARLIC,
OT_NUT,
OT_BANANA,
OT_BANANASKIN, // not really food
@ -1489,6 +1491,7 @@ enum NOISETYPE {
N_FLY,
N_WARCRY,
N_LOWHP,
N_FRUSTRATED,
};
enum LFSIZE {
@ -1838,8 +1841,10 @@ enum FLAG {
//F_SPELLLETTER, // text[0] = letter to cast this spell
F_AICASTTOFLEE, // AI can cast this spell to help flee/heal
// v0 is who to target
// v1 is pct chance of using this
F_AICASTTOATTACK, // AI can cast this spell to attack
// v0 is who to target
// v1 is pct chance of using this
F_AIBOOSTITEM, // ai will use this item to boost/buff itself.
// if using this on wands, update aiobok() !
F_AIHEALITEM, // ai will use this item when low on hp
@ -1858,6 +1863,7 @@ enum FLAG {
F_COUNTER, // generic counter flag for race abilities.
F_DEBUG, // debugging enabled
F_ACCURACYMOD, // modify your accuracy by val0
F_VAMPIRIC, // successful bite attacks form this lf will heal it
F_VEGETARIAN, // this lf will not eat meat.
F_PARTVEGETARIAN,// this lf will only eat if hunger >= 'hungry'
F_CARNIVORE, // this lf will only eat meat.
@ -1934,8 +1940,13 @@ enum FLAG {
// v2 is counter until casting
// text is: "targlfid;targobid;mapid;cellx;celly;"
F_AVOIDCURSEDOB, // for AI animals - they will avoid walking on obid 'text'
F_AVOIDOB, // for AI - they will avoid walking on obid 'text'
// (text is a long)
// if v0 is not NA, then only avoid it if its blessed
// value == v0.
F_AVOIDOBTYPE, // AI won't walk on top of obtype v0.
// if v1 == B_TRUE, then avoid lfs weilding this
// object too.
F_STAYINHABITAT, // lf will not walk onto a cell of a different
// habitat
F_STAYINROOM, // lf will not walk out of roomid v0
@ -2048,6 +2059,7 @@ enum FLAG {
// v0 = max distance to splatter (or UNLIMITED)
// text = type of object to splatter
F_OBESE, // double base weight for race!
F_FORCEPOLY, // when this lf polymorphs, always chance to raceid v0
F_ORIGRACE, // original player race (if you polymorphed)
F_ORIGJOB, // original player job (if you polymorphed)
F_POLYMORPHED, // lf has been polymorphed
@ -2113,7 +2125,8 @@ enum FLAG {
// otherwise just an indicative size is shown
F_DETECTMAGIC, // autodetect magic/special objects
F_DETECTMETAL, // autodetect nearby metal
F_DETECTOBS, // autodetect nearby obs in orthog dist v0
F_DETECTOBS, // autodetect nearby obs of type v1 in orthog dist v0
// v1 = NA means everything.
F_DISEASEIMMUNE, // lf can't be diseased
F_DRUNK, // v1 is drunknness - 1-5.
F_ENHANCESEARCH, // gives v0 bonus on search checks.

10
flag.c
View File

@ -100,6 +100,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
f->val[1] += val2;
f->val[2] += val3;
// TODO: how to handle text??
f->text = strdup("");
return f;
}
}
@ -303,6 +304,15 @@ flagpile_t *addflagpile(lifeform_t *owner, object_t *ob) {
return fp;
}
void changeflagtext(flag_t *f, char *newtext) {
free(f->text);
if (newtext) {
f->text = strdup(newtext);
} else {
f->text = strdup("");
}
}
void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id) {
flag_t *f;
for (f = src->first ; f ; f = f->next) {

1
flag.h
View File

@ -8,6 +8,7 @@ flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char
flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int timeleft);
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known, long obfromid);
flagpile_t *addflagpile(lifeform_t *owner, object_t *o);
void changeflagtext(flag_t *f, char *newtext);
void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id);
void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime);
int countflags(flagpile_t *fp);

13
god.c
View File

@ -293,7 +293,7 @@ int godgiftmaybe(enum RACE rid) {
int chance;
// ie. 100 -> 2%
// ie. 500 -> 10%
chance = piety / 5;
chance = piety / 50;
if (pctchance(chance)) { // if this is true, you get a gift.
char obtogive[BUFLEN];
int rollagain = B_TRUE;
@ -307,7 +307,7 @@ int godgiftmaybe(enum RACE rid) {
flag_t *f;
object_t *wep;
rollagain = B_FALSE;
switch (rnd(5,5)) {
switch (rnd(1,5)) {
case 1:
sprintf(obtogive, "3-5 cursed potions of water");
break;
@ -338,7 +338,7 @@ int godgiftmaybe(enum RACE rid) {
break;
case 5:
msg("\"Go forth and kill in my name!\"");
setrace(player, R_VAMPIRE, B_TRUE);
setrace(player, R_VAMPIRE, B_TRUE); // ie. don't set origrace!
break;
}
}
@ -394,8 +394,9 @@ int godgiftmaybe(enum RACE rid) {
}
}
// since you got a gift, lower piety back to 100 (slightly pleased)
setpiety(rid, 101);
// since you got a gift, lower piety a little.
//setpiety(rid, 101);
modpiety(rid, -50);
} // end if (pctchance enough to get a gift)
} // end if (piety > 100)
return gotgift;
@ -444,7 +445,7 @@ void pleasegod(enum RACE rid, int amt) {
modpiety(rid, amt);
// announce
//msg("You feel like %s approves of your actions.", lfname);
msg("You feel like %s approves of your actions.", lfname);
godgiftmaybe(rid);
}

4
io.c
View File

@ -7384,7 +7384,7 @@ void drawstatus(void) {
if (hlev == H_NONE) {
strcpy(buf2, "");
} else {
gethungername(gethungerlevel(f->val[0]), buf2);
gethungername(player, gethungerlevel(f->val[0]), buf2);
capitalise(buf2);
}
} else {
@ -8162,7 +8162,7 @@ void showlfstats(lifeform_t *lf, int showall) {
if (f) {
doheadingsmall(mainwin, y2, x2, ftext, "Hunger");
gethungername(gethungerlevel(f->val[0]), buf);
gethungername(lf, gethungerlevel(f->val[0]), buf);
capitalise(buf);
wprintw(mainwin, "%-14s", buf); y2++;
/*

192
lf.c
View File

@ -1236,6 +1236,16 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
// stop hiding
killflagsofid(lf->flags, F_HIDING);
// willing this spell? reset counter!
// do this _before_ casting the spell,
// in case the spell causes us to lose
// the f_canwill flag (eg. polymorph)
if (willflag) {
if (willflag->val[2] != NA) {
willflag->val[1] = -1;
}
}
// cast the spell
f = hasflag(sp->flags, F_CASTINGTIME);
if (f) {
@ -1284,13 +1294,6 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
}
}
// willing this spell? reset counter!
if (willflag) {
if (willflag->val[2] != NA) {
willflag->val[1] = -1;
}
}
// successful cast?
if (!rv) {
practice(lf, SK_SPELLCASTING, 1);
@ -1330,6 +1333,16 @@ int checkfordrowning(lifeform_t *lf, object_t *o) {
// will you drown?
if (depth >= DP_HEAD) {
if (lf->race->id == R_VAMPIRE) {
if (isplayer(lf)) {
msg("^BThe running water burns you!");
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("^%cThe running water burns %s!", getlfcol(lf, CC_BAD), lfname);
}
losehp(lf, roll("6d6"), DT_DIRECT, NULL, "running water");
}
if (!slev && !lfhasflag(lf, F_BREATHWATER)) {
int damamt;
@ -1673,9 +1686,9 @@ void die(lifeform_t *lf) {
}
}
if (lf->race->id == R_VAMPIRE) {
// if are asleep, we will die normally
if (lfhasflag(lf, F_ASLEEP)) {
if ((lf->race->id == R_VAMPIRE) && !hasflag(lf->flags, F_ORIGRACE)) {
// if are asleep or killed by running water/sunlight, we will die normally
if (lfhasflag(lf, F_ASLEEP) || (lf->lastdamtype == DT_DIRECT)) {
noise(lf->cell, lf, NC_OTHER, 4, "a horrified scream!", "screams in horror!");
} else if (findobinmap(lf->cell->map, OT_COFFIN)) { // coffin around?
// restore 1 hp
@ -1684,7 +1697,9 @@ void die(lifeform_t *lf) {
// convert into a gas cloud!
dospelleffects(NULL, OT_S_GASEOUSFORM, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
// ai will now look for our coffin
if (!isplayer(lf)) {
if (isplayer(lf)) {
msg("^GYou feel the presence of a nearby coffin...");
} else {
addflag(lf->flags, F_WANTS, OT_COFFIN, B_COVETS, NA, NULL);
addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
}
@ -1854,8 +1869,7 @@ void die(lifeform_t *lf) {
// remember what killed us.
f = hasflag(corpse->flags, F_CORPSEOF);
if (f) {
free(f->text);
f->text = strdup(lf->lastdam);
changeflagtext(f, lf->lastdam);
}
}
@ -2894,8 +2908,7 @@ void enhanceskills(lifeform_t *lf) {
break;
}
if (!streq(newtext, f->text)) {
free(f->text);
f->text = strdup(newtext);
changeflagtext(f, newtext);
if (isplayer(lf)) msg("^gYour unarmed attack damage has increased!");
}
}
@ -3252,7 +3265,6 @@ int flee(lifeform_t *lf) {
}
// are we fleeing?
getflags(lf->flags, F_FLEEFROM, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
@ -4193,8 +4205,42 @@ object_t *getbestweapon(lifeform_t *lf) {
object_t *bestwep = NULL;
//int bestmaxdam = -999;
object_t *o;
obpile_t *op = NULL;
bestwep = getweapon(lf);
if (!bestwep) {
int i;
// get best innate attack
getflags(lf->flags, F_HASATTACK, F_NONE);
for (i = 0; i < nretflags; i++) {
objecttype_t *ot;
if (!op) {
op = addobpile(NULL, NULL, NULL);
}
ot = findot(retflag[i]->val[0]);
if (ot) {
o = addob(op, ot->name);
if (isweapon(o) && !isfirearm(o) && canweild(lf, o) && isbetterwepthan(o, bestwep)) {
bestwep = o;
// inherit damage from hasattack flag
if (strlen(retflag[i]->text)) {
flag_t *damflag;
damflag = hasflag(bestwep->flags, F_DAM);
if (damflag) {
free(damflag->text);
damflag->text = strdup(retflag[i]->text);
}
}
} else {
killob(o);
}
}
}
}
for (o = lf->pack->first ; o ; o = o->next) {
// if it does damage and we can weild it...
@ -4216,6 +4262,15 @@ object_t *getbestweapon(lifeform_t *lf) {
}
*/
if (bestwep && (bestwep->pile->owner == NULL)) {
// ie. best weapon is an innate attack
bestwep = NULL;
}
if (op) {
killobpile(op);
}
return bestwep;
}
@ -4442,7 +4497,7 @@ enum HUNGER gethungerlevel(int hunger) {
return H_STARVED;
}
char *gethungername(enum HUNGER hunger, char *buf) {
char *gethungername(lifeform_t *lf, enum HUNGER hunger, char *buf) {
switch (hunger) {
case H_STUFFED:
strcpy(buf, "stuffed");
@ -4451,19 +4506,39 @@ char *gethungername(enum HUNGER hunger, char *buf) {
strcpy(buf, "full");
break;
case H_NONE:
if (lf && (lf->race->id == R_VAMPIRE)) {
strcpy(buf, "not thirsty");
} else {
strcpy(buf, "not hungry");
}
break;
case H_PECKISH:
if (lf && (lf->race->id == R_VAMPIRE)) {
strcpy(buf, "parched");
} else {
strcpy(buf, "peckish");
}
break;
case H_HUNGRY:
if (lf && (lf->race->id == R_VAMPIRE)) {
strcpy(buf, "thirsty");
} else {
strcpy(buf, "hungry");
}
break;
case H_VHUNGRY:
if (lf && (lf->race->id == R_VAMPIRE)) {
strcpy(buf, "very thirsty");
} else {
strcpy(buf, "very hungry");
}
break;
case H_STARVING:
if (lf && (lf->race->id == R_VAMPIRE)) {
strcpy(buf, "dehydrating");
} else {
strcpy(buf, "starving");
}
break;
case H_STARVED:
strcpy(buf, "starved");
@ -6262,16 +6337,14 @@ void givejob(lifeform_t *lf, enum JOB jobid) {
f = lfhasflagval(lf, F_HASATTACK, OT_FISTS, NA, NA, NULL);
if (f) {
// monk fists do more damage
free(f->text);
f->text = strdup("1d4");
changeflagtext(f, "1d4");
}
} else if (j->id == J_PIRATE) {
flag_t *f;
f = lfhasflagval(lf, F_HASATTACK, OT_FISTS, NA, NA, NULL);
if (f) {
f->val[0] = OT_HOOKHAND;
free(f->text);
f->text = strdup("1d4");
changeflagtext(f, "1d4");
}
} else if (j->id == J_SHOPKEEPER) {
// shopkeepers are not hostile.
@ -8330,7 +8403,8 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL);
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL);
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roars");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roar");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "roars^a roar");
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, 2, 2, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
@ -9510,6 +9584,28 @@ void initrace(void) {
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings");
addrace(R_BATVAMPIRE, "vampire bat", 6, 'B', C_BLUE, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 76, NA, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, 84, NA, "");
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, "");
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_HITDICE, 2, 4, NA, "");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3");
addflag(lastrace->flags, F_MAXATTACKS, 2, 2, NA, NULL);
addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL);
addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings");
addrace(R_BEAR, "black bear", 150, 'q', C_BLUE, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL);
@ -9679,6 +9775,8 @@ void initrace(void) {
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "barks^barking");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_FLEEONHPPCT, 60, NA, NA, "");
addrace(R_DOGBLINK, "blink dog", 35, 'd', C_BLUE, MT_FLESH, RC_ANIMAL);
@ -9703,6 +9801,8 @@ void initrace(void) {
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting
addflag(lastrace->flags, F_CANWILL, OT_S_BLINK, 2, 2, "pw:1;");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "barks^barking");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addrace(R_DOGDEATH, "death hound", 40, 'd', C_MAGENTA, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_NUMAPPEAR, 2, 6, NA, "");
@ -9727,6 +9827,8 @@ void initrace(void) {
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "howls^a howl");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling");
addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 24, "10-15");
addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL);
addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL);
@ -9751,6 +9853,8 @@ void initrace(void) {
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "barks^barking");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 2, NA, "growls^growling");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian
@ -10184,6 +10288,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 8, 8, NULL);
addflag(lastrace->flags, F_LEVRACE, 5, R_WOLF, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling");
addflag(lastrace->flags, F_FLEEONHPPCT, 75, NA, NA, "");
addrace(R_WOLF, "wolf", 25, 'd', C_GREY, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL);
@ -10208,6 +10313,7 @@ void initrace(void) {
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 5, 5, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling");
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, "");
// insects
@ -10460,21 +10566,33 @@ void initrace(void) {
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, "3d6");
addflag(lastrace->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 8, NA, NA, NULL);
addflag(lastrace->flags, F_AVOIDOBTYPE, OT_GARLIC, B_TRUE, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_FAST, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 8, 3, NA, NULL);
addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL);
addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "coffin");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+4");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4+3");
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_CANWILL, OT_S_CHARM, 3, 3, "pw:6;");
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 5, 5, "range:3;");
addflag(lastrace->flags, F_CANWILL, OT_S_STUN, 5, 5, "pw:1;");
addflag(lastrace->flags, F_CANWILL, OT_S_POLYMORPH, 3, 3, "pw:1;");
addflag(lastrace->flags, F_FORCEPOLY, R_BATVAMPIRE, 20, 20, "pw:3;");
addflag(lastrace->flags, F_DETECTOBS, 10, OT_COFFIN, NA, NULL);
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pile of ash");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "hisses angrily^an angry hiss");
// special: change to gas cloud with 1 hp on death, if not asleep
// special: flee from garlic
// TODO: can shapeshift to bat
// TODO: flee from holy symbols / garlic
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
@ -12569,6 +12687,10 @@ void modhunger(lifeform_t *lf, int amt) {
return;
}
if (isundead(lf) && (lf->race->id != R_VAMPIRE)) {
return;
}
// modify for effects
if (amt > 0) {
int multiplier = 0;
@ -12622,7 +12744,7 @@ void modhunger(lifeform_t *lf, int amt) {
if (isplayer(lf)) {
gethungername(posthlev, buf);
gethungername(lf, posthlev, buf);
msg("^wYou are %s%s%s%c",
((amt < 0) && (posthlev > H_NONE)) ? "still " : "",
needfeeling ? "feeling " : "",
@ -12633,7 +12755,7 @@ void modhunger(lifeform_t *lf, int amt) {
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
gethungername(posthlev, buf);
gethungername(lf, posthlev, buf);
msg("^%c%s looks %s%c", getlfcol(lf, CC_BAD), lfname, buf, (needexclam) ? '!' : '.');
}
@ -13792,6 +13914,7 @@ void setguntarget(lifeform_t *lf, lifeform_t *targ) {
void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
flag_t *f,*nextf;
int i;
int nkilled = 0;
race_t *newrace;
char buf[BUFLEN];
@ -13862,8 +13985,10 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
nextf = f->next;
if (f->lifetime == FROMRACE) {
killflag(f);
nkilled++;
} else if ((f->lifetime > 0) && (f->id != F_POLYMORPHED)) {
killflag(f);
nkilled++;
}
}
@ -14475,7 +14600,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r
}
break;
case SC_RESISTMAG:
attrib = (getattr(lf, A_CON)/4) + (getattr(lf, A_WIS)/4) + getmr(lf);
attrib = (getattr(lf, A_CON)/6) + (getattr(lf, A_WIS)/4) + getmr(lf);
break;
case SC_SEARCH:
attrib = (getskill(lf, SK_SPOTHIDDEN)*4);
@ -15045,6 +15170,7 @@ int takeoff(lifeform_t *lf, object_t *o) {
if ((gamemode == GM_GAMESTARTED)) {
if (isplayer(lf)) {
msg("You take off %s.", obname);
statdirty = B_TRUE;
} else if (cansee(player, lf)) {
getlfname(lf, buf);
capitalise(buf);
@ -15335,6 +15461,18 @@ void turneffectslf(lifeform_t *lf) {
if (isdead(lf)) return;
}
}
// vampire in sunlight?
if ((lf->race->id == R_VAMPIRE) && isoutdoors(lf->cell->map) && !isnighttime()) {
if (isplayer(lf)) {
msg("^bThe sunlight burns you!");
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("^%cThe sunlight burns %s!", getlfcol(lf, CC_BAD), lfname);
}
losehp(lf, roll("6d6"), DT_DIRECT, NULL, "sunlight");
if (isdead(lf)) return;
}
// float up into space?
if (lf->cell->map->region->rtype->id == RG_WORLDMAP) {

2
lf.h
View File

@ -120,7 +120,7 @@ int gethidemodifier(lifeform_t *lf);
int gethitdice(lifeform_t *lf);
int gethppct(lifeform_t *lf);
enum HUNGER gethungerlevel(int hunger);
char * gethungername(enum HUNGER hunger, char *buf);
char *gethungername(lifeform_t *lf, enum HUNGER hunger, char *buf);
int gethungerval(lifeform_t *lf);
job_t *getjob(lifeform_t *lf);
int getlastdir(lifeform_t *lf);

34
map.c
View File

@ -30,6 +30,9 @@ extern lifeform_t *player;
extern lifeform_t *godlf[];
extern int ngodlfs;
extern flag_t *retflag[];
extern int nretflags;
extern glyph_t tempglyph;
extern enum OBCLASS sortorder[];
@ -1247,7 +1250,7 @@ void calclight(map_t *map) {
if (isoutdoors(map)) {
int hours,mins,secs;
splittime(&hours,&mins,&secs);
if ((hours < 5) || (hours >= 19)) {
if (isnighttime()) {
// ie. nighttime, after 7pm or before 5am
} else {
// ie. daytime
@ -3861,6 +3864,7 @@ int isempty(cell_t *c) {
//returns TT_ based on what you can scan there
int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) {
flag_t *f;
int i;
// handle scanner
f = lfhasflag(player, F_DETECTLIFE);
if (f) {
@ -3933,23 +3937,34 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) {
return TT_MONSTER;
}
f = lfhasflag(player, F_DETECTOBS);
if (f) {
// get list of all detected ob ids.
getflags(player->flags, F_DETECTOBS, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (getcelldistorth(player->cell, c) <= f->val[0]) {
object_t *o;
for (o = c->obpile->first ; o ; o = o->next) {
if ((f->val[1] == NA) || (o->type->id == f->val[1])) {
if (!hasflag(o->flags, F_NOPICKUP) && !hasflag(o->flags, F_DOOR)) {
*thing = o;
if (glyph) {
glyph->ch = '*';
glyph->colour = C_GREY;
glyph->colour = C_BOLDGREEN;
}
if (desc) {
if (f->val[1] == NA) {
strcpy(desc, "a detected object");
} else {
getobname(o, desc, o->amt);
}
}
if (desc) sprintf(desc, "an object");
return TT_OBJECT;
}
}
}
}
}
return B_FALSE;
}
@ -4000,6 +4015,15 @@ int isnewcellok(cell_t *cell, char *err) {
return B_TRUE;
}
int isnighttime(void) {
int hours,mins,secs;
splittime(&hours,&mins,&secs);
if ((hours < 5) || (hours >= 19)) {
return B_TRUE;
}
return B_FALSE;
}
int isonmap(map_t *map, int x, int y) {
if ((x < 0) || (y < 0)) {
return B_FALSE;

1
map.h
View File

@ -97,6 +97,7 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph);
int islit(cell_t *c);
int isloopdirok(cell_t *cell, int dir);
int isnewcellok(cell_t *cell, char *err);
int isnighttime(void);
int isonmap(map_t *map, int x, int y);
int isoutdoors(map_t *m);
int isroom(cell_t *c);

39
move.c
View File

@ -26,6 +26,9 @@ extern enum GAMEMODE gamemode;
extern enum ERROR reason;
extern void *rdata;
extern flag_t *retflag[];
extern int nretflags;
extern WINDOW *gamewin, *msgwin;
int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error) {
@ -1946,7 +1949,22 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) {
reason = E_OK;
// avoid this object in future
sprintf(buf, "%ld",o->id);
addflag(lf->flags, F_AVOIDCURSEDOB, NA, NA, NA, buf);
addflag(lf->flags, F_AVOIDOB, B_CURSED, NA, NA, buf);
return B_TRUE;
} else if (lfhasflagval(lf, F_AVOIDOBTYPE, o->type->id, NA, NA, NULL)) {
if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf,lfname);
getobname(o, buf, o->amt);
msg("%s %s away from %s!", lfname, isplayer(lf) ? "shy" : "shies", buf);
o->blessknown = B_TRUE;
if (didmsg) *didmsg = B_TRUE;
}
taketime(lf, getmovespeed(lf));
reason = E_OK;
// avoid this object in future
sprintf(buf, "%ld",o->id);
addflag(lf->flags, F_AVOIDOB, NA, NA, NA, buf);
return B_TRUE;
}
}
@ -2317,8 +2335,12 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
msg("You swap places with %s.", lfname);
}
} else {
// attack!
if (!onpurpose || canandwillmove(lf, dir, &errcode)) {
return attackcell(lf, cell, B_FALSE);
} else {
// won't attack for some reason.
return B_TRUE;
}
}
break;
case E_CANTMOVE:
@ -2540,6 +2562,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
// don't attack other monsters
if (cell->lf) { // if someone is in the way
object_t *defenderwep = NULL;
if (lf->race->raceclass->id == RC_INSECT) {
if (hasactivespell(cell->lf, OT_S_REPELINSECTS)) {
if (error) *error = E_WONT;
@ -2547,6 +2570,14 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
}
}
defenderwep = getweapon(cell->lf);
if (defenderwep) {
if (lfhasflagval(lf, F_AVOIDOBTYPE, defenderwep->type->id, B_TRUE, NA, NULL)) {
if (error) *error = E_WONT;
return B_FALSE;
}
}
if (!isplayer(lf)) { // if we are a monster
// if the person in the way isn't our enemy...
if (!areenemies(lf, cell->lf)) {
@ -2573,10 +2604,10 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
for (o = cell->obpile->first ; o ; o = o->next) {
flag_t *f;
sprintf(buf, "%ld",o->id);
f = lfhasflagval(lf, F_AVOIDCURSEDOB, NA, NA, NA, buf);
f = lfhasflagval(lf, F_AVOIDOB, NA, NA, NA, buf);
if (f) {
// still cursed?
if (iscursed(o)) {
if ((f->val[0] != NA) && (o->blessed == f->val[0])) {
if (error) *error = E_WONT;
return B_FALSE;
} else {

View File

@ -2675,6 +2675,7 @@ objecttype_t *findotn(char *name) {
modname = strrep(modname, "blocks ", "block ", NULL);
modname = strrep(modname, "cans ", "can ", NULL);
modname = strrep(modname, "chunks ", "chunk ", NULL);
modname = strrep(modname, "cloves ", "clove ", NULL);
modname = strrep(modname, "flasks ", "flask ", NULL);
modname = strrep(modname, "gems ", "gem ", NULL);
modname = strrep(modname, "leaves ", "leaf ", NULL);
@ -6236,6 +6237,12 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 15, NA, "");
addot(OT_GARLIC, "clove of garlic", "A very pungent clove of raw garlic. ", MT_FOOD, 0.1, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, "");
addot(OT_NUT, "peanut", "A species in the legume family.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 12, NA, "");
@ -7088,6 +7095,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// l2
addot(OT_S_LOWERMETAB, "lower metabolism", "Slow your body's functions, decreasing your rate of hunger but also your speed. At power level V your speed is no longer affected.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
@ -7199,6 +7207,8 @@ void initobjects(void) {
addot(OT_S_POLYMORPH, "polymorph", "Transmutes the target into a new living race.\nBecomes semi-controlled at Power V, and fully-controlled at power VIII.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, 10, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
// l7
addot(OT_S_GASEOUSFORM, "gaseous form", "Changes the caster into a cloud of gas.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
@ -7390,6 +7400,7 @@ void initobjects(void) {
addot(OT_A_POLYREVERT, "revertform", "Revert to your original form.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, 10, NA, NULL);
addot(OT_A_QUIVERINGPALM, "quivering palm", "A deadly palm strike which knocks the molecules in the target's body out of alignment.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_PRAY, "pray", "Ask for help from a higher being.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
@ -9581,7 +9592,6 @@ int isbetterwepthan(object_t *a, object_t *b) {
acca = getobaccuracy(a, a->pile->owner);
accb = getobaccuracy(b, b->pile->owner);
if (db) {
msg("PREACC:a=%s:%d(acc %d), b=%s:%d(acc %d)",namea,dama,(int)acca, nameb, damb,(int)accb);
}
@ -12631,7 +12641,9 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
*seen = B_TRUE;
}
}
if (!isundead(lf)) {
modhunger(lf, -pctof(0.05, (float)HUNGERCONST));
}
break;
case OT_POT_BLOOD:
if (lf->race->id == R_VAMPIRE) {
@ -12643,6 +12655,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
b = B_BLESSED;
}
dospelleffects(lf, OT_S_HEALINGMAJ,b ? 5 : 1, lf, NULL, lf->cell, b, seen, B_TRUE);
modhunger(lf, -HUNGERCONST);
} else {
if (isplayer(lf)) msg("Yuck, this tastes like blood!");
}

18
spell.c
View File

@ -1406,7 +1406,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
char dirch;
char targetname[BUFLEN];
flag_t *f;
int heavyamt = 8;
int heavyamt = 5;
int badweapon = B_FALSE;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
@ -2183,7 +2183,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// controlled
// must be within line of sight.
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (!targcell) {
if (!targcell || !cellwalkable(caster, targcell, NULL)) {
fizzle(caster);
return B_TRUE;
}
@ -4109,8 +4109,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
flag_t *f;
f = hasflag(o->flags, F_WALKDAM);
if (f) {
free(f->text);
f->text = strdup(dambuf);
changeflagtext(f, dambuf);
}
}
}
@ -5819,6 +5818,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
breakallgrabs(caster);
} else if (spellid == OT_S_POLYMORPH) {
race_t *r = NULL;
flag_t *f;
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
@ -5828,7 +5828,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE;
}
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if ((target != caster) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (isplayer(target)) {
msg("You feel momentarily different.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -5840,6 +5840,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_FALSE;
}
f = lfhasflag(target, F_FORCEPOLY);
if (f) {
r = findrace(f->val[0]);
} else {
if (lfhasflag(caster, F_CONTROL)) {
if (power < 5) {
power = 5;
@ -5880,6 +5884,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
}
} // end if forcepoly
if (r == target->race) {
fizzle(caster);
@ -6984,9 +6989,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = hasflag(o->flags, F_DAM);
if (f) {
char buf[BUFLEN];
free(f->text);
sprintf(buf, "2d%d",power);
f->text = strdup(buf);
changeflagtext(f, buf);
}
} else {
killob(o);

2
text.c
View File

@ -439,6 +439,8 @@ char *makeplural(char *text) {
if (rv) return newtext;
newtext = strrep(newtext, "chunk ", "chunks ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "clove ", "cloves ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "flask ", "flasks ", &rv);
if (rv) return newtext;
newtext = strrep(newtext, "gem ", "gems ", &rv);