- [+] replace "fireplace" with "brazier"

- [+] make non-lethal kills (ie. knockouts) display in grey rather than
      green
- [+] ability: merciful fighting? always does bashing damage, always
      ko. 
    - [+] done
- [+] Chatting to gods shouldn't work
- [+] bug: when running with shift+dir, i'm running past corridors.
- [+] when announcing skill gains, say if they are from a level.
    - [+] set lifetime to FROMJOB when giving them.
    - [+] if lifetime = FROMJOB, ""you can now use the ability 'xxx' 
          (warrior skill)"
- [+] grenade/c4 explosions should be able to damage cells!
- [+] change grenades to have bigger radius (dtorth 1)
- [+] automatically call "fireat" for grenades
    - [+] impement this
    - [+] make the timer shorter!
- [+] add extra checks to stop monsters from attacking allies
- [+] replace "insane"monster behaviour with F_TERRITORIAL v0=range.
    - [+] will atatck anything else visible within range xxx
- [+] grave sprite should be able to see in the dark
- [+] instead of saying "An orc [drunk]", change getlfname to return "a
      drunken orc" etc
- [+] when you throw an object at someone in a wall, it should fall
      onto the ground in front, NOT the wall itself!
- [+] show how MUCH high/low str/agi will affect weapon damage/accuracy
- [+] different shoddy/masterwork text based on weapon types
- [+] bug: monsters never bleed from injuries!
- [+] another bug in getavgdam - negative accuracy returns negative
      damage since we modify damage by accuracy!
    - [+] within this function, limit accuracy to range 0-100
- [+] bug with options - opt->id never being initialised!
- [+] don't apply "behaviours" to anythuing other than humanoids.
- [+] increase missile accuracy if you are above your target
    - [+] (ie you are flying higher them them)
    - [+] getflightsizemod()
This commit is contained in:
Rob Pearce 2012-01-17 20:46:23 +00:00
parent db0b726088
commit 849e567b43
15 changed files with 440 additions and 178 deletions

14
ai.c
View File

@ -759,6 +759,7 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) {
}
if (pctchance(chance)) {
flag_t *f;
if (lfhasflag(lf, F_HATESALL) || lfhasflag(lf, F_RAGE)) {
if (nhateposs < MAXCANDIDATES) {
if (db) dblog(".oO { hate everything - found lfid %d (%s) ! }",who->id, who->race->name);
@ -767,11 +768,18 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) {
break;
} else if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) ||
lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) {
if (nhateposs < MAXCANDIDATES) {
if ((nhateposs < MAXCANDIDATES) && !areallies(lf, who)) {
if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name);
hateposs[nhateposs++] = who;
}
break;
} else if ( ((f = lfhasflag(lf, F_TERRITORIAL)) != NULL) &&
(getcelldist(who->cell, lf->cell) <= f->val[0]) ) {
if ((nhateposs < MAXCANDIDATES) && !areallies(lf, who)) {
if (db) dblog(".oO { territorial and found target in range - lfid %d (%s) ! }",who->id, who->race->name);
hateposs[nhateposs++] = who;
}
break;
} else if (!nhateposs && areenemies(lf, who)) { // dont check if we've already found a hated target
if (nposs < MAXCANDIDATES) {
if (db) dblog(".oO { found an enemy target - lfid %d (%s) ! }",who->id, who->race->name);
@ -780,7 +788,9 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) {
} else {
getflags(lf->flags, retflag, &nretflags, F_HATESRACEWITHFLAG, F_NONE);
for (i = 0; i < nretflags; i++) {
if (lfhasflag(who, retflag[i]->id)) {
if (lfhasflag(who, retflag[i]->id) &&
!areallies(lf, who)) {
if (db) dblog(".oO { found a target with hated flags - lfid %d (%s) ! }",who->id, who->race->name);
hateposs[nhateposs++] = who;
}

View File

@ -1542,38 +1542,11 @@ int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag) {
dam[i] += rnd(1,6);
}
// adjust dam
adjustdammaterial(&dam[i], damtype[i], c->type->material->id);
if (dam[i] > 0) {
// wall loses hp
c->hp -= dam[i];
if (c->hp <= 0) {
char cellname[BUFLEN];
int shattered = B_FALSE;
enum MATERIAL cellmat;
// remember cell properties
sprintf(cellname, "%s %s", needan(c->type->name) ? "An" : "A", c->type->name);
cellmat = c->type->material->id;
// cell dies (have to do this before calling fragments())
setcelltype(c, c->map->habitat->emptycelltype);
// announce
if (haslos(player, c)) {
msg("%s %s!", cellname, willshatter(cellmat) ? "shatters" : "is destroyed");
}
// shatter?
if (willshatter(cellmat)) {
char what[BUFLEN];
shattered = B_TRUE;
noise(c, NULL, NC_OTHER, SV_CAR, "something shattering.", NULL);
if (getshardobname(cellmat, what)) {
fragments(c, what, 3, 3);
}
}
damagecell(c, dam[i], damtype[i]);
// don't deal any more damage types
break;
}
}
} // end foreach damtype
// no special weapon effects on cells.

20
data.c
View File

@ -67,6 +67,7 @@ option_t *addoption(enum OPTION id, char *text, int def) {
a->next = NULL;
// set props
a->id = id;
a->text = strdup(text);
a->def = def;
a->enabled = def;
@ -490,6 +491,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_STARTSKILL, SK_RANGED, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_BEGINNER, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_THROWING, PR_NOVICE, NA, NULL);
// learnable skills
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL);
@ -1425,8 +1427,8 @@ void initobjects(void) {
addflag(lastot->flags, F_OPPOSITESTAIRS, OT_TUNNELUP, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_MAKESNOISE, 33, 3, NA, "a strange echoing.");
addflag(lastot->flags, F_MAKESNOISE, 33, 3, NA, "an echoing drip.");
addflag(lastot->flags, F_MAKESNOISE, 33, 1, NA, "a strange echoing.");
addflag(lastot->flags, F_MAKESNOISE, 33, 1, NA, "an echoing drip.");
addot(OT_TUNNELUP, "tunnel leading up", "A wide tunnel leading upwards.", MT_STONE, 3000, OC_DFEATURE, SZ_HUGE);
addflag(lastot->flags, F_GLYPH, C_BROWN, '<', NA, NULL);
addflag(lastot->flags, F_CLIMBABLE, D_UP, NA, NA, NULL);
@ -3908,6 +3910,8 @@ void initobjects(void) {
addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL);
addot(OT_A_STUDYSCROLL, "study scroll", "Attempt to learn a spell directly from a scroll.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_STRIKETOKO, "merciful fighting", "Try to knock out your opponents rather than killing them.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_SUCKBLOOD, "suck blood", "You can suck the blood from enemies after attaching to them.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
@ -4422,8 +4426,8 @@ void initobjects(void) {
addflag(lastot->flags, F_RECHARGEWHENOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDEATH, NA, NA, B_IFACTIVATED, "8d2");
addflag(lastot->flags, F_EXPLODEONDAM, NA, NA, B_IFACTIVATED, "5d2");
addflag(lastot->flags, F_EXPLODEONDEATH, NA, 1, B_IFACTIVATED, "16d2");
addflag(lastot->flags, F_EXPLODEONDAM, NA, 1, B_IFACTIVATED, "13d2");
addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
@ -4457,7 +4461,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RECHARGEWHENOFF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EXPLODEONDEATH, NA, B_BIG, B_IFACTIVATED, "90d2"); // 90 - 180 damage
addflag(lastot->flags, F_EXPLODEONDEATH, NA, 2, B_IFACTIVATED, "90d2"); // 90 - 180 damage
addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL);
addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL);
@ -4946,7 +4950,7 @@ void initobjects(void) {
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addot(OT_FIREPLACE, "fireplace", "A roaring fireplace.", MT_STONE, 200, OC_FURNITURE, SZ_LARGE);
addot(OT_FIREPLACE, "brazier", "A heavy iron bowl filled with fire.", MT_METAL, 200, OC_FURNITURE, SZ_LARGE);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_RED, '\\', NA, NULL);
@ -6154,6 +6158,7 @@ void initobjects(void) {
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 9, 10, NULL);
addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL);
addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 8, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_RARITY, H_CAVE, 70, NA, NULL);
@ -7001,6 +7006,7 @@ void initobjects(void) {
void initoptions(void) {
addoption(OPT_ALWAYSSHOWTRAILS, "always show trail objects", B_FALSE);
addoption(OPT_AUTORELOAD, "automatically reload empty firearms", B_TRUE);
addoption(OPT_STOPRUNONNOISE, "stop running if sound heard", B_TRUE);
}
@ -8975,6 +8981,7 @@ void initrace(void) {
addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL);
addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
addrace(R_SPRITEICE, "ice sprite", 5, 'n', C_WHITE, MT_ICE, RC_MAGIC, "A small magical creature made from freezing ice.");
setbodytype(lastrace, BT_HUMANOID);
@ -11756,6 +11763,7 @@ void initskills(void) {
if (isweaponskill(sk->id) || (sk->id == SK_UNARMED)) {
addskilldesc(sk->id, PR_INEPT, "This skill increases your accuracy and damage when using matching weapons.", B_FALSE);
addskilldesc(sk->id, PR_NOVICE, "^g-2 accuracy penalty.^n", B_FALSE);
if (sk->id == SK_CLUBS) addskilldesc(sk->id, PR_NOVICE, "^gYou gain the 'merciful fighting' ability.^n", B_FALSE);
addskilldesc(sk->id, PR_BEGINNER, "^g-1 accuracy penalty^n", B_FALSE);
addskilldesc(sk->id, PR_BEGINNER, "^gYou gain the 'wild strike' ability.^n", B_FALSE);
addskilldesc(sk->id, PR_ADEPT, "^g+10% damage bonus.^n", B_FALSE);

8
defs.h
View File

@ -1503,6 +1503,7 @@ enum OBTYPE {
OT_A_SPRINT,
OT_A_STUDYSCROLL,
OT_A_STINGACID, // need to define dam in f_canwill
OT_A_STRIKETOKO,
OT_A_SUCKBLOOD,
OT_A_SWALLOW,
OT_A_SWOOP,
@ -2125,12 +2126,12 @@ enum FLAG {
F_ACTIVATED, // val0 = is this object turned on?
F_GRENADE, // this object will drain charge when activated, then die
F_EXPLODEONDEATH, // explodes when it dies, deals TEXT damage.
// val1 = BIG means hit surrounding cells
// val1 = explosion radius (dtorth)
// val2 = ifactivated, only explodes if activated.
F_EXPLODEONDAM, // explodes when it is damaged, deals TEXT damage.
// v0 = damage type which makes it explode.
// NA means 'any damage type'
// val1 = BIG means hit surrounding cells
// val1 = explosion radius (dtorth)
// val2 = ifactivated, only explodes if activated.
F_FLASHONDEATH, // produce a bright flash when it dies,v0=range
F_FLASHONDAM, // produces a bright flash when it is damaged,v0=range,v2=ifacctivated
@ -2638,6 +2639,7 @@ enum FLAG {
F_HATESRACE, // lf will attack lfs with race=v0 or baseid=v0 on
// sight
F_HATESRACEWITHFLAG, // lf will attack lfs with flag v0 on sight
F_TERRITORIAL, // lf will attack ALL other visible lfs within range v0
F_HARMLESS, // it is safe to rest around this lf
F_RNDHOSTILE, // v0% chance of being hostile.
F_HOSTILE, // lf will attack the player if in sight
@ -2772,6 +2774,7 @@ enum FLAG {
F_COMBOSTRIKE, // lf is performing a combination strike
F_HEAVYBLOW, // next attack is a heavy blow
F_QUIVERINGPALM, // your next strike will be a quivpalm attack
F_STRIKETOKO, // your attacks will never kill, just KO.
F_TKTHROW, // when you throw an object, use your
// attrib = v0 and skilltype = v1
// rather than AGI and SK_THROWING like normal
@ -3287,6 +3290,7 @@ typedef struct warning_s {
enum OPTION {
OPT_ALWAYSSHOWTRAILS,
OPT_AUTORELOAD,
OPT_STOPRUNONNOISE,
};

74
io.c
View File

@ -775,16 +775,6 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
strcat(extrainfo, buf2);
}
// need a certain amount of race knowledge to recognise ai traits
if (lorelev >= PR_SKILLED) {
f = lfhasflag(c->lf, F_BEHAVIOUR);
if (f) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, f->text);
}
}
if ((getallegiance(c->lf) == AL_HOSTILE) &&
(lorelev >= PR_ADEPT)) {
char dangerbuf[BUFLEN];
@ -960,7 +950,7 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
cell_t *newcell;
int bad = B_FALSE;
if (srclf) {
if (!haslof_real(srclf->cell, c, LOFTYPE, &newcell, srclf)) {
if (!haslof_real(srclf->cell, c, LOFTYPE, &newcell, srclf, B_TRUE)) {
bad = B_TRUE;
}
} else {
@ -1346,8 +1336,9 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
if (ot) {
enum SPELLSCHOOL school;
school = getspellschoolknown(lf, ot->id);
msg("^gYou have learned the %s '%s'.",
(school == SS_MENTAL) ? "psionic power" : "spell", ot->name);
msg("^gYou have learned the %s '%s'%s.",
(school == SS_MENTAL) ? "psionic power" : "spell", ot->name,
getflagsourcetext(f));
donesomething = B_TRUE;
}
}
@ -1358,7 +1349,8 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
ot = findot(f->val[0]);
if (ot && (!hasflag(ot->flags, F_NOANNOUNCE))) {
char buf[BUFLEN];
snprintf(buf, BUFLEN, "^gYou have gained the ability '%s'.", ot->name);
snprintf(buf, BUFLEN, "^gYou have gained the ability '%s'%s.", ot->name,
getflagsourcetext(f));
/*
if (f->val[2] != NA) {
char turnbuf[BUFLEN];
@ -1758,6 +1750,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
msg("%s start%s emitting a foul odour!",lfname, isplayer(lf) ? "" : "s" );
donesomething = B_TRUE;
break;
case F_STRIKETOKO:
if (isplayer(lf)) { // don't know if monsters get it
msg("Your attacks will now be non-lethal.");
donesomething = B_TRUE;
}
break;
case F_STUNNED:
msg("%s %s stunned!",lfname, is(lf));
donesomething = B_TRUE;
@ -2353,6 +2351,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
msg("%s no longer smell%s bad.",lfname, isplayer(lf) ? "" : "s" );
donesomething = B_TRUE;
break;
case F_STRIKETOKO:
if (isplayer(lf)) { // don't know if monsters lose it
msg("Your attacks will no longer be non-lethal.");
donesomething = B_TRUE;
}
break;
case F_STUNNED:
msg("%s %s no longer stunned.",lfname, is(lf));
donesomething = B_TRUE;
@ -6012,14 +6016,19 @@ char *makedesc_ob(object_t *o, char *retbuf) {
if (usable && isweapon(o)) {
if (pctmod > 0) {
sprintf(buf, "^%dYour high %s will increase your %s with this weapon.^n\n", C_GREEN,
sprintf(buf, "^%dYour high %s will increase your %s with this weapon by %d%s.^n\n",
C_GREEN,
getattrname(f->val[0]),
(f->val[0] == A_AGI) ? "accuracy" : "damage");
(f->val[0] == A_AGI) ? "accuracy" : "damage",
(f->val[0] == A_AGI) ? getaccuracynum(pctmod) : pctmod,
(f->val[0] == A_AGI) ? "" : "%");
strncat(retbuf, buf, HUGEBUFLEN);
} else if (pctmod < 0) {
sprintf(buf, "^%dYour low %s will decrease your %s with this weapon.^n\n", C_BROWN,
sprintf(buf, "^%dYour low %s will decrease your %s with this weapon by %d%s.^n\n", C_BROWN,
getattrname(f->val[0]),
(f->val[0] == A_AGI) ? "accuracy" : "damage");
(f->val[0] == A_AGI) ? "accuracy" : "damage",
(f->val[0] == A_AGI) ? getaccuracynum(abs(pctmod)) : abs(pctmod),
(f->val[0] == A_AGI) ? "" : "%");
strncat(retbuf, buf, HUGEBUFLEN);
}
}
@ -7513,18 +7522,21 @@ int dotakeoff(obpile_t *op) {
return rv;
}
void dothrow(obpile_t *op) {
object_t *o;
// specify EITHER op or o.
// returns B_TRUE on failure.
int dothrow(obpile_t *op, object_t *o) {
char buf[BUFLEN],buf2[BUFLEN];
flag_t *f;
if (!hasbp(player, BP_HANDS)) {
msg("You have no hands to throw with!");
return;
return B_TRUE;
}
// ask which object to throw
if (!o) {
o = askobject(op, "Throw what", NULL, 't', AO_NONE);
}
if (o) {
int maxdist;
char subprompt[BUFLEN],oidbuf[BUFLENSMALL];
@ -7534,7 +7546,7 @@ void dothrow(obpile_t *op) {
f = hasflag(o->flags, F_EQUIPPED);
if (f && (f->val[0] != BP_WEAPON)) {
msg("You'll need to take it off first.");
return;
return B_TRUE;
}
// calculate throw range
@ -7558,14 +7570,14 @@ void dothrow(obpile_t *op) {
if (ch == 'y') {
// update destination cell.
where = newwhere;
} else return;
} else return B_TRUE;
} else {
if (reason == E_NOLOS) {
msg("You can't see there!");
} else { // ie. E_NOLOF and no new cell
msg("You don't have a clear line of fire to there.");
}
return;
return B_TRUE;
}
}
@ -7577,9 +7589,11 @@ void dothrow(obpile_t *op) {
}
} else {
throwat(player, o, where);
return B_FALSE;
}
}
}
return B_TRUE;
}
// returns TRUE if escape pressed
@ -8683,8 +8697,8 @@ void handleinput(void) {
// something here?
if (stopnow) {
} else if (!ihaveturned && moveclear(player, lastdir, NULL)) {
// haven't turned yet?
} else if (!ihaveturned && moveclear(player, lastdir, NULL) && isroom(player->cell)) {
// haven't turned yet and in a room?
// if walls to our l+r have changed...
if (getleftrightwalls(player) != walls) {
stopnow = B_TRUE;
@ -9040,7 +9054,7 @@ void handleinput(void) {
doquaff(player->pack);
break;
case 't': // throw
dothrow(player->pack);
dothrow(player->pack, NULL);
break;
case 'P': // Pour
dopour(player->pack);
@ -11771,6 +11785,12 @@ void showlfstats(lifeform_t *lf, int showall) {
y++;
}
f = lfhasflag(lf, F_STRIKETOKO);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s attacking in a non-lethal manner.", you(lf), is(lf));
y++;
}
f = lfhasflag(lf, F_STUNNED);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s stunned and cannot attack, cast spells or use abilities.", you(lf), is(lf));

2
io.h
View File

@ -72,7 +72,7 @@ void dorest(void);
int doselguntarget(void);
void dostairs(int dir);
int dotakeoff(obpile_t *op);
void dothrow(obpile_t *op);
int dothrow(obpile_t *op, object_t *o);
int dowear(obpile_t *op);
int doweild(obpile_t *op);
int downline(int *y, int h, char *heading, char *subheading, char *bottomstring, char *cmdchars, char *retchar);

201
lf.c
View File

@ -765,6 +765,17 @@ int caneat(lifeform_t *lf, object_t *o) {
return B_TRUE;
}
int canhaverandombehaviour(lifeform_t *lf) {
if (isundead(lf)) return B_FALSE;
if (isgod(lf)) return B_FALSE;
if (getraceclass(lf) == RC_HUMANOID) {
return B_TRUE;
}
return B_FALSE;
}
// ie. will sound from 'dest' reach the ears of 'lf'
int canhear(lifeform_t *lf, cell_t *dest, int volume) {
int numpixels;
int i;
@ -1049,17 +1060,9 @@ int canreachbp(lifeform_t *lf, lifeform_t *victim, enum BODYPART bp) {
}
lfsize = getlfsize(lf);
switch (isairborne(lf)) {
case F_FLYING: lfsize += 2; break;
case F_LEVITATING: lfsize++; break;
default: break;
}
lfsize += getflightsizemod(lf);
victimsize = getlfsize(victim);
switch (isairborne(victim)) {
case F_FLYING: victimsize += 2; break;
case F_LEVITATING: victimsize++; break;
default: break;
}
victimsize += getflightsizemod(victim);
howmuchsmaller = victimsize - lfsize;
if (howmuchsmaller <= 0) return B_TRUE;
@ -5421,6 +5424,7 @@ int getavgdam(lifeform_t *lf, int forxp) {
// modify for accuracy
acc = getlfaccuracy(lf, o);
limitf(&acc, 0, 100);
thisavg = pctof(acc, thisavg);
avgdam += thisavg;
@ -5899,8 +5903,13 @@ int getguntargetid(lifeform_t *lf) {
}
int gethearingrange(lifeform_t *lf) {
int range = 8; // deafult
range = 2 + (getskill(lf, SK_LISTEN)*2);
int range = 2; // default
if (!isasleep(lf)) {
// if awake, your listen skills helps
range += (getskill(lf, SK_LISTEN)*2);
}
return range;
}
@ -6326,6 +6335,17 @@ enum LFCONDITION getlfcondition(lifeform_t *lf) {
return C_DEAD;
}
// how much taller are you due to your flight?
int getflightsizemod(lifeform_t *lf) {
int howmuch = 0;
switch (isairborne(lf)) {
case F_FLYING: howmuch += 2; break;
case F_LEVITATING: howmuch++; break;
default: break;
}
return howmuch;
}
enum SKILLLEVEL getmaxskilllevel(lifeform_t *lf, enum SKILL skid) {
flag_t *f;
enum SKILLLEVEL maxlev = PR_MASTER;
@ -7098,6 +7118,7 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis, int showall) {
job_t *j;
flag_t *f;
enum LFSIZE size,racesize;
int dobehaviour = B_TRUE;
// 'the' or 'your' ?
@ -7133,11 +7154,27 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis, int showall) {
strcat(descstring, " ");
}
// need a certain amount of race knowledge to recognise ai traits
if (getlorelevel(player, lf->race->raceclass->id) < PR_SKILLED) {
dobehaviour = B_FALSE;
}
// frozen/headless trump behavioural descriptions like "insane"
if (lfhasflag(lf, F_FROZEN)) {
strcat(descstring, "frozen ");
dobehaviour = B_FALSE;
}
if (lfhasflag(lf, F_HEADLESS)) {
strcat(descstring, "headless ");
dobehaviour = B_FALSE;
}
if (dobehaviour) {
f = lfhasflag(lf, F_BEHAVIOUR);
if (f) {
strcat(descstring, f->text);
strcat(descstring, " ");
}
}
// construct job string
@ -8778,14 +8815,17 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
if (id == SK_ATHLETICS) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_CLIMBING) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_CLIMB, NA, NA, NULL);
if (!newf || (newf->lifetime > 0)) {
newf = addflag(lf->flags, F_CANWILL, OT_A_CLIMB, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_CLIMB, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_CLUBS) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_STRIKETOKO, NA, NA, NULL);
if (!newf || (newf->lifetime > 0)) {
newf = addtempflag(lf->flags, F_CANWILL, OT_A_STRIKETOKO, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_COOKING) {
if (isplayer(lf)) {
@ -8795,42 +8835,35 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
}
newf = hasflagval(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_LORE_ARCANA) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_LOCKPICKING) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_PICKLOCK, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_PICKLOCK, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_PICKLOCK, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_METALWORK) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_SEWING) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_THIEVERY) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_TRAPS) {
newf = addflag(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL, FROMSKILL);
}
// learning a new spell school skill will grant you a random first level spell from
@ -8867,20 +8900,17 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
if (id == SK_ATHLETICS) {
if (f->val[1] == PR_ADEPT) {
newf = addflag(lf->flags, F_CANWILL, OT_A_TUMBLE, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_TUMBLE, NA, NA, NULL, FROMSKILL);
} else if (f->val[1] == PR_EXPERT) {
newf = addflag(lf->flags, F_CANWILL, OT_A_JUMP, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_JUMP, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_CARTOGRAPHY) {
if (f->val[1] == PR_SKILLED) {
addflag(lf->flags, F_PHOTOMEM, B_TRUE, NA, NA, NULL);
addtempflag(lf->flags, F_PHOTOMEM, B_TRUE, NA, NA, NULL, FROMSKILL);
}
if (f->val[1] == PR_MASTER) {
if (!hasflagval(lf->flags, F_CANWILL, OT_S_MAPPING, NA, NA, NULL)) {
newf = addflag(lf->flags, F_CANWILL, OT_S_MAPPING, 50, 50, "pw:1;");
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_S_MAPPING, 50, 50, "pw:1;", FROMSKILL);
}
}
} else if (id == SK_COOKING) {
@ -8893,16 +8923,14 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
} else if (id == SK_EVASION) {
if (f->val[1] == PR_ADEPT) {
if (isplayer(lf)) {
newf = addflag(lf->flags, F_CANWILL, OT_A_SNATCH, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_SNATCH, NA, NA, NULL, FROMSKILL);
}
}
} else if (id == SK_LORE_ARCANA) {
if (f->val[1] == PR_ADEPT) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL, FROMSKILL);
}
}
} else if (id == SK_LORE_NATURE) {
@ -8916,14 +8944,12 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
if (f->val[1] == PR_SKILLED) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL, FROMSKILL);
}
} else if (f->val[1] == PR_MASTER) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL, FROMSKILL);
}
}
} else if (id == SK_PERCEPTION) {
@ -8936,25 +8962,21 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
if (f->val[1] == PR_SKILLED) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL, FROMSKILL);
}
} else if (f->val[1] == PR_MASTER) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL, FROMSKILL);
}
}
} else if (id == SK_SHIELDS) {
if (f->val[1] == PR_BEGINNER) {
newf = addflag(lf->flags, F_CANWILL, OT_A_SHIELDBASH, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_SHIELDBASH, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_STEALTH) {
if (f->val[1] == PR_BEGINNER) {
newf = addflag(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL, FROMSKILL);
}
} else if (id == SK_TECHUSAGE) {
if (isplayer(lf)) {
@ -9008,21 +9030,19 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
*/
}
if (isweaponskill(id)) {
if (f->val[1] == PR_BEGINNER) {
if (!hasflagval(lf->flags, F_CANWILL, OT_A_EXPOSEDSTRIKE, NA, NA, NULL)) {
newf = addflag(lf->flags, F_CANWILL, OT_A_EXPOSEDSTRIKE, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_EXPOSEDSTRIKE, NA, NA, NULL, FROMSKILL);
}
} else if (f->val[1] == PR_ADEPT) {
if (!hasflagval(lf->flags, F_CANWILL, OT_A_ALTERATTACK, NA, NA, NULL)) {
newf = addflag(lf->flags, F_CANWILL, OT_A_ALTERATTACK, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_ALTERATTACK, NA, NA, NULL, FROMSKILL);
}
} else if (f->val[1] == PR_MASTER) {
if (!hasflagval(lf->flags, F_CANWILL, OT_A_COMBOSTRIKE, NA, NA, NULL)) {
newf = addflag(lf->flags, F_CANWILL, OT_A_COMBOSTRIKE, NA, NA, NULL);
newf->lifetime = FROMSKILL;
newf = addtempflag(lf->flags, F_CANWILL, OT_A_COMBOSTRIKE, NA, NA, NULL, FROMSKILL);
}
}
}
@ -9412,11 +9432,14 @@ int gotosleep(lifeform_t *lf, int onpurpose) {
flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp) {
flag_t *f, *retflag[MAXCANDIDATES];
int nretflags,i;
getflags(player->flags, retflag, &nretflags, F_INJURY, F_NONE);
getflags(lf->flags, retflag, &nretflags, F_INJURY, F_NONE);
for (i = 0;i < nretflags; i++) {
f = retflag[i];
// only temporary flags count - not permenant ones
if ((f->lifetime > 0) && (f->val[1] == bp) && (f->val[2] == DT_SLASH)) {
if (isplayer(lf) && (f->lifetime < 0)) {
// for the player, only temporary flags count - not permenant ones
// this is so that losing a whole finger etc doesn't completely
// cripple you by making you always bleed.
} else if ((f->val[1] == bp) && (f->val[2] == DT_SLASH)) {
return f;
}
}
@ -10127,13 +10150,16 @@ flag_t *hasactivespell(lifeform_t *lf, enum OBTYPE sid) {
}
int haslof(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) {
return haslof_real(src, dest, loftype, newdest, NULL);
return haslof_real(src, dest, loftype, newdest, NULL, B_TRUE);
}
// got line of fire to dest? if lof is blocked, return last cell in 'newdest'
// if 'srclf' is set, we are checking whether 'srclf' THINKS they have line of fire. ie invisible/unseed
// lifeforms don't block lof.
int haslof_real(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest, lifeform_t *srclf) {
//
// if 'walllfsok' is set, then we ARE allowed to have lineoffire to walls (ie. solid cells) if there is a lifeform
// there.
int haslof_real(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest, lifeform_t *srclf, int walllfsok) {
int numpixels;
int i;
int x1,y1,x2,y2;
@ -10192,7 +10218,7 @@ int haslof_real(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdes
if (cell->type->solid) {
if (i == 0) {
// ok
} else if (cell->lf && (i == (numpixels-1)) ) {
} else if (walllfsok && cell->lf && (i == (numpixels-1)) ) {
// ok
} else {
reason = E_NOLOF;
@ -11497,6 +11523,7 @@ void makepeaceful(lifeform_t *who) {
killflagsofid(who->flags, F_HOSTILE);
killflagsofid(who->flags, F_HATESALL);
killflagsofid(who->flags, F_HATESRACE);
killflagsofid(who->flags, F_TERRITORIAL);
killflagsofid(who->flags, F_HATESRACEWITHFLAG);
loseaitargets(who);
}
@ -12446,7 +12473,6 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
if (fromob) {
f = hasflag(fromob->flags, F_MERCIFUL);
if (f && (amt >= lf->hp)) {
amt = lf->hp - 1; // ie end up at 1hp
ko = B_TRUE;
if (fromob->pile->owner && cansee(player, fromob->pile->owner)) {
f->known = B_TRUE;
@ -12463,12 +12489,24 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
if ((lf->hp > 1) && (hpleftafterdam >= -5) && (hpleftafterdam <= 0)) {
if (onein(2)) {
ko = B_TRUE;
}
}
}
}
if (!ko) {
if (fromlf && lfhasflag(fromlf, F_STRIKETOKO)) {
if (cansee(fromlf, lf)) {
ko = B_TRUE;
}
}
}
// just knock them out.
if (ko) {
amt = lf->hp - 1; // ie end up at 1hp
}
}
}
}
}
// large damage will be stopped by a ring of miracles
if ((amt >= (lf->maxhp / 2)) && (amt >= 20)) {
@ -12648,8 +12686,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
}
// low hitpoint warning
if (amt > 0) {
if (isplayer(lf)) {
if (isplayer(lf) && (amt > 0)) {
int warnthresh;
warnthresh = (int)((float)0.25 * (float)lf->maxhp);
if ((lf->hp <= warnthresh) && (lf->hp > 0)) {
@ -12657,15 +12694,16 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
more();
}
}
}
if (ko) {
if (!isunconscious(lf)) {
// you are knocked unconscious for a _long_ time
fallasleep(lf, ST_KO, rnd(50,100));
if (fromlf && isplayer(fromlf)) {
pleasegodmaybe(R_GODMERCY, 5);
}
breakgrabs(lf, B_TRUE, B_FALSE);
}
} else {
// you wake up if you were hit, unless you were unconscious!
f = lfhasflag(lf, F_ASLEEP);
@ -13284,8 +13322,6 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume,
dist = getcelldist(l->cell, c);
// listen check difficulty is based on sound distance vs max hearing distance
if ((nclass == NC_SPEECH) && isplayer(l)) {
// you always hear it, as long as you're in range
@ -13296,7 +13332,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume,
difficulty = 9999;
} else {
//difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20);
difficulty = (int) ( ((float)getcelldist(l->cell, c) / ((float)gethearingrange(l) + volume)) * 14);
difficulty = (int) ( ((float) dist / ((float)gethearingrange(l) + volume)) * 14);
}
// listen bonus is based on sound volume
@ -15400,6 +15436,8 @@ int shoot(lifeform_t *lf) {
fireat(lf, ammo, 1, targ->cell, firespeed, gun);
if (!getammo(gun)) {
if (!isplayer(lf) || getoption(OPT_AUTORELOAD)) {
// automatically try to reload our empty firearm/ranged weapon.
if (loadfirearmfast(lf, B_FALSE)) {
if (isplayer(lf)) {
char obname[BUFLEN];
@ -15408,6 +15446,7 @@ int shoot(lifeform_t *lf) {
}
}
}
}
return B_FALSE;
}
@ -16650,7 +16689,7 @@ void startlfturn(lifeform_t *lf) {
// effects for/on your own flags
getflags(lf->flags, retflag, &nretflags, F_ATTACHEDTO, F_CANWILL, F_CHARMEDBY, F_CLIMBING, F_FEIGNFOOLEDBY,F_FLEEFROM,
F_GRABBEDBY, F_GRABBING, F_GUNTARGET, F_BOOSTSPELL, F_FEIGNINGDEATH, F_HPDRAIN, F_INJURY,
F_NOFLEEFROM, F_PETOF, F_SPOTTED, F_STABBEDBY, F_TARGETCELL, F_TARGETLF, F_NONE);
F_NOFLEEFROM, F_PETOF, F_SPOTTED, F_STABBEDBY, F_STRIKETOKO, F_TARGETCELL, F_TARGETLF, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
// remove impossible flags
@ -16752,6 +16791,15 @@ void startlfturn(lifeform_t *lf) {
}
}
if (f->id == F_STRIKETOKO) {
skill_t *sk;
sk = getobskill(getweapon(lf));
if (!sk || (sk->id != SK_CLUBS)) {
killflag(f);
continue;
}
}
// recharge abilities
if (f->id == F_CANWILL) {
if (f->val[2] != NA) {
@ -16760,6 +16808,7 @@ void startlfturn(lifeform_t *lf) {
}
}
}
// remove invalid targets
if ((f->id == F_TARGETLF) || (f->id == F_TARGETCELL)) {
lifeform_t *targ = NULL;

4
lf.h
View File

@ -40,6 +40,7 @@ int cancook(lifeform_t *lf, recipe_t *rec, enum ERROR *reason);
int canclimb(lifeform_t *lf, enum ERROR *reason);
int candrink(lifeform_t *lf, object_t *o);
int caneat(lifeform_t *lf, object_t *o);
int canhaverandombehaviour(lifeform_t *lf);
int canhear(lifeform_t *lf, cell_t *c, int volume);
int canlearn(lifeform_t *lf, enum SKILL skid);
int canmakerecipe(lifeform_t *lf, recipe_t *rec);
@ -165,6 +166,7 @@ int getleftrightwalls(lifeform_t *lf);
int getlfaccuracy(lifeform_t *lf, object_t *wep);
char getlfcol(lifeform_t *lf, enum MSGCHARCOL cc);
enum LFCONDITION getlfcondition(lifeform_t *lf);
int getflightsizemod(lifeform_t *lf);
enum SKILLLEVEL getmaxskilllevel(lifeform_t *lf, enum SKILL skid);
int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions);
int getmiscastchance(lifeform_t *lf);
@ -273,7 +275,7 @@ void loseobflags(lifeform_t *lf, object_t *o, int kind);
int hasbp(lifeform_t *lf, enum BODYPART bp);
flag_t *hasactivespell(lifeform_t *lf, enum OBTYPE sid);
int haslof(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest);
int haslof_real(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest, lifeform_t *srclf);
int haslof_real(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest, lifeform_t *srclf, int walllfsok);
int haslos(lifeform_t *viewer, cell_t *dest);
int haslosdark(lifeform_t *viewer, cell_t *dest);
int haslos_fast(lifeform_t *viewer, cell_t *dest);

53
map.c
View File

@ -1154,6 +1154,41 @@ void clearcell_exceptflags(cell_t *c, ... ) {
}
}
int damagecell(cell_t *c, int amt, enum DAMTYPE damtype) {
if (!c->type->solid) return B_TRUE;
// adjust dam
adjustdammaterial(&amt, damtype, c->type->material->id);
if (amt <= 0) return B_TRUE;
// wall loses hp
c->hp -= amt;
if (c->hp <= 0) {
char cellname[BUFLEN];
int shattered = B_FALSE;
enum MATERIAL cellmat;
c->hp = 0;
// remember cell properties
sprintf(cellname, "%s %s", needan(c->type->name) ? "An" : "A", c->type->name);
cellmat = c->type->material->id;
// cell dies (have to do this before calling fragments())
setcelltype(c, c->map->habitat->emptycelltype);
// announce
if (haslos(player, c)) {
msg("%s %s!", cellname, willshatter(cellmat) ? "shatters" : "is destroyed");
}
// shatter?
if (willshatter(cellmat)) {
char what[BUFLEN];
shattered = B_TRUE;
noise(c, NULL, NC_OTHER, SV_CAR, "something shattering.", NULL);
if (getshardobname(cellmat, what)) {
fragments(c, what, 3, 3);
}
}
}
return B_FALSE;
}
// returns true if something happened
int doelementspread(cell_t *c) {
float thisdepth;
@ -4707,11 +4742,12 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int
inrange = B_TRUE;
}
if (inrange) {
cell_t *stopcell = NULL;
//cell_t *stopcell = NULL;
// if a door stops the explosion, the door will
// take the damage.
haslof(c, cc, LOF_WALLSTOP, &stopcell);
explodesinglecell(stopcell, dam, killwalls, o, c);
//haslof(c, cc, LOF_WALLSTOP, &stopcell);
// don't check LOF for explosions.
explodesinglecell(cc, dam, killwalls, o, c);
}
}
}
@ -4789,10 +4825,7 @@ void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *c
if (killwalls) {
if (c->type->solid) {
// make it empty!
setcelltype(c, c->habitat->emptycelltype);
// add some rubble
addob(c->obpile, "10-50 stones");
damagecell(c, dam, DT_EXPLOSIVE);
}
}
}
@ -5010,11 +5043,11 @@ void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags)
}
// random monster behaviours
if (!isundead(lf) && !isgod(lf) && onein(4)) {
if (canhaverandombehaviour(lf) && onein(6)) {
switch (rnd(0,6)) {
case 0: // insane
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "insane");
addflag(lf->flags, F_HATESALL, B_TRUE, NA, NA, NULL);
addflag(lf->flags, F_TERRITORIAL, 2, NA, NA, NULL); // attack anything within 1 cells
break;
case 1: // hungry
addflag(lf->flags, F_BEHAVIOUR, NA, NA, NA, "hungry");
@ -5974,7 +6007,7 @@ void initmap(void) {
addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEDARK, C_BROWN, B_SOLID, B_OPAQUE, MT_STONE, 0, 50);
addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, B_SOLID, B_OPAQUE, MT_WOOD, 0, 50);
addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, B_SOLID, B_OPAQUE, MT_FLESH, 0, 50);
addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, B_SOLID, B_TRANS, MT_GLASS, 0, 150);
addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, B_SOLID, B_TRANS, MT_GLASS, 0, 25);
addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, B_SOLID, B_OPAQUE, MT_METAL, 0, 200);
// cell types - non-solid
addcelltype(CT_FAKE, "fake cell", '.', C_GREEN, B_EMPTY, B_TRANS, MT_STONE, 0, -1);

1
map.h
View File

@ -18,6 +18,7 @@ int cellisfixedvaultwall(cell_t *c);
int cellokforreachability(cell_t *startcell, cell_t *c, int srcroomid, int dir, int wantfilled, int *insameroom);
void clearcell(cell_t *c);
void clearcell_exceptflags(cell_t *c, ...);
int damagecell(cell_t *c, int amt, enum DAMTYPE damtype);
int doelementspread(cell_t *c);
int fix_reachability(map_t *m);
int fix_unreachable_cell(cell_t *badcell);

View File

@ -3062,7 +3062,7 @@ void explodeob(object_t *o, flag_t *f, int bigness) {
} else if (haslos(player, c)) {
msg("%s explode%s!", obname,OBS1(o));
}
explodecells(c, dam * o->amt, bigness ? B_TRUE : B_FALSE, o, bigness ? 1 : 0, DT_COMPASS, B_FALSE);
explodecells(c, dam * o->amt, bigness ? B_TRUE : B_FALSE, o, bigness , DT_ORTH, B_FALSE);
// object dies.
removeob(o, o->amt);
@ -7901,10 +7901,10 @@ void obdie(object_t *o) {
if (f) {
if (f->val[2] == B_IFACTIVATED) {
if (isactivated(o)) {
explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0);
explodeob(o, f, f->val[1]);
}
} else {
explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0);
explodeob(o, f, f->val[1]);
}
return;
}
@ -10828,6 +10828,8 @@ int sethiddenname(objecttype_t *ot, char *text) {
addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
} else if (strstr(text, "luminous")) {
addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
} else if (strstr(text, "sparkling")) {
addflag(ot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
}
// set colour based on hiddenname
@ -11360,7 +11362,7 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce) {
} else {
// explode
if ((f->val[0] == NA) || (f->val[0] == damtype)) {
explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0);
explodeob(o, f, f->val[1]);
return howmuch;
}
}
@ -11372,7 +11374,7 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce) {
} else {
if ((f->val[0] == NA) || (f->val[0] == damtype)) {
// explode
explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0);
explodeob(o, f, f->val[1]);
return howmuch;
}
}
@ -11888,7 +11890,17 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
}
}
if (db && thrower) {
dblog("%s is throwing %s - acc = %d, speed = %d\n", realthrowername, obname, acc, speed);
char fatext[BUFLEN];
if (firearm) {
char faname[BUFLEN];
getobname(firearm, faname, 1);
sprintf(fatext," (from %s)",faname);
} else {
strcpy(fatext,"");
}
dblog("%s is %s %s%s - acc = %d, speed = %d\n", realthrowername,
firearm ? "firing" : "throwing", obname, fatext, acc, speed);
}
// roll for hit
@ -12178,6 +12190,16 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
}
}
// if we were throwing at a lifeform inside a wall, we need to make sure we don't
// now place the object inside the wall.
if (where->type->solid) {
newloc = NULL;
haslof_real(srcloc, where, LOF_NEED, &newloc, NULL, B_FALSE);
if (newloc) {
where = newloc;
}
}
// move the object to the cell then take dam or kill it. don't stack.
newob = real_moveob(o, where->obpile, amt, B_FALSE);
// fake its birth time so that it can be damaged
@ -13062,12 +13084,18 @@ void turnon(lifeform_t *lf, object_t *o) {
addflag(newob->flags, F_ACTIVATED, B_TRUE, NA, NA, NULL);
getobname(newob, newobname, 1);
if (lf && isplayer(lf)) {
// announce.
if (held) {
msgnocap("%c - %s [activated].",newob->letter, newobname);
more();
// ask where to throw it
dothrow(NULL, newob);
} else {
msgnocap("You activate %s.",newob->letter, newobname);
}
}
o = newob;
} else {
if (isplayer(lf)) {
msg("You don't have room for an activated %s!",noprefix(obname));
@ -13671,6 +13699,7 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob
acc -= (cellpenalty*howfar);
// modify based on attributes
if (whichatt != A_NONE) {
int mod;
mod = getstatmod(thrower, whichatt); // -50 to 50
@ -13693,6 +13722,14 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob
if (where->lf && isprone(where->lf)) {
acc -= 30;
}
// 10% bonus for being higher than your target
if (where->lf) {
if (getflightsizemod(thrower) > getflightsizemod(where->lf)) {
acc += 15;
}
}
limit(&acc, 0, NA);
return acc;
}

14
spell.c
View File

@ -1893,6 +1893,20 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// now kill the scroll
msg("The scroll crumbles to dust.");
removeob(o, 1);
} else if (abilid == OT_A_STRIKETOKO) {
skill_t *sk;
sk = getobskill(getweapon(user));
if (!sk || (sk->id != SK_CLUBS)) {
if (isplayer(user)) msg("You can only use bashing weapons to fight mercifully.");
return B_TRUE;
}
if (lfhasflag(user, F_STRIKETOKO)) {
killflagsofid(user->flags, F_STRIKETOKO);
} else {
addflag(user->flags, F_STRIKETOKO, B_TRUE, NA, NA, NULL);
}
// note: takes no time.
} else if (abilid == OT_A_SUCKBLOOD) {
int dam = 0;

112
text.c
View File

@ -131,6 +131,7 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam
needfree = B_TRUE;
} else if (fatal) {
verb = getkillverb(victim, wep, damtype, dam, maxhp);
if (strstr(verb, "knock out") && !isplayer(victim)) knownnodam = B_TRUE;
} else {
if (!victim || // atacking an object
(getlorelevel(lf, victim->race->raceclass->id) >= PR_BEGINNER) || // know about the race
@ -682,6 +683,21 @@ void getdisttext(cell_t *src, cell_t *dst,char *distbuf, char *distbufapprox, ch
}
char *getflagsourcetext(flag_t *f) {
switch (f->lifetime) {
case FROMSKILL: return " (skill perk)";
case FROMJOB: return " (job perk)";
case FROMOBEQUIP:
case FROMOBHOLD:
case FROMOBACTIVATE:
return " (conferred perk)";
case FROMGODGIFT:
return " (god gift)";
default: break;
}
return "";
}
int gethitconferlifetime(char *text, int *min, int *max) {
int howlong;
int localmin = -1,localmax = -1;
@ -721,7 +737,9 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d
if (wep && hasflag(wep->flags, F_MERCIFUL)) {
return "knock out";
}
if (wep && wep->pile->owner && lfhasflag(wep->pile->owner, F_STRIKETOKO)) {
return "knock out";
}
if (victim->race->id == R_DANCINGWEAPON) {
return "defeat";
}
@ -942,6 +960,98 @@ char *getobmodprefix(object_t *o, obmod_t *om) {
default: return "rotted ";
}
}
} else if (isweapon(o)) {
flag_t *f = NULL;
skill_t *sk;
sk = getobskill(o);
if (sk) {
if (om->id == OM_MASTERWORK) {
switch (sk->id) {
case SK_CLUBS:
case SK_STAVES:
return "reinforced ";
default: break;
}
} else if (om->id == OM_SHODDY) {
switch (sk->id) {
case SK_LONGBLADES:
case SK_SHORTBLADES:
case SK_AXES:
return "blunted ";
case SK_CLUBS:
return "cracked ";
case SK_POLEARMS:
return "notched ";
case SK_STAVES:
return "blunted ";
default: break;
}
}
}
if (f) return f->text;
} else if (isshield(o)) {
if (om->id == OM_MASTERWORK) {
switch (o->material->id) {
case MT_LEATHER:
return "studded ";
case MT_METAL:
case MT_WOOD:
case MT_DRAGONWOOD:
return "reinforced ";
default: break;
}
} else if (om->id == OM_SHODDY) {
switch (o->material->id) {
case MT_LEATHER:
case MT_RUBBER:
case MT_PAPER:
return "torn ";
case MT_CLOTH:
case MT_SILK:
return "frayed ";
case MT_GLASS:
case MT_STONE:
case MT_BONE:
return "chipped ";
case MT_METAL:
return "dented ";
case MT_WOOD:
case MT_DRAGONWOOD:
return "splintered ";
default: break;
}
}
} else if (isarmour(o)) {
if (om->id == OM_MASTERWORK) {
switch (o->material->id) {
case MT_LEATHER:
return "studded ";
case MT_CLOTH:
case MT_SILK:
return "tailored ";
default: break;
}
} else if (om->id == OM_SHODDY) {
switch (o->material->id) {
case MT_LEATHER:
case MT_RUBBER:
case MT_PAPER:
return "torn ";
case MT_CLOTH:
case MT_SILK:
return "frayed ";
case MT_GLASS:
case MT_STONE:
case MT_BONE:
return "chipped ";
case MT_METAL:
return "dented ";
case MT_WOOD:
case MT_DRAGONWOOD:
return "splintered ";
default: break;
}
}
}
return om->prefix;
}

1
text.h
View File

@ -16,6 +16,7 @@ char *getattrname(enum ATTRIB att);
char *getdirname(int dir);
char *getdirnameshort(int dir);
void getdisttext(cell_t *src, cell_t *dst,char *distbuf, char *distbufapprox, char *dirbuf);
char *getflagsourcetext(flag_t *f);
int gethitconferlifetime(char *text, int *min, int *max);
char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp);
char *getpoisondamverb(enum POISONTYPE ptype);

View File

@ -14,7 +14,7 @@ p:cell:shop floor
+:cell:dirt
+:ob:wooden door
s:ob:sign "Village Pub"
f:ob:fireplace
f:ob:brazier
@end
@flags