Skip to content

Commit

Permalink
Improve radio scanning experience, increase radios
Browse files Browse the repository at this point in the history
I've noticed we have this feature from poking around in the code, but
every time I've tried to use it, there haven't been any radios in range.

This commit does 4 things:
1. Increase both the min and max range of radios, so there's a greater
   chance a radio will be in range. Numbers semi-arbitrary.
2. Add a debugmode filter for radio, so I can add some debugging
   messages for it.
3. Save radio frequency, so your radio doesn't lose it's selected
   frequency every time you reload.
4. Make radio scanning better, and modify how noise is applied to radio
   messages.

While the current scanning is perhaps a little immersive, in actual use
it's quite annoying and, because it gives no feedback, it's hard to tell
if it actually did anything. Replace this with a list of stations in
range that you can select from, with a little descriptor describing how
much noise there is (the reason for the modification of the noise).
Messages are snippets to enable multiple options and ease of editing.
  • Loading branch information
anothersimulacrum committed Jul 24, 2022
1 parent 5ab7888 commit 16b67b7
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 29 deletions.
35 changes: 35 additions & 0 deletions data/json/snippets/radio.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,40 @@
"USS Eagle of Freedom to all callsigns. Operation Ocean 11 is in effect. Repeat. Operation Ocean 11 is in effect. Sir, this should effectively reach about 150 units, but there is no response from literally anyone in hours. Their coms winked out like candles in the wind. And how do we even secure the port to load anyone in?",
"Seagull 54 to USS Eagle of Freedom. It's as we predicted. Going down on last reserves of fuel, with dropping evacuated unit out of question at that point. This is our last call. Will try emergency landing at …kshssssssk… Don't send us a rescue team, we know the odds. Will be moving east towards the shore, and if we're not there in T minus 3 days, count us dead. Proud to serve the country. Over and out."
]
},
{
"type": "snippet",
"category": "radio_station_desc_noise_0",
"text": [ "It's quite clear." ]
},
{
"type": "snippet",
"category": "radio_station_desc_noise_20",
"text": [ "There's some noise, but you can make it out pretty well." ]
},
{
"type": "snippet",
"category": "radio_station_desc_noise_40",
"text": [ "There's a fair bit of noise, but you can occasionally make it out." ]
},
{
"type": "snippet",
"category": "radio_station_desc_noise_60",
"text": [ "There's a lot of noise, but you can make out something through it." ]
},
{
"type": "snippet",
"category": "radio_station_desc_noise_80",
"text": [ "You can barely make out a message through the noise." ]
},
{
"type": "snippet",
"category": "radio_station_desc_noise_max",
"text": [ "Only the occasional word escapes the static." ]
},
{
"type": "snippet",
"category": "radio_scan_no_stations",
"text": [ "You fiddle with the dial a bit, but there's only noise." ]
}
]
1 change: 1 addition & 0 deletions src/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ std::string filter_name( debug_filter value )
case DF_MONSTER: return "DF_MONSTER";
case DF_NPC: return "DF_NPC";
case DF_OVERMAP: return "DF_OVERMAP";
case DF_RADIO: return "DF_RADIO";
case DF_RANGED: return "DF_RANGED";
case DF_REQUIREMENTS_MAP: return "DF_REQUIREMENTS_MAP";
case DF_SOUND: return "DF_SOUND";
Expand Down
1 change: 1 addition & 0 deletions src/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ enum debug_filter : int {
DF_MONSTER, // monster generic
DF_NPC, // npc generic
DF_OVERMAP, // overmap generic
DF_RADIO, // radio stuff
DF_RANGED, // ranged generic
DF_REQUIREMENTS_MAP, // activity_item_handler requirements_map()
DF_SOUND, // sound generic
Expand Down
113 changes: 86 additions & 27 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2452,34 +2452,67 @@ cata::optional<int> iuse::directional_antenna( Character *p, item *it, bool, con
return it->type->charges_to_use();
}

// 0-100 percent chance of a character in a radio signal being obscured by static
static int radio_static_chance( const radio_tower_reference &tref )
{
constexpr int HALF_RADIO_MIN = RADIO_MIN_STRENGTH / 2;
const int signal_strength = tref.signal_strength;
const int max_strength = tref.tower->strength;
int dist = max_strength - signal_strength;
// For towers whose strength is quite close to the min, make them act as though they are farther away
if( RADIO_MIN_STRENGTH * 1.25 > max_strength ) {
dist += 25;
}
// When we're close enough, there's no noise
if( dist < HALF_RADIO_MIN ) {
return 0;
}
// There's minimal, but increasing noise when quite close to the signal
if( dist < RADIO_MIN_STRENGTH ) {
return lerp( 1, 20, static_cast<float>( dist - HALF_RADIO_MIN ) / HALF_RADIO_MIN );
}
// Otherwise, just a rapid increase until the signal stops
return lerp( 20, 100, static_cast<float>( dist - RADIO_MIN_STRENGTH ) /
( max_strength - RADIO_MIN_STRENGTH ) );
}

cata::optional<int> iuse::radio_on( Character *p, item *it, bool t, const tripoint &pos )
{
if( t ) {
// Normal use
std::string message = _( "Radio: Kssssssssssssh." );
const radio_tower_reference tref = overmap_buffer.find_radio_station( it->frequency );
add_msg_debug( debugmode::DF_RADIO, "Set freq: %d", it->frequency );
if( tref ) {
point_abs_omt dbgpos = project_to<coords::omt>( tref.abs_sm_pos );
add_msg_debug( debugmode::DF_RADIO, "found broadcast (str %d) at (%d %d)",
tref.signal_strength, dbgpos.x(), dbgpos.y() );
const radio_tower *selected_tower = tref.tower;
if( selected_tower->type == radio_type::MESSAGE_BROADCAST ) {
message = selected_tower->message;
} else if( selected_tower->type == radio_type::WEATHER_RADIO ) {
message = weather_forecast( tref.abs_sm_pos );
}

message = obscure_message( message, [&]()->int {
int signal_roll = dice( 10, tref.signal_strength * 3 );
int static_roll = dice( 10, 100 );
if( static_roll > signal_roll )
const city *c = overmap_buffer.closest_city( tripoint_abs_sm( tref.abs_sm_pos, 0 ) ).city;
const std::string cityname = c == nullptr ? "ksssh" : c->name;

replace_city_tag( message, cityname );
int static_chance = radio_static_chance( tref );
add_msg_debug( debugmode::DF_RADIO, "Message: '%s' at %d%% noise", message, static_chance );
message = obscure_message( message, [&static_chance]()->int {
if( x_in_y( static_chance, 100 ) )
{
if( static_roll < signal_roll * 1.1 && one_in( 4 ) ) {
// Gradually replace random characters with noise as distance increases
if( one_in( 3 ) && static_chance - rng( 0, 25 ) < 50 ) {
// Replace with random character
return 0;
} else {
return '#';
}
} else
{
return -1;
// Replace with '#'
return '#';
}
// Leave unchanged
return -1;
} );

std::vector<std::string> segments = foldstring( message, RADIO_PER_TURN );
Expand All @@ -2503,28 +2536,54 @@ cata::optional<int> iuse::radio_on( Character *p, item *it, bool t, const tripoi
} );
}

const auto tower_desc = []( const int noise ) {
if( noise == 0 ) {
return SNIPPET.random_from_category( "radio_station_desc_noise_0" )->translated();
} else if( noise <= 20 ) {
return SNIPPET.random_from_category( "radio_station_desc_noise_20" )->translated();
} else if( noise <= 40 ) {
return SNIPPET.random_from_category( "radio_station_desc_noise_40" )->translated();
} else if( noise <= 60 ) {
return SNIPPET.random_from_category( "radio_station_desc_noise_60" )->translated();
} else if( noise <= 80 ) {
return SNIPPET.random_from_category( "radio_station_desc_noise_80" )->translated();
}
return SNIPPET.random_from_category( "radio_station_desc_noise_max" )->translated();
};

switch( ch ) {
case 0: {
const int old_frequency = it->frequency;
const radio_tower *lowest_tower = nullptr;
const radio_tower *lowest_larger_tower = nullptr;
for( radio_tower_reference &tref : overmap_buffer.find_all_radio_stations() ) {
const int new_frequency = tref.tower->frequency;
if( new_frequency == old_frequency ) {
continue;
}
if( new_frequency > old_frequency &&
( lowest_larger_tower == nullptr || new_frequency < lowest_larger_tower->frequency ) ) {
lowest_larger_tower = tref.tower;
} else if( lowest_tower == nullptr || new_frequency < lowest_tower->frequency ) {
lowest_tower = tref.tower;
std::vector<radio_tower_reference> options = overmap_buffer.find_all_radio_stations();
if( options.empty() ) {
popup( SNIPPET.random_from_category( "radio_scan_no_stations" )->translated() );
}
uilist scanlist;
scanlist.title = _( "Select a station" );
scanlist.desc_enabled = true;
add_msg_debug( debugmode::DF_RADIO, "Radio scan:" );
for( size_t i = 0; i < options.size(); ++i ) {
std::string selected_text;
const radio_tower_reference &tref = options[i];
if( it->frequency == tref.tower->frequency ) {
selected_text = pgettext( "radio station", " (selected)" );
}
//~ Selected radio station, %d is a number in sequence (1,2,3...),
//~ %s is ' (selected)' if this is the radio station playing, else nothing
const std::string station_name = string_format( _( "Station %d%s" ), i + 1, selected_text );
const int noise_chance = radio_static_chance( tref );
scanlist.addentry_desc( i, true, MENU_AUTOASSIGN, station_name, tower_desc( noise_chance ) );
const point_abs_omt dbgpos = project_to<coords::omt>( tref.abs_sm_pos );
add_msg_debug( debugmode::DF_RADIO, " %d: %d at (%d %d) str [%d/%d]", i + 1, tref.tower->frequency,
dbgpos.x(), dbgpos.y(), tref.signal_strength, tref.tower->strength );
}
if( lowest_larger_tower != nullptr ) {
it->frequency = lowest_larger_tower->frequency;
} else if( lowest_tower != nullptr ) {
it->frequency = lowest_tower->frequency;
scanlist.query();
const int sel = scanlist.ret;
if( sel >= 0 && static_cast<size_t>( sel ) < options.size() ) {
it->frequency = options[sel].tower->frequency;
break;
}
// No selection made, don't tune to anything
it->frequency = 0;
}
break;
case 1:
Expand Down
4 changes: 2 additions & 2 deletions src/overmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ enum class radio_type : int {

extern std::map<radio_type, std::string> radio_type_names;

static constexpr int RADIO_MIN_STRENGTH = 80;
static constexpr int RADIO_MAX_STRENGTH = 200;
static constexpr int RADIO_MIN_STRENGTH = 120;
static constexpr int RADIO_MAX_STRENGTH = 360;

struct radio_tower {
// local (to the containing overmap) submap coordinates
Expand Down
3 changes: 3 additions & 0 deletions src/savegame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,8 @@ void overmap::unserialize( std::istream &fin )
jsin.read( new_radio.strength );
} else if( radio_member_name == "message" ) {
jsin.read( new_radio.message );
} else if( radio_member_name == "frequency" ) {
jsin.read( new_radio.frequency );
}
}
radios.push_back( new_radio );
Expand Down Expand Up @@ -1220,6 +1222,7 @@ void overmap::serialize( std::ostream &fout ) const
json.member( "strength", i.strength );
json.member( "type", radio_type_names[i.type] );
json.member( "message", i.message );
json.member( "frequency", i.frequency );
json.end_object();
}
json.end_array();
Expand Down

0 comments on commit 16b67b7

Please sign in to comment.