From 39af842e74615fbfb642c038e3a0231f298f5617 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Mon, 7 Nov 2011 02:12:04 +0000 Subject: [PATCH] - [+] bug: when ally can't see you it goes to sleep - [+] after waking it just goes to sleep again!!! - [+] bug:npc warriors aren't starting with a weapon - [+] shouldn't be able to shieldblock if youre asleep!!! - [+] allies sohuld announce what they are doing - [+] "I'm attacking a goblin" - [+] I just killed a goblin - [+] I need some rest soon... - [+] make sure only HUMANS do this...hu - [+] F_EXTRADESC v0 should be 'order'. - [+] makedesc_skill should honour this - [+] makedesc_spell - [+] same with other makedesc() functions - [+] auto-inc this when adding them. - [+] allies not properly following me downthe stairs - [+] armour that can cover multiple body parts - [+] f_goesonmulti - [+] multiple f_equipped flags. - [+] handle multiple f_equipped in takeoff() - [+] all required bodyparts must both be clear - [+] if not, prompt to remove both things. - [+] check all code for f_equipped copes with multiple occurences... - [+] display as: f - a wetsuit (worn over body and on legs) - [+] update io.c. "it is worn over xxx and yyy)" - [+] heat metal spell - [+] weilded metal burns hands and you drop it (unless immunte to fire/burn) - [+] metal armour damages you (1-4 each) - [+] metal lifeforms take huge damage - [+] all lifeforms should have at least novice level knowledge of their own raceclass - [+] new raceclass - dragons - [+] define it - [+] define skill for it - [+] make jobs know the skill - [+] red dragon - [+] high armourrating - [+] swoop - [+] fly - [+] breath weapon - [+] spells - [+] heat metal - [+] fireball - [+] burning wave - [+] want gold - [+] immune to fire - [+] red dragon hatchling - [+] generally lwoer power, only has heat metal and spark ? - [+] spellcasttext for individual spells - [+] ancient red dragon - [+] higher hp and armourrating - [+] more damage - [+] more spells --- ai.c | 15 +- attack.c | 1 + data.c | 614 +++++++++++++++++++++++++++++++++++------- data/hiscores.db | Bin 11264 -> 11264 bytes defs.h | 79 ++++-- doc/add_raceclass.txt | 11 + doc/add_skill.txt | 2 +- flag.c | 15 ++ io.c | 145 ++++++++-- lf.c | 566 ++++++++++++++++++++++++-------------- lf.h | 3 + map.c | 12 +- nexus.c | 1 + objects.c | 409 +++++++++++++++++++++++----- objects.h | 11 +- spell.c | 241 ++++++++++++----- text.c | 53 ++++ text.h | 2 + 18 files changed, 1689 insertions(+), 491 deletions(-) create mode 100644 doc/add_raceclass.txt diff --git a/ai.c b/ai.c index 2bee2b1..5b5670b 100644 --- a/ai.c +++ b/ai.c @@ -90,7 +90,15 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { addtempflag(lf->flags, F_TARGETLF, victim->id , victim->cell->x , victim->cell->y, NULL,timelimit); } // tell the player - if (cansee(player, lf)) { + if (areallies(player, lf) && cantalk(lf)) { + char text[BUFLEN]; + if (cansee(lf, victim)) { + real_getlfname(victim, text, B_FALSE); + } else { + strcpy(text, "something"); + } + sayphrase(lf, SP_ALLY_ATTACK, SV_SHOUT, NA, text); + } else { makenoise(lf, N_GETANGRY); } @@ -1298,6 +1306,11 @@ void aiturn(lifeform_t *lf) { if (isdead(target) || isunconscious(target)) { if (db) dblog(".oO { my target is dead/ko'd }", target->id, target->race->name); loseaitargets(lf); + if (areallies(lf, player) && cantalk(lf)) { + char text[BUFLEN]; + real_getlfname(target, text, B_FALSE); + sayphrase(lf, SP_ALLY_TARGETKILL, SV_SHOUT, NA, text); + } } else { // aquatic grabbers will try to drag their prey into the water if (lfhasflagval(lf, F_GRABBING, target->id, NA, NA, NULL) && isaquatic(lf) ) { diff --git a/attack.c b/attack.c index 6854958..5fad5a7 100644 --- a/attack.c +++ b/attack.c @@ -440,6 +440,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { if (hasbleedinginjury(lf, BP_HANDS)) { if (!bleedfrom(lf, BP_HANDS, B_FALSE)) { + if (isplayer(lf)) msg("^BYou bleed!"); losehp(lf, 1, DT_DIRECT, NULL, "blood loss"); } } diff --git a/data.c b/data.c index 0788f09..906c569 100644 --- a/data.c +++ b/data.c @@ -126,6 +126,10 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "hand of god"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 blocks of chocolate"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 vials of ambrosia"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 blessed scrolls of identify"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "newt corpse"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "potion of water"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "salt"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather boots"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather gloves"); @@ -283,6 +287,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, PR_BEGINNER, NA, NULL); // abilities mayusespellschool(lastjob->flags, SS_NATURE, F_CANCAST); addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf"); @@ -426,10 +431,12 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, PR_SKILLED, NA, NULL); // abilities // gained abilities addflag(lastjob->flags, F_LEVABIL, 2, OT_A_DISARMLF, NA, NULL); @@ -607,6 +614,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, PR_ADEPT, NA, NULL); // abilities addflag(lastjob->flags, F_MAXHPMOD, 120, NA, NA, NULL); addflag(lastjob->flags, F_SELECTWEAPON, B_TRUE, NA, NA, NULL); @@ -657,6 +665,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_SS_TRANSLOCATION, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_WILD, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LORE_DEMONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LORE_UNDEAD, NA, NA, NULL); // abilities addflag(lastjob->flags, F_NEEDOBFORSPELLS, OT_WIZARDSTAFF, NA, NA, NULL); @@ -968,14 +977,14 @@ void initobjects(void) { addflag(lastmaterial->flags, F_HARDNESS, 3, NA, NA, NULL); // object classes - addoc(OC_DFEATURE, "Dungeon Features", "Doors, etc.", '\\', C_GREY); - addoc(OC_FURNITURE, "Furniture", "Various kinds of mundane (or not so mundane) furnishings.", '\\', C_BROWN); + addoc(OC_DFEATURE, "Dungeon Features", "Doors, etc.", '\\', C_GREY, RR_RARE); + addoc(OC_FURNITURE, "Furniture", "Various kinds of mundane (or not so mundane) furnishings.", '\\', C_BROWN, RR_COMMON); addocnoun(lastobjectclass, "furniture"); - addoc(OC_TERRAIN, "Terrain", "Water, etc.", '\\', C_GREY); - addoc(OC_TRAP, "Trap", "Fiendish traps.", '^', C_GREY); + addoc(OC_TERRAIN, "Terrain", "Water, etc.", '\\', C_GREY, RR_NEVER); + addoc(OC_TRAP, "Trap", "Fiendish traps.", '^', C_GREY, RR_RARE); addocnoun(lastobjectclass, "trap"); - addoc(OC_MONEY, "Money", "The standard currency of Nexus.", '$', C_GREY); - addoc(OC_SCROLL, "Scrolls", "An arcane roll of parchment, inscribed with many magical glyphs.", '?', C_GREY); + addoc(OC_MONEY, "Money", "The standard currency of Nexus.", '$', C_GREY, RR_COMMON); + addoc(OC_SCROLL, "Scrolls", "An arcane roll of parchment, inscribed with many magical glyphs.", '?', C_GREY, RR_UNCOMMON); addocnoun(lastobjectclass, "scroll"); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); @@ -985,7 +994,7 @@ void initobjects(void) { //addflag(lastobjectclass->flags, F_MATCONVERTTEXT, MT_WATER, NA, NA, "goes soggy"); //addflag(lastobjectclass->flags, F_MATCONVERTTEXTPL, MT_WATER, NA, NA, "go soggy"); - addoc(OC_WAND, "Wands", "A limited-use magical wand which casts the imbued spell.", '/', C_GREY); + addoc(OC_WAND, "Wands", "A limited-use magical wand which casts the imbued spell.", '/', C_GREY, RR_VERYRARE); addocnoun(lastobjectclass, "wand"); addflag(lastobjectclass->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); @@ -994,25 +1003,25 @@ 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); + addoc(OC_POTION, "Potions", "A strange concoction contained within a small flask.", '!', C_GREY, RR_UNCOMMON); addocnoun(lastobjectclass, "potion"); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_POURABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL); - addoc(OC_RING, "Rings", "A circular band, worn on the finger.", '=', C_GREY); + addoc(OC_RING, "Rings", "A circular band, worn on the finger.", '=', C_GREY, RR_VERYRARE); addocnoun(lastobjectclass, "ring"); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_GOESON, BP_RIGHTFINGER, NA, NA, NULL); addflag(lastobjectclass->flags, F_GOESON, BP_LEFTFINGER, NA, NA, NULL); - addoc(OC_WEAPON, "Weapons", "An instrument used for the purpose of causing harm or death.", ')', C_GREY); + addoc(OC_WEAPON, "Weapons", "An instrument used for the purpose of causing harm or death.", ')', C_GREY, RR_COMMON); addocnoun(lastobjectclass, "weapon"); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_MASTERWORK, 17, NA, NULL); addflag(lastobjectclass->flags, F_CANHAVEOBMOD, OM_SHODDY, 34, NA, NULL); - addoc(OC_ARMOUR, "Armour/Clothing", "Protective gear.", '[', C_GREY); + addoc(OC_ARMOUR, "Armour/Clothing", "Protective gear.", '[', C_GREY, RR_COMMON); addocnoun(lastobjectclass, "armour"); addocnoun(lastobjectclass, "clothing"); addocnoun(lastobjectclass, "clothes"); @@ -1021,22 +1030,22 @@ 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); + addoc(OC_MISSILE, "Missiles/Ammunition", "An instrument used for the purpose of causing harm or death.", ';', C_GREY, RR_COMMON); addocnoun(lastobjectclass, "missile"); addocnoun(lastobjectclass, "ammo"); addocnoun(lastobjectclass, "ammunition"); addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addoc(OC_FLORA, "Plants", "Some kind of plant/foliage.", ',', C_GREEN); + addoc(OC_FLORA, "Plants", "Some kind of plant/foliage.", ',', C_GREEN, RR_COMMON); addocnoun(lastobjectclass, "plant"); - addoc(OC_ROCK, "Rocks/Gems", "Boring (or not so boring) rocks or plants.", '*', C_GREY); - addoc(OC_FOOD, "Food", "Yum!", '%', C_GREY); + addoc(OC_ROCK, "Rocks/Gems", "Boring (or not so boring) rocks or plants.", '*', C_GREY, RR_COMMON); + addoc(OC_FOOD, "Food", "Yum!", '%', C_GREY, RR_UNCOMMON); addocnoun(lastobjectclass, "food"); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_SMELLY, B_TRUE, NA, NA, NULL); - addoc(OC_GODSTONE, "Godstones", "Ancient artifacts, created by the elder gods.", '*', C_BOLDMAGENTA); + addoc(OC_GODSTONE, "Godstones", "Ancient artifacts, created by the elder gods.", '*', C_BOLDMAGENTA, RR_NEVER); addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pulsating purple stone"); addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL); @@ -1044,33 +1053,33 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addoc(OC_CORPSE, "Corpses", "Dead flesh which was once living.", '%', C_GREY); + addoc(OC_CORPSE, "Corpses", "Dead flesh which was once living.", '%', C_GREY, RR_NEVER); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_OBHP, 50, 50, NA, NULL); addflag(lastobjectclass->flags, F_OBHPDRAIN, 1, DT_DECAY, NA, NULL); // ie. corpses last for 50 turns - addoc(OC_TECH, "Technology", "A strange piece of futuristic technology.", '[', C_GREY); + addoc(OC_TECH, "Technology", "A strange piece of futuristic technology.", '[', C_GREY, RR_RARE); addocnoun(lastobjectclass, "technology"); addocnoun(lastobjectclass, "tech"); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addoc(OC_TOOLS, "Tools", "Useful items, from the common to the obscure.", ']', C_GREY); + addoc(OC_TOOLS, "Tools", "Useful items, from the common to the obscure.", ']', C_GREY, RR_RARE); addocnoun(lastobjectclass, "tool"); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addoc(OC_MISC, "Miscellaneous", "This could be anything.", '\\', C_GREY); - addoc(OC_EFFECT, "Environmental Effects", "Smoke, fire, etc.", '}', C_GREY); + addoc(OC_MISC, "Miscellaneous", "This could be anything.", '\\', C_GREY, RR_COMMON); + addoc(OC_EFFECT, "Environmental Effects", "Smoke, fire, etc.", '}', C_GREY, RR_NEVER); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); - addoc(OC_BOOK, "Books", "Spellbooks, tomes or manuals.", '+', C_GREY); + addoc(OC_BOOK, "Books", "Spellbooks, tomes or manuals.", '+', C_GREY, RR_VERYRARE); addocnoun(lastobjectclass, "spellbook"); addocnoun(lastobjectclass, "book"); addocnoun(lastobjectclass, "tome"); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addoc(OC_SPELL, "Spells", "A magical spell", '&', C_GREY); // this is a "virtual" object class - addoc(OC_ABILITY, "Abilities", "A special ability", '&', C_GREY); // this is a "virtual" object class + addoc(OC_SPELL, "Spells", "A magical spell", '&', C_GREY, RR_NEVER); // this is a "virtual" object class + addoc(OC_ABILITY, "Abilities", "A special ability", '&', C_GREY, RR_NEVER); // this is a "virtual" object class // object types @@ -1546,47 +1555,81 @@ void initobjects(void) { addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL); // food + addot(OT_APPLE, "apple", "A crunchy apple.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 40, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); + addot(OT_BANANA, "banana", "Ba-na-na-na-na-na na-na na-na-na.", MT_FOOD, 0.3, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 50, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); + addot(OT_BANANASKIN, "banana skin", "A slippery banana skin.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%"); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_SLIPPERY, 15, NA, NA, NULL); + addflag(lastot->flags, F_SLIPMOVE, 15, NA, NA, NULL); addot(OT_BERRY, "berry", "Juicy, brightly coloured berries.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 8, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 15, NA, ""); + addot(OT_BREADFRESH, "loaf of fresh bread", "A freshly-baked loaf of bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 200, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread"); + addot(OT_BREADGARLIC, "loaf of garlic bread", "A pungent loaf of garlic bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); + addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread"); + addot(OT_CAKEFRUIT, "fruit cake", "A very dense fruit cake. Restores all Stamina, Hit Points and Mana.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 200, NA, ""); + addot(OT_CARROT, "carrot", "A stout orange carrot. Rumour has it that carrots are good for your eyesight.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 60, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); + addot(OT_CHOCOLATE, "block of chocolate", "An entire block of chocolate.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 250, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); + addot(OT_CLOVER, "four leafed clover", "A rare 4-leafed clover.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_RARE, NULL); + addflag(lastot->flags, F_HOLDCONFER, F_EXTRALUCK, 1, NA, NULL); + addot(OT_BREADSTALE, "loaf of stale bread", "A small loaf of old, stale bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread"); addot(OT_CACFRUIT, "cactus fruit", "The nutritous fruit from a cactus plant.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL); + addot(OT_CHEESE, "chunk of cheese", "A chunk of hard cheese.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 85, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addot(OT_GARLIC, "clove of garlic", "A very pungent clove of raw garlic. ", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); - addot(OT_NUT, "peanut", "A species in the legume family.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); + addot(OT_HOTDOG, "hot dog", "A chunk of meat sandwiched between two pieces of bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 80, NA, ""); + addot(OT_JERKY, "jerky", "Salted animal flesh. Lightweight and filling.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 12, NA, ""); - addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); - addflag(lastot->flags, F_NUMAPPEAR, 1, 12, NA, ""); - addot(OT_BANANA, "banana", "Ba-na-na-na-na-na na-na na-na-na.", MT_FOOD, 0.3, OC_FOOD, SZ_TINY); - addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 50, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); - addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); - - addot(OT_BANANASKIN, "banana skin", "A slippery banana skin.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); - addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%"); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); - addflag(lastot->flags, F_SLIPPERY, 15, NA, NA, NULL); - addflag(lastot->flags, F_SLIPMOVE, 15, NA, NA, NULL); - - addot(OT_APPLE, "apple", "A crunchy apple.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); - addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 50, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); - addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 90, NA, ""); addot(OT_MUSHROOMSHI, "shiitake mushroom", "A large brown mushroom.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 60, NA, ""); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 30, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); @@ -1598,42 +1641,39 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "mushroom"); - addot(OT_BREADSTALE, "loaf of stale bread", "A small loaf of old, stale bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addot(OT_NUT, "peanut", "A species in the legume family.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); - addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread"); - addot(OT_CHEESE, "chunk of cheese", "A chunk of hard cheese.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); - addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 85, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); - addot(OT_STEW, "stew", "Some kind of meat soaked in water.", MT_FOOD, 1.5, OC_FOOD, SZ_TINY); - addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 12, NA, ""); + addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); + addflag(lastot->flags, F_NUMAPPEAR, 1, 12, NA, ""); addot(OT_ROASTMEAT, "chunk of roast meat", "A chunk of flame-roasted flesh.", MT_FLESH, 1, OC_FOOD, SZ_TINY); // weight normally comes from corpse type addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); - addot(OT_BREADFRESH, "loaf of fresh bread", "A freshly-baked loaf of bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addot(OT_RUMBALL, "rum ball", "A rum-filled ball of chocolate. Cures pain and restores 2-6 hit points.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); // weight normally comes from corpse type addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 200, NA, ""); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); - addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread"); - addot(OT_CLOVER, "four leafed clover", "A rare 4-leafed clover.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); - addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%"); + addot(OT_SALT, "pinch of salt", "A small measure of salt. Used for cooking.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); - addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_RARE, NULL); - addflag(lastot->flags, F_HOLDCONFER, F_EXTRALUCK, 1, NA, NULL); - addot(OT_CARROT, "carrot", "A stout orange carrot. Rumour has it that carrots are good for your eyesight.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); - addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 60, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addot(OT_SANDWICHCHEESE, "cheese sandwich", "A tasty cheese sandwich. Filling, and restores all stamina.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); + addot(OT_SANDWICHPB, "peanut butter sandwich", "An extremely filling sandwich. Restores all stamina and boosts Fitness.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 200, NA, ""); + addot(OT_SUGAR, "lump of sugar", "A small block of sugar. Used for cooking.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addot(OT_TOMATO, "tomato", "A juicy red tomato.", MT_FOOD, 0.3, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 30, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); - addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); - addot(OT_CHOCOLATE, "block of chocolate", "An entire block of chocolate.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); - addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 250, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); // corpses addot(OT_CORPSE, "corpse", "xxx", MT_FLESH, 1, OC_CORPSE, SZ_TINY); addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); // will be overridden @@ -1746,6 +1786,16 @@ void initobjects(void) { addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); + // potions which come from cooking + addot(OT_POT_SOUPMUSHROOM, "flask of mushroom soup", "Hearty soup which restores a small amount of stamina.", MT_GLASS, 1, OC_POTION, SZ_TINY); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + killflagsofid(lastot->flags, F_HASHIDDENNAME); + addot(OT_POT_SOUPTOMATO, "flask of tomato soup", "Hearty soup which restores a small amount of stamina.", MT_GLASS, 1, OC_POTION, SZ_TINY); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + killflagsofid(lastot->flags, F_HASHIDDENNAME); + addot(OT_POT_STROGONOFF, "flask of beef strogonoff", "A beef and mushroom stew which temporarily boosts your Fitness.", MT_GLASS, 1, OC_POTION, SZ_TINY); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + killflagsofid(lastot->flags, F_HASHIDDENNAME); // scrolls @@ -1880,21 +1930,31 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); // l3 - addot(OT_S_EXPLODEMETAL, "explode metal", "Causes all metal objects in a location explode.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); - addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); - addflag(lastot->flags, F_TARGETTEDSPELL, TT_OBJECT, NA, NA, NULL); - addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_MAGSHIELD, "magnetic shield", "Surrounds the caster with magnetic force, repelling metal objects and attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how long the magnetic shield will last."); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addot(OT_S_HEATMETAL, "heat metal", "Causes all metal in the target area to become red hot.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); + addflag(lastot->flags, F_RANGE, 2, NA, NA, NULL); // l4 - addot(OT_S_ANIMATEMETAL, "animate metal", "Imbues a metallic weapon with temporary life, enabling it to fight on its own.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_EXPLODEMETAL, "explode metal", "Causes all metal objects in a location explode.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_OBJECT, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + // l5 + addot(OT_S_ANIMATEMETAL, "animate metal", "Imbues a metallic weapon with temporary life, enabling it to fight on its own.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); /////////////////// @@ -2019,9 +2079,9 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addot(OT_S_SIXTHSENSE, "sixth sense", "Warns the caster of any creature attempting to sneak up behind them.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power III, the creature's species will be detected."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power V, the exact creature type will be detected."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VII, you can turn to face the creature."); + addflag(lastot->flags, F_EXTRADESC, 1, NA, NA, "At Power III, the creature's species will be detected."); + addflag(lastot->flags, F_EXTRADESC, 2, NA, NA, "At Power V, the exact creature type will be detected."); + addflag(lastot->flags, F_EXTRADESC, 3, NA, NA, "At Power VII, you can turn to face the creature."); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -2036,8 +2096,8 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addot(OT_S_DETECTLIFE, "detect life", "Senses the size of creatures within a 10-cell radius of the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the detection range."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VIII, exact creatures types are detected."); + addflag(lastot->flags, F_EXTRADESC, 1, NA, NA, "Spell power determines the detection range."); + addflag(lastot->flags, F_EXTRADESC, 2, NA, NA, "At power VIII, exact creatures types are detected."); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); // l3 @@ -2061,12 +2121,12 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addot(OT_S_LORE, "lore", "Obtain knowledge about any one species.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power I, you gain Novice level knowledge."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power II, you gain Beginner level knowledge."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power IV, you gain Adept level knowledge."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VI, you gain Skilled level knowledge."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VIII, you gain Expert level knowledge."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power X, you gain Master level knowledge."); + addflag(lastot->flags, F_EXTRADESC, 1, NA, NA, "At power I, you gain Novice level knowledge."); + addflag(lastot->flags, F_EXTRADESC, 2, NA, NA, "At power II, you gain Beginner level knowledge."); + addflag(lastot->flags, F_EXTRADESC, 3, NA, NA, "At power IV, you gain Adept level knowledge."); + addflag(lastot->flags, F_EXTRADESC, 4, NA, NA, "At power VI, you gain Skilled level knowledge."); + addflag(lastot->flags, F_EXTRADESC, 5, NA, NA, "At power VIII, you gain Expert level knowledge."); + addflag(lastot->flags, F_EXTRADESC, 6, NA, NA, "At power X, you gain Master level knowledge."); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); @@ -2125,8 +2185,8 @@ void initobjects(void) { // l2 addot(OT_S_GUSTOFWIND, "gust of wind", "Causes a gust of wind to blow up to ^bpower^n of the target's objects away.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The chance of each object blowing away is determined by the spell's power."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell's power is boosted when cast outside."); + addflag(lastot->flags, F_EXTRADESC, 1, NA, NA, "The chance of each object blowing away is determined by the spell's power."); + addflag(lastot->flags, F_EXTRADESC, 2, NA, NA, "This spell's power is boosted when cast outside."); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -2279,10 +2339,10 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_CRYSTALARM, "crystalline armour", "Summons ice crystal armour to protect you from damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 1-3: one piece of armour is created."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 4-6: two pieces of armour are created."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 7-9: three pieces of armour are created."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 10: four pieces of armour are created."); + addflag(lastot->flags, F_EXTRADESC, 1, NA, NA, "At power 1-3: one piece of armour is created."); + addflag(lastot->flags, F_EXTRADESC, 2, NA, NA, "At power 4-6: two pieces of armour are created."); + addflag(lastot->flags, F_EXTRADESC, 3, NA, NA, "At power 7-9: three pieces of armour are created."); + addflag(lastot->flags, F_EXTRADESC, 4, NA, NA, "At power 10: four pieces of armour are created."); addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); @@ -4338,6 +4398,19 @@ void initobjects(void) { addflag(lastot->flags, F_DTVULN, DT_ACID, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); + // armour - multipart + addot(OT_WETSUIT, "wetsuit", "Full-body rubber suit which provides good insulation from cold.", MT_RUBBER, 6, OC_ARMOUR, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_GOESONMULTI, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); + addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); + addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 5, 5, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_DTRESIST, DT_COLD, NA, NULL); + addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 3, NA, NULL); + addflag(lastot->flags, F_CRITPROTECTION, 80, NA, NA, NULL); // armour - body addot(OT_COTTONSHIRT, "cotton shirt", "A comfortable white cotton shirt.", MT_CLOTH, 0.7, OC_ARMOUR, SZ_MEDIUM); @@ -4348,6 +4421,19 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 3, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 33, NA, NA, NULL); + + + addot(OT_ARMOURDEMON, "demonskin vest", "Body armour created by flaying the flesh from a living demon, it retains its innate immunity to fire.", MT_FLESH, 7, OC_ARMOUR, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_FIRE, NA, NULL); + addflag(lastot->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 3, NA, NULL); + addflag(lastot->flags, F_CRITPROTECTION, 80, NA, NA, NULL); + addflag(lastot->flags, F_STARTBLESSED, B_CURSED, NA, NA, NULL); addot(OT_ARMOURLEATHER, "leather armour", "Body armour created from soft leather.", MT_LEATHER, 10, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); @@ -4432,6 +4518,8 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 75, NA, NA, NULL); + + // armour - shoulders addot(OT_CLOAK, "cloak", "A standard leather cloak.", MT_LEATHER, 4, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); @@ -5624,6 +5712,67 @@ void initobjects(void) { // special obs addot(OT_PLAYERSTART, "playerstart", "starting pos for player", MT_NOTHING, 0, OC_MISC, SZ_MINI); + + // recipes - easy + addrecipe(OT_POT_JUICE, + OT_APPLE, 2, B_TRUE, + OT_STONE, 1, B_FALSE, + OT_NONE); + addrecipe(OT_POT_SOUPTOMATO, + OT_TOMATO, 1, B_TRUE, + OT_POT_WATER, 1, B_TRUE, + OT_NONE); + addrecipe(OT_POT_SOUPMUSHROOM, + OT_MUSHROOMSHI, 1, B_TRUE, + OT_POT_WATER, 1, B_TRUE, + OT_NONE); + addrecipe(OT_RUMBALL, + OT_POT_RUM, 1, B_TRUE, + OT_CHOCOLATE, 1, B_TRUE, + OT_NONE); + addrecipe(OT_SANDWICHCHEESE, + OT_BREADFRESH, 1, B_TRUE, + OT_CHEESE, 1, B_TRUE, + OT_NONE); + // recipes - medium + addrecipe(OT_BREADGARLIC, + OT_BREADFRESH, 1, B_TRUE, + OT_GARLIC, 2, B_TRUE, + OT_SALT, 1, B_TRUE, + OT_NONE); + addrecipe(OT_HOTDOG, + OT_BREADFRESH, 1, B_TRUE, + OT_CORPSE, 1, B_TRUE, + OT_TOMATO, 1, B_TRUE, + OT_NONE); + addrecipe(OT_JERKY, + OT_CORPSE, 1, B_TRUE, + OT_POT_WATER, 1, B_TRUE, + OT_SALT, 1, B_TRUE, + OT_NONE); + addrecipe(OT_POT_SPEED, + OT_BERRY, 2, B_TRUE, + OT_POT_WATER, 1, B_TRUE, + OT_SUGAR, 1, B_TRUE, + OT_NONE); + addrecipe(OT_POT_STROGONOFF, + OT_CORPSE, 1, B_TRUE, + OT_MUSHROOMSHI, 1, B_TRUE, + OT_POT_WATER, 1, B_TRUE, + OT_NONE); + // recipes - hard + addrecipe(OT_CAKEFRUIT, + OT_CHOCOLATE, 1, B_TRUE, + OT_POT_RUM, 1, B_TRUE, + OT_SUGAR, 1, B_TRUE, + OT_BERRY, 3, B_TRUE, + OT_NONE); + addrecipe(OT_SANDWICHPB, + OT_BREADFRESH, 1, B_TRUE, + OT_NUT, 2, B_TRUE, + OT_SALT, 1, B_TRUE, + OT_STONE, 1, B_FALSE, + OT_NONE); } void initrace(void) { @@ -5635,6 +5784,7 @@ void initrace(void) { addraceclass(RC_ANIMAL, "animal", "animals and insects", SK_LORE_NATURE); addraceclass(RC_AQUATIC, "aquatic creature", "aquatic creatures", SK_LORE_NATURE); addraceclass(RC_DEMON, "demon", "demons", SK_LORE_DEMONS); + addraceclass(RC_DRAGON, "dragon", "dragons", SK_LORE_DRAGONS); addraceclass(RC_GOD, "god", "dieties", SK_NONE); addraceclass(RC_HUMANOID, "humanoid", "humanoid creatures", SK_LORE_HUMANOID); addraceclass(RC_INSECT, "insect", "insects and animals", SK_LORE_NATURE); @@ -6899,7 +7049,7 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 45, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 50, NA, NULL); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "35d4+0"); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "12d4+0"); addflag(lastrace->flags, F_ARMOURRATING, 11, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -7461,7 +7611,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); - addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, ""); + addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, ""); addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+2"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); @@ -7945,7 +8095,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_DTRESIST, DT_FIRE, B_TRUE, NA, NULL); + addflag(lastrace->flags, F_DTRESIST, DT_COLD, B_TRUE, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 3, NA, NA, NULL); @@ -8323,6 +8473,251 @@ void initrace(void) { addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addflag(lastrace->flags, F_MORALE, 7, NA, NA, NULL); + // end animals + + // dragons + + + addrace(R_DRAGONBLUE, "blue dragon", 400, 'D', C_BLUE, MT_FLESH, RC_DRAGON, "Blue dragons are massive reptilian creatures who can (and will) consume almost any living creature."); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, 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_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "30d4"); + addflag(lastrace->flags, F_ARMOURRATING, 18, NA, NA, NULL); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 16, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TAIL, 12, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars"); + addflag(lastrace->flags, F_ATTACKRANGE, 2, 5, NA, NULL); // maintain distance + addflag(lastrace->flags, F_FLEEONHPPCT, 15, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_AIR, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPEECH, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 7, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_GUSTOFWIND, NA, NA, "pw:8;"); + addflag(lastrace->flags, F_CANCAST, OT_S_LIGHTNINGBOLT, NA, NA, "pw:8;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "unleashes its lightning breath"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_GUSTOFWIND, NA, NA, "flaps its wings"); + addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + + addrace(R_DRAGONBLUEY, "young blue dragon", 150, 'D', C_BLUE, MT_FLESH, RC_DRAGON, "Blue dragons are massive reptilian creatures who can (and will) consume almost any living creature."); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, 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_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "15d4"); + addflag(lastrace->flags, F_ARMOURRATING, 12, NA, NA, NULL); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 10, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TAIL, 8, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 5, NA, "roars^a roars"); + addflag(lastrace->flags, F_ATTACKRANGE, 2, 5, NA, NULL); // maintain distance + addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_AIR, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPEECH, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_AIRBLAST, NA, NA, "pw:8;"); + addflag(lastrace->flags, F_CANCAST, OT_S_GUSTOFWIND, NA, NA, "pw:8;"); + addflag(lastrace->flags, F_CANCAST, OT_S_LIGHTNINGBOLT, NA, NA, "pw:8;"); + addflag(lastrace->flags, F_CANCAST, OT_S_FLOOD, NA, NA, "pw:2;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "unleashes its lightning breath"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_GUSTOFWIND, NA, NA, "flaps its wings"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_AIRBLAST, NA, NA, "flaps its wings"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FLOOD, NA, NA, "discharges electricity into the ground"); + addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 15, NA, NA, NULL); + addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + addrace(R_DRAGONBLUEA, "ancient blue dragon", 600, 'D', C_BLUE, MT_FLESH, RC_DRAGON, "Blue dragons are massive reptilian creatures who can (and will) consume almost any living creature."); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, 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_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "45d4"); + addflag(lastrace->flags, F_ARMOURRATING, 24, NA, NA, NULL); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 30, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TAIL, 21, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 5, NA, "roars^a roars"); + addflag(lastrace->flags, F_FLEEONHPPCT, 15, NA, NA, NULL); + addflag(lastrace->flags, F_ATTACKRANGE, 2, 5, NA, NULL); // maintain distance + addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_AIR, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPEECH, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 12, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_AIRBLAST, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANCAST, OT_S_GUSTOFWIND, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANCAST, OT_S_LIGHTNINGBOLT, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANCAST, OT_S_FLOOD, NA, NA, "pw:4;"); + addflag(lastrace->flags, F_CANCAST, OT_S_CHAINLIGHTNING, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_FEAR, 30, 30, "pw:6;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "unleashes its lightning breath"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_GUSTOFWIND, NA, NA, "flaps its wings"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_AIRBLAST, NA, NA, "flaps its wings"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FLOOD, NA, NA, "discharges electricity into the ground"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FEAR, NA, NA, NULL); + addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 45, NA, NA, NULL); + addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + + + addrace(R_DRAGONRED, "red dragon", 400, 'D', C_RED, MT_FLESH, RC_DRAGON, "Red dragons are massive evil reptilians who thrive on destruction, especially by means of fire."); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, 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_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "30d4"); + addflag(lastrace->flags, F_ARMOURRATING, 18, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 20, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TAIL, 16, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars"); + addflag(lastrace->flags, F_FLEEONHPPCT, 15, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_FIRE, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPEECH, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 7, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_FIREBALL, NA, NA, "pw:7;"); + addflag(lastrace->flags, F_CANCAST, OT_S_BURNINGWAVE, NA, NA, "pw:8;"); + addflag(lastrace->flags, F_CANCAST, OT_S_HEATMETAL, NA, NA, "pw:8;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "unleashes its fiery breath"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_HEATMETAL, NA, NA, "radiates an aura of intense heat"); + addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + addrace(R_DRAGONREDY, "young red dragon", 150, 'D', C_RED, MT_FLESH, RC_DRAGON, "Red dragons are massive evil reptilians who thrive on destruction, especially by means of fire."); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, 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_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "15d4"); + addflag(lastrace->flags, F_ARMOURRATING, 12, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 14, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TAIL, 10, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 5, NA, "roars^a roars"); + addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_FIRE, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPEECH, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_FIREDART, NA, NA, "pw:7;"); + addflag(lastrace->flags, F_CANCAST, OT_S_HEATMETAL, NA, NA, "pw:7;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "unleashes its fiery breath"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_HEATMETAL, NA, NA, "radiates an aura of intense heat"); + addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 15, NA, NA, NULL); + addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + addrace(R_DRAGONREDA, "ancient red dragon", 600, 'D', C_RED, MT_FLESH, RC_DRAGON, "Red dragons are massive evil reptilians who thrive on destruction, especially by means of fire."); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, 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_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "45d4"); + addflag(lastrace->flags, F_ARMOURRATING, 24, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 30, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TAIL, 21, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 5, NA, "roars^a roars"); + addflag(lastrace->flags, F_FLEEONHPPCT, 15, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_FIRE, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPEECH, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 12, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_FIREBALL, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANCAST, OT_S_FLAMEPILLAR, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANCAST, OT_S_BURNINGWAVE, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_FEAR, 30, 30, "pw:6;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "unleashes its fiery breath"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FEAR, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FLAMEPILLAR, NA, NA, "breaths fire into the ground"); + addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 45, NA, NA, NULL); + addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + // end dragons // insects addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_YELLOW, MT_FLESH, RC_ANIMAL, "A harmless, colourful butterfly."); @@ -8917,10 +9312,13 @@ void initskills(void) { addskilldesc(SK_CLIMBING, PR_EXPERT, "-10% accuracy penalty while climbing.", B_FALSE); addskilldesc(SK_CLIMBING, PR_MASTER, "No accuracy penalty or stamina cost to remain climbing.", B_FALSE); addskill(SK_COOKING, "Cooking", "Your ability to combine foods into nutritious meals.", 50); + addskilldesc(SK_COOKING, PR_INEPT, " - Note: when cooking, all ingredients must already be recognised.", B_TRUE); addskilldesc(SK_COOKING, PR_NOVICE, "^gYou now recognise water and rotting food.^n", B_TRUE); - addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou can now recognise all kinds of bad food.^n", B_TRUE); - addskilldesc(SK_COOKING, PR_ADEPT, "^gYou can use the 'cook' ability to make jerky.^n", B_FALSE); - addskilldesc(SK_COOKING, PR_EXPERT, "^gYou can use the 'cook' ability to make stew.^n", B_FALSE); + addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou can cook recipes using up to 2 ingredients.", B_TRUE); + addskilldesc(SK_COOKING, PR_ADEPT, "^gYou can cook recipes using up to 3 ingredients.", B_TRUE); + addskilldesc(SK_COOKING, PR_SKILLED, "^gYou can cook recipes using up to 4 ingredients.", B_TRUE); + addskilldesc(SK_COOKING, PR_EXPERT, "^gYou can cook recipes using up to 5 ingredients.", B_TRUE); + addskilldesc(SK_COOKING, PR_MASTER, "^gYou can cook all recipes.", B_TRUE); addskill(SK_EVASION, "Evasion", "Your ability to dodge blows or traps.", 50); addskilldesc(SK_EVASION, PR_NOVICE, "^gIncreases your EV by 5%.^n", B_FALSE); addskilldesc(SK_EVASION, PR_BEGINNER, "^gIncreases your EV by 10%.^n", B_FALSE); @@ -9035,6 +9433,14 @@ void initskills(void) { addskilldesc(SK_LORE_DEMONS, PR_ADEPT, "^gExact remaining hit points and stamina are shown and an approximate threat level is calculated.^n", B_FALSE); addskilldesc(SK_LORE_DEMONS, PR_SKILLED, "^gExact turns to kill are shown.", B_FALSE); addskilldesc(SK_LORE_DEMONS, PR_MASTER, "^gYou can view complete information about skills, magic and abilities.^n", B_FALSE); + addskill(SK_LORE_DRAGONS, "Lore:Dragons", "Determines your knowledge about dragons.", 0); + addskilldesc(SK_LORE_DRAGONS, PR_INEPT, "At each skill level, more information about related creatures will be shown.", B_FALSE); + addskilldesc(SK_LORE_DRAGONS, PR_INEPT, "Each level also gives +10% damage and accuracy against related creatures.", B_FALSE); + addskilldesc(SK_LORE_DRAGONS, PR_NOVICE, "^gExact attributes, armour rating and evasion are revealed.^n", B_FALSE); + addskilldesc(SK_LORE_DRAGONS, PR_BEGINNER, "^gExact attack damage is now revealed.^n", B_FALSE); + addskilldesc(SK_LORE_DRAGONS, PR_ADEPT, "^gExact remaining hit points and stamina are shown and an approximate threat level is calculated.^n", B_FALSE); + addskilldesc(SK_LORE_DRAGONS, PR_SKILLED, "^gExact turns to kill are shown.", B_FALSE); + addskilldesc(SK_LORE_DRAGONS, PR_MASTER, "^gYou can view complete information about skills, magic and abilities.^n", B_FALSE); addskill(SK_LORE_HUMANOID, "Lore:Humanoid", "Determines your knowledge about humanoid (bipedal) creatures.", 0); addskilldesc(SK_LORE_HUMANOID, PR_INEPT, "At each skill level, more information about related creatures will be shown.", B_FALSE); addskilldesc(SK_LORE_HUMANOID, PR_INEPT, "Each level also gives +10% damage and accuracy against related creatures.", B_FALSE); diff --git a/data/hiscores.db b/data/hiscores.db index e017819e1e319f8a0f991ba9a02177db2e60507a..272434d015872e62d1de4911c2b0b9ed823d27c5 100644 GIT binary patch delta 569 zcmXw#%WD%+6vofJUnY;4G?QkUKJu!Vq{%ckbc~{yx=0s_P%v32)fTM9SG5`U#z$Pun+H-_ z68-3=ZFdiOQu`bzyW}E={iO8DWMYt%tV|h>X{4`PdTeVTM^E!4fg2;gXL}Q-K+M#elH7(_$_BmyL3521DVI-tl zgoFz>g44Tb-3Nt13%#`IFKE@mHbT(^1-WriP=N_~j~w{%JI~@doaNc&+4YnBWizqc zQC;9V@DG3R6Fc~b4|s>Sc!{TYf;Ft-A@1WYZeaoQsNp)MQN?9kLOlQc zdumsG)02Tm7T5iGp?3l+t!rVg9=yXnf61IMKwK7F5a=JB{WY^BS`@f~aipnp%!gT! zHID+BqhcdCN9Jj<94?WW6&pr_%#4^LNDESeA%UI?Ig!U?o{;7EQPK)EGY_bnu8{xe z7H;4yy48F2TrH`qD$V=6%^O^!eR`#{VaFKBTjWiLiyYXaVUG2epubvi{Veh(=p-$Y zBr1v5i1x5eL@vit6b06uef*s_ zd4*@_6K!~>jxh(-Jvzg&T!l0bB>aZkLHE2I%a^0t9dvZN_dk#8cHgK`DEh5-{C5|k QoYWoJf!5-Im&~=*Az;E|v;Y7A diff --git a/defs.h b/defs.h index 9830963..f81e9ca 100644 --- a/defs.h +++ b/defs.h @@ -414,6 +414,9 @@ enum QUADRANT { }; enum SAYPHRASE { + SP_ALLY_ATTACK, + SP_ALLY_INPAIN, + SP_ALLY_TARGETKILL, SP_BEG, SP_BEGATTACK, SP_BEGTHANKS, @@ -435,7 +438,7 @@ enum SPEECHVOL { SV_TALK = 2, SV_SHOUT = 3, SV_ROAR = 4, - SV_BELLOW = 3, + SV_BELLOW = 5, }; enum SKILL { @@ -467,6 +470,7 @@ enum SKILL { // knowledge SK_LORE_ARCANA, SK_LORE_DEMONS, + SK_LORE_DRAGONS, SK_LORE_HUMANOID, SK_LORE_NATURE, SK_LORE_UNDEAD, @@ -496,7 +500,7 @@ enum SKILL { SK_SS_TRANSLOCATION, SK_SS_WILD, }; -#define MAXSKILLS 53 +#define MAXSKILLS 54 // proficiency levels enum SKILLLEVEL { @@ -714,6 +718,7 @@ enum DAMTYPE { // Object Classes enum OBCLASS { + OC_NONE, OC_ABILITY, OC_ARMOUR, OC_BOOK, @@ -774,6 +779,7 @@ enum RACECLASS { RC_ANIMAL, RC_AQUATIC, RC_DEMON, + RC_DRAGON, RC_GOD, RC_HUMANOID, RC_INSECT, @@ -895,6 +901,13 @@ enum RACE { R_SPIDERREDBACK, R_WOLF, R_WOLFYOUNG, + // dragons + R_DRAGONBLUE, + R_DRAGONBLUEY, + R_DRAGONBLUEA, + R_DRAGONRED, + R_DRAGONREDY, + R_DRAGONREDA, // insects R_BUTTERFLY, R_CENTIPEDE, @@ -1034,24 +1047,32 @@ enum OBTYPE { OT_STUMP, OT_TREE, // food - OT_BERRY, - OT_CACFRUIT, - OT_GARLIC, - OT_NUT, + OT_APPLE, OT_BANANA, OT_BANANASKIN, // not really food - OT_APPLE, - OT_MUSHROOMSHI, - OT_MUSHROOMTOAD, - OT_BREADSTALE, - OT_CHEESE, - OT_STEW, - OT_JERKY, - OT_ROASTMEAT, + OT_BERRY, OT_BREADFRESH, + OT_BREADGARLIC, + OT_BREADSTALE, + OT_CACFRUIT, + OT_CAKEFRUIT, OT_CARROT, + OT_CHEESE, OT_CHOCOLATE, OT_CLOVER, + OT_GARLIC, + OT_HOTDOG, + OT_JERKY, + OT_MUSHROOMSHI, + OT_MUSHROOMTOAD, + OT_NUT, + OT_ROASTMEAT, + OT_RUMBALL, + OT_SALT, + OT_SANDWICHCHEESE, + OT_SANDWICHPB, + OT_SUGAR, + OT_TOMATO, // corpses OT_CORPSE, OT_FINGER, @@ -1086,6 +1107,10 @@ enum OBTYPE { OT_POT_SPEED, OT_POT_WATER, OT_POT_JUICE, + // soup from recipes + OT_POT_SOUPMUSHROOM, + OT_POT_SOUPTOMATO, + OT_POT_STROGONOFF, // scrolls OT_MAP, OT_GRAPHPAPER, @@ -1120,6 +1145,7 @@ enum OBTYPE { OT_S_ACCELMETAL, OT_S_ANIMATEMETAL, OT_S_EXPLODEMETAL, + OT_S_HEATMETAL, OT_S_PULLMETAL, OT_S_MAGSHIELD, OT_S_METALHEAL, @@ -1469,7 +1495,10 @@ enum OBTYPE { OT_POISONPUFF, OT_VINE, OT_WEB, + // armour - multipart + OT_WETSUIT, // armour - body + OT_ARMOURDEMON, OT_ARMOURLEATHER, OT_ARMOURRING, OT_ARMOURSCALE, @@ -1822,6 +1851,8 @@ enum FLAG { // weapon/armour flags F_EQUIPPED, // val0 = where it is equipped. CLEAR WHEN OB MOVED! F_GOESON, // val0 = where it can be equipped. + F_GOESONMULTI, // ob is equipped on _ALL_ F_GOESON flags, rather than + // equipped on _ONE OF_ the. F_BONUS, // val0=bonus/penalty to damage/armour. ie. +1 sword F_THROWMISSILE, // weapon would make a good thrown missle - used by AI F_UNIQUE, // only one may appear @@ -2106,6 +2137,7 @@ enum FLAG { F_ONGOING, // this spell has an ongoing cost F_CASTINGTIME, // this spell takes v0 turns to cast F_EXTRADESC, // extra descriptions for this object + // v0 is the order in which these are displayed (0-5) //F_SPELLLETTER, // text[0] = letter to cast this spell F_AICASTTOFLEE, // AI can cast this spell to help flee/heal // v0 is who to target @@ -2185,6 +2217,8 @@ enum FLAG { F_STARTOB, // val0 = %chance of starting with it, text = ob name // val1,2 = min/max amounts. if NA, min=max=1. F_STARTOBDT, // val0 = %chance of starting with damtype val1 + // option val2 = addition to map depth for rarity + // calculation F_STARTOBCLASS, // val0 = %chance of starting with obclass val1 // option val2 = addition to map depth for rarity // calculation @@ -2327,6 +2361,7 @@ enum FLAG { F_SPELLCASTTEXT, // text is announcement for spellcast // if text is empty, then don't announce // this lf's spell casting at all. + // if v0 is set, only use text for spellid v0 // if v2 is 'appendyou' " at xxx" will // be appended. F_NODEATHANNOUNCE, // don't say 'the xx dies' if this lf dies @@ -2470,6 +2505,8 @@ enum FLAG { // the flagpile's F_BONUS flag. F_EXTRAINFO, // knows extra info F_EXTRALUCK, // lf gets +v0 to all skill checks! + // higher chance of rare objects + // lower chance of rare monsters F_EXTRAMP, // lf has +v0 % extra maxmp F_FEIGNINGDEATH, // lf is pretending to be dead F_FLYING, // lf is flying @@ -2555,7 +2592,7 @@ enum FLAG { F_MAXATTACKS, // v0 = min # attacks this lf can make per round // v1 = max # attacks this lf can make per round F_HASATTACK, // v0 = obid to use when attacking unarmed - // if v1 is set, it overrides DR + // if v1 is set, it overrides DR(damagerating) // if text is set, it overrides the damage F_EVASION, // % chance of evading an attack @@ -2750,6 +2787,7 @@ enum ERROR { E_WRONGCELLTYPE, E_OBINWAY, E_TOOHEAVY, + E_TOOHARD, E_NOHANDS, E_NOPACK, E_INSUBSTANTIAL, @@ -3233,6 +3271,16 @@ typedef struct hiddenname_s { } hiddenname_t; +#define MAXRECIPEINGREDIENTS 5 +typedef struct recipe_s { + int ningredients; + enum OBTYPE ingredient[MAXRECIPEINGREDIENTS]; + int count[MAXRECIPEINGREDIENTS]; + int consume[MAXRECIPEINGREDIENTS]; + enum OBTYPE result; + struct recipe_s *next, *prev; +} recipe_t; + typedef struct knowledge_s { enum OBTYPE id; char *hiddenname; @@ -3251,6 +3299,7 @@ typedef struct job_s { #define MAXOCNOUNS 5 typedef struct objectclass_s { enum OBCLASS id; + enum RARITY rarity; char *name; char *desc; char *noun[MAXOCNOUNS]; diff --git a/doc/add_raceclass.txt b/doc/add_raceclass.txt new file mode 100644 index 0000000..bf1c963 --- /dev/null +++ b/doc/add_raceclass.txt @@ -0,0 +1,11 @@ +defs.h: + add RC_xxx + +data.c: + addraceclass(xxx) + +lf.c: + update cantalk(xxx) + +ALSO: + add matching skill! diff --git a/doc/add_skill.txt b/doc/add_skill.txt index a9854ca..934808f 100644 --- a/doc/add_skill.txt +++ b/doc/add_skill.txt @@ -2,7 +2,7 @@ defs.h: add SK_xxx inc MAXSKILLS -lf.c: +data.c: add addskill() add addskilldesc() diff --git a/flag.c b/flag.c index e5c9188..86ca67c 100644 --- a/flag.c +++ b/flag.c @@ -73,6 +73,21 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, return NULL; } + // auto-increment order for EXTRADESC flag + if ((id == F_EXTRADESC) && (val1 == NA)) { + flag_t *retflag[MAXCANDIDATES]; + int nretflags; + int nextorder = 0,i; + getflags(fp, retflag, &nretflags, F_EXTRADESC, F_NONE); + for (i = 0; i < nretflags; i++) { + int this; + this = retflag[i]->val[0]; + if (this == NA) this = 0; + if (this >= nextorder) nextorder = this+1; + } + val1 = nextorder; + } + lf = fp->owner; if (gamemode == GM_GAMESTARTED) { diff --git a/io.c b/io.c index e4fc7d5..90e7233 100644 --- a/io.c +++ b/io.c @@ -1633,6 +1633,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s %s sprinting!",lfname, isplayer(lf) ? "start" : "starts"); donesomething = B_TRUE; break; + case F_STENCH: + msg("%s start%s emitting a foul odour!",lfname, isplayer(lf) ? "" : "s" ); + donesomething = B_TRUE; + break; case F_STUNNED: msg("%s %s stunned!",lfname, is(lf)); donesomething = B_TRUE; @@ -2204,6 +2208,10 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_STENCH: + msg("%s no longer smell%s bad.",lfname, isplayer(lf) ? "" : "s" ); + donesomething = B_TRUE; + break; case F_STUNNED: msg("%s %s no longer stunned.",lfname, is(lf)); donesomething = B_TRUE; @@ -3518,22 +3526,33 @@ void docomms(lifeform_t *lf) { snprintf(buf, BUFLEN, "Tell %s to attack who?",lfname); snprintf(buf2, BUFLEN, "%s->Attack->",lfname); c = askcoords(buf, buf2, TT_MONSTER, lf, UNLIMITED, LOF_DONTNEED, B_FALSE); - if (c && c->lf && cansee(lf, c->lf)) { + if (c && c->lf) { lf2 = c->lf; } if (!lf2) { msg("Cancelled."); return; - } + } getlfname(lf2, lfname2); msg("You say \"Attack %s!\" to %s.",isplayer(lf2) ? "me" : lfname2, lfname); - if (isplayer(lf)) { + if (lf == lf2) { + // won't attack itself msg("%s looks confused at your command.", lfname); } else { - // stop attacking all current targets first... - killflagsofid(lf->flags, F_TARGETLF); - aiattack(lf, lf2, DEF_AIFOLLOWTIME); + if (!cansee(lf, lf2)) { + turntoface(lf, lf2->cell); + } + if (cansee(lf, lf2)) { + // stop attacking all current targets first... + killflagsofid(lf->flags, F_TARGETLF); + aiattack(lf, lf2, DEF_AIFOLLOWTIME); + } else { + char saybuf[BUFLEN]; + getlfnamea(lf2, lfname2); + sprintf(saybuf, "I can't see %s!", lfname2); + say(lf, saybuf, SV_TALK); + } } break; case 'c': @@ -4332,6 +4351,7 @@ char *makedesc_ob(object_t *o, char *retbuf) { char buf[BIGBUFLEN]; char buf2[BUFLEN]; char buf3[BUFLEN]; + recipe_t *rec; flag_t *f; int obknown,i,throwrange; flag_t *retflag[MAXCANDIDATES]; @@ -4367,10 +4387,18 @@ char *makedesc_ob(object_t *o, char *retbuf) { // extra object descriptions? getflags(o->flags, retflag, &nretflags, F_EXTRADESC, F_NONE); - for (i = 0; i < nretflags; i++) { - f = retflag[i]; - snprintf(buf, BUFLEN, "%s^n\n", f->text); - strncat(retbuf, buf, BUFLEN); + if (nretflags) { + int order; + for (order = 0; order < 5; order++) { + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if ((f->val[0] == order) || + ((f->val[0] == NA) && (order == 0))) { + snprintf(buf, BUFLEN, "%s^n\n", f->text); + strncat(retbuf, buf, BUFLEN); + } + } + } } if (nretflags) { strcat(retbuf, "\n"); @@ -4724,27 +4752,47 @@ char *makedesc_ob(object_t *o, char *retbuf) { // 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); - if (strlen(buf)) { - snprintf(buf2, BUFLEN, "and has an Armour Rating of %d",thisar); - strcat(buf, buf2); - } else { - snprintf(buf, BUFLEN, "It has an Armour Rating of %d",thisar); - } + snprintf(buf, BUFLEN, "It has an Armour Rating of %d",thisar); } else { thisar = 0; - if (strlen(buf)) { - snprintf(buf2, BUFLEN, "and provides no protection"); - strcat(buf, buf2); - } + snprintf(buf, BUFLEN, "It provides no protection"); } if (strlen(buf) && compareob) { int diff,comparear = 0; @@ -5453,6 +5501,25 @@ char *makedesc_ob(object_t *o, char *retbuf) { } } + rec = findrecipefor(o->type->id); + if (rec && canmakerecipe(player, rec)) { + sprintf(buf, "\nYour cooking skill will allow you to make this using these ingredients:\n"); + strncat(retbuf, buf, HUGEBUFLEN); + for (i = 0; i < rec->ningredients; i++) { + objecttype_t *inot; + int incount,inconsume; + inot = findot(rec->ingredient[i]); + incount = rec->count[i]; + inconsume = rec->consume[i]; + sprintf(buf, " - %d x %s", incount, inot->name); + if (!inconsume) { + strcat(buf, " (not consumed)"); + } + strcat(buf, "\n"); + strncat(retbuf, buf, HUGEBUFLEN); + } + } + return retbuf; } @@ -5528,12 +5595,22 @@ char *makedesc_spell(objecttype_t *ot, char *retbuf) { snprintf(buf, BUFLEN, "%s\n", ot->desc); strncat(retbuf, buf, BUFLEN); + // extra spell/abil descriptions getflags(ot->flags, retflag, &nretflags, F_EXTRADESC, F_NONE); - for (i = 0; i < nretflags; i++) { - f = retflag[i]; - snprintf(buf, BUFLEN, "%s^n\n", f->text); - strncat(retbuf, buf, BUFLEN); + if (nretflags) { + int order; + for (order = 0; order < 5; order++) { + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if ((f->val[0] == order) || + ((f->val[0] == NA) && (order == 0))) { + snprintf(buf, BUFLEN, "%s^n\n", f->text); + strncat(retbuf, buf, BUFLEN); + } + } + } } + if (nretflags) { strcat(retbuf, "\n"); } @@ -9757,10 +9834,14 @@ void showlfstats(lifeform_t *lf, int showall) { slev = getskill(lf, sk->id); if (!dounknown && (slev != PR_INEPT)) { + char endbit[BUFLEN]; + char basecolour = 'n'; + if (ismaxedskill(lf, sk->id)) { + basecolour = 'h'; + } // known skill - sprintf(thisline, "^%c%-21s^n[^%d", - ismaxedskill(lf, sk->id) ? 'h' : 'n', - sk->name, getskilllevelcolour(slev)); + sprintf(thisline, "^%c%-21s^%c[^%d", basecolour, sk->name, basecolour, + getskilllevelcolour(slev)); for (i = PR_NOVICE; i <= PR_MASTER; i++) { char toadd[BUFLEN]; @@ -9782,7 +9863,8 @@ void showlfstats(lifeform_t *lf, int showall) { break; } } - strcat(thisline, "]^n"); + sprintf(endbit, "^%c]^n",basecolour); + strcat(thisline, endbit); wmove(mainwin, y, 0); textwithcol(mainwin, thisline); printed = B_TRUE; @@ -9790,7 +9872,6 @@ void showlfstats(lifeform_t *lf, int showall) { // learnable skill setcol(mainwin, C_RED); mvwprintw(mainwin, y, 0, "%-21s", sk->name, " " ); - unsetcol(mainwin, C_RED); wprintw(mainwin, "["); for (i = PR_NOVICE; i < PR_MASTER+1; i++) { wprintw(mainwin, " "); @@ -10606,6 +10687,12 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } + f = lfhasflag(lf, F_STENCH); + if (f && (f->known)) { + mvwprintw(mainwin, y, 0, "%s %s emitting a foul stench, nauseating those nearby.", you(lf), is(lf)); + y++; + } + f = lfhasflag(lf, F_STUNNED); if (f && (f->known)) { mvwprintw(mainwin, y, 0, "%s %s stunned and cannot attack, cast spells or use abilities.", you(lf), is(lf)); diff --git a/lf.c b/lf.c index 0ea5ea4..9b5e639 100644 --- a/lf.c +++ b/lf.c @@ -590,6 +590,20 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { return castable; } +int cancook(lifeform_t *lf, recipe_t *rec, enum ERROR *reason) { + // skill high enough? + if (!canmakerecipe(lf, rec)) { + if (reason) *reason = E_TOOHARD; + return B_FALSE; + } + // do we have the ingredients? + if (getingredients(lf->pack, rec, NULL, NULL, NULL, NULL, B_FALSE)) { + if (reason) *reason = E_NOOB; + return B_FALSE; + } + return B_TRUE; +} + int canclimb(lifeform_t *lf, enum ERROR *reason) { cell_t *cc; cc = getcellindir(lf->cell, lf->facing); @@ -799,6 +813,13 @@ int canlearn(lifeform_t *lf, enum SKILL skid) { return B_FALSE; } +int canmakerecipe(lifeform_t *lf, recipe_t *rec) { + if (getskill(lf, SK_COOKING) >= rec->ningredients) { + return B_TRUE; + } + return B_FALSE; +} + int canopendoors(lifeform_t *lf) { if (lf) { if (!lfhasflag(lf, F_HUMANOID)) { @@ -1008,6 +1029,12 @@ int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos) { } } + /* + if (areallies(player, viewee) && !isplayer(viewee) && canhear(player, viewee->cell, 3)) { + return B_TRUE; + } + */ + if (uselos) { // no line of sight? if (!haslos(viewer, viewee->cell)) { @@ -1078,11 +1105,10 @@ int canuseweapons(lifeform_t *lf) { // where == BP_NONE means "can i wear it anywhere?' int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { - int i; - object_t *oo; - flag_t *f; - flag_t *retflag[MAXCANDIDATES]; - int nretflags; + int i,nretflags,nparts = 0; + //object_t *oo; + flag_t *f, *retflag[MAXCANDIDATES]; + enum BODYPART possbp[MAXBODYPARTS]; reason = E_OK; if (where != BP_NONE) { @@ -1132,49 +1158,69 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { } } } - - if (where == BP_NONE) { - // can we wear it ANYWHERE? - enum BODYPART possbp[MAXBODYPARTS]; - int nparts = 0; - int i; - getflags(o->flags, retflag, &nretflags, F_GOESON, F_NONE); - for (i = 0; i < nretflags; i++) { - f = retflag[i]; - if (f->id == F_GOESON) { - possbp[nparts] = f->val[0]; - nparts++; - } - } - if (nparts == 0) { - // can't wear anywhere! - reason = E_IMPOSSIBLE; - return B_FALSE; + // can we wear it ANYWHERE? + getflags(o->flags, retflag, &nretflags, F_GOESON, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (f->id == F_GOESON) { + possbp[nparts] = f->val[0]; + nparts++; } + } - // are any of these body parts free? - for (i = 0; i < nparts; i++) { - if (isfreebp(lf, possbp[i])) { - return B_TRUE; - } - } - // no parts free - reason = E_WEARINGSOMETHINGELSE; + if (nparts == 0) { + // can't wear anywhere! + reason = E_IMPOSSIBLE; return B_FALSE; + } - } else { - // does this object go there? - f = hasflagval(o->flags, F_GOESON, where, NA, NA, NULL); - if (!f) { + if (where != BP_NONE) { + int found = B_FALSE; + // is one of the possible locations the one we are checking? + for (i = 0; i < nparts; i++) { + if (possbp[i] == where) { + found = B_TRUE; + } + } + if (!found) { // can't wear there! reason = E_IMPOSSIBLE; return B_FALSE; } + // is the GIVEN part free? + if (!isfreebp(lf, where)) { + reason = E_WEARINGSOMETHINGELSE; + return B_FALSE; + } + } else { + if (hasflag(o->flags, F_GOESONMULTI)) { + // are ALL of these body parts free? + for (i = 0; i < nparts; i++) { + if (!isfreebp(lf, possbp[i])) { + reason = E_WEARINGSOMETHINGELSE; + return B_FALSE; + } + } + return B_TRUE; + } else { + int ok = B_FALSE; + // are ANY of these body parts free? + for (i = 0; i < nparts; i++) { + if (isfreebp(lf, possbp[i])) { + ok = B_TRUE; + break; + } + } + // no parts free + if (!ok) { + reason = E_WEARINGSOMETHINGELSE; + return B_FALSE; + } + } } - - + /* // anything else worn there? for (oo = lf->pack->first ; oo ; oo = oo->next) { f = hasflagval(oo->flags, F_EQUIPPED, where, -1, -1, NULL); @@ -1183,8 +1229,7 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { return B_FALSE; } } - - + */ return B_TRUE; } @@ -1307,6 +1352,19 @@ int cantakeoff(lifeform_t *lf, object_t *o) { return B_TRUE; } +int cantalk(lifeform_t *lf) { + switch (lf->race->raceclass->id) { + case RC_DEMON: + case RC_DRAGON: + case RC_GOD: + case RC_HUMANOID: + return B_TRUE; + default: + break; + } + return B_FALSE; +} + int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell, object_t *fromob, int *seen) { int rv; int needtovalidate = B_FALSE; @@ -1477,7 +1535,10 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar getlfname(lf, lfname); // special case - f = lfhasflag(lf, F_SPELLCASTTEXT); + f = lfhasflagval(lf, F_SPELLCASTTEXT, sid, NA, NA, NULL); // specific text for this spell + if (!f) { + f = lfhasflag(lf, F_SPELLCASTTEXT); // generic spellcast + } if (f) { if (strlen(f->text)) { snprintf(whattosay, BUFLEN, "%s %s", lfname, f->text); @@ -3040,12 +3101,33 @@ int eat(lifeform_t *lf, object_t *o) { } if (fullyeaten) { - // special cases only when eaten switch (o->type->id) { + case OT_BREADGARLIC: + addtempflag(lf->flags, F_STENCH, 2, NA, NA, NULL, rnd(30,50)); + break; + case OT_CAKEFRUIT: + setstamina(lf, getmaxstamina(lf)); + gainhp(lf, lf->maxhp); + gainmp(lf, getmaxmp(lf)); + break; case OT_CHOCOLATE: setstamina(lf, getmaxstamina(lf)); break; + case OT_HOTDOG: + addtempflag(lf->flags, F_ATTRMOD, A_STR, 3, NA, NULL, rnd(30,50)); + break; + case OT_RUMBALL: + killflagsofid(lf->flags, F_PAIN); + gainhp(lf, rnd(2,6)); + break; + case OT_SANDWICHCHEESE: + setstamina(lf, getmaxstamina(lf)); + break; + case OT_SANDWICHPB: + setstamina(lf, getmaxstamina(lf)); + addtempflag(lf->flags, F_ATTRMOD, A_CON, 3, NA, NULL, rnd(30,50)); + break; default: break; } @@ -3073,12 +3155,16 @@ void endlfturn(lifeform_t *lf) { // lf will complain if in pain if (isbleeding(lf) && onein(3)) { // TODO: replace 4 - if (ispetof(lf, player) && !canhear(player, lf->cell, 4)) { - char realname[BUFLEN]; - real_getlfname(lf, realname, B_FALSE); - warn("You feel worried about your %s.", noprefix(realname)); - } else { - makenoise(lf, N_LOWHP); + if (ispetof(lf, player)) { + if (!canhear(player, lf->cell, 4)) { + char realname[BUFLEN]; + real_getlfname(lf, realname, B_FALSE); + warn("You feel worried about your %s.", noprefix(realname)); + } else if (cantalk(lf)) { + sayphrase(lf, SP_ALLY_INPAIN, SV_SHOUT, NA, NULL); + } else { + makenoise(lf, N_LOWHP); + } } if (ispetof(lf, player)) { more(); @@ -4495,13 +4581,14 @@ void getwhowillfollow(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, i cell_t *c; c = getcellat(lf->cell->map, x, y); if (c && c->lf && (c->lf != lf)) { - if (!isimmobile(c->lf) && cansee(c->lf, lf)) { + if (!isimmobile(c->lf)) { int ok = B_FALSE; - if (areallies(lf, c->lf) && haslof(c->lf->cell, lf->cell, LOF_WALLSTOP, NULL)) { - // ally with a clear path to you + if (areallies(lf, c->lf) && haslof(c->lf->cell, lf->cell, LOF_NEED, NULL)) { + // ally with a clear path to you (even if they can't see you, we assume + // that you would tell them where you are going) ok = B_TRUE; - } else if (areenemies(lf, c->lf) && (getcelldist(c, lf->cell) == 1)) { - // adjacent enemy + } else if (areenemies(lf, c->lf) && (getcelldist(c, lf->cell) == 1) && cansee(lf, c->lf)) { + // adjacent enemy who can see you ok = B_TRUE; } @@ -4664,6 +4751,7 @@ int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, int *narms for (o = lf->pack->first ; o ; o = o->next) { flag_t *eqflag; + // note: for obs equipped in multiples places, only the first is used. eqflag = hasflag(o->flags, F_EQUIPPED); if (eqflag) { f = hasflag(o->flags, F_ARMOURRATING); @@ -6835,10 +6923,7 @@ race_t *getrandomrace(cell_t *c, int forcedepth) { gethitdicerange(depth, &hdmin, &hdmax, RARITYVARIANCELF, B_TRUE); // pick rr... - wantrr = RR_COMMON; - while ((wantrr < RR_VERYRARE) && onein(3)) { - wantrr++; - } + wantrr = pickrr(TT_MONSTER); if (db) dblog("finding random lf with hitdice %d-%d and rr <= %d\n",hdmin,hdmax, wantrr); @@ -8050,35 +8135,29 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { } if (nposs) { objecttype_t *ot = NULL; - if (isplayer(lf)) { - char ch = 'a'; + char ch = 'a'; - // note: we use getplayername here even if this isn't a player, - // since in that case the prompt will never be displayed. - getplayernamefull(buf2); - snprintf(buf, BUFLEN, "%s, select your starting weapon:", buf2); - initprompt(&prompt, buf); + // note: we use getplayername here even if this isn't a player, + // since in that case the prompt will never be displayed. + getplayernamefull(buf2); + snprintf(buf, BUFLEN, "%s, select your starting weapon:", buf2); + initprompt(&prompt, buf); - for (i = 0; i < nposs; i++) { - addchoice(&prompt, ch++, poss[i]->name, NULL, poss[i], NULL); - } - - if (prompt.nchoices == 1) { - ot = (objecttype_t *)prompt.choice[0].data; - } else if (prompt.nchoices) { - if (isplayer(lf)) { - getchoice(&prompt); - ot = (objecttype_t *)prompt.result; - } else { - ot = (objecttype_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data; - } - } - } else { - // not player - pick randomly. - i = rnd(0,nposs-1); - ot = poss[i]; + for (i = 0; i < nposs; i++) { + addchoice(&prompt, ch++, poss[i]->name, NULL, poss[i], NULL); } + if (prompt.nchoices == 1) { + ot = (objecttype_t *)prompt.choice[0].data; + } else if (prompt.nchoices) { + if (isplayer(lf)) { + getchoice(&prompt); + ot = (objecttype_t *)prompt.result; + } else { + ot = (objecttype_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data; + } + } + if (ot) { skill_t *sk; object_t *o; @@ -8162,16 +8241,24 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { } // if (getrandomobofsize(targmap, buf, maxobsize)) { - if (real_getrandomob(targmap, buf, RO_HOLDABLE, NA, targmap->depth + depthmod, NA, maxobsize)) { + if (real_getrandomob(targmap, buf, targmap->depth + depthmod, NA, maxobsize, B_TRUE, OC_NONE, DT_NONE)) { o = addob(op, buf); } } } else if (id == F_STARTOBDT) { if (rnd(1,100) <= val[0]) { + int depthmod; if (db) { snprintf(buf2, BUFLEN, "calling startobdt"); } - if ( real_getrandomob(targmap, buf, RO_DAMTYPE, val[1], NA, NA, maxobsize)) { + + depthmod = val[1]; + switch (depthmod) { + case NA: depthmod = 0; break; + case RANDOM: depthmod = rnd(0,MAXDEPTH); break; + default: break; + } + if (real_getrandomob(targmap, buf, targmap->depth + depthmod, NA, maxobsize, B_TRUE, OC_NONE, val[1], DT_NONE)) { if (db) snprintf(buf2, BUFLEN, "finished startobdt successfuly."); o = addob(op, buf); } else { @@ -8186,7 +8273,8 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { } //obdb = B_TRUE; //if (getrandomobwithclass(targmap, val[1], buf, val[2])) { - if (real_getrandomob(targmap, buf, RO_OBCLASS, val[1], getmapdifficulty(targmap) + val[2], NA, maxobsize)) { + if (real_getrandomob(targmap, buf, getmapdifficulty(targmap) + val[2], NA, maxobsize, B_TRUE, + val[1], OC_NONE, DT_NONE)) { if (db) snprintf(buf2, BUFLEN, "finished startobclass, success."); o = addob(op, buf); } else { @@ -8273,6 +8361,11 @@ void givestartskills(lifeform_t *lf, flagpile_t *fp) { } // now remove startskill flags so we don't get them again! killflagsofid(fp, F_STARTSKILL); + + // all races know about their own race + if (getlorelevel(lf, lf->race->raceclass->id) < PR_NOVICE) { + giveskilllev(lf, lf->race->raceclass->skill, PR_NOVICE); + } } int gotosleep(lifeform_t *lf, int onpurpose) { @@ -8306,6 +8399,7 @@ int hasfreeaction(lifeform_t *lf) { if (isimmobile(lf)) return B_FALSE; if (lfhasflag(lf, F_CASTINGSPELL)) return B_FALSE; if (lfhasflag(lf, F_EATING)) return B_FALSE; + if (lfhasflag(lf, F_ASLEEP)) return B_FALSE; return B_TRUE; } @@ -9014,6 +9108,8 @@ int haslos(lifeform_t *viewer, cell_t *dest) { if (!viewer->cell) return B_FALSE; if (viewer->cell->map != dest->map) return B_FALSE; + if (gamemode < GM_GAMESTARTED) return B_FALSE; + // can't see when you're dead UNLESS you are the player. this is // to prevent the screen from going black when "You die" appears. //if (isdead(viewer) && !isplayer(viewer)) return B_FALSE; @@ -10743,6 +10839,7 @@ int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, ch return losehp_real(lf, amt, damtype, fromlf, damsrc, B_TRUE, NULL, B_TRUE); } +// returns the amt of damage taken int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate) { char buf[BUFLEN]; char buf2[BUFLEN]; @@ -12644,6 +12741,43 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t int i,rv = B_FALSE; char buf[BUFLEN]; switch (what) { + case SP_ALLY_ATTACK: + if (cansee(player, lf)) { + switch (rnd(1,3)) { + case 1: snprintf(buf, BUFLEN, "I'm attacking %s!", text); break; + case 2: snprintf(buf, BUFLEN, "%s is mine!", text); break; + case 3: snprintf(buf, BUFLEN, "I'll take care of %s!", text); break; + } + } else { + char *p; + p = strdup(text); + strrep(p, "the ","a ", NULL); + switch (rnd(1,3)) { + case 1: snprintf(buf, BUFLEN, "There's %s over here!", p); break; + case 2: snprintf(buf, BUFLEN, "I'm attacking %s!", p); break; + case 3: snprintf(buf, BUFLEN, "Beware %s!", p); break; + } + free(p); + } + rv = say(lf, buf, volume); + break; + case SP_ALLY_INPAIN: + switch (rnd(1,3)) { + case 1: snprintf(buf, BUFLEN, "I'm hurting here!"); break; + case 2: snprintf(buf, BUFLEN, "I need to rest soon!"); break; + case 3: snprintf(buf, BUFLEN, "Help me!"); break; + } + rv = say(lf, buf, volume); + break; + case SP_ALLY_TARGETKILL: + switch (rnd(1,4)) { + case 1: snprintf(buf, BUFLEN, "Got it!"); break; + case 2: snprintf(buf, BUFLEN, "%s one, %s zero!", lf->race->name, noprefix(text)); break; + case 3: snprintf(buf, BUFLEN, "Pow!"); break; + case 4: snprintf(buf, BUFLEN, "Take that!"); break; + } + rv = say(lf, buf, volume); + break; case SP_BEG: switch (rnd(1,3)) { case 1: snprintf(buf, BUFLEN, "Spare a coin, mister?"); break; @@ -12784,15 +12918,19 @@ int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus) { if (lfhasflag(lf, F_HUMANOID)) { object_t *o; for (o = scarer->pack->first ; o; o = o->next) { - flag_t *f; - f = isequipped(o); - // ie. equipped, but not primary or secondary weapon - if (f && (f->val[0] > BP_SECWEAPON)) { - f = hasflag(o->flags, F_SCARY); - if (f) { - scarerbonus += f->val[0]; + flag_t *scareflag; + scareflag = hasflag(o->flags, F_SCARY); + if (scareflag) { + flag_t *retflag[MAXCANDIDATES]; + int nretflags; + getflags(o->flags, retflag, &nretflags, F_EQUIPPED, F_NONE); + for (i = 0; i < nretflags; i++) { + // ie. equipped, but not primary or secondary weapon + if (retflag[i] && (retflag[i]->val[0] > BP_SECWEAPON)) { + scarerbonus += scareflag->val[0]; + } } - } + } } } @@ -13809,8 +13947,10 @@ void startlfturn(lifeform_t *lf) { } } + // oooooo replace with f_bleeding ? if (lfhasflagval(lf, F_INJURY, IJ_ARTERYPIERCE, NA, NA, NULL)) { if (!bleedfrom(lf, BP_HANDS, B_SPLATTER)) { + if (isplayer(lf)) msg("^BYou bleed!"); losehp(lf, rnd(1,8), DT_DIRECT, NULL, "blood loss"); } } @@ -13965,8 +14105,7 @@ void startlfturn(lifeform_t *lf) { for (o = lf->pack->first ; o ; o = nexto) { nexto = o->next; if (ismetal(o->material->id)) { - f = isequipped(o); - if (f && ((f->val[0] == BP_WEAPON) || (f->val[0] == BP_SECWEAPON))) { + if (isequippedon(o, BP_WEAPON) || isequippedon(o, BP_SECWEAPON)) { cell_t *c; // weapon flies away c = getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND); @@ -14866,8 +15005,7 @@ int takeoff(lifeform_t *lf, object_t *o) { } // remove the equipped flag - f = hasflag(o->flags, F_EQUIPPED); - killflag(f); + killflagsofid(o->flags, F_EQUIPPED); taketime(lf, getactspeed(lf)); if ((gamemode == GM_GAMESTARTED)) { @@ -15894,7 +16032,7 @@ int rest(lifeform_t *lf, int onpurpose) { mpheal = 1; } - if (onpurpose) { + if (onpurpose || !isplayer(lf)) { f = lfhasflag(lf, F_RESTCOUNT); if (!f) { f = addflag(lf->flags, F_RESTCOUNT, 0, NA, NA, NULL); @@ -15924,8 +16062,8 @@ int rest(lifeform_t *lf, int onpurpose) { // ie. for hp, at con <= 4 and no first aid skill, you NEVER Heal! difficulty = 25; } else { - // ai passes more easily - difficulty = 10; + // ai passes very easily + difficulty = 5; } // modify difficulty if you're resting properly via 'R' @@ -15939,7 +16077,7 @@ int rest(lifeform_t *lf, int onpurpose) { } //if (isplayer(lf)) msg("hp given."); - if (isplayer(lf) && (lf->hp < lf->maxhp)) { + if (lf->hp < lf->maxhp) { // pass a skill check to regain hp if (skillcheck(lf, SC_CON, difficulty, getskill(lf, SK_FIRSTAID))) { gainhp(lf, hpheal); @@ -16025,6 +16163,12 @@ int rest(lifeform_t *lf, int onpurpose) { wantclearmsg = B_FALSE; } } + // allies should wake up once healed + if (areallies(player, lf) && !isplayer(lf)) { + if ((lf->hp >= lf->maxhp) && (lf->mp >= getmaxmp(lf))) { + killflagsofid(lf->flags, F_ASLEEP); + } + } } // end if !poisoned if (statdirty || needredraw) { @@ -16045,7 +16189,7 @@ int wear(lifeform_t *lf, object_t *o) { char buf[BUFLEN],obname[BUFLEN]; flag_t *f; enum BODYPART possbp[MAXBODYPARTS]; - int nparts = 0; + int nparts = 0,ncheckparts = 0; enum BODYPART bp; flag_t *retflag[MAXCANDIDATES]; int nretflags; @@ -16097,77 +16241,96 @@ int wear(lifeform_t *lf, object_t *o) { } return B_TRUE; } else if (nparts == 1) { - bp = possbp[0]; + // go on the only needed body part + ncheckparts = nparts; } else { // multiple possible locations int i; showpos = B_TRUE; - // rings go in first possible place - if (o->type->obclass->id == OC_RING) { - bp = BP_NONE; - for (i = 0; i < nparts; i++) { - if (!hasobwithflagval(lf->pack, F_EQUIPPED, possbp[i], NA, NA, NULL)) { - bp = possbp[i]; - break; - } - } - - if ((bp == BP_NONE) && isplayer(lf)) msg("You have no room to wear that."); + + if (hasflag(o->flags, F_GOESONMULTI)) { + // goes on ALL of the parts + ncheckparts = nparts; } else { - char ch = 'a'; - // ask where to put it - snprintf(buf, BUFLEN, "Where will you wear %s?",obname); - initprompt(&prompt, buf); - for (i = 0; i < nparts; i++) { - object_t *inway; - inway = getequippedob(lf->pack, possbp[i]); - if (inway) { - char inwayname[BUFLEN]; - getobname(inway, inwayname, inway->amt); - snprintf(buf, BUFLEN, "%s (replace %s)", getbodypartname(lf, possbp[i]), inwayname); - } else { - snprintf(buf, BUFLEN, "%s", getbodypartname(lf, possbp[i])); - } - addchoice(&prompt, ch++, buf, NULL, &possbp[i], NULL); - } - addchoice(&prompt, '-', "(cancel)", NULL, NULL, NULL); - ch = getchoice(&prompt); - - if (ch == '-') { + // rings go in first possible place + if (o->type->obclass->id == OC_RING) { bp = BP_NONE; + for (i = 0; i < nparts; i++) { + if (isfreebp(lf, possbp[i])) { + bp = possbp[i]; + break; + } + } + + if (bp == BP_NONE) { + if (isplayer(lf)) msg("You have no room to wear that."); + return B_TRUE; + } + possbp[0] = bp; + nparts = 1; + ncheckparts = nparts; + + } else { + char ch = 'a'; + // ask where to put it + snprintf(buf, BUFLEN, "Where will you wear %s?",obname); + initprompt(&prompt, buf); + for (i = 0; i < nparts; i++) { + object_t *inway; + inway = getequippedob(lf->pack, possbp[i]); + if (inway) { + char inwayname[BUFLEN]; + getobname(inway, inwayname, inway->amt); + snprintf(buf, BUFLEN, "%s (replace %s)", getbodypartname(lf, possbp[i]), inwayname); + } else { + snprintf(buf, BUFLEN, "%s", getbodypartname(lf, possbp[i])); + } + addchoice(&prompt, ch++, buf, NULL, &possbp[i], NULL); + } + addchoice(&prompt, '-', "(cancel)", NULL, NULL, NULL); - if (isplayer(lf)) msg("Cancelled."); - } else bp = *((enum BODYPART *)prompt.result); - } - if (bp == BP_NONE) { - if (isplayer(lf)) { - msg("You have no room to wear that."); + if (prompt.nchoices == 1) { + if (isplayer(lf)) msg("You have nowhere to wear that!"); + return B_TRUE; + } + ch = getchoice(&prompt); + + if (ch == '-') { + bp = BP_NONE; + if (isplayer(lf)) msg("Cancelled."); + return B_TRUE; + } else bp = *((enum BODYPART *)prompt.result); + + possbp[0] = bp; + nparts = 1; + ncheckparts = nparts; + } - return B_TRUE; } //} } - while (!canwear(lf, o, bp)) { - int errresolved = B_FALSE; - if ((gamemode == GM_GAMESTARTED) && lf->created) { - switch (reason) { - case E_ALREADYUSING: - if (isplayer(lf)) msg("You're already wearing that!"); - break; - case E_DOESNTFIT: - if (isplayer(lf)) msg("The unnatural shape of your %s prevents this from fitting.", getbodypartname(lf, bp)); - break; - case E_INJURED: - if (isplayer(lf)) msg("Your injuries prevent you from wearing this."); - break; - case E_WEARINGSOMETHINGELSE: - f = hasflag(o->flags, F_GOESON); - if (f) { - object_t *inway; + // make sure all required parts are free... + for (i = 0; i < ncheckparts; i++) { + bp = possbp[i]; + while (!canwear(lf, o, bp)) { + object_t *inway = NULL; + int errresolved = B_FALSE; + if ((gamemode == GM_GAMESTARTED) && lf->created) { + switch (reason) { + case E_ALREADYUSING: + if (isplayer(lf)) msg("You're already wearing that!"); + break; + case E_DOESNTFIT: + if (isplayer(lf)) msg("The unnatural shape of your %s prevents this from fitting.", getbodypartname(lf, bp)); + break; + case E_INJURED: + if (isplayer(lf)) msg("Your injuries prevent you from wearing this."); + break; + case E_WEARINGSOMETHINGELSE: // find what else is there - inway = getequippedob(lf->pack, f->val[0]); + inway = getequippedob(lf->pack, bp); getobname(inway,buf, 1); if (isplayer(lf)) { int ch = '\0'; @@ -16202,47 +16365,44 @@ int wear(lifeform_t *lf, object_t *o) { } } } - } else { - // should never happen - if (isplayer(lf)) msg("You can't wear that!"); - } - break; - case E_NOTKNOWN: - if (isplayer(lf)) msg("You can't wear that!"); // same message as wearing non-armour - break; - case E_NOBP: - if (isplayer(lf)) msg("You have no %s on which to wear that!", getbodypartname(lf, bp)); - break; - case E_LOWCHA: - msg("You are not attractive enough to wear this."); - break; - case E_LOWCON: - msg("You are not healthy enough to wear this."); - break; - case E_LOWDEX: - msg("You are not dextrous enough to wear this."); - break; - case E_LOWIQ: - msg("You are not smart enough to wear this."); - break; - case E_LOWSTR: - msg("You are not strong enough to wear this."); - break; - case E_LOWWIS: - msg("You are not wise enough to wear this."); - break; - default: - if (isplayer(lf)) { - msg("You can't wear that!"); - } - break; + break; + case E_NOTKNOWN: + if (isplayer(lf)) msg("You can't wear that!"); // same message as wearing non-armour + break; + case E_NOBP: + if (isplayer(lf)) msg("You have no %s on which to wear that!", getbodypartname(lf, bp)); + break; + case E_LOWCHA: + msg("You are not attractive enough to wear this."); + break; + case E_LOWCON: + msg("You are not healthy enough to wear this."); + break; + case E_LOWDEX: + msg("You are not dextrous enough to wear this."); + break; + case E_LOWIQ: + msg("You are not smart enough to wear this."); + break; + case E_LOWSTR: + msg("You are not strong enough to wear this."); + break; + case E_LOWWIS: + msg("You are not wise enough to wear this."); + break; + default: + if (isplayer(lf)) { + msg("You can't wear that!"); + } + break; + } + } // end if gamestarted + if (!errresolved) { + return B_TRUE; } - } // end if gamestarted - if (!errresolved) { - return B_TRUE; - } - // if we DID resolve the error, loop around and check if we can wear again... - } // end while !canwear + // if we DID resolve the error, loop around and check if we can wear again... + } // end while !canwear + } // end for each required bodypart // some checks first... if (touch(lf, o)) { @@ -16260,7 +16420,9 @@ int wear(lifeform_t *lf, object_t *o) { //f = hasflag(o->flags, F_GOESON); //bp = f->val[0]; - addflag(o->flags, F_EQUIPPED, bp, -1, -1, NULL); + for (i = 0; i < ncheckparts; i++) { + addflag(o->flags, F_EQUIPPED, possbp[i], -1, -1, NULL); + } taketime(lf, getactspeed(lf)); if (isplayer(lf)) maketried(o->type->id); @@ -16278,7 +16440,9 @@ int wear(lifeform_t *lf, object_t *o) { if ((gamemode == GM_GAMESTARTED) && lf->created) { if (isplayer(lf)) { if (showpos) { - msg("You are now wearing %s (%s your %s).", obname, getbodypartequipname(bp), getbodypartname(lf, bp)); + char posbuf[BUFLEN]; + makewearstring(lf, o, B_TRUE, posbuf ); + msg("You are now wearing %s (%s).", obname, posbuf); } else { msg("You are now wearing %s.", obname); } @@ -16575,7 +16739,7 @@ int weild(lifeform_t *lf, object_t *o) { taketime(lf, getactspeed(lf)); - if (isplayer(lf)) maketried(o->type->id); + if (isplayer(lf) && isweapon(o)) maketried(o->type->id); if ((gamemode == GM_GAMESTARTED) && lf->created && (lf->race->id != R_DANCINGWEAPON)) { if (isplayer(lf)) { diff --git a/lf.h b/lf.h index 3b62826..24a3159 100644 --- a/lf.h +++ b/lf.h @@ -31,11 +31,13 @@ int calcxprace(enum RACE rid); void callguards(lifeform_t *caller, lifeform_t *victim); int canattack(lifeform_t *lf); int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost); +int cancook(lifeform_t *lf, recipe_t *rec, enum ERROR *reason); int canclimb(lifeform_t *lf, enum ERROR *reason); int candrink(lifeform_t *lf, object_t *o); int caneat(lifeform_t *lf, object_t *o); int canhear(lifeform_t *lf, cell_t *c, int volume); int canlearn(lifeform_t *lf, enum SKILL skid); +int canmakerecipe(lifeform_t *lf, recipe_t *rec); int canopendoors(lifeform_t *lf); int canpickup(lifeform_t *lf, object_t *o, int amt); int canpolymorphto(enum RACE rid); @@ -49,6 +51,7 @@ int canuseweapons(lifeform_t *lf); int canwear(lifeform_t *lf, object_t *o, enum BODYPART where); int canweild(lifeform_t *lf, object_t *o); int cantakeoff(lifeform_t *lf, object_t *o); +int cantalk(lifeform_t *lf); int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell, object_t *fromob, int *seen); int celllitfor(lifeform_t *lf, cell_t *c, int maxvisrange, int nightvisrange); int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod); diff --git a/map.c b/map.c index f6c36dc..98e394b 100644 --- a/map.c +++ b/map.c @@ -465,7 +465,7 @@ object_t *addrandomob(cell_t *c) { return NULL; } - if (real_getrandomob(c->map, buf, RO_NONE, NA, NA, c->habitat->id, SZ_MAX)) { + if (real_getrandomob(c->map, buf, NA, c->habitat->id, SZ_MAX, B_FALSE, OC_NONE, DT_NONE)) { if (db) dblog("adding rand obj %s to cell %d,%d",buf,c->x,c->y); o = addob(c->obpile, buf); } @@ -4852,6 +4852,16 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { int i; // handle scanner if (c->lf) { + if (areallies(player, c->lf) && !isplayer(c->lf) && canhear(player, c, SV_SHOUT)) { + // assume that allies will keep in contact with the player, as long + // as they're not asleep + if (!lfhasflag(c->lf, F_ASLEEP)) { + set_scanned_glyph(TT_MONSTER, c->lf, " (heard ally)", desc, glyph); + *thing = c->lf; + return TT_MONSTER; + } + } + f = lfhasflag(player, F_DETECTLIFE); if (f) { if (getcelldistorth(player->cell, c) <= f->val[0]) { diff --git a/nexus.c b/nexus.c index ac6fe5b..fadbff7 100644 --- a/nexus.c +++ b/nexus.c @@ -30,6 +30,7 @@ celltype_t *firstcelltype = NULL,*lastcelltype = NULL; command_t *firstcommand = NULL,*lastcommand = NULL; race_t *firstrace = NULL,*lastrace = NULL; raceclass_t *firstraceclass = NULL,*lastraceclass = NULL; +recipe_t *firstrecipe = NULL,*lastrecipe = NULL; job_t *firstjob = NULL,*lastjob = NULL; skill_t *firstskill = NULL,*lastskill = NULL; habitat_t *firsthabitat = NULL,*lasthabitat = NULL; diff --git a/objects.c b/objects.c index 5a76b0c..72d02f2 100644 --- a/objects.c +++ b/objects.c @@ -24,6 +24,7 @@ extern objectclass_t *objectclass,*lastobjectclass; extern brand_t *firstbrand,*lastbrand; extern obmod_t *firstobmod,*lastobmod; extern material_t *material,*lastmaterial; +extern recipe_t *firstrecipe,*lastrecipe; extern skill_t *firstskill, *lastskill; void (*precalclos)(lifeform_t *); @@ -252,7 +253,7 @@ object_t *addemptyob(obpile_t *where, object_t *o) { // determine what kind of empty container to drop if (strstr(o->type->name, "vial")) { strcpy(buf, "empty vial"); - } else if (strstr(o->type->name, "potion")) { + } else if (strstr(o->type->name, "potion") || strstr(o->type->name, "flask")) { strcpy(buf, "empty flask"); } else { return NULL; @@ -360,7 +361,7 @@ material_t *addmaterial(enum MATERIAL id, char *name, float weightrating) { return a; } -objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph, int glyphcolour) { +objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph, int glyphcolour, enum RARITY rarity) { objectclass_t *a; // add to the end of the list @@ -386,6 +387,7 @@ objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph, int gl a->glyph.ch = glyph; a->glyph.colour = glyphcolour; a->flags = addflagpile(NULL, NULL); + a->rarity = rarity; return a; } @@ -1359,6 +1361,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes cf->val[1] = sizetonutrition(rf->val[0]) / 3; } } + } else if (o->type->id == OT_JERKY) { + if (!corpserace) { + corpserace = getrandomcorpserace(NULL); + } + addflag(o->flags, F_LINKRACE, corpserace->id, NA, NA, NULL); } else if (o->type->id == OT_ROASTMEAT) { flag_t *rf, *cf; @@ -1755,6 +1762,50 @@ objecttype_t *addot(enum OBTYPE id, char *name, char *description, int material, return a; } +// usage: addrecipe(result, [ ingred_id, ingred_count, ingred_willbeconsumed ], OT_NONE) +recipe_t *addrecipe(enum OBTYPE result, ...) { + recipe_t *a, *recipe_exists; + va_list ingreds; + enum OBTYPE thisob; + //flag_t *f; + + // does this ob already exist? + recipe_exists = findrecipefor(result); + assert(!recipe_exists); + + // add to the end of the list + if (firstrecipe == NULL) { + firstrecipe = malloc(sizeof(recipe_t)); + a = firstrecipe; + a->prev = NULL; + } else { + // go to end of list + a = lastrecipe; + a->next = malloc(sizeof(recipe_t)); + a->next->prev = a; + a = a->next; + } + lastrecipe = a; + a->next = NULL; + + // props + a->result = result; + va_start(ingreds, result); + a->ningredients = 0; + thisob = va_arg(ingreds, enum OBTYPE); + while (thisob != OT_NONE) { + a->ingredient[a->ningredients] = thisob; + a->count[a->ningredients] = va_arg(ingreds, int); + a->consume[a->ningredients] = va_arg(ingreds, int); + a->ningredients++; + assert(a->ningredients < MAXRECIPEINGREDIENTS); + thisob = va_arg(ingreds, enum OBTYPE); + } + va_end(ingreds); + + return a; +} + void adjustdamhardness(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat) { // now check for hardness @@ -2848,9 +2899,11 @@ objecttype_t *findotn(char *name) { modname = strrep(modname, "lumps ", "lump ", NULL); modname = strrep(modname, "pieces ", "piece ", NULL); modname = strrep(modname, "piles ", "pile ", NULL); + modname = strrep(modname, "pinches ", "pinch ", NULL); modname = strrep(modname, "pools ", "pool ", NULL); modname = strrep(modname, "potions ", "potion ", NULL); modname = strrep(modname, "puddles ", "puddle ", NULL); + modname = strrep(modname, "puffs ", "puff ", NULL); modname = strrep(modname, "rings ", "ring ", NULL); modname = strrep(modname, "scrolls ", "scroll ", NULL); modname = strrep(modname, "sets ", "set ", NULL); @@ -3034,6 +3087,14 @@ glyph_t *getglyph(object_t *o) { return &tempglyph; } +recipe_t *findrecipefor(enum OBTYPE result) { + recipe_t *r; + for (r = firstrecipe ; r ; r = r->next) { + if (r->result == result) return r; + } + return NULL; +} + void fragments(cell_t *centre, char *what, int speed, int howfar) { cell_t *c,*dst; int n; @@ -4106,10 +4167,15 @@ char *getobequipinfo(object_t *o, char *buf) { strcat(buf, " (in left hand)"); } } else { + char posbuf[BUFLEN]; strcat(buf, " ("); + makewearstring(o->pile->owner, o, B_FALSE, posbuf); + /* strcat(buf, getbodypartequipname(f->val[0])); strcat(buf, " "); strcat(buf, getbodypartname(o->pile->owner, f->val[0])); + */ + strcat(buf, posbuf); strcat(buf, ")"); } } @@ -4466,7 +4532,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan corpserace = findrace(f->val[0]); snprintf(basename, BUFLEN, "statue of a %s",corpserace->name); } - } else if ((o->type->id == OT_STEW) || (o->type->id == OT_JERKY)) { + } else if (o->type->id == OT_JERKY) { f = hasflag(o->flags, F_LINKRACE); if (f) { race_t *r; @@ -4916,26 +4982,67 @@ objecttype_t *getoppositestairs(objecttype_t *ot) { return findot(f->val[0]); } -char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth, int forcehabitat, enum LFSIZE maxsize) { +//char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth, int forcehabitat, enum LFSIZE maxsize) { +// varargs are: +// OC_CLASS1, OC_CLAS2, OC_NONE, ..., DT_DAMTYPE1, DT_DAMTYPE2, .., DT_NONE +char *real_getrandomob(map_t *map, char *buf, int forcedepth, int forcehabitat, enum LFSIZE maxsize, int forpickup, ... ) { + va_list args; objecttype_t *ot; objecttype_t *poss[MAXRANDOMOBCANDIDATES]; + + enum OBCLASS wantclass[MAXCANDIDATES]; + int nwantclass = 0; + enum DAMTYPE wantdt[MAXCANDIDATES]; + int nwantdt = 0; + int nposs = 0; int selidx; int amt; flag_t *f; int db = B_FALSE; + int partdb = B_TRUE; char *pluralname; char brandname[BUFLEN]; char cursestr[BUFLEN]; int raritymin,raritymax; - int depth; + int depth,i; int done = B_FALSE; obmod_t *om; flag_t *omposs[MAXCANDIDATES]; int noms = 0; enum RARITY wantrr = RR_COMMON; + habitat_t *hab; + char habname[BUFLEN]; - db = obdb; + if (!db) db = obdb; + + va_start(args, forpickup); + wantclass[nwantclass] = va_arg(args, enum OBCLASS); + while (wantclass[nwantclass] != OC_NONE) { + nwantclass++; + wantclass[nwantclass] = va_arg(args, enum OBCLASS); + } + + wantdt[nwantdt] = va_arg(args, enum DAMTYPE); + while (wantdt[nwantdt] != DT_NONE) { + nwantdt++; + wantdt[nwantdt] = va_arg(args, enum DAMTYPE); + } + va_end(args); + + if (forcehabitat != NA) { + hab = findhabitat(forcehabitat); + } else if (map) { + hab = map->habitat; + } else { + hab = NULL; + } + + if (hab) { + strcpy(habname, hab->name); + } else { + strcpy(habname, "(any)"); + } //if (forcedepth != NA) { if (forcedepth >= 0) { @@ -4947,26 +5054,44 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth getrarityrange(depth, &raritymin, &raritymax, RARITYVARIANCEOB, B_TRUE); // pick rr... - wantrr = RR_COMMON; - while ((wantrr < RR_VERYRARE) && onein(3)) { - wantrr++; + wantrr = pickrr(TT_OBJECT); + + // no obclass given? pick one randomly. + if (!nwantclass) { + wantclass[0] = getrandomobclass(); + nwantclass = 1; } while (!done) { - if (db) dblog("adding random object with rarity value between %d - %d and rr <= %d",raritymin,raritymax,wantrr); - if (db) { - objectclass_t *oc = NULL; - switch (cond) { - case RO_DAMTYPE: - dblog(" (must have damtype = %s)",getdamname(cval)); - break; - case RO_OBCLASS: - oc = findoc(cval); - dblog(" (must have obclass = %s)",oc->name); - break; - case RO_HOLDABLE: - dblog(" (must be holdable)",oc->name); - break; + if (db || partdb) dblog("adding random object with rarity value between %d - %d and rr <= %d, for habitat %s", + raritymin,raritymax,wantrr, habname); + if (db || partdb) { + char dbuf[BUFLEN]; + if (nwantclass) { + objectclass_t *oc = NULL; + sprintf(dbuf, " must have obclass: "); + for (i = 0; i < nwantclass; i++) { + oc = findoc(wantclass[i]); + strcat(dbuf, oc->name); + if (i != nwantclass - 1) strcat(dbuf, ","); + } + dblog("%s", dbuf); + } + if (nwantdt) { + sprintf(dbuf, " must have damtype: "); + for (i = 0; i < nwantdt; i++) { + char dname[BUFLEN]; + strcpy(dname, getdamname(wantdt[i])); + if (strstr(dname, "unknown")) { + assert("unknown wantdt in real_getrandomob()" == 0); + } + strcat(dbuf, dname); + if (i != nwantdt - 1) strcat(dbuf, ","); + } + dblog("%s", dbuf); + } + if (forpickup) { + dblog(" must be holdable"); } } @@ -4975,43 +5100,72 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth // fit in the map's habitat nposs = 0; for (ot = objecttype ; ot ; ot = ot->next) { - int rarok = B_FALSE, condok = B_FALSE; + int rarok = B_FALSE, condok = B_TRUE; flag_t *rarflag = NULL; - // correct rarity? + // correct rarity number? rarflag = hasflagval(ot->flags, F_RARITY, H_ALL, NA, NA, NULL); if (!rarflag) { - if (forcehabitat != NA) { - rarflag = hasflagval(ot->flags, F_RARITY, forcehabitat, NA, NA, NULL); - } else if (map) { - rarflag = hasflagval(ot->flags, F_RARITY, map->habitat->id, NA, NA, NULL); + if (hab) { + rarflag = hasflagval(ot->flags, F_RARITY, hab->id, NA, NA, NULL); } else { - rarflag = hasflagval(ot->flags, F_RARITY, NA, NA, NA, NULL); + rarflag = hasflag(ot->flags, F_RARITY); } } if (rarflag) { if ((rarflag->val[1] >= raritymin) && (rarflag->val[1] <= raritymax)) { - if ((rarflag->val[2] == NA) || (rarflag->val[2] <= wantrr)) { + enum RARITY thisrr; + thisrr = rarflag->val[2]; + if (thisrr == NA) thisrr = RR_COMMON; + + if (thisrr == wantrr) { rarok = B_TRUE; + } else { + if (db) dblog(" %s rarity(%d) doesn't match wantrr(%d)", ot->name, + rarflag->val[2], wantrr); } + } else { + if (db) dblog(" rarity of %s out of range (%d)", ot->name, rarflag->val[1]); } + } else { + if (db) dblog(" %s doesn't have rarity flag", ot->name); } if (rarok) { - // matches condition? - if (cond == RO_NONE) { - condok = B_TRUE; - } else if (cond == RO_DAMTYPE) { - if (hasflagval(ot->flags, F_DAM, cval, NA, NA, NULL)) { - condok = B_TRUE; + int found; + if (db) dblog(" %s passes rarity check.", ot->name); + // matches obclass? + if (nwantclass) { + found = B_FALSE; + for (i = 0; i < nwantclass; i++) { + if (ot->obclass->id == wantclass[i]) { + found = B_TRUE; + } } - } else if (cond == RO_OBCLASS) { - if (ot->obclass->id == cval) { - condok = B_TRUE; + if (!found) { + condok = B_FALSE; + if (db) dblog(" %s fails obclass check.", ot->name); } - } else if (cond == RO_HOLDABLE) { - if (!hasflag(ot->flags, F_NOPICKUP)) { - condok = B_TRUE; + } + // matches damtype? + if (nwantdt) { + found = B_FALSE; + for (i = 0; i < nwantdt; i++) { + if (hasflagval(ot->flags, F_DAM, wantdt[i], NA, NA, NULL)) { + found = B_TRUE; + break; + } + } + if (!found) { + condok = B_FALSE; + if (db) dblog(" %s fails damtype check.", ot->name); + } + } + + if (forpickup) { + if (hasflag(ot->flags, F_NOPICKUP)) { + condok = B_FALSE; + if (db) dblog(" %s not pickupable.", ot->name); } } } @@ -5028,23 +5182,32 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth if (nposs == 0) { // already at lowest rarity? if ((raritymax >= 100) && (raritymin <= 0)) { - // give up - strcpy(buf, ""); - if (db) dblog("no possible objects at all! giving up."); - return NULL; - } - - // expand range and try again - raritymax += 10; if (raritymax > 100) raritymax = 100; - raritymin -= 10; if (raritymin < 0) raritymin = 0; - if (db) dblog("no possible objects like this. trying again with rarity %d-%d\n",raritymin,raritymax); + // now lower wantrr + if (wantrr > RR_COMMON) { + if (db) dblog("rarity at min/max and no obs. lowering wantrr to %d.",wantrr); + wantrr--; + } else { + // give up + strcpy(buf, ""); + if (db || partdb) dblog("no possible random objects at all for habitat %s! giving up.", habname); + if (!hab) { + dblog("xxx"); + } + return NULL; + } + } else { + // expand range and try again + raritymax += 10; if (raritymax > 100) raritymax = 100; + raritymin -= 10; if (raritymin < 0) raritymin = 0; + if (db) dblog("no possible objects like this. trying again with rarity %d-%d\n",raritymin,raritymax); + } } else { // something found done = B_TRUE; } } // end while !done - if (db) dblog("got %d possibilities. now adjusting for RR_",nposs); + if (db) dblog("got %d possibilities.", nposs); // pick a random object from our possiblities selidx = rnd(0,nposs-1); @@ -5133,27 +5296,52 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth snprintf(buf, BUFLEN, "%d %s%s%s", amt, cursestr, pluralname,brandname); - if (db) dblog("random ob: %d x %s ('%s')", amt, ot->name,pluralname); + if (db || partdb) dblog("random ob for %s: %d x %s ('%s')", habname, amt, ot->name,pluralname); free(pluralname); return buf; } char *getrandomob(map_t *map, char *buf) { - return real_getrandomob(map, buf, RO_NONE, NA, NA, NA, SZ_MAX); + return real_getrandomob(map, buf, NA, NA, SZ_MAX, B_FALSE, OC_NONE, DT_NONE); } char *getrandomobofsize(map_t *map, char *buf, enum LFSIZE maxsize) { - return real_getrandomob(map, buf, RO_NONE, NA, NA, NA, maxsize); + return real_getrandomob(map, buf, NA, NA, maxsize, B_FALSE, OC_NONE, DT_NONE); } char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf) { - return real_getrandomob(map, buf, RO_DAMTYPE, damtype, NA, NA, SZ_MAX); + return real_getrandomob(map, buf, NA, NA, SZ_MAX, B_TRUE, OC_NONE, damtype, DT_NONE); } char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf, int depthmod) { //return real_getrandomob(map, buf, RO_OBCLASS, cid, map->depth + depthmod); if (depthmod == NA) depthmod = 0; - return real_getrandomob(map, buf, RO_OBCLASS, cid, getmapdifficulty(map) + depthmod, NA, SZ_MAX); + return real_getrandomob(map, buf, getmapdifficulty(map) + depthmod, NA, SZ_MAX, B_FALSE, cid, OC_NONE, DT_NONE); +} + +enum OBCLASS getrandomobclass(void) { + enum RARITY wantrr; + objectclass_t *oc,*poss[MAXCANDIDATES]; + int nposs = 0; + + wantrr = pickrr(TT_OBJECT); + while (!nposs) { + for (oc = objectclass ; oc ; oc = oc->next) { + if (oc->rarity == wantrr) { + poss[nposs++] = oc; + } + } + if (!nposs) { + if (wantrr > RR_COMMON) { + wantrr--; + } else { + // should never happen! + assert("getrandomobclass failed" == 0); + } + } + } + oc = poss[rnd(0,nposs-1)]; + return oc->id; } int getobrarity(object_t *o, enum RARITY *rr) { @@ -5847,13 +6035,9 @@ int isedible(object_t *o) { return B_FALSE; } -flag_t *isequipped(object_t *o) { - flag_t *f; - f = hasflag(o->flags, F_EQUIPPED); - if (f) { - return f; - } - return NULL; +int isequipped(object_t *o) { + if (hasflag(o->flags, F_EQUIPPED)) return B_TRUE; + return B_FALSE; } int isequippedon(object_t *o, enum BODYPART bp) { @@ -8083,6 +8267,24 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } +enum RARITY pickrr(int whatfor) { + enum RARITY wantrr = RR_COMMON; + int chance = 3; + + if ((gamemode == GM_GAMESTARTED) && hasflag(player->flags, F_EXTRALUCK)) { + if (whatfor == TT_OBJECT) { + chance = 2; + } else if (whatfor == TT_MONSTER) { + chance = 4; + } + } + // pick rr... + while ((wantrr < RR_VERYRARE) && onein(chance)) { + wantrr++; + } + return wantrr; +} + int pilehasletter(obpile_t *op, char let) { object_t *o; int found = B_FALSE; @@ -8588,7 +8790,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } else { enum ATTRIB a; // modify just one attribute - a = rnd(0,MAXATTS); + a = rnd(0,MAXATTS-1); if (!modattr(lf, a, amt)) failed = B_FALSE; } if (failed) { @@ -8899,6 +9101,25 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE modhunger(lf, -pctof(25, (float)HUNGERCONST)); } break; + /////////// potions from recipes............ + case OT_POT_SOUPMUSHROOM: + case OT_POT_SOUPTOMATO: + if (isplayer(lf)) { + msg("Mmm, soup!"); + if (seen) *seen = B_TRUE; + } + modhunger(lf, -((float)HUNGERCONST/2)); + modstamina(lf, 2); + break; + case OT_POT_STROGONOFF: + if (isplayer(lf)) { + msg("Mmm, beef strogonoff!"); + if (seen) *seen = B_TRUE; + } + modhunger(lf, -((float)HUNGERCONST)); + // boost fitness + addtempflag(lf->flags, F_ATTRMOD, A_CON, 3, NA, NULL, rnd(50,100)); + break; default: // nothing happens break; } @@ -10616,7 +10837,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } // an actual physical shield? shield = getshield(target); - if (shield && !lfhasflag(target, F_CASTINGSPELL)) { + if (shield && hasfreeaction(target)) { // block chance based on shield skill // ie. AT_AVERAGE = speed3 = 18 // ie. gun = speed20 = 120 = impossible @@ -11211,8 +11432,9 @@ void timeeffectsob(object_t *o) { if (hasflag(o->flags, F_DEAD)) return; } - if ((f->id == F_EDIBLE) && (o->type->id == OT_STEW)) { - f->val[1] -= 20; + // corpses rot away... + if ((f->id == F_EDIBLE) && (o->type->obclass->id == OC_CORPSE)) { + f->val[1] -= 4; if (f->val[1] < 0) { f->val[1] = 0; addflag(o->flags, F_TAINTED, B_TRUE, NA, NA, NULL); @@ -11938,6 +12160,53 @@ int geteffecttime(int min, int max, enum BLESSTYPE isblessed) { return howlong; } +// populate retob[] with ingredents for the given recipe, taken from the given object pile +int getingredients(obpile_t *op, recipe_t *rec, object_t **retob, int *retcount, int *retconsume, int *nretobs, int promptformulti) { + int i; + object_t *o; + + if (nretobs) *nretobs = 0; + + for (i = 0; i < rec->ningredients; i++) { + 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])) { + poss[nposs++] = o; + } + } + + if ((nposs > 1) && promptformulti) { + int n,ch; + // ask which one to use + initprompt(&prompt, "Which item will you use in your cooking:"); + // you MUST pick one since at this point you've already been given the recipe result! + for (n = 0; n < nposs; n++) { + char iname[BUFLEN]; + getobname(poss[n], iname, 1); + addchoice(&prompt, poss[n]->letter, noprefix(iname), NULL, poss[n], NULL); + } + ch = getchoice(&prompt); + poss[0] = (object_t *)prompt.result; + nposs = 1; + } + + if (nposs == 0) { + // missing an ingredient! + if (nretobs) *nretobs = 0; + return B_TRUE; + } else { + if (retob && nretobs) { + if (retob) retob[*nretobs] = poss[0]; + if (retcount) retcount[*nretobs] = rec->count[i]; + if (retconsume) retconsume[*nretobs] = rec->consume[i]; + (*nretobs)++; + } + } + } + return B_FALSE; +} + objecttype_t *getlinkspell(object_t *o) { flag_t *f = NULL; objecttype_t *spelltype = NULL; diff --git a/objects.h b/objects.h index 747f2a6..05bb942 100644 --- a/objects.h +++ b/objects.h @@ -7,7 +7,7 @@ object_t *addemptyob(obpile_t *where, object_t *o); hiddenname_t *addhiddenname(enum OBCLASS obclass, char *text); knowledge_t *addknowledge(enum OBCLASS id, char *hiddenname, int known); material_t *addmaterial(enum MATERIAL id, char *name, float weightrating); -objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph, int glyphcolour); +objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph, int glyphcolour, enum RARITY rarity); void addocnoun(objectclass_t *oc, char *text); object_t *addob(obpile_t *where, char *name); object_t *addobfast(obpile_t *where, enum OBTYPE oid); @@ -17,6 +17,7 @@ obmod_t *addobmod(enum OBMOD id, char *prefix); obpile_t *addobpile(lifeform_t *owner, cell_t *where, object_t *parentob); void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes); objecttype_t *addot(enum OBTYPE id, char *name, char *description, int material, float weight, int obclassid, enum LFSIZE size); +recipe_t *addrecipe(enum OBTYPE result, ...); void adjustdamhardness(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat); void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat); void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype); @@ -57,6 +58,7 @@ brand_t *findbrand(enum BRAND id); obmod_t *findobmod(enum OBMOD id); objecttype_t *findot(enum OBTYPE id); objecttype_t *findotn(char *name); // find objecttype by name +recipe_t *findrecipefor(enum OBTYPE result); void fragments(cell_t *centre, char *what, int speed, int howfar); void genhiddennames(void); object_t *getbestcontainer(obpile_t *op); @@ -66,6 +68,7 @@ int getcritchance(lifeform_t *lf, object_t *o, lifeform_t *victim); int getdr(object_t *o); int checkcritprotection(lifeform_t *lf, object_t *o); int geteffecttime(int min, int max, enum BLESSTYPE isblessed); +int getingredients(obpile_t *op, recipe_t *rec, object_t **retob, int *retcount, int *retconsume, int *nretobs, int promptformulti); objecttype_t *getlinkspell(object_t *o); enum COLOUR getmaterialcolour(enum MATERIAL mat ); enum MATSTATE getmaterialstate(enum MATERIAL mat); @@ -122,11 +125,12 @@ char *getobhurtname(object_t *o, enum DAMTYPE damtype); float getobweight(object_t *o); float getobunitweight(object_t *o); objecttype_t *getoppositestairs(objecttype_t *ot); -char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth, int forcehabitat, enum LFSIZE maxsize); +char *real_getrandomob(map_t *map, char *buf, int forcedepth, int forcehabitat, enum LFSIZE maxsize, int forpickup, ... ); char *getrandomob(map_t *map, char *buf); char *getrandomobofsize(map_t *map, char *buf, enum LFSIZE maxsize); char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf); char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf, int depthmod); +enum OBCLASS getrandomobclass(void); int getobrarity(object_t *o, enum RARITY *rr); enum SPELLSCHOOL getschool(enum OBTYPE sid); char *getschoolname(enum SPELLSCHOOL sch); @@ -167,7 +171,7 @@ int isdangerousob(object_t *o, lifeform_t *lf, int onlyifknown); int isdeadob(object_t *o); int isdrinkable(object_t *o); int isedible(object_t *o); -flag_t *isequipped(object_t *o); +int isequipped(object_t *o); int isequippedon(object_t *o, enum BODYPART bp); int isfirearm(object_t *o); int isflammable(object_t *o); @@ -223,6 +227,7 @@ int obotpropsmatch(object_t *a, objecttype_t *b); flag_t *obrestrictsmovement(object_t *o, lifeform_t *lf); int obsfallthrough(cell_t *c, object_t *pit); int operate(lifeform_t *lf, object_t *o, cell_t *where); +enum RARITY pickrr(int whatfor); int pilehasletter(obpile_t *op, char let); void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE potlessed, int *seen); int pour(lifeform_t *lf, object_t *o); diff --git a/spell.c b/spell.c index 9cb16ce..c10c2fb 100644 --- a/spell.c +++ b/spell.c @@ -20,6 +20,7 @@ extern lifeform_t *player; extern skill_t *firstskill, *lastskill; extern race_t *firstrace, *lastrace; +extern recipe_t *firstrecipe, *lastrecipe; extern map_t *heaven; extern region_t *firstregion; extern knowledge_t *knowledge; @@ -573,9 +574,14 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef startclimbing(user); } else if (abilid == OT_A_COOK) { - object_t *water,*o; - race_t *r = NULL; - char buf[BUFLEN]; + object_t *o; + recipe_t *rec; + char *longdesc,ch; + int i; + cell_t fakecell; + map_t fakemap; + createfakes(&fakemap, &fakecell); + if (!isplayer(user)) { return B_TRUE; } @@ -583,49 +589,62 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) msg("You can't cook while swimming!"); return B_TRUE; } - water = hasob(user->pack, OT_POT_WATER); - if (!water || !isknown(water)) { - msg("You need some water before you can cook."); - return B_TRUE; - + + longdesc = malloc(HUGEBUFLEN * sizeof(char)); + initprompt(&prompt, "What will you cook (ESC to cancel)?"); + for (rec = firstrecipe ; rec ; rec = rec->next ) { + if (cancook(user, rec, NULL)) { + object_t *o; + o = addobfast(fakecell.obpile, rec->result); + makedesc_ob(o, longdesc); + addchoice(&prompt, 'a', o->type->name, NULL, rec, longdesc); + killob(o); + } } - o = doaskobject(user->pack, "What will you cook?", NULL, B_FALSE, B_FALSE, AO_EDIBLE, F_CORPSEOF); - if (!o) { + free(longdesc); + killfakes(&fakemap, &fakecell); + + addchoice(&prompt, '\0', "nothing", NULL, NULL, NULL); + prompt.maycancel = B_TRUE; + ch = getchoicestr(&prompt, B_FALSE, B_TRUE); + rec = (recipe_t *)prompt.result; + if (!rec) { msg("Cancelled."); return B_TRUE; - } - - f = hasflag(o->flags, F_CORPSEOF); - if (f) { - r = findrace(f->val[0]); - } - - taketime(user, getactspeed(user)); - - // remove object and water - removeob(o,ALL); - removeob(water,ALL); - // give food - if (getskill(user, SK_COOKING >= PR_EXPERT)) { - o = addobfast(user->pack, OT_JERKY); } else { - o = addobfast(user->pack, OT_STEW); - } - - if (o) { - if (r) { - addflag(o->flags, F_LINKRACE, r->id, NA, NA, NULL); + object_t *retob[MAXRECIPEINGREDIENTS]; + int retcount[MAXRECIPEINGREDIENTS]; + int retconsume[MAXRECIPEINGREDIENTS]; + int nretobs; + char obname[BUFLEN]; + enum RACE corpsetype = R_NONE; + // try to cook this... + // give the new object + o = addobfast(user->pack, rec->result); + if (o) { + // now remove the ingredients... + getingredients(user->pack, rec, retob, retcount, retconsume, &nretobs, B_TRUE); + for (i = 0; i < nretobs; i++) { + if (retconsume[i]) { + // remember corpse types + if (retob[i]->type->id == OT_CORPSE) { + f = hasflag(retob[i]->flags, F_CORPSEOF); + if (f) corpsetype = f->val[0]; + } + removeob(retob[i], retcount[i]); + } + } + if (corpsetype != R_NONE) { + addflag(o->flags, F_LINKRACE, corpsetype, NA, NA, NULL); + } + getobname(o, obname, o->amt); + msgnocap("%c - %s", o->letter, obname); + // take some time + taketime(user, getactspeed(user)); + } else { + // pack full? + msg("You have space to cook!"); } - f = hasflag(o->flags, F_EDIBLE); - if (f) { - f->val[1] = getskill(user, SK_COOKING)*20; - } - - getobname(o, buf, o->amt); - msgnocap("%c - %s", o->letter, buf); - practice(user, SK_COOKING, 1); - } else { - msg("Your cooking attempt fails (maybe your pack was too full?)."); } } else if (abilid == OT_A_DARKWALK) { if (range <= 0) range = UNLIMITED; @@ -5572,6 +5591,97 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } } + } else if (spellid == OT_S_HEATMETAL) { + int donesomething = B_FALSE; + object_t *o,*nexto; + target = targcell->lf; + if (target) { + if (ismetal(target->race->material->id)) { + if (!isimmuneto(target->flags, DT_HEAT)) { + if (isplayer(target)) { + msg("Your suffer massive burns!"); + } else if (cansee(player, target)) { + char lfname[BUFLEN]; + getlfname(target, lfname); + msg("%s glows red hot!", lfname); + } + losehp(target, roll("6d4"), DT_HEAT, caster, "massive burns"); + donesomething = B_TRUE; + } + } else { + int nburn = 0,ndropobs = 0; + object_t *dropob[MAXPILEOBS]; + // affect equipped objects + for (o = target->pack->first ; o ; o = nexto) { + nexto = o->next; + // destroy metal items on the ground + if (ismetal(o->material->id)) { + int dodam = B_FALSE; + if (isequippedon(o, BP_WEAPON) || isequippedon(o, BP_SECWEAPON)) { + nburn++; + dodam++; + dropob[ndropobs++] = o; + donesomething = B_TRUE; + } else if (isequipped(o)) { + nburn++; + donesomething = B_TRUE; + dodam++; + } + if (dodam) { + if (cansee(player, target)) { + char obname[BUFLEN]; + char lfname[BUFLEN]; + getobname(o, obname, o->amt); + getlfname(target, lfname); + msg("%s%s %s glow%s red hot!", lfname, getpossessive(lfname), + noprefix(obname), (o->amt == 1) ? "s" : ""); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + takedamage(o, rnd(1,4), DT_HEAT); + } + } + } + + if (nburn && !isimmuneto(target->flags, DT_FIRE)) { + int i; + losehp(target, rnd(nburn,4), DT_HEAT, caster, "red-hot metal"); + if (isplayer(target)) { + msg("^BThe red-hot metal burns you!"); + } else if (cansee(player, target)) { + char lfname[BUFLEN]; + getlfname(target, lfname); + msg("^BThe red-hot metal burns %s!", lfname); + } + for (i = 0; i < ndropobs; i++) { + drop(dropob[i], dropob[i]->amt); + } + } + } + } else { + // affect objects on ground + for (o = targcell->obpile->first ; o ; o = nexto) { + nexto = o->next; + // destroy metal items on the ground + if (ismetal(o->material->id)) { + if (haslos(player, targcell)) { + char obname[BUFLEN]; + getobname(o, obname, o->amt); + msg("%s glow%s red hot!", obname, (o->amt == 1) ? "s" : ""); + if (seenbyplayer) *seenbyplayer = B_TRUE; + donesomething = B_FALSE; + } + takedamage(o, rnd(1,4), DT_HEAT); + } + } + } + + if (!donesomething) { + if (isplayer(caster)) { + nothinghappens(); + } else { + fizzle(caster); + } + } } else if (spellid == OT_S_HOLDPORTAL) { object_t *o,*oo; cell_t *c; @@ -5810,27 +5920,23 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (o = caster->pack->first ; o ; o = nexto) { nexto = o->next; if (ismetal(o->material->id)) { - f = isequipped(o); - if (f) { - if ((f->val[0] == BP_WEAPON) || (f->val[0] == BP_SECWEAPON)) { - } else if ((f->val[0] == BP_RIGHTFINGER) || (f->val[0] == BP_LEFTFINGER)) { - if (isplayer(caster)) { - getobname(o, buf, 1); - msg("Your %s slides off your %s!", buf, getbodypartname(caster, f->val[0])); - } else if (cansee(player, caster)) { - getobname(o, buf, 1); - msg("%s%s %s slides off its %s!", castername, - getpossessive(castername), buf, getbodypartname(caster, f->val[0])); - } - moveob(o, caster->cell->obpile, o->amt); - } else { - if (isplayer(caster)) { - getobname(o, buf, 1); - msg("Your %s pulls away from you a little.", noprefix(buf)); - } - fizzle(caster); - return B_FALSE; + if (isequippedon(o, BP_RIGHTFINGER) || isequippedon(o, BP_LEFTFINGER)) { + if (isplayer(caster)) { + getobname(o, buf, 1); + msg("Your %s slides off your %s!", buf, getbodypartname(caster, f->val[0])); + } else if (cansee(player, caster)) { + getobname(o, buf, 1); + msg("%s%s %s slides off its %s!", castername, + getpossessive(castername), buf, getbodypartname(caster, f->val[0])); } + moveob(o, caster->cell->obpile, o->amt); + } else if (isequipped(o)) { + if (isplayer(caster)) { + getobname(o, buf, 1); + msg("Your %s pulls away from you a little.", noprefix(buf)); + } + fizzle(caster); + return B_FALSE; } } } @@ -6296,10 +6402,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // if they're wearing metal... for (o = targcell->lf->pack->first ; o ; o = o->next) { - if (ismetal(o->material->id)) { - flag_t *f; - f = isequipped(o); - if (f && (f->val[0] != BP_WEAPON) && (f->val[0] != BP_SECWEAPON)) { + if (ismetal(o->material->id) && isequipped(o)) { + if (!isequippedon(o, BP_WEAPON) && !isequippedon(o, BP_SECWEAPON)) { gotmetal = B_TRUE; metalweight += getobweight(o); break; @@ -6713,8 +6817,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ cell_t *c; c = retcell[i]; if (c->lf) { + int dam; // hit with lightning - losehp(c->lf, roll("2d6"), DT_ELECTRIC, caster, "an electricity bolt"); + dam = roll("2d6"); + if (power > 1) { + dam += power; // maxpower is 1, but blue dragons can exceed this + } + losehp(c->lf, dam, DT_ELECTRIC, caster, "an electricity bolt"); nhits--; } if (haslos(player, c)) { diff --git a/text.c b/text.c index 7e3973d..d325a98 100644 --- a/text.c +++ b/text.c @@ -1101,12 +1101,16 @@ char *makeplural(char *text) { if (rv) return newtext; newtext = strrep(newtext, "pile ", "piles ", &rv); if (rv) return newtext; + newtext = strrep(newtext, "pinch ", "pinches ", &rv); + if (rv) return newtext; newtext = strrep(newtext, "pool ", "pools ", &rv); if (rv) return newtext; newtext = strrep(newtext, "potion ", "potions ", &rv); if (rv) return newtext; newtext = strrep(newtext, "puddle ", "puddles ", &rv); if (rv) return newtext; + newtext = strrep(newtext, "puff ", "puffs ", &rv); + if (rv) return newtext; newtext = strrep(newtext, "ring ", "rings ", &rv); if (rv) return newtext; newtext = strrep(newtext, "scroll ", "scrolls ", &rv); @@ -1158,6 +1162,55 @@ char *makeuppercase(char *text) { return text; } +// return something like: +// "over the shoulders" +// or +// "on your body, over your eyes and on your legs" +char *makewearstring(lifeform_t *lf, object_t *o, int wantyour, char *posbuf) { + flag_t *retflag[MAXCANDIDATES]; + char yourbuf[BUFLEN]; + int nretflags = 0,i; + if (wantyour) { + if (!lf) { + strcpy(yourbuf, "the "); + } else if (isplayer(lf)) { + strcpy(yourbuf, "your "); + } else { + strcpy(yourbuf, "its "); + } + } else { + strcpy(yourbuf, ""); + } + getflags(o->flags, retflag, &nretflags, F_EQUIPPED, F_NONE); + for (i = 0; i < nretflags; i++) { + char thisposbuf[BUFLEN]; + + makewearstringsingle(lf, retflag[i], yourbuf, thisposbuf); + + if (i == 0) { + strcpy(posbuf, thisposbuf); + } else if (i == (nretflags - 1)) { + strcat(posbuf, " and "); + strcat(posbuf, thisposbuf); + } else { + strcat(posbuf, ", "); + strcat(posbuf, thisposbuf); + } + } + return posbuf; +} + +// return something like: +// "on your body" +// OR +// "over the eyes" +char *makewearstringsingle(lifeform_t *lf, flag_t *f, char *yourbuf , char *posbuf) { + enum BODYPART bp; + bp = f->val[0]; + sprintf(posbuf, "%s %s%s", getbodypartequipname(bp), yourbuf, getbodypartname(lf, bp)); + return posbuf; +} + int needses(char *text) { if (text[strlen(text)-1] == 's') { return B_TRUE; diff --git a/text.h b/text.h index 473c2ac..b6fc851 100644 --- a/text.h +++ b/text.h @@ -37,6 +37,8 @@ int isvowel(char c); char *makekillertext(char *retbuf, char *killverb, char *lastdam, int wantextra); char *makeplural(char *text); char *makeuppercase(char *text); +char *makewearstring(lifeform_t *lf, object_t *o, int wantyour, char *posbuf); +char *makewearstringsingle(lifeform_t *lf, flag_t *f, char *yourbuf, char *posbuf); int needses(char *text); char *noprefix(char *obname); char *numtotext(int num, char *buf);