nexus/god.c

613 lines
16 KiB
C

#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 / 50;
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(1,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); // ie. don't set origrace!
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 a little.
//setpiety(rid, 101);
modpiety(rid, -50);
} // 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);
}