Skip to content

Commit e49605e

Browse files
authored
Merge pull request #80753 from RenechCDDA/break_up_riot_damage_functions
Refactor riot damage + add 'pre-burnt' generator
2 parents e3fb5bb + fe3c805 commit e49605e

File tree

3 files changed

+255
-46
lines changed

3 files changed

+255
-46
lines changed

data/json/furniture_and_terrain/terrain-floors-indoor.json

+22
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,28 @@
16291629
"items": [ { "item": "clay_lump", "count": [ 6, 12 ] } ]
16301630
}
16311631
},
1632+
{
1633+
"type": "terrain",
1634+
"id": "t_floor_burnt",
1635+
"name": "burnt floor",
1636+
"description": "Whatever this floor used to be made of, it's little more than charred remains now.",
1637+
"symbol": ".",
1638+
"looks_like": "t_dirtfloor",
1639+
"color": "black",
1640+
"move_cost": 2,
1641+
"connect_groups": "INDOORFLOOR",
1642+
"flags": [ "TRANSPARENT", "COLLAPSES", "INDOORS" ],
1643+
"bash": {
1644+
"str_min": 1,
1645+
"str_max": 6,
1646+
"//COMMENT": "I don't know, charcoal breaking sounds? Onomatopoeia is outside my skillset!",
1647+
"sound": "crunch!",
1648+
"sound_fail": "twang!",
1649+
"sound_vol": 8,
1650+
"sound_fail_vol": 4,
1651+
"ter_set": "t_null"
1652+
}
1653+
},
16321654
{
16331655
"type": "terrain",
16341656
"id": "t_floor_paper",

data/json/furniture_and_terrain/terrain-walls.json

+23
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,29 @@
11721172
},
11731173
"shoot": { "chance_to_hit": 25, "reduce_damage": [ 20, 40 ], "reduce_damage_laser": [ 10, 30 ], "destroy_damage": [ 30, 100 ] }
11741174
},
1175+
{
1176+
"type": "terrain",
1177+
"id": "t_wall_burnt",
1178+
"name": "burnt wall",
1179+
"looks_like": "t_wall_wood_broken",
1180+
"description": "Whatever this wall used to be made of, it's little more than charred remains now.",
1181+
"symbol": "#",
1182+
"color": "black",
1183+
"move_cost": 0,
1184+
"coverage": 35,
1185+
"connect_groups": "WALL",
1186+
"connects_to": "WALL",
1187+
"flags": [ "TRANSPARENT", "NOITEM", "SUPPORTS_ROOF", "REDUCE_SCENT", "PERMEABLE" ],
1188+
"bash": {
1189+
"str_min": 4,
1190+
"str_max": 20,
1191+
"sound": "crash!",
1192+
"sound_fail": "whump!",
1193+
"ter_set": "t_null",
1194+
"items": [ { "item": "ash", "count": [ 200, 500 ] }, { "item": "scrap", "count": [ 2, 5 ] } ]
1195+
},
1196+
"shoot": { "chance_to_hit": 25, "reduce_damage": [ 5, 10 ], "reduce_damage_laser": [ 10, 30 ], "destroy_damage": [ 5, 20 ] }
1197+
},
11751198
{
11761199
"type": "terrain",
11771200
"id": "t_wall_log_half",

src/mapgen.cpp

+210-46
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ static const ter_str_id ter_t_door_glass_frosted_c( "t_door_glass_frosted_c" );
210210
static const ter_str_id ter_t_door_metal_c( "t_door_metal_c" );
211211
static const ter_str_id ter_t_door_metal_locked( "t_door_metal_locked" );
212212
static const ter_str_id ter_t_floor( "t_floor" );
213+
static const ter_str_id ter_t_floor_burnt( "t_floor_burnt" );
213214
static const ter_str_id ter_t_fungus_floor_in( "t_fungus_floor_in" );
214215
static const ter_str_id ter_t_fungus_wall( "t_fungus_wall" );
215216
static const ter_str_id ter_t_grass( "t_grass" );
@@ -225,6 +226,7 @@ static const ter_str_id ter_t_strconc_floor( "t_strconc_floor" );
225226
static const ter_str_id ter_t_thconc_floor( "t_thconc_floor" );
226227
static const ter_str_id ter_t_thconc_floor_olight( "t_thconc_floor_olight" );
227228
static const ter_str_id ter_t_vat( "t_vat" );
229+
static const ter_str_id ter_t_wall_burnt( "t_wall_burnt" );
228230
static const ter_str_id ter_t_water_sh( "t_water_sh" );
229231

230232
static const trait_id trait_NPC_STATIC_NPC( "NPC_STATIC_NPC" );
@@ -419,38 +421,62 @@ static void place_bool_pools( map &md, const tripoint_bub_ms &current_tile,
419421
}
420422
}
421423

422-
static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
423-
{
424-
std::list<tripoint_bub_ms> all_points_in_map;
425-
424+
struct generator_vars {
425+
int scaling_days_start;
426+
int scaling_days_end;
427+
int num_attempts;
428+
int percent_chance;
429+
int min_intensity;
430+
int max_intensity;
431+
};
426432

427-
int days_since_cataclysm = to_days<int>( calendar::turn - calendar::start_of_cataclysm );
433+
static void GENERATOR_bash_damage( map &md,
434+
std::list<tripoint_bub_ms> &all_points_in_map,
435+
int days_since_cataclysm )
436+
{
437+
// Later, this will be loaded from json.
438+
generator_vars bash_vars{};
439+
bash_vars.scaling_days_start = 0; // irrelevant for this one
440+
bash_vars.scaling_days_end = days_since_cataclysm; // irrelevant for this one
441+
bash_vars.num_attempts = 250; // Roughly half as many attempts as old version, may need tweaking
442+
bash_vars.percent_chance = 10;
443+
bash_vars.min_intensity = 6; // For this generator: Bash damage
444+
bash_vars.max_intensity = 60; // For this generator: Bash damage
428445

429-
// Placeholder / FIXME
430-
// This assumes that we're only dealing with regular 24x24 OMTs. That is likely not the case.
431-
for( int i = 0; i < SEEX * 2; i++ ) {
432-
for( int n = 0; n < SEEY * 2; n++ ) {
433-
tripoint_bub_ms current_tile( i, n, p.z() );
434-
all_points_in_map.push_back( current_tile );
446+
for( int i = 0; i < bash_vars.num_attempts; i++ ) {
447+
if( !x_in_y( bash_vars.percent_chance, 100 ) ) {
448+
continue; // failed roll
435449
}
436-
}
437-
for( size_t i = 0; i < all_points_in_map.size(); i++ ) {
438-
// Pick a tile at random!
439-
tripoint_bub_ms current_tile = random_entry( all_points_in_map );
440-
441-
// Do nothing at random!;
442-
if( x_in_y( 10, 100 ) ) {
450+
const tripoint_bub_ms current_tile = random_entry( all_points_in_map );
451+
if( md.has_flag_ter( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
443452
continue;
444453
}
445-
// Skip naturally occuring underground wall tiles
454+
md.bash( current_tile, rng( bash_vars.min_intensity, bash_vars.max_intensity ) );
455+
}
456+
}
457+
458+
static void GENERATOR_move_items( map &md,
459+
std::list<tripoint_bub_ms> &all_points_in_map,
460+
int days_since_cataclysm )
461+
{
462+
// Later, this will be loaded from json.
463+
generator_vars mover_vars{};
464+
mover_vars.scaling_days_start = 0; // irrelevant for this one, currently.
465+
mover_vars.scaling_days_end = days_since_cataclysm; // irrelevant for this one
466+
467+
// NOTE: Each tile of items is fully iterated over, to eliminate the effects of stack ordering.
468+
// Otherwise we would be biased towards the front of the stack
469+
mover_vars.num_attempts = 250; // Roughly half as many attempts as old version, may need tweaking
470+
471+
mover_vars.percent_chance = 10;
472+
mover_vars.min_intensity = 0; // For this generator: Min distance moved. Note: NOT IMPLEMENTED
473+
mover_vars.max_intensity = 3; // For this generator: Max distance moved
474+
475+
for( int i = 0; i < mover_vars.num_attempts; i++ ) {
476+
const tripoint_bub_ms current_tile = random_entry( all_points_in_map );
446477
if( md.has_flag_ter( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
447478
continue;
448479
}
449-
// Bash stuff at random!
450-
if( x_in_y( 20, 100 ) ) {
451-
md.bash( current_tile, rng( 6, 60 ) );
452-
}
453-
// Move stuff at random!
454480
auto item_iterator = md.i_at( current_tile.xy() ).begin();
455481
while( item_iterator != md.i_at( current_tile.xy() ).end() ) {
456482
// Some items must not be moved out of SEALED CONTAINER
@@ -463,11 +489,13 @@ static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
463489
continue;
464490
}
465491
}
466-
if( x_in_y( 10, 100 ) ) {
492+
493+
if( x_in_y( mover_vars.percent_chance, 100 ) ) {
467494
// pick a new spot...
468-
tripoint_bub_ms destination_tile( current_tile.x() + rng( -3, 3 ),
469-
current_tile.y() + rng( -3, 3 ),
470-
current_tile.z() );
495+
tripoint_bub_ms destination_tile(
496+
current_tile.x() + rng( -mover_vars.max_intensity, mover_vars.max_intensity ),
497+
current_tile.y() + rng( -mover_vars.max_intensity, mover_vars.max_intensity ),
498+
current_tile.z() );
471499
// oops, don't place out of bounds. just skip moving
472500
const bool outbounds_X = destination_tile.x() < 0 || destination_tile.x() >= SEEX * 2;
473501
const bool outbounds_Y = destination_tile.y() < 0 || destination_tile.y() >= SEEY * 2;
@@ -486,6 +514,155 @@ static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
486514
} else {
487515
item_iterator++;
488516
}
517+
518+
}
519+
}
520+
521+
}
522+
523+
static void GENERATOR_add_fire( map &md,
524+
std::list<tripoint_bub_ms> &all_points_in_map,
525+
int days_since_cataclysm )
526+
{
527+
// Later, this will be loaded from json.
528+
generator_vars fire_vars{};
529+
fire_vars.scaling_days_start = 0;
530+
fire_vars.scaling_days_end = 14;
531+
532+
// Placeholder. Number selected so that the # of fires is close to the old implementation.
533+
fire_vars.num_attempts = 2;
534+
535+
// FIXME? I'm concerned by the fact that the initial chance scales higher the later the last scaling day is.
536+
// This is not great, but it ramps down linearly without relying on magic numbers.
537+
fire_vars.percent_chance = std::max( fire_vars.scaling_days_end - days_since_cataclysm, 0 );
538+
539+
fire_vars.min_intensity = 1; // For this generator: field intensity
540+
fire_vars.max_intensity = 3; // For this generator: field intensity
541+
542+
for( int i = 0; i < fire_vars.num_attempts; i++ ) {
543+
if( !x_in_y( fire_vars.percent_chance, 100 ) ) {
544+
continue; // failed roll
545+
}
546+
const tripoint_bub_ms current_tile = random_entry( all_points_in_map );
547+
if( md.has_flag_ter( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
548+
continue;
549+
}
550+
551+
if( x_in_y( fire_vars.percent_chance, 100 ) ) {
552+
// FIXME: Magic number 3. Replace with some value loaded into generator_vars?
553+
if( md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_FLAMMABLE, current_tile ) ||
554+
md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_FLAMMABLE_ASH, current_tile ) ||
555+
md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_FLAMMABLE_HARD, current_tile ) ||
556+
days_since_cataclysm < 3 ) {
557+
// Only place fire on flammable surfaces unless the cataclysm started very recently
558+
// Note that most floors are FLAMMABLE_HARD, this is fine. This check is primarily geared
559+
// at preventing fire in the middle of roads or parking lots.
560+
md.add_field( current_tile, field_fd_fire,
561+
rng( fire_vars.min_intensity, fire_vars.max_intensity ) );
562+
}
563+
}
564+
565+
}
566+
567+
}
568+
569+
static void GENERATOR_pre_burn( map &md,
570+
std::list<tripoint_bub_ms> &all_points_in_map,
571+
int days_since_cataclysm )
572+
{
573+
// Later, this will be loaded from json.
574+
generator_vars burnt_vars{};
575+
// Fires are still raging around this time, but some start appearing
576+
// Never appears before this date
577+
burnt_vars.scaling_days_start = 3;
578+
579+
burnt_vars.scaling_days_end = 14; // Continues appearing at maximum appearance rate after this day
580+
burnt_vars.num_attempts = 1; // Currently only applied to the whole map, so one pass.
581+
582+
burnt_vars.min_intensity = 6; // For this generator: % chance at start day
583+
burnt_vars.max_intensity = 28; // For this generator: % chance at end day
584+
585+
// between start and end day we linearly interpolate.
586+
double lerp_scalar = static_cast<double>(
587+
static_cast<double>( days_since_cataclysm - burnt_vars.scaling_days_start ) /
588+
static_cast<double>( burnt_vars.scaling_days_end - burnt_vars.scaling_days_start ) );
589+
burnt_vars.percent_chance = lerp( burnt_vars.min_intensity, burnt_vars.max_intensity, lerp_scalar );
590+
// static values outside that range. Note we do not use std::clamp because the chance is *0* until the start day is reached
591+
if( days_since_cataclysm < burnt_vars.scaling_days_start ) {
592+
burnt_vars.percent_chance = 0;
593+
} else if( days_since_cataclysm >= burnt_vars.scaling_days_end ) {
594+
burnt_vars.percent_chance = burnt_vars.max_intensity;
595+
}
596+
597+
for( int i = 0; i < burnt_vars.num_attempts; i++ ) {
598+
if( !x_in_y( burnt_vars.percent_chance, 100 ) ) {
599+
continue; // failed roll
600+
}
601+
for( tripoint_bub_ms current_tile : all_points_in_map ) {
602+
if( md.has_flag_ter( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
603+
continue;
604+
}
605+
if( md.has_flag_ter( ter_furn_flag::TFLAG_WALL, current_tile ) ) {
606+
// burnt wall
607+
md.ter_set( current_tile.xy(), ter_t_wall_burnt );
608+
} else if( md.has_flag_ter( ter_furn_flag::TFLAG_INDOORS, current_tile ) ||
609+
md.has_flag_ter( ter_furn_flag::TFLAG_DOOR, current_tile ) ) {
610+
// if we're indoors but we're not a wall, then we must be a floor.
611+
// doorways also get burned to the ground.
612+
md.ter_set( current_tile.xy(), ter_t_floor_burnt );
613+
} else if( !md.has_flag_ter( ter_furn_flag::TFLAG_INDOORS, current_tile ) ) {
614+
// if we're outside on ground level, burn it to dirt.
615+
if( current_tile.z() == 0 ) {
616+
md.ter_set( current_tile.xy(), ter_t_dirt );
617+
}
618+
}
619+
620+
// destroy any furniture that is in the tile. it's been burned, after all.
621+
md.furn_set( current_tile.xy(), furn_str_id::NULL_ID() );
622+
623+
// destroy all items in the tile.
624+
md.i_clear( current_tile.xy() );
625+
}
626+
}
627+
}
628+
629+
static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p, bool is_a_road )
630+
{
631+
std::list<tripoint_bub_ms> all_points_in_map;
632+
633+
634+
int days_since_cataclysm = to_days<int>( calendar::turn - calendar::start_of_cataclysm );
635+
636+
// Placeholder / FIXME
637+
// This assumes that we're only dealing with regular 24x24 OMTs. That is likely not the case.
638+
for( int i = 0; i < SEEX * 2; i++ ) {
639+
for( int n = 0; n < SEEY * 2; n++ ) {
640+
tripoint_bub_ms current_tile( i, n, p.z() );
641+
all_points_in_map.push_back( current_tile );
642+
}
643+
}
644+
645+
// Run sub generators associated with this generator. Currently hardcoded.
646+
GENERATOR_bash_damage( md, all_points_in_map, days_since_cataclysm );
647+
GENERATOR_move_items( md, all_points_in_map, days_since_cataclysm );
648+
GENERATOR_add_fire( md, all_points_in_map, days_since_cataclysm );
649+
// HACK: Don't burn roads to the ground! This should be resolved when the system is moved to json
650+
if( !is_a_road ) {
651+
GENERATOR_pre_burn( md, all_points_in_map, days_since_cataclysm );
652+
}
653+
654+
// NOTE: Below currently only runs for bloodstains.
655+
for( size_t i = 0; i < all_points_in_map.size(); i++ ) {
656+
// Pick a tile at random!
657+
tripoint_bub_ms current_tile = random_entry( all_points_in_map );
658+
659+
// Do nothing at random!;
660+
if( x_in_y( 10, 100 ) ) {
661+
continue;
662+
}
663+
// Skip naturally occuring underground wall tiles
664+
if( md.has_flag_ter( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
665+
continue;
489666
}
490667
// Set some fields at random!
491668
if( x_in_y( 15, 1000 ) ) {
@@ -502,20 +679,6 @@ static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
502679
place_bool_pools( md, current_tile, days_since_cataclysm );
503680
}
504681
}
505-
506-
// Randomly spawn fires, with the chance decreasing from 1 in 2000 to 1 in 10,000 over the
507-
// course of 14 days
508-
if( x_in_y( 1, std::min( 2000 + 571 * days_since_cataclysm, 10000 ) ) ) {
509-
if( md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_FLAMMABLE, current_tile ) ||
510-
md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_FLAMMABLE_ASH, current_tile ) ||
511-
md.has_flag_ter_or_furn( ter_furn_flag::TFLAG_FLAMMABLE_HARD, current_tile ) ||
512-
days_since_cataclysm < 3 ) {
513-
// Only place fire on flammable surfaces unless the cataclysm started very recently
514-
// Note that most floors are FLAMMABLE_HARD, this is fine. This check is primarily geared
515-
// at preventing fire in the middle of roads or parking lots.
516-
md.add_field( current_tile, field_fd_fire );
517-
}
518-
}
519682
}
520683
}
521684

@@ -693,10 +856,11 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save
693856
if( any_missing || !save_results ) {
694857
const tripoint_abs_omt omt_point = { p.x(), p.y(), gridz };
695858
oter_id omt = overmap_buffer.ter( omt_point );
696-
if( omt->has_flag(
697-
oter_flags::pp_generate_riot_damage ) || ( omt->has_flag( oter_flags::road ) &&
698-
overmap_buffer.is_in_city( omt_point ) ) ) {
699-
GENERATOR_riot_damage( *this, omt_point );
859+
if( omt->has_flag( oter_flags::pp_generate_riot_damage ) && !omt->has_flag( oter_flags::road ) ) {
860+
GENERATOR_riot_damage( *this, omt_point, false );
861+
} else if( omt->has_flag( oter_flags::road ) && overmap_buffer.is_in_city( omt_point ) ) {
862+
// HACK: Hardcode running only certain sub-generators on roads
863+
GENERATOR_riot_damage( *this, omt_point, true );
700864
}
701865
}
702866
}

0 commit comments

Comments
 (0)