"
- html += "| Severity | Name | Ends At | Ends In | Stop |
"
+ html += "| Severity | Name | Ends At | Ends In | Stop |
"
for(var/datum/event/E in active_events)
if(!E.event_meta)
continue
diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm
index 71d78d96e4a..c485827efbc 100644
--- a/code/modules/events/grid_check.dm
+++ b/code/modules/events/grid_check.dm
@@ -8,9 +8,7 @@
power_failure(0)
/datum/event/grid_check/announce()
- command_alert("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Automated Grid Check")
- for(var/mob/M in player_list)
- M << sound('sound/AI/poweroff.ogg')
+ command_announcement.Announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Automated Grid Check", new_sound = 'sound/AI/poweroff.ogg')
/datum/event/grid_check/end()
power_restore()
diff --git a/code/modules/events/infestation.dm b/code/modules/events/infestation.dm
index 8971db74853..444da4675ef 100644
--- a/code/modules/events/infestation.dm
+++ b/code/modules/events/infestation.dm
@@ -102,7 +102,7 @@
/datum/event/infestation/announce()
- command_alert("Bioscans indicate that [vermstring] have been breeding in [locstring]. Clear them out, before this starts to affect productivity.", "Lifesign Alert")
+ command_announcement.Announce("Bioscans indicate that [vermstring] have been breeding in [locstring]. Clear them out, before this starts to affect productivity.", "Lifesign Alert")
#undef LOC_KITCHEN
#undef LOC_ATMOS
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index 7f66a4366a9..9e8f5d43b57 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -6,7 +6,7 @@
/datum/event/ionstorm/announce()
endWhen = rand(500, 1500)
-// command_alert("The station has entered an ion storm. Monitor all electronic equipment for malfunctions", "Anomaly Alert")
+// command_announcement.Announce("The station has entered an ion storm. Monitor all electronic equipment for malfunctions", "Anomaly Alert")
for (var/mob/living/carbon/human/player in world)
if(player.client)
players += player.real_name
@@ -86,7 +86,7 @@
/datum/event/ionstorm/end()
spawn(rand(5000,8000))
if(prob(50))
- command_alert("It has come to our attention that the station passed through an ion storm. Please monitor all electronic equipment for malfunctions.", "Anomaly Alert")
+ command_announcement.Announce("It has come to our attention that the station passed through an ion storm. Please monitor all electronic equipment for malfunctions.", "Anomaly Alert")
/*
/proc/IonStorm(botEmagChance = 10)
@@ -212,21 +212,21 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is
spawn(0)
world << "Started processing APCs"
for (var/obj/machinery/power/apc/APC in world)
- if(APC.z == 1)
+ if((APC.z in config.station_levels))
APC.ion_act()
apcnum++
world << "Finished processing APCs. Processed: [apcnum]"
spawn(0)
world << "Started processing SMES"
for (var/obj/machinery/power/smes/SMES in world)
- if(SMES.z == 1)
+ if((SMES.z in config.station_levels))
SMES.ion_act()
smesnum++
world << "Finished processing SMES. Processed: [smesnum]"
spawn(0)
world << "Started processing AIRLOCKS"
for (var/obj/machinery/door/airlock/D in world)
- if(D.z == 1)
+ if((D.z in config.station_levels))
//if(length(D.req_access) > 0 && !(12 in D.req_access)) //not counting general access and maintenance airlocks
airlocknum++
spawn(0)
@@ -235,7 +235,7 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is
spawn(0)
world << "Started processing FIREDOORS"
for (var/obj/machinery/door/firedoor/D in world)
- if(D.z == 1)
+ if((D.z in config.station_levels))
firedoornum++;
spawn(0)
D.ion_act()
diff --git a/code/modules/events/mass_hallucination.dm b/code/modules/events/mass_hallucination.dm
index 571a9ae7d1f..b3fbea5343c 100644
--- a/code/modules/events/mass_hallucination.dm
+++ b/code/modules/events/mass_hallucination.dm
@@ -3,4 +3,4 @@
if(!(C.species.flags & IS_SYNTHETIC))
C.hallucination += rand(50, 100)
/datum/event/mass_hallucination/announce()
- command_alert("It seems that station [station_name()] is passing through a minor radiation field, this may cause some hallucination, but no further damage")
\ No newline at end of file
+ command_announcement.Announce("It seems that station [station_name()] is passing through a minor radiation field, this may cause some hallucination, but no further damage")
\ No newline at end of file
diff --git a/code/modules/events/meteors.dm b/code/modules/events/meteors.dm
index 0f74d65b7d9..42b0b1eda1d 100644
--- a/code/modules/events/meteors.dm
+++ b/code/modules/events/meteors.dm
@@ -9,15 +9,14 @@
endWhen = rand(10,25) * 3
/datum/event/meteor_wave/announce()
- command_alert("Meteors have been detected on collision course with the station.", "Meteor Alert")
- world << sound('sound/AI/meteors.ogg')
-
+ command_announcement.Announce("Meteors have been detected on collision course with the station.", "Meteor Alert", new_sound = 'sound/AI/meteors.ogg')
+
/datum/event/meteor_wave/tick()
if(IsMultiple(activeFor, 3))
spawn_meteors(rand(2,5))
/datum/event/meteor_wave/end()
- command_alert("The station has cleared the meteor storm.", "Meteor Alert")
+ command_announcement.Announce("The station has cleared the meteor storm.", "Meteor Alert")
//
/datum/event/meteor_shower
@@ -30,7 +29,7 @@
waves = rand(1,4)
/datum/event/meteor_shower/announce()
- command_alert("The station is now in a meteor shower.", "Meteor Alert")
+ command_announcement.Announce("The station is now in a meteor shower.", "Meteor Alert")
//meteor showers are lighter and more common,
/datum/event/meteor_shower/tick()
@@ -44,4 +43,4 @@
endWhen = next_meteor + 1
/datum/event/meteor_shower/end()
- command_alert("The station has cleared the meteor shower", "Meteor Alert")
+ command_announcement.Announce("The station has cleared the meteor shower", "Meteor Alert")
diff --git a/code/modules/events/prison_break.dm b/code/modules/events/prison_break.dm
index 87135bda526..676661f2b7e 100644
--- a/code/modules/events/prison_break.dm
+++ b/code/modules/events/prison_break.dm
@@ -15,7 +15,7 @@
/datum/event/prison_break/announce()
if(prisonAreas && prisonAreas.len > 0)
- command_alert("[pick("Gr3y.T1d3 virus","Malignant trojan")] detected in [station_name()] imprisonment subroutines. Recommend station AI involvement.", "Security Alert")
+ command_announcement.Announce("[pick("Gr3y.T1d3 virus","Malignant trojan")] detected in [station_name()] imprisonment subroutines. Recommend station AI involvement.", "Security Alert")
else
world.log << "ERROR: Could not initate grey-tide. Unable find prison or brig area."
kill()
@@ -30,7 +30,7 @@
/datum/event/prison_break/announce()
if(prisonAreas && prisonAreas.len > 0)
- command_alert("[pick("Gr3y.T1d3 virus","Malignant trojan")] detected in [station_name()] imprisonment subroutines. Recommend station AI involvement.", "Security Alert")
+ command_announcement.Announce("[pick("Gr3y.T1d3 virus","Malignant trojan")] detected in [station_name()] imprisonment subroutines. Recommend station AI involvement.", "Security Alert")
else
world.log << "ERROR: Could not initate grey-tide. Unable find prison or brig area."
kill()
diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm
index 58b5f60c2cc..5daabc84799 100644
--- a/code/modules/events/radiation_storm.dm
+++ b/code/modules/events/radiation_storm.dm
@@ -22,11 +22,10 @@
/datum/event/radiation_storm/start()
spawn()
- world << sound('sound/AI/radiation.ogg')
- command_alert("High levels of radiation detected near the station. Please evacuate into one of the shielded maintenance tunnels.", "Anomaly Alert")
+ command_announcement.Announce("High levels of radiation detected near the station. Please evacuate into one of the shielded maintenance tunnels.", "Anomaly Alert", new_sound = 'sound/AI/radiation.ogg')
for(var/area/A in world)
- if(A.z != 1 || is_safe_zone(A))
+ if(!(A.z in config.station_levels) || is_safe_zone(A))
continue
A.radiation_alert()
@@ -36,7 +35,7 @@
sleep(600)
- command_alert("The station has entered the radiation belt. Please remain in a sheltered area until we have passed the radiation belt.", "Anomaly Alert")
+ command_announcement.Announce("The station has entered the radiation belt. Please remain in a sheltered area until we have passed the radiation belt.", "Anomaly Alert")
for(var/i = 0, i < 10, i++)
for(var/mob/living/carbon/human/H in living_mob_list)
@@ -45,7 +44,7 @@
var/turf/T = get_turf(H)
if(!T)
continue
- if(T.z != 1 || is_safe_zone(T.loc))
+ if(!(T.z in config.station_levels) || is_safe_zone(T.loc))
continue
if(istype(H,/mob/living/carbon/human))
@@ -64,16 +63,16 @@
var/turf/T = get_turf(M)
if(!T)
continue
- if(T.z != 1)
+ if(!(T.z in config.station_levels))
continue
M.apply_effect((rand(5,25)),IRRADIATE,0)
sleep(100)
- command_alert("The station has passed the radiation belt. Please report to medbay if you experience any unusual symptoms. Maintenance will lose all access again shortly.", "Anomaly Alert")
+ command_announcement.Announce("The station has passed the radiation belt. Please report to medbay if you experience any unusual symptoms. Maintenance will lose all access again shortly.", "Anomaly Alert")
for(var/area/A in world)
- if(A.z != 1 || is_safe_zone(A))
+ if(!(A.z in config.station_levels) || is_safe_zone(A))
continue
A.reset_radiation_alert()
diff --git a/code/modules/events/rogue_drones.dm b/code/modules/events/rogue_drones.dm
index d3ccaa4d89a..d96c80f60f8 100644
--- a/code/modules/events/rogue_drones.dm
+++ b/code/modules/events/rogue_drones.dm
@@ -30,7 +30,7 @@
msg = "Contact has been lost with a combat drone wing operating out of the NMV Icarus. If any are sighted in the area, approach with caution."
else
msg = "Unidentified hackers have targetted a combat drone wing deployed from the NMV Icarus. If any are sighted in the area, approach with caution."
- command_alert(msg, "Rogue drone alert")
+ command_announcement.Announce(msg, "Rogue drone alert")
/datum/event/rogue_drone/tick()
@@ -49,6 +49,6 @@
num_recovered++
if(num_recovered > drones_list.len * 0.75)
- command_alert("Icarus drone control reports the malfunctioning wing has been recovered safely.", "Rogue drone alert")
+ command_announcement.Announce("Icarus drone control reports the malfunctioning wing has been recovered safely.", "Rogue drone alert")
else
- command_alert("Icarus drone control registers disappointment at the loss of the drones, but the survivors have been recovered.", "Rogue drone alert")
+ command_announcement.Announce("Icarus drone control registers disappointment at the loss of the drones, but the survivors have been recovered.", "Rogue drone alert")
diff --git a/code/modules/events/sayuevents/meaty_ores.dm b/code/modules/events/sayuevents/meaty_ores.dm
index a44708693ef..d6e640934d9 100644
--- a/code/modules/events/sayuevents/meaty_ores.dm
+++ b/code/modules/events/sayuevents/meaty_ores.dm
@@ -1,9 +1,8 @@
/datum/event/dust/meaty/announce()
if(prob(16))
- command_alert("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert")
+ command_announcement.Announce("Unknown biological entities have been detected near [station_name()], please stand-by.", "Lifesign Alert")
else
- command_alert("Meaty ores have been detected on collision course with the station.", "Meaty Ore Alert")
- world << sound('sound/AI/meteors.ogg')
+ command_announcement.Announce("Meaty ores have been detected on collision course with the station.", "Meaty Ore Alert",new_sound = 'sound/AI/meteors.ogg')
/datum/event/dust/meaty/setup()
qnty = rand(45,125)
diff --git a/code/modules/events/sayuevents/undead.dm b/code/modules/events/sayuevents/undead.dm
index f9d82baf086..84c1c0bb1b1 100644
--- a/code/modules/events/sayuevents/undead.dm
+++ b/code/modules/events/sayuevents/undead.dm
@@ -8,7 +8,7 @@
RS.start()
RS.kill()
for(var/area/A)
- if(A.z != 1) continue //Spook on main station only.
+ if(!(A.z in config.station_levels)) continue //Spook on main station only.
if(A.luminosity) continue
// if(A.lighting_space) continue
if(A.type == /area) continue
diff --git a/code/modules/events/sayuevents/wormholes.dm b/code/modules/events/sayuevents/wormholes.dm
index e120d11630d..c31645d7a00 100644
--- a/code/modules/events/sayuevents/wormholes.dm
+++ b/code/modules/events/sayuevents/wormholes.dm
@@ -13,7 +13,7 @@
/datum/event/wormholes/start()
for(var/turf/simulated/floor/T in world)
- if(T.z == 1)
+ if((T.z in config.station_levels))
pick_turfs += T
for(var/i = 1, i <= number_of_wormholes, i++)
@@ -21,10 +21,7 @@
wormholes += new /obj/effect/portal/wormhole(T, null, null, -1)
/datum/event/wormholes/announce()
- command_alert("Space-time anomalies detected on the station. There is no additional data.", "Anomaly Alert")
- for(var/mob/M in player_list)
- if(!istype(M, /mob/new_player))
- M << sound('sound/AI/spanomalies.ogg')
+ command_announcement.Announce("Space-time anomalies detected on the station. There is no additional data.", "Anomaly Alert", new_sound = 'sound/AI/spanomalies.ogg')
/datum/event/wormholes/tick()
if(activeFor % shift_frequency == 0)
diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm
index 7a953d3fd40..227737ba99c 100644
--- a/code/modules/events/spider_infestation.dm
+++ b/code/modules/events/spider_infestation.dm
@@ -12,15 +12,13 @@
sent_spiders_to_station = 1
/datum/event/spider_infestation/announce()
- command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert")
- world << sound('sound/AI/aliens.ogg')
-
+ command_announcement.Announce("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", new_sound = 'sound/AI/aliens.ogg')
/datum/event/spider_infestation/start()
var/list/vents = list()
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world)
- if(temp_vent.loc.z == 1 && !temp_vent.welded && temp_vent.network)
+ if((temp_vent.loc.z in config.station_levels) && !temp_vent.welded && temp_vent.network)
if(temp_vent.network.normal_members.len > 50)
vents += temp_vent
diff --git a/code/modules/events/tear.dm b/code/modules/events/tear.dm
index d5d572c3b6a..a11455b351d 100644
--- a/code/modules/events/tear.dm
+++ b/code/modules/events/tear.dm
@@ -5,7 +5,7 @@
var/obj/effect/tear/TE
/datum/event/tear/announce()
- command_alert("A tear in the fabric of space and time has opened. Expected location: [impact_area.name].", "Anomaly Alert")
+ command_announcement.Announce("A tear in the fabric of space and time has opened. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/tear/start()
diff --git a/code/modules/events/tgevents/alien_infestation.dm b/code/modules/events/tgevents/alien_infestation.dm
deleted file mode 100644
index 3d1dca58bc2..00000000000
--- a/code/modules/events/tgevents/alien_infestation.dm
+++ /dev/null
@@ -1,40 +0,0 @@
-/var/global/sent_aliens_to_station = 0
-
-/datum/event/alien_infestation
- announceWhen = 400
-
- var/spawncount = 1
- var/successSpawn = 0 //So we don't make a command report if nothing gets spawned.
-
-
-/datum/event/alien_infestation/setup()
- announceWhen = rand(announceWhen, announceWhen + 50)
- spawncount = rand(1, 2)
- sent_aliens_to_station = 1
-
-
-/datum/event/alien_infestation/announce()
- if(successSpawn)
- command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert")
- world << sound('sound/AI/aliens.ogg')
-
-
-/datum/event/alien_infestation/start()
- var/list/vents = list()
- for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world)
- if(temp_vent.loc.z == 1 && !temp_vent.welded && temp_vent.network)
- if(temp_vent.network.normal_members.len > 50) //Stops Aliens getting stuck in small networks. See: Security, Virology
- vents += temp_vent
-
- var/list/candidates = get_candidates(BE_ALIEN,ALIEN_AFK_BRACKET,"alien","Syndicate")
-
- while(spawncount > 0 && vents.len && candidates.len)
- var/obj/vent = pick_n_take(vents)
- var/client/C = pick_n_take(candidates)
- if(C)
- respawnable_list -= C
- var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc)
- new_xeno.key = C.key
-
- spawncount--
- successSpawn = 1
\ No newline at end of file
diff --git a/code/modules/events/tgevents/anomaly.dm b/code/modules/events/tgevents/anomaly.dm
index 7ab1f25c9ca..a1f951f5747 100644
--- a/code/modules/events/tgevents/anomaly.dm
+++ b/code/modules/events/tgevents/anomaly.dm
@@ -15,7 +15,7 @@
setup(safety_loop)
/datum/event/anomaly/announce()
- command_alert("Localized hyper-energetic flux wave detected on long range scanners. Expected location of impact: [impact_area.name].", "Anomaly Alert")
+ command_announcement.Announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location of impact: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/start()
var/turf/T = pick(get_area_turfs(impact_area))
diff --git a/code/modules/events/tgevents/anomaly_bluespace.dm b/code/modules/events/tgevents/anomaly_bluespace.dm
index 224f6f0e2de..852680e69fa 100644
--- a/code/modules/events/tgevents/anomaly_bluespace.dm
+++ b/code/modules/events/tgevents/anomaly_bluespace.dm
@@ -4,7 +4,7 @@
endWhen = 160
/datum/event/anomaly/anomaly_bluespace/announce()
- command_alert("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
+ command_announcement.Announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/anomaly_bluespace/start()
@@ -21,7 +21,7 @@
var/obj/item/device/radio/beacon/chosen
var/list/possible = list()
for(var/obj/item/device/radio/beacon/W in world)
- if(W.z != 1)
+ if(!(W.z in config.station_levels))
continue
possible += W
@@ -35,7 +35,7 @@
var/turf/TO = get_turf(chosen) // the turf of origin we're travelling TO
playsound(TO, 'sound/effects/phasein.ogg', 100, 1)
- command_alert("Massive bluespace translocation detected.", "Anomaly Alert")
+ command_announcement.Announce("Massive bluespace translocation detected.", "Anomaly Alert")
var/list/flashers = list()
for(var/mob/living/carbon/human/M in viewers(TO, null))
diff --git a/code/modules/events/tgevents/anomaly_flux.dm b/code/modules/events/tgevents/anomaly_flux.dm
index bf2cb2d18cc..d02af07b3ef 100644
--- a/code/modules/events/tgevents/anomaly_flux.dm
+++ b/code/modules/events/tgevents/anomaly_flux.dm
@@ -4,7 +4,7 @@
endWhen = 180
/datum/event/anomaly/anomaly_flux/announce()
- command_alert("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
+ command_announcement.Announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/anomaly_flux/start()
var/turf/T = pick(get_area_turfs(impact_area))
diff --git a/code/modules/events/tgevents/anomaly_grav.dm b/code/modules/events/tgevents/anomaly_grav.dm
index c5430625ea8..0c9f3776f82 100644
--- a/code/modules/events/tgevents/anomaly_grav.dm
+++ b/code/modules/events/tgevents/anomaly_grav.dm
@@ -4,7 +4,7 @@
endWhen = 70
/datum/event/anomaly/anomaly_grav/announce()
- command_alert("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
+ command_announcement.Announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/anomaly_grav/start()
var/turf/T = pick(get_area_turfs(impact_area))
diff --git a/code/modules/events/tgevents/anomaly_pyro.dm b/code/modules/events/tgevents/anomaly_pyro.dm
index 4e7f6a0b947..df4805121cd 100644
--- a/code/modules/events/tgevents/anomaly_pyro.dm
+++ b/code/modules/events/tgevents/anomaly_pyro.dm
@@ -4,7 +4,7 @@
endWhen = 110
/datum/event/anomaly/anomaly_pyro/announce()
- command_alert("Atmospheric anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
+ command_announcement.Announce("Atmospheric anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
/datum/event/anomaly/anomaly_pyro/start()
var/turf/T = pick(get_area_turfs(impact_area))
diff --git a/code/modules/events/tgevents/anomaly_vortex.dm b/code/modules/events/tgevents/anomaly_vortex.dm
index 6f2f999e728..c950444978e 100644
--- a/code/modules/events/tgevents/anomaly_vortex.dm
+++ b/code/modules/events/tgevents/anomaly_vortex.dm
@@ -4,7 +4,7 @@
endWhen = 80
/datum/event/anomaly/anomaly_vortex/announce()
- command_alert("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert")
+ command_announcement.Announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert")
/datum/event/anomaly/anomaly_vortex/start()
var/turf/T = pick(get_area_turfs(impact_area))
diff --git a/code/modules/events/tgevents/brand_intelligence.dm b/code/modules/events/tgevents/brand_intelligence.dm
index 893cee98cf1..1cfeba0cd08 100644
--- a/code/modules/events/tgevents/brand_intelligence.dm
+++ b/code/modules/events/tgevents/brand_intelligence.dm
@@ -8,7 +8,7 @@
/datum/event/brand_intelligence/announce()
- command_alert("Rampant brand intelligence has been detected aboard [station_name()], please stand-by.", "Machine Learning Alert")
+ command_announcement.Announce("Rampant brand intelligence has been detected aboard [station_name()], please stand-by.", "Machine Learning Alert")
/datum/event/brand_intelligence/start()
diff --git a/code/modules/events/tgevents/immovable_rod.dm b/code/modules/events/tgevents/immovable_rod.dm
index 25c3d0308d4..ec86e89981f 100644
--- a/code/modules/events/tgevents/immovable_rod.dm
+++ b/code/modules/events/tgevents/immovable_rod.dm
@@ -12,7 +12,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
announceWhen = 5
/datum/event/immovable_rod/announce()
- command_alert("What the fuck was that?!", "General Alert")
+ command_announcement.Announce("What the fuck was that?!", "General Alert")
/datum/event/immovable_rod/start()
var/startx = 0
diff --git a/code/modules/events/tgevents/mass_hallucination.dm b/code/modules/events/tgevents/mass_hallucination.dm
index 6a34331acb3..f23a2c15510 100644
--- a/code/modules/events/tgevents/mass_hallucination.dm
+++ b/code/modules/events/tgevents/mass_hallucination.dm
@@ -6,4 +6,4 @@
if(!(C.species.flags & IS_SYNTHETIC))
C.hallucination += rand(50, 100)
/datum/event/mass_hallucination/announce()
- command_alert("It seems that station [station_name()] is passing through a minor radiation field, this may cause some hallucination, but no further damage")
\ No newline at end of file
+ command_announcement.Announce("It seems that station [station_name()] is passing through a minor radiation field, this may cause some hallucination, but no further damage")
\ No newline at end of file
diff --git a/code/modules/events/tgevents/spider_infestation.dm b/code/modules/events/tgevents/spider_infestation.dm
deleted file mode 100644
index 1f4cccdf418..00000000000
--- a/code/modules/events/tgevents/spider_infestation.dm
+++ /dev/null
@@ -1,33 +0,0 @@
-/var/global/sent_spiders_to_station = 0
-
-/datum/event/spider_infestation
- announceWhen = 400
-
- var/spawncount = 1
-
-
-/datum/event/spider_infestation/setup()
- announceWhen = rand(announceWhen, announceWhen + 50)
- spawncount = round(num_players() * 1.5)
- sent_spiders_to_station = 1
-
-/datum/event/spider_infestation/announce()
- command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert")
- world << sound('sound/AI/aliens.ogg')
-
-
-/datum/event/spider_infestation/start()
-
- var/list/vents = list()
- for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world)
- if(temp_vent.loc.z == 1 && !temp_vent.welded && temp_vent.network)
- if(temp_vent.network.normal_members.len > 50)
- vents += temp_vent
-
- while((spawncount >= 1) && vents.len)
- var/obj/vent = pick(vents)
- var/obj/effect/spider/spiderling/S = new(vent.loc)
- if(prob(66))
- S.grow_as = /mob/living/simple_animal/hostile/giant_spider/nurse
- vents -= vent
- spawncount--
\ No newline at end of file
diff --git a/code/modules/events/tgevents/vent_clog.dm b/code/modules/events/tgevents/vent_clog.dm
index 885552dff28..061450a197d 100755
--- a/code/modules/events/tgevents/vent_clog.dm
+++ b/code/modules/events/tgevents/vent_clog.dm
@@ -6,13 +6,13 @@
var/list/vents = list()
/datum/event/vent_clog/announce()
- command_alert("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "Atmospherics alert")
+ command_announcement.Announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "Atmospherics alert")
/datum/event/vent_clog/setup()
endWhen = rand(25, 100)
for(var/obj/machinery/atmospherics/unary/vent_scrubber/temp_vent in machines)
- if(temp_vent.loc.z == 1 && temp_vent.network)
+ if((temp_vent.loc.z in config.station_levels) && temp_vent.network)
if(temp_vent.network.normal_members.len > 50)
vents += temp_vent
diff --git a/code/modules/events/viral_infection.dm b/code/modules/events/viral_infection.dm
index 876e3453896..9ee3a47077a 100644
--- a/code/modules/events/viral_infection.dm
+++ b/code/modules/events/viral_infection.dm
@@ -8,8 +8,7 @@ datum/event/viral_infection/setup()
severity = rand(1, 3)
datum/event/viral_infection/announce()
- command_alert("Confirmed outbreak of level five viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert")
- world << sound('sound/AI/outbreak5.ogg')
+ command_announcement.Announce("Confirmed outbreak of level five viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = 'sound/AI/outbreak5.ogg')
datum/event/viral_infection/start()
var/list/candidates = list() //list of candidate keys
diff --git a/code/modules/events/viral_outbreak.dm b/code/modules/events/viral_outbreak.dm
index f11acd511f3..9e139f5742b 100644
--- a/code/modules/events/viral_outbreak.dm
+++ b/code/modules/events/viral_outbreak.dm
@@ -8,8 +8,7 @@ datum/event/viral_outbreak/setup()
severity = rand(2, 4)
datum/event/viral_outbreak/announce()
- command_alert("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert")
- world << sound('sound/AI/outbreak7.ogg')
+ command_announcement.Announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = 'sound/AI/outbreak7.ogg')
datum/event/viral_outbreak/start()
var/list/candidates = list() //list of candidate keys
diff --git a/code/modules/events/wallrot.dm b/code/modules/events/wallrot.dm
index 739ca92411b..b36f7f93760 100644
--- a/code/modules/events/wallrot.dm
+++ b/code/modules/events/wallrot.dm
@@ -3,7 +3,7 @@ datum/event/wallrot/setup()
endWhen = announceWhen + 1
datum/event/wallrot/announce()
- command_alert("Harmful fungi detected on station. Station structures may be contaminated.", "Biohazard Alert")
+ command_announcement.Announce("Harmful fungi detected on station. Station structures may be contaminated.", "Biohazard Alert")
datum/event/wallrot/start()
spawn()
diff --git a/code/modules/karma/karma.dm b/code/modules/karma/karma.dm
index 12924560685..0b97d51c8b3 100644
--- a/code/modules/karma/karma.dm
+++ b/code/modules/karma/karma.dm
@@ -52,42 +52,42 @@ var/list/karma_spenders = list()
set name = "Award Karma"
set desc = "Let the gods know whether someone's been nice. Can only be used once per round."
set category = "Special Verbs"
-
+
if(!ticker || !player_list.len)
usr << "\red You can't award karma until the game has started."
return
-
+
if(ticker.current_state == GAME_STATE_PREGAME)
usr << "\red You can't award karma until the game has started."
- return
+ return
var/list/karma_list = list("Cancel")
- for(var/mob/M in player_list) if(M.client && M.mind)
+ for(var/mob/M in player_list) if(M.client && M.mind)
var/special_role = M.mind.special_role
if (special_role == "Wizard" || special_role == "Ninja" || special_role == "Syndicate" || special_role == "Syndicate Commando" || special_role == "Vox Raider" || special_role == "Alien") // Don't include special roles, because players use it to meta
continue
karma_list += M
-
+
if(!karma_list.len || karma_list.len == 1)
usr << "\red There's no-one to spend your karma on."
return
-
+
var/pickedmob = input("Who would you like to award Karma to?", "Award Karma", "Cancel") as null|mob in karma_list
-
+
if(isnull(pickedmob))
return
-
+
if(!istype(pickedmob, /mob))
usr << "\red That's not a mob."
- return
-
+ return
+
spend_karma(pickedmob)
-
-/mob/verb/spend_karma(var/mob/M)
+
+/mob/verb/spend_karma(var/mob/M)
set name = "Award Karma to Player"
set desc = "Let the gods know whether someone's been nice. Can only be used once per round."
set category = "Special Verbs"
-
+
if(!M)
usr << "Please right click a mob to award karma directly, or use the 'Award Karma' verb to select a player from the player listing."
return
@@ -115,6 +115,9 @@ var/list/karma_spenders = list()
if(!choice || choice == "Cancel")
return
if(choice == "Good" && !(src.client.karma_spent))
+ if(src.client.karma_spent)
+ usr << "\red You've already spent your karma for the round."
+ return
M.client.karma += 1
usr << "[choice] karma spent on [M.name]."
src.client.karma_spent = 1
@@ -199,7 +202,7 @@ You've gained [totalkarma] total karma in your time here.
"}
Unlock Vox -- 45KP
Unlock Slime People -- 45KP
"}
-
+
if (2) // Karma Refunds
var/list/refundable = list()
var/list/purchased = checkpurchased()
@@ -208,31 +211,31 @@ You've gained [totalkarma] total karma in your time here.
"}
dat += "Refund Tajaran Ambassador -- 30KP
"
if("Unathi Ambassador" in purchased)
refundable += "Unathi Ambassador"
- dat += "Refund Unathi Ambassador -- 30KP
"
+ dat += "Refund Unathi Ambassador -- 30KP
"
if("Skrell Ambassador" in purchased)
refundable += "Skrell Ambassador"
- dat += "Refund Skrell Ambassador -- 30KP
"
+ dat += "Refund Skrell Ambassador -- 30KP
"
if("Diona Ambassador" in purchased)
refundable += "Diona Ambassador"
- dat += "Refund Diona Ambassador -- 30KP
"
+ dat += "Refund Diona Ambassador -- 30KP
"
if("Kidan Ambassador" in purchased)
refundable += "Kidan Ambassador"
- dat += "Refund Kidan Ambassador -- 30KP
"
+ dat += "Refund Kidan Ambassador -- 30KP
"
if("Slime People Ambassador" in purchased)
refundable += "Slime People Ambassador"
- dat += "Refund Slime People Ambassador -- 30KP
"
+ dat += "Refund Slime People Ambassador -- 30KP
"
if("Grey Ambassador" in purchased)
refundable += "Grey Ambassador"
- dat += "Refund Grey Ambassador -- 30KP
"
+ dat += "Refund Grey Ambassador -- 30KP
"
if("Vox Ambassador" in purchased)
refundable += "Vox Ambassador"
dat += "Refund Vox Ambassador -- 30KP
"
if("Customs Officer" in purchased)
refundable += "Customs Officer"
- dat += "Refund Customs Officer -- 30KP
"
+ dat += "Refund Customs Officer -- 30KP
"
if("Nanotrasen Recruiter" in purchased)
refundable += "Nanotrasen Recruiter"
- dat += "Refund Nanotrasen Recruiter -- 10KP
"
+ dat += "Refund Nanotrasen Recruiter -- 10KP
"
if(!refundable.len)
dat += "You do not have any refundable karma purchases.
"
@@ -345,7 +348,7 @@ You've gained [totalkarma] total karma in your time here.
"}
usr << "You have been charged [cost] karma."
message_admins("[key_name(usr)] has been charged [cost] karma.")
return
-
+
/client/proc/karmarefund(var/type,var/name,var/cost)
if(name == "Tajaran Ambassador")
cost = 30
@@ -368,12 +371,12 @@ You've gained [totalkarma] total karma in your time here.
"}
else if(name == "Nanotrasen Recruiter")
cost = 10
else
- usr << "\red That job is not refundable."
+ usr << "\red That job is not refundable."
return
-
+
var/DBQuery/query = dbcon.NewQuery("SELECT * FROM whitelist WHERE ckey='[usr.key]'")
query.Execute()
-
+
var/dbjob
var/dbspecies
var/dbckey
@@ -381,7 +384,7 @@ You've gained [totalkarma] total karma in your time here.
"}
dbckey = query.item[2]
dbjob = query.item[3]
dbspecies = query.item[4]
-
+
if(dbckey)
var/list/typelist = list()
if(type == "job")
@@ -389,8 +392,8 @@ You've gained [totalkarma] total karma in your time here.
"}
else if(type == "species")
typelist = text2list(dbspecies,",")
else
- usr << "\red Type [type] is not a valid column."
-
+ usr << "\red Type [type] is not a valid column."
+
if(name in typelist)
typelist -= name
var/newtypelist = list2text(typelist,",")
@@ -406,14 +409,14 @@ You've gained [totalkarma] total karma in your time here.
"}
karmacharge(text2num(cost),1)
else
usr << "\red You have not bought [name]."
-
+
else
- usr << "\red Your ckey ([dbckey]) was not found."
-
+ usr << "\red Your ckey ([dbckey]) was not found."
+
/client/proc/checkpurchased(var/name = null) // If the first parameter is null, return a full list of purchases
var/DBQuery/query = dbcon.NewQuery("SELECT * FROM whitelist WHERE ckey='[usr.key]'")
- query.Execute()
-
+ query.Execute()
+
var/dbjob
var/dbspecies
var/dbckey
@@ -421,7 +424,7 @@ You've gained [totalkarma] total karma in your time here.
"}
dbckey = query.item[2]
dbjob = query.item[3]
dbspecies = query.item[4]
-
+
if(dbckey)
var/list/joblist = text2list(dbjob,",")
var/list/specieslist = text2list(dbspecies,",")
@@ -434,4 +437,4 @@ You've gained [totalkarma] total karma in your time here.
"}
else
return combinedlist
else
- return 0
+ return 0
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index c1fdb193485..66c19bfcda0 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -238,8 +238,6 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
onclose(user, "library")
/obj/machinery/librarycomp/attackby(obj/item/weapon/W as obj, mob/user as mob)
- if (src.density && istype(W, /obj/item/weapon/card/emag))
- src.emagged = 1
if(istype(W, /obj/item/weapon/barcodescanner))
var/obj/item/weapon/barcodescanner/scanner = W
scanner.computer = src
@@ -248,6 +246,10 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
V.show_message("[src] lets out a low, short blip.", 2)
else
..()
+
+/obj/machinery/librarycomp/emag_act(user as mob)
+ if (src.density)
+ src.emagged = 1
/obj/machinery/librarycomp/Topic(href, href_list)
if(..())
diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm
index 1a0315b957d..82bc3a0f287 100644
--- a/code/modules/mining/equipment_locker.dm
+++ b/code/modules/mining/equipment_locker.dm
@@ -324,7 +324,7 @@
var/list/L = list()
for(var/obj/item/device/radio/beacon/B in world)
var/turf/T = get_turf(B)
- if(T.z == 1)
+ if((T.z in config.station_levels))
L += B
if(!L.len)
user << "The [src.name] failed to create a wormhole."
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index 0e0889bc637..ed588a76482 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -63,9 +63,10 @@
/obj/machinery/mineral/labor_claim_console/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/weapon/card/id))
return attack_hand(user)
- else if(istype(I, /obj/item/weapon/card/emag))
- return emag(user)
..()
+
+/obj/machinery/mineral/labor_claim_console/emag_act(user as mob)
+ emag(user)
/obj/machinery/mineral/labor_claim_console/proc/emag(mob/user as mob)
if(!emagged)
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index 3a39126d517..f6c03ee308b 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -55,19 +55,22 @@
flags = CONDUCT
slot_flags = SLOT_BELT
force = 15.0
- throwforce = 4.0
+ throwforce = 10.0
item_state = "pickaxe"
w_class = 4.0
m_amt = 3750 //one sheet, but where can you make them?
var/digspeed = 40 //moving the delay to an item var so R&D can make improved picks. --NEO
origin_tech = "materials=1;engineering=1"
attack_verb = list("hit", "pierced", "sliced", "attacked")
- var/drill_sound = 'sound/weapons/Genhit.ogg'
+ var/list/digsound = list('sound/effects/picaxe1.ogg','sound/effects/picaxe2.ogg','sound/effects/picaxe3.ogg')
var/drill_verb = "picking"
sharp = 1
var/excavation_amount = 100
+ proc/playDigSound()
+ playsound(src, pick(digsound),20,1)
+
hammer
name = "sledgehammer"
//icon_state = "sledgehammer" Waiting on sprite
@@ -86,6 +89,8 @@
icon_state = "handdrill"
item_state = "jackhammer"
digspeed = 30
+ hitsound = 'sound/weapons/drill.ogg'
+ digsound = list('sound/weapons/drill.ogg')
origin_tech = "materials=2;powerstorage=3;engineering=2"
desc = "Yours is the drill that will pierce through the rock walls."
@@ -94,6 +99,8 @@
icon_state = "jackhammer"
item_state = "jackhammer"
digspeed = 15 //faster than drill, but cannot dig
+ hitsound = 'sound/weapons/sonic_jackhammer.ogg'
+ digsound = list('sound/weapons/sonic_jackhammer.ogg')
origin_tech = "materials=3;powerstorage=2;engineering=2"
desc = "Cracks rocks with sonic blasts, perfect for killing cave lizards."
@@ -112,6 +119,8 @@
w_class = 3.0 //it is smaller than the pickaxe
damtype = "fire"
digspeed = 20 //Can slice though normal walls, all girders, or be used in reinforced wall deconstruction/ light thermite on fire
+ hitsound = 'sound/weapons/plasma_cutter.ogg'
+ digsound = list('sound/weapons/plasma_cutter.ogg')
origin_tech = "materials=4;plasmatech=3;engineering=3"
desc = "A rock cutter that uses bursts of hot plasma. You could use it to cut limbs off of xenos! Or, you know, mine stuff."
@@ -129,6 +138,8 @@
item_state = "jackhammer"
digspeed = 5 //Digs through walls, girders, and can dig up sand
origin_tech = "materials=6;powerstorage=4;engineering=5"
+ hitsound = 'sound/weapons/drill.ogg'
+ digsound = list('sound/weapons/drill.ogg')
desc = "Yours is the drill that will pierce the heavens!"
traitor //Pocket-sized traitor diamond drill.
@@ -143,6 +154,8 @@
icon_state = "jackhammer"
item_state = "jackhammer"
digspeed = 15
+ hitsound = 'sound/weapons/drill.ogg'
+ digsound = list('sound/weapons/drill.ogg')
desc = ""
/*****************************Shovel********************************/
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index b315ae31e5b..97216012983 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -137,7 +137,7 @@
return
last_act = world.time
- playsound(user, P.drill_sound, 20, 1)
+ P.playDigSound()
//handle any archaeological finds we might uncover
var/fail_message
diff --git a/code/modules/mining/ore.dm b/code/modules/mining/ore.dm
index fd3598ae985..866b46bae50 100644
--- a/code/modules/mining/ore.dm
+++ b/code/modules/mining/ore.dm
@@ -84,7 +84,7 @@
/obj/item/weapon/ore/New()
pixel_x = rand(0,16)-8
pixel_y = rand(0,8)-8
- if(src.z == 5) score_oremined++ //When ore spawns, increment score. Only include ore spawned on mining asteroid (No Clown Planet)
+ if(src.z == ASTEROID_Z) score_oremined++ //When ore spawns, increment score. Only include ore spawned on mining asteroid (No Clown Planet)
/obj/item/weapon/ore/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W,/obj/item/device/core_sampler))
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 517a91a3501..2db6b56b75a 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -74,7 +74,7 @@ var/const/ALIEN_AFK_BRACKET = 450 // 45 seconds
AttemptGrow()
/obj/item/alien_embryo/proc/AttemptGrow(var/gib_on_success = 1)
- var/list/candidates = get_candidates(BE_ALIEN,ALIEN_AFK_BRACKET,"alien","Syndicate")
+ var/list/candidates = get_candidates(BE_ALIEN,ALIEN_AFK_BRACKET,1)
var/client/C = null
// To stop clientless larva, we will check that our host has a client
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 99c5e7a1ced..dfdd8b41195 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -130,7 +130,9 @@
//handcuffed?
if(handcuffed)
- if(istype(handcuffed, /obj/item/weapon/handcuffs/cable))
+ if(istype(handcuffed, /obj/item/weapon/restraints/handcuffs/cable/zipties))
+ msg += "[t_He] [t_is] \icon[handcuffed] restrained with zipties!\n"
+ else if(istype(handcuffed, /obj/item/weapon/restraints/handcuffs/cable))
msg += "[t_He] [t_is] \icon[handcuffed] restrained with cable!\n"
else
msg += "[t_He] [t_is] \icon[handcuffed] handcuffed!\n"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 2216038aeaa..5f3a0cca482 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -538,7 +538,21 @@
var/obj/vehicle/V = AM
V.RunOver(src)
-
+// Get rank from ID, ID inside PDA, PDA, ID in wallet, etc.
+/mob/living/carbon/human/proc/get_authentification_rank(var/if_no_id = "No id", var/if_no_job = "No job")
+ var/obj/item/device/pda/pda = wear_id
+ if (istype(pda))
+ if (pda.id)
+ return pda.id.rank
+ else
+ return pda.ownrank
+ else
+ var/obj/item/weapon/card/id/id = get_idcard()
+ if(id)
+ return id.rank ? id.rank : if_no_job
+ else
+ return if_no_id
+
//gets assignment from ID or ID inside PDA or PDA itself
//Useful when player do something with computers
/mob/living/carbon/human/proc/get_assignment(var/if_no_id = "No id", var/if_no_job = "No job")
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 11ef4a1d587..de100bc759b 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -198,7 +198,17 @@ emp_act
I.emp_act(severity)
..()
-
+/mob/living/carbon/human/emag_act(user as mob, var/datum/organ/external/affecting)
+ if(!(affecting.status & ORGAN_ROBOT))
+ user << "\red That limb isn't robotic."
+ return
+ if(affecting.sabotaged)
+ user << "\red [src]'s [affecting.display_name] is already sabotaged!"
+ else
+ user << "\red You sneakily slide the card into the dataport on [src]'s [affecting.display_name] and short out the safeties."
+ affecting.sabotaged = 1
+ return 1
+
//Returns 1 if the attack hit, 0 if it missed.
/mob/living/carbon/human/proc/attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone)
if(!I || !user) return 0
@@ -236,17 +246,8 @@ emp_act
return 0
if(istype(I,/obj/item/weapon/card/emag))
- if(!(affecting.status & ORGAN_ROBOT))
- user << "\red That limb isn't robotic."
- return
- if(affecting.sabotaged)
- user << "\red [src]'s [affecting.display_name] is already sabotaged!"
- else
- user << "\red You sneakily slide [I] into the dataport on [src]'s [affecting.display_name] and short out the safeties."
- var/obj/item/weapon/card/emag/emag = I
- emag.uses--
- affecting.sabotaged = 1
- return 1
+ emag_act(user, affecting)
+
if(! I.discrete)
if(I.attack_verb.len)
visible_message("\red [src] has been [pick(I.attack_verb)] in the [hit_area] with [I.name] by [user]!")
@@ -337,6 +338,15 @@ emp_act
/mob/living/carbon/human/hitby(atom/movable/AM as mob|obj,var/speed = 5)
if(istype(AM,/obj/))
var/obj/O = AM
+
+ if(in_throw_mode && !get_active_hand() && speed <= 5) //empty active hand and we're in throw mode
+ if(canmove && !restrained())
+ if(isturf(O.loc))
+ put_in_active_hand(O)
+ visible_message("[src] catches [O]!")
+ throw_mode_off()
+ return
+
var/zone = ran_zone("chest", 65)
var/dtype = BRUTE
if(istype(O,/obj/item/weapon))
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 8eb38c1e7b0..8319046d5d5 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -1537,7 +1537,7 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc
// Not on the station or mining?
var/turf/temp_turf = get_turf(remoteview_target)
- if((temp_turf.z != 1 && temp_turf.z != 5) || remoteview_target.stat!=CONSCIOUS)
+ if((!(temp_turf.z in config.contact_levels)) || remoteview_target.stat!=CONSCIOUS)
src << "\red Your psy-connection grows too faint to maintain!"
isRemoteObserve = 0
if(!isRemoteObserve && client && !client.adminobs)
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 200ade3009a..9a47536c759 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -918,7 +918,7 @@ proc/get_damage_icon_part(damage_state, body_part)
var/obj/screen/inventory/L = hud_used.adding[8]
R.overlays += image("icon"='icons/mob/screen_gen.dmi', "icon_state"="markus")
L.overlays += image("icon"='icons/mob/screen_gen.dmi', "icon_state"="gabrielle")
- if(istype(handcuffed, /obj/item/weapon/handcuffs/pinkcuffs))
+ if(istype(handcuffed, /obj/item/weapon/restraints/handcuffs/pinkcuffs))
overlays_standing[HANDCUFF_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "pinkcuff1")
else
overlays_standing[HANDCUFF_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "handcuff1")
diff --git a/code/modules/mob/living/carbon/monkey/inventory.dm b/code/modules/mob/living/carbon/monkey/inventory.dm
index 2c5934da530..8ccadd0349c 100644
--- a/code/modules/mob/living/carbon/monkey/inventory.dm
+++ b/code/modules/mob/living/carbon/monkey/inventory.dm
@@ -164,7 +164,7 @@
W.layer = initial(W.layer)
W.add_fingerprint(source)
else
- if (istype(item, /obj/item/weapon/handcuffs))
+ if (istype(item, /obj/item/weapon/restraints/handcuffs))
source.drop_item()
target.handcuffed = item
item.loc = target
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index f159a9ca08c..246f6a1ba01 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -658,8 +658,8 @@
CM.handcuffed = null
CM.update_inv_handcuffed()
else
- var/obj/item/weapon/handcuffs/HC = CM.handcuffed
- var/breakouttime = 1200 //A default in case you are somehow handcuffed with something that isn't an obj/item/weapon/handcuffs type
+ var/obj/item/weapon/restraints/handcuffs/HC = CM.handcuffed
+ var/breakouttime = 1200 //A default in case you are somehow handcuffed with something that isn't an obj/item/weapon/restraints/handcuffs type
var/displaytime = 2 //Minutes to display in the "this will take X minutes."
if(istype(HC)) //If you are handcuffed with actual handcuffs... Well what do I know, maybe someone will want to handcuff you with toilet paper in the future...
breakouttime = HC.breakouttime
@@ -695,7 +695,7 @@
CM.legcuffed = null
CM.update_inv_legcuffed()
else
- var/obj/item/weapon/legcuffs/HC = CM.legcuffed
+ var/obj/item/weapon/restraints/legcuffs/HC = CM.legcuffed
var/breakouttime = 1200 //A default in case you are somehow legcuffed with something that isn't an obj/item/weapon/legcuffs type
var/displaytime = 2 //Minutes to display in the "this will take X minutes."
if(istype(HC)) //If you are legcuffed with actual legcuffs... Well what do I know, maybe someone will want to legcuff you with toilet paper in the future...
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 1714449cd21..117a2d127d5 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -1,3 +1,6 @@
+#define AI_CHECK_WIRELESS 1
+#define AI_CHECK_RADIO 2
+
var/list/ai_list = list()
//Not sure why this is necessary...
@@ -77,8 +80,8 @@ var/list/ai_list = list()
possibleNames -= pickedName
pickedName = null
- real_name = pickedName
- name = real_name
+ aiPDA = new/obj/item/device/pda/ai(src)
+ SetName(pickedName)
anchored = 1
canmove = 0
density = 1
@@ -96,11 +99,6 @@ var/list/ai_list = list()
verbs += /mob/living/silicon/ai/proc/show_laws_verb
- aiPDA = new/obj/item/device/pda/ai(src)
- aiPDA.owner = name
- aiPDA.ownjob = "AI"
- aiPDA.name = name + " (" + aiPDA.ownjob + ")"
-
aiMulti = new(src)
aiRadio = new(src)
aiRadio.myAi = src
@@ -112,7 +110,7 @@ var/list/ai_list = list()
if (istype(loc, /turf))
verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
- /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message, /mob/living/silicon/ai/proc/ai_store_location, /mob/living/silicon/ai/proc/ai_goto_location, /mob/living/silicon/ai/proc/ai_remove_location)
+ /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message, /mob/living/silicon/ai/proc/ai_store_location, /mob/living/silicon/ai/proc/ai_goto_location, /mob/living/silicon/ai/proc/ai_remove_location, /mob/living/silicon/ai/proc/nano_crew_monitor, /mob/living/silicon/ai/proc/ai_cancel_call)
if(!safety)//Only used by AIize() to successfully spawn an AI.
if (!B)//If there is no player/brain inside.
@@ -127,7 +125,7 @@ var/list/ai_list = list()
verbs.Remove(,/mob/living/silicon/ai/proc/ai_call_shuttle,/mob/living/silicon/ai/proc/ai_camera_track, \
/mob/living/silicon/ai/proc/ai_camera_list, /mob/living/silicon/ai/proc/ai_network_change, \
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
- /mob/living/silicon/ai/proc/toggle_camera_light,/mob/living/silicon/ai/verb/pick_icon,/mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message)
+ /mob/living/silicon/ai/proc/toggle_camera_light,/mob/living/silicon/ai/verb/pick_icon,/mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message, /mob/living/silicon/ai/proc/ai_cancel_call)
laws = new /datum/ai_laws/alienmov
else
B.brainmob.mind.transfer_to(src)
@@ -155,11 +153,25 @@ var/list/ai_list = list()
hud_list[IMPCHEM_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
- hud_list[NATIONS_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
+ hud_list[NATIONS_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
+ init_subsystems()
+
ai_list += src
..()
return
+
+/mob/living/silicon/ai/proc/SetName(pickedName as text)
+ real_name = pickedName
+ name = pickedName
+ if(eyeobj)
+ eyeobj.name = "[pickedName] (AI Eye)"
+
+ // Set ai pda name
+ if(aiPDA)
+ aiPDA.ownjob = "AI"
+ aiPDA.owner = pickedName
+ aiPDA.name = pickedName + " (" + aiPDA.ownjob + ")"
/mob/living/silicon/ai/Destroy()
ai_list -= src
@@ -301,14 +313,15 @@ var/list/ai_list = list()
if(src.stat == 2)
src << "You can't call the shuttle because you are dead!"
return
- if(istype(usr,/mob/living/silicon/ai))
- var/mob/living/silicon/ai/AI = src
- if(AI.control_disabled)
- usr << "Wireless control is disabled!"
- return
+
+ if(check_unable(AI_CHECK_WIRELESS))
+ return
var/confirm = alert("Are you sure you want to call the shuttle?", "Confirm Shuttle Call", "Yes", "No")
+ if(check_unable(AI_CHECK_WIRELESS))
+ return
+
if(confirm == "Yes")
call_shuttle_proc(src)
@@ -317,38 +330,57 @@ var/list/ai_list = list()
var/obj/machinery/computer/communications/C = locate() in machines
if(C)
C.post_status("shuttle")
-
return
+
+/mob/living/silicon/ai/proc/ai_cancel_call()
+ set name = "Recall Emergency Shuttle"
+ set category = "AI Commands"
+
+ if(src.stat == 2)
+ src << "You can't send the shuttle back because you are dead!"
+ return
+
+ if(check_unable(AI_CHECK_WIRELESS))
+ return
+
+ var/confirm = alert("Are you sure you want to recall the shuttle?", "Confirm Shuttle Recall", "Yes", "No")
+
+ if(check_unable(AI_CHECK_WIRELESS))
+ return
+
+ if(confirm == "Yes")
+ cancel_call_proc(src)
/mob/living/silicon/ai/cancel_camera()
src.view_core()
/mob/living/silicon/ai/verb/toggle_anchor()
- set category = "AI Commands"
- set name = "Toggle Floor Bolts"
- if(!isturf(loc)) // if their location isn't a turf
- return // stop
- anchored = !anchored // Toggles the anchor
+ set category = "AI Commands"
+ set name = "Toggle Floor Bolts"
+
+ if(!isturf(loc)) // if their location isn't a turf
+ return // stop
+
+ anchored = !anchored // Toggles the anchor
- src << "[anchored ? "You are now anchored." : "You are now unanchored."]"
- // the message in the [] will change depending whether or not the AI is anchored
+ src << "[anchored ? "You are now anchored." : "You are now unanchored."]"
/mob/living/silicon/ai/update_canmove()
return 0
-
-
-/mob/living/silicon/ai/proc/ai_cancel_call()
- set category = "Malfunction"
+
+/mob/living/silicon/ai/proc/announcement()
+ set name = "Announcement"
+ set desc = "Create a vocal announcement by typing in the available words to create a sentence."
+ set category = "AI Commands"
+
if(src.stat == 2)
- src << "You can't send the shuttle back because you are dead!"
+ src << "You can't call make an announcement because you are dead!"
return
- if(istype(usr,/mob/living/silicon/ai))
- var/mob/living/silicon/ai/AI = src
- if(AI.control_disabled)
- src << "Wireless control is disabled!"
- return
- cancel_call_proc(src)
- return
+
+ if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
+ return
+
+ ai_announcement()
/mob/living/silicon/ai/check_eye(var/mob/user as mob)
if (!current)
@@ -581,9 +613,9 @@ var/list/ai_list = list()
src << "Critical error. System offline."
return
- if(control_disabled)
- src << "Wireless communication is disabled."
+ if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
return
+
var/ai_allowed_Zlevel = list(1,3,5)
var/d
var/area/bot_area
@@ -704,6 +736,9 @@ var/list/ai_list = list()
set name = "Jump To Network"
unset_machine()
var/cameralist[0]
+
+ if(check_unable())
+ return
if(usr.stat == 2)
usr << "You can't change your camera network because you are dead!"
@@ -721,6 +756,9 @@ var/list/ai_list = list()
cameralist[i] = i
var/old_network = network
network = input(U, "Which network would you like to view?") as null|anything in cameralist
+
+ if(check_unable())
+ return
if(!U.eyeobj)
U.view_core()
@@ -752,8 +790,16 @@ var/list/ai_list = list()
if(usr.stat == 2)
usr <<"You cannot change your emotional status because you are dead!"
return
+
+ if(check_unable())
+ return
+
var/list/ai_emotions = list("Very Happy", "Happy", "Neutral", "Unsure", "Confused", "Sad", "BSOD", "Blank", "Problems?", "Awesome", "Facepalm", "Friend Computer")
var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions
+
+ if(check_unable())
+ return
+
for (var/obj/machinery/M in machines) //change status
if(istype(M, /obj/machinery/ai_status_display))
var/obj/machinery/ai_status_display/AISD = M
@@ -773,6 +819,9 @@ var/list/ai_list = list()
set name = "Change Hologram"
set desc = "Change the default hologram available to AI to something else."
set category = "AI Commands"
+
+ if(check_unable())
+ return
var/input
if(alert("Would you like to select a hologram based on a crew member or switch to unique avatar?",,"Crew Member","Unique")=="Crew Member")
@@ -827,6 +876,9 @@ var/list/ai_list = list()
if(stat != CONSCIOUS)
return
+
+ if(check_unable())
+ return
camera_light_on = !camera_light_on
src << "Camera lights [camera_light_on ? "activated" : "deactivated"]."
@@ -904,8 +956,11 @@ var/list/ai_list = list()
set name = "Radio Settings"
set desc = "Allows you to change settings of your radio."
set category = "AI Commands"
-
- src << "Accessing Subspace Transceiver control..."
+
+ if(check_unable(AI_CHECK_RADIO))
+ return
+
+ src << "Accessing Subspace Transceiver control..."
if (src.aiRadio)
src.aiRadio.interact(src)
@@ -956,4 +1011,25 @@ var/list/ai_list = list()
src << "\red You deny the request."
else
src << "\red You've failed to open an airlock for [target]"
- return
\ No newline at end of file
+ return
+
+
+/mob/living/silicon/ai/proc/check_unable(var/flags = 0)
+ if(stat == DEAD)
+ usr << "\red You are dead!"
+ return 1
+
+ if((flags & AI_CHECK_WIRELESS) && src.control_disabled)
+ usr << "\red Wireless control is disabled!"
+ return 1
+ if((flags & AI_CHECK_RADIO) && src.aiRadio.disabledAi)
+ src << "\red System Error - Transceiver Disabled!"
+ return 1
+ return 0
+
+/mob/living/silicon/ai/proc/is_in_chassis()
+ return istype(loc, /turf)
+
+#undef AI_CHECK_WIRELESS
+#undef AI_CHECK_RADIO
+
diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm
index c9541858467..dfa05ddc5d0 100644
--- a/code/modules/mob/living/silicon/ai/death.dm
+++ b/code/modules/mob/living/silicon/ai/death.dm
@@ -15,21 +15,21 @@
var/callshuttle = 0
for(var/obj/machinery/computer/communications/commconsole in world)
- if(commconsole.z == 2)
+ if((commconsole.z in config.admin_levels))
continue
if(istype(commconsole.loc,/turf))
break
callshuttle++
for(var/obj/item/weapon/circuitboard/communications/commboard in world)
- if(commboard.z == 2)
+ if((commboard.z in config.admin_levels))
continue
if(istype(commboard.loc,/turf) || istype(commboard.loc,/obj/item/weapon/storage))
break
callshuttle++
for(var/mob/living/silicon/ai/shuttlecaller in player_list)
- if(shuttlecaller.z == 2)
+ if((shuttlecaller.z in config.admin_levels))
continue
if(!shuttlecaller.stat && shuttlecaller.client && istype(shuttlecaller.loc,/turf))
break
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 8218bec993e..ec02433c46a 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -134,7 +134,7 @@
src << "ERROR: Eyeobj not found. Creating new eye..."
src.eyeobj = new(src.loc)
src.eyeobj.ai = src
- src.eyeobj.name = "[src.name] (AI Eye)" // Give it a name
+ src.SetName(src.name)
if(client && client.eye)
client.eye = src
diff --git a/code/modules/mob/living/silicon/ai/nano.dm b/code/modules/mob/living/silicon/ai/nano.dm
new file mode 100644
index 00000000000..f9bb7a25d79
--- /dev/null
+++ b/code/modules/mob/living/silicon/ai/nano.dm
@@ -0,0 +1,10 @@
+var/obj/nano_module/crew_monitor/crew_monitor
+
+/mob/living/silicon/ai/proc/init_subsystems()
+ crew_monitor = new(src)
+
+/mob/living/silicon/ai/proc/nano_crew_monitor()
+ set category = "AI Commands"
+ set name = "Crew Monitor"
+
+ crew_monitor.ui_interact(usr)
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm
index e535a2dedee..b596fd53541 100644
--- a/code/modules/mob/living/silicon/ai/say.dm
+++ b/code/modules/mob/living/silicon/ai/say.dm
@@ -1,32 +1,32 @@
/mob/living/silicon/ai/say(var/message)
- if(parent && istype(parent) && parent.stat != 2)
- parent.say(message)
- return
- //If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead.
- ..(message)
+ if(parent && istype(parent) && parent.stat != 2)
+ parent.say(message) //If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead.
+ return
+
+ ..(message)
/mob/living/silicon/ai/say_understands(var/other)
- if (istype(other, /mob/living/carbon/human))
- return 1
- if (istype(other, /mob/living/silicon/robot))
- return 1
- if (istype(other, /mob/living/silicon/decoy))
- return 1
- if (istype(other, /mob/living/carbon/brain))
- return 1
- if (istype(other, /mob/living/silicon/pai))
- return 1
- return ..()
+ if (istype(other, /mob/living/carbon/human))
+ return 1
+ if (istype(other, /mob/living/silicon/robot))
+ return 1
+ if (istype(other, /mob/living/silicon/decoy))
+ return 1
+ if (istype(other, /mob/living/carbon/brain))
+ return 1
+ if (istype(other, /mob/living/silicon/pai))
+ return 1
+ return ..()
/mob/living/silicon/ai/say_quote(var/text)
- var/ending = copytext(text, length(text))
+ var/ending = copytext(text, length(text))
- if (ending == "?")
- return "queries, \"[text]\"";
- else if (ending == "!")
- return "declares, \"[text]\"";
+ if (ending == "?")
+ return "queries, \"[text]\"";
+ else if (ending == "!")
+ return "declares, \"[text]\"";
- return "states, \"[text]\"";
+ return "states, \"[text]\"";
/mob/living/silicon/ai/proc/IsVocal()
@@ -36,44 +36,28 @@ var/const/VOX_DELAY = 100
var/const/VOX_PATH = "sound/vox_fem/"
/mob/living/silicon/ai/verb/announcement_help()
-
- set name = "Announcement Help"
- set desc = "Display a list of vocal words to announce to the crew."
- set category = "AI Commands"
-
-
- var/dat = "Here is a list of words you can type into the 'Announcement' button to create sentences to vocally announce to everyone on the same level at you.
\
- - You can also click on the word to preview it.
\
- - You can only say 30 words for every announcement.
\
- - Do not use punctuation as you would normally, if you want a pause you can use the full stop and comma characters by separating them with spaces, like so: 'Alpha . Test , Bravo'.
\
- WARNING:
Misuse of the announcement system will get you job banned.
"
-
- var/index = 0
- for(var/word in vox_sounds)
- index++
- dat += "[capitalize(word)]"
- if(index != vox_sounds.len)
- dat += " / "
-
- var/datum/browser/popup = new(src, "announce_help", "Announcement Help", 500, 400)
- popup.set_content(dat)
- popup.open()
-
-
-/mob/living/silicon/ai/proc/announcement()
-
- set name = "Announcement"
- set desc = "Create a vocal announcement by typing in the available words to create a sentence."
+ set name = "Announcement Help"
+ set desc = "Display a list of vocal words to announce to the crew."
set category = "AI Commands"
- if(src.stat == 2)
- src << "You can't call the shuttle because you are dead!"
- return
- if(istype(usr,/mob/living/silicon/ai))
- var/mob/living/silicon/ai/AI = src
- if(AI.control_disabled)
- usr << "Wireless control is disabled!"
- return
+ var/dat = "Here is a list of words you can type into the 'Announcement' button to create sentences to vocally announce to everyone on the same level at you.
\
+ - You can also click on the word to preview it.
\
+ - You can only say 30 words for every announcement.
\
+ - Do not use punctuation as you would normally, if you want a pause you can use the full stop and comma characters by separating them with spaces, like so: 'Alpha . Test , Bravo'.
\
+ WARNING:
Misuse of the announcement system will get you job banned.
"
+
+ var/index = 0
+ for(var/word in vox_sounds)
+ index++
+ dat += "[capitalize(word)]"
+ if(index != vox_sounds.len)
+ dat += " / "
+
+ var/datum/browser/popup = new(src, "announce_help", "Announcement Help", 500, 400)
+ popup.set_content(dat)
+ popup.open()
+
+/mob/living/silicon/ai/proc/ai_announcement()
if(announcing_vox > world.time)
src << "Please wait [round((announcing_vox - world.time) / 10)] seconds."
return
@@ -112,27 +96,24 @@ var/const/VOX_PATH = "sound/vox_fem/"
/proc/play_vox_word(var/word, var/z_level, var/mob/only_listener)
+ word = lowertext(word)
+ if(vox_sounds[word])
+ var/sound_file = vox_sounds[word]
+ var/sound/voice = sound(sound_file, wait = 1, channel = VOX_CHANNEL)
+ voice.status = SOUND_STREAM
- word = lowertext(word)
-
- if(vox_sounds[word])
-
- var/sound_file = vox_sounds[word]
- var/sound/voice = sound(sound_file, wait = 1, channel = VOX_CHANNEL)
- voice.status = SOUND_STREAM
-
- // If there is no single listener, broadcast to everyone in the same z level
- if(!only_listener)
- // Play voice for all mobs in the z level
- for(var/mob/M in player_list)
- if(M.client)
- var/turf/T = get_turf(M)
- if(T.z == z_level)
- M << voice
- else
- only_listener << voice
- return 1
- return 0
+ // If there is no single listener, broadcast to everyone in the same z level
+ if(!only_listener)
+ // Play voice for all mobs in the z level
+ for(var/mob/M in player_list)
+ if(M.client)
+ var/turf/T = get_turf(M)
+ if(T.z == z_level && !isdeaf(M))
+ M << voice
+ else
+ only_listener << voice
+ return 1
+ return 0
// VOX sounds moved to /code/defines/vox_sounds.dm
diff --git a/code/modules/mob/living/silicon/mommi/mommi.dm b/code/modules/mob/living/silicon/mommi/mommi.dm
index 91defdaedfb..b6e508d9d3a 100644
--- a/code/modules/mob/living/silicon/mommi/mommi.dm
+++ b/code/modules/mob/living/silicon/mommi/mommi.dm
@@ -149,7 +149,7 @@ They can only use one tool at a time, they can't choose modules, and they have 1
name = real_name
/mob/living/silicon/robot/attackby(obj/item/weapon/W as obj, mob/user as mob)
- if (istype(W, /obj/item/weapon/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do
+ if (istype(W, /obj/item/weapon/restraints/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do
return
if (istype(W, /obj/item/weapon/weldingtool))
@@ -240,68 +240,6 @@ They can only use one tool at a time, they can't choose modules, and they have 1
else
user << "\red Access denied."
- else if(istype(W, /obj/item/weapon/card/emag)) // trying to unlock with an emag card
- if(!opened)//Cover is closed
- if(locked)
- if(prob(90))
- user << "You emag the cover lock."
- locked = 0
- else
- user << "You fail to emag the cover lock."
- if(prob(25))
- src << "Hack attempt detected."
- else
- user << "The cover is already unlocked."
- return
-
- if(opened)//Cover is open
- if(emagged) return//Prevents the X has hit Y with Z message also you cant emag them twice
- if(wiresexposed)
- user << "You must close the panel first"
- return
- else
- sleep(6)
- if(prob(50))
- emagged = 1
- lawupdate = 0
- connected_ai = null
- user << "You emag [src]'s interface."
-// message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
- log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
- clear_supplied_laws()
- clear_inherent_laws()
- laws = new /datum/ai_laws/syndicate_override
- var/time = time2text(world.realtime,"hh:mm:ss")
- lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])")
- set_zeroth_law("Only [user.real_name] and people he designates as being such are Syndicate Agents.")
- src << "\red ALERT: Foreign software detected."
- sleep(5)
- src << "\red Initiating diagnostics..."
- sleep(20)
- src << "\red SynBorg v1.7 loaded."
- sleep(5)
- src << "\red LAW SYNCHRONISATION ERROR"
- sleep(5)
- src << "\red Would you like to send a report to NanoTraSoft? Y/N"
- sleep(10)
- src << "\red > N"
- sleep(20)
- src << "\red ERRORERRORERROR"
- src << "Obey these laws:"
- laws.show_laws(src)
- src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
- if(src.module && istype(src.module, /obj/item/weapon/robot_module/miner))
- for(var/obj/item/weapon/pickaxe/borgdrill/D in src.module.modules)
- del(D)
- src.module.modules += new /obj/item/weapon/pickaxe/diamonddrill(src.module)
- src.module.rebuild()
- updateicon()
- else
- user << "You fail to [ locked ? "unlock" : "lock"] [src]'s interface."
- if(prob(25))
- src << "Hack attempt detected."
- return
-
else if(istype(W, /obj/item/borg/upgrade/))
var/obj/item/borg/upgrade/U = W
if(!opened)
@@ -322,6 +260,68 @@ They can only use one tool at a time, they can't choose modules, and they have 1
else
spark_system.start()
return ..()
+
+/mob/living/silicon/robot/mommi/emag_act(user as mob)
+ if(!opened)//Cover is closed
+ if(locked)
+ if(prob(90))
+ user << "You emag the cover lock."
+ locked = 0
+ else
+ user << "You fail to emag the cover lock."
+ if(prob(25))
+ src << "Hack attempt detected."
+ else
+ user << "The cover is already unlocked."
+ return
+
+ if(opened)//Cover is open
+ if(emagged) return//Prevents the X has hit Y with Z message also you cant emag them twice
+ if(wiresexposed)
+ user << "You must close the panel first"
+ return
+ else
+ sleep(6)
+ if(prob(50))
+ emagged = 1
+ lawupdate = 0
+ connected_ai = null
+ user << "You emag [src]'s interface."
+// message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
+ log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
+ clear_supplied_laws()
+ clear_inherent_laws()
+ laws = new /datum/ai_laws/syndicate_override
+ var/time = time2text(world.realtime,"hh:mm:ss")
+ lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])")
+ set_zeroth_law("Only [user.real_name] and people he designates as being such are Syndicate Agents.")
+ src << "\red ALERT: Foreign software detected."
+ sleep(5)
+ src << "\red Initiating diagnostics..."
+ sleep(20)
+ src << "\red SynBorg v1.7 loaded."
+ sleep(5)
+ src << "\red LAW SYNCHRONISATION ERROR"
+ sleep(5)
+ src << "\red Would you like to send a report to NanoTraSoft? Y/N"
+ sleep(10)
+ src << "\red > N"
+ sleep(20)
+ src << "\red ERRORERRORERROR"
+ src << "Obey these laws:"
+ laws.show_laws(src)
+ src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
+ if(src.module && istype(src.module, /obj/item/weapon/robot_module/miner))
+ for(var/obj/item/weapon/pickaxe/borgdrill/D in src.module.modules)
+ del(D)
+ src.module.modules += new /obj/item/weapon/pickaxe/diamonddrill(src.module)
+ src.module.rebuild()
+ updateicon()
+ else
+ user << "You fail to [ locked ? "unlock" : "lock"] [src]'s interface."
+ if(prob(25))
+ src << "Hack attempt detected."
+ return
/mob/living/silicon/robot/mommi/attack_hand(mob/user)
add_fingerprint(user)
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 0073729778d..e3a04f2cd0f 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -172,41 +172,6 @@
user << "The machine is hermetically sealed. You can't open the case."
return
- else if (istype(W, /obj/item/weapon/card/emag))
-
- if(!client || stat == 2)
- user << "\red There's not much point subverting this heap of junk."
- return
-
- if(emagged)
- src << "\red [user] attempts to load subversive software into you, but your hacked subroutined ignore the attempt."
- user << "\red You attempt to subvert [src], but the sequencer has no effect."
- return
-
- user << "\red You swipe the sequencer across [src]'s interface and watch its eyes flicker."
- src << "\red You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script."
-
- var/obj/item/weapon/card/emag/emag = W
- emag.uses--
-
- message_admins("[key_name_admin(user)] emagged drone [key_name_admin(src)]. Laws overridden.")
- log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.")
- var/time = time2text(world.realtime,"hh:mm:ss")
- lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])")
-
- emagged = 1
- lawupdate = 0
- connected_ai = null
- clear_supplied_laws()
- clear_inherent_laws()
- laws = new /datum/ai_laws/syndicate_override
- set_zeroth_law("Only [user.real_name] and people he designates as being such are Syndicate Agents.")
-
- src << "Obey these laws:"
- laws.show_laws(src)
- src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
- return
-
else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
if(stat == 2)
@@ -242,6 +207,41 @@
return
..()
+
+/mob/living/silicon/robot/drone/emag_act(user as mob)
+ if(!client || stat == 2)
+ user << "\red There's not much point subverting this heap of junk."
+ return
+
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
+
+ if(emagged)
+ src << "\red [user] attempts to load subversive software into you, but your hacked subroutined ignore the attempt."
+ user << "\red You attempt to subvert [src], but the sequencer has no effect."
+ return
+
+ user << "\red You swipe the sequencer across [src]'s interface and watch its eyes flicker."
+ src << "\red You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script."
+
+ message_admins("[key_name_admin(user)] emagged drone [key_name_admin(src)]. Laws overridden.")
+ log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.")
+ var/time = time2text(world.realtime,"hh:mm:ss")
+ lawchanges.Add("[time] : [H.name]([H.key]) emagged [name]([key])")
+
+ emagged = 1
+ lawupdate = 0
+ connected_ai = null
+ clear_supplied_laws()
+ clear_inherent_laws()
+ laws = new /datum/ai_laws/syndicate_override
+ set_zeroth_law("Only [H.real_name] and people he designates as being such are Syndicate Agents.")
+
+ src << "Obey these laws:"
+ laws.show_laws(src)
+ src << "\red \b ALERT: [H.real_name] is your new master. Obey your new laws and his commands."
+ return
//DRONE LIFE/DEATH
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 1e0a62eedb2..e28f9ac8b7d 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -188,12 +188,12 @@
/mob/living/silicon/robot/proc/pick_module()
if(module)
return
- var/list/modules = list("Standard", "Engineering", "Surgeon", "Crisis", "Miner", "Janitor", "Service", "Security")
+ var/list/modules = list("Standard", "Engineering", "Medical", "Miner", "Janitor", "Service", "Security")
if(security_level == (SEC_LEVEL_GAMMA || SEC_LEVEL_EPSILON) || crisis)
src << "\red Crisis mode active. Combat module available."
modules+="Combat"
if(mmi != null && mmi.alien)
- modules="Hunter"
+ modules = "Hunter"
modtype = input("Please, select a module!", "Robot", null, null) in modules
designation = modtype
var/module_sprites[0] //Used to store the associations between sprite names and sprite index.
@@ -237,8 +237,8 @@
module_sprites["Advanced Droid"] = "droid-miner"
module_sprites["Treadhead"] = "Miner"
- if("Crisis")
- module = new /obj/item/weapon/robot_module/crisis(src)
+ if("Medical")
+ module = new /obj/item/weapon/robot_module/medical(src)
channels = list("Medical" = 1)
if(camera && "Robots" in camera.network)
camera.network.Add("Medical")
@@ -247,17 +247,6 @@
module_sprites["Advanced Droid"] = "droid-medical"
module_sprites["Needles"] = "medicalrobot"
- if("Surgeon")
- module = new /obj/item/weapon/robot_module/surgeon(src)
- channels = list("Medical" = 1)
- if(camera && "Robots" in camera.network)
- camera.network.Add("Medical")
-
- module_sprites["Basic"] = "Medbot"
- module_sprites["Standard"] = "surgeon"
- module_sprites["Advanced Droid"] = "droid-medical"
- module_sprites["Needles"] = "medicalrobot"
-
if("Security")
module = new /obj/item/weapon/robot_module/security(src)
channels = list("Security" = 1)
@@ -643,7 +632,7 @@
/mob/living/silicon/robot/attackby(obj/item/weapon/W as obj, mob/user as mob)
- if (istype(W, /obj/item/weapon/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do
+ if (istype(W, /obj/item/weapon/restraints/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do
return
if(opened) // Are they trying to insert something?
@@ -808,72 +797,6 @@
else
user << "\red Access denied."
- else if(istype(W, /obj/item/weapon/card/emag)) // trying to unlock with an emag card
- if(!opened)//Cover is closed
- if(locked)
- if(prob(90))
- var/obj/item/weapon/card/emag/emag = W
- emag.uses--
- user << "You emag the cover lock."
- locked = 0
- else
- user << "You fail to emag the cover lock."
- if(prob(25))
- src << "Hack attempt detected."
- else
- user << "The cover is already unlocked."
- return
-
- if(opened)//Cover is open
- if(emagged) return//Prevents the X has hit Y with Z message also you cant emag them twice
- if(wiresexposed)
- user << "You must close the panel first"
- return
- else
- sleep(6)
- if(prob(50))
- emagged = 1
- if(user.hud_used)
- user.hud_used.update_robot_modules_display() //Shows/hides the emag item if the inventory screen is already open.
- lawupdate = 0
- connected_ai = null
- user << "You emag [src]'s interface."
-// message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
- log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
- clear_supplied_laws()
- clear_inherent_laws()
- laws = new /datum/ai_laws/syndicate_override
- var/time = time2text(world.realtime,"hh:mm:ss")
- lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])")
- set_zeroth_law("Only [user.real_name] and people he designates as being such are Syndicate Agents.")
- src << "\red ALERT: Foreign software detected."
- sleep(5)
- src << "\red Initiating diagnostics..."
- sleep(20)
- src << "\red SynBorg v1.7 loaded."
- sleep(5)
- src << "\red LAW SYNCHRONISATION ERROR"
- sleep(5)
- src << "\red Would you like to send a report to NanoTraSoft? Y/N"
- sleep(10)
- src << "\red > N"
- sleep(20)
- src << "\red ERRORERRORERROR"
- src << "Obey these laws:"
- laws.show_laws(src)
- src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
- if(src.module && istype(src.module, /obj/item/weapon/robot_module/miner))
- for(var/obj/item/weapon/pickaxe/borgdrill/D in src.module.modules)
- del(D)
- src.module.modules += new /obj/item/weapon/pickaxe/diamonddrill(src.module)
- src.module.rebuild()
- updateicon()
- else
- user << "You fail to [ locked ? "unlock" : "lock"] [src]'s interface."
- if(prob(25))
- src << "Hack attempt detected."
- return
-
else if(istype(W, /obj/item/borg/upgrade/))
var/obj/item/borg/upgrade/U = W
if(!opened)
@@ -894,6 +817,73 @@
else
spark_system.start()
return ..()
+
+/mob/living/silicon/robot/emag_act(user as mob)
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
+ if(!opened)//Cover is closed
+ if(locked)
+ if(prob(90))
+ user << "You emag the cover lock."
+ locked = 0
+ else
+ user << "You fail to emag the cover lock."
+ if(prob(25))
+ src << "Hack attempt detected."
+ else
+ user << "The cover is already unlocked."
+ return
+
+ if(opened)//Cover is open
+ if(emagged) return//Prevents the X has hit Y with Z message also you cant emag them twice
+ if(wiresexposed)
+ user << "You must close the panel first"
+ return
+ else
+ sleep(6)
+ if(prob(50))
+ emagged = 1
+ if(H.hud_used)
+ H.hud_used.update_robot_modules_display() //Shows/hides the emag item if the inventory screen is already open.
+ lawupdate = 0
+ connected_ai = null
+ user << "You emag [src]'s interface."
+// message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
+ log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
+ clear_supplied_laws()
+ clear_inherent_laws()
+ laws = new /datum/ai_laws/syndicate_override
+ var/time = time2text(world.realtime,"hh:mm:ss")
+ lawchanges.Add("[time] : [H.name]([H.key]) emagged [name]([key])")
+ set_zeroth_law("Only [H.real_name] and people he designates as being such are Syndicate Agents.")
+ src << "\red ALERT: Foreign software detected."
+ sleep(5)
+ src << "\red Initiating diagnostics..."
+ sleep(20)
+ src << "\red SynBorg v1.7 loaded."
+ sleep(5)
+ src << "\red LAW SYNCHRONISATION ERROR"
+ sleep(5)
+ src << "\red Would you like to send a report to NanoTraSoft? Y/N"
+ sleep(10)
+ src << "\red > N"
+ sleep(20)
+ src << "\red ERRORERRORERROR"
+ src << "Obey these laws:"
+ laws.show_laws(src)
+ src << "\red \b ALERT: [H.real_name] is your new master. Obey your new laws and his commands."
+ if(src.module && istype(src.module, /obj/item/weapon/robot_module/miner))
+ for(var/obj/item/weapon/pickaxe/borgdrill/D in src.module.modules)
+ del(D)
+ src.module.modules += new /obj/item/weapon/pickaxe/diamonddrill(src.module)
+ src.module.rebuild()
+ updateicon()
+ else
+ user << "You fail to [ locked ? "unlock" : "lock"] [src]'s interface."
+ if(prob(25))
+ src << "Hack attempt detected."
+ return
/mob/living/silicon/robot/verb/unlock_own_cover()
set category = "Robot Commands"
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 831c6badf1e..a2c1fcb7347 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -71,10 +71,12 @@
src.emag = new /obj/item/weapon/melee/energy/sword/cyborg(src)
return
-/obj/item/weapon/robot_module/surgeon
- name = "surgeon robot module"
+/obj/item/weapon/robot_module/medical
+ name = "medical robot module"
stacktypes = list(
/obj/item/stack/medical/advanced/bruise_pack = 5,
+ /obj/item/stack/medical/advanced/ointment = 5,
+ /obj/item/stack/medical/splint = 5,
/obj/item/stack/nanopaste = 5
)
@@ -82,7 +84,18 @@
src.modules += new /obj/item/device/flashlight(src)
src.modules += new /obj/item/device/flash/cyborg(src)
src.modules += new /obj/item/device/healthanalyzer(src)
- src.modules += new /obj/item/weapon/reagent_containers/borghypo/surgeon(src)
+ src.modules += new /obj/item/device/reagent_scanner/adv(src)
+ src.modules += new /obj/item/weapon/borg_defib(src)
+ src.modules += new /obj/item/roller_holder(src)
+ src.modules += new /obj/item/weapon/reagent_containers/borghypo(src)
+ src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
+ src.modules += new /obj/item/weapon/reagent_containers/dropper(src)
+ src.modules += new /obj/item/weapon/reagent_containers/syringe(src)
+ src.modules += new /obj/item/weapon/extinguisher/mini(src)
+ src.modules += new /obj/item/stack/medical/advanced/bruise_pack(src)
+ src.modules += new /obj/item/stack/medical/advanced/ointment(src)
+ src.modules += new /obj/item/stack/medical/splint(src)
+ src.modules += new /obj/item/stack/nanopaste(src)
src.modules += new /obj/item/weapon/scalpel(src)
src.modules += new /obj/item/weapon/hemostat(src)
src.modules += new /obj/item/weapon/retractor(src)
@@ -92,9 +105,6 @@
src.modules += new /obj/item/weapon/bonesetter(src)
src.modules += new /obj/item/weapon/circular_saw(src)
src.modules += new /obj/item/weapon/surgicaldrill(src)
- src.modules += new /obj/item/weapon/extinguisher/mini(src)
- src.modules += new /obj/item/stack/medical/advanced/bruise_pack(src)
- src.modules += new /obj/item/stack/nanopaste(src)
src.emag = new /obj/item/weapon/reagent_containers/spray(src)
@@ -102,59 +112,12 @@
src.emag.name = "Polyacid spray"
return
-/obj/item/weapon/robot_module/surgeon/respawn_consumable(var/mob/living/silicon/robot/R)
+/obj/item/weapon/robot_module/medical/respawn_consumable(var/mob/living/silicon/robot/R)
if(src.emag)
var/obj/item/weapon/reagent_containers/spray/PS = src.emag
PS.reagents.add_reagent("pacid", 2)
..()
-/obj/item/weapon/robot_module/crisis
- name = "crisis robot module"
- stacktypes = list(
- /obj/item/stack/medical/advanced/ointment = 5,
- /obj/item/stack/medical/advanced/bruise_pack = 5,
- /obj/item/stack/medical/splint = 5
- )
-
-
- New()
- src.modules += new /obj/item/device/flashlight(src)
- src.modules += new /obj/item/device/flash/cyborg(src)
- src.modules += new /obj/item/device/healthanalyzer(src)
- src.modules += new /obj/item/device/reagent_scanner/adv(src)
- src.modules += new /obj/item/roller_holder(src)
- src.modules += new /obj/item/stack/medical/advanced/ointment(src)
- src.modules += new /obj/item/stack/medical/advanced/bruise_pack(src)
- src.modules += new /obj/item/stack/medical/splint(src)
- src.modules += new /obj/item/weapon/reagent_containers/borghypo/crisis(src)
- src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
- src.modules += new /obj/item/weapon/reagent_containers/robodropper(src)
- src.modules += new /obj/item/weapon/reagent_containers/syringe(src)
- src.modules += new /obj/item/weapon/extinguisher/mini(src)
-
- src.emag = new /obj/item/weapon/reagent_containers/spray(src)
-
- src.emag.reagents.add_reagent("pacid", 250)
- src.emag.name = "Polyacid spray"
- var/obj/item/weapon/reagent_containers/spray/S = emag
- S.banned_reagents = list()
- return
-
-/obj/item/weapon/robot_module/crisis/respawn_consumable(var/mob/living/silicon/robot/R)
-
- var/obj/item/weapon/reagent_containers/syringe/S = locate() in src.modules
- if(S.mode == 2)
- S.reagents.clear_reagents()
- S.mode = initial(S.mode)
- S.desc = initial(S.desc)
- S.update_icon()
-
- if(src.emag)
- var/obj/item/weapon/reagent_containers/spray/PS = src.emag
- PS.reagents.add_reagent("pacid", 2)
-
- ..()
-
/obj/item/weapon/robot_module/engineering
name = "engineering robot module"
@@ -220,7 +183,7 @@
New()
src.modules += new /obj/item/device/flashlight/seclite(src)
src.modules += new /obj/item/device/flash/cyborg(src)
- src.modules += new /obj/item/weapon/handcuffs/cyborg(src)
+ src.modules += new /obj/item/weapon/restraints/handcuffs/cable/zipties/cyborg(src)
src.modules += new /obj/item/weapon/melee/baton/robot(src)
src.modules += new /obj/item/weapon/gun/energy/disabler/cyborg(src)
src.modules += new /obj/item/taperoll/police(src)
diff --git a/code/modules/mob/living/simple_animal/friendly/butterfly.dm b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
new file mode 100644
index 00000000000..4c4841a77e9
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
@@ -0,0 +1,21 @@
+/mob/living/simple_animal/butterfly
+ name = "butterfly"
+ desc = "A colorful butterfly, how'd it get up here?"
+ icon_state = "butterfly"
+ icon_living = "butterfly"
+ icon_dead = "butterfly_dead"
+ turns_per_move = 1
+ emote_see = list("flutters")
+ response_help = "shoos"
+ response_disarm = "brushes aside"
+ response_harm = "aquashes"
+ speak_chance = 0
+ maxHealth = 2
+ health = 2
+ harm_intent_damage = 1
+ friendly = "nudges"
+ pass_flags = PASSTABLE
+
+/mob/living/simple_animal/butterfly/New()
+ ..()
+ color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm
index 9b638505e28..c9dfb0cccef 100644
--- a/code/modules/mob/living/simple_animal/friendly/corgi.dm
+++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm
@@ -25,7 +25,15 @@
var/obj/item/inventory_back
var/facehugger
-/mob/living/simple_animal/corgi/Life()
+/mob/living/simple_animal/corgi/New()
+ ..()
+ regenerate_icons()
+
+/mob/living/simple_animal/corgi/Die()
+ ..()
+ regenerate_icons()
+
+/mob/living/simple_animal/corgi/revive()
..()
regenerate_icons()
@@ -33,7 +41,7 @@
user.set_machine(src)
if(user.stat) return
- var/dat = "Inventory of [name]
"
+ var/dat = "
Inventory of [real_name]
"
if(inventory_head)
dat += "
Head: [inventory_head] (Remove)"
else
@@ -85,6 +93,7 @@
SetLuminosity(0)
inventory_head.loc = src.loc
inventory_head = null
+ regenerate_icons()
else
usr << "\red There is nothing to remove from its [remove_from]."
return
@@ -92,6 +101,7 @@
if(inventory_back)
inventory_back.loc = src.loc
inventory_back = null
+ regenerate_icons()
else
usr << "\red There is nothing to remove from its [remove_from]."
return
@@ -163,6 +173,7 @@
usr.drop_item()
place_on_head(item_to_add)
+ regenerate_icons()
if("back")
if(inventory_back)
@@ -383,7 +394,7 @@
..()
/mob/living/simple_animal/corgi/regenerate_icons()
- overlays = list()
+ overlays.Cut()
if(inventory_head)
var/head_icon_state = inventory_head.icon_state
@@ -471,14 +482,12 @@
icon_living = "borgi"
var/emagged = 0
-/mob/living/simple_animal/corgi/Ian/borgi/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if (istype(O, /obj/item/weapon/card/emag) && !emagged)
+/mob/living/simple_animal/corgi/Ian/borgi/emag_act(user as mob)
+ if(!emagged)
emagged = 1
visible_message("[user] swipes a card through [src].", "You overload [src]s internal reactor.")
spawn (1000)
src.explode()
- return
- ..()
/mob/living/simple_animal/corgi/Ian/borgi/proc/explode()
for(var/mob/M in viewers(src, null))
diff --git a/code/modules/mob/living/simple_animal/friendly/pug.dm b/code/modules/mob/living/simple_animal/friendly/pug.dm
new file mode 100644
index 00000000000..62456ed8a8b
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/friendly/pug.dm
@@ -0,0 +1,42 @@
+//Corgi //best comment 2014
+/mob/living/simple_animal/pug
+ name = "\improper pug"
+ real_name = "pug"
+ desc = "It's a pug."
+ icon_state = "pug"
+ icon_living = "pug"
+ icon_dead = "pug_dead"
+ speak = list("YAP", "Woof!", "Bark!", "AUUUUUU")
+ speak_emote = list("barks", "woofs")
+ emote_hear = list("barks!", "woofs!", "yaps.","pants.")
+ emote_see = list("shakes its head.", "chases its tail.","shivers.")
+ speak_chance = 1
+ turns_per_move = 10
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/pug
+ meat_amount = 3
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "kicks"
+ see_in_dark = 5
+
+/mob/living/simple_animal/pug/Life()
+ ..()
+
+ if(!stat && !resting && !buckled)
+ if(prob(1))
+ emote("me", 1, pick("chases its tail."))
+ spawn(0)
+ for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
+ dir = i
+ sleep(1)
+
+/mob/living/simple_animal/pug/attackby(var/obj/item/O as obj, var/mob/user as mob) //Marker -Agouri
+ if(istype(O, /obj/item/weapon/newspaper))
+ if(!stat)
+ user.visible_message("[user] baps [name] on the nose with the rolled up [O]")
+ spawn(0)
+ for(var/i in list(1,2,4,8,4,2,1,2))
+ dir = i
+ sleep(1)
+ else
+ ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm
index aa64a6fe921..73c4018e3b9 100644
--- a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm
+++ b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm
@@ -125,18 +125,6 @@
else
user << "\red You swipe your card, with no effect."
return 0
- else if (istype(O, /obj/item/weapon/card/emag))
- if (emagged)
- user << "\red [src] is already overloaded - better run."
- return 0
- else
- var/obj/item/weapon/card/emag/emag = O
- emag.uses--
- emagged = 1
- user << "\blue You short out the security protocols and overload [src]'s cell, priming it to explode in a short time."
- spawn(100) src << "\red Your cell seems to be outputting a lot of power..."
- spawn(200) src << "\red Internal heat sensors are spiking! Something is badly wrong with your cell!"
- spawn(300) src.explode()
else
if(O.force)
@@ -152,6 +140,17 @@
for(var/mob/M in viewers(src, null))
if ((M.client && !( M.blinded )))
M.show_message("\red [user] gently taps [src] with the [O]. ")
+
+/mob/living/simple_animal/spiderbot/emag_act(user as mob)
+ if (emagged)
+ user << "\red [src] is already overloaded - better run."
+ return 0
+ else
+ emagged = 1
+ user << "\blue You short out the security protocols and overload [src]'s cell, priming it to explode in a short time."
+ spawn(100) src << "\red Your cell seems to be outputting a lot of power..."
+ spawn(200) src << "\red Internal heat sensors are spiking! Something is badly wrong with your cell!"
+ spawn(300) src.explode()
/mob/living/simple_animal/spiderbot/proc/transfer_personality(var/obj/item/device/mmi/M as obj)
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 890c953c632..800d9967ca7 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -29,6 +29,7 @@
var/response_disarm = "shoves"
var/response_harm = "hits"
var/harm_intent_damage = 3
+ var/force_threshold = 0 //Minimum force required to deal any damage
//Temperature effect
var/minbodytemp = 250
@@ -372,7 +373,6 @@
/mob/living/simple_animal/attackby(var/obj/item/O as obj, var/mob/user as mob) //Marker -Agouri
if(istype(O, /obj/item/stack/medical))
-
if(stat != DEAD)
var/obj/item/stack/medical/MED = O
if(health < maxHealth)
@@ -399,20 +399,22 @@
if(istype(O, /obj/item/weapon/kitchenknife) || istype(O, /obj/item/weapon/butch))
harvest()
else
+ var/damage = 0
if(O.force)
- var/damage = O.force
- if (O.damtype == STAMINA)
- damage = 0
- adjustBruteLoss(damage)
- for(var/mob/M in viewers(src, null))
- if ((M.client && !( M.blinded )))
- M.show_message("\red \b "+"[src] has been attacked with [O] by [user]. ")
+ if(O.force >= force_threshold)
+ damage = O.force
+ if (O.damtype == STAMINA)
+ damage = 0
+ visible_message("[user] has [O.attack_verb.len ? "[pick(O.attack_verb)]": "attacked"] [src] with [O]!",\
+ "[user] has [O.attack_verb.len ? "[pick(O.attack_verb)]": "attacked"] you with [O]!")
+ else
+ visible_message("[O] bounces harmlessly off of [src].",\
+ "[O] bounces harmlessly off of [src].")
+ playsound(loc, O.hitsound, 50, 1, -1)
else
- usr << "\red This weapon is ineffective, it does no damage."
- for(var/mob/M in viewers(src, null))
- if ((M.client && !( M.blinded )))
- M.show_message("\red [user] gently taps [src] with [O]. ")
-
+ user.visible_message("[user] gently taps [src] with [O].",\
+ "This weapon is ineffective, it does no damage.")
+ adjustBruteLoss(damage)
/mob/living/simple_animal/movement_delay()
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 8e5b93a01f0..7b197aafcb2 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -399,13 +399,13 @@ var/list/slot_equipment_priority = list( \
if(slot_handcuffed)
if(H.handcuffed)
return 0
- if(!istype(src, /obj/item/weapon/handcuffs))
+ if(!istype(src, /obj/item/weapon/restraints/handcuffs))
return 0
return 1
if(slot_legcuffed)
if(H.legcuffed)
return 0
- if(!istype(src, /obj/item/weapon/legcuffs))
+ if(!istype(src, /obj/item/weapon/restraints/legcuffs))
return 0
return 1
if(slot_in_backpack)
@@ -881,8 +881,9 @@ var/list/slot_equipment_priority = list( \
stat(null, "Bots-[master_controller.aibots_cost]\t#[aibots.len]")
stat(null, "Obj-[master_controller.objects_cost]\t#[processing_objects.len]")
stat(null, "PiNet-[master_controller.networks_cost]\t#[pipe_networks.len]")
- stat(null, "Ponet-[master_controller.powernets_cost]\t#[powernets.len]")
+ stat(null, "PoNet-[master_controller.powernets_cost]\t#[powernets.len]")
stat(null, "NanoUI-[master_controller.nano_cost]\t#[nanomanager.processing_uis.len]")
+ stat(null,"Events-[master_controller.events_cost]\t#[event_manager.active_events.len]")
// stat(null, "GC-[master_controller.gc_cost]\t#[garbage.queue.len]")
stat(null, "Tick-[master_controller.ticker_cost]")
stat(null, "ALL-[master_controller.total_cost]")
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index ee3c953fb7e..d422fe644e6 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -158,6 +158,12 @@ proc/isnewplayer(A)
proc/hasorgans(A)
return ishuman(A)
+
+proc/isdeaf(A)
+ if(istype(A, /mob))
+ var/mob/M = A
+ return (M.sdisabilities & DEAF) || M.ear_deaf
+ return 0
/proc/hsl2rgb(h, s, l)
return
diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm
index bea08693fbc..399eeb1c83e 100644
--- a/code/modules/mob/mob_transformation_simple.dm
+++ b/code/modules/mob/mob_transformation_simple.dm
@@ -30,7 +30,7 @@
if(!M || !ismob(M))
usr << "Type path is not a mob (new_type = [new_type]) in change_mob_type(). Contact a coder."
- del(M)
+ qdel(M)
return
if( istext(new_name) )
@@ -43,12 +43,12 @@
if(src.dna)
M.dna = src.dna.Clone()
- if(mind)
+ if(mind && istype(M, /mob/living))
mind.transfer_to(M)
else
M.key = key
if(delete_old_mob)
spawn(1)
- del(src)
+ qdel(src)
return M
diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm
new file mode 100644
index 00000000000..c27c0446395
--- /dev/null
+++ b/code/modules/nano/modules/crew_monitor.dm
@@ -0,0 +1,88 @@
+/obj/nano_module/crew_monitor
+ name = "Crew monitor"
+ var/list/tracked = new
+
+/obj/nano_module/crew_monitor/Topic(href, href_list)
+ if(..()) return
+ var/turf/T = get_turf(src)
+ if (!T || !(T.z in config.player_levels))
+ usr << "Unable to establish a connection: You're too far away from the station!"
+ return 0
+ if(href_list["close"] )
+ var/mob/user = usr
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main")
+ usr.unset_machine()
+ ui.close()
+ return 0
+ if(href_list["update"])
+ src.updateDialog()
+ return 1
+
+/obj/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ user.set_machine(src)
+ src.scan()
+
+ var/data[0]
+ var/turf/T = get_turf(src)
+ var/list/crewmembers = list()
+ for(var/obj/item/clothing/under/C in src.tracked)
+
+ var/turf/pos = get_turf(C)
+
+ if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
+ if(istype(C.loc, /mob/living/carbon/human))
+
+ var/mob/living/carbon/human/H = C.loc
+ if(H.w_uniform != C)
+ continue
+
+ var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1)
+
+ crewmemberData["sensor_type"] = C.sensor_mode
+ crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
+ crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
+ crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
+
+ if(C.sensor_mode >= SUIT_SENSOR_BINARY)
+ crewmemberData["dead"] = H.stat > 1
+
+ if(C.sensor_mode >= SUIT_SENSOR_VITAL)
+ crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
+ crewmemberData["tox"] = round(H.getToxLoss(), 1)
+ crewmemberData["fire"] = round(H.getFireLoss(), 1)
+ crewmemberData["brute"] = round(H.getBruteLoss(), 1)
+
+ if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
+ var/area/A = get_area(H)
+ crewmemberData["area"] = sanitize(A.name)
+ crewmemberData["x"] = pos.x
+ crewmemberData["y"] = pos.y
+
+ crewmembers[++crewmembers.len] = crewmemberData
+
+ crewmembers = sortByKey(crewmembers, "name")
+
+ data["crewmembers"] = crewmembers
+
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800)
+
+ // adding a template with the key "mapContent" enables the map ui functionality
+ ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
+ // adding a template with the key "mapHeader" replaces the map header content
+ ui.add_template("mapHeader", "crew_monitor_map_header.tmpl")
+
+ ui.set_initial_data(data)
+ ui.open()
+
+ // should make the UI auto-update; doesn't seem to?
+ ui.set_auto_update(1)
+
+/obj/nano_module/crew_monitor/proc/scan()
+ for(var/mob/living/carbon/human/H in mob_list)
+ if(istype(H.w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/C = H.w_uniform
+ if (C.has_sensor)
+ tracked |= C
+ return 1
diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm
index 2ce8de3b08b..36241b2ec75 100644
--- a/code/modules/nano/nanomanager.dm
+++ b/code/modules/nano/nanomanager.dm
@@ -1,8 +1,9 @@
// This is the window/UI manager for Nano UI
// There should only ever be one (global) instance of nanomanger
/datum/nanomanager
- // the list of current open /nanoui UIs
+ // a list of current open /nanoui UIs, grouped by src_object and ui_key
var/open_uis[0]
+ // a list of current open /nanoui UIs, not grouped, for use in processing
var/list/processing_uis = list()
// a list of asset filenames which are to be sent to the client on user logon
var/list/asset_files = list()
@@ -26,7 +27,8 @@
filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore
- asset_files.Add(file(path + filename)) // add this file to asset_files for sending to clients when they connect
+ if(fexists(path + filename))
+ asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect
return
@@ -85,7 +87,7 @@
/**
* Update all /nanoui uis attached to src_object
*
- * @param src_object /obj|/mob The obj or mob which the uis belong to
+ * @param src_object /obj|/mob The obj or mob which the uis are attached to
*
* @return int The number of uis updated
*/
@@ -97,7 +99,7 @@
var/update_count = 0
for (var/ui_key in open_uis[src_object_key])
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
- if(ui && ui.src_object && ui.user)
+ if(ui && ui.src_object && ui.user && ui.src_object.nano_host())
ui.process(1)
update_count++
return update_count
@@ -245,4 +247,3 @@
for(var/file in asset_files)
client << browse_rsc(file) // send the file to the client
- return 1 // success
diff --git a/code/modules/nano/nanoprocs.dm b/code/modules/nano/nanoprocs.dm
new file mode 100644
index 00000000000..81b939cf5c4
--- /dev/null
+++ b/code/modules/nano/nanoprocs.dm
@@ -0,0 +1,11 @@
+/atom/movable/proc/nano_host()
+ return src
+
+/obj/nano_module/nano_host()
+ return loc
+
+/atom/movable/proc/nano_can_update()
+ return 1
+
+/obj/machinery/nano_can_update()
+ return !(stat & (NOPOWER|BROKEN))
diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm
index 01792ad0c3d..6b37eb96948 100644
--- a/code/modules/nano/nanoui.dm
+++ b/code/modules/nano/nanoui.dm
@@ -6,11 +6,6 @@ nanoui class (or whatever Byond calls classes)
nanoui is used to open and update nano browser uis
**********************************************************/
-
-#define STATUS_INTERACTIVE 2 // GREEN Visability
-#define STATUS_UPDATE 1 // ORANGE Visability
-#define STATUS_DISABLED 0 // RED Visability
-
/datum/nanoui
// the user who opened this ui
var/mob/user
@@ -143,36 +138,122 @@ nanoui is used to open and update nano browser uis
* @return nothing
*/
/datum/nanoui/proc/update_status(var/push_update = 0)
- if (istype(user, /mob/living/silicon/ai))
- set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
- else if (istype(user, /mob/living/silicon/robot))
- if (src_object in view(7, user)) // robots can see and interact with things they can see within 7 tiles
- set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
- else
- set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
+ var/atom/movable/host = src_object.nano_host()
+ if(!host.nano_can_update())
+ close()
+ return
+
+ var/status = user.can_interact_with_interface(host.nano_host())
+ if(status == STATUS_CLOSE)
+ close()
else
- var/dist = get_dist(src_object, user)
+ set_status(status, push_update)
+
+/*
+ Procs called by update_status()
+*/
- if (dist > 4)
- close()
- return
+/mob/living/silicon/pai/can_interact_with_interface(src_object)
+ if(src_object == src && !stat)
+ return STATUS_INTERACTIVE
+ else
+ return ..()
- if ((allowed_user_stat > -1) && (user.stat > allowed_user_stat))
- set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
- else if (user.restrained() || user.lying)
- set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
- else if (istype(src_object, /obj/item/device/uplink/hidden)) // You know what if they have the uplink open let them use the UI
- set_status(STATUS_INTERACTIVE, push_update) // Will build in distance checks on the topics for sanity.
- else if (!(src_object in view(4, user))) // If the src object is not in visable, set status to 0
- set_status(STATUS_DISABLED, push_update) // interactive (green visibility)
- else if (dist <= 1)
- set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
- else if (dist <= 2)
- set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
- else if (istype(src_object, /obj/item/device/uplink/hidden)) // You know what if they have the uplink open let them use the UI
- set_status(STATUS_INTERACTIVE, push_update) // Will build in distance checks on the topics for sanity.
- else if (dist <= 4)
- set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
+/mob/proc/can_interact_with_interface(var/src_object)
+ return STATUS_CLOSE // By default no mob can do anything with NanoUI
+
+/mob/dead/observer/can_interact_with_interface()
+ if(check_rights(R_ADMIN, 0))
+ return STATUS_INTERACTIVE // Admins are more equal
+ return STATUS_UPDATE // Ghosts can view updates
+
+/mob/living/silicon/robot/can_interact_with_interface(var/src_object)
+ if(stat || !client)
+ return STATUS_CLOSE
+ if(lockcharge || stunned || weakened)
+ return STATUS_DISABLED
+ if (src_object in view(client.view, src)) // robots can see and interact with things they can see within their view range
+ return STATUS_INTERACTIVE // interactive (green visibility)
+ return STATUS_DISABLED // no updates, completely disabled (red visibility)
+
+/mob/living/silicon/robot/syndicate/can_interact_with_interface(var/src_object)
+ . = ..()
+ if(. != STATUS_INTERACTIVE)
+ return
+
+ if(z in config.admin_levels) // Syndicate borgs can interact with everything on the admin level
+ return STATUS_INTERACTIVE
+ if(istype(get_area(src), /area/syndicate_station) || istype(get_area(src), /area/traitor)) // If elsewhere, they can interact with everything on the syndicate shuttle and traitor station
+ return STATUS_INTERACTIVE
+ if(istype(src_object, /obj/machinery)) // And they can also interact with everything else
+ /*var/obj/machinery/Machine = src_object
+ if(Machine.emagged) // Uncomment so they can only interact with emagged machinery
+ return STATUS_INTERACTIVE*/
+ return STATUS_INTERACTIVE
+ return STATUS_UPDATE
+
+/mob/living/silicon/ai/can_interact_with_interface(var/src_object)
+ if(!client || check_unable(1))
+ return STATUS_CLOSE
+ // Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
+ // unless it's on the same level as the object it's interacting with.
+ var/turf/T = get_turf(src_object)
+ if(!T || !(z == T.z || (T.z in config.player_levels)))
+ return STATUS_CLOSE
+
+ // If an object is in view then we can interact with it
+ if(src_object in view(client.view, src))
+ return STATUS_INTERACTIVE
+
+ // If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view
+ if(is_in_chassis())
+ //stop AIs from leaving windows open and using then after they lose vision
+ //apc_override is needed here because AIs use their own APC when powerless
+ if(cameranet && !cameranet.checkTurfVis(get_turf(src_object)))
+ return apc_override ? STATUS_INTERACTIVE : STATUS_CLOSE
+ return STATUS_INTERACTIVE
+
+ return STATUS_CLOSE
+
+/mob/living/proc/shared_living_nano_interaction(var/src_object)
+ if (src.stat != CONSCIOUS)
+ return STATUS_CLOSE // no updates, close the interface
+ else if (restrained() || lying || stat || stunned || weakened)
+ return STATUS_UPDATE // update only (orange visibility)
+ return STATUS_INTERACTIVE
+
+/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object)
+ if(!isturf(src_object.loc))
+ if(src_object.loc == src) // Item in the inventory
+ return STATUS_INTERACTIVE
+ if(src.contents.Find(src_object.loc)) // A hidden uplink inside an item
+ return STATUS_INTERACTIVE
+
+ if (!(src_object in view(4, src))) // If the src object is not in visable, disable updates
+ return STATUS_CLOSE
+
+ var/dist = get_dist(src_object, src)
+ if (dist <= 1)
+ return STATUS_INTERACTIVE // interactive (green visibility)
+ else if (dist <= 2)
+ return STATUS_UPDATE // update only (orange visibility)
+ else if (dist <= 4)
+ return STATUS_DISABLED // no updates, completely disabled (red visibility)
+ return STATUS_CLOSE
+
+/mob/living/can_interact_with_interface(var/src_object, var/be_close = 1)
+ . = shared_living_nano_interaction(src_object)
+ if(. == STATUS_INTERACTIVE && be_close)
+ . = shared_living_nano_distance(src_object)
+ if(STATUS_INTERACTIVE)
+ return STATUS_UPDATE
+
+/mob/living/carbon/human/can_interact_with_interface(var/src_object, var/be_close = 1)
+ . = shared_living_nano_interaction(src_object)
+ if(. == STATUS_INTERACTIVE && be_close)
+ . = shared_living_nano_distance(src_object)
+ if(. == STATUS_UPDATE && (M_TK in mutations)) // If we have telekinesis and remain close enough, allow interaction.
+ return STATUS_INTERACTIVE
/**
* Set the ui to auto update (every master_controller tick)
diff --git a/code/modules/paperwork/fax.dm b/code/modules/paperwork/fax.dm
new file mode 100644
index 00000000000..a4b13a2876f
--- /dev/null
+++ b/code/modules/paperwork/fax.dm
@@ -0,0 +1,87 @@
+// Fax datum - holds all faxes sent during the round
+var/list/faxes = list()
+var/list/adminfaxes = list()
+
+/datum/fax
+ var/name = "fax"
+ var/from_department = null
+ var/to_department = null
+ var/origin = null
+ var/message = null
+ var/sent_by = null
+ var/sent_at = null
+
+/datum/fax/New()
+ faxes += src
+
+/datum/fax/admin
+ var/list/reply_to = null
+
+/datum/fax/admin/New()
+ adminfaxes += src
+
+// Fax panel - lets admins check all faxes sent during the round
+/client/proc/fax_panel()
+ set name = "Fax Panel"
+ set category = "Event"
+ if(holder)
+ holder.fax_panel(usr)
+ feedback_add_details("admin_verb","FXP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ return
+
+/datum/admins/proc/fax_panel(var/mob/living/user)
+ var/html = "Refresh"
+ html += "Create Fax"
+
+ html += ""
+ html += "
Admin Faxes
"
+ html += "
"
+ html += "| Name | From Department | To Department | Sent At | Sent By | View | Reply | Replied To |
"
+ for(var/datum/fax/admin/A in adminfaxes)
+ html += ""
+ html += "| [A.name] | "
+ html += "[A.from_department] | "
+ html += "[A.to_department] | "
+ html += "[worldtime2text(A.sent_at)] | "
+ if(A.sent_by)
+ var/mob/living/S = A.sent_by
+ html += "[S.name] | "
+ else
+ html += "Unknown | "
+ html += "View | "
+ if(!A.reply_to)
+ if(A.from_department == "Administrator")
+ html += "N/A | "
+ else
+ html += "Reply | "
+ html += "N/A | "
+ else
+ html += "N/A | "
+ html += "Original | "
+ html += "
"
+ html += "
"
+ html += "
"
+
+ html += ""
+ html += "
Departmental Faxes
"
+ html += "
"
+ html += "| Name | From Department | To Department | Sent At | Sent By | View |
"
+ for(var/datum/fax/F in faxes)
+ html += ""
+ html += "| [F.name] | "
+ html += "[F.from_department] | "
+ html += "[F.to_department] | "
+ html += "[worldtime2text(F.sent_at)] | "
+ if(F.sent_by)
+ var/mob/living/S = F.sent_by
+ html += "[S.name] | "
+ else
+ html += "Unknown | "
+ html += "View | "
+ html += "
"
+ html += "
"
+ html += "
"
+
+ var/datum/browser/popup = new(user, "fax_panel", "Fax Panel", 950, 450)
+ popup.set_content(html)
+ popup.open()
diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm
index a727a3f59c3..98726004ea4 100644
--- a/code/modules/paperwork/faxmachine.dm
+++ b/code/modules/paperwork/faxmachine.dm
@@ -1,9 +1,8 @@
var/list/obj/machinery/photocopier/faxmachine/allfaxes = list()
var/list/admin_departments = list("Central Command")
+var/list/hidden_admin_departments = list("Syndicate")
var/list/alldepartments = list()
-var/list/adminfaxes = list() //cache for faxes that have been sent to admins
-
/obj/machinery/photocopier/faxmachine
name = "fax machine"
icon = 'icons/obj/library.dmi'
@@ -22,6 +21,8 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins
var/department = "Unknown" // our department
var/destination = "Central Command" // the department we're sending to
+
+ var/data[0]
/obj/machinery/photocopier/faxmachine/New()
..()
@@ -31,111 +32,146 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins
alldepartments |= department
/obj/machinery/photocopier/faxmachine/attack_hand(mob/user as mob)
- user.set_machine(src)
-
- var/dat = "Fax Machine
"
-
- var/scan_name
+ ui_interact(user)
+
+/obj/machinery/photocopier/faxmachine/attackby(obj/item/weapon/item, mob/user)
+ if(istype(item,/obj/item/weapon/card/id) && !scan)
+ scan(item)
+ else if(istype(item, /obj/item/weapon/paper) || istype(item, /obj/item/weapon/photo) || istype(item, /obj/item/weapon/paper_bundle))
+ ..()
+ nanomanager.update_uis(src)
+ else
+ return ..()
+
+/obj/machinery/photocopier/faxmachine/emag_act(user as mob)
+ if(!emagged)
+ emagged = 1
+ user << "The transmitters realign to an unknown source!"
+ else
+ user << "You swipe the card through [src], but nothing happens."
+
+/obj/machinery/photocopier/faxmachine/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(scan)
- scan_name = scan.name
+ data["scan_name"] = scan.name
else
- scan_name = "--------"
-
- dat += "Confirm Identity: [scan_name]
"
-
- if(authenticated)
- dat += "{Log Out}"
+ data["scan_name"] = "-----"
+ data["authenticated"] = authenticated
+ if(!authenticated)
+ data["network"] = "Disconnected"
+ else if(!emagged)
+ data["network"] = "Central Command Quantum Entanglement Network"
else
- dat += "{Log In}"
-
- dat += "
"
-
- if(authenticated)
- dat += "Logged in to: Central Command Quantum Entanglement Network
"
-
- if(copyitem)
- dat += "Remove Item
"
-
- if(sendcooldown)
- dat += "Transmitter arrays realigning. Please stand by.
"
-
- else
-
- dat += "Send
"
- dat += "Currently sending: [copyitem.name]
"
- dat += "Sending to: [destination]
"
-
- else
- if(sendcooldown)
- dat += "Please insert paper to send via secure connection.
"
- dat += "Transmitter arrays realigning. Please stand by.
"
- else
- dat += "Please insert paper to send via secure connection.
"
-
+ data["network"] = "ERR*?*%!*"
+ if(copyitem)
+ data["paper"] = copyitem.name
+ data["paperinserted"] = 1
else
- dat += "Proper authentication is required to use this device.
"
+ data["paper"] = "-----"
+ data["paperinserted"] = 0
+ data["destination"] = destination
+ data["cooldown"] = sendcooldown
+ if((destination in admin_departments) || (destination in hidden_admin_departments))
+ data["respectcooldown"] = 1
+ else
+ data["respectcooldown"] = 0
- if(copyitem)
- dat += "Remove Item
"
-
- user << browse(dat, "window=copier")
- onclose(user, "copier")
- return
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if (!ui)
+ ui = new(user, src, ui_key, "faxmachine.tmpl", "Fax Machine UI", 540, 450)
+ ui.set_initial_data(data)
+ ui.open()
/obj/machinery/photocopier/faxmachine/Topic(href, href_list)
+ if(..())
+ return 1
+
if(href_list["send"])
- if(copyitem)
- if (destination in admin_departments)
+ if(copyitem && authenticated)
+ if ((destination in admin_departments) || (destination in hidden_admin_departments))
send_admin_fax(usr, destination)
else
- sendfax(destination)
+ sendfax(destination,usr)
if (sendcooldown)
spawn(sendcooldown) // cooldown time
sendcooldown = 0
+ nanomanager.update_uis(src)
- else if(href_list["remove"])
+ if(href_list["paper"])
if(copyitem)
copyitem.loc = usr.loc
usr.put_in_hands(copyitem)
usr << "You take \the [copyitem] out of \the [src]."
copyitem = null
- updateUsrDialog()
+ else
+ var/obj/item/I = usr.get_active_hand()
+ if (istype(I, /obj/item/weapon/paper) || istype(I, /obj/item/weapon/photo) || istype(I, /obj/item/weapon/paper_bundle))
+ usr.drop_item()
+ copyitem = I
+ I.loc = src
+ usr << "You insert \the [I] into \the [src]."
+ flick(insert_anim, src)
if(href_list["scan"])
- if (scan)
- if(ishuman(usr))
- scan.loc = usr.loc
- if(!usr.get_active_hand())
- usr.put_in_hands(scan)
- scan = null
- else
- scan.loc = src.loc
- scan = null
+ scan()
+
+ if(href_list["dept"])
+ if(authenticated)
+ var/lastdestination = destination
+ var/list/combineddepartments = alldepartments + admin_departments
+ if(emagged)
+ combineddepartments += hidden_admin_departments
+ destination = input(usr, "To which department?", "Choose a department", "") as null|anything in combineddepartments
+ if(!destination)
+ destination = lastdestination
+
+ if(href_list["auth"])
+ if((!authenticated) && scan)
+ if(check_access(scan))
+ authenticated = 1
+ else if(authenticated)
+ authenticated = 0
+
+ if(href_list["rename"])
+ if(copyitem)
+ var/n_name = copytext(sanitize(input(usr, "What would you like to label the fax?", "Fax Labelling", copyitem.name) as text), 1, MAX_MESSAGE_LEN)
+ if((copyitem && copyitem.loc == src && usr.stat == 0))
+ if (istype(copyitem, /obj/item/weapon/paper))
+ copyitem.name = "[(n_name ? text("[n_name]") : initial(copyitem.name))]"
+ copyitem.desc = "This is a paper titled '" + copyitem.name + "'."
+ else if(istype(copyitem, /obj/item/weapon/photo))
+ copyitem.name = "[(n_name ? text("[n_name]") : "photo")]"
+ else if(istype(copyitem, /obj/item/weapon/paper_bundle))
+ copyitem.name = "[(n_name ? text("[n_name]") : "paper")]"
+ data["name"] = copyitem.name
+
+ nanomanager.update_uis(src)
+
+/obj/machinery/photocopier/faxmachine/proc/scan(var/obj/item/weapon/card/id/card = null)
+ if(scan) // Card is in machine
+ if(ishuman(usr))
+ scan.loc = usr.loc
+ if(!usr.get_active_hand())
+ usr.put_in_hands(scan)
+ scan = null
else
+ scan.loc = src.loc
+ scan = null
+ else
+ if(!card)
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/weapon/card/id))
usr.drop_item()
I.loc = src
scan = I
- authenticated = 0
+ else
+ if(istype(card))
+ usr.drop_item()
+ card.loc = src
+ scan = card
+ nanomanager.update_uis(src)
- if(href_list["dept"])
- var/lastdestination = destination
- destination = input(usr, "Which department?", "Choose a department", "") as null|anything in (alldepartments + admin_departments)
- if(!destination) destination = lastdestination
-
- if(href_list["auth"])
- if ( (!( authenticated ) && (scan)) )
- if (check_access(scan))
- authenticated = 1
-
- if(href_list["logout"])
- authenticated = 0
-
- updateUsrDialog()
-
-/obj/machinery/photocopier/faxmachine/proc/sendfax(var/destination)
+/obj/machinery/photocopier/faxmachine/proc/sendfax(var/destination,var/mob/sender)
if(stat & (BROKEN|NOPOWER))
return
@@ -144,15 +180,24 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins
var/success = 0
for(var/obj/machinery/photocopier/faxmachine/F in allfaxes)
if( F.department == destination )
- success = F.recievefax(copyitem)
+ success = F.receivefax(copyitem)
if (success)
+ var/datum/fax/F = new /datum/fax()
+ F.name = copyitem.name
+ F.from_department = department
+ F.to_department = destination
+ F.origin = src
+ F.message = copyitem
+ F.sent_by = sender
+ F.sent_at = world.time
+
visible_message("[src] beeps, \"Message transmitted successfully.\"")
//sendcooldown = 600
else
visible_message("[src] beeps, \"Error transmitting message.\"")
-/obj/machinery/photocopier/faxmachine/proc/recievefax(var/obj/item/incoming)
+/obj/machinery/photocopier/faxmachine/proc/receivefax(var/obj/item/incoming)
if(stat & (BROKEN|NOPOWER))
return 0
@@ -195,20 +240,29 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins
return
rcvdcopy.loc = null //hopefully this shouldn't cause trouble
- adminfaxes += rcvdcopy
+
+ var/datum/fax/admin/A = new /datum/fax/admin()
+ A.name = rcvdcopy.name
+ A.from_department = department
+ A.to_department = destination
+ A.origin = src
+ A.message = rcvdcopy
+ A.sent_by = sender
+ A.sent_at = world.time
//message badmins that a fax has arrived
switch(destination)
if ("Central Command")
- message_admins(sender, "CENTCOMM FAX", rcvdcopy, "CentcommFaxReply", "#006100")
-
+ message_admins(sender, "CENTCOM FAX", destination, rcvdcopy, "#006100")
+ if ("Syndicate")
+ message_admins(sender, "SYNDICATE FAX", destination, rcvdcopy, "#DC143C")
sendcooldown = 1800
sleep(50)
visible_message("[src] beeps, \"Message transmitted successfully.\"")
-/obj/machinery/photocopier/faxmachine/proc/message_admins(var/mob/sender, var/faxname, var/obj/item/sent, var/reply_type, font_colour="#006100")
- var/msg = "\blue [faxname]: [key_name(sender, 1)] (PP) (VV) (SM) (JMP) (CA) (REPLY): Receiving '[sent.name]' via secure connection ... view message"
+/obj/machinery/photocopier/faxmachine/proc/message_admins(var/mob/sender, var/faxname, var/faxtype, var/obj/item/sent, font_colour="#006100")
+ var/msg = "\blue [faxname]: [key_name(sender, 1)] (PP) (VV) (SM) (JMP) (CA) (BSA) (REPLY): Receiving '[sent.name]' via secure connection... view message"
for(var/client/C in admins)
if(R_ADMIN & C.holder.rights)
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 972fec5eddb..fce6c2acda6 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -76,7 +76,7 @@
if((M_CLUMSY in usr.mutations) && prob(50))
usr << "You cut yourself on the paper."
return
- var/n_name = copytext(sanitize(input(usr, "What would you like to label the paper?", "Paper Labelling", null) as text), 1, MAX_MESSAGE_LEN)
+ var/n_name = copytext(sanitize(input(usr, "What would you like to label the paper?", "Paper Labelling", name) as text), 1, MAX_MESSAGE_LEN)
if((loc == usr && usr.stat == 0))
name = "[(n_name ? text("[n_name]") : initial(name))]"
if(name != "paper")
diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm
index e7ccdf2bf90..f821871069c 100644
--- a/code/modules/paperwork/paper_bundle.dm
+++ b/code/modules/paperwork/paper_bundle.dm
@@ -189,9 +189,9 @@
set category = "Object"
set src in usr
- var/n_name = copytext(sanitize(input(usr, "What would you like to label the bundle?", "Bundle Labelling", null) as text), 1, MAX_MESSAGE_LEN)
+ var/n_name = copytext(sanitize(input(usr, "What would you like to label the bundle?", "Bundle Labelling", name) as text), 1, MAX_MESSAGE_LEN)
if((loc == usr && usr.stat == 0))
- name = "[(n_name ? text("[n_name]") : "paper")]"
+ name = "[(n_name ? text("[n_name]") : "paper bundle")]"
add_fingerprint(usr)
return
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 15e2e844f21..479d2510605 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -90,7 +90,7 @@
set category = "Object"
set src in usr
- var/n_name = copytext(sanitize(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text), 1, MAX_MESSAGE_LEN)
+ var/n_name = copytext(sanitize(input(usr, "What would you like to label the photo?", "Photo Labelling", name) as text), 1, MAX_MESSAGE_LEN)
//loc.loc check is for making possible renaming photos in clipboards
if(( (loc == usr || (loc.loc && loc.loc == usr)) && usr.stat == 0))
name = "[(n_name ? text("[n_name]") : "photo")]"
@@ -311,6 +311,7 @@
var/datum/picture/P = new()
P.fields["name"] = "photo"
+ P.fields["author"] = user
P.fields["icon"] = ic
P.fields["tiny"] = pc
P.fields["img"] = photoimage
@@ -401,4 +402,4 @@
if(get_dist(src, M) <= canhear_range)
talk_into(M, msg)
for(var/mob/living/carbon/human/H in watcherslist)
- H.show_message(text("\blue (Newscaster) [] says, '[]'",M,msg), 1)
\ No newline at end of file
+ H.show_message(text("\blue (Newscaster) [] says, '[]'",M,msg), 1)
diff --git a/code/modules/paperwork/stamps.dm b/code/modules/paperwork/stamps.dm
index 04320d51d16..243762eefb6 100644
--- a/code/modules/paperwork/stamps.dm
+++ b/code/modules/paperwork/stamps.dm
@@ -1,5 +1,5 @@
/obj/item/weapon/stamp
- name = "\improper GRANTED rubber stamp"
+ name = "\improper rubber stamp"
desc = "A rubber stamp for stamping important documents."
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "stamp-ok"
@@ -53,6 +53,11 @@
icon_state = "stamp-cmo"
_color = "cmo"
+/obj/item/weapon/stamp/granted
+ name = "\improper GRANTED rubber stamp"
+ icon_state = "stamp-ok"
+ _color = "qm"
+
/obj/item/weapon/stamp/denied
name = "\improper DENIED rubber stamp"
icon_state = "stamp-deny"
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 6de3d9cea23..2e09cd993a9 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -458,23 +458,6 @@
update_icon()
else
user << "\red Access denied."
- else if (istype(W, /obj/item/weapon/card/emag) && !(emagged || malfhack)) // trying to unlock with an emag card
- if(opened)
- user << "You must close the cover to swipe an ID card."
- else if(wiresexposed)
- user << "You must close the panel first"
- else if(stat & (BROKEN|MAINT))
- user << "Nothing happens."
- else
- flick("apc-spark", src)
- if (do_after(user,6))
- if(prob(50))
- emagged = 1
- locked = 0
- user << "You emag the APC interface."
- update_icon()
- else
- user << "You fail to [ locked ? "unlock" : "lock"] the APC interface."
else if (istype(W, /obj/item/stack/cable_coil) && !terminal && opened && has_electronics!=2)
if (src.loc:intact)
user << "\red You must remove the floor plating in front of the APC first."
@@ -598,8 +581,26 @@
"\red You hit the [src.name] with your [W.name]!", \
"You hear bang")
+/obj/machinery/power/apc/emag_act(user as mob)
+ if (!(emagged || malfhack)) // trying to unlock with an emag card
+ if(opened)
+ user << "You must close the cover to swipe an ID card."
+ else if(wiresexposed)
+ user << "You must close the panel first"
+ else if(stat & (BROKEN|MAINT))
+ user << "Nothing happens."
+ else
+ flick("apc-spark", src)
+ if (do_after(user,6))
+ if(prob(50))
+ emagged = 1
+ locked = 0
+ user << "You emag the APC interface."
+ update_icon()
+ else
+ user << "You fail to [ locked ? "unlock" : "lock"] the APC interface."
+
// attack with hand - remove cell (if cover open) or interact with the APC
-
/obj/machinery/power/apc/attack_hand(mob/user)
// if (!can_use(user)) This already gets called in interact() and in topic()
// return
@@ -941,7 +942,7 @@
malfai.malfhacking = 0
locked = 1
if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ if ((src.z in config.station_levels)) //if (is_type_in_list(get_area(src), the_station_areas))
ticker.mode:apcs++
if(usr:parent)
src.malfai = usr:parent
@@ -973,7 +974,7 @@
if(malfai)
if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ if ((src.z in config.station_levels)) //if (is_type_in_list(get_area(src), the_station_areas))
operating ? ticker.mode:apcs++ : ticker.mode:apcs--
src.update()
@@ -988,7 +989,7 @@
if(!malf.can_shunt)
malf << "You cannot shunt."
return
- if(src.z != 1)
+ if(!(src.z in config.station_levels))
return
src.occupant = new /mob/living/silicon/ai(src,malf.laws,null,1)
src.occupant.adjustOxyLoss(malf.getOxyLoss())
@@ -1037,7 +1038,7 @@
/obj/machinery/power/apc/proc/ion_act()
//intended to be exactly the same as an AI malf attack
- if(!src.malfhack && src.z == 1)
+ if(!src.malfhack && (src.z in config.station_levels))
if(prob(3))
src.locked = 1
if (src.cell.charge > 0)
@@ -1306,7 +1307,7 @@ obj/machinery/power/apc/proc/autoset(var/val, var/on)
/obj/machinery/power/apc/proc/set_broken()
if(malfai && operating)
if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ if ((src.z in config.station_levels)) //if (is_type_in_list(get_area(src), the_station_areas))
ticker.mode:apcs--
stat |= BROKEN
operating = 0
@@ -1332,7 +1333,7 @@ obj/machinery/power/apc/proc/autoset(var/val, var/on)
/obj/machinery/power/apc/Destroy()
if(malfai && operating)
if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ if ((src.z in config.station_levels)) //if (is_type_in_list(get_area(src), the_station_areas))
ticker.mode:apcs--
area.power_light = 0
area.power_equip = 0
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index d16e13b8a96..54741e0245d 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -270,7 +270,7 @@
if(src.amount <= 14)
usr << "\red You need at least 15 lengths to make restraints!"
return
- var/obj/item/weapon/handcuffs/cable/B = new /obj/item/weapon/handcuffs/cable(usr.loc)
+ var/obj/item/weapon/restraints/handcuffs/cable/B = new /obj/item/weapon/restraints/handcuffs/cable(usr.loc)
B.icon_state = "cuff_[_color]"
usr << "\blue You wind some cable together to make some restraints."
src.use(15)
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index df04bacdc70..c9ac32da530 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -123,7 +123,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
O.main_part = null
qdel(O)
for(var/area/A in world)
- if (A.z != 1) continue
+ if (!(A.z in config.station_levels)) continue
A.gravitychange(0,A)
shake_everyone()
..()
@@ -294,7 +294,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
investigate_log("was brought online and is now producing gravity for this level.", "gravity")
message_admins("The gravity generator was brought online. ([area.name])")
for(var/area/A in world)
- if (A.z != 1) continue
+ if (!(A.z in config.station_levels)) continue
A.gravitychange(1,A)
else
if(gravity_in_level() == 1)
@@ -302,7 +302,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
investigate_log("was brought offline and there is now no gravity for this level.", "gravity")
message_admins("The gravity generator was brought offline with no backup generator. ([area.name])")
for(var/area/A in world)
- if (A.z != 1) continue
+ if (!(A.z in config.station_levels)) continue
A.gravitychange(0,A)
update_icon()
diff --git a/code/modules/power/pacman2.dm b/code/modules/power/pacman2.dm
index 89d65a6ae21..9402a4c234f 100644
--- a/code/modules/power/pacman2.dm
+++ b/code/modules/power/pacman2.dm
@@ -81,14 +81,6 @@
user.drop_item()
O.loc = src
user << "\blue You add the plasma tank to the generator."
- else if (istype(O, /obj/item/weapon/card/emag))
- var/obj/item/weapon/card/emag/E = O
- if(E.uses)
- E.uses--
- else
- return
- emagged = 1
- emp_act(1)
else if(!active)
if(istype(O, /obj/item/weapon/wrench))
anchored = !anchored
@@ -114,6 +106,11 @@
new_frame.state = 2
new_frame.icon_state = "box_1"
del(src)
+
+ emag_act(user as mob)
+ if(!emagged)
+ emagged = 1
+ emp_act(1)
attack_hand(mob/user as mob)
..()
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index a334782cce1..d918ec86711 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -211,9 +211,6 @@ display round(lastgen) and plasmatank amount
addstack.use(amount)
updateUsrDialog()
return
- else if (istype(O, /obj/item/weapon/card/emag))
- emagged = 1
- emp_act(1)
else if(!active)
if(istype(O, /obj/item/weapon/wrench))
if(!anchored && !isinspace())
@@ -239,6 +236,10 @@ display round(lastgen) and plasmatank amount
else if(istype(O, /obj/item/weapon/crowbar) && panel_open)
default_deconstruction_crowbar(O)
+/obj/machinery/power/port_gen/pacman/emag_act(user as mob)
+ emagged = 1
+ emp_act(1)
+
/obj/machinery/power/port_gen/pacman/attack_hand(mob/user as mob)
..()
if (!anchored)
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 601d7191f7b..8e9e16c9943 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -222,12 +222,14 @@
user << "\red Access denied."
return
-
- if(istype(W, /obj/item/weapon/card/emag) && !emagged)
+ ..()
+ return
+
+/obj/machinery/power/emitter/emag_act(user as mob)
+ if(!emagged)
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
locked = 0
emagged = 1
- user.visible_message("[user.name] emags the [src.name].","\red You short out the lock.")
- return
-
- ..()
- return
\ No newline at end of file
+ H.visible_message("[H.name] emags the [src.name].","\red You short out the lock.")
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index a3065ce3bb4..3fe245d34dd 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -421,7 +421,7 @@
/obj/machinery/power/smes/proc/ion_act()
- if(src.z == 1)
+ if((src.z in config.station_levels))
if(prob(1)) //explosion
world << "\red SMES explosion in [src.loc.loc]"
for(var/mob/M in viewers(src))
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 9c622e47ca9..b8356cacc34 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -1,20 +1,8 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
-
#define SOLAR_MAX_DIST 40
#define SOLARGENRATE 1500
var/list/solars_list = list()
-// This will choose whether to get the solar list from the powernet or the powernet nodes,
-// depending on the size of the nodes.
-/obj/machinery/power/proc/get_solars_powernet()
- if(!powernet)
- return list()
- if(solars_list.len < powernet.nodes)
- return solars_list
- else
- return powernet.nodes
-
/obj/machinery/power/solar
name = "solar panel"
desc = "A solar electrical generator."
@@ -22,7 +10,6 @@ var/list/solars_list = list()
icon_state = "sp_base"
anchored = 1
density = 1
- directwired = 1
use_power = 0
idle_power_usage = 0
active_power_usage = 0
@@ -30,26 +17,33 @@ var/list/solars_list = list()
var/health = 10
var/obscured = 0
var/sunfrac = 0
- var/adir = SOUTH
- var/ndir = SOUTH
+ var/adir = SOUTH // actual dir
+ var/ndir = SOUTH // target dir
var/turn_angle = 0
var/obj/machinery/power/solar_control/control = null
-/obj/machinery/power/solar/New(var/turf/loc, var/obj/item/solar_assembly/S, var/process = 1)
+/obj/machinery/power/solar/New(var/turf/loc, var/obj/item/solar_assembly/S)
..(loc)
Make(S)
- connect_to_network(process)
+ connect_to_network()
-
-/obj/machinery/power/solar/disconnect_from_network()
+/obj/machinery/power/solar/Destroy()
+ unset_control() //remove from control computer
..()
- solars_list.Remove(src)
-/obj/machinery/power/solar/connect_to_network(var/process)
- ..()
- if(process)
- solars_list.Add(src)
+//set the control of the panel to a given computer if closer than SOLAR_MAX_DIST
+/obj/machinery/power/solar/proc/set_control(var/obj/machinery/power/solar_control/SC)
+ if(!SC || (get_dist(src, SC) > SOLAR_MAX_DIST))
+ return 0
+ control = SC
+ SC.connected_panels |= src
+ return 1
+//set the control of the panel to null and removes it from the control list of the previous control computer if needed
+/obj/machinery/power/solar/proc/unset_control()
+ if(control)
+ control.connected_panels.Remove(src)
+ control = null
/obj/machinery/power/solar/proc/Make(var/obj/item/solar_assembly/S)
if(!S)
@@ -57,22 +51,25 @@ var/list/solars_list = list()
S.glass_type = /obj/item/stack/sheet/glass
S.anchored = 1
S.loc = src
+ if(S.glass_type == /obj/item/stack/sheet/rglass) //if the panel is in reinforced glass
+ health *= 2 //this need to be placed here, because panels already on the map don't have an assembly linked to
update_icon()
/obj/machinery/power/solar/attackby(obj/item/weapon/W, mob/user)
- if(iscrowbar(W))
- playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
+ if(istype(W, /obj/item/weapon/crowbar))
+ playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
+ user.visible_message("[user] begins to take the glass off the solar panel.")
if(do_after(user, 50))
var/obj/item/solar_assembly/S = locate() in src
if(S)
S.loc = src.loc
S.give_glass()
- playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
+ playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
user.visible_message("[user] takes the glass off the solar panel.")
- del(src)
+ qdel(src)
return
else if (W)
src.add_fingerprint(user)
@@ -92,9 +89,9 @@ var/list/solars_list = list()
if(!(stat & BROKEN))
broken()
else
- getFromPool(/obj/item/weapon/shard, loc)
- getFromPool(/obj/item/weapon/shard, loc)
- del(src)
+ new /obj/item/weapon/shard(src.loc)
+ new /obj/item/weapon/shard(src.loc)
+ qdel(src)
return
return
@@ -109,70 +106,58 @@ var/list/solars_list = list()
src.dir = angle2dir(adir)
return
-
+//calculates the fraction of the sunlight that the panel recieves
/obj/machinery/power/solar/proc/update_solar_exposure()
if(!sun)
return
if(obscured)
sunfrac = 0
return
- var/p_angle = abs((360+adir)%360 - (360+sun.angle)%360)
+
+ //find the smaller angle between the direction the panel is facing and the direction of the sun (the sign is not important here)
+ var/p_angle = min(abs(adir - sun.angle), 360 - abs(adir - sun.angle))
+
if(p_angle > 90) // if facing more than 90deg from sun, zero output
sunfrac = 0
return
- sunfrac = cos(p_angle) ** 2
+ sunfrac = cos(p_angle) ** 2
+ //isn't the power recieved from the incoming light proportionnal to cos(p_angle) (Lambert's cosine law) rather than cos(p_angle)^2 ?
/obj/machinery/power/solar/process()//TODO: remove/add this from machines to save on processing as needed ~Carn PRIORITY
- if(stat & BROKEN) return
- if(!control) return
+ if(stat & BROKEN)
+ return
+ if(!sun || !control) //if there's no sun or the panel is not linked to a solar control computer, no need to proceed
+ return
- if(adir != ndir)
- adir = (360+adir+dd_range(-10,10,ndir-adir))%360
- update_icon()
- update_solar_exposure()
-
- if(obscured) return
-
- var/sgen = SOLARGENRATE * sunfrac
- add_avail(sgen)
- if(powernet && control)
- if(powernet.nodes[control])
+ if(powernet)
+ if(powernet == control.powernet)//check if the panel is still connected to the computer
+ if(obscured) //get no light from the sun, so don't generate power
+ return
+ var/sgen = SOLARGENRATE * sunfrac
+ add_avail(sgen)
control.gen += sgen
-
+ else //if we're no longer on the same powernet, remove from control computer
+ unset_control()
/obj/machinery/power/solar/proc/broken()
+ . = (!(stat & BROKEN))
stat |= BROKEN
+ unset_control()
update_icon()
return
-/obj/machinery/power/solar/meteorhit()
- if(stat & !BROKEN)
- broken()
- else
- del(src)
-
-
-/obj/machinery/power/solar/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- if(prob(15))
- getFromPool(/obj/item/weapon/shard, loc)
- return
- if(2.0)
- if (prob(25))
- getFromPool(/obj/item/weapon/shard, loc)
- qdel(src)
- return
- if (prob(50))
- broken()
- if(3.0)
- if (prob(25))
- broken()
- return
-
+/obj/machinery/power/solar/ex_act(severity, target)
+ ..()
+ if(!gc_destroyed)
+ switch(severity)
+ if(2)
+ if(prob(50) && broken())
+ new /obj/item/weapon/shard(src.loc)
+ if(3)
+ if(prob(25) && broken())
+ new /obj/item/weapon/shard(src.loc)
/obj/machinery/power/solar/blob_act()
if(prob(75))
@@ -187,6 +172,29 @@ var/list/solars_list = list()
. = PROCESS_KILL
return
+//trace towards sun to see if we're in shadow
+/obj/machinery/power/solar/proc/occlusion()
+
+ var/ax = x // start at the solar panel
+ var/ay = y
+ var/turf/T = null
+
+ for(var/i = 1 to 20) // 20 steps is enough
+ ax += sun.dx // do step
+ ay += sun.dy
+
+ T = locate( round(ax,0.5),round(ay,0.5),z)
+
+ if(T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) // not obscured if we reach the edge
+ break
+
+ if(T.density) // if we hit a solid turf, panel is obscured
+ obscured = 1
+ return
+
+ obscured = 0 // if hit the edge or stepped 20 times, not obscured
+ update_solar_exposure()
+
//
// Solar Assembly - For construction of solar arrays.
@@ -218,40 +226,42 @@ var/list/solars_list = list()
/obj/item/solar_assembly/attackby(var/obj/item/weapon/W, var/mob/user)
if(!anchored && isturf(loc))
- if(iswrench(W))
+ if(istype(W, /obj/item/weapon/wrench))
anchored = 1
user.visible_message("[user] wrenches the solar assembly into place.")
- playsound(get_turf(src), 'sound/items/Ratchet.ogg', 75, 1)
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
return 1
else
- if(iswrench(W))
+ if(istype(W, /obj/item/weapon/wrench))
anchored = 0
user.visible_message("[user] unwrenches the solar assembly from it's place.")
- playsound(get_turf(src), 'sound/items/Ratchet.ogg', 75, 1)
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
return 1
if(istype(W, /obj/item/stack/sheet/glass) || istype(W, /obj/item/stack/sheet/rglass))
var/obj/item/stack/sheet/S = W
- if(S.amount >= 2)
+ if(S.use(2))
glass_type = W.type
- S.use(2)
- playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
+ playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
user.visible_message("[user] places the glass on the solar assembly.")
if(tracker)
new /obj/machinery/power/tracker(get_turf(src), src)
else
new /obj/machinery/power/solar(get_turf(src), src)
+ else
+ user << "You need two sheets of glass to put them into a solar panel."
+ return
return 1
if(!tracker)
if(istype(W, /obj/item/weapon/tracker_electronics))
tracker = 1
user.drop_item()
- del(W)
+ qdel(W)
user.visible_message("[user] inserts the electronics into the solar assembly.")
return 1
else
- if(iscrowbar(W))
+ if(istype(W, /obj/item/weapon/crowbar))
new /obj/item/weapon/tracker_electronics(src.loc)
tracker = 0
user.visible_message("[user] takes out the electronics from the solar assembly.")
@@ -269,18 +279,18 @@ var/list/solars_list = list()
icon_state = "solar"
anchored = 1
density = 1
- directwired = 1
use_power = 1
- idle_power_usage = 5
- active_power_usage = 20
+ idle_power_usage = 250
var/id = 0
var/cdir = 0
+ var/targetdir = 0 // target angle in manual tracking (since it updates every game minute)
var/gen = 0
var/lastgen = 0
- var/track = 0 // 0=off 1=manual 2=automatic
- var/trackrate = 60 // Measured in tenths of degree per minute (i.e. defaults to 6.0 deg/min)
- var/trackdir = 1 // -1=CCW, 1=CW
- var/nexttime = 0 // Next clock time that manual tracking will move the array
+ var/track = 0 // 0= off 1=timed 2=auto (tracker)
+ var/trackrate = 600 // 300-900 seconds
+ var/nexttime = 0 // time for a panel to rotate of 1� in manual tracking
+ var/obj/machinery/power/tracker/connected_tracker = null
+ var/list/connected_panels = list()
/obj/machinery/power/solar_control/New()
@@ -289,14 +299,53 @@ var/list/solars_list = list()
initialize()
connect_to_network()
+/obj/machinery/power/solar_control/Destroy()
+ for(var/obj/machinery/power/solar/M in connected_panels)
+ M.unset_control()
+ if(connected_tracker)
+ connected_tracker.unset_control()
+ ..()
+
/obj/machinery/power/solar_control/disconnect_from_network()
..()
solars_list.Remove(src)
/obj/machinery/power/solar_control/connect_to_network()
- ..()
+ var/to_return = ..()
+ if(powernet) //if connected and not already in solar_list...
+ solars_list |= src //... add it
+ return to_return
+
+//search for unconnected panels and trackers in the computer powernet and connect them
+/obj/machinery/power/solar_control/proc/search_for_connected()
if(powernet)
- solars_list.Add(src)
+ for(var/obj/machinery/power/M in powernet.nodes)
+ if(istype(M, /obj/machinery/power/solar))
+ var/obj/machinery/power/solar/S = M
+ if(!S.control) //i.e unconnected
+ S.set_control(src)
+ else if(istype(M, /obj/machinery/power/tracker))
+ if(!connected_tracker) //if there's already a tracker connected to the computer don't add another
+ var/obj/machinery/power/tracker/T = M
+ if(!T.control) //i.e unconnected
+ T.set_control(src)
+
+//called by the sun controller, update the facing angle (either manually or via tracking) and rotates the panels accordingly
+/obj/machinery/power/solar_control/proc/update()
+ if(stat & (NOPOWER | BROKEN))
+ return
+
+ switch(track)
+ if(1)
+ if(trackrate) //we're manual tracking. If we set a rotation speed...
+ cdir = targetdir //...the current direction is the targetted one (and rotates panels to it)
+ if(2) // auto-tracking
+ if(connected_tracker)
+ connected_tracker.set_angle(sun.angle)
+
+ set_panels(cdir)
+ updateDialog()
+
/obj/machinery/power/solar_control/initialize()
..()
@@ -314,32 +363,47 @@ var/list/solars_list = list()
return
icon_state = "solar"
overlays.Cut()
- if(cdir > 0)
+ if(cdir > -1)
overlays += image('icons/obj/computer.dmi', "solcon-o", FLY_LAYER, angle2dir(cdir))
return
-
-/obj/machinery/power/solar_control/attack_ai(mob/user)
- src.add_hiddenprint(user)
- add_fingerprint(user)
- if(stat & (BROKEN | NOPOWER)) return
- interact(user)
-
-
/obj/machinery/power/solar_control/attack_hand(mob/user)
- add_fingerprint(user)
- if(stat & (BROKEN | NOPOWER)) return
- interact(user)
+ if(!..())
+ ui_interact(user)
+/obj/machinery/power/solar_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+
+ var/data = list()
+
+ data["generated"] = round(lastgen)
+ data["angle"] = cdir
+ data["direction"] = angle2text(cdir)
+
+ data["tracking_state"] = track
+ data["tracking_rate"] = trackrate
+ data["rotating_way"] = (trackrate<0 ? "CCW" : "CW")
+
+ data["connected_panels"] = connected_panels.len
+ data["connected_tracker"] = (connected_tracker ? 1 : 0)
+
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if (!ui)
+ ui = new(user, src, ui_key, "solar_control.tmpl", name, 490, 420)
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(1)
+ else
+ ui.push_data(data)
+ return
/obj/machinery/power/solar_control/attackby(I as obj, user as mob)
if(istype(I, /obj/item/weapon/screwdriver))
- playsound(get_turf(src), 'sound/items/Screwdriver.ogg', 50, 1)
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
if(do_after(user, 20))
if (src.stat & BROKEN)
- user << "\blue The broken glass falls out."
+ user << "The broken glass falls out."
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
- getFromPool(/obj/item/weapon/shard, loc)
+ new /obj/item/weapon/shard( src.loc )
var/obj/item/weapon/circuitboard/solar_control/M = new /obj/item/weapon/circuitboard/solar_control( A )
for (var/obj/C in src)
C.loc = src.loc
@@ -347,9 +411,9 @@ var/list/solars_list = list()
A.state = 3
A.icon_state = "3"
A.anchored = 1
- del(src)
+ qdel(src)
else
- user << "\blue You disconnect the monitor."
+ user << "You disconnect the monitor."
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
var/obj/item/weapon/circuitboard/solar_control/M = new /obj/item/weapon/circuitboard/solar_control( A )
for (var/obj/C in src)
@@ -358,12 +422,11 @@ var/list/solars_list = list()
A.state = 4
A.icon_state = "4"
A.anchored = 1
- del(src)
+ qdel(src)
else
src.attack_hand(user)
return
-
/obj/machinery/power/solar_control/process()
lastgen = gen
gen = 0
@@ -371,139 +434,64 @@ var/list/solars_list = list()
if(stat & (NOPOWER | BROKEN))
return
- use_power(250)
- if(track==1 && nexttime < world.time && trackdir*trackrate)
- // Increments nexttime using itself and not world.time to prevent drift
- nexttime = nexttime + 6000/trackrate
- // Nudges array 1 degree in desired direction
- cdir = (cdir+trackdir+360)%360
- set_panels(cdir)
- update_icon()
-
- src.updateDialog()
-
-
-// called by solar tracker when sun position changes
-/obj/machinery/power/solar_control/proc/tracker_update(var/angle)
- if(track != 2 || stat & (NOPOWER | BROKEN))
- return
- cdir = angle
- set_panels(cdir)
- update_icon()
- src.updateDialog()
-
-
-/obj/machinery/power/solar_control/interact(mob/user)
- if(stat & (BROKEN | NOPOWER)) return
- if ( (get_dist(src, user) > 1 ))
- if (!istype(user, /mob/living/silicon/ai))
- user.unset_machine()
- user << browse(null, "window=solcon")
- return
-
- add_fingerprint(user)
- user.set_machine(src)
-
-
- // AUTOFIXED BY fix_string_idiocy.py
- // C:\Users\Rob\Documents\Projects\vgstation13\code\modules\power\solar.dm:407: var/t = "Solar Generator Control
"
- var/t = {"Solar Generator Control
-Generated power : [round(lastgen)] W
-Station Rotational Period: [60/abs(sun.rate)] minutes
-Station Rotational Direction: [sun.rate<0 ? "CCW" : "CW"]
-Star Orientation: [sun.angle]° ([angle2text(sun.angle)])
-Array Orientation: [rate_control(src,"cdir","[cdir]°",1,10,60)] ([angle2text(cdir)])
-
-Tracking:"}
- // END AUTOFIX
- switch(track)
- if(0)
- t += "Off Manual Automatic
"
- if(1)
- t += "Off Manual Automatic
"
- if(2)
- t += "Off Manual Automatic
"
-
-
- // AUTOFIXED BY fix_string_idiocy.py
- // C:\Users\Rob\Documents\Projects\vgstation13\code\modules\power\solar.dm:423: t += "Manual Tracking Rate: [rate_control(src,"tdir","[trackrate/10]°/min ([trackdir<0 ? "CCW" : "CW"])",1,10)]
"
- t += {"Manual Tracking Rate: [rate_control(src,"tdir","[trackrate/10]°/min ([trackdir<0 ? "CCW" : "CW"])",1,10)]
-Manual Tracking Direction:"}
- // END AUTOFIX
- switch(trackdir)
- if(-1)
- t += "CW CCW
"
- if(1)
- t += "CW CCW
"
- t += "Close
"
- user << browse(t, "window=solcon")
- onclose(user, "solcon")
- return
+ if(connected_tracker) //NOTE : handled here so that we don't add trackers to the processing list
+ if(connected_tracker.powernet != powernet)
+ connected_tracker.unset_control()
+ if(track==1 && trackrate) //manual tracking and set a rotation speed
+ if(nexttime <= world.time) //every time we need to increase/decrease the angle by 1�...
+ targetdir = (targetdir + trackrate/abs(trackrate) + 360) % 360 //... do it
+ nexttime += 36000/abs(trackrate) //reset the counter for the next 1�
/obj/machinery/power/solar_control/Topic(href, href_list)
if(..())
- usr << browse(null, "window=solcon")
- usr.unset_machine()
return
- if(href_list["close"] )
- usr << browse(null, "window=solcon")
- usr.unset_machine()
- return
-
- if(href_list["dir"])
- cdir = text2num(href_list["dir"])
- set_panels(cdir)
- update_icon()
-
- if(href_list["rate control"])
+
+ if(href_list["rate_control"])
if(href_list["cdir"])
src.cdir = dd_range(0,359,(360+src.cdir+text2num(href_list["cdir"]))%360)
+ src.targetdir = src.cdir
+ if(track == 2) //manual update, so losing auto-tracking
+ track = 0
spawn(1)
set_panels(cdir)
- update_icon()
if(href_list["tdir"])
- src.trackrate = dd_range(0,360,src.trackrate+text2num(href_list["tdir"]))
- if(src.trackrate) nexttime = world.time + 6000/trackrate
+ src.trackrate = dd_range(-7200,7200,src.trackrate+text2num(href_list["tdir"]))
+ if(src.trackrate) nexttime = world.time + 36000/abs(trackrate)
if(href_list["track"])
- if(src.trackrate) nexttime = world.time + 6000/trackrate
track = text2num(href_list["track"])
- if(powernet && (track == 2))
- if(!solars_list.Find(src,1,0) || !(locate(src) in solars_list) || !(src in solars_list))
- solars_list.Add(src)
- for(var/obj/machinery/power/tracker/T in get_solars_powernet())
- if(powernet.nodes[T])
- cdir = T.sun_angle
- break
+ if(track == 2)
+ if(connected_tracker)
+ connected_tracker.set_angle(sun.angle)
+ set_panels(cdir)
+ else if (track == 1) //begin manual tracking
+ src.targetdir = src.cdir
+ if(src.trackrate) nexttime = world.time + 36000/abs(trackrate)
+ set_panels(targetdir)
- if(href_list["trackdir"])
- trackdir = text2num(href_list["trackdir"])
+ if(href_list["search_connected"])
+ search_for_connected()
+ if(connected_tracker && track == 2)
+ connected_tracker.set_angle(sun.angle)
+ set_panels(cdir)
- set_panels(cdir)
- update_icon()
- src.updateUsrDialog()
return
-
+//rotates the panel to the passed angle
/obj/machinery/power/solar_control/proc/set_panels(var/cdir)
- if(!powernet) return
- for(var/obj/machinery/power/solar/S in get_solars_powernet())
- if(powernet.nodes[S])
- if(get_dist(S, src) < SOLAR_MAX_DIST)
- if(!S.control)
- S.control = src
- S.ndir = cdir
+
+ for(var/obj/machinery/power/solar/S in connected_panels)
+ S.adir = cdir //instantly rotates the panel
+ S.occlusion()//and
+ S.update_icon() //update it
+
+ update_icon()
/obj/machinery/power/solar_control/power_change()
- if(powered())
- stat &= ~NOPOWER
- update_icon()
- else
- spawn(rand(0, 15))
- stat |= NOPOWER
- update_icon()
+ ..()
+ update_icon()
/obj/machinery/power/solar_control/proc/broken()
@@ -511,25 +499,16 @@ Manual Tracking Direction:"}
update_icon()
-/obj/machinery/power/solar_control/meteorhit()
- broken()
- return
-
-
-/obj/machinery/power/solar_control/ex_act(severity)
- switch(severity)
- if(1.0)
- //SN src = null
- qdel(src)
- return
- if(2.0)
- if (prob(50))
- broken()
- if(3.0)
- if (prob(25))
- broken()
- return
-
+/obj/machinery/power/solar_control/ex_act(severity, target)
+ ..()
+ if(!gc_destroyed)
+ switch(severity)
+ if(2)
+ if(prob(50))
+ broken()
+ if(3)
+ if(prob(25))
+ broken()
/obj/machinery/power/solar_control/blob_act()
if (prob(75))
@@ -543,4 +522,4 @@ Manual Tracking Direction:"}
/obj/item/weapon/paper/solar
name = "paper- 'Going green! Setup your own solar array instructions.'"
- info = "Welcome
At greencorps we love the environment, and space. With this package you are able to help mother nature and produce energy without any usage of fossil fuel or plasma! Singularity energy is dangerous while solar energy is safe, which is why it's better. Now here is how you setup your own solar array.
You can make a solar panel by wrenching the solar assembly onto a cable node. Adding a glass panel, reinforced or regular glass will do, will finish the construction of your solar panel. It is that easy!.
Now after setting up 19 more of these solar panels you will want to create a solar tracker to keep track of our mother nature's gift, the sun. These are the same steps as before except you insert the tracker equipment circuit into the assembly before performing the final step of adding the glass. You now have a tracker! Now the last step is to add a computer to calculate the sun's movements and to send commands to the solar panels to change direction with the sun. Setting up the solar computer is the same as setting up any computer, so you should have no trouble in doing that. You do need to put a wire node under the computer, and the wire needs to be connected to the tracker.
Congratulations, you should have a working solar array. If you are having trouble, here are some tips. Make sure all solar equipment are on a cable node, even the computer. You can always deconstruct your creations if you make a mistake.
That's all to it, be safe, be green!
"
+ info = "Welcome
At greencorps we love the environment, and space. With this package you are able to help mother nature and produce energy without any usage of fossil fuel or plasma! Singularity energy is dangerous while solar energy is safe, which is why it's better. Now here is how you setup your own solar array.
You can make a solar panel by wrenching the solar assembly onto a cable node. Adding a glass panel, reinforced or regular glass will do, will finish the construction of your solar panel. It is that easy!
Now after setting up 19 more of these solar panels you will want to create a solar tracker to keep track of our mother nature's gift, the sun. These are the same steps as before except you insert the tracker equipment circuit into the assembly before performing the final step of adding the glass. You now have a tracker! Now the last step is to add a computer to calculate the sun's movements and to send commands to the solar panels to change direction with the sun. Setting up the solar computer is the same as setting up any computer, so you should have no trouble in doing that. You do need to put a wire node under the computer, and the wire needs to be connected to the tracker.
Congratulations, you should have a working solar array. If you are having trouble, here are some tips. Make sure all solar equipment are on a cable node, even the computer. You can always deconstruct your creations if you make a mistake.
That's all to it, be safe, be green!
"
\ No newline at end of file
diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm
index d35cf81ed45..5cf341f9fbb 100644
--- a/code/modules/power/tracker.dm
+++ b/code/modules/power/tracker.dm
@@ -10,78 +10,70 @@
icon_state = "tracker"
anchored = 1
density = 1
- directwired = 1
use_power = 0
+ var/id = 0
var/sun_angle = 0 // sun angle as set by sun datum
+ var/obj/machinery/power/solar_control/control = null
/obj/machinery/power/tracker/New(var/turf/loc, var/obj/item/solar_assembly/S)
..(loc)
+ Make(S)
+ connect_to_network()
+
+/obj/machinery/power/tracker/Destroy()
+ unset_control() //remove from control computer
+ ..()
+
+//set the control of the tracker to a given computer if closer than SOLAR_MAX_DIST
+/obj/machinery/power/tracker/proc/set_control(var/obj/machinery/power/solar_control/SC)
+ if(!SC || (get_dist(src, SC) > SOLAR_MAX_DIST))
+ return 0
+ control = SC
+ SC.connected_tracker = src
+ return 1
+
+//set the control of the tracker to null and removes it from the previous control computer if needed
+/obj/machinery/power/tracker/proc/unset_control()
+ if(control)
+ control.connected_tracker = null
+ control = null
+
+/obj/machinery/power/tracker/proc/Make(var/obj/item/solar_assembly/S)
if(!S)
S = new /obj/item/solar_assembly(src)
S.glass_type = /obj/item/stack/sheet/glass
S.tracker = 1
S.anchored = 1
S.loc = src
- connect_to_network()
+ update_icon()
-/obj/machinery/power/tracker/disconnect_from_network()
- ..()
- solars_list.Remove(src)
-
-/obj/machinery/power/tracker/connect_to_network()
- ..()
- solars_list.Add(src)
-
-// called by datum/sun/calc_position() as sun's angle changes
+//updates the tracker icon and the facing angle for the control computer
/obj/machinery/power/tracker/proc/set_angle(var/angle)
sun_angle = angle
//set icon dir to show sun illumination
dir = turn(NORTH, -angle - 22.5) // 22.5 deg bias ensures, e.g. 67.5-112.5 is EAST
- // check we can draw power
- if(stat & NOPOWER)
- return
-
- // find all solar controls and update them
- // currently, just update all controllers in world
- // ***TODO: better communication system using network
- if(powernet)
- for(var/obj/machinery/power/solar_control/C in get_solars_powernet())
- if(powernet.nodes[C])
- if(get_dist(C, src) < SOLAR_MAX_DIST)
- C.tracker_update(angle)
-
+ if(powernet && (powernet == control.powernet)) //update if we're still in the same powernet
+ control.cdir = angle
/obj/machinery/power/tracker/attackby(var/obj/item/weapon/W, var/mob/user)
- if(iscrowbar(W))
- playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
+ if(istype(W, /obj/item/weapon/crowbar))
+ playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
+ user.visible_message("[user] begins to take the glass off the solar tracker.")
if(do_after(user, 50))
var/obj/item/solar_assembly/S = locate() in src
if(S)
S.loc = src.loc
S.give_glass()
- playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
+ playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
user.visible_message("[user] takes the glass off the tracker.")
- del(src)
+ qdel(src)
return
..()
-// timed process
-// make sure we can draw power from the powernet
-/obj/machinery/power/tracker/process()
-
- var/avail = surplus()
-
- if(avail > 500)
- add_load(500)
- stat &= ~NOPOWER
- else
- stat |= NOPOWER
-
-
// Tracker Electronic
/obj/item/weapon/tracker_electronics
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index d8a4ef3f1bf..b030faa14d6 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -26,6 +26,7 @@
var/list/broken_requirements = list()
var/broken_on_spawn = 0
var/recharge_delay = 15
+ var/image/icon_beaker = null //cached overlay
/obj/machinery/chem_dispenser/proc/recharge()
@@ -59,6 +60,7 @@
dispensable_reagents = sortList(dispensable_reagents)
if(broken_on_spawn)
+ overlays.Cut()
var/amount = pick(3,3,4)
var/list/options = list()
options[/obj/item/weapon/stock_parts/capacitor/adv] = "Add an advanced capacitor to fix it."
@@ -181,8 +183,7 @@
var/obj/item/weapon/reagent_containers/glass/B = beaker
B.loc = loc
beaker = null
- if(!panel_open)
- icon_state = initial(icon_state)
+ overlays.Cut()
add_fingerprint(usr)
return 1 // update UIs attached to this object
@@ -211,7 +212,10 @@
B.loc = src
user << "You set [B] on the machine."
nanomanager.update_uis(src) // update all UIs attached to src
- icon_state = "[initial(icon_state)]2"
+ if(!icon_beaker)
+ icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
+ icon_beaker.pixel_x = rand(-10,5)
+ overlays += icon_beaker
return
/obj/machinery/chem_dispenser/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob)
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index 23ae6ce02b1..afe56a4f731 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -67,14 +67,14 @@
var/datum/reagents/R = reagent_list[reagent_list.len]
R.add_reagent(reagent, 30)
-/obj/item/weapon/reagent_containers/borghypo/attack(mob/M as mob, mob/user as mob)
+/obj/item/weapon/reagent_containers/borghypo/attack(mob/living/M as mob, mob/user as mob)
var/datum/reagents/R = reagent_list[mode]
if(!R.total_volume)
user << "\red The injector is empty."
return
- if (!( istype(M, /mob) ))
+ if (!(istype(M)))
return
- if (R.total_volume)
+ if (R.total_volume && M.can_inject(user,1))
user << "\blue You inject [M] with the injector."
M << "\red You feel a tiny prick!"
diff --git a/code/modules/reagents/reagent_containers/food/snacks/meat.dm b/code/modules/reagents/reagent_containers/food/snacks/meat.dm
index d0c0e707c36..8809ddc6468 100644
--- a/code/modules/reagents/reagent_containers/food/snacks/meat.dm
+++ b/code/modules/reagents/reagent_containers/food/snacks/meat.dm
@@ -35,3 +35,7 @@
/obj/item/weapon/reagent_containers/food/snacks/meat/corgi
name = "Corgi meat"
desc = "Tastes like... well you know..."
+
+/obj/item/weapon/reagent_containers/food/snacks/meat/pug
+ name = "Pug meat"
+ desc = "Tastes like... well you know..."
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 4f1b8140531..ee8b39ce66b 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -226,7 +226,7 @@
name = "large beaker"
desc = "A large beaker. Can hold up to 100 units."
icon_state = "beakerlarge"
-
g_amt = 5000
+
g_amt = 2500
volume = 100
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,25,30,50,100)
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index a129dde7472..cd3acea26fe 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -230,7 +230,7 @@
name = "Metal"
id = "metal"
build_type = AUTOLATHE
- materials = list("$metal" = MINERAL_MATERIAL_AMOUNT)
+ materials = list("$metal" = 3750)
build_path = /obj/item/stack/sheet/metal
category = list("initial","Construction")
@@ -254,7 +254,7 @@
name = "Reinforced Glass"
id = "rglass"
build_type = AUTOLATHE
- materials = list("$metal" = 1000, "$glass" = MINERAL_MATERIAL_AMOUNT)
+ materials = list("$metal" = 1875, "$glass" = MINERAL_MATERIAL_AMOUNT)
build_path = /obj/item/stack/sheet/rglass
category = list("initial","Construction")
@@ -262,7 +262,7 @@
name = "Metal Rod"
id = "rods"
build_type = AUTOLATHE
- materials = list("$metal" = 1000)
+ materials = list("$metal" = 1875)
build_path = /obj/item/stack/rods
category = list("initial","Construction")
@@ -440,7 +440,7 @@
id = "handcuffs"
build_type = AUTOLATHE
materials = list("$metal" = 500)
- build_path = /obj/item/weapon/handcuffs
+ build_path = /obj/item/weapon/restraints/handcuffs
category = list("hacked", "Security")
/datum/design/incendiary_slug
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 3c4469f1859..d22d31ceeae 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -52,7 +52,7 @@
req_tech = list("programming" = 2, "biotech" = 2, "magnets" = 2)
build_type = PROTOLATHE
materials = list("$metal" = 30, "$glass" = 20)
- reliability_base = 74
+ reliability_base = 76
build_path = /obj/item/device/robotanalyzer
category = list("Medical")
@@ -77,6 +77,17 @@
build_path = /obj/item/weapon/implantcase/freedom
category = list("Medical")
+/datum/design/sensor_device
+ name = "Handheld Crew Monitor"
+ desc = "A device for tracking crew members on the station."
+ id = "sensor_device"
+ req_tech = list("biotech" = 4, "magnets" = 3, "materials" = 3)
+ build_type = PROTOLATHE
+ materials = list("$metal" = 30, "$glass" = 20)
+ reliability_base = 76
+ build_path = /obj/item/device/sensor_device
+ category = list("Medical")
+
/datum/design/implanter
name = "Implanter"
desc = "A basic implanter for injecting implants"
diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm
index 90e7ff47ace..94db17abdc4 100644
--- a/code/modules/research/rdconsole.dm
+++ b/code/modules/research/rdconsole.dm
@@ -130,8 +130,8 @@ won't update every console in existence) but it's more of a hassle to do. Also,
files.known_tech=files.possible_tech
for(var/datum/tech/KT in files.known_tech)
if(KT.level < KT.max_level)
- KT.level=KT.max_level
-
+ KT.level=KT.max_level
+
/obj/machinery/computer/rdconsole/New()
..()
files = new /datum/research(src) //Setup the research data holder.
@@ -165,16 +165,17 @@ won't update every console in existence) but it's more of a hassle to do. Also,
user.drop_item()
D.loc = src
user << " You add the disk to the machine!"
- else if(istype(D,/obj/item/weapon/card/emag))
- if(!emagged)
- playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1)
- emagged = 1
- user << "You you disable the security protocols"
else
..()
src.updateUsrDialog()
return
+/obj/machinery/computer/rdconsole/emag_act(user as mob)
+ if(!emagged)
+ playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1)
+ emagged = 1
+ user << "You disable the security protocols"
+
/obj/machinery/computer/rdconsole/Topic(href, href_list)
if(..())
return
@@ -207,7 +208,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
t_disk = null
screen = 1.0
- else if(href_list["copy_tech"]) //Copys some technology data from the research holder to the disk.
+ else if(href_list["copy_tech"]) //Copy some technology data from the research holder to the disk.
for(var/datum/tech/T in files.known_tech)
if(href_list["copy_tech_ID"] == T.id)
t_disk.stored = T
@@ -249,11 +250,12 @@ won't update every console in existence) but it's more of a hassle to do. Also,
linked_destroy.loaded_item = null
linked_destroy.icon_state = "d_analyzer"
screen = 2.1
-
+
else if(href_list["maxresearch"]) //Eject the item inside the destructive analyzer.
if(!usr.client.holder) return
+ if(usr.client.holder & R_MENTOR) return
screen = 0.0
- if(alert("Are you sure you want to maximize research levels?","Confirmation","Yes","No")=="No")
+ if(alert("Are you sure you want to maximize research levels?","Confirmation","Yes","No")=="No")
return
log_admin("[key_name(usr)] has maximized the research levels.")
message_admins("[key_name_admin(usr)] has maximized the research levels.")
@@ -261,7 +263,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
Maximize()
screen = 1.0
updateUsrDialog()
- griefProtection() //Update centcomm too
+ griefProtection() //Update centcomm too
else if(href_list["deconstruct"]) //Deconstruct the item in the destructive analyzer and update the research holder.
if(linked_destroy)
@@ -371,6 +373,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
if(being_built)
var/power = 2000
var/amount=text2num(href_list["amount"])
+ var/old_screen = screen
amount = max(1, min(10, amount))
for(var/M in being_built.materials)
power += round(being_built.materials[M] * amount / 5)
@@ -436,7 +439,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
else
new_item.loc = linked_lathe.loc
linked_lathe.busy = 0
- screen = 3.15
+ screen = old_screen
updateUsrDialog()
else if(href_list["imprint"]) //Causes the Circuit Imprinter to build something.
@@ -450,6 +453,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
break
if(being_built)
var/power = 2000
+ var/old_screen = screen
for(var/M in being_built.materials)
power += round(being_built.materials[M] / 5)
power = max(2000, power)
@@ -488,7 +492,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
new_item.reliability = R
new_item.loc = linked_imprinter.loc
linked_imprinter.busy = 0
- screen = 4.1
+ screen = old_screen
updateUsrDialog()
else if(href_list["disposeI"] && linked_imprinter) //Causes the circuit imprinter to dispose of a single reagent (all of it)
@@ -590,7 +594,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
spawn(20)
screen = 1.6
updateUsrDialog()
-
+
else if(href_list["search"]) //Search for designs with name matching pattern
var/compare
@@ -608,7 +612,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
continue
if(findtext(D.name,href_list["to_search"]))
matching_designs.Add(D)
-
+
updateUsrDialog()
return
@@ -870,7 +874,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
dat += " | LOCKED"
dat += "
"
dat += ""
-
+
if(3.17) //Display search result
dat += "Main Menu"
dat += "Protolathe Menu"
@@ -978,7 +982,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
dat += "Circuit Imprinter Menu:
"
dat += "Material Amount: [linked_imprinter.TotalMaterials()]
"
dat += "Chemical Volume: [linked_imprinter.reagents.total_volume]
"
-
+
dat += "