diff --git a/code/datums/components/remote_view.dm b/code/datums/components/remote_view.dm index 1e16f463676..06224e3c29a 100644 --- a/code/datums/components/remote_view.dm +++ b/code/datums/components/remote_view.dm @@ -485,7 +485,7 @@ // Yes this spawn is needed, yes I wish it wasn't. spawn(0) // Decouple the view to the turf on drop, or we'll be stuck on the mob that dropped us forever - if(!QDELETED(cache_mob)) + if(!QDELETED(cache_mob) && cache_mob.client) cache_mob.AddComponent(/datum/component/remote_view, focused_on = release_turf, viewsize = null, vconfig_path = /datum/remote_view_config/turf_decoupling) cache_mob.client.eye = release_turf // Yes-- cache_mob.client.perspective = EYE_PERSPECTIVE // --this is required too. diff --git a/code/game/objects/items/leash.dm b/code/game/objects/items/leash.dm index 0bb1aa314fd..31dcc246ddd 100644 --- a/code/game/objects/items/leash.dm +++ b/code/game/objects/items/leash.dm @@ -30,8 +30,8 @@ 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 + var/datum/weakref/leash_pet_ref + var/datum/weakref/leash_master_ref /obj/item/leash/Destroy() // Just in case @@ -39,6 +39,8 @@ return ..() /obj/item/leash/process() + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() if(!leash_pet) return if(!is_wearing_collar(leash_pet)) //The pet has slipped their collar and is not the pet anymore. @@ -53,6 +55,8 @@ //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 + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() 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) @@ -83,15 +87,15 @@ 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)) + leash_pet_ref = WEAKREF(C) //Save pet reference for later + C.add_modifier(/datum/modifier/leash) + C.throw_alert("leashed", /atom/movable/screen/alert/leash_pet, new_master = src) //Is the leasher + RegisterSignal(C, COMSIG_MOVABLE_MOVED, PROC_REF(on_pet_move)) + to_chat(C, span_userdanger("You have been leashed!")) + to_chat(C, span_danger("(You can use OOC escape to detach the leash)")) + leash_master_ref = WEAKREF(user) //Save dom reference for later + user.throw_alert("leash", /atom/movable/screen/alert/leash_dom, new_master = src)//Has now been leashed + RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_master_move)) START_PROCESSING(SSobj, src) @@ -101,14 +105,17 @@ . = ..(user) if(.) return TRUE - if(!leash_pet) //No pet, no tug. + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() + if(!leash_pet || leash_master) //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 - + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() //Make sure the dom still has a pet if(!leash_master || !leash_pet) return @@ -117,6 +124,8 @@ /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. + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() if(!leash_master || !leash_pet) //Just to stop error messages return apply_tug_mob_to_mob(leash_pet, leash_master, 2) @@ -124,29 +133,33 @@ //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 + clear_leash() 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) + leash_pet.apply_effect(5, 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 + clear_leash() 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.apply_effect(5, STUN, 0) leash_pet.adjustOxyLoss(5) clear_leash() /obj/item/leash/proc/on_pet_move() SIGNAL_HANDLER + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() //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) @@ -156,6 +169,8 @@ 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() + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() 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. @@ -164,32 +179,44 @@ /obj/item/leash/dropped(mob/user, equipping, slot) //Drop the leash, and the leash effects stop . = ..() + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() if(!leash_pet || !leash_master) //There is no pet. Stop this silliness + clear_leash() 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) + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() + if(leash_master && (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].")) + if(leash_master) + 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) + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() + if(leash_pet) + 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) + if(leash_master) + leash_master.clear_alert("leash") + UnregisterSignal(leash_master, COMSIG_MOVABLE_MOVED) leash_master = null STOP_PROCESSING(SSobj, src) /obj/item/leash/proc/struggle_leash() + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() 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)") @@ -200,6 +227,8 @@ clear_leash() /obj/item/leash/proc/unleash() + var/mob/living/carbon/human/leash_pet = leash_pet_ref?.resolve() + var/mob/living/carbon/human/leash_master = leash_master_ref?.resolve() 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)") diff --git a/code/game/objects/items/weapons/storage/quickdraw.dm b/code/game/objects/items/weapons/storage/quickdraw.dm index 6b2eabcdaa9..41f4f76985e 100644 --- a/code/game/objects/items/weapons/storage/quickdraw.dm +++ b/code/game/objects/items/weapons/storage/quickdraw.dm @@ -14,21 +14,22 @@ //When set to 1, a click while it is equipped will instead move the first item inside it to your hand var/quickmode = 0 -/obj/item/storage/quickdraw/attack_hand(mob/user as mob) - if(src.loc == user) //If they aren't holding us, we do nothing special +/obj/item/storage/quickdraw/attack_hand(mob/user) + if(loc == user) //If they aren't holding us, we do nothing special if(ishuman(user)) var/mob/living/carbon/human/H = user if(quickmode) - var/first_item = contents[1] - if(first_item && !H.get_active_hand()) //Do we have anything to give you? - H.put_in_hands(first_item) - return + if(length(contents)) + var/first_item = contents[1] + if(first_item && !H.get_active_hand()) //Do we have anything to give you? + H.put_in_hands(first_item) + return if(H.l_store == src && !H.get_active_hand()) //overrides - src.open(user) + open(user) return if(H.r_store == src && !H.get_active_hand()) - src.open(user) + open(user) return ..() //Nothing special happened, go call the other proc diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index beab9c99231..3251ae9cc20 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -66,18 +66,14 @@ ADMIN_VERB_AND_CONTEXT_MENU(jumptomob, R_ADMIN|R_MOD|R_DEBUG|R_EVENT, "Jump to M else to_chat(A, span_filter_adminlog("This mob is not located in the game world.")) -ADMIN_VERB(jumptocoord, R_ADMIN|R_MOD|R_DEBUG|R_EVENT,"Jump to Coordinate", "Jump to the target coordinates.", ADMIN_CATEGORY_GAME) +ADMIN_VERB(jumptocoord, R_ADMIN|R_MOD|R_DEBUG|R_EVENT,"Jump to Coordinate", "Jump to the target coordinates.", ADMIN_CATEGORY_GAME, tx, ty, tz) if(!CONFIG_GET(flag/allow_admin_jump)) tgui_alert_async(user, "Admin jumping disabled") return - - var/tx - var/ty - var/tz - - tx = tgui_input_number(user, "Select the target x coordinate", "X Loc", 1, world.maxx, 1) - ty = tgui_input_number(user, "Select the target y coordinate", "Y Loc", 1, world.maxy, 1) - tz = tgui_input_number(user, "Select the target z coordinate", "Z Loc", 1, world.maxz, 1) + if(!tx || !ty || !tz) + tx = tgui_input_number(user, "Select the target x coordinate", "X Loc", 1, world.maxx, 1) + ty = tgui_input_number(user, "Select the target y coordinate", "Y Loc", 1, world.maxy, 1) + tz = tgui_input_number(user, "Select the target z coordinate", "Z Loc", 1, world.maxz, 1) var/mob/user_mob = user.mob user_mob.on_mob_jump() diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index d737b48e5d0..3fdf3bc8359 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -415,16 +415,17 @@ if(equipping && slot && slot == slot_gloves) var/obj/item/clothing/G = H.gloves if(istype(G)) + to_chat(user, "You slip \the [src] on over \the [H.gloves].") if(istype(G, /obj/item/clothing/gloves)) gloves = H.gloves - H.unEquip(gloves, TRUE, src) - to_chat(user, "You slip \the [src] on over \the [gloves].") else if(istype(G, /obj/item/clothing/accessory)) ring = H.gloves - H.unEquip(ring, TRUE, src) - to_chat(user, "You slip \the [src] on over \the [ring].") + else + gloves = H.gloves //Fallback + H.unEquip(H.gloves, TRUE, src) if(!(flags & THICKMATERIAL)) - punch_force += gloves.punch_force + if(istype(G, /obj/item/clothing/gloves) || istype(G, /obj/item/clothing/accessory)) //Because sometimes you can wear non-glove items on your hands. + punch_force += ring.punch_force return //Taking our gloves off? Put our former gloves / ring on. diff --git a/code/modules/food/kitchen/cooking_machines/_appliance.dm b/code/modules/food/kitchen/cooking_machines/_appliance.dm index 2c26f08097b..979dfe75e35 100644 --- a/code/modules/food/kitchen/cooking_machines/_appliance.dm +++ b/code/modules/food/kitchen/cooking_machines/_appliance.dm @@ -1,9 +1,5 @@ // This folder contains code that was originally ported from Apollo Station and then refactored/optimized/changed. -// Tracks precooked food to stop deep fried baked grilled grilled grilled diona nymph cereal. -/obj/item/reagent_containers/food/snacks - var/tmp/list/cooked = list() - // Root type for cooking machines. See following files for specific implementations. /obj/machinery/appliance name = "cooker" @@ -216,10 +212,7 @@ // We're trying to cook something else. Check if it's valid. var/obj/item/reagent_containers/food/snacks/check = I - if(istype(check) && islist(check.cooked) && (cook_type in check.cooked)) - to_chat(user, span_warning("\The [check] has already been [cook_type].")) - return 0 - else if(istype(check, /obj/item/reagent_containers/glass)) + if(istype(check, /obj/item/reagent_containers/glass)) to_chat(user, span_warning("That would probably break [src].")) return 0 else if(istype(check, /obj/item/disk/nuclear)) @@ -428,11 +421,9 @@ var/obj/cook_path = output_options[CI.combine_target] var/list/words = list() - var/list/cooktypes = list() for(var/obj/item/reagent_containers/food/snacks/S in CI.container) words |= splittext(S.name, " ") - cooktypes |= S.cooked //Set the name. words -= list("and", "the", "in", "is", "bar", "raw", "sticks", "boiled", "fried", "deep", "-o-", "warm", "two", "flavored") @@ -487,7 +478,6 @@ for(var/obj/item/reagent_containers/food/snacks/R as anything in results) R.forceMove(C) //Move everything from the buffer back to the container - R.cooked |= cook_type QDEL_NULL(temp) //delete buffer object . = 1 //None of the rest of this function is relevant for recipe cooking @@ -513,7 +503,6 @@ var/cook_path = output_options[CI.combine_target] var/list/words = list() - var/list/cooktypes = list() var/datum/reagents/buffer = new /datum/reagents(1000) var/totalcolour var/reagents_determine_color @@ -532,7 +521,6 @@ continue words |= splittext(S.name," ") - cooktypes |= S.cooked if (S.reagents && S.reagents.total_volume > 0) if (S.filling_color) @@ -606,8 +594,6 @@ if (!result) return - result.cooked |= cook_type - // Set icon and appearance. change_product_appearance(result, CI) diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 746c022b03b..4483f9950d2 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -684,6 +684,10 @@ if(isnull(gene_chem[i])) gene_chem[i] = 0 + var/list/chems_rid = chems[rid] + if(istype(chems_rid) && (chems_rid.len < i)) + continue + if(chems[rid][i]) chems[rid][i] = max(1,round((gene_chem[i] + chems[rid][i])/2)) else @@ -836,13 +840,11 @@ var/clr if(get_trait(TRAIT_BIOLUM_COLOUR)) clr = get_trait(TRAIT_BIOLUM_COLOUR) - //VOREStation Edit Start - Tons of super bright super long range lights everywhere is annoying and laggy, so let's limit it a bit. var/blight = get_trait(TRAIT_BIOLUM) if(blight >= 5) blight = 5 product.set_light(blight, 0.5, l_color = clr) - //VOREStation Edit End - if(get_trait(TRAIT_STINGS)) + if(get_trait(TRAIT_STINGS) && isitem(product)) //Sometimes the product can be a mob. product.force = 1 //Handle spawning in living, mobile products (like dionaea). diff --git a/code/modules/xenobio/items/slimepotions.dm b/code/modules/xenobio/items/slimepotions.dm index 739dd7d0ad6..a68e51fe1fc 100644 --- a/code/modules/xenobio/items/slimepotions.dm +++ b/code/modules/xenobio/items/slimepotions.dm @@ -91,6 +91,7 @@ var/mob/living/simple_mob/slime/xenobio/S = M if(S.harmless) to_chat(user, span_warning("The slime is already docile!")) + currently_using = FALSE return ..() S.pacify() @@ -102,10 +103,12 @@ else if(isanimal(M)) var/mob/living/simple_mob/SM = M if(!(SM.mob_class & (MOB_CLASS_SLIME|MOB_CLASS_ANIMAL))) // So you can't use this on Russians/syndies/hivebots/etc. - to_chat(user, span_warning("\The [SM] only works on slimes and animals.")) + to_chat(user, span_warning("\The [src] only works on slimes and animals.")) + currently_using = FALSE return ..() if(!AI.hostile) to_chat(user, span_warning("\The [SM] is already passive!")) + currently_using = FALSE return ..() AI.hostile = FALSE