diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index d041306d6a5..44c4712617d 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -32,6 +32,11 @@
qdel(S)
else
S.be_replaced()
+ //NSV13 - stop runtiming
+ if(registered_z)
+ SSmobs.clients_by_zlevel[registered_z] -= src
+ registered_z = null
+ //NSV13 end
if(ranged_ability)
ranged_ability.remove_ranged_ability(src)
if(buckled)
diff --git a/code/modules/recycling/conveyor.dm b/code/modules/recycling/conveyor.dm
index 3516758366d..732db5c9c66 100644
--- a/code/modules/recycling/conveyor.dm
+++ b/code/modules/recycling/conveyor.dm
@@ -195,6 +195,11 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
if(!operating)
SSmove_manager.stop_looping(convayable, SSconveyors)
return
+ //NSV13 - account for potentially changing location between sig send and reaching this.
+ if(convayable.loc != source)
+ SSmove_manager.stop_looping(convayable, SSconveyors)
+ return
+ //NSV13 end.
start_conveying(convayable)
/obj/machinery/conveyor/proc/conveyable_exit(datum/source, atom/convayable, direction)
diff --git a/nsv13/code/modules/munitions/ship_weapons/ballistic_weapons/revision2/automation.dm b/nsv13/code/modules/munitions/ship_weapons/ballistic_weapons/revision2/automation.dm
index 3da4d67b4bd..02feb57dd98 100644
--- a/nsv13/code/modules/munitions/ship_weapons/ballistic_weapons/revision2/automation.dm
+++ b/nsv13/code/modules/munitions/ship_weapons/ballistic_weapons/revision2/automation.dm
@@ -8,30 +8,23 @@
anchored = TRUE
can_be_unanchored = TRUE
density = TRUE
- subsystem_type = /datum/controller/subsystem/processing //Needs to go faster than SSmachines
- var/process_delay = 0.5 SECONDS
- var/next_process = 0
+ processing_flags = START_PROCESSING_MANUALLY //Does not process.
+ ///Icon state the arm of this device will have
var/arm_icon_state = "welder3"
- var/tier = 1
- var/list/held_components = list() //All the missile construction components that they've put into the arm.
- var/obj/item/arm = null
- var/obj/item/ship_weapon/ammunition/missile/missile_casing/target
- var/munition_types = list(/obj/item/ship_weapon/ammunition/missile/missile_casing, /obj/item/ship_weapon/ammunition/torpedo/torpedo_casing)
- var/list/target_states = list(1, 7, 9) //The target construction state of the missile
-
-/obj/machinery/missile_builder/examine(mob/user)
- . = ..()
- if(held_components.len)
- . += "It currently holds..."
- var/listofitems = list()
- for(var/obj/item/C in held_components)
- var/path = C.type
- if (listofitems[path])
- listofitems[path]["amount"]++
- else
- listofitems[path] = list("name" = C.name, "amount" = 1)
- for(var/i in listofitems)
- . += "[listofitems[i]["name"]] x[listofitems[i]["amount"]]"
+ ///An overlay for the machine that varies by its arm icon state. For some reason an item and not an overlay or any kind of effect.
+ var/obj/item/arm = null //This being an /item makes me scream.
+ ///List of valid munition types. These are SUPER DIRTY types. DO NOT TRUST THESE TYPES. If you are reading this, new coder, PLEASE keep a common ancestor if you want to access vars and have the things be basically the same!!
+ var/munition_types = list(/obj/item/ship_weapon/ammunition/missile/missile_casing, /obj/item/ship_weapon/ammunition/torpedo/torpedo_casing) //This is super bad but I don't feel like rewriting all of missile / torp casing code so it stays :)
+ ///The target construction states of the missile
+ var/list/target_states = list(1, 7, 9) //Who would magic number these even *after* having to reference them in machines too?? I am not cleaning up after you.. right now at least. -Delta
+ ///The turf this assembler is tracking
+ var/turf/target_turf
+ ///The timer that tracks how long the arm should be doing arm things.
+ var/active_arm_timer_id
+ ///Next time a success sound can play.
+ var/next_success_sound = 0
+ ///Next time a fail sound can play.
+ var/next_fail_sound = 0
/obj/machinery/missile_builder/attackby(obj/item/I, mob/user, params)
if(default_unfasten_wrench(user, I))
@@ -43,6 +36,19 @@
return
. = ..()
+/obj/machinery/missile_builder/default_unfasten_wrench(mob/user, obj/item/I, time)
+ . = ..()
+ if(. != SUCCESSFUL_UNFASTEN)
+ return
+ if(anchored) //just got anchored
+ target_turf = get_turf(get_step(src, src.dir))
+ if(target_turf)
+ RegisterSignal(target_turf, COMSIG_ATOM_ENTERED, PROC_REF(attempt_assembler_action))
+ else //just got unanchored
+ if(target_turf)
+ UnregisterSignal(target_turf, COMSIG_ATOM_ENTERED)
+ target_turf = null
+
/obj/item/stack/conveyor/slow
name = "Slow conveyor assembly"
conveyor_type = /obj/machinery/conveyor/slow
@@ -70,59 +76,179 @@
/obj/machinery/missile_builder/AltClick(mob/user)
. = ..()
+ if(target_turf)
+ UnregisterSignal(target_turf, COMSIG_ATOM_ENTERED)
+ target_turf = null
setDir(turn(src.dir, -90))
+ target_turf = get_turf(get_step(src, src.dir))
+ if(target_turf)
+ RegisterSignal(target_turf, COMSIG_ATOM_ENTERED, PROC_REF(attempt_assembler_action))
/obj/machinery/missile_builder/Initialize(mapload)
. = ..()
- arm = new /obj/item(src)
+ arm = new /obj/item(src) //WHY IS THIS AN ITEM (worse, basetype..) and not an overlay or something else that would make more sense?!
arm.icon = icon
arm.icon_state = arm_icon_state
vis_contents += arm
arm.mouse_opacity = FALSE
+ target_turf = get_turf(get_step(src, src.dir))
+ if(target_turf)
+ RegisterSignal(target_turf, COMSIG_ATOM_ENTERED, PROC_REF(attempt_assembler_action)) //aaa
/obj/machinery/missile_builder/Destroy()
qdel(arm)
- . = ..()
+ if(target_turf)
+ UnregisterSignal(target_turf, COMSIG_ATOM_ENTERED)
+ target_turf = null
+ if(active_arm_timer_id)
+ deltimer(active_arm_timer_id)
+ active_arm_timer_id = null
+ return ..()
-/obj/machinery/missile_builder/process()
- if(world.time < next_process)
+/**
+ * This beautiful proc handles interacting with objects that enter the turf we watch. Which is much more effective than processing all the time.
+ * * Does not return anything. SHOULD NOT RETURN ANYTHING.
+**/
+/obj/machinery/missile_builder/proc/attempt_assembler_action(turf/source, atom/movable/entering, old_loc, old_locs)
+ SIGNAL_HANDLER
+ if(QDELETED(entering)) //How would this happen? Who knows.. but this is NSV after all.
+ return
+ if(!isobj(entering) || iseffect(entering))
return
- next_process = world.time + process_delay
- var/turf/input_turf = get_turf(get_step(src, src.dir))
- if(target && target.loc != input_turf)
- target = null
- visible_message("[name] shakes its arm melancholically.")
+ if(!(entering.type in munition_types))
+ visible_message("[src] shakes its arm melancholically.")
arm.shake_animation()
- playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
- if(target)
- arm.icon_state = arm_icon_state
- target.state++ //Next step!
- target.check_completion()
- do_sparks(10, TRUE, target)
- playsound(src, 'sound/items/welder.ogg', 100, 1)
- target = null
+ if(world.time >= next_fail_sound)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ next_fail_sound = world.time + 0.2 SECONDS
return
- for(var/munition_type in munition_types)
- target = locate(munition_type) in input_turf
- if(target)
- break
- if(!target)
- target = null
- arm.icon_state = arm_icon_state
+ switch(entering.type) //This is VERY BAD but they do not share a common type.
+ if(/obj/item/ship_weapon/ammunition/missile/missile_casing)
+ var/obj/item/ship_weapon/ammunition/missile/missile_casing/missile_target = entering
+ if(!(missile_target.state in target_states))
+ visible_message("[src] sighs.")
+ if(world.time >= next_fail_sound)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ next_fail_sound = world.time + 0.5 SECONDS
+ return
+ trigger_arm_animation()
+ missile_target.state++ //Next step!
+ missile_target.check_completion()
+ if(world.time >= next_success_sound)
+ do_sparks(4, TRUE, missile_target)
+ playsound(src, 'sound/items/welder.ogg', 100, 1)
+ next_success_sound = world.time + 0.2 SECONDS
+ if(/obj/item/ship_weapon/ammunition/torpedo/torpedo_casing)
+ var/obj/item/ship_weapon/ammunition/torpedo/torpedo_casing/torpedo_target = entering
+ if(!(torpedo_target.state in target_states))
+ visible_message("[src] sighs.")
+ if(world.time >= next_fail_sound)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ next_fail_sound = world.time + 0.5 SECONDS
+ return
+ trigger_arm_animation()
+ torpedo_target.state++ //Next step!
+ torpedo_target.check_completion()
+ if(world.time >= next_success_sound)
+ do_sparks(4, TRUE, torpedo_target)
+ playsound(src, 'sound/items/welder.ogg', 100, 1)
+ next_success_sound = world.time + 0.2 SECONDS
+ else
+ CRASH("Please stop handing the missile assemblers invalid types as valid ammunition. Type: [entering.type]. ALL valid casings must be missile or torpedo types.")
+
+//overrides parent.
+/obj/machinery/missile_builder/assembler/attempt_assembler_action(turf/source, atom/movable/entering, old_loc, old_locs)
+ if(QDELETED(entering)) //How would this happen? Who knows.. but this is NSV after all.
return
- var/found = FALSE
- for(var/target_state in target_states)
- if(target.state == target_state)
- found = TRUE
- break
- if(!found)
- visible_message("[src] sighs.")
- playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
- target = null
- return FALSE
- src.visible_message("[src] whirrs into life!")
- arm.icon_state = "[arm_icon_state]_anim"
- playsound(src, 'sound/items/drill_use.ogg', 70, 1)
+ if(!isobj(entering) || iseffect(entering))
+ return
+ if(entering.loc != source)
+ return
+ if(tracked_component_type && tracked_component_type == entering.type) //Please do throw these hungry machines some components.
+ var/obj/item/entering_item = entering
+ visible_message("[src] happily adds [entering_item] to its component storage.")
+ if(world.time >= next_success_sound)
+ playsound(src, 'sound/machines/ping.ogg', 50, 0)
+ next_success_sound = world.time + 0.2 SECONDS
+ entering_item.do_pickup_animation(src)
+ entering_item.forceMove(src)
+ held_components += entering_item
+ return
+ if(!(entering.type in munition_types))
+ visible_message("[src] shakes its arm melancholically.")
+ arm.shake_animation()
+ if(world.time >= next_fail_sound)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ next_fail_sound = world.time + 0.2 SECONDS
+ return
+ switch(entering.type) //This is VERY BAD but they do not share a common type.
+ if(/obj/item/ship_weapon/ammunition/missile/missile_casing)
+ var/obj/item/ship_weapon/ammunition/missile/missile_casing/missile_target = entering
+ if(!length(held_components))
+ visible_message("[src] sighs.")
+ if(world.time >= next_fail_sound)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ next_fail_sound = world.time + 0.5 SECONDS
+ return
+ var/obj/item/ship_weapon/parts/missile/missile_part = held_components[1]
+ if((missile_part.fits_type && !istype(missile_target, missile_part.fits_type)) || missile_target.state != missile_part.target_state)
+ visible_message("[src] sighs.")
+ if(world.time >= next_fail_sound)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ next_fail_sound = world.time + 0.5 SECONDS
+ return
+ trigger_arm_animation()
+ do_item_attack_animation(missile_target, used_item = missile_part)
+
+ missile_target.state++ //Next step!
+ missile_part.forceMove(missile_target)
+ held_components -= missile_part
+ missile_target.check_completion()
+ if(world.time >= next_success_sound)
+ do_sparks(4, TRUE, missile_target)
+ playsound(src, 'sound/machines/ping.ogg', 50, 0)
+ next_success_sound = world.time + 0.2 SECONDS
+ if(/obj/item/ship_weapon/ammunition/torpedo/torpedo_casing)
+ var/obj/item/ship_weapon/ammunition/torpedo/torpedo_casing/torpedo_target = entering
+ if(!length(held_components))
+ if(world.time >= next_fail_sound)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ next_fail_sound = world.time + 0.5 SECONDS
+ return
+ var/obj/item/ship_weapon/parts/missile/torpedo_part = held_components[1]
+ if((torpedo_part.fits_type && !istype(torpedo_target, torpedo_part.fits_type)) || torpedo_target.state != torpedo_part.target_state)
+ if(world.time >= next_fail_sound)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ next_fail_sound = world.time + 0.5 SECONDS
+ return
+ trigger_arm_animation()
+ do_item_attack_animation(torpedo_target, used_item = torpedo_part)
+
+ torpedo_target.state++ //Next step!
+ torpedo_part.forceMove(torpedo_target)
+ held_components -= torpedo_part
+ torpedo_target.check_completion()
+ if(world.time >= next_success_sound)
+ do_sparks(4, TRUE, torpedo_target)
+ playsound(src, 'sound/machines/ping.ogg', 50, 0)
+ next_success_sound = world.time + 0.2 SECONDS
+ else
+ CRASH("Please stop handing the missile assemblers invalid types as valid ammunition. Type: [entering.type]. ALL valid casings must be missile or torpedo types.")
+
+
+///Starts the machine's arm animation to reset after some time.
+/obj/machinery/missile_builder/proc/trigger_arm_animation()
+ if(arm.icon_state != "[arm_icon_state]_anim")
+ arm.icon_state = "[arm_icon_state]_anim"
+ visible_message("[src] whirrs into life!")
+ if(active_arm_timer_id)
+ deltimer(active_arm_timer_id)
+ active_arm_timer_id = addtimer(CALLBACK(src, PROC_REF(stop_arm_animation)), 1 SECONDS, TIMER_STOPPABLE)
+
+///Stops the machine's arm animation after some time.
+/obj/machinery/missile_builder/proc/stop_arm_animation()
+ arm.icon_state = arm_icon_state
+ active_arm_timer_id = null
/obj/machinery/missile_builder/assembler
name = "Robotic Missile Part Applicator"
@@ -130,6 +256,25 @@
desc = "An assembly arm which can slot a multitude of missile components into casings for you! Swipe it with an ID to release its stored components."
req_one_access = list(ACCESS_MUNITIONS)
circuit = /obj/item/circuitboard/machine/missile_builder/assembler
+ ///Currently loaded missile components.
+ var/list/held_components = list()
+ ///Currently tracked type for autopickup
+ var/tracked_component_type = null
+
+/obj/machinery/missile_builder/assembler/examine(mob/user)
+ . = ..()
+ if(!length(held_components))
+ return
+ . += "It currently holds..."
+ var/listofitems = list()
+ for(var/obj/item/C in held_components)
+ var/path = C.type
+ if(listofitems[path])
+ listofitems[path]["amount"]++
+ else
+ listofitems[path] = list("name" = C.name, "amount" = 1)
+ for(var/i in listofitems)
+ . += "[listofitems[i]["name"]] x[listofitems[i]["amount"]]"
/obj/machinery/missile_builder/assembler/attackby(obj/item/I, mob/living/user, params)
. = ..()
@@ -139,11 +284,13 @@
to_chat(user, "You slot [I] into [src], ready for construction.")
I.forceMove(src)
held_components += I
+ tracked_component_type = I.type
if(istype(I, /obj/item/card/id) && allowed(user))
to_chat(user, "You dump [src]'s contents out.")
for(var/obj/item/X in held_components)
X.forceMove(get_turf(src))
held_components -= X
+ tracked_component_type = null
/obj/machinery/missile_builder/assembler/MouseDrop_T(obj/structure/A, mob/user)
. = ..()
@@ -159,46 +306,6 @@
P.forceMove(src)
held_components += P
-/obj/machinery/missile_builder/assembler/process()
- if(world.time < next_process)
- return
- next_process = world.time + process_delay
- var/turf/input_turf = get_turf(get_step(src, src.dir))
- if(target && target.loc != input_turf)
- target = null
- visible_message("[name] shakes its arm melancholically.")
- arm.shake_animation()
- playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
- if(target)
- var/found = FALSE
- for(var/obj/item/ship_weapon/parts/missile/M in held_components)
- if(M.fits_type && !istype(target, M.fits_type))
- continue
- if(target.state == M.target_state)
- M.forceMove(target)
- held_components -= M
- target.state ++
- found = TRUE
- break
- if(found)
- target.check_completion()
- playsound(src, 'sound/machines/ping.ogg', 50, 0)
- do_sparks(10, TRUE, target)
- target = null
- arm.icon_state = arm_icon_state
- return
- for(var/munition_type in munition_types)
- target = locate(munition_type) in input_turf
- if(target)
- break
- if(!target || !held_components.len)
- target = null
- arm.icon_state = arm_icon_state
- return
- src.visible_message("[src] whirrs into life!")
- arm.icon_state = "[arm_icon_state]_anim"
- playsound(src, 'sound/items/drill_use.ogg', 70, 1)
-
/datum/design/board/ammo_sorter_computer
name = "Ammo sorter console (circuitboard)"
desc = "The central control console for ammo sorters.."
diff --git a/nsv13/code/modules/overmap/FTL/components/drive.dm b/nsv13/code/modules/overmap/FTL/components/drive.dm
index a1880a21904..65b375e0703 100644
--- a/nsv13/code/modules/overmap/FTL/components/drive.dm
+++ b/nsv13/code/modules/overmap/FTL/components/drive.dm
@@ -55,7 +55,7 @@
radio.keyslot = new radio_key
radio.listening = 0
radio.recalculateChannels()
- soundloop = new(list(src), FALSE, FALSE, CHANNEL_FTL_MANIFOLD, TRUE)
+ soundloop = new(src, FALSE, FALSE, CHANNEL_FTL_MANIFOLD, TRUE)
STOP_PROCESSING(SSmachines, src)
return INITIALIZE_HINT_LATELOAD