From 8a70cd0f9913a72d3eb3c31339d42e787ff45934 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Wed, 18 Apr 2012 21:34:41 +0000 Subject: [PATCH] - [+] 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. --- ai.c | 58 ++++++++++------ attack.c | 70 ++++++++++++++----- data.c | 47 +++++++++---- data/hiscores.db | Bin 15360 -> 15360 bytes defs.h | 10 ++- lf.c | 34 ++++++---- lf.h | 1 + nexus.c | 27 +++++--- objects.c | 170 +++++++++++++++++++++++++++++++++++------------ spell.c | 5 ++ 10 files changed, 303 insertions(+), 119 deletions(-) diff --git a/ai.c b/ai.c index 6e7273f..d31b65d 100644 --- a/ai.c +++ b/ai.c @@ -171,30 +171,35 @@ 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)) { - poss[nposs] = f->val[0]; - nposs++; + 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++; + } } } @@ -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 @@ -1913,7 +1919,13 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) { // remember NOT to target this one. addignorecell(lf, c); } else { - if (db) dblog(".oO { successfully walked towards f_targetcell. arrived at %d,%d }",lf->cell->x, lf->cell->y); + 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,7 +1947,9 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) { } killflag(f); } else { - turntoface(lf, c); + if (!turned) { + turntoface(lf, c); + } } } } else { diff --git a/attack.c b/attack.c index eecae1f..74999f7 100644 --- a/attack.c +++ b/attack.c @@ -622,21 +622,29 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { break; } } else if (attackedpeaceful) { - angergodmaybe(R_GODMERCY, 15, GA_ASSAULT); - angergodmaybe(R_GODLIFE, 15, GA_ASSAULT); - angergodmaybe(R_GODPURITY, 50, GA_ASSAULT); - switch (getalignment(attacktarget)) { - case AL_EVIL: - //angergodmaybe(R_GODDEATH, 20, GA_ASSAULT); // even more - break; - case AL_GOOD: - angergodmaybe(R_GODPURITY, 20, GA_ASSAULT); // even more - break; - default: - break; + 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); + switch (getalignment(attacktarget)) { + case AL_EVIL: + //angergodmaybe(R_GODDEATH, 20, GA_ASSAULT); // even more + break; + case AL_GOOD: + angergodmaybe(R_GODPURITY, 20, GA_ASSAULT); // even more + break; + default: + break; + } } } else if (attackedhelpless) { - angergodmaybe(R_GODMERCY, 15, GA_ATTACKHELPLESS); + 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; } diff --git a/data.c b/data.c index 290c49c..9f80c2c 100644 --- a/data.c +++ b/data.c @@ -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); diff --git a/data/hiscores.db b/data/hiscores.db index 944d73ff1dc2dbdcdd4d54223a776b595d2f8b72..c6dec185afe085c55af900ace78b5bafef9166ac 100644 GIT binary patch delta 1185 zcmbu7UrZcT6vpp4XIPeHL072RxC@=YQVRb)GnYBQ7^^f7SXyT8x70KHtOxxp33Da% zCw)xs(FIzjdCJll?W1lkx*J&to$-)AhpSDxWKx6X9?P zF=XrX0&{`K@i%M*pQA^3yJx6s!0|hr+bfQb@g+|x=!?&u*NDgV3y zFR@DY8ne!20EmDBXW$05;V`~Poz~6^v_@;iUEU=WEIQ+St+K;5d(OgL6*aKLJU|Qx z_Q3>viDfv0AL8%SKm{rkYlA1C9Q#=Z!>ZO!!Nm*r?Bw6Kx%icuXW(ctR_g_U)>xDe z?_3mUk-3W{;yih+^dWm6#Q6AhT2kbAO3Eo?S=o@2Vq#j9MBNw> zm7HWG8#7{BH#AjKGFgdVj0R7Ig=#ljVQdAO;R%?tsMO*py~6$BPZ8ebKZU;%aMh}C zv9;Ib_pp=9I@h2H4EPM&@i<@BB7UI=GF}pw(Q}jV+^NdP31RIAuoEw3?L+zStAk K`#-*&jp1)4R8AZK delta 665 zcmW-dOGs2<6vxlwo9oP-8DC>0IF3{K%ErOQ(HVtwL!o;YI+$1d`h!89xh>W1?{W$#i@tt$v`+td{#L&$W9C+$y zg=sUW7B~*zOCAC1{C#X7 zBPmxZ2tOPQ1nXNw-S#!x3v3ojoqp6uwr{h$%eJ@5lzz6HM?u2__C>zkoUvWm{@CWU zMBHyHtZeyk7pz)D#0Z|mNnE2a_0SDkpnqI%1-xxmdZtK4lGU0lM*iBuLiYZg?G@>rrwZ#OzLK;Q0jO6Frb)%g>b2IW{|$#_T=xgZUY#u_|~ zDV(!H2dGzyLvM&O@-6gHg^WVYoUd)uik;XD*o@b4l`6@guUy9?+{sVGA3Y;Y(WuOX zmE`TXYz{|XQNU|OaZndf7tL`FpXMwvRnr~I4{}BV@vylWokiUm>$INM(5Ga;yItPL Q0@Bx5Ap2vP@uolj0gS$zX8-^I diff --git a/defs.h b/defs.h index 17b85fc..6e29bef 100644 --- a/defs.h +++ b/defs.h @@ -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. diff --git a/lf.c b/lf.c index 05a04a7..145b092 100644 --- a/lf.c +++ b/lf.c @@ -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)) { diff --git a/lf.h b/lf.h index 28951d3..6fa3e0c 100644 --- a/lf.h +++ b/lf.h @@ -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); diff --git a/nexus.c b/nexus.c index a0f2890..96a39c4 100644 --- a/nexus.c +++ b/nexus.c @@ -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); diff --git a/objects.c b/objects.c index 9b2cf5c..af093a9 100644 --- a/objects.c +++ b/objects.c @@ -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,12 +10843,21 @@ 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; - newob = addob(c->obpile, "magical barrier"); - if (first && haslos(player, c)) { - msg("A magical barrier appears!"); - first = B_FALSE; + + // 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 @@ -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_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; - } else { - seen = B_FALSE; } @@ -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,21 +13037,44 @@ 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; - target = where->lf; - if (target && isdead(target)) { - target = NULL; - } - if (target) { - getlfname(target, targetname); - } } + // ... in case the target cell changed... + target = where->lf; + if (target && isdead(target)) { + target = NULL; + } + 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. - newob = real_moveob(o, where->obpile, amt, B_FALSE); + 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,27 +13471,31 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp outofammo = B_TRUE; } - if (willshatter(newob->material->id)) { - char dambuf[BUFLEN]; - snprintf(dambuf, BUFLEN, "%s (%s by %s)",obname,throwverbpast, realthrowernamea); - shatter(newob, youhit, dambuf, thrower); - if (thrower && isplayer(thrower)) { - angergodmaybe(R_GODNATURE, 10, GA_ATTACKOBJECT); - } - } else if (hasflag(newob->flags, F_MISSILEALWAYSDIES)) { - killob(newob); - newob = NULL; - } else { - // object only gets damaged if it hit someone/something - if (missiledam) { - // don't announce damage to the thrown object - real_takedamage(newob, missiledam, DT_BASH, B_FALSE); - } + if (thrower) { + addflag(newob->flags, F_THROWNBY, thrower->id, NA, NA, NULL); } - - if (newob && !isdeadob(newob)) { - killflagsofid(newob->flags, F_THROWNBY); + if (!stuck) { + if (willshatter(newob->material->id)) { + char dambuf[BUFLEN]; + snprintf(dambuf, BUFLEN, "%s (%s by %s)",obname,throwverbpast, realthrowernamea); + shatter(newob, youhit, dambuf, thrower); + if (thrower && isplayer(thrower)) { + angergodmaybe(R_GODNATURE, 10, GA_ATTACKOBJECT); + } + } else if (hasflag(newob->flags, F_MISSILEALWAYSDIES)) { + killob(newob); + newob = NULL; + } else { + // object only gets damaged if it hit someone/something + 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 (thrower && hasactivespell(thrower, OT_S_WHATGOESUP)) { // on the ground? @@ -13435,6 +13510,10 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp moveob(newob, thrower->pack, newob->amt); } } + } + + if (newob && !isdeadob(newob)) { + killflagsofid(newob->flags, F_THROWNBY); } /* @@ -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); diff --git a/spell.c b/spell.c index 56df679..79e9dcc 100644 --- a/spell.c +++ b/spell.c @@ -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;