You can subscribe to this list here.
| 2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(15) |
Sep
(131) |
Oct
(149) |
Nov
(216) |
Dec
(222) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2007 |
Jan
(152) |
Feb
(58) |
Mar
(184) |
Apr
(249) |
May
(96) |
Jun
(207) |
Jul
(248) |
Aug
(87) |
Sep
(232) |
Oct
(440) |
Nov
(248) |
Dec
(212) |
| 2008 |
Jan
(216) |
Feb
(118) |
Mar
(508) |
Apr
(796) |
May
(597) |
Jun
(896) |
Jul
(475) |
Aug
(124) |
Sep
(200) |
Oct
(248) |
Nov
(377) |
Dec
(373) |
| 2009 |
Jan
(807) |
Feb
(430) |
Mar
(276) |
Apr
(138) |
May
(161) |
Jun
(210) |
Jul
(390) |
Aug
(141) |
Sep
(286) |
Oct
(826) |
Nov
(1123) |
Dec
(419) |
| 2010 |
Jan
(671) |
Feb
(625) |
Mar
(328) |
Apr
(349) |
May
(296) |
Jun
(485) |
Jul
(396) |
Aug
(113) |
Sep
(582) |
Oct
(414) |
Nov
(248) |
Dec
(377) |
| 2011 |
Jan
(400) |
Feb
(225) |
Mar
(321) |
Apr
(264) |
May
(148) |
Jun
(249) |
Jul
(270) |
Aug
(217) |
Sep
(262) |
Oct
(356) |
Nov
(426) |
Dec
(359) |
| 2012 |
Jan
(203) |
Feb
(131) |
Mar
(317) |
Apr
(313) |
May
(170) |
Jun
(272) |
Jul
(363) |
Aug
(364) |
Sep
(330) |
Oct
(188) |
Nov
(178) |
Dec
(141) |
| 2013 |
Jan
(177) |
Feb
(258) |
Mar
(459) |
Apr
(352) |
May
(443) |
Jun
(364) |
Jul
(185) |
Aug
(175) |
Sep
(242) |
Oct
(237) |
Nov
(359) |
Dec
(300) |
| 2014 |
Jan
(331) |
Feb
(272) |
Mar
(446) |
Apr
(301) |
May
(577) |
Jun
(435) |
Jul
(365) |
Aug
(358) |
Sep
(306) |
Oct
(617) |
Nov
(863) |
Dec
(466) |
| 2015 |
Jan
(295) |
Feb
(165) |
Mar
(319) |
Apr
(201) |
May
(158) |
Jun
(148) |
Jul
(62) |
Aug
(91) |
Sep
(147) |
Oct
(203) |
Nov
(346) |
Dec
(382) |
| 2016 |
Jan
(242) |
Feb
(280) |
Mar
(229) |
Apr
(157) |
May
(297) |
Jun
(335) |
Jul
(157) |
Aug
(219) |
Sep
(307) |
Oct
(212) |
Nov
(177) |
Dec
(112) |
| 2017 |
Jan
(100) |
Feb
(203) |
Mar
(112) |
Apr
(124) |
May
(81) |
Jun
(43) |
Jul
(39) |
Aug
(49) |
Sep
(24) |
Oct
(55) |
Nov
(68) |
Dec
(95) |
| 2018 |
Jan
(130) |
Feb
(73) |
Mar
(47) |
Apr
(57) |
May
(62) |
Jun
(76) |
Jul
(159) |
Aug
(158) |
Sep
(81) |
Oct
(100) |
Nov
(62) |
Dec
(75) |
| 2019 |
Jan
(130) |
Feb
(138) |
Mar
(80) |
Apr
(61) |
May
(88) |
Jun
(65) |
Jul
(61) |
Aug
(37) |
Sep
(85) |
Oct
(155) |
Nov
(133) |
Dec
(91) |
| 2020 |
Jan
(59) |
Feb
(123) |
Mar
(121) |
Apr
(155) |
May
(300) |
Jun
(136) |
Jul
(330) |
Aug
(84) |
Sep
(56) |
Oct
(87) |
Nov
(154) |
Dec
(200) |
| 2021 |
Jan
(205) |
Feb
(203) |
Mar
(292) |
Apr
(165) |
May
(56) |
Jun
(135) |
Jul
(248) |
Aug
(218) |
Sep
(165) |
Oct
(150) |
Nov
(135) |
Dec
(266) |
| 2022 |
Jan
(194) |
Feb
(149) |
Mar
(49) |
Apr
(38) |
May
(145) |
Jun
(213) |
Jul
(150) |
Aug
(126) |
Sep
(188) |
Oct
(121) |
Nov
(34) |
Dec
(142) |
| 2023 |
Jan
(105) |
Feb
(82) |
Mar
(138) |
Apr
(125) |
May
(112) |
Jun
(90) |
Jul
(222) |
Aug
(279) |
Sep
(157) |
Oct
(100) |
Nov
(85) |
Dec
(295) |
| 2024 |
Jan
(123) |
Feb
(353) |
Mar
(220) |
Apr
(112) |
May
(162) |
Jun
(169) |
Jul
(205) |
Aug
(174) |
Sep
(73) |
Oct
(62) |
Nov
(95) |
Dec
(62) |
| 2025 |
Jan
(125) |
Feb
(90) |
Mar
(127) |
Apr
(188) |
May
(74) |
Jun
(59) |
Jul
(154) |
Aug
(117) |
Sep
(125) |
Oct
(157) |
Nov
(251) |
Dec
(177) |
| 2026 |
Jan
(115) |
Feb
(50) |
Mar
(63) |
Apr
(27) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: <gi...@cr...> - 2026-04-23 04:00:12
|
via 287807233436df280ed97f31ba3b48f7ffebedb7 (commit)
from 2ccebcafee383c5a585bbd620becca6dc0b6cb3e (commit)
-----------------------------------------------------------------------
commit 287807233436df280ed97f31ba3b48f7ffebedb7
Author: Isaac Clancy <ik...@ya...>
Date: Thu Apr 23 15:42:37 2026 +1200
Fix RTILE not respecting tile variant weights
When RTILE was used to define vault rock wall tiles, it picked its tile
variations completely at random, ignoring the weight values defined for
them. If the level containing these tiles was reloading, the variations
would be rechoosen in a way that respected weights often resulting in
different tile variations being used.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/mapdef.cc | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index 5f0c36d72e..7c79ce37be 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -647,7 +647,6 @@ void map_lines::apply_grid_overlay(const coord_def &c, bool is_layout)
if (colour)
floor = tile_dngn_coloured(floor, colour);
tile_env.flv(gc).floor = floor;
- tile_init_flavour(gc);
has_floor = true;
}
@@ -661,11 +660,11 @@ void map_lines::apply_grid_overlay(const coord_def &c, bool is_layout)
tile_dngn_index(name.c_str(), &rock);
if (colour)
rock = tile_dngn_coloured(rock, colour);
- int offset = random2(tile_dngn_count(rock));
- tile_env.flv(gc).wall = rock + offset;
+ tile_env.flv(gc).wall = rock;
has_rock = true;
}
+ bool has_tile = false;
name = (*overlay)(x, y).tile;
if (!name.empty() && name != "none")
{
@@ -684,7 +683,10 @@ void map_lines::apply_grid_overlay(const coord_def &c, bool is_layout)
tile_env.flv(gc).wall = feat;
else
tile_env.flv(gc).feat = feat;
+ has_tile = true;
}
+ if (has_floor || has_rock || has_tile)
+ tile_init_flavour(gc);
}
}
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-23 02:00:12
|
via 2ccebcafee383c5a585bbd620becca6dc0b6cb3e (commit)
from a3442ab72342427785c0939ac2aa527eaa525d39 (commit)
-----------------------------------------------------------------------
commit 2ccebcafee383c5a585bbd620becca6dc0b6cb3e
Author: Isaac Clancy <ik...@ya...>
Date: Thu Apr 23 13:45:05 2026 +1200
Fix tile variation duplicate detection
It shouldn't be possible to for example specify that the randart version
of the BROAD_AXE tile is BROAD_AXE_MAGIC as well as specify that it is
BROAD_AXE_RANDART. However, our duplicate tile variation detection was
failing to detect this which resulted in the tile applied to randart
broad axes being dependent on the implementation std::sort.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/rltiles/dc-player.txt | 2 +-
.../source/rltiles/tool/tile_list_processor.cc | 73 +++++++++-------------
.../source/rltiles/tool/tile_list_processor.h | 18 ++----
3 files changed, 36 insertions(+), 57 deletions(-)
diff --git a/crawl-ref/source/rltiles/dc-player.txt b/crawl-ref/source/rltiles/dc-player.txt
index 15223dc745..fd611c45dc 100644
--- a/crawl-ref/source/rltiles/dc-player.txt
+++ b/crawl-ref/source/rltiles/dc-player.txt
@@ -931,7 +931,7 @@ war_axe WAR_AXE
%enchant_variation WAR_AXE shiny runed glowing randart
war_axe2 WAR_AXE_MAGIC
broad_axe BROAD_AXE
-%enchant_variation BROAD_AXE shiny runed glowing randart
+%enchant_variation BROAD_AXE shiny runed glowing
broad_axe2 BROAD_AXE_MAGIC
%enchant_variation BROAD_AXE randart
broad_axe3 BROAD_AXE_RANDART
diff --git a/crawl-ref/source/rltiles/tool/tile_list_processor.cc b/crawl-ref/source/rltiles/tool/tile_list_processor.cc
index db27a0935a..d5b74170b3 100644
--- a/crawl-ref/source/rltiles/tool/tile_list_processor.cc
+++ b/crawl-ref/source/rltiles/tool/tile_list_processor.cc
@@ -253,12 +253,6 @@ bool tile_list_processor::variation::operator<(
return variety < other.variety;
}
-bool tile_list_processor::pending_variation::operator==(
- const pending_variation& other) const noexcept
-{
- return idx == other.idx && variety == other.variety;
-}
-
void tile_list_processor::recolour(tile &img)
{
for (int y = 0; y < img.height(); ++y)
@@ -765,16 +759,13 @@ bool tile_list_processor::process_line(char *read_line, const char *list_file,
list_file, line, m_args[i]);
return false;
}
- pending_variation new_v{(unsigned int)idx, colour};
- for (pending_variation v : m_pending_colour_variations)
+ variation new_v{(unsigned int)idx, colour};
+ if (!m_colour_variations.insert({new_v, -1}).second)
{
- if (new_v == v)
- {
- fprintf(stderr,
- "Error (%s:%d): duplicate colour variation'\n",
- list_file, line);
- return false;
- }
+ fprintf(stderr,
+ "Error (%s:%d): duplicate colour variation'\n",
+ list_file, line);
+ return false;
}
m_pending_colour_variations.push_back(new_v);
}
@@ -800,16 +791,13 @@ bool tile_list_processor::process_line(char *read_line, const char *list_file,
list_file, line, m_args[i]);
return false;
}
- pending_variation new_v{(unsigned int)idx, enchant};
- for (pending_variation v : m_pending_enchant_variations)
+ variation new_v{(unsigned int)idx, enchant};
+ if (!m_enchant_variations.insert({new_v, -1}).second)
{
- if (new_v == v)
- {
- fprintf(stderr,
+ fprintf(stderr,
"Error (%s:%d): duplicate enchant variation'\n",
list_file, line);
- return false;
- }
+ return false;
}
m_pending_enchant_variations.push_back(new_v);
}
@@ -1013,18 +1001,12 @@ void tile_list_processor::add_image(tile &img, const char *enumname)
if (!m_categories.empty())
m_ctg_counts[m_categories.size()-1]++;
- for (pending_variation v : m_pending_colour_variations)
- {
- variation new_v{v.idx, m_last_enum, v.variety};
- m_colour_variations.push_back(new_v);
- }
+ for (variation v : m_pending_colour_variations)
+ m_colour_variations[v] = m_last_enum;
m_pending_colour_variations.clear();
- for (pending_variation v : m_pending_enchant_variations)
- {
- variation new_v{v.idx, m_last_enum, v.variety};
- m_enchant_variations.push_back(new_v);
- }
+ for (variation v : m_pending_enchant_variations)
+ m_enchant_variations[v] = m_last_enum;
m_pending_enchant_variations.clear();
}
@@ -1086,9 +1068,6 @@ bool tile_list_processor::write_data(bool image, bool code)
return false;
}
- std::sort(m_colour_variations.begin(), m_colour_variations.end());
- std::sort(m_enchant_variations.begin(), m_enchant_variations.end());
-
string lcname = m_name;
string ucname = m_name;
for (unsigned int i = 0; i < m_name.size(); i++)
@@ -1515,12 +1494,16 @@ bool tile_list_processor::write_data(bool image, bool code)
" _variation_pair(tile_variation(0, 0), 0),\n",
lcname.c_str());
- for (variation v : m_colour_variations)
+ for (const pair<variation, int>& v : m_colour_variations)
{
+ int to_idx = v.second;
+ if (to_idx < 0)
+ continue;
+
fprintf(fp,
- " _variation_pair(tile_variation(%u + %s, %d), %u + %s),\n",
- v.from_idx, m_start_value.c_str(), v.variety, v.to_idx,
- m_start_value.c_str());
+ " _variation_pair(tile_variation(%u + %s, %d), %d + %s),\n",
+ v.first.from_idx, m_start_value.c_str(), v.first.variety,
+ to_idx, m_start_value.c_str());
}
fprintf(fp, "%s", "};\n\n");
@@ -1544,12 +1527,16 @@ bool tile_list_processor::write_data(bool image, bool code)
" _variation_pair(tile_variation(0, 0), 0),\n",
lcname.c_str());
- for (variation v : m_enchant_variations)
+ for (const pair<variation, int>& v : m_enchant_variations)
{
+ int to_idx = v.second;
+ if (to_idx < 0)
+ continue;
+
fprintf(fp,
- " _variation_pair(tile_variation(%u + %s, %d), %u + %s),\n",
- v.from_idx, m_start_value.c_str(), v.variety, v.to_idx,
- m_start_value.c_str());
+ " _variation_pair(tile_variation(%u + %s, %d), %d + %s),\n",
+ v.first.from_idx, m_start_value.c_str(), v.first.variety,
+ to_idx, m_start_value.c_str());
}
fprintf(fp, "%s", "};\n\n");
diff --git a/crawl-ref/source/rltiles/tool/tile_list_processor.h b/crawl-ref/source/rltiles/tool/tile_list_processor.h
index 6ca1089484..aba17ebe54 100644
--- a/crawl-ref/source/rltiles/tool/tile_list_processor.h
+++ b/crawl-ref/source/rltiles/tool/tile_list_processor.h
@@ -3,6 +3,7 @@
#include "tile.h"
#include "tile_page.h"
+#include <map>
#include <string>
#include <vector>
#include <stdio.h>
@@ -33,20 +34,11 @@ protected:
struct variation
{
unsigned int from_idx;
- unsigned int to_idx;
int variety;
bool operator<(const variation& other) const noexcept;
};
- struct pending_variation
- {
- unsigned int idx;
- int variety;
-
- bool operator==(const pending_variation& other) const noexcept;
- };
-
string m_name;
tile_page m_page;
@@ -70,10 +62,10 @@ protected:
vector<int> m_ctg_counts;
tile m_compose;
tile* m_texture;
- vector<pending_variation> m_pending_colour_variations;
- vector<variation> m_colour_variations;
- vector<pending_variation> m_pending_enchant_variations;
- vector<variation> m_enchant_variations;
+ vector<variation> m_pending_colour_variations;
+ map<variation, int> m_colour_variations;
+ vector<variation> m_pending_enchant_variations;
+ map<variation, int> m_enchant_variations;
int m_weight;
double m_alpha;
int m_domino;
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-22 03:55:09
|
via a3442ab72342427785c0939ac2aa527eaa525d39 (commit)
from a3715956db52052361ef25ae05bf469948de5578 (commit)
-----------------------------------------------------------------------
commit a3442ab72342427785c0939ac2aa527eaa525d39
Author: CrawlOdds <cra...@gm...>
Date: Fri Apr 17 21:58:57 2026 +0100
Fix hurling and don't apply infusion to throwing
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/attack.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crawl-ref/source/attack.cc b/crawl-ref/source/attack.cc
index 4dcded0000..42aea9c6ff 100644
--- a/crawl-ref/source/attack.cc
+++ b/crawl-ref/source/attack.cc
@@ -862,7 +862,7 @@ int attack::player_apply_slaying_bonuses(int damage, bool aux)
if (!aux && using_weapon())
damage_plus = get_weapon_plus();
- const bool throwing = !weapon && wpn_skill == SK_THROWING;
+ const bool throwing = wpn_skill == SK_THROWING;
const bool ranged = throwing
|| (weapon && is_range_weapon(*weapon)
&& using_weapon());
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-22 03:25:18
|
via a3715956db52052361ef25ae05bf469948de5578 (commit)
from 0a58930ff6185faeb40e5dcefd2981b417a6e95b (commit)
-----------------------------------------------------------------------
commit a3715956db52052361ef25ae05bf469948de5578
Author: Isaac Clancy <ik...@ya...>
Date: Thu Apr 16 14:49:32 2026 +1200
Fix info leaks from feature tile overrides (CrawlOdds)
When creating temporary terrain, we either clear or replace any
existing tile override and then restore it when the temporary terrain
ends. This is helpful as for example if you use summon forest to create
a tree on a square that contained a wall with a tile override you
wouldn't want the tree to use the tile override for the wall.
However, we were drawing the feature that the player remembered being at
a square with the current tile override for the square. This could leak
whether the feature in the square had changed since the player had last
seen it, so we were using a number of hacks to try and prevent this.
One of these hacks was that we wouldn't use the tile override when
drawing types of terrain that are used by temporary terrain. This would
prevent a problem in cases such as when the player had seen a tree from
summon forest on a square that used to have a wall with a tile override
then moved out of view of it then waited for summon forest to end as
this would result in there being a remembered tree with the tile
override from the wall that currently exists in the square. However,
this doesn't work for all terrain types that can be created by temporary
terrain as we want to use tile overrides for some of these terrain
types. Also, the list of terrain types to not use tile overrides on was
not being updated when adding new types of temporary terrain. Another
hack that we were using is that we would always draw some terrain using
the tile override that the square would have if it didn't have temporary
terrain (which can be extracted from the temporary terrain marker if
needed). We did this for terrain types that aren't created by temporary
terrain but can have temporary terrain created on them. This would
prevent an information leak where creating temporary terrain out of view
(such as some of the trees from summon forest) would cause the
remembered terrain to be drawn with the tile override for the temporary
terrain revealing where the out of view temporary terrain had been
created. However, our list of terrain types to use for this was outdated
and also could never be perfect as many terrain types can both have
temporary terrain created on them and be temporary terrain. This hack
also seems to have been lost in a recent refactoring.
Instead of using these hacks, store the remembered tile override for
squares the player has seen and magic mapped and use this for drawing.
A side effect of this change is that dead trees in Crypt now use the
dead tree tile when magic mapped rather than the living tree tile as
they have a tile override that used to be unused (non-magic mapped dead
trees in Crypt were able to got there dead tree tile through their grid
colour).
Fixes #5168
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/abyss.cc | 1 +
crawl-ref/source/dungeon.cc | 1 +
crawl-ref/source/files.cc | 1 +
crawl-ref/source/god-abil.cc | 3 +-
crawl-ref/source/god-passive.cc | 2 +-
crawl-ref/source/god-wrath.cc | 4 +-
crawl-ref/source/l-debug.cc | 3 ++
crawl-ref/source/map-cell.h | 11 ++++-
crawl-ref/source/map-knowledge.cc | 51 +++++++++++++++++-----
crawl-ref/source/map-knowledge.h | 5 +++
crawl-ref/source/mon-cast.cc | 3 +-
crawl-ref/source/mon-death.cc | 12 ++++++
crawl-ref/source/movement.cc | 4 +-
crawl-ref/source/player.cc | 6 ++-
crawl-ref/source/show.cc | 4 +-
crawl-ref/source/spl-goditem.cc | 6 ++-
crawl-ref/source/tag-version.h | 1 +
crawl-ref/source/tags.cc | 69 +++++++++++++++++++++++++++++-
crawl-ref/source/terrain.cc | 11 +++--
crawl-ref/source/tile-env.h | 47 +++++++++++++++++++++
crawl-ref/source/tilepick.cc | 16 +++----
crawl-ref/source/tileview.cc | 89 +++++++++++++++++++++++----------------
crawl-ref/source/tileview.h | 1 +
crawl-ref/source/timed-effects.cc | 4 +-
crawl-ref/source/traps.cc | 3 +-
crawl-ref/source/viewmap.cc | 1 +
crawl-ref/source/xom.cc | 2 +-
27 files changed, 282 insertions(+), 79 deletions(-)
diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc
index 5126ad7f5f..3fedf10bc9 100644
--- a/crawl-ref/source/abyss.cc
+++ b/crawl-ref/source/abyss.cc
@@ -777,6 +777,7 @@ static void _abyss_wipe_square_at(coord_def p, bool saveMonsters=false)
env.map_knowledge(p).clear();
if (env.map_forgotten)
(*env.map_forgotten)(p).clear();
+ tile_env.remembered_flavour.clear_at(p);
env.map_seen.set(p, false);
#ifdef USE_TILE
tile_forget_map(p);
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 9cda712fe3..e9e8955b9b 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -1558,6 +1558,7 @@ void dgn_reset_level(bool enable_random_maps)
env.grid_colours.init(BLACK);
env.map_knowledge.init(map_cell());
env.map_forgotten.reset();
+ tile_env.remembered_flavour.reset();
env.map_seen.reset();
// Initialise all items.
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index c9fb1b02cf..c28643db1a 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -1193,6 +1193,7 @@ static void _clear_env_map()
{
env.map_knowledge.init(map_cell());
env.map_forgotten.reset();
+ tile_env.remembered_flavour.reset();
}
static void _grab_follower(monster* fol)
diff --git a/crawl-ref/source/god-abil.cc b/crawl-ref/source/god-abil.cc
index 67135cae5b..c1de7883db 100644
--- a/crawl-ref/source/god-abil.cc
+++ b/crawl-ref/source/god-abil.cc
@@ -54,6 +54,7 @@
#include "libutil.h"
#include "losglobal.h"
#include "macro.h"
+#include "map-knowledge.h"
#include "mapmark.h"
#include "maps.h"
#include "message.h"
@@ -7366,7 +7367,7 @@ void makhleb_crucible_kill(monster& victim)
simple_god_message(" acknowledges your contrition and permits you to"
" depart the Crucible.", false, GOD_MAKHLEB);
- env.map_knowledge(pos).set_feature(DNGN_EXIT_CRUCIBLE);
+ update_terrain_knowledge(pos);
#ifdef USE_TILE
tile_env.bk_bg(pos) = TILE_DNGN_PORTAL;
tiles.update_minimap(pos);
diff --git a/crawl-ref/source/god-passive.cc b/crawl-ref/source/god-passive.cc
index eec44bd114..90f8049e6c 100644
--- a/crawl-ref/source/god-passive.cc
+++ b/crawl-ref/source/god-passive.cc
@@ -536,7 +536,7 @@ static bool _check_portal(coord_def where)
const dungeon_feature_type feat = env.grid(where);
if (feat != env.map_knowledge(where).feat() && is_ash_portal(feat))
{
- env.map_knowledge(where).set_feature(feat);
+ update_terrain_knowledge(where);
set_terrain_mapped(where);
if (!testbits(env.pgrid(where), FPROP_SEEN_OR_NOEXP))
diff --git a/crawl-ref/source/god-wrath.cc b/crawl-ref/source/god-wrath.cc
index c1bd23801d..fe2bd5770d 100644
--- a/crawl-ref/source/god-wrath.cc
+++ b/crawl-ref/source/god-wrath.cc
@@ -32,6 +32,7 @@
#include "items.h"
#include "losglobal.h"
#include "makeitem.h"
+#include "map-knowledge.h"
#include "message.h"
#include "misc.h"
#include "mon-behv.h"
@@ -1921,8 +1922,7 @@ void gozag_abandon_shops_on_level()
dungeon_change_base_terrain(pos, DNGN_ABANDONED_SHOP);
if (env.map_knowledge(pos).feat() == DNGN_ENTER_SHOP)
{
- const colour_t col = env.map_knowledge(pos).feat_colour();
- env.map_knowledge(pos).set_feature(DNGN_ABANDONED_SHOP, col);
+ update_terrain_knowledge(pos, !env.map_knowledge(pos).seen());
redraw_view_at(pos);
}
env.markers.remove(feat);
diff --git a/crawl-ref/source/l-debug.cc b/crawl-ref/source/l-debug.cc
index 6545349dd1..e38ffc1c6e 100644
--- a/crawl-ref/source/l-debug.cc
+++ b/crawl-ref/source/l-debug.cc
@@ -26,6 +26,7 @@
#include "stairs.h"
#include "state.h"
#include "stringutil.h"
+#include "tile-env.h"
#include "tileview.h"
#include "unique-creature-list-type.h"
#include "unwind.h"
@@ -103,6 +104,8 @@ LUAFN(debug_generate_level)
{
msg::suppress mx;
env.map_knowledge.init(map_cell());
+ env.map_forgotten.reset();
+ tile_env.remembered_flavour.reset();
los_changed();
tile_init_default_flavour();
tile_clear_flavour();
diff --git a/crawl-ref/source/map-cell.h b/crawl-ref/source/map-cell.h
index 9bc0024021..8fc53fd646 100644
--- a/crawl-ref/source/map-cell.h
+++ b/crawl-ref/source/map-cell.h
@@ -169,9 +169,13 @@ struct map_cell
return _feat_colour;
}
- void set_feature(dungeon_feature_type nfeat, unsigned colour = 0)
+ void set_feature(dungeon_feature_type nfeat)
{
_feat = nfeat;
+ }
+
+ void set_feat_colour(colour_t colour = 0)
+ {
_feat_colour = colour;
}
@@ -309,6 +313,11 @@ struct map_cell
return !!(flags & MAP_MAGIC_MAPPED_FLAG);
}
+ bool feat_known() const
+ {
+ return !!(flags & (MAP_MAGIC_MAPPED_FLAG | MAP_SEEN_FLAG));
+ }
+
#ifdef USE_TILE
char blood_rotation() const noexcept
{
diff --git a/crawl-ref/source/map-knowledge.cc b/crawl-ref/source/map-knowledge.cc
index 9f7b84e744..328f531ebe 100644
--- a/crawl-ref/source/map-knowledge.cc
+++ b/crawl-ref/source/map-knowledge.cc
@@ -13,6 +13,7 @@
#include "religion.h"
#include "stringutil.h"
#include "terrain.h"
+#include "tile-env.h"
#ifdef USE_TILE
#include "tilepick.h"
#include "tileview.h"
@@ -486,7 +487,8 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
if (knowledge.seen()
|| env.map_forgotten && (*env.map_forgotten)(pos).seen())
{
- knowledge.set_feature(env.grid(pos), env.grid_colours(pos));
+ update_terrain_knowledge(pos);
+ update_grid_colour_knowledge(pos);
redraw_view_at(pos);
}
else
@@ -503,13 +505,10 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
if (!full_info && (knowledge.seen() || already_mapped))
continue;
- dungeon_feature_type feat = env.grid(pos);
- if (!full_info)
- feat = magic_map_base_feat(feat);
-
bool open = true;
- if (feat_is_solid(feat) && !feat_is_closed_door(feat))
+ if (feat_is_solid(env.grid(pos))
+ && !feat_is_closed_door(env.grid(pos)))
{
open = false;
for (adjacent_iterator ai(pos); ai; ++ai)
@@ -525,9 +524,10 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
if (open)
{
- knowledge.set_feature(feat, _feat_default_map_colour(feat));
- if (is_notable_terrain(feat))
- seen_notable_thing(feat, pos);
+ update_terrain_knowledge(pos, !full_info);
+ update_grid_colour_knowledge(pos, !full_info);
+ if (is_notable_terrain(knowledge.feat()))
+ seen_notable_thing(knowledge.feat(), pos);
if (emphasise(pos))
knowledge.flags |= MAP_EMPHASIZE;
@@ -544,9 +544,9 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
else
{
set_terrain_mapped(pos);
- if (get_feature_dchar(feat) == DCHAR_ALTAR)
+ if (get_feature_dchar(knowledge.feat()) == DCHAR_ALTAR)
num_altars++;
- else if (get_feature_dchar(feat) == DCHAR_ARCH)
+ else if (get_feature_dchar(knowledge.feat()) == DCHAR_ARCH)
num_shops_portals++;
}
@@ -582,3 +582,32 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
return did_map;
}
+
+void update_terrain_knowledge(coord_def pos,
+ bool partial_knowledge_only)
+{
+ dungeon_feature_type feat = env.grid(pos);
+ tileidx_t feat_tile = tile_env.flv(pos).feat;
+ unsigned short feat_tile_idx = tile_env.flv(pos).feat_idx;
+ if (partial_knowledge_only)
+ {
+ feat = magic_map_base_feat(feat);
+ if (feat == DNGN_UNKNOWN_PORTAL || feat == DNGN_UNKNOWN_ALTAR)
+ {
+ feat_tile = 0;
+ feat_tile_idx = 0;
+ }
+ }
+ env.map_knowledge(pos).set_feature(feat);
+ tile_env.remembered_flavour.set_feat_flavour(pos, feat_tile,
+ feat_tile_idx);
+}
+
+void update_grid_colour_knowledge(coord_def pos,
+ bool partial_knowledge_only)
+{
+ colour_t colour = env.grid_colours(pos);
+ if (partial_knowledge_only)
+ colour = _feat_default_map_colour(env.map_knowledge(pos).feat());
+ env.map_knowledge(pos).set_feat_colour(colour);
+}
diff --git a/crawl-ref/source/map-knowledge.h b/crawl-ref/source/map-knowledge.h
index 82a0282924..44891d0d0b 100644
--- a/crawl-ref/source/map-knowledge.h
+++ b/crawl-ref/source/map-knowledge.h
@@ -56,3 +56,8 @@ void reautomap_level();
*/
std::pair<coord_def, coord_def> known_map_bounds();
bool in_known_map_bounds(const coord_def& p);
+
+void update_terrain_knowledge(coord_def pos,
+ bool partial_knowledge_only = false);
+void update_grid_colour_knowledge(coord_def pos,
+ bool partial_knowledge_only = false);
diff --git a/crawl-ref/source/mon-cast.cc b/crawl-ref/source/mon-cast.cc
index a08da30c28..ad9400d64e 100644
--- a/crawl-ref/source/mon-cast.cc
+++ b/crawl-ref/source/mon-cast.cc
@@ -42,6 +42,7 @@
#include "libutil.h"
#include "losglobal.h"
#include "makeitem.h"
+#include "map-knowledge.h"
#include "mapmark.h"
#include "message.h"
#include "misc.h"
@@ -3529,7 +3530,7 @@ static bool _seal_doors_and_stairs(const monster* warden,
{
if (env.map_knowledge(dc).seen())
{
- env.map_knowledge(dc).set_feature(DNGN_CLOSED_DOOR);
+ update_terrain_knowledge(dc);
#ifdef USE_TILE
tile_env.bk_bg(dc) = TILE_DNGN_CLOSED_DOOR;
#endif
diff --git a/crawl-ref/source/mon-death.cc b/crawl-ref/source/mon-death.cc
index d8c044d827..d7c3bd53b6 100644
--- a/crawl-ref/source/mon-death.cc
+++ b/crawl-ref/source/mon-death.cc
@@ -72,6 +72,7 @@
#include "tag-version.h"
#include "target.h"
#include "terrain.h"
+#include "tile-env.h"
#ifdef USE_TILE
#include "rltiles/tiledef-player.h"
#endif
@@ -1248,6 +1249,17 @@ void fire_monster_death_event(monster* mons,
tile_clear_flavour(*ri);
tile_init_flavour(*ri);
}
+ if (!env.map_knowledge(*ri).feat_known()
+ && env.map_forgotten
+ && feat_is_stone_stair((*env.map_forgotten)(*ri).feat()))
+ {
+ tile_env.remembered_flavour.set_feat_flavour(*ri, 0, 0);
+ }
+ else if (feat_is_stone_stair(env.map_knowledge(*ri).feat()))
+ {
+ tile_env.remembered_flavour.set_feat_flavour(*ri, 0, 0);
+ redraw_view_at(*ri);
+ }
}
}
}
diff --git a/crawl-ref/source/movement.cc b/crawl-ref/source/movement.cc
index 0c55d893b2..d53b8ba19d 100644
--- a/crawl-ref/source/movement.cc
+++ b/crawl-ref/source/movement.cc
@@ -654,8 +654,8 @@ static void _handle_trying_to_move_into_unpassable_terrain(coord_def targ)
map_cell& knowledge = env.map_knowledge(targ);
if (!knowledge.mapped() || knowledge.changed())
{
- dungeon_feature_type newfeat = env.grid(targ);
- knowledge.set_feature(newfeat, env.grid_colours(targ));
+ update_terrain_knowledge(targ);
+ update_grid_colour_knowledge(targ);
set_terrain_mapped(targ);
}
}
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index e21276eee3..20f892ae49 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -53,6 +53,7 @@
#include "level-state-type.h"
#include "libutil.h"
#include "macro.h"
+#include "map-knowledge.h"
#include "melee-attack.h"
#include "message.h"
#include "mon-behv.h"
@@ -2398,6 +2399,7 @@ void forget_map(bool rot)
env.map_knowledge(p).clear();
if (env.map_forgotten)
(*env.map_forgotten)(p).clear();
+ tile_env.remembered_flavour.clear_at(p);
StashTrack.update_stash(p);
#ifdef USE_TILE
tile_forget_map(p);
@@ -8943,7 +8945,7 @@ void player_open_door(coord_def doorpos)
// door!
if (env.map_knowledge(dc).seen())
{
- env.map_knowledge(dc).set_feature(env.grid(dc));
+ update_terrain_knowledge(dc);
#ifdef USE_TILE
tile_env.bk_bg(dc) = tileidx_feature_base(env.grid(dc));
#endif
@@ -9114,7 +9116,7 @@ void player_close_door(coord_def doorpos)
// want the entire door to be updated.
if (env.map_knowledge(dc).seen())
{
- env.map_knowledge(dc).set_feature(env.grid(dc));
+ update_terrain_knowledge(dc);
#ifdef USE_TILE
tile_env.bk_bg(dc) = tileidx_feature_base(env.grid(dc));
#endif
diff --git a/crawl-ref/source/show.cc b/crawl-ref/source/show.cc
index 516e6512b1..9592373fd8 100644
--- a/crawl-ref/source/show.cc
+++ b/crawl-ref/source/show.cc
@@ -111,9 +111,9 @@ bool show_type::is_cleanable_monster() const
static void _update_feat_at(const coord_def &gp)
{
dungeon_feature_type feat = env.grid(gp);
- unsigned colour = env.grid_colours(gp);
- env.map_knowledge(gp).set_feature(feat, colour);
+ update_terrain_knowledge(gp);
+ update_grid_colour_knowledge(gp);
if (haloed(gp))
env.map_knowledge(gp).flags |= MAP_HALOED;
diff --git a/crawl-ref/source/spl-goditem.cc b/crawl-ref/source/spl-goditem.cc
index 4f0c5297b1..c277bdb1c1 100644
--- a/crawl-ref/source/spl-goditem.cc
+++ b/crawl-ref/source/spl-goditem.cc
@@ -871,7 +871,8 @@ spret cast_tomb(int pow, actor* victim, int source, bool fail)
tile_env.flv(*ai).feat = TILE_DNGN_SILVER_WALL;
if (env.map_knowledge(*ai).seen())
{
- env.map_knowledge(*ai).set_feature(DNGN_METAL_WALL);
+ update_terrain_knowledge(*ai);
+ update_grid_colour_knowledge(*ai);
env.map_knowledge(*ai).clear_item();
#ifdef USE_TILE
tile_env.bk_bg(*ai) = TILE_DNGN_SILVER_WALL;
@@ -891,7 +892,8 @@ spret cast_tomb(int pow, actor* victim, int source, bool fail)
tile_env.flv(*ai).feat = TILE_WALL_SANDSTONE;
if (env.map_knowledge(*ai).seen())
{
- env.map_knowledge(*ai).set_feature(DNGN_ROCK_WALL);
+ update_terrain_knowledge(*ai);
+ update_grid_colour_knowledge(*ai);
env.map_knowledge(*ai).clear_item();
#ifdef USE_TILE
tile_env.bk_bg(*ai) = TILE_WALL_SANDSTONE;
diff --git a/crawl-ref/source/tag-version.h b/crawl-ref/source/tag-version.h
index d4f5bec9a1..5ed79156a8 100644
--- a/crawl-ref/source/tag-version.h
+++ b/crawl-ref/source/tag-version.h
@@ -350,6 +350,7 @@ enum tag_minor_version
TAG_MINOR_REFACTOR_MALIGN_MARKER, // Refactor handling of map_malign_gateway_marker
TAG_MINOR_REMOVE_MORTAR_MARKERS, // Remove map_hellfire_mortar_lava_marker and refactor again
TAG_MINOR_FIX_VENGEANCE_CLEANUP, // Fix a crash when changing levels due to old vengeance targets
+ TAG_MINOR_FLAVOUR_KNOWLEDGE, // Save player knowledge of feature flavour
#endif
NUM_TAG_MINORS,
TAG_MINOR_VERSION = NUM_TAG_MINORS - 1
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index d6cf2e899a..ba9b2d4e76 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -6520,7 +6520,8 @@ void unmarshallMapCell(reader &th, map_cell& cell)
#endif
}
- cell.set_feature(feature, feat_colour);
+ cell.set_feature(feature);
+ cell.set_feat_colour(feat_colour);
if (flags & MAP_SERIALIZE_CLOUD)
{
@@ -7167,6 +7168,15 @@ void _tag_construct_level_tiles(writer &th)
marshallShort(th, tile_env.flv[count_x][count_y].special);
}
+ const flavour_knowledge& remembered = tile_env.remembered_flavour;
+ for (int count_x = 0; count_x < GXM; count_x++)
+ for (int count_y = 0; count_y < GYM; count_y++)
+ {
+ coord_def pos(count_x, count_y);
+ unsigned short tile_idx = remembered.feat_flavour_idx(pos);
+ marshallShort(th, tile_idx);
+ }
+
marshallInt(th, TILE_WALL_MAX);
}
@@ -8290,6 +8300,33 @@ static void _debug_count_tiles()
#endif
}
+#if TAG_MAJOR_VERSION == 34
+static void _fixup_flavour_knowledge()
+{
+ flavour_knowledge& knowledge = tile_env.remembered_flavour;
+ const MapKnowledge& map = env.map_knowledge;
+
+ for (rectangle_iterator ri(0); ri; ++ri)
+ {
+ const dungeon_feature_type feat = map(*ri).feat();
+ // We used to ignore tile overrides on these features
+ if (feat != DNGN_FLOOR
+ && feat != DNGN_UNSEEN
+ && feat != DNGN_PASSAGE_OF_GOLUBRIA
+ && feat != DNGN_MALIGN_GATEWAY
+ && feat != DNGN_BINDING_SIGIL
+ && feat != DNGN_UNKNOWN_PORTAL
+ && feat != DNGN_TREE)
+ {
+ unsigned short tile_idx = tile_env.flv(*ri).feat_idx;
+ knowledge.set_feat_flavour(*ri, 0, tile_idx);
+ }
+ else
+ knowledge.set_feat_flavour(*ri, 0, 0);
+ }
+}
+#endif
+
void _tag_read_level_tiles(reader &th)
{
// Map grids.
@@ -8332,6 +8369,22 @@ void _tag_read_level_tiles(reader &th)
tile_env.flv[x][y].special = unmarshallShort(th);
}
+#if TAG_MAJOR_VERSION == 34
+ if (th.getMinorVersion() < TAG_MINOR_FLAVOUR_KNOWLEDGE)
+ _fixup_flavour_knowledge();
+ else
+#endif
+ {
+ flavour_knowledge& remembered = tile_env.remembered_flavour;
+ for (int x = 0; x < gx; x++)
+ for (int y = 0; y < gy; y++)
+ {
+ coord_def pos(x, y);
+ unsigned short feat_idx = unmarshallShort(th);
+ remembered.set_feat_flavour(pos, 0, feat_idx);
+ }
+ }
+
_debug_count_tiles();
_regenerate_tile_flavour();
@@ -8428,9 +8481,23 @@ static void _regenerate_tile_flavour()
else
flv.feat = new_feat;
}
+
+ unsigned short remembered_feat_idx =
+ tile_env.remembered_flavour.feat_flavour_idx(*ri);
+ if (remembered_feat_idx)
+ {
+ tileidx_t new_feat = _get_tile_from_vector(remembered_feat_idx);
+ if (!new_feat)
+ remembered_feat_idx = 0;
+ tile_env.remembered_flavour.set_feat_flavour(*ri, new_feat,
+ remembered_feat_idx);
+ }
}
tile_new_level(true, false);
+
+ for (rectangle_iterator ri(0); ri; ++ri)
+ tile_init_remembered_flavour(*ri);
}
static void _draw_tiles()
diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc
index c4fa0cdfc4..c9db38f006 100644
--- a/crawl-ref/source/terrain.cc
+++ b/crawl-ref/source/terrain.cc
@@ -2255,11 +2255,16 @@ bool revert_terrain_change(coord_def pos, terrain_change_type ctype)
noisy(spell_effect_noise(SPELL_GOLUBRIAS_PASSAGE), pos);
}
- if (ctype == TERRAIN_CHANGE_BOG)
- env.map_knowledge(pos).set_feature(newfeat, colour);
_current_terrain_changed(pos, newfeat, false, true, false, newfeat_flv,
newfeat_flv_idx);
env.grid_colours(pos) = colour;
+
+ if (ctype == TERRAIN_CHANGE_BOG)
+ {
+ update_terrain_knowledge(pos);
+ update_grid_colour_knowledge(pos);
+ }
+
return true;
}
@@ -2657,7 +2662,7 @@ void descent_crumble_stairs()
mpr("The exit collapses.");
if (env.map_knowledge(*ri).feat() == original_feat)
{
- env.map_knowledge(*ri).set_feature(DNGN_FLOOR);
+ update_terrain_knowledge(*ri, !env.map_knowledge(*ri).seen());
set_terrain_mapped(*ri);
redraw_view_at(*ri);
}
diff --git a/crawl-ref/source/tile-env.h b/crawl-ref/source/tile-env.h
index b4fe7cabb1..718bf48533 100644
--- a/crawl-ref/source/tile-env.h
+++ b/crawl-ref/source/tile-env.h
@@ -8,6 +8,52 @@
#include "fixedarray.h"
#include "rltiles/tiledef_defines.h"
+struct flavour_knowledge
+{
+ flavour_knowledge()
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ _feat_flavour.init(0);
+ _feat_flavour_idx.init(0);
+ }
+
+ tileidx_t feat_flavour(coord_def pos) const
+ {
+ return _feat_flavour(pos);
+ }
+
+ unsigned short feat_flavour_idx(coord_def pos) const
+ {
+ return _feat_flavour_idx(pos);
+ }
+
+ void set_feat_flavour(coord_def pos, tileidx_t tile,
+ unsigned short tile_idx)
+ {
+ _feat_flavour(pos) = tile;
+ _feat_flavour_idx(pos) = tile_idx;
+ }
+
+ void copy_at(coord_def pos, const flavour_knowledge& source)
+ {
+ _feat_flavour(pos) = source._feat_flavour(pos);
+ _feat_flavour_idx(pos) = source._feat_flavour_idx(pos);
+ }
+
+ void clear_at(coord_def pos)
+ {
+ set_feat_flavour(pos, 0, 0);
+ }
+
+private:
+ FixedArray<tileidx_t, GXM, GYM> _feat_flavour;
+ FixedArray<unsigned short, GXM, GYM> _feat_flavour_idx;
+};
+
struct crawl_tile_environment
{
// indexed by grid coords
@@ -19,6 +65,7 @@ struct crawl_tile_environment
#endif
FixedArray<tile_flavour, GXM, GYM> flv;
tile_flavour default_flavour;
+ flavour_knowledge remembered_flavour;
std::vector<std::string> names;
};
diff --git a/crawl-ref/source/tilepick.cc b/crawl-ref/source/tilepick.cc
index 6f0ae62a2b..a77d628b46 100644
--- a/crawl-ref/source/tilepick.cc
+++ b/crawl-ref/source/tilepick.cc
@@ -944,17 +944,13 @@ static tileidx_t _tileidx_feature_no_overrides(const coord_def &gc)
{
dungeon_feature_type feat = env.map_knowledge(gc).feat();
- tileidx_t override = tile_env.flv(gc).feat;
- bool can_override = !feat_is_door(feat)
- && feat != DNGN_FLOOR
- && feat != DNGN_UNSEEN
- && feat != DNGN_PASSAGE_OF_GOLUBRIA
- && feat != DNGN_MALIGN_GATEWAY
- && feat != DNGN_BINDING_SIGIL
- && feat != DNGN_UNKNOWN_PORTAL
- && feat != DNGN_TREE; // summon forest spell
- if (override && can_override)
+ tileidx_t override = tile_env.remembered_flavour.feat_flavour(gc);
+ // Door tile overrides get special handling in apply_variations
+ if (override && !feat_is_door(feat)
+ && env.map_knowledge(gc).feat_known())
+ {
return override;
+ }
// Any grid-specific tiles.
switch (feat)
diff --git a/crawl-ref/source/tileview.cc b/crawl-ref/source/tileview.cc
index 90a07c7b51..2f55d1f175 100644
--- a/crawl-ref/source/tileview.cc
+++ b/crawl-ref/source/tileview.cc
@@ -506,6 +506,46 @@ static bool _same_door_at(dungeon_feature_type feat, const coord_def &gc)
&& (feat_is_sealed(feat) || feat_is_sealed(door));
}
+static void _init_feat_flavour(tileidx_t& flavour, dungeon_feature_type feat)
+{
+ if (feat_is_stone_stair(feat))
+ {
+ const bool up = feat_stair_direction(feat) == CMD_GO_UPSTAIRS;
+ if (player_in_branch(BRANCH_SHOALS))
+ {
+ flavour = up ? TILE_DNGN_SHOALS_STAIRS_UP
+ : TILE_DNGN_SHOALS_STAIRS_DOWN;
+ }
+ else if (player_in_branch(BRANCH_VAULTS))
+ {
+ if (you.depth == branches[BRANCH_VAULTS].numlevels - 1 && !up)
+ flavour = TILE_DNGN_METAL_STAIRS_DOWN;
+ else if (you.depth == branches[BRANCH_VAULTS].numlevels && up)
+ flavour = TILE_DNGN_METAL_STAIRS_UP;
+ }
+ else if (player_in_branch(BRANCH_ZOT))
+ {
+ if (you.depth == branches[BRANCH_VAULTS].numlevels - 1 && !up)
+ flavour = TILE_DNGN_ZOT_STAIRS_DOWN;
+ else if (you.depth == branches[BRANCH_VAULTS].numlevels && up)
+ flavour = TILE_DNGN_ZOT_STAIRS_UP;
+ }
+ else if (player_in_branch(BRANCH_SLIME) && !you.royal_jelly_dead)
+ {
+ if (up)
+ flavour = TILE_DNGN_SLIMY_STAIRS_UP;
+ else
+ flavour = TILE_DNGN_SLIMY_STAIRS_DOWN;
+ }
+ }
+ else if (feat_is_escape_hatch(feat) && player_in_branch(BRANCH_TOMB))
+ {
+ const bool up = feat_stair_direction(feat) == CMD_GO_UPSTAIRS;
+ flavour = up ? TILE_DNGN_ONE_WAY_STAIRS_UP
+ : TILE_DNGN_ONE_WAY_STAIRS_DOWN;
+ }
+}
+
void tile_init_flavour(const coord_def &gc, const int domino)
{
if (!map_bounds(gc))
@@ -557,43 +597,7 @@ void tile_init_flavour(const coord_def &gc, const int domino)
else
tile_env.flv(gc).wall = pick_dngn_tile(tile_env.flv(gc).wall, rand2);
- if (feat_is_stone_stair(env.grid(gc)))
- {
- const bool up = feat_stair_direction(env.grid(gc)) == CMD_GO_UPSTAIRS;
- if (player_in_branch(BRANCH_SHOALS))
- {
- tile_env.flv(gc).feat = up ? TILE_DNGN_SHOALS_STAIRS_UP
- : TILE_DNGN_SHOALS_STAIRS_DOWN;
- }
- else if (player_in_branch(BRANCH_VAULTS))
- {
- if (you.depth == branches[BRANCH_VAULTS].numlevels - 1 && !up)
- tile_env.flv(gc).feat = TILE_DNGN_METAL_STAIRS_DOWN;
- else if (you.depth == branches[BRANCH_VAULTS].numlevels && up)
- tile_env.flv(gc).feat = TILE_DNGN_METAL_STAIRS_UP;
- }
- else if (player_in_branch(BRANCH_ZOT))
- {
- if (you.depth == branches[BRANCH_VAULTS].numlevels - 1 && !up)
- tile_env.flv(gc).feat = TILE_DNGN_ZOT_STAIRS_DOWN;
- else if (you.depth == branches[BRANCH_VAULTS].numlevels && up)
- tile_env.flv(gc).feat = TILE_DNGN_ZOT_STAIRS_UP;
- }
- else if (player_in_branch(BRANCH_SLIME) && !you.royal_jelly_dead)
- {
- if (up)
- tile_env.flv(gc).feat = TILE_DNGN_SLIMY_STAIRS_UP;
- else
- tile_env.flv(gc).feat = TILE_DNGN_SLIMY_STAIRS_DOWN;
- }
- }
-
- if (feat_is_escape_hatch(env.grid(gc)) && player_in_branch(BRANCH_TOMB))
- {
- const bool up = feat_stair_direction(env.grid(gc)) == CMD_GO_UPSTAIRS;
- tile_env.flv(gc).feat = up ? TILE_DNGN_ONE_WAY_STAIRS_UP
- : TILE_DNGN_ONE_WAY_STAIRS_DOWN;
- }
+ _init_feat_flavour(tile_env.flv(gc).feat, env.grid(gc));
if (feat_is_door(env.grid(gc)))
{
@@ -631,6 +635,17 @@ void tile_init_flavour(const coord_def &gc, const int domino)
tile_env.flv(gc).special = hash_with_seed(256, seed, 10);
}
+void tile_init_remembered_flavour(coord_def pos)
+{
+ dungeon_feature_type feat = env.map_knowledge(pos).feat();
+ if (!env.map_knowledge(pos).feat_known() && env.map_forgotten)
+ feat = (*env.map_forgotten)(pos).feat();
+ tileidx_t tile = tile_env.remembered_flavour.feat_flavour(pos);
+ _init_feat_flavour(tile, feat);
+ unsigned short idx = tile_env.remembered_flavour.feat_flavour_idx(pos);
+ tile_env.remembered_flavour.set_feat_flavour(pos, tile, idx);
+}
+
enum SpecialIdx
{
SPECIAL_N = 0,
diff --git a/crawl-ref/source/tileview.h b/crawl-ref/source/tileview.h
index b590061e0f..e768ebe69a 100644
--- a/crawl-ref/source/tileview.h
+++ b/crawl-ref/source/tileview.h
@@ -39,6 +39,7 @@ void tile_clear_flavour();
void tile_init_flavour();
// Init the flavour of a single cell.
void tile_init_flavour(const coord_def &gc, const int domino = -1);
+void tile_init_remembered_flavour(coord_def pos);
// Draw a halo using 'tile' (which has 9 variations) around any features
// that match target.
void tile_floor_halo(dungeon_feature_type target, tileidx_t tile);
diff --git a/crawl-ref/source/timed-effects.cc b/crawl-ref/source/timed-effects.cc
index b004b63664..80df94fd7d 100644
--- a/crawl-ref/source/timed-effects.cc
+++ b/crawl-ref/source/timed-effects.cc
@@ -28,6 +28,7 @@
#include "god-passive.h"
#include "items.h"
#include "libutil.h"
+#include "map-knowledge.h"
#include "mapmark.h"
#include "message.h"
#include "mgen-data.h"
@@ -990,7 +991,8 @@ void timeout_terrain_changes(int duration, bool force)
// so forcibly redraw anything the player could see at the start of them.
if (m_pos.was_in_los)
{
- env.map_knowledge(m_pos.pos).set_feature(env.grid(m_pos.pos));
+ update_terrain_knowledge(m_pos.pos);
+ update_grid_colour_knowledge(m_pos.pos);
#ifdef USE_TILE
tile_env.bk_bg(m_pos.pos) = tileidx_feature_base(env.grid(m_pos.pos));
#endif
diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc
index 1f099003a9..5b3ae6d25e 100644
--- a/crawl-ref/source/traps.cc
+++ b/crawl-ref/source/traps.cc
@@ -28,6 +28,7 @@
#include "item-prop.h"
#include "items.h"
#include "libutil.h"
+#include "map-knowledge.h"
#include "mapmark.h"
#include "mon-cast.h" // recall for zot traps
#include "mon-enum.h"
@@ -679,7 +680,7 @@ void destroy_trap(const coord_def& pos)
dungeon_terrain_changed(pos, DNGN_FLOOR);
if (you.see_cell(pos))
{
- env.map_knowledge(pos).set_feature(DNGN_FLOOR);
+ update_terrain_knowledge(pos);
StashTrack.update_stash(pos);
}
}
diff --git a/crawl-ref/source/viewmap.cc b/crawl-ref/source/viewmap.cc
index 7435c7cb2b..1f5f3d704a 100644
--- a/crawl-ref/source/viewmap.cc
+++ b/crawl-ref/source/viewmap.cc
@@ -30,6 +30,7 @@
#include "state.h"
#include "stringutil.h"
#include "terrain.h"
+#include "tile-env.h"
#include "tileview.h"
#include "tiles-build-specific.h"
#include "travel.h"
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index 6da3c899f5..cbac8a5380 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -1552,8 +1552,8 @@ static void _xom_lights_up_webs(int /*sever*/)
place_cloud(CLOUD_FIRE, pos, blaze_time, nullptr, 0);
webs_count++;
- env.map_knowledge(pos).set_feature(DNGN_FLOOR);
dungeon_terrain_changed(pos, DNGN_FLOOR);
+ update_terrain_knowledge(pos);
if (actor* act = actor_at(pos))
if (act->caught_by() == CAUGHT_WEB)
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-20 10:15:11
|
via 0a58930ff6185faeb40e5dcefd2981b417a6e95b (commit)
from 6208fce01160350e7621a00483614e87f0bd7d33 (commit)
-----------------------------------------------------------------------
commit 0a58930ff6185faeb40e5dcefd2981b417a6e95b
Author: regret-index <clo...@ho...>
Date: Mon Apr 20 07:41:42 2026 -0230
Fix Xom trying to hand out monster repel missiles (XicoYe)
The overflow altar brannock_xom_greatest_gift missed out on the shift
from monster repel missiles to monster deflect missiles in 91b9509.
(While I'm here, I have also updated the list to match the hyper-buff
list of 41e759f.)
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/dat/des/altar/overflow.des | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/crawl-ref/source/dat/des/altar/overflow.des b/crawl-ref/source/dat/des/altar/overflow.des
index aacd3db4c9..9e09457462 100644
--- a/crawl-ref/source/dat/des/altar/overflow.des
+++ b/crawl-ref/source/dat/des/altar/overflow.des
@@ -117,9 +117,11 @@ function callback.xom_greatest_gift(data, triggerable, triggerer, marker, ev)
elseif not dgn.persist.xom_gg_granted and you.god() == "Xom" then
local pos = dgn.find_marker_positions_by_prop("gift", "altar")
local gob = "generate_awake att:good_neutral goblin perm_ench:might " ..
- "perm_ench:haste perm_ench:invis perm_ench:repel_missiles " ..
+ "perm_ench:haste perm_ench:deflect_missiles " ..
"perm_ench:resistant perm_ench:regen perm_ench:magic_res " ..
- "perm_ench:doubled_vigour perm_ench:mirror_dam perm_ench:swift"
+ "perm_ench:doubled_vigour perm_ench:mirror_dam " ..
+ "perm_ench:warding perm_ench:chaos_laced " ..
+ "perm_ench:paradox-touched perm_ench:swift"
dgn.create_monster(pos[1].x, pos[1].y, gob)
crawl.god_speaks("Xom", 'A goblin pops into existence! It looks at you'
.. ' with admiration.')
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-16 13:15:16
|
via 6208fce01160350e7621a00483614e87f0bd7d33 (commit)
via 9593cc5487d67e5d7352a4fca996053fc8fe457c (commit)
from 5a097ed5b7b8be2aa738a7b545caf5ee5ee892eb (commit)
-----------------------------------------------------------------------
commit 6208fce01160350e7621a00483614e87f0bd7d33
Author: Isaac Clancy <ik...@ya...>
Date: Fri Apr 17 00:53:24 2026 +1200
Fix unforgetting the map losing terrain knowledge
If you forget the map and then read a scroll of revelation, this can
result in magic mapped squares in the map knowledge that are more up to
date than the same squares in the forgotten map. However, when
unforgetting the map, we would replace the map knowledge for these
squares with that from the forgotten map.
commit 9593cc5487d67e5d7352a4fca996053fc8fe457c
Author: Isaac Clancy <ik...@ya...>
Date: Fri Apr 17 00:13:04 2026 +1200
Fix revelation giving less information with map forgotten
If you read revelation with the map forgotten you wouldn't learn the
colours of changed terrain that you had previously seen, but if you were
to unforget the map before reading revalation you would learn the new
colour of this terrain. Instead always learn the new colour of terrain
that you have previously seen.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/map-knowledge.cc | 3 ++-
crawl-ref/source/viewmap.cc | 22 ++++++++++++++--------
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/crawl-ref/source/map-knowledge.cc b/crawl-ref/source/map-knowledge.cc
index 67fb34223d..9f7b84e744 100644
--- a/crawl-ref/source/map-knowledge.cc
+++ b/crawl-ref/source/map-knowledge.cc
@@ -483,7 +483,8 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
// If the player has already seen the square, update map
// knowledge with the new terrain. Otherwise clear what we had
// before.
- if (knowledge.seen())
+ if (knowledge.seen()
+ || env.map_forgotten && (*env.map_forgotten)(pos).seen())
{
knowledge.set_feature(env.grid(pos), env.grid_colours(pos));
redraw_view_at(pos);
diff --git a/crawl-ref/source/viewmap.cc b/crawl-ref/source/viewmap.cc
index a634b93a48..7435c7cb2b 100644
--- a/crawl-ref/source/viewmap.cc
+++ b/crawl-ref/source/viewmap.cc
@@ -501,16 +501,22 @@ static void _unforget_map()
MapKnowledge &old(*env.map_forgotten);
for (rectangle_iterator ri(0); ri; ++ri)
- if (!env.map_knowledge(*ri).seen() && old(*ri).seen())
- {
- // Don't overwrite known squares, nor magic-mapped with
- // magic-mapped data -- what was forgotten is less up to date.
+ {
+ // Don't overwrite known squares, nor magic-mapped with
+ // magic-mapped data -- what was forgotten is less up to date.
+ if (env.map_knowledge(*ri).seen() || !old(*ri).seen())
+ continue;
+
+ if (!env.map_knowledge(*ri).mapped())
env.map_knowledge(*ri) = old(*ri);
- env.map_seen.set(*ri);
-#ifdef USE_TILE
- tiles.update_minimap(*ri);
-#endif
+ else
+ {
+ // Don't use set_terrain_seen as that clears the
+ // MAP_CHANGED_FLAG flag
+ env.map_knowledge(*ri).flags |= MAP_SEEN_FLAG;
}
+ redraw_view_at(*ri);
+ }
}
static void _forget_map(bool wizard_forget = false)
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-16 11:30:14
|
via 5a097ed5b7b8be2aa738a7b545caf5ee5ee892eb (commit)
from a7f40f37fe9dd2e0a7555aaef06e013890dc78ea (commit)
-----------------------------------------------------------------------
commit 5a097ed5b7b8be2aa738a7b545caf5ee5ee892eb
Author: Isaac Clancy <ik...@ya...>
Date: Thu Apr 16 23:20:02 2026 +1200
Fix revelation updating seen squares not redrawing
If you read relevation and it updated an out of sight square you had
already seen, the square wouldn't be redrawn until you reloaded the
game.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/map-knowledge.cc | 3 +++
1 file changed, 3 insertions(+)
diff --git a/crawl-ref/source/map-knowledge.cc b/crawl-ref/source/map-knowledge.cc
index dfd1e0a3f2..67fb34223d 100644
--- a/crawl-ref/source/map-knowledge.cc
+++ b/crawl-ref/source/map-knowledge.cc
@@ -484,7 +484,10 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
// knowledge with the new terrain. Otherwise clear what we had
// before.
if (knowledge.seen())
+ {
knowledge.set_feature(env.grid(pos), env.grid_colours(pos));
+ redraw_view_at(pos);
+ }
else
knowledge.clear();
}
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-16 05:10:10
|
via a7f40f37fe9dd2e0a7555aaef06e013890dc78ea (commit)
from f03e214ed596faf0f9d88e6e141175f77d3deb6e (commit)
-----------------------------------------------------------------------
commit a7f40f37fe9dd2e0a7555aaef06e013890dc78ea
Author: CrawlOdds <cra...@gm...>
Date: Tue Apr 14 19:44:29 2026 +0100
Let tracers enchantment chain
This fixes petrify not targetting monsters who were petrifying
but could set off enchantment chains, following 8e16f14
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/beam.cc | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 8892187236..a30ed0bd2c 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -4615,6 +4615,9 @@ void bolt::tracer_enchantment_affect_monster(monster* mon)
}
tracer->monster_hit(*this, *mon);
+
+ // Potentially chain to adjacent monsters.
+ handle_enchant_chaining(mon->pos());
extra_range_used += range_used_on_hit();
}
@@ -4969,7 +4972,8 @@ static void _add_chain_candidates(const bolt& beam, coord_def pos,
if (!act
|| mons_aligned(beam.agent(), act)
|| act->is_peripheral()
- || shoot_through_actor(beam.agent(), act))
+ || shoot_through_actor(beam.agent(), act)
+ || (beam.is_tracer() && !act->visible_to(beam.agent())))
{
continue;
}
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-15 08:10:12
|
via f03e214ed596faf0f9d88e6e141175f77d3deb6e (commit)
from f0a2de8890b100a1f589e52b198d0905f1c31f35 (commit)
-----------------------------------------------------------------------
commit f03e214ed596faf0f9d88e6e141175f77d3deb6e
Author: Isaac Clancy <ik...@ya...>
Date: Wed Apr 15 20:07:25 2026 +1200
Add tile-env.h to visual studio project file
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/MSVC/crawl.vcxproj | 1 +
crawl-ref/source/MSVC/crawl.vcxproj.filters | 3 +++
2 files changed, 4 insertions(+)
diff --git a/crawl-ref/source/MSVC/crawl.vcxproj b/crawl-ref/source/MSVC/crawl.vcxproj
index c34869331c..51bff9f3a3 100644
--- a/crawl-ref/source/MSVC/crawl.vcxproj
+++ b/crawl-ref/source/MSVC/crawl.vcxproj
@@ -1004,6 +1004,7 @@ python.exe util/gen-all.py</Command>
<ClInclude Include="..\text-tag-type.h" />
<ClInclude Include="..\threads.h" />
<ClInclude Include="..\throw.h" />
+ <ClInclude Include="..\tile-env.h" />
<ClInclude Include="..\tile-flags.h" />
<ClInclude Include="..\tile-inventory-flags.h" />
<ClInclude Include="..\tile-player-flag-cut.h" />
diff --git a/crawl-ref/source/MSVC/crawl.vcxproj.filters b/crawl-ref/source/MSVC/crawl.vcxproj.filters
index 72226d9c6f..1dc059085e 100644
--- a/crawl-ref/source/MSVC/crawl.vcxproj.filters
+++ b/crawl-ref/source/MSVC/crawl.vcxproj.filters
@@ -2305,6 +2305,9 @@
<ClInclude Include="..\mon-aura.h">
<Filter>h</Filter>
</ClInclude>
+ <ClInclude Include="..\tile-env.h">
+ <Filter>h</Filter>
+ </ClInclude>
<ClInclude Include="..\rltiles\status-icon-sizes.h">
<Filter>rtiles_generated</Filter>
</ClInclude>
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-15 04:35:16
|
via f0a2de8890b100a1f589e52b198d0905f1c31f35 (commit)
from 0df9381b467745f58a8df51f7371fc4ecea82b88 (commit)
-----------------------------------------------------------------------
commit f0a2de8890b100a1f589e52b198d0905f1c31f35
Author: Isaac Clancy <ik...@ya...>
Date: Wed Apr 15 16:28:34 2026 +1200
Remove the needs_update parameter from dgn_replace_area
It is never used and its implementation is incorrect
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/dungeon.cc | 17 +++--------------
crawl-ref/source/dungeon.h | 4 ++--
2 files changed, 5 insertions(+), 16 deletions(-)
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index e3ea58ac57..9cda712fe3 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -5791,31 +5791,20 @@ bool seen_destroy_feat(dungeon_feature_type old_feat)
void dgn_replace_area(int sx, int sy, int ex, int ey,
dungeon_feature_type replace,
dungeon_feature_type feature,
- unsigned mmask, bool needs_update)
+ unsigned mmask)
{
dgn_replace_area(coord_def(sx, sy), coord_def(ex, ey),
- replace, feature, mmask, needs_update);
+ replace, feature, mmask);
}
void dgn_replace_area(const coord_def& p1, const coord_def& p2,
dungeon_feature_type replace,
- dungeon_feature_type feature, uint32_t mapmask,
- bool needs_update)
+ dungeon_feature_type feature, uint32_t mapmask)
{
for (rectangle_iterator ri(p1, p2); ri; ++ri)
{
if (env.grid(*ri) == replace && !map_masked(*ri, mapmask))
- {
env.grid(*ri) = feature;
- if (needs_update && env.map_knowledge(*ri).seen())
- {
- env.map_knowledge(*ri).set_feature(feature, 0);
-#ifdef USE_TILE
- // XXX: this will not be the correct tile for the feature...
- tile_env.bk_bg(*ri) = feature;
-#endif
- }
- }
}
}
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index 4b393c07e9..305efd73fa 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -277,11 +277,11 @@ int dgn_count_tele_zones(bool choose_stairless);
void dgn_replace_area(const coord_def& p1, const coord_def& p2,
dungeon_feature_type replace,
dungeon_feature_type feature,
- unsigned mmask = 0, bool needs_update = false);
+ unsigned mmask = 0);
void dgn_replace_area(int sx, int sy, int ex, int ey,
dungeon_feature_type replace,
dungeon_feature_type feature,
- unsigned mmask = 0, bool needs_update = false);
+ unsigned mmask = 0);
vault_placement *dgn_vault_at(coord_def gp);
void dgn_seen_vault_at(coord_def gp);
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-14 02:20:21
|
via 0df9381b467745f58a8df51f7371fc4ecea82b88 (commit)
via e3b7102c4d57eb25c2a7803435c51001c9225946 (commit)
via e713047c70333c3d72a5aa5072e5c4d86c285ee3 (commit)
via 8e16f14301014392c7b600164447adfffdb43a15 (commit)
via 7385d75e6399a24b1eb22eb95ef7539255f698f7 (commit)
via b0ab3d485ac2a7af580034166c0d59d54c820397 (commit)
via f34de8fe481039af76533236cbbc403388b4751f (commit)
via ec5cf0b163955b3625ab5d48f9eeebb66add21fb (commit)
via ab1eb49602d94bd5a77106324e6f67fbc41255cc (commit)
via 261e6ac810a549c45decbb6663c369fd06a2bdb7 (commit)
via 7ecd7e923ad0a6eb666ec1564f1539653df294f9 (commit)
via cbca37cc1acd523e83ffce3e318c5c6c95e5d836 (commit)
via 09ccc81b476fc6d772309d725715a5cf26985e2b (commit)
via 863a6f896110810bb6dfa9448ded17abee0bdccd (commit)
via eed6cab612f5e9413387e9de3aa7adddf2c6aba8 (commit)
via 63ac50c65189a4bdddef4976afba9284cd1998d4 (commit)
from 36cf4e329c1d913f02413c831329a6288be6b6e8 (commit)
-----------------------------------------------------------------------
commit 0df9381b467745f58a8df51f7371fc4ecea82b88
Author: DracoOmega <dra...@gm...>
Date: Mon Apr 13 23:20:01 2026 -0230
Remove an unused targeter
(This was used by pre-0.32 yellow draconian breath)
commit e3b7102c4d57eb25c2a7803435c51001c9225946
Author: DracoOmega <dra...@gm...>
Date: Mon Apr 13 23:12:32 2026 -0230
Maybe fix a CAO compilation issue?
(And incidentally give a few deep elf weapons a couple extra plusses).
This is maybe a long-shot, but I don't have a way to test it directly.
commit e713047c70333c3d72a5aa5072e5c4d86c285ee3
Author: DracoOmega <dra...@gm...>
Date: Mon Apr 13 23:02:24 2026 -0230
Fix some issues with spell autotargeting
The prompts removed by 453fa3c turned out to still be important to how
spell autofight worked, and since their removal, it was possible for
autofight to waste time/MP doing things like shooting stone arrows at
grates or plants (without even a message, in the former case).
So I have rewritten a little about spell targeting to try and improve the
situation, using a vaguely similar appproach as 5ec89a4. A new AFF_BAD is
added for 'line of fire blocked by firewood'. When using autofight, the
targeter will not accept any path to a target that ends in AFF_BAD,
effectively causing it to pick a different target, if one is available.
The biggest net effect of this is that when closer targets are obstructed
by firewood or grates, it will pick some other target that isn't, instead.
I am not entirely satisfied with some parts of this code, and vaguely
concerned this will introduce some other bug, but it does seem to improve
the desired behavior.
(As a side-effect, manual targeting will now draw the cells beyond the
first target hit, when using a single-target projectile, more faintly than
the initial path. I feel this may have been the original intent of some of
that code, but it hadn't actually done this for a very long time.)
commit 8e16f14301014392c7b600164447adfffdb43a15
Author: CrawlOdds <cra...@gm...>
Date: Fri Mar 6 20:16:41 2026 +0000
Don't target petrifying/petrified monsters with petrify
[Committer's note: gave players the same treatment for petrifying since
they already included petrified. I am not sure this actually affects
anything relevant.]
commit 7385d75e6399a24b1eb22eb95ef7539255f698f7
Author: CrawlOdds <cra...@gm...>
Date: Wed Mar 11 21:47:48 2026 +0000
Make LRD not useless when casting round corners
This means that instead of LRD being marked as useless when there
is no smite-targettable enemy, it is never marked as useless because
of a lack of enemies. This is better behaviour now we know how to
target enemies we can't see, and also in line with Fire Storm not being
useless because it can hit enemies out of LoS.
commit b0ab3d485ac2a7af580034166c0d59d54c820397
Author: CrawlOdds <cra...@gm...>
Date: Wed Mar 11 19:33:57 2026 +0000
Allow autoaiming explosions at targets we can't hit directly
When targets can be hit by an explosion, but not by a direct shot, we
were marking spells as useless and not autoaiming. This fixes this by
changing some visibility checks to use default visibility.
commit f34de8fe481039af76533236cbbc403388b4751f
Author: CrawlOdds <cra...@gm...>
Date: Sun Mar 29 09:23:52 2026 +0100
Fix free detection of invisible monsters with -move (Back-form)
When the player cannot move, direction keys currently do nothing
except if there is a monster, in which case they attack. This is fine
for visible monsters, but allows detection of invisible monsters by
attacking all surrounding squares. This seems undesirable, so we
don't allow this sort of attack against unknown monsters if the
player cannot move.
[Committer's note: Changed to use a direct monster check rather than a
monster_info check, since the former is more standard for this sort of
code.]
commit ec5cf0b163955b3625ab5d48f9eeebb66add21fb
Author: CrawlOdds <cra...@gm...>
Date: Sat Mar 21 16:34:40 2026 +0000
Make plasma beam useless if it will do no damage
Plasma beam was marked as useful against entirely resistant enemies.
We fix this so that it is useless if there are no visible enemies it might
damage.
commit ab1eb49602d94bd5a77106324e6f67fbc41255cc
Author: CrawlOdds <cra...@gm...>
Date: Tue Mar 31 20:34:48 2026 +0100
Do not stop channelling spells on any macro
Channelling spells was being interrupted by any macro, including ones
that only did a "wait" action or did no action at all (like pressing r)
commit 261e6ac810a549c45decbb6663c369fd06a2bdb7
Author: CrawlOdds <cra...@gm...>
Date: Tue Apr 7 20:59:41 2026 +0100
Stop Hep ancestors wandering off on Zot:5
They were spawning patrolling, which caused them to start wandering.
commit 7ecd7e923ad0a6eb666ec1564f1539653df294f9
Author: CrawlOdds <cra...@gm...>
Date: Mon Apr 6 20:19:01 2026 +0100
Explore boundary walls
This fixes a bug where sometimes autoexplore will not reveal some tiles
on the unnaturally hard boundary wall.
commit cbca37cc1acd523e83ffce3e318c5c6c95e5d836
Author: CrawlOdds <cra...@gm...>
Date: Fri Apr 10 18:51:01 2026 +0100
Do not power up Wyrmbane twice when killing dragons with convulsion
Since 2bee245, when we killed a dragon with convulsion wyrmbane
powered up twice - once in the on-hit melee effects call, and once in
the on-kill one.
The reason this worked _before_ that commit is that when wyrmbane
killed a monster via the hurt() method, the monster was cleaned up and
therefore did not register as a dragon in handle_phase_killed() call.
Now that we use inflict_damage, this has changed. So we make sure we
never power up wyrmbane in the on-hit melee effects, and leave it to
handle_phase_killed in all cases.
[Committer's note: removed an obsolete comment and added a new one, very
slightly rearranging code in the process.]
commit 09ccc81b476fc6d772309d725715a5cf26985e2b
Author: CrawlOdds <cra...@gm...>
Date: Fri Apr 10 19:31:04 2026 +0100
Don't trigger attunement on enemy staff attacks
Fixes #5193
commit 863a6f896110810bb6dfa9448ded17abee0bdccd
Author: CrawlOdds <cra...@gm...>
Date: Fri Apr 10 20:35:51 2026 +0100
Don't use randart tiles for enchanted hammers
Fixes #5165
I couldn't reproduce this (though I have seen it on webtiles), but this
seems very likely to be the cause.
commit eed6cab612f5e9413387e9de3aa7adddf2c6aba8
Author: DracoOmega <dra...@gm...>
Date: Sun Apr 12 21:30:07 2026 -0230
Fix a few abilities not interacting properly with the quiver
These would either not let you fire them with 'f', or require you to
confirm twice if you did so.
This closes #5196
commit 63ac50c65189a4bdddef4976afba9284cd1998d4
Author: DracoOmega <dra...@gm...>
Date: Sun Apr 12 21:29:01 2026 -0230
Give Vessel of Slaughter a static targeter
Both to indicate the range of the damnation blast and as a extra
confirmation before using it.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/ability.cc | 6 ++--
crawl-ref/source/art-func.h | 17 ++++++-----
crawl-ref/source/beam.cc | 6 ++--
crawl-ref/source/directn.cc | 47 ++++++++++++++++++++---------
crawl-ref/source/directn.h | 4 +++
crawl-ref/source/initfile.cc | 2 +-
crawl-ref/source/main.cc | 3 +-
crawl-ref/source/melee-attack.cc | 3 +-
crawl-ref/source/mon-gear.cc | 3 +-
crawl-ref/source/mon-place.cc | 3 +-
crawl-ref/source/movement.cc | 18 +++++++----
crawl-ref/source/quiver.cc | 3 ++
crawl-ref/source/rltiles/dc-item.txt | 2 +-
crawl-ref/source/spl-damage.cc | 27 +++++++++++++----
crawl-ref/source/spl-damage.h | 2 +-
crawl-ref/source/spl-util.cc | 5 ++--
crawl-ref/source/target.cc | 58 ++++++------------------------------
crawl-ref/source/target.h | 13 +++-----
crawl-ref/source/travel.cc | 12 ++++++--
19 files changed, 125 insertions(+), 109 deletions(-)
diff --git a/crawl-ref/source/ability.cc b/crawl-ref/source/ability.cc
index 3e2d5945a6..60317f8e4a 100644
--- a/crawl-ref/source/ability.cc
+++ b/crawl-ref/source/ability.cc
@@ -459,7 +459,7 @@ static vector<ability_def> &_get_ability_list()
{ ABIL_KIKU_UNEARTH_WRETCHES, "Unearth Wretches",
3, 0, 5, -1, {fail_basis::invo, 40, 5, 20}, abflag::none },
{ ABIL_KIKU_SIGN_OF_RUIN, "Sign of Ruin",
- 5, 0, 4, -1, {fail_basis::invo, 60, 5, 20}, abflag::target },
+ 5, 0, 4, LOS_MAX_RANGE, {fail_basis::invo, 60, 5, 20}, abflag::target },
{ ABIL_KIKU_GIFT_CAPSTONE_SPELLS, "Receive Forbidden Knowledge",
0, 0, 0, -1, {fail_basis::invo}, abflag::none },
{ ABIL_KIKU_BLESS_WEAPON, "Brand Weapon With Pain",
@@ -626,7 +626,7 @@ static vector<ability_def> &_get_ability_list()
{ ABIL_DITHMENOS_SHADOWSLIP, "Shadowslip",
4, 60, 4, -1, {fail_basis::invo, 50, 6, 30}, abflag::instant },
{ ABIL_DITHMENOS_APHOTIC_MARIONETTE, "Aphotic Marionette",
- 5, 0, 3, -1, {fail_basis::invo, 60, 4, 25}, abflag::target },
+ 5, 0, 3, LOS_MAX_RANGE, {fail_basis::invo, 60, 4, 25}, abflag::target },
{ ABIL_DITHMENOS_PRIMORDIAL_NIGHTFALL, "Primordial Nightfall",
8, 0, 13, -1, {fail_basis::invo, 80, 4, 25}, abflag::none },
@@ -2641,6 +2641,8 @@ unique_ptr<targeter> find_ability_targeter(ability_type ability)
case ABIL_CHEIBRIADOS_TIME_BEND:
case ABIL_USKAYAW_STOMP:
return make_unique<targeter_maybe_radius>(&you, LOS_NO_TRANS, 1, 0, 1);
+ case ABIL_MAKHLEB_VESSEL_OF_SLAUGHTER:
+ return make_unique<targeter_radius>(&you, LOS_SOLID, 3);
// Multiposition:
case ABIL_SPIDER_JUMP:
diff --git a/crawl-ref/source/art-func.h b/crawl-ref/source/art-func.h
index bdb2fc1349..b7699a4c4c 100644
--- a/crawl-ref/source/art-func.h
+++ b/crawl-ref/source/art-func.h
@@ -609,11 +609,6 @@ static void _WYRMBANE_melee_effects(item_def* weapon, actor* /*attacker*/,
if (!defender || !defender->is_dragonkind())
return;
- // Since the target will become a DEAD MONSTER if it dies due to the extra
- // damage to dragons, we need to grab this information now.
- const int hd = defender->dragon_level();
- string name = defender->name(DESC_THE);
-
if (defender->alive())
{
int bonus_dam = 1 + random2(3 * dam / 2);
@@ -623,9 +618,15 @@ static void _WYRMBANE_melee_effects(item_def* weapon, actor* /*attacker*/,
attack_strength_punctuation(bonus_dam).c_str());
atk->inflict_damage(bonus_dam);
+ // The defender may be dead, but even if so we dont want to power up
+ // the lance, as this will happen on another call in the kill phase.
+ return;
}
- if (defender->alive() || !hd)
+ // XXX: This is only reached if the defender was already dead at the time this
+ // function was called (which should only be from melee_attack::handle_phase_killed())
+ const int hd = defender->dragon_level();
+ if (!hd)
return;
// The cap can be reached by:
@@ -645,12 +646,12 @@ static void _WYRMBANE_melee_effects(item_def* weapon, actor* /*attacker*/,
{
mprf("<white>The lance glows brightly as it skewers %s. You feel "
"that it has reached its full power.</white>",
- name.c_str());
+ defender->name(DESC_THE).c_str());
}
else
{
mprf("<green>The lance glows as it skewers %s.</green>",
- name.c_str());
+ defender->name(DESC_THE).c_str());
}
you.wield_change = true;
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 558eaf6139..8892187236 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -3311,7 +3311,7 @@ bool bolt::harmless_to_player() const
return player_res_poison(false) > 0 || you.clarity();
case BEAM_PETRIFY:
- return you.res_petrify() || you.petrified();
+ return you.res_petrify() || you.petrified() || you.petrifying();
case BEAM_COLD:
return is_big_cloud() && actor_cloud_immune(you, CLOUD_COLD);
@@ -4845,7 +4845,7 @@ void bolt::tracer_affect_monster(monster* mon)
{
// Ignore unseen monsters.
if ((agent() && !agent()->can_see(*mon))
- || !cell_see_cell(source, mon->pos(), LOS_NO_TRANS))
+ || !cell_see_cell(source, mon->pos(), LOS_DEFAULT))
{
return;
}
@@ -5957,7 +5957,7 @@ bool ench_flavour_affects_monster(actor *agent, beam_type flavour,
break;
case BEAM_PETRIFY:
- rc = !mon->res_petrify();
+ rc = !mon->res_petrify() && !mon->petrifying() && !mon->petrified();
break;
case BEAM_INFESTATION:
diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc
index 65b8cb6a11..ae199678ae 100644
--- a/crawl-ref/source/directn.cc
+++ b/crawl-ref/source/directn.cc
@@ -429,6 +429,7 @@ direction_chooser::direction_chooser(dist& moves_,
hitfunc(args.hitfunc),
is_ranged_attack(args.is_ranged_attack),
is_piercing(args.is_piercing),
+ is_autotargeting(false),
default_place(args.default_place),
player_changed_target(false),
renderer(*this),
@@ -1060,16 +1061,24 @@ static bool _blocked_ray(const coord_def &where)
// allies). If that is not possible, returns the 'best' position found,
// priotizing (in order): can affect the monster, doesn't harm the player, and
// finally doesn't harm allies.
+//
+// If no aim can be found that affects the monster at all, return (0, 0).
coord_def direction_chooser::find_acceptable_aim(const monster* focus)
{
if (is_ranged_attack)
return best_ranged_aim(focus->pos(), is_piercing);
+ // Without a targeter, we can't refine this any better.
if (!hitfunc)
- return coord_def();
+ return focus->pos();
const aff_type desired_aff = try_multizap ? AFF_MULTIPLE : AFF_YES;
+ // When using manual targeting, it's okay to present the player paths to
+ // an intended target that are blocked by plants, but autofight should never
+ // use these.
+ const aff_type min_acceptable_aff = is_autotargeting ? AFF_MAYBE : AFF_BAD;
+
coord_def best_pos;
aff_type best_player_aff = harmful_to_player ? AFF_NO : AFF_YES;
aff_type best_target_aff = AFF_NO;
@@ -1088,7 +1097,7 @@ coord_def direction_chooser::find_acceptable_aim(const monster* focus)
hitfunc->set_aim(*ri);
// Has to at least hit the target in question to consider.
aff_type target_aff = hitfunc->is_affected(focus->pos());
- if (target_aff == AFF_NO)
+ if (target_aff < min_acceptable_aff)
continue;
// If this affects the player worse than a previously found position,
@@ -1133,12 +1142,8 @@ coord_def direction_chooser::find_acceptable_aim(const monster* focus)
}
// Return the best positon we found, assuming any of them were any good.
- // (Fall back on the target's own position, if we haven't, and it is at
- // least possible to aim at it.)
if (!best_pos.origin())
return best_pos;
- else if (!hitfunc || hitfunc->valid_aim(focus->pos()))
- return focus->pos();
else
return coord_def();
}
@@ -1186,7 +1191,7 @@ void direction_chooser::calculate_target_info()
harmful_to_player = hitfunc ? hitfunc->harmful_to_player() : true;
- for (monster_near_iterator mi(&you, LOS_NO_TRANS); mi; ++mi)
+ for (monster_near_iterator mi(&you, LOS_DEFAULT); mi; ++mi)
{
if (!you.can_see(**mi))
continue;
@@ -1207,8 +1212,6 @@ void direction_chooser::calculate_target_info()
}
}
- const bool check_past_range = hitfunc && hitfunc->can_affect_outside_range();
-
// Find all foes that could be affected by what we're aiming. For those we
// can aim at directly, put their coordinates into the list. For those we
// can't, try to find a nearby square that can hit them, if one exists.
@@ -1217,13 +1220,14 @@ void direction_chooser::calculate_target_info()
const bool in_range = range > -1 ? grid_distance(foe->pos(), you.pos()) <= range : true;
const bool can_aim = (!hitfunc || hitfunc->valid_aim(foe->pos()))
&& (!needs_path || !_blocked_ray(foe->pos()));
- if (in_range && can_aim)
+ if (Options.simple_targeting && !is_autotargeting && in_range && can_aim)
cycle_pos.push_back(foe->pos());
- else if (!Options.simple_targeting && hitfunc
- && ((in_range && !can_aim) || check_past_range))
+ else
{
coord_def pos = find_acceptable_aim(foe);
- if (!pos.origin())
+
+ // Don't include duplicate positions or we won't cycle properly.
+ if (!pos.origin() && find(cycle_pos.begin(), cycle_pos.end(), pos) == cycle_pos.end())
cycle_pos.push_back(pos);
}
}
@@ -1248,7 +1252,12 @@ coord_def direction_chooser::find_default_target()
if (mode == TARG_NON_ACTOR || just_looking
|| (cycle_pos.empty() && mode != TARG_HOSTILE_OR_EMPTY))
{
- return you.pos();
+ // Default to the player's position if there are no other valid targets,
+ // but don't *select* the player when autotargeting.
+ if (is_autotargeting)
+ return coord_def();
+ else
+ return you.pos();
}
if (mode == TARG_MOVABLE_OBJECT)
@@ -1318,6 +1327,8 @@ coord_def direction_chooser::find_default_monster_target()
// If we can find literally nowhere else useful to aim, fall back to the player.
if (!pos.origin())
return pos;
+ else if (is_autotargeting)
+ return coord_def();
else
return you.pos();
}
@@ -2673,9 +2684,17 @@ bool direction_chooser::noninteractive()
// if target is unset, this will find previous or closest target; if
// target is set this will adjust targeting depending on custom
// behavior
+ is_autotargeting = true;
calculate_target_info();
if (moves.find_target)
+ {
set_target(find_default_target());
+ if (moves.target.origin())
+ {
+ moves.isValid = false;
+ mpr("No reachable target in view!");
+ }
+ }
update_validity();
finalize_moves();
diff --git a/crawl-ref/source/directn.h b/crawl-ref/source/directn.h
index 321cbe9648..3dd5e089e2 100644
--- a/crawl-ref/source/directn.h
+++ b/crawl-ref/source/directn.h
@@ -286,6 +286,10 @@ private:
targeter *hitfunc; // Determine what would be hit.
bool is_ranged_attack; // Is this a launcher/throwing attack being aimed?
bool is_piercing; // If a ranged attack, does it penetrate targets?
+ bool is_autotargeting; // True if this is getting a default target
+ // non-interactively which using autofight with
+ // quivered spells (and thus we should be more
+ // stringent about only returning useful paths).
coord_def default_place; // Start somewhere other than you.pos()?
// Internal data.
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index 246325a755..ab8331d4a1 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -1655,7 +1655,7 @@ void game_options::reset_options()
ABIL_CHEIBRIADOS_SLOUCH, ABIL_QAZLAL_DISASTER_AREA,
ABIL_RU_APOCALYPSE, ABIL_LUGONU_CORRUPT, ABIL_IGNIS_FOXFIRE,
ABIL_SIPHON_ESSENCE, ABIL_DITHMENOS_SHADOWSLIP,
- ABIL_WATERY_GRAVE };
+ ABIL_WATERY_GRAVE, ABIL_MAKHLEB_VESSEL_OF_SLAUGHTER };
always_use_static_ability_targeters = false;
force_scroll_targeter =
diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc
index 73ab9b8830..5366bbd6b7 100644
--- a/crawl-ref/source/main.cc
+++ b/crawl-ref/source/main.cc
@@ -1176,7 +1176,8 @@ static void _input()
if (you_are_delayed()
&& !dynamic_cast<MacroProcessKeyDelay*>(current_delay().get()))
{
- stop_channelling_spells();
+ if (!current_delay().get()->is_macro())
+ stop_channelling_spells();
handle_delay();
// Some delays set you.turn_is_over.
diff --git a/crawl-ref/source/melee-attack.cc b/crawl-ref/source/melee-attack.cc
index 8179d698f0..c553e87fea 100644
--- a/crawl-ref/source/melee-attack.cc
+++ b/crawl-ref/source/melee-attack.cc
@@ -3472,7 +3472,8 @@ bool melee_attack::apply_staff_damage()
defender->poison(attacker, 2);
}
- if (you.wearing_ego(OBJ_ARMOUR, SPARM_ATTUNEMENT)
+ if (attacker->is_player()
+ && you.wearing_ego(OBJ_ARMOUR, SPARM_ATTUNEMENT)
&& you.magic_points < you.max_magic_points)
{
mpr("You draw in some of the released energy.");
diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc
index 80271bc8b9..8bcd7f4a82 100644
--- a/crawl-ref/source/mon-gear.cc
+++ b/crawl-ref/source/mon-gear.cc
@@ -414,7 +414,8 @@ int make_mons_weapon(monster_type type, int level, bool melee_only)
{ { { WPN_SCIMITAR, 2 },
{ WPN_FALCHION, 1 },
{ WPN_RAPIER, 1 },
- { WPN_ATHAME, 1 }, }, { },
+ { WPN_ATHAME, 1 }, },
+ { 1, 0, 4 },
{ { SPWPN_FLAMING, 1 },
{ SPWPN_FREEZING, 1 },
{ NUM_SPECIAL_WEAPONS, 3 } } };
diff --git a/crawl-ref/source/mon-place.cc b/crawl-ref/source/mon-place.cc
index 9806593149..afc9fb124e 100644
--- a/crawl-ref/source/mon-place.cc
+++ b/crawl-ref/source/mon-place.cc
@@ -1314,7 +1314,8 @@ static monster* _place_monster_aux(const mgen_data &mg, const monster *leader,
// Keep random monsters created inside the Orb vault from passively
// wandering out until the tesseracts are activated.
bool needs_patrol = false;
- if (mg.place == level_id(BRANCH_ZOT, 5) && !mg.is_summoned())
+ if (mg.place == level_id(BRANCH_ZOT, 5) && !mg.is_summoned()
+ && mg.behaviour != BEH_FRIENDLY)
{
const vault_placement *vp = dgn_vault_at(mon->pos());
if (vp && vp->map_name_at(mon->pos()) == "hall_of_Zot")
diff --git a/crawl-ref/source/movement.cc b/crawl-ref/source/movement.cc
index 579f38303c..0c55d893b2 100644
--- a/crawl-ref/source/movement.cc
+++ b/crawl-ref/source/movement.cc
@@ -893,6 +893,17 @@ static bool _handle_player_step(const coord_def& targ, int& delay, bool rampagin
coord_def mon_swap_dest;
bool fedhas_move = false;
+ // If we can't move, and don't have a non-move action, stop. We sometimes want
+ // to hit invisible monsters, but if we can't see them and can't move, it leaks
+ // information to allow the player to hit them.
+ if ((!mon || !mon->visible_to(&you))
+ && you.cannot_move()
+ && !feat_is_closed_door(env.grid(targ)))
+ {
+ canned_msg(MSG_CANNOT_MOVE);
+ return false;
+ }
+
// First, check for fighting a monster.
if (mon)
{
@@ -984,12 +995,7 @@ static bool _handle_player_step(const coord_def& targ, int& delay, bool rampagin
// Now we know we actually want to move *into* this spot, let's see if we can.
// XXX: Liquids the player cannot enter are handled by check_moveto_terrain(),
// which has already been called, so no need to check again.
- if (you.cannot_move())
- {
- canned_msg(MSG_CANNOT_MOVE);
- return false;
- }
- else if (_cannot_step_into(targ))
+ if (_cannot_step_into(targ))
{
_handle_trying_to_move_into_unpassable_terrain(targ);
you.digging = false;
diff --git a/crawl-ref/source/quiver.cc b/crawl-ref/source/quiver.cc
index 962ec5494e..2bd431d57d 100644
--- a/crawl-ref/source/quiver.cc
+++ b/crawl-ref/source/quiver.cc
@@ -1381,6 +1381,8 @@ namespace quiver
case ABIL_STEAM_BREATH:
case ABIL_NOXIOUS_BREATH:
case ABIL_MUD_BREATH:
+ case ABIL_GOLDEN_BREATH:
+ case ABIL_BREATHE_RUST:
case ABIL_DAMNATION:
case ABIL_ELYVILON_HEAL_OTHER:
case ABIL_LUGONU_BANISH:
@@ -1391,6 +1393,7 @@ namespace quiver
case ABIL_USKAYAW_LINE_PASS:
case ABIL_USKAYAW_GRAND_FINALE:
case ABIL_WU_JIAN_WALLJUMP:
+ case ABIL_YRED_HURL_TORCHLIGHT:
case ABIL_EVOKE_DISPATER:
case ABIL_EVOKE_OLGREB:
#ifdef WIZARD
diff --git a/crawl-ref/source/rltiles/dc-item.txt b/crawl-ref/source/rltiles/dc-item.txt
index f6f03fb888..280f0d9455 100644
--- a/crawl-ref/source/rltiles/dc-item.txt
+++ b/crawl-ref/source/rltiles/dc-item.txt
@@ -71,7 +71,7 @@ eveningstar3 WPN_EVENINGSTAR_RANDART
hammer1 WPN_HAMMER
%enchant_variation WPN_HAMMER shiny runed glowing
hammer2 WPN_HAMMER_MAGIC
-%enchant_variation WPN_HAMMER shiny runed glowing randart
+%enchant_variation WPN_HAMMER randart
hammer3 WPN_HAMMER_RANDART
bullwhip WPN_WHIP
%enchant_variation WPN_WHIP shiny runed glowing
diff --git a/crawl-ref/source/spl-damage.cc b/crawl-ref/source/spl-damage.cc
index 6754e55b9c..1704fd30e4 100644
--- a/crawl-ref/source/spl-damage.cc
+++ b/crawl-ref/source/spl-damage.cc
@@ -3105,8 +3105,8 @@ vector<coord_def> plasma_beam_targets(const actor &agent, int pow, bool actual)
return targets;
}
-static ai_action::goodness _fire_plasma_beam_at(const actor &agent, int pow,
- coord_def target, bool is_tracer)
+static targeting_tracer _fire_plasma_beam_at(const actor &agent, int pow,
+ coord_def target, bool is_tracer)
{
int range = grid_distance(agent.pos(), target);
const bool mon = agent.is_monster();
@@ -3121,7 +3121,6 @@ static ai_action::goodness _fire_plasma_beam_at(const actor &agent, int pow,
beam.attitude = mon ? mons_attitude(*agent.as_monster()) : ATT_FRIENDLY;
beam.origin_spell = SPELL_PLASMA_BEAM;
beam.draw_delay = 5;
- beam.foe_ratio = 80; // default
targeting_tracer tracer;
zappy(ZAP_PLASMA_LIGHTNING, pow, mon, beam);
if (is_tracer)
@@ -3139,7 +3138,7 @@ static ai_action::goodness _fire_plasma_beam_at(const actor &agent, int pow,
else
beam.fire();
- return tracer.good_to_fire(beam.foe_ratio);
+ return tracer;
}
bool mons_should_fire_plasma(int pow, const actor &agent)
@@ -3148,7 +3147,9 @@ bool mons_should_fire_plasma(int pow, const actor &agent)
bool ever_good = false;
for (auto target : targets)
{
- const ai_action::goodness result = _fire_plasma_beam_at(agent, pow, target, true);
+ int foe_ratio = 80; // default
+ const ai_action::goodness result = _fire_plasma_beam_at(
+ agent, pow, target, true).good_to_fire(foe_ratio);
if (result == ai_action::bad())
return false; // be very careful!
if (result == ai_action::good())
@@ -3157,8 +3158,22 @@ bool mons_should_fire_plasma(int pow, const actor &agent)
return ever_good;
}
-spret cast_plasma_beam(int pow, const actor &agent, bool fail)
+spret cast_plasma_beam(int pow, const actor &agent, bool fail, bool is_tracer)
{
+ if (is_tracer)
+ {
+ vector<coord_def> known_targs = plasma_beam_targets(agent, pow, false);
+ for (coord_def target : known_targs)
+ {
+ const targeting_tracer tracer = _fire_plasma_beam_at(agent, pow, target, true);
+ if (tracer.foe_info.count > 0)
+ return spret::success;
+ }
+
+ // Didn't find any susceptible targets
+ return spret::abort;
+ }
+
if (agent.is_player())
{
vector<coord_def> known_targs = plasma_beam_targets(agent, pow, false);
diff --git a/crawl-ref/source/spl-damage.h b/crawl-ref/source/spl-damage.h
index 2802dc3513..6c20760bba 100644
--- a/crawl-ref/source/spl-damage.h
+++ b/crawl-ref/source/spl-damage.h
@@ -81,7 +81,7 @@ void do_galvanic_jolt(const actor& agent, coord_def pos, dice_def damage);
void do_eel_melee_jolt(coord_def pos);
void do_eel_arcjolt();
bool mons_should_fire_plasma(int pow, const actor &agent);
-spret cast_plasma_beam(int pow, const actor &agent, bool fail);
+spret cast_plasma_beam(int pow, const actor &agent, bool fail, bool is_tracer=false);
vector<coord_def> plasma_beam_targets(const actor &agent, int pow, bool actual);
vector<coord_def> plasma_beam_paths(coord_def source, const vector<coord_def> &targets);
dice_def base_fragmentation_damage(int pow, bool random);
diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc
index a43b7a8bf3..080e74f223 100644
--- a/crawl-ref/source/spl-util.cc
+++ b/crawl-ref/source/spl-util.cc
@@ -1658,8 +1658,7 @@ bool spell_no_hostile_in_range(spell_type spell)
case SPELL_APPORTATION:
case SPELL_PASSWALL:
case SPELL_GOLUBRIAS_PASSAGE:
- // case SPELL_LRD: // TODO: LRD logic here is a bit confusing, it should error
- // // now that it doesn't destroy walls
+ case SPELL_LRD:
case SPELL_FULMINANT_PRISM:
case SPELL_FORGE_LIGHTNING_SPIRE:
case SPELL_NOXIOUS_BOG:
@@ -1793,7 +1792,7 @@ bool spell_no_hostile_in_range(spell_type spell)
return permafrost_targets(you, false).empty();
case SPELL_PLASMA_BEAM:
- return plasma_beam_targets(you, pow, false).empty();
+ return cast_plasma_beam(-1, you, false, true) == spret::abort;
default:
break;
diff --git a/crawl-ref/source/target.cc b/crawl-ref/source/target.cc
index 3fe1f8e832..b7cb0c494b 100644
--- a/crawl-ref/source/target.cc
+++ b/crawl-ref/source/target.cc
@@ -292,6 +292,7 @@ aff_type targeter_beam::is_affected(coord_def loc)
int visit_count = 0;
coord_def c;
aff_type current = AFF_YES;
+ aff_type initial = AFF_YES;
for (auto pc : path_taken)
{
if (cell_is_solid(pc)
@@ -306,6 +307,7 @@ aff_type targeter_beam::is_affected(coord_def loc)
if (c == loc)
{
visit_count++;
+ initial = current;
if (max_expl_rad > 0)
on_path = true;
else if (cell_is_solid(pc))
@@ -326,7 +328,11 @@ aff_type targeter_beam::is_affected(coord_def loc)
// We assume an exploding spell will always stop here.
if (max_expl_rad > 0)
break;
- current = AFF_MAYBE;
+
+ if (monster_at(pc) && monster_at(pc)->is_firewood())
+ current = AFF_BAD;
+ else if (current != AFF_BAD)
+ current = AFF_MAYBE;
}
}
if (max_expl_rad > 0)
@@ -352,8 +358,8 @@ aff_type targeter_beam::is_affected(coord_def loc)
}
return visit_count == 0 ? AFF_NO :
- visit_count == 1 ? AFF_YES :
- AFF_MULTIPLE;
+ visit_count == 1 ? initial
+ : AFF_MULTIPLE;
}
bool targeter_beam::affects_monster(const monster_info& mon)
@@ -1158,52 +1164,6 @@ bool targeter_cloud::harmful_to_player()
return !actor_cloud_immune(you, ctype);
}
-
-targeter_splash::targeter_splash(const actor *act, int r, int pow)
- : targeter_beam(act, r, ZAP_COMBUSTION_BREATH, pow, 0, 0)
-{
-}
-
-aff_type targeter_splash::is_affected(coord_def loc)
-{
- bool on_path = false;
- coord_def c;
- for (auto pc : path_taken)
- {
- if (cell_is_invalid_target(pc))
- break;
-
- c = pc;
- if (pc == loc)
- on_path = true;
-
- if (anyone_there(pc) && !beam.ignores_monster(monster_at(pc)))
- break;
- }
-
- if (loc == c)
- return AFF_YES;
-
- // self-spit doesn't splash
- if (aim == origin)
- return AFF_NO;
-
- // it splashes around only upon hitting someone
- if (anyone_there(c))
- {
- if (grid_distance(loc, c) > 1)
- return on_path ? AFF_YES : AFF_NO;
-
- // you're safe from being splashed by own spit
- if (loc == origin)
- return AFF_NO;
-
- return anyone_there(loc) ? AFF_YES : AFF_MAYBE;
- }
-
- return on_path ? AFF_YES : AFF_NO;
-}
-
targeter_radius::targeter_radius(const actor *act, los_type _los,
int ran, int ran_max, int ran_min, int ran_maybe):
range(ran), range_max(ran_max), range_min(ran_min), range_maybe(ran_maybe)
diff --git a/crawl-ref/source/target.h b/crawl-ref/source/target.h
index e0ee71106c..2dc7e1b189 100644
--- a/crawl-ref/source/target.h
+++ b/crawl-ref/source/target.h
@@ -14,8 +14,10 @@ enum aff_type // sign and non-zeroness matters
{
AFF_TRACER = -1,
AFF_NO = 0,
- AFF_MAYBE = 1, // can possibly affect
- AFF_YES, // intended/likely to affect
+ AFF_BAD = 1, // could theoretically affect, but is blocked by
+ // firewood or allies (for non-penetrating beams)
+ AFF_MAYBE, // can possibly affect
+ AFF_YES, // intended/likely to affect
// If you want to extend this to pass the probability somehow, feel free to,
// just keep AFF_YES the minimal "bright" value.
AFF_LANDING, // Valid shadow step landing site
@@ -238,13 +240,6 @@ public:
vector<vector<coord_def> > queue;
};
-class targeter_splash : public targeter_beam
-{
-public:
- targeter_splash(const actor *act, int ran, int pow);
- aff_type is_affected(coord_def loc) override;
-};
-
class targeter_radius : public targeter
{
public:
diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc
index 13ac16cb70..f31f0cbb3c 100644
--- a/crawl-ref/source/travel.cc
+++ b/crawl-ref/source/travel.cc
@@ -1653,7 +1653,8 @@ void travel_pathfind::check_square_greed(const coord_def &c)
bool travel_pathfind::path_flood(const coord_def &c, const coord_def &dc)
{
- if (!in_bounds(dc) || unreachables.count(dc))
+ // Squares outside the map cannot be explored or moved to.
+ if (!map_bounds(dc) || unreachables.count(dc))
return false;
if (floodout
@@ -1716,8 +1717,11 @@ bool travel_pathfind::path_flood(const coord_def &c, const coord_def &dc)
{
const coord_def ddc = dc + Compass[dir];
- if (feat_is_wall(env.map_knowledge(ddc).feat()))
+ if (map_bounds(ddc)
+ && feat_is_wall(env.map_knowledge(ddc).feat()))
+ {
dist -= Options.explore_wall_bias;
+ }
}
if (Options.explore_wall_bias < 0 &&
@@ -1770,6 +1774,10 @@ bool travel_pathfind::path_flood(const coord_def &c, const coord_def &dc)
return true;
}
+ // Don't consider moving to squares outside the playable area.
+ if (!in_bounds(dc))
+ return false;
+
// We don't want to follow the transporter at c if it's excluded. We also
// don't want to update point_distance for the destination based on
// taking this transporter.
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-11 21:40:14
|
via 36cf4e329c1d913f02413c831329a6288be6b6e8 (commit)
via ad89b66b9cb32925340d9423e467fbf62a8ff1c7 (commit)
from c7f2f743013dc6bcc02f8d6398a1519f49e1dd17 (commit)
-----------------------------------------------------------------------
commit 36cf4e329c1d913f02413c831329a6288be6b6e8
Author: regret-index <clo...@ho...>
Date: Sat Apr 11 19:06:57 2026 -0230
Make Xom never get bored on the orb run
Even if the floors are almost certainly heavily explored, Xomscumming's
pretty hard when random demons and Pan lords spawn indefinitely.
commit ad89b66b9cb32925340d9423e467fbf62a8ff1c7
Author: regret-index <clo...@ho...>
Date: Sat Apr 11 17:28:13 2026 -0230
Fix some more Trove lua errors (Patrick2011b)
After 2489330, some Trove randbook spell school assignments clashed either
in terms of redundant school assignments (the dragon trove's opposing
elements) or in terms of our inconsistent pluralizing of Translocations /
Conjurations / Summonings. (It's plural in manuals and skill menus, but
not in descriptions or miscast string look-ups or randbook assignments.)
While it'd be nice to make the latter not a perpetual potential source of
bugs, in this particular case it can sidestepped entirely by using the
orb randart enhancer artprops strings instead.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/dat/des/portals/trove.des | 8 ++++----
crawl-ref/source/xom.cc | 3 ++-
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/crawl-ref/source/dat/des/portals/trove.des b/crawl-ref/source/dat/des/portals/trove.des
index 70192be321..f1fb401b66 100644
--- a/crawl-ref/source/dat/des/portals/trove.des
+++ b/crawl-ref/source/dat/des/portals/trove.des
@@ -311,7 +311,7 @@ function trove_standard_magic(e, school, use_staff)
local inames = {
["conjuration"] = {"conjuration", "Conj", "conjurations"},
["summoning"] = {"ERROR: set use_staff to false", "Summ", "summonings"},
- ["necromancy"] = {"necromancy", "Necro", "Necromancy"},
+ ["necromancy"] = {"necromancy", "Necro", "necromancy"},
["translocations"] = {"ERROR: set use_staff to false", "Tloc", "translocations"},
["hexes"] = {"ERROR: set use_staff to false", "Hexes", "hexes"},
["fire"] = {"fire", "Fire", "fire magic"},
@@ -336,7 +336,7 @@ function trove_standard_magic(e, school, use_staff)
schname = iname[3]
elseif crawl.game_started() and you.base_skill(iname[3]) > max_other then
max_other = you.base_skill(iname[3])
- secondary = sc
+ secondary = iname[2]
end
end
if crawl.game_started() and you.base_skill(schname) < 27 then
@@ -1543,8 +1543,8 @@ kitem("f = storm " .. dg .. " w:6 / storm " .. dr .. " w:4 / \
golden " .. dg .. " w:4 / golden " .. dr .. " w:2")
kitem("g = serpent tailsman randart w:2 / dragon-coil talisman w:6 / \
dragon-coil talisman randart w:12")
-local book = trove_book(_G, "fire disc2:ice") .. " / " ..
- trove_book(_G, "air disc2:earth")
+local book = trove_book(_G, "fire", "ice") .. " / " ..
+ trove_book(_G, "air", "earth")
if no_friendlies == false then
book = book .. trove_book(_G, "summoning spells:dragon's_call") .. " w:25"
end
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index 226b453884..6da3c899f5 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -435,7 +435,8 @@ void xom_tick()
// ...but They get bored...
_calculate_exploration_estimate(true);
- if (you.gift_timeout > 0 && you.explore_estimate > 5 && coinflip())
+ if (you.gift_timeout > 0 && you.explore_estimate > 5 && coinflip() &&
+ !player_on_orb_run())
{
you.gift_timeout--;
// Especially if the floor's mostly done.
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-11 09:10:10
|
via c7f2f743013dc6bcc02f8d6398a1519f49e1dd17 (commit)
via 6df632f55283f63b716bb411e72b597c82d800b2 (commit)
from e5931b7edd296bdcc1c8d642640db0edccc7d123 (commit)
-----------------------------------------------------------------------
commit c7f2f743013dc6bcc02f8d6398a1519f49e1dd17
Author: regret-index <clo...@ho...>
Date: Sat Apr 11 06:39:46 2026 -0230
Tone down Xom's nearly-fully-explored floors interactions (various)
The antiscumming changes in 41e759f, in retrospect, may have been somewhat
overkill. Any two pieces of no good strategic effects on nearly-cleared
floors, making bad strategic effects worse on nearly-cleared floors, and
making boredom tick down much more rapidly on nearly-cleared floors would
be plenty to deal with the matters for now. The third of these, however,
unfortunately interacts badly with regular non-scumming play, which is
more than unideal- Xom's already inherently enough of a risky god that we
don't need people to focus on manual exploration.
This isn't a full reversion of any of the effects, but it does reduce the
speed of Xom's boredom ticking down on nearly-fully-explored floors from
x6 to x3, and it also allows slightly more of a floor to be known (if not
all of it) for the sake of offering up item gifts and good mutations
without trying to actively avoid nearly as much of each level. (This also
comes with some adjustments Xom bazaar rarity once more, which should
reduce the severity variance on the effect.) This will still need more
testing, but it should hopefully be less intense to test within.
(While it's been mentioned occasionally in developer discussions or in
the comments of the code, no commit message has actually stated directly
future Xom overhaul plans. These would eventually make Xom strategic
benefits mix together with 500+ turn bespoke buffs and only happen a
little whiles after entering new floors, allowing a lot more control
rather than relying entirely on random distribution resulting in either
permitting scumming or negatively influencing regular play. This would
also allow toning down much of Xom's boredom upscaling this version, since
scumming beyond floor-peeking (which would cost buffs instead) wouldn't
have almost any effect. Such efforts are, however, certainl delayed
to future versions due to the scope of other singular dev projects slated
for 0.35.)
commit 6df632f55283f63b716bb411e72b597c82d800b2
Author: regret-index <clo...@ho...>
Date: Sat Apr 11 06:12:10 2026 -0230
Tweak some monochromatic altar tiles (PureQuestion)
While it's reasonable in theme and concept for Okawaru's altar to be made
of iron, Elyvilon's altar to be made of white marble, and Kikubaaqudgha's
altar to stack up skulls, these early single-digit-versions altar tiles are
conspicuously plain compared to the majority of other altar tiles we've
gone through over time, and in particular at a too-quick glance it's
possible to confuse Ely and Oka's altar together. (There may have been
some policy for altars to each be immediately recognizable as an altar
back then, but we've more than drifted from that now.)
This quick fix for each of their altar tiles adds a bit more contrast and
colour to each of these, leaning off of iron / holy / undead mage colours
and corresponding invocation icon colour splashes, to make each of them
less greyscale as well as easier to distinguish at a quick glance. (Zin's
altar is still pretty monochromatic, though They've got the sparkle
animation anyway, which should cover for that plenty.)
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/dat/descript/features.txt | 4 ++--
crawl-ref/source/rltiles/dngn/altars/elyvilon.png | Bin 655 -> 1356 bytes
crawl-ref/source/rltiles/dngn/altars/kikubaaqudgha.png | Bin 404 -> 1698 bytes
crawl-ref/source/rltiles/dngn/altars/okawaru.png | Bin 568 -> 1238 bytes
crawl-ref/source/xom.cc | 12 ++++++------
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/crawl-ref/source/dat/descript/features.txt b/crawl-ref/source/dat/descript/features.txt
index d74e51f2d3..d07510f1da 100644
--- a/crawl-ref/source/dat/descript/features.txt
+++ b/crawl-ref/source/dat/descript/features.txt
@@ -38,8 +38,8 @@ surroundings.
%%%%
A white marble altar of Elyvilon
-An altar to Elyvilon the Healer, made from purest white marble and topped by a
-sculpture of the Chalice of Purification.
+An altar to Elyvilon the Healer, made from invigorated white marble and topped
+by a sculpture of the Chalice of Purification.
%%%%
A blossoming altar of Fedhas
diff --git a/crawl-ref/source/rltiles/dngn/altars/elyvilon.png b/crawl-ref/source/rltiles/dngn/altars/elyvilon.png
index 8af21dced2..55d049778c 100644
Binary files a/crawl-ref/source/rltiles/dngn/altars/elyvilon.png and b/crawl-ref/source/rltiles/dngn/altars/elyvilon.png differ
diff --git a/crawl-ref/source/rltiles/dngn/altars/kikubaaqudgha.png b/crawl-ref/source/rltiles/dngn/altars/kikubaaqudgha.png
index 0f619d30e9..31575053de 100644
Binary files a/crawl-ref/source/rltiles/dngn/altars/kikubaaqudgha.png and b/crawl-ref/source/rltiles/dngn/altars/kikubaaqudgha.png differ
diff --git a/crawl-ref/source/rltiles/dngn/altars/okawaru.png b/crawl-ref/source/rltiles/dngn/altars/okawaru.png
index 7b110545df..fe7addcd76 100644
Binary files a/crawl-ref/source/rltiles/dngn/altars/okawaru.png and b/crawl-ref/source/rltiles/dngn/altars/okawaru.png differ
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index 2c35e9c315..226b453884 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -440,7 +440,7 @@ void xom_tick()
you.gift_timeout--;
// Especially if the floor's mostly done.
if (you.explore_estimate >= 85)
- you.gift_timeout = max(you.gift_timeout - 5, 0);
+ you.gift_timeout = max(you.gift_timeout - 2, 0);
}
if (you.explore_estimate >= 85 && you.gift_timeout <= 15 ||
@@ -4857,7 +4857,7 @@ static const vector<xom_event_data> _list_xom_good_actions = {
}
// Check if you have enough gold, increased by each trip.
- if (you.gold < (900 + sv * (4 +
+ if (you.gold < (1000 + sv * (2 +
(you.props[XOM_BAZAAR_TRIP_COUNT].get_int() * 2))))
{
return false;
@@ -4873,7 +4873,7 @@ static const vector<xom_event_data> _list_xom_good_actions = {
// Each bazaar trip reduces the chance of the next, unless things
// are going badly enough it'd be funny to save the player.
return tn > 28
- || (one_chance_in(you.props[XOM_BAZAAR_TRIP_COUNT].get_int() * 7));
+ || (one_chance_in(you.props[XOM_BAZAAR_TRIP_COUNT].get_int() * 6));
}
},
{
@@ -4881,15 +4881,15 @@ static const vector<xom_event_data> _list_xom_good_actions = {
{return (random2(tn) < 5 // should really revise strategic benefits....
&& x_chance_in_y(you.how_mutated(), 54)
&& you.can_safely_mutate())
- && you.explore_estimate < 90;}
+ && you.explore_estimate < 95;}
},
{
XOM_GOOD_RANDOM_ITEM, 33, 775, [](int /*sv*/, int tn)
- {return tn < 20 && you.explore_estimate < 90;}
+ {return tn < 20 && you.explore_estimate < 95;}
},
{
XOM_GOOD_ACQUIREMENT, 21, 295, [](int /*sv*/, int tn)
- {return tn < 20 && you.explore_estimate < 90;}
+ {return tn < 20 && you.explore_estimate < 95;}
},
};
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-09 03:05:14
|
via e5931b7edd296bdcc1c8d642640db0edccc7d123 (commit)
from 9a5c35dbd8ad7ec7122057e617e6a180551b3558 (commit)
-----------------------------------------------------------------------
commit e5931b7edd296bdcc1c8d642640db0edccc7d123
Author: regret-index <clo...@ho...>
Date: Thu Apr 9 00:30:21 2026 -0230
Fix a Rutra trove Lua error (#5175)
As gammafunk points out, the Lua errors Rutra could produce are due to
a086fab refactoring the Trove magic item picking, resulting in a
case-sensitivity issues for that trove's Hexes magic item set-up. Alongside
setting said function call to get the correct lowercase argument, this also
adjusts the string comparison to make it be case-insensitive to avoid
tripping over this one way or another in the future.
This closes #5175.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/dat/des/portals/trove.des | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/crawl-ref/source/dat/des/portals/trove.des b/crawl-ref/source/dat/des/portals/trove.des
index ed8c206a9a..70192be321 100644
--- a/crawl-ref/source/dat/des/portals/trove.des
+++ b/crawl-ref/source/dat/des/portals/trove.des
@@ -328,7 +328,7 @@ function trove_standard_magic(e, school, use_staff)
table.insert(orbs, "stardust w:2")
end
for sc, iname in pairs(inames) do
- if school == sc then
+ if school:lower() == sc:lower() then
staff = "staff of " .. iname[1]
orb = "orb randart artprops:" .. iname[2] .. " ego:" ..
table.concat(orbs, " / orb randart artprops:" .. iname[2] .. " ego:")
@@ -1223,7 +1223,7 @@ end
trove_offense(_G, trove_weap_brand(_G, "venom", false) .. " / quick blade randart / " ..
"athame randart w:8 / quick blade ego:devious w:4 / " ..
"manual of Stealth w:8",
- trove_standard_magic(_G, "Hexes", false) .. " / " ..
+ trove_standard_magic(_G, "hexes", false) .. " / " ..
"orb ego:guile randart artprops:Hexes w:1",
trove_good_talisman(_G, "Stlth:2", talis),
"hexes magic")
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-08 10:35:13
|
via 9a5c35dbd8ad7ec7122057e617e6a180551b3558 (commit)
from bae5047b404d84a68c4d49c5568a6bac4f6035c2 (commit)
-----------------------------------------------------------------------
commit 9a5c35dbd8ad7ec7122057e617e6a180551b3558
Author: Isaac Clancy <ik...@ya...>
Date: Tue Apr 7 21:48:12 2026 +1200
Refactor: move tile flags out of tileidx_t
Most functions that handle tiles using the type tileidx_t would crash
or have incorrect behaviour if the tile had flags applied to it. Also,
some areas of the code were using unsigned short to store tiles
presumably because it is smaller (16 bits versus 64 bits) although it
might just be because they predate the tileidx_t type being added.
Instead, stop storing tile flags in tileidx_t (reducing its size from
64 bits to 16 bits) and instead use the new type tile_with_flags_t in
the few areas that actually want to store tile flags, also change most
of the places that use types other than tileidx_t to store tiles to use
tileidx_t.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/describe-spells.cc | 2 +-
crawl-ref/source/describe.cc | 12 +-
crawl-ref/source/externs.h | 14 +--
crawl-ref/source/map-cell.h | 3 +-
crawl-ref/source/menu.cc | 2 +-
crawl-ref/source/mon-death.cc | 4 +-
crawl-ref/source/rltiles/tiledef-unrand.h | 6 +-
crawl-ref/source/rltiles/tiledef_defines.h | 65 ++++++++++-
crawl-ref/source/tags.cc | 28 +++--
crawl-ref/source/tile-env.h | 2 +-
crawl-ref/source/tile-player-flags.h | 9 +-
crawl-ref/source/tilecell.cc | 8 +-
crawl-ref/source/tilecell.h | 14 ++-
crawl-ref/source/tiledgnbuf.cc | 174 ++++++++++++++---------------
crawl-ref/source/tilemcache.cc | 25 +++--
crawl-ref/source/tilemcache.h | 2 +-
crawl-ref/source/tilepick-p.cc | 4 +-
crawl-ref/source/tilepick-p.h | 2 +-
crawl-ref/source/tilepick.cc | 67 +++++------
crawl-ref/source/tilepick.h | 20 ++--
crawl-ref/source/tilereg-doll.cc | 21 ++--
crawl-ref/source/tilereg-doll.h | 2 +-
crawl-ref/source/tileview.cc | 48 ++++----
crawl-ref/source/tileweb.cc | 30 ++---
crawl-ref/source/tileweb.h | 2 +-
crawl-ref/source/util/art-data.pl | 4 +-
crawl-ref/source/view.cc | 4 +-
27 files changed, 322 insertions(+), 252 deletions(-)
diff --git a/crawl-ref/source/describe-spells.cc b/crawl-ref/source/describe-spells.cc
index a4a1a95d31..0dc26b0594 100644
--- a/crawl-ref/source/describe-spells.cc
+++ b/crawl-ref/source/describe-spells.cc
@@ -771,7 +771,7 @@ static void _write_book(const spellbook_contents &book,
tiles.json_write_string("title", dith_marker + spell_title(spell));
tiles.json_write_int("colour", _spell_colour(spell, source_item));
tiles.json_write_name("tile");
- tiles.write_tileidx(tileidx_spell(spell));
+ tiles.json_write_int(tileidx_spell(spell));
// don't crash if we have more spells than letters.
auto entry = find_if(spell_map.begin(), spell_map.end(),
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 7808ec7d6f..a011e22ec4 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -7090,20 +7090,20 @@ int describe_monster(const monster_info &mi, const string& /*footer*/)
write_spellset(spells, nullptr, &mi);
{
- tileidx_t t = tileidx_monster(mi);
- tileidx_t t0 = t & TILE_FLAG_MASK;
- tileidx_t flag = t & (~TILE_FLAG_MASK);
+ tile_with_flags_t t = tileidx_monster(mi);
+ tileidx_t t0 = t.tile();
+ tile_flag_t flag = t.flags();
if (!mons_class_is_stationary(mi.type) || mi.type == MONS_TRAINING_DUMMY)
{
tileidx_t mcache_idx = mcache.register_monster(mi);
- t = flag | (mcache_idx ? mcache_idx : t0);
- t0 = t & TILE_FLAG_MASK;
+ t0 = mcache_idx ? mcache_idx : t0;
+ t.set_tile(t0);
}
tiles.json_write_int("fg_idx", t0);
tiles.json_write_name("flag");
- tiles.write_tileidx(flag);
+ tiles.write_tile_with_flags(flag);
tiles.json_write_icons(status_icons_for(mi));
if (t0 >= TILEP_MCACHE_START)
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 9dc958b5ea..06371f7610 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -54,10 +54,10 @@ struct tile_flavour
unsigned short wall_idx;
unsigned short feat_idx;
- unsigned short floor;
- unsigned short wall;
+ tileidx_t floor;
+ tileidx_t wall;
// Used (primarily) by the vault 'TILE' overlay.
- unsigned short feat;
+ tileidx_t feat;
// Used as a random value or for special cases e.g. (bazaars, gates).
unsigned short special;
@@ -71,11 +71,11 @@ class tile_fg_store
{
public:
tile_fg_store() : m_tile(0) {}
- tile_fg_store(tileidx_t tile) : m_tile(tile) {}
- operator tileidx_t() { return m_tile; }
- tileidx_t operator=(tileidx_t tile);
+ tile_fg_store(tile_with_flags_t tile) : m_tile(tile) {}
+ operator tile_with_flags_t() { return m_tile; }
+ tile_with_flags_t operator=(tile_with_flags_t tile);
protected:
- tileidx_t m_tile;
+ tile_with_flags_t m_tile;
};
#define MAX_NAME_LENGTH 30
diff --git a/crawl-ref/source/map-cell.h b/crawl-ref/source/map-cell.h
index b1fc971792..9bc0024021 100644
--- a/crawl-ref/source/map-cell.h
+++ b/crawl-ref/source/map-cell.h
@@ -72,8 +72,7 @@ struct cloud_info
// for clouds with duration: decay/20, clamped to 0-3
// for vortex clouds: the vortex phase
uint8_t variety;
- // TODO: should this be tileidx_t?
- unsigned short tile;
+ tileidx_t tile;
coord_def pos;
killer_type killer;
};
diff --git a/crawl-ref/source/menu.cc b/crawl-ref/source/menu.cc
index 70e78747bf..9ec0a67a34 100644
--- a/crawl-ref/source/menu.cc
+++ b/crawl-ref/source/menu.cc
@@ -2534,7 +2534,7 @@ bool MonsterMenuEntry::get_tiles(vector<tile_def>& tileset) const
}
else
{
- tileidx_t idx = tileidx_monster(*m) & TILE_FLAG_MASK;
+ tileidx_t idx = tileidx_monster(*m).tile();
tileset.emplace_back(idx);
}
diff --git a/crawl-ref/source/mon-death.cc b/crawl-ref/source/mon-death.cc
index bac3773060..d8c044d827 100644
--- a/crawl-ref/source/mon-death.cc
+++ b/crawl-ref/source/mon-death.cc
@@ -957,7 +957,7 @@ static bool _blorkula_bat_split(monster& blorkula, killer_type ktype)
random_range(450, 900) * BASELINE_DELAY));
#ifdef USE_TILE
- static vector<int> bat_colours =
+ static vector<tileidx_t> bat_colours =
{
TILEP_MONS_VAMPIRE_BAT_GREEN,
TILEP_MONS_VAMPIRE_BAT_ORANGE,
@@ -985,7 +985,7 @@ static bool _blorkula_bat_split(monster& blorkula, killer_type ktype)
{
bat->props[BLORKULA_REVIVAL_TIMER_KEY] = revive_timer;
#ifdef USE_TILE
- bat->props[MONSTER_TILE_KEY] = bat_colours[i];
+ bat->props[MONSTER_TILE_KEY] = (int)bat_colours[i];
#endif
saved_blork.write_to_prop(bat->props[SAVED_BLORKULA_KEY].get_vector());
mons_add_blame(bat, "manifested out of " + blorkula.name(DESC_A, true));
diff --git a/crawl-ref/source/rltiles/tiledef-unrand.h b/crawl-ref/source/rltiles/tiledef-unrand.h
index a49c2113eb..fbeac9291b 100644
--- a/crawl-ref/source/rltiles/tiledef-unrand.h
+++ b/crawl-ref/source/rltiles/tiledef-unrand.h
@@ -1,4 +1,6 @@
#pragma once
-int unrandart_to_tile(int unrand);
-int unrandart_to_doll_tile(int unrand);
+#include "tiledef_defines.h"
+
+tileidx_t unrandart_to_tile(int unrand);
+tileidx_t unrandart_to_doll_tile(int unrand);
diff --git a/crawl-ref/source/rltiles/tiledef_defines.h b/crawl-ref/source/rltiles/tiledef_defines.h
index ba1e929336..5aab1ac17c 100644
--- a/crawl-ref/source/rltiles/tiledef_defines.h
+++ b/crawl-ref/source/rltiles/tiledef_defines.h
@@ -2,7 +2,70 @@
#include <vector>
-typedef uint64_t tileidx_t;
+#include "tile-flags.h"
+
+typedef uint16_t tileidx_t;
+typedef uint64_t tile_flag_t;
+
+struct tile_with_flags_t
+{
+ tile_with_flags_t(tile_flag_t v = 0) noexcept :
+ value(v)
+ {
+ }
+
+ tile_with_flags_t(tileidx_t tile, tile_flag_t flags) noexcept :
+ value((uint64_t)tile | flags)
+ {
+ }
+
+ tileidx_t tile() const noexcept
+ {
+ return (tileidx_t)(value & TILE_FLAG_MASK);
+ }
+
+ tile_flag_t flags(tile_flag_t mask = ~TILE_FLAG_MASK) const noexcept
+ {
+ return value & mask;
+ }
+
+ void operator|=(tile_flag_t flag) noexcept
+ {
+ value |= flag;
+ }
+
+ tile_with_flags_t operator|(tile_flag_t flag) const noexcept
+ {
+ return value | flag;
+ }
+
+ bool operator==(tile_with_flags_t other) const noexcept
+ {
+ return value == other.value;
+ }
+
+ bool operator!=(tile_with_flags_t other) const noexcept
+ {
+ return value != other.value;
+ }
+
+ bool has_flag(tile_flag_t flag) const noexcept
+ {
+ return (value & flag) != 0;
+ }
+
+ void remove_flag(tile_flag_t flag) noexcept
+ {
+ value &= ~flag;
+ }
+
+ void set_tile(tileidx_t tile) noexcept
+ {
+ value = tile | flags();
+ }
+
+ uint64_t value;
+};
class tile_info
{
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 8797fa2afa..d6cf2e899a 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -8272,21 +8272,19 @@ static void _debug_count_tiles()
{
#ifdef DEBUG_DIAGNOSTICS
# ifdef USE_TILE
- map<int,bool> found;
- int t, cnt = 0;
- for (int i = 0; i < GXM; i++)
- for (int j = 0; j < GYM; j++)
- {
- t = tile_env.bk_bg[i][j];
- if (!found.count(t))
- cnt++, found[t] = true;
- t = tile_env.bk_fg[i][j];
- if (!found.count(t))
- cnt++, found[t] = true;
- t = tile_env.bk_cloud[i][j];
- if (!found.count(t))
- cnt++, found[t] = true;
- }
+ set<tileidx_t> found;
+ tileidx_t t = 0;
+ for (rectangle_iterator ri(0); ri; ++ri)
+ {
+ coord_def pos = *ri;
+ t = tile_env.bk_bg(pos).tile();
+ found.insert(t);
+ t = ((tile_with_flags_t)tile_env.bk_fg(pos)).tile();
+ found.insert(t);
+ t = tile_env.bk_cloud(pos);
+ found.insert(t);
+ }
+ const int cnt = (int)found.size();
dprf("Unique tiles found: %d", cnt);
# endif
#endif
diff --git a/crawl-ref/source/tile-env.h b/crawl-ref/source/tile-env.h
index 2bc4373bda..b4fe7cabb1 100644
--- a/crawl-ref/source/tile-env.h
+++ b/crawl-ref/source/tile-env.h
@@ -13,7 +13,7 @@ struct crawl_tile_environment
// indexed by grid coords
#ifdef USE_TILE // TODO: separate out this stuff from crawl_environment
FixedArray<tile_fg_store, GXM, GYM> bk_fg;
- FixedArray<tileidx_t, GXM, GYM> bk_bg;
+ FixedArray<tile_with_flags_t, GXM, GYM> bk_bg;
FixedArray<tileidx_t, GXM, GYM> bk_cloud;
map<coord_def, set<tileidx_t>> icons;
#endif
diff --git a/crawl-ref/source/tile-player-flags.h b/crawl-ref/source/tile-player-flags.h
index 16ee589868..e47ccb7828 100644
--- a/crawl-ref/source/tile-player-flags.h
+++ b/crawl-ref/source/tile-player-flags.h
@@ -1,11 +1,10 @@
#pragma once
+#include <limits>
+
#include "rltiles/tiledef-player.h"
-enum tile_player_flags
-{
- TILEP_SHOW_EQUIP = 0x10000000,
-};
+const tileidx_t TILEP_SHOW_EQUIP = std::numeric_limits<tileidx_t>::max();
-static_assert(static_cast<int>(TILEP_SHOW_EQUIP) > static_cast<int>(TILEP_PLAYER_MAX),
+static_assert(TILEP_SHOW_EQUIP > static_cast<tileidx_t>(TILEP_PLAYER_MAX),
"TILEP_SHOW_EQUIP must be distinct from all player tile enums");
diff --git a/crawl-ref/source/tilecell.cc b/crawl-ref/source/tilecell.cc
index 1b7c2a5baf..416496efe2 100644
--- a/crawl-ref/source/tilecell.cc
+++ b/crawl-ref/source/tilecell.cc
@@ -84,7 +84,7 @@ enum wave_type
};
-void packed_cell::add_overlay(int tileidx)
+void packed_cell::add_overlay(tileidx_t tileidx)
{
// Deduplicate existing identical overlays
// There's a ton of ways to implement this.
@@ -539,4 +539,10 @@ void pack_cell_overlays(const coord_def &gc, crawl_view_buffer &vbuf)
_pack_wall_shadows(gc, vbuf, shadow_tile);
}
}
+
+bool is_in_water(const packed_cell& cell)
+{
+ return cell.bg.has_flag(TILE_FLAG_WATER)
+ && !cell.fg.has_flag(TILE_FLAG_FLYING);
+}
#endif //TILECELL.CC
diff --git a/crawl-ref/source/tilecell.h b/crawl-ref/source/tilecell.h
index 3f100acffc..4f691e1bd6 100644
--- a/crawl-ref/source/tilecell.h
+++ b/crawl-ref/source/tilecell.h
@@ -21,10 +21,10 @@ struct packed_cell
// For anything that requires multiple dungeon tiles (such as waves)
// These tiles will be placed directly on top of the bg tile.
static constexpr size_t MAX_DNGN_OVERLAY = 16;
- FixedVector<int, MAX_DNGN_OVERLAY> dngn_overlay;
+ FixedVector<tileidx_t, MAX_DNGN_OVERLAY> dngn_overlay;
// SSE2 / XMM registers = 128 bits or 16 bytes
- // Current size of 16x int32 == 512 bits aligns nicely
- COMPILE_CHECK(sizeof(FixedVector<int, MAX_DNGN_OVERLAY>) % 16 == 0);
+ // Current size of 16x uint16 == 256 bits aligns nicely
+ COMPILE_CHECK(sizeof(dngn_overlay) % 16 == 0);
// This is directly copied from env.map_knowledge by viewwindow()
// Here for packing / alignment purposes
@@ -51,8 +51,8 @@ struct packed_cell
uint8_t disjunct;
tile_flavour flv;
- tileidx_t fg;
- tileidx_t bg;
+ tile_with_flags_t fg;
+ tile_with_flags_t bg;
tileidx_t cloud;
set<tileidx_t> icons;
@@ -97,7 +97,7 @@ struct packed_cell
void clear();
// Add an overlay if not already present
- void add_overlay(int tileidx);
+ void add_overlay(tileidx_t tileidx);
};
class crawl_view_buffer;
@@ -106,4 +106,6 @@ class crawl_view_buffer;
// that require knowledge of the surrounding env cells.
void pack_cell_overlays(const coord_def &gc, crawl_view_buffer &vbuf);
+bool is_in_water(const packed_cell& cell);
+
#endif // TILECELL_H
diff --git a/crawl-ref/source/tiledgnbuf.cc b/crawl-ref/source/tiledgnbuf.cc
index 483f05a30e..f3d937a30a 100644
--- a/crawl-ref/source/tiledgnbuf.cc
+++ b/crawl-ref/source/tiledgnbuf.cc
@@ -32,11 +32,6 @@ DungeonCellBuffer::DungeonCellBuffer(const ImageManager *im) :
{
}
-static bool _in_water(const packed_cell &cell)
-{
- return (cell.bg & TILE_FLAG_WATER) && !(cell.fg & TILE_FLAG_FLYING);
-}
-
void DungeonCellBuffer::add_glyph(const char32_t &g, const VColour &col, int x, int y)
{
float sx = x;
@@ -55,10 +50,10 @@ void DungeonCellBuffer::add(const packed_cell &cell, int x, int y)
{
pack_background(x, y, cell);
- const tileidx_t fg_idx = cell.fg & TILE_FLAG_MASK;
- const bool in_water = _in_water(cell);
+ const tileidx_t fg_idx = cell.fg.tile();
+ const bool in_water = is_in_water(cell);
- tileidx_t cloud_idx = cell.cloud & TILE_FLAG_MASK;
+ tileidx_t cloud_idx = cell.cloud;
// in the shoals, ink is handled in pack_cell_overlays(): don't overdraw
if (cloud_idx == TILE_CLOUD_INK && player_in_branch(BRANCH_SHOALS))
@@ -109,16 +104,15 @@ void DungeonCellBuffer::add(const packed_cell &cell, int x, int y)
void DungeonCellBuffer::add_monster(const monster_info &mon, int x, int y)
{
- tileidx_t t = tileidx_monster(mon);
- tileidx_t t0 = t & TILE_FLAG_MASK;
- tileidx_t flag = t & (~TILE_FLAG_MASK);
+ tile_with_flags_t t = tileidx_monster(mon);
+ tileidx_t t0 = t.tile();
// Copied from _tile_place_monster()
if (!mons_class_is_stationary(mon.type) || mon.type == MONS_TRAINING_DUMMY)
{
tileidx_t mcache_idx = mcache.register_monster(mon);
- t = flag | (mcache_idx ? mcache_idx : t0);
- t0 = t & TILE_FLAG_MASK;
+ t0 = mcache_idx ? mcache_idx : t0;
+ t.set_tile(t0);
}
// Copied from ::add()
@@ -280,8 +274,8 @@ void DungeonCellBuffer::add_blood_overlay(int x, int y, const packed_cell &cell,
void DungeonCellBuffer::pack_background(int x, int y, const packed_cell &cell)
{
- const tileidx_t bg = cell.bg;
- const tileidx_t bg_idx = cell.bg & TILE_FLAG_MASK;
+ const tile_with_flags_t bg = cell.bg;
+ const tileidx_t bg_idx = bg.tile();
if (bg_idx >= TILE_DNGN_FIRST_TRANSPARENT)
add_dngn_tile(cell.flv.floor, x, y);
@@ -305,80 +299,80 @@ void DungeonCellBuffer::pack_background(int x, int y, const packed_cell &cell)
add_dngn_tile(tile, x, y);
}
- if (!(bg & TILE_FLAG_UNSEEN))
+ if (!bg.has_flag(TILE_FLAG_UNSEEN))
{
// Add tentacle corner overlays.
- if (bg & TILE_FLAG_TENTACLE_NW)
+ if (bg.has_flag(TILE_FLAG_TENTACLE_NW))
{
- if (bg & TILE_FLAG_TENTACLE_KRAKEN)
+ if (bg.has_flag(TILE_FLAG_TENTACLE_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_OVERLAY_NW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_ELDRITCH)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_ELDRITCH))
m_buf_feat.add(TILE_ELDRITCH_OVERLAY_NW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_STARSPAWN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_STARSPAWN))
m_buf_feat.add(TILE_STARSPAWN_OVERLAY_NW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_VINE)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_VINE))
m_buf_feat.add(TILE_VINE_OVERLAY_NW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_ZOMBIE_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_ZOMBIE_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_ZOMBIE_OVERLAY_NW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_SIMULACRUM_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SIMULACRUM_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_SIMULACRUM_OVERLAY_NW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_SPECTRAL_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SPECTRAL_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_SPECTRAL_OVERLAY_NW, x, y);
}
- else if (bg & TILE_FLAG_TENTACLE_NE)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_NE))
{
- if (bg & TILE_FLAG_TENTACLE_KRAKEN)
+ if (bg.has_flag(TILE_FLAG_TENTACLE_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_OVERLAY_NE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_ELDRITCH)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_ELDRITCH))
m_buf_feat.add(TILE_ELDRITCH_OVERLAY_NE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_STARSPAWN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_STARSPAWN))
m_buf_feat.add(TILE_STARSPAWN_OVERLAY_NE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_VINE)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_VINE))
m_buf_feat.add(TILE_VINE_OVERLAY_NE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_ZOMBIE_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_ZOMBIE_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_ZOMBIE_OVERLAY_NE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_SIMULACRUM_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SIMULACRUM_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_SIMULACRUM_OVERLAY_NE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_SPECTRAL_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SPECTRAL_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_SPECTRAL_OVERLAY_NE, x, y);
}
- else if (bg & TILE_FLAG_TENTACLE_SW)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SW))
{
- if (bg & TILE_FLAG_TENTACLE_KRAKEN)
+ if (bg.has_flag(TILE_FLAG_TENTACLE_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_OVERLAY_SW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_ELDRITCH)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_ELDRITCH))
m_buf_feat.add(TILE_ELDRITCH_OVERLAY_SW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_STARSPAWN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_STARSPAWN))
m_buf_feat.add(TILE_STARSPAWN_OVERLAY_SW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_VINE)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_VINE))
m_buf_feat.add(TILE_VINE_OVERLAY_SW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_ZOMBIE_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_ZOMBIE_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_ZOMBIE_OVERLAY_SW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_SIMULACRUM_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SIMULACRUM_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_SIMULACRUM_OVERLAY_SW, x, y);
- else if (bg & TILE_FLAG_TENTACLE_SPECTRAL_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SPECTRAL_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_SPECTRAL_OVERLAY_SW, x, y);
}
- else if (bg & TILE_FLAG_TENTACLE_SE)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SE))
{
- if (bg & TILE_FLAG_TENTACLE_KRAKEN)
+ if (bg.has_flag(TILE_FLAG_TENTACLE_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_OVERLAY_SE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_ELDRITCH)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_ELDRITCH))
m_buf_feat.add(TILE_ELDRITCH_OVERLAY_SE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_STARSPAWN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_STARSPAWN))
m_buf_feat.add(TILE_STARSPAWN_OVERLAY_SE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_VINE)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_VINE))
m_buf_feat.add(TILE_VINE_OVERLAY_SE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_ZOMBIE_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_ZOMBIE_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_ZOMBIE_OVERLAY_SE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_SIMULACRUM_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SIMULACRUM_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_SIMULACRUM_OVERLAY_SE, x, y);
- else if (bg & TILE_FLAG_TENTACLE_SPECTRAL_KRAKEN)
+ else if (bg.has_flag(TILE_FLAG_TENTACLE_SPECTRAL_KRAKEN))
m_buf_feat.add(TILE_KRAKEN_SPECTRAL_OVERLAY_SE, x, y);
}
}
- if (!(bg & TILE_FLAG_UNSEEN))
+ if (!bg.has_flag(TILE_FLAG_UNSEEN))
{
if (cell.is_sanctuary)
m_buf_feat.add(TILE_SANCTUARY, x, y);
@@ -405,9 +399,9 @@ void DungeonCellBuffer::pack_background(int x, int y, const packed_cell &cell)
if (cell.has_bfb_corpse)
m_buf_feat.add(TILE_BLOOD_FOR_BLOOD, x, y);
- if (cell.fg)
+ if (cell.fg != 0)
{
- const tileidx_t att_flag = cell.fg & TILE_FLAG_ATT_MASK;
+ const tile_flag_t att_flag = cell.fg.flags(TILE_FLAG_ATT_MASK);
if (att_flag == TILE_FLAG_PET)
m_buf_feat.add(TILE_HALO_FRIENDLY, x, y);
else if (att_flag == TILE_FLAG_GD_NEUTRAL)
@@ -415,9 +409,9 @@ void DungeonCellBuffer::pack_background(int x, int y, const packed_cell &cell)
else if (att_flag == TILE_FLAG_NEUTRAL)
m_buf_feat.add(TILE_HALO_NEUTRAL, x, y);
- const tileidx_t threat_flag = cell.fg & TILE_FLAG_THREAT_MASK;
+ const tile_flag_t threat_flag = cell.fg.flags(TILE_FLAG_THREAT_MASK);
- if (cell.fg & TILE_FLAG_GHOST)
+ if (cell.fg.has_flag(TILE_FLAG_GHOST))
{
if (threat_flag == TILE_FLAG_TRIVIAL)
m_buf_feat.add(TILE_THREAT_GHOST_TRIVIAL, x, y);
@@ -450,9 +444,9 @@ void DungeonCellBuffer::pack_background(int x, int y, const packed_cell &cell)
// Apply the travel exclusion under the foreground if the cell is
// visible. It will be applied later if the cell is unseen.
- if (bg & TILE_FLAG_EXCL_CTR)
+ if (bg.has_flag(TILE_FLAG_EXCL_CTR))
m_buf_feat.add(TILE_TRAVEL_EXCLUSION_CENTRE_BG, x, y);
- else if (bg & TILE_FLAG_TRAV_EXCL)
+ else if (bg.has_flag(TILE_FLAG_TRAV_EXCL))
m_buf_feat.add(TILE_TRAVEL_EXCLUSION_BG, x, y);
}
@@ -461,10 +455,10 @@ void DungeonCellBuffer::pack_background(int x, int y, const packed_cell &cell)
void DungeonCellBuffer::pack_foreground(int x, int y, const packed_cell &cell)
{
- const tileidx_t fg = cell.fg;
- const tileidx_t bg = cell.bg;
- const tileidx_t fg_idx = cell.fg & TILE_FLAG_MASK;
- const bool in_water = _in_water(cell);
+ const tile_with_flags_t fg = cell.fg;
+ const tile_with_flags_t bg = cell.bg;
+ const tileidx_t fg_idx = fg.tile();
+ const bool in_water = is_in_water(cell);
if (get_tile_texture(fg_idx) == TEX_DEFAULT)
{
@@ -514,19 +508,19 @@ void DungeonCellBuffer::pack_foreground(int x, int y, const packed_cell &cell)
}
}
- if (fg & TILE_FLAG_NET)
+ if (fg.has_flag(TILE_FLAG_NET))
m_buf_icons.add(TILEI_TRAP_NET, x, y);
- if (fg & TILE_FLAG_WEB)
+ if (fg.has_flag(TILE_FLAG_WEB))
m_buf_icons.add(TILEI_TRAP_WEB, x, y);
- if (fg & TILE_FLAG_S_UNDER)
+ if (fg.has_flag(TILE_FLAG_S_UNDER))
m_buf_icons.add(TILEI_SOMETHING_UNDER, x, y);
// Pet mark
- if (fg & TILE_FLAG_ATT_MASK)
+ if (fg.has_flag(TILE_FLAG_ATT_MASK))
{
- const tileidx_t att_flag = fg & TILE_FLAG_ATT_MASK;
+ const tile_flag_t att_flag = fg.flags(TILE_FLAG_ATT_MASK);
if (att_flag == TILE_FLAG_PET)
m_buf_icons.add(TILEI_FRIENDLY, x, y);
else if (att_flag == TILE_FLAG_GD_NEUTRAL)
@@ -536,9 +530,9 @@ void DungeonCellBuffer::pack_foreground(int x, int y, const packed_cell &cell)
}
int status_shift = 0;
- if (fg & TILE_FLAG_BEH_MASK)
+ if (fg.has_flag(TILE_FLAG_BEH_MASK))
{
- const tileidx_t beh_flag = fg & TILE_FLAG_BEH_MASK;
+ const tile_flag_t beh_flag = fg.flags(TILE_FLAG_BEH_MASK);
if (beh_flag == TILE_FLAG_PARALYSED)
{
m_buf_icons.add(TILEI_PARALYSED, x, y);
@@ -561,9 +555,9 @@ void DungeonCellBuffer::pack_foreground(int x, int y, const packed_cell &cell)
}
}
- if (fg & TILE_FLAG_POISON_MASK)
+ if (fg.has_flag(TILE_FLAG_POISON_MASK))
{
- const tileidx_t poison_flag = fg & TILE_FLAG_POISON_MASK;
+ const tile_flag_t poison_flag = fg.flags(TILE_FLAG_POISON_MASK);
if (poison_flag == TILE_FLAG_POISON)
{
m_buf_icons.add(TILEI_POISON, x, y, -status_shift, 0);
@@ -597,7 +591,7 @@ void DungeonCellBuffer::pack_foreground(int x, int y, const packed_cell &cell)
m_buf_icons.add(icon, x, y, -status_shift, 0);
if (size < 0)
{
- mprf(MSGCH_ERROR, "unknown size for icon %" PRIu64, icon);
+ mprf(MSGCH_ERROR, "unknown size for icon %u", (unsigned)icon);
size = 7; // could maybe crash here?
}
status_shift += size;
@@ -605,16 +599,19 @@ void DungeonCellBuffer::pack_foreground(int x, int y, const packed_cell &cell)
// the tile. Oh well! (Could skip those..?)
}
- if (bg & TILE_FLAG_UNSEEN && (bg != TILE_FLAG_UNSEEN || fg))
+ if (bg.has_flag(TILE_FLAG_UNSEEN) && (bg != TILE_FLAG_UNSEEN || fg != 0))
m_buf_icons.add(TILEI_MESH, x, y);
- if (bg & TILE_FLAG_OOR && (bg != TILE_FLAG_OOR || fg))
+ if (bg.has_flag(TILE_FLAG_OOR) && (bg != TILE_FLAG_OOR || fg != 0))
m_buf_icons.add(TILEI_OOR_MESH, x, y);
- if (bg & TILE_FLAG_MM_UNSEEN && (bg != TILE_FLAG_MM_UNSEEN || fg))
+ if (bg.has_flag(TILE_FLAG_MM_UNSEEN)
+ && (bg != TILE_FLAG_MM_UNSEEN || fg != 0))
+ {
m_buf_icons.add(TILEI_MAGIC_MAP_MESH, x, y);
+ }
- if (bg & TILE_FLAG_RAMPAGE)
+ if (bg.has_flag(TILE_FLAG_RAMPAGE))
{
if (you.duration[DUR_TAILWIND])
m_buf_icons.add(TILEI_RAMPAGE_INSTANT, x, y);
@@ -624,27 +621,28 @@ void DungeonCellBuffer::pack_foreground(int x, int y, const packed_cell &cell)
// Don't let the "new stair" icon cover up any existing icons, but
// draw it otherwise.
- if (bg & TILE_FLAG_NEW_STAIR && status_shift == 0)
+ if (bg.has_flag(TILE_FLAG_NEW_STAIR) && status_shift == 0)
m_buf_icons.add(TILEI_NEW_STAIR, x, y);
- if (bg & TILE_FLAG_NEW_TRANSPORTER && status_shift == 0)
+ if (bg.has_flag(TILE_FLAG_NEW_TRANSPORTER) && status_shift == 0)
m_buf_icons.add(TILEI_NEW_TRANSPORTER, x, y);
- if (bg & TILE_FLAG_EXCL_CTR && (bg & TILE_FLAG_UNSEEN))
+ if (bg.has_flag(TILE_FLAG_EXCL_CTR) && bg.has_flag(TILE_FLAG_UNSEEN))
m_buf_icons.add(TILEI_TRAVEL_EXCLUSION_CENTRE_FG, x, y);
- else if (bg & TILE_FLAG_TRAV_EXCL && (bg & TILE_FLAG_UNSEEN))
+ else if (bg.has_flag(TILE_FLAG_TRAV_EXCL) && bg.has_flag(TILE_FLAG_UNSEEN))
m_buf_icons.add(TILEI_TRAVEL_EXCLUSION_FG, x, y);
// Tutorial cursor takes precedence over other cursors.
- if (bg & TILE_FLAG_TUT_CURSOR)
+ if (bg.has_flag(TILE_FLAG_TUT_CURSOR))
m_buf_icons.add(TILEI_TUTORIAL_CURSOR, x, y);
- else if (bg & TILE_FLAG_CURSOR)
+ else if (bg.has_flag(TILE_FLAG_CURSOR))
{
- int type = ((bg & TILE_FLAG_CURSOR) == TILE_FLAG_CURSOR1) ?
- TILEI_CURSOR : TILEI_CURSOR2;
-
- if ((bg & TILE_FLAG_CURSOR) == TILE_FLAG_CURSOR3)
- type = TILEI_CURSOR3;
+ const tile_flag_t cursor_flag = bg.flags(TILE_FLAG_CURSOR);
+ tileidx_t type = TILEI_CURSOR2;
+ if (cursor_flag == TILE_FLAG_CURSOR3)
+ type = TILEI_CURSOR3;
+ else if (cursor_flag == TILE_FLAG_CURSOR1)
+ type = TILEI_CURSOR;
m_buf_icons.add(type, x, y);
}
@@ -660,9 +658,9 @@ void DungeonCellBuffer::pack_foreground(int x, int y, const packed_cell &cell)
((cell.travel_trail & 0xF0) >> 4) - 1, x, y);
}
- if (fg & TILE_FLAG_MDAM_MASK)
+ if (fg.has_flag(TILE_FLAG_MDAM_MASK))
{
- tileidx_t mdam_flag = fg & TILE_FLAG_MDAM_MASK;
+ const tile_flag_t mdam_flag = fg.flags(TILE_FLAG_MDAM_MASK);
if (mdam_flag == TILE_FLAG_MDAM_LIGHT)
m_buf_icons.add(TILEI_MDAM_LIGHTLY_DAMAGED, x, y);
else if (mdam_flag == TILE_FLAG_MDAM_MOD)
@@ -675,9 +673,9 @@ void DungeonCellBuffer::pack_foreground(int x, int y, const packed_cell &cell)
m_buf_icons.add(TILEI_MDAM_ALMOST_DEAD, x, y);
}
- if (fg & TILE_FLAG_DEMON)
+ if (fg.has_flag(TILE_FLAG_DEMON))
{
- tileidx_t demon_flag = fg & TILE_FLAG_DEMON;
+ const tile_flag_t demon_flag = fg.flags(TILE_FLAG_DEMON);
if (demon_flag == TILE_FLAG_DEMON_1)
m_buf_icons.add(TILEI_DEMON_NUM1, x, y);
else if (demon_flag == TILE_FLAG_DEMON_2)
diff --git a/crawl-ref/source/tilemcache.cc b/crawl-ref/source/tilemcache.cc
index cea26631c7..8af6c8cf8d 100644
--- a/crawl-ref/source/tilemcache.cc
+++ b/crawl-ref/source/tilemcache.cc
@@ -125,22 +125,24 @@ protected:
/////////////////////////////////////////////////////////////////////////////
// tile_fg_store
-tileidx_t tile_fg_store::operator=(tileidx_t tile)
+tile_with_flags_t tile_fg_store::operator=(tile_with_flags_t tile)
{
- if ((tile & TILE_FLAG_MASK) == (m_tile & TILE_FLAG_MASK))
+ if (tile.tile() == m_tile.tile())
{
// Update, as flags may have changed.
m_tile = tile;
return m_tile;
}
- mcache_entry *old_entry = mcache.get(m_tile);
+ tileidx_t old_tile = m_tile.tile();
+ mcache_entry *old_entry = mcache.get(old_tile);
if (old_entry)
old_entry->dec_ref();
m_tile = tile;
- mcache_entry *new_entry = mcache.get(m_tile);
+ tileidx_t new_tile = m_tile.tile();
+ mcache_entry *new_entry = mcache.get(new_tile);
if (new_entry)
new_entry->inc_ref();
@@ -155,7 +157,7 @@ mcache_manager::~mcache_manager()
clear_all();
}
-unsigned int mcache_manager::register_monster(const monster_info& minf)
+tileidx_t mcache_manager::register_monster(const monster_info& minf)
{
// TODO enne - is it worth it to search against all mcache entries?
// TODO enne - pool mcache types to avoid too much alloc/dealloc?
@@ -186,7 +188,7 @@ unsigned int mcache_manager::register_monster(const monster_info& minf)
tileidx_t idx = ~0;
- for (unsigned int i = 0; i < m_entries.size(); i++)
+ for (tileidx_t i = 0; i < (tileidx_t)m_entries.size(); i++)
{
if (!m_entries[i])
{
@@ -198,7 +200,7 @@ unsigned int mcache_manager::register_monster(const monster_info& minf)
if (idx > m_entries.size())
{
- idx = m_entries.size();
+ idx = (tileidx_t)m_entries.size();
m_entries.push_back(entry);
}
@@ -222,9 +224,8 @@ void mcache_manager::clear_all()
deleteAll(m_entries);
}
-mcache_entry *mcache_manager::get(tileidx_t tile)
+mcache_entry *mcache_manager::get(tileidx_t idx)
{
- tileidx_t idx = tile & TILE_FLAG_MASK;
if (idx < TILEP_MCACHE_START)
return nullptr;
@@ -243,7 +244,7 @@ mcache_monster::mcache_monster(const monster_info& mon)
ASSERT(mcache_monster::valid(mon));
mtype = mon.type;
- m_mon_tile = tileidx_monster(mon) & TILE_FLAG_MASK;
+ m_mon_tile = tileidx_monster(mon).tile();
const item_def* mon_weapon = mon.inv[MSLOT_WEAPON].get();
m_equ_tile = (mon_weapon != nullptr) ? tilep_equ_weapon(*mon_weapon) : 0;
@@ -1461,7 +1462,7 @@ int mcache_monster::info(tile_draw_info *dinfo) const
bool mcache_monster::valid(const monster_info& mon)
{
- tileidx_t mon_tile = tileidx_monster(mon) & TILE_FLAG_MASK;
+ tileidx_t mon_tile = tileidx_monster(mon).tile();
int ox, oy;
bool have_weapon_offs = (mon.type == MONS_PLAYER
@@ -1675,7 +1676,7 @@ mcache_armour::mcache_armour(const monster_info& mon)
{
ASSERT(mcache_armour::valid(mon));
- m_mon_tile = tileidx_monster(mon) & TILE_FLAG_MASK;
+ m_mon_tile = tileidx_monster(mon).tile();
const item_def* mon_armour = mon.inv[MSLOT_ARMOUR].get();
if (mon_armour)
diff --git a/crawl-ref/source/tilemcache.h b/crawl-ref/source/tilemcache.h
index 50ce6f4c3b..6b000c14ee 100644
--- a/crawl-ref/source/tilemcache.h
+++ b/crawl-ref/source/tilemcache.h
@@ -64,7 +64,7 @@ class mcache_manager
public:
~mcache_manager();
- unsigned int register_monster(const monster_info& mon);
+ tileidx_t register_monster(const monster_info& mon);
mcache_entry *get(tileidx_t idx);
void clear_nonref();
diff --git a/crawl-ref/source/tilepick-p.cc b/crawl-ref/source/tilepick-p.cc
index deb9d0fdb6..a52de491fb 100644
--- a/crawl-ref/source/tilepick-p.cc
+++ b/crawl-ref/source/tilepick-p.cc
@@ -418,9 +418,9 @@ tileidx_t tilep_equ_boots(const item_def &item)
return tile ? tileidx_enchant_equ(item, tile) : 0;
}
-tileidx_t tileidx_player()
+tile_with_flags_t tileidx_player()
{
- tileidx_t ch = TILEP_PLAYER;
+ tile_with_flags_t ch = TILEP_PLAYER;
// Currently, the flying flag is only used for not drawing the tile in the
// water. in_water() checks Beogh's water walking. If the flying flag is
diff --git a/crawl-ref/source/tilepick-p.h b/crawl-ref/source/tilepick-p.h
index 4c7e8687e8..0f904f620a 100644
--- a/crawl-ref/source/tilepick-p.h
+++ b/crawl-ref/source/tilepick-p.h
@@ -22,7 +22,7 @@ tileidx_t tilep_equ_helm(const item_def &item);
tileidx_t tilep_equ_gloves(const item_def &item);
tileidx_t tilep_equ_boots(const item_def &item);
-tileidx_t tileidx_player();
+tile_with_flags_t tileidx_player();
bool is_player_tile(tileidx_t tile, tileidx_t base_tile);
bool player_uses_monster_tile();
diff --git a/crawl-ref/source/tilepick.cc b/crawl-ref/source/tilepick.cc
index c391abd1d4..6f0ae62a2b 100644
--- a/crawl-ref/source/tilepick.cc
+++ b/crawl-ref/source/tilepick.cc
@@ -93,7 +93,7 @@ TextureID get_tile_texture(tileidx_t idx)
else if (idx < TILEI_ICONS_MAX)
return TEX_ICONS;
else
- die("Cannot get texture for bad tileidx %" PRIu64, idx);
+ die("Cannot get texture for bad tileidx %u", (unsigned)idx);
}
#endif
@@ -622,11 +622,8 @@ static int _get_door_offset(tileidx_t base_tile,
return offset + gateway_type;
}
-static tileidx_t _apply_branch_tile_overrides(tileidx_t tile, coord_def gc)
+static tileidx_t _apply_branch_tile_overrides(tileidx_t orig, coord_def gc)
{
- tileidx_t orig = tile & TILE_FLAG_MASK;
- tileidx_t flag = tile & (~TILE_FLAG_MASK);
-
// TODO: allow the stone type to be set in a cleaner way.
if (player_in_branch(BRANCH_GAUNTLET))
{
@@ -797,7 +794,7 @@ static tileidx_t _apply_branch_tile_overrides(tileidx_t tile, coord_def gc)
orig = TILE_DNGN_GRANITE_STATUE_DEPTHS_ZOT;
}
}
- return orig | flag;
+ return orig;
}
static colour_t _feat_colour(coord_def gc)
@@ -862,8 +859,7 @@ static colour_t _feat_colour(coord_def gc)
void apply_variations(const tile_flavour &flv, tileidx_t *bg,
const coord_def &gc)
{
- tileidx_t tile = (*bg) & TILE_FLAG_MASK;
- tileidx_t flag = (*bg) & (~TILE_FLAG_MASK);
+ tileidx_t tile = *bg;
if (tile == TILE_DNGN_UNSEEN)
return;
@@ -922,7 +918,7 @@ void apply_variations(const tile_flavour &flv, tileidx_t *bg,
if (!needs_tile_picking)
{
- *bg = tile | flag;
+ *bg = tile;
return;
}
@@ -941,7 +937,7 @@ void apply_variations(const tile_flavour &flv, tileidx_t *bg,
else if (tile < TILE_DNGN_MAX)
tile = pick_dngn_tile(tile, flv.special);
- *bg = tile | flag;
+ *bg = tile;
}
static tileidx_t _tileidx_feature_no_overrides(const coord_def &gc)
@@ -1267,7 +1263,7 @@ tileidx_t tileidx_tentacle(const monster_info& mon)
}
#ifdef USE_TILE
-tileidx_t tileidx_out_of_bounds(int branch)
+tile_with_flags_t tileidx_out_of_bounds(int branch)
{
if (branch == BRANCH_SHOALS)
return TILE_DNGN_OPEN_SEA | TILE_FLAG_UNSEEN;
@@ -1275,11 +1271,14 @@ tileidx_t tileidx_out_of_bounds(int branch)
return TILE_DNGN_UNSEEN | TILE_FLAG_UNSEEN;
}
-void tileidx_out_of_los(tileidx_t *fg, tileidx_t *bg, tileidx_t *cloud, const coord_def& gc)
+void tileidx_out_of_los(tile_with_flags_t *fg,
+ tile_with_flags_t *bg,
+ tileidx_t *cloud,
+ const coord_def& gc)
{
// Player memory.
- tileidx_t mem_fg = tile_env.bk_fg(gc);
- tileidx_t mem_bg = tile_env.bk_bg(gc);
+ tile_with_flags_t mem_fg = tile_env.bk_fg(gc);
+ tile_with_flags_t mem_bg = tile_env.bk_bg(gc);
tileidx_t mem_cloud = tile_env.bk_cloud(gc);
// Detected info is just stored in map_knowledge and doesn't get
@@ -1957,7 +1956,7 @@ static tileidx_t _mon_cycle(tileidx_t tile, int offset)
// extra parameters that have reasonable defaults for monsters where
// only the type is known are pushed here.
tileidx_t tileidx_monster_base(int type, int mon_id, bool in_water, int colour,
- int number, int tile_num_prop, bool vary)
+ int number, int tile_num_prop, bool vary)
{
switch (type)
{
@@ -2235,7 +2234,7 @@ static tileidx_t _tileidx_monster_no_props(const monster_info& mon)
const bool in_water = feat_is_water(env.map_knowledge(mon.pos).feat());
if (mon.props.exists(MONSTER_TILE_KEY))
- return mon.props[MONSTER_TILE_KEY].get_int();
+ return (tileidx_t)mon.props[MONSTER_TILE_KEY].get_int();
// Show only base class for detected monsters.
if (mons_class_is_zombified(mon.type))
@@ -2247,9 +2246,9 @@ static tileidx_t _tileidx_monster_no_props(const monster_info& mon)
bool vary = !(mon.props.exists(FAKE_MON_KEY) && mon.props[FAKE_MON_KEY].get_bool());
const tileidx_t base = tileidx_monster_base(mon.type,
- mon.pos.y*GXM + mon.pos.x,
- in_water, mon.colour(true),
- mon.number, tile_num, vary);
+ mon.pos.y*GXM + mon.pos.x,
+ in_water, mon.colour(true),
+ mon.number, tile_num, vary);
switch (mon.type)
{
@@ -2529,11 +2528,12 @@ static tileidx_t _tileidx_monster_no_props(const monster_info& mon)
}
}
-tileidx_t tileidx_monster(const monster_info& mons)
+tile_with_flags_t tileidx_monster(const monster_info& mons)
{
- tileidx_t ch = _tileidx_monster_no_props(mons);
+ tileidx_t tile = _tileidx_monster_no_props(mons);
+ tile_with_flags_t ch = tile;
- if ((mons.airborne() && !_tentacle_tile_not_flying(ch))
+ if ((mons.airborne() && !_tentacle_tile_not_flying(tile))
|| mons.type == MONS_ORC_APOSTLE || mons.type == MONS_SACRED_LOTUS)
{
ch |= TILE_FLAG_FLYING;
@@ -3823,7 +3823,7 @@ tileidx_t tileidx_cloud(const cloud_info &cl)
#ifdef USE_TILE
tileidx_t vary_bolt_tile(tileidx_t tile, const coord_def& origin,
- const coord_def& target, const coord_def& pos)
+ const coord_def& target, const coord_def& pos)
{
const coord_def diff = target - origin;
const int dir = _tile_bolt_dir(diff.x, diff.y);
@@ -4918,7 +4918,7 @@ tileidx_t tileidx_known_brand(const item_def &item)
}
#ifdef USE_TILE
-tileidx_t tileidx_unseen_flag(const coord_def &gc)
+tile_flag_t tileidx_unseen_flag(const coord_def &gc)
{
if (!map_bounds(gc))
return TILE_FLAG_UNSEEN;
@@ -5017,10 +5017,11 @@ tileidx_t tileidx_enchant_equ(const item_def &item, tileidx_t tile)
}
#ifdef USE_TILE
-string tile_debug_string(tileidx_t fg, tileidx_t bg, char prefix)
+string tile_debug_string(tile_with_flags_t fg, tile_with_flags_t bg,
+ char prefix)
{
- tileidx_t fg_idx = fg & TILE_FLAG_MASK;
- tileidx_t bg_idx = bg & TILE_FLAG_MASK;
+ tileidx_t fg_idx = fg.tile();
+ tileidx_t bg_idx = bg.tile();
string fg_name;
if (fg_idx < TILE_FLOOR_MAX)
@@ -5062,15 +5063,15 @@ string tile_debug_string(tileidx_t fg, tileidx_t bg, char prefix)
}
string tile_string = make_stringf(
- "%cFG: %4" PRIu64" | 0x%8llu (%s)\n"
- "%cBG: %4" PRIu64" | 0x%8llu (%s)\n",
+ "%cFG: %4u | 0x%8llu (%s)\n"
+ "%cBG: %4u | 0x%8llu (%s)\n",
prefix,
- fg_idx,
- fg & ~TILE_FLAG_MASK,
+ (unsigned)fg_idx,
+ (unsigned long long)fg.flags(),
fg_name.c_str(),
prefix,
- bg_idx,
- bg & ~TILE_FLAG_MASK,
+ (unsigned)bg_idx,
+ (unsigned long long)bg.flags(),
tile_dngn_name(bg_idx));
return tile_string;
diff --git a/crawl-ref/source/tilepick.h b/crawl-ref/source/tilepick.h
index a02b1bf453..90b0b75ee4 100644
--- a/crawl-ref/source/tilepick.h
+++ b/crawl-ref/source/tilepick.h
@@ -36,10 +36,13 @@ tileidx_t tileidx_feature_for_cache(coord_def gc);
tileidx_t tileidx_feature(const coord_def &gc);
tileidx_t tileidx_shop(const shop_struct *shop);
tileidx_t tileidx_feature_base(dungeon_feature_type feat);
-tileidx_t tileidx_out_of_bounds(int branch);
-void tileidx_out_of_los(tileidx_t *fg, tileidx_t *bg, tileidx_t *cloud, const coord_def& gc);
+tile_with_flags_t tileidx_out_of_bounds(int branch);
+void tileidx_out_of_los(tile_with_flags_t *fg,
+ tile_with_flags_t *bg,
+ tileidx_t *cloud,
+ const coord_def& gc);
-tileidx_t tileidx_monster(const monster_info& mon);
+tile_with_flags_t tileidx_monster(const monster_info& mon);
tileidx_t tileidx_draco_base(const monster_info& mon);
tileidx_t tileidx_draco_job(const monster_info& mon);
tileidx_t tileidx_player_mons();
@@ -53,7 +56,7 @@ tileidx_t tileidx_known_base_item(tileidx_t label);
tileidx_t tileidx_cloud(const cloud_info &cl);
tileidx_t tileidx_bolt(const bolt &bolt);
tileidx_t vary_bolt_tile(tileidx_t tile, const coord_def& origin,
- const coord_def& target, const coord_def& pos);
+ const coord_def& target, const coord_def& pos);
tileidx_t vary_bolt_tile(tileidx_t tile, int dir = 0, int dist = 0);
tileidx_t tileidx_zap(int colour, coord_def pos);
tileidx_t tileidx_spell(const spell_type spell);
@@ -67,7 +70,7 @@ tileidx_t tileidx_player_species(const species_type species, bool recommended);
tileidx_t tileidx_known_brand(const item_def &item);
-tileidx_t tileidx_unseen_flag(const coord_def &gc);
+tile_flag_t tileidx_unseen_flag(const coord_def &gc);
set<tileidx_t> status_icons_for(const monster_info &mon);
set<tileidx_t> status_icons_for_player();
@@ -81,12 +84,13 @@ void bind_item_tile(item_def &item);
// For a given fg/bg set of tile indices and a 1 character prefix,
// return index, flag, and tile name as a printable string.
-string tile_debug_string(tileidx_t fg, tileidx_t bg, char prefix);
+string tile_debug_string(tile_with_flags_t fg, tile_with_flags_t bg,
+ char prefix);
void tile_init_props(monster* mon);
tileidx_t tileidx_monster_base(int type, int mon_id, bool in_water = false,
- int colour = 0, int number = 4, int tile_num_prop = 0,
- bool vary = true);
+ int colour = 0, int number = 4, int tile_num_prop = 0,
+ bool vary = true);
tileidx_t tileidx_mon_clamp(tileidx_t tile, int offset);
void init_parchment_overlays();
diff --git a/crawl-ref/source/tilereg-doll.cc b/crawl-ref/source/tilereg-doll.cc
index 3b412f1ad8..7334103bf9 100644
--- a/crawl-ref/source/tilereg-doll.cc
+++ b/crawl-ref/source/tilereg-doll.cc
@@ -39,7 +39,7 @@ void DollEditRegion::clear()
m_font_buf.clear();
}
-static int _get_next_part(int cat, int part, int inc)
+static tileidx_t _get_next_part(int cat, tileidx_t part, int inc)
{
// Can't increment or decrement on show equip.
if (part == TILEP_SHOW_EQUIP)
@@ -48,12 +48,13 @@ static int _get_next_part(int cat, int part, int inc)
// Increment max_part by 1 to include the special value of "none".
// (Except for the base, for which "none" is disallowed.)
int max_part = tile_player_part_count[cat] + 1;
- int offset = tile_player_part_start[cat];
+ tileidx_t category_start = tile_player_part_start[cat];
if (cat == TILEP_PART_BASE)
{
- offset = tilep_species_to_base_tile(you.species, you.experience_level);
- max_part = tile_player_count(offset);
+ category_start = tilep_species_to_base_tile(you.species,
+ you.experience_level);
+ max_part = tile_player_count(category_start);
}
ASSERT(inc > -max_part || inc == -1);
@@ -61,14 +62,16 @@ static int _get_next_part(int cat, int part, int inc)
// Translate the "none" value into something we can do modulo math with.
if (part == 0)
{
- part = offset;
+ part = category_start;
inc--;
}
- // Valid part numbers are in the range [offset, offset + max_part - 1].
- int ret = (part + max_part + inc - offset) % (max_part);
+ // Valid part numbers are in the range
+ // [category_start, category_start + max_part - 1].
+ int offset_in_category = (int)(part - category_start);
+ int new_offset = (offset_in_category + max_part + inc) % (max_part);
- if (cat != TILEP_PART_BASE && ret == max_part - 1)
+ if (cat != TILEP_PART_BASE && new_offset == max_part - 1)
{
// "none" value.
return 0;
@@ -76,7 +79,7 @@ static int _get_next_part(int cat, int part, int inc)
else
{
// Otherwise, valid part number.
- return ret + offset;
+ return category_start + new_offset;
}
}
diff --git a/crawl-ref/source/tilereg-doll.h b/crawl-ref/source/tilereg-doll.h
index 9d4625a3e0..73452f4308 100644
--- a/crawl-ref/source/tilereg-doll.h
+++ b/crawl-ref/source/tilereg-doll.h
@@ -23,7 +23,7 @@ protected:
// Currently edited category of parts.
int m_cat_idx;
// Current part in current category.
- int m_part_idx;
+ tileidx_t m_part_idx;
// Set of loaded dolls.
dolls_data m_dolls[NUM_MAX_DOLLS];
diff --git a/crawl-ref/source/tileview.cc b/crawl-ref/source/tileview.cc
index 5fb7dacbe9..90a07c7b51 100644
--- a/crawl-ref/source/tileview.cc
+++ b/crawl-ref/source/tileview.cc
@@ -58,15 +58,15 @@ void tile_new_level(bool first_time, bool init_unseen)
for (unsigned int x = 0; x < GXM; x++)
for (unsigned int y = 0; y < GYM; y++)
{
- unsigned int tile = tile_env.bk_bg[x][y];
- if ((tile & TILE_FLAG_NEW_STAIR)
+ tile_with_flags_t tile = tile_env.bk_bg[x][y];
+ if ((tile.has_flag(TILE_FLAG_NEW_STAIR))
&& !is_unknown_stair(coord_def(x,y)))
{
- tile_env.bk_bg[x][y] &= ~TILE_FLAG_NEW_STAIR;
+ tile_env.bk_bg[x][y].remove_flag(TILE_FLAG_NEW_STAIR);
}
- else if ((tile & TILE_FLAG_NEW_TRANSPORTER)
+ else if ((tile.has_flag(TILE_FLAG_NEW_TRANSPORTER))
&& !is_unknown_transporter(coord_def(x,y)))
- tile_env.bk_bg[x][y] &= ~TILE_FLAG_NEW_TRANSPORTER;
+ tile_env.bk_bg[x][y].remove_flag(TILE_FLAG_NEW_TRANSPORTER);
}
tiles.clear_minimap();
@@ -909,9 +909,9 @@ void tile_draw_map_cells()
}
}
-static tileidx_t _get_floor_bg(const coord_def& gc)
+static tile_with_flags_t _get_floor_bg(const coord_def& gc)
{
- tileidx_t bg = TILE_DNGN_UNSEEN | tileidx_unseen_flag(gc);
+ tile_with_flags_t bg(TILE_DNGN_UNSEEN, tileidx_unseen_flag(gc));
if (map_bounds(gc))
{
@@ -943,7 +943,7 @@ void tile_draw_floor()
if (!you.see_cell(gc))
continue;
- tileidx_t bg = _get_floor_bg(gc);
+ tile_with_flags_t bg = _get_floor_bg(gc);
// init tiles
tile_env.bk_bg(gc) = bg;
@@ -966,7 +966,7 @@ void tile_forget_map(const coord_def &gc)
static void _tile_place_item(const coord_def &gc, const item_def &item,
bool more_items)
{
- tileidx_t t = tileidx_item(item);
+ tile_with_flags_t t = tileidx_item(item);
if (more_items)
t |= TILE_FLAG_S_UNDER;
@@ -978,7 +978,8 @@ static void _tile_place_item(const coord_def &gc, const item_def &item,
static void _tile_place_item_marker(const coord_def &gc, const item_def &item)
{
- tile_env.bk_fg(gc) = ((tileidx_t)tile_env.bk_fg(gc)) | TILE_FLAG_S_UNDER;
+ tile_with_flags_t fg = tile_env.bk_fg(gc);
+ tile_env.bk_fg(gc) = fg | TILE_FLAG_S_UNDER;
if (item_needs_autopickup(item))
tile_env.bk_bg(gc) |= TILE_FLAG_CURSOR3;
@@ -1007,9 +1008,8 @@ static void _tile_place_invisible_monster(const coord_def &gc)
static void _tile_place_monster(const coord_def &gc, const monster_info& mon)
{
- tileidx_t t = tileidx_monster(mon);
- tileidx_t t0 = t & TILE_FLAG_MASK;
- tileidx_t flag = t & (~TILE_FLAG_MASK);
+ tile_with_flags_t t = tileidx_monster(mon);
+ tileidx_t t0 = t.tile();
if (mons_class_is_stationary(mon.type)
&& mon.type != MONS_TRAINING_DUMMY)
@@ -1026,7 +1026,8 @@ static void _tile_place_monster(const coord_def &gc, const monster_info& mon)
else
{
tileidx_t mcache_idx = mcache.register_monster(mon);
- t = flag | (mcache_idx ? mcache_idx : t0);
+ t0 = mcache_idx ? mcache_idx : t0;
+ t.set_tile(t0);
}
tile_env.bk_fg(gc) = t;
@@ -1070,7 +1071,7 @@ static void _tile_place_monster(const coord_def &gc, const monster_info& mon)
void tile_reset_fg(const coord_def &gc)
{
// remove autopickup cursor, it will be added back if necessary
- tile_env.bk_bg(gc) &= ~TILE_FLAG_CURSOR3;
+ tile_env.bk_bg(gc).remove_flag(TILE_FLAG_CURSOR3);
tile_draw_map_cell(gc, true);
tiles.update_minimap(gc);
}
@@ -1140,11 +1141,9 @@ static bool _tile_has_random_misc_animation(tileidx_t tile)
// Updates the "flavour" of tiles that are animated.
// Unfortunately, these are all hard-coded for now.
-void tile_apply_animations(tileidx_t bg, tile_flavour *flv)
+void tile_apply_animations(tileidx_t bg_idx, tile_flavour *flv)
{
#ifndef USE_TILE_WEB
- tileidx_t bg_idx = bg & TILE_FLAG_MASK;
-
if (_tile_has_cycling_misc_animation(bg_idx))
flv->special = (flv->special + 1) % tile_dngn_count(bg_idx);
else if (bg_idx == TILE_DNGN_LAVA && Options.tile_water_anim)
@@ -1163,7 +1162,7 @@ void tile_apply_animations(tileidx_t bg, tile_flavour *flv)
else if (_tile_has_random_misc_animation(bg_idx))
flv->special = random2(256);
#else
- UNUSED(bg, flv);
+ UNUSED(bg_idx, flv);
#endif
}
@@ -1215,7 +1214,9 @@ void tile_apply_properties(const coord_def &gc, packed_cell &cell)
if (!map_bounds(gc))
return;
- apply_variations(tile_env.flv(gc), &cell.bg, gc);
+ tileidx_t bg_tile = cell.bg.tile();
+ apply_variations(tile_env.flv(gc), &bg_tile, gc);
+ cell.bg.set_tile(bg_tile);
const map_cell& mc = env.map_knowledge(gc);
@@ -1239,7 +1240,7 @@ void tile_apply_properties(const coord_def &gc, packed_cell &cell)
if (mc.flags & MAP_LIQUEFIED)
cell.is_liquefied = true;
else if (print_blood && (feat_suppress_blood(mc.feat())
- || _suppress_blood((cell.bg) & TILE_FLAG_MASK)))
+ || _suppress_blood(bg_tile)))
{
print_blood = false;
}
@@ -1316,8 +1317,9 @@ void tile_apply_properties(const coord_def &gc, packed_cell &cell)
{
// Use the id of the underlying tile to randomize the rock appearance.
// XXX: This doesn't look great when the underlying tile is animated.
- tileidx_t tile = TILE_FLOOR_SEISMOROCK
- + cell.bg % tile_dngn_count(TILE_FLOOR_SEISMOROCK);
+ unsigned int tile_count = tile_dngn_count(TILE_FLOOR_SEISMOROCK);
+ tileidx_t offset = (tileidx_t)(cell.bg.value % tile_count);
+ tileidx_t tile = TILE_FLOOR_SEISMOROCK + offset;
cell.add_overlay(tile);
}
diff --git a/crawl-ref/source/tileweb.cc b/crawl-ref/source/tileweb.cc
index 65406f9006..e85706703b 100644
--- a/crawl-ref/source/tileweb.cc
+++ b/crawl-ref/source/tileweb.cc
@@ -1561,14 +1561,9 @@ void TilesFramework::send_mcache(mcache_entry *entry, bool submerged, bool send)
tiles.json_close_array();
}
-static bool _in_water(const packed_cell &cell)
-{
- return (cell.bg & TILE_FLAG_WATER) && !(cell.fg & TILE_FLAG_FLYING);
-}
-
static bool _needs_flavour(const packed_cell &cell)
{
- tileidx_t bg_idx = cell.bg & TILE_FLAG_MASK;
+ tileidx_t bg_idx = cell.bg.tile();
if (bg_idx >= TILE_DNGN_FIRST_TRANSPARENT)
return true; // Needs flv.floor
if (cell.is_liquefied || cell.is_bloody)
@@ -1593,11 +1588,11 @@ static inline unsigned _get_highlight(int col)
: unsigned{CHATTR_NORMAL};
}
-void TilesFramework::write_tileidx(tileidx_t t)
+void TilesFramework::write_tile_with_flags(tile_with_flags_t t)
{
// JS can only handle signed ints
- const int lo = t & 0xFFFFFFFF;
- const int hi = t >> 32;
+ const int lo = t.value & 0xFFFFFFFF;
+ const int hi = t.value >> 32;
if (hi == 0)
tiles.write_message("%d", lo);
else
@@ -1648,9 +1643,9 @@ void TilesFramework::_send_cell(const coord_def &gc,
const packed_cell &next_pc = next_sc.tile;
const packed_cell ¤t_pc = current_sc.tile;
- const tileidx_t fg_idx = next_pc.fg & TILE_FLAG_MASK;
+ const tileidx_t fg_idx = next_pc.fg.tile();
- const bool in_water = _in_water(next_pc);
+ const bool in_water = is_in_water(next_pc);
bool fg_changed = false;
if (next_pc.fg != current_pc.fg)
@@ -1658,7 +1653,7 @@ void TilesFramework::_send_cell(const coord_def &gc,
fg_changed = true;
json_write_name("fg");
- write_tileidx(next_pc.fg);
+ write_tile_with_flags(next_pc.fg);
if (get_tile_texture(fg_idx) == TEX_DEFAULT)
json_write_int("base", (int) tileidx_known_base_item(fg_idx));
@@ -1683,13 +1678,13 @@ void TilesFramework::_send_cell(const coord_def &gc,
if (next_pc.bg != current_pc.bg)
{
json_write_name("bg");
- write_tileidx(next_pc.bg);
+ write_tile_with_flags(next_pc.bg);
}
if (next_pc.cloud != current_pc.cloud)
{
json_write_name("cloud");
- write_tileidx(next_pc.cloud);
+ json_write_int(next_pc.cloud);
}
if (next_pc.icons != current_pc.icons)
@@ -1883,7 +1878,7 @@ void TilesFramework::_mcache_ref(bool inc)
{
coord_def gc(x, y);
- int fg_idx = m_current_view(gc).tile.fg & TILE_FLAG_MASK;
+ int fg_idx = m_current_view(gc).tile.fg.tile();
if (fg_idx >= TILEP_MCACHE_START)
{
mcache_entry *entry = mcache.get(fg_idx);
@@ -2615,10 +2610,7 @@ void TilesFramework::json_write_icons(const set<tileidx_t> &icons)
{
json_open_array("icons");
for (const tileidx_t icon : icons)
- {
- json_write_comma(); // skipped for the first one
- write_tileidx(icon);
- }
+ json_write_int(icon);
json_close_array();
}
diff --git a/crawl-ref/source/tileweb.h b/crawl-ref/source/tileweb.h
index f10d878349..183c67175b 100644
--- a/crawl-ref/source/tileweb.h
+++ b/crawl-ref/source/tileweb.h
@@ -221,7 +221,7 @@ public:
void send_mcache(mcache_entry *entry, bool submerged,
bool send = true);
- void write_tileidx(tileidx_t t);
+ void write_tile_with_flags(tile_with_flags_t t);
void zoom_dungeon(bool in);
diff --git a/crawl-ref/source/util/art-data.pl b/crawl-ref/source/util/art-data.pl
index 8a246ef908..2255b5ec07 100755
--- a/crawl-ref/source/util/art-data.pl
+++ b/crawl-ref/source/util/art-data.pl
@@ -967,7 +967,7 @@ HEADER_END
#include "rltiles/tiledef-main.h"
#include "rltiles/tiledef-player.h"
-int unrandart_to_tile(int unrand)
+tileidx_t unrandart_to_tile(int unrand)
{
switch (unrand)
{
@@ -995,7 +995,7 @@ HEADER_END
$text .= (" " x 4) . "}\n";
$text .= "}\n\n";
- $text .= "int unrandart_to_doll_tile(int unrand)\n{\n";
+ $text .= "tileidx_t unrandart_to_doll_tile(int unrand)\n{\n";
$text .= (" " x 4) . "switch (unrand)\n";
$text .= (" " x 4) . "{\n";
foreach my $part (sort keys %parts)
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 40cf2b3233..b06fca8963 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -417,7 +417,7 @@ static void _draw_player(screen_cell_t *cell,
cell->tile.cloud = tile_env.bk_cloud(gc);
cell->tile.icons = status_icons_for_player();
if (anim_updates)
- tile_apply_animations(cell->tile.bg, &tile_env.flv(gc));
+ tile_apply_animations(cell->tile.bg.tile(), &tile_env.flv(gc));
#else
UNUSED(anim_updates);
#endif
@@ -438,7 +438,7 @@ static void _draw_los(screen_cell_t *cell,
if (set<tileidx_t>* icons = map_find(tile_env.icons, gc))
cell->tile.icons = *icons;...
[truncated message content] |
|
From: <gi...@cr...> - 2026-04-08 10:30:15
|
via bae5047b404d84a68c4d49c5568a6bac4f6035c2 (commit)
from dabc3d4ed190e721677da448488cbdc95f6c213b (commit)
-----------------------------------------------------------------------
commit bae5047b404d84a68c4d49c5568a6bac4f6035c2
Author: CrawlOdds <cra...@gm...>
Date: Sun Mar 29 09:55:57 2026 +0100
Fix message for escaping the constriction of invisible monsters (Back-form)
Although it's obviously Erica.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/player.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index b837b012f1..e21276eee3 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -8360,7 +8360,7 @@ bool player::attempt_escape()
= constricted_type == CONSTRICT_ROOTS ? "the roots'"
: constricted_type == CONSTRICT_BVC ? "the zombie hands'"
: constricted_type == CONSTRICT_ENTANGLE ? "the vines'"
- : themonst->name(DESC_ITS, true);
+ : you.can_see(*themonst) ? themonst->name(DESC_ITS, true) : "something's";
if (x_chance_in_y(_constriction_escape_chance(escape_attempts), 100))
{
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-08 09:25:14
|
via dabc3d4ed190e721677da448488cbdc95f6c213b (commit)
from 030a0ecb6a5a1333a59931a1048235c31b7d83dd (commit)
-----------------------------------------------------------------------
commit dabc3d4ed190e721677da448488cbdc95f6c213b
Author: Isaac Clancy <ik...@ya...>
Date: Wed Apr 8 21:07:52 2026 +1200
Give a better shoutitis message when damaged by contamination (kuniqsX)
It would give a message such as "You ribbit at INVALID YOU_FAULTLESS!",
instead give a message such as "You ribbit for attention!" similar to
what you would get from poison damage.
Fixes #5171
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/ouch.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index 0c4839669f..93153ba7fa 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -1095,7 +1095,7 @@ static void _maybe_scream(mid_t source)
if (x_chance_in_y(you.get_mutation_level(MUT_SCREAM), 20))
{
- yell(actor_by_mid(source));
+ yell(actor_by_mid(source, true));
you.shouted_pos = you.pos();
}
}
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-08 08:25:23
|
via 030a0ecb6a5a1333a59931a1048235c31b7d83dd (commit)
from 7ca9a3eb5b1cfee2472c08c0cff66d01c322016b (commit)
-----------------------------------------------------------------------
commit 030a0ecb6a5a1333a59931a1048235c31b7d83dd
Author: Isaac Clancy <ik...@ya...>
Date: Wed Apr 8 17:04:26 2026 +1200
Fix a crash when returning to a level with vengeance targets (kegye)
If you left a level with vengeance targets and then gained enough piety
to end vengeance and then returned to the level it was possible for
vengeance target monsters to die before the daction to clean up old
vengeance targets was run which resulting in a crash. This could happen
in at least the following two situations. First, if the vengeance
targets were Mara clones they would die from timing out when you entered
the level which happened before running dactions. Second, if the
vengeance targets were Pikel's lemures and you had killed Pikel off the
level while still under vengeance. This would cause the daction to kill
off Pikel's lemures to run before the daction to clean up vengeance
targets as dactions run in the order that they are added to the daction
queue.
To fix this, don't count a monster as a vengeance target unless its
vengeance target enchantment was added by the current vengeance (we
store which number vengeance the enchantment was added by in its degree
field already).
Fixes #5187
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/attitude-change.cc | 8 ++++----
crawl-ref/source/dactions.cc | 2 +-
crawl-ref/source/god-companions.cc | 33 +++++++++++++++++----------------
crawl-ref/source/mon-abil.cc | 5 ++++-
crawl-ref/source/mon-clone.cc | 2 +-
crawl-ref/source/mon-death.cc | 16 ++++++++++------
crawl-ref/source/mon-ench.cc | 15 +++++++++++++++
crawl-ref/source/monster.h | 2 ++
crawl-ref/source/tag-version.h | 1 +
crawl-ref/source/tags.cc | 9 +++++++++
10 files changed, 64 insertions(+), 29 deletions(-)
diff --git a/crawl-ref/source/attitude-change.cc b/crawl-ref/source/attitude-change.cc
index b5f4605c5f..f83c71cd55 100644
--- a/crawl-ref/source/attitude-change.cc
+++ b/crawl-ref/source/attitude-change.cc
@@ -89,7 +89,7 @@ void beogh_follower_convert(monster* mons, bool orc_hit)
|| mons->has_ench(ENCH_FIRE_CHAMPION)
|| mons->flags & MF_APOSTLE_BAND
// If marked for vengeance, only deathbed conversion.
- || (mons->has_ench(ENCH_VENGEANCE_TARGET) && !deathbed))
+ || (mons->is_vengeance_target() && !deathbed))
{
return;
}
@@ -105,8 +105,8 @@ void beogh_follower_convert(monster* mons, bool orc_hit)
conv_t ctype = conv_t::sight;
if (deathbed)
{
- ctype = mons->has_ench(ENCH_VENGEANCE_TARGET) ? conv_t::vengeance
- : conv_t::deathbed;
+ ctype = mons->is_vengeance_target() ? conv_t::vengeance
+ : conv_t::deathbed;
}
beogh_convert_orc(mons, ctype);
@@ -215,7 +215,7 @@ void beogh_convert_orc(monster* orc, conv_t conv)
}
// Count as having gotten vengeance.
- if (orc->has_ench(ENCH_VENGEANCE_TARGET))
+ if (orc->is_vengeance_target())
{
orc->del_ench(ENCH_VENGEANCE_TARGET);
beogh_progress_vengeance();
diff --git a/crawl-ref/source/dactions.cc b/crawl-ref/source/dactions.cc
index d4edb7bcf2..3eec0ed317 100644
--- a/crawl-ref/source/dactions.cc
+++ b/crawl-ref/source/dactions.cc
@@ -136,7 +136,7 @@ bool mons_matches_daction(const monster* mon, daction_type act)
case DACT_BEOGH_VENGEANCE_CLEANUP:
return mon->has_ench(ENCH_VENGEANCE_TARGET)
&& mon->get_ench(ENCH_VENGEANCE_TARGET).degree
- <= you.props[BEOGH_VENGEANCE_NUM_KEY].get_int();
+ != you.props[BEOGH_VENGEANCE_NUM_KEY].get_int();
case DACT_BANE_MORTALITY_CLEANUP:
return mon->was_created_by(MON_SUMM_MORTALITY);
diff --git a/crawl-ref/source/god-companions.cc b/crawl-ref/source/god-companions.cc
index 245e4bbcb6..ce3f3cd196 100644
--- a/crawl-ref/source/god-companions.cc
+++ b/crawl-ref/source/god-companions.cc
@@ -610,7 +610,7 @@ void win_apostle_challenge(monster& apostle)
apostle.del_ench(ENCH_TOUCH_OF_BEOGH);
// Count as having gotten vengeance, even though the target isn't 'dead'
- if (apostle.has_ench(ENCH_VENGEANCE_TARGET))
+ if (apostle.is_vengeance_target())
{
apostle.del_ench(ENCH_VENGEANCE_TARGET);
beogh_progress_vengeance();
@@ -906,10 +906,6 @@ bool apostle_has_unique_name(const monster& apostle)
void beogh_swear_vengeance(const monster& apostle)
{
- bool already_avenging = you.duration[DUR_BEOGH_SEEKING_VENGEANCE];
- if (!already_avenging)
- you.props[BEOGH_VENGEANCE_NUM_KEY].get_int() += 1;
-
bool new_targets = false;
// To keep track of which monsters correspond to which period of avenging
@@ -924,9 +920,10 @@ void beogh_swear_vengeance(const monster& apostle)
// prevents marking frenzied apostles
&& mon->attitude != ATT_FRIENDLY
&& !mon->is_summoned() && !mon->is_peripheral()
- && !mon->has_ench(ENCH_VENGEANCE_TARGET))
+ && !mon->is_vengeance_target())
{
you.duration[DUR_BEOGH_SEEKING_VENGEANCE] += 1;
+ mon->del_ench(ENCH_VENGEANCE_TARGET);
mon->add_ench(mon_enchant(ENCH_VENGEANCE_TARGET, &you, INFINITE_DURATION, vengeance_num));
mon->patrol_point = apostle.pos();
new_targets = true;
@@ -947,7 +944,7 @@ void beogh_swear_vengeance(const monster& apostle)
// If an apostle dies with no visible enemy to mark, and you are not already
// avenging a different dead, give the bonus progress immediately (otherwise
// the player may never receive it)
- if (new_targets || already_avenging)
+ if (you.duration[DUR_BEOGH_SEEKING_VENGEANCE])
a.vengeance_bonus = cost * 2 / 3;
else
you.props[BEOGH_RES_PIETY_GAINED_KEY].get_int() += (cost * 2 / 3);
@@ -965,6 +962,16 @@ void beogh_follower_banished(monster& apostle)
remove_companion(&apostle);
}
+static void _beogh_end_vengeance()
+{
+ you.duration[DUR_BEOGH_SEEKING_VENGEANCE] = 0;
+ // Mark any current vengeance targets as invalid
+ you.props[BEOGH_VENGEANCE_NUM_KEY].get_int() += 1;
+ // Make sure any monsters that were seeking vengeance have their
+ // patrol_point reset
+ add_daction(DACT_BEOGH_VENGEANCE_CLEANUP);
+}
+
void beogh_progress_vengeance()
{
ASSERT(you.duration[DUR_BEOGH_SEEKING_VENGEANCE]);
@@ -978,9 +985,7 @@ void beogh_progress_vengeance()
// splitting (and probably some other methods of cloning) can result in
// more monsters being marked in total than were marked originally,
// and subsequently killing one of them will assert.
- for (monster_iterator mi; mi; ++mi)
- mi->del_ench(ENCH_VENGEANCE_TARGET);
- add_daction(DACT_BEOGH_VENGEANCE_CLEANUP);
+ _beogh_end_vengeance();
// Calculate total vengeance bonus and apply it
int bonus = 0;
@@ -1087,12 +1092,8 @@ void beogh_resurrect_followers(bool end_ostracism_only)
you.props.erase(BEOGH_RES_PIETY_NEEDED_KEY);
// End vengeance statuses (in case we revived companions without finishing them)
- you.duration[DUR_BEOGH_SEEKING_VENGEANCE] = 0;
- add_daction(DACT_BEOGH_VENGEANCE_CLEANUP);
-
- // Increment how many times vengeance has been declared (so that the daction
- // will only clean up past marks and not future ones)
- you.props[BEOGH_VENGEANCE_NUM_KEY].get_int() += 1;
+ if (you.duration[DUR_BEOGH_SEEKING_VENGEANCE])
+ _beogh_end_vengeance();
}
bool tile_has_valid_bfb_corpse(const coord_def pos)
diff --git a/crawl-ref/source/mon-abil.cc b/crawl-ref/source/mon-abil.cc
index 731f323628..110d373869 100644
--- a/crawl-ref/source/mon-abil.cc
+++ b/crawl-ref/source/mon-abil.cc
@@ -165,8 +165,11 @@ static void _share_ench_durations(monster* initial_slime, monster* split_off)
// The newly split slime will also be vengeance marked, so we need
// to increment the total number of monsters the player has to kill
- if (entry.second.ench == ENCH_VENGEANCE_TARGET)
+ if (entry.second.ench == ENCH_VENGEANCE_TARGET
+ && split_off->is_vengeance_target())
+ {
you.duration[DUR_BEOGH_SEEKING_VENGEANCE] += 1;
+ }
}
}
}
diff --git a/crawl-ref/source/mon-clone.cc b/crawl-ref/source/mon-clone.cc
index ee21c6317e..e82ec028a5 100644
--- a/crawl-ref/source/mon-clone.cc
+++ b/crawl-ref/source/mon-clone.cc
@@ -358,7 +358,7 @@ monster* clone_mons(const monster* orig, bool quiet, bool* obvious,
if (mons->has_ench(ENCH_TOUCH_OF_BEOGH))
mons->del_ench(ENCH_TOUCH_OF_BEOGH);
- if (mons->has_ench(ENCH_VENGEANCE_TARGET))
+ if (mons->is_vengeance_target())
you.duration[DUR_BEOGH_SEEKING_VENGEANCE] += 1;
// Duplicate objects, or unequip them if they can't be duplicated.
diff --git a/crawl-ref/source/mon-death.cc b/crawl-ref/source/mon-death.cc
index 34eb0ed95e..bac3773060 100644
--- a/crawl-ref/source/mon-death.cc
+++ b/crawl-ref/source/mon-death.cc
@@ -858,7 +858,7 @@ static bool _beogh_forcibly_convert_orc(monster &mons, killer_type killer)
const bool follower = MON_KILL(killer);
conv_t ctype = follower ? conv_t::deathbed_follower
: conv_t::deathbed;
- if (mons.has_ench(ENCH_VENGEANCE_TARGET))
+ if (mons.is_vengeance_target())
{
ctype = follower ? conv_t::vengeance_follower
: conv_t::vengeance;
@@ -968,10 +968,11 @@ static bool _blorkula_bat_split(monster& blorkula, killer_type ktype)
shuffle_array(bat_colours);
#endif
+ bool is_vengeance_target = blorkula.is_vengeance_target();
mon_enchant vengeance_target = blorkula.get_ench(ENCH_VENGEANCE_TARGET);
+ if (is_vengeance_target)
+ blorkula.del_ench(ENCH_VENGEANCE_TARGET, true, false);
follower saved_blork = follower(blorkula);
- if (vengeance_target.ench != ENCH_NONE)
- saved_blork.mons.del_ench(ENCH_VENGEANCE_TARGET, true, false);
bool placed_bat = false;
for (int i = 0; i < num_bats; ++i)
{
@@ -990,7 +991,7 @@ static bool _blorkula_bat_split(monster& blorkula, killer_type ktype)
mons_add_blame(bat, "manifested out of " + blorkula.name(DESC_A, true));
bat->flags |= (MF_NO_REWARD | MF_WAS_IN_VIEW);
placed_bat = true;
- if (vengeance_target.ench != ENCH_NONE)
+ if (is_vengeance_target)
{
bat->add_ench(vengeance_target);
you.duration[DUR_BEOGH_SEEKING_VENGEANCE] += 1;
@@ -1020,7 +1021,7 @@ static monster* _retrieve_saved_blorkula(monster& bat)
{
follower saved_blork;
saved_blork.read_from_prop(bat.props[SAVED_BLORKULA_KEY].get_vector());
- const bool is_vengeance_target = bat.has_ench(ENCH_VENGEANCE_TARGET);
+ const bool is_vengeance_target = bat.is_vengeance_target();
if (is_vengeance_target)
{
saved_blork.mons.add_ench(bat.get_ench(ENCH_VENGEANCE_TARGET));
@@ -3538,8 +3539,11 @@ item_def* monster_die(monster& mons, killer_type killer,
return corpse;
}
- if (mons.has_ench(ENCH_VENGEANCE_TARGET))
+ if (mons.is_vengeance_target())
+ {
+ mons.del_ench(ENCH_VENGEANCE_TARGET);
beogh_progress_vengeance();
+ }
// If there are other duel targets alive (due to a slime splitting), don't
// count this as winning the duel.
diff --git a/crawl-ref/source/mon-ench.cc b/crawl-ref/source/mon-ench.cc
index ebfb585b32..e5e7b4c870 100644
--- a/crawl-ref/source/mon-ench.cc
+++ b/crawl-ref/source/mon-ench.cc
@@ -24,6 +24,7 @@
#include "fight.h"
#include "hints.h"
#include "god-abil.h"
+#include "god-companions.h"
#include "item-status-flag-type.h"
#include "items.h"
#include "libutil.h"
@@ -1975,6 +1976,20 @@ void monster::apply_enchantments()
apply_enchantment(enchantments.find(static_cast<enchant_type>(i))->second);
}
+bool monster::is_vengeance_target() const
+{
+ if (!has_ench(ENCH_VENGEANCE_TARGET))
+ return false;
+ // When entering a level, old vengeance will be removed from monsters by a
+ // daction. However, it is possible for a monster to die before that runs
+ // (e.g. from an earlier daction to clean up Pikel minions) and killing a
+ // monster that is a vengeance target while not under penance results in a
+ // crash, so don't count a monster as a vengeance target if it was set by
+ // an old vengeance.
+ return get_ench(ENCH_VENGEANCE_TARGET).degree
+ == you.props[BEOGH_VENGEANCE_NUM_KEY].get_int();
+}
+
// Used to adjust time durations in calc_duration() for monster speed.
static inline int _mod_speed(int val, int speed)
{
diff --git a/crawl-ref/source/monster.h b/crawl-ref/source/monster.h
index d0d5aa3544..8c0837d722 100644
--- a/crawl-ref/source/monster.h
+++ b/crawl-ref/source/monster.h
@@ -581,6 +581,8 @@ public:
monster* get_band_leader() const;
void set_band_leader(const monster& leader);
+ bool is_vengeance_target() const;
+
private:
int hit_dice;
diff --git a/crawl-ref/source/tag-version.h b/crawl-ref/source/tag-version.h
index f99c5fa42c..d4f5bec9a1 100644
--- a/crawl-ref/source/tag-version.h
+++ b/crawl-ref/source/tag-version.h
@@ -349,6 +349,7 @@ enum tag_minor_version
TAG_MINOR_TERRAIN_CHANGE_MID, // Marshall terrain change origin mids as int instead of shorts
TAG_MINOR_REFACTOR_MALIGN_MARKER, // Refactor handling of map_malign_gateway_marker
TAG_MINOR_REMOVE_MORTAR_MARKERS, // Remove map_hellfire_mortar_lava_marker and refactor again
+ TAG_MINOR_FIX_VENGEANCE_CLEANUP, // Fix a crash when changing levels due to old vengeance targets
#endif
NUM_TAG_MINORS,
TAG_MINOR_VERSION = NUM_TAG_MINORS - 1
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 527cae588c..8797fa2afa 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -4802,6 +4802,15 @@ static void _tag_read_you(reader &th)
you.attribute[ATTR_CHANNEL_DURATION] = 0;
}
}
+
+ // We didn't always used to increase the vengeance number when ending a
+ // vengeance, but monster::is_vengeance_target requires it to be higher
+ // than it was during the last vengeance if we are no longer in vengeance
+ if (th.getMinorVersion() < TAG_MINOR_FIX_VENGEANCE_CLEANUP
+ && !you.duration[DUR_BEOGH_SEEKING_VENGEANCE])
+ {
+ you.props[BEOGH_VENGEANCE_NUM_KEY].get_int() += 1;
+ }
#endif
}
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-07 12:10:11
|
via 7ca9a3eb5b1cfee2472c08c0cff66d01c322016b (commit)
from 8c878a6c5fb5b17d626cf4fc0cdd650b96de90ec (commit)
-----------------------------------------------------------------------
commit 7ca9a3eb5b1cfee2472c08c0cff66d01c322016b
Author: CrawlOdds <cra...@gm...>
Date: Tue Apr 7 13:08:13 2026 +0100
Fix a spurious "rune reappears" message (#5179)
When the abyss map recentred itself around the player, we were detecting
this as the rune moving, and messaging the player even though nothing
had actually changed.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/abyss.cc | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc
index 1338f9ec3a..5126ad7f5f 100644
--- a/crawl-ref/source/abyss.cc
+++ b/crawl-ref/source/abyss.cc
@@ -277,7 +277,7 @@ void clear_abyssal_rune_knowledge()
cur_loc = coord_def(-1,-1);
}
-static void _update_abyssal_map_knowledge()
+static void _update_abyssal_map_knowledge(coord_def map_shift = coord_def(0, 0))
{
// reset any waypoints set while in the abyss so far.
// XX currently maprot doesn't clear waypoints, but they then don't show in
@@ -298,8 +298,16 @@ static void _update_abyssal_map_knowledge()
you.props[ABYSSAL_RUNE_LOC_KEY].get_coord() = coord_def(-1,-1);
coord_def &cur_loc = you.props[ABYSSAL_RUNE_LOC_KEY].get_coord();
const bool existed = in_bounds(cur_loc);
- if (existed && _sync_rune_knowledge(cur_loc))
- return; // still exists in the same place, no need to do anything more
+ if (existed)
+ {
+ // Adjust the rune location by the shift we've applied to the map, if any.
+ cur_loc += map_shift;
+ // If the rune has gone out of bounds, forget it.
+ if (!in_bounds(cur_loc))
+ cur_loc = coord_def(-1,-1);
+ else if (_sync_rune_knowledge(cur_loc))
+ return; // still exists in the same place, no need to do anything more
+ }
// now we need to check if a new or moved rune appeared
@@ -1440,7 +1448,7 @@ static int _abyss_place_vaults(const map_bitmask &abyss_genlevel_mask, bool plac
return vaults_placed;
}
-static void _generate_area(const map_bitmask &abyss_genlevel_mask)
+static void _generate_area(const map_bitmask &abyss_genlevel_mask, coord_def map_shift = coord_def(0, 0))
{
// Any rune on the floor prevents the abyssal rune from being generated.
const bool placed_abyssal_rune = find_floor_item(OBJ_RUNES);
@@ -1460,7 +1468,7 @@ static void _generate_area(const map_bitmask &abyss_genlevel_mask)
_ensure_player_habitable(true);
- _update_abyssal_map_knowledge();
+ _update_abyssal_map_knowledge(map_shift);
// Abyss has a constant density.
env.density = 0;
@@ -1502,14 +1510,17 @@ static void abyss_area_shift()
// A teleport may move you back to the center, resulting in a (0,0)
// shift. The code can't handle those. We still to forget the map,
// spawn new monsters or allow return from transit, though.
- if (you.pos() != ABYSS_CENTRE)
+ coord_def old_centre = you.pos();
+ if (old_centre != ABYSS_CENTRE)
{
// Use a map mask to track the areas that the shift destroys and
// that must be regenerated by _generate_area.
map_bitmask abyss_genlevel_mask;
_abyss_shift_level_contents_around_player(
ABYSS_AREA_SHIFT_RADIUS, ABYSS_CENTRE, abyss_genlevel_mask);
- _generate_area(abyss_genlevel_mask);
+ // Specify the map shift so we can tell if the rune moved.
+ coord_def delta = you.pos() - old_centre;
+ _generate_area(abyss_genlevel_mask, delta);
}
forget_map(true);
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-06 22:25:15
|
via 8c878a6c5fb5b17d626cf4fc0cdd650b96de90ec (commit)
from f9e06672e492112214d3eb06629e27c47ed457ff (commit)
-----------------------------------------------------------------------
commit 8c878a6c5fb5b17d626cf4fc0cdd650b96de90ec
Author: CrawlOdds <cra...@gm...>
Date: Mon Apr 6 23:22:59 2026 +0100
Warn for riding crocodiles into traps (#4924)
The crocodiles were sometimes *too* surprising.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/spl-summoning.cc | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/crawl-ref/source/spl-summoning.cc b/crawl-ref/source/spl-summoning.cc
index 065e417d6a..b781188321 100644
--- a/crawl-ref/source/spl-summoning.cc
+++ b/crawl-ref/source/spl-summoning.cc
@@ -3919,6 +3919,29 @@ bool surprising_crocodile_can_drag(const actor& agent, const coord_def& target,
spret cast_surprising_crocodile(actor& agent, const coord_def& targ, int pow, bool fail)
{
+ const coord_def start_pos = agent.pos();
+ const coord_def drag_shift = -(targ - agent.pos()).sgn();
+
+ // Check for traps where the player expects to move.
+ if (agent.is_player())
+ {
+ coord_def one_square_move = agent.pos() + drag_shift;
+ const string verb = "ride";
+ if (surprising_crocodile_can_drag(agent, targ, false))
+ {
+ // The player will end up in one_square_move + drag_shift, and the
+ // crocodile in one_square_move. Check the crocodile position only
+ // for traps, which it will trigger.
+ if (!check_moveto_trap(one_square_move, verb)
+ || !check_moveto(one_square_move + drag_shift, verb))
+ {
+ return spret::abort;
+ }
+ }
+ else if (!check_moveto(one_square_move, verb))
+ return spret::abort;
+ }
+
fail_check();
// The targeter will prevent casting this at times where the player *knows*
@@ -3936,8 +3959,6 @@ spret cast_surprising_crocodile(actor& agent, const coord_def& targ, int pow, bo
// move one tile back or two.
bool can_drag = surprising_crocodile_can_drag(agent, targ, true);
- const coord_def start_pos = agent.pos();
- const coord_def drag_shift = -(targ - agent.pos()).sgn();
coord_def agent_pos = agent.pos() + drag_shift;
if (can_drag)
agent_pos += drag_shift;
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-04 21:45:15
|
via f9e06672e492112214d3eb06629e27c47ed457ff (commit)
from 859e8e3ba0ee06dbb1f0c94883075464fe6de16b (commit)
-----------------------------------------------------------------------
commit f9e06672e492112214d3eb06629e27c47ed457ff
Author: CrawlOdds <cra...@gm...>
Date: Fri Apr 3 20:33:33 2026 +0100
Fix a zero division error in describing monster hits
When our EV was between 0 and 1, we were dividing by 0.
This displayed hit chances like 0% and -MAX_INT%.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/fight.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 77e49703d2..1230a4977a 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -266,7 +266,7 @@ int mon_to_hit_pct(int to_land, int scaled_ev)
for (int ev1 = 0; ev1 < ev; ev1++)
for (int ev2 = 0; ev2 < ev; ev2++)
hits_lower += max(0, to_land - (ev1 + ev2));
- double hit_chance_lower = ((double)hits_lower) / (to_land * ev * ev);
+ double hit_chance_lower = ev ? ((double)hits_lower) / (to_land * ev * ev) : 1.0;
int hits_upper = 0;
for (int ev1 = 0; ev1 < ev+1; ev1++)
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-03 22:15:10
|
via 859e8e3ba0ee06dbb1f0c94883075464fe6de16b (commit)
from 7484870de73651b616880799dd1878bc82ba279b (commit)
-----------------------------------------------------------------------
commit 859e8e3ba0ee06dbb1f0c94883075464fe6de16b
Author: DracoOmega <dra...@gm...>
Date: Fri Apr 3 19:41:57 2026 -0230
Fix Marionette being unusuable on solo enemies (autumn)
Accidentally broken by 049f810. The fact that enemies could target
themselves here was needed to allow casting buffs/summons when solo.
But in an attempt to prevent just smiting themselves to death, try to
prevent casting attack spells on oneself. (This isn't 100% correct, but
hopefully adequate enough.)
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/god-abil.cc | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/crawl-ref/source/god-abil.cc b/crawl-ref/source/god-abil.cc
index 96e1a5dcc4..67135cae5b 100644
--- a/crawl-ref/source/god-abil.cc
+++ b/crawl-ref/source/god-abil.cc
@@ -2992,13 +2992,22 @@ static bool _marionette_spell_attempt(monster& caster, spell_type spell,
vector<monster*>& targs,
bool check_only = false)
{
- shuffle_array(targs);
+ const spell_flags flags = get_spell_flags(spell);
+ const bool aggressive = (flags & (spflag::targeting_mask))
+ && !(flags & ((spflag::helpful | spflag::escape)));
+ shuffle_array(targs);
for (monster* targ : targs)
{
+ // Don't cast attack spells directly on ourselves.
+ // (This is a very crude approximation, but in general we assume
+ // untargeted AoE already won't hurt its own caster.)
+ if (targ == &caster && aggressive)
+ continue;
+
// We verify alignment again at this point, just in case it's changed
// in the middle of Marionette (eg: by the monster charming something).
- if (!targ->alive() || targ->wont_attack())
+ if (!targ->alive() || (targ->wont_attack() && targ != &caster))
continue;
caster.foe = targ->mindex();
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-03 02:45:09
|
via 7484870de73651b616880799dd1878bc82ba279b (commit)
from bd006bb7f276f7f1b664c20f746f06cb3c7710cf (commit)
-----------------------------------------------------------------------
commit 7484870de73651b616880799dd1878bc82ba279b
Author: regret-index <clo...@ho...>
Date: Fri Apr 3 00:13:19 2026 -0230
Fix Storm Queen's Trove lua errors
96bc2dc accidentally introduced incorrect bracing into the trove's
unrand chance function, which should be fixed here.
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/dat/des/portals/trove.des | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/crawl-ref/source/dat/des/portals/trove.des b/crawl-ref/source/dat/des/portals/trove.des
index 0d3da31781..ed8c206a9a 100644
--- a/crawl-ref/source/dat/des/portals/trove.des
+++ b/crawl-ref/source/dat/des/portals/trove.des
@@ -950,8 +950,8 @@ trove_defense(_G, arm, "pair of gloves randart artprops:rElec w:2",
local sh = you.race() == "Spriggan" or you.race() == "Kobold" or
you.race() == "Felid" or you.mutation("missing a hand") == 1
trove_unrand_chances(_G, "dgh", {"storm_queen's_shield", "storm_bow",
- "lightning scales"}, {sh, sh and you.race("Formicid") == false},
- wants_barding(e), {"?", "!", "Z"})
+ "lightning scales"}, {sh, sh and you.race("Formicid") == false,
+ wants_barding(e)}, {"?", "!", "Z"})
}}
MARKER: V = lua:fog_machine { cloud_type = "thunder", walk_dist=2, \
pow_min=18, pow_max=26, delay=180, size=4, spread_rate=1 }
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-02 21:00:10
|
via bd006bb7f276f7f1b664c20f746f06cb3c7710cf (commit)
from 8808f4c9864abbfea70ce5d2737ee6f8e5e65f20 (commit)
-----------------------------------------------------------------------
commit bd006bb7f276f7f1b664c20f746f06cb3c7710cf
Author: DracoOmega <dra...@gm...>
Date: Thu Apr 2 18:25:25 2026 -0230
Remove some dead code (Odds)
Unused since 453fa3c
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/beam.cc | 19 ++-----------------
crawl-ref/source/beam.h | 10 +---------
crawl-ref/source/spl-damage.cc | 2 +-
crawl-ref/source/throw.cc | 2 +-
4 files changed, 5 insertions(+), 28 deletions(-)
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index a6d8eac788..558eaf6139 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -7766,18 +7766,11 @@ void player_beam_tracer::monster_hit(const bolt& beam, const monster& mon)
}
}
-void player_beam_tracer::blocked(string message) noexcept
-{
- blocked_message = std::move(message);
- blocked_count++;
-}
-
// Returns true if there is anything this tracer might possibly want to prompt
// the player about.
bool player_beam_tracer::has_any_warnings() noexcept
{
- return blocked_count > 0
- || god_hated_target
+ return god_hated_target
|| bad_charm_target
|| hit_self_count > 0
|| !bad_attack_targets.empty();
@@ -7816,16 +7809,8 @@ int targeting_tracer::player_hit_count() noexcept
}
// returns true if the player wishes to cancel firing the bolt, false otherwise
-bool cancel_beam_prompt(const bolt& beam, const player_beam_tracer& tracer,
- int beams_fired)
+bool cancel_beam_prompt(const bolt& beam, const player_beam_tracer& tracer)
{
- ASSERT(beams_fired >= tracer.blocked_count);
- if (tracer.blocked_count >= beams_fired)
- {
- mpr(tracer.blocked_message);
- return true;
- }
-
const spell_type spell = beam.origin_spell;
if (tracer.god_hated_target
diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h
index ec94f247b5..659a759741 100644
--- a/crawl-ref/source/beam.h
+++ b/crawl-ref/source/beam.h
@@ -83,10 +83,6 @@ struct beam_tracer
{
UNUSED(bolt, mon);
}
- virtual void blocked(string message)
- {
- UNUSED(message);
- }
};
// Used when casting a spell to check if the spell should be aborted
@@ -104,8 +100,6 @@ struct player_beam_tracer : beam_tracer
const monster* god_hated_target = nullptr;
int hit_self_count = 0;
int foe_count = 0;
- string blocked_message;
- int blocked_count = 0;
player_beam_tracer() {}
@@ -119,7 +113,6 @@ struct player_beam_tracer : beam_tracer
void actor_affected(bool friendly_fire, int power) noexcept override;
void player_hit(bool was_friendly) noexcept override;
void monster_hit(const bolt& bolt, const monster& mon) override;
- void blocked(string message) noexcept override;
bool has_any_warnings() noexcept;
};
@@ -494,8 +487,7 @@ void fill_chain_targets(const bolt& beam, coord_def centre,
bolt setup_targeting_beam(const monster &mons);
-bool cancel_beam_prompt(const bolt& beam, const player_beam_tracer& tracer,
- int beams_fired = 1);
+bool cancel_beam_prompt(const bolt& beam, const player_beam_tracer& tracer);
int apply_willpower_bypass(const actor& source, int willpower);
int apply_willpower_bypass(const monster_info& source, int willpower);
diff --git a/crawl-ref/source/spl-damage.cc b/crawl-ref/source/spl-damage.cc
index 50a32616a4..6754e55b9c 100644
--- a/crawl-ref/source/spl-damage.cc
+++ b/crawl-ref/source/spl-damage.cc
@@ -4100,7 +4100,7 @@ spret cast_starburst(int pow, bool fail, bool is_tracer)
fire_partial_player_tracer(ZAP_BOLT_OF_FIRE, pow, tracer, beam);
}
- if (cancel_beam_prompt(beam, tracer, 8))
+ if (cancel_beam_prompt(beam, tracer))
return spret::abort;
fail_check();
diff --git a/crawl-ref/source/throw.cc b/crawl-ref/source/throw.cc
index d9cc729f5f..7da6786ddb 100644
--- a/crawl-ref/source/throw.cc
+++ b/crawl-ref/source/throw.cc
@@ -604,7 +604,7 @@ static bool _trace_player_ranged_attacks(vector<ranged_attack_beam>& atks, bool
if (no_harm_allies && tracer.has_any_warnings())
return true;
- if (cancel_beam_prompt(atks[0].beam, tracer, atks.size()))
+ if (cancel_beam_prompt(atks[0].beam, tracer))
return true;
// Warn about Mule potentially knocking the player back into a trap.
--
Dungeon Crawl Stone Soup
|
|
From: <gi...@cr...> - 2026-04-02 20:15:10
|
via 8808f4c9864abbfea70ce5d2737ee6f8e5e65f20 (commit)
from 8b5e8d6024a2b9c91cf48ac5147c5250937b171f (commit)
-----------------------------------------------------------------------
commit 8808f4c9864abbfea70ce5d2737ee6f8e5e65f20
Author: DracoOmega <dra...@gm...>
Date: Thu Apr 2 17:43:53 2026 -0230
Fix monsters sometimes hitting their own sleeping allies
An oversight in a4800fc (as part of a change to allow thorn hunters to
walk onto their briars instead of attack them) meant that if
_monster_swaps_places() returned false, the movement delta wasn't being
reset and _do_move_monster would later be called to try and move into that
same space - this time without the swap check, resulting in attacking them.
While monsters generally won't call _monster_swap_places if the swap should
*never* be possible, there are some situations where it is *randomly*
possible. The most obvious of these are sleeping monsters, where the swap
attempt succeeds in waking them only 50% of the time. This meant that if a
monster tried to swap into a sleeping ally, 50% of the time they would just
attack them instead. Whoops!
This fixes #5172
-----------------------------------------------------------------------
Summary of changes:
crawl-ref/source/mon-act.cc | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/crawl-ref/source/mon-act.cc b/crawl-ref/source/mon-act.cc
index 4debab2956..24dd1ac08e 100644
--- a/crawl-ref/source/mon-act.cc
+++ b/crawl-ref/source/mon-act.cc
@@ -4081,16 +4081,17 @@ static bool _monster_move(monster* mons, coord_def& delta)
|| mons->confused()))
{
ret = _monster_swaps_places(mons, delta);
+ delta.reset(); // Swapping can fail, but even if it does, we
+ // shouldn't try hitting our ally later on.
}
else if (!delta.origin()) // confused self-hit handled below
{
if (mons_fight(mons, targ))
+ {
ret = true;
+ delta.reset();
+ }
}
-
- // If the monster swapped places, the work's already done.
- if (ret)
- delta.reset();
}
// The monster could die after a melee attack due to a mummy
--
Dungeon Crawl Stone Soup
|