diff --git a/code/datums/components/keep_me_secure.dm b/code/datums/components/keep_me_secure.dm new file mode 100644 index 00000000000..b9e8a403a0d --- /dev/null +++ b/code/datums/components/keep_me_secure.dm @@ -0,0 +1,75 @@ +/** + * ### Keep Me Secure component! + * + * Component that attaches to items, invoking a function to react when left unmoved and unsecured for too long. + * Used for Nuclear Authentication Disks, and whiny plushy as an example (which changes sprites depending on whether it considers itself secure.) + */ +/datum/component/keep_me_secure + /// callback for the parent being secure + var/datum/callback/secured_callback + /// callback for the parent being unsecured + var/datum/callback/unsecured_callback + + /// The last secure location the parent was at. + var/turf/last_secured_location + /// The last world time the parent moved. + var/last_move + +/datum/component/keep_me_secure/Initialize(secured_callback, unsecured_callback) + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + src.secured_callback = secured_callback + src.unsecured_callback = unsecured_callback + +/datum/component/keep_me_secure/RegisterWithParent() + last_move = world.time + START_PROCESSING(SSobj, src) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE_MORE, PROC_REF(on_examine_more)) + + +/datum/component/keep_me_secure/UnregisterFromParent() + STOP_PROCESSING(SSobj, src) + UnregisterSignal(parent, COMSIG_PARENT_EXAMINE) + +/// Returns whether the game is supposed to consider the parent "secure". +/datum/component/keep_me_secure/proc/is_secured() + var/obj/item/item_parent = parent + if (last_secured_location == get_turf(item_parent)) + return FALSE + + var/mob/holder = item_parent.pulledby || get(parent, /mob) + if (isnull(holder?.client)) + return FALSE + + return TRUE + +/datum/component/keep_me_secure/process(delta_time) + if(is_secured()) + last_secured_location = get_turf(parent) + last_move = world.time + if(secured_callback) + secured_callback.Invoke(last_move) + else + if(unsecured_callback) + unsecured_callback.Invoke(last_move) + +/// signal sent when parent is examined +/datum/component/keep_me_secure/proc/on_examine(mob/living/source, mob/examiner, list/examine_list) + SIGNAL_HANDLER + + examine_list += span_boldnotice("[parent] should be secured at all times.") + if(is_secured()) + examine_list += span_notice("Right now, it is.") + else + examine_list += span_warning("Right now, it isn't...") + examine_list += span_notice("Examine closer for more info.") + +/// signal sent when parent is examined more +/datum/component/keep_me_secure/proc/on_examine_more(mob/living/source, mob/examiner, list/examine_list) + SIGNAL_HANDLER + + examine_list += span_notice("For [parent] to be secure, it needs to be:") + examine_list += span_notice("1. Always on the move, and...") + examine_list += span_notice("2. Held or dragged by someone.") diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index 8bf2bfd69dd..f7eea34cbc2 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -586,6 +586,53 @@ . = ..() AddComponent(/datum/component/edit_complainer) +/obj/item/toy/plush/whiny_plushie + name = "whiny plushie" + desc = "An ancient plushie that demands constant companionship, after being forgotten for too long." + icon_state = "plushie_whiny" + inhand_icon_state = null + /// static list of cry messages it picks from to speak when it is insecure from no movement + var/static/list/cry_still_messages + /// static list of cry messages it picks from to speak when it is insecure from no holder + var/static/list/cry_alone_messages + /// cooldown for it sending messages, it will every 10 seconds + COOLDOWN_DECLARE(cry_cooldown) + +/obj/item/toy/plush/whiny_plushie/Initialize(mapload) + . = ..() + if(!cry_still_messages) + cry_still_messages = list( + "WHY DID WE STOP MOVING?! ARE YOU GOING TO LEAVE ME?!!", + "WE COULD GET ATTACKED WE'RE SITTING DUCKS MOVE MOOOOOOOVE!!", + "YOU'RE PLANNING ON DROPPING ME AREN'T YOU I KNOW YOU AAAAAAAREE!!", + "THE SYNDICATE ARE TRIANGULATING OUR LOCAAAAAAAATIONNN!!", + "THIS PLACE IS SCARY I WANNA LEEEEEAAAAAVVVEEEEEE!!", + "CHELP, CHELP CCCCHHHHEEEEEEEEEEEEEEELLLLLLLPPPPPP!!", + ) + cry_alone_messages = list( + "NOOOOOOOOOOOOOOOOOO DON'T LEAVE MEEEEE!!", + "WUH WHERE DID EVERYONE GOOOOOOHHHHHHH WAHHH!!", + "SOMEONE, ANYONEEEEEEEEE PICK ME UPP!!", + "I DIDN'T DESERVE ITTTTTTTTTT!!", + "I WILL DIE TO JUST ONE ATTTTTTAAAAACKKKKKK!!", + "I WILLLLLL NOT DROP GOOOD IITITTEEEEEMMMS!!", + ) + AddComponent(/datum/component/keep_me_secure, CALLBACK(src, PROC_REF(secured_process)) , CALLBACK(src, PROC_REF(unsecured_process))) + +/obj/item/toy/plush/whiny_plushie/proc/secured_process(last_move) + icon_state = initial(icon_state) + +/obj/item/toy/plush/whiny_plushie/proc/unsecured_process(last_move) + if(!COOLDOWN_FINISHED(src, cry_cooldown)) + return + COOLDOWN_START(src, cry_cooldown, 10 SECONDS) + icon_state = "plushie_whiny_crying" + if(isturf(loc)) + say(pick(cry_alone_messages)) + else + say(pick(cry_still_messages)) + playsound(src, 'sound/items/intents/Help.ogg', 50, FALSE) + /obj/item/toy/plush/beeplushie name = "bee plushie" desc = "A cute toy that resembles an even cuter bee." diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_authentication_disk.dm b/code/modules/antagonists/nukeop/equipment/nuclear_authentication_disk.dm index 633a8b7384d..a903fc02d45 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclear_authentication_disk.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclear_authentication_disk.dm @@ -18,10 +18,6 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF /// Whether we're a real nuke disk or not. var/fake = FALSE - /// The last secure location the disk was at. - var/turf/last_secured_location - /// The last world time the disk moved. - var/last_disk_move /datum/armor/disk_nuclear bomb = 30 @@ -34,54 +30,37 @@ AddComponent(/datum/component/stationloving, !fake) if(!fake) + AddComponent(/datum/component/keep_me_secure, CALLBACK(src, PROC_REF(secured_process)), CALLBACK(src, PROC_REF(unsecured_process))) SSpoints_of_interest.make_point_of_interest(src) - last_disk_move = world.time - START_PROCESSING(SSobj, src) - -/obj/item/disk/nuclear/process() - if(fake) - STOP_PROCESSING(SSobj, src) - CRASH("A fake nuke disk tried to call process(). Who the fuck and how the fuck") +/obj/item/disk/nuclear/proc/secured_process(last_move) var/turf/new_turf = get_turf(src) + var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control + if(istype(loneop) && loneop.occurrences < loneop.max_occurrences && prob(loneop.weight)) + loneop.weight = max(loneop.weight - 1, 0) + if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) + message_admins("[src] is secured (currently in [ADMIN_VERBOSEJMP(new_turf)]). The weight of Lone Operative is now [loneop.weight].") + log_game("[src] being secured has reduced the weight of the Lone Operative event to [loneop.weight].") - if (is_secured()) - last_secured_location = new_turf - last_disk_move = world.time +/obj/item/disk/nuclear/proc/unsecured_process(last_move) + var/turf/new_turf = get_turf(src) + /// How comfy is our disk? + var/disk_comfort_level = 0 + + //Go through and check for items that make disk comfy + for(var/obj/comfort_item in loc) + if(istype(comfort_item, /obj/item/bedsheet) || istype(comfort_item, /obj/structure/bed)) + disk_comfort_level++ + + if(last_move < world.time - 500 SECONDS && prob((world.time - 500 SECONDS - last_move)*0.0001)) var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control - if(istype(loneop) && loneop.occurrences < loneop.max_occurrences && prob(loneop.weight)) - loneop.weight = max(loneop.weight - 1, 0) + if(istype(loneop) && loneop.occurrences < loneop.max_occurrences) + loneop.weight += 1 if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) - message_admins("[src] is secured (currently in [ADMIN_VERBOSEJMP(new_turf)]). The weight of Lone Operative is now [loneop.weight].") - log_game("[src] being secured has reduced the weight of the Lone Operative event to [loneop.weight].") - else - /// How comfy is our disk? - var/disk_comfort_level = 0 - - //Go through and check for items that make disk comfy - for(var/obj/comfort_item in loc) - if(istype(comfort_item, /obj/item/bedsheet) || istype(comfort_item, /obj/structure/bed)) - disk_comfort_level++ - - if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.0001)) - var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control - if(istype(loneop) && loneop.occurrences < loneop.max_occurrences) - loneop.weight += 1 - if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) - if(disk_comfort_level >= 2) - visible_message(span_notice("[src] sleeps soundly. Sleep tight, disky.")) - message_admins("[src] is unsecured in [ADMIN_VERBOSEJMP(new_turf)]. The weight of Lone Operative is now [loneop.weight].") - log_game("[src] was left unsecured in [loc_name(new_turf)]. Weight of the Lone Operative event increased to [loneop.weight].") - -/obj/item/disk/nuclear/proc/is_secured() - if (last_secured_location == get_turf(src)) - return FALSE - - var/mob/holder = pulledby || get(src, /mob) - if (isnull(holder?.client)) - return FALSE - - return TRUE + if(disk_comfort_level >= 2) + visible_message(span_notice("[src] sleeps soundly. Sleep tight, disky.")) + message_admins("[src] is unsecured in [ADMIN_VERBOSEJMP(new_turf)]. The weight of Lone Operative is now [loneop.weight].") + log_game("[src] was left unsecured in [loc_name(new_turf)]. Weight of the Lone Operative event increased to [loneop.weight].") /obj/item/disk/nuclear/examine(mob/user) . = ..() diff --git a/icons/obj/toys/plushes.dmi b/icons/obj/toys/plushes.dmi index f6d957db640..1452b85aa47 100644 Binary files a/icons/obj/toys/plushes.dmi and b/icons/obj/toys/plushes.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 6cb87793c29..5113a2490a8 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -973,6 +973,7 @@ #include "code\datums\components\itempicky.dm" #include "code\datums\components\jetpack.dm" #include "code\datums\components\jousting.dm" +#include "code\datums\components\keep_me_secure.dm" #include "code\datums\components\knockoff.dm" #include "code\datums\components\label.dm" #include "code\datums\components\light_eater.dm"