From ad3493ea3219d0eb4f893836f25eba0e95e783d2 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Fri, 1 Aug 2025 02:52:51 +0200 Subject: [PATCH] Fixes fire arrow ritual not appearing, and certain nullrods not being considered valid for dispelling/conversion purposes (#92375) We have multiple "nullrods" which aren't actually ``/obj/item/nullrod`` subtypes, which causes runtimes when selecting them, which prevented the signal from being sent out and the global variable from being assigned. Additionally, we have multiple interactions which directly typecheck for the nullrod item, which blocked multiple interactions (dispelling heretic runes, rends, haunted items, psyker revolver and cult blade conversion), which I fixed by instead converting those interactions to check for ``TRAIT_NULLROD_ITEM`` which is assigned to all nullrods and non-nullrod weapons spawned from the nullrod. - Closes #77373 :cl: fix: Fixed fire arrow ritual not being accessible fix: Fixed certain nullrod types not being usable for certain holy and unholy interactions /:cl: --- code/__DEFINES/traits/declarations.dm | 3 ++ code/_globalvars/traits/_traits.dm | 1 + code/modules/antagonists/cult/runes.dm | 29 +++++++----- .../heretic/structures/carving_knife.dm | 2 +- .../antagonists/revenant/haunted_item.dm | 16 ++++++- .../antagonists/wizard/equipment/artefact.dm | 14 +++--- .../job_types/chaplain/chaplain_nullrod.dm | 47 +++++++++++-------- .../chaplain/chaplain_vorpal_scythe.dm | 5 ++ code/modules/religion/burdened/psyker.dm | 9 ++-- 9 files changed, 82 insertions(+), 44 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 6600242d5a9..38500df0291 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1551,4 +1551,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait that makes mobs with it immune to mining gear AOE attacks #define TRAIT_MINING_AOE_IMMUNE "mining_aoe_immune" +/// Trait that allows an item to perform holy rites akin to a nullrod +#define TRAIT_NULLROD_ITEM "nullrod_item" + // END TRAIT DEFINES diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 8cf7f0d0183..820d77d60d5 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -680,6 +680,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_SIDE_KICK" = TRAIT_NO_SIDE_KICK, "TRAIT_NODROP" = TRAIT_NODROP, "TRAIT_NO_WORN_ICON" = TRAIT_NO_WORN_ICON, + "TRAIT_NULLROD_ITEM" = TRAIT_NULLROD_ITEM, "TRAIT_OMNI_BAIT" = TRAIT_OMNI_BAIT, "TRAIT_PLANT_WILDMUTATE" = TRAIT_PLANT_WILDMUTATE, "TRAIT_POISONOUS_BAIT" = TRAIT_POISONOUS_BAIT, diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 4c781158da5..bdbe7447921 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -428,29 +428,36 @@ structure_check() searches for nearby cultist structures required for the invoca /// Tries to convert a null rod over the rune to a cult sword /obj/effect/rune/convert/proc/try_spawn_sword() - for(var/obj/item/nullrod/rod in loc) - if(rod.anchored || (rod.resistance_flags & INDESTRUCTIBLE)) + for(var/obj/item/potential_rod in loc) + if(!HAS_TRAIT(potential_rod, TRAIT_NULLROD_ITEM)) continue - var/num_slain = LAZYLEN(rod.cultists_slain) - var/displayed_message = "[rod] glows an unholy red and begins to transform..." - if(GET_ATOM_BLOOD_DNA_LENGTH(rod)) - displayed_message += " The blood of [num_slain] fallen cultist[num_slain == 1 ? "":"s"] is absorbed into [rod]!" + if(potential_rod.anchored || (potential_rod.resistance_flags & INDESTRUCTIBLE)) + continue - rod.visible_message(span_cult_italic(displayed_message)) + var/num_slain = 0 + if (istype(potential_rod, /obj/item/nullrod)) + var/obj/item/nullrod/actual_rod = potential_rod + num_slain = LAZYLEN(actual_rod.cultists_slain) + + var/displayed_message = "[potential_rod] glows an unholy red and begins to transform..." + if(num_slain && GET_ATOM_BLOOD_DNA_LENGTH(potential_rod)) + displayed_message += " The blood of [num_slain] fallen cultist[num_slain == 1 ? "":"s"] is absorbed into [potential_rod]!" + + potential_rod.visible_message(span_cult_italic(displayed_message)) switch(num_slain) if(0) - animate_spawn_sword(rod, /obj/item/melee/cultblade/dagger) + animate_spawn_sword(potential_rod, /obj/item/melee/cultblade/dagger) if(1) - animate_spawn_sword(rod, /obj/item/melee/cultblade) + animate_spawn_sword(potential_rod, /obj/item/melee/cultblade) else - animate_spawn_sword(rod, /obj/item/melee/cultblade/halberd) + animate_spawn_sword(potential_rod, /obj/item/melee/cultblade/halberd) return TRUE return FALSE /// Does an animation of a null rod transforming into a cult sword -/obj/effect/rune/convert/proc/animate_spawn_sword(obj/item/nullrod/former_rod, new_blade_typepath) +/obj/effect/rune/convert/proc/animate_spawn_sword(obj/item/former_rod, new_blade_typepath) playsound(src, 'sound/effects/magic.ogg', 33, vary = TRUE, extrarange = SILENCED_SOUND_EXTRARANGE, frequency = 0.66) former_rod.anchored = TRUE former_rod.Shake() diff --git a/code/modules/antagonists/heretic/structures/carving_knife.dm b/code/modules/antagonists/heretic/structures/carving_knife.dm index 5b2f8743691..289b1784c4d 100644 --- a/code/modules/antagonists/heretic/structures/carving_knife.dm +++ b/code/modules/antagonists/heretic/structures/carving_knife.dm @@ -190,7 +190,7 @@ return ..() /obj/structure/trap/eldritch/item_interaction(mob/living/user, obj/item/tool, list/modifiers) - if(istype(tool, /obj/item/melee/rune_carver) || istype(tool, /obj/item/nullrod)) + if(istype(tool, /obj/item/melee/rune_carver) || HAS_TRAIT(tool, TRAIT_NULLROD_ITEM)) loc.balloon_alert(user, "carving dispelled") playsound(src, 'sound/items/sheath.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE) qdel(src) diff --git a/code/modules/antagonists/revenant/haunted_item.dm b/code/modules/antagonists/revenant/haunted_item.dm index 642002976cb..bd1cac77fb7 100644 --- a/code/modules/antagonists/revenant/haunted_item.dm +++ b/code/modules/antagonists/revenant/haunted_item.dm @@ -7,6 +7,8 @@ var/despawn_message /// List of types that, if they hit our item, we will instantly stop the haunting var/list/types_which_dispell_us + /// List of traits which allow items outside of types_which_dispell_us to also work on us + var/list/traits_which_dispell_us /datum/component/haunted_item/Initialize( // What color should the haunted item be glowing? By default the color's white (passed into the haunted element). @@ -25,6 +27,9 @@ throw_force_max = 15, // See the types_which_dispell_us list. By default / if null, this will become the default static list. list/types_which_dispell_us, + // List of traits which allow items outside of types_which_dispell_us to also work on us + // By default / if null will default to TRAIT_NULLROD_ITEM + list/traits_which_dispell_us, ) if(!isitem(parent)) @@ -62,7 +67,9 @@ haunted_item.throwforce = min(haunted_item.throwforce + throw_force_bonus, throw_force_max) var/static/list/default_dispell_types = list(/obj/item/nullrod, /obj/item/book/bible) + var/static/list/default_dispell_traits = list(TRAIT_NULLROD_ITEM) src.types_which_dispell_us = types_which_dispell_us || default_dispell_types + src.traits_which_dispell_us = traits_which_dispell_us || default_dispell_traits src.despawn_message = despawn_message /datum/component/haunted_item/Destroy(force) @@ -94,7 +101,14 @@ SIGNAL_HANDLER if(!is_type_in_list(attacking_item, types_which_dispell_us)) - return + var/has_trait = FALSE + for(var/dispell_trait in traits_which_dispell_us) + if(HAS_TRAIT(attacking_item, dispell_trait)) + has_trait = TRUE + break + + if(!has_trait) + return attacker.visible_message(span_warning("[attacker] dispells the ghostly energy from [source]!"), span_warning("You dispel the ghostly energy from [source]!")) clear_haunting() diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index bee49757a18..4d90d4aa53b 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -63,13 +63,13 @@ qdel(src) return PROCESS_KILL -/obj/effect/rend/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers) - if(istype(I, /obj/item/nullrod)) - user.visible_message(span_danger("[user] seals \the [src] with \the [I].")) - qdel(src) - return - else - return ..() +/obj/effect/rend/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(!HAS_TRAIT(tool, TRAIT_NULLROD_ITEM)) + return NONE + + user.visible_message(span_danger("[user] seals \the [src] with \the [tool].")) + qdel(src) + return ITEM_INTERACT_SUCCESS /obj/effect/rend/singularity_act() return diff --git a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm index f48bbcc1e76..0c1ec753d15 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm @@ -36,30 +36,37 @@ effects_we_clear = list(/obj/effect/rune, /obj/effect/heretic_rune, /obj/effect/cosmic_rune), \ ) AddElement(/datum/element/bane, mob_biotypes = MOB_SPIRIT, damage_multiplier = 0, added_damage = 25, requires_combat_mode = FALSE) + ADD_TRAIT(src, TRAIT_NULLROD_ITEM, INNATE_TRAIT) - if((!GLOB.holy_weapon_type || !station_holy_item) && type == /obj/item/nullrod) - var/list/rods = list() - for(var/obj/item/nullrod/nullrod_type as anything in typesof(/obj/item/nullrod)) - if(!initial(nullrod_type.chaplain_spawnable)) - continue - rods[nullrod_type] = initial(nullrod_type.menu_description) - //special non-nullrod subtyped shit - rods[/obj/item/gun/ballistic/bow/divine/with_quiver] = "A divine bow and 10 quivered holy arrows." - rods[/obj/item/organ/cyberimp/arm/toolkit/shard/scythe] = "A shard that implants itself into your arm, \ - allowing you to conjure forth a vorpal scythe. \ - Allows you to behead targets for empowered strikes. \ - Harms you if you dismiss the scythe without first causing harm to a creature. \ - The shard also causes you to become Morbid, shifting your interests towards the macabre." - rods[/obj/item/melee/skateboard/holyboard] = "A skateboard that grants you flight and anti-magic abilities while ridden. Fits in your bag." - //bubberstation edit - start - rods[/obj/item/dualsaber/chaplain] = "A huge energy blade, it possesses the unique ability to block projectiles, but the unwieldy nature of it \ -means that you'll be forced to move carefully while it's on. Fits in pockets, and can be worn on the belt when off." - //bubberstation edit - end - AddComponent(/datum/component/subtype_picker, rods, CALLBACK(src, PROC_REF(on_holy_weapon_picked))) + if((GLOB.holy_weapon_type && station_holy_item) || type != /obj/item/nullrod) + return + + var/list/rods = list() + for(var/obj/item/nullrod/nullrod_type as anything in typesof(/obj/item/nullrod)) + if(!initial(nullrod_type.chaplain_spawnable)) + continue + rods[nullrod_type] = initial(nullrod_type.menu_description) + //special non-nullrod subtyped shit + rods[/obj/item/gun/ballistic/bow/divine/with_quiver] = "A divine bow and 10 quivered holy arrows." + rods[/obj/item/organ/cyberimp/arm/toolkit/shard/scythe] = "A shard that implants itself into your arm, \ + allowing you to conjure forth a vorpal scythe. \ + Allows you to behead targets for empowered strikes. \ + Harms you if you dismiss the scythe without first causing harm to a creature. \ + The shard also causes you to become Morbid, shifting your interests towards the macabre." + rods[/obj/item/melee/skateboard/holyboard] = "A skateboard that grants you flight and anti-magic abilities while ridden. Fits in your bag." + // BUBBER EDIT ADDITION BEGIN + rods[/obj/item/dualsaber/chaplain] = "A huge energy blade, it possesses the unique ability to block projectiles, but the unwieldy nature of it \ + means that you'll be forced to move carefully while it's on. Fits in pockets, and can be worn on the belt when off." + // BUBBER EDIT ADDITION END + AddComponent(/datum/component/subtype_picker, rods, CALLBACK(src, PROC_REF(on_holy_weapon_picked))) /// Callback for subtype picker, invoked when the chaplain picks a new nullrod /obj/item/nullrod/proc/on_holy_weapon_picked(obj/item/nullrod/new_holy_weapon, mob/living/picker) - new_holy_weapon.on_selected(src, picker) + // Some nullrod variants aren't nullrod subtypes + if(istype(new_holy_weapon)) + new_holy_weapon.on_selected(src, picker) + else // In which case they still need to be marked as one + ADD_TRAIT(new_holy_weapon, TRAIT_NULLROD_ITEM, INNATE_TRAIT) if(!station_holy_item) return GLOB.holy_weapon_type = new_holy_weapon.type diff --git a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm index 57a786bd20d..f521b7603ec 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm @@ -11,6 +11,11 @@ If the scythe isn't empowered when you sheath it, you take a heap of damage and items_to_create = list(/obj/item/vorpalscythe) organ_traits = list(TRAIT_MORBID) +/obj/item/organ/cyberimp/arm/toolkit/shard/scythe/Initialize(mapload) + . = ..() + for (var/obj/item/scythe as anything in items_list) + ADD_TRAIT(scythe, TRAIT_NULLROD_ITEM, INNATE_TRAIT) + /obj/item/organ/cyberimp/arm/toolkit/shard/scythe/Retract() var/obj/item/vorpalscythe/scythe = active_item if(!scythe) diff --git a/code/modules/religion/burdened/psyker.dm b/code/modules/religion/burdened/psyker.dm index 6a608059c49..2ffde313f6d 100644 --- a/code/modules/religion/burdened/psyker.dm +++ b/code/modules/religion/burdened/psyker.dm @@ -100,15 +100,16 @@ if(!burden || burden.burden_level < 9) to_chat(human_user, span_warning("You aren't burdened enough.")) return FALSE - for(var/obj/item/nullrod/null_rod in get_turf(religious_tool)) - transformation_target = null_rod - return ..() + for(var/obj/item/possible_rod in get_turf(religious_tool)) + if(HAS_TRAIT(possible_rod, TRAIT_NULLROD_ITEM)) + transformation_target = possible_rod + return ..() to_chat(human_user, span_warning("You need to place a null rod on [religious_tool] to do this!")) return FALSE /datum/religion_rites/nullrod_transformation/invoke_effect(mob/living/user, atom/movable/religious_tool) ..() - var/obj/item/nullrod/null_rod = transformation_target + var/obj/item/null_rod = transformation_target transformation_target = null if(QDELETED(null_rod) || null_rod.loc != get_turf(religious_tool)) to_chat(user, span_warning("Your target left the altar!"))