diff -Nru crawl-0.24.0/CREDITS.txt crawl-0.25.0/CREDITS.txt --- crawl-0.24.0/CREDITS.txt 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/CREDITS.txt 2020-06-15 16:26:04.000000000 +0000 @@ -31,19 +31,22 @@ * The administrators of public crawl servers, both present: John Boyle (crawl.berotato.org) + Jan Anders Bremer (underhound.eu) Rax E. Dillon (crawl.akrasiac.org) Wongi Hong (webzook.net / kr.dobrazupa.org) Alex Jurkiewicz (crawl.project357.org) - Neil Moore (crawl.s-z.org) Marc H. Thoben (crawl.develz.org) dplusplus (lazy-life.ddo.jp) floraline (crawl.kelbi.org) + Namanix (crawl.xtahua.com) and past: Jan Anders Bremer (crawl.lantea.net) - Aleksi Miikkael Luukkonen (crawl.lantea.net) joosa (rl.heh.fi) - sd1989 (kr.dobrazupa.org) + Medar, Zkyp (crawl.xtahua.com) + Aleksi Miikkael Luukkonen (crawl.lantea.net) + Neil Moore (crawl.s-z.org) phunktion (crawl.somatika.net) + sd1989 (kr.dobrazupa.org) ZiBuDo (crawl.jorgrun.rocks) * The members of various usability testing teams from the department of @@ -71,6 +74,8 @@ * Members of the Dungeon Crawl community who have contributed to Dungeon Crawl Stone Soup: + achuah + AdamPG Brent Adams Mike Adams Aj Adamson @@ -103,6 +108,7 @@ bones Peter Borgmann Matthew Boeh + Clare Boothby Mike Boutin John Boyle Josh Braden @@ -127,6 +133,7 @@ Aaron Curtis Simon Curtis cut1less + David Damerell Paul Dejean Denzi Lothar Dierkes @@ -154,10 +161,12 @@ GenericPseudonym Ge0ff Joshua Gelbard + Peter Gerlagh Benoît Giannangeli Ben Goetter Aaron Golden Ed Gonzalez + Goratrix Rob Grant John Greenberg GreyKnight @@ -191,6 +200,7 @@ Kornel Kisielewicz Vesa Kivimäki Daniel Klein + klorpa Jon Knapp Quinten Konyn Ilkka Koskela @@ -207,6 +217,7 @@ Jordan Lewis Sami Liedes Dom 'Bodrick' Light + Lightli Mark Lodato Matthew Ludivico Rob Lund @@ -221,13 +232,16 @@ Paul Maloney Pablo Mansanet Wille Mäntylä + István Markó Gabriel Marks Jean Martel James 'Eronarn' Meickle Jacob Meigs mgdelmonte mikee + Nathan Mills Andrew Minton + Byrel Mitchell Yer Mivvaggah Shawn M Moore Muffindrake @@ -238,6 +252,7 @@ Naruni neofelis nicolae + nirrattner Jonathon Nooner NormalPerson7 Michael Nowack @@ -273,6 +288,7 @@ Remsleep Chris Rendle-Short Ryan Riegel + riverfiend RjY rmcneive Andy Roche @@ -280,6 +296,7 @@ Will Rogers Nate Rook David Rose + runrin Risto Saarelma Sebastian Salman Sandman25 @@ -317,11 +334,13 @@ William Tanksley, Jr. Tedronai Chris Terenzi + theJollySin Jared 'Twinge' Tinney Matt Titus Tommy Sean VanMeter Mikko Vepsäläinen + vla22 WanderingBlade Richard Wardin waylon531 @@ -329,10 +348,12 @@ Thomas Willem Evan Williams Jeremey Wilson + wjchen ximxim Yelve Yakut Edward Z. Yang Yermak + Andrew G. York Rob Young Zannick Zooko diff -Nru crawl-0.24.0/debian/changelog crawl-0.25.0/debian/changelog --- crawl-0.24.0/debian/changelog 2020-03-23 06:11:57.000000000 +0000 +++ crawl-0.25.0/debian/changelog 2020-07-13 15:30:36.000000000 +0000 @@ -1,8 +1,10 @@ -crawl (2:0.24.0-1build1) focal; urgency=medium +crawl (2:0.25.0-1) unstable; urgency=medium - * No-change rebuild for libgcc-s1 package name change. + * New upstream release. + * Fixes CVE-2020-11722; closes: #958232. + * Clean up MacOS droppings. - -- Matthias Klose Mon, 23 Mar 2020 07:11:57 +0100 + -- Adam Borowski Mon, 13 Jul 2020 17:30:36 +0200 crawl (2:0.24.0-1) unstable; urgency=medium diff -Nru crawl-0.24.0/debian/patches/python3-hashbangs crawl-0.25.0/debian/patches/python3-hashbangs --- crawl-0.24.0/debian/patches/python3-hashbangs 2019-10-24 22:03:25.000000000 +0000 +++ crawl-0.25.0/debian/patches/python3-hashbangs 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -Description: point hashbangs at python3 - The hashbangs point at to-be-removed "python" (ie, python2), despite the - scripts being supposed to work with both. Also, using "env" is wrong. - ---- crawl-0.24.0.orig/source/util/species-gen.py -+++ crawl-0.24.0/source/util/species-gen.py -@@ -1,4 +1,4 @@ --#!/usr/bin/env python -+#!/usr/bin/python3 - - from __future__ import print_function - ---- crawl-0.24.0.orig/source/util/txc -+++ crawl-0.24.0/source/util/txc -@@ -1,4 +1,4 @@ --#!/usr/bin/env python -+#!/usr/bin/python3 - # -*- coding: utf-8 -*- - - import os, re, sys, codecs, difflib ---- crawl-0.24.0.orig/source/webserver/server.py -+++ crawl-0.24.0/source/webserver/server.py -@@ -1,4 +1,4 @@ --#!/usr/bin/env python -+#!/usr/bin/python3 - import os, os.path, errno, sys - - import tornado.httpserver diff -Nru crawl-0.24.0/debian/patches/series crawl-0.25.0/debian/patches/series --- crawl-0.24.0/debian/patches/series 2019-10-24 22:00:55.000000000 +0000 +++ crawl-0.25.0/debian/patches/series 2020-07-13 15:09:36.000000000 +0000 @@ -1,2 +1 @@ bogus_watch -python3-hashbangs diff -Nru crawl-0.24.0/debian/rules crawl-0.25.0/debian/rules --- crawl-0.24.0/debian/rules 2019-10-24 22:06:07.000000000 +0000 +++ crawl-0.25.0/debian/rules 2020-07-13 15:30:27.000000000 +0000 @@ -84,6 +84,7 @@ rm -rf build-console build-tiles git clean -dfX || true + find -name '._*' -execdir rm '{}' + dh_clean diff -Nru crawl-0.24.0/docs/changelog.txt crawl-0.25.0/docs/changelog.txt --- crawl-0.24.0/docs/changelog.txt 2019-10-24 18:25:14.000000000 +0000 +++ crawl-0.25.0/docs/changelog.txt 2020-06-14 20:47:50.000000000 +0000 @@ -1,6 +1,333 @@ -Stone Soup 0.24 (20191024) +Stone Soup 0.25.0 (20200612) +---------------------------- + +Highlights +---------- +* Spells in many schools have been redesigned to make the schools more + distinct. +* Acquirement scrolls have been despoilered, offering the player a choice of + generated items. +* Effects from spell miscasts, god wrath, death curses, and Zot traps have + been overhauled for consistency and simplicity. + +Branches, Environment +--------------------- +* Potions of cancellation now appear as loot in Ziggurats. +* Boris can now spawn after the player picks up the Orb of Zot. +* Forest fires and the Tornado spell can no longer destroy temporary trees + made by Summon Forest. +* D:1 Level spawns can no longer generate within LOS distance of the player's + starting position. +* Many arrival vaults have been reworked to allow better player tactics. +* A new Swamp ending themed as a conflict between Yred and Fedhas that + includes an undead version of the Lernaean Hydra. +* Ziggurats now have level set featuring many player ghosts. +* Zot traps have had their effect flowchart simplified and focused. +* Abyss exits that spawn from earning xp can spawn after the initial spawn, + instead of every subsequent spawn being a downstair. +* Troves can now ask for scrolls of fog or scrolls of fear. + +Character +--------- +* Monsters summoned by the player now dismiss when they become hostile. +* Players can now renounce their religion while silenced. +* All Evocable items can no longer be used by the player while confused. +* Formicids can no longer cast Swiftness. + +Gods +---- +* Trog no longer gifts ranged weapons nor ammunition, gifting only melee + weapons. These weapons can only have egos of plain, vorpal, flaming, and + anti-magic. +* Trog now hates use of all magical staves and pain weapons. +* Elyvilon's Divine Protection now always protects exactly at 5* piety instead + of protecting at a value between 5* and 6*. +* Fedhas now protects plant allies from collisions and from ranged attacks by + other allies. +* God conducts for harming allies now apply to spells and items that place + harmful clouds. +* Nemelex abilities can no longer be used while silenced. +* Nemelex card revisions: + - The pain card no longer summons a flayed ghost, instead it torments at high + power (the card user is spared). + - The cloud card now produces black smoke around enemies in sight, to better + fir with the deck of escape. +* Wu Jian has been tweaked: + - Wall jumps are now only activated via the 'a'bility menu. + - Whirlwind attacks no longer pin + - Heavenly Storm now starts with a slaying bonus of 5, capped at 15, and + increases by 1 for each martial attack. +* Xom no longer inflicts miscast effects. +* Xom demon summoning is increased in power. +* Wrath changes + - Trog's "firey rage" is now a fireball, instead of a fire miscast. Trog no + longer uses rot as retribution. + - Lugonu's "translocation wrath" no longer uses translocations miscast. + Instead, the player is either teleported to monsters, banished, or set upon + by Abyss summons. + - Cheibriados' wrath no longer uses miscasts. At very high tension, in + addition to sleeping and slowing the player, Chei makes a lot of noise. At + low tension, miscasts are replaced by stat damage. + - Fedhas' wrath no longer uses elemental miscasts. These are replaced by a + choice of corrosive bolt, primal wave, or thorn volley. + - Yredelemnul's wrath no longer uses necromancy miscasts, in their place Yred + fires a bolt of draining. + - Kikubaaqudgha's wrath uses death curses in place of necromancy miscasts. +* Vehumet is less likely to give duplicate gifts. +* Xom is stimulated upon worship at a faded altar. + +Items +----- +* Scroll of Acquirement rework: + - Offers players a choice of five fully generated items. + - Three of the item categories are randomly chosen and the other two are + always gold and food (for species that eat). + - Generated items are always useable and not hated by the player's current + god. + - The Miscellaneous category for evocable items is no longer available. +* New Potion of Stabbing that gives a 50% chance to upgrade weak stabs (e.g. + distracted monsters) to strong ones (e.g. sleeping monsters). +* Tin of Tremorstones, a new multiuse evocable. Tremorstones have 3 charges + which recover over time with XP. When used, it creates a number of radius 2 + explosions (the number scales with evocations skill) near the center + of present monster that are triple-affected by AC (like LRD). The explosions + are randomly skewed and may hit the user. Most useful for players with good + armour. +* The chaos brand now has might and agility effects, no longer causes miscast + effects, and its cloning effect can create friendly and neutral monsters. +* Potions of Brilliance now provide a stronger universal spell enhancer and + remove spell hunger. They no longer provide an Int bonus nor wizardry. +* Potions of Might no longer provide a bonus to strength. +* Scrolls of Magic Mapping now reveal any floor traps on the level. +* The -Tele property no longer appears on artefact weapons and jewellery. +* Ordinary shields have been renamed to kite shields and large shields have + been renamed to tower shields. This helps make equipment descriptions less + ambiguous. +* The vorpal weapon ego no longer has distinct adjectives for each weapon + class. Now all such weapons are described as 'vorpal'. +* Unrandart changes: + - New unrand: Cigotuvi's Embrace, a +4 leather armour with rN+, rRot and + *Drain that automatically gathers corpses to increase AC. The AC decays + slowly over time but decays more quickly as more corpses are added. + - Boots of the Assassin are now called the hood of the Assassin and use the + headgear slot. + - The demon blade Leech gains *Rage/+Rage and loses its AC-3 and EV-3 + properties. + - The Elemental Staff now acts as an enhancer for all elemental schools, + with enhancement applying independently for each school. + - Warlock's Mirror can now reflect piercing ranged weapons. + - The Staff of Olgreb now has a chance to deal poison-arrow flavored damage + on hit, based on evocations skill. It no longer has an additional chance to + cast Venom Bolt on top of casting OTR when evoked. It now grants poison + immunity to monsters wielding it. + - The Dragonskin Cloak now provides rCorr instead of sticky flame + resistance. + - The scythe of Curses no longer curses items in inventory, and now applies + death curses instead of necromancy miscasts. + - The plutonium sword still applies transmutations miscasts, but gains a + chance to polymorph the target on hit (since this is no longer a miscast + effect for monsters). + - The brooch of Shielding is now a guardian spirit amulet with SH+8. + - Bloodbane has been removed, having been merged into Leech. + - Maxwell's Etheric Cage has been removed. +* Phial of floods now applies a silencing "waterlogged" debuff to all monsters + in the flooded area and no longer summons water elementals. +* Staves of poison now do resistable poison damage on hit like other staves + instead of just having a chance to poison. +* Distortion branded weapons no longer teleport foes. +* Distortion unwield effects no longer cause a translocations miscast. Instead, + they either teleport the player to monsters, banish the player, or cause + severe contamination. +* Regeneration items only activate after attuning to the player at full HP, + identical to the amulet. +* Scarf egos are revised: cloud immunity and spirit shield are removed, harm + and invisibility are added. Harm scarves do not drain the player when + removed. +* Amulets of reflection now always give +5 SH and must attune to the player at + full HP. Reflected missiles, poison, and banishments now correctly award + piety. +* Cloak egos are revised: invisibility is removed, preservation (providing + corrosion resistance) and stealth are added. +* The Harm property can now appear on randart armour, and does not incur a + drain penalty on removal. +* Stat rings are now always either +6 or -4. AC, EV, and Slay rings are now + always either +4 or -4. +* Removed: potion of agility, staff of power, crystal ball of energy, sack of + spiders, lamp of fire, fan of gales, wand of scattershot, amulets of the + gourmand, amulets of harm, amulets of rage. + +Interface +--------- +* The seed selection dialogue has been ported to webtiles and is enabled on + select servers. +* auto_butcher has been changed to default to `always` (from the previous value + of `very hungry`). +* A new option, auto_butcher_max_chunks, prevents automatic butchering with more + than that many chunks in inventory. Its default value is 10 for non-ghoul + characters. +* explore_auto_rest now defaults to true. +* New morgue section: screenshots. When notes are taken with : an ascii + screenshot is additionally saved and can be added to morgues. +* The console monster list now displays monster status information and whether + or not the monster is wielding a launcher or polearm, or has a wand +* The ^x summary display now shows monster status information +* A new option, monster_item_view_coordinates, can be set to true to display + player-relative coordinates in the ^x display. +* The auto-travel trail displayed with show_travel_trail can now be customised + in console (both for glyph and colour). +* The "visited status" of stairs and transporters can now be indicated both by + glyph and by colour in console. +* Allies now show sleep and confusion status tiles. +* A new option, game_scale, allows for global pixel scaling to make dcss more + usable on large and/or high-resolution monitors. (Values in the range of 2-4 + will be helpful for upscaling for 2k-4k monitors.) +* The behavior of `tile_filter_scaling=false` has been improved to work on all + tiles in the game, for better pixelated effects. +* Webtiles now supports showing save info in the lobby; see CAO for this feature + in action. + +Monsters +-------- +* New unique: Maggie, a younger version of the unique Margery, who appears + just before and in Lair. She has a steam, acid, or swamp dragon scales, Bolt + of Fire, and Mesmerize. Only one of Maggie or Margery will place in a game. +* Margery now always gets Fire, Shadow, or Storm dragon scales as a + counterpart to Maggie's armour. +* Both Maggie and Margery have a small extra chance of spawning with a + pre-enchanted Wyrmbane (1 or 2 points of enchantment, respectively). +* Monsters such as spiders no longer have a clinging ability. +* Mummy death curses are no longer necromancy miscasts, and instead have their + own effect table. +* New monster: nameless horror. Nameless horrors are produced by summoning + miscasts. They are giant, tanky, have an antimagic attack and abjuration as a + natural ability. +* Hepliaklqana ancestors and demonic guardians can no longer be enslaved or + frenzied. +* Summoned monsters can now get the inner flame status, both from the spell and + the scroll. +* Monsters now try to avoid blocking the line of fire of monsters behind them. + +Spells +------ +* Spell in many schools have been redesigned to make the schools have better + differentiation, more positional considerations, and better UI. The + descriptions below describe the schools' individual focus and any new, + changed, and removed spells in each school: + - Fire spells have directed explosions or set things on fire: + + New L1 Conjurations/Fire spell Foxfire that conjures two foxfire + projectiles that quickly hone in on their target, each doing a bit more + than half the damage of Flame Tongue. + + Conjure Flame now creates embers on the player's position that turn into + a flame cloud a turn later. The embers smother if a monster steps on them. + + Inner Flame now creates a flame cloud under the affected monster + whenever it takes damage in addition to the usual explosion it makes + when the monster dies. + + New L6 Conjurations/Fire spell Starburst that fires 8 range 5 bolts in + the principle directions. + + Removed spells: Flame Tongue, Throw Flame, Bolt of Fire. + - Air school spells bounce, are pointy, or are hard to direct: + + Airstrike damage now scales so it's greater the more unoccupied squares + there are surrounding the target. + + Summon Lightning Spire now places the spire randomly. + - Earth spells are directed: + + Borgnjor's Vile Clutch now is a range 6 always-penetrating beam instead + of a smite-targeted 3x3 explosion. + - Ice spells are diffuse and subtle: + + New L3 Ice spell Frozen Ramparts that makes all walls within radius 2 + become covered in ice, damaging monsters that walk by. Damage bypasses AC + and slows cold-blooded animals. + + New L4 Conjurations/Ice spell Hailstorm that fires a ring of ice beams + from radius 2 to radius 3, not affecting radius 1 squares. Monsters with + rC+++ such as ice beasts are immune to this effect. + + Ozocubu's Refrigeration does 33% more damage on-average and no longer + harms the caster. + + New L9 Ice spell Absolute Zero that instantly freezes to death the + closest monster in range, leaving an ice block. A random closest monster + is chosen as the target when there are ties. The spell is range 5 and + very loud, with noise attenuated by power. + + Removed spells: Throw Frost, Throw Icicle, Bolt of Cold, Glaciate. + + As a result of these changes, Ice Elementalists no longer put starting + skill in Conjurations. + - Conjurations are pure magic with good accuracy in some way: + + Iskenderun's mystic blast now makes a range 5 explosion around the + player that damages and pushes back monsters, potentially colliding them + with features and other monsters. + + Dazzling Flash replaces Dazzling Spray. Makes a flash centered on the + player of up to radius 3 that can blind monsters in the affected area. + + Searing Ray now fires all its rays at the chosen target, adjusting + the rays as the target moves. If no target is chosen, the spell + repeatedly fires in the chosen direction. The rays all penetrate and + each has the same damage and to-hit. The ray damage is adjusted to have + the same overall damage distribution as before this change. + + Spellforged Servitor now gives only one spell to the servitor. This is + the highest level servitor-compatible spell the player has from the + following sets, in order of preference: L4 and higher ranged damage + spells, cloud spells, and low-level or short-range spells. + + Force Lance is removed. + - Poison spells poison things or perform some kind of alchemy + + Sting is now a range 3 Poison/Transmutations spell using the same + partly-resistable beam type previously used by Poison Arrow. + + New L6 Poison/Transmutations spell Eringya's Noxious Bog that creates a + temporary toxic bog trail as the player moves. The bog terrain applies + the same partly-resistable damage flavor as Sting as well as the + movement and combat penalties of shallow water. + + Removed spells: Venom Bolt, Poison Arrow + + As a result of these changes, Venom Mages now put starting skill in + Transmutations instead of Conjurations. + - Necromancy has balance adjustments to make the school not so strong and + to begin to move it closer to a melee support school: + + Corpse Rot now creates miasma clouds in a ring around the player, making + one cloud for each corpse in LOS, but with lower duration. + + Agony and Dispel Undead are now range 1, and Dispel Undead is now L4. + + Regeneration and Bolt of Draining are removed. +* The Young Poisoner's Handbook now contains Ignite Poison. +* Confusing Touch is now level 3 and checks MR instead of monster hit dice. +* The player is now immune to the melee-fumbling effects of liquefied ground + made by casting Leda's Liquefaction. The slow movement applies regardless of + flight status and the spell can be used while flying. +* Firestorm and Ignition now can burn trees, and Fireball burns trees in all + squares of its explosion. +* Call Imp no longer bases the type of imp summoned on spellpower. +* The Confuse spell has been removed. +* Spell miscast effects have been simplified to give contamination and a single + per-school effect, scaling with spell risk and level. The new effects by + school are: + - Charms and Hexes: debuff and slow. + - Summoning: durably summon a nameless horror (new monster). + - Translocation: dimension anchor. + - Transmutation: extra contamination for the player, malmutate a monster. + - Conjuration: irresistable AC-ignoring damage. + - Elemental schools: school flavored damage (Earth uses fragmentation + damage). +* The Deflect Missiles spell has been removed. +* Tukima's Dance can no longer be used if the player sacrificed Love. +* Lesser Beckoning and Teleport Other now turn allies hostile. +* Eldritch Tentacles from malign gateway can no longer attack out of LOS of the + player, and arrive sooner after the gateway is opened. + +Development +----------- +* The WebTiles server has seen a major overhaul and now supports python 3 as + well as Tornado 5+, as well as numerous other backend/technical improvements. +* The catch2 testing framework is now integrated into the project and is + enabled in our CI testing. +* GitHub actions have been configured to replace Travis CI testing. + +Stone Soup 0.24.1 (20200322) -------------------------------- +Bugfix Release +-------------- +* A remote code execution vulnerability has been patched. +* The UI has received some bug fixes and improvements. +* Pinned monsters can no longer trample. +* Some vaults have been tweaked. +* Fedhas protection is now extended to piercing attacks done by all allies. +* Fedhas summons' duration is now correctly capped. + +Stone Soup 0.24 (20191024) +-------------------------- + Highlights ---------- * Vampire species simplified @@ -12,7 +339,7 @@ --------------------- * Incremental pregeneration: - This mode generates the dungeon in a stable order for all games regardless - of the path taken by the player, meaning that the behavior of seeds for + of the path taken by the player, meaning that the behaviour of seeds for online and offline games should now be the same. - Games using the same seed will see the same dungeon if they are incrementally pregenerated without requiring the long initial generation @@ -245,11 +572,11 @@ Character --------- -* The player can no longer be put to sleep when paralyzed or petrified. +* The player can no longer be put to sleep when paralysed or petrified. * Tengu Permanent Flight becomes immediately available at XL 5. * Tengu EV bonuses are no longer applied to +EV from equipment. * Wanderer starting spell libraries are announced along with equipment. -* Wanderers that start with exactly one level 1 spell start with it memorized. +* Wanderers that start with exactly one level 1 spell start with it memorised. Gods ---- @@ -300,7 +627,7 @@ - Nemelex Xobeh displays deck information. - Wu Jian displays information about martial attacks. * The Hepliakqana ancestor reaching full health interrupts resting. The exact - behavior of this interrupt can be configured by rest_wait_ancestor. + behaviour of this interrupt can be configured by rest_wait_ancestor. * The new display_chars cloud_weak, cloud_fading, and cloud_terminal indicate remaining cloud duration in console. * WebTiles users can use a "Forgot Password" link to reset their password @@ -479,7 +806,7 @@ ------ * Spell Library: - Spells from books are automatically added to a global library upon pickup. - - Library spells can be memorized from anywhere through the 'M' screen. + - Library spells can be memorised from anywhere through the 'M' screen. - Spellbooks are destroyed after their spells are added to the library. - Vehumet won't offer you a spell you already have in your library. * Borgnjor's Vile Clutch constriction damage is reduced by 25% and the spell @@ -583,7 +910,7 @@ * Water species except for merfolk autoexplore/travel through shallow water. * Diagonal shift-running now stops properly at doors. * Draconian players now show their hat tiles in Tiles/WebTiles. -* New 'tc_forbidden' RC option to set color of squares forbidden by travel. +* New 'tc_forbidden' RC option to set colour of squares forbidden by travel. * New xp_by_level morgue table to track XP sources on a per-level basis. * New -force-map objstat/mapstat option to always place a given map on each level. @@ -718,8 +1045,8 @@ and "advanced" categories. * Noise from the last turn is displayed in the top-right, replacing gold. (Gold can still be seen with % and $.) -* Terminal colors now work properly on a wider range of terminals by default. - However, as a consequence the default background map color is dark blue. +* Terminal colours now work properly on a wider range of terminals by default. + However, as a consequence the default background map colour is dark blue. To get dark grey, depending on your terminal you can set `bold_brightens_foreground=true` or `allow_extended_colours=true` in your rc file. @@ -977,7 +1304,7 @@ Interface --------- * Most targeters will be more intelligent when trying to maximize enemies hit. -* In tiles, monster attitude is indicated with colored auras instead of icons. +* In tiles, monster attitude is indicated with coloured auras instead of icons. * The (p)rayer command is gone; pray at altars with > or <, as with shops. * Descriptions of monsters with multiple spellsets show which spells you've seen them cast. @@ -1277,7 +1604,7 @@ allies in their view, making them cast spells more frequently and with more spell power. * Hell hogs now have Fireball, replacing Sticky Flame. -* Giant eyeballs are now normal speed, but must stare thrice to paralyze. +* Giant eyeballs are now normal speed, but must stare thrice to paralyse. * Maurice can now steal from the floor as well as your inventory. * Natasha no longer becomes weaker upon revival. * Death cobs now drain speed, rather than causing hunger. @@ -1296,7 +1623,7 @@ Spells ------ -* New spell: Yara's Violent Unravelling (L5 Hexes/Transumations). Dispels +* New spell: Yara's Violent Unravelling (L5 Hexes/Transmutations). Dispels all cancellable effects on the target and, if any were dispelled, causes a damaging explosion of mutagenic energy around the victim. * Hydra Form now has a fixed number of heads. @@ -1413,7 +1740,7 @@ * Clawed attacks no longer have bleeding-over-time damage effects. * There's now a distinct hunger state of Fainting and appropriate warning messages for when the player is so low on nutrition that they might become - paralyzed. + paralysed. * The Breathe Flames and Spit Poison mutations are now mutually exclusive. * Demonspawn can shoot through their own demonic guardians. * Ability scores now cap at 125, up from 72. @@ -1432,8 +1759,8 @@ ---- * Gozag: - The fee for entry has been reduced, especially early on. - - Gold distraction is now an effect centered on the player that's refreshed - whenever they find (make) new corpse-gold, rather than being centered on + - Gold distraction is now an effect centred on the player that's refreshed + whenever they find (make) new corpse-gold, rather than being centred on the gold piles themselves. - The cost of Potion Petition is more variable and higher initially, but no longer increases with use. @@ -1734,7 +2061,7 @@ * Vampires now bottle blood with 'c', and can do so from the first level. * Butchering/bottling now only takes a single turn. * Wanderers now receive a randart spellbook instead of starting with a Level 1 - spell memorized. + spell memorised. * Wanderers can start with one elemental evoker or a box of beasts instead of a wand. * Wanderer starting equipment is noted in the game log. @@ -2057,7 +2384,7 @@ * Always weight formicid weapon acquirement towards two-handed weapons. * Allow in-game updates to the mon_glyph option to change the glyph. * Allow the option syntax of mon_glyph = : in order to set the - color/glyph of one monster using the base values of another monster. + colour/glyph of one monster using the base values of another monster. * In tiles, the tile_player_tile option allows you to specify an arbitrary monster tile to display for your character. The options tile_weapon_offsets and tile_shield_offsets can be used to adjust the player weapon and shield @@ -3366,7 +3693,7 @@ * Conjurers have a new book with non-elemental spells (including the new conjurations). * Spell memorisation failure is no more. As long as the failure chance is - not 100%, the spell can be memorized. There is a warning prompt if the + not 100%, the spell can be memorised. There is a warning prompt if the chance of a miscast is high. * Some spellbooks have been reorganized. * Condensation Shield's SH bonus no longer cares about Shields skill or @@ -3616,7 +3943,7 @@ * Weapons may corrode upon stabbing a jelly. * Ambrosia gives more mp, but only as you digest it. * Raw troll hides grant regeneration. -* Jewelry auto-ids when it shows an obvious effect. +* Jewellery auto-ids when it shows an obvious effect. * Ankuses, scrolls of detect curse, amulets of controlled flight, and rods of smiting are no more. * Rods of striking are better. @@ -4566,7 +4893,7 @@ * Make skeletal warriors obey silence. * Greatly improve cacodemons. * Hungry ghost attack takes 25% of your nutrition. -* Prevent confused giant eyeballs from paralyzing. +* Prevent confused giant eyeballs from paralysing. * Make aquatic monsters chase instead of submerging if they can. * Friendly monsters told to 'wait here' don't follow through stairs. * Merged slimes split on polymorph. @@ -5638,7 +5965,7 @@ Disclaimer: These are merely the highlights, not an exhaustive list of changes. -* Fixed defunct spell slot cap (and crash) with Selective Amnesia memorized. +* Fixed defunct spell slot cap (and crash) with Selective Amnesia memorised. * Fixed the game crashing if PlaceInfo somehow ends up buggy. * Fixed runaway skill training. * Fixed vampire draining not destroying small corpses. diff -Nru crawl-0.24.0/docs/crawl_manual.rst crawl-0.25.0/docs/crawl_manual.rst --- crawl-0.24.0/docs/crawl_manual.rst 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/docs/crawl_manual.rst 2020-05-23 16:07:19.000000000 +0000 @@ -238,8 +238,8 @@ will read "Dungeon:1" for a new character. Noise - This is a colored bar indicating the loudness of noise that you heard on your - last turn. The color provides a rough guide to how far away the noise it + This is a coloured bar indicating the loudness of noise that you heard on your + last turn. The colour provides a rough guide to how far away the noise it indicates might be audible. If the bar is gray, the sound is less likely to be audible outside of your line of sight (at least in an open area); if it is yellow, the sound is likely to be audible outside of your line of sight; and @@ -1026,8 +1026,8 @@ Your chance of failing to cast a spell properly depends on your skills, your intelligence, the level of the spell and whether you are wearing heavy armour. The chance of miscasting a spell is displayed on the spell screen, and coloured -based on potential severity (with yellow representing a moderate chance, and red -representing a severe chance). +based on severity (yellow for moderate damage, light red for major +damage, red for extreme damage, and magenta for potentially lethal damage). Be careful of magic-using enemies! Some of them can use magic just as well as you, if not better, and often use it intelligently. @@ -1771,7 +1771,7 @@ Demigods (Dg) Demigods are mortals with some divine or angelic ancestry, however distant; they can be created by a number of processes, including magical experiments - and the time-honoured practice of interplanar miscegenation. + and the time-honoured practise of interplanar miscegenation. Demigods look more or less like members of their mortal part's species, but have excellent attributes (Str, Int, Dex) and are extremely robust; they can @@ -2024,7 +2024,7 @@ with some way of defending themselves. Skalds - Formidable warriors in their own rights, Skalds practice a form of augmenting + Formidable warriors in their own rights, Skalds practise a form of augmenting battle magic that is either chanted or sung. Unique to the highlands in which they originate, these spells and formulae are second nature: they can either inspire greatness in themselves and their allies, or fear in the hearts of @@ -2039,7 +2039,7 @@ and a robe. Warpers - Warpers specialise in translocation magic, and are experts in traveling long + Warpers specialise in translocation magic, and are experts in travelling long distances and positioning themselves precisely and use this to their advantage in melee or missile combat. They start with a scroll of blinking, the Book of Spatial Translocations, some dispersal tomahawks, a simple weapon of their diff -Nru crawl-0.24.0/docs/develop/arena.txt crawl-0.25.0/docs/develop/arena.txt --- crawl-0.24.0/docs/develop/arena.txt 1970-01-01 00:00:00.000000000 +0000 +++ crawl-0.25.0/docs/develop/arena.txt 2020-05-23 16:07:19.000000000 +0000 @@ -0,0 +1,154 @@ +A. Testing with the arena +============================ + +Crawl's arena mode can be used to pit one set of monsters against another and +watch them fight. For example, + + crawl -arena "3 rat v 2 kobold" + +pits 3 rats against 2 kobolds. + +If you put "arena_dump_msgs = true" into your crawl init file, then most +messages generated during the fight will be dumped to the file "arena.result". +Also adding "arena_dump_msgs_all = true" will additionally cause messages to +the diagnostics channel to be dumped. Messages to some channels will be +prefixed with the channel name, to make grepping for results easier: + + MSGCH_ERROR is prefixed with "ERR:" + MSGCH_WARN is prefixed with "WARN:" + MSGCH_DIAGNOSTICS is prefixed with "DIAG:" + MSGCH_SOUND is prefixed with "SOUND: + The TALK channels are prefixed with "TALK:" + +See docs/arena.txt for more details. + +A.1 Testing specific problems with the arena +============================================= + +Using the arena to test problems with specific monsters is rather easy: + + crawl -arena "problem monster v problem monster" + +For specific ego items is not much harder. Say you had a problem with chaos +branded melee items. You could do + + crawl -arena "10 vault guard; long sword ego:chaos v + 10 vault guard; long sword ego:chaos" + +to pit two groups of 10 vault guards against each other, all armed with chaos +long swords. + +Or if you wanted to test ammo of penetration: + + crawl -arena "10 centaur ; bow . arrow ego:penetration v + 10 centaur ; bow . arrow ego:penetration" + +Note that: + +1) You have to specify "bow", since giving monsters any specific items at all +strips them of all the standard items they are normally generated with. + +2) Different items are separated by "." + +3) You don't use plurals in the item specification; for something like arrows +an appropriate amount is given automatically. + +For more on monster and item specifications, look up ITEM and MONS in +docs/develop/level/syntax.txt + +A.2 Testing general problems with the arena +============================================ + +You can also use the arena to just see if anything unusual is happening, or if +you can catch any crashes for unknown issues. + + crawl -arena "10 random v 10 random" + +would pit two teams of random monsters against each other, appropriate for +D:20. To change the place chosen for choosing random monsters, you can use +"arena_place:" + + crawl -arena "arena_place:D:27 10 random v 10 random" + crawl -arena "arena_place:Abyss 10 random v 10 random" + crawl -arena "arena_place:Zot:5 10 random v 10 random" + etc + +Note that "arena_place" controls what's generated by the spell Shadow +Creatures, in addition to the "random" monster spec used in the command line. + +You can also pit random uniques against each other (this also affects Shadow +Creatures as well): + + crawl -arena "random_uniques 10 random v 10 random" + +You might find that certain random monsters overwhelm the arena run, like +maybe jellies are eating so many corpses that they fill the whole arena. You +can forbid monsters with certain glyphs from being randomly generated: + + crawl -arena "ban_glyphs:J 10 random v 10 random" + +A.3 Getting the arena to run for a long time +============================================== + +By default the arena exits when all the monsters on one team die, ending the +round. You can specify that multiple rounds happen by adding "t:num", but +that's limited to 99 rounds. A way to make it so that the arena will run +forever (or until you press ESC to exit it) is to add the "respawn" tag to the +arena specification. You can then leave Crawl running under a debugger +waiting for a crash, or simply grep the arena.result file after it's run for +long enough. + +For example: + + crawl -arena "respawn rat v kobold" + +Will make it so that whenever the rat dies it's replaced by a new rat, and the +same for the kobold. + + crawl -arena "respawn random v random" + +Will cause a new, random monster for the same team to be placed whenever one +or the other dies. + +If you do + + crawl -arena "respawn 10 random v 10 random" + +then the monsters tend to clump up in the middle in a huge brawl. A way to +spread this out is by adding "move_respawns": + + crawl -arena "respawn move_respawns 10 random v 10 random" + +This will make it so that when a monster respawns, it's teleported to a random +location in the arena, spreading out the fights. + +Finally, if you're using non-unique random monsters, you can add +"cycle_random" so that the random monsters are chosen by linearly cycling +through the monsters that can possibly appear in the place chosen by +"arena_place:", rather than being chosen with the weights appropriate for that +place. This will cause rare monsters to be generated a lot more often. + +A.4 Speeding up the arena +========================== + +You can speed up the arena by reducing the delay in milliseconds between turns. +You can do this on the command line with "delay:": + + crawl -arena "delay:0 random v random" + +This will cause there to be no delay between turns, or when animating beams or +explosions. You can also set the option "arena_delay" in your init file to +have it apply to all arena runs. + +A.5 Changing the arena terrain +=============================== + +You can change the terrain used in the arena with the "arena:" tag. For +example: + + crawl -arena "arena:smoke random v random" + +will cause the monsters to fight in an arena which is filled with smoke. The +available alternate terrains are in source/dat/arena.des. If an arena you +want is tagged with "arena_foo" in the des file, then you put "arena:foo" on +the command line. diff -Nru crawl-0.24.0/docs/develop/background_creation.txt crawl-0.25.0/docs/develop/background_creation.txt --- crawl-0.24.0/docs/develop/background_creation.txt 2018-09-18 09:21:35.000000000 +0000 +++ crawl-0.25.0/docs/develop/background_creation.txt 2020-05-23 16:07:19.000000000 +0000 @@ -79,8 +79,8 @@ } }, That looks like what I expect a shepherd to look like: lightly armed, lightly -armored, and just a speck of potential. Other bits of code will ensure any -weapons and armor are automatically equipped at creation (but not staves or +armoured, and just a speck of potential. Other bits of code will ensure any +weapons and armour are automatically equipped at creation (but not staves or other equippables!). If you skip one of the above steps, you'll hit an ASSERT error after running diff -Nru crawl-0.24.0/docs/develop/coding_conventions.txt crawl-0.25.0/docs/develop/coding_conventions.txt --- crawl-0.24.0/docs/develop/coding_conventions.txt 2018-09-18 09:21:35.000000000 +0000 +++ crawl-0.25.0/docs/develop/coding_conventions.txt 2020-05-23 16:07:19.000000000 +0000 @@ -390,7 +390,7 @@ #endif The reason for this is that it's common for such debug flags to be left -undefined, leading to the #if statement having an undefined behavior. Most sane +undefined, leading to the #if statement having an undefined behaviour. Most sane compilers will give undefined macros a value of '0' during such #if comparisons, but some compilers throw errors. So, play it safe. Use #ifdef. @@ -406,7 +406,7 @@ #endif The #elif statement should read '#elif defined(SOME_OTHER_FLAG)'. If the -macro was undefined, this would lead to the same undefined behavior noted +macro was undefined, this would lead to the same undefined behaviour noted above. If it was defined as above, the #elif would not function as expected. G) Spaces around parenthesis diff -Nru crawl-0.24.0/docs/develop/git/quickstart.txt crawl-0.25.0/docs/develop/git/quickstart.txt --- crawl-0.24.0/docs/develop/git/quickstart.txt 2016-05-31 07:56:08.000000000 +0000 +++ crawl-0.25.0/docs/develop/git/quickstart.txt 2020-06-03 19:28:02.000000000 +0000 @@ -210,7 +210,7 @@ 6. Patching (for regular contributors, not core devs): - Once you have commited and tested a change, you can create a patch for it. + Once you have committed and tested a change, you can create a patch for it. You can then send this patch to the devs or upload it to a mantis issue for review and potential addition to the game. diff -Nru crawl-0.24.0/docs/develop/god_creation.txt crawl-0.25.0/docs/develop/god_creation.txt --- crawl-0.24.0/docs/develop/god_creation.txt 2017-04-28 07:04:16.000000000 +0000 +++ crawl-0.25.0/docs/develop/god_creation.txt 2020-06-03 19:28:02.000000000 +0000 @@ -9,7 +9,7 @@ Today, we will add in Ralph, Demon Prince of Apathy to the Crawl pantheon. He's not known for doing much, or caring much about his followers. -He does so little, his followers reace similar levels of apathy because +He does so little, his followers reach similar levels of apathy because he can't be bothered to stop his divine power from transferring. His followers, in turn, become so apathetic that even those attacking them with bloodlust in their hearts get bored and look elsewhere. @@ -98,8 +98,8 @@ divine_peeves() and divine_likes() so that we can define out what our deity does or doesn't like. About half the gods use an empty set, and the others have at least one special thing they don't like. This is -where you set the behaviors for piety gain/loss and penance, and most of -the behaviors you'll likely want are already implemented. Ralph will use +where you set the behaviours for piety gain/loss and penance, and most of +the behaviours you'll likely want are already implemented. Ralph will use the empty default sets. Once again, these are ordered in the god_type enum order: @@ -121,7 +121,7 @@ " forgives your inadvertent attack on a neutral, just this once." } }, { DID_ATTACK_IN_SANCTUARY, { - "you attack monters in a sanctuary", false, + "you attack monsters in a sanctuary", false, 1, 1 } }, { DID_UNCLEAN, { @@ -187,7 +187,7 @@ roulette. Altars are a feature_def type, which is explained in feature.h, but altars are so common, they get a shortcut method. Colours are defined in the "VColour str_to_tile_colour(string colour)" function in colour.cc, -so check there if you want to use a color and aren't sure if it exists +so check there if you want to use a colour and aren't sure if it exists or not. That's all we care about for now, so let's make a new one: ALTAR(DNGN_ALTAR_USKAYAW, "hide-covered altar of Uskayaw", "altar_uskayaw", ETC_INCARNADINE), @@ -239,7 +239,7 @@ full name, excommunication/desertion penalties, and decaying piety and wrath timers. Ralph doesn't have either of those last 2, but we'll show you where they get handled, and you'll more than likely be happy to copy -an existing entry for your new deity in mose cases. You may also want to +an existing entry for your new deity in most cases. You may also want to update the divine_retribution() function to handle the things your god does when angry. @@ -281,7 +281,7 @@ For most deities, godwrath.cc will be necessary. The upside is that for gods with wrath, adding this is very free-form. You need to add in a line -like this to divine_retribution() to handle wrath occuring: +like this to divine_retribution() to handle wrath occurring: bool divine_retribution(god_type god, bool no_bonus, bool force) { @@ -423,6 +423,6 @@ - religion.cc for declaring your deities powers, full name, and abandonment punishment. - use you_worship(GOD_NAME_HERE), you.piety, and piety_breakpoint(star_count) - elsewhere in code for conditional behavior based on piety levels. - - update /dat/descipt/gods.txt with the flavor text entries for your new god. + elsewhere in code for conditional behaviour based on piety levels. + - update /dat/descipt/gods.txt with the flavour text entries for your new god. There should be 3 of them, and separate them with 4 %'s and the title on the next line. diff -Nru crawl-0.24.0/docs/develop/history/major-tag-history.md crawl-0.25.0/docs/develop/history/major-tag-history.md --- crawl-0.24.0/docs/develop/history/major-tag-history.md 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/docs/develop/history/major-tag-history.md 2020-05-23 16:07:19.000000000 +0000 @@ -14,7 +14,7 @@ | 1 | Nov 2011 | (0.11b) | save compat for branch `portal_branches` | [7b91fc81](https://github.com/crawl/crawl/commit/7b91fc814655) (branch) | 32 | Jan 2011 | 0.8a | save compat? | [52b7544e](https://github.com/crawl/crawl/commit/52b7544e8eed3aee8228fbdfe939f11e1bab61aa) |31 | Nov 2010 | 0.8a | revert | [d509b89e](https://github.com/crawl/crawl/commit/d509b89e63a49cb4e48bac031cda2d785bd968a0) -| 32 | Nov 2010 | 0.8a | change in rune behavior | [3a1f4483](https://github.com/crawl/crawl/commit/3a1f44834a77762edbbf7740f324bdd48e13b52d) +| 32 | Nov 2010 | 0.8a | change in rune behaviour | [3a1f4483](https://github.com/crawl/crawl/commit/3a1f44834a77762edbbf7740f324bdd48e13b52d) | 31 | Sep 2010 | 0.8a | save compat | [98cba813](https://github.com/crawl/crawl/commit/98cba81361fe4c7d0564e021d10dc6c99a6b0379) | 30 | Sep 2010 | 0.8a | save compat | [a087ed69](https://github.com/crawl/crawl/commit/a087ed692319114f86589f392593ae50d704d48d) | 29 | Jul 2010 | 0.8a | map layers | [af76f809](https://github.com/crawl/crawl/commit/af76f809d3f1679210469c3b194f1b06dc85536b) diff -Nru crawl-0.24.0/docs/develop/keys.txt crawl-0.25.0/docs/develop/keys.txt --- crawl-0.24.0/docs/develop/keys.txt 2017-04-28 07:04:16.000000000 +0000 +++ crawl-0.25.0/docs/develop/keys.txt 2020-05-23 16:07:19.000000000 +0000 @@ -127,7 +127,7 @@ ^L fight east ^Z suspend to shell ^X view visible things -^C clear rembered monsters/items from map +^C clear remembered monsters/items from map ^V nothing ^B fight southwest ^N fight southeast diff -Nru crawl-0.24.0/docs/develop/levels/advanced.txt crawl-0.25.0/docs/develop/levels/advanced.txt --- crawl-0.24.0/docs/develop/levels/advanced.txt 2019-09-15 23:48:09.000000000 +0000 +++ crawl-0.25.0/docs/develop/levels/advanced.txt 2020-05-23 16:07:19.000000000 +0000 @@ -705,7 +705,7 @@ There are several properties a Lua marker can have which will affect the dungeon cell which they are on: -* connected_exclude: Consider the cell to be separate from neighboring +* connected_exclude: Consider the cell to be separate from neighbouring cells with identical or similar features. Currently only useful for preventing adjacent doors from grouping together into a gate, forcing them to open and close as separate doors. See the Evil diff -Nru crawl-0.24.0/docs/develop/levels/guidelines.md crawl-0.25.0/docs/develop/levels/guidelines.md --- crawl-0.24.0/docs/develop/levels/guidelines.md 2019-08-26 22:45:00.000000000 +0000 +++ crawl-0.25.0/docs/develop/levels/guidelines.md 2020-05-23 16:07:19.000000000 +0000 @@ -38,6 +38,8 @@ * Note that at the start of the game, the dungeon builder removes all monsters in view of the player. Zero experience monsters like plants are exempt. +* Arrival vaults should have multiple entry points, escape hatches, or enough + space to permit tactics. ### Naming conventions diff -Nru crawl-0.24.0/docs/develop/levels/syntax.txt crawl-0.25.0/docs/develop/levels/syntax.txt --- crawl-0.24.0/docs/develop/levels/syntax.txt 2019-09-15 23:48:09.000000000 +0000 +++ crawl-0.25.0/docs/develop/levels/syntax.txt 2020-06-07 14:33:24.000000000 +0000 @@ -498,8 +498,7 @@ Modifiers: * "q:N" sets the item quantity to N (if N > 0). Does nothing if the item is not stackable. - * "charges:N" sets the number of charges for wands. Does no checks - against the maximum number of charges. + * "charges:N" sets the number of charges for wands. * "plus:N" and "plus2:N" set the item pluses for weapons, armour, jewellery (such as rings of intelligence or slaying), and throwing nets. @@ -988,7 +987,7 @@ Setting enchantments: --------------------- You may give a monster any number of enchantments. It may - start hasted, blind, have permanent DMsl, etc. The syntax is + start hasted, blind, have permanent RMsl, etc. The syntax is "ench:::" or "perm_ench::". The and fields may be omitted. Note that the enchantment will start the moment the monster is created and diff -Nru crawl-0.24.0/docs/develop/levels/triggerables.txt crawl-0.25.0/docs/develop/levels/triggerables.txt --- crawl-0.24.0/docs/develop/levels/triggerables.txt 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/docs/develop/levels/triggerables.txt 2020-05-23 16:07:19.000000000 +0000 @@ -157,7 +157,7 @@ leaves the level. [1]: "Turns" are a misnomer. The countdown operates off the value of ev:ticks(), - a value which may be, but is not always, "10" for every turn. In practice, + a value which may be, but is not always, "10" for every turn. In practise, for randomised functions, you can times your values by 10 to roughly get a "turns" value: therefore, "50" ~= every 5 turns, "200" ~= every 20 turns. diff -Nru crawl-0.24.0/docs/develop/monster_creation.txt crawl-0.25.0/docs/develop/monster_creation.txt --- crawl-0.24.0/docs/develop/monster_creation.txt 2016-09-14 20:42:23.000000000 +0000 +++ crawl-0.25.0/docs/develop/monster_creation.txt 2020-06-03 19:28:02.000000000 +0000 @@ -23,7 +23,7 @@ - /source/enum.h - Defines monster type enumeration (an ID for the monster) - In monster_type, find similar monsters and add a new entry there. - - To preserve save compatability, you need to wrap that entry + - To preserve save compatibility, you need to wrap that entry in #if TAG_MAJOR_VERSION > 34 #endif. - In the '// Add new monsters here:' block, at the end of that block add another entry for the monster. This entry should come right above @@ -48,7 +48,7 @@ ==== Implementation now becomes more complicated. Edit these files for -any special abilities, spells, or unique behavior that the monster will have. +any special abilities, spells, or unique behaviour that the monster will have. - /source/mon-cast.cc diff -Nru crawl-0.24.0/docs/develop/monster_speech.txt crawl-0.25.0/docs/develop/monster_speech.txt --- crawl-0.24.0/docs/develop/monster_speech.txt 2016-05-31 07:56:08.000000000 +0000 +++ crawl-0.25.0/docs/develop/monster_speech.txt 2020-05-23 16:07:19.000000000 +0000 @@ -242,7 +242,7 @@ speech but rather the default speech defined for fleeing humanoids in general. -In practice this means that database keys starting with "default" are +In practise this means that database keys starting with "default" are the fallback solution if the exact look-up has failed. As such, the messages should be generic enough to allow for all the possibly skipped prefixes, or else those cases should be caught earlier, e.g. diff -Nru crawl-0.24.0/docs/develop/mutation_creation.txt crawl-0.25.0/docs/develop/mutation_creation.txt --- crawl-0.24.0/docs/develop/mutation_creation.txt 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/docs/develop/mutation_creation.txt 2020-06-03 19:28:02.000000000 +0000 @@ -129,7 +129,7 @@ chance is only attached to our character level, not any skill. Farther down, in, the _do_ability function, we see the master switch() statement that handles ability use. We'll add ours in here, and order does not -matter for this one, so we'll place it by similiar abilities instead of +matter for this one, so we'll place it by similar abilities instead of at the end: case ABIL_LASER_EYES: // eye lasers @@ -214,9 +214,9 @@ That leaves melee_attack.cc as where the meat of the mutation goes. The good news is that we can make a copy of already frequently implemented -code. First let's copy this auxilliary attack class and modify it, then +code. First let's copy this auxiliary attack class and modify it, then make an instance of our new class, and then check for our new attack -along with the other auxilliary attacks: +along with the other auxiliary attacks: //CREATE THIS: class AuxBeard: public AuxAttackType diff -Nru crawl-0.24.0/docs/develop/patch_guide.txt crawl-0.25.0/docs/develop/patch_guide.txt --- crawl-0.24.0/docs/develop/patch_guide.txt 2016-05-31 07:56:08.000000000 +0000 +++ crawl-0.25.0/docs/develop/patch_guide.txt 2020-06-03 19:28:02.000000000 +0000 @@ -10,7 +10,7 @@ -------------- The Stone Soup project uses git for version control. It is preferred, although -not mandatory, for the contributors to get acquinted with the git workflow and +not mandatory, for the contributors to get acquainted with the git workflow and submit their patches in the git format. For Windows, msysgit is a good, self-contained package of all the required tools for Windows. @@ -22,7 +22,7 @@ game, you can still submit patches for the documentation, descriptions or vaults. In that case, simply ignore the steps relating to compilation and coding. You don't even need the source code for that, instead you can - simply use the binary distributation that also contains the relevant + simply use the binary distribution that also contains the relevant text files. 1.) Make a local clone of the source code: @@ -48,7 +48,7 @@ 5.) Once everything works as it should, run util/checkwhite to fix a few formatting problems. Now, you should make a local commit (or several), and - use git format-patch to produce easily appliable patches: + use git format-patch to produce easily applicable patches: git format-patch -n Where n is the number of commits you made. Each is made into a separate @@ -129,7 +129,7 @@ totally obscure, so you should be able to find out a lot about them by just fiddling with the values. In particular, beam.flavour is set to something called BEAM_POTION_STINKING_CLOUD which looks interesting enough to check -out, so I grep the source (*.h and *.cc) for all occurences and have a look +out, so I grep the source (*.h and *.cc) for all occurrences and have a look at all files this turns up. And so on. Evaluating and prioritising the findings takes some experience with the source Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/docs/develop/release/._debian.md and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/docs/develop/release/._debian.md differ diff -Nru crawl-0.24.0/docs/develop/release/debian.md crawl-0.25.0/docs/develop/release/debian.md --- crawl-0.24.0/docs/develop/release/debian.md 1970-01-01 00:00:00.000000000 +0000 +++ crawl-0.25.0/docs/develop/release/debian.md 2020-05-23 16:07:19.000000000 +0000 @@ -0,0 +1,268 @@ +# Preparing the DCSS Debian Package + +This guide covers making the packages for a debian system like Debian or +Ubuntu and installing these into the CDO PPA, +https://crawl.develz.org/debian/. The goal is to generate packages that +install on both Debian and Ubuntu for the most common architectures. +Downstream distributions do package crawl as well, but often lag behind +relative to current crawl versions, and the CDO PPA is updated with every +release. We currently produce packages for both i386 and amd64 architectures +using debian (either stable or oldstable), which usually allows installing on +Ubuntu as well. This guide has steps for building these using cowbuilder and +pbuilder, based on the debian directory in crawl-ref/source/debian of the +crawl source repository. + +The Debian maintainer's guide is a good resource for working with debian +packages: + +https://www.debian.org/doc/manuals/maint-guide/index.en.html + +## 1. Prerequisites and setup + +Basics: + +1. A Debian system of some kind. One recommended option is to use a docker + container that is specific to this purpose. This section walks you through + installing the main packages (cowbuilder, pbuilder) used for building the + packages. +2. Login access to crawl.develz.org, in order to install into the PPA. + +The cowbuilder and pbuilderrc can be set up once and re-used for each DCSS +release. The cowbuilder directory should be updated before each release. + +See the following documentation if you have trouble with cowbuilder or +pbuilder during any of these steps: + +* https://wiki.debian.org/cowbuilder +* https://wiki.debian.org/PbuilderTricks + +### 1.1 Set up your pbuilderrc + +We use the cowbuilder program to create the copy-on-write chroot directories, +and use pbuilder to build the packages in the chroot. A `pbuilderrc` file is +needed to tell pbuilder to use the cowbuilder system and to set downstream +shell variables. To use the example pbuilderrc file in this directory, copy it +to `~/.pbuilderrc` or (as root) to `/etc/pbuilderrc` after making any +modifications. + +You can edit this file to set the variables `DEBFULLNAME` and `DEBEMAIL` to your +name and email. You can also set and export these variable directly in your +shell. + +In the example pbuilderrc, all pbuilder-related data go in +`/var/cache/pbuilder`. If you need to change this location, you'll need to +modify at least `BASEPATH`, `BUILDPLACE`, `BUILDRESULT`, and `APTCACHE`. + +### 1.2 Install the cowbuilder and pbuilder packages + +This should get you the necessary packages: + + sudo apt-get install cowbuilder debhelper + +### 1.3 Create a .cow chroot directory for each architecture. + +You'll need a cowbuilder chroot directory for each architecture you want to +build. If you're using the example pbuilderrc, we use the scheme +`DIST-ARCH.cow`. For example, when building based on debian stable, we'd use: + + /var/cache/pbuilder/stable-amd64.cow + /var/cache/pbuilder/stable-i386.cow + +To create these, run the following: + + sudo OS=debian DIST=stable ARCH=amd64 cowbuilder --create \ + --basepath /var/cache/pbuilder/stable-amd64.cow + sudo OS=debian DIST=stable ARCH=i386 cowbuilder --create \ + --basepath /var/cache/pbuilder/stable-i386.cow + +In principle you can leave some of these environment variables out where they +match your current system, but it is safest not to simplify. In order for +these to run succesfully in docker, you will need to be running the docker +image with `--privileged`. + +We build the debs against either debian stable, or debian oldstable. Debian +stable is preferred, except for scenarios where that might break compatibility +with currently common Ubuntu LTS versions, in which case you should use +oldstable. (This might happen, for example, if the value for `stable` has +recently changed in debian, but Ubuntu is lagging.) + +This chroot directory needs to be created only once for each OS/ARCH/DIST +combination on which you what to build the package. If It doesn't need to be +recreated if you're only building a different DCSS version, but if you're using +a different value for any of `OS`, `ARCH`, or `DIST`, you'll need to create a +corresponding .cow chroot. + +## 2 Steps needed before release and before building the packages + +The changelog update described in 2.1 should be done before you make the +release tag. If you forget, you can apply the changelog changes in the copy of +the debian directory you make in section 3.2. + +### 2.1 Update and commit the Debian changelog + +To update the Debian changelog, add an entry at the top of this file in the +following format. + + crawl (2:VERSION-1) unstable; urgency=low + + * Major bugfix release + -- devname TIMESTAMP + +You can copy the previous entry, update the version, and use output from the +`date' command to update the timestamp. A command like the following will +give you a valid timestamp: + + date +'%a, %d %b %Y %R:%S %z' + +The entire entry must match the format of previous entries; note the lines +following the first `crawl` line have leading spaces. Incorrect formatting +can cause debuild and hence pbuilder to fail. + +Once the file is updated, commit the change to the repository so that it's +included in the release version tag. + +### 2.2 Updating the cow chroots + +It's good to update your cow chroot directory with the latest security/bugfix +updates to its packages. For the above example of using debian stable, this +would involve: + + sudo OS=debian DIST=stable ARCH=amd64 cowbuilder --update \ + --basepath /var/cache/pbuilder/stable-amd64.cow + sudo OS=debian DIST=stable ARCH=amd64 cowbuilder --update \ + --basepath /var/cache/pbuilder/stable-i386.cow + +## 3. Making the Debian packages + +At this point the release should be tagged. + +### 3.1 Make a copy of the of the source packages and extract + +The source packages should be made using the `package-source` target. Run +the following from the source directory if you haven't yet: + + make package-source + +This will make several files in the toplevel repo dir, but you specifically +need the `stone_soup-VERSION-nodeps.tar.xz` file. Copy this to a location where +you'd like to prepare the packages, then extract the source directory and +rename the original file. Using version 0.17 as an example and with +`~/crawl-deb` as the staging directory: + + mkdir -p ~/crawl-deb + cp stone_soup-0.17.0-nodeps.tar.xz ~/crawl-deb + cd ~/crawl-deb + tar Jxf stone_soup-0.17.0-nodeps.tar.xz + mv stone_soup-0.17.0 crawl-0.17.0 + mv stone_soup-0.17.0-nodeps.tar.xz crawl_0.17.0.orig.tar.xz + +Note that the name formats of `crawl-VERSION` and `crawl_VERSION.orig.EXT` for +the source directory and archive are specifically looked for by pbuilder. If +you receive errors, check that your source directory and archive follow this +format, using `crawl-` as a prefix for the directory but `crawl_` as a +prefix for the source archive. + +### 3.2 Copy and update the debian directory in the source directory + +We need the `crawl-ref/source/debian` directory to be at the top level to +build the package. Using 0.17.0 as an example, and assuming we're already in +our staging directory with the unpacked source: + + cd crawl-0.17.0 + cp -r source/debian . + +### 3.3 Build the packages + +Assuming your pbuilderrc is based on the example one in this directory, you +need to set some of the shell variables `ARCH`, `DIST`, and `OS` downstream +variables. The pbuilderrc uses these to build the packages for the +architectures (e.g. `i386` or `amd64`) you want and against the distribution you +want (e.g. `stable` or `oldstable` for Debian). + +Run `pdebuild` from the `crawl-VERSION` source directory you made above. As with +building the cows, the safest option is to explicitly specify the `OS`, `DIST`, +and `ARCH` for each build, though in principle you can leave off options +matching your current system. + + sudo OS=debian DIST=stable ARCH=amd64 pdebuild + sudo OS=debian DIST=stable ARCH=i386 pdebuild + +Once the package building is finished, the results will be in +`/var/cache/pbuilder/result/`, if you're using the example pbuilderrc. + +At this point, it may be a good idea to check the dependencies of the package +you just built. This will head off OS version mistakes, and allow you to +identify potential incompatibilities before release. For example, it is worth +checking that currently common versions of Ubuntu meet the SDL2 requirements +imposed by your debs (and high version requirements can also be a sign that +you built against the wrong OS or version somehow). You can use `dpkg -I` to +do this, for example: + + dpkg -I /var/cache/pbuilder/result/crawl-tiles_0.24.0-1_amd64.deb + +This will show a result something like (abbreviated): + + Package: crawl-tiles + Source: crawl + Version: 2:0.24.0-1 + Architecture: amd64 + Maintainer: the DCSS Development Team + Installed-Size: 10205 + Depends: libc6 (>= 2.14), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:3.4), libgl1-mesa-glx | libgl1, libglu1-mesa | libglu1, liblua5.1-0, libsdl2-2.0-0 (>= 2.0.4), libsdl2-image-2.0-0 (>= 2.0.1), libsqlite3-0 (>= 3.5.9), libstdc++6 (>= 5.2), zlib1g (>= 1:1.1.4), crawl-common (= 2:0.24.0-1), crawl-tiles-data (= 2:0.24.0-1), fonts-dejavu-core + +These dependencies (built against debian oldstable at the time) are reasonable, +because Ubuntu xenial (at the time the most common LTS version) provides +libsdl2 2.0.4. + +## 4. Install files into the official crawl PPA + +You'll need to upload all the files produced for this version in +`/var/cache/pbuilder/result` (not just the deb and dsc files) to CDO under the +`crawl` account. To keep the home directory clean, create and use a staging +directory `~/upload/VERSION/deb-files/`. + +### 4.1 Install a new repo component (major release only) + +For point releases, this step should be skipped. + +For major releases, we make a new release component for all releases of that +version. If you're logged into CDO, edit the `deb/conf/distributions` file, +adding the new version in the "Components:" field before the final entry for +"trunk", e.g. for 0.17: + + Components: 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 trunk + +### 4.2 Install the debian packages into the repository + +Install the .deb files and the .dsc file using `reprepro`. An example using 0.17 +and `~/upload/0.17.0/deb-files` as a staging directory: + + cd ~/deb + for i in ../upload/0.17.0/deb-files/*.deb + do reprepro -C 0.17 includedeb crawl "$i"; done + for i in ../upload/0.17.0/deb-files/*.dsc + do reprepro -C 0.17 includedsc crawl "$i"; done + +Note that the other files produced by pdebuild in `/var/cache/pbuilder/result` +(section 3.3) must be present in the same directory as the dsc file you +install. + +Note: If you messed something up and need to upload a new build of packages +for a version already installed in the repo, you can remove the installed +debs with a command like the following (run from ~/deb): + + reprepro -C 0.17 remove crawl crawl crawl-common crawl-tiles crawl-tiles-data crawl-tiles-dbgsym crawl-dbgsym + +Test that the repository packages are working by following the apt instructions +on the download page to install and run them. + +### 4.3 Update the download page + +The version number in the Linux example command to add the repository URL +should be updated. See release.txt for details on keeping the CDO website in +sync with the website repository. (If you are following the release guide +yourself, there is a point where you will update the current version number +for all downloads.) + +At this point, the repository should be working and the packages ready for +users to install with `apt`. diff -Nru crawl-0.24.0/docs/develop/release/debian.txt crawl-0.25.0/docs/develop/release/debian.txt --- crawl-0.24.0/docs/develop/release/debian.txt 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/docs/develop/release/debian.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,230 +0,0 @@ -Preparing the DCSS Debian Package ---------------------------------- - -This guide covers making the packages from a debian system like Debian or -Ubuntu and installing these into the CDO repo. We currently produce packages -for both i386 and amd64 architectures, and the guide has steps for building -these using cowbuilder and pbuilder, based on the debian directory in -crawl-ref/source/debian of the repo. - -The Debian maintainer's guide is a good resource for working with debian -packages: - -https://www.debian.org/doc/manuals/maint-guide/index.en.html - -1. Software Prerequisites and setup - -The cowbuilder and pbuilderrc can be set up once and re-used for each DCSS -release. The cowbuilder directory should be updated before - -See the following documentation if you have trouble with cowbuilder or -pbuilder during any of these steps: - -https://wiki.debian.org/cowbuilder -https://wiki.debian.org/PbuilderTricks - -1.1 Set up your pbuilderrc - -We use the cowbuilder program to create the copy-on-write chroot directories, -and use pbuilder to build the packages in the chroot. A pbuilderrc file is -needed to tell pbuilder to use the cowbuilder system and to set downstream -shell variables. To use the example pbuilderrc file in this directory, copy it -to ~/.pbuilderrc or (as root) to /etc/pbuilderrc after making any -modifications. - -You can edit this file to set the variables DEBFULLNAME and DEBEMAIL to your -name and email. You can also set and export these variable directly in your -shell. - -In the example pbuilderrc, all pbuilder-related data go in -/var/cache/pbuilder. If you need to change this location, you'll need to modify -at least BASEPATH, BUILDPLACE, BUILDRESULT, and APTCACHE. - -1.2 Install the cowbuilder and pbuilder packages - -This should get you the necessary packages: - - sudo apt-get install cowbuilder debhelper - -1.3 Create a .cow chroot directory for each architecture. - -You'll need a cowbuilder chroot directory for each architecture you want to -build. If you're using the example pbuilderrc, we use the scheme -`DIST-ARCH.cow'. For example, when building based on debian stable, we'd use: - - /var/cache/pbuilder/stable-amd64.cow - /var/cache/pbuilder/stable-i386.cow - -To create these, run the following: - - sudo cowbuilder --create --architecture amd64 \ - --basepath /var/cache/pbuilder/stable-amd64.cow - sudo cowbuilder --create --architecture i386 \ - --basepath /var/cache/pbuilder/stable-i386.cow - -In order for these to run succesfully in docker, you will need to be running -the docker image with --privileged. - -This chroot directory needs to be created only once for each OS/ARCH/DIST -combination on which you what to build the package. If It doesn't need to be -recreated if you're only building a different DCSS version, but if you're using -a different value for any of OS, ARCH, or DIST, you'll need to create a -corresponding .cow chroot. - -2 Steps needed before release and before building the packages - -The changelog update described in 2.1 should be done before you make the -release tag. If you forget, you can apply the changelog changes in the copy of -the debian directory you make in section 3.2. - -2.1 Update and commit the Debian changelog - -To update the Debian changelog, add an entry at the top of this file in the -following format. - -crawl (2:VERSION-1) unstable; urgency=low - - * Major bugfix release - - -- devname TIMESTAMP - -You can copy the previous entry, update the version, and use output from the -`date' command to update the timestamp. A command like the following will -give you a valid timestamp: - - date +'%a, %d %b %Y %R:%S %z' - -The entire entry must match the format of previous entries; note the lines -following the first `crawl' line have leading spaces. Incorrect formatting -can cause debuild and hence pbuilder to fail. - -Once the file is updated, commit the change to the repository so that it's -included in the release version tag. - -2.2 Updating the cow chroots - -It's good to update your cow chroot directory with the latest security/bugfix -updates to its packages: - - sudo cowbuilder --update --architecture amd64 \ - --basepath /var/cache/pbuilder/stable-amd64.cow - sudo cowbuilder --update --architecture i386 \ - --basepath /var/cache/pbuilder/stable-i386.cow - -3. Making the Debian packages - -At this point the release should be tagged. - -3.1 Make a copy of the of the source packages and extract - -The source packages should be made using the `package-source' target. Run -the following from the source directory if you haven't yet: - - make package-source - -This will make several files in the toplevel repo dir, but you specifically -need the `stone_soup-VERSION-nodeps.tar.xz' file. Copy this to a location where -you'd like to prepare the packages, then extract the source directory and -rename the original file. Using version 0.17 as an example and with -~/crawl-deb as my staging directory: - - mkdir -p ~/crawl-deb - cp stone_soup-0.17.0-nodeps.tar.xz ~/crawl-deb - cd ~/crawl-deb - tar Jxf stone_soup-0.17.0-nodeps.tar.xz - mv stone_soup-0.17.0 crawl-0.17.0 - mv stone_soup-0.17.0-nodeps.tar.xz crawl_0.17.0.orig.tar.xz - -Note that the name formats of crawl-VERSION and crawl_VERSION.orig.EXT for -the source directory and archive are specifically looked for by pbuilder. If -you receive errors, check that your source directory and archive follow this -format, using `crawl-` as a prefix for the directory but `crawl_` as a -prefix for the source archive. - -3.2 Copy and update the debian directory in the source directory - -We need the crawl-ref/source/debian directory to be at the top level to -build the package. Using 0.17.0 as an example, and assuming we're already in -our staging directory with the unpacked source: - - cd crawl-0.17.0 - cp -r source/debian . - -3.3 Build the packages - -Assuming your pbuilderrc is based on the example one in this directory, you -need to set some of the shell variables ARCH, DIST, and OS downstream -variables. The pbuilderrc uses these to build the packages for the -architectures (e.g. i386 or amd64) you want and against the distribution you -want (e.g. stable or testing for Debian), and based on the OS you want (e.g. -debian or ubuntu). - -Run pdebuild from the `crawl-VERSION' source directory you made above. The -simplest build situation is making packages for the same architecture and -against the same distribution as your host system. Using our 0.17.0 example -building against debian stable on a debian stable system for amd64, simply: - - sudo pdebuild - -Then to build the i386 package: - - sudo ARCH=i386 pdebuild - -If you're on ubuntu, building against debian stable, you might need: - - sudo OS=debian DIST=stable pdebuild - sudo OS=debian DIST=stable ARCH=i386 pdebuild - -Once the package building is finished, the results will be in -/var/cache/pbuilder/result, if you're using the example pbuilderrc. - -3.4 Upload files to CDO - -You'll need to upload all the files produced in /var/cache/pbuilder/result (not -just the deb and dsc files) to CDO. The staging directory -~/upload/VERSION/deb-files can be used for this. - -3.5 Install a new repo component (major release only) - -For point releases, this step should be skipped. - -For major releases, we make a new release component for all releases of that -version. If you're logged into CDO, edit the `deb/conf/distributions` file, -adding the new version in the "Components:" field before the final entry for -"trunk": - -Components: 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 trunk - - -3.6 Install the debian packages into the repository - -Install the .deb files and the .dsc file using reprepro. An example using 0.17 -and `~/upload/0.17.0/deb-files' as a staging directory: - - cd ~/deb - for i in ../upload/0.17.0/deb-files/*.deb - do reprepro -C 0.17 includedeb crawl "$i"; done - for i in ../upload/0.17.0/deb-files/*.dsc - do reprepro -C 0.17 includedsc crawl "$i"; done - -Note that the other files produced by pdebuild in /var/cache/pbuilder/result -(section 3.3) must be present in the same directory as the dsc file you -install. - -Note: If you messed something up and need to upload a new build of packages -for a version already installed in the repo, you can remove the installed -debs with a command like the following (run from ~/deb): - - reprepro -C 0.17 remove crawl crawl crawl-common crawl-tiles crawl-tiles-data - -Test that the repository packages are working by following the apt instructions -on the download page to install and run them. - -3.6 Update the download page - -The version in the Linux example command to add the repository URL should be -updated. See release.txt for details on keeping the CDO website in sync with -the website repository. - -At this point, the repository should be working and the packages ready for -users to install with apt. diff -Nru crawl-0.24.0/docs/develop/release/guide.txt crawl-0.25.0/docs/develop/release/guide.txt --- crawl-0.24.0/docs/develop/release/guide.txt 2018-09-18 09:21:35.000000000 +0000 +++ crawl-0.25.0/docs/develop/release/guide.txt 2020-05-23 16:07:19.000000000 +0000 @@ -90,60 +90,35 @@ version. -7. Tag the release +7. Tag and create the release In the branch you're about to tag: - git tag -a 0.X.y - - Don't push the tag yet so you can make final amendments. - -8. Package the source tarball, produce final builds and Debian packages + git tag -a 0.X.y + git push --tags - "make package-source" will create three source tar/zipballs. + Then, visit the GitHub releases page: - For binary builds, you need to ensure at least the dat/ subdir contains no - foreign files (such as editor backup files, uncommitted stuff, random junk, - etc). Thus, "git clean -dfx". This is a potentially destructive operation so - if you have files lying around, you may want to do this from a separate - clone instead. + https://github.com/crawl/crawl/releases - You can use enable optimizations in the builds, but these can make - cross-compilation difficult. Adding the make option LTO=y will enable - long-term optimization, but this can fail under cross-compilation. + You should have the ability to create a release from this tag. Once you + create the release, GitHub Actions will automatically upload macOS and + Windows builds as release assets. - The Makefile targets are "package-windows" and "package-windows-zips" for - the installer and stand-alone zips respectively. Unless you're on msys, you - need to specify CROSSHOST as well: - make CROSSHOST=i686-w64-mingw32 package-windows +8. Package the source tarball, and produce Debian packages - It's ideal to test the windows packages (both Tiles and console) under wine - at the very least, assuming you've cross-compiled, and testing under a - recent version of windows is preferable. Follow the sanity test steps in - step 4. + "make package-source" will create three source tar/zipballs. You can add + these to the GitHub release as additional assets. For building the Debian packages and installing them into the CDO repository, see the debian.txt guide in this directory. -9. Push the tag - - Until the moment you push it to the official repository, you can delete it - and re-tag: - - git push --tags - - The tags are some sort of frozen state of the source for all releases, so - this is the last step you take before the actual release. All further - changes make it into the next minor version. - - -10. Upload the files to CDO +9. Update download links on CDO - Use the crawl login on CDO to upload the binaries to ~/website/release/ - over scp or sftp. The links on the download page currently at - ~/website/download.htm must then be updated. + Use the crawl login on CDO to update the links on the download page + currently at ~/website/download.htm. Presently there's a repository that manages the web files for non-wordpress pages on CDO like the splash and download pages. This repo is cloned to @@ -160,7 +135,7 @@ guide in this directory. -11. Update Sourceforge +10. Update Sourceforge We currently use Sourceforge only for the CRD mailing list. Until CRD is moved somewhere else, we want to keep the Sourceforge release binaries @@ -172,12 +147,12 @@ most, .exe installer for Windows). -12. Announce the release +11. Announce the release Post a release announcement to the CDO blog and send an email over crawl-ref-discuss. If you want you can also write a news item on Sourceforge. -13. Lean back and enjoy the excitement +12. Lean back and enjoy the excitement ...until the first bug reports roll in. ;) diff -Nru crawl-0.24.0/docs/develop/team/new_dev_guidelines.md crawl-0.25.0/docs/develop/team/new_dev_guidelines.md --- crawl-0.24.0/docs/develop/team/new_dev_guidelines.md 2018-10-13 03:25:38.000000000 +0000 +++ crawl-0.25.0/docs/develop/team/new_dev_guidelines.md 2020-05-23 16:07:19.000000000 +0000 @@ -4,60 +4,166 @@ ## Setup -Other team members will help you get the items in the [*new dev checklist*](../team/new_dev_checklist.txt) covered. Once you’ve been given commit access, configuring git properly so that you can make your first commit is a priority. See the [*git configuration doc*](../git/config.txt), especially the options about rebasing so you avoid making unnecessary merge commits. +Other team members will help you get the items in the [*new dev +checklist*](../team/new_dev_checklist.txt) covered. Once you’ve been given +commit access, configuring git properly so that you can make your first commit +is a priority. See the [*git configuration doc*](../git/config.txt), especially +the options about rebasing so you avoid making unnecessary merge commits. ## Team Discussion and Coordination -Most development discussion happens on IRC in the \#\#crawl-dev on Freenode, so it's good to join and participate in that channel. Use the !tell command through Sequell to leave IRC messages to other team or community members you’re working with. The channel is also [*logged*](http://s-z.org/crawl-dev/#), if you’d like to read or search previous discussions. - -Although nearly all changes are just discussed on IRC, larger projects can be written up in an email sent to the [*CRD mailing list*](http://sourceforge.net/p/crawl-ref/mailman/crawl-ref-discuss/) or placed on page in the [*Dev Wiki*](https://crawl.develz.org/wiki/doku.php). The Dev Wiki is helpful if you’d like to brainstorm and organize a large list of changes. The CRD mailing list is a way to discuss high-impact changes if you feel extended, organized discussion is necessary. - -We also coordinate [*release plans*](https://crawl.develz.org/wiki/doku.php?id=dcss:planning:release_plans) on the Dev Wiki. These plans are most useful at the beginning of each version, when we’re brainstorming what major areas to work on, and closer to release, when we decide which features will make it in the next version. You don’t have to continuously update entries you make in a release plan during the alpha version, but it’s good to update items as you complete them. +Most development discussion happens on IRC in the \#\#crawl-dev on Freenode, so +it's good to join and participate in that channel. Use the !tell command +through Sequell to leave IRC messages to other team or community members you’re +working with. The channel is also [*logged*](http://s-z.org/crawl-dev/#), if +you’d like to read or search previous discussions. + +Although nearly all changes are just discussed on IRC, larger projects can be +written up in an email sent to the [*CRD mailing +list*](http://sourceforge.net/p/crawl-ref/mailman/crawl-ref-discuss/) or placed +on page in the [*GitHub Wiki*](https://github.com/crawl/crawl/wiki). The +Wiki is helpful if you’d like to brainstorm and organize a large list of +changes. The CRD mailing list is a way to discuss high-impact changes if you +feel extended, organized discussion is necessary. + +We also coordinate *release plans* on the GitHub Wiki. These plans are most +useful at the beginning of each version, when we’re brainstorming what major +areas to work on, and closer to release, when we decide which features will +make it in the next version. You don’t have to continuously update entries you +make in a release plan during the alpha version, but it’s good to update items +as you complete them. ## Coding Standards -We value having reasonably correct, well-thought out code that doesn't break other aspects of the game over simply getting in content changes as fast as possible. If you're not sure how to implement something, please ask other team members who have more experience with the codebase. You can use a code pasting service like github gist, dpaste, sprunge, or pastebin to share code snippets. +We value having reasonably correct, well-thought out code that doesn't break +other aspects of the game over simply getting in content changes as fast as +possible. If you're not sure how to implement something, please ask other team +members who have more experience with the codebase. You can use a code pasting +service like github gist, dpaste, sprunge, or pastebin to share code snippets. ## Documentation and Formatting -The [*coding conventions*](http://s-z.org/neil/git/?p=crawl.git;a=blob;f=crawl-ref/docs/develop/coding_conventions.txt) document describes how Crawl’s C++ source code should be formatted. For documenting C++ code, we use [*Doxygen*](http://www.stack.nl/~dimitri/doxygen/index.html) comments and the JavaDoc style, and example of which you can see [*here*](http://s-z.org/neil/git/?p=crawl.git;a=blob;f=crawl-ref/source/ability.cc#l3553). It’s preferred that you document all new functions and data structures in this way, but not required. - -Significant changes that affect the gameplay should be documented in the [*changelog*](http://s-z.org/neil/git/?p=crawl.git;a=blob;f=crawl-ref/docs/changelog.txt;hb=HEAD). We try to be brief in these entries, giving players a simple description of the change without technical detail. It’s good to read previous entries or ask a team member if you’re not sure about including an item or how to word it. +The [*coding conventions*](crawl-ref/docs/develop/coding_conventions.txt) +document describes how Crawl’s C++ source code should be formatted. For +documenting C++ code, we use +[*Doxygen*](http://www.stack.nl/~dimitri/doxygen/index.html) comments and the +JavaDoc style, and example of which you can see +[*here*](crawl-ref/source/ability.cc#l3553). It’s preferred that you document +all new functions and data structures in this way, but not required. + +Significant changes that affect the gameplay should be documented in the +[*changelog*](crawl-ref/docs/changelog.txt). We try to be brief in +these entries, giving players a simple description of the change without +technical detail. It’s good to read previous entries or ask a team member if +you’re not sure about including an item or how to word it. ## Save Compatibility -Each trunk commit creates a new version, and we try hard to not break trunk games when a save is transferred to a new version. Making changes that force users to abandon a game they have in-progress is frustrating for players and creates problems for server administrators as well. There’s a [*document*](../save_compatibility.txt) in the source tree that discusses basic save compatibility and the technical reasons behind it. In general, if you’re not sure if a change will create a save compatibility issue or how to address it, ask another team member before pushing your changes. +Each trunk commit creates a new version, and we try hard to not break trunk +games when a save is transferred to a new version. Making changes that force +users to abandon a game they have in-progress is frustrating for players and +creates problems for server administrators as well. There’s a +[*document*](../save_compatibility.txt) in the source tree that discusses basic +save compatibility and the technical reasons behind it. In general, if you’re +not sure if a change will create a save compatibility issue or how to address +it, ask another team member before pushing your changes. ## Bug Reports and Community Contributions -We handle these through our [*Mantis issue tracker*](https://crawl.develz.org/mantis/view_all_bug_page.php) and our [*GitHub page*](https://github.com/crawl/crawl). - -On Mantis, we can also assign issues to ourselves or to other developers. Self-assignment is used if the developer in question is working on the issue. Assigning to someone else is used if the issue in question is in their area of expertise, or if the assigner wants their opinion. Either way, the reason for assignment should be explained in the assigning message. - -Contributions and patches are submitted through both systems. Depending on quality of submission, concordance to design guidelines, and general suitability, comment and ask for improvement/clarification on these, then close/merge accordingly. - -Desired features and changes -- "Implementables" -- can be posted to either system, informally requesting that someone from the community takes up the project and completes them. Do not expect that this will be fulfilled within a short time frame. On GitHub, you can post these as an Issue asking for help, and on Mantis you will need to tag them explicitly as an implementable. If people are looking for things to work on, then we can point them towards these implementables. +We handle these through our [*Mantis issue +tracker*](https://crawl.develz.org/mantis/view_all_bug_page.php) and our +[*GitHub page*](https://github.com/crawl/crawl). + +On Mantis, we can also assign issues to ourselves or to other developers. +Self-assignment is used if the developer in question is working on the issue. +Assigning to someone else is used if the issue in question is in their area of +expertise, or if the assigner wants their opinion. Either way, the reason for +assignment should be explained in the assigning message. + +Contributions and patches are submitted through both systems. Depending on +quality of submission, concordance to design guidelines, and general +suitability, comment and ask for improvement/clarification on these, then +close/merge accordingly. + +Desired features and changes -- "Implementables" -- can be posted to either +system, informally requesting that someone from the community takes up the +project and completes them. Do not expect that this will be fulfilled within a +short time frame. On GitHub, you can post these as an Issue asking for help, +and on Mantis you will need to tag them explicitly as an implementable. If +people are looking for things to work on, then we can point them towards these +implementables. ## Release Schedule -Although there isn’t a fixed schedule, releases tend to happen every 6 months and are followed by a two week [*online tournament*](http://dobrazupa.org/tournament/0.19/) based on the released version. The steps for branching and tagging the release in git as well as building the release packages are described in the [*release guide*](https://github.com/crawl/crawl/blob/master/crawl-ref/docs/develop/release/guide.txt). The work for release and tournament is usually done by several people who help out with specific portions of the process from release to release. Ask other team members if you’d like to help out. +Although there isn’t a fixed schedule, releases tend to happen every 6 months +and are followed by a two week *online tournament* based on the released +version. The steps for branching and tagging the release in git as well as +building the release packages are described in the [*release +guide*](crawl-ref/docs/develop/release/guide.txt). The work for release and +tournament is usually done by several people who help out with specific +portions of the process from release to release. Ask other team members if +you’d like to help out. ## Development Philosophy -As a new developer, it's good to discuss significant gameplay changes with at least a few others before pushing them and to not be too attached to a new idea you may have. Below are some general principles about the development process. +As a new developer, it's good to discuss significant gameplay changes with at +least a few others before pushing them and to not be too attached to a new idea +you may have. Below are some general principles about the development process. #### Team Cooperation -Team members have varying levels of free time, and their availability fluctuates. It's important to listen when others say they may not have time to critique your idea or double-check your code. Be prepared to ask someone else or the team as a whole in \#\#crawl-dev or on CRD. If your implementation seems well tested and reasonably agreed upon by the rest of the team in your best judgement, go ahead and push it to the repository! +Team members have varying levels of free time, and their availability +fluctuates. It's important to listen when others say they may not have time to +critique your idea or double-check your code. Be prepared to ask someone else +or the team as a whole in \#\#crawl-dev or on CRD. If your implementation seems +well tested and reasonably agreed upon by the rest of the team in your best +judgement, go ahead and push it to the repository! #### Game Design -It's important to play Crawl if you want to design for it. Experiencing the content you create is very helpful in determining whether that content is enjoyable and creates the intended game-play experience. Playing a variety of characters in Crawl also helps you understand how the game does and does not succeed in being highly replayable, with an emphasis on combat, and where the player is generally not rewarded for tedious game-play. You can also help us uncover bugs and problems with existing code, and stay informed as to the current state of Crawl. +It's important to play Crawl if you want to design for it. Experiencing the +content you create is very helpful in determining whether that content is +enjoyable and creates the intended game-play experience. Playing a variety of +characters in Crawl also helps you understand how the game does and does not +succeed in being highly replayable, with an emphasis on combat, and where the +player is generally not rewarded for tedious game-play. You can also help us +uncover bugs and problems with existing code, and stay informed as to the +current state of Crawl. #### Consensus and the Development Process -While we strive towards a general consensus, it is not required. There will be occasional disagreement on how to improve Crawl, or what paths to take towards that goal. There are no formal rules or processes for resolving these disagreements. Developers are free, within reason, to make commits and changes to the game. Not requiring the full consensus of the dev team to make any particular change prevents design stagnation (it is much more likely that at least one person disagrees than it is that everyone agrees), but because members of the team are allowed to disagree with each other monopolies are also prevented (others are capable of having good ideas, even if someone might disagree initially or continuously). +While we strive towards a general consensus, it is not required. There will be +occasional disagreement on how to improve Crawl, or what paths to take towards +that goal. There are no formal rules or processes for resolving these +disagreements. Developers are free, within reason, to make commits and changes +to the game. Not requiring the full consensus of the dev team to make any +particular change prevents design stagnation (it is much more likely that at +least one person disagrees than it is that everyone agrees), but because +members of the team are allowed to disagree with each other monopolies are also +prevented (others are capable of having good ideas, even if someone might +disagree initially or continuously). #### Player Feedback -In addition to play-testing, it’s good to watch players through WebTiles, via console ttyrecs, videos and other online recordings. Likewise, it can be useful to see what players think about certain features by reading online discussion on [*Tavern*](https://crawl.develz.org/tavern/), Reddit (see [*/r/dcss*](http://www.reddit.com/r/dcss/) and [*/r/roguelikes*](http://www.reddit.com/r/roguelikes/)), and other online discussion sites. However it’s important that player praise or criticism is always taken with a grain of salt. If in doubt, get in touch with other developers for some grounding -- \#\#crawl-dev is always good for that. +In addition to play-testing, it’s good to watch players through WebTiles, via +console ttyrecs, videos and other online recordings. Likewise, it can be useful +to see what players think about certain features by reading online discussion +on [*Tavern*](https://crawl.develz.org/tavern/), Reddit (see +[*/r/dcss*](http://www.reddit.com/r/dcss/) and +[*/r/roguelikes*](http://www.reddit.com/r/roguelikes/)), and other online +discussion sites. However it’s important that player praise or criticism is +always taken with a grain of salt. If in doubt, get in touch with other +developers for some grounding -- \#\#crawl-dev is always good for that. + +#### Adding new members + +An development team member may suggest to others in a private e-mail that +commit rights be given to a contributor. As other members agree (or there +are no objections), commit rights are usually given, and this is then +announced. + +Generally, if a contributor supplies a substantial amount of patches of good +quality (i.e. patches don't break things, don't need cleaning up before +committing and are in line with the general direction of the development) and +fits with the spirit of team cooperation it makes sense to give them commit +rights. Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/docs/develop/._testing.md and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/docs/develop/._testing.md differ diff -Nru crawl-0.24.0/docs/develop/testing.md crawl-0.25.0/docs/develop/testing.md --- crawl-0.24.0/docs/develop/testing.md 1970-01-01 00:00:00.000000000 +0000 +++ crawl-0.25.0/docs/develop/testing.md 2020-05-23 16:07:19.000000000 +0000 @@ -0,0 +1,167 @@ +# Testing + +## Contents + +* [Unit Tests](#unit-tests) + * [Plug & Play / Bisect Testing](#plug-play-bisect-testing) +* [Functional (Lua) Tests](#functional-lua-tests) +* [Arena Testing](#arena-testing) +* [Code Coverage](#code-coverage) + +## Unit Tests + +Crawl integrates the Catch2 unit testing framework. Tests are in the [crawl-ref/source/catch2-tests](crawl-ref/source/catch2-tests) directory. To compile and run all units tests, use: + +```sh +make catch2-tests +``` + +### Plug & Play / Bisect Testing + +`test_plug_and_play.cc` is an optional source file for catch2 tests. If +the source file is available, the `make plug-and-play-tests` command +will use it to create a catch2 tests binary. If the source file is not +available, the `make plug-and-play-tests` command will fail. This source +file is in the .gitignore and should never be added to the git project. + +The main use of `test_plug_and_play.cc` is for the file to be used in +conjunction with the `git bisect` command. If you don't know how the git +bisect command works, reference `git bisect --help` because otherwise +none of the following will make sense. + +`test_plug_and_play.cc` is a file which: + +1. Compilations of versions of crawl older than master can search for +catch2 tests +2. Will not be overwritten by git history changes, such as those which +occur while using git bisect. + +This combination of features allows for you to write tests once, then +use them for any version of crawl which has previously existed, all the +way back to the original implementation of catch2 support for crawl. + +While you are hunting down a bug introduced in newer versions of crawl, +see if you can create a catch2 test which checks for the bug in +`test_plug_and_play.cc`. Verify this test works with `make +plug-and-play-tests`. Then, see if this test works correctly when you +`git checkout` a version of crawl which does not have the bug. If both +are true, you can use `test_plug_and_play.cc` to easily find the bug. + +Simply use git bisect as normally, but compile and run +plug-and-play-tests instead of normal crawl. Whenever the bug is +present, your test will fail and you can mark that commit as bad. +Whenever the bug is absent, your test will pass and you can mark that +commit as good. + +This test process is so easy git bisect allows you to automate it. Look +into `git bisect run` for more details. + +When you've finished solving the bug, remember to move the new test from +`test_plug_and_play.cc` to a regular test file included in the git +project! This will help prevent regressions. + +## Functional (Lua) Tests + +Crawl has a set of functional tests in the [source/test/](crawl-ref/source/test/) directory, with each lua +file being a separate unit test. To use unit tests, you must compile Crawl +either with the macro `DEBUG_DIAGNOSTICS` defined (the debug make target) or +with both the macros `DEBUG` and `DEBUG_TESTS` defined (the wizard make target, +plus `-DDEBUG_TESTS`). You can then do + +```sh +crawl -test +``` + +to run all unit tests. To run a particular test, you can do + +```sh +crawl -test foo +``` + +and that will run all unit tests which have "foo" in their file name. + +If you want to write your own unit tests, take a look at the files in +[source/test/](crawl-ref/source/test/) for examples. [los_maps.lua](crawl-ref/source/test/los_maps.lua) and [bounce.lua](crawl-ref/source/test/bounce.lua) have +examples which use vaults (maps) which are located in test/des. You +might need to create new Lua functions in the `source/l_*.cc` files if none of +the `crawl.foo()`/`dgn.foo()`/etc functions do what you need. + +## Arena Testing + +You can use Crawl's arena mode to test a lot of things. See [arena.txt](crawl-ref/docs/develop/arena.txt) for more information. + +## Code Coverage + +Code coverage instrumentation is included in all debug & unit test builds. You can use it as follows: + +1. Compile the game in debug or unit test mode: + +```sh +make debug +# or +make catch2-tests +``` + +2. Run the compiled binary to generate coverage data: + +```sh +./crawl -test +# or +# ./catch2-test-executable # no need, Makefile ran this automatically +``` + +3. Generate the coverage report: + +```sh +util/coverage # Add --help to see customisation options +``` + +### Quirks + +1. Coverage data from multiple runs is combined. This can lead to confusing execution counts for source code lines in reports. Use `make clean-coverage` to remove all temporary coverage files (including reports). + +### A Quick Comparison of HTML Report Formats + +Sub-expression coverage covers the granularity of testing a line of code like this: + +```cpp +if (test1() && test2()) +``` + +#### lcov / genhtml + +* Included with GCC on many Linux distributions (if not, easy to install) +* No sub-expression coverage (line-coverage only) + +#### llvm-cov + +* Included with LLVM/Clang +* Partial sub-expression coverage (will detect un-executed sub-expressions) + +#### gcovr + +* Python 3-based utility, harder to install on mingw and older systems +* Full sub-expression coverage (will detect if each sub-expression was tested with a positive and negative test case) + +### Implementation Details + +Code coverage is handled very differently between the GCC and LLVM toolchains. The `Makefile` and `util/coverage` both auto-detect your toolchain, so this is abstracted away for general use. However, coverage percentages and details will be slightly different. + +#### GCC + +1. Compile with `-fprofile-arcs -ftest-coverage`, this generates `.gcno` files (one per source file) +2. When run, your executable creates `.gcda` (one per source file) +3. Use either `lcov`/`genhtml` or `gcovr`: + * `lcov`/`genhtml` + 1. Parse `gcno`/`gcda` files with `lcov` into a `.info` file + 2. Generate reports with `genhtml`. + * `gcovr` + 1. Generate reports with `gcovr`. + * (`gcovr` uses `gcov` to parse `gcno`/`gcda` files.) + +#### LLVM + +1. Compile with `-fprofile-instr-generate -fcoverage-mapping` +2. When run, your executable creates `default.profraw` +3. Parse this with `llvm-profdata` into a `.profdata` file +4. Generate reports with `llvm-cov`. diff -Nru crawl-0.24.0/docs/develop/testing.txt crawl-0.25.0/docs/develop/testing.txt --- crawl-0.24.0/docs/develop/testing.txt 2017-04-28 07:04:16.000000000 +0000 +++ crawl-0.25.0/docs/develop/testing.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,180 +0,0 @@ -A. Unit tests -=============== - -Crawl has a set of unit tests in the source/test/ directory, with each lua -file being a separate unit test. To use unit tests, you must compile Crawl -either with the macro DEBUG_DIAGNOSTICS defined (the debug make target) or -with both the macros DEBUG and DEBUG_TESTS defined (the wizard make target, -plus -DDEBUG_TESTS). You can then do - - crawl -test - -to run the unit tests. To run paricular unit tests, you can do - - crawl -test foo - -and that will run all unit tests which have "foo" in their file name. - -If you want to write your own unit tests, take a look at the files in -source/test for examples. test/los_maps.lua and test/bounce.lua have -examples which use vaults (maps) which are located in test/des. You -might need to create new Lua functions in the source/l_*.cc files if none of -the crawl.foo()/dgn.foo()/etc functions do what you need. - -============================================================================= -============================================================================= - -B. Testing with the arena -============================ - -Crawl's arena mode can be used to pit one set of monsters against another and -watch them fight. For example, - - crawl -arena "3 rat v 2 kobold" - -pits 3 rats against 2 kobolds. - -If you put "arena_dump_msgs = true" into your crawl init file, then most -messages generated during the fight will be dumped to the file "arena.result". -Also adding "arena_dump_msgs_all = true" will additionally cause messages to -the diagnostics channel to be dumped. Messages to some channels will be -prefixed with the channel name, to make grepping for results easier: - - MSGCH_ERROR is prefixed with "ERR:" - MSGCH_WARN is prefixed with "WARN:" - MSGCH_DIAGNOSTICS is prefixed with "DIAG:" - MSGCH_SOUND is prefixed with "SOUND: - The TALK channels are prefixed with "TALK:" - -See docs/arena.txt for more details. - -B.1 Testing specific problems with the arena -============================================= - -Using the arena to test problems with specific monsters is rather easy: - - crawl -arena "problem monster v problem monster" - -For specific ego items is not much harder. Say you had a problem with chaos -branded melee items. You could do - - crawl -arena "10 vault guard; long sword ego:chaos v - 10 vault guard; long sword ego:chaos" - -to pit two groups of 10 vault guards against each other, all armed with chaos -long swords. - -Or if you wanted to test ammo of penetration: - - crawl -arena "10 centaur ; bow . arrow ego:penetration v - 10 centaur ; bow . arrow ego:penetration" - -Note that: - -1) You have to specify "bow", since giving monsters any specific items at all -strips them of all the standard items they are normally generated with. - -2) Different items are separated by "." - -3) You don't use plurals in the item specification; for something like arrows -an appropriate amount is given automatically. - -For more on monster and item specifications, look up ITEM and MONS in -docs/develop/level/syntax.txt - -B.2 Testing general problems with the arena -============================================ - -You can also use the arena to just see if anything unusual is happening, or if -you can catch any crashes for unknown issues. - - crawl -arena "10 random v 10 random" - -would pit two teams of random monsters against each other, appropriate for -D:20. To change the place chosen for choosing random monsters, you can use -"arena_place:" - - crawl -arena "arena_place:D:27 10 random v 10 random" - crawl -arena "arena_place:Abyss 10 random v 10 random" - crawl -arena "arena_place:Zot:5 10 random v 10 random" - etc - -Note that "arena_place" controls what's generated by the spell Shadow -Creatures, in addition to the "random" monster spec used in the command line. - -You can also pit random uniques against each other (this also affects Shadow -Creatures as well): - - crawl -arena "random_uniques 10 random v 10 random" - -You might find that certain random monsters overwhelm the arena run, like -maybe jellies are eating so many corpses that they fill the whole arena. You -can forbid monsters with certain glyphs from being randomly generated: - - crawl -arena "ban_glyphs:J 10 random v 10 random" - -B.3 Getting the arena to run for a long time -============================================== - -By default the arena exits when all the monsters on one team die, ending the -round. You can specify that multiple rounds happen by adding "t:num", but -that's limited to 99 rounds. A way to make it so that the arena will run -forever (or until you press ESC to exit it) is to add the "respawn" tag to the -arena specification. You can then leave Crawl running under a debugger -waiting for a crash, or simply grep the arena.result file after it's run for -long enough. - -For example: - - crawl -arena "respawn rat v kobold" - -Will make it so that whenever the rat dies it's replaced by a new rat, and the -same for the kobold. - - crawl -arena "respawn random v random" - -Will cause a new, random monster for the same team to be placed whenever one -or the other dies. - -If you do - - crawl -arena "respawn 10 random v 10 random" - -then the monsters tend to clump up in the middle in a huge brawl. A way to -spread this out is by adding "move_respawns": - - crawl -arena "respawn move_respawns 10 random v 10 random" - -This will make it so that when a monster respawns, it's teleported to a random -location in the arena, spreading out the fights. - -Finally, if you're using non-unique random monsters, you can add -"cycle_random" so that the random monsters are chosen by linearly cycling -through the monsters that can possibly appear in the place chosen by -"arena_place:", rather than being chosen with the weights appropriate for that -place. This will cause rare monsters to be generated a lot more often. - -B.4 Speeding up the arena -========================== - -You can speed up the arena by reducing the delay in miliseconds between turns. -You can do this on the command line with "delay:": - - crawl -arena "delay:0 random v random" - -This will cause there to be no delay between turns, or when animating beams or -explosions. You can also set the option "arena_delay" in your init file to -have it apply to all arena runs. - -B.5 Changing the arena terrain -=============================== - -You can change the terrain used in the arena with the "arena:" tag. For -example: - - crawl -arena "arena:smoke random v random" - -will cause the monsters to fight in an arena which is filled with smoke. The -available alternate terrains are in source/dat/arena.des. If an arena you -want is tagged with "arena_foo" in the des file, then you put "arena:foo" on -the command line. diff -Nru crawl-0.24.0/docs/develop/test_plug_and_play_cc.txt crawl-0.25.0/docs/develop/test_plug_and_play_cc.txt --- crawl-0.24.0/docs/develop/test_plug_and_play_cc.txt 1970-01-01 00:00:00.000000000 +0000 +++ crawl-0.25.0/docs/develop/test_plug_and_play_cc.txt 2020-05-23 16:07:19.000000000 +0000 @@ -0,0 +1,42 @@ +"test_plug_and_play.cc" is an optional source file for catch2 tests. If +the source file is available, the "make plug-and-play-tests" command +will use it to create a catch2 tests binary. If the source file is not +available, the "make plug-and-play-tests" command will fail. This source +file is in the .gitignore and should never be added to the git project. + +The main use of test_plug_and_play.cc is for the file to be used in +conjunction with the "git bisect" command. If you don't know how the git +bisect command works, reference "git bisect --help" because otherwise +none of the following will make sense. + +test_plug_and_play.cc is a file which: + +1) Compilations of versions of crawl older than master can search for +catch2 tests + +2) Will not be overwritten by git history changes, such as those which +occur while using git bisect. + +This combination of features allows for you to write tests once, then +use them for any version of crawl which has previously existed, all the +way back to the original implementation of catch2 support for crawl. + +While you are hunting down a bug introduced in newer versions of crawl, +see if you can create a catch2 test which checks for the bug in +test_plug_and_play.cc. Verify this test works with "make +plug-and-play-tests". Then, see if this test works correctly when you +"git checkout" a version of crawl which does not have the bug. If both +are true, you can use test_plug_and_play.cc to easily find the bug. + +Simply use git bisect as normally, but compile and run +plug-and-play-tests instead of normal crawl. Whenever the bug is +present, your test will fail and you can mark that commit as bad. +Whenever the bug is absent, your test will pass and you can mark that +commit as good. + +This test process is so easy git bisect allows you to automate it. Look +into "git bisect run" for more details. + +When you've finished solving the bug, remember to move the new test from +test_plug_and_play.cc to a regular test file included in the git +project! This will help prevent regressions. diff -Nru crawl-0.24.0/docs/develop/tiles_creation.txt crawl-0.25.0/docs/develop/tiles_creation.txt --- crawl-0.24.0/docs/develop/tiles_creation.txt 2016-05-31 07:56:08.000000000 +0000 +++ crawl-0.25.0/docs/develop/tiles_creation.txt 2020-06-03 19:28:02.000000000 +0000 @@ -212,7 +212,7 @@ you can reuse an existing tile, either because it is currently not seeing use (check out the rltiles/UNUSED directory for this) or because it can easily be tweaked by adding details or changing its colour. Flipping or rotating (part -of) a tile can make a huge difference already, and sometimes a combinition of +of) a tile can make a huge difference already, and sometimes a combination of parts taken from different existing tiles can be used to great effect. For human monsters, usually uniques, in addition the in-game doll editor diff -Nru crawl-0.24.0/docs/develop/translation.txt crawl-0.25.0/docs/develop/translation.txt --- crawl-0.24.0/docs/develop/translation.txt 2016-05-31 07:56:08.000000000 +0000 +++ crawl-0.25.0/docs/develop/translation.txt 2020-06-03 19:28:02.000000000 +0000 @@ -43,7 +43,7 @@ references, but don't forget to include information about the translator. Quotes have keys ending with ':quote'. Not all entries have a quote associated with it. To submit a new quote from the transifex interface, edit the -descripton and add a line with :quote at the end. Then, below it, you can add +description and add a line with :quote at the end. Then, below it, you can add a quote. On the next synchronization, it will be moved to its own key. Aliases @@ -96,7 +96,7 @@ At any moment you can change the languages and resources. All commands only apply to what is currently selected. When there are pending changes of different types, you can also "select changes" which allows you to review -independantly new entries, changed ones, quotes and deleted entries. +independently new entries, changed ones, quotes and deleted entries. Here is the process to do a full sync (hotkey commands are uppercased): start with only the english language (txc -s). diff -Nru crawl-0.24.0/docs/obsolete/versions.txt crawl-0.25.0/docs/obsolete/versions.txt --- crawl-0.24.0/docs/obsolete/versions.txt 2016-05-31 07:56:08.000000000 +0000 +++ crawl-0.25.0/docs/obsolete/versions.txt 2020-05-23 16:07:19.000000000 +0000 @@ -38,7 +38,7 @@ * Stealth is now much more effective (try playing thieves again!); * Resistances to electricity and poison no longer absolute; * Disarming traps may now trigger them; - * Armor and evasion skills are more effective; + * Armour and evasion skills are more effective; * Great and triple swords now treated as long swords for purposes of skill (Great Swords skill removed); and * Berserk mode made more interesting: @@ -81,7 +81,7 @@ * Hand-and-a-half weapons added -- bonus if no shield wielded; * Added weapons of reaching, permitting attacks two squares over; * Cekugob no longer confers resistances to fire and cold; - * Worn cloaks no longer prevent donning/removal of body armor; + * Worn cloaks no longer prevent donning/removal of body armour; * Amulet of maintain speed now the amulet of resist slowness; and * New weapon types: knife, axe, broad axe, spiked flail, great flail, great mace, trident, demon trident. @@ -244,7 +244,7 @@ * Considerable balance changes; * New dungeon formations; * The 'V' command now gives more specific information for weapons - and armor; + and armour; * 'Target previous monster' function is now a bit easier to use; * You can now command your servants to attack ('!' command); and * Bugs fixed. diff -Nru crawl-0.24.0/docs/options_guide.txt crawl-0.25.0/docs/options_guide.txt --- crawl-0.24.0/docs/options_guide.txt 2019-09-15 23:48:09.000000000 +0000 +++ crawl-0.25.0/docs/options_guide.txt 2020-06-03 19:29:39.000000000 +0000 @@ -16,16 +16,17 @@ 0-e Aliases and variables. 1- Starting Screen. name, remember_name, weapon, species, background, combo, - restart_after_game, restart_after_save, name_bypasses_menu, - default_manual_training, autopickup_starting_ammo + restart_after_game, restart_after_save, newgame_after_quit, + name_bypasses_menu, default_manual_training, + autopickup_starting_ammo, game_seed, pregen_dungeon 2- File System and Sound. crawl_dir, morgue_dir, save_dir, macro_dir, sound, hold_sound, - sound_file_path + sound_file_path, one_SDL_sound_channel 3- Interface. 3-a Dropping and Picking up. autopickup, autopickup_exceptions, default_autopickup, pickup_thrown, assign_item_slot, pickup_menu_limit, - drop_filter, auto_hide_spells, + drop_filter, auto_hide_spells 3-b Passive Sightings (detected and remembered entities). detected_monster_colour, detected_item_colour, remembered_monster_colour @@ -38,24 +39,24 @@ view_max_width, view_max_height, view_lock_x, view_lock_y, view_lock, center_on_scroll, symmetric_scroll, scroll_margin_x, scroll_margin_y, - scroll_margin + scroll_margin, always_show_exclusions 3-f Travel and Exploration. travel_delay, explore_delay, rest_delay, travel_avoid_terrain, explore_greedy, explore_stop, explore_stop_pickup_ignore, explore_wall_bias, travel_key_stop, tc_reachable, tc_dangerous, tc_disconnected, tc_excluded, tc_exclude_circle, runrest_ignore_message, - runrest_stop_message, runrest_safe_poison, - runrest_ignore_monster, rest_wait_both, rest_wait_percent, - rest_wait_ancestor, explore_auto_rest, auto_exclude, - wall_jump_move, wall_jump_prompt + runrest_stop_message, interrupt_, delay_safe_poison, + runrest_ignore_monster, rest_wait_both, rest_wait_ancestor, + rest_wait_percent, explore_auto_rest, auto_exclude 3-g Command Enhancements. auto_switch, travel_open_doors, easy_unequip, equip_unequip, jewellery_prompt, easy_confirm, simple_targeting, - allow_self_target, auto_butcher, confirm_butcher, - easy_eat_chunks, easy_quit_item_prompts, ability_menu, - sort_menus, spell_slot, item_slot, ability_slot, - autofight_stop, autofight_warning, autofight_hunger_stop, + allow_self_target, auto_butcher, auto_butcher_max_chunks, + confirm_butcher, easy_eat_chunks, auto_eat_chunks, + easy_quit_item_prompts, ability_menu, easy_floor_use, + sort_menus, spell_slot, item_slot, ability_slot, autofight_stop, + autofight_warning, autofight_hunger_stop, autofight_hunger_stop_undead, autofight_throw, autofight_throw_nomove, autofight_fire_stop, autofight_caught, autofight_wait, autofight_prompt_range, automagic_enable, @@ -69,10 +70,11 @@ show_more, small_more, show_newturn_mark, show_game_time, equip_bar, animate_equip_bar, item_stack_summary_minimum, mlist_min_height, mlist_allow_alternate_layout, msg_min_height, - msg_max_height, messages_at_top, skill_focus, + msg_max_height, msg_webtiles_height, messages_at_top, msg_condense_repeats, msg_condense_short, show_travel_trail, - monster_list_colour, view_delay, force_more_message, - flash_screen_message, use_animations, darken_beyond_range + skill_focus, default_show_all_skills, monster_list_colour, + view_delay, use_animations, darken_beyond_range, + force_more_message, flash_screen_message, cloud_status 3-i Colours (messages and menus) menu_colour, message_colour 3-j Missiles. @@ -97,32 +99,35 @@ tile_item_col, tile_unseen_col, tile_floor_col, tile_wall_col, tile_mapped_floor_col, tile_mapped_wall_col, tile_explore_horizon_col, tile_door_col, tile_downstairs_col, - tile_upstairs_col, tile_branchstairs_col, tile_feature_col, + tile_upstairs_col, tile_branchstairs_col, tile_portal_col, tile_transporter_col, tile_transporter_landing_col, - tile_trap_col, tile_water_col, tile_lava_col, tile_excluded_col, - tile_excl_centre_col, tile_update_rate, tile_runrest_rate, - tile_key_repeat_delay, tile_tooltip_ms, tile_tag_pref, - tile_full_screen, tile_window_width, tile_window_height, - tile_map_pixels, tile_cell_pixels, tile_force_overlay, - tile_single_column_menus, tile_font_crt_file, - tile_font_stat_file, tile_font_msg_file, tile_font_tip_file, - tile_font_lbl_file, tile_font_crt_family, tile_font_stat_family, - tile_font_msg_family, tile_font_lbl_family, tile_font_crt_size, - tile_font_stat_size, tile_font_msg_size, tile_font_tip_size, - tile_font_lbl_size, tile_font_ft_light, tile_show_minihealthbar, + tile_feature_col, tile_trap_col, tile_water_col, + tile_deep_water_col, tile_lava_col, tile_excluded_col, + tile_excl_centre_col, tile_window_col, tile_update_rate, + tile_runrest_rate, tile_key_repeat_delay, tile_tooltip_ms, + tile_tag_pref, tile_window_width, tile_window_height, + tile_map_pixels, tile_viewport_scale, tile_map_scale, + tile_cell_pixels, tile_filter_scaling, tile_force_overlay, + tile_full_screen, tile_single_column_menus, + tile_font_crt_file, tile_font_stat_file, tile_font_msg_file, + tile_font_tip_file, tile_font_lbl_file, tile_font_crt_family, + tile_font_stat_family, tile_font_msg_family, + tile_font_lbl_family, tile_font_crt_size, tile_font_stat_size, + tile_font_msg_size, tile_font_tip_size, tile_font_lbl_size, + tile_font_ft_light, tile_show_minihealthbar, tile_show_minimagicbar, tile_show_demon_tier, tile_water_anim, tile_misc_anim, tile_realtime_anim, tile_show_player_species, - tile_layout_priority, tile_display_mode, - tile_level_map_hide_messages, tile_level_map_hide_sidebar, - tile_player_tile, tile_weapon_offsets, tile_shield_offsets, - tile_web_mouse_control + tile_show_threat_levels, tile_layout_priority, + tile_display_mode, tile_level_map_hide_messages, + tile_level_map_hide_sidebar, tile_player_tile, + tile_weapon_offsets, tile_shield_offsets, tile_web_mouse_control 4- Character Dump. 4-a Saving. dump_on_save 4-b Items and Kills. - kill_map, dump_kill_places, dump_kill_breakdowns, - dump_item_origins, dump_item_origin_price, dump_message_count, - dump_order + kill_map, dump_kill_places, dump_item_origins, + dump_item_origin_price, dump_message_count, dump_order, + dump_kill_breakdowns 4-c Notes. user_note_prefix, note_items, note_monsters, note_hp_percent, note_skill_levels, note_all_skill_levels, note_skill_max, @@ -132,8 +137,9 @@ 5-a All OS. mouse_input, wiz_mode, explore_mode, char_set, colour, display_char, feature, mon_glyph, item_glyph, - use_fake_player_cursor, show_player_species, language, - fake_lang, read_persist_options + use_fake_player_cursor, show_player_species, + use_modifier_prefix_keys, language, fake_lang, + read_persist_options 5-b DOS and Windows. dos_use_background_intensity @@ -149,6 +155,8 @@ 6-c Conditional options. 6-d Conditional option caveats. +7- Recommended Options for Blind Players. + ------------------------------------------------------------------------ 0- Generalities on options. @@ -332,18 +340,18 @@ weapon += (short sword |...| unarmed | random | viable), , ... (List option) Specifying the weapon option allows you to bypass the weapon - selection screen. Tridents, flails, cutlasses, long swords, and war + selection screen. Tridents, flails, rapiers, long swords, and war axes are restricted to fighters and gladiators, and quarterstaves are restricted to gladiators only. The standard weapon prompt will be shown if an illegal choice for the selected background is specified. The "viable" option makes a random choice from among the "good" weapons for the chosen character. Specifying more than one option causes the game to randomly select a weapon from the given list. The combo option - overrides (and is overriden by) this option. + overrides (and is overridden by) this option. species += (Human |...| Vampire | random | viable), , ... (List option) - The usual abbreviations (Hu, HE, etc.) work. "viable" will choose a + The usual abbreviations (Hu, HO, etc.) work. "viable" will choose a viable species for a given background if the background is chosen first. Specifying multiple species causes one to be selected at random from the given species. The combo option overrides (and is @@ -364,7 +372,7 @@ specified, it is prompted for. Combos may be abbreviated or specified in full. If multiple combos are specified, one is selected randomly from the specified combos. The weapon, species, and background - options are overriden by (and override) this option. + options are overridden by (and override) this option. restart_after_game = maybe/true When set to true, at the game end, crawl will return to the main menu. @@ -566,7 +574,7 @@ item. If zero, never use the menu. If negative, use the value of item_stack_summary_minimum - 1, instead. - Note that no matter the vaulue of the option, picking up will always + Note that no matter the value of the option, picking up will always take one turn. drop_filter += , , ... @@ -737,7 +745,7 @@ scroll_margin_x = 2 How far from the left or right edges scrolling starts. By - default, if the PC's circle of line-of-sight is closer than + default, if the PC's square of line-of-sight is closer than two squares from the edge, the viewport scrolls. If set at zero, the viewport scrolls only when the LOS circle reaches the viewport edge. @@ -887,7 +895,7 @@ Use these to force messages to interrupt travel and resting, or not. These are matched against full message text. To limit a substring match to a message channel, prefix the substring with - the channel name and a colon (see section 3-l below on Message + the channel name and a colon (see section 3-k below on Message Channels). For instance, if you want travel to stop when you're hit by divine retribution, you could use: runrest_stop_message += god:wrath finds you @@ -955,7 +963,7 @@ it will stop resting when this percent of maximum HP or MP is refilled. Resting after this point will still rest up to 100%. -explore_auto_rest = false +explore_auto_rest = true If true, auto-explore waits until your HP and MP are both at rest_wait_percent before moving. @@ -967,17 +975,6 @@ ever bring you into its line of sight. If the monster dies or wakes up while you are in sight, this exclusion is automatically removed again. -wall_jump_move = false - If true, a WJC character (with the appropriate piety level) can wall - jump simply by moving against a solid feature. Otherwise, they can only - do so by using the (a)bility. It is never possible to wall jump off of - closed doors via movement. - -wall_jump_prompt = false - If true, and wall_jump_move is also true, then a WJC character can wall - jump via movement by moving twice against a solid feature. No effect if - wall_jump_move = false. - 3-g Command Enhancements. ----------------------------- @@ -1007,8 +1004,8 @@ easy_confirm = (none | safe | all) Make confirmation questions easier to answer: - none = force capitals on Y/N questions - safe = force only on dangerous questions (default) + none = force capitals on Y/N questions and stat increases + safe = force only on dangerous questions and stat increases (default) all = never force capitals WARNING TO PUTTY USERS: If your Putty configuration sets the numeric keypad to "NetHack mode", the keypad '7' will be mapped @@ -1022,7 +1019,7 @@ while avoiding the player. allow_self_target = (yes | no | prompt) - Allow targeting yourself with risky magic (e.g., the spell Bolt of Fire + Allow targeting yourself with risky magic (e.g., the spell Bolt of Magma or a wand of paralysis.) When set to 'yes', you are a valid target. When set to 'no', you cannot target yourself with such spells. When set to 'prompt' (the default), @@ -1030,12 +1027,17 @@ effect on area-effect spells, such as Mephitic Cloud, where you are always a valid target. -auto_butcher = very hungry +auto_butcher = true If this is set to true, you will automatically travel to and attempt to butcher edible corpses. Can also be set to a hunger threshold ('very full', 'full', 'satiated', 'hungry', 'very hungry', or 'near starving') to enable automatic butchery only when at that state or hungrier. +auto_butcher_max_chunks = 10 + If this is set to a nonzero value, automatic butchering will not + be done if you have more than this many chunks in your inventory. This + defaults to 0 for ghouls. + confirm_butcher = (always | never | auto) If auto (default) you will be prompted for which corpses to butcher if there are multiple corpses on the square, and not prompted otherwise. @@ -1216,9 +1218,9 @@ Examples: * if you want Apportation to be placed on A: spell_slot ^= Apportation:A - * if you want Deflect Missiles to be placed on r normally or R if + * if you want Ozocubu's Armour to be placed on r normally or R if r is unavailable: - spell_slot ^= Deflect:rR + spell_slot ^= Ozocubu's Armour:rR * if you want the first "Bolt" spell to be placed on a, even if there is already a non-bolt spell there: spell_slot ^= Bolt:+a @@ -1492,6 +1494,10 @@ than using the fixed position below the stat area. This option is not supported in the tiles build. +monster_item_view_coordinates = false + Display player-centered coordinates in the ^x visible monsters/items + view. + msg_min_height = 7 You can reduce this to give more space to the map display. The minimum value is 5. In console, if this value is large enough @@ -1505,7 +1511,7 @@ will get the rest. msg_webtiles_height = -1 - This will set the height of the messages pane in (only) webtiles, + This will set the height of the messages pane in (only) WebTiles, scaling the map accordingly. Values less than `msg_min_height` will have no impact; in this case the height of the message pane is inherited from console (and so will typically be 7). One of these @@ -1531,7 +1537,9 @@ show_travel_trail = false (defaults to true for online servers) When set to true, the path taken during autoexplore or travel - will be highlighted. If a travel trail is currently being displayed, + will be highlighted. The console colour and glyph of the travel trail + can be further configured using the feature option to override the + "travel trail" feature. If a travel trail is currently being displayed, the Clear Map command (Ctrl-C) clears the trail instead of the map (pressing it a second time then clears the map as usual). @@ -1613,7 +1621,7 @@ Any message that contains a regex specified here will enforce a --More-- prompt, so it can be used to highlight really important events. This option ignores the show_more option. - The syntax is identical to that of runrest_ignore_message (3-g). + The syntax is identical to that of runrest_ignore_message (3-f). flash_screen_message += , (List option) @@ -1675,12 +1683,8 @@ The following apply only to items of certain base types, whether identified or not: inedible (You cannot eat this, or get no nutrition from it.) - preferred (The food type your character prefers, for example - for herbivores/carnivores.) - poisonous (Chunks/corpses that are poisonous.) - mutagenic (Chunks/corpses that are mutagenic.) - contaminated (Chunks/corpses that give reduced nutrition.) - rot-inducing (Chunks/corpses that cause rotting.) + preferred (The food type your character prefers. For example, + Ghouls prefer chunks to rations.) equipped (Equipped items.) artefact (For artefacts, whether identified or not.) @@ -1689,8 +1693,7 @@ When looking for menu_colour matches, these prefixes are prepended to the actual item name, e.g. in the form of - identified forbidden wand of draining (4) - unidentified equipped artefact sparkling ring (left hand) + identified forbidden wand of random effects (4) The same prefixes can also be used for highlighting prompts pertaining to items matching the description, or to define autopickup_exceptions. @@ -1712,7 +1715,7 @@ If you frequently die because you forget to use emergency items, try menu_colour ^= inventory:cyan:emergency_item - menu_colour ^= inventory:lightcyan:wand of (fire|cold|draining) + menu_colour ^= inventory:lightcyan:wand of (acid|iceblast) menu_colour can also be applied to colour the in-game notes (to be read with '?:'). The following line will show level ups in @@ -1795,7 +1798,7 @@ monster_damage = messages telling how damaged a monster is monster_target = messages marking the monster as a target (unused) banishment = messages about banishing and being banished to the Abyss - rotten_meat = messages about chunks/corpses/blood rotting away + rotten_meat = messages about chunks/corpses rotting away equipment = messages indicating worn/wielded equipment floor = messages when looking at or walking over a floor item multiturn = indicates long actions (wearing armour, dissecting etc.) @@ -1835,8 +1838,8 @@ inscribed (if autopickup is toggled on). For example, it can be used to avoid accidentally using charges of - important wands, as in - autoinscribe += wand of heal wounds:!V + potentially dangerous wands, as in + autoinscribe += wand of polymorph:!V The menu colour prefixes (forbidden etc.) can also be used here. For example: @@ -1970,10 +1973,10 @@ tile_item_col - colour of known or detected items tile_unseen_col - colour of unseen areas (usually stone) tile_floor_col - colour of floor - tile_mapped_floor_col - colour of floor detected via magic mapping - tile_explore_horizon_col - colour of the edge of explored territory tile_wall_col - colour of any wall type + tile_mapped_floor_col - colour of floor detected via magic mapping tile_mapped_wall_col - colour of walls detected via magic mapping + tile_explore_horizon_col - colour of the edge of explored territory tile_door_col - colour of known doors, open or closed tile_downstairs_col - colour of downstairs tile_upstairs_col - colour of upstairs, including branch exits @@ -2030,6 +2033,13 @@ will auto-size the window. If set to a negative number (default), it will use the screen's resolution, minus the given value. +game_scale = 1 + An integer scale value between 1 and 8 that will increase the size of + all UI elements. This can be used to simulate high-dpi rendering on + high resolution displays that don't directly support high-dpi, or adjust + scaling for very large displays. For a 4k display, we recommend a value + of 3 or 4, and a 2k display will typically look best with 2. Local tiles only. + tile_map_pixels = 0 The maximum number of pixels each minimap square should take up. If you have a low resolution, and feel like the inventory is too small, you @@ -2139,6 +2149,11 @@ If enabled, displays the player using the monster tile for her species, instead of using the normal doll and showing equipment. +tile_show_threat_levels = none + This option controls which monsters will be highlighted with their + threat level. Valid levels include: trivial, easy, tough, nasty. + You can specify multiple levels at once. + tile_layout_priority = minimap, inventory, command, spell, monster (Ordered list option) This option allows you to control the order in which elements are @@ -2206,7 +2221,7 @@ tile_web_mouse_control = true Whether to enable mouse control for tooltips/cursor interaction on - Webtiles. Regardless of the value of the setting, the minimap will + WebTiles. Regardless of the value of the setting, the minimap will respond to mouse control. 4- Character Dump. @@ -2244,12 +2259,12 @@ kill places, anything else to the default of showing kill places only for single kills -dump_item_origins = artefacts, rods +dump_item_origins = artefacts The game remembers where you find items. If you want this item origin memory listed in your dumps, use this option to select which items get annotated. Available selectors are: artefacts, ego_arm, ego_weap, jewellery, runes, - rods, staves, books, all, none. + staves, books, all, none. If you use multiple dump_item_origins lines, the last line takes effect; all preceding lines are ignored. @@ -2267,7 +2282,7 @@ dump_order = header,hiscore,stats,misc,inventory, dump_order += skills,spells,overview,mutations,messages,screenshot, -dump_order += monlist,kills,notes,skill_gains,action_counts +dump_order += monlist,kills,notes,screenshots,skill_gains,action_counts (Ordered list option) Controls the order of sections in the dump. @@ -2293,7 +2308,7 @@ The following events are logged: - Gaining or losing a level - Entering a dungeon level for the first time - - Memorizing a spell of higher level than any learned before + - Memorising a spell of higher level than any learned before - Becoming a worshipper of a god - Abandoning a god - Being put under penance and being forgiven @@ -2319,7 +2334,7 @@ (List option) When an item is identified for the first time, it will be noted if its short description matches a regex. E.g. - note_items += rod,book,acquirement + note_items += book,acquirement Artefacts (fixed, unrand, or random) will always be noted when identified, regardless of note_items. @@ -2368,7 +2383,7 @@ note_messages += Your scales start note_chat_messages = false - If set to false, this will disable logging of webtiles chat + If set to false, this will disable logging of WebTiles chat messages from other players. (This setting only applies on the online servers). @@ -2492,12 +2507,13 @@ to override the above display_char options, or also to distinguish among subtypes of a character. - 'magic' always refers to magic mapping. So the - entry determines what symbol will be used for features only - detected via magic mapping. + 'magic' refers to magic mapping. So the + entry determines what symbol will be used for features + detected via magic mapping. The will also be used + for stone stairs with unknown destination and unvisited transporters. - 'emphasised_colour' refers to the colour used to highlight - stone stairs with unknown destination; for non-stair features, + 'emphasised_colour' refers to the colour used to highlight stone stairs + and transporters with unknown destination; for non-stair features, setting emphasis colours does nothing useful. Leading parameters in the {...} list can be omitted by leaving @@ -2596,7 +2612,7 @@ Multiple rules can modify a single item, which is useful if you want to change the colour and glyph separately: item_glyph += corpse : x625 - item_glyph += poisonous.* corpse : lightgreen + item_glyph += inedible.* corpse : lightgreen Rules are applied in order, so later rules are higher priority. @@ -2872,3 +2888,46 @@ conditionalized wiz_mode, you can add to the command line "-extra-opt-last wiz_mode=yes" to make any new game start in wizard mode. + +7- Recommended Options for Blind Players. +========================================== + +The following settings are recommended to facilitate using crawl in console +with a screenreader. + +Disable animations and view delays so the screen updates immediately after each +command: + view_delay = 0 + travel_delay = -1 + rest_delay = -1 + use_animations = 0 + +Place messages at the top of the screen and remove message condensing for +easier screen reading: + messages_at_top = true + clear_messages = true + msg_condense_short = false + +Make the player cursor easier to track with screen reading, by setting a custom +symbol for the player: + use_fake_player_cursor = false + show_player_species = false + mon_glyph += player:x263A + +Use mouse input clicks for automove (see the discussion of the mouse_input +option for terminal configuration specifics): + mouse_input = true + +List player-relative coordinates in the ^x display: + monster_item_view_coordinates = true + +Mark the path taken by auto-travel and the exploration horizon with special +characters: + show_travel_trail = true + feature += travel trail {x25AA} + feature += explore horizon {x25AB} + +Set a separate glyph for unvisited stairs and transporters: + feature += stone staircase leading up {<,x25C2} + feature += stone staircase leading down {>,x25B8} + feature += transporter {xA9, x25CE} diff -Nru crawl-0.24.0/INSTALL.md crawl-0.25.0/INSTALL.md --- crawl-0.24.0/INSTALL.md 1970-01-01 00:00:00.000000000 +0000 +++ crawl-0.25.0/INSTALL.md 2020-05-23 16:07:19.000000000 +0000 @@ -0,0 +1,487 @@ +# Install instructions for Dungeon Crawl Stone Soup (DCSS) + +## Contents + +* [Getting DCSS To Run](#getting-dcss-to-run) +* [Compiling](#compiling) + * [Ubuntu / Debian](#ubuntu--debian) + * [Fedora](#fedora) + * [Void Linux](#void) + * [Other Linux / Unix](#other-linux--unix) + * [macOS](#macOS) + * [Windows](#windows) + * [MSYS2 (Recommended)](#msys2-recommended) + * [Windows Subsystem for Linux (WSL)](#windows-subsystem-for-linux-wsl) + * [Visual Studio](#visual-studio) +* [Advanced](#advanced) + * [ccache](#ccache) + * [Installing For All Users](#installing-for-all-users) + * [.des Level Compiler](#des-level-compiler) + * [Code Coverage](#code-coverage) + * [Lua](#lua) + * [PCRE](#pcre) + * [Unicode](#unicode) +* [Getting Help](#getting-help) + +## Getting DCSS To Run + +You can download prebuilt versions of DCSS from the +[DCSS homepage](https://crawl.develz.org/download.htm). + +If you're having any trouble running these versions, try asking for help in +[any of the community forums detailed in the README](../README.md#community). + +The rest of this file deals with compiling DCSS from source. + +## Compiling + +Here's the basic workflow. Please read the section for your OS below for more +detailed instructions. + +```sh +# Clone the repository +git clone https://github.com/crawl/crawl.git +cd crawl + +# Either install dependencies from your OS package manager (eg apt, yum) +apt install ... +# or use DCSS's packaged dependencies +git submodule update --init + +# Build DCSS (remove TILES=y for console mode) +cd crawl-ref/source +make -j4 TILES=y +``` + +### Packaged Dependencies + +DCSS uses Lua, SDL, SQLite and several other third party packages. Generally +you should use the versions supplied by your OS's package manager. If that's +not possible, you can use the versions packaged with DCSS. + +To use packaged dependencies: + +1. Clone the repository with Git (you can't use a tarball - the dependencies + use Git submodules). +2. Run `git submodule update --init` in the repository. +3. Compile as per above. + +### Ubuntu / Debian + +These instructions may work for other DPKG-based distros. + +```sh +sudo apt install build-essential libncursesw5-dev bison flex liblua5.1-0-dev \ +libsqlite3-dev libz-dev pkg-config python3-yaml binutils-gold + +# Dependencies for tiles builds +sudo apt install libsdl2-image-dev libsdl2-mixer-dev libsdl2-dev \ +libfreetype6-dev libpng-dev ttf-dejavu-core advancecomp pngcrush +``` + +Then follow [the above compilation steps](#compiling). + +### Fedora + +These instructions may work for other RPM-based distros. + +```sh +sudo dnf install gcc gcc-c++ make bison flex ncurses-devel compat-lua-devel \ +sqlite-devel zlib-devel pkgconfig python3-yaml + +# Dependencies for tiles builds: +sudo dnf install SDL2-devel SDL2_image-devel libpng-devel freetype-devel \ +dejavu-sans-fonts dejavu-sans-mono-fonts advancecomp pngcrush +``` + +Then follow [the above compilation steps](#compiling). + +## Other Linux / Unix + +You need the following dependencies: + +* GNU make +* gcc / clang +* perl +* pkg-config +* Python 3 and PyYAML +* libncurses +* flex / bison (optional) + +You can install these dependencies from your OS package manager, or use DCSS's +packaged versions (as described in [Packaged +Dependencies](#packaged-dependencies) above): + +* lua 5.1 +* sqlite +* zlib +* pcre +* zlib +* freetype (tiles builds only) +* DejaVu fonts (tiles builds only) +* SDL2 (tiles builds only) +* libpng (tiles builds only) + +Then follow [the above compilation steps](#compiling). + +## macOS + +1. Before building on macOS, you need a working copy of Xcode and the + associated command line tools. + 1. Install Xcode from the App Store + 2. Open Xcode and say yes if you are prompted to install optional developer + tools. (You can quit Xcode after this completes.) + 3. Run `xcode-select --install` in a Terminal + +2. You will also need to install DCSS's bundled dependencies: + + ```sh + cd crawl + git submodule update --init + ``` + +Then follow [the above compilation steps](#compiling). + +## Windows + +### MSYS2 (Recommended) + +This is the only currently recommended process for building DCSS on windows. +It is also possible to cross-compile windows builds; see the release guide +for instructions. + +MSYS2 is a Cygwin-derived software distro for Windows that can build +native applications; you will interact with the build process in a unix-like +shell interface. You can download the MSYS2 installer from the +[MSYS2 github page](https://msys2.github.io/) + +You generally want to install the 64-bit version of MSYS2 unless you have a +specific reason to build a 32-bit version of crawl. Follow all of the steps you +see on that page to install MSYS2, but please read the additional notes below. +In particular, when starting the MSYS2 Shell, be sure to run the 64-bit MinGW +version of the MSYS2 shell and *not* the version labeled 'MSYS2 MSYS' or the +32-bit version. + +The installer will put all MSYS2/MinGW files into a folder of your choice, +which defaults to `C:\msys64`. If you have crawl-related work files from +other directories that you'd like to carry over, you can copy them into +`C:\msys64\home\`, where `` is your Windows username. This +is the path to your MSYS2 home directory. From the MSYS2 shell you can always +get back to here with `cd ~`. + +After the installer finishes, start the MSYS2 shell ("MSYS2 MinGW 64-bit") +and do steps 5-6 from the MSYS2 install instructions in order to update your +installation. These steps are repeated here: + + 5. At the command line, run `pacman -Syu` to update the core packages. + Then restart your MSYS2 shell. (The installer will force you to restart.) + + 6. At the command line, run `pacman -Su` to update all packages. + +After MSYS2 is fully installed and updated, follow steps below to install +development packages and compile DCSS. The commands shown below should be run +from within the MSYS2 Shell. + +1. To install git and the base development packages, run: + + ```sh + pacman -S base-devel git + ``` + + Accept the default action to install all packages in base-devel, and say yes + to any questions about installing packages or removing packages due to + conflicts. + +2. To install the mingw-w64 GCC toolchain for your system, run: + + ```sh + pacman -S mingw-w64-x86_64-toolchain + ``` + +3. At this point on current MSYS2 versions, your development environment should + be complete. You can test it by running: + + ```sh + gcc -v + ``` + + If this works, you're all set. If it doesn't, you may be an an older version + of MSYS2 and need to manually add the newly installed toolchain to your + path. To do so, run the following line, either at the command line (for + that shell instance only) or in the file `~/.bashrc` to make it permanent: + + ```sh + export PATH=$PATH:/mingw64/bin + ``` + +4. To install PyYAML, you can install it from either pacman or Pip/PyPA: + + ```sh + pacman -S mingw-w64-x86_64-python-yaml + # or + pacman -S mingw-w64-x86_64-python-pip + pip install pyyaml + ``` + + You can verify PyYAML is installed by running `python -m yaml`, which should + give an error like `'yaml' is a package and cannot be directly imported` + (rather than `No module named yaml`). + +5. To get the DCSS source, follow the steps in the [Getting The + Source](#getting-the-source) section above to clone DCSS into your MSYS2 + home directory. We recommend using the MSYS2-installed version of git for + these steps. In brief: + + 1. `cd` to the location where you would like the crawl repository to be. It + will clone into a folder named `crawl`. Your home directory (`cd ~`) is + a reasonable choice. + 2. Run `git clone https://github.com/crawl/crawl.git`. + 3. Run `cd crawl/crawl-ref/source`. + 4. Run `git submodule update --init`. + +6. Build DCSS by simply running: + + ```sh + # console build + make + # tiles build + make TILES=y + ``` + + If you want a debug build, add the target `debug` to the above commands (eg + `make debug TILES=y`). + +7. When the build process finishes, you can run crawl.exe directly from the + source directory in the MSYS2 shell. For Tiles, type `./crawl.exe`, and for + console, type `start crawl`, which will open DCSS in a new command.exe + window (the Windows version of DCSS requires a command.exe shell and will + not run in an MSYS2 shell). Both versions can also be started by + double-clicking `crawl.exe` using the graphical file explorer. + +8. If you want to build the installer or zipped packages instead, + you need to install zip and nsis: + + ```sh + pacman -S zip + # and + pacman -S mingw-w64-x86_64-nsis + ``` + + Then build by running: + + ```sh + # installer + make package-windows-installer + # zips + make package-windows-zips + ``` + +### Windows Subsystem for Linux (WSL) + +These instructions have been successfully tested with Ubuntu only. + +1. [Follow the instructions on Microsoft's + website](https://docs.microsoft.com/en-us/windows/wsl/install-win10) at to + set up the Windows Subsystem for Linux. + +2. Follow the [Ubuntu instructions](#ubuntu--debian) to build DCSS. + +3. Console and Webtiles will work without any further configuration. To get SDL + tiles to work, you need an X server running on Windows; Xming is an option + that has worked in the past. If you run into an error about not finding a + matching GLX visual, try running: + + ```sh + export SDL_VIDEO_X11_VISUALID= + ``` + +### Visual Studio + +This build process is currently unsupported, and unlikely to be straightforward +in versions of MSVC besides those explicitly mentioned here. + +This build is tested on Visual Studio 2017 15.8.7 on Windows 8.1 and 10. +Tested configurations are `Debug/Release;Console/Tiles;Win32/x64`, Python and +Lua support for editing are untested, and a webtiles build is not available. + +1. To get the DCSS source, follow the steps in the [Getting The + Source](#getting-the-source) section above. + + ```sh + git clone https://github.com/crawl/crawl.git + git submodule update --init + ``` + +2. Install a perl environment, [Perl provides links to several Windows + binaries](http://www.perl.org/get.html). + +3. In the DCSS source, run `gen-all.cmd` inside `crawl-ref/source/util/`. This + step must be executed any time you update to a new version of the source (or + if you have modified tile data or unrandarts). + +4. The first time you compile, you need to build the `Contribs` solution. This + compiles various libraries which DCSS itself needs to build. This + needs to be performed the first time you build, when changing to the `Debug` + configuration, and when the contribs are + updated. To do this open and compile `Contribs.sln` in + `crawl-ref/source/contrib`. Make sure to set `Release` or `Debug` (not the + library versions), as well as the desired architecture (Win32 or x64). Then + build (or re-build) the solution. + +5. Open `crawl-ref.sln` in Visual Studio, this is in `crawl-ref/source/MSVC/`. + +6. Select `Debug` or `Release` from the build configurations menu on the main + toolbar; `crawl.exe` is compiled by selecting "Build Solution" in the BUILD + menu. + +7. To build the `Debug` version: + + 1. First build `Release` following the instructions above + 2. Set the `Debug` configuration + 3. Re-build the `Contribs` + 4. Re-build with the `Debug` configuration set + + Building the `Debug` version without first building the `Release` + configuration will result in an error on startup. The `Release` build can + still be debugged using the Visual Studio debugger. + +### Maintenance notes: + +MSVC solution files are finicky. Opening the "All Configurations" or +"All Platforms" will automatically change settings. This is typically unwanted. + +Troubleshooting tips: + +- Make sure Windows Universal C Runtime is installed in MSVC. +- Build Release before rebuilding both solutions with Debug +- Use "Rebuild Solution" to make sure all files are rewritten +- Make sure all projects use `/MD` (or `/MDd` for the debug version) +- Make sure the appropriate (`/MD` or `/MDd`) CRT libraries are included for + SDL, crawl, and tilegen + (https://msdn.microsoft.com/en-us/library/abx4dbyh.aspx) +- Make sure `libpng.dll`, `SDL2.dll`, and `SDL2_image.dll` are in + `crawl-ref/source` after building the `Contribs` solution. These are copied + post-build from their original location in + `source/contrib/bin/8.0/$(Platform)`. +- Make sure `freetype.lib`, `libpng.lib`, `lua.lib`, `pcre.lib`, `SDL2.lib`, + `SDL2_image.lib`, `SDL2main.lib`, `sqlite.lib`, and `zlib.lib` are in + `source/contrib/bin/8.0/$(Platform)` after building the `Contribs` solution. +- Make sure `crawl.exe` and `tilegen.exe` are in `crawl-ref/source` after + building the `crawl-ref` solution. +- `tilegen.exe runs early during the `crawl.exe` build process, using + `libpng.dll` to build PNG files inside `source/rtiles`. Breaking tilegen + (e.g. by building a different `Contribs` configuration) after building these + png files correctly will result in `tilegen.exe` crashing during the crawl + build process, but will not stop the build from working. `fresh.bat` inside + the MSVC folder will clear these files, making sure `tilegen.exe` stops the + build process if it fails. + +## Advanced + +DCSS looks for several data files when starting up. They include: + +* Special level and vault layout (`dat/*.des`) files. +* Core Lua code (`dat/dlua/*.lua`). +* Descriptions for monsters and game features (`dat/descript/*.txt`). +* Definitions for monster dialogue and randart names (`dat/database/*.txt`). + +All these files are in the source tree under `source/dat`. + +DCSS will also look for documentation files when players invoke the help +system. These files are available under the docs directory. + +Your built DCSS binary must be able to find these files, or it will not start. + +If DCSS is built without an explicit `DATA_DIR_PATH` (this is the most common +setup), it will search for its data files under the current directory, and if +it can't find them there, one level above the current directory. In short, it +uses these search paths: `.`, `./dat`, `./docs`, `..`, `../dat`, `../docs`. + +### ccache + +If you're recompiling DCSS many times (eg while developing features), `ccache` +can significantly speed up this process. It is generally easy to install and +set up. + +On Linux, try installing the `ccache` with your package manager. You will need +to add the ccache directory to your `PATH`. + +On macOS, run `brew install ccache` and follow the instructions to update your +`PATH`. + +### Installing For All Users + +You might want to install DCSS if you want to allow all users on your machine +to play it. + +Use `make install prefix=/usr/local` to build and install DCSS. + +Make options: + +* `prefix`: Specify the prefix to install to. You probably want `/usr` or `/usr/local` +* `SAVEDIR`: defaults to `~/.crawl` +* `DATADIR`: defaults to `$prefix/share/crawl` + +### .des level compiler + +DCSS uses a level compiler to read the level design (.des) files in the +`source/dat` directory. + +If you're using one of standard makefile, the steps described in this section +are performed automatically: + +The level compiler source is in the `source/util` directory (`levcomp.lpp` and +`levcomp.ypp`). The steps involved in building the level compiler are: + +* Run `flex` on `levcomp.lpp` to produce the `levcomp.lex.cc` lexer. +* Run `bison` on `levcomp.ypp` to produce the `levcomp.tab.cc` parser and + `levcomp.tab.h` +* Compile the resulting C++ source files and `levcomp.cc` and link the object + files into the DCSS executable. + +For convenience on systems that don't have flex/bison, pre-generated +intermediate files are provided under `source/prebuilt`. The makefiles provided +with the DCSS source distribution will use these pre-generated files +automatically if flex/bison is not available. + +### Code Coverage + +Code coverage requires some more package to be installed. See +[testing.md](crawl-ref/docs/develop/testing.md) for more info. + +### Lua + +The Lua source is included with DCSS. It will be used if you don't have Lua +headers installed. Note that we don't provide security support for Lua, and +thus if you run a public server or a kiosk, it is strongly recommended to use +system Lua which does receive security updates from whatever distribution you +use. + +### PCRE + +PCRE 8.12, with a custom build system but otherwise unchanged, is included with +DCSS. It is enabled by default on Windows; otherwise, unless you build with +`BUILD_PCRE=y` (to use the contrib) or `USE_PCRE=y` (to use a development +package from your manager), the system POSIX regex will be used. + +### Unicode + +On Unix, you want an UTF-8 locale. All modern distributions install one by +default, but you might have somehow dropped required settings. To check this, +run `locale charmap`, which should say `UTF-8`. If it's not, please ensure +either `LANG`, `LC_ALL` or `LC_CTYPE` is set. A typical line would be `export +LC_ALL=en_US.UTF-8`. + +On Windows, the console behaves differently for TrueType and legacy (bitmap) +fonts. The latter (mostly) work only on certain language editions of Windows, +such as English, and even there, they work adequately only for DCSS's default +settings. For anything more, please select one of TrueType fonts. If, like one +of our players, you are deeply attached to the looks of bitmap fonts, you can +[download a corrected version of the Terminal +font](http://www.yohng.com/software/terminalvector.html) + +## Getting Help + +The best place to ask for help is `##crawl-dev` on Freenode IRC, where developers chat. + +You can also try [any of the community forums detailed in the README](../README.md#community). diff -Nru crawl-0.24.0/INSTALL.txt crawl-0.25.0/INSTALL.txt --- crawl-0.24.0/INSTALL.txt 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/INSTALL.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,572 +0,0 @@ -Install instructions for Dungeon Crawl Stone Soup (DCSS) --------------------------------------------------------- - -Getting Crawl to run --------------------- - -This file describes how to compile a runtime executable of Crawl from the -source code. If you're trying to compile Crawl yourself, skip ahead to the next -section, "Building Crawl". - -If, however, you're having trouble getting a precompiled binary to run: - -1) Check whether you've downloaded and extracted the correct version. - - Platform Tiles? Download package - -------- ------ ---------------- - Windows yes stone_soup-VERSION-tiles-win32.zip - Windows no stone_soup-VERSION-win32.zip - Mac OS X yes stone_soup-VERSION-tiles-osx.zip - or stone_soup-VERSION-tiles-osx-app.dmg - Mac OS X no stone_soup-VERSION-osx.zip - or stone_soup-VERSION-osx-app.dmg - Source code yes stone_soup-VERSION-src.zip - or stone_soup-VERSION-src.tar.bz2 - -2) Try removing/renaming your saves/ directory in case older saves aren't - recognized anymore. - - -If you still can't get Crawl to run, you can ask for further help on IRC: -##crawl-dev on freenode, forums: https://crawl.develz.org/tavern/ or usenet: -rec.games.roguelike.misc. Please try to be as detailed as possible about any -error messages you're getting. - -The rest of the file deals with compiling from the source. - - -Building Crawl --------------- - -Crawl is known to run on the following platforms: - -- Any Unix with GNU or BSD userland. -- Mac OS X. -- Android. -- Microsoft Windows 2000/XP/Vista/7/8/10 - -The only officially supported compilers are gcc (4.7 or newer) and clang (3.4 -or newer). On Windows, gcc is usually available as MinGW. - -There's no reason Crawl shouldn't work on other modern systems, especially -Unixy ones, although some porting may be needed. - - -Source Code Checkout --------------------- - -If you don't already have the source code downloaded (in the form of a .zip or -.tar.bz2 file), you can obtain the latest source code from Git. MSYS2 users -should have Git if they followed the installation instructions in the MSYS2 -section. Linux users can just install the 'git' or 'git-core' package with -whatever package manager they use. Note that there used to be another package -called 'git' (now 'gnuit') going around which stands for 'GNU interactive -tools'. This is not what you want. - -Once you have Git installed, you just need to do: - - git clone https://github.com/crawl/crawl.git - -And then to get the contributing libraries, enter the newly cloned repository -via 'cd crawl' and type: - - git submodule update --init - -This should get you all you need to build Crawl from source. - - -Optional libraries ------------------- - -Crawl can be built with some optional features: - -* Sounds -* User Lua scripts - -Crawl also uses a level compiler to compile special level definitions; to make -changes to the level compiler, you'll need the flex and bison/byacc tools -(Other lex/yaccs may also work). More details are available below. - -Sound can be provided by SDL2_mixer (the default), by WINMM on Windows (defined -by WINMM_PLAY_SOUNDS in sound.h), or by an external command on Unix systems -(SOUND_PLAY_COMMAND in sound.h). To enable this, append SOUND=y to the make -invocation. - -Crawl includes Lua 5.1.4 in its submodules. Crawl uses Lua for dungeon -generation. In addition, Crawl has a (rudimentary) Lua interface for users to -run scripts which can do things such as conditionalise parts of the -.crawlrc/init.txt. Such user Lua scripts are enabled by default, but can be -turned off by appending NO_LUA_BINDINGS=y to the make invocation. - - -Building on Unix (Linux, *BSD, Solaris, etc.) ---------------------------------------------- - -To install or not to install: - -If only one user on the system (you) is going to be playing Crawl, you do not -need to use "make install". A simple "make" will build Crawl in the source -directory, where you can run it as "./crawl". - - -Prerequisites (Debian): - -On Debian-based systems (Ubuntu, Mint, ...), you can get all dependencies by -typing the following as root/sudo: - - apt-get install build-essential libncursesw5-dev bison flex liblua5.1-0-dev \ - libsqlite3-dev libz-dev pkg-config python-yaml libsdl2-image-dev \ - libsdl2-mixer-dev libsdl2-dev libfreetype6-dev libpng-dev ttf-dejavu-core - -(the last six are needed only for tiles builds). This is the complete set, -with it you don't have a need for the bundled "contribs". - -If you are going to be rebuilding after doing small changes a lot, it is -recommended that you also install and configure ccache and binutils-gold: - - apt-get install ccache binutils-gold - less /usr/share/doc/ccache/README.Debian - - -Prerequisites (Fedora): - -On Fedora, and possibly other RPM-based systems, you can get the dependencies -by running the following as root: - - dnf install gcc gcc-c++ make bison flex ncurses-devel compat-lua-devel \ - sqlite-devel zlib-devel pkgconfig python-yaml SDL2-devel SDL2_image-devel \ - libpng-devel freetype-devel dejavu-sans-fonts dejavu-sans-mono-fonts - -(the last six are needed only for tile builds). As with Debian, this package -list avoids the need for the bundled "contribs". - -ccache can be installed with: - - dnf install ccache - - -Prerequisites (Void): - -On Void Linux you can get all dependencies by running the following as root: - - xbps-install make gcc perl flex bison pkg-config ncurses-devel lua51-devel \ - sqlite-devel zlib-devel python-yaml pngcrush dejavu-fonts-ttf \ - SDL2-devel SDL2_mixer-devel SDL2_image-devel freetype-devel - -(the last six are needed only for tile builds). - -ccache can be installed with: - - xbps-install ccache - - -Prerequisites (other systems): - -GNU gcc and g++, GNU make, libncursesw or libcursesw. You need the development -headers for ncurses - they may not be installed by default on some Unixes. - -Python and PyYAML is required to parse some data files. - -For tile builds, you need FreeDesktop's pkg-config, X11 and opengl headers. -The latter are likely to come from mesa sources. - -flex and bison are optional but highly recommended. Recent versions of byacc -are also fine (edit your makefile appropriately). - -You need to link with a curses library that understands Unicode characters, -usually named libncursesw (the development headers for libncursesw are usually -in /usr/include/ncursesw). - - -Building: - -* cd to the source directory. - -* Most users can simply type 'make' without any extra flags, and get a working - build as a result. If just typing 'make' works for you, then you shouldn't - need to read any further. BSD and Solaris users may have to use 'gmake' - instead of 'make'. - -* For information Makefile settings beyond what is here, see the documentation - in comments in the Makefile itself. - -* If you want a graphical (tiled) build, then you should add 'TILES=y' to the - 'make' command-line, like so: - - make TILES=y - - Note that the graphical build requires that you have development libraries - installed for SDL, SDL_image, libpng, zlib, and freetype. If your system - doesn't have these installed, you can usually get them via your package - manager (apt-get, emerge, yum, etc). - - If you would rather, you can go to the source/contrib directory and type - 'make', and the required libraries should be built for you. - -* If you want to install Crawl system-wide rather than play from the build - directory, you need to specify a directory to hold the save and data files. - Specifying a prefix of /usr or /usr/local will default SAVEDIR to "~/.crawl" - and DATADIR to share/crawl (relative to the prefix). SAVEDIR must be - writeable and owned by the user running crawl, so except for special cases it - should be inside "~" (home directory). - -* To be specific, specifying a prefix means adding "prefix=foldername" to your - 'make' command. Specifying a prefix is not mutually exclusive with specifying - a SAVEDIR; you can set them to completely unrelated directories if desired. - -* If you're installing Crawl for multiple users, run 'make install' as root. - Crawl will be copied into the directory specified by 'prefix' (see above). - The data directory will be created if necessary, and the level layout, tile - and help files will be copied there. - -* If you do not want players to be able to script Crawl with Lua, add - 'NO_LUA_BINDINGS=y' to the 'make' command-line. This removes functionality - like autofight, and Lua scripts have been enabled on public servers for many - years without any security issues, so there is no real reason to do so. - - -Building on Mac OS X --------------------- - -Before building on Mac OS X, you need a working copy of Xcode and the -associated command line tools. For recent versions of OS X, Xcode can be -installed through the AppStore as a free download; the associated command line -tools can then be installed by opening Xcode, opening the Preferences dialog, -and clicking Install on the Command Line Tools line in the Download tab. - -Mac builds then use the Unix build process described above. To build Crawl on -a Mac you could use the following example command lines. - -For the console version: - make -For the graphical version: - make TILES=y - - -Building on Windows (MSYS2) ---------------------------- - -This is the only currently recommended process for building Crawl on windows. -It is also possible to cross-compile windows builds; see the release guide -for instructions. - -MSYS2 is a Cygwin-derived software distro for Windows that can build -native applications; you will interact with the build process in a unix-like -shell interface. You can download the MSYS2 installer from the following -website: - -https://msys2.github.io/ - -You generally want to install the 64-bit version of MSYS2 unless you have a -specific reason to build a 32-bit version of crawl. Follow all of the steps you -see on that page to install MSYS2, but please read the additional notes below. -In particular, when starting the MSYS2 Shell, be sure to run the 64-bit MinGW -version of the MSYS2 shell and *not* the version labeled 'MSYS2 MSYS' or the -32-bit version. - -* The installer will put all MSYS2/MinGW files into a folder of your choice, - which defaults to 'C:\msys64'. If you have crawl-related work files from - other directories that you'd like to carry over, you can copy them into - 'C:\msys64\home\', where is your Windows username. This - is the path to your MSYS2 home directory. From the MSYS2 shell you can always - get back to here with `cd ~`. - -* After the installer finishes, start the MSYS2 shell ("MSYS2 MinGW 64-bit") - and do steps 5-6 from the MSYS2 install instructions in order to update your - installation. These steps are repeated here: - - 5. At the command line, run `pacman -Syu` to update the core packages. - Then restart your MSYS2 shell. (The installer will force you to restart.) - - 6. At the command line, run `pacman -Su` to update all packages. - -After MSYS2 is fully installed and updated, follow steps below to install -development packages and compile Crawl. The commands shown below should be run -from within the MSYS2 Shell. - -* To install git and the base development packages, run: - - pacman -S base-devel git - - Accept the default action to install all packages in base-devel, and say yes - to any questions about installing packages or removing packages due to - conflicts. - -* To install the mingw-w64 GCC toolchain for your system, run: - - pacman -S mingw-w64-x86_64-toolchain - -* At this point on current MSYS2 versions, your development environment should - be complete. You can test it by running: - - gcc -v - - If this works, you're all set. If it doesn't, you may be an an older version - of MSYS2 and need to manually add the newly installed toolchain to your - path. To do so, run the following line, either at the command line (for - that shell instance only) or in the file `~/.bashrc` to make it permanent: - - export PATH=$PATH:/mingw64/bin - - After the packages are installed and gcc runs, you're ready to build crawl! - -* To install PyYAML, you can install it from either pacman or from Pip/PyPA: - - pacman -S mingw64/mingw-w64-x86_64-python3-pip - pip install pyyaml - - OR - - pacman -S mingw-w64-x86_64-python3-yaml - - You can verify PyYAML is installed by running `python -m yaml`, which should - give an error like "'yaml' is a package and cannot be directly imported" - (rather than "No module named yaml"). - -* To get the Crawl source, follow the steps in the Source Code Checkout - section above to clone Crawl into your MSYS2 home directory. We recommend - using the MSYS2-installed version of git for these steps. In brief: - - 1. `cd` to the location where you would like the crawl repository to be. It - will clone into a folder named `crawl`. Your home directory (`cd ~`) is - a reasonable choice. - 2. Run `git clone https://github.com/crawl/crawl.git`. - 3. Run `cd crawl/crawl-ref/source`. - 4. Run `git submodule update --init`. - -* Build the console version of Crawl by simply running: - - make - - If you want a graphical build, you will need to add 'TILES=y': - - make TILES=y - - If you want a debug build, add the target `debug` to the above commands. - For building packages, see instructions in the release guide. - -* When the build process finishes, you can run crawl.exe directly from the - source directory in the MSYS2 shell. For Tiles, type './crawl.exe', and for - console, type 'start crawl', which will open Crawl in a new command.exe - window (the Windows version of Crawl requires a command.exe shell and will - not run in an MSYS2 shell). Both versions can also be started by - double-clicking crawl.exe using the graphical file explorer. - -Building on Windows (Cygwin) ----------------------------- - -* This build process is not currently supported. - -* Get Cygwin from http://www.cygwin.com/. When installing, ensure that the - following packages are selected: gcc, g++, make, flex, bison, - libncurses-devel. If you'd like to build from git, install the git-core - package. You may also want to install diff, patch, and other such tools. - -* Once Cygwin is installed, open a Cygwin bash shell (use the Start menu or - desktop icon, do not double-click bash.exe in Explorer). - -* cd to the the Crawl source directory. For instance, if you have the Crawl - sources in c:\crawl\source, you would type 'cd /cygdrive/c/crawl/source'. - -* Follow the Linux build instructions to build Crawl. - -Building on Windows 10 (Linux Subsystem) --------------------------------------------------------------------- - -* Follow the instructions on Microsoft's website at - https://docs.microsoft.com/en-us/windows/wsl/install-win10 to set up the - Windows Subsystem for Linux. - -* Make sure to run 'apt-get update' to get the latest versions of the package - lists, if using Ubuntu. - -* Follow the Linux instructions to build Crawl. - -* Console and Webtiles will work without any further configuration. To get SDL - tiles to work, you need an X server running on Windows; Xming is an option - that has worked in the past. If you run into an error about not finding a - matching GLX visual, try running: - - export SDL_VIDEO_X11_VISUALID= - - -Building on Windows (MSVC) --------------------------- - -* This build process is currently unofficially supported, and unlikely - to be straightforward in versions of MSVC besides those explicitly mentioned - here. - -* You will need to download crawl, as well as its submodules. The easiest way to do - this is with the commands - `git clone https://github.com/crawl/crawl.git` - `git submodule update --init` - -* This build is tested on Visual Studio 2017 15.8.7 on Windows 8.1 and 10. - Supported configurations are Debug/Release;Console/Tiles;Win32/x64 - -* You'll need a perl environment, there are links to several Windows binaries - you can choose from at http://www.perl.org/get.html - -* In the Crawl source, run gen-all.cmd inside crawl-ref/source/util/. This step must - be executed any time you update to a new version of the source (or if you - have modified tile data or unrandarts). - -* To build the Debug version, first build Release, then re-build with the Debug - configuration set. You will need to re-build the Contribs solution as well. - Building the Debug version without first building the Release configuration will - result in an error on startup. - -* The first time you compile, you need to build the Contribs solution. This - compiles various libraries which Crawl itself needs to build. This only needs - to be performed the first time you build, or if the contribs are ever updated - (extremely rare). To do this open and compile Contribs.sln in crawl-ref/source/contrib. - Make sure to set "Release" or "Debug" (not the library versions), as well as - the desired architecture (Win32 or x64). Then build (or re-build) the solution. - -* Open crawl-ref.sln in Visual Studio, this is in crawl-ref/source/MSVC/. - -* You can now select Debug or Release from the drop-down build configurations - menu on the main toolbar (it should be next to "Local Windows Debugger"); - crawl.exe can them be compiled by selecting "Build Solution" in the BUILD - menu. You can quickly run it by selecting "Start without Debugging" in the - debug menu (or debug with "Start Debugging"). Note: the Release build can - still be debugged using the Visual Studio debugger. - -* Building the webserver and Lua (for the dat project) is untested as of now. - -* Better support for Python (for the webserver project) and Lua (for the dat - project) can be installed with these extensions: - - Python Tools for Visual Studio - http://pytools.codeplex.com/releases - - Ports of VsLua to Visual Studio 2012 - http://www.dbfinteractive.com/forum/index.php?topic=5873.0 - http://pouet.net/topic.php?which=9087 - - Try at your own risk, but the first one has been tested and found to be - effective. - -* Maintenance notes: - - MSVC solution files are finicky. Opening the "All Configurations" or - "All Platforms" will automatically change settings. This is typically unwanted. - - Troubleshooting tips: - - Make sure Windows Universal C Runtime is installed in MSVC. - - Build Release before rebuilding both solutions with Debug - - Use "Rebuild Solution" to make sure all files are rewritten - - Make sure all projects use /MD (or /MDd for the debug version) - - Make sure the appropriate (/MD or /MDd) CRT libraries are included for SDL, - crawl, and tilegen (https://msdn.microsoft.com/en-us/library/abx4dbyh.aspx) - - Make sure libpng.dll, SDL2.dll, and SDL2_image.dll are in crawl-ref/source - after building the Contribs solution. These are copied post-build from their - original location in source/contrib/bin/8.0/$(Platform). - - Make sure freetype.lib, libpng.lib, lua.lib, pcre.lib, SDL2.lib, SDL2_image.lib, - SDL2main.lib, sqlite.lib, and zlib.lib are in source/contrib/bin/8.0/$(Platform) - after building the Contribs solution. - - Make sure crawl.exe and tilegen.exe are in crawl-ref/source after building the - crawl-ref solution. - - Tilegen runs early during the crawl.exe build process, using libpng.dll to build PNG files - inside source/rtiles. Breaking tilegen (e.g. by building a different Contribs configuration) - after building these png files correctly will result in tilegen crashing during the crawl build - process, but will not stop the build from working (until it breaks for some other reason). fresh.bat - inside the MSVC folder will clear these files, making sure tilegen stops the build process if it fails. - - tilegen depends on SDL2, SDL2_image, and libpng. - crawl depends on SDL2, SDL2_image, libpng, lua, pcre, sqlite, zlib, and the CRT libraries. - freetype uses the zlib source directory as an include. - libpng depends on zlib, and uses the zlib source directory as an include. - SDL2_image depends on SDL2 and SDL2main. - SDL2 depends on winmm.lib,imm32.lib,version.lib, and the CRT libraries. - -***************************************************************************** - -Data files ----------- - -Crawl looks for several data files when starting up. They include: - -* Special level and vault layout (dat/*.des) files. -* Core Lua code (dat/dlua/*.lua). -* Descriptions for monsters and game features (dat/descript/*.txt). -* Definitions for monster dialogue and randart names (dat/database/*.txt). - -All these files are in the source tree under source/dat. - -Crawl will also look for documentation files when players invoke the help -system. These files are available under the docs directory. - -Your built Crawl binary must be able to find these files, or it will not start. - -If Crawl is built without an explicit DATA_DIR_PATH (this is the most common -setup), it will search for its data files under the current directory, and if -it can't find them there, one level above the current directory. In short, it -uses these search paths: ., ./dat, ./docs, .., ../dat, ../docs. - -The level compiler ------------------- - -Crawl uses a level compiler to read the level design (.des) files in the -source/dat directory. - -If you're using one of standard makefile, the steps described in this section -are performed automatically: - -The level compiler source is in the source/util directory (levcomp.lpp and -levcomp.ypp). The steps involved in building the level compiler are: - -* Run flex on levcomp.lpp to produce the levcomp.lex.cc lexer. -* Run bison on levcomp.ypp to produce the levcomp.tab.cc parser and - levcomp.tab.h -* Compile the resulting C++ source files and levcomp.cc and link the object - files into the Crawl executable. - -For convenience on systems that don't have flex/bison, pre-generated -intermediate files are provided under source/prebuilt. The makefiles provided -with the Crawl source distribution will use these pre-generated files -automatically if flex/bison is not available. - -Lua ---- - -The Lua source is included with Crawl. It will be used if you don't have Lua -headers installed. Note that we don't provide security support for Lua, and -thus if you run a public server or a kiosk, it is strongly recommended to use -system Lua which does receive security updates from whatever distribution you -use. - -PCRE ----- - -PCRE 8.12, with a custom build system but otherwise unchanged, is included with -Crawl. It is enabled by default on Windows; otherwise, unless you build with -BUILD_PCRE (to use the contrib) or USE_PCRE (to use a development package from -your manager), the system POSIX regex will be used. - -Unicode -------- - -On Unix, you want an UTF-8 locale. All modern distributions install one by -default, but you might have somehow dropped required settings. To check this, -run "locale charmap", which should say "UTF-8". If it's not, please ensure -either LANG, LC_ALL or LC_CTYPE is set. A typical line would be "export -LC_ALL=en_US.UTF-8". - -On Windows, the console behaves differently for TrueType and legacy (bitmap) -fonts. The latter (mostly) work only on certain language editions of Windows, -such as English, and even there, they work adequately only for Crawl's default -settings. For anything more, please select one of TrueType fonts. If, like one -of our players, you are deeply attached to the looks of bitmap fonts, you can -download a corrected version of the Terminal font from -http://www.yohng.com/software/terminalvector.html diff -Nru crawl-0.24.0/LICENSE crawl-0.25.0/LICENSE --- crawl-0.24.0/LICENSE 2019-10-24 19:10:56.000000000 +0000 +++ crawl-0.25.0/LICENSE 2020-06-15 16:26:18.000000000 +0000 @@ -19,6 +19,7 @@ worley.{cc,h} * zlib: webserver/static/scripts/contrib/inflate.js * Apache v2, MIT (see comments in the file for details): pcg.cc +* Boost Software License 1.0: catch2-tests/catch.hpp The majority of Crawl's tiles and artwork are released under the CC0 license (https://creativecommons.org/publicdomain/zero/1.0/), and new submissions are diff -Nru crawl-0.24.0/source/ability.cc crawl-0.25.0/source/ability.cc --- crawl-0.24.0/source/ability.cc 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/ability.cc 2020-05-23 16:07:19.000000000 +0000 @@ -15,11 +15,9 @@ #include #include "abyss.h" -#include "acquire.h" #include "areas.h" #include "art-enum.h" #include "branch.h" -#include "butcher.h" #include "chardump.h" #include "cleansing-flame-source-type.h" #include "cloud.h" @@ -37,13 +35,10 @@ #include "god-abil.h" #include "god-companions.h" #include "god-conduct.h" -#include "god-prayer.h" -#include "god-wrath.h" #include "hints.h" #include "invent.h" #include "item-prop.h" #include "items.h" -#include "item-status-flag-type.h" #include "item-use.h" #include "level-state-type.h" #include "libutil.h" @@ -60,6 +55,7 @@ #include "potion.h" #include "prompt.h" #include "religion.h" +#include "rltiles/tiledef-icons.h" #include "skills.h" #include "spl-book.h" #include "spl-cast.h" @@ -84,10 +80,6 @@ #include "unicode.h" #include "view.h" -#ifdef USE_TILE -# include "tiledef-icons.h" -#endif - enum class abflag { none = 0x00000000, @@ -446,7 +438,7 @@ { ABIL_TROG_BERSERK, "Berserk", 0, 0, 600, 0, {fail_basis::invo}, abflag::none }, { ABIL_TROG_REGEN_MR, "Trog's Hand", - 0, 0, 200, 2, {fail_basis::invo, piety_breakpoint(2), 0, 1}, abflag::none }, + 0, 0, 250, 2, {fail_basis::invo, piety_breakpoint(2), 0, 1}, abflag::none }, { ABIL_TROG_BROTHERS_IN_ARMS, "Brothers in Arms", 0, 0, 250, generic_cost::range(5, 6), {fail_basis::invo, piety_breakpoint(5), 0, 1}, abflag::none }, @@ -481,13 +473,13 @@ // Nemelex { ABIL_NEMELEX_DRAW_DESTRUCTION, "Draw Destruction", - 0, 0, 0, 0, {}, abflag::card }, + 0, 0, 0, 0, {fail_basis::invo}, abflag::card }, { ABIL_NEMELEX_DRAW_ESCAPE, "Draw Escape", - 0, 0, 0, 0, {}, abflag::card }, + 0, 0, 0, 0, {fail_basis::invo}, abflag::card }, { ABIL_NEMELEX_DRAW_SUMMONING, "Draw Summoning", - 0, 0, 0, 0, {}, abflag::card }, + 0, 0, 0, 0, {fail_basis::invo}, abflag::card }, { ABIL_NEMELEX_DRAW_STACK, "Draw Stack", - 0, 0, 0, 0, {}, abflag::card }, + 0, 0, 0, 0, {fail_basis::invo}, abflag::card }, { ABIL_NEMELEX_TRIPLE_DRAW, "Triple Draw", 2, 0, 0, 6, {fail_basis::invo, 60, 5, 20}, abflag::none }, { ABIL_NEMELEX_DEAL_FOUR, "Deal Four", @@ -1365,7 +1357,7 @@ if ((abil.ability == ABIL_EVOKE_FLIGHT || abil.ability == ABIL_TRAN_BAT || abil.ability == ABIL_FLY) - && !flight_allowed()) + && !flight_allowed(quiet)) { return false; } @@ -1383,7 +1375,7 @@ || you.duration[DUR_WATER_HOLD] && !you.res_water_drowning()) { talent tal = get_talent(abil.ability, false); - if (tal.is_invocation) + if (tal.is_invocation && abil.ability != ABIL_RENOUNCE_RELIGION) { if (!quiet) { @@ -1560,7 +1552,7 @@ return true; case ABIL_SIF_MUNA_DIVINE_EXEGESIS: - return can_cast_spells(); + return can_cast_spells(quiet, true); case ABIL_ASHENZARI_TRANSFER_KNOWLEDGE: if (!trainable_skills(true)) @@ -2153,7 +2145,7 @@ return cast_blink(fail); break; - case ABIL_EVOKE_BERSERK: // amulet of rage, randarts + case ABIL_EVOKE_BERSERK: // randarts fail_check(); you.go_berserk(true); break; @@ -2362,7 +2354,7 @@ case ABIL_TSO_CLEANSING_FLAME: { - targeter_los hitfunc(&you, LOS_SOLID, 2); + targeter_radius hitfunc(&you, LOS_SOLID, 2); { if (stop_attack_prompt(hitfunc, "harm", _cleansing_flame_affects)) return spret::abort; @@ -2460,7 +2452,7 @@ const spret result = fire_los_attack_spell(SPELL_DRAIN_LIFE, you.skill_rdiv(SK_INVOCATIONS), - &you, nullptr, fail, &damage); + &you, fail, &damage); if (result != spret::success) return result; @@ -3203,20 +3195,13 @@ return spret::success; case ABIL_WU_JIAN_HEAVENLY_STORM: - fail_check(); - mprf(MSGCH_GOD, "The air is filled with shimmering golden clouds!"); - wu_jian_sifu_message(" says: The storm will not cease as long as you " - "keep fighting, disciple!"); - - for (radius_iterator ai(you.pos(), 2, C_SQUARE, LOS_SOLID); ai; ++ai) + if (you.props.exists(WU_JIAN_HEAVENLY_STORM_KEY)) { - if (!cell_is_solid(*ai)) - place_cloud(CLOUD_GOLD_DUST, *ai, 5 + random2(5), &you); + mpr("You are already engulfed in a heavenly storm!"); + return spret::abort; } - - you.attribute[ATTR_HEAVENLY_STORM] = 12; - you.duration[DUR_HEAVENLY_STORM] = WU_JIAN_HEAVEN_TICK_TIME; - invalidate_agrid(true); + fail_check(); + wu_jian_heavenly_storm(); break; case ABIL_WU_JIAN_WALLJUMP: @@ -3369,15 +3354,11 @@ describe_talent(talents[i]), MEL_ITEM, 1, talents[i].hotkey); me->data = &numbers[i]; -#ifdef USE_TILE me->add_tile(tile_def(tileidx_ability(talents[i].which), TEX_GUI)); -#endif if (!check_ability_possible(talents[i].which, true)) { me->colour = COL_INAPPLICABLE; -#ifdef USE_TILE me->add_tile(tile_def(TILEI_MESH, TEX_ICONS)); -#endif } else if (_check_ability_dangerous(talents[i].which, true)) me->colour = COL_DANGEROUS; @@ -3406,16 +3387,12 @@ describe_talent(talents[i]), MEL_ITEM, 1, talents[i].hotkey); me->data = &numbers[i]; -#ifdef USE_TILE me->add_tile(tile_def(tileidx_ability(talents[i].which), TEX_GUI)); -#endif if (!check_ability_possible(talents[i].which, true)) { me->colour = COL_INAPPLICABLE; -#ifdef USE_TILE me->add_tile(tile_def(TILEI_MESH, TEX_ICONS)); -#endif } else if (_check_ability_dangerous(talents[i].which, true)) me->colour = COL_DANGEROUS; @@ -3847,6 +3824,14 @@ abilities.push_back(static_cast(anc_type)); } } + if (you.transfer_skill_points > 0) + abilities.push_back(ABIL_ASHENZARI_END_TRANSFER); + if (silenced(you.pos()) && you_worship(GOD_WU_JIAN) && piety_rank() >= 2) + abilities.push_back(ABIL_WU_JIAN_WALLJUMP); + + if (!ignore_silence && silenced(you.pos())) + return abilities; + // Remaining abilities are unusable if silenced. if (you_worship(GOD_NEMELEX_XOBEH)) { for (int deck = ABIL_NEMELEX_FIRST_DECK; @@ -3858,14 +3843,7 @@ if (!you.props[NEMELEX_STACK_KEY].get_vector().empty()) abilities.push_back(ABIL_NEMELEX_DRAW_STACK); } - if (you.transfer_skill_points > 0) - abilities.push_back(ABIL_ASHENZARI_END_TRANSFER); - if (silenced(you.pos()) && you_worship(GOD_WU_JIAN) && piety_rank() >= 2) - abilities.push_back(ABIL_WU_JIAN_WALLJUMP); - if (!ignore_silence && silenced(you.pos())) - return abilities; - // Remaining abilities are unusable if silenced. for (const auto& power : get_god_powers(you.religion)) { if (god_power_usable(power, ignore_piety, ignore_penance)) Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/._abyss.cc and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/._abyss.cc differ diff -Nru crawl-0.24.0/source/abyss.cc crawl-0.25.0/source/abyss.cc --- crawl-0.24.0/source/abyss.cc 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/abyss.cc 2020-05-23 16:07:19.000000000 +0000 @@ -35,7 +35,6 @@ #include "mapmark.h" #include "maps.h" #include "message.h" -#include "misc.h" #include "mon-cast.h" #include "mon-death.h" #include "mon-pathfind.h" @@ -51,7 +50,7 @@ #include "stairs.h" #include "stringutil.h" #include "terrain.h" -#include "tiledef-dngn.h" +#include "rltiles/tiledef-dngn.h" #include "tileview.h" #include "timed-effects.h" #include "traps.h" @@ -615,7 +614,7 @@ abyss_shift_start_centre); } else - remove_sanctuary(false); + remove_sanctuary(); } } @@ -1137,6 +1136,11 @@ complex_vec[0] = levelLayout; complex_vec[1] = &rivers; // const abyssLayout = new WorleyLayout(23571113, complex_vec, 6.1); + if (is_existing_level(lid)) + { + auto &vault_list = you.vault_list[level_id::current()]; + vault_list.push_back("base: " + lid.describe(false)); + } } const ProceduralSample sample = (*abyssLayout)(pt, abyssal_state.depth); @@ -1570,7 +1574,7 @@ _initialize_abyss_state(); dprf(DIAG_ABYSS, "Abyss Coord (%d, %d)", abyssal_state.major_coord.x, abyssal_state.major_coord.y); - remove_sanctuary(false); + remove_sanctuary(); env.floor_colour = _roll_abyss_floor_colour(); env.rock_colour = _roll_abyss_rock_colour(); @@ -1750,8 +1754,16 @@ struct corrupt_env { - int rock_colour, floor_colour; - corrupt_env(): rock_colour(BLACK), floor_colour(BLACK) { } + int rock_colour, floor_colour, secondary_floor_colour; + corrupt_env() + : rock_colour(BLACK), floor_colour(BLACK), + secondary_floor_colour(MAGENTA) + { } + + int pick_floor_colour() const + { + return random2(10) < 2 ? secondary_floor_colour : floor_colour; + } }; static void _place_corruption_seed(const coord_def &pos, int duration) @@ -1932,6 +1944,61 @@ return true; } +static void _corrupt_square_flavor(const corrupt_env &cenv, const coord_def &c) +{ + dungeon_feature_type feat = grd(c); + int floor = cenv.pick_floor_colour(); + + if (feat == DNGN_ROCK_WALL || feat == DNGN_METAL_WALL + || feat == DNGN_STONE_WALL || feat == DNGN_TREE) + { + env.grid_colours(c) = cenv.rock_colour; + } + else if (feat == DNGN_FLOOR) + env.grid_colours(c) = floor; + + // if you add new features to this, you'll probably need to do some + // hand-tweaking in tileview.cc apply_variations. + // TODO: these tile assignments here seem to get overridden in + // apply_variations, or not used at all...what gives? + if (feat == DNGN_ROCK_WALL) + { + tileidx_t idx = tile_dngn_coloured(TILE_WALL_ABYSS, + cenv.rock_colour); + env.tile_flv(c).wall = idx + random2(tile_dngn_count(idx)); + } + else if (feat == DNGN_FLOOR) + { + tileidx_t idx = tile_dngn_coloured(TILE_FLOOR_NERVES, + floor); + env.tile_flv(c).floor = idx + random2(tile_dngn_count(idx)); + } + else if (feat == DNGN_STONE_WALL) + { + // recoloring stone and metal is also impacted heavily by the rolls + // in _is_grid_corruptible + tileidx_t idx = tile_dngn_coloured(TILE_DNGN_STONE_WALL, + cenv.rock_colour); + env.tile_flv(c).wall = idx + random2(tile_dngn_count(idx)); + } + else if (feat == DNGN_METAL_WALL) + { + tileidx_t idx = tile_dngn_coloured(TILE_DNGN_METAL_WALL, + cenv.rock_colour); + env.tile_flv(c).wall = idx + random2(tile_dngn_count(idx)); + } + else if (feat == DNGN_TREE) + { + tileidx_t idx = tile_dngn_coloured(TILE_DNGN_TREE, + cenv.rock_colour); + // trees only have yellow, lightred, red, and darkgray (dead) + if (idx == TILE_DNGN_TREE) + idx = tile_dngn_coloured(TILE_DNGN_TREE, DARKGREY); + env.grid_colours(c) = DARKGREY; + env.tile_flv(c).wall = idx + random2(tile_dngn_count(idx)); + } +} + static void _corrupt_square(const corrupt_env &cenv, const coord_def &c) { // Ask dungeon_change_terrain to preserve things that are not altars. @@ -1989,23 +2056,7 @@ } dungeon_terrain_changed(c, feat, preserve_features, true); - if (feat == DNGN_ROCK_WALL) - env.grid_colours(c) = cenv.rock_colour; - else if (feat == DNGN_FLOOR) - env.grid_colours(c) = cenv.floor_colour; - - if (feat == DNGN_ROCK_WALL) - { - tileidx_t idx = tile_dngn_coloured(TILE_WALL_ABYSS, - cenv.floor_colour); - env.tile_flv(c).wall = idx + random2(tile_dngn_count(idx)); - } - else if (feat == DNGN_FLOOR) - { - tileidx_t idx = tile_dngn_coloured(TILE_FLOOR_NERVES, - cenv.floor_colour); - env.tile_flv(c).floor = idx + random2(tile_dngn_count(idx)); - } + _corrupt_square_flavor(cenv, c); } static void _corrupt_level_features(const corrupt_env &cenv) @@ -2027,11 +2078,23 @@ // at LOS range (radius 7). Even if the corruption roll is made, // the feature still gets a chance to resist if it's a wall. const int corrupt_perc_chance = - (idistance <= ground_zero_radius) ? 100 : - max(1, 100 - (sqr(idistance) - sqr(ground_zero_radius)) * 70 / 45); + (idistance <= ground_zero_radius) ? 1000 : + max(0, 1000 - (sqr(idistance) - sqr(ground_zero_radius)) * 700 / 45); + + // linear function that is at 30% at range 7, 15% at radius 20, + // maxed to 1%. Only affects outside of range 7. For cells within los + // that don't make the regular roll, this also gives them a 50% + // chance to get flavor-only corruption. + const int corrupt_flavor_chance = + (idistance <= 7) ? (corrupt_perc_chance + 1000) / 2 : + max(10, 380 - 150 * idistance / 13); + + const int roll = random2(1000); - if (random2(100) < corrupt_perc_chance && _is_grid_corruptible(*ri)) + if (roll < corrupt_perc_chance && _is_grid_corruptible(*ri)) _corrupt_square(cenv, *ri); + else if (roll < corrupt_flavor_chance && _is_grid_corruptible(*ri)) + _corrupt_square_flavor(cenv, *ri); } } @@ -2108,12 +2171,13 @@ || !you.props.exists(ABYSS_STAIR_XP_KEY) || you.props[ABYSS_STAIR_XP_KEY].get_int() > 0 || !in_bounds(you.pos()) - || feat_is_staircase(grd(you.pos()))) + || feat_is_critical(grd(you.pos()))) { return; } const bool stairs = !at_branch_bottom() && you.props.exists(ABYSS_SPAWNED_XP_EXIT_KEY) + && coinflip() && you.props[ABYSS_SPAWNED_XP_EXIT_KEY].get_bool(); destroy_wall(you.pos()); // fires listeners etc even if it wasn't a wall diff -Nru crawl-0.24.0/source/acquire.cc crawl-0.25.0/source/acquire.cc --- crawl-0.24.0/source/acquire.cc 2019-06-04 23:37:08.000000000 +0000 +++ crawl-0.25.0/source/acquire.cc 2020-06-15 13:26:54.000000000 +0000 @@ -15,8 +15,11 @@ #include #include +#include "ability.h" #include "artefact.h" #include "art-enum.h" +#include "colour.h" +#include "describe.h" #include "dungeon.h" #include "food.h" #include "god-item.h" @@ -26,10 +29,14 @@ #include "item-status-flag-type.h" #include "items.h" #include "item-use.h" +#include "invent.h" +#include "known-items.h" #include "libutil.h" #include "macro.h" #include "message.h" #include "output.h" +#include "options.h" +#include "prompt.h" #include "randbook.h" #include "random.h" #include "religion.h" @@ -49,7 +56,6 @@ static armour_type _acquirement_body_armour(bool); static armour_type _useless_armour_type(); - /** * Get a randomly rounded value for the player's specified skill, unmodified * by crosstraining, draining, etc. @@ -75,7 +81,8 @@ * @param divine Lowers the odds of high-tier body armours being chosen. * @return The armour_type of the armour to be generated. */ -static int _acquirement_armour_subtype(bool divine, int & /*quantity*/) +static int _acquirement_armour_subtype(bool divine, int & /*quantity*/, + int /*agent*/) { const equipment_type slot_type = _acquirement_armour_slot(divine); return _acquirement_armour_for_slot(slot_type, divine); @@ -197,12 +204,12 @@ * * Weighted by Shields skill & the secret racial shield bonus. * - * Ratios by shields skill & player size (B = buckler, S = shield, L = lg. sh.) + * Ratios by shields skill & player size (B = buckler, K = kite shield, P = tower shield) * * Shields 0 5 10 15 20 - * Large: {6B}/5S/4L ~{1B}/1S/1L ~{1B}/5S/7L ~2S/3L 1S/2L - * Med.: 2B/1S 6B/4S/1L 2B/2S/1L 4B/8S/3L 1S/1L - * Small: ~3B/1S ~5B/2S ~2B/1S ~3B/2S ~1B/1S + * Large: {6B}/5K/4P ~{1B}/1K/1P ~{1B}/5K/7P ~2K/3P 1K/2P + * Med.: 2B/1K 6B/4K/1P 2B/2K/1P 4B/8K/3P 1K/1P + * Small: ~3B/1K ~5B/2K ~2B/1K ~3B/2K ~1B/1K * * XXX: possibly shield skill should count for more for non-med races? * @@ -214,8 +221,8 @@ vector> weights = { { ARM_BUCKLER, player_shield_racial_factor() * 4 * scale - _skill_rdiv(SK_SHIELDS, scale) }, - { ARM_SHIELD, 10 * scale }, - { ARM_LARGE_SHIELD, 20 * scale + { ARM_KITE_SHIELD, 10 * scale }, + { ARM_TOWER_SHIELD, 20 * scale - player_shield_racial_factor() * 4 * scale + _skill_rdiv(SK_SHIELDS, scale / 2) }, }; @@ -346,8 +353,8 @@ { vector> shield_weights = { { ARM_BUCKLER, 1 }, - { ARM_SHIELD, 1 }, - { ARM_LARGE_SHIELD, 1 }, + { ARM_KITE_SHIELD, 1 }, + { ARM_TOWER_SHIELD, 1 }, }; return filtered_vector_select(shield_weights, @@ -401,7 +408,8 @@ return picked; } -static int _acquirement_food_subtype(bool /*divine*/, int& quantity) +static int _acquirement_food_subtype(bool /*divine*/, int& quantity, + int /*agent*/) { int type_wanted; // Food is a little less predictable now. - bwr @@ -427,12 +435,14 @@ * tailored to the player's skills. * @return An appropriate weapon skill; e.g. SK_LONG_BLADES. */ -static skill_type _acquirement_weapon_skill(bool divine) +static skill_type _acquirement_weapon_skill(bool divine, int agent) { // reservoir sample. int count = 0; skill_type skill = SK_FIGHTING; - for (skill_type sk = SK_FIRST_WEAPON; sk <= SK_LAST_WEAPON; ++sk) + for (skill_type sk = SK_FIRST_WEAPON; + sk <= (agent == GOD_TROG ? SK_LAST_MELEE_WEAPON : SK_LAST_WEAPON); + ++sk) { // Adding a small constant allows for the occasional // weapon in an untrained skill. @@ -449,13 +459,17 @@ return skill; } -static int _acquirement_weapon_subtype(bool divine, int & /*quantity*/) +static int _acquirement_weapon_subtype(bool divine, int & /*quantity*/, int agent) { - const skill_type skill = _acquirement_weapon_skill(divine); + const skill_type skill = _acquirement_weapon_skill(divine, agent); int best_sk = 0; - for (int i = SK_FIRST_WEAPON; i <= SK_LAST_WEAPON; i++) + for (int i = SK_FIRST_WEAPON; + i <= (agent == GOD_TROG ? SK_LAST_MELEE_WEAPON : SK_LAST_WEAPON); + i++) + { best_sk = max(best_sk, _skill_rdiv((skill_type)i)); + } best_sk = max(best_sk, _skill_rdiv(SK_UNARMED_COMBAT)); // Now choose a subtype which uses that skill. @@ -523,7 +537,8 @@ return result; } -static int _acquirement_missile_subtype(bool /*divine*/, int & /*quantity*/) +static int _acquirement_missile_subtype(bool /*divine*/, int & /*quantity*/, + int /*agent*/) { int count = 0; int skill = SK_THROWING; @@ -568,7 +583,8 @@ return result; } -static int _acquirement_jewellery_subtype(bool /*divine*/, int & /*quantity*/) +static int _acquirement_jewellery_subtype(bool /*divine*/, int & /*quantity*/, + int /*agent*/) { int result = 0; @@ -592,7 +608,8 @@ } -static int _acquirement_staff_subtype(bool /*divine*/, int & /*quantity*/) +static int _acquirement_staff_subtype(bool /*divine*/, int & /*quantity*/, + int /*agent*/) { // Try to pick an enhancer staff matching the player's best skill. skill_type best_spell_skill = best_skill(SK_FIRST_MAGIC_SCHOOL, @@ -624,57 +641,46 @@ return result; // Otherwise pick a non-enhancer staff. - switch (random2(5)) - { - case 0: case 1: result = STAFF_WIZARDRY; break; - case 2: case 3: result = STAFF_ENERGY; break; - case 4: result = STAFF_POWER; break; - } - return result; + return coinflip() ? STAFF_WIZARDRY : STAFF_ENERGY; } /** * Return a miscellaneous evokable item for acquirement. * @return The item type chosen. */ -static int _acquirement_misc_subtype(bool /*divine*/, int & /*quantity*/) +static int _acquirement_misc_subtype(bool /*divine*/, int & /*quantity*/, + int /*agent*/) { - // Give a crystal ball based on both evocations and either spellcasting or - // invocations if we haven't seen one. - int skills = _skill_rdiv(SK_EVOCATIONS) - * max(_skill_rdiv(SK_SPELLCASTING), _skill_rdiv(SK_INVOCATIONS)); - if (x_chance_in_y(skills, MAX_SKILL_LEVEL * MAX_SKILL_LEVEL) - && !you.seen_misc[MISC_CRYSTAL_BALL_OF_ENERGY]) - { - return MISC_CRYSTAL_BALL_OF_ENERGY; - } - const bool NO_LOVE = you.get_mutation_level(MUT_NO_LOVE); const vector > choices = { // These have charges, so give them a constant weight. - {MISC_BOX_OF_BEASTS, - (NO_LOVE ? 0 : 7)}, - {MISC_SACK_OF_SPIDERS, - (NO_LOVE ? 0 : 7)}, - {MISC_PHANTOM_MIRROR, - (NO_LOVE ? 0 : 7)}, - // The player never needs more than one. + {MISC_BOX_OF_BEASTS, (NO_LOVE ? 0 : 10)}, + {MISC_PHANTOM_MIRROR, (NO_LOVE ? 0 : 10)}, + // The player never needs more than one of the rest. + // Tremorstones are better for heavily armoured characters. + {MISC_TIN_OF_TREMORSTONES, + (you.seen_misc[MISC_TIN_OF_TREMORSTONES] + ? 0 : 5 + _skill_rdiv(SK_ARMOUR) / 3)}, {MISC_LIGHTNING_ROD, - (you.seen_misc[MISC_LIGHTNING_ROD] ? 0 : 17)}, - {MISC_LAMP_OF_FIRE, - (you.seen_misc[MISC_LAMP_OF_FIRE] ? 0 : 17)}, + (you.seen_misc[MISC_LIGHTNING_ROD] ? 0 : 20)}, {MISC_PHIAL_OF_FLOODS, - (you.seen_misc[MISC_PHIAL_OF_FLOODS] ? 0 : 17)}, - {MISC_FAN_OF_GALES, - (you.seen_misc[MISC_FAN_OF_GALES] ? 0 : 17)}, + (you.seen_misc[MISC_PHIAL_OF_FLOODS] ? 0 : 20)}, + }; const int * const choice = random_choose_weighted(choices); - // Could be nullptr if all the weights were 0. - return choice ? *choice : MISC_CRYSTAL_BALL_OF_ENERGY; + // Possible for everything to be 0 weight - if so just give a random spare. + if (choice == nullptr) + { + return random_choose(MISC_TIN_OF_TREMORSTONES, + MISC_LIGHTNING_ROD, + MISC_PHIAL_OF_FLOODS); + } + + return *choice; } /** @@ -685,12 +691,12 @@ * * @return A random wand type. */ -static int _acquirement_wand_subtype(bool /*divine*/, int & /*quantity*/) +static int _acquirement_wand_subtype(bool /*divine*/, int & /*quantity*/, + int /*agent */) { // basic total: 120 vector> weights = { - { WAND_SCATTERSHOT, 25 }, - { WAND_CLOUDS, 25 }, + { WAND_CLOUDS, 18 }, { WAND_ACID, 18 }, { WAND_ICEBLAST, 18 }, { WAND_ENSLAVEMENT, you.get_mutation_level(MUT_NO_LOVE) ? 0 : 8 }, @@ -712,14 +718,15 @@ return *wand; } -static int _acquirement_book_subtype(bool /*divine*/, int & /*quantity*/) +static int _acquirement_book_subtype(bool /*divine*/, int & /*quantity*/, + int /*agent*/) { return BOOK_MINOR_MAGIC; //this gets overwritten later, but needs to be a sane value //or asserts will get set off } -typedef int (*acquirement_subtype_finder)(bool divine, int &quantity); +typedef int (*acquirement_subtype_finder)(bool divine, int &quantity, int agent); static const acquirement_subtype_finder _subtype_finders[] = { _acquirement_weapon_subtype, @@ -763,7 +770,10 @@ class_wanted = random_choose(OBJ_WANDS, OBJ_MISCELLANY); if (_subtype_finders[class_wanted]) - type_wanted = (*_subtype_finders[class_wanted])(divine, quantity); + { + type_wanted = + (*_subtype_finders[class_wanted])(divine, quantity, agent); + } item_def dummy; dummy.base_type = class_wanted; @@ -836,23 +846,23 @@ static bool _skill_useless_with_god(int skill) { + if (skill == SK_INVOCATIONS) + { + // No active invocations, or uses a different skill. + return invo_skill() != SK_INVOCATIONS + || you_worship(GOD_XOM) + || you_worship(GOD_VEHUMET) + || you_worship(GOD_NO_GOD); + } + switch (you.religion) { case GOD_TROG: - return _is_magic_skill(skill) || skill == SK_INVOCATIONS; + return _is_magic_skill(skill); case GOD_ZIN: case GOD_SHINING_ONE: case GOD_ELYVILON: return skill == SK_NECROMANCY; - case GOD_XOM: - case GOD_RU: - case GOD_KIKUBAAQUDGHA: - case GOD_VEHUMET: - case GOD_ASHENZARI: - case GOD_JIYVA: - case GOD_GOZAG: - case GOD_NO_GOD: - return skill == SK_INVOCATIONS; default: return false; } @@ -933,9 +943,7 @@ choose_random_weighted(weights, end(weights))); // Set number of bonus skill points. book.skill_points = random_range(2000, 3000); - // Identify. - set_ident_type(book, true); - set_ident_flags(book, ISFLAG_IDENT_MASK); + return true; } @@ -979,8 +987,10 @@ book.sub_type = choose_random_weighted(weights, end(weights)); break; } - // else intentional fall-through + acquire_themed_randbook(book, agent); + break; } + case BOOK_RANDART_THEME: acquire_themed_randbook(book, agent); break; @@ -1123,15 +1133,19 @@ * Take a newly-generated acquirement item, and adjust its brand if we don't * like it. * - * Specifically, if we think the brand is too weak (for non-divine gifts), or - * sometimes if we've seen the brand before. + * Specifically, when any of: + * - The god doesn't like the brand (for divine gifts) + * - We think the brand is too weak (for non-divine gifts) + * - Sometimes if we've seen the brand before. * * @param item The item which may have its brand adjusted. Not necessarily * a weapon or piece of armour. * @param divine Whether the item is a god gift, rather than from * acquirement proper. + * @param agent The source of the acquirement. For god gifts, it's equal to + * the god. */ -static void _adjust_brand(item_def &item, bool divine) +static void _adjust_brand(item_def &item, bool divine, int agent) { if (item.base_type != OBJ_WEAPONS && item.base_type != OBJ_ARMOUR) return; // don't reroll missile brands, I guess @@ -1139,6 +1153,16 @@ if (is_artefact(item)) return; // their own kettle of fish + + // Trog has a restricted brand table. + if (agent == GOD_TROG && item.base_type == OBJ_WEAPONS) + { + // 75% chance of a brand + item.brand = random_choose(SPWPN_NORMAL, SPWPN_VORPAL, + SPWPN_FLAMING, SPWPN_ANTIMAGIC); + return; + } + // Not from a god, so we should prefer better brands. if (!divine && item.base_type == OBJ_WEAPONS) { @@ -1175,17 +1199,9 @@ return "Destroying unusable weapon or armour!"; } - // Trog does not gift the Wrath of Trog, nor weapons of pain - // (which work together with Necromantic magic). - // nor fancy magic staffs (wucad mu, majin-bo) - if (agent == GOD_TROG - && (get_weapon_brand(item) == SPWPN_PAIN - || is_unrandom_artefact(item, UNRAND_TROG) - || is_unrandom_artefact(item, UNRAND_WUCAD_MU) - || is_unrandom_artefact(item, UNRAND_MAJIN))) - { - return "Destroying a weapon Trog hates!"; - } + // Trog does not gift the Wrath of Trog. + if (agent == GOD_TROG && is_unrandom_artefact(item, UNRAND_TROG)) + return "Destroying Trog-gifted Wrath of Trog!"; // Pain brand is useless if you've sacrificed Necromacy. if (you.get_mutation_level(MUT_NO_NECROMANCY_MAGIC) @@ -1203,25 +1219,12 @@ return "Destroying sif-gifted rarebook!"; } -#if TAG_MAJOR_VERSION == 34 - // The crystal ball case should be handled elsewhere, but just in - // case, it's also handled here. - if (agent == GOD_PAKELLAS) - { - if (item.base_type == OBJ_MISCELLANY - && item.sub_type == MISC_CRYSTAL_BALL_OF_ENERGY) - { - return "Destroying CBoE that Pakellas hates!"; - } - } -#endif - return ""; // all OK } int acquirement_create_item(object_class_type class_wanted, int agent, bool quiet, - const coord_def &pos, bool debug) + const coord_def &pos) { ASSERT(class_wanted != OBJ_RANDOM); @@ -1264,7 +1267,7 @@ } item_def &acq_item(mitm[thing_created]); - _adjust_brand(acq_item, divine); + _adjust_brand(acq_item, divine, agent); // For plain armour, try to change the subtype to something // matching a currently unfilled equipment slot. @@ -1316,14 +1319,6 @@ } } - if (agent == GOD_TROG && coinflip() - && acq_item.base_type == OBJ_WEAPONS && !is_range_weapon(acq_item) - && !is_unrandom_artefact(acq_item)) - { - // ... but Trog loves the antimagic brand specially. - set_item_ego_type(acq_item, OBJ_WEAPONS, SPWPN_ANTIMAGIC); - } - const string rejection_reason = _why_reject(acq_item, agent); if (!rejection_reason.empty()) { @@ -1413,14 +1408,11 @@ make_item_randart(acq_item, true); } - if (agent == GOD_TROG || agent == GOD_OKAWARU) - { - if (agent == GOD_TROG) - acq_item.plus += random2(3); - - // On a weapon, an enchantment of less than 0 is never viable. - acq_item.plus = max(static_cast(acq_item.plus), random2(2)); - } + if (agent == GOD_TROG) + acq_item.plus += random2(3); + // God gifts (except Xom's) never have a negative enchantment + if (divine && agent != GOD_XOM) + acq_item.plus = max(static_cast(acq_item.plus), 0); } // Last check: don't acquire items your god hates. @@ -1448,9 +1440,20 @@ item_set_appearance(mitm[thing_created]); // cleanup + if (thing_created != NON_ITEM) + { + ASSERT(mitm[thing_created].is_valid()); + mitm[thing_created].props[ACQUIRE_KEY].get_int() = agent; + } + ASSERT(!is_useless_item(mitm[thing_created], false) || agent == GOD_XOM); ASSERT(!god_hates_item(mitm[thing_created])); + // If we have a zero coord_def, don't move the item to the grid. Used for + // generating scroll of acquirement items. + if (pos.origin()) + return thing_created; + // Moving this above the move since it might not exist after falling. if (thing_created != NON_ITEM && !quiet) canned_msg(MSG_SOMETHING_APPEARS); @@ -1461,127 +1464,333 @@ && agent > GOD_NO_GOD && agent < NUM_GODS) { - if (agent == GOD_XOM) + if (!quiet && agent == GOD_XOM) simple_god_message(" snickers.", GOD_XOM); else return _failed_acquirement(quiet); } - move_item_to_grid(&thing_created, pos); + move_item_to_grid(&thing_created, pos, quiet); - if (thing_created != NON_ITEM) + return thing_created; +} + +class AcquireMenu : public InvMenu +{ + friend class AcquireEntry; + + CrawlVector &acq_items; + + void init_entries(); + void update_help(); + bool acquire_selected(); + + virtual bool process_key(int keyin) override; + +public: + AcquireMenu(CrawlVector &aitems); +}; + +class AcquireEntry : public InvEntry +{ + string get_text(bool need_cursor = false) const override { - ASSERT(mitm[thing_created].is_valid()); - mitm[thing_created].props[ACQUIRE_KEY].get_int() = agent; + need_cursor = need_cursor && show_cursor; + const colour_t keycol = LIGHTCYAN; + const string keystr = colour_to_str(keycol); + const string itemstr = + colour_to_str(menu_colour(text, item_prefix(*item), tag)); + const string gold_text = item->base_type == OBJ_GOLD + ? make_stringf(" (you have %d gold)", you.gold) : ""; + return make_stringf(" <%s>%c%c%c%c<%s>%s%s", + keystr.c_str(), + hotkeys[0], + need_cursor ? '[' : ' ', + selected() ? '+' : '-', + need_cursor ? ']' : ' ', + keystr.c_str(), + itemstr.c_str(), + text.c_str(), + gold_text.c_str(), + itemstr.c_str()); } - return thing_created; + +public: + AcquireEntry(const item_def& i) : InvEntry(i) + { + show_background = false; + } +}; + +AcquireMenu::AcquireMenu(CrawlVector &aitems) + : InvMenu(MF_SINGLESELECT | MF_NO_SELECT_QTY | MF_QUIET_SELECT + | MF_ALWAYS_SHOW_MORE | MF_ALLOW_FORMATTING), + acq_items(aitems) +{ + menu_action = ACT_EXECUTE; + set_flags(get_flags() & ~MF_USE_TWO_COLUMNS); + + set_tag("acquirement"); + + init_entries(); + + update_help(); + + set_title("Choose an item to acquire."); } -bool acquirement(object_class_type class_wanted, int agent, - bool quiet, int* item_index, bool debug, bool known_scroll) +void AcquireMenu::init_entries() { - ASSERT(!crawl_state.game_is_arena()); + menu_letter ckey = 'a'; + for (item_def& item : acq_items) + { + auto newentry = make_unique(item); + newentry->hotkeys.clear(); + newentry->add_hotkey(ckey++); + add_entry(move(newentry)); + } +} - FixedBitVector bad_class; - if (you.species == SP_FELID) +static string _hyphenated_letters(int how_many, char first) +{ + string s = ""; + s += first; + s += ""; + if (how_many > 1) { - bad_class.set(OBJ_WEAPONS); - bad_class.set(OBJ_MISSILES); - bad_class.set(OBJ_ARMOUR); - bad_class.set(OBJ_STAVES); - } - if (you.get_mutation_level(MUT_NO_ARTIFICE)) - bad_class.set(OBJ_MISCELLANY); - - bad_class.set(OBJ_FOOD, you_foodless(false) && !you_worship(GOD_FEDHAS)); - - static struct { object_class_type type; const char* name; } acq_classes[] = - { - { OBJ_WEAPONS, "Weapon" }, - { OBJ_ARMOUR, "Armour" }, - { OBJ_JEWELLERY, "Jewellery" }, - { OBJ_BOOKS, "Book" }, - { OBJ_STAVES, "Staff " }, - { OBJ_MISCELLANY, "Evocable" }, - { OBJ_FOOD, "Food" }, // amended below - { OBJ_GOLD, 0 }, - }; - ASSERT(acq_classes[6].type == OBJ_FOOD); - string gold_text = make_stringf("Gold (you have $%d)", you.gold); - ASSERT(acq_classes[7].type == OBJ_GOLD); - acq_classes[7].name = gold_text.c_str(); + s += "-"; + s += first + how_many - 1; + s += ""; + } + return s; +} - int thing_created = NON_ITEM; +void AcquireMenu::update_help() +{ + string top_line = string(80, ' ') + '\n'; - if (item_index == nullptr) - item_index = &thing_created; + set_more(formatted_string::parse_string(top_line + make_stringf( + //[!] acquire|examine item [a-i] select item to acquire + //[Esc/R-Click] exit + "%s [%s] %s\n" + "[Esc/R-Click] exit", + menu_action == ACT_EXECUTE ? "[!] acquire|examine items" : + "[!] acquire|examine items", + _hyphenated_letters(item_count(), 'a').c_str(), + menu_action == ACT_EXECUTE ? "select item for acquirement" + : "examine item"))); +} - *item_index = NON_ITEM; +static void _create_acquirement_item(item_def &item) +{ + auto &acq_items = you.props[ACQUIRE_ITEMS_KEY].get_vector(); -#ifdef USE_TILE_WEB - ui::cutoff_point ui_cutoff_point; -#endif + // Now that we have a selection, mark any generated unrands as not having + // been generated, so they go back in circulation. Exclude the selected + // item from this, if it's an unrand. + for (auto aitem : acq_items) + { + if (is_unrandom_artefact(aitem) + && (!is_unrandom_artefact(item) + || !is_unrandom_artefact(aitem, item.unrand_idx))) + { + set_unique_item_status(aitem, UNIQ_NOT_EXISTS); + } + } + + // We're now safe to make any notes about finding the item. + unset_ident_flags(item, ISFLAG_NOTED_ID | ISFLAG_NOTED_GET); + set_ident_type(item, true); + + if (copy_item_to_grid(item, you.pos())) + canned_msg(MSG_SOMETHING_APPEARS); + else + canned_msg(MSG_NOTHING_HAPPENS); - while (class_wanted == OBJ_RANDOM) + acq_items.clear(); + you.props.erase(ACQUIRE_ITEMS_KEY); +} + +bool AcquireMenu::acquire_selected() +{ + vector selected = selected_entries(); + ASSERT(selected.size() == 1); + auto& entry = *selected[0]; + + const string col = colour_to_str(channel_to_colour(MSGCH_PROMPT)); + update_help(); + const formatted_string old_more = more; + more = formatted_string::parse_string(make_stringf( + "<%s>Acquire %s? (%s/N)\n", + col.c_str(), + entry.text.c_str(), + Options.easy_confirm == easy_confirm_type::none ? "Y" : "y", + col.c_str())); + more += old_more; + update_more(); + + if (!yesno(nullptr, true, 'n', false, false, true)) { - ASSERT(!quiet); - clear_messages(); + deselect_all(); + more = old_more; + update_more(); + return true; + } + + item_def &acq_item = *static_cast(entry.data); + _create_acquirement_item(acq_item); + + return false; +} - string line; - for (unsigned int i = 0; i < ARRAYSZ(acq_classes); i++) +bool AcquireMenu::process_key(int keyin) +{ + switch (keyin) + { + case '!': + case '?': + if (menu_action == ACT_EXECUTE) + menu_action = ACT_EXAMINE; + else + menu_action = ACT_EXECUTE; + update_help(); + update_more(); + return true; + default: + break; + } + + if (keyin - 'a' >= 0 && keyin - 'a' < (int)items.size()) + { + if (menu_action == ACT_EXAMINE) { - int len = max(strlen(acq_classes[i].name), - strlen(acq_classes[(i + ARRAYSZ(acq_classes) / 2) - % ARRAYSZ(acq_classes)].name)); - if (bad_class[acq_classes[i].type]) - line += make_stringf(" %-*s", len, ""); - else - line += make_stringf(" [%c] %-*s", i + 'a', len, acq_classes[i].name); + item_def& item(*const_cast(dynamic_cast( + items[letter_to_index(keyin)])->item)); - if (i == ARRAYSZ(acq_classes) / 2 - 1 || i == ARRAYSZ(acq_classes) - 1) - { - line.erase(0, 1); - mpr(line); - line.clear(); - } + unwind_var old_flags(item.flags); + item.flags |= (ISFLAG_IDENT_MASK | ISFLAG_NOTED_ID + | ISFLAG_NOTED_GET); + describe_item(item); + + return true; } - mprf(MSGCH_PROMPT, "What kind of item would you like to acquire?" - " [\\] known items %s", - shopping_list.empty() ? "" : "[$] shopping list"); - - const int keyin = toalower(get_ch()); - if (keyin >= 'a' && keyin < 'a' + (int)ARRAYSZ(acq_classes)) - class_wanted = acq_classes[keyin - 'a'].type; - else if (keyin == '\\') - check_item_knowledge(), redraw_screen(); - else if (keyin == '$' && !shopping_list.empty()) - shopping_list.display(true), redraw_screen(); else { - // Lets wizards escape out of accidentally choosing acquirement. - if (agent == AQ_WIZMODE || known_scroll) - { - canned_msg(MSG_OK); - return false; - } - - // If we've gotten a HUP signal then the player will be unable - // to make a selection. - if (crawl_state.seen_hups) - { - dprf("Acquirement interrupted by HUP signal."); - you.turn_is_over = false; - return false; - } + const unsigned int i = keyin - 'a'; + select_item_index(i, 1, false); + return acquire_selected(); } + } + + const bool ret = InvMenu::process_key(keyin); + auto selected = selected_entries(); + if (selected.size() == 1) + return acquire_selected(); + else + return ret; +} + +static item_def _acquirement_item_def(object_class_type item_type) +{ + item_def item; + + const int item_index = acquirement_create_item(item_type, AQ_SCROLL, true); - if (class_wanted >= NUM_OBJECT_CLASSES || bad_class[class_wanted]) - class_wanted = OBJ_RANDOM; + if (item_index != NON_ITEM) + { + ASSERT(!god_hates_item(mitm[item_index])); + + // We make a copy of the item def, but we don't keep the real item. + item = mitm[item_index]; + set_ident_flags(item, + // Act as if we've recieved this item already to prevent notes. + ISFLAG_IDENT_MASK | ISFLAG_NOTED_ID | ISFLAG_NOTED_GET); + destroy_item(item_index); } - *item_index = acquirement_create_item(class_wanted, agent, quiet, - you.pos(), debug); - ASSERT(*item_index == NON_ITEM || !god_hates_item(mitm[*item_index])); + return item; +} - return true; +static void _make_acquirement_items() +{ + vector rand_classes; + + if (you.species != SP_FELID) + { + rand_classes.emplace_back(OBJ_WEAPONS); + rand_classes.emplace_back(OBJ_ARMOUR); + rand_classes.emplace_back(OBJ_STAVES); + } + + rand_classes.emplace_back(OBJ_JEWELLERY); + rand_classes.emplace_back(OBJ_BOOKS); + + const int num_wanted = min(3, (int) rand_classes.size()); + shuffle_array(rand_classes); + + CrawlVector &acq_items = you.props[ACQUIRE_ITEMS_KEY].get_vector(); + acq_items.empty(); + + // Generate item defs until we have enough, skipping any random classes + // that fail to generate an item. + for (auto obj_type : rand_classes) + { + if (acq_items.size() == num_wanted) + break; + + auto item = _acquirement_item_def(obj_type); + if (item.defined()) + acq_items.push_back(item); + } + + // Gold and food (for characters that eat) are guaranteed. + auto gold_item = _acquirement_item_def(OBJ_GOLD); + if (gold_item.defined()) + acq_items.push_back(gold_item); + + if (!you_foodless(false)) + { + auto food_item = _acquirement_item_def(OBJ_FOOD); + if (food_item.defined()) + acq_items.push_back(food_item); + } +} + +/* + * Handle scroll of acquirement. + * + * Generate acquirement choices as items in a prop if these don't already exist + * (because a scroll was read and canceled. Then either get the acquirement + * choice from the c_choose_acquirement lua handler if one exists or present a + * menu for the player to choose an item. + * + * returns True if the scroll was used, false if it was canceled. +*/ +bool acquirement_menu() +{ + ASSERT(!crawl_state.game_is_arena()); + + if (!you.props.exists(ACQUIRE_ITEMS_KEY)) + _make_acquirement_items(); + + auto &acq_items = you.props[ACQUIRE_ITEMS_KEY].get_vector(); + +#ifdef CLUA_BINDINGS + int index = 0; + if (!clua.callfn("c_choose_acquirement", ">d", &index)) + { + if (!clua.error.empty()) + mprf(MSGCH_ERROR, "Lua error: %s", clua.error.c_str()); + } + else if (index >= 1 && index <= acq_items.size()) + { + _create_acquirement_item(acq_items[index - 1]); + return true; + } +#endif + + AcquireMenu acq_menu(acq_items); + acq_menu.show(); + + return !you.props.exists(ACQUIRE_ITEMS_KEY); } diff -Nru crawl-0.24.0/source/acquire.h crawl-0.25.0/source/acquire.h --- crawl-0.24.0/source/acquire.h 2018-10-13 03:25:38.000000000 +0000 +++ crawl-0.25.0/source/acquire.h 2020-05-23 16:07:19.000000000 +0000 @@ -5,10 +5,9 @@ #pragma once -bool acquirement(object_class_type force_class, int agent, - bool quiet = false, int *item_index = nullptr, - bool debug = false, bool known_scroll = false); +#include "item-prop-enum.h" -int acquirement_create_item(object_class_type class_wanted, - int agent, bool quiet, - const coord_def &pos, bool debug = false); +bool acquirement_menu(); + +int acquirement_create_item(object_class_type class_wanted, int agent, + bool quiet, const coord_def &pos = coord_def()); Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/._actor.cc and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/._actor.cc differ diff -Nru crawl-0.24.0/source/actor.cc crawl-0.25.0/source/actor.cc --- crawl-0.24.0/source/actor.cc 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/source/actor.cc 2020-06-15 00:09:57.000000000 +0000 @@ -16,6 +16,7 @@ #include "god-passive.h" #include "item-prop.h" #include "los.h" +#include "message.h" #include "mon-behv.h" #include "mon-death.h" #include "religion.h" @@ -39,9 +40,9 @@ && mons_is_elven_twin(static_cast(this))); } -level_id actor::shaft_dest(bool known = false) const +level_id actor::shaft_dest() const { - return generic_shaft_dest(pos(), known); + return generic_shaft_dest(level_id::current()); } /** @@ -49,13 +50,7 @@ */ bool actor::ground_level() const { - return !airborne() && !is_wall_clinging(); -} - -bool actor::stand_on_solid_ground() const -{ - return ground_level() && feat_has_solid_floor(grd(pos())) - && !feat_is_water(grd(pos())); + return !airborne(); } // Give hands required to wield weapon. @@ -95,9 +90,6 @@ bool actor::is_habitable(const coord_def &_pos) const { - if (can_cling_to(_pos)) - return true; - return is_habitable_feat(grd(_pos)); } @@ -203,24 +195,19 @@ return wearing(EQ_AMULET, AMU_INACCURACY); } -bool actor::gourmand(bool calc_unid, bool items) const -{ - return items && wearing(EQ_AMULET, AMU_THE_GOURMAND, calc_unid); -} - bool actor::res_corr(bool calc_unid, bool items) const { return items && (wearing(EQ_RINGS, RING_RESIST_CORROSION, calc_unid) || wearing(EQ_BODY_ARMOUR, ARM_ACID_DRAGON_ARMOUR, calc_unid) - || scan_artefacts(ARTP_RCORR, calc_unid)); + || scan_artefacts(ARTP_RCORR, calc_unid) + || wearing_ego(EQ_ALL_ARMOUR, SPARM_PRESERVATION, calc_unid)); } -bool actor::cloud_immune(bool calc_unid, bool items) const +bool actor::cloud_immune(bool /*calc_unid*/, bool items) const { const item_def *body_armour = slot_item(EQ_BODY_ARMOUR); - return items && (wearing_ego(EQ_CLOAK, SPARM_CLOUD_IMMUNE, calc_unid) - || (body_armour - && is_unrandom_artefact(*body_armour, UNRAND_RCLOUDS))); + return items && body_armour + && is_unrandom_artefact(*body_armour, UNRAND_RCLOUDS); } bool actor::holy_wrath_susceptible() const @@ -232,7 +219,7 @@ // not an actor is capable of teleporting, only whether they are specifically // under the influence of the "notele" effect. See actor::no_tele() for a // superset of this function. -bool actor::has_notele_item(bool calc_unid, vector *matches) const +bool actor::has_notele_item(bool calc_unid, vector *matches) const { return scan_artefacts(ARTP_PREVENT_TELEPORTATION, calc_unid, matches); } @@ -275,6 +262,8 @@ */ int actor::spec_evoke(bool calc_unid, bool items) const { + UNUSED(calc_unid); + UNUSED(items); return 0; } @@ -291,7 +280,7 @@ bool actor::extra_harm(bool calc_unid, bool items) const { return items && - (wearing(EQ_AMULET, AMU_HARM, calc_unid) + (wearing(EQ_CLOAK, SPARM_HARM, calc_unid) || scan_artefacts(ARTP_HARM, calc_unid)); } @@ -302,8 +291,7 @@ bool actor::evokable_berserk(bool calc_unid) const { - return wearing(EQ_AMULET, AMU_RAGE, calc_unid) - || scan_artefacts(ARTP_BERSERK, calc_unid); + return scan_artefacts(ARTP_BERSERK, calc_unid); } int actor::evokable_invis(bool calc_unid) const @@ -396,70 +384,6 @@ || act->is_monster() && mons_is_slime(*act->as_monster()); } -/** - * Accessor method to the clinging member. - * - * @return The value of clinging. - */ -bool actor::is_wall_clinging() const -{ - return props.exists(CLING_KEY) && props[CLING_KEY].get_bool(); -} - -/** - * Check a cell to see if actor can keep clinging if it moves to it. - * - * @param p Coordinates of the cell checked. - * @return Whether the actor can cling. - */ -bool actor::can_cling_to(const coord_def& p) const -{ - if (!is_wall_clinging() || !can_pass_through_feat(grd(p))) - return false; - - return cell_can_cling_to(pos(), p); -} - -/** - * Update the clinging status of an actor. - * - * It checks adjacent orthogonal walls to see if the actor can cling to them. - * If actor has fallen from the wall (wall dug or actor changed form), print a - * message and apply location effects. - * - * @param stepped Whether the actor has taken a step. - * @return the new clinging status. - */ -bool actor::check_clinging(bool stepped, bool door) -{ - bool was_clinging = is_wall_clinging(); - bool clinging = can_cling_to_walls() && cell_is_clingable(pos()) - && !airborne(); - - if (can_cling_to_walls()) - props[CLING_KEY] = clinging; - else if (props.exists(CLING_KEY)) - props.erase(CLING_KEY); - - if (!stepped && was_clinging && !clinging) - { - if (you.can_see(*this)) - { - mprf("%s %s off the %s.", name(DESC_THE).c_str(), - conj_verb("fall").c_str(), - door ? "door" : "wall"); - } - apply_location_effects(pos()); - } - return clinging; -} - -void actor::clear_clinging() -{ - if (props.exists(CLING_KEY)) - props[CLING_KEY] = false; -} - void actor::clear_constricted() { constricted_by = 0; @@ -992,6 +916,11 @@ void actor::collide(coord_def newpos, const actor *agent, int pow) { actor *other = actor_at(newpos); + const bool fedhas_prot = agent && agent->deity() == GOD_FEDHAS + && is_monster() && fedhas_protects(as_monster()); + const bool fedhas_prot_other = agent && agent->deity() == GOD_FEDHAS + && other && other->is_monster() + && fedhas_protects(other->as_monster()); ASSERT(this != other); ASSERT(alive()); @@ -1002,28 +931,42 @@ return; } - if (is_monster()) + if (is_monster() && !fedhas_prot) behaviour_event(as_monster(), ME_WHACK, agent); dice_def damage(2, 1 + pow / 10); if (other && other->alive()) { - if (other->is_monster()) - behaviour_event(other->as_monster(), ME_WHACK, agent); if (you.can_see(*this) || you.can_see(*other)) { mprf("%s %s with %s!", name(DESC_THE).c_str(), conj_verb("collide").c_str(), other->name(DESC_THE).c_str()); + if (fedhas_prot || fedhas_prot_other) + { + const bool both = fedhas_prot && fedhas_prot_other; + simple_god_message( + make_stringf(" protects %s plant%s from harm.", + agent->is_player() ? "your" : + both ? "some" : "a", + both ? "s" : "").c_str(), GOD_FEDHAS); + } } + + if (other->is_monster() && !fedhas_prot_other) + behaviour_event(other->as_monster(), ME_WHACK, agent); + const string thisname = name(DESC_A, true); const string othername = other->name(DESC_A, true); - other->hurt(agent, other->apply_ac(damage.roll()), - BEAM_MISSILE, KILLED_BY_COLLISION, - othername, thisname); - if (alive()) + if (other->alive() && !fedhas_prot_other) + { + other->hurt(agent, other->apply_ac(damage.roll()), + BEAM_MISSILE, KILLED_BY_COLLISION, + othername, thisname); + } + if (alive() && !fedhas_prot) { hurt(agent, apply_ac(damage.roll()), BEAM_MISSILE, KILLED_BY_COLLISION, thisname, othername); @@ -1038,7 +981,7 @@ mprf("%s %s into %s!", name(DESC_THE).c_str(), conj_verb("slam").c_str(), env.map_knowledge(newpos).known() - ? feature_description_at(newpos, false, DESC_THE, false) + ? feature_description_at(newpos, false, DESC_THE) .c_str() : "something"); } @@ -1047,10 +990,20 @@ mprf("%s violently %s moving!", name(DESC_THE).c_str(), conj_verb("stop").c_str()); } + + if (fedhas_prot) + { + simple_god_message( + make_stringf(" protects %s plant from harm.", + agent->is_player() ? "your" : "a").c_str(), GOD_FEDHAS); + } + } + + if (!fedhas_prot) + { + hurt(agent, apply_ac(damage.roll()), BEAM_MISSILE, + KILLED_BY_COLLISION, "", feature_description_at(newpos)); } - hurt(agent, apply_ac(damage.roll()), BEAM_MISSILE, - KILLED_BY_COLLISION, "", - feature_description_at(newpos, false, DESC_A, false)); } /// Is this creature despised by the so-called 'good gods'? diff -Nru crawl-0.24.0/source/actor.h crawl-0.25.0/source/actor.h --- crawl-0.24.0/source/actor.h 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/actor.h 2020-05-23 16:07:19.000000000 +0000 @@ -16,8 +16,6 @@ #include "size-type.h" #include "stat-type.h" -#define CLING_KEY "clinging" // 'is creature clinging' property key - enum class ev_ignore { none = 0, @@ -26,6 +24,13 @@ }; DEF_BITFIELD(ev_ignore_type, ev_ignore); +enum rot_resistance // Resistance to HP rot. +{ + ROT_RESIST_NONE, // No resistance to rotting. + ROT_RESIST_MUNDANE, // Immune to non-divine rotting. (Zin is special.) + ROT_RESIST_FULL, // Immune to all forms of rot. +}; + struct bolt; class actor @@ -119,7 +124,7 @@ bool calc_unid = true) const = 0; virtual int scan_artefacts(artefact_prop_type which_property, bool calc_unid = true, - vector *matches = nullptr) const = 0; + vector *matches = nullptr) const = 0; virtual hands_reqd_type hands_reqd(const item_def &item, bool base = false) const; @@ -139,14 +144,14 @@ bool ignore_transform = false, bool quiet = true) const = 0; - virtual void make_hungry(int nutrition, bool silent = true) + virtual void make_hungry(int /*nutrition*/, bool /*silent*/ = true) { } - virtual void lose_energy(energy_use_type, int div = 1, int mult = 1) + virtual void lose_energy(energy_use_type, int /*div*/ = 1, int /*mult*/ = 1) { } - virtual void gain_energy(energy_use_type, int div = 1, int mult = 1) + virtual void gain_energy(energy_use_type, int /*div*/ = 1, int /*mult*/ = 1) { } @@ -162,7 +167,7 @@ virtual bool fumbles_attack() = 0; - virtual bool fights_well_unarmed(int heavy_armour_penalty) + virtual bool fights_well_unarmed(int /*heavy_armour_penalty*/) { return true; } @@ -227,7 +232,7 @@ virtual void weaken(actor *attacker, int pow) = 0; virtual void expose_to_element(beam_type element, int strength = 0, bool slow_cold_blood = true) = 0; - virtual void drain_stat(stat_type stat, int amount) { } + virtual void drain_stat(stat_type /*stat*/, int /*amount*/) { } virtual void splash_with_acid(const actor* evildoer, int acid_strength = -1, bool allow_corrosion = true, const char* hurt_msg = nullptr) = 0; @@ -270,8 +275,10 @@ virtual int shield_block_penalty() const = 0; virtual int shield_bypass_ability(int tohit) const = 0; virtual void shield_block_succeeded(actor *foe); - virtual int missile_deflection() const = 0; // 1 = RMsl, 2 = DMsl - virtual void ablate_deflection() = 0; + virtual bool missile_repulsion() const = 0; + virtual void ablate_repulsion() + { + } // Combat-related virtual class methods virtual int unadjusted_body_armour_penalty() const = 0; @@ -298,7 +305,7 @@ virtual int res_cold() const = 0; virtual int res_elec() const = 0; virtual int res_poison(bool temp = true) const = 0; - virtual int res_rotting(bool temp = true) const = 0; + virtual rot_resistance res_rotting(bool temp = true) const = 0; virtual int res_water_drowning() const = 0; virtual bool res_sticky_flame() const = 0; virtual int res_holy_energy() const = 0; @@ -314,11 +321,11 @@ virtual int inaccuracy() const; virtual bool antimagic_susceptible() const = 0; - virtual bool gourmand(bool calc_unid = true, bool items = true) const; + virtual bool gourmand(bool, bool) const { return false; } virtual bool res_corr(bool calc_unid = true, bool items = true) const; bool has_notele_item(bool calc_unid = true, - vector *matches = nullptr) const; + vector *matches = nullptr) const; virtual bool stasis() const = 0; virtual bool cloud_immune(bool calc_unid = true, bool items = true) const; virtual bool run(bool calc_unid = true, bool items = true) const; @@ -339,16 +346,10 @@ virtual int evokable_flight(bool calc_unid = true) const; virtual int spirit_shield(bool calc_unid = true, bool items = true) const; - virtual bool is_wall_clinging() const; virtual bool is_banished() const = 0; - virtual bool can_cling_to_walls() const = 0; - virtual bool can_cling_to(const coord_def& p) const; - virtual bool check_clinging(bool stepped, bool door = false); - virtual void clear_clinging(); virtual bool is_web_immune() const = 0; virtual bool airborne() const = 0; virtual bool ground_level() const; - virtual bool stand_on_solid_ground() const; virtual bool paralysed() const = 0; virtual bool cannot_move() const = 0; @@ -382,7 +383,7 @@ virtual bool handle_trap(); - virtual void god_conduct(conduct_type thing_done, int level) { } + virtual void god_conduct(conduct_type /*thing_done*/, int /*level*/) { } virtual bool incapacitated() const { @@ -400,7 +401,7 @@ virtual bool has_spell(spell_type spell) const = 0; virtual bool will_trigger_shaft() const; - virtual level_id shaft_dest(bool known) const; + virtual level_id shaft_dest() const; virtual bool do_shaft() = 0; coord_def position; Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/._actor-los.cc and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/._actor-los.cc differ diff -Nru crawl-0.24.0/source/android-project/jni/src/Android.mk crawl-0.25.0/source/android-project/jni/src/Android.mk --- crawl-0.24.0/source/android-project/jni/src/Android.mk 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/source/android-project/jni/src/Android.mk 2020-05-23 16:07:19.000000000 +0000 @@ -34,6 +34,7 @@ $(CRAWL_PATH)/behold.cc \ $(CRAWL_PATH)/bitary.cc \ $(CRAWL_PATH)/branch.cc \ + $(CRAWL_PATH)/branch-data-json.cc \ $(CRAWL_PATH)/butcher.cc \ $(CRAWL_PATH)/bloodspatter.cc \ $(CRAWL_PATH)/chardump.cc \ Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/._AppHdr.cc and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/._AppHdr.cc differ Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/._AppHdr.h and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/._AppHdr.h differ diff -Nru crawl-0.24.0/source/AppHdr.h crawl-0.25.0/source/AppHdr.h --- crawl-0.24.0/source/AppHdr.h 2018-05-16 18:10:55.000000000 +0000 +++ crawl-0.25.0/source/AppHdr.h 2020-05-05 21:43:24.000000000 +0000 @@ -191,6 +191,13 @@ # define IMMUTABLE #endif +// /usr/bin is not writable on OSX 10.11+ due to System Integrity Protection +#ifdef TARGET_OS_MACOSX +# define GDB_PATH "/usr/local/bin/gdb" +#else +# define GDB_PATH "/usr/bin/gdb" +#endif + // ========================================================================= // Defines for dgamelaunch-specific things. @@ -403,6 +410,11 @@ { } +template +static inline void UNUSED(const volatile T &...) +{ +} + #endif // __cplusplus Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/._areas.cc and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/._areas.cc differ diff -Nru crawl-0.24.0/source/areas.cc crawl-0.25.0/source/areas.cc --- crawl-0.24.0/source/areas.cc 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/areas.cc 2020-05-23 16:07:19.000000000 +0000 @@ -15,6 +15,7 @@ #include "coordit.h" #include "env.h" #include "fprop.h" +#include "god-abil.h" #include "god-conduct.h" #include "god-passive.h" // passive_t::umbra #include "libutil.h" @@ -79,6 +80,7 @@ void areas_actor_moved(const actor* act, const coord_def& oldpos) { + UNUSED(oldpos); if (act->alive() && (you.entering_level || act->halo_radius() > -1 || act->silence_radius() > -1 @@ -278,12 +280,25 @@ env.pgrid(where) &= ~(FPROP_SANCTUARY_1 | FPROP_SANCTUARY_2); } +bool sanctuary_exists() +{ + return in_bounds(env.sanctuary_pos); +} + +/* + * Remove any sanctuary from the level. + * + * @param did_attack If true, the sanctuary removal was the result of a player + * attack, so we apply penance. Otherwise the sanctuary is + * removed with no penance. + * @returns True if we removed an existing sanctuary, false otherwise. + */ bool remove_sanctuary(bool did_attack) { if (env.sanctuary_time) env.sanctuary_time = 0; - if (!in_bounds(env.sanctuary_pos)) + if (!sanctuary_exists()) return false; const int radius = 4; @@ -456,14 +471,12 @@ mpr("The monsters scatter in all directions!"); } -///////////// -// Silence - -// radius, calculated from remaining duration +// Range calculation for spells whose radius shrinks over time with remaining +// duration. // dur starts at 10 (low power) and is capped at 100 // maximal range: 5 -// last 6 turns: range 0, hence only the player silenced -static int _silence_range(int dur) +// last 6 turns: range 0, hence only the player affected +static int _shrinking_aoe_range(int dur) { if (dur <= 0) return -1; @@ -471,9 +484,12 @@ return isqrt(max(0, min(3*(dur - 5)/4, 25))); } +///////////// +// Silence + int player::silence_radius() const { - return _silence_range(duration[DUR_SILENCE]); + return _shrinking_aoe_range(duration[DUR_SILENCE]); } int monster::silence_radius() const @@ -488,7 +504,7 @@ // The below is arbitrarily chosen to make monster decay look reasonable. const int moddur = BASELINE_DELAY * max(7, stepdown_value(dur * 10 - 60, 10, 5, 45, 100)); - return _silence_range(moddur); + return _shrinking_aoe_range(moddur); } bool silenced(const coord_def& p) @@ -530,8 +546,8 @@ if (player_equip_unrand(UNRAND_EOS)) size = max(size, 3); - else if (you.attribute[ATTR_HEAVENLY_STORM] > 0) - size = max(size, 1); + else if (you.props.exists(WU_JIAN_HEAVENLY_STORM_KEY)) + size = max(size, 2); return size; } @@ -582,7 +598,7 @@ int player::liquefying_radius() const { - return _silence_range(duration[DUR_LIQUEFYING]); + return _shrinking_aoe_range(duration[DUR_LIQUEFYING]); } int monster::liquefying_radius() const @@ -593,7 +609,7 @@ // The below is arbitrarily chosen to make monster decay look reasonable. const int moddur = BASELINE_DELAY * max(7, stepdown_value(dur * 10 - 60, 10, 5, 45, 100)); - return _silence_range(moddur); + return _shrinking_aoe_range(moddur); } bool liquefied(const coord_def& p, bool check_actual) @@ -604,7 +620,7 @@ if (!_agrid_valid) _update_agrid(); - if (feat_is_water(grd(p))) + if (feat_is_water(grd(p)) || feat_is_lava(grd(p))) return false; // "actually" liquefied (ie, check for movement) diff -Nru crawl-0.24.0/source/areas.h crawl-0.25.0/source/areas.h --- crawl-0.24.0/source/areas.h 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/areas.h 2020-05-05 21:43:24.000000000 +0000 @@ -24,6 +24,7 @@ void create_sanctuary(const coord_def& center, int time); bool remove_sanctuary(bool did_attack = false); void decrease_sanctuary_radius(); +bool sanctuary_exists(); coord_def find_centre_for(const coord_def& f, area_centre_type at = area_centre_type::none); diff -Nru crawl-0.24.0/source/arena.cc crawl-0.25.0/source/arena.cc --- crawl-0.24.0/source/arena.cc 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/arena.cc 2020-05-23 16:07:19.000000000 +0000 @@ -25,7 +25,6 @@ #include "maps.h" #include "menu.h" #include "message.h" -#include "misc.h" #include "mgen-data.h" #include "mon-death.h" #include "mon-pick.h" @@ -141,14 +140,11 @@ auto prompt_ui = make_shared( formatted_string::parse_string(msg)); bool done = false; - prompt_ui->on(Widget::slots.event, [&](wm_event ev) { - if (ev.type == WME_KEYDOWN) - { - if (ev.key.keysym.sym == CONTROL('P')) - replay_messages(); - else - done = true; - } + prompt_ui->on_hotkey_event([&](const KeyEvent& ev) { + if (ev.key() == CONTROL('P')) + replay_messages(); + else + done = true; return done; }); @@ -616,6 +612,12 @@ for (int i = 0; i < NUM_STATS; ++i) you.base_stats[i] = 20; + // XXX: now that you.species is valid, do a layout. + // This is necessary to ensure that the stat window is positioned. +#ifdef USE_TILE + tiles.resize(); +#endif + show_fight_banner(); } @@ -744,9 +746,12 @@ if (mon->type == MONS_TEST_SPAWNER) continue; - MiscastEffect(*mon, *mon, {miscast_source::wizard}, - spschool::random, random_range(1, 3), "arena miscast", - nothing_happens::NEVER); + if (!mon->alive()) + continue; + + miscast_effect(**mon, *mon, {miscast_source::wizard}, + spschool::random, random_range(1, 9), + random_range(1, 100), "arena miscast"); } } @@ -1047,10 +1052,10 @@ viewwindow(); display_message_window(); }; - virtual bool on_event(const wm_event& ev) override { - if (ev.type != WME_KEYDOWN) + virtual bool on_event(const Event& ev) override { + if (ev.type() != Event::Type::KeyDown) return false; - handle_keypress(ev.key.keysym.sym); + handle_keypress(static_cast(ev).key()); ASSERT(crawl_state.game_is_arena()); ASSERT(!crawl_state.arena_suspended); return true; @@ -1151,6 +1156,8 @@ bool arena_veto_place_monster(const mgen_data &mg, bool first_band_member, const coord_def& pos) { + UNUSED(pos); + // If the first band member makes it past the summon throttle cut, // let all of the rest of its band in too regardless of the summon // throttle. @@ -1477,47 +1484,31 @@ arena::skipped_arena_ui = false; clear_message_store(); - char buf[80]; - resumable_line_reader reader(buf, sizeof(buf)); - bool done = false; - bool cancel = false; - auto prompt_ui = make_shared(); - auto popup = make_shared(prompt_ui); - - popup->on(Widget::slots.event, [&](wm_event ev) { - if (ev.type != WME_KEYDOWN) - return false; - const int key = reader.putkey(ev.key.keysym.sym); - if (key == -1) - return true; - cancel = !!key; - return done = true; + auto vbox = make_shared(ui::Widget::VERT); + vbox->add_child(make_shared("Enter your choice of teams:\n ")); + vbox->set_cross_alignment(Widget::Align::STRETCH); + auto teams_input = make_shared(); + teams_input->set_sync_id("teams"); + teams_input->set_text(default_arena_teams); + vbox->add_child(teams_input); + formatted_string prompt; + prompt.cprintf("\nExamples:\n"); + prompt.cprintf(" Sigmund v Jessica\n"); + prompt.cprintf(" 99 orc v the Royal Jelly\n"); + prompt.cprintf(" 20-headed hydra v 10 kobold ; scimitar ego:flaming"); + vbox->add_child(make_shared(move(prompt))); + + auto popup = make_shared(move(vbox)); + + bool done = false, cancel = false; + popup->on_hotkey_event([&](const KeyEvent& ev) { + return done = (ev.key() == CK_ENTER); + }); + popup->on_keydown_event([&](const KeyEvent& ev) { + return done = cancel = key_is_escape(ev.key()); }); - ui::push_layout(move(popup)); - while (!done && !crawl_state.seen_hups) - { - string hlbuf = formatted_string(buf).to_colour_string(); - if (hlbuf.find(" v ") != string::npos) - hlbuf = "" + replace_all(hlbuf, " v ", " v ") + ""; - - formatted_string prompt; - prompt.cprintf("Enter your choice of teams:\n\n "); - prompt += formatted_string::parse_string(hlbuf); - - prompt.cprintf("\n\n"); - if (!default_arena_teams.empty()) - prompt.cprintf("Enter - %s\n", default_arena_teams.c_str()); - prompt.cprintf("\n"); - prompt.cprintf("Examples:\n"); - prompt.cprintf(" Sigmund v Jessica\n"); - prompt.cprintf(" 99 orc v the Royal Jelly\n"); - prompt.cprintf(" 20-headed hydra v 10 kobold ; scimitar ego:flaming"); - prompt_ui->set_text(prompt); - - ui::pump_events(); - } - ui::pop_layout(); + ui::run_layout(move(popup), done, teams_input); if (cancel || crawl_state.seen_hups) { @@ -1525,7 +1516,7 @@ game_ended(crawl_state.bypassed_startup_menu ? game_exit::death : game_exit::abort); } - choice.arena_teams = buf; + choice.arena_teams = teams_input->get_text(); if (choice.arena_teams.empty()) choice.arena_teams = default_arena_teams; } Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/._art-data.txt and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/._art-data.txt differ diff -Nru crawl-0.24.0/source/art-data.txt crawl-0.25.0/source/art-data.txt --- crawl-0.24.0/source/art-data.txt 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/art-data.txt 2020-05-23 16:07:19.000000000 +0000 @@ -93,8 +93,6 @@ # * notelep: Prevents wearer from teleporting or blinking. # * poison: Grants poison resistance. # * rcorr: Grants corrosion resistance. -# * randapp: Generated with a random artefact's appearance (used by -# strictly-bad unrands). # * rmsl: Passively repels missiles. # * rmut: Grants mutation resistance. # * rnd_tele: Induces random teleportation. @@ -149,7 +147,8 @@ # MAGIC: Magic resistance/vulnerability. # MP: Mana capacity modifier. # NAME: Name of artefact when identified. -# REGEN: Provides regeneration (1 = amulet of regen, 2.5 = the spell). +# REGEN: Health regeneration, in units of HP healed every 25 aut +# (2.5 normal turns). # STEALTH: Stealth modifier. # STR: Strength modifier. # TILE: The file containing the artefact's tile, with file type png. @@ -224,13 +223,13 @@ BOOL: special, no_upgrade NAME: staff of Olgreb +INSCRIP: rPois∞ OBJ: OBJ_WEAPONS/WPN_STAFF PLUS: +9 COLOUR: ETC_POISON TILE: spwpn_staff_of_olgreb TILE_EQ: olgreb VALUE: 1000 -BOOL: poison NAME: staff of Wucad Mu INSCRIP: channel @@ -271,7 +270,7 @@ TILE_EQ: sceptre_of_torment BRAND: SPWPN_PAIN VALUE: 1200 -BOOL: special, evil +BOOL: evil NAME: sword of Zonguldrok OBJ: OBJ_WEAPONS/WPN_DOUBLE_SWORD @@ -326,6 +325,7 @@ TILE_EQ: faerie_dragon_armour BOOL: nogen, no_upgrade +# start TAG_MAJOR_VERSION == 34 NAME: demon blade "Bloodbane" OBJ: OBJ_WEAPONS/WPN_DEMON_BLADE PLUS: +8 @@ -334,10 +334,11 @@ TILE_EQ: bloodbane BRAND: SPWPN_VORPAL ANGRY: 5 -BOOL: berserk +BOOL: berserk, nogen STEALTH: -1 +# end TAG_MAJOR_VERSION -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 NAME: scimitar of Flaming Death OBJ: OBJ_WEAPONS/WPN_SCIMITAR INSCRIP: sticky flame, @@ -350,8 +351,9 @@ COLD: -1 BOOL: poison, skip_ego, nogen MAGIC: 1 +# end TAG_MAJOR_VERSION -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 NAME: eveningstar "Brilliance" OBJ: OBJ_WEAPONS/WPN_EVENINGSTAR PLUS: +1 @@ -363,6 +365,7 @@ INT: 5 LIFE: 1 BOOL: nogen +# end TAG_MAJOR_VERSION NAME: demon blade "Leech" OBJ: OBJ_WEAPONS/WPN_DEMON_BLADE @@ -371,11 +374,11 @@ TILE: urand_leech TILE_EQ: leech BRAND: SPWPN_VAMPIRISM -AC: -3 -EV: -3 -LIFE: 1 +LIFE: 1 +ANGRY: 5 +BOOL: berserk -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 NAME: dagger of Chilly Death OBJ: OBJ_WEAPONS/WPN_DAGGER INSCRIP: flash freeze, @@ -388,6 +391,7 @@ COLD: 2 MAGIC: 1 BOOL: poison, skip_ego, nogen +# end TAG_MAJOR_VERSION NAME: dagger "Morg" OBJ: OBJ_WEAPONS/WPN_DAGGER @@ -474,7 +478,7 @@ VALUE: 800 BOOL: evil -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 NAME: sword of the Doom Knight OBJ: OBJ_WEAPONS/WPN_GREAT_SWORD PLUS: +13 @@ -484,6 +488,7 @@ BRAND: SPWPN_PAIN MAGIC: 1 BOOL: nospell, nogen +# end TAG_MAJOR_VERSION NAME: morningstar "Eos" OBJ: OBJ_WEAPONS/WPN_MORNINGSTAR @@ -495,7 +500,7 @@ BRAND: SPWPN_ELECTROCUTION BOOL: elec -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 # Was "spear of Voo-Doo". In the African origin, there is a distinction # between voodoo and bo, the latter dealing with curses, witchcraft and # spells designed to do harm. Priests (or rather sorcerers) of bo are @@ -512,6 +517,7 @@ HP: -6 LIFE: 1 BOOL: poison, nogen +# end TAG_MAJOR_VERSION NAME: trident of the Octopus King OBJ: OBJ_WEAPONS/WPN_TRIDENT @@ -558,7 +564,7 @@ BOOL: seeinv INSCRIP: Acc+∞ -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 NAME: longbow "Piercer" OBJ: OBJ_WEAPONS/WPN_LONGBOW PLUS: +7 @@ -568,8 +574,9 @@ BRAND: SPWPN_PENETRATION EV: -2 BOOL: nogen +# end TAG_MAJOR_VERSION -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 ENUM: BLOWGUN_ASSASSIN NAME: blowgun of the Assassin INSCRIP: stab, @@ -582,6 +589,7 @@ TILE_EQ: blowgun STEALTH: 2 BOOL: inv, tilerim, nogen +# end TAG_MAJOR_VERSION NAME: lance "Wyrmbane" OBJ: OBJ_WEAPONS/WPN_SPEAR @@ -642,7 +650,7 @@ BRAND: SPWPN_VENOM BOOL: poison, skip_ego -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 NAME: knife of Accuracy OBJ: OBJ_WEAPONS/WPN_DAGGER TYPE: knife @@ -651,8 +659,9 @@ TILE: urand_knife_of_accuracy TILE_EQ: knife_of_accuracy BOOL: tilerim, nogen +# end TAG_MAJOR_VERSION -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 # A play on the spell of the same name. Colour taken from crystal walls. ENUM: CRYSTAL_SPEAR NAME: Lehudib's crystal spear @@ -663,6 +672,7 @@ TILE_EQ: crystal_spear INT: 3 BOOL: nogen +# end TAG_MAJOR_VERSION ENUM: CAPTAIN NAME: captain's cutlass @@ -684,12 +694,12 @@ BRAND: SPWPN_ELECTROCUTION INSCRIP: penet -NAME: large shield of Ignorance -OBJ: OBJ_ARMOUR/ARM_LARGE_SHIELD +NAME: tower shield of Ignorance +OBJ: OBJ_ARMOUR/ARM_TOWER_SHIELD PLUS: +10 COLOUR: BROWN TILE: urand_ignorance -TILE_EQ: lshield_of_ignorance +TILE_EQ: tower_shield_of_ignorance INT: -4 LIFE: 1 @@ -715,15 +725,16 @@ STEALTH: 1 BOOL: seeinv, fog -# TAG_MAJOR_VERSION == 34 -NAME: large shield "Bullseye" -OBJ: OBJ_ARMOUR/ARM_LARGE_SHIELD +# start TAG_MAJOR_VERSION == 34 +NAME: tower shield "Bullseye" +OBJ: OBJ_ARMOUR/ARM_TOWER_SHIELD PLUS: +15 COLOUR: RED TILE: urand_bullseye -TILE_EQ: shield_bullseye +TILE_EQ: kite_shield_bullseye EV: -5 BOOL: nogen +# end TAG_MAJOR_VERSION NAME: crown of Dyrovepreva OBJ: OBJ_ARMOUR/ARM_HAT @@ -758,7 +769,7 @@ EV: 5 BOOL: harm, mutate, drain, slow, corrode -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 NAME: cloak of Flash OBJ: OBJ_ARMOUR/ARM_CLOAK PLUS: +3 @@ -767,16 +778,17 @@ TILE_EQ: red EV: 4 BOOL: fly, nogen +# end TAG_MAJOR_VERSION -ENUM: BOOTS_ASSASSIN -NAME: boots of the Assassin -OBJ: OBJ_ARMOUR/ARM_BOOTS -FB_BRAND: SPARM_STEALTH +ENUM: HOOD_ASSASSIN +NAME: hood of the Assassin +OBJ: OBJ_ARMOUR/ARM_HAT +FB_BRAND: SPARM_SEE_INVISIBLE INSCRIP: Detection Stab+ PLUS: +2 COLOUR: BROWN -TILE: urand_assassin -TILE_EQ: middle_gray +TILE: urand_hood_assassin +TILE_EQ: hood_purple STEALTH: 2 VALUE: 600 @@ -801,7 +813,7 @@ TILE_EQ: zhor COLD: 3 BOOL: seeinv -INSCRIP: Hibernate +INSCRIP: Englaciate ENUM: SALAMANDER NAME: salamander hide armour @@ -823,11 +835,11 @@ SLAY: 5 NAME: shield of Resistance -OBJ: OBJ_ARMOUR/ARM_SHIELD +OBJ: OBJ_ARMOUR/ARM_KITE_SHIELD PLUS: +2 COLOUR: LIGHTRED TILE: urand_resistance -TILE_EQ: shield_of_resistance +TILE_EQ: kite_shield_of_resistance FIRE: 1 COLD: 1 MAGIC: 1 @@ -930,12 +942,12 @@ BOOL: poison NAME: shield of the Gong -OBJ: OBJ_ARMOUR/ARM_SHIELD -FALLBACK: OBJ_ARMOUR/ARM_LARGE_SHIELD +OBJ: OBJ_ARMOUR/ARM_KITE_SHIELD +FALLBACK: OBJ_ARMOUR/ARM_TOWER_SHIELD PLUS: +18 COLOUR: ETC_GOLD TILE: urand_gong -TILE_EQ: shield_gong +TILE_EQ: kite_shield_gong EV: -5 MAGIC: 1 LIFE: 1 @@ -956,7 +968,7 @@ BOOL: inv VALUE: 400 -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 NAME: amulet of Cekugob OBJ: OBJ_JEWELLERY/AMU_ACROBAT COLOUR: ETC_SILVER @@ -965,6 +977,7 @@ EV: 1 LIFE: 2 BOOL: elec, poison, notelep, nogen +# end TAG_MAJOR_VERSION NAME: amulet of the Four Winds OBJ: OBJ_JEWELLERY/AMU_NOTHING @@ -975,14 +988,14 @@ BOOL: clarity NAME: necklace of Bloodlust -OBJ: OBJ_JEWELLERY/AMU_RAGE +OBJ: OBJ_JEWELLERY/AMU_NOTHING COLOUR: ETC_BLOOD TILE: urand_bloodlust INT: -3 MAGIC: 2 ANGRY: 5 SLAY: 6 -BOOL: curse +BOOL: curse, berserk NAME: ring of Phasing OBJ: OBJ_JEWELLERY/RING_EVASION @@ -1004,10 +1017,10 @@ MAGIC: 2 NAME: brooch of Shielding -OBJ: OBJ_JEWELLERY/AMU_REFLECTION +OBJ: OBJ_JEWELLERY/AMU_GUARDIAN_SPIRIT COLOUR: ETC_MAGIC TILE: urand_brooch_of_shielding -PLUS: +8 +SH: +8 ENUM: RCLOUDS NAME: robe of Clouds @@ -1148,7 +1161,7 @@ LIFE: 1 VALUE: 400 -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 ENUM: SPIDER NAME: boots of the spider OBJ: OBJ_ARMOUR/ARM_BOOTS @@ -1159,6 +1172,7 @@ COLOUR: LIGHTMAGENTA STEALTH: 1 BOOL: nogen +# end TAG_MAJOR_VERSION NAME: dark maul OBJ: OBJ_WEAPONS/WPN_GREAT_MACE @@ -1172,7 +1186,7 @@ BASE_DELAY: +13 BRAND: SPWPN_VORPAL -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 ENUM: HIGH_COUNCIL NAME: hat of the High Council INSCRIP: Wiz- @@ -1184,6 +1198,7 @@ BRAND: SPARM_ARCHMAGI STEALTH: -1 BOOL: nogen +# end TAG_MAJOR_VERSION NAME: arc blade INSCRIP: discharge, @@ -1265,6 +1280,7 @@ BRAND: SPWPN_PROTECTION FB_BRAND: SPWPN_VORPAL +# start TAG_MAJOR_VERSION == 34 ENUM: ETHERIC_CAGE NAME: Maxwell's etheric cage OBJ: OBJ_ARMOUR/ARM_HELMET @@ -1274,10 +1290,11 @@ INSCRIP: RegenMP+ PLUS: +0 MP: +4 -BOOL: mutate, elec, chaotic +BOOL: mutate, elec, chaotic, nogen VALUE: 400 +# end TAG_MAJOR_VERSION -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 ENUM: ETERNAL_TORMENT NAME: crown of Eternal Torment OBJ: OBJ_ARMOUR/ARM_HAT @@ -1288,6 +1305,7 @@ INSCRIP: rTorment HP-- LIFE: 3 BOOL: evil, seeinv, nogen, curse +# end TAG_MAJOR_VERSION ENUM: VINES NAME: robe of Vines @@ -1323,7 +1341,7 @@ COLD: 1 BOOL: skip_ego, fly, noises -# TAG_MAJOR_VERSION == 34 +# start TAG_MAJOR_VERSION == 34 ENUM: TALOS NAME: armour of Talos OBJ: OBJ_ARMOUR/ARM_PLATE_ARMOUR @@ -1334,6 +1352,7 @@ BRAND: SPARM_PONDEROUSNESS FIRE: 1 BOOL: nogen +# end TAG_MAJOR_VERSION ENUM: WARLOCK_MIRROR NAME: warlock's mirror @@ -1381,6 +1400,18 @@ TILE_EQ: battle_staff VALUE: 800 +ENUM: EMBRACE +NAME: Cigotuvi's embrace +OBJ: OBJ_ARMOUR/ARM_LEATHER_ARMOUR +PLUS: +4 # varies with corpse count +COLOUR: ETC_UNHOLY +TILE: urand_cigotuvi +TILE_EQ: bplate_green +# XXX TODO: tiles +LIFE: 1 +INSCRIP: rRot +BOOL: drain, evil, special, no_upgrade + # This entry must always be last. ENUM: DUMMY2 NAME: DUMMY UNRANDART 2 diff -Nru crawl-0.24.0/source/artefact.cc crawl-0.25.0/source/artefact.cc --- crawl-0.24.0/source/artefact.cc 2019-09-15 23:48:09.000000000 +0000 +++ crawl-0.25.0/source/artefact.cc 2020-06-14 18:57:04.000000000 +0000 @@ -15,10 +15,8 @@ #include #include -#include "areas.h" #include "branch.h" #include "colour.h" -#include "coordit.h" #include "database.h" #include "god-item.h" #include "item-name.h" @@ -132,21 +130,18 @@ break; case GOD_TROG: - // Anti-magic god: no spell use, no enhancing magic. - if (brand == SPWPN_PAIN) // Pain involves necromantic spell use. + // Limited selection of brands. + if (brand != SPWPN_VORPAL + && brand != SPWPN_FLAMING + && brand != SPWPN_ANTIMAGIC) + { return false; + } if (artefact_property(item, ARTP_MAGICAL_POWER) > 0) return false; break; - case GOD_FEDHAS: - // Fedhas forbids necromancy involving corpses, only reaping - // really applies. - if (brand == SPWPN_REAPING) - return false; - break; - case GOD_CHEIBRIADOS: // Slow god: no speed, no berserking. if (brand == SPWPN_SPEED) @@ -291,19 +286,12 @@ && (_seekunrandart(item)->flags & UNRAND_FLAG_SPECIAL); } -bool is_randapp_artefact(const item_def &item) -{ - return item.flags & ISFLAG_UNRANDART - && !(item.flags & ISFLAG_KNOW_TYPE) - && (_seekunrandart(item)->flags & UNRAND_FLAG_RANDAPP); -} - void autoid_unrand(item_def &item) { if (!(item.flags & ISFLAG_UNRANDART) || item.flags & ISFLAG_KNOW_TYPE) return; const uint16_t uflags = _seekunrandart(item)->flags; - if (uflags & UNRAND_FLAG_RANDAPP || uflags & UNRAND_FLAG_UNIDED) + if (uflags & UNRAND_FLAG_UNIDED) return; set_ident_flags(item, ISFLAG_IDENT_MASK | ISFLAG_NOTED_ID); @@ -315,9 +303,22 @@ return you.unique_items[art - UNRAND_START]; } -static void _set_unique_item_status(int art, unique_item_status_type status) +static void _set_unique_item_status(int art, bool exists) { ASSERT_RANGE(art, UNRAND_START + 1, UNRAND_LAST); + + const unique_item_status_type status = !exists + ? UNIQ_NOT_EXISTS + : !crawl_state.generating_level + // treat unrands that generate in these branches as if they + // were acquired. TODO: there's a potential bug here if every + // octopus king ring generates and the last is acquired. Also, + // I suspect that these getting lost in the abyss isn't handled + // right + || level_id::current().branch == BRANCH_TROVE + || level_id::current().branch == BRANCH_ABYSS + ? UNIQ_EXISTS_NONLEVELGEN + : UNIQ_EXISTS; you.unique_items[art - UNRAND_START] = status; } @@ -358,10 +359,8 @@ }; static map> jewellery_artps = { - { AMU_RAGE, { { ARTP_BERSERK, 1 } } }, { AMU_REGENERATION, { { ARTP_REGENERATION, 1 } } }, - { AMU_REFLECTION, { { ARTP_SHIELDING, 0 } } }, - { AMU_HARM, { { ARTP_DRAIN, 1 } } }, + { AMU_REFLECTION, { { ARTP_SHIELDING, AMU_REFLECT_SH / 2} } }, { RING_MAGICAL_POWER, { { ARTP_MAGICAL_POWER, 9 } } }, { RING_FLIGHT, { { ARTP_FLY, 1 } } }, @@ -449,7 +448,8 @@ return; // actual artefact properties - artefact_properties(item, proprt, known); + artefact_properties(item, proprt); + artefact_known_properties(item, known); // fake artefact properties (intrinsics) _populate_item_intrinsic_artps(item, proprt, known); @@ -572,8 +572,9 @@ // and obv we shouldn't generate contradictory props case ARTP_PREVENT_TELEPORTATION: return !extant_props[ARTP_BLINK] - && !extant_props[ARTP_CAUSE_TELEPORTATION]; - // no contradictory props + && !extant_props[ARTP_CAUSE_TELEPORTATION] + && item_class == OBJ_ARMOUR; + // armour only, and no contradictory props case ARTP_BLINK: return !extant_props[ARTP_PREVENT_TELEPORTATION]; // no contradictory props @@ -587,8 +588,8 @@ && (item_class != OBJ_JEWELLERY || jewellery_is_amulet(item)); case ARTP_HARM: - return item_class != OBJ_JEWELLERY && extant_props[ARTP_DRAIN]; - // only get harm with *Drain + return item_class == OBJ_ARMOUR; + // only get harm on delay equipment default: return true; } @@ -726,7 +727,7 @@ { "Fragile", ARTP_VAL_BOOL, 25, // ARTP_FRAGILE, nullptr, []() { return 1; }, 0, 0 }, { "SH", ARTP_VAL_ANY, 0, nullptr, nullptr, 0, 0 }, // ARTP_SHIELDING, - { "Harm", ARTP_VAL_BOOL, 0, // ARTP_HARM, + { "Harm", ARTP_VAL_BOOL, 25, // ARTP_HARM, []() {return 1;}, nullptr, 0, 0}, }; COMPILE_CHECK(ARRAYSZ(artp_data) == ARTP_NUM_PROPERTIES); @@ -983,12 +984,11 @@ return true; } -void artefact_properties(const item_def &item, - artefact_properties_t &proprt, - artefact_known_props_t &known) +void artefact_known_properties(const item_def &item, + artefact_known_props_t &known) { ASSERT(is_artefact(item)); - if (!item.props.exists(KNOWN_PROPS_KEY)) + if (!item.props.exists(KNOWN_PROPS_KEY)) // randbooks return; const CrawlStoreValue &_val = item.props[KNOWN_PROPS_KEY]; @@ -1008,6 +1008,13 @@ for (vec_size i = 0; i < ART_PROPERTIES; i++) known[i] = known_vec[i]; } +} + +void artefact_properties(const item_def &item, + artefact_properties_t &proprt) +{ + ASSERT(is_artefact(item)); + ASSERT(item.props.exists(ARTEFACT_PROPS_KEY) || is_unrandom_artefact(item)); if (item.props.exists(ARTEFACT_PROPS_KEY)) { @@ -1020,60 +1027,60 @@ for (vec_size i = 0; i < ART_PROPERTIES; i++) proprt[i] = rap_vec[i].get_short(); } - else if (is_unrandom_artefact(item)) + else // if (is_unrandom_artefact(item)) { const unrandart_entry *unrand = _seekunrandart(item); for (int i = 0; i < ART_PROPERTIES; i++) proprt[i] = static_cast(unrand->prpty[i]); } - else - _get_randart_properties(item, proprt); } -void artefact_properties(const item_def &item, - artefact_properties_t &proprt) +int artefact_property(const item_def &item, artefact_prop_type prop) { - artefact_known_props_t known; + ASSERT(is_artefact(item)); + ASSERT(item.props.exists(ARTEFACT_PROPS_KEY) || is_unrandom_artefact(item)); + + if (item.props.exists(ARTEFACT_PROPS_KEY)) + { + const CrawlVector &rap_vec = + item.props[ARTEFACT_PROPS_KEY].get_vector(); + return rap_vec[prop].get_short(); + } + else // if (is_unrandom_artefact(item)) + { + const unrandart_entry *unrand = _seekunrandart(item); + return static_cast(unrand->prpty[prop]); - artefact_properties(item, proprt, known); + } } -int artefact_property(const item_def &item, artefact_prop_type prop, - bool &_known) +/** + * Check whether a particular property's value is known to the player. + */ +bool artefact_property_known(const item_def &item, artefact_prop_type prop) { - artefact_properties_t proprt; - artefact_known_props_t known; - proprt.init(0); - known.init(0); - - artefact_properties(item, proprt, known); - - _known = known[prop]; + ASSERT(is_artefact(item)); + if (item_ident(item, ISFLAG_KNOW_PROPERTIES)) + return true; - return proprt[prop]; -} + if (!item.props.exists(KNOWN_PROPS_KEY)) // randbooks + return false; -int artefact_property(const item_def &item, artefact_prop_type prop) -{ - bool known; + const CrawlVector &known_vec = item.props[KNOWN_PROPS_KEY].get_vector(); + ASSERT(known_vec.get_type() == SV_BOOL); + ASSERT(known_vec.size() == ART_PROPERTIES); - return artefact_property(item, prop, known); + return known_vec[prop].get_bool(); } +/** + * check what the player knows about an a particular property. + */ int artefact_known_property(const item_def &item, artefact_prop_type prop) { - artefact_properties_t proprt; - artefact_known_props_t known; - proprt.init(0); - known.init(0); - - artefact_properties(item, proprt, known); - - if (known[prop]) - return proprt[prop]; - else - return 0; + return artefact_property_known(item, prop) ? artefact_property(item, prop) + : 0; } static int _artefact_num_props(const artefact_properties_t &proprt) @@ -1174,8 +1181,7 @@ const unrandart_entry *unrand = _seekunrandart(item); if (!appearance) return unrand->name; - if (!(unrand->flags & UNRAND_FLAG_RANDAPP)) - return unrand->unid_name; + return unrand->unid_name; } string lookup; @@ -1335,8 +1341,11 @@ { int ret = -1; - // Pick randomly among not-yet-existing unrandarts with the proper - // base_type and sub_type. + // Pick randomly among unrandarts with the proper + // base_type and sub_type. This will rule out unrands that have already + // placed as part of levelgen, but may find unrands that have been acquired. + // because of this, the caller needs to properly set up a fallback randart + // in some cases: see makeitem.cc:_setup_fallback_randart. for (int i = 0, count = 0; i < NUM_UNRANDARTS; i++) { const int index = i + UNRAND_START; @@ -1350,7 +1359,11 @@ get_unique_item_status(index); if (in_abyss && status != UNIQ_LOST_IN_ABYSS - || !in_abyss && status != UNIQ_NOT_EXISTS) + || !in_abyss && status != UNIQ_NOT_EXISTS + // for acquired items, ignore them in the random calculations + // here and let fallback artefacts replace them. + // TODO: abyss? double check trove + && status != UNIQ_EXISTS_NONLEVELGEN) { continue; } @@ -1487,10 +1500,6 @@ provides = ARTP_RCORR; break; - case AMU_RAGE: - provides = ARTP_BERSERK; - break; - case AMU_INACCURACY: provides = ARTP_SLAYING; break; @@ -1502,10 +1511,6 @@ case AMU_REFLECTION: provides = ARTP_SHIELDING; break; - - case AMU_HARM: - provides = ARTP_DRAIN; - break; } if (provides == ARTP_NUM_PROPERTIES) @@ -1558,10 +1563,6 @@ #endif conflicts = ARTP_PREVENT_TELEPORTATION; break; - - case AMU_RAGE: - conflicts = ARTP_STEALTH; - break; } if (conflicts == ARTP_NUM_PROPERTIES) @@ -1752,12 +1753,14 @@ // If there are any types left, unset the 'already found' flag if (you.octopus_king_rings != 0xff) - _set_unique_item_status(UNRAND_OCTOPUS_KING_RING, UNIQ_NOT_EXISTS); + _set_unique_item_status(UNRAND_OCTOPUS_KING_RING, false); } bool make_item_unrandart(item_def &item, int unrand_index) { ASSERT_RANGE(unrand_index, UNRAND_START + 1, (UNRAND_START + NUM_UNRANDARTS)); + rng::subgenerator item_rng; // for safety's sake, this is sometimes called + // directly item.unrand_idx = unrand_index; @@ -1772,15 +1775,9 @@ // get artefact appearance ASSERT(!item.props.exists(ARTEFACT_APPEAR_KEY)); - if (!(unrand->flags & UNRAND_FLAG_RANDAPP)) - item.props[ARTEFACT_APPEAR_KEY].get_string() = unrand->unid_name; - else - { - item.props[ARTEFACT_APPEAR_KEY].get_string() = make_artefact_name(item, true); - item_colour(item); - } + item.props[ARTEFACT_APPEAR_KEY].get_string() = unrand->unid_name; - _set_unique_item_status(unrand_index, UNIQ_EXISTS); + _set_unique_item_status(unrand_index, true); if (unrand_index == UNRAND_FAERIE) _make_faerie_armour(item); @@ -1793,8 +1790,7 @@ item.sub_type = WPN_BROAD_AXE; } - if (!(unrand->flags & UNRAND_FLAG_RANDAPP) - && !(unrand->flags & UNRAND_FLAG_UNIDED) + if (!(unrand->flags & UNRAND_FLAG_UNIDED) && !strcmp(unrand->name, unrand->unid_name)) { set_ident_flags(item, ISFLAG_IDENT_MASK | ISFLAG_NOTED_ID); diff -Nru crawl-0.24.0/source/artefact.h crawl-0.25.0/source/artefact.h --- crawl-0.24.0/source/artefact.h 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/artefact.h 2020-05-23 16:07:19.000000000 +0000 @@ -16,6 +16,7 @@ #define ARTEFACT_APPEAR_KEY "artefact_appearance" #define DAMNATION_BOLT_KEY "damnation_bolt" +#define EMBRACE_ARMOUR_KEY "embrace_armour" struct bolt; @@ -30,7 +31,7 @@ UNRAND_FLAG_CHAOTIC = 0x20, // = 0x40, // was UNRAND_FLAG_CORPSE_VIOLATING UNRAND_FLAG_NOGEN = 0x80, - UNRAND_FLAG_RANDAPP =0x100, + // =0x100, // was UNRAND_FLAG_RANDAPP UNRAND_FLAG_UNIDED =0x200, UNRAND_FLAG_SKIP_EGO =0x400, // Please make sure it fits in unrandart_entry.flags (currently 16 bits). @@ -79,7 +80,6 @@ bool is_random_artefact(const item_def &item); bool is_unrandom_artefact(const item_def &item, int which = 0); bool is_special_unrandom_artefact(const item_def &item); -bool is_randapp_artefact(const item_def &item); void autoid_unrand(item_def &item); void artefact_fixup_props(item_def &item); @@ -102,22 +102,19 @@ typedef FixedVector< int, ART_PROPERTIES > artefact_properties_t; typedef FixedVector< bool, ART_PROPERTIES > artefact_known_props_t; -void artefact_desc_properties(const item_def &item, - artefact_properties_t &proprt, +void artefact_desc_properties(const item_def &item, + artefact_properties_t &proprt, artefact_known_props_t &known); -void artefact_properties(const item_def &item, - artefact_properties_t &proprt, - artefact_known_props_t &known); +void artefact_known_properties(const item_def &item, + artefact_known_props_t &known); void artefact_properties(const item_def &item, - artefact_properties_t &proprt); - -int artefact_property(const item_def &item, artefact_prop_type prop, - bool &known); + artefact_properties_t &proprt); int artefact_property(const item_def &item, artefact_prop_type prop); +bool artefact_property_known(const item_def &item, artefact_prop_type prop); int artefact_known_property(const item_def &item, artefact_prop_type prop); void artefact_learn_prop(item_def &item, artefact_prop_type prop); diff -Nru crawl-0.24.0/source/art-func.h crawl-0.25.0/source/art-func.h --- crawl-0.24.0/source/art-func.h 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/art-func.h 2020-05-23 16:07:19.000000000 +0000 @@ -20,25 +20,33 @@ #define ART_FUNC_H +#include "areas.h" // For silenced() and invalidate_agrid() +#include "attack.h" // For attack_strength_punctuation() #include "beam.h" // For Lajatang of Order's silver damage +#include "bloodspatter.h" // For Leech #include "cloud.h" // For storm bow's and robe of clouds' rain +#include "coordit.h" // For distance_iterator() +#include "death-curse.h" // For the Scythe of Curses #include "english.h" // For apostrophise #include "exercise.h" // For practise_evoking #include "fight.h" #include "food.h" // For evokes #include "ghost.h" // For is_dragonkind ghost_demon datas -#include "god-conduct.h" // did_god_conduct -#include "god-passive.h" // passive_t::want_curses +#include "god-conduct.h" // did_god_conduct +#include "god-passive.h" // passive_t::want_curses #include "mgen-data.h" // For Sceptre of Asmodeus evoke +#include "message.h" +#include "monster.h" #include "mon-death.h" // For demon axe's SAME_ATTITUDE #include "mon-place.h" // For Sceptre of Asmodeus evoke #include "nearby-danger.h" // For Zhor #include "player.h" #include "player-stats.h" +#include "showsymb.h" // For Cigotuvi's Embrace #include "spl-cast.h" // For evokes #include "spl-damage.h" // For the Singing Sword. #include "spl-goditem.h" // For Sceptre of Torment tormenting -#include "spl-miscast.h" // For Staff of Wucad Mu and Scythe of Curses miscasts +#include "spl-miscast.h" // For Spellbinder and plutonium sword miscasts #include "spl-monench.h" // For Zhor's aura #include "spl-summoning.h" // For Zonguldrok animating dead #include "terrain.h" // For storm bow @@ -106,7 +114,8 @@ return true; } -static bool _ASMODEUS_evoke(item_def *item, bool* did_work, bool* unevokable) +static bool _ASMODEUS_evoke(item_def */*item*/, bool* did_work, + bool* /*unevokable*/) { if (_evoke_sceptre_of_asmodeus()) { @@ -119,7 +128,7 @@ } //////////////////////////////////////////////////// -static void _CEREBOV_melee_effects(item_def* weapon, actor* attacker, +static void _CEREBOV_melee_effects(item_def* /*weapon*/, actor* attacker, actor* defender, bool mondied, int dam) { if (dam) @@ -149,42 +158,25 @@ //////////////////////////////////////////////////// -static void _CURSES_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _CURSES_equip(item_def */*item*/, bool *show_msgs, bool unmeld) { _equip_mpr(show_msgs, "A shiver runs down your spine."); if (!unmeld) - { - const int pow = random2(9); - MiscastEffect(&you, nullptr, {miscast_source::wield}, - spschool::necromancy, pow, random2(70), - "the scythe of Curses", nothing_happens::NEVER); - } -} - -static void _CURSES_world_reacts(item_def *item) -{ - // don't spam messages for ash worshippers - if (one_chance_in(30) && !have_passive(passive_t::want_curses)) - curse_an_item(); + death_curse(you, nullptr, "the scythe of Curses", 0); } -static void _CURSES_melee_effects(item_def* weapon, actor* attacker, +static void _CURSES_melee_effects(item_def* /*weapon*/, actor* attacker, actor* defender, bool mondied, int dam) { if (attacker->is_player()) did_god_conduct(DID_EVIL, 3); if (!mondied && defender->holiness() == MH_NATURAL) - { - const int pow = random2(9); - MiscastEffect(defender, attacker, {miscast_source::melee}, - spschool::necromancy, pow, random2(70), - "the scythe of Curses", nothing_happens::NEVER); - } + death_curse(*defender, attacker, "the scythe of Curses", min(dam, 27)); } ///////////////////////////////////////////////////// -static bool _DISPATER_evoke(item_def *item, bool* did_work, bool* unevokable) +static bool _DISPATER_evoke(item_def */*item*/, bool* did_work, bool* unevokable) { if (!enough_hp(14, true)) { @@ -219,7 +211,7 @@ //////////////////////////////////////////////////// -static void _FINISHER_melee_effects(item_def* weapon, actor* attacker, +static void _FINISHER_melee_effects(item_def* /*weapon*/, actor* attacker, actor* defender, bool mondied, int dam) { // Can't kill a monster that's already dead. @@ -244,7 +236,7 @@ // XXX: Staff giving a boost to poison spells is hardcoded in // player_spec_poison() -static void _OLGREB_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _OLGREB_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { if (you.can_smell()) _equip_mpr(show_msgs, "You smell chlorine."); @@ -252,7 +244,7 @@ _equip_mpr(show_msgs, "The staff glows a sickly green."); } -static void _OLGREB_unequip(item_def *item, bool *show_msgs) +static void _OLGREB_unequip(item_def */*item*/, bool *show_msgs) { if (you.can_smell()) _equip_mpr(show_msgs, "The smell of chlorine vanishes."); @@ -260,7 +252,7 @@ _equip_mpr(show_msgs, "The staff's sickly green glow vanishes."); } -static bool _OLGREB_evoke(item_def *item, bool* did_work, bool* unevokable) +static bool _OLGREB_evoke(item_def */*item*/, bool* did_work, bool* unevokable) { if (!enough_mp(4, false)) { @@ -282,21 +274,43 @@ return false; } - if (x_chance_in_y(you.skill(SK_EVOCATIONS, 100) + 100, 2000)) - your_spells(SPELL_VENOM_BOLT, power, false); - dec_mp(4); make_hungry(50, false, true); practise_evoking(1); + did_god_conduct(DID_WIZARDLY_ITEM, 10); return false; } -static void _OLGREB_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, int dam) +// Based on melee_attack::staff_damage(), but using only evocations skill. +static int _calc_olgreb_damage(actor* attacker, actor* defender) { - if (defender->alive()) - defender->poison(attacker, 2); + int base_dam = 0; + if (x_chance_in_y(attacker->skill(SK_EVOCATIONS, 100), 1000)) + base_dam = random2(attacker->skill(SK_EVOCATIONS, 150) / 80); + + return resist_adjust_damage(defender, BEAM_POISON_ARROW, base_dam); +} + + +static void _OLGREB_melee_effects(item_def* /*weapon*/, actor* attacker, + actor* defender, bool mondied, + int /*dam*/) +{ + const int bonus_dam = _calc_olgreb_damage(attacker, defender); + + if (!mondied && bonus_dam) + { + mprf("%s %s %s%s", + attacker->name(DESC_THE).c_str(), + attacker->conj_verb("envenom").c_str(), + defender->name(DESC_THE).c_str(), + attack_strength_punctuation(bonus_dam).c_str()); + + defender->hurt(attacker, bonus_dam); + if (defender->alive()) + defender->poison(attacker, 2, true); + } } //////////////////////////////////////////////////// @@ -306,7 +320,7 @@ item->plus = min(you.hp / 10, 27); } -static void _POWER_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _POWER_equip(item_def *item, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, "You sense an aura of extreme power."); _power_pluses(item); @@ -319,7 +333,7 @@ //////////////////////////////////////////////////// -static void _SINGING_SWORD_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _SINGING_SWORD_equip(item_def *item, bool *show_msgs, bool /*unmeld*/) { bool def_show = true; @@ -368,8 +382,8 @@ } static void _SINGING_SWORD_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, - int dam) + actor* /* defender */, + bool /*mondied*/, int /*dam*/) { int tier; @@ -404,16 +418,16 @@ return; // Can't cast when silenced. const int spellpower = 100 + 13 * (tier - 1) + (tier == 4 ? 36 : 0); - fire_los_attack_spell(SPELL_SONIC_WAVE, spellpower, attacker, defender); + fire_los_attack_spell(SPELL_SONIC_WAVE, spellpower, attacker); } //////////////////////////////////////////////////// -static void _PRUNE_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _PRUNE_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, "You feel pruney."); } -static void _PRUNE_world_reacts(item_def *item) +static void _PRUNE_world_reacts(item_def */*item*/) { if (one_chance_in(10)) did_god_conduct(DID_CHAOS, 1); @@ -421,13 +435,14 @@ //////////////////////////////////////////////////// -static void _TORMENT_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _TORMENT_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, "A terribly searing pain shoots up your arm!"); } -static void _TORMENT_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, int dam) +static void _TORMENT_melee_effects(item_def* /*weapon*/, actor* attacker, + actor* /*defender*/, bool /*mondied*/, + int /*dam*/) { if (one_chance_in(5)) torment(attacker, TORMENT_SCEPTRE, attacker->pos()); @@ -435,12 +450,12 @@ ///////////////////////////////////////////////////// -static void _TROG_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _TROG_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, "You feel bloodthirsty!"); } -static void _TROG_unequip(item_def *item, bool *show_msgs) +static void _TROG_unequip(item_def */*item*/, bool *show_msgs) { _equip_mpr(show_msgs, "You feel less violent."); } @@ -483,7 +498,7 @@ } } -static bool _WUCAD_MU_evoke(item_def *item, bool* did_work, bool* unevokable) +static bool _WUCAD_MU_evoke(item_def */*item*/, bool* did_work, bool* unevokable) { if (you.magic_points == you.max_magic_points) { @@ -499,6 +514,7 @@ { _wucad_backfire(); did_god_conduct(DID_CHANNEL, 10, true); + did_god_conduct(DID_WIZARDLY_ITEM, 10); return false; } @@ -511,6 +527,7 @@ *did_work = true; practise_evoking(1); did_god_conduct(DID_CHANNEL, 10, true); + did_god_conduct(DID_WIZARDLY_ITEM, 10); return false; } @@ -520,7 +537,7 @@ // XXX: Always getting maximal vampiric drain is hardcoded in // attack::apply_damage_brand() -static void _VAMPIRES_TOOTH_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _VAMPIRES_TOOTH_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { if (you.undead_state() == US_ALIVE && (you.species == SP_VAMPIRE || !you_foodless())) @@ -535,9 +552,9 @@ /////////////////////////////////////////////////// -static void _VARIABILITY_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, - int dam) +static void _VARIABILITY_melee_effects(item_def* /*weapon*/, actor* attacker, + actor* /*defender*/, bool mondied, + int /*dam*/) { if (!mondied && one_chance_in(5)) { @@ -550,13 +567,15 @@ /////////////////////////////////////////////////// -static void _ZONGULDROK_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _ZONGULDROK_equip(item_def */*item*/, bool *show_msgs, + bool /*unmeld*/) { _equip_mpr(show_msgs, "You sense an extremely unholy aura."); } -static void _ZONGULDROK_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, int dam) +static void _ZONGULDROK_melee_effects(item_def* /*weapon*/, actor* attacker, + actor* /*defender*/, bool /*mondied*/, + int /*dam*/) { if (attacker->is_player()) did_god_conduct(DID_EVIL, 3); @@ -564,8 +583,9 @@ /////////////////////////////////////////////////// -static void _GONG_melee_effects(item_def* item, actor* wearer, - actor* attacker, bool dummy, int dam) +static void _GONG_melee_effects(item_def* /*item*/, actor* wearer, + actor* /*attacker*/, bool /*dummy*/, + int /*dam*/) { if (silenced(wearer->pos())) return; @@ -580,8 +600,9 @@ /////////////////////////////////////////////////// -static void _DEMON_AXE_melee_effects(item_def* item, actor* attacker, - actor* defender, bool mondied, int dam) +static void _DEMON_AXE_melee_effects(item_def* /*item*/, actor* attacker, + actor* /*defender*/, bool /*mondied*/, + int /*dam*/) { if (one_chance_in(10)) { @@ -613,7 +634,7 @@ return nullptr; } -static void _DEMON_AXE_world_reacts(item_def *item) +static void _DEMON_AXE_world_reacts(item_def */*item*/) { monster* mon = _find_nearest_possible_beholder(); @@ -644,7 +665,7 @@ you.add_beholder(closest, true); } -static void _DEMON_AXE_unequip(item_def *item, bool *show_msgs) +static void _DEMON_AXE_unequip(item_def */*item*/, bool */*show_msgs*/) { if (you.beheld()) { @@ -659,7 +680,7 @@ /////////////////////////////////////////////////// -static void _WYRMBANE_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _WYRMBANE_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, species_is_draconian(you.species) @@ -713,11 +734,13 @@ if (!mondied) { - mprf("%s %s!", + int bonus_dam = 1 + random2(3 * dam / 2); + mprf("%s %s%s", defender->name(DESC_THE).c_str(), - defender->conj_verb("convulse").c_str()); + defender->conj_verb("convulse").c_str(), + attack_strength_punctuation(bonus_dam).c_str()); - defender->hurt(attacker, 1 + random2(3*dam/2)); + defender->hurt(attacker, bonus_dam); // Allow the lance to charge when killing dragonform felid players. mondied = defender->is_player() ? defender->as_player()->pending_revival @@ -762,80 +785,84 @@ /////////////////////////////////////////////////// -static void _UNDEADHUNTER_melee_effects(item_def* item, actor* attacker, +static void _UNDEADHUNTER_melee_effects(item_def* /*item*/, actor* attacker, actor* defender, bool mondied, int dam) { if (defender->holiness() & MH_UNDEAD && !one_chance_in(3) && !mondied && dam) { - mprf("%s %s blasted by disruptive energy!", + int bonus_dam = random2avg((1 + (dam * 3)), 3); + mprf("%s %s blasted by disruptive energy%s", defender->name(DESC_THE).c_str(), - defender->conj_verb("be").c_str()); - defender->hurt(attacker, random2avg((1 + (dam * 3)), 3)); + defender->conj_verb("be").c_str(), + attack_strength_punctuation(bonus_dam).c_str()); + defender->hurt(attacker, bonus_dam); } } /////////////////////////////////////////////////// -static void _EOS_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _EOS_equip(item_def */*item*/, bool */*show_msgs*/, bool /*unmeld*/) { invalidate_agrid(true); } -static void _EOS_unequip(item_def *item, bool *show_msgs) +static void _EOS_unequip(item_def */*item*/, bool */*show_msgs*/) { invalidate_agrid(true); } /////////////////////////////////////////////////// -static void _SHADOWS_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _SHADOWS_equip(item_def */*item*/, bool */*show_msgs*/, bool /*unmeld*/) { invalidate_agrid(true); } -static void _SHADOWS_unequip(item_def *item, bool *show_msgs) +static void _SHADOWS_unequip(item_def */*item*/, bool */*show_msgs*/) { invalidate_agrid(true); } /////////////////////////////////////////////////// -static void _DEVASTATOR_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _DEVASTATOR_equip(item_def */*item*/, bool *show_msgs, + bool /*unmeld*/) { _equip_mpr(show_msgs, "Time to lay down the shillelagh law."); } -static void _DEVASTATOR_melee_effects(item_def* item, actor* attacker, - actor* defender, bool mondied, int dam) +static void _DEVASTATOR_melee_effects(item_def* /*item*/, actor* attacker, + actor* defender, bool /*mondied*/, + int dam) { if (dam) shillelagh(attacker, defender->pos(), dam); } /////////////////////////////////////////////////// -static void _DRAGONSKIN_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _DRAGONSKIN_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, "You feel oddly protected from the elements."); } -static void _DRAGONSKIN_unequip(item_def *item, bool *show_msgs) +static void _DRAGONSKIN_unequip(item_def */*item*/, bool *show_msgs) { _equip_mpr(show_msgs, "You no longer feel protected from the elements."); } /////////////////////////////////////////////////// -static void _BLACK_KNIGHT_HORSE_world_reacts(item_def *item) +static void _BLACK_KNIGHT_HORSE_world_reacts(item_def */*item*/) { if (one_chance_in(10)) did_god_conduct(DID_EVIL, 1); } /////////////////////////////////////////////////// -static void _NIGHT_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _NIGHT_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { update_vision_range(); _equip_mpr(show_msgs, "The light fades from your surroundings."); } -static void _NIGHT_unequip(item_def *item, bool *show_msgs) +static void _NIGHT_unequip(item_def */*item*/, bool *show_msgs) { update_vision_range(); _equip_mpr(show_msgs, "The light returns to your surroundings."); @@ -843,29 +870,32 @@ /////////////////////////////////////////////////// -static void _PLUTONIUM_SWORD_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, - int dam) +static void _PLUTONIUM_SWORD_melee_effects(item_def* /*weapon*/, + actor* attacker, actor* defender, + bool mondied, int dam) { - if (!mondied && one_chance_in(5) - && (!defender->is_monster() - || !mons_immune_magic(*defender->as_monster()))) + if (!mondied && one_chance_in(5) && defender->can_mutate()) { mpr("Mutagenic energy flows through the plutonium sword!"); - const int pow = random2(9); - MiscastEffect(defender, attacker, {miscast_source::melee}, - spschool::transmutation, pow, random2(70), - "the plutonium sword", nothing_happens::NEVER); if (attacker->is_player()) did_god_conduct(DID_CHAOS, 3); + + if (one_chance_in(10)) + defender->polymorph(0); // Low duration if applied to the player. + else + { + miscast_effect(*defender, attacker, {miscast_source::melee}, + spschool::transmutation, 5, random2(dam), + "the plutonium sword"); + } } } /////////////////////////////////////////////////// -static void _SNAKEBITE_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, int dam) +static void _SNAKEBITE_melee_effects(item_def* /*weapon*/, actor* attacker, + actor* defender, bool mondied, int /*dam*/) { if (!mondied && x_chance_in_y(2, 5)) { @@ -876,8 +906,8 @@ /////////////////////////////////////////////////// -static void _WOE_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, int dam) +static void _WOE_melee_effects(item_def* /*weapon*/, actor* attacker, + actor* defender, bool mondied, int /*dam*/) { const char *verb = "bugger", *adv = ""; switch (random2(8)) @@ -906,8 +936,8 @@ /////////////////////////////////////////////////// -static setup_missile_type _DAMNATION_launch(item_def* item, bolt* beam, - string* ammo_name, bool* returning) +static setup_missile_type _DAMNATION_launch(item_def* /*item*/, bolt* beam, + string* ammo_name, bool* /*returning*/) { ASSERT(beam->item && beam->item->base_type == OBJ_MISSILES @@ -991,11 +1021,12 @@ if (bonus_dam <= 0) return; - mprf("%s %s %s.", + mprf("%s %s %s%s", attacker->name(DESC_THE).c_str(), attacker->conj_verb(verb).c_str(), (attacker == defender ? defender->pronoun(PRONOUN_REFLEXIVE) - : defender->name(DESC_THE)).c_str()); + : defender->name(DESC_THE)).c_str(), + attack_strength_punctuation(bonus_dam).c_str()); defender->hurt(attacker, bonus_dam, flavour); @@ -1005,19 +1036,19 @@ /////////////////////////////////////////////////// -static void _ARC_BLADE_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _ARC_BLADE_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, "The arc blade crackles to life."); } -static void _ARC_BLADE_unequip(item_def *item, bool *show_msgs) +static void _ARC_BLADE_unequip(item_def */*item*/, bool *show_msgs) { _equip_mpr(show_msgs, "The arc blade stops crackling."); } -static void _ARC_BLADE_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, - int dam) +static void _ARC_BLADE_melee_effects(item_def* /*weapon*/, actor* attacker, + actor* /*defender*/, bool /*mondied*/, + int /*dam*/) { if (one_chance_in(3)) { @@ -1034,7 +1065,7 @@ /////////////////////////////////////////////////// -static void _SPELLBINDER_melee_effects(item_def* weapon, actor* attacker, +static void _SPELLBINDER_melee_effects(item_def* /*weapon*/, actor* attacker, actor* defender, bool mondied, int dam) { @@ -1042,16 +1073,15 @@ if (defender->antimagic_susceptible() && !mondied) { - const int pow = random2(9); - MiscastEffect(defender, attacker, {miscast_source::melee}, - spschool::random, pow, random2(70), - "the demon whip \"Spellbinder\"", nothing_happens::NEVER); + miscast_effect(*defender, attacker, {miscast_source::melee}, + spschool::random, random_range(1, 9), dam, + "the demon whip \"Spellbinder\""); } } /////////////////////////////////////////////////// -static void _ORDER_melee_effects(item_def* item, actor* attacker, +static void _ORDER_melee_effects(item_def* /*item*/, actor* attacker, actor* defender, bool mondied, int dam) { if (!mondied) @@ -1071,17 +1101,18 @@ /////////////////////////////////////////////////// -static void _FIRESTARTER_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _FIRESTARTER_equip(item_def */*item*/, bool *show_msgs, + bool /*unmeld*/) { _equip_mpr(show_msgs, "You are filled with an inner flame."); } -static void _FIRESTARTER_unequip(item_def *item, bool *show_msgs) +static void _FIRESTARTER_unequip(item_def */*item*/, bool *show_msgs) { _equip_mpr(show_msgs, "Your inner flame fades away."); } -static void _FIRESTARTER_melee_effects(item_def* weapon, actor* attacker, +static void _FIRESTARTER_melee_effects(item_def* /*weapon*/, actor* attacker, actor* defender, bool mondied, int dam) { if (dam) @@ -1102,17 +1133,18 @@ /////////////////////////////////////////////////// #if TAG_MAJOR_VERSION == 34 -static void _CHILLY_DEATH_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _CHILLY_DEATH_equip(item_def */*item*/, bool *show_msgs, + bool /*unmeld*/) { _equip_mpr(show_msgs, "The dagger glows with an icy blue light!"); } -static void _CHILLY_DEATH_unequip(item_def *item, bool *show_msgs) +static void _CHILLY_DEATH_unequip(item_def */*item*/, bool *show_msgs) { _equip_mpr(show_msgs, "The dagger stops glowing."); } -static void _CHILLY_DEATH_melee_effects(item_def* weapon, actor* attacker, +static void _CHILLY_DEATH_melee_effects(item_def* /*weapon*/, actor* attacker, actor* defender, bool mondied, int dam) { if (dam) @@ -1140,17 +1172,18 @@ /////////////////////////////////////////////////// #if TAG_MAJOR_VERSION == 34 -static void _FLAMING_DEATH_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _FLAMING_DEATH_equip(item_def */*item*/, bool *show_msgs, + bool /*unmeld*/) { _equip_mpr(show_msgs, "The scimitar bursts into red hot flame!"); } -static void _FLAMING_DEATH_unequip(item_def *item, bool *show_msgs) +static void _FLAMING_DEATH_unequip(item_def */*item*/, bool *show_msgs) { _equip_mpr(show_msgs, "The scimitar stops flaming."); } -static void _FLAMING_DEATH_melee_effects(item_def* weapon, actor* attacker, +static void _FLAMING_DEATH_melee_effects(item_def* /*weapon*/, actor* attacker, actor* defender, bool mondied, int dam) { if (!mondied && (dam > 2 && one_chance_in(3))) @@ -1170,7 +1203,7 @@ /////////////////////////////////////////////////// -static void _MAJIN_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _MAJIN_equip(item_def *item, bool *show_msgs, bool /*unmeld*/) { if (!you.max_magic_points) return; @@ -1187,7 +1220,7 @@ } } -static void _MAJIN_unequip(item_def *item, bool *show_msgs) +static void _MAJIN_unequip(item_def */*item*/, bool *show_msgs) { if (you.max_magic_points) { @@ -1215,7 +1248,8 @@ return worn; } -static void _OCTOPUS_KING_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _OCTOPUS_KING_equip(item_def *item, bool *show_msgs, + bool /*unmeld*/) { int rings = _octorings_worn(); @@ -1233,7 +1267,7 @@ /////////////////////////////////////////////////// -static void _CAPTAIN_melee_effects(item_def* weapon, actor* attacker, +static void _CAPTAIN_melee_effects(item_def* /*weapon*/, actor* attacker, actor* defender, bool mondied, int dam) { // Player disarming sounds like a bad idea; monster-on-monster might @@ -1260,19 +1294,21 @@ /////////////////////////////////////////////////// -static void _FENCERS_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _FENCERS_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, "En garde!"); } +#if TAG_MAJOR_VERSION == 34 /////////////////////////////////////////////////// -static void _ETHERIC_CAGE_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _ETHERIC_CAGE_equip(item_def */*item*/, bool *show_msgs, + bool /*unmeld*/) { _equip_mpr(show_msgs, "You sense a greater flux of ambient magical fields."); } -static void _ETHERIC_CAGE_world_reacts(item_def *item) +static void _ETHERIC_CAGE_world_reacts(item_def */*item*/) { const int delay = you.time_taken; ASSERT(delay > 0); @@ -1285,20 +1321,20 @@ /////////////////////////////////////////////////// -#if TAG_MAJOR_VERSION == 34 -static void _ETERNAL_TORMENT_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _ETERNAL_TORMENT_equip(item_def */*item*/, bool */*show_msgs*/, + bool /*unmeld*/) { calc_hp(); } -static void _ETERNAL_TORMENT_world_reacts(item_def *item) +static void _ETERNAL_TORMENT_world_reacts(item_def */*item*/) { if (one_chance_in(10)) did_god_conduct(DID_EVIL, 1); } -static void _ETERNAL_TORMENT_unequip(item_def *item, bool *show_msgs) +static void _ETERNAL_TORMENT_unequip(item_def */*item*/, bool */*show_msgs*/) { calc_hp(); } @@ -1306,32 +1342,33 @@ /////////////////////////////////////////////////// -static void _VINES_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _VINES_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, "The vines latch onto your body!"); } -static void _VINES_unequip(item_def *item, bool *show_msgs) +static void _VINES_unequip(item_def */*item*/, bool *show_msgs) { _equip_mpr(show_msgs, "The vines fall away from your body!"); } /////////////////////////////////////////////////// -static void _KRYIAS_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _KRYIAS_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { _equip_mpr(show_msgs, "Your attunement to healing potions increases."); } -static void _KRYIAS_unequip(item_def *item, bool *show_msgs) +static void _KRYIAS_unequip(item_def */*item*/, bool *show_msgs) { _equip_mpr(show_msgs, "Your attunement to healing potions decreases."); } /////////////////////////////////////////////////// -static void _FROSTBITE_melee_effects(item_def* weapon, actor* attacker, - actor* defender, bool mondied, int dam) +static void _FROSTBITE_melee_effects(item_def* /*weapon*/, actor* attacker, + actor* defender, bool /*mondied*/, + int /*dam*/) { coord_def spot = defender->pos(); if (!cell_is_solid(spot) @@ -1346,7 +1383,7 @@ // Vampiric effect triggers on every hit, see attack::apply_damage_brand() -static void _LEECH_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _LEECH_equip(item_def */*item*/, bool *show_msgs, bool /*unmeld*/) { if (you.undead_state() == US_ALIVE && (you.species == SP_VAMPIRE || !you_foodless())) @@ -1358,10 +1395,23 @@ // else let player-equip.cc handle message } +// Big killing blows give a bloodsplosion effect sometimes +static void _LEECH_melee_effects(item_def* /*item*/, actor* attacker, + actor* defender, bool mondied, int dam) +{ + if (attacker->is_player() && defender->can_bleed() + && mondied && x_chance_in_y(dam, 729)) + { + simple_monster_message(*(defender->as_monster()), + " liquefies into a cloud of blood!"); + blood_spray(defender->pos(), defender->type, 50); + } +} /////////////////////////////////////////////////// -static void _THERMIC_ENGINE_equip(item_def *item, bool *show_msgs, bool unmeld) +static void _THERMIC_ENGINE_equip(item_def *item, bool *show_msgs, + bool /*unmeld*/) { _equip_mpr(show_msgs, "The engine hums to life!"); item->plus = 2; @@ -1421,7 +1471,7 @@ /////////////////////////////////////////////////// -static void _ZHOR_world_reacts(item_def *item) +static void _ZHOR_world_reacts(item_def */*item*/) { if (there_are_monsters_nearby(true, false, false) && one_chance_in(7 * div_rand_round(BASELINE_DELAY, you.time_taken))) @@ -1435,16 +1485,121 @@ // XXX: Staff of Battle giving a boost to conjuration spells is hardcoded in // player_spec_conj(). -static void _BATTLE_unequip(item_def *item, bool *show_msgs) +static void _BATTLE_unequip(item_def */*item*/, bool */*show_msgs*/) { end_battlesphere(find_battlesphere(&you), false); } -static void _BATTLE_world_reacts(item_def *item) +static void _BATTLE_world_reacts(item_def */*item*/) { if (!find_battlesphere(&you) && there_are_monsters_nearby(true, true, false)) { your_spells(SPELL_BATTLESPHERE, 0, false); - did_god_conduct(DID_SPELL_CASTING, 1); + did_god_conduct(DID_WIZARDLY_ITEM, 10); } } + +//////////////////////////////////////////////////// + +static void _EMBRACE_unequip(item_def *item, bool *show_msgs) +{ + int &armour = item->props[EMBRACE_ARMOUR_KEY].get_int(); + if (armour > 0) + { + _equip_mpr(show_msgs, "Your corpse armour falls away."); + armour = 0; + item->plus = get_unrand_entry(item->unrand_idx)->plus; + } +} + +/** + * Iterate over all corpses in LOS and harvest them. + * + * @return The total number of corpses destroyed. + */ +static int _harvest_corpses() +{ + int harvested = 0; + + for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri) + { + for (stack_iterator si(*ri, true); si; ++si) + { + item_def &item = *si; + if (item.base_type != OBJ_CORPSES) + continue; + + // forbid harvesting orcs under Beogh + const monster_type monnum + = static_cast(item.orig_monnum); + if (you.religion == GOD_BEOGH && mons_genus(monnum) == MONS_ORC) + continue; + + did_god_conduct(DID_EVIL, 1); + + // apply these in addition to use of an evil item + if (mons_class_holiness(item.mon_type) & MH_HOLY) + did_god_conduct(DID_DESECRATE_HOLY_REMAINS, 4); + else if (corpse_intelligence(item) >= I_HUMAN) + did_god_conduct(DID_DESECRATE_SOULED_BEING, 1); + + ++harvested; + + // don't spam animations + if (harvested <= 5) + { + bolt beam; + beam.source = *ri; + beam.target = you.pos(); + beam.glyph = get_item_glyph(item).ch; + beam.colour = item.get_colour(); + beam.range = LOS_RADIUS; + beam.aimed_at_spot = true; + beam.item = &item; + beam.flavour = BEAM_VISUAL; + beam.draw_delay = 3; + beam.fire(); + viewwindow(); + } + + destroy_item(item.index()); + } + } + + return harvested; +} + +static void _EMBRACE_world_reacts(item_def *item) +{ + int &armour = item->props[EMBRACE_ARMOUR_KEY].get_int(); + const int harvested = _harvest_corpses(); + // diminishing returns for more corpses + for (int i = 0; i < harvested; i++) + armour += div_rand_round(100 * 100, (armour + 100)); + + // decay over time - 1 turn per 'armour' base, 0.5 turns at 400 'armour' + armour -= div_rand_round(you.time_taken * (armour + 400), 10 * 400); + + const int last_plus = item->plus; + const int base_plus = get_unrand_entry(item->unrand_idx)->plus; + if (armour <= 0) + { + armour = 0; + item->plus = base_plus; + if (last_plus > base_plus) + mpr("Your corpse armour falls away."); + } + else + { + item->plus = base_plus + 1 + (armour-1) * 6 / 100; + if (item->plus < last_plus) + mpr("A chunk of your corpse armour falls away."); + else if (last_plus == base_plus) + mpr("The bodies of the dead rush to embrace you!"); + else if (item->plus > last_plus) + mpr("Your shell of carrion and bone grows thicker."); + } + + if (item->plus != last_plus) + you.redraw_armour_class = true; +} diff -Nru crawl-0.24.0/source/attack.cc crawl-0.25.0/source/attack.cc --- crawl-0.24.0/source/attack.cc 2019-09-15 23:48:09.000000000 +0000 +++ crawl-0.25.0/source/attack.cc 2020-05-23 16:07:19.000000000 +0000 @@ -33,11 +33,9 @@ #include "mon-behv.h" #include "mon-clone.h" #include "mon-death.h" -#include "mon-poly.h" #include "nearby-danger.h" #include "pronoun-type.h" #include "religion.h" -#include "spl-miscast.h" #include "spl-util.h" #include "state.h" #include "stepdown.h" @@ -63,8 +61,7 @@ attacker_to_hit_penalty(0), attack_verb("bug"), verb_degree(), no_damage_message(), special_damage_message(), aux_attack(), aux_verb(), attacker_armour_tohit_penalty(0), attacker_shield_tohit_penalty(0), - defender_shield(nullptr), miscast_level(-1), miscast_type(spschool::none), - miscast_target(nullptr), fake_chaos_attack(false), simu(false), + defender_shield(nullptr), fake_chaos_attack(false), simu(false), aux_source(""), kill_type(KILLED_BY_MONSTER) { // No effective code should execute, we'll call init_attack again from @@ -126,8 +123,13 @@ bool attack::handle_phase_killed() { monster* mon = defender->as_monster(); - if (!invalid_monster(mon)) - monster_die(*mon, attacker); + if (!invalid_monster(mon)) { + // Was this a reflected missile from the player? + if (responsible->mid == MID_YOU_FAULTLESS) + monster_die(*mon, KILL_YOU_MISSILE, YOU_FAULTLESS); + else + monster_die(*mon, attacker); + } return true; } @@ -458,18 +460,14 @@ BIG_DMG, BANISH, BLINK, - TELE_INSTANT, - TELE_DELAYED, NONE }; - const disto_effect choice = random_choose_weighted(33, SMALL_DMG, - 22, BIG_DMG, - 5, BANISH, - 15, BLINK, - 10, TELE_INSTANT, - 10, TELE_DELAYED, - 5, NONE); + const disto_effect choice = random_choose_weighted(35, SMALL_DMG, + 25, BIG_DMG, + 10, BANISH, + 20, BLINK, + 10, NONE); if (simu && !(choice == SMALL_DMG || choice == BIG_DMG)) return false; @@ -502,23 +500,6 @@ defender->banish(attacker, attacker->name(DESC_PLAIN, true), attacker->get_experience_level()); return true; - case TELE_INSTANT: - case TELE_DELAYED: - if (defender_visible) - obvious_effect = true; - if (crawl_state.game_is_sprint() && defender->is_player() - || defender->no_tele()) - { - if (defender->is_player()) - canned_msg(MSG_STRANGE_STASIS); - return false; - } - - if (choice == TELE_INSTANT) - teleport_fineff::schedule(defender); - else - defender->teleport(); - break; case NONE: // Do nothing break; @@ -610,8 +591,10 @@ if (!clone) return false; - const bool obvious_effect - = you.can_see(defender) && you.can_see(*clone); + const bool obvious_effect = you.can_see(defender) && you.can_see(*clone); + + if (one_chance_in(3)) + clone->attitude = coinflip() ? ATT_FRIENDLY : ATT_NEUTRAL; // The player shouldn't get new permanent followers from cloning. if (clone->attitude == ATT_FRIENDLY && !clone->is_summoned()) @@ -654,27 +637,6 @@ }, }, { - "miscast", 20, nullptr, BEAM_NONE, [](attack &attack) { - - const int HD = attack.defender->get_hit_dice(); - - // At level == 27 there's a 13.9% chance of a level 3 miscast. - const int level0_chance = HD; - const int level1_chance = max(0, HD - 7); - const int level2_chance = max(0, HD - 12); - const int level3_chance = max(0, HD - 17); - - attack.miscast_level = random_choose_weighted(level0_chance, 0, - level1_chance, 1, - level2_chance, 2, - level3_chance, 3); - attack.miscast_type = spschool::random; - attack.miscast_target = attack.defender; - - return false; - }, - }, - { "rage", 5, [](const actor &defender) { return defender.can_go_berserk(); }, BEAM_NONE, [](attack &attack) { @@ -683,6 +645,8 @@ }, }, { "hasting", 10, _is_chaos_slowable, BEAM_HASTE }, + { "mighting", 10, nullptr, BEAM_MIGHT }, + { "agilitying", 10, nullptr, BEAM_AGILITY }, { "invisible", 10, nullptr, BEAM_INVISIBILITY, }, { "slowing", 10, _is_chaos_slowable, BEAM_SLOW }, { @@ -861,64 +825,6 @@ return *random_choose_weighted(weights); } -void attack::do_miscast() -{ - if (miscast_level == -1) - return; - - ASSERT(miscast_target != nullptr); - ASSERT_RANGE(miscast_level, 0, 4); - ASSERT(count_bits(static_cast(miscast_type)) == 1); - - if (!miscast_target->alive()) - return; - - if (miscast_target->is_player() && you.banished) - return; - - const bool chaos_brand = - using_weapon() && get_weapon_brand(*weapon) == SPWPN_CHAOS; - - // If the miscast is happening on the attacker's side and is due to - // a chaos weapon then make smoke/sand/etc pour out of the weapon - // instead of the attacker's hands. - string hand_str; - - string cause = atk_name(DESC_THE); - - const int ignore_mask = ISFLAG_KNOW_CURSE | ISFLAG_KNOW_PLUSES; - - if (attacker->is_player()) - { - if (chaos_brand) - { - cause = "a chaos effect from "; - // Ignore a lot of item flags to make cause as short as possible, - // so it will (hopefully) fit onto a single line in the death - // cause screen. - cause += wep_name(DESC_YOUR, ignore_mask | ISFLAG_COSMETIC_MASK); - - if (miscast_target == attacker) - hand_str = wep_name(DESC_PLAIN, ignore_mask); - } - } - else - { - if (chaos_brand && miscast_target == attacker - && you.can_see(*attacker)) - { - hand_str = wep_name(DESC_PLAIN, ignore_mask); - } - } - - MiscastEffect(miscast_target, attacker, {miscast_source::melee}, - (spschool) miscast_type, miscast_level, cause, - nothing_happens::NEVER, 0, hand_str, false); - - // Don't do miscast twice for one attack. - miscast_level = -1; -} - void attack::drain_defender() { if (defender->is_monster() && coinflip()) @@ -1281,7 +1187,7 @@ damage_max += attk_damage; damage += 1 + random2(attk_damage); - damage = apply_damage_modifiers(damage, damage_max); + damage = apply_damage_modifiers(damage); set_attack_verb(damage); return apply_defender_ac(damage, damage_max); @@ -1621,26 +1527,33 @@ break; } - if (!x_chance_in_y(melee_confuse_chance(defender->get_hit_dice()), 100) - || defender->as_monster()->check_clarity(false)) - { - break; - } - // Declaring these just to pass to the enchant function. bolt beam_temp; beam_temp.thrower = attacker->is_player() ? KILL_YOU : KILL_MON; beam_temp.flavour = BEAM_CONFUSION; beam_temp.source_id = attacker->mid; - beam_temp.apply_enchantment_to_monster(defender->as_monster()); - obvious_effect = beam_temp.obvious_effect; if (attacker->is_player() && damage_brand == SPWPN_CONFUSE && you.duration[DUR_CONFUSING_TOUCH]) { - you.duration[DUR_CONFUSING_TOUCH] = 0; - obvious_effect = false; + beam_temp.ench_power = you.props["confusing touch power"].get_int(); + int margin; + if (beam_temp.try_enchant_monster(defender->as_monster(), margin) + == MON_AFFECTED) + { + you.duration[DUR_CONFUSING_TOUCH] = 0; + obvious_effect = false; + } } + else if (!x_chance_in_y(melee_confuse_chance(defender->get_hit_dice()), + 100) + || defender->as_monster()->check_clarity()) + { + beam_temp.apply_enchantment_to_monster(defender->as_monster()); + obvious_effect = beam_temp.obvious_effect; + break; + } + break; } @@ -1665,14 +1578,6 @@ if (damage_brand == SPWPN_CHAOS) { - if (brand != SPWPN_CHAOS && !ret - && miscast_level == -1 && one_chance_in(20)) - { - miscast_level = 0; - miscast_type = spschool::random; - miscast_target = random_choose(attacker, defender); - } - if (responsible->is_player()) did_god_conduct(DID_CHAOS, 2 + random2(3), brand_was_known); } @@ -1685,10 +1590,6 @@ mpr(special_damage_message); special_damage_message.clear(); - // Don't do message-only miscasts along with a special - // damage message. - if (miscast_level == 0) - miscast_level = -1; } // Preserve Nessos's brand stacking in a hacky way -- but to be fair, it @@ -1743,7 +1644,7 @@ if (player_good_stab()) { - // We might be unarmed if we're using the boots of the Assassin. + // We might be unarmed if we're using the hood of the Assassin. const bool extra_good = using_weapon() && weapon->sub_type == WPN_DAGGER; int bonus = you.dex() * (stab_skill + 100) / (extra_good ? 500 : 1000); @@ -1789,7 +1690,7 @@ /* Check for stab and prepare combat for stab-values * - * Grant an automatic stab if paralyzed or sleeping (with highest damage value) + * Grant an automatic stab if paralysed or sleeping (with highest damage value) * stab_bonus is used as the divisor in damage calculations, so lower values * will yield higher damage. Normal stab chance is (stab_skill + dex + 1 / roll) * This averages out to about 1/3 chance for a non extended-endgame stabber. @@ -1806,9 +1707,10 @@ stab_type st = find_stab_type(&you, *defender); // Find stab type is also used for displaying information about monsters, - // so we need to upgrade the stab type for the Spriggan's Knife here - if (using_weapon() + // so upgrade the stab type for !stab and the Spriggan's Knife here + if ((using_weapon() && is_unrandom_artefact(*weapon, UNRAND_SPRIGGANS_KNIFE) + || you.duration[DUR_STABBING] > 0 && coinflip()) && st != STAB_NO_STAB) { st = STAB_SLEEPING; diff -Nru crawl-0.24.0/source/attack.h crawl-0.25.0/source/attack.h --- crawl-0.24.0/source/attack.h 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/source/attack.h 2020-05-23 16:07:19.000000000 +0000 @@ -84,12 +84,6 @@ item_def *defender_shield; - // Miscast to cause after special damage is done. If miscast_level == 0 - // the miscast is discarded if special_damage_message isn't empty. - int miscast_level; - spschool miscast_type; - actor* miscast_target; - bool fake_chaos_attack; bool simu; @@ -136,7 +130,7 @@ virtual int get_weapon_plus(); virtual int calc_base_unarmed_damage(); virtual int calc_mon_to_hit_base() = 0; - virtual int apply_damage_modifiers(int damage, int damage_max) = 0; + virtual int apply_damage_modifiers(int damage) = 0; virtual int calc_damage(); int test_hit(int to_hit, int ev, bool randomise_ev); int apply_defender_ac(int damage, int damage_max = 0) const; @@ -144,6 +138,7 @@ virtual bool attack_shield_blocked(bool verbose); virtual bool ignores_shield(bool verbose) { + UNUSED(verbose); return false; } virtual bool apply_damage_brand(const char *what = nullptr); @@ -162,7 +157,6 @@ void pain_affects_defender(); void chaos_affects_defender(); brand_type random_chaos_brand(); - void do_miscast(); void drain_defender(); void drain_defender_speed(); diff -Nru crawl-0.24.0/source/attribute-type.h crawl-0.25.0/source/attribute-type.h --- crawl-0.24.0/source/attribute-type.h 2019-08-26 22:45:00.000000000 +0000 +++ crawl-0.25.0/source/attribute-type.h 2020-05-23 16:07:19.000000000 +0000 @@ -63,8 +63,8 @@ ATTR_BARBS_POW, // How badly we are currently skewered #if TAG_MAJOR_VERSION == 34 ATTR_REPEL_MISSILES, // Repel missiles active -#endif ATTR_DEFLECT_MISSILES, // Deflect missiles active +#endif ATTR_PORTAL_PROJECTILE, // Accuracy bonus during portal projectile ATTR_GOD_WRATH_XP, // How much XP before our next god wrath check? ATTR_GOD_WRATH_COUNT, // Number of stored retributions @@ -94,8 +94,10 @@ ATTR_DIVINE_ENERGY, // Divine energy from Sif to cast with no MP. #endif ATTR_SERPENTS_LASH, // Remaining instant movement actions. +#if TAG_MAJOR_VERSION == 34 ATTR_HEAVENLY_STORM, // Strength of Heavenly Storm slaying. ATTR_WALL_JUMP_READY, // Ready to perform a wall jump. +#endif ATTR_DEATHS_DOOR_HP, // How much HP we should have under Death's Door NUM_ATTRIBUTES }; diff -Nru crawl-0.24.0/source/beam.cc crawl-0.25.0/source/beam.cc --- crawl-0.24.0/source/beam.cc 2019-10-24 18:24:39.000000000 +0000 +++ crawl-0.25.0/source/beam.cc 2020-06-11 16:00:41.000000000 +0000 @@ -21,7 +21,6 @@ #include "attack.h" #include "attitude-change.h" #include "bloodspatter.h" -#include "branch.h" #include "chardump.h" #include "cloud.h" #include "colour.h" @@ -33,7 +32,6 @@ #include "exercise.h" #include "fight.h" #include "food.h" -#include "god-abil.h" #include "god-conduct.h" #include "god-item.h" #include "god-passive.h" // passive_t::convert_orcs @@ -44,7 +42,6 @@ #include "losglobal.h" #include "los.h" #include "message.h" -#include "misc.h" #include "mon-behv.h" #include "mon-death.h" #include "mon-place.h" @@ -62,7 +59,6 @@ #include "spl-damage.h" #include "spl-goditem.h" #include "spl-monench.h" -#include "spl-other.h" #include "spl-summoning.h" #include "spl-transloc.h" #include "spl-util.h" @@ -334,9 +330,7 @@ // Returns true if the player wants / needs to abort based on god displeasure // with targeting this target with this spell. Returns false otherwise. static bool _stop_because_god_hates_target_prompt(monster* mon, - spell_type spell, - beam_type flavour, - item_def *item) + spell_type spell) { if (spell == SPELL_TUKIMAS_DANCE) { @@ -546,6 +540,8 @@ // this and SPWPN_CHAOS to use the same tables. static beam_type _chaos_beam_flavour(bolt* beam) { + UNUSED(beam); + beam_type flavour; flavour = random_choose_weighted( // SPWPN_CHAOS randomizes to brands analogous to these beam effects @@ -940,8 +936,7 @@ { const string prompt = make_stringf("Are you sure you want to burn %s?", - feature_description_at(pos(), false, DESC_THE, - false).c_str()); + feature_description_at(pos(), false, DESC_THE).c_str()); if (yesno(prompt.c_str(), false, 'n')) dont_stop_trees = true; @@ -1138,6 +1133,9 @@ const dungeon_feature_type feat = grd(pos()); if (in_bounds(target) + // Starburst beams are essentially untargeted; some might even hit + // a victim if others have LOF blocked. + && origin_spell != SPELL_STARBURST // We ran into a solid wall with a real beam... && (feat_is_solid(feat) && flavour != BEAM_DIGGING && flavour <= BEAM_LAST_REAL @@ -1170,12 +1168,12 @@ else { prompt += "the targeted " - + feature_description_at(target, false, DESC_PLAIN, false); + + feature_description_at(target, false, DESC_PLAIN); } prompt += " is blocked by " + (feat_is_solid(feat) ? - feature_description_at(pos(), false, DESC_A, false) : + feature_description_at(pos(), false, DESC_A) : monster_at(pos())->name(DESC_A)); prompt += ". Continue anyway?"; @@ -1442,20 +1440,23 @@ } case BEAM_POISON_ARROW: + { hurted = resist_adjust_damage(mons, pbolt.flavour, hurted); + const int stacks = pbolt.origin_spell == SPELL_STING ? 1 : 4; if (hurted < original) { if (doFlavouredEffects) { simple_monster_message(*mons, " partially resists."); - - poison_monster(mons, pbolt.agent(), 2, true); + poison_monster(mons, pbolt.agent(), div_rand_round(stacks, 2), + true); } } else if (doFlavouredEffects) - poison_monster(mons, pbolt.agent(), 4, true); + poison_monster(mons, pbolt.agent(), stacks , true); break; + } case BEAM_NEG: if (mons->res_negative_energy() == 3) @@ -2107,28 +2108,6 @@ } } -bool imb_can_splash(coord_def origin, coord_def center, - vector path_taken, coord_def target) -{ - // Don't go back along the path of the beam (the explosion doesn't - // reverse direction). We do this to avoid hitting the caster and - // also because we don't want aiming one - // square past a lone monster to be optimal. - if (origin == target) - return false; - if (find(begin(path_taken), end(path_taken), target) != end(path_taken)) - return false; - - // Don't go far away from the caster (not enough momentum). - if (grid_distance(origin, center + (target - center)*2) - > you.current_vision) - { - return false; - } - - return true; -} - void bolt_parent_init(const bolt &parent, bolt &child) { child.name = parent.name; @@ -2171,67 +2150,6 @@ #endif } -static void _maybe_imb_explosion(bolt *parent, coord_def center) -{ - if (parent->origin_spell != SPELL_ISKENDERUNS_MYSTIC_BLAST - || parent->in_explosion_phase) - { - return; - } - const int dist = grid_distance(parent->source, center); - if (dist == 0 || (!parent->is_tracer && !x_chance_in_y(3, 2 + 2 * dist))) - return; - bolt beam; - - bolt_parent_init(*parent, beam); - beam.name = "mystic blast"; - beam.aux_source = "orb of energy"; - beam.range = 3; - beam.hit = AUTOMATIC_HIT; - beam.colour = MAGENTA; - beam.obvious_effect = true; - beam.pierce = false; - beam.is_explosion = false; - // So as not to recur infinitely - beam.origin_spell = SPELL_NO_SPELL; - beam.passed_target = true; // The centre was the target. - beam.aimed_at_spot = true; - if (you.see_cell(center)) - beam.seen = true; - beam.source = center; - - bool first = true; - for (adjacent_iterator ai(center); ai; ++ai) - { - if (!imb_can_splash(parent->source, center, parent->path_taken, *ai)) - continue; - if (!beam.is_tracer && one_chance_in(4)) - continue; - - if (first && !beam.is_tracer) - { - if (you.see_cell(center)) - mpr("The orb of energy explodes!"); - noisy(spell_effect_noise(SPELL_ISKENDERUNS_MYSTIC_BLAST), - center); - first = false; - } - beam.friend_info.reset(); - beam.foe_info.reset(); - beam.friend_info.dont_stop = parent->friend_info.dont_stop; - beam.foe_info.dont_stop = parent->foe_info.dont_stop; - beam.target = center + (*ai - center) * 2; - beam.fire(); - parent->friend_info += beam.friend_info; - parent->foe_info += beam.foe_info; - if (beam.is_tracer && beam.beam_cancelled) - { - parent->beam_cancelled = true; - return; - } - } -} - static void _malign_offering_effect(actor* victim, const actor* agent, int damage) { if (!agent || damage < 1) @@ -2401,8 +2319,6 @@ return; } - _maybe_imb_explosion(this, pos()); - const cloud_type cloud = get_cloud_type(); if (is_tracer) @@ -2513,7 +2429,7 @@ return; } - if (!thrown_object_destroyed(item, pos())) + if (!thrown_object_destroyed(item)) { if (item->sub_type == MI_THROWING_NET) { @@ -2571,7 +2487,10 @@ || origin_spell == SPELL_BOLT_OF_FIRE || origin_spell == SPELL_BOLT_OF_MAGMA || origin_spell == SPELL_FIREBALL - || origin_spell == SPELL_INNER_FLAME; + || origin_spell == SPELL_FIRE_STORM + || origin_spell == SPELL_IGNITION + || origin_spell == SPELL_INNER_FLAME + || origin_spell == SPELL_STARBURST; } bool bolt::can_affect_wall(const coord_def& p, bool map_knowledge) const @@ -2751,7 +2670,6 @@ } else if (monst && (monst->type == MONS_BALLISTOMYCETE_SPORE || monst->type == MONS_BALL_LIGHTNING - || monst->type == MONS_HYPERACTIVE_BALLISTOMYCETE || monst->type == MONS_FULMINANT_PRISM || monst->type == MONS_BENNU // death flames )) @@ -2815,20 +2733,18 @@ // very kind to the player, but it should be fairer to monsters than // 4.0. static bool _test_beam_hit(int attack, int defence, bool pierce, - int defl, defer_rand &r) + bool repel, defer_rand &r) { if (attack == AUTOMATIC_HIT) return true; if (pierce) { - if (defl > 1) - attack = r[0].random2(attack * 2) / 3; - else if (defl && attack >= 2) // don't increase acc of 0 + if (repel && attack >= 2) // don't increase acc of 0 attack = r[0].random_range((attack + 1) / 2 + 1, attack); } - else if (defl) - attack = r[0].random2(attack / defl); + else if (repel) + attack = r[0].random2(attack); dprf(DIAG_BEAM, "Beam attack: %d, defence: %d", attack, defence); @@ -3146,20 +3062,17 @@ defer_rand r; - int defl = you.missile_deflection(); + bool repel = you.missile_repulsion(); if (!_test_beam_hit(real_tohit, dodge, pierce, 0, r)) { mprf("The %s misses you.", name.c_str()); count_action(CACT_DODGE, DODGE_EVASION); } - else if (defl && !_test_beam_hit(real_tohit, dodge, pierce, defl, r)) + else if (repel && !_test_beam_hit(real_tohit, dodge, pierce, repel, r)) { - // active voice to imply stronger effect - mprf(defl == 1 ? "The %s is repelled." : "You deflect the %s!", - name.c_str()); - you.ablate_deflection(); - count_action(CACT_DODGE, DODGE_DEFLECT); + mprf("The %s is repelled.", name.c_str()); + count_action(CACT_DODGE, DODGE_REPEL); } else return false; @@ -3460,7 +3373,7 @@ break; case BEAM_AGILITY: - potionlike_effect(POT_AGILITY, ench_power); + you.be_agile(ench_power); obvious_effect = true; nasty = false; nice = true; @@ -3578,7 +3491,7 @@ [](const actor &defender) { return defender.is_player(); }, - [](actor &defender, const bolt &/*beam*/) { + [](actor &/*defender*/, const bolt &/*beam*/) { if (you.duration[DUR_VERTIGO]) mpr("You feel your light-headedness will last longer."); else @@ -3593,7 +3506,7 @@ [](const actor &defender) { return defender.is_player() && !you_foodless(); }, - [](actor &defender, const bolt &beam) { + [](actor &/*defender*/, const bolt &/*beam*/) { if (you.duration[DUR_NO_POTIONS]) mpr("You feel your inability to drink will last longer."); else @@ -3635,7 +3548,7 @@ [](const actor &defender) { return defender.is_player(); }, - [](actor &defender, const bolt &beam) { + [](actor &/*defender*/, const bolt &/*beam*/) { for (int i = 0; i < NUM_STATS; ++i) lose_stat(static_cast(i), 1 + random2(3)); }, @@ -3677,7 +3590,7 @@ [](const actor &defender) { return defender.can_polymorph(); }, - [](actor &defender, const bolt &beam) { + [](actor &defender, const bolt &/*beam*/) { defender.polymorph(100, false); }, 4 @@ -3746,6 +3659,11 @@ return; } + // Visible beams reveal invisible monsters; otherwise animations confer + // an information advantage for sighted players + if (visible() && agent() && agent()->is_monster()) + agent()->as_monster()->unseen_pos = agent()->pos(); + if (misses_player()) return; @@ -3970,12 +3888,6 @@ you.duration[DUR_FROZEN] = (2 + random2(3)) * BASELINE_DELAY; } } - else if (origin_spell == SPELL_DAZZLING_SPRAY - && !(you.holiness() & (MH_UNDEAD | MH_NONLIVING | MH_PLANT))) - { - if (x_chance_in_y(85 - you.experience_level * 3 , 100)) - you.confuse(agent(), 5 + random2(3)); - } } int bolt::apply_AC(const actor *victim, int hurted) @@ -4053,8 +3965,7 @@ } // Return false if we should skip handling this monster. -bool bolt::determine_damage(monster* mon, int& preac, int& postac, int& final, - vector& messages) +bool bolt::determine_damage(monster* mon, int& preac, int& postac, int& final) { preac = postac = final = 0; @@ -4146,8 +4057,7 @@ bool prompted = false; if (stop_attack_prompt(mon, true, target, &prompted) - || _stop_because_god_hates_target_prompt(mon, origin_spell, flavour, - item)) + || _stop_because_god_hates_target_prompt(mon, origin_spell)) { beam_cancelled = true; finish_beam(); @@ -4175,10 +4085,9 @@ void bolt::tracer_nonenchantment_affect_monster(monster* mon) { - vector messages; int preac, post, final; - if (!determine_damage(mon, preac, post, final, messages)) + if (!determine_damage(mon, preac, post, final)) return; // Check only if actual damage and the monster is worth caring about. @@ -4218,13 +4127,6 @@ if (beam_cancelled) return; - // Check only if actual damage. - if (!is_tracer && final > 0) - { - for (const string &msg : messages) - mprf(MSGCH_MONSTER_DAMAGE, "%s", msg.c_str()); - } - // Either way, we could hit this monster, so update range used. extra_range_used += range_used_on_hit(); } @@ -4259,8 +4161,6 @@ tracer_enchantment_affect_monster(mon); else tracer_nonenchantment_affect_monster(mon); - - _maybe_imb_explosion(this, pos()); } void bolt::enchantment_affect_monster(monster* mon) @@ -4275,9 +4175,6 @@ { if (YOU_KILL(thrower)) { - if (is_sanctuary(mon->pos()) || is_sanctuary(you.pos())) - remove_sanctuary(true); - set_attack_conducts(conducts, *mon, you.can_see(*mon)); if (have_passive(passive_t::convert_orcs) @@ -4339,23 +4236,7 @@ extra_range_used += range_used_on_hit(); } -static bool _dazzle_monster(monster* mons, actor* act) -{ - if (!mons_can_be_dazzled(mons->type)) - return false; - - if (x_chance_in_y(95 - mons->get_hit_dice() * 5 , 100)) - { - simple_monster_message(*mons, " is dazzled."); - mons->add_ench(mon_enchant(ENCH_BLIND, 1, act, - random_range(4, 8) * BASELINE_DELAY)); - return true; - } - - return false; -} - -static void _glaciate_freeze(monster* mon, killer_type englaciator, +void glaciate_freeze(monster* mon, killer_type englaciator, int kindex) { const coord_def where = mon->pos(); @@ -4388,9 +4269,9 @@ void bolt::monster_post_hit(monster* mon, int dmg) { - // Suppress the message for scattershot. + // Suppress the message for tremorstones. if (YOU_KILL(thrower) && you.see_cell(mon->pos()) - && name != "burst of metal fragments") + && name != "burst of rock shards") { print_wounds(*mon); } @@ -4463,9 +4344,7 @@ knockback_actor(mon, dmg); - if (origin_spell == SPELL_DAZZLING_SPRAY) - _dazzle_monster(mon, agent()); - else if (origin_spell == SPELL_FLASH_FREEZE + if (origin_spell == SPELL_FLASH_FREEZE || name == "blast of ice" || origin_spell == SPELL_GLACIATE && !is_explosion) { @@ -4503,8 +4382,9 @@ return; const int distance = - (origin_spell == SPELL_FORCE_LANCE) - ? 1 + div_rand_round(ench_power, 40) : + (origin_spell == SPELL_FORCE_LANCE + || origin_spell == SPELL_ISKENDERUNS_MYSTIC_BLAST) + ? 2 + div_rand_round(ench_power, 50) : (origin_spell == SPELL_CHILLING_BREATH) ? 2 : 1; const int roll = origin_spell == SPELL_FORCE_LANCE @@ -4665,7 +4545,7 @@ } else { - mprf("The %s bounces off an invisible shield around %s!", + mprf("The %s reflects off an invisible shield around %s!", name.c_str(), mon->name(DESC_THE).c_str()); @@ -4756,7 +4636,24 @@ if (flavour == BEAM_MISSILE && item) { - ranged_attack attk(agent(true), mon, item, use_target_as_pos, agent()); + actor *ag = agent(true); + // if the immediate agent is now dead, check to see if we can get a + // usable agent by factoring in reflections. + // At this point, it is possible that the agent is the dummy monster + // associated with YOU_FAULTLESS. This case will cause + // "INVALID YOU_FAULTLESS" to show up in dprfs and mess up the to-hit, + // but it otherwise works. + // TODO: is there a good way of handling the to-hit correctly? (And why + // should the to-hit be affected by reflections at all?) + // An alternative would be to stop the missile at this point. + if (!ag) + ag = agent(false); + // if that didn't work, blanket fall back on YOU_FAULTLESS. This covers + // a number of other weird penetration cases. + if (!ag) + ag = &menv[YOU_FAULTLESS]; + ASSERT(ag); + ranged_attack attk(ag, mon, item, use_target_as_pos, agent()); attk.attack(); // fsim purposes - throw_it detects if an attack connected through // hit_verb @@ -4801,9 +4698,8 @@ // We need to know how much the monster _would_ be hurt by this, // before we decide if it actually hits. - vector messages; int preac, postac, final; - if (!determine_damage(mon, preac, postac, final, messages)) + if (!determine_damage(mon, preac, postac, final)) return; #ifdef DEBUG_DIAGNOSTICS @@ -4822,13 +4718,7 @@ if (nasty_to(mon)) { if (YOU_KILL(thrower) && final > 0) - { - if (is_sanctuary(mon->pos()) || is_sanctuary(you.pos())) - remove_sanctuary(true); - - // It's not the player's fault if the monster couldn't be seen set_attack_conducts(conducts, *mon, you.can_see(*mon)); - } } if (engulfs && flavour == BEAM_SPORE // XXX: engulfs is redundant? @@ -4867,23 +4757,22 @@ defer_rand r; int rand_ev = random2(mon->evasion()); - int defl = mon->missile_deflection(); + bool repel = mon->missile_repulsion(); // FIXME: We're randomising mon->evasion, which is further // randomised inside test_beam_hit. This is so we stay close to the // 4.0 to-hit system (which had very little love for monsters). - if (!engulfs && !_test_beam_hit(beam_hit, rand_ev, pierce, defl, r)) + if (!engulfs && !_test_beam_hit(beam_hit, rand_ev, pierce, repel, r)) { - const bool deflected = _test_beam_hit(beam_hit, rand_ev, pierce, 0, r); + const bool repelled = _test_beam_hit(beam_hit, rand_ev, pierce, 0, r); // If the PLAYER cannot see the monster, don't tell them anything! if (mon->observable() && name != "burst of metal fragments") { // if it would have hit otherwise... if (_test_beam_hit(beam_hit, rand_ev, pierce, 0, r)) { - string deflects = (defl == 2) ? "deflects" : "repels"; msg::stream << mon->name(DESC_THE) << " " - << deflects << " the " << name + << "repels the " << name << '!' << endl; } else @@ -4892,8 +4781,8 @@ << mon->name(DESC_THE) << '.' << endl; } } - if (deflected) - mon->ablate_deflection(); + if (repelled) + mon->ablate_repulsion(); return; } @@ -4904,15 +4793,8 @@ // up a group of 8 plants and get placed under penance until the end of // time otherwise. I'd prefer to do this elsewhere but the beam information // goes out of scope. - // - // Also exempting miscast explosions from this conduct -cao - if (you_worship(GOD_FEDHAS) - && (flavour == BEAM_SPORE - || source_id == MID_PLAYER - && aux_source.find("your miscasting") != string::npos)) - { + if (you_worship(GOD_FEDHAS) && flavour == BEAM_SPORE) conducts[0].set(); - } if (!is_explosion && !noise_generated) { @@ -4951,12 +4833,6 @@ mprf(MSGCH_SOUND, "The %s hits something.", name.c_str()); } - if (final > 0) - { - for (const string &msg : messages) - mprf(MSGCH_MONSTER_DAMAGE, "%s", msg.c_str()); - } - // Apply flavoured specials. mons_adjust_flavoured(mon, *this, postac, true); @@ -4996,7 +4872,7 @@ && x_chance_in_y(3, 5)) { // Includes monster_die as part of converting to block of ice. - _glaciate_freeze(mon, thrower, kindex); + glaciate_freeze(mon, thrower, kindex); } // Prevent spore explosions killing plants from being registered // as a Fedhas misconduct. Deaths can trigger the ally dying or @@ -5006,7 +4882,7 @@ // FIXME: Should be a better way of doing this. For now, we are // just falsifying the death report... -cao else if (you_worship(GOD_FEDHAS) && flavour == BEAM_SPORE - && fedhas_protects(*mon)) + && fedhas_protects(mon)) { if (mon->attitude == ATT_FRIENDLY) mon->attitude = ATT_HOSTILE; @@ -5163,7 +5039,7 @@ break; case BEAM_INNER_FLAME: - rc = !(mon->is_summoned() || mon->has_ench(ENCH_INNER_FLAME)); + rc = !mon->has_ench(ENCH_INNER_FLAME); break; case BEAM_PETRIFY: @@ -5178,6 +5054,12 @@ rc = !mons_aligned(&you, mon) && you.can_constrict(mon, false); break; + // These are special allies whose loyalty can't be so easily bent + case BEAM_ENSLAVE: + rc = !(mons_is_hepliaklqana_ancestor(mon->type) + || testbits(mon->flags, MF_DEMONIC_GUARDIAN)); + break; + default: break; } @@ -5473,7 +5355,7 @@ case BEAM_SPORE: case BEAM_CONFUSION: case BEAM_IRRESISTIBLE_CONFUSION: - if (mon->check_clarity(false)) + if (mon->check_clarity()) { if (you.can_see(*mon)) obvious_effect = true; @@ -5583,7 +5465,6 @@ case BEAM_INNER_FLAME: if (!mon->has_ench(ENCH_INNER_FLAME) - && !mon->is_summoned() && mon->add_ench(mon_enchant(ENCH_INNER_FLAME, 0, agent()))) { if (simple_monster_message(*mon, @@ -5760,15 +5641,21 @@ // Non-beams can only affect one thing (player/monster). if (!pierce) used = BEAM_STOP; - else if (is_enchantment() && name != "line pass") - used = (flavour == BEAM_DIGGING ? 0 : BEAM_STOP); - // Damnation stops for nobody! - else if (flavour == BEAM_DAMNATION) + // These beams fully penetrate regardless of anything else. + else if (flavour == BEAM_DAMNATION + || flavour == BEAM_DIGGING + || flavour == BEAM_VILE_CLUTCH) + { used = 0; - // Generic explosion. - else if (is_explosion || is_big_cloud()) + } + // Other enchants that aren't Line Pass and explosions/clouds stop. + else if (is_enchantment() && name != "line pass" + || is_explosion + || is_big_cloud()) + { used = BEAM_STOP; - // Lightning goes through things. + } + // Lightning that isn't an explosion goes through things. else if (flavour == BEAM_ELECTRICITY) used = 0; else @@ -5992,7 +5879,7 @@ // Not an "explosion", but still a bit noisy at the target location. if (origin_spell == SPELL_INFESTATION - || origin_spell == SPELL_BORGNJORS_VILE_CLUTCH) + || origin_spell == SPELL_DAZZLING_FLASH) { loudness = spell_effect_noise(origin_spell); } @@ -6145,6 +6032,7 @@ // those and simplify feat_is_wall() to return true for trees. -gammafunk if (feat_is_wall(dngn_feat) || feat_is_tree(dngn_feat) + && !can_burn_trees() || feat_is_closed_door(dngn_feat)) { // Special case: explosion originates from rock/statue @@ -6235,8 +6123,6 @@ return !mons_aligned(mon, agent()); case BEAM_TELEPORT: case BEAM_BECKONING: - // Friendly and good neutral monsters don't mind being teleported. - return !mon->wont_attack(); case BEAM_INFESTATION: case BEAM_VILE_CLUTCH: case BEAM_SLOW: @@ -6424,12 +6310,6 @@ if (flavour == BEAM_ELECTRICITY && pierce) return "lightning"; - if (origin_spell == SPELL_ISKENDERUNS_MYSTIC_BLAST - || origin_spell == SPELL_DAZZLING_SPRAY) - { - return "energy"; - } - if (name == "bolt of dispelling energy") return "dispelling energy"; @@ -6460,7 +6340,7 @@ case BEAM_ACID: return "acid"; case BEAM_MIASMA: return "miasma"; case BEAM_SPORE: return "spores"; - case BEAM_POISON_ARROW: return "poison arrow"; + case BEAM_POISON_ARROW: return "poison sting"; case BEAM_DAMNATION: return "damnation"; case BEAM_STICKY_FLAME: return "sticky fire"; case BEAM_STEAM: return "steam"; @@ -6558,7 +6438,8 @@ return flavour == BEAM_WATER && origin_spell == SPELL_PRIMAL_WAVE || origin_spell == SPELL_CHILLING_BREATH && act.airborne() - || origin_spell == SPELL_FORCE_LANCE && dam; + || origin_spell == SPELL_FORCE_LANCE && dam + || origin_spell == SPELL_ISKENDERUNS_MYSTIC_BLAST && dam; } /** @@ -6624,12 +6505,14 @@ monster* temp = originator->as_monster(); if (!temp) return false; - origin_worships_fedhas = temp->god == GOD_FEDHAS; + origin_worships_fedhas = (temp->god == GOD_FEDHAS + || (temp->friendly() + && have_passive(passive_t::shoot_through_plants))); origin_attitude = temp->attitude; } return (origin_worships_fedhas - && fedhas_protects(*victim)) + && fedhas_protects(victim)) || (originator->is_player() && testbits(victim->flags, MF_DEMONIC_GUARDIAN)) && !beam.is_enchantment() @@ -6650,7 +6533,7 @@ */ int omnireflect_chance_denom(int SH) { - return SH + 40; + return SH + 20; } /// Set up a beam aiming from the given monster to their target. diff -Nru crawl-0.24.0/source/beam.h crawl-0.25.0/source/beam.h --- crawl-0.24.0/source/beam.h 2019-08-27 00:35:36.000000000 +0000 +++ crawl-0.25.0/source/beam.h 2020-05-23 16:07:19.000000000 +0000 @@ -232,8 +232,7 @@ void emit_message(const char* msg); int apply_AC(const actor* victim, int hurted); - bool determine_damage(monster* mon, int& preac, int& postac, int& final, - vector &messages); + bool determine_damage(monster* mon, int& preac, int& postac, int& final); // Functions which handle actually affecting things. They all // operate on the beam's current position (i.e., whatever pos() @@ -263,9 +262,9 @@ void handle_stop_attack_prompt(monster* mon); bool attempt_block(monster* mon); void update_hurt_or_helped(monster* mon); - mon_resist_type try_enchant_monster(monster* mon, int &res_margin); void enchantment_affect_monster(monster* mon); public: + mon_resist_type try_enchant_monster(monster* mon, int &res_margin); mon_resist_type apply_enchantment_to_monster(monster* mon); void apply_beam_conducts(); private: @@ -322,8 +321,6 @@ int silver_damages_victim(actor* victim, int damage, string &dmg_msg); void fire_tracer(const monster* mons, bolt &pbolt, bool explode_only = false, bool explosion_hole = false); -bool imb_can_splash(coord_def origin, coord_def center, - vector path_taken, coord_def target); spret zapping(zap_type ztype, int power, bolt &pbolt, bool needs_tracer = false, const char* msg = nullptr, bool fail = false); @@ -345,4 +342,7 @@ int omnireflect_chance_denom(int SH); +void glaciate_freeze(monster* mon, killer_type englaciator, + int kindex); + bolt setup_targetting_beam(const monster &mons); diff -Nru crawl-0.24.0/source/bloodspatter.cc crawl-0.25.0/source/bloodspatter.cc --- crawl-0.24.0/source/bloodspatter.cc 2017-04-28 07:04:16.000000000 +0000 +++ crawl-0.25.0/source/bloodspatter.cc 2020-05-23 16:07:19.000000000 +0000 @@ -144,11 +144,13 @@ env.pgrid(where) |= FPROP_BLOODY; _orient_wall_blood(where, from, old_blood); + // Don't apply penance for involuntary cloud placement. if (ignite_blood && !cell_is_solid(where) && !cloud_at(where)) { - place_cloud(CLOUD_FIRE, where, 5 + random2(6), &you); + place_cloud(CLOUD_FIRE, where, 5 + random2(6), &you, -1, -1, + false); } } diff -Nru crawl-0.24.0/source/book-data.h crawl-0.25.0/source/book-data.h --- crawl-0.24.0/source/book-data.h 2018-09-18 09:21:35.000000000 +0000 +++ crawl-0.25.0/source/book-data.h 2020-05-23 16:07:19.000000000 +0000 @@ -14,15 +14,13 @@ { // Book of Conjurations SPELL_MAGIC_DART, SPELL_SEARING_RAY, - SPELL_DAZZLING_SPRAY, + SPELL_DAZZLING_FLASH, SPELL_FULMINANT_PRISM, - SPELL_FORCE_LANCE, SPELL_ISKENDERUNS_MYSTIC_BLAST, }, { // Book of Flames - SPELL_FLAME_TONGUE, - SPELL_THROW_FLAME, + SPELL_FOXFIRE, SPELL_CONJURE_FLAME, SPELL_INNER_FLAME, SPELL_STICKY_FLAME, @@ -31,9 +29,9 @@ { // Book of Frost SPELL_FREEZE, - SPELL_THROW_FROST, + SPELL_FROZEN_RAMPARTS, SPELL_OZOCUBUS_ARMOUR, - SPELL_THROW_ICICLE, + SPELL_HAILSTORM, SPELL_SUMMON_ICE_BEAST, }, @@ -49,7 +47,7 @@ { // Book of Fire SPELL_IGNITE_POISON, SPELL_FIREBALL, - SPELL_BOLT_OF_FIRE, + SPELL_STARBURST, SPELL_RING_OF_FLAMES, SPELL_IGNITION, }, @@ -58,7 +56,6 @@ SPELL_ICE_FORM, SPELL_ENGLACIATION, SPELL_OZOCUBUS_REFRIGERATION, - SPELL_BOLT_OF_COLD, SPELL_FREEZING_CLOUD, SPELL_SIMULACRUM, }, @@ -72,11 +69,10 @@ SPELL_GOLUBRIAS_PASSAGE, }, -{ // Book of Enchantments +{ // Book of Hexes SPELL_CAUSE_FEAR, SPELL_VIOLENT_UNRAVELLING, SPELL_SILENCE, - SPELL_DEFLECT_MISSILES, SPELL_DISCORD, }, @@ -84,8 +80,8 @@ SPELL_STING, SPELL_POISONOUS_VAPOURS, SPELL_MEPHITIC_CLOUD, + SPELL_IGNITE_POISON, SPELL_OLGREBS_TOXIC_RADIANCE, - SPELL_VENOM_BOLT, }, { // Book of the Tempests @@ -99,15 +95,13 @@ { // Book of Death SPELL_CORPSE_ROT, SPELL_SUBLIMATION_OF_BLOOD, - SPELL_AGONY, SPELL_DISPEL_UNDEAD, + SPELL_AGONY, SPELL_EXCRUCIATING_WOUNDS, - SPELL_BOLT_OF_DRAINING, }, { // Book of Misfortune SPELL_CONFUSING_TOUCH, - SPELL_CONFUSE, SPELL_GRAVITAS, SPELL_PETRIFY, SPELL_ENGLACIATION, @@ -132,8 +126,8 @@ { // Fen Folio SPELL_CORPSE_ROT, SPELL_STONE_ARROW, - SPELL_LEDAS_LIQUEFACTION, SPELL_SUMMON_FOREST, + SPELL_NOXIOUS_BOG, SPELL_HYDRA_FORM, SPELL_SUMMON_HYDRA, }, @@ -143,8 +137,8 @@ SPELL_INFUSION, SPELL_SHROUD_OF_GOLUBRIA, SPELL_SONG_OF_SLAYING, + SPELL_OZOCUBUS_ARMOUR, SPELL_SPECTRAL_WEAPON, - SPELL_REGENERATION, }, #endif { // Book of Clouds @@ -159,8 +153,8 @@ SPELL_PAIN, SPELL_ANIMATE_SKELETON, SPELL_VAMPIRIC_DRAINING, - SPELL_REGENERATION, SPELL_ANIMATE_DEAD, + SPELL_AGONY, }, { // Book of Callings @@ -175,9 +169,9 @@ { // Book of Maledictions SPELL_CORONA, SPELL_HIBERNATION, - SPELL_CONFUSE, + SPELL_CONFUSING_TOUCH, SPELL_TUKIMAS_DANCE, - SPELL_DAZZLING_SPRAY, + SPELL_DAZZLING_FLASH, }, { // Book of Air @@ -191,7 +185,6 @@ { // Book of the Sky SPELL_SUMMON_LIGHTNING_SPIRE, SPELL_SILENCE, - SPELL_DEFLECT_MISSILES, SPELL_CONJURE_BALL_LIGHTNING, SPELL_TORNADO, }, @@ -199,7 +192,6 @@ { // Book of the Warp SPELL_GRAVITAS, SPELL_PORTAL_PROJECTILE, - SPELL_FORCE_LANCE, SPELL_DISPERSAL, SPELL_CONTROLLED_BLINK, SPELL_DISJUNCTION, @@ -230,8 +222,8 @@ SPELL_INFUSION, SPELL_SHROUD_OF_GOLUBRIA, SPELL_SONG_OF_SLAYING, + SPELL_OZOCUBUS_ARMOUR, SPELL_SPECTRAL_WEAPON, - SPELL_REGENERATION, }, #endif @@ -253,7 +245,6 @@ #if TAG_MAJOR_VERSION == 34 { // Book of Wizardry - SPELL_FORCE_LANCE, SPELL_AGONY, SPELL_INVISIBILITY, SPELL_SPELLFORGED_SERVITOR, @@ -262,7 +253,6 @@ { // Book of Power SPELL_BATTLESPHERE, - SPELL_VENOM_BOLT, SPELL_BOLT_OF_MAGMA, SPELL_IRON_SHOT, SPELL_IOOD, @@ -270,7 +260,7 @@ }, { // Book of Cantrips - SPELL_CONFUSING_TOUCH, + SPELL_CORONA, SPELL_ANIMATE_SKELETON, SPELL_SUMMON_SMALL_MAMMAL, SPELL_APPORTATION, @@ -304,9 +294,8 @@ }, { // Book of the Dragon - SPELL_FLAME_TONGUE, + SPELL_FOXFIRE, SPELL_CAUSE_FEAR, - SPELL_BOLT_OF_FIRE, SPELL_DRAGON_FORM, SPELL_DRAGON_CALL, }, @@ -334,6 +323,7 @@ SPELL_PETRIFY, SPELL_INTOXICATE, SPELL_IRRADIATE, + SPELL_NOXIOUS_BOG, }, { // Book of Beasts @@ -345,10 +335,9 @@ }, { // Book of Annihilations - SPELL_POISON_ARROW, SPELL_CHAIN_LIGHTNING, SPELL_LEHUDIBS_CRYSTAL_SPEAR, - SPELL_GLACIATE, + SPELL_ABSOLUTE_ZERO, SPELL_FIRE_STORM, }, diff -Nru crawl-0.24.0/source/book-type.h crawl-0.25.0/source/book-type.h --- crawl-0.24.0/source/book-type.h 2017-04-28 07:04:16.000000000 +0000 +++ crawl-0.25.0/source/book-type.h 2020-05-23 16:07:19.000000000 +0000 @@ -10,7 +10,7 @@ BOOK_FIRE, BOOK_ICE, BOOK_SPATIAL_TRANSLOCATIONS, - BOOK_ENCHANTMENTS, + BOOK_HEXES, BOOK_YOUNG_POISONERS, BOOK_TEMPESTS, BOOK_DEATH, Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/._branch.cc and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/._branch.cc differ diff -Nru crawl-0.24.0/source/branch.cc crawl-0.25.0/source/branch.cc --- crawl-0.24.0/source/branch.cc 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/source/branch.cc 2020-05-23 16:07:19.000000000 +0000 @@ -105,6 +105,14 @@ }; COMPILE_CHECK(ARRAYSZ(danger_branch_order) == NUM_BRANCHES); +static const int number_of_branch_swap_pairs = 2; + +static const branch_type swap_branches[number_of_branch_swap_pairs][2] = +{ + {BRANCH_SHOALS, BRANCH_SWAMP}, + {BRANCH_SPIDER, BRANCH_SNAKE} +}; + branch_iterator::branch_iterator(branch_iterator_type type) : iter_type(type), i(0) { @@ -149,6 +157,18 @@ return copy; } +vector random_choose_disabled_branches() +{ + // You will get one of Shoals/Swamp and one of Spider/Snake. + // This way you get one "water" branch and one "poison" branch. + vector disabled_branch; + + for (int i=0; i < number_of_branch_swap_pairs; i++) + disabled_branch.push_back(swap_branches[i][random_choose(0,1)]); + + return disabled_branch; +} + const Branch& your_branch() { return branches[you.where_are_you]; @@ -182,8 +202,16 @@ bool is_random_subbranch(branch_type branch) { - return parent_branch(branch) == BRANCH_LAIR - && branch != BRANCH_SLIME; + for (int i=0; i < number_of_branch_swap_pairs; i++) + { + for (int j=0; j < 2; j++) + { + if (branch == swap_branches[i][j]) + return true; + } + } + + return false; } bool is_connected_branch(const Branch *branch) @@ -250,6 +278,8 @@ { return true; } +#else + UNUSED(branch); #endif return false; } diff -Nru crawl-0.24.0/source/branch-data.h crawl-0.25.0/source/branch-data.h --- crawl-0.24.0/source/branch-data.h 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/source/branch-data.h 2020-05-23 16:07:19.000000000 +0000 @@ -363,3 +363,8 @@ '!', {}, branch_noise::normal }, #endif }; + +/* + * There's a few more constant data structures related to branches in + * the early parts of branch.cc (Example: danger_branch_order) + */ diff -Nru crawl-0.24.0/source/branch-data-json.cc crawl-0.25.0/source/branch-data-json.cc --- crawl-0.24.0/source/branch-data-json.cc 1970-01-01 00:00:00.000000000 +0000 +++ crawl-0.25.0/source/branch-data-json.cc 2020-05-23 16:07:19.000000000 +0000 @@ -0,0 +1,38 @@ +/** + * @file + * @brief Provide branch data as JSON + */ + +#include "AppHdr.h" + +#include "branch-data-json.h" + +#include "json.h" +#include "json-wrapper.h" + +#include "branch.h" +#include "stringutil.h" // to_string on Cygwin + +static JsonNode *_branch_info_array() +{ + JsonNode *br(json_mkarray()); + for (branch_iterator it; it; ++it) + { + JsonNode *branch_info(json_mkobject()); + json_append_member(branch_info, "name", json_mkstring(it->shortname)); + json_append_member(branch_info, "long_name", + json_mkstring(it->longname)); + json_append_member(branch_info, "levels", json_mknumber(it->numlevels)); + json_append_member(branch_info, "has_rune", + json_mkbool(it->runes.size() > 0 ? true : false)); + json_append_element(br, branch_info); + } + return br; +} + +string branch_data_json() +{ + JsonWrapper json(json_mkobject()); + json_append_member(json.node, "branches", _branch_info_array()); + return json.to_string(); +} diff -Nru crawl-0.24.0/source/branch-data-json.h crawl-0.25.0/source/branch-data-json.h --- crawl-0.24.0/source/branch-data-json.h 1970-01-01 00:00:00.000000000 +0000 +++ crawl-0.25.0/source/branch-data-json.h 2020-05-23 16:07:19.000000000 +0000 @@ -0,0 +1,3 @@ +#pragma once + +string branch_data_json(); diff -Nru crawl-0.24.0/source/branch.h crawl-0.25.0/source/branch.h --- crawl-0.24.0/source/branch.h 2019-04-21 05:54:24.000000000 +0000 +++ crawl-0.25.0/source/branch.h 2020-05-23 16:07:19.000000000 +0000 @@ -116,3 +116,5 @@ string branch_noise_desc(branch_type br); string branch_rune_desc(branch_type br, bool remaining_only); branch_type rune_location(rune_type rune); + +vector random_choose_disabled_branches(); Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/._branch-type.h and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/._branch-type.h differ diff -Nru crawl-0.24.0/source/butcher.cc crawl-0.25.0/source/butcher.cc --- crawl-0.24.0/source/butcher.cc 2019-06-04 23:37:08.000000000 +0000 +++ crawl-0.25.0/source/butcher.cc 2020-05-23 16:07:19.000000000 +0000 @@ -15,7 +15,6 @@ #include "food.h" #include "god-conduct.h" #include "item-name.h" -#include "item-prop.h" #include "item-status-flag-type.h" #include "items.h" #include "libutil.h" @@ -24,7 +23,6 @@ #include "message.h" #include "options.h" #include "output.h" -#include "prompt.h" #include "rot.h" #include "stash.h" #include "stepdown.h" @@ -79,13 +77,6 @@ StashTrack.update_stash(you.pos()); // Stash-track the generated items. } -#ifdef TOUCH_UI -static string _butcher_menu_title(const Menu *menu, const string &oldt) -{ - return oldt; -} -#endif - static int _corpse_quality(const item_def &item) { return 3 * item.freshness; @@ -197,8 +188,7 @@ meat.push_back(entry.first); vector selected = - select_items(meat, "Choose a corpse to butcher", - false, menu_type::any, _butcher_menu_title); + select_items(meat, "Choose a corpse to butcher", false, menu_type::any); redraw_screen(); for (SelItem sel : selected) if (_start_butchering(const_cast(*sel.item))) Binary files /tmp/tmpZDJPUY/sMkn6Fyfck/crawl-0.24.0/source/catch2-tests/._catch.hpp and /tmp/tmpZDJPUY/zT9CgXbcWL/crawl-0.25.0/source/catch2-tests/._catch.hpp differ diff -Nru crawl-0.24.0/source/catch2-tests/catch.hpp crawl-0.25.0/source/catch2-tests/catch.hpp --- crawl-0.24.0/source/catch2-tests/catch.hpp 1970-01-01 00:00:00.000000000 +0000 +++ crawl-0.25.0/source/catch2-tests/catch.hpp 2020-05-23 16:07:19.000000000 +0000 @@ -0,0 +1,17603 @@ +/* + * Catch v2.11.0 + * Generated: 2019-11-15 15:01:56.628356 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 11 +#define CATCH_VERSION_PATCH 0 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +#if defined(__UCLIBC__) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template