- [+] if you cancel a limited wish, don't age you.

- [+] sourges shouldn't learn spells from books
- [+] MR doesn't affect canwill spells?
- [+] innate MR (ie. fromrace or from scource) doesn't affect spells
      either.
- [+] too many potions of water! made it common rather than frequent.
      now NO frequent potions.
- [+] getting 'wake t someone runmmaging through your pack' when noone
      nearby
    - [+] maybe this flag isn't gettginre removed properly?
- [+] polymorph should fix injuries first
* [+] for missing hand injuries, select the hand AFTER main switch()
* [+] shouldn't be able to weild 2-handed weapons if you only have 1
      hand!!!
- [+] "travel" spell should let you go to RT_HABITAT things.
- [+] fix crash validating f_spotted flag
- [+] don't always put "The " on unique objects.
    - [+] use F_THE for this instead.
    - [+] godstones should still have F_THE
- [+] don't place staircases inside MAINTAINEDGE vaults!!
- [+] burning a wood floor only makes a hole in the ground if there are
      more levels underneath!
- [+] end of caves:
    - [+] both bossrooms should have goblin king and red wyrmling
    - [+] stone key.
- [+] need a vault flag which say s: add f_stayinroom to everyone who
      is created in this room
    - [+] done: "keepmonsinroom"
- [+] cope with a branch's entry stairs coming from a vault 
- [+] killing unique monsters with necrotic damage should still leave a
      corpse.
- [+] make "ornate chest" which has rare objects
    - [+] put it in branch endings and make it a rare object
- [+] f_extrainfo in fireat() should show damage _after_ adjustment
- [+] BUG: swamp rooms aren't connected!!!!
- [+] end of forest branch:
    - [+] vault containing baba yaga's hut
        - [+] bone fence around it
        - [+] skeletons
        - [+] the hut.
    - [+] baba yaga's hut
        - [+] cabin on chicken legs
        - [+] f_timid!
        - [+] jump
        - [+] claw attacks
        - [+] walks around
        - [+] corpsetype = link to inside the hut
        - [+] made of dragonwood (ie. hardness 5)
        - [+] Don't say "You kill the walking hut".
        - [+] text when it dies: "Exhausted, the hut slumps to the
              ground."
    - [+] inside the hut = small level with baba yaga
        - [+] new regiontype: babayaga's hut
        - [+] new habitat: byhut
        - [+] making the habitat: only has a single vault. (one with
              tag 'byhut')
        - [+] diff layouts
            - [+] circular
            - [+] square
        - [+] baba yaga herself
    - [+] baba yaga
        - [+] weighs 50kg
        - [+] obs:
            - [+] key!
        - [+] hp: 135 = 22 hitdice (d6)
        - [+] 75% magic resistance
        - [+] attribs
            - [+] str: exhigh
            - [+] iq: exhigh
            - [+] wis: exhigh
            - [+] agi: average
            - [+] con: high
            - [+] cha: exlow
        - [+] fire, cold, magic, poison resist
        - [+] immune to  necrotic
        - [+] abilities
            - [+] seeinvis
            - [+] awareness
        - [+] claw/teeth attacks.
            - [+] claw = 8 DR
            - [+] teeth = 6 DR
            - [+] maxattacks = 2
        - [+] grab ability
        - [+] spells??????
            - [+] fear
            - [+] weaken
            - [+] summon insects/animals
            - [+] entangle
            - [+] blink
        - [+] when she dies, unlock the hut door.
- [+] delving code.
    - [+] new digging code:
        - [+] delve()
        - [+] delve_pullcell
        - [+] etc
    - [+] h_antnest
        - [+] creaetantnest calls delve() functions.
    - [+] insert this in the main dungeon somewhere
    - [+] populate with monsters (set rarity)
    - [+] place queen ant on the map.
        - [+] via new regionthing type RT_LF 
- [+] branch ends should have a boss with a key!
    - [+] jimbo
    - [+] babayaga
    - [+] cave boss (dragon ?)
This commit is contained in:
Rob Pearce 2012-04-04 09:59:48 +00:00
parent 252a4024a7
commit 892440031d
31 changed files with 1343 additions and 300 deletions

4
ai.c
View File

@ -786,7 +786,7 @@ int ai_attack_existing_target(lifeform_t *lf) {
if ( hasobwithflag(lf->cell->obpile, F_DEEPWATER) &&
!hasobwithflag(target->cell->obpile, F_DEEPWATER)) {
// move away!
if (!moveawayfrom(lf, target->cell, DT_ORTH, B_FALSE, B_TRUE)) {
if (!moveawayfrom(lf, target->cell, DT_ORTH, B_FALSE, B_TRUE, B_ONPURPOSE)) {
return B_TRUE;
}
}
@ -1759,7 +1759,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
}
} else if (dist < wantdistmin) {
if (db) dblog(".oO { moving away from target to maintain mindist %d. }", wantdistmin);
if (!moveawayfrom(lf, target->cell, DT_ORTH, B_KEEPLOF, B_TRUE)) { // maintain LOF, and keep facing the target
if (!moveawayfrom(lf, target->cell, DT_ORTH, B_KEEPLOF, B_TRUE, B_ONPURPOSE)) { // maintain LOF, and keep facing the target
// success
return B_FALSE;
} else {

View File

@ -1185,7 +1185,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// announce the hit
if (!feigneddeath) {
if (isplayer(lf) || isplayer(victim) || cansee(player, lf) || cansee(player, victim)) {
construct_hit_string(lf, victim, attackername, victimname, victimbpname, wep, damtype[i], dam[i], victim->maxhp, i, backstab, critical, fatal, isunarmed, buf);
construct_hit_string(lf, victim, attackername, victimname, victimbpname, wep, damtype[i], dam[i], victim->maxhp, i, backstab, critical, lfhasflag(victim, F_NOFATALTEXT) ? B_FALSE : fatal, isunarmed, buf);
if (strlen(buf)) {
warn("%s", buf);
}

209
data.c
View File

@ -1466,8 +1466,8 @@ void initobjects(void) {
addflag(lastobjectclass->flags, F_SMELLY, B_TRUE, NA, NA, NULL);
addoc(OC_GODSTONE, "Godstones", "Ancient artifacts, created by the elder gods.", '*', C_BOLDMAGENTA, RR_NEVER);
addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastobjectclass->flags, F_THE, NA, NA, NA, NULL);
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pulsating stone");
addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastobjectclass->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL);
@ -1627,6 +1627,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SHRINKSTO, OT_BED, VT_OB, NA, NULL);
addot(OT_GRATINGFLOOR, "drainage grate", "A hatchway in the ground made of strong iron mesh.", MT_METAL, 40, OC_DFEATURE, SZ_MEDIUM);
// important: don't make these in a swamp.
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_MAKESNOISE, 33, 3, NA, "a slow drip.");
addflag(lastot->flags, F_GLYPH, C_GREY, '#', NA, NULL);
@ -1650,6 +1651,7 @@ void initobjects(void) {
addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL);
addot(OT_HOLEINGROUND, "hole in the ground", "A gaping hole in the ground.", MT_NOTHING, 0, OC_DFEATURE, SZ_LARGE);
// important: don't make these in a swamp.
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
@ -1731,7 +1733,9 @@ void initobjects(void) {
killflagsofid(lastot->flags, F_SHOP);
// the exit to baba yaga's hut
addot(OT_BYHUTDOOR, "doorway", "The front door of Baba Yaga's hut.", MT_STONE, 3000, OC_DFEATURE, SZ_HUGE);
addot(OT_BYHUTDOOR, "hut's doorway", "The front door of Baba Yaga's hut.", MT_STONE, 3000, OC_DFEATURE, SZ_HUGE);
addflag(lastot->flags, F_UNIQUE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BROWN, '>', NA, NULL);
addflag(lastot->flags, F_CLIMBABLE, D_IN, NA, NA, "doorway");
addflag(lastot->flags, F_OPPOSITESTAIRS, OT_BABAYAGAHUT, NA, NA, NULL);
@ -2117,6 +2121,19 @@ void initobjects(void) {
addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL);
addflag(lastot->flags, F_SHRINKSTO, OT_ICESHEET, VT_OB, NA, NULL);
addot(OT_IRONBARS, "iron cage", "A series of vertical iron bars.", MT_METAL, 500, OC_DFEATURE, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_GREY, '|', NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_SMALL, SZ_MAX, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 120, 120, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL);
addflag(lastot->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL);
addflag(lastot->flags, F_GROWSTO, CT_WALLMETAL, VT_CELL, NA, NULL);
addflag(lastot->flags, F_SHRINKSTO, OT_IRONSTAFF, VT_OB, NA, NULL);
addot(OT_STATUE, "statue", "A stone statue of a monster.", MT_STONE, 80, OC_ROCK, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, "");
addflag(lastot->flags, F_RARITY, H_VILLAGE, NA, RR_COMMON, "");
@ -2599,8 +2616,8 @@ void initobjects(void) {
addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_VALUE, 30, NA, NA, NULL);
addot(OT_POT_WATER, "potion of water", "Plain, regular water.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_FREQUENT, NULL);
addflag(lastot->flags, F_RARITY, H_VILLAGE, 100, RR_FREQUENT, NULL);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_VILLAGE, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small puddle of water");
modflag(lastot->flags, F_HASHIDDENNAME, NA, NA, NA, "clear potion");
addflag(lastot->flags, F_VALUE, 5, NA, NA, NULL);
@ -3552,15 +3569,15 @@ void initobjects(void) {
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
// l3
addot(OT_S_CRYSTALSHIELD, "crystalline shield", "Summons a shield of ice crystals to protect you from missiles.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how effective the shield is.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
// l3
addot(OT_S_COLDRAY, "cold ray", "Shoots a blast of ice cold air, dealing 3d6 cold damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how difficult the ray is to dodge.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL);
@ -4758,8 +4775,25 @@ void initobjects(void) {
addot(OT_ORBDUNGEONEXIT, "dungeon exit orb", "When operated, this magical key will disable the barriers around the dungeon exit stairs.", MT_STONE, 2, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_GLYPH, C_MAGENTA, '[', NA, NULL);
addflag(lastot->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastot->flags, F_THE, NA, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addot(OT_KEYIRON, "ancient iron key", "An ancient key made from iron. It looks important.", MT_METAL, 2, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_GLYPH, C_GREY, '[', NA, NULL);
addflag(lastot->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addot(OT_KEYMOSS, "ancient mossy key", "An ancient key covered with moss. It looks important.", MT_METAL, 2, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_GLYPH, C_GREEN, '[', NA, NULL);
addflag(lastot->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addot(OT_KEYSTONE, "ancient stone key", "An ancient key made of stone. It looks important.", MT_METAL, 2, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_GLYPH, C_GREY, '[', NA, NULL);
addflag(lastot->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
// tools
addot(OT_BANDAGE, "bandage", "A small medical bandage. When worn, it will counteract bleeding.", MT_CLOTH, 0.5, OC_TOOLS, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL);
@ -5304,7 +5338,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GLYPH, NA, ',', NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addot(OT_CHEST, "chest", "A small wooden treasure chest.", MT_METAL, 40, OC_FURNITURE, SZ_MEDIUM);
addot(OT_CHEST, "chest", "An iron treasure chest.", MT_METAL, 40, OC_FURNITURE, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -5315,11 +5349,27 @@ void initobjects(void) {
addflag(lastot->flags, F_CANBELOCKED, 30, 10, NA, NULL);
addflag(lastot->flags, F_CANBETRAPPED, 20, 20, 66, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 90, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 80, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 70, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 60, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 90, 5, NA, NULL); // add 5 to depth for object rarity calculation
addflag(lastot->flags, F_STARTOBRND, 80, 5, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 70, 5, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 60, 5, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, 5, NA, NULL);
addot(OT_CHESTORNATE, "ornate chest", "An ornate golden treasure chest.", MT_GOLD, 80, OC_FURNITURE, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBELOCKED, 60, 10, NA, NULL);
addflag(lastot->flags, F_CANBETRAPPED, 50, 20, 100, NULL);
addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 90, 10, NA, NULL); // add 10 to depth for object rarity calculation
addflag(lastot->flags, F_STARTOBRND, 80, 10, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 70, 10, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 60, 10, NA, NULL);
addflag(lastot->flags, F_STARTOBRND, 50, 10, NA, NULL);
addot(OT_EMPTYFLASK, "empty flask", "An empty glass flask.", MT_GLASS, 0.2, OC_MISC, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -5817,7 +5867,7 @@ void initobjects(void) {
// effects
addot(OT_DUSTCLOUD, "large dust cloud", "A very thick cloud of dust particles.", MT_GAS, 0, OC_EFFECT, SZ_LARGE);
addflag(lastot->flags, F_GLYPH, C_BROWN, UNI_SHADEMED, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BROWN, UNI_SHADELIGHT, NA, NULL);
addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, 1, NA, NA, "small dust cloud");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
@ -8102,6 +8152,7 @@ void initobjects(void) {
addflag(lastot->flags, F_DAM, DT_SLASH, 100, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 500, NA, NA, NULL);
addflag(lastot->flags, F_UNIQUE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addot(OT_ICESHIELD, "ice crystal shield", "A summoned shield made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_SMALL);
@ -8292,6 +8343,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "armour");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "map");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "dungeon exit orb");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "old iron key");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "concealing powder");
addflag(lastrace->flags, F_FLEEONHPPCT, 40, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_POLEARMS, PR_ADEPT, NA, NULL);
@ -8308,8 +8360,8 @@ void initrace(void) {
addflag(lastrace->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, NA, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 20, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 20, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 16, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 17, 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, 2, 2, NA, NULL);
@ -8331,6 +8383,7 @@ void initrace(void) {
addflag(lastrace->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "ancient mossy key");
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_FEAR, NA, NA, "pw:3;");
addflag(lastrace->flags, F_CANCAST, OT_S_WEAKEN, NA, NA, "pw:5;");
@ -8348,6 +8401,7 @@ void initrace(void) {
addbodypart(lastrace, BP_BODY, "walls");
addbodypart(lastrace, BP_LEGS, "legs");
addbodypart(lastrace, BP_FEET, "feet");
addflag(lastrace->flags, F_NAME, NA, NA, NA, "Baba Yaga's hut");
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "wooden hut");
addflag(lastrace->flags, F_HOSTILE, NA, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL);
@ -8367,6 +8421,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STAYINROOM, NA, NA, NA, NULL);
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_JUMP, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 2, NA, "^clucking");
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
@ -9525,6 +9580,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 3, NA, NA, NULL);
@ -9631,6 +9687,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_EXLOW, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_VERYRARE, NULL);
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "splash of cockatrice blood");
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -9689,6 +9746,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 7, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 7, NA, NA, NULL);
@ -10246,8 +10304,8 @@ void initrace(void) {
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, 100, RR_FREQUENT, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_SWAMP, 100, RR_COMMON, NULL);
addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL);
@ -10293,6 +10351,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 4, NA, NA, NULL);
@ -11659,6 +11718,8 @@ void initrace(void) {
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "small dust cloud");
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "large dust cloud");
addflag(lastrace->flags, F_EXTRACORPSE, 50, NA, NA, "pile of sleeping powder");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL);
@ -11817,6 +11878,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_FREQUENT, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 4, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL);
@ -11845,6 +11907,7 @@ void initrace(void) {
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 4, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_PROJECTILE, NA, NA, NULL);
@ -12036,6 +12099,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 3, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 4, NA, NA, NULL);
@ -12090,7 +12154,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLL, NULL);
addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLL, "comes to life!");
addrace(R_TROLLKIN, "trollkin", 100, 't', C_GREY, MT_FLESH, RC_HUMANOID, "Trollkins are the horrific offspring of a troll and a human. While they lack the regenerative abilities of a standard troll, their human genes grant them a greater level of intelligence.");
setbodytype(lastrace, BT_HUMANOID);
@ -12162,7 +12226,7 @@ void initrace(void) {
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FROSTBITE, NA, NA, "exhales a freezing wind");
addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLLSNOW, NULL);
addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLLSNOW, "comes to life!");
addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_COLD, NA, "50");
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
@ -12202,7 +12266,50 @@ void initrace(void) {
addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLLSWAMP, NULL);
addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLLSWAMP, "comes to life!");
addrace(R_UNICORN, "unicorn", 500, 'u', C_WHITE, MT_FLESH, RC_ANIMAL, "Powerful steeds with gleaming coats of pure white, and a single ivory horn protruding from their forehead.");
setbodytype(lastrace, BT_QUADRAPED);
addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANTALK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_HIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_EXHIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VHIGH, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 5, NA, NA, NULL);
addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_HOOF, 6, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_HORN, 12, NA, NULL);
addflag(lastrace->flags, F_MAXATTACKS, 3, 3, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;");
//addflag(lastrace->flags, F_CANCAST, OT_S_SMITEEVIL, NA, NA, "pw:8;");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 4, NA, "screams in pain^screams of pain");
addflag(lastrace->flags, F_RESISTMAG, 10, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, 3, NA, NA, NULL);
addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL);
addflag(lastrace->flags, F_NOCHARM, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_TELEPORT, 20, 20, "pw:8;");
addflag(lastrace->flags, F_CANCAST, OT_S_CUREPOISON, 20, 20, "pw:10;");
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "raises its horn");
addflag(lastrace->flags, F_EQUINE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HATESRACE, R_ORC, NA, NA, NULL);
addflag(lastrace->flags, F_HATESRACE, R_GRIFFON, NA, NA, NULL);
addflag(lastrace->flags, F_HATESRACECLASS, RC_DRAGON, NA, NA, NULL);
addflag(lastrace->flags, F_EXTRACORPSE, 100, NA, NA, "unicorn horn");
addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL, "Xats are wild pigs with the claws of a dog.");
setbodytype(lastrace, BT_QUADRAPED);
@ -12445,6 +12552,7 @@ void initrace(void) {
addbodypart(lastrace, BP_BODY, "vines");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
addflag(lastrace->flags, F_HARMLESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -12494,6 +12602,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_HARMLESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -12518,6 +12627,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
addflag(lastrace->flags, F_HARMLESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -13036,6 +13146,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_FREQUENT, NULL);
addflag(lastrace->flags, F_NUMAPPEAR, 3, 4, NA, "");
addflag(lastrace->flags, F_ARMOURRATING, 4, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL);
@ -13065,6 +13176,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
@ -13097,6 +13209,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_ARMOURRATING, 4, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
@ -13607,7 +13720,8 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
addflag(lastrace->flags, F_WANTS, OT_NUT, B_COVETS, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "trumpets loudly^a loud trumpeting");
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
addflag(lastrace->flags, F_VISRANGEMOD, -2, NA, NA, NULL);
@ -13755,6 +13869,7 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_HITDICE, 3, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 4, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL);
@ -13809,6 +13924,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_HITDICE, 3, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 3, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 8, NA, NULL);
@ -13902,11 +14018,12 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_VERYSLOW, NA, NA, "");
addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, "");
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_FREQUENT, NULL);
addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_HITDICE, 7, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 7, NA, NA, NULL);
addflag(lastrace->flags, F_ARMOURRATING, 18, NA, NA, NULL);
@ -13936,11 +14053,12 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_VERYSLOW, NA, NA, "");
addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, "");
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_FREQUENT, NULL);
addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 5, NA, NA, NULL);
addflag(lastrace->flags, F_ARMOURRATING, 18, NA, NA, NULL);
@ -15222,6 +15340,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL);
addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_UNCOMMON, NULL);
addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL);
@ -16114,49 +16233,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTJOB, 25, J_NINJA, NA, NULL);
addflag(lastrace->flags, F_STARTJOB, 25, J_WARRIOR, NA, NULL);
addflag(lastrace->flags, F_STARTJOB, 100, J_WIZARD, SJ_RANDOM, NULL);
addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_REVENANT, NULL);
addrace(R_UNICORN, "unicorn", 500, 'u', C_WHITE, MT_FLESH, RC_ANIMAL, "Powerful steeds with gleaming coats of pure white, and a single ivory horn protruding from their forehead.");
setbodytype(lastrace, BT_QUADRAPED);
addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANTALK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_HIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_EXHIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VHIGH, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 5, NA, NA, NULL);
addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_HOOF, 6, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_HORN, 12, NA, NULL);
addflag(lastrace->flags, F_MAXATTACKS, 3, 3, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;");
//addflag(lastrace->flags, F_CANCAST, OT_S_SMITEEVIL, NA, NA, "pw:8;");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 4, NA, "screams in pain^screams of pain");
addflag(lastrace->flags, F_RESISTMAG, 10, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, 3, NA, NA, NULL);
addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL);
addflag(lastrace->flags, F_NOCHARM, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_TELEPORT, 20, 20, "pw:8;");
addflag(lastrace->flags, F_CANCAST, OT_S_CUREPOISON, 20, 20, "pw:10;");
addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "raises its horn");
addflag(lastrace->flags, F_EQUINE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HATESRACE, R_ORC, NA, NA, NULL);
addflag(lastrace->flags, F_HATESRACE, R_GRIFFON, NA, NA, NULL);
addflag(lastrace->flags, F_HATESRACECLASS, RC_DRAGON, NA, NA, NULL);
addflag(lastrace->flags, F_EXTRACORPSE, 100, NA, NA, "unicorn horn");
addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_REVENANT, "rises from the dead!");
addrace(R_VAMPIRE, "vampire", 75, 'V', C_BLUE, MT_FLESH, RC_UNDEAD, "Blood-drinking creatures of the night, vampires have pale white skin and prominent fangs protuding from their mouthes. They are said to be near immortal, able to survive even seemingly fatal attacks by converting themselves to a gaseous form.");
setbodytype(lastrace, BT_HUMANOID);

Binary file not shown.

View File

@ -0,0 +1,39 @@
! Boss room for sylvan woods
@id:babayagahut_1
@map
###########
#gBC+...|w#
#####...|w#
#.......SSS
#X.......FS
###+#...SSS
#...###+###
#sss#ppppp#
###########
@end
@legend
#:cell:wyrmwood wall
S:cell:brick wall
B:ob:bed
F:ob:brazier
s:ob:bookshelf
g:ob:grimoire
C:ob:ornate chest
+:ob:wooden door
p:ob:potion
|:ob:iron cage
X:ob:hut's doorway
w:ob:good weapon
w:ob:excellent weapon
@end
@flags
scatter(1,1,-2,-2) mon:Baba Yaga:1
norandom
mayrotate
tag:byhut
maintainedge
@end

View File

@ -0,0 +1,42 @@
! Boss room for sylvan woods
@id:babayagahut_2
@map
###################
######CcssscC######
###ccccccccccccc###
##cccccc...ccccc|##
#cccccc.ScS.cccc|.#
#Xccccc.cFc.cccc|.#
#cccccc.ScS.cccc|.#
##cccccc...ccccc|##
###ccccccccccccc###
######cccccBg######
###################
@end
@legend
#:cell:wyrmwood wall
S:cell:brick wall
c:cell:carpetted floor
B:ob:bed
F:ob:brazier
s:ob:bookshelf
g:ob:grimoire
C:ob:ornate chest
|:ob:iron cage
X:ob:hut's doorway
w:ob:great weapon
@end
@flags
scatter(2,2,-4,-4) mon:Baba Yaga:1
atoneof(17,4)(17,5)(17,6) ob:corpse
atoneof(17,4)(17,5)(17,6) ob:great weapon
atoneof(17,4)(17,5)(17,6) ob:cursed weapon
norandom
mayrotate
tag:byhut
maintainedge
@end

View File

@ -1,4 +1,4 @@
! Boss room for goblin caves
! Boss room for goblin caves - goblin king
@id:caveboss_1
@map
@ -6,8 +6,8 @@
#c......a.c.+AA###
#.w#.#.#.#..#AA+C#
+..........f####_#
#.w#.#.#.#..#WW+C#
#c......a.c.+WW###
#.w#.#.#.#.W#//+C#
#c......a.c.+//###
##################
@end
@ -15,26 +15,27 @@
#:cell:metal wall
f:ob:wooden footstool
f:mon:goblin king
W:mon:red wyrmling
a:mon:goblin archer
w:mon:goblin warrior
c:ob:lit candelabrum
+:ob:iron gate
+:exit
A:ob:good armour
W:ob:good weapon
A:ob:great armour
/:ob:great weapon
_:ob:pentagram
_:ob:Godstone of Destruction
C:ob:chest
_:ob:ancient stone key
C:ob:ornate chest
@end
@flags
goesin:cave
norandom
atoneof(10,1)(10,3)(10,5) ob:portal to lv1
scatter(1,1,-2,-2) ob:wooden footstool:0-3
scatter(1,1,-2,-2) ob:random food:0-2
mayflipx
tag:caveboss
maintainedge
nostairs
@end

View File

@ -1,4 +1,4 @@
! Boss room for goblin caves
! Boss room for goblin caves - red wyrmling
@id:caveboss_2
@map
@ -6,8 +6,8 @@
###.........######
#.......w.c.+AA###
#.w.........#AA+C#
+..........f####_#
#.w.........#WW+C#
+..........W####_#
#.w........f#WW+C#
#.......w.c.+WW###
###.........######
##################
@ -15,8 +15,9 @@
@legend
#:cell:metal wall
f:ob:wooden footstool
f:mon:red wyrmling
W:ob:wooden footstool
W:mon:red wyrmling
f:mon:goblin king
w:ob:goblin corpse
c:ob:lit candelabrum
+:ob:iron gate
@ -24,18 +25,19 @@ c:ob:lit candelabrum
A:ob:good armour
W:ob:good weapon
_:ob:pentagram
_:ob:Godstone of Destruction
C:ob:chest
_:ob:cursed excellent weapon
_:ob:ancient stone key
C:ob:ornate chest
@end
@flags
goesin:cave
norandom
atoneof(10,1)(10,3)(10,5) ob:portal to lv1
scatter(1,1,-2,-2) ob:wooden footstool:0-3
scatter(1,1,-2,-2) ob:random food:0-2
mayflipx
tag:caveboss
maintainedge
nostairs
@end

22
data/vaults/hut_shop.vlt Normal file
View File

@ -0,0 +1,22 @@
@id:hut_with_shop
@map
###
#s+
###
@end
@legend
#:cell:wooden wall
+:ob:wooden door
+:exit
s:ob:random shop
@end
@flags
goesin:dungeon
goesin:forest
rarity:uncommon
mayrotate
maintainedge
@end

View File

@ -34,5 +34,6 @@ scatter(1,1,-2,-2) ob:wooden footstool:0-3
scatter(1,1,-2,-2) ob:random food:0-2
mayrotate
maintainedge
nostairs
@end

View File

@ -42,5 +42,6 @@ scatter(0,0,-1,-1) ob:common weapon:4-5
mayrotate
! mayscale
rarity:rare
keepmonsinroom
maintainedge
@end

View File

@ -0,0 +1,20 @@
@id:boulder_circle
@map
.b.b.
b...b
.....
b...b
.b.b.
@end
@legend
.:cell:dirt
b:ob:boulder
@end
@flags
mayrotate
goesin:forest
rarity:common
@end

View File

@ -0,0 +1,20 @@
@id:tree_circle
@map
.t.t.
t...t
.....
t...t
.t.t.
@end
@legend
.:cell:dirt
t:ob:tree
@end
@flags
mayrotate
goesin:forest
rarity:frequent
@end

View File

@ -0,0 +1,18 @@
@id:tree_corridor
@map
ttt
...
ttt
@end
@legend
.:cell:dirt
t:ob:tree
@end
@flags
mayrotate
goesin:forest
rarity:frequent
@end

View File

@ -0,0 +1,36 @@
! Boss room for sylvan woods
@id:woodsboss_1
@map
..fffffff..
.ff.....ff.
ff..,,,,.ff
f..,,,,,,.f
+,,,,,,,_.f
f..,,,,,,.f
ff..,,,,.ff
.ff.....ff.
..fffffff..
@end
@legend
f:ob:bone fence
+:ob:bone gate
+:exit
,:cell:dirt
_:mon:walking hut
_:cell:dirt
@end
@flags
goesin:forest
norandom
scatter(2,2,-3,-3) ob:corpse:3-8
scatter(2,2,-3,-3) ob:bone:3-8
scatter(2,2,-3,-3) mon:skeleton:2-4
mayrotate
tag:forestboss
maintainedge
nostairs
@end

35
defs.h
View File

@ -78,8 +78,10 @@
#define B_TRUE (-1)
#define B_MAYBE (-2)
#define B_ONLYEXTERNAL (-1)
#define B_FORCE (-2)
#define B_ONPURPOSE (-1)
#define B_NOTONPURPOSE (0)
#define B_CHANGEDIR (-1)
#define B_VIS (1)
#define B_UNKNOWN (0)
@ -1091,7 +1093,6 @@ enum RACE {
R_TROLLSNOW,
R_TROLLSWAMP,
R_UNICORN,
R_VAMPIRE,
R_WEREBEAR,
R_WERERAT,
R_WEREWOLF,
@ -1220,6 +1221,7 @@ enum RACE {
R_SKELETON,
R_SKELETONFIRE,
R_SKELLION,
R_VAMPIRE,
R_WRAITHBOG,
R_WRAITHICE,
R_ZOMBIE,
@ -1325,6 +1327,7 @@ enum OBTYPE {
OT_GRATINGFLOOR,
OT_GRATINGROOF,
OT_ICICLE,
OT_IRONBARS,
OT_STATUE,
OT_DOORWOOD,
OT_DOORIRON,
@ -1832,6 +1835,9 @@ enum OBTYPE {
OT_WAND_WONDER,
// tools - unique
OT_ORBDUNGEONEXIT,
OT_KEYIRON,
OT_KEYMOSS,
OT_KEYSTONE,
// tools
OT_BAGOFHOLDING,
OT_BAGOFHOLDINGLARGE,
@ -1903,6 +1909,7 @@ enum OBTYPE {
// misc objects
OT_BONE,
OT_CHEST,
OT_CHESTORNATE,
OT_EMPTYFLASK,
OT_EMPTYVIAL,
OT_GLASSJAR,
@ -2212,7 +2219,7 @@ enum OBTYPE {
OT_PUSHW,
};
#define MAXBUILDINGTYPES (10)
#define MAXBUILDINGTYPES (11)
#define BP_NONE (-1)
@ -2384,6 +2391,7 @@ enum FLAG {
// v1 = VT_OB or VT_CELL
F_NOSHATTER, // object will not shatter, even if it's material should.
F_STACKABLE, // can stack multiple objects togethr
F_THE, // say "the xxx", not "a xxx"
F_NO_PLURAL, // this obname doesn't need an 's' for plurals (eg. gold, money)
F_NO_A, // this obname doesn't need to start with 'a' for singular (eg. gold)
F_CONTAINSOB, // for vending machiens. v0 is ob letter
@ -2482,6 +2490,8 @@ enum FLAG {
F_REVIVETIMER, // v0 = cur, v1 = max. v0 incremenets each tick.
// when v0 == v1, this object changes into lf of race
// v2.
// text = what to say when they come back to life.
// eg. "comes to life!", "rises from the dead."
F_LIFEOBFOR, // this ob is the lifeobject for lf id v0.
F_HOMEOBFOR, // this ob is a homeobject for lf id v0.
F_DTCONVERT, // damtype val0 converts this to f->text
@ -2924,7 +2934,11 @@ enum FLAG {
F_ACCURACYMOD, // modify your accuracy by val0
F_PLAYABLE, // player can select to be this race.
F_RACESLAY, // deal 4x damage to creatures of raceclass v0
F_NOFATALTEXT, // never say 'you kill xxx' for this lf
F_NOSTAIRS, // lf can't use stairs
// THIS CAN ALSO GO ON VAULTS:
// for vaults, it means that randomly created stairs
// cannot be created in this vault.
F_VAMPIRIC, // when on a lf:
// successful bite attacks from this lf will heal it
// when on an object
@ -3062,6 +3076,9 @@ enum FLAG {
// if v0 is not set, we won't leave our current room.
// if v1 is set (not NA), then we are allowed to chase
// our targets out of the room.
// THIS CAN ALSO GO ON VAULTS:
// for vaults, it means that monsters created in
// this vault will have: f_stayinroom, na, true, na
F_FALLDISTANCE, // how many floors this lf has fallen through.
// ABILITY/SPELL FLAGS / ability flags / spell flags
F_FAILEDINSPECT, // lf has failed an inspect check for objecttype v0
@ -3647,9 +3664,11 @@ enum INJURY {
IJ_WINGBRUISED,
// slashing
IJ_ARTERYPIERCE,
IJ_BRAINRUPTURED,
IJ_CHESTBLEED,
IJ_HAMSTRUNG,
IJ_HANDBLEED,
IJ_HEARTPIERCED,
IJ_LEGBLEED,
IJ_TENDONCUT,
IJ_FINGERMISSING,
@ -3659,6 +3678,7 @@ enum INJURY {
IJ_WINGBLEED,
IJ_WINGTORN,
// explosive
IJ_BLINDED,
IJ_EARSRINGING,
IJ_HANDMISSING,
IJ_LUNGCOLLAPSED,
@ -3940,6 +3960,7 @@ enum HABITAT {
H_STOMACH = 8,
H_SWAMP = 9,
H_BYHUT = 10,
H_ANTNEST = 11,
H_ALL = 999
};
@ -3958,7 +3979,10 @@ typedef struct regiontype_s {
} regiontype_t;
enum REGIONTHING {
RT_NONE = 0,
RT_HABITAT, // val is habitat
RT_LF, // text is a mosnter definition
// val is how many to place.
RT_OBJECT, // what is object name
RT_REGIONLINK, // val is enum regiontype to link to.
// what is stair object type
@ -4073,6 +4097,13 @@ typedef struct map_s {
struct map_s *next, *prev;
} map_t; //////////////// remember to modify save/load for new props!!
typedef struct cellstore_s {
struct cell_s **c;
int ncells;
int max;
int cutoff;
} cellstore_t;
#define MAXVAULTARGS 10
enum VAULTSTATE {

View File

@ -5,14 +5,7 @@ map.c:
initmap: define via addhabitat()
finalisemap():
define up/down stair types for this map
make a new function to create this kind of habitat
text.c:
update getregionname()
io.c:
update announcearrival()

View File

@ -5,6 +5,10 @@ map.c:
initmap(): define via new "addregiontype()" call
OPTIONAL: initmap(): define at least one regionoutline
finalisemap():
define up/down stair types for this map
create new habitats if required.
text.c:

4
god.c
View File

@ -933,7 +933,8 @@ int godgiftmaybe(enum RACE rid, int fromtemple) {
flag_t *f;
object_t *wep;
rollagain = B_FALSE;
switch (rnd(1,6)) {
switch (rnd(2,6)) {
/*
case 1:
if (lfhasflag(player, F_SEEINDARK)) {
rollagain = B_TRUE;
@ -943,6 +944,7 @@ int godgiftmaybe(enum RACE rid, int fromtemple) {
f->obfrom = god->race->id;
}
break;
*/
case 2:
snprintf(obtogive, BUFLEN, "cursed branded weapon");
break;

24
io.c
View File

@ -1207,10 +1207,9 @@ void announcearrival(lifeform_t *lf, map_t *newmap) {
} else {
flag_t *f;
switch (newmap->habitat->id) {
case H_DUNGEON:
msg("You arrive %sat dungeon level %d.",
(newmap->lastplayervisit == -1) ? "" : "back ",
newmap->depth);
case H_ANTNEST:
msg("You find yourself %sin a giant ant's nest.",
(newmap->lastplayervisit == -1) ? "" : "back ");
break;
case H_CAVE:
if ((newmap->depth == 1) && (newmap->lastplayervisit == -1)) {
@ -1221,6 +1220,23 @@ void announcearrival(lifeform_t *lf, map_t *newmap) {
newmap->depth);
}
break;
case H_DUNGEON:
msg("You arrive %sat dungeon level %d.",
(newmap->lastplayervisit == -1) ? "" : "back ",
newmap->depth);
break;
case H_FOREST:
if ((newmap->depth == 1) && (newmap->lastplayervisit == -1)) {
msg("You arrive in the sylvan woods.");
} else {
msg("You arrive %sat level %d of the sylvan woods.",
(newmap->lastplayervisit == -1) ? "" : "back ",
newmap->depth);
}
break;
case H_HEAVEN:
msg("You arrive in the Realm of the Gods!");
break;
case H_SWAMP:
msg("You arrive %sat a swamp.",
(newmap->lastplayervisit == -1) ? "" : "back ");

248
lf.c
View File

@ -1530,7 +1530,6 @@ int canweild(lifeform_t *lf, object_t *o) {
}
if (istwohandedfor(o, lf)) {
if (getlfsize(lf) <= f->val[0]) {
// need both hands free...
if (!hasbp(lf, otherloc)) {
reason = E_NOHANDS;
@ -1538,7 +1537,6 @@ int canweild(lifeform_t *lf, object_t *o) {
}
}
}
}
reason = E_OK;
@ -1805,7 +1803,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
power += countplantsinsight(lf);
limit(&power, NA, 10);
}
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 20 + power, 0) && !isgod(lf)) {
if (!willflag && real_getmr(lf, B_ONLYEXTERNAL) && skillcheck(lf, SC_RESISTMAG, 20 + power, 0) && !isgod(lf)) {
if (power > 1) {
// half strength
power /= 2;
@ -2892,7 +2890,29 @@ void die(lifeform_t *lf) {
}
}
// special cases based on race id
if (lf->race->id == R_BABAYAGAHUT) {
if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s slumps to the ground, exhausted.",lfname);
}
}
if (lf->race->id == R_BABAYAGA) {
object_t *exitob;
cell_t *exitcell;
// unlock the vault exit!
exitcell = findobinmap(lf->cell->map, OT_BYHUTDOOR);
exitob = hasob(exitcell->obpile, OT_BYHUTDOOR);
assert(exitob);
killflagsofid(exitob->flags, F_LOCKED);
if (haslos(player, exitcell)) {
char obname[BUFLEN];
getobname(exitob, obname, 1);
msg("%s unlocks with a loud 'click'.", obname);
}
noise(exitcell, NULL, NC_OTHER, SV_TALK, "a loud 'click'.", NULL);
}
if ((lf->race->id == R_VAMPIRE) && !hasflag(lf->flags, F_ORIGRACE)) {
// if are asleep or killed by running water/sunlight, we will die normally
if (lfhasflag(lf, F_ASLEEP) || (lf->lastdamtype == DT_DIRECT)) {
@ -2914,7 +2934,6 @@ void die(lifeform_t *lf) {
return;
}
}
if (lf->race->id == R_LICH) {
f = lfhasflag(lf, F_LIFEOB);
if (f) {
@ -3170,15 +3189,18 @@ void die(lifeform_t *lf) {
// shattered
fragments(corpsecell, "chunk of ice", 2, UNLIMITED);
} else {
int unique = B_FALSE;
if (lfhasflag(lf, F_UNIQUE)) unique = B_TRUE;
if (lfhasflag(lf, F_NOCORPSE)) {
if (isundead(lf) && cansee(player, lf)) {
getlfname(lf, buf);
msg("%s crumbles to dust.", buf);
}
} else if (lf->lastdamtype == DT_MELT) {
} else if (!unique && (lf->lastdamtype == DT_MELT)) {
// drop a pool of water
addob(corpsecell->obpile, "large puddle of water");
} else if (lf->lastdamtype == DT_NECROTIC) {
} else if (!unique && (lf->lastdamtype == DT_NECROTIC)) {
int n;
int numbones = 0;
char bonestring[BUFLEN];
@ -4156,8 +4178,8 @@ int eat(lifeform_t *lf, object_t *o) {
return B_TRUE;
}
}
// limit
if (nutrition > (HUNGERCONST/3)) nutrition = (HUNGERCONST/3);
// limit nutrition
if (nutrition > (HUNGERCONST/2)) nutrition = (HUNGERCONST/2);
rawmeat = B_TRUE;
}
@ -4731,7 +4753,7 @@ void enhanceskills(lifeform_t *lf) {
// pick randomly
att = rnd(0,MAXATTS-1);
}
modattr(lf, att, 2);
modattr(lf, att, 5);
f->val[2]--;
if (f->val[2] <= 0) {
killflag(f);
@ -5247,6 +5269,7 @@ int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) {
addflag(lf->flags, F_PRONE, B_TRUE, NA, NA, NULL);
loseconcentration(lf);
breakgrabs(lf, B_TRUE, B_TRUE);
if (isvulnto(lf->flags, DT_FALL, B_FALSE)) {
// 0 will be repplaced with the dtvuln flag
losehp(lf, 0, DT_FALL, fromlf, "a bad fall");
@ -5775,7 +5798,7 @@ int flee(lifeform_t *lf) {
if (db) dblog("%s - failed to flee via %s", lfname, stairs->type->name);
}
// move away from them
if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH, B_FALSE, B_FALSE)) {
if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH, B_FALSE, B_FALSE, B_NOTONPURPOSE)) {
if (db) dblog("%s - fleeing by moving away", lfname);
return B_TRUE;
}
@ -8293,13 +8316,29 @@ object_t *getmeleeweapon(lifeform_t *lf) {
int getmr(lifeform_t *lf) {
return real_getmr(lf, B_FALSE);
}
int real_getmr(lifeform_t *lf, int onlyexternal) {
int amt = 0;
if (onlyexternal) {
flag_t *f;
// sum all MR flags which DONT come from race/job
for (f = hasflag(lf->flags, F_RESISTMAG) ; f && (f->id == F_RESISTMAG) ; f = f->next) {
if ((f->lifetime != FROMRACE) && (f->lifetime != FROMJOB)) {
amt += f->val[0];
}
}
} else {
// sum all MR flags
sumflags(lf->flags, F_RESISTMAG, &amt, NULL, NULL);
// scourge gets job-based bonus
if (hassubjob(lf, SJ_SCOURGE)) {
amt += (gettr(lf) * 3);
}
}
return amt;
}
@ -10351,6 +10390,19 @@ void givesubjob(lifeform_t *lf, enum SUBJOB sj) {
addtempflag(lf->flags, F_LEVABIL, 16, OT_S_NULLIFY, NA, "pw:8;", FROMJOB);
addtempflag(lf->flags, F_LEVABIL, 18, OT_S_NULLIFY, NA, "pw:9;", FROMJOB);
addtempflag(lf->flags, F_LEVABIL, 20, OT_S_NULLIFY, NA, "pw:10;", FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_ALLOMANCY, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_MENTAL, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_NATURE, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_AIR, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_DEATH, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_DIVINATION, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_FIRE, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_COLD, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_LIFE, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_MODIFICATION, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_SUMMONING, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_TRANSLOCATION, NA, NA, NULL,FROMJOB);
addtempflag(lastrace->flags, F_NOSKILL, SK_SS_WILD, NA, NA, NULL,FROMJOB);
break;
//
@ -11411,7 +11463,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
case 4:
inj = IJ_TORSOBRUISEDBAD; break;
case 5:
inj = IJ_WINDED; howlong = rnd(3,5); break;
inj = IJ_WINDED; break;
}
break;
case BP_HANDS:
@ -11427,9 +11479,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
case BP_HEAD:
switch (rnd(1,4)) {
case 1:
if (!eyesshaded(lf)) {
inj = IJ_BLACKEYE;
}
break;
case 2:
inj = IJ_CONCUSSION;
@ -11476,14 +11526,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
switch (where) {
case BP_BODY:
if (pctchance(10)) {
if (isplayer(lf)) {
msg("^BYour heart is pierced!");
} else if (cansee(player, lf)) {
msg("^%c%s%s heart is pierced!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname));
}
if (lf->hp > 0) {
lf->hp = 0;
}
inj = IJ_HEARTPIERCED;
} else {
inj = IJ_CHESTBLEED; break;
}
@ -11497,39 +11540,12 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
case 3:
inj = IJ_ARTERYPIERCE; break;
case 4: // severed finger
if (onein(2)) bp2 = BP_RIGHTFINGER;
else bp2 = BP_LEFTFINGER;
if (hasbp(lf, bp2)) {
object_t *o;
addob(lf->cell->obpile, "severed finger");
o = getequippedob(lf->pack, bp2);
addflag(lf->flags, F_NOBODYPART, bp2, B_FROMINJURY, NA, NULL);
inj = IJ_FINGERMISSING;
howlong = PERMENANT;
if (o) {
char obname[BUFLEN];
if (isplayer(lf)) {
getobname(o,obname,o->amt);
msg("Your %s drops to the ground.",noprefix(obname));
} else if (cansee(player, lf)) {
getobname(o,obname,o->amt);
msg("%s%s %s drops to the ground.",lfname,getpossessive(lfname),noprefix(obname));
}
moveob(o, lf->cell->obpile, o->amt);
}
break;
}
break;
inj = IJ_FINGERMISSING; break;
}
break;
case BP_HEAD:
if (pctchance(10)) {
if (isplayer(lf)) {
msg("^BYour brain is ruptured!");
} else if (cansee(player, lf)) {
msg("^%c%s%s brain ruptures!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname));
}
if (lf->hp > 0) lf->hp = 0;
inj = IJ_BRAINRUPTURED;
} else {
switch (rnd(1,2)) {
case 1:
@ -11537,9 +11553,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
break;
case 2:
inj = IJ_EYEDESTROYED;
howlong = PERMENANT;
break;
}
}
break;
@ -11581,9 +11595,62 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
}
break;
case BP_HANDS:
inj = IJ_HANDMISSING;
break;
case BP_HEAD:
switch (rnd(1,2)) {
case 1: // ringing ears
inj = IJ_EARSRINGING; break;
case 2: // blinded
inj = IJ_BLINDED;
break;
}
break;
case BP_LEGS:
// lose limb
if (onein(2)) bp2 = BP_WEAPON;
break;
case BP_TAIL:
inj = IJ_TAILLACERATED;
break;
case BP_WINGS:
inj = IJ_WINGDESTROYED;
break;
default:
break;
}
}
}
// some injuries have extra effects before announcing the injury...
switch (inj) {
case IJ_BLACKEYE:
if (eyesshaded(lf)) {
inj = IJ_NONE;
}
break;
case IJ_BLINDED:
addtempflag(lf->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(50,100));
inj = IJ_NONE;
break;
case IJ_BRAINRUPTURED:
if (isplayer(lf)) {
msg("^BYour brain is ruptured!");
} else if (cansee(player, lf)) {
msg("^%c%s%s brain ruptures!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname));
}
if (lf->hp > 0) lf->hp = 0;
inj = IJ_NONE;
break;
case IJ_HANDMISSING:
// lose limb
if (onein(2)) {
if (hasbp(lf, BP_WEAPON)) bp2 = BP_WEAPON;
else bp2 = BP_SECWEAPON;
} else {
if (hasbp(lf, BP_SECWEAPON)) bp2 = BP_SECWEAPON;
else bp2 = BP_WEAPON;
}
if (hasbp(lf, bp2)) {
object_t *o[2];
enum BODYPART fingerbp;
@ -11599,7 +11666,6 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
}
addflag(lf->flags, F_NOBODYPART, bp2, B_FROMINJURY, NA, NULL);
addflag(lf->flags, F_NOBODYPART, fingerbp, B_FROMINJURY, NA, NULL);
inj = IJ_HANDMISSING;
howlong = PERMENANT;
for (i = 0; i < 2; i++) {
if (o[i]) {
@ -11615,34 +11681,63 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
moveob(o[i], lf->cell->obpile, o[i]->amt);
}
}
} else {
inj = IJ_NONE;
}
break;
case BP_HEAD:
// burnt eyes
switch (rnd(1,2)) {
case 1: // ringing ears
inj = IJ_EARSRINGING;
case 2: // blinded
addtempflag(lf->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(50,100));
case IJ_HEARTPIERCED:
if (isplayer(lf)) {
msg("^BYour heart is pierced!");
} else if (cansee(player, lf)) {
msg("^%c%s%s heart is pierced!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname));
}
if (lf->hp > 0) {
lf->hp = 0;
}
inj = IJ_NONE;
break;
case IJ_FINGERMISSING:
if (onein(2)) {
if (hasbp(lf, BP_RIGHTFINGER)) bp2 = BP_RIGHTFINGER;
else bp2 = BP_LEFTFINGER;
} else {
if (hasbp(lf, BP_LEFTFINGER)) bp2 = BP_LEFTFINGER;
else bp2 = BP_RIGHTFINGER;
}
if (hasbp(lf, bp2)) {
object_t *o;
addob(lf->cell->obpile, "severed finger");
o = getequippedob(lf->pack, bp2);
addflag(lf->flags, F_NOBODYPART, bp2, B_FROMINJURY, NA, NULL);
howlong = PERMENANT;
if (o) {
char obname[BUFLEN];
if (isplayer(lf)) {
getobname(o,obname,o->amt);
msg("Your %s drops to the ground.",noprefix(obname));
} else if (cansee(player, lf)) {
getobname(o,obname,o->amt);
msg("%s%s %s drops to the ground.",lfname,getpossessive(lfname),noprefix(obname));
}
moveob(o, lf->cell->obpile, o->amt);
}
break;
case BP_LEGS:
// lose limb
} else {
inj = IJ_NONE;
}
break;
case BP_TAIL:
inj = IJ_TAILLACERATED;
case IJ_EYEDESTROYED:
case IJ_TAILLACERATED:
case IJ_WINGDESTROYED:
howlong = PERMENANT;
break;
case BP_WINGS:
inj = IJ_WINGDESTROYED;
howlong = PERMENANT;
case IJ_WINDED:
howlong = rnd(3,5);
break;
default:
break;
}
}
}
// set description based on injury
switch (inj) {
@ -11687,6 +11782,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
case IJ_FINGERBROKEN: desc = strdup("finger is broken^acc penalty"); break;
case IJ_SHOULDERDISLOCATED: desc = strdup("shoulder is dislocated^acc penalty, cannot use heavy weapons"); break;
case IJ_ARTERYPIERCE: break; // fatal - no description
default:
case IJ_NONE: break;
}
@ -11701,6 +11797,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR
// special effects from taking injuries
if (damtype == DT_SLASH) bleed(lf, B_SPLATTER);
// extra effects after getting the injury.
switch (inj) {
case IJ_BLACKEYE:
case IJ_EYELIDSCRAPED:
@ -17946,8 +18043,12 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
}
}
}
}
// fix injuries
killflagsofid(lf->flags, F_INJURY);
// stop stoning.
killflagsofid(lf->flags, F_BEINGSTONED);
@ -18902,6 +19003,7 @@ void startlfturn(lifeform_t *lf) {
turntoface(lf, thief->cell);
}
killflagsofid(lf->flags, F_ASLEEP);
killflagsofid(lf->flags, F_WOKENBY);
}
@ -20120,7 +20222,7 @@ void startlfturn(lifeform_t *lf) {
lifeform_t *lf2;
lf2 = findlf(NULL, f->val[0]);
if (!lf || !cansee(lf, lf2) || !lfhasflag(lf2, F_HIDING)) {
if (!lf || !lf2 || !cansee(lf, lf2) || !lfhasflag(lf2, F_HIDING)) {
killflag(f);
continue;
}

1
lf.h
View File

@ -208,6 +208,7 @@ float getmaxpushweight(lifeform_t *lf);
float getmaxstamina(lifeform_t *lf);
object_t *getmeleeweapon(lifeform_t *lf);
int getmr(lifeform_t *lf);
int real_getmr(lifeform_t *lf, int onlyexternal);
int getvisrange(lifeform_t *lf, int useambient);
void idxtoxy(lifeform_t *lf, int idx, int *x, int *y);
//void setviscell(lifeform_t *lf, cell_t *cell, int how);

618
map.c
View File

@ -1381,6 +1381,385 @@ void clearcell_exceptflags(cell_t *c, ... ) {
}
}
// dungeon delving code from http://roguebasin.roguelikedevelopment.org/index.php/Delving_a_connected_cavern
// returns # of 'empty' cells created
int delve(map_t *map, int neighbourmin, int neighbourmax, int connchance, int chancepct, int newneighbourmin, int newneighbourmax, int newconnchance, enum CELLTYPE empty, enum CELLTYPE solid) {
cellstore_t *cs;
cell_t *c,*startcell;
int cellsdone = 0;
int wantcells;
int x,y;
int totcells;
int ngroups,ncount;
int changed = B_FALSE;
// calculate how many cells to fill based on parameters
/*
totcells = map->w * map->h;
minmax = neighbourmin + neighbourmax;
if (minmax <= 2) {
div = 8;
} else if (minmax == 3) {
div = 7;
} else if (minmax == 4) {
div = 6;
} else if (minmax <= 6) {
div = 5;
} else if (minmax <= 9) {
div = 4;
} else if (minmax <= 11) {
div = 3;
} else {
div = 2;
}
wantcells = totcells / div;
*/
wantcells = pctof(33,(map->w * map->h));
// start with all walls
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
c = getcellat(map, x, y);
if (c) {
setcelltype(c, solid);
}
}
}
// allocate datastore
cs = delve_makecellstore(map->w * map->h);
// select initial random spot
startcell = getcellat(map, map->w/2, map->h/2);
dblog("delve: initial cell is %d,%d.", startcell->x, startcell->y);
// add initial spot to the store
delve_storecell(cs, startcell);
dblog("delve: initial cellstore has %d cells.", cs->ncells);
// dig the initial 'seed' cells, and place their neighbours in the store.
while ( (cellsdone < (2*neighbourmin)) && (cellsdone < wantcells)) {
if (!delve_rndpull(cs, &c)) {
dblog("delve: rndpull failed during seeding!");
break;
}
ncount = countadjcellsoftype(c, empty, DT_COMPASS);
ngroups = delve_countadjgroups(c, empty);
// for the moment, stay close to the origin
if (c->type->solid && (getcelldist(c,startcell) <= 2) && (ncount <= neighbourmax) &&
((ngroups <= 1) || (pctchance(connchance)) ) ) {
int ndone;
dblog("delve: trying to seed %d,%d...", c->x, c->y);
ndone = delve_digcell(cs, c, empty, solid);
if (ndone) {
dblog("delve: success! cellstore now has %d cells.", cs->ncells);
} else {
dblog("delve: failed.");
}
cellsdone += ndone;
}
}
dblog("delve: seeded %d cells.", cellsdone);
// Main delving loop:
//
// while the wanted FLOOR count isn't reached, and drawing a cell succeedes:
// if the drawn cell is within map limits, and
// it is a WALL cell, and
// it has from ngb_min to ngb_max of FLOOR neighbours, and
// making it FLOOR either won't open new connections, or a random
// chance (connchance percent) allows opening a new connection,
// then the cell is made FLOOR, and its WALL neighbours are put in
// store in a random order.
dblog("delve: commencing main delve.");
while (cellsdone < wantcells) {
int xx,yy;
cell_t *c2;
char line[BUFLEN];
if (!delve_rndpull(cs, &c)) {
dblog("delve: rndpull failed during delving!");
break;
}
ncount = countadjcellsoftype(c, empty, DT_COMPASS);
ngroups = delve_countadjgroups(c, empty);
dblog("delve: pulled %d,%d (ncount=%d, groupcount=%d):", c->x, c->y, ncount, ngroups);
strcpy(line, "");
for (yy = c->y - 1; yy <= c->y + 1; yy++) {
for (xx = c->x - 1; xx <= c->x + 1; xx++) {
c2 = getcellat(map, xx, yy);
if (c2) {
if (c2->type->solid) {
strcat(line, "#");
} else {
strcat(line, ".");
}
} else {
strcat(line, "#");
}
}
dblog("%s",line);
strcpy(line, "");
}
dblog("%s",line);
strcpy(line, "");
if (c->type->solid && (ncount >= neighbourmin) && (ncount <= neighbourmax) &&
((ngroups <= 1) || pctchance(connchance)) ) {
int ndone;
dblog("delve: trying to delve %d,%d...", c->x, c->y);
ndone = delve_digcell(cs, c, empty, solid);
cellsdone += ndone;
if (ndone) {
dblog("delve: success! cellstore now has %d cells. dugcells=%d.", cs->ncells, cellsdone);
} else {
dblog("delve: failed.");
}
}
// after 50% of cells, chance params.
if ((chancepct >= 0) && !changed && (cellsdone >= pctof(chancepct, wantcells) ) ) {
changed = B_TRUE;
if (newneighbourmin != NA) neighbourmin = newneighbourmin;
if (newneighbourmax != NA) neighbourmax = newneighbourmax;
if (newconnchance != NA) connchance = newconnchance;
}
}
// clean up
delve_killcellstore(cs);
dblog("DELVE DEBUG:");
dblog(" PATTERN: ngb_min=%d, ngb_max=%d, connchance=%d", neighbourmin, neighbourmax, connchance);
dblog(" wanted cells: %d / %d (%d%%)", wantcells, totcells, (int) (((double)wantcells / (double)totcells)*(double)100) );
dblog(" dug cells: %d", cellsdone);
dblog("generated map:");
dumpmap(map, B_FALSE);
dblog("END DELVE DEBUG:");
return cellsdone;
}
// count how many 'groups' of celltype ct surround c.
int delve_countadjgroups(cell_t *centre, enum CELLTYPE ct) {
const int grouptable[256] = {
/********** 0 1 2 3 4 5 6 7 8 9 */
/* 000 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 2,
/* 010 */ 2, 2, 1, 1, 1, 1, 1, 2, 2, 2,
/* 020 */ 1, 1, 1, 1, 1, 2, 2, 2, 1, 1,
/* 030 */ 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
/* 040 */ 2, 3, 3, 3, 2, 2, 2, 2, 1, 2,
/* 050 */ 2, 2, 1, 1, 1, 1, 1, 2, 2, 2,
/* 060 */ 1, 1, 1, 1, 1, 1, 2, 1, 2, 1,
/* 070 */ 2, 1, 2, 2, 3, 2, 2, 1, 2, 1,
/* 080 */ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
/* 090 */ 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
/* 000 */ 2, 1, 2, 1, 2, 2, 3, 2, 2, 1,
/* 110 */ 2, 1, 1, 1, 2, 1, 1, 1, 1, 1,
/* 120 */ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
/* 130 */ 2, 1, 2, 1, 2, 1, 2, 2, 3, 2,
/* 140 */ 2, 1, 2, 1, 2, 2, 3, 2, 2, 1,
/* 150 */ 2, 1, 2, 2, 3, 2, 2, 1, 2, 1,
/* 160 */ 2, 2, 3, 2, 3, 2, 3, 2, 3, 3,
/* 170 */ 4, 3, 3, 2, 3, 2, 2, 2, 3, 2,
/* 180 */ 2, 1, 2, 1, 2, 2, 3, 2, 2, 1,
/* 190 */ 2, 1, 1, 1, 2, 1, 2, 1, 2, 1,
/* 200 */ 2, 2, 3, 2, 2, 1, 2, 1, 1, 1,
/* 210 */ 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
/* 220 */ 1, 1, 1, 1, 1, 1, 2, 1, 2, 1,
/* 230 */ 2, 1, 2, 2, 3, 2, 2, 1, 2, 1,
/* 240 */ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
/* 250 */ 2, 1, 1, 1, 1, 1
};
int d;
int bitmap = 0;
cell_t *c;
for (d = DC_N; d <= DC_NW; d++) {
bitmap >>= 1;
c = getcellindir(centre, d);
if (c && (c->type->id == ct)) {
bitmap |= 0x80;
}
}
return grouptable[bitmap];
/*
int enddir = DC_NW;
int groups = 0, ingroup = B_FALSE;
cell_t *c;
for (d = DC_N; d <= enddir; d++) {
c = getcellindir(centre, d);
if (c && (c->type->id == ct)) {
// special case if first cell checked (ie. N)
// matches - go backwards and see where this group
// started.
if (d == DC_N) {
int dd,foundend = B_FALSE;
for (dd = DC_NW; dd >= DC_NE; dd--){
cell_t *c2;
c2 = getcellindir(centre, dd);
// doesn't match? stop here.
if (!c2 || (c2->type->id != ct)) {
enddir = dd;
foundend = B_TRUE;
break;
}
}
if (!foundend) {
// ie. completely surrounded by
// correct type. this means 1 group.
return 1;
}
}
if (!ingroup) {
groups++;
ingroup = B_TRUE;
} else {
// still in a group...
}
} else {
// not in a group anymore
ingroup = B_FALSE;
}
}
return groups;
*/
}
int delve_cuberoot(int num) {
int rv,delta;
if (!num) return 0;
if (num < 1000) rv = 10;
else if (num < 1000000) rv = 100;
else if (num < 1000000000) rv = 1000;
else rv = 1290;
do {
delta = (num - (rv * rv * rv)) / (2 * rv * rv);
rv += delta;
} while (delta);
if ((rv * rv * rv) > num) {
rv--;
}
return rv;
}
// fills 'centre' with celltype 'empty', and stores any neighboughts with celltype 'solid'
// into the cellstore (in random order).
//
// returns the number of cells dug (ie. 1 or 0)
int delve_digcell(cellstore_t *cs, cell_t *centre, enum CELLTYPE empty, enum CELLTYPE solid) {
int dir[8] = { DC_N, DC_NE, DC_E, DC_SE, DC_S, DC_SW, DC_W, DC_NW};
int i;
if (!centre || !centre->type->solid) {
return 0;
}
setcelltype(centre, empty);
// shuffle directions
for (i = 0 ; i < 8; i++) {
int newpos;
int temp;
newpos = rnd(0,7);
temp = dir[newpos];
dir[newpos] = dir[i];
dir[i] = temp;
}
for (i = 0; i < 8; i++) {
cell_t *c;
c = getcellindir(centre, dir[i]);
if (c && c->type->solid) {
delve_storecell(cs, c);
}
}
return 1;
}
cellstore_t *delve_makecellstore(int maxsize) {
cellstore_t *cs;
cs = malloc(sizeof(cellstore_t));
cs->max = maxsize;
cs->ncells = 0;
cs->c = malloc(maxsize * sizeof(cell_t));
cs->cutoff = (pctof(2, maxsize));
return cs;
}
void delve_killcellstore(cellstore_t *cs) {
free(cs->c); cs->c = NULL;
free(cs);
}
// pulls a random cell from the datastore
// if the datastore has < cs->cutoff cells, return a random cell.
// otherwise, return a random cell from within the bottom cells.
// if it isn't the topmost cell which is pulled, then move the topmost one to
// its place.
cell_t *delve_rndpull(cellstore_t *cs, cell_t **c) {
int index,min,max;
*c = NULL;
if (cs->ncells <= 0) return NULL;
// *** "fluffy" patterns
if (cs->ncells < cs->cutoff) {
min = 0;
max = cs->ncells -1;
} else {
//int cuberoot;
//cuberoot = delve_cuberoot(cs->ncells);
//min = cs->ncells - (5*cuberoot) - 1;
//min = pctof(75, cs->ncells);
//max = cs->ncells - 1;
min = 0;
max = pctof(30, cs->ncells);
}
// compact patterns
/*
min = 0;
max = cs->ncells - 1;
*/
index = rnd(min,max);
*c = cs->c[index];
// not the topmost? topmost moves to here.
if (index != (cs->ncells-1)) {
cs->c[index] = cs->c[cs->ncells-1];
}
cs->ncells -= 1;
return *c;
}
// stores cell position 'c' into the store.
// if there's no more space, replace a random cell.
void delve_storecell(cellstore_t *cs, cell_t *c) {
if (cs->ncells < cs->max) {
cs->c[cs->ncells] = c;
(cs->ncells)++;
} else {
cs->c[rnd(0,cs->ncells-1)] = c;
}
}
int damagecell(cell_t *c, int amt, enum DAMTYPE damtype) {
if (!c->type->solid) return B_TRUE;
// adjust dam
@ -1671,21 +2050,45 @@ void floodfill(cell_t *startcell) {
}
}
// populates thing & nthings with all "regionthings" with
// populates thing & nthings with all "regionthings" with:
// whatkind == RT_REGIONLINK.
// OR
// whatkind = RT_HABITAT
// ie. links to all the map branches.
// returns # found
int getbranchlinks(regionthing_t **thing, int *nthings) {
int getbranchlinks(regionthing_t **thing, int *nthings, ...) {
va_list args;
int i;
enum REGIONTHING wantthingtype[MAXCANDIDATES];
int ntypes = 0;
region_t *r;
regionthing_t *temp;
va_start(args, nthings);
wantthingtype[ntypes] = va_arg(args, enum REGIONTHING);
while (wantthingtype[ntypes] != RT_NONE) {
ntypes++;
wantthingtype[ntypes] = va_arg(args, enum REGIONTHING);
}
va_end(args);
assert(ntypes < MAXCANDIDATES);
*nthings = 0;
for (r = firstregion ; r ; r = r->next) {
if (!r->outline) continue;
for (i = 0; i < r->outline->nthings; i++ ){
int n,ok = B_FALSE;
// pick a random regionlink thing.
temp = &r->outline->thing[i];
// valid ?
for (n = 0; n < ntypes; n++) {
if (temp->whatkind == wantthingtype[n]) {
ok = B_TRUE;
}
}
if (ok) {
if (temp->whatkind == RT_REGIONLINK) {
regiontype_t *rtype;
rtype = findregiontype(temp->value);
@ -1693,6 +2096,9 @@ int getbranchlinks(regionthing_t **thing, int *nthings) {
(rtype->id != RG_WORLDMAP)) {
thing[(*nthings)++] = temp;
}
} else if (temp->whatkind == RT_HABITAT) {
thing[(*nthings)++] = temp;
}
}
}
}
@ -2278,13 +2684,21 @@ int countadjcellswithflag(cell_t *cell, enum FLAG fid, int dirtype) {
return count;
}
int countadjcellsoftype(cell_t *cell, int id) {
int countadjcellsoftype(cell_t *cell, enum CELLTYPE id, int dirtype) {
int d;
int count = 0;
int start,end;
cell_t *newcell;
for (d = D_N; d < MAXDIR_ORTH; d++) {
if (dirtype == DT_ORTH) {
start = D_N;
end = D_W;
} else { // ie. DT_COMPASS
start = DC_N;
end = DC_NW;
}
for (d = start; d <= end; d++) {
newcell = getcellindir(cell, d);
if (newcell && newcell->type->id == id) {
if (newcell && (newcell->type->id == id)) {
count++;
}
}
@ -2429,6 +2843,38 @@ int countstairs(map_t *m, int dir) {
return count;
}
void createantnest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) {
int x,y;
cell_t *c;
enum CELLTYPE emptycell,solidcell;
int ndug = 0;
// fill entire maze with walls
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
addcell(map, x, y);
}
}
map->illumination = IL_FULLLIT;
// what kind of cells will 'empty' ones be?
emptycell = getmapempty(map);
solidcell = getmapsolid(map);
// pick initial random point
c = getrandomcell(map);
// delve out the ant's nest
ndug = 0;
while (ndug < 10) {
ndug = delve(map, 2, 3, 5, 75, 1, 1, 5, emptycell, solidcell);
}
// now do a border, just in case.
createborder(map, solidcell);
}
void createborder(map_t *map, enum CELLTYPE solidtype) {
int x,y;
cell_t *c;
@ -2513,6 +2959,7 @@ void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *
// is the map lit?
/*
if (depth == 1) {
map->illumination = IL_FULLLIT;
} else {
@ -2524,6 +2971,8 @@ void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *
map->illumination = IL_FULLLIT;
}
}
*/
map->illumination = IL_FULLLIT;
// what kind of cells will 'empty' ones be?
emptycell = getmapempty(map);
@ -3063,38 +3512,13 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_
} // end if wantrooms & nrooms>0
if (db) dblog("Finished adding stuff to rooms.");
// river?
if ((depth >= 4) && pctchance(20)) {
createriver(map);
}
// now do a border
y = 0;
for (x = 0; x < map->w; x++) {
// n
c = getcellat(map, x, 0);
clearcell(c);
setcelltype(c,solidcell);
c->locked = B_TRUE;
// s
c = getcellat(map, x, map->h-1);
clearcell(c);
setcelltype(c,solidcell);
c->locked = B_TRUE;
}
for (y = 1; y < map->h-1; y++) {
// w
c = getcellat(map, 0, y);
clearcell(c);
setcelltype(c,solidcell);
c->locked = B_TRUE;
// e
c = getcellat(map, map->w-1, y);
clearcell(c);
setcelltype(c,solidcell);
c->locked = B_TRUE;
}
createborder(map, solidcell);
}
void createfakes(map_t *map, cell_t *cell) {
@ -3222,6 +3646,9 @@ void createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir, object_
case H_DUNGEON:
createdungeon(map, depth, parentmap, exitdir, entryob);
break;
case H_ANTNEST:
createantnest(map, depth, parentmap, exitdir, entryob);
break;
case H_CAVE:
createcave(map, depth, parentmap, exitdir, entryob);
break;
@ -3585,6 +4012,13 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL);
addob(c->obpile, thing[i]->what);
break;
case RT_LF:
if (db) dblog(" adding forced regionthing lifeform: %s", thing[i]->what);
c = getrandomroomcell(map, ANYROOM, WE_WALKABLE);
if (!c) c = getrandomcell(map);
c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL);
addmonster(c, R_SPECIFIED, thing[i]->what, B_FALSE, thing[i]->value, B_TRUE, NULL);
break;
case RT_REGIONLINK:
if (db) dblog(" adding regionlink");
createregionlink(map, NULL, NULL, thing[i]->what, thing[i]->value, map->region);
@ -3618,6 +4052,8 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
failed = B_TRUE;
}
break;
case RT_NONE:
break;
}
}
//if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging
@ -4188,23 +4624,30 @@ void createswamp(map_t *map, int depth, map_t *parentmap, int exitdir, object_t
// first create a normal dungeon
createdungeon(map, depth, parentmap, exitdir, entryob);
// remove all doors and grates
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
c = getcellat(map, x, y);
// replace all walls with water
if (c->type->solid) {
setcelltype(c, CT_LOWFLOOR);
addob(c->obpile, "very deep water");
}
// remove all doors
for (o = c->obpile->first ; o ; o = nexto) {
int willkill = B_FALSE;
nexto = o->next;
if (isdoor(o, NULL)) {
if (isdoor(o, NULL) ) {
willkill = B_TRUE;
} else if (hasflagval(o->flags, F_PIT, D_DOWN, NA, NA, NULL)) {
// should never happen h_swamp due to no rarity flags.
willkill = B_TRUE;
} else if (o->type->id == OT_GRATINGFLOOR) {
// should never happen h_swamp due to no rarity flags.
willkill = B_TRUE;
}
if (willkill) {
killob(o);
}
}
}
}
// finalisemap() will replace all walls with deep water.
}
int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *retx, int *rety) {
@ -5332,6 +5775,7 @@ void finalisemap(map_t *map, object_t *entryob) {
char roomlightob[BUFLEN],corridorlightob[BUFLEN];
int roomlightchance = 0;
int corridorlightfreq = 0;
int nupstairsreq = 0,ndownstairsreq = 0;
int nupstairsneeded = 0,ndownstairsneeded = 0;
cell_t *c;
object_t *o,*nexto;
@ -5343,14 +5787,17 @@ void finalisemap(map_t *map, object_t *entryob) {
upstairtype = map->habitat->upstairtype;
downstairtype = map->habitat->downstairtype;
nupstairsneeded = map->region->rtype->stairsperlev - countmapobs(map, upstairtype);
ndownstairsneeded = map->region->rtype->stairsperlev - countmapobs(map, downstairtype);
nupstairsreq = map->region->rtype->stairsperlev;
ndownstairsreq = map->region->rtype->stairsperlev;
// override # up stairs for first level of a branch.
// override # up stairs for first level of a branch (we only want one up staircase)
if (hasflag(map->flags, F_FIRSTINBRANCH)) {
nupstairsneeded = 1;
nupstairsreq = 1;
}
nupstairsneeded = nupstairsreq - countmapobs(map, upstairtype);
ndownstairsneeded = ndownstairsreq - countmapobs(map, downstairtype);
if ( (nupstairsneeded && (upstairtype == OT_NONE)) ||
(ndownstairsneeded && (downstairtype == OT_NONE)) ) {
@ -5395,7 +5842,7 @@ void finalisemap(map_t *map, object_t *entryob) {
c = NULL;
while (!c || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM, WE_EMPTY);
if (!c) {
while (!c || (getcellvault(c) && hasflag(c->room->vault->flags, F_NOSTAIRS))) {
// ANY cell at all, doesn't have to be a room.
c = getrandomcell(map);
c = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND);
@ -5417,13 +5864,32 @@ void finalisemap(map_t *map, object_t *entryob) {
}
}
// if our up stairs were created by a vault, then we now need to link them.
if (entryob && !linkedentry) {
for (y = 0; (y < map->h) && !linkedentry; y++) {
for (x = 0; (x < map->w) && !linkedentry; x++) {
c = getcellat(map, x, y);
o = hasob(c->obpile, upstairtype);
if (o && !hasflag(o->flags, F_MAPLINK)) {
linkstairs(o, entryob);
linkedentry = B_TRUE;
break;
}
}
}
if (!linkedentry) {
dblog("ERROR - couldn't link stairs back to map entry object.");
msg("ERROR - couldn't link stairs back to map entry object."); more();
}
}
// DOWN STAIRS
if ((downstairtype != OT_NONE) && (map->depth < map->region->rtype->maxdepth)) {
for (i = 0; i < ndownstairsneeded; i++) {
c = NULL;
while (!c || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM, WE_EMPTY);
if (!c) {
while (!c || (getcellvault(c) && hasflag(c->room->vault->flags, F_NOSTAIRS))) {
// ANY cell at all, doesn't have to be a room.
c = getrandomcell(map);
c = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND);
@ -5442,7 +5908,7 @@ void finalisemap(map_t *map, object_t *entryob) {
nexto = o->next;
if (c->room && c->room->vault) {
} else {
// doors which go nowhere?
// remove doors which go nowhere
if (isdoor(o, NULL)) {
int dir, ok = B_FALSE;
cell_t *c2;
@ -5523,6 +5989,22 @@ void finalisemap(map_t *map, object_t *entryob) {
}
}
// in swamps, replace all walls with deep water
if (map->habitat->id == H_SWAMP) {
int x,y;
cell_t *c;
for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) {
c = getcellat(map, x, y);
// replace all walls with water
if (c->type->solid) {
setcelltype(c, CT_LOWFLOOR);
addob(c->obpile, "very deep water");
}
}
}
}
}
void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags, enum BEHAVIOUR wantbehaviour, int idx) {
@ -5530,6 +6012,7 @@ void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags,
enum FLAG noflag[MAXCANDIDATES];
int nnoflags = 0,i;
int mapdiff;
vault_t *v;
mapdiff = getmapdifficulty(lf->cell->map)/2;
@ -5609,6 +6092,12 @@ void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags,
}
}
// if monster is in a vault, check its flags...
v = getcellvault(lf->cell);
if (v) {
copyflags(lf->flags, v->flags, F_STAYINROOM);
}
/*
getflags(lf->flags, retflag, &nretflags, F_LIFEOB, F_NONE);
for (i = 0; i < nretflags; i++) {
@ -6530,13 +7019,14 @@ void initmap(void) {
addhabitat(H_SEWER, "sewer", CT_CORRIDOR, CT_WALL, 5, 50, 0, MAXVISRANGE, OT_NONE, OT_NONE);
addhabitat(H_STOMACH, "stomach", CT_FLOORFLESH, CT_WALLFLESH, 5, 80, 0, MAXVISRANGE, OT_NONE, OT_NONE);
addhabitat(H_SWAMP, "swamp", CT_CORRIDOR, CT_WALL, 3, 50, 0, MAXVISRANGE, OT_STAIRSUP, OT_STAIRSDOWN);
addhabitat(H_BYHUT, "babayaga's hut", CT_CORRIDOR, CT_WALLDWOOD, 0, 0, 0, MAXVISRANGE, OT_BYHUTDOOR, OT_NONE);
addhabitat(H_BYHUT, "babayaga's hut", CT_FLOORWOOD, CT_WALLDWOOD, 0, 0, 0, MAXVISRANGE, OT_BYHUTDOOR, OT_NONE);
addhabitat(H_ANTNEST, "ant nest", CT_DIRT, CT_WALLDIRT, 5, 40, 0, MAXVISRANGE, OT_STAIRSUP, OT_STAIRSDOWN);
// cell types - solid
// floorheight, hp
addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0, 50);
addcelltype(CT_WALLBRICK, "brick wall", UNI_SHADEDARK, C_ORANGE, B_SOLID, B_OPAQUE, MT_STONE, 0, 40);
addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEDARK, C_BROWN, B_SOLID, B_OPAQUE, MT_STONE, 0, 20);
addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEMED, C_BROWN, B_SOLID, B_OPAQUE, MT_STONE, 0, 20);
addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, B_SOLID, B_OPAQUE, MT_WOOD, 0, 30);
addcelltype(CT_WALLDWOOD, "wyrmwood wall", UNI_SOLID, C_BROWN, B_SOLID, B_OPAQUE, MT_DRAGONWOOD, 0, 100);
addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, B_SOLID, B_OPAQUE, MT_FLESH, 0, 25);
@ -6622,8 +7112,12 @@ void initmaplayout(void) {
addregionthing(lastregionoutline, rnd(2,4), NA, NA, RT_REGIONLINK, RG_CAVE, "tunnel leading down");
// l6: jimbo's lair
addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair");
// l7 - 10: swamp
addregionthing(lastregionoutline, rnd(7,10), NA, NA, RT_HABITAT, H_SWAMP, NULL);
// l7 - 10: ants nest
i = rnd(7,10);
addregionthing(lastregionoutline, i, NA, NA, RT_HABITAT, H_ANTNEST, NULL);
addregionthing(lastregionoutline, i, NA, NA, RT_LF, NA, "queen ant");
// l11 - 14: swamp
addregionthing(lastregionoutline, rnd(11,14), NA, NA, RT_HABITAT, H_SWAMP, NULL);
// l25: last level
addregionthing(lastregionoutline, 25, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISSHRINE, NULL); // godstone on last floor
@ -6649,6 +7143,9 @@ void initmaplayout(void) {
addregionoutline(RG_CAVE);
addregionthing(lastregionoutline, 5, NA, NA, RT_RNDVAULTWITHTAG, NA, "caveboss");
addregionoutline(RG_WOODS);
addregionthing(lastregionoutline, 5, NA, NA, RT_RNDVAULTWITHTAG, NA, "forestboss");
// add initial regions
addregion(RG_WORLDMAP, NULL, -1, 0, -1);
addregion(RG_HEAVEN, NULL, -1, 0, -1);
@ -6950,6 +7447,13 @@ int isroom(cell_t *c) {
return B_FALSE;
}
int issolid(cell_t *c) {
if (!c || c->type->solid) {
return B_TRUE;
}
return B_FALSE;
}
int iswallindir(cell_t *cell, int dir) {
cell_t *newcell;
newcell = getcellindir(cell, dir);
@ -7067,6 +7571,9 @@ int linkstairs(object_t *o, object_t *o2) {
assert(o);
// make sure these stairs aren't already linked.
assert(!hasflag(o->flags, F_MAPLINK));
staircell = getoblocation(o);
stairmap = staircell->map;
@ -7867,6 +8374,7 @@ int validateregionthing(regionthing_t *thing) {
map_t fakemap;
int goterrors = B_FALSE;
object_t *o;
enum RACE rid;
createfakes(&fakemap, &fakecell);
switch (thing->whatkind) {
case RT_HABITAT:
@ -7875,6 +8383,16 @@ int validateregionthing(regionthing_t *thing) {
goterrors = B_TRUE;
}
break;
case RT_LF:
rid = parserace(thing->what, NULL, NULL, NULL, NULL);
if (rid == R_NONE) {
dblog("Invalid lifeform '%s' specified in regionthing.", thing->what);
goterrors = B_TRUE;
} else if (thing->value <= 0) {
dblog("Invalid lifeform count (%d) specified in regionthing.", thing->value);
goterrors = B_TRUE;
}
break;
case RT_OBJECT:
o = addob(fakecell.obpile, thing->what);
if (!o) {
@ -7906,6 +8424,8 @@ int validateregionthing(regionthing_t *thing) {
goterrors = B_TRUE;
}
break;
case RT_NONE:
break;
}
killfakes(&fakemap, &fakecell);
return goterrors;

13
map.h
View File

@ -20,12 +20,20 @@ int cellmatchescondition(cell_t *c, int wecond);
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 delve(map_t *map, int neighbourmin, int neighbourmax, int connchance, int chancepct, int newneighbourmin, int newneighbourmax, int newconnchance, enum CELLTYPE empty, enum CELLTYPE solid);
int delve_countadjgroups(cell_t *centre, enum CELLTYPE ct);
int delve_cuberoot(int num);
int delve_digcell(cellstore_t *cs, cell_t *centre, enum CELLTYPE empty, enum CELLTYPE solid);
cellstore_t *delve_makecellstore(int maxsize);
void delve_killcellstore(cellstore_t *cs);
cell_t *delve_rndpull(cellstore_t *cs, cell_t **c);
void delve_storecell(cellstore_t *cs, 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);
void floodfill(cell_t *startcell);
int getbranchlinks(regionthing_t **thing, int *nthings);
int getbranchlinks(regionthing_t **thing, int *nthings, ...);
cell_t *getcellat(map_t *map, int x, int y);
int getcellclimbdifficulty(cell_t *c);
int getcellclimbdifficultyavg(cell_t *c);
@ -52,7 +60,7 @@ object_t *gettopobject(cell_t *where, int forglyph);
void calclight(map_t *map);
int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int *by, int force);
int compassdir(int orthdir);
int countadjcellsoftype(cell_t *cell, int id);
int countadjcellsoftype(cell_t *cell, enum CELLTYPE id, int dirtype);
int countadjrooms(cell_t *cell);
int countadjcellswithflag(cell_t *cell, enum FLAG fid, int dirtype);
int countadjdoors(cell_t *cell);
@ -151,6 +159,7 @@ int isnighttime(void);
int isonmap(map_t *map, int x, int y);
int isoutdoors(map_t *m);
int isroom(cell_t *c);
int issolid(cell_t *c);
int iswallindir(cell_t *cell, int dir);
void killcell(cell_t *c);
void killcelltype(celltype_t *ct);

4
move.c
View File

@ -994,7 +994,7 @@ int makeorthogonal(int dir) {
}
// see 'movetowards' for description of dirtype
int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int strafe ) {
int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int strafe, int onpurpose ) {
int dir;
int rv = B_TRUE;
@ -1008,7 +1008,7 @@ int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int st
if (dir == D_NONE) {
rv = B_TRUE;
} else {
rv = trymove(lf, dir, B_TRUE, strafe);
rv = trymove(lf, dir, onpurpose, strafe);
}
return rv;
}

2
move.h
View File

@ -15,7 +15,7 @@ cell_t *getdodgecell(lifeform_t *lf);
int getwalkoffdir(lifeform_t *lf, int dir);
int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallcheckdiff, int wantannounce);
int makeorthogonal(int dir);
int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int strafe);
int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int strafe, int onpurpose);
int moveclear(lifeform_t *lf, int dir, enum ERROR *error);
int moveeffects(lifeform_t *lf, int moved);
int movelf(lifeform_t *lf, cell_t *newcell);

View File

@ -1172,9 +1172,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
// special checks for unique objects
if (hasflag(ot->flags, F_UNIQUE)) {
object_t *origob;
// does this unique ob already exist?
if (obexists(ot->id)) {
if (db) dblog("DB: Unique ob %s already exists!", p );
origob = obexists(ot->id);
if (origob) {
if (db) dblog("DB: Unique ob %s already exists!", ot->name );
nretobs = 0;
killflagpile(wantflags);
return NULL;
@ -1769,7 +1771,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
int nposs = 0;
// fill in map destination.
if (!wantregionthing) {
getbranchlinks(poss, &nposs);
getbranchlinks(poss, &nposs, RT_REGIONLINK, RT_NONE);
if (nposs) {
wantregionthing = poss[rnd(0,nposs-1)];
@ -5789,7 +5791,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
strcpy(prefix, "");
}
} else {
if (hasflag(o->flags, F_UNIQUE) && isknown(o)) {
if (hasflag(o->flags, F_THE) && isknown(o)) {
strcpy(prefix, "The ");
} else {
if (needan(localbuf)) {
@ -6114,9 +6116,14 @@ char *real_getrandomob(map_t *map, char *buf, int forcedepth, int forcehabitat,
}
}
// find possibilities
nposs = 0;
for (i = 0; i < nbuildingusage; i++) {
if (buildingusage[i].count == minused) {
poss[nposs++] = findot(buildingusage[i].oid);
enum OBTYPE thisoid;
thisoid = buildingusage[i].oid;
poss[nposs] = findot(thisoid);
assert(poss[nposs]);
nposs++;
}
}
assert(nposs > 0);
@ -13137,6 +13144,10 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
}
}
reduceamt = getarmourdamreduction(target, o, dam, DT_PROJECTILE);
applyarmourdamreduction(target, o, reduceamt, &dam, DT_PROJECTILE);
// announce
if (haslos(player, where)) {
char buf2[BUFLEN];
@ -13156,9 +13167,6 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
}
snprintf(damstring, BUFLEN, "%s (%s by %s)",realobname,throwverbpast, realthrowernamea);
reduceamt = getarmourdamreduction(target, o, dam, DT_PROJECTILE);
applyarmourdamreduction(target, o, reduceamt, &dam, DT_PROJECTILE);
if (dam > 0) {
lifeform_t *whogetsxp = NULL;
@ -13502,7 +13510,9 @@ void timeeffectsob(object_t *o) {
break;
case CT_FLOORWOOD:
setcelltype(location, CT_CORRIDOR);
if (location->map->depth < location->map->region->rtype->maxdepth) {
burnoid = OT_HOLEINGROUND;
}
break;
default:
// stone floor
@ -13790,7 +13800,7 @@ void timeeffectsob(object_t *o) {
removeob(o, o->amt);
// announce
if (haslos(player, lfloc) || haslos(player, obloc)) {
msg("^W%s comes to life!^n", obname);
msg("^W%s %s!^n", obname, f->text);
interrupt(player);
}
return;
@ -14490,9 +14500,12 @@ int validateobs(void) {
// remember buildings
if (ot->obclass->id == OC_BUILDING) {
if (hasflag(ot->flags, F_RARITY)) {
buildingusage[nbuildingusage].oid = ot->id;
buildingusage[nbuildingusage].count = 0;
nbuildingusage++;
assert(nbuildingusage <= MAXBUILDINGTYPES);
}
}
if ((ot->obclass->id == OC_SPELL) || (ot->obclass->id == OC_ABILITY)) {

50
spell.c
View File

@ -8122,7 +8122,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
cell_t *dstcell = NULL;
if (!isplayer(caster)) return B_TRUE;
// ask which region to go to
getbranchlinks(poss, &nposs);
getbranchlinks(poss, &nposs, RT_REGIONLINK, RT_HABITAT, RT_NONE);
if (!nposs) {
fizzle(caster);
return B_TRUE;
@ -8131,22 +8131,32 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
prompt.maycancel = B_TRUE;
for (i = 0; i < nposs; i++) {
char choicetext[BUFLEN];
regiontype_t *destregiontype;
if (poss[i]->whatkind == RT_REGIONLINK) {
destregiontype = findregiontype(poss[i]->value);
addchoice(&prompt, ch++, destregiontype->name, NULL, poss[i], NULL);
strcpy(choicetext, destregiontype->name);
} else if (poss[i]->whatkind == RT_HABITAT) {
habitat_t *h;
h = findhabitat(poss[i]->value);
strcpy(choicetext, h->name);
}
capitalise(choicetext);
addchoice(&prompt, ch++, choicetext, NULL, poss[i], NULL);
}
ch = getchoice(&prompt);
rt = (regionthing_t *)prompt.result;
if (!rt) {
msg("Cancelled.");
return B_TRUE;
}
depth = rt->depth;
// find region containing this link.
findregionthing(rt->id, &srcregion);
if (srcregion) {
object_t *dstob = NULL;
region_t *destregion = NULL;
map_t *srcmap;
if (isplayer(caster)) {
@ -8161,18 +8171,33 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
srcmap = addmap();
createmap(srcmap, depth, srcregion, NULL, D_NONE, NULL);
}
if (rt->whatkind == RT_REGIONLINK) {
object_t *dstob = NULL;
region_t *destregion = NULL;
// find the regionlink object. ie. the stairs/portal which goes to
// the given region.
destregion = findregionbytype(rt->value);
dstob = findmapobwithflagval(srcmap, F_CLIMBABLE, NA, destregion->id, NA, NULL);
assert(dstob);
dstcell = getoblocation(dstob);
} else if (rt->whatkind == RT_HABITAT) {
// on top of the 'up' staircase
dstcell = findobinmap(srcmap, srcmap->habitat->upstairtype);
if (!dstcell) {
dstcell = getrandomcell(srcmap);
}
}
} else {
msg("srcregion doesnt exist!");
}
if (dstcell && !cellwalkable(caster, dstcell, NULL)) {
dstcell = real_getrandomadjcell(dstcell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL);
}
if (dstcell) {
// make sure it's walkable
teleportto(caster, dstcell, B_FALSE);
} else {
fizzle(caster);
@ -9121,9 +9146,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// on the ground?
for (o = c->obpile->first ; o ; o = o->next) {
char obname[BUFLEN];
real_getobname(o, obname, o->amt, B_PREMODS, B_CONDITION, B_NOBLINDADJUST,
B_NOBLESSINGS, B_USED, B_NOSHOWALL);
if (strcasestr(obname, wantname)) {
if (!hasflag(o->flags, F_TRAIL) && strcasestr(obname, wantname)) {
char ptext[BUFLEN];
char distbuf[BUFLEN],dirbuf[BUFLEN];
getdisttext(caster->cell, c, distbuf, NULL, dirbuf);
@ -12230,6 +12256,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
addchoice(&prompt, 'd', "Fame", NULL, NULL, NULL);
addchoice(&prompt, 'e', "Knowledge", NULL, NULL, NULL);
addchoice(&prompt, 'f', "Magic", NULL, NULL, NULL);
addchoice(&prompt, '-', "(nothing)", NULL, NULL, NULL);
if (isplayer(target)) {
ch = getchoice(&prompt);
} else {
@ -12392,6 +12419,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else {
strcpy(buf, "");
}
} else if (ch == '-') { // ie. nothing
if (isplayer(target)) {
msg("You resist the temptation of instant gratification.");
if (frompot || fromob) {
// small wisdom increase
modattr(target, A_WIS, 2);
}
}
return B_FALSE;
}
if (strlen(buf)) {

41
text.c
View File

@ -1941,15 +1941,34 @@ int needses(char *text) {
return B_FALSE;
}
// remove 'the ', 'an ', 'a ', '1 ' etc
char *noprefix(char *obname) {
char *p;
p = strchr(obname, ' ');
if (p) {
p++;
return p;
} else {
return obname;
int donesomething = B_TRUE;
p = obname;
while (donesomething) {
donesomething = B_FALSE;
if (strcasestarts(p, "the ")) {
p += strlen("the ");
donesomething = B_TRUE;
}
if (strcasestarts(p, "an ")) {
p += strlen("an ");
donesomething = B_TRUE;
}
if (strcasestarts(p, "a ")) {
p += strlen("a ");
donesomething = B_TRUE;
}
if (isdigit(*p)) {
// skip to after the first space
while (isdigit(*p) || (*p == ' ')) {
p++;
}
donesomething = B_TRUE;
}
}
return p;
}
char *numtotext(int num, char *buf) {
@ -2113,6 +2132,16 @@ char *strends(char *a, char *suffix) {
return NULL;
}
char *strcasestarts(char *a, char *prefix) {
if (!a || !prefix) return NULL;
if (strcasestr(a, prefix) == a) {
return a;
}
return NULL;
}
char *strstarts(char *a, char *prefix) {
if (!a || !prefix) return NULL;

1
text.h
View File

@ -64,6 +64,7 @@ char *strrep(char *text, char *oldtok, char *newtok, int *rv);
char *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv);
int streq(char *a, char *b);
char *strends(char *a, char *suffix);
char *strcasestarts(char *a, char *prefix);
char *strstarts(char *a, char *prefix);
int strlen_without_colours(char *buf);
int strpixmatch(char *haystack, char *needle);

View File

@ -1345,9 +1345,15 @@ int handleline(vault_t *v, char *line) {
} else {
dblog("invalid goesin() definition: '%s'", line);
}
} else if (streq(line, "keepmonsinroom")) {
addflag(v->flags, F_STAYINROOM, NA, B_TRUE, NA, NULL);
ok = B_TRUE;
} else if (streq(line, "maintainedge")) {
addflag(v->flags, F_MAINTAINEDGE, B_TRUE, NA, NA, NULL);
ok = B_TRUE;
} else if (strstarts(line, "nostairs")) {
addflag(v->flags, F_NOSTAIRS, B_TRUE, NA, NA, NULL);
ok = B_TRUE;
} else if (strstarts(line, "margin")) {
char *p;
p = line + 6;