Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 56 additions & 76 deletions _maps/RandomZLevels/VR/yuma_VR.dmm

Large diffs are not rendered by default.

15 changes: 1 addition & 14 deletions _maps/map_files/Tipton/Tipton-Dungeon.dmm
Original file line number Diff line number Diff line change
Expand Up @@ -9545,19 +9545,6 @@
},
/turf/open/floor/plasteel/f13/vault_floor/floor,
/area/f13/vault/dormitory)
"kTK" = (
/obj/docking_port/stationary{
area_type = /area/f13;
dir = 2;
dwidth = 1;
height = 1;
id = "North_Ground";
name = "Ground";
roundstart_template = /datum/map_template/shuttle/northbunker/elevator;
width = 4
},
/turf/open/floor/plasteel/elevatorshaft,
/area/f13/bunker/bunkertwo)
"kTV" = (
/obj/machinery/light{
bulb_colour = "#BC8F8F";
Expand Down Expand Up @@ -106602,7 +106589,7 @@ epd
epd
epd
rZT
kTK
orH
orH
orH
oLw
Expand Down
6 changes: 3 additions & 3 deletions code/controllers/subsystem/statpanel.dm
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ SUBSYSTEM_DEF(statpanels)
if(length(turfitems) < 30) // only create images for the first 30 items on the turf, for performance reasons
if(!(REF(turf_content) in cached_images))
cached_images += REF(turf_content)
turf_content.RegisterSignal(turf_content, COMSIG_PARENT_QDELETING, TYPE_PROC_REF(/atom, remove_from_cache)) // we reset cache if anything in it gets deleted
RegisterSignal(turf_content, COMSIG_PARENT_QDELETING, PROC_REF(remove_from_cache), override = TRUE)
if(ismob(turf_content) || length(turf_content.overlays) > 2)
turfitems[++turfitems.len] = list("[turf_content.name]", REF(turf_content), costly_icon2html(turf_content, target, sourceonly=TRUE))
else
Expand Down Expand Up @@ -170,9 +170,9 @@ SUBSYSTEM_DEF(statpanels)
mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", "\ref[GLOB.cameranet]")
mc_data_encoded = url_encode(json_encode(mc_data))

/atom/proc/remove_from_cache()
/datum/controller/subsystem/statpanels/proc/remove_from_cache(atom/source)
SIGNAL_HANDLER
SSstatpanels.cached_images -= REF(src)
cached_images -= REF(source)

/// verbs that send information from the browser UI
/client/verb/set_tab(tab as text|null)
Expand Down
23 changes: 12 additions & 11 deletions code/datums/traits/negative.dm
Original file line number Diff line number Diff line change
Expand Up @@ -766,17 +766,18 @@ Edit: TK~ This is the dumbest fucking shit I've ever seen in my life. This isn
mood_change = -3
timeout = 0

/datum/quirk/masked_mook/on_spawn()
. = ..()
var/mob/living/carbon/human/H = quirk_holder
var/list/obj/item/clothing/masks = subtypesof(/obj/item/clothing/mask)
var/obj/item/clothing/mask/chosen = pick(masks)
var/list/ciggies = subtypesof(/obj/item/clothing/mask/cigarette)
while(chosen in ciggies)
chosen = pick(masks)
var/obj/item/clothing/mask/gas = new chosen(get_turf(quirk_holder))
H.equip_to_slot(gas, SLOT_WEAR_MASK)
H.regenerate_icons()
// this is the code that gives the player a mask on spawn. If somebody takes the trait, they're responsible for getting their own mask in the first place, not getting it given to them.
// /datum/quirk/masked_mook/on_spawn()
// . = ..()
// var/mob/living/carbon/human/H = quirk_holder
// var/list/obj/item/clothing/masks = subtypesof(/obj/item/clothing/mask)
// var/obj/item/clothing/mask/chosen = pick(masks)
// var/list/ciggies = subtypesof(/obj/item/clothing/mask/cigarette)
// while(chosen in ciggies)
// chosen = pick(masks)
// var/obj/item/clothing/mask/gas = new chosen(get_turf(quirk_holder))
// H.equip_to_slot(gas, SLOT_WEAR_MASK)
// H.regenerate_icons()

/datum/quirk/paper_skin
name = "Paper Skin"
Expand Down
8 changes: 3 additions & 5 deletions code/game/machinery/autolathe.dm
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@

/obj/machinery/autolathe/Destroy()
QDEL_NULL(wires)
QDEL_NULL(stored_research) // Clean up techweb datum
QDEL_NULL(being_built) // Clear current design
QDEL_LIST(matching_designs) // Clear design list
QDEL_NULL(stored_research)
being_built = null // or just omit - it's likely already null
matching_designs = null // clear references, don't delete contents
return ..()

/obj/machinery/autolathe/ui_interact(mob/user)
Expand Down Expand Up @@ -772,8 +772,6 @@
/obj/machinery/autolathe/ammo/can_build(datum/design/D, amount = 1)
if(!D)
return FALSE
if(!islist(D.category)) // Changed from !D.category
return FALSE
if("Handloaded Ammo" in D.category)
return ..()
if("Handmade Magazines" in D.category)
Expand Down
4 changes: 3 additions & 1 deletion code/game/machinery/transformer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
if(cooldown && (hasSiliconAccessInArea(user) || isobserver(user)))
. += "It will be ready in [DisplayTimeText(cooldown_timer - world.time)]."

// Fix transformer to clear masterAI reference
/obj/machinery/transformer/Destroy()
QDEL_NULL(countdown)
. = ..()
masterAI = null
return ..()

/obj/machinery/transformer/power_change()
..()
Expand Down
150 changes: 105 additions & 45 deletions code/game/objects/effects/spiders.dm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,70 @@
density = FALSE
max_integrity = 15

// New procs to replace spawn() chains
/obj/structure/spider/spiderling/proc/vent_travel_stage1(datum/weakref/ourref, obj/machinery/atmospherics/components/unary/vent_pump/exit_vent, obj/machinery/atmospherics/components/unary/vent_pump/start_vent)
var/obj/structure/spider/spiderling/us = ourref?.resolve()
if(!us || us.being_deleted || QDELETED(us))
return

us.forceMove(exit_vent)
var/travel_time = round(get_dist(us.loc, exit_vent.loc) / 2)

addtimer(CALLBACK(us, PROC_REF(vent_travel_stage2), ourref, exit_vent, start_vent, travel_time), travel_time)

/obj/structure/spider/spiderling/proc/vent_travel_stage2(datum/weakref/ourref, obj/machinery/atmospherics/components/unary/vent_pump/exit_vent, obj/machinery/atmospherics/components/unary/vent_pump/start_vent, travel_time)
var/obj/structure/spider/spiderling/us = ourref?.resolve()
if(!us || us.being_deleted || QDELETED(us))
return

if(!exit_vent || exit_vent.welded)
if(start_vent && !QDELETED(start_vent))
us.forceMove(start_vent)
us.entry_vent = null
return
if(prob(50))
us.audible_message(span_italic("You hear something scampering through the ventilation ducts."))

addtimer(CALLBACK(us, PROC_REF(vent_travel_stage3), ourref, exit_vent, start_vent), travel_time)

/obj/structure/spider/spiderling/proc/vent_travel_stage3(datum/weakref/ourref, obj/machinery/atmospherics/components/unary/vent_pump/exit_vent, obj/machinery/atmospherics/components/unary/vent_pump/start_vent)
var/obj/structure/spider/spiderling/us = ourref?.resolve()
if(!us || us.being_deleted || QDELETED(us))
return

if(!exit_vent || exit_vent.welded)
if(start_vent && !QDELETED(start_vent))
us.forceMove(start_vent)
us.entry_vent = null
return

us.forceMove(exit_vent.loc)
us.entry_vent = null
var/area/new_area = get_area(us.loc)
if(new_area)
new_area.Entered(us)

/obj/structure/spider/spiderling/proc/grow_into_spider()
if(being_deleted || QDELETED(src))
return

if(!grow_as)
if(prob(3))
grow_as = pick(/mob/living/simple_animal/hostile/poison/giant_spider/tarantula, /mob/living/simple_animal/hostile/poison/giant_spider/hunter/viper, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife)
else
grow_as = pick(/mob/living/simple_animal/hostile/poison/giant_spider, /mob/living/simple_animal/hostile/poison/giant_spider/hunter, /mob/living/simple_animal/hostile/poison/giant_spider/nurse)

var/mob/living/simple_animal/hostile/poison/giant_spider/S = new grow_as(src.loc)
S.poison_per_bite = poison_per_bite
S.poison_type = poison_type
S.faction = faction.Copy()
S.directive = directive

if(player_spiders)
S.playable_spider = TRUE
notify_ghosts("Spider [S.name] can be controlled", null, enter_link="<a href=?src=[REF(S)];activate=1>(Click to play)</a>", source=S, action=NOTIFY_ATTACK, ignore_key = POLL_IGNORE_SPIDER, ignore_dnr_observers = TRUE)

qdel(src)


/obj/structure/spider/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
Expand Down Expand Up @@ -92,6 +156,16 @@
START_PROCESSING(SSobj, src)
. = ..()

/obj/structure/spider/eggcluster/Destroy()
// Stop processing FIRST
STOP_PROCESSING(SSobj, src)

// Clear all references
poison_type = null
directive = null
faction = null

return ..()
/obj/structure/spider/eggcluster/process()
amount_grown += rand(0,2)
if(amount_grown >= 100)
Expand All @@ -118,20 +192,37 @@
var/obj/machinery/atmospherics/components/unary/vent_pump/entry_vent
var/travelling_in_vent = 0
var/player_spiders = 0
var/directive = "" //Message from the mother
var/directive = ""
var/poison_type = "toxin"
var/poison_per_bite = 5
var/list/faction = list("spiders")
var/being_deleted = FALSE
// Track active callbacks so we can cancel them
var/list/active_callbacks = list()
attack_hand_speed = CLICK_CD_MELEE
attack_hand_is_action = TRUE

/obj/structure/spider/spiderling/Destroy()
// Break parent references
RemoveComponentByType(/datum/component/swarming)
// Set flag FIRST
being_deleted = TRUE

// CRITICAL: Stop processing IMMEDIATELY
STOP_PROCESSING(SSobj, src)

// Remove component BEFORE clearing references
var/datum/component/swarming/swarm = GetComponent(/datum/component/swarming)
if(swarm)
// Let the component clean itself up properly
qdel(swarm)

// Clear all references
entry_vent = null
grow_as = null
directive = null
faction = null
poison_type = null
active_callbacks = null

return ..()

/obj/structure/spider/spiderling/Initialize()
Expand Down Expand Up @@ -172,6 +263,11 @@
return TRUE

/obj/structure/spider/spiderling/process()
// ALWAYS check first
if(being_deleted || QDELETED(src))
STOP_PROCESSING(SSobj, src)
return

if(travelling_in_vent)
if(isturf(loc))
travelling_in_vent = 0
Expand All @@ -190,31 +286,10 @@
visible_message("<B>[src] scrambles into the ventilation ducts!</B>", \
span_italic("You hear something scampering through the ventilation ducts."))

spawn(rand(20,60))
forceMove(exit_vent)
var/travel_time = round(get_dist(loc, exit_vent.loc) / 2)
spawn(travel_time)

if(!exit_vent || exit_vent.welded)
forceMove(entry_vent)
entry_vent = null
return

if(prob(50))
audible_message(span_italic("You hear something scampering through the ventilation ducts."))
sleep(travel_time)

if(!exit_vent || exit_vent.welded)
forceMove(entry_vent)
entry_vent = null
return
forceMove(exit_vent.loc)
entry_vent = null
var/area/new_area = get_area(loc)
if(new_area)
new_area.Entered(src)
//=================

// Store weakref for callbacks to check
var/ourref = WEAKREF(src)
// Start the vent travel - callbacks will self-check if we're deleted
addtimer(CALLBACK(src, PROC_REF(vent_travel_stage1), ourref, exit_vent, entry_vent), rand(20,60))
else if(prob(33))
var/list/nearby = oview(10, src)
if(nearby.len)
Expand All @@ -223,31 +298,16 @@
if(prob(40))
src.visible_message(span_notice("\The [src] skitters[pick(" away"," around","")]."))
else if(prob(10))
//ventcrawl!
for(var/obj/machinery/atmospherics/components/unary/vent_pump/v in view(7,src))
if(!v.welded)
entry_vent = v
walk_to(src, entry_vent, 1)
break

if(isturf(loc))
amount_grown += rand(0,2)
if(amount_grown >= 100)
if(!grow_as)
if(prob(3))
grow_as = pick(/mob/living/simple_animal/hostile/poison/giant_spider/tarantula, /mob/living/simple_animal/hostile/poison/giant_spider/hunter/viper, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife)
else
grow_as = pick(/mob/living/simple_animal/hostile/poison/giant_spider, /mob/living/simple_animal/hostile/poison/giant_spider/hunter, /mob/living/simple_animal/hostile/poison/giant_spider/nurse)
var/mob/living/simple_animal/hostile/poison/giant_spider/S = new grow_as(src.loc)
S.poison_per_bite = poison_per_bite
S.poison_type = poison_type
S.faction = faction.Copy()
S.directive = directive
if(player_spiders)
S.playable_spider = TRUE
notify_ghosts("Spider [S.name] can be controlled", null, enter_link="<a href=?src=[REF(S)];activate=1>(Click to play)</a>", source=S, action=NOTIFY_ATTACK, ignore_key = POLL_IGNORE_SPIDER, ignore_dnr_observers = TRUE)
qdel(src)


grow_into_spider()

/obj/structure/spider/cocoon
name = "cocoon"
Expand Down
8 changes: 7 additions & 1 deletion code/game/objects/items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1177,8 +1177,14 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb

/obj/item/proc/updateEmbedding()
if(!LAZYLEN(embedding))
return
// Clean up if no embedding data
RemoveElement(/datum/element/embed)
return FALSE

// Remove existing element before adding new one
// This prevents duplicate signal registration
RemoveElement(/datum/element/embed)

AddElement(/datum/element/embed,\
embed_chance = (!isnull(embedding["embed_chance"]) ? embedding["embed_chance"] : EMBED_CHANCE),\
fall_chance = (!isnull(embedding["fall_chance"]) ? embedding["fall_chance"] : EMBEDDED_ITEM_FALLOUT),\
Expand Down
13 changes: 11 additions & 2 deletions code/game/objects/items/melee/f13powerfist.dm
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,16 @@
remove_sword()

/obj/item/shishkebabpack/proc/remove_sword()
// Check if sword exists before trying to access it
if(!sword || QDELETED(sword))
return

// Check if sword is in a mob's inventory
if(ismob(sword.loc))
var/mob/M = sword.loc
M.temporarilyRemoveItemFromInventory(sword, TRUE)

// Move sword back to backpack
sword.forceMove(src)

/obj/item/shishkebabpack/Destroy()
Expand Down Expand Up @@ -346,8 +353,10 @@
return ..()

/obj/item/shishkebabpack/dropped(mob/user)
..()
remove_sword()
. = ..()
// Only try to remove sword if we're not being deleted
if(!QDELETED(src))
remove_sword()

// Shishkebab sword Keywords: Damage 55 (fire), Tool welder
/obj/item/weapon/melee/shishkebab //This should never exist without the backpack.
Expand Down
12 changes: 12 additions & 0 deletions code/game/objects/items/robot/robot_parts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@
..()
update_icon()

// IMPORTANT: Also add this cleanup to robot_suit to prevent circular references
/obj/item/robot_suit/Destroy()
// Clear all bodypart references
l_arm = null
r_arm = null
l_leg = null
r_leg = null
chest = null
head = null
forced_ai = null
return ..()

/obj/item/robot_suit/prebuilt/New()
l_arm = new(src)
r_arm = new(src)
Expand Down
Loading