Files
VOREStation/code/game/objects/items/leash.dm
Cameron Lennox d5849910e5 Begin clickcode attack_self fix (#18797)
* Begin clickcode attack_self fix

Begins the work to make everything call back to parent for attack_self so that signals are sacred.

* Makes MORE things call the attack_self() parent

Yes, I could make special_handling a var on obj/item HOWEVER i want it to be specific so it can be tracked down later and ONLY the objects that use it can be refactored instead of sitting there literally forever and it just becoming 'a thing'.

* Finishes making the rest of attack_self call parent.

As mentioned, things such as 'specialty_goggles' 'special_handling' and the such are only there to help with attack_self until the attack_self is recoded for those items.

* begone foul demon

* some more cleanup

* These

* GOD this was annoying

* yeh

* Fix this

* fLARES

* Thesee too

* toys!

* Even more!

* More fixes

* Even more

* rest of em

* these too

* Update syndie.dm

* hardref clear

* Update code/game/gamemodes/nuclear/pinpointer.dm

* Update code/game/objects/effects/mines.dm

* Update code/game/objects/items/blueprints_vr.dm

* Update code/game/objects/items/blueprints_vr.dm

* Update code/game/objects/items/contraband_vr.dm

* Update code/game/objects/items/crayons.dm

* Update code/game/objects/items/crayons.dm

* Update code/game/objects/items/gunbox.dm

* Update code/game/objects/items/gunbox.dm

* Update code/game/objects/items/gunbox_vr.dm

* Update code/game/objects/items/gunbox_vr.dm

* Update code/game/objects/items/weapons/gift_wrappaper.dm

* Update code/game/objects/items/crayons.dm

* Update code/game/objects/items/crayons.dm

* Update code/game/objects/items/gunbox.dm

* these too

* Update maintpanel_stack.dm

* angry warning

* Fixes packaged snacks.

Fixes improper var default.

* Special handling for these

* proper poly types

* Fixes magclaws

Makes the 'features' it had just part  of base magboots that can be adjusted via varswap.

* Fixes jackets

Fixes https://github.com/VOREStation/VOREStation/issues/18941

* Small bugfix

Makes p_Theyre properly capitialize
Makes examine show proper wording

* Update gift_wrappaper.dm
2025-12-29 13:21:10 -05:00

275 lines
10 KiB
Plaintext

/atom/movable/screen/alert/leash_dom
name = "Leash Holder"
desc = "You're holding a leash, with someone on the end."
icon_state = "leash_master"
/atom/movable/screen/alert/leash_dom/Click()
var/obj/item/leash/owner = master
owner.unleash()
/atom/movable/screen/alert/leash_pet
name = "Leashed"
desc = "You're on the hook now!"
icon_state = "leash_pet"
/atom/movable/screen/alert/leash_dom/Click()
var/obj/item/leash/owner = master
owner.struggle_leash()
///// OBJECT /////
//The leash object itself
//The component variables are used for hooks, used later.
/obj/item/leash
name = "leash"
desc = "A simple tether that can easily be hooked onto a collar. Usually used to keep pets nearby."
icon = 'icons/obj/leash.dmi'
icon_state = "leash"
item_state = "leash"
throw_range = 4
slot_flags = SLOT_TIE
force = 1
throwforce = 1
w_class = ITEMSIZE_SMALL
var/mob/living/leash_pet = null //Variable to store our pet later
var/mob/living/leash_master = null //And our master too
/obj/item/leash/Destroy()
// Just in case
clear_leash()
return ..()
/obj/item/leash/process()
if(!leash_pet)
return
if(!is_wearing_collar(leash_pet)) //The pet has slipped their collar and is not the pet anymore.
leash_pet.visible_message(
span_warning("[leash_pet] has slipped out of [leash_pet.p_their()] collar!"),
span_warning("You have slipped out of your collar!")
)
clear_leash()
if(!leash_pet || !leash_master) //If there is no pet, there is no dom. Loop breaks.
clear_leash()
//Called when someone is clicked with the leash
/obj/item/leash/attack(mob/living/carbon/C, mob/living/user, attackchain_flags, damage_multiplier) //C is the target, user is the one with the leash
if(C.alerts && C.alerts["leashed"]) //If the pet is already leashed, do not leash them. For the love of god.
// If they re-click, remove the leash
if (C == leash_pet && user == leash_master)
unleash()
else
// Dear god not the double leashing
to_chat(user, span_notice("[C] has already been leashed."))
return
if (C == user)
to_chat(user, span_notice("You cannot leash yourself!"))
return
if (!is_wearing_collar(C))
to_chat(user, span_notice("[C] needs a collar before you can attach a leash to it."))
return
var/leashtime = 35
if(C.handcuffed)
leashtime = 5
C.visible_message(span_danger("\The [user] is attempting to put the leash on \the [C]!"), span_danger("\The [user] tries to put a leash on you"))
add_attack_logs(user,C,"Leashed (attempt)")
if(!do_after(user, leashtime, C)) //do_mob adds a progress bar, but then we also check to see if they have a collar
return
if(tgui_alert(C, "Would you like to be leased by [user]? You can OOC escape to escape", "Become Leashed",list("No","Yes")) != "Yes")
return
C.visible_message(span_danger("\The [user] puts a leash on \the [C]!"), span_danger("The leash clicks onto your collar!"))
leash_pet = C //Save pet reference for later
leash_pet.add_modifier(/datum/modifier/leash)
leash_pet.throw_alert("leashed", /atom/movable/screen/alert/leash_pet, new_master = src) //Is the leasher
RegisterSignal(leash_pet, COMSIG_MOVABLE_MOVED, PROC_REF(on_pet_move))
to_chat(leash_pet, span_userdanger("You have been leashed!"))
to_chat(leash_pet, span_danger("(You can use OOC escape to detach the leash)"))
leash_master = user //Save dom reference for later
leash_master.throw_alert("leash", /atom/movable/screen/alert/leash_dom, new_master = src)//Has now been leashed
RegisterSignal(leash_master, COMSIG_MOVABLE_MOVED, PROC_REF(on_master_move))
START_PROCESSING(SSobj, src)
//Called when the leash is used in hand
//Tugs the pet closer
/obj/item/leash/attack_self(mob/living/user)
. = ..(user)
if(.)
return TRUE
if(!leash_pet) //No pet, no tug.
return
//Yank the pet. Yank em in close.
apply_tug_mob_to_mob(leash_pet, leash_master, 1)
/obj/item/leash/proc/on_master_move()
SIGNAL_HANDLER
//Make sure the dom still has a pet
if(!leash_master || !leash_pet)
return
addtimer(CALLBACK(src, PROC_REF(after_master_move)), 0.2 SECONDS)
/obj/item/leash/proc/after_master_move()
//If the master moves, pull the pet in behind
//Also, the timer means that the distance check for master happens before the pet, to prevent both from proccing.
if(!leash_master || !leash_pet) //Just to stop error messages
return
apply_tug_mob_to_mob(leash_pet, leash_master, 2)
//Knock the pet over if they get further behind. Shouldn't happen too often.
sleep(3) //This way running normally won't just yank the pet to the ground.
if(!leash_master || !leash_pet) //Just to stop error messages. Break the loop early if something removed the master
return
if(get_dist(leash_pet, leash_master) > 3 && !leash_pet.stunned)
leash_pet.visible_message(
span_warning("[leash_pet] is pulled to the ground by [leash_pet.p_their()] leash!"),
span_warning("You are pulled to the ground by your leash!")
)
leash_pet.apply_effect(20, STUN, 0)
//This code is to check if the pet has gotten too far away, and then break the leash.
sleep(3) //Wait to snap the leash
if(!leash_master || !leash_pet) //Just to stop error messages
return
if(get_dist(leash_pet, leash_master) > 5)
leash_pet.visible_message(
span_warning("The leash snaps free from [leash_pet]'s collar!"),
span_warning("Your leash pops from your collar!")
)
leash_pet.apply_effect(20, STUN, 0)
leash_pet.adjustOxyLoss(5)
clear_leash()
/obj/item/leash/proc/on_pet_move()
SIGNAL_HANDLER
//This should only work if there is a pet and a master.
//This is here pretty much just to stop the console from flooding with errors
if(!leash_master || !leash_pet)
return
//If the pet gets too far away, they get tugged back
addtimer(CALLBACK(src, PROC_REF(after_pet_move)), 0.3 SECONDS) //A short timer so the pet kind of bounces back after they make the step
/obj/item/leash/proc/after_pet_move()
if(!leash_master || !leash_pet)
return
for(var/i in 3 to get_dist(leash_pet, leash_master)) // Move the pet to a minimum of 2 tiles away from the master, so the pet trails behind them.
step_towards(leash_pet, leash_master)
/obj/item/leash/dropped(mob/user)
//Drop the leash, and the leash effects stop
. = ..()
if(!leash_pet || !leash_master) //There is no pet. Stop this silliness
return
//Dropping procs any time the leash changes slots. So, we will wait a tick and see if the leash was actually dropped
addtimer(CALLBACK(src, PROC_REF(drop_effects), user), 1)
/obj/item/leash/proc/drop_effects(mob/user)
SIGNAL_HANDLER
if(leash_master.item_is_in_hands(src) || leash_master.get_item_by_slot(SLOT_TIE) == src)
return //Dom still has the leash as it turns out. Cancel the proc.
leash_master.visible_message(span_notice("\The [leash_master] drops \the [src]."), span_notice("You drop \the [src]."))
//DOM HAS DROPPED LEASH. PET IS FREE. SCP HAS BREACHED CONTAINMENT.
clear_leash()
/obj/item/leash/proc/clear_leash()
leash_pet?.clear_alert("leashed")
leash_pet?.remove_a_modifier_of_type(/datum/modifier/leash)
UnregisterSignal(leash_pet, COMSIG_MOVABLE_MOVED)
leash_pet = null
leash_master?.clear_alert("leash")
UnregisterSignal(leash_master, COMSIG_MOVABLE_MOVED)
leash_master = null
STOP_PROCESSING(SSobj, src)
/obj/item/leash/proc/struggle_leash()
leash_pet.visible_message(span_danger("\The [leash_pet] is attempting to unhook [leash_pet.p_their()] leash!"), span_danger("You attempt to unhook your leash"))
add_attack_logs(leash_master,leash_pet,"Self-unleash (attempt)")
if(!do_after(leash_pet, 3.5 SECONDS, leash_pet))
return
to_chat(leash_pet, span_userdanger("You have been released!"))
clear_leash()
/obj/item/leash/proc/unleash()
leash_pet.visible_message(span_danger("\The [leash_master] is attempting to remove the leash on \the [leash_pet]!"), span_danger("\The [leash_master] tries to remove leash from you"))
add_attack_logs(leash_master,leash_pet,"Unleashed (attempt)")
if(!do_after(leash_master, 0.5 SECONDS, leash_pet))
return
to_chat(leash_pet, span_userdanger("You have been released!"))
clear_leash()
/obj/item/leash/proc/is_wearing_collar(var/mob/living/carbon/human/human)
if (!istype(human))
return FALSE
for (var/obj/item/clothing/worn in human.worn_clothing)
if (istype(worn, /obj/item/clothing/accessory/collar) || (locate(/obj/item/clothing/accessory/collar) in worn.accessories))
return TRUE
return FALSE
/datum/modifier/leash
name = "Leash"
slowdown = 5
// Utility functions
/obj/item/proc/apply_tug_mob_to_mob(mob/living/carbon/tug_pet, mob/living/carbon/tug_master, distance = 2)
apply_tug_position(tug_pet, tug_pet.x, tug_pet.y, tug_master.x, tug_master.y, distance)
/obj/item/proc/apply_tug_mob_to_object(mob/living/carbon/tug_pet, obj/tug_master, distance = 2)
apply_tug_position(tug_pet, tug_pet.x, tug_pet.y, tug_master.x, tug_master.y, distance)
/obj/item/proc/apply_tug_object_to_mob(obj/tug_pet, mob/living/carbon/tug_master, distance = 2)
apply_tug_position(tug_pet, tug_pet.x, tug_pet.y, tug_master.x, tug_master.y, distance)
// TODO: improve this for bigger distances, where it's easy to hide behind something and break the tugging
/obj/item/proc/apply_tug_position(tug_pet, tug_pet_x, tug_pet_y, tug_master_x, tug_master_y, distance = 2)
if(tug_pet_x > tug_master_x + distance)
step(tug_pet, WEST, 1) //"1" is the speed of movement. We want the tug to be faster than their slow current walk speed.
if(tug_pet_y > tug_master_y)//Check the other axis, and tug them into alignment so they are behind the master
step(tug_pet, SOUTH, 1)
if(tug_pet_y < tug_master_y)
step(tug_pet, NORTH, 1)
if(tug_pet_x < tug_master_x - distance)
step(tug_pet, EAST, 1)
if(tug_pet_y > tug_master_y)
step(tug_pet, SOUTH, 1)
if(tug_pet_y < tug_master_y)
step(tug_pet, NORTH, 1)
if(tug_pet_y > tug_master_y + distance)
step(tug_pet, SOUTH, 1)
if(tug_pet_x > tug_master_x)
step(tug_pet, WEST, 1)
if(tug_pet_x < tug_master_x)
step(tug_pet, EAST, 1)
if(tug_pet_y < tug_master_y - distance)
step(tug_pet, NORTH, 1)
if(tug_pet_x > tug_master_x)
step(tug_pet, WEST, 1)
if(tug_pet_x < tug_master_x)
step(tug_pet, EAST, 1)
/obj/item/leash/cable
name = "cable leash"
desc = "A simple tether that can easily be hooked onto a collar. This one is made from wiring cable."
icon = 'icons/obj/leash.dmi'
icon_state = "cable"
/datum/crafting_recipe/leash
name = "cable leash"
result = /obj/item/leash/cable
reqs = list(
list(/obj/item/stack/cable_coil = 3)
)
time = 60
category = CAT_MISC