From 067cd92f378d4eb0c5192e009b3590031677b39b Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Fri, 17 Feb 2012 05:16:45 +0000 Subject: [PATCH] - [+] delvers should always want money for info, unless you are a delver too. - [+] mirror image (mental) - [+] varpower - [+] makes power 'clone' lfs who look the same as caster - [+] ie. same race. - [+] also same job/armour/weps? - [+] add f_noxp - [+] add f_nocorpse - [+] add f_summonedby so they vanish when the caster dies - [+] add f_phantasm - [+] vanish after _power_ hits, - [+] attacks do 0 damage - [+] don't announce innefectual attacks - [+] dont cast spells or use abilities - [+] petify() them if made by the player - [+] force them to stay close. - [+] in io.c or getlfname, show "[clone]" if it has f_phantasm and was created by player - [+] mosnters try to attack them. - [+] once one gets hit enough times, it disappears - [+] if the caster dies or changes level, they disappear. - [+] can't talk to them - [+] their obejcts vanish when they die - [+] don't talk - [+] make Yumi more about forgiving silly mistakes and avoiding instakills - [+] remove liking of healing - [+] remove like of healing spells - [+] takes a long time to anger. - [+] aviod traps (bamf you away before they trigger) - [+] prayers: - [+] resist stoning (pray while appropriate creatures around) - [+] resist paralysis (pray while appropriate creatures around) - [+] sleep on enemies - [+] passive powers: - [+] always warn as if wisdom is high (passive) - [+] always save when killed right after using stairs (passive) "well, that seemed unfair." - [+] gift: - [+] auto sixth sense - [+] potions of restoration - [+] ring of miracles - [+] shouldn't be able to Offer while enraged. - [+] don't lose stamina while caffeinated - [+] new vault: pit with walkway around it - [+] bug: when worshipping yumi you get "you kill xxx" but they're still alive - [+] ... but they're still alive! - [+] ... for yumi, move KO chance from losehp() to attacklf(). - [+] do the check BEFORE setting 'fatal' - [+] pass forceko to losehp_real - [+] bug: adjustdamhardness should only trigger when ismeleedam() is true, not isphysicaldam() - [+] greatly reduce motel cost - [+] change order in attack.c: apply damage THEN announce, to deal with KO - [+] do it. - [+] test KO code. - [+] then check that feign death still works - [+] demonskin vest should be flammable or vulnerable to fire. - [+] time to get up should depend on size. - [+] less than human: shortnone - [+] human: normal - [+] larger than human: longer - [+] expert unarmed now gives you 'flip' - [+] reduce damage done by low-level monsters - [+] change resoration into a spell - [+] implement - [+] test - [+] new spell: ressurection - [+] corpses need to remember their lf's level - [+] test - [+] godstone of life - revives/restores all - [+] rename "confiscate" to "yoink", and make it take a random object at power 1, selected at power 2 - [+] gods should attack player if they are Enraged or Furious - [+] is STR calc to see if you can push a boulder still working? - [+] change to wizards: - [+] start at novice in all magic skills (but don't gain initial spells) - [+] killing undead should please glorana LOTS. because it's hard to gain piety with her otherwise. - [+] restoration spells/potion should hurt undead - [+] healing spells/potions should hurt undead - [+] immolate shouldnt work if there is aleady a fire tehre. CODE FOR WINNING THE GAME: - [+] get at least one godstone - [+] exit the dungeon - [+] find the portal to the realm of gods - [+] opposing god should appear once you pick up a godstone, and tell you what to do next. - [+] "come to the realm of gods and use it to destroy (related god)" - [+] "or if you lack the courage, give it to me!" - [+] "you will find a portal on the surface" - [+] use the portal to teleport to realm of gods - [+] implement text for all gods... - [+] god text in wt_god - should say 'but you werent meant to replace them!' - [+] EITHER: - [+] challenge and defeat the god related to this godstone (more points. "Crowned the god of xxx.") - [+] TEST - [+] offer the godstone to the godstone's opposing god (less points, "Ascended to demigod-hood.") - [+] implement - [+] TEST GODSTONES: - [+] klikirak: rage - [+] done - [+] (make this one have fire effects too) - [+] glorana: life - [+] Felix shouldn't be able to yoink the godstone off you! - [+] Write up the rest of the Godstone finding text..... - [+] magic - [+] battle - [+] life - [+] mercy - [+] you can't hurt gods unless you - [+] a) have their godstone - [+] b) are in the realm of gods --- ai.c | 21 ++- attack.c | 134 +++++++++------ data.c | 106 ++++++++---- data/hiscores.db | Bin 13312 -> 13312 bytes defs.h | 23 +++ flag.c | 4 +- god.c | 259 ++++++++++++++++++++++++++++- god.h | 4 + io.c | 411 +++++++++++++++++++++++++++++++++++++++++++--- io.h | 3 +- lf.c | 333 +++++++++++++++++++++++++++++++------- lf.h | 5 +- move.c | 31 +++- nexus.c | 8 +- objects.c | 87 +++++----- shops.c | 8 +- spell.c | 413 +++++++++++++++++++++++++++++++++++++---------- text.c | 28 +++- 18 files changed, 1566 insertions(+), 312 deletions(-) diff --git a/ai.c b/ai.c index 998e895..41ecdb6 100644 --- a/ai.c +++ b/ai.c @@ -160,6 +160,10 @@ enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) { if (db) { dblog(".oO { looking for attack spells/abils }"); } + if (lfhasflag(lf, F_PHANTASM)) { + if (db) dblog(".oO { no attack spell because i am a phantasm }"); + return OT_NONE; + } f = lfhasflag(lf, F_NEEDOBFORSPELLS); @@ -222,6 +226,11 @@ enum OBTYPE aigetfleespell(lifeform_t *lf) { db = B_TRUE; } + if (lfhasflag(lf, F_PHANTASM)) { + if (db) dblog(".oO { no flee spell because i am a phantasm }"); + return OT_NONE; + } + f = lfhasflag(lf, F_FLEEFROM); if (f) { fleefrom = findlf(lf->cell->map, f->val[0]); @@ -788,7 +797,15 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) { if (pctchance(chance)) { flag_t *f; - if (lfhasflag(lf, F_HATESALL) || lfhasflag(lf, F_RAGE)) { + if ((getraceclass(lf) == RC_GOD) && + (getpietylev(lf->race->id, NULL, NULL) <= PL_FURIOUS) && + isplayer(who)) { + if (nhateposs < MAXCANDIDATES) { + if (db) dblog(".oO { i am an angry god - found player lfid %d (%s) ! }", + who->id, who->race->name); + hateposs[nhateposs++] = who; + } + } else if (lfhasflag(lf, F_HATESALL) || lfhasflag(lf, F_RAGE)) { if (nhateposs < MAXCANDIDATES) { if (db) dblog(".oO { hate everything - found lfid %d (%s) ! }",who->id, who->race->name); hateposs[nhateposs++] = who; @@ -863,7 +880,7 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) { } else { // god with no targets? if (lf->race->raceclass->id == RC_GOD) { - if (onein(6) && (lf->cell->map->habitat->id != H_HEAVEN)) { + if (onein(3) && (lf->cell->map->habitat->id != H_HEAVEN)) { if (db) dblog(".oO { planeshifting home }"); // gods will planeshift away if (!castspell(lf, OT_S_PLANESHIFT, lf, NULL, lf->cell, NULL, NULL)) { diff --git a/attack.c b/attack.c index 20c54a1..42e5592 100644 --- a/attack.c +++ b/attack.c @@ -585,6 +585,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) char attackername[BUFLEN]; char victimname[BUFLEN],victimbpname[BUFLEN]; int fatal = B_FALSE; + int waskod = B_FALSE; int feigneddeath = B_FALSE; int deflected = B_FALSE; int weppassthrough = B_FALSE; @@ -737,7 +738,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) hit = rolltohit(lf, victim, wep, &critical); - if (critical) { + if (critical && !lfhasflag(lf, F_PHANTASM)) { object_t *armour; char noun[BUFLEN]; critpos = getrandomcorebp(victim, lf); @@ -885,6 +886,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) dam[0] = (int) ( (float)dam[0] + loreadd ); } + if (lfhasflag(lf, F_PHANTASM)) { + dam[0] = 0; + if (aidb) dblog(".oO { adjusting phantasm dam to 0 }"); + } + if (aidb) dblog(".oO { dealing %d %s damage }", dam[0], getdamname(damtype[0])); ndam = 1; @@ -956,6 +962,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) adjustdamlf(victim, &dam[i], damtype[i]); //dblog("adjusted for lf to dam[%d] = %d",i,dam[i]); + if (lfhasflag(lf, F_PHANTASM)) dam[0] = 0; + // armour doesn't reduce damage for backstabs or critical hits. // BUT in the case of a critical hit, the armour might get // damaged during criticalhit() @@ -976,16 +984,22 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (lfhasflag(lf, F_QUIVERINGPALM)) { // make sure damage isn't fatal + // becquse we want them to explode if (dam[i] >= victim->hp) { dam[i] = victim->hp - 1; } } - // will this hit be fatal? + // at this point, will the damage be fatal? we need to know so we + // can determine whether monsters will use feign death ability. + // NOTE: whether or not the atatck is fatal is re-calculated again + // later on after damage is applied to ensure that the correct + // attack string is displayed ("you hit xxx" vs "you kill xxx"). if (dam[i] >= victim->hp) { fatal = B_TRUE; } + if (lfhasflag(lf, F_PHANTASM)) dam[0] = 0; // monsters feigning death? if (lfhasflag(victim, F_FEIGNINGDEATH)) { @@ -998,30 +1012,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } - // announce it - if (!feigneddeath) { - if (isplayer(lf) || isplayer(victim) || cansee(player, lf) || cansee(player, victim)) { - construct_hit_string(lf, victim, attackername, victimname, victimbpname, wep, damtype[i], dam[i], victim->maxhp, i, backstab, critical, fatal, isunarmed, buf); - if (strlen(buf)) { - warn("%s", buf); - } - } - //if (!isplayer(lf) && !isplayer(victim)) { - noise(lf->cell, lf, NC_FIGHTING, SV_SHOUT, "fighting.", NULL); - //} - if (fatal) { - if (strstr(buf, "behead")) { - // we'll need to place the severed head object - addflag(victim->flags, F_BEHEADED, B_TRUE, NA, NA, NULL); - } - if ((isplayer(lf) || cansee(player, victim)) && !hasflag(victim->flags, F_NODEATHANNOUNCE)) { - // don't also say "the xx dies" - addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); - } - } - } - - if (willheal) { if (cansee(player, victim)) { flag_t *f; @@ -1034,11 +1024,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (f) { f->known = B_TRUE; } - gainhp(victim, dam[i]); } + gainhp(victim, dam[i]); + reduceamt = 0; } else if (lfhasflag(lf, F_QUIVERINGPALM)) { // victim explodes! - losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE, NULL, B_FALSE); + losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE, NULL, B_FALSE, NULL); + reduceamt = 0; } else { char attackername2[BUFLEN]; real_getlfname(lf, attackername2, B_FALSE, B_TRUE); @@ -1067,21 +1059,58 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } else { strcpy(buf, attackername2); } - losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE, wep, B_FALSE); - - // victim's armour loses hp - if (reduceamt && !critical) { - applyarmourdamage(victim, wep, dam[i], damtype[i], lf); - // train armour - practice(victim, SK_ARMOUR, 1); + losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE, wep, B_FALSE, &waskod); + } + // was it fatal ? override previously calculated value. + if ((victim->hp <= 0) && !waskod) { + fatal = B_TRUE; + } else { + fatal = B_FALSE; + } + // announce it + if (!feigneddeath) { + if (isplayer(lf) || isplayer(victim) || cansee(player, lf) || cansee(player, victim)) { + construct_hit_string(lf, victim, attackername, victimname, victimbpname, wep, damtype[i], dam[i], victim->maxhp, i, backstab, critical, fatal, isunarmed, buf); + if (strlen(buf)) { + warn("%s", buf); + } } - if (backstab) { - practice(lf, SK_BACKSTAB, 1); + //if (!isplayer(lf) && !isplayer(victim)) { + //} + if (fatal) { + if (strstr(buf, "behead")) { + // we'll need to place the severed head object + addflag(victim->flags, F_BEHEADED, B_TRUE, NA, NA, NULL); + } + if ((isplayer(lf) || cansee(player, victim)) && !hasflag(victim->flags, F_NODEATHANNOUNCE)) { + if (!hasflag(victim->flags, F_PHANTASM)) { + // don't also say "the xx dies" + addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); + } + } } } + + // make noise + noise(lf->cell, lf, NC_FIGHTING, SV_SHOUT, "fighting.", NULL); + + // victim's armour loses hp + if (reduceamt && !critical) { + applyarmourdamage(victim, wep, dam[i], damtype[i], lf); + // train armour + practice(victim, SK_ARMOUR, 1); + } + if (backstab) { + practice(lf, SK_BACKSTAB, 1); + } + if (fatal || waskod) break; // stop now! } // end foreach damtype + if (waskod) { + loseconsciousness(victim, waskod, lf); + } + // other effects if (!isdead(victim) && !blocked) { // special weapon effects, as long as you're not doing a heavy blow @@ -1112,7 +1141,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) char lfname[BUFLEN]; dam = rolldie(f->val[0], f->val[1]) + f->val[2]; real_getlfname(lf, lfname, B_FALSE, B_FALSE); - losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE, NULL, B_FALSE); + losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE, NULL, B_FALSE, NULL); if (isplayer(victim) || cansee(player, victim)) { msg("^%c%s bites %s!", isplayer(victim) ? 'b' : 'n', lfname, victimname); } @@ -1138,7 +1167,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (nmatched >= f->val[2]) { char damstring[BUFLEN]; snprintf(damstring, BUFLEN, "%s pack", lfname); - losehp_real(victim, f->val[0], f->val[1], lf, damstring, B_TRUE, NULL, B_FALSE); + losehp_real(victim, f->val[0], f->val[1], lf, damstring, B_TRUE, NULL, B_FALSE, NULL); if (isplayer(victim) || cansee(player, victim)) { msg("^%c%s pack attacks %s!", isplayer(victim) ? 'b' : 'c', lfname, victimname); } @@ -1208,7 +1237,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) attackername); } snprintf(damstring, BUFLEN, "%s%s %s", victimname, getpossessive(victimname), noprefix(f->text)); - losehp_real(lf, rdam, f->val[2], victim, damstring, B_TRUE, NULL, B_TRUE); + losehp_real(lf, rdam, f->val[2], victim, damstring, B_TRUE, NULL, B_TRUE, NULL); } } } @@ -1492,7 +1521,6 @@ int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag) { enum DAMTYPE damtype[100]; int ndam = 0; char attackername[BUFLEN]; - char obname[BUFLEN]; int isunarmed = B_FALSE; char buf[BUFLEN]; int i; @@ -1530,8 +1558,10 @@ int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag) { for (i = 0; i < ndam; i++) { + char cellname[BUFLEN]; + sprintf(cellname, "%s %s", needan(c->type->name) ? "an" : "a", c->type->name); // announce the hit - construct_hit_string(lf, NULL, attackername, c->type->name, NULL, wep, damtype[i], dam[i], maxhp, i, B_FALSE, B_FALSE, B_FALSE, isunarmed, buf); + construct_hit_string(lf, NULL, attackername, cellname, NULL, wep, damtype[i], dam[i], maxhp, i, B_FALSE, B_FALSE, B_FALSE, isunarmed, buf); if (strlen(buf)) { msg("%s", buf); @@ -1587,7 +1617,7 @@ int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag) { // ok } else { char buf[BUFLEN]; - snprintf(buf, BUFLEN, "punching %s", obname); + snprintf(buf, BUFLEN, "punching %s", cellname); if ( losehp(lf, 1, DT_BASH, lf, buf)) { if (isplayer(lf)) { msg("^bOw!"); @@ -1929,6 +1959,11 @@ int getextradamlf(lifeform_t *lf, int *dam, enum DAMTYPE *damtype, int *ndam) { int i; flag_t *retflag[MAXCANDIDATES]; int nretflags = 0; + + if (lf && lfhasflag(lf, F_PHANTASM)) { + return *dam; + } + // special case - EXTRADAM goes onto INITIAL dam[] if the same type, rather than // adding a new one. getflags(lf->flags, retflag, &nretflags, F_EXTRADAM, F_NONE); @@ -1982,6 +2017,11 @@ int getextradamwep(object_t *wep, int *dam, enum DAMTYPE *damtype, int *ndam) { lifeform_t *owner; owner = wep->pile->owner; + if (owner && lfhasflag(owner, F_PHANTASM)) { + return *dam; + } + + // enchanted weapons only deal magic damage if the user has remaining mp. if (owner && owner->mp) { f = hasflag(wep->flags, F_ENCHANTED); @@ -2066,6 +2106,12 @@ int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag) { int dam; int bonusdam = 0; flag_t *f; + lifeform_t *owner; + owner = o->pile->owner; + + if (owner && lfhasflag(owner, F_PHANTASM)) { + return 0; + } if (damflag) { int min,max; @@ -2096,8 +2142,6 @@ int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag) { // special effects ? f = hasflag(o->flags, F_BALANCE); if (f) { - lifeform_t *owner; - owner = o->pile->owner; if (owner && victim) { float ratio; ratio = (float)owner->maxhp / (float)victim->maxhp; diff --git a/data.c b/data.c index ad1eadf..59d2322 100644 --- a/data.c +++ b/data.c @@ -829,6 +829,17 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_AIR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DEATH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_ENCHANTMENT, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_FIRE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_COLD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_GRAVITY, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_MODIFICATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_TRANSLOCATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_WILD, PR_NOVICE, NA, NULL); // learnable skills addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); @@ -838,17 +849,6 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); // limit addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_AIR, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_DEATH, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_DIVINATION, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_ENCHANTMENT, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_FIRE, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_COLD, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_GRAVITY, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_MODIFICATION, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_SUMMONING, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_TRANSLOCATION, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SS_WILD, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LORE_DEMONS, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LORE_UNDEAD, NA, NA, NULL); @@ -1655,7 +1655,7 @@ void initobjects(void) { addflag(lastot->flags, F_REPELBLESSED, B_BLESSED, B_CURSED, NA, NULL); addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); - addot(OT_PORTAL, "magic portal", "A magical portal to a different place...", MT_MAGIC, 0, OC_DFEATURE, SZ_LARGE); + addot(OT_PORTAL, "magic portal", "A magical portal to a different place...", MT_MAGIC, 0, OC_EFFECT, SZ_LARGE); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_VERYRARE, NULL); addflag(lastot->flags, F_GLYPH, C_BOLDGREEN, '^', NA, NULL); addflag(lastot->flags, F_CLIMBABLE, D_IN, NA, NA, "portal"); @@ -2058,6 +2058,8 @@ void initobjects(void) { addflag(lastot->flags, F_RECHARGE, 1, NA, NA, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_LINKGOD, R_GODPURITY, NA, NA, NULL); + addot(OT_GODSTONER, "Godstone of Rage", "An ancient artifact representing the power of anger.", MT_STONE, 3, OC_GODSTONE, SZ_SMALL); addflag(lastot->flags, F_GLYPH, C_RED, '*', NA, NULL); addflag(lastot->flags, F_VALUE, 1000, NA, NA, NULL); @@ -2065,6 +2067,17 @@ void initobjects(void) { addflag(lastot->flags, F_RECHARGE, 1, NA, NA, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_LINKGOD, R_GODFIRE, NA, NA, NULL); + + addot(OT_GODSTONEL, "Godstone of Life", "An ancient artifact representing the power of life.", MT_STONE, 3, OC_GODSTONE, SZ_SMALL); + addflag(lastot->flags, F_GLYPH, C_WHITE, '*', NA, NULL); + addflag(lastot->flags, F_VALUE, 1000, NA, NA, NULL); + addflag(lastot->flags, F_CHARGES, 100, 100, NA, NULL); + addflag(lastot->flags, F_RECHARGE, 1, NA, NA, NULL); + addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_LINKGOD, R_GODLIFE, NA, NA, NULL); + // flora addot(OT_FLOWER, "flower", "A colourful woodland flower.", MT_PLANT, 0.01, OC_FLORA, SZ_TINY); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_FREQUENT, ""); @@ -2333,7 +2346,7 @@ void initobjects(void) { addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "2d4"); addflag(lastot->flags, F_VALUE, 15, NA, NA, NULL); - addot(OT_POT_COFFEE, "potion of coffee", "A caffeinated beverage prepared from coffee beans.", MT_GLASS, 1, OC_POTION, SZ_TINY); + addot(OT_POT_COFFEE, "potion of coffee", "A caffeinated beverage prepared from coffee beans. Prevents your stamina from decreasing, but also prevents you from sleeping.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_VALUE, 10, NA, NA, NULL); addot(OT_POT_RUM, "potion of rum", "Strong liqour which is sure to make you tipsy. This will make you unsteady and lower your accuracy, but also let you ignore pain, minor damage, and many mental attacks.", MT_GLASS, 1, OC_POTION, SZ_TINY); @@ -2595,6 +2608,10 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MPCOST, 0, NA, NA, NULL); // l2 + addot(OT_S_ALCHEMY, "alchemy", "Converts any metal item into (^bpower * 10^n)% of its value in gold.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); addot(OT_S_PULLMETAL, "pull metal", "Pulls metal objects to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -3538,6 +3555,21 @@ void initobjects(void) { addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + // l5 + addot(OT_S_RESTORATION, "restoration", "Restore nearly all the target's HP and MP, and remove almost all negative status effects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 3, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_ALLY, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + // l6 + addot(OT_S_RESSURECTION, "ressurection", "Restore one adjacent corpse to life.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); + addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_OBJECT, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// // mental/psionic /////////////////// @@ -3581,6 +3613,12 @@ void initobjects(void) { addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_MIRRORIMAGE, "mirror image", "Creates ^bpower^n illusionary clones of the caster to distract enemies. These clones cannot deal damage, and vanish when hit.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how many clones are created, and how many hits they can sustain."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); // l3 addot(OT_S_PSYARMOUR, "psychic armour", "Mentally block incoming attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The psychic armour's Armour Rating is ^bpower*4^n."); @@ -3874,6 +3912,14 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addot(OT_S_CONFISCATE, "yoink", "Transports one random object directly from the target to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level II, the target object can be selected."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 2, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_DISPERSAL, "dispersal", "Scatters everything in the target cell around the area.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability."); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); @@ -3976,12 +4022,7 @@ void initobjects(void) { addot(OT_S_WISHLIMITED, "limited wish", "Grants the caster a wish of their choice. Beware - casting this powerful spell will reduce the caster's hit points by 25%.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL); - addot(OT_S_CONFISCATE, "confiscate", "Takes any object from the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); - addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); - addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + // l6 addot(OT_S_GIFT, "gift", "Grants the target any item of their choice (with some limitations).", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL); @@ -5543,6 +5584,8 @@ void initobjects(void) { addflag(lastot->flags, F_CRITPROTECTION, 33, NA, NA, NULL); addot(OT_ARMOURDEMON, "demonskin vest", "Body armour created by flaying the flesh from a living demon, it retains its innate immunity to fire.", MT_FLESH, 7, OC_ARMOUR, SZ_MEDIUM); + killflagsofid(lastot->flags, F_FLAMMABLE); + killflagsofid(lastot->flags, F_DTVULN); addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); @@ -7825,7 +7868,6 @@ void initrace(void) { addflag(lastrace->flags, F_SACRIFICEOB, OT_CORPSE, NA, 10, "OB explode#S in a shower of sparks!"); addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;"); - addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); // likes/dislikes addflag(lastrace->flags, F_GODPOISON, B_FALSE, 100, NA, NULL); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "destroying the undead"); @@ -7984,7 +8026,6 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANWILL, OT_S_BLINKASS, NA, NA, "pw:10;"); //addflag(lastrace->flags, F_CANWILL, OT_S_HUNGER, NA, NA, "pw:1;"); - addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); // likes/dislikes addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "backstabbing"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "stealing items"); @@ -8076,7 +8117,6 @@ void initrace(void) { } } addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;"); - addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); // likes addflag(lastrace->flags, F_GODPOISON, B_TRUE, 3, NA, NULL); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "killing (especially the good-aligned)"); @@ -8127,7 +8167,7 @@ void initrace(void) { addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "inflicting cold-based damage"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "using cold-based magic"); // sacrifices - addflag(lastrace->flags, F_SACRIFICEOBWITHFLAG, F_FLAMMABLE, NA, 10, "OB IS consumed in a burst of fire!"); + addflag(lastrace->flags, F_SACRIFICEOBWITHFLAG, F_FLAMMABLE, NA, 2, "OB IS consumed in a burst of fire!"); addrace(R_GODMAGIC, "Lumara", 55, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD, "Lumara is the goddess of magic. She appears as a slender elderly woman, her expression wise with age."); setbodytype(lastrace, BT_HUMANOID); @@ -8207,7 +8247,6 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_S_SATEHUNGER, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANWILL, OT_S_DISPERSAL, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANWILL, OT_S_SLEEP, NA, NA, "pw:10;"); - addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); addflag(lastrace->flags, F_GODPOISON, B_FALSE, 25, NA, NULL); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "allowing fleeing creatures to escape"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "knocking enemies unconscious"); @@ -9020,7 +9059,7 @@ void initrace(void) { addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 2, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_AGI, AT_HIGH, NA, NULL); @@ -9912,7 +9951,7 @@ void initrace(void) { addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "snorts^a snort"); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); @@ -10171,7 +10210,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_S_FLIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FLIGHT, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "0d4+2"); - addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 1, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 1, NA, NULL); addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); @@ -10736,7 +10775,8 @@ void initrace(void) { addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_FLEEONDAM, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_DTRESIST, DT_COLD, B_TRUE, NA, NULL); + addflag(lastrace->flags, F_DTRESIST, DT_FIRE, B_TRUE, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_COLD, B_TRUE, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 3, NA, NA, NULL); @@ -12161,7 +12201,7 @@ void initrace(void) { addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 5, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL); addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTOBWEPSK, 50, SK_AXES, NA, NULL); addflag(lastrace->flags, F_STARTOB, 25, NA, NA, "buckler"); @@ -12554,7 +12594,8 @@ void initrace(void) { addflag(r->flags, F_FLEEONHPPCT, 20, NA, NA, NULL); addflag(r->flags, F_RESISTMAG, 15, NA, NA, NULL); addflag(r->flags, F_MEDITATES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); + addflag(r->flags, F_SEEINDARK, 10, NA, NA, NULL); + addflag(r->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); } else if (r->raceclass->id == RC_MAGIC) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_PLANT) { @@ -12566,11 +12607,11 @@ void initrace(void) { addflag(r->flags, F_FLAMMABLE, PERMENANT, NA, NA, NULL); addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_SLIME) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_UNDEAD) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); @@ -12813,6 +12854,7 @@ void initskills(void) { addskill(SK_UNARMED, "Unarmed Combat", "Helps you fight using your bare hands.", 50); addskilldesc(SK_UNARMED, PR_ADEPT, "^gYour unarmed attacks can now smash wooden objects.^n", B_TRUE); addskilldesc(SK_UNARMED, PR_SKILLED, "^gYou can now make melee attacks with your off-hand.^n", B_TRUE); + addskilldesc(SK_UNARMED, PR_EXPERT, "^gYou gain the 'flip' ability.^n", B_FALSE); // spell schools addskill(SK_SS_ALLOMANCY, "Allomancy", "Boosts casting of spells from this school.", 50); diff --git a/data/hiscores.db b/data/hiscores.db index 7c61776d390d4f8f5379edb6e3f3735c624aa2f7..4b603d435d6961d29b0d2bacf73b443fff05befa 100644 GIT binary patch delta 635 zcmZ8dUr1A76hGg0wt08AVYbliy6oGgZkAbVGm02QKD0!7nnpnncRDx8cI$4lh|)C* z49arnA?Ycihk7aM23ap5D1>OxTMrtMKK3LL^b*}&e2Bgee*8Fpe&?KDC11%uX!X?K zpZ6-dhLRH((Tquk+cu95lXz|&#T5%%>6|>xnV&Z0$&eMXD&c;e!#xY{S~!gl!C~BTRcy^p*aFyM z-RusRd6NIYFplCQL)mebv+MM%?Vt@;AZ4tzwKHSIn~-FWxh_Kk&@kk{b8PCbwmN`& z_g|1>x|SK3h|{{)e=L(#bunDd2(2K-vlH2I5f|F1DCM(aq+G~lwL*`FodgLs05+J< zoZinTF^F@xYWT!s#$MCA;BOaZK{LgBlk6>hZVVgWLhbhE23P`EVn>8bmN(RT}EY-t2H{*0l+dDqmC!;>_4JRUe^b zSZUU^QfaJ^6Pa9bxi>BzvSN)T?!src||MTV;CN@eh7KO~x%T7B{rmEdL9lQKJa} delta 496 zcmXYsO=uHg5QgU`S+~0hEk<;SKWq|_#8ygbMFj)W92Bi0R9f`bnAJv>EN){#g>F_9 zD%fiH4)!D>J?K$C!RoDIQ35@9DGDmm^w?7o!Hc-NI)~?FW_aginiI{5hdYyX_*ZHm z_#*$6Rh8QuG)b9=EwaL^knnGb_Ld_!Bv{>tO_5g%_+6Y+bMfQU|3e^B+x478YYk4 z(@)OwDBtBpY@>&L^nnw6jIZ)zUV+}*J>iAkezAJsS2=iUBn-O_v#wJao+_FnmR)yT tbF6lA+^wFj*|t?RD>uw5race->id == R_GODMERCY) dopleasegod[i] += 5; + if (godlf[i] && (godlf[i]->race->id == R_GODMERCY)) dopleasegod[i] += 5; } } } @@ -1062,7 +1062,7 @@ void killflag(flag_t *f) { if (gamemode == GM_GAMESTARTED) { for (i = 0; i < ngodlfs; i++) { - if (dopleasegod[i]) { + if (godlf[i] && dopleasegod[i]) { pleasegodmaybe(godlf[i]->race->id, dopleasegod[i]); } } diff --git a/god.c b/god.c index 4ea247c..2273124 100644 --- a/god.c +++ b/god.c @@ -20,6 +20,8 @@ extern int statdirty; +extern WINDOW *mainwin; + extern map_t *firstmap; extern map_t *heaven; extern race_t *firstrace, *lastrace; @@ -35,9 +37,12 @@ int ngodlfs = 0; void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { lifeform_t *god; int piety; + char buf[BUFLEN]; enum PIETYLEV plev; int dosay = B_FALSE; + if (lfhasflag(player, F_WINNER)) return; + god = findgod(rid); modpiety(rid, -amt); @@ -74,6 +79,21 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { godsay(rid, B_TRUE, "Coward!"); break; case GA_EAT: godsay(rid, B_TRUE, "That is NOT acceptable for consumption!"); break; + case GA_GODSTONE: + switch (god->race->id) { + case R_GODPURITY: sprintf(buf, "That is not yours to touch, mortal!"); break; + case R_GODTHIEVES: sprintf(buf, "You dare to steal MY property?"); break; + case R_GODDEATH: sprintf(buf, "A fleshling thinks they can challenge the lord of death?"); break; + case R_GODFIRE: sprintf(buf, "THIIIEEEFFF!"); break; + case R_GODLIFE: sprintf(buf, "NO! You have stolen the very essense of life!"); break; + case R_GODMERCY: sprintf(buf, "NO!"); break; + case R_GODNATURE: sprintf(buf, "You threaten the destruction of everything!"); break; + case R_GODBATTLE: sprintf(buf, "Knave! Your theft constitutes a declaration of war!"); break; + case R_GODMAGIC: sprintf(buf, "One does not comprehend the danger of One's find!"); break; + default: break; + } + godsay(rid, B_TRUE, buf); + break; case GA_HERESY: if (rid == R_GODFIRE) { godsay(rid, B_TRUE, "HERESY!"); @@ -472,6 +492,9 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { // anger the god if you are worshippin them. void angergodmaybe(enum RACE rid, int amt, enum GODANGERREASON why) { lifeform_t *god; + + if (lfhasflag(player, F_WINNER)) return; + god = findgod(rid); if (lfhasflag(god, F_PRAYEDTO)) { angergod(rid, amt, why); @@ -485,6 +508,12 @@ void dooffer(void) { int nretflags,pietyplus = 0; char splatterob[BUFLEN]; strcpy(splatterob, ""); + + if (lfhasflag(player, F_RAGE)) { + msg("You are too enraged to offer a sacrifice!"); + return; + } + // which god? god = askgod("To whom will you sacrifice?", B_TRUE); if (!god) { @@ -633,6 +662,15 @@ enum RACE getopposinggod(enum RACE rid) { return R_NONE; } +enum OBTYPE getopposinggodstone(enum RACE rid) { + objecttype_t *ot; + for (ot = objecttype ; ot ; ot = ot->next) { + if (ot->obclass->id != OC_GODSTONE) continue; + if (hasflagval(ot->flags, F_LINKGOD, getopposinggod(rid), NA, NA, NULL)) return ot->id; + } + return OT_NONE; +} + int getpiety(enum RACE rid) { lifeform_t *god; flag_t *f; @@ -647,6 +685,22 @@ int getpiety(enum RACE rid) { return 0; } +// return the highest piety value which will result in the given level. +int getpietycutoff(enum PIETYLEV pl) { + switch (pl) { + case PL_ENRAGED: return -200; + case PL_FURIOUS: return -100; + case PL_ANGRY: return -1; + case PL_TOLERATED: return 99; + case PL_INDIFFERENT: return 199; + case PL_PLEASED: return 299; + case PL_DELIGHTED: return 399; + case PL_ECSTATIC: return 1000; + } + // default + return 0; +} + enum PIETYLEV getpietylev(enum RACE rid, enum COLOUR *col, char *happiness) { int piety; /// figure out piety bracket @@ -721,6 +775,16 @@ lifeform_t *getrandomprayedgod(void) { return poss[rnd(0,nposs-1)]; } +enum OBTYPE getrelatedgodstone(enum RACE rid) { + objecttype_t *ot; + for (ot = objecttype ; ot ; ot = ot->next) { + if (ot->obclass->id != OC_GODSTONE) continue; + if (hasflagval(ot->flags, F_LINKGOD, rid, NA, NA, NULL)) return ot->id; + } + return OT_NONE; +} + + lifeform_t *godappears(enum RACE rid, cell_t *where) { lifeform_t *god; char killedname[BUFLEN],godname[BUFLEN]; @@ -729,9 +793,9 @@ lifeform_t *godappears(enum RACE rid, cell_t *where) { strcpy(killedname, ""); if (!where) { // somewhere next to the player. - where = getrandomadjcell(player->cell, WE_WALKABLE, B_FALSE); + where = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, player); if (!where) { - where = getrandomadjcell(player->cell, B_FALSE, B_FALSE); + where = getrandomadjcell(player->cell, B_FALSE, B_NOEXPAND); } } @@ -773,8 +837,13 @@ void god_usepoison_response(void) { } int godblocked(enum RACE rid) { - lifeform_t *opposegod; + lifeform_t *opposegod,*god; enum RACE opposeid; + god = findgod(rid); + // forcibly blocked? + if (lfhasflag(god, F_GODBLOCKED)) { + return B_TRUE; + } // already prayed to the opposing god? opposeid = getopposinggod(rid); opposegod = findgod(opposeid); @@ -1322,6 +1391,187 @@ void godsay(enum RACE rid, int says, char *format, ...) { msg("\"%s\"", buf); } +void godstone_pickup_effects(lifeform_t *god, lifeform_t *opposegod, object_t *o) { + int x,y; + // opposing god appears + godappears(opposegod->race->id, NULL); + + msg("%s says:", opposegod->race->name); more(); + + cls(); + wmove(mainwin, 0, 0); + // tells you you can become the new god of xxx + // or give the stone to them, for a reward + //tells you about the portal on the surface + switch (opposegod->race->id) { + case R_GODBATTLE: + wprintw(mainwin, "\"Soldier. What you have just appropriated is the legendary\n"); + wprintw(mainwin, "Godstone of Magic. As you well know, the existence of magic\n"); + wprintw(mainwin, "has unfairly changed the outcome of many a battle. It causes\n"); + wprintw(mainwin, "even the most hardened veteran to tremble in the face of the\n"); + wprintw(mainwin, "weak and infirm. This goes against everything that is proper.\n"); + wprintw(mainwin, "Now that the Godstone has been captured, there is a singular\n"); + wprintw(mainwin, "opportunity to end this travesty.\n\n"); + wprintw(mainwin, "Claim the stone in the name of armies everywhere, stand before\n"); + wprintw(mainwin, "the Goddess of Magic, and issue your challenge. Strike her down,\n"); + wprintw(mainwin, "and with her strike down the imbalances of magic itself!\n\n"); + wprintw(mainwin, "Do not take any chances. If for any reason the success of your\n"); + wprintw(mainwin, "primary mission should become uncertain, your contingency plan is\n"); + wprintw(mainwin, "to immediately escort the stone safely to me. Such a dangerous\n"); + wprintw(mainwin, "weapon must not fall into the hands of enemies, and only in\n"); + wprintw(mainwin, "my possession can we be sure of its safety.\n\n"); + wprintw(mainwin, "Your first waypoint is the portal atop the dungeon. This will\n"); + wprintw(mainwin, "to the Realm of Gods, where both of your objectives can be\n"); + wprintw(mainwin, "achieved.\""); + break; + case R_GODDEATH: + wprintw(mainwin, "\"Heh, heh, heh.\n\n"); + wprintw(mainwin, "You, mortal, have just found the Godstone of Life.\n"); + wprintw(mainwin, "It is the source of all Glorana's power... and could also be used to murder\n"); + wprintw(mainwin, "her and take that power... if one had sufficient courage.\n\n"); + wprintw(mainwin, "As you are a mere fleshling however, I will offer you a deal. Simply\n"); + wprintw(mainwin, "deliver the Godstone to me, and in return I will forgo my claim on your\n"); + wprintw(mainwin, "life. Your flesh will never wither. Your strength will never fade.\n"); + wprintw(mainwin, "Death will never claim you.\n\n"); + wprintw(mainwin, "Whatever your choice, travel to the surface and you will find a portal\n"); + wprintw(mainwin, "to the Realm of Gods. Enter through, and claim your prize!\"\n\n"); + break; + case R_GODFIRE: + wprintw(mainwin, "\"NATURE STONE!!!!\n\n"); + wprintw(mainwin, "YOU WILL BRING IT! YOU WILL BRING IT AND KLIKIRAK WILL DESTROY!\n"); + wprintw(mainwin, "OR... STONE KILL EKRUB. YES! YOU WILL USE. YOU FIND\n"); + wprintw(mainwin, "HER. YOU USE STONE. STONE HELP BURN NATURE GODDESS!\n\n"); + wprintw(mainwin, "YOU GO UPWARD. UPWARD GOES TO FOREST. PORTAL IN FOREST.\n"); + wprintw(mainwin, "PORTAL TO TREE WOMAN. YOU KILL TREE WOMAN. OR YOU FIND KLIKIRAK,"); + wprintw(mainwin, "YOU GIVE STONE TO KLIKIRAK.\n\n"); + wprintw(mainwin, "YES. YES. YYYEESSS!!\"\n"); + break; + case R_GODLIFE: + wprintw(mainwin, "\"BEWARE, CHILD! That is the Godstone of Death!\n\n"); + wprintw(mainwin, "But wait... you seem unaffected by its power. Common wisdom\n"); + wprintw(mainwin, "holds that the stone destroys all who touch it. Since this is\n"); + wprintw(mainwin, "clearly untrue however... could it be that Hecta has fooled us\n"); + wprintw(mainwin, "all? That the God of Death does indeed possess a weakness?\"\n\n"); + wprintw(mainwin, "Lumara's pulsating form wavers for a moment, seemingly unsure.\n\n"); + wprintw(mainwin, "\"It must be. And if this stone is truly the source of Hecta's\n"); + wprintw(mainwin, "power, then destroying it... that would mean and end to death!\n"); + wprintw(mainwin, "Life could last forever - all could be immortal, rathern just\n"); + wprintw(mainwin, "a select few! It must be done - if you can bring me the\n"); + wprintw(mainwin, "Godstone it will take but a few moments and the meaning of life\n"); + wprintw(mainwin, "will be forever altered. Hecta will likely try to stop you.\n"); + wprintw(mainwin, "Avoid him if you can... but should that not prove possible, the\n"); + wprintw(mainwin, "the stone should at least grant you a slim chance of survival.\n"); + wprintw(mainwin, "It might even be powerful enough for you to triumph...\n\n"); + wprintw(mainwin, "But let us not dwell on that. Find the portal to my realm on\n"); + wprintw(mainwin, "the surface, and take the first step towards eternal life!\""); + break; + case R_GODMAGIC: + wprintw(mainwin, "\"One has made a monumental discovery!\n\n"); + wprintw(mainwin, "One my now comprehend, but the level of magic within the cosmos\n"); + wprintw(mainwin, "has been waning. One's find is the source of this - an artifact\n"); + wprintw(mainwin, "so imbued with the essense of physical conflict that its very\n"); + wprintw(mainwin, "existence has disrupted the energies of imagination so vital to magic.\n"); + wprintw(mainwin, "While One's path is of course One's own to decide, I would counsel you\n"); + wprintw(mainwin, "to consider two alternative courses of action.\n\n"); + wprintw(mainwin, "If you are able to bring the stone before me, the universe could be\n"); + wprintw(mainwin, "forever enlightened. I could unlock infinite magical potential within\n"); + wprintw(mainwin, "every living being, from the tiniest insect to the very stars themselves.\n\n"); + wprintw(mainwin, "If One craves danger and adventure, One could also use the stone to confront\n"); + wprintw(mainwin, "the God of Battle himself. Its power may just be sufficient to best the\n"); + wprintw(mainwin, "Battlelord, and doing so would open the doors for One's own ascension.\n\n"); + wprintw(mainwin, "One should consider these words wisely, and make One's choice.\"\n"); + break; + case R_GODMERCY: + wprintw(mainwin, "\"HALT! By touching the Godstone of Vengeance, you have commited a\n"); + wprintw(mainwin, "unspeakable sin! By rights your action should condemn you for\n"); + wprintw(mainwin, "eternity. However...\"\n"); + wprintw(mainwin, "Yumi's grave expression softens.\n"); + wprintw(mainwin, "\"I embody mercy, and all sins can be forgiven. In this case, the\n"); + wprintw(mainwin, "road to your redemption is tied with the deed itself.\n\n"); + wprintw(mainwin, "Bring the stone to me. Perform this penance and not only will you\n"); + wprintw(mainwin, "be forgiven, but you will ensure that your mistake is never again\n"); + wprintw(mainwin, "repeated for all eternity. The God of Revenge will be neutralised,"); + wprintw(mainwin, "his influence ended.\n\n"); + wprintw(mainwin, "Mercy however, extends even to the divine. I would not doom Felix\n"); + wprintw(mainwin, "to a life of misery, his very essence ripped away. Should you\n"); + wprintw(mainwin, "possess the power, the Godstone would be used to grant Felix the\n"); + wprintw(mainwin, "peaceful sleep of death. For a tormented soul such as his, this\n"); + wprintw(mainwin, "would truly be a mercy.\n\n"); + wprintw(mainwin, "Either way, your atonement begins now. Travel up to the surface,\n"); + wprintw(mainwin, "and enter the magic portal. Once you arrive in the Realm of Gods\n"); + wprintw(mainwin, "and complete your task, all will be forgiven.\""); + break; + case R_GODNATURE: + wprintw(mainwin, "\"%s! You hold the Godstone of Rage!\n\n", toupper(player->race->name[0]), (player->race->name + 1)); + wprintw(mainwin, "Long have I sought this ancient artifact - it is from this stone that the\n"); + wprintw(mainwin, "insane God of Fire draws his destructive power.\n"); + wprintw(mainwin, "If you can just deliver this stone to me, Klikirak's reign could be ended!\n\n"); + wprintw(mainwin, "Or even better...\"\n\n"); + wprintw(mainwin, "Ekrub pauses for a moment.\n\n"); + wprintw(mainwin, "As a being of creation I cannot affect the Fire God directly, but with the"); + wprintw(mainwin, "power of the stone, you could. If you can confront and defeat him, I vow"); + wprintw(mainwin, "to support you.\n\n"); + wprintw(mainwin, "Within my forest on the surface, there is a portal to the Realm of Gods."); + wprintw(mainwin, "Use it, and bring the Godstone!\"\n"); + break; + case R_GODTHIEVES: + wprintw(mainwin, "\"Oho, what have you there? That stone, my friend, is none other than\n"); + wprintw(mainwin, "the Godstone of Mercy itself! Oh sure, there are those rumours of\n"); + wprintw(mainwin, "its protective powers, but what people don't know is that it's also\n"); + wprintw(mainwin, "the direct source of power for Yumi, the Mercy Goddess.\n"); + wprintw(mainwin, "Now, were someone to hold that stone... well, they'd be in prime\n"); + wprintw(mainwin, "position to give the high and might lady of forgiveness a taste of\n"); + wprintw(mainwin, "good old fashioned Revenge.\n\n"); + wprintw(mainwin, "Of course you don't need to bother with all that. Just bring the stone\n"); + wprintw(mainwin, "to me and I'll do the rest. There's a portal up on the surface, all\n"); + wprintw(mainwin, "you need to do is step through, track me down, and hand over that little\n"); + wprintw(mainwin, "trinket. Piece of cake!\""); + break; + case R_GODPURITY: + wprintw(mainwin, "\"Mortal! You hold an ancient artifact of immense power!\n"); + wprintw(mainwin, "In your hands is the accursed Godstone of Chaos. For\n"); + wprintw(mainwin, "centuries I have tracked this vile object, but somehow\n"); + wprintw(mainwin, "the energies of the mortal world are keeping it from me.\n\n"); + wprintw(mainwin, "This single stone is the source of all impurity in the universe.\n"); + wprintw(mainwin, "Now all you need to do is deliver it to me, and it can be\n"); + wprintw(mainwin, "unmade. In fact with the Godstone possessed by another,\n"); + wprintw(mainwin, "the Chaos God's power may well have been waned far enough\n"); + wprintw(mainwin, "for him to be confronted directly.\n\n"); + wprintw(mainwin, "Travel to the Realm of Gods mortal, and come to me with the\n"); + wprintw(mainwin, "stone. If you find and destroy the Chaos god on the way, all"); + wprintw(mainwin, "the better. Chaos and impurity MUST be ended!\""); + break; + default: + break; + } + getyx(mainwin, y, x); + centre(mainwin,C_WHITE, y, "[Press any key]"); + getch(); + + restoregamewindows(); + + // identify the godstone + identify(o); + + // make sure related god's anger will trigger one bad effect. + if (!godprayedto(god->race->id)) { + addflag(god->flags, F_PRAYEDTO, B_TRUE, NA, NA, NULL); + } + // related god screams and gets furios/enraged at you. + // (you lose prayedto if you have it?) + if (getpietylev(god->race->id, NULL, NULL) == PL_FURIOUS) { + // becomes enraged + setpiety(god->race->id, getpietycutoff(PL_ENRAGED)); + } else { + // becomes furious + setpiety(god->race->id, getpietycutoff(PL_FURIOUS)); + } + angergod(god->race->id, 0, GA_GODSTONE); + + killflagsofid(god->flags, F_PRAYEDTO); + addflag(god->flags, F_GODBLOCKED, B_TRUE, NA, NA, NULL); +} + void modpiety(enum RACE rid, int amt) { lifeform_t *god; flag_t *f; @@ -1392,6 +1642,9 @@ void pleasegod(enum RACE rid, int amt) { void pleasegodmaybe(enum RACE rid, int amt) { enum PIETYLEV modplev; int chance; + + if (lfhasflag(player, F_WINNER)) return; + modplev = abs(getpietylev(rid, NULL, NULL)); // the angrier or more happy the god gets, the harder it diff --git a/god.h b/god.h index 5916324..7162cb6 100644 --- a/god.h +++ b/god.h @@ -5,11 +5,14 @@ void angergodmaybe(enum RACE rid, int amt, enum GODANGERREASON why); void dooffer(void); lifeform_t *findgod(enum RACE rid); enum RACE getopposinggod(enum RACE rid); +enum OBTYPE getopposinggodstone(enum RACE rid); int getpiety(enum RACE rid); +int getpietycutoff(enum PIETYLEV pl); enum PIETYLEV getpietylev(enum RACE rid, enum COLOUR *col, char *happiness); int getprayedgods(lifeform_t **retgod, int *nretgods); lifeform_t *getrandomgod(void); lifeform_t *getrandomprayedgod(void); +enum OBTYPE getrelatedgodstone(enum RACE rid); lifeform_t *godappears(enum RACE rid, cell_t *where); void god_usepoison_response(void); int godblocked(enum RACE rid); @@ -17,6 +20,7 @@ int godgiftmaybe(enum RACE rid, int fromtemple); int godisangry(enum RACE rid); int godprayedto(enum RACE rid); void godsay(enum RACE rid, int says, char *format, ...); +void godstone_pickup_effects(lifeform_t *god, lifeform_t *opposegod, object_t *o); void modpiety(enum RACE rid, int amt); void pleasegod(enum RACE rid, int amt); void pleasegodmaybe(enum RACE rid, int amt); diff --git a/io.c b/io.c index 0b1c3e6..8099431 100644 --- a/io.c +++ b/io.c @@ -29,6 +29,8 @@ WINDOW *gamewin; WINDOW *msgwin; WINDOW *statwin; +extern enum WINGAMETYPE wintype; + int statdirty = B_TRUE; int inaskcoords = B_FALSE; // are we inside this function? @@ -713,6 +715,12 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src break; } + // clone? + if (ispetof(c->lf, player) && lfhasflag(c->lf, F_PHANTASM)) { + if (strlen(extrainfo)) strcat(extrainfo, ", "); + strcat(extrainfo, "phantasm"); + } + // obvious things if (isfleeing(c->lf)) { if (strlen(extrainfo)) strcat(extrainfo, ", "); @@ -1049,10 +1057,10 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src tempob = addob(c->obpile, obname); } // show objects - o = doaskobject(c->obpile, "Describe which object", NULL, B_TRUE, B_FALSE, B_FALSE, '\0', NULL, AO_NONE, F_NONE); + o = doaskobject(c->obpile, "Describe which object", NULL, B_TRUE, B_FALSE, B_FALSE, '\0', NULL, MT_NOTHING, AO_NONE, F_NONE); while (o) { describeob(o); - o = doaskobject(c->obpile, "Describe which object", NULL, B_FALSE, B_FALSE, B_FALSE, '\0', NULL, AO_NONE, F_NONE); + o = doaskobject(c->obpile, "Describe which object", NULL, B_FALSE, B_FALSE, B_FALSE, '\0', NULL, MT_NOTHING, AO_NONE, F_NONE); } if (tempob) killob(tempob); } @@ -1187,6 +1195,11 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { return B_FALSE; } + // stop announcement when we add f_awareness at the end of the game. + if (lfhasflag(lf, F_WINNER)) { + return B_FALSE; + } + getlfname(lf, lfname); if (isdead(player)) return B_FALSE; @@ -2683,6 +2696,7 @@ lifeform_t *askgod(char *prompttext, int onlyprayed) { flag_t *f; char godof[BUFLEN],buf[BUFLEN]; lf = godlf[i]; + if (!lf) continue; if (onlyprayed && !lfhasflag(lf, F_PRAYEDTO)) { continue; @@ -2716,11 +2730,11 @@ object_t *askobject(obpile_t *op, char *prompt, int *count, char action, long o if (op->owner && isplayer(op->owner)) { showlong = B_FALSE; } - return doaskobject(op, prompt, count, showlong, B_TRUE, B_FALSE, action, NULL, opts, F_NONE); + return doaskobject(op, prompt, count, showlong, B_TRUE, B_FALSE, action, NULL, MT_NOTHING, opts, F_NONE); } object_t *askobjectwithflag(obpile_t *op, char *prompt, int *count, char action, long opts, enum FLAG withflag) { - return doaskobject(op, prompt, count, B_TRUE, B_TRUE, B_FALSE, action, NULL, opts, withflag, F_NONE); + return doaskobject(op, prompt, count, B_TRUE, B_TRUE, B_FALSE, action, NULL, MT_NOTHING, opts, withflag, F_NONE); } int contains(enum OBCLASS *array, int nargs, enum OBCLASS want) { @@ -2852,13 +2866,13 @@ void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int fi } -// varargs are: +// varargs are a list of flags which we want: // F_xxx // F_xxx // F_NONE // // If you pass "sellshop", DONT also pass F_xxx. -object_t *doaskobject(obpile_t *op, char *prompt, int *count, int showlong, int forpickup, int showpoints, char action, object_t *sellshop, long opts, ...) { +object_t *doaskobject(obpile_t *op, char *prompt, int *count, int showlong, int forpickup, int showpoints, char action, object_t *sellshop, int wantmaterial, long opts, ...) { int c,i; char defchar = '\0'; static char defaults[52] = {'\0'}; @@ -2962,6 +2976,12 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int showlong, int if (!canseeob(player, o)) ok = B_FALSE; + if (ok) { + if ((wantmaterial != MT_NOTHING) && (o->material->id != wantmaterial)) { + ok = B_FALSE; + } + } + if (ok) { // check for wanted flags for (n = 0; n < nwantflags; n++) { @@ -3860,6 +3880,7 @@ void docomms(lifeform_t *lf) { int count; int alignmod = 0; object_t *o, *givenob = NULL; + object_t *godstone = NULL; if (!lf) { where = askcoords("Talk to who?", "Talk->", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE); if (where && where->lf && cansee(player, where->lf)) { @@ -3875,6 +3896,7 @@ void docomms(lifeform_t *lf) { getlfname(lf, lfname); + snprintf(buf, BUFLEN, "What will you say to %s?",lfname); initprompt(&prompt, buf); prompt.maycancel = B_TRUE; @@ -3936,8 +3958,19 @@ void docomms(lifeform_t *lf) { } // if you are allies, use 'trade items' instead - if (isadjacent(lf->cell, player->cell) && !areallies(player,lf) && !isgod(lf)) { - addchoice(&prompt, 'd', "(donate an item)", NULL, NULL, NULL); + if (isadjacent(lf->cell, player->cell) && !areallies(player,lf)) { + if (isgod(lf)) { + // may only donate the godstone + godstone = hasob(player->pack, getopposinggodstone(lf->race->id)); + if (godstone) { + char buf[BUFLEN],obname[BUFLEN]; + getobname(godstone, obname, 1); + sprintf(buf, "(offer %s)", obname); + addchoice(&prompt, 'd', buf, NULL, NULL, NULL); + } + } else { + addchoice(&prompt, 'd', "(donate an item)", NULL, NULL, NULL); + } } /* @@ -3982,6 +4015,10 @@ void docomms(lifeform_t *lf) { msg("%s doesn't respond.", lfname); break; } + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } if (lf == lf2) { // won't attack itself @@ -4008,6 +4045,10 @@ void docomms(lifeform_t *lf) { msg("%s doesn't respond.", lfname); break; } + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } // find adjacent cell c = getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND); if (c) { @@ -4015,9 +4056,15 @@ void docomms(lifeform_t *lf) { } break; case 'd': // donate - // ask what to give - snprintf(buf, BUFLEN, "What will you give to %s?",lfname); - o = askobject(player->pack, buf, &count, '\0', AO_NONE); + // giving godstone to a god? + if (godstone) { + o = godstone; + count = 1; + } else { + // ask what to give + snprintf(buf, BUFLEN, "What will you give to %s?",lfname); + o = askobject(player->pack, buf, &count, '\0', AO_NONE); + } if (o) { if (o->type->id == OT_GOLD) { char countbuf[BUFLEN]; @@ -4093,6 +4140,17 @@ void docomms(lifeform_t *lf) { } pleasegodmaybe(R_GODPURITY, 10); pleasegodmaybe(R_GODMERCY, 20); + } else if (isgod(lf) && (givenob->type->obclass->id == OC_GODSTONE)) { + // in heaven? + if (lf->cell->map->habitat->id == H_HEAVEN) { + flag_t *gf; + gf = lfhasflag(lf, F_GODOF); + // you win! + addflag(player->flags, F_WINNER, WT_DEMIGOD, lf->race->id, NA, gf->text); + wingame(); + } else { + say(lf, "Not here, mortal! Come to the Realm of the Gods.", SV_SHOUT); + } } else { // not giving money to a begger enum ATTRBRACKET iqb; @@ -4164,10 +4222,18 @@ void docomms(lifeform_t *lf) { msg("%s doesn't respond.", lfname); break; } + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } aigoto(lf, c, MR_OTHER, NULL, DEF_AIFOLLOWTIME); break; case 'i': msg("You say \"What can you tell me about this area?\" to %s.", lfname); + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } if (askforinfo(lf, 2)) { genareaknowledge(lf->flags, 0); docomms_areainfo(lfname, lf->flags, lf); @@ -4180,14 +4246,26 @@ void docomms(lifeform_t *lf) { msg("%s doesn't respond.", lfname); break; } + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } recruit(lf); break; case 'k': // trade Knowledge msg("You say \"Care to trade knowledge?\" to %s.", lfname); + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } tradeknowledge(lf); break; case 'm': // mercy msg("You say \"Have mercy!\" to %s.", lfname); + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } if (islowhp(player) && cantalk(lf) && canhear(lf, player->cell, SV_SHOUT) && @@ -4259,6 +4337,10 @@ void docomms(lifeform_t *lf) { msg("%s doesn't respond.", lfname); break; } + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } f = isresting(lf); if (f) { stopresting(lf); @@ -4276,6 +4358,10 @@ void docomms(lifeform_t *lf) { } return; case 't': + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } // ask whtehr to give/take initprompt(&prompt, "How will you trade?"); snprintf(buf, BUFLEN, "Give items to %s",lfname); @@ -4305,6 +4391,10 @@ void docomms(lifeform_t *lf) { break; case 'x': msg("You say \"Any dangers nearby that I should look out for?\" to %s.", lfname); + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } if (askforinfo(lf, 4)) { genareaknowledge(lf->flags, 0); docomms_areadangers(lfname, lf->flags, lf); @@ -4320,6 +4410,10 @@ void docomms(lifeform_t *lf) { msg("%s doesn't respond.", lfname); break; } + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } setfollowdistance(lf, 1, 3); break; case '>': @@ -4328,6 +4422,10 @@ void docomms(lifeform_t *lf) { msg("%s doesn't respond.", lfname); break; } + if (lfhasflag(lf, F_PHANTASM)) { + msg("%s doesn't respond.", lfname); + break; + } setfollowdistance(lf, 3, 5); break; } @@ -7477,12 +7575,12 @@ void doexplain(char *question) { void dofinaloblist(obpile_t *op) { object_t *o; - o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE, '\0', NULL, AO_NONE, F_NONE); + o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE, '\0', NULL, MT_NOTHING, AO_NONE, F_NONE); while (o) { // describe it describeob(o); // ask for another one - o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE,'\0', NULL, AO_NONE, F_NONE); + o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE,'\0', NULL, MT_NOTHING, AO_NONE, F_NONE); } real_clearmsg(B_TRUE); } @@ -7617,7 +7715,7 @@ void doinventory(obpile_t *op) { maxweight = getmaxcarryweight(player); pct = (packweight / maxweight) * 100; snprintf(buf, BUFLEN, "Inventory (%0.0f/%0.0f kg, %0.0f%%)", packweight, maxweight, pct); - o = doaskobject(op, buf, NULL, B_TRUE, B_TRUE, B_FALSE, '\0', NULL, AO_NONE, F_NONE); + o = doaskobject(op, buf, NULL, B_TRUE, B_TRUE, B_FALSE, '\0', NULL, MT_NOTHING, AO_NONE, F_NONE); while (o) { // describe it describeob(o); @@ -12256,7 +12354,13 @@ void showlfstats(lifeform_t *lf, int showall) { } f = lfhasknownflag(lf, F_HEAVENARM); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s surrounded by a shell of divine armour. ", you(lf), is(lf)); + char hpbuf[BUFLEN]; + if (isplayer(lf)) { + sprintf(hpbuf, " (%d hp left)", f->val[0]); + } else { + strcpy(hpbuf, ""); + } + mvwprintw(mainwin, y, 0, "%s %s surrounded by a shell of divine armour.%s", you(lf), is(lf), hpbuf); y++; } f = lfhasknownflag(lf, F_INVULNERABLE); @@ -12405,6 +12509,8 @@ void showlfstats(lifeform_t *lf, int showall) { int blocked = B_FALSE; god = godlf[i]; + if (!god) continue; + blocked = godblocked(god->race->id); real_getlfname(god, godname, B_FALSE, B_FALSE); @@ -12585,6 +12691,9 @@ void tombstone(lifeform_t *lf) { int rank,minrank,maxrank; char *p; long playerscore; + flag_t *winflag; + + winflag = lfhasflag(player, F_WINNER); playerscore = calcscore(lf); @@ -12594,12 +12703,21 @@ void tombstone(lifeform_t *lf) { cls(); y = 1; - centre(mainwin, C_GREY, y, "R.I.P."); y++; + if (wintype) { + centre(mainwin, C_GREY, y, "CONGRATULATIONS!"); y+= 2; + } else { + centre(mainwin, C_GREY, y, "R.I.P."); y++; + } //printf("%s\n",lf->name); centre(mainwin, C_GREY, y, "%s (%ld points)",pname, playerscore); y++; - getregionname(buf, player->cell->map, NULL, RF_LONG); - centre(mainwin, C_GREY, y, "Died %s.", buf); y++; // ie. "Died on level 1 of the dungeon" + + if (wintype) { + y++; + } else { + getregionname(buf, player->cell->map, NULL, RF_LONG); + centre(mainwin, C_GREY, y, "Died %s.", buf); y++; // ie. "Died on level 1 of the dungeon" + } makekillertext(killer, lf->killverb, lf->lastdam, lf->cell->map, B_TRUE, B_FALSE); @@ -12694,6 +12812,259 @@ int real_warnabout(char *what, int lifetime, int doquestion) { return B_FALSE; } +void wingame(void) { + flag_t *winflag; + winflag = lfhasflag(player, F_WINNER); + if (winflag->val[0] == WT_DEMIGOD) { + lifeform_t *god; + // find the god who ascended us. + god = findgod(winflag->val[1]); + // god says something + switch (god->race->id) { + case R_GODPURITY: + msg("Amberon flings the Godstone out into the cosmos!\""); more(); + msg("\"Without the chaotic blight of this stone, the universe will be purified!\""); more(); + msg("\"Deformities will be cured, chance eliminated, entropy denied.\""); more(); + msg("\"From now on, all will be orderly and just.\""); more(); + msg("\"I name you the Arbiter of Divine Justice!\""); more(); + break; + case R_GODTHIEVES: + msg("Felix slips the Godstone into a pocket."); more(); + msg("\"By bringing this stone to me, you have brought closure to thousands.\""); more(); + msg("\"Every act of anger, every stolen penny, every wronged lover...\""); more(); + msg("\"No more shall they be told to simply 'forgive and forget'!\""); more(); + msg("\"All shall obtain their revenge!\""); more(); + msg("\"I name you the Hand of Veangence!\""); more(); + break; + case R_GODDEATH: + msg("A sinister smile spreads across Hecta's skull."); more(); + msg("\"With this artifact, I will annihilate all living beings!\""); more(); + msg("\"All souls throughout the universe shall become my servants!\""); more(); + msg("\"And you, fleshling...\""); more(); + msg("\"For your service, I name you my High Prince of the Dead!\""); more(); + msg("\"HAHAHahahahahahaha...\""); more(); + break; + case R_GODFIRE: + msg("Klikirak's flames explode outwards in a surge of triumphant fury!"); more(); + msg("\"NO CREATION! NO PLANTS! NO MORE GROWING!\""); more(); + msg("\"JUST FIRE! BURN! DESTROY! ANNIHILATE!\""); more(); + msg("\"OBLITERATE!!!!!\""); more(); + break; + case R_GODLIFE: + msg("Glorana's pulsating form melds into a female face, her eyes wide in shock."); more(); + msg("\"The Godstone of Death! You have brought it to me!\""); more(); + msg("\"Your efforts have earned eternal life for all humanity!\""); more(); + msg("\"Such an action deserves the highest possibble reward.\""); more(); + msg("\"Join me, as the Bringer of Life!\""); more(); + break; + case R_GODMERCY: + msg("Yumi beams radiantly at you."); more(); + msg("\"You do not know just how special this stone is.\""); more(); + msg("\"Without petty acts of revenge and jealousy, there will be peace.\""); more(); + msg("\"From the kindest soul, to the lowest criminal, all will know forgiveness.\""); more(); + msg("\"Rise up, and spread mercy as Mankind's Redemption.\""); more(); + break; + case R_GODNATURE: + msg("Ekrub gazes at the Godstone in awe."); more(); + msg("\"An end to burning... an end to destruction...\""); more(); + msg("\"All of nature's creations can finally grow in peace!\""); more(); + msg("\"As my children shall thrive, so shall you.\""); more(); + msg("\"I name you Nature's Soulmate!\""); more(); + break; + case R_GODBATTLE: + msg("Bjorn cleaves the Godstone with a might stroke of his battleaxe!\""); more(); + msg("\"You have won a great victory today, soldier.\""); more(); + msg("\"With this power, I will rally all existence for the final battle.\""); more(); + msg("\"No magic will interfere - might and battle tactics will win the day.\""); more(); + msg("\"For your valour, I promote you to General of the Gods!\""); more(); + break; + case R_GODMAGIC: + msg("Lumara's aging features begin to change, the years falling away in seconds.\""); more(); + msg("Soon, an energised young woman stands before you.\""); more(); + msg("\"You have done it!\""); more(); + msg("\"The cosmic forces are already being renewed with infinite potential!\""); more(); + msg("\"Henceforce all shall weild magic as easily as breathing.\""); more(); + msg("\"All restraints will be lifted, actions limited only by imagination!\""); more(); + msg("\"I name you the Font of Wizardry, the Arcane Grandmaster...\""); more(); + msg("\"The Connoisseur of the Cosmos!\""); more(); + break; + default: break; + } + msg("^%cYou ascend to a higher plane of existence as a demi-god!^n", getlfcol(player, CC_VGOOD)); more(); + msg("^%cCONGRATULATIONS!!!^n", getlfcol(player, CC_VGOOD)); more(); + } else { // ie. WT_GOD, killed a god + int i; + char *buf; + enum RACE opposeid; + lifeform_t *god[MAXGODS],*g; + int ngods = 0; + flag_t *tempflag[2]; + + opposeid = getopposinggod(winflag->val[1]); + + msg("As you vanquish your foe, a sudden stillness descends."); more(); + msg("For a brief moment, all is quiet."); more(); + msg("Then, there is an almighty clap of thunder and a brilliant flash of light!"); more(); + // make sure the player sees the gods appearing + tempflag[0] = addflag(player->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + tempflag[1] = addflag(player->flags, F_CANSEETHROUGHLF, B_TRUE, NA, NA, NULL); + setlosdirty(player); + for (i = 0; i < ngodlfs; i++) { + g = godlf[i]; + if (!g) continue; + godappears(g->race->id, NULL); + god[ngods++] = g; + } + needredraw = B_TRUE; + drawscreen(); + g = god[rnd(0,ngods-1)]; + say(g, "You have just done the unthinkable.", SV_TALK); more(); + g = god[rnd(0,ngods-1)]; + say(g, "You have killed a god!", SV_TALK); more(); + g = findgod(R_GODTHIEVES); + if (g) { + say(g, "This act cannot go unpunished!", SV_TALK); more(); + } else { + g = god[rnd(0,ngods-1)]; + say(g, "Felix would have insisted on punishment.", SV_TALK); more(); + } + g = findgod(R_GODMERCY); + if (g) { + say(g, "Although this seems unforgivable, we should always strive for mercy.", SV_TALK); more(); + } else { + g = god[rnd(0,ngods-1)]; + say(g, "Yumi would have wanted mercy to be given.", SV_TALK); more(); + } + + g = findgod(R_GODMAGIC); + if (!g) g = god[rnd(0,ngods-1)]; + say(g, "The cosmos works in mysterious ways.", SV_TALK); more(); + + g = findgod(R_GODBATTLE); + if (g) { + say(g, "The kill was through honourable battle!", SV_TALK); more(); + } else { + g = god[rnd(0,ngods-1)]; + say(g, "We all knew this was a possibility.", SV_TALK); more(); + } + + // nature + g = findgod(R_GODNATURE); + if (g) { + say(g, "This is the cycle of life, nothing more. What lives must die.", SV_TALK); more(); + } else { + g = god[rnd(0,ngods-1)]; + say(g, "Ekrub has withered, as all nature must do eventually.", SV_TALK); more(); + } + + // fire + g = findgod(R_GODFIRE); + if (g) { + say(g, "MIGHTY GOD DESTROYED!", SV_TALK); more(); + } else { + g = god[rnd(0,ngods-1)]; + say(g, "The fires of destruction have been quenched.", SV_TALK); more(); + } + + // life + g = findgod(R_GODLIFE); + if (g) { + say(g, "To take any life is abhorrent... but that of a god?", SV_TALK); more(); + } else { + g = god[rnd(0,ngods-1)]; + say(g, "The Goddess of Life destroyed? How can this be?", SV_TALK); more(); + } + + g = findgod(R_GODDEATH); + if (g) { + say(g, "The fleshling has given me a monumental gift.", SV_TALK); more(); + } else { + g = god[rnd(0,ngods-1)]; + say(g, "Had it been one of us, Hecta would exultant now.", SV_TALK); more(); + } + + g = findgod(R_GODPURITY); + if (g) { + say(g, "Nevertheless, there is now an impurity within our ranks.", SV_TALK); more(); + } else { + g = god[rnd(0,ngods-1)]; + say(g, "It would seem there is a new vacancy within our ranks.", SV_TALK); more(); + } + + // don't want the opposing god of the killed one responding + g = god[rnd(0,ngods-1)]; + while (g->race->id == opposeid) g = god[rnd(0,ngods-1)]; + say(g, "The one before us is obviously ambitious.", SV_TALK); more(); + + g = god[rnd(0,ngods-1)]; + while (g->race->id == opposeid) g = god[rnd(0,ngods-1)]; + say(g, "He has clearly proven his power.", SV_TALK); more(); + + g = god[rnd(0,ngods-1)]; + while (g->race->id == opposeid) g = god[rnd(0,ngods-1)]; + say(g, "Are we agreed, then?", SV_TALK); more(); + + // the opposing god will always disagree and storm off + // in a huff. + + g = findgod(opposeid); + switch (g->id) { + case R_GODPURITY: + say(g, "You fools would bring back Chaos?!", SV_SHOUT); more(); + msg("\"I will not be part of this!\""); more(); + break; + case R_GODTHIEVES: + say(g, "NO! Do not spoil my revenge by replacing her!", SV_SHOUT); more(); + break; + case R_GODDEATH: + say(g, "Fools. Replace her if you wish, it will change nothing.", SV_SHOUT); more(); + break; + case R_GODFIRE: + say(g, "NOOOO! WHY NATURE NEVER STOP REGROWING?!", SV_SHOUT); more(); + break; + case R_GODLIFE: + say(g, "It would seem that somehow death will result in life...", SV_TALK); more(); + msg("\"I must consider this.\""); more(); + break; + case R_GODMERCY: + say(g, "\"How dare you!\"", SV_SHOUT); more(); + msg("\"I show you mercy and you repay it by becoming my greatest rival?!\""); more(); + break; + case R_GODNATURE: + say(g, "\"TRAITOR!\"", SV_SHOUT); more(); + msg("\"I vowed to support you, but you know this is not what I meant!\""); more(); + break; + case R_GODBATTLE: + say(g, "\"Not again! Magic was meant to be destroyed!\"", SV_SHOUT); more(); + msg("\"Is there no end to the foul trickeries of magic?\""); more(); + break; + case R_GODMAGIC: + say(g, "\"One has decided. Time will determine the wisdom of One's choice.\"", SV_TALK); more(); + break; + } + + // calling "unsommon" will technically kill + // the god, but since the game is about to end it doesn't + // really matter. + unsummon(g, B_TRUE); + + msg("The remaining gods nod in unison."); more(); + + g = god[rnd(0,ngods-1)]; + say(g, "Arise then, and join us!", SV_TALK); more(); + + msg("The combined voices the gods ring out:"); more(); + buf = strdup(winflag->text); + strrep(buf, "&", "and", NULL); + makeuppercase(buf); + msg("^%c\"ALL HAIL THE NEW GOD OF %s!!\"", getlfcol(player, CC_VGOOD), buf); + more(); + free(buf); + killflag(tempflag[0]); + killflag(tempflag[1]); + } +} + // @ = tab char wrapprint(WINDOW *win, int *y, int *x, int newlineindent, char *format, ... ) { char word[HUGEBUFLEN],buf[HUGEBUFLEN]; @@ -12783,9 +13154,9 @@ char wrapprint(WINDOW *win, int *y, int *x, int newlineindent, char *format, ... } else if ((*x != newlineindent) && strlen(word)) { textwithcol_real(win, " ", B_FALSE); } - if (strlen(repword) < 2) { + /* if (strlen(repword) < 2) { dblog("xxx"); - } + } */ textwithcol_real(win, repword, B_FALSE); //(*x) += strlen(buf); getyx(win, *y, *x); diff --git a/io.h b/io.h index f89628a..d65e23a 100644 --- a/io.h +++ b/io.h @@ -21,7 +21,7 @@ int confirm_injury_action(enum BODYPART bp, enum DAMTYPE dt, char *actionname); lifeform_t *askgod(char *prompt, int onlyprayed); object_t *askobject(obpile_t *op, char *title, int *count, char action, long opts); object_t *askobjectwithflag(obpile_t *op, char *title, int *count, char action, long opts, enum FLAG withflag); -object_t *doaskobject(obpile_t *op, char *title, int *count, int showlong, int forpickup, int showpoints, char action, object_t *sellshop, long opts, ...); +object_t *doaskobject(obpile_t *op, char *title, int *count, int showlong, int forpickup, int showpoints, char action, object_t *sellshop, int wantmaterial, long opts, ...); int askobjectmulti(obpile_t *op, char *prompt, long opts); char askchar(char *prompt, char *validchars, char *def, int showchars, int maycancel); cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail); @@ -137,4 +137,5 @@ void updatestatus(void); int updateviewfor(cell_t *cell); int warnabout(char *what); int real_warnabout(char *what, int lifetime, int doquestion); +void wingame(void); char wrapprint(WINDOW *win, int *y, int *x, int newlineindent, char *format, ... ); diff --git a/lf.c b/lf.c index 140f3c1..32d6859 100644 --- a/lf.c +++ b/lf.c @@ -280,6 +280,7 @@ void breakaitargets(lifeform_t *lf, int onlylowerlev) { } long calcscore(lifeform_t *lf) { + flag_t *f; long points = 0; object_t *o; if (lfhasflag(lf, F_NOSCORE)) { @@ -291,6 +292,15 @@ long calcscore(lifeform_t *lf) { } // points for xp points += (lf->xp / 10); + + f = hasflag(player->flags, F_WINNER); + if (f) { + if (f->val[0] == WT_DEMIGOD) { + points *= 13; + } else if (f->val[0] == WT_GOD) { + points *= 23; + } + } return points; } @@ -1489,6 +1499,11 @@ int cantakeoff(lifeform_t *lf, object_t *o) { } int cantalk(lifeform_t *lf) { + // phantasms dont talk + if (lfhasflag(lf, F_PHANTASM)) { + return B_FALSE; + } + // if the lf can't explicitly talk, check its race if (!lfhasflag(lf, F_CANTALK)) { switch (lf->race->raceclass->id) { case RC_DEMON: @@ -1911,15 +1926,17 @@ int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod) { // check for lfs which block view if (c->lf && (c->lf != lf) && cansee_real(lf, c->lf, B_FALSE)) { - int sizediff; - // high sizediff means that the lf in the cell is bigger than the viewer - sizediff = getlfsize(c->lf) - getlfsize(lf); - // lf greater than 2 sizes bigger than us? - if (sizediff >= 2) { - if (xray && *xray) { - (*xray) -= (sizediff-1); - if (*xray < 0) *xray = 0; - } else return B_FALSE; + if (!lfhasflag(lf, F_CANSEETHROUGHLF)) { + int sizediff; + // high sizediff means that the lf in the cell is bigger than the viewer + sizediff = getlfsize(c->lf) - getlfsize(lf); + // lf greater than 2 sizes bigger than us? + if (sizediff >= 2) { + if (xray && *xray) { + (*xray) -= (sizediff-1); + if (*xray < 0) *xray = 0; + } else return B_FALSE; + } } } @@ -2091,6 +2108,16 @@ int check_rest_ok(lifeform_t *lf) { return B_FALSE; } +lifeform_t *clonelf(lifeform_t *src, cell_t *where) { + lifeform_t *lf; + lf = addmonster(where, src->race->id, NULL, B_FALSE, 1, B_FALSE, NULL); + if (lf) { + killflagsofid(lf->flags, F_XPVAL); + addflag(lf->flags, F_XPVAL, 0, NA, NA, NULL); + } + return lf; +} + // how dangerous is lf2 to lf1? // < 0 = harder // > 0 = easier @@ -2361,9 +2388,11 @@ int demandbribe(lifeform_t *lf) { void die(lifeform_t *lf) { char buf[BUFLEN]; flag_t *f; + int killedgod = B_FALSE; cell_t *where; //int dropobs = B_TRUE; int vaporised = B_FALSE, i; + int dropobs = B_TRUE; int willbecomeghost = B_FALSE; object_t *corpse = NULL; flag_t *retflag[MAXCANDIDATES]; @@ -2413,6 +2442,21 @@ void die(lifeform_t *lf) { return; } + // a god died? + if (getraceclass(lf) == RC_GOD) { + flag_t *f; + // update godlf pointer + for (i = 0; i < ngodlfs; i++) { + if (godlf[i] == lf) { + godlf[i] = NULL; + break; + } + } + f = hasflag(lf->flags, F_GODOF); + addflag(player->flags, F_WINNER, WT_GOD, lf->race->id, NA, f->text); + killedgod = B_TRUE; + } + if (!willbecomeghost) { if (isplayer(lf) && hasjob(lf, J_GOD)) { char ch; @@ -2591,9 +2635,9 @@ void die(lifeform_t *lf) { awardxpfor(lf,100); if ((getalignment(lf) == AL_EVIL) || isundead(lf)) { pleasegodmaybe(R_GODPURITY, 5); - pleasegodmaybe(R_GODLIFE, 5); + pleasegodmaybe(R_GODLIFE, 10); } else if (getalignment(lf) == AL_GOOD) { - pleasegodmaybe(R_GODDEATH, 3); + pleasegodmaybe(R_GODDEATH, 5); } else { // ie. neutral pleasegodmaybe(R_GODDEATH, 1); } @@ -2638,10 +2682,14 @@ void die(lifeform_t *lf) { } } + if (lfhasflag(lf, F_PHANTASM)) { + dropobs = B_FALSE; + } + // drop/kill all objects if (corpsecell && (willbecomeghost || !isplayer(lf))) { while (lf->pack->first) { - if (vaporised) { + if (vaporised || !dropobs) { killob(lf->pack->first); } else { object_t *droppedob; @@ -2737,6 +2785,11 @@ void die(lifeform_t *lf) { copyflag(corpse->flags, lf->flags, F_KNOWSABOUT); copyflag(corpse->flags, lf->flags, F_HOMEMAP); + f = hasflag(corpse->flags, F_CORPSEOF); + if (f) { + f->val[1] = lf->level; + } + // some corpses will regenerate... if (copyflag(corpse->flags, lf->flags, F_REVIVETIMER)) { killflagsofid(corpse->flags, F_OBHPDRAIN); @@ -2832,7 +2885,6 @@ void die(lifeform_t *lf) { } } - if (willbecomeghost) { flag_t *f, *nextf; // remove all job flags @@ -2865,6 +2917,10 @@ void die(lifeform_t *lf) { if (needredraw) { drawscreen(); } + + if (killedgod) { + wingame(); + } } void dumplf(void) { @@ -3673,7 +3729,7 @@ int eat(lifeform_t *lf, object_t *o) { if (fid != F_NONE) { // lose half your max hp! losehp_real(lf, (lf->maxhp/2), DT_DIRECT, NULL, "the shock of mutation", - B_FALSE, o, B_FALSE); + B_FALSE, o, B_FALSE, NULL); if (isplayer(lf)) { msg("^%cYou convulse in agony as your body mutates!", getlfcol(lf, CC_BAD)); @@ -4535,6 +4591,7 @@ int fallasleep(lifeform_t *lf, enum SLEEPTYPE how, int howlong) { } loseconcentration(lf); interrupt(lf); + breakgrabs(lf, B_TRUE, B_FALSE); // falling asleep while flying = fall! fall_from_air(lf); @@ -7236,13 +7293,15 @@ int getattacks(lifeform_t *lf, int *min, int *max) { } // if we have high unarmed skill and our second hand is free, - // we get one more attack - if (lfhasflag(lf, F_HUMANOID)) { - if (getskill(lf, SK_UNARMED) >= PR_SKILLED) { - if (hasbp(lf, BP_SECWEAPON) && !getequippedob(lf->pack, BP_SECWEAPON)) { - maxattacks++; - } - } + // AND we only had 1 attack before, we get one more attack + if (maxattacks < 2) { + if (lfhasflag(lf, F_HUMANOID)) { + if (getskill(lf, SK_UNARMED) >= PR_SKILLED) { + if (hasbp(lf, BP_SECWEAPON) && !getequippedob(lf->pack, BP_SECWEAPON)) { + maxattacks++; + } + } + } } if (getskill(lf, SK_TWOWEAPON) && isdualweilding(lf)) { @@ -7333,7 +7392,10 @@ int getmaxmp(lifeform_t *lf) { float getmaxpushweight(lifeform_t *lf) { float max; - max = getlfweight(lf, B_NOOBS) * 2; // twice your body weight + int pct; + pct = 100 + getstatmod(lf, A_STR); + max = getlfweight(lf, B_NOOBS); // your body weight + max = pctof(pct, max); return max; } @@ -9076,9 +9138,10 @@ void givejob(lifeform_t *lf, enum JOB jobid) { // now give start obs/skills from it givestartskills(lf, lf->flags); - givestartobs(lf, NULL, lf->flags); - autoskill(lf); - + if (!lfhasflag(lf, F_PHANTASM)) { + givestartobs(lf, NULL, lf->flags); + autoskill(lf); + } // override hp/mp from race /* @@ -9419,8 +9482,8 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { newf = addtempflag(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL, FROMSKILL); } - // learning a new spell school skill will grant you a random first level spell from - // that school. (player and allies only) + // learning a new spell school skill after the game has started will grant + // you a random first level spell from that school. (player and allies only) if (isspellskill(id) && (gamemode == GM_GAMESTARTED)) { if (isplayer(lf) || areallies(player, lf)) { enum OBTYPE oid; @@ -9565,7 +9628,17 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { } } else if (id == SK_TWOWEAPON) { if (f->val[1] == PR_EXPERT) { - addflag(lf->flags, F_CANWILL, OT_A_FLURRY, NA, NA, "pw:1;"); + newf = hasflagval(lf->flags, F_CANWILL, OT_A_FLURRY, NA, NA, NULL); + if (!newf) { + newf = addtempflag(lf->flags, F_CANWILL, OT_A_FLURRY, NA, NA, "pw:1;", FROMSKILL); + } + } + } else if (id == SK_UNARMED) { + if (f->val[1] == PR_EXPERT) { + newf = hasflagval(lf->flags, F_CANWILL, OT_A_FLIP, NA, NA, NULL); + if (!newf) { + newf = addtempflag(lf->flags, F_CANWILL, OT_A_FLIP, NA, NA, NULL, FROMSKILL); + } } } else if (id == SK_SS_ALLOMANCY) { // give all allomantic spells @@ -12122,9 +12195,18 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { *amt -= rnd(1,f->val[0]); } + // gods can't die unless they are in the realm of gods if (lf->race->raceclass->id == RC_GOD) { - // immortal - limit(amt, 0, lf->hp-1); + int damok = B_FALSE; + if (lf->cell->map->habitat->id == H_HEAVEN) { + if (hasob(player->pack, getrelatedgodstone(lf->race->id)) ) { + damok = B_TRUE; + } + } + if (!damok) { + // immortal + limit(amt, 0, lf->hp-1); + } } else { limit(amt, 0, NA); } @@ -12441,23 +12523,32 @@ int askforinfo(lifeform_t *lf, int diffmod) { } else { // they will consider it - now negotiate a price f = lfhasflag(lf, F_INFOPRICE); - if (f) { + if (f) { // already got a price in mind? askingprice = f->val[0]; } else { int result; int difficulty; + int greedy = B_FALSE; + + // delvers are greedy, so they'll nearly always help, but + // nearly always want money too! + if ((lf->race->id == R_DWARF) && (player->race->id != R_DWARF)) { + greedy = B_TRUE; + diffmod += 15; + } difficulty = 20 + diffmod + ((gethitdice(player) - gethitdice(lf))*2); if (real_skillcheck(player, SC_SPEECH, difficulty, alignmod, &result)) { askingprice = 0; // passed - free! } else { - if (difficulty - result >= 10) { + if (!greedy && (difficulty - result >= 10)) { // will not help! askingprice = -1; } else { // will help for gold askingprice = rnd(gethitdice(lf)*5, gethitdice(lf)*15 ); + limit(&askingprice, 1, NA); // just in case } } @@ -13072,13 +13163,22 @@ void loseconcentration(lifeform_t *lf) { interrupt(lf); } +void loseconsciousness(lifeform_t *lf, int howlong, lifeform_t *fromlf) { + if (!isunconscious(lf)) { + fallasleep(lf, ST_KO, rnd(50,100)); + if (fromlf && isplayer(fromlf)) { + pleasegodmaybe(R_GODMERCY, 5); + } + } +} + // lose hp, and adjust damage based on resistances int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc) { - return losehp_real(lf, amt, damtype, fromlf, damsrc, B_TRUE, NULL, B_TRUE); + return losehp_real(lf, amt, damtype, fromlf, damsrc, B_TRUE, NULL, B_TRUE, NULL); } // returns the amt of damage taken -int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate) { +int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate, int *waskod) { char buf[BUFLEN]; char buf2[BUFLEN]; char lfname[BUFLEN]; @@ -13173,7 +13273,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // methods of knocking unconscious if (!isundead(lf)) { // merciful weapons - if (fromob) { + if (!ko && fromob) { f = hasflag(fromob->flags, F_MERCIFUL); if (f && (amt >= lf->hp)) { ko = B_TRUE; @@ -13205,10 +13305,14 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml if (damtypeok) { if (playerinvolved && godprayedto(R_GODMERCY)) { threshold = -10; - kochance = 75; + if (isplayer(lf)) { + kochance = 75; + } else { + kochance = 50; + } } else { threshold = -5; - kochance = 50; + kochance = 30; } } @@ -13232,7 +13336,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } } - // just knock them out. + // just knock them out, don't kill. if (ko) { amt = lf->hp - 1; // ie end up at 1hp } @@ -13265,8 +13369,19 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } } - // take damage - lf->hp -= amt; + + // phantasms have a fake hp counter + f = lfhasflag(lf, F_PHANTASM); + if (f) { + f->val[0] -= amt; + // they die when their FAKE hp drops below 0 + if (f->val[0] <= 0) { + lf->hp = 0; + } + } else { + // take damage + lf->hp -= amt; + } // fill in lastdam... lf->lastdamtype = damtype; @@ -13430,13 +13545,18 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } if (ko) { - if (!isunconscious(lf)) { - // you are knocked unconscious for a _long_ time - fallasleep(lf, ST_KO, rnd(50,100)); - breakgrabs(lf, B_TRUE, B_FALSE); - if (fromlf && isplayer(fromlf)) { - pleasegodmaybe(R_GODMERCY, 5); - } + int kotime; + // is waskod was passed, allow the calling function to actually + // knock us unconscious. + // + // this is mainly used in attack.c, so that we can announce + // "you hit xxx. xxx loses consciousness." as opposed to + // "xxx loses consciousness. you hit xxx." which makes no sense! + kotime = rnd(50,100); + if (waskod) { + *waskod = kotime; + } else { + loseconsciousness(lf, kotime, fromlf); } } else { // you wake up if you were hit, unless you were unconscious! @@ -14003,8 +14123,9 @@ void modstamina(lifeform_t *lf, float howmuch) { if (howmuch == 0) return; - // you don't lose stamina while enraged + // you don't lose stamina while enraged or caffeinated if (lfhasflag(lf, F_RAGE) && (howmuch < 0)) return; + if (lfhasflag(lf, F_CAFFEINATED) && (howmuch < 0)) return; if (isplayer(lf)) { if (howmuch < 0) { @@ -14377,11 +14498,13 @@ void outfitlf(lifeform_t *lf) { // make 'lf' into a pet/ally of 'owner' void petify(lifeform_t *lf, lifeform_t *owner) { - makefriendly(lf, PERMENANT); + if (isplayer(owner)) { + makefriendly(lf, PERMENANT); + killflagsofid(lf->flags, F_NOINFO); + killflagsofid(lf->flags, F_INFOPRICE); + } addflag(lf->flags, F_PETOF, owner->id, owner->cell->x, owner->cell->y, NULL); killflagsofid(lf->flags, F_STAYINROOM); - killflagsofid(lf->flags, F_NOINFO); - killflagsofid(lf->flags, F_INFOPRICE); } @@ -15437,6 +15560,44 @@ int say(lifeform_t *lf, char *text, int volume) { char hearbuf[BUFLEN]; char verb[BUFLEN]; char noun[BUFLEN]; + char *localtext; + int rv; + + localtext = strdup(text); + + // adjust text and volume for gods + if (lf) { + switch (lf->race->id) { + case R_GODMAGIC: + volume = SV_TALK; + strrep(localtext, "You have", "One has", NULL); + strrep(localtext, "You", "One", NULL); + strrep(localtext, "you", "one", NULL); + break; + case R_GODTHIEVES: + case R_GODDEATH: + volume = SV_WHISPER; + break; + case R_GODFIRE: + volume = SV_TRUCK; + makeuppercase(localtext); + break; + case R_GODPURITY: + case R_GODLIFE: + case R_GODMERCY: + case R_GODNATURE: + volume = SV_TALK; + break; + case R_GODBATTLE: + if (localtext[strlen(localtext)-1] == '.') { + localtext[strlen(localtext)-1] = '!'; + } + volume = SV_SHOUT; + break; + default: break; + } + } + if (volume < 2) { strcpy(verb, "whispers"); strcpy(noun, "a whisper:"); @@ -15454,10 +15615,12 @@ int say(lifeform_t *lf, char *text, int volume) { strcpy(noun, "a bellow:"); } - snprintf(seebuf, BUFLEN, "%s \"%s\"", verb, text); - snprintf(hearbuf, BUFLEN, "%s \"%s\"", noun, text); + snprintf(seebuf, BUFLEN, "%s \"%s\"", verb, localtext); + snprintf(hearbuf, BUFLEN, "%s \"%s\"", noun, localtext); - return noise(lf->cell, lf, NC_SPEECH, volume, hearbuf, seebuf); + rv = noise(lf->cell, lf, NC_SPEECH, volume, hearbuf, seebuf); + free(localtext); + return rv; } // volume = -1 means "auto" @@ -17175,6 +17338,7 @@ void startlfturn(lifeform_t *lf) { // god piety gets restored over time if (isplayer(lf)) { for (i = 0; i < ngodlfs; i++) { + if (!godlf[i]) continue; if (getpietylev(godlf[i]->race->id, NULL, NULL) == PL_TOLERATED) { // slowly tick upwards if (onein(2)) modpiety(godlf[i]->race->id, 1); @@ -17958,6 +18122,20 @@ void startlfturn(lifeform_t *lf) { } } } // end loop through lf flags + + // picked up your first godstone ? + if (isplayer(lf)) { + o = hasobofclass(lf->pack, OC_GODSTONE); + if (o && !lfhasflag(lf, F_FOUNDGODSTONE)) { + lifeform_t *god,*opposegod; + // get linked gods + f = hasflag(o->flags, F_LINKGOD); + god = findgod(f->val[0]); + opposegod = findgod(getopposinggod(god->race->id)); + godstone_pickup_effects(god, opposegod, o); + addflag(lf->flags, F_FOUNDGODSTONE, B_TRUE, NA, NA, NULL); + } + } } // returns TRUE on failure (ie. nothing to steal) @@ -18791,7 +18969,7 @@ int touch(lifeform_t *lf, object_t *o) { } else { // wearing gloves? they get damaged. if (gloves) { - if (f->id == F_ONFIRE) { + if (f->id == F_ONFIRE) { // fire will damage your gloves, just being hot will not. takedamage(gloves, 2, DT_FIRE); if (hasflag(gloves->flags, F_DEAD)) { gloves = NULL; @@ -19615,6 +19793,50 @@ int resizelf(lifeform_t *lf, enum LFSIZE newsize) { return B_FALSE; } +lifeform_t *ressurect(object_t *o) { + flag_t *f; + race_t *r; + lifeform_t *lf; + cell_t *where; + int level = 1; + char obname[BUFLEN]; + + if (o->type->id != OT_CORPSE) return NULL; + if (hasflag(o->flags, F_HEADLESS)) return NULL; + + f = hasflag(o->flags, F_CORPSEOF); + if (f) { + level = f->val[1]; + } else { + return NULL; + } + + r = findrace(f->val[0]); + if (!r) return NULL; + + where = getoblocation(o); + getobname(o, obname, 1); + + if (!cellwalkable(NULL, where, NULL)) { + where = getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND); + } + if (!where) return NULL; + + lf = addlf(where, r->id, level); + + // remove the corpse object + removeob(o,o->amt); + + // redraw & announce + if (haslos(player, where)) { + needredraw = B_TRUE; + drawscreen(); + msg("%s is restored to life!", obname); + } + + return lf; +} + int rest(lifeform_t *lf, int onpurpose) { flag_t *f; flag_t *ff; @@ -20134,7 +20356,6 @@ int wear(lifeform_t *lf, object_t *o) { } if ((gamemode == GM_GAMESTARTED) && lf->created) { - if (isplayer(lf)) { // announce if (showpos) { diff --git a/lf.h b/lf.h index eb47313..de0d7cb 100644 --- a/lf.h +++ b/lf.h @@ -69,6 +69,7 @@ int checkburdened(lifeform_t *lf, int preburdened); int checkfordrowning(lifeform_t *lf, object_t *o); int check_rest_ok(lifeform_t *lf); //void checkxp(enum RACE rid); +lifeform_t *clonelf(lifeform_t *src, cell_t *where); float comparelfs(lifeform_t *lf1, lifeform_t *lf2); int confuse(lifeform_t *lf, int howlong); void copycorpseflags(flagpile_t *dst, flagpile_t *src); @@ -348,8 +349,9 @@ flag_t *levelabilityready(lifeform_t *lf); int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo); int loadfirearmfast(lifeform_t *lf, int onpurpose); void loseconcentration(lifeform_t *lf); +void loseconsciousness(lifeform_t *lf, int howlong, lifeform_t *fromlf); int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc); -int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate); +int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate, int *waskod); void losemp(lifeform_t *lf, int amt); void makefriendly(lifeform_t *lf, int howlong); int makenauseated(lifeform_t *lf, int amt, int howlong); @@ -386,6 +388,7 @@ int recruit(lifeform_t *lf); void refreshlevelabilities(lifeform_t *lf); void relinklf(lifeform_t *src, map_t *dst); int resizelf(lifeform_t *lf, enum LFSIZE newsize); +lifeform_t *ressurect(object_t *o); int rest(lifeform_t *lf, int onpurpose); void setskillused(lifeform_t *lf, enum SKILL skid); void spot_hiding_lf(lifeform_t *lf, lifeform_t *hider); diff --git a/move.c b/move.c index 9e0ebcf..6c4d768 100644 --- a/move.c +++ b/move.c @@ -2525,15 +2525,34 @@ void standup(lifeform_t *lf) { // monsters don't take time to stand up if they were feigning death! if (!isplayer(lf) && lfhasflag(lf, F_FEIGNINGDEATH)) { } else { - int howlong; + int baseunits = 0,armourunits = 0,totunits = 0,howlong; float quartermax; - int units; - // time to get up depends on armour + enum LFSIZE sz; + // time to get up depends on size and armour + + // base time depends on size + sz = getlfsize(lf); + if (sz < SZ_HUMAN) { + baseunits = 0; + } else if (sz == SZ_HUMAN) { + baseunits = 1; + } else if (sz == SZ_LARGE) { + baseunits = 2; + } else { // ie. SZ_HUGE or larger + baseunits = 3; + } + // 1*movespeed for every 1/4 of maxcarryweight being worn. quartermax = getmaxcarryweight(lf) / 4; - units = (getequippedweight(lf) / quartermax)+1; - howlong = getmovespeed(lf)*units; - taketime(lf, howlong); + if (quartermax > 0) { + armourunits = (getequippedweight(lf) / quartermax); + } + totunits = baseunits + armourunits; + howlong = getmovespeed(lf) * totunits; + + if (howlong > 0) { + taketime(lf, howlong); + } } } diff --git a/nexus.c b/nexus.c index 2d39e22..3f22ca2 100644 --- a/nexus.c +++ b/nexus.c @@ -98,6 +98,7 @@ int gameover; int obdb = B_FALSE; enum GAMEMODE gamemode = GM_FIRST; +enum WINGAMETYPE wintype = WT_NONE; long curtime = 0; // # current game clock (in seconds) long gamedays = 0; // # game days passed since start of game @@ -360,7 +361,6 @@ int main(int argc, char **argv) { addchoice(&prompt, 'w', getskillname(SK_SS_WILD), NULL, findskill(SK_SS_WILD), NULL); getchoice(&prompt); sk = (skill_t *) prompt.result; - giveskilllev(player, sk->id, PR_NOVICE); switch (sk->id) { case SK_SS_AIR: addflag(player->flags, F_CANSEETHROUGHMAT, MT_GAS, NA, NA, NULL); @@ -396,7 +396,6 @@ int main(int argc, char **argv) { addchoice(&prompt, 't', getskillname(SK_SS_TRANSLOCATION), NULL, findskill(SK_SS_TRANSLOCATION), NULL); getchoice(&prompt); sk = (skill_t *) prompt.result; - giveskilllev(player, sk->id, PR_NOVICE); switch (sk->id) { case SK_SS_DIVINATION: sb2 = addob(player->pack, "spellbook of divination magic"); @@ -685,9 +684,14 @@ void checkdeath(void) { void checkendgame(void) { + flag_t *f; if (!player->alive) { gamemode = GM_GAMEOVER; gameover = B_TRUE; + } else if ((f = lfhasflag(player, F_WINNER)) != NULL) { + gamemode = GM_GAMEOVER; + gameover = B_TRUE; + wintype = f->val[0]; } } diff --git a/objects.c b/objects.c index 9401775..45053fb 100644 --- a/objects.c +++ b/objects.c @@ -1264,6 +1264,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } else { if (gamemode == GM_GAMESTARTED) { msg("DB: created abandoned temple"); more(); + dblog("DB: created abandoned temple"); + raise(SIGINT); } } } @@ -1496,7 +1498,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes o->material = corpserace->material; // remember the race type - addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); + addflag(o->flags, F_CORPSEOF, corpserace->id, 1, NA, NULL); // override ot_corpse nutrition flag based on race's size rf = hasflag(corpserace->flags, F_SIZE); @@ -1572,7 +1574,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes o->weight = corpserace->weight * ratio; // remember the race type - addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); + addflag(o->flags, F_CORPSEOF, corpserace->id, 1, NA, NULL); // set impassable size f = hasflag(o->flags, F_IMPASSABLE); @@ -1607,7 +1609,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes o->material = corpserace->material; // remember the race type - addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); + addflag(o->flags, F_CORPSEOF, corpserace->id, 1, NA, NULL); // override ot_corpse nutrition flag based on race's size rf = hasflag(corpserace->flags, F_SIZE); @@ -1635,7 +1637,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes o->weight = corpserace->weight / 2; // remember the race type - addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); + addflag(o->flags, F_CORPSEOF, corpserace->id, 1, NA, NULL); // override ot_roastmeat nutrition flag based on race's size rf = hasflag(corpserace->flags, F_SIZE); @@ -2100,7 +2102,7 @@ recipe_t *addrecipe(enum OBTYPE result, ...) { void adjustdamhardness(int *dam, enum DAMTYPE damtype, enum MATERIAL mat) { // now check for hardness - if (isphysicaldam(damtype)) { + if (ismeleedam(damtype)) { *dam -= gethardness(mat); if (*dam < 0) *dam = 0; /* @@ -9107,12 +9109,42 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { c = getcellat(lf->cell->map, x, y); if (c && c->lf && (c->lf != lf) && haslof(lf->cell, c, LOF_NEED, NULL)) { int howlong = 50; + // create fire + addobfast(c->obpile, OT_FIRELARGE); + // enrage addtempflag(c->lf->flags, F_RAGE, B_TRUE, NA, NA, NULL, howlong); if (!isplayer(c->lf)) { addtempflag(c->lf->flags, F_HATESALL, B_TRUE, NA, NA, NULL, howlong); loseaitargets(c->lf); } - + } + } + } + break; + case OT_GODSTONEL: // life + // everything in sight is restored + // all corpses in sight are revived + // everyone in lof gets f_rage, and hates everything + for (y = 0; y < lf->cell->map->h; y++) { + for (x = 0; x < lf->cell->map->w; x++) { + cell_t *c; + c = getcellat(lf->cell->map, x, y); + if (c && haslof(lf->cell, c, LOF_NEED, NULL)) { + if (c->lf) { + // restore + dospelleffects(NULL, OT_S_RESTORATION, 1, + c->lf, NULL, c->lf->cell, B_BLESSED, NULL, B_TRUE); + } else { + object_t *oo, *nextoo; + // revive corpses + for (oo = c->obpile->first ; oo ; oo = nextoo) { + nextoo = oo->next; + if (oo->type->id == OT_CORPSE) { + dospelleffects(NULL, OT_S_RESSURECTION, 1, + NULL, oo, c, B_BLESSED, NULL, B_TRUE); + } + } + } } } } @@ -10001,7 +10033,6 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE int amt; int failed; int seenbyplayer; - int hpheal,mpheal; flag_t *f; if (isplayer(lf)) { @@ -10276,43 +10307,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } break; case OT_POT_RESTORATION: - failed = B_TRUE; - for (i = 0; i < MAXATTS; i++ ){ - if (getattr(lf,i) < lf->baseatt[i]) { - setattr(lf, i, lf->baseatt[i]); - failed = B_FALSE; - } - } - // fix diseases (even magical ones) - killflagsofid(lf->flags, F_POISONED); - // blessed restores hp/mp to full - if (potblessed == B_BLESSED) { - hpheal = lf->maxhp; - mpheal = getmaxmp(lf); - } else if (potblessed == B_CURSED) { - hpheal = lf->maxhp / 3; - mpheal = getmaxmp(lf) / 3; - } else { - hpheal = lf->maxhp / 2; - mpheal = getmaxmp(lf) / 2; - } - if (lf->hp < hpheal) { - gainhp(lf, hpheal - lf->hp); - if (!isplayer(lf) && cansee(player, lf)) { - msg("%s%s health has been restored!", lfname, getpossessive(lfname)); - } - failed = B_FALSE; - } - if (lf->mp < mpheal) { - gainmp(lf, mpheal - lf->mp); - failed = B_FALSE; - } - - if (failed) { - if (isplayer(lf)) msg("You feel momentarily restored."); - } else { - if (isplayer(lf)) msg("You feel restored!"); - } + dospelleffects(NULL, OT_S_RESTORATION, 1, lf, NULL, lf->cell, potblessed, NULL, B_TRUE); break; case OT_POT_SANCTUARY: // how long for? @@ -11740,7 +11735,7 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce) { // now use the REAL name real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_TRUE); - losehp_real(owner, howmuch , damtype, NULL, obname, B_TRUE, o, B_FALSE); + losehp_real(owner, howmuch , damtype, NULL, obname, B_TRUE, o, B_FALSE, NULL); if (isdead(owner)) { return howmuch; } @@ -12636,7 +12631,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp if (thrower && (thrower->cell == srcloc)) { whogetsxp = thrower; } - losehp_real(target, dam, DT_PROJECTILE, whogetsxp, damstring, B_TRUE, o, B_TRUE); + losehp_real(target, dam, DT_PROJECTILE, whogetsxp, damstring, B_TRUE, o, B_TRUE, NULL); } if (reduceamt && (speed >= 3)) { diff --git a/shops.c b/shops.c index b34632d..ceaa557 100644 --- a/shops.c +++ b/shops.c @@ -411,7 +411,7 @@ enum SHOPRETURN shopdonate(lifeform_t *lf, object_t *vm, int starty, char *topte default: wantflag = F_NONE; wantoc = OC_NONE; break; } */ - o = doaskobject(lf->pack, "What will you donate?", &count, B_TRUE, B_FALSE, B_FALSE, '\0', vm, AO_NONE, F_NONE); + o = doaskobject(lf->pack, "What will you donate?", &count, B_TRUE, B_FALSE, B_FALSE, '\0', vm, MT_NOTHING, AO_NONE, F_NONE); // validate it if (o) { @@ -800,7 +800,7 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top // you got it! buyit = B_TRUE; usecharges(money, value); - strcpy(buytext, "Charged to card:"); + strcpy(buytext, "Charged to card"); if (npurchased) (*npurchased)++; } else { // maxed! @@ -1034,7 +1034,7 @@ enum SHOPRETURN shoprest(lifeform_t *lf, object_t *vm, int starty, char *toptext y = starty; - cost = applyshoppricemod(100, lf, vm, SA_BUY); + cost = applyshoppricemod(10, lf, vm, SA_BUY); mvwprintw(mainwin, y, 0, "We offer good quality rooms for only $%d per hour.", cost); y += 2; @@ -1107,7 +1107,7 @@ enum SHOPRETURN shopsell(lifeform_t *lf, object_t *vm, int starty, char *toptext // ask what to sell sprintf(buf, "What will you sell (you have $%d)?", countmoney(lf->pack)); - o = doaskobject(player->pack, buf, &count, B_TRUE, B_FALSE, B_FALSE, '\0', vm, AO_NONE, F_NONE); + o = doaskobject(player->pack, buf, &count, B_TRUE, B_FALSE, B_FALSE, '\0', vm, MT_NOTHING, AO_NONE, F_NONE); if (!o) { return SR_BACK; } diff --git a/spell.c b/spell.c index aada29a..afc7011 100644 --- a/spell.c +++ b/spell.c @@ -45,9 +45,6 @@ extern object_t *retobs[MAXPILEOBS+1]; extern int retobscount[MAXPILEOBS+1]; extern int nretobs; -extern lifeform_t *godlf[]; -extern int ngodlfs; - extern enum ERROR reason; extern int needredraw, statdirty; @@ -3674,6 +3671,60 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster)) { msg("You create a alarm field around yourself."); } + } else if (spellid == OT_S_ALCHEMY) { + char obname[BUFLEN]; + char obtocreate[BUFLEN]; + obpile_t *op; + object_t *newob = NULL; + int obvalue,obamt; + // needs: + // object = which object to convert + if (!targob && isplayer(caster)) { + targob = doaskobject(caster->pack, "Convert which object to gold", NULL, B_FALSE, B_FALSE, B_FALSE, '\0', NULL, MT_METAL, AO_NONE, F_NONE); + } + if (!targob) { + fizzle(caster); + return B_TRUE; + } + op = targob->pile; + obamt = targob->amt; + getobname(targob, obname, targob->amt); + obvalue = getobvalue(targob); + obvalue = pctof(power*10, obvalue); + limit(&obvalue, 0, NA); + // original object vanishes. + killob(targob); + // create new object + if (obvalue > 0) { + if (op->owner) { + newob = hasob(op, OT_GOLD); + if (newob) { + newob->amt += obvalue; + } else { + sprintf(obtocreate, "%d gold coins", obvalue); + newob = addob(op, obtocreate); + } + } else { + sprintf(obtocreate, "%d gold coins", obvalue); + newob = addob(op, obtocreate); + } + } + + // announce + if (isplayer(op->owner) || (op->where && haslos(player, op->where)) ) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + if (newob) { + char newobname[BUFLEN]; + msg("%s change%s into %d gold coin%s!", obname, (obamt == 1) ? "s" : "", obvalue, (obvalue == 1) ? "" : "s"); + if (newob->pile->owner && isplayer(newob->pile->owner)) { + getobname(newob, newobname, newob->amt); + msgnocap("%c - %s", newob->letter, newobname); + } + } else { + msg("%s vanishes!", obname); + if (isplayer(caster)) angergodmaybe(R_GODNATURE, 10, GA_ATTACKOBJECT); + } + } } else if (spellid == OT_S_ANIMATEDEAD) { int i; object_t *o,*nexto; @@ -4137,6 +4188,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ initprompt(&prompt, "Confiscate which object?"); addchoice(&prompt, '-', "(Cancel)", NULL, NULL, NULL); for (o = target->pack->first ; o ; o = o->next) { + if (o->type->obclass->id == OC_GODSTONE) continue; getobname(o, obname, o->amt); addchoice(&prompt, ch, obname, NULL, o, NULL); if (ch == 'z') { @@ -4145,7 +4197,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ ch++; } } - if (isplayer(caster)) { + if (isplayer(caster) && (power > 1)) { // select one getchoice(&prompt); targob = (object_t *)prompt.result; @@ -4420,7 +4472,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } // end while narccells } else if (spellid == OT_S_CLONE) { - lifeform_t *lf; // duplicate the caster targcell = getrandomadjcell(caster->cell, WE_WALKABLE, B_NOEXPAND); if (!targcell) { @@ -4430,11 +4481,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster) || haslos(player, targcell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } - lf = addmonster(targcell, caster->race->id, NULL, B_FALSE, 1, B_FALSE, NULL); - if (lf) { - killflagsofid(lf->flags, F_XPVAL); - addflag(lf->flags, F_XPVAL, 0, NA, NA, NULL); - } + clonelf(caster, targcell); } else if (spellid == OT_S_CLOUDKILL) { int radius; @@ -6547,54 +6594,59 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int donesomething = B_FALSE,i; flag_t *retflag[MAXCANDIDATES]; int nretflags; + int undead = B_FALSE; target = targcell->lf; if (!target) { fizzle(caster); return B_TRUE; } - // cure certain bad effects - if (killflagsofid(target->flags, F_PAIN)) { - donesomething = B_TRUE; - } - getflags(target->flags, retflag, &nretflags, F_POISONED, F_NONE); - for (i = 0; i < nretflags; i++) { - poisontype_t *pt; - pt = findpoisontype(retflag[i]->val[0]); - if (pt->severity == PS_CURSE) { - } else { - killflag(retflag[i]); - donesomething = B_TRUE; - if (seenbyplayer) *seenbyplayer = B_TRUE; - } - } + undead = isundead(target); - if (!lfhasflagval(target, F_POISONED, P_ROT, NA, NA, NULL)) { - // severed body parts - getflags(target->flags, retflag, &nretflags, F_INJURY, F_NOBODYPART, F_NONE); + // cure certain bad effects + if (!undead) { + if (killflagsofid(target->flags, F_PAIN)) { + donesomething = B_TRUE; + } + getflags(target->flags, retflag, &nretflags, F_POISONED, F_NONE); for (i = 0; i < nretflags; i++) { - enum BODYPART bpgone = BP_NONE; - if ((retflag[i]->id == F_NOBODYPART) && (retflag[i]->val[1] == B_FROMINJURY)) { - bpgone = retflag[i]->val[0]; - } else if ((retflag[i]->id == F_INJURY) && (retflag[i]->lifetime == PERMENANT)) { // permenant injury - bpgone = retflag[i]->val[1]; + poisontype_t *pt; + pt = findpoisontype(retflag[i]->val[0]); + if (pt->severity == PS_CURSE) { + } else { + killflag(retflag[i]); + donesomething = B_TRUE; + if (seenbyplayer) *seenbyplayer = B_TRUE; } - if (bpgone != BP_NONE) { - if (isplayer(target)) { - msg("Your %s grows back!", getbodypartname(target, bpgone)); - if (seenbyplayer) *seenbyplayer = B_TRUE; - } else if (cansee(player, target)) { - char targname[BUFLEN]; - getlfname(target, targname); - msg("%s%s %s grows back!", targname, getpossessive(targname), - getbodypartname(target, bpgone)); - if (seenbyplayer) *seenbyplayer = B_TRUE; + } + + if (!lfhasflagval(target, F_POISONED, P_ROT, NA, NA, NULL)) { + // severed body parts + getflags(target->flags, retflag, &nretflags, F_INJURY, F_NOBODYPART, F_NONE); + for (i = 0; i < nretflags; i++) { + enum BODYPART bpgone = BP_NONE; + if ((retflag[i]->id == F_NOBODYPART) && (retflag[i]->val[1] == B_FROMINJURY)) { + bpgone = retflag[i]->val[0]; + } else if ((retflag[i]->id == F_INJURY) && (retflag[i]->lifetime == PERMENANT)) { // permenant injury + bpgone = retflag[i]->val[1]; + } + if (bpgone != BP_NONE) { + if (isplayer(target)) { + msg("Your %s grows back!", getbodypartname(target, bpgone)); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (cansee(player, target)) { + char targname[BUFLEN]; + getlfname(target, targname); + msg("%s%s %s grows back!", targname, getpossessive(targname), + getbodypartname(target, bpgone)); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + killflag(retflag[i]); + donesomething = B_TRUE; + } else if ((retflag[i]->id == F_INJURY) && (retflag[i]->lifetime > 0)) { + killflag(retflag[i]); + donesomething = B_TRUE; } - killflag(retflag[i]); - donesomething = B_TRUE; - } else if ((retflag[i]->id == F_INJURY) && (retflag[i]->lifetime > 0)) { - killflag(retflag[i]); - donesomething = B_TRUE; } } } @@ -6617,47 +6669,55 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ break; } amt = getspellduration(min,max,blessed) + (power*2); - if (lfhasflagval(target, F_POISONED, P_ROT, NA, NA, NULL)) { + if (!undead && lfhasflagval(target, F_POISONED, P_ROT, NA, NA, NULL)) { amt /= 10; } if (amt > 0) { - gainhp(target, amt); - if (isplayer(target)) { - if (target->hp >= target->maxhp) { - switch (spellid) { - case OT_S_HEALINGMIN: - msg("All of your scrapes and bruises are healed!"); - break; - case OT_S_HEALING: - default: - msg("Your wounds close themselves!"); - break; - case OT_S_HEALINGMAJ: - msg("Your injuries are healed!"); - break; - } - } else { - switch (spellid) { - case OT_S_HEALINGMIN: - msg("Some of your scrapes and bruises are healed!"); - break; - case OT_S_HEALING: - default: - msg("Some of your wounds close themselves!"); - break; - case OT_S_HEALINGMAJ: - msg("Your injuries are partially healed!"); - break; - } + if (undead) { + losehp(target, amt, DT_HOLY, caster, "the power of healing"); + if (isplayer(target) || cansee(player, target)) { + getlfname(target, buf); + msg("%s writhe%s in agony!", buf, isplayer(target) ? "" : "s"); } - if (seenbyplayer) *seenbyplayer = B_TRUE; - } else if (haslos(player, target->cell)) { - getlfname(target, buf); - msg("%s looks healthier!", buf); - if (seenbyplayer) *seenbyplayer = B_TRUE; - } + } else { + gainhp(target, amt); + if (isplayer(target)) { + if (target->hp >= target->maxhp) { + switch (spellid) { + case OT_S_HEALINGMIN: + msg("All of your scrapes and bruises are healed!"); + break; + case OT_S_HEALING: + default: + msg("Your wounds close themselves!"); + break; + case OT_S_HEALINGMAJ: + msg("Your injuries are healed!"); + break; + } + } else { + switch (spellid) { + case OT_S_HEALINGMIN: + msg("Some of your scrapes and bruises are healed!"); + break; + case OT_S_HEALING: + default: + msg("Some of your wounds close themselves!"); + break; + case OT_S_HEALINGMAJ: + msg("Your injuries are partially healed!"); + break; + } + } + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (haslos(player, target->cell)) { + getlfname(target, buf); + msg("%s looks healthier!", buf); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } // end if undead + donesomething = B_TRUE; } - donesomething = B_TRUE; } } @@ -6674,7 +6734,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ angergodmaybe(R_GODDEATH, 40, GA_HERESY); } // hostile monsters might calm down - if (!frompot && donesomething && isplayer(caster) && !isplayer(target) && (getallegiance(target) == AL_HOSTILE)) { + if (!undead && !frompot && donesomething && isplayer(caster) && !isplayer(target) && (getallegiance(target) == AL_HOSTILE)) { enum ATTRBRACKET iqb; iqb = getattrbracket(getattr(target, A_IQ), A_IQ, NULL); if ((iqb >= IQ_ANIMAL) && cansee(target, caster)) { @@ -6967,6 +7027,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ fizzle(caster); return B_TRUE; } + + if (hasobofmaterial(targcell->obpile, MT_FIRE)) { + fizzle(caster); + return B_TRUE; + } getlfname(target, targname); if (rolltohit(caster, target, NULL, NULL)) { if (isplayer(caster) || cansee(player, caster)) { @@ -7226,6 +7291,75 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ fizzle(caster); return B_TRUE; } + } else if (spellid == OT_S_MIRRORIMAGE) { + int i,ndone = 0; + int seen = B_FALSE; + for (i = 0; i < power; i++) { + lifeform_t *lf; + job_t *j; + object_t *o; + // create a mirror image + targcell = real_getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, caster); + if (!targcell) break; + lf = clonelf(caster, targcell); + if (!lf) break; + if (isplayer(caster) || cansee(player, lf)) { + seen = B_TRUE; + } + killflagsofid(lf->flags, F_CORPSETYPE); + killflagsofid(lf->flags, F_EXTRACORPSE); + addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_PHANTASM, caster->hp, NA, NA, NULL); + + // copy caster's job + j = getjob(caster); + if (j) { + givejob(lf, j->id); + } + addflag(lf->flags, F_NOTIME, B_TRUE, NA, NA, NULL); + lf->created = B_FALSE; // to avoid "the xxx puts on armour" messages + // copy caster's weapons & armour + for (o = caster->pack->first ; o ; o = o->next) { + flag_t *equipflag; + equipflag = isequipped(o); + if (equipflag) { + object_t *newob; + newob = addobfast(lf->pack,o->type->id); + if (newob) { + if (isweapon(newob) && canweild(lf, newob)) { + weild(lf, newob); + } else if (canwear(lf, newob, equipflag->val[0])) { + wear(lf, newob); + } + } + } + } + killflagsofid(lf->flags, F_NOTIME); + lf->created = B_TRUE; + + addflag(lf->flags, F_NODEATHSPEECH, B_TRUE, NA, NA, NULL); + petify(lf, caster); + setfollowdistance(lf, 1, 2); // stay close + + addflag(lf->flags, F_SUMMONEDBY, caster->id, PERMENANT, NA, NULL); + + ndone++; + } + + + if (!ndone) { + fizzle(caster); + return B_TRUE; + } else if (seen) { + char copytext[BUFLEN]; + if (ndone == 1) { + sprintf(copytext, "A duplicate"); + } else { + sprintf(copytext, "%d duplicates", ndone); + } + msg("%s of %s appear%s!", copytext, castername, (ndone == 1) ? "s" : ""); + } + } else if (spellid == OT_S_NULLIFY) { flag_t *retflag[MAXCANDIDATES],*poss[MAXCANDIDATES],*f; int nretflags,i,ndone = 0,nposs; @@ -7313,7 +7447,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int seen; if (targcell->obpile->first) { - targob = doaskobject(targcell->obpile, "Target which object", NULL, B_TRUE, B_FALSE, B_FALSE, '\0', NULL, AO_NONE, F_NONE); + targob = doaskobject(targcell->obpile, "Target which object", NULL, B_TRUE, B_FALSE, B_FALSE, '\0', NULL, MT_NOTHING, AO_NONE, F_NONE); } if (!targob) { @@ -9161,6 +9295,110 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } } + } else if (spellid == OT_S_RESSURECTION) { + lifeform_t *newlf; + if (!targob) { + // select object from cell... + targob = askobjectwithflag(targcell->obpile, "Revive which corpse", NULL, '\0', AO_NONE, F_CORPSEOF); + if (!targob) { + fizzle(caster); + return B_TRUE; + } + } + newlf = ressurect(targob); + + if (newlf) { + if (haslos(player, targcell)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } else { + fizzle(caster); + return B_TRUE; + } + } else if (spellid == OT_S_RESTORATION) { + int seen = B_FALSE; + int i,hpheal,mpheal; + int failed = B_TRUE; + char lfname[BUFLEN]; + if (!target) target = caster; + + getlfname(target, lfname); + + if (frompot) { + if (blessed == B_BLESSED) { + power = 3; + } else if (blessed == B_CURSED) { + power = 1; + } else { + power = 2; + } + } + + if (!isplayer(target) && cansee(player, target)) { + seen = B_TRUE; + } + + if (isundead(target)) { + if (seen) { + msg("%s writhe%s in agony!", lfname, isplayer(target) ? "" : "s"); + } + losehp(target, power*10, DT_HOLY, caster, "the power of restoration"); + return B_FALSE; + } + + for (i = 0; i < MAXATTS; i++ ){ + if (getattr(target,i) < target->baseatt[i]) { + setattr(target, i, target->baseatt[i]); + failed = B_FALSE; + } + } + // fix diseases (even magical ones) + if (killflagsofid(target->flags, F_POISONED)) { + failed = B_FALSE; + } + // wake up from sleep/ko + if (killflagsofid(target->flags, F_ASLEEP)) { + failed = B_FALSE; + } + // fix pain + if (killflagsofid(target->flags, F_PAIN)) { + failed = B_FALSE; + } + // fix injuries + if (killflagsofid(target->flags, F_INJURY)) { + failed = B_FALSE; + } + // blessed restores hp/mp to full + if (power == 3) { // heal ALL hp & mp + hpheal = target->maxhp; + mpheal = getmaxmp(target); + } else if (power == 2) { // heal 3/4 hp & mp + hpheal = pctof(target->maxhp, 75); + mpheal = pctof(getmaxmp(target), 75); + } else { // heal half hp & mp + hpheal = target->maxhp / 2; + mpheal = getmaxmp(target) / 2; + } + + if (target->hp < hpheal) { + gainhp(target, hpheal - target->hp); + failed = B_FALSE; + if (!isplayer(target) && cansee(player, target)) { + msg("%s%s health has been restored!", lfname, getpossessive(lfname)); + } + } + if (target->mp < mpheal) { + gainmp(target, mpheal - target->mp); + failed = B_FALSE; + } + + if (failed) { + if (isplayer(target)) msg("You feel momentarily restored."); + fizzle(caster); + return B_TRUE; + } else { + if (isplayer(target)) msg("You feel restored!"); + } } else if (spellid == OT_S_REVEALHIDDEN) { int i; int seen = B_FALSE; @@ -11825,6 +12063,9 @@ char *getspelldesc(enum OBTYPE spellid, int power, char *buf) { snprintf(buf, BUFLEN, "reduces hunger and speed"); } break; + case OT_S_MIRRORIMAGE: + snprintf(buf, BUFLEN, "Create %d mirror images", power); + break; case OT_S_PSYARMOUR: snprintf(buf, BUFLEN, "+%d Armour Rating", power*4); break; diff --git a/text.c b/text.c index 6d8e291..d32892f 100644 --- a/text.c +++ b/text.c @@ -16,9 +16,11 @@ extern long curtime; + extern lifeform_t *player; extern enum GAMEMODE gamemode; +extern enum WINGAMETYPE wintype; int needan(char *text) { if (isvowel(tolower(text[0]))) { @@ -145,9 +147,11 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam strcpy(extradambuf, ""); if ((dam == 0) && (damtype != DT_TOUCH)) { if (!victim || getlorelevel(lf, victim->race->raceclass->id)) { - //strcpy(extradambuf, " but do no damage"); - strcpy(extradambuf, " ineffectually"); - knownnodam = B_TRUE; + if (!lfhasflag(lf, F_PHANTASM)) { + //strcpy(extradambuf, " but do no damage"); + strcpy(extradambuf, " ineffectually"); + knownnodam = B_TRUE; + } } } else if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) { snprintf(extradambuf, BUFLEN, " [%d dmg]",dam); @@ -203,11 +207,11 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam } strcpy(attackverb, getattackverb(lf, wep, damtype,dam,maxhp)); - if ((dam == 0) && (damtype != DT_TOUCH)) { + + strcpy(nodamstr, ""); + if ((dam == 0) && (damtype != DT_TOUCH) && !lfhasflag(lf, F_PHANTASM)) { nodam = B_TRUE; strcpy(nodamstr, " ineffectually"); - } else { - strcpy(nodamstr, ""); } if (victim && isplayer(victim) && !nodam) { @@ -1327,6 +1331,18 @@ void makegunaimstring(lifeform_t *lf, int lfid, char *retbuf) { char *makekillertext(char *retbuf, char *killverb, char *lastdam, map_t *where, int wantextra, int wantlocation) { char *p, *dummy; char regionbuf[BUFLEN]; + + if (wintype) { + flag_t *winflag; + winflag = lfhasflag(player, F_WINNER); + if (winflag->val[0] == WT_GOD) { + sprintf(retbuf, "Crowned the God of %s.", winflag->text); // ie. "Became the God of Fire & Destruction" + } else if (winflag->val[0] == WT_DEMIGOD) { + sprintf(retbuf, "Ascended to Demigod-hood."); + } + return retbuf; + } + p = strtok_r(lastdam,"^", &dummy); if (p) { if (!strcmp(p, "you")) {