* [+] bug: map structure being corrupted.

- [+] reduce hardness values
* [+] problem with skills: as you level up , you learn them less often
* [+] throw objects to set off traps
- [+] combination strike ability at expert wep level
- [+] reduce skill bonus to sc_stealth and sc_search
- [+] modify descriptions for all spells to explain the effect of spell
      power
- [+] make chill work more like frostbite (but less powerful)
- [+] make beginner skills still only cost 1.  above there thye csost
      more
- [+] modify cha check based on remaining hp% (ie. less attractive if
      you're bleeding everywhere!)
- [+] am i getting all level up skill messages? don't think  i saw "you
      can now detect magic" as a wizard.
    - [+] can use "more()" more often now that it checks strlen(msgbuf)
          first.
    - [+] make askchar etc call more() first.
- [+] falling over should lower your visrange.
- [+] missile size should impact how hard it is to catch it
- [+] backstabbing doesn't seem to work..... fixed now ?
- [+] all non-movement actions should stop sprinting.
Cold spells:
- [+] l1 - glaciate (turns water to sheets of ice)
- [+] l1 - snowball (minor cold damage in a ball, 1 to all)
- [+] l2 - e "train" to train skills or go up a levle, instead of 'R'.
- [+] better way to learn spells (without spellbooks)
    - [+] transcribe from scrolls using "study scroll"ability
    - [+] sc_learnmagic
        - [+] (int/2) + yourlevel + sorceryskill + BONUS:(spellskill*2)
        - [+] difficulty is 20 + spelllevel*3
    - [+] you lose the scroll even if it fails
    - [+] same for learning from a spellbook!
        - [+] but difficulty is 15 + sorceryskill + spelllevel*3
- [+] make pea soup be targetted.  ie. make mist on top of your enemy,
      not you!
- [+] implement maximum level in f_canlearn.
    - [+] wizards - short blades at novice.
    - [+] limit spell skills for some other classes?
ce shield? creates a shield
This commit is contained in:
Rob Pearce 2011-08-30 20:10:43 +00:00
parent c7f1cff1d5
commit b1b8e2506a
16 changed files with 1463 additions and 762 deletions

2
ai.c
View File

@ -215,7 +215,7 @@ cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *l
// can only obtain direction from footprints if your // can only obtain direction from footprints if your
// tracking skill is high enough. // tracking skill is high enough.
if (bestflag->val[2] == S_SIGHT) { if (bestflag->val[2] == S_SIGHT) {
if (getskill(lf, SK_TRACKING) >= PR_SKILLED) { if (getskill(lf, SK_PERCEPTION) >= PR_SKILLED) {
*lastdir = bestflag->val[1]; *lastdir = bestflag->val[1];
} else { } else {
*lastdir = D_NONE; *lastdir = D_NONE;

View File

@ -21,11 +21,13 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty
object_t *armour = NULL; object_t *armour = NULL;
int damtaken = 0; int damtaken = 0;
/*
// first of all, only apply some of the damage // first of all, only apply some of the damage
dam /= 2; dam /= 2;
if (dam == 0) { if (dam == 0) {
return 0; return 0;
} }
*/
// special case - missiles always hit flak jacket // special case - missiles always hit flak jacket
if (damtype == DT_PROJECTILE) { if (damtype == DT_PROJECTILE) {
@ -63,7 +65,7 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty
// ALL of damage reduction goes towards armour // ALL of damage reduction goes towards armour
} else { } else {
// SOME of the damage reduction goes towards the armour // SOME of the damage reduction goes towards the armour
// damage taken by armour is reduced by half its armour rating // damage taken by armour is reduced by _UP TO_ half its armour rating
if (ar) { if (ar) {
int maxreduction; int maxreduction;
maxreduction = ar/2; maxreduction = ar/2;
@ -310,7 +312,10 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
// take time // take time
attacktime = getattackspeed(lf); attacktime = getattackspeed(lf);
taketime(lf, attacktime);
if (!lfhasflag(lf, F_COMBOSTRIKE)) {
taketime(lf, attacktime);
}
if (nweps <= 0) { if (nweps <= 0) {
if (isplayer(lf)) { if (isplayer(lf)) {
@ -433,7 +438,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
int ndam = 0; int ndam = 0;
char buf[BUFLEN]; char buf[BUFLEN];
char attackername[BUFLEN]; char attackername[BUFLEN];
char victimname[BUFLEN]; char victimname[BUFLEN],victimbpname[BUFLEN];
int fatal = B_FALSE; int fatal = B_FALSE;
int feigneddeath = B_FALSE; int feigneddeath = B_FALSE;
int deflected = B_FALSE; int deflected = B_FALSE;
@ -522,6 +527,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} }
} }
// did you hit? // did you hit?
ndam = 0; ndam = 0;
@ -531,11 +537,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
critpos = getrandomcorebp(victim); critpos = getrandomcorebp(victim);
// replace victicname to include body part // replace victicname to include body part
if ((lf == victim) && !isplayer(lf)) { if ((lf == victim) && !isplayer(lf)) {
sprintf(victimname, "it's %s", getbodypartname(critpos)); sprintf(victimbpname, "its %s", getbodypartname(critpos));
} else { } else {
getlfname(victim, buf); getlfname(victim, buf);
sprintf(victimname, "%s%s %s", buf, getpossessive(buf), getbodypartname(critpos)); sprintf(victimbpname, "%s%s %s", buf, getpossessive(buf), getbodypartname(critpos));
} }
} else {
strcpy(victimbpname, "");
} }
if (lf == victim) { if (lf == victim) {
@ -548,6 +556,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
getlfname(victim, victimname); getlfname(victim, victimname);
} }
// weapon passing through ghosts etc? // weapon passing through ghosts etc?
if (hit) { if (hit) {
if (lfhasflag(victim, F_NONCORPOREAL) && if (lfhasflag(victim, F_NONCORPOREAL) &&
@ -639,8 +648,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// backstab? // backstab?
if ((damtype[0] == DT_PIERCE) && // using a stabbing weapon if ((damtype[0] == DT_PIERCE) && // using a stabbing weapon
getskill(lf, SK_BACKSTAB)) { // able to backstab getskill(lf, SK_BACKSTAB)) { // able to backstab
if (!lfhasflagval(victim, F_STABBEDBY, lf->id, NA, NA, NULL) && // haven't stabbed them before if (!lfhasflagval(victim, F_STABBEDBY, lf->id, NA, NA, NULL) ) { // haven't stabbed them before
!lfhasflagval(victim, F_TARGETLF, lf->id, NA, NA, NULL)) { // victim isnt attacking us // && !lfhasflagval(victim, F_TARGETLF, lf->id, NA, NA, NULL)) { // victim isnt attacking us
if (!cansee(victim, lf) || // victim can't see us if (!cansee(victim, lf) || // victim can't see us
isfleeing(victim)) { isfleeing(victim)) {
@ -779,6 +788,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// announce it // announce it
if (!feigneddeath) { if (!feigneddeath) {
int usecrittext = B_FALSE;
if ((i == 0) && critical && !fatal) usecrittext = B_TRUE;
if (isplayer(lf)) { if (isplayer(lf)) {
char extradambuf[BUFLEN]; char extradambuf[BUFLEN];
char withwep[BUFLEN]; char withwep[BUFLEN];
@ -817,9 +830,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
verb = getattackverb(lf, wep, damtype[i], pctof(10, victim->maxhp), victim->maxhp); verb = getattackverb(lf, wep, damtype[i], pctof(10, victim->maxhp), victim->maxhp);
} }
} }
warn("^%cYou %s %s%s%s%s", fatal ? 'g' : 'n', warn("^%cYou %s%s %s%s%s%s", fatal ? 'g' : 'n',
verb, usecrittext ? "critically " : "", verb,
victimname, withwep,extradambuf, usecrittext ? victimbpname : victimname, withwep,extradambuf,
(fatal || backstab) ? "!" : "."); (fatal || backstab) ? "!" : ".");
if (fatal && strstr(verb, "behead")) { if (fatal && strstr(verb, "behead")) {
@ -857,9 +870,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} else { } else {
strcpy(nodamstr, ""); strcpy(nodamstr, "");
} }
warn("^%c%s %s%s %s%s%s.", (isplayer(victim) && !nodam) ? 'b' : 'n', buf, attackverb, warn("^%c%s %s%s%s %s%s%s.", (isplayer(victim) && !nodam) ? 'b' : 'n', buf,
usecrittext ? "critically " : "", attackverb,
needses(attackverb) ? "es" : "s", needses(attackverb) ? "es" : "s",
victimname,withwep, nodamstr); usecrittext ? victimbpname : victimname,withwep, nodamstr);
} }
noise(lf->cell, lf, NC_OTHER, 3, "sounds of fighting.", NULL); noise(lf->cell, lf, NC_OTHER, 3, "sounds of fighting.", NULL);
} }
@ -1848,9 +1862,11 @@ int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag) {
} }
} }
if (lfhasflagval(victim, F_INJURY, BP_BODY, DT_SLASH, NA, NULL)) { if (victim) {
// extra damage if (lfhasflagval(victim, F_INJURY, BP_BODY, DT_SLASH, NA, NULL)) {
dam += rnd(1,2); // extra damage
dam += rnd(1,2);
}
} }
return dam; return dam;

Binary file not shown.

29
defs.h
View File

@ -173,6 +173,9 @@
#define SPEEDUNIT 5 #define SPEEDUNIT 5
// experience
#define SKILLXPPERPOINT 250
// speed settings (lower is faster) // speed settings (lower is faster)
#define SPEED_ATTACK SP_NORMAL #define SPEED_ATTACK SP_NORMAL
#define SPEED_DEAD 50 #define SPEED_DEAD 50
@ -223,7 +226,7 @@
// String buffer lengths // String buffer lengths
#define BUFLENTINY 10 #define BUFLENTINY 10
#define BUFLENSMALL 64 #define BUFLENSMALL 64
#define BUFLEN 128 #define BUFLEN 256
#define BIGBUFLEN 512 #define BIGBUFLEN 512
#define HUGEBUFLEN 1024 #define HUGEBUFLEN 1024
#define MAXPNAMELEN 12 // max player name length #define MAXPNAMELEN 12 // max player name length
@ -363,18 +366,17 @@ enum SKILL {
SK_LISTEN, SK_LISTEN,
SK_LOCKPICKING, SK_LOCKPICKING,
SK_METALWORK, SK_METALWORK,
SK_PERCEPTION,
SK_RANGED, SK_RANGED,
SK_SEWING, SK_SEWING,
SK_SHIELDS, SK_SHIELDS,
SK_SPEECH, SK_SPEECH,
SK_SPELLCASTING, SK_SPELLCASTING,
SK_SPOTHIDDEN,
SK_STEALTH, SK_STEALTH,
SK_SWIMMING, SK_SWIMMING,
SK_TECHUSAGE, SK_TECHUSAGE,
SK_THIEVERY, SK_THIEVERY,
SK_THROWING, SK_THROWING,
SK_TRACKING,
SK_TRAPS, SK_TRAPS,
SK_TWOWEAPON, SK_TWOWEAPON,
// knowledge // knowledge
@ -408,7 +410,7 @@ enum SKILL {
SK_SS_TRANSLOCATION, SK_SS_TRANSLOCATION,
SK_SS_WILD, SK_SS_WILD,
}; };
#define MAXSKILLS 54 #define MAXSKILLS 53
// proficiency levels // proficiency levels
enum SKILLLEVEL { enum SKILLLEVEL {
@ -458,6 +460,7 @@ enum CHECKTYPE {
SC_SHIELDBLOCK, SC_SHIELDBLOCK,
SC_FALL, SC_FALL,
SC_SLIP, SC_SLIP,
SC_LEARNMAGIC,
SC_LISTEN, SC_LISTEN,
SC_MORALE, SC_MORALE,
SC_OPENLOCKS, SC_OPENLOCKS,
@ -1062,10 +1065,14 @@ enum OBTYPE {
OT_S_CHILL, OT_S_CHILL,
OT_S_COLDBURST, OT_S_COLDBURST,
OT_S_COLDRAY, OT_S_COLDRAY,
OT_S_CRYSTALSHIELD,
OT_S_FREEZEOB, OT_S_FREEZEOB,
OT_S_FROSTBITE, OT_S_FROSTBITE,
OT_S_GLACIATE,
OT_S_ICEEDGE, OT_S_ICEEDGE,
OT_S_ICICLE, OT_S_ICICLE,
OT_S_SLIDE,
OT_S_SNOWBALL,
OT_S_WALLOFICE, OT_S_WALLOFICE,
// -- gravity // -- gravity
OT_S_TRUESTRIKE, OT_S_TRUESTRIKE,
@ -1179,12 +1186,14 @@ enum OBTYPE {
OT_A_FLURRY, OT_A_FLURRY,
OT_A_GRAB, OT_A_GRAB,
OT_A_CHARGE, OT_A_CHARGE,
OT_A_COMBOSTRIKE,
OT_A_CRUSH, OT_A_CRUSH,
OT_A_JUMP, OT_A_JUMP,
OT_A_PRAY, OT_A_PRAY,
OT_A_RAGE, OT_A_RAGE,
OT_A_REPAIR, OT_A_REPAIR,
OT_A_SPRINT, OT_A_SPRINT,
OT_A_STUDYSCROLL,
OT_A_STINGACID, // need to define dam in f_canwill OT_A_STINGACID, // need to define dam in f_canwill
OT_A_SUCKBLOOD, OT_A_SUCKBLOOD,
OT_A_SWOOP, OT_A_SWOOP,
@ -1196,6 +1205,7 @@ enum OBTYPE {
OT_A_POLYREVERT, OT_A_POLYREVERT,
OT_A_QUIVERINGPALM, OT_A_QUIVERINGPALM,
OT_A_STEAL, OT_A_STEAL,
OT_A_TRAIN,
OT_A_TUMBLE, OT_A_TUMBLE,
OT_A_WARCRY, // uses F_NOISETEXT -> N_WARCRY if it is there. OT_A_WARCRY, // uses F_NOISETEXT -> N_WARCRY if it is there.
// otherwise 'shouts a blood-curdling war cry' // otherwise 'shouts a blood-curdling war cry'
@ -1404,6 +1414,7 @@ enum OBTYPE {
OT_BOLT, OT_BOLT,
OT_DART, OT_DART,
OT_NANODART, OT_NANODART,
OT_NEEDLE,
OT_JAVELIN, OT_JAVELIN,
OT_BULLET, OT_BULLET,
OT_RUBBERBULLET, OT_RUBBERBULLET,
@ -1466,6 +1477,7 @@ enum OBTYPE {
// special weapons // special weapons
OT_ENERGYBLADE, OT_ENERGYBLADE,
OT_HANDOFGOD, OT_HANDOFGOD,
OT_ICESHIELD,
}; };
@ -1883,6 +1895,7 @@ enum FLAG {
F_MPCOST, // v0=mp cost of spell. if missing, mpcost if splev^2 F_MPCOST, // v0=mp cost of spell. if missing, mpcost if splev^2
F_ONGOING, // this spell has an ongoing cost F_ONGOING, // this spell has an ongoing cost
F_CASTINGTIME, // this spell takes v0 turns to cast F_CASTINGTIME, // this spell takes v0 turns to cast
F_EXTRADESC, // extra descriptions for this object
//F_SPELLLETTER, // text[0] = letter to cast this spell //F_SPELLLETTER, // text[0] = letter to cast this spell
F_AICASTTOFLEE, // AI can cast this spell to help flee/heal F_AICASTTOFLEE, // AI can cast this spell to help flee/heal
// v0 is who to target // v0 is who to target
@ -1946,6 +1959,7 @@ enum FLAG {
F_AUTOCMD, // val0 = how many times to repeat this 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_LASTCMD, // text[0] = last command performed, v0/1 = x/y of cell, v2=various
F_CANLEARN, // lf is able to learn skill val0 F_CANLEARN, // lf is able to learn skill val0
// v1 = max lev
F_STARTOB, // val0 = %chance of starting with it, text = ob name F_STARTOB, // val0 = %chance of starting with it, text = ob name
// val1,2 = min/max amounts. if NA, min=max=1. // val1,2 = min/max amounts. if NA, min=max=1.
F_STARTOBDT, // val0 = %chance of starting with damtype val1 F_STARTOBDT, // val0 = %chance of starting with damtype val1
@ -2139,6 +2153,8 @@ enum FLAG {
F_MORALE, // gain +v0 in morale checks. F_MORALE, // gain +v0 in morale checks.
F_SPOTTED, // you have spotted hiding lf id v0. you lsoe this if they F_SPOTTED, // you have spotted hiding lf id v0. you lsoe this if they
// go out of sight. // go out of sight.
// special attack flags
F_COMBOSTRIKE, // lf is performing a combination strike
F_HEAVYBLOW, // next attack is a heavy blow F_HEAVYBLOW, // next attack is a heavy blow
F_QUIVERINGPALM, // your next strike will be a quivpalm attack F_QUIVERINGPALM, // your next strike will be a quivpalm attack
// INTRINSICS // INTRINSICS
@ -2204,6 +2220,8 @@ enum FLAG {
F_GRABBING, // you are grabbing lf id v0 F_GRABBING, // you are grabbing lf id v0
F_HURRICANESTRIKE, // lf is performing a hurricane strike F_HURRICANESTRIKE, // lf is performing a hurricane strike
F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks. F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks.
F_ICESLIDE, // lf has "slide" spell active.
// v0 = timeleft (since 'lifetime' is used for FROMSPELL)
F_INJURY, // v0 = where, v1 = damtype F_INJURY, // v0 = where, v1 = damtype
F_INVISIBLE, // lifeform is invisible F_INVISIBLE, // lifeform is invisible
F_INVULNERABLE,// immune to most damage F_INVULNERABLE,// immune to most damage
@ -2616,6 +2634,7 @@ typedef struct map_s {
struct cell_s *cell[MAX_MAPW*MAX_MAPH]; // list of cells in this map struct cell_s *cell[MAX_MAPW*MAX_MAPH]; // list of cells in this map
int nextmap[MAXDIR_MAP]; // which map is in each direction int nextmap[MAXDIR_MAP]; // which map is in each direction
int beingcreated; int beingcreated;
int nfixedrooms; // used for map creation only, not saved.
struct lifeform_s *lf,*lastlf; struct lifeform_s *lf,*lastlf;
@ -2751,7 +2770,7 @@ typedef struct lifeform_s {
struct race_s *race; struct race_s *race;
int level; int level;
int newlevel; int newlevel;
long xp; long xp,skillxp;
int skillpoints; int skillpoints;
int hp,maxhp; int hp,maxhp;
int mp,maxmp; int mp,maxmp;

22
flag.c
View File

@ -353,6 +353,7 @@ int countflags(flagpile_t *fp) {
int flagcausesloscalc(enum FLAG fid) { int flagcausesloscalc(enum FLAG fid) {
switch (fid) { switch (fid) {
case F_BLOCKSVIEW: case F_BLOCKSVIEW:
case F_PRONE:
return B_TRUE; return B_TRUE;
default: break; default: break;
} }
@ -413,6 +414,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) {
case F_FLYING: case F_FLYING:
case F_HASNEWLEVEL: case F_HASNEWLEVEL:
case F_HIDING: case F_HIDING:
case F_ICESLIDE:
case F_INVISIBLE: case F_INVISIBLE:
case F_LEVITATING: case F_LEVITATING:
case F_PARALYZED: case F_PARALYZED:
@ -822,12 +824,20 @@ void killflag(flag_t *f) {
} }
} }
if (redolos) { if (redolos) {
// everyone who can see this cell recalcs their los // - if this was a lf's flag, they recalc their los.
lifeform_t *l; // - if it was an object flag, then everyone who can see
for (l = redolos->map->lf ; l ; l = l->next) { // its cell recalcs their los.
if (haslos(l, redolos)) { if (f->pile->owner) {
precalclos(l); precalclos(f->pile->owner);
if (isplayer(l)) redoscreen = B_TRUE; if (isplayer(f->pile->owner)) redoscreen = B_TRUE;
} else {
// everyone who can see this cell recalcs their los
lifeform_t *l;
for (l = redolos->map->lf ; l ; l = l->next) {
if (haslos(l, redolos)) {
precalclos(l);
if (isplayer(l)) redoscreen = B_TRUE;
}
} }
} }
} }

234
io.c
View File

@ -468,6 +468,7 @@ char askchar(char *prompt, char *validchars, char *def, int showchars) {
char ch; char ch;
int valid = B_FALSE; int valid = B_FALSE;
more();
wclear(msgwin); wclear(msgwin);
if (showchars) { if (showchars) {
sprintf(buf, "%s (",prompt); sprintf(buf, "%s (",prompt);
@ -1002,6 +1003,8 @@ char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def)
char buf[BUFLEN]; char buf[BUFLEN];
char *ending; char *ending;
more();
wclear(msgwin); wclear(msgwin);
sprintf(buf, "%s",prompt); sprintf(buf, "%s",prompt);
if (def) { if (def) {
@ -1300,6 +1303,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE; donesomething = B_TRUE;
} }
break; break;
case F_ICESLIDE:
msg("Sheets of ice start forming under %s%s feet!",lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_INJURY: case F_INJURY:
strcpy(buf, getinjuredbpname(f->val[0])); strcpy(buf, getinjuredbpname(f->val[0]));
strcpy(buf3, getinjuryname(f->val[1])); strcpy(buf3, getinjuryname(f->val[1]));
@ -1551,7 +1558,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE; donesomething = B_TRUE;
break; break;
case F_SLOWACTMOVE: case F_SLOWACTMOVE:
msg("%s %s",getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "feel slow and sluggish." : "looks slow and sluggish."); msg("^%c%s %s",getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "feel slow and sluggish." : "looks slow and sluggish.");
donesomething = B_TRUE; donesomething = B_TRUE;
break; break;
case F_SPRINTING: case F_SPRINTING:
@ -1880,6 +1887,10 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE; donesomething = B_TRUE;
} }
break; break;
case F_ICESLIDE:
msg("%s%s feet are longer generating ice.",lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_INJURY: case F_INJURY:
strcpy(buf, getinjuredbpname(f->val[0])); strcpy(buf, getinjuredbpname(f->val[0]));
strcpy(buf3, getinjuryname(f->val[1])); strcpy(buf3, getinjuryname(f->val[1]));
@ -3917,6 +3928,7 @@ void describeob(object_t *o) {
void describeskill(enum SKILL skid) { void describeskill(enum SKILL skid) {
skill_t *sk; skill_t *sk;
enum SKILLLEVEL slev;
char buf[BUFLEN]; char buf[BUFLEN];
int i; int i;
cls(); cls();
@ -3933,13 +3945,17 @@ void describeskill(enum SKILL skid) {
// descriptions // descriptions
wmove(mainwin, 4, 0); wmove(mainwin, 4, 0);
for (i = 0; i < sk->nskilldesc; i++) { for (slev = PR_INEPT; slev <= PR_MASTER; slev++) {
if (sk->skilldesclev[i] == PR_INEPT) { for (i = 0; i < sk->nskilldesc; i++) {
sprintf(buf, "%s\n",sk->skilldesctext[i]); if (sk->skilldesclev[i] == slev) {
} else { if (slev == PR_INEPT) {
sprintf(buf, "At %s level: %s\n",getskilllevelname(sk->skilldesclev[i]), sk->skilldesctext[i]); sprintf(buf, "%s\n",sk->skilldesctext[i]);
} else {
sprintf(buf, "At %s level: %s\n",getskilllevelname(sk->skilldesclev[i]), sk->skilldesctext[i]);
}
textwithcol(mainwin, buf);
}
} }
textwithcol(mainwin, buf);
} }
wrefresh(mainwin); wrefresh(mainwin);
@ -3952,9 +3968,8 @@ void describeskill(enum SKILL skid) {
void describespell(objecttype_t *ot) { void describespell(objecttype_t *ot) {
char buf[BUFLEN]; char buf[BUFLEN];
flag_t *f; flag_t *retflag[MAXCANDIDATES], *f;
int i; int nretflags,i,power,range;
int power,range;
cls(); cls();
@ -3972,9 +3987,16 @@ void describespell(objecttype_t *ot) {
mvwprintw(mainwin, 0, 0, buf); mvwprintw(mainwin, 0, 0, buf);
wmove(mainwin, 2, 0); wmove(mainwin, 2, 0);
sprintf(buf, "%s\n\n", ot->desc); sprintf(buf, "%s\n", ot->desc);
textwithcol(mainwin, buf); textwithcol(mainwin, buf);
getflags(ot->flags, retflag, &nretflags, F_EXTRADESC, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
sprintf(buf, "%s\n", f->text);
textwithcol(mainwin, buf);
}
wprintw(mainwin, "\n");
// properties // properties
f = hasflag(ot->flags, F_SPELLLEVEL); f = hasflag(ot->flags, F_SPELLLEVEL);
@ -5684,83 +5706,61 @@ void doread(obpile_t *op) {
void dorest(void) { void dorest(void) {
// can we rest? // can we rest?
if (safetorest(player)) { char validchars[BUFLEN];
int willtrain = B_FALSE; char ques[BUFLEN];
if (lfhasflag(player, F_HASNEWLEVEL)) { char ch;
int ch;
ch = askchar("Would you like to train your skills?","yn","y", B_TRUE);
if (ch == 'y') {
willtrain = B_TRUE;
}
}
// if not training, only rest if we need to.
if (!willtrain) {
char validchars[BUFLEN];
char ques[BUFLEN];
char ch;
if (needstorest(player, validchars)) {
if (strchr(validchars, 'h') && strchr(validchars, 'm')) {
strcat(validchars, "bn");
strcpy(ques, "Rest until full HP, Mana, Both, or none");
ch = askchar(ques, validchars, "b", B_TRUE);
if (ch == 'b') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
} else if (ch == 'h') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
} else if (ch == 'm') {
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
}
} else if (strchr(validchars, 'h')) {
strcpy(ques, "Rest until full HP");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
}
} else if (strchr(validchars, 'm')) {
strcpy(ques, "Rest until full Mana");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
}
}
} else {
if (countnearbyhurtallies(player)) {
strcpy(ques, "Rest until nearby allies are healed?");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILALLIES, B_TRUE, NA, NA, NULL);
}
} else {
msg("You don't need to rest at the moment.");
return;
}
}
if (!lfhasflag(player, F_RESTUNTILHP) && if (check_rest_ok(player)) return;
!lfhasflag(player, F_RESTUNTILMP) &&
!lfhasflag(player, F_RESTUNTILALLIES)) { if (needstorest(player, validchars)) {
msg("Cancelled."); if (strchr(validchars, 'h') && strchr(validchars, 'm')) {
return; strcat(validchars, "bn");
} strcpy(ques, "Rest until full HP, Mana, Both, or none");
} ch = askchar(ques, validchars, "b", B_TRUE);
if (!startresting(player, willtrain)) { if (ch == 'b') {
// do the first one right away addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
rest(player, B_TRUE); addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
} else if (ch == 'h') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
} else if (ch == 'm') {
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
}
} else if (strchr(validchars, 'h')) {
strcpy(ques, "Rest until full HP");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILHP, B_TRUE, NA, NA, NULL);
}
} else if (strchr(validchars, 'm')) {
strcpy(ques, "Rest until full Mana");
ch = askchar(ques, "yn", "y", B_TRUE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILMP, B_TRUE, NA, NA, NULL);
}
} }
} else { } else {
switch (reason) { if (countnearbyhurtallies(player)) {
case E_LEVITATING: strcpy(ques, "Rest until nearby allies are healed?");
msg("You cannot rest while levitating in mid-air!"); ch = askchar(ques, "yn", "y", B_TRUE);
break; if (ch == 'y') {
case E_MONSTERNEARBY: addflag(player->flags, F_RESTUNTILALLIES, B_TRUE, NA, NA, NULL);
msg("You cannot rest - there are monsters nearby!"); }
break; } else {
default: msg("You don't need to rest at the moment.");
msg("You cannot rest for some reason."); return;
break;
} }
} }
if (!lfhasflag(player, F_RESTUNTILHP) &&
!lfhasflag(player, F_RESTUNTILMP) &&
!lfhasflag(player, F_RESTUNTILALLIES)) {
msg("Cancelled.");
return;
}
if (!startresting(player, B_FALSE)) {
// do the first one right away
rest(player, B_TRUE);
}
} }
int doselguntarget(void) { int doselguntarget(void) {
@ -6303,6 +6303,7 @@ char getchoice(prompt_t *prompt) {
int nextpage = -1; int nextpage = -1;
int lastline = SCREENH - 4; int lastline = SCREENH - 4;
more();
gotheadings = B_FALSE; gotheadings = B_FALSE;
for (i = 0; i < prompt->nchoices; i++) { for (i = 0; i < prompt->nchoices; i++) {
@ -6416,6 +6417,8 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) {
strcpy(inpstring, ""); strcpy(inpstring, "");
more();
// mark valid choices, and determine whether we have // mark valid choices, and determine whether we have
// headings // headings
gotheadings = B_FALSE; gotheadings = B_FALSE;
@ -6885,6 +6888,17 @@ void handleinput(void) {
} }
temp[0] = ch; temp[0] = ch;
temp[1] = '\0'; temp[1] = '\0';
// actions other than movement will cancel certain effects
switch (tolower(ch)) {
case 'h': case 'j': case 'k': case 'l':
case 'y': case 'u': case 'b': case 'n':
break;
default:
stoprunning(player);
if (hasactivespell(player, OT_S_SLIDE)) stopspell(player, OT_S_SLIDE);
break;
}
switch (ch) { switch (ch) {
// movement // movement
@ -7167,16 +7181,18 @@ void dblog_nocr(char *format, ... ) {
// force a '--more--' prompt // force a '--more--' prompt
void more(void) { void more(void) {
//msg("^"); if (strlen(msgbuf)) {
strcat(msgbuf, MSGMORESTRING); //msg("^");
//mvwprintw(msgwin, 0, 0, msgbuf); strcat(msgbuf, MSGMORESTRING);
drawmsg(); //mvwprintw(msgwin, 0, 0, msgbuf);
curs_set(1); drawmsg();
// wait for space curs_set(1);
while (getch() != ' '); // wait for space
curs_set(0); while (getch() != ' ');
// clear msg curs_set(0);
clearmsg(); // clear msg
clearmsg();
}
} }
@ -7354,6 +7370,7 @@ void drawstatus(void) {
wattron(statwin, A_BOLD); wprintw(statwin, "/"); wattroff(statwin, A_BOLD); wattron(statwin, A_BOLD); wprintw(statwin, "/"); wattroff(statwin, A_BOLD);
wprintw(statwin, "%d%%",xpleft); wprintw(statwin, "%d%%",xpleft);
} }
// blinded? // blinded?
if (isblind(player) && !lfhasflag(player, F_ASLEEP)) { if (isblind(player) && !lfhasflag(player, F_ASLEEP)) {
setcol(statwin, C_RED); setcol(statwin, C_RED);
@ -7384,7 +7401,7 @@ void drawstatus(void) {
unsetcol(statwin, C_BOLDBLUE); unsetcol(statwin, C_BOLDBLUE);
} else { } else {
setcol(statwin, C_BOLDBLUE); setcol(statwin, C_BOLDBLUE);
wprintw(statwin, " Flt"); // "float"ing wprintw(statwin, " Hov"); // "hov"ering
unsetcol(statwin, C_BOLDBLUE); unsetcol(statwin, C_BOLDBLUE);
} }
} }
@ -7807,7 +7824,7 @@ void showlfarmour(lifeform_t *lf) {
strcat(rhs, "(covered) "); strcat(rhs, "(covered) ");
} }
f = hasflag(o->flags, F_ARMOURRATING); f = hasflag(o->flags, F_ARMOURRATING);
if (f) { if (f && (f->val[0])) {
char numbuf[BUFLENSMALL]; char numbuf[BUFLENSMALL];
sprintf(numbuf, " ^g[AR:%d]^n",f->val[0]); sprintf(numbuf, " ^g[AR:%d]^n",f->val[0]);
strcat(rhs, numbuf); strcat(rhs, numbuf);
@ -7992,7 +8009,11 @@ void showlfstats(lifeform_t *lf, int showall) {
wprintw(mainwin, "%d / %d%s", lf->mp , lf->maxmp,maxmpstr); y++; wprintw(mainwin, "%d / %d%s", lf->mp , lf->maxmp,maxmpstr); y++;
} }
if (showall) { if (showall) {
doheadingsmall(mainwin, y, 0, ftext, "Exp Level"); if (isplayer(lf)) {
doheadingsmall(mainwin, y, 0, ftext, "Exp Level");
} else {
doheadingsmall(mainwin, y, 0, ftext, "Hit Dice");
}
if (isplayer(lf)) { if (isplayer(lf)) {
xpneeded = getxpforlev(lf->level + 1) - lf->xp; xpneeded = getxpforlev(lf->level + 1) - lf->xp;
wprintw(mainwin, "%d (%ld XP, %ld for next)", lf->level, lf->xp, xpneeded); y++; wprintw(mainwin, "%d (%ld XP, %ld for next)", lf->level, lf->xp, xpneeded); y++;
@ -8006,10 +8027,14 @@ void showlfstats(lifeform_t *lf, int showall) {
if ((lf->skillpoints == 0) && (attpoints == 0)) { if ((lf->skillpoints == 0) && (attpoints == 0)) {
wprintw(mainwin, "n/a"); wprintw(mainwin, "n/a");
} else { } else {
/*
wprintw(mainwin, "%d skill%s, %d attrib%s", lf->skillpoints, wprintw(mainwin, "%d skill%s, %d attrib%s", lf->skillpoints,
(lf->skillpoints == 1) ? "" : "s", (lf->skillpoints == 1) ? "" : "s",
attpoints, attpoints,
(attpoints == 1) ? "" : "s"); (attpoints == 1) ? "" : "s");
*/
wprintw(mainwin, "%d skill point%s", lf->skillpoints,
(lf->skillpoints == 1) ? "" : "s");
} }
y++; y++;
} }
@ -8483,12 +8508,14 @@ void showlfstats(lifeform_t *lf, int showall) {
strcpy(buf2, getinjuryname(f->val[1])); strcpy(buf2, getinjuryname(f->val[1]));
strcpy(buf3, getinjurydesc(f->val[0], f->val[1])); strcpy(buf3, getinjurydesc(f->val[0], f->val[1]));
if (isplayer(lf)) { if (isplayer(lf)) {
msg("^%cYour %s is %s%s.", getlfcol(lf, CC_VBAD), buf, buf2, buf3); mvwprintw(mainwin, y, 0, "^%cYour %s is %s%s.", getlfcol(lf, CC_VBAD), buf, buf2, buf3);
y++;
} else { } else {
char lfname[BUFLEN]; char lfname[BUFLEN];
getlfname(lf, lfname); getlfname(lf, lfname);
msg("^%c%s%s %s is %s%s.", getlfcol(lf, CC_VBAD), mvwprintw(mainwin, y, 0, "^%c%s%s %s is %s%s.", getlfcol(lf, CC_VBAD),
lfname, getpossessive(lfname), buf, buf2, buf3); lfname, getpossessive(lfname), buf, buf2, buf3);
y++;
} }
} }
f = lfhasknownflag(lf, F_INVISIBLE); f = lfhasknownflag(lf, F_INVISIBLE);
@ -8813,7 +8840,7 @@ void showlfstats(lifeform_t *lf, int showall) {
//centre(mainwin, y, "SKILLS"); y ++; //centre(mainwin, y, "SKILLS"); y ++;
sprintf(skilltitle, "%-40s%-40s","AVAILABLE SKILLS", "KNOWN SKILLS"); sprintf(skilltitle, "%-40s%-40s","AVAILABLE SKILLS", "KNOWN SKILLS (*=maxed)");
doheading(mainwin, &y, 0, skilltitle); doheading(mainwin, &y, 0, skilltitle);
for (n = 0; n < MAXOF(numknown,numavailable); n++) { for (n = 0; n < MAXOF(numknown,numavailable); n++) {
if (n < numavailable) { if (n < numavailable) {
@ -9231,16 +9258,21 @@ void showlfstats(lifeform_t *lf, int showall) {
y++; y++;
} }
f = lfhasknownflag(lf, F_HEAVYBLOW); f = lfhasknownflag(lf, F_HEAVYBLOW);
if (f && (f->known)) { if (f) {
sprintf(buf,"%s%s attacks knock enemies back.", you(lf), getpossessive(you(lf))); sprintf(buf,"%s%s attacks knock enemies back.", you(lf), getpossessive(you(lf)));
mvwprintw(mainwin, y, 0, buf); mvwprintw(mainwin, y, 0, buf);
y++; y++;
} }
f = lfhasknownflag(lf, F_HOLYAURA); f = lfhasknownflag(lf, F_HOLYAURA);
if (f && (f->known)) { if (f) {
mvwprintw(mainwin, y, 0, "%s %s surrounded by a holy aura.", you(lf), is(lf)); mvwprintw(mainwin, y, 0, "%s %s surrounded by a holy aura.", you(lf), is(lf));
y++; y++;
} }
f = lfhasknownflag(lf, F_ICESLIDE);
if (f) {
msg("%s%s feet automatically generating sheets of ice.",your(lf));
}
f = lfhasknownflag(lf, F_QUICKBITE); f = lfhasknownflag(lf, F_QUICKBITE);
if (f && (f->known)) { if (f && (f->known)) {
sprintf(buf,"%s can bite wounded enemies for extra damage.", you(lf)); sprintf(buf,"%s can bite wounded enemies for extra damage.", you(lf));

841
lf.c

File diff suppressed because it is too large Load Diff

6
lf.h
View File

@ -47,6 +47,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
int celllitfor(lifeform_t *lf, cell_t *c, int maxvisrange, int nightvisrange); 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);
int checkfordrowning(lifeform_t *lf, object_t *o); int checkfordrowning(lifeform_t *lf, object_t *o);
int check_rest_ok(lifeform_t *lf);
//void checkxp(enum RACE rid); //void checkxp(enum RACE rid);
float comparelfs(lifeform_t *lf1, lifeform_t *lf2); float comparelfs(lifeform_t *lf1, lifeform_t *lf2);
int countinnateattacks(lifeform_t *lf); int countinnateattacks(lifeform_t *lf);
@ -91,7 +92,8 @@ void gainmp(lifeform_t *lf, int amt);
void gainxp(lifeform_t *lf, long amt); void gainxp(lifeform_t *lf, long amt);
void genxplist(void); void genxplist(void);
int getactspeed(lifeform_t *lf); int getactspeed(lifeform_t *lf);
void getadjallies(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, int *nadjallies); int getadjenemies(lifeform_t *lf, lifeform_t **adjlf, int *nadjlfs);
void getwhowillfollow(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, int *nadjallies);
enum ALIGNMENT getalignment(lifeform_t *lf); enum ALIGNMENT getalignment(lifeform_t *lf);
enum ALLEGIENCE getallegiance(lifeform_t *lf); enum ALLEGIENCE getallegiance(lifeform_t *lf);
int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs); int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs);
@ -131,6 +133,7 @@ int getlastdir(lifeform_t *lf);
int getlfaccuracy(lifeform_t *lf, object_t *wep); int getlfaccuracy(lifeform_t *lf, object_t *wep);
char getlfcol(lifeform_t *lf, enum MSGCHARCOL cc); char getlfcol(lifeform_t *lf, enum MSGCHARCOL cc);
enum LFCONDITION getlfcondition(lifeform_t *lf); enum LFCONDITION getlfcondition(lifeform_t *lf);
enum SKILLLEVEL getmaxskilllevel(lifeform_t *lf, enum SKILL skid);
int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions); int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions);
int getnightvisrange(lifeform_t *lf); int getnightvisrange(lifeform_t *lf);
char *getlfconditionname(enum LFCONDITION cond); char *getlfconditionname(enum LFCONDITION cond);
@ -184,6 +187,7 @@ race_t *getreallyrandomrace(enum RACECLASS wantrc);
enum SKILL getrandomskill(void); enum SKILL getrandomskill(void);
object_t *getrestob(lifeform_t *lf); object_t *getrestob(lifeform_t *lf);
enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id); enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id);
int getskilllevcost(enum SKILLLEVEL slev);
int getsounddist(int volume); int getsounddist(int volume);
char *getspeedname(int speed, char *buf); char *getspeedname(int speed, char *buf);
char *getspeednameshort(int speed, char *buf); char *getspeednameshort(int speed, char *buf);

29
map.c
View File

@ -152,6 +152,7 @@ map_t *addmap(void) {
a->beingcreated = B_TRUE; a->beingcreated = B_TRUE;
a->habitat = findhabitat(H_DUNGEON); // default!!! a->habitat = findhabitat(H_DUNGEON); // default!!!
a->lastplayervisit = -1; a->lastplayervisit = -1;
a->nfixedrooms = 0;
return a; return a;
} }
@ -262,7 +263,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int
} }
} }
if (!lfhasflag(lf, F_HIDING) && !lfhasflag(lf, F_DEAF) && cansleep(lf) ) { if (!lfhasflag(lf, F_HIDING) && !lfhasflag(lf, F_DEAF) && cansleep(lf) ) {
int asleepchance = 50; int asleepchance = 70;
f = lfhasflag(lf, F_STARTASLEEPPCT); f = lfhasflag(lf, F_STARTASLEEPPCT);
if (f) { if (f) {
asleepchance = f->val[0]; asleepchance = f->val[0];
@ -1785,8 +1786,15 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
} }
} }
} }
// adjust min/maxrooms based on fixed vaults
minrooms -= map->nfixedrooms;
maxrooms -= map->nfixedrooms;
limit(&minrooms, 0, NA);
limit(&maxrooms, 0, NA);
// create rooms // create rooms
if (wantrooms) { if (wantrooms && (maxrooms > 0)) {
numrooms = rnd(minrooms, maxrooms); numrooms = rnd(minrooms, maxrooms);
//printf("using %d rooms\n",numrooms); //printf("using %d rooms\n",numrooms);
@ -1843,6 +1851,12 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
if (map->region->rtype->id == RG_FIRSTDUNGEON) { if (map->region->rtype->id == RG_FIRSTDUNGEON) {
if (c->lf) killlf(c->lf); if (c->lf) killlf(c->lf);
addobfast(c->obpile, OT_MAGICBARRIER); addobfast(c->obpile, OT_MAGICBARRIER);
// also clear all the cells around it to prevent reachability errors
for (d = DC_N; d <= DC_NW; d++) {
cell_t *c2;
c2 = getcellindir(c, d);
if (c2) setcelltype(c2, map->habitat->emptycelltype);
}
} }
} else { } else {
for (i = 0; i < map->region->rtype->stairsperlev; i++) { for (i = 0; i < map->region->rtype->stairsperlev; i++) {
@ -2276,6 +2290,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
map->name = strdup(buf); map->name = strdup(buf);
// get a list of what things are here based on the region's outline // get a list of what things are here based on the region's outline
map->nfixedrooms = 0;
nthings = 0; nthings = 0;
if (region->outline) { if (region->outline) {
if (db) dblog(" checking region outline for things..."); if (db) dblog(" checking region outline for things...");
@ -2312,6 +2327,16 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
if (db) dblog(" remembering region thing for later."); if (db) dblog(" remembering region thing for later.");
// remember this thing // remember this thing
thing[nthings] = &region->outline->thing[i]; thing[nthings] = &region->outline->thing[i];
switch (thing[nthings]->whatkind) {
case RT_VAULT:
case RT_RNDVAULTWITHFLAG:
// this will reduce the amount of random rooms which can
// be created on this map.
map->nfixedrooms++;
break;
default:
break;
}
nthings++; nthings++;
} }
} }

40
move.c
View File

@ -1419,18 +1419,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
for (o = newcell->obpile->first ; o ; o = nexto ) { for (o = newcell->obpile->first ; o ; o = nexto ) {
nexto = o->next; nexto = o->next;
if (hasflag(o->flags, F_TRAP)) { if (hasflag(o->flags, F_TRAP)) {
char trapname[BUFLEN]; triggertrap(lf, NULL, o, lf->cell);
getobname(o, trapname, 1);
if (haslos(player, newcell)) {
msg("%s trigger%s %s!", lfname, isplayer(lf) ? "" : "s", trapname);
if (isplayer(lf)) more();
}
if (haslos(player, newcell)) {
// no longer hidden
killflagsofid(o->flags, F_SECRET);
}
// NOTE: after trapeffects(), o might be killed.
trapeffects(o, o->type->id, lf);
interrupt(lf); interrupt(lf);
} }
} }
@ -2086,6 +2075,31 @@ int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke) {
return B_FALSE; return B_FALSE;
} }
void triggertrap(lifeform_t *lf, object_t *o, object_t *trapob, cell_t *where) {
char triggerer[BUFLEN];
char trapname[BUFLEN];
int wants;
getobname(trapob, trapname, 1);
if (lf) {
getlfname(lf, triggerer);
if (isplayer(lf)) wants = B_FALSE;
else wants = B_TRUE;
} else {
getobname(o, triggerer, o->amt);
if (o->amt == 1) wants = B_TRUE;
else wants = B_FALSE;
}
if (haslos(player, where)) {
msg("%s trigger%s %s!", triggerer, (wants) ? "s" : "", trapname);
if (lf && isplayer(lf)) more();
// no longer hidden
killflagsofid(trapob->flags, F_SECRET);
}
// NOTE: after trapeffects(), oo might be killed.
trapeffects(trapob, trapob->type->id, where);
if (lf) interrupt(lf);
}
int trymove(lifeform_t *lf, int dir, int onpurpose) { int trymove(lifeform_t *lf, int dir, int onpurpose) {
cell_t *cell; cell_t *cell;
@ -2498,7 +2512,7 @@ int walkoffmap(lifeform_t *lf, int dir, int onpurpose) {
if (onpurpose) { if (onpurpose) {
// get list of adjacent allies // get list of adjacent allies
if (isplayer(lf)) { if (isplayer(lf)) {
getadjallies(lf, NULL, adjally, &nadjallies); getwhowillfollow(lf, NULL, adjally, &nadjallies);
} }
} }

1
move.h
View File

@ -27,6 +27,7 @@ int isorthogonal(int dir);
int ispossiblemove(lifeform_t *lf, int dir); int ispossiblemove(lifeform_t *lf, int dir);
void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int onpurpose); void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int onpurpose);
int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke); int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke);
void triggertrap(lifeform_t *lf, object_t *o, object_t *trapob, cell_t *where);
int trymove(lifeform_t *lf, int dir, int onpurpose); int trymove(lifeform_t *lf, int dir, int onpurpose);
int tryrun(lifeform_t *lf, int dir); int tryrun(lifeform_t *lf, int dir);
int trysneak(lifeform_t *lf, int dir); int trysneak(lifeform_t *lf, int dir);

View File

@ -231,6 +231,7 @@ int main(int argc, char **argv) {
// add abilities which the player always has // add abilities which the player always has
addflag(player->flags, F_CANWILL, OT_A_PRAY, 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);
user = getenv("USER"); user = getenv("USER");
if (user) { if (user) {
@ -246,7 +247,7 @@ int main(int argc, char **argv) {
skill_t *sk; skill_t *sk;
initprompt(&prompt, "Select your spell specialty:"); initprompt(&prompt, "Select your spell specialty:");
addchoice(&prompt, 'a', getskillname(SK_SS_AIR), NULL, findskill(SK_SS_AIR)); addchoice(&prompt, 'a', getskillname(SK_SS_AIR), NULL, findskill(SK_SS_AIR));
addchoice(&prompt, 'i', getskillname(SK_SS_COLD), NULL, findskill(SK_SS_COLD)); addchoice(&prompt, 'c', getskillname(SK_SS_COLD), NULL, findskill(SK_SS_COLD));
addchoice(&prompt, 'f', getskillname(SK_SS_FIRE), NULL, findskill(SK_SS_FIRE)); addchoice(&prompt, 'f', getskillname(SK_SS_FIRE), NULL, findskill(SK_SS_FIRE));
getchoice(&prompt); getchoice(&prompt);
sk = (skill_t *) prompt.result; sk = (skill_t *) prompt.result;
@ -256,7 +257,7 @@ int main(int argc, char **argv) {
addflag(player->flags, F_CANCAST, OT_S_MIST, NA, NA, NULL); addflag(player->flags, F_CANCAST, OT_S_MIST, NA, NA, NULL);
break; break;
case SK_SS_COLD: case SK_SS_COLD:
addflag(player->flags, F_CANCAST, OT_S_FROSTBITE, NA, NA, NULL); addflag(player->flags, F_CANCAST, OT_S_CHILL, NA, NA, NULL);
break; break;
case SK_SS_FIRE: case SK_SS_FIRE:
addflag(player->flags, F_CANCAST, OT_S_SPARK, NA, NA, NULL); addflag(player->flags, F_CANCAST, OT_S_SPARK, NA, NA, NULL);

445
objects.c

File diff suppressed because it is too large Load Diff

View File

@ -233,7 +233,8 @@ int takedamage(object_t *o, unsigned int howmuch, int damtype);
int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantannounce); int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantannounce);
int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, object_t *firearm); int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, object_t *firearm);
void timeeffectsob(object_t *o); void timeeffectsob(object_t *o);
void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf); //void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf);
void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c);
void turnoff(lifeform_t *lf, object_t *o); void turnoff(lifeform_t *lf, object_t *o);
void turnon(lifeform_t *lf, object_t *o); void turnon(lifeform_t *lf, object_t *o);
int uncurseob(object_t *o, int *seen); int uncurseob(object_t *o, int *seen);

521
spell.c
View File

@ -416,9 +416,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} }
if (trapflag->id == F_TRAP) { if (trapflag->id == F_TRAP) {
trapeffects(trapob, trapob->type->id, user); trapeffects(trapob, trapob->type->id, user->cell);
} else { } else {
trapeffects(NULL, trapflag->val[0], user); trapeffects(NULL, trapflag->val[0], user->cell);
} }
} else { } else {
getobname(trapob, buf, 1); getobname(trapob, buf, 1);
@ -986,6 +986,59 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// cause ongoing pain for 2 turns // cause ongoing pain for 2 turns
addtempflag(target->flags, F_PAIN, DT_ACID, NA, NA, damstr, 2); addtempflag(target->flags, F_PAIN, DT_ACID, NA, NA, damstr, 2);
taketime(user, getactspeed(user)); taketime(user, getactspeed(user));
} else if (abilid == OT_A_STUDYSCROLL) {
object_t *o;
int difficulty, mod;
flag_t *f;
// only players can do this
if (!isplayer(user)) {
return B_TRUE;
}
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("That wouldn't be a good idea while swimming.");
return B_TRUE;
}
if (!haslos(user, user->cell)) {
msg("You can't study anything, since you can't see!");
return B_TRUE;
}
// ask what to inspect
initprompt(&prompt, "Study which scroll");
for (o = user->pack->first ; o ; o = o->next) {
if ((o->type->obclass->id == OC_SCROLL) && isknown(o)) {
f = hasflag(o->flags, F_LINKSPELL);
if (f && !cancast(user, f->val[0], NULL)) {
getobname(o, buf, o->amt);
addchoice(&prompt, o->letter, buf, NULL, f);
}
}
}
getchoice(&prompt);
f = (flag_t *)prompt.result;
if (!f) {
msg("Cancelled");
return B_TRUE;
}
o = f->pile->ob;
// try to transcribe it...
difficulty = 20 + (getspelllevel(f->val[0])*3);
mod = getspellskill(user, f->val[0]) * 2;
if (skillcheck(user, SC_LEARNMAGIC, difficulty, mod)) {
addflag(user->flags, F_CANCAST, f->val[0], NA, NA, NULL);
} else {
// failed!
msg("You fail to comprehend this spell.");
}
taketime(user, getactspeed(user));
// now kill the scroll
msg("The scroll crumbles to dust.");
removeob(o, 1);
} else if (abilid == OT_A_SUCKBLOOD) { } else if (abilid == OT_A_SUCKBLOOD) {
int dam = 0; int dam = 0;
@ -1135,6 +1188,23 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (haslos(player, origcell)) { if (haslos(player, origcell)) {
redraw(); redraw();
} }
} else if (abilid == OT_A_TRAIN) {
// can we train?
if (!user->skillpoints && !lfhasflag(user, F_HASNEWLEVEL)) {
if(isplayer(user)) {
msg("You are not ready for any training right now.");
}
return B_TRUE;
}
// safe to train?
if (check_rest_ok(user)) return B_TRUE;
// start training!
if (!startresting(user, B_TRUE)) {
// do the first one right away
rest(user, B_TRUE);
}
} else if (abilid == OT_A_TUMBLE) { } else if (abilid == OT_A_TUMBLE) {
cell_t *origcell,*c; cell_t *origcell,*c;
cell_t *retcell[MAXRETCELLS]; cell_t *retcell[MAXRETCELLS];
@ -1341,6 +1411,91 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} }
msg("all blinded!"); msg("all blinded!");
return B_FALSE; return B_FALSE;
} else if (abilid == OT_A_COMBOSTRIKE) {
object_t *wep;
skill_t *wepsk = NULL;
int keepgoing = B_TRUE,nhits = 0;
enum SKILLLEVEL slev;
if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) {
if (isplayer(user)) msg("You cannot perform a combination attack while swimming.");
return B_TRUE;
}
wep = getweapon(user);
if (wep) {
wepsk = getobskill(wep);
} else {
wepsk = findskill(SK_UNARMED);
}
if (wepsk) {
slev = getskill(user, wepsk->id);
} else {
slev = PR_INEPT;
}
if (slev < PR_MASTER) {
if (isplayer(user)) msg("You must have Mastered your weapon to perform a combination attack.");
return B_TRUE;
}
if (!getadjenemies(user, NULL, NULL)) {
if (isplayer(user)) msg("You cannot see anyone nearby to attack!");
return B_TRUE;
}
// take time
taketime(user, getattackspeed(user));
// remember that we are doing a combo. this will stop taketime() from being
// 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) {
char ques[BUFLEN];
sprintf(ques,"%s combination in which direction (- to cancel)", nhits ? "Continue" : "Start");
dirch = askchar("%s combination in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE);
if (dirch == '-') {
break;
} else {
int dir;
dir = chartodir(dirch);
c = getcellindir(user->cell, dir);
}
}
// attack in that dir
if (c && c->lf) {
attackcell(user, c, B_TRUE);
// if the lf there died, keep going.
if (!c->lf || isdead(c->lf)) {
keepgoing = B_TRUE;
}
// other reasons to stop the combo now?
if (keepgoing) {
if (isdead(user) || (getweapon(user) != wep)) { // dead or lost our weapon?
keepgoing = B_FALSE;
} else if (!getadjenemies(user, NULL, NULL)) { // noone left to attack
keepgoing = B_FALSE;
}
}
} else {
msg("Combination ended.");
keepgoing = B_FALSE;
}
// process lf deaths, then redraw the screen
checkdeath();
needredraw = B_TRUE;
drawscreen();
more(); // clear msgs
nhits++;
}
killflagsofid(user->flags, F_COMBOSTRIKE);
} else if (abilid == OT_A_DEBUG) { } else if (abilid == OT_A_DEBUG) {
cell_t *where; cell_t *where;
where = askcoords("Debug who?", "Debug->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE); where = askcoords("Debug who?", "Debug->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
@ -1430,7 +1585,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// ask for direction // ask for direction
if (!targcell) { if (!targcell) {
dirch = askchar("Attack in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE); dirch = askchar("Heavy blow in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE);
if (dirch == '.') { if (dirch == '.') {
// yourself! // yourself!
targcell = user->cell; targcell = user->cell;
@ -1475,7 +1630,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// ask for direction // ask for direction
if (!targcell) { if (!targcell) {
dirch = askchar("Attack in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE); dirch = askchar("Quivering Palm in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE);
if (dirch == '.') { if (dirch == '.') {
// yourself! // yourself!
targcell = user->cell; targcell = user->cell;
@ -1731,29 +1886,34 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// ask what to inspect // ask what to inspect
o = askobject(user->pack, "Inspect which object", NULL, AO_NOTKNOWN);
initprompt(&prompt, "Inspect which object");
for (o = user->pack->first ; o ; o = o->next) {
int classok = B_FALSE;
// can only inspect certain types of things
switch (o->type->obclass->id) {
case OC_SCROLL:
case OC_BOOK:
case OC_WAND:
case OC_RING:
classok = B_TRUE;
break;
default:
break;
}
if (classok && !isknown(o)) {
char buf[BUFLEN];
getobname(o, buf, o->amt);
addchoice(&prompt, o->letter, buf, NULL, f);
}
}
getchoice(&prompt);
o = (object_t *)prompt.result;
if (!o) { if (!o) {
msg("Cancelled"); msg("Cancelled");
return B_TRUE; return B_TRUE;
} }
if (isknown(o)) {
msg("You already know what that is!");
return B_TRUE;
}
// can only inspect certain types of things
switch (o->type->obclass->id) {
case OC_SCROLL:
case OC_BOOK:
case OC_WAND:
case OC_RING:
break;
default:
msg("Your knowledge doesn't extend to this kind of item.");
return B_TRUE;
}
// failed this already? // failed this already?
if (lfhasflagval(user, F_FAILEDINSPECT, o->type->id, NA, NA, NULL)) { if (lfhasflagval(user, F_FAILEDINSPECT, o->type->id, NA, NA, NULL)) {
msg("You won't be able to recognise this until you are more experienced."); msg("You won't be able to recognise this until you are more experienced.");
@ -2712,6 +2872,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_CHILL) { } else if (spellid == OT_S_CHILL) {
char lfname[BUFLEN]; char lfname[BUFLEN];
int exposedlimbs,dam;
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = targcell->lf; target = targcell->lf;
if (!target) { if (!target) {
@ -2720,18 +2881,23 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
getlfname(target, lfname); getlfname(target, lfname);
// how many body parts are impacted?
exposedlimbs = getexposedlimbs(target);
dam = rnd(1,exposedlimbs);
if (isplayer(target)) { if (isplayer(target)) {
if (isimmuneto(target->flags, DT_COLD)) { if (isimmuneto(target->flags, DT_COLD)) {
msg("You feel mildly chilly."); msg("You feel mildly chilly.");
} else { } else {
msg("You feel very cold!"); msg("You feel cold!");
} }
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) { } else if (cansee(player, target)) {
if (isimmuneto(target->flags, DT_COLD)) { if (isimmuneto(target->flags, DT_COLD)) {
msg("%s looks mildly chilly.", lfname); msg("%s looks mildly chilly.", lfname);
} else { } else {
msg("%s looks very cold!", lfname); msg("%s looks cold!", lfname);
} }
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
@ -2739,7 +2905,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// target takes magical damage // target takes magical damage
// always hit // always hit
if (!isimmuneto(target->flags, DT_COLD)) { if (!isimmuneto(target->flags, DT_COLD)) {
losehp(target, roll("1d3"), DT_COLD, caster, "a frostbite spell"); losehp(target, dam, DT_COLD, caster, "a chill spell");
} }
} else if (spellid == OT_S_COLDBURST) { } else if (spellid == OT_S_COLDBURST) {
int range = 1; int range = 1;
@ -2950,6 +3116,53 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} }
} else if (spellid == OT_S_CRYSTALSHIELD) {
object_t *o;
targcell = caster->cell;
target = caster;
if (getequippedob(target->pack, BP_SECWEAPON)) {
fizzle(caster);
stopspell(caster, spellid);
return B_FALSE;
}
o = addob(target->pack, "ice crystal shield");
if (o) {
if (canwear(target, o, BP_NONE)) {
flag_t *f;
enum LFSIZE sz;
if (power <= 2) {
sz = SZ_SMALL;
} else if (power <= 4) {
sz = SZ_MEDIUM;
} else {
sz = SZ_LARGE;
}
// announce
if (isplayer(target)) {
msg("A %s shield of shimmering ice forms in your hand!", getsizetext(sz));
} else if (cansee(player, target)) {
msg("A %s shield of shimmering ice forms in %s%s hand!", getsizetext(sz), castername,
getpossessive(castername));
}
wear(target, o);
// set its values
f = hasflag(o->flags, F_ARMOURRATING);
if (f) f->val[0] = power;
f = hasflag(o->flags, F_OBHP);
if (f) {
f->val[0] = power*5;
f->val[1] = power*5;
}
} else {
killob(o);
fizzle(caster);
stopspell(caster, spellid);
}
} else {
fizzle(caster);
stopspell(caster, spellid);
return B_FALSE;
}
} else if (spellid == OT_S_CUREPOISON) { } else if (spellid == OT_S_CUREPOISON) {
if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power, frompot)) return B_TRUE;
target = targcell->lf; target = targcell->lf;
@ -3233,6 +3446,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
nseen++; nseen++;
removeob(o, ALL); removeob(o, ALL);
} else if (o->material->id == MT_ICE) {
takedamage(o, roll("2d6"), DT_FIRE);
} }
} }
} }
@ -3388,7 +3603,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
amt = rnd(1,6) + power; amt = rnd(1,6) + power;
gainhp(target, amt); gainhp(target, amt);
// caster loses it // caster loses it
amt = losehp(caster, rnd(1,6) + power, DT_NECROTIC, caster, "lifeforce drain"); amt = losehp(caster, amt, DT_NECROTIC, caster, "lifeforce drain");
} else { } else {
// target loses hp // target loses hp
amt = losehp(target, rnd(1,6) + power, DT_NECROTIC, caster, "lifeforce drain"); amt = losehp(target, rnd(1,6) + power, DT_NECROTIC, caster, "lifeforce drain");
@ -4029,7 +4244,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// target takes magical damage // target takes magical damage
// always hit // always hit
if (!isimmuneto(target->flags, DT_COLD)) { if (!isimmuneto(target->flags, DT_COLD)) {
losehp(target, dam, DT_COLD, caster, "a chill spell"); losehp(target, dam, DT_COLD, caster, "a frostbite spell");
} }
} else if (spellid == OT_S_GASEOUSFORM) { } else if (spellid == OT_S_GASEOUSFORM) {
if (!target) target = caster; if (!target) target = caster;
@ -4050,6 +4265,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
setrace(target, R_GASCLOUD, B_TRUE); setrace(target, R_GASCLOUD, B_TRUE);
} }
} else if (spellid == OT_S_GLACIATE) {
object_t *o,*nexto;
int donesomething = B_FALSE;
if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (haslos(player, targcell)) {
msg("A puff of vapour appears.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
for (o = targcell->obpile->first ; o ; o = nexto) {
nexto = o->next;
takedamage(o, 1, DT_COLD);
donesomething = B_TRUE;
}
} else if (spellid == OT_S_GREASE) { } else if (spellid == OT_S_GREASE) {
int radius; int radius;
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
@ -5663,7 +5893,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (target && cansee(player, target)) { if (target && cansee(player, target)) {
msg("A gust of wind whips up around %s!", targname); msg("A gust of wind whips up around %s!", targname);
} else if (haslos(player, targcell)) { } else if (haslos(player, targcell)) {
msg("A gust of wind whips up!"); msg("A gust of wind whips up from nowhere!");
} }
// chance of blowing each ob away // chance of blowing each ob away
@ -5687,6 +5917,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
needredraw = B_TRUE; needredraw = B_TRUE;
} else if (spellid == OT_S_MIST) { } else if (spellid == OT_S_MIST) {
object_t *o; object_t *o;
lifeform_t *l;
targcell = caster->cell; targcell = caster->cell;
if (haslos(player, targcell)) { if (haslos(player, targcell)) {
@ -5708,6 +5940,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f->val[1] += power; f->val[1] += power;
} }
} }
// hack - make all monsters who can see you stop targetting you.
for (l = caster->cell->map->lf ; l ; l = l->next) {
flag_t *f;
if ((l != caster) && (gethitdice(l) <= gethitdice(caster)) ) {
f = lfhasflagval(l, F_TARGETLF, caster->id, NA, NA, NULL);
if (f) killflag(f);
f = lfhasflagval(l, F_TARGETCELL, caster->cell->x, caster->cell->y, NA, NULL);
if (f) killflag(f);
}
}
} else if (spellid == OT_S_MENDING) { } else if (spellid == OT_S_MENDING) {
object_t *o; object_t *o;
int donesomething = B_FALSE; int donesomething = B_FALSE;
@ -6149,6 +6392,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (seen) { if (seen) {
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
if (isplayer(caster)) {
needredraw = B_TRUE;
}
} else { } else {
if (isplayer(caster)) { if (isplayer(caster)) {
nothinghappens(); nothinghappens();
@ -6249,6 +6495,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (failed) { if (failed) {
fizzle(caster); fizzle(caster);
} }
} else if (spellid == OT_S_SLIDE) {
flag_t *f;
target = caster;
if (lfhasflag(target, F_ICESLIDE)) {
fizzle(target);
return B_TRUE;
}
f = addtempflag(target->flags, F_ICESLIDE, power, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
f = addtempflag(target->flags, F_AUTOCREATEOB, 0, NA, NA, "sheet of ice", FROMSPELL);
f->obfrom = spellid;
f = addtempflag(target->flags, F_FASTMOVE, 10, NA, NA, "sheet of ice", FROMSPELL);
f->obfrom = spellid;
if (cansee(player, target) && seenbyplayer) if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (spellid == OT_S_SLOW) { } else if (spellid == OT_S_SLOW) {
int howlong = 15; int howlong = 15;
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
@ -6294,6 +6555,63 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// use direct damage rather than holy, because otherwise it might be increased // use direct damage rather than holy, because otherwise it might be increased
// due to vulnerabilities // due to vulnerabilities
losehp(target, rnd(1,power*2), DT_DIRECT, caster, "a smiting"); losehp(target, rnd(1,power*2), DT_DIRECT, caster, "a smiting");
} else if (spellid == OT_S_SNOWBALL) {
int failed = B_FALSE;
// ask for a target cell
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (targcell) {
if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) {
int dir;
cell_t *c;
// centre snowball here...
if (isplayer(caster)) {
msg("You launch a huge snowball!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, caster)) {
msg("%s launches a huge snowball!",castername);
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, targcell)) {
msg("An enormous ball of fire explodes!");
}
anim(caster->cell, targcell, '^', C_WHITE);
animradialorth(targcell, 1, '}', C_WHITE);
redrawpause();
// add snow as follows (3 = medium, 2 = medium, 1 = smell)
// o
// ooo
// o
if (targcell->lf) {
losehp(targcell->lf, 1, DT_COLD, caster, "a snowball");
} else {
addob(targcell->obpile, "small puddle of water");
}
for (dir = D_N; dir <= D_W; dir++) {
c = getcellindir(targcell, dir);
if (c && !c->type->solid ) {
if (c->lf) {
losehp(c->lf, 1, DT_COLD, caster, "a snowball");
} else {
addob(c->obpile, "small puddle of water");
}
}
}
redrawresume();
} else {
failed = B_TRUE;
}
} else {
if (isplayer(caster)) {
msg("You have no line of fire to there!");
}
failed = B_TRUE;
}
if (failed) {
fizzle(caster);
}
} else if (spellid == OT_S_SOFTENEARTH) { } else if (spellid == OT_S_SOFTENEARTH) {
int seen = B_FALSE; int seen = B_FALSE;
int ndone = 0; int ndone = 0;
@ -7950,131 +8268,6 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) {
return power; return power;
} }
/*
ooooooo old oooooooo
int getspellpower(lifeform_t *lf, enum OBTYPE spellid) {
int power = 0;
int statmod;
int spelllev;
enum SKILLLEVEL spellskill,schoolskill;
enum SPELLSCHOOL school;
int db = B_FALSE;
int max = 10;
flag_t *f;
objecttype_t *ot;
ot = findot(spellid);
if (db) dblog("getspellpower for lf %s, spell %s", lf->race->name, ot->name);
// first: can we WILL this to occur? if so, we might have a set
// spellpower
f = lfhasflagval(lf, F_CANWILL, spellid, NA, NA, NULL);
if (f && strlen(f->text)) {
texttospellopts(f->text, &power, NULL, NULL, NULL);
if (power > 0) {
if (db) {
dblog("-->power = %d (from canwill)", power);
}
return power;
}
}
// player can only ever cast spells up to your level.
if (isplayer(lf) && !hasjob(lf, J_GOD)) {
if (getspelllevel(spellid) > lf->level) {
if (db) {
dblog("-->power = 0 (spell level > lf level)", power);
}
return 0;
}
}
// statmod is -1 to 1
statmod = getstatmod(lf, A_IQ);
if (statmod >= 40) {
statmod = 1;
} else if (statmod <= -40) {
statmod = -1;
} else {
statmod = 0;
}
school = getspellschoolknown(lf, spellid);
spellskill = getskill(lf, SK_SPELLCASTING);
if (hasjob(lf, J_DRUID) && (school == SS_NATURE)) {
// druid doesn't use spellcasting skill for nature spells
} else {
// dont need spellcasting skill for mental/allomancy
switch (school) {
case SS_ALLOMANCY:
case SS_MENTAL:
break;
default:
if (spellskill == PR_INEPT) {
if (db) {
dblog("-->power = 0 (inept in sorcery)");
}
return 0;
}
break;
}
}
if (hasjob(lf, J_DRUID)) {
power = (lf->level/3) + statmod;
if (db) dblog("-->(druid) basepower from level+iq is %d", power);
} else {
// every 6 levels you get 1 more power
// ie. at level 30 you get +5 power
power = (lf->level/6) + statmod;
if (db) dblog("-->basepower from level+iq is %d", power);
}
switch (school) {
case SS_ALLOMANCY:
case SS_MENTAL:
break;
default:
if (db) dblog("--> + %d from skill in Sorcery", spellskill);
power += spellskill;
break;
}
spelllev = getspelllevel(spellid);
if (spelllev > 0) {
int divamt;
if ((school == SS_ALLOMANCY) || (school == SS_MENTAL)) {
divamt = (spelllev/2);
} else {
divamt = spelllev;
}
if (divamt > 0) {
if (db) dblog("--> divided by %d (based on spelllevel %d)", divamt, spelllev);
power /= divamt;
}
}
// specialised school skill - apply this AFTER dividing by spell level
schoolskill = getskill(lf, getschoolskill(school));
if (schoolskill != PR_INEPT) {
float addamt;
addamt = (float)schoolskill * 1.5;
if (db) dblog("--> + %0.1f from skill in %s", addamt, getschoolname(school));
power += addamt;
}
// enforce maximum
max = getspellmaxpower(spellid);
if (power > max) power = max;
if (db) dblog("==> final power: %d", power);
return power;
}
*/
enum SPELLSCHOOL getspellschool(enum OBTYPE spellid) { enum SPELLSCHOOL getspellschool(enum OBTYPE spellid) {
flag_t *f; flag_t *f;
objecttype_t *ot; objecttype_t *ot;
@ -8154,6 +8347,14 @@ enum SPELLSCHOOL getspellschoolknown(lifeform_t *lf, enum OBTYPE spellid) {
return thisschool; return thisschool;
} }
enum SKILLLEVEL getspellskill(lifeform_t *lf, enum OBTYPE spellid) {
enum SPELLSCHOOL school;
enum SKILLLEVEL slev;
school = getspellschoolknown(lf, spellid);
slev = getskill(lf, getschoolskill(school));
return slev;
}
int getspellrange(enum OBTYPE spellid, int power) { int getspellrange(enum OBTYPE spellid, int power) {
objecttype_t *st; objecttype_t *st;
int range = UNLIMITED; int range = UNLIMITED;
@ -8363,7 +8564,18 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) {
// remove any other specific effects based on spell type. // remove any other specific effects based on spell type.
for (o = caster->pack->first; o ; o = nexto) { for (o = caster->pack->first; o ; o = nexto) {
nexto = o->next; nexto = o->next;
if (o->type->id == OT_ENERGYBLADE) { if ((o->type->id == OT_ENERGYBLADE) && (spellid == OT_S_SUMMONWEAPON)) {
if (cansee(player, caster)) {
char obname[BUFLEN];
char lfname[BUFLEN];
getobname(o, obname, 1);
getlfname(caster, lfname);
msg("%s%s %s vanishes.", lfname, getpossessive(lfname),
obname);
}
killob(o);
}
if ((o->type->id == OT_ICESHIELD) && (spellid == OT_S_CRYSTALSHIELD)) {
if (cansee(player, caster)) { if (cansee(player, caster)) {
char obname[BUFLEN]; char obname[BUFLEN];
char lfname[BUFLEN]; char lfname[BUFLEN];
@ -8375,6 +8587,7 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) {
killob(o); killob(o);
} }
} }
if ((spellid == OT_S_BARKSKIN) && (getlfmaterial(caster) == MT_WOOD)) { if ((spellid == OT_S_BARKSKIN) && (getlfmaterial(caster) == MT_WOOD)) {
setlfmaterial(caster, caster->race->material->id); setlfmaterial(caster, caster->race->material->id);
} else if (spellid == OT_S_FLOATINGDISC) { } else if (spellid == OT_S_FLOATINGDISC) {

View File

@ -18,6 +18,7 @@ char *getspellname(enum OBTYPE spellid, lifeform_t *lf, char *buf);
int getspellpower(lifeform_t *lf, enum OBTYPE spellid); int getspellpower(lifeform_t *lf, enum OBTYPE spellid);
enum SPELLSCHOOL getspellschool(enum OBTYPE spellid); enum SPELLSCHOOL getspellschool(enum OBTYPE spellid);
enum SPELLSCHOOL getspellschoolknown(lifeform_t *lf, enum OBTYPE spellid); enum SPELLSCHOOL getspellschoolknown(lifeform_t *lf, enum OBTYPE spellid);
enum SKILLLEVEL getspellskill(lifeform_t *lf, enum OBTYPE spellid);
int getspellrange(enum OBTYPE spellid, int power); int getspellrange(enum OBTYPE spellid, int power);
char *getvarpowerspelldesc(enum OBTYPE spellid, int power, char *buf); char *getvarpowerspelldesc(enum OBTYPE spellid, int power, char *buf);
void pullobto(object_t *o, lifeform_t *lf); void pullobto(object_t *o, lifeform_t *lf);