diff --git a/doc/evilhack-changelog.md b/doc/evilhack-changelog.md index a9f76c402..ebe305e00 100644 --- a/doc/evilhack-changelog.md +++ b/doc/evilhack-changelog.md @@ -2198,4 +2198,5 @@ The following changes to date are: - Implement new dragon armor system: DSM replaced by scaled armor (dtsund) - Fix: a couple small issues with dtsund-DSM implementation - Some minor player monster armor tweaks +- Tortle as a playable race diff --git a/include/mondata.h b/include/mondata.h index 2102d9970..17a87d095 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -240,6 +240,10 @@ ((((ptr)->mhflags & MH_ILLITHID) != 0L) \ || ((ptr) == youmonst.data && !Upolyd && Race_if(PM_ILLITHID))) #define racial_illithid(mon) mon_has_race(mon, MH_ILLITHID) +#define is_tortle(ptr) \ + ((((ptr)->mhflags & MH_TORTLE) != 0L) \ + || ((ptr) == youmonst.data && !Upolyd && Race_if(PM_TORTLE))) +#define racial_tortle(mon) mon_has_race(mon, MH_TORTLE) #define your_race(ptr) (((ptr)->mhflags & urace.selfmask) != 0L) #define racial_match(mon) mon_has_race(mon, urace.selfmask) #define is_bat(ptr) \ diff --git a/include/monflag.h b/include/monflag.h index 0f2165fe8..4612578af 100644 --- a/include/monflag.h +++ b/include/monflag.h @@ -179,16 +179,17 @@ #define MH_HOBBIT 0x00000040L #define MH_CENTAUR 0x00000080L #define MH_ILLITHID 0x00000100L +#define MH_TORTLE 0x00000200L /* Flags below not used as a player race */ -#define MH_UNDEAD 0x00000200L -#define MH_WERE 0x00000400L -#define MH_DEMON 0x00000800L -#define MH_DRAGON 0x00001000L -#define MH_ANGEL 0x00002000L -#define MH_OGRE 0x00004000L -#define MH_TROLL 0x00008000L -#define MH_GNOLL 0x00010000L -#define MH_JABBERWOCK 0x00020000L +#define MH_UNDEAD 0x00000400L +#define MH_WERE 0x00000800L +#define MH_DEMON 0x00001000L +#define MH_DRAGON 0x00002000L +#define MH_ANGEL 0x00004000L +#define MH_OGRE 0x00008000L +#define MH_TROLL 0x00010000L +#define MH_GNOLL 0x00020000L +#define MH_JABBERWOCK 0x00040000L #define MH_ANY 0x80000000L diff --git a/src/attrib.c b/src/attrib.c index 01a516d4c..d82bca74b 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -128,6 +128,8 @@ static const struct innate { { 0, 0, 0, 0 } }, cen_abil[] = { { 1, &(HFast), "", "" }, + /* use EJumping here, otherwise centaurs would only + be able to jump the same way as knights */ { 5, &(EJumping), "light on your hooves", "weighted down" }, { 10, &(HWarning), "sensitive", "" }, { 0, 0, 0, 0 } }, @@ -147,6 +149,12 @@ static const struct innate { /* also inediate */ { 0, 0, 0, 0 } }, + trt_abil[] = { { 1, &(HSwimming), "", "" }, + { 1, &(HMagical_breathing), "", "" }, + { 5, &(HWarning), "sensitive", "" }, + { 12, &(HRegeneration), "resilient", "less resilient" }, + { 0, 0, 0, 0 } }, + hum_abil[] = { { 0, 0, 0, 0 } }; STATIC_DCL void NDECL(exerper); @@ -245,7 +253,9 @@ boolean givemsg; { int num = incr; - if ((!num) || (((Race_if(PM_GIANT)) || (Race_if(PM_CENTAUR))) && (!(otmp && otmp->cursed)))) { + if ((!num) || ((Race_if(PM_GIANT) + || Race_if(PM_CENTAUR) || Race_if(PM_TORTLE)) + && (!(otmp && otmp->cursed)))) { if (ABASE(A_STR) < 18) num = (rn2(4) ? 1 : rnd(6)); else if (ABASE(A_STR) < STR18(85)) @@ -840,6 +850,9 @@ long frommask; case PM_DEMON: abil = dem_abil; break; + case PM_TORTLE: + abil = trt_abil; + break; case PM_HUMAN: abil = hum_abil; break; @@ -1031,6 +1044,9 @@ int oldlevel, newlevel; case PM_ILLITHID: rabil = ill_abil; break; + case PM_TORTLE: + rabil = trt_abil; + break; case PM_HUMAN: case PM_DWARF: case PM_GNOME: diff --git a/src/do_wear.c b/src/do_wear.c index 5c4ae3167..6a83e9f78 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -534,6 +534,7 @@ Helmet_on(VOID_ARGS) switch (uarmh->otyp) { case FEDORA: + case TOQUE: case HELMET: case DENTED_POT: case ELVEN_HELM: @@ -622,6 +623,7 @@ Helmet_off(VOID_ARGS) switch (uarmh->otyp) { case FEDORA: + case TOQUE: case HELMET: case DENTED_POT: case ELVEN_HELM: @@ -2184,6 +2186,13 @@ boolean noisy; helm_simple_name(otmp), plur(num_horns(youmonst.data))); err++; + } else if (Race_if(PM_TORTLE) && is_hard(otmp)) { + /* Tortles can't retreat back into their shells + whilst wearing rigid head gear */ + if (noisy) + pline_The("%s is too rigid to wear.", + helm_simple_name(otmp)); + err++; } else *mask = W_ARMH; } else if (is_shield(otmp)) { @@ -2222,6 +2231,14 @@ boolean noisy; c_boots); /* makeplural(body_part(FOOT)) yields "rear hooves" which sounds odd */ err++; + } else if (Race_if(PM_TORTLE)) { + /* Tortles can't retreat back into their shells + whilst wearing footwear, plus their shape is + all wrong */ + if (noisy) + pline("Your %s are not shaped correctly to wear %s.", + makeplural(body_part(FOOT)), c_boots); + err++; } else if (u.utrap && (u.utraptype == TT_BEARTRAP || u.utraptype == TT_INFLOOR || u.utraptype == TT_LAVA @@ -2258,6 +2275,13 @@ boolean noisy; Your("%s are too slippery to pull on %s.", fingers_or_gloves(FALSE), gloves_simple_name(otmp)); err++; + } else if (Race_if(PM_TORTLE) && is_hard(otmp)) { + /* Tortles can't retreat back into their shells + whilst wearing rigid gauntlets */ + if (noisy) + pline_The("%s are too rigid to wear.", + gloves_simple_name(otmp)); + err++; } else *mask = W_ARMG; } else if (is_shirt(otmp)) { @@ -2596,9 +2620,15 @@ find_ac() * Giants can't wear body armor, t-shirt or cloaks, * but they do have thick skin. So they get a little bit * of love in the AC department to compensate somewhat. - */ + * + * Tortles have even more armor restrictions than giants. + * The large shell that makes up a good portion of their + * body provides exceptional protection */ int uac = maybe_polyd(mons[u.umonnum].ac, - Race_if(PM_GIANT) ? 6 : mons[u.umonnum].ac); + Race_if(PM_GIANT) + ? 6 : Race_if(PM_TORTLE) + ? 0 : mons[u.umonnum].ac); + /* armor class from worn gear */ diff --git a/src/mhitm.c b/src/mhitm.c index 36a3baecc..2fd7e75f1 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -192,7 +192,8 @@ int target, roll; fmt = "%s %s %s"; Sprintf(buf, fmt, s_suffix(Monnam(mdef)), (is_dragon(mdef->data) ? "scaly hide" - : mdef->data == &mons[PM_GIANT_TURTLE] + : (mdef->data == &mons[PM_GIANT_TURTLE] + || is_tortle(mdef->data)) ? "protective shell" : "thick hide"), (rn2(2) ? "blocks" : "deflects")); diff --git a/src/mhitu.c b/src/mhitu.c index c911536b7..30a05e4f4 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -157,16 +157,16 @@ struct attack *mattk; /* get object responsible, work from the closest to the skin outwards */ - /* Try undershirt */ if (uarmu && !uarm && !uarmc && target <= roll) { + /* Try undershirt */ target += armor_bonus(uarmu); if (target > roll) blocker = uarmu; } - /* Try body armour */ if (uarm && !uarmc && target <= roll) { + /* Try body armour */ target += armor_bonus(uarm); if (target > roll) blocker = uarm; @@ -218,18 +218,20 @@ struct attack *mattk; if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); - if (could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan) + if (could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan) { pline("%s pretends to be friendly.", Monnam(mtmp)); - else { - if (!flags.verbose || (!nearmiss && !blocker)) + } else { + if (!flags.verbose || (!nearmiss && !blocker)) { pline("%s misses.", Monnam(mtmp)); - else if (nearmiss || !blocker) { - if (thick_skinned(youmonst.data) && rn2(2)) { + } else if (nearmiss || !blocker) { + if ((thick_skinned(youmonst.data) || Race_if(PM_TORTLE)) + && rn2(2)) { Your("%s %s %s attack.", - (is_dragon(youmonst.data) ? "scaly hide" - : youmonst.data == &mons[PM_GIANT_TURTLE] - ? "protective shell" - : "thick hide"), + (is_dragon(youmonst.data) ? "scaly hide" + : (youmonst.data == &mons[PM_GIANT_TURTLE] + || Race_if(PM_TORTLE)) + ? "protective shell" + : "thick hide"), (rn2(2) ? "blocks" : "deflects"), s_suffix(mon_nam(mtmp))); } else { @@ -237,9 +239,9 @@ struct attack *mattk; : rn2(2) ? You("evade %s attack!", s_suffix(mon_nam(mtmp))) : pline("%s narrowly misses!", Monnam(mtmp)); } - } else if (blocker == &zeroobj) + } else if (blocker == &zeroobj) { pline("%s is stopped by your golden haze.", Monnam(mtmp)); - else + } else { Your("%s %s%s %s attack.", blocker->oartifact ? xname(blocker) : simple_typename(blocker->otyp), @@ -247,6 +249,7 @@ struct attack *mattk; ((blocker == uarmg && blocker->oartifact != ART_DRAGONBANE) || blocker == uarmf) ? "" : "s", s_suffix(mon_nam(mtmp))); + } if (!blocker) goto end; /* called if attacker hates the material of the armor @@ -3839,15 +3842,18 @@ int dmg; || !m_canseeu(mtmp) || mtmp->mspec_used) return FALSE; - if (canseemon(mtmp) && (Deaf)) + if (canseemon(mtmp) && Deaf) { pline("It looks as if %s is yelling at you.", mon_nam(mtmp)); - if (!cancelled && ((m_canseeu(mtmp) && Blind && Deaf))) + } else if (!cancelled && m_canseeu(mtmp) + && Blind && Deaf) { You("sense a disturbing vibration in the air."); - else if (m_canseeu(mtmp) && canseemon(mtmp) && !Deaf && cancelled) + } else if (m_canseeu(mtmp) && canseemon(mtmp) + && !Deaf && cancelled) { pline("%s croaks hoarsely.", Monnam(mtmp)); - else if (cancelled && !Deaf) + } else if (cancelled && !Deaf) { You_hear("a hoarse croak nearby."); + } /* Set mspec->mused */ mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6)); @@ -3857,38 +3863,47 @@ int dmg; /* scream attacks */ switch (mattk->adtyp) { - case AD_LOUD: - if (m_canseeu(mtmp)) - pline("%s lets out a bloodcurdling scream!", Monnam(mtmp)); - else if (u.usleep && m_canseeu(mtmp) && (!Deaf)) - unmul("You are frightened awake!"); + case AD_LOUD: + if (m_canseeu(mtmp)) + pline("%s lets out a bloodcurdling scream!", Monnam(mtmp)); + else if (u.usleep && m_canseeu(mtmp) && (!Deaf)) + unmul("You are frightened awake!"); + + if (uarmh && uarmh->otyp == TOQUE && !Deaf) { + pline("Your %s protects your ears from the sonic onslaught.", + helm_simple_name(uarmh)); + break; + } else { Your("mind reels from the noise!"); make_stunned((HStun & TIMEOUT) + (long) dmg, TRUE); stop_occupation(); + } - if (!rn2(6)) - erode_armor(&youmonst, ERODE_FRACTURE); - if (!rn2(5)) - erode_obj(uwep, (char *) 0, ERODE_FRACTURE, EF_DESTROY); - if (!rn2(6)) - erode_obj(uswapwep, (char *) 0, ERODE_FRACTURE, EF_DESTROY); - if (rn2(2)) - destroy_item(POTION_CLASS, AD_LOUD); - if (!rn2(4)) - destroy_item(RING_CLASS, AD_LOUD); - if (!rn2(4)) - destroy_item(TOOL_CLASS, AD_LOUD); - if (!rn2(3)) - destroy_item(WAND_CLASS, AD_LOUD); - - if (u.umonnum == PM_GLASS_GOLEM) { - You("shatter into a million pieces!"); - rehumanize(); - break; - } - break; - default: + /* being deaf won't protect objects in inventory, + or being made of glass */ + if (!rn2(6)) + erode_armor(&youmonst, ERODE_FRACTURE); + if (!rn2(5)) + erode_obj(uwep, (char *) 0, ERODE_FRACTURE, EF_DESTROY); + if (!rn2(6)) + erode_obj(uswapwep, (char *) 0, ERODE_FRACTURE, EF_DESTROY); + if (rn2(2)) + destroy_item(POTION_CLASS, AD_LOUD); + if (!rn2(4)) + destroy_item(RING_CLASS, AD_LOUD); + if (!rn2(4)) + destroy_item(TOOL_CLASS, AD_LOUD); + if (!rn2(3)) + destroy_item(WAND_CLASS, AD_LOUD); + + if (u.umonnum == PM_GLASS_GOLEM) { + You("shatter into a million pieces!"); + rehumanize(); break; + } + break; + default: + break; } return TRUE; } diff --git a/src/mondata.c b/src/mondata.c index 5bb6098b6..4f71b326e 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -602,6 +602,9 @@ struct monst *mon; if (racial_centaur(mon)) return FALSE; + if (racial_tortle(mon)) + return TRUE; + return (boolean) (r_bigmonst(mon) || (ptr->msize > MZ_SMALL && !humanoid(ptr)) /* special cases of humanoids that cannot wear suits */ diff --git a/src/monmove.c b/src/monmove.c index dc56ca66d..c9ceec8de 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -2115,7 +2115,7 @@ struct monst *mtmp; return TRUE; if (obj->oclass != GEM_CLASS && !(typ >= ARROW && typ <= BOOMERANG) && !(typ >= DAGGER && typ <= CRYSKNIFE) && typ != SLING - && !is_cloak(obj) && typ != FEDORA && !is_gloves(obj) + && !is_cloak(obj) && typ != FEDORA && typ != TOQUE && !is_gloves(obj) && typ != JACKET && typ != CREDIT_CARD && !is_shirt(obj) && !(typ == CORPSE && verysmall(&mons[obj->corpsenm])) && typ != FORTUNE_COOKIE && typ != CANDY_BAR && typ != PANCAKE diff --git a/src/monst.c b/src/monst.c index 4f76c028b..b1e325fd8 100644 --- a/src/monst.c +++ b/src/monst.c @@ -1979,8 +1979,7 @@ struct permonst _mons2[] = { SIZ(2250, 750, MS_BOAST, MZ_HUGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, M2_STRONG | M2_ROCKTHROW | M2_NASTY | M2_COLLECT | M2_JEWELS, M3_INFRAVISIBLE | M3_INFRAVISION, 0, MH_GIANT, 8, CLR_GRAY), - /* From SporkHack. - */ + /* From SporkHack */ MON("hill giant shaman", S_GIANT, LVL(7, 10, 4, 0, -3), (G_GENO | 2), A(ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), @@ -3653,8 +3652,15 @@ struct permonst _mons2[] = { M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_THICK_HIDE | M1_NOHANDS | M1_OVIPAROUS | M1_CARNIVORE, M2_STRONG | M2_HOSTILE, 0, 0, 0, 7, CLR_BROWN), - /* From SporkHack. - */ + MON("tortle", S_LIZARD, LVL(0, 8, 0, 0, 3), G_NOGEN, /* placeholder */ + A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, + NO_ATTK), + SIZ(1200, 300, MS_HUMANOID, MZ_LARGE), 0, 0, + M1_HUMANOID | M1_THICK_HIDE | M1_OMNIVORE | M1_AMPHIBIOUS + | M1_SWIM, + M2_NOPOLY | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, 0, + MH_TORTLE, 2, CLR_BRIGHT_GREEN), + /* From SporkHack */ MON("giant turtle", S_LIZARD, LVL(7, 2, -8, 10, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), diff --git a/src/objects.c b/src/objects.c index 88e813771..3bf5f779d 100644 --- a/src/objects.c +++ b/src/objects.c @@ -377,6 +377,8 @@ HELM("cornuthaum", "conical hat", blocks clairvoyance if worn by role other than wizard */ HELM("fedora", None, 1, 0, 0, 0, 0, 3, 1, 10, 0, CLOTH, CLR_BROWN), +HELM("toque", None, + 1, 0, 0, 0, 0, 3, 1, 10, 0, CLOTH, CLR_ORANGE), HELM("elven helm", "hat", 0, 0, 0, 6, 1, 3, 8, 9, 0, LEATHER, HI_LEATHER), HELM("orcish helm", "skull cap", diff --git a/src/polyself.c b/src/polyself.c index 1ef5a5fdf..cb0beaca4 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1836,10 +1836,10 @@ int part; } if ((part == HAND || part == HANDED) && ((humanoid(mptr) && attacktype(mptr, AT_CLAW) - && (has_claws(mptr) || has_claws_undead(mptr)) - && !index(not_claws, mptr->mlet) && mptr != &mons[PM_STONE_GOLEM] - && mptr != &mons[PM_INCUBUS] && mptr != &mons[PM_SUCCUBUS]) - || Race_if(PM_DEMON) || Race_if(PM_ILLITHID))) + && (has_claws(mptr) || has_claws_undead(mptr)) + && !index(not_claws, mptr->mlet) && mptr != &mons[PM_STONE_GOLEM] + && mptr != &mons[PM_INCUBUS] && mptr != &mons[PM_SUCCUBUS]) + || Race_if(PM_DEMON) || Race_if(PM_ILLITHID) || Race_if(PM_TORTLE))) return (part == HAND) ? "claw" : "clawed"; if ((mptr == &mons[PM_MUMAK] || mptr == &mons[PM_MASTODON] || mptr == &mons[PM_WOOLLY_MAMMOTH]) diff --git a/src/role.c b/src/role.c index 7ad976c52..229e30147 100644 --- a/src/role.c +++ b/src/role.c @@ -50,7 +50,7 @@ const struct Role roles[] = { S_SNAKE, S_MUMMY, ART_XIUHCOATL, - MH_HUMAN | MH_DWARF | MH_GNOME | MH_HOBBIT, + MH_HUMAN | MH_DWARF | MH_GNOME | MH_HOBBIT | MH_TORTLE, ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 7, 10, 10, 7, 7, 7 }, @@ -92,7 +92,8 @@ const struct Role roles[] = { S_OGRE, S_TROLL, ART_RING_OF_P_HUL, - MH_HUMAN | MH_DWARF | MH_ORC | MH_GIANT | MH_CENTAUR, + MH_HUMAN | MH_DWARF | MH_ORC | MH_GIANT | MH_CENTAUR + | MH_TORTLE, ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 16, 7, 7, 15, 16, 6 }, @@ -220,7 +221,7 @@ const struct Role roles[] = { S_YETI, ART_STAFF_OF_AESCULAPIUS, MH_HUMAN | MH_ELF | MH_DWARF | MH_GNOME | MH_HOBBIT - | MH_CENTAUR, + | MH_CENTAUR | MH_TORTLE, ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 7, 7, 13, 7, 11, 16 }, @@ -346,7 +347,8 @@ const struct Role roles[] = { S_ELEMENTAL, S_XORN, ART_EYES_OF_THE_OVERWORLD, - MH_HUMAN | MH_ELF | MH_DWARF | MH_GIANT | MH_CENTAUR, + MH_HUMAN | MH_ELF | MH_DWARF | MH_GIANT | MH_CENTAUR + | MH_TORTLE, ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ @@ -390,7 +392,7 @@ const struct Role roles[] = { S_WRAITH, ART_MITRE_OF_HOLINESS, MH_HUMAN | MH_ELF | MH_DWARF | MH_ORC | MH_GIANT - | MH_HOBBIT | MH_CENTAUR | MH_ILLITHID, + | MH_HOBBIT | MH_CENTAUR | MH_ILLITHID | MH_TORTLE, ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ @@ -575,7 +577,7 @@ const struct Role roles[] = { S_SPIDER, S_CENTAUR, ART_YENDORIAN_EXPRESS_CARD, - MH_HUMAN | MH_HOBBIT | MH_GNOME, + MH_HUMAN | MH_HOBBIT | MH_GNOME | MH_TORTLE, ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 7, 10, 6, 7, 7, 10 }, @@ -660,7 +662,7 @@ const struct Role roles[] = { S_WRAITH, ART_EYE_OF_THE_AETHIOPICA, MH_HUMAN | MH_ELF | MH_DWARF | MH_GNOME | MH_ORC - | MH_HOBBIT | MH_GIANT | MH_ILLITHID, + | MH_HOBBIT | MH_GIANT | MH_ILLITHID | MH_TORTLE, ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 7, 10, 7, 7, 7, 7 }, @@ -907,7 +909,8 @@ const struct Race races[] = { MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC, MH_ORC, 0, - MH_HUMAN | MH_ELF | MH_DWARF | MH_GNOME | MH_HOBBIT, + MH_HUMAN | MH_ELF | MH_DWARF | MH_GNOME | MH_HOBBIT + | MH_TORTLE, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(50), 16, 16, 18, 19, 16 }, @@ -949,7 +952,7 @@ const struct Race races[] = { PM_HOBBIT_ZOMBIE, MH_HOBBIT | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL, MH_HOBBIT, - MH_HOBBIT, + MH_HOBBIT | MH_TORTLE, MH_ORC | MH_ILLITHID, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, @@ -993,7 +996,7 @@ const struct Race races[] = { MH_ILLITHID, MH_ILLITHID, MH_HUMAN | MH_ELF | MH_DWARF | MH_GNOME | MH_HOBBIT - | MH_GIANT | MH_CENTAUR | MH_ORC, + | MH_GIANT | MH_CENTAUR | MH_ORC | MH_TORTLE, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { 10, 22, 22, 20, 12, 16 }, @@ -1001,6 +1004,28 @@ const struct Race races[] = { { 2, 0, 1, 1, 1, 0 }, /* Hit points */ { 3, 0, 3, 0, 4, 0 } /* Energy */ }, + { + "tortle", + "tortle", + "tortle", + "Trt", + { 0, 0 }, + PM_TORTLE, + NON_PM, + NON_PM, + NON_PM, + MH_TORTLE | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL + | ROLE_NEUTRAL, + MH_TORTLE, + MH_TORTLE | MH_HOBBIT, + MH_ORC | MH_ILLITHID, + /* Str Int Wis Dex Con Cha */ + { 3, 3, 3, 3, 3, 3 }, + { STR19(19), 18, 20, 10, 18, 14 }, + /* Init Lower Higher */ + { 2, 0, 0, 2, 1, 0 }, /* Hit points */ + { 2, 0, 2, 1, 2, 0 } /* Energy */ + }, /* Array terminator */ { 0, 0, 0, 0 } }; @@ -1020,7 +1045,7 @@ struct Race race_demon = { MH_DEMON, MH_DEMON, MH_HUMAN | MH_ELF | MH_DWARF | MH_GNOME | MH_HOBBIT - | MH_GIANT | MH_CENTAUR, + | MH_GIANT | MH_CENTAUR | MH_TORTLE, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(100), 18, 18, 20, 20, 18 }, diff --git a/src/u_init.c b/src/u_init.c index 716cb5549..7391887eb 100644 --- a/src/u_init.c +++ b/src/u_init.c @@ -218,9 +218,9 @@ struct trobj Tinningkit[] = { { TINNING_KIT, UNDEF_SPE, TOOL_CLASS, 1, 0 }, struct trobj Pickaxe[] = { { PICK_AXE, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; struct trobj Psionics[] = { { SPE_PSIONIC_WAVE, 0, SPBOOK_CLASS, 1, 0 }, - { 0, 0, 0, 0, 0 } }; + { 0, 0, 0, 0, 0 } }; struct trobj AoMR[] = { { AMULET_OF_MAGIC_RESISTANCE, 0, AMULET_CLASS, 1, 0 }, - { 0, 0, 0, 0, 0 } }; + { 0, 0, 0, 0, 0 } }; /* race-based substitutions for initial inventory; the weaker cloak for elven rangers is intentional--they shoot better */ @@ -278,6 +278,12 @@ struct inv_sub { { PM_HOBBIT, HELMET, ELVEN_HELM }, { PM_HOBBIT, CLOAK_OF_DISPLACEMENT, ELVEN_CLOAK }, { PM_HOBBIT, CRAM_RATION, LEMBAS_WAFER }, + /* Tortles also have special considerations */ + { PM_TORTLE, JACKET, GLOVES }, + { PM_TORTLE, RING_MAIL, TOQUE }, + { PM_TORTLE, ROBE, TOQUE }, + { PM_TORTLE, HAWAIIAN_SHIRT, TOQUE }, + { PM_TORTLE, CLOAK_OF_MAGIC_RESISTANCE, GLOVES }, { NON_PM, STRANGE_OBJECT, STRANGE_OBJECT } }; @@ -984,7 +990,7 @@ u_init() break; case PM_WIZARD: ini_inv(Wizard); - if (Race_if(PM_GIANT)) + if (Race_if(PM_GIANT) || Race_if(PM_TORTLE)) ini_inv(AoMR); if (Race_if(PM_ILLITHID)) ini_inv(Psionics); @@ -1054,22 +1060,25 @@ u_init() knows_object(DWARVISH_BOOTS); knows_object(DWARVISH_ROUNDSHIELD); - if (!Role_if(PM_ARCHEOLOGIST) && !Role_if(PM_CONVICT)) + if (!Role_if(PM_ARCHEOLOGIST) && !Role_if(PM_CONVICT)) { if (!rn2(4)) { /* Wise dwarves bring their toy to the dungeons. */ ini_inv(Pickaxe); } + } break; case PM_GNOME: case PM_ILLITHID: + case PM_TORTLE: break; case PM_GIANT: /* Giants know valuable gems from glass, and may recognize a few types of valuable gem. */ - for (i = DILITHIUM_CRYSTAL; i <= LUCKSTONE; i++) + for (i = DILITHIUM_CRYSTAL; i <= LUCKSTONE; i++) { if ((objects[i].oc_cost <= 1) || (rn2(100) < 5 + ACURR(A_INT))) knows_object(i); + } break; case PM_HOBBIT: diff --git a/src/uhitm.c b/src/uhitm.c index 2314531e8..f219ebfd2 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1637,6 +1637,7 @@ int dieroll; } else if (!uwep && (has_claws(youmonst.data) || has_claws_undead(youmonst.data) || (Race_if(PM_DEMON) && !Upolyd) + || (Race_if(PM_TORTLE) && !Upolyd) || (Race_if(PM_ILLITHID) && !Upolyd))) { You("claw %s%s", mon_nam(mon), canseemon(mon) ? exclam(tmp) : "."); @@ -3330,7 +3331,8 @@ boolean wouldhavehit; pline("%s %s %s your attack.", s_suffix(Monnam(mdef)), (is_dragon(mdef->data) ? "scaly hide" - : mdef->data == &mons[PM_GIANT_TURTLE] + : (mdef->data == &mons[PM_GIANT_TURTLE] + || is_tortle(mdef->data)) ? "protective shell" : "thick hide"), (rn2(2) ? "blocks" : "deflects"));