- [+] bug: getobvlue price keeps going up

- [+] make food poisoning last longer!
- [+] bug: pet starting in water
- [+] ability to pay at shops using gems?  but no change.
    - [+] implement
    - [+] require speech skill at a certain level (novice)
- [+] reveal attack location for unseen attacks
- [+] bug: poisonbolt spell shouldn't cause fire damage to objects!
- [+] return to your original form after dying when polymorphed, but
      just retain SOME hp
- [+] new spell: shapeshift
    - [+] like polymorph but only affects yourself and always controlled
    - [+] you have to pick something you can see
    - [+] spell power determiens hitdice you can copy
- [+] purify food now works on all your objects, not just one
- [+] Nature god(farming, creation)
    - [+] Ekrub  
        - [+] doesn't like wyrms because they destroy things?
    - [+] objects
        - [+] has a pitchfork vs dragons
        - [+] longbow of xxx
        - [+] sun hat
        - [+] overalls
        - [+] gloves
    - [+] effects:
        - [+] canwill all nature spells
    - [+] likes
        - [+] killing animals (but only while hungry)
        - [+] killing dragons
        - [+] casting nature spells
        - [+] creating objects or lfs (wish, monsters, food)
    - [+] dislikes:
        - [+] destroying objects
            - [+] attackob()
            - [+] throwing a flask which shatters
            - [+] crush objects underfoot
            - [+] via non-nature spells...?
        - [+] poison
        - [+] attacking plants
        - [+] casting poison spells (same with other antipoison gods!)
    - [+] sacrifice:
        - [+] animal corpses
        - [+] dragon corpses
    - [+] pray:
        - [+] battle:
            - [+] will come to your aid against wyrms 
            - [+] OTHERWISE:
            - [+] entangle enemies
            - [+] lightning
            - [+] summon plants to help you
        - [+] nonbattle:
            - [+] purify food on player
            - [+] THEN one of the following:
            - [+] cure poison
            - [+] fix hunger or give food
            - [+] heal
            - [+] give ammo (if ranged weapon equipped and out of ammo)
                - [+] give it.
                - [+] make it "of seeking" (ie. always hits)
            - [+] mend armour
            - [+] bless armour 
    - [+] gifts
        - [+] ability: calm animals, power 10
        - [+] can shapeshift into a bear
        - [+] resist poison
        - [+] resist cold
        - [+] ranged weapon
        - [+] magic ammo for ranged weapons
    - [+] angry (minor)
        - [+] no nature spells work while god is angry ?
        - [+] taint your food and any food you touch
        - [+] summons entangling vines around you 
    - [+] angry (major)
        - [+] one of:
            - [+] cloudkill
            - [+] summon storm
            - [+] surround you with sawgrass
This commit is contained in:
Rob Pearce 2012-02-01 01:31:36 +00:00
parent 81d65d35d9
commit 5506fdcc86
16 changed files with 944 additions and 283 deletions

6
ai.c
View File

@ -799,6 +799,12 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) {
hateposs[nhateposs++] = who; hateposs[nhateposs++] = who;
} }
break; break;
} else if (lfhasflagval(lf, F_HATESRACECLASS, who->race->raceclass->id, NA, NA, NULL) ) {
if ((nhateposs < MAXCANDIDATES) && !areallies(lf, who)) {
if (db) dblog(".oO { found a hated raceclass target - lfid %d (%s) ! }",who->id, who->race->name);
hateposs[nhateposs++] = who;
}
break;
} else if ( ((f = lfhasflag(lf, F_TERRITORIAL)) != NULL) && } else if ( ((f = lfhasflag(lf, F_TERRITORIAL)) != NULL) &&
(getcelldist(who->cell, lf->cell) <= f->val[0]) ) { (getcelldist(who->cell, lf->cell) <= f->val[0]) ) {
if ((nhateposs < MAXCANDIDATES) && !areallies(lf, who)) { if ((nhateposs < MAXCANDIDATES) && !areallies(lf, who)) {

102
attack.c
View File

@ -19,7 +19,8 @@
extern lifeform_t *player; extern lifeform_t *player;
extern lifeform_t *godlf[]; extern lifeform_t *godlf[];
extern int ngodlfs;
extern int needredraw;
extern enum ERROR reason; extern enum ERROR reason;
@ -478,59 +479,53 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
} }
// god effects... // god effects...
if ((attacktype == AT_LF) && isplayer(lf) && attacktarget) { if (isplayer(lf) && attacktarget) {
if (!isgod(attacktarget)) { if (attacktype == AT_LF) {
if (attackedfriend) { if (!isgod(attacktarget)) {
angergodmaybe(R_GODMERCY, 100, GA_ATTACKALLY); if (attackedfriend) {
angergodmaybe(R_GODPURITY, 100, GA_ATTACKALLY); angergodmaybe(R_GODMERCY, 100, GA_ATTACKALLY);
switch (getalignment(attacktarget)) { angergodmaybe(R_GODPURITY, 100, GA_ATTACKALLY);
case AL_EVIL: switch (getalignment(attacktarget)) {
angergodmaybe(R_GODDEATH, 20, GA_ATTACKALLY); // even more case AL_EVIL:
break; angergodmaybe(R_GODDEATH, 20, GA_ATTACKALLY); // even more
case AL_GOOD: break;
angergodmaybe(R_GODPURITY, 20, GA_ATTACKALLY); // even more case AL_GOOD:
break; angergodmaybe(R_GODPURITY, 20, GA_ATTACKALLY); // even more
default: break;
break; default:
} break;
} else if (attackedpeaceful) { }
angergodmaybe(R_GODMERCY, 50, GA_ASSAULT); } else if (attackedpeaceful) {
angergodmaybe(R_GODPURITY, 50, GA_ASSAULT); angergodmaybe(R_GODMERCY, 50, GA_ASSAULT);
switch (getalignment(attacktarget)) { angergodmaybe(R_GODPURITY, 50, GA_ASSAULT);
case AL_EVIL: switch (getalignment(attacktarget)) {
angergodmaybe(R_GODDEATH, 20, GA_ASSAULT); // even more case AL_EVIL:
break; angergodmaybe(R_GODDEATH, 20, GA_ASSAULT); // even more
case AL_GOOD: break;
angergodmaybe(R_GODPURITY, 20, GA_ASSAULT); // even more case AL_GOOD:
break; angergodmaybe(R_GODPURITY, 20, GA_ASSAULT); // even more
default: break;
break; default:
} break;
} else if (attackedhelpless) { }
angergodmaybe(R_GODMERCY, 50, GA_ATTACKHELPLESS); } else if (attackedhelpless) {
angergodmaybe(R_GODPURITY, 50, GA_ATTACKHELPLESS); angergodmaybe(R_GODMERCY, 50, GA_ATTACKHELPLESS);
if (getalignment(attacktarget) != AL_EVIL) { angergodmaybe(R_GODPURITY, 50, GA_ATTACKHELPLESS);
pleasegodmaybe(R_GODTHIEVES, 5); if (getalignment(attacktarget) != AL_EVIL) {
pleasegodmaybe(R_GODDEATH, 10); pleasegodmaybe(R_GODTHIEVES, 5);
} pleasegodmaybe(R_GODDEATH, 10);
}
if (lfhasflag(lf, F_USEDPOISON)) {
int i;
flag_t *f;
killflagsofid(lf->flags, F_USEDPOISON);
for (i = 0; i < ngodlfs; i++) {
if (godlf[i]) {
f = lfhasflag(godlf[i], F_GODPOISON);
if (f) {
if (f->val[0]) {
pleasegodmaybe(godlf[i]->race->id, f->val[1]);
} else {
angergodmaybe(godlf[i]->race->id, f->val[1], GA_POISON);
}
}
} }
} }
if ( ((lifeform_t *)attacktarget)->race->raceclass->id == RC_PLANT) {
angergodmaybe(R_GODNATURE, 25, GA_ATTACKOBJECT);
}
if (lfhasflag(lf, F_USEDPOISON)) {
killflagsofid(lf->flags, F_USEDPOISON);
if (isplayer(lf)) god_usepoison_response();
}
} }
} else if (attacktype == AT_OB) {
angergodmaybe(R_GODNATURE, 10, GA_ATTACKOBJECT);
} }
} }
@ -750,6 +745,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (hit) { if (hit) {
if (aidb) dblog(".oO { i hit! }"); if (aidb) dblog(".oO { i hit! }");
if (!cansee(victim, lf)) {
addflag(lf->flags, F_UNSEENATTACKER, victim->id, NA, NA, NULL);
if (isplayer(victim) && !isplayer(lf)) needredraw = B_TRUE;
}
// special case // special case
if (isplayer(lf) && (victim->race->id == R_GLOWBUG)) { if (isplayer(lf) && (victim->race->id == R_GLOWBUG)) {
if ((wep->type->id == OT_EMPTYFLASK) || (wep->type->id == OT_EMPTYVIAL)) { if ((wep->type->id == OT_EMPTYFLASK) || (wep->type->id == OT_EMPTYVIAL)) {

94
data.c
View File

@ -988,9 +988,14 @@ void initobjects(void) {
addflag_real(lastobmod->flags, F_RUSTED, R_TRUSTY, NA, NA, NULL, PERMENANT, B_KNOWN, -1); addflag_real(lastobmod->flags, F_RUSTED, R_TRUSTY, NA, NA, NULL, PERMENANT, B_KNOWN, -1);
// brands modifiers - flags should be UNKNOWN! // brands modifiers - flags should be UNKNOWN!
// also don't double up with names of scrolls etc. // also don't double up with names of scrolls,books etc.
// ie. spellbook of flight, boots of flight. // ie. spellbook of flight, boots of flight.
// missile weapons
addbrand(BR_HOMING, "of seeking", BP_NONE, B_UNCURSED, 0);
addflag_real(lastbrand->flags, F_HOMING, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addflag_real(lastbrand->flags, F_ONLYFOROBCLASS, OC_MISSILE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
// weapons // weapons
addbrand(BR_BALANCE, "of balance", BP_WEAPON, B_UNCURSED, 0); addbrand(BR_BALANCE, "of balance", BP_WEAPON, B_UNCURSED, 0);
addflag_real(lastbrand->flags, F_BALANCE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); addflag_real(lastbrand->flags, F_BALANCE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
@ -1088,6 +1093,7 @@ void initobjects(void) {
addbrand(BR_HEALTH, "of health", BP_BODY, B_UNCURSED, 0); addbrand(BR_HEALTH, "of health", BP_BODY, B_UNCURSED, 0);
addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ATTRMOD, A_CON, 15, NULL, PERMENANT, B_UNKNOWN, -1); addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ATTRMOD, A_CON, 15, NULL, PERMENANT, B_UNKNOWN, -1);
// materials // materials
addmaterial(MT_NOTHING, "nothing", 0); addmaterial(MT_NOTHING, "nothing", 0);
addmaterial(MT_MAGIC, "magical energy", 0); addmaterial(MT_MAGIC, "magical energy", 0);
@ -3611,6 +3617,12 @@ void initobjects(void) {
addot(OT_S_EXCAVATE, "excavate", "Creates a large open area surrounding the caster. No effect on living creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_EXCAVATE, "excavate", "Creates a large open area surrounding the caster. No effect on living creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addot(OT_S_SHAPESHIFT, "shapeshift", "Causes the caster to take on the form of any creature within sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how powerful a creature you can become.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, 10, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
// l5 // l5
addot(OT_S_GASEOUSFORM, "gaseous form", "Changes the caster into a cloud of gas.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_GASEOUSFORM, "gaseous form", "Changes the caster into a cloud of gas.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
@ -3633,8 +3645,7 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addot(OT_S_POLYMORPH, "polymorph", "Transmutes the target into a new living race.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_POLYMORPH, "polymorph", "Transmutes the target into a new living race.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power V, you can polymorph other creatures."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power V, you can choose what kind of creature to polymorph into.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VIII, you can choose what kind of creature to polymorph into.");
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
@ -5275,7 +5286,7 @@ void initobjects(void) {
addot(OT_POISONPUFF, "puff of poison gas", "A small puff of poisonous gas.", MT_GAS, 0, OC_EFFECT, SZ_MEDIUM); addot(OT_POISONPUFF, "puff of poison gas", "A small puff of poisonous gas.", MT_GAS, 0, OC_EFFECT, SZ_MEDIUM);
addflag(lastot->flags, F_GLYPH, C_GREEN, UNI_SHADELIGHT, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREEN, UNI_SHADELIGHT, NA, NULL);
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
@ -6215,8 +6226,8 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 15, NA, NULL); addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 15, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 0.25, OC_MISSILE, SZ_SMALL); addot(OT_BOLT, "bolt", "A sharp metal spike, meant for firing from a crossbow.", MT_METAL, 0.25, OC_MISSILE, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
@ -6227,7 +6238,6 @@ void initobjects(void) {
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 20, NA, NULL); addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 20, NA, NULL);
addot(OT_BULLET, "bullet", "A regular gun bullet.", MT_METAL, 0.1, OC_MISSILE, SZ_MINI); addot(OT_BULLET, "bullet", "A regular gun bullet.", MT_METAL, 0.1, OC_MISSILE, SZ_MINI);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, "");
@ -6581,6 +6591,16 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_AGI, 65, 80, "10"); addflag(lastot->flags, F_ATTREQ, A_AGI, 65, 80, "10");
addflag(lastot->flags, F_CRITCHANCE, 1, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 1, NA, NA, NULL);
addot(OT_PITCHFORK, "pitchfork", "A multi-pronged agricultural tool designed to lift loose material. Works as a makeshift weapon.", MT_METAL, 5, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, RR_FREQUENT, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 85, RR_FREQUENT, NULL);
addflag(lastot->flags, F_DAM, DT_SLASH, 3, NA, NULL);
addflag(lastot->flags, F_ALTDAM, DT_BASH, 3, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL);
addflag(lastot->flags, F_ATTACKVERB, NA, 2, NA, "scratch");
addflag(lastot->flags, F_ATTACKVERB, 3, 6, NA, "scrape");
addflag(lastot->flags, F_ATTACKVERB, 7, NA, NA, "rake");
addot(OT_RANSEUR, "ranseur", "A long spear and cross hilt, resembling a pole-mounted sai. Good for disarming.", MT_METAL, 12, OC_WEAPON, SZ_HUMAN); addot(OT_RANSEUR, "ranseur", "A long spear and cross hilt, resembling a pole-mounted sai. Good for disarming.", MT_METAL, 12, OC_WEAPON, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL);
addflag(lastot->flags, F_RARITY, H_CAVE, 67, NA, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 67, NA, NULL);
@ -7703,6 +7723,59 @@ void initrace(void) {
addflag(lastrace->flags, F_SACRIFICEOBWITHFLAG, F_BATTLESPOILS, NA, 3, "OB explode#S into a shower of blood!"); addflag(lastrace->flags, F_SACRIFICEOBWITHFLAG, F_BATTLESPOILS, NA, 3, "OB explode#S into a shower of blood!");
addflag(lastrace->flags, F_SACRIFICEOB, OT_SPELLBOOK, NA, 10, "OB explode#S into a shower of blood!"); addflag(lastrace->flags, F_SACRIFICEOB, OT_SPELLBOOK, NA, 10, "OB explode#S into a shower of blood!");
addrace(R_GODNATURE, "Ekrub", 200, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Ekrub is god of nature and creation. She appears as a female figure dressed in farming clothes. Ekrub has a burning hatred of all dragonkind, who she views as abhorrent due to their destructive nature.");
setbodytype(lastrace, BT_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL);
addflag(lastrace->flags, F_FLEEONHPPCT, 95, NA, NA, "");
addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "80");
addflag(lastrace->flags, F_STARTATT, A_AGI, NA, NA, "80");
addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "85");
addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "65");
addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "90");
addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "60");
addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "50d4");
addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 6, NA, NULL);
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed +5 pitchfork of dragonslaying");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed +5 longbow");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "100 arrows of seeking");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed +2 overalls");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed sun hat");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed leather gloves");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed rubber boots");
addflag(lastrace->flags, F_STARTSKILL, SK_POLEARMS, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_EXPERT, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_COOKING, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_RANGED, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_SWIMMING, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_LORE_NATURE, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_ADEPT, NA, NULL); // ekrub hates dragons
// god abilities
addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Nature");
// may cast all nature spells
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == OC_SPELL) && (getspellschool(ot->id) == SS_NATURE)) {
addflag(lastrace->flags, F_CANWILL, ot->id, NA, NA, "pw:10;");
}
}
addflag(lastrace->flags, F_GODPOISON, B_FALSE, 25, NA, NULL);
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "killing animals when hungry");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "killing dragons");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "cooking");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "creating objects");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "casting nature spells");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "damaging or destroying objects");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of poison");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "attacking plants");
addflag(lastrace->flags, F_HATESRACECLASS, RC_DRAGON, NA, NA, NULL);
// sacrifices
addflag(lastrace->flags, F_SACRIFICEOB, OT_CORPSE, RC_ANIMAL, 10, "Writhing vines sprout up and drag OB underground.");
addflag(lastrace->flags, F_SACRIFICEOB, OT_CORPSE, RC_DRAGON, 25, "Writhing vines sprout up and tear OB to pieces!");
addrace(R_GODTHIEVES, "Felix", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Felix is the god of Thieves, Greed and Trickery. He generally appears as an overweight glutton carrying his contraband loot around in huge sacks. Despite this, he is amazingly agile and is said to be able to steal one's soul right out of their body."); addrace(R_GODTHIEVES, "Felix", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Felix is the god of Thieves, Greed and Trickery. He generally appears as an overweight glutton carrying his contraband loot around in huge sacks. Despite this, he is amazingly agile and is said to be able to steal one's soul right out of their body.");
@ -7889,7 +7962,7 @@ void initrace(void) {
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "allowing fleeing creatures to escape"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "allowing fleeing creatures to escape");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "acts of charity"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "acts of charity");
addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "natural healing"); 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, "attacking the innocent or helpless");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "sneak attacks"); 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 use of poison");
addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the destruction of healing potions"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the destruction of healing potions");
@ -11642,7 +11715,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANWILL, OT_S_CHARM, 3, 3, "pw:6;"); addflag(lastrace->flags, F_CANWILL, OT_S_CHARM, 3, 3, "pw:6;");
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:3;"); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:3;");
addflag(lastrace->flags, F_CANWILL, OT_S_STUN, 5, 5, "pw:1;"); addflag(lastrace->flags, F_CANWILL, OT_S_STUN, 5, 5, "pw:1;");
addflag(lastrace->flags, F_CANWILL, OT_S_POLYMORPH, 3, 3, "pw:1;race:vampire bat;"); addflag(lastrace->flags, F_CANWILL, OT_S_SHAPESHIFT, 3, 3, "pw:1;race:vampire bat;");
addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL);
addflag(lastrace->flags, F_DETECTOBS, 10, OT_COFFIN, NA, NULL); addflag(lastrace->flags, F_DETECTOBS, 10, OT_COFFIN, NA, NULL);
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pile of ash"); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pile of ash");
@ -11966,8 +12039,9 @@ void initskills(void) {
addskilldesc(SK_SHIELDS, PR_MASTER, "^gShield accuracy penalties are reduced by 6.^n", B_FALSE); addskilldesc(SK_SHIELDS, PR_MASTER, "^gShield accuracy penalties are reduced by 6.^n", B_FALSE);
addskill(SK_SPEECH, "Negotiation", "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_INEPT, "- Each skill level reduces shop prices by 5%.", B_TRUE); addskilldesc(SK_SPEECH, PR_INEPT, "- Each skill level reduces shop prices by 5%.", B_TRUE);
addskilldesc(SK_SPEECH, PR_NOVICE, "^gYou can now question people about items on the current level.", B_TRUE); addskilldesc(SK_SPEECH, PR_NOVICE, "^gYou can now question people about nearby traps or monsters.", B_TRUE);
addskilldesc(SK_SPEECH, PR_BEGINNER, "^gYou can now question people about nearby traps or monsters.", B_TRUE); addskilldesc(SK_SPEECH, PR_NOVICE, "^gYou can now offer gems as payment in shops.", B_TRUE);
addskilldesc(SK_SPEECH, PR_BEGINNER, "^gYou can now question people about items on the current level.", B_TRUE);
addskilldesc(SK_SPEECH, PR_ADEPT, "^gYou can now trade knowledge and spells with other people.", B_TRUE); addskilldesc(SK_SPEECH, PR_ADEPT, "^gYou can now trade knowledge and spells with other people.", B_TRUE);
addskilldesc(SK_SPEECH, PR_SKILLED, "^gYou can now persuade people to join to as followers.", B_TRUE); addskilldesc(SK_SPEECH, PR_SKILLED, "^gYou can now persuade people to join to as followers.", B_TRUE);
addskilldesc(SK_SPEECH, PR_EXPERT, "^gYou can now choose which skills to learn from people.", B_TRUE); addskilldesc(SK_SPEECH, PR_EXPERT, "^gYou can now choose which skills to learn from people.", B_TRUE);

16
defs.h
View File

@ -445,6 +445,7 @@ enum GODANGERREASON {
GA_MURDER, // killed someone peaceful GA_MURDER, // killed someone peaceful
GA_POISON, // used poison GA_POISON, // used poison
GA_PRAY, // pestering through constant prayer GA_PRAY, // pestering through constant prayer
GA_RACE, // prayed while a hated race.
GA_SPELL, // cast a spell from the wrong school GA_SPELL, // cast a spell from the wrong school
}; };
@ -877,7 +878,7 @@ enum RACECLASS {
}; };
#define R_GODFIRST R_GODPURITY #define R_GODFIRST R_GODPURITY
#define MAXGODS 6 #define MAXGODS 7
enum RACE { enum RACE {
R_NONE = 0, R_NONE = 0,
@ -904,6 +905,7 @@ enum RACE {
R_GODTHIEVES, // felix R_GODTHIEVES, // felix
R_GODDEATH, // hecta R_GODDEATH, // hecta
R_GODMERCY, // yumi R_GODMERCY, // yumi
R_GODNATURE, // ekrub
R_GODBATTLE, // bjorn R_GODBATTLE, // bjorn
R_GODMAGIC, // lumara R_GODMAGIC, // lumara
// monsters // monsters
@ -1440,6 +1442,7 @@ enum OBTYPE {
OT_S_POLYMORPH, OT_S_POLYMORPH,
OT_S_POLYMORPHRND, OT_S_POLYMORPHRND,
OT_S_QUICKENSTONE, OT_S_QUICKENSTONE,
OT_S_SHAPESHIFT,
OT_S_SIZEUP, OT_S_SIZEUP,
OT_S_SIZEDOWN, OT_S_SIZEDOWN,
// nature / enviromancy // nature / enviromancy
@ -1867,6 +1870,7 @@ enum OBTYPE {
OT_GUISARME, OT_GUISARME,
OT_HALBERD, OT_HALBERD,
OT_LANCE, OT_LANCE,
OT_PITCHFORK,
OT_RANSEUR, OT_RANSEUR,
OT_SCYTHE, OT_SCYTHE,
OT_SPEAR, OT_SPEAR,
@ -2098,6 +2102,7 @@ enum FLAG {
// monetary value) // monetary value)
// for object brands // for object brands
F_ONLYFOROBTYPE, // brand can only go on obtype v0 F_ONLYFOROBTYPE, // brand can only go on obtype v0
F_ONLYFOROBCLASS, // brand can only go on obclass v0
F_ONLYFOROBWITHFLAG, // brand can only go on obs with flag v0 F_ONLYFOROBWITHFLAG, // brand can only go on obs with flag v0
F_ONLYFORDAMTYPE, // brand can only go on obs with damtype v0 F_ONLYFORDAMTYPE, // brand can only go on obs with damtype v0
F_ONLYFORWEPSKILL, // brand can only go on obclass v0 F_ONLYFORWEPSKILL, // brand can only go on obclass v0
@ -2108,6 +2113,7 @@ enum FLAG {
// equipped on _ONE OF_ the. // equipped on _ONE OF_ the.
F_BONUS, // val0=bonus/penalty to damage+accuracy/armour. ie. +1 sword F_BONUS, // val0=bonus/penalty to damage+accuracy/armour. ie. +1 sword
F_THROWMISSILE, // weapon would make a good thrown missle - used by AI F_THROWMISSILE, // weapon would make a good thrown missle - used by AI
F_CANHOME, // this object can have the 'homing' flag
F_UNIQUE, // only one may appear F_UNIQUE, // only one may appear
F_GLYPH, // override the glyph with the first char of text. F_GLYPH, // override the glyph with the first char of text.
// v0 is either NA (white) or colourid (C_xxx). // v0 is either NA (white) or colourid (C_xxx).
@ -2406,6 +2412,7 @@ enum FLAG {
// end gun flags // end gun flags
F_FLAMESTRIKE, // causes fires where you hit F_FLAMESTRIKE, // causes fires where you hit
F_BALANCE, // heals target if their maxhp < your maxhp F_BALANCE, // heals target if their maxhp < your maxhp
F_HOMING, // missile always hits
F_MERCIFUL, // puts to sleep instead of killing. F_MERCIFUL, // puts to sleep instead of killing.
F_REVENGE, // causes damage based on your hp F_REVENGE, // causes damage based on your hp
// //
@ -2555,6 +2562,9 @@ enum FLAG {
F_ATTRSET, // forces attribute val0 to be val1. ie. 0=A_STR,1=18 F_ATTRSET, // forces attribute val0 to be val1. ie. 0=A_STR,1=18
F_SIZE, // val0 = lf size (enum LFSIZE) F_SIZE, // val0 = lf size (enum LFSIZE)
F_SIZETIMER, // lf weill resize to LFSIZE val0 in val1 turns. F_SIZETIMER, // lf weill resize to LFSIZE val0 in val1 turns.
F_UNSEENATTACKER, // this lf attacked lfid v0 while lfid v0 couldn't
// see them. used to mark 'X' on the player's map
// for unseen attackers.
F_USEDPOISON, // this lf used a poisoned weapon to attack F_USEDPOISON, // this lf used a poisoned weapon to attack
F_RANDOMTALKPCT, // v0 = chance of randomly saying something each turn F_RANDOMTALKPCT, // v0 = chance of randomly saying something each turn
F_RANDOMTALK, // EITHER: F_RANDOMTALK, // EITHER:
@ -2715,6 +2725,7 @@ enum FLAG {
F_HATESALL, // lf will attack ALL other lfs on sight F_HATESALL, // lf will attack ALL other lfs on sight
F_HATESRACE, // lf will attack lfs with race=v0 or baseid=v0 on F_HATESRACE, // lf will attack lfs with race=v0 or baseid=v0 on
// sight // sight
F_HATESRACECLASS, // lf will attack lfs with raceclass->id=v0
F_HATESRACEWITHFLAG, // lf will attack lfs with flag v0 on sight F_HATESRACEWITHFLAG, // lf will attack lfs with flag v0 on sight
F_TERRITORIAL, // lf will attack ALL other visible lfs within range v0 F_TERRITORIAL, // lf will attack ALL other visible lfs within range v0
F_HARMLESS, // it is safe to rest around this lf F_HARMLESS, // it is safe to rest around this lf
@ -2798,6 +2809,8 @@ enum FLAG {
// OB is replace with object name // OB is replace with object name
F_SACRIFICEOBWITHFLAG, // v0 = can sacrifice obs with flag v0 to this go F_SACRIFICEOBWITHFLAG, // v0 = can sacrifice obs with flag v0 to this go
F_SACRIFICEOB, // v0 = can sacrifice obtype v0 to this god F_SACRIFICEOB, // v0 = can sacrifice obtype v0 to this god
// if v1 is set, object must be the
// corpse of something with raceclass v1.
F_SACRIFICEOBCLASS, // v0 = can sacrifice obclass v0 to this god F_SACRIFICEOBCLASS, // v0 = can sacrifice obclass v0 to this god
F_SACRIFICEOBBLESSED, // v0 = can sacrifice obs with ->blessed=v0 F_SACRIFICEOBBLESSED, // v0 = can sacrifice obs with ->blessed=v0
@ -3939,6 +3952,7 @@ enum BRAND {
BR_FLIGHT, BR_FLIGHT,
BR_GIANTSTRENGTH, BR_GIANTSTRENGTH,
BR_HEALTH, BR_HEALTH,
BR_HOMING,
BR_IMPACT, BR_IMPACT,
BR_THINKING, BR_THINKING,
BR_KNOWLEDGE, BR_KNOWLEDGE,

286
god.c
View File

@ -57,6 +57,8 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) {
case GA_ATTACKOBJECT: case GA_ATTACKOBJECT:
if (rid == R_GODTHIEVES) { if (rid == R_GODTHIEVES) {
godsay(rid, B_TRUE, "What are you, a common thug?"); break; godsay(rid, B_TRUE, "What are you, a common thug?"); break;
} else if (rid == R_GODNATURE) {
godsay(rid, B_TRUE, "You dare destroy my creations?"); break;
} else { } else {
godsay(rid, B_TRUE, "You dare destroy my symbols?"); break; godsay(rid, B_TRUE, "You dare destroy my symbols?"); break;
} }
@ -77,6 +79,8 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) {
case GA_PRAY: dosay = B_TRUE; break; case GA_PRAY: dosay = B_TRUE; break;
case GA_POISON: case GA_POISON:
godsay(rid, B_TRUE, "I do not condone the use of poison!"); break; godsay(rid, B_TRUE, "I do not condone the use of poison!"); break;
case GA_RACE:
godsay(rid, B_TRUE, "Your form offends me!"); break;
case GA_SPELL: case GA_SPELL:
godsay(rid, B_TRUE, "Your magic offends me!"); break; godsay(rid, B_TRUE, "Your magic offends me!"); break;
} }
@ -182,6 +186,12 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) {
killflag(f); killflag(f);
} }
break; break;
case R_GODNATURE:
msg("\"You have transgressed against nature!\"");
dospelleffects(NULL, OT_S_ENTANGLE, 10, NULL, NULL, player->cell, B_BLESSED, NULL, B_TRUE);
// note: you will also rot food on touch until god is appeased.
// see touch().
break;
case R_GODMERCY: case R_GODMERCY:
// lower one attribute // lower one attribute
msg("\"Be glad that I am feeling merciful, mortal!\""); msg("\"Be glad that I am feeling merciful, mortal!\"");
@ -344,6 +354,22 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) {
modattr(player, a, -1); modattr(player, a, -1);
} }
break;
case R_GODNATURE:
msg("\"You have violated the cardinal laws of nature!\"");
dospelleffects(NULL, OT_S_ENTANGLE, 10, NULL, NULL, player->cell, B_BLESSED, NULL, B_TRUE);
switch (rnd(1,3)) {
case 1:
dospelleffects(NULL, OT_S_CLOUDKILL, 10, NULL, NULL, player->cell, B_BLESSED, NULL, B_TRUE);
break;
case 2:
dospelleffects(NULL, OT_S_HAILSTORM, 10, NULL, NULL, player->cell, B_BLESSED, NULL, B_TRUE);
break;
case 3:
msg("\"Destroy him, my pets!\"");
summonlfs(god, player->cell, R_SAWGRASS, RC_ANY, SZ_ANY, AL_GOOD, 8, PERMENANT, B_FALSE);
break;
}
break; break;
case R_GODPURITY: case R_GODPURITY:
switch (rnd(1,2)) { switch (rnd(1,2)) {
@ -424,8 +450,24 @@ void dooffer(void) {
flag_t *f; flag_t *f;
f = retflag[i]; f = retflag[i];
if ((f->id == F_SACRIFICEOB) && (f->val[0] == o->type->id)) { if ((f->id == F_SACRIFICEOB) && (f->val[0] == o->type->id)) {
ok = B_TRUE; int validcorpse = B_FALSE;
thispiety = f->val[2]; if (f->val[1] == NA) {
validcorpse = B_TRUE;
} else {
flag_t *ff;
ff = hasflag(o->flags, F_CORPSEOF);
if (ff) {
race_t *r;
r = findrace(ff->val[0]);
if (r->raceclass->id == f->val[1]) {
validcorpse = B_TRUE;
}
}
}
if (validcorpse) {
ok = B_TRUE;
thispiety = f->val[2];
}
} else if ((f->id == F_SACRIFICEOBCLASS) && (f->val[0] == o->type->obclass->id)) { } else if ((f->id == F_SACRIFICEOBCLASS) && (f->val[0] == o->type->obclass->id)) {
ok = B_TRUE; ok = B_TRUE;
thispiety = f->val[2]; thispiety = f->val[2];
@ -508,6 +550,7 @@ enum RACE getopposinggod(enum RACE rid) {
case R_GODMERCY: return R_GODDEATH; case R_GODMERCY: return R_GODDEATH;
case R_GODBATTLE: return R_GODMAGIC; case R_GODBATTLE: return R_GODMAGIC;
case R_GODMAGIC: return R_GODBATTLE; case R_GODMAGIC: return R_GODBATTLE;
// TODO: nature/destruction
default: break; default: break;
} }
return R_NONE; return R_NONE;
@ -639,6 +682,23 @@ lifeform_t *godappears(enum RACE rid, cell_t *where) {
return god; return god;
} }
void god_usepoison_response(void) {
int i;
flag_t *f;
for (i = 0; i < ngodlfs; i++) {
if (godlf[i]) {
f = lfhasflag(godlf[i], F_GODPOISON);
if (f) {
if (f->val[0]) {
pleasegodmaybe(godlf[i]->race->id, f->val[1]);
} else {
angergodmaybe(godlf[i]->race->id, f->val[1], GA_POISON);
}
}
}
}
}
int godblocked(enum RACE rid) { int godblocked(enum RACE rid) {
lifeform_t *opposegod; lifeform_t *opposegod;
enum RACE opposeid; enum RACE opposeid;
@ -813,6 +873,81 @@ int godgiftmaybe(enum RACE rid, int fromtemple) {
} }
} }
break; break;
case R_GODNATURE:
while (rollagain) {
flag_t *f;
object_t *o;
objecttype_t *ot;
rollagain = B_FALSE;
switch (rnd(1,6)) {
case 1: // resist/immune 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;
case 2: // resist/immune cold
if (lfhasflagval(player, F_DTRESIST, DT_COLD, NA, NA, NULL)) {
if (lfhasflagval(player, F_DTIMMUNE, DT_COLD, NA, NA, NULL)) {
rollagain = B_TRUE;
} else {
f = addtempflag(player->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL, FROMGODGIFT);
f->obfrom = god->race->id;
}
} else {
f = addtempflag(player->flags, F_DTRESIST, DT_COLD, NA, NA, NULL, FROMGODGIFT);
f->obfrom = god->race->id;
}
break;
case 3:
// good ranged weapon
if (getskill(player, SK_RANGED)) {
char obname[BUFLEN];
if (real_getrandomob(NULL, obname, 25, NA, getlfsize(player),
SK_RANGED, B_TRUE, OC_WEAPON, OC_NONE, DT_NONE)) {
snprintf(obtogive, BUFLEN, "excellent %s", obname);
} else {
rollagain = B_TRUE;
}
} else {
rollagain = B_TRUE;
}
break;
case 4: // ammo
o = getfirearm(player);
if (o) {
ot = getrandomammofor(o);
snprintf(obtogive, BUFLEN, "%d excellent %s", rnd(20,30), ot->name);
} else {
rollagain = B_TRUE;
}
break;
case 5: // calm animals ability
if (lfhasflagval(player, F_CANWILL, OT_S_CALMANIMALS, NA, NA, NULL)) {
rollagain = B_TRUE;
} else {
f = addtempflag(player->flags, F_CANWILL, OT_S_CALMANIMALS, NA, NA, "pw:10;", FROMGODGIFT);
f->obfrom = god->race->id;
}
break;
case 6:
if (lfhasflagval(player, F_CANWILL, OT_S_SHAPESHIFT, NA, NA, "pw:1;race:hawk;")) {
rollagain = B_TRUE;
} else {
f = addtempflag(player->flags, F_CANWILL, OT_S_SHAPESHIFT, 50, 50, "pw:1;race:hawk;", FROMGODGIFT);
f->obfrom = god->race->id;
}
break;
}
}
break;
case R_GODPURITY: case R_GODPURITY:
while (rollagain) { while (rollagain) {
int n,nposs,i; int n,nposs,i;
@ -939,6 +1074,15 @@ int godisangry(enum RACE rid) {
return B_FALSE; return B_FALSE;
} }
int godprayedto(enum RACE rid) {
lifeform_t *god;
god = findgod(rid);
if (hasflag(god->flags, F_PRAYEDTO)) {
return B_TRUE;
}
return B_FALSE;
}
void godsay(enum RACE rid, int says, char *format, ...) { void godsay(enum RACE rid, int says, char *format, ...) {
lifeform_t *god; lifeform_t *god;
char godname[BUFLEN], buf[BUFLEN]; char godname[BUFLEN], buf[BUFLEN];
@ -968,6 +1112,13 @@ void godsay(enum RACE rid, int says, char *format, ...) {
case R_GODMERCY: case R_GODMERCY:
strcpy(voiceverb, "washes over you"); strcpy(voiceverb, "washes over you");
break; break;
case R_GODNATURE:
if (godisangry(rid)) {
strcpy(voiceverb, "arrives with a buffeting wind");
} else {
strcpy(voiceverb, "arrives with a gentle breeze");
}
break;
case R_GODPURITY: case R_GODPURITY:
default: default:
strcpy(voiceverb, "booms out from the heavens"); strcpy(voiceverb, "booms out from the heavens");
@ -1016,6 +1167,9 @@ void pleasegod(enum RACE rid, int amt) {
case R_GODMAGIC: case R_GODMAGIC:
msg("You feel Lumara's presense nearby."); msg("You feel Lumara's presense nearby.");
break; break;
case R_GODNATURE:
msg("You feel in tune with nature.");
break;
case R_GODMERCY: case R_GODMERCY:
msg("You feel a sense of serenity."); msg("You feel a sense of serenity.");
break; break;
@ -1063,6 +1217,12 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
return B_TRUE; return B_TRUE;
} }
if (lfhasflagval(god, F_HATESRACECLASS, lf->race->raceclass->id, NA, NA, NULL) ||
lfhasflagval(god, F_HATESRACE, lf->race->id, NA, NA, NULL)) {
angergod(god->race->id, 50, GA_RACE);
return B_TRUE;
}
// this will return 100 if we haven't prayed to this // this will return 100 if we haven't prayed to this
// god before // god before
piety = getpiety(god->race->id); piety = getpiety(god->race->id);
@ -1103,6 +1263,9 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
case R_GODMERCY: case R_GODMERCY:
strcpy(assisttext, "I hear your prayer, child."); strcpy(assisttext, "I hear your prayer, child.");
break; break;
case R_GODNATURE:
strcpy(assisttext, "Nature hears your call!");
break;
case R_GODMAGIC: case R_GODMAGIC:
strcpy(assisttext, "One calls upon the eldritch powers..."); strcpy(assisttext, "One calls upon the eldritch powers...");
break; break;
@ -1288,7 +1451,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
case 1: case 1:
// steal from your enemies // steal from your enemies
for (l = lf->cell->map->lf ; l ; l = l->next) { for (l = lf->cell->map->lf ; l ; l = l->next) {
if ((l != lf) && lfhasflagval(l, F_TARGETLF, lf->id, NA, NA, NULL)) { if ((l != lf) && areenemies(l, lf)) {
object_t *wep; object_t *wep;
// confiscate their weapon // confiscate their weapon
wep = getweapon(l); wep = getweapon(l);
@ -1436,7 +1599,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
castspell(god, OT_S_SATEHUNGER, player, NULL, player->cell, NULL, NULL); castspell(god, OT_S_SATEHUNGER, player, NULL, player->cell, NULL, NULL);
donesomething = B_TRUE; donesomething = B_TRUE;
} }
if (islowhp(lf) || !donesomething) { if (islowhp(lf)) {
msg("\"Let thy wounds be healed.\""); msg("\"Let thy wounds be healed.\"");
castspell(god, OT_S_HEALINGMAJ, player, NULL, player->cell, NULL, NULL); castspell(god, OT_S_HEALINGMAJ, player, NULL, player->cell, NULL, NULL);
donesomething = B_TRUE; donesomething = B_TRUE;
@ -1445,6 +1608,121 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
// uncurse one equipped ob // uncurse one equipped ob
uncurse_one_equipped(lf, "\"Let thy curse be ended!\""); uncurse_one_equipped(lf, "\"Let thy curse be ended!\"");
break; break;
case R_GODNATURE:
if (isinbattle(lf, B_TRUE)) {
lifeform_t *l;
int donesomething = B_FALSE;
int redo = B_TRUE;
while (redo) {
redo = B_FALSE;
switch (rnd(1,3)) {
case 1:
msg("\"My children will bind your enemies!\"");
// entangle your enemies
for (l = lf->cell->map->lf ; l ; l = l->next) {
if ((l != lf) && areenemies(l, lf)) {
dospelleffects(NULL, OT_S_ENTANGLE, 10, NULL, NULL, l->cell, B_BLESSED, NULL, B_TRUE);
}
}
break;
case 2: // summon plants
msg("\"My children will aid you!\"");
summonlfs(player, player->cell, R_NONE, RC_PLANT, SZ_ANY, AL_NONE, 5, PERMENANT, B_TRUE);
break;
case 3: // lightning
msg("\"The powers of the sky will smite your foes!\"");
for (l = lf->cell->map->lf ; l ; l = l->next) {
if ((l != lf) && areenemies(l, lf)) {
dospelleffects(god, OT_S_CALLLIGHTNING, 10, NULL, NULL, l->cell, B_BLESSED, NULL, B_TRUE);
}
}
break;
}
}
// fighting a dragon?
for (i = 0; i < lf->nlos; i++) {
if (lf->los[i]->lf && (getraceclass(lf->los[i]->lf) == RC_DRAGON)) {
godappears(god->race->id, NULL);
aiattack(god, lf->los[i]->lf, PERMENANT);
donesomething = B_TRUE;
break;
}
}
} else {// not in battle
int donesomething = B_FALSE;
flag_t *f;
// fix any poison potions
dospelleffects(god, OT_S_PURIFYFOOD, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);
if (ispoisoned(lf)) {
msg("\"I will cure your poison...\"");
castspell(god, OT_S_CUREPOISON, player, NULL, player->cell, NULL, NULL);
donesomething = B_TRUE;
}
if (!donesomething && (gethungerlevel(gethungerval(player)) >= H_PECKISH)) {
msg("\"I will cure your hunger...\"");
castspell(god, OT_S_SATEHUNGER, player, NULL, player->cell, NULL, NULL);
donesomething = B_TRUE;
}
if (!donesomething && islowhp(lf)) {
msg("\"I will heal your injuries...\"");
castspell(god, OT_S_HEALINGMAJ, player, NULL, player->cell, NULL, NULL);
donesomething = B_TRUE;
}
if (!donesomething) { // out of ammo?
object_t *gun;
gun = getfirearm(lf);
if (gun && !getammo(gun) && !getrandomammo(lf)) {
objecttype_t *ot;
ot = getrandomammofor(gun);
if (ot) {
char obtogive[BUFLEN],ammoname[BUFLEN];
char gunname[BUFLEN];
object_t *ammo;
f = hasflag(gun->flags, F_AMMOCAPACITY);
snprintf(obtogive, BUFLEN, "%d %s of seeking", f->val[0], ot->name);
ammo = addob(gun->contents, obtogive);
identify(ammo);
getobname(ammo, ammoname, ammo->amt);
getobname(gun, gunname, 1);
msg("%s appear%s in your %s!", ammoname, OBS1(ammo), noprefix(gunname));
donesomething = B_TRUE;
}
}
}
if (!donesomething) { // mend one random armour
object_t *poss[MAXCANDIDATES];
int nposs = 0;
for (o = lf->pack->first ; o ; o = o->next) {
if (isequipped(o) && isarmour(o) && isdamaged(o)) {
poss[nposs++] = o;
}
}
if (nposs) {
o = poss[rnd(0,nposs-1)];
dospelleffects(lf, OT_S_MENDING, 10, NULL, o, NULL, B_BLESSED, NULL, B_FALSE);
donesomething = B_TRUE;
}
}
if (!donesomething) { // bless armour
object_t *poss[MAXCANDIDATES];
int nposs = 0;
for (o = lf->pack->first ; o ; o = o->next) {
if (isequipped(o) && isarmour(o) && (o->blessed == B_UNCURSED)) {
poss[nposs++] = o;
}
}
if (nposs) {
o = poss[rnd(0,nposs-1)];
msg("\"Nature's power will protect you...\"");
blessob(o);
}
donesomething = B_TRUE;
}
}
break;
default: default:
break; break;
} }

2
god.h
View File

@ -11,9 +11,11 @@ int getprayedgods(lifeform_t **retgod, int *nretgods);
lifeform_t *getrandomgod(void); lifeform_t *getrandomgod(void);
lifeform_t *getrandomprayedgod(void); lifeform_t *getrandomprayedgod(void);
lifeform_t *godappears(enum RACE rid, cell_t *where); lifeform_t *godappears(enum RACE rid, cell_t *where);
void god_usepoison_response(void);
int godblocked(enum RACE rid); int godblocked(enum RACE rid);
int godgiftmaybe(enum RACE rid, int fromtemple); int godgiftmaybe(enum RACE rid, int fromtemple);
int godisangry(enum RACE rid); int godisangry(enum RACE rid);
int godprayedto(enum RACE rid);
void godsay(enum RACE rid, int says, char *format, ...); void godsay(enum RACE rid, int says, char *format, ...);
void modpiety(enum RACE rid, int amt); void modpiety(enum RACE rid, int amt);
void pleasegod(enum RACE rid, int amt); void pleasegod(enum RACE rid, int amt);

20
io.c
View File

@ -3790,10 +3790,10 @@ void docomms(lifeform_t *lf) {
enum SKILLLEVEL slev; enum SKILLLEVEL slev;
slev = getskill(player, SK_SPEECH); slev = getskill(player, SK_SPEECH);
if (slev >= PR_NOVICE) { if (slev >= PR_NOVICE) {
addchoice(&prompt, 'i', "What can you tell me about this area?", NULL, NULL, NULL); addchoice(&prompt, 'x', "Any dangers nearby that I should look out for?", NULL, NULL, NULL);
} }
if (slev >= PR_BEGINNER) { if (slev >= PR_BEGINNER) {
addchoice(&prompt, 'x', "Any dangers nearby that I should look out for?", NULL, NULL, NULL); addchoice(&prompt, 'i', "What can you tell me about this area?", NULL, NULL, NULL);
} }
if (!areallies(player, lf)) { if (!areallies(player, lf)) {
if (slev >= PR_ADEPT) { if (slev >= PR_ADEPT) {
@ -4841,14 +4841,22 @@ char *makedesc_god(lifeform_t *god, char *retbuf) {
} }
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_NONE); getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_NONE);
for (i = 0; i < nretflags; i++) { for (i = 0; i < nretflags; i++) {
objecttype_t *ot;
if (i == 0) { if (i == 0) {
sprintf(thisline, "%s accepts the sacrifice of:\n", godname); sprintf(thisline, "%s accepts the sacrifice of:\n", godname);
strncat(retbuf, thisline, HUGEBUFLEN); strncat(retbuf, thisline, HUGEBUFLEN);
} }
ot = findot(retflag[i]->val[0]);
sprintf(thisline, "- %s\n", ot->name); if (retflag[i]->val[1] == NA) {
strncat(retbuf, thisline, HUGEBUFLEN); objecttype_t *ot;
ot = findot(retflag[i]->val[0]);
sprintf(thisline, "- %s\n", ot->name);
strncat(retbuf, thisline, HUGEBUFLEN);
} else {
raceclass_t *rc;
rc = findraceclass(retflag[i]->val[1]);
sprintf(thisline, "- %s corpses\n", rc->name);
strncat(retbuf, thisline, HUGEBUFLEN);
}
} }
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOBBLESSED, F_NONE); getflags(god->flags, retflag, &nretflags, F_SACRIFICEOBBLESSED, F_NONE);
for (i = 0; i < nretflags; i++) { for (i = 0; i < nretflags; i++) {

58
lf.c
View File

@ -1662,6 +1662,13 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
return B_FALSE; return B_FALSE;
} }
} }
// casting a nature spell while nature god is angry at you?
if (isplayer(lf) && godprayedto(R_GODNATURE) && godisangry(R_GODNATURE) && !willflag) {
if (hasflagval(sp->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL)) {
msg("You seem to be cut off from the powers of nature magic.");
return B_FALSE;
}
}
// adjust power? // adjust power?
if (hasjob(lf, J_DRUID)) { if (hasjob(lf, J_DRUID)) {
@ -1814,6 +1821,9 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
pleasegodmaybe(R_GODPURITY, getspelllevel(sid)); pleasegodmaybe(R_GODPURITY, getspelllevel(sid));
angergodmaybe(R_GODDEATH, getspelllevel(sid)*5, GA_SPELL); angergodmaybe(R_GODDEATH, getspelllevel(sid)*5, GA_SPELL);
break; break;
case SS_NATURE:
pleasegodmaybe(R_GODNATURE, getspelllevel(sid)*2);
break;
default: default:
break; break;
} }
@ -2401,9 +2411,22 @@ void die(lifeform_t *lf) {
// revert to your original form first. // revert to your original form first.
if (lfhasflag(lf, F_POLYMORPHED)) { if (lfhasflag(lf, F_POLYMORPHED)) {
if (lfhasflag(lf, F_ORIGRACE)) { if (lfhasflag(lf, F_ORIGRACE)) {
int premaxhp;
premaxhp = lf->maxhp;
abilityeffects(lf, OT_A_POLYREVERT, lf->cell, lf, NULL); abilityeffects(lf, OT_A_POLYREVERT, lf->cell, lf, NULL);
// but you stay at lower hp.
if (premaxhp < lf->maxhp) {
float ratio;
ratio = (float)premaxhp / (float) lf->maxhp;
lf->maxhp = ratio * lf->maxhp;
limit(&(lf->hp), 1, lf->maxhp);
}
if (isplayer(lf)) statdirty = B_TRUE;
/*
// ... but you're still dead // ... but you're still dead
lf->hp = 0; lf->hp = 0;
*/
return;
} }
} }
@ -2527,6 +2550,19 @@ void die(lifeform_t *lf) {
pleasegodmaybe(R_GODDEATH, 1); pleasegodmaybe(R_GODDEATH, 1);
} }
switch (lf->race->raceclass->id) {
case RC_ANIMAL:
if (gethungerlevel(gethungerval(player)) > H_NONE) {
pleasegodmaybe(R_GODNATURE, 3);
}
break;
case RC_DRAGON:
pleasegodmaybe(R_GODNATURE, 50);
break;
default:
break;
}
// mercy god doesn't like killing // mercy god doesn't like killing
//angergodmaybe(R_GODMERCY, 1, GA_MURDER); //angergodmaybe(R_GODMERCY, 1, GA_MURDER);
} }
@ -3446,7 +3482,7 @@ int eat(lifeform_t *lf, object_t *o) {
} else { } else {
snprintf(dambuf, BUFLEN, "a bad %s",noprefix(obname)); snprintf(dambuf, BUFLEN, "a bad %s",noprefix(obname));
} }
poison(lf, 20, P_FOOD, 1, dambuf); poison(lf, rnd(20,40), P_FOOD, 1, dambuf);
} }
} }
@ -12839,7 +12875,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
} else if (damtype == DT_POISONGAS) { } else if (damtype == DT_POISONGAS) {
if (amt > 0) { if (amt > 0) {
if (!skillcheck(lf, SC_POISON, 35, 0)) { // HARD. if (!skillcheck(lf, SC_POISON, 35, 0)) { // HARD.
poison(lf, rnd(5,10), P_GAS, 2, "poison gas"); poison(lf, rnd(20,40), P_GAS, 2, "poison gas");
} }
} }
} }
@ -15520,14 +15556,14 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
// announce // announce
if (reverting) { if (reverting) {
// reverting to original form.... // reverting to original form....
if (!isdead(lf)) { //if (!isdead(lf)) {
if (isplayer(lf)) { if (isplayer(lf)) {
msg("^wYou revert to your original form!"); msg("^wYou revert to your original form!");
} else if (cansee(player, lf)) { } else if (cansee(player, lf)) {
getlfname(lf, buf); getlfname(lf, buf);
msg("^wThe %s transforms back to its original form!", newrace->name); msg("^wThe %s transforms back to its original form!", newrace->name);
} }
} //}
if ((lf->race->id == R_GASCLOUD) && (origrace->id == R_VAMPIRE)) { if ((lf->race->id == R_GASCLOUD) && (origrace->id == R_VAMPIRE)) {
if (!isplayer(lf)) { if (!isplayer(lf)) {
@ -16444,6 +16480,7 @@ void startlfturn(lifeform_t *lf) {
if (isplayer(lf) && lfhasflag(lf, F_DRUNK)) statdirty = B_TRUE; if (isplayer(lf) && lfhasflag(lf, F_DRUNK)) statdirty = B_TRUE;
// clear one-turn-only flags // clear one-turn-only flags
killflagsofid(lf->flags, F_UNSEENATTACKER);
killflagsofid(lf->flags, F_DONELISTEN); killflagsofid(lf->flags, F_DONELISTEN);
killflagsofid(lf->flags, F_NOSWAP); killflagsofid(lf->flags, F_NOSWAP);
movedlastturn = 0; movedlastturn = 0;
@ -18137,6 +18174,19 @@ int touch(lifeform_t *lf, object_t *o) {
} }
if (isplayer(lf)) {
if (godprayedto(R_GODNATURE) && godisangry(R_GODNATURE) && isedible(o)) {
char obname[BUFLEN];
getobname(o, obname, o->amt);
msg("A green miasma surrounds %s as you touch %s.", obname,
(o->amt == 1) ? "it" : "them");
if (!hasflag(o->flags, F_TAINTED)) {
addflag(o->flags, F_TAINTED, B_TRUE, NA, NA, NULL);
}
}
}
f = hasflag(o->flags, F_SHARP); f = hasflag(o->flags, F_SHARP);
if (f) { if (f) {
object_t *gloves; object_t *gloves;

23
map.c
View File

@ -2852,7 +2852,7 @@ void createheaven(map_t *map, int depth, map_t *parentmap, int exitdir, object_t
godlf[ngodlfs++] = lf; godlf[ngodlfs++] = lf;
if (ngodlfs > MAXGODS) { if (ngodlfs > MAXGODS) {
dblog("Error - number of gods(%d) exceeds MAXGODS.",ngodlfs); dblog("Error - number of gods(%d) exceeds MAXGODS.",ngodlfs);
msg("Error - number of gods(%d) exceeds MAXGODS.",ngodlfs); msg("Error - number of gods(%d) exceeds MAXGODS.",ngodlfs); more();
exit(1); exit(1);
} }
roomid++; roomid++;
@ -6245,6 +6245,9 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) {
if (!f) { if (!f) {
f = lfhasflagval(c->lf, F_ATTACHEDTO, player->id, NA, NA, NULL); f = lfhasflagval(c->lf, F_ATTACHEDTO, player->id, NA, NA, NULL);
} }
if (!f) {
f = lfhasflagval(c->lf, F_UNSEENATTACKER, player->id, NA, NA, NULL);
}
if (f) { if (f) {
if (glyph) { if (glyph) {
glyph->ch = 'X'; glyph->ch = 'X';
@ -6253,10 +6256,20 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) {
*thing = c->lf; *thing = c->lf;
if (desc) { if (desc) {
getlfname(c->lf, desc); getlfname(c->lf, desc);
if (f->id == F_GRABBEDBY) { switch (f->id) {
strcat(desc, " (holding you)"); case F_GRABBEDBY:
} else { strcat(desc, " (holding you)");
strcat(desc, " (attached to you)"); break;
case F_ATTACHEDTO:
strcat(desc, " (attached to you)");
break;
case F_UNSEENATTACKER:
strcat(desc, " (unseen attacker)");
break;
default:
// should never happen
strcat(desc, " (detected)");
break;
} }
} }
return TT_MONSTER; return TT_MONSTER;

3
move.c
View File

@ -1342,6 +1342,9 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
} }
// kill object which is being crushed. // kill object which is being crushed.
removeob(o, o->amt); removeob(o, o->amt);
if (isplayer(lf)) {
angergodmaybe(R_GODNATURE, 10, GA_ATTACKOBJECT);
}
continue; continue;
} }
} // end if crushable } // end if crushable

10
nexus.c
View File

@ -11,6 +11,7 @@
#include "data.h" #include "data.h"
#include "io.h" #include "io.h"
#include "flag.h" #include "flag.h"
#include "god.h"
#include "lf.h" #include "lf.h"
#include "map.h" #include "map.h"
#include "move.h" #include "move.h"
@ -330,6 +331,7 @@ int main(int argc, char **argv) {
if (j->id == J_DRUID) { if (j->id == J_DRUID) {
enum OBTYPE spell; enum OBTYPE spell;
int i; int i;
lifeform_t *god;
for (i = 0;i < 3; i++) { for (i = 0;i < 3; i++) {
// pick a spell which you don't already have... // pick a spell which you don't already have...
spell = getrandomspellfromschool(SS_NATURE, 1); spell = getrandomspellfromschool(SS_NATURE, 1);
@ -339,6 +341,9 @@ int main(int argc, char **argv) {
// you can now cast it. // you can now cast it.
addflag(player->flags, F_CANCAST, spell, NA, NA, NULL); addflag(player->flags, F_CANCAST, spell, NA, NA, NULL);
} }
// druids always worship ekrub
god = findgod(R_GODNATURE);
addflag(god->flags, F_PRAYEDTO, B_TRUE, NA, NA, NULL);
} else if (j->id == J_WIZARD) { } else if (j->id == J_WIZARD) {
skill_t *sk; skill_t *sk;
object_t *sb1,*sb2; object_t *sb1,*sb2;
@ -443,13 +448,14 @@ int main(int argc, char **argv) {
cell_t *c; cell_t *c;
race_t *r; race_t *r;
lifeform_t *pet; lifeform_t *pet;
enum OBTYPE avoidob = OT_WATERDEEP;
f = retflag[i]; f = retflag[i];
r = findracebyname(f->text); r = findracebyname(f->text);
assert(r); assert(r);
// create it // create pet, in view of player if possible.
c = getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND); c = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, &avoidob, player);
assert(c); assert(c);
pet = addlf(c, r->id, 1); pet = addlf(c, r->id, 1);
// mark us as its master // mark us as its master

129
objects.c
View File

@ -2833,6 +2833,23 @@ int countnames(char **list) {
return count; return count;
} }
// returns the value of the most valuable object with flag 'fid'
// if fid is F_NONE, just returns the most valuable object
int counthighestobflagvalue(obpile_t *op, enum FLAG fid) {
object_t *o;
int maxval = -1;
for (o = op->first ; o ; o = o->next) {
if ((fid == F_NONE) || hasflag(o->flags, fid)) {
int thisval;
thisval = getobvalue(o);
if (thisval > maxval) {
maxval = thisval;
}
}
}
return maxval;
}
int countobs(obpile_t *op, int onlyifknown) { int countobs(obpile_t *op, int onlyifknown) {
object_t *o; object_t *o;
@ -3741,32 +3758,39 @@ int getobspellpower(object_t *o, lifeform_t *lf) {
return power; return power;
} }
// returns value of obejcts, in gold
int getobvalue(object_t *o) { int getobvalue(object_t *o) {
float price; return real_getobvalue(o, o->amt);
}
// returns value of obejcts, in gold
int real_getobvalue(object_t *o, int amt) {
float price = 1;
flag_t *f; flag_t *f;
int rarity = 0,i; int i;
enum RARITY rr = RR_FREQUENT; enum RARITY rr = RR_FREQUENT;
flag_t *retflag[MAXCANDIDATES]; flag_t *retflag[MAXCANDIDATES];
int nretflags = 0; int nretflags = 0;
if (o->type->id == OT_GOLD) { if (o->type->id == OT_GOLD) {
return o->amt; return amt;
} }
if (o->type->id == OT_CREDITCARD) { if (o->type->id == OT_CREDITCARD) {
return getcharges(o); return getcharges(o);
} }
// rarity
getobrarity(o, &rr);
// base value: weight * material value
price = (float)getobweight(o) * (float)getmaterialvalue(o->material->id);
//adjustprice(o->type, &price); //adjustprice(o->type, &price);
// fixed prices // fixed prices
f = hasflag(o->flags, F_VALUE); f = hasflag(o->flags, F_VALUE);
if (f) { if (f) {
price += f->val[0]; price = f->val[0];
} else {
// base value: weight * material value
price = (float)getobweight(o) * (float)getmaterialvalue(o->material->id);
} }
if (o->type->id == OT_SPELLBOOK) { if (o->type->id == OT_SPELLBOOK) {
@ -3822,9 +3846,6 @@ int getobvalue(object_t *o) {
price += 1000; price += 1000;
} }
// rarity
rarity = getobrarity(o, &rr);
// TODO: conferred intrinsics - depends on which one // TODO: conferred intrinsics - depends on which one
// TODO: conferred spells - use spell price * multiplier // TODO: conferred spells - use spell price * multiplier
@ -3838,27 +3859,30 @@ int getobvalue(object_t *o) {
} }
// scarcity... // scarcity...
switch (rr) { if (!hasflag(o->flags, F_VALUE)) {
case RR_UNIQUE: switch (rr) {
price *= 5; case RR_UNIQUE:
break; price *= 5;
case RR_VERYRARE: break;
price *= 3; case RR_VERYRARE:
break; price *= 3;
case RR_RARE: break;
price *= 2; case RR_RARE:
break; price *= 2;
case RR_UNCOMMON: break;
break; case RR_UNCOMMON:
case RR_COMMON: break;
price *= 0.75; case RR_COMMON:
break; price *= 0.75;
case RR_FREQUENT: break;
price *= 0.5; case RR_FREQUENT:
break; price *= 0.5;
default: break;
break; default:
break;
}
} }
// blessed/cursed // blessed/cursed
if (o->type->id == OT_POT_WATER) { if (o->type->id == OT_POT_WATER) {
if (isblessed(o) || iscursed(o)) price *= 29.25; if (isblessed(o) || iscursed(o)) price *= 29.25;
@ -3869,7 +3893,8 @@ int getobvalue(object_t *o) {
// minimum // minimum
limitf(&price, 1, NA); limitf(&price, 1, NA);
price = ((int)price * o->amt); price = ((int)price * amt);
dblog("price for %s is %d", o->type->name, (int)price);
return (int) price; return (int) price;
} }
@ -8146,20 +8171,28 @@ int brandappliesto(brand_t *br, objecttype_t *ot) {
flag_t *retflag[MAXCANDIDATES]; flag_t *retflag[MAXCANDIDATES];
int i,nretflags = 0; int i,nretflags = 0;
if (br->bp == BP_WEAPON) { if (br->bp != BP_NONE) {
if (ot->obclass->id != OC_WEAPON) { if (br->bp == BP_WEAPON) {
return B_FALSE; if (ot->obclass->id != OC_WEAPON) {
return B_FALSE;
}
} else {
// differentiate shields from guns using f_onlywithwepskill below.
if (!hasflagval(ot->flags, F_GOESON, br->bp, NA, NA, NULL)) {
return B_FALSE;
}
} }
} else { }
// TODO: how do we differentiate shields from guns?
if (!hasflagval(ot->flags, F_GOESON, br->bp, NA, NA, NULL)) { // other restrictions?
if (hasflag(br->flags, F_ONLYFOROBTYPE)) {
if (!hasflagval(br->flags, F_ONLYFOROBTYPE, ot->id, NA, NA, NULL)) {
return B_FALSE; return B_FALSE;
} }
} }
// other restrictions?
if (hasflag(br->flags, F_ONLYFOROBTYPE)) { if (hasflag(br->flags, F_ONLYFOROBCLASS)) {
if (!hasflagval(br->flags, F_ONLYFOROBTYPE, ot->id, NA, NA, NULL)) { if (!hasflagval(br->flags, F_ONLYFOROBCLASS, ot->obclass->id, NA, NA, NULL)) {
return B_FALSE; return B_FALSE;
} }
} }
@ -10937,15 +10970,18 @@ object_t *relinkob(object_t *src, obpile_t *dst) {
return src; return src;
} }
void removedeadobs(obpile_t *op) { int removedeadobs(obpile_t *op) {
object_t *o, *nexto; object_t *o, *nexto;
int nremoved = 0;
for (o = op->first ; o ; o = nexto) { for (o = op->first ; o ; o = nexto) {
nexto = o->next; nexto = o->next;
if (hasflag(o->flags, F_DEAD)) { if (hasflag(o->flags, F_DEAD)) {
checkflagpile(o->flags); checkflagpile(o->flags);
obdie(o); obdie(o);
nremoved++;
} }
} }
return nremoved;
} }
// returns the amount left // returns the amount left
@ -11240,6 +11276,9 @@ int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
makeknown(o->type->id); makeknown(o->type->id);
} }
potioneffects(target, o->type->id, o, o->blessed, &observed); potioneffects(target, o->type->id, o, o->blessed, &observed);
if (fromlf && isplayer(fromlf) && (o->type->id == OT_POT_POISON)) {
god_usepoison_response();
}
} }
break; break;
case OT_POT_HEALING: case OT_POT_HEALING:
@ -12163,6 +12202,11 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
myroll -= 20; myroll -= 20;
} }
// "of homing" missiles always hit.
if (hasflag(o->flags, F_HOMING)) {
myroll = acc;
}
// metal projectile versus magnetic shield? // metal projectile versus magnetic shield?
if (target && lfhasflag(target, F_MAGSHIELD) && ismetal(o->material->id)) { if (target && lfhasflag(target, F_MAGSHIELD) && ismetal(o->material->id)) {
// announce // announce
@ -12457,6 +12501,9 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
char dambuf[BUFLEN]; char dambuf[BUFLEN];
snprintf(dambuf, BUFLEN, "%s (%s by %s)",obname,throwverbpast, realthrowernamea); snprintf(dambuf, BUFLEN, "%s (%s by %s)",obname,throwverbpast, realthrowernamea);
shatter(newob, youhit, dambuf, thrower); shatter(newob, youhit, dambuf, thrower);
if (thrower && isplayer(thrower)) {
angergodmaybe(R_GODNATURE, 10, GA_ATTACKOBJECT);
}
} else { } else {
// object only gets damaged if it hit someone/something // object only gets damaged if it hit someone/something
if (missiledam) { if (missiledam) {

View File

@ -42,6 +42,7 @@ void copyobprops(object_t *dst, object_t *src);
int counthiddennames(enum OBCLASS ocid, char *text); int counthiddennames(enum OBCLASS ocid, char *text);
int countmoney(obpile_t *op); int countmoney(obpile_t *op);
int countnames(char **list); int countnames(char **list);
int counthighestobflagvalue(obpile_t *op, enum FLAG fid);
int countobs(obpile_t *op, int onlyifknown); int countobs(obpile_t *op, int onlyifknown);
int countobsoftype(obpile_t *op, enum OBTYPE oid); int countobsoftype(obpile_t *op, enum OBTYPE oid);
int countobswithflag(obpile_t *op, enum FLAG flagid); int countobswithflag(obpile_t *op, enum FLAG flagid);
@ -87,6 +88,7 @@ skill_t *getobskill(flagpile_t *fp);
enum LFSIZE getobsize(object_t *o); enum LFSIZE getobsize(object_t *o);
int getobspellpower(object_t *o, lifeform_t *lf); int getobspellpower(object_t *o, lifeform_t *lf);
int getobvalue(object_t *o); int getobvalue(object_t *o);
int real_getobvalue(object_t *o, int amt);
char *getoperateverb(object_t *o); char *getoperateverb(object_t *o);
object_t *getoutercontainer(object_t *o); object_t *getoutercontainer(object_t *o);
object_t *getoutercontainerop(obpile_t *op); object_t *getoutercontainerop(obpile_t *op);
@ -253,7 +255,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
int pour(lifeform_t *lf, object_t *o); int pour(lifeform_t *lf, object_t *o);
void quaff(lifeform_t *lf, object_t *o); void quaff(lifeform_t *lf, object_t *o);
int readsomething(lifeform_t *lf, object_t *o); int readsomething(lifeform_t *lf, object_t *o);
void removedeadobs(obpile_t *op); int removedeadobs(obpile_t *op);
int removeob(object_t *o, int howmany); int removeob(object_t *o, int howmany);
object_t *relinkob(object_t *src, obpile_t *dst); object_t *relinkob(object_t *src, obpile_t *dst);
void resizeobject(object_t *o, enum LFSIZE wantsize); void resizeobject(object_t *o, enum LFSIZE wantsize);

201
shops.c
View File

@ -32,17 +32,18 @@ extern WINDOW *mainwin;
float applyshoppricemod(float origprice, lifeform_t *lf) { float applyshoppricemod(float origprice, lifeform_t *lf) {
float newprice; float newprice;
if (lf) { if (lf) {
float pricepctmod = 0; float pricepct = 100;
enum SKILLLEVEL slev; enum SKILLLEVEL slev;
// price goes up/down for charisma (+/- 25%) // price goes up/down for charisma (+/- 25%)
pricepctmod -= getstatmod(lf, A_CHA)/2; // high bonus = lower price.
pricepct -= (getstatmod(lf, A_CHA)/2);
// modify for speech (up to -30%); // reduce based on speech (up to -30%);
slev = getskill(lf, SK_SPEECH); slev = getskill(lf, SK_SPEECH);
if (slev) { if (slev) {
pricepctmod -= (slev*5); pricepct -= (slev*5);
} }
newprice = pctof(origprice, 100 + pricepctmod); newprice = pctof(pricepct, origprice);
} else { } else {
newprice = origprice; newprice = origprice;
} }
@ -52,6 +53,18 @@ float applyshoppricemod(float origprice, lifeform_t *lf) {
return newprice; return newprice;
} }
int canafford(lifeform_t *lf, int amt) {
int goldamt = 0,gemamt = 0;
goldamt = countmoney(lf->pack);
if (getskill(lf, SK_SPEECH) >= PR_NOVICE) {
gemamt = applyshoppricemod(counthighestobflagvalue(lf->pack, F_GEM), lf); // adjust using charisma etc
}
if ((goldamt >= amt ) || (gemamt >= amt) || hasob(lf->pack, OT_CREDITCARD)) {
return B_TRUE;
}
return B_FALSE;
}
int getshopblessprice(object_t *o) { int getshopblessprice(object_t *o) {
int cost = 0; int cost = 0;
int remcursecost, blesscost,surcharge; int remcursecost, blesscost,surcharge;
@ -616,7 +629,7 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top
snprintf(buf, BUFLEN, "%c - %s", o->letter, obname); snprintf(buf, BUFLEN, "%c - %s", o->letter, obname);
if (shopmode == BUY) { if (shopmode == BUY) {
if (countmoney(player->pack) >= thisprice) { if (canafford(player, thisprice)) {
col = C_GREY; col = C_GREY;
} else { } else {
col = C_RED; col = C_RED;
@ -676,80 +689,140 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top
} }
answer = askchar(buf, validchars,"n", B_TRUE, B_FALSE); answer = askchar(buf, validchars,"n", B_TRUE, B_FALSE);
if (answer == 'y') { if (answer == 'y') {
// prompt to use a card char ques[BUFLEN];
if (hasob(player->pack, OT_CREDITCARD)) { object_t *oo;
char ch2;
ch2 = askchar("Charge this purchase to your credit card?","yn","n", B_TRUE, B_FALSE); // do you have enough money (or a credit card)?
if (ch2 == 'y') { if (canafford(player, value)) {
object_t *cc; object_t *money = NULL;
// ask which one enum SKILLLEVEL slev;
initprompt(&prompt, "Which credit card will you use?"); slev = getskill(lf, SK_SPEECH);
for (cc = player->pack->first ; cc ; cc = cc->next) { // determine payment method
if (cc->type->id == OT_CREDITCARD) { sprintf(ques, "How will you pay for %s?", obname);
char cardname[BUFLEN]; initprompt(&prompt, ques);
getobname(cc, cardname, 1); for (oo = player->pack->first ; oo ; oo = oo->next) {
addchoice(&prompt, cc->letter, cardname, cardname, cc, NULL); if ((oo->type->id == OT_GOLD) || (oo->type->id == OT_CREDITCARD) || hasflag(oo->flags, F_GEM)) {
char moneyname[BUFLEN];
char fullname[BUFLEN];
int valid = B_FALSE;
getobname(oo, moneyname, oo->amt);
if (oo->type->id == OT_GOLD) {
// only list gold if you have enough
if (getobvalue(oo) >= value) valid = B_TRUE;
strcpy(fullname, moneyname);
} else if ((slev >= PR_NOVICE) && hasflag(oo->flags, F_GEM)) {
// only list gems which are worth enough
int thisval;
thisval = applyshoppricemod(getobvalue(oo), player);
if (thisval >= value) {
valid = B_TRUE;
sprintf(fullname, "%s (worth $%d)", moneyname, thisval);
}
} else {
// always list cards
valid = B_TRUE;
strcpy(fullname, moneyname);
}
if (valid) {
addchoice(&prompt, oo->letter, fullname, fullname, oo, NULL);
} }
} }
if (prompt.nchoices == 1) { }
// only one card? money = NULL;
cc = (object_t *)prompt.choice[0].data; if (prompt.nchoices == 1) {
} else { // only one possibility.
addchoice(&prompt, '-', "(cancel)", "(cancel)", NULL, NULL); // is it gold?
prompt.maycancel = B_TRUE; money = (object_t *)prompt.choice[0].data;
getchoice(&prompt); if (money->type->id != OT_GOLD) {
cc = (object_t *)prompt.result; // if not gold, still confirm it.
money = NULL;
} }
if (cc) { }
if (getcharges(cc) >= getobvalue(o)) { if (!money) {
int shopamt; addchoice(&prompt, '-', "(cancel)", "(cancel)", NULL, NULL);
prompt.maycancel = B_TRUE;
getchoice(&prompt);
money = (object_t *)prompt.result;
}
if (money) {
int buyit = B_FALSE;
char buytext[BUFLEN];
enum {
PM_GOLD,
PM_GEM,
PM_CARD,
} purchasemethod;
if (money->type->id == OT_CREDITCARD) {
purchasemethod = PM_CARD;
if (getcharges(money) >= value) {
// you got it! // you got it!
usecharges(cc, getobvalue(o)); buyit = B_TRUE;
o->letter = '\0'; usecharges(money, value);
shopamt = o->amt; // avoid "purchased: 2 apples" when you only bought 1 but were holding 1 strcpy(buytext, "Charged to card:");
o = moveob(o, player->pack, ALL);
identify(o);
getobname(o, obname, shopamt);
snprintf(toptext, BUFLEN, "Charged to card: %c - %s", o->letter, obname);
if (npurchased) (*npurchased)++; if (npurchased) (*npurchased)++;
// god of thieves likes credit cards...
pleasegodmaybe(R_GODTHIEVES, (value/75));
return SR_CONTINUE;
} else { } else {
// maxed! // maxed!
usecharges(cc, getcharges(o)); // use up all remaining charges usecharges(money, getcharges(o)); // use up all remaining charges
// get kicked out // get kicked out
msg("^B\"Trying to use a maxed out card, eh? Get out of here, thief!\""); more(); msg("^B\"Trying to use a maxed out card, eh? Get out of here, thief!\""); more();
// shop closes // shop closes
addflag(vm->flags, F_BANNEDLF, player->id, NA, NA, NULL); addflag(vm->flags, F_BANNEDLF, player->id, NA, NA, NULL);
return SR_QUIT; return SR_QUIT;
} }
} else { // ie gold or gem;
if (getobvalue(money) >= value) {
buyit = B_TRUE;
// lose money (do this first to avoid potential weight issues)
if (hasflag(money->flags, F_GEM)) {
int gemsneeded;
char gemname[BUFLEN];
int valpergem;
valpergem = applyshoppricemod(real_getobvalue(money, 1), player);
gemsneeded = value / valpergem;
limit(&gemsneeded, 1, NA); // (in case gem is worth more than object)
getobname(money, gemname, gemsneeded);
// remove enough to pay...
removeob(money, gemsneeded);
purchasemethod = PM_GEM;
// announce that we're using a gem
msg("You hand over %s.", gemname); more();
} else {
givemoney(player, NULL, value);
purchasemethod = PM_GOLD;
}
strcpy(buytext, "Purchased");
if (npurchased) (*npurchased)++;
} else {
msg("I'm afraid that won't cover it..."); more();
o = NULL;
}
}
if (buyit) {
int shopamt;
// clear o->letter
o->letter = '\0';
// give object
shopamt = o->amt; // avoid "purchased: 2 apples" when you only bought 1 but were holding 1
o = moveob(o, player->pack, ALL);
identify(o);
getobname(o, obname, shopamt);
snprintf(toptext, BUFLEN, "%s: %c - %s", buytext, o->letter, obname);
if (npurchased) (*npurchased)++;
if (purchasemethod == PM_CARD) {
// god of thieves likes credit cards...
pleasegodmaybe(R_GODTHIEVES, (value/75));
} else {
practice(player, SK_SPEECH, 1);
}
} }
}
}
// do you have enough money?
if (countmoney(player->pack) >= getobvalue(o) ) {
int shopamt;
object_t *gold;
gold = hasob(player->pack, OT_GOLD);
if (gold) {
// if so, buy it
// lose money (do this first to avoid potential weight issues)
givemoney(player, NULL, value);
// clear o->letter
o->letter = '\0';
// give object
shopamt = o->amt; // avoid "purchased: 2 apples" when you only bought 1 but were holding 1
o = moveob(o, player->pack, ALL);
identify(o);
getobname(o, obname, shopamt);
snprintf(toptext, BUFLEN, "Purchased: %c - %s", o->letter, obname);
if (npurchased) (*npurchased)++;
practice(player, SK_SPEECH, 1);
} else { } else {
msg("You don't seem to have any money..."); more(); msg("Cancelled."); more();
o = NULL; o = NULL;
} } // end if money
} else { } else {
msg("You can't afford that!"); more(); msg("You can't afford that!"); more();
o = NULL; o = NULL;

View File

@ -1,6 +1,7 @@
#include "defs.h" #include "defs.h"
float applyshoppricemod(float origprice, lifeform_t *lf); float applyshoppricemod(float origprice, lifeform_t *lf);
int canafford(lifeform_t *lf, int amt);
int getshopblessprice(object_t *o); int getshopblessprice(object_t *o);
void shop(lifeform_t *lf, object_t *vm); void shop(lifeform_t *lf, object_t *vm);
enum SHOPRETURN shopabsolve(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated); enum SHOPRETURN shopabsolve(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated);

268
spell.c
View File

@ -698,6 +698,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// take some time // take some time
taketime(user, getactspeed(user)); taketime(user, getactspeed(user));
practice(user, SK_COOKING, 1); practice(user, SK_COOKING, 1);
if (isplayer(user)) pleasegodmaybe(R_GODNATURE, 5);
} else { } else {
// pack full? // pack full?
msg("You have no space to cook!"); msg("You have no space to cook!");
@ -3778,6 +3779,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
// no corpse after death (so you can't keep reanimating it) // no corpse after death (so you can't keep reanimating it)
addflag(lf->flags, F_NOCORPSE, NA, NA, NA, NULL); addflag(lf->flags, F_NOCORPSE, NA, NA, NA, NULL);
if (isplayer(caster)) pleasegodmaybe(R_GODNATURE, 25);
} else { } else {
fizzle(caster); fizzle(caster);
return B_FALSE; return B_FALSE;
@ -4167,7 +4169,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
// outdoors? // outdoors?
if (isoutdoors(target->cell->map)) { if (caster && (getraceclass(caster) == RC_GOD)) {
losehp(target, rolldie(5,6), DT_ELECTRIC, caster, "a heavenly bolt of lightning");
} else if (isoutdoors(target->cell->map)) {
losehp(target, rolldie(4,6), DT_ELECTRIC, caster, "a bolt of lightning"); losehp(target, rolldie(4,6), DT_ELECTRIC, caster, "a bolt of lightning");
} else { } else {
losehp(target, rolldie(3,6), DT_ELECTRIC, caster, "a bolt of lightning"); losehp(target, rolldie(3,6), DT_ELECTRIC, caster, "a bolt of lightning");
@ -4413,7 +4417,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
addobburst(targcell, radius, DT_COMPASS, "puff of poison gas", caster, LOF_WALLSTOP); addobburst(targcell, radius, DT_COMPASS, "puff of poison gas", caster, LOF_WALLSTOP);
if (haslos(player, targcell)) { if (haslos(player, targcell)) {
msg("A puff of poison gas appears!"); msg("A cloud of poison gas appears!");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
} else if (spellid == OT_S_CHARM) { } else if (spellid == OT_S_CHARM) {
@ -4729,6 +4733,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
if (isplayer(caster)) pleasegodmaybe(R_GODNATURE, 5);
} else if (spellid == OT_S_CREATEMONSTER) { } else if (spellid == OT_S_CREATEMONSTER) {
lifeform_t *newlf; lifeform_t *newlf;
race_t *r = NULL; race_t *r = NULL;
@ -5081,7 +5086,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (cansee(player, c2->lf)) { if (cansee(player, c2->lf)) {
char lfname[BUFLEN]; char lfname[BUFLEN];
getlfname(c2->lf, lfname); getlfname(c2->lf, lfname);
msg("%s %s showed with debris!", lfname, isplayer(c2->lf) ? "are" : "is"); msg("%s %s showered with debris!", lfname, isplayer(c2->lf) ? "are" : "is");
} }
losehp(c2->lf, rnd(2,6), DT_PROJECTILE, NULL, "flying debris"); losehp(c2->lf, rnd(2,6), DT_PROJECTILE, NULL, "flying debris");
} }
@ -5381,7 +5386,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} }
// destroy objects right away // destroy objects right away
removedeadobs(targcell->obpile); if (removedeadobs(targcell->obpile)) {
if (isplayer(caster)) angergodmaybe(R_GODNATURE, 20, GA_ATTACKOBJECT);
}
// explosion, based on size... // explosion, based on size...
if (totalmass > 0) { if (totalmass > 0) {
@ -5702,6 +5709,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("A huge pool of water appears!"); msg("A huge pool of water appears!");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
if (isplayer(caster)) pleasegodmaybe(R_GODNATURE, 5);
} else { } else {
failed = B_TRUE; failed = B_TRUE;
} }
@ -6102,13 +6110,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f->val[0] = 30 + (power/2); f->val[0] = 30 + (power/2);
f->val[1] = B_FALSE; // struggling doesn't damage the vine f->val[1] = B_FALSE; // struggling doesn't damage the vine
} }
/// remmeber creator. if they don't have los to us, spell if (caster) {
// is broken and vines will vanish. /// remmeber creator. if they don't have los to us, spell
setobcreatedby(o, caster); // is broken and vines will vanish.
setobcreatedby(o, caster);
}
} else if (spellid == OT_S_EXCAVATE) { } else if (spellid == OT_S_EXCAVATE) {
cell_t *retcell[MAXRETCELLS],*c; cell_t *retcell[MAXRETCELLS],*c;
int nretcells,i,radius,seenwalls = 0, seenobs = 0; int nretcells,i,radius,seenwalls = 0, seenobs = 0;
int killedobs = 0;
radius = power; radius = power;
limit(&radius, 3, NA); limit(&radius, 3, NA);
getradiuscells(caster->cell, radius, DT_ORTH, B_FALSE, LOF_DONTNEED, B_FALSE, retcell, &nretcells, 0); getradiuscells(caster->cell, radius, DT_ORTH, B_FALSE, LOF_DONTNEED, B_FALSE, retcell, &nretcells, 0);
@ -6127,6 +6137,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
killob(o); killob(o);
addobfast(c->obpile, OT_ASH); addobfast(c->obpile, OT_ASH);
if (haslos(player, c)) seenobs++; if (haslos(player, c)) seenobs++;
killedobs++;
} }
} }
} }
@ -6134,6 +6145,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("A shockwave of destructive force rips through the air!"); msg("A shockwave of destructive force rips through the air!");
setlosdirty(player); setlosdirty(player);
} }
if (isplayer(caster) && killedobs) {
angergodmaybe(R_GODNATURE, 10*killedobs, GA_ATTACKOBJECT);
}
} else if (spellid == OT_S_FLIGHT) { } else if (spellid == OT_S_FLIGHT) {
flag_t *f; flag_t *f;
// always targetted at caster // always targetted at caster
@ -6354,7 +6368,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_HAILSTORM) { } else if (spellid == OT_S_HAILSTORM) {
int failed = B_FALSE; int failed = B_FALSE;
if (isoutdoors(caster->cell->map)) { if (caster && isoutdoors(caster->cell->map)) {
power += 3; power += 3;
limit(&power, NA, 10); limit(&power, NA, 10);
} }
@ -7439,9 +7453,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
poison(target, power*3, P_VENOM, (power/4)+1, "a glob of venom"); poison(target, power*3, P_VENOM, (power/4)+1, "a glob of venom");
} }
} }
} else {
damageallobs(NULL, targcell->obpile, 0, DT_FIRE);
} }
if (isplayer(caster)) god_usepoison_response();
} else if (spellid == OT_S_POSSESSION) { } else if (spellid == OT_S_POSSESSION) {
char targname[BUFLEN]; char targname[BUFLEN];
@ -8461,12 +8474,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f->obfrom = OT_S_PASSWALL; f->obfrom = OT_S_PASSWALL;
breakgrabs(target, B_TRUE, B_TRUE); breakgrabs(target, B_TRUE, B_TRUE);
} else if (spellid == OT_S_POLYMORPH) { } else if ((spellid == OT_S_POLYMORPH) || (spellid == OT_S_SHAPESHIFT)) {
race_t *r = NULL; race_t *r = NULL;
target = targcell->lf;
if (frompot) { if (frompot || (spellid == OT_S_SHAPESHIFT)) {
caster = target; target = caster;
} else {
target = targcell->lf;
} }
if (!target) { if (!target) {
@ -8474,63 +8488,109 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE; return B_TRUE;
} }
if ((target != caster) && spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) { if (spellid != OT_S_SHAPESHIFT) {
if (isplayer(target)) { if ((target != caster) && spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
msg("You feel momentarily different."); if (isplayer(target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE; msg("You feel momentarily different.");
} else if (haslos(player, target->cell)) { if (seenbyplayer) *seenbyplayer = B_TRUE;
getlfname(target, buf); } else if (haslos(player, target->cell)) {
msg("%s looks momentarily different.", buf); getlfname(target, buf);
if (seenbyplayer) *seenbyplayer = B_TRUE; msg("%s looks momentarily different.", buf);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
} }
return B_FALSE;
} }
if ((caster == target) && getforcedspellrace(caster, spellid, buf)) { //if ((caster == target) && getforcedspellrace(caster, spellid, buf)) {
if (caster && getforcedspellrace(caster, spellid, buf)) {
r = findracebyname(buf); r = findracebyname(buf);
} else { } else {
if (lfhasflag(caster, F_CONTROL)) { if (spellid == OT_S_POLYMORPH) {
if (power < 5) { if (lfhasflag(caster, F_CONTROL)) {
power = 5; if (power < 5) {
power = 5;
}
}
if (isplayer(caster) && (power >= 5)) {
if (isplayer(target)) { // ie. polymorphing yourself
askstring("What will you become", '?', buf, BUFLEN, NULL);
} else {
char buf2[BUFLEN];
char targname[BUFLEN];
getlfname(target, targname);
snprintf(buf2, BUFLEN, "What will you transform %s into", targname);
askstring(buf2, '?', buf, BUFLEN, NULL);
}
r = findracebyname(buf);
} else { // random
if (isplayer(target) && lfhasflag(target, F_CONTROL)) {
askstring("What will you become", '?', buf, BUFLEN, NULL);
r = findracebyname(buf);
// make sure race is valid:
if (r && !canpolymorphto(r->id)) r = NULL;
}
if (!r) {
// random race, but not the same!
r = target->race;
while ((r == target->race) || !canpolymorphto(r->id)) {
r = getrandomrace(NULL, NA);
}
}
}
} else if (spellid == OT_S_SHAPESHIFT) {
int i,ch = 'a';
// get list of all lfs in sight
initprompt(&prompt, "What will you become?");
for (i = 0; i < target->nlos; i++) {
if (target->los[i]->lf && cansee(target, target->los[i]->lf)) {
race_t *potrace;
int n;
potrace = target->los[i]->lf->race;
// same race?
if (potrace == target->race) continue;
// too powerful?
if (gethitdicerace(potrace) > power) {
continue;
}
// already in the list?
for (n = 0; n < prompt.nchoices; n++) {
if (prompt.choice[n].data == potrace) {
continue;
}
}
addchoice(&prompt, ch++, potrace->name, NULL, potrace, NULL);
}
}
addchoice(&prompt, '-', "(cancel)", NULL, NULL, NULL);
prompt.maycancel = B_TRUE;
if (prompt.nchoices == 1) {
if (isplayer(caster)) {
msg("You cannot see any forms to copy!");
} else {
fizzle(caster);
}
return B_TRUE;
} else {
if (isplayer(caster)) {
getchoice(&prompt);
r = (race_t *)prompt.result;
} else {
r = (race_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data;
}
} }
} }
if (isplayer(caster) && (power >= 5)) { // make sure race is valid:
if (isplayer(target)) { // ie. polymorphing yourself // - can't turn into monsters which aren't randomly generated.
askstring("What will you become", '?', buf, BUFLEN, NULL); // - can't turn into unique monsters
} else { // - can't turn into undead monsters
char buf2[BUFLEN]; if (r && !canpolymorphto(r->id) && !hasjob(caster, J_GOD)) {
char targname[BUFLEN]; if (isplayer(caster)) msg("As you think of a %s, magic energy dampens around you.", r->name);
getlfname(target, targname); r = NULL;
snprintf(buf2, BUFLEN, "What will you transform %s into", targname);
askstring(buf2, '?', buf, BUFLEN, NULL);
}
r = findracebyname(buf);
// make sure race is valid:
// - can't turn into monsters which aren't randomly generated.
// - can't turn into unique monsters
// - can't turn into undead monsters
if (r && !canpolymorphto(r->id) && !hasjob(caster, J_GOD)) {
if (isplayer(caster)) msg("As you think of a %s, magic energy dampens around you.", r->name);
r = NULL;
}
} else { // random
if (isplayer(target) && lfhasflag(target, F_CONTROL)) {
askstring("What will you become", '?', buf, BUFLEN, NULL);
r = findracebyname(buf);
// make sure race is valid:
if (r && !canpolymorphto(r->id)) r = NULL;
}
if (!r) {
// random race, but not the same!
r = target->race;
while ((r == target->race) || !canpolymorphto(r->id)) {
r = getrandomrace(NULL, NA);
}
}
} }
} // end if forcepoly } // end if forcepoly
@ -8564,8 +8624,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
setrace(target, r->id, B_TRUE); setrace(target, r->id, B_TRUE);
// if someone cast the spell at themself and it's controlled, they can change back at will. // if someone cast the spell at themself and it's controlled, they can change back at will.
if ((target == caster) && (power >= 5)) { if (target == caster) {
addflag(target->flags, F_CANWILL, OT_A_POLYREVERT, NA, NA, NULL); int canrevert = B_FALSE;
if ((spellid == OT_S_POLYMORPH) && (power >= 5)) {
canrevert = B_TRUE;
} else if (spellid == OT_S_SHAPESHIFT) {
canrevert = B_TRUE;
}
if (canrevert) {
addflag(target->flags, F_CANWILL, OT_A_POLYREVERT, NA, NA, NULL);
}
} }
if (haslos(player, target->cell)) { if (haslos(player, target->cell)) {
@ -8577,59 +8645,69 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE; return B_TRUE;
} }
} else if (spellid == OT_S_PURIFYFOOD) { } else if (spellid == OT_S_PURIFYFOOD) {
object_t *o; object_t *o,*nexto;
int ndone = 0;
if (targob) { if (!target) {
o = targob; target = caster;
} else {
// ask for an object
o = askobject(caster->pack, "Purify what?", NULL, '\0', AO_EDIBLE | AO_DRINKABLE);
} }
if (!o) { if (!o) {
fizzle(caster); fizzle(caster);
return B_TRUE; return B_TRUE;
} }
if (isplayer(caster)) { for (o = target->pack->first ; o ; o = nexto) {
char obname[BUFLEN]; char obname[BUFLEN];
flag_t *f;
int donesomething = B_FALSE; int donesomething = B_FALSE;
flag_t *f;
nexto = o->next;
getobname(o, obname, o->amt); getobname(o, obname, o->amt);
if (o->type->id == OT_POT_POISON) { if (o->type->id == OT_POT_POISON) {
msg("Your %s sparkles for a while.", noprefix(obname)); if (isplayer(target)) {
makeknown(o->type->id); // you now know that it was poison. msg("Your %s sparkles for a while.", noprefix(obname));
makeknown(o->type->id); // you now know that it was poison.
}
o->type = findot(OT_POT_WATER); o->type = findot(OT_POT_WATER);
makeknown(o->type->id); // you now know what water is too. if (isplayer(target)) {
makeknown(o->type->id); // you now know what water is too.
}
donesomething = B_TRUE; donesomething = B_TRUE;
ndone++;
} else { } else {
f = hasflag(o->flags, F_OBHP); f = hasflag(o->flags, F_OBHP);
if (f) { if (f) {
f->val[0] = f->val[1]; f->val[0] = f->val[1];
f = hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL); f = hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL);
if (f) killflag(f); if (f) {
donesomething = B_TRUE; killflag(f);
donesomething = B_TRUE;
ndone++;
}
} }
if (killflagsofid(o->flags, F_TAINTED)) { if (killflagsofid(o->flags, F_TAINTED)) {
donesomething = B_TRUE; donesomething = B_TRUE;
ndone++;
} }
} }
if (donesomething) { if (donesomething) {
if (isdrinkable(o)) { if (isplayer(target)) {
msg("Your %s looks more clean now.", noprefix(obname)); if (isdrinkable(o)) {
} else { msg("Your %s looks more clean now.", noprefix(obname));
msg("Your %s looks more fresh now.", noprefix(obname)); } else {
msg("Your %s looks more fresh now.", noprefix(obname));
}
if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else {
nothinghappens();
return B_TRUE;
} }
} else { }
// monsters can't purify things!
if (!ndone) {
fizzle(caster);
return B_TRUE;
} }
} else if (spellid == OT_S_PYROMANIA) { } else if (spellid == OT_S_PYROMANIA) {
int i,donesomething = B_FALSE; int i,donesomething = B_FALSE;
@ -10308,8 +10386,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("A wall of ice appears!"); msg("A wall of ice appears!");
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
if (isplayer(caster)) pleasegodmaybe(R_GODNATURE, 5);
} else if (spellid == OT_S_WATERJET) { } else if (spellid == OT_S_WATERJET) {
char lfname[BUFLEN]; char lfname[BUFLEN];
cell_t *retcell[MAXRETCELLS]; cell_t *retcell[MAXRETCELLS];
@ -10517,7 +10594,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = addtempflag(caster->flags, F_WINDSHIELD, power, NA, NA, NULL, FROMSPELL); f = addtempflag(caster->flags, F_WINDSHIELD, power, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid; f->obfrom = spellid;
} else if (spellid == OT_S_WISHLIMITED) { } else if (spellid == OT_S_WISHLIMITED) {
object_t *o; object_t *o = NULL;
char obname[BUFLEN]; char obname[BUFLEN];
char ch; char ch;
if (!target) target = caster; if (!target) target = caster;
@ -10707,6 +10784,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (isplayer(target)) { if (isplayer(target)) {
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
if (o && isplayer(caster)) pleasegodmaybe(R_GODNATURE, 5);
} else if ((spellid == OT_S_WISH) || (spellid == OT_S_GIFT)) { } else if ((spellid == OT_S_WISH) || (spellid == OT_S_GIFT)) {
object_t *o; object_t *o;
if (isplayer(caster)) { if (isplayer(caster)) {
@ -10732,6 +10810,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
askstring(question, '?', buf, BUFLEN, NULL); askstring(question, '?', buf, BUFLEN, NULL);
addob(target->cell->obpile, buf); addob(target->cell->obpile, buf);
if (nretobs) { if (nretobs) {
int ncreated = 0;
for (i = 0; i < nretobs; i++) { for (i = 0; i < nretobs; i++) {
char obname[BUFLEN]; char obname[BUFLEN];
o = retobs[i]; o = retobs[i];
@ -10744,6 +10823,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else { } else {
msg("%s is gifted with %s.", lfname, obname); msg("%s is gifted with %s.", lfname, obname);
} }
ncreated++;
} else { } else {
// can't pick this up... // can't pick this up...
@ -10759,6 +10839,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!isblind(caster)) { if (!isblind(caster)) {
msg("%s appear%s on the ground!", obname, OBS1(o)); msg("%s appear%s on the ground!", obname, OBS1(o));
} }
ncreated++;
} else { } else {
// ob exists but couldn't make it appear // ob exists but couldn't make it appear
msg("The air in front of %s seems to ripple for a moment.", lfname); msg("The air in front of %s seems to ripple for a moment.", lfname);
@ -10766,6 +10847,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} }
} }
if (ncreated) {
if (isplayer(caster)) pleasegodmaybe(R_GODNATURE, 10);
}
} else { } else {
// couldn't make it appear - ob doesn't exist // couldn't make it appear - ob doesn't exist
msg("The air in front of %s seems to ripple for a while.", lfname); msg("The air in front of %s seems to ripple for a while.", lfname);