Skip to content

Commit

Permalink
Merge pull request #69980 from esotericist/hordes-intensify
Browse files Browse the repository at this point in the history
re-add pre-seeded hordes, make them unconditional, and show up even with wandering hordes disabled
  • Loading branch information
kevingranade authored Dec 6, 2023
2 parents 96b2e8d + 27c72b7 commit 1e7d45b
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 6 deletions.
28 changes: 28 additions & 0 deletions data/core/game_balance.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,34 @@
"stype": "bool",
"value": false
},
{
"type": "EXTERNAL_OPTION",
"name": "SPAWN_CITY_HORDE_THRESHOLD",
"info": "Minimum city size to guarantee extra zombies are spawned in cities. 0 means all cities spawn extra zombies. Negative values disable extra city zombies.",
"stype": "int",
"value": 4
},
{
"type": "EXTERNAL_OPTION",
"name": "SPAWN_CITY_HORDE_SMALL_CITY_CHANCE",
"info": "Probability of a city smaller than SPAWN_HORDE_THRESHOLD having city zombies spawned, express in 'one in x' fashion .",
"stype": "int",
"value": 16
},
{
"type": "EXTERNAL_OPTION",
"name": "SPAWN_CITY_HORDE_SPREAD",
"info": "A scaling factor that determines how far from the center of cities extra zombies spawn, multiplied by city size, when city hordes are indicated.",
"stype": "float",
"value": 1.5
},
{
"type": "EXTERNAL_OPTION",
"name": "SPAWN_CITY_HORDE_SCALAR",
"info": "A scaling factor that determines how many zombies are spawned in cites, multiplied by city size, when city hordes are indicated.",
"stype": "float",
"value": 80.0
},
{
"type": "EXTERNAL_OPTION",
"name": "SPAWN_ANIMAL_DENSITY",
Expand Down
5 changes: 4 additions & 1 deletion src/do_turn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,10 @@ bool do_turn()

// Move hordes every 2.5 min
if( calendar::once_every( time_duration::from_minutes( 2.5 ) ) ) {
overmap_buffer.move_hordes();

if( get_option<bool>( "WANDER_SPAWNS" ) ) {
overmap_buffer.move_hordes();
}
if( u.has_trait( trait_HAS_NEMESIS ) ) {
overmap_buffer.move_nemesis();
}
Expand Down
99 changes: 97 additions & 2 deletions src/overmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5273,8 +5273,7 @@ void overmap::place_cities()

tripoint_om_omt p;
city tmp;


tmp.pos_om = pos();
if( use_random_cities ) {
// randomly make some cities smaller or larger
int size = rng( op_city_size - 1, max_city_size );
Expand Down Expand Up @@ -6661,6 +6660,102 @@ void overmap::place_specials( overmap_special_batch &enabled_specials )

void overmap::place_mongroups()
{
// Cities can be full of zombies
int city_spawn_threshold = get_option<int>( "SPAWN_CITY_HORDE_THRESHOLD" );
if( city_spawn_threshold > -1 ) {
int city_spawn_chance = get_option<int>( "SPAWN_CITY_HORDE_SMALL_CITY_CHANCE" );
float city_spawn_scalar = get_option<float>( "SPAWN_CITY_HORDE_SCALAR" );
float city_spawn_spread = get_option<float>( "SPAWN_CITY_HORDE_SPREAD" );
float spawn_density = get_option<float>( "SPAWN_DENSITY" );

for( city &elem : cities ) {
if( elem.size > city_spawn_threshold || !one_in( city_spawn_chance ) ) {

// with the default numbers (80 scalar, 1 density), a size 16 city
// will produce 1280 zombies.
int desired_zombies = elem.size * city_spawn_scalar * spawn_density;

float city_effective_radius = elem.size * city_spawn_spread;

int city_distance_increment = std::ceil( city_effective_radius / 4 );

tripoint_abs_omt city_center = project_combine( elem.pos_om, tripoint_om_omt( elem.pos, 0 ) );

std::vector<tripoint_abs_sm> submap_list;

// gather all of the points in range to test for viable placement of hordes.
for( tripoint_om_omt const &temp_omt : points_in_radius( tripoint_om_omt( elem.pos, 0 ),
static_cast<int>( city_effective_radius ), 0 ) ) {

// running too close to the edge of the overmap can get us cascading mapgen
if( inbounds( temp_omt, 2 ) ) {

tripoint_abs_omt target_omt = project_combine( elem.pos_om, temp_omt );

// right now we're only placing city horde spawns on roads, for simplicity.
// this can be replaced with an OMT flag for later for better flexibility.
if( overmap_buffer.ter( target_omt )->get_type_id() == oter_type_road ) {
tripoint_abs_sm this_sm = project_to<coords::sm>( target_omt );

// for some reason old style spawns are submap-aligned.
// get all four quadrants for better distribution.
std::vector<tripoint_abs_sm> local_sm_list;
local_sm_list.push_back( this_sm );
local_sm_list.push_back( this_sm + point_east );
local_sm_list.push_back( this_sm + point_south );
local_sm_list.push_back( this_sm + point_south_east );

// shuffle, then prune submaps based on distance from city center
// this should let us concentrate hordes closer to the center.
// the shuffling is so they aren't all aligned consistently.
int new_size = 4 - ( trig_dist( target_omt, city_center ) / city_distance_increment );
if( new_size > 0 ) {
std::shuffle( local_sm_list.begin(), local_sm_list.end(), rng_get_engine() );
local_sm_list.resize( new_size );

submap_list.insert( submap_list.end(), local_sm_list.begin(), local_sm_list.end() );
}

}
}
}

if( submap_list.empty() ) {
// somehow the city has no roads. this shouldn't happen.
add_msg_debug( debugmode::DF_OVERMAP,
"tried to add zombie hordes to city %s centered at omt %s, but there were no roads!",
elem.name, city_center.to_string_writable() );
continue;
}

add_msg_debug( debugmode::DF_OVERMAP, "adding %i zombies in hordes to city %s centered at omt %s.",
desired_zombies, elem.name, city_center.to_string_writable() );

// if there aren't enough roads, we'll just reuse them, re-shuffled.
while( desired_zombies > 0 ) {
std::shuffle( submap_list.begin(), submap_list.end(), rng_get_engine() );
for( tripoint_abs_sm const &s : submap_list ) {
if( desired_zombies <= 0 ) {
break;
}
mongroup m( GROUP_ZOMBIE, s, desired_zombies > 10 ? 10 : desired_zombies );

// with wander_spawns (aka wandering hordes) off, these become 'normal'
// zombie spawns and behave like ants, triffids, fungals, etc.
// they won't try very hard to get placed in the world, so there will
// probably be fewer zombies than expected.
m.horde = true;
if( get_option<bool>( "WANDER_SPAWNS" ) ) {
m.wander( *this );
}
add_mon_group( m );
desired_zombies -= 10;
}
}
}
}
}

if( get_option<bool>( "DISABLE_ANIMAL_CLASH" ) ) {
// Figure out where swamps are, and place swamp monsters
for( int x = 3; x < OMAPX - 3; x += 7 ) {
Expand Down
4 changes: 3 additions & 1 deletion src/overmap_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ static const oter_str_id oter_unexplored( "unexplored" );

static const oter_type_str_id oter_type_forest_trail( "forest_trail" );

static const trait_id trait_DEBUG_CLAIRVOYANCE( "DEBUG_CLAIRVOYANCE" );
static const trait_id trait_DEBUG_NIGHTVISION( "DEBUG_NIGHTVISION" );

#if defined(__ANDROID__)
Expand Down Expand Up @@ -783,7 +784,8 @@ static void draw_ascii(
ter_sym = "!";
} else if( blink && showhordes &&
overmap_buffer.get_horde_size( omp ) >= HORDE_VISIBILITY_SIZE &&
get_and_assign_los( los, player_character, omp, sight_points ) ) {
( get_and_assign_los( los, player_character, omp, sight_points ) ||
uistate.overmap_debug_mongroup || player_character.has_trait( trait_DEBUG_CLAIRVOYANCE ) ) ) {
// Display Hordes only when within player line-of-sight
ter_color = c_green;
ter_sym = overmap_buffer.get_horde_size( omp ) > HORDE_VISIBILITY_SIZE * 2 ? "Z" : "z";
Expand Down
6 changes: 4 additions & 2 deletions src/sdltiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@

static const oter_type_str_id oter_type_forest_trail( "forest_trail" );

static const trait_id trait_DEBUG_CLAIRVOYANCE( "DEBUG_CLAIRVOYANCE" );
static const trait_id trait_DEBUG_NIGHTVISION( "DEBUG_NIGHTVISION" );

//***********************************
Expand Down Expand Up @@ -891,7 +892,8 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt &center_abs_
const tripoint_abs_omt omp = origin + point( col, row );

const bool see = overmap_buffer.seen( omp );
const bool los = see && you.overmap_los( omp, sight_points );
const bool los = see && ( you.overmap_los( omp, sight_points ) || uistate.overmap_debug_mongroup ||
you.has_trait( trait_DEBUG_CLAIRVOYANCE ) );
// the full string from the ter_id including _north etc.
std::string id;
int rotation = 0;
Expand Down Expand Up @@ -937,7 +939,7 @@ void cata_tiles::draw_om( const point &dest, const tripoint_abs_omt &center_abs_
// a little bit of hardcoded fallbacks for hordes
if( find_tile_with_season( id ) ) {
// NOLINTNEXTLINE(cata-translate-string-literal)
draw_from_id_string( string_format( "overmap_horde_%d", horde_size ),
draw_from_id_string( string_format( "overmap_horde_%d", horde_size < 10 ? horde_size : 10 ),
omp.raw(), 0, 0, lit_level::LIT, false );
} else {
switch( horde_size ) {
Expand Down

0 comments on commit 1e7d45b

Please sign in to comment.