Skip to content

Commit

Permalink
feat: add SHATTERS flag for non-glass items that can shatter on imp…
Browse files Browse the repository at this point in the history
…act (#4717)

* commit for remote

* finish up implementation

* style(autofix.ci): automated formatting

* Update item.cpp

* Update iteminfo_test.cpp

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
chaosvolt and autofix-ci[bot] authored Jun 8, 2024
1 parent 5277097 commit 182e5cf
Show file tree
Hide file tree
Showing 19 changed files with 52 additions and 20 deletions.
5 changes: 5 additions & 0 deletions data/json/flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -1826,6 +1826,11 @@
"type": "json_flag",
"context": [ ]
},
{
"id": "SHATTERS",
"type": "json_flag",
"context": [ ]
},
{
"id": "SHOCKING",
"type": "json_flag",
Expand Down
1 change: 1 addition & 0 deletions data/json/items/ammo.json
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@
"dispersion": 12,
"loudness": 0,
"count": 40,
"flags": [ "SHATTERS" ],
"effects": [ "NEVER_MISFIRES" ]
},
{
Expand Down
6 changes: 4 additions & 2 deletions data/json/items/containers.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@
"contains": "250 ml",
"seals": true,
"watertight": true,
"qualities": [ [ "BOIL", 2 ], [ "CONTAIN", 1 ] ]
"qualities": [ [ "BOIL", 2 ], [ "CONTAIN", 1 ] ],
"flags": [ "SHATTERS" ]
},
{
"id": "box_cigarette",
Expand Down Expand Up @@ -619,7 +620,8 @@
"contains": "250 ml",
"seals": true,
"watertight": true,
"qualities": [ [ "BOIL", 2 ], [ "CONTAIN", 1 ] ]
"qualities": [ [ "BOIL", 2 ], [ "CONTAIN", 1 ] ],
"flags": [ "SHATTERS" ]
},
{
"id": "clay_hydria",
Expand Down
3 changes: 2 additions & 1 deletion data/json/items/generic.json
Original file line number Diff line number Diff line change
Expand Up @@ -2785,7 +2785,8 @@
"bashing": 1,
"material": "clay",
"symbol": ")",
"color": "brown"
"color": "brown",
"flags": [ "SHATTERS" ]
},
{
"id": "plastic_pot_flower",
Expand Down
6 changes: 4 additions & 2 deletions data/json/items/generic/dining_kitchen.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
"weight": "322 g",
"volume": "250 ml",
"bashing": 3,
"to_hit": -1
"to_hit": -1,
"flags": [ "SHATTERS" ]
},
{
"id": "base_glass_dish",
Expand Down Expand Up @@ -382,7 +383,8 @@
"weight": "650 g",
"volume": "2 L",
"bashing": 4,
"container_data": { "contains": "2 L", "watertight": true }
"container_data": { "contains": "2 L", "watertight": true },
"extend": { "flags": [ "SHATTERS" ] }
},
{
"type": "GENERIC",
Expand Down
2 changes: 1 addition & 1 deletion data/json/items/resources/misc.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"name": { "str": "ceramic shard" },
"description": "A broken ceramic shard. It is heavy and has a somewhat sharp edge, but it's too irregular to cut properly.",
"material": "ceramic",
"flags": [ "TRADER_AVOID" ],
"flags": [ "TRADER_AVOID", "SHATTERS" ],
"weight": "750 g",
"volume": "250 ml",
"bashing": 5,
Expand Down
8 changes: 5 additions & 3 deletions data/json/items/tool/cooking.json
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@
"container_data": { "contains": "2 L", "watertight": true },
"qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "CHEM", 1 ] ],
"use_action": "HEAT_FOOD",
"flags": [ "ALLOWS_REMOTE_USE" ]
"flags": [ "ALLOWS_REMOTE_USE", "SHATTERS" ]
},
{
"id": "clay_quern",
Expand Down Expand Up @@ -220,7 +220,8 @@
"symbol": ")",
"color": "brown",
"container_data": { "contains": "750 ml", "watertight": true },
"qualities": [ [ "BOIL", 1 ] ]
"qualities": [ [ "BOIL", 1 ] ],
"flags": [ "SHATTERS" ]
},
{
"id": "coffeemaker",
Expand Down Expand Up @@ -444,7 +445,8 @@
"type": "delayed_transform",
"transform_age": 259200,
"not_ready_msg": "The yeast isn't done culturing yet."
}
},
"flags": [ "SHATTERS" ]
},
{
"id": "food_processor",
Expand Down
3 changes: 2 additions & 1 deletion data/json/items/tool/fishing.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"description": "This is a fish trap made from clay canisters, closely resembling old Japanese squid traps. It's simple, even primitive, but easy to use. The principle of action: the fish swims inside for bait, but can't get out. Not humane, prohibited by law, but there are no cops left to care.",
"weight": "1 kg",
"material": "clay",
"color": "brown"
"color": "brown",
"flags": [ "SHATTERS" ]
},
{
"id": "fishing_hook_basic",
Expand Down
2 changes: 2 additions & 0 deletions doc/src/content/docs/en/mod/json/reference/json_flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,8 @@ List of known flags, used in both `terrain.json` and `furniture.json`.
- `REDUCED_WEIGHT` ... Gunmod flag; reduces the item's base weight by 25%.
- `REQUIRES_TINDER` ... Requires tinder to be present on the tile this item tries to start a fire
on.
- `SHATTERS` ... This item can potentially shatter as if it as made of glass when used as a weapon,
thrown, bashed, etc.
- `SLEEP_AID` ... This item helps in sleeping.
- `SLEEP_IGNORE` ... This item is not shown as before-sleep warning.
- `SLOW_WIELD` ... Has an additional time penalty upon wielding. For melee weapons and guns this is
Expand Down
1 change: 1 addition & 0 deletions src/flag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ const flag_id flag_ROLLER_ONE( "ROLLER_ONE" );
const flag_id flag_ROLLER_QUAD( "ROLLER_QUAD" );
const flag_id flag_SAFECRACK( "SAFECRACK" );
const flag_id flag_SEMITANGIBLE( "SEMITANGIBLE" );
const flag_id flag_SHATTERS( "SHATTERS" );
const flag_id flag_SHOCKING( "SHOCKING" );
const flag_id flag_SILENT( "SILENT" );
const flag_id flag_SKINNED( "SKINNED" );
Expand Down
1 change: 1 addition & 0 deletions src/flag.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ extern const flag_id flag_ROLLER_ONE;
extern const flag_id flag_ROLLER_QUAD;
extern const flag_id flag_SAFECRACK;
extern const flag_id flag_SEMITANGIBLE;
extern const flag_id flag_SHATTERS;
extern const flag_id flag_SHOCKING;
extern const flag_id flag_SILENT;
extern const flag_id flag_SKINNED;
Expand Down
2 changes: 1 addition & 1 deletion src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5137,7 +5137,7 @@ bool game::forced_door_closing( const tripoint &p, const ter_id &door_type, int
it = items.erase( it );
continue;
}
if( ( *it )->made_of( material_id( "glass" ) ) && one_in( 2 ) ) {
if( ( ( *it )->can_shatter() ) && one_in( 2 ) ) {
if( can_see ) {
add_msg( m_warning, _( "A %s shatters!" ), ( *it )->tname() );
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/handle_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,8 +689,8 @@ static void smash()
}
}
item &weapon = u.primary_weapon();
if( weapon.made_of( material_id( "glass" ) ) &&
!query_yn( _( "Are you sure you want to smash with an item made of glass?" ) ) ) {
if( weapon.can_shatter() &&
!query_yn( _( "Are you sure you want to smash with an item that might shatter?" ) ) ) {
return;
}
const int move_cost = !u.is_armed() ? 80 : weapon.attack_cost() * 0.8;
Expand Down Expand Up @@ -794,7 +794,7 @@ static void smash()
u.practice( skill_melee, rng( 0, 1 ) * rng( 0, 1 ) );
}
const int vol = weapon.volume() / units::legacy_volume_factor;
if( weapon.made_of( material_id( "glass" ) ) &&
if( weapon.can_shatter() &&
rng( 0, vol + 3 ) < vol ) {
add_msg( m_bad, _( "Your %s shatters!" ), weapon.tname() );
weapon.spill_contents( u.pos() );
Expand Down
11 changes: 11 additions & 0 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3678,6 +3678,12 @@ void item::final_info( std::vector<iteminfo> &info, const iteminfo_query &parts_

insert_separation_line( info );

if( can_shatter() ) {
info.emplace_back( "BASE",
_( "* This item will potentially <info>shatter</info> if used as a weapon"
" or thrown, instantly <bad>destroying it and spilling any contents</bad>." ) );
}

if( parts->test( iteminfo_parts::BASE_RIGIDITY ) ) {
if( const islot_armor *armor = find_armor_data() ) {
if( !type->rigid ) {
Expand Down Expand Up @@ -5344,6 +5350,11 @@ int item::reach_range( const Character &guy ) const
return std::max( 1, res );
}

bool item::can_shatter() const
{
return made_of( material_id( "glass" ) ) || has_flag( flag_SHATTERS );
}

void item::unset_flags()
{
item_tags.clear();
Expand Down
3 changes: 3 additions & 0 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -1534,6 +1534,9 @@ class item : public location_visitable<item>, public game_object<item>
/**Does this item have the specified fault*/
bool has_fault( const fault_id &fault ) const;

/**If item made out of glass, or has the SHATTERS flag?*/
bool can_shatter() const;

/**
* @name Item properties
*
Expand Down
2 changes: 1 addition & 1 deletion src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3662,7 +3662,7 @@ bash_results map::bash_items( const tripoint &p, const bash_params &params )
bool smashed_glass = false;
for( auto bashed_item = bashed_items.begin(); bashed_item != bashed_items.end(); ) {
// the check for active suppresses Molotovs smashing themselves with their own explosion
if( ( *bashed_item )->made_of( material_id( "glass" ) ) && !( *bashed_item )->active &&
if( ( *bashed_item )->can_shatter() && !( *bashed_item )->active &&
one_in( 2 ) ) {
result.did_bash = true;
smashed_glass = true;
Expand Down
6 changes: 3 additions & 3 deletions src/melee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1823,7 +1823,7 @@ bool Character::block_hit( Creature *source, bodypart_id &bp_hit, damage_instanc
if( tec != tec_none && !is_dead_state() ) {
if( get_stamina() < get_stamina_max() / 3 ) {
add_msg( m_bad, _( "You try to counterattack but you are too exhausted!" ) );
} else if( primary_weapon().made_of( material_id( "glass" ) ) ) {
} else if( primary_weapon().can_shatter() ) {
add_msg( m_bad, _( "The item you are wielding is too fragile to counterattack with!" ) );
} else {
melee_attack( *source, false, &tec );
Expand Down Expand Up @@ -1922,8 +1922,8 @@ std::string Character::melee_special_effects( Creature &t, damage_instance &d, i
}

const int vol = weap.volume() / 250_ml;
// Glass weapons shatter sometimes
if( weap.made_of( material_id( "glass" ) ) &&
// Glass weapons and stuff with SHATTERS flag can shatter sometimes
if( weap.can_shatter() &&
/** @EFFECT_STR increases chance of breaking glass weapons (NEGATIVE) */
rng( 0, vol + 8 ) < vol + str_cur ) {
if( is_player() ) {
Expand Down
2 changes: 1 addition & 1 deletion src/ranged.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1213,7 +1213,7 @@ dealt_projectile_attack throw_item( Character &who, const tripoint &target,

// Item will shatter upon landing, destroying the item, dealing damage, and making noise
/** @EFFECT_STR increases chance of shattering thrown glass items (NEGATIVE) */
const bool shatter = !thrown.active && thrown.made_of( material_id( "glass" ) ) &&
const bool shatter = !thrown.active && thrown.can_shatter() &&
rng( 0, units::to_milliliter( 2_liter - volume ) ) < who.get_str() * 100;

// Item will burst upon landing, destroying the item, and spilling its contents
Expand Down
2 changes: 1 addition & 1 deletion tests/iteminfo_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ TEST_CASE( "food freshness and lifetime", "[item][iteminfo][food]" )
}

SECTION( "liquid food is stored in a container in a fridge" ) {
detached_ptr<item> food_item = item::in_container( itype_id( "glass" ),
detached_ptr<item> food_item = item::in_container( itype_id( "can_medium_unsealed" ),
item::spawn( itype_id( "milk" ) ) );
test_info_equals(
*food_item, q,
Expand Down

0 comments on commit 182e5cf

Please sign in to comment.