diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm index b6cc94584be..6e70a9b36b9 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm @@ -151,6 +151,10 @@ #define COMSIG_ATOM_FINALIZE_MATERIAL_EFFECTS "atom_finalize_material_effects" /// From /atom/finalize_remove_material_effects(): (list/materials, datum/material/main_material) #define COMSIG_ATOM_FINALIZE_REMOVE_MATERIAL_EFFECTS "atom_finalize_remove_material_effects" +/// /atom/proc/apply_single_mat_effect(): (datum/material/material, amount, multiplier) +#define COMSIG_ATOM_SINGLE_MATERIAL_EFFECT_APPLY "atom_single_material_effect_apply" +/// /atom/proc/remove_single_mat_effect(): (datum/material/material, amount, multiplier) +#define COMSIG_ATOM_SINGLE_MATERIAL_EFFECT_REMOVE "atom_single_material_effect_remove" /// From /atom/proc/update_atom_colour() : (color_changed) #define COMSIG_ATOM_COLOR_UPDATED "atom_color_updated" diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index f5e8f847a7c..3081b60449f 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -195,6 +195,7 @@ #define COMPONENT_BLOCK_SHARPEN_BLOCKED (1<<1) #define COMPONENT_BLOCK_SHARPEN_ALREADY (1<<2) #define COMPONENT_BLOCK_SHARPEN_MAXED (1<<3) + #define COMPONENT_BLOCK_SHARPEN_SHARPNESS (1<<4) ///Called when an armor plate is successfully applied to an object #define COMSIG_ARMOR_PLATED "armor_plated" diff --git a/code/datums/components/transforming.dm b/code/datums/components/transforming.dm index 81913616bd8..6c51d0d102d 100644 --- a/code/datums/components/transforming.dm +++ b/code/datums/components/transforming.dm @@ -24,6 +24,16 @@ var/sharpness_on /// Hitsound played when active var/hitsound_on + /// Force when the weapon is inactive + var/force_off + /// Throwforce when the weapon is inactive + var/throwforce_off + /// Throw speed of the weapon when inactive + var/throw_speed_off + /// Weight class of the weapon when inactive + var/w_class_off + /// The sharpness of the weapon when inactive + var/sharpness_off /// List of the original continuous attack verbs the item has. var/list/attack_verb_continuous_off /// List of the original simple attack verbs the item has. @@ -75,6 +85,12 @@ src.clumsy_damage = clumsy_damage src.inhand_icon_change = inhand_icon_change + src.force_off = item_parent.force + src.throwforce_off = item_parent.throwforce + src.throw_speed_off = item_parent.throw_speed + src.sharpness_off = item_parent.sharpness // Raw value, not via the getter + src.w_class_off = item_parent.w_class + if(attack_verb_continuous_on) src.attack_verb_continuous_on = attack_verb_continuous_on attack_verb_continuous_off = item_parent.attack_verb_continuous @@ -95,6 +111,10 @@ RegisterSignal(parent, COMSIG_DETECTIVE_SCANNED, PROC_REF(on_scan)) RegisterSignal(parent, COMSIG_ITEM_APPLY_FANTASY_BONUSES, PROC_REF(apply_fantasy_bonuses)) RegisterSignal(parent, COMSIG_ITEM_REMOVE_FANTASY_BONUSES, PROC_REF(remove_fantasy_bonuses)) + RegisterSignal(parent, COMSIG_ATOM_FINALIZE_MATERIAL_EFFECTS, PROC_REF(on_materials_updated)) + RegisterSignal(parent, COMSIG_ATOM_FINALIZE_REMOVE_MATERIAL_EFFECTS, PROC_REF(on_materials_updated)) + RegisterSignal(parent, COMSIG_ATOM_SINGLE_MATERIAL_EFFECT_APPLY, PROC_REF(on_material_apply)) + RegisterSignal(parent, COMSIG_ATOM_SINGLE_MATERIAL_EFFECT_REMOVE, PROC_REF(on_material_remove)) /datum/component/transforming/proc/apply_fantasy_bonuses(obj/item/source, bonus) SIGNAL_HANDLER @@ -110,9 +130,38 @@ force_on = source.reset_fantasy_variable("force_on", force_on) throwforce_on = source.reset_fantasy_variable("throwforce_on", throwforce_on) +/datum/component/transforming/proc/on_material_apply(obj/item/source, datum/material/material, amount, multiplier) + SIGNAL_HANDLER + // Opposite state's force needs to be calculated for each material's effect + if (active) + force_off *= GET_MATERIAL_MODIFIER(source.get_material_force_modifier(material, initial(source.sharpness)), multiplier) + throwforce_off *= GET_MATERIAL_MODIFIER(source.get_material_throwforce_modifier(material, initial(source.sharpness)), multiplier) + else + force_on *= GET_MATERIAL_MODIFIER(source.get_material_force_modifier(material, sharpness_on), multiplier) + throwforce_on *= GET_MATERIAL_MODIFIER(source.get_material_throwforce_modifier(material, sharpness_on), multiplier) + +/datum/component/transforming/proc/on_material_remove(obj/item/source, datum/material/material, amount, multiplier) + SIGNAL_HANDLER + // Same as appliation but inversed + if (active) + force_off /= GET_MATERIAL_MODIFIER(source.get_material_force_modifier(material, initial(source.sharpness)), multiplier) + throwforce_off /= GET_MATERIAL_MODIFIER(source.get_material_throwforce_modifier(material, initial(source.sharpness)), multiplier) + else + force_on /= GET_MATERIAL_MODIFIER(source.get_material_force_modifier(material, sharpness_on), multiplier) + throwforce_on /= GET_MATERIAL_MODIFIER(source.get_material_throwforce_modifier(material, sharpness_on), multiplier) + +/datum/component/transforming/proc/on_materials_updated(obj/item/source, list/materials, datum/material/main_material) + SIGNAL_HANDLER + // Current force can be set directly + if (active) + force_on = source.force + throwforce_on = source.throwforce + else + force_off = source.force + throwforce_off = source.throwforce /datum/component/transforming/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_ITEM_ATTACK_SELF, COMSIG_ITEM_SHARPEN_ACT, COMSIG_DETECTIVE_SCANNED)) + UnregisterSignal(parent, list(COMSIG_ITEM_ATTACK_SELF, COMSIG_ITEM_SHARPEN_ACT, COMSIG_DETECTIVE_SCANNED, COMSIG_ATOM_FINALIZE_MATERIAL_EFFECTS, COMSIG_ATOM_FINALIZE_REMOVE_MATERIAL_EFFECTS)) /datum/component/transforming/proc/on_scan(datum/source, mob/user, datum/detective_scanner_log/entry) SIGNAL_HANDLER @@ -198,13 +247,13 @@ */ /datum/component/transforming/proc/set_active(obj/item/source) ADD_TRAIT(source, TRAIT_TRANSFORM_ACTIVE, REF(src)) - if(sharpness_on) + if(!isnull(sharpness_on)) source.sharpness = sharpness_on - if(force_on) - source.force = force_on + (source.sharpness ? sharpened_bonus : 0) - if(throwforce_on) - source.throwforce = throwforce_on + (source.sharpness ? sharpened_bonus : 0) - if(throw_speed_on) + if(!isnull(force_on)) + source.force = force_on + if(!isnull(throwforce_on)) + source.throwforce = throwforce_on + if(!isnull(throw_speed_on)) source.throw_speed = throw_speed_on if(LAZYLEN(attack_verb_continuous_on)) @@ -228,14 +277,14 @@ */ /datum/component/transforming/proc/set_inactive(obj/item/source) REMOVE_TRAIT(source, TRAIT_TRANSFORM_ACTIVE, REF(src)) - if(sharpness_on) - source.sharpness = initial(source.sharpness) - if(force_on) - source.force = initial(source.force) + (source.sharpness ? sharpened_bonus : 0) - if(throwforce_on) - source.throwforce = initial(source.throwforce) + (source.sharpness ? sharpened_bonus : 0) - if(throw_speed_on) - source.throw_speed = initial(source.throw_speed) + if(!isnull(sharpness_on)) + source.sharpness = sharpness_off + if(!isnull(force_on)) + source.force = force_off + if(!isnull(throwforce_on)) + source.throwforce = throwforce_off + if(!isnull(throw_speed_on)) + source.throw_speed = throwforce_off if(LAZYLEN(attack_verb_continuous_on)) source.attack_verb_continuous = attack_verb_continuous_off @@ -243,7 +292,7 @@ source.attack_verb_simple = attack_verb_simple_off source.hitsound = initial(source.hitsound) - source.update_weight_class(initial(source.w_class)) + source.update_weight_class(w_class_off) source.icon_state = initial(source.icon_state) source.inhand_icon_state = initial(source.inhand_icon_state) source.update_appearance() @@ -307,3 +356,11 @@ if(force_on + increment > max) return COMPONENT_BLOCK_SHARPEN_MAXED sharpened_bonus = increment + force_on += sharpened_bonus + throwforce_on += sharpened_bonus + force_off += sharpened_bonus + throwforce_off += sharpened_bonus + // Mimics base whetstone effect for the on state + sharpness_on = SHARP_EDGED + if (!active) + return COMPONENT_BLOCK_SHARPEN_SHARPNESS diff --git a/code/datums/components/twohanded.dm b/code/datums/components/twohanded.dm index a65d8c4f3c7..0db3642eb60 100644 --- a/code/datums/components/twohanded.dm +++ b/code/datums/components/twohanded.dm @@ -149,6 +149,8 @@ RegisterSignal(parent, COMSIG_ITEM_REMOVE_FANTASY_BONUSES, PROC_REF(remove_fantasy_bonuses)) RegisterSignal(parent, COMSIG_ATOM_FINALIZE_MATERIAL_EFFECTS, PROC_REF(on_materials_updated)) RegisterSignal(parent, COMSIG_ATOM_FINALIZE_REMOVE_MATERIAL_EFFECTS, PROC_REF(on_materials_updated)) + RegisterSignal(parent, COMSIG_ATOM_SINGLE_MATERIAL_EFFECT_APPLY, PROC_REF(on_material_apply)) + RegisterSignal(parent, COMSIG_ATOM_SINGLE_MATERIAL_EFFECT_REMOVE, PROC_REF(on_material_remove)) // Remove all siginals registered to the parent item /datum/component/two_handed/UnregisterFromParent() @@ -427,15 +429,26 @@ SIGNAL_HANDLER // With materials assigned we need to update our forces. if (wielded) - // Materials modify force multiplicatively! Most of the time, for snowflakes they gotta handle it themselves - if (!isnull(force_wielded)) - force_unwielded *= source.force / force_wielded force_wielded = source.force else - if (!isnull(force_unwielded)) - force_wielded *= source.force / force_unwielded force_unwielded = source.force +/datum/component/two_handed/proc/on_material_apply(obj/item/source, datum/material/material, amount, multiplier) + SIGNAL_HANDLER + // Opposite state's force needs to be calculated for each material's effect + if (wielded) + force_unwielded *= GET_MATERIAL_MODIFIER(source.get_material_force_modifier(material, source.sharpness), multiplier) + else + force_wielded *= GET_MATERIAL_MODIFIER(source.get_material_force_modifier(material, source.sharpness), multiplier) + +/datum/component/two_handed/proc/on_material_remove(obj/item/source, datum/material/material, amount, multiplier) + SIGNAL_HANDLER + // Same as appliation but inversed + if (wielded) + force_unwielded /= GET_MATERIAL_MODIFIER(source.get_material_force_modifier(material, source.sharpness), multiplier) + else + force_wielded /= GET_MATERIAL_MODIFIER(source.get_material_force_modifier(material, source.sharpness), multiplier) + /** * The offhand dummy item for two handed items */ diff --git a/code/game/atom/atom_materials.dm b/code/game/atom/atom_materials.dm index 05a1801ee6f..1f787d217bd 100644 --- a/code/game/atom/atom_materials.dm +++ b/code/game/atom/atom_materials.dm @@ -343,6 +343,7 @@ ///Apply material effects of a single material. /atom/proc/apply_single_mat_effect(datum/material/material, amount, multiplier) SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ATOM_SINGLE_MATERIAL_EFFECT_APPLY, material, amount, multiplier) // Derived and not optional, so this needs to be on base and not in the property code itself var/beauty_modifier = material.get_property(MATERIAL_BEAUTY) @@ -432,6 +433,7 @@ ///Remove material effects of a single material. /atom/proc/remove_single_mat_effect(datum/material/material, amount, multiplier) SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ATOM_SINGLE_MATERIAL_EFFECT_REMOVE, material, amount, multiplier) var/beauty_modifier = material.get_property(MATERIAL_BEAUTY) if(beauty_modifier) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index fd7a3f3058c..f45cc864750 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -2066,47 +2066,8 @@ obj_flags |= CONDUCTS_ELECTRICITY /obj/item/change_material_strength(datum/material/material, mat_amount, multiplier, remove = FALSE) - var/density = material.get_property(MATERIAL_DENSITY) - var/hardness = material.get_property(MATERIAL_HARDNESS) - var/flexibility = material.get_property(MATERIAL_FLEXIBILITY) - - // Item force calculation depends on its initial (assumed to be main) sharpness - // Transforming component doesn't work with materials at all and will need a refactor to change that, so we don't care about it here. - - var/force_mod = 1 - var/throwforce_mod = 1 - - switch (sharpness) - if (NONE) - // Blunt items are really hurt by all the flexing - force_mod = (1 + (density - 4) * 0.1) / (1 + flexibility * 0.1) - throwforce_mod = 1 + (density - 4) * 0.1 - flexibility * 0.1 - - if (SHARP_EDGED) - // Sharp items don't care about density and need high hardness to get a real bonus, but can tolerate (and benefit from) some flex - force_mod = 1 + (hardness - 4) * 0.1 - throwforce_mod = 1 + (hardness - 4) * 0.1 - - // Peaks out at 20% at flexibility of 1, drops off up to -80% at 10 - if (flexibility < 2) - force_mod *= 1 + (1 - abs(1 - flexibility)) * 0.2 - throwforce_mod += (1 - abs(1 - flexibility)) * 0.2 - else - force_mod *= 1 - (flexibility - 2) * 0.1 - throwforce_mod -= (flexibility - 2) * 0.1 - - if (SHARP_POINTY) - // Pointy items care about both density and hardness - force_mod = 1 + MATERIAL_PROPERTY_DIVERGENCE(density, 4, 6) * 0.05 + (hardness - 4) * 0.1 - throwforce_mod = 1 + MATERIAL_PROPERTY_DIVERGENCE(density, 4, 6) * 0.05 * 0.05 + (hardness - 4) * 0.1 - // But are not affected by flexibility until higher values, although they don't benefit from it either - if (flexibility > 4) - force_mod *= (1 - (flexibility - 4) * 0.2) - throwforce_mod -= (flexibility - 4) * 0.2 - - // Just for sanity in case something breaks - force_mod = round(clamp(force_mod, MATERIAL_MIN_FORCE_MULTIPLIER, MATERIAL_MAX_FORCE_MULTIPLIER), 0.01) - throwforce_mod = round(clamp(throwforce_mod, MATERIAL_MIN_FORCE_MULTIPLIER, MATERIAL_MAX_FORCE_MULTIPLIER), 0.01) + var/force_mod = get_material_force_modifier(material) + var/throwforce_mod = get_material_throwforce_modifier(material) if (!remove) force *= GET_MATERIAL_MODIFIER(force_mod, multiplier) @@ -2115,6 +2076,70 @@ force /= GET_MATERIAL_MODIFIER(force_mod, multiplier) throwforce /= GET_MATERIAL_MODIFIER(throwforce_mod, multiplier) +/// Returns a force multiplier from a material for a given sharpness +/obj/item/proc/get_material_force_modifier(datum/material/material, item_sharpness = get_sharpness()) + var/density = material.get_property(MATERIAL_DENSITY) + var/hardness = material.get_property(MATERIAL_HARDNESS) + var/flexibility = material.get_property(MATERIAL_FLEXIBILITY) + var/force_mod = 1 + switch (item_sharpness) + if (NONE) + // Blunt items are really hurt by all the flexing + force_mod = (1 + (density - 4) * 0.1) / (1 + flexibility * 0.1) + + if (SHARP_EDGED) + // Sharp items don't care about density and need high hardness to get a real bonus, but can tolerate (and benefit from) some flex + force_mod = 1 + (hardness - 4) * 0.1 + + // Peaks out at 20% at flexibility of 1, drops off up to -80% at 10 + if (flexibility < 2) + force_mod *= 1 + (1 - abs(1 - flexibility)) * 0.2 + else + force_mod *= 1 - (flexibility - 2) * 0.1 + + if (SHARP_POINTY) + // Pointy items care about both density and hardness + force_mod = 1 + MATERIAL_PROPERTY_DIVERGENCE(density, 4, 6) * 0.05 + (hardness - 4) * 0.1 + // But are not affected by flexibility until higher values, although they don't benefit from it either + if (flexibility > 4) + force_mod *= (1 - (flexibility - 4) * 0.2) + + // Just for sanity in case something breaks + force_mod = round(clamp(force_mod, MATERIAL_MIN_FORCE_MULTIPLIER, MATERIAL_MAX_FORCE_MULTIPLIER), 0.01) + return force_mod + +/// Returns a force multiplier from a material for a given sharpness +/obj/item/proc/get_material_throwforce_modifier(datum/material/material, item_sharpness = get_sharpness()) + var/density = material.get_property(MATERIAL_DENSITY) + var/hardness = material.get_property(MATERIAL_HARDNESS) + var/flexibility = material.get_property(MATERIAL_FLEXIBILITY) + var/throwforce_mod = 1 + switch (item_sharpness) + if (NONE) + // Blunt items are really hurt by all the flexing + throwforce_mod = 1 + (density - 4) * 0.1 - flexibility * 0.1 + + if (SHARP_EDGED) + // Sharp items don't care about density and need high hardness to get a real bonus, but can tolerate (and benefit from) some flex + throwforce_mod = 1 + (hardness - 4) * 0.1 + + // Peaks out at 20% at flexibility of 1, drops off up to -80% at 10 + if (flexibility < 2) + throwforce_mod += (1 - abs(1 - flexibility)) * 0.2 + else + throwforce_mod -= (flexibility - 2) * 0.1 + + if (SHARP_POINTY) + // Pointy items care about both density and hardness + throwforce_mod = 1 + MATERIAL_PROPERTY_DIVERGENCE(density, 4, 6) * 0.05 * 0.05 + (hardness - 4) * 0.1 + // But are not affected by flexibility until higher values, although they don't benefit from it either + if (flexibility > 4) + throwforce_mod -= (flexibility - 4) * 0.2 + + // Just for sanity in case something breaks + throwforce_mod = round(clamp(throwforce_mod, MATERIAL_MIN_FORCE_MULTIPLIER, MATERIAL_MAX_FORCE_MULTIPLIER), 0.01) + return throwforce_mod + /** * Returns the atom(either itself or an internal module) that will interact/attack the target on behalf of us * For example an object can have different `tool_behaviours` (e.g borg omni tool) but will return an internal reference of that tool to attack for us diff --git a/code/game/objects/items/sharpener.dm b/code/game/objects/items/sharpener.dm index daf1bf0ba96..f01ca917f8c 100644 --- a/code/game/objects/items/sharpener.dm +++ b/code/game/objects/items/sharpener.dm @@ -53,7 +53,8 @@ I.wound_bonus = I.wound_bonus + increment //wound_bonus has no cap user.visible_message(span_notice("[user] sharpens [I] with [src]!"), span_notice("You sharpen [I], making it much more deadly than before.")) playsound(src, 'sound/items/unsheath.ogg', 25, TRUE) - I.sharpness = SHARP_EDGED //When you whetstone something, it becomes an edged weapon, even if it was previously dull or pointy + if(!(signal_out & COMPONENT_BLOCK_SHARPEN_SHARPNESS)) + I.sharpness = SHARP_EDGED //When you whetstone something, it becomes an edged weapon, even if it was previously dull or pointy I.throwforce = clamp(I.throwforce + increment, 0, max) I.name = "[prefix] [I.name]" //This adds a prefix and a space to the item's name regardless of what the prefix is desc = "[desc] At least, it used to."