From c36abfdb99135582bc4bb1c0f2dd893a828873b1 Mon Sep 17 00:00:00 2001 From: Beatrice <83368538+SpaceDragon00@users.noreply.github.com> Date: Sun, 11 Jul 2021 09:23:19 -0400 Subject: [PATCH] Fixing Energy Gun Weapon Description Runtimes + Miscellaneous Weapon Description Fixes, Take 2 (#59778) Fixes a runtime issue cause by the possibility of loaded_projectile being null by changing how projectile stats are obtained on energy weapons, and adds a separate line for energy ammo types that deal stamina damage and regular damage to incorporate both damage types --- code/__HELPERS/global_lists.dm | 9 ++++++ code/_globalvars/misc.dm | 2 ++ code/datums/elements/weapon_description.dm | 9 +++--- code/game/objects/items.dm | 5 +--- code/game/objects/items/storage/secure.dm | 1 - .../structures/crates_lockers/closets.dm | 2 ++ .../projectiles/ammunition/_ammunition.dm | 28 +++++++++---------- .../boxes_magazines/_box_magazine.dm | 18 ++++++++++++ code/modules/projectiles/guns/ballistic.dm | 4 +-- code/modules/projectiles/guns/energy.dm | 20 ++++++++----- 10 files changed, 66 insertions(+), 32 deletions(-) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index f0e17c123f7..4023ef5c811 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -58,6 +58,8 @@ init_crafting_recipes(GLOB.crafting_recipes) + init_subtypes_w_path_keys(/obj/projectile, GLOB.proj_by_path_key) + /// Inits the crafting recipe list, sorting crafting recipe requirements in the process. /proc/init_crafting_recipes(list/crafting_recipes) for(var/path in subtypesof(/datum/crafting_recipe)) @@ -84,3 +86,10 @@ L+= path return L +/// Functions like init_subtypes, but uses the subtype's path as a key for easy access +/proc/init_subtypes_w_path_keys(prototype, list/L) + if(!istype(L)) + L = list() + for(var/path as anything in subtypesof(prototype)) + L[path] = new path() + return L diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index f67c4f68398..32cec5cd523 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -34,3 +34,5 @@ GLOBAL_VAR_INIT(glowshrooms, 0) /// If drones are blacklisted from certain sensitive machines GLOBAL_VAR_INIT(drone_machine_blacklist_enabled, TRUE) + +GLOBAL_LIST_EMPTY_TYPED(proj_by_path_key, /obj/projectile) // A list of projectile objects, which are keyed by their path diff --git a/code/datums/elements/weapon_description.dm b/code/datums/elements/weapon_description.dm index 0314e2a8d52..32f0e17282f 100644 --- a/code/datums/elements/weapon_description.dm +++ b/code/datums/elements/weapon_description.dm @@ -1,6 +1,7 @@ +#define HITS_TO_CRIT(damage) round(100 / damage, 0.1) /** * - * The purpose of this element is to widely provide the ability to examine an object and determine its damage, with the ability to add + * The purpose of this element is to widely provide the ability to examine an object and determine its stats, with the ability to add * additional notes or information based on type or other factors * */ @@ -42,7 +43,7 @@ /datum/element/weapon_description/proc/warning_label(obj/item/item, mob/user, list/examine_texts) SIGNAL_HANDLER - if(item.force >= 5 || item.throwforce >= 5 || item.override_notes || item.offensive_notes) /// Only show this tag for items that could feasibly be weapons, shields, or those that have special notes + if(item.force >= 5 || item.throwforce >= 5 || item.override_notes || item.offensive_notes || attached_proc) /// Only show this tag for items that could feasibly be weapons, shields, or those that have special notes examine_texts += span_notice("It appears to have an ever-updating bluespace warning label.") /** @@ -82,12 +83,12 @@ if(!source.override_notes) // Make sure not to divide by 0 on accident if(source.force > 0) - readout += "Our extensive research has shown that it takes a mere [span_warning("[round((100 / source.force), 0.1)]")] hit\s to beat down [victims[rand(1, victims.len)]] with no armor." + readout += "Our extensive research has shown that it takes a mere [span_warning("[HITS_TO_CRIT(source.force)] hit\s")] to beat down [victims[rand(1, victims.len)]] with no armor." else readout += "Our extensive research found that you couldn't beat anyone to death with this if you tried." if(source.throwforce > 0) - readout += "If you decide to throw this object instead, one will take [span_warning("[round((100 / source.throwforce), 0.1)]")] hit\s before collapsing." + readout += "If you decide to throw this object instead, one will take [span_warning("[HITS_TO_CRIT(source.throwforce)] hit\s")] before collapsing." else readout += "If you decide to throw this object instead, then you will have trouble damaging anything." if(source.armour_penetration > 0 || source.block_chance > 0) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d1cc20ab61a..9880ef2e03f 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -241,10 +241,7 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e qdel(X) return ..() -/* - * Adds the weapon_description element, which shows the warning label for especially dangerous objects. - * Made to be overridden by item subtypes that require specific notes outside of the scope of offensive_notes - */ +/// Adds the weapon_description element, which shows the 'warning label' for especially dangerous objects. Override this for item types with special notes. /obj/item/proc/add_weapon_description() AddElement(/datum/element/weapon_description) diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm index 5d588169eb6..4a6ce29fc93 100644 --- a/code/game/objects/items/storage/secure.dm +++ b/code/game/objects/items/storage/secure.dm @@ -167,7 +167,6 @@ icon_locking = "safeb" icon_sparking = "safespark" desc = "Excellent for securing things away from grubby hands." - force = 8 w_class = WEIGHT_CLASS_GIGANTIC anchored = TRUE density = FALSE diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 27b872efbe3..41b00f29a51 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -169,6 +169,8 @@ /obj/structure/closet/proc/take_contents() var/atom/L = drop_location() + if(!L) + return for(var/atom/movable/AM in L) if(AM != src && insert(AM) == LOCKER_FULL) // limit reached break diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm index 79bb0252798..5d4f5351bf6 100644 --- a/code/modules/projectiles/ammunition/_ammunition.dm +++ b/code/modules/projectiles/ammunition/_ammunition.dm @@ -65,20 +65,20 @@ * */ /obj/item/ammo_casing/proc/add_notes_ammo() - // Make sure there is actually something IN the casing - if(loaded_projectile) - var/list/readout = list("") - // No dividing by 0 - if(loaded_projectile.damage > 0) - readout += "Most monkeys our legal team subjected to these rounds succumbed to their wounds after [span_warning("[round(100 / (loaded_projectile.damage * pellets), 0.1)]")] discharge\s at point-blank, taking [span_warning("[pellets]")] shot\s per round" - if(loaded_projectile.stamina > 0) - readout += "[loaded_projectile.damage == 0 ? "Most Monkeys" : "More Fortunate Monkeys" ] collapsed from exhaustion after [span_warning("[round(100 / ((loaded_projectile.damage + loaded_projectile.stamina) * pellets), 0.1)]")] of these rounds" - if(loaded_projectile.damage == 0 && loaded_projectile.stamina == 0) - return "Our legal team has determined the offensive nature of these rounds to be esoteric" - return readout.Join("\n") // Sending over a single string, rather than the whole list - else - // Labels don't do well with extreme forces - return "The warning label was blown away..." + // Try to get a projectile to derive stats from + var/obj/projectile/exam_proj = GLOB.proj_by_path_key[projectile_type] + if(!istype(exam_proj) || pellets == 0) + return + + var/list/readout = list() + // No dividing by 0 + if(exam_proj.damage > 0) + readout += "Most monkeys our legal team subjected to these [span_warning(caliber)] rounds succumbed to their wounds after [span_warning("[HITS_TO_CRIT(exam_proj.damage * pellets)] shot\s")] at point-blank, taking [span_warning("[pellets] shot\s")] per round" + if(exam_proj.stamina > 0) + readout += "[!readout.len ? "Most monkeys" : "More fortunate monkeys"] collapsed from exhaustion after [span_warning("[HITS_TO_CRIT(exam_proj.stamina * pellets)] impact\s")] of these [span_warning("[caliber]")] rounds" + if(!readout.len) // Everything else failed, give generic text + return "Our legal team has determined the offensive nature of these [span_warning(caliber)] rounds to be esoteric" + return readout.Join("\n") // Sending over a single string, rather than the whole list /obj/item/ammo_casing/update_icon_state() icon_state = "[initial(icon_state)][loaded_projectile ? "-live" : null]" diff --git a/code/modules/projectiles/boxes_magazines/_box_magazine.dm b/code/modules/projectiles/boxes_magazines/_box_magazine.dm index c41972d7b3e..e2d7c1b0926 100644 --- a/code/modules/projectiles/boxes_magazines/_box_magazine.dm +++ b/code/modules/projectiles/boxes_magazines/_box_magazine.dm @@ -14,6 +14,7 @@ w_class = WEIGHT_CLASS_TINY throw_speed = 3 throw_range = 7 + override_notes = TRUE ///list containing the actual ammo within the magazine var/list/stored_ammo = list() ///type that the magazine will be searching for, rejects if not a subtype of @@ -41,6 +42,23 @@ if(!start_empty) top_off(starting=TRUE) +/obj/item/ammo_box/add_weapon_description() + AddElement(/datum/element/weapon_description, attached_proc = .proc/add_notes_box) + +/obj/item/ammo_box/proc/add_notes_box() + var/list/readout = list() + + if(caliber && max_ammo) // Text references a 'magazine' as only magazines generally have the caliber variable initialized + readout += "Up to [span_warning("[max_ammo] [caliber] rounds")] can be found within this magazine. \ + \nAccidentally discharging any of these projectiles may void your insurance contract." + + var/obj/item/ammo_casing/mag_ammo = get_round(TRUE) + + if(istype(mag_ammo)) + readout += "\n[mag_ammo.add_notes_ammo()]" + + return readout.Join("\n") + /** * top_off is used to refill the magazine to max, in case you want to increase the size of a magazine with VV then refill it at once * diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index d1854b3f255..ed49d65d0da 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -141,8 +141,8 @@ * */ /obj/item/gun/ballistic/proc/add_notes_ballistic() - if(magazine) // Make sure you have a magazine, thats where the warning is! - return "\nBe especially careful around this device, as it can be loaded with [span_warning("[magazine.caliber]")] rounds, which you can inspect for more information." + if(magazine) // Make sure you have a magazine, to get the notes from + return "\n[magazine.add_notes_box()]" else return "\nThe warning attached to the magazine is missing..." diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index b3a79d07c51..0a95c936784 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -59,19 +59,25 @@ * */ /obj/item/gun/energy/proc/add_notes_energy() - var/list/readout = list("") + var/list/readout = list() // Make sure there is something to actually retrieve - if(!ammo_type) + if(!ammo_type.len) return var/obj/projectile/exam_proj - readout += "Standard models of this projectile weapon have [span_warning("[ammo_type.len]")] mode\s" + readout += "\nStandard models of this projectile weapon have [span_warning("[ammo_type.len] mode\s")]" readout += "Our heroic interns have shown that one can theoretically stay standing after..." - for(var/obj/item/ammo_casing/energy/for_ammo in ammo_type) - exam_proj = for_ammo.loaded_projectile + for(var/obj/item/ammo_casing/energy/for_ammo as anything in ammo_type) + exam_proj = GLOB.proj_by_path_key[for_ammo?.projectile_type] + if(!istype(exam_proj)) + continue + if(exam_proj.damage > 0) // Don't divide by 0!!!!! - readout += "[span_warning("[round(100 / exam_proj.damage, 0.1)]")] shot\s on [span_warning("[for_ammo.select_name]")] mode before collapsing from [exam_proj.damage_type == STAMINA ? "immense pain" : "their wounds"]." + readout += "[span_warning("[HITS_TO_CRIT(exam_proj.damage)] shot\s")] on [span_warning("[for_ammo.select_name]")] mode before collapsing from [exam_proj.damage_type == STAMINA ? "immense pain" : "their wounds"]." + if(exam_proj.stamina > 0) // In case a projectile does damage AND stamina damage (Energy Crossbow) + readout += "[span_warning("[HITS_TO_CRIT(exam_proj.stamina)] shot\s")] on [span_warning("[for_ammo.select_name]")] mode before collapsing from immense pain." else - readout += "an infinite number of shots on [span_warning("[for_ammo.select_name] mode")]." + readout += "a theoretically infinite number of shots on [span_warning("[for_ammo.select_name]")] mode." + return readout.Join("\n") // Sending over the singular string, rather than the whole list /obj/item/gun/energy/ComponentInitialize()