diff --git a/ai.c b/ai.c index c33f5f3..a1b6ee7 100644 --- a/ai.c +++ b/ai.c @@ -1043,7 +1043,7 @@ int aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim } cell_t *aigettargetcell(lifeform_t *lf, flag_t **targflag) { - flag_t *f; + flag_t *f = NULL; if (targflag) { *targflag = NULL; @@ -1856,7 +1856,7 @@ int ai_movement(lifeform_t *lf) { // do we have a target cell? c = aigettargetcell(lf, &f); - if (!f) return B_FALSE; + if (!f) return B_FALSE; // ooo is f bad here? // is it still valid? if (!c) { @@ -1887,6 +1887,8 @@ int ai_movement(lifeform_t *lf) { // always ok. } else if (f->val[2] == MR_BACKTOLAIR) { // always ok. + } else if (f->val[2] == MR_OTHER) { + // always ok. } else { // weird ? raise (SIGINT); @@ -2362,6 +2364,9 @@ int aimovetotargetcell(lifeform_t *lf, flag_t *f) { cell_t *c = NULL,*origc,*targetc; int db = B_FALSE; enum ATTRBRACKET iqb; + + assert(f->id <= F_LAST); + iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL); checkflagpile_maplfs(lf->cell->map); diff --git a/data.c b/data.c index fe422b3..a8c3031 100644 --- a/data.c +++ b/data.c @@ -206,6 +206,7 @@ void initcommands(void) { addcommand(CMD_NEXTTARGET, '\'', "Cycle to next firearm target."); // Information addcommand(CMD_HELP, '?', "Display this text."); + addcommand(CMD_COUNTMONEY, '$', "Count your funds."); addcommand(CMD_INFOPLAYER, '@', "Display player stats."); addcommand(CMD_INFOARMOUR, ']', "Display player armour."); addcommand(CMD_FORCEATTACK, 'A', "Force an attack in a given direction."); @@ -1391,6 +1392,7 @@ void initjobs(void) { 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_CANSTUDY, SS_AIR, NA, NA, NULL); 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 @@ -1451,6 +1453,7 @@ void initjobs(void) { 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_CANSTUDY, SS_FIRE, 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); @@ -1511,6 +1514,7 @@ void initjobs(void) { 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_CANSTUDY, SS_COLD, 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); @@ -1571,6 +1575,7 @@ void initjobs(void) { 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_CANSTUDY, SS_DEATH, NA, NA, NULL); 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 @@ -1628,6 +1633,7 @@ void initjobs(void) { 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_CANSTUDY, SS_WILD, 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); @@ -4323,7 +4329,7 @@ void initobjects(void) { // elemental - air /////////////////// // l1 - addot(OT_S_TRUESTRIKE, "weapon attraction", "Wind currents gives the target unerring accuracy, making their attacks always hit and negating strength penalties.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_TRUESTRIKE, "guided weapon", "Wind currents give the target unerring accuracy, making their attacks always hit and negating strength penalties.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the amount of strikes before it expires."); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -21014,7 +21020,7 @@ void initskills(void) { // spell schools addskill(SK_SS_ALLOMANCY, "Allomancy", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_ALLOMANCY, PR_INEPT, "- Spell power power depends on your Level and Strength.", B_FALSE); + addskilldesc(SK_SS_ALLOMANCY, PR_INEPT, "- Spell power depends on your Level and Strength.", B_FALSE); addskilldesc(SK_SS_ALLOMANCY, PR_INEPT, "- Each rank gives you a 20% chance to learn a new allomantic ability when levelling up.", B_FALSE); addskilldesc(SK_SS_ALLOMANCY, PR_NOVICE, "Allows you to cast Allomancy spells up to level 1.", B_FALSE); addskilldesc(SK_SS_ALLOMANCY, PR_BEGINNER, "Allows you to cast Allomancy spells up to level 2.", B_FALSE); @@ -21023,7 +21029,7 @@ void initskills(void) { addskilldesc(SK_SS_ALLOMANCY, PR_EXPERT, "Allows you to cast Allomancy spells up to level 5.", B_FALSE); addskilldesc(SK_SS_ALLOMANCY, PR_MASTER, "Allows you to cast Allomancy spells up to level 6.", B_FALSE); addskill(SK_SS_MENTAL, "Psionics", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_MENTAL, PR_INEPT, "- Spell power power depends on your Level and Intelligence.", B_FALSE); + addskilldesc(SK_SS_MENTAL, PR_INEPT, "- Spell power depends on your Level and Intelligence.", B_FALSE); addskilldesc(SK_SS_MENTAL, PR_INEPT, "- Each rank gives you a 20% chance to learn a new psionic ability when levelling up.", B_FALSE); addskilldesc(SK_SS_MENTAL, PR_NOVICE, "Allows you to cast Psionic spells up to level 1.", B_FALSE); addskilldesc(SK_SS_MENTAL, PR_BEGINNER, "Allows you to cast Psionic spells up to level 2.", B_FALSE); @@ -21032,7 +21038,7 @@ void initskills(void) { addskilldesc(SK_SS_MENTAL, PR_EXPERT, "Allows you to cast Psionic spells up to level 5.", B_FALSE); addskilldesc(SK_SS_MENTAL, PR_MASTER, "Allows you to cast Psionic spells up to level 6.", B_FALSE); addskill(SK_SS_NATURE, "Enviromancy", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_NATURE, PR_INEPT, "- Spell power power depends on your Level and Wisdom.", B_FALSE); + addskilldesc(SK_SS_NATURE, PR_INEPT, "- Spell power depends on your Level and Wisdom.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_NOVICE, "Allows you to cast Nature spells up to level 1.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_BEGINNER, "Allows you to cast Nature spells up to level 2.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_ADEPT, "Allows you to cast Nature spells up to level 3.", B_FALSE); @@ -21040,7 +21046,7 @@ void initskills(void) { addskilldesc(SK_SS_NATURE, PR_EXPERT, "Allows you to cast Nature spells up to level 5.", B_FALSE); addskilldesc(SK_SS_NATURE, PR_MASTER, "Allows you to cast Nature spells up to level 6.", B_FALSE); addskill(SK_SS_AIR, "Sorcery:Air Magic", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_AIR, PR_INEPT, "- Spell power power depends on your Level and Intelligence.", B_FALSE); + addskilldesc(SK_SS_AIR, PR_INEPT, "- Spell power depends on your Level and Intelligence.", B_FALSE); addskilldesc(SK_SS_AIR, PR_NOVICE, "Allows you to cast Air Magic spells up to level 1.", B_FALSE); addskilldesc(SK_SS_AIR, PR_BEGINNER, "Allows you to cast Air Magic spells up to level 2.", B_FALSE); addskilldesc(SK_SS_AIR, PR_ADEPT, "Allows you to cast Air Magic spells up to level 3.", B_FALSE); @@ -21048,7 +21054,7 @@ void initskills(void) { addskilldesc(SK_SS_AIR, PR_EXPERT, "Allows you to cast Air Magic spells up to level 5.", B_FALSE); addskilldesc(SK_SS_AIR, PR_MASTER, "Allows you to cast Air Magic spells up to level 6.", B_FALSE); addskill(SK_SS_DEATH, "Sorcery:Necromancy", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_DEATH, PR_INEPT, "- Spell power power depends on your Level, your Intelligence, and Hecta's pleasure.", B_FALSE); + addskilldesc(SK_SS_DEATH, PR_INEPT, "- Spell power depends on your Level, your Intelligence, and Hecta's pleasure.", B_FALSE); addskilldesc(SK_SS_DEATH, PR_NOVICE, "Allows you to cast Necromancy spells up to level 1.", B_FALSE); addskilldesc(SK_SS_DEATH, PR_BEGINNER, "Allows you to cast Necromancy spells up to level 2.", B_FALSE); addskilldesc(SK_SS_DEATH, PR_ADEPT, "Allows you to cast Necromancy spells up to level 3.", B_FALSE); @@ -21056,7 +21062,7 @@ void initskills(void) { addskilldesc(SK_SS_DEATH, PR_EXPERT, "Allows you to cast Necromancy spells up to level 5.", B_FALSE); addskilldesc(SK_SS_DEATH, PR_MASTER, "Allows you to cast Necromancy spells up to level 6.", B_FALSE); addskill(SK_SS_DIVINATION, "Sorcery:Divination", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_DIVINATION, PR_INEPT, "- Spell power power depends on your Level and Intelligence.", B_FALSE); + addskilldesc(SK_SS_DIVINATION, PR_INEPT, "- Spell power depends on your Level and Intelligence.", B_FALSE); addskilldesc(SK_SS_DIVINATION, PR_NOVICE, "Allows you to cast Divination spells up to level 1.", B_FALSE); addskilldesc(SK_SS_DIVINATION, PR_BEGINNER, "Allows you to cast Divination spells up to level 2.", B_FALSE); addskilldesc(SK_SS_DIVINATION, PR_ADEPT, "Allows you to cast Divination spells up to level 3.", B_FALSE); @@ -21064,7 +21070,7 @@ void initskills(void) { addskilldesc(SK_SS_DIVINATION, PR_EXPERT, "Allows you to cast Divination spells up to level 5.", B_FALSE); addskilldesc(SK_SS_DIVINATION, PR_MASTER, "Allows you to cast Divination spells up to level 6.", B_FALSE); addskill(SK_SS_FIRE, "Sorcery:Fire Magic", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_FIRE, PR_INEPT, "- Spell power power depends on your Level and Intelligence.", B_FALSE); + addskilldesc(SK_SS_FIRE, PR_INEPT, "- Spell power depends on your Level and Intelligence.", B_FALSE); addskilldesc(SK_SS_FIRE, PR_NOVICE, "Allows you to cast Fire Magic spells up to level 1.", B_FALSE); addskilldesc(SK_SS_FIRE, PR_BEGINNER, "Allows you to cast Fire Magic spells up to level 2.", B_FALSE); addskilldesc(SK_SS_FIRE, PR_ADEPT, "Allows you to cast Fire Magic spells up to level 3.", B_FALSE); @@ -21072,7 +21078,7 @@ void initskills(void) { addskilldesc(SK_SS_FIRE, PR_EXPERT, "Allows you to cast Fire Magic spells up to level 5.", B_FALSE); addskilldesc(SK_SS_FIRE, PR_MASTER, "Allows you to cast Fire Magic spells up to level 6.", B_FALSE); addskill(SK_SS_COLD, "Sorcery:Cold Magic", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_COLD, PR_INEPT, "- Spell power power depends on your Level and Intelligence.", B_FALSE); + addskilldesc(SK_SS_COLD, PR_INEPT, "- Spell power depends on your Level and Intelligence.", B_FALSE); addskilldesc(SK_SS_COLD, PR_NOVICE, "Allows you to cast Cold Magic spells up to level 1.", B_FALSE); addskilldesc(SK_SS_COLD, PR_BEGINNER, "Allows you to cast Cold Magic spells up to level 2.", B_FALSE); addskilldesc(SK_SS_COLD, PR_ADEPT, "Allows you to cast Cold Magic spells up to level 3.", B_FALSE); @@ -21080,7 +21086,7 @@ void initskills(void) { addskilldesc(SK_SS_COLD, PR_EXPERT, "Allows you to cast Cold Magic spells up to level 5.", B_FALSE); addskilldesc(SK_SS_COLD, PR_MASTER, "Allows you to cast Cold Magic spells up to level 6.", B_FALSE); addskill(SK_SS_LIFE, "Sorcery:Life Magic", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_LIFE, PR_INEPT, "- Spell power power depends on your Level, your Intelligence, and Glorana's pleasure.", B_FALSE); + addskilldesc(SK_SS_LIFE, PR_INEPT, "- Spell power depends on your Level, your Intelligence, and Glorana's pleasure.", B_FALSE); addskilldesc(SK_SS_LIFE, PR_NOVICE, "Allows you to cast Life Magic spells up to level 1.", B_FALSE); addskilldesc(SK_SS_LIFE, PR_BEGINNER, "Allows you to cast Life Magic spells up to level 2.", B_FALSE); addskilldesc(SK_SS_LIFE, PR_ADEPT, "Allows you to cast Life Magic spells up to level 3.", B_FALSE); @@ -21088,7 +21094,7 @@ void initskills(void) { addskilldesc(SK_SS_LIFE, PR_EXPERT, "Allows you to cast Life Magic spells up to level 5.", B_FALSE); addskilldesc(SK_SS_LIFE, PR_MASTER, "Allows you to cast Life Magic spells up to level 6.", B_FALSE); addskill(SK_SS_SUMMONING, "Sorcery:Summoning", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_SUMMONING, PR_INEPT, "- Spell power power depends on your Level and Intelligence.", B_FALSE); + addskilldesc(SK_SS_SUMMONING, PR_INEPT, "- Spell power depends on your Level and Intelligence.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_NOVICE, "Allows you to cast Summoning spells up to level 1.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_BEGINNER, "Allows you to cast Summoning spells up to level 2.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_ADEPT, "Allows you to cast Summoning spells up to level 3.", B_FALSE); @@ -21096,7 +21102,7 @@ void initskills(void) { addskilldesc(SK_SS_SUMMONING, PR_EXPERT, "Allows you to cast Summoning spells up to level 5.", B_FALSE); addskilldesc(SK_SS_SUMMONING, PR_MASTER, "Allows you to cast Summoning spells up to level 6.", B_FALSE); addskill(SK_SS_TRANSLOCATION, "Sorcery:Translocation", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_TRANSLOCATION, PR_INEPT, "- Spell power power depends on your Level and Intelligence.", B_FALSE); + addskilldesc(SK_SS_TRANSLOCATION, PR_INEPT, "- Spell power depends on your Level and Intelligence.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_NOVICE, "Allows you to cast Translocation spells up to level 1.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_BEGINNER, "Allows you to cast Translocation spells up to level 2.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_ADEPT, "Allows you to cast Translocation spells up to level 3.", B_FALSE); @@ -21104,7 +21110,7 @@ void initskills(void) { addskilldesc(SK_SS_TRANSLOCATION, PR_EXPERT, "Allows you to cast Translocation spells up to level 5.", B_FALSE); addskilldesc(SK_SS_TRANSLOCATION, PR_MASTER, "Allows you to cast Translocation spells up to level 6.", B_FALSE); addskill(SK_SS_WILD, "Sorcery:Wild Magic", "Boosts casting of spells from this school.", 50); - addskilldesc(SK_SS_WILD, PR_INEPT, "- Spell power power depends on your Level and Intelligence.", B_FALSE); + addskilldesc(SK_SS_WILD, PR_INEPT, "- Spell power depends on your Level and Intelligence.", B_FALSE); addskilldesc(SK_SS_WILD, PR_NOVICE, "Allows you to cast Wild Magic spells up to level 1.", B_FALSE); addskilldesc(SK_SS_WILD, PR_BEGINNER, "Allows you to cast Wild Magic spells up to level 2.", B_FALSE); addskilldesc(SK_SS_WILD, PR_ADEPT, "Allows you to cast Wild Magic spells up to level 3.", B_FALSE); diff --git a/defs.h b/defs.h index afa7986..e4d8f81 100644 --- a/defs.h +++ b/defs.h @@ -38,6 +38,7 @@ #define TEXT_WARN_FLY "Warning: while airborne you will not map your surroundings." #define TEXT_WARN_MUTABLE "(you can now gain attributes by eating corpses)" #define TEXT_WARN_NOXP_GOODVSPEACEFUL "Warning: Only Evil players gain XP for peaceful kills." +#define TEXT_WARN_TRAIN_NOBOOK "You will not be able to study spells without a spellbook. Really train?" // F_SCOREBONUS text args #define SCB_DONATIONS "charitable donations" @@ -3722,6 +3723,7 @@ enum FLAG { F_AUTOCMD, // val0 = how many times to repeat this F_LASTCMD, // text[0] = last command performed, v0/1 = x/y of cell, v2=various F_WILLTHROW, // this lf will treat obid v0 as a thrown missile. + F_CANSTUDY, // lf can study spells from school v0 F_CANLEARN, // lf is able to learn skill val0 // v1 = max lev F_STAMBOOST, // lf gets v0 extra stamina @@ -4758,6 +4760,7 @@ enum COMMAND { CMD_WEAR, CMD_WEILD, CMD_EXCHANGE, + CMD_COUNTMONEY, }; typedef struct condset_s { diff --git a/io.c b/io.c index c647e35..74cae6d 100644 --- a/io.c +++ b/io.c @@ -5420,6 +5420,53 @@ void docomms_areadangers(char *who, flagpile_t *fp, lifeform_t *lf) { msg("\"I know of no %sdangers in this area.\"", (totdone) ? "other " : ""); } +void docountmoney(lifeform_t *lf) { + int goldamt = 0,gemamt = 0,credit = 0; + int unknowncredit = 0; + char goldbuf[BUFLEN], gembuf[BUFLEN],creditbuf[BUFLEN]; + object_t *o; + goldamt = countmoney(lf->pack); + + for (o = lf->pack->first ; o ; o = o->next) { + if (hasflag(o->flags, F_GEM)) { + gemamt += getobvalue(o); + } else if (o->type->id == OT_CREDITCARD) { + if (isidentified(o)) { + credit += getcharges(o); + } else { + unknowncredit++; + } + } + } + + if (gemamt) { + snprintf(gembuf, BUFLEN, ", $%d worth of gemstones", gemamt); + } else { + strcpy(gembuf, ""); + } + if (credit) { + if (unknowncredit) { + snprintf(creditbuf, BUFLEN, " and at least $%d credit", credit); + } else { + snprintf(creditbuf, BUFLEN, " and $%d credit", credit); + } + } else if (unknowncredit) { + if (unknowncredit == 1) { + snprintf(creditbuf, BUFLEN, " and a stolen credit card"); + } else { + snprintf(creditbuf, BUFLEN, " and %d stolen credit cards", unknowncredit); + } + } else { + strcpy(creditbuf, ""); + } + if (goldamt == 0) { + sprintf(goldbuf, "no money"); + } else { + sprintf(goldbuf, "$%d", goldamt); + } + msg("You have %s%s%s.", goldbuf, gembuf, creditbuf); +} + void dodrop(obpile_t *op, int wantmulti, obpile_t *dst) { object_t *o; char buf[BUFLEN]; @@ -7722,7 +7769,7 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf, " - %s", contentname); if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { char lbuf[BUFLEN]; - sprintf(lbuf, " (Lv %d)%s", getspelllevel(oo->type->id), + sprintf(lbuf, " (Lv %d %s)%s", getspelllevel(oo->type->id), getschoolname(getspellschool(oo->type->id)), lfhasflagval(player, F_CANCAST, oo->type->id, NA, NA, NULL) ? " [known]" : ""); strcat(buf, lbuf); @@ -11170,6 +11217,9 @@ void handleinput(void) { case CMD_INV: // inventory doinventory(player->pack); break; + case CMD_COUNTMONEY: // count money + docountmoney(player); + break; case CMD_INFOPLAYER: // display player stats showlfstats(player, B_FALSE); break; diff --git a/io.h b/io.h index de6ca35..e32bb2d 100644 --- a/io.h +++ b/io.h @@ -57,6 +57,7 @@ void docomms(lifeform_t *target); void docommslf(lifeform_t *lf, char ch, lifeform_t *lf2, cell_t *targc); void docomms_areainfo(char *who, flagpile_t *fp, lifeform_t *lf); void docomms_areadangers(char *who, flagpile_t *fp, lifeform_t *lf); +void docountmoney(lifeform_t *lf); void dodrop(obpile_t *op, int wantmulti, obpile_t *dst); void doeat(obpile_t *op); void doenter(lifeform_t *lf); diff --git a/lf.c b/lf.c index 89aeedd..bd8ab9e 100644 --- a/lf.c +++ b/lf.c @@ -719,6 +719,12 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { flag_t *f; objecttype_t *ot; int stamcost = 0; + + if (mpcost) { + // default to base cost + *mpcost = getmpcost(lf, oid); + } + if (lfhasflag(lf, F_SILENCED)) { reason = E_SILENCED; return B_FALSE; @@ -1565,6 +1571,48 @@ int cansleep(lifeform_t *lf) { return B_TRUE; } +int canstudyspell(lifeform_t *lf, enum OBTYPE spellid) { + //object_t *o; + //int hasbook = B_FALSE; + enum SPELLSCHOOL school; + school = getspellschool(spellid); + + switch (school) { + case SS_NATURE: + case SS_ALLOMANCY: + case SS_LIFE: + case SS_MENTAL: + return B_FALSE; + default: + break; + } + + if (!lfhasflagval(lf, F_CANSTUDY, school, NA, NA, NULL)) return B_FALSE; + + /* + // must have a spellbook to record the spell in. + for (o = lf->pack->first ; o ; o = o->next) { + if (o->type->id == OT_SPELLBOOK) { + if (hasflagval(o->flags, F_LINKSCHOOL, school, NA, NA, NULL)) { + hasbook = B_TRUE; + } + } else if (o->type->id == OT_GRIMOIRE) { + hasbook = B_TRUE; + } + } + + if (!hasbook) return B_FALSE; + */ + + + if (lf->skillpoints < getspelllevel(spellid)) return B_FALSE; // too high a level + + if (!spelllearnable(lf, spellid)) return B_FALSE; // too high powered ? + + + return B_TRUE; +} + int canthrow(lifeform_t *lf, object_t *o, enum ERROR *why) { flag_t *f; if (why) *why = E_OK; @@ -5766,7 +5814,10 @@ void enhanceskills(lifeform_t *lf) { char eorl = 'e'; int skillstoenhance = 0; int skillstolearn = 0; + int magictolearn = 0; int done = B_FALSE; + obpile_t *spells; + objecttype_t *ot; skillstoenhance = 0; for (f = lf->flags->first ; f ; f = f->next) { @@ -5786,28 +5837,57 @@ void enhanceskills(lifeform_t *lf) { } } + // construct list of spells you can study + // + // can study a spell if: + // - it's not a nature spell. + // - player can't already cast it + // - player is skilled in at least one of the spell's schools. + // - player is a high enough level to cast the spell. + // - player has sufficient training points + magictolearn = 0; + spells = addobpile(NOOWNER, NOLOC, NULL); - while (!done && lf->skillpoints && (skillstolearn || skillstoenhance)) { + for (ot = objecttype ; ot ; ot = ot->next) { + if (ot->obclass->id != OC_SPELL) continue; + if (!canstudyspell(lf, ot->id)) continue; + + // spell is learnable - add to the list + addobfast(spells, ot->id); + magictolearn++; + } + + while (!done && lf->skillpoints && (skillstolearn || skillstoenhance || magictolearn)) { + char q[BUFLEN],buf2[BUFLEN],validchars[BUFLEN]; + char defchar[BUFLEN]; + + strcpy(q, ""); + strcpy(validchars, "n"); + strcpy(defchar, "n"); if (skillstolearn) { - char buf[BUFLEN]; - if (skillstoenhance) { - snprintf(buf, BUFLEN, "(E)nhance skills, (L)earn skills, or (N)one (%d points left)?",lf->skillpoints); - eorl = askchar(buf,"eln","e", B_TRUE, B_FALSE); - } else { - snprintf(buf, BUFLEN,"Learn a new skill (%d points left)?",lf->skillpoints); - ch = askchar(buf,"yn","y", B_TRUE, B_FALSE); - if (ch == 'y') eorl = 'l'; - else eorl = 'n'; - } - } else if (skillstoenhance) { - char buf[BUFLEN]; - snprintf(buf, BUFLEN,"Enhance your current skills (%d points left)?",lf->skillpoints); - ch = askchar(buf,"yn","y", B_TRUE, B_FALSE); - if (ch == 'y') eorl = 'e'; - else eorl = 'n'; - } else { - eorl = 'n'; + strcat(q, "(E)nhance"); + strcat(validchars, "e"); + strcpy(defchar, "e"); } + if (skillstoenhance) { + if (strlen(q)) { + strcat(q, "/"); + } + strcat(q, "(L)earn"); + strcat(validchars, "l"); + } + strcat(q, " skills"); + + if (magictolearn && !lfhasflag(lf, F_NOSPELLS)) { + strcat(q, ", study (M)agic"); + strcat(validchars, "m"); + } + + strcat(q, " or (N)one"); + snprintf(buf2, BUFLEN, " [%d trn left]",lf->skillpoints); // ooo add color? + strcat(q, buf2); + + eorl = askchar(q,validchars,defchar, B_TRUE, B_FALSE); if (eorl == 'e') { // enhance an existing skill @@ -5905,10 +5985,113 @@ void enhanceskills(lifeform_t *lf) { msg("There is nothing more that you can learn."); } } + } else if (eorl == 'm') { + object_t *o = NULL; + int schoolok[SS_LAST],i; + // select a magic spell + + // get a list of possible schools + for (i = 0; i < SS_LAST; i++) { + schoolok[i] = B_FALSE; + } + for (o = spells->first ; o ; o = o->next) { + enum SPELLSCHOOL school; + school = getspellschoolknown(lf, o->type->id); + schoolok[school] = B_TRUE; + } + + // ask which school + initprompt(&prompt, "Learn a spell from which school?"); + ch = 'a'; + for (i = 0; i < SS_LAST; i++) { + if (schoolok[i]) { + addchoice(&prompt, i, getschoolname(i), NULL, NULL, NULL); + } + } + addchoice(&prompt, '\0', "(none)", NULL, NULL, NULL); + ch = getchoicestr(&prompt, B_FALSE, B_TRUE); + + if (ch != '\0') { + char ques[BUFLEN]; + snprintf(ques, BUFLEN, "Learn which spell (%d point%s left)?", lf->skillpoints, + (lf->skillpoints == 1) ? "" : "s"); + + initprompt(&prompt, ques); + + // ask which spell from that school + for (o = spells->first ; o ; o = o->next) { + enum SPELLSCHOOL school; + school = getspellschoolknown(lf, o->type->id); + if (school == ch) { + char buf[BUFLEN]; + snprintf(buf, BUFLEN, "%s (%s) [%d points]", o->type->name, + getschoolname(school), + getspelllevel(o->type->id) ); + + addchoice(&prompt, o->type->id, o->type->name, buf, o, NULL); + } + } + addchoice(&prompt, '-', "(none)", NULL, NULL, NULL); + + getchoicestr(&prompt, B_FALSE, B_TRUE); + o = prompt.result; + if (o) { + if (prompt.whichq == 0) { + + learnspell(lf, o->type->id, B_TRUE); + player->skillpoints -= getspelllevel(o->type->id); + done = B_TRUE; + + /* + char bookname[BUFLEN]; + enum SPELLSCHOOL school; + school = getspellschoolknown(lf, o->type->id); + object_t *book; + + // add it to a spellbook. + snprintf(ques, BUFLEN, "Which spellbook will you record '%s' in?", o->type->name); + initprompt(&prompt, ques); + for (book = lf->pack->first ; book ; book = book->next) { + int ok = B_FALSE; + if (book->type->id == OT_SPELLBOOK) { + if (hasflagval(book->flags, F_LINKSCHOOL, school, NA, NA, NULL)) { + ok = B_TRUE; + } + } else if (book->type->id == OT_GRIMOIRE) { + ok = B_TRUE; + } + + if (ok) { + addchoice(&prompt, book->letter, book->type->name, NULL, book, NULL); + } + } + + // prompt for which spellbook. + if (prompt.nchoices == 1) { + book = prompt.choice[0].data; + } else { + getchoice(&prompt); + book = (object_t *)prompt.result; + } + assert(book != NULL); + addobfast(book->contents, o->type->id); + + getobname(book, bookname, 1); + msg("'%s' added to %s.", o->type->name, bookname); + */ + } else { + describespell(o->type); + } + } + } } else if (eorl == 'n') { done = B_TRUE; } // end enhance/learnnew } // whiel skillstolearn || skillstoenhance + + // free list of possible spells + killobpile(spells); + statdirty = B_TRUE; } else if (lf->skillpoints) { // monsters will just enhance a random skill, they never learn new ones. @@ -5946,8 +6129,7 @@ void enhanceskills(lifeform_t *lf) { ff = giveskill(lf, f->val[1]); ff->fromlev = lf->level; } else if ((f->id == F_LEVSPELL) && !lfhasflag(lf, F_NOSPELLS)) { - ff = addtempflag(lf->flags, F_CANCAST, f->val[1], NA, NA, NULL, FROMJOB); - ff->fromlev = lf->level; + learnspell(lf, f->val[1], B_TRUE); } else if ((f->id == F_LEVSPELLSCHOOL) && !lfhasflag(lf, F_NOSPELLS)) { // select a spell from school if (isplayer(lf)) { select_new_spell(f->val[1], lf->level); @@ -5959,8 +6141,7 @@ void enhanceskills(lifeform_t *lf) { // pick one randomly ot = (objecttype_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data; if (ot) { - ff = addtempflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL, FROMJOB); - ff->fromlev = lf->level; + learnspell(lf, ot->id, B_TRUE); } } } @@ -6031,8 +6212,7 @@ void enhanceskills(lifeform_t *lf) { ot = prompt.result; if (ot) { if (prompt.whichq == 0) { // learn the spell - ff = addtempflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL, FROMJOB); - ff->fromlev = lf->level; + learnspell(lf, ot->id, B_TRUE); done = B_TRUE; } else { describespell(ot); @@ -6048,8 +6228,7 @@ void enhanceskills(lifeform_t *lf) { // pick randomly ot = (objecttype_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data; if (ot) { - ff = addtempflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL, FROMJOB); - ff->fromlev = lf->level; + learnspell(lf, ot->id, B_TRUE); } } } @@ -7154,10 +7333,6 @@ void gainxp(lifeform_t *lf, long amt) { amtneeded = getspforpoint(lf); if (isplayer(lf)) statdirty = B_TRUE; } - // debug! - if (newskillpoints >= 5) { - raise(SIGINT); - } } // ready for next level? can only go up ONE level. @@ -11607,24 +11782,13 @@ int getteachableskills(lifeform_t *teacher, lifeform_t *student, int *info, enum for (i = 0; i < nretflags; i++) { objecttype_t *spell; enum OBTYPE spellid; - enum SPELLSCHOOL knownschool; int teachable = B_FALSE; f = retflag[i]; spellid = f->val[0]; spell = findot(spellid); if (spell->obclass->id != OC_SPELL) continue; - // student skilled in one of the spell's schools? - knownschool = getspellschoolknown(student, spellid); - if (getskill(student, getschoolskill(knownschool))) { - int mpneeded; - if (!cancast(student, spellid, &mpneeded) && (getspellpower(student, spellid) > 0)) { - if (getmaxmp(student) >= mpneeded) { - teachable = B_TRUE; - } - } - } - + teachable = spelllearnable(student, spellid); if (teachable) { info[*ninfo] = spellid; tradetype[*ninfo] = TI_SPELL; @@ -12107,7 +12271,7 @@ void givejob(lifeform_t *lf, enum JOB jobid) { spell = getrandomspellfromschool(SS_NATURE, 1); } // you can now cast it. - addtempflag(lf->flags, F_CANCAST, spell, NA, NA, NULL, FROMJOB); + learnspell(lf, spell, B_FALSE); } // druids always worship ekrub if (isplayer(lf)) { @@ -16774,7 +16938,10 @@ void autolearnspellsfrombook(lifeform_t *lf, object_t *book) { 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); + + //addtempflag(lf->flags, F_CANCAST, o->type->id, NA, NA, NULL, FROMJOB); + learnspell(lf, o->type->id, B_FALSE); + //if (isplayer(lf)) { // autoshortcut(lf, o->type->id); //} @@ -17321,6 +17488,17 @@ void killsubjob(subjob_t *sj) { } */ +void learnspell(lifeform_t *lf, enum OBTYPE sid, int fromlevelup) { + flag_t *ff; + + // learn the spell + ff = addtempflag(lf->flags, F_CANCAST, sid, NA, NA, NULL, FROMJOB); + assert(ff); + if (fromlevelup) { + ff->fromlev = lf->level; + } +} + flag_t *levelabilityready(lifeform_t *lf) { flag_t *f; int i; diff --git a/lf.h b/lf.h index 2c9e0e9..3eb6fd4 100644 --- a/lf.h +++ b/lf.h @@ -71,6 +71,7 @@ int cansee(lifeform_t *viewer, lifeform_t *viewee); int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos); int canshoot(lifeform_t *lf, enum ERROR *why); int cansleep(lifeform_t *lf); +int canstudyspell(lifeform_t *lf, enum OBTYPE spellid); int canthrow(lifeform_t *lf, object_t *o, enum ERROR *why); int canuseweapons(lifeform_t *lf); int canwear(lifeform_t *lf, object_t *o, enum BODYPART where); @@ -426,6 +427,7 @@ void killlf(lifeform_t *lf); void killpoisontype(poisontype_t *pt); void killrace(race_t *race); //void killsubjob(subjob_t *sj); +void learnspell(lifeform_t *lf, enum OBTYPE sid, int fromlevelup); flag_t *levelabilityready(lifeform_t *lf); int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo); int loadfirearmfast(lifeform_t *lf, int onpurpose); diff --git a/objects.c b/objects.c index 058020b..7afaf6c 100644 --- a/objects.c +++ b/objects.c @@ -6023,7 +6023,7 @@ char *getobextrainfo(object_t *o, char *buf) { } } else if (o->type->id == OT_CREDITCARD) { if (f->val[0] > 0) { - snprintf(chargestr, BUFLEN, " ($%d balance)",f->val[0]); + snprintf(chargestr, BUFLEN, " ($%d credit)",f->val[0]); } else { snprintf(chargestr, BUFLEN, " (maxed out)"); } diff --git a/spell.c b/spell.c index 9337256..c216724 100644 --- a/spell.c +++ b/spell.c @@ -2866,6 +2866,23 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // safe to train? if (check_rest_ok(user)) return B_TRUE; + // warn if we're a mage training without a spellbook + /* + f = lfhasflag(user, F_CANSTUDY); + if (f) { + if (!hasobwithflagval(user->pack, F_LINKSCHOOL, f->val[0], NA, NA, NULL) && + !hasob(user->pack, OT_GRIMOIRE)) { + char buf[BUFLEN]; + snprintf(buf, BUFLEN, "You cannot study %s without a spellbook. Continue", getschoolname(f->val[0])); + // warn + if (!real_warnabout(buf, DEF_WARNINGTIME, B_TRUE)) { + return B_TRUE; + } + } + } + */ + + // start training! if (!startresting(user, B_TRUE)) { // do the first one right away @@ -15608,6 +15625,25 @@ int spellisfromschool(int spellid, enum SPELLSCHOOL school) { return B_FALSE; } +int spelllearnable(lifeform_t *lf, enum OBTYPE spellid) { + enum SPELLSCHOOL knownschool; + int ok = B_FALSE; + + // skilled in one of the spell's schools? + knownschool = getspellschoolknown(lf, spellid); + if (getskill(lf, getschoolskill(knownschool))) { + int mpneeded; + if (!cancast(lf, spellid, &mpneeded)) { + if (getspellpower(lf, spellid) > 0) { + if (getmaxmp(lf) >= mpneeded) { + ok = B_TRUE; + } + } + } + } + return ok; +} + int spellokformonsters(int spellid) { objecttype_t *sp; sp = findot(spellid); diff --git a/spell.h b/spell.h index 2057bc1..e0813b7 100644 --- a/spell.h +++ b/spell.h @@ -40,6 +40,7 @@ void pullobto(object_t *o, lifeform_t *lf); int schoolappearsinbooks(enum SPELLSCHOOL ss); 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 spelllearnable(lifeform_t *lf, enum OBTYPE spellid); int spellokformonsters(int spellid); int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power, int *seenbyplayer, int announce); int stopspell(lifeform_t *caster, enum OBTYPE spellid);