Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions data/json/item_actions.json
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,11 @@
"id": "reveal_map",
"name": { "str": "Read" }
},
{
"type": "item_action",
"id": "sonar_scan",
"name": { "str": "Scan with sonar" }
},
{
"type": "item_action",
"id": "change_scent",
Expand Down
33 changes: 33 additions & 0 deletions data/json/items/tool/electronics.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,39 @@
"flags": [ "TRADER_AVOID" ],
"magazine_well": "250 ml"
},
{
"id": "sonar_device",
"type": "TOOL",
"category": "electronics",
"name": { "str": "handheld sonar" },
"description": "A rugged sonar unit with a compact transducer and display. Activate it to ping nearby underwater terrain and sketch what you find onto the overmap.",
"weight": "500 g",
"volume": "500 ml",
"price": "450 USD",
"price_postapoc": "15 USD",
"bashing": 2,
"material": [ "plastic", "steel" ],
"symbol": ";",
"color": "light_blue",
"ammo": "battery",
"charges_per_use": 100,
"use_action": "sonar_scan",
"magazines": [
[
"battery",
[
"light_battery_cell",
"light_plus_battery_cell",
"light_minus_battery_cell",
"light_atomic_battery_cell",
"light_minus_atomic_battery_cell",
"light_minus_disposable_cell",
"light_disposable_cell"
]
]
],
"magazine_well": "250 ml"
},
{
"id": "hand_crank_charger",
"type": "TOOL",
Expand Down
5 changes: 5 additions & 0 deletions data/json/main.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
local voltmeter = require("./voltmeter")
local nyctophobia = require("./nyctophobia")

local sonar = require("./sonar")
local slimepit = require("./slimepit")
local artifact_analyzer = require("./artifact_analyzer")
local lua_traits = require("./lua_traits")
Expand All @@ -9,5 +12,7 @@ local storage = game.mod_storage[game.current_mod]
mod.voltmeter = voltmeter
mod.slimepit = slimepit
mod.artifact_analyzer = artifact_analyzer
nyctophobia.register(mod)
sonar.register(mod)
mod.lua_traits = lua_traits
lua_traits.register(mod)
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
{ "item": "rope_30", "x": 9, "y": [ 13, 15 ], "chance": 30 },
{ "item": "rope_30", "x": 14, "y": [ 13, 15 ], "chance": 70 },
{ "item": "sea_scooter", "x": [ 14, 15 ], "y": [ 11, 16 ], "chance": 50 },
{ "item": "sonar_device", "x": [ 14, 15 ], "y": [ 11, 16 ], "chance": 50 },
{ "item": "sea_scooter", "x": [ 9, 10 ], "y": [ 11, 16 ], "chance": 50 }
],
"items": { "#": { "item": "fishing_items", "chance": 10 } },
Expand Down
1 change: 1 addition & 0 deletions data/json/preload.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ local storage = game.mod_storage[game.current_mod]
mod.storage = storage

game.iuse_functions["VOLTMETER"] = function(...) return mod.voltmeter.menu(...) end
game.iuse_functions["sonar_scan"] = function(...) return mod.sonar_scan(...) end
game.iuse_functions["ARTIFACT_ANALYZER"] = function(...) return mod.artifact_analyzer.menu(...) end
game.mapgen_functions["slimepit"] = function(...) return mod.slimepit.draw(...) end

Expand Down
58 changes: 58 additions & 0 deletions data/json/sonar.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
local sonar = {}

local underwater_patterns = {
"river",
"lake",
"lake_bed_lab",
"ocean",
"bay",
"sea",
"water",
"cargo_ship",
"shipwreck",
"sealab",
}

local function oter_id_to_string(oter_id)
if oter_id.str then return oter_id:str() end
if oter_id.str_id then return oter_id:str_id():str() end
return tostring(oter_id)
end

local function is_underwater_oter(oter_id)
local id_str = oter_id_to_string(oter_id)
for _, pattern in ipairs(underwater_patterns) do
if string.find(id_str, pattern, 1, true) then return true end
end
return false
end

sonar.register = function(mod)
mod.sonar_scan = function(who, item, pos)
local map = gapi.get_map()
local abs_ms = map:get_abs_ms(pos)
local center_omt = coords.ms_to_omt(abs_ms)
local radius = 7
local depth_steps = 5
local any_revealed = false
local start_omt = center_omt
if center_omt.z >= 0 and is_underwater_oter(overmapbuffer.ter(center_omt)) then
start_omt = Tripoint.new(center_omt.x, center_omt.y, center_omt.z - 1)
end
for depth_index = 0, depth_steps - 1 do
local scan_omt = Tripoint.new(start_omt.x, start_omt.y, start_omt.z - depth_index)
if not is_underwater_oter(overmapbuffer.ter(scan_omt)) then break end
if overmapbuffer.reveal(scan_omt, radius, is_underwater_oter) then any_revealed = true end
end

if any_revealed then
gapi.add_msg(locale.gettext("The sonar pulse maps nearby underwater terrain."))
else
gapi.add_msg(locale.gettext("The sonar pulse finds nothing new."))
end

return 1
end
end

return sonar
25 changes: 25 additions & 0 deletions data/json/vehicleparts/controls.json
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,31 @@
"flags": [ "VISION", "CAMERA", "CAMERA_CONTROL", "ENABLED_DRAINS_EPOWER", "SHOCK_RESISTANT" ],
"breaks_into": [ { "item": "e_scrap", "count": [ 4, 10 ] }, { "item": "plastic_chunk", "count": [ 2, 8 ] } ]
},
{
"type": "vehicle_part",
"id": "sonar_array",
"name": { "str": "sonar array" },
"symbol": "#",
"color": "light_blue",
"broken_symbol": "#",
"broken_color": "blue",
"damage_modifier": 15,
"durability": 150,
"description": "A set of sonar transducers and electronics used to scan underwater terrain. Activate it from the vehicle controls to reveal local underwater overmap tiles.",
"folded_volume": "2 L",
"item": "sonar_device",
"requirements": {
"install": { "skills": [ [ "mechanics", 3 ] ], "time": "60 m", "using": [ [ "vehicle_screw", 1 ] ] },
"removal": { "skills": [ [ "mechanics", 2 ] ], "time": "30 m", "using": [ [ "vehicle_screw", 1 ] ] },
"repair": {
"skills": [ [ "mechanics", 4 ] ],
"time": "60 m",
"using": [ [ "adhesive", 1 ], [ "vehicle_repair_electronics", 1 ] ]
}
},
"flags": [ "SONAR", "SHOCK_RESISTANT" ],
"breaks_into": [ { "item": "e_scrap", "count": [ 4, 8 ] }, { "item": "plastic_chunk", "count": [ 2, 6 ] } ]
},
{
"type": "vehicle_part",
"id": "omnicam",
Expand Down
6 changes: 6 additions & 0 deletions data/json/vehicleparts/vp_flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@
"context": [ "vehicle_part" ],
"info": "Armor plate. Will partially protect other components on the same frame from the shock damage of a distant collision but not from direct attacks."
},
{
"id": "SONAR",
"type": "json_flag",
"context": [ "vehicle_part" ],
"info": "This part can be activated to perform a sonar scan from the vehicle."
},
{
"id": "STABLE",
"type": "json_flag",
Expand Down
2 changes: 1 addition & 1 deletion data/json/vehicles/boats.json
Original file line number Diff line number Diff line change
Expand Up @@ -1560,7 +1560,7 @@
{ "x": -2, "y": 0, "parts": [ "battery_car", "alternator_car", "engine_inline4" ] },
{ "x": 3, "y": -1, "part": "halfboard_nw" },
{ "x": 3, "y": 0, "part": "halfboard_ne" },
{ "x": 1, "y": -1, "part": "minifridge" },
{ "x": 1, "y": -1, "parts": [ "minifridge", "sonar_array" ] },
{ "x": -1, "y": -1, "part": "trunk_floor" },
{ "x": -2, "y": 0, "part": "folding_seat" },
{ "x": -3, "y": 0, "part": "folding_seat" },
Expand Down
19 changes: 19 additions & 0 deletions src/catalua_bindings_overmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "catalua_bindings.h"
#include "catalua.h"
#include "catalua_bindings_utils.h"
#include "catalua_impl.h"
#include "catalua_luna.h"
#include "catalua_luna_doc.h"

Expand Down Expand Up @@ -172,6 +173,24 @@
overmap_buffer.set_seen( tripoint_abs_omt( p ), seen_val.value_or( true ) );
} );

DOC( "Reveal a square area around a center point on the overmap. Returns true if any new tiles were revealed." );
DOC( "Optional filter callback receives oter_id and should return true to reveal that tile." );
luna::set_fx( lib, "reveal",
[]( const tripoint & center, int radius,
sol::optional<sol::protected_function> filter_fn ) -> bool {
if( filter_fn.has_value() )
{
auto filter = filter_fn.value();

Check warning on line 183 in src/catalua_bindings_overmap.cpp

View workflow job for this annotation

GitHub Actions / build

the variable 'filter' is copy-constructed from a const reference but is only used as const reference; consider making it a const reference [performance-unnecessary-copy-initialization]
const auto wrapped_filter = [filter]( const oter_id & ter ) -> bool {
sol::protected_function_result res = filter( ter );
check_func_result( res );
return res.get<bool>();
};
return overmap_buffer.reveal( tripoint_abs_omt( center ), radius, wrapped_filter );
}
return overmap_buffer.reveal( tripoint_abs_omt( center ), radius );
} );

DOC( "Check if the terrain at the given position has been explored by the player. Returns boolean." );
luna::set_fx( lib, "is_explored",
[]( const tripoint & p ) -> bool {
Expand Down
11 changes: 10 additions & 1 deletion src/vehicle_use.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@
static const itype_id itype_fungal_seeds( "fungal_seeds" );
static const itype_id itype_hotplate( "hotplate" );
static const itype_id itype_marloss_seed( "marloss_seed" );
static const auto itype_sonar_device = itype_id( "sonar_device" );
static const itype_id itype_water( "water" );
static const itype_id itype_water_clean( "water_clean" );
static const itype_id itype_water_purifier( "water_purifier" );
static const itype_id itype_welder( "welder" );

Check warning on line 83 in src/vehicle_use.cpp

View workflow job for this annotation

GitHub Actions / build

Variable 'itype_welder' declared but not used. [cata-unused-statics]

static const efftype_id effect_harnessed( "harnessed" );
static const efftype_id effect_tied( "tied" );
Expand Down Expand Up @@ -121,13 +122,13 @@
bool allow = true;

// determine target state - currently parts of similar type are all switched concurrently
bool state = std::none_of( found.begin(), found.end(), []( const vpart_reference & vp ) {

Check warning on line 125 in src/vehicle_use.cpp

View workflow job for this annotation

GitHub Actions / build

use a ranges version of this algorithm [modernize-use-ranges]
return vp.part().enabled;
} );

// if toggled part potentially usable check if could be enabled now (sufficient fuel etc.)
if( state ) {
allow = std::any_of( found.begin(), found.end(), []( const vpart_reference & vp ) {

Check warning on line 131 in src/vehicle_use.cpp

View workflow job for this annotation

GitHub Actions / build

use a ranges version of this algorithm [modernize-use-ranges]
return vp.vehicle().can_enable( vp.part() );
} );
}
Expand Down Expand Up @@ -230,7 +231,7 @@
pmenu.query();

if( pmenu.ret >= 0 ) {
if( pmenu.ret < static_cast<int>( doors_with_motors.size() ) ) {

Check warning on line 234 in src/vehicle_use.cpp

View workflow job for this annotation

GitHub Actions / build

comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
int part = doors_with_motors[pmenu.ret];
open_or_close( part, !( parts[part].open ) );
} else if( pmenu.ret < ( static_cast<int>( doors_with_motors.size() ) + CANCEL ) ) {
Expand Down Expand Up @@ -1174,7 +1175,7 @@

void vehicle::start_engines( const bool take_control, const bool autodrive )
{
bool has_engine = std::any_of( engines.begin(), engines.end(), [&]( int idx ) {

Check warning on line 1178 in src/vehicle_use.cpp

View workflow job for this annotation

GitHub Actions / build

use a ranges version of this algorithm [modernize-use-ranges]
return parts[ idx ].enabled && !parts[ idx ].is_broken();
} );

Expand Down Expand Up @@ -1281,7 +1282,7 @@

int seed_index = iexamine::query_seed( seed_entries );

if( seed_index > 0 && seed_index < static_cast<int>( seed_entries.size() ) ) {

Check warning on line 1285 in src/vehicle_use.cpp

View workflow job for this annotation

GitHub Actions / build

comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison]
const int count = std::get<2>( seed_entries[seed_index] );
int amount = 0;
const std::string popupmsg = string_format( _( "Move how many? [Have %d] (0 to cancel)" ), count );
Expand Down Expand Up @@ -1429,7 +1430,7 @@
}
// Can't use item_stack::only_item() since there might be fertilizer
map_stack items = g->m.i_at( reaper_pos );
map_stack::iterator seed = std::find_if( items.begin(), items.end(), []( const item * const & it ) {

Check warning on line 1433 in src/vehicle_use.cpp

View workflow job for this annotation

GitHub Actions / build

use a ranges version of this algorithm [modernize-use-ranges]
return it->is_seed();
} );
if( seed == items.end() || ( *seed )->typeId() == itype_fungal_seeds ||
Expand Down Expand Up @@ -1886,11 +1887,12 @@
const bool has_planter = avail_part_with_feature( interact_part, "PLANTER", true ) >= 0;
const int door_lock_part = avail_part_with_feature( interact_part, "DOOR_LOCKING", true );
const bool has_door_lock = door_lock_part >= 0;
const bool has_sonar = avail_part_with_feature( interact_part, "SONAR", true ) >= 0;

enum {
EXAMINE, TRACK, HANDBRAKE, CONTROL, CONTROL_ELECTRONICS, GET_ITEMS, GET_ITEMS_ON_GROUND, FOLD_VEHICLE, UNLOAD_TURRET,
RELOAD_TURRET, USE_HOTPLATE, FILL_CONTAINER, DRINK, USE_CRAFTER, USE_PURIFIER, PURIFY_TANK, USE_AUTOCLAVE, USE_AUTODOC,
USE_MONSTER_CAPTURE, USE_BIKE_RACK, USE_HARNESS, RELOAD_PLANTER, USE_TOWEL, PEEK_CURTAIN, PICK_LOCK
USE_MONSTER_CAPTURE, USE_BIKE_RACK, USE_HARNESS, RELOAD_PLANTER, USE_TOWEL, USE_SONAR, PEEK_CURTAIN, PICK_LOCK
};
uilist selectmenu;

Expand Down Expand Up @@ -1964,6 +1966,9 @@
if( has_planter ) {
selectmenu.addentry( RELOAD_PLANTER, true, 's', _( "Reload seed drill with seeds" ) );
}
if( has_sonar && fuel_left( itype_battery, true ) > 0 ) {
selectmenu.addentry( USE_SONAR, true, 'S', _( "Activate sonar" ) );
}

int choice;
if( selectmenu.entries.size() == 1 ) {
Expand Down Expand Up @@ -2017,6 +2022,10 @@
iuse::towel_common( &you, nullptr, false );
return;
}
case USE_SONAR: {
veh_tool( itype_sonar_device );
return;
}
case USE_AUTOCLAVE: {
iexamine::autoclave_empty( you, pos );
return;
Expand Down
Loading