mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-20 20:45:28 +01:00
Fixes cursed duffelbag's permanent curse (again), unit tests it. (#71969)
## About The Pull Request Curse of hunger did some funky stuff by checking for `slot_equipment_priority` (which ONLY BUCKETS use) and registering certain signals based on that The signals they were using instead didn't pass the unequipper, so the curse never got removed on unequip. Replaced them with just equip and drop, as equipped and dropped work just fine for it. Unit tests this. ## Why It's Good For The Game Infinite curse of clumsy and pacifism is kinda bad ## Changelog 🆑 Melbert fix: Dufflebag Curse no longer lasts forever after the bag is destroyed. fix: Dufflebag Cursing someone already afflicted properly doesn't try to add the curse again /🆑
This commit is contained in:
@@ -337,8 +337,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define TRAIT_CAN_SIGN_ON_COMMS "can_sign_on_comms"
|
||||
/// nobody can use martial arts on this mob
|
||||
#define TRAIT_MARTIAL_ARTS_IMMUNE "martial_arts_immune"
|
||||
/// You've been cursed with a living duffelbag, and can't have more added
|
||||
#define TRAIT_DUFFEL_CURSE_PROOF "duffel_cursed"
|
||||
/// Immune to being afflicted by time stop (spell)
|
||||
#define TRAIT_TIME_STOP_IMMUNE "time_stop_immune"
|
||||
/// Revenants draining you only get a very small benefit.
|
||||
@@ -1011,4 +1009,3 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define SPEAKING_FROM_TONGUE "tongue"
|
||||
///trait source that sign language should use
|
||||
#define SPEAKING_FROM_HANDS "hands"
|
||||
|
||||
|
||||
@@ -32,16 +32,15 @@
|
||||
. = ..()
|
||||
var/obj/item/cursed_item = parent
|
||||
RegisterSignal(cursed_item, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
|
||||
//checking slot_equipment_priority is the better way to decide if it should be an equip-curse (alternative being if it has slot_flags)
|
||||
//because it needs to know where to equip to (and stuff like buckets and cones can be on_pickup curses despite having slots to equip to)
|
||||
if(cursed_item.slot_equipment_priority)
|
||||
RegisterSignal(cursed_item, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
|
||||
else
|
||||
RegisterSignal(cursed_item, COMSIG_ITEM_PICKUP, PROC_REF(on_pickup))
|
||||
RegisterSignal(cursed_item, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
|
||||
|
||||
/datum/component/curse_of_hunger/UnregisterFromParent()
|
||||
. = ..()
|
||||
UnregisterSignal(parent, list(COMSIG_PARENT_EXAMINE, COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_POST_UNEQUIP, COMSIG_ITEM_PICKUP, COMSIG_ITEM_DROPPED))
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_PARENT_EXAMINE,
|
||||
COMSIG_ITEM_EQUIPPED,
|
||||
COMSIG_ITEM_DROPPED,
|
||||
))
|
||||
|
||||
///signal called on parent being examined
|
||||
/datum/component/curse_of_hunger/proc/on_examine(datum/source, mob/user, list/examine_list)
|
||||
@@ -57,23 +56,15 @@
|
||||
/datum/component/curse_of_hunger/proc/on_equip(datum/source, mob/equipper, slot)
|
||||
SIGNAL_HANDLER
|
||||
var/obj/item/at_least_item = parent
|
||||
if(!(at_least_item.slot_flags & slot))
|
||||
// Items with no slot flags curse on pickup (because hand slot)
|
||||
if(at_least_item.slot_flags && !(at_least_item.slot_flags & slot))
|
||||
return
|
||||
the_curse_begins(equipper)
|
||||
|
||||
///signal called from a successful unequip of parent
|
||||
/datum/component/curse_of_hunger/proc/on_unequip(mob/living/unequipper, force, atom/newloc, no_move, invdrop, silent)
|
||||
SIGNAL_HANDLER
|
||||
the_curse_ends(unequipper)
|
||||
|
||||
///signal called from picking up parent
|
||||
/datum/component/curse_of_hunger/proc/on_pickup(datum/source, mob/grabber)
|
||||
SIGNAL_HANDLER
|
||||
the_curse_begins(grabber)
|
||||
|
||||
///signal called from dropping parent
|
||||
/datum/component/curse_of_hunger/proc/on_drop(datum/source, mob/dropper)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
the_curse_ends(dropper)
|
||||
|
||||
/datum/component/curse_of_hunger/proc/the_curse_begins(mob/cursed)
|
||||
@@ -85,27 +76,24 @@
|
||||
ADD_TRAIT(cursed, TRAIT_PACIFISM, CURSED_ITEM_TRAIT(cursed_item.type))
|
||||
if(add_dropdel)
|
||||
cursed_item.item_flags |= DROPDEL
|
||||
return
|
||||
if(cursed_item.slot_equipment_priority)
|
||||
RegisterSignal(cursed_item, COMSIG_ITEM_POST_UNEQUIP, PROC_REF(on_unequip))
|
||||
else
|
||||
RegisterSignal(cursed_item, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
|
||||
|
||||
RegisterSignal(cursed_item, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
|
||||
|
||||
/datum/component/curse_of_hunger/proc/the_curse_ends(mob/uncursed)
|
||||
var/obj/item/at_least_item = parent
|
||||
var/obj/item/cursed_item = parent
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
REMOVE_TRAIT(parent, TRAIT_NODROP, CURSED_ITEM_TRAIT(parent.type))
|
||||
REMOVE_TRAIT(uncursed, TRAIT_CLUMSY, CURSED_ITEM_TRAIT(at_least_item.type))
|
||||
REMOVE_TRAIT(uncursed, TRAIT_PACIFISM, CURSED_ITEM_TRAIT(at_least_item.type))
|
||||
REMOVE_TRAIT(cursed_item, TRAIT_NODROP, CURSED_ITEM_TRAIT(cursed_item.type))
|
||||
REMOVE_TRAIT(uncursed, TRAIT_CLUMSY, CURSED_ITEM_TRAIT(cursed_item.type))
|
||||
REMOVE_TRAIT(uncursed, TRAIT_PACIFISM, CURSED_ITEM_TRAIT(cursed_item.type))
|
||||
//remove either one of the signals that could have called this proc
|
||||
UnregisterSignal(parent, list(COMSIG_ITEM_POST_UNEQUIP, COMSIG_ITEM_DROPPED))
|
||||
UnregisterSignal(cursed_item, COMSIG_ITEM_DROPPED)
|
||||
|
||||
var/turf/vomit_turf = get_turf(at_least_item)
|
||||
var/turf/vomit_turf = get_turf(cursed_item)
|
||||
playsound(vomit_turf, 'sound/effects/splat.ogg', 50, TRUE)
|
||||
new /obj/effect/decal/cleanable/vomit(vomit_turf)
|
||||
|
||||
uncursed.dropItemToGround(at_least_item, force = TRUE)
|
||||
if(!QDELETED(at_least_item)) //gives a head start for the person to get away from the cursed item before it begins hunting again!
|
||||
uncursed.dropItemToGround(cursed_item, force = TRUE)
|
||||
if(!QDELING(cursed_item)) //gives a head start for the person to get away from the cursed item before it begins hunting again!
|
||||
addtimer(CALLBACK(src, PROC_REF(seek_new_target)), 10 SECONDS)
|
||||
|
||||
///proc called after a timer to awaken the AI in the cursed item if it doesn't have a target already.
|
||||
@@ -166,3 +154,6 @@
|
||||
cursed.visible_message(span_danger("[cursed_item] bites [cursed]!"), span_userdanger("[cursed_item] bites you to sate [cursed_item.p_their()] hunger!"))
|
||||
cursed.apply_damage(60, BRUTE, BODY_ZONE_CHEST, wound_bonus = -20, bare_wound_bonus = 20)
|
||||
current_health = min(current_health + 1, max_health)
|
||||
|
||||
#undef HUNGER_THRESHOLD_WARNING
|
||||
#undef HUNGER_THRESHOLD_TRY_EATING
|
||||
|
||||
@@ -203,8 +203,7 @@
|
||||
var/filter_color = "#8a0c0ca1" //clarified args
|
||||
var/new_name = pick(", eternally hungry", " of the glutton", " cursed with hunger", ", consumer of all", " of the feast")
|
||||
master.AddElement(/datum/element/curse_announcement, "[master] is cursed with the curse of hunger!", filter_color, new_name, comp)
|
||||
var/add_dropdel = FALSE //clarified boolean
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/curse_of_hunger, add_dropdel)
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/curse_of_hunger)
|
||||
return newName //no spoilers!
|
||||
|
||||
/datum/fantasy_affix/curse_of_hunger/remove(datum/component/fantasy/comp)
|
||||
|
||||
@@ -361,7 +361,6 @@
|
||||
icon_state = "duffel-curse"
|
||||
inhand_icon_state = "duffel-curse"
|
||||
slowdown = 2
|
||||
item_flags = DROPDEL
|
||||
max_integrity = 100
|
||||
|
||||
/obj/item/storage/backpack/duffelbag/cursed/Initialize(mapload)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
victim.Knockdown(5 SECONDS)
|
||||
|
||||
// If someone's already cursed, don't try to give them another
|
||||
if(HAS_TRAIT(victim, TRAIT_DUFFEL_CURSE_PROOF))
|
||||
if(istype(victim.back, /obj/item/storage/backpack/duffelbag/cursed))
|
||||
to_chat(caster, span_warning("The burden of [victim]'s duffel bag becomes too much, shoving them to the floor!"))
|
||||
to_chat(victim, span_warning("The weight of this bag becomes overburdening!"))
|
||||
return TRUE
|
||||
@@ -53,8 +53,6 @@
|
||||
span_danger("You feel something attaching itself to you, and a strong desire to discuss your [pick(elaborate_backstory)] at length!"),
|
||||
)
|
||||
|
||||
// This duffelbag is now cuuuurrrsseed! Equip it on them
|
||||
ADD_TRAIT(conjured_duffel, TRAIT_DUFFEL_CURSE_PROOF, CURSED_ITEM_TRAIT(conjured_duffel.name))
|
||||
conjured_duffel.pickup(victim)
|
||||
conjured_duffel.forceMove(victim)
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
#include "heretic_rituals.dm"
|
||||
#include "holidays.dm"
|
||||
#include "human_through_recycler.dm"
|
||||
#include "hunger_curse.dm"
|
||||
#include "hydroponics_extractor_storage.dm"
|
||||
#include "hydroponics_harvest.dm"
|
||||
#include "hydroponics_self_mutations.dm"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/// Tests that the curse of hunger, from [/datum/component/curse_of_hunger],
|
||||
/// is properly added when equipped to the correct slot and removed when dropped / deleted
|
||||
/datum/unit_test/hunger_curse
|
||||
|
||||
/datum/unit_test/hunger_curse/Run()
|
||||
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
|
||||
var/obj/item/storage/backpack/duffelbag/cursed/cursed_bag = allocate(/obj/item/storage/backpack/duffelbag/cursed)
|
||||
|
||||
dummy.equip_to_appropriate_slot(cursed_bag)
|
||||
|
||||
TEST_ASSERT(HAS_TRAIT(cursed_bag, TRAIT_NODROP), "The cursed bag wasn't NODROP after being cursed!")
|
||||
TEST_ASSERT(HAS_TRAIT(dummy, TRAIT_CLUMSY), "Dummy wasn't clumsy after being cursed!")
|
||||
TEST_ASSERT(HAS_TRAIT(dummy, TRAIT_PACIFISM), "Dummy wasn't a pacifist after being cursed!")
|
||||
|
||||
QDEL_NULL(cursed_bag)
|
||||
|
||||
TEST_ASSERT(!HAS_TRAIT(dummy, TRAIT_CLUMSY), "Dummy was still clumsy after being cured of its curse!")
|
||||
TEST_ASSERT(!HAS_TRAIT(dummy, TRAIT_PACIFISM), "Dummy was still a pacifist after being cured of its curse!")
|
||||
Reference in New Issue
Block a user