diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 04bdb0d8e177..87799bb075f7 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -335,6 +335,8 @@
else
parts += "
"
parts += "
You managed to survive the events on [station_name()] as [M.real_name]."
+ if(M.mind.assigned_role in GLOB.engineering_positions) // We don't actually need to even really do a check to see if assigned_role is set to anything.
+ SSachievements.unlock_achievement(/datum/achievement/engineering, C)
else
parts += "
"
diff --git a/code/controllers/subsystem/achievements.dm b/code/controllers/subsystem/achievements.dm
index 2119f9c2e20c..49d5f01757c2 100644
--- a/code/controllers/subsystem/achievements.dm
+++ b/code/controllers/subsystem/achievements.dm
@@ -1,10 +1,11 @@
SUBSYSTEM_DEF(achievements)
name = "Achievements"
- flags = SS_NO_FIRE
+ flags = SS_BACKGROUND
var/list/achievements = list()
var/list/cached_achievements = list()
var/list/browsers = list()
var/list/achievementsEarned = list()
+ var/mob/living/carbon/human/CE // The current guy that SSachievements believes to be the CE.
/datum/controller/subsystem/achievements/Initialize(timeofday)
for(var/i in subtypesof(/datum/achievement))
@@ -47,6 +48,23 @@ SUBSYSTEM_DEF(achievements)
qdel(ridOldChieves)
return ..()
+/datum/controller/subsystem/achievements/fire(resumed)
+ //The solar panel achievement
+ if(!CE)
+ for(var/x in GLOB.player_list)
+ if(ishuman(x))
+ var/mob/living/carbon/human/H = x
+ if(H.mind?.assigned_role == "Chief Engineer")
+ CE = H
+ break
+ else
+ for(var/n in SSmachines.powernets)
+ var/datum/powernet/net = n
+ if(is_station_level(net.z)) // If the powernet is on the station z-level
+ if(net.avail >= 3000 && CE.stat != DEAD && CE.client) // If there's 3 MW available (Value is in kW)
+ unlock_achievement(/datum/achievement/engineering/scotty, CE.client)
+
+//Ad-hoc procs
/datum/controller/subsystem/achievements/proc/unlock_achievement(achievementPath, client/C)
var/datum/achievement/achievement = get_achievement(achievementPath)
if(!achievement)
diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm
index c4b09d1b8741..8ebe7b4eedb8 100644
--- a/code/controllers/subsystem/machines.dm
+++ b/code/controllers/subsystem/machines.dm
@@ -18,7 +18,7 @@ SUBSYSTEM_DEF(machines)
for(var/obj/structure/cable/PC in GLOB.cable_list)
if(!PC.powernet)
- var/datum/powernet/NewPN = new()
+ var/datum/powernet/NewPN = new(PC.loc.z)
NewPN.add_cable(PC)
propagate_network(PC,PC.powernet)
@@ -53,7 +53,7 @@ SUBSYSTEM_DEF(machines)
for(var/A in cables)
var/obj/structure/cable/PC = A
if(!PC.powernet)
- var/datum/powernet/NewPN = new()
+ var/datum/powernet/NewPN = new(PC.loc.z)
NewPN.add_cable(PC)
propagate_network(PC,PC.powernet)
diff --git a/code/datums/achievements/achievements.dm b/code/datums/achievements/achievements.dm
index 568ad226ba0a..458bf0476cfc 100644
--- a/code/datums/achievements/achievements.dm
+++ b/code/datums/achievements/achievements.dm
@@ -3,6 +3,7 @@
//TO BE HONEST THIS OFFSET DOESN'T EVEN NEED TO BE POWER OF TWO, THOUGH.
#define GREENTEXT 256 // An offset for new greentext-related achievements, to keep the incremental pattern.
#define REDTEXT 512 // Offset for redtexts.
+#define ENGIEDEPT 768 // Offset for engineering-related achievements.
/datum/achievement
var/name = "achievement"
@@ -25,7 +26,7 @@
desc = "Successfully defibrillate someone"
id = 3
-/datum/achievement/pa_emag
+/datum/achievement/engineering/pa_emag
name = "Catastrophe"
desc = "Emag a particle accelerator"
id = 4
@@ -100,13 +101,13 @@
id = 17
hidden = TRUE
-/datum/achievement/Poly_silent
+/datum/achievement/engineering/Poly_silent
name = "Silence Bird!"
desc = "As a signal technician, create a script that mutes poly"
id = 18
hidden = TRUE
-/datum/achievement/Poly_loud
+/datum/achievement/engineering/Poly_loud
name = "Embrace the Bird!"
desc = "As a signal technician, create a script that makes poly LOUD"
id = 19
@@ -143,6 +144,12 @@
desc = "Trigger a keycard authentication device event, by yourself."
id = 23
+/datum/achievement/dab
+ name = "Brain Damage"
+ desc = "Dab."
+ id = 24
+ hidden = TRUE
+
// The achievements that are basically just "greentext as this sort of antag"
/datum/achievement/greentext
@@ -245,5 +252,25 @@
hidden = TRUE
//end-redtext
+//start-engineering
+/datum/achievement/engineering
+ name = "Isaac Clarke"
+ desc = "Survive a full round as part of the Engineering team."
+ id = ENGIEDEPT + 1
+/datum/achievement/engineering/solar
+ name = "Honest Work"
+ desc = "Set up one of the solar arrays as part of the Engineering team."
+ id = ENGIEDEPT + 2
+/datum/achievement/engineering/scotty
+ name = "\"I'm givin' it all she's got, Captain!\""
+ desc = "As Chief Engineer, produce more than three megawatts of power."
+ id = ENGIEDEPT + 3
+/datum/achievement/engineering/toasty
+ name = "Nice and Toasty"
+ desc = "Get set on fire in a fire-resistant suit."
+ id = ENGIEDEPT + 4
+//end-engineering
+
#undef GREENTEXT
-#undef REDTEXT
\ No newline at end of file
+#undef REDTEXT
+#undef ENGIEDEPT
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 4f213e55d98a..57320f133592 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -150,6 +150,8 @@
//If have no DNA or can be Ignited, call parent handling to light user
//If firestacks are high enough
if(!dna || dna.species.CanIgniteMob(src))
+ if(get_thermal_protection() > FIRE_SUIT_MAX_TEMP_PROTECT*0.95) // If they're resistant to fire (slightly undercut to make sure get_thermal_protection doesn't fuck over this achievement due to floating-point errors
+ SSachievements.unlock_achievement(/datum/achievement/engineering/toasty,src.client) // Fear the reaper man!
return ..()
. = FALSE //No ignition
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 22e5b0bcce8f..d42110d582a1 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -260,7 +260,7 @@ By design, d1 is the smallest direction and d2 is the highest
if(C.d1 == (direction^3) || C.d2 == (direction^3)) //we've got a diagonally matching cable
if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
- var/datum/powernet/newPN = new()
+ var/datum/powernet/newPN = new(C.loc.z)
newPN.add_cable(C)
if(powernet) //if we already have a powernet, then merge the two powernets
@@ -280,7 +280,7 @@ By design, d1 is the smallest direction and d2 is the highest
continue
if(C.d1 == (direction^12) || C.d2 == (direction^12)) //we've got a diagonally matching cable
if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
- var/datum/powernet/newPN = new()
+ var/datum/powernet/newPN = new(C.loc.z)
newPN.add_cable(C)
if(powernet) //if we already have a powernet, then merge the two powernets
@@ -308,7 +308,7 @@ By design, d1 is the smallest direction and d2 is the highest
if(C.d1 == fdir || C.d2 == fdir) //we've got a matching cable in the neighbor turf
if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
- var/datum/powernet/newPN = new()
+ var/datum/powernet/newPN = new(C.loc.z)
newPN.add_cable(C)
if(powernet) //if we already have a powernet, then merge the two powernets
@@ -321,7 +321,7 @@ By design, d1 is the smallest direction and d2 is the highest
var/list/to_connect = list()
if(!powernet) //if we somehow have no powernet, make one (should not happen for cables)
- var/datum/powernet/newPN = new()
+ var/datum/powernet/newPN = new(loc.z)
newPN.add_cable(src)
//first let's add turf cables to our powernet
@@ -410,7 +410,7 @@ By design, d1 is the smallest direction and d2 is the highest
var/list/powerlist = power_list(T1,src,0,0) //find the other cables that ended in the centre of the turf, with or without a powernet
if(powerlist.len>0)
- var/datum/powernet/PN = new()
+ var/datum/powernet/PN = new(loc.z)
propagate_network(powerlist[1],PN) //propagates the new powernet beginning at the source cable
if(PN.is_empty()) //can happen with machines made nodeless when smoothing cables
@@ -418,7 +418,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/structure/cable/proc/auto_propogate_cut_cable(obj/O)
if(O && !QDELETED(O))
- var/datum/powernet/newPN = new()// creates a new powernet...
+ var/datum/powernet/newPN = new(loc.z)// creates a new powernet...
propagate_network(O, newPN)//... and propagates it to the other side of the cable
// cut the cable's powernet at this cable and updates the powergrid
@@ -620,7 +620,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
C.update_icon()
//create a new powernet with the cable, if needed it will be merged later
- var/datum/powernet/PN = new()
+ var/datum/powernet/PN = new(loc.z)
PN.add_cable(C)
C.mergeConnectedNetworks(C.d2) //merge the powernet with adjacents powernets
@@ -692,7 +692,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
NC.update_icon()
//create a new powernet with the cable, if needed it will be merged later
- var/datum/powernet/newPN = new()
+ var/datum/powernet/newPN = new(loc.z)
newPN.add_cable(NC)
NC.mergeConnectedNetworks(NC.d2) //merge the powernet with adjacents powernets
diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm
index 9660e8359c55..64727cd9edf0 100644
--- a/code/modules/power/powernet.dm
+++ b/code/modules/power/powernet.dm
@@ -14,9 +14,11 @@
var/viewload = 0 // the load as it appears on the power console (gradually updated)
var/netexcess = 0 // excess power on the powernet (typically avail-load)///////
var/delayedload = 0 // load applied to powernet between power ticks.
+ var/z = 0 // the Z coordinate of this powernet. Only used by some random achievement, at the moment.
-/datum/powernet/New()
+/datum/powernet/New(newz)
SSmachines.powernets += src
+ z = newz
/datum/powernet/Destroy()
//Go away references, you suck!
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 9316a145251a..b9f8bf009aaa 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -273,6 +273,7 @@
var/nexttime = 0 // time for a panel to rotate of 1 degree in manual tracking
var/obj/machinery/power/tracker/connected_tracker = null
var/list/connected_panels = list()
+ var/mob/living/carbon/human/last_user // The last guy to open up the console
/obj/machinery/power/solar_control/Initialize()
. = ..()
@@ -344,6 +345,8 @@
if(!ui)
ui = new(user, src, ui_key, "solar_control", name, 380, 230, master_ui, state)
ui.open()
+ if(ishuman(user))
+ last_user = user
/obj/machinery/power/solar_control/ui_data()
var/data = list()
@@ -398,7 +401,11 @@
set_panels(targetdir)
return TRUE
if(action == "refresh")
+ var/was_not_connected = !(connected_tracker && connected_panels.len)
search_for_connected()
+ if(last_user && last_user.client && was_not_connected && connected_tracker && connected_panels.len) // If this guy finished up the solars
+ if(last_user.stat != DEAD && (last_user.mind?.assigned_role in GLOB.engineering_positions)) // and he's an engineer who isn't long-dead or adminbussing
+ SSachievements.unlock_achievement(/datum/achievement/engineering/solar, last_user.client) // Give him the achievement
if(connected_tracker && track == 2)
connected_tracker.set_angle(SSsun.angle)
set_panels(currentdir)
diff --git a/yogstation/code/game/machinery/telecomms/machines/server.dm b/yogstation/code/game/machinery/telecomms/machines/server.dm
index f2e348e8f4b5..80bc569aa9eb 100644
--- a/yogstation/code/game/machinery/telecomms/machines/server.dm
+++ b/yogstation/code/game/machinery/telecomms/machines/server.dm
@@ -75,15 +75,11 @@
signal.data["reject"] = 0
Compiler.Run(signal)
if(signal.data["reject"] == 0)
- SSachievements.unlock_achievement(/datum/achievement/Poly_silent, user.client)
+ SSachievements.unlock_achievement(/datum/achievement/engineering/Poly_silent, user.client)
else
for(var/sample in signal.data["spans"])
if(sample == SPAN_COMMAND)
- signal.data["name"] = ""
- signal.data["spans"] = list()
- Compiler.Run(signal)
- for(var/S in signal.data["spans"])
- if(S == SPAN_COMMAND)
- SSachievements.unlock_achievement(/datum/achievement/Poly_loud, user.client)
+ SSachievements.unlock_achievement(/datum/achievement/engineering/Poly_loud, user.client)
+ break // Not having this break leaves us open to a potential DoS attack.
return compileerrors
//end-NTSL
diff --git a/yogstation/code/modules/mob/living/emote.dm b/yogstation/code/modules/mob/living/emote.dm
index ee6e02e506e4..1f3d9c7a0098 100644
--- a/yogstation/code/modules/mob/living/emote.dm
+++ b/yogstation/code/modules/mob/living/emote.dm
@@ -74,3 +74,4 @@
var/light_dab_speed = rand(3,7)
H.DabAnimation(angle = light_dab_angle , speed = light_dab_speed)
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5)
+ SSachievements.unlock_achievement(/datum/achievement/dab,H.client)
diff --git a/yogstation/code/modules/power/singularity/particle_accelerator/particle_control.dm b/yogstation/code/modules/power/singularity/particle_accelerator/particle_control.dm
index 64b7b68c32d4..0ec34ca74ed2 100644
--- a/yogstation/code/modules/power/singularity/particle_accelerator/particle_control.dm
+++ b/yogstation/code/modules/power/singularity/particle_accelerator/particle_control.dm
@@ -5,7 +5,7 @@
if(obj_flags & EMAGGED)
return
to_chat(user, "The laws of physics no longer apply in the future, god help you...")
- SSachievements.unlock_achievement(/datum/achievement/pa_emag, user.client)
+ SSachievements.unlock_achievement(/datum/achievement/engineering/pa_emag, user.client)
do_sparks(5, 0, src)
obj_flags |= EMAGGED