* [+] operate a candlabrum on the ground confers permenant light

producing!
* [+] bug - water appearing in walls.
- [+] make armour less common in forests
- [+] too many --more--s when enhancing stats.  use drawmsg() rather
      than more().
- [+] when i go up/down stairs, i keep ending up BESIDE them??
* [+] "you hear footstepszzzzzzzzzzzzzzzzzzzzzzz" (random junk)
- [+] when i start training with a spell active, it gets interrupted.
      try again, interrupted again! works 3rd time.
- [+] replace lockpicking with "locksmithing"
- [+] replace 'body control' with 'slow metabolism'
- [+] pit traps broken - fixed now.
- [+] doheading issue in @M still.
* [+] how did zombie get 28 hp? bug in rollhitdice.
- [+] blind a skeleton with light.  it gets blind, starts fleeing. but
      because it can't SEE you, it stops fleeing instantly!
* [+] getflags(flagpile_t *fp, ... )
- [+] stun spell
- [+] only say "x2" etc if msgbuf we are going to draw still contains
      the original text.
- [+] when you level up, your psionic skill determines your chance of
      learning a new psionic spell?
- [+] when you teleport/use stairs, get all allies in SIGHT, not
      adjacent.
* [+] more traps!
* [+] prisoners in cells
- [+] recruitment: instead of outright refusing to join, just up the
      price.
* [+] make spellbook contents depend on map difficulty
- [+] cloak of shadows - give invisibility when in darkness
* [+] limited wish:
- [+] casting WISH reduces max hp by 50%!
- [+] monster ai code: if inventory full (or close), put non-eqiupped
      stuff into containers
* [+] infinite loop in firedam to lf
- [+] pot of xp isn't working for monsters. they get no more hp!!
- [+] summonmosnter should jsut relocate existing uniques
- [+] 'planeshift' spell for gods - "unsummon"s them.
* [+] diety - greedgod
* [+] more village contents
This commit is contained in:
Rob Pearce 2011-07-26 02:01:05 +00:00
parent ce878f6ae8
commit 07844bb69e
18 changed files with 1401 additions and 341 deletions

56
ai.c
View File

@ -603,7 +603,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
} else {
// spell succesful
if (spell == OT_A_STEAL) {
if ((spell == OT_A_STEAL) && !lfhasflag(lf, F_NOFLEE)) {
// run away for a few turns
fleefrom(lf, spelllf, rnd(3,7), B_TRUE);
}
@ -800,7 +800,7 @@ int aipickup(lifeform_t *lf, object_t *o) {
if (isedible(o)) {
return eat(lf, o);
} else {
return pickup(lf, o, o->amt, B_TRUE);
return pickup(lf, o, o->amt, B_TRUE, B_TRUE);
}
return B_FALSE;
}
@ -918,6 +918,53 @@ void aiturn(lifeform_t *lf) {
// use items, talk,etc
///////////////////////////////////////////////
if ((lf->race->id == R_PRISONER) && master && isplayer(master) && cansee(lf, master)) {
if (isoutdoors(lf->cell->map) && pctchance(20)) {
object_t *o;
say(lf, "Thanks for getting me out!", SV_TALK);
o = addob(master->pack, "manual");
if (o) {
char obname[BUFLEN];
say(lf, "Here, let me teach you something as a reward.", SV_TALK);
getobname(o, obname, o->amt);
msgnocap("%c - %s", o->letter, obname);
}
killflagsofid(lf->flags, F_PETOF);
}
}
// too many objects?
i = countobs(lf->pack, B_FALSE);
if (i >= (MAXPILEOBS - 5)) {
object_t *container;
// get largest container with space
container = getbestcontainer(lf->pack);
if (container) {
object_t *o;
// find object which will fit
for (o = lf->pack->first ; o ; o = o->next) {
if ((o != container) && !isequipped(o) && obfits(o, container->contents)) {
// put it in.
moveob(o, container->contents, ALL);
if (cansee(player, lf)) {
char obname[BUFLEN];
char lfname[BUFLEN];
char containername[BUFLEN];
// announce
getobname(o, obname, o->amt);
getobname(container, containername, 1);
getlfname(lf, lfname);
msg("%s puts %s into %s.", lfname, obname, containername);
}
// timetime
taketime(lf, getactspeed(lf));
return;
}
}
}
}
// talking
f = lfhasflag(lf, F_RANDOMTALKPCT);
if (f) {
@ -1572,6 +1619,11 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if ((ot->id == OT_A_SPRINT) && lfhasflag(lf, F_SPRINTING)) {
specificcheckok = B_FALSE;
}
if ((ot->id == OT_A_STEAL) || (ot->id == OT_S_CONFISCATE)) {
if (!countobs(victim->pack, B_FALSE)) {
specificcheckok = B_FALSE;
}
}
if ((ot->id == OT_A_SWOOP) || (ot->id == OT_A_CHARGE)) {
flag_t *willflag;
flag_t *srflag;

View File

@ -84,9 +84,11 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty
actualdam *= multiplier;
}
if (actualdam > 0) {
// actually apply the damage to the armour
damtaken = takedamage(armour,actualdam, damtype);
}
}
return damtaken;
}
@ -351,7 +353,6 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
} else if (attacktype == AT_OB) {
if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) break;
}
}
attacksdone++;
// stop attacking if they somehow got out of range
@ -364,6 +365,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
}
}
}
}
// now kill all temp obs
if (op) {
@ -789,7 +791,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
} else if (lfhasflag(lf, F_QUIVERINGPALM)) {
// victim explodes!
losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE);
losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE, NULL);
} else {
char attackername2[BUFLEN];
real_getlfname(lf, attackername2, B_FALSE);
@ -805,7 +807,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
strcpy(buf, attackername2);
}
losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE);
losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE, NULL);
// victim's armour loses hp
if (reduceamt) {
@ -850,7 +852,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
char lfname[BUFLEN];
dam = rolldie(f->val[0], f->val[1]) + f->val[2];
real_getlfname(lf, lfname, B_FALSE);
losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE);
losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE, NULL);
if (isplayer(victim) || cansee(player, victim)) {
msg("^%c%s bites %s!", isplayer(victim) ? 'b' : 'n', lfname, victimname);
}

29
defs.h
View File

@ -47,6 +47,8 @@ enum NOISECLASS {
enum SAYPHRASE {
SP_BEG,
SP_BEGATTACK,
SP_BEGTHANKS,
SP_DRUNK,
SP_PAYWARN,
SP_PAYTHREAT,
@ -641,6 +643,7 @@ enum RACECLASS {
RC_ANIMAL,
RC_AQUATIC,
RC_DEMON,
RC_GOD,
RC_HUMANOID,
RC_INSECT,
RC_SLIME,
@ -659,7 +662,10 @@ enum RACE {
R_BANDIT,
R_BEGGAR,
R_DRUNK,
R_PRISONER,
R_TOWNGUARD,
// gods
R_GODGREED,
// monsters
R_BEHOLDER,
R_BUGBEAR,
@ -841,14 +847,20 @@ enum OBTYPE {
// terrain
OT_WATERDEEP,
// traps
OT_TRAPALARM,
OT_TRAPARROW,
OT_TRAPARROWP,
OT_TRAPEBLAST,
OT_TRAPFIRE,
OT_TRAPGAS,
OT_TRAPMINE,
OT_TRAPNEEDLEP,
OT_TRAPPIT,
OT_TRAPROCK,
OT_TRAPSUMMON,
OT_TRAPTELEPORT,
OT_TRAPTRIP,
OT_TRAPWIND,
// rocks / plants
OT_GOLD,
OT_STONE,
@ -1012,15 +1024,18 @@ enum OBTYPE {
OT_S_HEALING,
OT_S_HEALINGMIN,
OT_S_HEALINGMAJ,
OT_S_SPEAKDEAD,
OT_S_TURNUNDEAD,
// -- mental / psionic
OT_S_BODYCONTROL,
OT_S_CHARM,
OT_S_HUNGER,
OT_S_MINDSCAN,
OT_S_SLEEP,
OT_S_TELEKINESIS,
OT_S_LOWERMETAB,
OT_S_PACIFY,
OT_S_PSYARMOUR,
OT_S_CHARM,
OT_S_SLEEP,
OT_S_STUN,
OT_S_TELEKINESIS,
// -- modification
OT_S_DARKNESS,
OT_S_ENCHANT,
@ -1076,6 +1091,7 @@ enum OBTYPE {
OT_S_BLINK,
OT_S_DISPERSAL,
OT_S_GATE,
OT_S_PLANESHIFT,
OT_S_SUCK,
OT_S_TELEPORT,
OT_S_TWIDDLE,
@ -1090,7 +1106,9 @@ enum OBTYPE {
OT_S_CREATEVAULT,
OT_S_GIFT,
OT_S_WISH,
OT_S_WISHLIMITED,
OT_A_BLINDALL,
OT_S_CONFISCATE,
OT_A_DEBUG,
OT_A_ENHANCE,
OT_A_LEARN,
@ -1153,6 +1171,7 @@ enum OBTYPE {
OT_PICKAXE,
OT_ROPE,
OT_SACK,
OT_SACKHUGE,
OT_SAFEBOX,
OT_TORCH,
OT_TOWEL,
@ -1559,6 +1578,7 @@ enum FLAG {
F_NOBLESS, // can't be blessed or cursed
F_NOQUALITY, // can't be masterwork / shoddy
F_CORPSEOF, // this is a corpse of montype val0.
// text is how it died.
F_DTCONVERT, // damtype val0 converts this to f->text
F_DTCREATEOB, // damtype val0 creates object f->text here
// v1 = radius to burst in
@ -1977,6 +1997,7 @@ enum FLAG {
F_HITDICE, // val0: # d4 to roll for maxhp per level. val1: +xx
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.
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

5
doc/colours.txt Normal file
View File

@ -0,0 +1,5 @@
^B very bad
^b bad
^w warning
^g good
^G very good

1
doc/godnames Normal file
View File

@ -0,0 +1 @@
Avamon God of greed (neutral)

31
flag.c
View File

@ -10,6 +10,9 @@
#include "spell.h"
#include "text.h"
flag_t *retflag[MAXCANDIDATES];
int nretflags;
extern enum GAMEMODE gamemode;
extern int needredraw;
extern int statdirty;
@ -1016,6 +1019,34 @@ void timeeffectsflag(flag_t *f, int howlong) {
}
}
// populates retflag & nretflags with matching flags
int getflags(flagpile_t *fp, ... ) {
va_list flags;
enum FLAG wantflag[MAXCANDIDATES];
int nwantflags,i;
flag_t *f;
va_start(flags, fp);
nwantflags = 0;
wantflag[nwantflags] = va_arg(flags, enum FLAG);
while (wantflag[nwantflags] != F_NONE) {
nwantflags++;
wantflag[nwantflags] = va_arg(flags, enum FLAG);
}
va_end(flags);
// now populate retflag[] with matches flags
nretflags = 0;
for (i = 0; i < nwantflags; i++) {
f = hasflag(fp, wantflag[i]);
while (f && (f->id == wantflag[i])) {
retflag[nretflags++] = f;
f = f->next;
}
}
return nretflags;
}
int modcounter(flagpile_t *fp, int amt) {
flag_t *f;
f = hasflag(fp, F_COUNTER);

1
flag.h
View File

@ -14,6 +14,7 @@ int countflags(flagpile_t *fp);
int flagcausesredraw(lifeform_t *lf, enum FLAG fid);
int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid);
int flagstacks(enum FLAG fid);
int getflags(flagpile_t *fp, ... );
int modcounter(flagpile_t *fp, int amt);
flag_t *hasflag(flagpile_t *fp, int id);
flag_t *hasflagknown(flagpile_t *fp, int id);

82
io.c
View File

@ -1174,7 +1174,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
objecttype_t *ot;
ot = findot(f->val[0]);
if (ot) {
msg("^gYou have learned the spell '%s'.", ot->name);
enum SPELLSCHOOL school;
school = getspellschoolknown(lf, ot->id);
msg("^gYou have learned the %s '%s'.",
(school = SS_MENTAL) ? "psionic power" : "spell", ot->name);
donesomething = B_TRUE;
}
}
@ -1392,7 +1395,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, buf);
msg("^w%s %s %s!",buf, isplayer(lf2) ? "grab" : "grabs", lfname);
msg("^%c%s %s %s!",getlfcol(lf, CC_VBAD), buf, isplayer(lf2) ? "grab" : "grabs", lfname);
donesomething = B_TRUE;
}
break;
@ -3956,6 +3959,7 @@ void doclose(void) {
void docomms(lifeform_t *lf) {
cell_t *where;
int i;
char buf[BUFLEN];
char lfname[BUFLEN];
char ch;
@ -4008,8 +4012,16 @@ void docomms(lifeform_t *lf) {
addchoice(&prompt, '>', "Keep your distance.", NULL, NULL);
}
} else if (ishirable(lf) ) {
if (lf->race->id == R_PRISONER) {
addchoice(&prompt, 'j', "Join me, and I will help you escape.", NULL, NULL);
} else {
addchoice(&prompt, 'j', "Join me on my quest!", NULL, NULL);
}
}
if ((lf->race->id == R_BEGGAR) && countmoney(player)) {
addchoice(&prompt, 'd', "(donate a gold coin)", NULL, NULL);
}
f = lfhasflag(lf, F_OWNSSHOP);
if (f) {
@ -4060,6 +4072,57 @@ void docomms(lifeform_t *lf) {
aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME);
}
break;
case 'd': // donate to beggar
givemoney(player, lf, 1); // we already checked that we had enough.
if (countmoney(lf) == 1) {
i = rnd(1,100);
if (i <= 5) { // attack you
sayphrase(lf, SP_BEGATTACK, SV_SHOUT, NA, NULL);
fightback(lf, player);
} else if (i <= 10) { // limited wish
// change to a god.
setrace(lf, R_GODGREED, B_TRUE);
// 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);
// grant a wish.
castspell(lf, OT_S_WISHLIMITED, player, NULL, NULL);
say(lf, "Until next time, mortal!", SV_TALK);
unsummon(lf, B_TRUE);
} else if (i <= 20) { // identify
object_t *poss[MAXPILEOBS],*o;
int nposs = 0;
sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL);
// get random unknown item from player's pack
for (o = player->pack->first ; o ; o = o->next){
if (!isknown(o)) {
poss[nposs++] = o;
}
}
if (nposs) {
char oldobname[BUFLEN];
char newobname[BUFLEN];
o = poss[rnd(0,nposs-1)];
getobname(o, oldobname, o->amt);
makeknown(o->type->id);
getobname(o, newobname, o->amt);
msg("%s points at your pack.", lfname);
msg("Hey I recognise %s %s.",
(o->amt == 1) ? "that" : "those",
oldobname);
msg("%s %s.",
(o->amt == 1) ? "It's" : "They're",
newobname);
}
} else { // nothing
sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL);
}
} else {
// they already had some money
sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL);
}
break;
case 'g':
sprintf(buf, "Tell %s to go where?",lfname);
sprintf(buf2, "%s->Goto->",lfname);
@ -5025,7 +5088,7 @@ int dopickup(obpile_t *op, int forceask) {
}
for (i = 0; i < nretobs; i++) {
pickup(player, retobs[i],retobscount[i], B_TRUE);
pickup(player, retobs[i],retobscount[i], B_TRUE, B_TRUE);
}
/*
@ -5724,12 +5787,14 @@ void drawlevelfor(lifeform_t *lf) {
}
void doheading(WINDOW *win, int *y, int x, char *what) {
int len;
int len,i;
char *buf;
len = strlen(what) + 1;
buf = malloc(len * sizeof(char));
memset(buf, '-', (size_t)(len-1));
buf[len] = '\0';
for (i = 0; i < len; i++) {
buf[i] = '-';
}
buf[i] = '\0';
setcol(win, C_WHITE);
mvwprintw(win, *y, x, what); (*y)++;
mvwprintw(win, *y, x, buf); (*y)++;
@ -6850,7 +6915,10 @@ void msg_real(char *format, ... ) {
vsprintf( buf, format, args );
va_end(args);
if (streq(buf, prevmsg) && !strchr(buf, '^')) {
assert(buf[0] != '\0');
// ie repeat of previous message, doesn't have colours, prev msg still on screen
if (streq(buf, prevmsg) && !strchr(buf, '^') && strstr(msgbuf, prevmsg)) {
msgmulti++;
sprintf(buf, "x%d",msgmulti);
} else {

365
lf.c
View File

@ -27,6 +27,9 @@ extern skill_t *firstskill, *lastskill;
extern objecttype_t *objecttype;
extern lifeform_t *player;
extern flag_t *retflag[];
extern int nretflags;
extern glyph_t playerglyph;
extern glyph_t tempglyph;
@ -821,6 +824,7 @@ int cansee(lifeform_t *viewer, lifeform_t *viewee) {
flag_t *f;
int xray = 0;
int dist;
int tremordist;
if (gamemode < GM_GAMESTARTED) {
return B_TRUE;
@ -836,6 +840,16 @@ int cansee(lifeform_t *viewer, lifeform_t *viewee) {
xray = 0;
}
dist = getcelldist(viewer->cell, viewee->cell);
f = lfhasflag(viewer, F_TREMORSENSE);
if (f) {
if (f->val[0] > 0) {
tremordist = f->val[0];
} else {
tremordist = dist;
}
} else {
tremordist = -1;
}
// viewer asleep?
if (lfhasflag(viewer, F_ASLEEP)) {
@ -852,11 +866,21 @@ int cansee(lifeform_t *viewer, lifeform_t *viewee) {
// viewee is invisible?
if (lfhasflag(viewee, F_INVISIBLE)) {
if (!lfhasflag(viewer, F_SEEINVIS)) {
if (!lfhasflag(viewer, F_SEEINVIS) && (tremordist < dist)) {
return B_FALSE;
}
}
// cloak of shadows?
o = getequippedob(viewee->pack, BP_SHOULDERS);
if (o && hasflagval(o->flags, F_HASBRAND, BR_SHADOWS, NA, NA, NULL)) {
if (!islit(viewee->cell)) {
if (!lfhasflag(viewer, F_SEEINVIS) && (tremordist < dist)) {
return B_FALSE;
}
}
}
// viewee hiding?
if (lfhasflag(viewee, F_HIDING) && (viewee != viewer)) {
if (!lfhasflagval(viewer, F_SPOTTED, viewee->id, NA, NA, NULL)) {
@ -1780,6 +1804,13 @@ void die(lifeform_t *lf) {
addflag(corpse->flags, f->val[0], f->val[1], f->val[2], NA, f->text);
}
}
// remember what killed us.
f = hasflag(corpse->flags, F_CORPSEOF);
if (f) {
free(f->text);
f->text = strdup(lf->lastdam);
}
}
@ -2486,6 +2517,7 @@ void enhanceskills(lifeform_t *lf) {
char ch = 'a';
int newskillcost = 1;
float hpratio,mpratio;
enum SKILLLEVEL slev;
lf->level = lf->newlevel;
@ -2547,7 +2579,7 @@ void enhanceskills(lifeform_t *lf) {
drawstatus();
wrefresh(statwin);
// wait for player to acknowledge 'you feel stronger' etc
more();
drawmsg(); // TODO: this use to be more()
}
f = lfhasflag(lf, F_STATGAINREADY);
}
@ -2842,6 +2874,27 @@ void enhanceskills(lifeform_t *lf) {
}
}
// psionics sometimes lets you learn spells
slev = getskill(lf, SK_SS_MENTAL);
if (pctchance(slev*10)) {
// construct list of castable mental spells
makespellchoicelist(&prompt, lf, "Learn which new psionic power:","Describe which psionic power:", SS_MENTAL, B_TRUE, B_FALSE, player->maxmp);
if (prompt.nchoices > 0) {
objecttype_t *ot;
msg("You have developed a new psionic power!"); more();
getchoicestr(&prompt, B_TRUE, B_TRUE);
ot = prompt.result;
if (ot) {
if (prompt.whichq == 0) { // learn the spell
addflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL);
} else {
describespell(ot);
}
}
}
}
killflagsofid(lf->flags, F_HASNEWLEVEL);
// ready for another level?
@ -3029,6 +3082,17 @@ lifeform_t *findlf(map_t *m, int lfid) {
return NULL;
}
lifeform_t *findlfunique(enum RACE rid) {
lifeform_t *lf;
map_t *thismap;
for (thismap = firstmap ; thismap ; thismap = thismap->next) {
for (lf = thismap->lf ; lf ; lf = lf->next) {
if (lf->race->id == rid) return lf;
}
}
return NULL;
}
race_t *findrace(enum RACE id) {
race_t *r;
for (r = firstrace; r ; r = r->next) {
@ -3151,8 +3215,10 @@ int flee(lifeform_t *lf) {
// a certain time period (ie. f->lifetime == PERMENANT), we can now stop fleeing.
if (f->lifetime == PERMENANT) {
killflag(f);
}
} else {
// if the flag is temporary, wait for it to time out normally
fleefrom = thisone;
}
}
}
}
@ -3161,6 +3227,9 @@ int flee(lifeform_t *lf) {
// found someone who we are fleeing from?
if (fleefrom) {
object_t *stairs;
breakallgrabs(lf);
// ways of fleeing other than movement?
if (!isplayer(lf)) {
enum OBTYPE spell;
@ -3478,21 +3547,34 @@ int getactspeed(lifeform_t *lf) {
}
// include allies or enemies which will follow you up/down stairs etc
// ie. allies within LOS
// ie. adjacent enemies
void getadjallies(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, int *nadjallies) {
int d;
for (d = DC_N; d <= DC_NW; d++) {
int x,y;
for (y = 0; y < lf->cell->map->h; y++) {
for (x = 0; x < lf->cell->map->w; x++) {
cell_t *c;
c = getcellindir(lf->cell, d);
if (c && c->lf) {
if (areallies(lf, c->lf) || areenemies(lf, c->lf)) {
c = getcellat(lf->cell->map, x, y);
if (c && c->lf && (c->lf != lf)) {
if (!isimmobile(c->lf) && cansee(c->lf, lf)) {
int ok = B_TRUE;
int ok = B_FALSE;
if (areallies(lf, c->lf) && haslof(c->lf->cell, lf->cell, LOF_WALLSTOP, NULL)) {
// ally with a clear path to you
ok = B_TRUE;
} else if (areenemies(lf, c->lf) && (getcelldist(c, lf->cell) == 1)) {
// adjacent enemy
ok = B_TRUE;
}
if (ok) {
// if this was a pit, only flying things will follow
if (stairob && hasflag(stairob->flags, F_PIT)) {
if (!lfhasflag(c->lf, F_FLYING)) {
ok = B_FALSE;
}
}
if (ok) { // still ok?
adjally[*nadjallies] = c->lf;
(*nadjallies)++;
}
@ -3500,6 +3582,8 @@ void getadjallies(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, int *
}
}
}
}
}
enum ALLEGIENCE getallegiance(lifeform_t *lf) {
flag_t *f;
@ -4352,6 +4436,8 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) {
// get weapon
if (wep) {
acc = getobaccuracy(wep, lf);
} else {
acc = 100; // fists
}
// dual weilding?
@ -7493,6 +7579,8 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_RANGED, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL);
// abilities
@ -7547,7 +7635,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_LEVFLAG, 2, F_MPDICE, 1, NULL);
addflag(lastjob->flags, F_LEVSPELL, 2, OT_S_CALMANIMALS, NA, NULL);
// 2: body control - low metabolism
addflag(lastjob->flags, F_LEVSPELL, 3, OT_S_BODYCONTROL, NA, NULL);
addflag(lastjob->flags, F_LEVSPELL, 3, OT_S_LOWERMETAB, NA, NULL);
// 4: self-healing (mp), immune to haste/slow (innate)
addflag(lastjob->flags, F_LEVFLAG, 4, F_DISEASEIMMUNE, B_TRUE, NULL);
addflag(lastjob->flags, F_LEVABIL, 5, OT_A_HEAVYBLOW, 3, NULL);
@ -7795,6 +7883,7 @@ void initrace(void) {
addraceclass(RC_ANIMAL, "animal", "animals and insects", SK_LORE_NATURE);
addraceclass(RC_AQUATIC, "aquatic creature", "aquatic creatures", SK_LORE_NATURE);
addraceclass(RC_DEMON, "demon", "demons", SK_LORE_DEMONS);
addraceclass(RC_GOD, "god", "dieties", SK_NONE);
addraceclass(RC_HUMANOID, "humanoid", "humanoid creatures", SK_LORE_HUMANOID);
addraceclass(RC_INSECT, "insect", "insects and animals", SK_LORE_NATURE);
addraceclass(RC_MAGIC, "magical creature", "magical creatures", SK_LORE_ARCANA);
@ -7856,6 +7945,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTJOB, 75, J_RANDOM, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL);
// human monsters...
addrace(R_BANDIT, "bandit", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID);
@ -7917,6 +8007,22 @@ void initrace(void) {
f = addflag(lastrace->flags, F_DRUNK, 5, NA, NA, NULL);
addcondition(f, FC_NOCONDITION, 30);
addaltval(f, F_DRUNK, 3, NA, NA, NULL);
addrace(R_PRISONER, "prisoner", 60, '@', C_GREY, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2");
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-2 stones");
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HIRABLE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HIREPRICE, 0, NA, NA, NULL);
addrace(R_TOWNGUARD, "town guard", 100, '@', C_GREY, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "12-18");
@ -7943,6 +8049,38 @@ void initrace(void) {
addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
// gods
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");
addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "9");
addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "10");
addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "8");
addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "6");
addflag(lastrace->flags, F_DONTSTARTASLEEP, NA, 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_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, "blessed ring of hunger");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 huge sacks");
//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_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_OBESE, B_TRUE, NA, NA, NULL);
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;");
// monsters
addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VHIGH, NA, NULL);
@ -9315,7 +9453,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addrace(R_DOGBLINK, "blink dog", 35, 'd', C_BLUE, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NUMAPPEAR, 2, 8, NA, "");
addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, "");
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_HIGH, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
@ -9981,13 +10119,14 @@ void initrace(void) {
// undead
addrace(R_ZOMBIE, "zombie", 50, 'Z', C_BLUE, MT_FLESH, RC_UNDEAD);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "6");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, NULL);
addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 2, 4, 1, NULL);
addflag(lastrace->flags, F_HITDICE, 2, 4, NA, NULL);
addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
@ -10421,9 +10560,15 @@ int isingunrange(lifeform_t *lf, cell_t *where) {
return B_FALSE;
}
int isgod(lifeform_t *lf) {
if (lf->race->raceclass->id == RC_GOD) return B_TRUE;
if (hasjob(lf, J_GOD)) return B_TRUE;
return B_FALSE;
}
// can you try to recruit this lf?
int ishirable(lifeform_t *lf) {
if (!isplayer(lf) && ispeaceful(lf) && lfhasflag(lf, F_JOB)) {
if (!isplayer(lf) && ispeaceful(lf)) {
if (lfhasflag(lf, F_HIRABLE)) {
return B_TRUE;
}
@ -11151,8 +11296,10 @@ void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o) {
msg("^b%s %ss you!", buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp));
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
char buf2[BUFLEN];
getlfname(lf, lfname);
msg("^c%s %ss %s!", getlfcol(lf, CC_BAD), buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp), lfname);
sprintf(buf2, "^%c%s %ss %s!", getlfcol(lf, CC_BAD), buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp), lfname);
msg("%s", buf2);
}
}
}
@ -11607,10 +11754,10 @@ void loseconcentration(lifeform_t *lf) {
// lose hp, and adjust damage based on resistances
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc) {
return losehp_real(lf, amt, damtype, fromlf, damsrc, B_TRUE);
return losehp_real(lf, amt, damtype, fromlf, damsrc, B_TRUE, NULL);
}
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam) {
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob) {
char buf[BUFLEN];
char buf2[BUFLEN];
char lfname[BUFLEN];
@ -11800,7 +11947,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
}
// elemental effects on held objects
if (damtype == DT_FIRE) {
if ((damtype == DT_FIRE) && !fromob) {
object_t *o, *nexto;
// fire: dam*10 chance of burning each object which is vulnerable to fire
for (o = lf->pack->first ; o ; o = nexto) {
@ -11813,7 +11960,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
takedamage(o, newdam, DT_FIRE);
}
}
} else if (damtype == DT_COLD) {
} else if ((damtype == DT_COLD) && !fromob) {
object_t *o, *nexto;
// cold: dam*10 chance of shattering potions, or damaging other things.
for (o = lf->pack->first ; o ; o = nexto) {
@ -12254,7 +12401,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
// something, its ->cell will be null here!
dist = getcelldist(l->cell, c);
if ((l != noisemaker) && (l->cell)) {
if (l != noisemaker) {
int difficulty;
int lbonus;
//if (canhear(l, c) && haslos(l, c)) {
@ -12265,14 +12412,15 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
// you always hear it, as long as you're in range
difficulty = 0;
} else {
difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20);
//difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20);
difficulty = (int) ( ((float)getcelldist(l->cell, c) / ((float)gethearingrange(l) + volume)) * 20);
}
// listen bonus is the sound volume
if (lfhasflag(l, F_ASLEEP)) {
lbonus = 0;
} else {
lbonus = volume;
if (lfhasflag(l, F_ASLEEP)) {
lbonus -= 5;
limit(&lbonus, 0, NA);
}
// skillcheck to hear this
@ -12294,9 +12442,11 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
char punc;
int dist;
punc = text[strlen(text)-1];
strncpy(textnopunc, text, strlen(text)-1);
textnopunc[strlen(text)] = '\0';
//punc = text[strlen(text)-1];
//strncpy(textnopunc, text, strlen(text)-1);
strcpy(textnopunc, text);
punc = textnopunc[strlen(textnopunc)-1];
textnopunc[strlen(textnopunc)-1] = '\0';
dist = getcelldist(l->cell, c);
@ -12357,15 +12507,17 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
rv = B_TRUE;
}
// only hear one thing per turn.
if (isplayer(l)) {
addflag(l->flags, F_DONELISTEN, B_TRUE, NA, NA, NULL);
practice(l, SK_LISTEN, 1);
}
}
}
// wake up a little
f = lfhasflag(l, F_ASLEEP);
if (f) {
if (f->lifetime > 0) { // ie. temporary
timeeffectsflag(f, rnd(1,10));
timeeffectsflag(f, volume + rnd(1,3));
} else if (f->lifetime == PERMENANT) {
if (f->val[2] == NA) { // ie asleep rather than 'resting'
// wake up!
@ -12403,8 +12555,6 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
isplayer(l) ? "" : "s",
isplayer(l) ? "your" : "its");
}
} else {
break;
}
}
}
@ -12432,7 +12582,7 @@ void petify(lifeform_t *lf, lifeform_t *owner) {
}
int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground) {
int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int wantannounce) {
char obname[BUFLEN];
object_t *o;
//flag_t *f;
@ -12511,6 +12661,7 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground) {
// try to move whatever was selected
o = moveob(what, lf->pack, howmany);
if (o) { // if pickup was successful...
if (wantannounce) {
if (isplayer(lf)) {
// refresh obname to copd with stacking
getobname(o, obname, o->amt);
@ -12520,6 +12671,7 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground) {
getlfname(lf, buf);
msg("%s picks up %s.",buf, obname);
}
}
/*
taketime(lf, (SPEED_PICKUP * howmany));
*/
@ -12677,25 +12829,26 @@ void practice(lifeform_t *lf, enum SKILL skid, int amt) {
void precalclos(lifeform_t *lf) {
int x,y;
cell_t *c;
cell_t **los;
int maxvisrange;
cell_t *los[MAX_MAPW * MAX_MAPH];
int nlos;
int oldnlos = -1,nlos = 0;
int i;
los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH));
// free existing structures
if (lf->los) {
free(lf->los);
oldnlos = lf->nlos;
free(lf->los); lf->los = NULL;
}
nlos = 0;
maxvisrange = getvisrange(lf);
for (y = lf->cell->y - maxvisrange; y <= lf->cell->y + maxvisrange ; y++) {
for (x = lf->cell->x - maxvisrange; x <= lf->cell->x + maxvisrange ; x++) {
c = getcellat(lf->cell->map, x, y);
//
if ((c != lf->cell) && haslos(lf, c)) {
if (c && (c != lf->cell) && haslos(lf, c)) {
los[nlos] = c;
nlos++;
}
@ -12708,6 +12861,7 @@ void precalclos(lifeform_t *lf) {
lf->los[i] = los[i];
}
lf->nlos = nlos;
free(los);
}
int push(lifeform_t *lf, object_t *o, int dir) {
@ -12766,7 +12920,11 @@ int readytotrain(lifeform_t *lf) {
int recruit(lifeform_t *lf) {
int rv = B_FALSE;
if (!lfhasflag(lf, F_NOHIRE)) {
if (lfhasflag(lf, F_NOHIRE)) {
// refusing to join at all.
sayphrase(lf, SP_RECRUIT_DECLINE, SV_TALK, NA, NULL);
rv = B_TRUE;
} else {
int dohire = B_FALSE;
int askingprice = -1;
char lfname[BUFLEN];
@ -12788,8 +12946,9 @@ int recruit(lifeform_t *lf) {
addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL);
} else {
if (difficulty - result >= 10) {
// will never join
askingprice = -1;
// very expensive
askingprice = rnd(gethitdice(lf)*250, gethitdice(lf)*300 );
addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL);
} else {
// expensive
askingprice = rnd(gethitdice(lf)*100, gethitdice(lf)*200 );
@ -12798,14 +12957,7 @@ int recruit(lifeform_t *lf) {
}
}
if (askingprice == -1) {
// refusing to join at all.
sayphrase(lf, SP_RECRUIT_DECLINE, SV_TALK, NA, NULL);
rv = B_TRUE;
if (!lfhasflag(lf, F_NOHIRE)) {
addflag(lf->flags, F_NOHIRE, B_TRUE, NA, NA, NULL);
}
} else {
if (askingprice != 0) {
// modify by charisma
askingprice = pctof(100 + getstatmod(player, A_CHA), askingprice);
@ -12821,13 +12973,17 @@ int recruit(lifeform_t *lf) {
dohire = B_TRUE;
}
}
} else {
dohire = B_TRUE;
}
if (dohire) {
char *p = NULL;
petify(lf, player);
// give them a name
if (getjob(lf)) {
//if (getjob(lf)) {
if (lf->race->raceclass->id == RC_HUMANOID) {
p = assignnpcname(lf);
}
sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p);
@ -12838,7 +12994,6 @@ int recruit(lifeform_t *lf) {
sayphrase(lf, SP_RECRUIT_DECLINE_WONTPAY, SV_TALK, askingprice, NULL);
}
}
}
} // end if !nohire
return rv;
}
@ -12923,6 +13078,11 @@ int startresting(lifeform_t *lf, int willtrain) {
// stop hiding
killflagsofid(lf->flags, F_HIDING);
// stop all spells
stopallspells(lf);
killflagsofid(lf->flags, F_INTERRUPTED);
if (willtrain) {
addflag(lf->flags, F_TRAINING, B_TRUE, NA, traincounter, NULL);
} else {
@ -13088,6 +13248,22 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t
}
rv = say(lf, buf, volume);
break;
case SP_BEGATTACK:
switch (rnd(1,3)) {
case 1: sprintf(buf, "Now give me the everything else!"); break;
case 2: sprintf(buf, "Rich fool!"); break;
case 3: sprintf(buf, "Is that all?"); break;
}
rv = say(lf, buf, volume);
break;
case SP_BEGTHANKS:
switch (rnd(1,3)) {
case 1: sprintf(buf, "A thousand thanks, good sir!"); break;
case 2: sprintf(buf, "Oh thank you!"); break;
case 3: sprintf(buf, "My family shall eat tonight!"); break;
}
rv = say(lf, buf, volume);
break;
case SP_DRUNK:
// random blurred speech
strcpy(buf, "");
@ -13132,11 +13308,19 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t
rv = say(lf, buf, volume);
break;
case SP_RECRUIT_ACCEPT:
if (lf->race->id == R_PRISONER) {
if (text) {
sprintf(buf, "Thank you! My name is %s.", text);
} else {
sprintf(buf, "Thank you!");
}
} else {
if (text) {
sprintf(buf, "I will join you - my name is %s.", text);
} else {
sprintf(buf, "I will join you.");
}
}
rv = say(lf, buf, volume);
break;
case SP_RECRUIT_ASKPRICE:
@ -13180,6 +13364,7 @@ int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus) {
// immune to fear?
if (lfhasflag(lf, F_UNDEAD)) return B_FALSE;
if (isgod(lf)) return B_FALSE;
if (lfhasflag(lf, F_ASLEEP)) {
return B_FALSE;
@ -13342,10 +13527,15 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
msg("^wYou transform into %s %s!", isvowel(newrace->name[0]) ? "an" : "a", newrace->name);
} else if (cansee(player, lf)) {
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);
} else {
msg("^w%s transforms into %s %s!", buf, isvowel(newrace->name[0]) ? "an" : "a", newrace->name);
}
}
}
}
// stop stoning.
killflagsofid(lf->flags, F_BEINGSTONED);
@ -13579,7 +13769,7 @@ void initskills(void) {
addskilldesc(SK_SHIELDS, PR_SKILLED, "^gShield accuracy penalties are reduced by 20%.", B_FALSE);
addskilldesc(SK_SHIELDS, PR_EXPERT, "^gShield accuracy penalties are reduced by 25%.", B_FALSE);
addskilldesc(SK_SHIELDS, PR_MASTER, "^gShield accuracy penalties are reduced by 30%.", B_FALSE);
addskill(SK_SPEECH, "Speech", "Your skill at haggling prices, or swaying others through speech.", 50);
addskill(SK_SPEECH, "Negotiation", "Your skill at haggling prices, or swaying others through speech.", 50);
addskilldesc(SK_SPEECH, PR_NOVICE, "^gShop item prices are reduced by 5%.", B_FALSE);
addskilldesc(SK_SPEECH, PR_BEGINNER, "^gShop item prices are reduced by 10%.", B_FALSE);
addskilldesc(SK_SPEECH, PR_ADEPT, "^gShop item prices are reduced by 15%.", B_FALSE);
@ -14285,7 +14475,6 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) {
char buf[BUFLEN];
sprintf(buf, "Steal what (%d of %d)?", i+1, nsteals);
initprompt(&prompt, buf);
addchoice(&prompt, '-', "Nothing", NULL, NULL);
for (o = op->first ; o ; o = o->next) {
int ok = B_TRUE;
if ((slev < PR_SKILLED) && (getobunitweight(o) >= 3)) {
@ -14307,7 +14496,8 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) {
}
}
if (prompt.nchoices > 1) {
if (slev >= PR_ADEPT) {
if (isplayer(lf) && (slev >= PR_ADEPT)) {
addchoice(&prompt, '-', "Nothing", NULL, NULL);
// pick what you want
getchoice(&prompt);
o = (object_t *)prompt.result;
@ -14448,9 +14638,25 @@ void stopsprinting(lifeform_t *lf) {
// very much like addmonster(), but announce that it appears
// 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 *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.
if (newlf) {
teleportto(newlf, c, B_FALSE);
}
}
if (!newlf) {
newlf = addmonster(c, rid, randomjobsok, 1, B_FALSE, NULL);
if (newlf) {
// assign job if required
@ -14464,6 +14670,7 @@ lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, int rand
msg("%s appears!", buf);
}
// summoned
if (caster) {
addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL);
if (wantfriendly) {
addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL);
@ -14471,10 +14678,12 @@ lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, int rand
makefriendly(newlf, PERMENANT);
}
}
}
// not worth any xp
killflagsofid(newlf->flags, F_XPVAL);
addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL);
}
}
return newlf;
}
@ -14625,10 +14834,9 @@ void timeeffectslf(lifeform_t *lf) {
}
}
f = lfhasflag(lf, F_INTERRUPTED);
if (f) {
if (lfhasflag(lf, F_INTERRUPTED)) {
interrupt(lf);
killflag(f);
killflagsofid(lf->flags, F_INTERRUPTED);
}
if (isdead(lf)) {
@ -14756,7 +14964,7 @@ void turneffectslf(lifeform_t *lf) {
map_t *map;
enum ERROR error;
object_t *o;
flag_t *f, *nextf;
flag_t *f;
flag_t *asp;
char buf[BUFLEN];
lifeform_t *l;
@ -14849,7 +15057,9 @@ void turneffectslf(lifeform_t *lf) {
}
// MP regeneration
for (f = lf->flags->first ; f ; f = f->next) {
getflags(lf->flags, F_MPREGEN, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->id == F_MPREGEN) {
gainmp(lf, f->val[0]);
}
@ -15055,7 +15265,7 @@ void turneffectslf(lifeform_t *lf) {
}
}
f = hasflag(o->flags, F_TRAPPED);
if (f && (f->val[2] != B_TRUE)) {
if (f && (f->val[2] != B_TRUE) && !hasflag(o->flags, F_SECRET)) {
objecttype_t *ot;
flag_t *trapflag;
int diff;
@ -15237,7 +15447,9 @@ void turneffectslf(lifeform_t *lf) {
// for flags which can occur multiple times
for (f = o->flags->first ; f ; f = f->next) {
getflags(o->flags, F_DEEPWATER, F_WALKDAMBP, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if ((f->id == F_DEEPWATER) && !isairborne(lf)) {
checkfordrowning(lf, o);
if (isdead(lf)) return;
@ -15282,8 +15494,10 @@ void turneffectslf(lifeform_t *lf) {
if (isdead(lf)) return;
for (f = lf->flags->first ; f ; f = nextf) {
nextf = f->next;
getflags(lf->flags, F_ATTACHEDTO, F_CANWILL, F_CHARMEDBY, F_FLEEFROM, F_GRABBEDBY, F_GRABBING, F_BOOSTSPELL, F_FEIGNINGDEATH,
F_NOFLEEFROM, F_PETOF, F_SPOTTED, F_STABBEDBY, F_TARGETCELL, F_TARGETLF, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
// remove impossible flags
if ((f->id == F_BOOSTSPELL) && (f->val[0] == OT_S_PASSWALL)) {
if (!lfhasflag(lf, F_NONCORPOREAL)) {
@ -15515,11 +15729,17 @@ void unsummon(lifeform_t *lf, int vanishobs) {
if (cansee(player, lf)) {
char lfname[BUFLEN];
int doyour = B_FALSE;
if (creator && (creator == player)) {
if (!hasflag(lf->flags, F_UNIQUE)) {
doyour = B_TRUE;
}
}
getlfname(lf, lfname);
msg("%s%s vanishes.",
(creator && (creator == player)) ? "Your " : "",
(creator && (creator == player)) ? noprefix(lfname) : lfname
);
msg("%s%s vanishes.", doyour ? "Your " : "",
doyour ? noprefix(lfname) : lfname);
}
if (vanishobs) {
@ -15983,9 +16203,18 @@ int validateraces(void) {
addflag(r->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL);
} else if (r->raceclass->id == RC_DEMON) {
addflag(lastrace->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL);
} else if (r->raceclass->id == RC_GOD) {
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);
addflag(r->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
addflag(r->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL);
addflag(r->flags, F_FLEEONHPPCT, 20, NA, NA, NULL);
addflag(r->flags, F_RESISTMAG, 15, NA, NA, NULL);
addflag(r->flags, F_MORALE, 40, NA, NA, NULL);
} else if (r->raceclass->id == RC_MAGIC) {
addflag(lastrace->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL);
} else if (r->raceclass->id == RC_PLANT) {
addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_DTRESIST, DT_BASH, NA, NA, NULL);

6
lf.h
View File

@ -69,6 +69,7 @@ void fightback(lifeform_t *lf, lifeform_t *attacker);
job_t *findjob(enum JOB jobid);
job_t *findjobbyname(char *name);
lifeform_t *findlf(map_t *m, int lfid);
lifeform_t *findlfunique(enum RACE rid);
race_t *findrace(enum RACE id);
race_t *findracebyname(char *name);
raceclass_t *findraceclass(enum RACECLASS id);
@ -223,6 +224,7 @@ int isfleeing(lifeform_t *lf);
int isfreebp(lifeform_t *lf, enum BODYPART bp);
int isfriendly(lifeform_t *lf);
int isgenius(lifeform_t *lf);
int isgod(lifeform_t *lf);
int ishirable(lifeform_t *lf);
int isimmobile(lifeform_t *lf);
flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt);
@ -253,7 +255,7 @@ int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo);
int loadfirearmfast(lifeform_t *lf);
void loseconcentration(lifeform_t *lf);
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc);
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam);
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob);
void losemp(lifeform_t *lf, int amt);
void makefriendly(lifeform_t *lf, int howlong);
int makenauseated(lifeform_t *lf, int amt, int howlong);
@ -269,7 +271,7 @@ int needstorest(lifeform_t *lf, char *validchars);
int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext);
void outfitlf(lifeform_t *lf);
void petify(lifeform_t *lf, lifeform_t *owner);
int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground);
int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int antannounce);
void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat);
int poisoncausesvomit(enum POISONTYPE ptype);
int poisonthreatenslife(lifeform_t *lf, flag_t *f);

8
map.c
View File

@ -1105,7 +1105,7 @@ flag_t *getmapcoords(map_t *m, int *x, int *y) {
int getmapdifficulty(map_t *m) {
int diff = 1;
if (m) {
if (m->region == RG_WORLDMAP) {
if (isoutdoors(m)) {
int x,y;
// depth is distance from 0,0
getmapcoords(m, &x, &y);
@ -2541,14 +2541,14 @@ int linkexits(map_t *m, int roomid, int minx, int miny, int maxx, int maxy) {
int bestdist = 999;
if (db) dblog(" Need to link.");
// link it. starting from the door, count the number of cells in
// each direction until we hit an empty (walkable) cell not of this room.
// each direction until we hit an empty (walkable) cell which isn't a room.
// if we hit a cell of this roomid, mark this dir as invalid.
for (d = D_N; d <= D_W; d++) {
dist[d] = 0;
c = getcellindir(poss[i], d);
while (c) {
dist[d]++;
if (c->roomid == roomid) {
if (isroom(c)) {
// mark dir as invalid
dist[d] = 999;
break;
@ -3915,7 +3915,7 @@ int isonmap(map_t *map, int x, int y) {
}
int isoutdoors(map_t *m) {
if (m->region == RG_WORLDMAP) {
if (m->region->rtype->id == RG_WORLDMAP) {
return B_TRUE;
}
return B_FALSE;

20
move.c
View File

@ -1467,8 +1467,8 @@ int opendoor(lifeform_t *lf, object_t *o) {
return B_TRUE;
} else {
if (lf) {
// has known trap?
if (isplayer(lf)) {
// has known trap?
if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) {
if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_AVERAGE) {
char ch;
@ -1480,6 +1480,24 @@ int opendoor(lifeform_t *lf, object_t *o) {
}
}
}
// hear water behind it?
if (getskill(lf, SK_LISTEN)) {
int dir;
cell_t *pastdoorcell;
dir = getdirtowards(doorcell, lf->cell, NULL, B_FALSE, DT_ORTH);
pastdoorcell = getcellindir(doorcell, dir);
if (pastdoorcell && getcellwaterdepth(pastdoorcell, NULL)) {
if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_AVERAGE) {
char ch;
sprintf(buf,"Your hear running water behind %s. Really open it?", obname);
ch = askchar(buf,"yn","n", B_TRUE);
if (ch != 'y') {
msg("Cancelled.");
return B_TRUE;
}
}
}
}
}
taketime(lf, getactspeed(lf));

14
nexus.c
View File

@ -1183,15 +1183,14 @@ int rollhitdice(lifeform_t *lf) {
}
if (db) dblog("rollhitdice() for %s - rolling %dd4 + %d",lf->race->name,ndice,plus);
mod = getstatmod(lf, A_CON);
if (mod > 0) mod *= 2;
mod = 100 + getstatmod(lf, A_CON);
if (db) dblog("rollhitdice() - mod is +%0.0f%%",mod);
if (ndice == 0) {
int thisroll;
// just the bonus
thisroll = plus;
thisroll = thisroll + (int)((float)thisroll * (mod/100));
if (thisroll < 1) thisroll = 1;
roll += thisroll;
@ -1206,8 +1205,8 @@ int rollhitdice(lifeform_t *lf) {
}
}
if (db) dblog("TOTAL: %d",roll);
roll = roll + (int)((float)roll * (mod/100));
// must be at least 1!!
// modify for fitness/con
roll = pctof(mod, roll);
limit(&roll, 1, NA);
if (db) dblog(" -> modified to: %d",roll);
return roll;
@ -1227,12 +1226,11 @@ int rollmpdice(lifeform_t *lf) {
} else {
return 0;
}
mod = getstatmod(lf, A_IQ);
if (mod > 0) mod *= 2;
mod = 100 + getstatmod(lf, A_IQ);
roll = rolldie(ndice, 4) + plus;
roll = roll + (int)((float)roll * (mod/100));
roll = pctof(mod, roll);
return roll;
}

532
objects.c

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,7 @@ objecttype_t *findot(enum OBTYPE id);
objecttype_t *findotn(char *name); // find objecttype by name
void fragments(cell_t *centre, char *what, int speed, int howfar);
void genhiddennames(void);
object_t *getbestcontainer(obpile_t *op);
int getchargeinfo(object_t *o, int *cur, int *max);
int getcharges(object_t *o);
int geteffecttime(int min, int max, enum BLESSTYPE isblessed);

432
spell.c
View File

@ -19,6 +19,7 @@
extern lifeform_t *player;
extern skill_t *firstskill, *lastskill;
extern race_t *firstrace, *lastrace;
extern knowledge_t *knowledge;
extern int needredraw;
@ -1814,15 +1815,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int d;
float totweight = 0;
int powerinc = 0;
object_t *o;
for (d = DC_N; d <= DC_NW; d++) {
c = getcellindir(caster->cell, d);
if (c) {
object_t *o;
for (o = c->obpile->first ; o ; o = o->next){
if (o->type->obclass->id == OC_FLORA) totweight += getobweight(o);
}
}
}
for (o = caster->cell->obpile->first ; o ; o = o->next){
if (o->type->obclass->id == OC_FLORA) totweight += getobweight(o);
}
for (o = caster->pack->first ; o ; o = o->next){
if (o->type->obclass->id == OC_FLORA) totweight += getobweight(o);
}
powerinc = totweight / 50;
if (powerinc > 0) {
power += powerinc;
@ -2150,7 +2157,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
teleportto(caster, targcell, B_TRUE);
}
} else if (spellid == OT_S_BODYCONTROL) {
} else if (spellid == OT_S_LOWERMETAB) {
flag_t *f;
// ie. 2 - 4
f = addtempflag(caster->flags, F_SLOWMETAB, 2+(power/4), NA, NA, NULL, FROMSPELL);
@ -2213,6 +2220,62 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (cansee(player, caster)) {
needredraw = B_TRUE;
}
} else if (spellid == OT_S_CONFISCATE) {
object_t *o;
char ch = 'a';
char obname[BUFLEN];
// ask for a target cell
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_FALSE;
}
// take an object
initprompt(&prompt, "Confiscate which object?");
addchoice(&prompt, '-', "(Cancel)", NULL, NULL);
for (o = target->pack->first ; o ; o = o->next) {
getobname(o, obname, o->amt);
addchoice(&prompt, ch, obname, NULL, o);
if (ch == 'z') {
ch = 'A';
} else {
ch++;
}
}
if (isplayer(caster)) {
// select one
getchoice(&prompt);
o = (object_t *)prompt.result;
} else {
// random one
o = (object_t *) prompt.choice[rnd(0,prompt.nchoices-1)].data;
}
if (o) {
if (isplayer(target)) {
getobname(o, obname, o->amt);
msg("^%cYour %s vanish%s!", getlfcol(target, CC_VBAD), noprefix(obname), (o->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (isplayer(caster)) {
char targname[BUFLEN];
getlfname(target, targname);
getobname(o, obname, o->amt);
msg("%s%s %s appear%s in your pack!", targname, getpossessive(targname),
noprefix(obname), (o->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) {
char targname[BUFLEN];
getlfname(target, targname);
getobname(o, obname, o->amt);
msg("^%c%s%s %s vanish%s!", getlfcol(target, CC_VBAD), targname, getpossessive(targname), noprefix(obname),
(o->amt == 1) ? "es" : "");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
moveob(o, caster->pack, ALL);
} else {
fizzle(caster);
}
} else if (spellid == OT_S_CALLLIGHTNING) {
int failed = B_FALSE;
// ask for a target cell
@ -3311,30 +3374,32 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int range;
int x,y;
// announce
if (caster) {
if (!targcell) targcell = caster->cell;
if (isplayer(caster) || cansee(player, caster)) {
msg("%s emit%s a radial blast of energy!",castername,isplayer(caster) ? "" : "s");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
}
range = 2 + (power / 4);
animradial(caster->cell, range, '}', C_CYAN);
animradial(targcell, range, '}', C_CYAN);
for (y = caster->cell->y - range ; y <= caster->cell->y + range; y++) {
for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) {
targcell = getcellat(caster->cell->map, x,y);
if (targcell && (getcelldist(caster->cell, targcell) <= range)) {
if (targcell->lf && (targcell->lf != caster) && haslof(caster->cell, targcell, B_FALSE, NULL)) {
for (y = targcell->y - range ; y <= targcell->y + range; y++) {
for (x = targcell->x - range ; x <= targcell->x + range; x++) {
cell_t *c;
c = getcellat(targcell->map, x,y);
if (c && (getcelldist(targcell, c) <= range)) {
if (c->lf && (c->lf != caster) && haslof(targcell, c, B_FALSE, NULL)) {
// automatic hit
if (isplayer(targcell->lf)) {
if (isplayer(c->lf)) {
msg("A blast of energy hits you!");
}
/*
if (haslos(caster, targcell)) {
} else if (cansee(player, c->lf)) {
char lfname[BUFLEN];
getlfname(c->lf, lfname);
msg("A blast of energy hits %s.",lfname);
}
*/
losehp(targcell->lf, rnd(2,6), DT_MAGIC, caster, "an energy blast");
losehp(c->lf, rnd(2,6), DT_MAGIC, caster, "an energy blast");
}
}
}
@ -4154,6 +4219,29 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("%s glows for a moment.",buf);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_HUNGER) {
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_FALSE;
}
if (isplayer(target)) {
// make more hungry
modhunger(target, HUNGERCONST);
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 (seenbyplayer) *seenbyplayer = B_TRUE;
}
}
} else if (spellid == OT_S_ICEEDGE) {
object_t *wep;
enum DAMTYPE dt;
@ -4533,6 +4621,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// 5 is the same as AT_VHIGH strength
// 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__");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else {
if (cansee(player, caster)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// for now, just disappear.
unsummon(caster, B_TRUE);
}
} else if (spellid == OT_S_PARALYZE) {
int howlong;
int saved = B_FALSE;
@ -5442,15 +5541,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int i;
char targname[BUFLEN];
if (isoutdoors(caster->cell->map)) {
power += 5;
limit(&power, NA, 10);
}
if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_OBJECT, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (isoutdoors(targcell->map)) {
power += 5;
limit(&power, NA, 10);
}
if (target) {
getlfname(target, targname);
// objects held by target
@ -6000,7 +6100,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_FALSE;
}
howlong = getspellduration(5,10,blessed) + (power/2);
fallasleep(target, F_ASLEEP);
fallasleep(target, howlong);
if (isplayer(target) || haslos(player, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
@ -6121,6 +6221,53 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
}
} else if (spellid == OT_S_SPEAKDEAD) {
object_t *corpse = NULL;
if (!isplayer(caster)) {
return B_FALSE;
}
corpse = hasobwithflag(caster->cell->obpile, F_CORPSEOF);
if (corpse) {
char buf[BUFLEN],corpsename[BUFLEN];
char ch;
getobname(corpse, corpsename, 1);
sprintf(buf, "What will you ask %s?", corpsename);
initprompt(&prompt, buf);
addchoice(&prompt, 'a', "How did you die?", NULL, NULL);
addchoice(&prompt, '-', "(nothing)", NULL, NULL);
ch = getchoice(&prompt);
if (ch == 'a') {
flag_t *f;
char *p;
sprintf(buf, "%s whispers:", corpsename);
msg(buf);
f = hasflag(corpse->flags, F_CORPSEOF);
if (f && strlen(f->text)) {
char killer[BUFLEN];
char weapon[BUFLEN];
p = readuntil(killer, f->text, '^');
if (strstr(p, "weilding")) {
p = readuntil(weapon, p, '^');
} else {
strcpy(weapon, "");
}
sprintf(buf, "\"I was killed by %s", killer);
if (strlen(weapon)) {
strcat(buf, ", ");
strcat(buf, weapon);
}
strcat(buf, ".\"");
msg(buf);
} else {
msg("\"I do not know what killed me.\"");
}
}
}
} else if (spellid == OT_S_STENCH) {
int howlong;
if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, spellid, power, frompot)) return B_TRUE;
@ -6271,6 +6418,36 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else {
fizzle(caster);
}
} else if (spellid == OT_S_STUN) {
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf;
if (lfhasflag(target, F_ASLEEP) || !ischarmable(target)) {
fizzle(caster);
return B_TRUE;
}
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (isplayer(target)) {
msg("You shrug off a mental attack.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, target->cell)) {
getlfname(target, buf);
msg("%s shrugs off %s mental attack.", buf, isplayer(caster) ? "your" : "a");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
} else {
if (isplayer(target)) {
msg("You are stunned!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, target->cell)) {
getlfname(target, buf);
msg("%s is stunned!", buf);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
taketime(target, getactspeed(target)*2);
}
} else if (spellid == OT_S_SUCK) {
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
@ -7028,6 +7205,203 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = addtempflag(caster->flags, F_WINDSHIELD, power, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
} else if (spellid == OT_S_WISHLIMITED) {
object_t *o;
char obname[BUFLEN];
char ch;
if (!target) target = caster;
initprompt(&prompt, "For what do you wish?");
addchoice(&prompt, 'a', "Wealth", NULL, NULL);
addchoice(&prompt, 'b', "Power", NULL, NULL);
addchoice(&prompt, 'c', "Protection", NULL, NULL);
addchoice(&prompt, 'd', "Fame", NULL, NULL);
addchoice(&prompt, 'e', "Knowledge", NULL, NULL);
addchoice(&prompt, 'f', "Magic", NULL, NULL);
if (isplayer(target)) {
ch = getchoice(&prompt);
} else {
ch = 'e';
// ie. don't select 'knowledge'
while (ch == 'e') {
ch = rnd('a', 'f');
}
}
if (ch == 'a') { // wealth (gold, bad: goldtouch)
sprintf(buf, "1000-2000 gold coins");
} else if (ch == 'b') { // power (weapons, bad: battery)
skill_t *sk,*poss[MAXSKILLS];
int nposs = 0;
// get a list of all valid weapon skills
for (sk = firstskill ; sk ; sk = sk->next) {
if (isweaponskill(sk->id) && getskill(target, sk->id)) {
poss[nposs++] = sk;
}
}
if (nposs) {
int nweps = 0;
objecttype_t *ot;
// pick a random one
sk = poss[rnd(0,nposs-1)];
// find all associated weapons
for (ot = objecttype ; ot ; ot = ot->next) {
if (hasflagval(ot->flags, F_USESSKILL, sk->id, NA, NA, NULL)) {
nweps++;
}
}
if (nweps) {
int sel,n = 0;
sel = rnd(0,nweps-1);
for (ot = objecttype ; ot ; ot = ot->next) {
if (hasflagval(ot->flags, F_USESSKILL, sk->id, NA, NA, NULL)) {
if (n == sel) break;
n++;
}
}
sprintf(buf, "excellent branded %s", ot->name);
} else {
sprintf(buf, "stick");
}
} else {
sprintf(buf, "stick");
}
} else if (ch == 'c') { // protection. bad: turn to stone
enum BODYPART bp,poss[MAXBODYPARTS];
int nposs = 0;
// get a list of all valid body parts
for (bp = 0; bp <= MAXBODYPARTS; bp++) {
if (!lfhasflagval(target, F_NOBODYPART, bp, NA, NA, NULL)) {
poss[nposs++] = bp;
}
}
if (nposs) {
int narms = 0;
objecttype_t *ot;
// pick a random body part
bp = poss[rnd(0,nposs-1)];
// find all associated armour
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == OC_ARMOUR) && hasflagval(ot->flags, F_GOESON, bp, NA, NA, NULL)) {
narms++;
}
}
if (narms) {
int sel,n = 0;
sel = rnd(0,narms-1);
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == OC_ARMOUR) && hasflagval(ot->flags, F_GOESON, bp, NA, NA, NULL)) {
if (n == sel) break;
n++;
}
}
sprintf(buf, "excellent branded %s", ot->name);
} else {
sprintf(buf, "sun hat");
}
} else {
sprintf(buf, "sun hat");
}
} else if (ch == 'd') { // fame (allies bad: useless allies)
lifeform_t *lf;
cell_t *c;
job_t *j;
char *p,lfname[BUFLEN];
// summon a human
c = getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND);
j = getrandomjob(B_TRUE);
lf = addlf(c, R_HUMAN, target->level);
givejob(lf, j->id);
getlfnamea(lf, lfname);
if (cansee(player, lf)) {
msg("%s appears!", lfname);
}
petify(lf, target);
if (isplayer(target)) {
p = assignnpcname(lf);
sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p);
}
strcpy(buf, "");
} else if (ch == 'e') { // knowledge (makeknown everything you have plus 5-10 others. bad: insanity)
// only possible for the player!
strcpy(buf, "");
if (isplayer(target)) {
knowledge_t *k;
msg("^GKnowledge floods into your mind!");
for (o = target->pack->first ; o ; o = o->next) {
if (!isidentified(o)) {
identify(o);
getobname(o, obname, o->amt);
msgnocap("%c - %s.", o->letter, obname);
}
}
// now identify everything that you have tried,
// and 10% chance of identifying others
for (k = knowledge; k ; k = k->next) {
if ((k->known == B_TRIED) || pctchance(10)) {
makeknown(k->id);
}
}
}
} else if (ch == 'f') { // magic (spellbooks)
objecttype_t *ot,*poss[MAXCANDIDATES];
int nposs = 0;
// find all castable spells (spellpower > 0)
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == OC_SPELL) && getspellpower(target, ot->id)) {
poss[nposs++] = ot;
}
}
if (!nposs) {
// give knowledge of a random spell school plus sorcery
enum SPELLSCHOOL school;
skill_t *poss2[MAXSKILLS],*sk;
int nposs2 = 0;
giveskill(target, SK_SPELLCASTING);
for (school = SS_AIR; school < SS_LAST; school++) {
sk = findskill(getschoolskill(school));
poss2[nposs2++] = sk;
}
sk = poss2[rnd(0,nposs2-1)];
giveskill(target, sk->id);
// ... then try to find castable spells again
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == OC_SPELL) && getspellpower(target, ot->id)) {
poss[nposs++] = ot;
}
}
}
if (nposs) {
// pick a random spell from this list
ot = poss[rnd(0,nposs-1)];
sprintf(buf, "spellbook of %s",ot->name);
} else {
strcpy(buf, "");
}
}
if (strlen(buf)) {
// give the object
o = addob(target->pack, buf);
getobname(o, obname, o->amt);
msgnocap("%c - %s.", o->letter, obname);
}
// 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;
}
}
if (isplayer(target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if ((spellid == OT_S_WISH) || (spellid == OT_S_GIFT)) {
object_t *o;
if (isplayer(caster)) {
@ -7091,6 +7465,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// couldn't make it appear - ob doesn't exist
msg("The air in front of %s seems to ripple for a while.", lfname);
}
// 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;
}
}
} else {
// monsters can't wish
}
@ -7127,7 +7511,9 @@ void fizzle(lifeform_t *caster) {
}
}
enum OBTYPE getrandomspell(void) {
// maxlev <= 0 means 'any lev'
enum OBTYPE getrandomspell(int maxlev) {
int wantlev;
objecttype_t *ot,*poss[MAXCANDIDATES];
int nposs = 0;
@ -7136,6 +7522,7 @@ enum OBTYPE getrandomspell(void) {
while (rnd(1,2) == 1) {
wantlev++;
}
limit(&wantlev, 1, maxlev);
// get list of all spells of this level
for (ot = objecttype ; ot ; ot = ot->next) {
@ -7343,6 +7730,7 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) {
if (db) {
dblog("-->power = %d (from canwill)", power);
}
// note that this power _can_ override max spell power
return power;
}
}
@ -7740,7 +8128,7 @@ void pullobto(object_t *o, lifeform_t *lf) {
if (isplayer(lf) || haslos(player, lf->cell)) {
msg("%s %s %s.", lfname, isplayer(lf) ? "catch" : "catches", obname);
}
pickup(lf, o, o->amt, B_FALSE);
pickup(lf, o, o->amt, B_FALSE, B_FALSE);
}
}

View File

@ -8,7 +8,7 @@ objecttype_t *findspelln(char *buf);
void fizzle(lifeform_t *caster);
//int getiqreq(enum OBTYPE oid);
int getmpcost(lifeform_t *lf, enum OBTYPE oid);
enum OBTYPE getrandomspell(void);
enum OBTYPE getrandomspell(int maxlev);
enum SKILL getschoolskill(enum SPELLSCHOOL ss);
char *getspellcosttext(lifeform_t *lf, enum OBTYPE spellid, int power, char *buf);
int getspellduration(int min,int max,int blessed);

View File

@ -15,6 +15,7 @@
#:cell:rock wall
|:ob:locked iron gate
,:ob:1-4 bones:50
,:mon:prisoner:50
+:ob:wooden door
/:ob:wooden table
-:ob:wooden footstool