From d5b1e40f9871b6c7625ff75c4a1bbf07ba551352 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Sat, 3 Dec 2011 22:33:37 +0000 Subject: [PATCH] - [+] add more vrare vaults to reduce likelihood of cockatrice lair! - [+] bazaar - [+] money vault hsould be vrare - [+] so should traproom - [+] rename giant rat to "dire rat" - [+] don't show anything other than object description and throwing for unknown tech - [+] shouldn't be able to rest in a tent if it's not known! - [+] eyebat corpse increase maxmp? - [+] blessed missiles should nearly always hit undead * [+] too easy to dodge thrown missiles? - [+] spell and wand of culinary abundance - [+] if a carnivorous animal kills you: "Eaten by a xxx" * [+] bug: stairsperlev is only ever used in making DUNGEONS. generecise this ?? - [+] safetorest - should ignore monsters feigning death - [+] broken nose should reduce smell range - [+] fresh and stale bread should be interchangable in cooking - [+] make scroll of permenance act on you, not your objects - [+] tweak object rarity yet agian... - [+] bug: hole in roof above player start pos is immediately destroyed. - [+] change pickaxe to be like resting - [+] wait first, then if not interrupted, do the dig. - [+] add cell->hp, celltype->hp. around 100. - [+] f_digging, x, y, digperturn - [+] interrupt() will stop this. - [+] each turn, lower hp of cell by 1. - [+] make wlaking bakwards take less time based on athletics skill!!! - [+] at adept, takes no extra time? - [+] better racial display - [+] ? for extra info. - [+] hitdice - [+] general attribs (str etc) - [+] don't show description until you press '?' - [+] addbonustext(flagpile, f_BONDESC, "asdffas") - to avoid index issues - [+] remove VULNS from "effects" unless temporary - [+] isresistantto() etc need to have "int onlytemp" - [+] remove VULNS from manual BONTEXT flags - [+] CRASH IN DTVULN CODE!! - [+] limit '?r' display ?? - [+] what to show - [+] show races you have encountered - [+] show races you know about through Lore (adept level) - [+] show playable races????? - [+] structs - [+] race->encountered - [+] need to save this. - [+] make EFFECTS only show TEMPORARY effects or ones which don't come from race? - [+] automate bondesc/pendesc based on flags! - [+] vulnarabilities / resist / immun - [+] vision range!! (visrangemod) - [+] size? restricted armour. - [+] stayinroom - [+] f_humanoid (can use weapons) - [+] tamable - [+] seeindark - [+] caneatraw - [+] enhancesmell - [+] caneatraw - [+] vegeatrian - [+] cernivore - [+] fastmetab - [+] startskill - [+] tremorsense - [+] silentmove - [+] deaf - [+] flying / levitating - [+] awareness - [+] nocturnal / diurnal - [+] heavyblow - [+] packattack - [+] dodges - [+] autocreateob - [+] MPMOD - [+] HPMOD - [+] MEDITATES - [+] PHOOTMEM - [+] canwill "Spells: xx, x, x, x" - [+] spells: - [+] animate stone - "power" walls turn into stone golems - [+] implement spell - [+] golem - [+] r_golemstone - [+] knockback attack - [+] high str - [+] fists - [+] corpsetype and iunsummonob = boulder - [+] spell power modification - subtract spell level. - [+] when i go down a drain, make sure the new map links to THE DRAIN I WENT DOWN. not some otehr one. - [+] some monsters shouldn't sleep! add new flag: f_nosleep - [+] make spanner help disarm traps! --- ai.c | 5 +- attack.c | 8 +- data.c | 156 +++-- data.h | 1 + data/hiscores.db | Bin 13312 -> 13312 bytes defs.h | 43 +- flag.c | 31 +- flag.h | 1 + io.c | 1398 ++++++++++++++++++++++++------------------- io.h | 3 +- lf.c | 318 +++++++--- lf.h | 8 +- map.c | 37 +- move.c | 17 +- nexus.c | 21 +- nexus.h | 2 +- objects.c | 196 +++--- objects.h | 1 + save.c | 20 + spell.c | 133 +++- vaults/traproom.vlt | 2 +- vaults/vault.vlt | 2 +- 22 files changed, 1488 insertions(+), 915 deletions(-) diff --git a/ai.c b/ai.c index a7114ee..483209b 100644 --- a/ai.c +++ b/ai.c @@ -794,7 +794,6 @@ int ai_healing(lifeform_t *lf) { if ((lf->race->id == R_STIRGE) || (lf->race->id == R_LEECH)) { if (ispeaceful(lf)) { int sleepval = 18; - if (modcounter(lf->flags, 1) >= sleepval) { // we say that this ISNT on purpose, because otherwise // we'll wake up as soon as we're healed. in this case @@ -833,7 +832,7 @@ int ai_healing(lifeform_t *lf) { if (lf->hp < (lf->maxhp/2)) { if (!useitemwithflag(lf, F_AIHEALITEM)) { return B_TRUE; - } else { + } else if (cansleep(lf)) { // don't have or can't use our healing items // no enemies in sight? if (safetorest(lf)) { @@ -1978,7 +1977,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if ((ot->id == OT_S_DISPERSAL) && (lf->race->raceclass->id == RC_GOD)) { specificcheckok = B_FALSE; } - if ((ot->id == OT_S_DRAINLIFE) && isimmuneto(victim->flags, DT_NECROTIC)) { + if ((ot->id == OT_S_DRAINLIFE) && isimmuneto(victim->flags, DT_NECROTIC, B_FALSE)) { specificcheckok = B_FALSE; } if (ot->id == OT_A_FLIP) { diff --git a/attack.c b/attack.c index 5980215..f39acd2 100644 --- a/attack.c +++ b/attack.c @@ -852,7 +852,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } if (i == 0) { - if (lfhasflag(lf, F_HOLYAURA) && isvulnto(victim->flags, DT_HOLY)) { + if (lfhasflag(lf, F_HOLYAURA) && isvulnto(victim->flags, DT_HOLY, B_FALSE)) { damtype[i] = DT_HOLY; } // blocked by defender's shield? @@ -1021,7 +1021,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (f) { int diff; diff = f->val[2]; - if (isimmuneto(victim->flags, DT_COLD) || skillcheck(victim, SC_RESISTMAG, diff, 0)) { + if (isimmuneto(victim->flags, DT_COLD, B_FALSE) || skillcheck(victim, SC_RESISTMAG, diff, 0)) { if (isplayer(victim)) { msg("You feel mildly chilly."); } @@ -2270,10 +2270,10 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { draintype = DR_FROMWEP; } - if (draintype && !isimmuneto(victim->flags, DT_NECROTIC)) { + if (draintype && !isimmuneto(victim->flags, DT_NECROTIC, B_FALSE)) { int hpgain; // drain life! - if (isresistantto(victim->flags, DT_NECROTIC)) { + if (isresistantto(victim->flags, DT_NECROTIC, B_FALSE)) { hpgain = dam; } else { hpgain = (dam/2); diff --git a/data.c b/data.c index 82050e4..cc97ee1 100644 --- a/data.c +++ b/data.c @@ -31,6 +31,18 @@ extern char *technoun[]; extern objecttype_t *lastot; +void addbonustext(flagpile_t *fp, enum FLAG fid, char *text) { + int idx = -1; + flag_t *f; + // find last index + for (f = fp->first ; f; f = f->next) { + if (f->id == fid) { + if (f->val[0] > idx) idx = f->val[0]; + } + } + addflag(fp, fid, idx+1, NA, NA, text); +} + command_t *addcommand(enum COMMAND id, char ch, char *desc) { command_t *a; @@ -1123,7 +1135,7 @@ void initobjects(void) { addoc(OC_TRAP, "Trap", "Fiendish traps.", '^', C_GREY, RR_RARE); addocnoun(lastobjectclass, "trap"); addoc(OC_MONEY, "Money", "The standard currency of Nexus.", '$', C_GREY, RR_UNCOMMON); - addoc(OC_SCROLL, "Scrolls", "An arcane roll of parchment, inscribed with many magical glyphs.", '?', C_GREY, RR_UNCOMMON); + addoc(OC_SCROLL, "Scrolls", "An arcane roll of parchment, inscribed with many magical glyphs.", '?', C_GREY, RR_COMMON); addocnoun(lastobjectclass, "scroll"); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); @@ -1142,7 +1154,7 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_OPERUSECHARGE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_RNDCHARGES, 1, 8, NA, NULL); - addoc(OC_POTION, "Potions", "A strange concoction contained within a small flask.", '!', C_GREY, RR_UNCOMMON); + addoc(OC_POTION, "Potions", "A strange concoction contained within a small flask.", '!', C_GREY, RR_COMMON); addocnoun(lastobjectclass, "potion"); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); @@ -1171,7 +1183,7 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_MASTERWORK, 17, NA, NULL); addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_SHODDY, 34, NA, NULL); addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_BLOODSTAINED, 17, NA, NULL); - addoc(OC_MISSILE, "Missiles/Ammunition", "An instrument used for the purpose of causing harm or death.", ';', C_GREY, RR_COMMON); + addoc(OC_MISSILE, "Missiles/Ammunition", "An instrument used for the purpose of causing harm or death.", ';', C_GREY, RR_UNCOMMON); addocnoun(lastobjectclass, "missile"); addocnoun(lastobjectclass, "ammo"); addocnoun(lastobjectclass, "ammunition"); @@ -3255,10 +3267,9 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); - addot(OT_S_ANIMATESTATUE, "animate statue", "Temporarily transforms a statue into living flesh, under control of the caster. Also stops stoning.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_ANIMATESTATUE, "animate statue", "Temporarily brings a statue to life, under control of the caster. Also stops stoning.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell only affects stone which is in the form of a living creature."); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); - addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_OBJECT|TT_PLAYER, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); @@ -3274,6 +3285,12 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + addot(OT_S_QUICKENSTONE, "quicken stone", "Crafts nearby stone into powerful stone primalities.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how many creatures will be created."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 8, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); // l6 addot(OT_S_PETRIFY, "petrify", "Causes a living creature to turn into stone.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability."); @@ -3317,11 +3334,18 @@ void initobjects(void) { addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); // l2 + addot(OT_S_CREATEFOOD, "sultan's feast", "Creates a meal in the target location.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how much food is created."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_NONE, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + // l3 addot(OT_S_CREATEMONSTER, "create monster", "Summons a (probably hostile) monster to a nearby location.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power V you can control where the monster appears."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VII you can control the type of monster created."); addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l5 @@ -3627,6 +3651,10 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); // wands + addot(OT_WAND_CREATEFOOD, "wand of culinary abundance", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_LINKSPELL, OT_S_CREATEFOOD, NA, NA, NULL); + addflag(lastot->flags, F_OPERNEEDTARGET, TT_NONE, NA, NA, NULL); addot(OT_WAND_KNOCK, "wand of opening", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL); addflag(lastot->flags, F_LINKSPELL, OT_S_KNOCK, NA, NA, NULL); @@ -3817,6 +3845,7 @@ void initobjects(void) { addot(OT_PICKAXE, "pickaxe", "A heavy tool for breaking rock.", MT_METAL, 8, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_HELPSDIG, 10, NA, NA, NULL); addot(OT_ROPE, "rope", "A long length of strong rope.", MT_CLOTH, 5, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); @@ -6121,6 +6150,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERNEEDDIR, B_TRUE, NA, NA, "Use your spanner in which direction"); + addflag(lastot->flags, F_HELPSDISARM, 5, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addot(OT_SHILLELAGH, "shillelagh", "An small cudgel with a strap, lightweight yet surprisingly effective. Irish in origin.", MT_WOOD, 2, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); @@ -6432,18 +6462,13 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CHA, AT_RANDOM, NA, NULL); // bonuses - addflag(lastrace->flags, F_BONDESC, 0, NA, NA, "Unarmed claw attack (damage rating 4)"); - addflag(lastrace->flags, F_BONDESC, 1, NA, NA, "Can fly at will"); - addflag(lastrace->flags, F_BONDESC, 2, NA, NA, "+1 vision range"); - addflag(lastrace->flags, F_BONDESC, 3, NA, NA, "Starts with one rank of Evasion."); + addbonustext(lastrace->flags, F_BONDESC, "Unarmed claw attack (damage rating 4)"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_FLIGHT, NA, NA, "pw:1;"); addflag(lastrace->flags, F_VISRANGEMOD, 1, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_EVASION, PR_NOVICE, NA, NULL); // penalties - addflag(lastrace->flags, F_PENDESC, 0, NA, NA, "Low hit points."); - addflag(lastrace->flags, F_PENDESC, 1, NA, NA, "Low Strength and Fitness."); - addflag(lastrace->flags, F_PENDESC, 2, NA, NA, "Vulnerable to Fire and Electricity."); + addbonustext(lastrace->flags, F_PENDESC, "Low hit points."); addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_ELECTRIC, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+3"); @@ -6480,16 +6505,11 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL); // bonuses - addflag(lastrace->flags, F_BONDESC, 0, NA, NA, "Computerised brain provides automatic analysis."); - addflag(lastrace->flags, F_BONDESC, 1, NA, NA, "Starts with one rank of Tech Usage."); - addflag(lastrace->flags, F_BONDESC, 2, NA, NA, "Above average Strength, Intelligence and Fitness."); + addbonustext(lastrace->flags, F_BONDESC, "Computerised brain provides automatic analysis."); addflag(lastrace->flags, F_EXTRAINFO, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_TECHUSAGE, PR_ADEPT, NA, NULL); // penalties - addflag(lastrace->flags, F_PENDESC, 0, NA, NA, "Cannot use magic."); - addflag(lastrace->flags, F_PENDESC, 1, NA, NA, "Vulnerable to Cold, Water and Electricity."); - addflag(lastrace->flags, F_PENDESC, 2, NA, NA, "Low Agility and Wisdom."); - addflag(lastrace->flags, F_PENDESC, 3, NA, NA, "Very low Charisma."); + addbonustext(lastrace->flags, F_PENDESC, "Cannot use magic."); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_WATER, NA, NA, "2d6"); addflag(lastrace->flags, F_DTVULN, DT_ELECTRIC, NA, NA, NULL); @@ -6548,13 +6568,7 @@ void initrace(void) { addflag(lastrace->flags, F_HATESRACEWITHFLAG, F_CANINE, NA, NA, NULL); addflag(lastrace->flags, F_HATESRACEWITHFLAG, F_AVIAN, NA, NA, NULL); // bonuses - addflag(lastrace->flags, F_BONDESC, 0, NA, NA, "Above average Agility and Charisma."); - addflag(lastrace->flags, F_BONDESC, 1, NA, NA, "Unarmed claw attack (damage rating 3)"); - addflag(lastrace->flags, F_BONDESC, 2, NA, NA, "Starts with one rank of Climbing and Listen."); - addflag(lastrace->flags, F_BONDESC, 3, NA, NA, "Can Jump at will."); - addflag(lastrace->flags, F_BONDESC, 4, NA, NA, "Enhanced balance prevents slips and falls."); - addflag(lastrace->flags, F_BONDESC, 5, NA, NA, "Enhanced sense of smell (range 2)"); - addflag(lastrace->flags, F_BONDESC, 6, NA, NA, "Darkvision (range 2)"); + addbonustext(lastrace->flags, F_BONDESC, "Unarmed claw attack (damage rating 3)"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_NOVICE, NA, NULL); @@ -6564,12 +6578,9 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); // penalties - addflag(lastrace->flags, F_PENDESC, 0, NA, NA, "Below average Strength, low Wisdom, and slightly low Hit Points."); - addflag(lastrace->flags, F_PENDESC, 1, NA, NA, "Carnivorous (only eats meat)."); - addflag(lastrace->flags, F_PENDESC, 2, NA, NA, "Fast metabolism."); - addflag(lastrace->flags, F_PENDESC, 3, NA, NA, "Vulnerable to Magic, Water and Sonic damage."); - addflag(lastrace->flags, F_PENDESC, 4, NA, NA, "Can never learn Swimming."); - addflag(lastrace->flags, F_PENDESC, 5, NA, NA, "Enters a bezerk rage upon sight of avians or canines."); + addbonustext(lastrace->flags, F_PENDESC, "Slightly low Hit Points."); + addbonustext(lastrace->flags, F_PENDESC, "Can never learn Swimming."); + addbonustext(lastrace->flags, F_PENDESC, "Enters a bezerk rage upon sight of avians or canines."); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FASTMETAB, 2, NA, NA, NULL); @@ -6602,16 +6613,10 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); // bonuses - addflag(lastrace->flags, F_BONDESC, 0, NA, NA, "High Fitness."); - addflag(lastrace->flags, F_BONDESC, 1, NA, NA, "Above average Strength."); - addflag(lastrace->flags, F_BONDESC, 2, NA, NA, "Darkvision (range: 3)"); - addflag(lastrace->flags, F_BONDESC, 3, NA, NA, "Starts with one rank of Cartography and Metalwork."); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_METALWORK, PR_NOVICE, NA, NULL); // penalties - addflag(lastrace->flags, F_PENDESC, 0, NA, NA, "Below average Agility, Intelligence and Charisma."); - addflag(lastrace->flags, F_PENDESC, 1, NA, NA, "Penalty to Mana."); addflag(lastrace->flags, F_MPMOD, -3, NA, NA, NULL); addflag(lastrace->flags, F_TAMABLE, 35, NA, NA, NULL); @@ -6647,19 +6652,13 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); // bonuses - addflag(lastrace->flags, F_BONDESC, 0, NA, NA, "Above average Agility, Intelligence and Charisma."); - addflag(lastrace->flags, F_BONDESC, 1, NA, NA, "Darkvision (range: 2)"); - addflag(lastrace->flags, F_BONDESC, 2, NA, NA, "Meditates to retain awareness while resting."); - addflag(lastrace->flags, F_BONDESC, 3, NA, NA, "Extra Mana points."); - addflag(lastrace->flags, F_BONDESC, 4, NA, NA, "Starts with one rank of Ranged Weapons and Stealth."); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_MEDITATES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MPMOD, 3, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_RANGED, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_NOVICE, NA, NULL); // penalties - addflag(lastrace->flags, F_PENDESC, 0, NA, NA, "Below average Strength and Fitness."); - addflag(lastrace->flags, F_PENDESC, 1, NA, NA, "Slightly below average Hit Points."); + addbonustext(lastrace->flags, F_PENDESC, "Slightly below average Hit Points."); addflag(lastrace->flags, F_TAMABLE, 25, NA, NA, NULL); addrace(R_MAMMOAN, "mammoan", 150, '@', C_GREY, MT_LEATHER, RC_HUMANOID, "Mammoans are huge, elephant-like humanoids. Their have great senses of hearing and smell, a photographic memory, and leather skin which greatly lessens damage. On the other hand they vision is poor, their movement slow, and their digestive system cannot cope with meat."); @@ -6690,20 +6689,12 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); // bonuses - addflag(lastrace->flags, F_BONDESC, 0, NA, NA, "High Strength."); - addflag(lastrace->flags, F_BONDESC, 1, NA, NA, "Leather skin reduces damage."); - addflag(lastrace->flags, F_BONDESC, 2, NA, NA, "Photographic memory."); - addflag(lastrace->flags, F_BONDESC, 3, NA, NA, "Enhanced sense of smell (range 3)"); - addflag(lastrace->flags, F_BONDESC, 4, NA, NA, "Starts with one rank of Listen."); + addbonustext(lastrace->flags, F_BONDESC, "Leather skin reduces damage."); addflag(lastrace->flags, F_PHOTOMEM, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 3, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_NOVICE, NA, NULL); // penalties - addflag(lastrace->flags, F_PENDESC, 0, NA, NA, "Very low Agility and Charisma."); - addflag(lastrace->flags, F_PENDESC, 1, NA, NA, "-2 vision range."); - addflag(lastrace->flags, F_PENDESC, 2, NA, NA, "Vulnerable to Sonic damage."); - addflag(lastrace->flags, F_PENDESC, 3, NA, NA, "Vegeterian (will not eat meat)"); - addflag(lastrace->flags, F_PENDESC, 4, NA, NA, "Can never learn Athletics."); + addbonustext(lastrace->flags, F_PENDESC, "Can never learn Athletics."); addflag(lastrace->flags, F_VISRANGEMOD, -2, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_SONIC, NA, NA, NULL); addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); @@ -7065,6 +7056,7 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_BUGBEAR, "bugbear", 120, 'G', C_BROWN, MT_FLESH, RC_HUMANOID, "A huge goblinoid creature, similar to a hobgoblin but larger again, with a temperament to match."); setbodytype(lastrace, BT_HUMANOID); @@ -7135,6 +7127,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;"); addflag(lastrace->flags, F_CASTCHANCE, 70, NA, NA, NULL); addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_DARKMANTLE, "darklurk", 70, 'U', C_BLUE, MT_FLESH, RC_MAGIC, "A floating squid-like creature, rarely seen due to its ability to cloak itself in a magical darkness. They use their huge tentacles to grab then crush their unsuspecting prey."); addbodypart(lastrace, BP_BODY, NULL); @@ -7168,6 +7161,7 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addrace(R_EYEBAT, "eyebat", 5, 'e', C_BLUE, MT_FLESH, RC_MAGIC, "A smaller cousin to the beholder, an eyebat is a single oversized eyeball suspended between bat-like wings."); addbodypart(lastrace, BP_BODY, NULL); @@ -7574,6 +7568,30 @@ void initrace(void) { addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 0, NA, NA, NULL); + addrace(R_GOLEMSTONE, "stone primality", 200, 'H', C_GREY, MT_STONE, RC_HUMANOID, "A living mass of stone, animated by powerful magic."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_NONE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_EXLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_EXLOW, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "10d4"); + addflag(lastrace->flags, F_ARMOURRATING, 14, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, -50, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_VERYSLOW, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 16, NA, NULL); + addflag(lastrace->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 50, NA, NA, NULL); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "boulder"); + addflag(lastrace->flags, F_UNSUMMONOB, NA, NA, NA, "boulder"); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + addrace(R_HOBGOBLIN, "hobgoblin", 90, 'g', C_GREEN, MT_FLESH, RC_HUMANOID, "A larger, stronger, smarter and more menacing form of a goblin."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -7988,6 +8006,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_XPMULTIPLY, 2, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_SATYR, "satyr", 80, 'h', C_GREEN, MT_FLESH, RC_HUMANOID, "A goat-like humanoid equipped with a set of magical panpipes."); setbodytype(lastrace, BT_HUMANOID); @@ -8064,6 +8083,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOFLEE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_SPRITEFIRE, "fire sprite", 5, 'n', C_RED, MT_FIRE, RC_MAGIC, "A small magical creature surrounded by crackling flames."); setbodytype(lastrace, BT_HUMANOID); @@ -8092,6 +8112,7 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_SPRITEICE, "ice sprite", 5, 'n', C_WHITE, MT_ICE, RC_MAGIC, "A small magical creature surrounded by freezing ice."); setbodytype(lastrace, BT_HUMANOID); @@ -8120,6 +8141,7 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_TROLL, "troll", 100, 't', C_GREEN, MT_FLESH, RC_HUMANOID, "A savage, hairy green monster. Trolls are extremely muscular, move abnormally quickly and regenerate."); setbodytype(lastrace, BT_HUMANOID); @@ -8225,6 +8247,7 @@ void initrace(void) { addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); addflag(lastrace->flags, F_MORALE, 2, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_PIRANHAKING, "king piranha", 1, ';', C_GREEN, MT_FLESH, RC_AQUATIC, "A larger version of a standard piranha. King piranhas can leap through the air."); setbodytype(lastrace, BT_FISH); addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL); @@ -8242,6 +8265,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 6, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;"); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_EELELEC, "electric eel", 120, ';', C_CYAN, MT_FLESH, RC_AQUATIC, "A sliippery eel charged with electricity."); setbodytype(lastrace, BT_FISH); addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL); @@ -8258,6 +8282,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, 6, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 3, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_EELGIANT, "giant eel", 150, ';', C_BLUE, MT_FLESH, RC_AQUATIC, "A very long, slippery eel. They tend to catch and crush their prey."); setbodytype(lastrace, BT_FISH); addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL); @@ -8274,6 +8299,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;"); addflag(lastrace->flags, F_MORALE, 3, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); // plants addrace(R_CACTUS, "cactus", 30, 'F', C_YELLOW, MT_PLANT, RC_PLANT, "A wide upright plant coated with sharp spines. Said to sprout delicious fruit."); addbodypart(lastrace, BP_BODY, "stalk"); @@ -8843,7 +8869,7 @@ void initrace(void) { addflag(lastrace->flags, F_RETALIATE, 1, 4, DT_PIERCE, "sharp spines"); addflag(lastrace->flags, F_CORPSEFLAG, F_SHARP, 1, 4, NULL); addflag(lastrace->flags, F_MORALE, 8, NA, NA, NULL); - addrace(R_RAT, "giant rat", 3, 'r', C_BROWN, MT_FLESH, RC_ANIMAL, "A rodent of unusual size."); + addrace(R_RAT, "dire rat", 3, 'r', C_BROWN, MT_FLESH, RC_ANIMAL, "A rodent of unusual size."); setbodytype(lastrace, BT_QUADRAPED); addbodypart(lastrace, BP_TAIL, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -9706,14 +9732,14 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+1"); addflag(lastrace->flags, F_ENHANCESMELL, 2, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 1, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "buzzes angrily^an angry buzzing"); addflag(lastrace->flags, F_NOISETEXT, N_FLY, 2, NA, "^buzzing"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:1d4;"); + addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:1d1;"); addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); @@ -10055,6 +10081,7 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); // special: fully heal if our origrace is a vampire, and we are resting over a coffin addrace(R_DANCINGWEAPON, "dancing weapon", 0, ')', C_GREY, MT_METAL, RC_OTHER, "A magically animated weapon."); @@ -10073,6 +10100,7 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addrace(R_FLOATINGDISC, "floating disc", 0, '_', C_BOLDGREEN, MT_METAL, RC_OTHER, "A magically created disc of energy which floats in the air."); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); @@ -10090,11 +10118,15 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); // now do final steps in race initialisation: // - add flags based on raceclass, etc // - fill in missing alignments for (r = firstrace ; r ; r = r->next) { + if (hasflag(r->flags, F_PLAYABLE)) { + r->known = B_TRUE; + } if (r->raceclass->id == RC_AQUATIC) { addflag(r->flags, F_HASSKILL, SK_SWIMMING, PR_MASTER, NA, NULL); addflag(r->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); @@ -10104,6 +10136,7 @@ void initrace(void) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_MATVULN, MT_SILVER, 200, NA, NULL); addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_GOD) { addflag(r->flags, F_PIETY, 100, NA, NA, NULL); addflag(r->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -10115,6 +10148,7 @@ void initrace(void) { addflag(r->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(r->flags, F_FLEEONHPPCT, 20, NA, NA, NULL); addflag(r->flags, F_RESISTMAG, 15, NA, NA, NULL); + addflag(r->flags, F_MEDITATES, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_MAGIC) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_PLANT) { @@ -10125,8 +10159,9 @@ void initrace(void) { addflag(r->flags, F_DTVULN, DT_DECAY, NA, NA, NULL); 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); } else if (r->raceclass->id == RC_SLIME) { - addflag(lastrace->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_UNDEAD) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); @@ -10138,6 +10173,7 @@ void initrace(void) { addflag(r->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); addflag(r->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); } // fill in missins alignments diff --git a/data.h b/data.h index 1fbdfa3..e2a1d24 100644 --- a/data.h +++ b/data.h @@ -1,5 +1,6 @@ #include "defs.h" +void addbonustext(flagpile_t *fp, enum FLAG fid, char *text); command_t *addcommand(enum COMMAND id, char c, char *desc); void initcommands(void); void initjobs(void); diff --git a/data/hiscores.db b/data/hiscores.db index 8459baf1a7d6a49a75d59b0b74f0bd868bf94810..7b814a5e9959a0bda4a6ab3df3d1bb5b671af1ac 100644 GIT binary patch delta 366 zcmZq3Xvml#%~-urW-~jx7Xt$Wccb~_YwUWAsgqebf+t6Dl(8^fW@6iXi9?5xPmqDL zl8K#xm6e%+iQ)8Q9cVVaz$V>a1D$BG-tB%q|$CWDL2`kKxnV51BbJW6vD l^AvpZ^Riuv^2_s5Qxr1u6v|SIDiu;vQwtQz6H8Ky^Z@o#T=@V1 delta 296 zcmZq3Xvml#%~-NgW-~jxI|Bm)ccatext); if (newtext) { diff --git a/flag.h b/flag.h index 68bbdc0..c280c3a 100644 --- a/flag.h +++ b/flag.h @@ -8,6 +8,7 @@ flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, /*@n flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, /*@null@*/ char *text, int timeleft); flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, /*@null@*/ char *text, int lifetime, int known, long obfromid); flagpile_t *addflagpile(lifeform_t *owner, object_t *o); +int canbemadepermenant(enum FLAG id); void changeflagtext(flag_t *f, char *newtext); void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id); void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime); diff --git a/io.c b/io.c index 8934f43..edbbdcc 100644 --- a/io.c +++ b/io.c @@ -64,6 +64,7 @@ extern int nretobs; extern FILE *logfile; extern enum OBCLASS sortorder[]; +extern objectclass_t *objectclass; extern knowledge_t *knowledge; extern objecttype_t *objecttype; extern command_t *firstcommand; @@ -3416,6 +3417,7 @@ void describeob(object_t *o) { void describerace(enum RACE rid) { char buf[BUFLEN]; char *buf2; + int x,y; race_t *r; cls(); r = findrace(rid); @@ -3430,8 +3432,10 @@ void describerace(enum RACE rid) { wmove(mainwin, 2, 0); buf2 = malloc(HUGEBUFLEN * sizeof(char)); - makedesc_race(rid, buf2, B_FALSE); - textwithcol(mainwin, buf2); + makedesc_race(rid, buf2, B_TRUE); + //textwithcol(mainwin, buf2); + getyx(mainwin,y,x); + wrapprint(mainwin, &y, &x, "%s", buf2); free(buf2); wrefresh(mainwin); @@ -4554,17 +4558,18 @@ char *makedesc_ob(object_t *o, char *retbuf) { } strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN); - f = hasflag(o->flags, F_THROWMISSILE); - if (f) { - if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT)) { - int dam; - dam = getthrowdam(o); - sprintf(buf, "@%s good for throwing [base damage %d].",(o->amt == 1) ? "It is" : "They are", dam); - } else { - sprintf(buf, "@%s good for throwing.", (o->amt == 1) ? "It is" : "They are"); - } - strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN); + } + + f = hasflag(o->flags, F_THROWMISSILE); + if (f) { + if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT)) { + int dam; + dam = getthrowdam(o); + sprintf(buf, "@%s good for throwing [base damage %d].",(o->amt == 1) ? "It is" : "They are", dam); + } else { + sprintf(buf, "@%s good for throwing.", (o->amt == 1) ? "It is" : "They are"); } + strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN); } if ((f = hasflag(o->flags, F_IMPASSABLE)) != NULL) { @@ -4596,538 +4601,552 @@ char *makedesc_ob(object_t *o, char *retbuf) { } } - - // weapons? - if (isfirearm(o)) { - flag_t *ff, *ff2; - sprintf(buf, "It is a %s firearm.\n", hasflag(o->flags, F_TWOHANDED) ? "two-handed" : "single handed"); - strncat(retbuf, buf, HUGEBUFLEN); - f = hasflag(o->flags, F_ACCURACY); - if (f) { - int acc,accnum; - acc = getobaccuracy(o, NULL); - accnum = getaccuracynum(acc); - sprintf(buf, "@It has an accuracy modifier of %c%d (%s).\n",(accnum < 0) ? '-' : '+', abs(accnum), getaccuracyname(acc)); - strncat(retbuf, buf, HUGEBUFLEN); - } - f = hasflag(o->flags, F_RANGE); - if (f) { - sprintf(buf, "@Its maximum range is %d.\n",f->val[0]); - strncat(retbuf, buf, HUGEBUFLEN); - } - f = hasflag(o->flags, F_AMMOCAPACITY); - if (f) { - sprintf(buf, "@It can hold up to %d of the following kind(s) of ammo:\n",f->val[0]); + // unknown items? + if (isknown(o)) { + // weapons? + if (isfirearm(o)) { + flag_t *ff, *ff2; + sprintf(buf, "It is a %s firearm.\n", hasflag(o->flags, F_TWOHANDED) ? "two-handed" : "single handed"); strncat(retbuf, buf, HUGEBUFLEN); + f = hasflag(o->flags, F_ACCURACY); + if (f) { + int acc,accnum; + acc = getobaccuracy(o, NULL); + accnum = getaccuracynum(acc); + sprintf(buf, "@It has an accuracy modifier of %c%d (%s).\n",(accnum < 0) ? '-' : '+', abs(accnum), getaccuracyname(acc)); + strncat(retbuf, buf, HUGEBUFLEN); + } + f = hasflag(o->flags, F_RANGE); + if (f) { + sprintf(buf, "@Its maximum range is %d.\n",f->val[0]); + strncat(retbuf, buf, HUGEBUFLEN); + } + f = hasflag(o->flags, F_AMMOCAPACITY); + if (f) { + sprintf(buf, "@It can hold up to %d of the following kind(s) of ammo:\n",f->val[0]); + strncat(retbuf, buf, HUGEBUFLEN); - strcpy(buf, ""); + strcpy(buf, ""); - getflags(o->flags, retflag, &nretflags, F_AMMOOB, F_NONE); - for (i = 0; i < nretflags; i++) { - objecttype_t *ot; - ff = retflag[i]; - ot = findot(ff->val[0]); - if (ot) { - if (streq(buf, "")) { - snprintf(buf, BUFLEN, "@@%s",ot->name); - } else { - if (strlen(buf) >= 60) { - strncat(retbuf, buf, HUGEBUFLEN); - snprintf(buf, BUFLEN, "\n@@%s",ot->name); + getflags(o->flags, retflag, &nretflags, F_AMMOOB, F_NONE); + for (i = 0; i < nretflags; i++) { + objecttype_t *ot; + ff = retflag[i]; + ot = findot(ff->val[0]); + if (ot) { + if (streq(buf, "")) { + snprintf(buf, BUFLEN, "@@%s",ot->name); } else { - strcat(buf, ", "); - strcat(buf, ot->name); + if (strlen(buf) >= 60) { + strncat(retbuf, buf, HUGEBUFLEN); + snprintf(buf, BUFLEN, "\n@@%s",ot->name); + } else { + strcat(buf, ", "); + strcat(buf, ot->name); + } } } } + if (strlen(buf)) { + strncat(retbuf, buf, HUGEBUFLEN); + strncat(retbuf, "\n", HUGEBUFLEN); + } } - if (strlen(buf)) { + ff = hasflag(o->flags, F_FIRESPEED); + if (ff) { + sprintf(buf, "@It fires at a speed of %d km/h.\n",speedtokph(ff->val[0])); + strncat(retbuf, buf, HUGEBUFLEN); + } + ff2 = hasflag(o->flags, F_RELOADTURNS); + sprintf(buf, "@It takes %d turn%s to reload.\n", ff2->val[0], (ff2->val[0] == 1) ? "" : "s"); + strncat(retbuf, buf, HUGEBUFLEN); + } else if (isweapon(o) && isknown(o)) { + flag_t *damflag; + int delay; + int critchance; + snprintf(buf, BUFLEN, "%s %s weapon", + (o->type->obclass->id == OC_WEAPON) ? "It is a" : "It can be used as a", + hasflag(o->flags, F_TWOHANDED) ? "two-handed" : "single handed"); + damflag = hasflag(o->flags, F_DAM); + if (damflag) { + //int bonus = 0; + char buf2[BUFLEN]; + //int mindam,maxdam; + int dr; + enum DAMTYPE damtype; + + /* + f = hasflag(o->flags, F_BONUS); + if (f && f->known) { + // only tell player about bonuses if they are known.! + bonus = f->val[0]; + } + */ + + damtype = damflag->val[0]; + dr = damflag->val[1]; + /* + getdamrange(o, &mindam, &maxdam); + mindam += bonus; + maxdam += bonus; + limit(&mindam, 0, NA); + limit(&maxdam, 0, NA); + */ + + /* + if (mindam == maxdam) { + snprintf(buf2, BUFLEN, ", dealing %d %s damage",maxdam, getdamname(damtype)); + } else { + snprintf(buf2, BUFLEN, ", dealing %d-%d %s damage",mindam,maxdam, getdamname(damtype)); + } + */ + snprintf(buf2, BUFLEN, " which deals %s damage.\n",getdamname(damtype)); + strcat(buf, buf2); + + //dicetotext(f->val[0], f->val[1], f->val[2], NULL, NULL, dicebuf, NULL); + + sprintf(buf2, "@It has a base Damage Rating of %d",dr); + strcat(buf, buf2); + + strncat(retbuf, buf, HUGEBUFLEN); + + if (compareob) { + flag_t *comparedf; + //int comparebonus = 0,cmin,cmax,diff; + int comparedr,diff; + comparedf = hasflag(compareob->flags, F_DAM); + comparedr = comparedf->val[1]; + + //f = hasflag(compareob->flags, F_BONUS); + //if (f && f->known) comparebonus = f->val[0]; + + //getdamrange(compareob, &cmin, &cmax); + //cmin += bonus; cmax += bonus; + //limit(&cmin, 0, NA); limit(&cmax, 0, NA); + + diff = dr - comparedr; + + if (diff == 0) { + strcat(retbuf, " (=)"); + } else { + // higher damagerating is better + snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff < 0) ? "^B" : "^g", + (diff < 0) ? '-' : '+', abs(diff)); + strcat(retbuf, buf2); + } + } + + strcat(retbuf, ".\n"); + + // other extra damage or effects? + f = hasflag(o->flags, F_ONFIRE); + if (f) { + sprintf(buf,"@It also inflicts %s extra burning damage.\n", strlen(f->text) ? f->text : "1-4"); + strncat(retbuf, buf, HUGEBUFLEN); + } + f = hasflag(o->flags, F_FROZEN); + if (f) { + sprintf(buf,"@It also inflicts %s extra cold damage.\n", strlen(f->text) ? f->text : "1-4"); + strncat(retbuf, buf, HUGEBUFLEN); + } + f = hasflag(o->flags, F_ENCHANTED); + if (f) { + sprintf(buf,"@It also inflicts %s extra magical damage if the user has spare mana.\n", strlen(f->text) ? f->text : "1-2"); + strncat(retbuf, buf, HUGEBUFLEN); + } + } else { strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN); } - } - ff = hasflag(o->flags, F_FIRESPEED); - if (ff) { - sprintf(buf, "@It fires at a speed of %d km/h.\n",speedtokph(ff->val[0])); - strncat(retbuf, buf, HUGEBUFLEN); - } - ff2 = hasflag(o->flags, F_RELOADTURNS); - sprintf(buf, "@It takes %d turn%s to reload.\n", ff2->val[0], (ff2->val[0] == 1) ? "" : "s"); - strncat(retbuf, buf, HUGEBUFLEN); - } else if (isweapon(o) && isknown(o)) { - flag_t *damflag; - int delay; - int critchance; - snprintf(buf, BUFLEN, "%s %s weapon", - (o->type->obclass->id == OC_WEAPON) ? "It is a" : "It can be used as a", - hasflag(o->flags, F_TWOHANDED) ? "two-handed" : "single handed"); - damflag = hasflag(o->flags, F_DAM); - if (damflag) { - //int bonus = 0; - char buf2[BUFLEN]; - //int mindam,maxdam; - int dr; - enum DAMTYPE damtype; - /* - f = hasflag(o->flags, F_BONUS); - if (f && f->known) { - // only tell player about bonuses if they are known.! - bonus = f->val[0]; + f = hasflag(o->flags, F_ACCURACY); + if (f) { + int acc,accnum; + acc = getobaccuracy(o, NULL); + accnum = getaccuracynum(acc); + sprintf(buf, "@It has an accuracy modifier of %c%d (%s)",(accnum < 0) ? '-' : '+', abs(accnum) , getaccuracyname(acc)); + if (compareob && hasflag(compareob->flags, F_ACCURACY)) { + int cacc,caccnum,diff; + cacc = getobaccuracy(compareob, NULL); + caccnum = getaccuracynum(cacc); + diff = accnum - caccnum; + if (diff == 0) { + strcat(buf, " (=)"); + } else { + // higher accuracy is better + snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff < 0) ? "^B" : "^g", (diff < 0) ? '-' : '+', abs(diff)); + strcat(buf, buf2); + } + } + + strcat(buf, ".\n"); + strncat(retbuf, buf, HUGEBUFLEN); } - */ - - damtype = damflag->val[0]; - dr = damflag->val[1]; - /* - getdamrange(o, &mindam, &maxdam); - mindam += bonus; - maxdam += bonus; - limit(&mindam, 0, NA); - limit(&maxdam, 0, NA); - */ - - /* - if (mindam == maxdam) { - snprintf(buf2, BUFLEN, ", dealing %d %s damage",maxdam, getdamname(damtype)); - } else { - snprintf(buf2, BUFLEN, ", dealing %d-%d %s damage",mindam,maxdam, getdamname(damtype)); - } - */ - snprintf(buf2, BUFLEN, " which deals %s damage.\n",getdamname(damtype)); - strcat(buf, buf2); - - //dicetotext(f->val[0], f->val[1], f->val[2], NULL, NULL, dicebuf, NULL); - - sprintf(buf2, "@It has a base Damage Rating of %d",dr); - strcat(buf, buf2); - - strncat(retbuf, buf, HUGEBUFLEN); + critchance = getcritchance(player, o, NULL); + sprintf(buf, "@You have a %d%% critical hit chance with it", critchance); if (compareob) { - flag_t *comparedf; - //int comparebonus = 0,cmin,cmax,diff; - int comparedr,diff; - comparedf = hasflag(compareob->flags, F_DAM); - comparedr = comparedf->val[1]; - - //f = hasflag(compareob->flags, F_BONUS); - //if (f && f->known) comparebonus = f->val[0]; - - //getdamrange(compareob, &cmin, &cmax); - //cmin += bonus; cmax += bonus; - //limit(&cmin, 0, NA); limit(&cmax, 0, NA); - - diff = dr - comparedr; - + int ccritch,diff; + ccritch = getcritchance(player, compareob, NULL); + diff = critchance - ccritch; if (diff == 0) { - strcat(retbuf, " (=)"); + strcat(buf, " (=)"); } else { - // higher damagerating is better + // higher crit chance is better snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff < 0) ? "^B" : "^g", - (diff < 0) ? '-' : '+', abs(diff)); - strcat(retbuf, buf2); + (diff > 0) ? '+' : '-', abs(diff)); + strcat(buf, buf2); } } - strcat(retbuf, ".\n"); + strcat(buf, ".\n"); + strncat(retbuf, buf, HUGEBUFLEN); - // other extra damage or effects? - f = hasflag(o->flags, F_ONFIRE); + f = hasflag(o->flags, F_OBATTACKDELAY); + if (f) delay = f->val[0]; + else delay = 100; + sprintf(buf, "@Its attack delay is %d%%",delay - 100); + if (compareob) { + int cdelay,diff; + f = hasflag(compareob->flags, F_OBATTACKDELAY); + if (f) cdelay = f->val[0]; + else cdelay = 100; + diff = delay - cdelay; + if (diff == 0) { + strcat(buf, " (=)"); + } else { + // lower attack delay is better + snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff > 0) ? "^B" : "^g", + (diff > 0) ? '+' : '-', abs(diff)); + strcat(buf, buf2); + } + } + + strcat(buf, ".\n"); + strncat(retbuf, buf, HUGEBUFLEN); + } + // damage + if (isarmour(o)) { + int thisar = 0; + flag_t *goesmulti; + goesmulti = hasflag(o->flags, F_GOESONMULTI); + + /* + f = hasflag(o->flags, F_GOESON); if (f) { - sprintf(buf,"@It also inflicts %s extra burning damage.\n", strlen(f->text) ? f->text : "1-4"); + snprintf(buf, BUFLEN, "It is worn %s your %s, ",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0])); + } else { + strcpy(buf, ""); + } + */ + + strcpy(buf, ""); + getflags(o->flags, retflag, &nretflags, F_GOESON, F_NONE); + for (i = 0; i < nretflags; i++) { + char posbuf[BUFLEN]; + f = retflag[i]; + + makewearstringsingle(NULL, f, "the ", posbuf); + if (i == 0) { + sprintf(buf, "It is worn %s", posbuf); + } else if (i == (nretflags - 1)) { + strcat(buf, " and "); + strcat(buf, posbuf); + } else { + strcat(buf, ", "); + strcat(buf, posbuf); + } + } + if (strlen(buf)) { + strcat(buf, ".\n"); strncat(retbuf, buf, HUGEBUFLEN); } - f = hasflag(o->flags, F_FROZEN); + + f = hasflag(o->flags, F_ARMOURRATING); if (f) { - sprintf(buf,"@It also inflicts %s extra cold damage.\n", strlen(f->text) ? f->text : "1-4"); + thisar = f->val[0] + getobbonus(o, B_TRUE); + snprintf(buf, BUFLEN, "It has an Armour Rating of %d",thisar); + } else { + thisar = 0; + snprintf(buf, BUFLEN, "It provides no protection"); + } + if (strlen(buf) && compareob) { + int diff,comparear = 0; + + f = hasflag(compareob->flags, F_ARMOURRATING); + if (f) { + comparear = f->val[0] + getobbonus(compareob, B_TRUE); + } else { + comparear = 0; + } + diff = thisar - comparear; + if (diff == 0) { + strcpy(buf2, " (=)"); + } else { + // higher AR is better + snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff > 0) ? "^g" : "^B", + (diff > 0) ? '+' : '-', abs(diff)); + } + strncat(buf, buf2, HUGEBUFLEN); + } + strcat(buf, "."); + + strncat(retbuf, buf, HUGEBUFLEN); + strncat(retbuf, "\n", HUGEBUFLEN); + + f = hasflag(o->flags, F_EVASION); + if (f) { + int evmod; + evmod = adjustarmourpenalty(player, f->val[0]); + if (evmod != 0) { + snprintf(buf, BUFLEN, "@When worn, it %s your evasion chance by %d%%\n.", (evmod < 0) ? "reduces" : "increases", abs(evmod)); + strncat(retbuf, buf, HUGEBUFLEN); + } + } + + f = hasflag(o->flags, F_ACCURACYMOD); + if (f) { + sprintf(buf, "@It will %s your evasion chance by %d%%.\n", + (f->val[0] < 0) ? "lower" : "raise", abs(f->val[0])); strncat(retbuf, buf, HUGEBUFLEN); } - f = hasflag(o->flags, F_ENCHANTED); + f = hasflag(o->flags, F_SCARY); if (f) { - sprintf(buf,"@It also inflicts %s extra magical damage if the user has spare mana.\n", strlen(f->text) ? f->text : "1-2"); + sprintf(buf, "@It may unnerve others when worn.\n"); strncat(retbuf, buf, HUGEBUFLEN); } } else { + // non armour, but still wearable. + f = hasflag(o->flags, F_GOESON); + if (f) { + snprintf(buf, BUFLEN, "It is worn %s your %s.\n",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0])); + strncat(retbuf, buf, HUGEBUFLEN); + } + } + + // critical protection chance + f = hasflag(o->flags, F_GOESON); + if (f) { + int critprotchance; + critprotchance = getcritprotection(o); + snprintf(buf, BUFLEN, "It has a %d%% chance of preventing critical hits to your %s", + critprotchance, getbodypartname(player, f->val[0])); + + if (compareob) { + int diff,comparechance = 0; + + comparechance = getcritprotection(compareob); + diff = critprotchance - comparechance; + if (diff == 0) { + strcpy(buf2, " (=)"); + } else { + // higher protchance is better + snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff > 0) ? "^g" : "^B", + (diff > 0) ? '+' : '-', abs(diff)); + } + strncat(buf, buf2, HUGEBUFLEN); + } + strcat(buf, ".\n"); + strncat(retbuf, buf, HUGEBUFLEN); + } + + if (hasflag(o->flags, F_DAMAGABLE) && isarmour(o) ) { + int showfullhp = B_FALSE; + char hpbuf[BUFLEN]; + f = hasflag(o->flags, F_OBHP); + if (isarmour(o) && getskill(player, SK_ARMOUR)) { + showfullhp = B_TRUE; + } else if (isshield(o) && getskill(player, SK_SHIELDS)) { + showfullhp = B_TRUE; + } else if ((o->type->material->id == MT_METAL) && getskill(player, SK_METALWORK)) { + showfullhp = B_TRUE; + } else if ( ((o->type->material->id == MT_LEATHER) || (o->type->material->id == MT_CLOTH)) && + getskill(player, SK_SEWING)) { + showfullhp = B_TRUE; + } + + if (isdamaged(o)) { + snprintf(buf, BUFLEN, "It has been damaged."); + } else { + snprintf(buf, BUFLEN, "It is in perfect condition."); + } + if (showfullhp) { + int pct; + pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0); + snprintf(hpbuf, BUFLEN, " [%d%%, %d/%d hp]", pct, f->val[0], f->val[1]); + } else if (isdamaged(o)) { + int pct; + pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0); + snprintf(hpbuf, BUFLEN, " [%d%% hp]", pct); + } else { + strcpy(hpbuf, ""); + } strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN); } - f = hasflag(o->flags, F_ACCURACY); + f = hasflag(o->flags, F_ARMOURSIZE); if (f) { - int acc,accnum; - acc = getobaccuracy(o, NULL); - accnum = getaccuracynum(acc); - sprintf(buf, "@It has an accuracy modifier of %c%d (%s)",(accnum < 0) ? '-' : '+', abs(accnum) , getaccuracyname(acc)); - if (compareob && hasflag(compareob->flags, F_ACCURACY)) { - int cacc,caccnum,diff; - cacc = getobaccuracy(compareob, NULL); - caccnum = getaccuracynum(cacc); - diff = accnum - caccnum; - if (diff == 0) { - strcat(buf, " (=)"); + char sizetext[BUFLEN]; + switch (f->val[0]) { + case SZ_MEDIUM: + snprintf(sizetext, BUFLEN, "small"); + break; + case SZ_LARGE: + snprintf(sizetext, BUFLEN, "very large"); + break; + case SZ_HUMAN: + default: + snprintf(sizetext, BUFLEN, "human"); + break; + } + snprintf(buf, BUFLEN, "%sIt will only fit %s sized creatures.^n\n", + (f->val[0] != getlfsize(player)) ? "^B" : "^n", sizetext); + strncat(retbuf, buf, HUGEBUFLEN); + } + + + // charges remaining + if (o->type->obclass->id == OC_WAND) { + if (isidentified(o)) { + int charges; + charges = getcharges(o); + if (charges) { + sprintf(buf, "It has %d charges left.\n",charges); } else { - // higher accuracy is better - snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff < 0) ? "^B" : "^g", (diff < 0) ? '-' : '+', abs(diff)); - strcat(buf, buf2); + sprintf(buf, "It has no charges left.\n"); } + strncat(retbuf, buf, HUGEBUFLEN); } - - strcat(buf, ".\n"); - strncat(retbuf, buf, HUGEBUFLEN); - } - - critchance = getcritchance(player, o, NULL); - sprintf(buf, "@You have a %d%% critical hit chance with it", critchance); - if (compareob) { - int ccritch,diff; - ccritch = getcritchance(player, compareob, NULL); - diff = critchance - ccritch; - if (diff == 0) { - strcat(buf, " (=)"); - } else { - // higher crit chance is better - snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff < 0) ? "^B" : "^g", - (diff > 0) ? '+' : '-', abs(diff)); - strcat(buf, buf2); - } - } - - strcat(buf, ".\n"); - strncat(retbuf, buf, HUGEBUFLEN); - - f = hasflag(o->flags, F_OBATTACKDELAY); - if (f) delay = f->val[0]; - else delay = 100; - sprintf(buf, "@Its attack delay is %d%%",delay - 100); - if (compareob) { - int cdelay,diff; - f = hasflag(compareob->flags, F_OBATTACKDELAY); - if (f) cdelay = f->val[0]; - else cdelay = 100; - diff = delay - cdelay; - if (diff == 0) { - strcat(buf, " (=)"); - } else { - // lower attack delay is better - snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff > 0) ? "^B" : "^g", - (diff > 0) ? '+' : '-', abs(diff)); - strcat(buf, buf2); - } - } - - strcat(buf, ".\n"); - strncat(retbuf, buf, HUGEBUFLEN); - } - // damage - if (isarmour(o)) { - int thisar = 0; - flag_t *goesmulti; - goesmulti = hasflag(o->flags, F_GOESONMULTI); - -/* - f = hasflag(o->flags, F_GOESON); - if (f) { - snprintf(buf, BUFLEN, "It is worn %s your %s, ",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0])); - } else { - strcpy(buf, ""); - } -*/ - - strcpy(buf, ""); - getflags(o->flags, retflag, &nretflags, F_GOESON, F_NONE); - for (i = 0; i < nretflags; i++) { - char posbuf[BUFLEN]; - f = retflag[i]; - - makewearstringsingle(NULL, f, "the ", posbuf); - if (i == 0) { - sprintf(buf, "It is worn %s", posbuf); - } else if (i == (nretflags - 1)) { - strcat(buf, " and "); - strcat(buf, posbuf); - } else { - strcat(buf, ", "); - strcat(buf, posbuf); - } - } - if (strlen(buf)) { - strcat(buf, ".\n"); - strncat(retbuf, buf, HUGEBUFLEN); - } - - f = hasflag(o->flags, F_ARMOURRATING); - if (f) { - thisar = f->val[0] + getobbonus(o, B_TRUE); - snprintf(buf, BUFLEN, "It has an Armour Rating of %d",thisar); - } else { - thisar = 0; - snprintf(buf, BUFLEN, "It provides no protection"); - } - if (strlen(buf) && compareob) { - int diff,comparear = 0; - - f = hasflag(compareob->flags, F_ARMOURRATING); - if (f) { - comparear = f->val[0] + getobbonus(compareob, B_TRUE); - } else { - comparear = 0; - } - diff = thisar - comparear; - if (diff == 0) { - strcpy(buf2, " (=)"); - } else { - // higher AR is better - snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff > 0) ? "^g" : "^B", - (diff > 0) ? '+' : '-', abs(diff)); - } - strncat(buf, buf2, HUGEBUFLEN); - } - strcat(buf, "."); - - strncat(retbuf, buf, HUGEBUFLEN); - strncat(retbuf, "\n", HUGEBUFLEN); - - f = hasflag(o->flags, F_EVASION); - if (f) { - int evmod; - evmod = adjustarmourpenalty(player, f->val[0]); - if (evmod != 0) { - snprintf(buf, BUFLEN, "@When worn, it %s your evasion chance by %d%%\n.", (evmod < 0) ? "reduces" : "increases", abs(evmod)); + } else if (o->type->obclass->id == OC_GODSTONE) { + if (isidentified(o)) { + int charges,max; + getchargeinfo(o, &charges, &max); + if (charges == max) { + sprintf(buf, "It is fully charged.\n"); + } else { + sprintf(buf, "It is depleted.\n"); + } strncat(retbuf, buf, HUGEBUFLEN); } } - f = hasflag(o->flags, F_ACCURACYMOD); + f = hasflag(o->flags, F_PICKLOCKS); if (f) { - sprintf(buf, "@It will %s your evasion chance by %d%%.\n", - (f->val[0] < 0) ? "lower" : "raise", abs(f->val[0])); + sprintf(buf, "You can use it to pick locks.\n"); strncat(retbuf, buf, HUGEBUFLEN); } - f = hasflag(o->flags, F_SCARY); + + f = hasflag(o->flags, F_HELPSCLIMB); if (f) { - sprintf(buf, "@It may unnerve others when worn.\n"); + sprintf(buf, "It can be used to assist in climbing.\n"); strncat(retbuf, buf, HUGEBUFLEN); } - } else { - // non armour, but still wearable. - f = hasflag(o->flags, F_GOESON); + f = hasflag(o->flags, F_HELPSDISARM); if (f) { - snprintf(buf, BUFLEN, "It is worn %s your %s.\n",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0])); + sprintf(buf, "It gives a +%d%% bonus when disarming traps.\n", f->val[0] * 5); strncat(retbuf, buf, HUGEBUFLEN); } - } - - // critical protection chance - f = hasflag(o->flags, F_GOESON); - if (f) { - int critprotchance; - critprotchance = getcritprotection(o); - snprintf(buf, BUFLEN, "It has a %d%% chance of preventing critical hits to your %s", - critprotchance, getbodypartname(player, f->val[0])); - - if (compareob) { - int diff,comparechance = 0; - - comparechance = getcritprotection(compareob); - diff = critprotchance - comparechance; - if (diff == 0) { - strcpy(buf2, " (=)"); - } else { - // higher protchance is better - snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff > 0) ? "^g" : "^B", - (diff > 0) ? '+' : '-', abs(diff)); - } - strncat(buf, buf2, HUGEBUFLEN); - } - strcat(buf, ".\n"); - strncat(retbuf, buf, HUGEBUFLEN); - } - - if (hasflag(o->flags, F_DAMAGABLE) && isarmour(o) ) { - int showfullhp = B_FALSE; - char hpbuf[BUFLEN]; - f = hasflag(o->flags, F_OBHP); - if (isarmour(o) && getskill(player, SK_ARMOUR)) { - showfullhp = B_TRUE; - } else if (isshield(o) && getskill(player, SK_SHIELDS)) { - showfullhp = B_TRUE; - } else if ((o->type->material->id == MT_METAL) && getskill(player, SK_METALWORK)) { - showfullhp = B_TRUE; - } else if ( ((o->type->material->id == MT_LEATHER) || (o->type->material->id == MT_CLOTH)) && - getskill(player, SK_SEWING)) { - showfullhp = B_TRUE; + f = hasflag(o->flags, F_HELPSREST); + if (f) { + sprintf(buf, "It provides a %d%% bonus to health regeneration when resting.", f->val[0] * 5); + strncat(retbuf, buf, HUGEBUFLEN); } - if (isdamaged(o)) { - snprintf(buf, BUFLEN, "It has been damaged."); - } else { - snprintf(buf, BUFLEN, "It is in perfect condition."); - } - if (showfullhp) { - int pct; - pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0); - snprintf(hpbuf, BUFLEN, " [%d%%, %d/%d hp]", pct, f->val[0], f->val[1]); - } else if (isdamaged(o)) { - int pct; - pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0); - snprintf(hpbuf, BUFLEN, " [%d%% hp]", pct); - } else { - strcpy(hpbuf, ""); - } - strncat(retbuf, buf, HUGEBUFLEN); + + // skip line strncat(retbuf, "\n", HUGEBUFLEN); - } - f = hasflag(o->flags, F_ARMOURSIZE); - if (f) { - char sizetext[BUFLEN]; - switch (f->val[0]) { - case SZ_MEDIUM: - snprintf(sizetext, BUFLEN, "small"); - break; - case SZ_LARGE: - snprintf(sizetext, BUFLEN, "very large"); - break; - case SZ_HUMAN: - default: - snprintf(sizetext, BUFLEN, "human"); - break; - } - snprintf(buf, BUFLEN, "%sIt will only fit %s sized creatures.^n\n", - (f->val[0] != getlfsize(player)) ? "^B" : "^n", sizetext); - strncat(retbuf, buf, HUGEBUFLEN); - } - - - // charges remaining - if (o->type->obclass->id == OC_WAND) { - if (isidentified(o)) { - int charges; - charges = getcharges(o); - if (charges) { - sprintf(buf, "It has %d charges left.\n",charges); + // been made invulnerable ? + if (hasflagknown(o->type->flags, F_INVULNERABLE) && !hasflag(o->flags, F_DAMAGABLE)) { + strncat(retbuf, "It is invulnerable to most damage.\n", HUGEBUFLEN); + } else { + // immunities + strcpy(buf, ""); + f = hasflagval(o->flags, F_DTIMMUNE, DT_ALL, NA, NA, NULL); + if (f) { + snprintf(buf, BUFLEN, "It is immune to %s", getdamname(DT_ALL)); } else { - sprintf(buf, "It has no charges left.\n"); + int first = B_TRUE; + for (i = 0; i < MAXDAMTYPE; i++) { + if (basedamagetype(i) != i) continue; + f = isimmuneto(o->flags, i, B_FALSE); + if (f) { + char buf2[BUFLEN]; + if (first) { + snprintf(buf2, BUFLEN, "It is immune to: %s", getdamname(i)); + first = B_FALSE; + } else { + snprintf(buf2, BUFLEN, ", %s", getdamname(i)); + } + strcat(buf, buf2); + } + } } - strncat(retbuf, buf, HUGEBUFLEN); - } - } else if (o->type->obclass->id == OC_GODSTONE) { - if (isidentified(o)) { - int charges,max; - getchargeinfo(o, &charges, &max); - if (charges == max) { - sprintf(buf, "It is fully charged.\n"); + if (strlen(buf) > 0) { + strcat(buf, ".\n"); + strncat(retbuf, buf, HUGEBUFLEN); + } + + // resistances + strcpy(buf, ""); + f = hasflagval(o->flags, F_DTRESIST, DT_ALL, NA, NA, NULL); + if (f) { + snprintf(buf, BUFLEN, "It is resistant to %s", getdamname(DT_ALL)); } else { - sprintf(buf, "It is depleted.\n"); + int first = B_TRUE; + for (i = 0; i < MAXDAMTYPE; i++) { + if (basedamagetype(i) != i) continue; + f = isresistantto(o->flags, i, B_FALSE); + if (f) { + char buf2[BUFLEN]; + if (first) { + snprintf(buf2, BUFLEN, "It is resistant to: %s", getdamname(i)); + first = B_FALSE; + } else { + snprintf(buf2, BUFLEN, ", %s", getdamname(i)); + } + strcat(buf, buf2); + } + } + } + if (strlen(buf) > 0) { + strcat(buf, ".\n"); + strncat(retbuf, buf, HUGEBUFLEN); + } + + // vulnerabilities + strcpy(buf, ""); + f = hasflagval(o->flags, F_DTVULN, DT_ALL, NA, NA, NULL); + if (f) { + snprintf(buf, BUFLEN, "It is vulnerable to %s", getdamname(DT_ALL)); + } else { + int first = B_TRUE; + for (i = 0; i < MAXDAMTYPE; i++) { + if (basedamagetype(i) != i) continue; + f = isvulnto(o->flags, i, B_FALSE); + if (f) { + char buf2[BUFLEN]; + if (first) { + snprintf(buf2, BUFLEN, "It is vulnerable to: %s", getdamname(i)); + first = B_FALSE; + } else { + snprintf(buf2, BUFLEN, ", %s", getdamname(i)); + } + strcat(buf, buf2); + } + } + } + if (strlen(buf) > 0) { + strcat(buf, ".\n"); + strncat(retbuf, buf, HUGEBUFLEN); } - strncat(retbuf, buf, HUGEBUFLEN); } - } - - f = hasflag(o->flags, F_PICKLOCKS); - if (f) { - sprintf(buf, "You can use it to pick locks.\n"); - strncat(retbuf, buf, HUGEBUFLEN); - } - - f = hasflag(o->flags, F_HELPSCLIMB); - if (f) { - sprintf(buf, "It can be used to assist in climbing.\n"); - strncat(retbuf, buf, HUGEBUFLEN); - } - + } // end if isknown // skip line strncat(retbuf, "\n", HUGEBUFLEN); - // been made invulnerable ? - if (hasflagknown(o->type->flags, F_INVULNERABLE) && !hasflag(o->flags, F_DAMAGABLE)) { - strncat(retbuf, "It is invulnerable to most damage.\n", HUGEBUFLEN); - } else { - // immunities - strcpy(buf, ""); - f = hasflagval(o->flags, F_DTIMMUNE, DT_ALL, NA, NA, NULL); - if (f) { - snprintf(buf, BUFLEN, "It is immune to %s", getdamname(DT_ALL)); - } else { - int first = B_TRUE; - for (i = 0; i < MAXDAMTYPE; i++) { - if (basedamagetype(i) != i) continue; - f = isimmuneto(o->flags, i); - if (f) { - char buf2[BUFLEN]; - if (first) { - snprintf(buf2, BUFLEN, "It is immune to: %s", getdamname(i)); - first = B_FALSE; - } else { - snprintf(buf2, BUFLEN, ", %s", getdamname(i)); - } - strcat(buf, buf2); - } - } - } - if (strlen(buf) > 0) { - strcat(buf, ".\n"); - strncat(retbuf, buf, HUGEBUFLEN); - } - - // resistances - strcpy(buf, ""); - f = hasflagval(o->flags, F_DTRESIST, DT_ALL, NA, NA, NULL); - if (f) { - snprintf(buf, BUFLEN, "It is resistant to %s", getdamname(DT_ALL)); - } else { - int first = B_TRUE; - for (i = 0; i < MAXDAMTYPE; i++) { - if (basedamagetype(i) != i) continue; - f = isresistantto(o->flags, i); - if (f) { - char buf2[BUFLEN]; - if (first) { - snprintf(buf2, BUFLEN, "It is resistant to: %s", getdamname(i)); - first = B_FALSE; - } else { - snprintf(buf2, BUFLEN, ", %s", getdamname(i)); - } - strcat(buf, buf2); - } - } - } - if (strlen(buf) > 0) { - strcat(buf, ".\n"); - strncat(retbuf, buf, HUGEBUFLEN); - } - - // vulnerabilities - strcpy(buf, ""); - f = hasflagval(o->flags, F_DTVULN, DT_ALL, NA, NA, NULL); - if (f) { - snprintf(buf, BUFLEN, "It is vulnerable to %s", getdamname(DT_ALL)); - } else { - int first = B_TRUE; - for (i = 0; i < MAXDAMTYPE; i++) { - if (basedamagetype(i) != i) continue; - f = isvulnto(o->flags, i); - if (f) { - char buf2[BUFLEN]; - if (first) { - snprintf(buf2, BUFLEN, "It is vulnerable to: %s", getdamname(i)); - first = B_FALSE; - } else { - snprintf(buf2, BUFLEN, ", %s", getdamname(i)); - } - strcat(buf, buf2); - } - } - } - if (strlen(buf) > 0) { - strcat(buf, ".\n"); - strncat(retbuf, buf, HUGEBUFLEN); - } - } - - for (f = o->flags->first ; f ; f = f->next) { if ((f->id == F_HITCONFER) && (f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) { sprintf(buf, "It has been coated with poison.\n"); @@ -5136,9 +5155,6 @@ char *makedesc_ob(object_t *o, char *retbuf) { } - // skip line - strncat(retbuf, "\n", HUGEBUFLEN); - // physical properties f = hasflag(o->flags, F_ONFIRE); if (f) { @@ -5155,7 +5171,6 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf, "It is rusty.\n"); strncat(retbuf, buf, HUGEBUFLEN); } - f = hasflag(o->flags, F_WATERPROOF); if (f) { sprintf(buf, "It is waterproof.\n"); @@ -5173,13 +5188,12 @@ char *makedesc_ob(object_t *o, char *retbuf) { strncat(retbuf, buf, HUGEBUFLEN); } + // other weapon properties... f = hasflag(o->flags, F_NEEDSSPACE); - if (f) { + if (f && f->known) { sprintf(buf, "It is ineffective in confined spaces due to its length.\n"); strncat(retbuf, buf, HUGEBUFLEN); } - - // show special properties where known f = hasflag(o->flags, F_ARMOURPIERCE); if (f && f->known) { sprintf(buf, "Armour will not reduce %s damage.\n",(o->amt == 1) ? "its" : "their"); @@ -5679,29 +5693,66 @@ char *makedesc_ob(object_t *o, char *retbuf) { return retbuf; } -char *makedesc_race(enum RACE rid, char *retbuf, int showbonpen) { +char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { race_t *r; char buf[HUGEBUFLEN]; flag_t *retflag[MAXCANDIDATES],*f; int nretflags,i; + flagpile_t *doneflags; + + doneflags = addflagpile(NULL, NULL); strcpy(retbuf, ""); r = findrace(rid); - snprintf(buf, HUGEBUFLEN, "%s\n\n", r->desc); - strncat(retbuf, buf, HUGEBUFLEN); - - if (showbonpen) { + if (showextra) { + int a; int curidx,donesomething; - - // bonuses - getflags(r->flags, retflag, &nretflags, F_BONDESC, F_NONE); - if (nretflags) { - snprintf(buf, HUGEBUFLEN, "^%dBonuses^n:\n", C_WHITE); + char bonheading[BUFLEN],penheading[BUFLEN]; + sprintf(bonheading, "^%dStrengths^n:\n", C_WHITE); + sprintf(penheading, "^%dWeaknesses^n:\n", C_WHITE); + // stats + snprintf(buf, HUGEBUFLEN, "HD: %-3d ", gethitdicerace(r)); + strncat(retbuf, buf, HUGEBUFLEN); + for (a = 0; a < MAXATTS; a++) { + char ch[BUFLENTINY]; + int col; + f = hasflagval(r->flags, F_STARTATT, a, NA, NA, NULL); + if (f) { + switch (f->val[1]) { + case AT_RANDOM: sprintf(ch, "?"); col = C_GREY; break; + case AT_EXLOW: sprintf(ch, "%-4s", "xxxx"); col = C_MAGENTA; break; + case AT_VLOW: sprintf(ch, "%-4s", "xxx"); col = C_RED; break; + case AT_LOW: sprintf(ch, "%-4s", "xx"); col = C_RED; break; + case AT_LTAVERAGE: sprintf(ch, "%-4s", "x"); col = C_RED; break; + case AT_AVERAGE: sprintf(ch, "%-4s", "-"); col = C_GREY; break; + case AT_GTAVERAGE: sprintf(ch, "%-4s", "+"); col = C_GREEN; break; + case AT_HIGH: sprintf(ch, "%-4s", "++"); col = C_GREEN; break; + case AT_VHIGH: sprintf(ch, "%-4s", "+++"); col = C_GREEN; break; + case AT_EXHIGH: sprintf(ch, "%-4s", "++++"); col = C_BOLDBLUE; break; + } + } else { + sprintf(ch, "%-4s", "?"); + col = C_GREY; + } + sprintf(buf, "^n%s:^%d%s ^n", getattrabbrev(a), col, ch); strncat(retbuf, buf, HUGEBUFLEN); + } + strncat(retbuf, "\n\n", HUGEBUFLEN); + + snprintf(buf, HUGEBUFLEN, "%s\n\n", r->desc); + strncat(retbuf, buf, HUGEBUFLEN); + + ////////////////////////////////////////////// + // bonuses + ////////////////////////////////////////////// + strncat(retbuf, bonheading, HUGEBUFLEN); + // manually specified bonuses + getflags(r->flags, retflag, &nretflags, F_BONDESC, F_NONE); + curidx = 0; + if (nretflags) { donesomething = B_TRUE; - curidx = 0; while (donesomething) { donesomething = B_FALSE; for (i = 0; i < nretflags; i++) { @@ -5715,17 +5766,153 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showbonpen) { } } } - } else { - snprintf(buf, HUGEBUFLEN, "^%dBonuses^n:\n@None.\n", C_WHITE); - strncat(retbuf, buf, HUGEBUFLEN); + } + + // auto bonuses from flags + for (f = r->flags->first ; f ; f = f->next) { + char *p; + objecttype_t *ot; + int power; + strcpy(buf, ""); + switch (f->id) { + case F_AUTOCREATEOB: + p = makeplural(f->text); + sprintf(buf, "Automatically creates %s around itself.", p); + free(p); + break; + case F_AQUATIC: strcpy(buf, "Moves normally through water"); break; + case F_AWARENESS: strcpy(buf, "Can see in all directions."); break; + case F_CANEATRAW: strcpy(buf, "Can safely digest raw meat."); break; + case F_CANWILL: + ot = findot(f->val[0]); + sprintf(buf, "%s: %s", (ot->obclass->id == OC_ABILITY) ? "Ability" : "Spell", + ot->name); + texttospellopts(f->text, "pw:", &power, NULL); + if (power) { + strcat(buf, " (power "); + strcat(buf, roman(power)); + strcat(buf, ")"); + } + break; + case F_DODGES: strcpy(buf, "Can dodge attacks into adjacent locations"); break; + case F_DTIMMUNE: + if (!hasflag(doneflags, F_DTIMMUNE)) { + if (f->val[0] == DT_ALL) { + sprintf(buf, "Immune to %s.", getdamname(DT_ALL)); + } else { + char buf2[BUFLEN]; + int first = B_TRUE,n; + strcpy(buf, ""); + for (n = 0; n < MAXDAMTYPE; n++) { + if (basedamagetype(n) != n) continue; + if (isimmuneto(r->flags, n, B_FALSE)) { + if (first) { + sprintf(buf2, "Immune to: %s", getdamname(n)); + first = B_FALSE; + } else { + sprintf(buf2, ", %s", getdamname(n)); + } + strcat(buf, buf2); + } + } + } + addflag(doneflags, F_DTIMMUNE, B_TRUE, NA, NA, NULL); + } + break; + case F_DTRESIST: + if (!hasflag(doneflags, F_DTRESIST)) { + if (f->val[0] == DT_ALL) { + sprintf(buf, "Resistant to %s.", getdamname(DT_ALL)); + } else { + char buf2[BUFLEN]; + int first = B_TRUE,n; + strcpy(buf, ""); + for (n = 0; n < MAXDAMTYPE; n++) { + if (basedamagetype(n) != n) continue; + if (isimmuneto(r->flags, n, B_FALSE)) { + if (first) { + sprintf(buf2, "Resistant to: %s", getdamname(n)); + first = B_FALSE; + } else { + sprintf(buf2, ", %s", getdamname(n)); + } + strcat(buf, buf2); + } + } + } + addflag(doneflags, F_DTRESIST, B_TRUE, NA, NA, NULL); + } + break; + case F_DTVULN: + if (!hasflag(doneflags, F_DTVULN)) { + if (f->val[0] == DT_ALL) { + sprintf(buf, "Vulnerable to %s.", getdamname(DT_ALL)); + } else { + char buf2[BUFLEN]; + int first = B_TRUE,n; + strcpy(buf, ""); + for (n = 0; n < MAXDAMTYPE; n++) { + if (basedamagetype(n) != n) continue; + if (isimmuneto(r->flags, n, B_FALSE)) { + if (first) { + sprintf(buf2, "Vulnerable to: %s", getdamname(n)); + first = B_FALSE; + } else { + sprintf(buf2, ", %s", getdamname(n)); + } + strcat(buf, buf2); + } + } + } + addflag(doneflags, F_DTVULN, B_TRUE, NA, NA, NULL); + } + break; + case F_ENHANCESMELL: sprintf(buf, "Enhanced sense of smell (range %d)", f->val[0]); break; + case F_FLYING: sprintf(buf, "Can fly at will"); break; + case F_HEAVYBLOW: sprintf(buf, "Attacks will knock enemies backwards"); break; + case F_HUMANOID: sprintf(buf, "Can use weapons and armour."); break; + case F_LEVITATING: sprintf(buf, "Can levitate at will"); break; + case F_MEDITATES: sprintf(buf, "Meditates to retain awareness while sleeping."); break; + case F_MPMOD: if (f->val[0] > 0) sprintf(buf, "+%d Mana", f->val[0]); break; + case F_NOSLEEP: sprintf(buf, "Does not sleep"); break; + case F_PACKATTACK: sprintf(buf, "Deals extra damage when in a pack."); break; + case F_PHALANX: sprintf(buf, "Gains extra defence when in a pack."); break; + case F_PHOTOMEM: sprintf(buf, "Photographic memory"); break; + case F_QUICKBITE: sprintf(buf, "Can bite wounded enemies for extra damage"); break; + case F_REGENERATES: sprintf(buf, "Automatically regenerates health."); break; + case F_RESISTMAG: sprintf(buf, "Magic-resistant"); break; + case F_SEEINDARK: sprintf(buf, "Darkvision (range %d)", f->val[0]); break; + case F_SEEINVIS: sprintf(buf, "Can see invisible things"); break; + case F_SILENTMOVE: sprintf(buf, "Moves silently"); break; + case F_STABILITY: sprintf(buf, "Will not fall on slippery ground."); break; + case F_STARTSKILL: sprintf(buf, "%s %s", getskillname(f->val[0]), getskilllevelname(f->val[1])); break; + case F_STENCH: sprintf(buf, "Emits a foul odour which affects others"); break; + case F_TREMORSENSE: sprintf(buf, "Can sense vibrations (range %d)", f->val[0]); break; + case F_VISRANGEMOD: if (f->val[0] > 0) sprintf(buf, "Enhanced vision range (+%d)", f->val[0]); break; + default: + break; + } + if (strlen(buf)) { + strncat(retbuf, "@- ", HUGEBUFLEN); + strcat(buf, "\n"); + strncat(retbuf, buf, HUGEBUFLEN); + curidx++; + } } + if (curidx == 0) { + strncat(retbuf, "^n@None.\n", HUGEBUFLEN); + } + + ////////////////////////////////////////////// + // penalties + ////////////////////////////////////////////// + strncat(retbuf, penheading, HUGEBUFLEN); + // manually specified penalties + curidx = 0; getflags(r->flags, retflag, &nretflags, F_PENDESC, F_NONE); if (nretflags) { - snprintf(buf, HUGEBUFLEN, "^%dPenalties^n:\n", C_WHITE); - strncat(retbuf, buf, HUGEBUFLEN); donesomething = B_TRUE; - curidx = 0; while (donesomething) { donesomething = B_FALSE; for (i = 0; i < nretflags; i++) { @@ -5739,15 +5926,57 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showbonpen) { } } } - } else { - snprintf(buf, HUGEBUFLEN, "^%dPenalties^n:\n@None.\n", C_WHITE); - strncat(retbuf, buf, HUGEBUFLEN); + } + + // auto penalties from flags + for (f = r->flags->first ; f ; f = f->next) { + material_t *mt; + strcpy(buf, ""); + switch (f->id) { + case F_CARNIVORE: sprintf(buf, "Will only eat meat."); break; + case F_DEAF: sprintf(buf, "Deaf"); break; + case F_DIURNAL: sprintf(buf, "Sleeps at night."); break; + case F_FASTMETAB: sprintf(buf, "Fast metabolism (needs to eat often)"); break; + case F_MATVULN: + mt = findmaterial(f->val[0]); + sprintf(buf, "Takes %d%% damage from weapons made of %s.", retflag[i]->val[1], mt->name); + break; + case F_MPMOD: if (f->val[0] < 0) sprintf(buf, "-%d Mana", f->val[0]); break; + case F_NEEDSWATER: sprintf(buf, "Will suffocate without water"); break; + case F_NOCTURNAL: sprintf(buf, "Sleeps during the day."); break; + case F_NOPACK: sprintf(buf, "Cannot carry objects."); break; + case F_SIZE: + if (hasflag(r->flags, F_HUMANOID) && (f->val[0] != SZ_HUMAN)) { + sprintf(buf, "Only specially sized armour will fit."); + } + break; + case F_STAYINROOM: + sprintf(buf, "Will not leave its home territory."); break; + break; + case F_TAMABLE: + sprintf(buf, "Susceptible to bribery."); break; + break; + case F_VEGETARIAN: sprintf(buf, "Will not eat meat."); break; + case F_VISRANGEMOD: if (f->val[0] < 0) sprintf(buf, "Reduced vision range (%d)", f->val[0]); break; + case F_PARTVEGETARIAN: sprintf(buf, "Will only eat meat when hungry."); break; + default: + break; + } + if (strlen(buf)) { + strncat(retbuf, "@- ", HUGEBUFLEN); + strcat(buf, "\n"); + strncat(retbuf, buf, HUGEBUFLEN); + curidx++; + } } - while (donesomething) { - donesomething = B_FALSE; + + if (curidx == 0) { + strncat(retbuf, "^n@None.\n", HUGEBUFLEN); } } + free(doneflags); + return retbuf; } @@ -6475,7 +6704,9 @@ void dohelp(char helpmode) { initprompt(&prompt, "Describe which race (ESC when done)?"); for (r = firstrace ; r ; r = r->next) { - addchoice(&prompt, 'a', r->name, NULL, r, r->desc); + if (r->known) { + addchoice(&prompt, 'a', r->name, NULL, r, r->desc); + } } addchoice(&prompt, '\0', "(done)", NULL, NULL, NULL); prompt.maycancel = B_TRUE; @@ -6484,7 +6715,7 @@ void dohelp(char helpmode) { done = B_TRUE; } else { r = (race_t *)prompt.result; - describerace(r->id); + if (r) describerace(r->id); } } else if (helpmode == 's') { skill_t *sk; @@ -6502,7 +6733,8 @@ void dohelp(char helpmode) { done = B_TRUE; } else { sk = (skill_t *)prompt.result; - describeskill(sk->id, PR_INEPT); + if (sk) describeskill(sk->id, PR_INEPT); + else done = B_TRUE; } } else if (helpmode == 'g') { lifeform_t *god; @@ -7262,6 +7494,21 @@ int drop(object_t *o, int count) { return B_FALSE; } +void dumpoc(void) { + enum RARITY rr; + objectclass_t *oc; + dblog("BEGIN OBJECTCLASS DUMP"); + for (rr = RR_FREQUENT; rr <= RR_VERYRARE; rr++ ){ + dblog(" %s", getrarityname(rr)); + for (oc = objectclass ; oc ; oc = oc->next) { + if (oc->rarity == rr) { + dblog(" %s", oc->name); + } + } + } + dblog("END OBJECTCLASS DUMP"); +} + void dumpspells(void) { objecttype_t *ot; enum SPELLSCHOOL ss; @@ -9645,7 +9892,7 @@ void showlfstats(lifeform_t *lf, int showall) { int x=0; // description first. descbuf = malloc(HUGEBUFLEN * sizeof(char)); - makedesc_race(lf->race->id, descbuf, B_FALSE); + makedesc_race(lf->race->id, descbuf, B_FALSE ); //mvwprintw(mainwin, y, 0, "%s", descbuf); wrapprint(mainwin, &y, &x, "%s", descbuf); free(descbuf); @@ -10302,8 +10549,6 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } - - // show racial effects if (hasjob(lf, J_PIRATE)) { mvwprintw(mainwin, y, 0, "%s can hold %s liquor well.", you(lf), isplayer(lf) ? "Your" : "its"); @@ -10327,25 +10572,18 @@ void showlfstats(lifeform_t *lf, int showall) { } } - // traits based on the monster's racial characteristics - // these are fairly common knowledge - ie if you ask around most - // people would know this. + + // we DONT show traits based on the monster's racial characteristics + // here. leave that to makedesc_race. + // + // This display is only for effects specific to this INDIVIDUAL lifeform. if (showall || (lorelev >= PR_NOVICE)) { - if (lfhasflag(lf, F_AQUATIC)) { - mvwprintw(mainwin, y, 0, "%s %s aquatic, and move normally through water.", you(lf), is(lf)); - y++; - } if (isdeaf(lf)) { mvwprintw(mainwin, y, 0, "%s %s deaf.", you(lf), is(lf)); y++; } - f = lfhasknownflag(lf, F_NOPACK); - if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s cannot carry objects.", you(lf)); - y++; - } f = lfhasknownflag(lf, F_ENHANCESMELL); - if (f) { + if (f && (f->lifetime != FROMRACE)) { mvwprintw(mainwin, y, 0, "%s %s an enhanced sense of smell.", you(lf), isplayer(lf) ? "have" : "has"); y++; } @@ -10355,43 +10593,12 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } - f = lfhasknownflag(lf, F_PACKATTACK); - if (f && (f->known)) { - snprintf(buf, BUFLEN,"%s deal%s extra damage when in a pack.", you(lf), isplayer(lf) ? "" : "s"); - mvwprintw(mainwin, y, 0, buf); - y++; - } - f = lfhasknownflag(lf, F_PHALANX); - if (f && (f->known)) { - snprintf(buf, BUFLEN,"%s gain%s %d extra armour rating when in a %s pack.", you(lf), isplayer(lf) ? "" : "s", - f->val[0], f->text); - mvwprintw(mainwin, y, 0, buf); - y++; - } f = lfhasknownflag(lf, F_HEAVYBLOW); - if (f) { + if (f && (f->lifetime != FROMRACE)) { snprintf(buf, BUFLEN,"%s%s attacks knock enemies back.", you(lf), getpossessive(you(lf))); mvwprintw(mainwin, y, 0, buf); y++; } - f = lfhasknownflag(lf, F_QUICKBITE); - if (f && (f->known)) { - snprintf(buf, BUFLEN,"%s can bite wounded enemies for extra damage.", you(lf)); - mvwprintw(mainwin, y, 0, buf); - y++; - } - f = lfhasflag(lf, F_MEDITATES); - if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s retain awareness via 'sleeping' through meditation.", you(lf)); - y++; - } - - f = lfhasflag(lf, F_NEEDSWATER); - if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s will suffocate without water.", you(lf)); - y++; - } - f = lfhasknownflag(lf, F_REGENERATES); if (f) { char regenspeed[BUFLEN]; @@ -10427,27 +10634,27 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } f = lfhasknownflag(lf, F_TREMORSENSE); - if (f) { + if (f && (f->lifetime != FROMRACE)) { mvwprintw(mainwin, y, 0, "%s can 'see' by sensing vibrations around %s.", you(lf), you(lf)); y++; } f = lfhasflag(lf, F_STENCH); - if (f && (f->known)) { + if (f && (f->known) && (f->lifetime != FROMRACE)) { mvwprintw(mainwin, y, 0, "%s smell%s terrible.", you(lf), isplayer(lf) ? "" : "s"); y++; } f = lfhasknownflag(lf, F_SEEINDARK); - if (f) { + if (f && (f->known) && (f->lifetime != FROMRACE)) { mvwprintw(mainwin, y, 0, "%s can see in the dark.", you(lf)); y++; } f = lfhasknownflag(lf, F_SEEINVIS); - if (f) { + if (f && (f->known) && (f->lifetime != FROMRACE)) { mvwprintw(mainwin, y, 0, "%s can see invisible things.", you(lf)); y++; } f = lfhasknownflag(lf, F_XRAYVIS); - if (f) { + if (f && (f->known) && (f->lifetime != FROMRACE)) { mvwprintw(mainwin, y, 0, "%s can see through walls.", you(lf)); y++; } @@ -10462,17 +10669,6 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } } - - // material vulnerbilities - getflags(lf->flags, retflag, &nretflags, F_MATVULN, F_NONE); - for (i = 0; i < nretflags; i++) { - material_t *mt; - mt = findmaterial(retflag[i]->val[0]); - - sprintf(buf, "%s take%s %d%% damage from weapons made of %s.", you(lf), - isplayer(lf) ? "" : "s", retflag[i]->val[1], mt->name); - mvwprintw(mainwin, y, 0, "%s", buf); y++; - } } // traits based on the monster's bevaviour. @@ -10482,12 +10678,6 @@ void showlfstats(lifeform_t *lf, int showall) { if (!isplayer(lf)) { int morale; char moralebuf[BUFLEN]; - if (lfhasflag(lf, F_NOCTURNAL)) { - mvwprintw(mainwin, y, 0, "It normally sleeps during the day."); y++; - } - if (lfhasflag(lf, F_DIURNAL)) { - mvwprintw(mainwin, y, 0, "It normally sleeps during the night."); y++; - } morale = getmorale(lf); if (morale >= 30) { strcpy(moralebuf, "fearless"); @@ -10505,22 +10695,7 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "It looks %s.", moralebuf); y++; } - // eating habits - if (lfhasflag(lf, F_CARNIVORE)) { - mvwprintw(mainwin, y, 0, "%s %s a carnivore (only eats meat).", you(lf), is(lf)); - y++; - } else if (lfhasflag(lf, F_PARTVEGETARIAN)) { - mvwprintw(mainwin, y, 0, "%s %s a vegetarian (will only eat meat when hungry).", you(lf), is(lf)); - y++; - } else if (lfhasflag(lf, F_VEGETARIAN)) { - mvwprintw(mainwin, y, 0, "%s %s a vegetarian (will not eat meat).", you(lf), is(lf)); - y++; - } - if (lfhasflag(lf, F_CANEATRAW)) { - mvwprintw(mainwin, y, 0, "%s can digest raw meat.", you(lf)); - y++; - } - + // damage desistances/vulnerabilities // resistances strcpy(buf, ""); @@ -10531,7 +10706,7 @@ void showlfstats(lifeform_t *lf, int showall) { first = B_TRUE; for (i = 0; i < MAXDAMTYPE; i++) { if (basedamagetype(i) != i) continue; - f = isresistantto(lf->flags, i); + f = isresistantto(lf->flags, i, B_TRUE); if (f) { if (first) { snprintf(buf2, BUFLEN, "%s %s resistant to: %s", you(lf), is(lf),getdamnamenoun(i)); @@ -10565,7 +10740,7 @@ void showlfstats(lifeform_t *lf, int showall) { first = B_TRUE; for (i = 0; i < MAXDAMTYPE; i++) { if (basedamagetype(i) != i) continue; - f = isimmuneto(lf->flags, i); + f = isimmuneto(lf->flags, i, B_TRUE); if (f) { if (first) { snprintf(buf2, BUFLEN, "%s %s immune to: %s", you(lf), is(lf), getdamname(i)); @@ -10591,7 +10766,7 @@ void showlfstats(lifeform_t *lf, int showall) { first = B_TRUE; for (i = 0; i < MAXDAMTYPE; i++) { if (basedamagetype(i) != i) continue; - f = isvulnto(lf->flags, i); + f = isvulnto(lf->flags, i, B_TRUE); if (f) { if (first) { snprintf(buf2, BUFLEN, "%s %s vulnerable to: %s", you(lf), is(lf), getdamnamenoun(i)); @@ -10650,19 +10825,6 @@ void showlfstats(lifeform_t *lf, int showall) { } } } - - // other - f = lfhasflag(lf, F_SILENTMOVE); - if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s move%s silently.", you(lf), isplayer(lf) ? "" : "s"); - y++; - } - - f = lfhasflag(lf, F_STABILITY); - if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s will not fall on slippery ground.", you(lf)); - y++; - } } @@ -10682,7 +10844,8 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s identity is obscured.", your(lf)); y++; } - if (lfhasknownflag(lf, F_AWARENESS)) { + f = lfhasknownflag(lf, F_AWARENESS); + if (f && (f->lifetime != FROMRACE)) { mvwprintw(mainwin, y, 0, "%s can see things which are behind %s.", you(lf), you(lf)); y++; } @@ -10908,11 +11071,6 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "Gravity is lessened around %s, preventing fall damage and increasing flight speed.", you_l(lf)); y++; } - f = lfhasknownflag(lf, F_DODGES); - if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s can dodge attacks.", you(lf)); - y++; - } f = lfhasknownflag(lf, F_INVULNERABLE); if (f && (f->known)) { mvwprintw(mainwin, y, 0, "%s %s protected from all physical harm.", you(lf), is(lf)); @@ -10939,7 +11097,7 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } f = lfhasflag(lf, F_PHOTOMEM); - if (f && (f->known)) { + if (f && (f->known) && (f->lifetime != FROMRACE)) { mvwprintw(mainwin, y, 0, "%s do not forget your surroundings.", you(lf)); y++; } @@ -10971,7 +11129,7 @@ void showlfstats(lifeform_t *lf, int showall) { } f = lfhasflag(lf, F_STENCH); - if (f && (f->known)) { + if (f && (f->known) && (f->lifetime != FROMRACE)) { mvwprintw(mainwin, y, 0, "%s %s emitting a foul stench, nauseating those nearby.", you(lf), is(lf)); y++; } diff --git a/io.h b/io.h index a9e8cb1..8d4bac9 100644 --- a/io.h +++ b/io.h @@ -82,6 +82,7 @@ void drawmsg(void); void drawscreen(void); void drawstatus(void); int drop(object_t *o, int count); +void dumpoc(void); void dumpspells(void); void dumpweps(void); void forceredraw(void); @@ -100,7 +101,7 @@ int keycodetokey(int keycode, int escseqok); void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int firstob, int *counter, int lastline, int *y, char *myletters, int forpickup, int showpoints); char *makedesc_god(lifeform_t *god, char *retbuf); char *makedesc_ob(object_t *o, char *retbuf); -char *makedesc_race(enum RACE rid, char *retbuf, int showbonpen); +char *makedesc_race(enum RACE rid, char *retbuf, int showextra); char *makedesc_skill(enum SKILL skid, char *retbuf, enum SKILLLEVEL levhilite); char *makedesc_spell(objecttype_t *ot, char *retbuf); void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, enum SPELLSCHOOL wantschool, int wantunknown, int wantlowmp, int wanttoohard,int mpcutoff); diff --git a/lf.c b/lf.c index 546ad7a..6912315 100644 --- a/lf.c +++ b/lf.c @@ -1130,11 +1130,7 @@ int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos) { } int cansleep(lifeform_t *lf) { - enum RACECLASS rc; - rc = getraceclass(lf); - if (rc == RC_PLANT) { - return B_FALSE; - } else if (rc == RC_UNDEAD) { + if (lfhasflag(lf, F_NOSLEEP)) { return B_FALSE; } return B_TRUE; @@ -1406,11 +1402,18 @@ int cantalk(lifeform_t *lf) { case RC_DRAGON: case RC_GOD: case RC_HUMANOID: - return B_TRUE; + // these ones can talk + break; default: + return B_FALSE; break; } - return B_FALSE; + + // too dumb? + if (getattr(lf, A_IQ) <= AT_VLOW) { + return B_FALSE; + } + return B_TRUE; } int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell, object_t *fromob, int *seen) { @@ -1909,7 +1912,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) { } if (!isdead(lf)) { - f = isvulnto(lf->flags, DT_WATER); + f = isvulnto(lf->flags, DT_WATER, B_FALSE); if (f) { int dam; if (strlen(f->text)) { @@ -1979,6 +1982,61 @@ int confuse(lifeform_t *lf, int howlong) { return B_FALSE; } +int continuedigging(lifeform_t *lf) { + cell_t *c; + flag_t *f = NULL; + int digpower; + int stopnow = B_FALSE; + + if (!hasfreeaction(lf)) { + stopnow = B_TRUE; + } + + f = hasflag(lf->flags, F_DIGGING); + if (!f) { + stopnow = B_TRUE; + } + if (!stopnow) { + c = getcellat(lf->cell->map, f->val[0], f->val[1]); + if (!c) { + stopnow = B_TRUE; + } + } + + if (stopnow) { + if (f) killflag(f); + return B_TRUE; + } + + digpower = f->val[2]; + c->hp -= digpower; + if (c->hp <= 0) { + if (isplayer(lf)) { + msg("You finish digging through %s %s.",needan(c->type->name) ? "an" : "a", c->type->name); + needredraw = B_TRUE; + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s finishes digging through %s %s.",lfname,needan(c->type->name) ? "an" : "a", c->type->name); + needredraw = B_TRUE; + } + // replace wall + setcelltype(c, c->map->habitat->emptycelltype); + // stop digging + killflag(f); + } else { + if (isplayer(lf)) { + msg("You dig into %s %s.",needan(c->type->name) ? "an" : "a", c->type->name); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s digs into %s %s.",lfname,needan(c->type->name) ? "an" : "a", c->type->name); + } + } + return B_FALSE; +} + + int countinnateattacks(lifeform_t *lf) { int count = 0,i; flag_t *f; @@ -2277,20 +2335,21 @@ void die(lifeform_t *lf) { } } } else { - // intelligent monsters will say something - if (ispetof(lf, player)) { - if (cantalk(lf) && canhear(player, lf->cell, 4)) { - sayphrase(lf, SP_DIE, SV_SHOUT, NA, NULL); + if (!hasflag(lf->flags, F_NODEATHSPEECH)) { + if (ispetof(lf, player)) { + if (cantalk(lf) && canhear(player, lf->cell, 4)) { + sayphrase(lf, SP_DIE, SV_SHOUT, NA, NULL); + } else if (cantalk(lf)) { + warn("You feel a profound sense of loss."); + more(); + //} else { + // makenoise(lf, N_DIE); + } } else if (cantalk(lf)) { - warn("You feel a profound sense of loss."); - more(); - //} else { - // makenoise(lf, N_DIE); - } - } else if (cantalk(lf)) { - if (pctchance(33)) { - sayphrase(lf, SP_DIE, SV_SHOUT, NA, NULL); + if (pctchance(33)) { + sayphrase(lf, SP_DIE, SV_SHOUT, NA, NULL); + } } } @@ -2612,27 +2671,31 @@ void dumpxp(void) { int digcell(lifeform_t *lf, cell_t *c, object_t *o) { char obname[BUFLEN]; + flag_t *f; + int digpower = 1; getobname(o, obname, 1); + f = hasflag(o->flags, F_HELPSDIG); + if (f) { + digpower = f->val[0]; + } if (!c) { return B_TRUE; } if (c->type->solid) { if (isdiggable(c)) { - // replace wall - setcelltype(c, c->map->habitat->emptycelltype); + // start digging! + addflag(lf->flags, F_DIGGING, c->x, c->y, digpower, NULL); if (isplayer(lf)) { - msg("You dig through the wall."); + msg("You start digging into %s %s.", needan(c->type->name) ? "an" : "a", c->type->name); needredraw = B_TRUE; } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("%s digs through a wall.",lfname); + msg("%s starts digging into %s %s.", lfname, needan(c->type->name) ? "an" : "a", c->type->name); needredraw = B_TRUE; } - //drawscreen(); - // takes extra time - taketime(lf, getactspeed(lf)*9); + taketime(lf, getactspeed(lf)); } else { // fail if (isplayer(lf)) { @@ -2655,7 +2718,7 @@ int digcell(lifeform_t *lf, cell_t *c, object_t *o) { if (door) { // TODO: metal doors are immune to CHOP damage - if (!isimmuneto(door->flags, DT_CHOP)) { + if (!isimmuneto(door->flags, DT_CHOP, B_FALSE)) { taketime(lf, getactspeed(lf)); removeob(door, door->amt); if (isplayer(lf)) { @@ -3111,7 +3174,7 @@ int eat(lifeform_t *lf, object_t *o) { } if (isrotting(o)) { - if (!isimmuneto(lf->flags, DT_POISON)) { + if (!isimmuneto(lf->flags, DT_POISON, B_FALSE)) { char dambuf[BUFLEN]; // lose hp if (isplayer(lf)) { @@ -3140,6 +3203,14 @@ int eat(lifeform_t *lf, object_t *o) { // think "eye of newt" gainmp(lf, 2); } + if (hasflagval(o->flags, F_CORPSEOF, R_EYEBAT, NA, NA, NULL)) { + lf->maxmp++; + if (isplayer(lf)) { + statdirty = B_TRUE; + drawstatus(); + msg("You feel slightly more magically attuned."); + } + } // special case for bananas if (o->type->id == OT_BANANA) { @@ -4200,12 +4271,12 @@ void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong, int onpurpose) { } int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong) { - if (isimmuneto(freezee->flags, DT_COLD)) { + if (isimmuneto(freezee->flags, DT_COLD, B_FALSE)) { if (isplayer(freezee)) { msg("You feel a slight chill."); } return B_TRUE; - } else if (isresistantto(freezee->flags, DT_COLD)) { + } else if (isresistantto(freezee->flags, DT_COLD, B_FALSE)) { char buf[BUFLEN]; if (isplayer(freezee)) { msg("^bYou feel freezing cold!"); @@ -6258,6 +6329,20 @@ char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer) { return getlfconditionname(cond); } +int getsmellrange(lifeform_t *lf) { + flag_t *f; + int range = 0; + f = lfhasflag(lf, F_ENHANCESMELL); + if (f) { + range = f->val[0]; + // adjust for injuries + if (lfhasflagval(lf, F_INJURY, IJ_NOSEBROKEN, NA, NA, NULL)) { + range /= 2; + } + } + return range; +} + glyph_t *getlfglyph(lifeform_t *lf) { flag_t *f; @@ -7302,28 +7387,32 @@ object_t *getrestob(lifeform_t *lf) { } for (o = lf->cell->obpile->first ; o ; o = o->next) { - f = hasflag(o->flags, F_HELPSREST); - if (f && !isarmour(o)) { - if (!bestob || (f->val[0] > bestval)) { - bestval = f->val[0]; - bestob = o; + if (isknown(o)) { + f = hasflag(o->flags, F_HELPSREST); + if (f && !isarmour(o)) { + if (!bestob || (f->val[0] > bestval)) { + bestval = f->val[0]; + bestob = o; + } } } } for (o = lf->pack->first; o ; o = o->next) { - f = hasflag(o->flags, F_HELPSREST); - if (f) { - int valid = B_TRUE; - // can't rest in armour which doesn't fit - if (isarmour(o) && !armourfits(lf, o, NULL)) { - valid = B_FALSE; - } - if (valid) { - if (!bestob || (f->val[0] > bestval)) { - bestval = f->val[0]; - bestob = o; + if (isknown(o)) { + f = hasflag(o->flags, F_HELPSREST); + if (f) { + int valid = B_TRUE; + // can't rest in armour which doesn't fit + if (isarmour(o) && !armourfits(lf, o, NULL)) { + valid = B_FALSE; + } + if (valid) { + if (!bestob || (f->val[0] > bestval)) { + bestval = f->val[0]; + bestob = o; + } } } } @@ -8244,6 +8333,15 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { // special effects based on skill level + if (isplayer(lf) && isloreskill(id) && (f->val[1] == PR_ADEPT)) { + race_t *r; + // at adept lore skill, you can look up this kind of race in '?r' + for (r = firstrace ; r ; r = r->next) { + if (r->raceclass->skill == id) r->known = B_TRUE; + } + } + + if (id == SK_ATHLETICS) { if (f->val[1] == PR_ADEPT) { newf = addflag(lf->flags, F_CANWILL, OT_A_TUMBLE, NA, NA, NULL); @@ -8720,6 +8818,7 @@ flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp) { int hasfreeaction(lifeform_t *lf) { if (isimmobile(lf)) return B_FALSE; if (lfhasflag(lf, F_CASTINGSPELL)) return B_FALSE; + if (lfhasflag(lf, F_DIGGING)) return B_FALSE; if (lfhasflag(lf, F_EATING)) return B_FALSE; if (lfhasflag(lf, F_ASLEEP)) return B_FALSE; return B_TRUE; @@ -8844,7 +8943,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { break; case 4: inj = IJ_NOSEBROKEN; - desc = strdup("nose is broken^charisma penalty"); + desc = strdup("nose is broken^charisma penalty,reduced smell sense"); break; } break; @@ -9113,7 +9212,7 @@ int lfcanbestoned(lifeform_t *lf) { if (lfhasflag(lf, F_NONCORPOREAL)) { return B_FALSE; } - if (isimmuneto(lf->flags, DT_PETRIFY)) { + if (isimmuneto(lf->flags, DT_PETRIFY, B_FALSE)) { return B_FALSE; } if (isdead(lf)) { @@ -9973,13 +10072,21 @@ int isgenius(lifeform_t *lf) { return B_FALSE; } -flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt) { +flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt, int onlytemp) { flag_t *f; dt = basedamagetype(dt); f = hasflagval(fp, F_DTIMMUNE, dt, NA, NA, NULL); - if (f) return f; + if (f) { + if (!onlytemp || (f->lifetime != FROMRACE)) { + return f; + } + } f = hasflagval(fp, F_DTIMMUNE, DT_ALL, NA, NA, NULL); - if (f) return f; + if (f) { + if (!onlytemp || (f->lifetime != FROMRACE)) { + return f; + } + } return NULL; } @@ -10178,13 +10285,21 @@ int isprone(lifeform_t *lf) { return B_FALSE; } -flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt) { +flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt, int onlytemp) { flag_t *f; dt = basedamagetype(dt); f = hasflagval(fp, F_DTRESIST, dt, NA, NA, NULL); - if (f) return f; + if (f) { + if (!onlytemp || (f->lifetime != FROMRACE)) { + return f; + } + } f = hasflagval(fp, F_DTRESIST, DT_ALL, NA, NA, NULL); - if (f) return f; + if (f) { + if (!onlytemp || (f->lifetime != FROMRACE)) { + return f; + } + } if (dt == DT_FIRE) { f = hasflag(fp, F_WET); if (f) return f; @@ -10431,6 +10546,7 @@ race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcol a->weight = weight; a->glyph.ch = glyph; a->glyph.colour = glyphcolour; + a->known = B_FALSE; a->nbodyparts = 0; @@ -10597,7 +10713,7 @@ void adjustspeedforwater(lifeform_t *lf, int *speed) { void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { flag_t *f; - if (isimmuneto(lf->flags, damtype)) { + if (isimmuneto(lf->flags, damtype, B_FALSE)) { *amt = 0; return; } @@ -10608,7 +10724,7 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { } // water normally doesn't hurt. - if ((damtype == DT_WATER) && !isvulnto(lf->flags, damtype)) { + if ((damtype == DT_WATER) && !isvulnto(lf->flags, damtype, B_FALSE)) { *amt = 0; return; } @@ -10645,10 +10761,10 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { *amt = 0; } - if (isresistantto(lf->flags, damtype)) { + if (isresistantto(lf->flags, damtype, B_FALSE)) { (*amt) /= 2; } - f = isvulnto(lf->flags, damtype); + f = isvulnto(lf->flags, damtype, B_FALSE); if (f) { if ((*amt == 0) && strlen(f->text)) { int ndice,nsides,bonus; @@ -11166,14 +11282,22 @@ int isundead(lifeform_t *lf) { return B_FALSE; } -flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt) { +flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt, int onlytemp) { flag_t *f; dt = basedamagetype(dt); f = hasflagval(fp, F_DTVULN, dt, NA, NA, NULL); - if (f) return f; + if (f) { + if (!onlytemp || (f->lifetime != FROMRACE)) { + return f; + } + } f = hasflagval(fp, F_DTVULN, DT_ALL, NA, NA, NULL); - if (f) return f; + if (f) { + if (!onlytemp || (f->lifetime != FROMRACE)) { + return f; + } + } return NULL; } @@ -11629,6 +11753,13 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml postbleed = B_TRUE; } + ////////////////////////////////////////// + // Figure out death text for tombstone. + // eg. Killed by something + // Impaled by something. + // etc + ////////////////////////////////////////// + // replace 'the' at start of damsrc with 'a' if (strstr(damsrc, "the ") == damsrc) { snprintf(buf, BUFLEN, "a %s", (damsrc+4)); @@ -11659,18 +11790,22 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml setlastdam(lf, buf); - switch (damtype) { - case DT_ACID: setkillverb(lf, "Dissolved"); break; - case DT_COLD: setkillverb(lf, "Frozen"); break; - case DT_CRUSH: setkillverb(lf, "Crushed"); break; - case DT_ELECTRIC: setkillverb(lf, "Electrocuted"); break; - case DT_FIRE: - case DT_HEAT: - setkillverb(lf, "Incinerated"); break; - case DT_MELT: setkillverb(lf, "Melted"); break; - case DT_PIERCE: setkillverb(lf, "Impaled"); break; - case DT_EXPLOSIVE: setkillverb(lf, "Vaporised"); break; - default: break; + if (fromlf && lfhasflag(fromlf, F_CARNIVORE)) { + setkillverb(lf, "Eaten"); + } else { + switch (damtype) { + case DT_ACID: setkillverb(lf, "Dissolved"); break; + case DT_COLD: setkillverb(lf, "Frozen"); break; + case DT_CRUSH: setkillverb(lf, "Crushed"); break; + case DT_ELECTRIC: setkillverb(lf, "Electrocuted"); break; + case DT_FIRE: + case DT_HEAT: + setkillverb(lf, "Incinerated"); break; + case DT_MELT: setkillverb(lf, "Melted"); break; + case DT_PIERCE: setkillverb(lf, "Impaled"); break; + case DT_EXPLOSIVE: setkillverb(lf, "Vaporised"); break; + default: break; + } } // special case @@ -11735,7 +11870,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // fire: dam*10 chance of burning each object which is vulnerable to fire for (o = lf->pack->first ; o ; o = nexto) { nexto = o->next; - if (isvulnto(o->flags, DT_FIRE) && pctchance(amt*10)) { + if (isvulnto(o->flags, DT_FIRE, B_FALSE) && pctchance(amt*10)) { int newdam; nburnt++; if (nburnt >= (amt/5)) break; @@ -11751,7 +11886,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml for (o = lf->pack->first ; o ; o = nexto) { nexto = o->next; //if (isvulnto(o->flags, DT_COLD) && pctchance(amt*10)) { - if (isvulnto(o->flags, DT_COLD)) { + if (isvulnto(o->flags, DT_COLD, B_FALSE)) { int newdam; // object takes 1/4 of damage newdam = pctof(25, amt); @@ -13399,7 +13534,7 @@ int safetorest(lifeform_t *lf) { reason = E_OK; for (l = lf->cell->map->lf ; l ; l = l->next) { - if ((l != lf) && areenemies(lf, l) && !lfhasflag(l, F_HARMLESS)) { + if ((l != lf) && areenemies(lf, l) && !lfhasflag(l, F_HARMLESS) && !lfhasflag(l, F_FEIGNINGDEATH)) { int monsternearby = B_FALSE; if (isplayer(lf)) { @@ -14105,6 +14240,7 @@ void interrupt(lifeform_t *lf) { stopresting(lf); stoprunning(lf); killflagsofid(lf->flags, F_AUTOCMD); + killflagsofid(lf->flags, F_DIGGING); } int setlfmaterial(lifeform_t *lf, enum MATERIAL id, int wantannounce) { @@ -14348,8 +14484,8 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r } } else if (ct == SC_DODGE) { if (attrib) { - // ie. -5 to 5 - othermod += (getstatmod(lf, A_AGI) / 10); + // ie. -2 to 2 + othermod += (getstatmod(lf, A_AGI) / 20); } } else if (ct == SC_SLIP) { if (lfhasflagval(lf, F_INJURY, IJ_LEGBROKEN, NA, NA, NULL)) { @@ -14404,11 +14540,11 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r } } else if (ct == SC_POISON) { // auto pass if we are immune - if (isimmuneto(lf->flags, DT_POISON)) { + if (isimmuneto(lf->flags, DT_POISON, B_FALSE)) { othermod += (diff*2); - } else if (isresistantto(lf->flags, DT_POISON)) { + } else if (isresistantto(lf->flags, DT_POISON, B_FALSE)) { othermod += 5; - } else if (isvulnto(lf->flags, DT_POISON)) { + } else if (isvulnto(lf->flags, DT_POISON, B_FALSE)) { othermod -= 10; } } else if (ct == SC_SEARCH) { @@ -15335,7 +15471,7 @@ void startlfturn(lifeform_t *lf) { } f = hasflag(o->flags, F_CAUSESCOUGH); - if (f && !isimmuneto(lf->flags, DT_POISONGAS)) { + if (f && !isimmuneto(lf->flags, DT_POISONGAS, B_FALSE)) { char obname[BUFLEN]; getobname(o, obname, o->amt); if (!skillcheck(lf, SC_CON, f->val[0] * o->amt, 0)) { @@ -16256,6 +16392,7 @@ void turntoface(lifeform_t *lf, cell_t *dstcell) { void unsummon(lifeform_t *lf, int vanishobs) { lifeform_t *creator = NULL; flag_t *f; + char unsummonob[BUFLEN]; f = hasflag(lf->flags, F_SUMMONEDBY); if (f) { creator = findlf(NULL, f->val[0]); @@ -16286,8 +16423,16 @@ void unsummon(lifeform_t *lf, int vanishobs) { lf->hp = 0; addflag(lf->flags, F_DEAD, B_TRUE, NA, NA, NULL); addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_NODEATHSPEECH, B_TRUE, NA, NA, NULL); addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); - addob(lf->cell->obpile, "puff of smoke"); + + f = lfhasflag(lf, F_UNSUMMONOB); + if (f) { + strcpy(unsummonob, f->text); + } else { + strcpy(unsummonob, "puff of smoke"); + } + addob(lf->cell->obpile, unsummonob); } int unweild(lifeform_t *lf, object_t *o) { @@ -16835,6 +16980,11 @@ int validateraces(void) { printf("ERROR in race '%s' - has NOISETEXT but no volume.\n", r->name); goterror = B_TRUE; } + } else if (f->id == F_NOSLEEP) { + if (hasflag(r->flags, F_NOCTURNAL) || hasflag(r->flags, F_DIURNAL) || hasflag(r->flags, F_STARTASLEEPPCT)) { + printf("ERROR in race '%s' - has both NOSSLEEP and nocturnal/diurnal/startasleeppct.\n", r->name); + goterror = B_TRUE; + } } else if (f->id == F_NOSMELL) { if (hasflag(r->flags, F_ENHANCESMELL)) { printf("ERROR in race '%s' - has both NOSMELL and ENHANCESMELL.\n", r->name); diff --git a/lf.h b/lf.h index 39bfcad..b48d5a8 100644 --- a/lf.h +++ b/lf.h @@ -65,6 +65,7 @@ int check_rest_ok(lifeform_t *lf); //void checkxp(enum RACE rid); float comparelfs(lifeform_t *lf1, lifeform_t *lf2); int confuse(lifeform_t *lf, int howlong); +int continuedigging(lifeform_t *lf); int countinnateattacks(lifeform_t *lf); int countnearbyallies(lifeform_t *lf); int countnearbyhurtallies(lifeform_t *lf); @@ -171,6 +172,7 @@ object_t *getouterequippedob(lifeform_t *lf, enum BODYPART bp); int getowing(lifeform_t *buyer, int shopid, int *retnitems); enum LFCONDITION getseenlfconditioncutoff(lifeform_t *lf); char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer); +int getsmellrange(lifeform_t *lf); glyph_t *getlfglyph(lifeform_t *lf); enum MATERIAL getlfmaterial(lifeform_t *lf); enum SKILLLEVEL getlorelevel(lifeform_t *lf, enum RACECLASS rcid); @@ -286,7 +288,7 @@ int isgenius(lifeform_t *lf); int isgod(lifeform_t *lf); int ishirable(lifeform_t *lf); int isimmobile(lifeform_t *lf); -flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt); +flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt, int onlytemp); int isinbattle(lifeform_t *lf); int isingunrange(lifeform_t *lf, cell_t *where); int isloreskill(enum SKILL skid); @@ -301,7 +303,7 @@ flag_t *ispoisoned(lifeform_t *lf); flag_t *ispoisonedwith(lifeform_t *lf, enum POISONTYPE pt); int ispolymorphed(lifeform_t *lf); int isprone(lifeform_t *lf); -flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt); +flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt, int onlytemp); flag_t *isresting(lifeform_t *lf); int issleepingtimefor(lifeform_t *lf); object_t *isstuck(lifeform_t *lf); @@ -309,7 +311,7 @@ int issmellablelf(lifeform_t *lf); int isswimming(lifeform_t *lf); int isunconscious(lifeform_t *lf); int isundead(lifeform_t *lf); -flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt); +flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt, int onlytemp); int isweaponskill(enum SKILL skid); enum FLAG iswoozy(lifeform_t *lf); void killjob(job_t *job); diff --git a/map.c b/map.c index fc07634..76442dc 100644 --- a/map.c +++ b/map.c @@ -177,7 +177,7 @@ map_t *addmap(void) { // when monsters are made during level generation, autogen will be true. otherwise false; -// if "rid" RR_NONE, paste racename to get the race. +// if "rid" RR_NONE, parse racename to get the race. // otherwise just use the given race. lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int amt, int autogen, int *nadded) { lifeform_t *lf = NULL; @@ -3173,7 +3173,7 @@ void createsewer(map_t *map, int depth, map_t *parentmap, int exitdir, object_t // have to force these stairs to go back to a different region. f = hasflag(o->flags, F_CLIMBABLE); f->val[1] = map->region->parentregion->id; - linkstairs(o, NULL); + linkstairs(o, entryob); } @@ -5069,22 +5069,22 @@ void initmap(void) { addhabitat(H_SWAMP, "swamp", CT_CORRIDOR, CT_WALL, 3, 50, 0, MAXVISRANGE); // cell types - solid - addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0); - addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, B_SOLID, B_OPAQUE, MT_WOOD, 0); - addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, B_SOLID, B_TRANS, MT_GLASS, 0); - addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, B_SOLID, B_OPAQUE, MT_METAL, 0); - addcelltype(CT_ROOMWALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0); + addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0, 100); + addcelltype(CT_ROOMWALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0, 100); + addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, B_SOLID, B_OPAQUE, MT_WOOD, 0, 50); + addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, B_SOLID, B_TRANS, MT_GLASS, 0, 150); + addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, B_SOLID, B_OPAQUE, MT_METAL, 0, 200); // cell types - non-solid - addcelltype(CT_FAKE, "fake cell", '.', C_GREEN, B_EMPTY, B_TRANS, MT_STONE, 0); - addcelltype(CT_CORRIDOR, "rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0); - addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0); - addcelltype(CT_FLOORWOOD, "wood floor", '.', C_BROWN, B_EMPTY, B_TRANS, MT_WOOD, 0); - addcelltype(CT_FLOORSHOP, "shop floor", '.', C_BROWN, B_EMPTY, B_TRANS, MT_WOOD, 0); - addcelltype(CT_ROOM, "rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0); - addcelltype(CT_GRASS, "grass", '.', C_GREEN, B_EMPTY, B_TRANS, MT_PLANT, 0); - addcelltype(CT_DIRT, "dirt", '.', C_BROWN, B_EMPTY, B_TRANS, MT_STONE, 0); - addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -1); - addcelltype(CT_VLOWFLOOR, "very low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -2); + addcelltype(CT_FAKE, "fake cell", '.', C_GREEN, B_EMPTY, B_TRANS, MT_STONE, 0, -1); + addcelltype(CT_CORRIDOR, "rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0, -1); + addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0, -1); + addcelltype(CT_FLOORWOOD, "wood floor", '.', C_BROWN, B_EMPTY, B_TRANS, MT_WOOD, 0, -1); + addcelltype(CT_FLOORSHOP, "shop floor", '.', C_BROWN, B_EMPTY, B_TRANS, MT_WOOD, 0, -1); + addcelltype(CT_ROOM, "rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0, -1); + addcelltype(CT_GRASS, "grass", '.', C_GREEN, B_EMPTY, B_TRANS, MT_PLANT, 0, -1); + addcelltype(CT_DIRT, "dirt", '.', C_BROWN, B_EMPTY, B_TRANS, MT_STONE, 0, -1); + addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -1, -1); + addcelltype(CT_VLOWFLOOR, "very low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -2, -1); // region types addregiontype(RG_WORLDMAP, "World map", H_FOREST, 10, 0, D_NONE, B_TRUE); @@ -5523,7 +5523,7 @@ object_t *linkportal(object_t *srcportal, int wantdepth) { } // link the staircase 'o' to a free one in adjacent maps. -// o2 is options. if not probided, we will try to find +// o2 is optional. if not probided, we will try to find // something to link to ourself. // returns TRUE if it failed because othermap doesn't exist. int linkstairs(object_t *o, object_t *o2) { @@ -5922,6 +5922,7 @@ void setcelltype(cell_t *cell, enum CELLTYPE id) { assert(cell); cell->type = findcelltype(id); assert(cell->type); + cell->hp = cell->type->hp; if (cell->type->solid) { assert(!cell->obpile->first); } diff --git a/move.c b/move.c index a56e09d..9b2f14c 100644 --- a/move.c +++ b/move.c @@ -242,7 +242,7 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err } f = hasflag(o->flags, F_WALKDAM); if (f) { - if ((f->val[0] != DT_WATER) || isvulnto(lf->flags, DT_WATER)) { + if ((f->val[0] != DT_WATER) || isvulnto(lf->flags, DT_WATER, B_FALSE)) { // are we immune to this? if (!lfhasflagval(lf, F_DTIMMUNE, f->val[0], NA, NA, NULL)) { if (error) { @@ -1386,6 +1386,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) { //} } dointerrupt = B_TRUE; + // mark the observed race as known. + lf->race->known = B_TRUE; } } else if (isplayer(lf)) { if (areallies(lf, l)) { @@ -2627,8 +2629,17 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { // strafing sideways/backwards takes longer if (strafe && !lfhasflag(lf, F_AWARENESS)) { switch (reldir) { - case RD_SIDEWAYS: howlong = pctof(125, howlong); break; - case RD_BACKWARDS: howlong = pctof(150, howlong); break; + //case RD_SIDEWAYS: howlong = pctof(125, howlong); break; + case RD_SIDEWAYS: break; + case RD_BACKWARDS: + switch (getskill(lf, SK_ATHLETICS)) { + case PR_INEPT: howlong = pctof(150, howlong); break; + case PR_NOVICE: + case PR_BEGINNER: + howlong = pctof(125, howlong); break; + default: break; + } + break; case RD_FORWARDS: if (hasactivespell(lf, OT_S_TAILWIND)) { // faster diff --git a/nexus.c b/nexus.c index 4d58553..0af521e 100644 --- a/nexus.c +++ b/nexus.c @@ -209,7 +209,7 @@ int main(int argc, char **argv) { if (hasflag(r->flags, F_PLAYABLE)) { char *longdesc; longdesc = malloc(HUGEBUFLEN * sizeof(char)); - makedesc_race(r->id, longdesc, B_TRUE); + makedesc_race(r->id, longdesc, B_TRUE ); addchoice(&prompt, ch++, r->name, NULL, r, longdesc); free(longdesc); } @@ -276,7 +276,7 @@ int main(int argc, char **argv) { // this is the hole which you fell down to get here. addobfast(where->obpile, OT_HOLEINROOF); // kill any objects which were already there, or which fell down the hole - killallobs(where->obpile); + killallobsexcept(where->obpile, OT_HOLEINROOF, OT_NONE); // now add the player real_addlf(where, startrace->id, 1, C_PLAYER); // this will assign 'player' @@ -540,7 +540,7 @@ int main(int argc, char **argv) { return B_FALSE; } -celltype_t *addcelltype(int id, char *name, int glyph, int colour, int solid, int transparent, enum MATERIAL mat, int floorheight) { +celltype_t *addcelltype(int id, char *name, int glyph, int colour, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp) { celltype_t *a; // add to the end of the list @@ -567,6 +567,7 @@ celltype_t *addcelltype(int id, char *name, int glyph, int colour, int solid, in a->transparent = transparent; a->material = findmaterial(mat); a->floorheight = floorheight; + a->hp = hp; a->flags = addflagpile(NULL, NULL); @@ -798,6 +799,19 @@ void donextturn(map_t *map) { } } + // digging? + if (donormalmove) { + f = lfhasflag(who, F_DIGGING); + if (f) { + if (isplayer(who) && checkforkey()) { + msg("Stopped digging."); + killflag(f); + } else { + if (!continuedigging(who)) donormalmove = B_FALSE; + } + } + } + // eating? if (donormalmove) { f = lfhasflag(who, F_EATING); @@ -841,7 +855,6 @@ void donextturn(map_t *map) { } } - if (donormalmove) { // paralyzed etc? if (isimmobile(who)) { diff --git a/nexus.h b/nexus.h index e39a556..d1fe328 100644 --- a/nexus.h +++ b/nexus.h @@ -1,6 +1,6 @@ #include "defs.h" -celltype_t *addcelltype(int id, char *name, int glyph, int colour, int solid, int transparent, enum MATERIAL mat, int floorheight); +celltype_t *addcelltype(int id, char *name, int glyph, int colour, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp); warning_t *addwarning(char *text); void checkdeath(void); void checkendgame(void); diff --git a/objects.c b/objects.c index 4e0bb98..3ab51ee 100644 --- a/objects.c +++ b/objects.c @@ -1487,7 +1487,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes switch (wantom[n]->id) { case OM_FLAMING: // flaming weapons are immune to fire if (o->type->obclass->id == OC_WEAPON) { - if (!isimmuneto(o->flags, DT_FIRE)) { + if (!isimmuneto(o->flags, DT_FIRE, B_FALSE)) { addflag(o->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); } } @@ -2034,17 +2034,17 @@ void adjustdamob(object_t *o, int *dam, enum DAMTYPE damtype) { } // immune? - if (isimmuneto(o->flags, damtype)) { + if (isimmuneto(o->flags, damtype, B_FALSE)) { *dam = 0; return; } - if (isresistantto(o->flags, damtype)) { + if (isresistantto(o->flags, damtype, B_FALSE)) { // no resistances etc if rusty... if (!hasflag(o->flags, F_RUSTED)) { *dam /= 2; } } - if (isvulnto(o->flags, damtype)) { + if (isvulnto(o->flags, damtype, B_FALSE)) { *dam *= 2; } @@ -2055,7 +2055,7 @@ void adjustdamob(object_t *o, int *dam, enum DAMTYPE damtype) { } if (damtype == DT_WATER) { - if (!isvulnto(o->flags, damtype)) { + if (!isvulnto(o->flags, damtype, B_FALSE)) { *dam = 0; return; } @@ -2326,10 +2326,13 @@ int canbepoisoned(enum OBTYPE oid) { int canseeob(lifeform_t *lf, object_t *o) { flag_t *f; + cell_t *obloc; if (gamemode != GM_GAMESTARTED) { return B_TRUE; } + obloc = getoblocation(o); + if (hasflag(o->flags, F_SECRET) && isplayer(lf)) { // can't see return B_FALSE; @@ -2369,6 +2372,7 @@ int canseeob(lifeform_t *lf, object_t *o) { return B_FALSE; } } else { + int smellrange; // ie. SCENT // special case: if lf is the player's pet, they can always "smell" the player @@ -2378,9 +2382,11 @@ int canseeob(lifeform_t *lf, object_t *o) { return B_TRUE; } } + + smellrange = getsmellrange(lf); // can't smell your own race... - if ((f->val[0] != lf->race->id) && lfhasflag(lf, F_ENHANCESMELL)) { + if ((f->val[0] != lf->race->id) && smellrange && (getcelldist(lf->cell, obloc) <= smellrange)) { return B_TRUE; } else { return B_FALSE; @@ -6197,7 +6203,7 @@ int isdangerousob(object_t *o, lifeform_t *lf, int onlyifknown) { if (!onlyifknown || (iqb >= AT_AVERAGE)) { if (hasflag(o->flags, F_SHARP)) { - if (!getequippedob(lf->pack, BP_HANDS) && !isimmuneto(lf->flags, DT_SLASH)) { + if (!getequippedob(lf->pack, BP_HANDS) && !isimmuneto(lf->flags, DT_SLASH, B_FALSE)) { return B_TRUE; } } @@ -6205,7 +6211,7 @@ int isdangerousob(object_t *o, lifeform_t *lf, int onlyifknown) { if (!onlyifknown || (iqb >= IQ_ANIMAL)) { if (hasflag(o->flags, F_ONFIRE)) { - if (!isimmuneto(lf->flags, DT_FIRE)) { + if (!isimmuneto(lf->flags, DT_FIRE, B_FALSE)) { return B_TRUE; } } @@ -6611,6 +6617,38 @@ void killallobs(obpile_t *op) { } } +// returns number of obs killed. +// terminate args with OT_NONE +int killallobsexcept(obpile_t *op, ...) { + va_list args; + enum OBTYPE exception[MAXCANDIDATES],thisob; + int nexceptions = 0,i,nkilled = 0; + object_t *o,*nexto; + va_start(args, op); + + thisob = va_arg(args, enum OBTYPE); + while (thisob != OT_NONE) { + exception[nexceptions++] = thisob; + thisob = va_arg(args, enum OBTYPE); + } + va_end(args); + for (o = op->first ; o; o = nexto) { + int killthis = B_TRUE; + nexto = o->next; + for (i = 0;i < nexceptions; i++) { + if (o->type->id == exception[i]) { + killthis = B_FALSE; + break; + } + } + if (killthis) { + killob(o); + nkilled++; + } + } + return nkilled; +} + void killmaterial(material_t *m) { material_t *nextone, *lastone; @@ -9125,10 +9163,10 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE // how long for? i = geteffecttime(15,25,potblessed); - if (!isimmuneto(lf->flags, DT_FIRE)) { + if (!isimmuneto(lf->flags, DT_FIRE, B_FALSE)) { addtempflag(lf->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL, i); } - if (!isimmuneto(lf->flags, DT_COLD)) { + if (!isimmuneto(lf->flags, DT_COLD, B_FALSE)) { addtempflag(lf->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL, i); } break; @@ -9821,19 +9859,21 @@ int readsomething(lifeform_t *lf, object_t *o) { // removeob one of the object removeob(o, 1); } else if (o->type->id == OT_SCR_PERMENANCE) { - if (isplayer(lf)) { - targob = askobject(lf->pack, "Target which object", NULL, '\0', AO_NONE); + int ndone = 0; + flag_t *f; + // makes certain flags permenant + for (f = lf->flags->first ; f ; f = f->next) { + if ((f->lifetime > 0) && canbemadepermenant(f->id)) { + f->lifetime = PERMENANT; + ndone++; + } } - if (targob) { - flag_t *f; - for (f = targob->flags->first ; f ; f = f->next) { - f->lifetime = PERMENANT; - } - if (isplayer(lf)) { - char obname[BUFLEN]; - getobname(targob, obname, targob->amt); - msg("Your %s emit%s a blinding burst of power!",noprefix(obname), (targob->amt == 1) ? "s" : ""); + if (isplayer(lf)) { + if (ndone) { + msg("You are surrounded by a stabilising aura."); + } else { + nothinghappens(); } } @@ -11179,6 +11219,12 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, // roll for hit youhit = B_FALSE; myroll = rnd(1,100); + + // blessed projectile vs undead? 20% bonus. + if (isblessed(o) && isundead(target)) { + myroll -= 20; + } + // metal projectile versus magnetic shield? if (target && lfhasflag(target, F_MAGSHIELD) && ismetal(o->material->id)) { // announce @@ -11237,51 +11283,54 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } } - // saving throws if (youhit && !willcatch && !isprone(target)) { - // can the victim see where the object came from? - if (haslos(target, srcloc)) { - int catchmod,dodgemod; - enum LFSIZE sz; - sz = getobsize(o); - // smaller things are harder to catch, but easier to dodge - if (sz >= SZ_HUMAN) { - catchmod = 4; - dodgemod = -3; - } else if (sz == SZ_MEDIUM) { - catchmod = 4; - dodgemod = -1; - } else if (sz == SZ_SMALL) { - catchmod = 0; - dodgemod = 0; - } else if (sz == SZ_TINY) { - catchmod = -3; - dodgemod = 1; - } else if (sz <= SZ_MINI) { - catchmod = -6; - dodgemod = 2; - } - // first check to see if you can catch it. this is hard! - if (!lfhasflag(target, F_NOPACK) && hasbp(target, BP_HANDS) && - lfhasflag(target, F_HUMANOID) && - canpickup(target, o, o->amt) && - !willburden(target, o, o->amt) && - !isimmobile(target) && - skillcheck(target, SC_DEX, 30 + (speed*5), catchmod)) { - willcatch = B_TRUE; - } else if (!lfhasflag(target, F_CASTINGSPELL) && skillcheck(target, SC_DODGE, 14+(speed*2), dodgemod)) { - // then check if we dodge it... - if (db) dblog("target passed dodge check."); + // undead can't dodge blessed missiles + if (isblessed(o) && isundead(target)) { + } else { + // can the victim see where the object came from? + if (haslos(target, srcloc)) { + int catchmod,dodgemod; + enum LFSIZE sz; + sz = getobsize(o); + // smaller things are harder to catch, but easier to dodge + if (sz >= SZ_HUMAN) { + catchmod = 4; + dodgemod = -3; + } else if (sz == SZ_MEDIUM) { + catchmod = 4; + dodgemod = -1; + } else if (sz == SZ_SMALL) { + catchmod = 0; + dodgemod = 0; + } else if (sz == SZ_TINY) { + catchmod = -3; + dodgemod = 1; + } else if (sz <= SZ_MINI) { + catchmod = -6; + dodgemod = 2; + } + // first check to see if you can catch it. this should be very hard! + if (!lfhasflag(target, F_NOPACK) && hasbp(target, BP_HANDS) && + lfhasflag(target, F_HUMANOID) && + canpickup(target, o, o->amt) && + !willburden(target, o, o->amt) && + !isimmobile(target) && + skillcheck(target, SC_DEX, 27 + (speed*5), catchmod)) { + willcatch = B_TRUE; + } else if (hasfreeaction(target) && skillcheck(target, SC_DODGE, 27+(speed*2), dodgemod)) { + // then check if we dodge it... + if (db) dblog("target passed dodge check."); - youhit = B_FALSE; - if (seen) { - if (isplayer(target)) { - msg("You dodge %s.", obname); - } else if (cansee(player, target)) { - msg("%s dodges %s.", targetname, obname); + youhit = B_FALSE; + if (seen) { + if (isplayer(target)) { + msg("You dodge %s.", obname); + } else if (cansee(player, target)) { + msg("%s dodges %s.", targetname, obname); + } + announcedmiss = B_TRUE; } - announcedmiss = B_TRUE; } } } @@ -11299,7 +11348,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (youhit && lfhasflag(target, F_NONCORPOREAL)) { - if (isvulnto(target->flags, DT_HOLY) && isblessed(o)) { + if (isvulnto(target->flags, DT_HOLY, B_FALSE) && isblessed(o)) { } else { youhit = B_FALSE; willcatch = B_FALSE; @@ -12622,15 +12671,26 @@ int getingredients(obpile_t *op, recipe_t *rec, object_t **retob, int *retcount, object_t *poss[MAXPILEOBS]; int nposs = 0; for (o = op->first ; o ; o = o->next) { - if ((o->type->id == rec->ingredient[i]) && (o->amt >= rec->count[i])) { - int valid = B_TRUE; - // special case - chicken soup must use chicken meat + int obmatches = B_FALSE; + if (o->type->id == rec->ingredient[i]) { + obmatches = B_TRUE; + } else if ((rec->ingredient[i] == OT_BREADSTALE) && (o->type->id == OT_BREADFRESH)) { + obmatches = B_TRUE; + } else if ((rec->ingredient[i] == OT_BREADFRESH) && (o->type->id == OT_BREADSTALE)) { + obmatches = B_TRUE; + } + + if (obmatches) { + // chicken soup must have chicken if ((rec->result == OT_POT_SOUPCHICKEN) && (rec->ingredient[i] == OT_ROASTMEAT)) { if (!hasflagval(o->flags, F_CORPSEOF, R_CHICKEN, NA, NA, NULL)) { - valid = B_FALSE; + obmatches = B_FALSE; } } - if (valid) poss[nposs++] = o; + } + + if (obmatches && (o->amt >= rec->count[i])) { + poss[nposs++] = o; } } diff --git a/objects.h b/objects.h index 9cf09e5..c44cf8e 100644 --- a/objects.h +++ b/objects.h @@ -202,6 +202,7 @@ int istriedot(objecttype_t *ot); int isweapon(object_t *o); int iswearable(object_t *o); void killallobs(obpile_t *op); +int killallobsexcept(obpile_t *op, ...); void killmaterial(material_t *m); void killob(object_t *o); void killobpile(obpile_t *o); diff --git a/save.c b/save.c index 2547fa8..24e3100 100644 --- a/save.c +++ b/save.c @@ -21,6 +21,7 @@ extern long curtime; extern lifeform_t *player; extern map_t *firstmap; +extern race_t *firstrace; extern knowledge_t *knowledge; extern region_t *firstregion,*lastregion; extern regionoutline_t *firstregionoutline,*lastregionoutline; @@ -140,11 +141,21 @@ int loadknowledge(FILE *f) { } int loadvars(FILE *f) { + int id; int db = B_FALSE; + race_t *r; if (db) dblog("--> Loading knowledge...\n"); fscanf(f, "startvars\n"); fscanf(f, "curtime:%ld\n",&curtime); fscanf(f, "endvars\n"); + fscanf(f, "startknownraces\n"); + fscanf(f, "%d\n", &id); + while (id != -1) { + r = findrace(id); + r->known = B_TRUE; + fscanf(f, "%d\n", &id); + } + fscanf(f, "endknownraces\n"); return B_FALSE; } @@ -731,10 +742,19 @@ int loadsavegame(void) { int savevars(FILE *f) { int db = B_FALSE; + race_t *r; if (db) dblog("--> Saving knowledge...\n"); fprintf(f, "startvars\n"); fprintf(f, "curtime:%ld\n",curtime); fprintf(f, "endvars\n"); + fprintf(f, "startknownraces\n"); + for (r = firstrace ; r ; r = r->next) { + if (r->known) { + fprintf(f, "%d\n",r->id); + } + } + fprintf(f, "-1\n"); + fprintf(f, "endknownraces\n"); return B_FALSE; } diff --git a/spell.c b/spell.c index 72193bd..3aef41e 100644 --- a/spell.c +++ b/spell.c @@ -745,6 +745,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef object_t *o,*trapob = NULL; flag_t *trapflag = NULL; char buf[BUFLEN]; + int bonus = 0; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { if (isplayer(user)) msg("You can't disable traps while swimming!"); @@ -807,8 +808,17 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef movelf(user, targcell); } + // have any objects which will help? + bonus = 0; + for (o = user->pack->first ; o ; o = o->next) { + f = hasflag(o->flags, F_HELPSDISARM); + if (f && (f->val[0] > bonus)) { + bonus = f->val[0]; + } + } + // try to disarm it - if (skillcheck(user, SC_DISARM, trapflag->val[0], 0)) { + if (skillcheck(user, SC_DISARM, trapflag->val[0], bonus)) { if (trapflag->id == F_TRAP) { // ie. trapped cell getobname(trapob, buf, 1); @@ -3566,7 +3576,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ char damstring[BUFLEN]; char realcname[BUFLEN]; getlfname(c->lf,buf); - if (!isimmuneto(c->lf->flags, DT_FIRE)) { + if (!isimmuneto(c->lf->flags, DT_FIRE, B_FALSE)) { msg("%s burn%s!",buf,isplayer(c->lf) ? "" : "s"); } real_getlfname(caster, realcname, B_FALSE); @@ -4040,14 +4050,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ dam = rnd(1,exposedlimbs); if (isplayer(target)) { - if (isimmuneto(target->flags, DT_COLD)) { + if (isimmuneto(target->flags, DT_COLD, B_FALSE)) { msg("You feel mildly chilly."); } else { msg("You feel cold!"); } if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (cansee(player, target)) { - if (isimmuneto(target->flags, DT_COLD)) { + if (isimmuneto(target->flags, DT_COLD, B_FALSE)) { msg("%s doesn't seem to mind the cold.", lfname); } else { msg("%s looks cold!", lfname); @@ -4057,7 +4067,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // target takes magical damage // always hit - if (!isimmuneto(target->flags, DT_COLD)) { + if (!isimmuneto(target->flags, DT_COLD, B_FALSE)) { losehp(target, dam, DT_COLD, caster, "a chill spell"); } } else if (spellid == OT_S_COLDBURST) { @@ -4168,6 +4178,36 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ killflag(f); } + } else if (spellid == OT_S_CREATEFOOD) { + objecttype_t *ot; + object_t *o; + char obname[BUFLEN]; + int i,amt; + if (!targcell || targcell->type->solid) { + fizzle(caster); + return B_TRUE; + } + for (i = 0; i < power; i++) { + ot = getrandomobofclass(OC_FOOD, NA, NA); + o = addobfast(targcell->obpile, ot->id); + if (i == 0) { + getobname(o, obname, o->amt); + amt = o->amt; + } + } + if (haslos(player, targcell)) { + if (power >= 8) { + msg("A grand feast appears!"); + } else if (power >= 5) { + msg("A hearty meal appears!"); + } else if (power >= 2) { + msg("Some light refreshments appear!"); + } else { // ie. power == 1 + msg("%s appear%s!", obname, (amt == 1) ? "s" : ""); + } + + if (seenbyplayer) *seenbyplayer = B_TRUE; + } } else if (spellid == OT_S_CREATEMONSTER) { lifeform_t *newlf; race_t *r = NULL; @@ -4252,17 +4292,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ needredraw = B_TRUE; ch = askchar("Teleport to the new vault", "yn","y", B_TRUE, B_FALSE); if (ch == 'y') { - int x,y; - // find it - for (y = vy; y < vy+vh; y++) { - for (x = vy; x < vx + vw; x++) { - c = getcellat(caster->cell->map, x, y); - if (c && cellwalkable(caster, c, NULL)) { - teleportto(caster, c, B_TRUE); - return B_FALSE; - } + int ntries = 0; + c = getrandomroomcell(caster->cell->map, caster->cell->map->nrooms-1); + if (!c || !cellwalkable(caster, c, NULL)) { + if (++ntries >= 10) { + msg("Oops, couldn't find a free space."); + return B_FALSE; } + c = getrandomroomcell(caster->cell->map, caster->cell->map->nrooms-1); } + teleportto(caster, c, B_TRUE); + return B_FALSE; } } @@ -4837,12 +4877,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } - if (!isimmuneto(target->flags, DT_NECROTIC)) { + if (!isimmuneto(target->flags, DT_NECROTIC, B_FALSE)) { // animation (opposite dir) anim(targcell, caster->cell, '%', C_MAGENTA); } if (isplayer(caster) || cansee(player, caster)) { - if (isimmuneto(target->flags, DT_NECROTIC)) { + if (isimmuneto(target->flags, DT_NECROTIC, B_FALSE)) { msg("%s suck%s death from %s!",castername,isplayer(caster) ? "" : "s", lfname); } else { msg("%s suck%s life from %s!",castername,isplayer(caster) ? "" : "s", lfname); @@ -4855,7 +4895,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (target) { int amt; - if (isimmuneto(target->flags, DT_NECROTIC)) { + if (isimmuneto(target->flags, DT_NECROTIC, B_FALSE)) { // target gains hp amt = rnd(1,6) + power; gainhp(target, amt); @@ -5574,14 +5614,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ dam = rolldie(exposedlimbs, 3); if (isplayer(target)) { - if (isimmuneto(target->flags, DT_COLD)) { + if (isimmuneto(target->flags, DT_COLD, B_FALSE)) { msg("You feel mildly chilly."); } else { msg("You feel extremely cold!"); } if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (cansee(player, target)) { - if (isimmuneto(target->flags, DT_COLD)) { + if (isimmuneto(target->flags, DT_COLD, B_FALSE)) { msg("%s looks mildly chilly.", lfname); } else { msg("%s looks extremely cold!", lfname); @@ -5591,7 +5631,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // target takes magical damage // always hit - if (!isimmuneto(target->flags, DT_COLD)) { + if (!isimmuneto(target->flags, DT_COLD, B_FALSE)) { losehp(target, dam, DT_COLD, caster, "a frostbite spell"); } } else if (spellid == OT_S_GASEOUSFORM) { @@ -5850,7 +5890,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ target = targcell->lf; if (target) { if (ismetal(target->race->material->id)) { - if (!isimmuneto(target->flags, DT_HEAT)) { + if (!isimmuneto(target->flags, DT_HEAT, B_FALSE)) { if (isplayer(target)) { msg("Your suffer massive burns!"); } else if (cansee(player, target)) { @@ -5895,7 +5935,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } - if (nburn && !isimmuneto(target->flags, DT_FIRE)) { + if (nburn && !isimmuneto(target->flags, DT_FIRE, B_FALSE)) { int i; losehp(target, rnd(nburn,4), DT_HEAT, caster, "red-hot metal"); if (isplayer(target)) { @@ -6126,7 +6166,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } for (l = caster->cell->map->lf ; l ; l = l->next) { if (l != caster) { - if (isimmuneto(l->flags, DT_NECROTIC) || + if (isimmuneto(l->flags, DT_NECROTIC, B_FALSE) || spellresisted(l, caster, spellid, power, seenbyplayer, B_FALSE)) { if (isplayer(l)) { msg("Luckily, the evil doesn't seem to harm you."); @@ -6143,7 +6183,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // now hit the caster! - if (isimmuneto(caster->flags, DT_NECROTIC) || spellresisted(caster, caster, spellid, power, seenbyplayer, B_FALSE)) { + if (isimmuneto(caster->flags, DT_NECROTIC, B_FALSE) || spellresisted(caster, caster, spellid, power, seenbyplayer, B_FALSE)) { if (isplayer(caster)) { msg("Luckily, the evil doesn't seem to harm you."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -6534,7 +6574,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (cansee(player, target)) { msg("A glob of venom hits %s.",lfname); } - if (!isimmuneto(target->flags, DT_POISON)) { + if (!isimmuneto(target->flags, DT_POISON, B_FALSE)) { poison(target, power*3, P_VENOM, (power/4)+1, "a glob of venom"); } } @@ -7823,6 +7863,43 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!ndone) { fizzle(caster); } + } else if (spellid == OT_S_QUICKENSTONE) { + int howmany,i,n,sel,nposs = 0,nseen = 0; + cell_t *c,*poss[MAXCANDIDATES]; + howmany = (power / 2) + 1; + // get a list of all stone cells near caster + for (i = DC_N; i <= DC_NW; i++) { + c = getcellindir(caster->cell, i); + if (c && c->type->solid && (c->type->material->id == MT_STONE)) { + poss[nposs++] = c; + } + } + limit(&howmany, NA, nposs); + if (!howmany) { + fizzle(caster); + return B_TRUE; + } + // now change them + for (i = 0; i < howmany; i++) { + lifeform_t *lf; + // pick a random one + sel = rnd(0,nposs-1); + c = poss[sel]; + // turn it into a golem + setcelltype(c, c->map->habitat->emptycelltype); + lf = summonmonster(caster, c, R_GOLEMSTONE, NULL, 30, B_TRUE); + if (haslos(player, c)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + nseen++; + } + // remove it from the list + for (n = sel ; n < (nposs-1); n++) { + poss[n] = poss[n+1]; + } + nposs--; + } + // set dirty line of sight for caster, as walls have vanished + caster->losdirty = B_TRUE; } else if (spellid == OT_S_LESSENPOISON) { flag_t *f; int ndone = 0; @@ -10097,7 +10174,7 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { // HOW POWERFUL IS THIS SPELL? //////////////////////////////////// if (isplayer(lf)) { - power = 1; // base power of 1. + power = 1; // plus your hitdice/3 power += (gethitdice(lf)/3); @@ -10114,8 +10191,8 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { power += (getstatmod(lf, A_IQ) / 50); } - // plus your school skill - power += schoolskill; + // plus any extra school levels + power += (schoolskill - spelllev); } else { // for monsters, just based on hitdice: power = gethitdice(lf); diff --git a/vaults/traproom.vlt b/vaults/traproom.vlt index 61bcce3..c1c353f 100644 --- a/vaults/traproom.vlt +++ b/vaults/traproom.vlt @@ -17,6 +17,6 @@ scatter(1,1,-2,-2) ob:corpse:1-5 ! chance of great items... scatter(1,1,-2,-2) ob:great armour:1:30 scatter(1,1,-2,-2) ob:great weapon:1:30 -rarity:uncommon +rarity:vrare @end diff --git a/vaults/vault.vlt b/vaults/vault.vlt index 6333d8c..9198f5c 100644 --- a/vaults/vault.vlt +++ b/vaults/vault.vlt @@ -17,7 +17,7 @@ $:ob:25-200 gold @flags goesin:dungeon mayrotate -rarity:uncommon +rarity:vrare ! don't link to rest of map. ie this can be in the middle of nowhere. nolink @end