- [+] 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
This commit is contained in:
Rob Pearce 2011-11-07 02:12:04 +00:00
parent 06cf19e7c9
commit 39af842e74
18 changed files with 1689 additions and 491 deletions

15
ai.c
View File

@ -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) ) {

View File

@ -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");
}
}

614
data.c
View File

@ -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);

Binary file not shown.

79
defs.h
View File

@ -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];

11
doc/add_raceclass.txt Normal file
View File

@ -0,0 +1,11 @@
defs.h:
add RC_xxx
data.c:
addraceclass(xxx)
lf.c:
update cantalk(xxx)
ALSO:
add matching skill!

View File

@ -2,7 +2,7 @@ defs.h:
add SK_xxx
inc MAXSKILLS
lf.c:
data.c:
add addskill()
add addskilldesc()

15
flag.c
View File

@ -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) {

119
io.c
View File

@ -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,7 +3526,7 @@ 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;
}
@ -3528,12 +3536,23 @@ void docomms(lifeform_t *lf) {
}
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 {
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,11 +4387,19 @@ char *makedesc_ob(object_t *o, char *retbuf) {
// extra object descriptions?
getflags(o->flags, retflag, &nretflags, F_EXTRADESC, F_NONE);
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);
}
} 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);
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));

326
lf.c
View File

@ -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) {
@ -1134,11 +1160,7 @@ 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];
@ -1154,27 +1176,51 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) {
return B_FALSE;
}
// are any of these body parts free?
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 (isfreebp(lf, possbp[i])) {
return B_TRUE;
if (possbp[i] == where) {
found = B_TRUE;
}
}
// no parts free
reason = E_WEARINGSOMETHINGELSE;
return B_FALSE;
} else {
// does this object go there?
f = hasflagval(o->flags, F_GOESON, where, NA, NA, NULL);
if (!f) {
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,13 +3155,17 @@ 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)) {
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,7 +8135,6 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) {
}
if (nposs) {
objecttype_t *ot = NULL;
if (isplayer(lf)) {
char ch = 'a';
// note: we use getplayername here even if this isn't a player,
@ -8073,11 +8157,6 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) {
ot = (objecttype_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data;
}
}
} else {
// not player - pick randomly.
i = rnd(0,nposs-1);
ot = poss[i];
}
if (ot) {
skill_t *sk;
@ -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,13 +12918,17 @@ 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);
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 (f && (f->val[0] > BP_SECWEAPON)) {
f = hasflag(o->flags, F_SCARY);
if (f) {
scarerbonus += f->val[0];
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,23 +16241,36 @@ 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;
if (hasflag(o->flags, F_GOESONMULTI)) {
// goes on ALL of the parts
ncheckparts = nparts;
} else {
// 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)) {
if (isfreebp(lf, possbp[i])) {
bp = possbp[i];
break;
}
}
if ((bp == BP_NONE) && isplayer(lf)) msg("You have no room to wear that.");
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
@ -16132,24 +16289,33 @@ int wear(lifeform_t *lf, object_t *o) {
addchoice(&prompt, ch++, buf, NULL, &possbp[i], NULL);
}
addchoice(&prompt, '-', "(cancel)", NULL, NULL, NULL);
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.");
} else bp = *((enum BODYPART *)prompt.result);
}
if (bp == BP_NONE) {
if (isplayer(lf)) {
msg("You have no room to wear that.");
}
return B_TRUE;
} else bp = *((enum BODYPART *)prompt.result);
possbp[0] = bp;
nparts = 1;
ncheckparts = nparts;
}
}
//}
}
// 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) {
@ -16163,11 +16329,8 @@ int wear(lifeform_t *lf, object_t *o) {
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;
// 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,10 +16365,6 @@ 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
@ -16243,6 +16402,7 @@ int wear(lifeform_t *lf, object_t *o) {
}
// 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)) {

3
lf.h
View File

@ -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);

12
map.c
View File

@ -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]) {

View File

@ -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;

391
objects.c
View File

@ -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) {
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;
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;
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;
}
} else if (cond == RO_HOLDABLE) {
if (!hasflag(ot->flags, F_NOPICKUP)) {
condok = B_TRUE;
if (!found) {
condok = B_FALSE;
if (db) dblog(" %s fails obclass check.", ot->name);
}
}
// 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)) {
// 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) dblog("no possible objects at all! giving up.");
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;

View File

@ -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);

205
spell.c
View File

@ -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);
}
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) {
if (r) {
addflag(o->flags, F_LINKRACE, r->id, NA, NA, NULL);
// 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];
}
f = hasflag(o->flags, F_EDIBLE);
if (f) {
f->val[1] = getskill(user, SK_COOKING)*20;
removeob(retob[i], retcount[i]);
}
getobname(o, buf, o->amt);
msgnocap("%c - %s", o->letter, buf);
practice(user, SK_COOKING, 1);
}
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 {
msg("Your cooking attempt fails (maybe your pack was too full?).");
// pack full?
msg("You have space to cook!");
}
}
} 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,10 +5920,7 @@ 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 (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]));
@ -5823,7 +5930,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getpossessive(castername), buf, getbodypartname(caster, f->val[0]));
}
moveob(o, caster->cell->obpile, o->amt);
} else {
} else if (isequipped(o)) {
if (isplayer(caster)) {
getobname(o, buf, 1);
msg("Your %s pulls away from you a little.", noprefix(buf));
@ -5833,7 +5940,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
}
}
// add the magnetic field!
addtempflag(caster->flags, F_MAGSHIELD, B_TRUE, NA, NA, NULL, 25 + (power*2));
@ -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)) {

53
text.c
View File

@ -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;

2
text.h
View File

@ -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);