Move mangroves back to their own feature type
authorgammafunk <gammafunk@gmail.com>
Thu, 22 Apr 2021 19:24:15 +0000 (14:24 -0500)
committergammafunk <gammafunk@gmail.com>
Sat, 24 Apr 2021 08:38:09 +0000 (03:38 -0500)
Mangroves were made normal trees in 7a9dbbb8 when trees were made fully
opaque, instead of requiring two to break LOS. However multiple gameplay
differences remain between trees and mangroves, namely they don't spread
forest fires and they leave shallow water after destruction. Having them
be normal tree features but with the behaviour conditioned on location
complicates documenting these differences for the player. It also
complicates their usage in other areas, since they'll be mangroves in
appearance only, and will not do any of the usual mangrove things.

It's far more straightforward to have features with gameplay differences
be properly distinct feature types, hence this commit restores mangroves
to their own type. The handling for flame clouds and leaving water is
conditioned on the original feature being a mangrove, not its being a
tree in Swamp. I've also added a mangrove feature description that
mentions mangrove differences.

This change does bring some complications. For vaults, we condition the
default meaning of the 't' glyph by branch, so that mangroves are the
default definition for any vault placing in Swamp. Vault authors can
still use a KFEAT to get whichever type of tree they need. For save
compat, we add a minor version that converts all normal trees to
mangroves in Swamp. For vaults, I've gone through and modified the few
vaults using mangrove tree tiles outside of Swamps to use proper
mangrove trees.

17 files changed:
crawl-ref/source/beam.cc
crawl-ref/source/colour.cc
crawl-ref/source/colour.h
crawl-ref/source/dat/des/branches/swamp.des
crawl-ref/source/dat/des/variable/float.des
crawl-ref/source/dat/descript/features.txt
crawl-ref/source/dgn-swamp.cc
crawl-ref/source/dungeon-feature-type.h
crawl-ref/source/dungeon.cc
crawl-ref/source/feature-data.h
crawl-ref/source/spl-damage.cc
crawl-ref/source/tag-version.h
crawl-ref/source/tags.cc
crawl-ref/source/terrain.cc
crawl-ref/source/tilecell.cc
crawl-ref/source/tilepick.cc
crawl-ref/source/tileview.cc

index a7cc7e1..0fc88fd 100644 (file)
@@ -931,8 +931,8 @@ void bolt::burn_wall_effect()
     destroy_wall(pos());
     if (you.see_cell(pos()))
     {
-        if (player_in_branch(BRANCH_SWAMP))
-            emit_message("The tree smoulders and burns.");
+        if (feat == DNGN_MANGROVE)
+            emit_message("The mangrove smoulders and burns.");
         else
             emit_message("The tree burns like a torch!");
     }
@@ -943,8 +943,8 @@ void bolt::burn_wall_effect()
     else if (whose_kill() == KC_FRIENDLY && !crawl_state.game_is_arena())
         did_god_conduct(DID_KILL_PLANT, 1, god_cares());
 
-    // Trees do not burn so readily in a wet environment.
-    if (player_in_branch(BRANCH_SWAMP))
+    // Mangroves do not burn so readily.
+    if (feat == DNGN_MANGROVE)
         place_cloud(CLOUD_FIRE, pos(), random2(12)+5, agent());
     else
         place_cloud(CLOUD_FOREST_FIRE, pos(), random2(30)+25, agent());
index 0d9d975..dddbe1a 100644 (file)
@@ -252,8 +252,13 @@ static int _etc_tree(int, const coord_def& loc)
     h += loc.y;
     h+=h<<10; h^=h>>6;
     h+=h<<3; h^=h>>11; h+=h<<15;
-    return (h>>30) ? GREEN :
-        player_in_branch(BRANCH_SWAMP) ? BROWN : LIGHTGREEN; // Swamp trees are mangroves.
+    return (h>>30) ? GREEN : LIGHTGREEN;
+}
+
+static int _etc_mangrove(int, const coord_def& loc)
+{
+    static int col = _etc_tree(0, loc);
+    return col == LIGHTGREEN ? BROWN : col;
 }
 
 bool get_tornado_phase(const coord_def& loc)
@@ -581,6 +586,9 @@ void init_element_colours()
                             ETC_TREE, "tree", _etc_tree
                        ));
     add_element_colour(new element_colour_calc(
+                            ETC_MANGROVE, "mangrove", _etc_mangrove
+                       ));
+    add_element_colour(new element_colour_calc(
                             ETC_TORNADO, "tornado", _etc_tornado
                        ));
     add_element_colour(new element_colour_calc(
index 6dd1afb..06d2369 100644 (file)
@@ -52,9 +52,7 @@ enum element_type
     ETC_RANDOM,         // any colour (except BLACK)
     ETC_TORNADO,        // twisting swirls of grey
     ETC_LIQUEFIED,      // ripples of yellow and brown.
-#if TAG_MAJOR_VERSION == 34
     ETC_MANGROVE,       // colour of trees on water
-#endif
     ETC_ORB_GLOW,       // halo coming from the Orb of Zot
     ETC_DISJUNCTION,    // halo from Disjunction
     ETC_DITHMENOS,      // Dithmenos altar colours
index 0622c6c..00e7b55 100644 (file)
@@ -1814,7 +1814,7 @@ NSUBST: ' = 1:h / 1:g / 2:c / 1:c' / 2:% / 2:%' / 5:p / 4:p' / *:'
 SUBST: ' = ....b
 KPROP: bc = bloody
 SUBST: b = ., . = ..W
-KFEAT: T = tree
+KFEAT: T = t
 KMONS: p = plant
 : kmons( "h = " .. heads .. "-headed hydra patrolling" )
 KITEM: g = any weapon good_item / any armour good_item / any jewellery good_item
@@ -2795,7 +2795,7 @@ SUBST:  ' = ..t__, E = .Wt
 KFEAT:  H = W
 COLOUR: t = lightgrey w:5 / brown
 TILE:   t = dngn_tree_dead
-: set_feature_name("tree", "dead tree")
+: set_feature_name("mangrove", "dead mangrove")
 MARKER: H = lua:fog_machine { cloud_type = "foul pestilence", \
             pow_min = 3, pow_max = 4, delay_min = 35, delay_max = 45, \
             size = 3, walk_dist = 1, excl_rad = 0}
index 518f679..7d54cb6 100644 (file)
@@ -2874,6 +2874,7 @@ KITEM:    * = *
 KITEM:    6| = |
 KFEAT:    h3456DHJK%$*| = W
 KFEAT:    K = w
+KFEAT:    t = mangrove
 KPROP:    ~"DE = no_tele_into
 SHUFFLE:  FH / IJ
 SUBST:    i : ch, j : ch, ~' = hhhhW, -" = W, k = .
index e6f60e0..ec359d3 100644 (file)
@@ -253,6 +253,11 @@ A large tree. While in most places the dim light of the dungeon is not bright
 enough to sustain large plants, there are spots where, with the grace of
 Fedhas, trees as big as those on the surface can grow underground.
 %%%%
+A mangrove
+
+This tree is specially adapted for growing in swampy conditions. Its vines are
+too thick to see through.
+%%%%
 An awoken tree
 
 A large tree that has been enchanted to grant it some limited motility,
@@ -858,6 +863,10 @@ A dead tree
 
 The dry remains of a long-dead tree.
 %%%%
+A dead mangrove
+
+The dry remains of a long-dead mangrove.
+%%%%
 # Dis:7
 An iron statue
 
index 05af8e6..698b92d 100644 (file)
@@ -37,7 +37,7 @@ static dungeon_feature_type _swamp_feature_for_height(int height)
     return height > (8 - you.depth * 2) ? DNGN_SHALLOW_WATER :
         height > -8 ? DNGN_FLOOR :
         height > -10 ? DNGN_SHALLOW_WATER :
-        DNGN_TREE;
+        DNGN_MANGROVE;
 }
 
 static void _swamp_apply_features(int margin)
@@ -50,7 +50,7 @@ static void _swamp_apply_features(int margin)
             if (c.x < margin || c.y < margin || c.x >= GXM - margin
                 || c.y >= GYM - margin)
             {
-                env.grid(c) = DNGN_TREE;
+                env.grid(c) = DNGN_MANGROVE;
             }
             else
                 env.grid(c) = _swamp_feature_for_height(dgn_height_at(c));
index bdc6ab7..47fd5f3 100644 (file)
@@ -28,7 +28,8 @@ enum dungeon_feature_type
 #endif
     DNGN_TREE,
 #if TAG_MAJOR_VERSION > 34
-    DNGN_PETRIFIED_TREE,               // tree but lrd-able
+    DNGN_MANGROVE,                    // Swamp's tree type
+    DNGN_PETRIFIED_TREE,              // tree but lrd-able
 #endif
 
     // Walls
@@ -323,6 +324,7 @@ enum dungeon_feature_type
     DNGN_TRAP_TELEPORT_PERMANENT,
     DNGN_TRAVEL_TRAIL,
     DNGN_PETRIFIED_TREE,
+    DNGN_MANGROVE,
 #endif
 
     NUM_FEATURES
index 60fd13f..860f02d 100644 (file)
@@ -4455,14 +4455,14 @@ static const vault_placement *_build_vault_impl(const map_def *vault,
     if (!build_only && (placed_vault_orientation != MAP_ENCOMPASS || is_layout)
         && player_in_branch(BRANCH_SWAMP))
     {
-        _process_disconnected_zones(0, 0, GXM-1, GYM-1, true, DNGN_TREE);
+        _process_disconnected_zones(0, 0, GXM-1, GYM-1, true, DNGN_MANGROVE);
         // do a second pass to remove tele closets consisting of deep water
         // created by the first pass -- which will not fill in deep water
         // because it is treated as impassable.
         // TODO: get zonify to prevent these?
         // TODO: does this come up anywhere outside of swamp?
-        _process_disconnected_zones(0, 0, GXM-1, GYM-1, true, DNGN_TREE,
-                                    _dgn_square_is_ever_passable);
+        _process_disconnected_zones(0, 0, GXM-1, GYM-1, true, DNGN_MANGROVE,
+                _dgn_square_is_ever_passable);
     }
 
     if (!make_no_exits)
@@ -5208,7 +5208,9 @@ static dungeon_feature_type _glyph_to_feat(int glyph)
            (glyph == 'm') ? DNGN_CLEAR_ROCK_WALL :
            (glyph == 'n') ? DNGN_CLEAR_STONE_WALL :
            (glyph == 'o') ? DNGN_CLEAR_PERMAROCK_WALL :
-           (glyph == 't') ? DNGN_TREE :
+           // We make 't' correspond to the right tree type by branch.
+           (glyph == 't') ? player_in_branch(BRANCH_SWAMP)
+                          ? DNGN_MANGROVE : DNGN_TREE
            (glyph == '+') ? DNGN_CLOSED_DOOR :
            (glyph == '=') ? DNGN_RUNED_CLEAR_DOOR :
            (glyph == 'w') ? DNGN_DEEP_WATER :
index d0d1ea1..3ab8d92 100644 (file)
@@ -91,6 +91,13 @@ static feature_def feat_defs[] =
 },
 
 {
+    DNGN_MANGROVE, "mangrove", "mangrove",
+    DCHAR_TREE, DCHAR_WALL_MAGIC,
+    COLOUR_IS(ETC_MANGROVE),
+    FFT_OPAQUE | FFT_SOLID, MF_WALL,
+},
+
+{
     DNGN_PETRIFIED_TREE, "petrified tree", "petrified_tree",
     DCHAR_TREE, DCHAR_WALL_MAGIC,
     COLOUR_IS(DARKGREY),
index e760f65..61bd652 100644 (file)
@@ -1289,6 +1289,7 @@ static int _shatter_walls(coord_def where, int /*pow*/, actor *agent)
     case DNGN_SLIMY_WALL:
     case DNGN_CRYSTAL_WALL:
     case DNGN_TREE:
+    case DNGN_MANGROVE:
     case DNGN_PETRIFIED_TREE:
         chance = 33;
         break;
index f5f8214..c2c4c99 100644 (file)
@@ -258,6 +258,7 @@ enum tag_minor_version
     TAG_MINOR_UNCURSE,             // Remove curses from items
     TAG_MINOR_NEW_ASHENZARI,       // New Ashenzari
     TAG_MINOR_COMPRESS_BADMUTS,    // Reduce some mutations to 2 levels
+    TAG_MINOR_NEW_TREES,           // New tree types
 #endif
     NUM_TAG_MINORS,
     TAG_MINOR_VERSION = NUM_TAG_MINORS - 1
index 1a65237..8ccc7ca 100644 (file)
@@ -1033,6 +1033,13 @@ static dungeon_feature_type rewrite_feature(dungeon_feature_type x,
 
     if (x == DNGN_ENTER_LABYRINTH)
         x = DNGN_ENTER_GAUNTLET;
+
+    if (minor_version < TAG_MINOR_NEW_TREES
+        && you.where_are_you == BRANCH_SWAMP
+        && x == DNGN_TREE)
+    {
+        x = DNGN_MANGROVE;
+    }
 #else
     UNUSED(minor_version);
 #endif
index ff0171d..8639749 100644 (file)
@@ -54,7 +54,7 @@
 #include "viewchar.h"
 #include "view.h"
 
-static bool _revert_terrain_to_floor(coord_def pos);
+static bool _revert_terrain_to(coord_def pos, dungeon_feature_type feat);
 
 actor* actor_at(const coord_def& c)
 {
@@ -505,7 +505,8 @@ bool feat_is_water(dungeon_feature_type feat)
     return feat == DNGN_SHALLOW_WATER
            || feat == DNGN_DEEP_WATER
            || feat == DNGN_OPEN_SEA
-           || feat == DNGN_TOXIC_BOG;
+           || feat == DNGN_TOXIC_BOG
+           || feat == DNGN_MANGROVE;
 }
 
 /** Does this feature have enough water to keep water-only monsters alive in it?
@@ -606,14 +607,15 @@ bool feat_is_player_altar(dungeon_feature_type grid)
  */
 bool feat_is_tree(dungeon_feature_type feat)
 {
-    return feat == DNGN_TREE || feat == DNGN_PETRIFIED_TREE;
+    return feat == DNGN_TREE || feat == DNGN_MANGROVE
+        || feat == DNGN_PETRIFIED_TREE;
 }
 
 /** Is this feature flammable?
  */
 bool feat_is_flammable(dungeon_feature_type feat)
 {
-    return feat == DNGN_TREE;
+    return feat == DNGN_TREE || feat == DNGN_MANGROVE;
 }
 
 
@@ -1883,7 +1885,8 @@ void destroy_wall(const coord_def& p)
     if (is_bloodcovered(p))
         env.pgrid(p) &= ~(FPROP_BLOODY);
 
-    _revert_terrain_to_floor(p);
+    _revert_terrain_to(p,
+            env.grid(p) == DNGN_MANGROVE ? DNGN_SHALLOW_WATER : DNGN_FLOOR);
     env.level_map_mask(p) |= MMT_TURNED_TO_FLOOR;
 }
 
@@ -2063,17 +2066,9 @@ void temp_change_terrain(coord_def pos, dungeon_feature_type newfeat, int dur,
     dungeon_terrain_changed(pos, newfeat, false, true, true);
 }
 
-/// What terrain type do destroyed feats become, in the current branch?
-static dungeon_feature_type _destroyed_feat_type()
+static bool _revert_terrain_to(coord_def pos, dungeon_feature_type feat)
 {
-    return player_in_branch(BRANCH_SWAMP) ?
-        DNGN_SHALLOW_WATER :
-        DNGN_FLOOR;
-}
-
-static bool _revert_terrain_to_floor(coord_def pos)
-{
-    dungeon_feature_type newfeat = _destroyed_feat_type();
+    dungeon_feature_type newfeat = feat;
     for (map_marker *marker : env.markers.get_markers_at(pos))
     {
         if (marker->get_type() == MAT_TERRAIN_CHANGE)
@@ -2086,7 +2081,7 @@ static bool _revert_terrain_to_floor(coord_def pos)
             // Same for destroyed trees
             if ((tmarker->change_type == TERRAIN_CHANGE_DOOR_SEAL
                 || tmarker->change_type == TERRAIN_CHANGE_FORESTED)
-                && newfeat == _destroyed_feat_type())
+                && newfeat == feat)
             {
                 env.markers.remove(tmarker);
             }
index cc31c17..d0ea4cd 100644 (file)
@@ -353,17 +353,12 @@ static dungeon_feature_type _safe_feat(coord_def gc, crawl_view_buffer& vbuf)
     return vbuf(gc).tile.map_knowledge.feat();
 }
 
-static bool _feat_is_mangrove(dungeon_feature_type feat)
-{
-    return feat_is_tree(feat) && player_in_branch(BRANCH_SWAMP);
-}
-
 static bool _is_seen_land(coord_def gc, crawl_view_buffer& vbuf)
 {
     const auto feat = _safe_feat(gc, vbuf);
 
     return feat != DNGN_UNSEEN && !feat_is_water(feat) && !feat_is_lava(feat)
-           && !_feat_is_mangrove(feat);
+           && feat != DNGN_MANGROVE;
 }
 
 static bool _is_seen_shallow(coord_def gc, crawl_view_buffer& vbuf)
@@ -373,7 +368,7 @@ static bool _is_seen_shallow(coord_def gc, crawl_view_buffer& vbuf)
     if (!vbuf(gc).tile.map_knowledge.seen())
         return false;
 
-    return feat == DNGN_SHALLOW_WATER || _feat_is_mangrove(feat);
+    return feat == DNGN_SHALLOW_WATER || feat == DNGN_MANGROVE;
 }
 
 static tileidx_t _base_wave_tile(colour_t colour)
@@ -394,8 +389,8 @@ static void _pack_default_waves(const coord_def &gc, crawl_view_buffer& vbuf)
     auto feat = cell.map_knowledge.feat();
     auto colour = cell.map_knowledge.feat_colour();
 
-    // Treat trees in Swamp as though they were shallow water.
-    if (cell.mangrove_water && feat_is_tree(feat))
+    // Treat mangroves as though they were shallow water.
+    if (cell.mangrove_water && feat == DNGN_MANGROVE)
         feat = DNGN_SHALLOW_WATER;
 
     if (!feat_is_water(feat) && !feat_is_lava(feat))
index 71d52e1..7b02ff7 100644 (file)
@@ -200,7 +200,9 @@ tileidx_t tileidx_feature_base(dungeon_feature_type feat)
     case DNGN_ORCISH_IDOL:
         return TILE_DNGN_ORCISH_IDOL;
     case DNGN_TREE:
-        return player_in_branch(BRANCH_SWAMP) ? TILE_DNGN_MANGROVE : TILE_DNGN_TREE;
+        return TILE_DNGN_TREE;
+    case DNGN_MANGROVE:
+        return TILE_DNGN_MANGROVE;
     case DNGN_PETRIFIED_TREE:
         return TILE_DNGN_PETRIFIED_TREE;
     case DNGN_GRANITE_STATUE:
index bdea289..2594f63 100644 (file)
@@ -1414,7 +1414,7 @@ void tile_apply_properties(const coord_def &gc, packed_cell &cell)
     if (mc.flags & MAP_SILENCED)
         cell.is_silenced = true;
 
-    if (feat_is_tree(feat) && player_in_branch(BRANCH_SWAMP))
+    if (feat == DNGN_MANGROVE)
         cell.mangrove_water = true;
     cell.awakened_forest = feat_is_tree(feat) && env.forest_awoken_until;