From db635b50dbe76557c3b52c9a4976032df5ff0168 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Fri, 9 Nov 2012 11:50:52 +0000 Subject: [PATCH] - [+] most monsters which covet food should have snatch - so that you can just drop food for them. - [+] when looking for remote obs, DO include adjacent cells with lfs, if we have the snatch ability. - [+] some long thin levels (80 x 12 ?) - [+] fix code to remove useless doors. - [+] 0 pairs of dirs with empty cells = change door to wall - [+] pick an adjacent empty cell - [+] floodfill the 8 cells around the door. - [+] start with adj cell - [+] can't go more than 1 cell away from door - [+] solid cells or doors will stop movement - [+] if no unfilled cells around the door, bad. - [+] new way of fixing unconnected levels - portal! - [+] pick one spot in each section then place a portal there. - [+] dying should cure poison - [+] tweaks to attack text - [+] floor tile effecst - [+] absorbancy - ie. carpet should absorb water. - [+] converyors - [+] only walkable sometime (crushers?) - [+] in tombstone, show "eaten by Rattus", not "eaten by a rattus" - [+] god of nature should like eating animals all the time, not just when hungry (makes piety gain easier) - [+] announce when eyes are protected from a spellcloud - [+] klikirak should like setting off fire traps. - [+] floodfill() should follow portals to the same level. - [+] show >1 skillpoints in green on status bar - [+] bug: gods are apeparing behind you. - [+] bug in getrandomadjcell - [+] gods' planeshift spells failing? might be fixed now. using getrandomroomcell instead of getrandomcell. - [+] increaes damage dealt by smite evil/good - [+] lightning javelins shouldn't be stackable - [+] monsters not firing ranged weapons! - [+] they just walk back and forth - [+] bug with how i was calling haslof() for cells other than where the mosnter was (in getdiraway()) - [+] turn undead should only work if caster level*2 is >= monster level fullblock basics: - [+] penalties - [+] lowers visrange to 1 - [+] huge attack penalties - [+] huge evasion penalties - [+] vhigh chance of all ranged damage going to shield instead. - [+] buckler = 75 (small) - [+] shield = 80 - [+] large shield = 85 - [+] tower = 90 - [+] plus shield skill*2 - [+] use check_shield_block in all spell effects - [+] this checks whether player is shieldblocoking (or evades??) - [+] then applies damage appropriatly. - [+] new ability; - [+] stopped by: - [+] losing or unequipping the shield - [+] being interrupted - [+] casting a spell or using an ability - [+] exotic weapons should cost more. - [+] maybe prevent prayer until gods have been pleased enough ? - [+] while you're not worshipping anyone, piety gain is x4. - [+] once first one hits 'pleased', they will appear and offer you a place - [+] advantge to this is that you get a gift - [+] picking up new gold should please felix...... - [+] you shoudl only be able to sacrifice untouched gold. this pleases felix double as much as grabbing it. - [+] gods sohuld appear "in a cloud of ..." - [+] bjorn - blood - [+] klik - fire - [+] lumara - bright light --- ai.c | 47 +++-- attack.c | 37 +++- attack.h | 2 +- data.c | 118 ++++++++++-- data/hiscores.db | Bin 17408 -> 17408 bytes defs.h | 24 ++- flag.c | 12 ++ flag.h | 1 + god.c | 248 ++++++++++++------------ god.h | 4 +- io.c | 39 +++- lf.c | 123 +++++++++--- lf.h | 1 + map.c | 490 +++++++++++++++++++++++++++++++++++++---------- map.h | 8 +- move.c | 8 +- nexus.c | 5 +- nexus.h | 2 +- objects.c | 72 +++++-- shops.c | 2 +- spell.c | 308 ++++++++++++++++++++++------- text.c | 19 +- 22 files changed, 1180 insertions(+), 390 deletions(-) diff --git a/ai.c b/ai.c index f00b5ae..7aacf57 100644 --- a/ai.c +++ b/ai.c @@ -2432,10 +2432,9 @@ int aipickupok(lifeform_t *lf, object_t *o) { } */ - if (isedible(o)) { - if (caneat(lf, o) && !isinbattle(lf, B_NODISTANT, B_FALSE)) { - ok = B_TRUE; - } + //if (isedible(o) && caneat(lf, o) && !isinbattle(lf, B_NODISTANT, B_FALSE)) { + if (isedible(o) && caneat(lf, o)) { + ok = B_TRUE; } else if (canpickup(lf, o, 1)) { ok = B_TRUE; } @@ -3366,15 +3365,17 @@ int lookforobs(lifeform_t *lf) { c = lf->los[i]; celldist = getcelldist(lf->cell, c); - if ((c != lf->cell) && !c->lf && !lfhasflagval(lf, F_IGNORECELL, c->x, c->y, NA, NULL)) { + if ((c != lf->cell) && (!c->lf || cancast(lf, OT_A_SNATCH, NULL)) && + !lfhasflagval(lf, F_IGNORECELL, c->x, c->y, NA, NULL)) { for (o = c->obpile->first ; o ; o = nexto) { nexto = o->next; if (aiwants_real(lf, o, &covets, &noids, oid, oidcovet, &nwantflags, wantflag, wantflagcovet) && - canpickup(lf, o, 1)) { + //canpickup(lf, o, 1)) { + aipickupok(lf, o)) { gothere = B_TRUE; // if we are in battle only go for it if we covet it and - // it's closer than our target + // it's similar distance to our target if (target) { if (!covets || (celldist > targdist)) { gothere = B_FALSE; @@ -3397,8 +3398,8 @@ int lookforobs(lifeform_t *lf) { if (!target || ((f->val[1] != B_COVETS) && (celldist <= targdist)) ) { o = hasbetterweapon(lf, c->obpile); - if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o) && - canpickup(lf, o, 1)) { + if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o)) { + //&& canpickup(lf, o, 1)) { if (db) dblog(".oO { remote cell has better weapon (%s). setting f_targetcell }",o->type->name); gothere = B_TRUE; } @@ -3415,8 +3416,8 @@ int lookforobs(lifeform_t *lf) { ((f->val[1] != B_COVETS) && (celldist <= targdist)) ) { o = hasbetterarmour(lf, c->obpile); - if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o) && - canpickup(lf, o, 1)) { + if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o)) { + //canpickup(lf, o, 1)) { if (db) dblog(".oO { remote cell has better armour (%s). setting f_targetcell }",o->type->name); gothere = B_TRUE; } @@ -3426,19 +3427,31 @@ int lookforobs(lifeform_t *lf) { } if (gothere) { - // cast a spell? + long obid; + int success = B_FALSE; + // remember object id. + obid = o->id; + // cast a spell to get it? if (cancast(lf, OT_S_CALLWIND, NULL) && haslofknown(lf->cell, c, LOF_NEED, NULL)) { if (!castspell(lf, OT_S_CALLWIND, NULL, o, c, NULL, NULL)) { - // successful - return B_TRUE; + success = B_TRUE; } } - if (cancast(lf, OT_A_SNATCH, NULL) && haslofknown(lf->cell, c, LOF_NEED, NULL)) { + if (cancast(lf, OT_A_SNATCH, NULL) && haslofknown(lf->cell, c, LOF_NEED, NULL) && + (getcelldist(lf->cell, c) == 1)) { if (!useability(lf, OT_A_SNATCH, NULL, c)) { - // successful - return B_TRUE; + success = B_TRUE; } } + if (success) { + // got the object. now try to eat it if possible. + object_t *oo; + oo = hasobid(lf->pack, obid); + if (oo && isedible(oo) && caneat(lf, oo)) { + eat(lf, o); + } + return B_TRUE; + } // start walking towards target cell if (aigoto(lf, c, MR_OB, o, aigetchasetime(lf))) { return B_FALSE; diff --git a/attack.c b/attack.c index 027ee9f..61b5f14 100644 --- a/attack.c +++ b/attack.c @@ -1244,7 +1244,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } sprintf(attackname, "%s%s attack", attackername, getpossessive(attackername)); difficulty = 100 + (gettr(victim)*5) - (gettr(lf)*5); - if (check_for_block(lf, victim, dam[i], damtype[i], difficulty, attackname)) { + if (check_for_block(lf, victim, dam[i], damtype[i], difficulty, attackname, isadjacent(lf->cell,victim->cell))) { blocked = B_TRUE; break; // stop processing damage now. } @@ -1456,7 +1456,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (damtypecausesbleed(damtype[i], wep)) { bleed(victim, B_SPLATTER); } - } else if (strstr(buf, "bisect")) { + } else if (strstr(buf, "bisect") || strstr(buf, "dismember")) { if (victim->race->id != R_EARTHWYRM) { addflag(victim->flags, F_MUTILATED, B_TRUE, NA, NA, NULL); } @@ -2165,12 +2165,31 @@ enum DAMTYPE basedamagetype(enum DAMTYPE dt) { } // returns B_TRUE if victim blocked lf's attack -int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE damtype, int difficulty, char *attackname) { +// +// Note: sometimes we'll call this function with a check difficulty of IMPOSSIBLE. +// This means that it'sonly possible to block the attack if you are in +// 'fullshield' mode. +int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE damtype, int difficulty, char *attackname, int ranged) { object_t *shield[MAXPILEOBS]; int checkmod[MAXPILEOBS]; int nshields,i; + flag_t *fflag; + long shid; - if (lf && !cansee(victim, lf)) return B_FALSE; + fflag = lfhasflag(victim, F_FULLSHIELD); + if (fflag) { + shid = atol(fflag->text); + } else { + shid = -1; + } + + if (lf && !cansee(victim, lf)) { + // in fullblock mode, you can block even if you can't see + // your attacker. + if (!fflag) { + return B_FALSE; + } + } if (lfhasflag(victim, F_STUNNED) || !hasfreeaction(victim)) { return B_FALSE; } @@ -2181,8 +2200,16 @@ int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE da // get all usable shields for this damtype getallshields(victim, damtype, shield, checkmod, &nshields); for (i = 0; i < nshields; i++) { + int blocked = B_FALSE; + int fullbonus = 0; + if (fflag && ranged && (shield[i]->id == shid)) { + fullbonus = 40 + (getobsize(shield[i])*5); + } // did we block with this object? - if (skillcheck(victim, SC_SHIELDBLOCK, difficulty, checkmod[i])) { + if (skillcheck(victim, SC_SHIELDBLOCK, difficulty, checkmod[i] + fullbonus)) { + blocked = B_TRUE; + } + if (blocked) { char shname[BUFLEN]; char victimname[BUFLEN]; getlfname(victim, victimname); diff --git a/attack.h b/attack.h index 78c115b..3c0e81b 100644 --- a/attack.h +++ b/attack.h @@ -7,7 +7,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag); int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag); enum DAMTYPE basedamagetype(enum DAMTYPE dt); -int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE damtype, int difficulty, char *attackname); +int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE damtype, int difficulty, char *attackname, int ranged); //void confereffects(flagpile_t *fp, lifeform_t *victim); void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, object_t *wep, int dam, enum DAMTYPE damtype); int damtypecausesbleed(enum DAMTYPE dt, object_t *fromob); diff --git a/data.c b/data.c index 5ba4a94..379535c 100644 --- a/data.c +++ b/data.c @@ -2172,7 +2172,7 @@ void initobjects(void) { addflag(lastot->flags, F_GROWSTO, CT_WALLMETAL, VT_CELL, NA, NULL); addflag(lastot->flags, F_SHRINKSTO, OT_SHIELD, VT_OB, NA, NULL); - addot(OT_FOUNTAIN, "fountain", "A running fountain of some kind of liquid.", MT_WATER, 20, OC_MISC, SZ_MEDIUM); + addot(OT_FOUNTAIN, "fountain", "A running fountain of some kind of liquid.", MT_NOTHING, 20, OC_MISC, SZ_MEDIUM); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); @@ -2855,6 +2855,7 @@ void initobjects(void) { addflag(lastot->flags, F_NUMAPPEAR, 1, 100, NA, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some gold"); + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves // rocks addot(OT_BOULDER, "boulder", "A massive stone boulder.", MT_STONE, 80, OC_ROCK, SZ_HUGE); @@ -2934,6 +2935,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL); + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves addot(OT_AMETHYST, "amethyst", "A purple gemstone.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_MAGENTA, '*', NA, NULL); @@ -2944,6 +2946,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 15, NA, NA, NULL); + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves addot(OT_DIAMOND, "diamond", "A sparkling diamond.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_WHITE, '*', NA, NULL); @@ -2954,6 +2957,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 1000, NA, NA, NULL); + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves addot(OT_EMERALD, "emerald", "A deep green gem.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREEN, '*', NA, NULL); @@ -2964,6 +2968,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 650, NA, NA, NULL); + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves addot(OT_OPAL, "opal", "An amorphous form of silica related to quartz.", MT_STONE, 0.1, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREY, '*', NA, NULL); @@ -2974,6 +2979,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 70, NA, NA, NULL); + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves addot(OT_PEARL, "pearl", "A small pinkish-white gem.", MT_STONE, 0.1, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_WHITE, '*', NA, NULL); @@ -2984,6 +2990,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 30, NA, NA, NULL); + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves addot(OT_RUBY, "ruby", "A large red gem.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_RED, '*', NA, NULL); @@ -2994,6 +3001,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 110, NA, NA, NULL); + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves addot(OT_SAPPHIRE, "sapphire", "A brilliant blue gem.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_CYAN, '*', NA, NULL); @@ -3004,6 +3012,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 850, NA, NA, NULL); + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves addot(OT_TOPAZ, "topaz stone", "A dull blue gem.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_BLUE, '*', NA, NULL); @@ -3014,7 +3023,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 60, NA, NA, NULL); - + addflag(lastot->flags, F_UNTOUCHED, B_TRUE, NA, NA, NULL); // for god of thieves addot(OT_ASH, "pile of ash", "A pile of ash.", MT_STONE, 0.1, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GLYPH, NA, ',', NA, NULL); @@ -3882,7 +3891,7 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODDEATH, 2, NA, NULL); - addot(OT_S_SMITEGOOD, "smite good", "Instantly deals 1-^bpower*2^n damage to good creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_SMITEGOOD, "smite good", "Instantly deals 1d4 + ^bpower^nd4 damage to good creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -4849,7 +4858,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); - addot(OT_S_SMITEEVIL, "smite evil", "Instantly deals 1-^bpower*2^n damage to evil creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_SMITEEVIL, "smite evil", "Instantly deals 1d4 _ ^bpower^nd4 damage to evil creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 10, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -5541,6 +5550,10 @@ void initobjects(void) { addflag(lastot->flags, F_STAMCOST, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); + addot(OT_A_FULLSHIELD, "fullshield", "Raise your shield to (almost) completely cover your body.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "While in fullshield mode your vision, evasion and accuracy are greatly lowered."); + addflag(lastot->flags, F_STAMCOST, 1, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_GRAB, "grab", "You can grab hold of nearby enemies to prevent their escape.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); @@ -8485,7 +8498,6 @@ void initobjects(void) { addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); addot(OT_JAVELINLT, "lightning javelin", "A long, sharp missile weapon which transforms into a bolt of lightning when thrown.", MT_METAL, 4, OC_MISSILE, SZ_MEDIUM); - addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_MISSILEDAM, NA, NA, NA, "3"); addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); @@ -10877,7 +10889,13 @@ void initrace(void) { addflag(lastrace->flags, F_GODNOBATTLE, NA, NA, NA, "removing polymorphs"); addflag(lastrace->flags, F_GODNOBATTLE, NA, NA, NA, "purifying food"); addflag(lastrace->flags, F_GODNOBATTLE, NA, NA, NA, "blessing your items"); - + // text + addflag(lastrace->flags, F_GODBONUSTEXT, NA, NA, NA, "You have impressed me, mortal!"); + addflag(lastrace->flags, F_GODNOBONUSTEXT, NA, NA, NA, "Your service is lacking, mortal."); + addflag(lastrace->flags, F_GODGIFTTEXT, NA, NA, NA, "I bestow a gift upon you, mortal!"); + addflag(lastrace->flags, F_GODASK1, NA, NA, NA, "Mortal! Your actions have impressed me."); + addflag(lastrace->flags, F_GODASK2, NA, NA, NA, "I offer you a place in my service."); + addflag(lastrace->flags, F_GODTEXTAPPEAR, NA, NA, NA, "appears in a flash of power!"); addrace(R_GODBATTLE, "Bjorn", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Bjorn the Battlelord is the god of honourable combat. He appears as a heavily built, bearded warrior clad in well-used armour."); setbodytype(lastrace, BT_HUMANOID); @@ -10952,7 +10970,13 @@ void initrace(void) { addflag(lastrace->flags, F_GODNOBATTLE, NA, NA, NA, "repairing items"); addflag(lastrace->flags, F_GODNOBATTLE, NA, NA, NA, "detecting enemies"); addflag(lastrace->flags, F_GODNOBATTLE, NA, NA, NA, "blessing your weapon"); - + // text + addflag(lastrace->flags, F_GODBONUSTEXT, NA, NA, NA, "Onwards to victory!"); + addflag(lastrace->flags, F_GODNOBONUSTEXT, NA, NA, NA, "Your slothfulness has earned you a demotion, soldier."); + addflag(lastrace->flags, F_GODGIFTTEXT, NA, NA, NA, "Gather up the spoils of battle!"); + addflag(lastrace->flags, F_GODASK1, NA, NA, NA, "Your actions have proved worthy of notice."); + addflag(lastrace->flags, F_GODASK2, NA, NA, NA, "Join me in my eternal battle!"); + addflag(lastrace->flags, F_GODTEXTAPPEAR, NA, NA, NA, "appears in a shower of blood!"); addrace(R_GODNATURE, "Ekrub", 200, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Ekrub is goddess of nature and creation. She appears as a female figure dressed in farming clothes. Ekrub has a burning hatred of all dragonkind, who she views as abhorrent due to their destructive nature."); setbodytype(lastrace, BT_HUMANOID); @@ -10997,7 +11021,7 @@ void initrace(void) { } } addflag(lastrace->flags, F_GODPOISON, B_FALSE, 25, NA, NULL); - addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "eating animals when hungry"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "eating animals"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "killing dragons"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "cooking"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "creating objects"); @@ -11026,8 +11050,13 @@ void initrace(void) { addflag(lastrace->flags, F_GODBONUS, PL_PLEASED, GB_FLAG, F_PLANTFRIEND, "-1,NA,NA"); addflag(lastrace->flags, F_GODBONUS, PL_DELIGHTED, GB_FLAG, F_DISEASEIMMUNE, "1,NA,NA"); addflag(lastrace->flags, F_GODBONUS, PL_ECSTATIC, GB_FLAG, F_AUTOTANGLE, "20,5,NA"); - - + // text + addflag(lastrace->flags, F_GODBONUSTEXT, NA, NA, NA, "You are progressing in nature's path..."); + addflag(lastrace->flags, F_GODNOBONUSTEXT, NA, NA, NA, "Nature will not tolerate the lazy."); + addflag(lastrace->flags, F_GODGIFTTEXT, NA, NA, NA, "Harvest nature's bounty!"); + addflag(lastrace->flags, F_GODASK1, NA, NA, NA, "You have demonstrated an affinity for creation."); + addflag(lastrace->flags, F_GODASK2, NA, NA, NA, "Nature would welcome your continued worship."); + addflag(lastrace->flags, F_GODTEXTAPPEAR, NA, NA, NA, "coalesces out of twisting air currents!"); addrace(R_GODTHIEVES, "Felix", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Felix is the god of Thieves, Revenge and Greed. He generally appears as an overweight glutton carrying his contraband loot around in huge sacks. Despite this, he is amazingly agile and is said to be able to steal one's soul right out of their body."); setbodytype(lastrace, BT_HUMANOID); @@ -11073,6 +11102,7 @@ void initrace(void) { addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "stealing items"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "lockpicking"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "bribery"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "gaining wealth"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "purchasing items"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "giving away or discarding money"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "opening locked objects through force"); @@ -11093,6 +11123,13 @@ void initrace(void) { addflag(lastrace->flags, F_GODBONUS, PL_DELIGHTED, GB_FLAG, F_SKILLCHECKMOD, buf); sprintf(buf, "%d,40,NA", SC_SEARCH); addflag(lastrace->flags, F_GODBONUS, PL_ECSTATIC, GB_FLAG, F_SKILLCHECKMOD, buf); + // text + addflag(lastrace->flags, F_GODBONUSTEXT, NA, NA, NA, "Very impressive..."); + addflag(lastrace->flags, F_GODNOBONUSTEXT, NA, NA, NA, "I expect more results, mortal."); + addflag(lastrace->flags, F_GODGIFTTEXT, NA, NA, NA, "Loyalty has its rewards..."); + addflag(lastrace->flags, F_GODASK1, NA, NA, NA, "Some would denounce your greed... but others would welcome it."); + addflag(lastrace->flags, F_GODASK2, NA, NA, NA, "We could work together, you and I. What say you?"); + addflag(lastrace->flags, F_GODTEXTAPPEAR, NA, NA, NA, "steps out of the shadows."); addrace(R_GODLIFE, "Glorana", 2, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Glorana is the goddess of life. She appears as a pulsating orb of holy energy."); addbodypart(lastrace, BP_BODY, "life energy"); @@ -11152,6 +11189,13 @@ void initrace(void) { addflag(lastrace->flags, F_GODBONUS, PL_PLEASED, GB_FLAG, F_STAMBOOST, "3"); addflag(lastrace->flags, F_GODBONUS, PL_DELIGHTED, GB_FLAG, F_HOLYTOUCH, "1"); addflag(lastrace->flags, F_GODBONUS, PL_ECSTATIC, GB_FLAG, F_REGENERATES, "1,NA,NA"); + // text + addflag(lastrace->flags, F_GODBONUSTEXT, NA, NA, NA, "A good life has its rewards!"); + addflag(lastrace->flags, F_GODNOBONUSTEXT, NA, NA, NA, "You must be more proactive, my child."); + addflag(lastrace->flags, F_GODGIFTTEXT, NA, NA, NA, "Use this gift to spread the joy of life!"); + addflag(lastrace->flags, F_GODASK1, NA, NA, NA, "Well met, my child! I am Glorana, protector of all that is living."); + addflag(lastrace->flags, F_GODASK2, NA, NA, NA, "I would gladly welcome you to into my service, should you accept."); + addflag(lastrace->flags, F_GODTEXTAPPEAR, NA, NA, NA, "appears in a shaft of holy light."); addrace(R_GODDEATH, "Hecta", 100, '@', C_BOLDMAGENTA, MT_BONE, RC_GOD, "The skeletal god of Death is garbed in a cloak made of pure shadow. and weilds an enormous scythe."); setbodytype(lastrace, BT_HUMANOID); @@ -11211,6 +11255,13 @@ void initrace(void) { addflag(lastrace->flags, F_GODBATTLE, NA, NA, NA, "sending servants to aid you"); addflag(lastrace->flags, F_GODBATTLE, NA, NA, NA, "slaying a nearby enemy"); addflag(lastrace->flags, F_GODBATTLE, NA, NA, NA, "animating the dead"); + // text + addflag(lastrace->flags, F_GODBONUSTEXT, NA, NA, NA, "Your kills are impressive..."); + addflag(lastrace->flags, F_GODNOBONUSTEXT, NA, NA, NA, "Lazy servants can easily be removed..."); + addflag(lastrace->flags, F_GODGIFTTEXT, NA, NA, NA, "Your service has impressed me..."); + addflag(lastrace->flags, F_GODASK1, NA, NA, NA, "I bring you an offer, murderous fleshling."); + addflag(lastrace->flags, F_GODASK2, NA, NA, NA, "Great power in life, in return for eternal service in death."); + addflag(lastrace->flags, F_GODTEXTAPPEAR, NA, NA, NA, "rises up from the underworld!"); addrace(R_GODFIRE, "Klikirak", 2, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Klikirak is the burning god of Fire and Destruction. He is visible only as a raging inferno of fire, destroying anything in his path."); addbodypart(lastrace, BP_BODY, "flames"); @@ -11257,7 +11308,14 @@ void initrace(void) { // granted bonuses addflag(lastrace->flags, F_GODBONUS, PL_PLEASED, GB_DTRESIST, DT_FIRE, NULL); addflag(lastrace->flags, F_GODBONUS, PL_DELIGHTED, GB_DTIMMUNE, DT_FIRE, NULL); - // TODO: e = burning body + // e = burning body. hardcoded. + // text + addflag(lastrace->flags, F_GODBONUSTEXT, NA, NA, NA, "DESTROY IN MY NAME!"); + addflag(lastrace->flags, F_GODNOBONUSTEXT, NA, NA, NA, "PAY ATTENTION!"); + addflag(lastrace->flags, F_GODGIFTTEXT, NA, NA, NA, "TAKE AND DESTROY!"); + addflag(lastrace->flags, F_GODASK1, NA, NA, NA, "YOU BURN/DESTROY... I BURN/DESTROY..."); + addflag(lastrace->flags, F_GODASK2, NA, NA, NA, "WE BURN/DESTROY TOGETHER! YES?"); + addflag(lastrace->flags, F_GODTEXTAPPEAR, NA, NA, NA, "appears in a burst of white-hot fire!"); addrace(R_GODMAGIC, "Lumara", 55, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Lumara is the goddess of magic. She appears as a slender elderly woman, her expression wise with age."); setbodytype(lastrace, BT_HUMANOID); @@ -11317,6 +11375,13 @@ void initrace(void) { addflag(lastrace->flags, F_GODBONUS, PL_DELIGHTED, GB_MAGICBOOST, 1, NULL); addflag(lastrace->flags, F_GODBONUS, PL_ECSTATIC, GB_MAGICBOOST, 1, NULL); addflag(lastrace->flags, F_GODBONUS, PL_ECSTATIC, GB_FLAG, F_MPREGEN, "1,0,0"); + // text + addflag(lastrace->flags, F_GODBONUSTEXT, NA, NA, NA, "One is on the right path!"); + addflag(lastrace->flags, F_GODNOBONUSTEXT, NA, NA, NA, "One must always strive towards the path!"); + addflag(lastrace->flags, F_GODGIFTTEXT, NA, NA, NA, "One has earned a reward!"); + addflag(lastrace->flags, F_GODASK1, NA, NA, NA, "One walks the path of magic... but One has far to go."); + addflag(lastrace->flags, F_GODASK2, NA, NA, NA, "Become my student, and experience the full spectrum of arcane knowledge."); + addflag(lastrace->flags, F_GODTEXTAPPEAR, NA, NA, NA, "appears in a swirl of multicoloured lights!"); addrace(R_GODMERCY, "Yumi", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Yumi is the goddess of Mercy and Forgiveness. She has a calm, serene face and wears simple clothing."); setbodytype(lastrace, BT_HUMANOID); @@ -11373,8 +11438,14 @@ void initrace(void) { addflag(lastrace->flags, F_GODBONUS, PL_PLEASED, GB_FLAG, F_ENHANCESEARCH, "10,NA,NA"); addflag(lastrace->flags, F_GODBONUS, PL_DELIGHTED, GB_FLAG, F_DETECTAURAS, "1,NA,NA"); addflag(lastrace->flags, F_GODBONUS, PL_DELIGHTED, GB_FLAG, F_DETECTLIFE, "5,0,NA"); - // TODO: e = save life ??? - + // e = save life. hardcoded. + // text + addflag(lastrace->flags, F_GODBONUSTEXT, NA, NA, NA, "Your devoutness is impressive."); + addflag(lastrace->flags, F_GODNOBONUSTEXT, NA, NA, NA, "Your lack of proactiveness is disappointing..."); + addflag(lastrace->flags, F_GODGIFTTEXT, NA, NA, NA, "As you have shown mercy, so shall you receive it!"); + addflag(lastrace->flags, F_GODASK1, NA, NA, NA, "Such mercy as you have shown is rarely seen in your kind."); + addflag(lastrace->flags, F_GODASK2, NA, NA, NA, "Would you consider a position as my disciple?"); + addflag(lastrace->flags, F_GODTEXTAPPEAR, NA, NA, NA, "fades slowly into view."); // monsters addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC, "A floating orb of flesh with a large mouth, single central eye, and numerous smaller eyestalks."); @@ -11697,7 +11768,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 4, NA, NULL); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "knife"); addflag(lastrace->flags, F_CANCAST, OT_S_PLANTWALK, NA, NA, NULL); - addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, "pw:1;"); + addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, "pw:1;range:4;"); addflag(lastrace->flags, F_CASTCHANCE, 70, NA, NA, NULL); addflag(lastrace->flags, F_CASTTYPE, OT_S_CHARM, CT_GAZE, NA, NULL); //addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, 10, 10, NULL); @@ -14117,6 +14188,7 @@ 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_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLL, "comes to life!"); addrace(R_TROLLKIN, "trollkin", 100, 't', C_GREY, MT_FLESH, RC_HUMANOID, "Trollkins are the horrific offspring of a troll and a human. While they lack the regenerative abilities of a standard troll, their human genes grant them a greater level of intelligence."); @@ -14198,6 +14270,7 @@ void initrace(void) { addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_COLD, NA, "50"); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addrace(R_TROLLSWAMP, "swamp troll", 100, 't', C_BOLDGREEN, MT_FLESH, RC_HUMANOID, "Twisted trolls who roam the swamplands, their claws infected with a lethal poison."); setbodytype(lastrace, BT_HUMANOID); @@ -14238,6 +14311,7 @@ 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_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLLSWAMP, "comes to life!"); addrace(R_UNICORN, "unicorn", 500, 'u', C_WHITE, MT_FLESH, RC_ANIMAL, "Powerful steeds with gleaming coats of pure white, and a single ivory horn protruding from their forehead."); @@ -14492,6 +14566,7 @@ void initrace(void) { addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_WHIPATTACK, 6, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "pw:1;"); addflag(lastrace->flags, F_CANWILL, OT_S_SUCK, NA, NA, "pw:1;range:2;"); @@ -14693,7 +14768,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, 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_AGI, AT_AVERAGE, 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); @@ -14921,6 +14996,7 @@ 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_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_FATALFOOD, OT_CHOCOLATE, NA, NA, NULL); addflag(lastrace->flags, F_SKILLCHECKMOD, SC_SLIP, -15, NA, NULL); // paws can't grip @@ -14961,6 +15037,7 @@ void initrace(void) { addflag(lastrace->flags, F_STABILITY, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_FATALFOOD, OT_CHOCOLATE, NA, NA, NULL); addflag(lastrace->flags, F_FELINE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HATESRACEWITHFLAG, F_CANINE, NA, NA, NULL); @@ -15004,6 +15081,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_SWIMMING, PR_SKILLED, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_SKILLED, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_FATALFOOD, OT_CHOCOLATE, NA, NA, NULL); addflag(lastrace->flags, F_FELINE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HATESRACEWITHFLAG, F_CANINE, NA, NA, NULL); @@ -15044,6 +15122,7 @@ void initrace(void) { addflag(lastrace->flags, F_STABILITY, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_FATALFOOD, OT_CHOCOLATE, NA, NA, NULL); addflag(lastrace->flags, F_FELINE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HATESRACEWITHFLAG, F_CANINE, NA, NA, NULL); @@ -15076,6 +15155,7 @@ 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_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_FATALFOOD, OT_CHOCOLATE, NA, NA, NULL); addflag(lastrace->flags, F_EATCONFER, F_CANSEETHROUGHMAT, MT_GAS, NA, "80"); addflag(lastrace->flags, F_FELINE, B_TRUE, NA, NA, NULL); @@ -15106,6 +15186,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roar"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); @@ -15978,6 +16059,7 @@ void initrace(void) { addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); @@ -16011,6 +16093,7 @@ void initrace(void) { addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 4, NA, NA, NULL); @@ -16045,6 +16128,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); @@ -16590,6 +16674,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); addflag(lastrace->flags, F_LEVRACE, 5, R_WOLF, NA, NULL); @@ -16625,6 +16710,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); @@ -16694,6 +16780,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SNATCH, NA, NA, "range:1;"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); @@ -16734,7 +16821,6 @@ void initrace(void) { addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); diff --git a/data/hiscores.db b/data/hiscores.db index 8d935585ffdd908bae10aab881a015de9c185562..d57dc74e09b2b5e00d04337a89760f0b86c2048f 100644 GIT binary patch delta 1189 zcmeHGzi-n(7(M&5^V3aJl?18b$AJ(Kg(gZ0DnqIch^i>1NV7bI@>ejKFi_<7{ zARUm3SSTkUcK!jXN(^0CSXk&#A$6&cKnMvK+5rZ#;Ip%&{RbHE@O<*!_rCX?-)pZ6 z?RDYVP(&7y_ejo5*}S|5Sawzdbol21=!iSwV{us66`l%X=m&a<3JgoBXhHEIaWG|} z18S9~R&s17d6Ip}#n_+N!1bB14+(?GM-RL`JgXT7p4QDpa?331rbdaaskqd_1gnJF z*qX=l2B~W7AeI;{hB$L_6+Jmteb*qm>DAfPsu-5qvb9TfTs9gdmdPZ}PX&47j8*NH zPByB<#PkV@o4ve0PX#H|o6q_?+MGY-HEqqDzv+H(Di& zR(e=m4JNi|88M}99;~%A{FKdKy75$SkmzP?~ zdLsDs1}i!-ZCoNYo5>HIO5c>+BO2=J^oDhNuuriByPuB=X%_c?O*(&4RzeO&U>iXP ze#0UBgm3T}_F)fp;RC#fckmXrw=M);z^DXBh;ZoRpl}Ft2yqB<2ypOo@NtkiNbE2i zm%~n%=$4}Vg0s#_K?MYFU=iZSZM0GQ?;x##e5=^p6+w~+gxSm#!vUFv_(`W NMGM3(FK9Lo!C$9BTB!g4 delta 2008 zcmbVNTW=dh6yDwOB^T$?IB^>%ZYLqG<0Rh1ae_%oFR2odLZh}RYG_NLWA9|Wc)gqM zt{qY?u3ZWBfd{0OS{~sC@K7oN4}f^6ct91Zcz{YEAtWA1D^-d_L81sTGrLLMMivsg zvUhgQcfRwTGiPQmUEwcX;ol3ldj8~`%R?Tm*9Y$a*g{4CggEdCcnyTW_uwz^4Y&!u z1fPN5!F}+X4L!p{r6gR?wfqZ;s$vOd)*ym;J)^6VIN0UmgkU7iy=&;1qor~Cc6WDK zjCT4sJ{UvWhP=L)()y$V=1!)#Eh&9^Gq^6u`b!!)IVz7NZj;L)V$?DlWvJ54Q#b~3$ zc*xPQ4NBye=~_k`99+0Qj>7u=43+?OU^K8gQ-zB>?P2)U_7;nosmk|4h8QH zG_ls);J`!h2iO2%AP9GbUxn|4uZ63EA*jN6;mnPJhN~d$1)RXYdXw|A!7Jb)=bdB2 z_#KWt53~Pe=S62PrWe>7%^@${0Nxvczyna`SGh*+7RTM+Tc9EC>@wobb6Id!>4va?fU(iT{Q zSv_MQ5iD^(6PLuCcb>US*zKd;eNKO8v1TbNSi%&QCaB4@$7$e6yV4m6XD~8gwwMux zer}qY_j~U#5@wE+P+>(eFwBq+BLovP%#_zTd6G0tmlKBC6O~1(d^ih0V*2uWicB0i(Xz-jx75orGuY6|Iwrf9NhAw!&~#?M$ z5?nwsu5nsLMy{ylp{_v{m#_-Q$DzIqtsI6DDGeqyJ6m1z69LJJKk$RAU>2(-a;Ton z>P17wM+z%w>+6x}G!(MbktR&U~jxB87rZHoy`x3`I9)71Pv-D)%FXvWf&vwJ1Nz zESY>Vv!&{rG_&D~xAzodop2S+8bw9g(u1JfrRk~)bFAb{nU&39%RaF`X#d^auz;&? rQKHGp&cKI^XmfWSMwX@G!s9h3pH~YGE|Y$D#X21fkwHj}IIY#c)Z9Fc diff --git a/defs.h b/defs.h index 4d7e5fe..1f41dde 100644 --- a/defs.h +++ b/defs.h @@ -86,6 +86,12 @@ #define B_TRUE (-1) #define B_MAYBE (-2) +#define B_NORANGED (0) +#define B_RANGED (-1) + +#define B_NOABSORB (0) +#define B_ABSORB (-1) + #define B_ALLOWID (-1) #define B_NOID (0) @@ -513,6 +519,8 @@ enum SHOPACTION { #define FROMLYCANTHROPY (-9861) #define FROMGAMESTART (-9860) +#define IMPOSSIBLE (9999) + // flag lifetimes - external sources (ie. don't kill them) #define FROMEXTERNAL_HIGH (-7000) #define FROMRACE (-7872) @@ -1939,6 +1947,7 @@ enum OBTYPE { OT_A_FEIGNDEATH, OT_A_FLIP, OT_A_FLURRY, + OT_A_FULLSHIELD, OT_A_GRAB, OT_A_CHARGE, OT_A_COMBOSTRIKE, @@ -2582,6 +2591,7 @@ enum FLAG { // potion of sleep, etc. F_BATTLESPOILS, // this obejct was dropped by a monster which the // player killed, and has not yet been touched. + F_UNTOUCHED, // this obejct has not yet been picked up by anyone F_BEINGUSED, // this object is currently being used F_BRANDCHANCE, // this object has v0% extra chance of being branded F_DEAD, // object will be removed. v0 = lfid who killed it @@ -3230,6 +3240,7 @@ enum FLAG { // if text is set, and it was the player waking up, // then print this text. F_TURNED, // lf turned this turn. + F_GODOFFERDONE, // player has been offered a position with a god F_PRAYEDTO, // player has prayed to this god before. F_GODBLOCKED, // player may NOT pray to this god F_GIFTTIMER, // v0 = ticks down to zero whenever you please this @@ -3572,6 +3583,12 @@ enum FLAG { F_GODBONUS, // this god gives enum GODBONUS v1 at pietylev v0 // v2 = arg to GB.. // text = arg2 + F_GODBONUSTEXT, // text = what the god says when you get a bonus + F_GODNOBONUSTEXT, // text = what the god says when you lose a bonus + F_GODGIFTTEXT, // text = what the god says when you get a gift + F_GODASK1, // text = how the god asks you to join them + F_GODASK2, // text = how the god asks you to join them (2nd line) + F_GODTEXTAPPEAR, // text = godname ->xxxxx<- (when they teleport in) F_GODOF, // text = what this lf is the god of. use capitals. F_GODLIKES, // text = something this god likes (ie. incs piety) F_GODDISLIKES, // text = something this god likes (ie. decs piety) @@ -3792,6 +3809,8 @@ enum FLAG { F_FREEZINGTOUCH,// next thing touched turns to ice! // v1 = power // v2 is save difficulty + F_FULLSHIELD, // lf is fully hiding behind a shield (obid v0). + // text = obid of shield being used. F_GRABBEDBY,// you've been grabbed by lf id v0 F_GRABBING, // you are grabbing lf id v0 F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks. @@ -4581,8 +4600,10 @@ enum MAPSHAPE { MS_CROSS, MS_CIRCLE, MS_TURRET, + MS_HORZ, + MS_VERT, }; -#define MAXMAPSHAPES (4) +#define MAXMAPSHAPES (6) enum CORRIDORTYPE { CDT_NORMAL, // make corridors, remove deadends, add rooms, autolink @@ -4637,6 +4658,7 @@ typedef struct celltype_s { int floorheight; // 0 is default. <0 is low. int hp; // hit points left. <0 = invulnerable int volumemod; // modifer to footstep volume + int absorbent; // will this cell absorb liquids? struct material_s *material; struct flagpile_s *flags; diff --git a/flag.c b/flag.c index 892a9ea..0cf0adb 100644 --- a/flag.c +++ b/flag.c @@ -620,6 +620,7 @@ int flagcausesloscalc(enum FLAG fid) { case F_ASLEEP: case F_BLIND: case F_BLOCKSVIEW: + case F_FULLSHIELD: case F_NIGHTVISRANGEMOD: case F_PRONE: case F_PRODUCESLIGHT: @@ -700,6 +701,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) { case F_EATING: case F_FASTMOVE: case F_FLYING: + case F_FULLSHIELD: case F_GRAVBOOSTED: case F_GUNTARGET: case F_HASNEWLEVEL: @@ -1468,6 +1470,7 @@ int flagretainedduringpoly(enum FLAG fid) { case F_HOSTILE: case F_LYCANTHROPE: case F_ALIGNMENT: + case F_GENDER: return B_TRUE; default: break; } @@ -1529,6 +1532,15 @@ int getflags(flagpile_t *fp, flag_t **retflag, int *nretflags, ... ) { return *nretflags; } +char *getflagtext(flagpile_t *fp, enum FLAG fid) { + flag_t *f; + f = hasflag(fp, fid); + if (f) { + return f->text; + } + return "?unknownflagtext?"; +} + void getmaxflags(flagpile_t *fp, int id, int *max0, int *max1, int *max2) { flag_t *f; if (max0) *max0 = 0; diff --git a/flag.h b/flag.h index 55db498..bc21097 100644 --- a/flag.h +++ b/flag.h @@ -28,6 +28,7 @@ int flagstacks(enum FLAG fid); int flagtomaxhp(flag_t *f); cell_t *getflagpilelocation(flagpile_t *fp); int getflags(flagpile_t *fp, flag_t **retflag, int *nretflags, ... ); +char *getflagtext(flagpile_t *fp, enum FLAG fid); void getmaxflags(flagpile_t *fp, int id, int *max0, int *max1, int *max2); flag_t *getrandomflag(flagpile_t *fp, enum FLAG fid); flag_t *hasflag(flagpile_t *fp, int id); diff --git a/god.c b/god.c index 0c54989..e2742d7 100644 --- a/god.c +++ b/god.c @@ -516,6 +516,37 @@ int angergodmaybe(enum RACE rid, int amt, enum GODANGERREASON why) { return B_FALSE; } +void askforworship(enum RACE rid) { + lifeform_t *god; + char yn; + + + // make sure the player knows about it! + killtransitoryflags(player->flags, F_BLIND); + killtransitoryflags(player->flags, F_DEAF); + + god = godappears(rid, NULL); + if (!god) return; + + addflag(player->flags, F_GODOFFERDONE, B_TRUE, NA, NA, NULL); + + say(god, getflagtext(god->flags, F_GODASK1), SV_TALK); more(); + msg("\"%s\"", getflagtext(god->flags, F_GODASK2)); more(); + + yn = askchar("Will you accept", "yn", "n", B_TRUE, B_FALSE); + if (yn == 'y') { + // should never be true, but check just in case... + if (!godprayedto(rid)) { + addflag(god->flags, F_PRAYEDTO, B_TRUE, NA, NA, NULL); + } + // always get a gift, but announce it first. + say(god, getflagtext(god->flags, F_GODGIFTTEXT), SV_TALK); more(); + godgiftmaybe(rid, B_TRUE, B_FALSE); + // increment piety so that it doesn't remain around the border. + modpiety(rid, PIETYPRAYLOSS); + } +} + void checkgodbonus(enum RACE rid, enum PIETYLEV newlev, enum PIETYLEV oldlev) { flag_t *retflag[MAXCANDIDATES]; int nretflags,i; @@ -616,7 +647,7 @@ void dooffer(void) { } else if ((f->id == F_SACRIFICEOBCLASS) && (f->val[0] == o->type->obclass->id)) { ok = B_TRUE; thispiety = f->val[2]; - // will be override late though, if val[0] is OC_MONEY + // will be overridden late though, if val[0] is OC_MONEY } else if ((f->id == F_SACRIFICEOBWITHFLAG) && hasflag(o->flags, f->val[0])) { ok = B_TRUE; thispiety = f->val[2]; @@ -627,20 +658,29 @@ void dooffer(void) { ok = B_TRUE; thispiety = f->val[2]; } + + // god of thieves only accepts untouched stuff + if (ok && (god->race->id == R_GODTHIEVES)) { + if (!hasflag(o->flags, F_UNTOUCHED)) { + ok = B_FALSE; + thispiety = 0; + } + } + if (ok) { char *p; char obname[BUFLEN]; cell_t *newcell = NULL; // gold/gems are treated differently - // if you don't donate at least 100gold worth, you - // might not get any piety. - if ((o->type->id == OT_GOLD) || hasflag(o->flags, F_GEM)) { - if (pctchance(getobvalue(o))) { - thispiety = (getobvalue(o) / 100); - } else { - thispiety = 0; - } + if (o->type->id == OT_GOLD) { + thispiety = (getobvalue(o) / 2); + } else if (hasflag(o->flags, F_GEM)) { + thispiety = (getobvalue(o) / 50); + //if (pctchance(getobvalue(o))) { + //} else { + // thispiety = 0; + // } } // special effect sacrificing flora to ekrub makes it turn into a @@ -873,42 +913,16 @@ enum OBTYPE getrelatedgodstone(enum RACE rid) { void givegodbonus(enum RACE rid, flag_t *bf) { flag_t *f; + lifeform_t *god; int targ[3], arg = NA; enum PIETYLEV bonuslev; enum GODBONUS bonusid; + + god = findgod(rid); + if (!god) return; // god announcement. - switch (rid) { - case R_GODPURITY: - godsay(rid, B_TRUE, "You have impressed me, mortal!"); - break; - case R_GODTHIEVES: - godsay(rid, B_TRUE, "Very impressive..."); - break; - case R_GODDEATH: - godsay(rid, B_TRUE, "Your kills are impressive..."); - break; - case R_GODFIRE: - godsay(rid, B_TRUE, "DESTROY!"); - break; - case R_GODLIFE: - godsay(rid, B_TRUE, "A good life has its rewards!"); - break; - case R_GODMERCY: - godsay(rid, B_TRUE, "Your devoutness is impressive."); - break; - case R_GODNATURE: - godsay(rid, B_TRUE, "You are progressing in nature's path..."); - break; - case R_GODBATTLE: - godsay(rid, B_TRUE, "Onwards to victory!"); - break; - case R_GODMAGIC: - godsay(rid, B_TRUE, "One is on the right path!"); - break; - default: - break; - } + godsay(rid, B_TRUE, getflagtext(god->flags, F_GODBONUSTEXT)); more(); // increment piety so that it doesn't keep bouncing around the border. @@ -964,43 +978,29 @@ void givegodbonus(enum RACE rid, flag_t *bf) { break; } } + + +int prayedtoany(void) { + int i; + for (i = 0; i < ngodlfs; i++) { + if (godlf[i] && godprayedto(godlf[i]->race->id)) { + return B_TRUE; + } + } + return B_FALSE; +} + void removegodbonus(enum RACE rid, flag_t *bf) { int targ[3], arg = NA; enum PIETYLEV bonuslev; enum GODBONUS bonusid; + lifeform_t *god; + + god = findgod(rid); + if (!god) return; // god announcement. - switch (rid) { - case R_GODPURITY: - godsay(rid, B_TRUE, "Your service is lacking, mortal."); - break; - case R_GODTHIEVES: - godsay(rid, B_TRUE, "I expect more results, mortal."); - break; - case R_GODDEATH: - godsay(rid, B_TRUE, "Lazy servants can easily be removed..."); - break; - case R_GODFIRE: - godsay(rid, B_TRUE, "PAY ATTENTION!"); - break; - case R_GODLIFE: - godsay(rid, B_TRUE, "You must be more proactive, my child."); - break; - case R_GODMERCY: - godsay(rid, B_TRUE, "You lack of proactiveness is disappointing..."); - break; - case R_GODNATURE: - godsay(rid, B_TRUE, "Nature will not tolerate the lazy."); - break; - case R_GODBATTLE: - godsay(rid, B_TRUE, "Your slothfulness has earned you a demotion, soldier."); - break; - case R_GODMAGIC: - godsay(rid, B_TRUE, "One must always strive towards the path!"); - break; - default: - break; - } + godsay(rid, B_TRUE, getflagtext(god->flags, F_GODNOBONUSTEXT)); more(); // parse regular rags @@ -1044,7 +1044,10 @@ lifeform_t *godappears(enum RACE rid, cell_t *where) { // somewhere next to the player. where = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, player, MT_NOTHING); if (!where) { - where = getrandomadjcell(player->cell, B_FALSE, B_NOEXPAND); + where = real_getrandomadjcell(player->cell, WE_NOTWALL, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, player, MT_NOTHING); + } + if (!where) { + where = real_getrandomadjcell(player->cell, WE_NOTWALL, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, player, MT_NOTHING); } } @@ -1063,6 +1066,21 @@ lifeform_t *godappears(enum RACE rid, cell_t *where) { } else { teleportto(god, where, B_TRUE); + // visual effect for some gods + switch (god->race->id) { + case R_GODBATTLE: // bloodsplatter + addob(god->cell->obpile, "splash of blood"); + addobsinradius(god->cell, 2, DT_COMPASS, "splash of blood", B_TRUE, NULL); + break; + case R_GODLIFE: //light + addob(god->cell->obpile, "bright light"); + addobsinradius(god->cell, 2, DT_COMPASS, "bright light", B_TRUE, NULL); + break; + case R_GODFIRE: // fire + addob(god->cell->obpile, "large fire"); + break; + default: break; + } } return god; @@ -1103,7 +1121,7 @@ int godblocked(enum RACE rid) { } // maybe get a gift -int godgiftmaybe(enum RACE rid, int fromtemple) { +int godgiftmaybe(enum RACE rid, int fromtemple, int announce) { lifeform_t *god; int piety,gotgift = B_FALSE; enum PIETYLEV plev; @@ -1140,38 +1158,11 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { killflagsofid(player->flags, F_ASLEEP); - switch (god->race->id) { - case R_GODPURITY: - godsay(god->race->id, B_TRUE, "I bestow a gift upon you, mortal!"); - break; - case R_GODTHIEVES: - godsay(god->race->id, B_TRUE, "Loyalty has its rewards..."); - break; - case R_GODDEATH: - godsay(god->race->id, B_TRUE, "Your service has impressed me..."); - break; - case R_GODFIRE: - godsay(god->race->id, B_TRUE, "DESTROY IN MY NAME!"); - break; - case R_GODLIFE: - godsay(god->race->id, B_TRUE, "Use this gift to spread the joy of life!"); - break; - case R_GODMERCY: - godsay(god->race->id, B_TRUE, "As you have shown mercy, so shall you receive it!"); - break; - case R_GODNATURE: - godsay(god->race->id, B_TRUE, "Harvest nature's bounty!"); - break; - case R_GODBATTLE: - godsay(god->race->id, B_TRUE, "Gather up the spoils of battle!"); - break; - case R_GODMAGIC: - godsay(god->race->id, B_TRUE, "One has earned a reward!"); - break; - default: - break; + if (announce) { + // god announcement. + godsay(rid, B_TRUE, getflagtext(god->flags, F_GODGIFTTEXT)); + more(); } - more(); strcpy(obtogive, ""); switch (god->race->id) { case R_GODBATTLE: @@ -1910,6 +1901,17 @@ void pleasegod(enum RACE rid, int amt) { // don't please/anger gods while enraged. if (lfhasflag(player, F_RAGE)) return; + // if you haven't praeyd to anyone yet, piety + // gain is boosted heaps. + /* + if (!prayedtoany()) { + switch (rid) { + case R_GODTHIEVES: amt *= 4; break; + default: break; + } + } + */ + lf = findgod(rid); real_getlfname(lf, lfname, NULL, B_NOSHOWALL, B_REALRACE); @@ -1959,10 +1961,16 @@ void pleasegod(enum RACE rid, int amt) { break; } } - godgiftmaybe(rid, B_FALSE); - } + godgiftmaybe(rid, B_FALSE, B_TRUE); // - checkgodbonus(rid,newplev, oldplev); + checkgodbonus(rid,newplev, oldplev); + } + + if (!prayedtoany() && !lfhasflag(player, F_GODOFFERDONE)) { + if ((newplev > oldplev) && (newplev >= PL_PLEASED)) { + askforworship(rid); + } + } } void pleasegodmaybe(enum RACE rid, int amt) { @@ -1973,17 +1981,21 @@ void pleasegodmaybe(enum RACE rid, int amt) { modplev = abs(getpietylev(rid, NULL, NULL)); - // the angrier or more happy the god gets, the harder it - // is to please them. - // ie. INDIFFERENT = 1 in 1 (always) - // ie. PLEASED/TOLERATED = 1 in 2 - // ie. DELIGHTED/ANGRY = 1 in 3 - // ie. ECSTATIC/FURIOUS = 1 in 4 - // ie. ENRAGED = 1 in 5 - chance = modplev + 1; - if (hasequippedobid(player->pack, OT_AMU_PIETY)) { - chance--; - limit(&chance, 1, NA); + if (!prayedtoany()) { + chance = 1; + } else { + // the angrier or more happy the god gets, the harder it + // is to please them. + // ie. INDIFFERENT = 1 in 1 (always) + // ie. PLEASED/TOLERATED = 1 in 2 + // ie. DELIGHTED/ANGRY = 1 in 3 + // ie. ECSTATIC/FURIOUS = 1 in 4 + // ie. ENRAGED = 1 in 5 + chance = modplev + 1; + if (hasequippedobid(player->pack, OT_AMU_PIETY)) { + chance--; + limit(&chance, 1, NA); + } } if (onein(chance)) { diff --git a/god.h b/god.h index 191d9d6..b2fda13 100644 --- a/god.h +++ b/god.h @@ -2,6 +2,7 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why); int angergodmaybe(enum RACE rid, int amt, enum GODANGERREASON why); +void askforworship(enum RACE rid); void checkgodbonus(enum RACE rid, enum PIETYLEV newlev, enum PIETYLEV oldlev); void dooffer(void); lifeform_t *findgod(enum RACE rid); @@ -18,7 +19,7 @@ void givegodbonus(enum RACE rid, flag_t *bf); lifeform_t *godappears(enum RACE rid, cell_t *where); void god_usepoison_response(void); int godblocked(enum RACE rid); -int godgiftmaybe(enum RACE rid, int fromtemple); +int godgiftmaybe(enum RACE rid, int fromtemple, int announce); int godisangry(enum RACE rid); int godprayedto(enum RACE rid); void godsay(enum RACE rid, int says, char *format, ...); @@ -28,6 +29,7 @@ void parsegodbonusargs(flag_t *bf, enum PIETYLEV *bonuslev, enum GODBONUS *bonus void pleasegod(enum RACE rid, int amt); void pleasegodmaybe(enum RACE rid, int amt); int prayto(lifeform_t *lf, lifeform_t *god); +int prayedtoany(void); void removegodbonus(enum RACE rid, flag_t *bf); void setpiety(enum RACE rid, int amt); int uncurse_one_equipped(lifeform_t *lf, char *text); diff --git a/io.c b/io.c index 17504b1..dfb586b 100644 --- a/io.c +++ b/io.c @@ -1311,6 +1311,7 @@ void announcearrival(lifeform_t *lf, map_t *newmap) { } int announceflaggain(lifeform_t *lf, flag_t *f) { + object_t *o; int donesomething = B_FALSE; lifeform_t *lf2; char lfname[BUFLEN]; @@ -1672,6 +1673,18 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_FULLSHIELD: + o = hasobid(lf->pack, atol(f->text)); + assert(o); + getobname(o,obname,1); + if (isplayer(lf)) { + msg("You are now cowering behind your %s.", noprefix(obname)); + donesomething = B_TRUE; + } else { + msg("%s is now cowering behind %s.", lfname, obname); + donesomething = B_TRUE; + } + break; case F_HEAVENARM: if (isplayer(lf)) { // don't know if monsters get it msg("^%cYou are surrounded by a %s!", getlfcol(lf, CC_GOOD), f->text); @@ -2506,6 +2519,10 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { msg("^%c%s %s less sick now.^n", getlfcol(lf, CC_VGOOD), lfname, isplayer(lf) ? "feel" : "looks"); donesomething = B_TRUE; break; + case F_FULLSHIELD: + msg("%s %s no longer fully shielded.", lfname, isplayer(lf) ? "are" : "is"); + donesomething = B_TRUE; + break; case F_HEAVENARM: if (isplayer(lf)) { // don't know if monsters get it msg("^%cYour %s vanishes!", getlfcol(lf, CC_BAD), f->text); @@ -11118,8 +11135,10 @@ void drawstatus(void) { } wattron(statwin, A_BOLD); wprintw(statwin, " Trn:"); wattroff(statwin, A_BOLD); - wprintw(statwin, "%d/%d%% ", player->skillpoints, - (int) ((float)player->skillxp / (float)getspforpoint(player) * 100.0) ); + if (player->skillpoints > 0) setcol(statwin, C_BOLDGREEN); + wprintw(statwin, "%d", player->skillpoints); + if (player->skillpoints > 0) unsetcol(statwin, C_BOLDGREEN); + wprintw(statwin, "/%d%% ", (int) ((float)player->skillxp / (float)getspforpoint(player) * 100.0) ); // blinded? @@ -11364,6 +11383,13 @@ void drawstatus(void) { unsetcol(statwin, C_MAGENTA); } + f = lfhasflag(player, F_FULLSHIELD); + if (f) { + setcol(statwin, C_MAGENTA); + wprintw(statwin, " FullShld"); + unsetcol(statwin, C_MAGENTA); + } + // construct waiting string strcpy(waitbuf, ""); /* @@ -13876,6 +13902,15 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "Gravity is lessened around %s, preventing fall damage, increasing flight speed and reducing load.", you_l(lf)); y++; } + f = lfhasknownflag(lf, F_FULLSHIELD); + if (f && (f->known)) { + object_t *sh; + char obname[BUFLEN]; + sh = hasobid(lf->pack, atol(f->text)); + getobname(sh, obname, 1); + mvwprintw(mainwin, y, 0, "%s %s fully shielded by %s %s.", you(lf), is(lf), your(lf), obname); + y++; + } f = lfhasknownflag(lf, F_HEAVENARM); if (f && (f->known)) { char hpbuf[BUFLEN]; diff --git a/lf.c b/lf.c index 2af42b0..8696e08 100644 --- a/lf.c +++ b/lf.c @@ -1937,6 +1937,8 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar // take time taketime(lf, getspellspeed(lf)); + killflagsofid(lf->flags, F_FULLSHIELD); + if (!fromob) { flag_t *retflag[MAXCANDIDATES]; int nretflags,tempboost = 0,i; @@ -3075,6 +3077,10 @@ void die(lifeform_t *lf) { willbecomeghost = B_TRUE; } + // remove poison when you die + killflagsofid(lf->flags, F_INCUBATING); + killflagsofid(lf->flags, F_POISONED); + // died after entering a new level without a chance to move? // note that this won't save you frmo bring killed by a monster which // chases you up/down the stairs. @@ -5056,10 +5062,10 @@ int eat(lifeform_t *lf, object_t *o) { } // eating animals pleases ekrub if (corpserace && (corpserace->raceclass->id == RC_ANIMAL)) { - if (gethungerlevel(gethungerval(lf)) > H_NONE) { - pleasegodmaybe(R_GODNATURE, 5); - addflag(o->flags, F_NOSACRIFICE, B_TRUE, NA, NA, NULL); - } + //if (gethungerlevel(gethungerval(lf)) > H_NONE) { + pleasegodmaybe(R_GODNATURE, 5); + addflag(o->flags, F_NOSACRIFICE, B_TRUE, NA, NA, NULL); + //} } } @@ -5835,6 +5841,7 @@ int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) { addflag(lf->flags, F_PRONE, B_TRUE, NA, NA, NULL); loseconcentration(lf); + interrupt(lf); breakgrabs(lf, B_TRUE, B_TRUE); if (isvulnto(lf->flags, DT_FALL, B_FALSE)) { // 0 will be repplaced with the dtvuln flag @@ -7677,6 +7684,10 @@ int getevasion(lifeform_t *lf) { } } + if (lfhasflag(lf, F_FULLSHIELD)) { + ev -= 50; + } + // modify for stickiness if (hasobwithflag(lf->cell->obpile, F_RESTRICTMOVEMENT)) { ev -= 50; @@ -8320,6 +8331,10 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) { // modify for weilder's level acc += (lf->level * 2); + if (lfhasflag(lf, F_FULLSHIELD)) { + acc -= 50; + } + if (lfhasflag(lf, F_RAGE)) { // huge bonus acc += 50; @@ -9278,6 +9293,10 @@ int getvisrange(lifeform_t *lf, int useambient) { // can't see as far if you're on the ground range /= 2; } + if (lfhasflag(lf, F_FULLSHIELD)) { + if (range > 1) range = 1; + } + limit(&range, 0, MAXVISRANGE); return range; } @@ -9525,27 +9544,33 @@ char *real_getlfname(lifeform_t *lf, char *buf, lifeform_t *usevis, int showall, lorelev = PR_MASTER; } - // 'the' or 'your' ? - f = lfhasflag(lf, F_NAME); + f = hasname(lf); if (f) { strcpy(the, ""); strcpy(lname, f->text); - } else if (lfhasflag(lf, F_UNIQUE)) { - strcpy(the, ""); - strcpy(lname, lfrace->name); } else { - if (ispetof(lf, player)) { - strcpy(the, "your "); + // 'the' or 'your' ? + f = lfhasflag(lf, F_NAME); + if (f) { + strcpy(the, ""); + strcpy(lname, f->text); + } else if (lfhasflag(lf, F_UNIQUE)) { + strcpy(the, ""); + strcpy(lname, lfrace->name); } else { - strcpy(the, "the "); - } - f = lfhasflag(lf, F_NAMED); - if (f) { // ie. "the xat named blah" - strcpy(lname, lfrace->name); - strcat(lname, " named "); - strcat(lname, f->text); - } else { // ie. "the xat" - strcpy(lname, lfrace->name); + if (ispetof(lf, player)) { + strcpy(the, "your "); + } else { + strcpy(the, "the "); + } + f = lfhasflag(lf, F_NAMED); + if (f) { // ie. "the xat named blah" + strcpy(lname, lfrace->name); + strcat(lname, " named "); + strcat(lname, f->text); + } else { // ie. "the xat" + strcpy(lname, lfrace->name); + } } } @@ -9702,7 +9727,7 @@ char *real_getlfnamea(lifeform_t *lf, char *buf, lifeform_t * usevis, int showal real_getlfname(lf, buf2, usevis, showall, useorigrace); - if (lfhasflag(lf, F_NAME) || lfhasflag(lf, F_UNIQUE)) { + if (hasname(lf) || lfhasflag(lf, F_UNIQUE)) { strcpy(the, ""); } else { if (ispetof(lf, player)) { @@ -12315,6 +12340,23 @@ int hastempinjuries(lifeform_t *lf) { return count; } +flag_t *hasname(lifeform_t *lf) { + flag_t *nameflag = NULL,*f; + // check for polymorphed named creatures + f = lfhasflag(lf, F_ORIGRACE); + if (f) { + race_t *origrace; + origrace = findrace(f->val[0]); + if (origrace) { + nameflag = hasflag(origrace->flags, F_NAME); + } + } + if (!nameflag) { + nameflag = lfhasflag(lf, F_NAME); + } + return nameflag; +} + /* int hassubjob(lifeform_t *lf, enum SUBJOB id) { flag_t *f; @@ -13143,7 +13185,7 @@ int haslofknown(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdes } // got line of fire to dest? if lof is blocked, return last cell in 'newdest' // if 'srclf' is set, we are checking whether 'srclf' THINKS they have line of fire. ie invisible/unseed -// lifeforms don't block lof. +// lifeforms don't block lof. also srclf won't be able to block its own lof. // // if 'walllfsok' is set, then we ARE allowed to have lineoffire to walls (ie. solid cells) if there is a lifeform // there. @@ -13238,7 +13280,7 @@ int haslof_real(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdes // lifeforms block lof unless: // - they're in the first cell (ie the one doing the throwing/firing/shooting/etc) // - they're in our destination - if (cell->lf && (!isprone(cell->lf)) && (loftype & LOF_LFSSTOP)) { + if (cell->lf && (!isprone(cell->lf)) && (loftype & LOF_LFSSTOP) && (cell->lf != srclf)) { int lfcanblocklof = B_TRUE; if (srclf && !cansee(srclf, cell->lf)) { @@ -15839,6 +15881,8 @@ int loadfirearmfast(lifeform_t *lf, int onpurpose) { } void loseconcentration(lifeform_t *lf) { + killflagsofid(lf->flags, F_FULLSHIELD); + // stop sprinting stopsprinting(lf); @@ -17449,11 +17493,13 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, } else if (noisemaker && !isplayer(noisemaker) && (nclass == NC_MOVEMENT)) { // monsters won't turn to face other monsters' footsteps } else if (tf) { + lifeform_t *targlf = NULL; if (tf->id == F_TARGETLF) { - lifeform_t *targlf; // will probably ignore the sound unless // it is closer. - targlf = gettargetlf(l); + targlf = findlf(l->cell->map, tf->val[0]); + } + if (targlf) { if (getcelldist(l->cell, c) < getcelldist(l->cell, targlf->cell)) { if ((volume >= 4) && onein(2)) { willrespond = B_TRUE; @@ -19592,7 +19638,12 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { msg("^wYou revert to your original form!"); } else if (cansee(player, lf)) { getlfname(lf, buf); - msg("^wThe %s transforms back to its original form!", newrace->name); + if (hasname(lf)) { + msg("^w%s transforms back to %s original form!", newrace->name, + (getgender(lf) == G_FEMALE) ? "her" : "his"); + } else { + msg("^wThe %s transforms back to its original form!", newrace->name); + } } //} @@ -19706,7 +19757,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { // set material lf->material = lf->race->material; - // inherit most flags from race + // inherit most flags from new race for (f = lf->race->flags->first ; f ; f = f->next) { int ignorethis = B_FALSE; switch (f->id) { @@ -22248,7 +22299,7 @@ void startlfturn(lifeform_t *lf) { // effects for/on your own flags getflags(lf->flags, retflag, &nretflags, F_ANTICIPATE, F_ATTACHEDTO, F_CANCAST, F_CANWILL, F_CHARMEDBY, F_CLIMBING, F_FEIGNFOOLEDBY,F_FLEEFROM, - F_GRABBEDBY, F_GRABBING, F_HIDING, F_BOOSTSPELL, F_FEIGNINGDEATH, F_HPDRAIN, F_INCUBATING, F_INJURY, + F_GRABBEDBY, F_GRABBING, F_HIDING, F_BOOSTSPELL, F_FEIGNINGDEATH, F_FULLSHIELD,F_HPDRAIN, F_INCUBATING, F_INJURY, F_NOFLEEFROM, F_PETOF, F_SIZETIMER, F_SPOTTED, F_STRIKETOKO, F_TARGETCELL, F_TARGETLF, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; @@ -22294,6 +22345,15 @@ void startlfturn(lifeform_t *lf) { } } + if (f->id == F_FULLSHIELD) { + object_t *sh; + sh = hasobid(lf->pack, atol(f->text)); + if (!sh || !isequipped(sh)) { + killflag(f); + continue; + } + } + if (f->id == F_GRABBEDBY) { lifeform_t *lf2; lf2 = findlf(NULL, f->val[0]); @@ -23626,6 +23686,9 @@ int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where) } } + if (aid != OT_A_FULLSHIELD) { + killflagsofid(lf->flags, F_FULLSHIELD); + } // taketime() will happen during abiltiyeffects() // use the ability @@ -23711,7 +23774,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { object_t *dstportal; wantdepth = rnd(1,lf->cell->map->region->rtype->maxdepth); // generate random destination portal - dstportal = linkportal(o, wantdepth); + dstportal = linkportaltodepth(o, wantdepth); if (dstportal) { flag_t *newf; // if source portal is temporary, make the @@ -23871,7 +23934,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { if (curmap->depth < MAXDEPTH) { newdepth = rnd(curmap->depth, curmap->depth + 5); limit(&newdepth, curmap->depth, MAXDEPTH); - linkportal(o, newdepth); + linkportaltodepth(o, newdepth); newcell = getstairdestination(o, &madenewmap); } if (!newcell) { diff --git a/lf.h b/lf.h index ec707a9..2104aad 100644 --- a/lf.h +++ b/lf.h @@ -313,6 +313,7 @@ int real_hasfreeaction(lifeform_t *lf, enum FLAG exception); int hashealableinjuries(lifeform_t *lf); job_t *hasjob(lifeform_t *lf, enum JOB job); int hasjobcat(lifeform_t *lf, enum JOBCATEGORY jcid); +flag_t *hasname(lifeform_t *lf); //int hassubjob(lifeform_t *lf, enum SUBJOB id); int hassoul(lifeform_t *lf); void inc_quad_range(enum QUADRANT *start, enum QUADRANT *end, int howmuch); diff --git a/map.c b/map.c index cc934a9..a20784d 100644 --- a/map.c +++ b/map.c @@ -980,7 +980,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in int possdir[MAXCANDIDATES]; int ncells = 0, npossible = 0; int doorsadded = 0; - int db = B_TRUE; + int db = B_FALSE; if (db) dblog("autodoors starting"); @@ -2018,9 +2018,101 @@ int doelementspread(cell_t *c) { return B_FALSE; } +// returns # cells filled in +int dodoorfill(cell_t *c) { + int dir,nfilled = 0,db = B_FALSE; + cell_t *firstadj = NULL; + int firstdir = D_NONE; + // fill in the door cell itself + c->filled = B_TRUE; + // empty all surrounding cells + for (dir = DC_N; dir <= DC_NW; dir++) { + cell_t *c2; + c2 = getcellindir(c, dir); + if (c2) { + c2->filled = B_FALSE; + if (!firstadj && !issolid(c2)) { + firstadj = c2; + firstdir = dir; + } + } + } + if (db) dblog("first dir was %s\n",getdirname(firstdir)); + if (!firstadj) return 0; + // floodfill from an adacent cell + doorfill_r(c, firstadj, &nfilled); + // debug... + if (db) { + int order[9] = { + DC_NW, DC_N, DC_NE, + DC_W, D_NONE, DC_E, + DC_SW, DC_S, DC_SE + }; + int i; + char buf[BUFLEN]; + cell_t *c2; + strcpy(buf, ""); + for (i = 0; i < 9; i++) { + dir = order[i]; + if (dir == D_NONE) { + strcat(buf, "+"); + } else { + c2 = getcellindir(c, dir); + if (c2) { + if (c2->filled) { + strcat(buf, "F"); + } else { + if (issolid(c2)) { + strcat(buf, "#"); + } else { + strcat(buf, "."); + } + } + } else { + strcat(buf, "x"); + } + } + switch (dir) { + case DC_NE: + case DC_E: + case DC_SE: + dblog("%s", buf); + strcpy(buf, ""); + break; + } + } + + } + + return nfilled; +} + + +void doorfill_r(cell_t *startcell, cell_t *c, int *nfilled) { + int d; + if (c && // not off the map + !c->type->solid && // empty cell + !c->filled && // not already filled + !hasdoor(c) && // not a door + (getcelldist(startcell,c) == 1) // adjacent to first cell + ) { + if (nfilled) (*nfilled)++; + c->filled = B_TRUE; + } else { + return; + } + for (d = DC_N; d <= DC_NW; d++) { + doorfill_r(startcell, getcellindir(c, d), nfilled); // recursive call + } +} + + int fix_reachability(map_t *m) { - int i,keepgoing = B_TRUE, nfixed = 0; + int i,nfixed = 0; int db = B_TRUE; + cell_t *unreachcell[MAX_MAPW*MAX_MAPH]; + cell_t *reachcell[MAX_MAPW*MAX_MAPH]; + int nunreach = 0,nreach = 0; cell_t *c = NULL; if (db) dblog("fix_reachability starting."); @@ -2044,15 +2136,18 @@ int fix_reachability(map_t *m) { } // no empty cells in map? if (!c) return B_FALSE; - while (keepgoing) { - keepgoing = B_FALSE; + nunreach = 1; + while (nunreach) { // mark all cells as non-filled for (i = 0; i < m->w * m->h; i++) { m->cell[i]->filled = FALSE; } // floodfill floodfill(c); + // any remaining non-filled empty cells? + nunreach = 0; + nreach = 0; for (i = 0; i < m->w * m->h; i++) { if (!m->cell[i]->type->solid && !m->cell[i]->filled && ((m->cell[i]->room && m->cell[i]->room->prevault) || !m->cell[i]->locked ) ) { @@ -2061,34 +2156,68 @@ int fix_reachability(map_t *m) { if (v && hasflag(v->flags, F_VAULTNOLINK)) { // don't need to link it. } else { - int nadded = 0; - // found an unreachable cell! link it back to a filled cell. - if (db) dblog(" found unreachable area at %d,%d. will fix it.", - m->cell[i]->x, m->cell[i]->y); - - if (linkexit(m->cell[i], B_TRUE, &nadded)) { - // failed! - if (db) dblog(" fix_reachability failed - couldn't fix an unreachable area."); - return B_TRUE; - } - - if (nadded) { - if (db) dblog(" fixed unreachable area by adding %d cells.", nadded); - } else { - // didn't add anything - fail! - if (db) dblog(" fix_reachability failed."); - return B_TRUE; - } - - // now run the test again. - // 'c' will be where the next flood will will happen. - keepgoing = B_TRUE; - c = m->cell[i]; - nfixed++; - break; + unreachcell[nunreach++] = m->cell[i]; + } + } else { + if (!m->cell[i]->type->solid) { + // reachable. + reachcell[nreach++] = m->cell[i]; } } } + // try to fix unreachable areas. + if (nunreach) { + int nadded = 0,nportals = 0; + int idx,ntries = 0,maxtries = 5; + cell_t *ucell; + // pick one of the unreachable cells + while (ntries < maxtries) { + idx = rnd(0,nunreach-1); + ucell = unreachcell[idx]; + // try to link it back to a filled cell. + if (db) dblog(" attempting to fix unreachable area at %d,%d.", + ucell->x, ucell->y); + + if (!linkexit(ucell, B_TRUE, &nadded)) { + // fixed. + if (db) dblog(" successfully fixed by digging tunnels."); + break; + } else { + if (db) dblog("failed, trying new cell."); + ntries++; + } + } + if (ntries >= maxtries) { + cell_t *rcell; + int ptries = 0; + // failed! try to link via portals. + if (db) dblog(" couldn't link via tunnels. trying to link via portals."); + // select random REACHABLE cell + while (ptries < maxtries) { + rcell = reachcell[rnd(0,nreach-1)]; + if (!createportallink(ucell,rcell, OT_PORTAL)) { + if (db) dblog(" successfully fixed by adding portals."); + nportals++; + break; + } else { + ptries++; + } + } + } + + if (nadded || nportals) { + if (db) dblog(" fixed unreachable area by adding %d cells and %d portals.", nadded,nportals); + } else { + // didn't add anything - fail! + if (db) dblog(" fix_reachability failed."); + return B_TRUE; + } + + // now run the test again. + // 'c' will be where the next flood will will happen. + c = ucell; + nfixed++; + } } if (db) dblog(" fix_reachability complete. fixed %d unreachable areas.", nfixed); return B_FALSE; @@ -2097,6 +2226,7 @@ int fix_reachability(map_t *m) { void floodfill(cell_t *startcell) { int d; + object_t *o; if (startcell && // not off the map !startcell->type->solid && // empty cell !startcell->filled) { // not already filled @@ -2107,6 +2237,23 @@ void floodfill(cell_t *startcell) { for (d = DC_N; d <= DC_NW; d++) { floodfill(getcellindir(startcell, d)); // recursive call } + // follow portals + o = hasob(startcell->obpile, OT_PORTAL); + if (o) { + flag_t *f; + // not using getstairdest cause we don't want to generate + // new levels due to unlinked portals. + f = hasflag(o->flags, F_MAPLINK); + if (f && (f->val[0] == startcell->map->id) && + (f->val[1] != NA) && (f->val[2] != NA)) { + cell_t *c; + c = getcellat(startcell->map, f->val[1], f->val[2]); + if (c) { + floodfill(c); // recursive call + dblog("FLOODFILL THROUGH PORTAL"); + } + } + } } // populates thing & nthings with all "regionthings" with: @@ -3197,7 +3344,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ int moved = 0; enum CELLTYPE emptycell,solidcell; - char buf[BUFLEN]; + //char buf[BUFLEN]; // select dungeon shape. if (onein(3)) { @@ -3208,6 +3355,40 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ switch (shape) { case MS_NORMAL:// normal break; + case MS_HORZ: // horizontal bar + // ###### + // ###### + // + // ###### + // ###### + for (y = 0; y < map->h/4; y++) { + for (x = 0; x < map->w; x++) { + c = getcellat(map, x, y); c->locked = B_TRUE; + } + } + for (y = (map->h/4)*3; y < map->h; y++) { + for (x = 0; x < map->w; x++) { + c = getcellat(map, x, y); c->locked = B_TRUE; + } + } + break; + case MS_VERT: // vertical bar + // ## ## + // ## ## + // ## ## + // ## ## + // ## ## + for (x = 0; x < map->w/4; x++) { + for (y = 0; y < map->h; y++) { + c = getcellat(map, x, y); c->locked = B_TRUE; + } + } + for (x = (map->w/4)*3; x < map->w; x++) { + for (y = 0; y < map->h; y++) { + c = getcellat(map, x, y); c->locked = B_TRUE; + } + } + break; case MS_CROSS: // cross // ## ## // ## ## @@ -3276,6 +3457,17 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ } addflag(map->flags, F_MAPSHAPE, shape, NA, NA, NULL); + for (y = 0; y < map->h; y++) { + for (x = 0; x < map->w; x++) { + c = getcellat(map, x, y); + if (c->locked) { + c->visited = B_TRUE; + } + } + } + + + /* for (y = 0; y < map->h; y++) { strcpy(buf, ""); for (x = 0; x < map->w; x++) { @@ -3291,6 +3483,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ } dblog("%s",buf); } + */ // randomise dungeon parameters turnpct += (rnd(0,40)-20); // (-20 to +20)% @@ -4233,6 +4426,9 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex } } + if (!failed) { + remove_baddoors(map); + } // ensure there are no unreachable areas if (!failed) { if (fix_reachability(map)) { @@ -4256,7 +4452,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex expand_cave(map, 2); } - // add any required stairs + // add any required stairs, fix doors, etc. finalisemap(map, entryob, exitdir); // special cases @@ -5442,7 +5638,7 @@ int linkexits(map_t *m, int roomid) { int x,y,i; cell_t *poss[MAXCANDIDATES],*c; int nposs = 0; - int db = B_TRUE; + int db = B_FALSE; int nadded = 0; int minx = -1, miny = -1, maxx = -1, maxy = -1; int roomidx = -1; @@ -5666,6 +5862,52 @@ void createbranchlink(map_t *m, cell_t *c, object_t *o, char *obname, enum BRANC f->val[1] = r->id; } +// return true on error +int createportallink(cell_t *src, cell_t *dst, enum OBTYPE portalid) { + object_t *dstportal = NULL,*srcportal = NULL; + // make sure cells exist + if (!src || !dst) { + dblog(" createportals(): src or dst cell doesn't exist"); + return B_TRUE; + } + // make sure cells are empty + if (issolid(src) || issolid(dst)) { + dblog(" createportals(): src or dst cell is solid"); + return B_TRUE; + } + + // make sure neither cell has a portal already + if (hasob(src->obpile, portalid) || hasob(dst->obpile, portalid)) { + dblog(" createportals(): src or dst cell already has a portal"); + return B_TRUE; + } + // add the portals + srcportal = addobfast(src->obpile, portalid); + if (!srcportal) { + dblog(" createportals(): couldn't create source portal."); + return B_TRUE; + } + dstportal = addobfast(dst->obpile, portalid); + if (!dstportal) { + dblog(" createportals(): couldn't create destination portal."); + killob(srcportal); + return B_TRUE; + } + linkportals(srcportal,dstportal); + return B_FALSE; +} + +int linkportals(object_t *srcportal, object_t *dstportal) { + cell_t *src,*dst; + src = getoblocation(srcportal); + dst = getoblocation(dstportal); + if (!src || !dst) return B_TRUE; + // link them + addflag_real(srcportal->flags, F_MAPLINK, dst->map->id, dst->x, dst->y, NULL, PERMENANT, B_FALSE, -1); + addflag_real(dstportal->flags, F_MAPLINK, src->map->id, src->x, src->y, NULL, PERMENANT, B_FALSE, -1); + return B_FALSE; +} + void createriver(map_t *m) { int dir,width,startcentre,endcentre; cell_t *retcell[MAX_MAPW*MAX_MAPH]; @@ -5884,6 +6126,36 @@ int dirtoy(int dt, int dir) { return 0; } +int doorisvalid(object_t *o) { + int dir,nfilled = 0; + cell_t *c; + c = getoblocation(o); + /* + // doors must be between two solid cells + for (dir = DC_N; dir <= DC_SE; dir++) { + cell_t *c1; + cell_t *c2; + c1 = getcellindir(c, dir); + c2 = getcellindir(c, diropposite(dir)); + if (!issolid(c1) && !issolid(c2)) { + return B_TRUE; + } + } + */ + if (!dodoorfill(c)) { + // door is surrounded by walls + return B_FALSE; + } + // if there are any empty unfilled cells around the door, it's ok. + nfilled = 0; + for (dir = DC_N; dir <= DC_NW; dir++) { + cell_t *c2; + c2 = getcellindir(c, dir); + if (c2 && !issolid(c2) && !c2->filled) return B_TRUE; + } + + return B_FALSE; +} void dumpmap(map_t *map, int showrooms) { int x,y; @@ -6205,45 +6477,12 @@ void finalisemap(map_t *map, object_t *entryob, int exitdir) { } } - // other finalisation tasks... for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { c = getcellat(map, x, y); for (o = c->obpile->first ; o ; o = nexto) { nexto = o->next; - if (!getcellvault(c)) { - // remove doors which go nowhere (internal to rooms) - if (isdoor(o, NULL)) { - int dir, ok = B_FALSE; - /* - // check all directions for a cell which isn't - // part of this room. - for (dir = DC_N; dir <= DC_NW; dir++) { - c2 = getcellindir(c, dir); - if (c2 && cellwalkable(NULL, c2, NULL) && getroomid(c2) != getroomid(c)) { - ok = B_TRUE; - break; - } - } - */ - // doors must be between two solid cells - for (dir = DC_N; dir <= DC_NW; dir++) { - cell_t *c1; - cell_t *c2; - c1 = getcellindir(c, dir); - c2 = getcellindir(c, diropposite(dir)); - if (issolid(c1) && issolid(c2)) { - ok = B_TRUE; - break; - } - } - if (!ok) { - killob(o); - continue; - } - } - } // unlinked stairs? ie ones added from vaults. if so, link them. if (hasflag(o->flags, F_CLIMBABLE) && !hasflag(o->flags, F_MAPLINK)) { if (!hasflag(o->flags, F_PORTAL)) { @@ -6998,12 +7237,16 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LO int numwithlof = 0; for (y = c->y - radius ; y <= c->y + radius ; y++) { for (x = c->x - radius ; x <= c->x + radius ; x++) { + int gotlof = B_FALSE; new = getcellat(c->map, x, y); + if (new && haslof(c, new, needlof, NULL)) { + gotlof = B_TRUE; + numwithlof++; + } if (new && (new != c) && (getcelldist(c,new) == radius) && - (new != dontwantcell) && - haslof(c, new, needlof, NULL)) { + (new != dontwantcell) && gotlof) { enum OBTYPE *badoid; int ok = B_FALSE; numwithlof++; @@ -7036,7 +7279,9 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LO } // found any possibilities ? - if (nposs) { + if (preferlos && nlosposs) { + done = B_TRUE; + } else if (!preferlos && nposs) { done = B_TRUE; } else { if (allowexpand) { @@ -7044,10 +7289,22 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LO // increment radius radius++; } else { - return NULL; + if (preferlos) { + // start again without preferlos + radius = 1; + preferlos = NULL; + } else { + return NULL; + } } } else { - return NULL; + if (preferlos) { + // start again without preferlos + radius = 1; + preferlos = NULL; + } else { + return NULL; + } } } } @@ -7431,33 +7688,33 @@ void initmap(void) { addhabitat(H_MASTERVAULTS, "master vaults", CT_FLOORDURANITE, CT_WALLDURANITE, 5, 0, 0, MAXVISRANGE, OT_VSTAIRSUP, OT_VSTAIRSDOWN); // cell types - solid - // floorheight, hp, volmod - addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 50, 0); - addcelltype(CT_WALLBRICK, "brick wall", UNI_SHADEDARK, C_ORANGE, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 40, 0); - addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEMED, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 20, 0); - addcelltype(CT_WALLDURANITE, "duranite wall", UNI_SHADEDARK, C_MAGENTA, NA, B_SOLID, B_OPAQUE, MT_DURANITE, 0, 20000, 0); - addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_WOOD, 0, 30, 0); - addcelltype(CT_WALLDWOOD, "wyrmwood wall", UNI_SOLID, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_DRAGONWOOD, 0, 100, 0); - addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, NA, B_SOLID, B_OPAQUE, MT_FLESH, 0, 25, 0); - addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, NA, B_SOLID, B_TRANS, MT_GLASS, 0, 20, 0); + // floorheight, hp, volmod, absorbant + addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 50, 0, B_NOABSORB); + addcelltype(CT_WALLBRICK, "brick wall", UNI_SHADEDARK, C_ORANGE, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 40, 0, B_NOABSORB); + addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEMED, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 20, 0, B_NOABSORB); + addcelltype(CT_WALLDURANITE, "duranite wall", UNI_SHADEDARK, C_MAGENTA, NA, B_SOLID, B_OPAQUE, MT_DURANITE, 0, 20000, 0, B_NOABSORB); + addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_WOOD, 0, 30, 0, B_NOABSORB); + addcelltype(CT_WALLDWOOD, "wyrmwood wall", UNI_SOLID, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_DRAGONWOOD, 0, 100, 0, B_NOABSORB); + addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, NA, B_SOLID, B_OPAQUE, MT_FLESH, 0, 25, 0, B_NOABSORB); + addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, NA, B_SOLID, B_TRANS, MT_GLASS, 0, 20, 0, B_NOABSORB); //addcelltype(CT_WALLTREE, "dense bushland", UNI_SHADEDARK, C_GREEN, B_SOLID, B_OPAQUE, MT_PLANT, 0, 100); - addcelltype(CT_WALLTREE, "dense bushland", UNI_TREELOTS, C_GREEN, NA, B_SOLID, B_OPAQUE, MT_PLANT, 0, 100, 0); - addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, NA, B_SOLID, B_OPAQUE, MT_METAL, 0, 75, 0); + addcelltype(CT_WALLTREE, "dense bushland", UNI_TREELOTS, C_GREEN, NA, B_SOLID, B_OPAQUE, MT_PLANT, 0, 100, 0, B_NOABSORB); + addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, NA, B_SOLID, B_OPAQUE, MT_METAL, 0, 75, 0, B_NOABSORB); // cell types - non-solid - addcelltype(CT_FAKE, "fake cell", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0); - addcelltype(CT_MOSSROCK, "mossy rock floor", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0); - addcelltype(CT_CORRIDOR, "rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0); - addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0); - addcelltype(CT_FLOORCARPET, "carpetted floor", '.', C_RED, C_ORANGE, B_EMPTY, B_TRANS, MT_CLOTH, 0, -1, -1); - addcelltype(CT_FLOORDURANITE, "duranite floor", '.', C_MAGENTA, NA, B_EMPTY, B_TRANS, MT_DURANITE, 0, -1, 1); - addcelltype(CT_FLOORWOOD, "wood floor", '.', C_BROWN, NA, B_EMPTY, B_TRANS, MT_WOOD, 0, -1, 1); - addcelltype(CT_FLOORFLESH, "flesh floor", '.', C_RED, NA, B_EMPTY, B_TRANS, MT_FLESH, 0, -1, -2); - addcelltype(CT_FLOORSHOP, "shop floor", '.', C_BROWN, NA, B_EMPTY, B_TRANS, MT_WOOD, 0, -1, 0); - addcelltype(CT_FLOORTILE, "tiled floor", '.', C_CYAN, C_WHITE, B_EMPTY, B_TRANS, MT_METAL, 0, -1, 2); - addcelltype(CT_GRASS, "grass", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_PLANT, 0, -1, -1); - addcelltype(CT_DIRT, "dirt", '.', C_BROWN, C_YELLOW, B_EMPTY, B_TRANS, MT_STONE, 0, -1, -1); - addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, -1, -1, 0); - addcelltype(CT_VLOWFLOOR, "very low rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, -2, -1, 0); + addcelltype(CT_FAKE, "fake cell", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0, B_NOABSORB); + addcelltype(CT_MOSSROCK, "mossy rock floor", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0, B_NOABSORB); + addcelltype(CT_CORRIDOR, "rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0, B_NOABSORB); + addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0, B_NOABSORB); + addcelltype(CT_FLOORCARPET, "carpetted floor", '.', C_RED, C_ORANGE, B_EMPTY, B_TRANS, MT_CLOTH, 0, -1, -1, B_ABSORB); + addcelltype(CT_FLOORDURANITE, "duranite floor", '.', C_MAGENTA, NA, B_EMPTY, B_TRANS, MT_DURANITE, 0, -1, 1, B_NOABSORB); + addcelltype(CT_FLOORWOOD, "wood floor", '.', C_BROWN, NA, B_EMPTY, B_TRANS, MT_WOOD, 0, -1, 1, B_NOABSORB); + addcelltype(CT_FLOORFLESH, "flesh floor", '.', C_RED, NA, B_EMPTY, B_TRANS, MT_FLESH, 0, -1, -2, B_NOABSORB); + addcelltype(CT_FLOORSHOP, "shop floor", '.', C_BROWN, NA, B_EMPTY, B_TRANS, MT_WOOD, 0, -1, 0, B_NOABSORB); + addcelltype(CT_FLOORTILE, "tiled floor", '.', C_CYAN, C_WHITE, B_EMPTY, B_TRANS, MT_METAL, 0, -1, 2, B_NOABSORB); + addcelltype(CT_GRASS, "grass", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_PLANT, 0, -1, -1, B_ABSORB); + addcelltype(CT_DIRT, "dirt", '.', C_BROWN, C_YELLOW, B_EMPTY, B_TRANS, MT_STONE, 0, -1, -1, B_NOABSORB /* mud instead */); + addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, -1, -1, 0, B_NOABSORB); + addcelltype(CT_VLOWFLOOR, "very low rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, -2, -1, 0, B_NOABSORB); // region types // name, pluralname?, defaulthab, maxdepth stairs stair major? depthmod inherit_parent_depth? @@ -8079,7 +8336,7 @@ int linkholes(map_t *map) { return nlinked; } -object_t *linkportal(object_t *srcportal, int wantdepth) { +object_t *linkportaltodepth(object_t *srcportal, int wantdepth) { cell_t *srcloc,*newcell; map_t *newmap = NULL; object_t *dstportal = NULL; @@ -8097,15 +8354,12 @@ object_t *linkportal(object_t *srcportal, int wantdepth) { while (!cellwalkable(NULL, newcell, NULL) || hasenterableobject(newcell) || getcellwaterdepth(newcell, NULL)) { newcell = getrandomcell(newmap); } + // add the dst portal dstportal = addobfast(newcell->obpile, srcportal->type->id); assert(dstportal); - // link the dst portal - addflag_real(dstportal->flags, F_MAPLINK, srcloc->map->id, srcloc->x, srcloc->y, NULL, PERMENANT, B_FALSE, -1); - - // link the source portal - addflag_real(srcportal->flags, F_MAPLINK, newmap->id, newcell->x, newcell->y, NULL, PERMENANT, B_FALSE, -1); + linkportals(srcportal,dstportal); return dstportal; } @@ -8211,6 +8465,7 @@ int linkstairs(object_t *o, object_t *o2) { return B_FALSE; } + void makedoor(cell_t *cell, int openchance) { object_t *o; map_t *m; @@ -8729,6 +8984,39 @@ int remove_deadends(map_t *m, int howmuch) { return count; } +// returns # doors removed +int remove_baddoors(map_t *m) { + int x,y,num=0; + object_t *o,*nexto; + cell_t *c; + // remove useless doors. + for (y = 0; y < m->h; y++) { + for (x = 0; x < m->w; x++) { + c = getcellat(m, x, y); + for (o = c->obpile->first ; o ; o = nexto) { + nexto = o->next; + //if (!getcellvault(c)) { + if (!cellisfixedvaultwall(c)) { + // remove doors which go nowhere (internal to rooms) + if (isdoor(o, NULL)) { + if (!doorisvalid(o)) { + num++; + dblog("removed useless door at %d,%d", c->x, c->y); + killob(o); + // no other obs here? + if (!countobs(c->obpile, B_FALSE)) { + setcelltype(c, getcellsolid(c)); + } + continue; + } + } + } + } + } + } + return num; +} + void selectcelltypes(map_t *map) { if (map->habitat->id == H_DUNGEON) { // random chance of different wall type diff --git a/map.h b/map.h index 51fdd7e..b0a5373 100644 --- a/map.h +++ b/map.h @@ -30,6 +30,8 @@ cell_t *delve_rndpull(cellstore_t *cs, cell_t **c); void delve_storecell(cellstore_t *cs, cell_t *c); int damagecell(cell_t *c, int amt, enum DAMTYPE damtype, lifeform_t *fromlf); int doelementspread(cell_t *c); +int dodoorfill(cell_t *c); +void doorfill_r(cell_t *startcell, cell_t *c, int *nfilled); int fix_reachability(map_t *m); int fix_unreachable_cell(cell_t *badcell); void floodfill(cell_t *startcell); @@ -84,6 +86,7 @@ void createheaven(map_t *map, int depth, map_t *parentmap, int exitdir, object_t void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int exitdir, object_t *entryob); void createmastervaults(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob); void createpit(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob); +int createportallink(cell_t *c1, cell_t *c2, enum OBTYPE portalid); void createbranchlink(map_t *m, cell_t *c, object_t *o, char *obname, enum BRANCH newbranch, region_t *parent); void createregionthing(map_t *map, regionthing_t *rt); void createriver(map_t *m); @@ -95,6 +98,7 @@ void createswamp(map_t *map, int depth, map_t *parentmap, int exitdir, object_t int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *retx, int *rety); int dirtox(int dt, int dir); int dirtoy(int dt, int dir); +int doorisvalid(object_t *o); void dumpmap(map_t *map, int showrooms); void expand_cave(map_t *map, int numpasses); void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *centre, lifeform_t *fromwho); @@ -176,7 +180,8 @@ void killregion(region_t *r); int linkexit(cell_t *c, int wantfilled, int *ncellsadded); int linkexits(map_t *m, int roomid); int linkholes(map_t *map); -object_t *linkportal(object_t *srcportal, int wantdepth); +object_t *linkportaltodepth(object_t *srcportal, int wantdepth); +int linkportals(object_t *srcportal, object_t *dstportal); int linkstairs(object_t *o, object_t *o2); void makedoor(cell_t *cell, int openchance); void makelit(cell_t *c, enum OBTYPE how, int howlong, int power); @@ -188,6 +193,7 @@ void moveobtoclearcell(object_t *o); int orthdir(int compassdir); enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum BEHAVIOUR *wantbehaviour); int remove_deadends(map_t *m, int howmuch); +int remove_baddoors(map_t *m); void selectcelltypes(map_t *map); void set_scanned_glyph(int targettype, void *what, char *descappend, char *desc, glyph_t *glyph); void setcellknown(cell_t *cell, int forcelev); diff --git a/move.c b/move.c index ed07e29..8eeae37 100644 --- a/move.c +++ b/move.c @@ -680,7 +680,7 @@ int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int d } if (keepinlof) { - if (!haslof(c, dst, LOF_NEED, NULL)) { + if (!haslof_real(c, dst, LOF_NEED, NULL, srclf, B_TRUE)) { ok = B_FALSE; } } @@ -2824,7 +2824,11 @@ int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke) { msg("Suddenly, your surroundings appear different!"); } else if (cansee(player, lf)) { getlfname(lf, buf); - msg("%s appears!", buf); + if (getraceclass(lf) == RC_GOD) { + msg("%s %s!", buf, getflagtext(lf->flags, F_GODTEXTAPPEAR)); + } else { + msg("%s appears!", buf); + } } // show any objects here, just like if we moved. // BUT don't let dolook() clear the msg bar if there are diff --git a/nexus.c b/nexus.c index 5182beb..b4f8ad7 100644 --- a/nexus.c +++ b/nexus.c @@ -696,7 +696,7 @@ int main(int argc, char **argv) { return B_FALSE; } -celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp, int volumemod) { +celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp, int volumemod, int absorbent) { celltype_t *a; // add to the end of the list @@ -730,6 +730,7 @@ celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, i a->floorheight = floorheight; a->hp = hp; a->volumemod = volumemod; + a->absorbent = absorbent; a->flags = addflagpile(NULL, NULL); @@ -2070,7 +2071,7 @@ void timeeffectsworld(map_t *map, int updategametime) { splittime(&th, &tm, &ts); timeleft -= TICK_INTERVAL; - dblog("------ tick (time=%ld %d:%d:%d) ----", curtime,th,tm,ts); + dblog("------ tick (time=%ld %02d:%02d:%02d) ----", curtime,th,tm,ts); // global time-based effects on map or map objects for (y = 0; y < map->h; y++) { diff --git a/nexus.h b/nexus.h index f107dc1..bc39cc4 100644 --- a/nexus.h +++ b/nexus.h @@ -1,6 +1,6 @@ #include "defs.h" -celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp, int volumemod); +celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp, int volumemod, int absobent); warning_t *addwarning(char *text, int lifetime); void checkdeath(void); void checkendgame(void); diff --git a/objects.c b/objects.c index d2cbcb7..36aa740 100644 --- a/objects.c +++ b/objects.c @@ -1452,6 +1452,9 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum o->blessed = B_CURSED; } } + if (where->owner && isplayer(where->owner)) { + killflagsofid(o->flags, F_UNTOUCHED); + } // fill in portal destinations @@ -4307,7 +4310,6 @@ int real_getobvalue(object_t *o, int amt) { } else if (o->type->id == OT_GRIMOIRE) { price += (59*countobs(o->contents, B_FALSE)); } - getflags(o->flags, retflag, &nretflags, F_ARMOURRATING, F_ARMOURSIZE, F_BONUS, F_DAM, F_EDIBLE, F_LINKSPELL, F_MANUALOF, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; @@ -4315,7 +4317,7 @@ int real_getobvalue(object_t *o, int amt) { if (f->id == F_DAM) { int min,max; getdamrange(o, f, &min, &max); - price += (max*5); + price += (max*7); } // armour rating if (f->id == F_ARMOURRATING) { @@ -4351,6 +4353,11 @@ int real_getobvalue(object_t *o, int amt) { } } + if (hasflagval(o->flags, F_USESSKILL, SK_EXOTICWEPS, NA, NA, NULL)) { + price *= 2; + } + + // TODO: rings? if (hasflag(o->flags, F_HASBRAND)) { @@ -6381,8 +6388,8 @@ objecttype_t *real_getrandomob(map_t *map, char *buf, int forcedepth, int forceh } while (!done) { - if (db || partdb) dblog("adding random object with rarity value between %d - %d and rr <= %d, for habitat %s", - raritymin,raritymax,wantrr, habname); + if (db || partdb) dblog("adding random object with rarity value between %d - %d and rr <= %d(%s), for habitat %s", + raritymin,raritymax,wantrr, getrarityname(wantrr), habname); if (db || partdb) { char dbuf[BUFLEN]; if (wantsk) { @@ -6452,8 +6459,8 @@ objecttype_t *real_getrandomob(map_t *map, char *buf, int forcedepth, int forceh if (thisrr == wantrr) { rarok = B_TRUE; } else { - if (db) dblog(" %s rarity(%d) doesn't match wantrr(%d)", ot->name, - rarflag->val[2], wantrr); + if (db) dblog(" %s rarity(%d) doesn't match wantrr(%d,%s)", ot->name, + rarflag->val[2], wantrr, getrarityname(wantrr)); } } else { if (db) dblog(" rarity of %s out of range (%d)", ot->name, rarflag->val[1]); @@ -6540,18 +6547,18 @@ objecttype_t *real_getrandomob(map_t *map, char *buf, int forcedepth, int forceh if (rrmoddir == -1) { if (wantrr > RR_FREQUENT) { wantrr--; - if (db || partdb) dblog("rarity at min/max and no obs. lowering wantrr to %d.",wantrr); + if (db || partdb) dblog("rarity at min/max and no obs. lowering wantrr to %d (%s).",wantrr,getrarityname(wantrr)); } else { // wantrr is already at rr_frequent // start increasing it now. wantrr = origwantrr + 1; rrmoddir = 1; - if (db || partdb) dblog("rarity got below frequent. raising to original rr + 1 (%d)",wantrr); + if (db || partdb) dblog("rarity got below frequent. raising to original rr + 1 (%d, %s)",wantrr,getrarityname(wantrr)); } } else { if (wantrr < RR_VERYRARE) { wantrr++; - if (db || partdb) dblog("rarity at min/max and no obs. raising wantrr to %d.",wantrr); + if (db || partdb) dblog("rarity at min/max and no obs. raising wantrr to %d(s).",wantrr,getrarityname(wantrr)); } else { // give up strcpy(buf, ""); @@ -8563,6 +8570,7 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { int i,preburdened = B_FALSE; int db = B_FALSE; int redrawaftermove = B_FALSE; + int pleasethiefgod = 0; lifeform_t *robbedlf = NULL; flag_t *f; @@ -8573,6 +8581,16 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { return NULL; } + if (dst->owner && isplayer(dst->owner) && hasflag(src->flags, F_UNTOUCHED)) { + // values here should be half as much as if you + // were to sacrifice it. + if (src->type->id == OT_GOLD) { + pleasethiefgod = (getobvalue(src) / 4); + } else if (hasflag(src->flags, F_GEM)) { + pleasethiefgod = (getobvalue(src) / 100); + } + } + touch_battle_spoils(src); // object being taken from an unconscious lf? @@ -8786,6 +8804,10 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { } } + if (pleasethiefgod) { + pleasegodmaybe(R_GODTHIEVES, pleasethiefgod); + } + // in case you picked up money, something which changes your AR, etc if (isplayer(dst->owner)) { statdirty = B_TRUE; @@ -12204,14 +12226,14 @@ int readsomething(lifeform_t *lf, object_t *o) { if (isplayer(lf)) { char ooname[BUFLEN]; getobname(oo, ooname, oo->amt); - msg("Your %s become%s ultra-dense!", noprefix(ooname), (oo->amt == 1) ? "s" : ""); + msg("Your %s become%s ultra-dense!", noprefix(ooname), OBS1(oo)); } else if (cansee(player, lf)) { char lfname[BUFLEN]; char ooname[BUFLEN]; getlfname(lf, lfname); getobname(oo, ooname, oo->amt); msg("%s%s %s become%s ultra-dense!", lfname, getpossessive(lfname), - noprefix(ooname), (oo->amt == 1) ? "s" : ""); + noprefix(ooname), OBS1(oo)); } addflag(oo->flags, F_IMMUTABLE, B_TRUE, NA, NA, NULL); killflagsofid(oo->flags, F_DAMAGABLE); @@ -12407,6 +12429,12 @@ object_t *relinkob(object_t *src, obpile_t *dst) { // previous owner loses all flags conferred by this object loseobflags(src->pile->owner, src, ALLCONFERRED); } + if (dst->owner) { + if (isplayer(dst->owner)) { + // can't now sacrifice this money! + killflagsofid(src->flags, F_UNTOUCHED); + } + } // unweild killflagsofid(src->flags, F_EQUIPPED); @@ -13973,7 +14001,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp // an actual physical shield? sprintf(attackname, "%s", obname); difficulty = 60 + (speed*10); - if (check_for_block(thrower, target, getthrowdam(o) + speed, DT_PROJECTILE, difficulty, attackname)) { + if (check_for_block(thrower, target, getthrowdam(o) + speed, DT_PROJECTILE, difficulty, attackname, B_RANGED)) { announcedmiss = B_TRUE; youhit = B_FALSE; missiledam += ((speed*2)+rnd(1,4)); @@ -14650,6 +14678,21 @@ void timeeffectsob(object_t *o) { } } + if (location && onground) { + + if ((o->type->material->id == MT_WATER) || (o->type->id == OT_SPLASHWATER)) { + if (location->type->absorbent) { + if (haslos(player, location)) { + msg("%s %s absorbed into the %s.", obname, + OB1(o,"is","are"), location->type->name); + } + removeob(o, ALL); + return; + } + } + } + + // check each flag for this object... getflags(o->flags, retflag, &nretflags, F_ACTIVATED, F_EDIBLE, F_EXPLODEONDEATH, F_MATCONVERT, F_HOT, F_KNOCKAWAY, F_OBHPDRAIN, F_ONFIRE, F_RECHARGE, F_REVIVETIMER, F_WALKDAM, F_WET, F_NONE); @@ -15370,6 +15413,9 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c, object_t *trapped movelf(lf, escapeto, B_TRUE); } } + if (lf && isplayer(lf)) { + pleasegodmaybe(R_GODFIRE, 10); + } if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards } else if (oid == OT_TRAPLIGHTNING) { // can't be dodged @@ -15861,6 +15907,8 @@ int wepdullable(object_t *o) { if (!o) return B_FALSE; + if (o->blessed) return B_FALSE; + // exceptions switch (o->type->id) { case OT_NANOBLADE: diff --git a/shops.c b/shops.c index cbfad9e..e7ef817 100644 --- a/shops.c +++ b/shops.c @@ -820,7 +820,7 @@ enum SHOPRETURN shopmiracle(lifeform_t *lf, object_t *vm, int starty, char *topt givemoney(lf, NULL, cost); - godgiftmaybe(god->race->id, B_TRUE); + godgiftmaybe(god->race->id, B_TRUE, B_TRUE); more(); return SR_BACK; diff --git a/spell.c b/spell.c index c0f88ea..99ca11e 100644 --- a/spell.c +++ b/spell.c @@ -850,6 +850,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } practice(user, SK_COOKING, 1); ncooked++; + if (isplayer(user)) pleasegodmaybe(R_GODNATURE, 1); } // set donesomething even if the actual cooking failed. donesomething = B_TRUE; @@ -1325,7 +1326,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef taketime(user, getactspeed(user)); - if (lfhasflag(target, F_NONCORPOREAL)) { if (isplayer(user)) { msg("You grab at %s%s insubstantial body.", targetname, getpossessive(targetname)); @@ -1423,6 +1423,45 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // now attack them attackcell(user, target->cell, B_TRUE); + } else if (abilid == OT_A_FULLSHIELD) { + object_t *shield[MAXPILEOBS],*selshield = NULL; + int checkmod[MAXPILEOBS]; + int nshields,i; + char shtext[BUFLEN]; + if (isimmobile(user)) { + if (isplayer(user)) msg("You can't do that while stuck!"); + return B_TRUE; + } + if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { + if (isplayer(user)) msg("You can't do that while swimming!"); + return B_TRUE; + } else if (isstuck(user)) { + if (isplayer(user)) msg("You can't do that while stuck!"); + return B_TRUE; + } + + // stop fullshielding. + if (lfhasflag(user, F_FULLSHIELD)) { + killflagsofid(user->flags, F_FULLSHIELD); + taketime(user, getactspeed(user)); + return B_FALSE; + } + + getallshields(user, DT_BASH, shield, checkmod, &nshields); + for (i = 0; i < nshields; i++) { + if (isshield(shield[i])) { + selshield = shield[i]; + break; + } + } + if (!selshield) { + if (isplayer(user)) msg("You need to equip a shield first!"); + return B_TRUE; + } + + sprintf(shtext, "%ld", selshield->id); + addflag(user->flags, F_FULLSHIELD, NA, NA, NA, shtext); + taketime(user, getactspeed(user)); } else if (abilid == OT_A_GRAB) { flag_t *f; @@ -2012,6 +2051,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } else if (abilid == OT_A_SNATCH) { object_t *o = NULL; flag_t *f; + char obname[BUFLEN]; if (!targcell) { int dir; @@ -2046,12 +2086,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) msg("Cancelled."); return B_TRUE; } + getobname(o, obname, 1); // spell doesn't take any time, using an object does. if (fromob) { if (cansee(player, user)) { - char obname[BUFLEN]; - getobname(o, obname, 1); msg("%s%s %s wraps around %s.", username, getpossessive(username), noprefix(fromobname), obname); } @@ -2059,7 +2098,14 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // setting v0 to spellid just in case pickup() changes flags addflag(user->flags, F_NOTIME, OT_A_SNATCH, NA, NA, NULL); } - pickup(user, o, 1, B_TRUE, B_TRUE); + + if (!pickup(user, o, 1, B_TRUE, B_FALSE)) { + if (isplayer(user)) { + msg("You snatch %s from the ground!",obname); + } else if (cansee(player, user)) { + msg("%s snatches %s from the ground!",username, obname); + } + } f = lfhasflagval(user, F_NOTIME, OT_A_SNATCH, NA, NA, NULL); if (f) killflag(f); } else if (abilid == OT_A_SONICBOLT) { @@ -5430,6 +5476,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // target takes magical damage // always hit if (!isimmuneto(target->flags, DT_COLD, B_FALSE)) { + // partially avoidable + if (check_for_block(caster, target, dam, DT_COLD, 999, "the icy air", B_RANGED)) { + dam /= 2; + } losehp(target, dam, DT_COLD, caster, "a chill spell"); } } else if (spellid == OT_S_COLDBURST) { @@ -5455,13 +5505,20 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (targcell->lf) { if (targcell->lf != caster) { char lfname[BUFLEN]; + int dam; // automatic hit getlfname(targcell->lf, lfname); - if (haslos(player, targcell)) { - msg("^%c%s %s chilled!",getlfcol(targcell->lf, CC_BAD), - lfname,is(targcell->lf)); + dam = rolldie(1,8)+3; + // partially avoidable + if (check_for_block(caster, target, dam, DT_COLD, 999, "a burst of coldness", B_RANGED)) { + dam /= 2; + } else { + if (haslos(player, targcell)) { + msg("^%c%s %s chilled!",getlfcol(targcell->lf, CC_BAD), + lfname,is(targcell->lf)); + } } - losehp(targcell->lf, rolldie(1,8)+3, DT_COLD, caster, "a burst of coldness"); + losehp(targcell->lf, dam, DT_COLD, caster, "a burst of coldness"); } } else { // noone there, hit objects. @@ -5497,14 +5554,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { int dam; // hit - if (cansee(player, target)) { - msg("^%cA blast of icy air assails %s.",getlfcol(target, CC_BAD), lfname); - } dam = roll("3d6"); if (power > 1) { // overcast for dragons dam += (power-1); } - losehp(target, roll("3d6"), DT_COLD, caster, "a blast of ice-cold air"); + if (check_for_block(caster, target, dam, DT_COLD, 999, "a blast of icy air", B_RANGED)) { + dam /= 2; + } else { + if (cansee(player, target)) { + msg("^%cA blast of icy air assails %s.",getlfcol(target, CC_BAD), lfname); + } + } + losehp(target, dam, DT_COLD, caster, "a blast of ice-cold air"); // ray stops here. break; } @@ -6052,12 +6113,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ c2 = getcellindir(c, d2); if (c2 && !c2->type->solid && c2->lf) { if (!isimmuneto(c2->lf->flags, DT_PROJECTILE, B_FALSE)) { - if (cansee(player, c2->lf)) { - char lfname[BUFLEN]; - getlfname(c2->lf, lfname); - msg("%s %s showered with debris!", lfname, isplayer(c2->lf) ? "are" : "is"); + int dam; + dam = roll("2d6"); + if (check_for_block(caster, c2->lf, dam, DT_PROJECTILE, 999, "flying debris", B_RANGED)) { + } else { + if (cansee(player, c2->lf)) { + char lfname[BUFLEN]; + getlfname(c2->lf, lfname); + msg("%s %s showered with debris!", lfname, isplayer(c2->lf) ? "are" : "is"); + } + losehp(c2->lf, dam, DT_PROJECTILE, NULL, "flying debris"); } - losehp(c2->lf, rnd(2,6), DT_PROJECTILE, NULL, "flying debris"); } } } @@ -6607,15 +6673,20 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ c = getcellat(targcell->map, x,y); if (c && (getcelldist(targcell, c) <= range)) { if (c->lf && (c->lf != caster) && haslof(targcell, c, B_FALSE, NULL)) { + int dam; + dam = roll("2d6"); // automatic hit - if (isplayer(c->lf)) { - msg("^%cA blast of energy hits you!", getlfcol(c->lf, CC_BAD)); - } else if (cansee(player, c->lf)) { - char lfname[BUFLEN]; - getlfname(c->lf, lfname); - msg("^%cA blast of energy hits %s.", getlfcol(c->lf, CC_BAD), lfname); + if (check_for_block(caster, c->lf, dam, DT_MAGIC, 999, "an energy blast", B_RANGED)) { + } else { + if (isplayer(c->lf)) { + msg("^%cA blast of energy hits you!", getlfcol(c->lf, CC_BAD)); + } else if (cansee(player, c->lf)) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); + msg("^%cA blast of energy hits %s.", getlfcol(c->lf, CC_BAD), lfname); + } + losehp(c->lf, dam, DT_MAGIC, caster, "an energy blast"); } - losehp(c->lf, roll("2d6"), DT_MAGIC, caster, "an energy blast"); } } } @@ -6868,17 +6939,22 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ target = haslf(targcell); if (target) { + int dam; getlfname(target, lfname); // target takes magical damage // ALWAYS hits. - if (cansee(player, target)) { - if (power == 1) { - msg("^%cA bolt of energy hits %s.",getlfcol(target, CC_BAD), lfname); - } else { - msg("^%c%s bolts of energy hit %s.",getlfcol(target, CC_BAD), numbuf, lfname); + dam = rolldie(power*2,4); + if (check_for_block(caster, target, dam, DT_MAGIC, 999, "an energy bolt", B_RANGED)) { + } else { + if (cansee(player, target)) { + if (power == 1) { + msg("^%cA bolt of energy hits %s.",getlfcol(target, CC_BAD), lfname); + } else { + msg("^%c%s bolts of energy hit %s.",getlfcol(target, CC_BAD), numbuf, lfname); + } } } - losehp(target, rolldie(power*2,4), DT_MAGIC, caster, "an energy bolt"); + losehp(target, dam, DT_MAGIC, caster, "an energy bolt"); } } else if ((spellid == OT_S_FIREBALL) || (spellid == OT_S_METEOR)) { int failed = B_FALSE; @@ -6932,11 +7008,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ setobcreatedby(o, caster); } if (c->lf) { + int dam; + char attackname[BUFLEN]; if (spellid == OT_S_FIREBALL) { - losehp(c->lf, rolldie(power,3), DT_FIRE, caster, "a fireball"); + dam = rolldie(power,3); + strcpy(attackname, "a fireball"); } else { - losehp(c->lf, 30+rolldie(power,6), DT_FIRE, caster, "a meterorite"); + dam = 30+rolldie(power,6); + strcpy(attackname, "a meteorite"); } + + if (check_for_block(caster, c->lf, dam, DT_FIRE, 999, attackname, B_RANGED)) { + // partial damage + dam /= 2; + } + losehp(c->lf, dam, DT_FIRE, caster, attackname); } } } @@ -7023,11 +7109,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("A dart of flame misses %s.",lfname); } } else { + int dam; // hit - if (isplayer(target) || cansee(player, target)) { - msg("^%cA dart of flame hits %s.",getlfcol(target, CC_BAD), lfname); + dam = rnd(1,6) + power; + if (check_for_block(caster, target, dam, DT_FIRE, 999, "a dart of flame", B_RANGED)) { + } else { + if (isplayer(target) || cansee(player, target)) { + msg("^%cA dart of flame hits %s.",getlfcol(target, CC_BAD), lfname); + } + losehp(target, dam, DT_FIRE, caster, "a dart of flame"); } - losehp(target, rnd(1,6) + power, DT_FIRE, caster, "a dart of flame"); } } else { damageallobs(NULL, targcell->obpile, 0, DT_FIRE, caster); @@ -7056,13 +7147,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (targcell && (getcelldistorth(caster->cell, targcell) <= range)) { if (targcell->lf && (targcell->lf != caster) && haslof(caster->cell, targcell, B_FALSE, NULL)) { char lfname[BUFLEN]; + int dam; + dam = rolldie(2,6); // automatic hit getlfname(targcell->lf, lfname); - if (haslos(caster, targcell)) { - msg("^%c%s burn%s!",getlfcol(targcell->lf, CC_BAD), - lfname,isplayer(targcell->lf) ? "" : "s"); + if (check_for_block(caster, targcell->lf, dam, DT_FIRE, 999, "a burst of fire", B_RANGED)) { + } else { + if (haslos(caster, targcell)) { + msg("^%c%s burn%s!",getlfcol(targcell->lf, CC_BAD), + lfname,isplayer(targcell->lf) ? "" : "s"); + } + losehp(targcell->lf, dam, DT_FIRE, caster, "a burst of fire"); } - losehp(targcell->lf, rolldie(2,6), DT_FIRE, caster, "a burst of fire"); } damageallobs(NULL, targcell->obpile, rolldie(2,6), DT_FIRE, caster); } @@ -8234,17 +8330,28 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ target = haslf(targcell); if (target) { + int dam; + char attackname[BUFLEN]; getlfname(target, lfname); + dam = rolldie(power, 4); + if (power == 1) { + sprintf(attackname, "a spike of mana"); + } else { + sprintf(attackname, "%s spikes of mana", numbuf); + } // target takes magical damage // always hit - if (cansee(player, target)) { - if (power == 1) { - msg("^%cA spike of mana hits %s.",getlfcol(target, CC_BAD), lfname); - } else { - msg("^%c%s spikes of mana hit %s.",getlfcol(target, CC_BAD), numbuf, lfname); + if (check_for_block(caster, target, dam, DT_FIRE, 999, attackname, B_RANGED)) { + } else { + if (cansee(player, target)) { + if (power == 1) { + msg("^%cA spike of mana hits %s.",getlfcol(target, CC_BAD), lfname); + } else { + msg("^%c%s spikes of mana hit %s.",getlfcol(target, CC_BAD), numbuf, lfname); + } } + losehp(target, dam, DT_MAGIC, caster, "a mana spike"); } - losehp(target, rolldie(power,4), DT_MAGIC, caster, "a mana spike"); } } else if (spellid == OT_S_MAGSHIELD) { object_t *o,*nexto; @@ -9006,9 +9113,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (m) { int ntries = 0; // find random free cell in map - targcell = getrandomcell(m); + //targcell = getrandomcell(m); + targcell = getrandomroomcell(m, ANYROOM, WE_WALKABLE); while (!cellwalkable(target, targcell, NULL) || celldangerous(target, targcell, B_FALSE, NULL)) { - targcell = getrandomcell(m); + //targcell = getrandomcell(m); + targcell = getrandomroomcell(m, ANYROOM, WE_WALKABLE); ntries++; if (ntries >= 5) { fizzle(caster); @@ -9505,7 +9614,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } - dstportal = linkportal(srcportal, newdepth); + dstportal = linkportaltodepth(srcportal, newdepth); setobcreatedby(dstportal, caster); @@ -9791,17 +9900,20 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (power > 1) { dam += power; // maxpower is 1, but blue dragons can exceed this } - losehp(c->lf, dam, DT_ELECTRIC, caster, "a lightning bolt"); - nhits--; - } - if (haslos(player, c)) { - if (fromob) { - char lfname[BUFLEN]; - getlfname(c->lf, lfname); - msg("^%cThe bolt of lightning strikes %s!", getlfcol(c->lf, CC_BAD), lfname); + if (check_for_block(caster, c->lf, dam, DT_ELECTRIC, 999, "a lightning bolt", B_RANGED)) { + } else { + losehp(c->lf, dam, DT_ELECTRIC, caster, "a lightning bolt"); + if (haslos(player, c)) { + if (fromob) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); + msg("^%cThe bolt of lightning strikes %s!", getlfcol(c->lf, CC_BAD), lfname); + } + needredraw = B_TRUE; + if (seenbyplayer) *seenbyplayer = B_TRUE; + } } - needredraw = B_TRUE; - if (seenbyplayer) *seenbyplayer = B_TRUE; + nhits--; } } } else if (spellid == OT_S_LIGHTNINGSTORM) { @@ -9848,15 +9960,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } for (i = 0; i < ntarg; i++) { + int dam; if (cansee(player, targ[i])) { getlfname(targ[i],targname); msg("^%c%s %s struck by a bolt of lightning!",getlfcol(targ[i], CC_BAD), targname, is(targ[i])); } if (caster && (targ[i]->cell->map->habitat->id == H_FOREST)) { - losehp(targ[i], rolldie(4,6), DT_ELECTRIC, caster, "a bolt of lightning"); + dam = rolldie(4,6); } else { - losehp(targ[i], rolldie(3,6), DT_ELECTRIC, caster, "a bolt of lightning"); + dam = rolldie(3,6); + } + + if (check_for_block(caster, targ[i], dam, DT_ELECTRIC, 999, "a bolt of lightning", B_RANGED)) { + } else { + losehp(targ[i], dam, DT_ELECTRIC, caster, "a bolt of lightning"); } } @@ -11208,8 +11326,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ cell_t *c; c = retcell[i]; if (c->lf) { + int dam; + dam = rolldie(nhits, 6); // hit with ice - losehp(c->lf, rolldie(nhits, 6), DT_COLD, caster, "a burst of ice shards"); + if (check_for_block(caster, c->lf, dam, DT_COLD, 999, "a burst of ice shards", B_RANGED)) { + } else { + if (isplayer(c->lf) || cansee(player, c->lf)) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); + msg("^%cA burst of ice shards hits %s.",getlfcol(target, CC_BAD), lfname); + } + losehp(c->lf, dam, DT_COLD, caster, "a burst of ice shards"); + } nhits--; } if (haslos(player, c)) { @@ -11424,7 +11552,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // use direct damage rather than holy, because otherwise it might be increased // due to vulnerabilities - losehp(target, rnd(1,power*2), DT_DIRECT, caster, "a smiting"); + losehp(target, rolldie(1+power,4), DT_DIRECT, caster, "a smiting"); } else if (spellid == OT_S_SNAPFREEZE) { target = haslf(targcell); if (target) { @@ -11469,7 +11597,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // *** // * if (targcell->lf) { - losehp(targcell->lf, 1, DT_COLD, caster, "a snowball"); + if (check_for_block(caster, targcell->lf, 1, DT_COLD, 999, "a snowball", B_RANGED)) { + } else { + losehp(targcell->lf, 1, DT_COLD, caster, "a snowball"); + } } else { addob(targcell->obpile, "small puddle of water"); } @@ -11477,7 +11608,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ c = getcellindir(targcell, dir); if (c && !c->type->solid ) { if (c->lf) { - losehp(c->lf, 1, DT_COLD, caster, "a snowball"); + if (check_for_block(caster, c->lf, 1, DT_COLD, 999, "a burst of snow", B_RANGED)) { + } else { + losehp(c->lf, 1, DT_COLD, caster, "a burst of snow"); + } } else { addob(c->obpile, "small puddle of water"); } @@ -12372,6 +12506,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_TURNUNDEAD) { int i,ndone = 0; lifeform_t *lf; + if (caster && !isplayer(caster) && cansee(player, caster)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s glows brightly with the essense of life!", lfname); + } if (!target) { target = caster; } @@ -12381,15 +12520,31 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ lf = targcell->lf; if (lf && (lf != caster) && isundead(lf)) { int howlong = 10; - int worked = B_TRUE; - // TODO: does it work? depends on caster level & intelligence & power - worked = B_TRUE; - // TODO: how long for? depends on caster level & intelligence & power + int worked = B_FALSE; + if ((gettr(caster)+power)*2 > gettr(lf)) { + worked = B_TRUE; + } else { + int diff; + diff = gettr(lf) - ((gettr(caster)+power)*2); + // if monster level is too high, the chance of working + // is 50%, -10% for every level too high. + if (pctchance(50-diff)) { + worked = B_TRUE; + } + } howlong = rnd(10,20)+(power*2); if (worked) { // don't use scare() since it will fail due to them being undead. addtempflag(lf->flags, F_FLEEFROM, target->id, NA, NA, NULL,howlong); ndone++; + } else { + if (isplayer(lf)) { + msg("You resist the urge to flee from the lifeforce aura."); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s flinches.", lfname); + } } } } @@ -14476,6 +14631,10 @@ int stopallspells(lifeform_t *lf) { if (!stopspell(lf, f->val[0])) nstopped++; } } + + // also stop spelllike abilities + nstopped += killflagsofid(lf->flags, F_FULLSHIELD); + return nstopped; } @@ -14582,7 +14741,20 @@ void spellcloud(cell_t *srcloc, int radius, int dirtype, int ch, enum COLOUR col safe = B_TRUE; } if (aimedateyes && (!hasbp(c->lf, BP_EYES) || getarmour(c->lf, BP_EYES))) { + object_t *arm; safe = B_TRUE; + arm = getarmour(c->lf, BP_EYES); + if (arm) { + char armname[BUFLEN]; + getobname(arm, armname, 1); + if (isplayer(c->lf)) { + msg("Your %s protects your eyes.", noprefix(armname)); + } else if (cansee(player, c->lf)) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); + msg("%s%s %s protects its eyes.", lfname, getpossessive(lfname), noprefix(armname)); + } + } } if (!safe) { if (distfunc(srcloc, c) <= radius) { diff --git a/text.c b/text.c index e7961c0..c1331a2 100644 --- a/text.c +++ b/text.c @@ -610,9 +610,9 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam } else if (dam <= 16) { return "slam"; } else if (dam <= 20) { - return "pummel"; + return "smash"; } else { - return "clobber"; + return "pulverise"; } } } else if (damtype == DT_BITE) { @@ -708,7 +708,7 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam if (dam <= 2) { return "scratch"; } else if (dam <= 6) { - return "hit"; + return "cut"; } else if (dam <= 12) { return "slash"; } else { @@ -1324,14 +1324,11 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d if (canbehead) { if (victim && (victim->race->id == R_EARTHWYRM)) { return "bisect"; - } else if (!hasbp(victim, BP_HEAD)) { - return "bisect"; + } else if (hasbp(victim, BP_HEAD) && (getlfsize(victim) >= SZ_MEDIUM) && onein(3)) { + return "behead"; } else { - if ((getlfsize(victim) >= SZ_MEDIUM) && onein(3)) { - return "behead"; - } else { - return "bisect"; - } + if (onein(2) && (getraceclass(victim) == RC_HUMANOID)) return "dismember"; + else return "bisect"; } } } @@ -2122,7 +2119,7 @@ char *makekillertext(char *retbuf, char *killverb, char *lastdam, map_t *where, p = strtok_r(lastdam,"^", &dummy); if (p) { - if (!strcmp(p, "you")) { + if (streq(p, "you")) { strcpy(retbuf, "Committed suicide"); } else { snprintf(retbuf, BUFLEN, "%s %s %s",killverb,