Skip to content

Commit 8e2f6b2

Browse files
committed
Implement guns being able to have flashlights, add one
1 parent e9b6db7 commit 8e2f6b2

File tree

13 files changed

+141
-16
lines changed

13 files changed

+141
-16
lines changed

data/json/items/gunmod/underbarrel.json

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,5 +616,62 @@
616616
"min_skills": [ [ "weapon", 2 ] ],
617617
"flags": [ "BIPOD", "SLOW_WIELD" ],
618618
"melee_damage": { "bash": 12 }
619+
},
620+
{
621+
"id": "mounted_flashlight",
622+
"type": "ITEM",
623+
"subtypes": [ "TOOL", "GUNMOD" ],
624+
"name": { "str": "mounted flashlight" },
625+
"description": "Precisely manufactured flashlight that can be mounted on any modern gun. You still can use it without attaching it to anything if you happen to never find a handheld one.",
626+
"weight": "68 g",
627+
"volume": "150 ml",
628+
"longest_side": "63 mm",
629+
"price": "350 USD",
630+
"price_postapoc": "4 USD",
631+
"install_time": "4 m",
632+
"material": [ "steel", "plastic" ],
633+
"symbol": ":",
634+
"color": "brown",
635+
"location": "underbarrel",
636+
"mod_targets": [ "shotgun", "smg", "rifle", "crossbow", "launcher" ],
637+
"min_skills": [ [ "weapon", 1 ] ],
638+
"charges_per_use": 1,
639+
"is_visible_when_installed": true,
640+
"use_action": {
641+
"type": "transform",
642+
"msg": "You turn the mounted flashlight on.",
643+
"target": "mounted_flashlight_on",
644+
"active": true,
645+
"need_charges": 1,
646+
"need_charges_msg": "The mounted flashlight's batteries are dead."
647+
},
648+
"pocket_data": [
649+
{
650+
"pocket_type": "MAGAZINE_WELL",
651+
"rigid": true,
652+
"flag_restriction": [ "BATTERY_LIGHT" ],
653+
"default_magazine": "light_battery_cell"
654+
}
655+
],
656+
"tool_ammo": [ "battery" ]
657+
},
658+
{
659+
"id": "mounted_flashlight_on",
660+
"copy-from": "mounted_flashlight",
661+
"type": "ITEM",
662+
"subtypes": [ "TOOL", "GUNMOD" ],
663+
"name": { "str": "mounted flashlight (on)", "str_pl": "mounted flashlights (on)" },
664+
"//": "about 1.5 h of work off a single battery",
665+
"power_draw": "2700 mW",
666+
"revert_to": "mounted_flashlight",
667+
"use_action": {
668+
"menu_text": "Turn off",
669+
"type": "transform",
670+
"msg": "You turn the mounted flashlight off.",
671+
"target": "mounted_flashlight",
672+
"ammo_scale": 0
673+
},
674+
"light": 160,
675+
"extend": { "flags": [ "CHARGEDIM", "TRADER_AVOID" ] }
619676
}
620677
]

doc/JSON/ITEM.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,7 @@ Guns can be defined like this:
855855
856856
Gun mods can be defined like this:
857857
858-
```C++
858+
```jsonc
859859
"type": "ITEM",
860860
"subtypes": [ "GUNMOD" ], // Allows the below GUNMOD fields to be read in addition to generic ITEM fields
861861
"location": "stock", // Mandatory. Where is this gunmod is installed?
@@ -891,14 +891,15 @@ Gun mods can be defined like this:
891891
"consume_divisor": 10, // Divide damage against mod by this amount (default 1)
892892
"handling_modifier": 4, // Improve gun handling. For example a forward grip might have 6, a bipod 18
893893
"mode_modifier": [ [ "AUTO", "auto", 4 ] ], // Modify firing modes of the gun, to give AUTO or REACH for example
894-
"barrel_length": "45 mm" // Specify a direct barrel length for this gun mod. If used only the first mod with a barrel length will be counted
894+
"barrel_length": "45 mm", // Specify a direct barrel length for this gun mod. If used only the first mod with a barrel length will be counted
895895
"overheat_threshold_modifier": 100, // Add a flat amount to gun's "overheat_threshold"; if the threshold is 100, and the modifier is 10, the result is 110; if the modifier is -25, the result is 75
896896
"overheat_threshold_multiplier": 1.5, // Multiply gun's "overheat_threshold" by this number; if the threshold is 100, and the multiplier is 1.5, the result is 150; if the multiplier is 0.8, the result is 80
897897
"cooling_value_modifier": 2, // Add a flat amount to gun's "cooling_value"; works the same as overheat_threshold_modifier
898898
"cooling_value_multiplier": 0.5, // Multiply gun's "cooling_value" by this number; works the same as overheat_threshold_multiplier
899899
"heat_per_shot_modifier": -2, // Add a flat amount to gun's "heat_per_shot"; works the same as overheat_threshold_modifier
900900
"heat_per_shot_multiplier": 2.0, // Multiply the gun's "heat_per_shot" by this number; works the same as overheat_threshold_multiplier
901901
"is_bayonet": true, // Optional, if true, the melee damage of this item is added to the base damage of the gun. Defaults to false.
902+
"is_visible_when_installed": false, // optional, if true, this gunmod is shown in your inventory akin to items in pockets, making it possible to interact with it in
902903
"blacklist_slot": [ "rail", "underbarrel" ], // prevents installation of the gunmod if the specified slot(s) are present on the gun.
903904
"blacklist_mod": [ "m203", "m320" ], // prevents installation of the gunmod if the specified mods(s) are present on the gun.
904905
"to_hit_mod": -1 // increases or decreases the item to_hit value

src/game.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2240,7 +2240,8 @@ int game::inventory_item_menu( item_location locThisItem,
22402240
int cMenu = static_cast<int>( '+' );
22412241

22422242
item &oThisItem = *locThisItem;
2243-
if( u.has_item( oThisItem ) ) {
2243+
// u.has_item(oThisItem) do not include mod pockets, where mounted flashlights are
2244+
if( /* u.has_item(oThisItem) */ true ) {
22442245
#if defined(__ANDROID__)
22452246
if( get_option<bool>( "ANDROID_INVENTORY_AUTOADD" ) ) {
22462247
add_key_to_quick_shortcuts( oThisItem.invlet, "INVENTORY", false );

src/game_inventory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ class pickup_inventory_preset : public inventory_selector_preset
532532
bool skip_wield_check = false, bool ignore_liquidcont = false ) : you( you ),
533533
skip_wield_check( skip_wield_check ), ignore_liquidcont( ignore_liquidcont ) {
534534
save_state = &pickup_sel_default_state;
535-
_pk_type = pocket_type::LAST;
535+
_pk_type = { pocket_type::LAST };
536536
}
537537

538538
std::string get_denial( const item_location &loc ) const override {

src/inventory_ui.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,9 +2049,14 @@ bool inventory_selector::add_contained_items( item_location &container, inventor
20492049
return false;
20502050
}
20512051

2052-
std::list<item *> const items = preset.get_pocket_type() == pocket_type::LAST
2053-
? container->all_items_top()
2054-
: container->all_items_top( preset.get_pocket_type() );
2052+
std::list<item *> items;
2053+
if( preset.get_pocket_type().size() == 1 && preset.has_pocket_type( pocket_type::LAST ) ) {
2054+
items = container->all_items_top();
2055+
} else {
2056+
for( const pocket_type pt : preset.get_pocket_type() ) {
2057+
items.splice( items.begin(), container->all_items_top( pt ) );
2058+
}
2059+
}
20552060

20562061
bool vis_top = false;
20572062
inventory_column temp( preset );

src/inventory_ui.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#ifndef CATA_SRC_INVENTORY_UI_H
33
#define CATA_SRC_INVENTORY_UI_H
44

5+
#include <algorithm>
56
#include <array>
67
#include <climits>
78
#include <cstddef>
@@ -23,20 +24,22 @@
2324
#include "cursesdef.h"
2425
#include "debug.h"
2526
#include "input_context.h"
27+
#include "item.h"
2628
#include "item_location.h"
29+
#include "itype.h"
2730
#include "memory_fast.h"
2831
#include "pimpl.h"
2932
#include "pocket_type.h"
3033
#include "point.h"
3134
#include "translations.h"
3235
#include "units.h"
36+
#include "value_ptr.h"
3337

3438
class Character;
3539
class JsonObject;
3640
class JsonOut;
3741
class basecamp;
3842
class inventory_selector_preset;
39-
class item;
4043
class item_category;
4144
class item_stack;
4245
class string_input_popup;
@@ -238,7 +241,10 @@ class inventory_selector_preset
238241
virtual ~inventory_selector_preset() = default;
239242

240243
/** Does this entry satisfy the basic preset conditions? */
241-
virtual bool is_shown( const item_location & ) const {
244+
virtual bool is_shown( const item_location &loc ) const {
245+
if( loc->is_gunmod() && !loc->type->gunmod->is_visible_when_installed ) {
246+
return false;
247+
}
242248
return true;
243249
}
244250

@@ -269,10 +275,14 @@ class inventory_selector_preset
269275
return check_components;
270276
}
271277

272-
pocket_type get_pocket_type() const {
278+
std::vector<pocket_type> get_pocket_type() const {
273279
return _pk_type;
274280
}
275281

282+
bool has_pocket_type( pocket_type pt ) const {
283+
return std::find( _pk_type.begin(), _pk_type.end(), pt ) != _pk_type.end();
284+
}
285+
276286
virtual std::function<bool( const inventory_entry & )> get_filter( const std::string &filter )
277287
const;
278288

@@ -307,7 +317,7 @@ class inventory_selector_preset
307317
bool _indent_entries = true;
308318
bool _collate_entries = false;
309319

310-
pocket_type _pk_type = pocket_type::CONTAINER;
320+
std::vector<pocket_type> _pk_type = { pocket_type::CONTAINER, pocket_type::MOD };
311321

312322
private:
313323
class cell_t

src/item.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10300,6 +10300,16 @@ std::vector<const item_pocket *> item::get_all_ablative_pockets() const
1030010300
return contents.get_all_ablative_pockets();
1030110301
}
1030210302

10303+
std::vector<const item_pocket *> item::get_all_contained_and_mod_pockets() const
10304+
{
10305+
return contents.get_all_contained_and_mod_pockets();
10306+
}
10307+
10308+
std::vector<item_pocket *> item::get_all_contained_and_mod_pockets()
10309+
{
10310+
return contents.get_all_contained_and_mod_pockets();
10311+
}
10312+
1030310313
item_pocket *item::contained_where( const item &contained )
1030410314
{
1030510315
return contents.contained_where( contained );
@@ -10536,7 +10546,7 @@ bool item::is_emissive() const
1053610546
return true;
1053710547
}
1053810548

10539-
for( const item_pocket *pkt : get_all_contained_pockets() ) {
10549+
for( const item_pocket *pkt : get_all_contained_and_mod_pockets() ) {
1054010550
if( pkt->transparent() ) {
1054110551
for( const item *it : pkt->all_items_top() ) {
1054210552
if( it->is_emissive() ) {
@@ -12715,7 +12725,16 @@ int item::getlight_emit() const
1271512725
float lumint = type->light_emission;
1271612726

1271712727
if( lumint == 0 ) {
12718-
return 0;
12728+
// gunmods can create light, but cache_visit_items_with() do not check items inside mod pockets
12729+
// we will check it here
12730+
if( is_gun() && !gunmods().empty() ) {
12731+
for( const item *maybe_flashlight : gunmods() ) {
12732+
if( maybe_flashlight->type->light_emission != 0 ) {
12733+
return maybe_flashlight->getlight_emit();
12734+
}
12735+
}
12736+
return 0;
12737+
}
1271912738
}
1272012739

1272112740
if( ammo_required() == 0 || ( has_flag( flag_USE_UPS ) && ammo_capacity( ammo_battery ) == 0 ) ||

src/item.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,8 @@ class item : public visitable
884884
std::vector<item_pocket *> get_all_standard_pockets();
885885
std::vector<item_pocket *> get_all_ablative_pockets();
886886
std::vector<const item_pocket *> get_all_ablative_pockets() const;
887+
std::vector<const item_pocket *> get_all_contained_and_mod_pockets() const;
888+
std::vector<item_pocket *> get_all_contained_and_mod_pockets();
887889
/**
888890
* Updates the pockets of this item to be correct based on the mods that are installed.
889891
* Pockets which are modified that contain an item will be spilled

src/item_contents.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2179,6 +2179,20 @@ std::vector<item_pocket *> item_contents::get_all_ablative_pockets()
21792179
} );
21802180
}
21812181

2182+
std::vector<const item_pocket *> item_contents::get_all_contained_and_mod_pockets() const
2183+
{
2184+
return get_pockets( []( item_pocket const & pocket ) {
2185+
return pocket.is_type( pocket_type::CONTAINER ) || pocket.is_type( pocket_type::MOD );
2186+
} );
2187+
}
2188+
2189+
std::vector<item_pocket *> item_contents::get_all_contained_and_mod_pockets()
2190+
{
2191+
return get_pockets( []( item_pocket const & pocket ) {
2192+
return pocket.is_type( pocket_type::CONTAINER ) || pocket.is_type( pocket_type::MOD );
2193+
} );
2194+
}
2195+
21822196
std::vector<const item *> item_contents::get_added_pockets() const
21832197
{
21842198
std::vector<const item *> items_added;
@@ -2585,7 +2599,7 @@ void item_contents::process( map &here, Character *carrier, const tripoint_bub_m
25852599
temperature_flag flag, float spoil_multiplier_parent, bool watertight_container )
25862600
{
25872601
for( item_pocket &pocket : contents ) {
2588-
if( pocket.is_type( pocket_type::CONTAINER ) ) {
2602+
if( pocket.is_type( pocket_type::CONTAINER ) || pocket.is_type( pocket_type::MOD ) ) {
25892603
pocket.process( here, carrier, pos, insulation, flag, spoil_multiplier_parent,
25902604
watertight_container );
25912605
}

src/item_contents.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ class item_contents
235235
std::vector<item_pocket *> get_all_standard_pockets();
236236
std::vector<const item_pocket *> get_all_ablative_pockets() const;
237237
std::vector<item_pocket *> get_all_ablative_pockets();
238+
std::vector<const item_pocket *> get_all_contained_and_mod_pockets() const;
239+
std::vector<item_pocket *> get_all_contained_and_mod_pockets();
238240
std::vector<const item_pocket *>
239241
get_pockets( std::function<bool( item_pocket const & )> const &filter ) const;
240242
std::vector<item_pocket *>

0 commit comments

Comments
 (0)