diff --git a/code/ATMOSPHERICS/pipeline.dm b/code/ATMOSPHERICS/pipeline.dm
index aa65828231b..9a30d3936d9 100644
--- a/code/ATMOSPHERICS/pipeline.dm
+++ b/code/ATMOSPHERICS/pipeline.dm
@@ -220,11 +220,12 @@ var/pipenetwarnings = 10
total_thermal_energy += G.thermal_energy()
total_heat_capacity += G.heat_capacity()
- total_gas_mixture.temperature = total_heat_capacity ? total_thermal_energy/total_heat_capacity : 0
+ total_gas_mixture.temperature = total_heat_capacity ? total_thermal_energy/total_heat_capacity : 0
if(total_gas_mixture.volume > 0)
//Update individual gas_mixtures by volume ratio
- for(var/datum/gas_mixture/G in GL)
+ for(var/i in GL)
+ var/datum/gas_mixture/G = i
G.copy_from(total_gas_mixture)
var/list/G_gases = G.gases
for(var/id in G_gases)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 5497e1ba8b1..20d35846a87 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1182,3 +1182,35 @@ B --><-- A
for(var/atom/location = A.loc, location, location = location.loc)
if(location == src)
return 1
+
+proc/add_to_proximity_list(atom/A, range)
+ var/turf/T = get_turf(A)
+ var/list/L = block(locate(T.x - range, T.y - range, T.z), locate(T.x + range, T.y + range, T.z))
+ for(var/B in L)
+ var/turf/C = B
+ C.proximity_checkers |= A
+ return L
+
+proc/remove_from_proximity_list(atom/A, range)
+ var/turf/T = get_turf(A)
+ var/list/L = block(locate(T.x - range, T.y - range, T.z), locate(T.x + range, T.y + range, T.z))
+ for(var/B in L)
+ var/turf/C = B
+ C.proximity_checkers.Remove(A)
+
+proc/shift_proximity(atom/checker, atom/A, range, atom/B, newrange)
+ var/turf/T = get_turf(A)
+ var/turf/Q = get_turf(B)
+ if(T == Q && range == newrange)
+ return 0
+ var/list/L = block(locate(T.x - range, T.y - range, T.z), locate(T.x + range, T.y + range, T.z))
+ var/list/M = block(locate(Q.x - newrange, Q.y - newrange, Q.z), locate(Q.x + newrange, Q.y + newrange, Q.z))
+ var/list/N = L - M
+ var/list/O = M - L
+ for(var/C in N)
+ var/turf/D = C
+ D.proximity_checkers.Remove(checker)
+ for(var/E in O)
+ var/turf/F = E
+ F.proximity_checkers |= checker
+ return 1
diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm
index b0b2b840af1..a7a0f0a847e 100644
--- a/code/game/machinery/camera/motion.dm
+++ b/code/game/machinery/camera/motion.dm
@@ -5,6 +5,16 @@
var/area/ai_monitored/area_motion = null
var/alarm_delay = 30 // Don't forget, there's another 3 seconds in queueAlarm()
+/obj/machinery/camera/New()
+ add_to_proximity_list(src, 1) //1 was default of everything
+
+/obj/machinery/camera/Move()
+ remove_from_proximity_list(src, 1)
+ ..()
+
+/obj/machinery/camera/Destroy()
+ remove_from_proximity_list(src, 1)
+ ..()
/obj/machinery/camera/process()
// motion camera event loop
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 304d927c9dd..7b57aae3915 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -1113,11 +1113,6 @@ var/list/airlock_overlays = list()
//Airlock is passable if it is open (!density), bot has access, and is not bolted shut or powered off)
return !density || (check_access(ID) && !locked && hasPower())
-/obj/machinery/door/airlock/HasProximity(atom/movable/AM as mob|obj)
- for (var/obj/A in contents)
- A.HasProximity(AM)
- return
-
/obj/machinery/door/airlock/emag_act(mob/user)
if(!operating && density && hasPower() && !emagged)
operating = 1
diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm
index c261956806f..00f5ad0e24b 100644
--- a/code/game/machinery/flasher.dm
+++ b/code/game/machinery/flasher.dm
@@ -26,6 +26,10 @@
..() // ..() is EXTREMELY IMPORTANT, never forget to add it
bulb = new /obj/item/device/assembly/flash/handheld(src)
+/obj/machinery/flasher/Move()
+ remove_from_proximity_list(src, range)
+ ..()
+
/obj/machinery/flasher/power_change()
if (powered() && anchored && bulb)
stat &= ~NOPOWER
@@ -127,11 +131,13 @@
overlays += "[base_state]-s"
anchored = 1
power_change()
+ add_to_proximity_list(src, range)
else
user << "[src] can now be moved."
overlays.Cut()
anchored = 0
power_change()
+ remove_from_proximity_list(src, range)
else
..()
\ No newline at end of file
diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm
index 92b74435c6d..cc54f73b47c 100644
--- a/code/game/objects/effects/aliens.dm
+++ b/code/game/objects/effects/aliens.dm
@@ -318,6 +318,9 @@
spawn(rand(MIN_GROWTH_TIME, MAX_GROWTH_TIME))
Grow()
+/obj/structure/alien/egg/Destroy()
+ remove_from_proximity_list(src, 1)
+ ..()
/obj/structure/alien/egg/attack_paw(mob/living/user)
return attack_hand(user)
@@ -348,10 +351,11 @@
/obj/structure/alien/egg/proc/Grow()
icon_state = "egg"
status = GROWN
-
+ add_to_proximity_list(src, 1)
/obj/structure/alien/egg/proc/Burst(kill = 1) //drops and kills the hugger if any is remaining
if(status == GROWN || status == GROWING)
+ remove_from_proximity_list(src, 1)
icon_state = "egg_hatched"
flick("egg_opening", src)
status = BURSTING
@@ -368,6 +372,9 @@
child.Attach(M)
break
+/obj/structure/alien/egg/Move()
+ remove_from_proximity_list(src, 1)
+ ..()
/obj/structure/alien/egg/bullet_act(obj/item/projectile/Proj)
health -= Proj.damage
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index eb13de0ce1a..a8de11836a8 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -60,12 +60,6 @@
attacher = user
return
-
-/obj/item/device/transfer_valve/HasProximity(atom/movable/AM as mob|obj)
- if(!attached_device)
- return
- attached_device.HasProximity(AM)
- return
/obj/item/device/transfer_valve/attack_self(mob/user)
user.set_machine(src)
var/dat = {" Valve properties:
diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm
index 56031b41c4e..509999d5f92 100644
--- a/code/game/objects/items/weapons/grenades/chem_grenade.dm
+++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm
@@ -143,9 +143,6 @@
/obj/item/weapon/grenade/chem_grenade/receive_signal()
prime()
-/obj/item/weapon/grenade/chem_grenade/HasProximity(atom/movable/AM)
- if(nadeassembly)
- nadeassembly.HasProximity(AM)
/obj/item/weapon/grenade/chem_grenade/Crossed(atom/movable/AM)
if(nadeassembly)
diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm
index 43a79de4c46..79a25e3cd0b 100644
--- a/code/game/objects/items/weapons/stunbaton.dm
+++ b/code/game/objects/items/weapons/stunbaton.dm
@@ -181,3 +181,12 @@
stunforce = 5
hitcost = 2500
slot_flags = null
+ var/obj/item/device/assembly/igniter/sparkler = 0
+
+/obj/item/weapon/melee/baton/cattleprod/New()
+ ..()
+ sparkler = new (src)
+
+/obj/item/weapon/melee/baton/cattleprod/baton_stun()
+ if(sparkler.activate())
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm
index 9087ec8dc77..910c3dfc84a 100644
--- a/code/game/objects/items/weapons/weaponry.dm
+++ b/code/game/objects/items/weapons/weaponry.dm
@@ -117,7 +117,7 @@
qdel(I)
qdel(src)
- else if(istype(I, /obj/item/weapon/wirecutters) && !(I.flags & NODROP))
+ else if(istype(I, /obj/item/device/assembly/igniter) && !(I.flags & NODROP))
var/obj/item/weapon/melee/baton/cattleprod/P = new /obj/item/weapon/melee/baton/cattleprod
if(!remove_item_from_storage(user))
@@ -125,7 +125,7 @@
user.unEquip(I)
user.put_in_hands(P)
- user << "You fasten the wirecutters to the top of the rod with the cable, prongs outward."
+ user << "You fasten [I] to the top of the rod with the cable."
qdel(I)
qdel(src)
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index a02fb4c3bca..ae925323705 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -26,6 +26,8 @@
flags = 0
+ var/list/proximity_checkers = list()
+
var/image/obscured //camerachunks
/turf/New()
..()
@@ -91,12 +93,9 @@
return 1 //Nothing found to block so return success!
/turf/Entered(atom/movable/M)
- var/loopsanity = 100
- for(var/atom/A in range(1))
- if(loopsanity == 0)
- break
- loopsanity--
- A.HasProximity(M, 1)
+ for(var/A in proximity_checkers)
+ var/atom/B = A
+ B.HasProximity(M)
/turf/proc/is_plasteel_floor()
return 0
diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm
index e55cf0149b2..a999ed9e2ee 100644
--- a/code/modules/assembly/assembly.dm
+++ b/code/modules/assembly/assembly.dm
@@ -25,6 +25,10 @@
var/const/WIRE_RADIO_RECEIVE = 8 //Allows Pulsed(1) to call Activate()
var/const/WIRE_RADIO_PULSE = 16 //Allows Pulse(1) to send a radio message
+/obj/item/device/assembly/proc/on_attach()
+
+/obj/item/device/assembly/proc/on_detach()
+
/obj/item/device/assembly/proc/holder_movement() //Called when the holder is moved
return
diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm
index 3a446749607..81e4a92f2e6 100644
--- a/code/modules/assembly/bomb.dm
+++ b/code/modules/assembly/bomb.dm
@@ -69,10 +69,6 @@
else
bombtank.release()
-/obj/item/device/onetankbomb/HasProximity(atom/movable/AM as mob|obj)
- if(bombassembly)
- bombassembly.HasProximity(AM)
-
/obj/item/device/onetankbomb/Crossed(atom/movable/AM as mob|obj) //for mousetraps
if(bombassembly)
bombassembly.Crossed(AM)
diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm
index 6be68eb1a84..a4b7720d0c8 100644
--- a/code/modules/assembly/holder.dm
+++ b/code/modules/assembly/holder.dm
@@ -55,13 +55,6 @@
if(master)
master.update_icon()
-/obj/item/device/assembly_holder/HasProximity(atom/movable/AM as mob|obj)
- if(a_left)
- a_left.HasProximity(AM)
- if(a_right)
- a_right.HasProximity(AM)
-
-
/obj/item/device/assembly_holder/Crossed(atom/movable/AM as mob|obj)
if(a_left)
a_left.Crossed(AM)
diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm
index 79c8b67c0b5..ce2f468e0d6 100644
--- a/code/modules/assembly/proximity.dm
+++ b/code/modules/assembly/proximity.dm
@@ -9,6 +9,9 @@
var/scanning = 0
var/timing = 0
var/time = 10
+ var/sensitivity = 1
+ var/atom/oldloc
+ var/list/turfs_around = list()
/obj/item/device/assembly/prox_sensor/proc/toggle_scan()
@@ -19,12 +22,19 @@
/obj/item/device/assembly/prox_sensor/New()
..()
SSobj.processing |= src
+ oldloc = loc
/obj/item/device/assembly/prox_sensor/describe()
if(timing)
return "The proximity sensor is arming."
return "The proximity sensor is [scanning?"armed":"disarmed"]."
+/obj/item/device/assembly/prox_sensor/on_attach(datum/wires/w)
+ handle_move(w.holder)
+
+/obj/item/device/assembly/prox_sensor/on_detach(datum/wires/w)
+ handle_move(w.holder.loc)
+
/obj/item/device/assembly/prox_sensor/activate()
if(!..())
return 0//Cooldown check
@@ -35,12 +45,9 @@
/obj/item/device/assembly/prox_sensor/toggle_secure()
secured = !secured
- if(secured)
- SSobj.processing |= src
- else
+ if(!secured)
scanning = 0
timing = 0
- SSobj.processing.Remove(src)
update_icon()
return secured
@@ -52,7 +59,7 @@
/obj/item/device/assembly/prox_sensor/sense()
- if((!secured)||(!scanning)||(cooldown > 0))
+ if((!secured)||(cooldown > 0))
return 0
pulse(0)
audible_message("\icon[src] *beep* *beep*", null, 3)
@@ -66,22 +73,32 @@
time--
if(time <= 0)
timing = 0
- toggle_scan()
+ toggle_scan(1)
time = initial(time)
-
+ handle_move(get_turf(loc))
/obj/item/device/assembly/prox_sensor/dropped()
- spawn(0)
- sense()
+ if(scanning)
+ spawn(0)
+ sense()
-/obj/item/device/assembly/prox_sensor/toggle_scan()
+/obj/item/device/assembly/prox_sensor/toggle_scan(scan)
if(!secured)
return 0
- scanning = !scanning
+ scanning = scan
+ if(scanning)
+ add_to_proximity_list(src, sensitivity)
+ else
+ remove_from_proximity_list(src, sensitivity)
+ oldloc = get_turf(loc)
update_icon()
-
+/obj/item/device/assembly/prox_sensor/proc/sensitivity_change(value)
+ var/sense = min(max(sensitivity + value, 0), 5)
+ if(scanning)
+ shift_proximity(src, oldloc, sensitivity, loc, sense)
+ sensitivity = sense
/obj/item/device/assembly/prox_sensor/update_icon()
overlays.Cut()
@@ -96,11 +113,15 @@
holder.update_icon()
return
+/obj/item/device/assembly/prox_sensor/proc/handle_move(atom/newloc)
+ if(scanning)
+ if(shift_proximity(src, oldloc, sensitivity, newloc, sensitivity))
+ sense()
+ oldloc = newloc
-/obj/item/device/assembly/prox_sensor/Move()
+/obj/item/device/assembly/prox_sensor/Move(newloc)
..()
- sense()
- return
+ handle_move(newloc)
/obj/item/device/assembly/prox_sensor/interact(mob/user)//TODO: Change this to the wires thingy
@@ -108,7 +129,8 @@
var/second = time % 60
var/minute = (time - second) / 60
var/dat = "Proximity Sensor\n[(timing ? "Arming" : "Not Arming")] [minute]:[second]\n- - + +\n"
- dat += "
[scanning?"Armed":"Unarmed"] (Movement sensor active when armed!)"
+ dat += "
Armed":"1'>Unarmed"] (Movement sensor active when armed!)"
+ dat += "
Detection range: - [sensitivity] +"
dat += "
Refresh"
dat += "
Close"
user << browse(dat, "window=prox")
@@ -123,8 +145,11 @@
onclose(usr, "prox")
return
+ if(href_list["sense"])
+ sensitivity_change(((href_list["sense"] == "up") ? 1 : -1))
+
if(href_list["scanning"])
- toggle_scan()
+ toggle_scan(text2num(href_list["scanning"]))
if(href_list["time"])
timing = text2num(href_list["time"])
diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm
index e889d6fc723..3432899486a 100644
--- a/code/modules/assembly/timer.dm
+++ b/code/modules/assembly/timer.dm
@@ -8,6 +8,8 @@
var/timing = 0
var/time = 5
+ var/saved_time = 5
+ var/loop = 0
/obj/item/device/assembly/timer/New()
@@ -47,6 +49,8 @@
cooldown = 2
spawn(10)
process_cooldown()
+ if(loop)
+ timing = 1
update_icon()
@@ -56,7 +60,7 @@
if(time <= 0)
timing = 0
timer_end()
- time = initial(time)
+ time = saved_time
/obj/item/device/assembly/timer/update_icon()
@@ -74,6 +78,7 @@
var/second = time % 60
var/minute = (time - second) / 60
var/dat = "Timing Unit\n[(timing ? "Timing" : "Not Timing")] [minute]:[second]\n- - + +\n"
+ dat += "
Stop repeating" : "1'>Set to repeat")]"
dat += "
Refresh"
dat += "
Close"
var/datum/browser/popup = new(user, "timer", name)
@@ -96,11 +101,14 @@
bombers += timer_message
log_game("[key_name(usr)] activated [src] attachment for [loc]")
update_icon()
+ if(href_list["repeat"])
+ loop = text2num(href_list["repeat"])
if(href_list["tp"])
var/tp = text2num(href_list["tp"])
time += tp
time = min(max(round(time), 1), 600)
+ saved_time = time
if(href_list["close"])
usr << browse(null, "window=timer")
diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm
index 9364743c5db..71ef85ef8c5 100644
--- a/code/modules/assembly/voice.dm
+++ b/code/modules/assembly/voice.dm
@@ -11,20 +11,66 @@
verb_exclaim = "beeps"
var/listening = 0
var/recorded = "" //the activation message
+ var/mode = 1
+ var/global/list/modes = list("inclusive",
+ "exclusive",
+ "recognizer",
+ "voice sensor")
/obj/item/device/assembly/voice/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
if(speaker == src)
return
if(listening && !radio_freq)
- recorded = raw_message
- listening = 0
- say("Activation message is '[recorded]'.")
+ record_speech(speaker, raw_message)
else
- if(findtextEx(raw_message, recorded))
+ if(check_activation(speaker, raw_message))
spawn(10)
pulse(0)
+/obj/item/device/assembly/voice/proc/record_speech(atom/movable/speaker, raw_message)
+ switch(mode)
+ if(1)
+ recorded = raw_message
+ listening = 0
+ say("Activation message is '[recorded]'.")
+ if(2)
+ recorded = raw_message
+ listening = 0
+ say("Activation message is '[recorded]'.")
+ if(3)
+ recorded = speaker.GetVoice()
+ listening = 0
+ say("Your voice pattern is saved.")
+ if(4)
+ if(length(raw_message))
+ spawn(10)
+ pulse(0)
+
+/obj/item/device/assembly/voice/proc/check_activation(atom/movable/speaker, raw_message)
+ . = 0
+ switch(mode)
+ if(1)
+ if(findtextEx(raw_message, recorded))
+ . = 1
+ if(2)
+ if(raw_message == recorded)
+ . = 1
+ if(3)
+ if(speaker.GetVoice() == recorded)
+ . = 1
+ if(4)
+ if(length(raw_message))
+ . = 1
+
+/obj/item/device/assembly/voice/attackby(obj/item/weapon/W, mob/user, params)
+ if(istype(W, /obj/item/device/multitool))
+ mode %= modes.len
+ mode++
+ user << "You set [src] into a [modes[mode]] mode."
+ listening = 0
+ recorded = ""
+
/obj/item/device/assembly/voice/activate()
if(secured)
if(!holder)
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index 1b242b34cfa..76e0cead24a 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -63,7 +63,7 @@
result = /obj/item/weapon/melee/baton/cattleprod
reqs = list(/obj/item/weapon/restraints/handcuffs/cable = 1,
/obj/item/stack/rods = 1,
- /obj/item/weapon/wirecutters = 1,
+ /obj/item/device/assembly/igniter = 1,
/obj/item/weapon/stock_parts/cell = 1)
time = 80
parts = list(/obj/item/weapon/stock_parts/cell = 1)
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 5093003a035..8e8cdeb2fc2 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index f5868458340..37d22120d7d 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi
index 93ed62314d3..675da21434a 100644
Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ