- [+] don't make skill points exponentially harder to gain (or greatly

reduce the impact)
- [+] remove 'attacked peaceful' penalty for animals
- [+] ring of decel should also not let YOU throw. limit your throw
      range to 1.
- [+] fruit should get bruised when it takes dt_projectile / dt_bash
      damage?
    - [+] -25% nutrition.
    - [+] f_bruisable
    - [+] f_bruised
    - [+] *addobject()
    - [+] getobname()
- [+] gluon (yellow)
    - [+] f_adhesive, xx
    - [+] sticky
        - [+] str check of diff xx
        - [+] - weapons have a chance of sticking to it when you hit it
        - [+] same if you block its attack with a shield.
        - [+] always stick if thrown .
- [+] bug on load - no gods.
    - [+] need to repopulate godlf[] on load.
- [+] monsters getting stuck. changed so that turntoface isn't called
      if you just turned.
- [+] sanctuary potion should knock other lfs away
- [+] backstabbing shoudl please felix
- [+] genericize determining casttype
- [+] remove nutrition penalty for uncooked food - the threat of
      disease should be enough.
This commit is contained in:
Rob Pearce 2012-04-18 21:34:41 +00:00
parent 97eda5fa2d
commit 8a70cd0f99
10 changed files with 303 additions and 119 deletions

50
ai.c
View File

@ -171,32 +171,37 @@ enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) {
if (db) dblog(".oO { Cannot cast spell, I don't have my spellcast object }");
return OT_NONE;
}
f = lfhasflag(lf, F_CASTTYPE);
if (f) {
switch (f->val[0]) {
case CT_GAZE: // gaze into victim's eyes: they must be able to see you and vice versa
if (!cansee(victim, lf) || !cansee(lf, victim)) {
if (db) dblog(".oO { Cannot cast spell, no 2way los for gaze attack or victims eyes covered }");
return OT_NONE;
}
break;
case CT_EYESPIT: // spit into the victim's eyes. lof is checked in aispellok
if (!cansee(victim, lf) ) {
if (db) dblog(".oO { Cannot cast spell, no 2way los for gaze attack or victims eyes covered }");
return OT_NONE;
}
break;
}
}
getflags(lf->flags, retflag, &nretflags, F_CANCAST, F_CANWILL, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (aispellok(lf, f->val[0], victim, F_AICASTTOATTACK)) {
enum CASTTYPE ctype;
int ok = B_TRUE;
ctype = getcasttype(lf, f->val[0]);
switch (ctype) {
case CT_GAZE: // gaze into victim's eyes: they must be able to see you and vice versa
if (!cansee(victim, lf) || !cansee(lf, victim)) {
if (db) dblog(".oO { Cannot cast spell, no 2way los for gaze attack or victims eyes covered }");
ok = B_FALSE;
}
break;
case CT_EYESPIT: // spit into the victim's eyes. lof is checked in aispellok
if (!cansee(victim, lf) ) {
if (db) dblog(".oO { Cannot cast spell, no 2way los for gaze attack or victims eyes covered }");
ok = B_FALSE;
}
break;
default:
break;
}
if (ok) {
poss[nposs] = f->val[0];
nposs++;
}
}
}
// select a random one
if (nposs > 0) {
@ -1892,7 +1897,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
int x,y;
cell_t *c;
cell_t *c,*origc;
int db = B_FALSE;
if (lfhasflag(lf, F_DEBUG)) {
@ -1902,6 +1907,7 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
x = f->val[0];
y = f->val[1];
if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y);
origc = lf->cell;
c = getcellat(lf->cell->map, x, y);
if (c) {
// try to move towards the cell
@ -1912,8 +1918,14 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
killflag(f);
// remember NOT to target this one.
addignorecell(lf, c);
} else {
int turned = B_FALSE;
if (lf->cell == origc) {
if (db) dblog(".oO { turned to face f_targetcell. (still at %d,%d) }",lf->cell->x, lf->cell->y);
turned = B_TRUE;
} else {
if (db) dblog(".oO { successfully walked towards f_targetcell. arrived at %d,%d }",lf->cell->x, lf->cell->y);
}
// moved towards it.
// reset lifetime
f->lifetime = aigetchasetime(lf);
@ -1935,9 +1947,11 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
}
killflag(f);
} else {
if (!turned) {
turntoface(lf, c);
}
}
}
} else {
if (db) dblog(".oO { f_targetcell doesn't exist. abandoning. }");
// destination doesn't exist!

View File

@ -622,6 +622,9 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
break;
}
} else if (attackedpeaceful) {
if (getraceclass(attacktarget) == RC_ANIMAL) {
// attacking helpless animals is fine
} else {
angergodmaybe(R_GODMERCY, 15, GA_ASSAULT);
angergodmaybe(R_GODLIFE, 15, GA_ASSAULT);
angergodmaybe(R_GODPURITY, 50, GA_ASSAULT);
@ -635,8 +638,13 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
default:
break;
}
}
} else if (attackedhelpless) {
if (getraceclass(attacktarget) == RC_ANIMAL) {
// attacking helpless animals is fine
} else {
angergodmaybe(R_GODMERCY, 15, GA_ATTACKHELPLESS);
}
if (getalignment(attacktarget) != AL_EVIL) {
angergodmaybe(R_GODPURITY, 50, GA_ATTACKHELPLESS);
pleasegodmaybe(R_GODTHIEVES, 5);
@ -1018,6 +1026,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
int damreducedbyarmour = 0;
int backstab = B_FALSE;
int prebleed = B_FALSE;
int stopnow = B_FALSE;
if (firstisbackstab && (i == 0)) backstab = B_TRUE;
@ -1310,12 +1319,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (backstab) {
practice(lf, SK_BACKSTAB, 1);
pleasegodmaybe(R_GODTHIEVES, 8);
}
// now handle the extra hp loss effects which we postponed above.
losehpeffects(victim, dam[i], damtype[i], lf, wep, B_NORETALIATE, waskod, &waskod, prebleed);
if (fatal || waskod || dodged) break; // stop now, don't process further damtypes!
if (fatal || waskod || dodged || stopnow) break; // stop now, don't process further damtypes!
} // end foreach damtype
if (waskod) {
@ -1323,7 +1333,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
// other effects
if ((victim->material->id == MT_WATER) && wep && !isunarmed) {
makewet(wep, 1);
}
@ -1397,8 +1406,22 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
} // end if !isdead(victim)
// retaliation happens even if victim died
if (!blocked && !dodged) {
// adhesion?
f = lfhasflag(victim, F_ADHESIVE);
if (f && wep && !isunarmed && !skillcheck(lf, SC_STR, f->val[0], 0)) {
// attacker's weapon sticks to it!
if (cansee(player, lf) || cansee(player, victim)) {
char wepname[BUFLEN];
real_getobname(wep, wepname, 1, B_PREMODS, B_NOCONDITION, B_NOBLINDADJUST, B_BLESSINGS, B_NOUSED, B_NOSHOWALL);
msg("^%c%s%s %s %s to %s!", getlfcol(lf, CC_BAD),
attackername, getpossessive(attackername), noprefix(wepname),
(wep->amt == 1) ? "sticks" : "stick", victimname);
}
moveob(wep, victim->pack, wep->amt);
}
// retaliation happens even if victim died
getflags(victim->flags, retflag, &nretflags, F_RETALIATE, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
@ -1891,6 +1914,21 @@ int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE da
takedamage(shield[i], dam, damtype);
practice(victim, SK_SHIELDS, 1);
}
if (!isdeadob(shield[i])) {
flag_t *f;
f = hasflag(lf->flags, F_ADHESIVE);
if (f && !skillcheck(victim, SC_STR, f->val[0], 0)) {
if (cansee(player, lf) || cansee(player, victim)) {
char attname[BUFLEN];
getlfname(lf, attname);
msg("^%c%s%s %s %s to %s!", getlfcol(victim, CC_BAD),
victimname, getpossessive(victimname), noprefix(shname),
(shield[i]->amt == 1) ? "sticks" : "stick", attname);
}
moveob(shield[i], lf->pack, shield[i]->amt);
}
}
// stop checking.
return B_TRUE;
}

47
data.c
View File

@ -912,6 +912,7 @@ void initjobs(void) {
f = addflag(lastjob->flags, F_STARTOBCLASS, 100, OC_BOOK, NA, NULL); addcondition(f, FC_IFMONSTER, 50);
// initial skills
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_BEGINNER, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_UNDEAD, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_DEMONS, PR_NOVICE, NA, NULL);
@ -931,7 +932,6 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, PR_ADEPT, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); // limit
@ -2441,6 +2441,7 @@ void initobjects(void) {
addot(OT_APPLE, "apple", "A crunchy apple.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_GREEN, '%', NA, NULL);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 40, NA, "");
addflag(lastot->flags, F_BRUISABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, "");
@ -2512,6 +2513,7 @@ void initobjects(void) {
addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread");
addot(OT_CACFRUIT, "cactus fruit", "The nutritous fruit from a cactus plant.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_RED, '%', NA, NULL);
addflag(lastot->flags, F_BRUISABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, "");
addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL);
addot(OT_CHEESE, "chunk of cheese", "A chunk of hard cheese.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY);
@ -2615,6 +2617,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addot(OT_TOMATO, "tomato", "A juicy red tomato.", MT_FOOD, 0.3, OC_FOOD, SZ_TINY);
addflag(lastot->flags, F_GLYPH, C_RED, '%', NA, NULL);
addflag(lastot->flags, F_BRUISABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 30, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL);
@ -3769,7 +3772,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_WARPWOOD, "warp wood", "Causes damage to all wooden object in the target area.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addot(OT_S_WARPWOOD, "warp wood", "Causes damage to all wooden objects in the target area.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_OBJECT, NA, NA, NULL);
@ -6940,7 +6943,7 @@ void initobjects(void) {
addot(OT_RING_NOINJURY, "ring of injury prevention", "Completely protects the wearer from crippling body injuries.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, "");
addflag(lastot->flags, F_VALUE, 350, NA, NA, NULL);
addot(OT_RING_DECELERATION, "ring of deceleration", "Protects the wearer from projectile attacks.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addot(OT_RING_DECELERATION, "ring of deceleration", "Slows down all nearby projectiles, providing protection from projectile attacks but also limiting their use.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, "");
addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_PROJECTILE, B_TRUE, NULL);
addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL);
@ -11755,7 +11758,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 3, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 1, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 3, NA, NA, NULL);
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
addflag(lastrace->flags, F_NATURALFLIGHT, B_TRUE, NA, NA, "");
@ -11764,7 +11767,7 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLSPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_CANCAST, OT_S_TELEKINESIS, NA, NA, "pw:5;");
addflag(lastrace->flags, F_CANCAST, OT_S_TELEKINESIS, NA, NA, "pw:4;");
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "gestures");
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
@ -12907,6 +12910,31 @@ void initrace(void) {
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL);
addrace(R_GLUON, "gluon", 1, 'F', C_YELLOW, MT_PLANT, RC_PLANT, "A walking plant-based monster whose body is covered with a thick glue-like secretion.");
addbodypart(lastrace, BP_BODY, "stalk");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_EXLOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_RANDOM, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_EXLOW, 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_NOCORPSE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_HITDICE, 3, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 4, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_ACIDATTACK, 5, NA, NULL);
addflag(lastrace->flags, F_MAXATTACKS, 1, 1, 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_ADHESIVE, 25, NA, NA, NULL);
addrace(R_IVYRAPID, "rapid ivy", 1, 'F', C_CYAN, MT_PLANT, RC_PLANT, "A strain of ivy which reproduces with incredible speed. Farmers find it difficult to remove due to its sharp spines.");
addbodypart(lastrace, BP_BODY, "stalk");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL);
@ -12993,6 +13021,7 @@ void initrace(void) {
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_ELECTRIC, NA, NA, NULL);
addrace(R_UNYON, "unyon", 0.5, 'F', C_WHITE, MT_PLANT, RC_PLANT, "This genetically engineered onion plant has developed its stinging fumes into a self-defense mechanism.");
addbodypart(lastrace, BP_BODY, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL);
@ -13455,7 +13484,6 @@ void initrace(void) {
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 6, NA, NA, NULL);
addrace(R_ANTS, "giant soldier ant", 25, 'a', C_ORANGE, MT_FLESH, RC_ANIMAL, "The fighter of the giant ant family. Giant soldier ants are equipped with a powerful acidic stinger.");
@ -13486,7 +13514,6 @@ void initrace(void) {
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:1d6;");
addflag(lastrace->flags, F_CANWILL, OT_A_STINGACID, NA, NA, "dam:3d3;needgrab:1;");
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_MINIONS, 50, 2, 3, "giant ant");
addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL);
@ -13516,7 +13543,6 @@ void initrace(void) {
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 8, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:2d4;");
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roar");
addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL);
@ -13548,7 +13574,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_STING, 12, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_ENHANCESMELL, 6, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 12, NA, NA, NULL);
@ -13577,7 +13602,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, SV_SHOUT, NA, "croaks^croaking");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, SV_SHOUT, NA, "croaks^croaking");
@ -13804,7 +13828,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "croaks^croaking");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "croaking^croaking");
@ -14179,7 +14202,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTRESIST, DT_FIRE, B_TRUE, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_COLD, B_TRUE, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL);
addrace(R_PORCUPINE, "giant porcupine", 10, 'r', C_GREY, MT_FLESH, RC_ANIMAL, "A large four legged creature covered with sharp spines.");
setbodytype(lastrace, BT_QUADRAPED);
@ -15115,7 +15137,6 @@ void initrace(void) {
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
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_CYAN, MT_FLESH, RC_DRAGON, "Blue wyrms are massive reptilian creatures who can (and will) consume almost any living creature.");
setbodytype(lastrace, BT_HUMANOID);

Binary file not shown.

10
defs.h
View File

@ -1113,6 +1113,7 @@ enum RACE {
R_BINGEBARK,
R_BRIARTHRASH,
R_CACTUS,
R_GLUON,
R_IVYRAPID,
R_FUNGUSDREAM,
R_FUNGUSRAGE,
@ -2736,6 +2737,10 @@ enum FLAG {
F_CANGETWET, // object will get F_WET if hit by water
// v0 = enum WETNESS. v1 = how long
F_WATERPROOF, // object doesn't get wet. note: overrides CANGETWET!
F_BRUISABLE, // object can get bruised through bashing/projectile
// damage.
F_BRUISED, // object is bruised (nutrition penalty)
F_WET, // object is wet
F_RUSTED, // object is rusty
// v0 = enum RUSTINESS.
@ -2910,7 +2915,10 @@ enum FLAG {
F_DONEDARKMSG, // tells the game not to say 'it is very dark here'
F_DONELISTEN, // supress further 'you hear xx' messages this turn.
// lifeform flags / lf flags / monster flags
F_ADHESIVE, // this lf's skin is sticky. must pass a str check
// of difficulty v0 to avoid your weapon sticking
// to it, or it taking your shield if you block
// it.
F_ARBOOST, // modify lf's armour rating by v0
// this is slightly different from f_armourrating.
// f_armourrating is used for innate armour.

34
lf.c
View File

@ -1659,7 +1659,6 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
spellblessed = fromob->blessed;
power = getobspellpower(fromob, lf);
} else {
flag_t *ctf;
spellblessed = B_UNCURSED;
power = getspellpower(lf, sid);
// check whether we _can_ cast it.
@ -1728,14 +1727,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
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];
}
casttype = getcasttype(lf, sid);
}
sp = findot(sid);
@ -4367,7 +4359,7 @@ int eat(lifeform_t *lf, object_t *o) {
}
}
// limit nutrition
if (nutrition > (HUNGERCONST/2)) nutrition = (HUNGERCONST/2);
//if (nutrition > (HUNGERCONST/2)) nutrition = (HUNGERCONST/2);
rawmeat = B_TRUE;
}
@ -7065,6 +7057,18 @@ int getavgdam(lifeform_t *lf, int forxp) {
return (int)avgdam;
}
enum CASTTYPE getcasttype(lifeform_t *lf, enum OBTYPE sid) {
flag_t *ctf;
ctf = lfhasflagval(lf, F_CASTTYPE, sid, NA, NA, NULL);
if (!ctf) {
ctf = lfhasflagval(lf, F_CASTTYPE, OT_NONE, NA, NA, NULL);
}
if (ctf) {
return ctf->val[1];
}
return CT_NORMAL;
}
float getequippedweight(lifeform_t *lf) {
object_t *o;
float total = 0;
@ -9785,8 +9789,9 @@ long getspforpoint(lifeform_t *lf) {
float mod;
float amtneeded;
amtneeded = SKILLXPPERPOINT;
amtneeded += (50 * lf->totskillpoints);
mod = MAXOF(getstatmod(lf, A_IQ), getstatmod(lf, A_WIS));
amtneeded += (30 * lf->totskillpoints);
//mod = MAXOF(getstatmod(lf, A_IQ), getstatmod(lf, A_WIS));
mod = getstatmod(lf, A_IQ) + getstatmod(lf, A_WIS);
amtneeded = pctof(100 - mod, amtneeded);
return amtneeded;
}
@ -15421,7 +15426,7 @@ void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fr
char buf2[BUFLEN];
sprintf(buf, "^w%s releases a cloud of fumes!", lfname);
sprintf(buf2, "^wSomething releases a cloud of fumes!");
spellcloud(lf->cell, 3, UNI_SHADELIGHT, C_GREY, OT_S_BLINDNESS, 8, B_TRUE, buf, buf2, B_TRUE, NULL);
spellcloud(lf->cell, 1, UNI_SHADELIGHT, C_GREY, OT_S_BLINDNESS, 8, B_TRUE, buf, buf2, B_TRUE, NULL);
}
@ -17613,7 +17618,8 @@ int safetorest(lifeform_t *lf) {
reason = E_OK;
for (l = lf->cell->map->lf ; l ; l = l->next) {
if ((l != lf) && areenemies(lf, l) && !lfhasflag(l, F_HARMLESS) && !lfhasflag(l, F_FEIGNINGDEATH)) {
if ((l != lf) && (areenemies(lf, l) || !isknownpeaceful(lf) ) &&
!lfhasflag(l, F_HARMLESS) && !lfhasflag(l, F_FEIGNINGDEATH)) {
int monsternearby = B_FALSE;
if (isplayer(lf)) {

1
lf.h
View File

@ -151,6 +151,7 @@ int getattr(lifeform_t *lf, enum ATTRIB attr);
enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, /*@null@*/char *buf);
int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset);
int getavgdam(lifeform_t *lf, int forxp);
enum CASTTYPE getcasttype(lifeform_t *lf, enum OBTYPE sid);
float getequippedweight(lifeform_t *lf);
int getevasion(lifeform_t *lf);
object_t *getbestthrowmissile(lifeform_t *lf, lifeform_t *target);

27
nexus.c
View File

@ -48,6 +48,9 @@ hiddenname_t *firsthiddenname = NULL, *lasthiddenname = NULL;
npcname_t *npcname;
int numnpcnames;
extern lifeform_t *godlf[];
extern int ngodlfs;
int nextregionthingid = 0;
buildingusage_t buildingusage[MAXBUILDINGTYPES];
@ -160,6 +163,20 @@ int main(int argc, char **argv) {
// load savegame, if available
foundsavegame = loadall();
if (foundsavegame) {
region_t *r;
map_t *m;
lifeform_t *l;
// fill in gods
r = findregionbytype(RG_HEAVEN);
m = findregionmap(r->id, 1);
ngodlfs = 0;
for (l = m->lf ; l ; l = l->next) {
if (getraceclass(l) == RC_GOD) {
godlf[ngodlfs++] = l;
}
}
}
// init graphics
initgfx();
@ -289,15 +306,6 @@ int main(int argc, char **argv) {
dmap = addmap();
createmap(dmap, 1, dregion, firstmap, D_DOWN, NULL);
// find staircase
where = findobinmap(dmap, OT_STAIRSUP);
assert(where);
// make sure no lifeforms are there
if (where->lf) {
killlf(where->lf);
}
// add player in the starting position
//where = real_getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL);
@ -308,6 +316,7 @@ int main(int argc, char **argv) {
more();
exit(1);
}
if (where->lf) killlf(where->lf);
movelf(player, where);
// new remove fakes
killfakes(&fakemap, &fakecell);

120
objects.c
View File

@ -711,6 +711,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
p += strlen("cursed ");
donesomething = B_TRUE;
// food flags
} else if (strstarts(p, "bruised ")) {
addflag(wantflags, F_BRUISED, B_TRUE, NA, NA, NULL);
p += strlen("bruised ");
donesomething = B_TRUE;
} else if (strstarts(p, "cooked ")) {
addflag(wantflags, F_PREPARED, B_TRUE, NA, NA, NULL);
p += strlen("cooked ");
@ -4307,7 +4311,7 @@ int real_getobvalue(object_t *o, int amt) {
limitf(&price, 1, NA);
price = ((int)price * amt);
dblog("price for %s is %d", o->type->name, (int)price);
//dblog("price for %s is %d", o->type->name, (int)price);
return (int) price;
}
@ -4800,6 +4804,11 @@ int getnutritionbase(object_t *o) {
}
}
if (hasflag(o->flags, F_BRUISED)) {
basenutr = pctof(75, basenutr);
limitf(&basenutr, 1, NA);
}
return basenutr;
}
@ -5878,6 +5887,11 @@ char *getobconditionname(object_t *o, char *buf) {
strcpy(buf, "");
}
if (hasflag(o->flags, F_BRUISED)) {
if (strlen(buf)) strcat(buf, " ");
strcat(buf, "bruised");
}
if (iscorpse(o)) {
if (hasflag(o->flags, F_PREPARED)) {
if (strlen(buf)) strcat(buf, " ");
@ -10829,13 +10843,22 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
for (dir = DC_N; dir <= DC_NW; dir++) {
cell_t *c;
c = getcellindir(lf->cell, dir);
if (c && isempty(c)) {
if (c && !c->type->solid) {
object_t *newob;
// get lifeforms out of the way
if (c->lf) {
knockback(c->lf, getdiraway(c, lf->cell, NULL, B_FALSE, DT_ORTH, B_FALSE),
1, lf, 0, B_TRUE);
}
if (!c->lf) {
newob = addob(c->obpile, "magical barrier");
if (first && haslos(player, c)) {
msg("A magical barrier appears!");
first = B_FALSE;
}
}
// it will disappear eventually
//addflag(newob->flags, F_OBHP, i, i, NA, NULL);
@ -12368,6 +12391,12 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce) {
}
if ((damtype == DT_BASH) || (damtype == DT_PROJECTILE)) {
if (hasflag(o->flags, F_BRUISABLE) && !hasflag(o->flags, F_BRUISED)) {
addflag(o->flags, F_BRUISED, B_TRUE, NA, NA, NULL);
}
}
// damage type creates other objects?
f = hasflagval(o->flags, F_DTCREATEOB, damtype, NA, NA, NULL);
@ -12620,7 +12649,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
char targetname[BUFLEN];
lifeform_t *target;
cell_t *srcloc;
int seen;
int seen,seensrc,seendst;
int shattered = B_FALSE;
char throwverbpast[BUFLEN];
char throwverbpres[BUFLEN];
@ -12630,6 +12659,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
object_t *newob = NULL;
cell_t *newloc;
int db = B_TRUE;
int stuck = B_FALSE;
int willcatch = B_FALSE;
int announcedmiss = B_FALSE;
int outofammo = B_FALSE;
@ -12737,10 +12767,17 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
// identify as cursed!
}
if (haslos(player, where) || haslos(player, srcloc)) { // can see the src/dst location
seen = B_TRUE;
} else {
seen = B_FALSE;
seensrc = B_FALSE;
seendst = B_FALSE;
if (haslos(player, where)) {
seendst = B_TRUE;
}
if (haslos(player, srcloc)) {
seensrc = B_TRUE;
}
if (seensrc || seendst) {
seen = B_TRUE;
}
@ -12989,6 +13026,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
}
if (thrower) {
object_t *tempo;
// gravboost?
if (lfhasflag(thrower, F_GRAVBOOSTED) && (srcloc == thrower->cell)) {
if (isplayer(thrower) || haslos(player, srcloc)) {
@ -12999,12 +13037,37 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
if (newobptr) *newobptr = o;
return B_FALSE;
}
// thrower had a ring of deceleration?
tempo = hasequippedobid(thrower->pack, OT_RING_DECELERATION);
if (tempo) {
cell_t *retcell[MAXRETCELLS];
int nretcells;
if (seensrc) {
msg("%s suddenly slows down!", obname);
makeknown(tempo->type->id);
}
// change dest cell.
calcbresnham(where->map, thrower->cell->x, thrower->cell->y,
where->x, where->y, retcell, &nretcells );
if (nretcells > 1) {
// 1 cell in front of thrower.
where = retcell[1];
}
// also slow it down
speed = 1;
}
}
// adjust destination location in case something is in the way.
haslof(srcloc, where, LOF_NEED, &newloc);
if (newloc) {
where = newloc;
}
// ... in case the target cell changed...
target = where->lf;
if (target && isdead(target)) {
target = NULL;
@ -13012,8 +13075,6 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
if (target) {
getlfname(target, targetname);
}
}
// do throw animation
if (seen) {
@ -13382,16 +13443,26 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
}
// move the object to the cell then take dam or kill it. don't stack.
if (target && lfhasflag(target, F_ADHESIVE)) {
newob = real_moveob(o, target->pack, amt, B_FALSE);
stuck = B_TRUE;
if (cansee(player, target)) {
if (thrower) {
msg("^%c%s sticks to %s!", getlfcol(thrower, CC_BAD), obname, targetname);
} else {
msg("%s sticks to %s!", obname, targetname);
}
}
killflagsofid(newob->flags, F_PLAYERMISSILE);
} else {
newob = real_moveob(o, where->obpile, amt, B_FALSE);
}
// fake its birth time so that it can be damaged
newob->birthtime = -1;
killflagsofid(newob->flags, F_PLAYERMISSILE);
if (thrower) {
addflag(newob->flags, F_THROWNBY, thrower->id, NA, NA, NULL);
}
// now we can get rid of the fake obpile, if we used it
if (op) killobpile(op);
@ -13400,6 +13471,11 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
outofammo = B_TRUE;
}
if (thrower) {
addflag(newob->flags, F_THROWNBY, thrower->id, NA, NA, NULL);
}
if (!stuck) {
if (willshatter(newob->material->id)) {
char dambuf[BUFLEN];
snprintf(dambuf, BUFLEN, "%s (%s by %s)",obname,throwverbpast, realthrowernamea);
@ -13415,13 +13491,12 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
if (missiledam) {
// don't announce damage to the thrown object
real_takedamage(newob, missiledam, DT_BASH, B_FALSE);
} else {
// ie things like bruising
real_takedamage(newob, 0, DT_BASH, B_FALSE);
}
}
if (newob && !isdeadob(newob)) {
killflagsofid(newob->flags, F_THROWNBY);
if (thrower && hasactivespell(thrower, OT_S_WHATGOESUP)) {
// on the ground?
if ((newob->pile->where == where) && haslof(newob->pile->where, thrower->cell, LOF_NEED, NULL)) {
@ -13437,6 +13512,10 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
}
}
if (newob && !isdeadob(newob)) {
killflagsofid(newob->flags, F_THROWNBY);
}
/*
if (firearm && outofammo && isplayer(thrower)) {
char buf[BUFLEN];
@ -15136,7 +15215,7 @@ enum MATSTATE getmaterialstate(enum MATERIAL mat) {
}
int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, flag_t *tkthrow) {
int acc,howfar,cellpenalty;
int acc,howfar,cellpenalty,plus=0;
enum SKILLLEVEL slev;
enum SKILL whichskill;
enum ATTRIB whichatt;
@ -15159,6 +15238,9 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob
// (firearm == null) means we are throwing.
acc = getobaccuracy(firearm, thrower, B_TRUE);
sumflags(thrower->flags, F_ACCURACYMOD, &plus, NULL, NULL);
acc += plus;
// for each cell travelled after the first, lower accuracy, based on skill.
slev = getskill(thrower, whichskill);

View File

@ -8231,7 +8231,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
killflagsofid(caster->flags, F_THROWING);
// 5 is the same as AT_VHIGH strength
addflag(targob->flags, F_MISSILEALWAYSDIES, B_TRUE, NA, NA, NULL);
addflag(caster->flags, F_TKTHROW, A_IQ, SK_SS_AIR, NA, NULL);
f = addflag(caster->flags, F_ACCURACYMOD, 50, NA, NA, NULL);
real_fireat(caster, targob, 1, targcell, 5, NULL, B_TRUE, spellid, NULL);
killflag(f);
killflagsofid(caster->flags, F_TKTHROW);
} else if (spellid == OT_S_TRAVEL) {
regionthing_t *poss[MAXCANDIDATES],*rt;
region_t *srcregion = NULL;