- [+] outdoor bug: at -1,-1. travel south. end up at 0,0!!!

- [+] blink should go to random place within lof, not los
- [+] sunglasses shuld reduce nightvis range, not visrange
* [+] since jolt needs adjacency, make it more powerful
- [+] use colours for spell descriptions
- [+] replace 'call wind' with 'zephyr'
* [+] add vault commonality.
- [+] add more common vaults - roundabout etc
* [+] change "addmonster" to take a string arg instrad of RACEID
- [+] pouring cursed water on blessed scroll didn't work.....
- [+] append "...god of xxx" to rc_god lifeforms
- [+] try to attack with f_pain -> INFINITE LOOP.
- [+] ARMOURPIERCE shouldn't hurt armour
- [+] ghast touchparalyze attack isn't working.
* [+] bug: when praying to gods, ones not in heaven aren't listed.
- [+] when a god apepars..."Hecta appears" x2
- [+] attacking fleeing lf should count as a backstab (if you have the
      skill)
* [+] "nothing happens" during god spell effects
* [+] allow hunger to work on monsters
- [+] pressing 'a' on @Magic has weird results.
- [+] bug: got a gift form yumi during combat???? what for? healing?
initial vampire implementation
initial god implementation
- [+] they all start off in "heaven" map.
- [+] gods ahve f_piety. starts at 0
- [+] keep track of piety with each god. starts at 0 for each one.
* [+] let planeshift take you to heaven (for debugging)
* [+] everyone has 'pray' ability.
- [+] modpiety(rid, amt)
* [+] piety vals
* [+] when you pray
- [+] isangry(god) - ie is piety < 0
* [+] if you pray when god is angry, bad!
* [+] once piety gets over 200 or so, praying  might give you a gift. 
* [+] god_appears(lifeform_t *victim)
- [+] if >=0 (indiff / pleased), goes up to indiff over time(1 per
      turn).
- [+] regain through doing actions ... in progress
- [+] lose through doing actions only if you have prayed to this god
      before (angergodmaybe)
- [+] special: gods don't need LOS to cast spells.
- [+] gods planeshift away if not doing anything else.
* [+] @g to see your piety levels for each god
- [+] ?g for help on gods
- [+] IN general:
    - [+] prey = oneoff effect
    - [+] gift = ongoing
    * [+] makeangry() vs modpiety
* [+] Yumi - fem,mercy/healing - if you die within the first few turns!
Hecta - partial
Avamon - partial
This commit is contained in:
Rob Pearce 2011-08-03 18:43:05 +00:00
parent 94ed133ace
commit 81c7f37eff
41 changed files with 1884 additions and 356 deletions

View File

@ -1,2 +1,2 @@
nexus: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h flag.c flag.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h spell.c spell.h vault.c vault.h nexus: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h flag.c flag.h god.c god.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h spell.c spell.h vault.c vault.h
gcc -Wall -g -pg -o nexus nexus.c ai.c attack.c flag.c io.c lf.c map.c move.c objects.c text.c save.c spell.c vault.c vault.h -lncurses -lsqlite3 gcc -Wall -g -pg -o nexus nexus.c ai.c attack.c flag.c god.c io.c lf.c map.c move.c objects.c text.c save.c spell.c vault.c vault.h -lncurses -lsqlite3

54
ai.c
View File

@ -5,6 +5,7 @@
#include "attack.h" #include "attack.h"
#include "defs.h" #include "defs.h"
#include "flag.h" #include "flag.h"
#include "god.h"
#include "io.h" #include "io.h"
#include "lf.h" #include "lf.h"
#include "map.h" #include "map.h"
@ -28,6 +29,7 @@ void addignorecell(lifeform_t *lf, cell_t *c) {
// returns true on failure // returns true on failure
int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
int db = B_FALSE; int db = B_FALSE;
int innocentattack = 0;
flag_t *f; flag_t *f;
if (lfhasflag(lf, F_DEBUG)) { if (lfhasflag(lf, F_DEBUG)) {
@ -85,18 +87,24 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
// become hostile? // become hostile?
if (!hasflag(lf->flags, F_HOSTILE)) { if (!hasflag(lf->flags, F_HOSTILE)) {
addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
innocentattack = 1;
} }
// change allegience ? // change allegience ?
if (!areenemies(lf, victim)) { if (!areenemies(lf, victim)) {
if (getallegiance(victim) == AL_FRIENDLY) { if (getallegiance(victim) == AL_FRIENDLY) {
killflagsofid(lf->flags, F_FRIENDLY); killflagsofid(lf->flags, F_FRIENDLY);
innocentattack = 3;
} }
} }
// no longer a pet // no longer a pet
f = lfhasflagval(lf, F_PETOF, victim->id, NA, NA, NULL); f = lfhasflagval(lf, F_PETOF, victim->id, NA, NA, NULL);
if (f) killflag(f); if (f) {
innocentattack = 3;
killflag(f);
}
return B_FALSE; return B_FALSE;
} }
@ -817,6 +825,10 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
} }
int aipickup(lifeform_t *lf, object_t *o) { int aipickup(lifeform_t *lf, object_t *o) {
// special case
if ((o->type->id == OT_COFFIN) && (lf->race->id == R_GASCLOUD) && lfhasflagval(lf, F_ORIGRACE, R_VAMPIRE, NA, NA, NULL)) {
return rest(lf, B_TRUE);
}
if (isedible(o)) { if (isedible(o)) {
return eat(lf, o); return eat(lf, o);
} else { } else {
@ -829,6 +841,11 @@ int aipickup(lifeform_t *lf, object_t *o) {
int aipickupok(lifeform_t *lf, object_t *o) { int aipickupok(lifeform_t *lf, object_t *o) {
int ok = B_FALSE; int ok = B_FALSE;
// special case
if ((o->type->id == OT_COFFIN) && (lf->race->id == R_GASCLOUD) && lfhasflagval(lf, F_ORIGRACE, R_VAMPIRE, NA, NA, NULL)) {
return B_TRUE;
}
if (hasflag(o->flags, F_SHOPITEM)) { if (hasflag(o->flags, F_SHOPITEM)) {
return B_FALSE; return B_FALSE;
} }
@ -899,14 +916,12 @@ void aiturn(lifeform_t *lf) {
dblog("AIMOVE: %s", lfname); dblog("AIMOVE: %s", lfname);
} }
/*
// if lifeform isn't alive, skip turn // if lifeform isn't alive, skip turn
if (isdead(lf)) { if (isdead(lf)) {
if (db) dblog(".oO { i am not alive, skipping turn. }"); if (db) dblog(".oO { i am not alive, skipping turn. }");
taketime(lf, SPEED_DEAD); taketime(lf, SPEED_DEAD);
return; return;
} }
*/
/////////////////////////////////////////// ///////////////////////////////////////////
// info gathering // info gathering
@ -1035,6 +1050,15 @@ void aiturn(lifeform_t *lf) {
return; return;
} }
// hurt gods planeshift away
if (lf->race->raceclass->id == RC_GOD) {
if (gethppct(lf) <= 10) {
if (!castspell(lf, OT_S_PLANESHIFT, lf, NULL, lf->cell)) {
return;
}
}
}
// need to heal? // need to heal?
if (lf->hp < (lf->maxhp/2)) { if (lf->hp < (lf->maxhp/2)) {
if (!useitemwithflag(lf, F_AIHEALITEM)) { if (!useitemwithflag(lf, F_AIHEALITEM)) {
@ -1289,8 +1313,7 @@ void aiturn(lifeform_t *lf) {
return; return;
} }
} }
} }
// look for any race which we hate // look for any race which we hate
newtarget = NULL; newtarget = NULL;
@ -1335,6 +1358,16 @@ void aiturn(lifeform_t *lf) {
if (db) dblog(".oO { won't move towards target - i have no weapon. }"); if (db) dblog(".oO { won't move towards target - i have no weapon. }");
} }
} }
} else {
// god with no targets?
if (lf->race->raceclass->id == RC_GOD) {
if (onein(6)) {
// gods will planeshift away
if (!castspell(lf, OT_S_PLANESHIFT, lf, NULL, lf->cell)) {
return;
}
}
}
} }
/////////////////////////////////////////////// ///////////////////////////////////////////////
@ -1590,6 +1623,9 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) { if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) {
specificcheckok = B_FALSE; specificcheckok = B_FALSE;
} }
if ((ot->id == OT_S_DISPERSAL) && (lf->race->raceclass->id == RC_GOD)) {
specificcheckok = B_FALSE;
}
if ((ot->id == OT_S_DRAINLIFE) && isimmuneto(victim->flags, DT_NECROTIC)) { if ((ot->id == OT_S_DRAINLIFE) && isimmuneto(victim->flags, DT_NECROTIC)) {
specificcheckok = B_FALSE; specificcheckok = B_FALSE;
} }
@ -1789,6 +1825,14 @@ int lookforobs(lifeform_t *lf) {
} }
} }
if (hasflag(lf->flags, F_HUNGER)) {
// monsters dont normaly need to eat. if they have hunger, it's due
// to a spell.
wantflag[nwantflags] = F_EDIBLE;
wantflagcovet[nwantflags] = B_TRUE;
nwantflags++;
}
// current cell has an object we want? // current cell has an object we want?
o = hasobmulti(lf->cell->obpile, oid, noids); o = hasobmulti(lf->cell->obpile, oid, noids);
if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o)) { if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o)) {

View File

@ -6,6 +6,7 @@
#include "attack.h" #include "attack.h"
#include "defs.h" #include "defs.h"
#include "flag.h" #include "flag.h"
#include "god.h"
#include "io.h" #include "io.h"
#include "lf.h" #include "lf.h"
#include "map.h" #include "map.h"
@ -24,6 +25,9 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty
int damtaken = 0; int damtaken = 0;
// figure out what bit of armour was hit // figure out what bit of armour was hit
if (dam == 0) {
return 0;
}
// special case - missiles always hit flak jacket // special case - missiles always hit flak jacket
if (damtype == DT_PROJECTILE) { if (damtype == DT_PROJECTILE) {
@ -56,7 +60,6 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty
// adjust how much damage to do to armour // adjust how much damage to do to armour
if ( ((armour->type->id == OT_FLAKJACKET) && (damtype == DT_PROJECTILE)) || if ( ((armour->type->id == OT_FLAKJACKET) && (damtype == DT_PROJECTILE)) ||
(damtype == DT_ACID) || (damtype == DT_ACID) ||
hasflag(wep->flags, F_ARMOURPIERCE) ||
rust ) { rust ) {
// ALL of damage reduction goes towards armour // ALL of damage reduction goes towards armour
} else { } else {
@ -353,10 +356,18 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
(getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= A_LOW) ) { (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= A_LOW) ) {
saysorry = B_TRUE; saysorry = B_TRUE;
} }
if (attacklf(lf, victim, wep[i], damflag[i])) break; if (attacklf(lf, victim, wep[i], damflag[i])) {
// failed
attacksdone = maxattacks;
break;
}
} }
} else if (attacktype == AT_OB) { } else if (attacktype == AT_OB) {
if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) break; if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) {
// failed
attacksdone = maxattacks;
break;
}
} }
attacksdone++; attacksdone++;
@ -399,6 +410,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
int deflected = B_FALSE; int deflected = B_FALSE;
int weppassthrough = B_FALSE; int weppassthrough = B_FALSE;
int firstisbackstab = B_FALSE; int firstisbackstab = B_FALSE;
int attackedhelpless = B_FALSE;
int attackedfriend = B_FALSE;
int hit = B_FALSE; int hit = B_FALSE;
int critical = 0; int critical = 0;
char wepname[BUFLEN]; char wepname[BUFLEN];
@ -573,14 +586,25 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// backstab? // backstab?
if ((damtype[0] == DT_PIERCE) && // using a stabbing weapon if ((damtype[0] == DT_PIERCE) && // using a stabbing weapon
getskill(lf, SK_BACKSTAB) && // able to backstab getskill(lf, SK_BACKSTAB)) { // able to backstab
!cansee(victim, lf) && // victim can't see us if (!lfhasflagval(victim, F_STABBEDBY, lf->id, NA, NA, NULL) && // haven't stabbed them before
!lfhasflagval(victim, F_STABBEDBY, lf->id, NA, NA, NULL) && // haven't stabbed them before !lfhasflagval(victim, F_TARGETLF, lf->id, NA, NA, NULL)) { // victim isnt attacking us
!lfhasflagval(victim, F_TARGETLF, lf->id, NA, NA, NULL) // victim isnt attacking us
) { if (!cansee(victim, lf) || // victim can't see us
addflag(victim->flags, F_STABBEDBY, lf->id, NA, NA, NULL); isfleeing(victim)) {
dam[0] *= (getskill(lf, SK_BACKSTAB)); addflag(victim->flags, F_STABBEDBY, lf->id, NA, NA, NULL);
firstisbackstab = B_TRUE; dam[0] *= (getskill(lf, SK_BACKSTAB));
firstisbackstab = B_TRUE;
attackedhelpless = B_TRUE;
}
}
}
if (!cansee(victim, lf)) {
attackedhelpless = B_TRUE;
}
if (areallies(lf, victim)) {
attackedfriend = B_TRUE;
} }
// extra damage for being skilled? // extra damage for being skilled?
if (wepsk) { if (wepsk) {
@ -767,9 +791,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} }
strcpy(attackverb, getattackverb(lf, wep, damtype[i],dam[i],victim->maxhp)); strcpy(attackverb, getattackverb(lf, wep, damtype[i],dam[i],victim->maxhp));
if (strstr(attackverb, "hit")) {
dblog("xxx");
}
if ((dam[i] == 0) && (damtype[i] != DT_TOUCH)) { if ((dam[i] == 0) && (damtype[i] != DT_TOUCH)) {
nodam = B_TRUE; nodam = B_TRUE;
strcpy(nodamstr, " but does no damage"); strcpy(nodamstr, " but does no damage");
@ -805,6 +826,16 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} else { } else {
char attackername2[BUFLEN]; char attackername2[BUFLEN];
real_getlfname(lf, attackername2, B_FALSE); real_getlfname(lf, attackername2, B_FALSE);
if (lf->race->raceclass->id == RC_GOD) {
flag_t *gf;
gf = lfhasflag(lf, F_GODOF);
if (gf->val[0] == B_FEMALE) {
strcat(attackername2, " the Goddess of ");
} else {
strcat(attackername2, " the God of ");
}
strcat(attackername2, gf->text);
}
// victim loses hp // victim loses hp
// don't adjust damage - we've already done that // don't adjust damage - we've already done that
if (wep && !isunarmed) { if (wep && !isunarmed) {
@ -1045,6 +1076,18 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} }
} }
if (isplayer(lf)) {
if (attackedfriend) {
angergodmaybe(R_GODMERCY, 100);
} else if (attackedhelpless) {
angergodmaybe(R_GODMERCY, 50);
} else if (lfhasflag(lf, F_USEDPOISON)) {
killflagsofid(lf->flags, F_USEDPOISON);
angergodmaybe(R_GODMERCY, 50);
}
}
if (aidb) dblog(".oO { doattack about to return B_FALSE }"); if (aidb) dblog(".oO { doattack about to return B_FALSE }");
return B_FALSE; return B_FALSE;
} }
@ -1206,6 +1249,10 @@ int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE d
//int pctrange; //int pctrange;
object_t *o; object_t *o;
if (hasflag(wep->flags, F_ARMOURPIERCE)) {
reduceamt = 0;
}
ar = getarmourrating(lf, NULL, NULL, NULL); ar = getarmourrating(lf, NULL, NULL, NULL);
// between 25% and 75% of AR. // between 25% and 75% of AR.
@ -2105,6 +2152,9 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
// was this from a poisoned weapon? if so the poison vanishes // was this from a poisoned weapon? if so the poison vanishes
if ((f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) { if ((f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) {
killflag(f); killflag(f);
if (owner && isplayer(owner)) {
addflag(owner->flags, F_USEDPOISON, B_TRUE, NA, NA, NULL);
}
} }
} }
} // end if (fid == hitconfer) } // end if (fid == hitconfer)

Binary file not shown.

50
defs.h
View File

@ -268,6 +268,7 @@ enum SENSE {
#define FROMBRAND (-7865) #define FROMBRAND (-7865)
#define FROMOBMOD (-7864) #define FROMOBMOD (-7864)
#define FROMSKILL (-7863) #define FROMSKILL (-7863)
#define FROMGODGIFT (-7862)
#define FROMEXTERNAL_LOW (-7999) #define FROMEXTERNAL_LOW (-7999)
@ -660,8 +661,11 @@ enum RACECLASS {
RC_UNDEAD, RC_UNDEAD,
}; };
#define MAXGODS 3
enum RACE { enum RACE {
R_NONE, R_RANDOM, R_NONE = 0,
R_RANDOM, R_SPECIFIED,
// unique monstesr // unique monstesr
R_JAILER, R_JAILER,
// human monsters // human monsters
@ -673,7 +677,9 @@ enum RACE {
R_PRISONER, R_PRISONER,
R_TOWNGUARD, R_TOWNGUARD,
// gods // gods
R_GODDEATH,
R_GODGREED, R_GODGREED,
R_GODMERCY,
// monsters // monsters
R_BEHOLDER, R_BEHOLDER,
R_BUGBEAR, R_BUGBEAR,
@ -712,6 +718,7 @@ enum RACE {
R_SPRITEFIRE, R_SPRITEFIRE,
R_TROGLODYTE, R_TROGLODYTE,
R_TROLL, R_TROLL,
R_VAMPIRE,
R_XAT, R_XAT,
// fish // fish
R_CRAB, R_CRAB,
@ -1082,6 +1089,7 @@ enum OBTYPE {
OT_S_QUENCH, OT_S_QUENCH,
OT_S_LESSENPOISON, OT_S_LESSENPOISON,
OT_S_REPELINSECTS, OT_S_REPELINSECTS,
OT_S_SATEHUNGER,
OT_S_SLEETSTORM, OT_S_SLEETSTORM,
OT_S_SOFTENEARTH, OT_S_SOFTENEARTH,
OT_S_STICKTOSNAKE, OT_S_STICKTOSNAKE,
@ -1132,6 +1140,7 @@ enum OBTYPE {
OT_A_CHARGE, OT_A_CHARGE,
OT_A_CRUSH, OT_A_CRUSH,
OT_A_JUMP, OT_A_JUMP,
OT_A_PRAY,
OT_A_RAGE, OT_A_RAGE,
OT_A_REPAIR, OT_A_REPAIR,
OT_A_SPRINT, OT_A_SPRINT,
@ -1210,6 +1219,7 @@ enum OBTYPE {
OT_XRAYGOGGLES, OT_XRAYGOGGLES,
// furniture // furniture
OT_CANDELABRUM, OT_CANDELABRUM,
OT_COFFIN,
OT_FIREPLACE, OT_FIREPLACE,
OT_WEAPONRACK, OT_WEAPONRACK,
OT_WOODENTABLE, OT_WOODENTABLE,
@ -1534,6 +1544,7 @@ enum FLAG {
F_ONEPERCELL, // only one of these objects can exist per cell F_ONEPERCELL, // only one of these objects can exist per cell
F_CREATEDBY, // object was made by lf id v0, text=real lfname F_CREATEDBY, // object was made by lf id v0, text=real lfname
F_ENCHANTABLE, // object can get +1/-1 ect F_ENCHANTABLE, // object can get +1/-1 ect
F_GODGIFT, // this was a gift form god with race v0.
F_NOSHATTER, // object will not shatter, even if it's material should. F_NOSHATTER, // object will not shatter, even if it's material should.
F_STACKABLE, // can stack multiple objects togethr F_STACKABLE, // can stack multiple objects togethr
F_NO_PLURAL, // this obname doesn't need an 's' for plurals (eg. gold, money) F_NO_PLURAL, // this obname doesn't need an 's' for plurals (eg. gold, money)
@ -1842,6 +1853,8 @@ enum FLAG {
F_DONEDARKMSG, // tells the game not to say 'it is very dark here' F_DONEDARKMSG, // tells the game not to say 'it is very dark here'
F_DONELISTEN, // supress further 'you hear xx' messages this turn. F_DONELISTEN, // supress further 'you hear xx' messages this turn.
// lifeform flags / lf flags // lifeform flags / lf flags
F_PIETY, // for god lifeforms - tracks player's piety with them
F_PRAYEDTO, // player has prayed to this god before.
F_COUNTER, // generic counter flag for race abilities. F_COUNTER, // generic counter flag for race abilities.
F_DEBUG, // debugging enabled F_DEBUG, // debugging enabled
F_ACCURACYMOD, // modify your accuracy by val0 F_ACCURACYMOD, // modify your accuracy by val0
@ -1859,6 +1872,7 @@ enum FLAG {
F_ATTRMOD, // modify attribute val0 by val1. ie. 0=A_STR,1=-3 F_ATTRMOD, // modify attribute val0 by val1. ie. 0=A_STR,1=-3
F_ATTRSET, // forces attribute val0 to be val1. ie. 0=A_STR,1=18 F_ATTRSET, // forces attribute val0 to be val1. ie. 0=A_STR,1=18
F_SIZE, // val0 = lf size (enum LFSIZE) F_SIZE, // val0 = lf size (enum LFSIZE)
F_USEDPOISON, // this lf used a poisoned weapon to attack
F_RANDOMTALKPCT, // v0 = chance of randomly saying something each turn F_RANDOMTALKPCT, // v0 = chance of randomly saying something each turn
F_RANDOMTALK, // v0 = sp_xxx for what to say when we randomly talk. F_RANDOMTALK, // v0 = sp_xxx for what to say when we randomly talk.
// v1/v2 are min/max volume // v1/v2 are min/max volume
@ -1909,6 +1923,7 @@ enum FLAG {
F_LFSUFFIX, // text = suffix. eg. "skeleton" F_LFSUFFIX, // text = suffix. eg. "skeleton"
F_VISRANGE, // how far you can see (in the light) F_VISRANGE, // how far you can see (in the light)
F_VISRANGEMOD, // modifications to visrange F_VISRANGEMOD, // modifications to visrange
F_NIGHTVISRANGEMOD, // modifications to nightvisrange
F_GUNTARGET, // current projectile weapon target F_GUNTARGET, // current projectile weapon target
F_CASTINGSPELL, // set while the player is casting a spell F_CASTINGSPELL, // set while the player is casting a spell
// for instant spells: // for instant spells:
@ -1959,6 +1974,8 @@ enum FLAG {
F_PETOF, // this lf is a pet of lfid v0 F_PETOF, // this lf is a pet of lfid v0
// v1/2 = last known location of my owner. // v1/2 = last known location of my owner.
// optional text is last known movement dir. // optional text is last known movement dir.
// note: can also go on corpse objects to show that this
// is the corpse of a pet.
F_SUMMONEDBY, // this lf was summoned by lfid v0. if they die, we F_SUMMONEDBY, // this lf was summoned by lfid v0. if they die, we
// vanish. // vanish.
// v1 is lifetime left. this decrements each turn. // v1 is lifetime left. this decrements each turn.
@ -2020,6 +2037,9 @@ enum FLAG {
F_MPDICE, // val0: # d4 to roll for maxmp per level. val1: +xx F_MPDICE, // val0: # d4 to roll for maxmp per level. val1: +xx
F_JOB, // val0 = player's class/job F_JOB, // val0 = player's class/job
F_GODOF, // text = what this lf is the god of. use capitals. F_GODOF, // text = what this lf is the god of. use capitals.
// if v0 is b_true, means this is a goddess
F_GODLIKES, // text = something this god likes (ie. incs piety)
F_GODDISLIKES, // text = something this god likes (ie. decs piety)
F_NAME, // text = lf's name F_NAME, // text = lf's name
F_XPMOD, // add/subtract this much from calculated xpval F_XPMOD, // add/subtract this much from calculated xpval
F_BLOODOB, // text = type of object to drop for blood F_BLOODOB, // text = type of object to drop for blood
@ -2243,6 +2263,7 @@ enum FLAG {
F_VAULTISSHOP, // this vault is a shop, so add f_shopitem to objects F_VAULTISSHOP, // this vault is a shop, so add f_shopitem to objects
// here. // here.
F_VAULTISSHRINE, // this vault is a godstone shrine F_VAULTISSHRINE, // this vault is a godstone shrine
F_VAULTRARITY, // v0=rr_xxx
F_VAULTSCATTER, // v0=thingtype, v1=pctchance F_VAULTSCATTER, // v0=thingtype, v1=pctchance
// text=x1,y1,x2,y2,mincount-maxcount,thingname // text=x1,y1,x2,y2,mincount-maxcount,thingname
// if maxcount is PCT, mincount is a percentage // if maxcount is PCT, mincount is a percentage
@ -2276,6 +2297,21 @@ enum HUNGER {
H_STARVED = 5 H_STARVED = 5
}; };
#define PIETYPRAYLOSS 75
#define PIETY_MIN -200
#define PIETY_MAX 400
enum PIETYLEV {
PL_ENRAGED = -4,
PL_FURIOUS = -3,
PL_ANGRY = -2,
PL_TOLERATED = -1,
PL_INDIFFERENT = 0,
PL_PLEASED = 1,
PL_DELIGHTED = 2,
PL_ECSTATIC = 3,
};
// probabilities // probabilities
//#define CH_DEADENDOB 35 //#define CH_DEADENDOB 35
//#define CH_EMPTYCELLOB 3 //#define CH_EMPTYCELLOB 3
@ -2286,6 +2322,9 @@ enum HUNGER {
#define B_FALSE (0) #define B_FALSE (0)
#define B_TRUE (-1) #define B_TRUE (-1)
#define B_MALE (0)
#define B_FEMALE (-1)
#define B_MAYCHASE (-1) #define B_MAYCHASE (-1)
#define B_NODOORS (0) #define B_NODOORS (0)
@ -2487,14 +2526,16 @@ typedef struct command_s {
enum REGIONTYPE { enum REGIONTYPE {
RG_WORLDMAP, RG_WORLDMAP,
RG_FIRSTDUNGEON, RG_FIRSTDUNGEON,
RG_HEAVEN,
RG_PIT, RG_PIT,
}; };
enum HABITAT { enum HABITAT {
H_DUNGEON = 1, H_DUNGEON = 1,
H_FOREST = 2, H_FOREST = 2,
H_PIT = 3, H_HEAVEN = 3,
H_VILLAGE = 4, H_PIT = 4,
H_VILLAGE = 5,
H_ALL = 999 H_ALL = 999
}; };
@ -2534,6 +2575,7 @@ typedef struct regionoutline_s {
struct regionoutline_s *next, *prev; struct regionoutline_s *next, *prev;
} regionoutline_t; } regionoutline_t;
// a region is a link of a regiontype and an outline
typedef struct region_s { typedef struct region_s {
int id; int id;
regiontype_t *rtype; regiontype_t *rtype;
@ -2781,6 +2823,8 @@ typedef struct flag_s {
int chance; int chance;
long obfrom; // for conferred flags, link to object->id. -1 if not conferred. long obfrom; // for conferred flags, link to object->id. -1 if not conferred.
// also used for godgifts, in which case it is thr race->id of
// the god who gifted you this flag.
// //
int known; int known;

13
doc/add_god Normal file
View File

@ -0,0 +1,13 @@
In defs.h
Add R_GODxxxx
update MAXGODS
In lf.c
addrace() for the new god
include f_godlikes/f_goddislikes
In god.c:
prayto() - add help effects.
prayto() - add gift effects.
angergod() - add angry effects (minor).
angergod() - add angry effects (major).

View File

@ -33,6 +33,7 @@ h = humanoid
H = large humanoid H = large humanoid
U = unearthly/demonic/horrific creature U = unearthly/demonic/horrific creature
w = worm w = worm
V = vampire
z = lizard-like creature z = lizard-like creature
Z = undead Z = undead

View File

@ -18,7 +18,7 @@ General format:
Legend is: Legend is:
c:type:what[:pct] c:type:what[:pct]
OR OR
c:exit c:exit (denotes an exit, for use by linkexits)
c = any letter c = any letter
@ -64,6 +64,15 @@ Flags can be:
mayrotate // vault can be rotated randomly mayrotate // vault can be rotated randomly
rarity:xxx // how common this vault is.
// xxx can be:
// common (default)
// uncommon
// rare
// vrare / veryrare
// never
norandom // this vault doesn't appear randomly. it will only norandom // this vault doesn't appear randomly. it will only
// appear when specifically requested via a region's // appear when specifically requested via a region's
// outline. // outline.

611
god.c Normal file
View File

@ -0,0 +1,611 @@
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ai.h"
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
#include "move.h"
#include "nexus.h"
#include "objects.h"
#include "spell.h"
#include "text.h"
extern map_t *firstmap;
extern map_t *heaven;
extern race_t *firstrace, *lastrace;
extern raceclass_t *firstraceclass, *lastraceclass;
extern job_t *firstjob, *lastjob;
extern skill_t *firstskill, *lastskill;
extern objecttype_t *objecttype;
extern lifeform_t *player;
lifeform_t *godlf[MAXGODS];
int ngodlfs = 0;
void angergod(enum RACE rid, int amt) {
lifeform_t *god;
char lfname[BUFLEN];
int piety;
god = findgod(rid);
real_getlfname(god, lfname, B_FALSE);
modpiety(rid, -amt);
piety = getpiety(rid);
// if you have never prayed to this god before, finish now.
if (!lfhasflag(god, F_PIETY)) {
return;
}
// if you HAVE prayed to this god before, something bad will probably happen.
// announce
if (piety > 0) { // not angry yet.
godsay(rid, "You are testing my patience, mortal!");
} else if (piety > -100) { // minor bad stuff
godsay(rid, "You have angered me, mortal!");
} else if (piety > -200) { // major bad stuff
godsay(rid, "You go too far, mortal!");
} else { // god will attack
godsay(rid, "You will regret that!");
}
// bad stuff
if (piety <= 0) {
void *poss[MAXCANDIDATES];
object_t *o;
flag_t *f;
int isflag[MAXCANDIDATES];
int nposs = 0;
enum ATTRIB a;
// lose at least one god gift
for (o = player->pack->first ; o ; o = o->next) {
if (hasflagval(o->flags, F_GODGIFT, rid, NA, NA, NULL)) {
poss[nposs] = o;
isflag[nposs] = B_FALSE;
nposs++;
}
}
for (f = player->flags->first ; f ; f = f->next) {
if ((f->lifetime == FROMGODGIFT) && (f->obfrom == god->race->id)) {
poss[nposs] = f;
isflag[nposs] = B_TRUE;
nposs++;
}
}
if (nposs) {
int sel;
msg("\"You are unworthy of my gifts, mortal!\"");
sel = rnd(0,nposs-1);
if (isflag[sel]) {
killflag((flag_t *)poss[sel]);
} else {
obdie((object_t *)poss[sel]);
}
}
// then...
if (piety > -100) {
// minor bad stuff
switch (rid) {
case R_GODDEATH:
castspell(god, OT_S_DRAINLIFE, player, NULL, player->cell);
castspell(god, OT_S_PAIN, player, NULL, player->cell);
break;
case R_GODGREED:
// take a random object
msg("\"Yoink!\"");
castspell(god, OT_S_CONFISCATE, player, NULL, player->cell);
break;
case R_GODMERCY:
// lower one attribute
msg("\"Be glad that I am feeling merciful, mortal!\"");
a = rnd(0,MAXATTS-1);
modattr(player, a, -1);
break;
default:
break;
}
} else if (piety > -200) {
object_t *o;
// major bad stuff
switch (god->race->id) {
case R_GODDEATH:
castspell(god, OT_S_PAIN, player, NULL, player->cell);
castspell(god, OT_S_DRAINLIFE, player, NULL, player->cell);
switch (rnd(1,2)) {
case 1:
msg("\"This will teach you some humility, mortal!\"");
if (getattr(player, A_IQ) > getattr(player, A_STR)) {
castspell(god, OT_S_FEEBLEMIND, player, NULL, player->cell);
} else {
castspell(god, OT_S_WEAKEN, player, NULL, player->cell);
}
break;
case 2:
// summon undead
msg("\"Destroy him, my pets!\"");
summonlfs(god, player->cell, RC_UNDEAD, SZ_ANY, 3, PERMENANT);
break;
}
break;
case R_GODGREED:
o = getweapon(player);
msg("\"Allow me to lighten your load a little...\"");
if (o) { // take player's weapon
castspell(god, OT_S_CONFISCATE, player, o, player->cell);
} else { // take 3 objects
int i;
for (i = 0; i < 3; i++) {
castspell(god, OT_S_CONFISCATE, player, NULL, player->cell);
}
}
break;
case R_GODMERCY:
msg("\"Even my mercy has its limits!\"");
// age
age(player, 15);
// lower every attribute by one
for (a = 0; a < MAXATTS; a++) {
modattr(player, a, -1);
}
break;
default:
break;
}
} else {
// god attacks!
godappears(god->race->id, NULL);
aiattack(god, player, PERMENANT);
}
}
}
// anger the god if you are worshippin them.
void angergodmaybe(enum RACE rid, int amt) {
lifeform_t *god;
god = findgod(rid);
if (lfhasflag(god, F_PRAYEDTO)) {
angergod(rid, amt);
}
}
lifeform_t *findgod(enum RACE rid) {
lifeform_t *lf;
// search heaven first
for (lf = heaven->lf ; lf ; lf = lf->next) {
if (lf->race->id == rid) return lf;
}
// now search other maps
lf = findlfunique(rid);
return lf;
}
int getpiety(enum RACE rid) {
lifeform_t *god;
flag_t *f;
god = findgod(rid);
f = lfhasflag(god, F_PIETY);
if (f) {
return f->val[0];
} else {
// ie. haven't prayed to them before.
return 100;
}
return 0;
}
enum PIETYLEV getpietylev(enum RACE rid, enum COLOUR *col, char *happiness) {
int piety;
/// figure out piety bracket
// min = -200
// max = 400
// range = 600
piety = getpiety(rid);
if (piety <= -200) { // -200 - -100
if (col) *col = C_ORANGE;
if (happiness) strcpy(happiness, "Enraged");
return PL_ENRAGED;
} else if (piety <= -100) { // -199 - -100
if (col) *col = C_RED;
if (happiness) strcpy(happiness, "Furious");
return PL_FURIOUS;
} else if (piety < 0) { // -99 - 0
if (col) *col = C_YELLOW;
if (happiness) strcpy(happiness, "Angry");
return PL_ANGRY;
} else if (piety <= 99) { // 0 - 99
if (col) *col = C_BROWN;
if (happiness) strcpy(happiness, "Tolerated");
return PL_TOLERATED;
} else if (piety <= 199) { // 100 - 199
if (col) *col = C_GREY;
if (happiness) strcpy(happiness, "Indifferent");
return PL_INDIFFERENT;
} else if (piety <= 299) { // 200 - 299
if (col) *col = C_GREEN;
if (happiness) strcpy(happiness, "Pleased");
return PL_PLEASED;
} else if (piety <= 399) { // 300 - 399
if (col) *col = C_BOLDGREEN;
if (happiness) strcpy(happiness, "Delighted");
return PL_DELIGHTED;
} else { // 400+
if (col) *col = C_BOLDCYAN;
if (happiness) strcpy(happiness, "Ecstatic");
return PL_ECSTATIC;
}
return PL_INDIFFERENT;
}
lifeform_t *godappears(enum RACE rid, cell_t *where) {
lifeform_t *god;
char killedname[BUFLEN],godname[BUFLEN];
god = findgod(rid);
real_getlfname(god, godname, B_FALSE);
strcpy(killedname, "");
if (!where) {
// somewhere next to the player.
where = getrandomadjcell(player->cell, WE_WALKABLE, B_FALSE);
if (!where) {
where = getrandomadjcell(where, B_FALSE, B_FALSE);
}
}
// now see if anyone is there.
if (where->lf) {
// kill them.
getlfname(where->lf, killedname);
killlf(where->lf);
if (where->type->solid) {
setcelltype(where, where->habitat->emptycelltype);
}
teleportto(god, where, B_TRUE);
if (haslos(player, where) && strlen(killedname)) {
msg("%s transforms into %s!", killedname, godname);
}
} else {
teleportto(god, where, B_TRUE);
}
return god;
}
// maybe get a gift
int godgiftmaybe(enum RACE rid) {
lifeform_t *god;
int piety,gotgift = B_FALSE;
god = findgod(rid);
piety = getpiety(rid);
if (piety >= 100) {
int chance;
// ie. 100 -> 2%
// ie. 500 -> 10%
chance = piety / 5;
if (pctchance(chance)) { // if this is true, you get a gift.
char obtogive[BUFLEN];
int rollagain = B_TRUE;
gotgift = B_TRUE;
godsay(god->race->id, "I bestow a gift upon you, mortal!");
strcpy(obtogive, "");
switch (god->race->id) {
case R_GODDEATH:
while (rollagain) {
flag_t *f;
object_t *wep;
rollagain = B_FALSE;
switch (rnd(5,5)) {
case 1:
sprintf(obtogive, "3-5 cursed potions of water");
break;
case 2:
sprintf(obtogive, "cursed branded weapon");
break;
case 3: // poison your weapon
wep = getweapon(player);
if (wep && canbepoisoned(wep->type->id)) {
applyobmod(wep, findobmod(OM_POISONED));
msg("A layer of venom covers your weapon!");
} else {
rollagain = B_TRUE;
}
break;
case 4: // resistant/immune to necrotic
if (lfhasflagval(player, F_DTRESIST, DT_NECROTIC, NA, NA, NULL)) {
if (lfhasflagval(player, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL)) {
rollagain = B_TRUE;
} else {
f = addtempflag(player->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL, FROMGODGIFT);
f->obfrom = god->race->id;
}
} else {
f = addtempflag(player->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL, FROMGODGIFT);
f->obfrom = god->race->id;
}
break;
case 5:
msg("\"Go forth and kill in my name!\"");
setrace(player, R_VAMPIRE, B_TRUE);
break;
}
}
break;
case R_GODGREED:
break;
case R_GODMERCY:
while (rollagain) {
flag_t *f;
rollagain = B_FALSE;
switch (rnd(1,4)) {
case 1:
sprintf(obtogive, "3 vials of ambrosia");
break;
case 2:
sprintf(obtogive, "ring of regeneration");
break;
case 3:
sprintf(obtogive, "ring of miracles");
break;
case 4: // immune to disease / poison
if (lfhasflag(player, F_DISEASEIMMUNE)) {
if (lfhasflagval(player, F_DTIMMUNE, DT_POISON, NA, NA, NULL)) {
rollagain = B_TRUE;
} else {
f = addtempflag(player->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL, FROMGODGIFT);
f->obfrom = god->race->id;
}
} else {
f = addtempflag(player->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL, FROMGODGIFT);
f->obfrom = god->race->id;
}
break;
}
}
break;
default:
break;
} // end switch
if (strlen(obtogive)) {
object_t *o;
o = addob(player->cell->obpile, obtogive);
if (o) {
char buf[BUFLEN];
addflag(o->flags, F_GODGIFT, god->race->id, NA, NA, NULL);
if (haslos(player, player->cell)) {
getobname(o, buf, o->amt);
msg("%s appear%s!", buf, (o->amt == 1) ? "s" : "");
} else {
msg("You hear something hitting the ground.");
}
}
}
// since you got a gift, lower piety back to 100 (slightly pleased)
setpiety(rid, 101);
} // end if (pctchance enough to get a gift)
} // end if (piety > 100)
return gotgift;
}
int godisangry(enum RACE rid) {
if (getpiety(rid) < 0) {
return B_TRUE;
}
return B_FALSE;
}
void godsay(enum RACE rid, char *format, ...) {
lifeform_t *god;
char godname[BUFLEN], buf[BUFLEN];
va_list args;
va_start(args, format);
vsprintf( buf, format, args );
va_end(args);
god = findgod(rid);
real_getlfname(god, godname, B_FALSE);
msg("%s%s voice booms out from the heavens:", godname, getpossessive(godname)); more();
msg("\"%s\"", buf);
}
void modpiety(enum RACE rid, int amt) {
lifeform_t *god;
flag_t *f;
god = findgod(rid);
f = lfhasflag(god, F_PIETY);
if (!f) return;
f->val[0] += amt;
limit(&f->val[0], PIETY_MIN, PIETY_MAX);
}
void pleasegod(enum RACE rid, int amt) {
lifeform_t *lf;
char lfname[BUFLEN];
lf = findgod(rid);
real_getlfname(lf, lfname, B_FALSE);
modpiety(rid, amt);
// announce
//msg("You feel like %s approves of your actions.", lfname);
godgiftmaybe(rid);
}
void pleasegodmaybe(enum RACE rid, int amt) {
enum PIETYLEV modplev;
int chance;
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 (onein(chance)) {
pleasegod(rid, amt);
}
}
int prayto(lifeform_t *lf, lifeform_t *god) {
int piety,i;
taketime(lf, getactspeed(lf));
// this will return 100 if we haven't prayed to this
// god before
piety = getpiety(god->race->id);
// remember that we have now prayed to this god.
// ie. player is expected to follow the god's rules.
if (!hasflag(god->flags, F_PRAYEDTO)) {
addflag(god->flags, F_PRAYEDTO, B_TRUE, NA, NA, NULL);
}
if (godisangry(god->race->id)) {
// get even more angry
angergod(god->race->id, PIETYPRAYLOSS);
return B_FALSE;
} else if (piety <= 99) {
// piety between 0 and 99 = ignored
//godsay(god->race->id, "Stop pestering me!");
angergod(god->race->id, 0);
modpiety(god->race->id, -30);
return B_FALSE;
}
// if we get here, piety is >= 100.
// you get some help...
godsay(god->race->id, "You appear in need of assistance, mortal!");
switch (god->race->id) {
lifeform_t *l;
int donesomething = B_FALSE;
case R_GODDEATH:
msg("\"Behold, the power of death!\"");
for (l = lf->cell->map->lf ; l ; l = l->next) {
if ((l != lf) && lfhasflagval(l, F_TARGETLF, lf->id, NA, NA, NULL)) {
castspell(god, OT_S_PAIN, l, NULL, l->cell);
}
}
dospelleffects(god, OT_S_ANIMATEDEAD, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
dospelleffects(god, OT_S_DARKNESS, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
break;
case R_GODGREED:
if (isinbattle(lf)) {
lifeform_t *l;
int donesomething = B_FALSE;
if (isbleeding(lf)) {
// teleport away
msg("\"Nothing like a quick getaway!\"");
dospelleffects(NULL, OT_S_DISPERSAL, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_FALSE);
} else {
// steal from your enemies
for (l = lf->cell->map->lf ; l ; l = l->next) {
if ((l != lf) && lfhasflagval(l, F_TARGETLF, lf->id, NA, NA, NULL)) {
object_t *wep;
// confiscate their weapon
wep = getweapon(l);
if (wep) {
if (!donesomething) {
msg("\"I'll take that...\"");
donesomething = B_TRUE;
}
castspell(god, OT_S_CONFISCATE, l, wep, l->cell);
}
}
}
}
if (!donesomething) {
// teleport away
msg("\"Nothing like a quick getaway!\"");
dospelleffects(NULL, OT_S_DISPERSAL, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_FALSE);
}
} else {
int i,first = B_TRUE;
msg("\"Allow me to reveal your surroundings...\"");
dospelleffects(lf, OT_S_MAPPING, 5, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
dospelleffects(lf, OT_S_REVEALHIDDEN, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
// unlock doors
for (i = 0; i < player->nlos; i++) {
cell_t *c;
object_t *o;
c = player->los[i];
o = hascloseddoor(c);
if (o && hasflag(o->flags, F_LOCKED)) {
if (first) {
msg("\"Access granted!\"");
first = B_FALSE;
}
killflagsofid(o->flags, F_LOCKED);
noise(c, NULL, NC_OTHER, 2, "the click of a lock.", NULL);
}
}
}
break;
case R_GODMERCY:
if (ispoisoned(lf)) {
msg("\"Let thy body be purged of toxins.\"");
castspell(god, OT_S_CUREPOISON, player, NULL, player->cell);
donesomething = B_TRUE;
}
if (gethungerlevel(gethungerval(player)) >= H_PECKISH) {
msg("\"Let thy stomach be satisfied.\"");
castspell(god, OT_S_SATEHUNGER, player, NULL, player->cell);
donesomething = B_TRUE;
}
if (isbleeding(lf) || !donesomething) {
msg("\"Let thy wounds be healed.\"");
castspell(god, OT_S_HEALINGMAJ, player, NULL, player->cell);
donesomething = B_TRUE;
}
break;
default:
break;
}
if (!godgiftmaybe(god->race->id)) {
// if you didn't get a gift, lower piety for this god
modpiety(god->race->id, -PIETYPRAYLOSS);
}
// lower piety for other related gods
for (i = 0; i < ngodlfs; i++) {
if (godlf[i] != god) {
modpiety(godlf[i]->race->id, -25);
}
}
return B_FALSE;
}
void setpiety(enum RACE rid, int amt) {
lifeform_t *god;
flag_t *f;
god = findgod(rid);
f = lfhasflag(god, F_PIETY);
if (!f) return;
f->val[0] = amt;
limit(&f->val[0], PIETY_MIN, PIETY_MAX);
}

16
god.h Normal file
View File

@ -0,0 +1,16 @@
#include "defs.h"
void angergod(enum RACE rid, int amt);
void angergodmaybe(enum RACE rid, int amt);
lifeform_t *findgod(enum RACE rid);
int getpiety(enum RACE rid);
enum PIETYLEV getpietylev(enum RACE rid, enum COLOUR *col, char *happiness);
lifeform_t *godappears(enum RACE rid, cell_t *where);
int godgiftmaybe(enum RACE rid);
int godisangry(enum RACE rid);
void godsay(enum RACE rid, char *format, ...);
void modpiety(enum RACE rid, int amt);
void pleasegod(enum RACE rid, int amt);
void pleasegodmaybe(enum RACE rid, int amt);
int prayto(lifeform_t *lf, lifeform_t *god);
void setpiety(enum RACE rid, int amt);

352
io.c
View File

@ -10,6 +10,7 @@
#include "attack.h" #include "attack.h"
#include "defs.h" #include "defs.h"
#include "flag.h" #include "flag.h"
#include "god.h"
#include "io.h" #include "io.h"
#include "lf.h" #include "lf.h"
#include "map.h" #include "map.h"
@ -41,6 +42,12 @@ extern enum ERROR reason;
extern char msghist[MAXHISTORY][BUFLEN]; extern char msghist[MAXHISTORY][BUFLEN];
extern int nmsghist; extern int nmsghist;
extern lifeform_t *godlf[];
extern int ngodlfs;
extern flag_t *retflag[];
extern int nretflags;
extern prompt_t prompt; extern prompt_t prompt;
extern object_t *retobs[MAXPILEOBS+1]; extern object_t *retobs[MAXPILEOBS+1];
@ -627,6 +634,14 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
strcat(buf, " the "); strcat(buf, " the ");
strcat(buf, j->name); strcat(buf, j->name);
} }
} else if (c->lf->race->raceclass->id == RC_GOD) {
f = lfhasflag(c->lf, F_GODOF);
if (f->val[0] == B_FEMALE) {
strcat(buf, " the Goddess of ");
} else {
strcat(buf, " the God of ");
}
strcat(buf, f->text);
} }
// level // level
/* /*
@ -1177,7 +1192,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
enum SPELLSCHOOL school; enum SPELLSCHOOL school;
school = getspellschoolknown(lf, ot->id); school = getspellschoolknown(lf, ot->id);
msg("^gYou have learned the %s '%s'.", msg("^gYou have learned the %s '%s'.",
(school = SS_MENTAL) ? "psionic power" : "spell", ot->name); (school == SS_MENTAL) ? "psionic power" : "spell", ot->name);
donesomething = B_TRUE; donesomething = B_TRUE;
} }
} }
@ -2772,16 +2787,27 @@ void centre(WINDOW *win, enum COLOUR col, int y, char *format, ... ) {
char buf[BUFLEN]; char buf[BUFLEN];
va_list args; va_list args;
int startx; int startx;
int len;
char *p;
int colcount = 0;
va_start(args, format); va_start(args, format);
vsprintf( buf, format, args ); vsprintf( buf, format, args );
va_end(args); va_end(args);
for (p = buf ; *p ; p++) {
if (*p == '^') colcount++;
}
len = strlen(buf) - (colcount*2);
w = getmaxx(win); w = getmaxx(win);
startx = (w/2) - (strlen(buf)/2); startx = (w/2) - (len/2);
if (startx < 0) startx = 0; if (startx < 0) startx = 0;
if (col != C_NONE) setcol(win, col); if (col != C_NONE) setcol(win, col);
mvwprintw(win, y, (w/2) - (strlen(buf)/2), buf); wmove(win, y, (w/2) - (len/2));
textwithcol(win, buf);
//mvwprintw(win, y, (w/2) - (strlen(buf)/2), buf);
if (col != C_NONE) unsetcol(win, col); if (col != C_NONE) unsetcol(win, col);
} }
@ -2923,6 +2949,60 @@ void cls(void) {
statdirty = B_TRUE; statdirty = B_TRUE;
} }
void describegod(lifeform_t *god) {
char buf[BUFLEN];
char godname[BUFLEN];
char goddesc[BUFLEN];
int i;
flag_t *f;
cls();
f = hasflag(god->flags, F_GODOF);
real_getlfname(god, godname, B_FALSE);
sprintf(goddesc, "(%s of %s)", (f->val[0] == B_FEMALE) ? "Goddess" : "God", f->text);
// title
sprintf(buf, "God::%s %s",godname, goddesc);
wattron(mainwin, A_BOLD);
mvwprintw(mainwin, 0, 0, buf);
wattroff(mainwin, A_BOLD);
wmove(mainwin, 2, 0);
wprintw(mainwin, "%s likes ", godname);
getflags(god->flags, F_GODLIKES, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (i == 0) {
wprintw(mainwin, "%s", f->text);
} else if (i == nretflags - 1) {
wprintw(mainwin, " and %s", f->text);
} else {
wprintw(mainwin, ", %s", f->text);
}
}
wprintw(mainwin, ".\n\n");
wprintw(mainwin, "%s dislikes ", godname);
getflags(god->flags, F_GODDISLIKES, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (i == 0) {
wprintw(mainwin, "%s", f->text);
} else if (i == nretflags - 1) {
wprintw(mainwin, " and %s", f->text);
} else {
wprintw(mainwin, ", %s", f->text);
}
}
wprintw(mainwin, ".\n\n");
wrefresh(mainwin);
// wait for key
getch();
real_clearmsg(B_TRUE);
restoregamewindows();
}
void describeob(object_t *o) { void describeob(object_t *o) {
char buf[BIGBUFLEN]; char buf[BIGBUFLEN];
char buf2[BUFLEN]; char buf2[BUFLEN];
@ -3822,16 +3902,26 @@ void describespell(objecttype_t *ot) {
char buf[BUFLEN]; char buf[BUFLEN];
flag_t *f; flag_t *f;
int i; int i;
int power; int power,range;
cls(); cls();
if (ot->obclass->id == OC_SPELL) {
power = getspellpower(player, ot->id);
} else {
power = -1;
}
range = getspellrange(ot->id, power);
// title // title
sprintf(buf, "%s",ot->name); sprintf(buf, "%s",ot->name);
capitalise(buf); capitalise(buf);
mvwprintw(mainwin, 0, 0, buf); mvwprintw(mainwin, 0, 0, buf);
mvwprintw(mainwin, 2, 0,"%s\n\n", ot->desc); wmove(mainwin, 2, 0);
sprintf(buf, "%s\n\n", ot->desc);
textwithcol(mainwin, buf);
// properties // properties
@ -3862,12 +3952,15 @@ void describespell(objecttype_t *ot) {
wprintw(mainwin, "\n"); wprintw(mainwin, "\n");
if (ot->obclass->id == OC_SPELL) { if (ot->obclass->id == OC_SPELL) {
power = getspellpower(player, ot->id);
if (power > 0) { if (power > 0) {
wprintw(mainwin, "You can cast it at power level %d (maximum %d).\n",power, getspellmaxpower(ot->id)); wprintw(mainwin, "You can cast it at power level %d (maximum %d).\n",power, getspellmaxpower(ot->id));
} else { } else {
wprintw(mainwin, "It is too powerful for you to cast (maximum power %d).\n",power, getspellmaxpower(ot->id)); wprintw(mainwin, "It is too powerful for you to cast (maximum power %d).\n",power, getspellmaxpower(ot->id));
} }
if (range != UNLIMITED) {
wprintw(mainwin, "At this power, it has a range of %d cell%s.",range, (range == 1) ? "" : "s");
}
} }
wrefresh(mainwin); wrefresh(mainwin);
@ -4085,7 +4178,7 @@ void docomms(lifeform_t *lf) {
fightback(lf, player); fightback(lf, player);
} else if (i <= 10) { // limited wish } else if (i <= 10) { // limited wish
// change to a god. // change to a god.
setrace(lf, R_GODGREED, B_TRUE); lf = godappears(R_GODGREED, lf->cell);
// behold! i am me! // behold! i am me!
say(lf, "Behold mortal! It is I, Avamon!", SV_SHOUT); say(lf, "Behold mortal! It is I, Avamon!", SV_SHOUT);
say(lf, "For your selfless act, I grant you a wish.", SV_TALK); say(lf, "For your selfless act, I grant you a wish.", SV_TALK);
@ -5163,16 +5256,11 @@ void dofire(void) {
} }
} }
void dohelp(void) { void dohelp(char helpmode) {
int h; int h;
int y; int y;
command_t *c; command_t *c;
char *ftext= "%c %s"; char *ftext= "%c %s";
enum {
HM_COMMANDS,
HM_MAIN,
HM_SKILLS,
} helpmode = HM_MAIN;
int done = B_FALSE; int done = B_FALSE;
int ch; int ch;
@ -5180,25 +5268,24 @@ void dohelp(void) {
while (!done) { while (!done) {
cls(); cls();
if (helpmode == HM_MAIN) { if (helpmode == '?') {
initprompt(&prompt, "What would you like help with (ESC when done)?"); initprompt(&prompt, "What would you like help with (ESC when done)?");
addchoice(&prompt, '?', "Keyboard Commands", NULL, NULL); addchoice(&prompt, '?', "Keyboard Commands", NULL, NULL);
addchoice(&prompt, 's', "Skill Descriptions", NULL, NULL); addchoice(&prompt, 'g', "Skill Descriptions", NULL, NULL);
addchoice(&prompt, 's', "God Descriptions", NULL, NULL);
addchoice(&prompt, '-', "(done)", NULL, NULL); addchoice(&prompt, '-', "(done)", NULL, NULL);
prompt.maycancel = B_TRUE; prompt.maycancel = B_TRUE;
ch = getchoice(&prompt); ch = getchoice(&prompt);
switch (ch) { switch (ch) {
case '?': case '?':
helpmode = HM_COMMANDS; case 'g':
break;
case 's': case 's':
helpmode = HM_SKILLS; helpmode = ch;
break;
default: default:
done = B_TRUE; done = B_TRUE;
break; break;
} }
} else if (helpmode == HM_COMMANDS) { } else if (helpmode == 'c') {
centre(mainwin,C_WHITE, 0, "KEYBOARD COMMAND REFERENCE"); centre(mainwin,C_WHITE, 0, "KEYBOARD COMMAND REFERENCE");
y = 2; y = 2;
@ -5213,8 +5300,8 @@ void dohelp(void) {
} }
centre(mainwin,C_WHITE, h-1, "[Press any key]"); centre(mainwin,C_WHITE, h-1, "[Press any key]");
getch(); getch();
helpmode = HM_MAIN; done = B_TRUE;
} else if (helpmode == HM_SKILLS) { } else if (helpmode == 's') {
skill_t *sk; skill_t *sk;
centre(mainwin,C_WHITE, 0, "SKILL REFERENCE"); centre(mainwin,C_WHITE, 0, "SKILL REFERENCE");
y = 2; y = 2;
@ -5227,11 +5314,40 @@ void dohelp(void) {
prompt.maycancel = B_TRUE; prompt.maycancel = B_TRUE;
ch = getchoicestr(&prompt, B_FALSE, B_TRUE); ch = getchoicestr(&prompt, B_FALSE, B_TRUE);
if (!ch) { if (!ch) {
helpmode = HM_MAIN; done = B_TRUE;
} else { } else {
sk = (skill_t *)prompt.result; sk = (skill_t *)prompt.result;
describeskill(sk->id); describeskill(sk->id);
} }
} else if (helpmode == 'g') {
int i;
centre(mainwin,C_WHITE, 0, "SKILL REFERENCE");
y = 2;
initprompt(&prompt, "Describe which god (ESC when done)?");
for (i = 0 ; i < ngodlfs; i++) {
lifeform_t *lf;
flag_t *f;
char buf[BUFLEN];
char godof[BUFLEN];
lf = godlf[i];
real_getlfname(lf, buf, B_FALSE);
f = hasflag(lf->flags, F_GODOF);
sprintf(godof, " (%s of %s)", (f->val[0] == B_FEMALE) ? "Goddess" : "God", f->text);
strcat(buf, godof);
addchoice(&prompt, 'a', buf, NULL, lf);
}
addchoice(&prompt, '\0', "(done)", NULL, NULL);
prompt.maycancel = B_TRUE;
ch = getchoicestr(&prompt, B_FALSE, B_TRUE);
if (!ch) {
done = B_TRUE;
} else {
lifeform_t *god;
god = (lifeform_t *)prompt.result;
describegod(god);
}
} }
} }
@ -6696,7 +6812,7 @@ void handleinput(void) {
doinventory(player->pack); doinventory(player->pack);
break; break;
case '?': // help case '?': // help
dohelp(); dohelp('?');
break; break;
case '@': // display player stats case '@': // display player stats
showlfstats(player, B_FALSE); showlfstats(player, B_FALSE);
@ -7637,8 +7753,9 @@ void showlfstats(lifeform_t *lf, int showall) {
} }
if (showall) { if (showall) {
sprintf(prompt, "[@=stats S=skills/abilities M=magic E=effects %sESC=quit]", isplayer(lf) ? "" : "I=items " ); sprintf(prompt, "^h[^W@^n=stats ^WS^nkills ^WA^nbils ^WM^nagic ^WE^nffects ^WG^nods %s^W?^n=help ^WESC^n=quit^h]",
sprintf(cmdchars, "@asme%s",isplayer(lf) ? "" : "i"); isplayer(lf) ? "" : "^WI^ntems " );
sprintf(cmdchars, "@asmeg%s",isplayer(lf) ? "" : "i");
} else { } else {
sprintf(prompt, "%s", "[ESC=quit]"); sprintf(prompt, "%s", "[ESC=quit]");
sprintf(cmdchars, "%s", "@"); sprintf(cmdchars, "%s", "@");
@ -8457,10 +8574,7 @@ void showlfstats(lifeform_t *lf, int showall) {
} }
} }
} else if (mode == 's') { } else if (mode == 'a') {
int exitnow = B_FALSE;
// now show intrinsics on next page
centre(mainwin, C_WHITE, 0, "ABILITIES"); centre(mainwin, C_WHITE, 0, "ABILITIES");
y = 2; y = 2;
@ -8505,7 +8619,6 @@ void showlfstats(lifeform_t *lf, int showall) {
wprintw(mainwin, buf); wprintw(mainwin, buf);
if (downline(&y, h, "ABILITIES", NULL, prompt, cmdchars, &ch)) { if (downline(&y, h, "ABILITIES", NULL, prompt, cmdchars, &ch)) {
exitnow = B_TRUE;
break; break;
} }
} }
@ -8513,55 +8626,55 @@ void showlfstats(lifeform_t *lf, int showall) {
} }
y++; y++;
if (!exitnow) { } else if (mode == 's') {
char skilltitle[BUFLEN]; char skilltitle[BUFLEN];
flag_t *known[MAXSKILLS], *available[MAXSKILLS]; flag_t *known[MAXSKILLS], *available[MAXSKILLS];
int numknown = 0, numavailable = 0; int numknown = 0, numavailable = 0;
int n; int n;
enum SKILLLEVEL slev; enum SKILLLEVEL slev;
// get available skills centre(mainwin, C_WHITE, 0, "SKILLS");
// get available skills
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_CANLEARN) {
if (!getskill(lf, f->val[0])) {
available[numavailable++] = f;
}
}
}
// get known skills, in order
for (slev = PR_MASTER ; slev >= PR_NOVICE; slev--) {
for (f = lf->flags->first ; f ; f = f->next) { for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_CANLEARN) { if ((f->id == F_HASSKILL) && (f->val[1] == slev)) {
if (!getskill(lf, f->val[0])) { known[numknown++] = f;
available[numavailable++] = f;
}
} }
} }
// get known skills, in order }
for (slev = PR_MASTER ; slev >= PR_NOVICE; slev--) {
for (f = lf->flags->first ; f ; f = f->next) {
if ((f->id == F_HASSKILL) && (f->val[1] == slev)) { //centre(mainwin, y, "SKILLS"); y ++;
known[numknown++] = f; sprintf(skilltitle, "%-40s%-40s","AVAILABLE SKILLS", "KNOWN SKILLS");
} doheading(mainwin, &y, 0, skilltitle);
} for (n = 0; n < MAXOF(numknown,numavailable); n++) {
if (n < numavailable) {
setcol(mainwin, C_RED);
mvwprintw(mainwin, y, 0, "- %s",
getskillname(available[n]->val[0]) );
unsetcol(mainwin, C_RED);
} }
if (n < numknown) {
setcol(mainwin, getskilllevelcolour(known[n]->val[1]));
//centre(mainwin, y, "SKILLS"); y ++; mvwprintw(mainwin, y, 40, "%c %s (%s)%s",
sprintf(skilltitle, "%-40s%-40s","AVAILABLE SKILLS", "KNOWN SKILLS"); ismaxedskill(lf, known[n]->val[0]) ? '*' : '-',
doheading(mainwin, &y, 0, skilltitle); getskillname(known[n]->val[0]),
for (n = 0; n < MAXOF(numknown,numavailable); n++) { getskilllevelname(known[n]->val[1]),
if (n < numavailable) { //ismaxedskill(lf, known[n]->val[0]) ? "/MAX" : "",
setcol(mainwin, C_RED); (known[n]->lifetime == FROMSPELL) ? "[spell]" : "");
mvwprintw(mainwin, y, 0, "- %s", unsetcol(mainwin, getskilllevelcolour(known[n]->val[1]));
getskillname(available[n]->val[0]) ); }
unsetcol(mainwin, C_RED); if (downline(&y, h, "SKILLS", skilltitle, prompt, cmdchars, &ch)) {
} break;
if (n < numknown) {
setcol(mainwin, getskilllevelcolour(known[n]->val[1]));
mvwprintw(mainwin, y, 40, "%c %s (%s)%s",
ismaxedskill(lf, known[n]->val[0]) ? '*' : '-',
getskillname(known[n]->val[0]),
getskilllevelname(known[n]->val[1]),
//ismaxedskill(lf, known[n]->val[0]) ? "/MAX" : "",
(known[n]->lifetime == FROMSPELL) ? "[spell]" : "");
unsetcol(mainwin, getskilllevelcolour(known[n]->val[1]));
}
if (downline(&y, h, "SKILLS", skilltitle, prompt, cmdchars, &ch)) {
exitnow = B_TRUE;
break;
}
} }
} }
} else if (mode == 'm') { } else if (mode == 'm') {
@ -9155,6 +9268,82 @@ void showlfstats(lifeform_t *lf, int showall) {
} else { } else {
mvwprintw(mainwin, y, 0, "It is not carrying anything."); mvwprintw(mainwin, y, 0, "It is not carrying anything.");
} }
} else if (mode == 'g') {
int i;
char line[BUFLEN];
cls();
centre(mainwin, C_WHITE, 0, "GODS");
y = 2;
sprintf(line, "%-26s Prayed? %-22s %s","God","Piety", "Happiness");
doheading(mainwin, &y, 0, line);
for (i = 0; i < ngodlfs; i++) {
lifeform_t *god;
flag_t *f;
char godname[BUFLEN];
char pietybuf[BUFLEN];
char happiness[BUFLEN];
int prayedto = B_FALSE;
char colbuf[3];
enum PIETYLEV plev;
enum COLOUR col;
int piety,n;
god = godlf[i];
real_getlfname(god, godname, B_FALSE);
f = lfhasflag(god, F_GODOF);
if (f->val[0] == B_FEMALE) {
strcat(godname, " (Goddess of ");
} else {
strcat(godname, " (God of ");
}
strcat(godname, f->text);
strcat(godname, ")");
if (lfhasflag(god, F_PRAYEDTO)) {
prayedto = B_TRUE;
}
piety = getpiety(god->race->id);
plev = getpietylev(god->race->id, &col, happiness);
// TODO: construct piety buf [---+--|--------------------]
sprintf(pietybuf, "^n[");
switch (col) {
case C_ORANGE: strcpy(colbuf, "^T"); break;
case C_RED: strcpy(colbuf, "^B"); break;
case C_YELLOW: strcpy(colbuf, "^w"); break;
case C_BROWN: strcpy(colbuf, "^b"); break;
case C_GREEN: strcpy(colbuf, "^g"); break;
case C_BOLDGREEN: strcpy(colbuf, "^G"); break;
case C_BOLDCYAN: strcpy(colbuf, "^E"); break;
default: case C_GREY: strcpy(colbuf, "^n"); break;
}
strcat(pietybuf, colbuf);
for (n = PIETY_MIN; n <= PIETY_MAX; n += 25) {
if ((piety >= n) && (piety < n+25)){
strcat(pietybuf, "+");
} else {
strcat(pietybuf, "-");
}
}
strcat(pietybuf, "^n]");
sprintf(line, "%s%-26s%-9s%s %s%s",
prayedto ? "^g" : "^n",
godname,
prayedto ? " Yes " : " No ",
pietybuf, colbuf, happiness);
wmove(mainwin, y, 0);
textwithcol(mainwin, line);
y++;
}
} }
// wait for key // wait for key
@ -9169,14 +9358,23 @@ void showlfstats(lifeform_t *lf, int showall) {
case '@': case '@':
mode = ch; mode = ch;
break; break;
case 's': case 'a':
case 'm':
case 'e': case 'e':
case 'g':
case 'm':
case 's':
if (showall) mode = ch; if (showall) mode = ch;
break; break;
case 'i': case 'i':
if (showall && !isplayer(lf)) mode = ch; if (showall && !isplayer(lf)) mode = ch;
break; break;
case '?':
if (mode == 'g') { // help on gods
dohelp('g');
} else if (mode == 's') { // help on skills
dohelp('s');
}
break;
default: default:
break; break;
} }

3
io.h
View File

@ -33,6 +33,7 @@ void real_clearmsg(int force);
void clearretobs(void); void clearretobs(void);
void cls(void); void cls(void);
int contains(enum OBCLASS *array, int nargs, enum OBCLASS want); int contains(enum OBCLASS *array, int nargs, enum OBCLASS want);
void describegod(lifeform_t *god);
void describeob(object_t *o); void describeob(object_t *o);
void describeskill(enum SKILL skid); void describeskill(enum SKILL skid);
void describespell(objecttype_t *ot); void describespell(objecttype_t *ot);
@ -45,7 +46,7 @@ void doenter(lifeform_t *lf);
void doexplain(char *question); void doexplain(char *question);
void dofinaloblist(obpile_t *op); void dofinaloblist(obpile_t *op);
void dofire(void); void dofire(void);
void dohelp(void); void dohelp(char helpmode);
void doinventory(obpile_t *op); void doinventory(obpile_t *op);
void doknowledgelist(void); void doknowledgelist(void);
void dolook(cell_t *where, int onpurpose); void dolook(cell_t *where, int onpurpose);

294
lf.c
View File

@ -8,6 +8,7 @@
#include "attack.h" #include "attack.h"
#include "defs.h" #include "defs.h"
#include "flag.h" #include "flag.h"
#include "god.h"
#include "io.h" #include "io.h"
#include "lf.h" #include "lf.h"
#include "map.h" #include "map.h"
@ -19,6 +20,7 @@
extern FILE *logfile; extern FILE *logfile;
extern map_t *firstmap; extern map_t *firstmap;
extern race_t *firstrace, *lastrace; extern race_t *firstrace, *lastrace;
extern raceclass_t *firstraceclass, *lastraceclass; extern raceclass_t *firstraceclass, *lastraceclass;
@ -53,6 +55,9 @@ extern int loading;
extern int obdb; extern int obdb;
extern lifeform_t *godlf[];
extern int ngodlfs;
extern enum ERROR reason; extern enum ERROR reason;
@ -70,9 +75,6 @@ void autoweild(lifeform_t *lf) {
pretimespent = lf->timespent; pretimespent = lf->timespent;
if (isplayer(lf)) {
dblog("xxx");
}
// weild weapons if required // weild weapons if required
bestwep = getbestweapon(lf); bestwep = getbestweapon(lf);
if (bestwep) { if (bestwep) {
@ -1671,6 +1673,25 @@ void die(lifeform_t *lf) {
} }
} }
if (lf->race->id == R_VAMPIRE) {
// if are asleep, we will die normally
if (lfhasflag(lf, F_ASLEEP)) {
noise(lf->cell, lf, NC_OTHER, 4, "a horrified scream!", "screams in horror!");
} else if (findobinmap(lf->cell->map, OT_COFFIN)) { // coffin around?
// restore 1 hp
lf->hp = 1;
killflagsofid(lf->flags, F_DEAD);
// convert into a gas cloud!
dospelleffects(NULL, OT_S_GASEOUSFORM, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
// ai will now look for our coffin
if (!isplayer(lf)) {
addflag(lf->flags, F_WANTS, OT_COFFIN, B_COVETS, NA, NULL);
addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
}
return;
}
}
// revert to your original form first. // revert to your original form first.
if (lfhasflag(lf, F_POLYMORPHED)) { if (lfhasflag(lf, F_POLYMORPHED)) {
if (lfhasflag(lf, F_ORIGRACE)) { if (lfhasflag(lf, F_ORIGRACE)) {
@ -1816,6 +1837,11 @@ void die(lifeform_t *lf) {
colourmatchob(corpse, lf); colourmatchob(corpse, lf);
} }
// corpse of a player pet?
if (ispetof(lf, player)) {
addflag(corpse->flags, F_PETOF, player->id, NA, NA, NULL);
}
// add extra flags ? // add extra flags ?
getflags(lf->flags, F_CORPSEFLAG, F_NONE); getflags(lf->flags, F_CORPSEFLAG, F_NONE);
for (i = 0; i < nretflags; i++) { for (i = 0; i < nretflags; i++) {
@ -2477,6 +2503,12 @@ int eat(lifeform_t *lf, object_t *o) {
stopeating = B_TRUE; stopeating = B_TRUE;
} }
if (isplayer(lf) && hasflagval(o->flags, F_PETOF, player->id, NA, NA, NULL)) {
angergodmaybe(R_GODMERCY, 150);
stopeating = B_TRUE;
}
// stop eating if we are full // stop eating if we are full
if (!stopeating && !fullyeaten && (posthlev != hlev) && (posthlev <= H_FULL)) { if (!stopeating && !fullyeaten && (posthlev != hlev) && (posthlev <= H_FULL)) {
if (isplayer(lf) && (posthlev != H_STUFFED)) { if (isplayer(lf) && (posthlev != H_STUFFED)) {
@ -3239,9 +3271,12 @@ int flee(lifeform_t *lf) {
if (f->lifetime == PERMENANT) { if (f->lifetime == PERMENANT) {
killflag(f); killflag(f);
} else { } else {
// if the flag is temporary, wait for it to time out normally // if the flag is temporary, keep fleeing and wait for it to time out normally
fleefrom = thisone; fleefrom = thisone;
} }
if (isplayer(thisone)) {
pleasegodmaybe(R_GODMERCY, 5);
}
} }
} }
} }
@ -4656,7 +4691,7 @@ int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions) {
} }
int getnightvisrange(lifeform_t *lf) { int getnightvisrange(lifeform_t *lf) {
int range = 1; // default int range = 1,i; // default
flag_t *f; flag_t *f;
f = lfhasflag(lf, F_SEEINDARK); f = lfhasflag(lf, F_SEEINDARK);
@ -4672,6 +4707,16 @@ int getnightvisrange(lifeform_t *lf) {
return f->val[0]; return f->val[0];
} }
} }
// modifications?
getflags(lf->flags, F_NIGHTVISRANGEMOD, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->id == F_NIGHTVISRANGEMOD) {
range += f->val[0];
}
}
if (range < 0) range = 0;
return range; return range;
} }
@ -5546,7 +5591,7 @@ race_t *getrandomrace(cell_t *c, int forcedepth) {
if (forcedepth != NA) { if (forcedepth != NA) {
depth = forcedepth; depth = forcedepth;
} else { } else {
depth = getmapdifficulty(c ? c->map : NULL); depth = getmapdifficulty((c && c->map) ? c->map : NULL);
} }
getrarityrange(depth, &raritymin, &raritymax, RARITYVARIANCELF, B_TRUE); getrarityrange(depth, &raritymin, &raritymax, RARITYVARIANCELF, B_TRUE);
@ -7898,6 +7943,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SPEECH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SPEECH, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SS_AIR, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_AIR, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SS_DEATH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_DEATH, NA, NA, NULL);
@ -7941,6 +7987,7 @@ void initjobs(void) {
void initrace(void) { void initrace(void) {
flag_t *f; flag_t *f;
objecttype_t *ot;
// race classes // race classes
addraceclass(RC_OTHER, "misc. creature", "miscellaneous creatures", SK_NONE); addraceclass(RC_OTHER, "misc. creature", "miscellaneous creatures", SK_NONE);
addraceclass(RC_ANIMAL, "animal", "animals and insects", SK_LORE_NATURE); addraceclass(RC_ANIMAL, "animal", "animals and insects", SK_LORE_NATURE);
@ -8135,6 +8182,38 @@ void initrace(void) {
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
// gods // gods
addrace(R_GODDEATH, "Hecta", 100, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD);
addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "16");
addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "20");
addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "15");
addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "18");
addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "6");
addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "6");
addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d6");
addflag(lastrace->flags, F_HASATTACK, OT_TOUCHPARALYZE2, NA, NA, "1d6");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "cloak of shadows");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "bone helmet");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10-20 bones");
//addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_SS_DEATH, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "extends a skeletal finger");
// god abilities
addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Death");
addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL);
// may cast all death spells
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == OC_SPELL) && (getspellschool(ot->id) == SS_DEATH)) {
addflag(lastrace->flags, F_CANWILL, ot->id, NA, NA, "pw:10;");
}
}
addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;");
addrace(R_GODGREED, "Avamon", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); addrace(R_GODGREED, "Avamon", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD);
addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "20"); addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "20");
addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "10"); addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "10");
@ -8149,23 +8228,64 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "+5 dagger of sharpness");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed ring of hunger"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed ring of hunger");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 huge bags of holding"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 huge bags of holding");
//addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); //addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_RARITY, NA, NA, NULL); // ie. everything addflag(lastrace->flags, F_WANTSOBFLAG, F_RARITY, NA, NA, NULL); // ie. everything
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_THIEVERY, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_THIEVERY, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_BACKSTAB, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_THROWING, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "waves his hand"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "waves his hand");
// god abilities // god abilities
addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Greed"); addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Thieves");
addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL);
addflag(lastrace->flags, F_OBESE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_OBESE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_CALLWIND, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANWILL, OT_S_CALLWIND, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_CONFISCATE, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANWILL, OT_S_CONFISCATE, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_HUNGER, NA, NA, "pw:1;"); addflag(lastrace->flags, F_CANWILL, OT_S_HUNGER, NA, NA, "pw:1;");
addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;");
addrace(R_GODMERCY, "Yumi", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD);
addflag(lastrace->flags, F_FLEEONHPPCT, 95, NA, NA, "");
addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "10");
addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "10");
addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "18");
addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "17");
addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "10");
addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "17");
addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 50, NA, NA, NULL);
addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 blessed vials of ambrosia");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "2 rings of regeneration");
addflag(lastrace->flags, F_STARTSKILL, SK_FIRSTAID, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "raises her hand");
// god abilities
addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Mercy");
addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_S_CUREPOISON, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_HEALINGMAJ, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_SATEHUNGER, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_DISPERSAL, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_SLEEP, NA, NA, "pw:10;");
addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "the successful casting of healing spells");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "allowing fleeing creatures to escape");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "natural healing");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "attacking the innocent");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "sneak attacks");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of poison");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the destruction of healing potions");
// monsters // monsters
addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC); addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VHIGH, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VHIGH, NA, NULL);
@ -9170,8 +9290,7 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d6");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6");
addflag(lastrace->flags, F_REGENERATES, 2, NA, NA, NULL); addflag(lastrace->flags, F_REGENERATES, 2, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
@ -10280,7 +10399,8 @@ void initrace(void) {
addflag(lastrace->flags, F_HITDICE, 4, 2, NA, NULL); addflag(lastrace->flags, F_HITDICE, 4, 2, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_HASATTACK, OT_TOUCHPARALYZE2, NA, NA, "0d1+0"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6");
addflag(lastrace->flags, F_HASATTACK, OT_TOUCHPARALYZE2, NA, NA, "1d1");
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, NULL);
@ -10321,7 +10441,7 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, ""); addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, "");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5+3"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5+3");
addflag(lastrace->flags, F_HASATTACK, OT_TOUCHPARALYZE, NA, NA, "0d1+0"); addflag(lastrace->flags, F_HASATTACK, OT_TOUCHPARALYZE, NA, NA, "1d1");
addflag(lastrace->flags, F_CARNIVORE, 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_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
@ -10329,6 +10449,35 @@ void initrace(void) {
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addrace(R_VAMPIRE, "vampire", 75, 'V', C_BLUE, MT_FLESH, RC_UNDEAD);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_DEX, AT_VHIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXHIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VHIGH, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, RR_RARE, NULL);
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_FAST, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 8, 3, NA, NULL);
addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL);
addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "coffin");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+4");
addflag(lastrace->flags, F_CANWILL, OT_S_CHARM, 3, 3, "pw:6;");
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 5, 5, "range:3;");
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pile of ash");
// special: change to gas cloud with 1 hp on death, if not asleep
// TODO: can shapeshift to bat
// TODO: flee from holy symbols / garlic
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
// special monsters // special monsters
addrace(R_GASCLOUD, "cloud of gas", 0.1, '}', C_GREY, MT_GAS, RC_OTHER); addrace(R_GASCLOUD, "cloud of gas", 0.1, '}', C_GREY, MT_GAS, RC_OTHER);
addflag(lastrace->flags, F_MOVESPEED, SP_ULTRAFAST, NA, NA, ""); addflag(lastrace->flags, F_MOVESPEED, SP_ULTRAFAST, NA, NA, "");
@ -10355,6 +10504,7 @@ void initrace(void) {
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
// special: fully heal if our origrace is a vampire, and we are resting over a coffin
addrace(R_DANCINGWEAPON, "dancing weapon", 0, ')', C_GREY, MT_METAL, RC_OTHER); addrace(R_DANCINGWEAPON, "dancing weapon", 0, ')', C_GREY, MT_METAL, RC_OTHER);
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
@ -11242,7 +11392,12 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) {
*amt -= rnd(0,3); *amt -= rnd(0,3);
} }
limit(amt, 0, NA); if (lf->race->raceclass->id == RC_GOD) {
// immortal
limit(amt, 0, lf->hp-1);
} else {
limit(amt, 0, NA);
}
} }
void makepeaceful(lifeform_t *who) { void makepeaceful(lifeform_t *who) {
@ -11284,6 +11439,9 @@ lifeform_t *makezombie(object_t *o) {
where = getoblocation(o); where = getoblocation(o);
getobname(o, obname, 1); getobname(o, obname, 1);
if (!cellwalkable(NULL, where, NULL)) {
where = getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND);
}
lf = addlf(where, r->id, 1); lf = addlf(where, r->id, 1);
addflag(lf->flags, F_LFSUFFIX, B_TRUE, NA, NA, "zombie"); addflag(lf->flags, F_LFSUFFIX, B_TRUE, NA, NA, "zombie");
@ -11384,6 +11542,16 @@ int areenemies(lifeform_t *lf1, lifeform_t *lf2) {
return B_TRUE; return B_TRUE;
} }
void age(lifeform_t *lf, int pct) {
lf->maxhp -= pctof(pct,lf->maxhp);
limit(&lf->maxhp, 0, NA);
limit(&lf->hp, NA, lf->maxhp);
if (isplayer(lf)) {
msg("^BYour body ages unnaturally!");
statdirty = B_TRUE;
}
}
void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o) { void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o) {
flag_t *fromlfflag; flag_t *fromlfflag;
lifeform_t *fromlf = NULL; lifeform_t *fromlf = NULL;
@ -12462,6 +12630,11 @@ void modhunger(lifeform_t *lf, int amt) {
(needexclam) ? '!' : '.'); (needexclam) ? '!' : '.');
statdirty = B_TRUE; statdirty = B_TRUE;
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
gethungername(posthlev, buf);
msg("^%c%s looks %s%c", getlfcol(lf, CC_BAD), lfname, buf, (needexclam) ? '!' : '.');
} }
if ((posthlev >= H_VHUNGRY) && (amt > 0)) { if ((posthlev >= H_VHUNGRY) && (amt > 0)) {
@ -12472,6 +12645,13 @@ void modhunger(lifeform_t *lf, int amt) {
// reset hunger // reset hunger
f->val[0] = 0; f->val[0] = 0;
} }
// ai doesn't get hungry anymore after they have
// satisfied their hunger.
if (!isplayer(lf) && (posthlev <= H_NONE)) {
killflag(f);
return;
}
} }
} }
} }
@ -13644,6 +13824,13 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
} }
} }
if ((lf->race->id == R_GASCLOUD) && (origrace->id == R_VAMPIRE)) {
if (!isplayer(lf)) {
f = lfhasflagval(lf, F_WANTS, OT_COFFIN, NA, NA, NULL);
if (f) killflag(f);
}
}
f = lfhasflagval(lf, F_CANWILL, OT_A_POLYREVERT, NA, NA, NULL); f = lfhasflagval(lf, F_CANWILL, OT_A_POLYREVERT, NA, NA, NULL);
if (f) { if (f) {
killflag(f); killflag(f);
@ -13657,7 +13844,8 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
getlfname(lf, buf); getlfname(lf, buf);
f = lfhasflag(lf, F_GODOF); f = lfhasflag(lf, F_GODOF);
if (f) { if (f) {
msg("^w%s transforms into %s, the God of %s!", buf, newrace->name, f->text); msg("^w%s transforms into %s, the %s of %s!", buf, newrace->name,
(f->val[0] == B_FEMALE) ? "Goddess" : "God", f->text);
} else { } else {
msg("^w%s transforms into %s %s!", buf, isvowel(newrace->name[0]) ? "an" : "a", newrace->name); msg("^w%s transforms into %s %s!", buf, isvowel(newrace->name[0]) ? "an" : "a", newrace->name);
} }
@ -13798,6 +13986,14 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
moveob(o, lf->cell->obpile, o->amt); moveob(o, lf->cell->obpile, o->amt);
} }
} }
if (isplayer(lf)) {
needredraw = B_TRUE;
statdirty = B_TRUE;
} else if (cansee(player, lf)) {
needredraw = B_TRUE;
}
} // end if gamestarted } // end if gamestarted
} }
@ -14771,35 +14967,20 @@ void stopsprinting(lifeform_t *lf) {
// and make it worth zero xp. // and make it worth zero xp.
// //
// for unique monsters, they move from their current position. // for unique monsters, they move from their current position.
lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, int randomjobsok, job_t *forcejob, int lifetime, int wantfriendly) { lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, char *racename, int lifetime, int wantfriendly) {
lifeform_t *newlf = NULL; lifeform_t *newlf = NULL;
char buf[BUFLEN]; char buf[BUFLEN];
race_t *r;
r = findrace(rid);
if (r && hasflag(r->flags, F_UNIQUE)) { newlf = addmonster(c, rid, racename, B_FALSE, 1, B_FALSE, NULL);
// does it already exist? if (newlf) {
newlf = findlfunique(rid); if (haslos(player, c)) {
//char *newbuf;
// if so, move it here, then exit. getlfnamea(newlf, buf);
if (newlf) { capitalise(buf);
teleportto(newlf, c, B_FALSE); msg("%s appears!", buf);
} }
}
if (!newlf) { if (!hasflag(newlf->flags, F_UNIQUE)) {
newlf = addmonster(c, rid, randomjobsok, 1, B_FALSE, NULL);
if (newlf) {
// assign job if required
if (forcejob) {
givejob(newlf, forcejob->id);
}
if (haslos(player, c)) {
//char *newbuf;
getlfnamea(newlf, buf);
capitalise(buf);
msg("%s appears!", buf);
}
// summoned // summoned
if (caster) { if (caster) {
addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL); addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL);
@ -15206,6 +15387,16 @@ void turneffectslf(lifeform_t *lf) {
} }
// god piety gets restored over time
if (isplayer(lf)) {
for (i = 0; i < ngodlfs; i++) {
if (getpietylev(godlf[i]->race->id, NULL, NULL) == PL_TOLERATED) {
// slowly tick upwards
if (onein(2)) modpiety(godlf[i]->race->id, 1);
}
}
}
if (hasactivespell(lf, OT_S_SUMMONWEAPON)) { if (hasactivespell(lf, OT_S_SUMMONWEAPON)) {
if (!hasob(lf->pack, OT_ENERGYBLADE)) { if (!hasob(lf->pack, OT_ENERGYBLADE)) {
stopspell(lf, OT_S_SUMMONWEAPON); stopspell(lf, OT_S_SUMMONWEAPON);
@ -16345,6 +16536,9 @@ int validateraces(void) {
} else if (r->raceclass->id == RC_DEMON) { } else if (r->raceclass->id == RC_DEMON) {
addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL);
} else if (r->raceclass->id == RC_GOD) { } else if (r->raceclass->id == RC_GOD) {
addflag(r->flags, F_PIETY, 100, NA, NA, NULL);
addflag(r->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_MORALE, 10, NA, NA, NULL);
addflag(r->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); addflag(r->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); addflag(r->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL);
@ -16536,6 +16730,23 @@ int rest(lifeform_t *lf, int onpurpose) {
int resting = B_FALSE; int resting = B_FALSE;
object_t *restob = NULL; object_t *restob = NULL;
// special case
if ((lf->race->id == R_GASCLOUD) && lfhasflagval(lf, F_ORIGRACE, R_VAMPIRE, NA, NA, NULL)) {
if (hasob(lf->cell->obpile, OT_COFFIN)) {
// restore original form.
abilityeffects(lf, OT_A_POLYREVERT, lf->cell, lf, NULL);
// restore full hp
lf->hp = lf->maxhp;
// fall asleep for a while
fallasleep(lf, 50);
// mark screen as dirty
needredraw = B_TRUE;
if (isplayer(lf)) {
statdirty = B_TRUE;
}
return B_FALSE;
}
}
rf = lfhasflag(lf, F_TRAINING); rf = lfhasflag(lf, F_TRAINING);
if (rf) { if (rf) {
@ -16613,10 +16824,13 @@ int rest(lifeform_t *lf, int onpurpose) {
} }
//if (isplayer(lf)) msg("hp given."); //if (isplayer(lf)) msg("hp given.");
if (lf->hp < lf->maxhp) { if (isplayer(lf) && (lf->hp < lf->maxhp)) {
// pass a skill check to regain hp // pass a skill check to regain hp
if (skillcheck(lf, SC_CON, difficulty, getskill(lf, SK_FIRSTAID))) { if (skillcheck(lf, SC_CON, difficulty, getskill(lf, SK_FIRSTAID))) {
gainhp(lf, hpheal); gainhp(lf, hpheal);
if (isplayer(lf)) {
pleasegodmaybe(R_GODMERCY, 1);
}
} }
} }

3
lf.h
View File

@ -10,6 +10,7 @@ void addskilldesc(enum SKILL id, enum SKILLLEVEL lev, char *text, int wantmsg);
void addtrail(lifeform_t *lf, int dir); void addtrail(lifeform_t *lf, int dir);
void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype); void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype);
void adjustspeedforwater(lifeform_t *lf, int *speed); void adjustspeedforwater(lifeform_t *lf, int *speed);
void age(lifeform_t *lf, int pct);
void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o); void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o);
int areallies(lifeform_t *lf1, lifeform_t *lf2); int areallies(lifeform_t *lf1, lifeform_t *lf2);
int areenemies(lifeform_t *lf1, lifeform_t *lf2); int areenemies(lifeform_t *lf1, lifeform_t *lf2);
@ -311,7 +312,7 @@ void stopeating(lifeform_t *lf);
void stopresting(lifeform_t *lf); void stopresting(lifeform_t *lf);
void stoprunning(lifeform_t *lf); void stoprunning(lifeform_t *lf);
void stopsprinting(lifeform_t *lf); void stopsprinting(lifeform_t *lf);
lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, int randomjobsok, job_t *forcejob, int lifetime, int wantfriendly); lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, char *racename, int lifetime, int wantfriendly);
//int testammo(lifeform_t *lf, object_t *o); //int testammo(lifeform_t *lf, object_t *o);
int takeoff(lifeform_t *lf, object_t *o); int takeoff(lifeform_t *lf, object_t *o);
void taketime(lifeform_t *lf, long howlong); void taketime(lifeform_t *lf, long howlong);

209
map.c
View File

@ -1,4 +1,5 @@
#include <assert.h> #include <assert.h>
#include <ctype.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -15,15 +16,20 @@
#include "vault.h" #include "vault.h"
extern habitat_t *firsthabitat,*lasthabitat; extern habitat_t *firsthabitat,*lasthabitat;
extern job_t *firstjob;
extern map_t *firstmap,*lastmap; extern map_t *firstmap,*lastmap;
extern region_t *firstregion,*lastregion; extern region_t *firstregion,*lastregion;
extern regionoutline_t *firstregionoutline,*lastregionoutline; extern regionoutline_t *firstregionoutline,*lastregionoutline;
extern regiontype_t *firstregiontype,*lastregiontype; extern regiontype_t *firstregiontype,*lastregiontype;
extern celltype_t *firstcelltype, *lastcelltype; extern celltype_t *firstcelltype, *lastcelltype;
extern objecttype_t *objecttype,*lastobjecttype; extern objecttype_t *objecttype,*lastobjecttype;
extern race_t *firstrace;
extern int viewx,viewy,vieww,viewh; extern int viewx,viewy,vieww,viewh;
extern lifeform_t *player; extern lifeform_t *player;
extern lifeform_t *godlf[];
extern int ngodlfs;
extern glyph_t tempglyph; extern glyph_t tempglyph;
extern enum OBCLASS sortorder[]; extern enum OBCLASS sortorder[];
@ -148,10 +154,14 @@ map_t *addmap(void) {
// when monsters are made during level generation, autogen will be true. otherwise false; // when monsters are made during level generation, autogen will be true. otherwise false;
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int autogen, int *nadded) { // if "rid" RR_NONE, paste racename to get the race.
// otherwise just use the given race.
lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int amt, int autogen, int *nadded) {
lifeform_t *lf = NULL; lifeform_t *lf = NULL;
race_t *r; race_t *r;
int db = B_FALSE; int db = B_FALSE;
flagpile_t *wantflags = NULL;
enum JOB wantjob = J_NONE;
if (nadded) *nadded = 0; if (nadded) *nadded = 0;
@ -160,21 +170,31 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
return NULL; return NULL;
} }
if ((raceid == R_NONE) || (raceid == R_RANDOM)) { if (rid != R_SPECIFIED) {
r = getrandomrace(c, NA); if (rid == R_RANDOM) {
r = getrandomrace(c, NA);
} else {
r = findrace(rid);
}
} else { } else {
r = findrace(raceid); // get params
wantflags = addflagpile(NULL, NULL);
rid = parserace(racename, wantflags, &wantjob);
if (rid == R_RANDOM) {
r = getrandomrace(c, NA);
} else {
r = findrace(rid);
}
} }
if (!r) { if (!r) {
r = getreallyrandomrace(RC_ANY); return NULL;
} }
assert(r);
if (db) { if (db) {
char buf[BUFLEN]; char buf[BUFLEN];
sprintf(buf, "start addmonster for %s",r->name); sprintf(buf, "addmonster for '%s'->%s",racename, r->name);
dbtimestart(buf); dbtimestart(buf);
} }
@ -182,6 +202,18 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
if (r) { if (r) {
if (db) dbtime("doing lf addition"); if (db) dbtime("doing lf addition");
if (hasflag(r->flags, F_UNIQUE)) {
// does it already exist?
lf = findlfunique(rid);
// if so, move it here, then exit.
if (lf) {
teleportto(lf, c, B_FALSE);
return lf;
}
}
lf = addlf(c, r->id, getrandommonlevel(r, c->map)); lf = addlf(c, r->id, getrandommonlevel(r, c->map));
if (db) dbtime("finished lf addition"); if (db) dbtime("finished lf addition");
if (lf) { if (lf) {
@ -191,24 +223,28 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
if (db) dbtime("checking for job"); if (db) dbtime("checking for job");
lf->born = B_FALSE; lf->born = B_FALSE;
if (jobok) {
for (f = lf->flags->first ; f ; f = f->next) { if (wantjob == J_NONE) {
// has a job? if (jobok) {
if (f->id == F_STARTJOB) { for (f = lf->flags->first ; f ; f = f->next) {
if (rnd(1,100) <= f->val[0]) { // has a job?
enum JOB wantjob; if (f->id == F_STARTJOB) {
if (f->val[1] == J_RANDOM) { if (rnd(1,100) <= f->val[0]) {
job_t *j; if (f->val[1] == J_RANDOM) {
j = getrandomjob(B_TRUE); job_t *j;
wantjob = j->id; j = getrandomjob(B_TRUE);
} else { wantjob = j->id;
wantjob = f->val[1]; } else {
wantjob = f->val[1];
}
givejob(lf, wantjob);
break;
} }
givejob(lf, wantjob);
break;
} }
} }
} }
} else {
givejob(lf, wantjob);
} }
if (autogen) { if (autogen) {
@ -360,11 +396,21 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
} }
} }
} }
if (wantflags) {
// wantflags?
copyflags(lf->flags, wantflags, NA);
}
lf->born = B_TRUE; lf->born = B_TRUE;
} // end if lf } // end if lf
} }
// free mem
if (wantflags) {
killflagpile(wantflags);
}
if (db) dbtimeend("finished addmonster"); if (db) dbtimeend("finished addmonster");
return lf; return lf;
@ -401,7 +447,7 @@ int addrandomthing(cell_t *c, int obchance, int *nadded) {
} }
} else { } else {
// monster // monster
if (addmonster(c, R_RANDOM, B_TRUE, 1, B_TRUE, nadded)) { if (addmonster(c, R_RANDOM, NULL, B_TRUE, 1, B_TRUE, nadded)) {
rv = TT_MONSTER; rv = TT_MONSTER;
} }
} }
@ -1907,16 +1953,53 @@ void createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir, object_
case H_VILLAGE: case H_VILLAGE:
createforest(map, depth, parentmap, exitdir, entryob, 0); createforest(map, depth, parentmap, exitdir, entryob, 0);
break; break;
case H_HEAVEN:
createheaven(map, depth, parentmap, exitdir, entryob);
break;
case H_PIT: case H_PIT:
createpit(map, depth, parentmap, exitdir, entryob); createpit(map, depth, parentmap, exitdir, entryob);
break; break;
break;
default: default:
dblog("ERROR - createhabitat with invalid habitat!"); dblog("ERROR - createhabitat with invalid habitat!");
msg("ERROR - createhabitat with invalid habitat!"); msg("ERROR - createhabitat with invalid habitat!");
} }
} }
void createheaven(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) {
int x,y;
enum CELLTYPE emptycell;
cell_t *c;
race_t *r;
lifeform_t *lf;
//object_t *o;
// what kind of cells will 'empty' ones be?
emptycell = map->habitat->emptycelltype;
// fill entire maze with corridors
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
c = addcell(map, x, y);
setcelltype(c, emptycell);
}
}
// add one of each god.
for (r = firstrace ; r ; r = r->next) {
if (r->raceclass->id == RC_GOD) {
// find a position
c = getrandomcell(map);
while (!cellwalkable(NULL, c, NULL)) {
c = getrandomcell(map);
}
// place god
lf = addmonster(c, r->id, NULL, B_FALSE, 1, B_FALSE, NULL);
assert(lf);
// add to god list
godlf[ngodlfs++] = lf;
}
}
}
/* /*
seed = random number seed seed = random number seed
@ -2297,7 +2380,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
// village guards // village guards
for (i = 0; i < 1; i++) { for (i = 0; i < 1; i++) {
if ((c->x == guardx[dir][i]) && (c->y == guardy[dir][i])) { if ((c->x == guardx[dir][i]) && (c->y == guardy[dir][i])) {
addmonster(c, R_TOWNGUARD, B_FALSE, 1, B_TRUE, NULL); addmonster(c, R_TOWNGUARD, NULL, B_FALSE, 1, B_TRUE, NULL);
} }
} }
} }
@ -2371,25 +2454,25 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
int thisx,thisy; int thisx,thisy;
getmapcoords(m, &thisx, &thisy); getmapcoords(m, &thisx, &thisy);
if (map->nextmap[D_N] == -1) { if (map->nextmap[D_N] == -1) {
if (thisy == (y - 1)) { if ((thisy == (y - 1)) && (thisx == x)) {
map->nextmap[D_N] = m->id; map->nextmap[D_N] = m->id;
if (db) dblog(" linked to map %d (dir N)",m->id); if (db) dblog(" linked to map %d (dir N)",m->id);
} }
} }
if (map->nextmap[D_E] == -1) { if (map->nextmap[D_E] == -1) {
if (thisx == (x + 1)) { if ((thisx == (x + 1)) && (thisy == y)) {
map->nextmap[D_E] = m->id; map->nextmap[D_E] = m->id;
if (db) dblog(" linked to map %d (dir E)",m->id); if (db) dblog(" linked to map %d (dir E)",m->id);
} }
} }
if (map->nextmap[D_S] == -1) { if (map->nextmap[D_S] == -1) {
if (thisy == (y + 1)) { if ((thisy == (y + 1)) && (thisx == x)) {
map->nextmap[D_S] = m->id; map->nextmap[D_S] = m->id;
if (db) dblog(" linked to map %d (dir S)",m->id); if (db) dblog(" linked to map %d (dir S)",m->id);
} }
} }
if (map->nextmap[D_W] == -1) { if (map->nextmap[D_W] == -1) {
if (thisx == (x - 1)) { if ((thisx == (x - 1)) && (thisy == y)) {
map->nextmap[D_W] = m->id; map->nextmap[D_W] = m->id;
if (db) dblog(" linked to map %d (dir W)",m->id); if (db) dblog(" linked to map %d (dir W)",m->id);
} }
@ -3324,6 +3407,9 @@ char *getregionname(char *buf, map_t *m, int withlevel) {
case RG_FIRSTDUNGEON: case RG_FIRSTDUNGEON:
sprintf(buf, "dungeon L%d", m->depth); sprintf(buf, "dungeon L%d", m->depth);
break; break;
case RG_HEAVEN:
sprintf(buf, "the realm of gods");
break;
case RG_PIT: case RG_PIT:
sprintf(buf, "a pit L%d", m->depth); sprintf(buf, "a pit L%d", m->depth);
break; break;
@ -3339,6 +3425,9 @@ char *getregionname(char *buf, map_t *m, int withlevel) {
case RG_FIRSTDUNGEON: case RG_FIRSTDUNGEON:
strcpy(buf, "a dungeon"); strcpy(buf, "a dungeon");
break; break;
case RG_HEAVEN:
sprintf(buf, "the realm of gods");
break;
case RG_PIT: case RG_PIT:
sprintf(buf, "a pit"); sprintf(buf, "a pit");
break; break;
@ -3654,8 +3743,9 @@ void initmap(void) {
int vx[4],vy[4],i; int vx[4],vy[4],i;
// habitats // habitats
// thingchance, obchance, vaultchance // thingchance, obchance, vaultchance
addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 10); addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 30);
addhabitat(H_FOREST, "forest", CT_GRASS, CT_WALL, 3, 75, 0); addhabitat(H_FOREST, "forest", CT_GRASS, CT_WALL, 3, 75, 0);
addhabitat(H_HEAVEN, "heaven", CT_CORRIDOR, CT_WALL, 0, 0, 0);
addhabitat(H_PIT, "pit", CT_CORRIDOR, CT_WALL, 0, 0, 0); addhabitat(H_PIT, "pit", CT_CORRIDOR, CT_WALL, 0, 0, 0);
addhabitat(H_VILLAGE, "village", CT_GRASS, CT_WALL, 3, 70, 0); addhabitat(H_VILLAGE, "village", CT_GRASS, CT_WALL, 3, 70, 0);
@ -3676,7 +3766,8 @@ void initmap(void) {
// region types // region types
addregiontype(RG_WORLDMAP, "World map", H_FOREST, 10, 0, D_NONE, B_TRUE); addregiontype(RG_WORLDMAP, "World map", H_FOREST, 10, 0, D_NONE, B_TRUE);
addregiontype(RG_FIRSTDUNGEON, "First Dungeon", H_DUNGEON, 20, 3, D_DOWN, B_TRUE); addregiontype(RG_FIRSTDUNGEON, "First Dungeon", H_DUNGEON, 10, 3, D_DOWN, B_TRUE);
addregiontype(RG_HEAVEN, "Realm of Gods", H_HEAVEN, 1, 0, D_NONE, B_FALSE);
addregiontype(RG_PIT, "Pit", H_PIT, 1, 1, D_DOWN, B_FALSE); addregiontype(RG_PIT, "Pit", H_PIT, 1, 1, D_DOWN, B_FALSE);
// region definitions (outlines) // region definitions (outlines)
@ -3709,7 +3800,7 @@ void initmap(void) {
//vx = 0; vy = -1; //vx = 0; vy = -1;
addregionoutline(RG_FIRSTDUNGEON); addregionoutline(RG_FIRSTDUNGEON);
addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair"); addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair");
addregionthing(lastregionoutline, 20, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISSHRINE, NULL); // godstone on last floor addregionthing(lastregionoutline, 10, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISSHRINE, NULL); // godstone on last floor
} }
int isadjacent(cell_t *src, cell_t *dst) { int isadjacent(cell_t *src, cell_t *dst) {
@ -3921,7 +4012,7 @@ int isonmap(map_t *map, int x, int y) {
} }
int isoutdoors(map_t *m) { int isoutdoors(map_t *m) {
if (m->region->rtype->id == RG_WORLDMAP) { if (m->region && m->region->rtype->id == RG_WORLDMAP) {
return B_TRUE; return B_TRUE;
} }
return B_FALSE; return B_FALSE;
@ -4222,12 +4313,58 @@ void mapentereffects(map_t *m) {
if (c->vault && streq(c->vault->id, "inn") && c->lf && (c->lf->race->id == R_HUMAN)) { if (c->vault && streq(c->vault->id, "inn") && c->lf && (c->lf->race->id == R_HUMAN)) {
lifeform_t *lf; lifeform_t *lf;
killlf(c->lf); killlf(c->lf);
lf = addmonster(c, R_HUMAN, B_TRUE, 1, B_FALSE, NULL); lf = addmonster(c, R_HUMAN, NULL, B_TRUE, 1, B_FALSE, NULL);
addflag(lf->flags, F_STAYINROOM, c->roomid, B_MAYCHASE, NA, NULL); addflag(lf->flags, F_STAYINROOM, c->roomid, B_MAYCHASE, NA, NULL);
} }
} }
} }
enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob) {
int donesomething;
char *p;
job_t *j;
// get params
donesomething = B_TRUE;
p = name;
while (donesomething) {
donesomething = B_FALSE;
if (strstarts(p, "sleeping ")) {
p += strlen("sleeping ");
if (wantflags) addflag(wantflags, F_ASLEEP, NA, NA, NA, NULL);
donesomething = B_TRUE;
}
}
// try removing suffixes for jobs
for (j = firstjob ; j ; j = j->next) {
char *ep;
char jobname[BUFLEN];
sprintf(jobname, " %s", j->name);
jobname[1] = tolower(jobname[1]);
ep = strends(name, jobname);
if (ep) {
// got it
if (wantjob) *wantjob = j->id;
// now strip the suffix off, starting at the space before it
*ep = '\0';
break;
}
}
// now get raceid
if (streq(p, "random")) {
return R_RANDOM;
} else {
race_t *r;
r = findracebyname(p);
if (r) {
return r->id;
}
}
return R_NONE;
}
void setcellknown(cell_t *cell, int forcelev) { void setcellknown(cell_t *cell, int forcelev) {
enum SKILLLEVEL slev; enum SKILLLEVEL slev;
object_t *o; object_t *o;

4
map.h
View File

@ -4,7 +4,7 @@ cell_t *addcell(map_t *map, int x, int y);
habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance); habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance);
void addhomeobs(lifeform_t *lf); void addhomeobs(lifeform_t *lf);
map_t *addmap(void); map_t *addmap(void);
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int autogen, int *nadded); lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int amt, int autogen, int *nadded);
object_t *addrandomob(cell_t *c); object_t *addrandomob(cell_t *c);
int addrandomthing(cell_t *c, int obchance, int *nadded); int addrandomthing(cell_t *c, int obchance, int *nadded);
region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid); region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid);
@ -39,6 +39,7 @@ int countcellexitsfor(lifeform_t *lf);
void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob); void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob);
void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob, int nclearings); void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob, int nclearings);
void createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob); void createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob);
void createheaven(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob);
void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int exitdir, object_t *entryob); void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int exitdir, object_t *entryob);
void createpit(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);
void createregionlink(map_t *m, cell_t *c, object_t *o, char *obname, enum REGIONTYPE newregiontype, region_t *parent); void createregionlink(map_t *m, cell_t *c, object_t *o, char *obname, enum REGIONTYPE newregiontype, region_t *parent);
@ -107,6 +108,7 @@ void makedoor(cell_t *cell, int openchance);
void makelit(cell_t *c, enum LIGHTLEV how, int howlong); void makelit(cell_t *c, enum LIGHTLEV how, int howlong);
void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong); void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong);
void mapentereffects(map_t *m); void mapentereffects(map_t *m);
enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob);
void setcellknown(cell_t *cell, int forcelev); void setcellknown(cell_t *cell, int forcelev);
void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype); void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype);
void setcelltype(cell_t *cell, enum CELLTYPE id); void setcelltype(cell_t *cell, enum CELLTYPE id);

13
nexus.c
View File

@ -33,6 +33,7 @@ job_t *firstjob = NULL,*lastjob = NULL;
skill_t *firstskill = NULL,*lastskill = NULL; skill_t *firstskill = NULL,*lastskill = NULL;
habitat_t *firsthabitat = NULL,*lasthabitat = NULL; habitat_t *firsthabitat = NULL,*lasthabitat = NULL;
map_t *firstmap = NULL,*lastmap = NULL; map_t *firstmap = NULL,*lastmap = NULL;
map_t *heaven = NULL;
region_t *firstregion = NULL,*lastregion = NULL; region_t *firstregion = NULL,*lastregion = NULL;
regionoutline_t *firstregionoutline = NULL,*lastregionoutline = NULL; regionoutline_t *firstregionoutline = NULL,*lastregionoutline = NULL;
regiontype_t *firstregiontype = NULL,*lastregiontype = NULL; regiontype_t *firstregiontype = NULL,*lastregiontype = NULL;
@ -187,19 +188,23 @@ int main(int argc, char **argv) {
// if no maps (ie. ALWAYS now that maps aren't persistent), // if no maps (ie. ALWAYS now that maps aren't persistent),
// make the initial level // make the initial level
if (!firstmap) { if (!firstmap) {
region_t *wregion, *dregion; region_t *wregion, *dregion,*hregion;
newworld = B_TRUE; newworld = B_TRUE;
// create world map. // create world map.
wregion = addregion(RG_WORLDMAP, NULL, -1); wregion = addregion(RG_WORLDMAP, NULL, -1);
assert(wregion); assert(wregion);
addmap(); addmap();
createmap(firstmap, 1, wregion, NULL, D_NONE, NULL); createmap(firstmap, 1, wregion, NULL, D_NONE, NULL);
//createmap(firstmap, 1, RG_FIRSTDUNGEON, H_DUNGEON, NULL, D_NONE);
// create first dungeon // create first dungeon
dregion = findregionbytype(RG_FIRSTDUNGEON); dregion = findregionbytype(RG_FIRSTDUNGEON);
assert(dregion); assert(dregion);
dmap = addmap(); dmap = addmap();
createmap(dmap, 1, dregion, firstmap, D_DOWN, NULL); createmap(dmap, 1, dregion, firstmap, D_DOWN, NULL);
// create heaven
hregion = addregion(RG_HEAVEN, NULL, -1);
assert(hregion);
heaven = addmap();
createmap(heaven, 1, hregion, NULL, D_NONE, NULL);
} }
// find staircase // find staircase
@ -214,6 +219,9 @@ int main(int argc, char **argv) {
where = real_getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL); where = real_getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL);
real_addlf(where, R_HUMAN, 1, C_PLAYER); // this will assign 'player' real_addlf(where, R_HUMAN, 1, C_PLAYER); // this will assign 'player'
// add abilities which the player always has
addflag(player->flags, F_CANWILL, OT_A_PRAY, NA, NA, NULL);
user = getenv("USER"); user = getenv("USER");
if (user) { if (user) {
char pname[MAXPNAMELEN]; char pname[MAXPNAMELEN];
@ -249,7 +257,6 @@ int main(int argc, char **argv) {
} }
// read cheat info from player file // read cheat info from player file
if (playerfile) { if (playerfile) {
if (parseplayerfile(playerfile, player)) { if (parseplayerfile(playerfile, player)) {

108
objects.c
View File

@ -7,6 +7,7 @@
#include "attack.h" #include "attack.h"
#include "defs.h" #include "defs.h"
#include "flag.h" #include "flag.h"
#include "god.h"
#include "io.h" #include "io.h"
#include "lf.h" #include "lf.h"
#include "map.h" #include "map.h"
@ -2149,7 +2150,6 @@ int canbepoisoned(enum OBTYPE oid) {
if (hasflagval(ot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL)) { if (hasflagval(ot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL)) {
return B_TRUE; return B_TRUE;
} }
return B_FALSE; return B_FALSE;
} }
@ -6688,7 +6688,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_ADJSELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_ADJSELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CALLWIND, "call wind", "Conjures a friendly wind, carrying a single object to the caster's hands.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_CALLWIND, "zephyr", "Conjures a friendly wind, carrying a single object to the caster's hands.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
@ -6702,7 +6702,7 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
// l2 // l2
addot(OT_S_GUSTOFWIND, "gust of wind", "Causes a gust of wind to blow the target's objects away.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_GUSTOFWIND, "gust of wind", "Causes a gust of wind to blow up to ^bpower^n of the target's objects away.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
@ -6898,15 +6898,17 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); 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_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l3 // l3
addot(OT_S_CALLLIGHTNING, "call lightning", "Blasts a single enemy with a bolt of lightning from the sky.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_CALLLIGHTNING, "call lightning", "Blasts a single enemy with a bolt of lightning from the sky, dealing 3d6 damage (4d6 if outdoors).", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_LIGHTNINGBOLT, "lightning bolt", "Fires electricity through multiple enemies.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_LIGHTNINGBOLT, "electricity bolt", "Fires a bolt of electricity through multiple enemies, dealing 2d6 damage to each.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_ENDUREELEMENTS, "endure elements", "Provides resistance to fire and cold.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_ENDUREELEMENTS, "endure elements", "Provides resistance to fire and cold.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
@ -6973,6 +6975,11 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SATEHUNGER, "sate hunger", "Immediately satisfies the hunger of one living creature.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 10, NA, NA, NULL);
addot(OT_S_SUMMONANIMALSMD, "summon medium animals", "Summons 2-3 medium animals.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_SUMMONANIMALSMD, "summon medium animals", "Summons 2-3 medium animals.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
@ -7092,12 +7099,6 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_HUNGER, "hunger", "Causes the target to become revenously hungry.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l3 // l3
addot(OT_S_PSYARMOUR, "psychic armour", "Mentally block incoming attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_PSYARMOUR, "psychic armour", "Mentally block incoming attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
@ -7111,6 +7112,12 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_HUNGER, "hunger", "Causes the target to become ravenously hungry.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l4 // l4
addot(OT_S_SLEEP, "sleep", "Puts the target creature to sleep.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_SLEEP, "sleep", "Puts the target creature to sleep.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
@ -7254,6 +7261,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
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_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l6 // l6
addot(OT_S_GATE, "gate", "Creates a portal to a different dungeon level.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_GATE, "gate", "Creates a portal to a different dungeon level.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
@ -7375,7 +7383,7 @@ void initobjects(void) {
addot(OT_A_HURRICANESTRIKE, "hurricane strike", "A sweeping attack aginst everything nearby.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_HURRICANESTRIKE, "hurricane strike", "A sweeping attack aginst everything nearby.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addot(OT_A_INSPECT, "inspect", "Try to identify an unknown object from your pack.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_INSPECT, "inspect", "Try to identify an unknown scroll, book, wand or ring from your pack.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_JUMP, "jump", "You can leap large distances.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_JUMP, "jump", "You can leap large distances.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
@ -7384,6 +7392,8 @@ void initobjects(void) {
addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL);
addot(OT_A_QUIVERINGPALM, "quivering palm", "A deadly palm strike which knocks the molecules in the target's body out of alignment.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_QUIVERINGPALM, "quivering palm", "A deadly palm strike which knocks the molecules in the target's body out of alignment.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_PRAY, "pray", "Ask for help from a higher being.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_RAGE, "rage", "Enter a state of berzerker rage, gaining attack and defence bonuses.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_RAGE, "rage", "Enter a state of berzerker rage, gaining attack and defence bonuses.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
@ -8186,6 +8196,17 @@ void initobjects(void) {
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers"); addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out"); addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out");
addot(OT_COFFIN, "coffin", "A wooden coffin, made for holding the dead.", MT_WOOD, 100, OC_FURNITURE, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "|");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOB, 80, NA, NA, "3-4 piles of ash");
addflag(lastot->flags, F_STARTOB, 80, NA, NA, "5-10 bones");
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addot(OT_FIREPLACE, "fireplace", "A roaring fireplace.", MT_STONE, 200, OC_FURNITURE, SZ_LARGE); addot(OT_FIREPLACE, "fireplace", "A roaring fireplace.", MT_STONE, 200, OC_FURNITURE, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "\\"); addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "\\");
addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, IFACTIVE, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, IFACTIVE, NULL);
@ -8691,7 +8712,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL); addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -4, NA, NULL);
addot(OT_GOLDCROWN, "golden crown", "A heavy gold crown, encrusted with jewels.", MT_GOLD, 5, OC_ARMOUR, SZ_SMALL); addot(OT_GOLDCROWN, "golden crown", "A heavy gold crown, encrusted with jewels.", MT_GOLD, 5, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 25, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 25, RR_RARE, NULL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
@ -8712,7 +8733,8 @@ void initobjects(void) {
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -4, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_NIGHTVISRANGEMOD, -2, NA, NULL);
addflag(lastot->flags, F_TINTED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TINTED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addot(OT_EYEPATCH, "eyepatch", "A small patch of black material which covers one eye. Scary looking.", MT_CLOTH, 0.01, OC_ARMOUR, SZ_SMALL); addot(OT_EYEPATCH, "eyepatch", "A small patch of black material which covers one eye. Scary looking.", MT_CLOTH, 0.01, OC_ARMOUR, SZ_SMALL);
@ -8721,6 +8743,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_SCARY, 2, NA, NA, NULL); addflag(lastot->flags, F_SCARY, 2, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL);
// armour - shields // armour - shields
@ -8765,7 +8788,7 @@ void initobjects(void) {
addot(OT_RING_SIGHT, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING, SZ_MINI); addot(OT_RING_SIGHT, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, ""); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINVIS, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SEEINVIS, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 3, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 2, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, 1, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, 1, NA, NULL);
addot(OT_RING_MANA, "ring of mana", "Increases the wearer's MP pool.", MT_METAL, 0.1, OC_RING, SZ_MINI); addot(OT_RING_MANA, "ring of mana", "Increases the wearer's MP pool.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, ""); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
@ -8825,7 +8848,7 @@ void initobjects(void) {
addflag(lastot->flags, F_EQUIPCONFER, F_RESISTMAG, 5, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_RESISTMAG, 5, NA, NULL);
addot(OT_RING_MIRACLES, "ring of miracles", "Grants a limited number of miracles to the wearer.", MT_METAL, 0.1, OC_RING, SZ_MINI); addot(OT_RING_MIRACLES, "ring of miracles", "Grants a limited number of miracles to the wearer.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 40, NA, ""); addflag(lastot->flags, F_RARITY, H_ALL, 40, NA, "");
addflag(lastot->flags, F_CHARGES, 3, 3, NA, NULL); addflag(lastot->flags, F_CHARGES, 1, 3, NA, NULL);
// unarmed weapons - note these damage/accuracys can be // unarmed weapons - note these damage/accuracys can be
// overridded with the lifeform flag F_HASATTACK // overridded with the lifeform flag F_HASATTACK
@ -8919,7 +8942,8 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addot(OT_TOUCHPARALYZE, "paralyzing touch", "paralyzing touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addot(OT_TOUCHPARALYZE, "paralyzing touch", "paralyzing touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_TOUCH, NA, NA, "0d1"); addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_DAM, DT_TOUCH, NA, NA, "1d1");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 22, "2-4"); addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 22, "2-4");
addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL);
@ -8927,7 +8951,8 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
addot(OT_TOUCHPARALYZE2, "strong paralyzing touch", "strong paralyzing touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addot(OT_TOUCHPARALYZE2, "strong paralyzing touch", "strong paralyzing touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY);
addflag(lastot->flags, F_DAM, DT_TOUCH, NA, NA, "0d1"); addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_DAM, DT_TOUCH, NA, NA, "1d1");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 30, "5-10"); addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 30, "5-10");
addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL);
@ -11288,7 +11313,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
case 0: // butterflies around user case 0: // butterflies around user
willid = B_TRUE; willid = B_TRUE;
where = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND); where = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND);
addmonster(where, R_BUTTERFLY, B_FALSE, rnd(10,20), B_FALSE, NULL); addmonster(where, R_BUTTERFLY, NULL, B_FALSE, rnd(10,20), B_FALSE, NULL);
if (haslos(player, where)) { if (haslos(player, where)) {
msg("A swarm of butterflies appears!"); msg("A swarm of butterflies appears!");
} }
@ -11964,6 +11989,15 @@ int pour(lifeform_t *lf, object_t *o) {
blessob(dst); blessob(dst);
// we now know that this is holy water // we now know that this is holy water
if (!isknown(o)) makeknown(o->type->id); if (!isknown(o)) makeknown(o->type->id);
} else if ((o->type->id == OT_POT_WATER) && (o->blessed == B_CURSED)) { // unholy water
if (isplayer(lf)) {
msg("You pour %s onto %s.", obname,dstname);
}
o->blessknown = B_TRUE;
// bless whatever we poured onto
curseob(dst);
// we now know that this is holy water
if (!isknown(o)) makeknown(o->type->id);
} else if (o->type->id == OT_POT_INVULN) { } else if (o->type->id == OT_POT_INVULN) {
flag_t *f; flag_t *f;
f = hasflag(dst->flags, F_DAMAGABLE); f = hasflag(dst->flags, F_DAMAGABLE);
@ -12582,14 +12616,14 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
} }
losehp(lf, rnd(5,15), DT_HOLY, NULL, "drinking holy water"); losehp(lf, rnd(5,15), DT_HOLY, NULL, "drinking holy water");
} else { } else {
msg("Mmm, holy water."); if (isplayer(lf)) msg("Mmm, holy water.");
} }
break; break;
case B_UNCURSED: case B_UNCURSED:
msg("Mmm, water."); if (isplayer(lf)) msg("Mmm, water.");
break; break;
case B_CURSED: case B_CURSED:
msg("Yuck! Something is wrong with this water."); if (isplayer(lf)) msg("Yuck! Something is wrong with this water.");
break; break;
} }
if (seen) { if (seen) {
@ -12600,14 +12634,25 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
modhunger(lf, -pctof(0.05, (float)HUNGERCONST)); modhunger(lf, -pctof(0.05, (float)HUNGERCONST));
break; break;
case OT_POT_BLOOD: case OT_POT_BLOOD:
msg("Yuck, this tastes like blood!"); if (lf->race->id == R_VAMPIRE) {
int b = B_UNCURSED;
if (isplayer(lf)) msg("This blood is delicious!");
if (potblessed == B_BLESSED) {
b = B_CURSED;
} else if (potblessed == B_CURSED) {
b = B_BLESSED;
}
dospelleffects(lf, OT_S_HEALINGMAJ,b ? 5 : 1, lf, NULL, lf->cell, b, seen, B_TRUE);
} else {
if (isplayer(lf)) msg("Yuck, this tastes like blood!");
}
break; break;
case OT_POT_BLOODC: case OT_POT_BLOODC:
f = lfhasflag(lf, F_BEINGSTONED); f = lfhasflag(lf, F_BEINGSTONED);
if (f) { if (f) {
killflag(f); killflag(f);
} else { } else {
msg("Yuck, this tastes like oddly-flavoured blood!"); if (isplayer(lf)) msg("Yuck, this tastes like oddly-flavoured blood!");
} }
break; break;
case OT_POT_JUICE: case OT_POT_JUICE:
@ -13517,6 +13562,19 @@ int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
addflag(o->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(o->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
if (fromlf && isplayer(fromlf)) {
switch (o->type->id) {
case OT_POT_HEALING:
case OT_POT_HEALINGMIN:
case OT_POT_HEALINGMAJ:
case OT_POT_AMBROSIA:
angergodmaybe(R_GODMERCY, 25);
break;
default:
break;
}
}
return B_TRUE; return B_TRUE;
} }
@ -15017,7 +15075,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf) {
// can't be dodged // can't be dodged
c = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND); c = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND);
if (c) { if (c) {
summonmonster(NULL, c, R_NONE, B_TRUE, NULL, PERMENANT, B_FALSE); summonmonster(NULL, c, R_SPECIFIED, "random", PERMENANT, B_FALSE);
} }
if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards

4
save.c
View File

@ -1035,12 +1035,12 @@ int showhiscores(lifeform_t *lf, int min, int max) {
sprintf(hilitescoretext, "%ld",hilitescore); sprintf(hilitescoretext, "%ld",hilitescore);
rc = sqlite3_exec(db, cmd, showhiscoreline, hilitescoretext, &errmsg); rc = sqlite3_exec(db, cmd, showhiscoreline, hilitescoretext, &errmsg);
free(cmd);
if (rc != SQLITE_OK) { if (rc != SQLITE_OK) {
msg("error writing hiscores: '%s'", errmsg); msg("error writing hiscores: '%s'", errmsg);
dblog("error writing hiscores: '%s'", errmsg); dblog("error writing hiscores: '%s'\n sql command: [%s]", errmsg, cmd);
sqlite3_free(errmsg); sqlite3_free(errmsg);
} }
free(cmd);
sqlite3_close(db); sqlite3_close(db);
return B_FALSE; return B_FALSE;

367
spell.c
View File

@ -7,6 +7,7 @@
#include "attack.h" #include "attack.h"
#include "defs.h" #include "defs.h"
#include "flag.h" #include "flag.h"
#include "god.h"
#include "io.h" #include "io.h"
#include "lf.h" #include "lf.h"
#include "map.h" #include "map.h"
@ -19,6 +20,8 @@
extern lifeform_t *player; extern lifeform_t *player;
extern skill_t *firstskill, *lastskill; extern skill_t *firstskill, *lastskill;
extern race_t *firstrace, *lastrace; extern race_t *firstrace, *lastrace;
extern map_t *heaven;
extern region_t *firstregion;
extern knowledge_t *knowledge; extern knowledge_t *knowledge;
extern int needredraw; extern int needredraw;
@ -36,6 +39,9 @@ extern object_t *retobs[MAXPILEOBS+1];
extern int retobscount[MAXPILEOBS+1]; extern int retobscount[MAXPILEOBS+1];
extern int nretobs; extern int nretobs;
extern lifeform_t *godlf[];
extern int ngodlfs;
extern enum ERROR reason; extern enum ERROR reason;
extern int needredraw, statdirty; extern int needredraw, statdirty;
@ -1250,7 +1256,34 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// this call will also remove this ability... // this call will also remove this ability...
setrace(user, f->val[0], B_TRUE); setrace(user, f->val[0], B_TRUE);
} else if (abilid == OT_A_PRAY) {
lifeform_t *lf;
char buf[BUFLEN];
int i;
if (!isplayer(user)) return B_FALSE;
// ask for which god
initprompt(&prompt, "To whom will you pray?");
prompt.maycancel = B_TRUE;
for (i = 0 ; i < ngodlfs; i++) {
flag_t *f;
char godof[BUFLEN];
lf = godlf[i];
real_getlfname(lf, buf, B_FALSE);
f = hasflag(lf->flags, F_GODOF);
sprintf(godof, " (%s of %s)", (f->val[0] == B_FEMALE) ? "Goddess" : "God", f->text);
strcat(buf, godof);
addchoice(&prompt, 'a', buf, NULL, lf);
}
getchoicestr(&prompt, B_FALSE, B_TRUE);
lf = (lifeform_t *)prompt.result;
if (!lf) {
msg("Cancelled.");
return B_TRUE;
}
prayto(user, lf);
} else if (abilid == OT_A_LEARN) { } else if (abilid == OT_A_LEARN) {
skill_t *sk; skill_t *sk;
char ch = 'a'; char ch = 'a';
@ -1995,9 +2028,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int i; int i;
object_t *o,*nexto; object_t *o,*nexto;
int donesomething = B_FALSE; int donesomething = B_FALSE;
// animate corpses within los of caster if (isplayer(caster)) {
for (i = 0; i < caster->nlos; i++) { target = caster;
targcell = caster->los[i]; }
// animate corpses within lof of caster
for (i = 0; i < target->nlos; i++) {
targcell = target->los[i];
for (o = targcell->obpile->first ; o ; o = nexto) { for (o = targcell->obpile->first ; o ; o = nexto) {
nexto = o->next; nexto = o->next;
if (o->type->id == OT_CORPSE) { if (o->type->id == OT_CORPSE) {
@ -2140,30 +2176,42 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// can't see anywhere // can't see anywhere
fizzle(caster); fizzle(caster);
} else { } else {
int tries = 0,maxtries = 10;
if (lfhasflag(caster, F_CONTROL) && (power < 6)) { if (lfhasflag(caster, F_CONTROL) && (power < 6)) {
power = 6; power = 6;
} }
if (power >= 6) { if (power >= 6) {
// controlled // controlled
// must be within line of sight.
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (!targcell) { if (!targcell) {
fizzle(caster); fizzle(caster);
return B_TRUE; return B_TRUE;
} }
} else { } else {
cell_t *poss[MAXCANDIDATES];
int nposs = 0,x,y;
// pick a random location // pick a random location
targcell = NULL; // only needs to be in line-of-FIRE, not neccesarily sight.
while (!targcell || !cellwalkable(caster, targcell, NULL) || celldangerous(caster, targcell, B_FALSE, NULL)) { for (y = 0 ; y <= caster->cell->map->h; y++) {
int i; for (x = 0 ; x <= caster->cell->map->w; x++) {
i = rnd(0,caster->nlos-1); cell_t *c;
targcell = caster->los[i]; c = getcellat(caster->cell->map, x, y);
tries++; if (c && haslof(caster->cell, c, LOF_WALLSTOP, NULL)) {
if (tries >= maxtries) { if (cellwalkable(caster, targcell, NULL) &&
fizzle(caster); !celldangerous(caster, targcell, B_FALSE, NULL)) {
return B_FALSE; poss[nposs++] = c;
}
}
if (nposs >= MAXCANDIDATES) break;
} }
if (nposs >= MAXCANDIDATES) break;
} }
if (!nposs) {
fizzle(caster);
return B_TRUE;
}
targcell = poss[rnd(0,nposs-1)];
} }
teleportto(caster, targcell, B_TRUE); teleportto(caster, targcell, B_TRUE);
} }
@ -2231,58 +2279,65 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
needredraw = B_TRUE; needredraw = B_TRUE;
} }
} else if (spellid == OT_S_CONFISCATE) { } else if (spellid == OT_S_CONFISCATE) {
object_t *o;
char ch = 'a'; char ch = 'a';
char obname[BUFLEN]; char obname[BUFLEN];
// ask for a target cell if (targob) {
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; target = targob->pile->owner;
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_FALSE;
}
// take an object
initprompt(&prompt, "Confiscate which object?");
addchoice(&prompt, '-', "(Cancel)", NULL, NULL);
for (o = target->pack->first ; o ; o = o->next) {
getobname(o, obname, o->amt);
addchoice(&prompt, ch, obname, NULL, o);
if (ch == 'z') {
ch = 'A';
} else {
ch++;
}
}
if (isplayer(caster)) {
// select one
getchoice(&prompt);
o = (object_t *)prompt.result;
} else { } else {
// random one object_t *o;
o = (object_t *) prompt.choice[rnd(0,prompt.nchoices-1)].data; // ask for a target cell
} if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (o) {
if (isplayer(target)) { target = targcell->lf;
getobname(o, obname, o->amt); if (!target) {
msg("^%cYour %s vanish%s!", getlfcol(target, CC_VBAD), noprefix(obname), (o->amt == 1) ? "es" : ""); fizzle(caster);
if (seenbyplayer) *seenbyplayer = B_TRUE; return B_FALSE;
} else if (isplayer(caster)) {
char targname[BUFLEN];
getlfname(target, targname);
getobname(o, obname, o->amt);
msg("%s%s %s appear%s in your pack!", targname, getpossessive(targname),
noprefix(obname), (o->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) {
char targname[BUFLEN];
getlfname(target, targname);
getobname(o, obname, o->amt);
msg("^%c%s%s %s vanish%s!", getlfcol(target, CC_VBAD), targname, getpossessive(targname), noprefix(obname),
(o->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
moveob(o, caster->pack, ALL);
// which object to take?
initprompt(&prompt, "Confiscate which object?");
addchoice(&prompt, '-', "(Cancel)", NULL, NULL);
for (o = target->pack->first ; o ; o = o->next) {
getobname(o, obname, o->amt);
addchoice(&prompt, ch, obname, NULL, o);
if (ch == 'z') {
ch = 'A';
} else {
ch++;
}
}
if (isplayer(caster)) {
// select one
getchoice(&prompt);
targob = (object_t *)prompt.result;
} else {
// random one
targob = (object_t *) prompt.choice[rnd(0,prompt.nchoices-1)].data;
}
}
if (targob) {
if (target) {
if (isplayer(target)) {
getobname(targob, obname, targob->amt);
msg("^%cYour %s vanish%s!", getlfcol(target, CC_VBAD), noprefix(obname), (targob->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (isplayer(caster)) {
char targname[BUFLEN];
getlfname(target, targname);
getobname(targob, obname, targob->amt);
msg("%s%s %s appear%s in your pack!", targname, getpossessive(targname),
noprefix(obname), (targob->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) {
char targname[BUFLEN];
getlfname(target, targname);
getobname(targob, obname, targob->amt);
msg("^%c%s%s %s vanish%s!", getlfcol(target, CC_VBAD), targname, getpossessive(targname), noprefix(obname),
(targob->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
}
moveob(targob, caster->pack, ALL);
} else { } else {
fizzle(caster); fizzle(caster);
} }
@ -2809,9 +2864,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_CREATEMONSTER) { } else if (spellid == OT_S_CREATEMONSTER) {
lifeform_t *newlf; lifeform_t *newlf;
job_t *forcejob = NULL;
race_t *r = NULL; race_t *r = NULL;
int randomjobsok = B_TRUE;
if (!targcell) { if (!targcell) {
if ((power >= 5) && isplayer(caster)) { if ((power >= 5) && isplayer(caster)) {
@ -2836,52 +2889,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if ((power >= 7) && isplayer(caster)) { if ((power >= 7) && isplayer(caster)) {
// ask what kind of monster // ask what kind of monster
askstring("Create what kind of monster", '?', buf, BUFLEN, NULL); askstring("Create what kind of monster", '?', buf, BUFLEN, NULL);
r = findracebyname(buf);
// not found - are we asking for a job with the monster?
if (!r) {
job_t *j;
// try removing suffixes
for (j = firstjob ; j ; j = j->next) {
char *p;
char jobname[BUFLEN];
strcpy(jobname, j->name);
jobname[0] = tolower(jobname[0]);
p = strstr(buf, jobname);
if (p) {
if (p == buf) {
// just asked for the job name
// fail.
break;
} else {
char newbuf[BUFLEN];
strncpy(newbuf, buf, (p - buf) - 1);
r = findracebyname(newbuf);
if (r) {
forcejob = j;
break;
}
}
}
}
}
if (!r) {
fizzle(caster);
return B_TRUE;
}
} else { } else {
// random one
r = getreallyrandomrace(RC_ANY); r = getreallyrandomrace(RC_ANY);
} sprintf(buf, "%s", r->name);
if (forcejob) {
randomjobsok = B_FALSE;
} else {
randomjobsok = B_TRUE;
} }
// add the monster // add the monster
newlf = summonmonster(caster, targcell, r->id, randomjobsok, forcejob, PERMENANT, B_FALSE); newlf = summonmonster(caster, targcell, R_SPECIFIED, buf, PERMENANT, B_FALSE);
if (newlf) { if (newlf) {
if (haslos(player, targcell)) { if (haslos(player, targcell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -2952,6 +2966,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (cansee(player, target)) { if (cansee(player, target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
if (isplayer(caster) && !frompot) {
pleasegodmaybe(R_GODMERCY, 3);
}
} else if (spellid == OT_S_DARKNESS) { } else if (spellid == OT_S_DARKNESS) {
if (!targcell) targcell = caster->cell; if (!targcell) targcell = caster->cell;
// centre on the caster // centre on the caster
@ -3008,7 +3025,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
o->blessknown = B_TRUE; o->blessknown = B_TRUE;
} }
} else { } else {
nothinghappens(); if (isplayer(caster)) nothinghappens();
} }
} else { } else {
// monsters can't use this // monsters can't use this
@ -3363,6 +3380,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("%s suck%s life from %s!",castername,isplayer(caster) ? "" : "s", lfname); msg("%s suck%s life from %s!",castername,isplayer(caster) ? "" : "s", lfname);
} }
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (isplayer(target)) {
msg("You feel your life force draining away!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
if (target) { if (target) {
@ -3498,7 +3518,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE; return B_TRUE;
} }
// add it // add it
newlf = summonmonster(caster, targcell, R_FLOATINGDISC, B_FALSE, NULL, PERMENANT, B_TRUE); newlf = summonmonster(caster, targcell, R_FLOATINGDISC, NULL, PERMENANT, B_TRUE);
if (newlf) { if (newlf) {
if (haslos(player, targcell)) { if (haslos(player, targcell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -3790,7 +3810,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (isplayer(caster)) { if (isplayer(caster)) {
if (!hasflag(o->flags, F_ENCHANTABLE)) { if (!hasflag(o->flags, F_ENCHANTABLE)) {
nothinghappens(); if (isplayer(caster)) nothinghappens();
return B_TRUE; return B_TRUE;
} else { } else {
int amt; int amt;
@ -4010,8 +4030,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
losehp(target, roll("1d3"), DT_COLD, caster, "a frostbite spell"); losehp(target, roll("1d3"), DT_COLD, caster, "a frostbite spell");
} }
} else if (spellid == OT_S_GASEOUSFORM) { } else if (spellid == OT_S_GASEOUSFORM) {
target = caster; if (!target) target = caster;
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { if ((target->race->id != R_VAMPIRE) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (isplayer(target)) { if (isplayer(target)) {
msg("You feel momentarily insubstantial."); msg("You feel momentarily insubstantial.");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -4022,8 +4042,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
// remember the original race // remember the original race
addflag(target->flags, F_ORIGRACE, target->race->id, NA, NA, NULL); addflag(target->flags, F_ORIGRACE, target->race->id, NA, NA, NULL);
// polymorph is always will be temporary if (target->race->id != R_VAMPIRE) {
addtempflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL, 10); // polymorph is temporary
addtempflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL, 10);
}
setrace(target, R_GASCLOUD, B_TRUE); setrace(target, R_GASCLOUD, B_TRUE);
} }
} else if (spellid == OT_S_GREASE) { } else if (spellid == OT_S_GREASE) {
@ -4208,11 +4230,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
donesomething = B_TRUE; donesomething = B_TRUE;
} }
if (!donesomething) { if (isplayer(target)) {
if (isplayer(target)) { if (!donesomething) {
nothinghappens(); nothinghappens();
} }
} }
if (donesomething && isplayer(caster) && !frompot) {
pleasegodmaybe(R_GODMERCY, 3);
}
} else if (spellid == OT_S_HOLDPORTAL) { } else if (spellid == OT_S_HOLDPORTAL) {
object_t *o; object_t *o;
if (!validatespellcell(caster, &targcell,TT_DOOR, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell,TT_DOOR, spellid, power, frompot)) return B_TRUE;
@ -4246,11 +4271,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} else { } else {
if (cansee(player, target)) { if (cansee(player, target)) {
char lfname[BUFLEN]; if (lfhasflag(target, F_HUNGER)) {
getlfname(target, lfname); modhunger(target, HUNGERCONST); // make more hungry
msg("%s looks ravenously hungry!", lfname); } else {
if (!lfhasflagval(target, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL)) { // ie. "hungry"
addflag(target->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(target->flags, F_HUNGER, HUNGERCONST*2, NA, NA, NULL);
} }
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
@ -4635,15 +4660,49 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// 10 = gun speed // 10 = gun speed
fireat(caster, targob, 1, targcell, 8 + (power / 2) , NULL); fireat(caster, targob, 1, targcell, 8 + (power / 2) , NULL);
} else if (spellid == OT_S_PLANESHIFT) { } else if (spellid == OT_S_PLANESHIFT) {
if (isplayer(caster)) { map_t *m;
msg("^B__not yet implemented__"); target = caster;
if (isplayer(target)) {
region_t *r;
char ch = 'a';
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
// ask for region
initprompt(&prompt, "Where do you wish to travel?");
prompt.maycancel = B_TRUE;
for (r = firstregion ; r ; r = r->next) {
regiontype_t *rt;
rt = r->rtype;
addchoice(&prompt, ch++, rt->name, NULL, r);
}
ch = getchoice(&prompt);
r = (region_t *)prompt.result;
// find first map in region
m = findregionmap(r->id, 1);
} else { } else {
if (cansee(player, caster)) { if (cansee(player, target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
// for now, just disappear.
unsummon(caster, B_TRUE); m = findregionmap(RG_HEAVEN, 1);
}
if (m) {
int ntries = 0;
// find random free cell in map
targcell = getrandomcell(m);
while (!cellwalkable(target, targcell, NULL)) {
targcell = getrandomcell(m);
ntries++;
if (ntries >= 5) {
fizzle(caster);
return B_TRUE;
}
}
teleportto(target, targcell, B_TRUE);
} else {
fizzle(caster);
return B_TRUE;
} }
} else if (spellid == OT_S_PARALYZE) { } else if (spellid == OT_S_PARALYZE) {
int howlong; int howlong;
@ -5156,7 +5215,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getlfname(target, lfname); getlfname(target, lfname);
msg("A pulse of electricity shocks %s!",lfname); msg("A pulse of electricity shocks %s!",lfname);
} }
dam = rolldie(1, power); dam = power*2;
losehp(target, dam, DT_ELECTRIC, caster, "a jolt of electricity"); losehp(target, dam, DT_ELECTRIC, caster, "a jolt of electricity");
} else { } else {
fizzle(caster); fizzle(caster);
@ -5604,7 +5663,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getobname(blowob[i], obname, 1); getobname(blowob[i], obname, 1);
c = getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND); c = getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND);
if (c && ((rnd(1,100)+power) <= 33)) { if (c && ((rnd(1,100)-power) <= 33)) {
// move it // move it
fireat(NULL, blowob[i], 1, c, 4, NULL); fireat(NULL, blowob[i], 1, c, 4, NULL);
} }
@ -5702,7 +5761,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
} else { } else {
nothinghappens(); if (isplayer(caster)) nothinghappens();
return B_TRUE; return B_TRUE;
} }
} else if (spellid == OT_S_PACIFY) { } else if (spellid == OT_S_PACIFY) {
@ -6009,6 +6068,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else { } else {
fizzle(caster); fizzle(caster);
} }
if (ndone && isplayer(caster) && !frompot) {
pleasegodmaybe(R_GODMERCY, 3);
}
} else if (spellid == OT_S_REPELINSECTS) { } else if (spellid == OT_S_REPELINSECTS) {
// just announce // just announce
if (isplayer(caster)) { if (isplayer(caster)) {
@ -6075,6 +6137,29 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
nothinghappens(); nothinghappens();
} }
} }
} else if (spellid == OT_S_SATEHUNGER) {
int hunger;
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_TRUE;
}
hunger = gethungerval(target);
if (hunger > 0) {
int modamt;
modamt = hunger; // take away all current hunger
modamt += HUNGERCONST * 2; // ... then make them stuffed
modhunger(target, -modamt);
if (isplayer(target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else {
fizzle(caster);
return B_TRUE;
}
} else if (spellid == OT_S_SEEINVIS) { } else if (spellid == OT_S_SEEINVIS) {
flag_t *f; flag_t *f;
// always targetted at caster // always targetted at caster
@ -6862,7 +6947,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
wantsize = SZ_ANY; wantsize = SZ_ANY;
break; break;
} }
ngot = summonlfs(caster, wantrc, wantsize, nwant, lifetime); ngot = summonlfs(caster, caster->cell, wantrc, wantsize, nwant, lifetime);
if (!ngot) { if (!ngot) {
fizzle(caster); fizzle(caster);
return B_TRUE; return B_TRUE;
@ -7414,12 +7499,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// now age the caster // now age the caster
if (!isgod(caster)) { if (!isgod(caster)) {
caster->maxhp -= pctof(25,caster->maxhp); age(caster, 25);
limit(&caster->hp, NA, caster->maxhp);
if (isplayer(caster)) {
msg("^BYour body ages unnaturally!");
statdirty = B_TRUE;
}
} }
if (isplayer(target)) { if (isplayer(target)) {
@ -7491,12 +7571,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// now age the caster // now age the caster
if (!isgod(caster)) { if (!isgod(caster)) {
caster->maxhp -= pctof(50,caster->maxhp); age(caster, 50);
limit(&caster->hp, NA, caster->maxhp);
if (isplayer(caster)) {
msg("^BYour body ages unnaturally!");
statdirty = B_TRUE;
}
} }
} else { } else {
// monsters can't wish // monsters can't wish
@ -8281,7 +8356,7 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) {
// returns # created // returns # created
int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime) { int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime) {
lifeform_t *newlf; lifeform_t *newlf;
race_t *r = NULL; race_t *r = NULL;
enum RACE poss[MAXCANDIDATES]; enum RACE poss[MAXCANDIDATES];
@ -8316,7 +8391,7 @@ int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, i
ncreated = 0; ncreated = 0;
for (i = 0; i < howmany; i++) { for (i = 0; i < howmany; i++) {
// get random adjacent cell // get random adjacent cell
c = getrandomadjcell(caster->cell, WE_EMPTY, B_ALLOWEXPAND); c = getrandomadjcell(where, WE_EMPTY, B_ALLOWEXPAND);
if (!c) { if (!c) {
return ncreated; return ncreated;
} }
@ -8324,7 +8399,7 @@ int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, i
r = findrace(poss[rnd(0,nposs-1)]); r = findrace(poss[rnd(0,nposs-1)]);
if (r) { if (r) {
// add it! // add it!
newlf = addmonster(c, r->id, B_FALSE, 1, B_FALSE, NULL); newlf = addmonster(c, r->id, NULL, B_FALSE, 1, B_FALSE, NULL);
// not worth any xp // not worth any xp
killflagsofid(newlf->flags, F_XPVAL); killflagsofid(newlf->flags, F_XPVAL);
addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL);
@ -8396,6 +8471,8 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, e
if (!caster) { if (!caster) {
return *targcell; return *targcell;
} else if ((caster->race->raceclass->id == RC_GOD) && targcell) {
return *targcell;
} }
sp = findot(spellid); sp = findot(spellid);
@ -8408,6 +8485,10 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, e
} }
} }
if (caster && (caster->race->raceclass->id == RC_GOD)) {
needlos = B_FALSE;
}
maxrange = getspellrange(spellid, power); maxrange = getspellrange(spellid, power);

View File

@ -26,7 +26,7 @@ void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYP
void stopspell(lifeform_t *caster, enum OBTYPE spellid); void stopspell(lifeform_t *caster, enum OBTYPE spellid);
void stopallspells(lifeform_t *lf); void stopallspells(lifeform_t *lf);
void stopallspellsexcept(lifeform_t *lf, ...); void stopallspellsexcept(lifeform_t *lf, ...);
int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime); int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime);
lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target); lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target);
cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power, int frompot); cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power, int frompot);
//lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf); //lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf);

21
text.c
View File

@ -10,7 +10,6 @@
extern long curtime; extern long curtime;
int needan(char *text) { int needan(char *text) {
if (isvowel(tolower(text[0]))) { if (isvowel(tolower(text[0]))) {
return B_TRUE; return B_TRUE;
@ -58,12 +57,18 @@ enum COLOUR chartocol(char ch) {
return C_BROWN; return C_BROWN;
case 'B': // v.bad case 'B': // v.bad
return C_RED; return C_RED;
case 'T': // terrible
return C_ORANGE;
case 'g': // good case 'g': // good
return C_GREEN; return C_GREEN;
case 'G': // v.good case 'G': // v.good
return C_CYAN; return C_CYAN;
case 'E': // excllent
return C_BOLDCYAN;
case 'h': // 'hilite' case 'h': // 'hilite'
return C_WHITE; return C_WHITE;
case 'l': // 'bLue'
return C_BLUE;
case 'n': // normal case 'n': // normal
default: default:
break; break;
@ -678,6 +683,20 @@ int streq(char *a, char *b) {
return !strcmp(a,b); return !strcmp(a,b);
} }
char *strends(char *a, char *suffix) {
char *ep;
if (!a || !suffix) return NULL;
ep = strstr(a, suffix);
if (ep) {
if ((ep - a) + strlen(ep) == strlen(a)) {
return ep;
}
}
return NULL;
}
char *strstarts(char *a, char *prefix) { char *strstarts(char *a, char *prefix) {
if (!a || !prefix) return NULL; if (!a || !prefix) return NULL;

1
text.h
View File

@ -32,6 +32,7 @@ void splittime(int *hours, int *mins, int *secs);
char *strrep(char *text, char *oldtok, char *newtok, int *rv); char *strrep(char *text, char *oldtok, char *newtok, int *rv);
char *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv); char *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv);
int streq(char *a, char *b); int streq(char *a, char *b);
char *strends(char *a, char *suffix);
char *strstarts(char *a, char *prefix); char *strstarts(char *a, char *prefix);
int strpixmatch(char *haystack, char *needle); int strpixmatch(char *haystack, char *needle);
int texttodice(char *text, int *ndice, int *nsides, int *bonus); int texttodice(char *text, int *ndice, int *nsides, int *bonus);

View File

@ -13,5 +13,6 @@ autodoors:25
autopop autopop
scatter(1,1,-2,-2) ob:boulder:25% scatter(1,1,-2,-2) ob:boulder:25%
scatter(1,1,-2,-2) ob:25-75 stones:50% scatter(1,1,-2,-2) ob:25-75 stones:50%
rarity:uncommon
@end @end

View File

@ -14,11 +14,13 @@
@legend @legend
#:cell:rock wall #:cell:rock wall
+:ob:wooden door +:ob:wooden door
+:exit
@end @end
@flags @flags
goesin:dungeon goesin:dungeon
autodoors:50 autodoors:50
autopop autopop
rarity:uncommon
@end @end

View File

@ -21,5 +21,6 @@
goesin:dungeon goesin:dungeon
autodoors:50 autodoors:50
autopop autopop
rarity:uncommon
@end @end

View File

@ -20,5 +20,6 @@ X:exit
! autoscale, lock xy ! autoscale, lock xy
goesin:dungeon goesin:dungeon
mayrotate mayrotate
rarity:common
@end @end

View File

@ -18,5 +18,6 @@ scatter(1,1,-2,-2) ob:random food:5-10
scatter(1,1,-2,-2) ob:steak knife:1-5 scatter(1,1,-2,-2) ob:steak knife:1-5
! mayrotate ! mayrotate
! mayscale ! mayscale
rarity:uncommon
@end @end

View File

@ -15,5 +15,6 @@ autodoors:100
autopop autopop
fill(1,1,-2,-2) ob:very deep water:100 fill(1,1,-2,-2) ob:very deep water:100
scatter(1,1,-2,-2) mon:piranha:3:100 scatter(1,1,-2,-2) mon:piranha:3:100
rarity:uncommon
@end @end

View File

@ -14,5 +14,6 @@ autopop
fill(2,2,-3,-3) cell:low rock floor:100 fill(2,2,-3,-3) cell:low rock floor:100
fill(2,2,-3,-3) ob:waist-deep water:100 fill(2,2,-3,-3) ob:waist-deep water:100
scatter(2,2,-3,-3) mon:piranha:50%:100 scatter(2,2,-3,-3) mon:piranha:50%:100
rarity:uncommon
@end @end

View File

@ -17,6 +17,7 @@
,:ob:1-4 bones:50 ,:ob:1-4 bones:50
,:mon:prisoner:50 ,:mon:prisoner:50
+:ob:wooden door +:ob:wooden door
+:exit
/:ob:wooden table /:ob:wooden table
-:ob:wooden footstool -:ob:wooden footstool
c:ob:lit candelabrum c:ob:lit candelabrum

View File

@ -21,6 +21,8 @@
@legend @legend
#:cell:metal wall #:cell:metal wall
m:mon:minotaur m:mon:minotaur
+:ob:iron door
+:exit
@end @end
@flags @flags
@ -38,5 +40,6 @@ scatter(0,0,-1,-1) ob:common weapon:4-5
! TODO: scattered minions around ?? ! TODO: scattered minions around ??
mayrotate mayrotate
! mayscale ! mayscale
rarity:rare
@end @end

View File

@ -14,5 +14,6 @@ autodoors:100
scatter(1,1,-2,-2) ob:statue:25% scatter(1,1,-2,-2) ob:statue:25%
scatter(1,1,-2,-2) mon:cockatrice:1 scatter(1,1,-2,-2) mon:cockatrice:1
scatter(1,1,-2,-2) ob:1-10 stones:1-5 scatter(1,1,-2,-2) ob:1-10 stones:1-5
rarity:rare
@end @end

View File

@ -16,5 +16,6 @@ scatter(1,1,-2,-2) ob:random:100%
scatter(1,1,-2,-2) ob:random:100% scatter(1,1,-2,-2) ob:random:100%
scatter(1,1,-2,-2) ob:random:100%:50 scatter(1,1,-2,-2) ob:random:100%:50
scatter(1,1,-2,-2) ob:random:100%:50 scatter(1,1,-2,-2) ob:random:100%:50
rarity:rare
@end @end

View File

@ -13,5 +13,6 @@ autopop
goesin:dungeon goesin:dungeon
! add mud to 50% of room cells ! add mud to 50% of room cells
scatter(1,1,-2,-2) ob:pool of mud:50% scatter(1,1,-2,-2) ob:pool of mud:50%
rarity:uncommon
@end @end

View File

@ -11,5 +11,6 @@ goesin:dungeon
autodoors:50 autodoors:50
autopop autopop
scatter(1,1,-2,-2) cell:rock wall:25% scatter(1,1,-2,-2) cell:rock wall:25%
rarity:uncommon
@end @end

View File

@ -12,5 +12,6 @@ goesin:dungeon
autodoors:50 autodoors:50
autopop autopop
scatter(1,1,-2,-2) cell:glass wall:25% scatter(1,1,-2,-2) cell:glass wall:25%
rarity:uncommon
@end @end

View File

@ -20,5 +20,6 @@
goesin:dungeon goesin:dungeon
autodoors:50 autodoors:50
mayrotate mayrotate
rarity:uncommon
@end @end

View File

@ -17,5 +17,6 @@ scatter(1,1,-2,-2) ob:corpse:1-5
! chance of great items... ! chance of great items...
scatter(1,1,-2,-2) ob:great armour:1:30 scatter(1,1,-2,-2) ob:great armour:1:30
scatter(1,1,-2,-2) ob:great weapon:1:30 scatter(1,1,-2,-2) ob:great weapon:1:30
rarity:uncommon
@end @end

View File

@ -15,5 +15,6 @@ X:exit
! autoscale ! autoscale
goesin:dungeon goesin:dungeon
mayrotate mayrotate
rarity:common
@end @end

View File

@ -18,5 +18,6 @@ $:ob:25-200 gold
goesin:dungeon goesin:dungeon
mayrotate mayrotate
! no auto doors. ie this can be in the middle of nowhere. ! no auto doors. ie this can be in the middle of nowhere.
rarity:uncommon
@end @end