diff --git a/Makefile b/Makefile index 371477a..1d4b2fe 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,65 @@ -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 +#all: 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 + +all: ai.o attack.o data.o findleak.o flag.o god.o io.o lf.o map.o move.o nexus.o objects.o save.o shops.o spell.o text.o vault.o ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h nexus.h objects.h save.h shops.h spell.h text.h vault.h + gcc -g -Wall -o nexus ai.o attack.o data.o findleak.o flag.o god.o io.o lf.o map.o move.o nexus.o objects.o save.o shops.o spell.o text.o vault.o -lncurses -lsqlite3 + +ai.o: ai.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h ai.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o ai.o ai.c + +attack.o: attack.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h attack.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o attack.o attack.c + +data.o: data.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h data.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o data.o data.c + +findleak.o: findleak.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h findleak.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o findleak.o findleak.c + +flag.o: flag.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h flag.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o flag.o flag.c + +god.o: god.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h god.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o god.o god.c + +io.o: io.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h io.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o io.o io.c + +lf.o: lf.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h lf.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o lf.o lf.c + +map.o: map.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h map.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o map.o map.c + +move.o: move.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h move.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o move.o move.c + +nexus.o: nexus.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h nexus.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o nexus.o nexus.c + +objects.o: objects.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h objects.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o objects.o objects.c + +save.o: save.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h save.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o save.o save.c + +shops.o: shops.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h shops.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o shops.o shops.c + +spell.o: spell.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h spell.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o spell.o spell.c + +text.o: text.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h text.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o text.o text.c + +vault.o: vault.c ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h vault.h objects.h save.h shops.h spell.h text.h vault.h + gcc -Wall -c -g -o vault.o vault.c + + +###################### + +clean: + rm nexus *.o 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 c81ac27..03b40e5 100644 --- a/ai.c +++ b/ai.c @@ -167,8 +167,8 @@ enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) { } - f = lfhasflag(lf, F_NEEDOBFORSPELLS); - if (f && !hasob(lf->pack, f->val[0])) { + + if (missingspellcastob(lf)) { if (db) dblog(".oO { Cannot cast spell, I don't have my spellcast object }"); return OT_NONE; } @@ -308,14 +308,16 @@ cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *l f = ispetortarget(lf, target); if (f) { c = getcellat(lf->cell->map, f->val[1], f->val[2]); - if (c) { + if (c && cellwalkable(lf, c, NULL)) { if (lastx) *lastx = c->x; if (lasty) *lasty = c->y; if (strlen(f->text)) { locallastdir = atoi(f->text); } + trailcell = c; + if (lastx) *lastx = c->x; + if (lasty) *lasty = c->y; } - trailcell = c; } // if not, check for the most recent scent/footprints first @@ -350,13 +352,18 @@ cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *l // if we found somewhere, follow any trails out of there if (trailcell) { + finalcell = trailcell; if (locallastdir != D_NONE) { + cell_t *c; // follow the trail - finalcell = getcellindir(trailcell, locallastdir); - locallastdir = D_NONE; - } else { - finalcell = trailcell; + c = getcellindir(trailcell, locallastdir); + if (getcelldist(c, target->cell) < getcelldist(trailcell, target->cell)) { + locallastdir = D_NONE; + finalcell = c; + } } + if (lastx) *lastx = finalcell->x; + if (lasty) *lasty = finalcell->y; } // return last movement direction @@ -364,6 +371,13 @@ cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *l *lastdir = locallastdir; } + // just in case... + if (!finalcell) { + if ((*lastx != NA) && (*lasty != NA)) { + finalcell = getcellat(lf->cell->map, *lastx, *lasty); + } + } + return finalcell; } @@ -1489,7 +1503,7 @@ int ai_premovement(lifeform_t *lf) { if (lfhasflag(lf, F_RAGE)) return B_FALSE; // need light? - if (!lfhasflag(lf, F_PRODUCESLIGHT) && (lf->cell->map->illumination != IL_FULLLIT)) { + if (lfproduceslight(lf, NULL) && (lf->cell->map->illumination != IL_FULLLIT)) { object_t *lamp; lamp = hasobwithflagval(lf->pack, F_ACTIVATECONFER, F_PRODUCESLIGHT, NA, NA, NULL); if (lamp && !isactivated(lamp)) { @@ -1912,6 +1926,8 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { } else { // not already at their last known cell. try to go there. if (db) dblog(".oO { i cannot see my target. moving to last known loc %d/%d }",lastx,lasty); + assert(targcell->x == lastx); + assert(targcell->y == lasty); if (aigoto(lf, targcell, MR_LF, target, PERMENANT)) { if (db) dblog(".oO { set target cell for LKL. }"); // success @@ -2627,7 +2643,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG specificcheckok = B_FALSE; } else if (!safetorest(lf)) { specificcheckok = B_FALSE; - } else if (lfhasflag(lf, F_PRODUCESLIGHT)) { + } else if (lfproduceslight(lf, NULL)) { specificcheckok = B_FALSE; } } diff --git a/attack.c b/attack.c index 012872a..048949d 100644 --- a/attack.c +++ b/attack.c @@ -1649,7 +1649,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) rdam = roll(dicetext); if (cansee(player, victim)) { - msg("^%c%s%s %s %s %s!", isplayer(lf) ? 'b' : 'n', victimname, getpossessive(victimname), + msg("^%c%s%s %s %s %s!", getlfcol(lf, CC_BAD), victimname, getpossessive(victimname), noprefix(obname), getattackverb(victim, NULL, f->val[0], rdam, lf->maxhp), attackername); @@ -1718,10 +1718,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // high chance that ai will give up if we can't reach the victim if (!isplayer(lf) && !canreach(lf, victim, NULL)) { - if (pctchance(90)) { + if (pctchance(80)) { loseaitargets(lf); if (isplayer(victim) && cansee(player, lf)) { - msg("%s seems to have lost interest in you.", attackername); + //msg("%s seems to have lost interest in you.", attackername); + msg("%s can't reach you!", attackername); } } } @@ -1849,6 +1850,11 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { getextradamwep(wep, &dam[0], &damtype[0], &ndam, B_FALSE); getextradamlf(lf, &dam[0], &damtype[0], &ndam, B_FALSE); + if (isdoor(o, NULL)) { + // extra damage for engineering skill + dam[0] += getengineeringwallmod(lf); + } + for (i = 0; i < ndam; i++) { // announce the hit construct_hit_string(lf, NULL, attackername, obname, NULL, wep, damtype[i], dam[i], maxhp, i, B_FALSE, B_FALSE, B_FALSE, isunarmed, buf); @@ -2026,6 +2032,8 @@ int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag) { getextradamwep(wep, &dam[0], &damtype[0], &ndam, B_FALSE); getextradamlf(lf, &dam[0], &damtype[0], &ndam, B_FALSE); + // extra damage for engineering skill + dam[0] += getengineeringwallmod(lf); for (i = 0; i < ndam; i++) { char cellname[BUFLEN]; @@ -2141,6 +2149,9 @@ int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE da if (lf && !cansee(victim, lf)) return B_FALSE; + // need stamina to block + if (!getstamina(victim)) return B_FALSE; + // get all usable shields for this damtype getallshields(victim, damtype, shield, checkmod, &nshields); for (i = 0; i < nshields; i++) { @@ -3059,6 +3070,8 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isu if (!where) return; wep = fp->ob; + if (wep && isdeadob(wep)) wep = NULL; + if (wep) { cell_t *c; c = getoblocation(wep); @@ -3274,7 +3287,11 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isu if (wep && owner && victim) { enum DRAINTYPE draintype = DR_NONE; - if ((wep->type->id == OT_TEETH) && lfhasflag(owner, F_VAMPIRIC) && islowhp(victim)) { + flag_t *vampflag; + vampflag = lfhasflag(owner, F_VAMPIRIC); + if ((wep->type->id == OT_TEETH) && vampflag && + ((vampflag->val[0] == B_TRUE) || islowhp(victim)) + ) { draintype = DR_FROMBITE; } else if (hasflag(wep->flags, F_VAMPIRIC)) { draintype = DR_FROMWEP; diff --git a/data.c b/data.c index a50b1ec..1bd2f07 100644 --- a/data.c +++ b/data.c @@ -19,7 +19,6 @@ extern race_t *firstrace, *lastrace; extern raceclass_t *firstraceclass, *lastraceclass; extern job_t *firstjob, *lastjob; extern poisontype_t *firstpoisontype,*lastpoisontype; -extern subjob_t *firstsubjob,*lastsubjob; extern skill_t *firstskill, *lastskill; extern objecttype_t *objecttype; extern objectclass_t *objectclass,*lastobjectclass; @@ -219,21 +218,11 @@ void initjobs(void) { int i; flag_t *f; - // subjob definitions - keep these in alphabetical order - addsubjob(SJ_BATTLEMAGE, "Battlemage", "Unlike other warriors Battlemages are skilled in magic, but at the expense of the regular warrior abilities.", 'b'); - addsubjob(SJ_FIREMAGE, "Firemage", "Firemages weild the destructive powers of fire to incinerate their enemies.", 'f'); - addsubjob(SJ_ICEMAGE, "Icemage", "Icemages are masters over the powers of cold. Their magic is less direct damaging than that of their fire-based cousins, but can also be used for defence.", 'i'); - addsubjob(SJ_NECROMANCER, "Necromancer", "", 'n'); - addsubjob(SJ_PALADIN, "Paladin", "Paladins are holy warriors dedicated to the Goddess of Life. They gain powerful abilities and have access to healing magics, but these powers are dependant upon their goddess' approval. Paladins must take holy vows to only ever use battle equipiment which has first been blessed.", 'p'); - addsubjob(SJ_SCOURGE, "Scourge", "Scourges have dedicated their life to ridding the world of magic. Strict training has granted them an innate immunity to magic, but this immunity also extends to beneficial effects.", 's'); - addsubjob(SJ_AIRMAGE, "Skymage", "Initially the weakest of the mages, higher level Skymages become both extremely versatile and extremely power.", 's'); - addsubjob(SJ_WILDMAGE, "Wild Mage", "Wild mages specialise in the random power of Wild magic.", 'w'); - // job definitions // NOTE: try to always make the job's primary weapon be the first object defined. // this will make sure that they have the letter 'a'. - addjob(J_GOD, "Diety", "A divine job mainly known for its importance in debugging. Dieties can use all abilities and are prompted before death. Due to their infinite power, they consider earthly diversions such as high score tables beneath their dignity."); + addjob(J_GOD, "Diety", "A divine job mainly known for its importance in debugging. Dieties can use all abilities and are prompted before death. Due to their infinite power, they consider earthly diversions such as high score tables beneath their dignity.", JC_NONE); /* addflag(lastjob->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_AGI, AT_EXHIGH, NA, NULL); @@ -292,7 +281,7 @@ void initjobs(void) { } addflag(lastjob->flags, F_NOSCORE, B_TRUE, NA, NA, NULL); - addjob(J_ADVENTURER, "Adventurer", "Adventurers are a versatile jack-of-all-trades type job. They can learn all skills, and already have basic Cartography and Lore skills. They also start the game with three healing potions. Recommended for beginners."); + addjob(J_ADVENTURER, "Adventurer", "Adventurers are a versatile jack-of-all-trades type job. They can learn all skills, and already have basic Cartography and Lore skills. They also start the game with three healing potions. Recommended for beginners.", JC_FIGHTERTHIEF); // stat mods addflag(lastjob->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); // ie. select // initial objects @@ -353,7 +342,7 @@ void initjobs(void) { addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); */ - addjob(J_CHEF, "Chef", "Considered by some to be simple culinary experts, a chef's skillset is in fact surprisingly flexible. Their cooking skill can give a wide range of benefits, while working in a kitchen requires perception and a good ear. Once experienced, their ego lets them enter a bezerk rage during combat."); + addjob(J_CHEF, "Chef", "Considered by some to be simple culinary experts, a chef's skillset is in fact surprisingly flexible. Their cooking skill can give a wide range of benefits, while working in a kitchen requires perception and a good ear. Once experienced, their ego lets them enter a bezerk rage during combat.", JC_GENERAL); // stat mods addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 5, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 5, NA, NULL); @@ -397,7 +386,7 @@ void initjobs(void) { addflag(lastjob->flags, F_LEVABIL, 3, OT_A_RAGE, NA, NULL); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_COMMANDO, "Commando", "An elite modern military fighter. Commandoes are very well equipped and capable of using (or learning to use) all technology. Unfortunately their adreneline-filled lifestyle leaves them a little lacking in wisdom, and they have no magical aptitude."); + addjob(J_COMMANDO, "Commando", "An elite modern military fighter. Commandoes are very well equipped and capable of using (or learning to use) all technology. Unfortunately their adreneline-filled lifestyle leaves them a little lacking in wisdom, and they have no magical aptitude.", JC_FIGHTER); // stat mods addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 10, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_WIS, -5, NA, NULL); @@ -445,7 +434,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, PR_SKILLED, NA, NULL); // abilities addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_DRUID, "Druid", "Druids use the power of nature to aid themselves or harm others. They start with a pet wolf, and their spells are more powerful when near plants. They are willing to eat other lifeforms when neccessary but prefer a vegetable-based diet. Unlike other spellcasters, Druids gain spells automotically when levelling."); + addjob(J_DRUID, "Druid", "Druids use the power of nature to aid themselves or harm others. They start with a pet wolf, and their spells are more powerful when near plants. They are willing to eat other lifeforms when neccessary but prefer a vegetable-based diet. Unlike other spellcasters, Druids gain spells automotically when levelling.", JC_FIGHTERMAGE); // stats addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_WIS, 15, NA, NULL); @@ -462,7 +451,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_EVASION, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_SKILLED, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_ADEPT, NA, NULL); @@ -484,16 +473,18 @@ void initjobs(void) { addflag(lastjob->flags, F_LEVSPELLSCHOOLFROMX, 101, SS_NATURE, 3, NULL); // new enviromancy spell every 1 level addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf"); addflag(lastjob->flags, F_PARTVEGETARIAN, B_TRUE, NA, NA, NULL); + // at level 4, plants become allied. + addflag(lastjob->flags, F_LEVFLAG, 4, F_PLANTFRIEND, B_TRUE, NULL); addflag(lastjob->flags, F_LEVSKILL, 5, SK_LORE_NATURE, NA, NULL); addflag(lastjob->flags, F_LEVSPELL, 7, OT_S_PLANTWALK, NA, NULL); - addflag(lastjob->flags, F_LEVSKILL, 10, SK_LORE_NATURE, NA, NULL); + addflag(lastjob->flags, F_LEVSKILL, 9, SK_LORE_NATURE, NA, NULL); addflag(lastjob->flags, F_LEVSKILL, 15, SK_LORE_NATURE, NA, NULL); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); f = addflag(lastjob->flags, F_RNDSPELLCOUNT, 5, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 100); f = addflag(lastjob->flags, F_RNDSPELLSCHOOL, SS_NATURE, 1, 6, NULL); addcondition(f, FC_IFMONSTER, 100); /////////////////////////////////////// - addjob(J_MONK, "Monk", "A life of strict self-discipline from an early age makes Monks masters of unarmed combat. This discipline extends to their minds, sometimes allowing them to develop powerful psionic abilities over time. On the downside, they are useless with most weapons and are strict vegetarians."); + addjob(J_MONK, "Monk", "A life of strict self-discipline from an early age makes Monks masters of unarmed combat. This discipline extends to their minds, sometimes allowing them to develop powerful psionic abilities over time. On the downside, they are useless with most weapons and are strict vegetarians.", JC_FIGHTERMAGE); // stats addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 5, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 20, NA, NULL); @@ -528,7 +519,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_TRAPS, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_ENGINEERING, PR_ADEPT, NA, NULL); // abilities addflag(lastjob->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_CANWILL, OT_A_FEIGNDEATH, NA, NA, NULL); @@ -567,7 +558,7 @@ void initjobs(void) { f = addflag(lastjob->flags, F_RNDSPELLCOUNT, 4, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 100); f = addflag(lastjob->flags, F_RNDSPELLSCHOOL, SS_MENTAL, 1, 6, NULL); addcondition(f, FC_IFMONSTER, 100); - addjob(J_HUNTER, "Hunter", "Hunters eke out a living hunting game in the woods. Their dependance on wild animals for sustenance has made them skilled archers."); + addjob(J_HUNTER, "Hunter", "Hunters eke out a living hunting game in the woods. Their dependance on wild animals for sustenance has made them skilled archers.", JC_FIGHTERRANGED); // stats addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 5, NA, NULL); @@ -607,7 +598,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, PR_ADEPT, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_TRAPS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_ENGINEERING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LORE_HUMANOID, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, NA, NA, NULL); // abilities @@ -620,7 +611,7 @@ void initjobs(void) { addflag(lastjob->flags, F_LEVSKILL, 15, SK_LORE_NATURE, NA, NULL); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_MECHANIC, "Mechanic", "Mechanics, while great at negotiating high hourly rates, are not generally very suited for adventuring. Their spanner and metal-working skills might come in handy though."); + addjob(J_MECHANIC, "Mechanic", "Mechanics, while great at negotiating high hourly rates, are not generally very suited for adventuring. Their spanner and metal-working skills might come in handy though.", JC_GENERAL); // stats addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 5, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_CHA, -20, NA, NULL); @@ -636,6 +627,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "rubber boots"); // initial skills addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ENGINEERING, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_METALWORK, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_BEGINNER, NA, NULL); @@ -652,7 +644,7 @@ void initjobs(void) { // abilities addflag(lastjob->flags, F_OBESE, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_NINJA, "Ninja", "A dark warrior-assassin dedicated to the art of ninjutsu. Ninjas are skilled with exotic weapons, and gain special martial arts abilities at higher levels."); + addjob(J_NINJA, "Ninja", "A dark warrior-assassin dedicated to the art of ninjutsu. Ninjas are skilled with exotic weapons, and gain special martial arts abilities at higher levels.", JC_FIGHTER); // stats addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 5, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 5, NA, NULL); @@ -710,7 +702,7 @@ void initjobs(void) { addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_PRINCE, "Prince", "Princes have lived a life of leisure and privilege. Their time is generally spent either hunting (making them quite fit and skilled with a bow) or reading (giving them knowledge about the world around them). As they normally travel with a pack of bodyguards though, their weapons are more for show than actually useful."); + addjob(J_PRINCE, "Prince", "Princes have lived a life of leisure and privilege. Their time is generally spent either hunting (making them quite fit and skilled with a bow) or reading (giving them knowledge about the world around them). As they normally travel with a pack of bodyguards though, their weapons are more for show than actually useful.", JC_GENERAL); // stats addflag(lastjob->flags, F_JOBATTRMOD, A_CHA, 20, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_WIS, 10, NA, NULL); @@ -754,7 +746,7 @@ void initjobs(void) { // abilities addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_PIRATE, "Pirate", "Pirates roam the seven seas, their mug of ale in one hand, and... nothing much in the other, since all pirates (in deference to some kind of ancient tale) have had their left hand replaced with a sharp hook. Their lifestyle has made them very wealthy and given them an impressive ability to handle their alcohol. They even start with a pet hawk. On the other hand, they are missing an eye, and not very attractive."); + addjob(J_PIRATE, "Pirate", "Pirates roam the seven seas, their mug of ale in one hand, and... nothing much in the other, since all pirates (in deference to some kind of ancient tale) have had their left hand replaced with a sharp hook. Their lifestyle has made them very wealthy and given them an impressive ability to handle their alcohol. They even start with a pet hawk. On the other hand, they are missing an eye, and not very attractive.", JC_GENERAL); // stats addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 15, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 10, NA, NULL); @@ -804,18 +796,18 @@ void initjobs(void) { // also: has a hook instead of fists. addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_ROGUE, "Rogue", "Rogues (AKA \"thieves\") are criminals who are skilled in the appropriation of valuable goods. They can hide in the shadows, stab unsuspecting victims in the back and foil the most cunning traps."); + addjob(J_ROGUE, "Rogue", "Rogues (AKA \"thieves\") are criminals who are skilled in the appropriation of valuable goods. They can hide in the shadows, stab unsuspecting victims in the back and foil the most cunning traps.", JC_THIEF); // stats addflag(lastjob->flags, F_JOBATTRMOD, A_STR, -10, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 15, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -10, NA, NULL); addflag(lastjob->flags, F_ALIGNMENT, AL_NONE, NA, NA, "ne"); // initial objects - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "daggers"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "dagger"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 throwing knives"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather cloak"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "5 lockpicks"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 lockpicks"); // initial skills addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); @@ -824,6 +816,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LISTEN, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_BACKSTAB, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ENGINEERING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); @@ -852,7 +845,100 @@ void initjobs(void) { // abilities addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_WARRIOR, "Warrior", "Warriors are good at hitting things, hard."); + addjob(J_ASSASSIN, "Assassin", "Rogues of a darker dispoistion sometimes become Assassins, famed for their skill at taking lives. Assassins have less ability in lockpicking or thievery than regular rogues, prefering to tackle their enemies head on.", JC_THIEF); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 5, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 15, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, 0, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_EVIL, NA, NA, "e"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "short sword"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "5 poisoned knifes"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "3 potions of posion"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather cloak"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CLIMBING, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LISTEN, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_BACKSTAB, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_THROWING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_BEGINNER, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_ARMOUR, PR_NOVICE, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, PR_SKILLED, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_COMBAT, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); // + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_EXPERT, NA, NULL); // + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_WHIPS, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, PR_EXPERT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, PR_EXPERT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_DIVINATION, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_MENTAL, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_TRANSLOCATION, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_ARCANA, PR_ADEPT, NA, NULL); + // abilities + addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL); + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + addjob(J_KNIFEDANCER, "Knifedancer", "A more combat-focussed rogue who has trained exclusively in knife combat, at the expense of stealth and trap knowledge.", JC_FIGHTERRANGED); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 0, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 15, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -10, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_NONE, NA, NA, "ne"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "dagger"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "20 throwing knifes"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather cloak"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "3 lockpicks"); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CLIMBING, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LISTEN, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_THIEVERY, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_THROWING, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_BEGINNER, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_ARMOUR, PR_NOVICE, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, PR_SKILLED, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_COMBAT, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); // + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_SKILLED, NA, NULL); // + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_WHIPS, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, PR_EXPERT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, PR_EXPERT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_DIVINATION, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_MENTAL, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_TRANSLOCATION, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_ARCANA, PR_ADEPT, NA, NULL); + // abilities + addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL); + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + addjob(J_WARRIOR, "Warrior", "Warriors are good at hitting things, hard.", JC_FIGHTER); // stats addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 10, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 10, NA, NULL); @@ -914,12 +1000,213 @@ void initjobs(void) { addflag(lastjob->flags, F_LEVABIL, 8, OT_A_AIMEDSTRIKE, NA, NULL); addflag(lastjob->flags, F_LEVABIL, 10, OT_A_HURRICANESTRIKE, NA, NULL); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - // sub jobs - addflag(lastjob->flags, F_CANHAVESUBJOB, SJ_BATTLEMAGE, NA, NA, NULL); - addflag(lastjob->flags, F_CANHAVESUBJOB, SJ_PALADIN, NA, NA, NULL); - addflag(lastjob->flags, F_CANHAVESUBJOB, SJ_SCOURGE, NA, NA, NULL); - addjob(J_WIZARD, "Wizard", "Specialising in Arcane lore, high level wizards use their magic to create awe-inspiring effects on the world around them, raining death upon their enemies with eldritch wizardries. Not much is known about low level wizards, as they tend to get mauled to death by newts due to their lack of combat skills."); + addjob(J_BATTLEMAGE, "Battlemage", "Unlike other warriors Battlemages are minimally skilled in magic, but at the expense of the regular warrior abilities.", JC_FIGHTERMAGE); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CHA, -10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_WIS, -20, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "helmet"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "suit of ring mail"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of gauntlets"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "buckler"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10-20 gold dollars"); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_AXES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COMBAT, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CLUBS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_POLEARMS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_WHIPS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SEWING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_METALWORK, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_SS_ALLOMANCY, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_COOKING, PR_ADEPT, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_AXES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_EXOTICWEPS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LONGBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_FIRE, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_COLD, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_AIR, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_TRANSLOCATION, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_WILD, PR_ADEPT, NA, NULL); + // abilities + addflag(lastjob->flags, F_MPDICE, 1, 0, NA, NULL); + addflag(lastjob->flags, F_SELECTWEAPON, B_TRUE, NA, NA, NULL); + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + + addjob(J_PALADIN, "Paladin", "Paladins are holy warriors dedicated to the Goddess of Life. They gain powerful abilities and have access to healing magics, but these powers are dependant upon their goddess' approval. Paladins must take holy vows to only ever use battle equipiment which has first been blessed.", JC_FIGHTERMAGE); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, -10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CHA, 20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_WIS, 20, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_GOOD, NA, NA, "g"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "helmet"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "suit of ring mail"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of gauntlets"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "buckler"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10-20 gold dollars"); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_AXES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COMBAT, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CLUBS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_POLEARMS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_WHIPS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SEWING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_METALWORK, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); + // + addflag(lastjob->flags, F_STARTSKILL, SK_SS_LIFE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_SS_ALLOMANCY, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_COOKING, PR_ADEPT, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_AXES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_EXOTICWEPS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LONGBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, PR_ADEPT, NA, NULL); + // abilities + addflag(lastjob->flags, F_MPDICE, 1, -1, NA, NULL); + addflag(lastjob->flags, F_MAXHPMOD, 120, NA, NA, NULL); + addflag(lastjob->flags, F_SELECTWEAPON, B_TRUE, NA, NA, NULL); + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + // can permenantly turn undead for 0 power. + addflag(lastjob->flags, F_CANWILL, OT_S_TURNUNDEAD, NA, NA, NULL); + addflag(lastjob->flags, F_LEVABIL, 5, OT_S_DISRUPTUNDEAD, NA, NULL); + addflag(lastjob->flags, F_LEVABIL, 7, OT_S_EXORCISE, NA, "pw:1;"); + + addjob(J_SCOURGE, "Scourge", "Scourges have dedicated their life to ridding the world of magic. Strict training has granted them an innate immunity to magic, but this immunity also extends to beneficial effects.", JC_FIGHTER); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, -10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, 10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CHA, -10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_WIS, -20, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "bullwhip"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "helmet"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "suit of ring mail"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of gauntlets"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "buckler"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10-20 gold dollars"); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_AXES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CLUBS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_POLEARMS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_WHIPS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SEWING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_METALWORK, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_COOKING, PR_ADEPT, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_AXES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_EXOTICWEPS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LONGBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, PR_ADEPT, NA, NULL); + // abilities + addflag(lastjob->flags, F_MAXHPMOD, 120, NA, NA, NULL); + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + addflag(lastjob->flags, F_RESISTMAG, 5, NA, NA, NULL); + addflag(lastjob->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastjob->flags, F_LEVABIL, 2, OT_S_NULLIFY, NA, "pw:1;"); + addflag(lastjob->flags, F_LEVABIL, 4, OT_S_NULLIFY, NA, "pw:2;"); + addflag(lastjob->flags, F_LEVABIL, 6, OT_S_NULLIFY, NA, "pw:3;"); + addflag(lastjob->flags, F_LEVABIL, 8, OT_S_NULLIFY, NA, "pw:4;"); + addflag(lastjob->flags, F_LEVABIL, 10, OT_S_NULLIFY, NA, "pw:5;"); + addflag(lastjob->flags, F_LEVABIL, 12, OT_S_NULLIFY, NA, "pw:6;"); + addflag(lastjob->flags, F_LEVABIL, 14, OT_S_NULLIFY, NA, "pw:7;"); + addflag(lastjob->flags, F_LEVABIL, 16, OT_S_NULLIFY, NA, "pw:8;"); + addflag(lastjob->flags, F_LEVABIL, 18, OT_S_NULLIFY, NA, "pw:9;"); + addflag(lastjob->flags, F_LEVABIL, 20, OT_S_NULLIFY, NA, "pw:10;"); + addflag(lastjob->flags, F_NOSKILL, SK_SS_ALLOMANCY, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_MENTAL, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_NATURE, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_AIR, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_DEATH, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_DIVINATION, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_FIRE, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_COLD, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_LIFE, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_SUMMONING, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_TRANSLOCATION, NA, NA, NULL); + addflag(lastjob->flags, F_NOSKILL, SK_SS_WILD, NA, NA, NULL); + + +/* + addjob(J_WIZARD, "Wizard", "Specialising in Arcane lore, high level wizards use their magic to create awe-inspiring effects on the world around them, raining death upon their enemies with eldritch wizardries. Not much is known about low level wizards, as they tend to get mauled to death by newts due to their lack of combat skills.", JC_MAGE); // stats addflag(lastjob->flags, F_JOBATTRMOD, A_STR, -20, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 20, NA, NULL); @@ -972,22 +1259,294 @@ void initjobs(void) { addflag(lastjob->flags, F_LEVFLAG, 10, F_CONTROL, B_TRUE, NULL); //addflag(lastjob->flags, F_LEVSPELLSCHOOL, 101, SS_NONE, B_TRUE, NULL); // new spell every 1 level addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - // monsters - f = addflag(lastjob->flags, F_RNDSPELLCOUNT, 4, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 100); - f = addflag(lastjob->flags, F_RNDSPELLSCHOOL, SS_MENTAL, 1, 6, NULL); addcondition(f, FC_IFMONSTER, 100); - - // note: monster spells are defined in subjobs, since wizard MUST have a subjob. // monster job flags addflag(lastjob->flags, F_CASTCHANCE, 30, NA, NA, NULL); - // sub jobs - addflag(lastjob->flags, F_CANHAVESUBJOB, SJ_AIRMAGE, NA, NA, NULL); - addflag(lastjob->flags, F_CANHAVESUBJOB, SJ_FIREMAGE, NA, NA, NULL); - addflag(lastjob->flags, F_CANHAVESUBJOB, SJ_ICEMAGE, NA, NA, NULL); - addflag(lastjob->flags, F_CANHAVESUBJOB, SJ_NECROMANCER, NA, NA, NULL); - addflag(lastjob->flags, F_CANHAVESUBJOB, SJ_WILDMAGE, NA, NA, NULL); + */ + + addjob(J_AIRMAGE, "Skymage", "Those wizards who choose to specialise in the school of air learn to bend the very winds to their will. While initially the weakest of the mages, higher level Skymages become both extremely versatile and extremely power.", JC_MAGE); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, -20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -15, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "enchanted neophyte staff"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "wizard hat"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 potions of magic"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "15 blessed darts"); + // monster wizards sometimes start with a random book + f = addflag(lastjob->flags, F_STARTOBCLASS, 100, OC_BOOK, NA, NULL); addcondition(f, FC_IFMONSTER, 50); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_UNDEAD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_DEMONS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_THROWING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_AIR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DEATH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_FIRE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_COLD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_TRANSLOCATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_WILD, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DEMONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_UNDEAD, NA, NA, NULL); + // abilities + addflag(lastjob->flags, F_CANSEETHROUGHMAT, MT_GAS, NA, NA, NULL); + addflag(lastjob->flags, F_NEEDOBFORSPELLS, NA, F_WIZSTAFF, NA, "wizard staff"); + addflag(lastjob->flags, F_MAXHPMOD, 80, NA, NA, NULL); // low hp + addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); + addflag(lastjob->flags, F_RESTHEALTIME, 6, NA, NA, NULL); // wizard heals slowly, but regenerates mp + addflag(lastjob->flags, F_LEVFLAG, 3, F_DETECTMAGIC, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 7, F_DETECTAURAS, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 10, F_CONTROL, B_TRUE, NULL); + //addflag(lastjob->flags, F_LEVSPELLSCHOOL, 101, SS_NONE, B_TRUE, NULL); // new spell every 1 level + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + // monster job flags + addflag(lastjob->flags, F_CASTCHANCE, 30, NA, NA, NULL); + + addjob(J_FIREMAGE, "Firemage", "Firemages weild the destructive powers of fire to incinerate their enemies.", JC_MAGE); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, -20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -15, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "enchanted neophyte staff"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "wizard hat"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 potions of magic"); + // monster wizards sometimes start with a random book + f = addflag(lastjob->flags, F_STARTOBCLASS, 100, OC_BOOK, NA, NULL); addcondition(f, FC_IFMONSTER, 50); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_UNDEAD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_DEMONS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_AIR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DEATH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_FIRE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_COLD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_TRANSLOCATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_WILD, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DEMONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_UNDEAD, NA, NA, NULL); + // abilities + addflag(lastjob->flags, F_NEEDOBFORSPELLS, NA, F_WIZSTAFF, NA, "wizard staff"); + addflag(lastjob->flags, F_MAXHPMOD, 80, NA, NA, NULL); // low hp + addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); + addflag(lastjob->flags, F_RESTHEALTIME, 6, NA, NA, NULL); // wizard heals slowly, but regenerates mp + addflag(lastjob->flags, F_LEVFLAG, 3, F_DETECTMAGIC, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 7, F_DETECTAURAS, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 10, F_CONTROL, B_TRUE, NULL); + //addflag(lastjob->flags, F_LEVSPELLSCHOOL, 101, SS_NONE, B_TRUE, NULL); // new spell every 1 level + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + // monster job flags + addflag(lastjob->flags, F_CASTCHANCE, 30, NA, NA, NULL); + + addjob(J_ICEMAGE, "Icemage", "Icemages are masters over the powers of cold. Their magic is less direct damaging than that of their fire-based cousins, but can also be used for defence.", JC_MAGE); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, -20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -15, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "enchanted neophyte staff"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "wizard hat"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 potions of magic"); + // monster wizards sometimes start with a random book + f = addflag(lastjob->flags, F_STARTOBCLASS, 100, OC_BOOK, NA, NULL); addcondition(f, FC_IFMONSTER, 50); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_UNDEAD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_DEMONS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_AIR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DEATH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_FIRE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_COLD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_TRANSLOCATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_WILD, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DEMONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_UNDEAD, NA, NA, NULL); + // abilities + addflag(lastjob->flags, F_NEEDOBFORSPELLS, NA, F_WIZSTAFF, NA, "wizard staff"); + addflag(lastjob->flags, F_MAXHPMOD, 80, NA, NA, NULL); // low hp + addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); + addflag(lastjob->flags, F_RESTHEALTIME, 6, NA, NA, NULL); // wizard heals slowly, but regenerates mp + addflag(lastjob->flags, F_LEVFLAG, 3, F_DETECTMAGIC, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 7, F_DETECTAURAS, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 10, F_CONTROL, B_TRUE, NULL); + //addflag(lastjob->flags, F_LEVSPELLSCHOOL, 101, SS_NONE, B_TRUE, NULL); // new spell every 1 level + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + // monster job flags + addflag(lastjob->flags, F_CASTCHANCE, 30, NA, NA, NULL); + + addjob(J_NECROMANCER, "Necromancer", "The profession of Necromancer is one shunned by most, for it deals with the powers of death. Necromancers use their dark arts both to instil the dead with temporary life, and to make the living wish they were dead.", JC_MAGE); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, -20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -15, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_EVIL, NA, NA, "e"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "enchanted neophyte staff"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "wizard hat"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 potions of magic"); + // monster wizards sometimes start with a random book + f = addflag(lastjob->flags, F_STARTOBCLASS, 100, OC_BOOK, NA, NULL); addcondition(f, FC_IFMONSTER, 50); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_UNDEAD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_DEMONS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_AIR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DEATH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_FIRE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_COLD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_TRANSLOCATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_WILD, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DEMONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_UNDEAD, NA, NA, NULL); + // abilities + addflag(lastjob->flags, F_NEEDOBFORSPELLS, NA, F_WIZSTAFF, NA, "wizard staff"); + addflag(lastjob->flags, F_MAXHPMOD, 80, NA, NA, NULL); // low hp + addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); + addflag(lastjob->flags, F_RESTHEALTIME, 6, NA, NA, NULL); // wizard heals slowly, but regenerates mp + addflag(lastjob->flags, F_LEVFLAG, 3, F_DETECTMAGIC, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 7, F_DETECTAURAS, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 10, F_CONTROL, B_TRUE, NULL); + //addflag(lastjob->flags, F_LEVSPELLSCHOOL, 101, SS_NONE, B_TRUE, NULL); // new spell every 1 level + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + // monster job flags + addflag(lastjob->flags, F_CASTCHANCE, 30, NA, NA, NULL); + + addjob(J_WILDMAGE, "Wild Mage", "Wild mages specialise in the random power of Wild magic. While extremely powerful, the chaotic nature of their spells occasionally surprises even themselves.", JC_MAGE); + // stats + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, -20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_IQ, 20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -15, NA, NULL); + addflag(lastjob->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "enchanted neophyte staff"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "wizard hat"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 potions of magic"); + // monster wizards sometimes start with a random book + f = addflag(lastjob->flags, F_STARTOBCLASS, 100, OC_BOOK, NA, NULL); addcondition(f, FC_IFMONSTER, 50); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_UNDEAD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_DEMONS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_AIR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DEATH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_FIRE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_COLD, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_TRANSLOCATION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_WILD, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, PR_ADEPT, NA, NULL); // limit + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DEMONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_DRAGONS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LORE_UNDEAD, NA, NA, NULL); + // abilities + addflag(lastjob->flags, F_NEEDOBFORSPELLS, NA, F_WIZSTAFF, NA, "wizard staff"); + addflag(lastjob->flags, F_MAXHPMOD, 80, NA, NA, NULL); // low hp + addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); + addflag(lastjob->flags, F_RESTHEALTIME, 6, NA, NA, NULL); // wizard heals slowly, but regenerates mp + addflag(lastjob->flags, F_LEVFLAG, 3, F_DETECTMAGIC, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 7, F_DETECTAURAS, B_TRUE, NULL); + addflag(lastjob->flags, F_LEVFLAG, 10, F_CONTROL, B_TRUE, NULL); + //addflag(lastjob->flags, F_LEVSPELLSCHOOL, 101, SS_NONE, B_TRUE, NULL); // new spell every 1 level + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + // monster job flags + addflag(lastjob->flags, F_CASTCHANCE, 30, NA, NA, NULL); // monster jobs - addjob(J_GUARD, "Guard", "Guards are paid mercenaries employed to protect a certain area. Accordingly, they are generally outfitetd with high quality armour."); + addjob(J_GUARD, "Guard", "Guards are paid mercenaries employed to protect a certain area. Accordingly, they are generally outfitetd with high quality armour.", JC_GENERAL); addflag(lastjob->flags, F_NOPLAYER, B_TRUE, NA, NA, NULL); f = addflag(lastjob->flags, F_STARTOBWEPSK, SK_LONGBLADES, NA, NA, NULL); addcondition(f, FC_NOCONDITION, 50); @@ -1001,13 +1560,13 @@ void initjobs(void) { // 50% of guards are bribable f = addflag(lastjob->flags, F_WANTS, OT_GOLD, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 50); - addjob(J_DEMONOLOGIST, "Demonologist", "Demonologists frequently dabble into evil forces, summoning forth horrors from other planes of existence."); + addjob(J_DEMONOLOGIST, "Demonologist", "Demonologists frequently dabble into evil forces, summoning forth horrors from other planes of existence.", JC_GENERAL); addflag(lastjob->flags, F_NOPLAYER, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_STARTOB, 40, NA, NA, "bone helmet"); addflag(lastjob->flags, F_STARTOB, 70, NA, NA, "robes"); addflag(lastjob->flags, F_CANWILL, OT_S_SUMMONDEMON, 10, 10, "pw:2;"); - addjob(J_SHAMAN, "Shaman", "Shamans call on natural magics to heal allies or summon hordes of angry animals."); + addjob(J_SHAMAN, "Shaman", "Shamans call on natural magics to heal allies or summon hordes of angry animals.", JC_GENERAL); addflag(lastjob->flags, F_NOPLAYER, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_STARTOB, 40, NA, NA, "bone helmet"); addflag(lastjob->flags, F_STARTOB, 70, NA, NA, "robes"); @@ -1021,7 +1580,7 @@ void initjobs(void) { f = addflag(lastjob->flags, F_RNDSPELLCOUNT, 2, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 100); f = addflag(lastjob->flags, F_RNDSPELLSCHOOL, SS_NATURE, 1, 3, NULL); addcondition(f, FC_IFMONSTER, 100); - addjob(J_BERZERKER, "Berzerker", "Berzerkers can enter a start of berzerk rage for short periods."); + addjob(J_BERZERKER, "Berzerker", "Berzerkers can enter a start of berzerk rage for short periods.", JC_GENERAL); addflag(lastjob->flags, F_NOPLAYER, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_CANWILL, OT_A_RAGE, 20, 20, NULL); @@ -1221,7 +1780,7 @@ void initobjects(void) { addbrand(BR_SHARPNESS, "of penetration", BP_WEAPON, B_UNCURSED, 0); addflag_real(lastbrand->flags, F_ARMOURIGNORE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); addbrand(BR_LIFESUCK, "of lifesucking", BP_WEAPON, B_UNCURSED, 0); - addflag_real(lastbrand->flags, F_VAMPIRIC, NA, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); + addflag_real(lastbrand->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); addbrand(BR_PROTECTION, "of protection", BP_WEAPON, B_UNCURSED, 0); addflag_real(lastbrand->flags, F_EQUIPCONFER, F_ARBOOST, 10, NA, NULL, PERMENANT, B_UNKNOWN, -1); @@ -1511,7 +2070,7 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_OBHP, 50, 50, NA, NULL); addflag(lastobjectclass->flags, F_OBHPDRAIN, 1, DT_DECAY, NA, NULL); // ie. corpses last for 50 turns - addoc(OC_TECH, "Technology", "A strange piece of futuristic equipment. Perhaps someone with more skill in Technology could recognise it...", '[', C_GREY, RR_UNCOMMON); + addoc(OC_TECH, "Technology", "A strange piece of futuristic equipment. Perhaps someone with more skill in Technology could recognise it...", '[', C_GREY, RR_RARE); addocnoun(lastobjectclass, "technology"); addocnoun(lastobjectclass, "tech"); addflag(lastobjectclass->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL); @@ -1548,9 +2107,9 @@ void initobjects(void) { addot(OT_DOORWOOD, "wooden door", "A sturdy wooden door.", MT_WOOD, 150, OC_DFEATURE, SZ_LARGE); // GLYPH here is a special case in getglyph addflag(lastot->flags, F_DOOR, SZ_MIN, SZ_MAX, NA, NULL); - addflag(lastot->flags, F_DOORFALLOB, NA, NA, NA, "wooden plank"); + addflag(lastot->flags, F_DOORFALLOB, NA, NA, NA, "plank of wood"); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, B_TRUE, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -1571,7 +2130,7 @@ void initobjects(void) { addflag(lastot->flags, F_DOOR, SZ_MIN, SZ_MAX, NA, NULL); addflag(lastot->flags, F_DOORFALLOB, NA, NA, NA, "sheet of metal"); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, B_TRUE, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -1653,7 +2212,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_GREY, '/', NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); addflag(lastot->flags, F_CLIMBOBSTACLE, 90, NA, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, B_TRUE, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -1663,7 +2222,7 @@ void initobjects(void) { addot(OT_FENCEWOOD, "wooden fence", "A tell fence created from a series of upright logs of wood.", MT_WOOD, 200, OC_DFEATURE, SZ_LARGE); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); addflag(lastot->flags, F_CLIMBOBSTACLE, 80, NA, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, B_TRUE, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -1779,7 +2338,6 @@ void initobjects(void) { addflag(lastot->flags, F_GROWSTO, OT_BOULDER, VT_OB, NA, NULL); addflag(lastot->flags, F_SHRINKSTO, OT_STONE, VT_OB, NA, NULL); - addot(OT_STAIRSDOWN, "staircase going down", "A stone staircase winding downwards.", MT_STONE, 3000, OC_DFEATURE, SZ_HUGE); addflag(lastot->flags, F_GLYPH, NA, '>', NA, NULL); addflag(lastot->flags, F_STAIRS, B_TRUE, NA, NA, NULL); @@ -1868,6 +2426,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPENHOURS, 9, 17, SP_CLOSEDTILMORN, NULL); addflag(lastot->flags, F_SHOPACCEPTSFLAG, F_ARMOURRATING, NA, OC_ARMOUR, 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"); @@ -1881,6 +2440,7 @@ void initobjects(void) { addot(OT_SHOPBOOK, "book store", "A small kiosk dealing in books.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_VERYRARE, NULL); + addflag(lastot->flags, F_OPENHOURS, 9, 17, SP_CLOSEDTILMORN, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHOPACCEPTSFLAG, F_HASHIDDENNAME, NA, OC_SCROLL, NULL); addflag(lastot->flags, F_SHOPACCEPTSFLAG, F_HASHIDDENNAME, NA, OC_BOOK, NULL); @@ -1894,6 +2454,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPENHOURS, 9, 17, SP_CLOSEDTILMORN, NULL); make_basic_shop(lastot->flags, B_NOID, B_NODONATE); for (i = 0; i < 10; i++) { addflag(lastot->flags, F_STARTOBCLASS, 100, OC_FOOD, RANDOM, NULL); @@ -1902,6 +2463,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPENHOURS, 9, 17, SP_CLOSEDTILMORN, NULL); make_basic_shop(lastot->flags, B_NOID, B_NODONATE); for (i = 0; i < 10; i++) { addflag(lastot->flags, F_STARTOBRND, 100, RANDOM, NA, NULL); @@ -1909,6 +2471,7 @@ void initobjects(void) { 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_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_OPENHOURS, 9, 17, SP_CLOSEDTILMORN, NULL); addflag(lastot->flags, F_SHOPACCEPTSFLAG, F_HASHIDDENNAME, NA, OC_TOOLS, NULL); addflag(lastot->flags, F_SHOPACCEPTSFLAG, F_HASHIDDENNAME, NA, OC_TECH, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); @@ -1921,6 +2484,7 @@ void initobjects(void) { 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_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); + addflag(lastot->flags, F_OPENHOURS, 9, 17, SP_CLOSEDTILMORN, NULL); addflag(lastot->flags, F_SHOPACCEPTSFLAG, F_DRINKABLE, NA, OC_POTION, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); make_basic_shop(lastot->flags, B_ALLOWID, B_ALLOWDONATE); @@ -1939,6 +2503,7 @@ void initobjects(void) { 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_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_VERYRARE, NULL); + addflag(lastot->flags, F_OPENHOURS, 9, 17, SP_CLOSEDTILMORN, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHOPACCEPTSFLAG, F_GEM, 75, NA, NULL); addflag(lastot->flags, F_SHOPACCEPTSFLAG, F_JEWELERY, 75, NA, NULL); @@ -1961,6 +2526,7 @@ void initobjects(void) { addot(OT_SHOPWEAPON, "weapon store", "A small kiosk dealing in weapons.", MT_METAL, 500, OC_BUILDING, SZ_LARGE); addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); + addflag(lastot->flags, F_OPENHOURS, 9, 17, SP_CLOSEDTILMORN, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHOPACCEPTSFLAG, F_DAM, NA, OC_WEAPON, NULL); addflag(lastot->flags, F_SHOPMENU, 0, MA_GOTOMENU, SM_PURCHASEITEMS, "a:buy something"); @@ -2268,7 +2834,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, NA, '\'', NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL); addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, B_TRUE, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); // addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); @@ -2282,7 +2848,7 @@ void initobjects(void) { addot(OT_ICICLE, "huge icicle", "A massive ice stalacmite.", MT_ICE, 200, OC_ROCK, SZ_LARGE); addflag(lastot->flags, F_GLYPH, C_CYAN, '\'', NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, B_TRUE, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -2321,7 +2887,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, NA, RR_COMMON, ""); - addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); + addflag(lastot->flags, F_NUMAPPEAR, 1, 4, NA, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); @@ -2637,7 +3203,7 @@ void initobjects(void) { //addflag(lastot->flags, F_GLYPH, C_GREEN, '#', NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREEN, UNI_TREE, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, B_TRUE, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -2778,6 +3344,19 @@ void initobjects(void) { addflag(lastot->flags, F_PURIFIESTO, OT_MUSHROOMSHI, NA, NA, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "mushroom"); + + + addot(OT_MUSHROOMGREY, "greycap", "A strange mushroom with a greyish-white tip.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 50, NA, NULL); + addflag(lastot->flags, F_TAINTED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_SWAMP, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_RARE, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "mushroom"); + + addot(OT_MUSHROOMSTUFFED, "stuffed mushroom", "A large brown mushroom stuffed with breadcrumbs. This healthy food slightly increases your maximum hit points..", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); 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); @@ -3161,7 +3740,7 @@ void initobjects(void) { // allomancy /////////////////// // l1 - addot(OT_S_ABSORBMETAL, "absorb metal", "Draws mana from nearby metallic objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_ABSORBMETAL, "absorb metal", "Destroys nearby metallic objects to boost mana. Warning: this affects equipped weapons!", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the maximum amount of metal which can be absorbed."); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -3418,6 +3997,10 @@ void initobjects(void) { addflag(lastot->flags, F_EXTRADESC, 2, NA, NA, "At power VIII, exact creatures types are detected."); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addot(OT_S_REVEALHIDDEN, "reveal hidden", "Reveals hidden doors or invisible creatures in the caster's line of sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); // l3 addot(OT_S_AWARENESS, "heightened awareness", "This spell effectively gives the caster \"eyes in the back of their head\", expending their field of vision to a full 360 degrees.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); @@ -3448,10 +4031,6 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); - addot(OT_S_REVEALHIDDEN, "reveal hidden", "Reveals hidden doors or invisible creatures in the caster's line of sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); - addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); // l5 addot(OT_S_DETECTMAGIC, "detect magic", "Allows the caster to detect magical enchantments.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines duration."); @@ -3481,7 +4060,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_ADJSELF, NA, NA, NULL); - addflag(lastot->flags, F_TARGETTEDSPELL, TT_NONE, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_CALLWIND, "zephyr", "Conjures a friendly wind, carrying a single object to the caster's hands.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines its range and the weight of objects affected."); @@ -3997,6 +4576,11 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); // l2 + addot(OT_S_ABSORBWOOD, "absorb metal", "Destroys nearby wooden objects to boost caster's mana. Does NOT affect carried or equipped items.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the maximum amount of wood which can be absorbed."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_MPCOST, 0, NA, NA, NULL); addot(OT_S_BARKSKIN, "barkskin", "Covers the caster with a skin of bark, reducing damage but making them vulnerable to fire.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -4025,6 +4609,7 @@ void initobjects(void) { addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addot(OT_S_SOFTENEARTH, "soften earth", "Converts earth into mud, slowing down all who pass.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how much mud will be created."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level II this spell can transmute a single stone wall into dirt."); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_NONE, NA, NA, NULL); @@ -4213,8 +4798,8 @@ void initobjects(void) { // life spells / cleric spells /////////////////// // l1 - addot(OT_S_HEALINGMIN, "minor healing", "Restores 1-8 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell heals an extra 2 damage per power level."); + addot(OT_S_HEALINGMIN, "minor healing", "Restores 1-10 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell will always heal at least 2 hp per power."); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -4247,7 +4832,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODLIFE, 1, NA, NULL); addot(OT_S_HEALING, "healing", "Restores 10-20 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell heals an extra 2 damage per power level."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell will always heal at least 2 hp per power."); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); @@ -4278,7 +4863,7 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); addot(OT_S_HEALINGMAJ, "major healing", "Restores 20-30 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell heals an extra 2 damage per power level."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "This spell will always heal at least 2 hp per power."); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); @@ -4704,7 +5289,7 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); // l3 - addot(OT_S_ENERGYBLAST, "energy blast", "Causes a ring of energy to expand from the caster, causing 2d6 damage to anything in sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_ENERGYBLAST, "energy blast", "Causes a ring of energy to expand from the caster, causing 2d6 damage to anything in range.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the radius of the blast."); addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); @@ -4858,6 +5443,10 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_EMPLOY, "employ", "Assigns a job to the target lifeform.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addot(OT_A_BUILD, "build", "Create something out of raw materials.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); + addflag(lastot->flags, F_STAMCOST, 2, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); addot(OT_A_CHARGE, "charge", "You can quickly charge into close quarters for battle.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_STAMCOST, 2, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); @@ -4890,6 +5479,10 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); + addot(OT_A_DISMANTLE, "dismantle", "Attempt to remove an observed obstacle.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); + addflag(lastot->flags, F_STAMCOST, 2, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); addot(OT_A_DRAGUNDERGROUND, "drag underground", "You drag your foe underground to its doom.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); @@ -5447,6 +6040,11 @@ void initobjects(void) { addflag(lastot->flags, F_HOLDCONFER, F_DTIMMUNE, DT_POISON, NA, NULL); // tech - l0 + addot(OT_CHEWINGGUM, "packet of chewing gum", "A small packet containing a sticky gum.", MT_FOOD, 0.1, OC_TOOLS, SZ_MINI); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPERNEEDDIR, B_TRUE, NA, NA, "Use your gum in which direction"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 10, NA, ""); addot(OT_COMPUTER, "computer", "A complex technological device. In theory it is usable by most but without the correct skill your mileage may vary...", MT_METAL, 500, OC_TECH, SZ_LARGE); addflag(lastot->flags, F_GLYPH, C_BLUE, '[', NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); @@ -6264,7 +6862,7 @@ void initobjects(void) { addflag(lastot->flags, F_PURIFIESTO, OT_PUDDLEWATERL, NA, NA, NULL); addflag(lastot->flags, F_FILLPOT, OT_POT_BLOOD, NA, NA, NULL); - addot(OT_WOODPLANK, "plank of wood", "A large plank of heavy wood.", MT_WOOD, 150, OC_MISC, SZ_LARGE); + addot(OT_WOODPLANK, "plank of wood", "A large plank of heavy wood.", MT_WOOD, 150, OC_MISC, SZ_MEDIUM); addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, '_', NA, NULL); @@ -6346,14 +6944,17 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_WHITE, ',', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); + addflag(lastot->flags, F_DIMONWALK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addot(OT_MOSSSUN, "patch of sun moss", "A patch of brightly glowing yellow moss.", MT_PLANT, 0.1, OC_FLORA, SZ_MINI); addflag(lastot->flags, F_GLYPH, C_YELLOW, ',', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_DIMONWALK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 5, NA, NA, NULL); - - + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addot(OT_COFFIN, "coffin", "A wooden coffin, made for holding the dead.", MT_WOOD, 100, OC_FURNITURE, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, NULL); @@ -6459,7 +7060,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_YELLOW, '\'', NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL); addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, B_TRUE, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); // addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); @@ -6705,7 +7306,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_YELLOW, UNI_SHADEDARK, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); addflag(lastot->flags, F_REALLYIMPASSABLE, NA, NA, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, B_TRUE, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "vanishes"); @@ -7381,7 +7982,7 @@ void initobjects(void) { addflag(lastot->flags, F_VALUE, 600, NA, NA, NULL); - // rings + // rings - uncommon 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); @@ -7506,7 +8107,7 @@ void initobjects(void) { addflag(lastot->flags, F_EQUIPCONFER, F_STENCH, 2, 1, NULL); addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); addot(OT_RING_UNHOLINESS, "ring of unholiness", "An evil ring which renders its wearer effectively undead.", MT_METAL, 0.1, OC_RING, SZ_MINI); - addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_RARE, ""); + addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); addflag(lastot->flags, F_EQUIPCONFER, F_UNDEAD, B_TRUE, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DISEASEIMMUNE, B_TRUE, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_COLD, NA, NULL); @@ -7514,8 +8115,9 @@ void initobjects(void) { addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_POISONGAS, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_DECAY, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_NECROTIC, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_DTVULN, DT_HOLY, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_BREATHWATER, B_TRUE, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_DTVULN, DT_HOLY, NA, "2d6"); + addflag(lastot->flags, F_EQUIPCONFER, F_DTVULN, DT_LIGHT, NA, "2d6"); addflag(lastot->flags, F_EQUIPCONFER, F_NIGHTBOOST, 15, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DAYBOOST, -15, NA, NULL); addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); @@ -8032,11 +8634,11 @@ void initobjects(void) { addflag(lastot->flags, F_OBATTACKDELAY, 125, NA, NA, NULL); // short blades - addot(OT_COMBATKNIFE, "combat knife", "A sharp knife designed for military use.", MT_METAL, 1, OC_WEAPON, SZ_SMALL); + addot(OT_COMBATKNIFE, "combat knife", "A sharp, lightweight knife designed for military use.", MT_METAL, 1, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 65, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 75, NA, NA, NULL); - addflag(lastot->flags, F_DAM, DT_SLASH, 5, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 50, NA, NA, NULL); + addflag(lastot->flags, F_DAM, DT_SLASH, 4, NA, NULL); addflag(lastot->flags, F_ALTDAM, DT_PIERCE, 3, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -8060,8 +8662,8 @@ void initobjects(void) { addot(OT_DAGGER, "dagger", "A short stabbing weapon with a pointed blade.", MT_METAL, 1, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 90, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 50, NA, NA, NULL); - addflag(lastot->flags, F_DAM, DT_PIERCE, 4, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 75, NA, NA, NULL); + addflag(lastot->flags, F_DAM, DT_PIERCE, 5, NA, NULL); addflag(lastot->flags, F_ALTDAM, DT_SLASH, 4, NA, NULL); addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); @@ -8308,7 +8910,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); - addot(OT_SCIMITAR, "scimitar", "A fast, sharp, curved blade.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM); + addot(OT_SCIMITAR, "scimitar", "A curved blade with a wide, flattened end. Designed to be sharp and quick to use.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 90, NA, NA, NULL); @@ -8520,6 +9122,7 @@ void initobjects(void) { addflag(lastot->flags, F_CANBLOCK, DT_BASH, NA, NA, NULL); addot(OT_WIZARDSTAFF, "neophyte staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_WIZSTAFF, NA, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_RARE, NULL); @@ -8533,6 +9136,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addot(OT_WIZARDSTAFF2, "enchanter staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_WIZSTAFF, NA, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_RARE, NULL); @@ -8547,6 +9151,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addot(OT_WIZARDSTAFF3, "sorcerer staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_WIZSTAFF, NA, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_RARE, NULL); @@ -8560,6 +9165,7 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "twisted branch"); addot(OT_WIZARDSTAFF4, "spellbinder staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_WIZSTAFF, NA, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_VERYRARE, NULL); @@ -8574,6 +9180,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addot(OT_WIZARDSTAFF5, "warlock staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_WIZSTAFF, NA, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_VERYRARE, NULL); @@ -8588,6 +9195,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addot(OT_WIZARDSTAFF6, "archmagi staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); + addflag(lastot->flags, F_WIZSTAFF, NA, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_VERYRARE, NULL); @@ -8680,6 +9288,29 @@ void initobjects(void) { addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + // hammer + addot(OT_WARHAMMER, "warhammer", "A double-headed metal wedge mounted upon a long pole.", MT_METAL, 12, OC_WEAPON, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_RARITY, H_CAVE, 100, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 8, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 70, 80, "10"); + addflag(lastot->flags, F_CRITCHANCE, 15, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 4, NA, NA, ""); + + addot(OT_SLEDGEHAMMER, "sledgehammer", "A long handle with an extremely heavy cylindrical weight at one end.", MT_METAL, 20, OC_WEAPON, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_RARITY, H_CAVE, 100, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 14, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 80, 90, "10"); + addflag(lastot->flags, F_CRITCHANCE, 15, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 6, NA, NA, ""); + // exotic weapons addot(OT_KATANA, "katana", "A long, finely balanced blade. Ideal for critical hits.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); @@ -9041,6 +9672,46 @@ void initrace(void) { // givebehaviour() will modify maxhp // unique monsters / bosses + addrace(R_CLANK, "Clank", 200, '@', C_GREY, MT_METAL, RC_ROBOT, "An oversized humanoid mech with razor sharp metal teeth."); + setbodytype(lastrace, BT_HUMANOID); + setbodypartname(lastrace, BP_EARS, "audio sensors"); + setbodypartname(lastrace, BP_EYES, "video sensors"); + setbodypartname(lastrace, BP_BODY, "central frame"); + setbodypartname(lastrace, BP_LEGS, "stabilisers"); + setbodypartname(lastrace, BP_HANDS, "manipulators"); + setbodypartname(lastrace, BP_FEET, "propulsors"); + setbodypartname(lastrace, BP_RIGHTFINGER, "right sensor"); + setbodypartname(lastrace, BP_LEFTFINGER, "left sensor"); + addflag(lastrace->flags, F_NAME, NA, NA, NA, "Clank"); + addflag(lastrace->flags, F_UNIQUE, NA, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, NA, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 6, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 8, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ALIGNMENT, AL_NONE, NA, NA, NULL); + addflag(lastrace->flags, F_EXTRAINFO, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_TECHUSAGE, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "bleeps^a bleep"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 8, NA, NULL); + addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_CASTWITHOUTIQ, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_ENERGYBLAST, 10, 10, "pw:10;"); + addflag(lastrace->flags, F_CASTWITHOUTIQ, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTIME, 3, OT_S_ENERGYBLAST, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "begins to glow red."); + addflag(lastrace->flags, F_SPELLCASTCONTTEXT, OT_NONE, NA, NA, "begins to glow bright red"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + + addrace(R_JAILER, "jailer", 110, '@', C_MAGENTA, MT_FLESH, RC_HUMANOID, "Jailers are generally known for their surplus of brawn and utter lack of brains. This one is no different."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_NAME, NA, NA, NA, "Jimbo"); @@ -9290,7 +9961,7 @@ void initrace(void) { // stats addflag(lastrace->flags, F_PLAYABLE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL); @@ -9330,7 +10001,7 @@ void initrace(void) { setbodypartname(lastrace, BP_BODY, "central frame"); setbodypartname(lastrace, BP_LEGS, "stabilisers"); setbodypartname(lastrace, BP_HANDS, "manipulators"); - setbodypartname(lastrace, BP_FEET, "lower propulsion units"); + setbodypartname(lastrace, BP_FEET, "propulsors"); setbodypartname(lastrace, BP_RIGHTFINGER, "right sensor"); setbodypartname(lastrace, BP_LEFTFINGER, "left sensor"); // stats @@ -9456,6 +10127,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 7, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_METALWORK, PR_NOVICE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_ENGINEERING, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_SS_ALLOMANCY, PR_NOVICE, NA, NULL); // penalties addflag(lastrace->flags, F_MPMOD, -3, NA, NA, NULL); @@ -9608,7 +10280,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL); - addflag(lastrace->flags, F_STARTJOB, 33, J_WIZARD, SJ_NECROMANCER, NULL); + addflag(lastrace->flags, F_STARTJOB, 33, J_NECROMANCER, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 50, J_RANDOM, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -9718,7 +10390,7 @@ void initrace(void) { setbodypartname(lastrace, BP_BODY, "central frame"); setbodypartname(lastrace, BP_LEGS, "stabilisers"); setbodypartname(lastrace, BP_HANDS, "manipulators"); - setbodypartname(lastrace, BP_FEET, "lower propulsion units"); + setbodypartname(lastrace, BP_FEET, "propulsors"); setbodypartname(lastrace, BP_RIGHTFINGER, "right sensor"); setbodypartname(lastrace, BP_LEFTFINGER, "left sensor"); addflag(lastrace->flags, F_ALIGNMENT, AL_NONE, NA, NA, NULL); @@ -9778,6 +10450,8 @@ void initrace(void) { addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_TECH, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, 6, NA, NULL); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_SLIP, -30, NA, NULL); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_FALL, -30, NA, NULL); addrace(R_BOTSECURITY, "security bot", 90, 'b', C_BROWN, MT_METAL, RC_ROBOT, "One step up from droids, security bots are basic robotic constructs equipped with razor-sharp sawblades, and a protective force field."); addbodypart(lastrace, BP_BODY, "central core"); @@ -9809,6 +10483,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_TECH, NA, NULL); addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "swivels its sensors"); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_SLIP, -30, NA, NULL); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_FALL, -30, NA, NULL); addrace(R_DROID, "droid", 90, 'b', C_GREY, MT_METAL, RC_ROBOT, "Droids are very basic robots designed for one simple function. Generally this function is \"kill\". They can generate short (but powerful) electrical charges to deter trespassers."); addbodypart(lastrace, BP_BODY, "central core"); @@ -9836,6 +10512,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_TECH, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, 3, NA, NULL); addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_SLIP, -30, NA, NULL); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_FALL, -30, NA, NULL); addrace(R_FLAMETURRET, "flame turret", 100, 'R', C_RED, MT_METAL, RC_ROBOT, "A motorised flamethrower mounted on an automated turntable."); addbodypart(lastrace, BP_BODY, "central core"); @@ -9865,6 +10543,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_TECH, NA, NULL); addflag(lastrace->flags, F_AUTOROTATE, 1, NA, NA, NULL); addflag(lastrace->flags, F_FOLLOWTIME, 3, NA, NA, NULL); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_SLIP, -30, NA, NULL); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_FALL, -30, NA, NULL); addrace(R_HOVERSCOUT, "hoverscout", 100, 'b', C_CYAN, MT_METAL, RC_ROBOT, "An airborne drone constantly on the lookout for intruders. Hoverscouts are equipped with technology allowing them to teleport in backup units."); addbodypart(lastrace, BP_BODY, "central core"); @@ -9896,6 +10576,8 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "emits a beam of coloured light"); addflag(lastrace->flags, F_SPELLCASTCONTTEXT, OT_NONE, NA, NA, "intensifies its beam of light"); addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_TECH, NA, NULL); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_SLIP, -30, NA, NULL); + addflag(lastrace->flags, F_SKILLCHECKMOD, SC_FALL, -30, NA, NULL); // human monsters... addrace(R_BANDITLDR, "bandit leader", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID, "Like a regular bandit, but bigger and stronger. Enough so to bully their followers into submission anyway."); @@ -9966,7 +10648,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOJOBTEXT, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_STARTJOB, 15, J_WIZARD, NA, NULL); + addflag(lastrace->flags, F_STARTJOB, 15, J_WILDMAGE, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 50, J_ROGUE, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addrace(R_BEGGAR, "beggar", 50, '@', C_BROWN, MT_FLESH, RC_HUMANOID, "Beggar roam the streets of towns, pleading for any spare cash."); @@ -10527,10 +11209,10 @@ void initrace(void) { addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of missile or ranged weapons"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of technology"); // sacrifices - addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_POTION, NA, 2, "OB disappear#S in a swirl of multicoloured lights."); - addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_SCROLL, NA, 2, "OB disappear#S in a swirl of multicoloured lights."); + addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_AMULET, NA, 10, "OB disappear#S in a swirl of multicoloured lights."); + addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_RING, NA, 7, "OB disappear#S in a swirl of multicoloured lights."); addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_WAND, NA, 5, "OB disappear#S in a swirl of multicoloured lights."); - addflag(lastrace->flags, F_SACRIFICEOBCLASS, OC_RING, NA, 10, "OB disappear#S in a swirl of multicoloured lights."); + addflag(lastrace->flags, F_SACRIFICEOBMAGIC, NA, NA, 2, "OB disappear#S in a swirl of multicoloured lights."); addflag(lastrace->flags, F_GODBATTLE, NA, NA, NA, "restoring your mana"); addflag(lastrace->flags, F_GODNOBATTLE, NA, NA, NA, "restoring your mana"); addflag(lastrace->flags, F_GODNOBATTLE, NA, NA, NA, "uncursing items"); @@ -11418,7 +12100,7 @@ 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_STARTJOB, 10, J_ROGUE, NA, NULL); - addflag(lastrace->flags, F_STARTJOB, 5, SJ_NECROMANCER, NA, NULL); + addflag(lastrace->flags, F_STARTJOB, 5, J_NECROMANCER, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 5, J_DEMONOLOGIST, NA, NULL); addrace(R_GOBLINR, "froglin", 25, 'g', C_GREEN, MT_FLESH, RC_HUMANOID, "River goblins (more commonly known as 'froglins') are blueish goblins with sleek, leathery skin. They seems constantly wet, and can leap like a frog."); @@ -11949,7 +12631,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, RR_COMMON, NULL); addflag(lastrace->flags, F_RARITY, H_SWAMP, 78, RR_COMMON, NULL); addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_UNCOMMON, NULL); - addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 3, NA, NA, NULL); addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 10, NA, NA, NULL); @@ -12224,7 +12906,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 8, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_STARTJOB, 20, J_WIZARD, SJ_RANDOM, NULL); + addflag(lastrace->flags, F_STARTJOB, 20, J_FIREMAGE, NA, NULL); addrace(R_NIXIE, "nixie", 5, 'n', C_BLUE, MT_FLESH, RC_MAGIC, "A small, beautiful water spirit with webbed hands and feet."); setbodytype(lastrace, BT_HUMANOID); @@ -12303,7 +12985,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 8, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_STARTJOB, 20, J_WIZARD, SJ_RANDOM, NULL); + addflag(lastrace->flags, F_STARTJOB, 20, J_ICEMAGE, NA, NULL); addrace(R_OGREWARHULK, "warhulk", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID, "Warhulks are huge ogres, even angrier than their comrades."); setbodytype(lastrace, BT_HUMANOID); @@ -12647,7 +13329,7 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 1, NA, NA, NULL); addflag(lastrace->flags, F_TR, 2, NA, NA, NULL); - addflag(lastrace->flags, F_EVASION, 20, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_NATURALFLIGHT, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_CANWILL, OT_S_FLIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FLIGHT, NA, NA, NULL); @@ -12930,6 +13612,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, NA, NA, "range:1;"); addflag(lastrace->flags, F_CASTWITHOUTIQ, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_SLEEP, NA, B_APPENDYOU, "throws a handful of sand"); + addflag(lastrace->flags, F_AISPELLTARGETOVERRIDE, OT_S_SLEEP, F_AICASTTOATTACK, ST_ADJVICTIM, NULL); addflag(lastrace->flags, F_TREMORSENSE, 4, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^rushing air"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); @@ -12991,7 +13674,7 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "plays its pipes"); addflag(lastrace->flags, F_RESISTMAG, 10, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NEEDOBFORSPELLS, OT_PANPIPES, NA, NA, NULL); + addflag(lastrace->flags, F_NEEDOBFORSPELLS, OT_PANPIPES, NA, NA, "panpipes"); addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_FEAR, 15, 15, "pw:1;"); @@ -13124,7 +13807,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 80, OC_ARMOUR, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); - addflag(lastrace->flags, F_STARTSKILL, SK_TRAPS, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_ENGINEERING, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_LOCKPICKING, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_LISTEN, PR_ADEPT, NA, NULL); @@ -14267,7 +14950,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 3, NA, NA, NULL); - addflag(lastrace->flags, F_TR, 3, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); @@ -16746,7 +17429,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_HITDICE, 1, NA, NA, NULL); - addflag(lastrace->flags, F_TR, 2, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 3, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 10, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 1, NA, NULL); addflag(lastrace->flags, F_GERMS, NA, NA, NA, NULL); @@ -16768,6 +17451,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_CON, AT_RANDOM, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_WATER, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TOUCHBURN, 2, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "flares its flames^crackling flames"); addflag(lastrace->flags, F_DAMAGEGROUNDOBS, 2, DT_FIRE, NA, NULL); @@ -16948,7 +17632,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANCAST, OT_S_HEATMETAL, 5, 5, "pw:1;"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "waves its trident"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "red-hot trident"); - addflag(lastrace->flags, F_NEEDOBFORSPELLS, OT_TRIDENT, NA, NA, NULL); + addflag(lastrace->flags, F_NEEDOBFORSPELLS, OT_TRIDENT, NA, NA, "trident"); addflag(lastrace->flags, F_RESISTMAG, 10, NA, NA, NULL); addrace(R_ICEDEMON, "ice demon", 80, '&', C_WHITE, MT_ICE, RC_DEMON, "A dense, humanoid demon comprised of solid ice and covered with sharp icicles."); @@ -16995,7 +17679,7 @@ void initrace(void) { addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 1, NA, NA, NULL); addflag(lastrace->flags, F_TR, 2, NA, NA, NULL); addflag(lastrace->flags, F_REGENERATES, 1, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 8, NA, NA, NULL); @@ -17672,7 +18356,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTJOB, 25, J_DRUID, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 25, J_NINJA, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 25, J_WARRIOR, NA, NULL); - addflag(lastrace->flags, F_STARTJOB, 100, J_WIZARD, SJ_RANDOM, NULL); + addflag(lastrace->flags, F_STARTJOB, 100, J_NECROMANCER, NA, NULL); addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_REVENANT, "rises from the dead!"); addflag(lastrace->flags, F_FOLLOWTIME, 40, NA, NA, NULL); @@ -18140,9 +18824,9 @@ void initskills(void) { addskilldesc(SK_ARMOUR, PR_EXPERT, "^gReduces armour penalties by 50%.^n", B_FALSE); addskilldesc(SK_ARMOUR, PR_MASTER, "^gReduces armour penalties by 60%.^n", B_FALSE); addskill(SK_ATHLETICS, "Athletics", "Grants various athletic abilities and increases Stamina.", 50); - addskilldesc(SK_ATHLETICS, PR_NOVICE, "^gYou gain the 'sprint' ability.^n", B_FALSE); - addskilldesc(SK_ATHLETICS, PR_ADEPT, "^gYou gain the 'tumble' ability.^n", B_FALSE); - addskilldesc(SK_ATHLETICS, PR_EXPERT, "^gYou gain the 'jump' ability.^n", B_FALSE); + addskillabil(SK_ATHLETICS, PR_NOVICE, OT_A_SPRINT, NA, NULL, B_TRUE); + addskillabil(SK_ATHLETICS, PR_ADEPT, OT_A_TUMBLE, NA, NULL, B_TRUE); + addskillabil(SK_ATHLETICS, PR_EXPERT, OT_A_JUMP, NA, NULL, B_TRUE); addskill(SK_BACKSTAB, "Backstabbing", "Lets you inflict massive damage when unseen and using a piercing weapon.", 50); addskilldesc(SK_BACKSTAB, PR_NOVICE, "^gYour unseen attacks inflict double damage.^n", B_FALSE); addskilldesc(SK_BACKSTAB, PR_BEGINNER, "^gYour unseen attacks inflict triple damage.^n", B_FALSE); @@ -18158,6 +18842,7 @@ void initskills(void) { addskilldesc(SK_CARTOGRAPHY, PR_SKILLED, "^gYou no longer forget your surroundings.^n", B_FALSE); addskilldesc(SK_CARTOGRAPHY, PR_EXPERT, "^gYour can now remember the location of objects.^n", B_TRUE); addskilldesc(SK_CARTOGRAPHY, PR_MASTER, "^gEvery 50 turns, you can intuitively map a small area around you.^n", B_FALSE); + addskillabil(SK_CARTOGRAPHY, PR_MASTER, OT_S_MAPPING, 50, "pw:1;", B_FALSE); addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items.", 0); // untrainable addskilldesc(SK_CHANNELING, PR_NOVICE, "^gThe power level of wands and scrolls is increased by 1.^n", B_FALSE); addskilldesc(SK_CHANNELING, PR_NOVICE, "^gYou can now recognise when objects are low on charges.^n", B_TRUE); @@ -18174,6 +18859,7 @@ void initskills(void) { addskill(SK_CLIMBING, "Climbing", "Helps you to climb walls, mountains or other terrain.", 50); addskilldesc(SK_CLIMBING, PR_INEPT, "Increases your chances of successfully climbing by 10% per level.", B_FALSE); addskilldesc(SK_CLIMBING, PR_NOVICE, "You gain the 'climb walls' ability. Cannot attack while climbing.", B_FALSE); + addskillabil(SK_CLIMBING, PR_NOVICE, OT_A_CLIMB, NA, NULL, B_FALSE); addskilldesc(SK_CLIMBING, PR_BEGINNER, "May attack while climbing, with -15 accuracy.", B_FALSE); addskilldesc(SK_CLIMBING, PR_ADEPT, "-10 accuracy penalty while climbing.", B_FALSE); addskilldesc(SK_CLIMBING, PR_SKILLED, "-5 accuracy penalty while climbing.", B_FALSE); @@ -18183,28 +18869,31 @@ void initskills(void) { free(lastskill->shortname); lastskill->shortname = strdup("Adv Combat"); addskilldesc(SK_COMBAT, PR_INEPT, " - Each skill level grants a 10% chance to bypass stamina drain when attacking.", B_FALSE); addskilldesc(SK_COMBAT, PR_NOVICE, "Unskilled weapon penalties are greatly reduced.", B_FALSE); + addskillabil(SK_COMBAT, PR_NOVICE, OT_A_STRIKETOKO, NA, NULL, B_TRUE); addskilldesc(SK_COMBAT, PR_BEGINNER, "Eliminates penalties for being prone or nauseated.", B_FALSE); addskilldesc(SK_COMBAT, PR_ADEPT, "Eliminates penalties when fighting unseen enemies.", B_FALSE); - addskilldesc(SK_COMBAT, PR_ADEPT, "You gain the 'disarm' ability.", B_FALSE); - addskilldesc(SK_COMBAT, PR_SKILLED, "You gain the 'flip' ability.", B_FALSE); + addskillabil(SK_COMBAT, PR_ADEPT, OT_A_DISARMLF, NA, NULL, B_TRUE); + addskillabil(SK_COMBAT, PR_SKILLED, OT_A_FLIP, NA, NULL, B_TRUE); addskilldesc(SK_COMBAT, PR_EXPERT, "^gSecond wind restores stamina after defeating enemies.^n", B_TRUE); addskilldesc(SK_COMBAT, PR_MASTER, "^gAttacking will no longer drain your stamina.^n", B_TRUE); addskill(SK_COOKING, "Cooking", "Your ability to combine foods into nutritious meals.", 50); addskilldesc(SK_COOKING, PR_INEPT, " - Note: when cooking, all ingredients must already be recognised.", B_FALSE); - addskilldesc(SK_COOKING, PR_NOVICE, "^gYou can now cook corpses before consumption.", B_TRUE); + addskilldesc(SK_COOKING, PR_NOVICE, "^gYou can now cook corpses before consumption.^n", B_TRUE); + addskillabil(SK_COOKING, PR_NOVICE, OT_A_COOK, NA, NULL, B_TRUE); addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou now recognise bad food.^n", B_TRUE); - addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou can now cook recipes using up to 2 ingredients.", B_TRUE); - addskilldesc(SK_COOKING, PR_ADEPT, "^gYou can now cook recipes using up to 3 ingredients.", B_TRUE); - addskilldesc(SK_COOKING, PR_SKILLED, "^gYou can now cook recipes using up to 4 ingredients.", B_TRUE); - 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); + addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou can now cook recipes using up to 2 ingredients.^n", B_TRUE); + addskilldesc(SK_COOKING, PR_ADEPT, "^gYou can now cook recipes using up to 3 ingredients.^n", B_TRUE); + addskilldesc(SK_COOKING, PR_SKILLED, "^gYou can now cook recipes using up to 4 ingredients.^n", B_TRUE); + addskilldesc(SK_COOKING, PR_EXPERT, "^gYou can now cook recipes using up to 5 ingredients.^n", B_TRUE); + addskilldesc(SK_COOKING, PR_MASTER, "^gYou can now cook all recipes.^n", B_TRUE); addskill(SK_EVASION, "Evasion", "Your ability to dodge blows or traps.", 50); 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_ADEPT, "^gYou gain the 'snatch' ability.^n", B_FALSE); + addskillabil(SK_EVASION, PR_ADEPT, OT_A_SNATCH, NA, NULL, B_TRUE); addskilldesc(SK_EVASION, PR_SKILLED, "^gIncreases your EV by 48%.^n", B_FALSE); addskilldesc(SK_EVASION, PR_SKILLED, "^gYou now automatically dodge fatal attacks if you have free stamina.^n", B_TRUE); + addskillabil(SK_EVASION, PR_SKILLED, OT_A_REFLEXDODGE, NA, NULL, 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 @@ -18230,15 +18919,18 @@ void initskills(void) { addskilldesc(SK_LISTEN, PR_EXPERT, "^gYou can now pinpoint sound sources up to 4 cells away.^n", B_TRUE); addskilldesc(SK_LISTEN, PR_MASTER, "^gYou can now pinpoint sound sources up to 6 cells away.^n", B_TRUE); addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.", 50); - addskilldesc(SK_LOCKPICKING, PR_NOVICE, "^gYou gain the 'pick locks' ability.^n", B_FALSE); + addskillabil(SK_LOCKPICKING, PR_NOVICE, OT_A_PICKLOCK, NA, NULL, B_TRUE); addskill(SK_METALWORK, "Metalwork", "Lets you repair metal objects.", 25); addskilldesc(SK_METALWORK, PR_NOVICE, "^gYou can repair metal items with condition >= 80%.^n", B_FALSE); + addskillabil(SK_METALWORK, PR_NOVICE, OT_A_REPAIR, NA, NULL, B_FALSE); addskilldesc(SK_METALWORK, PR_BEGINNER, "^gYou can repair metal items with condition >= 65%.^n", B_FALSE); + addskilldesc(SK_METALWORK, PR_BEGINNER, "^gYou can repair metal items with condition >= 25%.^n", B_FALSE); + addskilldesc(SK_METALWORK, PR_BEGINNER, "^gYou can re-size metal armour (at the expense of durability).^n", B_FALSE); + addskillabil(SK_METALWORK, PR_BEGINNER, OT_A_RESIZE, NA, NULL, B_FALSE); addskilldesc(SK_METALWORK, PR_ADEPT, "^gYou can repair metal items with condition >= 50%.^n", B_FALSE); - addskilldesc(SK_METALWORK, PR_SKILLED, "^gYou can repair metal items with condition >= 25%.^n", B_FALSE); - addskilldesc(SK_METALWORK, PR_SKILLED, "^gYou can re-size metal armour (at the expense of durability).^n", B_FALSE); + addskilldesc(SK_METALWORK, PR_SKILLED, "^gYou can increase an item's quality to masterwork using a duplicate.^n", B_FALSE); + addskillabil(SK_METALWORK, PR_SKILLED, OT_A_ENHANCEOB, NA, NULL, B_FALSE); addskilldesc(SK_METALWORK, PR_EXPERT, "^gYou can fully repair metal items.^n", B_FALSE); - addskilldesc(SK_METALWORK, PR_MASTER, "^gYou can increase an item's quality to masterwork using a duplicate.^n", B_FALSE); addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun.", 50); addskilldesc(SK_RANGED, PR_INEPT, "^gYour ranged accuracy decreases by 32% per cell.^n", B_FALSE); addskilldesc(SK_RANGED, PR_NOVICE, "^gYour ranged accuracy decreases by 22% per cell.^n", B_FALSE); @@ -18253,18 +18945,21 @@ void initskills(void) { free(lastskill->shortname); lastskill->shortname = strdup("Ranged Wpns"); addskill(SK_SEWING, "Sewing", "Lets you repair cloth or leather objects.", 25); addskilldesc(SK_SEWING, PR_NOVICE, "^gYou can repair cloth items with condition >= 80%.^n", B_FALSE); + addskillabil(SK_SEWING, PR_NOVICE, OT_A_REPAIR, NA, NULL, B_FALSE); addskilldesc(SK_SEWING, PR_BEGINNER, "^gYou can repair cloth items with condition >= 65%.^n", B_FALSE); + addskilldesc(SK_SEWING, PR_BEGINNER, "^gYou can re-size cloth armour (at the expense of durability).^n", B_FALSE); + addskillabil(SK_SEWING, PR_BEGINNER, OT_A_RESIZE, NA, NULL, B_FALSE); addskilldesc(SK_SEWING, PR_ADEPT, "^gYou can repair cloth items with condition >= 50%.^n", B_FALSE); addskilldesc(SK_SEWING, PR_SKILLED, "^gYou can repair cloth items with condition >= 25%.^n", B_FALSE); - addskilldesc(SK_SEWING, PR_SKILLED, "^gYou can re-size cloth armour (at the expense of durability).^n", B_FALSE); + addskilldesc(SK_SEWING, PR_SKILLED, "^gYou can increase an item's quality to masterwork using a duplicate.^n", B_FALSE); + addskillabil(SK_SEWING, PR_SKILLED, OT_A_ENHANCEOB, NA, NULL, B_FALSE); addskilldesc(SK_SEWING, PR_EXPERT, "^gYou can fully repair cloth items.^n", B_FALSE); - addskilldesc(SK_SEWING, PR_MASTER, "^gYou can increase an item's quality to masterwork using a duplicate.^n", B_FALSE); addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block attacks.", 50); addskilldesc(SK_SHIELDS, PR_INEPT, "- Without this skill, shield accuracy penalties are tripled.", B_FALSE); addskilldesc(SK_SHIELDS, PR_NOVICE, "^gShield accuracy penalties are reduced by 1.^n", B_FALSE); addskilldesc(SK_SHIELDS, PR_NOVICE, "^gYou can now recognise the quality of shields.^n", B_FALSE); addskilldesc(SK_SHIELDS, PR_BEGINNER, "^gShield accuracy penalties are reduced by 2.^n", B_FALSE); - addskilldesc(SK_SHIELDS, PR_BEGINNER, "^gYou gain the 'shield bash' ability.^n", B_FALSE); + addskillabil(SK_SHIELDS, PR_BEGINNER, OT_A_SHIELDBASH, NA, NULL, B_TRUE); addskilldesc(SK_SHIELDS, PR_ADEPT, "^gShield accuracy penalties are reduced by 3.^n", B_FALSE); addskilldesc(SK_SHIELDS, PR_SKILLED, "^gShield accuracy penalties are reduced by 4.^n", B_FALSE); addskilldesc(SK_SHIELDS, PR_EXPERT, "^gShield accuracy penalties are reduced by 5.^n", B_FALSE); @@ -18274,8 +18969,9 @@ void initskills(void) { addskilldesc(SK_SPEECH, PR_NOVICE, "^gYou can determine when others are peaceful.^n", B_TRUE); addskilldesc(SK_SPEECH, PR_NOVICE, "^gYou can now question people about nearby traps or monsters.^n", B_TRUE); addskilldesc(SK_SPEECH, PR_BEGINNER, "^gYou can now offer gems as payment in shops.^n", B_TRUE); - addskilldesc(SK_SPEECH, PR_BEGINNER, "^gYou can now question people about items on the current level.^n", B_TRUE); + addskilldesc(SK_SPEECH, PR_BEGINNER, "^gYou can now ask people about items on the current level.^n", B_TRUE); addskilldesc(SK_SPEECH, PR_ADEPT, "^gYou can now recognise which items others desire.^n", B_TRUE); + addskilldesc(SK_SPEECH, PR_ADEPT, "^gYou now receive change when using gems as payment.^n", B_TRUE); addskilldesc(SK_SPEECH, PR_SKILLED, "^gYou can now trade knowledge and spells with other people.^n", B_TRUE); addskilldesc(SK_SPEECH, PR_EXPERT, "^gYou can now persuade people to join to as followers.^n", B_TRUE); addskilldesc(SK_SPEECH, PR_MASTER, "^gYou can now choose which skills to learn from people.^n", B_TRUE); @@ -18290,7 +18986,7 @@ void initskills(void) { addskilldesc(SK_PERCEPTION, PR_EXPERT, "^gYou can now move without leaving footprints.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_MASTER, "^gYou field of vision now extends behind you.^n", B_TRUE); addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable? - addskilldesc(SK_STEALTH, PR_NOVICE, "^gYou gain the 'hide' ability.^n", B_FALSE); + addskillabil(SK_STEALTH, PR_NOVICE, OT_A_HIDE, NA, NULL, B_TRUE); addskilldesc(SK_STEALTH, PR_BEGINNER, "^gYou can now move while hiding.^n", B_TRUE); addskilldesc(SK_STEALTH, PR_SKILLED, "^gYou can now peek down staircases.^n", B_TRUE); addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water.", 50); @@ -18314,6 +19010,19 @@ void initskills(void) { addskilldesc(SK_THIEVERY, PR_SKILLED, "^gYou can now steal heavy items.", B_TRUE); addskilldesc(SK_THIEVERY, PR_EXPERT, "^gYou can now steal multiple items.", B_TRUE); addskilldesc(SK_THIEVERY, PR_MASTER, "^gYou can now steal equipped items.", B_TRUE); + addskill(SK_ENGINEERING, "Engineering", "Your construction knowledge and skill with devices like traps.", 25); + addskilldesc(SK_ENGINEERING, PR_INEPT, "Each level increases damage dealt to doors/walls by +2.", B_FALSE); + addskillabil(SK_ENGINEERING, PR_NOVICE, OT_A_DISARM, NA, NULL, B_TRUE); + addskilldesc(SK_ENGINEERING, PR_NOVICE, "You receive extra knowledge about walls/floors.", B_FALSE); + addskilldesc(SK_ENGINEERING, PR_BEGINNER, "You can now 'see' the remaining hit points of walls.", B_FALSE); + addskillabil(SK_ENGINEERING, PR_BEGINNER, OT_A_DISMANTLE, NA, NULL, B_TRUE); + addskilldesc(SK_ENGINEERING, PR_BEGINNER, "You can now detect hollow spaces.", B_TRUE); + addskilldesc(SK_ENGINEERING, PR_BEGINNER, "You can now identify trap types.", B_TRUE); + addskilldesc(SK_ENGINEERING, PR_ADEPT, "You can now create barricades and basic traps.", B_TRUE); + addskilldesc(SK_ENGINEERING, PR_SKILLED, "You now automatically detect traps.", B_TRUE); + addskilldesc(SK_ENGINEERING, PR_SKILLED, "You can now dismantle doors as well as obstacles.", B_TRUE); + addskilldesc(SK_ENGINEERING, PR_EXPERT, "You can now create advanced traps.", B_TRUE); + addskilldesc(SK_ENGINEERING, PR_MASTER, "You are now immune to most trap effects.", B_TRUE); addskill(SK_THROWING, "Throwing", "Your accuracy when throwing objects at things.", 50); addskilldesc(SK_THROWING, PR_INEPT, "^gYour throw accuracy decreases by 32%% per cell.^n", B_FALSE); addskilldesc(SK_THROWING, PR_NOVICE, "^gYour throw accuracy decreases by 22%% per cell.^n", B_FALSE); @@ -18322,24 +19031,24 @@ void initskills(void) { addskilldesc(SK_THROWING, PR_SKILLED, "^gYour throw accuracy decreases by 10%% per cell.^n", B_FALSE); addskilldesc(SK_THROWING, PR_EXPERT, "^gYour throw accuracy decreases by 8%% per cell.^n", B_FALSE); addskilldesc(SK_THROWING, PR_MASTER, "^gYour throw accuracy decreases by 6%% per cell.^n", B_FALSE); - addskill(SK_TRAPS, "Traps", "Affects your ability to locate and disarm traps.", 25); - addskilldesc(SK_TRAPS, PR_NOVICE, "^gYou gain the 'disarm traps' ability.^n", B_FALSE); addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once.", 50); addskilldesc(SK_TWOWEAPON, PR_NOVICE, "^gYou can now weild two weapons at once, with -4 accuracy.^n", B_TRUE); addskilldesc(SK_TWOWEAPON, PR_BEGINNER, "^gDual-weapon accuracy penalty reduced to -2.^n", B_FALSE); addskilldesc(SK_TWOWEAPON, PR_ADEPT, "^gYou no longer suffer an accuracy penalty when weilding two weapons.^n", B_TRUE); addskilldesc(SK_TWOWEAPON, PR_SKILLED, "^gFollow-up attacks with your second weapon are now more accurate.^n", B_TRUE); - addskilldesc(SK_TWOWEAPON, PR_EXPERT, "^gYou gain the 'flurry attack' ability.^n", B_FALSE); + addskillabil(SK_TWOWEAPON, PR_EXPERT, OT_A_FLURRY, NA, "pw:1;", B_TRUE); addskilldesc(SK_TWOWEAPON, PR_MASTER, "^gYou can now deflect attacks with your second weapon.^n", B_TRUE); // knowledge // descriptions for all of these will be added later. addskill(SK_LORE_ARCANA, "Lore:Arcana", "Allows you a chance of recognising magical objects and creatures.", 5); addskilldesc(SK_LORE_ARCANA, PR_NOVICE, "^gYou can attempt to identify objects with the 'inspect' ability.^n", B_FALSE); - addskilldesc(SK_LORE_ARCANA, PR_ADEPT, "^gYou gain the 'study scrolls' ability.", B_FALSE); + addskillabil(SK_LORE_ARCANA, PR_NOVICE, OT_A_INSPECT, NA, NULL, B_FALSE); + addskillabil(SK_LORE_ARCANA, PR_ADEPT, OT_A_STUDYSCROLL, NA, NULL, B_TRUE); addskill(SK_LORE_DEMONS, "Lore:Demonology", "Determines your knowledge about demons.", 5); free(lastskill->shortname); lastskill->shortname = strdup("Lore:Demons"); - addskilldesc(SK_LORE_ARCANA, PR_NOVICE, "^gYou gain the 'exorcise' ability.", B_FALSE); - addskilldesc(SK_LORE_ARCANA, PR_SKILLED, "^gYou gain the 'summon demons' ability.", B_FALSE); + addskillabil(SK_LORE_DEMONS, PR_NOVICE, OT_S_EXORCISE, NA, NULL, B_TRUE); + addskilldesc(SK_LORE_DEMONS, PR_SKILLED, "^gEvery 50 turns you can summon demons.", B_FALSE); + addskillabil(SK_LORE_DEMONS, PR_SKILLED, OT_S_SUMMONDEMON, 50, "pw:1", B_FALSE); addskill(SK_LORE_HUMANOID, "Lore:Humanoid", "Determines your knowledge about humanoid (bipedal) creatures.", 5); addskill(SK_LORE_NATURE, "Lore:Nature", "Determines your knowledge of plants, animals and insects.", 5); addskill(SK_LORE_UNDEAD, "Lore:Undead", "Determines your knowledge of the undead.", 5); @@ -18348,6 +19057,7 @@ void initskills(void) { // weaponry addskill(SK_AXES, "Axes", "Helps you use chopping weapons like axes.", 50); addskill(SK_CLUBS, "Clubs", "Helps you use bashing weapons like maces or clubs.", 50); + addskillabil(SK_CLUBS, PR_NOVICE, OT_A_STRIKETOKO, NA, NULL, B_TRUE); addskill(SK_EXOTICWEPS, "Exotic Weapons", "Helps you use nunchaku, sais, etc.", 50); free(lastskill->shortname); lastskill->shortname = strdup("Exotic Wpns"); addskill(SK_LONGBLADES, "Long Blades", "Helps you use long swords, scimitars, etc.", 50); @@ -18357,6 +19067,7 @@ void initskills(void) { addskill(SK_WHIPS, "Whips", "Helps you use whips, flails, etc.", 50); addskill(SK_UNARMED, "Unarmed Combat", "Helps you fight using your bare hands.", 50); free(lastskill->shortname); lastskill->shortname = strdup("Unarmed"); + addskillabil(SK_UNARMED, PR_EXPERT, OT_A_FLIP, NA, NULL, B_TRUE); // spell schools addskill(SK_SS_ALLOMANCY, "Allomancy", "Boosts casting of spells from this school.", 50); @@ -18509,6 +19220,12 @@ void initskills(void) { addskilldesc(sk->id, PR_EXPERT, "^g+4 accuracy, +30% damage bonus.^n", B_FALSE); if (sk->id == SK_UNARMED) addskilldesc(sk->id, PR_EXPERT, "^gYou gain the 'flip' ability.^n", B_FALSE); addskilldesc(sk->id, PR_MASTER, "^g+6 accuracy, +40%% damage bonus, combination strike ability.^n", B_FALSE); + + if (sk->id != SK_UNARMED) { + addskillabil(sk->id, PR_BEGINNER, OT_A_EXPOSEDSTRIKE, NA, NULL, B_FALSE); + addskillabil(sk->id, PR_ADEPT, OT_A_ALTERATTACK, NA, NULL, B_FALSE); + addskillabil(sk->id, PR_MASTER, OT_A_COMBOSTRIKE, NA, NULL, B_FALSE); + } } } } @@ -18528,6 +19245,7 @@ void inittext(void) { addplural("leaf","leaves", B_TRUE); addplural("loaf","loaves", B_TRUE); addplural("lump","lumps", B_TRUE); + addplural("packet","packets", B_TRUE); addplural("piece","pieces", B_TRUE); addplural("pile","piles", B_TRUE); addplural("pinch","pinches", B_TRUE); diff --git a/data/hiscores.db b/data/hiscores.db index be8b068..0cccdb5 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/data/vaults/monsterzoo.vlt b/data/vaults/monsterzoo.vlt index b95edf0..64c4c2a 100644 --- a/data/vaults/monsterzoo.vlt +++ b/data/vaults/monsterzoo.vlt @@ -17,5 +17,7 @@ scatter(1,1,-2,-2) ob:random:100% scatter(1,1,-2,-2) ob:random:100%:50 scatter(1,1,-2,-2) ob:random:100%:50 rarity:rare +mayrotate +maintainedge @end diff --git a/defs.h b/defs.h index bb5a20f..8e04b11 100644 --- a/defs.h +++ b/defs.h @@ -16,6 +16,9 @@ #define ONEIN_FOUNTAINDRYUP 3 #define PCTCH_PILLAR 5 +// skill check difficulty +#define D_ALWAYSFAIL -99 + // Text #define TEXT_WARN_ATTACK_NOXP "You will not gain experience until you train. Really attack?" #define TEXT_WARN_CLIMB "Really attempt to climb without Climbing skill?" @@ -324,6 +327,7 @@ #define D_NONE -1 #define D_UNKNOWN -2 #define D_ALL -3 +#define D_MYSELF -4 // Orthogonal directions #define D_N 0 @@ -491,6 +495,7 @@ enum SHOPACTION { #define FROMSPELL (-9863) #define FROMPOISON (-9862) #define FROMLYCANTHROPY (-9861) +#define FROMGAMESTART (-9860) // flag lifetimes - external sources (ie. don't kill them) #define FROMEXTERNAL_HIGH (-7000) @@ -611,6 +616,9 @@ enum SAYPHRASE { SP_BEG, SP_BEGATTACK, SP_BEGTHANKS, + SP_CLOSEDTILMORN, + SP_CLOSEDTILNIGHT, + SP_CLOSEDTILTIME, SP_DIE, SP_DRUNK, SP_LIFEOB_DESTROYED, @@ -647,6 +655,8 @@ enum SPEECHVOL { SV_TRUCK = 5, SV_PLANE = 6, }; +#define MINVOL SV_SILENT +#define MAXVOL SV_PLANE enum SKILL { SK_NONE = 0, @@ -673,7 +683,7 @@ enum SKILL { SK_TECHUSAGE, SK_THIEVERY, SK_THROWING, - SK_TRAPS, + SK_ENGINEERING, SK_TWOWEAPON, // knowledge SK_LORE_ARCANA, @@ -719,6 +729,7 @@ enum SKILLLEVEL { PR_MASTER = 6, }; #define MAXSKILLLEVEL 7 +#define MAXSKILLWILLS (MAXSKILLLEVEL*5) enum GAMEMODE { @@ -861,6 +872,7 @@ enum CELLTYPE { CT_WALLDURANITE, // empty CT_CORRIDOR, + CT_MOSSROCK, CT_DIRT, CT_VILLAGEGROUND, CT_FAKE, @@ -1031,6 +1043,7 @@ enum RACE { R_NONE = 0, R_RANDOM, R_SPECIFIED, // unique monstesr + R_CLANK, R_BABAYAGAHUT, R_BABAYAGA, R_JAILER, @@ -1305,6 +1318,9 @@ enum JOB { J_ADVENTURER, J_ALLOMANCER, J_WARRIOR, + J_BATTLEMAGE, + J_PALADIN, + J_SCOURGE, J_CHEF, J_COMMANDO, J_DRUID, @@ -1315,8 +1331,15 @@ enum JOB { J_PIRATE, J_PRINCE, J_ROGUE, + J_ASSASSIN, + J_KNIFEDANCER, //J_SHOPKEEPER, - J_WIZARD, + //J_WIZARD, + J_AIRMAGE, + J_ICEMAGE, + J_FIREMAGE, + J_NECROMANCER, + J_WILDMAGE, // monster-only jobs J_BERZERKER, J_DEMONOLOGIST, @@ -1325,6 +1348,20 @@ enum JOB { }; #define J_RANDOM J_NONE +enum JOBCATEGORY { + JC_NONE, + JC_FIGHTER, + JC_FIGHTERRANGED, + JC_MAGE, + JC_THIEF, + JC_FIGHTERMAGE, + JC_FIGHTERTHIEF, + JC_GENERAL, +}; +#define JC_FIRST JC_NONE +#define JC_LAST JC_GENERAL + +/* enum SUBJOB { SJ_NONE, SJ_RANDOM, @@ -1338,8 +1375,10 @@ enum SUBJOB { SJ_BATTLEMAGE, SJ_PALADIN, SJ_SCOURGE, - + // rogue + SJ_KNIFEDANCER, }; +*/ enum MATSTATE { MS_SOLID, @@ -1515,6 +1554,7 @@ enum OBTYPE { OT_GARLIC, OT_HOTDOG, OT_JERKY, + OT_MUSHROOMGREY, OT_MUSHROOMSHI, OT_MUSHROOMTOAD, OT_MUSHROOMSTUFFED, @@ -1754,6 +1794,7 @@ enum OBTYPE { OT_S_STUNMASS, OT_S_TELEKINESIS, // nature / enviromancy + OT_S_ABSORBWOOD, OT_S_ANIMATETREE, OT_S_BARKSKIN, OT_S_CALLLIGHTNING, @@ -1861,12 +1902,14 @@ enum OBTYPE { // abilities OT_A_AIMEDSTRIKE, OT_A_ALTERATTACK, + OT_A_BUILD, OT_A_CHECKSTAIRS, OT_A_CLIMB, OT_A_COOK, OT_A_DARKWALK, OT_A_DISARM, // disarm a trap OT_A_DISARMLF, // disarm an opponent + OT_A_DISMANTLE, OT_A_DRAGUNDERGROUND, OT_A_ENHANCEOB, OT_A_EXPLODESELF, @@ -1960,6 +2003,7 @@ enum OBTYPE { OT_TOWEL, OT_UNICORNHORN, // tech l0 + OT_CHEWINGGUM, OT_COMPUTER, OT_CREDITCARD, OT_PAPERCLIP, @@ -2317,6 +2361,9 @@ enum OBTYPE { OT_SHILLELAGH, OT_SPANNER, OT_STICK, + // hammers + OT_WARHAMMER, + OT_SLEDGEHAMMER, // projectile weapons OT_BLOWGUN, OT_BOW, @@ -2535,6 +2582,7 @@ enum FLAG { // f->text (if given), or obtype v1. F_STACKABLE, // can stack multiple objects togethr F_THE, // say "the xxx", not "a xxx" + F_WIZSTAFF, // this object counts as a wizard staff F_NO_PLURAL, // this obname doesn't need an 's' for plurals (eg. gold, money) F_NO_A, // this obname doesn't need to start with 'a' for singular (eg. gold) F_CONTAINSOB, // for vending machiens. v0 is ob letter @@ -2548,6 +2596,7 @@ enum FLAG { // where the amulet was put on. v1/v2 is x/y coords. F_NEWMAP, // for amulet of the traveller - v0 = target map id // where amulet takes us. v1/v2 is x/y coords. + F_NOSACRIFICE, // cannot be sacrificed. F_SIGNTEXT, // for 'sign' objects. f->text is what is says. F_IMPORTANT, // don't destroy this object F_IMMUTABLE, // this object cannot be damaged OR repaired. @@ -2619,8 +2668,14 @@ enum FLAG { F_CAUSESCOUGH, // being in this ob's cell will make you cough unless // immune to gas. // v0 = con skillcheck difficulty. + F_DIMONWALK, // when a lf walks on this ob, its f_produceslight + // flag v0 reduces by one. + // if it gets to 0 (or doesnt have produceslight), + // the object will vanish. F_BLOCKSVIEW, // if v0 = true, cannot see past this // if v0 > 0, reduces your vision by v0. + // if v1 = true then don't block sight if you are + // standing on it. F_BLOCKSLOF, // this object interrupts line of fire F_THEREISHERE, // announce "there is xx here!", not "you see xx here" // text[0] is punctuation to use. @@ -2701,7 +2756,7 @@ enum FLAG { // val2 = ifactivated, only explodes if activated. F_FLASHONDEATH, // produce a bright flash when it dies,v0=range F_FLASHONDAM, // produces a bright flash when it is damaged,v0=range,v2=ifacctivated - F_SPELLCLOUDONDEATH, // cast spell v0 in radius v1 upon death. + F_SPELLCLOUDONDEATH, // cast spell v0 in radius v1 (orth) upon death. // v2 = ifactivated // text = "seebuf^noseebuf^spell_power" F_SPELLCLOUDONDAM, // cast spell v0 in radius v1 upon damage. @@ -2819,8 +2874,9 @@ enum FLAG { // v1 = enum MENUACTION // v2 = value for action (optional) // text = "x:whatever" (x is letter to press) - - + F_OPENHOURS, // v0 = shop open time (inclusive) + // v1 = shop close time (inclusive) + // v2 = enuim sayphrase SP_xxx when closed // doors F_DOOR, // this object is a door - ie. can open it // v0 and v1 are like F_IMPASSABLE @@ -3118,6 +3174,7 @@ enum FLAG { // can pick what alignment they want to be. // text shows the choices ("g", "n" or "e") F_PIETY, // for god lifeforms - tracks player's piety with them + F_PLANTFRIEND, // for player druids - makes plants friendly. F_HOMEMAP, // which map did this lf get created on? F_TOOKACTION, // lf purposely took action in their last turn. F_JUSTENTERED, // lf just entered a new map. @@ -3161,6 +3218,8 @@ enum FLAG { // successful bite attacks from this lf will heal it // when on an object // successful attacks with this weapon will heal lf + // v0 = TRUE means always drain, otherwise only drain + // if victim has low hp. F_VEGETARIAN, // this lf will not eat meat. F_PARTVEGETARIAN,// this lf will only eat if hunger >= 'hungry' F_CARNIVORE, // this lf will only eat meat. @@ -3235,7 +3294,7 @@ enum FLAG { // to take stuff out or put it in. F_HOLDING, // this container is a xxx of holding and makes objects // inside become weightless - F_STARTJOB, // val0 = %chance of starting with it, v1 = jobid, v2=subjobid + F_STARTJOB, // val0 = %chance of starting with it, v1 = jobid F_STARTSKILL, // val0 = skill id F_STARTATT, // val0 = A_xxx, val0 = start bracket (ie. IQ_GENIUS) // if text is set, it overrides val0. @@ -3466,7 +3525,6 @@ enum FLAG { F_GENDER, // v0 = G_MALE or G_FEMALE. default if G_NONE if this // flag isn't set. F_JOB, // val0 = player's job - // val1 = player's subjob or NA F_GODOF, // text = what this lf is the god of. use capitals. F_GODLIKES, // text = something this god likes (ie. incs piety) F_GODDISLIKES, // text = something this god likes (ie. decs piety) @@ -3486,6 +3544,8 @@ enum FLAG { // corpse of something with raceclass v1. F_SACRIFICEOBCLASS, // v0 = can sacrifice obclass v0 to this god F_SACRIFICEOBBLESSED, // v0 = can sacrifice obs with ->blessed=v0 and blessknown! + F_SACRIFICEOBMAGIC, // can sacrifice obs which are magical. + // v2 = piety per ob F_NAME, // text = lf's name. ie. lfname = "Fred" // also used for names of OT_GRIMOIRE objects @@ -3596,7 +3656,12 @@ enum FLAG { F_BLIND, // cannot see anything F_CONFUSED, // move randomly about F_DEAF, // cannot hear - F_NEEDOBFORSPELLS, // lf can only cast spells if it has object v0 + F_NEEDOBFORSPELLS, // if v0 != NA, lf can only cast spells if + // it has object v0 + // if v1 != NA, lf can only cast spells if they + // have an object with flag v1. + // text = name of object you need, only used for + // messages. F_CASTTYPE, // lf uses enum CASTTYPE v1 for spellid v0. (ot_none=all) // optional v2 is colour for casttype-based animations // (ie. spit spells) @@ -3811,7 +3876,7 @@ enum FLAG { F_NOSELECTWEAPON, // override F_SELECTWEAPON from job F_NOPLAYER, // players can't pick this job F_HASPET, // this job starts with a pet of race f->text - F_CANHAVESUBJOB, // this job can have subjob = v0 + //F_CANHAVESUBJOB, // this job can have subjob = v0 //F_IFPCT, // only add the NEXT job flag if rnd(1,100) <= v0. //F_ELSE, //F_IFPLAYER, @@ -4331,6 +4396,7 @@ typedef struct poisontype_s { struct poisontype_s *next, *prev; } poisontype_t; +/* typedef struct subjob_s { enum SUBJOB id; char *name; @@ -4338,6 +4404,7 @@ typedef struct subjob_s { char letter; struct subjob_s *next, *prev; } subjob_t; +*/ typedef struct room_s { int id; @@ -4512,6 +4579,7 @@ typedef struct celltype_s { int transparent; // can you see through it? int floorheight; // 0 is default. <0 is low. int hp; // hit points left. <0 = invulnerable + int volumemod; // modifer to footstep volume struct material_s *material; struct flagpile_s *flags; @@ -4670,6 +4738,7 @@ typedef struct flag_s { enum FLAGCONDITION condition; int chance; + struct skill_s *skillfrom; // only used if ->lifetime is FROMSKILL. long obfrom; // for conferred flags, link to object->id. -1 if not conferred. // also used for godgifts, in which case it is thr race->id of // the god who gifted you this flag. @@ -4701,6 +4770,15 @@ typedef struct skill_s { char *skilldesctext[MAXSKILLLEVEL*2]; int skilldescmsg[MAXSKILLLEVEL*2]; int nskilldesc; + + struct skillwill_s { + enum SKILLLEVEL lev; + enum OBTYPE abilid; + int timeout; + char *text; + } skillwill[MAXSKILLWILLS]; + int nskillwills; + int traintime; struct skill_s *next, *prev; } skill_t; @@ -4733,6 +4811,7 @@ typedef struct knowledge_s { typedef struct job_s { enum JOB id; + enum JOBCATEGORY category; char *name; char *desc; flagpile_t *flags; diff --git a/flag.c b/flag.c index cf1cca9..e96f1f7 100644 --- a/flag.c +++ b/flag.c @@ -208,6 +208,8 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, f->known = known; f->obfrom = obfromid; + f->skillfrom = NULL; + f->altval = NULL; f->condition = FC_NOCONDITION; f->chance = 100; @@ -1464,6 +1466,23 @@ int getflags(flagpile_t *fp, flag_t **retflag, int *nretflags, ... ) { return *nretflags; } +void getmaxflags(flagpile_t *fp, int id, int *max0, int *max1, int *max2) { + flag_t *f; + if (max0) *max0 = 0; + if (max1) *max1 = 0; + if (max2) *max2 = 0; + for (f = fp->first ; f ; f = f->next) { + // gone past the requrested id's number - ie. it's not there. + if (f->id > id) break; + + if (f->id == id) { + if (max0 && (f->val[0] > *max0)) *max0 = f->val[0]; + if (max1 && (f->val[1] > *max1)) *max1 = f->val[1]; + if (max2 && (f->val[2] > *max2)) *max2 = f->val[2]; + } + } +} + flag_t *getrandomflag(flagpile_t *fp, enum FLAG fid) { flag_t *retflag[MAXCANDIDATES]; int nretflags = 0; diff --git a/flag.h b/flag.h index 75ad58f..876347b 100644 --- a/flag.h +++ b/flag.h @@ -27,6 +27,7 @@ int flagstacks(enum FLAG fid); int flagtomaxhp(flag_t *f); cell_t *getflagpilelocation(flagpile_t *fp); int getflags(flagpile_t *fp, flag_t **retflag, int *nretflags, ... ); +void getmaxflags(flagpile_t *fp, int id, int *max0, int *max1, int *max2); flag_t *getrandomflag(flagpile_t *fp, enum FLAG fid); flag_t *hasflag(flagpile_t *fp, int id); flag_t *hasflagknown(flagpile_t *fp, int id); diff --git a/god.c b/god.c index 2a72117..7b8e02e 100644 --- a/god.c +++ b/god.c @@ -520,6 +520,7 @@ void dooffer(void) { flag_t *retflag[MAXCANDIDATES]; int nretflags,pietyplus = 0; int dowoodsangry = B_FALSE; + int success = B_FALSE; char splatterob[BUFLEN]; strcpy(splatterob, ""); @@ -534,7 +535,7 @@ void dooffer(void) { msg("Cancelled."); return; } - getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_SACRIFICEOBCLASS, F_SACRIFICEOBWITHFLAG, F_SACRIFICEOBBLESSED, F_NONE); + getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_SACRIFICEOBCLASS, F_SACRIFICEOBWITHFLAG, F_SACRIFICEOBBLESSED, F_SACRIFICEOBMAGIC, F_NONE); if (nretflags == 0) { msg("%s does not accept sacrifices.", god->race->name); return; @@ -543,8 +544,9 @@ void dooffer(void) { for (o = player->cell->obpile->first ; o ; o = nexto) { int i; nexto = o->next; + if (hasflag(o->flags, F_NOSACRIFICE)) continue; // does the god want this? - getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_SACRIFICEOBCLASS, F_SACRIFICEOBWITHFLAG, F_SACRIFICEOBBLESSED, F_NONE); + getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_SACRIFICEOBCLASS, F_SACRIFICEOBWITHFLAG, F_SACRIFICEOBBLESSED, F_SACRIFICEOBMAGIC, F_NONE); for (i = 0; i < nretflags; i++) { int ok = B_FALSE; int thispiety = 0; @@ -589,6 +591,9 @@ void dooffer(void) { } else if ((f->id == F_SACRIFICEOBBLESSED) && (f->val[0] == o->blessed) && (o->blessknown == B_TRUE)) { ok = B_TRUE; thispiety = f->val[2]; + } else if ((f->id == F_SACRIFICEOBMAGIC) && ismagical(o)) { + ok = B_TRUE; + thispiety = f->val[2]; } if (ok) { char *p; @@ -670,7 +675,7 @@ void dooffer(void) { if (god->race->id == R_GODFIRE) { dospelleffects(player, OT_S_FLAMEBURST, 1, NULL, NULL, player->cell, B_UNCURSED, NULL, B_FALSE, NULL); } - } else { + } else if (!success) { nothinghappens(); } taketime(player, getactspeed(player)); @@ -843,7 +848,7 @@ lifeform_t *godappears(enum RACE rid, cell_t *where) { strcpy(killedname, ""); if (!where) { // somewhere next to the player. - where = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, player); + where = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, player, MT_NOTHING); if (!where) { where = getrandomadjcell(player->cell, B_FALSE, B_NOEXPAND); } @@ -964,6 +969,7 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { default: break; } + more(); strcpy(obtogive, ""); switch (god->race->id) { case R_GODBATTLE: @@ -2222,19 +2228,27 @@ int prayto(lifeform_t *lf, lifeform_t *god) { object_t *possob[MAXPILEOBS]; int npossob,i,first; object_t *o; - // unlock doors + // unlock doors and remove impassable objects first = B_TRUE; for (i = 0; i < player->nlos; i++) { cell_t *c; - object_t *o; + object_t *o,*nexto; c = player->los[i]; - for (o = c->obpile->first ; o ; o = o->next) { + for (o = c->obpile->first ; o ; o = nexto) { + nexto = o->next; if (killflagsofid(o->flags, F_LOCKED) || killflagsofid(o->flags, F_SECRET)) { if (first) { msg("\"Access granted!\""); first = B_FALSE; } noise(c, NULL, NC_OTHER, SV_TALK, "the click of a lock.", NULL); + } else if (isimpassableob(o, lf, SZ_ANY)) { + if (first) { + msg("\"Access granted!\""); + first = B_FALSE; + } + removeob(o, ALL); + noise(c, NULL, NC_OTHER, SV_TALK, "the sucking of air.", NULL); } } } @@ -2524,9 +2538,13 @@ int prayto(lifeform_t *lf, lifeform_t *god) { if (god->race->id == R_GODNATURE) { - addob(lf->cell->obpile, "flower"); - if (haslos(player, lf->cell)) { - msg("A beautiful flower grows from the ground."); + object_t *oo; + oo = addob(lf->cell->obpile, "flower"); + if (oo) { + if (haslos(player, lf->cell)) { + msg("A beautiful flower grows from the ground."); + } + addflag(oo->flags, F_NOSACRIFICE, B_TRUE, NA, NA, NULL); } } diff --git a/io.c b/io.c index 64c7440..cfcda26 100644 --- a/io.c +++ b/io.c @@ -700,12 +700,16 @@ cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t while (!finished) { int dir; char ch; + char groundbuf[BUFLEN],fullbuf[BUFLEN]; int valid = B_TRUE; drawstatus(); updateviewfor(c); drawlevelfor(player); + strcpy(groundbuf, c->type->name); + addengineeringinfo(player, groundbuf, c); + if (moved) { flag_t *f; int inlof = B_TRUE, inrange = B_TRUE; @@ -1026,11 +1030,16 @@ cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t } } // dont use msg() to avoid 'more's - capitalise(buf); + if (streq(groundbuf, buf)) { + strcpy(fullbuf, buf); + } else { + sprintf(fullbuf, "%s, %s", groundbuf, buf); + } + capitalise(fullbuf); if (srclf && (maxrange != UNLIMITED)) { if (getcelldist(srclf->cell, c) > maxrange) { inrange = B_FALSE; - strcat(buf, " ^R[too-far]^n"); + strcat(fullbuf, " ^R[too-far]^n"); valid = B_FALSE; } } @@ -1050,7 +1059,7 @@ cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t } if (bad) { inlof = B_FALSE; - strcat(buf, " ^B[no-lof]^n"); + strcat(fullbuf, " ^B[no-lof]^n"); valid = B_FALSE; if (newcell) trailtarg = newcell; } @@ -1062,7 +1071,7 @@ cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t char throwbuf[BUFLEN]; makethrowaccstring(player, c, f, throwbuf); if (strlen(throwbuf)) { - strcat(buf, throwbuf); + strcat(fullbuf, throwbuf); } } @@ -1071,11 +1080,11 @@ cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t if (subprompt) { char fullline[BUFLEN]; wmove(msgwin, 0, 0); - sprintf(fullline, "%s%s", subprompt, buf); + sprintf(fullline, "%s%s", subprompt, fullbuf); textwithcol(msgwin, fullline); } else { wmove(msgwin, 0, 0); - textwithcol(msgwin, buf); + textwithcol(msgwin, fullbuf); } wrefresh(msgwin); @@ -1168,6 +1177,25 @@ cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t return NULL; } +char askdir(char *prompt, int maycancel, int usedrunk) { + int dirch,dir = D_NONE; + dirch = askchar(prompt, "yuhjklbn.-","-", B_FALSE, maycancel); + if (dirch == '.') return D_MYSELF; + + dir = chartodir(dirch); + + // tipsy... + if (usedrunk && movesrandomly(player)) { + int dir; + dir = rnd(DC_N, DC_NW+1); + if (dir == (DC_NW + 1)) { + dir = D_MYSELF; + } + } + + return dir; +} + // retbuf must already be allocated // "def" is optional char *askstring(char *prompt, char punc, char *retbuf, int retBUFLEN, char *def) { @@ -1293,7 +1321,8 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { return B_FALSE; } - if (notime) return B_FALSE; + /// note: notime = maybe means we can still announce flag loss + if (notime == B_TRUE) return B_FALSE; if (!lf->born && !isplayer(lf)) { return B_FALSE; @@ -1688,8 +1717,11 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { } break; case F_INVULNERABLE: - if (isplayer(lf)) { // don't know if monsters get it - msg("You feel invulnerable!"); + if (isplayer(lf)) { + msg("^%cYou feel invulnerable!", getlfcol(lf, CC_VGOOD)); + donesomething = B_TRUE; + } else { + msg("^%c%s looks invulnerable!", lfname, getlfcol(lf, CC_VGOOD)); donesomething = B_TRUE; } break; @@ -1725,7 +1757,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("^%cYou %s %s.", getlfcol(lf, CC_VBAD), pt->contracttext, pt->name); more(); } else { - msg("^%c%s looks very sick.", getlfcol(lf, CC_VBAD), lfname); + msg("^%c%s looks sick.", getlfcol(lf, CC_VBAD), lfname); } donesomething = B_TRUE; break; @@ -1886,6 +1918,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_PLANTFRIEND: + if (isplayer(lf)) { // don't know if monsters get it + msg("^gYou feel a sudden affinity towards plantlife!"); + donesomething = B_TRUE; + } + break; case F_PRODUCESLIGHT: msg("%s start%s producing light!", lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; @@ -2102,7 +2140,10 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { if (isdead(player)) { return B_FALSE; } - if (notime) return B_FALSE; + + /// note: notime = maybe means we can still announce flag loss + if (notime == B_TRUE) return B_FALSE; + if (!lf->born) { return B_FALSE; } @@ -2472,9 +2513,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { } break; case F_INVULNERABLE: - if (isplayer(lf)) { // don't know if monsters lose it + if (isplayer(lf)) { msg("You no longer feel invulnerable."); donesomething = B_TRUE; + } else { + msg("%s no longer looks invulnerable.", lfname); + donesomething = B_TRUE; } break; case F_DETECTAURAS: @@ -2598,6 +2642,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_PLANTFRIEND: + if (isplayer(lf)) { // don't know if monsters get it + msg("You no longer feel an affinity towards plantlife."); + donesomething = B_TRUE; + } + break; case F_PRODUCESLIGHT: msg("%s %s no longer producing light.", lfname, is(lf)); donesomething = B_TRUE; @@ -4144,17 +4194,12 @@ void doattackcell(char dirch) { cell_t *c; if (dirch == '\0') { - dirch = askchar("Attack in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); + dir = askdir("Attack in which direction (- to cancel)", B_TRUE, B_TRUE); } - - if (dirch == '.') { - // yourself! + if (dir == D_MYSELF) { c = player->cell; - } - - dir = chartodir(dirch); - if (dir == D_NONE) { + } else if (dir == D_NONE) { msg("Cancelled."); return; } else { @@ -4181,7 +4226,6 @@ void doattackcell(char dirch) { } void doclose(void) { - char ch; int failed = B_TRUE; // default is to fail int dir; int adjdoors; @@ -4217,12 +4261,11 @@ void doclose(void) { } else if (adjdoors == 1) { dir = forcedir; } else { - ch = askchar("Close door in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE, B_TRUE); - dir = chartodir(ch); + dir = askdir("Close door in which direction (- to cancel)", B_TRUE, B_FALSE); } if (dir == D_NONE) { - clearmsg(); + msg("Cancelled."); return; } else { cell_t *c; @@ -5084,7 +5127,6 @@ void dodrop(obpile_t *op, int wantmulti, obpile_t *dst) { object_t *toob = NULL; char toname[BUFLEN]; - // where is destination? if (dst->owner) { tolf = dst->owner; @@ -5126,6 +5168,8 @@ void dodrop(obpile_t *op, int wantmulti, obpile_t *dst) { //pickup(player, retobs[i],retobscount[i]); o = retobs[i]; + if (isdeadob(o)) continue; + count = retobscount[i]; getobname(o, buf, count); @@ -5664,8 +5708,6 @@ char *makedesc_god(lifeform_t *god, char *retbuf) { char *makedesc_job(job_t *j, char *retbuf) { char thisline[BUFLEN]; - flag_t *retflag[MAXCANDIDATES]; - int nretflags,i; skill_t *sk; enum ATTRIB a; int count = 0; @@ -5744,9 +5786,6 @@ char *makedesc_job(job_t *j, char *retbuf) { count = 0; strcpy(thisline, ""); - if (j->id == J_PIRATE) { - dblog("xxx"); - } for (sk = firstskill ; sk ; sk = sk->next) { char lev[BUFLEN]; enum SKILLLEVEL slev = PR_INEPT; @@ -5798,32 +5837,6 @@ char *makedesc_job(job_t *j, char *retbuf) { strcpy(thisline, ""); } - // specialisations - getflags(j->flags, retflag, &nretflags, F_CANHAVESUBJOB, F_NONE); - strcpy(thisline, ""); - if (nretflags > 0) { - int first = B_TRUE; - strcat(retbuf, "SPECIALISATIONS\n"); - for (i = 0; i < nretflags; i++) { - subjob_t *sj; - sj = findsubjob(retflag[i]->val[0]); - if (sj) { - char buf[BUFLEN]; - if (first) { - sprintf(buf, "- %s",sj->name); - first = B_FALSE; - } else { - sprintf(buf, ", %s",sj->name); - } - strncat(thisline, buf, HUGEBUFLEN); - } - } - if (strlen(thisline)) { - strcat(thisline, "\n"); - strncat(retbuf, thisline, HUGEBUFLEN); - } - } - return retbuf; } @@ -6639,8 +6652,9 @@ char *makedesc_ob(object_t *o, char *retbuf) { strncat(retbuf, buf, HUGEBUFLEN); } - if (obproduceslight(o)) { - sprintf(buf, "It is producing light.\n"); + i = obproduceslight(o); + if (i > 0) { + sprintf(buf, "It is producing light (%d metre%s).\n", i, (i == 1) ? "" : "s"); strncat(retbuf, buf, HUGEBUFLEN); } f = hasflag(o->flags, F_RUSTED); @@ -6970,6 +6984,13 @@ char *makedesc_ob(object_t *o, char *retbuf) { strncat(retbuf, buf2, HUGEBUFLEN); } break; + case F_DAYBOOST: + if (f->val[0] > 0) { + sprintf(buf2, "%s grants a +%d accuracy bonus during daytime.\n", buf,getaccuracymodnum(f->val[0])); + } else { + sprintf(buf2, "%s imposes a -%d accuracy penalty during daytime.\n", buf, getaccuracymodnum(abs(f->val[0]))); + } + break; case F_DETECTAURAS: sprintf(buf2, "%s allows you to detect blessings or curses.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); @@ -7014,6 +7035,13 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf2, "%s causes you to feel nauseated.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; + case F_NIGHTBOOST: + if (f->val[0] > 0) { + sprintf(buf2, "%s grants a +%d accuracy bonus at night.\n", buf,getaccuracymodnum(f->val[0])); + } else { + sprintf(buf2, "%s imposes a -%d accuracy penalty at night.\n", buf, getaccuracymodnum(abs(f->val[0]))); + } + break; case F_NONCORPOREAL: sprintf(buf2, "%s makes you non-corporeal.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); @@ -7043,7 +7071,8 @@ char *makedesc_ob(object_t *o, char *retbuf) { strncat(retbuf, buf2, HUGEBUFLEN); break; case F_PRODUCESLIGHT: - sprintf(buf2, "%s produces light.\n", buf); + sprintf(buf2, "%s produces light out to %d metre%s.\n", buf, + f->val[0], (f->val[0] == 1) ? "" : "s"); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_RETALIATE: @@ -7331,6 +7360,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel // NOVICE: // common knowledge // eg: whether it breathes water, can fly, etc. + // skills // BEGINNER: // spells/powers // knowledge known by studying this creature a little. @@ -7428,7 +7458,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel ot = findot(f->val[0]); if (ot && (ot->obclass->id == spellorabil[n])) { if (i == 0) { - sprintf(buf, "%s: %s", (spellorabil[n] == OC_ABILITY) ? "Ability" : "Spell", + sprintf(buf, "Innate %s: %s", (spellorabil[n] == OC_ABILITY) ? "Ability" : "Spell", ot->name); } else { sprintf(buf, ", %s", ot->name); @@ -7451,23 +7481,25 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel } // skills? - getflags(r->flags, retflag, &nretflags, F_STARTSKILL, F_NONE); - strcpy(buf, ""); - for (i = 0; i < nretflags; i++) { - char nextbit[BUFLEN]; - f = retflag[i]; - if (i == 0) { - sprintf(nextbit, "%s %s", getskilllevelname(f->val[1]), getskillname(f->val[0])); - } else { - sprintf(nextbit, ", %s %s", getskilllevelname(f->val[1]), getskillname(f->val[0])); + if (lorelev >= PR_NOVICE) { + getflags(r->flags, retflag, &nretflags, F_STARTSKILL, F_NONE); + strcpy(buf, ""); + for (i = 0; i < nretflags; i++) { + char nextbit[BUFLEN]; + f = retflag[i]; + if (i == 0) { + sprintf(nextbit, "%s %s", getskilllevelname(f->val[1]), getskillname(f->val[0])); + } else { + sprintf(nextbit, ", %s %s", getskilllevelname(f->val[1]), getskillname(f->val[0])); + } + strcat(buf, nextbit); + } + if (strlen(buf)) { + strncat(retbuf, "@- ", HUGEBUFLEN); + strcat(buf, "\n"); + strncat(retbuf, buf, HUGEBUFLEN); + curidx++; } - strcat(buf, nextbit); - } - if (strlen(buf)) { - strncat(retbuf, "@- ", HUGEBUFLEN); - strcat(buf, "\n"); - strncat(retbuf, buf, HUGEBUFLEN); - curidx++; } // auto bonuses from flags @@ -7554,9 +7586,13 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel case F_HITCONFER: if (lorelev >= PR_BEGINNER) { if (f->val[0] == F_POISONED) { - poisontype_t *pt; - pt = findpoisontype(f->val[1]); - sprintf(buf, "Attacks inflict %s.", pt->name); + flag_t *f2; + f2 = hasflag(r->flags, F_HITCONFERVALS); + if (f2) { + poisontype_t *pt; + pt = findpoisontype(f2->val[0]); + sprintf(buf, "Attacks inflict %s.", pt->name); + } } } break; @@ -8685,7 +8721,7 @@ void dohelp(char helpmode) { done = B_TRUE; } else { sk = (skill_t *)prompt.result; - if (sk) describeskill(sk->id, PR_INEPT); + if (sk) describeskill(sk->id, getskill(player, sk->id)); else done = B_TRUE; } } else if (helpmode == 'g') { @@ -9312,6 +9348,16 @@ int haschoice(prompt_t *p, char ch) { return B_FALSE; } +choice_t *haschoicedata(prompt_t *p, void *data) { + int i; + for (i = 0; i < p->nchoices; i++) { + if (p->choice[i].data == data) { + return &(p->choice[i]); + } + } + return NULL; +} + void doheading(WINDOW *win, int *y, int x, char *what) { int len,i; char *underline; @@ -9477,6 +9523,8 @@ int drop(object_t *o, int count) { obpile_t *op; char obname[BUFLEN]; enum OBTYPE origid; + + if (isdeadob(o)) return B_TRUE; op = o->pile; assert(op->owner); @@ -11145,6 +11193,7 @@ void drawstatus(void) { char dstring[BUFLEN]; strcpy(dstring, getdrunktext(f)); capitalise(dstring); + setcol(statwin, C_BROWN); //wprintw(statwin, " %s(%d)", dstring,f->lifetime); wprintw(statwin, " %s", dstring); @@ -12450,7 +12499,11 @@ void showlfstats(lifeform_t *lf, int showall) { } f = lfhasflag(lf, F_PRODUCESLIGHT); if (f && (f->known)) { - wrapprint(mainwin, &y, &x, 0, "%s produce%s light. ", you(lf), isplayer(lf) ? "" : "s"); + int amt; + getmaxflags(lf->flags, F_PRODUCESLIGHT, &amt, NULL, NULL); + wrapprint(mainwin, &y, &x, 0, "%s produce%s light (minimum vision range: %d). ", you(lf), + isplayer(lf) ? "" : "s", + amt); } f = lfhasknownflag(lf, F_SLOWMETAB); if (f && (f->known)) { @@ -13531,8 +13584,10 @@ void showlfstats(lifeform_t *lf, int showall) { } f = lfhasknownflag(lf, F_DRUNK); - if (f) { - mvwprintw(mainwin, y, 0, "%s %s %s.", you(lf), is(lf), getdrunktext(f)); + if (f) { + char ddesc[BUFLEN]; + getdrunkdesc(lf, f, ddesc); + mvwprintw(mainwin, y, 0, "%s %s %s (%s).", you(lf), is(lf), getdrunktext(f), ddesc); y++; } @@ -14520,9 +14575,6 @@ char wrapprint(WINDOW *win, int *y, int *x, int newlineindent, char *format, ... } else if ((*x != newlineindent) && strlen(word)) { textwithcol_real(win, " ", B_FALSE); } - /* if (strlen(repword) < 2) { - dblog("xxx"); - } */ textwithcol_real(win, repword, B_FALSE); //(*x) += strlen(buf); getyx(win, *y, *x); diff --git a/io.h b/io.h index cfeaec2..494c7e4 100644 --- a/io.h +++ b/io.h @@ -28,6 +28,7 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts); char askchar(char *prompt, char *validchars, char *def, int showchars, int maycancel); cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail); cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int minrange, int maxrange, enum LOFTYPE loftype, int wanttrail, cell_t **spectarg, int nspectargs); +char askdir(char *prompt, int maycancel, int usedrunk); char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def); vault_t *askvault(char *prompttext); void centre(WINDOW *win, enum COLOUR col, int y, char *format, ... ); @@ -105,6 +106,7 @@ enum COLOUR getskilllevelcolour(enum SKILLLEVEL slev); void handle_ctrl_y(int arg); void handleinput(void); int haschoice(prompt_t *p, char ch); +choice_t *haschoicedata(prompt_t *p, void *data); void doheading(WINDOW *win, int *y, int x, char *what); void doheadingsmall(WINDOW *win, int y, int x, char *format, char *heading); void initgfx(void); diff --git a/lf.c b/lf.c index a55201f..42d3f8f 100644 --- a/lf.c +++ b/lf.c @@ -37,7 +37,6 @@ extern behaviour_t *firstbehaviour, *lastbehaviour; extern job_t *firstjob, *lastjob; extern skill_t *firstskill, *lastskill; extern poisontype_t *firstpoisontype,*lastpoisontype; -extern subjob_t *firstsubjob,*lastsubjob; extern objecttype_t *objecttype; extern lifeform_t *player; @@ -81,8 +80,15 @@ race_t **raceposs; int *xpposs; int xplistlen; -int notime = B_FALSE; // prevent taketime from doing anything +// notime has three options: +// B_FALSE = no special effects +// B_MAYBE = prevent taketime from doing anything +// B_TRUE = prevent taketime from doing anything +// don't announce flag gain/loss +int notime = B_FALSE; + +/* void add_subjob_alignment_restrictions(flagpile_t *fp, enum SUBJOB sj) { if (sj == SJ_PALADIN) { addflag(fp, F_ALIGNMENT, AL_NONE, NA, NA, "g"); @@ -90,6 +96,7 @@ void add_subjob_alignment_restrictions(flagpile_t *fp, enum SUBJOB sj) { addflag(fp, F_ALIGNMENT, AL_NONE, NA, NA, "e"); } } +*/ void autoweild(lifeform_t *lf) { @@ -595,6 +602,76 @@ int canattack(lifeform_t *lf) { return B_TRUE; } +// need ob is populated with with the obejcttype needed. +int canbuild(lifeform_t *lf, objecttype_t *ot, char *needtext, enum OBTYPE *needob, int *numneed) { + char requiretext[BUFLEN]; + objecttype_t *tempot; + char *template = " (required %d x %s)"; + object_t *o; + + *needob = OT_NONE; + if (needtext) sprintf(needtext, "%s", ot->name); + + switch (ot->id) { + case OT_BARRICADE: + *needob = OT_IRONSTAFF; + *numneed = 2; + break; + case OT_RUBBLE: + *needob = OT_STONE; + *numneed = 20; + break; + case OT_FENCEWOOD: + *needob = OT_WOODPLANK; + *numneed = 1; + break; + case OT_TRAPDOORFALL: + *needob = OT_NONE; + *numneed = 0; + break; + case OT_TRAPNEEDLEP: + *needob = OT_NEEDLE; + *numneed = 1; + break; + case OT_TRAPFIRE: + *needob = OT_POT_RUM; + *numneed = 1; + break; + case OT_TRAPMINE: + *needob = OT_GRENADE; + *numneed = 1; + break; + case OT_TRAPARROW: + *needob = OT_ARROW; + *numneed = 1; + break; + case OT_TRAPROCK: + *needob = OT_STONE; + *numneed = 1; + break; + case OT_TRAPTRIP: + *needob = OT_ROPE; + *numneed = 1; + break; + default: + break; + } + + if (*needob == OT_NONE) { + return B_TRUE; + } + + o = hasob(lf->pack, *needob); + if (o && (o->amt >= *numneed)) { + tempot = findot(*needob); + sprintf(requiretext, template, *numneed, tempot->name); + if (needtext) strcat(needtext, requiretext); + return B_TRUE; + } + + return B_FALSE; +} + int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { int castable = B_FALSE; flag_t *f; @@ -621,7 +698,7 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { return B_FALSE; } - if (hassubjob(lf, SJ_PALADIN)) { + if (hasjob(lf, J_PALADIN)) { object_t *o; // using cursed weapons/armour? no spells. for (o = lf->pack->first ; o ; o = o->next) { @@ -1414,7 +1491,7 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { return B_FALSE; } // paladin? - if (getsubjob(lf) == SJ_PALADIN) { + if (hasjob(lf, J_PALADIN)) { if (!isblessed(o) || !o->blessknown) { if (isarmour(o)) { reason = E_PALADIN; @@ -1531,7 +1608,7 @@ int canweild(lifeform_t *lf, object_t *o) { } // paladin? - if (getsubjob(lf) == SJ_PALADIN) { + if (hasjob(lf, J_PALADIN)) { if (!isblessed(o) || !o->blessknown) { reason = E_PALADIN; return B_FALSE; @@ -1744,12 +1821,23 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar // special case if (!willflag) { - f = lfhasflag(lf, F_NEEDOBFORSPELLS); - if (f && !hasob(lf->pack, f->val[0])) { - objecttype_t *ot; - ot = findot(f->val[0]); - if (isplayer(lf)) { - msg("You can't cast spells without %s %s.",needan(ot->name) ? "an" : "a", ot->name); + flag_t *mf; + mf = missingspellcastob(lf); + if (mf) { + if (strlen(mf->text)) { + if (isplayer(lf)) { + msg("You can't cast spells without a %s.", mf->text); + } + } else if (mf->val[0] != NA) { + objecttype_t *ot; + ot = findot(mf->val[0]); + if (isplayer(lf)) { + msg("You can't cast spells without %s %s.",needan(ot->name) ? "an" : "a", ot->name); + } + } else { + if (isplayer(lf)) { + msg("You can't cast spells without a spell focus."); + } } return B_TRUE; } @@ -1930,10 +2018,12 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar if (!isplayer(lf) && !fromob) { int doannounce = B_FALSE; - if (cansee(player, lf)) { - doannounce = B_TRUE; - } else if ((casttype == CT_SOUNDBASED) && canhear(player, lf->cell, SV_TALK, NULL)) { - doannounce = B_TRUE; + if (gamemode == GM_GAMESTARTED) { + if (cansee(player, lf)) { + doannounce = B_TRUE; + } else if ((casttype == CT_SOUNDBASED) && canhear(player, lf->cell, SV_TALK, NULL)) { + doannounce = B_TRUE; + } } if (doannounce) { char lfname[BUFLEN]; @@ -2193,7 +2283,7 @@ int celllitfor(lifeform_t *lf, cell_t *c, int maxvisrange, int nightvisrange) { } */ -int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod) { +int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod, cell_t *nextcell) { object_t *o; flag_t *f; @@ -2201,9 +2291,22 @@ int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod) { // solid cells stop los (unless it's your own cell) if (!c->type->transparent && (c != lf->cell)) { - if (xray && *xray) { - (*xray)--; - } else return B_FALSE; + int ok = B_FALSE; + + // high engineering lets you detect hollow walls. ie. + // if a wall has another wall behind it, you 'see' it. + if (c->type->solid && nextcell && nextcell->type->solid) { + if (isadjacent(c, lf->cell) && !isadjacent(nextcell, lf->cell) && + (getskill(lf, SK_ENGINEERING) >= PR_BEGINNER)) { + ok = B_TRUE; + } + } + + if (!ok) { + if (xray && *xray) { + (*xray)--; + } else return B_FALSE; + } } // check for lfs which block view @@ -2226,7 +2329,8 @@ int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod) { for (o = c->obpile->first ; o ; o = o->next) { f = hasflag(o->flags, F_BLOCKSVIEW); if (f) { - if (!lfhasflagval(lf, F_CANSEETHROUGHMAT, o->material->id, NA, NA, NULL)) { + if ((lf->cell == c) && (f->val[1] == B_TRUE)) { + } else if (!lfhasflagval(lf, F_CANSEETHROUGHMAT, o->material->id, NA, NA, NULL)) { if (xray && *xray) { (*xray)--; } else { @@ -3066,9 +3170,9 @@ void die(lifeform_t *lf) { if (cansee(player, lf)) dividelos = B_TRUE; // are there 2 random cells free? - dividecell[0] = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND, LOF_WALLSTOP, NULL, NULL, NULL); + dividecell[0] = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND, LOF_WALLSTOP, NULL, NULL, NULL, MT_NOTHING); if (dividecell[0]) { - dividecell[1] = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND, LOF_WALLSTOP, NULL, dividecell[0], NULL); + dividecell[1] = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND, LOF_WALLSTOP, NULL, dividecell[0], NULL, MT_NOTHING); } if (!dividecell[1]) { @@ -3272,8 +3376,8 @@ void die(lifeform_t *lf) { } } - // award xp (but not if another monster killed it) if (hasflag(lf->flags, F_KILLEDBYPLAYER)) { + // award xp if the player killed it. awardxpfor(lf,100); if ((getalignment(lf) == AL_EVIL) || isundead(lf) || (getraceclass(lf) == RC_DEMON)) { pleasegodmaybe(R_GODPURITY, 5); @@ -4865,27 +4969,14 @@ int eat(lifeform_t *lf, object_t *o) { } else if (o->type->id == OT_CARROT) { killtransitoryflags(lf->flags, F_BLIND); addtempflag(lf->flags, F_SEEINDARK, 3, NA, NA, NULL, rnd(20,40)); + } else if (o->type->id == OT_MUSHROOMGREY) { + addtempflag(lf->flags, F_DTRESIST, DT_COLD, NA, NA, NULL, rnd(20,40)); } else if (o->type->id == OT_POISONSAC) { // very bad! poison(lf, rnd(10,20), P_VENOM, 4, "eating a venom sac", R_NONE); } if (isplayer(lf)) makeknown(o->type->id); - - if (isplayer(lf)) { - flag_t *f; - f = hasflag(o->flags, F_CORPSEOF); - if (f) { - race_t *r; - r = findrace(f->val[0]); - if (r && (r->raceclass->id == RC_ANIMAL)) { - if (gethungerlevel(gethungerval(lf)) > H_NONE) { - pleasegodmaybe(R_GODNATURE, 5); - } - } - } - } - } // end if fullyeaten // take time @@ -4937,6 +5028,13 @@ int eat(lifeform_t *lf, object_t *o) { angergodmaybe(R_GODNATURE, 100, GA_EAT); stopeating = B_TRUE; } + // eating animals pleases ekrub + if (corpserace && (corpserace->raceclass->id == RC_ANIMAL)) { + if (gethungerlevel(gethungerval(lf)) > H_NONE) { + pleasegodmaybe(R_GODNATURE, 5); + addflag(o->flags, F_NOSACRIFICE, B_TRUE, NA, NA, NULL); + } + } } if (lfhasflagval(lf, F_FATALFOOD, o->type->id, NA, NA, NULL)) { @@ -6099,6 +6197,7 @@ enum SKILLLEVEL findskilllevbyname(char *name) { return PR_INEPT; } +/* subjob_t *findsubjob(enum SUBJOB sjid) { subjob_t *j; for (j = firstsubjob ; j ; j = j->next) { @@ -6114,6 +6213,7 @@ subjob_t *findsubjobbyletter(char letter) { } return NULL; } +*/ // returns true if we did somethign int fixcurses(lifeform_t *lf) { @@ -6940,6 +7040,11 @@ int getalignmod(lifeform_t *lf) { enum ALLEGIENCE getallegiance(lifeform_t *lf) { flag_t *f; + + if (lfhasflag(player, F_PLANTFRIEND) && (getraceclass(lf) == RC_PLANT)) { + return AL_FRIENDLY; + } + f = lfhasflag(lf, F_CHARMEDBY); if (f) { lifeform_t *cb; @@ -7198,15 +7303,7 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) { val += f->val[1]; } if (f->id == F_DRUNK) { - if (attr == A_AGI) { - if (hasjob(lf, J_PIRATE)) { - val += (f->val[0]*5); - } else { - val -= (f->val[0]*5); - } - } else if (attr == A_WIS) { - val -= (f->val[0]*5); - } + val += getdrunkattrmod(lf, attr, f->val[0]); } if (f->id == F_INJURY) { if ((f->val[0] == IJ_NOSEBROKEN) && (attr == A_CHA)) { @@ -7432,6 +7529,26 @@ enum CASTTYPE getcasttype(lifeform_t *lf, enum OBTYPE sid) { return CT_NORMAL; } +int getdrunkattrmod(lifeform_t *lf, enum ATTRIB att, int drunkamt) { + int val = 0; + if (att == A_AGI) { + if (hasjob(lf, J_PIRATE)) { + val += (drunkamt*5); + } else { + val -= (drunkamt*5); + } + } else if (att == A_WIS) { + val -= (drunkamt*5); + } + return val; +} + +int getengineeringwallmod(lifeform_t *lf) { + enum SKILLLEVEL slev; + slev = getskill(lf, SK_ENGINEERING); + return slev * 2; +} + float getequippedweight(lifeform_t *lf) { object_t *o; float total = 0; @@ -7449,6 +7566,9 @@ int getevasion(lifeform_t *lf) { flag_t *retflag[MAXCANDIDATES]; int nretflags; double level_ev = 0, skillpctmod; + enum SKILLLEVEL slev; + + slev = getskill(lf, SK_EVASION); // no evasion if you can't move! if (isimmobile(lf)) { @@ -7474,10 +7594,15 @@ int getevasion(lifeform_t *lf) { ev += level_ev; // dexterity mod - ev += (getattr(lf, A_AGI)/5); + + if (slev) { + ev += (getattr(lf, A_AGI)/5); + } else { + ev += (getattr(lf, A_AGI)/10); + } // apply skill based evasion modifier - skillpctmod = 100 + (getskill(lf, SK_EVASION) * 12); + skillpctmod = 100 + (slev * 12); ev = pctof(skillpctmod, ev); // swimevasion creatures get extra evasion while swimming @@ -7507,7 +7632,7 @@ int getevasion(lifeform_t *lf) { } // you are easier to hit if you're glowing - if (hasflag(lf->flags, F_PRODUCESLIGHT)) { + if (lfproduceslight(lf, NULL)) { ev -= 5; } @@ -8033,6 +8158,24 @@ job_t *getjob(lifeform_t *lf) { return NULL; } +enum JOBCATEGORY getjobcat(lifeform_t *lf) { + flag_t *f; + + // no job if polymorphed + if (lfhasflag(lf, F_POLYMORPHED)) { + return JC_NONE; + } + + f = hasflag(lf->flags, F_JOB); + if (f) { + job_t *j; + j = findjob(f->val[0]); + if (j) return j->category; + } + return JC_NONE; +} + +/* enum SUBJOB getsubjob(lifeform_t *lf) { flag_t *f; f = lfhasflag(lf, F_JOB); @@ -8041,17 +8184,10 @@ enum SUBJOB getsubjob(lifeform_t *lf) { } return SJ_NONE; } +*/ char *getjobname(lifeform_t *lf) { - enum SUBJOB sjid; job_t *j; - subjob_t *sj; - sjid = getsubjob(lf); - sj = findsubjob(sjid); - if (sj) { - return sj->name; - } - j = getjob(lf); if (j) { return j->name; @@ -8496,7 +8632,8 @@ int getnightvisrange(lifeform_t *lf) { } } - sumflags(lf->flags, F_PRODUCESLIGHT, &lightamt, NULL, NULL); + //getmaxflags(lf->flags, F_PRODUCESLIGHT, &lightamt, NULL, NULL); + lightamt = lfproduceslight(lf, NULL); range += lightamt; limit(&range, 0, MAXVISRANGE); @@ -8648,6 +8785,13 @@ int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, flag_t *noiseflag, if (*volume <= 0) return B_TRUE; } } + + + // adjust footstep volume for floor type + if ((nid == N_WALK) && lf->cell && volume) { + *volume += lf->cell->type->volumemod; + if (*volume <= 0) return B_TRUE; + } return B_FALSE; } @@ -9044,7 +9188,7 @@ int real_getmr(lifeform_t *lf, int onlyexternal) { // sum all MR flags sumflags(lf->flags, F_RESISTMAG, &amt, NULL, NULL); // scourge gets job-based bonus - if (hassubjob(lf, SJ_SCOURGE)) { + if (hasjob(lf, J_SCOURGE)) { amt += (gettr(lf) * 3); } } @@ -10739,10 +10883,7 @@ void givebehaviour(lifeform_t *lf, enum BEHAVIOUR bid) { } } -// subjobid is ONLY used when giving the player their initial job. -// -// in other cases, use givesubjob() directly. -void givejob(lifeform_t *lf, enum JOB jobid, enum SUBJOB sj) { +void givejob(lifeform_t *lf, enum JOB jobid) { job_t *j; flag_t *f; int i; @@ -10752,6 +10893,8 @@ void givejob(lifeform_t *lf, enum JOB jobid, enum SUBJOB sj) { int db = B_FALSE; flag_t *retflag[MAXCANDIDATES]; int nretflags; + object_t *sb1 = NULL, *sb2 = NULL,*o = NULL; + skill_t *sk; if (db) dblog("givejob() starting.\n"); @@ -10837,7 +10980,7 @@ void givejob(lifeform_t *lf, enum JOB jobid, enum SUBJOB sj) { switch (f->id) { case F_MAXHPMOD: case F_JOBATTRMOD: - case F_CANHAVESUBJOB: + //case F_CANHAVESUBJOB: ignorethis = B_TRUE; break; case F_CANLEARN: @@ -10861,11 +11004,6 @@ void givejob(lifeform_t *lf, enum JOB jobid, enum SUBJOB sj) { } } - // special case - override selectweapon - if (sj == SJ_SCOURGE) { - killflagsofid(lf->flags, F_SELECTWEAPON); - } - // now give start obs/skills from the job givestartskills(lf, lf->flags); if (!lfhasflag(lf, F_PHANTASM)) { @@ -10963,198 +11101,61 @@ void givejob(lifeform_t *lf, enum JOB jobid, enum SUBJOB sj) { } } - // select subjobs - if ((gamemode == GM_CHARGEN) && isplayer(lf)) { - /* - subjob_t *sub; - else { - initprompt(&prompt, "Select your job specialty:"); - for (sub = firstsubjob ; sub ; sub = sub->next) { - if (hasflagval(j->flags, F_CANHAVESUBJOB, sub->id, NA, NA, NULL)) { - if (jobpossible(lf->flags, J_NONE, sub->id)) { - addchoice(&prompt, sub->letter, sub->name, NULL, sub, sub->desc); - } - } - } - - addchoice(&prompt, '-', "(none)", NULL, NULL, NULL); - if (prompt.nchoices > 1) { - getchoicestr(&prompt, B_FALSE, B_TRUE); - sub = (subjob_t *)prompt.result; - if (sub) { - sj = sub->id; - } else { - sj = SJ_NONE; - } - } - } - */ - - givesubjob(lf, sj); - - if (j->id == J_WIZARD) { - object_t *sb2; - skill_t *sk; - // wizards with no subjob: - if (sj == SJ_NONE) { - object_t *sb1; - // start with a grimoire of spells - sb1 = addob(lf->pack, "grimoire"); - identify(sb1); - - // monsters get spells from a random school - addflag(lf->flags, F_RNDSPELLCOUNT, rnd(2,4), NA, NA, NULL); - addflag(lf->flags, F_RNDSPELLSCHOOL, SS_NONE, 1, lf->level, NULL); - - } - - if (sj != SJ_NONE) { - // wizards with sub-jobs now get a secondary school - initprompt(&prompt, "Select your secondary spell school:"); - addchoice(&prompt, 'd', getskillname(SK_SS_DIVINATION), NULL, findskill(SK_SS_DIVINATION), NULL); - addchoice(&prompt, 's', getskillname(SK_SS_SUMMONING), NULL, findskill(SK_SS_SUMMONING), NULL); - addchoice(&prompt, 't', getskillname(SK_SS_TRANSLOCATION), NULL, findskill(SK_SS_TRANSLOCATION), NULL); - getchoice(&prompt); - sk = (skill_t *) prompt.result; - switch (sk->id) { - case SK_SS_DIVINATION: - sb2 = addob(lf->pack, "spellbook of divination magic"); - break; - case SK_SS_SUMMONING: - sb2 = addob(lf->pack, "spellbook of summoning magic"); - break; - case SK_SS_TRANSLOCATION: - sb2 = addob(lf->pack, "spellbook of translocation magic"); - break; - default: - sb2 = NULL; - break; - } - if (sb2) { - addflag(lf->flags, F_CANCAST, sb2->contents->first->type->id, NA, NA, NULL); - if (isplayer(lf)) { - addflag(lf->flags, F_SHORTCUT, getnextshortcut(lf), NA, NA, sb2->contents->first->type->name); - addflag(sb2->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); - } - } - identify(sb2); - } - } - } - - if (isplayer(lf)) { - generatealignment(lf); - } - - if (hasflag(j->flags, F_STAYINROOM)) sethomeroom(lf); -} - -void givesubjob(lifeform_t *lf, enum SUBJOB sj) { - flag_t *jobflag,*f; - object_t *sb1 = NULL,*o; - int i; - - if (sj == SJ_NONE) return; - - // remember the subjob - jobflag = lfhasflag(lf, F_JOB); - jobflag->val[1] = sj; - - switch (sj) { - // mage types - case SJ_AIRMAGE: - o = addob(lf->pack, "15 blessed darts"); - identify(o); - giveskilllev(lf, SK_THROWING, PR_NOVICE); - addflag(lf->flags, F_CANSEETHROUGHMAT, MT_GAS, NA, NA, NULL); + // magic-user spellbooks + switch (j->id) { + case J_AIRMAGE: sb1 = addob(lf->pack, "spellbook of air magic"); if (!isplayer(lf)) { addflag(lf->flags, F_RNDSPELLCOUNT, rnd(2,4), NA, NA, NULL); addflag(lf->flags, F_RNDSPELLSCHOOL, SS_AIR, 1, lf->level, NULL); } break; - case SJ_ICEMAGE: + case J_ICEMAGE: sb1 = addob(lf->pack, "spellbook of cold magic"); if (!isplayer(lf)) { addflag(lf->flags, F_RNDSPELLCOUNT, rnd(2,4), NA, NA, NULL); addflag(lf->flags, F_RNDSPELLSCHOOL, SS_COLD, 1, lf->level, NULL); } break; - case SJ_FIREMAGE: + case J_FIREMAGE: sb1 = addob(lf->pack, "spellbook of fire magic"); if (!isplayer(lf)) { addflag(lf->flags, F_RNDSPELLCOUNT, rnd(2,4), NA, NA, NULL); addflag(lf->flags, F_RNDSPELLSCHOOL, SS_FIRE, 1, lf->level, NULL); } break; - case SJ_NECROMANCER: + case J_NECROMANCER: sb1 = addob(lf->pack, "spellbook of necromancy"); if (!isplayer(lf)) { addflag(lf->flags, F_RNDSPELLCOUNT, rnd(2,4), NA, NA, NULL); addflag(lf->flags, F_RNDSPELLSCHOOL, SS_DEATH, 1, lf->level, NULL); } break; - case SJ_WILDMAGE: + case J_WILDMAGE: sb1 = addob(lf->pack, "spellbook of wild magic"); if (!isplayer(lf)) { addflag(lf->flags, F_RNDSPELLCOUNT, rnd(2,4), NA, NA, NULL); addflag(lf->flags, F_RNDSPELLSCHOOL, SS_WILD, 1, lf->level, NULL); } break; - // warrior types - case SJ_BATTLEMAGE: + case J_BATTLEMAGE: // starts off with a grimoire (special code in objects.c will restrict this // to only have 3 spells) sb1 = addob(lf->pack, "grimoire"); identify(sb1); - // can learn some spell schools, but only up to adept level - addtempflag(lf->flags, F_CANLEARN, SK_SS_FIRE, PR_ADEPT, NA, NULL, FROMJOB); - addtempflag(lf->flags, F_CANLEARN, SK_SS_COLD, PR_ADEPT, NA, NULL, FROMJOB); - addtempflag(lf->flags, F_CANLEARN, SK_SS_AIR, PR_ADEPT, NA, NULL, FROMJOB); - addtempflag(lf->flags, F_CANLEARN, SK_SS_TRANSLOCATION, PR_ADEPT, NA, NULL, FROMJOB); - addtempflag(lf->flags, F_CANLEARN, SK_SS_WILD, PR_ADEPT, NA, NULL, FROMJOB); - // raise IQ to average so that we aren't too dumb to cast L1 spells - i = rollattr(AT_AVERAGE); - limit(&i, 50, NA); - lf->baseatt[A_IQ] = i; - lf->att[A_IQ] = i; - // replace mpdice - killflagsofid(lf->flags, F_MPDICE); - addtempflag(lf->flags, F_MPDICE, 1, 0, NA, NULL, FROMJOB); - // remove warrior's hitdice bonus - killflagsofid(lf->flags, F_MAXHPMOD); - // remove warrior's level abilities - killflagsofid(lf->flags, F_LEVABIL); // make sure we have the right skills for (o = sb1->contents->first ; o ; o = o->next) { giveskill(lf, getschoolskill(getspellschool(o->type->id))); } - // un-set sb1 so we don't automatically learn the first spell - sb1 = NULL; break; - case SJ_PALADIN: - // extra skills - healing magic & speech - giveskilllev(lf, SK_SS_LIFE, PR_NOVICE); + case J_PALADIN: sb1 = addob(lf->pack, "spellbook of life magic"); - giveskilllev(lf, SK_SPEECH, PR_NOVICE); - // must worship glorana if (isplayer(lf)) { lifeform_t *god; god = findgod(R_GODLIFE); addflag(god->flags, F_PRAYEDTO, B_TRUE, NA, NA, NULL); } - // raise WIS to gtaverage for life magic - lf->baseatt[A_WIS] = rollattr(AT_GTAVERAGE); - lf->att[A_WIS] = lf->baseatt[A_WIS]; - // raise CHA to average for speech - if (getattrbracket(getattr(lf, A_CHA), A_CHA, NULL) < AT_AVERAGE) { - lf->baseatt[A_CHA] = rollattr(AT_AVERAGE); - lf->att[A_CHA] = lf->baseatt[A_CHA]; - } - // can permenantly turn undead for 0 power. - addtempflag(lf->flags, F_CANWILL, OT_S_TURNUNDEAD, NA, NA, NULL, FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 5, OT_S_DISRUPTUNDEAD, NA, NULL, FROMJOB); if (isplayer(lf)) { addflag(lf->flags, F_SHORTCUT, getnextshortcut(lf), NA, NA, "turn undead"); } @@ -11164,71 +11165,52 @@ void givesubjob(lifeform_t *lf, enum SUBJOB sj) { blessob(o); } } - // remove warrior's level abilities - killflagsofid(lf->flags, F_LEVABIL); - // instead, you get 'exorcise' at level 5 - addflag(lf->flags, F_LEVABIL, 5, OT_S_EXORCISE, NA, "pw:1;"); // monster spells if (!isplayer(lf)) { addflag(lf->flags, F_RNDSPELLCOUNT, rnd(2,4), NA, NA, NULL); addflag(lf->flags, F_RNDSPELLSCHOOL, SS_LIFE, 1, 6, NULL); } - break; - case SJ_SCOURGE: - // remove warrior's level abilities - killflagsofid(lf->flags, F_LEVABIL); - // scourges can't pick their weapon - they start with a whip - addob(lf->pack, "bullwhip"); - autoweild(lf); - // scourges don't get advanced combat - f = lfhasflagval(lf, F_HASSKILL, SK_COMBAT, NA, NA, NULL); - if (f) killflag(f); - f = lfhasflagval(lf, F_CANWILL, OT_A_STRIKETOKO, NA, NA, NULL); - if (f) killflag(f); - - // magic resistance at level 5 - addtempflag(lf->flags, F_RESISTMAG, 5, NA, NA, NULL, FROMJOB); - // no mp or other magic. - killflagsofid(lf->flags, F_MPDICE); - killflagsofid(lf->flags, F_CANCAST); - f = lfhasflagval(lf, F_HASSKILL, SK_SS_ALLOMANCY, NA, NA, NULL); - if (f) killflag(f); - // - addtempflag(lf->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL, FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 2, OT_S_NULLIFY, NA, "pw:1;", FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 4, OT_S_NULLIFY, NA, "pw:2;", FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 6, OT_S_NULLIFY, NA, "pw:3;", FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 8, OT_S_NULLIFY, NA, "pw:4;", FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 10, OT_S_NULLIFY, NA, "pw:5;", FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 12, OT_S_NULLIFY, NA, "pw:6;", FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 14, OT_S_NULLIFY, NA, "pw:7;", FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 16, OT_S_NULLIFY, NA, "pw:8;", FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 18, OT_S_NULLIFY, NA, "pw:9;", FROMJOB); - addtempflag(lf->flags, F_LEVABIL, 20, OT_S_NULLIFY, NA, "pw:10;", FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_ALLOMANCY, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_MENTAL, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_NATURE, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_AIR, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_DEATH, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_DIVINATION, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_FIRE, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_COLD, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_LIFE, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_SUMMONING, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_TRANSLOCATION, NA, NA, NULL,FROMJOB); - addtempflag(lf->flags, F_NOSKILL, SK_SS_WILD, NA, NA, NULL,FROMJOB); - - break; - // default: break; } + // player-controlled specialised wizards now get a secondary school + if (isplayer(lf) && (j->category == JC_MAGE)) { + initprompt(&prompt, "Select your secondary spell school:"); + addchoice(&prompt, 'd', getskillname(SK_SS_DIVINATION), NULL, findskill(SK_SS_DIVINATION), NULL); + addchoice(&prompt, 's', getskillname(SK_SS_SUMMONING), NULL, findskill(SK_SS_SUMMONING), NULL); + addchoice(&prompt, 't', getskillname(SK_SS_TRANSLOCATION), NULL, findskill(SK_SS_TRANSLOCATION), NULL); + getchoice(&prompt); + sk = (skill_t *) prompt.result; + switch (sk->id) { + case SK_SS_DIVINATION: + sb2 = addob(lf->pack, "spellbook of divination magic"); + break; + case SK_SS_SUMMONING: + sb2 = addob(lf->pack, "spellbook of summoning magic"); + break; + case SK_SS_TRANSLOCATION: + sb2 = addob(lf->pack, "spellbook of translocation magic"); + break; + default: + sb2 = NULL; + break; + } + if (sb2) { + autolearnspellsfrombook(lf, sb2); + addflag(sb2->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); + } + identify(sb2); + } // end if not plain wizard + + + // special spellbook code. if (sb1) { if (isplayer(lf)) { - addtempflag(lf->flags, F_CANCAST, sb1->contents->first->type->id, NA, NA, NULL, FROMJOB); - addtempflag(lf->flags, F_SHORTCUT, getnextshortcut(lf), NA, NA, sb1->contents->first->type->name, FROMJOB); + // auto learn and shortcut all spells form it. + autolearnspellsfrombook(lf, sb1); + addflag(sb1->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); identify(sb1); } else { @@ -11253,9 +11235,40 @@ void givesubjob(lifeform_t *lf, enum SUBJOB sj) { } } - add_subjob_alignment_restrictions(lf->flags, sj); -} + // select subjobs + /* + if ((gamemode == GM_CHARGEN) && isplayer(lf)) { + subjob_t *sub; + else { + initprompt(&prompt, "Select your job specialty:"); + for (sub = firstsubjob ; sub ; sub = sub->next) { + if (hasflagval(j->flags, F_CANHAVESUBJOB, sub->id, NA, NA, NULL)) { + if (jobpossible(lf->flags, J_NONE, sub->id)) { + addchoice(&prompt, sub->letter, sub->name, NULL, sub, sub->desc); + } + } + } + addchoice(&prompt, '-', "(none)", NULL, NULL, NULL); + if (prompt.nchoices > 1) { + getchoicestr(&prompt, B_FALSE, B_TRUE); + sub = (subjob_t *)prompt.result; + if (sub) { + sj = sub->id; + } else { + sj = SJ_NONE; + } + } + } + } + */ + + if (isplayer(lf)) { + generatealignment(lf); + } + + if (hasflag(j->flags, F_STAYINROOM)) sethomeroom(lf); +} int givemoney(lifeform_t *from, lifeform_t *to, int amt) { object_t *gold; @@ -11424,7 +11437,7 @@ int giverandomobs(lifeform_t *lf, int amt) { flag_t *giveskill(lifeform_t *lf, enum SKILL id) { flag_t *f = NULL, *newf; skill_t *sk; - int markasused = B_FALSE; + int markasused = B_FALSE,i; switch (id) { case SK_CARTOGRAPHY: @@ -11465,77 +11478,13 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { more(); } - // special effects for gaining a skill. - - // remember that these from from a SKILL, so that - // they are invalidated if we get polymorphed. - if (id == SK_ATHLETICS) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_CLIMBING) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_CLIMB, NA, NA, NULL); - if (!newf || (newf->lifetime > 0)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_CLIMB, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_CLUBS) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_STRIKETOKO, NA, NA, NULL); - if (!newf || (newf->lifetime > 0)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_STRIKETOKO, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_COMBAT) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_STRIKETOKO, NA, NA, NULL); - if (!newf || (newf->lifetime > 0)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_STRIKETOKO, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_COOKING) { + // special effects for gaining a skill (other than conferred abilities). + if (id == SK_COOKING) { if (isplayer(lf)) { makeknown(OT_POT_WATER); makeknown(OT_POT_JUICE); makeknown(OT_POT_RUM); } - newf = hasflagval(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_LORE_ARCANA) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_LORE_DEMONS) { - newf = hasflagval(lf->flags, F_CANWILL, OT_S_EXORCISE, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_S_EXORCISE, NA, NA, "pw:1;", FROMSKILL); - } - } else if (id == SK_LOCKPICKING) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_PICKLOCK, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_PICKLOCK, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_METALWORK) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_SEWING) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_STEALTH) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_THIEVERY) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_TRAPS) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL, FROMSKILL); } // learning a new spell school skill after the game has started will grant @@ -11559,7 +11508,6 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { } - // special effects based on skill level if (isplayer(lf) && isloreskill(id) && (f->val[1] == PR_ADEPT)) { race_t *r; @@ -11569,64 +11517,27 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { } } + // grant abilities based on skills... + for (i = 0; i < sk->nskillwills; i++) { + if (sk->skillwill[i].lev == f->val[1]) { + newf = hasflagval(lf->flags, F_CANWILL, sk->skillwill[i].abilid, + NA, NA, NULL); + if (!newf || (newf->lifetime > 0)) { + newf = addtempflag(lf->flags, F_CANWILL, sk->skillwill[i].abilid, + sk->skillwill[i].timeout, sk->skillwill[i].timeout, + sk->skillwill[i].text, FROMSKILL); + newf->skillfrom = sk; + } + } + } - if (id == SK_ATHLETICS) { - if (f->val[1] == PR_ADEPT) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_TUMBLE, NA, NA, NULL, FROMSKILL); - } else if (f->val[1] == PR_EXPERT) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_JUMP, NA, NA, NULL, FROMSKILL); - } - } else if (id == SK_CARTOGRAPHY) { - if (f->val[1] == PR_SKILLED) { - addtempflag(lf->flags, F_PHOTOMEM, B_TRUE, NA, NA, NULL, FROMSKILL); - } - if (f->val[1] == PR_MASTER) { - if (!hasflagval(lf->flags, F_CANWILL, OT_S_MAPPING, NA, NA, NULL)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_S_MAPPING, 50, 50, "pw:1;", FROMSKILL); - } - } - } else if (id == SK_COMBAT) { - if (f->val[1] == PR_ADEPT) { - if (!hasflagval(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_DISARMLF, NA, NA, NULL, FROMSKILL); - } - } else if (f->val[1] == PR_SKILLED) { - if (!hasflagval(lf->flags, F_CANWILL, OT_A_FLIP, NA, NA, NULL)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_FLIP, NA, NA, NULL, FROMSKILL); - } - } - } else if (id == SK_COOKING) { + if (id == SK_COOKING) { if (f->val[1] == PR_ADEPT) { if (isplayer(lf)) { makeknown(OT_MUSHROOMSHI); makeknown(OT_MUSHROOMTOAD); } } - } else if (id == SK_EVASION) { - if (f->val[1] == PR_ADEPT) { - if (isplayer(lf)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_SNATCH, NA, NA, NULL, FROMSKILL); - } - } else if (f->val[1] == PR_SKILLED) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_REFLEXDODGE, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_REFLEXDODGE, NA, NA, NULL, FROMSKILL); - } - } - } else if (id == SK_LORE_ARCANA) { - if (f->val[1] == PR_ADEPT) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL, FROMSKILL); - } - } - } else if (id == SK_LORE_DEMONS) { - if (f->val[1] == PR_SKILLED) { - newf = hasflagval(lf->flags, F_CANWILL, OT_S_SUMMONDEMON, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_S_SUMMONDEMON, NA, NA, "pw:1;", FROMSKILL); - } - } } else if (id == SK_LORE_NATURE) { if (f->val[1] == PR_BEGINNER) { if (isplayer(lf)) { @@ -11634,40 +11545,12 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { makeknown(OT_MUSHROOMTOAD); } } - } else if (id == SK_METALWORK) { - if (f->val[1] == PR_SKILLED) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL, FROMSKILL); - } - } else if (f->val[1] == PR_MASTER) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL, FROMSKILL); - } - } } else if (id == SK_PERCEPTION) { if ((f->val[1] == PR_ADEPT) || (f->val[1] == PR_MASTER)) { // our FOV gets wider lf->losdirty = B_TRUE; if (isplayer(lf)) needredraw = B_TRUE; } - } else if (id == SK_SEWING) { - if (f->val[1] == PR_SKILLED) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL, FROMSKILL); - } - } else if (f->val[1] == PR_MASTER) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL, FROMSKILL); - } - } - } else if (id == SK_SHIELDS) { - if (f->val[1] == PR_BEGINNER) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_SHIELDBASH, NA, NA, NULL, FROMSKILL); - } } else if (id == SK_TECHUSAGE) { if (isplayer(lf)) { objecttype_t *ot; @@ -11704,20 +11587,6 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { } } } - } else if (id == SK_TWOWEAPON) { - if (f->val[1] == PR_EXPERT) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_FLURRY, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_FLURRY, NA, NA, "pw:1;", FROMSKILL); - } - } - } else if (id == SK_UNARMED) { - if (f->val[1] == PR_EXPERT) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_FLIP, NA, NA, NULL); - if (!newf) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_FLIP, NA, NA, NULL, FROMSKILL); - } - } } else if (id == SK_SS_ALLOMANCY) { // give all allomantic spells //mayusespellschool(lf->flags, SS_ALLOMANCY, F_CANCAST , B_FALSE); @@ -11731,22 +11600,6 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { } - if (isweaponskill(id)) { - if (f->val[1] == PR_BEGINNER) { - if (!hasflagval(lf->flags, F_CANWILL, OT_A_EXPOSEDSTRIKE, NA, NA, NULL)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_EXPOSEDSTRIKE, NA, NA, NULL, FROMSKILL); - } - } else if (f->val[1] == PR_ADEPT) { - if (!hasflagval(lf->flags, F_CANWILL, OT_A_ALTERATTACK, NA, NA, NULL)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_ALTERATTACK, NA, NA, NULL, FROMSKILL); - } - } else if (f->val[1] == PR_MASTER) { - if (!hasflagval(lf->flags, F_CANWILL, OT_A_COMBOSTRIKE, NA, NA, NULL)) { - newf = addtempflag(lf->flags, F_CANWILL, OT_A_COMBOSTRIKE, NA, NA, NULL, FROMSKILL); - } - } - } - // announecments based on skill level if ( (gamemode == GM_GAMESTARTED) && isplayer(lf)) { int i; @@ -12287,6 +12140,15 @@ job_t *hasjob(lifeform_t *lf, enum JOB job) { return j; } +int hasjobcat(lifeform_t *lf, enum JOBCATEGORY jcid) { + job_t *j = NULL; + j = getjob(lf); + if (j && (j->category == jcid)) { + return B_TRUE; + } + return B_FALSE; +} + int hastempinjuries(lifeform_t *lf) { flag_t *retflag[MAXCANDIDATES]; int nretflags,i,count = 0; @@ -12298,6 +12160,7 @@ int hastempinjuries(lifeform_t *lf) { return count; } +/* int hassubjob(lifeform_t *lf, enum SUBJOB id) { flag_t *f; f = lfhasflag(lf, F_JOB); @@ -12306,6 +12169,7 @@ int hassubjob(lifeform_t *lf, enum SUBJOB id) { } return B_FALSE; } +*/ int hassoul(lifeform_t *lf) { switch (getraceclass(lf)) { @@ -12878,7 +12742,7 @@ int lfproduceslight(lifeform_t *lf, object_t **fromwhat) { if (fromwhat) *fromwhat = NULL; // lf producing light itself? - sumflags(lf->flags, F_PRODUCESLIGHT, &temp, NULL, NULL); + getmaxflags(lf->flags, F_PRODUCESLIGHT, &temp, NULL, NULL); if (temp) radius = temp; // objects in hands or on body... @@ -12933,12 +12797,7 @@ int lockpick(lifeform_t *lf, cell_t *targcell, object_t *target, object_t *devic int nposs = 0,i; if (!targcell) { int dir; - ch = askchar("Lockpick in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if ((ch == '-') || (ch == '\0')) { - msg("Cancelled."); - return B_TRUE; - } - dir = chartodir(ch); + dir = askdir("Lockpick in which direction (- to cancel)", B_TRUE, B_FALSE); if (dir == D_NONE) { targcell = lf->cell; } else { @@ -13947,9 +13806,11 @@ int ispeaceful(lifeform_t *lf) { return B_TRUE; } int isknownpeaceful(lifeform_t *lf) { + if (ispetof(lf, player)) return B_TRUE; + if ((getlorelevel(player, getraceclass(lf)) >= PR_NOVICE) || (getskill(player, SK_SPEECH)) ) { - return B_FALSE; + return B_TRUE; } return ispeaceful(lf); } @@ -14119,7 +13980,7 @@ poisontype_t *addpoisontype(enum POISONTYPE id, char *name, char *desc, char *co return a; } -job_t *addjob(enum JOB id, char *name, char *desc) { +job_t *addjob(enum JOB id, char *name, char *desc, enum JOBCATEGORY category) { job_t *a; // add to the end of the list @@ -14141,6 +14002,7 @@ job_t *addjob(enum JOB id, char *name, char *desc) { a->id = id; a->name = strdup(name); a->desc = strdup(desc); + a->category = category; a->flags = addflagpile(NULL, NULL); return a; @@ -14385,6 +14247,33 @@ raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum return a; } +void addskillabil(enum SKILL id, enum SKILLLEVEL lev, enum OBTYPE abilid, int timeout, char *text, int announce) { + skill_t *sk; + sk = findskill(id); + assert(sk); + + if (announce) { + objecttype_t *ot; + char buf[BUFLEN]; + ot = findot(abilid); + assert(ot); + sprintf(buf, "^gYou gain the '%s' ability.^n", ot->name); + addskilldesc(sk->id, lev, buf, B_FALSE); + } + + sk->skillwill[sk->nskillwills].lev = lev; + sk->skillwill[sk->nskillwills].abilid = abilid; + sk->skillwill[sk->nskillwills].timeout = timeout; + if (text) { + sk->skillwill[sk->nskillwills].text = strdup(text); + } else { + sk->skillwill[sk->nskillwills].text = NULL; + } + sk->nskillwills++; + + +} + skill_t *addskill(enum SKILL id, char *name, char *desc, int traintime) { skill_t *a,*temp; int count = 0; @@ -14421,6 +14310,7 @@ skill_t *addskill(enum SKILL id, char *name, char *desc, int traintime) { a->desc = strdup(desc); a->traintime = traintime; a->nskilldesc = 0; + a->nskillwills = 0; return a; } @@ -14435,6 +14325,7 @@ void addskilldesc(enum SKILL id, enum SKILLLEVEL lev, char *text, int wantmsg) { sk->nskilldesc++; } +/* subjob_t *addsubjob(enum SUBJOB id, char *name, char *desc, char letter) { subjob_t *a; @@ -14461,6 +14352,7 @@ subjob_t *addsubjob(enum SUBJOB id, char *name, char *desc, char letter) { return a; } +*/ object_t *addtrail(lifeform_t *lf, cell_t *where, int dir, int doprints, int doscents) { object_t *footprint, *scent,*retob = NULL; @@ -15130,6 +15022,20 @@ int attrincreasable(enum ATTRIB a) { return B_FALSE; } +void autolearnspellsfrombook(lifeform_t *lf, object_t *book) { + object_t *o; + for (o = book->contents->first ; o ; o = o->next) { + if ((getspellschoolknown(lf, o->type->id) != SS_NONE) && + !hasflagval(lf->flags, F_CANCAST, o->type->id, NA, NA, NULL) && + (getspellpower(lf, o->type->id) > 0)) { + addtempflag(lf->flags, F_CANCAST, o->type->id, NA, NA, NULL, FROMJOB); + if (isplayer(lf)) { + addtempflag(lf->flags, F_SHORTCUT, getnextshortcut(lf), NA, NA, o->type->name, FROMJOB); + } + } + } +} + void autoshortcut(lifeform_t *lf, enum OBTYPE spellid) { flag_t *retflag[MAXCANDIDATES],*f; int nretflags,i,found = B_FALSE; @@ -15183,7 +15089,11 @@ void autoskill(lifeform_t *lf) { if (isweapon(o)) { sk = getobskill(o->flags); if (sk && !getskill(lf, sk->id)) { - giveskilllev(lf, sk->id, slev); + if ((sk->id == SK_SHORTBLADES) && hasjob(lf, J_DRUID)) { + // special case. + } else { + giveskilllev(lf, sk->id, slev); + } } // monsters:increase stats to match attribn requirements for starting @@ -15472,13 +15382,12 @@ enum FLAG iswoozy(lifeform_t *lf) { return F_NONE; } -// check if this job/subjob is possible -int jobpossible(flagpile_t *basefp, enum JOB jid, enum SUBJOB sjid) { +// check if this job is possible +int jobpossible(flagpile_t *basefp, enum JOB jid) { int ok = B_FALSE; job_t *j; flagpile_t *fp; - fp = addflagpile(NULL, NULL); // take lifeform/race's alignment restrictions @@ -15490,8 +15399,10 @@ int jobpossible(flagpile_t *basefp, enum JOB jid, enum SUBJOB sjid) { copyflag(fp, j->flags, F_ALIGNMENT); } + /* // take subjob's alignment restrictions add_subjob_alignment_restrictions(fp, sjid); + */ if (genalignmentlist(fp, NULL)) { ok = B_TRUE; } @@ -15583,6 +15494,7 @@ void killrace(race_t *r) { } } +/* void killsubjob(subjob_t *sj) { subjob_t *nextone, *lastone; @@ -15594,12 +15506,12 @@ void killsubjob(subjob_t *sj) { nextone = sj->next; if (nextone != NULL) { nextone->prev = sj->prev; - } else { /* last */ + } else { // last lastsubjob = sj->prev; } if (sj->prev == NULL) { - /* first */ + // first nextone = sj->next; free(firstsubjob); firstsubjob = nextone; @@ -15609,6 +15521,7 @@ void killsubjob(subjob_t *sj) { lastone->next = nextone; } } +*/ flag_t *levelabilityready(lifeform_t *lf) { flag_t *f; @@ -16003,7 +15916,9 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // replace 'the' at start of damsrc with 'a' if (strstr(damsrc, "the ") == damsrc) { - snprintf(buf, BUFLEN, "a %s", (damsrc+4)); + int an; + an = needan(damsrc+4); + snprintf(buf, BUFLEN, "%s %s",an ? "an" : "a", (damsrc+4)); } else { strcpy(buf, damsrc); } @@ -16165,22 +16080,22 @@ void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fr 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, B_FALSE, NULL, B_NOCENTRE); + spellcloud(lf->cell, 1, DT_COMPASS, UNI_SHADELIGHT, C_MAGENTA, OT_S_SLEEP, 8, B_TRUE, buf, buf2, B_FALSE, NULL, B_NOCENTRE); } else if (lf->race->id == R_FUNGUSPETRIFY) { char buf2[BUFLEN]; sprintf(buf, "^w%s releases a cloud of grey spores!", lfname); sprintf(buf2, "^wSomething releases a cloud of grey spores!"); - spellcloud(lf->cell, 3, UNI_SHADELIGHT, C_GREY, OT_S_PETRIFY, 5, B_TRUE, buf, buf2, B_FALSE, NULL, B_NOCENTRE); + spellcloud(lf->cell, 1, DT_COMPASS, UNI_SHADELIGHT, C_GREY, OT_S_PETRIFY, 5, B_TRUE, buf, buf2, B_FALSE, NULL, B_NOCENTRE); } 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, B_FALSE, NULL, B_NOCENTRE); + spellcloud(lf->cell, 1, DT_COMPASS, UNI_SHADELIGHT, C_RED, OT_A_RAGE, 8, B_TRUE, buf, buf2, B_FALSE, NULL, B_NOCENTRE); } else if ((lf->race->id == R_UNYON) && ((damtype == DT_SLASH) || (damtype == DT_CHOP))) { char buf2[BUFLEN]; sprintf(buf, "^w%s releases a cloud of fumes!", lfname); sprintf(buf2, "^wSomething releases a cloud of fumes!"); - spellcloud(lf->cell, 2, UNI_SHADELIGHT, C_GREY, OT_S_BLINDNESS, 8, B_TRUE, buf, buf2, B_TRUE, NULL, B_NOCENTRE); + spellcloud(lf->cell, 2, DT_ORTH, UNI_SHADELIGHT, C_GREY, OT_S_BLINDNESS, 8, B_TRUE, buf, buf2, B_TRUE, NULL, B_NOCENTRE); } @@ -16319,6 +16234,34 @@ void losemp(lifeform_t *lf, int amt) { } } +void loseskill(lifeform_t *lf, enum SKILL skid) { + flag_t *f; + skill_t *sk; + int i; + + sk = findskill(skid); + assert(sk); + + f = lfhasflagval(lf, F_HASSKILL, skid, NA, NA, NULL); + if (f) { + killflag(f); + } + // now lose any skills which came from this. + for (i = 0; i < sk->nskillwills; i++) { + int nretflags,n; + flag_t *retflag[MAXCANDIDATES]; + getflags(lf->flags, retflag, &nretflags, F_CANWILL, F_NONE); + for (n = 0; n < nretflags; n++) { + f = retflag[n]; + if ((f->val[0] == sk->skillwill[i].abilid) && (f->lifetime == FROMSKILL) && + (f->skillfrom == sk) ) { + killflag(f); + continue; + } + } + } +} + void magicwoods_warn(lifeform_t *who) { if (isplayer(who)) { msg("^wYou sense anger from the woods around you..."); @@ -16459,6 +16402,7 @@ int makelearnable(lifeform_t *lf, enum SKILL skid) { return B_FALSE; } +// returns TRUE on failure. int makenauseated(lifeform_t *lf, int amt, int howlong) { flag_t *f; @@ -16482,6 +16426,12 @@ int makenauseated(lifeform_t *lf, int amt, int howlong) { //if (!lfhasflag(lf, F_HUMANOID)) return B_TRUE; + // skillcheck to avoid this. + if (skillcheck(lf, SC_CON, 80 + (amt*10), gettr(lf)*2)) { + return B_TRUE; + } + + // already nauseated? f = lfhasflag(lf, F_NAUSEATED); if (f) { if ((f->lifetime >= 0) && (f->lifetime < howlong)) { @@ -16710,8 +16660,25 @@ int mightflee(lifeform_t *lf) { } -int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) { +// returns F_NEEDOBFORSPELLS flag if the lifeform is missing an object which they +// need for spellcasting. If the lf has everything needed to cast spells +// OR simply can't cast spells, it returns NULL. +// +flag_t *missingspellcastob(lifeform_t *lf) { + flag_t *f; + f = lfhasflag(lf, F_NEEDOBFORSPELLS); + if (f) { + if ((f->val[0] != NA) && !hasob(lf->pack, f->val[0])) { + return f; + } + if ((f->val[1] != NA) && !hasobwithflag(lf->pack, f->val[1])) { + return f; + } + } + return B_FALSE; +} +int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) { if (isplayer(lf)) { statdirty = B_TRUE; } @@ -16974,6 +16941,25 @@ int movecausesnoise(lifeform_t *lf) { return B_TRUE; } +int movesrandomly(lifeform_t *lf) { + flag_t *f; + int rndmove = B_FALSE; + f = lfhasflag(lf, F_DRUNK); + if (f) { + if (!hasjob(lf, J_PIRATE)) { + if (rnd(1,6) <= ((f->lifetime/TM_DRUNKTIME)+1)) { + // randomize move + rndmove = B_TRUE; // ie. you can walk into walls now. + } + } + } else if (iswoozy(lf)) { + rndmove = B_TRUE; + } else if (lfhasflagval(lf, F_INJURY, IJ_TAILBRUISED, NA, NA, NULL) && onein(6)) { + rndmove = B_TRUE; + } + return rndmove; +} + int needstobreath(lifeform_t *lf) { if (lfhasflag(lf, F_NOBREATH)) { return B_FALSE; @@ -17057,7 +17043,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, } else if ((nclass == NC_FIGHTING) && isplayer(l) && (dist <= 1)) { // players never hear fighting unless it's a small distance away // this prevents "you hear fighting" when you are attacked from behind. - difficulty = 9999; + difficulty = D_ALWAYSFAIL; } else { //difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20); difficulty = (int) ( ((float) dist / ((float)gethearingrange(l) + volume)) * 75); @@ -17886,7 +17872,11 @@ void precalclos(lifeform_t *lf) { assert(numpixels < MAXRETCELLS); // keep going until we lose los for (n = 0; keepgoing && (n < numpixels); n++) { + cell_t *nextc = NULL; c = retcell[n]; + if (n < numpixels-1) { + nextc = retcell[n+1]; + } if (n != 0) currange++; if (currange > maxvisrange) c = NULL; if (c) { @@ -17909,7 +17899,7 @@ void precalclos(lifeform_t *lf) { litforus = celllitfor(lf, c, maxvisrange, nightvisrange); */ - if (!celltransparentfor(lf, c, &xray, &rangemod)) { + if (!celltransparentfor(lf, c, &xray, &rangemod, nextc)) { keepgoing = B_FALSE; } currange += rangemod; @@ -18296,9 +18286,11 @@ void spot_hiding_lf(lifeform_t *lf, lifeform_t *hider) { getlfname(hider, hidername); msg("^wYou spot %s!", hidername); } else if (isplayer(hider) && cansee(hider, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("You think %s has spotted you!", lfname); + if (getlorelevel(hider, lf->race->raceclass->id)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("You think %s has spotted you!", lfname); + } } practice(lf, SK_PERCEPTION, 1); } @@ -18352,7 +18344,7 @@ int startclimbing(lifeform_t *lf) { if (pit) { int diff; // move there. - movelf(lf, where); + movelf(lf, where, B_TRUE); // make a skill check. //mod = (countadjwalls(where)+1)/2; diff = getcellclimbdifficultyavg(where); @@ -18363,7 +18355,7 @@ int startclimbing(lifeform_t *lf) { } else { // you will fall... if (isplayer(lf)) { - msg("You lose your footing!"); + msg("^bYou lose your footing!"); } } } else if (obstacle) { @@ -18379,20 +18371,20 @@ int startclimbing(lifeform_t *lf) { msg("%s climbs out of view.", lfname); } } - movelf(lf, where); + movelf(lf, where, B_TRUE); practice(lf, SK_CLIMBING, 1); } else { cell_t *c2; if (isplayer(lf)) { - msg("You try to climb onto %s, but lose your footing!", obname); + msg("^wYou try to climb onto %s, but lose your footing!", obname); } else if (cansee(player, lf)) { msg("%s tries to start climbing, but slips.", lfname); } c2 = getrandomadjcell(where, WE_WALKABLE, B_NOEXPAND); if (c2) { - movelf(lf, c2); - fall(lf, NULL, B_TRUE); + movelf(lf, c2, B_TRUE); } + fall(lf, NULL, B_TRUE); // fall return B_TRUE; } @@ -18417,7 +18409,7 @@ int startclimbing(lifeform_t *lf) { // change facing BEFORE moving, so that we don't reveal cells on the other // side of the wall setfacing(lf, diropposite(lf->facing)); - movelf(lf, where); + movelf(lf, where, B_TRUE); addflag(lf->flags, F_CLIMBING, B_TRUE, NA, NA, NULL); } else { if (isplayer(lf)) { @@ -18588,7 +18580,7 @@ int safetorest(lifeform_t *lf) { reason = E_OK; for (l = lf->cell->map->lf ; l ; l = l->next) { - if ((l != lf) && (areenemies(lf, l) || !isknownpeaceful(lf) ) && + if ((l != lf) && (areenemies(lf, l) || !isknownpeaceful(l) ) && !lfhasflag(l, F_HARMLESS) && !lfhasflag(l, F_FEIGNINGDEATH)) { int monsternearby = B_FALSE; @@ -18759,6 +18751,27 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t } rv = say(lf, buf, volume); break; + case SP_CLOSEDTILMORN: + switch (rnd(1,2)) { + case 1: snprintf(buf, BUFLEN, "We're closed, come back in the morning!"); break; + case 2: snprintf(buf, BUFLEN, "Sorry, we're only open during daylight hours."); break; + } + rv = say(lf, buf, volume); + break; + case SP_CLOSEDTILNIGHT: + switch (rnd(1,2)) { + case 1: snprintf(buf, BUFLEN, "We're closed, come back in the evening!"); break; + case 2: snprintf(buf, BUFLEN, "Sorry, we're only open during nighttime hours."); break; + } + rv = say(lf, buf, volume); + break; + case SP_CLOSEDTILTIME: + switch (rnd(1,2)) { + case 1: snprintf(buf, BUFLEN, "We're closed, come back at %d o'clock.", val0); break; + case 2: snprintf(buf, BUFLEN, "Sorry, we're closed until %d o'clock.", val0); break; + } + rv = say(lf, buf, volume); + break; case SP_DIE: switch (rnd(1,4)) { case 1: @@ -19957,7 +19970,7 @@ int getskillcheckchance(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod) { attrib = getattr(lf, A_CON)/5; break; case SC_DISARM: - attrib = (getskill(lf, SK_TRAPS)*3); + attrib = (getskill(lf, SK_ENGINEERING)*3); if (attrib) { attrib += (getattr(lf, A_AGI)/20); } @@ -20195,7 +20208,7 @@ int modskillcheckroll(lifeform_t *lf, enum CHECKTYPE ct, int *roll) { attrib = getattr(lf, A_CON); break; case SC_DISARM: - attrib = (getskill(lf, SK_TRAPS)*15); + attrib = (getskill(lf, SK_ENGINEERING)*15); if (attrib) { attrib += (getattr(lf, A_AGI)/3); } @@ -20372,7 +20385,7 @@ int modskillcheckroll(lifeform_t *lf, enum CHECKTYPE ct, int *roll) { *roll += (othermod); // auto fail... - if (isimmobile(lf) || lfhasflag(lf, F_DOESNTMOVE)) { + if (isimmobile(lf) || lfhasflag(lf, F_DOESNTMOVE) || !getstamina(lf)) { switch (ct) { case SC_CLIMB: case SC_DODGE: @@ -20451,26 +20464,33 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r ////////////////////////////////////// // debugging for new skillcheck code - dblog("%s difficulty %d, mod %d",dbtag, diff, mod); + if (lfhasflag(lf, F_DEBUG)) dblog("%s difficulty %d, mod %d",dbtag, diff, mod); ////////////////////////////////////// + if (diff == D_ALWAYSFAIL) { + // fail. + if (result) *result = -1; + if (lfhasflag(lf, F_DEBUG)) dblog("%s autofail as difficulty is D_ALWAYSFAIL.",dbtag); + return B_FALSE; + } + //pct = getskillcheckchance(lf, ct, diff, mod); // higher roll is better roll = rnd(1,100); // debugging for new skillcheck code - dblog("%s initial roll=%d",dbtag,roll); + if (lfhasflag(lf, F_DEBUG)) dblog("%s initial roll=%d",dbtag,roll); ////////////////////////////////////// roll += mod; - dblog("%s +mod(%d) = %d",dbtag,mod,roll); + if (lfhasflag(lf, F_DEBUG)) dblog("%s +mod(%d) = %d",dbtag,mod,roll); modskillcheckroll(lf, ct, &roll); - dblog("%s +other_factors = %d",dbtag,roll); + if (lfhasflag(lf, F_DEBUG)) dblog("%s +other_factors = %d",dbtag,roll); if (db) { msg("%s: %s check, rolled %d, need >= %d. (%s)",lf->race->name, getskillcheckname(ct), roll,diff, (roll >= diff) ? "PASS" : "fail"); } - dblog("%s === rolled %d, need >= %d. (%s)",dbtag,roll,diff, (roll >= diff) ? "PASS" : "fail"); + if (lfhasflag(lf, F_DEBUG)) dblog("%s === rolled %d, need >= %d. (%s)",dbtag,roll,diff, (roll >= diff) ? "PASS" : "fail"); if (result) { *result = roll; @@ -20549,9 +20569,14 @@ int slipon(lifeform_t *lf, object_t *o) { snprintf(damstring, BUFLEN, "slipping on %s",obname); losehp(lf, 1, DT_FALL, NULL, damstring); } + noise(lf->cell, lf, NC_OTHER, SV_TALK, "a thump.", NULL); fall(lf, NULL, B_FALSE); + if (isplayer(lf)) { + real_warnabout("(use 's' to walk carefully)", PERMENANT, B_FALSE); + } + // object gets damaged? if (hasflag(o->flags, F_DAMAGABLE)) { takedamage(o, 1, DT_DIRECT, NULL); @@ -20701,7 +20726,7 @@ void startlfturn(lifeform_t *lf) { c = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND); } // move lf out! - movelf(lf, c); + movelf(lf, c, B_FALSE); if (isplayer(lf)) { msg("You get expelled from %s!", sf->text); } else if (cansee(player, lf)) { @@ -20802,6 +20827,8 @@ void startlfturn(lifeform_t *lf) { if (checkfordrowning(lf, o)) { if (isdead(lf)) return; } + // fixes stench + killtransitoryflags(lf->flags, F_STENCH); } else { // amulet of swimming? if (hasequippedobid(lf->pack, OT_AMU_SWIMMING) && (lf->race->id == R_SWAN) && ispolymorphed(lf)) { @@ -20874,7 +20901,6 @@ void startlfturn(lifeform_t *lf) { } } - // oooooo replace with f_bleeding ? if (lfhasflagval(lf, F_INJURY, IJ_ARTERYPIERCE, NA, NA, NULL)) { if (!bleedfrom(lf, BP_HANDS, B_SPLATTER)) { @@ -21367,9 +21393,18 @@ void startlfturn(lifeform_t *lf) { for (i = 0; i < lf->nlos; i++) { if (!lf->los[i]->lf || (lf->los[i]->lf == lf)) { object_t *o; - int distmod; - distmod = getcelldist(lf->cell, lf->los[i]); + int distmod,distance; + + distance = getcelldist(lf->cell, lf->los[i]); + // can't spot things which are further away than your + // perception skill. + if (distance > getskill(lf, SK_PERCEPTION)) { + distmod = 400; // ie. almost impossible + } else { + distmod = distance * 20; + } limit(&distmod, 1, NA); + for (o = lf->los[i]->obpile->first; o ; o = o->next) { flag_t *f; int mod = 0; @@ -21378,9 +21413,15 @@ void startlfturn(lifeform_t *lf) { if (f && (f->val[0] != NA)) { int diff; if (hasflag(o->flags, F_TRAP)) { - mod += (getskill(lf, SK_TRAPS)*2); + enum SKILLLEVEL slev; + slev = getskill(lf, SK_ENGINEERING); + if (slev == PR_MASTER) { + mod += 500; // ie. autopass + } else { + mod += (slev*2); + } } - diff = f->val[0] + (distmod*15); + diff = f->val[0] + distmod; if (skillcheck(lf, SC_SEARCH, diff, mod)) { char obname[BUFLEN]; // reveal it @@ -21393,7 +21434,7 @@ void startlfturn(lifeform_t *lf) { // train skills practice(lf, SK_PERCEPTION, 1); if (hasflag(o->flags, F_TRAP)) { - practice(lf, SK_TRAPS, 1); + practice(lf, SK_ENGINEERING, 1); } } } @@ -21402,13 +21443,22 @@ void startlfturn(lifeform_t *lf) { if (f && (f->val[2] != B_TRUE) && !hasflag(o->flags, F_SECRET)) { objecttype_t *ot; flag_t *trapflag; + enum SKILLLEVEL slev; int diff; // find trap type ot = findot(f->val[0]); trapflag = hasflag(ot->flags, F_TRAP); assert(trapflag); - diff = trapflag->val[0] + (distmod*20); - mod += getskill(lf, SK_TRAPS); + diff = trapflag->val[0] + distmod; + + slev = getskill(lf, SK_ENGINEERING); + if (slev == PR_MASTER) { + mod += 500; // ie. autopass + } else { + mod += (slev*2); + } + diff = trapflag->val[0] + distmod; + if (skillcheck(lf, SC_SEARCH, diff, mod)) { char obname[BUFLEN]; // reveal it @@ -21421,7 +21471,7 @@ void startlfturn(lifeform_t *lf) { // train skills practice(lf, SK_PERCEPTION, 1); if (hasflag(o->flags, F_TRAP)) { - practice(lf, SK_TRAPS, 1); + practice(lf, SK_ENGINEERING, 1); } } @@ -21784,6 +21834,7 @@ void startlfturn(lifeform_t *lf) { // effects from cell objects? for (o = lf->cell->obpile->first ; o ; o = nexto) { + int amt; nexto = o->next; if (bloodamu && (o->material->id == MT_BLOOD)) { int amt; @@ -21819,6 +21870,20 @@ void startlfturn(lifeform_t *lf) { losehp(lf, rnd(10,20), DT_HOLY, NULL, "a holy circle"); } } + if (o->type->id == OT_PENTAGRAM) { + if (isundead(lf) && (lf->hp < lf->maxhp)) { + char obname[BUFLEN]; + getobname(o, obname, 1); + if (isplayer(lf)) { + msg("^%c%s heals you!^n", getlfcol(lf, CC_GOOD), obname); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("^%c%s heals %s!^n", getlfcol(lf, CC_GOOD), obname, lfname); + } + gainhp(lf, rnd(1,6)); + } + } /* f = hasflag(o->flags, F_GODSTONE); @@ -21838,16 +21903,16 @@ void startlfturn(lifeform_t *lf) { applywalkdam(lf, roll(f->text), f->val[0], o, BP_NONE); } - f = hasflag(o->flags, F_PRODUCESLIGHT); - if (f) { - if (lfhasflag(lf, F_SEEINDARK)) { + amt = obproduceslight(o); + if (amt) { + if (lfhasflag(lf, F_SEEINDARK) && !isblind(lf)) { // if you don't have eyes, your'e safe! if (!lfhasflagval(lf, F_NOBODYPART, BP_EYES, NA, NA, NULL)) { if (isplayer(lf)) { msg("The bright light burns your vision-enhanced eyes!"); } // blind for 1-3 turns - addtempflag(lf->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(3,3+f->val[0])); + addtempflag(lf->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(3,3+amt)); } } if (isvulnto(lf->flags, DT_LIGHT, B_FALSE)) { @@ -21855,7 +21920,7 @@ void startlfturn(lifeform_t *lf) { char obname[BUFLEN],damstring[BUFLEN]; // note: amt will be doubled due to light vulnerability, // so half it here. - dam = f->val[0]/2; + dam = amt/2; limit(&dam, 1, NA); getobnametruebase(o, obname, o->amt); @@ -21989,7 +22054,7 @@ void startlfturn(lifeform_t *lf) { } if (f->id == F_HIDING) { - if (lfhasflag(lf, F_SPRINTING) || lfhasflag(lf, F_PRODUCESLIGHT)) { + if (lfhasflag(lf, F_SPRINTING) || lfproduceslight(lf, NULL)) { killflag(f); continue; } @@ -22362,7 +22427,7 @@ int stopclimbing(lifeform_t *lf, int onpurpose) { return B_TRUE; } } - movelf(lf, c); + movelf(lf, c, onpurpose); killflagsofid(lf->flags, F_CLIMBING); if (onpurpose) { if (isplayer(lf)) msg("You drop down to the ground."); @@ -22640,7 +22705,7 @@ void timeeffectslf(lifeform_t *lf) { int dir; // make SURE we don't take any time! - notime = B_TRUE; + notime = B_MAYBE; // decrement flags timeeffectsflags(lf->flags); @@ -22970,7 +23035,7 @@ int real_touch(lifeform_t *lf, object_t *o, int onpurpose) { } if (!safe) { if (isplayer(lf)) { - msg("^bThe %s burn%s you as you touch %s!",noprefix(obname), + msg("^b%s %s burn%s you as you touch %s!",isequipped(o) ? "Your" : "The", noprefix(obname), OBS1(o), OB1(o, "it", "them") ) ; o->blessknown = B_TRUE; } else if (cansee(player, lf)) { @@ -23586,7 +23651,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { // straight back down! if (hasflag(o->flags, F_PIT) && (dir == D_UP) && !isairborne(lf)) { cell_t *noholecell; - noholecell = real_getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, NULL ); + noholecell = real_getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, NULL, MT_NOTHING); if (noholecell) { // go here instead newcell = noholecell; @@ -23631,7 +23696,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { if (!initiatemove(adjally[n], NULL, B_TRUE, NULL)) { int climbtime; stopsprinting(adjally[n]); - movelf(adjally[n], c); + movelf(adjally[n], c, B_TRUE); climbtime = getmovespeed(adjally[n]); if ((dir == D_UP) && !isairborne(adjally[n])) { climbtime *= 2; @@ -25253,6 +25318,19 @@ int weild(lifeform_t *lf, object_t *o) { return B_FALSE; } +enum SKILLLEVEL whichlevforabil(enum SKILL skid, enum OBTYPE oid) { + int i; + skill_t *sk; + sk = findskill(skid); + assert(sk); + for (i = 0; i < sk->nskillwills; i++) { + if (sk->skillwill[i].abilid == oid) { + return sk->skillwill[i].lev; + } + } + return PR_INEPT; +} + int willbackstab(lifeform_t *lf, lifeform_t *victim, object_t *wep) { if (getraceclass(victim) == RC_PLANT) return B_FALSE; diff --git a/lf.h b/lf.h index 68ea075..1f91ad8 100644 --- a/lf.h +++ b/lf.h @@ -1,16 +1,17 @@ #include "defs.h" -void add_subjob_alignment_restrictions(flagpile_t *fp, enum SUBJOB sj); +//void add_subjob_alignment_restrictions(flagpile_t *fp, enum SUBJOB sj); void addbodypart(race_t *r, enum BODYPART bp, char *name); lifeform_t *addlf(cell_t *cell, enum RACE rid, int level); lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller); poisontype_t *addpoisontype(enum POISONTYPE id, char *name, char *desc, char *contracttext, char *damverb, enum OBTYPE vomitob, int dam, int dampct, enum POISONSEVERITY severity, int incubationtime); -job_t *addjob(enum JOB id, char *name, char *desc); +job_t *addjob(enum JOB id, char *name, char *desc, enum JOBCATEGORY category); race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcolour, enum MATERIAL mat, enum RACECLASS raceclass, char *desc); raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill); skill_t *addskill(enum SKILL id, char *name, char *desc, int traintime); +void addskillabil(enum SKILL id, enum SKILLLEVEL lev, enum OBTYPE abilid, int timeout, char *text, int announce); void addskilldesc(enum SKILL id, enum SKILLLEVEL lev, char *text, int wantmsg); -subjob_t *addsubjob(enum SUBJOB id, char *name, char *desc, char letter); +//subjob_t *addsubjob(enum SUBJOB id, char *name, char *desc, char letter); object_t *addtrail(lifeform_t *lf, cell_t *where, int dir, int doprints, int doscents); void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype); void adjustspeedforwater(lifeform_t *lf, int *speed); @@ -25,6 +26,7 @@ int askforinfo(lifeform_t *lf, int diffmod); //int askforpayment(lifeform_t *shk, lifeform_t *lf); char *assignnpcname(flagpile_t *fp); int attrincreasable(enum ATTRIB a); +void autolearnspellsfrombook(lifeform_t *lf, object_t *book); void autoshortcut(lifeform_t *lf, enum OBTYPE spellid); void autoskill(lifeform_t *lf); void autospells(lifeform_t *lf, int howmany); @@ -42,6 +44,7 @@ int calcxp(lifeform_t *lf); int calcxprace(enum RACE rid); void callguards(lifeform_t *caller, lifeform_t *victim); int canattack(lifeform_t *lf); +int canbuild(lifeform_t *lf, objecttype_t *ot, char *needtext, enum OBTYPE *needob, int *numneed); int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost); int cancook(lifeform_t *lf, recipe_t *rec, enum ERROR *reason); int canclimb(lifeform_t *lf, enum ERROR *reason); @@ -69,7 +72,7 @@ int cantakeoff(lifeform_t *lf, object_t *o); int cantalk(lifeform_t *lf); int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell, object_t *fromob, int *seen); int celllitfor(lifeform_t *lf, cell_t *c, int maxvisrange, int nightvisrange); -int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod); +int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod, cell_t *nextcell); int charmedaction(lifeform_t *lf, flag_t *charmflag); int checkburdened(lifeform_t *lf, int preburdened); int checkfordrowning(lifeform_t *lf, object_t *o); @@ -124,8 +127,8 @@ raceclass_t *findraceclass(enum RACECLASS id); skill_t *findskill(enum SKILL id); skill_t *findskillbyname(char *name); enum SKILLLEVEL findskilllevbyname(char *name); -subjob_t *findsubjob(enum SUBJOB sjid); -subjob_t *findsubjobbyletter(char letter); +//subjob_t *findsubjob(enum SUBJOB sjid); +//subjob_t *findsubjobbyletter(char letter); int fixcurses(lifeform_t *lf); int flee(lifeform_t *lf); void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong, int onpurpose); @@ -160,6 +163,8 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, /*@null@*/cha int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset); int getavgdam(lifeform_t *lf, int forxp); enum CASTTYPE getcasttype(lifeform_t *lf, enum OBTYPE sid); +int getdrunkattrmod(lifeform_t *lf, enum ATTRIB att, int drunkamt); +int getengineeringwallmod(lifeform_t *lf); float getequippedweight(lifeform_t *lf); int getevasion(lifeform_t *lf); object_t *getbestthrowmissile(lifeform_t *lf, lifeform_t *target); @@ -186,7 +191,8 @@ enum HUNGER gethungerlevel(int hunger); char *gethungername(lifeform_t *lf, enum HUNGER hunger, char *buf); int gethungerval(lifeform_t *lf); job_t *getjob(lifeform_t *lf); -enum SUBJOB getsubjob(lifeform_t *lf); +enum JOBCATEGORY getjobcat(lifeform_t *lf); +//enum SUBJOB getsubjob(lifeform_t *lf); char *getjobname(lifeform_t *lf); int getlastdir(lifeform_t *lf); int getleftrightwalls(lifeform_t *lf); @@ -288,8 +294,8 @@ int getweapons(lifeform_t *lf, int meleeonly, object_t **wep, flag_t **damflag, enum SKILLLEVEL getweaponskill(lifeform_t *lf, object_t *o); long getxpforlev(int level); void givebehaviour(lifeform_t *lf, enum BEHAVIOUR bid); -void givejob(lifeform_t *lf, enum JOB jobid, enum SUBJOB sj); -void givesubjob(lifeform_t *lf, enum SUBJOB sj); +void givejob(lifeform_t *lf, enum JOB jobid); +//void givesubjob(lifeform_t *lf, enum SUBJOB sj); int givemoney(lifeform_t *from, lifeform_t *to, int amt); void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype); int giverandomobs(lifeform_t *lf, int amt); @@ -306,7 +312,8 @@ int hasfreeaction(lifeform_t *lf); int real_hasfreeaction(lifeform_t *lf, enum FLAG exception); int hashealableinjuries(lifeform_t *lf); job_t *hasjob(lifeform_t *lf, enum JOB job); -int hassubjob(lifeform_t *lf, enum SUBJOB id); +int hasjobcat(lifeform_t *lf, enum JOBCATEGORY jcid); +//int hassubjob(lifeform_t *lf, enum SUBJOB id); int hassoul(lifeform_t *lf); void inc_quad_range(enum QUADRANT *start, enum QUADRANT *end, int howmuch); int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJURY forcetype); @@ -382,12 +389,12 @@ flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt, int onlytemp); int isweaponbp(enum BODYPART bp); int isweaponskill(enum SKILL skid); enum FLAG iswoozy(lifeform_t *lf); -int jobpossible(flagpile_t *basefp, enum JOB jid, enum SUBJOB sjid); +int jobpossible(flagpile_t *basefp, enum JOB jid); void killjob(job_t *job); void killlf(lifeform_t *lf); void killpoisontype(poisontype_t *pt); void killrace(race_t *race); -void killsubjob(subjob_t *sj); +//void killsubjob(subjob_t *sj); flag_t *levelabilityready(lifeform_t *lf); int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo); int loadfirearmfast(lifeform_t *lf, int onpurpose); @@ -398,6 +405,7 @@ int losehp_bp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate, int *waskod, int doeffects, int bodypart); void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fromlf, object_t *fromob, int retaliate, int ko, int *waskod, int prelowhp, int bodypart); void losemp(lifeform_t *lf, int amt); +void loseskill(lifeform_t *lf, enum SKILL skid); void magicwoods_angry(lifeform_t *who); void magicwoods_warn(lifeform_t *who); void makefriendly(lifeform_t *lf, int howlong); @@ -411,6 +419,7 @@ void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how, int o int meetsallattreqs(lifeform_t *lf, object_t *o); int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o, int *modpct); int mightflee(lifeform_t *lf); +flag_t *missingspellcastob(lifeform_t *lf); int modattr(lifeform_t *lf, enum ATTRIB attr, int amt); void modhunger(lifeform_t *lf, int amt); float modifybystat(float num, lifeform_t *lf, enum ATTRIB att); @@ -418,6 +427,7 @@ void modmorale(lifeform_t *lf, int howmuch); int modskillcheckroll(lifeform_t *lf, enum CHECKTYPE ct, int *roll); void modstamina(lifeform_t *lf, float howmuch); int movecausesnoise(lifeform_t *lf); +int movesrandomly(lifeform_t *lf); int needstobreath(lifeform_t *lf); int needstorest(lifeform_t *lf, char *validchars); void noarmouron(race_t *r, enum BODYPART bp); @@ -509,6 +519,7 @@ int validateraces(void); void wakeup(lifeform_t *lf, int howmuch); int wear(lifeform_t *lf, object_t *o); int weild(lifeform_t *lf, object_t *o); +enum SKILLLEVEL whichlevforabil(enum SKILL skid, enum OBTYPE oid); int willbackstab(lifeform_t *lf, lifeform_t *victim, object_t *wep); int willbleedfrom(lifeform_t *lf, enum BODYPART bp); int willburden(lifeform_t *lf, object_t *o, int howmany); diff --git a/map.c b/map.c index feb72d8..2d3e1bd 100644 --- a/map.c +++ b/map.c @@ -133,7 +133,7 @@ void addhomeobs(lifeform_t *lf, int dolevelobs) { cell_t *c; o = addob(homeobloc->obpile, f->text); if (o && (homeobloc == lf->cell) && isimpassableob(o, lf, SZ_ANY)) { - c = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL); + c = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL, MT_NOTHING); if (c) { homeobloc = c; // future obs will go here too. moveob(o, homeobloc->obpile, o->amt); @@ -246,7 +246,6 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok int db = B_FALSE; flagpile_t *wantflags = NULL; enum JOB wantjob = J_NONE; - enum SUBJOB wantsubjob = SJ_NONE; enum BEHAVIOUR wantbehaviour = BH_NONE; if (nadded) *nadded = 0; @@ -274,7 +273,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok } else { //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging - rid = parserace(racename, wantflags, &wantjob, &wantsubjob, &wantbehaviour); + rid = parserace(racename, wantflags, &wantjob, &wantbehaviour); //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging if (rid == R_RANDOM) { @@ -340,8 +339,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok f = retflag[i]; // has a job? if (rnd(1,100) <= f->val[0]) { - job_t *j; - enum SUBJOB wantsubjob; + //job_t *j; if (f->val[1] == J_RANDOM) { job_t *j; j = getrandomjob(B_TRUE); @@ -349,40 +347,13 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok } else { wantjob = f->val[1]; } - // special case: wizards MUST have a subjob. - if (wantjob == J_WIZARD) { - wantsubjob = SJ_RANDOM; - } else { - wantsubjob = f->val[2]; - } - givejob(lf, wantjob, SJ_NONE); - - j = findjob(wantjob); - // subjob ? - if (j && (wantsubjob != NA)) { - // cope with random - if (wantsubjob == SJ_RANDOM) { - // find a subjob which applies - flag_t *retflag[MAXCANDIDATES]; - int nretflags; - - getflags(j->flags, retflag, &nretflags, F_CANHAVESUBJOB, F_NONE); - if (nretflags) { - givesubjob(lf, retflag[rnd(0,nretflags-1)]->val[0]); - } - } else { - givesubjob(lf, wantsubjob); - } - } + givejob(lf, wantjob); break; } } } } else { - givejob(lf, wantjob, SJ_NONE); - } - if (wantsubjob != SJ_NONE) { - givesubjob(lf, wantsubjob); + givejob(lf, wantjob); } generatealignment(lf); @@ -483,7 +454,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok lifeform_t *newlf; // find an adjacent cell to one of the newly added monsters, // starting with the first one - adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, NULL); + adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, NULL, MT_NOTHING); // did we find one? if (!adjcell) break; @@ -533,10 +504,10 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok enum RACE newrid; race_t *newr; - adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, NULL); + adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, NULL, MT_NOTHING); if (!adjcell) break; - newrid = parserace(f->text, NULL, NULL, NULL, NULL); + newrid = parserace(f->text, NULL, NULL, NULL); newr = findrace(newrid); if (!newr) break; @@ -1244,6 +1215,7 @@ int cellhaslos(cell_t *c1, cell_t *dest) { // you can always see your own cell if (i != 0) { + object_t *oo; // solid cells stop los - but if you are standing on a solid // cell you can still see out. cell = getcellat(map, x, y); @@ -1263,8 +1235,19 @@ int cellhaslos(cell_t *c1, cell_t *dest) { */ // check for objects which block view - if (hasobwithflag(cell->obpile, F_BLOCKSVIEW)) { - return B_FALSE; + oo = hasobwithflag(cell->obpile, F_BLOCKSVIEW); + if (oo) { + if (cell == c1) { + flag_t *f; + f = hasflag(oo->flags, F_BLOCKSVIEW); + if (f && (f->val[1] == B_TRUE)) { + // ok. + } else { + return B_FALSE; + } + } else { + return B_FALSE; + } } } @@ -1879,11 +1862,7 @@ int damagecell(cell_t *c, int amt, enum DAMTYPE damtype, lifeform_t *fromlf) { // returns true if something happened int doelementspread(cell_t *c) { - float thisdepth; - int i; - int nsurround = 0; - int db = B_FALSE; - cell_t *surroundcell[8]; + //int db = B_FALSE; object_t *fireob = NULL; if (!c || c->type->solid) { @@ -1891,7 +1870,13 @@ int doelementspread(cell_t *c) { } // calculate depth of this cell + /* DISABLED FOR NOW. if (!hascloseddoor(c)) { + float thisdepth; + int i; + int nsurround = 0; + cell_t *surroundcell[8]; + thisdepth = getcellwaterdepth(c, NULL); if (thisdepth) { @@ -1904,20 +1889,18 @@ int doelementspread(cell_t *c) { float newcdepth; int ok = B_FALSE; - /* - FIX THIS CODE LATER - if (newc->type->floorheight == c->type->floorheight) { - // same height - don't include these??? - ok = B_FALSE; - //ok = B_TRUE; - } else if (newc->type->floorheight < c->type->floorheight) { - // ie. downhill. don't include these - ok = B_FALSE; - } else if (newc->type->floorheight > c->type->floorheight) { - // ie. uphill. - ok = B_TRUE; - } - */ + //FIX THIS CODE LATER + //if (newc->type->floorheight == c->type->floorheight) { + // // same height - don't include these??? + // ok = B_FALSE; + // //ok = B_TRUE; + //} else if (newc->type->floorheight < c->type->floorheight) { + // // ie. downhill. don't include these + // ok = B_FALSE; + //} else if (newc->type->floorheight > c->type->floorheight) { + // // ie. uphill. + // ok = B_TRUE; + //} if (newc->type->floorheight == c->type->floorheight) { ok = B_TRUE; } else { @@ -1971,6 +1954,7 @@ int doelementspread(cell_t *c) { } } } + */ // fire fireob = hasobofmaterial(c->obpile, MT_FIRE); if (fireob && (fireob->birthtime != curtime) && !isdeadob(fireob)) { @@ -3311,7 +3295,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ // randomise dungeon parameters turnpct += (rnd(0,40)-20); // (-20 to +20)% sparseness += (rnd(0,20)-10); // -10 to +10 - looppct -= (rnd(0,10)); // subtrace 0 - 10 + looppct -= (rnd(0,10)); // subtract 0 - 10 if (shape == MS_NORMAL) { if (onein(2)) { @@ -3443,7 +3427,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ c = getcellat(map, x, y); if (!c->type->solid && countcellexits(c, DT_ORTH) == 1) { // dead end - maybe make loop from here - if (rnd(1,100) <= looppct) { + if (pctchance(looppct)) { int connected = B_FALSE; int loopok = B_TRUE; int dir; @@ -4216,14 +4200,14 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex if (db) dblog(" adding forced regionthing object: %s", thing[i]->what); c = getrandomroomcell(map, ANYROOM, WE_WALKABLE); if (!c) c = getrandomcell(map); - c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL); + c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL, MT_NOTHING); addob(c->obpile, thing[i]->what); break; case RT_LF: if (db) dblog(" adding forced regionthing lifeform: %s", thing[i]->what); c = getrandomroomcell(map, ANYROOM, WE_WALKABLE); if (!c) c = getrandomcell(map); - c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL); + c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL, MT_NOTHING); addmonster(c, R_SPECIFIED, thing[i]->what, B_FALSE, thing[i]->value, B_TRUE, NULL); break; case RT_BRANCHLINK: @@ -4240,6 +4224,16 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex } //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + // ensure that starting level has a player start position + if ((gamemode == GM_CHARGEN) && (region->rtype->id == BH_MAINDUNGEON)) { + cell_t *startpos; + startpos = findobinmap(map, OT_PLAYERSTART); + if (!startpos) { + dblog("ERROR - first level of main dungeon missing player start position."); + failed = B_TRUE; + } + } + // ensure there are no unreachable areas if (!failed) { if (fix_reachability(map)) { @@ -4402,6 +4396,21 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex } */ + // link up holes - this will create NEW holes in THIS map connecting to + // EXISTING unlinked holes in adjacent maps + // + // do this BEFORE linkind stairs, in case the act of linking holes generates the next map. + // if this happens then we want to also join up unlinked stairs. + // if we don't do this then when the player tries to use stairs, we will find + // that an existing map below/above exists but has no stairs linked, + // which isn't meant to happen. + i = linkholes(map); + if (db) { + if (db) dblog(" autolinked to %d holes in adjacent maps.",i); + } + //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + + //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging // try to join up any unlinked staircases in this map. if (db) dblog(" joining unlinked stairs..."); @@ -4435,13 +4444,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging - // link up holes - this will create NEW holes in THIS map connecting to - // EXISTING unlinked holes in adjacent maps - i = linkholes(map); - if (db) { - if (db) dblog(" autolinked to %d holes in adjacent maps.",i); - } - //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + // add random objects and monsters , and remove // bad objects @@ -6838,6 +6841,8 @@ cell_t *getcellindir(cell_t *cell, int dir) { case DC_NW: dt = DT_COMPASS; break; + case D_MYSELF: + return cell; default: return NULL; } @@ -6977,10 +6982,10 @@ int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved) { cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand) { - return real_getrandomadjcell(c, wantempty, allowexpand, LOF_NEED, NULL, NULL, NULL); + return real_getrandomadjcell(c, wantempty, allowexpand, LOF_NEED, NULL, NULL, NULL, MT_NOTHING); } -cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob, cell_t *dontwantcell, lifeform_t *preferlos) { +cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob, cell_t *dontwantcell, lifeform_t *preferlos, enum MATERIAL wantmat) { int radius = 1; int x,y; cell_t *poss[MAXCANDIDATES]; @@ -7014,6 +7019,11 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LO } } } + if (wantmat != MT_NOTHING) { + if (new->type->material->id != wantmat) { + ok = B_FALSE; + } + } if (ok) { if (preferlos && haslos(preferlos, new)) { @@ -7176,6 +7186,10 @@ int getslipperyness(cell_t *c, object_t **slipob) { if (slipob) *slipob = NULL; switch (c->type->id) { + case CT_MOSSROCK: + addition = 15; + pctmod += 50; + break; case CT_FLOORTILE: addition = 10; pctmod += 50; @@ -7199,12 +7213,13 @@ int getslipperyness(cell_t *c, object_t **slipob) { bestob = o; bestslip = thisslip; } - thisslip += pctof(pctmod, addition); + thisslip = pctof(pctmod, thisslip); thisslip *= o->amt; totalslip += thisslip; } } + totalslip += addition; //totalslip *= 2; if (slipob) { @@ -7301,6 +7316,16 @@ cell_t *getstairdestination(object_t *o, int *madenewmap) { return newcell; } +object_t *hasdoor(cell_t *c) { + object_t *o; + for (o = c->obpile->first ; o ; o = o->next) { + if (isdoor(o, NULL)) { + return o; + } + } + return NULL; +} + object_t *hasenterableobject(cell_t *c) { return hasobwithflag(c->obpile, F_CLIMBABLE); } @@ -7398,7 +7423,7 @@ void initmap(void) { addhabitat(H_HEAVEN, "heaven", CT_CORRIDOR, CT_WALLGLASS, 5, 0, 0, MAXVISRANGE, OT_NONE, OT_NONE); addhabitat(H_PIT, "pit", CT_CORRIDOR, CT_WALL, 0, 0, 0, 5, OT_NONE, OT_NONE); addhabitat(H_VILLAGE, "village", CT_GRASS, CT_WALL, 3, 70, 0, MAXVISRANGE, OT_NONE, OT_NONE); - addhabitat(H_SEWER, "sewer", CT_CORRIDOR, CT_WALL, 5, 50, 0, MAXVISRANGE, OT_GRATINGROOF, OT_NONE); + addhabitat(H_SEWER, "sewer", CT_MOSSROCK, CT_WALL, 5, 50, 0, MAXVISRANGE, OT_GRATINGROOF, OT_NONE); addhabitat(H_STOMACH, "stomach", CT_FLOORFLESH, CT_WALLFLESH, 5, 80, 0, MAXVISRANGE, OT_NONE, OT_NONE); addhabitat(H_SWAMP, "swamp", CT_CORRIDOR, CT_WALL, 3, 50, 0, MAXVISRANGE, OT_STAIRSUP, OT_STAIRSDOWN); addhabitat(H_BYHUT, "babayaga's hut", CT_FLOORWOOD, CT_WALLDWOOD, 0, 0, 0, MAXVISRANGE, OT_BYHUTDOOR, OT_NONE); @@ -7406,32 +7431,33 @@ void initmap(void) { addhabitat(H_MASTERVAULTS, "master vaults", CT_FLOORDURANITE, CT_WALLDURANITE, 5, 0, 0, MAXVISRANGE, OT_VSTAIRSUP, OT_VSTAIRSDOWN); // cell types - solid - // floorheight, hp - addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 50); - addcelltype(CT_WALLBRICK, "brick wall", UNI_SHADEDARK, C_ORANGE, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 40); - addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEMED, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 20); - addcelltype(CT_WALLDURANITE, "duranite wall", UNI_SHADEDARK, C_MAGENTA, NA, B_SOLID, B_OPAQUE, MT_DURANITE, 0, 20000); - addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_WOOD, 0, 30); - addcelltype(CT_WALLDWOOD, "wyrmwood wall", UNI_SOLID, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_DRAGONWOOD, 0, 100); - addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, NA, B_SOLID, B_OPAQUE, MT_FLESH, 0, 25); - addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, NA, B_SOLID, B_TRANS, MT_GLASS, 0, 20); + // floorheight, hp, volmod + addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 50, 0); + addcelltype(CT_WALLBRICK, "brick wall", UNI_SHADEDARK, C_ORANGE, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 40, 0); + addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEMED, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_STONE, 0, 20, 0); + addcelltype(CT_WALLDURANITE, "duranite wall", UNI_SHADEDARK, C_MAGENTA, NA, B_SOLID, B_OPAQUE, MT_DURANITE, 0, 20000, 0); + addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_WOOD, 0, 30, 0); + addcelltype(CT_WALLDWOOD, "wyrmwood wall", UNI_SOLID, C_BROWN, NA, B_SOLID, B_OPAQUE, MT_DRAGONWOOD, 0, 100, 0); + addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, NA, B_SOLID, B_OPAQUE, MT_FLESH, 0, 25, 0); + addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, NA, B_SOLID, B_TRANS, MT_GLASS, 0, 20, 0); //addcelltype(CT_WALLTREE, "dense bushland", UNI_SHADEDARK, C_GREEN, B_SOLID, B_OPAQUE, MT_PLANT, 0, 100); - addcelltype(CT_WALLTREE, "dense bushland", UNI_TREELOTS, C_GREEN, NA, B_SOLID, B_OPAQUE, MT_PLANT, 0, 100); - addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, NA, B_SOLID, B_OPAQUE, MT_METAL, 0, 75); + addcelltype(CT_WALLTREE, "dense bushland", UNI_TREELOTS, C_GREEN, NA, B_SOLID, B_OPAQUE, MT_PLANT, 0, 100, 0); + addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, NA, B_SOLID, B_OPAQUE, MT_METAL, 0, 75, 0); // cell types - non-solid - addcelltype(CT_FAKE, "fake cell", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1); - addcelltype(CT_CORRIDOR, "rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1); - addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1); - addcelltype(CT_FLOORCARPET, "carpetted floor", '.', C_RED, C_ORANGE, B_EMPTY, B_TRANS, MT_CLOTH, 0, -1); - addcelltype(CT_FLOORDURANITE, "duranite floor", '.', C_MAGENTA, NA, B_EMPTY, B_TRANS, MT_DURANITE, 0, -1); - addcelltype(CT_FLOORWOOD, "wood floor", '.', C_BROWN, NA, B_EMPTY, B_TRANS, MT_WOOD, 0, -1); - addcelltype(CT_FLOORFLESH, "flesh floor", '.', C_RED, NA, B_EMPTY, B_TRANS, MT_FLESH, 0, -1); - addcelltype(CT_FLOORSHOP, "shop floor", '.', C_BROWN, NA, B_EMPTY, B_TRANS, MT_WOOD, 0, -1); - addcelltype(CT_FLOORTILE, "tiled floor", '.', C_CYAN, C_WHITE, B_EMPTY, B_TRANS, MT_METAL, 0, -1); - addcelltype(CT_GRASS, "grass", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_PLANT, 0, -1); - addcelltype(CT_DIRT, "dirt", '.', C_BROWN, C_YELLOW, B_EMPTY, B_TRANS, MT_STONE, 0, -1); - addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, -1, -1); - addcelltype(CT_VLOWFLOOR, "very low rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, -2, -1); + addcelltype(CT_FAKE, "fake cell", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0); + addcelltype(CT_MOSSROCK, "mossy rock floor", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0); + addcelltype(CT_CORRIDOR, "rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0); + addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, 0, -1, 0); + addcelltype(CT_FLOORCARPET, "carpetted floor", '.', C_RED, C_ORANGE, B_EMPTY, B_TRANS, MT_CLOTH, 0, -1, -1); + addcelltype(CT_FLOORDURANITE, "duranite floor", '.', C_MAGENTA, NA, B_EMPTY, B_TRANS, MT_DURANITE, 0, -1, 1); + addcelltype(CT_FLOORWOOD, "wood floor", '.', C_BROWN, NA, B_EMPTY, B_TRANS, MT_WOOD, 0, -1, 1); + addcelltype(CT_FLOORFLESH, "flesh floor", '.', C_RED, NA, B_EMPTY, B_TRANS, MT_FLESH, 0, -1, -2); + addcelltype(CT_FLOORSHOP, "shop floor", '.', C_BROWN, NA, B_EMPTY, B_TRANS, MT_WOOD, 0, -1, 0); + addcelltype(CT_FLOORTILE, "tiled floor", '.', C_CYAN, C_WHITE, B_EMPTY, B_TRANS, MT_METAL, 0, -1, 2); + addcelltype(CT_GRASS, "grass", '.', C_GREEN, NA, B_EMPTY, B_TRANS, MT_PLANT, 0, -1, -1); + addcelltype(CT_DIRT, "dirt", '.', C_BROWN, C_YELLOW, B_EMPTY, B_TRANS, MT_STONE, 0, -1, -1); + addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, -1, -1, 0); + addcelltype(CT_VLOWFLOOR, "very low rock floor", '.', C_GREY, NA, B_EMPTY, B_TRANS, MT_STONE, -2, -1, 0); // region types // name, pluralname?, defaulthab, maxdepth stairs stair major? depthmod inherit_parent_depth? @@ -7813,7 +7839,7 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { int islit(cell_t *c) { int amt = 0; object_t *o; - flag_t *f; + //flag_t *f; /* switch (c->lit) { case L_TEMP: @@ -7828,18 +7854,24 @@ int islit(cell_t *c) { return 0; } + amt += obproduceslight(o); + /* f = hasflag(o->flags, F_PRODUCESLIGHT); if (f) { amt += f->val[0]; } + */ } if (c->lf) { + amt += lfproduceslight(c->lf, NULL); + /* for (o = c->lf->pack->first ; o ; o = o->next) { f = hasflag(o->flags, F_PRODUCESLIGHT); if (f) { amt += f->val[0]; } } + */ } return amt; } @@ -8018,7 +8050,7 @@ int linkholes(map_t *map) { // this will automatically avoid lifeforms since we're using // we_walkable rather than we_notwall. this saves problems // with someine coming up underneath you! - c2 = real_getrandomadjcell(c2, WE_NOLF, B_ALLOWEXPAND, LOF_DONTNEED, &ot->id, NULL, NULL); + c2 = real_getrandomadjcell(c2, WE_NOLF, B_ALLOWEXPAND, LOF_DONTNEED, &ot->id, NULL, NULL, MT_NOTHING); } // clear out the cell if required if (c2->type->solid) { @@ -8395,7 +8427,7 @@ void mapentereffects(map_t *m) { // find the closest cell of my lair where = getclosestroomcell(c->lf, roomid); if (where) { - movelf(c->lf, where); + movelf(c->lf, where, B_FALSE); } } } @@ -8498,7 +8530,7 @@ int orthdir(int compassdir) { return D_NONE; } -enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum SUBJOB *wantsubjob, enum BEHAVIOUR *wantbehaviour) { +enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum BEHAVIOUR *wantbehaviour) { int donesomething; char *p,*suff; job_t *j; @@ -8566,42 +8598,6 @@ enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum S } } - if (!j) { - int foundsubjob = B_FALSE; - // search for subjob names - char *ep; - ep = strends(localname, "Skymage"); - if (ep && !foundsubjob) { - if (wantjob) *wantjob = J_WIZARD; - if (wantsubjob) *wantsubjob = SJ_AIRMAGE; - *ep = '\0'; - foundsubjob = B_TRUE; - } - ep = strends(localname, "Icemage"); - if (ep && !foundsubjob) { - if (wantjob) *wantjob = J_WIZARD; - if (wantsubjob) *wantsubjob = SJ_ICEMAGE; - *ep = '\0'; - foundsubjob = B_TRUE; - } - ep = strends(localname, "Firemage"); - if (ep && !foundsubjob) { - if (wantjob) *wantjob = J_WIZARD; - if (wantsubjob) *wantsubjob = SJ_FIREMAGE; - *ep = '\0'; - foundsubjob = B_TRUE; - } - ep = strends(localname, "Necromancer"); - if (ep && !foundsubjob) { - if (wantjob) *wantjob = J_WIZARD; - if (wantsubjob) *wantsubjob = SJ_NECROMANCER; - *ep = '\0'; - foundsubjob = B_TRUE; - } - - } - - // try removing suffixes for "named xxx" strcpy(named, ""); suff = strstr(localname, " named "); @@ -9095,7 +9091,7 @@ int validateregionthing(regionthing_t *thing) { } break; case RT_LF: - rid = parserace(thing->what, NULL, NULL, NULL, NULL); + rid = parserace(thing->what, NULL, NULL, NULL); if (rid == R_NONE) { dblog("Invalid lifeform '%s' specified in regionthing.", thing->what); goterrors = B_TRUE; diff --git a/map.h b/map.h index 9eb70d7..51fdd7e 100644 --- a/map.h +++ b/map.h @@ -132,7 +132,7 @@ int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved); int getobchance(int habitat); int getthingchance(int habitat); cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand); -cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob, cell_t *dontwantcell, lifeform_t *preferlos); +cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob, cell_t *dontwantcell, lifeform_t *preferlos, enum MATERIAL wantmat); cell_t *getrandomcell(map_t *map); cell_t *getrandomcelloftype(map_t *map, enum CELLTYPE id); int getrandomdir(int dirtype); @@ -141,6 +141,7 @@ cell_t *getrandomroomcell(map_t *map, int roomid, int wantempty); void getroomcells(map_t *m, int roomid, cell_t **retcell, int *ncells); int getslipperyness(cell_t *c, object_t **slipob); cell_t *getstairdestination(object_t *o, int *madenewmap); +object_t *hasdoor(cell_t *c); object_t *hasenterableobject(cell_t *c); object_t *hascloseddoor(cell_t *c); int hascrushableob(cell_t *c, lifeform_t *lf); @@ -185,7 +186,7 @@ void mapentereffects(map_t *m); void modillumination(map_t *m, int dir); void moveobtoclearcell(object_t *o); int orthdir(int compassdir); -enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum SUBJOB *wantsubjob, enum BEHAVIOUR *wantbehaviour); +enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum BEHAVIOUR *wantbehaviour); int remove_deadends(map_t *m, int howmuch); void selectcelltypes(map_t *map); void set_scanned_glyph(int targettype, void *what, char *descappend, char *desc, glyph_t *glyph); diff --git a/move.c b/move.c index 841665b..f3743c0 100644 --- a/move.c +++ b/move.c @@ -143,9 +143,10 @@ int canswapwith(lifeform_t *lf, lifeform_t *lf2) { if (isknownpeaceful(lf2)) { // player can swap with peaceful lfs // if they are a lot smaller - if (getlfsize(lf) - getlfsize(lf2) >= 2) { - return B_TRUE; - } + //if (getlfsize(lf) - getlfsize(lf2) >= 2) { + // return B_TRUE; + //} + return B_TRUE; } } return B_FALSE; @@ -1194,7 +1195,7 @@ int moveeffects(lifeform_t *lf, int moved) { // returns TRUE if something happened -int movelf(lifeform_t *lf, cell_t *newcell) { +int movelf(lifeform_t *lf, cell_t *newcell, int onpurpose) { object_t *o,*nexto; cell_t *precell; char obname[BUFLEN],lfname[BUFLEN],buf[BUFLEN]; @@ -1222,9 +1223,6 @@ int movelf(lifeform_t *lf, cell_t *newcell) { needredraw = B_TRUE; } - - - if (newcell->map != lf->cell->map) { changedlev = B_TRUE; lf->changinglev = B_TRUE; @@ -1341,6 +1339,9 @@ int movelf(lifeform_t *lf, cell_t *newcell) { */ //precalclos(lf); + // refresh name of lf, in case it came into view. + getlfname(lf, lfname); + if (isplayer(lf) || cansee(player, lf)) { needredraw = B_TRUE; } @@ -1453,36 +1454,58 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } } - if (!lfhasflag(lf, F_CAREFULMOVE) && cancrush(lf, o)) { - // crush it - getobname(o, obname, 1); - - // special case - if (o->type->id == OT_BROKENGLASS) { - if (o->amt > 1) { - char *newname; - // we want 'xx steps on some pieces of broken glass' - // not 'xx steps on 5 pieces of broken glass' - newname = makeplural(obname); - newname = strrep(newname, "a ", "some ", NULL); - strcpy(obname, newname); - free(newname); + if (!lfhasflag(lf, F_CAREFULMOVE)) { + if (cancrush(lf, o)) { + // crush it + getobname(o, obname, 1); + + // special case + if (o->type->id == OT_BROKENGLASS) { + if (o->amt > 1) { + char *newname; + // we want 'xx steps on some pieces of broken glass' + // not 'xx steps on 5 pieces of broken glass' + newname = makeplural(obname); + newname = strrep(newname, "a ", "some ", NULL); + strcpy(obname, newname); + free(newname); + } } - } - if (isplayer(lf)) { - msg("You crush %s underfoot.",obname); - didmsg = B_TRUE; - } else if (haslos(player, newcell)) { - msg("%s crushes %s.",lfname, obname); - didmsg = B_TRUE; - } - // kill object which is being crushed. - removeob(o, o->amt); - if (isplayer(lf)) { - angergodmaybe(R_GODNATURE, 10, GA_ATTACKOBJECT); - } - continue; + if (isplayer(lf)) { + msg("You crush %s underfoot.",obname); + didmsg = B_TRUE; + } else if (haslos(player, newcell)) { + msg("%s crushes %s.",lfname, obname); + didmsg = B_TRUE; + } + // kill object which is being crushed. + removeob(o, o->amt); + if (isplayer(lf)) { + angergodmaybe(R_GODNATURE, 10, GA_ATTACKOBJECT); + } + continue; + } + if (hasflag(o->flags, F_DIMONWALK)) { + f = hasflag(o->flags, F_PRODUCESLIGHT); + getobname(o, obname, o->amt); + if (f) f->val[0]--; + if (!f || (f->val[0] <= 0)) { + if (haslos(player, newcell)) { + msg("%s dim%s and crumbles.",obname, + (o->amt == 1) ? "s" : ""); + didmsg = B_TRUE; + } + removeob(o, ALL); + continue; + } else { + if (haslos(player, newcell)) { + msg("%s dim%s slightly.",obname, + (o->amt == 1) ? "s" : ""); + didmsg = B_TRUE; + } + } + } // end if dimonwalk } // end if crushable if ((o->type->id == OT_VINE) && !hasjob(lf, J_DRUID)) { @@ -1664,7 +1687,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } } */ - if (preseenbyplayer && !cansee(player, lf) && !changedlev) { + if (onpurpose && preseenbyplayer && !cansee(player, lf) && !changedlev) { if (isadjacent(lf->cell, precell)) { // ie don't say this if we teleported/jumped if (areenemies(player, lf)) { char buf[BUFLEN]; @@ -1703,7 +1726,7 @@ int movelfsoutofway(cell_t *newcell) { c = getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND); if (c) { // move them there - movelf(newcell->lf, c); + movelf(newcell->lf, c, B_FALSE); } else { return B_TRUE; } @@ -1748,7 +1771,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { dontclearmsg = B_TRUE; } // actually do the move - didmsg = movelf(lf, newcell); + didmsg = movelf(lf, newcell, onpurpose); if (isplayer(lf)) { // is new cell dark? @@ -2085,11 +2108,20 @@ int opendoor(lifeform_t *lf, object_t *o) { // known - try to force it int amt = 0; amt = getattr(lf, A_STR) - 10; - if (amt < 0) amt = 0; + limit(&amt, 0, NA); + + // loosen a bit + if (amt > 0) { + f->val[0] -= amt; + } if (isplayer(lf)) { if (amt > 0) { - msg("The %s moves slightly but remains jammed.", noprefix(obname)); + if (f->val[0] > 0) { + msg("The %s moves slightly but remains jammed.", noprefix(obname)); + } + // ... otherwise we'll announce later that we forced the door + // successfully } else { msg("You cannot budge the jammed %s.", noprefix(obname)); } @@ -2113,12 +2145,9 @@ int opendoor(lifeform_t *lf, object_t *o) { } } } - // loosen a bit - if (amt) { - f->val[0] -= amt; - } if (f->val[0] <= 0) { - killflag(f); + killflag(f); + f = NULL; openit = B_TRUE; } else { openit = B_FALSE; // don't open the door @@ -2374,7 +2403,7 @@ int pullnextto(lifeform_t *lf, cell_t *c) { isairborne(lf) ? "through the air" : "along the ground"); } - movelf(lf, dst); + movelf(lf, dst, B_FALSE); return B_FALSE; } @@ -2404,7 +2433,7 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int onpurpose, int *didmsg) { } else { // must pass a skill check to keep climbing! if (!skillcheck(lf, SC_CLIMB, getcellclimbdifficulty(cell), 0)) { - msg("You lose your footing!"); + msg("^bYou lose your footing!"); stopclimbing(lf, B_FALSE); reason = E_OK; return B_TRUE; @@ -2771,7 +2800,7 @@ int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke) { if (wantsmoke) { addob(lf->cell->obpile, "cloud of smoke"); } - movelf(lf, c); + movelf(lf, c, B_FALSE); if (cansee(player, lf)) { redraw(); // redraw screen @@ -2858,7 +2887,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { int srcmoney = 0; int prebattle = B_FALSE; int prebattlearmed = B_FALSE; - flag_t *f,*fleeing = NULL; + flag_t *fleeing = NULL; // are we next to an enemy who we can see? prebattle = isinbattle(lf, B_NODISTANT, B_FALSE); if (isplayer(lf)) { @@ -2911,21 +2940,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { } - f = lfhasflag(lf, F_DRUNK); - if (f) { - if (!hasjob(lf, J_PIRATE)) { - if (rnd(1,6) <= ((f->lifetime/TM_DRUNKTIME)+1)) { - // randomize move - rndmove = B_TRUE; // ie. you can walk into walls now. - } - } - } else if (iswoozy(lf)) { - rndmove = B_TRUE; - } else if (lfhasflagval(lf, F_INJURY, IJ_TAILBRUISED, NA, NA, NULL) && onein(6)) { - rndmove = B_TRUE; - } - - + rndmove = movesrandomly(lf); if (rndmove) { dir = rnd(DC_N, DC_NW); strafe = B_TRUE; @@ -3105,7 +3120,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { getlfname(alf, alfname); msg("%s drags %s along.", lfname, alfname); } - movelf(alf, nc); + movelf(alf, nc, B_FALSE); } } } @@ -3358,18 +3373,32 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { } else { if (canswapwith(lf, cell->lf)) { lifeform_t *lfinway; + char lfname[BUFLEN]; + strcpy(lfname, "__not used yet__"); // otherwise swap locations. lfinway = cell->lf; + // need to get the name of whoever you swapped with + // BEFORE moving, as afterwards we may no longer be + // able to see it. if (isplayer(lf)) { - char lfname[BUFLEN]; getlfname(lfinway, lfname); - msg("You swap places with %s.", lfname); - dontclearmsg = B_TRUE; } swapplaces(lf, lfinway, B_NOCHANGEDIR, B_NOCHANGEDIR, onpurpose); + // need to print this AFTER moving, because otherwise the + // act of moving will clear the message line and we'll never + // see it. + if (isplayer(lf)) { + msg("You swap places with %s.", lfname); + dontclearmsg = B_TRUE; + } + + if (isplayer(lf)) { + dontclearmsg = B_TRUE; + } + //if (onpurpose) taketime(lf, getmovespeed(lf)); taketime(lf, getmovespeed(lf)); } else { @@ -3536,7 +3565,7 @@ int walkoffmap(lifeform_t *lf, int dir, int onpurpose) { c = getrandomadjcell(dst, WE_WALKABLE, B_ALLOWEXPAND); if (c) { if (!initiatemove(adjally[n], NULL, B_TRUE, NULL)) { - movelf(adjally[n], c); + movelf(adjally[n], c, B_FALSE); taketime(adjally[n], getmovespeed(adjally[n])); } } @@ -3719,8 +3748,9 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { } if (isundead(lf)) { - f = hasflag(o->flags, F_PRODUCESLIGHT); - if (f && (f->val[0] >= gettr(lf))) { + int amt; + amt = obproduceslight(o); + if (amt && (amt >= gettr(lf))) { if (error) *error = E_WONT; return B_FALSE; } diff --git a/move.h b/move.h index f3e9fd0..79d4e68 100644 --- a/move.h +++ b/move.h @@ -18,7 +18,7 @@ int makeorthogonal(int dir); int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int strafe, int onpurpose); int moveclear(lifeform_t *lf, int dir, enum ERROR *error); int moveeffects(lifeform_t *lf, int moved); -int movelf(lifeform_t *lf, cell_t *newcell); +int movelf(lifeform_t *lf, cell_t *newcell, int onpurpose); int movelfsoutofway(cell_t *newcell); int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg); int movetowards(lifeform_t *lf, cell_t *dst, int dirtype, int strafe); diff --git a/nexus.c b/nexus.c index 5e6e2d8..0ead5b1 100644 --- a/nexus.c +++ b/nexus.c @@ -35,7 +35,6 @@ raceclass_t *firstraceclass = NULL,*lastraceclass = NULL; recipe_t *firstrecipe = NULL,*lastrecipe = NULL; job_t *firstjob = NULL,*lastjob = NULL; poisontype_t *firstpoisontype = NULL,*lastpoisontype = NULL; -subjob_t *firstsubjob = NULL,*lastsubjob = NULL; skill_t *firstskill = NULL,*lastskill = NULL; habitat_t *firsthabitat = NULL,*lasthabitat = NULL; map_t *firstmap = NULL,*lastmap = NULL; @@ -51,6 +50,9 @@ int numnpcnames; extern lifeform_t *godlf[]; extern int ngodlfs; + +extern WINDOW *mainwin; + int nextregionthingid = 0; int playerorigalignment = AL_NONE; @@ -207,7 +209,6 @@ int main(int argc, char **argv) { if (!foundsavegame) { char *user,pname[BUFLEN],buf[BUFLEN]; job_t *j = NULL; - enum SUBJOB wantsubjob = SJ_NONE; race_t *startrace = NULL; char ch; //object_t *o; @@ -262,48 +263,33 @@ int main(int argc, char **argv) { } if (!j) { + enum JOBCATEGORY jcid; // ask for job initprompt(&prompt, "Select your base job:"); ch = 'a'; - for (j = firstjob ; j ; j = j->next) { - if (jobpossible(startrace->flags, j->id, SJ_NONE)) { - subjob_t *sub; - char *longdesc; - // wizards must have a subjob - if (j->id != J_WIZARD) { + for (jcid = JC_FIRST ; jcid <= JC_LAST; jcid++) { + for (j = firstjob ; j ; j = j->next) { + if ((j->category == jcid) && jobpossible(startrace->flags, j->id)) { + char *longdesc,buf[BUFLEN]; longdesc = malloc(HUGEBUFLEN * sizeof(char)); makedesc_job(j, longdesc); if (!hasflag(j->flags, F_NOPLAYER)) { // letter isn't used - addchoice(&prompt, '-', (j->id == J_GOD) ? "Diety (for debugging)" : j->name, NULL, j, longdesc); + if (j->id == J_GOD) { + sprintf(buf, "%-20s(%s)", "Diety", "for debugging"); + } else { + sprintf(buf, "%-20s(%s)", j->name, getjobcatname(j->category)); + } + addchoice(&prompt, '-', buf, NULL, j, longdesc); } free(longdesc); } - // show subjobs of this one too... - for (sub = firstsubjob ; sub ; sub = sub->next) { - if (hasflagval(j->flags, F_CANHAVESUBJOB, sub->id, NA, NA, NULL)) { - if (jobpossible(startrace->flags, J_NONE, sub->id)) { - char thisname[BUFLEN]; - sprintf(thisname, "%s:%s", j->name, sub->name); - addchoice(&prompt, sub->letter, thisname, NULL, j, sub->desc); - } - } - } } } j = NULL; while (!j) { getchoicestr(&prompt, B_FALSE, B_TRUE); j = prompt.result; - if (prompt.selection != '-') { - subjob_t *sj; - // ie. selected a subjob - // find the subjob with this letter.... - sj = findsubjobbyletter(prompt.choice[prompt.selection].ch); - if (sj) { - wantsubjob = sj->id; - } - } } } @@ -313,10 +299,10 @@ int main(int argc, char **argv) { createfakes(&fakemap, &fakecell); real_addlf(&fakecell, startrace->id, 1, C_PLAYER); // this will assign 'player' // give them basic abilities - addflag(player->flags, F_CANWILL, OT_A_CHECKSTAIRS, NA, NA, NULL); - addflag(player->flags, F_CANWILL, OT_A_PRAY, NA, NA, NULL); - addflag(player->flags, F_CANWILL, OT_A_TRAIN, NA, NA, NULL); - addflag(player->flags, F_CANWILL, OT_A_DEBUG, NA, NA, NULL); ///////// + addtempflag(player->flags, F_CANWILL, OT_A_CHECKSTAIRS, NA, NA, NULL, FROMGAMESTART); + addtempflag(player->flags, F_CANWILL, OT_A_PRAY, NA, NA, NULL, FROMGAMESTART); + addtempflag(player->flags, F_CANWILL, OT_A_TRAIN, NA, NA, NULL, FROMGAMESTART); + addtempflag(player->flags, F_CANWILL, OT_A_DEBUG, NA, NA, NULL, FROMGAMESTART); ///////// // make the initial level @@ -353,7 +339,7 @@ int main(int argc, char **argv) { exit(1); } if (where->lf) killlf(where->lf); - movelf(player, where); + movelf(player, where, B_FALSE); // new remove fakes killfakes(&fakemap, &fakecell); @@ -394,7 +380,7 @@ int main(int argc, char **argv) { } // give the player their job - givejob(player, j->id, wantsubjob); + givejob(player, j->id); ////////////////////// // read cheat info from player file @@ -431,7 +417,7 @@ int main(int argc, char **argv) { assert(r); // create pet, in view of player if possible. - c = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, &avoidob, NULL, player); + c = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, &avoidob, NULL, player, MT_NOTHING); assert(c); pet = addlf(c, r->id, 1); // mark us as its master @@ -531,9 +517,127 @@ int main(int argc, char **argv) { // show level drawscreen(); + if (!hasjob(player, J_GOD) && (lfhasflag(player, F_CANCAST) || lfhasflag(player, F_CANWILL))) { + int order[3] = { FROMRACE, FROMJOB, FROMSKILL }, norder = 3; + int first = B_TRUE,i,nspells = 0, nabils = 0, n; + char buf[BUFLEN]; + cls(); + wmove(mainwin, 0, 0); + textwithcol(mainwin, welcomemsg); + textwithcol(mainwin, "\n\n"); + + // show spells + getflags(player->flags, retflag, &nspells, F_CANCAST, F_NONE); + for (n = 0; n < norder; n++) { + for (i = 0; i < nspells; i++) { + objecttype_t *sp; + if (retflag[i]->lifetime != order[n]) continue; + + sp = findot(retflag[i]->val[0]); + if (sp) { + if (first) { + textwithcol(mainwin, "Your starting spells are:\n"); + first = B_FALSE; + } + sprintf(buf, " - %-20s (%s", sp->name, getschoolname(getspellschoolknown(player, sp->id)) ); + if (order[n] == FROMRACE) { + char rname[BUFLEN]; + strcat(buf, ", ^g"); + sprintf(rname, "%s", player->race->name); + capitalise(rname); + strcat(buf, rname); + strcat(buf, " perk^n"); + } else if (order[n] == FROMJOB) { + strcat(buf, ", ^G"); + strcat(buf, getjobname(player)); + strcat(buf, " perk^n"); + } else if (order[n] == FROMSKILL) { + skill_t *sk; + enum SKILLLEVEL whichlev; + sk = retflag[i]->skillfrom; + assert(sk); + + whichlev = whichlevforabil(sk->id, sp->id); + assert(whichlev != PR_INEPT); + + strcat(buf, ", ^w"); + strcat(buf, getskilllevelname(whichlev)); + strcat(buf, " "); + strcat(buf, sk->name); + strcat(buf, " perk^n"); + } + strcat(buf, ")\n"); + textwithcol(mainwin, buf); + } + } + } + if (nspells) { + textwithcol(mainwin, "\n"); + } + + // show racial and job abilities + first = B_TRUE; + getflags(player->flags, retflag, &nabils, F_CANWILL, F_NONE); + for (n = 0; n < norder; n++) { + for (i = 0; i < nabils; i++) { + objecttype_t *sp; + // don't list abilities which everyone has. + if (retflag[i]->lifetime == FROMGAMESTART) continue; + if (retflag[i]->lifetime != order[n]) continue; + + sp = findot(retflag[i]->val[0]); + if (sp) { + if (first) { + textwithcol(mainwin, "Your unique starting abilities are:\n"); + first = B_FALSE; + } + sprintf(buf, " - %-20s", sp->name); + if (order[n] == FROMRACE) { + char rname[BUFLEN]; + strcat(buf, " (^g"); + + sprintf(rname, "%s", player->race->name); + capitalise(rname); + strcat(buf, rname); + + strcat(buf, " perk^n)"); + } else if (order[n] == FROMJOB) { + strcat(buf, " (^G"); + strcat(buf, getjobname(player)); + strcat(buf, " perk^n)"); + } else if (order[n] == FROMSKILL) { + skill_t *sk; + enum SKILLLEVEL whichlev; + sk = retflag[i]->skillfrom; + assert(sk); + + whichlev = whichlevforabil(sk->id, sp->id); + assert(whichlev != PR_INEPT); + + strcat(buf, " (^w"); + strcat(buf, getskilllevelname(whichlev)); + strcat(buf, " "); + strcat(buf, sk->name); + strcat(buf, " perk^n)"); + } + strcat(buf, "\n"); + textwithcol(mainwin, buf); + } + } + } + if (nabils) { + textwithcol(mainwin, "\n"); + } + wprintw(mainwin, "\n[Press any key to begin]"); + getch(); + + restoregamewindows(); + } + clearmsg(); msg("%s",welcomemsg); - more(); + //more(); + playerorigalignment = getalignment(player); // MAIN LOOP @@ -587,7 +691,7 @@ int main(int argc, char **argv) { return B_FALSE; } -celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp) { +celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp, int volumemod) { celltype_t *a; // add to the end of the list @@ -620,6 +724,7 @@ celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, i a->material = findmaterial(mat); a->floorheight = floorheight; a->hp = hp; + a->volumemod = volumemod; a->flags = addflagpile(NULL, NULL); diff --git a/nexus.h b/nexus.h index 60a9db6..f107dc1 100644 --- a/nexus.h +++ b/nexus.h @@ -1,6 +1,6 @@ #include "defs.h" -celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp); +celltype_t *addcelltype(int id, char *name, int glyph, int colour, int altcol, int solid, int transparent, enum MATERIAL mat, int floorheight, int hp, int volumemod); warning_t *addwarning(char *text, int lifetime); void checkdeath(void); void checkendgame(void); diff --git a/objects.c b/objects.c index 04d847f..4c1c612 100644 --- a/objects.c +++ b/objects.c @@ -1464,12 +1464,23 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum addflag(o->flags, F_MAPLINK, targetmap->id, tx, ty, NULL); } - // assign gods to temples + // assign gods to temples, and set opening hours. if (o->type->id == OT_TEMPLE) { lifeform_t *god; god = getrandomgod(); if (god) { addflag(o->flags, F_LINKGOD, god->race->id, NA, NA, NULL); + switch (god->race->id) { + case R_GODDEATH: + case R_GODTHIEVES + +oooooo + // open at night only + addflag(lastot->flags, F_OPENHOURS, 9, 17, SP_CLOSEDTILNIGHT, NULL); + break; + default: // always open + break; + } } else { // this should only ever happen when creating the // surface map - because the realm of gods (and hence the @@ -1631,7 +1642,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum // add contents to the book if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { // giving to player at start of game - if (hasjob(where->owner, J_WIZARD)) { + if (hasjobcat(where->owner, JC_MAGE)) { enum OBTYPE firstspell; nspells = 5; firstlev = 2; @@ -1654,7 +1665,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum if (lev > MAXSPELLLEV) break; oid = getrandomspellfromschool(bookcontents,lev); // special case - paladin's always have this spell - if ((lev == 3) && (where->owner) && hassubjob(where->owner, SJ_PALADIN) && + if ((lev == 3) && (where->owner) && hasjob(where->owner, J_PALADIN) && (bookcontents == SS_LIFE)) { while (oid == OT_S_DISRUPTUNDEAD) { oid = getrandomspellfromschool(bookcontents,lev); @@ -1671,10 +1682,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum enum SPELLSCHOOL school[MAXCANDIDATES]; if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { - if (hassubjob(where->owner, SJ_BATTLEMAGE)) { + if (hasjob(where->owner, J_BATTLEMAGE)) { nschools = 3; - } else if (hasjob(where->owner, J_WIZARD)) { - nschools = 6; + } else if (hasjobcat(where->owner, JC_MAGE)) { + nschools = 6; } } @@ -1691,7 +1702,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum } else { // select actual random schools to use. for (i = 0; i < nschools; i++) { - if (where->owner && hassubjob(where->owner, SJ_BATTLEMAGE)) { + if (where->owner && hasjob(where->owner, J_BATTLEMAGE)) { switch (rnd(1,5)) { case 1: school[i] = SS_FIRE; break; case 2: school[i] = SS_COLD; break; @@ -1699,8 +1710,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum case 4: school[i] = SS_TRANSLOCATION; break; case 5: school[i] = SS_WILD; break; } - } else if (where->owner && hasjob(where->owner, J_WIZARD)) { - school[i] = getrandomspellschool(where->owner, B_TRUE); + } else if (where->owner && hasjobcat(where->owner, JC_MAGE)) { + school[i] = getrandomspellschool(where->owner, B_TRUE); } else { // should never happen? school[i] = getrandomspellschool(NULL, B_FALSE); @@ -1718,7 +1729,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum // giving to player at start of game? limit levels to // 1-3. if (where->owner && isplayer(where->owner) && (gamemode == GM_CHARGEN)) { - if (hasjob(where->owner, J_WIZARD)) { + if (hasjobcat(where->owner, JC_MAGE)) { switch (rnd(1,10)) { case 1: case 2: case 3: case 4: case 5: case 6: @@ -1731,7 +1742,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum wantlev = 3; break; } - } else if (hassubjob(where->owner, SJ_BATTLEMAGE)) { + } else if (hasjob(where->owner, J_BATTLEMAGE)) { wantlev = 1; } else { wantlev = getrandomgrimoirelev(); @@ -2946,6 +2957,15 @@ int canseeob(lifeform_t *lf, object_t *o) { object_t *blockob; blockob = hasobwithflag(o->pile, F_BLOCKSVIEW); if (blockob && (blockob != o)) { + if (o->pile->where == lf->cell) { + flag_t *f; + f = hasflag(blockob->flags, F_BLOCKSVIEW); + if (f && (f->val[1] == B_TRUE)) { + // ok + } else { + return B_FALSE; + } + } return B_FALSE; } } @@ -5874,6 +5894,21 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan strcat(localbuf, "}"); } + // trap type known? + f = hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL); + if (f) { + if (getskill(player, SK_ENGINEERING) >= PR_BEGINNER) { + objecttype_t *traptype; + traptype = findot(f->val[0]); + if (traptype) { + strcat(localbuf, " ("); + strcat(localbuf, traptype->name); + strcat(localbuf, ")"); + } + } + } + + // show if we've tried this //if (!shopitem && (gamemode == GM_GAMESTARTED)) { if ((gamemode == GM_GAMESTARTED) && wanttried) { @@ -6296,6 +6331,10 @@ objecttype_t *real_getrandomob(map_t *map, char *buf, int forcedepth, int forceh } else if (!nwantflag) { wantclass[0] = getrandomobclass(hab->id); nwantclass = 1; + if (wantclass[0] == OC_WAND) { + dblog("random WAND picked!"); + partdb = B_TRUE; + } } } @@ -6384,7 +6423,12 @@ objecttype_t *real_getrandomob(map_t *map, char *buf, int forcedepth, int forceh }*/ if (rarflag) { - if ((rarflag->val[1] >= raritymin) && (rarflag->val[1] <= raritymax)) { + int rarnum; + rarnum = rarflag->val[1]; + if (rarnum == NA) rarnum = 100; + + if ((rarnum >= raritymin) && (rarnum <= raritymax)) { + // now check common, rare, etc enum RARITY thisrr; thisrr = rarflag->val[2]; if (thisrr == NA) thisrr = RR_FREQUENT; @@ -6868,6 +6912,7 @@ char *gettopobname(cell_t *c, char *retbuf) { } else { // just print the cell's name strcat(retbuf, c->type->name); + addengineeringinfo(player, retbuf, c); } if (c->writing) { strcat(retbuf, ", writing:"); @@ -8426,6 +8471,11 @@ void makewet(object_t *o, int amt) { } f = addflag(o->flags, F_WET, amt, TM_WETTIME, NA, NULL); } + // water washes off bloodstain and stench + if (hasobmod(o, findobmod(OM_BLOODSTAINED)) ){ + killflagsofid(o->flags, F_SCARY); + } + killflagsofid(o->flags, F_STENCH); } } } @@ -8885,13 +8935,13 @@ void obdie(object_t *o) { if (f->val[2] == B_IFACTIVATED) { if (isactivated(o)) { - spellcloud(where, f->val[1], cloudglyph.ch, cloudglyph.colour, f->val[0], power, B_TRUE, + spellcloud(where, f->val[1], DT_ORTH, cloudglyph.ch, cloudglyph.colour, f->val[0], power, B_TRUE, seebuf, noseebuf, B_FALSE, o, B_INCLUDECENTRE); removeob(o, o->amt); return; } } else { - spellcloud(where, f->val[1], cloudglyph.ch, cloudglyph.colour, f->val[0], power, B_TRUE, + spellcloud(where, f->val[1], DT_ORTH, cloudglyph.ch, cloudglyph.colour, f->val[0], power, B_TRUE, seebuf, noseebuf, B_FALSE, o, B_INCLUDECENTRE); removeob(o, o->amt); return; @@ -10027,7 +10077,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { r = poss[rnd(0,nposs-1)]; sprintf(wname, "%s warrior", r->name); - c = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, lf); + c = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, lf, MT_NOTHING); if (c) { summonmonster(lf, c, R_SPECIFIED, wname, rnd(50,90), B_TRUE); } @@ -10169,7 +10219,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } } // summon treant - c = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, lf); + c = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, lf, MT_NOTHING); if (c) { summonmonster(lf, c, R_TREANT, NULL, rnd(50,90), B_TRUE); } @@ -10433,11 +10483,9 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { msg("%s looks at %s.",buf, obname); } } else if (o->type->id == OT_LOCKHACKER) { - char ch; int dir; // ask direction - ch = askchar("Manipulate lock in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE, B_TRUE); - dir = chartodir(ch); + dir = askdir("Manipulate lock in which direction (- to cancel)", B_TRUE, B_TRUE); if (dir == D_NONE) { clearmsg(); return B_TRUE; @@ -10514,6 +10562,33 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { return B_TRUE; } } // end if ch is a direction + } else if (o->type->id == OT_CHEWINGGUM) { + int donesomething = B_FALSE; + if (!where) { + if (isplayer(lf)) msg("There is nothing to use your gum on there!"); + } else if (where->lf) { + if (isplayer(lf)) msg("There is someone in your way!"); + } else { + object_t *o; + for (o = where->obpile->first ; o ; o = o->next) { + int isopen = B_FALSE; + // jammed doors + if (isdoor(o, &isopen) && !isopen) { + char obname[BUFLEN]; + getobname(o, obname, 1); + msg("You stick your gum into the hinges of %s.", obname); + addflag(o->flags, F_JAMMED, rnd(5,10), B_TRUE, NA, NULL); + taketime(lf, getactspeed(lf)); + donesomething = B_TRUE; + } + } + } + if (donesomething) { + removeob(o, 1); + } else { + taketime(lf, getactspeed(lf)); + if (isplayer(lf)) msg("There is nothing to use your gum on there!"); + } } else if (o->type->id == OT_SPANNER) { int donesomething = B_FALSE; if (!where) { @@ -10668,7 +10743,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { enum RARITY pickrr(int whatfor) { enum RARITY wantrr = RR_FREQUENT; - int chance = 2; + int chance = 3; int mod = 0; if ((gamemode == GM_GAMESTARTED) && hasflag(player->flags, F_EXTRALUCK)) { @@ -10885,12 +10960,8 @@ int pour(lifeform_t *lf, object_t *o) { } else if (isdoor(dst, NULL)) { msg("Your pour %s all over %s.", obname, dstname); if (o->type->id == OT_POT_OIL) { - flag_t *f; // unjam doors - f = hasflag(dst->flags, F_JAMMED); - if (f) { - killflag(f); - } + killflagsofid(dst->flags, F_JAMMED); } } else { // default if (isplayer(lf)) { @@ -11347,8 +11418,15 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } i = geteffecttime(20,40,potblessed); - if (!lfhasflagval(lf, F_INVULNERABLE, B_TRUE, NA, NA, NULL)) { - addtempflag(lf->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL, i); + if (potblessed == B_CURSED) { + if (isplayer(lf)) { + msg("^%cYou feel invulnerable!", getlfcol(lf, CC_VGOOD)); + // but you don't actually become invulnerable! + } + } else { + if (!lfhasflagval(lf, F_INVULNERABLE, B_TRUE, NA, NA, NULL)) { + addtempflag(lf->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL, i); + } } break; case OT_POT_LEVITATION: @@ -13106,14 +13184,14 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce, lif if (f->val[2] == B_IFACTIVATED) { if (isactivated(o)) { if (!hasflag(o->flags, F_SPELLCLOUDONDEATH)) { - spellcloud(where, f->val[1], cloudglyph.ch, cloudglyph.colour, f->val[0], power, B_TRUE, + spellcloud(where, f->val[1], DT_ORTH, cloudglyph.ch, cloudglyph.colour, f->val[0], power, B_TRUE, seebuf, noseebuf, B_FALSE, o, B_INCLUDECENTRE); } addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); } } else { if (!hasflag(o->flags, F_SPELLCLOUDONDEATH)) { - spellcloud(where, f->val[1], cloudglyph.ch, cloudglyph.colour, f->val[0], power, B_TRUE, + spellcloud(where, f->val[1], DT_ORTH, cloudglyph.ch, cloudglyph.colour, f->val[0], power, B_TRUE, seebuf, noseebuf, B_FALSE, o, B_INCLUDECENTRE); } addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); @@ -13443,6 +13521,11 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp } } + // adjust destination location in case something is in the way. + // but DONT modify 'where' yet, as we still want to say (for example) + // "the orc throws a knife at you", even if something is in the way. + haslof(srcloc, where, LOF_NEED, &newloc); + // announce it ("xx throws xx" "at yy") if (announcethrow) { if (thrower && isplayer(thrower)) { @@ -13469,24 +13552,39 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp msg("%s", throwstring); } else if (seen) { char throwstring[BUFLEN]; - // an object is moving on its own if (o->pile->owner && cansee(player, o->pile->owner)) { char ownername[BUFLEN]; getlfname(o->pile->owner, ownername); snprintf(throwstring, BUFLEN, "%s%s %s %s through the air", ownername, getpossessive(ownername), noprefix(obname), (amt == 1) ? "flies" : "fly"); } else { + // an object is moving on its own snprintf(throwstring, BUFLEN, "%s %s through the air", obname, (amt == 1) ? "flies" : "fly"); } - if (target && haslos(player, where)) { - strcat(throwstring, " toward "); - strcat(throwstring, targetname); + if (target) { + int showtoward = B_FALSE; + if (!newloc && haslos(player, where)) { + // player can see the destination?. + showtoward = B_TRUE; + } else if (haslos(player, srcloc)) { + // player can see the source.. + showtoward = B_TRUE; + } + if (showtoward) { + strcat(throwstring, " toward "); + strcat(throwstring, targetname); + } } strcat(throwstring, "."); msg("%s", throwstring); } } + // now that announcement is done, adjust the destination if anyone + // is in the way. + if (newloc) { + where = newloc; + } //taketime(thrower, SPEED_THROW); // special case @@ -13569,7 +13667,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp radius = o->amt * 2; if (radius > 10) radius = 10; - spellcloud(srcloc, radius, UNI_SHADELIGHT, C_RANDOM, OT_S_INVISIBILITY, radius, B_TRUE, buf, "A cloud of twinkling lights appear!", B_FALSE, NULL, B_INCLUDECENTRE); + spellcloud(srcloc, radius, DT_ORTH, UNI_SHADELIGHT, C_RANDOM, OT_S_INVISIBILITY, radius, B_TRUE, buf, "A cloud of twinkling lights appear!", B_FALSE, NULL, B_INCLUDECENTRE); } else if (o->type->id == OT_ASHSLEEP) { int radius; char buf[BUFLEN]; @@ -13582,7 +13680,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp radius = o->amt * 2; if (radius > 10) radius = 10; - spellcloud(srcloc, radius, UNI_SHADELIGHT, C_MAGENTA, OT_S_SLEEP, radius, B_TRUE, buf, "A wispy mist appears!", B_FALSE, NULL, B_INCLUDECENTRE); + spellcloud(srcloc, radius, DT_ORTH, UNI_SHADELIGHT, C_MAGENTA, OT_S_SLEEP, radius, B_TRUE, buf, "A wispy mist appears!", B_FALSE, NULL, B_INCLUDECENTRE); } else if (o->type->id == OT_SALT) { int dist; dist = getcelldist(srcloc, where); @@ -13688,12 +13786,6 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp } - // adjust destination location in case something is in the way. - haslof(srcloc, where, LOF_NEED, &newloc); - if (newloc) { - where = newloc; - } - // ... in case the target cell changed... target = where->lf; if (target && isdead(target)) { @@ -14964,8 +15056,6 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c, object_t *trapped if (lf) getlfname(lf, lfname); temp = findot(oid); - - // saving throw? if (temp && lf) { flag_t *f; @@ -14983,7 +15073,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c, object_t *trapped } // easier to avoid if you're sneaking if (lfhasflag(lf, F_CAREFULMOVE)) mod += 5; - mod += getskill(lf, SK_TRAPS); + mod += getskill(lf, SK_ENGINEERING); avoided = skillcheck(lf, ct, f->val[2], mod); } } @@ -14995,6 +15085,11 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c, object_t *trapped f = hasflag(trapob->flags, F_TRAP); if (f) f->val[1] = curtime; } + + if (lf && (getskill(lf, SK_ENGINEERING) == PR_MASTER)) { + avoided = B_TRUE; + } + if (oid == OT_TRAPWIND) { // can't be dodged @@ -15111,7 +15206,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c, object_t *trapped } else if (cansee(player, lf)) { msg("%s leaps away from a pit!", lfname); } - movelf(lf, escapeto); + movelf(lf, escapeto, B_TRUE); } } } else if (oid == OT_TRAPALARM) { @@ -15183,7 +15278,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c, object_t *trapped } else if (cansee(player, lf)) { msg("%s leaps out of the way!", lfname); } - movelf(lf, escapeto); + movelf(lf, escapeto, B_TRUE); } } if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards @@ -15823,13 +15918,13 @@ int geteffecttime(int min, int max, enum BLESSTYPE isblessed) { // how long for? switch (isblessed) { case B_BLESSED: - howlong = 15; + howlong = max; break; case B_CURSED: - howlong = 5; + howlong = min; break; default: // ie. B_UNCURSED - howlong = rnd(5,15); + howlong = rnd(min,max); break; } return howlong; diff --git a/save.c b/save.c index 9752166..4a417c4 100644 --- a/save.c +++ b/save.c @@ -518,7 +518,7 @@ map_t *loadmap(FILE *f) { l->x, l->y, l->id); exit(1); } - movelf(l, c); + movelf(l, c, B_FALSE); //dblog("Moving lf %d to %d,%d\n",l->id, l->x, l->y); } diff --git a/shops.c b/shops.c index 9253be7..cbfad9e 100644 --- a/shops.c +++ b/shops.c @@ -154,10 +154,11 @@ void shop(lifeform_t *lf, object_t *vm) { int ngiven = 0; flag_t *f; object_t *o; + strcpy(toptext, ""); - taketime(lf, getactspeed(lf)); + if (!isplayer(lf)) { if (cansee(player, lf)) { char lfname[BUFLEN]; @@ -168,6 +169,16 @@ void shop(lifeform_t *lf, object_t *vm) { return; } + // closed? + f = hasflag(vm->flags, F_OPENHOURS); + if (f) { + int h = -1,m = -1,s = -1; + splittime(&h, &m, &s); + if (!timeisbetween(h, f->val[0], f->val[1])) { + sayphrase(NULL, f->val[2], SV_TALK, hoursto12(f->val[0]), NULL, player); + } + } + if (lfhasflag(lf, F_STENCH)) { msg("\"Pheeew! You're not coming in smelling like that.\""); return; @@ -990,17 +1001,36 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top if (hasflag(money->flags, F_GEM)) { int gemsneeded; char gemname[BUFLEN]; - int valpergem; + int valpergem,amtpaid = 0, change = 0; valpergem = applyshoppricemod(real_getobvalue(money, 1), player, vm, SA_SELL); gemsneeded = value / valpergem; limit(&gemsneeded, 1, NA); // (in case gem is worth more than object) getobname(money, gemname, gemsneeded); - // remove enough to pay... + // calculate how much change to give... + amtpaid = gemsneeded * valpergem; + change = amtpaid - value; + + // remove enough gems to pay... removeob(money, gemsneeded); purchasemethod = PM_GEM; // announce that we're using a gem - msg("You hand over %s.", gemname); more(); + // also determine whether the player get change + if (slev >= PR_ADEPT) { + msg("You hand over %s%s.", gemname, + (change > 0) ? " and ask for change." : ""); + more(); + if (change > 0) { + char changebuf[BUFLEN]; + + sprintf(changebuf, "%d gold dollars", change); + addob(player->pack, changebuf); + msg("You receive $%d change.", change); more(); + } + + } else { + msg("You hand over %s.", gemname); more(); + } } else { givemoney(player, NULL, value); purchasemethod = PM_GOLD; diff --git a/spell.c b/spell.c index 581ad4a..5261abb 100644 --- a/spell.c +++ b/spell.c @@ -106,7 +106,129 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef getlfname(target, targetname); } - if (abilid == OT_A_CHARGE) { + if (abilid == OT_A_BUILD) { + char tempname[BUFLEN]; + objecttype_t *tempot = NULL; + int dir; + char ch = 'a'; + cell_t *c; + object_t *o; + enum SKILLLEVEL slev; + enum OBTYPE needob = OT_NONE; + int numneed = 0; + if (!isplayer(user)) return B_TRUE; + + if (isimmobile(user)) { + if (isplayer(user)) msg("You can't move!"); + return B_TRUE; + } + if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { + if (isplayer(user)) msg("You can't build anything while swimming!"); + return B_TRUE; + } else if (isstuck(user)) { + if (isplayer(user)) msg("You can't build anything while stuck!"); + return B_TRUE; + } else if (isairborne(user)) { + if (isplayer(user)) msg("You can't build anything while airborne!"); + return B_TRUE; + } + slev = getskill(user, SK_ENGINEERING); + + dir = askdir("Build something in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir < 0) { + msg("Cancelled."); + return B_TRUE; + } + c = getcellindir(user->cell, dir); + + if (c->lf || c->type->solid) { + msg("There is no space to build anything there!"); + return B_TRUE; + } + // what can we build? + initprompt(&prompt, "What will you build?"); + if (hasdoor(c)) { + + if (slev >= PR_BEGINNER) { + // collapsing door + tempot = findot(OT_TRAPDOORFALL); + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) { + addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + } + } + + if (slev >= PR_EXPERT) { + // other door traps + tempot = findot(OT_TRAPNEEDLEP); + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + tempot = findot(OT_TRAPFIRE); + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + tempot = findot(OT_TRAPMINE); + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + } + } + // floor traps? + if (cellwalkable(NULL, c, NULL)) { + if (slev >= PR_BEGINNER) { + tempot = findot(OT_TRAPTRIP); + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + tempot = findot(OT_BARRICADE); // diff50 - need 2 metal poles + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + tempot = findot(OT_RUBBLE); // diff70 - need 20 stones + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + tempot = findot(OT_FENCEWOOD); // diff80 - need 1 plank of wood + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + } + if (slev >= PR_EXPERT) { + tempot = findot(OT_TRAPARROW); + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + tempot = findot(OT_TRAPROCK); + if (!haschoicedata(&prompt, tempot) && canbuild(user, tempot, tempname, &needob, &numneed)) addchoice(&prompt, ch++, tempname, NULL, tempot, NULL); + } + } + + if (prompt.nchoices <= 0) { + msg("There is nothing that you can build there."); + return B_TRUE; + } + prompt.maycancel = B_TRUE; + ch = getchoice(&prompt); + tempot = (objecttype_t *)prompt.result; + if (!tempot || (ch == '\0')) { + msg("Cancelled."); + return B_TRUE; + } + // remove ingredients + canbuild(user, tempot, NULL, &needob, &numneed); // just using this to get ingredients and count + if (needob != OT_NONE) { + o = hasob(user->pack, needob); + if (o && (o->amt >= numneed)) { + removeob(o, numneed); + } else { + msg("You don't have the required components to build that."); + return B_TRUE; + } + } + // create the trap/obstacle/whatever + o = hasdoor(c); + if (o) { + addflag(o->flags, F_TRAPPED, tempot->id, NA, B_TRUE, NULL); + o = NULL; + } else { + o = addobfast(c->obpile, tempot->id); + if (o) { + killflagsofid(o->flags, F_SECRET); + } else { + msg("For some reason, you can't build there."); + return B_TRUE; + } + } + + taketime(user, getactspeed(user)*2); + setlosdirty(user); + msg("You build %s %s.", needan(tempot->name) ? "an" : "a", tempot->name); + + } else if (abilid == OT_A_CHARGE) { cell_t *adjcell = NULL,*origcell; char targetname[BUFLEN]; @@ -183,7 +305,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef origcell = user->cell; // teleport next to them - movelf(user, adjcell); + movelf(user, adjcell, B_FALSE); if (haslos(player, adjcell)) { char verb[BUFLEN]; // special case: sometimes we call this a 'leap' @@ -249,6 +371,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef getobname(stairs, obname, 1); sprintf(buf, "How will you check %s", obname); initprompt(&prompt, buf); + if (lfhasflag(user, F_DETECTLIFE)) { + addchoice(&prompt, 'd', "Detect lifeforms", NULL, NULL, NULL); + } if ( ((getskill(user, SK_LISTEN) >= PR_ADEPT) && !isdeaf(user)) || hasequippedobid(user->pack, OT_AMU_THIEF)) { addchoice(&prompt, 'l', "Listen for sounds", NULL, NULL, NULL); @@ -277,7 +402,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // announce the check, so that the player has feedback // if map generation takes a while. - if (ch == 'l') { + if (ch == 'd') { + msg("You concentrate on %s...",obname); + } else if (ch == 'l') { msg("You listen at %s...",obname); } else if (ch == 's') { // smell msg("You sniff %s...",obname); @@ -320,7 +447,67 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } // now actually do the check - if (ch == 'l') { + if (ch == 'd') { + lifeform_t *lf; + char *dname[MAXCANDIDATES],thisdname[BUFLEN]; + int nposs = 0,n,dcount[MAXCANDIDATES]; + int maxdist,showreal = B_FALSE; + f = lfhasflag(user, F_DETECTLIFE); + assert(f); + maxdist = f->val[0]; + if (f->val[1] == B_TRUE) showreal = B_TRUE; + + // get all lfs which are within flag v0 of the other end + for (lf = c->map->lf ; lf ; lf = lf->next) { + if (lf == user) continue; + // within maxdist of stairs? + if (getcelldist(lf->cell, c) <= maxdist) { + int dirtolf; + dirtolf = getdirtowards(c, lf->cell, NULL, B_FALSE, DT_ORTH); + int found = B_FALSE; + if (showreal) { + getlfnamea(lf, thisdname); + } else { + // detected size - "large monster" etc + snprintf(thisdname, BUFLEN, "%s monster", getsizetext(getlfsize(lf))); + } + + // already a name like this? + for (n = 0; n < nposs; n++) { + if (streq(dname[n], thisdname)) { + dcount[n]++; + found = B_TRUE; + } + } + if (!found) { + if (showreal) { + dname[nposs] = strdup(noprefix(thisdname)); + } else { + dname[nposs] = strdup(thisdname); + } + dcount[nposs] = 1; + nposs++; + } + } + } + user->changinglev = B_FALSE; + // announce + if (nposs) { + for (n = 0; n < nposs; n++) { + char amttext[BUFLEN]; + if (dcount[n] == 1) { + strcpy(amttext, ""); + } else if (dcount[n] <= 3) { + strcpy(amttext, "several "); + } else { // 4+ + strcpy(amttext, "lots of "); + } + msg("You detect %s%s.", amttext, dname[n]); + } + } else { + msg("You don't detect any living creatures."); + } + } else if (ch == 'l') { lifeform_t *lf; enum SKILLLEVEL slev; char *movetext[MAXCANDIDATES],thismovetext[BUFLEN]; @@ -783,14 +970,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // ask for direction if (!targcell) { - int dirch; - dirch = askchar("Disable trap in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if ((dirch == '-') || !dirch) { + dir = askdir("Disable trap in which direction (- to cancel)", B_TRUE, B_FALSE); + if (dir == D_NONE) { if (isplayer(user)) msg("Cancelled."); return B_TRUE ; - } - dir = chartodir(dirch); - if (dir == D_NONE) { + } else if (dir == D_MYSELF) { targcell = user->cell; } else { targcell = getcellindir(user->cell, dir); @@ -834,7 +1018,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // if this was a cell trap, move player there. if (trapflag->id == F_TRAP) { - movelf(user, targcell); + movelf(user, targcell, B_TRUE); } // have any objects which will help? @@ -866,7 +1050,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user) && hasjob(user, J_ROGUE)) { gainxp(user, trapflag->val[0]); } - practice(user, SK_TRAPS, 1); + practice(user, SK_ENGINEERING, 1); } else { int trapgoesoff = B_FALSE; // failed. another check to see if it goes off @@ -909,20 +1093,16 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef int skillmod = 0,targetskillmod = 0; // ask for direction if (!targcell) { - char dirch; - dirch = askchar("Disarm in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { + int dir; + dir = askdir("Disarm in which direction (- to cancel)", B_TRUE, B_FALSE); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE; + } else if (dir == D_MYSELF) { if (isplayer(user)) msg("You can't disarm yourself!"); return B_TRUE; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -975,6 +1155,83 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef msg("%s tries to disarm %s, but fail.",username, targetname); } } + } else if (abilid == OT_A_DISMANTLE) { + objecttype_t *newot = NULL; + int numnew = 0; + int dir; + char dirch; + cell_t *c; + object_t *o; + char obname[BUFLEN]; + enum SKILLLEVEL slev; + if (!isplayer(user)) return B_TRUE; + + if (isimmobile(user)) { + if (isplayer(user)) msg("You can't move!"); + return B_TRUE; + } + if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { + if (isplayer(user)) msg("You can't dismantle anything while swimming!"); + return B_TRUE; + } else if (isstuck(user)) { + if (isplayer(user)) msg("You can't dismantle anything while stuck!"); + return B_TRUE; + } + slev = getskill(user, SK_ENGINEERING); + + + dir = askdir("Dismantle obstacle in which direction (- to cancel)", B_TRUE, B_FALSE); + if (dir == D_NONE) { + msg("Cancelled."); + return B_TRUE; + } else if (dir == D_MYSELF) { + c = user->cell; + } else { + dir = chartodir(dirch); + } + c = getcellindir(user->cell, dir); + + // antything there? + o = hasobwithflag(c->obpile, F_CLIMBOBSTACLE); + if (c->type->solid) { + msg("There is nothing to dismantle there."); + return B_TRUE; + } else if (!o) { + if (slev >= PR_SKILLED) { + // you can dismantle doors too... + o = hasdoor(c); + } + if (!o) { + msg("There is nothing to dismantle there."); + return B_TRUE; + } + } + + // figrue out what to replace it with + switch (o->material->id) { + case MT_STONE: newot = findot(OT_STONE); break; + case MT_METAL: newot = findot(OT_IRONSTAFF); break; + case MT_WOOD: newot = findot(OT_WOODPLANK); break; + default: break; + } + + if (newot) { + int origsize,junksize; + // figure out how many + origsize = getobsize(o); + junksize = newot->size; + numnew = origsize / junksize; + limit(&numnew, 1, 10); + } + getobname(o, obname, 1); + removeob(o, 1); + if (numnew && newot) { + char newobname[BUFLEN]; + sprintf(newobname, "%d %s", numnew, newot->name); + addob(c->obpile, newobname); + } + taketime(user, getactspeed(user)*2); + msg("You dismantle %s.", obname); } else if (abilid == OT_A_DRAGUNDERGROUND) { // announce if (cansee(player, target)) { @@ -1028,20 +1285,16 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } else if (abilid == OT_A_FLIP) { // ask for direction if (!targcell) { - char dirch; - dirch = askchar("Flip from which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { + int dir; + dir = askdir("Flip from which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_MYSELF) { if (isplayer(user)) msg("You can't flip yourself!"); return B_TRUE; + } else if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -1086,7 +1339,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (c && cellwalkable(target, c, NULL)) { int dist; setfacing(user, dir); // turn player to face them - movelf(target, c); // move target behind player + movelf(target, c, B_FALSE); // move target behind player // throw! if (isplayer(user)) { msg("You flip %s over your head!", targetname); @@ -1106,7 +1359,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } else if (abilid == OT_A_FLURRY) { int dir; - int dirch; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { if (isplayer(user)) msg("You can't make an attack flurry traps while swimming!"); @@ -1127,11 +1379,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (targcell) { dir = getdirtowards(user->cell, targcell, NULL, B_FALSE, DT_ORTH); } else { - dirch = askchar("Flurry in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE, B_TRUE); - dir = chartodir(dirch); - if (dir == D_NONE) { + dir = askdir("Flurry in which direction (- to cancel)", B_TRUE, B_TRUE); + if ((dir == D_NONE) || (dir == D_MYSELF)) { if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; + return B_TRUE; } else { targcell = getcellindir(user->cell, dir); } @@ -1154,13 +1405,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // if we succeeded in pushing them... if (target->cell != targcell) { - movelf(user, targcell); + movelf(user, targcell, B_FALSE); } // now attack them attackcell(user, target->cell, B_TRUE); } else if (abilid == OT_A_GRAB) { - char dirch; flag_t *f; f = lfhasflag(user, F_GRABBING); @@ -1176,19 +1426,16 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // ask for direction if (!targcell) { - dirch = askchar("Grab in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { + int dir; + dir = askdir("Grab in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE; + } else if (dir == D_MYSELF) { if (isplayer(user)) msg("You can't grab yourself!"); return B_TRUE; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -1361,7 +1608,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef c = getrandomadjcell(victim->cell, WE_EMPTY, B_NOEXPAND); // nowhere to move? move to where the lf jumped from! if (c) { - movelf(victim, c); + movelf(victim, c, B_FALSE); } else { swapplaces(victim, user, B_CHANGEDIR, B_CHANGEDIR, B_NOTONPURPOSE); swapped = B_TRUE; @@ -1375,7 +1622,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } if (!swapped) { - movelf(user, targcell); + movelf(user, targcell, B_FALSE); } // announce @@ -1652,7 +1899,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef taketime(user, getactspeed(user)); } else if (abilid == OT_A_SHIELDBASH) { object_t *shield = NULL; - char dirch; flag_t *f; int badshield = B_FALSE; int shpenalty,mod; @@ -1697,19 +1943,16 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // ask for direction if (!targcell) { - dirch = askchar("Shield bash in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { + int dir; + dir = askdir("Shield bash in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_MYSELF) { // yourself! targcell = user->cell; + } else if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -1748,21 +1991,14 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef flag_t *f; if (!targcell) { - int dirch; + int dir; // ask which dir - dirch = askchar("Snatch from which direction (- to cancel)", "yuhjklbn-","-", B_FALSE, B_TRUE); - if ((dirch == '-') || !dirch) { + dir = askdir("Snatch from which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_NONE) { if (isplayer(user)) msg("Cancelled."); return B_TRUE; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -1857,13 +2093,12 @@ 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 == '.') || (dirch == '\0')) { + int dir; + dir = askdir("Sprint in which direction (- to cancel)", B_TRUE, B_TRUE); + if ((dir == D_NONE) || (dir == D_MYSELF)) { msg("Cancelled."); return B_TRUE; } - dir = chartodir(dirch); setfacing(user, dir); } @@ -2025,21 +2260,14 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef int nswallowed = 0,dodged = B_FALSE; if (!targcell) { - int dirch; + int dir; // ask which dir - dirch = askchar("Swallow in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE, B_TRUE); - if ((dirch == '-') || !dirch) { + dir = askdir("Swallow in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_NONE) { if (isplayer(user)) msg("Cancelled."); return B_TRUE; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -2146,7 +2374,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } // move target close to entrypoint - movelf(target, entry); + movelf(target, entry, B_FALSE); // announce announcearrival(target, target->cell->map); } @@ -2236,7 +2464,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef origcell = user->cell; // teleport next to them - movelf(user, adjcell); + movelf(user, adjcell, B_FALSE); if (haslos(player, adjcell)) { msg("%s swoop%s towards %s!",username,isplayer(user) ? "" : "s",targetname); needredraw = B_TRUE; @@ -2256,7 +2484,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // teleport back to initial pos if (hasfreeaction(user)) { - movelf(user, origcell); + movelf(user, origcell, B_FALSE); if (haslos(player, adjcell)) { msg("%s swoop%s away!",username,isplayer(user) ? "" : "s"); needredraw = B_TRUE; @@ -2354,20 +2582,16 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef int legs; // ask for direction if (!targcell) { - char dirch; - dirch = askchar("Trip in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { + int dir; + dir = askdir("Trip in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_MYSELF) { if (isplayer(user)) msg("You can't trip yourself!"); return B_TRUE; + } else if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -2448,12 +2672,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (targcell) { dir = getdirtowards(user->cell, targcell, NULL, B_FALSE, DT_ORTH); } else { - char dirch; - dirch = askchar("Tumble in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - dir = chartodir(dirch); - if (dir == D_NONE) { + dir = askdir("Tumble in which direction (- to cancel)", B_TRUE, B_TRUE); + if ((dir == D_NONE) || (dir == D_MYSELF)) { if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; + return B_TRUE; } else { cell_t *cell1 = NULL,*cell2 = NULL; @@ -2588,7 +2810,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } // go there! - movelf(user, targcell); + movelf(user, targcell, B_FALSE); // pits/water? if (strlen(stopthing)) { @@ -2709,7 +2931,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef msg("all blinded!"); } else if (abilid == OT_A_AIMEDSTRIKE) { object_t *wep; - char dirch; char targetname[BUFLEN]; flag_t *f; @@ -2722,19 +2943,16 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // ask for direction if (!targcell) { - dirch = askchar("Aimed strike in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { + int dir; + dir = askdir("Aimed strike in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE; + } else if (dir == D_MYSELF) { // yourself! targcell = user->cell; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -2842,21 +3060,19 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // called during our attacks. addflag(user->flags, F_COMBOSTRIKE, B_TRUE, NA, NA, NULL); while (keepgoing) { - char dirch; cell_t *c; keepgoing = B_FALSE; // ask direction c = NULL; while (!c) { + int dir; char ques[BUFLEN]; snprintf(ques, BUFLEN,"%s combination in which direction (- to cancel)", nhits ? "Continue" : "Start"); - dirch = askchar(ques, "yuhjklbn-","-", B_FALSE, B_TRUE); - if (dirch == '-') { + dir = askdir(ques, B_TRUE, B_TRUE); + if (dir == D_NONE) { break; } else { - int dir; - dir = chartodir(dirch); c = getcellindir(user->cell, dir); } } @@ -2912,7 +3128,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef askstring(question, '?', buf, BUFLEN, NULL); j = findjobbyname(buf); if (j) { - givejob(target, j->id, SJ_NONE); + givejob(target, j->id); msg("%s is now a %s.", lfname, j->name); } else { fizzle(user); @@ -3066,20 +3282,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } // ask for direction if (!targcell) { - char dirch; - dirch = askchar("Wild strike in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { - // yourself! - targcell = user->cell; + int dir; + dir = askdir("Wild strike in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE ; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -3089,7 +3298,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef killflag(f); } else if (abilid == OT_A_HEAVYBLOW) { object_t *wep; - char dirch; char targetname[BUFLEN]; flag_t *f,*damflag; int badweapon = B_FALSE; @@ -3119,19 +3327,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // ask for direction if (!targcell) { - dirch = askchar("Heavy blow in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { - // yourself! - targcell = user->cell; + int dir; + dir = askdir("Heavy blow in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -3148,7 +3350,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef killflag(f); } else if (abilid == OT_A_QUIVERINGPALM) { object_t *wep; - char dirch; char targetname[BUFLEN]; flag_t *f; @@ -3165,19 +3366,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // ask for direction if (!targcell) { - dirch = askchar("Quivering Palm in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { - // yourself! - targcell = user->cell; + int dir; + dir = askdir("Quivering Palm in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE ; } else { - int dir; - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -3193,7 +3388,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef killflag(f); } else if (abilid == OT_A_STEAL) { enum SKILLLEVEL slev; - char dirch; object_t *wep; char targetname[BUFLEN]; flag_t *penalty = NULL; @@ -3209,8 +3403,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // ask for direction if (!targcell) { int dir; - dirch = askchar("Steal in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE, B_TRUE); - dir = chartodir(dirch); + dir = askdir("Steal in which direction (- to cancel)", B_TRUE, B_TRUE); if (dir == D_NONE) { if (isplayer(user)) msg("Cancelled."); return B_TRUE ; @@ -3352,7 +3545,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) msg("You can't hide while swimming!"); return B_TRUE; } - if (lfhasflag(user, F_PRODUCESLIGHT)) { + if (lfproduceslight(user, NULL)) { if (isplayer(user)) msg("You can't hide while producing light!"); return B_TRUE; } @@ -3497,7 +3690,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } taketime(user, getactspeed(user)); } else if (abilid == OT_A_IRONFIST) { - char dirch,tname[BUFLEN]; + char tname[BUFLEN]; int dam,dir = D_NONE; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { @@ -3512,18 +3705,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // ask for direction if (!targcell) { - dirch = askchar("Iron fist in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if (dirch == '.') { - // yourself! - targcell = user->cell; + dir = askdir("Iron fist in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE ; } else { - dir = chartodir(dirch); - if (dir == D_NONE) { - if (isplayer(user)) msg("Cancelled."); - return B_TRUE ; - } else { - targcell = getcellindir(user->cell, dir); - } + targcell = getcellindir(user->cell, dir); } } @@ -3755,7 +3942,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // destroy WORN metal objects by the caster (not CARRIED ones) for (o = caster->pack->first ; o ; o = o->next) { - if (isequipped(o) && ismetal(o->material->id)) { + if (isequipped(o) && ismetal(o->material->id) && isweapon(o)) { takedamage(o, 9999, DT_DIRECT, caster); if (hasflag(o->flags, F_DEAD)) { totalmass += getobweight(o); @@ -3795,6 +3982,78 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } + if (totalmass > 0) { + float max; + int mptoheal; + // heal 1 mp per kilo + howmuch = floor(totalmass); + + // maximum based on power + max = 40 + (power*10); + + if (howmuch > max) howmuch = max; + + mptoheal = getmaxmp(caster) - caster->mp; + + gainmp(caster, howmuch); + + // any left? heal hp with half the remaining amt now. + howmuch -= mptoheal; + howmuch /= 2; + if (howmuch > 0) { + gainhp(caster, howmuch); + } + } else { + fizzle(caster); + return B_TRUE; + } + } else if (spellid == OT_S_ABSORBWOOD) { + int i; + float totalmass = 0; + object_t *o; + int howmuch; + // works on all metal in sight + if (isplayer(caster)) { + if (seenbyplayer) *seenbyplayer = B_FALSE; + msg("You draw power from nearby wood!"); + } else if (cansee(player, caster)) { + if (seenbyplayer) *seenbyplayer = B_FALSE; + msg("%s draws power from nearby wood!",castername); + } + totalmass = 0; + + for (i = 0; i < caster->nlos; i++) { + targcell = caster->los[i]; + // destroy wood items on the ground + for (o = targcell->obpile->first ; o ; o = o->next) { + if (o->material->id == MT_WOOD) { + takedamage(o, 9999, DT_DIRECT, caster); + if (hasflag(o->flags, F_DEAD)) { + totalmass += getobweight(o); + } + } + } + // destroy objects right away + removedeadobs(targcell->obpile); + + + // carried wood? + if (targcell->lf && (targcell->lf != caster) && + !spellresisted(targcell->lf, caster, spellid, power, seenbyplayer, B_TRUE)) { + // destroy only WORN wood objects, not CARRIED ones + for (o = targcell->lf->pack->first ; o ; o = o->next) { + if (isequipped(o) && (o->material->id == MT_WOOD)) { + takedamage(o, 9999, DT_DIRECT, caster); + if (hasflag(o->flags, F_DEAD)) { + totalmass += getobweight(o); + } + } + } + // destroy objects right away + removedeadobs(targcell->lf->pack); + } + } + if (totalmass > 0) { float max; int mptoheal; @@ -3829,13 +4088,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (targcell) { dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS); } else { - int dirch; - dirch = askchar("Airblast in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if ((dirch == '.') || (dirch == '-')) { + dir = askdir("Airblast in which direction (- to cancel)", B_TRUE, B_TRUE); + if (dir == D_NONE) { fizzle(caster); return B_TRUE; } - dir = chartodir(dirch); } // keep going that dir until the next cell is a wall/lf/impassable ob @@ -3957,9 +4214,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ newlf = makezombie(o); if (newlf) { if (isplayer(target)){ - if (skillcheck(target, A_IQ, 100, power)) { + if (caster && isgod(caster)) { makefriendly(newlf, PERMENANT); - } else if (cansee(target, newlf)) { + } else if (skillcheck(target, A_IQ, 100, power)) { + makefriendly(newlf, PERMENANT); + } else if (cansee(target, newlf) && + areenemies(target, newlf)) { msg("Uh oh, you have a bad feeling about this..."); } } @@ -4132,8 +4392,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!validatespellcell(caster, &targcell, TT_OBJECT, spellid, power, frompot)) return B_TRUE; if (targcell->obpile->first) { - // select object from cell... - targob = askobject(targcell->obpile, "Target which object", NULL, NULL, '\0', AO_NONE); + // more than object? + if (targcell->obpile->first->next) { + // select object from cell... + targob = askobject(targcell->obpile, "Target which object", NULL, NULL, '\0', AO_NONE); + } else { + targob = targcell->obpile->first; + } if (!targob) { failed = B_TRUE; } @@ -5437,7 +5702,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ object_t *o; targcell = caster->cell; target = caster; - if (getequippedob(target->pack, BP_SECWEAPON)) { + o = getequippedob(target->pack, BP_SECWEAPON); + if (o) { + if (isplayer(caster)) { + char obname[BUFLEN]; + getobname(o, obname, o->amt); + msg("Your %s shimmers like a crystal for a moment.", noprefix(obname)); + } fizzle(caster); stopspell(caster, spellid); return B_TRUE; @@ -6484,7 +6755,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ badoid[1] = OT_NONE; for (i = 0; i < amt; i++) { cell_t *c; - c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_WALLSTOP, badoid, NULL, NULL); + c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_WALLSTOP, badoid, NULL, NULL, MT_NOTHING); if (c) { object_t *water; water = addob(c->obpile, "water"); @@ -7412,6 +7683,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ break; } amt = getspellduration(min,max,blessed) + (power*2); + limit(&amt, min, max); if (undead) { losehp(target, amt, DT_HOLY, caster, "the power of healing"); @@ -8115,7 +8387,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ job_t *j; object_t *o; // create a mirror image - targcell = real_getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, caster); + targcell = real_getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, caster, MT_NOTHING); if (!targcell) break; lf = clonelf(caster, targcell); if (!lf) break; @@ -8130,7 +8402,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // copy caster's job j = getjob(caster); if (j) { - givejob(lf, j->id, SJ_NONE); + givejob(lf, j->id); } addflag(lf->flags, F_NOTIME, B_TRUE, NA, NA, NULL); lf->created = B_FALSE; // to avoid "the xxx puts on armour" messages @@ -8660,7 +8932,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (dstcell && !cellwalkable(caster, dstcell, NULL)) { - dstcell = real_getrandomadjcell(dstcell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL); + dstcell = real_getrandomadjcell(dstcell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL, MT_NOTHING); } if (dstcell) { @@ -8783,7 +9055,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (!cellwalkable(caster, targcell, NULL)) { - targcell = real_getrandomadjcell(targcell, WE_WALKABLE, B_NOEXPAND, LOF_DONTNEED, NULL, NULL, NULL); + targcell = real_getrandomadjcell(targcell, WE_WALKABLE, B_NOEXPAND, LOF_DONTNEED, NULL, NULL, NULL, MT_NOTHING); if (!targcell) { fizzle(caster); return B_FALSE; @@ -9183,7 +9455,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ object_t *srcportal,*dstportal; // find adjacent cell for portal - srccell = real_getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, caster); + srccell = real_getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, caster, MT_NOTHING); if (!srccell) { fizzle(caster); return B_TRUE; @@ -9847,7 +10119,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ getlfname(targcell->lf, lfname); msg("^%cA thick veil of mist surrounds %s!", getlfcol(targcell->lf, CC_GOOD), lfname); } else { - msg("^%cA thick veil of mist appears!", getlfcol(targcell->lf, CC_GOOD)); + msg("A thick veil of mist appears!"); } } o = addob(targcell->obpile, "thick mist"); @@ -11193,44 +11465,82 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } } else if (spellid == OT_S_SOFTENEARTH) { - int seen = B_FALSE; + int seenground = B_FALSE; + int seenwall = B_FALSE; + int seenboulder = B_FALSE; int ndone = 0; int powerleft = power; // ask for a target cell if (targcell) { - object_t *o; + object_t *o,*oo; enum OBTYPE badoid[2]; int i; - cell_t *c; - // do first cell - // TODO: is it actually earth here, not stone,metal etc? - o = addob(targcell->obpile, "pool of mud"); - if (o) { + + oo = hasob(targcell->obpile, OT_BOULDER); + while (oo && powerleft) { + removeob(oo, 1); + o = addobfast(targcell->obpile, OT_RUBBLE); ndone++; powerleft--; - if (haslos(player, targcell)) seen = B_TRUE; - // do the rest - badoid[0] = OT_MUDPOOL; - badoid[1] = OT_NONE; - for (i = 0; i < powerleft; i++) { - c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_DONTNEED, badoid, NULL, NULL); - if (c) { - o = addob(c->obpile, "pool of mud"); + if (haslos(player, targcell)) { + seenboulder++; + msg("A boulder crumbles into rubble!"); + } + oo = hasob(targcell->obpile, OT_BOULDER); + } + + if (powerleft) { + // do first cell + // is it actually earth here? + if (targcell->type->material->id == MT_STONE) { + if (targcell->type->solid) { + if (power >= 2) { + // soften into dirt + setcelltype(targcell, CT_WALLDIRT); + if (haslos(player, targcell)) seenwall = B_TRUE; + ndone++; + powerleft = 0; + } + } else { + if (targcell->type->id != CT_DIRT) setcelltype(targcell, CT_DIRT); + o = addob(targcell->obpile, "pool of mud"); if (o) { ndone++; - if (haslos(player, targcell)) seen = B_TRUE; - // do the rest + powerleft--; + if (haslos(player, targcell)) seenground = B_TRUE; + // do the rest + badoid[0] = OT_MUDPOOL; + badoid[1] = OT_NONE; + for (i = 0; i < powerleft; i++) { + cell_t *c; + c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_DONTNEED, badoid, NULL, NULL, MT_STONE); + if (c) { + if (targcell->type->id != CT_DIRT) setcelltype(targcell, CT_DIRT); + o = addob(c->obpile, "pool of mud"); + if (o) { + ndone++; + if (haslos(player, targcell)) seenground = B_TRUE; + } + } + } } - } - } - } - } + } // end if solid + } // end if material is stone + } // end if powerleft + } // end if targcell if (ndone) { - if (seen) { + if (seenground) { if (seenbyplayer) *seenbyplayer = B_TRUE; msg("The ground nearby softens into mud."); } + if (seenwall) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + msg("The walls nearby soften into dirt."); + } + if (seenboulder) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } } else { fizzle(caster); return B_TRUE; @@ -11626,6 +11936,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } return B_FALSE; + } else { + // if successful, target gets delayed so they can't just + // walk away again + taketime(target, getactspeed(target)); } } else { if (!fromob) fizzle(caster); @@ -11754,7 +12068,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else { // ie. if (power >= 5) int dir; - char dirch; cell_t *poss[MAX_MAPW * MAX_MAPH]; int nposs; int x,y; @@ -11762,12 +12075,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int xmax,ymax; // semicontrolled // ask for dir - dirch = askchar("Teleport in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); - if ((dirch == '.') || (dirch == '-') || !dirch) { + dir = askdir("Teleport in which direction (- to cancel)", B_TRUE, B_TRUE); + if ((dir == D_NONE) || (dir == D_MYSELF)) { fizzle(caster); return B_TRUE; - } else { - dir = chartodir(dirch); } // make a list of all valid cells in that dir @@ -12912,7 +13223,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ c = getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND); j = getrandomjob(B_TRUE); lf = addlf(c, R_HUMAN, target->level); - givejob(lf, j->id, SJ_NONE); + givejob(lf, j->id); getlfnamea(lf, lfname); if (cansee(player, lf)) { msg("%s appears!", lfname); @@ -13018,7 +13329,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (strlen(buf)) { if (appearonground) { cell_t *where; - where = real_getrandomadjcell(target->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, target); + where = real_getrandomadjcell(target->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, target, MT_NOTHING); if (!where) { where = target->cell; } @@ -13099,7 +13410,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (hasflag(o->flags, F_IMPASSABLE)) { cell_t *newloc; // if so, don't put it where the player is! - newloc = real_getrandomadjcell(target->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, target); + newloc = real_getrandomadjcell(target->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, target, MT_NOTHING); o = relinkob(o, newloc->obpile); } if (o) { @@ -13535,6 +13846,10 @@ char *getspellname(enum OBTYPE spellid, lifeform_t *lf, char *buf, int forcepowe if (power >= 5) { strcat(buf, "(ctrl)"); } + } else if (spellid == OT_S_SOFTENEARTH) { + if (power >= 2) { + strcat(buf, "(boost)"); + } } else if (spellid == OT_S_TELEPORT) { if (power >= 8) { strcat(buf, "(fullctrl)"); @@ -14138,13 +14453,22 @@ int schoolappearsinbooks(enum SPELLSCHOOL ss) { return B_TRUE; } -void spellcloud(cell_t *srcloc, int radius, int ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot, char *seetext, char *noseetext, int aimedateyes, object_t *fromob, int includecentre) { +void spellcloud(cell_t *srcloc, int radius, int dirtype, int ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot, char *seetext, char *noseetext, int aimedateyes, object_t *fromob, int includecentre) { int x,y; char *see = NULL, *nosee = NULL; objecttype_t *ot; + int (*distfunc)(cell_t *, cell_t *); + ot = findot(sid); if (!ot) return; + if (dirtype == DT_ORTH) { + distfunc = getcelldistorth; + } else { + distfunc = getcelldist; + } + + if (seetext) { see = strdup(seetext); } @@ -14187,7 +14511,7 @@ void spellcloud(cell_t *srcloc, int radius, int ch, enum COLOUR col, enum OBTYPE safe = B_TRUE; } if (!safe) { - if (getcelldistorth(srcloc, c) <= radius) { + if (distfunc(srcloc, c) <= radius) { // cast the spell if (ot->obclass->id == OC_SPELL) { dospelleffects(NULL, ot->id, power, c->lf, NULL, c, B_UNCURSED, NULL, frompot, fromob); @@ -14252,7 +14576,7 @@ int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power if ((spellid == OT_S_SLEEP) && lfhasflag(target, F_RAGE)) { bonus += 10; } - if (caster && hassubjob(caster, SJ_SCOURGE) && (spellid == OT_S_NULLIFY)) { + if (caster && hasjob(caster, J_SCOURGE) && (spellid == OT_S_NULLIFY)) { // cancel out the difficulty from NULLIFY being a level 4 spell bonus += 8; } @@ -14394,7 +14718,7 @@ int summonlfs(lifeform_t *caster, cell_t *where, enum RACE wantrace, enum RACECL for (i = 0; i < howmany; i++) { // get random adjacent cell // (prefer cells in sight of caster) - c = real_getrandomadjcell(where, WE_EMPTY, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, caster); + c = real_getrandomadjcell(where, WE_EMPTY, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, caster, MT_NOTHING); if (!c) { return ncreated; } diff --git a/spell.h b/spell.h index 5c92eb7..6c28183 100644 --- a/spell.h +++ b/spell.h @@ -36,7 +36,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, int ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot, char *seetext, char *noseetext, int aimedateyes, object_t *fromob, int includecentre); +void spellcloud(cell_t *srcloc, int radius, int dirtype, int ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot, char *seetext, char *noseetext, int aimedateyes, object_t *fromob, int includecentre); int spellisfromschool(int spellid, enum SPELLSCHOOL school); int spellokformonsters(int spellid); int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power, int *seenbyplayer, int announce); diff --git a/text.c b/text.c index 41da4c1..e307035 100644 --- a/text.c +++ b/text.c @@ -54,6 +54,66 @@ plural_t *addplural(char *singulartext, char *pluraltext, int stopafter) { return a; } +void addengineeringinfo(lifeform_t *lf, char *buf, cell_t *c) { + enum SKILLLEVEL slev; + char newbuf[BUFLEN]; + strcpy(newbuf, ""); + slev = getskill(lf, SK_ENGINEERING); + if (slev >= PR_NOVICE) { + int cdiff = NA; + int slip = 0; + slip = getslipperyness(c, NULL); + if (slip > 0) { + char tempbuf[BUFLEN]; + if (strlen(newbuf)) strcat(newbuf, ","); + sprintf(tempbuf, "slippery:%d%%",slip); + strcat(newbuf, tempbuf); + } else if (slip < 0) { + if (strlen(newbuf)) strcat(newbuf, ","); + char tempbuf[BUFLEN]; + sprintf(tempbuf, "stable:%d%%",abs(slip)); + strcat(newbuf, tempbuf); + } + + if (c->type->solid) { + cdiff = getcellclimbdifficulty(c); + } + if (cdiff == NA) { + object_t *o; + o = hasobwithflag(c->obpile, F_CLIMBOBSTACLE); + if (o) { + flag_t *f; + f = hasflag(o->flags, F_CLIMBOBSTACLE); + if (f) { // should always be true + cdiff = f->val[0]; + } + } + } + + if (cdiff != NA) { + char tempbuf[BUFLEN]; + if (strlen(newbuf)) strcat(newbuf, ","); + sprintf(tempbuf, "climb diff:%d%%",cdiff); + strcat(newbuf, tempbuf); + } + + } + if (slev >= PR_BEGINNER) { + if (c->hp != -1) { + char tempbuf[BUFLEN]; + if (strlen(newbuf)) strcat(newbuf, ","); + sprintf(tempbuf, "hp:%d",c->hp); + strcat(newbuf, tempbuf); + } + } + + if (strlen(newbuf)) { + strcat(buf, "("); + strcat(buf, newbuf); + strcat(buf, ")"); + } +} + int needan(char *text) { if (isvowel(tolower(text[0]))) { return B_TRUE; @@ -1145,6 +1205,28 @@ int gethitconferlifetime(char *text, int *min, int *max) { return howlong; } +char *getjobcatname(enum JOBCATEGORY jc) { + switch (jc) { + case JC_GENERAL: + return "Generalist"; + case JC_FIGHTER: + return "Fighter"; + case JC_FIGHTERMAGE: + return "Fighter/Mage"; + case JC_FIGHTERTHIEF: + return "Fighter/Thief"; + case JC_FIGHTERRANGED: + return "Ranged Fighter"; + case JC_MAGE: + return "Mage"; + case JC_THIEF: + return "Thief"; + default: + break; + } + return "None"; +} + char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp) { float pct; pct = (int)(((float) dam / (float) maxhp) * 100.0); @@ -1276,6 +1358,30 @@ char *getpossessive(char *text) { return "'s"; } +char *getdrunkdesc(lifeform_t *lf, flag_t *drunkflag, char *buf) { + int agimod, wismod; + char agibuf[BUFLEN], wisbuf[BUFLEN], dambuf[BUFLEN]; + + strcpy(buf, ""); + // agi / wis mod + agimod = getdrunkattrmod(lf, A_AGI, drunkflag->val[0]); + wismod = getdrunkattrmod(lf, A_WIS, drunkflag->val[0]); + sprintf(agibuf, "%s%d Agi", (agimod >= 0) ? "+" : "", agimod); + sprintf(wisbuf, "%s%d Wis", (wismod >= 0) ? "+" : "", wismod); + + // damage mod + if (drunkflag->val[0] == 1) { + sprintf(dambuf, "1 damage reduction"); + } else { + sprintf(dambuf, "1-%d damage reduction", drunkflag->val[0]); + } + + // full + sprintf(buf, "%s, %s, %s, mental immunity", dambuf, agibuf, wisbuf); + + return buf; +} + char *getdrunktext(flag_t *drunkflag) { int bracket; bracket = (drunkflag->lifetime / TM_DRUNKTIME) + 1; @@ -1879,6 +1985,17 @@ char *getweighttext(float weight, char *buf, int shortfmt) { return buf; } +int hoursto12(int h) { + int twelveh; + if (h > 12) { + twelveh = h - 12; + } else { + twelveh = h; + } + if (twelveh == 0) twelveh = 12; + return twelveh; +} + char *is(lifeform_t *lf) { if (isplayer(lf)) return "are"; else return "is"; @@ -2758,6 +2875,20 @@ int texttospellopts(char *text, ... ) { return nfilled; } +int timeisbetween(int h, int start, int end) { + int hh = start; + if (h == hh) return B_TRUE; + while (hh != end) { + // increment hour being checked + if (++hh >= 24) { + hh = 0; + } + // check... + if (h == hh) return B_TRUE; + } + return B_FALSE; +} + char *you(lifeform_t *lf) { if (isplayer(lf)) { return "You"; diff --git a/text.h b/text.h index 885c172..cf3e5dd 100644 --- a/text.h +++ b/text.h @@ -1,6 +1,7 @@ #include "defs.h" plural_t *addplural(char *singulartext, char *pluraltext, int stopafter); +void addengineeringinfo(lifeform_t *lf, char *buf, cell_t *c); int needan(char *text); char *capitalise(char *text); char *capitaliseall(char *text); @@ -25,12 +26,14 @@ void getdisttext(cell_t *src, cell_t *dst,char *distbuf, char *distbufapprox, ch char *getfillingname(int nutrition); char *getflagsourcetext(flag_t *f); int gethitconferlifetime(char *text, int *min, int *max); +char *getjobcatname(enum JOBCATEGORY jc); char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp); char *getpctname(int pct); char *getpoisondamverb(enum POISONTYPE ptype); //char *getpoisondesc(enum POISONTYPE ptype); //char *getpoisonname(enum POISONTYPE ptype); char *getpossessive(char *text); +char *getdrunkdesc(lifeform_t *lf, flag_t *drunkflag, char *buf); char *getdrunktext(flag_t *drunkflag); char *getilluminationdesc(enum ILLUMINATION il); char *getinjuredbpname(enum BODYPART bp); @@ -49,6 +52,7 @@ char *gettimetext(char *retbuf); char *gettimetextfuzzy(char *retbuf, int wantpm); char *getwaterdepthname(enum DEPTH d); char *getweighttext(float weight, char *buf, int shortfmt); +int hoursto12(int h); char *is(lifeform_t *lf); char *it(lifeform_t *lf); int isvowel(char c); @@ -82,6 +86,7 @@ int strpixmatch(char *haystack, char *needle); enum VAULTTHING strtovt(char *text); int texttodice(char *text, int *ndice, int *nsides, int *bonus); int texttospellopts(char *text, ... ); +int timeisbetween(int h, int start, int end); //void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range, char *racestr); char *you(lifeform_t *lf); char *you_l(lifeform_t *lf); diff --git a/vault.c b/vault.c index cc32bd6..fd77ef0 100644 --- a/vault.c +++ b/vault.c @@ -1760,7 +1760,7 @@ int real_vaultthingok(enum VAULTTHING vt, char *what, int *hasfire) { return B_TRUE; } else { enum RACE rid; - rid = parserace(what, NULL, NULL, NULL, NULL); + rid = parserace(what, NULL, NULL, NULL); if (rid) { if (hasfire) { r = findrace(rid);