Rewrite leashes to have better code quality

This commit is contained in:
Elizabeth Lavenza
2024-04-01 19:23:48 -04:00
parent 6dcccb6a02
commit 61b42df4df
@@ -45,8 +45,7 @@ Icons, maybe?
/datum/status_effect/leash_pet/on_apply()
//redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist))))
RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/owner_resist)
RegisterSignal(owner, COMSIG_LIVING_RESIST, PROC_REF(owner_resist))
redirect_component = owner
if(!owner.stat)
to_chat(owner, span_userdanger("You have been leashed!"))
@@ -79,13 +78,36 @@ Icons, maybe?
force = 1
throwforce = 1
w_class = WEIGHT_CLASS_SMALL
var/leash_used = 0 //A flag to see if the leash has been used yet, because for some reason picking up an unused leash is weird
var/mob/living/leash_pet = "null" //Variable to store our pet later
var/mob/living/leash_master = "null" //And our master too
var/mob/living/leash_pet = null //Variable to store our pet later
var/mob/living/leash_master = null //And our master too
var/mob/mobhook_leash_pet
var/mob/mobhook_leash_master //Needed to watch for these entities to move
var/mob/mobhook_leash_freepet
var/leash_location[3] //Three digit list for us to store coordinates later
/obj/item/leash/process(delta_time)
if(!leash_pet) //No pet, break loop
return PROCESS_KILL
if(!(leash_pet.get_item_by_slot(ITEM_SLOT_NECK))) //The pet has slipped their collar and is not the pet anymore.
leash_pet.visible_message(
span_warning("[leash_pet] has slipped out of their collar!"),
span_warning("You have slipped out of your collar!"),
target = leash_master,
target_message = span_warning("[leash_pet] has slipped out of their collar!")
)
leash_pet.remove_status_effect(/datum/status_effect/leash_pet)
if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet)) //If there is no pet, there is no dom. Loop breaks.
//QDEL_NULL(mobhook_leash_master)
UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_pet)
UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_freepet)
UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED)
leash_pet.remove_status_effect(/datum/status_effect/leash_freepet)
leash_pet.remove_movespeed_modifier(/datum/movespeed_modifier/leash)
leash_master?.remove_status_effect(/datum/status_effect/leash_dom)
leash_pet = null
return PROCESS_KILL
//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
@@ -103,15 +125,12 @@ Icons, maybe?
user.apply_status_effect(/datum/status_effect/leash_dom) //Is the leasher
leash_pet = C //Save pet reference for later
leash_master = user //Save dom reference for later
//mobhook_leash_pet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_pet_move)))
RegisterSignal(leash_pet, COMSIG_MOVABLE_MOVED, .proc/on_pet_move)
RegisterSignal(leash_pet, COMSIG_MOVABLE_MOVED, PROC_REF(on_pet_move))
mobhook_leash_pet = leash_pet
//mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move)))
RegisterSignal(leash_master, COMSIG_MOVABLE_MOVED, .proc/on_master_move)
RegisterSignal(leash_master, COMSIG_MOVABLE_MOVED, PROC_REF(on_master_move))
mobhook_leash_master = leash_master
leash_used = 1
if(!leash_pet.has_status_effect(/datum/status_effect/leash_dom)) //Add slowdown if the pet didn't leash themselves
leash_pet.add_movespeed_modifier(MOVESPEED_ID_LEASH)
leash_pet.add_movespeed_modifier(/datum/movespeed_modifier/leash)
for(var/mob/viewing in viewers(user, null))
if(viewing == leash_master)
to_chat(leash_master, span_warning("You have hooked a leash onto [leash_pet]!"))
@@ -120,116 +139,90 @@ Icons, maybe?
if(leash_pet.has_status_effect(/datum/status_effect/leash_dom)) //Pet leashed themself. They are not the dom
leash_pet.apply_status_effect(/datum/status_effect/leash_freepet)
leash_pet.remove_status_effect(/datum/status_effect/leash_dom)
while(1) //While true loop. The mark of a genius coder. ##MAINLOOP START
sleep(2) //Check every other tick
if(leash_pet == "null") //No pet, break loop
return
if(!(leash_pet.get_item_by_slot(ITEM_SLOT_NECK))) //The pet has slipped their collar and is not the pet anymore.
for(var/mob/viewing in viewers(user, null))
viewing.show_message(span_notice("[leash_pet] has slipped out of their collar!!"), 1)
to_chat(leash_pet, span_notice("You have slipped out of your collar!"))
to_chat(loc, span_notice("[leash_pet] has slipped out of their collar!"))
leash_pet.remove_status_effect(/datum/status_effect/leash_pet)
if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet)) //If there is no pet, there is no dom. Loop breaks.
//QDEL_NULL(mobhook_leash_master)
UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_pet)
UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_freepet)
UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED)
if(leash_pet.has_status_effect(/datum/status_effect/leash_freepet))
leash_pet.remove_status_effect(/datum/status_effect/leash_freepet)
if(leash_pet.has_movespeed_modifier(MOVESPEED_ID_LEASH))
leash_pet.remove_movespeed_modifier(MOVESPEED_ID_LEASH)
if(!leash_master == "null")
leash_master.remove_status_effect(/datum/status_effect/leash_dom)
leash_used = 0 //reset the leash to neutral
leash_pet = "null"
return
START_PROCESSING(SSfastprocess, src) // The original while loop here ran every 2 deciseconds, and so does SSfastprocess.
else //No collar, no fun
var/leash_message = pick("Your pet needs a collar")
var/leash_message = pick("[C] needs a collar before you can attach a leash to it.")
to_chat(user, span_notice("[leash_message]"))
//Called when the leash is used in hand
//Tugs the pet closer
/obj/item/leash/attack_self(mob/living/user)
if(!leash_pet == "null") //No pet, no tug.
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 == "null") //There must be a master
if(!leash_master) //There must be a master
return
if(leash_pet == "null") //There must be a pet
if(!leash_pet) //There must be a pet
return
if(leash_pet == leash_master) //Pet is the master
return
if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet))
//QDEL_NULL(mobhook_leash_master) //Probably redundant, but it's nice to be safe
UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED)
mobhook_leash_master = null
leash_master.remove_status_effect(/datum/status_effect/leash_dom)
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
sleep(2) //A small sleep so the pet kind of bounces back after they make the step
//Also, the sleep means that the distance check for master happens before the pet, to prevent both from proccing.
//Also, the timer means that the distance check for master happens before the pet, to prevent both from proccing.
if(leash_master == "null") //Just to stop error messages
if(!leash_master) //Just to stop error messages
return
if(leash_pet == "null")
if(!leash_pet)
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 == "null") //Just to stop error messages. Break the loop early if something removed the master
if(!leash_master) //Just to stop error messages. Break the loop early if something removed the master
return
if(leash_pet == "null")
if(!leash_pet)
return
if(leash_pet.x > leash_master.x + 3 || leash_pet.x < leash_master.x - 3 || leash_pet.y > leash_master.y + 3 || leash_pet.y < leash_master.y - 3)
//var/leash_knockdown_message = "[leash_pet] got pulled to the ground by their leash!"
//to_chat(leash_master, span_notice("[leash_knockdown_message]"))
//to_chat(leash_pet, span_notice("[leash_knockdown_message]"))
if(get_dist(leash_pet, leash_master) > 3)
leash_pet.visible_message(
span_warning("[leash_pet] is pulled to the ground by their leash!"),
span_warning("You are pulled to the ground by your leash!")
)
leash_pet.apply_effect(20, EFFECT_KNOCKDOWN, 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 == "null") //Just to stop error messages
if(!leash_master) //Just to stop error messages
return
if(leash_pet == "null")
if(!leash_pet)
return
if(leash_pet.x > leash_master.x + 5 || leash_pet.x < leash_master.x - 5 || leash_pet.y > leash_master.y + 5 || leash_pet.y < leash_master.y - 5)
var/leash_break_message = "The leash snapped free from [leash_pet]!"
for(var/mob/viewing in viewers(leash_pet, null))
if(viewing == leash_master)
to_chat(leash_master, span_warning("The leash snapped free from your pet!"))
if(viewing == leash_pet)
to_chat(leash_pet, span_warning("Your leash has popped from your collar!"))
else
viewing.show_message(span_warning("[leash_break_message]"), 1)
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!"),
target = leash_master,
target_message = span_warning("The leash snaps free from your pet's collar!")
)
leash_pet.apply_effect(20, EFFECT_KNOCKDOWN, 0)
leash_pet.adjustOxyLoss(5)
leash_pet.remove_status_effect(/datum/status_effect/leash_pet)
leash_pet.remove_movespeed_modifier(MOVESPEED_ID_LEASH)
leash_pet.remove_movespeed_modifier(/datum/movespeed_modifier/leash)
leash_master.remove_status_effect(/datum/status_effect/leash_dom)
//QDEL_NULL(mobhook_leash_master)
UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_pet)
UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED)
leash_pet = "null"
leash_master = "null"
leash_used = 0
mobhook_leash_master = null
mobhook_leash_pet = null
leash_pet = null
leash_master = null
/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 == "null")
if(!leash_master)
return
if(leash_pet == "null")
if(!leash_pet)
return
//Make sure the pet is still a pet
if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet))
@@ -240,84 +233,43 @@ Icons, maybe?
//The pet has escaped. There is no DOM. GO PET RUN.
if(leash_pet.has_status_effect(/datum/status_effect/leash_freepet))//If the pet is free, break
return
//If the pet gets too far away, they get tugged back
sleep(3)//A small sleep so the pet kind of bounces back after they make the step
if(leash_master == "null")
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)
return
if(leash_pet == "null")
if(!leash_pet)
return
//West tug
if(leash_pet.x > leash_master.x + 2)
step(leash_pet, WEST, 1) //"1" is the speed of movement. We want the tug to be faster than their slow current walk speed.
//East tug
if(leash_pet.x < leash_master.x - 2)
step(leash_pet, EAST, 1)
//South tug
if(leash_pet.y > leash_master.y + 2)
step(leash_pet, SOUTH, 1)
//North tug
if(leash_pet.y < leash_master.y - 2)
step(leash_pet, NORTH, 1)
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/proc/on_freepet_move()
SIGNAL_HANDLER
//Pet is on the run. Let's drag the leash behind them.
if(!leash_master == "null") //If there is a master, don't do this
if(leash_master) //If there is a master, don't do this
return
if(leash_pet == "null") //If there is no pet, don't do this
if(!leash_pet) //If there is no pet, don't do this
return
if(leash_pet.is_holding_item_of_type(/obj/item/leash)) //If the pet is holding the leash, don't do this
if(leash_pet.is_holding(src)) //If the pet is holding the leash, don't do this
return
sleep(2)
if(leash_pet == "null")
//If the pet gets too far away, we get tugged to them.
addtimer(CALLBACK(src, PROC_REF(after_freepet_move)), 0.2 SECONDS, TIMER_UNIQUE) //A short timer so the leash trails behind us.
/obj/item/leash/proc/after_freepet_move()
if(!leash_pet)
return
//Double move to catch the leash up to the pet
if(src.x > leash_pet.x + 2)
. = step(src, WEST, 1)
if(src.x < leash_pet.x - 2)
. = step(src, EAST, 1)
if(src.y > leash_pet.y + 2)
. = step(src, SOUTH, 1)
if(src.y < leash_pet.y - 2)
. = step(src, NORTH, 1)
//Primary dragging code
if(src.x > leash_pet.x + 1)
. = step(src, WEST, 1) //"1" is the speed of movement. We want the tug to be faster than their slow current walk speed.
if(src.y > leash_pet.y)//Check the other axis, and tug them into alignment so they are behind the pet
. = step(src, SOUTH, 1)
if(src.y < leash_pet.y)
. = step(src, NORTH, 1)
if(src.x < leash_pet.x - 1)
. = step(src, EAST, 1)
if(src.y > leash_pet.y)
. = step(src, SOUTH, 1)
if(src.y < leash_pet.y)
. = step(src, NORTH, 1)
if(src.y > leash_pet.y + 1)
. = step(src, SOUTH, 1)
if(src.x > leash_pet.x)
. = step(src, WEST, 1)
if(src.x < leash_pet.x)
. = step(src, EAST, 1)
if(src.y < leash_pet.y - 1)
. = step(src, NORTH, 1)
if(src.x > leash_pet.x)
. = step(src, WEST, 1)
if(src.x < leash_pet.x)
. = step(src, EAST, 1)
for(var/i in 3 to get_dist(src, leash_pet)) // Move us to a minimum of 2 tiles away from the pet, so we trail behind them.
step_towards(src, leash_pet)
sleep(1)
//Just to prevent error messages
if(leash_pet == "null")
if(!leash_pet)
return
if(src.x > leash_pet.x + 5 || src.x < leash_pet.x - 5 || src.y > leash_pet.y + 5 || src.y < leash_pet.y - 5)
var/leash_break_message = "The leash snapped free from [leash_pet]!"
for(var/mob/viewing in viewers(leash_pet, null))
if(viewing == leash_pet)
to_chat(leash_pet, span_warning("Your leash has popped from your collar!"))
else
viewing.show_message(span_warning("[leash_break_message]"), 1)
if(get_dist(src, leash_pet) > 5)
leash_pet.visible_message(span_warning("\The [src] snaps free from \the [leash_pet]!"), span_warning("Your leash pops free from your collar!"))
leash_pet.apply_effect(20, EFFECT_KNOCKDOWN, 0)
leash_pet.adjustOxyLoss(5)
leash_pet.remove_status_effect(/datum/status_effect/leash_pet)
@@ -326,57 +278,62 @@ Icons, maybe?
UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED)
//QDEL_NULL(mobhook_leash_freepet)
UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED)
leash_pet = "null"
leash_used = 0
leash_pet = null
//The proc below in question is the one causing all the errors apparently
/obj/item/leash/dropped(mob/user, silent)
//Drop the leash, and the leash effects stop
. = ..()
if(leash_pet == "null") //There is no pet. Stop this silliness
if(!leash_pet) //There is no pet. Stop this silliness
return
if(leash_master == "null")
if(!leash_master)
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/drop_effects, user, silent), 1)
addtimer(CALLBACK(src, PROC_REF(drop_effects), user, silent), 1)
/obj/item/leash/proc/drop_effects(mob/user, silent)
if(leash_master.is_holding_item_of_type(/obj/item/leash) || istype(leash_master.get_item_by_slot(ITEM_SLOT_BELT), /obj/item/leash))
SIGNAL_HANDLER
if(leash_master.is_holding(src) || leash_master.get_item_by_slot(ITEM_SLOT_BELT) == src)
return //Dom still has the leash as it turns out. Cancel the proc.
for(var/mob/viewing in viewers(leash_master, null))
viewing.show_message(span_notice("[leash_master] has dropped the leash."), 1)
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.
leash_pet.remove_movespeed_modifier(MOVESPEED_ID_LEASH)
//mobhook_leash_freepet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_freepet_move)))
RegisterSignal(leash_pet, COMSIG_MOVABLE_MOVED, .proc/on_freepet_move)
leash_pet.remove_movespeed_modifier(/datum/movespeed_modifier/leash)
UnregisterSignal(leash_pet, COMSIG_MOVABLE_MOVED)
mobhook_leash_freepet = leash_pet
RegisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED, PROC_REF(on_freepet_move))
leash_master.remove_status_effect(/datum/status_effect/leash_dom) //No dom with no leash. We will get a new dom if the leash is picked back up.
leash_master = "null"
leash_master = null
//QDEL_NULL(mobhook_leash_master)
UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED)
/obj/item/leash/equipped(mob/user)
. = ..()
if(leash_used == 0) //Don't apply statuses with a fresh leash. Keeps things clean on the backend.
if(!leash_pet) //Don't apply statuses with a petless leash.
return
addtimer(CALLBACK(src, .proc/equip_effects, user), 2)
addtimer(CALLBACK(src, PROC_REF(equip_effects), user), 2)
/obj/item/leash/proc/equip_effects(mob/user)
if(leash_pet == "null")
if(!leash_pet)
return
if(leash_master == user)
return // Don't double-register.
if(leash_pet == user) //Pet picked up their own leash.
leash_master = null
return
leash_master = user
if(leash_master.has_status_effect(/datum/status_effect/leash_freepet) || leash_master.has_status_effect(/datum/status_effect/leash_pet)) //Pet picked up their own leash.
leash_master = "null"
return
leash_master.apply_status_effect(/datum/status_effect/leash_dom)
//mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move)))
RegisterSignal(leash_master, COMSIG_MOVABLE_MOVED, .proc/on_master_move)
RegisterSignal(leash_master, COMSIG_MOVABLE_MOVED, PROC_REF(on_master_move))
mobhook_leash_master = leash_master
leash_pet.remove_status_effect(/datum/status_effect/leash_freepet)
//QDEL_NULL(mobhook_leash_freepet)
UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED)
leash_pet.add_movespeed_modifier(MOVESPEED_ID_LEASH)
if(mobhook_leash_freepet)
UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED)
leash_pet.add_movespeed_modifier(/datum/movespeed_modifier/leash)
/datum/movespeed_modifier/leash
id = MOVESPEED_ID_LEASH
multiplicative_slowdown = 5
/*/datum/crafting_recipe/leash
name = "Leash"