Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Riot Damage in City Roads and Subway Stations. Adjust Fire and Blood placement over time. #79641

Merged
merged 11 commits into from
Feb 14, 2025
5 changes: 5 additions & 0 deletions data/json/flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -2691,5 +2691,10 @@
"id": "BANK_NETWORKED",
"type": "json_flag",
"//": "Vending machines with this flag will allow purchasing items with your bank balance."
},
{
"id": "NATURAL_UNDERGROUND",
"type": "json_flag",
"//": "Wall tiles with this flag occur naturally underground and are not manmade."
}
]
2 changes: 2 additions & 0 deletions data/json/furniture_and_terrain/terrain-walls.json
Original file line number Diff line number Diff line change
Expand Up @@ -1789,6 +1789,7 @@
"copy-from": "t_abstract_wall_earthen",
"name": "solid earth",
"description": "A wall of solid earth.",
"extend": { "flags": [ "NATURAL_UNDERGROUND" ] },
"delete": { "flags": [ "AUTO_WALL_SYMBOL" ] },
"roof": "t_dirt",
"bash": {
Expand All @@ -1808,6 +1809,7 @@
"name": "solid rock",
"description": "A wall of solid rock, could be full of all kinds of interesting things. Best grab your pickaxe or equivalent digging implement, and strike the earth!",
"color": "white",
"extend": { "flags": [ "NATURAL_UNDERGROUND" ] },
"delete": { "flags": [ "AUTO_WALL_SYMBOL" ] },
"roof": "t_rock_floor_no_roof",
"bash": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
"see_cost": "high",
"extras": "build",
"mondensity": 2,
"flags": [ "KNOWN_DOWN", "SIDEWALK" ]
"flags": [ "KNOWN_DOWN", "SIDEWALK", "PP_GENERATE_RIOT_DAMAGE" ]
},
{
"type": "overmap_terrain",
Expand All @@ -167,7 +167,7 @@
"color": "yellow",
"see_cost": "full_high",
"extras": "subway",
"flags": [ "KNOWN_UP", "KNOWN_DOWN", "NO_ROTATE" ]
"flags": [ "KNOWN_UP", "KNOWN_DOWN", "NO_ROTATE", "PP_GENERATE_RIOT_DAMAGE" ]
},
{
"type": "overmap_terrain",
Expand All @@ -178,7 +178,7 @@
"color": "yellow",
"see_cost": "full_high",
"extras": "subway",
"flags": [ "KNOWN_UP", "NO_ROTATE" ]
"flags": [ "KNOWN_UP", "NO_ROTATE", "PP_GENERATE_RIOT_DAMAGE" ]
},
{
"type": "overmap_terrain",
Expand Down
1 change: 1 addition & 0 deletions doc/JSON/JSON_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,7 @@ List of known flags, used in both `furniture` and `terrain`. Some work for both
- ```MINEABLE``` Can be mined with a pickaxe/jackhammer.
- ```MOUNTABLE``` Suitable for guns with the `MOUNTED_GUN` flag.
- ```NANOFAB_TABLE``` This is a nanofabricator, and it can generate items out of specific blueprints. Hardcoded
- ```NATURAL_UNDERGROUND``` This terrain occurs naturally underground and is not man made.
- ```NOCOLLIDE``` Feature that simply doesn't collide with vehicles at all.
- ```NOITEM``` Items cannot be added here but may overflow to adjacent tiles. See also `DESTROY_ITEM`.
- ```NO_FLOOR``` Things should fall when placed on this tile.
Expand Down
1 change: 1 addition & 0 deletions src/mapdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ std::string enum_to_string<ter_furn_flag>( ter_furn_flag data )
case ter_furn_flag::TFLAG_CLIMB_ADJACENT: return "CLIMB_ADJACENT";
case ter_furn_flag::TFLAG_FLOATS_IN_AIR: return "FLOATS_IN_AIR";
case ter_furn_flag::TFLAG_HARVEST_REQ_CUT1: return "HARVEST_REQ_CUT1";
case ter_furn_flag::TFLAG_NATURAL_UNDERGROUND: return "NATURAL_UNDERGROUND";

// *INDENT-ON*
case ter_furn_flag::NUM_TFLAG_FLAGS:
Expand Down
1 change: 1 addition & 0 deletions src/mapdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ enum class ter_furn_flag : int {
TFLAG_CLIMB_ADJACENT,
TFLAG_FLOATS_IN_AIR,
TFLAG_HARVEST_REQ_CUT1,
TFLAG_NATURAL_UNDERGROUND,

NUM_TFLAG_FLAGS
};
Expand Down
90 changes: 60 additions & 30 deletions src/mapgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,28 +259,36 @@ static tripoint_bub_ms get_point_from_direction( int direction,
}

static bool tile_can_have_blood( map &md, const tripoint_bub_ms &current_tile,
bool wall_streak )
bool wall_streak, int days_since_cataclysm )
{
// Wall streaks stick to walls, like blood was splattered against the surface
// Floor streaks avoid obstacles to look more like a person left the streak behind (Not walking through walls, closed doors, windows, or furniture)
if( wall_streak ) {
return md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_WALL, current_tile );
return md.has_flag_ter( ter_furn_flag::TFLAG_WALL, current_tile ) &&
!md.has_flag_ter( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile );
} else {
return !md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_WALL, current_tile ) &&
!md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_WINDOW, current_tile ) &&
!md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_DOOR, current_tile ) &&
if( !md.has_flag_ter( ter_furn_flag::TFLAG_INDOORS, current_tile ) &&
!x_in_y( ( 30.0 - days_since_cataclysm ) / 30.0, 1 ) ) {
QuillInkwell marked this conversation as resolved.
Show resolved Hide resolved
// Placement of blood outdoors scales down over the course of 30 days until no further blood is placed.
return false;
}

return !md.has_flag_ter( ter_furn_flag::TFLAG_WALL, current_tile ) &&
!md.has_flag_ter( ter_furn_flag::TFLAG_WINDOW, current_tile ) &&
!md.has_flag_ter( ter_furn_flag::TFLAG_DOOR, current_tile ) &&
!md.has_furn( current_tile );
}

}

static void place_blood_on_adjacent( map &md, const tripoint_bub_ms &current_tile, int chance )
static void place_blood_on_adjacent( map &md, const tripoint_bub_ms &current_tile, int chance,
int days_since_catacylsm )
{
for( int i = static_cast<int>( blood_trail_direction::first );
i <= static_cast<int>( blood_trail_direction::last ); i++ ) {
tripoint_bub_ms adjacent_tile = get_point_from_direction( i, current_tile );

if( !tile_can_have_blood( md, adjacent_tile, false ) ) {
if( !tile_can_have_blood( md, adjacent_tile, false, days_since_catacylsm ) ) {
continue;
}
if( rng( 1, 100 ) < chance ) {
Expand All @@ -289,15 +297,16 @@ static void place_blood_on_adjacent( map &md, const tripoint_bub_ms &current_til
}
}

static void place_blood_streaks( map &md, const tripoint_bub_ms &current_tile )
static void place_blood_streaks( map &md, const tripoint_bub_ms &current_tile,
int days_since_cataclysm )
{
int streak_length = rng( 3, 12 );
int streak_direction = rng( static_cast<int>( blood_trail_direction::first ),
static_cast<int>( blood_trail_direction::last ) );

bool wall_streak = md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_WALL, current_tile );

if( !tile_can_have_blood( md, current_tile, wall_streak ) ) {
if( !tile_can_have_blood( md, current_tile, wall_streak, days_since_cataclysm ) ) {
// Quick check the tile is valid.
return;
}
Expand All @@ -308,7 +317,7 @@ static void place_blood_streaks( map &md, const tripoint_bub_ms &current_tile )
for( int i = 0; i < streak_length; i++ ) {
tripoint_bub_ms destination_tile = get_point_from_direction( streak_direction, last_tile );

if( !tile_can_have_blood( md, destination_tile, wall_streak ) ) {
if( !tile_can_have_blood( md, destination_tile, wall_streak, days_since_cataclysm ) ) {
// We hit a non-valid tile. Try to find a new direction otherwise just terminate the streak.
bool terminate_streak = true;

Expand All @@ -321,7 +330,7 @@ static void place_blood_streaks( map &md, const tripoint_bub_ms &current_tile )
}
tripoint_bub_ms adjacent_tile = get_point_from_direction( ii, last_tile );

if( tile_can_have_blood( md, adjacent_tile, wall_streak ) ) {
if( tile_can_have_blood( md, adjacent_tile, wall_streak, days_since_cataclysm ) ) {
streak_direction = ii;
destination_tile = adjacent_tile;
terminate_streak = false;
Expand Down Expand Up @@ -364,42 +373,42 @@ static void place_blood_streaks( map &md, const tripoint_bub_ms &current_tile )
}

tripoint_bub_ms adjacent_tile = get_point_from_direction( new_direction, last_tile );
if( tile_can_have_blood( md, adjacent_tile, wall_streak ) ) {
if( tile_can_have_blood( md, adjacent_tile, wall_streak, days_since_cataclysm ) ) {
md.add_field( adjacent_tile, field_fd_blood );
last_tile = adjacent_tile;
}
}
}
}

static void place_bool_pools( map &md, const tripoint_bub_ms &current_tile )
static void place_bool_pools( map &md, const tripoint_bub_ms &current_tile,
int days_since_cataclysm )
{
if( !tile_can_have_blood( md, current_tile, false ) ) {
if( !tile_can_have_blood( md, current_tile, false, days_since_cataclysm ) ) {
// Quick check the first tile is valid for placement
return;
}

md.add_field( current_tile, field_fd_blood );
place_blood_on_adjacent( md, current_tile, 60 );
place_blood_on_adjacent( md, current_tile, 60, days_since_cataclysm );

for( int i = static_cast<int>( blood_trail_direction::first );
i <= static_cast<int>( blood_trail_direction::last ); i++ ) {
tripoint_bub_ms adjacent_tile = get_point_from_direction( i, current_tile );
if( !tile_can_have_blood( md, adjacent_tile, false ) ) {
if( !tile_can_have_blood( md, adjacent_tile, false, days_since_cataclysm ) ) {
continue;
}
place_blood_on_adjacent( md, adjacent_tile, 30 );
place_blood_on_adjacent( md, adjacent_tile, 30, days_since_cataclysm );
}
}

static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
{
if( p.z() < 0 ) {
// for the moment make sure we don't apply this to labs or other places
debugmsg( "Riot damage mapgen generator called on underground structure. This is likely a bug." );
return;
}
std::list<tripoint_bub_ms> all_points_in_map;


int days_since_cataclysm = to_days<int>( calendar::turn - calendar::start_of_cataclysm );

// Placeholder / FIXME
// This assumes that we're only dealing with regular 24x24 OMTs. That is likely not the case.
for( int i = 0; i < SEEX * 2; i++ ) {
Expand All @@ -411,10 +420,15 @@ static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
for( size_t i = 0; i < all_points_in_map.size(); i++ ) {
// Pick a tile at random!
tripoint_bub_ms current_tile = random_entry( all_points_in_map );

// Do nothing at random!;
if( x_in_y( 10, 100 ) ) {
continue;
}
// Skip naturally occuring underground wall tiles
if( md.has_flag_ter( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
continue;
}
// Bash stuff at random!
if( x_in_y( 20, 100 ) ) {
md.bash( current_tile, rng( 6, 60 ) );
Expand Down Expand Up @@ -451,15 +465,26 @@ static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
int behavior_roll = rng( 1, 100 );

if( behavior_roll <= 20 ) {
md.add_field( current_tile, field_fd_blood );
if( tile_can_have_blood( md, current_tile, md.has_flag_ter( ter_furn_flag::TFLAG_WALL,
current_tile ), days_since_cataclysm ) ) {
md.add_field( current_tile, field_fd_blood );
}
} else if( behavior_roll <= 60 ) {
place_blood_streaks( md, current_tile );
place_blood_streaks( md, current_tile, days_since_cataclysm );
} else {
place_bool_pools( md, current_tile );
place_bool_pools( md, current_tile, days_since_cataclysm );
}
}
if( x_in_y( 1, 2000 ) ) {
md.add_field( current_tile, field_fd_fire );

// Decrease the chance of fire spawning as the Cataclysm progresses to the min fire chance of 1 in 10,000
QuillInkwell marked this conversation as resolved.
Show resolved Hide resolved
if( x_in_y( 1, std::min( 2000 + 714 * days_since_cataclysm, 10000 ) ) ) {
if( md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_FLAMMABLE, current_tile ) ||
md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_FLAMMABLE_ASH, current_tile ) ||
md.has_flag_ter_or_furn( ter_furn_flag:: TFLAG_FLAMMABLE_HARD, current_tile ) ||
QuillInkwell marked this conversation as resolved.
Show resolved Hide resolved
days_since_cataclysm < 3 ) {
// Only place fire on flammable surfaces unless the cataclysm started very recently
QuillInkwell marked this conversation as resolved.
Show resolved Hide resolved
md.add_field( current_tile, field_fd_fire );
}
}
}
}
Expand Down Expand Up @@ -633,9 +658,14 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save
}

// Apply post-process generators
if( ( any_missing || !save_results ) && overmap_buffer.ter( {p.x(), p.y(), gridz} )->has_flag(
oter_flags::pp_generate_riot_damage ) ) {
GENERATOR_riot_damage( *this, { p.x(), p.y(), gridz } );
const tripoint_abs_omt omt_point = { p.x(), p.y(), gridz };
oter_id omt = overmap_buffer.ter( omt_point );
if( any_missing || !save_results ) {
if( omt->has_flag(
oter_flags::pp_generate_riot_damage ) || ( omt->has_flag( oter_flags::road ) &&
overmap_buffer.is_in_city( omt_point ) ) ) {
GENERATOR_riot_damage( *this, omt_point );
}
}
}

Expand Down
Loading