- [+] intelligent (ie. more than animal) ai shouldn't move if it will

cause damage
    - [+] move_will_hurt()
        - [+] ie. if in PAIN, or appropriate injury.
- [+] if you're deaf, use "the xx says something" rather than "the xx
      says yy"
- [+] STILL reachability errors in dlev 6 (jimbos' lair not linked)
- [+] new forest habitat mechanism - clusters of trees
- [+] bashing injury if you are slammed into a wall?
- [+] jimbo didn't have a weapon! "+2 halberd" not working
- [+] if you don't have knowledge about a creature, still show items
      (but only equipped ones)
- [+] listen skill should take longer to train
- [+] candle should last longer
- [+] carrot grants temp darkvision
- [+] shouldn't be able to eat stuff from floor while levitating
- [+] CHANGE f_hitdice to use text
- [+] fear spell from dretch always failing even on l1 player.  why?
* [+] summondemon spell
- [+] adjust spell damage - 1d6 per level.
ice spells:
- [+] l4 - ice armour (higher power means more pieces of ice armour)
    - [+] (power/3)+1 pieces of armour. ie. 1 - 4
    - [+] order:  body,helmet, gloves, feet
    - [+] 4AC each.
* [+] l5 - shardshot (higher level ray damage, does less damage the
      further away it goes)
- [+] l5 - snap freeze ? turn one lf to ice?
- [+] more things which use light attacks (ie. make glasses useful)
- [+] replace bp_righthand with bp_rightfinger
- [+] bug in blink spell: "Nothing seems to happen."
- [+] make metal resist bite/slash/chop, not be immune.
- [+] fix shatter spell on glass wall
* [+] bug: in jimbos vault and plaeyrstart2, exits are being added in
      in appropriate places.
* [+] make player's starting point be a "prison_cell" vault.
- [+] earplugs - stop all sound.  
    - [+] make f_deaf an intrinsic (ie. announcements)
    - [+] add the object
critical hits:
- [+] "you hit xxx" "xxx turns to flee" "xxx's leg is bruised"
    - [+] need losehp to NOT trigger fightback in this case - we will
          trigger it ourself after crithit.
    - [+] pass this as a param?
- [+] critical eye hits
    - [+] scraped eyelid (slash, lower accuracy)
    - [+] black eye (bash, lower vision range and charisma)
    - [+] destroyed eye (pierce, permenant lower vision range!)
- [+] injuries heal heaps faster when asleep
- [+] redo f_injured flag to use an "enum INJURY" IJ_xxx
- [+] change how it is applied
- [+] change how it is announced (io.c)
- [+] change how effects work (search for F_INJURY)
- [+] pierce
    - [+] pierced artery: v.high bleed
    - [+] stabbed heart (instant death, very unlikely)
- [+] slash:
    - [+] cut flexor tendon (cannot weild ANY weapon)
    - [+] slashed hamstring (fall. skillcehck every time you move, 
          vslow movement)
    - [+] severed finger
        - [+] finger drops to the ground
        - [+] ring drops to the ground
        - [+]  (get nobodypart bp_rightfinger or bp_leftfinger)
- [+] bash:
    - [+] dislocated arm (cannot weild anything heavy in that hand)
    - [+] broken rib (reduced carrying capacity)
    - [+] swelled ankle (cannot remove or put on boots)
This commit is contained in:
Rob Pearce 2011-09-05 22:04:51 +00:00
parent c181893ae4
commit 1f6429e305
19 changed files with 1340 additions and 640 deletions

2
ai.c
View File

@ -1183,7 +1183,7 @@ void aiturn(lifeform_t *lf) {
}
// do we have better armour?
for (bp = BP_RIGHTHAND ; bp < MAXBODYPARTS; bp++) {
for (bp = BP_RIGHTFINGER ; bp < MAXBODYPARTS; bp++) {
object_t *curarm;
curarm = getarmour(lf, bp);
// do we have a better one?

View File

@ -425,7 +425,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
}
if (lfhasflagval(lf, F_INJURY, NA, BP_HANDS, DT_SLASH, NULL)) {
bleed(lf);
bleed(lf, B_FALSE);
losehp(lf, 1, DT_DIRECT, NULL, "blood loss");
}
@ -762,6 +762,12 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
//dblog("reduced by armour to dam[%d] = %d",i,dam[i]);
}
// if damage has dropped to zero, it's not a critical hit anymore.
if (dam[i] <= 0) {
critical = B_FALSE;
critpos = BP_NONE;
}
if (lfhasflag(lf, F_QUIVERINGPALM)) {
// make sure damage isn't fatal
if (dam[i] >= victim->hp) {
@ -898,7 +904,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
} else if (lfhasflag(lf, F_QUIVERINGPALM)) {
// victim explodes!
losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE, NULL);
losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE, NULL, B_FALSE);
} else {
char attackername2[BUFLEN];
real_getlfname(lf, attackername2, B_FALSE);
@ -923,7 +929,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} else {
strcpy(buf, attackername2);
}
losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE, NULL);
losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE, NULL, B_FALSE);
// victim's armour loses hp
if (reduceamt && !critical) {
@ -968,7 +974,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
char lfname[BUFLEN];
dam = rolldie(f->val[0], f->val[1]) + f->val[2];
real_getlfname(lf, lfname, B_FALSE);
losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE, NULL);
losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE, NULL, B_FALSE);
if (isplayer(victim) || cansee(player, victim)) {
msg("^%c%s bites %s!", isplayer(victim) ? 'b' : 'n', lfname, victimname);
}
@ -994,7 +1000,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (nmatched >= f->val[2]) {
char damstring[BUFLEN];
snprintf(damstring, BUFLEN, "%s pack", lfname);
losehp(victim, f->val[0], f->val[1], lf, damstring);
losehp_real(victim, f->val[0], f->val[1], lf, damstring, B_TRUE, NULL, B_FALSE);
if (isplayer(victim) || cansee(player, victim)) {
msg("%c%s pack attacks %s!", isplayer(victim) ? 'b' : 'c', lfname, victimname);
}
@ -1004,7 +1010,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// critical hit effects
if (critical && damtypecausescriteffects(damtype[0])) {
criticalhit(lf, victim, critpos, damtype[0]);
}
// confer flags from attacker?
@ -1036,6 +1041,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
}
}
fightback(victim, lf);
}
// retaliation happens even if victim died
@ -1053,7 +1060,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
attackername);
}
snprintf(damstring, BUFLEN, "%s%s %s", victimname, getpossessive(victimname), noprefix(f->text));
losehp(lf, rdam, f->val[2], victim, damstring);
losehp_real(lf, rdam, f->val[2], victim, damstring, B_TRUE, NULL, B_TRUE);
}
}
@ -1104,7 +1111,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
}
fightback(victim, lf);
}
// practice?
@ -1345,14 +1351,14 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum
// chance of your helmet falling off
o = getarmour(victim, BP_HEAD);
if (o) {
if (isplayer(lf)) {
if (isplayer(victim)) {
char buf[BUFLEN];
getobname(o, buf, o->amt);
msg("Your %s falls off!", noprefix(buf));
} else if (cansee(player, lf)) {
} else if (cansee(player, victim)) {
char buf[BUFLEN], lfname[BUFLEN];
getobname(o, buf, o->amt);
getlfname(lf, lfname);
getlfname(victim, lfname);
msg("%s%s %s falls off!", lfname, getpossessive(lfname), noprefix(buf));
}
moveob(o, victim->cell->obpile, o->amt);
@ -1375,8 +1381,10 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum
if (!getarmour(victim, hitpos)) injure(victim, hitpos, damtype);
}
if (lfhasflag(lf, F_CRITKNOCKDOWN) && !isprone(victim)) {
fall(victim, lf, B_TRUE);
if (lf) {
if (lfhasflag(lf, F_CRITKNOCKDOWN) && !isprone(victim)) {
fall(victim, lf, B_TRUE);
}
}
}
@ -2033,7 +2041,6 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
int acc,ev;
int gothit = B_FALSE;
enum SKILLLEVEL lorelev = PR_INEPT;
int myroll;
flag_t *f;
// remember lore about victim...
@ -2088,37 +2095,19 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical)
acc -= ev;
// modify if we can't see the victim
if (!cansee(lf, victim)) {
acc -= 50;
}
if (!cansee(lf, victim)) acc -= 50;
// metal weapon versus magnetic shield?
if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) {
acc -= 45;
}
if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) acc -= 45;
// victim immobile or asleep?
if (isimmobile(victim) || lfhasflag(victim, F_EATING)) {
acc += 50;
}
if (isimmobile(victim) || lfhasflag(victim, F_EATING)) acc += 50;
// modify for lore level
if (lorelev != PR_INEPT) {
lorelev += (lorelev*10);
}
if (lorelev != PR_INEPT) lorelev += (lorelev*10);
limit(&acc, 0, 100);
//if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc);
myroll = rnd(1,100);
// modify for lore
if (myroll <= acc) {
gothit = B_TRUE;
}
if (pctchance(acc)) gothit = B_TRUE;
}
return gothit;

48
defs.h
View File

@ -49,6 +49,7 @@
#define B_NODOORS (0)
#define B_DONTKILL (-1)
#define B_APPENDYOU (-1)
#define B_SPLATTER (-1)
//#define B_TEMP (-1)
//#define B_PERM (-2)
@ -256,6 +257,14 @@
#define AUTO (-7654)
#define HEAVYWEPKG (5)
// how quickly the game clock increments
// 1 = roughly 30 secs per turn
#define TIMECONST (3)
// hunger constant - this is how many turns
// it will take to go from 'normal' to 'peckish' etc
// ... try to make this roughly 4 hours (check TIMECONST.
#define HUNGERCONST 500
// Time periods
#define TM_DRUNKTIME (10) // how long it takes for alcohol to wear off
#define TM_WETTIME (10) // how long it takes for things to dry
@ -520,9 +529,6 @@ enum MSGCHARCOL {
CC_VGOOD,
};
// hunger constant - this is how many turns
// it will take to go from 'normal' to 'hungry' etc
#define HUNGERCONST 200
enum MODTYPE {
M_PCT,
@ -747,7 +753,6 @@ enum RACE {
R_HOBGOBLINWAR,
R_KOBOLD,
R_LIZARDMAN,
R_LURKINGHORROR,
R_MINOTAUR,
R_OGRE,
R_OGRESAVAGE,
@ -817,6 +822,10 @@ enum RACE {
R_GIANTFLY,
R_GIANTBLOWFLY,
R_STIRGE,
// demons
R_DRETCH,
R_LURKINGHORROR,
R_QUASIT,
// undead
R_GHAST,
R_GHOST,
@ -960,6 +969,7 @@ enum OBTYPE {
OT_CLOVER,
// corpses
OT_CORPSE,
OT_FINGER,
OT_HEAD,
// potions
OT_POT_ACID,
@ -1073,6 +1083,7 @@ enum OBTYPE {
OT_S_CHILL,
OT_S_COLDBURST,
OT_S_COLDRAY,
OT_S_CRYSTALARM,
OT_S_CRYSTALSHIELD,
OT_S_FREEZEOB,
OT_S_FROSTBITE,
@ -1080,6 +1091,8 @@ enum OBTYPE {
OT_S_ICEEDGE,
OT_S_ICICLE,
OT_S_SLIDE,
OT_S_SHARDSHOT,
OT_S_SNAPFREEZE,
OT_S_SNOWBALL,
OT_S_WALLOFICE,
// -- gravity
@ -1152,6 +1165,7 @@ enum OBTYPE {
OT_S_SUMMONANIMALSSM,
OT_S_SUMMONANIMALSMD,
OT_S_SUMMONANIMALSLG,
OT_S_SUMMONDEMON,
OT_S_THORNS,
OT_S_WARPWOOD,
OT_S_WATERJET,
@ -1373,6 +1387,8 @@ enum OBTYPE {
OT_GOLDCROWN,
OT_HELMBONE,
OT_HELMFOOTBALL,
// armour - ears
OT_EARPLUGS,
// armour - eyes
OT_SUNGLASSES,
OT_EYEPATCH,
@ -1485,7 +1501,13 @@ enum OBTYPE {
// special weapons
OT_ENERGYBLADE,
OT_HANDOFGOD,
OT_ICEARMOUR,
OT_ICEBOOTS,
OT_ICEGLOVES,
OT_ICEHELMET,
OT_ICESHIELD,
// special obs
OT_PLAYERSTART,
};
@ -1495,6 +1517,7 @@ enum OBTYPE {
enum BODYPART {
BP_WEAPON = 0,
BP_SECWEAPON,
BP_EARS,
BP_EYES,
BP_HEAD,
BP_SHOULDERS,
@ -1503,10 +1526,10 @@ enum BODYPART {
BP_WAIST,
BP_LEGS,
BP_FEET,
BP_RIGHTHAND,
BP_LEFTHAND,
BP_RIGHTFINGER,
BP_LEFTFINGER,
};
#define MAXBODYPARTS (12)
#define MAXBODYPARTS (13)
// depth on a human
@ -1607,6 +1630,7 @@ enum FLAG {
F_DEAD, // object will be removed
F_ONEPERCELL, // only one of these objects can exist per cell
F_CREATEDBY, // object was made by lf id v0, text=real lfname
F_CREATEDBYSPELL, // object was made by spell id v0
F_ENCHANTABLE, // object can get +1/-1 ect
F_GODGIFT, // this was a gift form god with race v0.
F_NOSHATTER, // object will not shatter, even if it's material should.
@ -2118,7 +2142,7 @@ enum FLAG {
F_NUMAPPEAR, // when randomly appearing, can have > 1. val[0] = min, val[1] = max
F_MINIONS, // val0 % chance of appearing with v1-v2 lf of type text
F_HITDICE, // val0: # d4 to roll for maxhp per level. val1: +xx
F_HITDICE, // text = xdy+z to roll for maxhp per level.
F_MPDICE, // val0: # d4 to roll for maxmp per level. val1: +xx
F_JOB, // val0 = player's class/job
F_GODOF, // text = what this lf is the god of. use capitals.
@ -2363,6 +2387,7 @@ enum FLAG {
F_VAULTGOESIN, // this vault randomly appears in habitat type v0.
// can be repeated multiple times
// if a vault doesnt have this flag, it can go anywhere
F_VAULTISPLAYERSTART, // player can start in this vault
F_VAULTISSHOP, // this vault is a shop, so add f_shopitem to objects
// here.
F_VAULTISSHRINE, // this vault is a godstone shrine
@ -2403,9 +2428,15 @@ enum HUNGER {
// injuries
enum INJURY {
IJ_NONE,
IJ_ANKLESWOLLEN,
IJ_ARTERYPIERCE,
IJ_BLACKEYE,
IJ_CHESTBLEED,
IJ_EYELIDSCRAPED,
IJ_EYEDESTROYED,
IJ_FINGERBROKEN,
IJ_FINGERMISSING,
IJ_HAMSTRUNG,
IJ_HANDBLEED,
IJ_LEGBLEED,
IJ_LEGBROKEN,
@ -2651,6 +2682,7 @@ typedef struct room_s {
int id;
int x1,y1,x2,y2;
struct vault_s *vault;
int exitslinked; // don't need to save this.
} room_t;
typedef struct map_s {

3
flag.c
View File

@ -921,7 +921,10 @@ void timeeffectsflag(flag_t *f, int howlong) {
if (multiplier > 0) {
howlong *= multiplier;
}
} else if ((f->id == F_INJURY) && hasflag(f->pile, F_ASLEEP)) {
howlong *= 3;
}
f->lifetime -= howlong;

4
god.c
View File

@ -175,7 +175,7 @@ void angergod(enum RACE rid, int amt) {
case 2:
// summon undead
msg("\"Destroy him, my pets!\"");
summonlfs(god, player->cell, RC_UNDEAD, SZ_ANY, AL_EVIL, 3, PERMENANT);
summonlfs(god, player->cell, RC_UNDEAD, SZ_ANY, AL_EVIL, 3, PERMENANT, B_FALSE);
break;
}
break;
@ -227,7 +227,7 @@ void angergod(enum RACE rid, int amt) {
case 2:
// summon holy creautes
msg("\"Destroy him, my pets!\"");
summonlfs(god, player->cell, RC_ANY, SZ_ANY, AL_GOOD, 3, PERMENANT);
summonlfs(god, player->cell, RC_ANY, SZ_ANY, AL_GOOD, 3, PERMENANT, B_FALSE);
break;
}
break;

97
io.c
View File

@ -1240,6 +1240,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
}
break;
case F_DEAF:
if (isplayer(lf)) {
msg("^WYou cannot hear anything!");
}
donesomething = B_TRUE;
break;
case F_DTIMMUNE:
if (isplayer(lf)) { // don't know if monsters get it
msg("^gYou feel immune to %s!", getdamnamenoun(f->val[0]));
@ -1780,6 +1786,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
}
break;
case F_DEAF:
if (isplayer(lf)) {
msg("Your hearing returns.");
}
donesomething = B_TRUE;
break;
case F_DTIMMUNE:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You are no longer immune to %s.", getdamnamenoun(f->val[0]));
@ -3426,7 +3438,6 @@ void describeob(object_t *o) {
}
// skip line
y++;
@ -3615,7 +3626,7 @@ void describeob(object_t *o) {
mvwprintw(mainwin, y, 0, "%s modifies your %s.", buf, getattrname(f->val[1])); y++;
break;
case F_BLIND:
mvwprintw(mainwin, y, 0, "%s prevents you from seeing.", buf); y++;
mvwprintw(mainwin, y, 0, "%s prevents you from seeing anything.", buf); y++;
break;
case F_BREATHWATER:
mvwprintw(mainwin, y, 0, "%s allows you to breath normally while underwater.", buf); y++;
@ -3623,6 +3634,9 @@ void describeob(object_t *o) {
case F_CONTROL:
mvwprintw(mainwin, y, 0, "%s lets you control teleportation and polymorphic effects.", buf); y++;
break;
case F_DEAF:
mvwprintw(mainwin, y, 0, "%s prevents you from hearing anything.", buf); y++;
break;
case F_DETECTLIFE:
mvwprintw(mainwin, y, 0, "%s will detect nearby lifeforms.", buf); y++;
break;
@ -4611,7 +4625,7 @@ void doeat(obpile_t *op) {
// edible objects here?
for (o = player->cell->obpile->first; o ; o = o->next) {
if (caneat(player, o)) {
if (caneat(player, o) && canpickup(player, o, 1)) {
getobname(o, obname, o->amt);
snprintf(buf, BUFLEN, "There %s %s here. Eat %s",
(o->amt == 1) ? "is" : "are",
@ -5211,7 +5225,7 @@ void dooperate(obpile_t *op) {
// operable objects here?
for (o = player->cell->obpile->first; o ; o = o->next) {
if (isoperable(o)) {
if (isoperable(o) && canpickup(player, o, 1)) {
char obname[BUFLEN],buf[BUFLEN];
char verb[BUFLEN];
int ch;
@ -5503,7 +5517,7 @@ void doquaff(obpile_t *op) {
// quaffable objects here?
for (o = player->cell->obpile->first; o ; o = o->next) {
if (isdrinkable(o) && canquaff(player, o)) {
if (isdrinkable(o) && canquaff(player, o) && canpickup(player, o, 1)) {
char obname[BUFLEN];
char buf[BUFLEN];
char ch;
@ -7865,7 +7879,7 @@ void showlfstats(lifeform_t *lf, int showall) {
char buf[BUFLEN],buf2[BUFLEN];
job_t *j;
flag_t *f;
char *ftext= "%12s: ";
char *ftext= "%13s: ";
long xpneeded;
object_t *o;
object_t *w[2];
@ -7881,7 +7895,7 @@ void showlfstats(lifeform_t *lf, int showall) {
obpile_t *op = NULL;
char ch;
char mode = '@';
char prompt[BUFLEN];
char promptstr[BUFLEN];
char cmdchars[BUFLEN];
int done = B_FALSE;
enum SKILLLEVEL lorelev;
@ -7912,12 +7926,12 @@ void showlfstats(lifeform_t *lf, int showall) {
}
if (showall) {
snprintf(prompt, BUFLEN, "^h[^W@^n=stats ^WS^nkills ^WA^nbils ^WM^nagic ^WE^nffects ^WG^nods %s^W?^n=help ^WESC^n=quit^h]",
snprintf(promptstr, BUFLEN, "^h[^W@^n=stats ^WS^nkills ^WA^nbils ^WM^nagic ^WE^nffects ^WG^nods %s^W?^n=help ^WESC^n=quit^h]",
isplayer(lf) ? "" : "^WI^ntems " );
snprintf(cmdchars, BUFLEN, "@asmeg%s",isplayer(lf) ? "" : "i");
} else {
snprintf(prompt, BUFLEN, "%s", "[ESC=quit]");
snprintf(cmdchars, BUFLEN, "%s", "@");
snprintf(promptstr, BUFLEN, "^h[^W@^n=stats %s ESC=quit]", isplayer(lf) ? "" : "^WI^ntems ");
snprintf(cmdchars, BUFLEN, "@i");
}
while (!done) {
@ -8393,7 +8407,7 @@ void showlfstats(lifeform_t *lf, int showall) {
rating = comparelfs(player, lf);
setcol(mainwin, lorecol);
if (rating >= 4) {
snprintf(buf, BUFLEN, "It is not a threat.");
snprintf(buf, BUFLEN, "It should pose no threat to you.");
} else if (rating >= 3) {
snprintf(buf, BUFLEN, "You could defeat it very easily.");
} else if (rating >= 2) {
@ -8549,12 +8563,12 @@ void showlfstats(lifeform_t *lf, int showall) {
nmissingbp = 0;
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
if (lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
if (bp == BP_RIGHTHAND) {
if (bp == BP_RIGHTFINGER) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else if (bp == BP_LEFTHAND) {
} else if (bp == BP_LEFTFINGER) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL) &&
!lfhasflagval(lf, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL)
) {
@ -8762,7 +8776,7 @@ void showlfstats(lifeform_t *lf, int showall) {
snprintf(buf, BUFLEN, "%s%s", ot->desc, eb2);
wprintw(mainwin, buf);
if (downline(&y, h, "ABILITIES", NULL, prompt, cmdchars, &ch)) {
if (downline(&y, h, "ABILITIES", NULL, promptstr, cmdchars, &ch)) {
break;
}
}
@ -8817,7 +8831,7 @@ void showlfstats(lifeform_t *lf, int showall) {
(known[n]->lifetime == FROMSPELL) ? "[spell]" : "");
unsetcol(mainwin, getskilllevelcolour(known[n]->val[1]));
}
if (downline(&y, h, "SKILLS", skilltitle, prompt, cmdchars, &ch)) {
if (downline(&y, h, "SKILLS", skilltitle, promptstr, cmdchars, &ch)) {
break;
}
}
@ -8898,7 +8912,7 @@ void showlfstats(lifeform_t *lf, int showall) {
if (castable) unsetcol(mainwin, C_GREEN);
else unsetcol(mainwin, C_RED);
anyfound = B_TRUE;
if (downline(&y, h, "MAGIC", subheading, prompt, cmdchars, &ch)) {
if (downline(&y, h, "MAGIC", subheading, promptstr, cmdchars, &ch)) {
exitnow = B_TRUE;
break;
}
@ -8944,7 +8958,7 @@ void showlfstats(lifeform_t *lf, int showall) {
isplayer(lf) ? "have" : "has");
y++;
}
mvwprintw(mainwin, y, 0, " - %s", sp->name);
mvwprintw(mainwin, y, 0, " - %s %s (consuming %d MP)", sp->name, roman(f->val[2]), f->val[1]);
y++;
nfound++;
}
@ -9052,6 +9066,11 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, "%s can control teleportation and polymorphic effects.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_DEAF);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s deaf.", you(lf), is(lf));
y++;
}
f = lfhasknownflag(lf, F_DETECTAURAS);
if (f) {
mvwprintw(mainwin, y, 0, "%s automatically detect blessings or curses.", you(lf));
@ -9410,27 +9429,39 @@ void showlfstats(lifeform_t *lf, int showall) {
} else if (mode == 'i') {
object_t *o;
cls();
centre(mainwin, C_WHITE, 0, "INVENTORY");
if (lf == player) { // mindscanning it
centre(mainwin, C_WHITE, 0, "INVENTORY");
} else { // not mindscanning
centre(mainwin, C_WHITE, 0, "INVENTORY (equipped items only)");
}
y = 2;
if (lfhasflag(lf, F_NOPACK)) {
if ((lf == player) && lfhasflag(lf, F_NOPACK)) {
mvwprintw(mainwin, y, 0, "It cannot carry anything.");
} else if (countobs(lf->pack, B_FALSE)) {
char invtitle[BUFLEN];
float packweight,maxweight,pct;
packweight = getobpileweight(lf->pack);
maxweight = getmaxcarryweight(lf);
pct = (packweight / maxweight) * 100;
snprintf(invtitle, BUFLEN, "It is carrying: (%0.0f/%0.0f kg, %0.0f%%)", packweight, maxweight, pct);
if (lf == player) {
float packweight,maxweight,pct;
packweight = getobpileweight(lf->pack);
maxweight = getmaxcarryweight(lf);
pct = (packweight / maxweight) * 100;
snprintf(invtitle, BUFLEN, "It is carrying: (%0.0f/%0.0f kg, %0.0f%%)", packweight, maxweight, pct);
} else {
snprintf(invtitle, BUFLEN, "It is using:");
}
mvwprintw(mainwin, y, 0, "%s", invtitle);
y += 2;
for (o = lf->pack->first ; o ; o = o->next) {
getobname(o, buf,o->amt);
getobextrainfo(o, buf2);
mvwprintw(mainwin, y, 0, "%s%s", buf,buf2);
if (o->next && downline(&y, h, "INVENTORY", NULL, prompt, cmdchars, &ch)) {
break;
if ((lf == player) || isequipped(o)) {
getobname(o, buf,o->amt);
getobequipinfo(o, buf2); strcat(buf, buf2);
getobextrainfo(o, buf2); strcat(buf, buf2);
mvwprintw(mainwin, y, 0, "%s", buf);
if (o->next && downline(&y, h, "INVENTORY", NULL, promptstr, cmdchars, &ch)) {
break;
}
}
}
} else {
@ -9515,7 +9546,7 @@ void showlfstats(lifeform_t *lf, int showall) {
}
// wait for key
centre(mainwin, C_WHITE, h-1, prompt);
centre(mainwin, C_WHITE, h-1, promptstr);
if (ch == '\0') {
ch = getch();
}
@ -9534,7 +9565,7 @@ void showlfstats(lifeform_t *lf, int showall) {
if (showall) mode = ch;
break;
case 'i':
if (showall && !isplayer(lf)) mode = ch;
if (!isplayer(lf)) mode = ch;
break;
case '?':
if (mode == 'g') { // help on gods

668
lf.c

File diff suppressed because it is too large Load Diff

4
lf.h
View File

@ -21,7 +21,7 @@ void autotarget(lifeform_t *lf);
void autoweild(lifeform_t *lf);
int appearsrandomly(enum RACE rid);
void awardxpfor(lifeform_t *killed, float pct);
void bleed(lifeform_t *lf);
void bleed(lifeform_t *lf, int splatter);
void breakgrabs(lifeform_t *lf, int fromme, int tome);
long calcscore(lifeform_t *lf);
int calcxp(lifeform_t *lf);
@ -272,7 +272,7 @@ int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo);
int loadfirearmfast(lifeform_t *lf);
void loseconcentration(lifeform_t *lf);
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc);
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob);
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate);
void losemp(lifeform_t *lf, int amt);
void makefriendly(lifeform_t *lf, int howlong);
int makenauseated(lifeform_t *lf, int amt, int howlong);

355
map.c
View File

@ -1038,7 +1038,19 @@ void fix_reachability(map_t *m) {
int i,keepgoing = B_TRUE, nfixed = 0;
int db = B_TRUE;
cell_t *c = NULL;
if (db) dblog("fix_reachability starting.");
switch (m->habitat->id) {
case H_FOREST:
case H_HEAVEN:
case H_PIT:
case H_VILLAGE:
if (db) dblog("fix_reachability not required for this habitat.");
return;
default: break;
}
// find first non-empty cell
for (i = 0; i < m->w * m->h; i++) {
if (!m->cell[i]->type->solid) {
@ -1065,8 +1077,8 @@ void fix_reachability(map_t *m) {
m->cell[i]->x, m->cell[i]->y);
linkexit(m->cell[i], B_TRUE, &nadded);
if (db) dblog(" fixed unreachable area by added %d cells.", nadded);
if (db) dblog(" fixed unreachable area by adding %d cells.", nadded);
assert(nadded);
// now run the test again.
// 'c' will be where the next flood will will happen.
@ -1821,14 +1833,16 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
}
}
// link up room exits
for (i = 0; i < map->nrooms; i++) {
linkexits(map, map->room[i].id);
}
// now clear up dead ends again.
remove_deadends(map, sparseness);
// link up room exits
for (i = 0; i < map->nrooms; i++) {
if (!map->room[i].exitslinked) {
linkexits(map, map->room[i].id);
}
}
// add staircases.
// first dungeon level has 1 up stairs, 3 down.
// subsequent levels always have 3 up and down stairs
@ -1868,6 +1882,8 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
linkstairs(o, NULL);
}
}
// make sure we have at least one up stairs
assert(findobinmap(map, OT_STAIRSUP));
// DOWN STAIRS
if (map->depth < map->region->rtype->maxdepth) {
@ -1980,9 +1996,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
clearcell(c);
setcelltype(c,solidcell);
}
// ensure there are no unreachable areas
fix_reachability(map);
}
void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob, int nclearings) {
@ -1995,9 +2008,8 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t
char buf[BUFLEN];
//object_t *o;
// what kind of cells will 'empty' ones be?
// fill entire maze with emptiness
emptycell = map->habitat->emptycelltype;
// fill entire maze with walls
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
c = addcell(map, x, y);
@ -2005,55 +2017,84 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t
}
}
// determine density
density = rnd(40,70);
// add a plant to density percent of cells
ntrees = (int)(((float)density/100.0) * (float)(map->w*map->h));
for (i = 0; i < ntrees; i++) {
c = getrandomcell(map);
while (c->lf) {
c = getrandomcell(map);
}
switch (rnd(0,1)) {
default: case 0: strcpy(buf, "tree"); break;
case 1: strcpy(buf, "shrub"); break;
}
addob(c->obpile, buf);
}
// clearings
for (i = 0; i < nclearings; i++) {
int w;
c = getrandomcell(map);
w = rnd(MINCLEARINGRADIUS,MAXCLEARINGRADIUS);
for (y = c->y - w; y <= c->y + w; y++) {
for (x = c->x - w; x <= c->x + w; x++) {
cell_t *newc;
int dist = 999;
newc = getcellat(map, x, y);
if (newc) {
dist = getcelldistorth(newc, c);
if (dist <= w) {
int dirtchance;
// kill all obs here
while (newc->obpile->first) killob(newc->obpile->first);
// change it into dirt.
// ie. at centre (dist=0) dirt chance is 100%
// ie. at max distance, dirt chance is 30%
dirtchance = 100 - (((float)dist / (float)w) * 70);
if (rnd(1,100) <= dirtchance) {
setcelltype(newc, CT_DIRT);
switch (rnd(1,2)) {
case 1: // forest type 1: add trees in x% of cells, then add some clearings
// determine density
density = rnd(40,70);
// add a plant to density percent of cells
ntrees = (int)(((float)density/100.0) * (float)(map->w*map->h));
for (i = 0; i < ntrees; i++) {
c = getrandomcell(map);
while (c->lf) c = getrandomcell(map);
switch (rnd(0,1)) {
default: case 0: strcpy(buf, "tree"); break;
case 1: strcpy(buf, "shrub"); break;
}
addob(c->obpile, buf);
}
// clearings
for (i = 0; i < nclearings; i++) {
int w;
c = getrandomcell(map);
w = rnd(MINCLEARINGRADIUS,MAXCLEARINGRADIUS);
for (y = c->y - w; y <= c->y + w; y++) {
for (x = c->x - w; x <= c->x + w; x++) {
cell_t *newc;
int dist = 999;
newc = getcellat(map, x, y);
if (newc) {
dist = getcelldistorth(newc, c);
if (dist <= w) {
int dirtchance;
// kill all obs here
while (newc->obpile->first) killob(newc->obpile->first);
// change it into dirt.
// ie. at centre (dist=0) dirt chance is 100%
// ie. at max distance, dirt chance is 30%
dirtchance = 100 - (((float)dist / (float)w) * 70);
if (rnd(1,100) <= dirtchance) {
setcelltype(newc, CT_DIRT);
}
}
}
}
}
}
}
}
break;
case 2: // add clusters of trees
nclearings = rnd(5,10);
for (i = 0; i < nclearings; i++) {
int w;
c = getrandomcell(map);
while (c->lf) c = getrandomcell(map);
// add monsters
w = rnd(MINCLEARINGRADIUS,MAXCLEARINGRADIUS);
for (y = c->y - w; y <= c->y + w; y++) {
for (x = c->x - w; x <= c->x + w; x++) {
cell_t *newc;
int dist = 999;
newc = getcellat(map, x, y);
if (newc) {
dist = getcelldistorth(newc, c);
if (dist <= w) {
int treechance;
treechance = 100 - (((float)dist / (float)w) * 70);
if (rnd(1,100) <= treechance) {
switch (rnd(0,1)) {
default: case 0: strcpy(buf, "tree"); break;
case 1: strcpy(buf, "shrub"); break;
}
addob(c->obpile, buf);
}
}
}
}
}
}
break;
}
}
@ -2391,6 +2432,9 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
}
}
// ensure there are no unreachable areas
fix_reachability(map);
// special cases
// village - add town walls and clear it out
if (db) dblog(" finalising village creation...");
@ -2677,6 +2721,7 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r
map->room[map->nrooms].x2 = maxx;
map->room[map->nrooms].y2 = maxy;
map->room[map->nrooms].vault = v;
map->room[map->nrooms].exitslinked = B_FALSE;
thisroom = &(map->room[map->nrooms]);
map->nrooms++;
@ -2718,6 +2763,9 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r
autodoors(map, roomid, minx, miny, maxx, maxy, f->val[0], B_NODOORS);
}
// link up exits from this vault
linkexits(map, roomid);
return B_FALSE;
}
@ -2726,11 +2774,11 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r
// if 'wantfilled' is set, only link to "filled" cells.
// return TRUE on failure.
int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
int db = B_FALSE;
int db = B_TRUE;
int d, roomid;
int poss2[MAXCANDIDATES],nposs2;
int dist[MAXDIR_ORTH];
int hitsedge[MAXDIR_ORTH];
int dist[MAXDIR_ORTH],hitsedge[MAXDIR_ORTH], sameroom[MAXDIR_ORTH];
cell_t *directendcell[MAXDIR_ORTH];
int mindist = 999,maxdist = -1;
cell_t *c;
@ -2739,6 +2787,10 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
if (db) dblog(" calling linkexit() for cell at %d,%d", startcell->x, startcell->y);
roomid = getroomid(startcell);
for (d = D_N; d <= D_W; d++) {
hitsedge[d] = B_TRUE;
directendcell[d] = NULL;
}
// link it. starting from the door, count the number of cells in
// each direction until we hit an empty (walkable) cell which isn't a room.
@ -2747,6 +2799,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
for (d = D_N; d <= D_W; d++) {
dist[d] = 0;
hitsedge[d] = B_TRUE;
sameroom[d] = B_FALSE;
c = getcellindir(startcell, d);
while (c) {
dist[d]++;
@ -2760,6 +2813,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
} else {
// mark dir as invalid
dist[d] = 999;
sameroom[d] = B_TRUE;
if (db) dblog(" going %s hits same room. invalid.", getdirname(d));
break;
}
@ -2767,6 +2821,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
if (!wantfilled || c->filled) {
// walkable and not in this vault. finished.
hitsedge[d] = B_FALSE;
directendcell[d] = c;
if (db) dblog(" can make %s path (hits empty cell at dist %d)", getdirname(d), dist[d]);
break;
}
@ -2785,7 +2840,8 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
if (!wantfilled || c->filled) {
// finished.
hitsedge[d] = B_FALSE;
if (db) dblog(" can make %s path (hits adjacent empty cell at dist %d)", getdirname(d), dist[d]);
directendcell[d] = c;
if (db) dblog(" can make %s path (hits adjacent empty cell at dist %d)", getdirname(d), dist[d]);
break;
}
}
@ -2796,32 +2852,47 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
c = getcellindir(c, d); // getting the same cell!
}
if (dist[d] != 999) {
if (!hitsedge[d]) {
if (dist[d] < mindist) mindist = dist[d];
}
if (dist[d] < mindist) mindist = dist[d];
if (dist[d] > maxdist) maxdist = dist[d];
}
}
if (mindist == 999) {
cell_t *turncell = NULL,*endcell = NULL;
cell_t *perpcell[MAX_MAPW*MAX_MAPH];
cell_t *perpturncell1[MAX_MAPW*MAX_MAPH];
int perpturndir1[MAX_MAPW*MAX_MAPH];
int nperpcells = 0;
int perpdir[2];
int startdir = D_NONE;
int turndir = D_NONE;
int startdist = 0;
int maxdist2 = -1;
int startposs[MAXDIR_ORTH];
int nstartposs = 0;
// no good directions.
if (db) dblog(" No directions lead to valid cells. Trying turns.");
// starting at the LONGEST distance, traverse up each dir,
// branching off looking for rooms.
// find longest distance
// find longest distance that doesn't go through same room
for (d = D_N; d <= D_W; d++) {
if (dist[d] == maxdist) {
startdir = d;
break;
if (!sameroom[d] && (dist[d] > maxdist2)) {
maxdist2 = dist[d];
}
}
// pick one randomly
for (d = D_N; d <= D_W; d++) {
if (dist[d] == maxdist2) {
startposs[nstartposs++] = d;
}
}
if (nstartposs) {
startdir = startposs[rnd(0,nstartposs-1)];
}
assert(startdir != D_NONE);
// figure out perpendicular dirs
perpdir[0] = startdir - 1; if (perpdir[0] < D_N) perpdir[0] = D_W;
perpdir[1] = startdir + 1; if (perpdir[1] > D_W) perpdir[1] = D_N;
@ -2839,6 +2910,12 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
for (n = 0; n <= 1; n++) {
int turndist = 0;
c2 = getcellindir(c, perpdir[n]);
perpcell[nperpcells] = c2; // this will be used if we need to make 2 turns
perpturncell1[nperpcells] = c;
perpturndir1[nperpcells] = perpdir[n];
nperpcells++;
while (c2) {
int gotsolution = B_FALSE;
turndist++;
@ -2875,7 +2952,6 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
}
}
}
if (gotsolution) {
if (db) dblog(" Solution found: Walk %d %s, then %d %s.",
startdist, getdirname(startdir),
@ -2915,17 +2991,126 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
c = getcellindir(c, turndir);
}
} else {
// give up??
if (db) dblog(" Cannot find a way to link up.");
// We need to make 3 turns.
// for each perpcell[], look in startdir + diropposite(startdir)
int dir3[2],i,n;
cell_t *turncell2 = NULL;
int turndir2;
dir3[0] = startdir;
dir3[1] = diropposite(startdir);
for (i = 0; i < nperpcells; i++) {
for (n = 0; n < 1; n++) {
cell_t *c2;
int turndist = 0;
c2 = getcellindir(perpcell[i], dir3[n]);
while (c2) {
int gotsolution = B_FALSE;
turndist++;
if ((roomid >= 0) && (getroomid(c2) == roomid)) {
if (wantfilled && c2->type->solid) {
// see EXCEPTION above.
} else {
// hits same room, not ok.
break;
}
} else if (cellwalkable(NULL, c2, NULL)) {
if (!wantfilled || c2->filled) {
if (db) dblog(" Got to an empty cell here.");
gotsolution = B_TRUE;
}
} else if (turndist > 1) {
// check l/r too
int perpdir2[2],nn;
cell_t *pcell = NULL;
perpdir2[0] = perpdir[n] - 1; if (perpdir2[0] < D_N) perpdir2[0] = D_W;
perpdir2[1] = perpdir[n] + 1; if (perpdir2[1] > D_W) perpdir2[1] = D_N;
for (nn = 0; nn <= 1; nn++) {
pcell = getcellindir(c2, perpdir2[nn]);
if (pcell) {
if ( ((roomid == -1) || (getroomid(pcell) != roomid)) &&
cellwalkable(NULL, pcell, NULL)) {
if (!wantfilled || pcell->filled) {
// finished.
if (db) dblog(" Got to an empty cell next to us.");
gotsolution = B_TRUE;
break;
}
}
}
}
}
if (gotsolution) {
if (db) dblog(" Solution found: Walk %d %s, then %d %s.",
startdist, getdirname(startdir),
turndist, getdirname(perpdir[n]));
turncell = perpturncell1[i];
turndir = perpturndir1[i];
turncell2 = perpcell[i];
turndir2 = dir3[n];
endcell = c2;
break;
}
// check next cell
c2 = getcellindir(c2, perpdir[n]);
} // end while c2
if (turncell2) break;
} // end for n=1-2
if (turncell2) break;
} // end foreach perpcell
// TODO: if we find a solution, fill in turncell2 and make path.
if (turncell2) {
if (db) dblog(" 2turn Solution found: Walk %s, then %s, then %s.",
getdirname(startdir), getdirname(turndir), getdirname(turndir2));
// make a path up to the turn point.
if (db) dblog(" Making path from vault to first corner, initdir=%s", getdirname(startdir));
c = getcellindir(startcell, startdir);
while (c != turncell) {
setcelltype(c, c->habitat->emptycelltype);
if (ncellsadded) (*ncellsadded)++;
c = getcellindir(c, startdir);
}
// clear the corner cell
setcelltype(c, c->habitat->emptycelltype);
// now turn and clear up to the next turn
if (db) dblog(" Making path from 1st corner to 2nd corner, turndir=%s", getdirname(turndir));
c = getcellindir(c, turndir);
while (c != turncell2) {
setcelltype(c, c->habitat->emptycelltype);
if (ncellsadded) (*ncellsadded)++;
c = getcellindir(c, turndir);
}
// now turn and clear up to the next room/empty cell
if (db) dblog(" Making path from 2nd corner to rest of map, turndir=%s", getdirname(turndir2));
c = getcellindir(c, turndir2);
while (c != endcell) {
setcelltype(c, c->habitat->emptycelltype);
if (ncellsadded) (*ncellsadded)++;
c = getcellindir(c, turndir2);
}
} else {
if (db) dblog(" Cannot find a way to link up.");
}
return B_TRUE;
}
} else {
} else { // we found a way to go without needing to turn.
int whichway,sel;
// now pick the shortest one which doesn't hits the edge
int mindist2 = 999;
// now pick the shortest one which doesn't hit the edge
// get list of all the minimums and randomly tie-break
nposs2 = 0;
for (d = D_N; d <= D_W; d++) {
if (dist[d] == mindist) {
if (!hitsedge[d] && (dist[d] < mindist2)) {
mindist2 = dist[d];
}
}
for (d = D_N; d <= D_W; d++) {
if (dist[d] == mindist2) {
poss2[nposs2++] = d;
}
}
@ -2933,9 +3118,10 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
whichway = poss2[sel];
// now create a path
if (db) dblog(" Linking %s (distance %d).", getdirname(whichway), mindist);
if (db) dblog(" Linking directly %s (distance %d).", getdirname(whichway), mindist);
c = getcellindir(startcell, whichway);
while (c && !cellwalkable(NULL, c, NULL)) {
//while (c && !cellwalkable(NULL, c, NULL)) {
while (c && c != directendcell[whichway]) {
setcelltype(c, c->habitat->emptycelltype);
if (ncellsadded) (*ncellsadded)++;
c = getcellindir(c, whichway);
@ -2949,9 +3135,10 @@ int linkexits(map_t *m, int roomid) {
int x,y,i;
cell_t *poss[MAXCANDIDATES],*c;
int nposs = 0;
int db = B_FALSE;
int db = B_TRUE;
int nadded = 0;
int minx = -1, miny = -1, maxx = -1, maxy = -1;
int roomidx = -1;
// figure out room coords
for (i = 0; i < m->nrooms; i++) {
@ -2960,10 +3147,11 @@ int linkexits(map_t *m, int roomid) {
miny = m->room[i].y1;
maxx = m->room[i].x2;
maxy = m->room[i].y2;
roomidx = i;
break;
}
}
assert(minx != -1);
assert(roomidx != -1);
if (db) {
@ -2984,8 +3172,10 @@ int linkexits(map_t *m, int roomid) {
if (!c) continue;
if (hasobwithflag(c->obpile, F_DOOR)) {
if (db) dblog("found door at %d,%d",x,y);
poss[nposs++] = c;
if ((x == minx) || (x == maxx) || (y == miny) || (y == maxy) ) {
if (db) dblog("found wall door at %d,%d",x,y);
poss[nposs++] = c;
}
} else if (hasflagval(m->flags, F_ROOMEXIT, roomid, x, y, NULL)) {
if (db) dblog("found roomexit at %d,%d",x,y);
poss[nposs++] = c;
@ -3016,6 +3206,8 @@ int linkexits(map_t *m, int roomid) {
}
} // end for each door
m->room[roomidx].exitslinked = B_TRUE;
if (db) dblog("linkexits complete (%d added).", nadded);
return nadded;
}
@ -3116,6 +3308,7 @@ int createroom(map_t *map, int roomid, int overrideminw, int overrideminh, int x
map->room[map->nrooms].x2 = maxx;
map->room[map->nrooms].y2 = maxy;
map->room[map->nrooms].vault = NULL;
map->room[map->nrooms].exitslinked = B_FALSE;
thisroom = &(map->room[map->nrooms]);
map->nrooms++;
@ -4184,6 +4377,7 @@ void initmap(void) {
}
//vx = 0; vy = -1;
addregionoutline(RG_FIRSTDUNGEON);
addregionthing(lastregionoutline, 1, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISPLAYERSTART, NULL);
addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair");
addregionthing(lastregionoutline, 10, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISSHRINE, NULL); // godstone on last floor
}
@ -4904,6 +5098,9 @@ int shattercell(cell_t *c, lifeform_t *fromlf, char *damstring) {
losehp(target, rnd(1,100), DT_SLASH, fromlf, damstring); // BIG damage
}
// change cell type
setcelltype(c, c->habitat->emptycelltype);
// place shards
if (c->type->material->id == MT_GLASS) {
int numshards;

40
move.c
View File

@ -28,9 +28,6 @@ extern void (*precalclos)(lifeform_t *);
extern enum ERROR reason;
extern void *rdata;
extern flag_t *retflag[];
extern int nretflags;
extern long curtime;
extern WINDOW *gamewin, *msgwin;
@ -739,6 +736,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
i = howfar;
// don't fall
mightfall = B_FALSE;
if (onein(3)) criticalhit(NULL, lf, getrandomcorebp(lf), DT_BASH);
break;
case E_SWIMMING:
case E_LFINWAY:
@ -874,21 +872,25 @@ int moveclear(lifeform_t *lf, int dir, enum ERROR *error) {
}
// effects which happen after player moves.
// IMPORTANT: don't modify lf's flagpile during this code!
// particularly don't remove flags...
// returns TRUE if we displayed a message
int moveeffects(lifeform_t *lf) {
flag_t *f;
int didmsg = B_FALSE;
if (lfhasflagval(lf, F_INJURY, IJ_HAMSTRUNG, NA, NA, NULL)) {
if (!skillcheck(lf, SC_FALL, 20, 0)) fall(lf, NULL, B_TRUE);
}
if (isbleeding(lf)) {
if (lfhasflagval(lf, F_INJURY, NA, BP_LEGS, DT_SLASH, NULL)) {
bleed(lf);
bleed(lf, B_FALSE);
losehp(lf, 1, DT_DIRECT, NULL, "blood loss");
} else {
if (rnd(1,2) == 1) {
bleed(lf);
bleed(lf, B_FALSE);
}
}
}
@ -1455,6 +1457,30 @@ int movetowards(lifeform_t *lf, cell_t *dst, int dirtype) {
return rv;
}
int move_will_hurt(lifeform_t *lf) {
flag_t *retflag[MAXCANDIDATES];
int nretflags,i;
if (lfhasflag(lf, F_PAIN)) {
return B_TRUE;
}
getflags(lf->flags, retflag, &nretflags, F_INJURY, F_PAIN, F_NONE);
for (i = 0; i < nretflags; i++) {
flag_t *f;
f = retflag[i];
if (f->id == F_PAIN) return B_TRUE;
if (f->id == F_INJURY) {
switch (f->val[0]) {
case IJ_LEGBLEED:
return B_TRUE;
default:
break;
}
}
}
return B_FALSE;
}
int opendoorat(lifeform_t *lf, cell_t *c) {
object_t *o;
int rv;
@ -2649,7 +2675,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
// for at least average iq things...
if (iq >= AT_AVERAGE) {
// don't move if in pain
if (lfhasflag(lf, F_PAIN)) {
if (move_will_hurt(lf)) {
if (error) *error = E_WONT;
return B_FALSE;
}

1
move.h
View File

@ -19,6 +19,7 @@ int moveeffects(lifeform_t *lf);
int movelf(lifeform_t *lf, cell_t *newcell);
int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg);
int movetowards(lifeform_t *lf, cell_t *dst, int dirtype);
int move_will_hurt(lifeform_t *lf);
int opendoorat(lifeform_t *lf, cell_t *c);
int opendoor(lifeform_t *lf, object_t *o);
int pullnextto(lifeform_t *lf, cell_t *c);

64
nexus.c
View File

@ -151,11 +151,10 @@ int main(int argc, char **argv) {
// if no player (ie. didn't load a game), add them
if (!player) {
char *user;
char pname[BUFLEN];
char buf[BUFLEN];
char *user,pname[BUFLEN],buf[BUFLEN];
job_t *j = NULL;
char ch;
object_t *o;
cell_t *where;
int dir;
flag_t *f;
@ -222,13 +221,20 @@ int main(int argc, char **argv) {
killlf(where->lf);
}
// add player nearby
where = real_getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL);
// add player in the starting position
//where = real_getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL);
where = findobinmap(dmap, OT_PLAYERSTART);
if (!where) {
dblog("fatal error: couldn't find player start position!");
msg("fatal error: couldn't find player start position!");
more();
exit(1);
}
real_addlf(where, R_HUMAN, 1, C_PLAYER); // this will assign 'player'
// 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_TRAIN, NA, NA, NULL);
o = hasob(where->obpile, OT_PLAYERSTART);
killob(o);
user = getenv("USER");
if (user) {
@ -1199,50 +1205,32 @@ int rolldie(int ndice, int sides) {
int rollhitdice(lifeform_t *lf) {
flag_t *f;
int ndice, plus;
int roll = 0;
int i;
int ndice, nsides = 4, plus = 0;
int myroll = 0;
float mod;
int db = B_FALSE;
f = hasflag(lf->flags, F_HITDICE);
if (f) {
ndice = f->val[0];
if (f->val[1] == NA) plus = 0;
else plus = f->val[1];
myroll = roll(f->text);
} else {
ndice = 1;
nsides = 4;
plus = 0;
myroll = roll("1d4");
}
if (db) dblog("rollhitdice() for %s - rolling %dd4 + %d",lf->race->name,ndice,plus);
mod = 100 + getstatmod(lf, A_CON);
if (db) dblog("rollhitdice() - mod is +%0.0f%%",mod);
if (ndice == 0) {
int thisroll;
// just the bonus
thisroll = plus;
if (thisroll < 1) thisroll = 1;
roll += thisroll;
} else {
for (i = 0; i < ndice; i++) {
int thisroll;
thisroll = rolldie(1, 4) + plus;
if (thisroll < 1) thisroll = 1;
if (db) dblog("rollhitdice() ---- die %d/%d == %d",i+1,ndice,thisroll);
roll += thisroll;
}
}
if (db) dblog("TOTAL: %d",roll);
if (db) dblog("TOTAL: %d",myroll);
// modify for fitness/con
roll = pctof(mod, roll);
limit(&roll, 1, NA);
if (db) dblog(" -> modified to: %d",roll);
return roll;
myroll = pctof(mod, myroll);
limit(&myroll, 1, NA);
if (db) dblog(" -> modified to: %d",myroll);
return myroll;
}
int rollmpdice(lifeform_t *lf) {
@ -1533,7 +1521,7 @@ void timeeffectsworld(map_t *map, int updategametime) {
if (updategametime) {
// inc game time
curtime += firstlftime;
curtime += (firstlftime*(TIMECONST));
// don't let it get higher than 23:59
while (curtime >= DAYSECS) {
curtime -= DAYSECS;

184
objects.c
View File

@ -455,6 +455,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
nadded = 0;
nretobs = 0;
if (where->where) {
assert(!where->where->type->solid);
}
if (where->owner && hasflag(where->owner->flags, F_NOPACK)) {
if (db) dblog("error giving ob '%s' - owner isn't allowed to carry objects!", name);
nretobs = 0;
@ -468,7 +472,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
dblog("DB: called addobject() for forceoid %s, canstack = %d",ot->name, canstack);
}
} else {
char *p2;
char *bonusstart,*p2;
int bonussign = 1;
localname = strdup(name);
if (db) {
@ -532,36 +537,34 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
}
bonus = 0;
// handle for bonuses. eg. "+1"
p2 = strchr(p, '+');
if (p2) {
char *p3;
bonusstart = strchr(p, '+');
if (!bonusstart) {
bonussign = -1;
bonusstart = strchr(p, '-');
}
if (bonusstart) {
char *p3,*bonusend;
char numbuf[BUFLENSMALL];
p3 = numbuf;
p++;
while (isdigit(*p2)) {
*p3 = *p2;
p2++;
bonusend = bonusstart+1; // go past the + or -
while (isdigit(*bonusend)) { // grab the full number
*p3 = *bonusend;
bonusend++;
p3++;
}
*p3 = '\0';
bonus += atoi(numbuf);
}
// check for penalties. eg. "-1"
p2 = strchr(p, '-');
if (p2) {
char *p3;
char numbuf[BUFLENSMALL];
p3 = numbuf;
p2++;
while (isdigit(*p2)) {
*p3 = *p2;
p2++;
p3++;
bonus += (atoi(numbuf) * bonussign);
// strip off the "+xxx" / "-xxx", as long as xxx was a number.
// might not be the case if it was part of the object name
// eg. "waist-deep water"
if (bonus) {
while (*bonusend == ' ') bonusend++; // go past spaces
strcpy(bonusstart, bonusend);
}
*p3 = '\0';
bonus -= atoi(numbuf);
}
}
// handle prefixes. strip them off as we go.
donesomething = B_TRUE;
@ -1269,7 +1272,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes
rf = hasflag(corpserace->flags, F_HITDICE);
if (rf) {
int maxhp;
maxhp = (rf->val[0] * 4) + rf->val[1];
maxhp = roll(rf->text);
f->val[0] = maxhp;
f->val[1] = maxhp;
}
@ -4576,7 +4579,9 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
strcpy(triedbuf, "");
if (hasflag(o->flags, F_BEINGUSED)) {
strcat(triedbuf, " [currently being read]");
if (strlen(triedbuf)) strcat(triedbuf, ", ");
else strcpy(triedbuf, " [");
strcat(triedbuf, "currently being read");
}
if (istried(o)) {
@ -5734,9 +5739,8 @@ void initobjects(void) {
addmaterial(MT_METAL, "metal", 13);
addflag(lastmaterial->flags, F_HARDNESS, 5, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTIMMUNE, DT_BITE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_BITE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_PIERCE, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_SLASH, NA, NA, NULL);
addflag(lastmaterial->flags, F_DTRESIST, DT_PROJECTILE, NA, NA, NULL);
addmaterial(MT_GLASS, "glass", 13);
@ -5784,8 +5788,8 @@ void initobjects(void) {
addoc(OC_RING, "Rings", "A circular band, worn on the finger.", '=', C_GREY);
addocnoun(lastobjectclass, "ring");
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_GOESON, BP_RIGHTHAND, NA, NA, NULL);
addflag(lastobjectclass->flags, F_GOESON, BP_LEFTHAND, NA, NA, NULL);
addflag(lastobjectclass->flags, F_GOESON, BP_RIGHTFINGER, NA, NA, NULL);
addflag(lastobjectclass->flags, F_GOESON, BP_LEFTFINGER, NA, NA, NULL);
addoc(OC_WEAPON, "Weapons", "An instrument used for the purpose of causing harm or death.", ')', C_GREY);
addocnoun(lastobjectclass, "weapon");
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -6041,7 +6045,7 @@ void initobjects(void) {
addot(OT_PORTAL, "magic portal", "A magical portal to a different place...", MT_MAGIC, 0, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_BOLDGREEN, NA, NA, "&");
addflag(lastot->flags, F_GLYPH, C_BOLDGREEN, NA, NA, "^");
addflag(lastot->flags, F_CLIMBABLE, D_IN, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -6101,7 +6105,7 @@ void initobjects(void) {
addot(OT_TRAPSUMMON, "summoning trap", "A magical trap which causes a monster to appear.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BOLDGREEN, NA, NA, "^");
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "^");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
@ -6400,12 +6404,14 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
// corpses
addot(OT_CORPSE, "corpse", "xxx", MT_FLESH, 1, OC_CORPSE, SZ_TINY);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); // will be overridden
addot(OT_HEAD, "head", "xxx", MT_FLESH, 1, OC_CORPSE, SZ_SMALL);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); // will be overridden
addot(OT_FLESHCHUNK, "chunk of flesh", "A chunk of flesh from something.", MT_FLESH, 1, OC_FOOD, SZ_SMALL);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, "");
addflag(lastot->flags, F_EDIBLE, B_TRUE, 25, NA, NULL);
addot(OT_FINGER, "severed finger", "The severed finger from some kind of creature.", MT_FLESH, 0.02, OC_CORPSE, SZ_TINY);
addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL);
// potions (sorted by rarity)
@ -6589,8 +6595,8 @@ void initobjects(void) {
addot(OT_SCR_TELEPORT, "scroll of teleportation", "Causes the caster to teleport to a random location within the same level.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_TELEPORT, 4, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL);
addot(OT_SCR_TURNUNDEAD, "scroll of turn undead", "Instills fear in undead creatures.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_TURNUNDEAD, NA, NA, NULL);
@ -6681,7 +6687,7 @@ void initobjects(void) {
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SMITEGOOD, "smite good", "Instantly deals 1-^bpower*2^n damage to good creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 10, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
@ -6837,7 +6843,7 @@ void initobjects(void) {
addot(OT_S_JOLT, "jolt", "Jolts an adjacent enemy with a short pulse of electricity, dealing 1-^bpower^n damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
@ -6854,6 +6860,7 @@ void initobjects(void) {
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL);
addot(OT_S_SHATTER, "shatter", "Instantly shatters all glass in the target location.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
@ -6880,8 +6887,9 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
// l5
addot(OT_S_CHAINLIGHTNING, "chain lightning", "Electricity arcs up to 5 times between all nearby enemies. The initial arc deals 2d6 damage, the next deals 2d5 damage, etc.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addot(OT_S_CHAINLIGHTNING, "chain lightning", "Electricity arcs up to 5 times between all nearby enemies. The initial arc deals 3d6 damage, the next deals 3d5 damage, etc.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's range is based on its power.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
@ -6933,14 +6941,14 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_FIREBALL, "fireball", "Creates a huge ball of fire, dealing up to ^bpower^nd4 damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addot(OT_S_FIREBALL, "fireball", "Creates a huge ball of fire, dealing up to ^bpower^nd3 damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The damage is lower for enemies further away from the ball's centre.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); // TODO: should be "near victim"
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
///////////////////
// elemental - ice
// elemental - cold
///////////////////
// l1
addot(OT_S_CHILL, "chill", "Deals minor (1d3) cold damage to a single target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
@ -6981,7 +6989,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
// l3
addot(OT_S_COLDRAY, "cold ray", "Shoots a blast of ice cold air, dealing 2-10 cold damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addot(OT_S_COLDRAY, "cold ray", "Shoots a blast of ice cold air, dealing 3d6 cold damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how difficult the ray is to dodge.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
@ -7020,6 +7028,27 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_CRYSTALARM, "crystalline armour", "Summons ice crystal armour to protect you from damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 1-3: one piece of armour is created.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 4-6: two pieces of armour are created.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 7-9: three pieces of armour are created.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power 10: four pieces of armour are created.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SHARDSHOT, "shard shot", "Fires a scattered burst of small, fast moving ice shards. The shot will pass through multiple creatures, but damage is reduced with range.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's range is determined by its power.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_WALLSTOP, NA, NULL);
addot(OT_S_SNAPFREEZE, "snap freeze", "Instantly freezes the target creature. Cold-resistant creatures will take minor damage instead.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
///////////////////
// nature
///////////////////
@ -7076,6 +7105,7 @@ void initobjects(void) {
addot(OT_S_SUMMONANIMALSSM, "summon small animals", "Summons 2-3 small animals.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the summoned creatures will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
@ -7166,6 +7196,7 @@ void initobjects(void) {
addot(OT_S_SUMMONANIMALSMD, "summon medium animals", "Summons 2-3 medium animals.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the summoned creatures will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
@ -7187,7 +7218,7 @@ void initobjects(void) {
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l6
addot(OT_S_LIGHTNINGSTORM, "lightning storm", "Blasts all visible enemies bolts of lightning from the sky.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addot(OT_S_LIGHTNINGSTORM, "lightning storm", "Blasts all visible enemies bolts of lightning from the sky, dealing 3d6 damage (4d6 if outdoors).", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how many bolts will appear.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
@ -7196,6 +7227,7 @@ void initobjects(void) {
addot(OT_S_SUMMONANIMALSLG, "summon large animals", "Summons 2-3 large animals.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the summoned creatures will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
@ -7486,6 +7518,12 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l5
addot(OT_S_SUMMONDEMON, "summon demon", "Summons a random demonic entity.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines its chances of success, and how long the demon will remain.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
///////////////////
// translocation
///////////////////
@ -7551,7 +7589,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addot(OT_S_ALARM, "alarm", "Creates a passive alarm which goes off when an enemy is nearby.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
@ -7559,7 +7597,7 @@ void initobjects(void) {
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
// l3
addot(OT_S_ENERGYBLAST, "energy blast", "Causes a ring of energy to expand from the caster, causing 2-6 damage to anything in sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addot(OT_S_ENERGYBLAST, "energy blast", "Causes a ring of energy to expand from the caster, causing 2d6 damage to anything in sight.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the radius of the blast.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
@ -7815,7 +7853,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit");
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 1, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 1, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 5, 10, NA, NULL);
addflag(lastot->flags, F_RNDCHARGES, 50, 100, NA, NULL);
addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out");
@ -7837,7 +7875,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 2, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 100, 200, NA, NULL);
addflag(lastot->flags, F_RNDCHARGES, 200, 400, NA, NULL);
addflag(lastot->flags, F_REFILLWITH, OT_POT_OIL, NA, NA, NULL);
addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
@ -7849,7 +7887,7 @@ void initobjects(void) {
addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 3, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 200, 300, NA, NULL);
addflag(lastot->flags, F_RNDCHARGES, 300, 500, NA, NULL);
addflag(lastot->flags, F_REFILLWITH, OT_POT_OIL, NA, NA, NULL);
addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
@ -7875,7 +7913,7 @@ void initobjects(void) {
addflag(lastot->flags, F_HELPSCLIMB, 3, NA, NA, NULL);
addot(OT_SACK, "sack", "A small cloth sack.", MT_CLOTH, 0.5, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -7982,7 +8020,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ACTIVATEPREFIX, NA, NA, NA, "lit");
addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 2, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, IFACTIVE, NULL);
addflag(lastot->flags, F_RNDCHARGES, 50, 100, NA, NULL);
addflag(lastot->flags, F_RNDCHARGES, 100, 200, NA, NULL);
addflag(lastot->flags, F_REFILLWITH, OT_POT_OIL, NA, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAM, DT_FIRE, NA, NA, "1d4");
@ -8174,7 +8212,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addot(OT_CHEST, "chest", "A small wooden treasure chest.", MT_METAL, 40, OC_FURNITURE, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "(");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -9007,6 +9045,14 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL);
addflag(lastot->flags, F_SCARY, 4, NA, NA, NULL);
// armour - ears
addot(OT_EARPLUGS, "set of earplugs", "A pair of cloth plugs designed to give the wearer a peaceful night's sleep. ", MT_CLOTH, 0.01, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_EARS, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_DEAF, NA, NA, NULL);
addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL);
// armour - eyes
addot(OT_SUNGLASSES, "pair of sunglasses", "Tinted eyewear to protect against sunlight.", MT_GLASS, 0.01, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
@ -9796,6 +9842,26 @@ void initobjects(void) {
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); // will be replaced when summoned
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
addot(OT_ICEARMOUR, "ice crystal armour", "Summoned body armour made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_HUMAN);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
addot(OT_ICEBOOTS, "pair of ice crystal boots", "Summoned boots made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
addot(OT_ICEGLOVES, "pair of ice crystal gauntlets", "Summoned gauntlets made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
addot(OT_ICEHELMET, "ice crystal helmet", "A summoned helmet made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_SMALL);
addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned
// special obs
addot(OT_PLAYERSTART, "playerstart", "starting pos for player", MT_NOTHING, 0, OC_MISC, SZ_MINI);
}
// returns the 'armourrating' flag
@ -13217,9 +13283,10 @@ int readsomething(lifeform_t *lf, object_t *o) {
// let player select ANY object (even if it won't
// work).
if (needsob && isplayer(lf) && !isknown(o)) {
f = addflag(o->flags, F_BEINGUSED, B_TRUE, NA, NA, NULL);
flag_t *f2;
f2 = addflag(o->flags, F_BEINGUSED, B_TRUE, NA, NA, NULL);
targob = askobject(lf->pack, "Target which object", NULL, AO_NONE);
killflag(f);
killflag(f2);
}
dospelleffects(lf, f->val[0], power, NULL, targob, NULL, o->blessed, &seen, B_FALSE);
@ -14101,7 +14168,7 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno
// now use the REAL name
real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_TRUE);
losehp_real(owner, howmuch , damtype, NULL, obname, B_TRUE, o);
losehp_real(owner, howmuch , damtype, NULL, obname, B_TRUE, o, B_FALSE);
if (isdead(owner)) {
return howmuch;
}
@ -15929,11 +15996,6 @@ int getcritchance(lifeform_t *lf, object_t *o) {
}
}
if (isplayer(lf)) {
// oooooo
chance = 100;
}
return chance;
}

340
spell.c
View File

@ -794,8 +794,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
howlong = 10;
addtempflag(user->flags, F_RAGE, B_TRUE, NA, NA, NULL, howlong);
needredraw = B_TRUE;
statdirty = B_TRUE;
if (isplayer(user)) {
needredraw = B_TRUE;
statdirty = B_TRUE;
drawscreen();
}
} else if (abilid == OT_A_REPAIR) {
enum SKILLLEVEL slev;
object_t *o;
@ -1983,7 +1986,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
char castername[BUFLEN];
int rv = B_FALSE;
objecttype_t *sp;
flag_t *casttype;
flag_t *casttype = NULL;
sp = findot(spellid);
@ -2042,18 +2045,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
power += powerinc;
}
}
}
// special: spit attacks need an animation
casttype = lfhasflag(caster, F_CASTTYPE);
if (casttype && (casttype->val[0] == CT_EYESPIT)) {
enum COLOUR col;
if (casttype->val[1] == NA) {
col = C_GREEN;
} else {
col = casttype->val[1];
// special: spit attacks need an animation
casttype = lfhasflag(caster, F_CASTTYPE);
if (casttype && (casttype->val[0] == CT_EYESPIT)) {
enum COLOUR col;
if (casttype->val[1] == NA) {
col = C_GREEN;
} else {
col = casttype->val[1];
}
anim(caster->cell, targcell, '}', col);
}
anim(caster->cell, targcell, '}', col);
}
// switch based on spell effects...
@ -2337,49 +2340,44 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
}
} else if (spellid == OT_S_BLINK) {
if (!caster->nlos) {
// can't see anywhere
fizzle(caster);
} else {
if (lfhasflag(caster, F_CONTROL) && (power < 6)) {
power = 6;
if (lfhasflag(caster, F_CONTROL) && (power < 6)) {
power = 6;
}
if (power >= 6) {
// controlled
// must be within line of sight.
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (!targcell || !cellwalkable(caster, targcell, NULL)) {
fizzle(caster);
return B_TRUE;
}
if (power >= 6) {
// controlled
// must be within line of sight.
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (!targcell || !cellwalkable(caster, targcell, NULL)) {
fizzle(caster);
return B_TRUE;
}
} else {
cell_t *poss[MAXCANDIDATES];
int nposs = 0,x,y;
// pick a random location
// only needs to be in line-of-FIRE, not neccesarily sight.
for (y = 0 ; y <= caster->cell->map->h; y++) {
for (x = 0 ; x <= caster->cell->map->w; x++) {
cell_t *c;
c = getcellat(caster->cell->map, x, y);
if (c && haslof(caster->cell, c, LOF_WALLSTOP, NULL)) {
if (cellwalkable(caster, targcell, NULL) &&
!celldangerous(caster, targcell, B_FALSE, NULL)) {
poss[nposs++] = c;
}
} else {
cell_t *poss[MAXCANDIDATES];
int nposs = 0,x,y;
// pick a random location
// only needs to be in line-of-FIRE, not neccesarily sight.
for (y = 0 ; y <= caster->cell->map->h; y++) {
for (x = 0 ; x <= caster->cell->map->w; x++) {
cell_t *c;
c = getcellat(caster->cell->map, x, y);
if (c && haslof(caster->cell, c, LOF_WALLSTOP, NULL)) {
if (cellwalkable(caster, c, NULL) &&
!celldangerous(caster, c, B_FALSE, NULL)) {
poss[nposs++] = c;
}
if (nposs >= MAXCANDIDATES) break;
}
if (nposs >= MAXCANDIDATES) break;
}
if (!nposs) {
fizzle(caster);
return B_TRUE;
}
targcell = poss[rnd(0,nposs-1)];
if (nposs >= MAXCANDIDATES) break;
}
teleportto(caster, targcell, B_TRUE);
if (!nposs) {
fizzle(caster);
return B_TRUE;
}
targcell = poss[rnd(0,nposs-1)];
}
teleportto(caster, targcell, B_TRUE);
} else if (spellid == OT_S_LOWERMETAB) {
flag_t *f;
// ie. 2 - 4
@ -2669,7 +2667,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int stillseen = B_FALSE;
// everyone takes damage, and mark cells as hit
for (i = 0; i < narccells; i++) {
losehp(arccell[i]->lf, rolldie(2,nsides), DT_ELECTRIC, caster, "an electricity bolt");
losehp(arccell[i]->lf, rolldie(3,nsides), DT_ELECTRIC, caster, "an electricity bolt");
hitcell[nhitcells++] = arccell[i];
if (haslos(player, arccell[i])) {
@ -2731,8 +2729,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
return B_FALSE;
}
radius = power/3;
if (radius < 1) radius = 1;
radius = (power/4)+1;
addobburst(targcell, radius, DT_COMPASS, "cloud of poison gas", caster, LOF_WALLSTOP);
@ -2988,7 +2985,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (cansee(player, target)) {
msg("A ray of coldness ray hits %s.",lfname);
}
losehp(target, rnd(2,5), DT_COLD, caster, "a blast of coldness");
losehp(target, roll("3d6"), DT_COLD, caster, "a blast of coldness");
// ray stops here.
break;
}
@ -3130,6 +3127,63 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
} else if (spellid == OT_S_CRYSTALARM) {
object_t *o;
enum BODYPART bp[4];
int nbp, donesomething = B_FALSE,i;
targcell = caster->cell;
target = caster;
nbp = (power/3)+1;
bp[0] = BP_BODY;
bp[1] = BP_HEAD;
bp[2] = BP_HANDS;
bp[3] = BP_FEET;
for (i = 0; (i < 4) && (i < nbp); i++) {
if (hasbp(target, bp[i]) && !getequippedob(target->pack, bp[i])) {
switch (bp[i]) {
case BP_BODY: default:
o = addob(target->pack, "ice crystal armour"); break;
case BP_HEAD:
o = addob(target->pack, "ice crystal helmet"); break;
case BP_HANDS:
o = addob(target->pack, "ice crystal gauntlets"); break;
case BP_FEET:
o = addob(target->pack, "ice crystal boots"); break;
}
if (o) {
if (canwear(target, o, BP_NONE)) {
char obname[BUFLEN];
flag_t *f;
// announce
getobname(o, obname, 1);
if (isplayer(target)) {
msg("%s forms %s your %s!", obname, getbodypartequipname(bp[i]), getbodypartname(bp[i]));
} else if (cansee(player, target)) {
msg("%s forms %s %s%s %s!", obname, getbodypartequipname(bp[i]),
castername, getpossessive(castername), getbodypartname(bp[i]));
}
wear(target, o);
// set its values
f = hasflag(o->flags, F_OBHP);
if (f) {
f->val[0] = power*5;
f->val[1] = power*5;
}
addflag(o->flags, F_CREATEDBYSPELL, spellid, NA, NA, NULL);
donesomething = B_TRUE;
} else {
killob(o);
}
}
}
}
if (!donesomething) {
fizzle(caster);
stopspell(caster, spellid);
return B_FALSE;
}
} else if (spellid == OT_S_CRYSTALSHIELD) {
object_t *o;
targcell = caster->cell;
@ -3167,6 +3221,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f->val[0] = power*5;
f->val[1] = power*5;
}
addflag(o->flags, F_CREATEDBYSPELL, spellid, NA, NA, NULL);
} else {
killob(o);
fizzle(caster);
@ -3654,7 +3709,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
getlfname(c->lf, lfname);
msg("A blast of energy hits %s.",lfname);
}
losehp(c->lf, rnd(2,6), DT_MAGIC, caster, "an energy blast");
losehp(c->lf, roll("2d6"), DT_MAGIC, caster, "an energy blast");
}
}
}
@ -3876,7 +3931,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
setobcreatedby(o, caster);
}
if (c->lf) {
losehp(c->lf, rolldie(power,4), DT_FIRE, caster, "a fireball");
losehp(c->lf, rolldie(power,3), DT_FIRE, caster, "a fireball");
}
}
}
@ -3891,7 +3946,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (c->lf) {
int ndice;
ndice = power / 2; if (ndice < 1) ndice = 1;
losehp(c->lf, rolldie(ndice,4), DT_FIRE, caster, "a fireball");
losehp(c->lf, rolldie(ndice,3), DT_FIRE, caster, "a fireball");
}
}
}
@ -4115,8 +4170,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
o = targob;
} else {
// rings?
o = hasobwithflagval(caster->pack, F_EQUIPPED, BP_RIGHTHAND, NA, NA, NULL);
if (!o) o = hasobwithflagval(caster->pack, F_EQUIPPED, BP_LEFTHAND, NA, NA, NULL);
o = hasobwithflagval(caster->pack, F_EQUIPPED, BP_RIGHTFINGER, NA, NA, NULL);
if (!o) o = hasobwithflagval(caster->pack, F_EQUIPPED, BP_LEFTFINGER, NA, NA, NULL);
// gloves?
if (!o) o = hasobwithflagval(caster->pack, F_EQUIPPED, BP_HANDS, NA, NA, NULL);
// weapon?
@ -4737,7 +4792,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = isequipped(o);
if (f) {
if ((f->val[0] == BP_WEAPON) || (f->val[0] == BP_SECWEAPON)) {
} else if ((f->val[0] == BP_RIGHTHAND) || (f->val[0] == BP_LEFTHAND)) {
} else if ((f->val[0] == BP_RIGHTFINGER) || (f->val[0] == BP_LEFTFINGER)) {
if (isplayer(caster)) {
getobname(o, buf, 1);
msg("Your %s slides off your %s!", buf, getbodypartname(f->val[0]));
@ -5027,7 +5082,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_FALSE;
} else {
int howlong = 7;
howlong = getspellduration(3,5,blessed) + (power/2);
howlong = getspellduration(3,5,blessed) + (power/4);
addtempflag(target->flags, F_PAIN, DT_MAGIC, NA, NA, "1d3", howlong);
}
} else {
@ -5083,7 +5138,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("A glob of venom hits %s.",lfname);
}
if (!isimmuneto(target->flags, DT_POISON)) {
poison(target, power*3, P_VENOM, power, "a glob of venom");
poison(target, power*3, P_VENOM, (power/4)+1, "a glob of venom");
}
}
} else {
@ -6449,6 +6504,34 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = addtempflag(caster->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
} else if (spellid == OT_S_SHARDSHOT) {
cell_t *retcell[MAXRETCELLS];
int nretcells;
int i;
int nhits = power;
if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;
// create a line of fire towards the target cell
calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, targcell->x, targcell->y, retcell, &nretcells);
animcells(caster->cell, &retcell[1], nretcells-1, B_FALSE, '*', '\0', C_WHITE);
if (cansee(player, caster)) {
msg("%s fire%s a burst of ice shards!",castername, isplayer(caster) ? "" : "s");
}
// don't hit the caster cell on fire!
for (i = 1; (i < nretcells) && (nhits > 0); i++) {
cell_t *c;
c = retcell[i];
if (c->lf) {
// hit with ice
losehp(c->lf, rolldie(nhits, 6), DT_COLD, caster, "a burst of ice shards");
nhits--;
}
if (haslos(player, c)) {
needredraw = B_TRUE;
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
}
} else if (spellid == OT_S_SHATTER) {
char buf[BUFLEN];
if (!validatespellcell(caster, &targcell,TT_NONE, spellid, power, frompot)) return B_TRUE;
@ -6573,6 +6656,28 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// use direct damage rather than holy, because otherwise it might be increased
// due to vulnerabilities
losehp(target, rnd(1,power*2), DT_DIRECT, caster, "a smiting");
} else if (spellid == OT_S_SNAPFREEZE) {
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE;
target = haslf(targcell);
if (target) {
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (isplayer(caster) || cansee(player, target)) {
char tname[BUFLEN];
getlfname(target, tname);
msg("%s resists.",tname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
// they get angry!
if (!isplayer(target) && cansee(target, caster)) {
fightback(target, caster);
}
} else {
if (seenbyplayer && (isplayer(caster) || cansee(player, target))) *seenbyplayer = B_TRUE;
freezelf(target, caster, rnd(20,40));
}
} else {
fizzle(caster);
}
} else if (spellid == OT_S_SNOWBALL) {
int failed = B_FALSE;
// ask for a target cell
@ -6790,12 +6895,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (strstr(r->name, " snake")) {
flag_t *f;
f = hasflag(r->flags, F_HITDICE);
// ie. 1hd needs power 2
// ie. 2hd needs power 4
// ie. 3hd needs power 6
// ie. 4hd needs power 8
if (f && (power >= (f->val[0] * 2))) {
raceposs[nraceposs++] = r;
if (f) {
int ndice,nsides,bonus,maxroll;
texttodice(f->text, &ndice,&nsides,&bonus);
maxroll = ndice * nsides + bonus;
// ie. 1hd needs power 2
// ie. 2hd needs power 4
// ie. 3hd needs power 6
// ie. 4hd needs power 8
if (power >= (maxroll/4)) {
raceposs[nraceposs++] = r;
}
}
}
}
@ -7302,30 +7412,62 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
swapplaces(caster, target, B_FALSE);
} else if ((spellid == OT_S_SUMMONANIMALSSM) ||
(spellid == OT_S_SUMMONANIMALSMD) ||
(spellid == OT_S_SUMMONANIMALSLG)) {
int lifetime, nwant,ngot;
(spellid == OT_S_SUMMONANIMALSLG) ||
(spellid == OT_S_SUMMONDEMON)) {
int lifetime, nwant,ngot,successrate;
enum LFSIZE wantsize;
enum RACECLASS wantrc;
int friendly;
lifetime = (power * 9) + rnd(1,power*2);
nwant = rnd(2,3);
switch (spellid) {
case OT_S_SUMMONDEMON:
wantrc = RC_DEMON;
wantsize = SZ_ANY;
nwant = 1;
successrate = power*10;
if (caster->race->raceclass->id == RC_DEMON) {
friendly = B_TRUE;
} else if (onein(4)) {
friendly = B_FALSE;
} else {
friendly = B_TRUE;
}
break;
case OT_S_SUMMONANIMALSSM:
wantrc = RC_ANIMAL;
wantsize = SZ_SMALL;
nwant = rnd(2,3);
successrate = 100;
friendly = B_TRUE;
break;
case OT_S_SUMMONANIMALSMD:
wantrc = RC_ANIMAL;
wantsize = SZ_MEDIUM;
nwant = rnd(2,3);
successrate = 100;
friendly = B_TRUE;
break;
case OT_S_SUMMONANIMALSLG:
wantrc = RC_ANIMAL;
wantsize = SZ_LARGE;
nwant = rnd(2,3);
successrate = 100;
friendly = B_TRUE;
break;
default:
wantsize = SZ_ANY;
successrate = 100;
break;
}
ngot = summonlfs(caster, caster->cell, wantrc, wantsize, AL_NONE, nwant, lifetime);
if (!pctchance(successrate)) {
fizzle(caster);
return B_TRUE;
}
ngot = summonlfs(caster, caster->cell, wantrc, wantsize, AL_NONE, nwant, lifetime, friendly);
if (!ngot) {
fizzle(caster);
return B_TRUE;
@ -7334,7 +7476,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
raceclass_t *rc;
rc = findraceclass(wantrc);
if (seenbyplayer) *seenbyplayer = B_TRUE;
msg("%s appear around %s!", makeplural(rc->name), castername);
if (ngot == 1) {
msg("%s %s appears near %s!", needan(rc->name) ? "An" : "A", rc->name, castername);
} else {
msg("%s appear around %s!", makeplural(rc->name), castername);
}
}
}
} else if (spellid == OT_S_SUMMONWEAPON) {
@ -7365,6 +7511,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
snprintf(buf, BUFLEN, "2d%d",power);
changeflagtext(f, buf);
}
addflag(o->flags, F_CREATEDBYSPELL, spellid, NA, NA, NULL);
} else {
killob(o);
fizzle(caster);
@ -7977,12 +8124,11 @@ void fizzle(lifeform_t *caster) {
} else {
nothinghappens();
}
/*
} else if (cansee(player, caster)) {
char buf[BUFLEN];
getlfname(caster, buf);
capitalise(buf);
msg("%s's spell fizzles.", buf);
*/
}
}
@ -8383,12 +8529,13 @@ int getspellrange(lifeform_t *lf, enum OBTYPE spellid, int power) {
// If we can _will_ this to occur then we might have a set
// range
if (lf) {
int newrange;
flag_t *f;
f = lfhasflagval(lf, F_CANWILL, spellid, NA, NA, NULL);
if (f && strlen(f->text)) {
texttospellopts(f->text, NULL, NULL, NULL, &range);
if (range > 0) {
return range;
texttospellopts(f->text, NULL, NULL, NULL, &newrange);
if (newrange > 0) {
return newrange;
}
}
}
@ -8419,6 +8566,9 @@ int getspellrange(lifeform_t *lf, enum OBTYPE spellid, int power) {
case OT_S_CHAINLIGHTNING:
range = (power*3);
break;
case OT_S_SHARDSHOT:
range = power;
break;
default:
break;
}
@ -8587,6 +8737,10 @@ void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYP
void stopspell(lifeform_t *caster, enum OBTYPE spellid) {
flag_t *f,*nextf;
object_t *o, *nexto;
objecttype_t *sp;
sp = findot(spellid);
if (!sp) return;
for (f = caster->flags->first ; f ; f = nextf) {
nextf = f->next;
@ -8596,28 +8750,22 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) {
killflag(f);
}
}
if (isplayer(caster)) {
msg("Your %s spell disappates.",sp->name);
}
// remove any other specific effects based on spell type.
for (o = caster->pack->first; o ; o = nexto) {
nexto = o->next;
if ((o->type->id == OT_ENERGYBLADE) && (spellid == OT_S_SUMMONWEAPON)) {
if (hasflagval(o->flags, F_CREATEDBYSPELL, spellid, NA, NA, NULL)) {
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)) {
char obname[BUFLEN];
char lfname[BUFLEN];
getobname(o, obname, 1);
getlfname(caster, lfname);
msg("%s%s %s vanishes.", lfname, getpossessive(lfname),
obname);
noprefix(obname));
}
killob(o);
}
@ -8642,7 +8790,7 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) {
// returns # created
int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, enum ALIGNMENT wantalign, int howmany, int lifetime) {
int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, enum ALIGNMENT wantalign, int howmany, int lifetime, int friendly) {
lifeform_t *newlf;
race_t *r = NULL;
enum RACE poss[MAXCANDIDATES];
@ -8699,10 +8847,12 @@ int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFS
addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL);
// summoned
addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL);
addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL);
if (areallies(player, caster)) {
makefriendly(newlf, PERMENANT);
}
if (friendly) {
addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL);
if (areallies(player, caster)) {
makefriendly(newlf, PERMENANT);
}
}
ncreated++;
}
}

View File

@ -27,7 +27,7 @@ void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYP
void stopspell(lifeform_t *caster, enum OBTYPE spellid);
void stopallspells(lifeform_t *lf);
void stopallspellsexcept(lifeform_t *lf, ...);
int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, enum ALIGNMENT wantalign, int howmany, int lifetime);
int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, enum ALIGNMENT wantalign, int howmany, int lifetime, int friendly);
lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target);
cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power, int frompot);
//lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf);

29
vaults/playerstart1.vlt Normal file
View File

@ -0,0 +1,29 @@
@id:playerstart_1
@map
##########
#...c..|,#
#...-/-###
+......|,#
#.-/-..###
#...c..|,#
##########
@end
@legend
#:cell:rock wall
|:ob:iron gate
,:ob:1-4 bones:50
+:ob:wooden door
+:exit
/:ob:wooden table
-:ob:wooden footstool
@end
@flags
goesin:dungeon
playerstart
norandom
atoneof(8,1)(8,3)(8,5) ob:playerstart
scatter(1,1,-2,-2) ob:wooden footstool:0-3
scatter(1,1,-2,-2) ob:random food:0-2
mayrotate
@end

25
vaults/playerstart2.vlt Normal file
View File

@ -0,0 +1,25 @@
@id:playerstart_2
@map
###x###
#.|.|.#
###.###
#.|.|.#
###.###
#.|.|.#
###.###
#.|.|.#
###x###
@end
@legend
#:cell:rock wall
|:ob:iron gate
x:exit
@end
@flags
goesin:dungeon
playerstart
norandom
atoneof(1,1)(1,3)(1,5)(1,7)(5,1)(5,3)(5,5)(5,7) ob:playerstart
mayrotate
@end

26
vaults/playerstart3.vlt Normal file
View File

@ -0,0 +1,26 @@
@id:playerstart_3
@map
#########
#.......#
#.IIIII.#
#.II.I..#
#.I.p.,.#
#.II.II.#
#.IIIII.#
#.......#
#########
@end
@legend
#:cell:rock wall
I:cell:glass wall
,:ob:4-8 pieces of broken glass
p:ob:playerstart
@end
@flags
goesin:dungeon
autodoors:50
playerstart
norandom
mayrotate
@end

25
vaults/playerstart4.vlt Normal file
View File

@ -0,0 +1,25 @@
@id:playerstart_4
@map
#######
#wwwww#
#ww.ww#
#w.p._x
#ww.ww#
#wwwww#
#######
@end
@legend
#:cell:rock wall
w:cell:low rock floor
w:ob:very deep water
_:cell:wood floor
p:ob:playerstart
x:exit
@end
@flags
goesin:dungeon
playerstart
norandom
mayrotate
@end