- [+] chat->all allies command.

- [+] replace 'step carefully' key to free up 's' - OT_A_TIPTOE
    - [+] 's' = 'shut door' (replace 'c')
    - [+] 'c' = 'chat to single'
    - [+] rewrite docomms() to use other funcs
    - [+] 'C' = 'command all allies'
        - [+] only possible for single person:
            - [+] 'o' donate
            - [+] 'i' tell me about this area
            - [+] 'j' join me
            - [+] 'k' trade knowledge
            - [+] 'm' mercy
            - [+] 't' trade
            - [+] 'x' dangers nearby?
        - [+] make a list of all commands which are valid for EVERYONE
        - [+] send command to everyone.
        - [+] docommslf()
    - [+] test with single target
    - [+] test with multiple targets
- [+] hitconfer lifetime for wight/contagion zombie should only happen
      on fatal hits
- [+] makezombie() should be able to call petify()
- [+] bug: mosnters never using HIDE ability.
- [+] monsters which pretend to be objects (ie. gargoyle)
    - [+] F_ISMONSTER v0=raceid v1=objectid, v2 = spot check difficulty
    - [+] when generating, add contents->first as objectid v1
    - [+] getobname -> if you have f_mosnters, use contents->first
    - [+] getobdesc -> if you have f_mosnters, use contents->first
    - [+] mosnters won't walk onto it
    - [+] if you are next to them and can't see them... reveal then
          attack!
    - [+] F_ISMONSTER - must always be impassable to everyone!!!
    - [+] if you try to walk onto it:
        - [+] "the xxx starts to move!"
        - [+] kill ob
        - [+] add lf
        - [+] they get a free attack
    - [+] if it takes damage
        - [+] ... convert.
    - [+] spot checks to see them.
        - [+] ...convert.
    - [+] F_PRETENDSTOBE - mosnters will revert if unseen.
    - [+] reveal hidden should show them.
- [+] gargoyle
    - [+] stone statues
    - [+] winged
    - [+] large
    - [+] ~37hp
    - [+] start off as an obejct
- [+] wight
    - [+] rare.
    - [+] ~26 hp ...TR5
    - [+] silent move
    - [+] dr4 attack (low damage) but....
    - [+] any humans killed rise as a wight .
        - [+]  (hitconfer revive).  how can i limit hitconfer to a
              race? maybe f_hitconferrace
        - [+] bones file
        - [+] tested ok.
    - [+] 1 leveldrain per hit
        - [+] skillcheck to avoid
        - [+] wight gains +5 hp
This commit is contained in:
Rob Pearce 2012-12-04 05:15:27 +00:00
parent ae01d1bbfa
commit 234d70b099
17 changed files with 856 additions and 374 deletions

107
ai.c
View File

@ -1336,7 +1336,7 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) {
// need to train skills?
if (!enraged) {
if (readytotrain(lf) && safetorest(lf)) {
if (readytotrain(lf) && safetorest(lf, NULL)) {
// special case - monsters don't need to actually rest to gain
// skills, although they DO still need to wait until the player
// is out of sight.
@ -1375,11 +1375,44 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) {
///////////////////////////////////////////////
if (!enraged) {
// hide?
if (!ispetof(lf, player) && cancast(lf, OT_A_HIDE, NULL) && aispellok(lf, OT_A_HIDE, lf, F_AICASTTOFLEE)) {
if (db) dblog(".oO { trying to hide. }");
if (!useability(lf, OT_A_HIDE, lf, lf->cell)) {
if (db) dblog(".oO { success! }");
return B_TRUE;
}
}
// need to heal?
if (needstorest(lf, NULL) && safetorest(lf) && !hasflag(lf->flags, F_RAGE)) {
if (db) dblog(".oO { resting to heal }");
rest(lf, B_TRUE);
return B_TRUE;
if (needstorest(lf, NULL) && !hasflag(lf->flags, F_RAGE)) {
enum ERROR why;
if (safetorest(lf, &why) || (why == E_TOOSOON)) {
if (db) dblog(".oO { resting to heal }");
rest(lf, B_TRUE);
return B_TRUE;
}
}
// pretending to be an object? revert.
f = lfhasflag(lf, F_PRETENDSTOBE);
if (f) {
if (safetorest(lf, NULL)) {
object_t *oo;
oo = addobfast(lf->cell->obpile, f->val[0]);
if (oo) {
killflagsofid(oo->flags, F_SIZE);
addflag(oo->flags, F_SIZE, getlfsize(lf), NA, NA, NULL);
// replace contents object
if (oo->contents->first && strlen(f->text)) {
killob(oo->contents->first);
addob(oo->contents, f->text);
}
// kill original monster
addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
addflag(lf->flags, F_XPVAL, 0, NA, NA, NULL);
lf->hp = 0;
}
}
}
}
@ -1507,7 +1540,7 @@ int ai_healing(lifeform_t *lf) {
}
// feigning death with enemies in sight, and hurt?
if (lfhasflag(lf, F_FEIGNINGDEATH) && !safetorest(lf)) {
if (lfhasflag(lf, F_FEIGNINGDEATH) && !safetorest(lf, NULL)) {
if (islowhp(lf)) {
if (db) dblog(".oO { i am feigning death and bleeding (hp=%d/%d), skipping turn. }",lf->hp,lf->maxhp);
// just wait...
@ -1532,7 +1565,7 @@ int ai_healing(lifeform_t *lf) {
} else if (cansleep(lf)) {
// don't have or can't use our healing items
// no enemies in sight?
if (safetorest(lf)) {
if (safetorest(lf, NULL)) {
// gods will only sleep/meditate if they are in the realm of gods
if (isgod(lf) && (lf->cell->habitat->id != H_HEAVEN)) {
} else {
@ -1898,15 +1931,41 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
if (cansee(lf, target)) {
int dist,wantdistmin,wantdistmax;
int attackok;
flag_t *f;
enum OBTYPE spell;
object_t *rangedob = NULL;
enum RANGEATTACK rangedattack = RA_NONE;
int shootrange = 0;
int movefailed = B_FALSE;
int closethrowok = B_FALSE;
object_t *rangedob = NULL;
int spellchance = 0;
if (db) dblog(".oO { can see my target }");
// see if we have a ranged attack. if so, adjust wantdist
// to maintain distance.
rangedob = aigetrangedattack(lf, target, &rangedattack, &shootrange);
// try spells first.
// can we attack with spells (ie. ones which target the victim)?
// if target is adjacent, we will normally just attack rather than try a spell.
// random chance of casting a spell
f = lfhasflag(lf, F_CASTCHANCE);
if (f) spellchance = f->val[0];
else spellchance = 30;
// some attacks can always happen
if (cancast(lf, OT_A_THRUST, NULL) && (dist == 2) && haslofknown(lf->cell, target->cell, LOF_NEED, NULL)) {
spellchance = 100;
}
if (pctchance(spellchance)) {
spell = aigetattackspell(lf, target);
} else {
spell = OT_NONE;
}
// pet movement
if (ismaster) {
if (isresting(target)) {
@ -1943,7 +2002,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
if (wantattack) {
if (dist == 1) {
attackok = B_TRUE;
} else if (!lfhasflag(lf, F_HIDING)) {
} else if (!lfhasflag(lf, F_HIDING) || rangedob || (spell != OT_NONE)) {
attackok = B_TRUE;
} else if (!lfhasflag(lf, F_FEIGNINGDEATH)) {
attackok = B_TRUE;
@ -1952,33 +2011,12 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
if (attackok) {
objecttype_t *st;
flag_t *f;
int spellchance = 0;
// drink boost potions
if (!useitemwithflag(lf, F_AIBOOSTITEM)) {
return B_FALSE;
}
// try spells first.
// can we attack with spells (ie. ones which target the victim)?
// if target is adjacent, we will normally just attack rather than try a spell.
// random chance of casting a spell
f = lfhasflag(lf, F_CASTCHANCE);
if (f) spellchance = f->val[0];
else spellchance = 30;
// some attacks can always happen
if (cancast(lf, OT_A_THRUST, NULL) && (dist == 2) && haslofknown(lf->cell, target->cell, LOF_NEED, NULL)) {
spellchance = 100;
}
if (pctchance(spellchance)) {
spell = aigetattackspell(lf, target);
} else {
spell = OT_NONE;
}
st = findot(spell);
if ( (spell != OT_NONE) && // found a valid spell/ability to use
// AND one of these:
((dist != 1) || // there is distance between us and target
@ -2065,10 +2103,6 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
}
}
// see if we have a ranged attack. if so, adjust wantdist
// to maintain distance.
rangedob = aigetrangedattack(lf, target, &rangedattack, &shootrange);
// for firearms/projectiles, chance to fire/throw depends on accuracy.
if ((rangedattack == RA_GUN) || (rangedattack == RA_THROW)) {
int chance;
@ -3057,11 +3091,12 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
}
}
if (ot->id == OT_A_HIDE) {
enum ERROR why;
if (lfhasflag(lf, F_HIDING)) {
specificcheckok = B_FALSE;
} else if (lfhasflag(lf, F_FEIGNINGDEATH)) {
specificcheckok = B_FALSE;
} else if (!safetorest(lf)) {
} else if (!safetorest(lf, &why) && (why != E_TOOSOON)) {
specificcheckok = B_FALSE;
} else if (lfproduceslight(lf, NULL)) {
specificcheckok = B_FALSE;

View File

@ -1621,11 +1621,14 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
makewet(wep, 1);
}
// special weapon effects, as long as you're not doing a heavy blow
if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) {
// confer flags from weapon
wepeffects(wep->flags, victim->cell, damflag, dam[0], isunarmed);
// confer flags from attacker themselves
wepeffects(lf->flags, victim->cell, damflag, dam[0], isunarmed);
}
if (!isdead(victim) && !blocked && !dodged) {
// special weapon effects, as long as you're not doing a heavy blow
if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) {
wepeffects(wep->flags, victim->cell, damflag, dam[0], isunarmed);
}
f = lfhasflag(lf, F_FREEZINGTOUCH);
if (f) {
int diff;
@ -1646,10 +1649,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
criticalhit(lf, victim, critpos, wep, dam[0], damtype[0]);
}
// confer flags from attacker?
if (dam[0]) {
wepeffects(lf->flags, victim->cell, damflag, dam[0], isunarmed);
}
// special lifeform-based effects
if ((lf->race->id == R_COCKATRICE) && dam[0]) {
@ -3306,18 +3305,25 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isu
}
}
getflags(fp, retflag, &nretflags, F_AUTOTANGLE, F_FLAMESTRIKE, F_HEAVYBLOW, F_HITCONFER, F_RACESLAY, F_REVENGE, F_RUSTED, F_NONE);
getflags(fp, retflag, &nretflags, F_AUTOTANGLE, F_DRAINONHIT, F_FLAMESTRIKE, F_HEAVYBLOW, F_HITCONFER,
F_RACESLAY, F_REVENGE, F_RUSTED, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->id == F_AUTOTANGLE) {
if ((f->id == F_AUTOTANGLE) && victim && !isdead(victim)) {
if (pctchance(f->val[0]) && !hasob(where->obpile, OT_VINE)) {
dospelleffects(owner, OT_S_ENTANGLE, f->val[1], victim, NULL, where, B_UNCURSED,
NULL, B_FALSE, NULL);
f->known = B_KNOWN;
}
} else if ((f->id == F_DRAINONHIT) && victim && !isdead(victim)) {
if (!leveldrain(victim, f->val[0], f->val[1], f->val[2], owner)) {
if (strlen(f->text)) {
gainhp(owner, roll(f->text));
}
}
} else if (f->id == F_FLAMESTRIKE) {
if (!hasob(where->obpile, OT_FIRESMALL)) {
// ignite!
// ignite
addobfast(where->obpile, OT_FIRESMALL);
// announce
if (haslos(player, where)) {
@ -3412,6 +3418,18 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isu
continue;
}
// sometimes we can only hitconfer against certain races
if (hasflag(fp, F_HITCONFERRC)) {
if (!hasflagval(fp, F_HITCONFERRC, getraceclass(victim), NA, NA, NULL)) {
continue;
}
}
if (hasflag(fp, F_HITCONFERDEADONLY)) {
if (!isdead(victim)) {
continue;
}
}
// the f_poisoned flag stacks, others don't.
if (!lfhasflag(victim, fid) || (fid == F_POISONED)) {
int passedcheck = B_FALSE;
@ -3482,7 +3500,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isu
addflag(owner->flags, F_USEDPOISON, B_TRUE, NA, NA, NULL);
}
}
} else if ((f->id == F_RUSTED) && victim ) {
} else if ((f->id == F_RUSTED) && victim && !isdead(victim) ) {
int pct;
pct = f->val[0] * 10;
if (pctchance(pct)) {

118
data.c
View File

@ -177,8 +177,9 @@ void initcommands(void) {
addcommand(CMD_AGAIN, 'g', "Repeat last action.");
addcommand(CMD_REST, '.', "Rest once.");
addcommand(CMD_PICKUP, ',', "Pick up something from the ground.");
addcommand(CMD_CLOSE, 'c', "Close a door.");
addcommand(CMD_COMMS, 'C', "Chat/Communicate with someone.");
addcommand(CMD_COMMS, 'c', "Chat/Communicate with someone.");
addcommand(CMD_COMMSALL, 'C', "Command all allies.");
//addcommand(CMD_COMMS, 'C', "Chat/Communicate with someone.");
//addcommand(CMD_DROP, 'd', "Drop an item.");
addcommand(CMD_DROPMULTI, 'd', "Drop one or more items.");
addcommand(CMD_EAT, 'e', "Eat something.");
@ -190,7 +191,7 @@ void initcommands(void) {
addcommand(CMD_QUAFF, 'q', "Quaff (drink) a potion.");
addcommand(CMD_READ, 'r', "Read a scroll/book.");
addcommand(CMD_RESTFULL, 'R', "Rest until healed, or train your skills.");
addcommand(CMD_SLOWWALK, 's', "Step carefully.");
addcommand(CMD_CLOSE, 's', "Shut a door.");
addcommand(CMD_THROW, 't', "Throw an object.");
addcommand(CMD_TAKEOFF, 'T', "Take off an item of clothing/jewelery.");
addcommand(CMD_WEILD, 'w', "Weild a weapon.");
@ -2138,7 +2139,7 @@ void initobjects(void) {
addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addoc(OC_FLORA, "Plants", "Some kind of plant/foliage.", ',', C_GREEN, RR_FREQUENT);
addocnoun(lastobjectclass, "plant");
addoc(OC_ROCK, "Rocks/Gems", "Boring (or not so boring) rocks or plants.", '*', C_GREY, RR_FREQUENT);
addoc(OC_ROCK, "Rocks/Gems", "Boring (or not so boring) rocks or plants.", '*', C_STONE, RR_FREQUENT);
addoc(OC_FOOD, "Food", "Yum!", '%', C_GREY, RR_FREQUENT);
addocnoun(lastobjectclass, "food");
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, "");
@ -2822,6 +2823,15 @@ void initobjects(void) {
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL);
// traps - hiding monsters
addot(OT_GARGOYLE, "gargoyle", "A sneaky hidden gargoyle!", MT_STONE, 80, OC_TRAP, SZ_HUMAN);
addflag(lastot->flags, F_GLYPH, C_STONE, '\'', NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ISMONSTER, R_GARGOYLE, OT_STATUE, 140, "3"); // reveal if within 3 cells
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
// traps - object only
addot(OT_TRAPNEEDLEP, "poison needle trap", "A springed needle coated with poison.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL);
@ -2991,7 +3001,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_FOREST, NA, RR_RARE, "");
addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_ICECAVE, NA, RR_COMMON, NULL);
addflag(lastot->flags, F_GLYPH, NA, '\'', NA, NULL);
addflag(lastot->flags, F_GLYPH, C_STONE, '\'', NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL); // will be overridden
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
@ -5903,6 +5913,8 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 2, NA, NA, NULL);
addot(OT_A_TIPTOE, "tiptoe", "Walk carefully to avoid obstacles or slippery floors.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_TRIPLF, "trip", "Attempt to trip your opponent over.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_STAMCOST, 2, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
@ -6857,7 +6869,6 @@ void initobjects(void) {
// tech - l6 ???
// misc
addot(OT_TUSK, "ivory tusk", "A large ivory tusk from a slain elephant. Could be used as weapon by very large creatures.", MT_BONE, 61, OC_MISC, SZ_HUMAN);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_VALUE, 450, NA, NA, NULL);
@ -12514,6 +12525,47 @@ void initrace(void) {
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL);
addrace(R_GARGOYLE, "gargoyle", 220, '\'', C_STONE, MT_STONE, RC_MAGIC, "Gargoyles are winged statues which have been imbued with magical life. These evil creatures delight in tricking unsuspecting adventurers by pretending to be ordinary statues.");
setbodytype(lastrace, BT_HUMANOID);
addbodypart(lastrace, BP_TAIL, NULL);
addbodypart(lastrace, BP_WINGS, NULL);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_GETKILLEDVERB, NA, NA, NA, "defeat");
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_RARITY, H_MASTERVAULTS, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 7, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_VHIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VLOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_EXHIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_NATURALFLIGHT, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_CANWILL, OT_A_FLY, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_A_FLY, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 6, NA, NULL);
addflag(lastrace->flags, F_MAXATTACKS, 3, 3, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOBREATH, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOSTAM, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOTAKECRITS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NONAUSEA, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, NA, NA, NULL);
addflag(lastrace->flags, F_SWOOPRANGE, 3, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_FLIGHT, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_PRETENDSTOBE, OT_GARGOYLE, NA, NA, NULL);
addrace(R_GIANTHILL, "mountain giant", 160, 'H', C_GREY, MT_FLESH, RC_HUMANOID, "Enormous humanoids who dwell in the mountains, using their grat strength to leap between valleys and pelt their prey with enormous boulders.");
setbodytype(lastrace, BT_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -12897,6 +12949,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTHIDDENPCT, 75, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 2, NA, NA, NULL);
addflag(lastrace->flags, F_ATTACKRANGE, 2, 5, NA, NULL); // maintain distance
@ -19038,6 +19091,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "screechs^an other-wordly screech");
// undead
addrace(R_ZOMBIE, "zombie", 50, 'Z', C_BLUE, MT_FLESH, RC_UNDEAD, "The re-animated corpse of a once living entity, zombies seek to consume the brains of living creatures in an attempt to regain their soul.");
setbodytype(lastrace, BT_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -19074,7 +19128,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "groans^a gutteral groan");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "gurgles^a gurgle");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "growls^a growl");
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
@ -19107,6 +19160,9 @@ void initrace(void) {
addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL);
addflag(lastrace->flags, F_HITCONFER, F_REVIVETIMER, NA, 0, NULL);
addflag(lastrace->flags, F_HITCONFERVALS, 0, 1, R_ZOMBIECON, "rises up as a zombie");
addflag(lastrace->flags, F_HITCONFERDEADONLY, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RANDOMTALKPCT, 20, NA, NA, NULL);
@ -19116,10 +19172,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "groans^a gutteral groan");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "gurgles^a gurgle");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "growls^a growl");
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_HITCONFER, F_REVIVETIMER, SC_POISON, 165, NULL);
addflag(lastrace->flags, F_HITCONFERVALS, 0, 1, R_ZOMBIECON, "rises up as a zombie");
addrace(R_SKELETON, "skeleton", 20, 'Z', C_BONE, MT_BONE, RC_UNDEAD, "A walking set of bones, animated through the use of necromancy. Due to their lack of soft flesh, they have little to fear from edged weapons.");
setbodytype(lastrace, BT_HUMANOID);
@ -19161,7 +19214,6 @@ void initrace(void) {
addflag(lastrace->flags, F_DTVULN, DT_FALL, NA, NA, "1d3+3");
addflag(lastrace->flags, F_DTRESIST, DT_PIERCE, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_FOLLOWTIME, 0, NA, NA, NULL);
@ -19202,7 +19254,6 @@ void initrace(void) {
addflag(lastrace->flags, F_DTVULN, DT_FALL, NA, NA, "1d3+3");
addflag(lastrace->flags, F_DTRESIST, DT_PIERCE, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addrace(R_SKELLION, "skellion", 10, 'r', C_RED, MT_BONE, RC_UNDEAD, "A floating skull, immersed in flames. Skellions are often created when attempting to animate a beheaded corpse.");
@ -19236,6 +19287,36 @@ void initrace(void) {
addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_FOLLOWTIME, 10, NA, NA, NULL);
addrace(R_WIGHT, "wight", 50, 'Z', C_LIGHTBLUE, MT_FLESH, RC_UNDEAD, "A twisted and misshappen creature of evil, vague recognisable as humanoid.");
setbodytype(lastrace, BT_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_NOSTAIRS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 5, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TOUCHNECROTIC, 4, NA, NULL);
addflag(lastrace->flags, F_HITCONFER, F_REVIVETIMER, NA, 0, NULL);
addflag(lastrace->flags, F_HITCONFERVALS, 0, 1, R_WIGHT, "rises up as a wight");
addflag(lastrace->flags, F_HITCONFERRC, RC_HUMANOID, NA, NA, NULL);
addflag(lastrace->flags, F_HITCONFERDEADONLY, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DRAINONHIT, 1, SC_CON, 100, "1d0+5");
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addrace(R_WRAITHBOG, "bog wraith", 20, 'Z', C_BROWN, MT_PLANT, RC_UNDEAD, "Bog wraiths take the form of vaguely humanoid blobs of putrid mud.");
setbodytype(lastrace, BT_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -19264,7 +19345,6 @@ void initrace(void) {
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "undulates");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "screeches^a screech");
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
@ -19335,7 +19415,6 @@ void initrace(void) {
addflag(lastrace->flags, F_INDUCEFEAR, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL);
@ -19366,7 +19445,6 @@ void initrace(void) {
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addrace(R_GHOST, "ghost", 50, 'p', C_GREY, MT_FLESH, RC_UNDEAD, "Wispy spirits formed when a soul refuses to depart the earthly realm after death, ghosts exist part way between dimensions. The sight of a ghost can cause fear in all who behold it, and their ethereal nature makes them immune to most attacks."); // p for sPirit
@ -19438,7 +19516,6 @@ void initrace(void) {
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
@ -19507,7 +19584,6 @@ void initrace(void) {
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_FOLLOWTIME, 30, NA, NA, NULL);
@ -19548,11 +19624,10 @@ void initrace(void) {
addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_FOLLOWTIME, 50, NA, NA, NULL);
addrace(R_REVENANT, "revenant", 60, 'Z', C_LIGHTBLUE, MT_FLESH, RC_UNDEAD, "A powerful zombie which retains full memory of its former life and abilities.");
addrace(R_REVENANT, "revenant", 60, 'Z', C_MAGENTA, MT_FLESH, RC_UNDEAD, "A powerful zombie which retains full memory of its former life and abilities.");
setbodytype(lastrace, BT_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL);
@ -19855,7 +19930,6 @@ void initrace(void) {
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL);
@ -19886,7 +19960,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL);
@ -19917,7 +19990,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL);
@ -19941,7 +20013,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL);
@ -20087,6 +20158,7 @@ void initrace(void) {
addflag(r->flags, F_NORESTHEAL, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_NOSTAM, B_TRUE, NA, NA, NULL);
addflag(r->flags, F_NONAUSEA, B_TRUE, NA, NA, NULL);
// +/- 15 accuracy during day/night
addflag(r->flags, F_NIGHTBOOST, 15, NA, NA, NULL);
addflag(r->flags, F_DAYBOOST, -15, NA, NA, NULL);

35
defs.h
View File

@ -111,6 +111,9 @@
#define B_BLINDABLE (-1)
#define B_ALLOWEXTRA (-1)
#define B_NOEXTRA (0)
#define B_ADD 1
#define B_REMOVE -1
@ -709,6 +712,7 @@ enum COLOUR {
C_CARPET1,
C_CARPET2,
C_SMOKE,
C_STONE,
C_WOOD,
// dark colours
C_DARKCYAN,
@ -1295,6 +1299,7 @@ enum RACE {
R_DRYAD,
R_EFREETI,
R_EYEBAT,
R_GARGOYLE,
R_GIANTHILL,
R_GIANTFIRE,
R_GIANTFIREFC,
@ -1512,6 +1517,7 @@ enum RACE {
R_SKELETONFIRE,
R_SKELLION,
R_VAMPIRE,
R_WIGHT,
R_WRAITHBOG,
R_WRAITHICE,
R_ZOMBIE,
@ -1717,6 +1723,8 @@ enum OBTYPE {
OT_TRAPTELEPORT,
OT_TRAPTRIP,
OT_TRAPWIND,
// traps - hiding monsters
OT_GARGOYLE,
// rocks
OT_ASH,
OT_ASHLARGE,
@ -2177,6 +2185,7 @@ enum OBTYPE {
OT_A_SUCKBLOOD,
OT_A_SWALLOW,
OT_A_SWOOP,
OT_A_TIPTOE,
OT_A_TRIPLF, // trip an opponent
OT_A_EMPLOY,
OT_A_EXPOSEDSTRIKE,
@ -2960,6 +2969,15 @@ enum FLAG {
F_CORPSEOF, // this is a corpse of montype val0.
// v1 is its level when it died
// text is how it died.
F_ISMONSTER, // this object is really a mosnter staying still to
// trick you!
// v0 = race id of monster
// v1 = object id to hide as
// v2 = spot check difficulty (or NA)
// text = reveal ourselves if prey <= this distance
//
// Also see: F_PRETENDSTOBE
F_REVIVETIMER, // v0 = cur, v1 = max. v0 incremenets each tick.
// when v0 == v1, this object changes into lf of race
// v2.
@ -2998,6 +3016,10 @@ enum FLAG {
// text
F_CRITKNOCKDOWN, // lf knocks down victims on a critical hit
F_DRAINONHIT, // victims hit by this lf get v0 xplevs drained unless
// they pass a skillcheck of type v1, diff v2.
// v1 can be NA.
// if successful, lf gains 'text' hp (in dice format)
F_HITCONFER, // hitting with this gives flagid=v0
// with timeleft = text ("min-max"
// or NULL for permenant)
@ -3005,6 +3027,9 @@ enum FLAG {
// if val1 = NA, no check.
// MUST ALSO HAVE HITCONFERVALS.
F_HITCONFERVALS,// specifies values for conferred flag.
F_HITCONFERRC, // hitconfer only works against victims of raceclass
// v0
F_HITCONFERDEADONLY, // hitconfer only works on fatal hits
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.
@ -4139,6 +4164,13 @@ enum FLAG {
F_PARALYZED,// cannot do anything
F_PARANOIA, // mosnters randomly appear out of sight, or random
// noises happen from behind you.
F_PRETENDSTOBE, // this lf will pretend to be object v0.
// when bored, revert to an ob of type v0.
//
// if 'text' is set, then v0's contents object
// should be this.
//
// Also see: F_ISMONSTER
F_PRONE, // lying on the ground
F_FROZEN, // made of ice
F_HEAVENARM, // prevent the next v0 damage received.
@ -4469,6 +4501,7 @@ enum ERROR {
E_OBINWAY,
E_TOOHEAVY,
E_TOOHARD,
E_TOOSOON,
E_NOHANDS,
E_NOPACK,
E_INSUBSTANTIAL,
@ -4565,6 +4598,7 @@ enum COMMAND {
CMD_AIM,
CMD_CLOSE,
CMD_COMMS,
CMD_COMMSALL,
CMD_DOWN,
CMD_DROP,
CMD_DROPMULTI,
@ -4597,7 +4631,6 @@ enum COMMAND {
CMD_REST,
CMD_RESTFULL,
CMD_SAVEQUIT,
CMD_SLOWWALK,
CMD_TAKEOFF,
CMD_THROW,
CMD_UP,

2
god.c
View File

@ -737,7 +737,7 @@ void dooffer(void) {
if ((god->race->id == R_GODNATURE) &&
(o->type->obclass->id == OC_FLORA) &&
newcell) {
addmonster(player->cell, R_BUTTERFLY, NULL, B_FALSE, 1, B_FALSE, NULL);
addmonster(player->cell, R_BUTTERFLY, NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
}
if (o->type->obclass->id == OC_FLORA) {

349
io.c
View File

@ -4441,160 +4441,30 @@ void doclose(void) {
}
}
void docomms(lifeform_t *lf) {
cell_t *where = NULL;
int i;
int askforob = B_FALSE;
void docommslf(lifeform_t *lf, char ch, lifeform_t *lf2, cell_t *targc) {
char lfname[BUFLEN], lfname2[BUFLEN];
char buf[BUFLEN];
char lfname[BUFLEN];
char ch;
//int moneyowing = 0;
enum ATTRBRACKET iqb;
flag_t *f;
cell_t *c;
lifeform_t *lf2 = NULL;
char lfname2[BUFLEN];
char buf2[BUFLEN];
int count;
int alignmod = 0;
cell_t *c;
flag_t *f;
object_t *o, *givenob = NULL;
object_t *godstone = NULL;
if (!lf) {
where = askcoords("Talk to who?", "Talk->", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf && cansee(player, where->lf)) {
lf = where->lf;
}
}
if (!lf) {
msg("Cancelled.");
return;
}
int i;
int askforob = B_FALSE;
alignmod = getalignmod(lf);
getlfname(lf, lfname);
snprintf(buf, BUFLEN, "What will you say to %s?",lfname);
initprompt(&prompt, buf);
prompt.maycancel = B_TRUE;
iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
// are they friendly?
if (ispetof(lf, player)) {
if ((iqb >= IQ_ANIMAL) || isundead(lf)) {
addchoice(&prompt, 'a', "Attack something", NULL, NULL, NULL);
}
if (!isadjacent(lf->cell, player->cell)) {
addchoice(&prompt, 'c', "Come here", NULL, NULL, NULL);
}
addchoice(&prompt, 'g', "Go somewhere", NULL, NULL, NULL);
if (isadjacent(lf->cell, player->cell) && !lfhasflag(lf, F_NOPACK)) {
addchoice(&prompt, 't', "Trade items with me", NULL, NULL, NULL);
}
if (iqb >= IQ_ANIMAL) {
f = isresting(lf);
if (f) {
addchoice(&prompt, 'r', "Stop resting.", NULL, NULL, NULL);
} else {
addchoice(&prompt, 'r', "Rest until you are healed.", NULL, NULL, NULL);
}
addchoice(&prompt, '<', "Stay close.", NULL, NULL, NULL);
addchoice(&prompt, '>', "Keep your distance.", NULL, NULL, NULL);
}
} else if (ishirable(lf) ) {
if (lfhasflag(lf, F_ISPRISONER)) {
addchoice(&prompt, 'j', "Join me, and I will help you escape.", NULL, NULL, NULL);
} else if (getskill(player, SK_SPEECH) >= PR_EXPERT) {
addchoice(&prompt, 'j', "Join me on my quest!", NULL, NULL, NULL);
}
}
if (!isgod(lf) && ispeaceful(lf) && cantalk(lf)) {
enum SKILLLEVEL slev;
job_t *j;
slev = getskill(player, SK_SPEECH);
// same race or job?
j = getjob(player);
if ((slev != PR_MASTER) && j && (j == getjob(lf))) slev++;
if ((slev != PR_MASTER) && (player->race->id == lf->race->id)) slev++;
if (slev >= PR_NOVICE) {
addchoice(&prompt, 'x', "Any dangers nearby that I should look out for?", NULL, NULL, NULL);
}
if (slev >= PR_BEGINNER) {
addchoice(&prompt, 'i', "What can you tell me about this area?", NULL, NULL, NULL);
}
if (!areallies(player, lf)) {
if (slev >= PR_SKILLED) {
addchoice(&prompt, 'k', "Care to trade knowledge?", NULL, NULL, NULL);
}
}
}
if (isadjacent(lf->cell, player->cell)) {
if (areenemies(player, lf)) {
addchoice(&prompt, 'm', "Have mercy!", NULL, NULL, NULL);
}
// if you are allies, use 'trade items' instead
if (!areallies(player, lf)) {
if (isgod(lf)) {
// may only donate the godstone
godstone = hasob(player->pack, getopposinggodstone(lf->race->id));
if (godstone) {
char buf[BUFLEN],obname[BUFLEN];
getobname(godstone, obname, 1);
sprintf(buf, "(offer %s)", obname);
addchoice(&prompt, 'o', buf, NULL, NULL, NULL);
}
} else {
addchoice(&prompt, 'o', "(offer a bribe)", NULL, NULL, NULL);
}
}
}
/*
f = lfhasflag(lf, F_OWNSSHOP);
if (f) {
int shopid;
shopid = f->val[0];
moneyowing = getowing(player, shopid, NULL);
if (moneyowing > 0) {
snprintf(buf, BUFLEN, "(pay $%d to the shopkeeper)",moneyowing);
addchoice(&prompt, 'p', buf, NULL, NULL, NULL);
}
}
*/
addchoice(&prompt, 'y', "Yeeeeeaaaargh!", NULL, NULL, NULL);
addchoice(&prompt, 'n', "(nothing)", NULL, NULL, NULL);
ch = getchoice(&prompt);
if ((ch == 'n') || (ch == '\0')) {
msg("Cancelled.");
return;
if (lf2) {
getlfname(lf2, lfname2);
} else {
strcpy(lfname2, "?noone?");
}
// process command
switch (ch) {
case 'a':
snprintf(buf, BUFLEN, "Tell %s to attack who?",lfname);
snprintf(buf2, BUFLEN, "%s->Attack->",lfname);
c = askcoords(buf, buf2, TT_MONSTER, lf, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && c->lf) {
lf2 = c->lf;
}
if (!lf2) {
msg("Cancelled.");
return;
}
getlfname(lf2, lfname2);
msg("You say \"Attack %s!\" to %s.",isplayer(lf2) ? "me" : lfname2, lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) {
msg("%s doesn't respond.", lfname);
break;
@ -4624,7 +4494,6 @@ void docomms(lifeform_t *lf) {
}
break;
case 'c':
msg("You say \"Come here!\" to %s.",lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) {
msg("%s doesn't respond.", lfname);
break;
@ -4857,17 +4726,8 @@ void docomms(lifeform_t *lf) {
break;
case 'g':
snprintf(buf, BUFLEN, "Tell %s to go where?",lfname);
snprintf(buf2, BUFLEN, "%s->Goto->",lfname);
c = askcoords(buf, buf2, TT_NONE, lf, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && cellwalkable(lf, c, NULL) ) {
} else {
msg("Cancelled.");
return;
}
// stop attacking all current targets first...
killflagsofid(lf->flags, F_TARGETLF);
msg("You say \"Go over there!\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) {
msg("%s doesn't respond.", lfname);
break;
@ -4876,10 +4736,9 @@ void docomms(lifeform_t *lf) {
msg("%s doesn't respond.", lfname);
break;
}
aigoto(lf, c, MR_OTHER, NULL, DEF_AIFOLLOWTIME);
aigoto(lf, targc, MR_OTHER, NULL, DEF_AIFOLLOWTIME);
break;
case 'i':
msg("You say \"What can you tell me about this area?\" to %s.", lfname);
if (lfhasflag(lf, F_PHANTASM)) {
msg("%s doesn't respond.", lfname);
break;
@ -4891,7 +4750,6 @@ void docomms(lifeform_t *lf) {
break;
case 'j':
// charisma check to see if they'll join you.
msg("You say \"Join me on my quest!\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) {
msg("%s doesn't respond.", lfname);
break;
@ -4903,7 +4761,6 @@ void docomms(lifeform_t *lf) {
recruit(lf);
break;
case 'k': // trade Knowledge
msg("You say \"Care to trade knowledge?\" to %s.", lfname);
if (lfhasflag(lf, F_PHANTASM)) {
msg("%s doesn't respond.", lfname);
break;
@ -4911,7 +4768,6 @@ void docomms(lifeform_t *lf) {
tradeknowledge(lf);
break;
case 'm': // mercy
msg("You say \"Have mercy!\" to %s.", lfname);
if (lfhasflag(lf, F_PHANTASM)) {
msg("%s doesn't respond.", lfname);
break;
@ -4982,7 +4838,6 @@ void docomms(lifeform_t *lf) {
break;
*/
case 'r':
msg("You say \"Get some rest.\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) {
msg("%s doesn't respond.", lfname);
break;
@ -4996,7 +4851,8 @@ void docomms(lifeform_t *lf) {
stopresting(lf);
} else {
if (needstorest(lf, NULL)) {
if (safetorest(lf)) {
enum ERROR why;
if (safetorest(lf, &why) || (why == E_TOOSOON)) {
addflag(lf->flags, F_RESTUNTILBETTER, B_TRUE, NA, NA, NULL);
startresting(lf, B_FALSE);
} else {
@ -5040,7 +4896,6 @@ void docomms(lifeform_t *lf) {
}
break;
case 'x':
msg("You say \"Any dangers nearby that I should look out for?\" to %s.", lfname);
if (lfhasflag(lf, F_PHANTASM)) {
msg("%s doesn't respond.", lfname);
break;
@ -5051,11 +4906,9 @@ void docomms(lifeform_t *lf) {
}
break;
case 'y':
msg("You shout at %s!", lfname);
noise(where, player, NC_OTHER, 3, "someone shouting!", NULL);
noise(player->cell, player, NC_OTHER, 3, "someone shouting!", NULL);
break;
case '<':
msg("You say \"Stay close!\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) {
msg("%s doesn't respond.", lfname);
break;
@ -5067,7 +4920,6 @@ void docomms(lifeform_t *lf) {
setfollowdistance(lf, 1, 3);
break;
case '>':
msg("You say \"Keep your distance!\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) {
msg("%s doesn't respond.", lfname);
break;
@ -5079,9 +4931,173 @@ void docomms(lifeform_t *lf) {
setfollowdistance(lf, 3, 5);
break;
}
}
void docommsmulti(void) {
lifeform_t *ally[MAX_MAPW*MAX_MAPH],*l,*lfarg;
cell_t *cellarg,*origc = NULL;
int nallies = 0,i;
char buf[BUFLEN],ch;
snprintf(buf, BUFLEN, "What will you command your allies to do?");
initprompt(&prompt, buf);
prompt.maycancel = B_TRUE;
// find all allies on the map who can hear the player
for (l = player->cell->map->lf ; l ; l = l->next) {
if ((l != player) && (getallegiance(l) == AL_FRIENDLY)) {
ally[nallies] = l;
nallies++;
// add options to say to this person
makecommslist(&prompt, l, B_TRUE);
}
}
// ask what to say to them all
ch = getchoice(&prompt);
if ((ch == 'n') || (ch == '\0')) {
msg("Cancelled.");
return;
}
if (getcommsopts(ch, "Allies", &lfarg, &cellarg)) {
msg("Cancelled.");
return;
}
announcecomms(ch, "your allies", lfarg, cellarg);
origc = cellarg;
for (i = 0; i < nallies; i++) {
docommslf(ally[i], ch, lfarg, cellarg);
if (ch == 'g') {
// pick a new cell
cellarg = getrandomadjcell(cellarg, &ccwalkable, B_ALLOWEXPAND);
if (!cellarg) cellarg = origc;
}
}
taketime(player, getactspeed(player));
}
void announcecomms(char ch, char *talkto, lifeform_t *lfarg, cell_t *cellarg) {
char lfname2[BUFLEN];
if (lfarg) {
getlfname(lfarg, lfname2);
}
switch (ch) {
case 'a':
msg("You say \"Attack %s!\" to %s.",isplayer(lfarg) ? "me" : lfname2, talkto);
break;
case 'c':
msg("You say \"Come here!\" to %s.",talkto);
break;
case 'g':
msg("You say \"Go over there!\" to %s.", talkto);
break;
case 'i':
msg("You say \"What can you tell me about this area?\" to %s.", talkto);
break;
case 'j':
msg("You say \"Join me on my quest!\" to %s.", talkto);
break;
case 'k': // trade Knowledge
msg("You say \"Care to trade knowledge?\" to %s.", talkto);
break;
case 'm': // mercy
msg("You say \"Have mercy!\" to %s.", talkto);
break;
case 'r':
msg("You say \"Get some rest.\" to %s.", talkto);
break;
case 'x':
msg("You say \"Any dangers nearby that I should look out for?\" to %s.", talkto);
break;
case 'y':
msg("You shout at %s!", talkto);
break;
case '<':
msg("You say \"Stay close!\" to %s.", talkto);
break;
case '>':
msg("You say \"Keep your distance!\" to %s.", talkto);
break;
default: break;
}
}
void docomms(lifeform_t *lf) {
cell_t *where = NULL;
char buf[BUFLEN],lfname[BUFLEN];
char ch;
lifeform_t *lfarg;
cell_t *cellarg;
//int moneyowing = 0;
if (!lf) {
where = askcoords("Talk to who?", "Talk->", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf && cansee(player, where->lf)) {
lf = where->lf;
}
}
if (!lf) {
msg("Cancelled.");
return;
}
getlfname(lf, lfname);
snprintf(buf, BUFLEN, "What will you say to %s?",lfname);
initprompt(&prompt, buf);
prompt.maycancel = B_TRUE;
makecommslist(&prompt, lf, B_FALSE);
ch = getchoice(&prompt);
if ((ch == 'n') || (ch == '\0')) {
msg("Cancelled.");
return;
}
getcommsopts(ch, lfname, &lfarg, &cellarg);
announcecomms(ch, lfname, lfarg, cellarg);
docommslf(lf, ch, lfarg, cellarg);
taketime(player, getactspeed(player));
}
// return true on error
int getcommsopts(char ch, char *talkto, lifeform_t **retlf, cell_t **retcell) {
cell_t *c;
char buf[BUFLEN],buf2[BUFLEN];
*retlf = NULL;
*retcell = NULL;
// get other options for comms...
switch (ch) {
case 'a': // who to attack?
snprintf(buf, BUFLEN, "Tell %s to attack who?",talkto);
snprintf(buf2, BUFLEN, "%s->Attack->",talkto);
c = askcoords(buf, buf2, TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && c->lf) {
*retlf = c->lf;
} else {
return B_TRUE;
}
break;
case 'g': // go where?
snprintf(buf, BUFLEN, "Tell %s to go where?",talkto);
snprintf(buf2, BUFLEN, "%s->Goto->",talkto);
*retcell = askcoords(buf, buf2, TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (! (*retcell)) {
return B_TRUE;
}
break;
}
return B_FALSE;
}
// lf is the person (if any) who you are talking to
void docomms_areainfo(char *who, flagpile_t *fp, lifeform_t *lf) {
int x,y,ndone;
@ -9682,6 +9698,7 @@ void initgfx(void) {
initcol(C_CARPET1, 560, 280, 136);
initcol(C_CARPET2, 360, 80, 36);
initcol(C_SMOKE, 250, 250, 300);
initcol(C_STONE, 800, 800, 800);
initcol(C_WOOD, 384, 244, 64);
// dark cols
initcol(C_DARKCYAN, 0, 500, 500);
@ -10783,9 +10800,6 @@ void handleinput(void) {
drawscreen();
}
break;
case CMD_SLOWWALK: // slowwalk
trysneak(player, D_NONE);
break;
case CMD_REST: // wait
addflag(player->flags, F_LASTCMD, NA, NA, NA, temp);
if (count > 1) {
@ -10878,6 +10892,9 @@ void handleinput(void) {
case CMD_COMMS: // communicate
docomms(NULL);
break;
case CMD_COMMSALL: // communicate
docommsmulti();
break;
case CMD_EAT: // eat
doeat(player->pack);
break;

3
io.h
View File

@ -14,6 +14,7 @@ void animradial(cell_t *src, int radius, int ch, int colour, int dirtype, char *
void animsky(cell_t *src, char ch, int colour);
//void announceob(enum OBTYPE oid);
void announcearrival(lifeform_t *lf, map_t *newmap);
void announcecomms(char ch, char *talkto, lifeform_t *lfarg, cell_t *cellarg);
int announceflaggain(lifeform_t *lf, flag_t *f);
int announceflagloss(lifeform_t *lf, flag_t *f);
int announceobflaggain(object_t *o, flag_t *f);
@ -51,6 +52,7 @@ void describespell(objecttype_t *ot);
void doattackcell(int dir);
void doclose(void);
void docomms(lifeform_t *target);
void docommslf(lifeform_t *lf, char ch, lifeform_t *lf2, cell_t *targc);
void docomms_areainfo(char *who, flagpile_t *fp, lifeform_t *lf);
void docomms_areadangers(char *who, flagpile_t *fp, lifeform_t *lf);
void dodrop(obpile_t *op, int wantmulti, obpile_t *dst);
@ -103,6 +105,7 @@ void forceredraw(void);
enum COLOUR getattrcolour(enum ATTRBRACKET brack);
char getchoice(prompt_t *prompt);
char getchoicestr(prompt_t *prompt, int useshortcuts, int showlallatstart);
int getcommsopts(char ch, char *talkto, lifeform_t **retlf, cell_t **retcell);
int getkey(int escseqok);
enum COLOUR getskilllevelcolour(enum SKILLLEVEL slev);
void handle_ctrl_y(int arg);

304
lf.c
View File

@ -516,7 +516,10 @@ int calcxp(lifeform_t *lf) {
// extra 'spells'
if (hasflag(lf->race->flags, F_INDUCEFEAR)) {
spells += 10;
spells += 5;
}
if (hasflag(lf->race->flags, F_DRAINONHIT)) {
spells += 15;
}
// TOTAL:
@ -2644,9 +2647,10 @@ int checkfordrowning(lifeform_t *lf, object_t *o) {
}
int check_rest_ok(lifeform_t *lf) {
if (!safetorest(lf)) {
enum ERROR why;
if (!safetorest(lf, &why)) {
if (isplayer(lf)) {
switch (reason) {
switch (why) {
case E_LEVITATING:
msg("You cannot rest while levitating in mid-air!");
break;
@ -2671,7 +2675,7 @@ int check_rest_ok(lifeform_t *lf) {
lifeform_t *clonelf(lifeform_t *src, cell_t *where) {
lifeform_t *lf;
lf = addmonster(where, src->race->id, NULL, B_FALSE, 1, B_FALSE, NULL);
lf = addmonster(where, src->race->id, NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
if (lf) {
killflagsofid(lf->flags, F_XPVAL);
addflag(lf->flags, F_XPVAL, 0, NA, NA, NULL);
@ -3403,6 +3407,59 @@ void die(lifeform_t *lf) {
}
more(); drawmsg();
if (!vaporised) {
flag_t *retflag[MAXCANDIDATES], *f;
int nretflags,i;
f = hasflag(lf->flags, F_REVIVETIMER);
if (f) {
race_t *r;
r = findrace(f->val[2]);
if (f) {
strcpy(reanimateas, r->name);
}
}
if (!strlen(reanimateas)) {
// killed by a vampire = vampire.
if (killer) {
switch (killer->race->id) {
case R_VAMPIRE: sprintf(reanimateas, "vampire"); break;
default: break;
}
}
}
// died by eating your own race = ghoul.
// died by eating a vampire corpse = vampire.
if (!strlen(reanimateas)) {
getflags(lf->flags, retflag, &nretflags, F_POISONED, F_NONE);
for (i = 0; i < nretflags; i++) {
if (retflag[i]->val[2] == R_VAMPIRE) {
sprintf(reanimateas, "vampire");
} else if (retflag[i]->val[2] == lf->race->baseid) {
sprintf(reanimateas, "ghoul");
}
}
}
// hecta-worshippers often get reanimated.
if (!strlen(reanimateas) && thisisplayer && godprayedto(R_GODDEATH)) {
if (onein(3)) {
switch (rnd(1,2)) {
case 1:
sprintf(reanimateas, "zombie");
break;
case 2:
sprintf(reanimateas, "skeleton");
break;
}
}
}
}
// god effects...
if (!vaporised) {
god = getrandomprayedgod();
@ -3968,53 +4025,16 @@ void die(lifeform_t *lf) {
addflag(lf->flags, F_LIFEOB, NA, 5, 2, cid);
}
} else {
// Will the dead lf get reanimated up as a monster ?
// Will the dead player get reanimated up as a monster in bones files?
//
if (!vaporised) {
flag_t *retflag[MAXCANDIDATES];
int nretflags,i;
// killed by a vampire = vampire.
if (killer) {
switch (killer->race->id) {
case R_VAMPIRE: sprintf(reanimateas, "vampire"); break;
default: break;
}
}
// died by eating your own race = ghoul.
// died by eating a vampire corpse = vampire.
if (!strlen(reanimateas)) {
getflags(lf->flags, retflag, &nretflags, F_POISONED, F_NONE);
for (i = 0; i < nretflags; i++) {
if (retflag[i]->val[2] == R_VAMPIRE) {
sprintf(reanimateas, "vampire");
} else if (retflag[i]->val[2] == lf->race->baseid) {
sprintf(reanimateas, "ghoul");
}
}
}
// hecta-worshippers often get reanimated.
if (!strlen(reanimateas) && thisisplayer && godprayedto(R_GODDEATH)) {
if (onein(3)) {
switch (rnd(1,2)) {
case 1:
sprintf(reanimateas, "zombie");
break;
case 2:
sprintf(reanimateas, "skeleton");
break;
}
}
}
// announce
if (strlen(reanimateas)) {
if (thisisplayer || cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("^%c%s%s corpse rises up as %s %s!^n",
C_MAGENTA,
getlfcol(player, CC_VBAD),
lfname, getpossessive(lfname),
needan(reanimateas) ? "an" : "a", reanimateas);
}
@ -4034,7 +4054,7 @@ void die(lifeform_t *lf) {
// UNLESS WE ARE _SURE_ IT IS THE PLAYER (ie. thisisplayer = true)
if (createrace != R_NONE) {
lifeform_t *newlf;
newlf = addmonster(where, createrace, NULL, B_FALSE, 1, B_FALSE, NULL);
newlf = addmonster(where, createrace, NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
if (newlf) {
// no xp for killing
killflagsofid(newlf->flags, F_XPVAL);
@ -4047,7 +4067,7 @@ void die(lifeform_t *lf) {
// add two new worms nearby, with less hp.
for (i = 0;i < 2; i++) {
lifeform_t *newlf;
newlf = addmonster(dividecell[i], dividerace, NULL, B_FALSE, 1, B_FALSE, NULL);
newlf = addmonster(dividecell[i], dividerace, NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
if (newlf) {
// half hp
f = hasflag(newlf->flags, F_HITDICE);
@ -4090,7 +4110,7 @@ void die(lifeform_t *lf) {
// remove the corpse...
if (corpse) killob(corpse);
// add the reanimated monster
addmonster(c, R_SPECIFIED, reanimateas, B_FALSE, 1, B_FALSE, NULL);
addmonster(c, R_SPECIFIED, reanimateas, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
}
}
@ -4867,7 +4887,7 @@ int eat(lifeform_t *lf, object_t *o) {
setlastdam(lf, "merging with a corpse");
lf->lastdamtype = DT_DIRECT;
lf->hp = 0;
newlf = makezombie(o, 0, "rises from the dead");
newlf = makezombie(o, 0, "rises from the dead", NULL);
if (newlf) {
addflag(newlf->flags, F_CORPSELF, R_LINGPARASITE, NA, NA, NULL);
}
@ -10639,10 +10659,14 @@ enum BODYPART getrandomcorebp(lifeform_t *lf, lifeform_t *attacker) {
return selbp;
}
race_t *getrandomcorpserace(cell_t *c) {
race_t *getrandomcorpserace(cell_t *c, enum LFSIZE wantsize) {
condset_t cs;
initcondv(&cs, CC_HASCORPSE, B_TRUE, NA, CC_NONE);
if (wantsize != SZ_ANY) {
addcond(&cs, CC_HASSIZE, B_TRUE, wantsize);
}
return getrandomrace(c, NA, &cs);
}
@ -11406,6 +11430,8 @@ long getxpforlev(int level) {
float multiplier = 13;
float constant = 2.8;
if (level <= 0) return 0;
// no xp needed for level 1
/*
for (i = 0; i < level - 1; i++) {
@ -13506,13 +13532,13 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
// return TRUE on failure
int leveldrain(lifeform_t *lf, int amt, int power, lifeform_t *fromlf) {
int leveldrain(lifeform_t *lf, int amt, enum CHECKTYPE sctype, int scdiff, lifeform_t *fromlf) {
int resisted = B_FALSE;
if (isimmuneto(lf->flags, DT_NECROTIC, B_FALSE)) resisted = B_TRUE;
if (!resisted && isresistantto(lf->flags, DT_NECROTIC, B_FALSE) && onein(2)) resisted = B_TRUE;
// fit check
if (!resisted && skillcheck(lf, SC_CON, 100+(power*6), 0 )) {
if (!resisted && skillcheck(lf, sctype, scdiff, 0 )) {
resisted = B_TRUE;
}
if (resisted) {
@ -14975,7 +15001,6 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) {
assert(!cell->type->solid);
}
m = cell->map;
// add to the end of the list
@ -15564,7 +15589,7 @@ void makepeaceful(lifeform_t *who, lifeform_t *causedby) {
// 'power' is 0-10, determines how poewrful the zombie is.
// if 0, don't do any special changes.
lifeform_t *makezombie(object_t *o, int power, char *description) {
lifeform_t *makezombie(object_t *o, int power, char *description, lifeform_t *master) {
flag_t *f;
race_t *r;
lifeform_t *lf;
@ -15671,6 +15696,10 @@ lifeform_t *makezombie(object_t *o, int power, char *description) {
msg("^W%s %s!", obname, description);
}
if (master) {
petify(lf, master);
}
return lf;
}
@ -17364,7 +17393,7 @@ void loselevel(lifeform_t *lf, int amt, lifeform_t *fromlf) {
statdirty = B_TRUE;
drawstatus();
wrefresh(statwin);
msg("^%cWelcome back to level %d.",getlfcol(lf, CC_BAD), lf->level);
msg("^%cWelcome back to level %d.",getlfcol(lf, CC_VBAD), lf->level);
}
}
@ -17486,6 +17515,107 @@ void magicwoods_angry(lifeform_t *who) {
}
}
// make a list of choices for player to talk to a lf
//
// 'multiple' means 'we're talking to multiple people,not just one'
void makecommslist(prompt_t *p, lifeform_t *lf, int multiple) {
flag_t *f;
object_t *godstone;
enum ATTRBRACKET iqb;
iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
// are they friendly?
if (ispetof(lf, player)) {
if ((iqb >= IQ_ANIMAL) || isundead(lf)) {
if (!haschoice(p, 'a')) addchoice(p, 'a', "Attack something", NULL, NULL, NULL);
}
if (!isadjacent(lf->cell, player->cell)) {
if (!haschoice(p, 'c')) addchoice(p, 'c', "Come here", NULL, NULL, NULL);
}
if (!haschoice(p, 'g')) addchoice(p, 'g', "Go somewhere", NULL, NULL, NULL);
if (isadjacent(lf->cell, player->cell) && !lfhasflag(lf, F_NOPACK) && !multiple) {
if (!haschoice(p, 't')) addchoice(p, 't', "Trade items with me", NULL, NULL, NULL);
}
if (iqb >= IQ_ANIMAL) {
f = isresting(lf);
if (f) {
if (!haschoice(p, 'r')) addchoice(p, 'r', "Stop resting.", NULL, NULL, NULL);
} else {
if (!haschoice(p, 'r')) addchoice(p, 'r', "Rest until you are healed.", NULL, NULL, NULL);
}
if (!haschoice(p, '"')) addchoice(p, '<', "Stay close.", NULL, NULL, NULL);
if (!haschoice(p, '"')) addchoice(p, '>', "Keep your distance.", NULL, NULL, NULL);
}
} else if (ishirable(lf) && !multiple) {
if (lfhasflag(lf, F_ISPRISONER)) {
if (!haschoice(p, 'j')) addchoice(p, 'j', "Join me, and I will help you escape.", NULL, NULL, NULL);
} else if (getskill(player, SK_SPEECH) >= PR_EXPERT) {
if (!haschoice(p, 'j')) addchoice(p, 'j', "Join me on my quest!", NULL, NULL, NULL);
}
}
if (!isgod(lf) && ispeaceful(lf) && cantalk(lf) && !multiple) {
enum SKILLLEVEL slev;
job_t *j;
slev = getskill(player, SK_SPEECH);
// same race or job?
j = getjob(player);
if ((slev != PR_MASTER) && j && (j == getjob(lf))) slev++;
if ((slev != PR_MASTER) && (player->race->id == lf->race->id)) slev++;
if (slev >= PR_NOVICE) {
if (!haschoice(p, 'x')) addchoice(p, 'x', "Any dangers nearby that I should look out for?", NULL, NULL, NULL);
}
if (slev >= PR_BEGINNER) {
if (!haschoice(p, 'i')) addchoice(p, 'i', "What can you tell me about this area?", NULL, NULL, NULL);
}
if (!areallies(player, lf)) {
if (slev >= PR_SKILLED) {
if (!haschoice(p, 'k')) addchoice(p, 'k', "Care to trade knowledge?", NULL, NULL, NULL);
}
}
}
if (isadjacent(lf->cell, player->cell) && !multiple) {
if (areenemies(player, lf)) {
if (!haschoice(p, 'm')) addchoice(p, 'm', "Have mercy!", NULL, NULL, NULL);
}
// if you are allies, use 'trade items' instead
if (!areallies(player, lf)) {
if (isgod(lf)) {
// may only donate the godstone
godstone = hasob(player->pack, getopposinggodstone(lf->race->id));
if (godstone) {
char buf[BUFLEN],obname[BUFLEN];
getobname(godstone, obname, 1);
sprintf(buf, "(offer %s)", obname);
if (!haschoice(p, 'o')) addchoice(p, 'o', buf, NULL, NULL, NULL);
}
} else {
if (!haschoice(p, 'o')) addchoice(p, 'o', "(offer a bribe)", NULL, NULL, NULL);
}
}
}
/*
f = lfhasflag(lf, F_OWNSSHOP);
if (f) {
int shopid;
shopid = f->val[0];
moneyowing = getowing(player, shopid, NULL);
if (moneyowing > 0) {
snprintf(buf, BUFLEN, "(pay $%d to the shopkeeper)",moneyowing);
addchoice(p, 'p', buf, NULL, NULL, NULL);
}
}
*/
if (!multiple && !haschoice(p, 'y')) addchoice(p, 'y', "Yeeeeeaaaargh!", NULL, NULL, NULL);
if (!haschoice(p, 'n')) addchoice(p, 'n', "(nothing)", NULL, NULL, NULL);
}
void makefriendly(lifeform_t *who, int howlong) {
char lfname[BUFLEN];
@ -19921,12 +20051,12 @@ int rollstat(lifeform_t *lf, enum ATTRIB attr) {
}
// safe to rest?
int safetorest(lifeform_t *lf) {
int safetorest(lifeform_t *lf, enum ERROR *why) {
lifeform_t *l;
reason = E_OK;
if (why) *why = E_OK;
if (lfhasflag(lf, F_STASIS)) {
reason = E_STASIS;
if (why) *why = E_STASIS;
return B_FALSE;
}
@ -19946,7 +20076,7 @@ int safetorest(lifeform_t *lf) {
}
if (monsternearby) {
reason = E_MONSTERNEARBY;
if (why) *why = E_MONSTERNEARBY;
return B_FALSE;
}
}
@ -19954,7 +20084,7 @@ int safetorest(lifeform_t *lf) {
if (getlftemp(lf) <= T_VCOLD) {
if (!isimmuneto(lf->flags, DT_COLD, B_FALSE) && !isresistantto(lf->flags, DT_COLD, B_FALSE)) {
reason = E_TOOCOLD;
if (why) *why = E_TOOCOLD;
return B_FALSE;
}
}
@ -19969,6 +20099,7 @@ int safetorest(lifeform_t *lf) {
f = lfhasflag(lf, F_TURNSINPEACE);
if (!f || (f->val[0] < timeneeded)) {
if (why) *why = E_TOOSOON;
return B_FALSE;
}
}
@ -22566,7 +22697,7 @@ void startlfturn(lifeform_t *lf) {
// create the monster directly behind you
if (monisreal) {
// set autogen to false, we don't want minions appearing too.
mon = addmonster(c, r->id, NULL, B_FALSE, 1, B_FALSE, NULL);
mon = addmonster(c, r->id, NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
} else {
mon = addlf(c, r->id, 1);
}
@ -23025,7 +23156,32 @@ void startlfturn(lifeform_t *lf) {
practice(lf, SK_ENGINEERING, 1);
}
}
}
// object which is really a monster
f = hasflag(o->flags, F_ISMONSTER);
if (f && (f->val[2] != NA)) {
int diff;
diff = f->val[2] + distmod;
if (skillcheck(lf, SC_SEARCH, diff, mod)) {
lifeform_t *newlf;
// reveal it
newlf = reveal_pretendob(o);
if (newlf && cansee(player, newlf)) {
char obname[BUFLEN];
char lfname[BUFLEN];
getobname(o, obname, o->amt);
capitalise(obname);
getlfnamea(newlf, lfname);
msg("^wHey! %s %s really %s!",obname, (o->amt == 1) ? "is" : "are",lfname);
more();
interrupt(lf);
needredraw = B_TRUE;
drawscreen();
// train skills
practice(lf, SK_PERCEPTION, 1);
}
continue;
}
}
}
}
@ -24118,7 +24274,7 @@ lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, char *ra
lifeform_t *newlf = NULL;
char buf[BUFLEN];
newlf = addmonster(c, rid, racename, B_TRUE, 1, B_FALSE, NULL);
newlf = addmonster(c, rid, racename, B_TRUE, 1, B_FALSE, B_NOEXTRA, NULL);
if (newlf) {
if (haslos(player, c)) {
//char *newbuf;
@ -24790,6 +24946,32 @@ int real_touch(lifeform_t *lf, object_t *o, int onpurpose) {
return B_FALSE;
}
lifeform_t *reveal_pretendob(object_t *o) {
enum RACE rid;
flag_t *f;
cell_t *c;
lifeform_t *lf;
c = getoblocation(o);
f = hasflag(o->flags, F_ISMONSTER);
assert(f);
rid = f->val[0];
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
lf = addmonster(c, rid, NULL, B_TRUE, 1, B_FALSE, B_FALSE, NULL);
if (lf) {
f = lfhasflag(lf, F_PRETENDSTOBE);
if (f) {
char obname[BUFLEN];
// replace text
getobnametruebase(o, obname, 1);
free(f->text);
f->text = strdup(obname);
}
}
return lf;
}
void turntoface(lifeform_t *lf, cell_t *dstcell) {
if (isdead(lf)) return;
if (lfhasflag(lf, F_AUTOROTATE)) return;

10
lf.h
View File

@ -281,7 +281,7 @@ int getracerarity(enum HABITAT hab, enum RACE rid, enum RARITY *rr);
object_t *getrandomarmour(lifeform_t *lf, lifeform_t *attacker);
enum BEHAVIOUR getrandombehaviour(void);
enum BODYPART getrandomcorebp(lifeform_t *lf, lifeform_t *attacker);
race_t *getrandomcorpserace(cell_t *c);
race_t *getrandomcorpserace(cell_t *c, enum LFSIZE wantsize);
job_t *getrandomjob(int onlyplayerjobs);
int getrandommonlevel(race_t *r, map_t *m);
race_t *getrandomrace(cell_t *c, int forcedepth, condset_t *cs);
@ -336,7 +336,7 @@ flag_t *hasname(lifeform_t *lf);
int hassoul(lifeform_t *lf);
void inc_quad_range(enum QUADRANT *start, enum QUADRANT *end, int howmuch);
int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJURY forcetype);
int leveldrain(lifeform_t *lf, int amt, int power, lifeform_t *fromlf);
int leveldrain(lifeform_t *lf, int amt, enum CHECKTYPE sctype, int scdiff, lifeform_t *fromlf);
int lfcanbekod(lifeform_t *lf);
int lfcanbestoned(lifeform_t *lf);
flag_t *lfhasflag(lifeform_t *lf, enum FLAG fid);
@ -432,13 +432,14 @@ void loselevel(lifeform_t *lf, int amt, lifeform_t *fromlf);
void loseskill(lifeform_t *lf, enum SKILL skid);
void magicwoods_angry(lifeform_t *who);
void magicwoods_warn(lifeform_t *who);
void makecommslist(prompt_t *p, lifeform_t *lf, int multiple);
void makefriendly(lifeform_t *lf, int howlong);
void makeheard(lifeform_t *listener, lifeform_t *noisemaker, int showglyph, char *noisetext, int howlong);
int makelearnable(lifeform_t *lf, enum SKILL skid);
int makenauseated(lifeform_t *lf, int amt, int howlong, enum ERROR *why);
void makenoise(lifeform_t *lf, enum NOISETYPE nid);
void makepeaceful(lifeform_t *lf, lifeform_t *causedby);
lifeform_t *makezombie(object_t *o, int power, char *description);
lifeform_t *makezombie(object_t *o, int power, char *description, lifeform_t *master);
void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how, int overridepower);
int meetsallattreqs(lifeform_t *lf, object_t *o);
int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o, int *modpct);
@ -487,7 +488,7 @@ int startclimbing(lifeform_t *lf);
int startresting(lifeform_t *lf, int willtrain);
int rollattr(enum ATTRBRACKET bracket);
int rollstat(lifeform_t *lf, enum ATTRIB attr);
int safetorest(lifeform_t *lf);
int safetorest(lifeform_t *lf, enum ERROR *why);
int say(lifeform_t *lf, char *text, int volume);
int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *text, lifeform_t *talkingto);
int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus);
@ -537,6 +538,7 @@ int tradeknowledge(lifeform_t *lf);
int tryclimb(lifeform_t *lf, cell_t *where, char *towhat, int onpurpose);
int touch(lifeform_t *lf, object_t *o);
int real_touch(lifeform_t *lf, object_t *o, int onpurpose);
lifeform_t *reveal_pretendob(object_t *o);
void turntoface(lifeform_t *lf, cell_t *dstcell);
void unequipeffects(lifeform_t *lf, object_t *o);
void unpoison(lifeform_t *lf);

99
map.c
View File

@ -21,6 +21,8 @@
int enteringmap = B_FALSE;
extern void *rdata;
extern habitat_t *firsthabitat,*lasthabitat;
extern job_t *firstjob;
extern map_t *firstmap,*lastmap;
@ -251,21 +253,27 @@ map_t *addmap(void) {
// if "rid" R_SPECIFIED, parse racename to get the race.
// rid can also be R_RANDOM.
// otherwise just use the given race.
lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok, int amt, int autogen, int *nadded) {
lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok, int amt, int autogen, int allowextras, int *nadded) {
lifeform_t *lf = NULL;
race_t *r;
int db = B_FALSE;
flagpile_t *wantflags = NULL;
enum JOB wantjob = J_NONE;
enum BEHAVIOUR wantbehaviour = BH_NONE;
enum ERROR why;
if (nadded) *nadded = 0;
/*if gamemode == GM_GAMESTARTED checkallflags(player->cell->map); */
// ie. don't create mosnters on closed doors!
if (!cellwalkable(NULL, c, NULL)) {
return NULL;
if (!cellwalkable(NULL, c, &why)) {
object_t *o;
o = (object_t *)rdata;
if ((why == E_OBINWAY) && o && hasflag(o->flags, F_ISMONSTER)) {
} else {
return NULL;
}
}
wantflags = addflagpile(NULL, NULL);
@ -450,50 +458,50 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok
// appears in groups?
if (db) dblog("handling groups");
if (autogen) {
if (autogen && allowextras) {
f = hasflag(lf->flags, F_NUMAPPEAR);
if (f) {
// override amount
amt = rnd(f->val[0], f->val[1]);
}
if (amt > 1) {
int idx = 0;
cell_t *adjcell;
amt--; // we've already added one
}
if (amt > 1) {
int idx = 0;
cell_t *adjcell;
amt--; // we've already added one
//adjcell = c;
for ( ; amt > 0; amt--, idx++) {
lifeform_t *newlf;
// find an adjacent cell to one of the newly added monsters,
// starting with the first one
adjcell = real_getrandomadjcell(c, &ccwalkable, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL);
// did we find one?
if (!adjcell) break;
//adjcell = c;
for ( ; amt > 0; amt--, idx++) {
lifeform_t *newlf;
// find an adjacent cell to one of the newly added monsters,
// starting with the first one
adjcell = real_getrandomadjcell(c, &ccwalkable, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL);
// did we find one?
if (!adjcell) break;
newlf = addlf(adjcell, r->id, getrandommonlevel(r, adjcell->map));
if (!newlf) {
break;
}
if (nadded) (*nadded)++;
newlf->born = B_FALSE;
finalisemonster(newlf, lf, wantflags, idx, BH_NONE);
newlf->born = B_TRUE;
// match alignment
setalignment(newlf, getalignment(lf));
// match hostility
if (lfhasflag(lf, F_HOSTILE)) {
if (!lfhasflag(newlf, F_HOSTILE)) addflag(newlf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
} else {
killflagsofid(newlf->flags, F_HOSTILE);
}
// initial monster should remember its minions
addflag(lf->flags, F_MINION, newlf->id, NA, NA, NULL);
newlf = addlf(adjcell, r->id, getrandommonlevel(r, adjcell->map));
if (!newlf) {
break;
}
if (nadded) (*nadded)++;
newlf->born = B_FALSE;
finalisemonster(newlf, lf, wantflags, idx, BH_NONE);
newlf->born = B_TRUE;
// match alignment
setalignment(newlf, getalignment(lf));
// match hostility
if (lfhasflag(lf, F_HOSTILE)) {
if (!lfhasflag(newlf, F_HOSTILE)) addflag(newlf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
} else {
killflagsofid(newlf->flags, F_HOSTILE);
}
// initial monster should remember its minions
addflag(lf->flags, F_MINION, newlf->id, NA, NA, NULL);
}
}
//if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging
@ -501,7 +509,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok
// minons?
// appears in groups?
if (db) dblog("handling minions");
if (autogen) {
if (autogen && allowextras) {
f = hasflag(lf->flags, F_MINIONS);
if (f) {
if (rnd(1,100) <= f->val[0]) {
@ -636,7 +644,7 @@ int addrandomthing(cell_t *c, int obchance, int *nadded) {
lifeform_t *lf;
// monster
//if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging
lf = addmonster(c, R_RANDOM, NULL, B_TRUE, 1, B_TRUE, nadded);
lf = addmonster(c, R_RANDOM, NULL, B_TRUE, 1, B_TRUE, B_ALLOWEXTRA, nadded);
if (lf) {
rv = TT_MONSTER;
}
@ -2606,7 +2614,7 @@ int fix_unreach_via_doors(map_t *m) {
setcelltype(c, getmapempty(m));
makedoor(c, 0);
setcellreason(c, "making door to link seperated areas");
dblog(" successfully fixed by creating a door.");
dblog(" successfully fixed by creating a door at %d,%d.",c->x, c->y);
return 1;
}
}
@ -4527,7 +4535,7 @@ void createheaven(map_t *map, int depth, map_t *parentmap, int exitdir, object_t
c = map->cell[i];
}
// place god
lf = addmonster(c, r->id, NULL, B_FALSE, 1, B_FALSE, NULL);
lf = addmonster(c, r->id, NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
assert(lf);
// add to god list
godlf[ngodlfs++] = lf;
@ -4964,7 +4972,8 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
c = getcell_cond(map, &ccwalkableroom);
if (!c) c = getrandomcell(map);
c = real_getrandomadjcell(c, &ccwalkable, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL);
addmonster(c, R_SPECIFIED, thing[i]->what, B_FALSE, thing[i]->value, B_TRUE, NULL);
addmonster(c, R_SPECIFIED, thing[i]->what, B_FALSE, thing[i]->value, B_TRUE,
B_ALLOWEXTRA, NULL);
break;
case RT_BRANCHLINK:
if (db) dblog(" adding branchlink");
@ -9850,7 +9859,7 @@ void mapentereffects(map_t *m) {
//c = getrandomroomcell(m, m->room[i].id, WE_WALKABLE);
c = getcell_cond(m, &cs);
if (c && !hasobflagwithin(c, F_STAIRS, 15, DT_COMPASS)) {
addmonster(c, R_RANDOM, NULL, B_TRUE, 1, B_TRUE, NULL);
addmonster(c, R_RANDOM, NULL, B_TRUE, 1, B_TRUE, B_ALLOWEXTRA, NULL);
}
}
}

2
map.h
View File

@ -4,7 +4,7 @@ cell_t *addcell(map_t *map, int x, int y);
habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance, int maxvisrange, enum OBTYPE upstairtype, enum OBTYPE downstairtype, int stairsinrooms, enum TEMPERATURE temp);
void addhomeobs(lifeform_t *lf, int dolevelobs);
map_t *addmap(void);
lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok, int amt, int autogen, int *nadded);
lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok, int amt, int autogen, int allowextras, int *nadded);
object_t *addrandomob(cell_t *c);
int addrandomthing(cell_t *c, int obchance, int *nadded);
region_t *addregion(enum BRANCH rtype, region_t *parent, int outlineid, int depthmod, int createdby);

26
move.c
View File

@ -3286,6 +3286,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
if (door) {
msg("^gThere seems to be a secret door here!");
killflagsofid(door->flags, F_SECRET);
needredraw = B_TRUE;
}
}
//if (isblind(lf) || !haslos(lf, cell)) {
@ -3366,6 +3367,24 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
break;
case E_OBINWAY:
inway = (object_t *)rdata;
// walked into someone who was feigning death?
if (inway && hasflag(inway->flags, F_ISMONSTER)) {
lifeform_t *newlf;
if (haslos(lf, cell)) {
char inwayname[BUFLEN];
getobname(inway, inwayname, 1);
msg("^B%s starts to move!", inwayname);
more();
}
// reaveal
newlf = reveal_pretendob(inway);
if (newlf) {
turntoface(newlf, lf->cell);
aiattack(newlf, lf, aigetchasetime(newlf));
}
if (onpurpose || fleeing) taketime(lf, getmovespeed(lf));
return B_FALSE;
}
// can we push this?
if (ispushable(inway)) {
if (canpush(lf, inway, dir)) {
@ -3764,6 +3783,13 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
return B_FALSE;
}
// mosnters will never move on top of other monsters
// pretending to be objects (ie. gargoyles)
if (hasobwithflag(cell->obpile, F_ISMONSTER)) {
if (error) *error = E_WONT;
return B_FALSE;
}
if (celldangerous(lf, cell, B_TRUE, error)) {
// if lfs are fleeing and have below average wisdom,
// they will walk onto dangerous cells

View File

@ -307,6 +307,7 @@ int main(int argc, char **argv) {
addtempflag(player->flags, F_CANWILL, OT_A_CHECKSTAIRS, NA, NA, NULL, FROMGAMESTART);
addtempflag(player->flags, F_CANWILL, OT_A_PRAY, NA, NA, NULL, FROMGAMESTART);
addtempflag(player->flags, F_CANWILL, OT_A_TRAIN, NA, NA, NULL, FROMGAMESTART);
addtempflag(player->flags, F_CANWILL, OT_A_TIPTOE, NA, NA, NULL, FROMGAMESTART);
addtempflag(player->flags, F_CANWILL, OT_A_DEBUG, NA, NA, NULL, FROMGAMESTART); /////////
// make the initial level
@ -1932,6 +1933,7 @@ int roll(char *string) {
int rolldie(int ndice, int sides) {
int i;
int res = 0;
if (sides <= 0) return 0;
for (i = 0; i < ndice; i++) {
res += rnd(1,sides);
}

View File

@ -1571,6 +1571,14 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
}
}
// hiding monsters?
f = hasflag(o->flags, F_ISMONSTER);
if (f) {
object_t *oo;
oo = addobfast(o->contents, f->val[1]);
assert(oo);
}
// extra chance of bone items being cursed
if (o->type->material->id == MT_BONE) {
if (pctchance(15)) {
@ -1966,7 +1974,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
if (!corpserace || hasflag(corpserace->flags, F_NOCORPSE)) {
// random one.
corpserace = getrandomcorpserace(NULL);
corpserace = getrandomcorpserace(NULL, wantarmsize);
}
o->weight = corpserace->weight;
@ -2027,13 +2035,13 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
if (!corpserace) {
cell_t *where;
where = getoblocation(o);
// select random race
// select random race, or correct size.
if (where) {
corpserace = getrandomcorpserace(where);
corpserace = getrandomcorpserace(where, wantarmsize);
}
if (!corpserace) {
// ie. vending machine, or inside another object/fake cell?
corpserace = getrandomcorpserace(NULL);
corpserace = getrandomcorpserace(NULL, wantarmsize);
}
if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid);
}
@ -2090,7 +2098,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
}
} else if (o->type->id == OT_JERKY) {
if (!corpserace) {
corpserace = getrandomcorpserace(NULL);
corpserace = getrandomcorpserace(NULL, wantarmsize);
if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid);
}
addflag(o->flags, F_LINKRACE, corpserace->id, NA, NA, NULL);
@ -2099,7 +2107,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
if (!corpserace || hasflag(corpserace->flags, F_NOCORPSE)) {
// random one.
corpserace = getrandomcorpserace(NULL);
corpserace = getrandomcorpserace(NULL, wantarmsize);
if (corpserace->id != corpserace->baseid) corpserace = findrace(corpserace->baseid);
}
@ -5503,6 +5511,11 @@ char *getobdesc(object_t *o, char *buf) {
int blind = B_FALSE;
int known = B_FALSE;
if (gamemode == GM_GAMESTARTED) {
if (hasflag(o->flags, F_ISMONSTER)) {
if (o->contents->first) {
o = o->contents->first;
}
}
// can't see the object ?
if (o->pile->owner == player) {
if (!haslos(player, player->cell) || isblind(player)) {
@ -5814,6 +5827,13 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
where = getoblocation(o);
if (hasflag(o->flags, F_ISMONSTER)) {
if (o->contents->first) {
o = o->contents->first;
}
}
f = hasflag(o->flags, F_TRAIL);
if (f) {
race_t *r = NULL;
@ -10465,7 +10485,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
where = getrandomadjcell(lf->cell, &ccwalkable, B_ALLOWEXPAND);
if (where) {
mon = addmonster(where, f->val[0], NULL, B_TRUE, 1, B_FALSE, NULL);
mon = addmonster(where, f->val[0], NULL, B_TRUE, 1, B_FALSE, B_NOEXTRA, NULL);
}
if (mon) {
char monname[BUFLEN];
@ -10612,7 +10632,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
case 0: // butterflies around user
willid = B_TRUE;
where = getrandomadjcell(lf->cell, &ccwalkable, B_ALLOWEXPAND);
addmonster(where, R_BUTTERFLY, NULL, B_FALSE, rnd(10,20), B_FALSE, NULL);
addmonster(where, R_BUTTERFLY, NULL, B_FALSE, rnd(10,20), B_FALSE, B_NOEXTRA, NULL);
if (haslos(player, where)) {
msg("A swarm of butterflies appears!");
}
@ -12383,7 +12403,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
break;
case OT_POT_EXPERIENCE:
if (potblessed == B_CURSED) {
leveldrain(lf, 1, 99, NULL);
leveldrain(lf, 1, SC_CON, 999, NULL);
} else {
// gain xp!
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 150, 0)) {
@ -14281,6 +14301,17 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce, lif
return 0;
}
// monster pretending to be object?
if (hasflag(o->flags, F_ISMONSTER)) {
lifeform_t *newlf;
newlf = reveal_pretendob(o);
if (newlf && attacker) {
turntoface(newlf, attacker->cell);
aiattack(newlf, attacker, aigetchasetime(newlf));
}
return 0;
}
// update lastdamtype
f = hasflag(o->flags, F_LASTDAMTYPE);
if (f) {
@ -15420,6 +15451,26 @@ void timeeffectsob(object_t *o) {
killflagsofid(o->flags, F_FILLPOT);
}
// mosnters pretending to be objects?
if (onground && hasflag(o->flags, F_ISMONSTER)) {
f = hasflag(o->flags, F_ISMONSTER);
if (strlen(f->text)) {
int dist;
dist = atoi(f->text);
// player within reveal distance?
if ((getcelldist(player->cell, location) <= dist) && !haslos(player, location)) {
lifeform_t *newlf;
newlf = reveal_pretendob(o);
if (newlf) {
turntoface(newlf, player->cell);
aiattack(newlf, player, aigetchasetime(newlf));
}
return;
}
}
}
// expire flags
timeeffectsflags(o->flags);
checkflagpile(o->flags);
@ -16010,7 +16061,7 @@ void timeeffectsob(object_t *o) {
contagious = B_TRUE;
}
// turn into a zombified version of itself.
lf = makezombie(o, 10, revivetext);
lf = makezombie(o, 10, revivetext, lf); // this will do the announcement
if (lf && contagious) {
addflag(lf->flags, F_HITCONFER, F_REVIVETIMER, SC_POISON, 165, NULL);
addflag(lf->flags, F_HITCONFERVALS, 0, 1, R_ZOMBIECON, "rises up as a zombie!");
@ -16018,7 +16069,7 @@ void timeeffectsob(object_t *o) {
addflag(lf->flags, F_HATESALL, B_TRUE, NA, NA, NULL);
} else {
// revive!
lf = addmonster(lfloc, f->val[2], NULL, B_FALSE, 1, B_FALSE, NULL);
lf = addmonster(lfloc, f->val[2], NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
// gain flags form corpse
copyflag(lf->flags, o->flags, F_CANWILL);
copyflag(lf->flags, o->flags, F_CANCAST);
@ -16029,11 +16080,11 @@ void timeeffectsob(object_t *o) {
// corpse vanishes
removeob(o, o->amt);
}
// announce
if (haslos(player, lfloc) || haslos(player, obloc)) {
msg("^W%s %s!^n", obname, revivetext);
interrupt(player);
// announce
if (haslos(player, lfloc) || haslos(player, obloc)) {
msg("^W%s %s!^n", obname, revivetext);
interrupt(player);
}
}
free(revivetext);
return;
@ -16838,6 +16889,11 @@ int validateobs(void) {
}
}
if (hasflag(ot->flags, F_ISMONSTER) && !hasflag(ot->flags, F_IMPASSABLE)) {
printf("ERROR in object '%s' - objects with f_ismonster MUST also have f_impassable too!\n", ot->name);
goterror = B_TRUE;
}
// remember buildings
if (ot->obclass->id == OC_BUILDING) {
if (hasflag(ot->flags, F_RARITY)) {

40
spell.c
View File

@ -2720,6 +2720,20 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// do the first one right away
rest(user, B_TRUE);
}
} else if (abilid == OT_A_TIPTOE) {
if (isswimming(user)) {
if (isplayer(user)) msg("You can't tiptoe while swimming!");
return B_TRUE;
}
if (isairborne(user, NULL)) {
if (isplayer(user)) msg("You can't tiptoe while airborne!");
return B_TRUE;
}
if (isclimbing(user)) {
if (isplayer(user)) msg("You can't tiptoe while climbing!");
return B_TRUE;
}
trysneak(user, D_NONE);
} else if (abilid == OT_A_TRIPLF) {
object_t *wep;
int skillmod = 0;
@ -3719,7 +3733,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
}
if (isplayer(user)) {
if (!safetorest(user)) {
if (!safetorest(user, NULL)) {
if (getattrbracket(getattr(user, A_WIS), A_WIS, NULL) >= AT_GTAVERAGE) {
if (askchar("Really try to hide while in view of enemies?", "yn", "n", B_TRUE, B_FALSE) != 'y') {
return B_TRUE;
@ -4387,9 +4401,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int sel,n;
sel = rnd(0,nposs-1);
o = poss[sel];
newlf = makezombie(o, power, "rises from the dead");
newlf = makezombie(o, power, "rises from the dead", target);
if (newlf) {
petify(newlf, target);
donesomething = B_TRUE;
}
// remove from list
@ -4482,7 +4495,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// add it!
getobname(o, obname, 1);
removeob(o, ALL);
lf = addmonster(targcell, f->val[0], NULL, B_FALSE, 1, B_FALSE, NULL);
lf = addmonster(targcell, f->val[0], NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
setlfmaterial(lf, MT_STONE, B_FALSE);
if (cansee(player, lf)) {
msg("%s comes to life!",obname);
@ -4528,7 +4541,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
getobname(o, obname, 1);
removeob(o, ALL);
lf = addmonster(targcell, rid, NULL, B_FALSE, 1, B_FALSE, NULL);
lf = addmonster(targcell, rid, NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
if (cansee(player, lf)) {
msg("%s comes to life!",obname);
if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -11420,6 +11433,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_REVEALHIDDEN) {
int i;
int seen = B_FALSE;
if (!isplayer(caster)) return B_TRUE;
if (!target) target = caster;
for (i = 0 ; i < target->nlos; i++ ){
targcell = target->los[i];
@ -11434,9 +11450,19 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
char obname[BUFLEN];
killflag(f);
getobname(o, obname, o->amt);
msg("%s is magically revealed!", obname);
msg("^G%s is magically revealed!", obname);
seen = B_TRUE;
}
if (hasflag(o->flags, F_ISMONSTER)) {
lifeform_t *newlf;
newlf = reveal_pretendob(o);
if (newlf) {
char lfname[BUFLEN];
getlfnamea(newlf, lfname);
msg("^G%s is magically revealed!", lfname);
seen = B_TRUE;
}
}
}
}
@ -15283,7 +15309,7 @@ int summonlfs(lifeform_t *caster, cell_t *where, enum RACE wantrace, enum RACECL
r = findrace(poss[rnd(0,nposs-1)]);
if (r) {
// add it!
newlf = addmonster(c, r->id, NULL, B_FALSE, 1, B_FALSE, NULL);
newlf = addmonster(c, r->id, NULL, B_FALSE, 1, B_FALSE, B_NOEXTRA, NULL);
// not worth any xp
killflagsofid(newlf->flags, F_XPVAL);
addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL);

1
text.c
View File

@ -1012,6 +1012,7 @@ char *getcolname(enum COLOUR c) {
case C_CARPET2: return "carpet2";
case C_METAL: return "metal";
case C_SMOKE: return "smoke";
case C_STONE: return "stone";
case C_WOOD: return "wood";
case C_DARKCYAN: return "darkcyan";
case C_DARKBLUE: return "darkblue";

View File

@ -416,7 +416,7 @@ int addvaultthing(cell_t *c, vault_t *v, enum VAULTTHING vt, char *what) {
break;
case VT_LF:
lf = addmonster(c, R_SPECIFIED, what, B_TRUE, 1, B_TRUE, NULL);
lf = addmonster(c, R_SPECIFIED, what, B_TRUE, 1, B_TRUE, B_NOEXTRA, NULL);
if (!lf) {
dblog("invalid racename '%s' in vault %s", what, v->id);
msg("invalid racename '%s' in vault %s", what, v->id);