diff --git a/Makefile b/Makefile index 1c3fe7f..e7e420c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ -nexus: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h data.c data.h flag.c flag.h god.c god.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h shops.c shops.h spell.c spell.h vault.c vault.h - gcc -Wall -g -pg -o nexus nexus.c ai.c attack.c data.c flag.c god.c io.c lf.c map.c move.c objects.c text.c save.c spell.c shops.c vault.c vault.h -lncurses -lsqlite3 +nexus: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h data.c data.h flag.c flag.h god.c god.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h shops.c shops.h spell.c spell.h vault.c vault.h + gcc -Wall -g -o nexus nexus.c ai.c attack.c data.c flag.c god.c io.c lf.c map.c move.c objects.c text.c save.c spell.c shops.c vault.c -lncurses -lsqlite3 + #gcc -Wall -g -o nexus nexus.c ai.c attack.c data.c flag.c god.c io.c lf.c map.c move.c objects.c text.c save.c spell.c shops.c vault.c findleak.c -lncurses -lsqlite3 check: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h data.c data.h flag.c flag.h god.c god.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h shops.c shops.h spell.c spell.h vault.c vault.h splint -onlytrans -nullret -nullstate -branchstate -usedef -type -retvalint -retvalother +posixlib -unrecog -boolops -mustfreefresh -predboolint -unqualifiedtrans -compdef *.c diff --git a/ai.c b/ai.c index abfa89d..9aec84d 100644 --- a/ai.c +++ b/ai.c @@ -54,10 +54,10 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { // already targetting this lf? f = lfhasflagval(lf, F_TARGETLF, victim->id, NA, NA, NULL); if (f) { - dblog(".oO { i am already targetting this lf }"); + if (db) dblog(".oO { i am already targetting this lf }"); if ((f->lifetime > 0) && (f->lifetime < timelimit)) { f->lifetime = timelimit; - dblog(".oO { (flag lifetime updated) }"); + if (db) dblog(".oO { (flag lifetime updated) }"); } return B_TRUE; } @@ -307,9 +307,11 @@ object_t *aigetrangedattack(lifeform_t *lf, lifeform_t *target, enum RANGEATTACK if (iqb <= IQ_ANIMAL) { // animal and lower intelligence won't use ranged // attacks. - if (db) dblog(".oO { no ranged attack due to low iq. }"); - if (ra) *ra = RA_NONE; - return NULL; + if (!lfhasflag(lf, F_WILLTHROW)) { + if (db) dblog(".oO { no ranged attack due to low iq. }"); + if (ra) *ra = RA_NONE; + return NULL; + } } o = getfirearm(lf); @@ -412,7 +414,23 @@ void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victi } if (specialcase) { - if (spelltype->id == OT_S_TELEKINESIS) { + if (spelltype->id == OT_A_CLIMB) { + int i,nposs = 0; + cell_t *poss[MAXCANDIDATES]; + // cell in sight and adjacent? aispellok() should have already confirmed + // that there will be at least one of these. + for (i = 1; i < lf->nlos; i++) { + if (!lf->los[i]->lf && lf->los[i]->type->solid && (getcelldist(lf->cell, lf->los[i]) == 1)) { + poss[nposs++] = lf->los[i]; + } + } + if (spellcell) { + *spellcell = poss[rnd(0,nposs-1)]; + } + if (spelllf) *spelllf = NULL; + if (spellob) *spellob = NULL; + + } else if (spelltype->id == OT_S_TELEKINESIS) { float maxweight; object_t *poss[MAXPILEOBS]; int nposs; @@ -578,6 +596,19 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) { // not attacking anyone in particular if (db) dblog(".oO { i do not have a target or can't move towards it. }"); + // special cases + if (lf->race->id == R_IVYRAPID) { + if (cancast(lf, OT_S_CLONE, NULL)) { + // try to expand + if (!castspell(lf, OT_S_CLONE, lf, NULL, lf->cell, NULL, NULL)) { + // stop reproducing + f = hasflagval(lf->flags, F_CANWILL, OT_S_CLONE, NA, NA, NULL); + if (f) killflag(f); + return B_TRUE; + } + } + } + // shopkeepers will return to their shops if (hasjob(lf, J_SHOPKEEPER)) { f = lfhasflag(lf, F_OWNSSHOP); @@ -634,7 +665,13 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) { } if (pctchance(chance)) { - if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) || + if (lfhasflag(lf, F_HATESALL)) { + if (nhateposs < MAXCANDIDATES) { + if (db) dblog(".oO { hate everything - found lfid %d (%s) ! }",who->id, who->race->name); + hateposs[nhateposs++] = who; + } + break; + } else if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) || lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) { if (nhateposs < MAXCANDIDATES) { if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name); @@ -1340,18 +1377,23 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { // for firearms/projectiles, chance to fire/throw depends on accuracy. if ((rangedattack == RA_GUN) || (rangedattack == RA_THROW)) { - int acc,chance; - acc = getmissileaccuracy(lf, target->cell, getammo(rangedob), rangedob, NULL); - switch (getpctletter(acc,100)) { - case 'S': - case 'A': - chance = 100; break; - case 'B': - chance = 75; break; - case 'C': - chance = 50; break; - default: - chance = 25; break; + int chance; + if (lfhasflag(lf, F_WILLTHROW)) { + chance = 100; + } else { + int acc; + acc = getmissileaccuracy(lf, target->cell, getammo(rangedob), rangedob, NULL); + switch (getpctletter(acc,100)) { + case 'S': + case 'A': + chance = 100; break; + case 'B': + chance = 75; break; + case 'C': + chance = 50; break; + default: + chance = 25; break; + } } if (!pctchance(chance)) { rangedattack = RA_NONE; @@ -1901,7 +1943,26 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG } if (specialcase) { - if (ot->id == OT_S_PYROMANIA) { + if (ot->id == OT_A_CLIMB) { + int possible = B_TRUE,i; + enum ERROR reason; + // can't climb for a reason other than that there isn't + // a climbabnle cell in front of us? + if (!canclimb(lf, &reason)) { + if (reason != E_BADCLIMBDIR) { + possible = B_FALSE; + } + } + if (possible) { + // cell in sight and adjacent? + for (i = 1; i < lf->nlos; i++) { + if (!lf->los[i]->lf && lf->los[i]->type->solid && (getcelldist(lf->cell, lf->los[i]) == 1)) { + ok = B_TRUE; + break; + } + } + } + } else if (ot->id == OT_S_PYROMANIA) { int i; for (i = 0; i < lf->nlos; i++) { if ((lf->los[i] != lf->cell) && getflamingobs(lf->los[i]->obpile, NULL, NULL)) { @@ -1964,11 +2025,6 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) { specificcheckok = B_FALSE; } - if (ot->id == OT_A_CLIMB) { - if (!canclimb(lf, NULL)) { - specificcheckok = B_FALSE; - } - } if (ot->id == OT_A_DISARM) { if (!getweapon(victim)) { specificcheckok = B_FALSE; diff --git a/attack.c b/attack.c index 9749a48..6bc8807 100644 --- a/attack.c +++ b/attack.c @@ -328,6 +328,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { if (isplayer(lf)) { msg("You cannot attack!"); } + if (op) killobpile(op); return B_TRUE; } diff --git a/data.c b/data.c index b99ade1..a67ebdf 100644 --- a/data.c +++ b/data.c @@ -26,6 +26,7 @@ extern hiddennamewithcol_t colour[]; extern char *bookadjective[]; extern char *potadjective[]; extern hiddennamewithcol_t gemtype[]; +extern char *ringadjective[]; extern char *techadjective[]; extern char *technoun[]; @@ -892,6 +893,12 @@ void initobjects(void) { // add it without an adjective snprintf(buf, BUFLEN, "%s ring", gemtype[n].name); addhiddenname(OC_RING, buf); + // add it with all known adjectives + for (i = 0; strlen(ringadjective[i]) ; i++) { + char buf2[BUFLEN]; + snprintf(buf2, BUFLEN, "%s %s",ringadjective[i], buf); + addhiddenname(OC_RING, buf); + } } for (n = 0; strlen(technoun[n]); n++) { @@ -1378,7 +1385,7 @@ void initobjects(void) { // buildings addot(OT_MOTEL, "motel", "A small structure providing cheap overnight rooms for rent", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHOPMENU, 0, MA_GOTOMENU, SM_REST, "a:rent a room"); addflag(lastot->flags, F_SHOPMENU, 1, MA_GOTOMENU, SM_PURCHASEITEMS, "b:buy provisions"); @@ -1390,7 +1397,7 @@ void initobjects(void) { } addot(OT_SHOPARMOUR, "armour store", "A small kiosk dealing in armour.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHOPMENU, 0, MA_GOTOMENU, SM_PURCHASEITEMS, "a:buy something"); addflag(lastot->flags, F_SHOPMENU, 1, MA_GOTOMENU, SM_DONATE, "d:donate something"); @@ -1399,7 +1406,7 @@ void initobjects(void) { addflag(lastot->flags, F_STARTOBCLASS, 100, OC_ARMOUR, RANDOM, NULL); } addot(OT_SHOPBOOK, "book store", "A small kiosk dealing in books.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); make_basic_shop(lastot->flags); for (i = 0; i < 10; i++) { @@ -1408,21 +1415,21 @@ void initobjects(void) { addaltval(f, F_STARTOBCLASS, 100, OC_SCROLL, RANDOM, NULL); } addot(OT_SHOPFOOD, "food vendor", "A small kiosk dealing in food.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); make_basic_shop(lastot->flags); for (i = 0; i < 10; i++) { addflag(lastot->flags, F_STARTOBCLASS, 100, OC_FOOD, RANDOM, NULL); } addot(OT_SHOPGENERAL, "general store", "A small kiosk which sells various objects.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); make_basic_shop(lastot->flags); for (i = 0; i < 10; i++) { addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL); } addot(OT_SHOPHARDWARE, "hardware store", "A small kiosk which sells tools and technology.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); make_basic_shop(lastot->flags); for (i = 0; i < 10; i++) { @@ -1431,21 +1438,21 @@ void initobjects(void) { addaltval(f, F_STARTOBCLASS, 100, OC_TECH, RANDOM, NULL); } addot(OT_SHOPPOTION, "potion store", "A small kiosk dealing in liqour and potions.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); make_basic_shop(lastot->flags); for (i = 0; i < 10; i++) { addflag(lastot->flags, F_STARTOBCLASS, 100, OC_POTION, RANDOM, NULL); } addot(OT_SHOPRING, "jewellery store", "A small kiosk dealing in rings and amulets.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); make_basic_shop(lastot->flags); for (i = 0; i < 10; i++) { addflag(lastot->flags, F_STARTOBCLASS, 100, OC_RING, RANDOM, NULL); } addot(OT_SHOPWEAPON, "weapon store", "A small kiosk dealing in weapons.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHOPMENU, 0, MA_GOTOMENU, SM_PURCHASEITEMS, "a:buy something"); addflag(lastot->flags, F_SHOPMENU, 1, MA_GOTOMENU, SM_DONATE, "d:donate something"); @@ -1454,7 +1461,7 @@ void initobjects(void) { addflag(lastot->flags, F_STARTOBCLASS, 100, OC_WEAPON, RANDOM, NULL); } addot(OT_TEMPLE, "temple", "A small structure dedicated to one of the gods.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); - addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_MAKESNOISE, 33, 3, NA, "voices chanting."); addflag(lastot->flags, F_SHOPMENU, 0, MA_GOTOMENU, 1, "a:speak to a deacon (earthly concerns)"); @@ -1919,8 +1926,8 @@ void initobjects(void) { 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, NULL); 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_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_HOLDCONFER, F_EXTRALUCK, 1, NA, NULL); killflagsofid(lastot->flags, F_STACKABLE); addot(OT_BREADSTALE, "loaf of stale bread", "A small loaf of old, stale bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); @@ -1969,10 +1976,15 @@ void initobjects(void) { addflag(lastot->flags, F_EDIBLE, B_TRUE, 30, NA, ""); 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, NULL); - addflag(lastot->flags, F_EDIBLE, B_TRUE, 12, NA, ""); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 22, 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_PASSIONFRUIT, "passionfruit", "A succulent passionfruit.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_MAGENTA, '%', NA, NULL); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, 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_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, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); @@ -2020,36 +2032,44 @@ void initobjects(void) { addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); - // potions + // potions addot(OT_POT_SPIDERCLIMB, "potion of arachnid adhesion", "Temporarily allows you to climb on walls like a spider.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_VALUE, 45, NA, NA, NULL); addot(OT_POT_JUICE, "potion of fruit juice", "Tasty (but not very fresh) fruit juice! Sates hunger and restores a little stamina.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); + addflag(lastot->flags, F_VALUE, 10, NA, NA, NULL); addot(OT_POT_CANINETRACKING, "potion of canine tracking", "Mimics the effects of a 'canine tracking' spell.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addot(OT_POT_HEALINGMIN, "potion of minor healing", "Restores 1-10 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 30, NA, NA, NULL); addot(OT_POT_WATER, "potion of water", "Plain, regular water.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_FREQUENT, NULL); addflag(lastot->flags, F_RARITY, H_VILLAGE, 100, RR_FREQUENT, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small puddle of water"); modflag(lastot->flags, F_HASHIDDENNAME, NA, NA, NA, "clear potion"); + addflag(lastot->flags, F_VALUE, 5, NA, NA, NULL); addot(OT_POT_HEALING, "potion of healing", "Restores 10-20 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 90, NA, NA, NULL); addot(OT_POT_HEALINGMAJ, "potion of major healing", "Restores 20-30 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 120, NA, NA, NULL); addot(OT_POT_OIL, "potion of oil", "A bottle of cooking oil.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of oil"); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "2d4"); + addflag(lastot->flags, F_VALUE, 15, NA, NA, NULL); addot(OT_POT_COFFEE, "potion of coffee", "A caffeinated beverage prepared from coffee beans.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); + addflag(lastot->flags, F_VALUE, 10, NA, NA, NULL); addot(OT_POT_RUM, "potion of rum", "Strong liqour which is sure to make you tipsy. This will make you unsteady and lower your accuracy, but also let you ignore pain, minor damage, and many mental attacks.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_FLAMMABLE, 1, NA, NA, "medium fire"); @@ -2057,70 +2077,91 @@ void initobjects(void) { addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "2d6"); addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 15, NA, NA, NULL); addot(OT_POT_RESTORATION, "potion of restoration", "Restores lost abilities to the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); + addflag(lastot->flags, F_VALUE, 170, NA, NA, NULL); addot(OT_POT_SLEEP, "potion of sleep", "Puts the drinker into a deep sleep.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 80, NA, NA, NULL); addot(OT_POT_SPEED, "potion of haste", "Temporarily increasees the drinker's speed.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addot(OT_POT_LEVITATION, "potion of levitation", "Causes the drinker to float up in the air.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); + addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addot(OT_POT_MAGIC, "potion of magic", "Fully restores the drinker's magical energy.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 60, NA, NA, NULL); addot(OT_POT_ACROBATICS, "potion of acrobatics", "Allows the drinker to leap large distances.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); + addflag(lastot->flags, F_VALUE, 45, NA, NA, NULL); addot(OT_POT_INVIS, "potion of invisibility", "Temporarily renders the drinker invisible.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 70, NA, NA, NULL); addot(OT_POT_POISON, "potion of poison", "Poisons the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); addot(OT_POT_ACID, "flask of battery acid", "Causes massive internal burning if ingested.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of acid"); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); addot(OT_POT_ELEMENTIMMUNE, "potion of elemental immunity", "Grants the imbiber temporary immunity to both fire and cold.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); + addflag(lastot->flags, F_VALUE, 75, NA, NA, NULL); addot(OT_POT_BLOOD, "potion of blood", "A small quantity of blood.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "splash of blood"); + addflag(lastot->flags, F_VALUE, 15, NA, NA, NULL); addot(OT_POT_SANCTUARY, "potion of sanctuary", "Creates a temporary magical barrier abour the drinker.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); + addflag(lastot->flags, F_VALUE, 75, NA, NA, NULL); addot(OT_POT_ETHEREALNESS, "potion of etherealness", "Allows the walker to temporarily pass through walls.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); + addflag(lastot->flags, F_VALUE, 140, NA, NA, NULL); addot(OT_POT_EXPERIENCE, "potion of experience", "Instantly grants the imbiber the next experience level.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, 40, NA, NULL); + addflag(lastot->flags, F_VALUE, 210, NA, NA, NULL); addot(OT_POT_BLOODC, "potion of cockatrice blood", "A small quantity of cockatrice blood.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "splash of cockatrice blood"); + addflag(lastot->flags, F_VALUE, 35, NA, NA, NULL); addot(OT_POT_COMPETENCE, "potion of competence", "Permemantly increases the drinker's strength, intelligence or dexterity.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); + addflag(lastot->flags, F_VALUE, 160, NA, NA, NULL); addot(OT_POT_GASEOUSFORM, "potion of gaseous form", "Turns the drinker into a cloud of gas. Only intended for emergencies, since it will cause you to drop all your items.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 120, NA, NA, NULL); addot(OT_POT_POLYMORPH, "potion of polymorph self", "Transmutes the drinker into another living race.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 120, NA, NA, NULL); addot(OT_POT_INVULN, "potion of invulnerability", "Grants the drinker temporary immunity to physical harm.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 200, NA, NA, NULL); addot(OT_POT_AMBROSIA, "vial of ambrosia", "The nectar of the gods, said to completely restore the drinker's health.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 220, NA, NA, NULL); // potions which come from cooking @@ -2304,7 +2345,7 @@ void initobjects(void) { // death / necromancy /////////////////// // l1 - addot(OT_S_STENCH, "stench", "Nauseates the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_STENCH, "stench of death", "Nauseates the target with the smell of dying flesh.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability and duration."); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -3357,6 +3398,11 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); // l5 + addot(OT_S_CLONE, "clone", "Creates an identical clone of the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, 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_ANYWHERE, NA, NA, NULL); addot(OT_S_SUMMONDEMON, "summon demon", "Summons a random demonic entity.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines its chances of success, and how long the demon will remain."); addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); @@ -3374,13 +3420,13 @@ void initobjects(void) { addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l2 addot(OT_S_BLINK, "bamf", "Teleports the caster to a random location within view.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VI you can choose where to blink to."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VI you can choose where to teleport to."); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); - addot(OT_S_SUCK, "suck", "Sucks the target lifeform towards the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_SUCK, "get over here!", "Sucks the target lifeform towards the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability."); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -3537,8 +3583,8 @@ void initobjects(void) { addot(OT_A_CLIMB, "climb", "Climb up or down whatever is in front of you (walls or pits).", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_STAMCOST, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOFLEE, ST_ANYWHERE, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SPECIAL, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); addot(OT_A_COOK, "cook", "Cook a corpse, or combine various foods into a healthy meal.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_DARKWALK, "darkwalk", "Step between the shadows.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); @@ -3749,18 +3795,20 @@ void initobjects(void) { // tools addot(OT_BANDAGE, "bandage", "A small medical bandage. When worn, it will counteract bleeding.", MT_CLOTH, 0.5, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); + addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); addot(OT_BLANKET, "wool blanket", "A warm wool blanket for those cold winter nights.", MT_CLOTH, 2, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); + addflag(lastot->flags, F_VALUE, 50, NA, NA, NULL); addflag(lastot->flags, F_HELPSREST, 10, NA, NA, NULL); addot(OT_BLINDFOLD, "blindfold", "Short length of wide cloth, used for blocking eyesight.", MT_CLOTH, 0.01, OC_TOOLS, SZ_TINY); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_BLIND, B_TRUE, NA, NULL); - addflag(lastot->flags, F_VALUE, 20, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 15, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addot(OT_CALTROP, "caltrop", "Connected metal spikes arranged such that one will always point upwards.", MT_METAL, 0.2, OC_TOOLS, SZ_TINY); @@ -3770,6 +3818,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_GREY, '^', NA, NULL); addflag(lastot->flags, F_SHARP, 2, 5, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, NULL); + addflag(lastot->flags, F_VALUE, 20, NA, NA, NULL); addot(OT_BUGLAMP, "glowing flask", "A glass flask with a glowbug corpse inside.", MT_GLASS, 0.3, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_GLYPH, NA, '!', NA, NULL); @@ -3779,6 +3828,7 @@ void initobjects(void) { addot(OT_CANDLE, "candle", "A short wax candle.", MT_WAX, 0.2, OC_TOOLS, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); + addflag(lastot->flags, F_VALUE, 20, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit"); @@ -3791,6 +3841,7 @@ void initobjects(void) { addot(OT_FRIDGE, "refrigerator", "An insulated household appliance, made for storing food.", MT_METAL, 120, OC_TOOLS, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 1500, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_WHITE, ']', NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -3811,6 +3862,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, NA, ',', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 65, NA, NULL); + addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "8d2"); addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "2d6"); @@ -3819,6 +3871,7 @@ void initobjects(void) { addot(OT_LAMPOIL, "oil lamp", "An oil-powered lamp which produces light.", MT_METAL, 1, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); + addflag(lastot->flags, F_VALUE, 80, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 5, NA, NULL); @@ -3831,6 +3884,7 @@ void initobjects(void) { addot(OT_LANTERNOIL, "oil lantern", "An oil-powered lantern which produces a lot of light.", MT_METAL, 1, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 55, NA, NULL); + addflag(lastot->flags, F_VALUE, 100, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 6, NA, NULL); @@ -3844,25 +3898,30 @@ void initobjects(void) { addot(OT_LOCKPICK, "lockpick", "An angled piece of metal, used to open locks.", MT_METAL, 0.05, OC_TOOLS, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, NULL); + addflag(lastot->flags, F_VALUE, 10, NA, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 10, B_DIEONFAIL, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addot(OT_PANPIPES, "set of panpipes", "A set of musical pipes.", MT_METAL, 0.5, OC_TOOLS, SZ_TINY); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastot->flags, F_VALUE, 75, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addot(OT_PICKAXE, "pickaxe", "A heavy tool for breaking rock.", MT_METAL, 8, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); + addflag(lastot->flags, F_VALUE, 75, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HELPSDIG, 10, NA, NA, NULL); addot(OT_ROPE, "rope", "A long length of strong rope.", MT_CLOTH, 5, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 75, NA, NULL); + addflag(lastot->flags, F_VALUE, 35, NA, NA, NULL); addflag(lastot->flags, F_HELPSCLIMB, 3, NA, NA, NULL); addot(OT_SACK, "sack", "A small cloth sack.", MT_CLOTH, 0.5, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -3874,6 +3933,8 @@ void initobjects(void) { addflag(lastot->flags, F_STARTOBRND, 10, NA, NA, NULL); addot(OT_SACKLARGE, "large sack", "A large cloth sack.", MT_CLOTH, 1, OC_TOOLS, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 50, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -3886,6 +3947,8 @@ void initobjects(void) { addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); addot(OT_SACKHUGE, "huge sack", "An enormous cloth sack.", MT_CLOTH, 1, OC_TOOLS, SZ_LARGE); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL); + addflag(lastot->flags, F_VALUE, 85, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -3904,6 +3967,7 @@ void initobjects(void) { addot(OT_BAGOFHOLDING, "bag of holding", "A magical sack which causes items placed inside it to become weightless.", MT_CLOTH, 0.5, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_RARE, NULL); + addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL); @@ -3918,6 +3982,7 @@ void initobjects(void) { addot(OT_BAGOFHOLDINGLARGE, "large bag of holding", "A large magical sack which causes items placed inside it to become weightless.", MT_CLOTH, 0.5, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_RARE, NULL); + addflag(lastot->flags, F_VALUE, 220, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL); @@ -3933,6 +3998,7 @@ void initobjects(void) { addot(OT_BAGOFHOLDINGHUGE, "huge bag of holding", "An enormous magical sack which causes items placed inside it to become weightless.", MT_CLOTH, 0.5, OC_TOOLS, SZ_LARGE); addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_VERYRARE, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL); @@ -3952,6 +4018,7 @@ void initobjects(void) { addot(OT_SAFEBOX, "safebox", "A small metal container for safely storing valuables.", MT_METAL, 2, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 77, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -3966,6 +4033,7 @@ void initobjects(void) { addot(OT_TORCH, "torch", "A metre-long wooden rod with a flammable end.", MT_WOOD, 2, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 85, NA, NULL); + addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit"); @@ -3983,18 +4051,20 @@ void initobjects(void) { addot(OT_TOWEL, "towel", "An large absorbent cloth used for drawing off moisture.", MT_CLOTH, 1.5, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 73, NA, NULL); + addflag(lastot->flags, F_VALUE, 15, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); // tech - l0 addot(OT_CREDITCARD, "credit card", "A rectangular plastic card.", MT_PLASTIC, 0.01, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); - addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_RNDCHARGES, 75, 500, NA, NULL); + addflag(lastot->flags, F_STACKABLE, B_FALSE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 2, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addot(OT_PAPERCLIP, "paperclip", "A thin, looped wire for holding paper together.", MT_WIRE, 0.01, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); + addflag(lastot->flags, F_VALUE, 5, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); @@ -4006,11 +4076,13 @@ void initobjects(void) { addot(OT_SLEEPINGBAG, "sleeping bag", "An insulated bag for sleeping in. Very comfortable.", MT_CLOTH, 2, OC_TECH, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); + addflag(lastot->flags, F_VALUE, 75, NA, NA, NULL); addflag(lastot->flags, F_HELPSREST, 15, NA, NA, NULL); // tech - l1 addot(OT_BUTANETORCH, "butane torch", "A cooking tool which creates an intensely hot flame using butane gas.", MT_METAL, 0.5, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 85, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 75, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERUSECHARGE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, TR_NEEDLOF, 1, "Where will you aim?"); @@ -4019,17 +4091,20 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_POCKETWATCH, "pocket watch", "A portable timekeeping device made to be carried in a pocket.", MT_METAL, 0.1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); + addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_DIGITALWATCH, "digital watch", "An electronic timekeeping device which shows the time as a number.", MT_METAL, 0.1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 85, NA, NULL); + addflag(lastot->flags, F_VALUE, 50, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_INSECTICIDE, "can of insecticide", "A spraycan containing poisonous chemicals.", MT_METAL, 0.5, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_SWAMP, 85, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 85, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 75, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERUSECHARGE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, "Where will you spray?"); @@ -4039,6 +4114,7 @@ void initobjects(void) { addot(OT_LANTERNLED, "LED lantern", "A low-powered but efficient lantern which will last almost forever.", MT_METAL, 0.5, OC_TECH, SZ_TINY); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 3, NA, NULL); @@ -4049,11 +4125,13 @@ void initobjects(void) { // tech - l2 addot(OT_TENT, "tent", "A easy to use, portable shelter made of fabric.", MT_CLOTH, 10, OC_TECH, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); + addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addflag(lastot->flags, F_HELPSREST, 15, 1, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addot(OT_FLASHBANG, "flashbang", "A stun grenade which temporarily blinds all within sight.", MT_METAL, 1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 90, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 60, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); @@ -4071,6 +4149,7 @@ void initobjects(void) { addot(OT_GRENADE, "grenade", "An explosive weapon which explodes a short time after activation.", MT_METAL, 1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 100, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -4087,6 +4166,7 @@ void initobjects(void) { addot(OT_GRENADESMOKE, "smoke grenade", "A device which once activated, will explode into a cloud of smoke upon impact.", MT_METAL, 1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 55, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -4104,6 +4184,7 @@ void initobjects(void) { addot(OT_C4, "block of c4", "An extremely explosive plastic which explodes a medium time after activation.", MT_PLASTIC, 1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 76, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -4118,11 +4199,13 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_MOTIONSCANNER, "motion scanner", "Small scanning device which detects nearby lifeforms.", MT_METAL, 1.5, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, NULL); + addflag(lastot->flags, F_VALUE, 200, NA, NA, NULL); addflag(lastot->flags, F_HOLDCONFER, F_DETECTLIFE, 10, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_NVGOGGLES, "nightvis goggles", "Special goggles which allow the wear to see in the dark.", MT_METAL, 1.5, OC_TECH, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, NULL); + addflag(lastot->flags, F_VALUE, 200, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); @@ -4132,6 +4215,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addot(OT_SOLDERINGIRON, "soldering iron", "A hand tool with an electrically heated metal tip. This unit is operated by an in-built battery.", MT_METAL, 0.5, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, RR_UNCOMMON, NA, NULL); + addflag(lastot->flags, F_VALUE, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_HEAT, 5, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); @@ -4142,6 +4226,7 @@ void initobjects(void) { addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addot(OT_STYPTIC, "styptic", "A medical compound designed to inhibit bleeding.", MT_METAL, 0.5, OC_TECH, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 65, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); @@ -4152,6 +4237,7 @@ void initobjects(void) { addot(OT_INFOVISOR, "infovisor", "Sleek looking metal visor which displays info directly into the retina.", MT_METAL, 0.2, OC_TECH, SZ_SMALL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, NULL); + addflag(lastot->flags, F_VALUE, 125, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_EXTRAINFO, B_TRUE, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ENHANCESEARCH, 10, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_ADEPT, NA, NA, NULL); @@ -4159,18 +4245,21 @@ void initobjects(void) { addot(OT_LOCKHACKER, "lock hacker", "A sophisticated machine to manipulate physical locks.", MT_METAL, 3, OC_TECH, SZ_TINY); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 78, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_ADEPT, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_PORTLADDER, "portable ladder", "A lightweight two metre ladder which automatically folds down to pocket size.", MT_METAL, 2, OC_TECH, SZ_TINY); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 83, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_ADEPT, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); // tech - l4 addot(OT_JETPACK, "jet pack", "A portable ion-thruster which allows the wearer to fly.", MT_METAL, 10, OC_TECH, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 68, RR_RARE, NULL); + addflag(lastot->flags, F_VALUE, 200, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RNDCHARGES, 10, 30, NA, NULL); @@ -4183,10 +4272,12 @@ void initobjects(void) { // tech - l5 addot(OT_TELEPAD, "teleport beacon", "A metal cone which will teleport the user to the nearest similar cone.", MT_METAL, 3, OC_TECH, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 68, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_EXPERT, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_XRAYGOGGLES, "pair of xray goggles", "Bulky looking goggles which allow you to see through walls.", MT_METAL, 0.3, OC_TECH, SZ_TINY); + addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_XRAYVIS, 2, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 60, RR_RARE, NULL); @@ -5337,9 +5428,17 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); // rings + addot(OT_RING_EDUCATION, "ring of education", "Boosts earned XP and Skill points.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_LEARNBOOST, 35, NA, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); addot(OT_RING_ENDURANCE, "ring of endurance", "Boosts stamina regeneration.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); addflag(lastot->flags, F_EQUIPCONFER, F_STAMREGEN, NA, NA, "0.5"); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_RING_GREED, "ring of greed", "Much sought after by treasure hunters, this ring detects the presence of any nearby objects.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_DETECTOBS, 10, NA, NULL); addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL); addot(OT_RING_SIGHT, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); @@ -5419,10 +5518,41 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); addflag(lastot->flags, F_EQUIPCONFER, F_RESISTMAG, 5, NA, NULL); addflag(lastot->flags, F_VALUE, 350, NA, NA, NULL); + addot(OT_RING_MEDITATION, "ring of meditation", "Allows the wearer to rest by entering a state of meditation.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_MEDITATES, B_TRUE, NA, NULL); + addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL); addot(OT_RING_MIRACLES, "ring of miracles", "Grants a limited number of miracles to the wearer.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); addflag(lastot->flags, F_CHARGES, 1, 3, NA, NULL); addflag(lastot->flags, F_VALUE, 400, NA, NA, NULL); + addot(OT_RING_MPBOOST, "ring of arcane power", "Increases the power of the wearer's spells.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_MAGICBOOST, 1, NA, NULL); + addot(OT_RING_NOINJURY, "ring of injury prevention", "Completely protects the wearer from crippling body injuries.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_VALUE, 350, NA, NA, NULL); + addot(OT_RING_DECELERATION, "ring of deceleration", "Protects the wearer from projectile attacks.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_PROJECTILE, B_TRUE, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_RING_DETECTLIFE, "ring of detect life", "Warns the wearer about any nearby lifeforms.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_DETECTLIFE, 5, NA, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_RING_REFLECTION, "ring of reflection", "Bounces any projectiles which hit the wearer back to their source.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_REFLECTION, B_TRUE, NA, NULL); + addflag(lastot->flags, F_VALUE, 350, NA, NA, NULL); + addot(OT_RING_STENCH, "ring of stench", "Causes the wearer to emit a foul stench.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_STENCH, 2, 1, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_RING_WATERBREATHING, "ring of water breathing", "Allows the wearer to breath normally while underwater.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_BREATHWATER, B_TRUE, NA, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); // unarmed weapons - note these damage/accuracys can be // overridded with the lifeform flag F_HASATTACK @@ -8309,7 +8439,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 3, NA, NA, NULL); addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); // plants - addrace(R_CACTUS, "cactus", 30, 'F', C_YELLOW, MT_PLANT, RC_PLANT, "A wide upright plant coated with sharp spines. Said to sprout delicious fruit."); + addrace(R_CACTUS, "cactus", 30, 'F', C_BOLDGREEN, MT_PLANT, RC_PLANT, "A wide upright plant coated with sharp spines. Said to sprout delicious fruit."); addbodypart(lastrace, BP_BODY, "stalk"); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_HARMLESS, B_TRUE, NA, NA, NULL); @@ -8323,7 +8453,8 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4"); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); - addrace(R_DREAMFUNGUS, "dreamfungus", 0.5, 'F', C_MAGENTA, MT_PLANT, RC_PLANT, "A huge, spotty, purple mold which releases speed-inducing spores on the slightest contact."); + + addrace(R_FUNGUSDREAM, "dreamfungus", 0.5, 'F', C_MAGENTA, MT_PLANT, RC_PLANT, "A huge, spotty, purple mold which releases speed-inducing spores on the slightest contact."); addbodypart(lastrace, BP_BODY, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL); @@ -8338,10 +8469,73 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4"); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); + addrace(R_FUNGUSRAGE, "ragefungus", 0.5, 'F', C_RED, MT_PLANT, RC_PLANT, "This deep red fungus protects itself by explelling rage-inducing pheremones, causing predators to attack each other instead of it."); + addbodypart(lastrace, BP_BODY, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_HARMLESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "1-4 shiitake mushrooms"); + addflag(lastrace->flags, F_DOESNTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOPRINTS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4"); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); + + addrace(R_IVYRAPID, "rapid ivy", 1, 'F', C_CYAN, MT_PLANT, RC_PLANT, "A strain of ivy which reproduces with incredible speed. Farmers find it difficult to remove due to its sharp spines."); + addbodypart(lastrace, BP_BODY, "stalk"); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DOESNTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOPRINTS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4"); + addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "passionfruit"); + addflag(lastrace->flags, F_RETALIATE, 1, 1, DT_PIERCE, "sharp spines"); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_CLONE, 0, 100, "pw:1;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_CLONE, NA, NA, "grows"); + + addrace(R_NUTTER, "nutter", 0.5, 'F', C_BROWN, MT_PLANT, RC_PLANT, "Nutters are dense brown bushes covered by clumps of hard-shelled nuts. When threatened, they can propel these nuts towards their predators at very high speeds."); + addbodypart(lastrace, BP_BODY, NULL); + addbodypart(lastrace, BP_HANDS, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HARMLESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "5-10 peanuts"); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "5-10 peanuts"); + addflag(lastrace->flags, F_WILLTHROW, OT_NUT, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_THROWING, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_DOESNTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOPRINTS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4"); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); + addrace(R_SAWGRASS, "sawgrass", 1, 'F', C_GREY, MT_METAL, RC_PLANT, "Razor sharp metallic grass with serrated edges. This plant senses vibrations in the air around it and lashes out with its sharp fronds."); addbodypart(lastrace, BP_BODY, "stalk"); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); @@ -8354,6 +8548,7 @@ void initrace(void) { addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); // end plants // animals @@ -8427,7 +8622,7 @@ void initrace(void) { addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); - addrace(R_BEAR, "black bear", 150, 'q', C_BLUE, MT_FLESH, RC_ANIMAL, "A medium sized omnivore bear."); + addrace(R_BEAR, "black bear", 150, 'Q', C_BLUE, MT_FLESH, RC_ANIMAL, "A medium sized omnivore bear."); setbodytype(lastrace, BT_QUADRAPED); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); @@ -8453,7 +8648,7 @@ void initrace(void) { addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "bear cub"); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'q', C_YELLOW, MT_FLESH, RC_ANIMAL, "A large angry bear."); + addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'Q', C_YELLOW, MT_FLESH, RC_ANIMAL, "A large angry bear."); setbodytype(lastrace, BT_QUADRAPED); lastrace->baseid = R_BEAR; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -9809,6 +10004,29 @@ void initrace(void) { addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 0, NA, NA, NULL); addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addrace(R_STINKBUG, "stinkbeetle", 1, 'x', C_MAGENTA, MT_FLESH, RC_INSECT, "A dog-sized beetle with tough scales. Emits a foul odour upon death."); + setbodytype(lastrace, BT_QUADRAPED); + addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+0"); + addflag(lastrace->flags, F_ARMOURRATING, 10, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, 1, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_STINGACID, NA, NA, "dam:1d1;"); + addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 0, NA, NA, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CORPSEFLAG, F_STENCH, 1, 3, NULL); // demons addrace(R_DRETCH, "dretch", 30, '&', C_BROWN, MT_FLESH, RC_DEMON, "An ape-like creature with extended forearms ending in clawed hands. They stand about 4 feet tall and weigh 60 pounds."); @@ -10250,12 +10468,12 @@ void initskills(void) { addskilldesc(SK_COOKING, PR_EXPERT, "^gYou can now cook recipes using up to 5 ingredients.", B_TRUE); addskilldesc(SK_COOKING, PR_MASTER, "^gYou can now 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); - addskilldesc(SK_EVASION, PR_ADEPT, "^gIncreases your EV by 15%.^n", B_FALSE); - addskilldesc(SK_EVASION, PR_SKILLED, "^gIncreases your EV by 20%.^n", B_FALSE); - addskilldesc(SK_EVASION, PR_EXPERT, "^gIncreases your EV by 25%.^n", B_FALSE); - addskilldesc(SK_EVASION, PR_MASTER, "^gIncreases your EV by 30%.^n", B_FALSE); + addskilldesc(SK_EVASION, PR_NOVICE, "^gIncreases your EV by 12%.^n", B_FALSE); + addskilldesc(SK_EVASION, PR_BEGINNER, "^gIncreases your EV by 24%.^n", B_FALSE); + addskilldesc(SK_EVASION, PR_ADEPT, "^gIncreases your EV by 36%.^n", B_FALSE); + addskilldesc(SK_EVASION, PR_SKILLED, "^gIncreases your EV by 48%.^n", B_FALSE); + addskilldesc(SK_EVASION, PR_EXPERT, "^gIncreases your EV by 60%.^n", B_FALSE); + addskilldesc(SK_EVASION, PR_MASTER, "^gIncreases your EV by 72%.^n", B_FALSE); addskill(SK_FIRSTAID, "First Aid", "Increases your healing rate and reduces duration of poison.", 0); // untrainable addskilldesc(SK_FIRSTAID, PR_INEPT, "- Lets you recognise how healthy your opponents are.", B_FALSE); addskilldesc(SK_FIRSTAID, PR_INEPT, "- Determines how fast you heal when resting. ", B_FALSE); @@ -10561,6 +10779,32 @@ void initskills(void) { } } +void killcommand(command_t *cmd) { + command_t *nextone, *lastone; + + // free mem + if (cmd->desc) free(cmd->desc); + + // remove from list + nextone = cmd->next; + if (nextone != NULL) { + nextone->prev = cmd->prev; + } else { /* last */ + lastcommand = cmd->prev; + } + + if (cmd->prev == NULL) { + /* first */ + nextone = cmd->next; + free(firstcommand); + firstcommand = nextone; + } else { + lastone = cmd->prev; + free (lastone->next ); + lastone->next = nextone; + } +} + void make_basic_shop(flagpile_t *fp) { addflag(fp, F_SHOPMENU, 0, MA_GOTOMENU, SM_PURCHASEITEMS, "a:buy something"); addflag(fp, F_SHOPMENU, 1, MA_QUIT, NA, "q:leave"); diff --git a/data.h b/data.h index e2a1d24..e5ffbe8 100644 --- a/data.h +++ b/data.h @@ -7,5 +7,6 @@ void initjobs(void); void initobjects(void); void initrace(void); void initskills(void); +void killcommand(command_t *cmd); void make_basic_shop(flagpile_t *fp); void sortcommands(void); diff --git a/data/hiscores.db b/data/hiscores.db index 77ed758..a97f37a 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 0307da2..f758e4b 100644 --- a/defs.h +++ b/defs.h @@ -1,6 +1,7 @@ #ifndef __DEFS_H #define __DEFS_H +//#include "findleak.h" // MACROS #define MAXOF(a,b) (a > b ? a : b) @@ -20,7 +21,8 @@ // Defaults #define DEF_AIFOLLOWTIME (50) // if target lf is out of view // for this many turns, abandon chase -#define DEF_ANIMDELAY (1000000 / 50) // 1/100 of a second +//#define DEF_ANIMDELAY (1000000 / 50) // 1/100 of a second +#define DEF_ANIMDELAY (1000000 / 25) // 1/50 of a second #define DEF_RESTHEALTIME (3) #define DEF_SCREENW 80 @@ -902,7 +904,10 @@ enum RACE { R_EELGIANT, // plants R_CACTUS, - R_DREAMFUNGUS, + R_IVYRAPID, + R_FUNGUSDREAM, + R_FUNGUSRAGE, + R_NUTTER, R_SAWGRASS, // animals R_ANT, @@ -955,6 +960,7 @@ enum RACE { R_GLOWBUG, R_GIANTFLY, R_GIANTBLOWFLY, + R_STINKBUG, R_STIRGE, // demons R_DRETCH, @@ -1058,7 +1064,7 @@ enum OBTYPE { OT_STAIRSDOWN, OT_STAIRSUP, OT_PORTAL, - // buildings + // buildings - rememebr to update MAXBUILDINGTYPES! OT_MOTEL, OT_SHOPARMOUR, OT_SHOPBOOK, @@ -1135,6 +1141,7 @@ enum OBTYPE { OT_MUSHROOMTOAD, OT_MUSHROOMSTUFFED, OT_NUT, + OT_PASSIONFRUIT, OT_ROASTMEAT, OT_RUMBALL, OT_SALT, @@ -1372,6 +1379,7 @@ enum OBTYPE { OT_S_WARPWOOD, OT_S_WATERJET, // -- summoning + OT_S_CLONE, OT_S_CREATEFOOD, OT_S_FLOATINGDISC, OT_S_FRIENDS, @@ -1649,23 +1657,33 @@ enum OBTYPE { OT_SHIELDTOWER, // rings OT_RING_ENDURANCE, + OT_RING_GREED, OT_RING_INVIS, OT_RING_INVULN, OT_RING_LUCK, OT_RING_CONTROL, OT_RING_CON, + OT_RING_DECELERATION, + OT_RING_DETECTLIFE, OT_RING_DEX, + OT_RING_EDUCATION, OT_RING_HUNGER, OT_RING_IQ, OT_RING_STR, OT_RING_MANA, + OT_RING_MEDITATION, OT_RING_MIRACLES, + OT_RING_MPBOOST, OT_RING_MPREGEN, + OT_RING_NOINJURY, OT_RING_PROTFIRE, OT_RING_PROTCOLD, + OT_RING_REFLECTION, OT_RING_REGENERATION, OT_RING_RESISTMAG, OT_RING_SIGHT, + OT_RING_STENCH, + OT_RING_WATERBREATHING, OT_RING_WOUNDING, // innate / animal weapons OT_BEAK, @@ -1780,6 +1798,8 @@ enum OBTYPE { }; +#define MAXBUILDINGTYPES (10) + #define BP_NONE (-1) enum BODYPART { @@ -2364,6 +2384,7 @@ enum FLAG { F_SNEAK, // moving slowly on purpose to avoid slipping. F_AUTOCMD, // val0 = how many times to repeat this F_LASTCMD, // text[0] = last command performed, v0/1 = x/y of cell, v2=various + F_WILLTHROW, // this lf will treat obid v0 as a thrown missile. F_CANLEARN, // lf is able to learn skill val0 // v1 = max lev F_STARTOB, // val0 = %chance of starting with it, text = ob name @@ -2439,7 +2460,7 @@ enum FLAG { // our targets out of the room. F_FALLDISTANCE, // how many floors this lf has fallen through. // ABILITY/SPELL FLAGS / ability flags / spell flags - F_FAILEDINSPECT, // lf has failed an inspect check for item id v0 + F_FAILEDINSPECT, // lf has failed an inspect check for objecttype v0 F_TARGETTEDSPELL, // this spell needs you to specify a target cell // v0 is the tt_targettype F_BOOSTSPELL, // v0 is active boost spell, v1 is ongoing mpcost, v2 is power @@ -2485,6 +2506,7 @@ enum FLAG { // when at zero, lf vanishes. F_OWNSSHOP, // v0 is roomid of the shop which this shopkeeper owns. F_GUARD, // this lf is a guard, who can be called by shopkeepers + F_HATESALL, // lf will attack ALL other lfs on sight F_HATESRACE, // lf will attack lfs with race=v0 or baseid=v0 on // sight F_HATESRACEWITHFLAG, // lf will attack lfs with flag v0 on sight @@ -2717,6 +2739,7 @@ enum FLAG { F_FROZEN, // made of ice F_HOLYAURA, // holy aura - attacks deal holy damage to vulnerable // enemies. + F_LEARNBOOST, // +v0% xp and skillxp F_LEVITATING, // like flying but uncontrolled F_MAGSHIELD,// magnetic shield F_NAUSEATED, // lf has a stench penalty of v0 (-v0*10 to hit). @@ -3274,6 +3297,11 @@ typedef struct glyph_s { int colour; } glyph_t; +typedef struct buildingusage_s { + enum OBTYPE oid; + int count; +} buildingusage_t; + typedef struct hiddennamewithcol_s { char *name; enum COLOUR col; @@ -3378,6 +3406,7 @@ typedef struct lifeform_s { int att[MAXATTS]; int baseatt[MAXATTS]; + int origatt[MAXATTS]; float forgettimer; @@ -3400,7 +3429,7 @@ typedef struct lifeform_s { int losdirty; int nlos; cell_t **los; - int *viscell; + //int *viscell; int visw; int visrange; int eyeadjustment; // have your eyes adjusted to the dark? @@ -3566,6 +3595,8 @@ typedef struct object_s { int blessknown; int amt; // for stackable objects long birthtime; + int dying; // not saved, just used to avoid flag messages for dying + // objects. flagpile_t *flags; struct obpile_s *contents; diff --git a/doc/add_building.txt b/doc/add_building.txt new file mode 100644 index 0000000..d3c7a22 --- /dev/null +++ b/doc/add_building.txt @@ -0,0 +1,7 @@ +defs.h + add OT_xxx + inc MAXBUILDINGTYPES +data.c + define it +shops.c + update details diff --git a/doc/dungeon_layout.txt b/doc/dungeon_layout.txt new file mode 100644 index 0000000..319da00 --- /dev/null +++ b/doc/dungeon_layout.txt @@ -0,0 +1,4 @@ +1: first dungeon level +6: jimbo's lair +7-10: swamp +25: godstone diff --git a/doc/glyphs.txt b/doc/glyphs.txt index 9575483..ccf3e4f 100644 --- a/doc/glyphs.txt +++ b/doc/glyphs.txt @@ -9,33 +9,33 @@ UNI_SOLID = deep water A = avian / bird a = ant B = bat +c = cockatricoe C = celestial / divine ? d = canine/dog e = eye f = feline/cat F = flora (flowers, plants, etc) g = goblin +G = large goblin +h = humanoid +H = large humanoid i = insect j = jelly/ooze/leech k = kobold -G = large goblin m = mutant n = small humanoid / nymph / sprite o = orc O = ogre p = sPirit -c = cockatricoe q = quadraped Q = large quadraped r = rodent R = robot s = snake S = spider -h = humanoid -H = large humanoid U = unearthly/horrific creature -w = worm V = vampire +w = worm x = small creature/monster X = unknown thing! y/Y = air related creatures like clouds of gas, air elemental diff --git a/flag.c b/flag.c index 3cab249..ec0dbd2 100644 --- a/flag.c +++ b/flag.c @@ -901,7 +901,7 @@ void killflag(flag_t *f) { setstamina(lf, 0); } - } else if (f->pile->ob) { + } else if (f->pile->ob && !isdeadob(f->pile->ob)) { announceobflagloss(f->pile->ob, f); } } diff --git a/io.c b/io.c index 715b78d..ac9acb8 100644 --- a/io.c +++ b/io.c @@ -33,6 +33,9 @@ int statdirty = B_TRUE; int inaskcoords = B_FALSE; // are we inside this function? +extern buildingusage_t buildingusage[]; +extern int nbuildingusage; + int hascolour = B_TRUE; int noredraw = B_FALSE; @@ -357,10 +360,11 @@ void animline(cell_t *src, cell_t *dst, int gradual, char ch, char ch2, int colo needredraw = B_TRUE; } -void animradial(cell_t *src, int radius, char ch, int colour) { +void animradial(cell_t *src, int radius, int ch,int colour, int dirtype, char *seetext, char *noseetext) { glyph_t gl; int i; int x,y; + int nseen = 0; cell_t *c; gl.ch = ch; @@ -372,71 +376,64 @@ void animradial(cell_t *src, int radius, char ch, int colour) { // hide cursor curs_set(0); - for (i = 0; i <= radius; i++) { - int drawn = B_FALSE; - for (y = src->y - radius ; y <= src->y + radius ; y++) { - for (x = src->x - radius ; x <= src->x + radius ; x++) { - c = getcellat(src->map, x, y); - if (c && haslos(player, c) && (getcelldist(src, c) <= i)) { - // draw char & cursor at its current pos... - //mvwprintw(gamewin, c->y - viewy, c->x - viewx, "%c", ch); - drawglyph(&gl, c->x - viewx, c->y - viewy); - drawn = B_TRUE; + if (dirtype == DT_ORTH) { + for (i = 0; i <= radius; i++) { + int drawn = B_FALSE; + for (y = src->y - radius ; y <= src->y + radius ; y++) { + for (x = src->x - radius ; x <= src->x + radius ; x++) { + c = getcellat(src->map, x, y); + if (c && haslos(player, c) && (getcelldistorth(src, c) <= i)) { + // draw char & cursor at its current pos... + //mvwprintw(gamewin, c->y - viewy, c->x - viewx, "%c", ch); + drawglyph(&gl, c->x - viewx, c->y - viewy); + drawn = B_TRUE; + nseen++; + } } } - } - wrefresh(gamewin); - if (drawn) { - usleep(DEF_ANIMDELAY); + if (drawn) { + wrefresh(gamewin); + usleep(DEF_ANIMDELAY); + } + } + } else { // radial + for (i = 0; i <= radius; i++) { + int drawn = B_FALSE; + + for (y = src->y - radius ; y <= src->y + radius ; y++) { + for (x = src->x - radius ; x <= src->x + radius ; x++) { + c = getcellat(src->map, x, y); + if (c && haslos(player, c) && (getcelldist(src, c) <= i)) { + // draw char & cursor at its current pos... + //mvwprintw(gamewin, c->y - viewy, c->x - viewx, "%c", ch); + drawglyph(&gl, c->x - viewx, c->y - viewy); + drawn = B_TRUE; + nseen++; + } + } + } + + if (drawn) { + wrefresh(gamewin); + usleep(DEF_ANIMDELAY); + } } } - // show cursor - curs_set(1); - - needredraw = B_TRUE; -} - -void animradialorth(cell_t *src, int radius, char ch,int colour) { - glyph_t gl; - int i; - int x,y; - cell_t *c; - - gl.ch = ch; - gl.colour = colour; - - // update screen - updateviewfor(src); - drawlevelfor(player); - - // hide cursor - curs_set(0); - for (i = 0; i <= radius; i++) { - int drawn = B_FALSE; - - - for (y = src->y - radius ; y <= src->y + radius ; y++) { - for (x = src->x - radius ; x <= src->x + radius ; x++) { - c = getcellat(src->map, x, y); - if (c && haslos(player, c) && (getcelldistorth(src, c) <= i)) { - // draw char & cursor at its current pos... - //mvwprintw(gamewin, c->y - viewy, c->x - viewx, "%c", ch); - drawglyph(&gl, c->x - viewx, c->y - viewy); - drawn = B_TRUE; - } - } - } - - wrefresh(gamewin); - if (drawn) { - usleep(DEF_ANIMDELAY); + if (nseen) { + if (seetext && haslos(player, src)) { + msg(seetext); + more(); + } else if (noseetext) { + msg(noseetext); + more(); } } // show cursor curs_set(1); needredraw = B_TRUE; + drawscreen(); } @@ -1585,6 +1582,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s %s surrounded by a holy aura!", lfname, isplayer(lf) ? "are" : "is"); donesomething = B_TRUE; break; + case F_LEARNBOOST: + if (isplayer(lf)) { + msg("You feel more receptive to new knowledge!"); + donesomething = B_TRUE; + } + break; case F_LEVITATING: msg("%s begin%s to levitate in the air!",lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; @@ -2168,6 +2171,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { msg("%s%s holy aura vanishes.", lfname, getpossessive(lfname)); donesomething = B_TRUE; break; + case F_LEARNBOOST: + if (isplayer(lf)) { + msg("You no longer feel receptive to new knowledge."); + donesomething = B_TRUE; + } + break; case F_LEVITATING: msg("%s %s down to the ground.", lfname, isplayer(lf) ? "float" : "floats"); donesomething = B_TRUE; @@ -2515,7 +2524,6 @@ lifeform_t *askgod(char *prompttext, int onlyprayed) { snprintf(godof, BUFLEN, " (%s of %s)", (f->val[0] == B_FEMALE) ? "goddess" : "god", f->text); strcat(buf, godof); - makedesc_god(lf, longdesc); addchoice(&prompt, tolower(buf[0]), buf, NULL, lf, longdesc); } @@ -2546,13 +2554,6 @@ object_t *askobjectwithflag(obpile_t *op, char *prompt, int *count, char action, return doaskobject(op, prompt, count, B_TRUE, B_TRUE, B_FALSE, action, opts, withflag, F_NONE); } -/* -object_t *askobjectofclass(obpile_t *op, char *prompt, int *count, long opts, enum OBCLASS obclass) { - return doaskobject(op, prompt, count, opts, F_NONE, obclass, OC_NULL); -} -*/ - - int contains(enum OBCLASS *array, int nargs, enum OBCLASS want) { int i; for (i = 0; i < nargs; i++) { @@ -3711,7 +3712,6 @@ void docomms(lifeform_t *lf) { c = askcoords(buf, buf2, TT_MONSTER, lf, UNLIMITED, LOF_DONTNEED, B_FALSE); if (c && c->lf) { lf2 = c->lf; - } if (!lf2) { msg("Cancelled."); @@ -3720,7 +3720,7 @@ void docomms(lifeform_t *lf) { getlfname(lf2, lfname2); msg("You say \"Attack %s!\" to %s.",isplayer(lf2) ? "me" : lfname2, lfname); - if (lfhasflag(c->lf, F_RAGE) || !canhear(c->lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { msg("%s doesn't respond.", lfname); break; } @@ -3746,7 +3746,7 @@ void docomms(lifeform_t *lf) { break; case 'c': msg("You say \"Come here!\" to %s.",lfname); - if (lfhasflag(c->lf, F_RAGE) || !canhear(c->lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { msg("%s doesn't respond.", lfname); break; } @@ -3902,7 +3902,7 @@ void docomms(lifeform_t *lf) { // stop attacking all current targets first... killflagsofid(lf->flags, F_TARGETLF); msg("You say \"Go over there!\" to %s.", lfname); - if (lfhasflag(c->lf, F_RAGE) || !canhear(c->lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { msg("%s doesn't respond.", lfname); break; } @@ -3911,7 +3911,7 @@ void docomms(lifeform_t *lf) { case 'j': // charisma check to see if they'll join you. msg("You say \"Join me on my quest!\" to %s.", lfname); - if (lfhasflag(c->lf, F_RAGE) || !canhear(c->lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { msg("%s doesn't respond.", lfname); break; } @@ -3957,7 +3957,7 @@ void docomms(lifeform_t *lf) { break; case 'r': msg("You say \"Get some rest.\" to %s.", lfname); - if (lfhasflag(c->lf, F_RAGE) || !canhear(c->lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { msg("%s doesn't respond.", lfname); break; } @@ -4011,7 +4011,7 @@ void docomms(lifeform_t *lf) { break; case '<': msg("You say \"Stay close!\" to %s.", lfname); - if (lfhasflag(c->lf, F_RAGE) || !canhear(c->lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { msg("%s doesn't respond.", lfname); break; } @@ -4019,7 +4019,7 @@ void docomms(lifeform_t *lf) { break; case '>': msg("You say \"Keep your distance!\" to %s.", lfname); - if (lfhasflag(c->lf, F_RAGE) || !canhear(c->lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { msg("%s doesn't respond.", lfname); break; } @@ -4374,9 +4374,50 @@ void dolook(cell_t *where, int onpurpose) { } msg("You %s %s here.", seeverb, buf); } - } else if ((numobs > 1) && (numobs <= 3)) { + } else if (numobs == 2) { + char buf2[BUFLEN]; + object_t *secondob; + secondob = firstob->next; + if (hasflag(firstob->flags, F_THEREISHERE)) { + strcpy(buf, ""); // don't show it + } else { + if (streq(seeverb, "feel")) { + f = hasflag(firstob->flags, F_FEELTEXT); + if (f) { + strcpy(buf, f->text); + } else { + getobname(firstob, buf, firstob->amt); + } + } else { + getobname(firstob, buf, firstob->amt); + } + } + if (hasflag(secondob->flags, F_THEREISHERE)) { + strcpy(buf2, ""); // don't show it + } else { + if (streq(seeverb, "feel")) { + f = hasflag(secondob->flags, F_FEELTEXT); + if (f) { + strcpy(buf2, f->text); + } else { + getobname(secondob, buf2, secondob->amt); + } + } else { + getobname(secondob, buf2, secondob->amt); + } + } + if (!strlen(buf) && !strlen(buf2)) { + // both obs shown later! + } else if (!strlen(buf)) { + msg("You %s %s here.", seeverb, buf2); + } else if (!strlen(buf2)) { + msg("You %s %s here.", seeverb, buf); + } else { + msg("You %s %s and %s here.", seeverb, buf, buf2); + } + } else if ((numobs >= 3) && (numobs <= 4)) { msg("You %s a few things here.", seeverb); - } else if ((numobs > 3) && (numobs <= 6)) { + } else if ((numobs >= 5) && (numobs <= 6)) { msg("You %s some things here.", seeverb); } else if (numobs > 6) { msg("You %s many things here.", seeverb); @@ -5071,6 +5112,17 @@ char *makedesc_ob(object_t *o, char *retbuf) { } strncat(retbuf, buf, HUGEBUFLEN); } + } else if (o->type->id == OT_CREDITCARD) { + if (isidentified(o)) { + int charges; + charges = getcharges(o); + if (charges) { + sprintf(buf, "It has $%d remaining until its limit.\n",charges); + } else { + sprintf(buf, "It is maxed out.\n"); + } + strncat(retbuf, buf, HUGEBUFLEN); + } } f = hasflag(o->flags, F_PICKLOCKS); @@ -5349,11 +5401,11 @@ char *makedesc_ob(object_t *o, char *retbuf) { strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DETECTLIFE: - sprintf(buf2, "%s will detect nearby lifeforms.\n", buf); + sprintf(buf2, "%s lets you detect nearby lifeforms.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DETECTOBS: - sprintf(buf2, "%s will detect nearby objects.\n", buf); + sprintf(buf2, "%s lets you detect nearby objects.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DETECTMAGIC: @@ -5486,12 +5538,20 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf2, "%s surrounds you with a holy aura.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; + case F_LEARNBOOST: + sprintf(buf2, "%s grants a bonus to earned experience points.\n", buf); + strncat(retbuf, buf2, HUGEBUFLEN); + break; case F_LEVITATING: sprintf(buf2, "%s causes you to levitate.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_MAGICBOOST: - sprintf(buf2, "%s boosts the power of your spells by %d.\n", buf, f->val[0]); + sprintf(buf2, "%s boosts the power of your spells by %d.\n", buf, f->val[1]); + strncat(retbuf, buf2, HUGEBUFLEN); + break; + case F_MEDITATES: + sprintf(buf2, "%s allows you to retain awareness while resting.", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_MAGSHIELD: @@ -5530,10 +5590,6 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf2, "%s produces light.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; - case F_REFLECTION: - sprintf(buf2, "%s reflects all missiles back to their source.\n", buf); - strncat(retbuf, buf2, HUGEBUFLEN); - break; case F_RETALIATE: sprintf(buf2, "%s protects you with %s.\n", buf, f->text); strncat(retbuf, buf2, HUGEBUFLEN); @@ -5542,6 +5598,10 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf2, "%s makes you enraged.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; + case F_REFLECTION: + sprintf(buf2, "%s reflects all projectiles back to their source.\n", buf); + strncat(retbuf, buf2, HUGEBUFLEN); + break; case F_REGENERATES: if (f->val[1] == 1) { strcpy(buf3, ""); @@ -5875,7 +5935,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { strcpy(buf, ""); for (n = 0; n < MAXDAMTYPE; n++) { if (basedamagetype(n) != n) continue; - if (isimmuneto(r->flags, n, B_FALSE)) { + if (isresistantto(r->flags, n, B_FALSE)) { if (first) { sprintf(buf2, "Resistant to: %s", getdamname(n)); first = B_FALSE; @@ -5889,30 +5949,6 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { addflag(doneflags, F_DTRESIST, B_TRUE, NA, NA, NULL); } break; - case F_DTVULN: - if (!hasflag(doneflags, F_DTVULN)) { - if (f->val[0] == DT_ALL) { - sprintf(buf, "Vulnerable to %s.", getdamname(DT_ALL)); - } else { - char buf2[BUFLEN]; - int first = B_TRUE,n; - strcpy(buf, ""); - for (n = 0; n < MAXDAMTYPE; n++) { - if (basedamagetype(n) != n) continue; - if (isimmuneto(r->flags, n, B_FALSE)) { - if (first) { - sprintf(buf2, "Vulnerable to: %s", getdamname(n)); - first = B_FALSE; - } else { - sprintf(buf2, ", %s", getdamname(n)); - } - strcat(buf, buf2); - } - } - } - addflag(doneflags, F_DTVULN, B_TRUE, NA, NA, NULL); - } - break; case F_ENHANCESMELL: sprintf(buf, "Enhanced sense of smell (range %d)", f->val[0]); break; case F_FLYING: sprintf(buf, "Can fly at will"); break; case F_HEAVYBLOW: sprintf(buf, "Attacks will knock enemies backwards"); break; @@ -5983,12 +6019,36 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { case F_CARNIVORE: sprintf(buf, "Will only eat meat."); break; case F_DEAF: sprintf(buf, "Deaf"); break; case F_DIURNAL: sprintf(buf, "Sleeps at night."); break; + case F_DTVULN: + if (!hasflag(doneflags, F_DTVULN)) { + if (f->val[0] == DT_ALL) { + sprintf(buf, "Vulnerable to %s.", getdamname(DT_ALL)); + } else { + char buf2[BUFLEN]; + int first = B_TRUE,n; + strcpy(buf, ""); + for (n = 0; n < MAXDAMTYPE; n++) { + if (basedamagetype(n) != n) continue; + if (isvulnto(r->flags, n, B_FALSE)) { + if (first) { + sprintf(buf2, "Vulnerable to: %s", getdamname(n)); + first = B_FALSE; + } else { + sprintf(buf2, ", %s", getdamname(n)); + } + strcat(buf, buf2); + } + } + } + addflag(doneflags, F_DTVULN, B_TRUE, NA, NA, NULL); + } + break; case F_FASTMETAB: sprintf(buf, "Fast metabolism (needs to eat often)"); break; case F_MATVULN: mt = findmaterial(f->val[0]); sprintf(buf, "Takes %d%% damage from weapons made of %s.", retflag[i]->val[1], mt->name); break; - case F_MPMOD: if (f->val[0] < 0) sprintf(buf, "-%d Mana", f->val[0]); break; + case F_MPMOD: if (f->val[0] < 0) sprintf(buf, "%d Mana", f->val[0]); break; case F_NEEDSWATER: sprintf(buf, "Will suffocate without water"); break; case F_NOCTURNAL: sprintf(buf, "Sleeps during the day."); break; case F_NOPACK: sprintf(buf, "Cannot carry objects."); break; @@ -6668,12 +6728,12 @@ void doexplain(char *question) { void dofinaloblist(obpile_t *op) { object_t *o; - o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE, AO_NONE, F_NONE); + o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE, '\0', AO_NONE, F_NONE); while (o) { // describe it describeob(o); // ask for another one - o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE, AO_NONE, F_NONE); + o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE,'\0', AO_NONE, F_NONE); } real_clearmsg(B_TRUE); } @@ -6808,7 +6868,7 @@ void doinventory(obpile_t *op) { maxweight = getmaxcarryweight(player); pct = (packweight / maxweight) * 100; snprintf(buf, BUFLEN, "Inventory (%0.0f/%0.0f kg, %0.0f%%)", packweight, maxweight, pct); - o = doaskobject(op, buf, NULL, B_TRUE, B_TRUE, B_FALSE, AO_NONE, F_NONE); + o = doaskobject(op, buf, NULL, B_TRUE, B_TRUE, B_FALSE, '\0', AO_NONE, F_NONE); while (o) { // describe it describeob(o); @@ -7139,41 +7199,6 @@ void dothrow(obpile_t *op) { } } -/* -void drawscannedcell(cell_t *cell, int x, int y) { - if (cell->lf) { - char glyph; - // draw glyph based on size - switch(getlfsize(cell->lf)) { - case SZ_ENORMOUS: - glyph = '6'; - break; - case SZ_HUGE: - glyph = '5'; - break; - case SZ_LARGE: - glyph = '4'; - break; - case SZ_HUMAN: - glyph = '3'; - break; - case SZ_MEDIUM: - glyph = '2'; - break; - case SZ_SMALL: - glyph = '1'; - break; - case SZ_MINI: - case SZ_TINY: - default: - glyph = '0'; - break; - } - mvwprintw(gamewin, y, x, "%c", glyph); - } -} -*/ - // returns TRUE if escape pressed int downline(int *y, int h, char *heading, char *subheading, char *bottomstring, char *cmdchars, char *retchar) { char headbuf[BUFLEN]; @@ -7641,6 +7666,17 @@ int drop(object_t *o, int count) { return B_FALSE; } +void dumpbuildingusage(void) { + int i; + objecttype_t *ot; + dblog("BEGIN BUILDING USAGE DUMP"); + for (i = 0; i < nbuildingusage; i++) { + ot = findot(buildingusage[i].oid); + dblog("'%s' used %d times", ot->name, buildingusage[i].count); + } + dblog("END BUILDING USAGE DUMP"); +} + void dumpoc(void) { enum RARITY rr; objectclass_t *oc; @@ -8001,7 +8037,7 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) { } } else { int yy; - char gamewinbuf[BUFLEN]; + int gamewinbuf[BUFLEN]; // copy text from gamewin for (yy = y ; yy < lastline; yy++) { mvwinchstr(gamewin, yy-2, 0, (chtype *)gamewinbuf); @@ -8043,7 +8079,7 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) { */ // show the remainder of what we have typed. // ('validchoice' was calculated earlier) - snprintf(remainder, BUFLEN, "^g%s",prompt->choice[validchoice].text + strlen(inpstring)); + snprintf(remainder, BUFLEN, "^g%s^n",prompt->choice[validchoice].text + strlen(inpstring)); textwithcol(mainwin, remainder); // move cursor back wmove(mainwin, cy, cx); diff --git a/io.h b/io.h index 7fcbe5c..adda93d 100644 --- a/io.h +++ b/io.h @@ -7,8 +7,8 @@ void addpromptq(prompt_t *p, char *q); void anim(cell_t *src, cell_t *dst, char ch, int colour); void animline(cell_t *src, cell_t *dst, int gradual, char ch, char ch2, int colour); void animcells(cell_t *src, cell_t **dst, int ndst, int gradual, char ch, char ch2, int colour); -void animradial(cell_t *src, int radius, char ch, int colour); -void animradialorth(cell_t *src, int radius, char ch, int colour); +//void animradial(cell_t *src, int radius, int ch, int colour); +void animradial(cell_t *src, int radius, int ch, int colour, int dirtype, char *text, char *noseetext); void animsky(cell_t *src, char ch, int colour); //void announceob(enum OBTYPE oid); void announcearrival(lifeform_t *lf, map_t *newmap); @@ -83,6 +83,7 @@ void drawmsg(void); void drawscreen(void); void drawstatus(void); int drop(object_t *o, int count); +void dumpbuildingusage(void); void dumpoc(void); void dumpspells(void); void dumpweps(void); diff --git a/lf.c b/lf.c index 8586a43..3e8ed34 100644 --- a/lf.c +++ b/lf.c @@ -2210,6 +2210,7 @@ void die(lifeform_t *lf) { object_t *corpse = NULL; flag_t *retflag[MAXCANDIDATES]; int nretflags; + cell_t *corpsecell; if (cansee(player, lf)) { needredraw = B_TRUE; @@ -2238,11 +2239,10 @@ void die(lifeform_t *lf) { return; } - if (!willbecomeghost) { if (isplayer(lf) && hasjob(lf, J_GOD)) { char ch; - msg("^BYou die..."); more(); + msg("^BYou are about to die..."); more(); ch = askchar("Die", "yn", "n", B_TRUE, B_FALSE); if (ch == 'n') { lf->hp = lf->maxhp; @@ -2394,13 +2394,24 @@ void die(lifeform_t *lf) { } } + // determine where to drop objects + corpsecell = lf->cell; + if (corpsecell && corpsecell->type->solid) { + // try the cell in front (in case they were climbing) + corpsecell = getcellindir(corpsecell, lf->facing); + // still solid? give up. + if (corpsecell && corpsecell->type->solid) { + corpsecell = NULL; + } + } + // drop/kill all objects - if (willbecomeghost || !isplayer(lf)) { + if (corpsecell && (willbecomeghost || !isplayer(lf))) { while (lf->pack->first) { if (vaporised) { killob(lf->pack->first); } else { - if (!moveob(lf->pack->first, lf->cell->obpile, ALL)) { + if (!moveob(lf->pack->first, corpsecell->obpile, ALL)) { killob(lf->pack->first); } } @@ -2408,121 +2419,123 @@ void die(lifeform_t *lf) { } // drop corpse/splatter blood - if (vaporised) { - switch (rnd(1,2)) { - case 1: - fragments(lf->cell, "chunk of flesh", 2, UNLIMITED); - break; - case 2: - fragments(lf->cell, "pool of blood", 2, UNLIMITED); - break; - } - } else if ((lf->lastdamtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) { - // shattered - fragments(lf->cell, "chunk of ice", 2, UNLIMITED); - } else { - if (lfhasflag(lf, F_NOCORPSE)) { - if (isundead(lf) && cansee(player, lf)) { - getlfname(lf, buf); - msg("%s crumbles to dust.", buf); + if (corpsecell) { + if (vaporised) { + switch (rnd(1,2)) { + case 1: + fragments(corpsecell, "chunk of flesh", 2, UNLIMITED); + break; + case 2: + fragments(corpsecell, "pool of blood", 2, UNLIMITED); + break; } - } else if (lf->lastdamtype == DT_MELT) { - // drop a pool of water - addob(lf->cell->obpile, "large puddle of water"); - } else if (lf->lastdamtype == DT_NECROTIC) { - int n; - int numbones = 0; - char bonestring[BUFLEN]; - for (n = 0; n < getlfsize(lf); n++) { - numbones += rnd(1,10); - } - // drop bones - snprintf(bonestring, BUFLEN, "%d bones",numbones); - addob(lf->cell->obpile, bonestring); + } else if ((lf->lastdamtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) { + // shattered + fragments(corpsecell, "chunk of ice", 2, UNLIMITED); } else { - char corpseprefix[BUFLEN]; - char corpsename[BUFLEN]; - - strcpy(corpseprefix, ""); - switch (lf->lastdamtype) { - case DT_COLD: - strcat(corpseprefix, "frozen "); - break; - default: - if (lfhasflag(lf, F_FROZEN)) { - strcat(corpseprefix, "frozen "); - } - break; - } - if (lfhasflag(lf, F_BEHEADED) && !lfhasflag(lf, F_CORPSETYPE)) { - strcat(corpseprefix, "headless "); - } - - f = lfhasflag(lf, F_CORPSETYPE); - if (f) { - snprintf(corpsename, BUFLEN, "%s%s", corpseprefix, f->text); + if (lfhasflag(lf, F_NOCORPSE)) { + if (isundead(lf) && cansee(player, lf)) { + getlfname(lf, buf); + msg("%s crumbles to dust.", buf); + } + } else if (lf->lastdamtype == DT_MELT) { + // drop a pool of water + addob(corpsecell->obpile, "large puddle of water"); + } else if (lf->lastdamtype == DT_NECROTIC) { + int n; + int numbones = 0; + char bonestring[BUFLEN]; + for (n = 0; n < getlfsize(lf); n++) { + numbones += rnd(1,10); + } + // drop bones + snprintf(bonestring, BUFLEN, "%d bones",numbones); + addob(corpsecell->obpile, bonestring); } else { - snprintf(corpsename, BUFLEN, "%s%s corpse", corpseprefix, lf->race->name); - } + char corpseprefix[BUFLEN]; + char corpsename[BUFLEN]; - corpse = addob(lf->cell->obpile, corpsename); - if (corpse) { - if ((lf->lastdamtype == DT_FIRE) && isflammable(corpse)) { - addflag(corpse->flags, F_ONFIRE, B_TRUE, NA, NA, NULL); + strcpy(corpseprefix, ""); + switch (lf->lastdamtype) { + case DT_COLD: + strcat(corpseprefix, "frozen "); + break; + default: + if (lfhasflag(lf, F_FROZEN)) { + strcat(corpseprefix, "frozen "); + } + break; + } + if (lfhasflag(lf, F_BEHEADED) && !lfhasflag(lf, F_CORPSETYPE)) { + strcat(corpseprefix, "headless "); } - // tainted? - if ((lf->lastdamtype == DT_POISONGAS) || lfhasflag(lf, F_POISONCORPSE) || lfhasflag(lf, F_POISONED)) { - addflag(corpse->flags, F_TAINTED, B_TRUE, NA, NA, NULL); + f = lfhasflag(lf, F_CORPSETYPE); + if (f) { + snprintf(corpsename, BUFLEN, "%s%s", corpseprefix, f->text); + } else { + snprintf(corpsename, BUFLEN, "%s%s corpse", corpseprefix, lf->race->name); } - // set colour based on monster - if (corpse->type->id == OT_CORPSE) { - colourmatchob(corpse, lf); - } + corpse = addob(corpsecell->obpile, corpsename); + if (corpse) { + if ((lf->lastdamtype == DT_FIRE) && isflammable(corpse)) { + addflag(corpse->flags, F_ONFIRE, B_TRUE, NA, NA, NULL); + } - // corpse of a player pet? - if (ispetof(lf, player)) { - addflag(corpse->flags, F_PETOF, player->id, NA, NA, NULL); - } + // tainted? + if ((lf->lastdamtype == DT_POISONGAS) || lfhasflag(lf, F_POISONCORPSE) || lfhasflag(lf, F_POISONED)) { + addflag(corpse->flags, F_TAINTED, B_TRUE, NA, NA, NULL); + } - // add extra flags ? - getflags(lf->flags, retflag, &nretflags, F_CORPSEFLAG, F_NONE); - for (i = 0; i < nretflags; i++) { - f = retflag[i]; - if (f->id == F_CORPSEFLAG) { - addflag(corpse->flags, f->val[0], f->val[1], f->val[2], NA, f->text); + // set colour based on monster + if (corpse->type->id == OT_CORPSE) { + colourmatchob(corpse, lf); + } + + // corpse of a player pet? + if (ispetof(lf, player)) { + addflag(corpse->flags, F_PETOF, player->id, NA, NA, NULL); + } + + // add extra flags ? + getflags(lf->flags, retflag, &nretflags, F_CORPSEFLAG, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (f->id == F_CORPSEFLAG) { + addflag(corpse->flags, f->val[0], f->val[1], f->val[2], NA, f->text); + } + } + + // remember what killed us. + f = hasflag(corpse->flags, F_CORPSEOF); + if (f) { + changeflagtext(f, lf->lastdam); } } - // remember what killed us. - f = hasflag(corpse->flags, F_CORPSEOF); - if (f) { - changeflagtext(f, lf->lastdam); + + if (hasflag(corpse->flags, F_HEADLESS)) { + object_t *headob; + char headname[BUFLEN]; + // drop head too + snprintf(headname, BUFLEN, "%s head",lf->race->name); + headob = addob(corpsecell->obpile, headname); + colourmatchob(headob, lf); } + } + } - - if (hasflag(corpse->flags, F_HEADLESS)) { - object_t *headob; - char headname[BUFLEN]; - // drop head too - snprintf(headname, BUFLEN, "%s head",lf->race->name); - headob = addob(lf->cell->obpile, headname); - colourmatchob(headob, lf); + // splatter + if (!vaporised) { + flag_t *f; + f = lfhasflag(lf, F_DIESPLATTER); + if (f) { + fragments(corpsecell, f->text, 1, f->val[0]); } - } - } - - // splatter - if (!vaporised) { - flag_t *f; - f = lfhasflag(lf, F_DIESPLATTER); - if (f) { - fragments(lf->cell, f->text, 1, f->val[0]); - } - } + } // end if corpsecell if (willbecomeghost) { @@ -4435,9 +4448,14 @@ void gainmp(lifeform_t *lf, int amt) { void gainxp(lifeform_t *lf, long amt) { int newskillpoints = 0; int doxp = B_TRUE; + int boostamt = 0; assert(amt >= 0); + // adjust for xp boosts... + sumflags(lf->flags, F_LEARNBOOST, &boostamt, NULL, NULL); + amt = pctof(100+boostamt, amt); + if (lfhasflag(lf, F_HASNEWLEVEL) || (lf->level == 0)) { doxp = B_FALSE; } @@ -5289,15 +5307,17 @@ int getevasion(lifeform_t *lf) { } } - // level based evasion (modified by evasion skill) + // level based evasion level_ev = gethitdice(lf); - skillpctmod = (getskill(lf, SK_EVASION) + 1) * 40; - level_ev = pctof(skillpctmod, level_ev); ev += level_ev; // dexterity mod ev += getattr(lf, A_AGI); + // apply skill based evasion modifier + skillpctmod = 100 + (getskill(lf, SK_EVASION)) * 12; + ev = pctof(skillpctmod, ev); + // you are easier to hit if you're glowing if (hasflag(lf->flags, F_PRODUCESLIGHT)) { ev -= 5; @@ -5326,9 +5346,14 @@ object_t *getbestthrowmissile(lifeform_t *lf, lifeform_t *target) { object_t *o; for (o = lf->pack->first ; o ; o = o->next) { + int ismissileob = B_FALSE; if (!isequipped(o) && isthrowmissile(o) ) { + ismissileob = B_TRUE; + } else if (lfhasflagval(lf, F_WILLTHROW, o->type->id, NA, NA, NULL)) { + ismissileob = B_TRUE; + } + if (ismissileob) { int valid = B_TRUE; - // powder is only a valid missile if we're adjacent to our target if (target && hasflag(o->flags, F_POWDER)) { if (getcelldist(lf->cell,target->cell) > 1) valid = B_FALSE; @@ -7021,7 +7046,7 @@ char *getplayernamefull(char *buf) { if (strlen(pname)) { j = getjob(player); if (j) { - snprintf(buf, BUFLEN, "%s the %s", pname, j->name); + snprintf(buf, BUFLEN, "%s the %s %s", pname, player->race->name, j->name); } else { snprintf(buf, BUFLEN, "%s the %s", pname, player->race->name); } @@ -8555,7 +8580,7 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { // note: we use getplayername here even if this isn't a player, // since in that case the prompt will never be displayed. - getplayernamefull(buf2); + getplayername(buf2); snprintf(buf, BUFLEN, "%s, select your starting weapon:", buf2); initprompt(&prompt, buf); @@ -8907,9 +8932,31 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { char *desc = NULL; enum INJURY inj = IJ_NONE; enum BODYPART bp2; - object_t *wep = NULL; + object_t *wep = NULL,*o; int howlong; + getlfname(lf, lfname); + + o = hasequippedobid(lf->pack, OT_RING_NOINJURY); + if (o) { + char obname[BUFLEN]; + int seen = B_FALSE; + getobname(o, obname, 1); + if (isplayer(lf)) { + msg("Your %s throbs.", noprefix(obname)); + seen = B_TRUE; + } else if (cansee(player, lf)) { + msg("%s%s %s throbs.", lfname, getpossessive(lfname), obname); + seen = B_TRUE; + } + if (seen && !isknown(o)) { + makeknown(o->type->id); + if (isplayer(lf)) { + msg("Amazingly, your %s is unharmed!", getbodypartname(lf, where)); + } + } + return B_TRUE; + } if (where == BP_NONE) return B_TRUE; @@ -9016,7 +9063,6 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { if (isplayer(lf)) { msg("^BYour heart is pierced!"); } else if (cansee(player, lf)) { - getlfname(lf, lfname); msg("^%c%s%s heart is pierced!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname)); } if (lf->hp > 0) lf->hp = 0; @@ -9051,9 +9097,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { getobname(o,obname,o->amt); msg("Your %s drops to the ground.",noprefix(obname)); } else if (cansee(player, lf)) { - char lfname[BUFLEN]; getobname(o,obname,o->amt); - getlfname(lf,lfname); msg("%s%s %s drops to the ground.",lfname,getpossessive(lfname),noprefix(obname)); } moveob(o, lf->cell->obpile, o->amt); @@ -9068,7 +9112,6 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { if (isplayer(lf)) { msg("^BYour brain is ruptured!"); } else if (cansee(player, lf)) { - getlfname(lf, lfname); msg("^%c%s%s brain ruptures!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname)); } if (lf->hp > 0) lf->hp = 0; @@ -9150,7 +9193,6 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getobname(o[i],obname,o[i]->amt); - getlfname(lf,lfname); msg("%s%s %s drops to the ground.",lfname,getpossessive(lfname),noprefix(obname)); } moveob(o[i], lf->cell->obpile, o[i]->amt); @@ -9668,6 +9710,7 @@ int xytoidx(lifeform_t *lf, int x, int y) { return idx; } +/* void setviscell(lifeform_t *lf, cell_t *cell, int how) { int idx; int x,y; @@ -9677,7 +9720,6 @@ void setviscell(lifeform_t *lf, cell_t *cell, int how) { assert(idx < (lf->visw * lf->visw)); lf->viscell[idx] = how; - // checks if (how == B_VIS) { assert (abs(lf->cell->x - cell->x) <= 10); @@ -9700,6 +9742,7 @@ int getviscell(lifeform_t *lf, cell_t *cell) { return lf->viscell[idx]; } +*/ int haslos(lifeform_t *viewer, cell_t *dest) { int numpixels; @@ -10490,10 +10533,8 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { a->facing = rnd(DC_N, DC_NW); a->losdirty = B_TRUE; a->nlos = 0; - //a->los = malloc(sizeof(cell_t *) * MAXVISRANGE); - a->los = malloc( sizeof(cell_t *) * ((MAXVISRANGE*2+1)*(MAXVISRANGE*2+1))); - //a->viscell = NULL; - a->viscell = malloc( sizeof(int) * ((MAXVISRANGE*2+1)*(MAXVISRANGE*2+1))); + //a->los = malloc( sizeof(cell_t *) * ((MAXVISRANGE*2+1)*(MAXVISRANGE*2+1))); + a->los = NULL; // will be alloced in precalclos a->eyeadjustment = 0; @@ -10528,6 +10569,12 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { a->race = NULL; setrace(a, rid, B_FALSE); + // remember original attribs so that if we are polymorphed, we're + // able to revert back. + for (i = 0; i < MAXATTS; i++) { + a->origatt[i] = a->baseatt[i]; + } + // set stamina AFTER setrace as it depends on your attribs a->stamina = getmaxstamina(a); @@ -11393,34 +11440,33 @@ void killjob(job_t *job) { } -void killrace(race_t *race) { +void killrace(race_t *r) { race_t *nextone, *lastone; // free mem - free(race->name); - killflagpile(race->flags); + free(r->name); + killflagpile(r->flags); // remove from list - nextone = race->next; + nextone = r->next; if (nextone != NULL) { - nextone->prev = race->prev; + nextone->prev = r->prev; } else { /* last */ - lastrace = race->prev; + lastrace = r->prev; } - if (race->prev == NULL) { + if (r->prev == NULL) { /* first */ - nextone = race->next; - free(race); - race = nextone; + nextone = r->next; + free(firstrace); + firstrace = nextone; } else { - lastone = race->prev; + lastone = r->prev; free (lastone->next ); lastone->next = nextone; } } - flag_t *levelabilityready(lifeform_t *lf) { flag_t *f; int i; @@ -11861,14 +11907,17 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } } - // special case - if (lf->race->id == R_DREAMFUNGUS) { - if (cansee(player, lf)) { - animradialorth(lf->cell, 4, '}', C_MAGENTA); - msg("^w%s releases a cloud of purple spores!", lfname); - drawscreen(); - } - spellcloud(lf->cell, 3, '\0', C_MAGENTA, OT_S_SLEEP, 8, B_TRUE); + // special cases + if (lf->race->id == R_FUNGUSDREAM) { + char buf2[BUFLEN]; + sprintf(buf, "^w%s releases a cloud of purple spores!", lfname); + sprintf(buf2, "^wSomething releases a cloud of purple spores!"); + spellcloud(lf->cell, 3, UNI_SHADELIGHT, C_MAGENTA, OT_S_SLEEP, 8, B_TRUE, buf, buf2); + } else if (lf->race->id == R_FUNGUSRAGE) { + char buf2[BUFLEN]; + sprintf(buf, "^w%s releases a cloud of red spores!", lfname); + sprintf(buf2, "^wSomething releases a cloud of red spores!"); + spellcloud(lf->cell, 3, UNI_SHADELIGHT, C_RED, OT_A_RAGE, 8, B_TRUE, buf, buf2); } // further effects if not dead... @@ -13025,13 +13074,14 @@ void precalclos_new(lifeform_t *lf) { // right eye missing? missingeye = lfhasflagval(lf, F_INJURY, IJ_EYEDESTROYED, NA, NA, NULL); - los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); - blocker = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); - nlos = 0; if (lf->los) { free(lf->los); lf->los = NULL; } + los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); + blocker = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); + nlos = 0; + maxvisrange = getvisrange(lf, B_FALSE); nightvisrange = getnightvisrange(lf); plev = getskill(lf, SK_PERCEPTION); @@ -13464,12 +13514,12 @@ int startresting(lifeform_t *lf, int willtrain) { // player can't rest while in the air, unless you're in a motel room if (isplayer(lf)) { if (isairborne(lf) && !lfhasflag(lf, F_RESTINGINMOTEL)) { - msg("You can't rest while airborne!"); + msg("You can't %s while airborne!", willtrain ? "train" : "rest"); return B_TRUE; } } if (lfhasflag(lf, F_RAGE)) { - if (isplayer(lf)) msg("You are too enraged to rest!"); + if (isplayer(lf)) msg("You are too enraged to %s!", willtrain ? "train" : "rest"); return B_TRUE; } @@ -14122,6 +14172,13 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { } killflagsofid(lf->flags, F_ORIGRACE); killflagsofid(lf->flags, F_POLYMORPHED); + + // restore stats + for (i = 0; i < MAXATTS; i++) { + lf->att[i] = lf->origatt[i]; + lf->baseatt[i] = lf->origatt[i]; + if (isplayer(lf)) statdirty = B_TRUE; + } } else { if (isplayer(lf)) { msg("^wYou transform into %s %s!", isvowel(newrace->name[0]) ? "an" : "a", newrace->name); diff --git a/lf.h b/lf.h index b48d5a8..e689ea4 100644 --- a/lf.h +++ b/lf.h @@ -185,8 +185,8 @@ float getmaxstamina(lifeform_t *lf); int getmr(lifeform_t *lf); int getvisrange(lifeform_t *lf, int useambient); void idxtoxy(lifeform_t *lf, int idx, int *x, int *y); -void setviscell(lifeform_t *lf, cell_t *cell, int how); -int getviscell(lifeform_t *lf, cell_t *cell); +//void setviscell(lifeform_t *lf, cell_t *cell, int how); +//int getviscell(lifeform_t *lf, cell_t *cell); int xytoidx(lifeform_t *lf, int x, int y); int getmovespeed(lifeform_t *lf); char *getmoveverb(lifeform_t *lf); diff --git a/map.c b/map.c index 3d7d40a..1cec371 100644 --- a/map.c +++ b/map.c @@ -1194,6 +1194,7 @@ int doelementspread(cell_t *c) { getradiuscells(c, 1, DT_COMPASS, B_FALSE, LOF_DONTNEED, B_FALSE, retcell, &nretcells, B_FALSE); for (i = 0; i < nretcells; i++) { object_t *oo; + int celldone = B_FALSE; for (oo = retcell[i]->obpile->first ; oo ; oo = oo->next) { if (isflammable(oo) && !hasobofmaterial(retcell[i]->obpile, MT_FIRE)) { ignite(oo); @@ -1202,6 +1203,18 @@ int doelementspread(cell_t *c) { addobfast(retcell[i]->obpile, fireob->type->id); } nspread++; + celldone = B_TRUE; + } + } + // lifeforms made out of something flammable? ie. plants + // don't include flesh even though it's technically flammable + if (retcell[i]->lf && (retcell[i]->lf->material->id != MT_FLESH)) { + if (!hasobofmaterial(retcell[i]->obpile, MT_FIRE)) { + if (lfhasflag(retcell[i]->lf, F_FLAMMABLE)) { + addobfast(retcell[i]->obpile, fireob->type->id); + nspread++; + celldone = B_TRUE; + } } } } @@ -1650,6 +1663,10 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int if (cellwalkable(NULL, cell, NULL) && isroom(cell)) { valid = B_FALSE; } + // - overlap any part of an existing vault + if (cell->room && cell->room->vault) { + valid = B_FALSE; + } // is this cell adjacent to an empty cell and not a // corner (ie. a valid door location) @@ -2992,7 +3009,6 @@ void createsewer(map_t *map, int depth, map_t *parentmap, int exitdir, object_t addcell(map, x, y); } } - roomon = malloc((roomcountx * roomcounty) * sizeof(int)); rowfirst = malloc(roomcounty * sizeof(int)); rowlast = malloc(roomcounty * sizeof(int)); @@ -3315,11 +3331,73 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r return B_FALSE; } +void killcell(cell_t *c) { + killobpile(c->obpile); + if (c->writing) free(c->writing); +} + +void killcelltype(celltype_t *ct) { + celltype_t *nextone, *lastone; + if (ct->name) free(ct->name); + if (ct->flags) killflagpile(ct->flags); + + // remove from list + nextone = ct->next; + if (nextone != NULL) { + nextone->prev = ct->prev; + } else { /* last */ + lastcelltype = ct->prev; + } + + if (ct->prev == NULL) { + /* first */ + nextone = ct->next; + free(firstcelltype); + firstcelltype = nextone; + } else { + lastone = ct->prev; + free (lastone->next ); + lastone->next = nextone; + } +} + void killfakes(map_t *map, cell_t *cell) { killobpile(cell->obpile); free(map->name); } +void killmap(map_t *m) { + map_t *nextone, *lastone; + int i; + // free mem + while (m->lf) killlf(m->lf); + + killflagpile(m->flags); + + for (i = 0; i < (m->w*m->h); i++){ + killcell(m->cell[i]); + } + + // remove from list + nextone = m->next; + if (nextone != NULL) { + nextone->prev = m->prev; + } else { /* last */ + lastmap = m->prev; + } + + if (m->prev == NULL) { + /* first */ + nextone = m->next; + free(firstmap); + firstmap = nextone; + } else { + lastone = m->prev; + free (lastone->next ); + lastone->next = nextone; + } +} + // link a single cell up to the rest of the map. // make sure it links to an empty cell of a DIFFERENT roomid. // if 'wantfilled' is set, only link to "filled" cells. @@ -4130,18 +4208,18 @@ void dumpoutlines(void) { // dirtype of DT_COMPASS will give a circular explosion void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int dirtype, int wantannounce) { int x,y; + char buf[BUFLEN]; + if (wantannounce) { + sprintf(buf, "You see %s explosion!", (range > 0) ? "a huge" : "an"); + } if (dirtype == DT_COMPASS) { - animradial(c, range, '}', C_RED); + animradial(c, range, '}', C_RED, DT_COMPASS, wantannounce ? buf : NULL, wantannounce ? buf : NULL); } else { // ie. DT_ORTH - animradialorth(c, range, '}', C_RED); + animradial(c, range, '}', C_RED, DT_ORTH, wantannounce ? buf : NULL, wantannounce ? buf : NULL); } - if (haslos(player, c)) { - if (wantannounce) { - msg("You see %s explosion!", (range > 0) ? "a huge" : "an"); - } - } else { + if (!haslos(player, c)) { noise(c, NULL, NC_OTHER, (range > 0) ? 6 : 5, "an explosion!", NULL); } @@ -4857,6 +4935,7 @@ cell_t *getrandomroomcell(map_t *map, int roomid) { } } if (npossible <= 0) { + free(poss); return NULL; } @@ -5680,6 +5759,14 @@ void makelit(cell_t *c, enum LIGHTLEV how, int howlong) { c->origlittimer = c->littimer; c->littimer = howlong; } + if ((gamemode == GM_GAMESTARTED) && (c->lit != how)) { + lifeform_t *lf; + for (lf = c->map->lf ; lf ; lf = lf->next) { + if (haslos(lf, c)) { + setlosdirty(lf); + } + } + } c->lit = how; } @@ -5864,7 +5951,6 @@ void set_scanned_glyph(int targettype, void *what, char *descappend, char *desc, void setcellknown(cell_t *cell, int forcelev) { enum SKILLLEVEL slev; object_t *o; - if (forcelev > 0) { slev = forcelev; } else { @@ -6089,24 +6175,6 @@ void updateknowncells(void) { if (isairborne(player) && !lfhasflag(player, F_PHOTOMEM)) { return; } - - /* - map = player->cell->map; - //wep = getweapon(player); - - for (y = viewy; y < viewy + viewh; y++) { - for (x = viewx; x < viewx + vieww; x++) { - cell_t *cell; - cell = getcellat(map, x, y); - if (cell) { - //if ((player->cell == cell) || haslos(player, cell)) { - if (haslos(player, cell)) { - setcellknown(cell, B_FALSE); - } - } - } - } - */ for (i = 0; i < player->nlos; i++) { setcellknown(player->los[i], B_FALSE); } diff --git a/map.h b/map.h index 763b9d2..9492e0e 100644 --- a/map.h +++ b/map.h @@ -121,7 +121,10 @@ int isonmap(map_t *map, int x, int y); int isoutdoors(map_t *m); int isroom(cell_t *c); int iswallindir(cell_t *cell, int dir); +void killcell(cell_t *c); +void killcelltype(celltype_t *ct); void killfakes(map_t *map, cell_t *cell); +void killmap(map_t *m); int linkexit(cell_t *c, int wantfilled, int *ncellsadded); int linkexits(map_t *m, int roomid); int linkholes(map_t *map); diff --git a/move.c b/move.c index 7676fbc..47eaead 100644 --- a/move.c +++ b/move.c @@ -298,53 +298,67 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) { if (lf && isclimbing(lf)) { cell_t *rightcell,*leftcell,*frontcell; int rightdir,leftdir,i; + int gotlf = B_FALSE; // climbing rules: you can climb into a cell if: + // - it contains a lifeform and is in front of you + // OR // - it is directly to your side // - the target cell (beside you) is a wall // - the cell in FRONT (ie. dir you are facing) of the target cell // is NOT a wall // OR // - it is straight forward (ie. off the wall) - rightdir = lf->facing; - leftdir = lf->facing; - for (i = 0; i < 2; i++) { - if (++rightdir > DC_NW) rightdir = DC_N; - if (--leftdir < DC_N) leftdir = DC_NW; + + + if (cell->lf && (cell->lf != lf)) { + if (getrelativedir(lf, getdirtowards(lf->cell, cell, lf, B_FALSE, DT_ORTH)) == RD_FORWARDS) { + if (error) *error = E_LFINWAY; // ok but still set reason + gotlf = B_TRUE; + } } - rightcell = getcellindir(lf->cell, rightdir); - leftcell = getcellindir(lf->cell, leftdir); - frontcell = getcellindir(lf->cell, lf->facing); - if ((cell != rightcell) && (cell != leftcell) && (cell != frontcell)) { - // not left/right/front - if (error) *error = E_BADCLIMBDIR; - return B_FALSE; - } - - if (cell == frontcell) { - // in front - if (cell->type->solid) { + + if (!gotlf) { + rightdir = lf->facing; + leftdir = lf->facing; + for (i = 0; i < 2; i++) { + if (++rightdir > DC_NW) rightdir = DC_N; + if (--leftdir < DC_N) leftdir = DC_NW; + } + rightcell = getcellindir(lf->cell, rightdir); + leftcell = getcellindir(lf->cell, leftdir); + frontcell = getcellindir(lf->cell, lf->facing); + if ((cell != rightcell) && (cell != leftcell) && (cell != frontcell)) { + // not left/right/front if (error) *error = E_BADCLIMBDIR; return B_FALSE; - } else if (!cell->lf) { - // in front and not solid, and no lf there - if (error) *error = E_STOPCLIMBING; - return B_TRUE; } - } else { - // to the side - if (cell->type->solid) { - cell_t *sidefrontcell; - sidefrontcell = getcellindir(cell, lf->facing); - if (!sidefrontcell || sidefrontcell->type->solid) { - // cell in front of target cell is solid + + if (cell == frontcell) { + // in front + if (cell->type->solid) { if (error) *error = E_BADCLIMBDIR; return B_FALSE; + } else if (!cell->lf) { + // in front and not solid, and no lf there + if (error) *error = E_STOPCLIMBING; + return B_TRUE; } } else { - // to the side and not solid - if (error) *error = E_BADCLIMBDIR; - return B_FALSE; - } + // to the side + if (cell->type->solid) { + cell_t *sidefrontcell; + sidefrontcell = getcellindir(cell, lf->facing); + if (!sidefrontcell || sidefrontcell->type->solid) { + // cell in front of target cell is solid + if (error) *error = E_BADCLIMBDIR; + return B_FALSE; + } + } else { + // to the side and not solid + if (error) *error = E_BADCLIMBDIR; + return B_FALSE; + } + } } // if okay, now drop through to below code which checks // whether there are any lfs or objects in the way @@ -490,6 +504,7 @@ int diropposite(int dir) { // restonfail means "if we can't find any valid moves, just rest" // returns true on error int dorandommove(lifeform_t *lf, int badmovesok, int restonfail) { + int origtimespent; int dir; int tries = 0; int moveok,rv; @@ -534,8 +549,10 @@ int dorandommove(lifeform_t *lf, int badmovesok, int restonfail) { } } } + + origtimespent = lf->timespent; rv = trymove(lf, dir, B_TRUE, B_FALSE); - if (rv && restonfail) { + if (restonfail && (rv || (lf->timespent == origtimespent))) { // ie move failed rest(lf, B_TRUE); } @@ -1356,7 +1373,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (!preroom && postroom && postroom->vault) { f = hasflag(postroom->vault->flags, F_VAULTENTERTEXT); if (f) { - msg("%s", f->text); + msg("%s", f->text); more(); didmsg = B_TRUE; } } diff --git a/nexus.c b/nexus.c index 59021e0..7d19a28 100644 --- a/nexus.c +++ b/nexus.c @@ -44,6 +44,9 @@ hiddenname_t *firsthiddenname = NULL, *lasthiddenname = NULL; npcname_t *npcname; int numnpcnames; +buildingusage_t buildingusage[MAXBUILDINGTYPES]; +int nbuildingusage = 0; + warning_t *firstwarning = NULL,*lastwarning = NULL; int maxmonhitdice = 0; // highest number of hitdice for any monster @@ -428,7 +431,9 @@ int main(int argc, char **argv) { curtime = rnd(0,DAYSECS-1); } else { - snprintf(welcomemsg, BUFLEN, "Welcome back!"); + char pname[BUFLEN]; + getplayernamefull(pname); + snprintf(welcomemsg, BUFLEN, "Welcome back, %s!", pname); } // start game - this will cause debug messages to now @@ -520,7 +525,6 @@ int main(int argc, char **argv) { donextturn(curmap); // show level (if required) - //if (haslos(player, curmap->lf->cell)) { drawscreen(); //dblog("**** END of turn, numdraws = %d", numdraws); @@ -537,6 +541,8 @@ int main(int argc, char **argv) { dofinaloblist(player->pack); // print tombstone tombstone(player); + + //WriteMemLeak(); return B_FALSE; } @@ -645,13 +651,31 @@ void cleanup(void) { fclose(logfile); cleanupgfx(); - // free maps + // free commands + while (firstcommand) killcommand(firstcommand); + // free maps (this will kill its lifeforms & obs & cells too) + while (firstmap) killmap(firstmap); // free knowledge + while (knowledge) killknowledge(knowledge); // free brands + while (firstbrand) killbrand(firstbrand); + // free obmods + while (firstobmod) killobmod(firstobmod); // free obtypes - // free objects + while (objecttype) killot(objecttype); + // free obclasses + while (objectclass) killoc(objectclass); // free materials + while (material) killmaterial(material); // free races + while (firstrace) killrace(firstrace); + // free celltypes + while (firstcelltype) killcelltype(firstcelltype); + // free npcnames + free(npcname); + // free hidden names + while (firsthiddenname) killhiddenname(firsthiddenname); + //WriteMemLeak(); } void dbtimestart(char *text) { @@ -1276,6 +1300,10 @@ int loadnpcnames(void) { return B_FALSE; } +void *mymalloc(size_t sz) { + return malloc(sz); +} + int onein(int howmany) { if (howmany <= 0) return B_FALSE; if (rnd(1,howmany) == 1) return B_TRUE; diff --git a/nexus.h b/nexus.h index d1fe328..fd15fea 100644 --- a/nexus.h +++ b/nexus.h @@ -25,6 +25,7 @@ int limit(int *what, int min, int max); int limitf(float *what, float min, float max); int limitd(double *what, double min, double max); int loadnpcnames(void); +void *mymalloc(size_t sz); int onein(int howmany); int parseplayerfile(FILE *f, lifeform_t *lf); int pctchance(int pct); diff --git a/objects.c b/objects.c index 75a02de..4ddaf21 100644 --- a/objects.c +++ b/objects.c @@ -28,6 +28,9 @@ extern material_t *material,*lastmaterial; extern recipe_t *firstrecipe,*lastrecipe; extern skill_t *firstskill, *lastskill; +extern buildingusage_t buildingusage[]; +extern int nbuildingusage; + extern int inaskcoords; void (*precalclos)(lifeform_t *); @@ -194,11 +197,12 @@ hiddennamewithcol_t gemtype[] = { { "copper",C_BROWN }, { "diamond",C_BOLDCYAN }, { "emerald",C_GREEN }, - { "flourite",C_GREY }, + { "flourite",C_RED }, { "garnet",C_ORANGE }, { "gold",C_YELLOW }, { "iridium",C_WHITE }, { "jade",C_GREEN }, + { "jasper",C_RED }, { "lapis lazuli",C_BOLDBLUE }, { "malachite",C_BOLDCYAN }, { "onyx",C_BLUE }, @@ -207,10 +211,20 @@ hiddennamewithcol_t gemtype[] = { { "quartz",C_GREY }, { "ruby",C_RED }, { "sapphire",C_BLUE }, + { "topaz", C_YELLOW }, { "zinc",C_GREY }, + { "zircon",C_CYAN }, { "",C_GREY }, }; +char *ringadjective[] = { + "cracked", + "dusty", + "ornate", + "sparkling", + "twinkling", + "", +}; long nextoid = 0; @@ -924,6 +938,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes // don't give nopickup objects to lifeforms if (hasflag(ot->flags, F_NOPICKUP) && where->owner) { + if (db) dblog("DB: trying to give NOPICKUP object '%s' to a lifeform ('%s').", ot->name, where->owner->race->name ); nretobs = 0; return NULL; } @@ -934,10 +949,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes if (db) dblog("DB: setting canstack = false, objecttype '%s' not stackable", ot->name ); canstack = B_FALSE; } - if (where->parentob && hasflag(where->parentob->flags, F_SHOP)) { if (db) dblog("DB: setting canstack = false, object is going into a shop"); canstack = B_FALSE; + // also override amount + howmany = 1; } // special checks for unique objects @@ -1035,6 +1051,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes o->contents = addobpile(NOOWNER, NOLOC, o); o->birthtime = curtime; + o->dying = B_FALSE; // inherit props from objecttype o->material = ot->material; @@ -1049,39 +1066,41 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes // don't want certain objecttype only flags... //killflagsofid(o->flags, F_RARITY); - // random flags... - f = hasflag(o->flags, F_RNDCHARGES); - if (f) { - int amt; - flag_t *chargeflag; - amt = rnd(f->val[0], f->val[1]); - chargeflag = hasflag(o->flags, F_CHARGES); - if (chargeflag) { - chargeflag->val[0] = amt; - chargeflag->val[1] = amt; - chargeflag->known = B_FALSE; - } else { - chargeflag = addflag_real(o->flags, F_CHARGES, amt, amt, NA, NULL, PERMENANT, B_UNKNOWN, -1); + if (gamemode != GM_LOADING) { + // random flags... + f = hasflag(o->flags, F_RNDCHARGES); + if (f) { + int amt; + flag_t *chargeflag; + amt = rnd(f->val[0], f->val[1]); + chargeflag = hasflag(o->flags, F_CHARGES); + if (chargeflag) { + chargeflag->val[0] = amt; + chargeflag->val[1] = amt; + chargeflag->known = B_FALSE; + } else { + chargeflag = addflag_real(o->flags, F_CHARGES, amt, amt, NA, NULL, PERMENANT, B_UNKNOWN, -1); + } } - } - // charge flag always starts unknown. - f = hasflag(o->flags, F_CHARGES); - if (f) { - f->known = B_FALSE; - } - - // non-inherited from here on: - // if adding to a player... - if (where->owner) { - if (o->type->obclass->id == OC_MONEY) { - o->letter = '$'; - } else { - o->letter = getnextletter(where, NULL); + // charge flag always starts unknown. + f = hasflag(o->flags, F_CHARGES); + if (f) { + f->known = B_FALSE; + } + + // non-inherited from here on: + // if adding to a player... + if (where->owner) { + if (o->type->obclass->id == OC_MONEY) { + o->letter = '$'; + } else { + o->letter = getnextletter(where, NULL); + } + } else { + // new object on the ground - has no letter yet. + o->letter = '\0'; } - } else { - // new object on the ground - has no letter yet. - o->letter = '\0'; } if (canstack) { @@ -1091,7 +1110,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes o->amt = 1; } - addedob[nadded++] = o; if (canstack) { @@ -1110,575 +1128,588 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes o = addedob[i]; obloc = getoblocation(o); - if (hasflag(o->flags, F_NOBLESS)) { - setblessed(o, B_UNCURSED); - } else { - setblessed(o, wantblessed); - } - o->blessknown = B_FALSE; - - - if (wantdiffmat != MT_NOTHING) { - changemat(o, wantdiffmat); - } - - // extra chance of bone items being cursed - if (o->type->material->id == MT_BONE) { - if (pctchance(15)) { - o->blessed = B_CURSED; - } - } - - // fill in sign text - if (signtext) { - addflag(o->flags, F_SIGNTEXT, NA, NA, NA, signtext); - } - - // fill in portal destinations - if (targetmap) { - int tx = NA,ty = NA; - if (targetcell) { - tx = targetcell->x; - ty = targetcell->y; - } - addflag(o->flags, F_MAPLINK, targetmap->id, tx, ty, NULL); - } - - // assign gods to temples - if (o->type->id == OT_TEMPLE) { - lifeform_t *god; - god = getrandomgod(); - if (god) { - addflag(o->flags, F_LINKGOD, god->race->id, NA, NA, NULL); - } - } - - // fill in door flags - if (ndoorflags && isdoor(o, NULL)) { - int n; - for (n = 0; n < ndoorflags; n++) { - int val[3]; - int ok = B_FALSE; - if (obloc) { - // fill in flag vals - switch (doorflag[n]) { - case F_LOCKED: - val[0] = B_TRUE; - val[1] = getdoorlockdiff(obloc->map->depth); - val[2] = NA; - ok = B_TRUE; - break; - case F_JAMMED: - val[0] = rnd(1,obloc->map->depth+3); - val[1] = NA; - val[2] = NA; - ok = B_TRUE; - break; - case F_SECRET: - val[0] = getdoorsecretdiff(obloc->map->depth); - val[1] = NA; - val[2] = NA; - ok = B_TRUE; - break; - default: - break; - } - if (ok) { - addflag(o->flags, doorflag[n], val[0], val[1], val[2], NULL); + // inc usage counter for buildings + if (gamemode > GM_VALIDATION) { + if (o->type->obclass->id == OC_BUILDING) { + for (n = 0; n < nbuildingusage; n++) { + if (buildingusage[n].oid == o->type->id) { + buildingusage[n].count++; } } } } - // foundtain flags - if (o && (o->type->id == OT_FOUNTAIN)) { - f = hasflag(o->flags, F_LINKOB); - if (where->where && (where->where->habitat->id != H_VILLAGE)) { - objecttype_t *ot; - int min,max; - - getrarityrange(where->where->map->depth, &min, &max, RARITYVARIANCEOB, B_FALSE); - // random potion type - ot = getrandomobofclass(OC_POTION, min, max); - if (ot) { - f->val[0] = ot->id; + if (gamemode != GM_LOADING) { + if (hasflag(o->flags, F_NOBLESS)) { + setblessed(o, B_UNCURSED); + } else { + setblessed(o, wantblessed); + } + o->blessknown = B_FALSE; + + + if (wantdiffmat != MT_NOTHING) { + changemat(o, wantdiffmat); + } + + // extra chance of bone items being cursed + if (o->type->material->id == MT_BONE) { + if (pctchance(15)) { + o->blessed = B_CURSED; } } - } + // fill in sign text + if (signtext) { + addflag(o->flags, F_SIGNTEXT, NA, NA, NA, signtext); + } - // food flags - if ((ot->obclass->id == OC_FOOD) && wantfoodtaint) { - addflag(o->flags, F_TAINTED, B_TRUE, NA, NA, NULL); - } - // tool flags - if (o && hasflag(o->flags, F_LIGHTSOURCE) && wantlit) { - turnon(NULL, o); - } + // fill in portal destinations + if (targetmap) { + int tx = NA,ty = NA; + if (targetcell) { + tx = targetcell->x; + ty = targetcell->y; + } + addflag(o->flags, F_MAPLINK, targetmap->id, tx, ty, NULL); + } - // fill in armour size - if (o && hasflag(o->flags, F_MULTISIZE)) { - if (wantarmsize == SZ_ANY) { - // if giving to a lifeform being created, match their size - if (where->owner) { - wantarmsize = getlfsize(where->owner); - } else { - // random size - if (onein(4)) { - // nonstandard size - if (onein(2)) { - wantarmsize = SZ_MEDIUM; - } else { - wantarmsize = SZ_LARGE; + // assign gods to temples + if (o->type->id == OT_TEMPLE) { + lifeform_t *god; + god = getrandomgod(); + if (god) { + addflag(o->flags, F_LINKGOD, god->race->id, NA, NA, NULL); + } + } + + // fill in door flags + if (ndoorflags && isdoor(o, NULL)) { + int n; + for (n = 0; n < ndoorflags; n++) { + int val[3]; + int ok = B_FALSE; + if (obloc) { + // fill in flag vals + switch (doorflag[n]) { + case F_LOCKED: + val[0] = B_TRUE; + val[1] = getdoorlockdiff(obloc->map->depth); + val[2] = NA; + ok = B_TRUE; + break; + case F_JAMMED: + val[0] = rnd(1,obloc->map->depth+3); + val[1] = NA; + val[2] = NA; + ok = B_TRUE; + break; + case F_SECRET: + val[0] = getdoorsecretdiff(obloc->map->depth); + val[1] = NA; + val[2] = NA; + ok = B_TRUE; + break; + default: + break; + } + if (ok) { + addflag(o->flags, doorflag[n], val[0], val[1], val[2], NULL); } - } else { - wantarmsize = SZ_HUMAN; } } } - addflag(o->flags, F_ARMOURSIZE, wantarmsize, NA, NA, NULL); - } - // fill in book types - if (o && (o->type->obclass->id == OC_BOOK)) { - hiddenname_t *hn,*selhn = NULL; - int numhiddennames; - int n,sel; - if (bookcontents == -1) { - if (o->type->id == OT_SPELLBOOK) { - // pick a random school - bookcontents = getrandomspellschool(); - //bookcontents = getrandomspell(maxlev); - //while (!schoolappearsinbooks(getspellschool(bookcontents))) { - // bookcontents = getrandomspell(maxlev); - // } - } else { // ie. manual - bookcontents = getrandomskill(); - } - } - - // link - if (o->type->id == OT_SPELLBOOK) { - int nspells,firstlev; - // remember the book's school (used for description) - addflag(o->flags, F_LINKSCHOOL, bookcontents, NA, NA, NULL); - // add contents to the book - if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { - enum OBTYPE firstspell; - // giving to player at start of game - nspells = 5; - firstlev = 2; - - // fixed first spell - firstspell = getfirstwizspell(bookcontents); - assert(addobfast(o->contents, firstspell)); - } else { - nspells = rnd(2,5); - firstlev = rnd(1,4); - } - for (i = 0; i < nspells; i++) { - enum OBTYPE oid; - int lev; - lev = firstlev + i; - if (lev > MAXSPELLLEV) break; - oid = getrandomspellfromschool(bookcontents,lev); - if (oid != OT_NONE) { - assert(addobfast(o->contents, oid)); - } - } - } else { - addflag(o->flags, F_MANUALOF, bookcontents, NA, NA, NULL); - } - - // count hidden names - numhiddennames = 0; - for (hn = firsthiddenname ; hn ; hn = hn->next) { - if (hn->obclass == o->type->obclass->id) { - numhiddennames++; - } - } - // assign hidden name - sel = rnd(0,numhiddennames-1); - n = 0; - for (hn = firsthiddenname ; hn ; hn = hn->next) { - if (hn->obclass == o->type->obclass->id) { - if (n == sel) { - selhn = hn; - break; - } - n++; - } - } - addflag(o->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, selhn->text); - // don't call sethiddenname, because it acts on OBJECT TYPES not OBJECTS. - // all books are unique - } - - - // create linked holes in adjacent maps - if (wantlinkholes && o && hasflag(o->flags, F_PIT)) { - cell_t *c; - map_t *adjmap = NULL; - - f = hasflag(o->flags, F_PIT); - - c = getoblocation(o); - adjmap = getmapindir(c->map, f->val[0]); - if ((c->map->region->rtype->id == RG_WORLDMAP) && !adjmap) { - // ie. going down from the surface, and no dungeon below. - // ( MUST be down because holes going up make no sense! ) - createregionlink(c->map, c, o, NULL, RG_PIT, c->map->region); - } else { - // create linked holes on the map at the other end of this one. - if (adjmap) { - linkholes(adjmap); - } - } - } - - // other special changes we need to make based on what was - // asked for - if ((gamemode != GM_LOADING) && o) { - // corpses - fill in details - if (o->type->id == OT_CORPSE) { - flag_t *rf, *cf; - - if (!corpserace || hasflag(corpserace->flags, F_NOCORPSE)) { - // random one. - corpserace = getrandomcorpserace(NULL); - } + // fountain flags + if (o && (o->type->id == OT_FOUNTAIN)) { + f = hasflag(o->flags, F_LINKOB); + if (where->where && (where->where->habitat->id != H_VILLAGE)) { + objecttype_t *ot; + int min,max; - o->weight = corpserace->weight; - o->material = corpserace->material; - - // remember the race type - addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); - - // override ot_corpse nutrition flag based on race's size - rf = hasflag(corpserace->flags, F_SIZE); - if (rf) { - cf = hasflag(o->flags, F_EDIBLE); - if (cf) { - cf->val[1] = sizetonutrition(rf->val[0]); + getrarityrange(where->where->map->depth, &min, &max, RARITYVARIANCEOB, B_FALSE); + // random potion type + ot = getrandomobofclass(OC_POTION, min, max); + if (ot) { + f->val[0] = ot->id; } - } - } else if (o->type->id == OT_STATUE) { - flag_t *f, *rf; - float ratio; + } + } - if (!corpserace) { - cell_t *where; - where = getoblocation(o); - // select random race - if (where) { - corpserace = getrandomcorpserace(where); - } - if (!corpserace) { - // ie. vending machine, or inside another object/fake cell? + + // food flags + if ((ot->obclass->id == OC_FOOD) && wantfoodtaint) { + addflag(o->flags, F_TAINTED, B_TRUE, NA, NA, NULL); + } + // tool flags + if (o && hasflag(o->flags, F_LIGHTSOURCE) && wantlit) { + turnon(NULL, o); + } + + // fill in armour size + if (o && hasflag(o->flags, F_MULTISIZE)) { + if (wantarmsize == SZ_ANY) { + // if giving to a lifeform being created, match their size + if (where->owner) { + wantarmsize = getlfsize(where->owner); + } else { + // random size + if (onein(4)) { + // nonstandard size + if (onein(2)) { + wantarmsize = SZ_MEDIUM; + } else { + wantarmsize = SZ_LARGE; + } + } else { + wantarmsize = SZ_HUMAN; + } + } + } + addflag(o->flags, F_ARMOURSIZE, wantarmsize, NA, NA, NULL); + } + + // fill in book types + if (o && (o->type->obclass->id == OC_BOOK)) { + hiddenname_t *hn,*selhn = NULL; + int numhiddennames; + int n,sel; + if (bookcontents == -1) { + if (o->type->id == OT_SPELLBOOK) { + // pick a random school + bookcontents = getrandomspellschool(); + //bookcontents = getrandomspell(maxlev); + //while (!schoolappearsinbooks(getspellschool(bookcontents))) { + // bookcontents = getrandomspell(maxlev); + // } + } else { // ie. manual + bookcontents = getrandomskill(); + } + } + + // link + if (o->type->id == OT_SPELLBOOK) { + int nspells,firstlev; + // remember the book's school (used for description) + addflag(o->flags, F_LINKSCHOOL, bookcontents, NA, NA, NULL); + // add contents to the book + if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { + enum OBTYPE firstspell; + // giving to player at start of game + nspells = 5; + firstlev = 2; + + // fixed first spell + firstspell = getfirstwizspell(bookcontents); + assert(addobfast(o->contents, firstspell)); + } else { + nspells = rnd(2,5); + firstlev = rnd(1,4); + } + for (i = 0; i < nspells; i++) { + enum OBTYPE oid; + int lev; + lev = firstlev + i; + if (lev > MAXSPELLLEV) break; + oid = getrandomspellfromschool(bookcontents,lev); + if (oid != OT_NONE) { + assert(addobfast(o->contents, oid)); + } + } + } else { + addflag(o->flags, F_MANUALOF, bookcontents, NA, NA, NULL); + } + + // count hidden names + numhiddennames = 0; + for (hn = firsthiddenname ; hn ; hn = hn->next) { + if (hn->obclass == o->type->obclass->id) { + numhiddennames++; + } + } + // assign hidden name + sel = rnd(0,numhiddennames-1); + n = 0; + for (hn = firsthiddenname ; hn ; hn = hn->next) { + if (hn->obclass == o->type->obclass->id) { + if (n == sel) { + selhn = hn; + break; + } + n++; + } + } + addflag(o->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, selhn->text); + // don't call sethiddenname, because it acts on OBJECT TYPES not OBJECTS. + // all books are unique + } + + + // create linked holes in adjacent maps + if (wantlinkholes && o && hasflag(o->flags, F_PIT)) { + cell_t *c; + map_t *adjmap = NULL; + + f = hasflag(o->flags, F_PIT); + + c = getoblocation(o); + adjmap = getmapindir(c->map, f->val[0]); + if ((c->map->region->rtype->id == RG_WORLDMAP) && !adjmap) { + // ie. going down from the surface, and no dungeon below. + // ( MUST be down because holes going up make no sense! ) + createregionlink(c->map, c, o, NULL, RG_PIT, c->map->region); + } else { + // create linked holes on the map at the other end of this one. + if (adjmap) { + linkholes(adjmap); + } + } + } + + // other special changes we need to make based on what was + // asked for + if (o) { + // corpses - fill in details + if (o->type->id == OT_CORPSE) { + flag_t *rf, *cf; + + if (!corpserace || hasflag(corpserace->flags, F_NOCORPSE)) { + // random one. corpserace = getrandomcorpserace(NULL); } - if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid); - } - - ratio = o->material->weightrating / corpserace->material->weightrating; + + o->weight = corpserace->weight; + o->material = corpserace->material; - o->weight = corpserace->weight * ratio; + // remember the race type + addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); - // remember the race type - addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); - - // set impassable size - f = hasflag(o->flags, F_IMPASSABLE); - if (f) { + // override ot_corpse nutrition flag based on race's size rf = hasflag(corpserace->flags, F_SIZE); if (rf) { - f->val[0] = SZ_MIN; - f->val[1] = rf->val[0]; - } else { - killflag(f); - } - } + cf = hasflag(o->flags, F_EDIBLE); + if (cf) { + cf->val[1] = sizetonutrition(rf->val[0]); + } + } + } else if (o->type->id == OT_STATUE) { + flag_t *f, *rf; + float ratio; - // set ob hp - f = hasflag(o->flags, F_OBHP); - if (f) { - rf = hasflag(corpserace->flags, F_HITDICE); + if (!corpserace) { + cell_t *where; + where = getoblocation(o); + // select random race + if (where) { + corpserace = getrandomcorpserace(where); + } + if (!corpserace) { + // ie. vending machine, or inside another object/fake cell? + corpserace = getrandomcorpserace(NULL); + } + if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid); + } + + ratio = o->material->weightrating / corpserace->material->weightrating; + + o->weight = corpserace->weight * ratio; + + // remember the race type + addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); + + // set impassable size + f = hasflag(o->flags, F_IMPASSABLE); + if (f) { + rf = hasflag(corpserace->flags, F_SIZE); + if (rf) { + f->val[0] = SZ_MIN; + f->val[1] = rf->val[0]; + } else { + killflag(f); + } + } + + // set ob hp + f = hasflag(o->flags, F_OBHP); + if (f) { + rf = hasflag(corpserace->flags, F_HITDICE); + if (rf) { + int maxhp; + maxhp = roll(rf->text); + f->val[0] = maxhp; + f->val[1] = maxhp; + } + } + } else if (o->type->id == OT_HEAD) { + flag_t *rf, *cf; + + assert(corpserace); + + o->weight = pctof(8, corpserace->weight); + limitf(&o->weight, 0.01, NA); + o->material = corpserace->material; + + // remember the race type + addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); + + // override ot_corpse nutrition flag based on race's size + rf = hasflag(corpserace->flags, F_SIZE); if (rf) { - int maxhp; - maxhp = roll(rf->text); - f->val[0] = maxhp; - f->val[1] = maxhp; + cf = hasflag(o->flags, F_EDIBLE); + if (cf) { + cf->val[1] = sizetonutrition(rf->val[0]) / 3; + } + } + } else if (o->type->id == OT_JERKY) { + if (!corpserace) { + corpserace = getrandomcorpserace(NULL); + if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid); } - } - } else if (o->type->id == OT_HEAD) { - flag_t *rf, *cf; + addflag(o->flags, F_LINKRACE, corpserace->id, NA, NA, NULL); + } else if (o->type->id == OT_ROASTMEAT) { + flag_t *rf, *cf; - assert(corpserace); - - o->weight = pctof(8, corpserace->weight); - limitf(&o->weight, 0.01, NA); - o->material = corpserace->material; - - // remember the race type - addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); - - // override ot_corpse nutrition flag based on race's size - rf = hasflag(corpserace->flags, F_SIZE); - if (rf) { - cf = hasflag(o->flags, F_EDIBLE); - if (cf) { - cf->val[1] = sizetonutrition(rf->val[0]) / 3; + if (!corpserace || hasflag(corpserace->flags, F_NOCORPSE)) { + // random one. + corpserace = getrandomcorpserace(NULL); + if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid); } + + o->weight = corpserace->weight / 2; + + // remember the race type + addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); + + // override ot_roastmeat nutrition flag based on race's size + rf = hasflag(corpserace->flags, F_SIZE); + if (rf) { + cf = hasflag(o->flags, F_EDIBLE); + if (cf) { + cf->val[1] = sizetonutrition(rf->val[0]); + } + } } - } else if (o->type->id == OT_JERKY) { - if (!corpserace) { - corpserace = getrandomcorpserace(NULL); - if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid); + + // depth + f = hasflag(o->flags, F_DEEPWATER); + if (f && (f->val[0] != wantdepth)) { + f->val[0] = wantdepth; } - addflag(o->flags, F_LINKRACE, corpserace->id, NA, NA, NULL); - } else if (o->type->id == OT_ROASTMEAT) { - flag_t *rf, *cf; - if (!corpserace || hasflag(corpserace->flags, F_NOCORPSE)) { - // random one. - corpserace = getrandomcorpserace(NULL); - if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid); - } - - o->weight = corpserace->weight / 2; - - // remember the race type - addflag(o->flags, F_CORPSEOF, corpserace->id, NA, NA, NULL); - - // override ot_roastmeat nutrition flag based on race's size - rf = hasflag(corpserace->flags, F_SIZE); - if (rf) { - cf = hasflag(o->flags, F_EDIBLE); - if (cf) { - cf->val[1] = sizetonutrition(rf->val[0]); - } - } - } - - // depth - f = hasflag(o->flags, F_DEEPWATER); - if (f && (f->val[0] != wantdepth)) { - f->val[0] = wantdepth; - } - - // chance of masterwork based on wantgoodness - switch (wantgoodness) { - case G_GREAT: - if (onein(6)) { - wantom[nom++] = findobmod(OM_MASTERWORK); - } - break; - case G_EXCELLENT: - if (onein(3)) { - wantom[nom++] = findobmod(OM_MASTERWORK); - } - break; - } - - for (n = 0; n < nom; n++) { - // add flags from obmod - applyobmod(o, wantom[n]); - // other effects... - switch (wantom[n]->id) { - case OM_FLAMING: // flaming weapons are immune to fire - if (o->type->obclass->id == OC_WEAPON) { - if (!isimmuneto(o->flags, DT_FIRE, B_FALSE)) { - addflag(o->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); - } - } - break; - case OM_FROZEN: - if (o->material->id != MT_FIRE) { // fire can't be frozen! - // made of ice - // note: not using changemat() here to avoid adding f_frozen twice. - o->material = findmaterial(MT_ICE); - } - break; - case OM_MASTERWORK: - if (isweapon(o) || isarmour(o)) { - flag_t *f; - f = hasflag(o->flags, F_OBHP); - if (f) { - f->val[0] *= 2; - f->val[1] *= 2; - } - } - break; - case OM_SHODDY: - if (isweapon(o) || isarmour(o)) { - flag_t *f; - f = hasflag(o->flags, F_OBHP); - if (f) { - f->val[0] /= 2; if (f->val[0] < 1) f->val[0] = 1; - f->val[1] /= 2; if (f->val[1] < 1) f->val[1] = 1; - - } - } - break; - - default: - break; - } - } - - // if no bonus yet, get one based on 'wantgoodness' - if (!bonus) { + // chance of masterwork based on wantgoodness switch (wantgoodness) { - case G_GOOD: // 1 - 2 - bonus = 1; - if (onein(2)) bonus++; - break; - case G_GREAT: // 1 - 3 - bonus = 1; - while (onein(2) && (bonus < 3)) { - bonus++; + case G_GREAT: + if (onein(6)) { + wantom[nom++] = findobmod(OM_MASTERWORK); } break; - case G_EXCELLENT: // 1 - 4 - bonus = 1; - while (onein(2) && (bonus < 4)) { - bonus++; + case G_EXCELLENT: + if (onein(3)) { + wantom[nom++] = findobmod(OM_MASTERWORK); } break; - default: // no bonus - break; - } - } - - if (bonus && hasflag(o->flags, F_ENCHANTABLE)) { - // for swords, armour etc - addflag_real(o->flags, F_BONUS, bonus, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); - } - - // special rings which get randomized... - if (o->type->id == OT_RING_CON) { - flag_t *f; - f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_CON, NA, NULL); - if (f) { - if (bonus) f->val[2] = bonus; - else f->val[2] = rnd(1,3); - } - if (o->blessed == B_CURSED) f->val[2] *= -1; - } else if (o->type->id == OT_RING_DEX) { - flag_t *f; - f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_AGI, NA, NULL); - if (f) { - if (bonus) f->val[2] = bonus; - else f->val[2] = rnd(1,3); - } - if (o->blessed == B_CURSED) f->val[2] *= -1; - } else if (o->type->id == OT_RING_IQ) { - flag_t *f; - f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_IQ, NA, NULL); - if (f) { - if (bonus) f->val[2] = bonus; - else f->val[2] = rnd(1,3); - } - if (o->blessed == B_CURSED) f->val[2] *= -1; - } else if (o->type->id == OT_RING_STR) { - flag_t *f; - f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_STR, NA, NULL); - if (f) { - if (bonus) f->val[2] = bonus; - else f->val[2] = rnd(1,3); } - if (o->blessed == B_CURSED) f->val[2] *= -1; - } + for (n = 0; n < nom; n++) { + // add flags from obmod + applyobmod(o, wantom[n]); + // other effects... + switch (wantom[n]->id) { + case OM_FLAMING: // flaming weapons are immune to fire + if (o->type->obclass->id == OC_WEAPON) { + if (!isimmuneto(o->flags, DT_FIRE, B_FALSE)) { + addflag(o->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); + } + } + break; + case OM_FROZEN: + if (o->material->id != MT_FIRE) { // fire can't be frozen! + // made of ice + // note: not using changemat() here to avoid adding f_frozen twice. + o->material = findmaterial(MT_ICE); + } + break; + case OM_MASTERWORK: + if (isweapon(o) || isarmour(o)) { + flag_t *f; + f = hasflag(o->flags, F_OBHP); + if (f) { + f->val[0] *= 2; + f->val[1] *= 2; + } + } + break; + case OM_SHODDY: + if (isweapon(o) || isarmour(o)) { + flag_t *f; + f = hasflag(o->flags, F_OBHP); + if (f) { + f->val[0] /= 2; if (f->val[0] < 1) f->val[0] = 1; + f->val[1] /= 2; if (f->val[1] < 1) f->val[1] = 1; - // now apply a random brand if we wanted one - if (!wantbrand && dorandombrand) { - wantbrand = getrandombrandfor(ot); - } + } + } + break; - } - - // apply the brand - if (wantbrand) { - if (brandappliesto(wantbrand, o->type)) { - copyflags(o->flags, wantbrand->flags, FROMBRAND); - addflag(o->flags, F_HASBRAND, wantbrand->id, NA, NA, NULL); - } - } - - if (where->owner) { - // new owner gains "hold confer" flags conferred by this object - giveobflags(where->owner, o, F_HOLDCONFER); - } - - // special cases - - // ie. don't do these things when just creating objects - // for validation purposes - if (obloc) { - // containers - if (hasflag(o->flags, F_CONTAINER)) { - if (getoblocation(o)) { - givestartobs(NULL, o, o->flags); - } - } - - - - // locked? - if (!lockchance) { - f = hasflag(o->flags, F_CANBELOCKED); - if (f) { - lockchance = f->val[0] + (f->val[1] * (obloc->map->depth/5)); - limit(&lockchance, f->val[0], 100); - } - } - if (lockchance && pctchance(lockchance)) { - addflag(o->flags, F_LOCKED, B_TRUE, getdoorlockdiff(obloc->map->depth), NA, NULL); - } - - // trapped? l1=10%, l5=20%, l10=30%, l15=40%, l20+=60% - if (!trapchance) { - f = hasflag(o->flags, F_CANBETRAPPED); - if (f) { - trapchance = f->val[0] + (f->val[1] * (obloc->map->depth/5)); - limit(&trapchance, f->val[0], f->val[2]); - } - } - if (trapchance && pctchance(trapchance)) { - enum OBTYPE traptype; - // get a random trap - // - traptype = getrandomtrapforob(); - addflag(o->flags, F_TRAPPED, traptype, NA, NA, NULL); - } - } - - if (o->pile->where) { - vault_t *v; - v = getcellvault(o->pile->where); - // apply cost to shop items - if (v && hasflag(v->flags, F_VAULTISSHOP)) { - if (canpickup(NULL, o, 1)) { - addflag(o->flags, F_SHOPITEM, getobvalue(o), getroomid(o->pile->where), NA, NULL); - } - } - // blood will stain things on the ground - if (o->material->id == MT_BLOOD) { - object_t *poss[MAXPILEOBS],*oo; - int nposs = 0; - // bloodstain one piece of armour - for (oo = o->pile->first ; oo ; oo = oo->next) { - if ((oo != o) && isarmour(oo)) { - poss[nposs++] = oo; + default: + break; } } - if (nposs) { - oo = poss[rnd(0,nposs-1)]; - applyobmod(oo, findobmod(OM_BLOODSTAINED)); + + // if no bonus yet, get one based on 'wantgoodness' + if (!bonus) { + switch (wantgoodness) { + case G_GOOD: // 1 - 2 + bonus = 1; + if (onein(2)) bonus++; + break; + case G_GREAT: // 1 - 3 + bonus = 1; + while (onein(2) && (bonus < 3)) { + bonus++; + } + break; + case G_EXCELLENT: // 1 - 4 + bonus = 1; + while (onein(2) && (bonus < 4)) { + bonus++; + } + break; + default: // no bonus + break; + } + } + + if (bonus && hasflag(o->flags, F_ENCHANTABLE)) { + // for swords, armour etc + addflag_real(o->flags, F_BONUS, bonus, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); + } + + // special rings which get randomized... + if (o->type->id == OT_RING_CON) { + flag_t *f; + f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_CON, NA, NULL); + if (f) { + if (bonus) f->val[2] = bonus; + else f->val[2] = rnd(1,3); + } + if (o->blessed == B_CURSED) f->val[2] *= -1; + } else if (o->type->id == OT_RING_DEX) { + flag_t *f; + f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_AGI, NA, NULL); + if (f) { + if (bonus) f->val[2] = bonus; + else f->val[2] = rnd(1,3); + } + if (o->blessed == B_CURSED) f->val[2] *= -1; + } else if (o->type->id == OT_RING_IQ) { + flag_t *f; + f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_IQ, NA, NULL); + if (f) { + if (bonus) f->val[2] = bonus; + else f->val[2] = rnd(1,3); + } + if (o->blessed == B_CURSED) f->val[2] *= -1; + } else if (o->type->id == OT_RING_STR) { + flag_t *f; + f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_STR, NA, NULL); + if (f) { + if (bonus) f->val[2] = bonus; + else f->val[2] = rnd(1,3); + } + + if (o->blessed == B_CURSED) f->val[2] *= -1; + } + + // now apply a random brand if we wanted one + if (!wantbrand && dorandombrand) { + wantbrand = getrandombrandfor(ot); + } + + } + + // apply the brand + if (wantbrand) { + if (brandappliesto(wantbrand, o->type)) { + copyflags(o->flags, wantbrand->flags, FROMBRAND); + addflag(o->flags, F_HASBRAND, wantbrand->id, NA, NA, NULL); } } - } + + if (where->owner) { + // new owner gains "hold confer" flags conferred by this object + giveobflags(where->owner, o, F_HOLDCONFER); + } + + // special cases + + // ie. don't do these things when just creating objects + // for validation purposes + if (obloc) { + // containers + if (hasflag(o->flags, F_CONTAINER)) { + if (getoblocation(o)) { + givestartobs(NULL, o, o->flags); + } + } + + + + // locked? + if (!lockchance) { + f = hasflag(o->flags, F_CANBELOCKED); + if (f) { + lockchance = f->val[0] + (f->val[1] * (obloc->map->depth/5)); + limit(&lockchance, f->val[0], 100); + } + } + if (lockchance && pctchance(lockchance)) { + addflag(o->flags, F_LOCKED, B_TRUE, getdoorlockdiff(obloc->map->depth), NA, NULL); + } + + // trapped? l1=10%, l5=20%, l10=30%, l15=40%, l20+=60% + if (!trapchance) { + f = hasflag(o->flags, F_CANBETRAPPED); + if (f) { + trapchance = f->val[0] + (f->val[1] * (obloc->map->depth/5)); + limit(&trapchance, f->val[0], f->val[2]); + } + } + if (trapchance && pctchance(trapchance)) { + enum OBTYPE traptype; + // get a random trap + // + traptype = getrandomtrapforob(); + addflag(o->flags, F_TRAPPED, traptype, NA, NA, NULL); + } + } + + if (o->pile->where) { + vault_t *v; + v = getcellvault(o->pile->where); + // apply cost to shop items + if (v && hasflag(v->flags, F_VAULTISSHOP)) { + if (canpickup(NULL, o, 1)) { + addflag(o->flags, F_SHOPITEM, getobvalue(o), getroomid(o->pile->where), NA, NULL); + } + } + // blood will stain things on the ground + if (o->material->id == MT_BLOOD) { + object_t *poss[MAXPILEOBS],*oo; + int nposs = 0; + // bloodstain one piece of armour + for (oo = o->pile->first ; oo ; oo = oo->next) { + if ((oo != o) && isarmour(oo)) { + poss[nposs++] = oo; + } + } + if (nposs) { + oo = poss[rnd(0,nposs-1)]; + applyobmod(oo, findobmod(OM_BLOODSTAINED)); + } + } + } + } // end if !loading if ((gamemode == GM_GAMESTARTED) && !inaskcoords) { if (o && where->where && !hasflag(o->flags, F_NOGLYPH) && haslos(player, where->where) ) { @@ -2241,14 +2272,11 @@ int blessob(object_t *o) { void brightflash(cell_t *centre, int range, lifeform_t *immunelf) { int x,y; cell_t *c; + char buf[BUFLEN]; - animradial(centre, range, '}', C_WHITE); + sprintf(buf, "You see an intense flash of light!"); + animradial(centre, range, '}', DT_ORTH, C_WHITE, buf, buf); - // announce - if (haslos(player, centre) && !isblind(player)) { - msg("You see an intense flash of light!"); - more(); - } // blind monsters for (y = centre->y - range; y <= centre->y + range; y++) { for (x = centre->x - range; x <= centre->x + range; x++) { @@ -3270,7 +3298,7 @@ void genhiddennames(void) { if (strlen(f->text)) { thisname = strdup(f->text); } else { - thisname = genhiddenname(ot->obclass->id); + thisname = strdup(genhiddenname(ot->obclass->id)); } sethiddenname(ot, thisname); free(thisname); @@ -3486,6 +3514,10 @@ int getobvalue(object_t *o) { return o->amt; } + if (o->type->id == OT_CREDITCARD) { + return getcharges(o); + } + // base value: weight * material value price = (float)getobweight(o) * (float)getmaterialvalue(o->material->id); //adjustprice(o->type, &price); @@ -3544,15 +3576,16 @@ int getobvalue(object_t *o) { // rarity rarity = getobrarity(o, &rr); - // potions + /* if (o->type->obclass->id == OC_POTION) { // potion value is based on rarity - price += ((100 - rarity)*0.5); + price += (rr * 112); } else if (o->type->obclass->id == OC_TOOLS) { // tool value is based on rarity - price += ((100 - rarity)*3.75); + //price += ((100 - rarity)*3.75); + price += ((rr*43) + (r-1)*22); } else if (o->type->obclass->id == OC_TECH) { - // tech value is based on tech level & rarity + // tech value is based on tech level float multiplier = 1; switch (gettechlevel(o->type->id)) { case PR_INEPT: @@ -3577,8 +3610,10 @@ int getobvalue(object_t *o) { multiplier = 10.25; break; } - price += ((100 - rarity)*multiplier); + //price += ((100 - rarity)*multiplier); + price += ((rr*20)*multiplier); } + */ // TODO: conferred intrinsics - depends on which one @@ -4329,6 +4364,12 @@ char *getobextrainfo(object_t *o, char *buf) { } else { snprintf(chargestr, BUFLEN, " (depleted)"); } + } else if (o->type->id == OT_CREDITCARD) { + if (f->val[0] > 0) { + snprintf(chargestr, BUFLEN, " ($%d balance)",f->val[0]); + } else { + snprintf(chargestr, BUFLEN, " (maxed out)"); + } } else { if (f->val[0] > 0) { snprintf(chargestr, BUFLEN, " (%d charge%s left)",f->val[0], (f->val[0] == 1) ? "" : "s"); @@ -4375,6 +4416,15 @@ cell_t *getobpilelocation(obpile_t *op) { return NULL; } +char *getshopobname(object_t *o, char *buf, int count) { + if (gettechlevel(o->type->id) > getskill(player, SK_TECHUSAGE)) { + // unidentified tech - hide the name + return real_getobname(o, buf, o->amt, B_TRUE, B_TRUE, B_TRUE, B_TRUE, B_FALSE); + } + // anything else - show the real name + return real_getobname(o, buf, o->amt, B_TRUE, B_TRUE, B_TRUE, B_TRUE, B_TRUE); +} + char *getobname(object_t *o, char *buf, int count) { return real_getobname(o, buf, count, B_TRUE, B_TRUE, B_TRUE, B_TRUE, B_FALSE); } @@ -4922,10 +4972,12 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan else strcpy(triedbuf, " ["); strcat(triedbuf, "tried"); } - if (lfhasflagval(player, F_FAILEDINSPECT, o->type->id, NA, NA, NULL)) { - if (strlen(triedbuf)) strcat(triedbuf, ", "); - else strcpy(triedbuf, " ["); - strcat(triedbuf, "inspected"); + if (!isknown(o)) { + if (lfhasflagval(player, F_FAILEDINSPECT, o->type->id, NA, NA, NULL)) { + if (strlen(triedbuf)) strcat(triedbuf, ", "); + else strcpy(triedbuf, " ["); + strcat(triedbuf, "inspected"); + } } if (strlen(triedbuf)) { strcat(triedbuf, "]"); @@ -5180,12 +5232,10 @@ char *real_getrandomob(map_t *map, char *buf, int forcedepth, int forcehabitat, 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; @@ -5264,6 +5314,25 @@ char *real_getrandomob(map_t *map, char *buf, int forcedepth, int forcehabitat, nwantclass = 1; } + if ((nwantclass == 1) && (wantclass[0] == OC_BUILDING)) { + int minused = 9999; + // find least used building + for (i = 0; i < nbuildingusage; i++) { + if (buildingusage[i].count < minused) { + minused = buildingusage[i].count; + } + } + // find possibilities + for (i = 0; i < nbuildingusage; i++) { + if (buildingusage[i].count == minused) { + poss[nposs++] = findot(buildingusage[i].oid); + } + } + assert(nposs > 0); + sprintf(buf, "%s", poss[rnd(0,nposs-1)]->name); + return buf; + } + while (!done) { if (db || partdb) dblog("adding random object with rarity value between %d - %d and rr <= %d, for habitat %s", raritymin,raritymax,wantrr, habname); @@ -5374,9 +5443,6 @@ char *real_getrandomob(map_t *map, char *buf, int forcedepth, int forcehabitat, // matches wanted weapon skill? if (wantsk) { - if (ot->id == OT_QUICKBLADE) { - dblog("xxx"); - } if (!hasflagval(ot->flags, F_USESSKILL, wantsk->id, NA, NA, NULL)) { condok = B_FALSE; if (db) dblog(" %s doesn't use correct weapon skill.", ot->name); @@ -5423,9 +5489,6 @@ char *real_getrandomob(map_t *map, char *buf, int forcedepth, int forcehabitat, // give up strcpy(buf, ""); if (db || partdb) dblog("no possible random objects at all for habitat %s! giving up.", habname); - if (!hab) { - dblog("xxx"); - } return NULL; } } @@ -5561,7 +5624,7 @@ char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf) { 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; + //if (depthmod == NA) depthmod = 0; return real_getrandomob(map, buf, getmapdifficulty(map) + depthmod, NA, SZ_MAX, SK_NONE, B_FALSE, cid, OC_NONE, DT_NONE); } @@ -6256,6 +6319,9 @@ int isdangerousob(object_t *o, lifeform_t *lf, int onlyifknown) { } int isdeadob(object_t *o) { + if (o->dying) { + return B_TRUE; + } if (hasflag(o->flags, F_DEAD)) { return B_TRUE; } @@ -6679,6 +6745,88 @@ int killallobsexcept(obpile_t *op, ...) { return nkilled; } +void killbrand(brand_t *b) { + brand_t *nextone, *lastone; + + // free mem + if (b->description) free(b->description); + if (b->suffix) free(b->suffix); + killflagpile(b->flags); + + // remove from list + nextone = b->next; + if (nextone != NULL) { + nextone->prev = b->prev; + } else { /* last */ + lastbrand = b->prev; + } + + if (b->prev == NULL) { + /* first */ + nextone = b->next; + free(firstbrand); + firstbrand = nextone; + } else { + lastone = b->prev; + free (lastone->next ); + lastone->next = nextone; + } +} + + +void killhiddenname(hiddenname_t *hn) { + hiddenname_t *nextone, *lastone; + + // free mem + if (hn->text) free(hn->text); + hn->text = NULL; + + // remove from list + nextone = hn->next; + if (nextone != NULL) { + nextone->prev = hn->prev; + } else { /* last */ + lasthiddenname = hn->prev; + } + + if (hn->prev == NULL) { + /* first */ + nextone = hn->next; + free(firsthiddenname); + firsthiddenname = nextone; + } else { + lastone = hn->prev; + free (lastone->next ); + lastone->next = nextone; + } +} + +void killknowledge(knowledge_t *k) { + knowledge_t *nextone, *lastone; + + // free mem + if (k->hiddenname) free(k->hiddenname); + + // remove from list + nextone = k->next; + if (nextone != NULL) { + nextone->prev = k->prev; + } else { /* last */ + lastknowledge = k->prev; + } + + if (k->prev == NULL) { + /* first */ + nextone = k->next; + free(knowledge); + knowledge = nextone; + } else { + lastone = k->prev; + free (lastone->next ); + lastone->next = nextone; + } +} + void killmaterial(material_t *m) { material_t *nextone, *lastone; @@ -6727,6 +6875,8 @@ void killob(object_t *o) { // free mem if (o->inscription) free(o->inscription); + if (o->contents) killobpile(o->contents); + if (o->flags) killflagpile(o->flags); // remove from list nextone = o->next; @@ -6748,6 +6898,33 @@ void killob(object_t *o) { } } +void killobmod(obmod_t *om) { + obmod_t *nextone, *lastone; + + // free mem + if (om->prefix) free(om->prefix); + killflagpile(om->flags); + + // remove from list + nextone = om->next; + if (nextone != NULL) { + nextone->prev = om->prev; + } else { /* last */ + lastobmod = om->prev; + } + + if (om->prev == NULL) { + /* first */ + nextone = om->next; + free(firstobmod); + firstobmod = nextone; + } else { + lastone = om->prev; + free (lastone->next ); + lastone->next = nextone; + } +} + void killobpile(obpile_t *op) { killallobs(op); free(op); @@ -6943,14 +7120,6 @@ void makeknown(enum OBTYPE otid) { flag_t *retflag[MAXCANDIDATES]; int nretflags = 0; - /* - objecttype_t *ot; - ot = findot(otid); - if (ot && (ot->obclass->id == OC_TECH)) { - dblog("xxx"); - } - */ - if (player) { // if player is holding an object of that type with F_CONFER.. IFKNOWN... and isn't known... // then by making the object known, we also need to give them the flag. @@ -6989,6 +7158,10 @@ void makeknown(enum OBTYPE otid) { for (i = 0; i < nobs; i++) { giveobflags(player, srcob[i], fttogive[i]); } + f = lfhasflagval(player, F_FAILEDINSPECT, otid, NA, NA, NULL); + if (f) { + killflag(f); + } } void maketried(enum OBTYPE otid) { @@ -7203,14 +7376,13 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { while (tempop->first) { o = relinkob(tempop->first, dst); } - free(tempop); + killobpile(tempop); } } if (o) { - if (dst->owner && isplayer(dst->owner) && isblessknown(o)) { o->blessknown = B_TRUE; } @@ -7287,6 +7459,30 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { if (f && (f->val[1] != curtime)) { triggertrap(NULL, o, oo, dst->where); } + // bless objects which land on a holy circle. + if ((oo->type->id == OT_HOLYCIRCLE) && !blessob(o)) { + // holy circle vanishes. + if (onein(3)) { + if (haslos(player, dst->where)) { + char ooname[BUFLEN]; + getobname(oo, ooname, 1); + msg("%s fades and vanishes.", ooname); + } + removeob(oo, oo->amt); + } + } + // curse objects which land on a pentagram. + if ((oo->type->id == OT_PENTAGRAM) && !curseob(o)) { + // pentagrams don't vanish as often as holy circles + if (onein(6)) { + if (haslos(player, dst->where)) { + char ooname[BUFLEN]; + getobname(oo, ooname, 1); + msg("%s fades and vanishes.", ooname); + } + removeob(oo, oo->amt); + } + } } } } @@ -7364,6 +7560,8 @@ object_t *obexists(enum OBTYPE obid) { void obdie(object_t *o) { char obname[BUFLEN]; flag_t *f; + + o->dying = B_TRUE; // handle object conversion if (!doobdieconvert(o, B_TRUE)) { @@ -11136,18 +11334,17 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, explodecells(thrower->cell, roll(diebuf), B_FALSE, o, 1, DT_COMPASS, B_FALSE); } else if (o->type->id == OT_ASHSLEEP) { int radius; + char buf[BUFLEN]; // make smoke - if (haslos(player, srcloc)) { - msg("%s dispers%s into a wispy mist!", obname, - (amt == 1) ? "es" : "e", - (amt == 1) ? "es" : "e" ); + sprintf(buf, "%s dispers%s into a wispy mist!", obname, (amt == 1) ? "es" : "e" ); + if (haslos(player, srcloc)) { if (!isknown(o)) makeknown(o->type->id); } radius = o->amt * 2; if (radius > 10) radius = 10; - spellcloud(srcloc, radius, '}', C_MAGENTA, OT_S_SLEEP, radius, B_TRUE); + spellcloud(srcloc, radius, UNI_SHADELIGHT, C_MAGENTA, OT_S_SLEEP, radius, B_TRUE, buf, "A wispy mist appears!"); } else if (o->type->id == OT_SALT) { if (target && (getcelldist(srcloc, where) <= 1)) { if (hasbp(target, BP_EYES) && !isblind(target) && !getequippedob(target->pack, BP_EYES)) { @@ -12442,6 +12639,21 @@ int usecharge(object_t *o) { return -1; } +// returns charges remaining, -1 if object doesn't have the flag +int usecharges(object_t *o, int amt) { + flag_t *f; + f = hasflag(o->flags, F_CHARGES); + if (f) { + f->val[0] -= amt; + if (f->val[0] < 0) { + f->val[0] = 0; + } + return f->val[0]; + } + return -1; +} + + int validateobs(void) { objecttype_t *ot; int foundspells = B_FALSE; @@ -12457,6 +12669,13 @@ int validateobs(void) { } } + // remember buildings + if (ot->obclass->id == OC_BUILDING) { + buildingusage[nbuildingusage].oid = ot->id; + buildingusage[nbuildingusage].count = 0; + nbuildingusage++; + } + if ((ot->obclass->id == OC_SPELL) || (ot->obclass->id == OC_ABILITY)) { if (!foundspells) foundspells = B_TRUE; if (!hasflag(ot->flags, F_SPELLSCHOOL)) { @@ -12887,7 +13106,9 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob // penalty for throwing non-missiles if (missile && !firearm && !isthrowmissile(missile) && !tkthrow) { - acc -= 20; + if (!lfhasflagval(thrower, F_WILLTHROW, missile->type->id, NA, NA, NULL)) { + acc -= 20; + } } // modify for prone throwers if (isprone(thrower)) { diff --git a/objects.h b/objects.h index ae1cee4..50ef2ac 100644 --- a/objects.h +++ b/objects.h @@ -119,6 +119,7 @@ char *getobextrainfo(object_t *o, char *buf); cell_t *getoblocation(object_t *o); cell_t *getobpilelocation(obpile_t *op); char *getobname(object_t *o, char *buf, int count); +char *getshopobname(object_t *o, char *buf, int count); char *getobnametrue(object_t *o, char *buf, int count); char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wantcondition, int adjustforblind, int wantblesscurse, int showall); float getobpileweight(obpile_t *op); @@ -203,9 +204,14 @@ int isweapon(object_t *o); int iswearable(object_t *o); void killallobs(obpile_t *op); int killallobsexcept(obpile_t *op, ...); +void killbrand(brand_t *b); +void killhiddenname(hiddenname_t *hn); +void killknowledge(knowledge_t *k); void killmaterial(material_t *m); void killob(object_t *o); +void killobmod(obmod_t *om); void killobpile(obpile_t *o); +void killobtype(object_t *o); void killoc(objectclass_t *oc); void killot(objecttype_t *ot); int knockbackob(object_t *o, int dir, int howfar, int power, lifeform_t *pusher); @@ -260,6 +266,7 @@ void turnoff(lifeform_t *lf, object_t *o); void turnon(lifeform_t *lf, object_t *o); int uncurseob(object_t *o, int *seen); int usecharge(object_t *o); +int usecharges(object_t *o, int amt); int usefountaincharge(object_t *o, flag_t *drinkflag); int validateobs(void); int wepdullable(object_t *o); diff --git a/save.c b/save.c index 24e3100..1210d42 100644 --- a/save.c +++ b/save.c @@ -63,6 +63,8 @@ int loadall(void) { printf("Error loading map from file '%s'",ent->d_name); exit(1); } + // remove this map + unlink(ent->d_name); } } closedir(dir); @@ -260,7 +262,7 @@ lifeform_t *loadlf(FILE *f, cell_t *where) { } if (db) dblog("--> Finished oblist. Found %d objects.",obcount); - // now load load object defs for this player! + // now load object defs for this player! fscanf(f, "obdefs\n"); for (i = 0; i < obcount; i++) { long thisid; diff --git a/shops.c b/shops.c index e28a323..7a7e046 100644 --- a/shops.c +++ b/shops.c @@ -558,13 +558,7 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top for (o = vm->contents->first ; o ; o = o->next) { char obname[BUFLEN]; // get the name of the object - if (gettechlevel(o->type->id) > getskill(player, SK_TECHUSAGE)) { - // unidentifie tech - hide the name - real_getobname(o, obname, o->amt, B_TRUE, B_TRUE, B_TRUE, B_TRUE, B_FALSE); - } else { - // anything else - show the real name - real_getobname(o, obname, o->amt, B_TRUE, B_TRUE, B_TRUE, B_TRUE, B_TRUE); - } + getshopobname(o, obname, o->amt); snprintf(buf, BUFLEN, "%c - %s", o->letter, obname); snprintf(buf2, BUFLEN, "%-60s$%d",buf,(int)getshopprice(o, player)); mvwprintw(mainwin, y, 0, "%s", buf2); @@ -598,7 +592,7 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top slev = getskill(player, SK_THIEVERY); // confirm - getobname(o, obname, o->amt); + getshopobname(o, obname, o->amt); snprintf(buf, BUFLEN, "Buy%s %s for $%d?", slev ? "/steal" : "", obname, value); strcpy(validchars, "yn"); if (slev) { @@ -606,8 +600,59 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top } answer = askchar(buf, validchars,"n", B_TRUE, B_FALSE); if (answer == 'y') { + // prompt to use a card + if (hasob(player->pack, OT_CREDITCARD)) { + char ch2; + ch2 = askchar("Charge this purchase to your credit card?","yn","n", B_TRUE, B_FALSE); + if (ch2 == 'y') { + object_t *cc; + // ask which one + initprompt(&prompt, "Which credit card will you use?"); + for (cc = player->pack->first ; cc ; cc = cc->next) { + if (cc->type->id == OT_CREDITCARD) { + char cardname[BUFLEN]; + getobname(cc, cardname, 1); + addchoice(&prompt, cc->letter, cardname, cardname, cc, NULL); + } + } + if (prompt.nchoices == 1) { + // only one card? + cc = (object_t *)prompt.choice[0].data; + } else { + addchoice(&prompt, '-', "(cancel)", "(cancel)", NULL, NULL); + prompt.maycancel = B_TRUE; + getchoice(&prompt); + cc = (object_t *)prompt.result; + } + if (cc) { + if (getcharges(cc) >= getobvalue(o)) { + int shopamt; + // you got it! + usecharges(cc, getobvalue(o)); + o->letter = '\0'; + shopamt = o->amt; // avoid "purchased: 2 apples" when you only bought 1 but were holding 1 + o = moveob(o, player->pack, ALL); + identify(o); + getobname(o, obname, shopamt); + snprintf(toptext, BUFLEN, "Charged to card: %c - %s", o->letter, obname); + if (npurchased) (*npurchased)++; + // god of thieves likes credit cards... + pleasegodmaybe(R_GODTHIEVES, (value/75)); + return SR_CONTINUE; + } else { + // maxed! + usecharges(cc, getcharges(o)); // use up all remaining charges + // get kicked out + msg("^B\"Trying to use a maxed out card, eh? Get out of here, thief!\""); more(); + // shop closes + addflag(vm->flags, F_BANNEDLF, player->id, NA, NA, NULL); + return SR_QUIT; + } + } + } + } // do you have enough money? - if (slev || (countmoney(player->pack) >= getobvalue(o)) ) { + if (countmoney(player->pack) >= getobvalue(o) ) { int shopamt; object_t *gold; gold = hasob(player->pack, OT_GOLD); diff --git a/spell.c b/spell.c index be185c4..8ed9844 100644 --- a/spell.c +++ b/spell.c @@ -567,6 +567,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef taketime(user, getactspeed(user)*2); } else if (abilid == OT_A_CLIMB) { enum ERROR why; + + // for ai only: turn to face target cell first. + if (!isplayer(user) && targcell) { + turntoface(user, targcell); + } + if (!canclimb(user, &why)) { if (isplayer(user)){ switch (why) { @@ -1072,8 +1078,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (hasjob(user, J_MONK)) { if (getweapon(user)) { if (isplayer(user)) msg("You need be unarmed to perform an attack flurry!"); + return B_TRUE; } - return B_TRUE; } else if (!isdualweilding(user)) { if (isplayer(user)) msg("You need to be dual-weilding to perform an attack flurry!"); return B_TRUE; @@ -1240,10 +1246,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) msg("You can't jump with gravity boosted around you!"); return B_TRUE; } else if (lfhasflag(user, F_GRABBING)) { - if (isplayer(user)) msg("You can't jump while being held!"); + if (isplayer(user)) msg("You can't jump while holding someone!"); return B_TRUE; } else if (lfhasflag(user, F_GRABBEDBY)) { - if (isplayer(user)) msg("You can't jump while holding someone!"); + if (isplayer(user)) msg("You can't jump while being held!"); return B_TRUE; } @@ -1732,7 +1738,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) { int dir,dirch; dirch = askchar("Sprint in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { + if ((dirch == '.') || (dirch == '\0')) { msg("Cancelled."); return B_TRUE; } @@ -1753,8 +1759,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef targetname); } losehp(target, roll(damstr), DT_ACID, user, killername); - // cause ongoing pain for 2 turns - addtempflag(target->flags, F_PAIN, DT_ACID, NA, NA, damstr, 2); + if (!lfhasflagval(target, F_PAIN, DT_ACID, NA,NA, NULL)) { + // cause ongoing pain for 2 turns + addtempflag(target->flags, F_PAIN, DT_ACID, NA, NA, damstr, 2); + } taketime(user, getactspeed(user)); } else if (abilid == OT_A_STUDYSCROLL) { object_t *o; @@ -2110,10 +2118,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) msg("You can't tumble while airbourne!"); return B_TRUE; } else if (lfhasflag(user, F_GRABBING)) { - if (isplayer(user)) msg("You can't tumble while being held!"); + if (isplayer(user)) msg("You can't tumble while holding someone!"); return B_TRUE; } else if (lfhasflag(user, F_GRABBEDBY)) { - if (isplayer(user)) msg("You can't tumble while holding someone!"); + if (isplayer(user)) msg("You can't tumble while being held!"); return B_TRUE; } @@ -3882,6 +3890,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("The electricity arcs!"); } } // end while narccells + } else if (spellid == OT_S_CLONE) { + // duplicate the caster + targcell = getrandomadjcell(caster->cell, WE_WALKABLE, B_NOEXPAND); + if (!targcell) { + if (isplayer(caster)) fizzle(caster); + return B_TRUE; + } + if (isplayer(caster) || haslos(player, targcell)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + addmonster(targcell, caster->race->id, NULL, B_FALSE, 1, B_FALSE, NULL); } else if (spellid == OT_S_CLOUDKILL) { int radius; @@ -4074,16 +4093,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_COLDBURST) { int range = 1; int x,y; + char buf[BUFLEN]; range = 1 + (power / 5); // announce + sprintf(buf, "%s emit%s a blast of icy cold!",castername,isplayer(caster) ? "" : "s"); + animradial(caster->cell, range, '}', C_GREY, DT_ORTH, buf, "Something emits a blast of icy cold!"); + if (isplayer(caster) || cansee(player, caster)) { - msg("%s emit%s a blast of icy cold!",castername,isplayer(caster) ? "" : "s"); if (seenbyplayer) *seenbyplayer = B_TRUE; } - - animradialorth(caster->cell, range, '}', C_GREY); for (y = caster->cell->y - range ; y <= caster->cell->y + range; y++) { for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) { @@ -4439,8 +4459,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ makelitradius(targcell, power*2, L_PERMDARK, rnd(5,10) + power ); } calclight(targcell->map); - needredraw = B_TRUE; - drawscreen(); } else if (spellid == OT_S_DETECTAURA) { if (isplayer(caster)) { object_t *o; @@ -4912,17 +4930,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_ENERGYBLAST) { int range; int x,y; - // announce - if (caster) { - if (!targcell) targcell = caster->cell; - if (isplayer(caster) || cansee(player, caster)) { - msg("%s emit%s a radial blast of energy!",castername,isplayer(caster) ? "" : "s"); - if (seenbyplayer) *seenbyplayer = B_TRUE; - } - } - + char buf[BUFLEN]; + if (caster && !targcell) targcell = caster->cell; range = 2 + (power / 4); - animradial(targcell, range, '}', C_CYAN); + + sprintf(buf, "%s emit%s a radial blast of energy!",castername,isplayer(caster) ? "" : "s"); + animradial(targcell, range, '}', C_CYAN, DT_COMPASS, buf, "Something emits a radial blast of energy!"); + + if (isplayer(caster) || haslos(player, targcell)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } for (y = targcell->y - range ; y <= targcell->y + range; y++) { for (x = targcell->x - range ; x <= targcell->x + range; x++) { @@ -5265,17 +5282,20 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_FLAMEBURST) { int range = 1; int x,y; + char buf[BUFLEN],buf2[BUFLEN]; range = 1 + (power / 5); // announce + sprintf(buf, "%s emit%s a %sblast of fire!",castername,isplayer(caster) ? "" : "s", + (power >= 5) ? "huge " : ""); + sprintf(buf2, "Something emit%s a %sblast of fire!",isplayer(caster) ? "" : "s", + (power >= 5) ? "huge " : ""); + + animradial(caster->cell, range, '}', C_RED, DT_ORTH, buf, buf2); if (isplayer(caster) || cansee(player, caster)) { - msg("%s emit%s a %sblast of fire!",castername,isplayer(caster) ? "" : "s", - (power >= 5) ? "huge " : ""); if (seenbyplayer) *seenbyplayer = B_TRUE; } - - animradialorth(caster->cell, range, '}', C_RED); for (y = caster->cell->y - range ; y <= caster->cell->y + range; y++) { for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) { @@ -6143,17 +6163,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ nothinghappens(); return B_TRUE; } else { - int charges; + char extrabuf[BUFLEN]; identify(o); - getobname(o, buf, o->amt); + //getobname(o, buf, o->amt); + real_getobname(o, buf, o->amt, B_TRUE, B_TRUE, B_TRUE, B_TRUE, B_TRUE); + getobextrainfo(o, extrabuf); + if (strlen(extrabuf)) strcat(buf, extrabuf); // charges - charges = getcharges(o); - if (charges == -1) { - msgnocap("%c - %s.",o->letter, buf); - } else { - msgnocap("%c - %s (%d charges left).",o->letter, buf, charges); - } + msgnocap("%c - %s.",o->letter, buf); if (seenbyplayer) *seenbyplayer = B_TRUE; } } else { @@ -8238,6 +8256,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (targcell) { if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) { int dir; + char buf[BUFLEN]; cell_t *c; // centre snowball here... if (isplayer(caster)) { @@ -8246,12 +8265,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (cansee(player, caster)) { msg("%s launches a huge snowball!",castername); if (seenbyplayer) *seenbyplayer = B_TRUE; - } else if (haslos(player, targcell)) { - msg("An enormous ball of fire explodes!"); } anim(caster->cell, targcell, '^', C_WHITE); - animradialorth(targcell, 1, '}', C_WHITE); + + sprintf(buf, "A huge snowball explodes! "); + animradial(targcell, 1, '}', C_WHITE, DT_ORTH, buf, buf); redrawpause(); // add snow as follows (3 = medium, 2 = medium, 1 = smell) @@ -8427,7 +8446,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } howlong = getspellduration(5,10,blessed) + power; if (makenauseated(target, power, howlong)) { - fizzle(caster); + if (isplayer(caster)) nothinghappens(); return B_FALSE; } if (isplayer(target) || haslos(player, target->cell)) { @@ -10563,13 +10582,14 @@ int schoolappearsinbooks(enum SPELLSCHOOL ss) { return B_TRUE; } -void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot) { +void spellcloud(cell_t *srcloc, int radius, int ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot, char *seetext, char *noseetext) { int x,y; + objecttype_t *ot; + ot = findot(sid); + if (!ot) return; + if (ch != '\0') { - if (haslos(player, srcloc)) { - animradialorth(srcloc, radius, ch, col); - drawscreen(); - } + animradial(srcloc, radius, ch, col, DT_ORTH, seetext, noseetext); } for (y = srcloc->y - radius ; y <= srcloc->y + radius; y++) { for (x = srcloc->x - radius ; x <= srcloc->x + radius; x++) { @@ -10578,8 +10598,12 @@ void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYP if (c && c->lf && (c != srcloc) && !c->type->solid && haslof(srcloc, c, LOF_WALLSTOP, NULL)) { if (getcelldistorth(srcloc, c) <= radius) { - // fall asleep - dospelleffects(NULL, sid, power, c->lf, NULL, c, B_UNCURSED, NULL, frompot); + // cast the spell + if (ot->obclass->id == OC_SPELL) { + dospelleffects(NULL, ot->id, power, c->lf, NULL, c, B_UNCURSED, NULL, frompot); + } else if (ot->obclass->id == OC_ABILITY) { + abilityeffects(c->lf, ot->id, c, c->lf, NULL); + } } } } diff --git a/spell.h b/spell.h index c17494f..b7ad2d0 100644 --- a/spell.h +++ b/spell.h @@ -32,7 +32,7 @@ int getworkablematerials(lifeform_t *lf, enum SKILL skid , enum MATERIAL *repair object_t *getworkhelpob(obpile_t *op, enum MATERIAL mat); void pullobto(object_t *o, lifeform_t *lf); int schoolappearsinbooks(enum SPELLSCHOOL ss); -void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot); +void spellcloud(cell_t *srcloc, int radius, int ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot, char *seetext, char *noseetext); int spellisfromschool(int spellid, enum SPELLSCHOOL school); int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power, int *seenbyplayer, int announce); void stopspell(lifeform_t *caster, enum OBTYPE spellid); diff --git a/vault.c b/vault.c index 066c7aa..df381bc 100644 --- a/vault.c +++ b/vault.c @@ -75,6 +75,8 @@ vault_t *addvault(void) { v->valid = B_TRUE; v->state = VS_ALLOCATED; v->flags = addflagpile(NULL, NULL); + v->legend = NULL; + v->lastlegend = NULL; v->map[0].mlen = 0; v->map[0].w = 0; v->map[0].h = 0;