From 9666ad5d6371c34a050cbe3f2c3ef8de7ea8a11f Mon Sep 17 00:00:00 2001 From: GuardianDll Date: Thu, 27 Jun 2024 00:33:00 +0200 Subject: [PATCH] refine calculations, add field for guns also, add debug tool to damage items --- data/json/items/tool/debug_tools.json | 65 +++++++++++++++++++++++++++ src/item_factory.cpp | 3 +- src/itype.h | 9 +++- src/ranged.cpp | 26 ++++++++--- 4 files changed, 95 insertions(+), 8 deletions(-) diff --git a/data/json/items/tool/debug_tools.json b/data/json/items/tool/debug_tools.json index f45d84ad27d84..755608eb9fdb7 100644 --- a/data/json/items/tool/debug_tools.json +++ b/data/json/items/tool/debug_tools.json @@ -11,5 +11,70 @@ "symbol": ";", "color": "light_gray", "use_action": [ "DBG_LUX_METER" ] + }, + { + "id": "debug_item_damager", + "type": "TOOL", + "category": "tools", + "name": { "str_sp": "debug item damager (simple)" }, + "description": "Deals 1 full bar of damage to an item you wield.", + "weight": "1 g", + "volume": "1 ml", + "material": [ "plastic" ], + "symbol": ";", + "color": "light_gray", + "use_action": { + "type": "effect_on_conditions", + "menu_text": "Damage item", + "effect_on_conditions": [ + { + "id": "EOC_FIND_ITEM_simple", + "effect": { + "u_run_inv_eocs": "all", + "search_data": [ { "wielded_only": true } ], + "true_eocs": { + "id": "EOC_DAMAGE_ITEM_simple", + "effect": [ + { "math": [ "_hp_before", "=", "n_hp('ALL')" ] }, + { "math": [ "n_hp('ALL')", "-=", "1000" ] }, + { "math": [ "_hp_after", "=", "n_hp('ALL')" ] }, + { "u_message": " have had hp, now has hp." } + ] + } + } + } + ] + } + }, + { + "id": "debug_item_damager_adv", + "type": "TOOL", + "category": "tools", + "name": { "str_sp": "debug item damager (advanced)" }, + "description": "Deals damage to items you pick.", + "weight": "1 g", + "volume": "1 ml", + "material": [ "plastic" ], + "symbol": ";", + "color": "light_gray", + "use_action": { + "type": "effect_on_conditions", + "menu_text": "Damage item", + "effect_on_conditions": [ + { + "id": "EOC_FIND_ITEM", + "effect": { + "u_run_inv_eocs": "manual_mult", + "true_eocs": { + "id": "EOC_DAMAGE_ITEM", + "effect": [ + { "math": [ "n_hp('ALL')", "-=", "num_input('Amount of damage, 1000 is one bar of damage.', 1000)" ] }, + { "u_message": "Dealt damage to all items." } + ] + } + } + } + ] + } } ] diff --git a/src/item_factory.cpp b/src/item_factory.cpp index f12a9dc4b0e3b..0239489a98936 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -2839,6 +2839,7 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin assign( jo, "heat_per_shot", slot.heat_per_shot, strict, 0.0 ); assign( jo, "cooling_value", slot.cooling_value, strict, 0.0 ); assign( jo, "overheat_threshold", slot.overheat_threshold, strict, -1.0 ); + optional(jo, false, "gun_fail_to_feed_chance", slot.gun_fail_to_feed_chance, 0.00027 ); if( jo.has_array( "valid_mod_locations" ) ) { slot.valid_mod_locations.clear(); @@ -3571,7 +3572,7 @@ void Item_factory::load( islot_magazine &slot, const JsonObject &jo, const std:: assign( jo, "count", slot.count, strict, 0 ); assign( jo, "default_ammo", slot.default_ammo, strict ); assign( jo, "reload_time", slot.reload_time, strict, 0 ); - assign( jo, "mag_jam_odds", slot.mag_jam_odds, strict, 0, 1000 ); + optional(jo, false, "mag_fail_to_feed_chance", slot.mag_fail_to_feed_chance, 0.00053 ); assign( jo, "linkage", slot.linkage, strict ); } diff --git a/src/itype.h b/src/itype.h index 938d1549fdc9f..68f2cecd8e7c8 100644 --- a/src/itype.h +++ b/src/itype.h @@ -787,6 +787,11 @@ struct islot_gun : common_ranged_data { */ double overheat_threshold = -1.0; + /** + * Chance for the gun to fail to feed. + */ + double gun_fail_to_feed_chance = 0.00027; + std::map> cached_ammos; /** @@ -945,8 +950,8 @@ struct islot_magazine { /** How long it takes to load each unit of ammo into the magazine */ int reload_time = 100; - /** Permille for the gun to jam, usually due the size of the magazine*/ - int mag_jam_odds = 0; + /** Permille for the gun to fail to feed, usually due the size of the magazine*/ + double mag_fail_to_feed_chance = 0.00053 ; /** For ammo belts one linkage (of given type) is dropped for each unit of ammo consumed */ std::optional linkage; diff --git a/src/ranged.cpp b/src/ranged.cpp index 250b5104d500f..25f3cc8343cbc 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -675,6 +675,20 @@ bool Character::handle_gun_damage( item &it ) return false; } + + double mag_ftf_chance = 0.0; + double mag_damage = 0.0; + if (it.magazine_current()) { + mag_ftf_chance = it.magazine_current()->type->magazine->mag_fail_to_feed_chance; + mag_damage = it.magazine_current()->damage() / 1000.0; + } + const double gun_damage = it.damage() / 1000.0; + const double gun_ftf_chance = firing.gun_fail_to_feed_chance; + + const double jam_chance = (mag_ftf_chance + gun_ftf_chance) * std::pow(2, (gun_damage * 1.75) + (mag_damage * 2)); + + add_msg_debug(debugmode::DF_RANGED, "Gun fail to feed chance: %g\nMagazine fail to feed chance: %g\nGun damage level: %g\nMagazine damage level: %g\nFail to feed chance: %g%%", gun_ftf_chance, mag_ftf_chance, gun_damage, mag_damage, jam_chance * 100); + // Here we check if we're underwater and whether we should misfire. // As a result this causes no damage to the firearm, note that some guns are waterproof // and so are immune to this effect, note also that WATERPROOF_GUN status does not @@ -690,14 +704,16 @@ bool Character::handle_gun_damage( item &it ) // effect as current guns have a durability between 5 and 9 this results in // a chance of mechanical failure between 1/(64*3) and 1/(1024*3) on any given shot. // the malfunction can't cause damage - } else if( one_in( ( 2 << effective_durability ) * 3 ) && !it.has_flag( flag_NEVER_JAMS ) ) { - add_msg_player_or_npc( _( "Your %s malfunctions!" ), - _( "'s %s malfunctions!" ), - it.tname() ); + } + else if (one_in((2 << effective_durability) * 3) && !it.has_flag(flag_NEVER_JAMS)) { + add_msg_player_or_npc(_("Your %s malfunctions!"), + _("'s %s malfunctions!"), + it.tname()); return false; // Here we check for a chance for the weapon to suffer a failure to feed // usually caused by the magazine size or condition - else if ( x_in_y( it.magazine_current()->type->magazine->mag_jam_odds, 1000 )) { + } + else if (x_in_y(jam_chance, 1 )) { add_msg_player_or_npc(_("Your %s didn't load into the chamber!"), _("'s %s didn't load into the chamber!"), it.tname());