Hello crawlers, and welcome to the most completely serious and truthful trunk update of the year! The 0.30 development cycle is (finally!) nearing a close, and we are pleased to announce a tentative tournament start date of Friday, May 5, 2023, at 20:00 UTC for the sixteen day 0.30 Release tournament. We’ll shift towards bug fixes and balance as we get closer to 0.30′s release, sometime before the start of the tournament. More details about the tournament, including a tournament website and rules changes, will be available here!

We’d also like to celebrate the addition of two (!) new devs to the team. Félix Medrano (née robertxgray) and Implojin have both more than proven themselves by their work so far, with Félix specializing on the Crawl Android port and Implojin contributing great designs like Rampage and the toga of Victory. We’re very happy to have them onboard!

Anyway, let’s get some very real and serious changes headed your way.

  • Branches and Environments:
    • You can now enter the Vaults without holding a rune. However… you can never leave! Unless you get a rune while you’re inside.
    • Slime walls now corrode instead of dealing damage. Unless you use Oozemancy, in which case they still do damage. Also, they don’t corrode monsters. Unless the monsters take Oozemancy damage. It’s all pretty straightforward.
    • Thunderstorms now do much more damage. If you were in the habit of standing in the middle of thunderstorms before… this might be a good time to break the habit.
    • Zigsprint now lets you start with orbs of guile or mayhem. But why would you not use Gong? It’s Gong!
    • By overwhelming popular demand, you can now place up to 100 waypoints. We know you, the players, were suffocating under the previous 10 waypoint limit. Now you are freed. Go forth!
  • Characters:
    • Harm now stacks. This is a game changer.
    • Channeling effects (from Wucad Mu or orbs of energy) no longer backlash and no longer scale with Evocations. They just give -Wiz and have a flat chance of refunding spell costs. We’ve reworked this mechanic about four times this year and I’m sure it’s going to stick at some point.
    • The acidic bite mutation works again, for the first time since 2016. Oops.
    • Armataurs no longer claim to drink ten potions at once. Their tongues are long, but they aren’t actually that long.
  • Gods:
    • Piety costs are now shown more clearly for invocations. Did you know that Enter the Abyss costs Piety——-? Sort of unclear what that means, but it seems like an awful lot of -s, huh?
    • Kikubaaqudgha’s second gift is now a little less predictable. It could be anything. It’s probably about four Necromancy spells… but what if it’s not?
    • Good gods will no longer get mad when you generate negative energy clouds with a condenser vane. Instead, they’ll get even. They put their metaphysical foot down and squash the evil clouds – just like that!
    • Hepliaklqana’s Knights are now as good at attacking as ogres, or at least as slow as them.
    • Xom is no longer fixated on giving you a few different mutations.
    • Ashenzari’s trap detection ability is now only available at 4* of piety. Except that traps are always revealed these days, so this is more of a malevolence suppression ability. The world is so cruel…
    • Ashenzari’s skill boost is a little less boosted.
    • For Gozag’s gold distraction aura duration, size really doesn’t matter. (Anymore.)
    • Ru can no longer redirect butterflies’ attacks.
    • Flame Tongue is removed.
  • Unrands:
    • New unrand: the toga ‘Victory’. Gives +AC, Int, and Slay if you kill scary stuff while wearing a toga. If you drink or read anything while foes are in sight, though, you are a coward and a fool, and the toga will revert to its primal state. Victory!
    • New unrand: the Consecrated Labrys. It’s like the obsidian axe, but it’s good instead of evil, and it gets more enchanted the more scary enemies are in sight. As with the obsidian axe, we strongly recommend charging headfirst at every group of enemies while holding this.
    • New unrand: the Storm Queen’s Shield. You have probably never in your life thought “I would like to be a shock serpent”, but that’s how powerful this shield is: it will grant a wish you didn’t even know you had.
    • The Staff of Dispater is now an orb. It has +AC and *Corrode. Much to ponder…
    • The Slick Slippers are even slicker and slipperier than before. Also, they’ll no longer hustle you around when your feet are already occupied climbing stairs.
    • Majin-Bo’s spell-vamprisim now can suck up blood from a Polar Vortex. It all just flies right into the middle, it’s kinda gross.
    • Many unrands now have helpful inscriptions for their special effects, like EVERVAMP, MEGAVAMP, and probably some other things that don’t involve VAMP.
    • Morg has been removed. Actually, for all you know, it might have been removed years ago. Would you have even noticed?
  • Items:
    • Orbs, scarfs, and even magical staffs can now all generate as random artefacts. Finally, you can find the orb of “Zot” of rage!
    • Randarts are very slightly, ever so imperceptibly, worse. Yes, that is why your best character splatted the other day. How did you know?
    • Hyperinflation has hit throwing weapons, causing javelins, boomerangs, darts, and even large rocks to skyrocket in price.
    • Tremorstones and condenser vanes are now in a set: you only get one of the two per game. Star-crossed lovers…
    • When throwing weapons break, they now deal extra damage. It’s a considerate thing. They’re very sorry that you can’t throw them around anymore and they’d like to offer you a little parting gift as they go.
    • Spectral weapons now deal damage as if you were launching an extra attack, rather than using a secret and inscrutable set of spectral weapon monster stats. They’re also not allowed to attack themselves anymore, since that was really creeping us out.
    • Longbows, arbalests, and hand crossbows have all had their stats shuffled around a little.
  • Spells:
    • New spell: Plasma Beam (L5 Fire/Air), which shoots a bolt of lightning AND a bolt of fire at the most distant foe around. My first email address involved both “fire” and “plasma” so I’m very excited about this.
    • Lesser Beckoning is now level 2 (was level 3). This gives more potential design space for Greater Beckoning, to say nothing of the long-awaited Greatest Beckoning.
    • Battlespheres now fire when you cast any destructive spell, matching Vehumet. Vehumet says that a god can’t be matched by a mere L5 spell, but I’m unconvinced.
    • Arcjolt can now hit any monster in sight, as long as there are a continuous chain of other monsters between you and that monster.
    • Irradiate now only malmutates monsters sometimes. Try saying ‘pretty please’ before casting it for best effects.
    • Lightning Bolt is gone. Amazing it lasted this long, really. Not really famous for their longevity, lightning bolts.
  • Monsters:
    • New monster: sleepcaps. If they hit you, their spores might put you to sleep. If they put you to sleep, the next thing that hits you will get a big stabbing damage multiplier. And if you lose all your hit points? That’s right: you die in real life.
    • New monster: skysharks, cutting through the air (as sharks are known to). If they bite you and draw blood, somehow they’re the ones that get mad about it? And that makes them bite even harder? Seems very unfair, frankly.
    • Smitten monsters now wake up, but they’re not happy about it.
    • Giant fish zombies have been removed.
    • Endotherms have been removed.
  • Webtiles:
    • You can now enter explore mode online! Hit + to explore freely… without any fear of death. You are immortal. You are a god!
    • You can now block trolls. They cannot regenerate from this. (Not yet enabled on every server: this will roll out to servers next time they restart webtiles.)
  • Crawl has, somehow, become even more Australian.
  • We fixed a typo in which we wrote “entire the” instead of “the entire”. Not really a big deal, honestly… except that this text has been in every single morgue since 2007! Shouldn’t someone have told us? We’re so embarrassed right now.
  • Last but not least, we rewrote maybe_bool to be, arguably, better. See below for
    motivation, but here are the practical notes up front:

    * `maybe_bool` becomes a class rather than an enum.
    * After this commit, nearly anywhere you would write MB_FALSE or
      MB_TRUE you would simply write `false` or `true`.
    * Where you would write MB_MAYBE you now should write
      `maybe_bool::maybe`.
    * Comparison to `true` or `false` is safe and will do exact
      comparison. (The latter may appear surprising, but it is because
      comparison will cause a bool to be cast to maybe_bool, rather than a
      maybe_bool to be cast down to bool.)
    * Semantics change: `maybe_bool::maybe` does not convert to true by
      default under any circumstance.
    * In cases where you would have previously written `mb == MB_TRUE` you
      can just rely on a bool cast (`maybe` does not convert to `true`). In
      cases where you would write `mb == MB_FALSE` you can write `!mb`.
    * frombool and tobool are replaced respectively by constructors and
      the class method maybe_bool::to_bool (as well as an explicit bool
      cast).
    * While bool explicit operators have weird rules and can be used
      implicitly in some cases, there are still times when you'll need
      to do the cast. In particular, if a function returns a bool, to
      return a maybe_bool you'll need to explicitly cast.
    * Mixing bools and maybe_bools in logical expressions generally requires
      an explicit cast. (If you write a condition that just uses !, that
      doesn't need one.)
    
    Old `maybe_bool` had the advantage of simplicity: it was just an enum
    and as long as these enum values are used consistently, it is pretty
    simple to use and as efficient as any integer-based type, with
    effectively no implementation code.
    
    However, there are a few complaints about it. First, the naming scheme
    was quite ad hoc across the enum values and various functions that used
    them.  Second, and more importantly in my mind, the enum-based
    implementation led in a very non-clean way to implicit int and bool
    casts, and a very ad hoc semantics for this type, especially in its
    interaction with boolean expressions. Taken as a three-valued logic, it
    is very weird. The law of the excluded middle *is* valid (in the sense
    that `p || !p` is always true), but double negation elimination is *not*
    valid (i.e. `!!p != p`); the weaker double negation inference `!!!p ==
    !p` does hold conceivably classing it with some paraconsistent logics,
    though I haven't found an exact analogue (see [1], though this logic
    doesn't much resemble L8 there, which has the same double negation
    pattern). At a practical level this ad hoc nature made mixing with bools
    in both directions weird and somewhat error prone; aside from the above
    concerns (which essentially result from MB_MAYBE implicitly casting to
    `true`), `true` would cast to the enum value MB_MAYBE, leading to clunky
    conversion code in a lot of places, needing to always use MB
    constants, and error-prone comparison with regular bools.
    
    This commit tries to systematize things more cleanly, albeit with a much
    more complicated implementation. The underlying data type does still
    amount to a fancy enum (now an enum class), but it's wrapped with a more
    clearly defined class, largely inspired by boost's logic::tribool.  (I
    considered whether importing one of the various "`optional` but for
    c++11" packages out there might be a solution, but ultimately rejected
    this, because these classes tend to have an even weirder, for a
    bool-based type, set of implicit conversions to bool). A `bool`
    constructor is provided making it generally safe to use `true` and
    `false` as e.g. return values, and an explicit cast to bool is provided
    that has a better default than MB_MAYBE->true. (In some cases, this may
    be the desired semantics, of course, but this is still doable via
    `to_bool` or direct checks against false.) The operator semantics is
    based on the standard "Strong Kleene" three-valued logic operators,
    which provide a (imo) very sensible set of defaults for a three-valued
    logic. Note that because of the existence of the bool operator, this
    won't let you mix `maybe_bool`s in logical expressions together with
    bools without some explicit casting one way or the other.  The
    implementation is nearly (but not quite) purely header-based.
    
    As part of this commit, I have implemented everything as a
    back-compatibility layer and purely just tried to clarify the semantics
    of various instances of maybe_bool in cases where it did get an implicit
    conversion. The bulk of this is around `can_wear_item` which does tend
    to treat its maybe return as truth-y.  A future commit will convert
    MB_TRUE etc into their `maybe_bool::t` etc equivalents.
    
    [1] Kamide 2013, A Hierarchy of Weak Double Negations, Studia Logica 101.6

Many thanks also to Sastreii and CanOfWorms for contributing many new tiles over this period, including spell icons, artefact art, Shrek, and more.

Thanks also to all the community members who’ve contributed over the last few months, who I am too tired to credit in full. In particular, check out what SpinningBird sent us!

Happy crawling! Stay serious out there.