From 5c9340d4e5664bc3690986ab97b6663fbdeb6ec4 Mon Sep 17 00:00:00 2001 From: MistakeNot4892 Date: Thu, 9 Jan 2025 21:19:26 +1100 Subject: [PATCH] Adding grindstones and whetstones. --- code/__defines/item_effects.dm | 15 +++++ code/_onclick/item_attack.dm | 2 +- code/game/machinery/floor_light.dm | 2 +- code/game/objects/items/__item.dm | 4 +- code/game/objects/items/_item_force.dm | 21 ++++-- code/game/objects/items/blades/_blade.dm | 2 + .../structures/_structure_materials.dm | 4 +- code/modules/crafting/working/_working.dm | 6 +- .../modules/crafting/working/textiles/loom.dm | 16 ++--- .../working/textiles/spinning_wheel.dm | 22 +++---- code/modules/item_effects/_item_effect.dm | 15 ++--- code/modules/item_effects/item_effect_aura.dm | 2 +- .../item_effects/item_effect_charges.dm | 8 +-- .../modules/item_effects/item_effect_debug.dm | 28 ++++---- code/modules/item_effects/item_effect_item.dm | 61 ++++++++++++------ .../solids/materials_solid_mineral.dm | 1 + .../living/simple_animal/natural_weapons.dm | 2 +- maps/modpack_testing/modpack_testing.dm | 1 + maps/shaded_hills/shaded_hills.dm | 1 + .../item_sharpening/_item_sharpening.dm | 4 ++ .../item_sharpening/_item_sharpening.dme | 11 ++++ mods/content/item_sharpening/blade_sharpen.dm | 24 +++++++ .../content/item_sharpening/effect_sharpen.dm | 19 ++++++ mods/content/item_sharpening/grindstone.dm | 42 ++++++++++++ .../item_sharpening/icons/grindstone.dmi | Bin 0 -> 914 bytes mods/content/item_sharpening/item_sharpen.dm | 46 +++++++++++++ mods/content/item_sharpening/whetstone.dm | 18 ++++++ mods/~compatibility/patches/fantasy.dm | 7 +- .../patches/fantasy/whetstone_fantasy.dm | 7 ++ nebula.dme | 1 + 30 files changed, 307 insertions(+), 85 deletions(-) create mode 100644 code/__defines/item_effects.dm create mode 100644 mods/content/item_sharpening/_item_sharpening.dm create mode 100644 mods/content/item_sharpening/_item_sharpening.dme create mode 100644 mods/content/item_sharpening/blade_sharpen.dm create mode 100644 mods/content/item_sharpening/effect_sharpen.dm create mode 100644 mods/content/item_sharpening/grindstone.dm create mode 100644 mods/content/item_sharpening/icons/grindstone.dmi create mode 100644 mods/content/item_sharpening/item_sharpen.dm create mode 100644 mods/content/item_sharpening/whetstone.dm create mode 100644 mods/~compatibility/patches/fantasy/whetstone_fantasy.dm diff --git a/code/__defines/item_effects.dm b/code/__defines/item_effects.dm new file mode 100644 index 00000000000..d5c79b402f9 --- /dev/null +++ b/code/__defines/item_effects.dm @@ -0,0 +1,15 @@ +// Identifiers for various categories of item effects. +#define IE_CAT_DAMAGE "weff_damage" +#define IE_CAT_STRIKE "weff_strike" +#define IE_CAT_PARRY "weff_parry" +#define IE_CAT_USED "weff_used" +#define IE_CAT_WIELDED "weff_wield" +#define IE_CAT_VISUAL "weff_visual" +#define IE_CAT_LISTENER "weff_listener" +#define IE_CAT_EXAMINE "weff_visible" +#define IE_CAT_RANGED "weff_ranged" +#define IE_CAT_PROCESS "weff_process" + +// Identifiers for parameters for item effects. +#define IE_PAR_USES "uses" +#define IE_PAR_MAX_USES "max_uses" diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 1dbed7ab122..a5e8fb4dbb3 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -87,7 +87,7 @@ avoid code duplication. This includes items that may sometimes act as a standard var/oldhealth = current_health . = used_item.use_on_mob(src, user) - if(used_item.get_attack_force(user) && istype(ai) && current_health < oldhealth) + if(used_item.get_attack_force(user, dry_run = TRUE) && istype(ai) && current_health < oldhealth) ai.retaliate(user) if(!. && user == src && user.get_target_zone() == BP_MOUTH && can_devour(used_item, silent = TRUE)) diff --git a/code/game/machinery/floor_light.dm b/code/game/machinery/floor_light.dm index b6fefd1fe27..e31a013168b 100644 --- a/code/game/machinery/floor_light.dm +++ b/code/game/machinery/floor_light.dm @@ -58,7 +58,7 @@ var/global/list/floor_light_cache = list() qdel(src) return TRUE - if(W.get_attack_force(user) && user.check_intent(I_FLAG_HARM)) + if(W.get_attack_force(user, dry_run = TRUE) && user.check_intent(I_FLAG_HARM)) return physical_attack_hand(user) return ..() diff --git a/code/game/objects/items/__item.dm b/code/game/objects/items/__item.dm index 20c732782fa..f90ecf6e411 100644 --- a/code/game/objects/items/__item.dm +++ b/code/game/objects/items/__item.dm @@ -775,7 +775,7 @@ . += wielded_parry_bonus /obj/item/proc/on_disarm_attempt(mob/target, mob/living/attacker) - var/force = get_attack_force(attacker) + var/force = get_attack_force(attacker, dry_run = TRUE) if(force < 1) return 0 if(!istype(attacker)) @@ -1008,7 +1008,7 @@ modules/mob/living/human/life.dm if you die, you will be zoomed out. descriptors += "sharp" if(edge) descriptors += "edged" - if(get_attack_force() >= 10 && !sharp && !edge) + if(get_attack_force(dry_run = TRUE) >= 10 && !sharp && !edge) descriptors += "heavy" if(material) descriptors += "made of [material.solid_name]" diff --git a/code/game/objects/items/_item_force.dm b/code/game/objects/items/_item_force.dm index 3ff63de0cc7..86d105167cf 100644 --- a/code/game/objects/items/_item_force.dm +++ b/code/game/objects/items/_item_force.dm @@ -13,18 +13,20 @@ VAR_PROTECTED/_hardness_force_factor = 0.25 /obj/item/proc/get_max_weapon_force() - . = get_attack_force() + . = get_attack_force(dry_run = TRUE) if(can_be_twohanded) . = round(. * _wielded_force_multiplier) -/obj/item/proc/get_attack_force(mob/living/user) +// `dry_run` param is used for things like the grindstone modpack to avoid +// depleting sharpness when not actually being used to attack. +/obj/item/proc/get_attack_force(mob/living/user, dry_run = FALSE) if(_base_attack_force <= 0 || (item_flags & ITEM_FLAG_NO_BLUDGEON)) return 0 if(isnull(_cached_attack_force)) update_attack_force() if(_cached_attack_force <= 0) return 0 - return istype(user) ? user.modify_attack_force(src, _cached_attack_force, _wielded_force_multiplier) : _cached_attack_force + return istype(user) ? user.modify_attack_force(src, _cached_attack_force, _wielded_force_multiplier, dry_run) : _cached_attack_force // Existing hitby() code expects mobs, structures and machines to be thrown, it seems. /atom/movable/proc/get_thrown_attack_force() @@ -108,10 +110,17 @@ return _cached_attack_force // TODO: consider strength, athletics, mob size -/mob/living/proc/modify_attack_force(obj/item/weapon, supplied_force, wield_mult) +// `dry_run` param used in grindstone modpack to avoid depleting sharpness on non-attacks. +/mob/living/proc/modify_attack_force(obj/item/weapon, supplied_force, wield_mult, dry_run) if(!istype(weapon) || !weapon.is_held_twohanded()) - return supplied_force - return round(supplied_force * wield_mult) + . = supplied_force + else + . = supplied_force * wield_mult + var/list/item_effects = weapon.get_item_effects(IE_CAT_DAMAGE) + if(length(item_effects)) + for(var/decl/item_effect/damage_effect as anything in item_effects) + . = damage_effect.modify_attack_damage(., weapon, src, parameters = item_effects[damage_effect]) + return round(.) // Debug proc - leaving in for future work. Linter hates protected var access so leave commented. /* diff --git a/code/game/objects/items/blades/_blade.dm b/code/game/objects/items/blades/_blade.dm index 60a42215399..19dbcbce1cd 100644 --- a/code/game/objects/items/blades/_blade.dm +++ b/code/game/objects/items/blades/_blade.dm @@ -15,9 +15,11 @@ slot_flags = SLOT_LOWER_BODY material = /decl/material/solid/metal/steel _base_attack_force = 10 + var/decl/material/hilt_material = /decl/material/solid/organic/wood/oak var/decl/material/guard_material = /decl/material/solid/organic/wood/oak var/decl/material/pommel_material = /decl/material/solid/organic/wood/oak + /// Cache var for blade material shine calculation. var/tmp/shine diff --git a/code/game/objects/structures/_structure_materials.dm b/code/game/objects/structures/_structure_materials.dm index f3c619b1f61..db8065e41d4 100644 --- a/code/game/objects/structures/_structure_materials.dm +++ b/code/game/objects/structures/_structure_materials.dm @@ -37,14 +37,14 @@ /obj/structure/proc/update_material_name(var/override_name) var/base_name = override_name || initial(name) - if(istype(material)) + if(istype(material) && (material_alteration & MAT_FLAG_ALTERATION_NAME)) SetName("[material.adjective_name] [base_name]") else SetName(base_name) /obj/structure/proc/update_material_desc(var/override_desc) var/base_desc = override_desc || initial(desc) - if(istype(material)) + if(istype(material) && (material_alteration & MAT_FLAG_ALTERATION_DESC)) desc = "[base_desc] This one is made of [material.solid_name]." else desc = base_desc diff --git a/code/modules/crafting/working/_working.dm b/code/modules/crafting/working/_working.dm index e848937907a..4957dc0052a 100644 --- a/code/modules/crafting/working/_working.dm +++ b/code/modules/crafting/working/_working.dm @@ -49,7 +49,7 @@ work_sound.stop(src) update_icon() -/obj/structure/working/attackby(obj/item/W, mob/user) +/obj/structure/working/attackby(obj/item/used_item, mob/user) if(user.check_intent(I_FLAG_HARM)) return ..() @@ -58,12 +58,12 @@ to_chat(user, SPAN_WARNING("\The [src] is currently in use, please wait for it to be finished.")) return TRUE - if(try_take_input(W, user)) + if(try_take_input(used_item, user)) return TRUE return ..() -/obj/structure/working/proc/try_take_input(obj/item/W, mob/user, silent) +/obj/structure/working/proc/try_take_input(obj/item/used_item, mob/user, silent) return FALSE /obj/structure/working/proc/try_unload_material(mob/user) diff --git a/code/modules/crafting/working/textiles/loom.dm b/code/modules/crafting/working/textiles/loom.dm index 2b7bf5ae868..a68bdacbf57 100644 --- a/code/modules/crafting/working/textiles/loom.dm +++ b/code/modules/crafting/working/textiles/loom.dm @@ -34,24 +34,24 @@ weaving_type = null weaving_progress = 0 -/obj/structure/working/loom/try_take_input(obj/item/W, mob/user) +/obj/structure/working/loom/try_take_input(obj/item/used_item, mob/user) - if(istype(W, /obj/item/stack/material/thread)) + if(istype(used_item, /obj/item/stack/material/thread)) - if(!W.material.has_textile_fibers) - to_chat(user, SPAN_WARNING("\The [W] isn't suitable for making cloth.")) + if(!used_item.material.has_textile_fibers) + to_chat(user, SPAN_WARNING("\The [used_item] isn't suitable for making cloth.")) return TRUE var/loaded = FALSE if(loaded_thread) - if(!loaded_thread.can_merge_stacks(W)) + if(!loaded_thread.can_merge_stacks(used_item)) to_chat(user, SPAN_WARNING("\The [src] is already wound with \the [loaded_thread].")) return TRUE - var/obj/item/stack/feeding = W + var/obj/item/stack/feeding = used_item feeding.transfer_to(loaded_thread) loaded = TRUE - else if(user.try_unequip(W, src)) - loaded_thread = W + else if(user.try_unequip(used_item, src)) + loaded_thread = used_item loaded = TRUE if(loaded) weaving_color = loaded_thread.get_color() diff --git a/code/modules/crafting/working/textiles/spinning_wheel.dm b/code/modules/crafting/working/textiles/spinning_wheel.dm index e79afe92379..84b1dab6e1b 100644 --- a/code/modules/crafting/working/textiles/spinning_wheel.dm +++ b/code/modules/crafting/working/textiles/spinning_wheel.dm @@ -24,16 +24,16 @@ /obj/structure/working/spinning_wheel/proc/can_process(obj/item/thing) return istype(thing) && thing.has_textile_fibers() -/obj/structure/working/spinning_wheel/try_take_input(obj/item/W, mob/user) +/obj/structure/working/spinning_wheel/try_take_input(obj/item/used_item, mob/user) - if(istype(W.storage)) + if(istype(used_item.storage)) var/list/loading_growns = list() - for(var/obj/item/thing in W.get_stored_inventory()) + for(var/obj/item/thing in used_item.get_stored_inventory()) if(can_process(thing)) loading_growns += thing if(!length(loading_growns)) - to_chat(user, SPAN_WARNING("Nothing in \the [W] is suitable for processing on \the [src].")) + to_chat(user, SPAN_WARNING("Nothing in \the [used_item] is suitable for processing on \the [src].")) return TRUE if(length(loaded) >= MAX_LOADED) @@ -42,24 +42,24 @@ var/loaded_items = 0 for(var/obj/item/thing as anything in loading_growns) - if(W.storage.remove_from_storage(thing, src, TRUE)) + if(used_item.storage.remove_from_storage(thing, src, TRUE)) loaded_items++ LAZYADD(loaded, thing) if(length(loaded) >= MAX_LOADED) break if(loaded_items) - W.storage.finish_bulk_removal() - to_chat(user, SPAN_NOTICE("You prepare \the [src] with [loaded_items] items from \the [W].")) + used_item.storage.finish_bulk_removal() + to_chat(user, SPAN_NOTICE("You prepare \the [src] with [loaded_items] items from \the [used_item].")) update_icon() return TRUE - if(can_process(W)) + if(can_process(used_item)) if(length(loaded) >= MAX_LOADED) to_chat(user, SPAN_WARNING("\The [src] is already fully stocked and ready for spinning.")) return TRUE - if(user.try_unequip(W, src)) - LAZYADD(loaded, W) - to_chat(user, SPAN_NOTICE("You prepare \the [src] with \the [W].")) + if(user.try_unequip(used_item, src)) + LAZYADD(loaded, used_item) + to_chat(user, SPAN_NOTICE("You prepare \the [src] with \the [used_item].")) update_icon() return TRUE return TRUE diff --git a/code/modules/item_effects/_item_effect.dm b/code/modules/item_effects/_item_effect.dm index 9516a3a9639..3c88e828021 100644 --- a/code/modules/item_effects/_item_effect.dm +++ b/code/modules/item_effects/_item_effect.dm @@ -1,13 +1,3 @@ -#define ITEM_EFFECT_STRIKE "weff_strike" -#define ITEM_EFFECT_PARRY "weff_parry" -#define ITEM_EFFECT_USED "weff_used" -#define ITEM_EFFECT_WIELDED "weff_wield" -#define ITEM_EFFECT_VISUAL "weff_visual" -#define ITEM_EFFECT_LISTENER "weff_listener" -#define ITEM_EFFECT_VISIBLE "weff_visible" -#define ITEM_EFFECT_RANGED "weff_ranged" -#define ITEM_EFFECT_PROCESS "weff_process" - /decl/item_effect abstract_type = /decl/item_effect @@ -75,6 +65,9 @@ SHOULD_CALL_PARENT(FALSE) return FALSE -/decl/item_effect/proc/examined(obj/item/item, mob/user) +/decl/item_effect/proc/on_examined(obj/item/item, mob/user, distance, list/parameters) SHOULD_CALL_PARENT(FALSE) return FALSE + +/decl/item_effect/proc/modify_attack_damage(base_damage, obj/item/used_item, mob/user, dry_run, list/parameters) + return base_damage diff --git a/code/modules/item_effects/item_effect_aura.dm b/code/modules/item_effects/item_effect_aura.dm index d08b4a4968e..c30e3a36461 100644 --- a/code/modules/item_effects/item_effect_aura.dm +++ b/code/modules/item_effects/item_effect_aura.dm @@ -16,7 +16,7 @@ user.remove_aura(aura_type) return TRUE -/decl/item_effect/aura/examined(obj/item/item, mob/user) +/decl/item_effect/aura/on_examined(obj/item/item, mob/user) var/obj/aura/aura = aura_type to_chat(user, SPAN_NOTICE("\The [item] grants \a [initial(aura.name)] to the wielder.")) diff --git a/code/modules/item_effects/item_effect_charges.dm b/code/modules/item_effects/item_effect_charges.dm index 4a27d3d0a27..06e8126b16f 100644 --- a/code/modules/item_effects/item_effect_charges.dm +++ b/code/modules/item_effects/item_effect_charges.dm @@ -3,14 +3,14 @@ abstract_type = /decl/item_effect/charges /decl/item_effect/charges/do_ranged_effect(mob/user, obj/item/item, atom/target, list/parameters) - var/charges = (LAZYACCESS(parameters, "charges") || 0) + var/charges = (LAZYACCESS(parameters, IE_PAR_USES) || 0) if(charges <= 0) return FALSE - item.set_item_effect_parameter(src, ITEM_EFFECT_RANGED, "charges", charges-1) + item.set_item_effect_parameter(src, IE_CAT_RANGED, IE_PAR_USES, charges-1) return TRUE -/decl/item_effect/charges/examined(obj/item/item, mob/user) - to_chat(user, SPAN_NOTICE("\The [item] has [item.get_item_effect_parameter(src, ITEM_EFFECT_RANGED, "charges") || 0] charge\s of [effect_descriptor] left.")) +/decl/item_effect/charges/on_examined(obj/item/item, mob/user) + to_chat(user, SPAN_NOTICE("\The [item] has [item.get_item_effect_parameter(src, IE_CAT_RANGED, IE_PAR_USES) || 0] charge\s of [effect_descriptor] left.")) /obj/item/projectile/fireball name = "fireball" diff --git a/code/modules/item_effects/item_effect_debug.dm b/code/modules/item_effects/item_effect_debug.dm index 352143ed57b..1533abda483 100644 --- a/code/modules/item_effects/item_effect_debug.dm +++ b/code/modules/item_effects/item_effect_debug.dm @@ -37,7 +37,7 @@ /decl/item_effect/debug/hear_speech(obj/item/item, mob/user, message, decl/language/speaking) log_debug("[type]: [item] heard [user] say [message] in [speaking] ([json_encode(args)])") -/decl/item_effect/debug/examined(obj/item/item, mob/user) +/decl/item_effect/debug/on_examined(obj/item/item, mob/user) log_debug("[type]: [user] examined [item] ([json_encode(args)])") /decl/item_effect/debug/do_process_effect(obj/item/item, list/parameters) @@ -46,21 +46,21 @@ /obj/item/sword/katana/debug/Initialize() . = ..() add_item_effect(/decl/item_effect/debug, list( - ITEM_EFFECT_VISUAL = list("vis" = "ual"), - ITEM_EFFECT_STRIKE = list("foo" = "bar"), - ITEM_EFFECT_PARRY = list("fizz" = "buzz"), - ITEM_EFFECT_USED = list("aard" = "vark"), - ITEM_EFFECT_VISIBLE = list("ooo" = "aaa"), - ITEM_EFFECT_LISTENER = list("walla walla" = "bing bong"), - ITEM_EFFECT_PROCESS = list("hyonk" = "hjonk") + (IE_CAT_VISUAL) = list("vis" = "ual"), + (IE_CAT_STRIKE) = list("foo" = "bar"), + (IE_CAT_PARRY) = list("fizz" = "buzz"), + (IE_CAT_USED) = list("aard" = "vark"), + (IE_CAT_EXAMINE) = list("ooo" = "aaa"), + (IE_CAT_LISTENER) = list("walla walla" = "bing bong"), + (IE_CAT_PROCESS) = list("hyonk" = "hjonk") )) add_item_effect(/decl/item_effect/charges/fireball, list( - ITEM_EFFECT_VISIBLE, - ITEM_EFFECT_RANGED = list("charges" = 5) + (IE_CAT_EXAMINE), + (IE_CAT_RANGED) = list(IE_PAR_USES = 5) )) add_item_effect(/decl/item_effect/aura/regeneration, list( - ITEM_EFFECT_VISIBLE, - ITEM_EFFECT_WIELDED + (IE_CAT_EXAMINE), + (IE_CAT_WIELDED) )) /obj/item/staff/crystal/beacon/fireball @@ -71,6 +71,6 @@ /obj/item/staff/crystal/beacon/fireball/Initialize(ml, material_key) . = ..() add_item_effect(/decl/item_effect/charges/fireball, list( - ITEM_EFFECT_VISIBLE, - ITEM_EFFECT_RANGED = list("charges" = 5) + (IE_CAT_EXAMINE), + (IE_CAT_RANGED) = list(IE_PAR_USES = 5) )) \ No newline at end of file diff --git a/code/modules/item_effects/item_effect_item.dm b/code/modules/item_effects/item_effect_item.dm index 22c57157bd4..ea1be1cfd24 100644 --- a/code/modules/item_effects/item_effect_item.dm +++ b/code/modules/item_effects/item_effect_item.dm @@ -1,6 +1,15 @@ /obj/item var/list/_item_effects +/obj/item/proc/has_item_effect(decl/item_effect/effect, effect_category) + if(!length(_item_effects)) + return FALSE + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect)) + return FALSE + return LAZYISIN(LAZYACCESS(_item_effects, effect_category), effect) + /obj/item/proc/add_item_effect(effect_type, list/effect_parameters) if(!effect_type || !length(effect_parameters)) return FALSE @@ -13,13 +22,15 @@ . = TRUE if(.) - if(ITEM_EFFECT_LISTENER in effect_parameters) + if(IE_CAT_LISTENER in effect_parameters) global.listening_objects |= src - if(ITEM_EFFECT_PROCESS in effect_parameters) + if(IE_CAT_PROCESS in effect_parameters) SSitem_effects.queued_items |= src /obj/item/proc/remove_item_effect(decl/item_effect/effect) - if(!effect || !length(_item_effects)) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects)) return FALSE var/list/removed_effect_categories = list() for(var/effect_category in _item_effects) @@ -30,13 +41,23 @@ LAZYREMOVE(_item_effects, effect_category) . = TRUE if(.) - if(ITEM_EFFECT_LISTENER in removed_effect_categories) + if(IE_CAT_LISTENER in removed_effect_categories) global.listening_objects -= src - if(ITEM_EFFECT_PROCESS in removed_effect_categories) + if(IE_CAT_PROCESS in removed_effect_categories) SSitem_effects.queued_items -= src +/obj/item/proc/get_item_effect_parameters(decl/item_effect/effect, effect_category) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects) || !effect_category) + return null + var/list/effects = LAZYACCESS(_item_effects, effect_category) + return LAZYACCESS(effects, effect) + /obj/item/proc/get_item_effect_parameter(decl/item_effect/effect, effect_category, parameter_name) - if(!effect || !length(_item_effects) || !effect_category || !parameter_name) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects) || !effect_category || !parameter_name) return null var/list/effects = LAZYACCESS(_item_effects, effect_category) if(!LAZYISIN(effects, effect)) @@ -44,7 +65,9 @@ return LAZYACCESS(effects[effect], parameter_name) /obj/item/proc/set_item_effect_parameter(decl/item_effect/effect, effect_category, parameter_name, parameter_value) - if(!effect || !length(_item_effects) || !effect_category || !parameter_name) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect) || !length(_item_effects) || !effect_category || !parameter_name) return FALSE var/list/effects = LAZYACCESS(_item_effects, effect_category) if(!LAZYISIN(effects, effect)) @@ -59,7 +82,7 @@ /obj/item/resolve_attackby(atom/A, mob/user, var/click_params) if(!(. = ..())) return - var/list/item_effects = get_item_effects(ITEM_EFFECT_STRIKE) + var/list/item_effects = get_item_effects(IE_CAT_STRIKE) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src)) @@ -72,7 +95,7 @@ // PARRY effects /obj/item/on_parry(mob/user, damage_source, mob/attacker) . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_PARRY) + var/list/item_effects = get_item_effects(IE_CAT_PARRY) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src)) @@ -86,7 +109,7 @@ // VISUAL effects (world icon) /obj/item/on_update_icon() . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_VISUAL) + var/list/item_effects = get_item_effects(IE_CAT_VISUAL) if(!length(item_effects)) return for(var/decl/item_effect/used_effect as anything in item_effects) @@ -96,7 +119,7 @@ /obj/item/adjust_mob_overlay(mob/living/user_mob, bodytype, image/overlay, slot, bodypart, use_fallback_if_icon_missing = TRUE) // TODO: this might need work to handle items that do a state or appearance update in the parent call. if(overlay) - var/list/item_effects = get_item_effects(ITEM_EFFECT_VISUAL) + var/list/item_effects = get_item_effects(IE_CAT_VISUAL) if(length(item_effects)) for(var/decl/item_effect/used_effect as anything in item_effects) used_effect.apply_onmob_appearance_to(src, user_mob, bodytype, overlay, slot, bodypart, item_effects[used_effect]) @@ -106,7 +129,7 @@ /obj/item/attack_self(mob/user) if((. = ..())) return - var/list/item_effects = get_item_effects(ITEM_EFFECT_USED) + var/list/item_effects = get_item_effects(IE_CAT_USED) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src)) @@ -120,7 +143,7 @@ // WIELD effects (unwielded) /obj/item/dropped(mob/user) . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_WIELDED) + var/list/item_effects = get_item_effects(IE_CAT_WIELDED) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src)) @@ -133,7 +156,7 @@ // WIELD effects (wielded) /obj/item/equipped(mob/user, slot) . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_WIELDED) + var/list/item_effects = get_item_effects(IE_CAT_WIELDED) if(!length(item_effects)) return if(!istype(user) || QDELETED(user) || QDELETED(src) || loc != user || !(slot in user.get_held_item_slots())) @@ -146,7 +169,7 @@ // LISTENING effects /obj/item/hear_talk(mob/M, text, verb, decl/language/speaking) . = ..() - var/list/item_effects = get_item_effects(ITEM_EFFECT_LISTENER) + var/list/item_effects = get_item_effects(IE_CAT_LISTENER) if(!length(item_effects)) return for(var/decl/item_effect/listening_effect as anything in item_effects) @@ -157,17 +180,17 @@ . = ..() if(!user) return - var/list/item_effects = get_item_effects(ITEM_EFFECT_VISIBLE) + var/list/item_effects = get_item_effects(IE_CAT_EXAMINE) if(!length(item_effects)) return for(var/decl/item_effect/examine_effect as anything in item_effects) - examine_effect.examined(src, user, distance, item_effects[examine_effect]) + examine_effect.on_examined(src, user, distance, item_effects[examine_effect]) // RANGED effects /obj/item/afterattack(turf/floor/target, mob/user, proximity) if((. = ..()) || proximity) return - var/list/item_effects = get_item_effects(ITEM_EFFECT_RANGED) + var/list/item_effects = get_item_effects(IE_CAT_RANGED) if(!length(item_effects)) return for(var/decl/item_effect/ranged_effect as anything in item_effects) @@ -177,7 +200,7 @@ // PROCESS effects /obj/item/proc/process_item_effects() - var/list/item_effects = get_item_effects(ITEM_EFFECT_PROCESS) + var/list/item_effects = get_item_effects(IE_CAT_PROCESS) if(length(item_effects)) for(var/decl/item_effect/process_effect as anything in item_effects) process_effect.do_process_effect(src, item_effects[process_effect]) diff --git a/code/modules/materials/definitions/solids/materials_solid_mineral.dm b/code/modules/materials/definitions/solids/materials_solid_mineral.dm index ac92e330a7d..9f17d069f3f 100644 --- a/code/modules/materials/definitions/solids/materials_solid_mineral.dm +++ b/code/modules/materials/definitions/solids/materials_solid_mineral.dm @@ -68,6 +68,7 @@ boiling_point = 2504 color = "#effffe" reflectiveness = MAT_VALUE_SHINY + hardness = MAT_VALUE_VERY_HARD - 5 // Hard enough to whet steel. sparse_material_weight = 3 rich_material_weight = 1 dissolves_into = list( diff --git a/code/modules/mob/living/simple_animal/natural_weapons.dm b/code/modules/mob/living/simple_animal/natural_weapons.dm index 161bf49f7cd..06611f0170c 100644 --- a/code/modules/mob/living/simple_animal/natural_weapons.dm +++ b/code/modules/mob/living/simple_animal/natural_weapons.dm @@ -10,7 +10,7 @@ weapon_can_knock_prone = FALSE // Very powerful in the hands of simplemobs. var/show_in_message // whether should we show up in attack message, e.g. 'urist has been bit with teeth by carp' vs 'urist has been bit by carp' -/obj/item/natural_weapon/get_attack_force(mob/living/user) +/obj/item/natural_weapon/get_attack_force(mob/living/user, dry_run = FALSE) return get_base_attack_force() /obj/item/natural_weapon/attack_message_name() diff --git a/maps/modpack_testing/modpack_testing.dm b/maps/modpack_testing/modpack_testing.dm index d7843b96d6b..6db9fe8ec33 100644 --- a/maps/modpack_testing/modpack_testing.dm +++ b/maps/modpack_testing/modpack_testing.dm @@ -21,6 +21,7 @@ #include "../../mods/content/psionics/_psionics.dme" #include "../../mods/content/shackles/_shackles.dme" #include "../../mods/content/xenobiology/_xenobiology.dme" + #include "../../mods/content/item_sharpening/_item_sharpening.dme" #include "../../mods/gamemodes/cult/_cult.dme" #include "../../mods/gamemodes/heist/_heist.dme" diff --git a/maps/shaded_hills/shaded_hills.dm b/maps/shaded_hills/shaded_hills.dm index 1931b81ef34..eb386cc8180 100644 --- a/maps/shaded_hills/shaded_hills.dm +++ b/maps/shaded_hills/shaded_hills.dm @@ -5,6 +5,7 @@ #include "../../mods/content/mouse_highlights/_mouse_highlight.dme" #include "../../mods/content/scaling_descriptors.dm" #include "../../mods/species/drakes/_drakes.dme" // include before _fantasy.dme so overrides work + #include "../../mods/content/item_sharpening/_item_sharpening.dme" #include "../../mods/content/fantasy/_fantasy.dme" #include "areas/_areas.dm" diff --git a/mods/content/item_sharpening/_item_sharpening.dm b/mods/content/item_sharpening/_item_sharpening.dm new file mode 100644 index 00000000000..53c03251f44 --- /dev/null +++ b/mods/content/item_sharpening/_item_sharpening.dm @@ -0,0 +1,4 @@ +#define IE_PAR_SHARP_DAM_MULT "sharp_dam_mult" + +/decl/modpack/item_sharpening + name = "Item Sharpening" diff --git a/mods/content/item_sharpening/_item_sharpening.dme b/mods/content/item_sharpening/_item_sharpening.dme new file mode 100644 index 00000000000..cf812cb8b32 --- /dev/null +++ b/mods/content/item_sharpening/_item_sharpening.dme @@ -0,0 +1,11 @@ +#ifndef MODPACK_ITEM_SHARPENING +#define MODPACK_ITEM_SHARPENING +// BEGIN_INCLUDE +#include "_item_sharpening.dm" +#include "blade_sharpen.dm" +#include "grindstone.dm" +#include "effect_sharpen.dm" +#include "item_sharpen.dm" +#include "whetstone.dm" +//END_INCLUDE +#endif diff --git a/mods/content/item_sharpening/blade_sharpen.dm b/mods/content/item_sharpening/blade_sharpen.dm new file mode 100644 index 00000000000..a46b8d69033 --- /dev/null +++ b/mods/content/item_sharpening/blade_sharpen.dm @@ -0,0 +1,24 @@ +/obj/item/bladed/proc/get_sharpened_effect_params() + return list( + (IE_CAT_DAMAGE) = list( + (IE_PAR_USES) = max(1, max(1, rand(round(10 * 0.3), round(20 * 0.6)))), + (IE_PAR_MAX_USES) = 30, + (IE_PAR_SHARP_DAM_MULT) = 0.25 + ), + (IE_CAT_EXAMINE) + ) + +/obj/item/bladed/Initialize(ml, material_key, _hilt_mat, _guard_mat, _pommel_mat) + var/list/sharpened_params = get_sharpened_effect_params() + if(length(sharpened_params)) + add_item_effect(/decl/item_effect/sharpened, sharpened_params) + . = ..() + if(length(sharpened_params)) + update_attack_force() + update_name() + +/obj/item/bladed/folding/try_sharpen_with(mob/user, obj/sharpening_with) + if(!open) + to_chat(user, SPAN_WARNING("You cannot sharpen \the [src] while it's closed!")) + return FALSE + return ..() diff --git a/mods/content/item_sharpening/effect_sharpen.dm b/mods/content/item_sharpening/effect_sharpen.dm new file mode 100644 index 00000000000..4331f18e0d4 --- /dev/null +++ b/mods/content/item_sharpening/effect_sharpen.dm @@ -0,0 +1,19 @@ +/decl/item_effect/sharpened/modify_attack_damage(base_damage, obj/item/used_item, mob/user, dry_run, list/parameters) + var/uses = LAZYACCESS(parameters, IE_PAR_USES) + if(uses <= 0) + return base_damage + . = (1 + ((uses / max(1, LAZYACCESS(parameters, IE_PAR_MAX_USES))) * LAZYACCESS(parameters, IE_PAR_SHARP_DAM_MULT))) + if(!dry_run) + uses = max(0, uses-1) + used_item.set_item_effect_parameter(src, IE_CAT_DAMAGE, IE_PAR_USES, uses) + if(uses == 0) // We've gone dull! + used_item.update_attack_force() + used_item.update_name() + +/decl/item_effect/sharpened/on_examined(obj/item/item, mob/user, distance, list/parameters) + if(distance <= 1) + var/uses = item.get_item_effect_parameter(src, IE_CAT_DAMAGE, IE_PAR_USES) + if(uses > 0) + to_chat(user, SPAN_NOTICE("\The [src] has been sharpened to a keen edge.")) + else + to_chat(user, SPAN_NOTICE("\The [src] is dull and in need of sharpening.")) diff --git a/mods/content/item_sharpening/grindstone.dm b/mods/content/item_sharpening/grindstone.dm new file mode 100644 index 00000000000..13bc15f848b --- /dev/null +++ b/mods/content/item_sharpening/grindstone.dm @@ -0,0 +1,42 @@ +// TODO: better sound effects for working. +/obj/structure/working/grindstone + name = "grindstone" + desc = "A rotating section of coarse stone used to polish and sharpen metalwork like blades." + icon = 'mods/content/item_sharpening/icons/grindstone.dmi' + material_alteration = MAT_FLAG_ALTERATION_COLOR // Name and desc handled manually. + var/decl/material/stone_material = /decl/material/solid/quartz + +/obj/structure/working/grindstone/Initialize() + stone_material = GET_DECL(stone_material) + . = ..() + update_material_name() + update_material_desc() + +/obj/structure/working/grindstone/update_material_name(override_name) + . = ..() + if(stone_material) + SetName("[stone_material.adjective_name] [name]") + +/obj/structure/working/grindstone/update_material_desc(override_desc) + . = ..() + if(stone_material && istype(material)) + desc = "[desc] This one is made from [stone_material.solid_name] with \a [material.adjective_name] frame." + +/obj/structure/working/grindstone/on_update_icon() + . = ..() + underlays = list( + overlay_image(icon, "[icon_state]-grindstone", stone_material.color, RESET_COLOR), + overlay_image(icon, "[initial(icon_state)]-backdrop") + ) + +// Slightly wonky override, but this basically intercepts items being used on the grindstone. +/obj/structure/working/grindstone/try_take_input(obj/item/used_item, mob/user, silent) + if(working) + if(!silent) + to_chat(user, SPAN_WARNING("\The [src] is already in use, please wait for it to be free.")) + else + start_working() + used_item.try_sharpen_with(user, src) + if(!QDELETED(src) && working) + stop_working() + return TRUE diff --git a/mods/content/item_sharpening/icons/grindstone.dmi b/mods/content/item_sharpening/icons/grindstone.dmi new file mode 100644 index 0000000000000000000000000000000000000000..70b311b63b5c8f68854a03a206211bdc316f508c GIT binary patch literal 914 zcmV;D18w|?P)004jl0{{R3eocQU0000LP)t-sz`($Y zik`y3$w^0C|NsAGVs^m5z#D@x2wg|Jao=>o~@%)E5$sx5$`sX2+2AYmPf zAiA|liOJb1Mfn9px-z{eGcTpMBtI{eG;a~qh}(x;$_lQ2F5vJ70Q+8RYGa`M3IG5C zfJsC_RA_0cZ>c?U0qt_?PDK?zU5L%QSqVM;IduVhkmF8Q$n_) z?-t#?1v}jz9rRFXt=uDtk4KnuJ)E)A{n6b=wC19q+5{Pvb$?{ z#!mM~hhMjU3->PRa%KPFg+iea@N*d^b2=M8Mqx5mzukdhF3WLFXG7<7HeoL7ac*Z5 z=CYW~k_sArBP+bze7_ruSbM9~Qc<<;Vuk_xWD|GLouej2C zu^-;19{-3dy%)Pe9`R%!j(%;B7Yc>{7}@OX7t`$N2RFpbj_yYH{W{IXTnBS!_4RE( zKm2B#)h6XNah7s8*xKINHR%jH!_JVy$+{K$o^avbK=zR{Act z=vlSwHF2Ka_XoI7s1j~BIY9Ug{v=!ww`qsoAJA>^nmD)DsrzR{-+0{x@fx`+DpqxS zx?9=V3xz_V@Ih`5M(1VrASJs8DcL&2M-9*j;bJ@|e23nyG7u#3Dt7ytkO07*qoM6N<$f~sr1p8x;= literal 0 HcmV?d00001 diff --git a/mods/content/item_sharpening/item_sharpen.dm b/mods/content/item_sharpening/item_sharpen.dm new file mode 100644 index 00000000000..28290a6d13a --- /dev/null +++ b/mods/content/item_sharpening/item_sharpen.dm @@ -0,0 +1,46 @@ +/obj/item/update_name() + . = ..() + if(has_item_effect(/decl/item_effect/sharpened, IE_CAT_EXAMINE) && get_item_effect_parameter(/decl/item_effect/sharpened, IE_CAT_DAMAGE, IE_PAR_USES) <= 0) + SetName("dulled [name]") + +/obj/item/proc/can_sharpen_with(obj/item/sharpening_with) + if(!has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE)) + return FALSE + var/list/params = get_item_effect_parameters(/decl/item_effect/sharpened, IE_CAT_DAMAGE) + if(!islist(params) || params[IE_PAR_USES] >= params[IE_PAR_MAX_USES]) + return FALSE + if(istype(sharpening_with, /obj/structure/working/grindstone)) + var/obj/structure/working/grindstone/stone = sharpening_with + return !material || material.hardness <= stone.stone_material?.hardness + return !material || material.hardness <= sharpening_with.material?.hardness + +/obj/item/proc/sharpen_with(mob/user, obj/item/sharpen_with) + if(!has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE)) + return FALSE + var/list/params = get_item_effect_parameters(/decl/item_effect/sharpened, IE_CAT_DAMAGE) + if(!islist(params)) + return FALSE + var/max_uses = params[IE_PAR_MAX_USES] + if(max_uses <= 0) + return FALSE + var/uses = params[IE_PAR_USES] || 0 + if(uses >= max_uses) + return FALSE + set_item_effect_parameter(/decl/item_effect/sharpened, IE_CAT_DAMAGE, IE_PAR_USES, max_uses) + if(uses == 0) // We've sharpened up from dull. + update_attack_force() + update_name() + return TRUE + +/obj/item/proc/try_sharpen_with(mob/user, obj/sharpening_with) + if(!has_item_effect(/decl/item_effect/sharpened, IE_CAT_DAMAGE)) + return FALSE + if(can_sharpen_with(sharpening_with)) + user.visible_message("\The [user] begins sharpening \the [src] with \the [sharpening_with].") + // TODO: play sharpening sound? Spawn sparks for metal? + if(user.do_skilled(10 SECONDS, SKILL_WEAPONS, src, check_holding = TRUE) && !QDELETED(sharpening_with) && can_sharpen_with(sharpening_with) && sharpen_with(user, sharpening_with)) + // TODO: play sharpening sound? Spawn sparks for metal? + user.visible_message("\The [user] sharpens \the [src] with \the [sharpening_with].") + else + to_chat(user, SPAN_WARNING("\The [src] cannot be [sharp ? "further sharpened" : "sharpened"] with \the [sharpening_with].")) + return TRUE diff --git a/mods/content/item_sharpening/whetstone.dm b/mods/content/item_sharpening/whetstone.dm new file mode 100644 index 00000000000..cdfbb09eea5 --- /dev/null +++ b/mods/content/item_sharpening/whetstone.dm @@ -0,0 +1,18 @@ +/obj/item/whetstone + name = "whetstone" + desc = "A worn-down lozenge used to sharpen blades." + icon = 'icons/obj/items/striker.dmi' // TODO unique icon? + w_class = ITEM_SIZE_TINY + material_alteration = MAT_FLAG_ALTERATION_ALL + material = /decl/material/solid/quartz + +/obj/item/attackby(obj/item/used_item, mob/user) + if(istype(used_item, /obj/item/whetstone)) + return try_sharpen_with(user, used_item) + return ..() + +/decl/loadout_option/utility/whetstone + name = "whetstone" + path = /obj/item/whetstone + loadout_flags = null + uid = "gear_utility_whetstone" diff --git a/mods/~compatibility/patches/fantasy.dm b/mods/~compatibility/patches/fantasy.dm index c176360672c..4b4d6f7feab 100644 --- a/mods/~compatibility/patches/fantasy.dm +++ b/mods/~compatibility/patches/fantasy.dm @@ -1,4 +1,9 @@ // Override drake lore and names for the fantasy modpack. #ifdef MODPACK_DRAKES #include "fantasy/drake_fantasy.dm" -#endif \ No newline at end of file +#endif + +// Make whetstones available for the fantasy modpack/ +#ifdef MODPACK_ITEM_SHARPENING +#include "fantasy/whetstone_fantasy.dm" +#endif diff --git a/mods/~compatibility/patches/fantasy/whetstone_fantasy.dm b/mods/~compatibility/patches/fantasy/whetstone_fantasy.dm new file mode 100644 index 00000000000..b2821d26fa6 --- /dev/null +++ b/mods/~compatibility/patches/fantasy/whetstone_fantasy.dm @@ -0,0 +1,7 @@ +// Make whetstones available in character generation. +/decl/loadout_option/fantasy/utility/whetstone + name = "whetstone" + path = /obj/item/whetstone + available_materials = null + loadout_flags = null + uid = "gear_fantasy_whetstone" diff --git a/nebula.dme b/nebula.dme index c4e9c0bfc54..a194e1350fc 100644 --- a/nebula.dme +++ b/nebula.dme @@ -60,6 +60,7 @@ #include "code\__defines\intent.dm" #include "code\__defines\interactions.dm" #include "code\__defines\inventory_sizes.dm" +#include "code\__defines\item_effects.dm" #include "code\__defines\items_clothing.dm" #include "code\__defines\jobs.dm" #include "code\__defines\languages.dm"