- [+] 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
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
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 god.c io.c lf.c map.c move.c objects.c text.c save.c spell.c vault.c vault.h -lncurses -lsqlite3

52
ai.c
View File

@ -5,6 +5,7 @@
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
@ -28,6 +29,7 @@ void addignorecell(lifeform_t *lf, cell_t *c) {
// returns true on failure
int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
int db = B_FALSE;
int innocentattack = 0;
flag_t *f;
if (lfhasflag(lf, F_DEBUG)) {
@ -85,18 +87,24 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
// become hostile?
if (!hasflag(lf->flags, F_HOSTILE)) {
addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
innocentattack = 1;
}
// change allegience ?
if (!areenemies(lf, victim)) {
if (getallegiance(victim) == AL_FRIENDLY) {
killflagsofid(lf->flags, F_FRIENDLY);
innocentattack = 3;
}
}
// no longer a pet
f = lfhasflagval(lf, F_PETOF, victim->id, NA, NA, NULL);
if (f) killflag(f);
if (f) {
innocentattack = 3;
killflag(f);
}
return B_FALSE;
}
@ -817,6 +825,10 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
}
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)) {
return eat(lf, o);
} else {
@ -829,6 +841,11 @@ int aipickup(lifeform_t *lf, object_t *o) {
int aipickupok(lifeform_t *lf, object_t *o) {
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)) {
return B_FALSE;
}
@ -899,14 +916,12 @@ void aiturn(lifeform_t *lf) {
dblog("AIMOVE: %s", lfname);
}
/*
// if lifeform isn't alive, skip turn
if (isdead(lf)) {
if (db) dblog(".oO { i am not alive, skipping turn. }");
taketime(lf, SPEED_DEAD);
return;
}
*/
///////////////////////////////////////////
// info gathering
@ -1035,6 +1050,15 @@ void aiturn(lifeform_t *lf) {
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?
if (lf->hp < (lf->maxhp/2)) {
if (!useitemwithflag(lf, F_AIHEALITEM)) {
@ -1291,7 +1315,6 @@ void aiturn(lifeform_t *lf) {
}
}
// look for any race which we hate
newtarget = NULL;
for (n = 0; n < lf->nlos; n++) {
@ -1335,6 +1358,16 @@ void aiturn(lifeform_t *lf) {
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)) {
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)) {
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?
o = hasobmulti(lf->cell->obpile, oid, noids);
if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o)) {

View File

@ -6,6 +6,7 @@
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
@ -24,6 +25,9 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty
int damtaken = 0;
// figure out what bit of armour was hit
if (dam == 0) {
return 0;
}
// special case - missiles always hit flak jacket
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
if ( ((armour->type->id == OT_FLAKJACKET) && (damtype == DT_PROJECTILE)) ||
(damtype == DT_ACID) ||
hasflag(wep->flags, F_ARMOURPIERCE) ||
rust ) {
// ALL of damage reduction goes towards armour
} 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) ) {
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) {
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++;
@ -399,6 +410,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
int deflected = B_FALSE;
int weppassthrough = B_FALSE;
int firstisbackstab = B_FALSE;
int attackedhelpless = B_FALSE;
int attackedfriend = B_FALSE;
int hit = B_FALSE;
int critical = 0;
char wepname[BUFLEN];
@ -573,14 +586,25 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// backstab?
if ((damtype[0] == DT_PIERCE) && // using a stabbing weapon
getskill(lf, SK_BACKSTAB) && // able to backstab
!cansee(victim, lf) && // victim can't see us
!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
) {
getskill(lf, SK_BACKSTAB)) { // able to backstab
if (!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
if (!cansee(victim, lf) || // victim can't see us
isfleeing(victim)) {
addflag(victim->flags, F_STABBEDBY, lf->id, NA, NA, NULL);
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?
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));
if (strstr(attackverb, "hit")) {
dblog("xxx");
}
if ((dam[i] == 0) && (damtype[i] != DT_TOUCH)) {
nodam = B_TRUE;
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 {
char attackername2[BUFLEN];
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
// don't adjust damage - we've already done that
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 }");
return B_FALSE;
}
@ -1206,6 +1249,10 @@ int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE d
//int pctrange;
object_t *o;
if (hasflag(wep->flags, F_ARMOURPIERCE)) {
reduceamt = 0;
}
ar = getarmourrating(lf, NULL, NULL, NULL);
// 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
if ((f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) {
killflag(f);
if (owner && isplayer(owner)) {
addflag(owner->flags, F_USEDPOISON, B_TRUE, NA, NA, NULL);
}
}
}
} // end if (fid == hitconfer)

Binary file not shown.

50
defs.h
View File

@ -268,6 +268,7 @@ enum SENSE {
#define FROMBRAND (-7865)
#define FROMOBMOD (-7864)
#define FROMSKILL (-7863)
#define FROMGODGIFT (-7862)
#define FROMEXTERNAL_LOW (-7999)
@ -660,8 +661,11 @@ enum RACECLASS {
RC_UNDEAD,
};
#define MAXGODS 3
enum RACE {
R_NONE, R_RANDOM,
R_NONE = 0,
R_RANDOM, R_SPECIFIED,
// unique monstesr
R_JAILER,
// human monsters
@ -673,7 +677,9 @@ enum RACE {
R_PRISONER,
R_TOWNGUARD,
// gods
R_GODDEATH,
R_GODGREED,
R_GODMERCY,
// monsters
R_BEHOLDER,
R_BUGBEAR,
@ -712,6 +718,7 @@ enum RACE {
R_SPRITEFIRE,
R_TROGLODYTE,
R_TROLL,
R_VAMPIRE,
R_XAT,
// fish
R_CRAB,
@ -1082,6 +1089,7 @@ enum OBTYPE {
OT_S_QUENCH,
OT_S_LESSENPOISON,
OT_S_REPELINSECTS,
OT_S_SATEHUNGER,
OT_S_SLEETSTORM,
OT_S_SOFTENEARTH,
OT_S_STICKTOSNAKE,
@ -1132,6 +1140,7 @@ enum OBTYPE {
OT_A_CHARGE,
OT_A_CRUSH,
OT_A_JUMP,
OT_A_PRAY,
OT_A_RAGE,
OT_A_REPAIR,
OT_A_SPRINT,
@ -1210,6 +1219,7 @@ enum OBTYPE {
OT_XRAYGOGGLES,
// furniture
OT_CANDELABRUM,
OT_COFFIN,
OT_FIREPLACE,
OT_WEAPONRACK,
OT_WOODENTABLE,
@ -1534,6 +1544,7 @@ enum FLAG {
F_ONEPERCELL, // only one of these objects can exist per cell
F_CREATEDBY, // object was made by lf id v0, text=real lfname
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_STACKABLE, // can stack multiple objects togethr
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_DONELISTEN, // supress further 'you hear xx' messages this turn.
// 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_DEBUG, // debugging enabled
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_ATTRSET, // forces attribute val0 to be val1. ie. 0=A_STR,1=18
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_RANDOMTALK, // v0 = sp_xxx for what to say when we randomly talk.
// v1/v2 are min/max volume
@ -1909,6 +1923,7 @@ enum FLAG {
F_LFSUFFIX, // text = suffix. eg. "skeleton"
F_VISRANGE, // how far you can see (in the light)
F_VISRANGEMOD, // modifications to visrange
F_NIGHTVISRANGEMOD, // modifications to nightvisrange
F_GUNTARGET, // current projectile weapon target
F_CASTINGSPELL, // set while the player is casting a spell
// for instant spells:
@ -1959,6 +1974,8 @@ enum FLAG {
F_PETOF, // this lf is a pet of lfid v0
// v1/2 = last known location of my owner.
// 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
// vanish.
// 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_JOB, // val0 = player's class/job
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_XPMOD, // add/subtract this much from calculated xpval
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
// here.
F_VAULTISSHRINE, // this vault is a godstone shrine
F_VAULTRARITY, // v0=rr_xxx
F_VAULTSCATTER, // v0=thingtype, v1=pctchance
// text=x1,y1,x2,y2,mincount-maxcount,thingname
// if maxcount is PCT, mincount is a percentage
@ -2276,6 +2297,21 @@ enum HUNGER {
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
//#define CH_DEADENDOB 35
//#define CH_EMPTYCELLOB 3
@ -2286,6 +2322,9 @@ enum HUNGER {
#define B_FALSE (0)
#define B_TRUE (-1)
#define B_MALE (0)
#define B_FEMALE (-1)
#define B_MAYCHASE (-1)
#define B_NODOORS (0)
@ -2487,14 +2526,16 @@ typedef struct command_s {
enum REGIONTYPE {
RG_WORLDMAP,
RG_FIRSTDUNGEON,
RG_HEAVEN,
RG_PIT,
};
enum HABITAT {
H_DUNGEON = 1,
H_FOREST = 2,
H_PIT = 3,
H_VILLAGE = 4,
H_HEAVEN = 3,
H_PIT = 4,
H_VILLAGE = 5,
H_ALL = 999
};
@ -2534,6 +2575,7 @@ typedef struct regionoutline_s {
struct regionoutline_s *next, *prev;
} regionoutline_t;
// a region is a link of a regiontype and an outline
typedef struct region_s {
int id;
regiontype_t *rtype;
@ -2781,6 +2823,8 @@ typedef struct flag_s {
int chance;
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;

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
U = unearthly/demonic/horrific creature
w = worm
V = vampire
z = lizard-like creature
Z = undead

View File

@ -18,7 +18,7 @@ General format:
Legend is:
c:type:what[:pct]
OR
c:exit
c:exit (denotes an exit, for use by linkexits)
c = any letter
@ -64,6 +64,15 @@ Flags can be:
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
// appear when specifically requested via a region's
// 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);

270
io.c
View File

@ -10,6 +10,7 @@
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
@ -41,6 +42,12 @@ extern enum ERROR reason;
extern char msghist[MAXHISTORY][BUFLEN];
extern int nmsghist;
extern lifeform_t *godlf[];
extern int ngodlfs;
extern flag_t *retflag[];
extern int nretflags;
extern prompt_t prompt;
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, 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
/*
@ -1177,7 +1192,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
enum SPELLSCHOOL school;
school = getspellschoolknown(lf, ot->id);
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;
}
}
@ -2772,16 +2787,27 @@ void centre(WINDOW *win, enum COLOUR col, int y, char *format, ... ) {
char buf[BUFLEN];
va_list args;
int startx;
int len;
char *p;
int colcount = 0;
va_start(args, format);
vsprintf( buf, format, args );
va_end(args);
for (p = buf ; *p ; p++) {
if (*p == '^') colcount++;
}
len = strlen(buf) - (colcount*2);
w = getmaxx(win);
startx = (w/2) - (strlen(buf)/2);
startx = (w/2) - (len/2);
if (startx < 0) startx = 0;
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);
}
@ -2923,6 +2949,60 @@ void cls(void) {
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) {
char buf[BIGBUFLEN];
char buf2[BUFLEN];
@ -3822,16 +3902,26 @@ void describespell(objecttype_t *ot) {
char buf[BUFLEN];
flag_t *f;
int i;
int power;
int power,range;
cls();
if (ot->obclass->id == OC_SPELL) {
power = getspellpower(player, ot->id);
} else {
power = -1;
}
range = getspellrange(ot->id, power);
// title
sprintf(buf, "%s",ot->name);
capitalise(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
@ -3862,12 +3952,15 @@ void describespell(objecttype_t *ot) {
wprintw(mainwin, "\n");
if (ot->obclass->id == OC_SPELL) {
power = getspellpower(player, ot->id);
if (power > 0) {
wprintw(mainwin, "You can cast it at power level %d (maximum %d).\n",power, getspellmaxpower(ot->id));
} else {
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);
@ -4085,7 +4178,7 @@ void docomms(lifeform_t *lf) {
fightback(lf, player);
} else if (i <= 10) { // limited wish
// change to a god.
setrace(lf, R_GODGREED, B_TRUE);
lf = godappears(R_GODGREED, lf->cell);
// behold! i am me!
say(lf, "Behold mortal! It is I, Avamon!", SV_SHOUT);
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 y;
command_t *c;
char *ftext= "%c %s";
enum {
HM_COMMANDS,
HM_MAIN,
HM_SKILLS,
} helpmode = HM_MAIN;
int done = B_FALSE;
int ch;
@ -5180,25 +5268,24 @@ void dohelp(void) {
while (!done) {
cls();
if (helpmode == HM_MAIN) {
if (helpmode == '?') {
initprompt(&prompt, "What would you like help with (ESC when done)?");
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);
prompt.maycancel = B_TRUE;
ch = getchoice(&prompt);
switch (ch) {
case '?':
helpmode = HM_COMMANDS;
break;
case 'g':
case 's':
helpmode = HM_SKILLS;
break;
helpmode = ch;
default:
done = B_TRUE;
break;
}
} else if (helpmode == HM_COMMANDS) {
} else if (helpmode == 'c') {
centre(mainwin,C_WHITE, 0, "KEYBOARD COMMAND REFERENCE");
y = 2;
@ -5213,8 +5300,8 @@ void dohelp(void) {
}
centre(mainwin,C_WHITE, h-1, "[Press any key]");
getch();
helpmode = HM_MAIN;
} else if (helpmode == HM_SKILLS) {
done = B_TRUE;
} else if (helpmode == 's') {
skill_t *sk;
centre(mainwin,C_WHITE, 0, "SKILL REFERENCE");
y = 2;
@ -5227,11 +5314,40 @@ void dohelp(void) {
prompt.maycancel = B_TRUE;
ch = getchoicestr(&prompt, B_FALSE, B_TRUE);
if (!ch) {
helpmode = HM_MAIN;
done = B_TRUE;
} else {
sk = (skill_t *)prompt.result;
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);
break;
case '?': // help
dohelp();
dohelp('?');
break;
case '@': // display player stats
showlfstats(player, B_FALSE);
@ -7637,8 +7753,9 @@ void showlfstats(lifeform_t *lf, int showall) {
}
if (showall) {
sprintf(prompt, "[@=stats S=skills/abilities M=magic E=effects %sESC=quit]", isplayer(lf) ? "" : "I=items " );
sprintf(cmdchars, "@asme%s",isplayer(lf) ? "" : "i");
sprintf(prompt, "^h[^W@^n=stats ^WS^nkills ^WA^nbils ^WM^nagic ^WE^nffects ^WG^nods %s^W?^n=help ^WESC^n=quit^h]",
isplayer(lf) ? "" : "^WI^ntems " );
sprintf(cmdchars, "@asmeg%s",isplayer(lf) ? "" : "i");
} else {
sprintf(prompt, "%s", "[ESC=quit]");
sprintf(cmdchars, "%s", "@");
@ -8457,10 +8574,7 @@ void showlfstats(lifeform_t *lf, int showall) {
}
}
} else if (mode == 's') {
int exitnow = B_FALSE;
// now show intrinsics on next page
} else if (mode == 'a') {
centre(mainwin, C_WHITE, 0, "ABILITIES");
y = 2;
@ -8505,7 +8619,6 @@ void showlfstats(lifeform_t *lf, int showall) {
wprintw(mainwin, buf);
if (downline(&y, h, "ABILITIES", NULL, prompt, cmdchars, &ch)) {
exitnow = B_TRUE;
break;
}
}
@ -8513,13 +8626,15 @@ void showlfstats(lifeform_t *lf, int showall) {
}
y++;
if (!exitnow) {
} else if (mode == 's') {
char skilltitle[BUFLEN];
flag_t *known[MAXSKILLS], *available[MAXSKILLS];
int numknown = 0, numavailable = 0;
int n;
enum SKILLLEVEL slev;
centre(mainwin, C_WHITE, 0, "SKILLS");
// get available skills
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_CANLEARN) {
@ -8559,11 +8674,9 @@ void showlfstats(lifeform_t *lf, int showall) {
unsetcol(mainwin, getskilllevelcolour(known[n]->val[1]));
}
if (downline(&y, h, "SKILLS", skilltitle, prompt, cmdchars, &ch)) {
exitnow = B_TRUE;
break;
}
}
}
} else if (mode == 'm') {
char subheading[BUFLEN];
int lev;
@ -9155,6 +9268,82 @@ void showlfstats(lifeform_t *lf, int showall) {
} else {
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
@ -9169,14 +9358,23 @@ void showlfstats(lifeform_t *lf, int showall) {
case '@':
mode = ch;
break;
case 's':
case 'm':
case 'a':
case 'e':
case 'g':
case 'm':
case 's':
if (showall) mode = ch;
break;
case 'i':
if (showall && !isplayer(lf)) mode = ch;
break;
case '?':
if (mode == 'g') { // help on gods
dohelp('g');
} else if (mode == 's') { // help on skills
dohelp('s');
}
break;
default:
break;
}

3
io.h
View File

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

282
lf.c
View File

@ -8,6 +8,7 @@
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
@ -19,6 +20,7 @@
extern FILE *logfile;
extern map_t *firstmap;
extern race_t *firstrace, *lastrace;
extern raceclass_t *firstraceclass, *lastraceclass;
@ -53,6 +55,9 @@ extern int loading;
extern int obdb;
extern lifeform_t *godlf[];
extern int ngodlfs;
extern enum ERROR reason;
@ -70,9 +75,6 @@ void autoweild(lifeform_t *lf) {
pretimespent = lf->timespent;
if (isplayer(lf)) {
dblog("xxx");
}
// weild weapons if required
bestwep = getbestweapon(lf);
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.
if (lfhasflag(lf, F_POLYMORPHED)) {
if (lfhasflag(lf, F_ORIGRACE)) {
@ -1816,6 +1837,11 @@ void die(lifeform_t *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 ?
getflags(lf->flags, F_CORPSEFLAG, F_NONE);
for (i = 0; i < nretflags; i++) {
@ -2477,6 +2503,12 @@ int eat(lifeform_t *lf, object_t *o) {
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
if (!stopeating && !fullyeaten && (posthlev != hlev) && (posthlev <= H_FULL)) {
if (isplayer(lf) && (posthlev != H_STUFFED)) {
@ -3239,9 +3271,12 @@ int flee(lifeform_t *lf) {
if (f->lifetime == PERMENANT) {
killflag(f);
} 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;
}
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 range = 1; // default
int range = 1,i; // default
flag_t *f;
f = lfhasflag(lf, F_SEEINDARK);
@ -4672,6 +4707,16 @@ int getnightvisrange(lifeform_t *lf) {
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;
}
@ -5546,7 +5591,7 @@ race_t *getrandomrace(cell_t *c, int forcedepth) {
if (forcedepth != NA) {
depth = forcedepth;
} else {
depth = getmapdifficulty(c ? c->map : NULL);
depth = getmapdifficulty((c && c->map) ? c->map : NULL);
}
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_CHANNELING, 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_SS_AIR, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SS_DEATH, NA, NA, NULL);
@ -7941,6 +7987,7 @@ void initjobs(void) {
void initrace(void) {
flag_t *f;
objecttype_t *ot;
// race classes
addraceclass(RC_OTHER, "misc. creature", "miscellaneous creatures", SK_NONE);
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);
// 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);
addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "20");
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_ACTIONSPEED, SP_SLOW, NA, NA, NULL);
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, "10 huge bags of holding");
//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_HUMANOID, B_TRUE, NA, 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");
// god abilities
addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Greed");
addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Thieves");
addflag(lastrace->flags, F_FLEEONHPPCT, 10, 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_CONFISCATE, 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_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
addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC);
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_STARTATT, A_IQ, AT_LOW, 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, "1d6");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d6");
addflag(lastrace->flags, F_REGENERATES, 2, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 5, 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_MOVESPEED, SP_SLOW, NA, NA, NULL);
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_WANTSOBFLAG, F_EDIBLE, 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_ACTIONSPEED, SP_SLOW, NA, NA, "");
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_WANTSOBFLAG, F_EDIBLE, B_COVETS, 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_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
addrace(R_GASCLOUD, "cloud of gas", 0.1, '}', C_GREY, MT_GAS, RC_OTHER);
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_DEAF, B_TRUE, 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);
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);
}
if (lf->race->raceclass->id == RC_GOD) {
// immortal
limit(amt, 0, lf->hp-1);
} else {
limit(amt, 0, NA);
}
}
void makepeaceful(lifeform_t *who) {
@ -11284,6 +11439,9 @@ lifeform_t *makezombie(object_t *o) {
where = getoblocation(o);
getobname(o, obname, 1);
if (!cellwalkable(NULL, where, NULL)) {
where = getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND);
}
lf = addlf(where, r->id, 1);
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;
}
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) {
flag_t *fromlfflag;
lifeform_t *fromlf = NULL;
@ -12462,6 +12630,11 @@ void modhunger(lifeform_t *lf, int amt) {
(needexclam) ? '!' : '.');
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)) {
@ -12472,6 +12645,13 @@ void modhunger(lifeform_t *lf, int amt) {
// reset hunger
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);
if (f) {
killflag(f);
@ -13657,7 +13844,8 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
getlfname(lf, buf);
f = lfhasflag(lf, F_GODOF);
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 {
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);
}
}
if (isplayer(lf)) {
needredraw = B_TRUE;
statdirty = B_TRUE;
} else if (cansee(player, lf)) {
needredraw = B_TRUE;
}
} // end if gamestarted
}
@ -14771,35 +14967,20 @@ void stopsprinting(lifeform_t *lf) {
// and make it worth zero xp.
//
// 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;
char buf[BUFLEN];
race_t *r;
r = findrace(rid);
if (r && hasflag(r->flags, F_UNIQUE)) {
// does it already exist?
newlf = findlfunique(rid);
// if so, move it here, then exit.
newlf = addmonster(c, rid, racename, B_FALSE, 1, B_FALSE, NULL);
if (newlf) {
teleportto(newlf, c, B_FALSE);
}
}
if (!newlf) {
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);
}
if (!hasflag(newlf->flags, F_UNIQUE)) {
// summoned
if (caster) {
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 (!hasob(lf->pack, OT_ENERGYBLADE)) {
stopspell(lf, OT_S_SUMMONWEAPON);
@ -16345,6 +16536,9 @@ int validateraces(void) {
} else if (r->raceclass->id == RC_DEMON) {
addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL);
} 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_DISEASEIMMUNE, B_TRUE, 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;
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);
if (rf) {
@ -16613,10 +16824,13 @@ int rest(lifeform_t *lf, int onpurpose) {
}
//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
if (skillcheck(lf, SC_CON, difficulty, getskill(lf, SK_FIRSTAID))) {
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 adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype);
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);
int areallies(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 stoprunning(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 takeoff(lifeform_t *lf, object_t *o);
void taketime(lifeform_t *lf, long howlong);

179
map.c
View File

@ -1,4 +1,5 @@
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
@ -15,15 +16,20 @@
#include "vault.h"
extern habitat_t *firsthabitat,*lasthabitat;
extern job_t *firstjob;
extern map_t *firstmap,*lastmap;
extern region_t *firstregion,*lastregion;
extern regionoutline_t *firstregionoutline,*lastregionoutline;
extern regiontype_t *firstregiontype,*lastregiontype;
extern celltype_t *firstcelltype, *lastcelltype;
extern objecttype_t *objecttype,*lastobjecttype;
extern race_t *firstrace;
extern int viewx,viewy,vieww,viewh;
extern lifeform_t *player;
extern lifeform_t *godlf[];
extern int ngodlfs;
extern glyph_t tempglyph;
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;
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;
race_t *r;
int db = B_FALSE;
flagpile_t *wantflags = NULL;
enum JOB wantjob = J_NONE;
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;
}
if ((raceid == R_NONE) || (raceid == R_RANDOM)) {
if (rid != R_SPECIFIED) {
if (rid == R_RANDOM) {
r = getrandomrace(c, NA);
} else {
r = findrace(raceid);
r = findrace(rid);
}
} else {
// 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) {
r = getreallyrandomrace(RC_ANY);
return NULL;
}
assert(r);
if (db) {
char buf[BUFLEN];
sprintf(buf, "start addmonster for %s",r->name);
sprintf(buf, "addmonster for '%s'->%s",racename, r->name);
dbtimestart(buf);
}
@ -182,6 +202,18 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
if (r) {
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));
if (db) dbtime("finished lf addition");
if (lf) {
@ -191,12 +223,13 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
if (db) dbtime("checking for job");
lf->born = B_FALSE;
if (wantjob == J_NONE) {
if (jobok) {
for (f = lf->flags->first ; f ; f = f->next) {
// has a job?
if (f->id == F_STARTJOB) {
if (rnd(1,100) <= f->val[0]) {
enum JOB wantjob;
if (f->val[1] == J_RANDOM) {
job_t *j;
j = getrandomjob(B_TRUE);
@ -210,6 +243,9 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
}
}
}
} else {
givejob(lf, wantjob);
}
if (autogen) {
// sometimes start off hiding/asleep in new maps
@ -361,10 +397,20 @@ 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;
} // end if lf
}
// free mem
if (wantflags) {
killflagpile(wantflags);
}
if (db) dbtimeend("finished addmonster");
return lf;
@ -401,7 +447,7 @@ int addrandomthing(cell_t *c, int obchance, int *nadded) {
}
} else {
// 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;
}
}
@ -1907,16 +1953,53 @@ void createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir, object_
case H_VILLAGE:
createforest(map, depth, parentmap, exitdir, entryob, 0);
break;
case H_HEAVEN:
createheaven(map, depth, parentmap, exitdir, entryob);
break;
case H_PIT:
createpit(map, depth, parentmap, exitdir, entryob);
break;
break;
default:
dblog("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
@ -2297,7 +2380,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
// village guards
for (i = 0; i < 1; 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;
getmapcoords(m, &thisx, &thisy);
if (map->nextmap[D_N] == -1) {
if (thisy == (y - 1)) {
if ((thisy == (y - 1)) && (thisx == x)) {
map->nextmap[D_N] = m->id;
if (db) dblog(" linked to map %d (dir N)",m->id);
}
}
if (map->nextmap[D_E] == -1) {
if (thisx == (x + 1)) {
if ((thisx == (x + 1)) && (thisy == y)) {
map->nextmap[D_E] = m->id;
if (db) dblog(" linked to map %d (dir E)",m->id);
}
}
if (map->nextmap[D_S] == -1) {
if (thisy == (y + 1)) {
if ((thisy == (y + 1)) && (thisx == x)) {
map->nextmap[D_S] = m->id;
if (db) dblog(" linked to map %d (dir S)",m->id);
}
}
if (map->nextmap[D_W] == -1) {
if (thisx == (x - 1)) {
if ((thisx == (x - 1)) && (thisy == y)) {
map->nextmap[D_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:
sprintf(buf, "dungeon L%d", m->depth);
break;
case RG_HEAVEN:
sprintf(buf, "the realm of gods");
break;
case RG_PIT:
sprintf(buf, "a pit L%d", m->depth);
break;
@ -3339,6 +3425,9 @@ char *getregionname(char *buf, map_t *m, int withlevel) {
case RG_FIRSTDUNGEON:
strcpy(buf, "a dungeon");
break;
case RG_HEAVEN:
sprintf(buf, "the realm of gods");
break;
case RG_PIT:
sprintf(buf, "a pit");
break;
@ -3654,8 +3743,9 @@ void initmap(void) {
int vx[4],vy[4],i;
// habitats
// 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_HEAVEN, "heaven", 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);
@ -3676,7 +3766,8 @@ void initmap(void) {
// region types
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);
// region definitions (outlines)
@ -3709,7 +3800,7 @@ void initmap(void) {
//vx = 0; vy = -1;
addregionoutline(RG_FIRSTDUNGEON);
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) {
@ -3921,7 +4012,7 @@ int isonmap(map_t *map, int x, int y) {
}
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_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)) {
lifeform_t *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);
}
}
}
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) {
enum SKILLLEVEL slev;
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);
void addhomeobs(lifeform_t *lf);
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);
int addrandomthing(cell_t *c, int obchance, int *nadded);
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 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 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 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);
@ -107,6 +108,7 @@ void makedoor(cell_t *cell, int openchance);
void makelit(cell_t *c, enum LIGHTLEV how, int howlong);
void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong);
void mapentereffects(map_t *m);
enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob);
void setcellknown(cell_t *cell, int forcelev);
void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype);
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;
habitat_t *firsthabitat = NULL,*lasthabitat = NULL;
map_t *firstmap = NULL,*lastmap = NULL;
map_t *heaven = NULL;
region_t *firstregion = NULL,*lastregion = NULL;
regionoutline_t *firstregionoutline = NULL,*lastregionoutline = 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),
// make the initial level
if (!firstmap) {
region_t *wregion, *dregion;
region_t *wregion, *dregion,*hregion;
newworld = B_TRUE;
// create world map.
wregion = addregion(RG_WORLDMAP, NULL, -1);
assert(wregion);
addmap();
createmap(firstmap, 1, wregion, NULL, D_NONE, NULL);
//createmap(firstmap, 1, RG_FIRSTDUNGEON, H_DUNGEON, NULL, D_NONE);
// create first dungeon
dregion = findregionbytype(RG_FIRSTDUNGEON);
assert(dregion);
dmap = addmap();
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
@ -214,6 +219,9 @@ int main(int argc, char **argv) {
where = real_getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL);
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");
if (user) {
char pname[MAXPNAMELEN];
@ -249,7 +257,6 @@ int main(int argc, char **argv) {
}
// read cheat info from player file
if (playerfile) {
if (parseplayerfile(playerfile, player)) {

108
objects.c
View File

@ -7,6 +7,7 @@
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
@ -2149,7 +2150,6 @@ int canbepoisoned(enum OBTYPE oid) {
if (hasflagval(ot->flags, F_CANHAVEOBMOD, OM_POISONED, NA, NA, NULL)) {
return B_TRUE;
}
return B_FALSE;
}
@ -6688,7 +6688,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_ADJSELF, NA, 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_SPELLLEVEL, 1, 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);
// 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_NATURE, 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_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// 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_AIR, 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);
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_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_WALLSTOP, NA, NULL);
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_MAXPOWER, 5, NA, 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);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, 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_AICASTTOATTACK, ST_SPECIAL, NA, 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
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);
@ -7111,6 +7112,12 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, 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
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);
@ -7254,6 +7261,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, 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_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l6
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);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, 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);
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);
@ -7384,6 +7392,8 @@ void initobjects(void) {
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);
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);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, 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_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);
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "\\");
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_ACCURACYMOD, -10, NA, 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);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 25, RR_RARE, 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_ARMOURRATING, 0, NA, 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_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);
@ -8721,6 +8743,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GOESON, BP_EYES, 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_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL);
// 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);
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_SEEINDARK, 3, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 2, 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);
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);
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_CHARGES, 3, 3, NA, NULL);
addflag(lastot->flags, F_CHARGES, 1, 3, NA, NULL);
// unarmed weapons - note these damage/accuracys can be
// 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_UNARMEDWEP, B_TRUE, NA, NA, NULL);
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_HITCONFER, F_PARALYZED, SC_CON, 22, "2-4");
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_UNARMEDWEP, B_TRUE, NA, NA, NULL);
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_HITCONFER, F_PARALYZED, SC_CON, 30, "5-10");
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
willid = B_TRUE;
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)) {
msg("A swarm of butterflies appears!");
}
@ -11964,6 +11989,15 @@ int pour(lifeform_t *lf, object_t *o) {
blessob(dst);
// we now know that this is holy water
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) {
flag_t *f;
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");
} else {
msg("Mmm, holy water.");
if (isplayer(lf)) msg("Mmm, holy water.");
}
break;
case B_UNCURSED:
msg("Mmm, water.");
if (isplayer(lf)) msg("Mmm, water.");
break;
case B_CURSED:
msg("Yuck! Something is wrong with this water.");
if (isplayer(lf)) msg("Yuck! Something is wrong with this water.");
break;
}
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));
break;
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;
case OT_POT_BLOODC:
f = lfhasflag(lf, F_BEINGSTONED);
if (f) {
killflag(f);
} else {
msg("Yuck, this tastes like oddly-flavoured blood!");
if (isplayer(lf)) msg("Yuck, this tastes like oddly-flavoured blood!");
}
break;
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_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;
}
@ -15017,7 +15075,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf) {
// can't be dodged
c = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND);
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

4
save.c
View File

@ -1035,12 +1035,12 @@ int showhiscores(lifeform_t *lf, int min, int max) {
sprintf(hilitescoretext, "%ld",hilitescore);
rc = sqlite3_exec(db, cmd, showhiscoreline, hilitescoretext, &errmsg);
free(cmd);
if (rc != SQLITE_OK) {
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);
}
free(cmd);
sqlite3_close(db);
return B_FALSE;

289
spell.c
View File

@ -7,6 +7,7 @@
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
@ -19,6 +20,8 @@
extern lifeform_t *player;
extern skill_t *firstskill, *lastskill;
extern race_t *firstrace, *lastrace;
extern map_t *heaven;
extern region_t *firstregion;
extern knowledge_t *knowledge;
extern int needredraw;
@ -36,6 +39,9 @@ extern object_t *retobs[MAXPILEOBS+1];
extern int retobscount[MAXPILEOBS+1];
extern int nretobs;
extern lifeform_t *godlf[];
extern int ngodlfs;
extern enum ERROR reason;
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...
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) {
skill_t *sk;
char ch = 'a';
@ -1995,9 +2028,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int i;
object_t *o,*nexto;
int donesomething = B_FALSE;
// animate corpses within los of caster
for (i = 0; i < caster->nlos; i++) {
targcell = caster->los[i];
if (isplayer(caster)) {
target = caster;
}
// 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) {
nexto = o->next;
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
fizzle(caster);
} else {
int tries = 0,maxtries = 10;
if (lfhasflag(caster, F_CONTROL) && (power < 6)) {
power = 6;
}
if (power >= 6) {
// controlled
// must be within line of sight.
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (!targcell) {
fizzle(caster);
return B_TRUE;
}
} else {
cell_t *poss[MAXCANDIDATES];
int nposs = 0,x,y;
// pick a random location
targcell = NULL;
while (!targcell || !cellwalkable(caster, targcell, NULL) || celldangerous(caster, targcell, B_FALSE, NULL)) {
int i;
i = rnd(0,caster->nlos-1);
targcell = caster->los[i];
tries++;
if (tries >= maxtries) {
// only needs to be in line-of-FIRE, not neccesarily sight.
for (y = 0 ; y <= caster->cell->map->h; y++) {
for (x = 0 ; x <= caster->cell->map->w; x++) {
cell_t *c;
c = getcellat(caster->cell->map, x, y);
if (c && haslof(caster->cell, c, LOF_WALLSTOP, NULL)) {
if (cellwalkable(caster, targcell, NULL) &&
!celldangerous(caster, targcell, B_FALSE, NULL)) {
poss[nposs++] = c;
}
}
if (nposs >= MAXCANDIDATES) break;
}
if (nposs >= MAXCANDIDATES) break;
}
if (!nposs) {
fizzle(caster);
return B_FALSE;
}
return B_TRUE;
}
targcell = poss[rnd(0,nposs-1)];
}
teleportto(caster, targcell, B_TRUE);
}
@ -2231,9 +2279,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
needredraw = B_TRUE;
}
} else if (spellid == OT_S_CONFISCATE) {
object_t *o;
char ch = 'a';
char obname[BUFLEN];
if (targob) {
target = targob->pile->owner;
} else {
object_t *o;
// ask for a target cell
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
@ -2242,7 +2293,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
return B_FALSE;
}
// take an object
// which object to take?
initprompt(&prompt, "Confiscate which object?");
addchoice(&prompt, '-', "(Cancel)", NULL, NULL);
for (o = target->pack->first ; o ; o = o->next) {
@ -2257,32 +2309,35 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (isplayer(caster)) {
// select one
getchoice(&prompt);
o = (object_t *)prompt.result;
targob = (object_t *)prompt.result;
} else {
// random one
o = (object_t *) prompt.choice[rnd(0,prompt.nchoices-1)].data;
targob = (object_t *) prompt.choice[rnd(0,prompt.nchoices-1)].data;
}
if (o) {
}
if (targob) {
if (target) {
if (isplayer(target)) {
getobname(o, obname, o->amt);
msg("^%cYour %s vanish%s!", getlfcol(target, CC_VBAD), noprefix(obname), (o->amt == 1) ? "es" : "");
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(o, obname, o->amt);
getobname(targob, obname, targob->amt);
msg("%s%s %s appear%s in your pack!", targname, getpossessive(targname),
noprefix(obname), (o->amt == 1) ? "es" : "");
noprefix(obname), (targob->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) {
char targname[BUFLEN];
getlfname(target, targname);
getobname(o, obname, o->amt);
getobname(targob, obname, targob->amt);
msg("^%c%s%s %s vanish%s!", getlfcol(target, CC_VBAD), targname, getpossessive(targname), noprefix(obname),
(o->amt == 1) ? "es" : "");
(targob->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
moveob(o, caster->pack, ALL);
}
moveob(targob, caster->pack, ALL);
} else {
fizzle(caster);
}
@ -2809,9 +2864,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
} else if (spellid == OT_S_CREATEMONSTER) {
lifeform_t *newlf;
job_t *forcejob = NULL;
race_t *r = NULL;
int randomjobsok = B_TRUE;
if (!targcell) {
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)) {
// ask what kind of monster
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 {
// random one
r = getreallyrandomrace(RC_ANY);
}
if (forcejob) {
randomjobsok = B_FALSE;
} else {
randomjobsok = B_TRUE;
sprintf(buf, "%s", r->name);
}
// 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 (haslos(player, targcell)) {
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 (seenbyplayer) *seenbyplayer = B_TRUE;
}
if (isplayer(caster) && !frompot) {
pleasegodmaybe(R_GODMERCY, 3);
}
} else if (spellid == OT_S_DARKNESS) {
if (!targcell) targcell = caster->cell;
// centre on the caster
@ -3008,7 +3025,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
o->blessknown = B_TRUE;
}
} else {
nothinghappens();
if (isplayer(caster)) nothinghappens();
}
} else {
// 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);
}
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (isplayer(target)) {
msg("You feel your life force draining away!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
if (target) {
@ -3498,7 +3518,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE;
}
// 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 (haslos(player, targcell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -3790,7 +3810,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (isplayer(caster)) {
if (!hasflag(o->flags, F_ENCHANTABLE)) {
nothinghappens();
if (isplayer(caster)) nothinghappens();
return B_TRUE;
} else {
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");
}
} else if (spellid == OT_S_GASEOUSFORM) {
target = caster;
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (!target) target = caster;
if ((target->race->id != R_VAMPIRE) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (isplayer(target)) {
msg("You feel momentarily insubstantial.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -4022,8 +4042,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
// remember the original race
addflag(target->flags, F_ORIGRACE, target->race->id, NA, NA, NULL);
// polymorph is always will be temporary
if (target->race->id != R_VAMPIRE) {
// polymorph is temporary
addtempflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL, 10);
}
setrace(target, R_GASCLOUD, B_TRUE);
}
} else if (spellid == OT_S_GREASE) {
@ -4208,11 +4230,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
donesomething = B_TRUE;
}
if (!donesomething) {
if (isplayer(target)) {
if (!donesomething) {
nothinghappens();
}
}
if (donesomething && isplayer(caster) && !frompot) {
pleasegodmaybe(R_GODMERCY, 3);
}
} else if (spellid == OT_S_HOLDPORTAL) {
object_t *o;
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;
} else {
if (cansee(player, target)) {
char lfname[BUFLEN];
getlfname(target, lfname);
msg("%s looks ravenously hungry!", lfname);
if (!lfhasflagval(target, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL)) {
addflag(target->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
if (lfhasflag(target, F_HUNGER)) {
modhunger(target, HUNGERCONST); // make more hungry
} else {
// ie. "hungry"
addflag(target->flags, F_HUNGER, HUNGERCONST*2, NA, NA, NULL);
}
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
@ -4635,15 +4660,49 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// 10 = gun speed
fireat(caster, targob, 1, targcell, 8 + (power / 2) , NULL);
} else if (spellid == OT_S_PLANESHIFT) {
if (isplayer(caster)) {
msg("^B__not yet implemented__");
map_t *m;
target = caster;
if (isplayer(target)) {
region_t *r;
char ch = 'a';
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 {
if (cansee(player, caster)) {
if (cansee(player, target)) {
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) {
int howlong;
@ -5156,7 +5215,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getlfname(target, 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");
} else {
fizzle(caster);
@ -5604,7 +5663,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getobname(blowob[i], obname, 1);
c = getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND);
if (c && ((rnd(1,100)+power) <= 33)) {
if (c && ((rnd(1,100)-power) <= 33)) {
// move it
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;
}
} else {
nothinghappens();
if (isplayer(caster)) nothinghappens();
return B_TRUE;
}
} else if (spellid == OT_S_PACIFY) {
@ -6009,6 +6068,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else {
fizzle(caster);
}
if (ndone && isplayer(caster) && !frompot) {
pleasegodmaybe(R_GODMERCY, 3);
}
} else if (spellid == OT_S_REPELINSECTS) {
// just announce
if (isplayer(caster)) {
@ -6075,6 +6137,29 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
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) {
flag_t *f;
// always targetted at caster
@ -6862,7 +6947,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
wantsize = SZ_ANY;
break;
}
ngot = summonlfs(caster, wantrc, wantsize, nwant, lifetime);
ngot = summonlfs(caster, caster->cell, wantrc, wantsize, nwant, lifetime);
if (!ngot) {
fizzle(caster);
return B_TRUE;
@ -7414,12 +7499,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// now age the caster
if (!isgod(caster)) {
caster->maxhp -= pctof(25,caster->maxhp);
limit(&caster->hp, NA, caster->maxhp);
if (isplayer(caster)) {
msg("^BYour body ages unnaturally!");
statdirty = B_TRUE;
}
age(caster, 25);
}
if (isplayer(target)) {
@ -7491,12 +7571,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// now age the caster
if (!isgod(caster)) {
caster->maxhp -= pctof(50,caster->maxhp);
limit(&caster->hp, NA, caster->maxhp);
if (isplayer(caster)) {
msg("^BYour body ages unnaturally!");
statdirty = B_TRUE;
}
age(caster, 50);
}
} else {
// monsters can't wish
@ -8281,7 +8356,7 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) {
// 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;
race_t *r = NULL;
enum RACE poss[MAXCANDIDATES];
@ -8316,7 +8391,7 @@ int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, i
ncreated = 0;
for (i = 0; i < howmany; i++) {
// get random adjacent cell
c = getrandomadjcell(caster->cell, WE_EMPTY, B_ALLOWEXPAND);
c = getrandomadjcell(where, WE_EMPTY, B_ALLOWEXPAND);
if (!c) {
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)]);
if (r) {
// 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
killflagsofid(newlf->flags, F_XPVAL);
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) {
return *targcell;
} else if ((caster->race->raceclass->id == RC_GOD) && targcell) {
return *targcell;
}
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);

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 stopallspells(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);
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);

21
text.c
View File

@ -10,7 +10,6 @@
extern long curtime;
int needan(char *text) {
if (isvowel(tolower(text[0]))) {
return B_TRUE;
@ -58,12 +57,18 @@ enum COLOUR chartocol(char ch) {
return C_BROWN;
case 'B': // v.bad
return C_RED;
case 'T': // terrible
return C_ORANGE;
case 'g': // good
return C_GREEN;
case 'G': // v.good
return C_CYAN;
case 'E': // excllent
return C_BOLDCYAN;
case 'h': // 'hilite'
return C_WHITE;
case 'l': // 'bLue'
return C_BLUE;
case 'n': // normal
default:
break;
@ -678,6 +683,20 @@ int streq(char *a, char *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) {
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 *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv);
int streq(char *a, char *b);
char *strends(char *a, char *suffix);
char *strstarts(char *a, char *prefix);
int strpixmatch(char *haystack, char *needle);
int texttodice(char *text, int *ndice, int *nsides, int *bonus);

View File

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

View File

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

View File

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

View File

@ -20,5 +20,6 @@ X:exit
! autoscale, lock xy
goesin:dungeon
mayrotate
rarity:common
@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
! mayrotate
! mayscale
rarity:uncommon
@end

View File

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

View File

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

View File

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

View File

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

View File

@ -14,5 +14,6 @@ autodoors:100
scatter(1,1,-2,-2) ob:statue:25%
scatter(1,1,-2,-2) mon:cockatrice:1
scatter(1,1,-2,-2) ob:1-10 stones:1-5
rarity:rare
@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%:50
scatter(1,1,-2,-2) ob:random:100%:50
rarity:rare
@end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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