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

🆑
fix: Fixed fire arrow ritual not being accessible
fix: Fixed certain nullrod types not being usable for certain holy and
unholy interactions
/🆑
This commit is contained in:
SmArtKar
2025-08-04 20:53:37 -04:00
committed by Roxy
parent 46e5e89439
commit ad3493ea32
9 changed files with 82 additions and 44 deletions
+3
View File
@@ -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
+1
View File
@@ -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,
+18 -11
View File
@@ -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()
@@ -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)
@@ -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()
@@ -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
@@ -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
@@ -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)
+5 -4
View File
@@ -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!"))