")
- t = replacetext(t, "\[br\]", " ")
- t = replacetext(t, "\[b\]", "")
- t = replacetext(t, "\[/b\]", "")
- t = replacetext(t, "\[i\]", "")
- t = replacetext(t, "\[/i\]", "")
- t = replacetext(t, "\[u\]", "")
- t = replacetext(t, "\[/u\]", "")
- t = replacetext(t, "\[large\]", "")
- t = replacetext(t, "\[/large\]", "")
- if(user)
- t = replacetext(t, "\[sign\]", "[user.real_name]")
- else
- t = replacetext(t, "\[sign\]", "")
- t = replacetext(t, "\[field\]", "")
+ // This parses markdown with no custom rules
- t = replacetext(t, "\[*\]", "
")
- t = replacetext(t, "\[hr\]", "")
- t = replacetext(t, "\[small\]", "")
- t = replacetext(t, "\[/small\]", "")
- t = replacetext(t, "\[list\]", "
")
- t = replacetext(t, "\[/list\]", "
")
+ // Escape backslashed
+
+ t = replacetext(t, "$", "$-")
+ t = replacetext(t, "\\\\", "$1")
+ t = replacetext(t, "\\**", "$2")
+ t = replacetext(t, "\\*", "$3")
+ t = replacetext(t, "\\__", "$4")
+ t = replacetext(t, "\\_", "$5")
+ t = replacetext(t, "\\^", "$6")
+ t = replacetext(t, "\\((", "$7")
+ t = replacetext(t, "\\))", "$8")
+ t = replacetext(t, "\\|", "$9")
+ t = replacetext(t, "\\%", "$0")
+
+ // Escape single characters that will be used
+
+ t = replacetext(t, "!", "$a")
+
+ // Parse hr and small
+
+ if(!limited)
+ t = replacetext(t, "((", "")
+ t = replacetext(t, "))", "")
+ t = replacetext(t, regex("^-{3,}$", "gm"), "")
+ t = replacetext(t, regex("^\\(-{3,})$", "gm"), "$1")
+
+ // Parse lists
+
+ var/list/tlist = splittext(t, "\n")
+ var/tlistlen = tlist.len
+ var/listlevel = -1
+ var/singlespace = -1 // if 0, double spaces are used before asterisks, if 1, single are
+ for(var/i = 1, i <= tlistlen, i++)
+ var/line = tlist[i]
+ var/count_asterisk = length(replacetext(line, regex("\[^\\*\]+", "g"), ""))
+ if(count_asterisk % 2 == 1 && findtext(line, regex("^\\s*\\*", "g"))) // there is an extra asterisk in the beggining
+
+ var/count_w = length(replacetext(line, regex("^( *)\\*.*$", "g"), "$1")) // whitespace before asterisk
+ line = replacetext(line, regex("^ *(\\*.*)$", "g"), "$1")
+
+ if(singlespace == -1 && count_w == 2)
+ if(listlevel == 0)
+ singlespace = 0
+ else
+ singlespace = 1
+
+ if(singlespace == 0)
+ count_w = count_w % 2 ? round(count_w / 2 + 0.25) : count_w / 2
+
+ line = replacetext(line, regex("\\*", ""), "
")
+ while(listlevel < count_w)
+ line = "
" + line
+ listlevel++
+ while(listlevel > count_w)
+ line = "
" + line
+ listlevel--
+
+ else while(listlevel >= 0)
+ line = "" + line
+ listlevel--
+
+ tlist[i] = line
+ // end for
+
+ t = tlist[1]
+ for(var/i = 2, i <= tlistlen, i++)
+ t += "\n" + tlist[i]
+
+ while(listlevel >= 0)
+ t += ""
+ listlevel--
+
+ else
+ t = replacetext(t, "((", "")
+ t = replacetext(t, "))", "")
+
+ // Parse headers
+
+ t = replacetext(t, regex("^#(?!#) ?(.+)$", "gm"), "
$1
")
+ t = replacetext(t, regex("^##(?!#) ?(.+)$", "gm"), "
$1
")
+ t = replacetext(t, regex("^###(?!#) ?(.+)$", "gm"), "
$1
")
+ t = replacetext(t, regex("^#### ?(.+)$", "gm"), "
$1
")
+
+ // Parse most rules
+
+ t = replacetext(t, regex("\\*(\[^\\*\]*)\\*", "g"), "$1")
+ t = replacetext(t, regex("_(\[^_\]*)_", "g"), "$1")
+ t = replacetext(t, "", "!")
+ t = replacetext(t, "", "!")
+ t = replacetext(t, regex("\\!(\[^\\!\]+)\\!", "g"), "$1")
+ t = replacetext(t, regex("\\^(\[^\\^\]+)\\^", "g"), "$1")
+ t = replacetext(t, regex("\\|(\[^\\|\]+)\\|", "g"), "
$1
")
+ t = replacetext(t, "!", "")
+
+ return t
+
+/proc/parsemarkdown_basic_step2(t)
+ if(length(t) <= 0)
+ return
+
+ // Restore the single characters used
+
+ t = replacetext(t, "$a", "!")
+
+ // Redo the escaping
+
+ t = replacetext(t, "$1", "\\")
+ t = replacetext(t, "$2", "**")
+ t = replacetext(t, "$3", "*")
+ t = replacetext(t, "$4", "__")
+ t = replacetext(t, "$5", "_")
+ t = replacetext(t, "$6", "^")
+ t = replacetext(t, "$7", "((")
+ t = replacetext(t, "$8", "))")
+ t = replacetext(t, "$9", "|")
+ t = replacetext(t, "$0", "%")
+ t = replacetext(t, "$-", "$")
+
+ return t
+
+/proc/parsemarkdown_basic(t, limited=FALSE)
+ t = parsemarkdown_basic_step1(t, limited)
+ t = parsemarkdown_basic_step2(t)
+ return t
+
+/proc/parsemarkdown(t, mob/user=null, limited=FALSE)
+ if(length(t) <= 0)
+ return
+
+ // Premanage whitespace
+
+ t = replacetext(t, regex("\[^\\S\\r\\n \]", "g"), " ")
+
+ t = parsemarkdown_basic_step1(t)
+
+ t = replacetext(t, regex("%s(?:ign)?(?=\\s|$)", "igm"), user ? "[user.real_name]" : "")
+ t = replacetext(t, regex("%f(?:ield)?(?=\\s|$)", "igm"), "")
+
+ t = parsemarkdown_basic_step2(t)
+
+ // Manage whitespace
+
+ t = replacetext(t, regex("(?:\\r\\n?|\\n)", "g"), " ")
+
+ t = replacetext(t, " ", " ")
+
+ // Done
return t
diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm
index 546935e697..e3ce12397e 100644
--- a/code/__HELPERS/time.dm
+++ b/code/__HELPERS/time.dm
@@ -1,52 +1,148 @@
-//Returns the world time in english
-/proc/worldtime2text()
- return gameTimestamp("hh:mm:ss", world.time)
-
-/proc/time_stamp(format = "hh:mm:ss", show_ds)
- var/time_string = time2text(world.timeofday, format)
- return show_ds ? "[time_string]:[world.timeofday % 10]" : time_string
-
-/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
- if(!wtime)
- wtime = world.time
- return time2text(wtime - GLOB.timezoneOffset + SSticker.gametime_offset - SSticker.round_start_time, format)
-
-/* Returns 1 if it is the selected month and day */
-/proc/isDay(month, day)
- if(isnum(month) && isnum(day))
- var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
- var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
- if(month == MM && day == DD)
- return 1
-
- // Uncomment this out when debugging!
- //else
- //return 1
-
-//returns timestamp in a sql and ISO 8601 friendly format
-/proc/SQLtime(timevar)
- if(!timevar)
- timevar = world.realtime
- return time2text(timevar, "YYYY-MM-DD hh:mm:ss")
-
-
-GLOBAL_VAR_INIT(midnight_rollovers, 0)
-GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
-/proc/update_midnight_rollover()
- if (world.timeofday < GLOB.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS!
- return GLOB.midnight_rollovers++
- return GLOB.midnight_rollovers
-
-/proc/weekdayofthemonth()
- var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
- switch(DD)
- if(8 to 13)
- return 2
- if(14 to 20)
- return 3
- if(21 to 27)
- return 4
- if(28 to INFINITY)
- return 5
- else
- return 1
+//Returns the world time in english
+/proc/worldtime2text()
+ return gameTimestamp("hh:mm:ss", world.time)
+
+/proc/time_stamp(format = "hh:mm:ss", show_ds)
+ var/time_string = time2text(world.timeofday, format)
+ return show_ds ? "[time_string]:[world.timeofday % 10]" : time_string
+
+/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
+ if(!wtime)
+ wtime = world.time
+ return time2text(wtime - GLOB.timezoneOffset + SSticker.gametime_offset - SSticker.round_start_time, format)
+
+/* Returns 1 if it is the selected month and day */
+/proc/isDay(month, day)
+ if(isnum(month) && isnum(day))
+ var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
+ var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
+ if(month == MM && day == DD)
+ return 1
+
+ // Uncomment this out when debugging!
+ //else
+ //return 1
+
+//returns timestamp in a sql and ISO 8601 friendly format
+/proc/SQLtime(timevar)
+ if(!timevar)
+ timevar = world.realtime
+ return time2text(timevar, "YYYY-MM-DD hh:mm:ss")
+
+
+GLOBAL_VAR_INIT(midnight_rollovers, 0)
+GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
+/proc/update_midnight_rollover()
+ if (world.timeofday < GLOB.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS!
+ return GLOB.midnight_rollovers++
+ return GLOB.midnight_rollovers
+
+/proc/weekdayofthemonth()
+ var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
+ switch(DD)
+ if(8 to 13)
+ return 2
+ if(14 to 20)
+ return 3
+ if(21 to 27)
+ return 4
+ if(28 to INFINITY)
+ return 5
+ else
+ return 1
+
+//Takes a value of time in deciseconds.
+//Returns a text value of that number in hours, minutes, or seconds.
+/proc/DisplayTimeText(time_value)
+ var/second = time_value*0.1
+ var/second_adjusted = null
+ var/second_rounded = FALSE
+ var/minute = null
+ var/hour = null
+ var/day = null
+
+ if(!second)
+ return "0 seconds"
+ if(second >= 60)
+ minute = round_down(second/60)
+ second = round(second - (minute*60), 0.1)
+ second_rounded = TRUE
+ if(second) //check if we still have seconds remaining to format, or if everything went into minute.
+ second_adjusted = round(second) //used to prevent '1 seconds' being shown
+ if(day || hour || minute)
+ if(second_adjusted == 1 && second >= 1)
+ second = " and 1 second"
+ else if(second > 1)
+ second = " and [second_adjusted] seconds"
+ else //shows a fraction if seconds is < 1
+ if(second_rounded) //no sense rounding again if it's already done
+ second = " and [second] seconds"
+ else
+ second = " and [round(second, 0.1)] seconds"
+ else
+ if(second_adjusted == 1 && second >= 1)
+ second = "1 second"
+ else if(second > 1)
+ second = "[second_adjusted] seconds"
+ else
+ if(second_rounded)
+ second = "[second] seconds"
+ else
+ second = "[round(second, 0.1)] seconds"
+ else
+ second = null
+
+ if(!minute)
+ return "[second]"
+ if(minute >= 60)
+ hour = round_down(minute/60,1)
+ minute = (minute - (hour*60))
+ if(minute) //alot simpler from here since you don't have to worry about fractions
+ if(minute != 1)
+ if((day || hour) && second)
+ minute = ", [minute] minutes"
+ else if((day || hour) && !second)
+ minute = " and [minute] minutes"
+ else
+ minute = "[minute] minutes"
+ else
+ if((day || hour) && second)
+ minute = ", 1 minute"
+ else if((day || hour) && !second)
+ minute = " and 1 minute"
+ else
+ minute = "1 minute"
+ else
+ minute = null
+
+ if(!hour)
+ return "[minute][second]"
+ if(hour >= 24)
+ day = round_down(hour/24,1)
+ hour = (hour - (day*24))
+ if(hour)
+ if(hour != 1)
+ if(day && (minute || second))
+ hour = ", [hour] hours"
+ else if(day && (!minute || !second))
+ hour = " and [hour] hours"
+ else
+ hour = "[hour] hours"
+ else
+ if(day && (minute || second))
+ hour = ", 1 hour"
+ else if(day && (!minute || !second))
+ hour = " and 1 hour"
+ else
+ hour = "1 hour"
+ else
+ hour = null
+
+ if(!day)
+ return "[hour][minute][second]"
+ if(day > 1)
+ day = "[day] days"
+ else
+ day = "1 day"
+
+ return "[day][hour][minute][second]"
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index a20cad1cf2..c2398982c2 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -502,28 +502,12 @@ Turf and target are separate in case you want to teleport some distance from a t
var/y=arcsin(x/sqrt(1+x*x))
return y
-/atom/proc/GetAllContents(list/ignore_typecache)
- var/list/processing_list = list(src)
- var/list/assembled = list()
- if(ignore_typecache) //If there's a typecache, use it.
- while(processing_list.len)
- var/atom/A = processing_list[1]
- processing_list -= A
- if(ignore_typecache[A.type])
- continue
- processing_list |= (A.contents - assembled)
- assembled |= A
-
- else //If there's none, only make this check once for performance.
- while(processing_list.len)
- var/atom/A = processing_list[1]
- processing_list -= A
-
- processing_list |= (A.contents - assembled)
-
- assembled |= A
-
- return assembled
+/atom/proc/GetAllContents(list/output=list())
+ . = output
+ output += src
+ for(var/i in 1 to contents.len)
+ var/atom/thing = contents[i]
+ thing.GetAllContents(output)
//Step-towards method of determining whether one atom can see another. Similar to viewers()
/proc/can_see(atom/source, atom/target, length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate.
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index ccab4a645b..829a55150f 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -33,7 +33,7 @@
#define MAX_CHARTER_LEN 80
//MINOR TWEAKS/MISC
-#define AGE_MIN 17 //youngest a character can be
+#define AGE_MIN 18 //youngest a character can be
#define AGE_MAX 85 //oldest a character can be
#define WIZARD_AGE_MIN 30 //youngest a wizard can be
#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up
diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm
index 74e8f230ba..03824c4c83 100644
--- a/code/_globalvars/lists/mapping.dm
+++ b/code/_globalvars/lists/mapping.dm
@@ -33,6 +33,8 @@ GLOBAL_LIST_EMPTY(department_security_spawns) //list of all department security
GLOBAL_LIST_EMPTY(generic_event_spawns) //list of all spawns for events
GLOBAL_LIST_EMPTY(wizardstart)
+GLOBAL_LIST_EMPTY(nukeop_start)
+GLOBAL_LIST_EMPTY(nukeop_leader_start)
GLOBAL_LIST_EMPTY(newplayer_start)
GLOBAL_LIST_EMPTY(prisonwarp) //prisoners go to these
GLOBAL_LIST_EMPTY(holdingfacility) //captured people go here
diff --git a/code/citadel/cit_guns.dm b/code/citadel/cit_guns.dm
index efab785d12..e62884ecbc 100644
--- a/code/citadel/cit_guns.dm
+++ b/code/citadel/cit_guns.dm
@@ -172,6 +172,27 @@
spread = 30 //should be 40 for XCOM memes, but since its adminspawn only, might as well make it useable
recoil = 1
+///toy memes///
+
+/obj/item/ammo_box/magazine/toy/x9
+ name = "foam force X9 magazine"
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "toy9magazine"
+ max_ammo = 30
+ multiple_sprites = 2
+
+/obj/item/gun/ballistic/automatic/x9/toy
+ name = "donksoft X9"
+ desc = "An old but reliable assault rifle made for combat against unknown enemies. Appears to be hastily converted. Ages 8 and up."
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "toy9"
+ can_suppress = 0
+ needs_permit = 0
+ mag_type = /obj/item/ammo_box/magazine/toy/x9
+ casing_ejector = 0
+ spread = 45 //MAXIMUM XCOM MEMES (actually that'd be 90 spread)
+
+
////////XCOM2 Magpistol/////////
//////projectiles//////
@@ -213,7 +234,7 @@
//////magazines/////
-/obj/item/ammo_box/magazine/mmags
+/obj/item/ammo_box/magazine/mmag/small
name = "magpistol magazine (non-lethal disabler)"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "nlmagmag"
@@ -223,7 +244,7 @@
max_ammo = 7
multiple_sprites = 2
-/obj/item/ammo_box/magazine/mmags/lethal
+/obj/item/ammo_box/magazine/mmag/small/lethal
name = "magpistol magazine (lethal)"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "smallmagmag"
@@ -239,7 +260,7 @@
icon_state = "magpistol"
force = 10
fire_sound = 'sound/weapons/magpistol.ogg'
- mag_type = /obj/item/ammo_box/magazine/mmags
+ mag_type = /obj/item/ammo_box/magazine/mmag/small
can_suppress = 0
casing_ejector = 0
fire_delay = 5
@@ -276,7 +297,7 @@
req_tech = list("combat" = 5, "magnets" = 6, "materials" = 5, "syndicate" = 3)
build_type = PROTOLATHE
materials = list(MAT_METAL = 4000, MAT_SILVER = 500)
- build_path = /obj/item/ammo_box/magazine/mmags/lethal
+ build_path = /obj/item/ammo_box/magazine/mmag/small/lethal
category = list("Ammo")
/datum/design/mag_magpistol/nl
@@ -285,7 +306,7 @@
id = "mag_magpistol_nl"
req_tech = list("combat" = 5, "magnets" = 6, "materials" = 5)
materials = list(MAT_METAL = 3000, MAT_SILVER = 250, MAT_TITANIUM = 250)
- build_path = /obj/item/ammo_box/magazine/mmags
+ build_path = /obj/item/ammo_box/magazine/mmag/small
//////toy memes/////
@@ -339,3 +360,412 @@
materials = list(MAT_METAL = 7500, MAT_GLASS = 1000)
build_path = /obj/item/gun/ballistic/shotgun/toy/mag
category = list("hacked", "Misc")
+
+//////Magrifle//////
+
+///projectiles///
+
+/obj/item/projectile/bullet/magrifle
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "magjectile-large"
+ damage = 30
+ armour_penetration = 25
+ light_range = 3
+ light_color = LIGHT_COLOR_RED
+
+/obj/item/projectile/bullet/nlmagrifle //non-lethal boolets
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "magjectile-large-nl"
+ damage = 5
+ knockdown = 30
+ stamina = 75
+ armour_penetration = 0
+ light_range = 3
+ light_color = LIGHT_COLOR_BLUE
+
+///ammo casings///
+
+/obj/item/ammo_casing/caseless/amagm
+ desc = "A large ferromagnetic slug intended to be launched out of a compatible weapon."
+ caliber = "magm"
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "mag-casing-live"
+ projectile_type = /obj/item/projectile/bullet/magrifle
+
+/obj/item/ammo_casing/caseless/anlmagm
+ desc = "A large, specialized ferromagnetic slug designed with a less-than-lethal payload."
+ caliber = "magm"
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "mag-casing-live"
+ projectile_type = /obj/item/projectile/bullet/nlmagrifle
+
+///magazines///
+
+/obj/item/ammo_box/magazine/mmag/
+ name = "magrifle magazine (non-lethal disabler)"
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "mediummagmag"
+ origin_tech = "magnets=6"
+ ammo_type = /obj/item/ammo_casing/caseless/anlmagm
+ caliber = "magm"
+ max_ammo = 15
+ multiple_sprites = 2
+
+/obj/item/ammo_box/magazine/mmag/lethal
+ name = "magrifle magazine (lethal)"
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "mediummagmag"
+ origin_tech = "combat=6"
+ ammo_type = /obj/item/ammo_casing/caseless/amagm
+
+///the gun itself///
+
+/obj/item/gun/ballistic/automatic/magrifle
+ name = "\improper Magnetic Rifle"
+ desc = "A simple upscalling of the technologies used in the magpistol, the magrifle is capable of firing slightly larger slugs in bursts. Compatible with the magpistol's slugs."
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "magrifle"
+ item_state = "arg"
+ slot_flags = 0
+ origin_tech = "combat=6;engineering=6;magnets=6"
+ mag_type = /obj/item/ammo_box/magazine/mmag
+ fire_sound = 'sound/weapons/magrifle.ogg'
+ can_suppress = 0
+ burst_size = 3
+ fire_delay = 2
+ spread = 15
+ recoil = 1
+ casing_ejector = 0
+
+///research///
+
+/obj/item/gun/ballistic/automatic/magrifle/nopin
+ pin = null
+
+/datum/design/magrifle
+ name = "Magrifle"
+ desc = "An upscaled Magpistol in rifle form."
+ id = "magrifle"
+ req_tech = list("combat" = 7, "magnets" = 7, "powerstorage" = 7)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 10000, MAT_GLASS = 2000, MAT_URANIUM = 2000, MAT_TITANIUM = 10000, MAT_SILVER = 4000, MAT_GOLD = 2000)
+ build_path = /obj/item/gun/ballistic/automatic/magrifle/nopin
+ category = list("Weapons")
+
+/datum/design/mag_magrifle
+ name = "Magrifle Magazine (Lethal)"
+ desc = "A 15 round magazine for the Magrifle."
+ id = "mag_magrifle"
+ req_tech = list("combat" = 7, "magnets" = 7, "materials" = 5, "syndicate" = 4)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 8000, MAT_SILVER = 1000)
+ build_path = /obj/item/ammo_box/magazine/mmag/lethal
+ category = list("Ammo")
+
+/datum/design/mag_magrifle/nl
+ name = "Magrifle Magazine (Non-Lethal)"
+ desc = "A 15 round non-lethal magazine for the Magrifle."
+ id = "mag_magrifle_nl"
+ req_tech = list("combat" = 7, "magnets" = 7, "materials" = 5)
+ materials = list(MAT_METAL = 6000, MAT_SILVER = 500, MAT_TITANIUM = 500)
+ build_path = /obj/item/ammo_box/magazine/mmag
+
+//////Hyper-Burst Rifle//////
+
+///projectiles///
+
+/obj/item/projectile/bullet/mags/hyper
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "magjectile"
+ damage = 10
+ armour_penetration = 10
+ stamina = 10
+ forcedodge = TRUE
+ range = 6
+ light_range = 1
+ light_color = LIGHT_COLOR_RED
+
+/obj/item/projectile/bullet/mags/hyper/inferno
+ icon_state = "magjectile-large"
+ stamina = 0
+ forcedodge = FALSE
+ range = 25
+ light_range = 4
+
+/obj/item/projectile/bullet/mags/hyper/inferno/on_hit(atom/target, blocked = FALSE)
+ ..()
+ explosion(target, -1, 1, 2, 4, 5)
+ return 1
+
+///ammo casings///
+
+/obj/item/ammo_casing/caseless/ahyper
+ desc = "A large block of speciallized ferromagnetic material designed to be fired out of the experimental Hyper-Burst Rifle."
+ caliber = "hypermag"
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "hyper-casing-live"
+ projectile_type = /obj/item/projectile/bullet/mags/hyper
+ pellets = 12
+ variance = 40
+
+/obj/item/ammo_casing/caseless/ahyper/inferno
+ projectile_type = /obj/item/projectile/bullet/mags/hyper/inferno
+ pellets = 1
+ variance = 0
+
+///magazines///
+
+/obj/item/ammo_box/magazine/mhyper
+ name = "hyper-burst rifle magazine"
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "hypermag-4"
+ ammo_type = /obj/item/ammo_casing/caseless/ahyper
+ caliber = "hypermag"
+ desc = "A magazine for the Hyper-Burst Rifle. Loaded with a special slug that fragments into 12 smaller shards which can absolutely puncture anything, but has rather short effective range."
+ max_ammo = 4
+
+/obj/item/ammo_box/magazine/mhyper/update_icon()
+ ..()
+ icon_state = "hypermag-[ammo_count() ? "4" : "0"]"
+
+/obj/item/ammo_box/magazine/mhyper/inferno
+ name = "hyper-burst rifle magazine (inferno)"
+ ammo_type = /obj/item/ammo_casing/caseless/ahyper/inferno
+ desc = "A magazine for the Hyper-Burst Rifle. Loaded with a special slug that violently reacts with whatever surface it strikes, generating a massive amount of heat and light."
+
+///gun itself///
+
+/obj/item/gun/ballistic/automatic/hyperburst
+ name = "\improper Hyper-Burst Rifle"
+ desc = "An extremely beefed up version of a stolen Nanotrasen weapon prototype, this 'rifle' is more like a cannon, with an extremely large bore barrel capable of generating several smaller magnetic 'barrels' to simultaneously launch multiple projectiles at once."
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "hyperburst"
+ item_state = "arg"
+ slot_flags = 0
+ origin_tech = "combat=6;engineering=6;magnets=6;syndicate=6"
+ mag_type = /obj/item/ammo_box/magazine/mhyper
+ fire_sound = 'sound/weapons/magburst.ogg'
+ can_suppress = 0
+ burst_size = 1
+ fire_delay = 40
+ recoil = 2
+ casing_ejector = 0
+ weapon_weight = WEAPON_HEAVY
+
+/obj/item/gun/ballistic/automatic/hyperburst/update_icon()
+ ..()
+ icon_state = "hyperburst[magazine ? "-[get_ammo()]" : ""][chambered ? "" : "-e"]"
+
+/* made redundant by reskinnable stetchkins
+//////Stealth Pistol//////
+
+/obj/item/gun/ballistic/automatic/pistol/stealth
+ name = "stealth pistol"
+ desc = "A unique bullpup pistol with a compact frame. Has an integrated surpressor."
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "stealthpistol"
+ w_class = WEIGHT_CLASS_SMALL
+ origin_tech = "combat=3;materials=3;syndicate=4"
+ mag_type = /obj/item/ammo_box/magazine/m10mm
+ can_suppress = 0
+ fire_sound = 'sound/weapons/gunshot_silenced.ogg'
+ suppressed = 1
+ burst_size = 1
+
+/obj/item/gun/ballistic/automatic/pistol/stealth/update_icon()
+ ..()
+ if(magazine)
+ cut_overlays()
+ add_overlay("stealthpistol-magazine")
+ else
+ cut_overlays()
+ icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
+
+*/
+
+//////10mm soporific bullets//////
+
+obj/item/projectile/bullet/c10mm/soporific
+ name ="10mm soporific bullet"
+ armour_penetration = 0
+ nodamage = TRUE
+ dismemberment = 0
+ knockdown = 0
+
+/obj/item/projectile/bullet/c10mm/soporific/on_hit(atom/target, blocked = FALSE)
+ if((blocked != 100) && isliving(target))
+ var/mob/living/L = target
+ L.blur_eyes(6)
+ if(L.staminaloss >= 40)
+ L.Sleeping(250)
+ else
+ L.adjustStaminaLoss(58)
+ return 1
+
+/obj/item/ammo_casing/c10mm/soporific
+ name = ".10mm soporific bullet casing"
+ desc = "A 10mm soporific bullet casing."
+ projectile_type = /obj/item/projectile/bullet/c10mm/soporific
+
+/obj/item/ammo_box/magazine/m10mm/soporific
+ name = "pistol magazine (10mm soporific)"
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "9x19pS"
+ desc = "A gun magazine. Loaded with rounds which inject the target with a variety of illegal substances to induce sleep in the target."
+ ammo_type = /obj/item/ammo_casing/c10mm/soporific
+
+/obj/item/ammo_box/c10mm/soporific
+ name = "ammo box (10mm soporific)"
+ ammo_type = /obj/item/ammo_casing/c10mm/soporific
+ max_ammo = 24
+
+//////Flechette Launcher//////
+
+///projectiles///
+
+/obj/item/projectile/bullet/cflechetteap //shreds armor
+ name = "flechette (armor piercing)"
+ damage = 8
+ armour_penetration = 80
+
+/obj/item/projectile/bullet/cflechettes //shreds flesh and forces bleeding
+ name = "flechette (serrated)"
+ damage = 8
+ dismemberment = 10
+ armour_penetration = -80
+
+/obj/item/projectile/bullet/cflechettes/on_hit(atom/target, blocked = FALSE)
+ if((blocked != 100) && iscarbon(target))
+ var/mob/living/carbon/C = target
+ C.bleed(10)
+ return ..()
+
+///ammo casings (CASELESS AMMO CASINGS WOOOOOOOO)///
+
+/obj/item/ammo_casing/caseless/flechetteap
+ name = "flechette (armor piercing)"
+ desc = "A flechette made with a tungsten alloy."
+ projectile_type = /obj/item/projectile/bullet/cflechetteap
+ caliber = "flechette"
+ throwforce = 1
+ throw_speed = 3
+
+/obj/item/ammo_casing/caseless/flechettes
+ name = "flechette (serrated)"
+ desc = "A serrated flechette made of a special alloy intended to deform drastically upon penetration of human flesh."
+ projectile_type = /obj/item/projectile/bullet/cflechettes
+ caliber = "flechette"
+ throwforce = 2
+ throw_speed = 3
+ embed_chance = 75
+
+///magazine///
+
+/obj/item/ammo_box/magazine/flechette
+ name = "flechette magazine (armor piercing)"
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "flechettemag"
+ origin_tech = "combat=5;syndicate=1"
+ ammo_type = /obj/item/ammo_casing/caseless/flechetteap
+ caliber = "flechette"
+ max_ammo = 40
+ multiple_sprites = 2
+
+/obj/item/ammo_box/magazine/flechette/s
+ name = "flechette magazine (serrated)"
+ ammo_type = /obj/item/ammo_casing/caseless/flechettes
+
+///the gun itself///
+
+/obj/item/gun/ballistic/automatic/flechette
+ name = "\improper CX Flechette Launcher"
+ desc = "A flechette launching machine pistol with an unconventional bullpup frame."
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "flechettegun"
+ item_state = "gun"
+ w_class = WEIGHT_CLASS_NORMAL
+ slot_flags = 0
+ /obj/item/device/firing_pin/implant/pindicate
+ origin_tech = "combat=6;materials=2;syndicate=5"
+ mag_type = /obj/item/ammo_box/magazine/flechette/
+ fire_sound = 'sound/weapons/gunshot_smg.ogg'
+ can_suppress = 0
+ burst_size = 5
+ fire_delay = 1
+ casing_ejector = 0
+ spread = 20
+
+/obj/item/gun/ballistic/automatic/flechette/update_icon()
+ ..()
+ if(magazine)
+ cut_overlays()
+ add_overlay("flechettegun-magazine")
+ else
+ cut_overlays()
+ icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
+
+///unique variant///
+
+/obj/item/projectile/bullet/cflechetteshredder
+ name = "flechette (shredder)"
+ damage = 5
+ dismemberment = 40
+
+/obj/item/ammo_casing/caseless/flechetteshredder
+ name = "flechette (shredder)"
+ desc = "A serrated flechette made of a special alloy that forms a monofilament edge."
+ projectile_type = /obj/item/projectile/bullet/cflechettes
+
+/obj/item/ammo_box/magazine/flechette/shredder
+ name = "flechette magazine (shredder)"
+ icon_state = "shreddermag"
+ ammo_type = /obj/item/ammo_casing/caseless/flechetteshredder
+
+/obj/item/gun/ballistic/automatic/flechette/shredder
+ name = "\improper CX Shredder"
+ desc = "A flechette launching machine pistol made of ultra-light CFRP optimized for firing serrated monofillament flechettes."
+ w_class = WEIGHT_CLASS_SMALL
+ mag_type = /obj/item/ammo_box/magazine/flechette/shredder
+ spread = 30
+
+/obj/item/gun/ballistic/automatic/flechette/shredder/update_icon()
+ ..()
+ if(magazine)
+ cut_overlays()
+ add_overlay("shreddergun-magazine")
+ else
+ cut_overlays()
+ icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
+
+//////modular pistol////// (reskinnable stetchkins)
+
+/obj/item/gun/ballistic/automatic/pistol/modular
+ name = "modular pistol"
+ desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors."
+ icon = 'icons/obj/guns/cit_guns.dmi'
+ icon_state = "cde"
+ can_unsuppress = TRUE
+ unique_rename = TRUE
+ unique_reskin = list("Default" = "cde",
+ "NT-99" = "n99",
+ "Stealth" = "stealthpistol",
+ "HKVP-78" = "vp78",
+ "Luger" = "p08b",
+ "Mk.58" = "secguncomp",
+ "PX4 Storm" = "px4"
+ )
+
+/obj/item/gun/ballistic/automatic/pistol/modular/update_icon()
+ ..()
+ if(current_skin)
+ icon_state = "[unique_reskin[current_skin]][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
+ else
+ icon_state = "[initial(icon_state)][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
+ if(magazine && suppressed)
+ cut_overlays()
+ add_overlay("[unique_reskin[current_skin]]-magazine-sup") //Yes, this means the default iconstate can't have a magazine overlay
+ else if (magazine)
+ cut_overlays()
+ add_overlay("[unique_reskin[current_skin]]-magazine")
+ else
+ cut_overlays()
\ No newline at end of file
diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm
new file mode 100644
index 0000000000..b439743a79
--- /dev/null
+++ b/code/controllers/configuration/config_entry.dm
@@ -0,0 +1,198 @@
+#undef CURRENT_RESIDENT_FILE
+
+#define LIST_MODE_NUM 0
+#define LIST_MODE_TEXT 1
+#define LIST_MODE_FLAG 2
+
+/datum/config_entry
+ var/name //read-only, this is determined by the last portion of the derived entry type
+ var/value
+ var/default //read-only, just set value directly
+
+ var/resident_file //the file which this belongs to, must be set
+ var/modified = FALSE //set to TRUE if the default has been overridden by a config entry
+
+ var/protection = NONE
+ var/abstract_type = /datum/config_entry //do not instantiate if type matches this
+
+ var/dupes_allowed = FALSE
+
+/datum/config_entry/New()
+ if(!resident_file)
+ CRASH("Config entry [type] has no resident_file set")
+ if(type == abstract_type)
+ CRASH("Abstract config entry [type] instatiated!")
+ name = lowertext(type2top(type))
+ if(islist(value))
+ var/list/L = value
+ default = L.Copy()
+ else
+ default = value
+
+/datum/config_entry/Destroy()
+ config.RemoveEntry(src)
+ return ..()
+
+/datum/config_entry/can_vv_get(var_name)
+ . = ..()
+ if(var_name == "value" || var_name == "default")
+ . &= !(protection & CONFIG_ENTRY_HIDDEN)
+
+/datum/config_entry/vv_edit_var(var_name, var_value)
+ var/static/list/banned_edits = list("name", "default", "resident_file", "protection", "abstract_type", "modified", "dupes_allowed")
+ if(var_name == "value")
+ if(protection & CONFIG_ENTRY_LOCKED)
+ return FALSE
+ . = ValidateAndSet("[var_value]")
+ if(.)
+ var_edited = TRUE
+ return
+ if(var_name in banned_edits)
+ return FALSE
+ return ..()
+
+/datum/config_entry/proc/VASProcCallGuard(str_val)
+ . = !(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "ValidateAndSet" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
+ if(!.)
+ log_admin_private("Config set of [type] to [str_val] attempted by [key_name(usr)]")
+
+/datum/config_entry/proc/ValidateAndSet(str_val)
+ VASProcCallGuard(str_val)
+ CRASH("Invalid config entry type!")
+
+/datum/config_entry/proc/ValidateKeyedList(str_val, list_mode, splitter)
+ str_val = trim(str_val)
+ var/key_pos = findtext(str_val, splitter)
+ var/key_name = null
+ var/key_value = null
+
+ if(key_pos || list_mode == LIST_MODE_FLAG)
+ key_name = lowertext(copytext(str_val, 1, key_pos))
+ key_value = copytext(str_val, key_pos + 1)
+ var/temp
+ var/continue_check
+ switch(list_mode)
+ if(LIST_MODE_FLAG)
+ temp = TRUE
+ continue_check = TRUE
+ if(LIST_MODE_NUM)
+ temp = text2num(key_value)
+ continue_check = !isnull(temp)
+ if(LIST_MODE_TEXT)
+ temp = key_value
+ continue_check = temp
+ if(continue_check && ValidateKeyName(key_name))
+ value[key_name] = temp
+ return TRUE
+ return FALSE
+
+/datum/config_entry/proc/ValidateKeyName(key_name)
+ return TRUE
+
+/datum/config_entry/string
+ value = ""
+ abstract_type = /datum/config_entry/string
+ var/auto_trim = TRUE
+
+/datum/config_entry/string/vv_edit_var(var_name, var_value)
+ return var_name != "auto_trim" && ..()
+
+/datum/config_entry/string/ValidateAndSet(str_val)
+ if(!VASProcCallGuard(str_val))
+ return FALSE
+ value = auto_trim ? trim(str_val) : str_val
+ return TRUE
+
+/datum/config_entry/number
+ value = 0
+ abstract_type = /datum/config_entry/number
+ var/integer = TRUE
+ var/max_val = INFINITY
+ var/min_val = -INFINITY
+
+/datum/config_entry/number/ValidateAndSet(str_val)
+ if(!VASProcCallGuard(str_val))
+ return FALSE
+ var/temp = text2num(trim(str_val))
+ if(!isnull(temp))
+ value = Clamp(integer ? round(temp) : temp, min_val, max_val)
+ if(value != temp && !var_edited)
+ log_config("Changing [name] from [temp] to [value]!")
+ return TRUE
+ return FALSE
+
+/datum/config_entry/number/vv_edit_var(var_name, var_value)
+ var/static/list/banned_edits = list("max_val", "min_val", "integer")
+ return !(var_name in banned_edits) && ..()
+
+/datum/config_entry/flag
+ value = FALSE
+ abstract_type = /datum/config_entry/flag
+
+/datum/config_entry/flag/ValidateAndSet(str_val)
+ if(!VASProcCallGuard(str_val))
+ return FALSE
+ value = text2num(trim(str_val)) != 0
+ return TRUE
+
+/datum/config_entry/number_list
+ abstract_type = /datum/config_entry/number_list
+ value = list()
+
+/datum/config_entry/number_list/ValidateAndSet(str_val)
+ if(!VASProcCallGuard(str_val))
+ return FALSE
+ str_val = trim(str_val)
+ var/list/new_list = list()
+ var/list/values = splittext(str_val," ")
+ for(var/I in values)
+ var/temp = text2num(I)
+ if(isnull(temp))
+ return FALSE
+ new_list += temp
+ if(!new_list.len)
+ return FALSE
+ value = new_list
+ return TRUE
+
+/datum/config_entry/keyed_flag_list
+ abstract_type = /datum/config_entry/keyed_flag_list
+ value = list()
+ dupes_allowed = TRUE
+
+/datum/config_entry/keyed_flag_list/ValidateAndSet(str_val)
+ if(!VASProcCallGuard(str_val))
+ return FALSE
+ return ValidateKeyedList(str_val, LIST_MODE_FLAG, " ")
+
+/datum/config_entry/keyed_number_list
+ abstract_type = /datum/config_entry/keyed_number_list
+ value = list()
+ dupes_allowed = TRUE
+ var/splitter = " "
+
+/datum/config_entry/keyed_number_list/vv_edit_var(var_name, var_value)
+ return var_name != "splitter" && ..()
+
+/datum/config_entry/keyed_number_list/ValidateAndSet(str_val)
+ if(!VASProcCallGuard(str_val))
+ return FALSE
+ return ValidateKeyedList(str_val, LIST_MODE_NUM, splitter)
+
+/datum/config_entry/keyed_string_list
+ abstract_type = /datum/config_entry/keyed_string_list
+ value = list()
+ dupes_allowed = TRUE
+ var/splitter = " "
+
+/datum/config_entry/keyed_string_list/vv_edit_var(var_name, var_value)
+ return var_name != "splitter" && ..()
+
+/datum/config_entry/keyed_string_list/ValidateAndSet(str_val)
+ if(!VASProcCallGuard(str_val))
+ return FALSE
+ return ValidateKeyedList(str_val, LIST_MODE_TEXT, splitter)
+
+#undef LIST_MODE_NUM
+#undef LIST_MODE_TEXT
+#undef LIST_MODE_FLAG
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
new file mode 100644
index 0000000000..8df012e5de
--- /dev/null
+++ b/code/controllers/configuration/configuration.dm
@@ -0,0 +1,287 @@
+GLOBAL_VAR_INIT(config_dir, "config/")
+GLOBAL_PROTECT(config_dir)
+
+/datum/controller/configuration
+ name = "Configuration"
+
+ var/hiding_entries_by_type = TRUE //Set for readability, admins can set this to FALSE if they want to debug it
+ var/list/entries
+ var/list/entries_by_type
+
+ var/list/maplist
+ var/datum/map_config/defaultmap
+
+ var/list/modes // allowed modes
+ var/list/gamemode_cache
+ var/list/votable_modes // votable modes
+ var/list/mode_names
+ var/list/mode_reports
+ var/list/mode_false_report_weight
+
+/datum/controller/configuration/New()
+ config = src
+ var/list/config_files = InitEntries()
+ LoadModes()
+ for(var/I in config_files)
+ LoadEntries(I)
+ if(Get(/datum/config_entry/flag/maprotation))
+ loadmaplist(CONFIG_MAPS_FILE)
+
+/datum/controller/configuration/Destroy()
+ entries_by_type.Cut()
+ QDEL_LIST_ASSOC_VAL(entries)
+ QDEL_LIST_ASSOC_VAL(maplist)
+ QDEL_NULL(defaultmap)
+
+ config = null
+
+ return ..()
+
+/datum/controller/configuration/proc/InitEntries()
+ var/list/_entries = list()
+ entries = _entries
+ var/list/_entries_by_type = list()
+ entries_by_type = _entries_by_type
+
+ . = list()
+
+ for(var/I in typesof(/datum/config_entry)) //typesof is faster in this case
+ var/datum/config_entry/E = I
+ if(initial(E.abstract_type) == I)
+ continue
+ E = new I
+ _entries_by_type[I] = E
+ var/esname = E.name
+ var/datum/config_entry/test = _entries[esname]
+ if(test)
+ log_config("Error: [test.type] has the same name as [E.type]: [esname]! Not initializing [E.type]!")
+ qdel(E)
+ continue
+ _entries[esname] = E
+ .[E.resident_file] = TRUE
+
+/datum/controller/configuration/proc/RemoveEntry(datum/config_entry/CE)
+ entries -= CE.name
+ entries_by_type -= CE.type
+
+/datum/controller/configuration/proc/LoadEntries(filename)
+ log_config("Loading config file [filename]...")
+ var/list/lines = world.file2list("[GLOB.config_dir][filename]")
+ var/list/_entries = entries
+ for(var/L in lines)
+ if(!L)
+ continue
+
+ if(copytext(L, 1, 2) == "#")
+ continue
+
+ var/pos = findtext(L, " ")
+ var/entry = null
+ var/value = null
+
+ if(pos)
+ entry = lowertext(copytext(L, 1, pos))
+ value = copytext(L, pos + 1)
+ else
+ entry = lowertext(L)
+
+ if(!entry)
+ continue
+
+ var/datum/config_entry/E = _entries[entry]
+ if(!E)
+ log_config("Unknown setting in configuration: '[entry]'")
+ continue
+
+ if(filename != E.resident_file)
+ log_config("Found [entry] in [filename] when it should have been in [E.resident_file]! Ignoring.")
+ continue
+
+ var/validated = E.ValidateAndSet(value)
+ if(!validated)
+ log_config("Failed to validate setting \"[value]\" for [entry]")
+ else if(E.modified && !E.dupes_allowed)
+ log_config("Duplicate setting for [entry] ([value]) detected! Using latest.")
+
+ if(validated)
+ E.modified = TRUE
+
+/datum/controller/configuration/can_vv_get(var_name)
+ return (var_name != "entries_by_type" || !hiding_entries_by_type) && ..()
+
+/datum/controller/configuration/vv_edit_var(var_name, var_value)
+ return !(var_name in list("entries_by_type", "entries")) && ..()
+
+/datum/controller/configuration/stat_entry()
+ if(!statclick)
+ statclick = new/obj/effect/statclick/debug(null, "Edit", src)
+ stat("[name]:", statclick)
+
+/datum/controller/configuration/proc/Get(entry_type)
+ if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
+ log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]")
+ return
+ var/datum/config_entry/E = entry_type
+ var/entry_is_abstract = initial(E.abstract_type) == entry_type
+ if(entry_is_abstract)
+ CRASH("Tried to retrieve an abstract config_entry: [entry_type]")
+ E = entries_by_type[entry_type]
+ if(!E)
+ CRASH("Missing config entry for [entry_type]!")
+ return E.value
+
+/datum/controller/configuration/proc/Set(entry_type, new_val)
+ if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Set" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
+ log_admin_private("Config rewrite of [entry_type] to [new_val] attempted by [key_name(usr)]")
+ return
+ var/datum/config_entry/E = entry_type
+ var/entry_is_abstract = initial(E.abstract_type) == entry_type
+ if(entry_is_abstract)
+ CRASH("Tried to retrieve an abstract config_entry: [entry_type]")
+ E = entries_by_type[entry_type]
+ if(!E)
+ CRASH("Missing config entry for [entry_type]!")
+ return E.ValidateAndSet(new_val)
+
+/datum/controller/configuration/proc/LoadModes()
+ gamemode_cache = typecacheof(/datum/game_mode, TRUE)
+ modes = list()
+ mode_names = list()
+ mode_reports = list()
+ mode_false_report_weight = list()
+ votable_modes = list()
+ var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
+ for(var/T in gamemode_cache)
+ // I wish I didn't have to instance the game modes in order to look up
+ // their information, but it is the only way (at least that I know of).
+ var/datum/game_mode/M = new T()
+
+ if(M.config_tag)
+ if(!(M.config_tag in modes)) // ensure each mode is added only once
+ modes += M.config_tag
+ mode_names[M.config_tag] = M.name
+ probabilities[M.config_tag] = M.probability
+ mode_reports[M.config_tag] = M.generate_report()
+ mode_false_report_weight[M.config_tag] = M.false_report_weight
+ if(M.votable)
+ votable_modes += M.config_tag
+ qdel(M)
+ votable_modes += "secret"
+
+/datum/controller/configuration/proc/loadmaplist(filename)
+ filename = "[GLOB.config_dir][filename]"
+ var/list/Lines = world.file2list(filename)
+
+ var/datum/map_config/currentmap = null
+ for(var/t in Lines)
+ if(!t)
+ continue
+
+ t = trim(t)
+ if(length(t) == 0)
+ continue
+ else if(copytext(t, 1, 2) == "#")
+ continue
+
+ var/pos = findtext(t, " ")
+ var/command = null
+ var/data = null
+
+ if(pos)
+ command = lowertext(copytext(t, 1, pos))
+ data = copytext(t, pos + 1)
+ else
+ command = lowertext(t)
+
+ if(!command)
+ continue
+
+ if (!currentmap && command != "map")
+ continue
+
+ switch (command)
+ if ("map")
+ currentmap = new ("_maps/[data].json")
+ if(currentmap.defaulted)
+ log_config("Failed to load map config for [data]!")
+ if ("minplayers","minplayer")
+ currentmap.config_min_users = text2num(data)
+ if ("maxplayers","maxplayer")
+ currentmap.config_max_users = text2num(data)
+ if ("weight","voteweight")
+ currentmap.voteweight = text2num(data)
+ if ("default","defaultmap")
+ defaultmap = currentmap
+ if ("endmap")
+ LAZYINITLIST(maplist)
+ maplist[currentmap.map_name] = currentmap
+ currentmap = null
+ if ("disabled")
+ currentmap = null
+ else
+ WRITE_FILE(GLOB.config_error_log, "Unknown command in map vote config: '[command]'")
+
+
+/datum/controller/configuration/proc/pick_mode(mode_name)
+ // I wish I didn't have to instance the game modes in order to look up
+ // their information, but it is the only way (at least that I know of).
+ // ^ This guy didn't try hard enough
+ for(var/T in gamemode_cache)
+ var/datum/game_mode/M = T
+ var/ct = initial(M.config_tag)
+ if(ct && ct == mode_name)
+ return new T
+ return new /datum/game_mode/extended()
+
+/datum/controller/configuration/proc/get_runnable_modes()
+ var/list/datum/game_mode/runnable_modes = new
+ var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
+ var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
+ var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
+ var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust)
+ for(var/T in gamemode_cache)
+ var/datum/game_mode/M = new T()
+ if(!(M.config_tag in modes))
+ qdel(M)
+ continue
+ if(probabilities[M.config_tag]<=0)
+ qdel(M)
+ continue
+ if(min_pop[M.config_tag])
+ M.required_players = min_pop[M.config_tag]
+ if(max_pop[M.config_tag])
+ M.maximum_players = max_pop[M.config_tag]
+ if(M.can_start())
+ var/final_weight = probabilities[M.config_tag]
+ if(SSpersistence.saved_modes.len == 3 && repeated_mode_adjust.len == 3)
+ var/recent_round = min(SSpersistence.saved_modes.Find(M.config_tag),3)
+ var/adjustment = 0
+ while(recent_round)
+ adjustment += repeated_mode_adjust[recent_round]
+ recent_round = SSpersistence.saved_modes.Find(M.config_tag,recent_round+1,0)
+ final_weight *= ((100-adjustment)/100)
+ runnable_modes[M] = final_weight
+ return runnable_modes
+
+/datum/controller/configuration/proc/get_runnable_midround_modes(crew)
+ var/list/datum/game_mode/runnable_modes = new
+ var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
+ var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
+ var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
+ for(var/T in (gamemode_cache - SSticker.mode.type))
+ var/datum/game_mode/M = new T()
+ if(!(M.config_tag in modes))
+ qdel(M)
+ continue
+ if(probabilities[M.config_tag]<=0)
+ qdel(M)
+ continue
+ if(min_pop[M.config_tag])
+ M.required_players = min_pop[M.config_tag]
+ if(max_pop[M.config_tag])
+ M.maximum_players = max_pop[M.config_tag]
+ if(M.required_players <= crew)
+ if(M.maximum_players >= 0 && M.maximum_players < crew)
+ continue
+ runnable_modes[M] = probabilities[M.config_tag]
+ return runnable_modes
diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm
index eee6945c41..e160c132b9 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -69,7 +69,7 @@
can_fire = 0
flags |= SS_NO_FIRE
Master.subsystems -= src
-
+ return ..()
//Queue it to run.
// (we loop thru a linked list until we get to the end or find the right point)
diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm
index e018ccad91..b5dbabb934 100644
--- a/code/controllers/subsystem/air.dm
+++ b/code/controllers/subsystem/air.dm
@@ -322,7 +322,7 @@ SUBSYSTEM_DEF(air)
EG.dismantle()
CHECK_TICK
- var/msg = "HEY! LISTEN! [(world.timeofday - timer)/10] Seconds were wasted processing [starting_ats] turf(s) (connected to [ending_ats] other turfs) with atmos differences at round start."
+ var/msg = "HEY! LISTEN! [DisplayTimeText(world.timeofday - timer)] were wasted processing [starting_ats] turf(s) (connected to [ending_ats] other turfs) with atmos differences at round start."
to_chat(world, "[msg]")
warning(msg)
diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm
index ec34cfb8ed..87b06cd587 100644
--- a/code/controllers/subsystem/server_maint.dm
+++ b/code/controllers/subsystem/server_maint.dm
@@ -29,7 +29,7 @@ SUBSYSTEM_DEF(server_maint)
var/cmob = C.mob
if(!(isobserver(cmob) || (isdead(cmob) && C.holder)))
log_access("AFK: [key_name(C)]")
- to_chat(C, "You have been inactive for more than [config.afk_period / 600] minutes and have been disconnected.")
+ to_chat(C, "You have been inactive for more than [DisplayTimeText(config.afk_period)] and have been disconnected.")
qdel(C)
if (!(!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1)))
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index a5b4a60e84..2b1080049e 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -178,7 +178,7 @@ SUBSYSTEM_DEF(shuttle)
emergency = backup_shuttle
if(world.time - SSticker.round_start_time < config.shuttle_refuel_delay)
- to_chat(user, "The emergency shuttle is refueling. Please wait another [abs(round(((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)/600))] minutes before trying again.")
+ to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)] before trying again.")
return
switch(emergency.mode)
diff --git a/code/controllers/subsystem/squeak.dm b/code/controllers/subsystem/squeak.dm
index 16b722c71b..964d970e2b 100644
--- a/code/controllers/subsystem/squeak.dm
+++ b/code/controllers/subsystem/squeak.dm
@@ -11,6 +11,7 @@ SUBSYSTEM_DEF(squeak)
/datum/controller/subsystem/squeak/Initialize(timeofday)
trigger_migration(config.mice_roundstart)
+ return ..()
/datum/controller/subsystem/squeak/proc/trigger_migration(num_mice=10)
if(!num_mice)
diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm
index f245b0766c..97d84a0d3b 100644
--- a/code/controllers/subsystem/throwing.dm
+++ b/code/controllers/subsystem/throwing.dm
@@ -57,6 +57,9 @@ SUBSYSTEM_DEF(throwing)
var/pure_diagonal
var/diagonal_error
var/datum/callback/callback
+ var/paused = FALSE
+ var/delayed_time = 0
+ var/last_move = 0
/datum/thrownthing/proc/tick()
var/atom/movable/AM = thrownthing
@@ -64,14 +67,20 @@ SUBSYSTEM_DEF(throwing)
finalize()
return
+ if(paused)
+ delayed_time += world.time - last_move
+ return
+
if (dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept
finalize()
return
var/atom/step
+ last_move = world.time
+
//calculate how many tiles to move, making up for any missed ticks.
- var/tilestomove = Ceiling(min(((((world.time+world.tick_lag) - start_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
+ var/tilestomove = Ceiling(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
while (tilestomove-- > 0)
if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc))
finalize()
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 220c0e355a..3932eada60 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -51,14 +51,14 @@ SUBSYSTEM_DEF(ticker)
var/queue_delay = 0
var/list/queued_players = list() //used for join queues when the server exceeds the hard population cap
- var/obj/screen/cinematic = null //used for station explosion cinematic
-
var/maprotatechecked = 0
var/news_report
var/late_join_disabled
+ var/roundend_check_paused = FALSE
+
var/round_start_time = 0
var/list/round_start_events
var/mode_result = "undefined"
@@ -137,7 +137,7 @@ SUBSYSTEM_DEF(ticker)
scripture_states = scripture_unlock_alert(scripture_states)
SSshuttle.autoEnd()
- if(!mode.explosion_in_progress && mode.check_finished(force_ending) || force_ending)
+ if(!roundend_check_paused && mode.check_finished(force_ending) || force_ending)
current_state = GAME_STATE_FINISHED
toggle_ooc(TRUE) // Turn it on
toggle_dooc(TRUE)
@@ -273,144 +273,7 @@ SUBSYSTEM_DEF(ticker)
qdel(bomb)
if(epi)
explosion(epi, 0, 256, 512, 0, TRUE, TRUE, 0, TRUE)
-
-//Plus it provides an easy way to make cinematics for other events. Just use this as a template
-/datum/controller/subsystem/ticker/proc/station_explosion_cinematic(station_missed=0, override = null, atom/bomb = null)
- if( cinematic )
- return //already a cinematic in progress!
-
- for (var/datum/html_interface/hi in GLOB.html_interfaces)
- hi.closeAll()
- SStgui.close_all_uis()
-
- //Turn off the shuttles, there's no escape now
- if(!station_missed && bomb)
- SSshuttle.registerHostileEnvironment(src)
- SSshuttle.lockdown = TRUE
-
- //initialise our cinematic screen object
- cinematic = new /obj/screen{icon='icons/effects/station_explosion.dmi';icon_state="station_intact";layer=21;mouse_opacity = MOUSE_OPACITY_TRANSPARENT;screen_loc="1,0";}(src)
-
- for(var/mob/M in GLOB.mob_list)
- M.notransform = TRUE //stop everything moving
- if(M.client)
- M.client.screen += cinematic //show every client the cinematic
-
- var/actually_blew_up = TRUE
- //Now animate the cinematic
- switch(station_missed)
- if(NUKE_NEAR_MISS) //nuke was nearby but (mostly) missed
- if(mode && !override )
- override = mode.name
- switch( override )
- if("nuclear emergency") //Nuke wasn't on station when it blew up
- flick("intro_nuke",cinematic)
- sleep(35)
- SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
- station_explosion_detonation(bomb)
- flick("station_intact_fade_red",cinematic)
- cinematic.icon_state = "summary_nukefail"
- if("cult")
- cinematic.icon_state = null
- flick("intro_cult",cinematic)
- sleep(25)
- SEND_SOUND(world, sound('sound/magic/enter_blood.ogg'))
- sleep(28)
- SEND_SOUND(world, sound('sound/machines/terminal_off.ogg'))
- sleep(20)
- flick("station_corrupted",cinematic)
- SEND_SOUND(world, sound('sound/effects/ghost.ogg'))
- actually_blew_up = FALSE
- if("fake") //The round isn't over, we're just freaking people out for fun
- flick("intro_nuke",cinematic)
- sleep(35)
- SEND_SOUND(world, sound('sound/items/bikehorn.ogg'))
- flick("summary_selfdes",cinematic)
- actually_blew_up = FALSE
- else
- flick("intro_nuke",cinematic)
- sleep(35)
- SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
- station_explosion_detonation(bomb)
-
-
- if(NUKE_MISS_STATION || NUKE_SYNDICATE_BASE) //nuke was nowhere nearby //TODO: a really distant explosion animation
- sleep(50)
- SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
- station_explosion_detonation(bomb)
- actually_blew_up = station_missed == NUKE_SYNDICATE_BASE //don't kill everyone on station if it detonated off station
- else //station was destroyed
- if( mode && !override )
- override = mode.name
- switch( override )
- if("nuclear emergency") //Nuke Ops successfully bombed the station
- flick("intro_nuke",cinematic)
- sleep(35)
- flick("station_explode_fade_red",cinematic)
- SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
- station_explosion_detonation(bomb)
- cinematic.icon_state = "summary_nukewin"
- if("AI malfunction") //Malf (screen,explosion,summary)
- flick("intro_malf",cinematic)
- sleep(76)
- flick("station_explode_fade_red",cinematic)
- SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
- station_explosion_detonation(bomb) //TODO: If we ever decide to actually detonate the vault bomb
- cinematic.icon_state = "summary_malf"
- if("blob") //Station nuked (nuke,explosion,summary)
- flick("intro_nuke",cinematic)
- sleep(35)
- flick("station_explode_fade_red",cinematic)
- SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
- station_explosion_detonation(bomb) //TODO: no idea what this case could be
- cinematic.icon_state = "summary_selfdes"
- if("cult") //Station nuked (nuke,explosion,summary)
- flick("intro_nuke",cinematic)
- sleep(35)
- flick("station_explode_fade_red",cinematic)
- SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
- station_explosion_detonation(bomb) //TODO: no idea what this case could be
- cinematic.icon_state = "summary_cult"
- if("no_core") //Nuke failed to detonate as it had no core
- flick("intro_nuke",cinematic)
- sleep(35)
- flick("station_intact",cinematic)
- SEND_SOUND(world, sound('sound/ambience/signal.ogg'))
- addtimer(CALLBACK(src, .proc/finish_cinematic, null, FALSE), 100)
- return //Faster exit, since nothing happened
- else //Station nuked (nuke,explosion,summary)
- flick("intro_nuke",cinematic)
- sleep(35)
- flick("station_explode_fade_red", cinematic)
- SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
- station_explosion_detonation(bomb)
- cinematic.icon_state = "summary_selfdes"
- //If its actually the end of the round, wait for it to end.
- //Otherwise if its a verb it will continue on afterwards.
-
- var/bombloc = null
- if(actually_blew_up)
- if(bomb && bomb.loc)
- bombloc = bomb.z
- else if(!station_missed)
- bombloc = ZLEVEL_STATION_PRIMARY
-
- if(mode)
- mode.explosion_in_progress = 0
- to_chat(world, "The station was destoyed by the nuclear blast!")
- mode.station_was_nuked = (station_missed<2) //station_missed==1 is a draw. the station becomes irradiated and needs to be evacuated.
-
- addtimer(CALLBACK(src, .proc/finish_cinematic, bombloc, actually_blew_up), 300)
-
-/datum/controller/subsystem/ticker/proc/finish_cinematic(killz, actually_blew_up)
- if(cinematic)
- qdel(cinematic) //end the cinematic
- cinematic = null
- for(var/mob/M in GLOB.mob_list)
- M.notransform = FALSE
- if(actually_blew_up && !isnull(killz) && M.stat != DEAD && M.z == killz)
- M.gib()
-
+
/datum/controller/subsystem/ticker/proc/create_characters()
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
@@ -505,7 +368,7 @@ SUBSYSTEM_DEF(ticker)
end_state.count()
var/station_integrity = min(PERCENT(GLOB.start_state.score(end_state)), 100)
- to_chat(world, " [GLOB.TAB]Shift Duration: [round(world.time / 36000)]:[add_zero("[world.time / 600 % 60]", 2)]:[world.time / 100 % 6][world.time / 100 % 10]")
+ to_chat(world, " [GLOB.TAB]Shift Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]")
to_chat(world, " [GLOB.TAB]Station Integrity: [mode.station_was_nuked ? "Destroyed" : "[station_integrity]%"]")
if(mode.station_was_nuked)
SSticker.news_report = STATION_DESTROYED_NUKE
@@ -711,13 +574,11 @@ SUBSYSTEM_DEF(ticker)
queue_delay = SSticker.queue_delay
queued_players = SSticker.queued_players
- cinematic = SSticker.cinematic
maprotatechecked = SSticker.maprotatechecked
round_start_time = SSticker.round_start_time
queue_delay = SSticker.queue_delay
queued_players = SSticker.queued_players
- cinematic = SSticker.cinematic
maprotatechecked = SSticker.maprotatechecked
modevoted = SSticker.modevoted
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index 0dbc7c5d3a..0ea16b32d8 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -169,7 +169,7 @@ SUBSYSTEM_DEF(vote)
admin = TRUE
if(next_allowed_time > world.time && !admin)
- to_chat(usr, "A vote was initiated recently, you must wait roughly [(next_allowed_time-world.time)/10] seconds before a new vote can be started!")
+ to_chat(usr, "A vote was initiated recently, you must wait [DisplayTimeText(next_allowed_time-world.time)] before a new vote can be started!")
return 0
reset()
@@ -198,7 +198,7 @@ SUBSYSTEM_DEF(vote)
if(mode == "custom")
text += "\n[question]"
log_vote(text)
- to_chat(world, "\n[text]\nType vote or click here to place your votes.\nYou have [config.vote_period/10] seconds to vote.")
+ to_chat(world, "\n[text]\nType vote or click here to place your votes.\nYou have [DisplayTimeText(config.vote_period)] to vote.")
time_remaining = round(config.vote_period/10)
for(var/c in GLOB.clients)
var/client/C = c
diff --git a/code/datums/action.dm b/code/datums/action.dm
index ca71a7cbec..a65294fa40 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -485,7 +485,7 @@
/datum/action/spell_action/New(Target)
..()
- var/obj/effect/proc_holder/spell/S = target
+ var/obj/effect/proc_holder/S = target
S.action = src
name = S.name
desc = S.desc
@@ -495,36 +495,40 @@
button.name = name
/datum/action/spell_action/Destroy()
- var/obj/effect/proc_holder/spell/S = target
+ var/obj/effect/proc_holder/S = target
S.action = null
return ..()
/datum/action/spell_action/Trigger()
if(!..())
- return 0
+ return FALSE
if(target)
- var/obj/effect/proc_holder/spell = target
- spell.Click()
- return 1
+ var/obj/effect/proc_holder/S = target
+ S.Click()
+ return TRUE
/datum/action/spell_action/IsAvailable()
if(!target)
- return 0
- var/obj/effect/proc_holder/spell/spell = target
- if(owner)
- return spell.can_cast(owner)
- return 0
+ return FALSE
+ return TRUE
+/datum/action/spell_action/spell/IsAvailable()
+ if(!target)
+ return FALSE
+ var/obj/effect/proc_holder/spell/S = target
+ if(owner)
+ return S.can_cast(owner)
+ return FALSE
/datum/action/spell_action/alien
/datum/action/spell_action/alien/IsAvailable()
if(!target)
- return 0
+ return FALSE
var/obj/effect/proc_holder/alien/ab = target
if(owner)
return ab.cost_check(ab.check_turf,owner,1)
- return 0
+ return FALSE
diff --git a/code/datums/antagonists/datum_abductor.dm b/code/datums/antagonists/datum_abductor.dm
new file mode 100644
index 0000000000..6d08d61b8a
--- /dev/null
+++ b/code/datums/antagonists/datum_abductor.dm
@@ -0,0 +1,60 @@
+/datum/antagonist/abductor
+ name = "Abductor"
+ var/datum/objective_team/abductor_team/team
+ var/sub_role
+ var/outfit
+ var/landmark_type
+ var/greet_text
+
+/datum/antagonist/abductor/agent
+ sub_role = "Agent"
+ outfit = /datum/outfit/abductor/agent
+ landmark_type = /obj/effect/landmark/abductor/agent
+ greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
+
+/datum/antagonist/abductor/scientist
+ sub_role = "Scientist"
+ outfit = /datum/outfit/abductor/scientist
+ landmark_type = /obj/effect/landmark/abductor/scientist
+ greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
+
+/datum/antagonist/abductor/New(datum/mind/new_owner, datum/objective_team/abductor_team/T)
+ team = T
+ return ..()
+
+/datum/antagonist/abductor/on_gain()
+ SSticker.mode.abductors += owner
+ owner.special_role = "[name] [sub_role]"
+ owner.objectives += team.objectives
+ finalize_abductor()
+ return ..()
+
+/datum/antagonist/abductor/on_removal()
+ SSticker.mode.abductors -= owner
+ team.members -= owner
+ owner.objectives -= team.objectives
+ if(owner.current)
+ to_chat(owner.current,"You are no longer the [owner.special_role]!")
+ owner.special_role = null
+ return ..()
+
+/datum/antagonist/abductor/greet()
+ to_chat(owner.current, "You are the [owner.special_role]!")
+ to_chat(owner.current, "With the help of your teammate, kidnap and experiment on station crew members!")
+ to_chat(owner.current, "[greet_text]")
+ owner.announce_objectives()
+
+/datum/antagonist/abductor/proc/finalize_abductor()
+ //Equip
+ var/mob/living/carbon/human/H = owner.current
+ H.set_species(/datum/species/abductor)
+ H.real_name = "[team.name] [sub_role]"
+ H.equipOutfit(outfit)
+
+ //Teleport to ship
+ for(var/obj/effect/landmark/abductor/LM in GLOB.landmarks_list)
+ if(istype(LM, landmark_type) && LM.team_number == team.team_number)
+ H.forceMove(LM.loc)
+ break
+
+ SSticker.mode.update_abductor_icons_added(owner)
diff --git a/code/datums/antagonists/ninja.dm b/code/datums/antagonists/ninja.dm
index 230a4d64e4..f51b22dde2 100644
--- a/code/datums/antagonists/ninja.dm
+++ b/code/datums/antagonists/ninja.dm
@@ -1,6 +1,5 @@
/datum/antagonist/ninja
name = "Ninja"
- var/team
var/helping_station = 0
var/give_objectives = TRUE
@@ -19,36 +18,8 @@
..(new_owner)
helping_station = rand(0,1)
-/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current, safety=0)//Safety in case you need to unequip stuff for existing characters.
- if(safety)
- qdel(H.w_uniform)
- qdel(H.wear_suit)
- qdel(H.wear_mask)
- qdel(H.head)
- qdel(H.shoes)
- qdel(H.gloves)
-
- var/obj/item/clothing/suit/space/space_ninja/theSuit = new(H)
- var/obj/item/dash/energy_katana/EK = new(H)
- theSuit.energyKatana = EK
-
- H.equip_to_slot_or_del(new /obj/item/device/radio/headset(H), slot_ears)
- H.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(H), slot_w_uniform)
- H.equip_to_slot_or_del(new /obj/item/clothing/shoes/space_ninja(H), slot_shoes)
- H.equip_to_slot_or_del(theSuit, slot_wear_suit)
- H.equip_to_slot_or_del(new /obj/item/clothing/gloves/space_ninja(H), slot_gloves)
- H.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/space_ninja(H), slot_head)
- H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/space_ninja(H), slot_wear_mask)
- H.equip_to_slot_or_del(new /obj/item/clothing/glasses/night(H), slot_glasses)
- H.equip_to_slot_or_del(EK, slot_belt)
- H.equip_to_slot_or_del(new /obj/item/grenade/plastic/x4(H), slot_l_store)
- H.equip_to_slot_or_del(new /obj/item/tank/internals/emergency_oxygen(H), slot_s_store)
- H.equip_to_slot_or_del(new /obj/item/tank/jetpack/carbondioxide(H), slot_back)
- theSuit.randomize_param()
-
- var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H)
- E.implant(H)
- return 1
+/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current)
+ return H.equipOutfit(/datum/outfit/ninja)
/datum/antagonist/ninja/proc/addMemories()
owner.store_memory("I am an elite mercenary assassin of the mighty Spider Clan. A SPACE NINJA!")
diff --git a/code/datums/cinematic.dm b/code/datums/cinematic.dm
new file mode 100644
index 0000000000..3f72ff995b
--- /dev/null
+++ b/code/datums/cinematic.dm
@@ -0,0 +1,223 @@
+GLOBAL_LIST_EMPTY(cinematics)
+
+// Use to play cinematics.
+// Watcher can be world,mob, or a list of mobs
+// Blocks until sequence is done.
+/proc/Cinematic(id,watcher,datum/callback/special_callback)
+ var/datum/cinematic/playing
+ for(var/V in subtypesof(/datum/cinematic))
+ var/datum/cinematic/C = V
+ if(initial(C.id) == id)
+ playing = new V()
+ break
+ if(!playing)
+ CRASH("Cinematic type not found")
+ if(special_callback)
+ playing.special_callback = special_callback
+ if(watcher == world)
+ playing.is_global = TRUE
+ watcher = GLOB.mob_list
+ playing.play(watcher)
+
+/obj/screen/cinematic
+ icon = 'icons/effects/station_explosion.dmi'
+ icon_state = "station_intact"
+ layer = 21
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ screen_loc = "1,1"
+
+/datum/cinematic
+ var/id = CINEMATIC_DEFAULT
+ var/list/watching = list() //List of clients watching this
+ var/list/locked = list() //Who had notransform set during the cinematic
+ var/is_global = FALSE //Global cinematics will override mob-specific ones
+ var/obj/screen/cinematic/screen
+ var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc)
+ var/cleanup_time = 300 //How long for the final screen to remain
+
+/datum/cinematic/New()
+ GLOB.cinematics += src
+ screen = new(src)
+
+/datum/cinematic/Destroy()
+ GLOB.cinematics -= src
+ QDEL_NULL(screen)
+ for(var/mob/M in locked)
+ M.notransform = FALSE
+ return ..()
+
+/datum/cinematic/proc/play(watchers)
+ //Check if you can actually play it (stop mob cinematics for global ones) and create screen objects
+ for(var/A in GLOB.cinematics)
+ var/datum/cinematic/C = A
+ if(C == src)
+ continue
+ if(C.is_global || !is_global)
+ return //Can't play two global or local cinematics at the same time
+
+ //Close all open windows if global
+ if(is_global)
+ for (var/datum/html_interface/hi in GLOB.html_interfaces)
+ hi.closeAll()
+ SStgui.close_all_uis()
+
+
+ for(var/mob/M in GLOB.mob_list)
+ if(M in watchers)
+ M.notransform = TRUE //Should this be done for non-global cinematics or even at all ?
+ locked += M
+ //Close watcher ui's
+ SStgui.close_user_uis(M)
+ if(M.client)
+ watching += M.client
+ M.client.screen += screen
+ else
+ if(is_global)
+ M.notransform = TRUE
+ locked += M
+
+ //Actually play it
+ content()
+ //Cleanup
+ sleep(cleanup_time)
+ qdel(src)
+
+//Sound helper
+/datum/cinematic/proc/cinematic_sound(s)
+ if(is_global)
+ SEND_SOUND(world,s)
+ else
+ for(var/C in watching)
+ SEND_SOUND(C,s)
+
+//Fire up special callback for actual effects synchronized with animation (eg real nuke explosion happens midway)
+/datum/cinematic/proc/special()
+ if(special_callback)
+ special_callback.Invoke()
+
+//Actual cinematic goes in here
+/datum/cinematic/proc/content()
+ sleep(50)
+
+/datum/cinematic/nuke_win
+ id = CINEMATIC_NUKE_WIN
+
+/datum/cinematic/nuke_win/content()
+ flick("intro_nuke",screen)
+ sleep(35)
+ flick("station_explode_fade_red",screen)
+ cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special()
+ screen.icon_state = "summary_nukewin"
+
+/datum/cinematic/nuke_miss
+ id = CINEMATIC_NUKE_MISS
+
+/datum/cinematic/nuke_miss/content()
+ flick("intro_nuke",screen)
+ sleep(35)
+ cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special()
+ flick("station_intact_fade_red",screen)
+ screen.icon_state = "summary_nukefail"
+
+//Also used for blob
+/datum/cinematic/nuke_selfdestruct
+ id = CINEMATIC_SELFDESTRUCT
+
+/datum/cinematic/nuke_selfdestruct/content()
+ flick("intro_nuke",screen)
+ sleep(35)
+ flick("station_explode_fade_red", screen)
+ cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special()
+ screen.icon_state = "summary_selfdes"
+
+/datum/cinematic/nuke_selfdestruct_miss
+ id = CINEMATIC_SELFDESTRUCT_MISS
+
+/datum/cinematic/nuke_selfdestruct_miss/content()
+ flick("intro_nuke",screen)
+ sleep(35)
+ cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special()
+ screen.icon_state = "station_intact"
+
+/datum/cinematic/malf
+ id = CINEMATIC_MALF
+
+/datum/cinematic/malf/content()
+ flick("intro_malf",screen)
+ sleep(76)
+ flick("station_explode_fade_red",screen)
+ cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special()
+ screen.icon_state = "summary_malf"
+
+/datum/cinematic/cult
+ id = CINEMATIC_CULT
+
+/datum/cinematic/cult/content()
+ screen.icon_state = null
+ flick("intro_cult",screen)
+ sleep(25)
+ cinematic_sound(sound('sound/magic/enter_blood.ogg'))
+ sleep(28)
+ cinematic_sound(sound('sound/machines/terminal_off.ogg'))
+ sleep(20)
+ flick("station_corrupted",screen)
+ cinematic_sound(sound('sound/effects/ghost.ogg'))
+ sleep(70)
+ special()
+
+/datum/cinematic/nuke_annihilation
+ id = CINEMATIC_ANNIHILATION
+
+/datum/cinematic/nuke_annihilation/content()
+ flick("intro_nuke",screen)
+ sleep(35)
+ flick("station_explode_fade_red",screen)
+ cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special()
+ screen.icon_state = "summary_totala"
+
+/datum/cinematic/fake
+ id = CINEMATIC_NUKE_FAKE
+ cleanup_time = 100
+
+/datum/cinematic/fake/content()
+ flick("intro_nuke",screen)
+ sleep(35)
+ cinematic_sound(sound('sound/items/bikehorn.ogg'))
+ flick("summary_selfdes",screen) //???
+ special()
+
+/datum/cinematic/no_core
+ id = CINEMATIC_NUKE_NO_CORE
+ cleanup_time = 100
+
+/datum/cinematic/no_core/content()
+ flick("intro_nuke",screen)
+ sleep(35)
+ flick("station_intact",screen)
+ cinematic_sound(sound('sound/ambience/signal.ogg'))
+ sleep(100)
+
+/datum/cinematic/nuke_far
+ id = CINEMATIC_NUKE_FAR
+ cleanup_time = 0
+
+/datum/cinematic/nuke_far/content()
+ cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
+ special()
+
+/* Intended usage.
+Nuke.Explosion()
+ -> Cinematic(NUKE_BOOM,world)
+ -> ActualExplosion()
+ -> Mode.OnExplosion()
+
+
+Narsie()
+ -> Cinematic(CULT,world)
+*/
\ No newline at end of file
diff --git a/code/datums/components/README.md b/code/datums/components/README.md
index 04dc21f33e..81218700c1 100644
--- a/code/datums/components/README.md
+++ b/code/datums/components/README.md
@@ -94,7 +94,8 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* Allows the component to react to ownership transfers
1. `/datum/component/proc/_RemoveNoSignal()` (private, final)
* Internal, clears the parent var and removes the component from the parents component list
-1. `/datum/component/proc/RegisterSignal(signal(string), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
+1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
+ * If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
* Makes a component listen for the specified `signal` on it's `parent` datum.
* When that signal is recieved `proc_ref` will be called on the component, along with associated arguments
* Example proc ref: `.proc/OnEvent`
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index 667ffa7b82..a4c85f7816 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -95,7 +95,7 @@
P.datum_components = null
parent = null
-/datum/component/proc/RegisterSignal(sig_type, proc_on_self, override = FALSE)
+/datum/component/proc/RegisterSignal(sig_type_or_types, proc_on_self, override = FALSE)
if(QDELETED(src))
return
var/list/procs = signal_procs
@@ -103,12 +103,14 @@
procs = list()
signal_procs = procs
- if(!override)
- . = procs[sig_type]
- if(.)
- stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
-
- procs[sig_type] = CALLBACK(src, proc_on_self)
+ var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
+ for(var/sig_type in sig_types)
+ if(!override)
+ . = procs[sig_type]
+ if(.)
+ stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
+
+ procs[sig_type] = CALLBACK(src, proc_on_self)
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm
index 321d407e92..573bb81d11 100644
--- a/code/datums/components/slippery.dm
+++ b/code/datums/components/slippery.dm
@@ -6,10 +6,7 @@
/datum/component/slippery/Initialize(_intensity, _lube_flags = NONE)
intensity = max(_intensity, 0)
lube_flags = _lube_flags
- if(ismovableatom(parent))
- RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/Slip)
- else
- RegisterSignal(COMSIG_ATOM_ENTERED, .proc/Slip)
+ RegisterSignal(list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), .proc/Slip)
/datum/component/slippery/proc/Slip(atom/movable/AM)
var/mob/victim = AM
diff --git a/code/datums/components/squeek.dm b/code/datums/components/squeek.dm
index 40fd0af598..ebc9cf0434 100644
--- a/code/datums/components/squeek.dm
+++ b/code/datums/components/squeek.dm
@@ -24,22 +24,9 @@
if(use_delay_override)
use_delay = use_delay_override
- if(istype(parent, /atom))
- RegisterSignal(COMSIG_ATOM_BLOB_ACT, .proc/play_squeak)
- RegisterSignal(COMSIG_ATOM_HULK_ATTACK, .proc/play_squeak)
- RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/play_squeak)
- if(istype(parent, /atom/movable))
- RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/play_squeak)
- RegisterSignal(COMSIG_MOVABLE_COLLIDE, .proc/play_squeak)
- RegisterSignal(COMSIG_MOVABLE_IMPACT, .proc/play_squeak)
- if(istype(parent, /obj/item))
- RegisterSignal(COMSIG_ITEM_ATTACK, .proc/play_squeak)
- RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/use_squeak)
- RegisterSignal(COMSIG_ITEM_ATTACK_OBJ, .proc/play_squeak)
- if(istype(parent, /obj/item/clothing/shoes))
- RegisterSignal(COMSIG_SHOES_STEP_ACTION, .proc/step_squeak)
- else
- RegisterSignal(COMSIG_ATOM_ENTERED, .proc/play_squeak)
+ RegisterSignal(list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_CROSSED, COMSIG_MOVABLE_COLLIDE, COMSIG_MOVABLE_IMPACT, COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_ATTACK_OBJ), .proc/play_squeak)
+ RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/use_squeak)
+ RegisterSignal(COMSIG_SHOES_STEP_ACTION, .proc/step_squeak)
/datum/component/squeak/proc/play_squeak()
if(prob(squeak_chance))
diff --git a/code/datums/helper_datums/construction_datum.dm b/code/datums/helper_datums/construction_datum.dm
index e4017e9ece..7768a929da 100644
--- a/code/datums/helper_datums/construction_datum.dm
+++ b/code/datums/helper_datums/construction_datum.dm
@@ -1,103 +1,111 @@
-#define FORWARD -1
-#define BACKWARD 1
-
-/datum/construction
- var/list/steps
- var/atom/holder
- var/result
- var/list/steps_desc
-
-/datum/construction/New(atom)
- ..()
- holder = atom
- if(!holder) //don't want this without a holder
- qdel(src)
- set_desc(steps.len)
- return
-
-/datum/construction/proc/next_step()
- steps.len--
- if(!steps.len)
- spawn_result()
- else
- set_desc(steps.len)
- return
-
-/datum/construction/proc/action(atom/used_atom,mob/user)
- return
-
-/datum/construction/proc/check_step(atom/used_atom,mob/user) //check last step only
- var/valid_step = is_right_key(used_atom)
- if(valid_step)
- if(custom_action(valid_step, used_atom, user))
- next_step()
- return 1
- return 0
-
-/datum/construction/proc/is_right_key(atom/used_atom) // returns current step num if used_atom is of the right type.
- var/list/L = steps[steps.len]
- if(istype(used_atom, L["key"]))
- return steps.len
- return 0
-
-/datum/construction/proc/custom_action(step, used_atom, user)
- return 1
-
-/datum/construction/proc/check_all_steps(atom/used_atom,mob/user) //check all steps, remove matching one.
- for(var/i=1;i<=steps.len;i++)
- var/list/L = steps[i];
- if(istype(used_atom, L["key"]))
- if(custom_action(i, used_atom, user))
- steps[i]=null;//stupid byond list from list removal...
- listclearnulls(steps);
- if(!steps.len)
- spawn_result()
- return 1
- return 0
-
-
-/datum/construction/proc/spawn_result()
- if(result)
- new result(get_turf(holder))
- qdel(holder)
- return
-
-/datum/construction/proc/set_desc(index as num)
- var/list/step = steps[index]
- holder.desc = step["desc"]
- return
-
-/datum/construction/reversible
- var/index
-
-/datum/construction/reversible/New(atom)
- ..()
- index = steps.len
- return
-
-/datum/construction/reversible/proc/update_index(diff as num)
- index+=diff
- if(index==0)
- spawn_result()
- else
- set_desc(index)
- return
-
-/datum/construction/reversible/is_right_key(atom/used_atom) // returns index step
- var/list/L = steps[index]
- if(istype(used_atom, L["key"]))
- return FORWARD //to the first step -> forward
- else if(L["backkey"] && istype(used_atom, L["backkey"]))
- return BACKWARD //to the last step -> backwards
- return 0
-
-/datum/construction/reversible/check_step(atom/used_atom,mob/user)
- var/diff = is_right_key(used_atom)
- if(diff)
- if(custom_action(index, diff, used_atom, user))
- update_index(diff)
- return 1
- return 0
-
-/datum/construction/reversible/custom_action(index, diff, used_atom, user)
- return 1
+#define FORWARD -1
+#define BACKWARD 1
+
+/datum/construction
+ var/list/steps
+ var/atom/holder
+ var/result
+ var/list/steps_desc
+
+/datum/construction/New(atom)
+ ..()
+ holder = atom
+ if(!holder) //don't want this without a holder
+ qdel(src)
+ set_desc(steps.len)
+ return
+
+/datum/construction/proc/next_step()
+ steps.len--
+ if(!steps.len)
+ spawn_result()
+ else
+ set_desc(steps.len)
+ return
+
+/datum/construction/proc/action(atom/used_atom,mob/user)
+ return
+
+/datum/construction/proc/check_step(atom/used_atom,mob/user) //check last step only
+ var/valid_step = is_right_key(used_atom)
+ if(valid_step)
+ if(custom_action(valid_step, used_atom, user))
+ next_step()
+ return 1
+ return 0
+
+/datum/construction/proc/is_right_key(atom/used_atom) // returns current step num if used_atom is of the right type.
+ var/list/L = steps[steps.len]
+ if(istype(used_atom, L["key"]))
+ return steps.len
+ return 0
+
+/datum/construction/proc/custom_action(step, used_atom, user)
+ return 1
+
+/datum/construction/proc/check_all_steps(atom/used_atom,mob/user) //check all steps, remove matching one.
+ for(var/i=1;i<=steps.len;i++)
+ var/list/L = steps[i];
+ if(istype(used_atom, L["key"]))
+ if(custom_action(i, used_atom, user))
+ steps[i]=null;//stupid byond list from list removal...
+ listclearnulls(steps);
+ if(!steps.len)
+ spawn_result()
+ return 1
+ return 0
+
+
+/datum/construction/proc/spawn_result()
+ if(result)
+ new result(get_turf(holder))
+ qdel(holder)
+ return
+
+/datum/construction/proc/spawn_mecha_result()
+ if(result)
+ var/obj/mecha/m = new result(get_turf(holder))
+ var/obj/item/oldcell = locate (/obj/item/stock_parts/cell) in m
+ QDEL_NULL(oldcell)
+ m.CheckParts(holder.contents)
+ QDEL_NULL(holder)
+
+/datum/construction/proc/set_desc(index as num)
+ var/list/step = steps[index]
+ holder.desc = step["desc"]
+ return
+
+/datum/construction/reversible
+ var/index
+
+/datum/construction/reversible/New(atom)
+ ..()
+ index = steps.len
+ return
+
+/datum/construction/reversible/proc/update_index(diff as num)
+ index+=diff
+ if(index==0)
+ spawn_result()
+ else
+ set_desc(index)
+ return
+
+/datum/construction/reversible/is_right_key(atom/used_atom) // returns index step
+ var/list/L = steps[index]
+ if(istype(used_atom, L["key"]))
+ return FORWARD //to the first step -> forward
+ else if(L["backkey"] && istype(used_atom, L["backkey"]))
+ return BACKWARD //to the last step -> backwards
+ return 0
+
+/datum/construction/reversible/check_step(atom/used_atom,mob/user)
+ var/diff = is_right_key(used_atom)
+ if(diff)
+ if(custom_action(index, diff, used_atom, user))
+ update_index(diff)
+ return 1
+ return 0
+
+/datum/construction/reversible/custom_action(index, diff, used_atom, user)
+ return 1
diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm
index 6ce082bd2a..84f0f00e45 100644
--- a/code/datums/martial/krav_maga.dm
+++ b/code/datums/martial/krav_maga.dm
@@ -11,7 +11,7 @@
/datum/action/neck_chop/Trigger()
if(owner.incapacitated())
- to_chat(owner, "You can't use Krav Maga while you're incapacitated.")
+ to_chat(owner, "You can't use [name] while you're incapacitated.")
return
var/mob/living/carbon/human/H = owner
if (H.mind.martial_art.streak == "neck_chop")
@@ -28,7 +28,7 @@
/datum/action/leg_sweep/Trigger()
if(owner.incapacitated())
- to_chat(owner, "You can't use Krav Maga while you're incapacitated.")
+ to_chat(owner, "You can't use [name] while you're incapacitated.")
return
var/mob/living/carbon/human/H = owner
if (H.mind.martial_art.streak == "leg_sweep")
@@ -45,7 +45,7 @@
/datum/action/lung_punch/Trigger()
if(owner.incapacitated())
- to_chat(owner, "You can't use Krav Maga while you're incapacitated.")
+ to_chat(owner, "You can't use [name] while you're incapacitated.")
return
var/mob/living/carbon/human/H = owner
if (H.mind.martial_art.streak == "quick_choke")
@@ -57,14 +57,14 @@
/datum/martial_art/krav_maga/teach(mob/living/carbon/human/H,make_temporary=0)
if(..())
- to_chat(H, "You know the arts of Krav Maga!")
+ to_chat(H, "You know the arts of [name]!")
to_chat(H, "Place your cursor over a move at the top of the screen to see what it does.")
neckchop.Grant(H)
legsweep.Grant(H)
lungpunch.Grant(H)
/datum/martial_art/krav_maga/on_remove(mob/living/carbon/human/H)
- to_chat(H, "You suddenly forget the arts of Krav Maga...")
+ to_chat(H, "You suddenly forget the arts of [name]...")
neckchop.Remove(H)
legsweep.Remove(H)
lungpunch.Remove(H)
@@ -140,7 +140,7 @@
playsound(get_turf(D), 'sound/effects/hit_punch.ogg', 50, 1, -1)
D.visible_message("[A] [picked_hit_type] [D]!", \
"[A] [picked_hit_type] you!")
- add_logs(A, D, "[picked_hit_type] with Krav Maga")
+ add_logs(A, D, "[picked_hit_type] with [name]")
return 1
/datum/martial_art/krav_maga/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 8548ab2bc4..7f909144aa 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -590,8 +590,6 @@
if(src in SSticker.mode.abductors)
text += "Abductor | human"
text += " | undress | equip"
- else
- text += "abductor | human"
if(current && current.client && (ROLE_ABDUCTOR in current.client.prefs.be_special))
text += " | Enabled in Prefs"
@@ -1244,13 +1242,6 @@
if("clear")
to_chat(usr, "Not implemented yet. Sorry!")
//SSticker.mode.update_abductor_icons_removed(src)
- if("abductor")
- if(!ishuman(current))
- to_chat(usr, "This only works on humans!")
- return
- make_Abductor()
- log_admin("[key_name(usr)] turned [current] into abductor.")
- SSticker.mode.update_abductor_icons_added(src)
if("equip")
if(!ishuman(current))
to_chat(usr, "This only works on humans!")
@@ -1496,52 +1487,7 @@
take_uplink()
var/fail = 0
fail |= !SSticker.mode.equip_revolutionary(current)
-
-/datum/mind/proc/make_Abductor()
- var/role = alert("Abductor Role ?","Role","Agent","Scientist")
- var/team = input("Abductor Team ?","Team ?") in list(1,2,3,4)
- var/teleport = alert("Teleport to ship ?","Teleport","Yes","No")
-
- if(!role || !team || !teleport)
- return
-
- if(!ishuman(current))
- return
-
- SSticker.mode.abductors |= src
-
- var/datum/objective/experiment/O = new
- O.owner = src
- objectives += O
-
- var/mob/living/carbon/human/H = current
-
- H.set_species(/datum/species/abductor)
- var/datum/species/abductor/S = H.dna.species
-
- if(role == "Scientist")
- S.scientist = TRUE
- S.team = team
-
- var/list/obj/effect/landmark/abductor/agent_landmarks = new
- var/list/obj/effect/landmark/abductor/scientist_landmarks = new
- agent_landmarks.len = 4
- scientist_landmarks.len = 4
- for(var/obj/effect/landmark/abductor/A in GLOB.landmarks_list)
- if(istype(A, /obj/effect/landmark/abductor/agent))
- agent_landmarks[text2num(A.team)] = A
- else if(istype(A, /obj/effect/landmark/abductor/scientist))
- scientist_landmarks[text2num(A.team)] = A
-
- var/obj/effect/landmark/L
- if(teleport=="Yes")
- switch(role)
- if("Agent")
- L = agent_landmarks[team]
- if("Scientist")
- L = scientist_landmarks[team]
- H.forceMove(L.loc)
-
+
/datum/mind/proc/AddSpell(obj/effect/proc_holder/spell/S)
spell_list += S
S.action.Grant(current)
diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm
index 8d4413171d..3c3ab905ea 100755
--- a/code/datums/outfit.dm
+++ b/code/datums/outfit.dm
@@ -102,10 +102,10 @@
if(implants)
for(var/implant_type in implants)
var/obj/item/implant/I = new implant_type(H)
- I.implant(H, null, silent=TRUE)
+ I.implant(H, null, TRUE)
H.update_body()
- return 1
+ return TRUE
/datum/outfit/proc/apply_fingerprints(mob/living/carbon/human/H)
if(!istype(H))
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 6c544c4497..a880a44fa6 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -225,6 +225,17 @@
A.CollidedWith(src)
/atom/movable/proc/forceMove(atom/destination)
+ . = FALSE
+ if(destination)
+ . = doMove(destination)
+ else
+ CRASH("No valid destination passed into forceMove")
+
+/atom/movable/proc/moveToNullspace()
+ return doMove(null)
+
+/atom/movable/proc/doMove(atom/destination)
+ . = FALSE
if(destination)
if(pulledby)
pulledby.stop_pulling()
@@ -251,8 +262,17 @@
AM.Crossed(src, oldloc)
Moved(oldloc, 0)
- return 1
- return 0
+ . = TRUE
+
+ //If no destination, move the atom into nullspace (don't do this unless you know what you're doing)
+ else
+ . = TRUE
+ var/atom/oldloc = loc
+ var/area/old_area = get_area(oldloc)
+ oldloc.Exited(src, null)
+ if(old_area)
+ old_area.Exited(src, null)
+ loc = null
/mob/living/forceMove(atom/destination)
stop_pulling()
@@ -261,9 +281,10 @@
if(has_buckled_mobs())
unbuckle_all_mobs(force=1)
. = ..()
- if(client)
- reset_perspective(destination)
- update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
+ if(.)
+ if(client)
+ reset_perspective(destination)
+ update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
/mob/living/brain/forceMove(atom/destination)
if(container)
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm
index 64b405bbd5..3b5b862559 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/game/gamemodes/antag_spawner.dm
@@ -203,9 +203,9 @@
var/mob/living/silicon/robot/R
switch(borg_to_spawn)
if("Medical")
- R = new /mob/living/silicon/robot/syndicate/medical(T)
+ R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
else
- R = new /mob/living/silicon/robot/syndicate(T) //Assault borg by default
+ R = new /mob/living/silicon/robot/modules/syndicate(T) //Assault borg by default
var/brainfirstname = pick(GLOB.first_names_male)
if(prob(50))
diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm
index e22b2747e0..9f8a44bed2 100644
--- a/code/game/gamemodes/blob/overmind.dm
+++ b/code/game/gamemodes/blob/overmind.dm
@@ -57,7 +57,7 @@
if(!placed)
if(manualplace_min_time && world.time >= manualplace_min_time)
to_chat(src, "You may now place your blob core.")
- to_chat(src, "You will automatically place your blob core in [round((autoplace_max_time - world.time)/600, 0.5)] minutes.")
+ to_chat(src, "You will automatically place your blob core in [DisplayTimeText(autoplace_max_time - world.time)].")
manualplace_min_time = 0
if(autoplace_max_time && world.time >= autoplace_max_time)
place_blob_core(base_point_rate, 1)
diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm
index 6baf8b4dbe..026183d951 100644
--- a/code/game/gamemodes/blob/powers.dm
+++ b/code/game/gamemodes/blob/powers.dm
@@ -365,5 +365,5 @@
to_chat(src, "Shortcuts: Click = Expand Blob | Middle Mouse Click = Rally Spores | Ctrl Click = Create Shield Blob | Alt Click = Remove Blob")
to_chat(src, "Attempting to talk will send a message to all other overminds, allowing you to coordinate with them.")
if(!placed && autoplace_max_time <= world.time)
- to_chat(src, "You will automatically place your blob core in [round((autoplace_max_time - world.time)/600, 0.5)] minutes.")
+ to_chat(src, "You will automatically place your blob core in [DisplayTimeText(autoplace_max_time - world.time)].")
to_chat(src, "You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the Place Blob Core button in the bottom right corner of the screen.")
diff --git a/code/game/gamemodes/clock_cult/clock_effects/spatial_gateway.dm b/code/game/gamemodes/clock_cult/clock_effects/spatial_gateway.dm
index a6eb5fb4e7..9b1ef66c9e 100644
--- a/code/game/gamemodes/clock_cult/clock_effects/spatial_gateway.dm
+++ b/code/game/gamemodes/clock_cult/clock_effects/spatial_gateway.dm
@@ -207,7 +207,7 @@
time_duration = round(time_duration * (2 * efficiency), 1)
CO.active = TRUE //you'd be active in a second but you should update immediately
invoker.visible_message("The air in front of [invoker] ripples before suddenly tearing open!", \
- "With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [time_duration / 10] seconds and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].")
+ "With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [DisplayTimeText(time_duration)] and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].")
var/obj/effect/clockwork/spatial_gateway/S1 = new(issrcobelisk ? get_turf(src) : get_step(get_turf(invoker), invoker.dir))
var/obj/effect/clockwork/spatial_gateway/S2 = new(istargetobelisk ? get_turf(target) : get_step(get_turf(target), target.dir))
diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm
index 0ec876dc92..423763f3b4 100644
--- a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm
@@ -195,6 +195,19 @@
textlist += "HONOR RATVAR "
textlist += ""
else
+ var/servants = 0
+ var/production_time = SLAB_PRODUCTION_TIME
+ for(var/mob/living/M in GLOB.living_mob_list)
+ if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
+ servants++
+ if(servants > SCRIPT_SERVANT_REQ)
+ servants -= SCRIPT_SERVANT_REQ
+ production_time += min(SLAB_SERVANT_SLOWDOWN * servants, SLAB_SLOWDOWN_MAXIMUM)
+ if(production_time != SLAB_PRODUCTION_TIME+SLAB_SLOWDOWN_MAXIMUM)
+ production_time = "[DisplayTimeText(production_time)], which increases for each human or silicon Servant above [SCRIPT_SERVANT_REQ]"
+ else
+ production_time = "[DisplayTimeText(production_time)]"
+
textlist = list("
[text2ratvar("Purge all untruths and honor Engine.")]
\
\
NOTICE: This information is out of date. Read the Ark & You primer in your backpack or read the wiki page for current info. \
@@ -287,12 +300,24 @@
dat += "Transmission: Drains and stores power for clockwork structures. Feeding it brass sheets will create additional power.
"
dat += "-=-=-=-=-=-"
if("Components")
+ var/servants = 0 //Calculate the current production time for slab components
+ var/production_time = SLAB_PRODUCTION_TIME
+ for(var/mob/living/M in GLOB.living_mob_list)
+ if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
+ servants++
+ if(servants > SCRIPT_SERVANT_REQ)
+ servants -= SCRIPT_SERVANT_REQ
+ production_time += min(SLAB_SERVANT_SLOWDOWN * servants, SLAB_SLOWDOWN_MAXIMUM)
+ if(production_time != SLAB_PRODUCTION_TIME+SLAB_SLOWDOWN_MAXIMUM)
+ production_time = "[DisplayTimeText(production_time)], which increases for each human or silicon Servant above [SCRIPT_SERVANT_REQ]"
+ else
+ production_time = "[DisplayTimeText(production_time)]"
dat += "Components & Their Uses
"
dat += "Components are your primary resource as a Servant. There are five types of component, with each one being used in different roles:
"
dat += "Although this is a good rule of thumb, their effects become much more nuanced when used together. For instance, a turret might have both belligerent eyes and \
vanguard cogwheels as construction requirements, because it defends its allies by harming its enemies.
"
dat += "Components' primary use is fueling scripture (covered in its own section), and they can be created through various ways. This clockwork slab, for instance, \
- will make a random component of every type - or a specific one, if you choose a target component from the interface - every remove me already. This number will increase \
+ will make a random component of every type - or a specific one, if you choose a target component from the interface - every [production_time]. This number will increase \
as the amount of Servants in the covenant increase; additionally, slabs can only produce components when held by a Servant, and holding more than one slab will cause both \
of them to halt progress until one of them is removed from their person.
"
dat += "Your slab has an internal storage of components, but it isn't meant to be the main one. Instead, there's a global storage of components that can be \
diff --git a/code/game/gamemodes/clock_cult/clock_items/soul_vessel.dm b/code/game/gamemodes/clock_cult/clock_items/soul_vessel.dm
index 0ee6d45f7d..ca80d6f082 100644
--- a/code/game/gamemodes/clock_cult/clock_items/soul_vessel.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/soul_vessel.dm
@@ -23,6 +23,7 @@
autoping = FALSE
resistance_flags = FIRE_PROOF | ACID_PROOF
force_replace_ai_name = TRUE
+ overrides_aicore_laws = TRUE
/obj/item/device/mmi/posibrain/soul_vessel/Initialize()
. = ..()
diff --git a/code/game/gamemodes/clock_cult/clock_structures/tinkerers_cache.dm b/code/game/gamemodes/clock_cult/clock_structures/tinkerers_cache.dm
index 326aa46c06..cd33cf7adc 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/tinkerers_cache.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/tinkerers_cache.dm
@@ -105,7 +105,7 @@
..()
if(is_servant_of_ratvar(user) || isobserver(user))
if(linkedwall)
- to_chat(user, "It is linked to a Clockwork Wall and will generate a component every [round(get_production_time() * 0.1, 0.1)] seconds!")
+ to_chat(user, "It is linked to a Clockwork Wall and will generate a component every [DisplayTimeText(get_production_time())]!")
else
to_chat(user, "It is unlinked! Construct a Clockwork Wall nearby to generate components!")
to_chat(user, "Stored components:")
diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm
index 283376b055..b8cbed5051 100644
--- a/code/game/gamemodes/cult/cult_comms.dm
+++ b/code/game/gamemodes/cult/cult_comms.dm
@@ -96,7 +96,7 @@
/proc/pollCultists(var/mob/living/Nominee) //Cult Master Poll
if(world.time < CULT_POLL_WAIT)
- to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [round((CULT_POLL_WAIT-world.time)/10)] seconds.")
+ to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].")
return
GLOB.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
for(var/datum/mind/B in SSticker.mode.cult)
@@ -232,7 +232,7 @@
return FALSE
if(cooldown > world.time)
if(!CM.active)
- to_chat(owner, "You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can mark another target!")
+ to_chat(owner, "You need to wait [DisplayTimeText(cooldown - world.time)] before you can mark another target!")
return FALSE
return ..()
@@ -324,7 +324,7 @@
return FALSE
if(cooldown > world.time)
if(!PM.active)
- to_chat(owner, "You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can pulse again!")
+ to_chat(owner, "You need to wait [DisplayTimeText(cooldown - world.time)] before you can pulse again!")
return FALSE
return ..()
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index 0cba943287..c1ccf9a368 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -10,7 +10,7 @@
..()
to_chat(user, "\The [src] is [anchored ? "":"not "]secured to the floor.")
if((iscultist(user) || isobserver(user)) && cooldowntime > world.time)
- to_chat(user, "The magic in [src] is too weak, [p_they()] will be ready to use again in [getETA()].")
+ to_chat(user, "The magic in [src] is too weak, [p_they()] will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].")
/obj/structure/destructible/cult/examine_status(mob/user)
if(iscultist(user) || isobserver(user))
@@ -50,13 +50,6 @@
animate(src, color = previouscolor, time = 8)
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
-/obj/structure/destructible/cult/proc/getETA()
- var/time = (cooldowntime - world.time)/600
- var/eta = "[round(time, 1)] minutes"
- if(time <= 1)
- time = (cooldowntime - world.time)*0.1
- eta = "[round(time, 1)] seconds"
- return eta
/obj/structure/destructible/cult/talisman
name = "altar"
@@ -72,7 +65,7 @@
to_chat(user, "You need to anchor [src] to the floor with a tome first.")
return
if(cooldowntime > world.time)
- to_chat(user, "The magic in [src] is weak, it will be ready to use again in [getETA()].")
+ to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].")
return
var/choice = alert(user,"You study the schematics etched into the forge...",,"Eldritch Whetstone","Zealot's Blindfold","Flask of Unholy Water")
var/pickedtype
@@ -105,7 +98,7 @@
to_chat(user, "You need to anchor [src] to the floor with a tome first.")
return
if(cooldowntime > world.time)
- to_chat(user, "The magic in [src] is weak, it will be ready to use again in [getETA()].")
+ to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].")
return
var/choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Nar-Sien Hardsuit")
var/pickedtype
@@ -212,7 +205,7 @@
to_chat(user, "You need to anchor [src] to the floor with a tome first.")
return
if(cooldowntime > world.time)
- to_chat(user, "The magic in [src] is weak, it will be ready to use again in [getETA()].")
+ to_chat(user, "The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].")
return
var/choice = alert(user,"You flip through the black pages of the archives...",,"Supply Talisman","Shuttle Curse","Veil Walker Set")
var/list/pickedtype = list()
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index f65a64fb08..18a19fb153 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -19,7 +19,6 @@
var/probability = 0
var/false_report_weight = 0 //How often will this show up incorrectly in a centcom report?
var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
- var/explosion_in_progress = 0 //sit back and relax
var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
var/list/datum/mind/modePlayer = new
var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
@@ -562,3 +561,8 @@
/datum/game_mode/proc/generate_report() //Generates a small text blurb for the gamemode in centcom report
return "Gamemode report for [name] not set. Contact a coder."
+
+//By default nuke just ends the round
+/datum/game_mode/proc/OnNukeExplosion(off_station)
+ if(off_station < 2)
+ station_was_nuked = TRUE //Will end the round on next check.
\ No newline at end of file
diff --git a/code/game/gamemodes/miniantags/abduction/abduction.dm b/code/game/gamemodes/miniantags/abduction/abduction.dm
index 7ff5a9742d..ed5c2e9d76 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction.dm
@@ -1,5 +1,17 @@
+/datum/objective_team/abductor_team
+ member_name = "abductor"
+ var/list/objectives = list()
+ var/team_number
+
+/datum/objective_team/abductor_team/is_solo()
+ return FALSE
+
+/datum/objective_team/abductor_team/proc/add_objective(datum/objective/O)
+ O.team = src
+ O.update_explanation_text()
+ objectives += O
+
/datum/game_mode
- var/abductor_teams = 0
var/list/datum/mind/abductors = list()
var/list/datum/mind/abductees = list()
@@ -12,12 +24,8 @@
required_players = 15
maximum_players = 50
var/max_teams = 4
- abductor_teams = 1
- var/list/datum/mind/scientists = list()
- var/list/datum/mind/agents = list()
- var/list/datum/objective/team_objectives = list()
- var/list/team_names = list()
- var/finished = 0
+ var/list/datum/objective_team/abductor_team/abductor_teams = list()
+ var/finished = FALSE
/datum/game_mode/abduction/announce()
to_chat(world, "The current game mode is - Abduction!")
@@ -26,163 +34,78 @@
to_chat(world, "Crew - don't get abducted and stop the abductors.")
/datum/game_mode/abduction/pre_setup()
- abductor_teams = max(1, min(max_teams,round(num_players()/config.abductor_scaling_coeff)))
- var/possible_teams = max(1,round(antag_candidates.len / 2))
- abductor_teams = min(abductor_teams,possible_teams)
+ var/num_teams = max(1, min(max_teams, round(num_players() / config.abductor_scaling_coeff)))
+ var/possible_teams = max(1, round(antag_candidates.len / 2))
+ num_teams = min(num_teams, possible_teams)
- abductors.len = 2*abductor_teams
- scientists.len = abductor_teams
- agents.len = abductor_teams
- team_objectives.len = abductor_teams
- team_names.len = abductor_teams
+ for(var/i = 1 to num_teams)
+ if(!make_abductor_team())
+ return FALSE
+ return TRUE
- for(var/i=1,i<=abductor_teams,i++)
- if(!make_abductor_team(i))
- return 0
+/datum/game_mode/abduction/proc/make_abductor_team(datum/mind/agent, datum/mind/scientist)
+ var/team_number = abductor_teams.len+1
- return 1
+ var/datum/objective_team/abductor_team/team = new
+ team.team_number = team_number
+ team.name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
+ team.add_objective(new/datum/objective/experiment)
-/datum/game_mode/abduction/proc/make_abductor_team(team_number,preset_agent=null,preset_scientist=null)
- //Team Name
- team_names[team_number] = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
- //Team Objective
- var/datum/objective/experiment/team_objective = new
- team_objective.team_number = team_number
- team_objectives[team_number] = team_objective
- //Team Members
+ if(antag_candidates.len < (!agent + !scientist))
+ return
- if(!preset_agent || !preset_scientist)
- if(antag_candidates.len <=2)
- return 0
-
- var/datum/mind/scientist
- var/datum/mind/agent
-
- if(!preset_scientist)
+ if(!scientist)
scientist = pick(antag_candidates)
- antag_candidates -= scientist
- else
- scientist = preset_scientist
+ antag_candidates -= scientist
+ team.members |= scientist
+ scientist.assigned_role = "Abductor Scientist"
+ log_game("[scientist.key] (ckey) has been selected as [team.name] abductor scientist.")
- if(!preset_agent)
+ if(!agent)
agent = pick(antag_candidates)
- antag_candidates -= agent
- else
- agent = preset_agent
+ antag_candidates -= agent
+ team.members |= agent
+ agent.assigned_role = "Abductor Agent"
+ log_game("[agent.key] (ckey) has been selected as [team.name] abductor agent.")
-
- scientist.assigned_role = "abductor scientist"
- scientist.special_role = "abductor scientist"
- log_game("[scientist.key] (ckey) has been selected as an abductor team [team_number] scientist.")
-
- agent.assigned_role = "abductor agent"
- agent.special_role = "abductor agent"
- log_game("[agent.key] (ckey) has been selected as an abductor team [team_number] agent.")
-
- abductors |= agent
- abductors |= scientist
- scientists[team_number] = scientist
- agents[team_number] = agent
- return 1
+ abductor_teams += team
+ return team
/datum/game_mode/abduction/post_setup()
- for(var/team_number=1,team_number<=abductor_teams,team_number++)
- post_setup_team(team_number)
+ for(var/datum/objective_team/abductor_team/team in abductor_teams)
+ post_setup_team(team)
return ..()
//Used for create antag buttons
-/datum/game_mode/abduction/proc/post_setup_team(team_number)
- var/list/obj/effect/landmark/abductor/agent_landmarks = list()
- var/list/obj/effect/landmark/abductor/scientist_landmarks = list()
- agent_landmarks.len = max_teams
- scientist_landmarks.len = max_teams
- for(var/obj/effect/landmark/abductor/A in GLOB.landmarks_list)
- if(istype(A, /obj/effect/landmark/abductor/agent))
- agent_landmarks[text2num(A.team)] = A
- else if(istype(A, /obj/effect/landmark/abductor/scientist))
- scientist_landmarks[text2num(A.team)] = A
-
- var/team_name = team_names[team_number]
-
- var/datum/mind/agent
- var/obj/effect/landmark/L
- var/datum/mind/scientist
- var/mob/living/carbon/human/H
- var/datum/species/abductor/S
-
- agent = agents[team_number]
- H = agent.current
- L = agent_landmarks[team_number]
- H.forceMove(L.loc)
- H.set_species(/datum/species/abductor)
- S = H.dna.species
- S.team = team_number
- H.real_name = team_name + " Agent"
- H.equipOutfit(/datum/outfit/abductor/agent)
- greet_agent(agent,team_number)
-
-
- scientist = scientists[team_number]
- H = scientist.current
- L = scientist_landmarks[team_number]
- H.forceMove(L.loc)
- H.set_species(/datum/species/abductor)
- S = H.dna.species
- S.scientist = TRUE
- S.team = team_number
- H.real_name = team_name + " Scientist"
- H.equipOutfit(/datum/outfit/abductor/scientist)
- greet_scientist(scientist,team_number)
-
-
-
-/datum/game_mode/abduction/proc/greet_agent(datum/mind/abductor,team_number)
- abductor.objectives += team_objectives[team_number]
- var/team_name = team_names[team_number]
-
- to_chat(abductor.current, "You are an agent of [team_name]!")
- to_chat(abductor.current, "With the help of your teammate, kidnap and experiment on station crew members!")
- to_chat(abductor.current, "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve.")
-
- abductor.announce_objectives()
-
-/datum/game_mode/abduction/proc/greet_scientist(datum/mind/abductor,team_number)
- abductor.objectives += team_objectives[team_number]
- var/team_name = team_names[team_number]
-
- to_chat(abductor.current, "You are a scientist of [team_name]!")
- to_chat(abductor.current, "With the help of your teammate, kidnap and experiment on station crew members!")
- to_chat(abductor.current, "Use your tool and ship consoles to support the agent and retrieve human specimens.")
-
- abductor.announce_objectives()
-
-/datum/game_mode/abduction/proc/get_team_console(team_number)
- for(var/obj/machinery/abductor/console/C in GLOB.machines)
- if(C.team == team_number)
- return C
+/datum/game_mode/abduction/proc/post_setup_team(datum/objective_team/abductor_team/team)
+ for(var/datum/mind/M in team.members)
+ if(M.assigned_role == "Abductor Scientist")
+ M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_SCIENTIST, team)
+ else
+ M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_AGENT, team)
/datum/game_mode/abduction/check_finished()
if(!finished)
- for(var/team_number=1,team_number<=abductor_teams,team_number++)
- var/obj/machinery/abductor/console/con = get_team_console(team_number)
- var/datum/objective/objective = team_objectives[team_number]
- if (con.experiment.points >= objective.target_amount)
- SSshuttle.emergency.request(null, set_coefficient = 0.5)
- finished = 1
- return ..()
+ for(var/datum/objective_team/abductor_team/team in abductor_teams)
+ for(var/datum/objective/O in team.objectives)
+ if(O.check_completion())
+ SSshuttle.emergency.request(null, set_coefficient = 0.5)
+ finished = TRUE
+ return ..()
return ..()
/datum/game_mode/abduction/declare_completion()
- for(var/team_number=1,team_number<=abductor_teams,team_number++)
- var/obj/machinery/abductor/console/console = get_team_console(team_number)
- var/datum/objective/objective = team_objectives[team_number]
- var/team_name = team_names[team_number]
- if(console.experiment.points >= objective.target_amount)
- to_chat(world, "[team_name] team fulfilled its mission!")
+ for(var/datum/objective_team/abductor_team/team in abductor_teams)
+ var/won = TRUE
+ for(var/datum/objective/O in team.objectives)
+ if(!O.check_completion())
+ won = FALSE
+ if(won)
+ to_chat(world, "[team.name] team fulfilled its mission!")
else
- to_chat(world, "[team_name] team failed its mission.")
+ to_chat(world, "[team.name] team failed its mission.")
..()
- return 1
+ return TRUE
/datum/game_mode/proc/auto_declare_completion_abduction()
var/text = ""
@@ -200,40 +123,28 @@
text += " "
to_chat(world, text)
-//Landmarks
-// TODO: Split into separate landmarks for prettier ships
+// LANDMARKS
/obj/effect/landmark/abductor
- var/team = 1
+ var/team_number = 1
/obj/effect/landmark/abductor/agent
/obj/effect/landmark/abductor/scientist
-
// OBJECTIVES
/datum/objective/experiment
target_amount = 6
- var/team_number
/datum/objective/experiment/New()
explanation_text = "Experiment on [target_amount] humans."
/datum/objective/experiment/check_completion()
- var/ab_team = team_number
- if(owner)
- if(!owner.current || !ishuman(owner.current))
- return 0
- var/mob/living/carbon/human/H = owner.current
- if(H.dna.species.id != "abductor")
- return 0
- var/datum/species/abductor/S = H.dna.species
- ab_team = S.team
for(var/obj/machinery/abductor/experiment/E in GLOB.machines)
- if(E.team == ab_team)
- if(E.points >= target_amount)
- return 1
- else
- return 0
- return 0
+ if(!istype(team, /datum/objective_team/abductor_team))
+ return FALSE
+ var/datum/objective_team/abductor_team/T = team
+ if(E.team_number == T.team_number)
+ return E.points >= target_amount
+ return FALSE
/datum/game_mode/proc/update_abductor_icons_added(datum/mind/alien_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_ABDUCTOR]
diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
index 8c6bf1a8aa..36168a58d2 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
@@ -328,7 +328,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
return
/obj/item/paper/guides/antag/abductor/AltClick()
- return
+ return //otherwise it would fold into a paperplane.
#define BATON_STUN 0
#define BATON_SLEEP 1
diff --git a/code/game/gamemodes/miniantags/abduction/abduction_outfits.dm b/code/game/gamemodes/miniantags/abduction/abduction_outfits.dm
index aa97d1e2d8..b24bef0433 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction_outfits.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction_outfits.dm
@@ -5,20 +5,14 @@
back = /obj/item/storage/backpack
ears = /obj/item/device/radio/headset/abductor
-/datum/outfit/abductor/proc/get_team_console(team_number)
- for(var/obj/machinery/abductor/console/C in GLOB.machines)
- if(C.team == team_number)
- return C
-
/datum/outfit/abductor/proc/link_to_console(mob/living/carbon/human/H, team_number)
- if(!team_number && isabductor(H))
- var/datum/species/abductor/S = H.dna.species
- team_number = S.team
-
+ var/datum/antagonist/abductor/A = H.mind.has_antag_datum(ANTAG_DATUM_ABDUCTOR)
+ if(!team_number && A)
+ team_number = A.team.team_number
if(!team_number)
team_number = 1
- var/obj/machinery/abductor/console/console = get_team_console(team_number)
+ var/obj/machinery/abductor/console/console = get_abductor_console(team_number)
if(console)
var/obj/item/clothing/suit/armor/abductor/vest/V = locate() in H
if(V)
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/camera.dm b/code/game/gamemodes/miniantags/abduction/machinery/camera.dm
index 97893d6d2e..fd9ca0a658 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/camera.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/camera.dm
@@ -1,6 +1,6 @@
/obj/machinery/computer/camera_advanced/abductor
name = "Human Observation Console"
- var/team = 0
+ var/team_number = 0
networks = list("SS13","Abductor")
var/datum/action/innate/teleport_in/tele_in_action = new
var/datum/action/innate/teleport_out/tele_out_action = new
@@ -9,7 +9,7 @@
var/datum/action/innate/vest_disguise_swap/vest_disguise_action = new
var/datum/action/innate/set_droppoint/set_droppoint_action = new
var/obj/machinery/abductor/console/console
- z_lock = ZLEVEL_STATION_PRIMARY
+ station_lock_override = TRUE
icon = 'icons/obj/abductor.dmi'
icon_state = "camera"
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/console.dm b/code/game/gamemodes/miniantags/abduction/machinery/console.dm
index f3deebc6b7..d44ff57c96 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/console.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/console.dm
@@ -1,8 +1,13 @@
+/proc/get_abductor_console(team_number)
+ for(var/obj/machinery/abductor/console/C in GLOB.machines)
+ if(C.team_number == team_number)
+ return C
+
//Common
/obj/machinery/abductor
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
- var/team = 0
+ var/team_number = 0
//Console
@@ -139,21 +144,21 @@
return INITIALIZE_HINT_LATELOAD
/obj/machinery/abductor/console/LateInitialize()
- if(!team)
+ if(!team_number)
return
for(var/obj/machinery/abductor/pad/p in GLOB.machines)
- if(p.team == team)
+ if(p.team_number == team_number)
pad = p
break
for(var/obj/machinery/abductor/experiment/e in GLOB.machines)
- if(e.team == team)
+ if(e.team_number == team_number)
experiment = e
e.console = src
for(var/obj/machinery/computer/camera_advanced/abductor/c in GLOB.machines)
- if(c.team == team)
+ if(c.team_number == team_number)
camera = c
c.console = src
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
index 182b7e2756..0a7427b610 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
@@ -13,7 +13,7 @@
var/flash = " - || - "
var/obj/machinery/abductor/console/console
var/message_cooldown = 0
- var/breakout_time = 0.75
+ var/breakout_time = 450
/obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
@@ -50,9 +50,9 @@
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("You see [user] kicking against the door of [src]!", \
- "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
"You hear a metallic creaking from [src].")
- if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
+ if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open)
return
user.visible_message("[user] successfully broke out of [src]!", \
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index d48628ddd1..acf55e4036 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -22,27 +22,17 @@
var/nukes_left = 1 // Call 3714-PRAY right now and order more nukes! Limited offer!
var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station
var/syndies_didnt_escape = 0 //Used for tracking if the syndies got the shuttle off of the z-level
+ var/list/pre_nukeops = list()
/datum/game_mode/nuclear/pre_setup()
- var/n_players = num_players()
- var/n_agents = min(round(n_players / 10, 1), agents_possible)
-
- if(antag_candidates.len < n_agents) //In the case of having less candidates than the selected number of agents
- n_agents = antag_candidates.len
-
- while(n_agents > 0)
- var/datum/mind/new_syndicate = pick(antag_candidates)
- syndicates += new_syndicate
- antag_candidates -= new_syndicate //So it doesn't pick the same guy each time.
- n_agents--
-
- for(var/datum/mind/synd_mind in syndicates)
- synd_mind.assigned_role = "Syndicate"
- synd_mind.special_role = "Syndicate"//So they actually have a special role/N
- log_game("[synd_mind.key] (ckey) has been selected as a nuclear operative")
-
- return 1
-
+ var/n_agents = min(round(num_players() / 10), antag_candidates.len, agents_possible)
+ for(var/i = 0, i < n_agents, ++i)
+ var/datum/mind/new_op = pick_n_take(antag_candidates)
+ pre_nukeops += new_op
+ new_op.assigned_role = "Nuclear Operative"
+ new_op.special_role = "Nuclear Operative"
+ log_game("[new_op.key] (ckey) has been selected as a nuclear operative")
+ return TRUE
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
@@ -60,48 +50,36 @@
////////////////////////////////////////////////////////////////////////////////////////
/datum/game_mode/nuclear/post_setup()
-
- var/list/turf/synd_spawn = list()
-
- for(var/obj/effect/landmark/A in GLOB.landmarks_list)
- if(A.name == "Syndicate-Spawn")
- synd_spawn += get_turf(A)
- continue
-
var/nuke_code = random_nukecode()
- var/leader_selected = 0
var/agent_number = 1
- var/spawnpos = 1
+ var/datum/mind/leader = pick(pre_nukeops)
+ syndicates += pre_nukeops
+ for(var/i = 1 to pre_nukeops.len)
+ var/datum/mind/op = pre_nukeops[i]
- for(var/datum/mind/synd_mind in syndicates)
- if(spawnpos > synd_spawn.len)
- spawnpos = 2
- synd_mind.current.loc = synd_spawn[spawnpos]
-
- forge_syndicate_objectives(synd_mind)
- greet_syndicate(synd_mind)
- equip_syndicate(synd_mind.current)
+ forge_syndicate_objectives(op)
+ greet_syndicate(op)
+ equip_syndicate(op.current)
if(nuke_code)
- synd_mind.store_memory("Syndicate Nuclear Bomb Code: [nuke_code]", 0, 0)
- to_chat(synd_mind.current, "The nuclear authorization code is: [nuke_code]")
+ op.store_memory("Syndicate Nuclear Bomb Code: [nuke_code]", 0, 0)
+ to_chat(op.current, "The nuclear authorization code is: [nuke_code]")
- if(!leader_selected)
- prepare_syndicate_leader(synd_mind, nuke_code)
- leader_selected = 1
+ if(op == leader)
+ op.current.forceMove(pick(GLOB.nukeop_leader_start))
+ prepare_syndicate_leader(op, nuke_code)
else
- synd_mind.current.real_name = "[syndicate_name()] Operative #[agent_number]"
- agent_number++
- spawnpos++
- update_synd_icons_added(synd_mind)
- synd_mind.current.playsound_local(get_turf(synd_mind.current), 'sound/ambience/antag/ops.ogg',100,0)
- var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
+ op.current.forceMove(GLOB.nukeop_start[((i - 1) % GLOB.nukeop_start.len) + 1])
+ op.current.real_name = "[syndicate_name()] Operative #[agent_number++]"
+ update_synd_icons_added(op)
+ op.current.playsound_local(get_turf(op.current), 'sound/ambience/antag/ops.ogg',100,0)
+
+ var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
if(nuke)
nuke.r_code = nuke_code
return ..()
-
/datum/game_mode/proc/prepare_syndicate_leader(datum/mind/synd_mind, nuke_code)
var/leader_title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
spawn(1)
@@ -161,6 +139,12 @@
synd_mob.equipOutfit(/datum/outfit/syndicate/no_crystals)
return 1
+/datum/game_mode/nuclear/OnNukeExplosion(off_station)
+ ..()
+ nukes_left--
+ var/obj/docking_port/mobile/Shuttle = SSshuttle.getShuttle("syndicate")
+ syndies_didnt_escape = (Shuttle && (Shuttle.z == ZLEVEL_CENTCOM || Shuttle.z == ZLEVEL_TRANSIT)) ? 0 : 1
+ nuke_off_station = off_station
/datum/game_mode/nuclear/check_win()
if (nukes_left == 0)
diff --git a/code/game/gamemodes/nuclear/nuclear_challenge.dm b/code/game/gamemodes/nuclear/nuclear_challenge.dm
index 7b2a20a297..f51b9ac914 100644
--- a/code/game/gamemodes/nuclear/nuclear_challenge.dm
+++ b/code/game/gamemodes/nuclear/nuclear_challenge.dm
@@ -19,7 +19,7 @@
return
declaring_war = TRUE
- var/are_you_sure = alert(user, "Consult your team carefully before you declare war on [station_name()]]. Are you sure you want to alert the enemy crew? You have [-round((world.time-SSticker.round_start_time - CHALLENGE_TIME_LIMIT)/10)] seconds to decide", "Declare war?", "Yes", "No")
+ var/are_you_sure = alert(user, "Consult your team carefully before you declare war on [station_name()]]. Are you sure you want to alert the enemy crew? You have [DisplayTimeText(world.time-SSticker.round_start_time - CHALLENGE_TIME_LIMIT)] to decide", "Declare war?", "Yes", "No")
declaring_war = FALSE
if(!check_allowed(user))
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index 7642801a6a..8870399f24 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -81,6 +81,20 @@
/obj/machinery/nuclearbomb/syndicate
//ui_style = "syndicate" // actually the nuke op bomb is a stole nt bomb
+/obj/machinery/nuclearbomb/syndicate/get_cinematic_type(off_station)
+ var/datum/game_mode/nuclear/NM = SSticker.mode
+ switch(off_station)
+ if(0)
+ if(istype(NM) && NM.syndies_didnt_escape)
+ return CINEMATIC_ANNIHILATION
+ else
+ return CINEMATIC_NUKE_WIN
+ if(1)
+ return CINEMATIC_NUKE_MISS
+ if(2)
+ return CINEMATIC_NUKE_FAR
+ return CINEMATIC_NUKE_FAR
+
/obj/machinery/nuclearbomb/syndicate/Initialize()
. = ..()
var/obj/machinery/nuclearbomb/existing = locate("syndienuke") in GLOB.nuke_list
@@ -422,12 +436,12 @@
update_icon()
sound_to_playing_players('sound/machines/alarm.ogg')
if(SSticker && SSticker.mode)
- SSticker.mode.explosion_in_progress = 1
+ SSticker.roundend_check_paused = TRUE
sleep(100)
if(!core)
- SSticker.station_explosion_cinematic(3,"no_core",src)
- SSticker.mode.explosion_in_progress = 0
+ Cinematic(CINEMATIC_NUKE_NO_CORE,world)
+ SSticker.roundend_check_paused = FALSE
return
GLOB.enter_allowed = 0
@@ -437,28 +451,37 @@
var/area/A = get_area(bomb_location)
if(bomb_location && (bomb_location.z in GLOB.station_z_levels))
if(istype(A, /area/space))
- off_station = NUKE_MISS_STATION
+ off_station = NUKE_NEAR_MISS
if((bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE)))
- off_station = NUKE_MISS_STATION
+ off_station = NUKE_NEAR_MISS
else if((istype(A, /area/syndicate_mothership) || (istype(A, /area/shuttle/syndicate)) && bomb_location.z == ZLEVEL_CENTCOM))
off_station = NUKE_SYNDICATE_BASE
else
- off_station = NUKE_NEAR_MISS
+ off_station = NUKE_MISS_STATION
- if(istype(SSticker.mode, /datum/game_mode/nuclear))
- var/obj/docking_port/mobile/Shuttle = SSshuttle.getShuttle("syndicate")
- var/datum/game_mode/nuclear/NM = SSticker.mode
- NM.syndies_didnt_escape = (Shuttle && (Shuttle.z == ZLEVEL_CENTCOM || Shuttle.z == ZLEVEL_TRANSIT)) ? 0 : 1
- NM.nuke_off_station = off_station
+ if(off_station < 2)
+ SSshuttle.registerHostileEnvironment(src)
+ SSshuttle.lockdown = TRUE
- SSticker.station_explosion_cinematic(off_station,null,src)
- if(SSticker.mode)
- if(istype(SSticker.mode, /datum/game_mode/nuclear))
- var/datum/game_mode/nuclear/NM = SSticker.mode
- NM.nukes_left --
- if(!SSticker.mode.check_finished())//If the mode does not deal with the nuke going off so just reboot because everyone is stuck as is
- SSticker.Reboot("Station destroyed by Nuclear Device.", "nuke - unhandled ending")
+ //Cinematic
+ SSticker.mode.OnNukeExplosion(off_station)
+ var/bombz = z
+ Cinematic(get_cinematic_type(off_station),world,CALLBACK(SSticker,/datum/controller/subsystem/ticker/proc/station_explosion_detonation,src))
+ INVOKE_ASYNC(GLOBAL_PROC,.proc/KillEveryoneOnZLevel,bombz)
+ SSticker.roundend_check_paused = FALSE
+/obj/machinery/nuclearbomb/proc/get_cinematic_type(off_station)
+ if(off_station < 2)
+ return CINEMATIC_SELFDESTRUCT
+ else
+ return CINEMATIC_SELFDESTRUCT_MISS
+
+/proc/KillEveryoneOnZLevel(z)
+ if(!z)
+ return
+ for(var/mob/M in GLOB.mob_list)
+ if(M.stat != DEAD && M.z == z)
+ M.gib()
/*
This is here to make the tiles around the station mininuke change when it's armed.
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 75ed90d712..c00328243a 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -121,7 +121,7 @@
return target
/datum/objective/assassinate/check_completion()
- return !target || !considered_alive(target)
+ return !considered_alive(target) || considered_afk(target)
/datum/objective/assassinate/update_explanation_text()
..()
diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm
index 8384892044..d538c7f75e 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -154,8 +154,7 @@
var/obj/item/device/assembly/flash/T = new(mob)
- var/obj/item/toy/crayon/spraycan/R = new(mob)
- var/obj/item/clothing/glasses/hud/security/chameleon/C = new(mob)
+ var/obj/item/organ/cyberimp/eyes/hud/security/syndicate/S = new(mob)
var/list/slots = list (
"backpack" = slot_in_backpack,
@@ -163,13 +162,8 @@
"right pocket" = slot_r_store
)
var/where = mob.equip_in_one_of_slots(T, slots)
- var/where2 = mob.equip_in_one_of_slots(C, slots)
- mob.equip_in_one_of_slots(R,slots)
-
- if (!where2)
- to_chat(mob, "The Syndicate were unfortunately unable to get you a chameleon security HUD.")
- else
- to_chat(mob, "The chameleon security HUD in your [where2] will help you keep track of who is mindshield-implanted, and unable to be recruited.")
+ S.Insert(mob, special = FALSE, drop_if_replaced = FALSE)
+ to_chat(mob, "Your eyes have been implanted with a cybernetic security HUD which will help you keep track of who is mindshield-implanted, and therefore unable to be recruited.")
if (!where)
to_chat(mob, "The Syndicate were unfortunately unable to get you a flash.")
diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm
index ae7143d5a2..aae0261320 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -119,7 +119,7 @@
////////////////////////////Proc for moving soul in and out off stone//////////////////////////////////////
-/obj/item/device/soulstone/proc/transfer_soul(choice as text, target, mob/user).
+/obj/item/device/soulstone/proc/transfer_soul(choice as text, target, mob/user)
switch(choice)
if("FORCE")
if(!iscarbon(target)) //TODO: Add sacrifice stoning for non-organics, just because you have no body doesnt mean you dont have a soul
diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm
index 4f691e053f..8a4c854d76 100644
--- a/code/game/machinery/ai_slipper.dm
+++ b/code/game/machinery/ai_slipper.dm
@@ -43,7 +43,7 @@
to_chat(user, "[src] is out of foam and cannot be activated.")
return
if(cooldown_time > world.time)
- to_chat(user, "[src] cannot be activated for another [round((world.time - cooldown_time) * 0.1)] second\s.")
+ to_chat(user, "[src] cannot be activated for [DisplayTimeText(world.time - cooldown_time)].")
return
new /obj/effect/particle_effect/foam(loc)
uses--
diff --git a/code/game/machinery/aug_manipulator.dm b/code/game/machinery/aug_manipulator.dm
index ff072fd010..299b0500ce 100644
--- a/code/game/machinery/aug_manipulator.dm
+++ b/code/game/machinery/aug_manipulator.dm
@@ -11,6 +11,9 @@
var/initial_icon_state
var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', "security" = 'icons/mob/augmentation/augments_security.dmi', "mining" = 'icons/mob/augmentation/augments_mining.dmi')
+/obj/machinery/aug_manipulator/examine(mob/user)
+ ..()
+ to_chat(user, "Alt-click to eject the limb.")
/obj/machinery/aug_manipulator/Initialize()
initial_icon_state = initial(icon_state)
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index d8ba1d4cb5..9f252effa6 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -3,7 +3,8 @@
desc = "Used to access the various cameras on the station."
icon_screen = "cameras"
icon_keyboard = "security_key"
- var/z_lock = null // Lock use to this zlevel
+ var/list/z_lock = list() // Lock use to these z levels
+ var/station_lock_override = FALSE
var/mob/camera/aiEye/remote/eyeobj
var/mob/living/current_user = null
var/list/networks = list("SS13")
@@ -13,6 +14,11 @@
light_color = LIGHT_COLOR_RED
+/obj/machinery/computer/camera_advanced/Initialize()
+ . = ..()
+ if(station_lock_override)
+ z_lock = GLOB.station_z_levels.Copy()
+
/obj/machinery/computer/camera_advanced/syndie
icon_keyboard = "syndie_key"
@@ -76,7 +82,7 @@
if(!eyeobj.eye_initialized)
var/camera_location
for(var/obj/machinery/camera/C in GLOB.cameranet.cameras)
- if(!C.can_use() || z_lock && C.z != z_lock)
+ if(!C.can_use() || z_lock.len && !(C.z in z_lock))
continue
if(C.network & networks)
camera_location = get_turf(C)
@@ -201,7 +207,7 @@
var/list/L = list()
for (var/obj/machinery/camera/cam in GLOB.cameranet.cameras)
- if(origin.z_lock && cam.z != origin.z_lock)
+ if(origin.z_lock.len && !(cam.z in origin.z_lock))
continue
L.Add(cam)
diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm
index aafe74f2b3..105fb64042 100644
--- a/code/game/machinery/computer/dna_console.dm
+++ b/code/game/machinery/computer/dna_console.dm
@@ -169,7 +169,7 @@
if("working")
temp_html += status
temp_html += "
"
+ dat += "Track Length: [DisplayTimeText(selection.song_length)]
"
dat += " DJ's Soundboard: "
dat +="
"
dat += "Air Horn "
@@ -122,7 +122,7 @@
return
if(!active)
if(stop > world.time)
- to_chat(usr, "Error: The device is still resetting from the last activation, it will be ready again in [round((stop-world.time)/10)] seconds.")
+ to_chat(usr, "Error: The device is still resetting from the last activation, it will be ready again in [DisplayTimeText(stop-world.time)].")
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
return
active = TRUE
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index 333aa6ac55..f0e1e8a18a 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -110,13 +110,17 @@
/obj/item/grenade/barrier
name = "barrier grenade"
- desc = "Instant cover. Alt+click to toggle modes."
+ desc = "Instant cover."
icon = 'icons/obj/grenade.dmi'
icon_state = "flashbang"
item_state = "flashbang"
actions_types = list(/datum/action/item_action/toggle_barrier_spread)
var/mode = SINGLE
+/obj/item/grenade/barrier/examine(mob/user)
+ ..()
+ to_chat(user, "Alt-click to toggle modes.")
+
/obj/item/grenade/barrier/AltClick(mob/living/user)
if(!istype(user) || user.incapacitated())
return
diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm
index 4085b4edb4..034a260925 100644
--- a/code/game/machinery/dna_scanner.dm
+++ b/code/game/machinery/dna_scanner.dm
@@ -15,7 +15,7 @@
var/scan_level
var/precision_coeff
var/message_cooldown
- var/breakout_time = 2
+ var/breakout_time = 1200
/obj/machinery/dna_scannernew/RefreshParts()
scan_level = 0
@@ -73,9 +73,9 @@
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("You see [user] kicking against the door of [src]!", \
- "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
"You hear a metallic creaking from [src].")
- if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
+ if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked)
return
locked = FALSE
diff --git a/code/game/machinery/gulag_teleporter.dm b/code/game/machinery/gulag_teleporter.dm
index d77e91af90..2d7c7708b3 100644
--- a/code/game/machinery/gulag_teleporter.dm
+++ b/code/game/machinery/gulag_teleporter.dm
@@ -20,7 +20,7 @@ The console is located at computer/gulag_teleporter.dm
circuit = /obj/item/circuitboard/machine/gulag_teleporter
var/locked = FALSE
var/message_cooldown
- var/breakout_time = 1
+ var/breakout_time = 600
var/jumpsuit_type = /obj/item/clothing/under/rank/prisoner
var/shoes_type = /obj/item/clothing/shoes/sneakers/orange
var/obj/machinery/gulag_item_reclaimer/linked_reclaimer
@@ -104,9 +104,9 @@ The console is located at computer/gulag_teleporter.dm
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("You see [user] kicking against the door of [src]!", \
- "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
"You hear a metallic creaking from [src].")
- if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
+ if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked)
return
locked = FALSE
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index f50ddbdf7e..204ae83c9d 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -305,7 +305,7 @@ GLOBAL_LIST_EMPTY(allCasters)
dat+="Creating new Feed Message..."
dat+="Receiving Channel: [channel_name] "
dat+="Message Author: [scanned_user] "
- dat+="Message Body: [parsepencode(msg, user, SIGNFONT)] "
+ dat+="Message Body: [parsemarkdown(msg, user)] "
dat+="Attach Photo: [(photo ? "Photo Attached" : "No Photo")]"
dat+="Comments [allow_comments ? "Enabled" : "Disabled"] "
dat+=" Submit
Cancel "
@@ -555,7 +555,7 @@ GLOBAL_LIST_EMPTY(allCasters)
if(msg =="" || msg=="\[REDACTED\]" || scanned_user == "Unknown" || channel_name == "" )
screen=6
else
- GLOB.news_network.SubmitArticle("[parsepencode(msg, usr, SIGNFONT)]", scanned_user, channel_name, photo, 0, allow_comments)
+ GLOB.news_network.SubmitArticle("[parsemarkdown(msg, usr)]", scanned_user, channel_name, photo, 0, allow_comments)
SSblackbox.inc("newscaster_stories",1)
screen=4
msg = ""
diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm
index 3fb3447f61..34d2edc56c 100644
--- a/code/game/machinery/pipe/construction.dm
+++ b/code/game/machinery/pipe/construction.dm
@@ -213,6 +213,8 @@ GLOBAL_LIST_INIT(pipeID2State, list(
return ..()
if (!isturf(src.loc))
return 1
+
+ add_fingerprint(user)
fixdir()
if(pipe_type in list(PIPE_GAS_MIXER, PIPE_GAS_FILTER))
diff --git a/code/game/machinery/quantum_pad.dm b/code/game/machinery/quantum_pad.dm
index e86f78722b..6af0240214 100644
--- a/code/game/machinery/quantum_pad.dm
+++ b/code/game/machinery/quantum_pad.dm
@@ -79,7 +79,7 @@
return
if(world.time < last_teleport + teleport_cooldown)
- to_chat(user, "[src] is recharging power. Please wait [round((last_teleport + teleport_cooldown - world.time) / 10)] seconds.")
+ to_chat(user, "[src] is recharging power. Please wait [DisplayTimeText(last_teleport + teleport_cooldown - world.time)].")
return
if(teleporting)
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index a78fa50a6a..7c51c383fa 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -27,7 +27,7 @@
var/uv_super = FALSE
var/uv_cycles = 6
var/message_cooldown
- var/breakout_time = 0.5
+ var/breakout_time = 300
/obj/machinery/suit_storage_unit/standard_unit
suit_type = /obj/item/clothing/suit/space/eva
@@ -267,9 +267,9 @@
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("You see [user] kicking against the doors of [src]!", \
- "You start kicking against the doors... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You start kicking against the doors... (this will take about [DisplayTimeText(breakout_time)].)", \
"You hear a thump from [src].")
- if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
+ if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src )
return
user.visible_message("[user] successfully broke out of [src]!", \
diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm
index 4e8e42e10f..626c405284 100644
--- a/code/game/mecha/combat/combat.dm
+++ b/code/game/mecha/combat/combat.dm
@@ -1,37 +1,26 @@
-/obj/mecha/combat
- force = 30
- internal_damage_threshold = 50
- armor = list(melee = 30, bullet = 30, laser = 15, energy = 20, bomb = 20, bio = 0, rad = 0, fire = 100, acid = 100)
-
-/obj/mecha/combat/CheckParts(list/parts_list)
- ..()
- var/obj/item/stock_parts/capacitor/C = locate() in contents
- var/obj/item/stock_parts/scanning_module/SM = locate() in contents
- step_energy_drain = 20 - (5 * SM.rating) //10 is normal, so on lowest part its worse, on second its ok and on higher its real good up to 0 on best
- armor["energy"] += (C.rating * 10) //Each level of capacitor protects the mech against emp by 10%
- qdel(C)
- qdel(SM)
-
-/obj/mecha/combat/moved_inside(mob/living/carbon/human/H)
- if(..())
- if(H.client && H.client.mouse_pointer_icon == initial(H.client.mouse_pointer_icon))
- H.client.mouse_pointer_icon = 'icons/mecha/mecha_mouse.dmi'
- return 1
- else
- return 0
-
-/obj/mecha/combat/mmi_moved_inside(obj/item/device/mmi/mmi_as_oc,mob/user)
- if(..())
- if(occupant.client && occupant.client.mouse_pointer_icon == initial(occupant.client.mouse_pointer_icon))
- occupant.client.mouse_pointer_icon = 'icons/mecha/mecha_mouse.dmi'
- return 1
- else
- return 0
-
-
-/obj/mecha/combat/go_out()
- if(occupant && occupant.client && occupant.client.mouse_pointer_icon == 'icons/mecha/mecha_mouse.dmi')
- occupant.client.mouse_pointer_icon = initial(occupant.client.mouse_pointer_icon)
- ..()
-
-
+/obj/mecha/combat
+ force = 30
+ internal_damage_threshold = 50
+ armor = list(melee = 30, bullet = 30, laser = 15, energy = 20, bomb = 20, bio = 0, rad = 0, fire = 100, acid = 100)
+
+/obj/mecha/combat/moved_inside(mob/living/carbon/human/H)
+ if(..())
+ if(H.client && H.client.mouse_pointer_icon == initial(H.client.mouse_pointer_icon))
+ H.client.mouse_pointer_icon = 'icons/mecha/mecha_mouse.dmi'
+ return 1
+ else
+ return 0
+
+/obj/mecha/combat/mmi_moved_inside(obj/item/device/mmi/mmi_as_oc,mob/user)
+ if(..())
+ if(occupant.client && occupant.client.mouse_pointer_icon == initial(occupant.client.mouse_pointer_icon))
+ occupant.client.mouse_pointer_icon = 'icons/mecha/mecha_mouse.dmi'
+ return 1
+ else
+ return 0
+
+
+/obj/mecha/combat/go_out()
+ if(occupant && occupant.client && occupant.client.mouse_pointer_icon == 'icons/mecha/mecha_mouse.dmi')
+ occupant.client.mouse_pointer_icon = initial(occupant.client.mouse_pointer_icon)
+ ..()
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index ed2a1ff82a..9b27e1e7c6 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -202,6 +202,19 @@
GLOB.mechas_list -= src //global mech list
return ..()
+/obj/mecha/CheckParts(list/parts_list)
+ ..()
+ var/obj/item/C = locate(/obj/item/stock_parts/cell) in contents
+ cell = C
+ var/obj/item/stock_parts/scanning_module/SM = locate() in contents
+ var/obj/item/stock_parts/capacitor/CP = locate() in contents
+ if(SM)
+ step_energy_drain = 20 - (5 * SM.rating) //10 is normal, so on lowest part its worse, on second its ok and on higher its real good up to 0 on best
+ qdel(SM)
+ if(CP)
+ armor["energy"] += (CP.rating * 10) //Each level of capacitor protects the mech against emp by 10%
+ qdel(CP)
+
////////////////////////
////// Helpers /////////
////////////////////////
diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm
index 24c1c513c3..27aeea4c09 100644
--- a/code/game/mecha/mecha_construction_paths.dm
+++ b/code/game/mecha/mecha_construction_paths.dm
@@ -102,8 +102,11 @@
/datum/construction/reversible/mecha/ripley
- result = "/obj/mecha/working/ripley"
+ result = /obj/mecha/working/ripley
steps = list(
+ //0, dummy step used to stop the steps from finishing and spawn_result() being called automatically.
+ list("desc"="You shouldn't be able to see this."),
+
//1
list("key"=/obj/item/weldingtool,
"backkey"=/obj/item/wrench,
@@ -127,38 +130,47 @@
//6
list("key"=/obj/item/stack/sheet/metal,
"backkey"=/obj/item/screwdriver,
- "desc"="Peripherals control module is secured."),
+ "desc"="The power cell is secured."),
//7
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Peripherals control module is installed."),
+ "desc"="The power cell is installed."),
//8
- list("key"=/obj/item/circuitboard/mecha/ripley/peripherals,
+ list("key"=/obj/item/stock_parts/cell,
"backkey"=/obj/item/screwdriver,
- "desc"="Central control module is secured."),
+ "desc"="Peripherals control module is secured."),
//9
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Central control module is installed."),
+ "desc"="Peripherals control module is installed."),
//10
+ list("key"=/obj/item/circuitboard/mecha/ripley/peripherals,
+ "backkey"=/obj/item/screwdriver,
+ "desc"="Central control module is secured."),
+ //11
+ list("key"=/obj/item/screwdriver,
+ "backkey"=/obj/item/crowbar,
+ "desc"="Central control module is installed."),
+ //12
list("key"=/obj/item/circuitboard/mecha/ripley/main,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is adjusted."),
- //11
+ //13
list("key"=/obj/item/wirecutters,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is added."),
- //12
+ //14
list("key"=/obj/item/stack/cable_coil,
"backkey"=/obj/item/screwdriver,
"desc"="The hydraulic systems are active."),
- //13
+ //15
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/wrench,
"desc"="The hydraulic systems are connected."),
- //14
+ //16
list("key"=/obj/item/wrench,
"desc"="The hydraulic systems are disconnected.")
+
)
/datum/construction/reversible/mecha/ripley/action(atom/used_atom,mob/user)
@@ -170,24 +182,24 @@
//TODO: better messages.
switch(index)
- if(14)
+ if(17)
user.visible_message("[user] connects the [holder] hydraulic systems", "You connect the [holder] hydraulic systems.")
holder.icon_state = "ripley1"
- if(13)
+ if(16)
if(diff==FORWARD)
user.visible_message("[user] activates the [holder] hydraulic systems.", "You activate the [holder] hydraulic systems.")
holder.icon_state = "ripley2"
else
user.visible_message("[user] disconnects the [holder] hydraulic systems", "You disconnect the [holder] hydraulic systems.")
holder.icon_state = "ripley0"
- if(12)
+ if(15)
if(diff==FORWARD)
user.visible_message("[user] adds the wiring to the [holder].", "You add the wiring to the [holder].")
holder.icon_state = "ripley3"
else
user.visible_message("[user] deactivates the [holder] hydraulic systems.", "You deactivate the [holder] hydraulic systems.")
holder.icon_state = "ripley1"
- if(11)
+ if(14)
if(diff==FORWARD)
user.visible_message("[user] adjusts the wiring of the [holder].", "You adjust the wiring of the [holder].")
holder.icon_state = "ripley4"
@@ -196,7 +208,7 @@
var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder))
coil.amount = 4
holder.icon_state = "ripley2"
- if(10)
+ if(13)
if(diff==FORWARD)
user.visible_message("[user] installs the central control module into the [holder].", "You install the central computer mainboard into the [holder].")
qdel(used_atom)
@@ -204,7 +216,7 @@
else
user.visible_message("[user] disconnects the wiring of the [holder].", "You disconnect the wiring of the [holder].")
holder.icon_state = "ripley3"
- if(9)
+ if(12)
if(diff==FORWARD)
user.visible_message("[user] secures the mainboard.", "You secure the mainboard.")
holder.icon_state = "ripley6"
@@ -212,7 +224,7 @@
user.visible_message("[user] removes the central control module from the [holder].", "You remove the central computer mainboard from the [holder].")
new /obj/item/circuitboard/mecha/ripley/main(get_turf(holder))
holder.icon_state = "ripley4"
- if(8)
+ if(11)
if(diff==FORWARD)
user.visible_message("[user] installs the peripherals control module into the [holder].", "You install the peripherals control module into the [holder].")
qdel(used_atom)
@@ -220,7 +232,7 @@
else
user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.")
holder.icon_state = "ripley5"
- if(7)
+ if(10)
if(diff==FORWARD)
user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.")
holder.icon_state = "ripley8"
@@ -228,54 +240,73 @@
user.visible_message("[user] removes the peripherals control module from the [holder].", "You remove the peripherals control module from the [holder].")
new /obj/item/circuitboard/mecha/ripley/peripherals(get_turf(holder))
holder.icon_state = "ripley6"
- if(6)
+ if(9)
if(diff==FORWARD)
- user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ user.visible_message("[user] installs the power cell into the [holder].", "You install the power cell into the [holder].")
+ var/obj/item/I = used_atom
+ user.transferItemToLoc(I, holder, TRUE)
holder.icon_state = "ripley9"
else
user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.")
holder.icon_state = "ripley7"
- if(5)
+ if(8)
+ if(diff==FORWARD)
+ user.visible_message("[user] secures the power cell.", "You secure the power cell.")
+ holder.icon_state = "ripley10"
+ else
+ user.visible_message("[user] prys the power cell from [holder].", "You pry the power cell from [holder].")
+ var/obj/item/I = locate(/obj/item/stock_parts/cell) in holder
+ I.forceMove(holder.drop_location())
+ holder.icon_state = "ripley8"
+ if(7)
+ if(diff==FORWARD)
+ user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ holder.icon_state = "ripley11"
+ else
+ user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.")
+ holder.icon_state = "ripley9"
+ if(6)
if(diff==FORWARD)
user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.")
- holder.icon_state = "ripley10"
+ holder.icon_state = "ripley12"
else
user.visible_message("[user] pries internal armor layer from the [holder].", "You pry internal armor layer from the [holder].")
var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder))
MS.amount = 5
- holder.icon_state = "ripley8"
- if(4)
+ holder.icon_state = "ripley10"
+ if(5)
if(diff==FORWARD)
user.visible_message("[user] welds the internal armor layer to the [holder].", "You weld the internal armor layer to the [holder].")
- holder.icon_state = "ripley11"
+ holder.icon_state = "ripley13"
else
user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.")
- holder.icon_state = "ripley9"
- if(3)
+ holder.icon_state = "ripley11"
+ if(4)
if(diff==FORWARD)
user.visible_message("[user] installs the external reinforced armor layer to the [holder].", "You install the external reinforced armor layer to the [holder].")
- holder.icon_state = "ripley12"
+ holder.icon_state = "ripley14"
else
user.visible_message("[user] cuts the internal armor layer from the [holder].", "You cut the internal armor layer from the [holder].")
- holder.icon_state = "ripley10"
- if(2)
+ holder.icon_state = "ripley12"
+ if(3)
if(diff==FORWARD)
user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.")
- holder.icon_state = "ripley13"
+ holder.icon_state = "ripley15"
else
user.visible_message("[user] pries external armor layer from the [holder].", "You pry external armor layer from the [holder].")
var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder))
MS.amount = 5
- holder.icon_state = "ripley11"
- if(1)
+ holder.icon_state = "ripley13"
+ if(2)
if(diff==FORWARD)
user.visible_message("[user] welds the external armor layer to the [holder].", "You weld the external armor layer to the [holder].")
+ spawn_mecha_result()
else
user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.")
- holder.icon_state = "ripley12"
+ holder.icon_state = "ripley14"
return 1
-/datum/construction/reversible/mecha/ripley/spawn_result()
+/datum/construction/reversible/mecha/ripley/spawn_mecha_result()
..()
SSblackbox.inc("mecha_ripley_created",1)
return
@@ -311,8 +342,11 @@
/datum/construction/reversible/mecha/gygax
- result = "/obj/mecha/combat/gygax"
+ result = /obj/mecha/combat/gygax
steps = list(
+ //0, dummy step used to stop the steps from finishing and spawn_result() being called automatically.
+ list("desc"="You shouldn't be able to see this."),
+
//1
list("key"=/obj/item/weldingtool,
"backkey"=/obj/item/wrench,
@@ -336,60 +370,68 @@
//6
list("key"=/obj/item/stack/sheet/metal,
"backkey"=/obj/item/screwdriver,
- "desc"="Advanced capacitor is secured."),
+ "desc"="The power cell is secured."),
//7
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Advanced capacitor is installed."),
+ "desc"="The power cell is installed."),
//8
- list("key"=/obj/item/stock_parts/capacitor,
+ list("key"=/obj/item/stock_parts/cell,
"backkey"=/obj/item/screwdriver,
- "desc"="Advanced scanner module is secured."),
+ "desc"="Advanced capacitor is secured."),
//9
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Advanced scanner module is installed."),
+ "desc"="Advanced capacitor is installed."),
//10
- list("key"=/obj/item/stock_parts/scanning_module,
+ list("key"=/obj/item/stock_parts/capacitor,
"backkey"=/obj/item/screwdriver,
- "desc"="Weapon control module is secured."),
+ "desc"="Advanced scanner module is secured."),
//11
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Weapon control module is installed."),
+ "desc"="Advanced scanner module is installed."),
//12
- list("key"=/obj/item/circuitboard/mecha/gygax/targeting,
+ list("key"=/obj/item/stock_parts/scanning_module,
"backkey"=/obj/item/screwdriver,
- "desc"="Peripherals control module is secured."),
+ "desc"="Weapon control module is secured."),
//13
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Peripherals control module is installed."),
+ "desc"="Weapon control module is installed."),
//14
- list("key"=/obj/item/circuitboard/mecha/gygax/peripherals,
+ list("key"=/obj/item/circuitboard/mecha/gygax/targeting,
"backkey"=/obj/item/screwdriver,
- "desc"="Central control module is secured."),
+ "desc"="Peripherals control module is secured."),
//15
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Central control module is installed."),
+ "desc"="Peripherals control module is installed."),
//16
+ list("key"=/obj/item/circuitboard/mecha/gygax/peripherals,
+ "backkey"=/obj/item/screwdriver,
+ "desc"="Central control module is secured."),
+ //17
+ list("key"=/obj/item/screwdriver,
+ "backkey"=/obj/item/crowbar,
+ "desc"="Central control module is installed."),
+ //18
list("key"=/obj/item/circuitboard/mecha/gygax/main,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is adjusted."),
- //17
+ //19
list("key"=/obj/item/wirecutters,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is added."),
- //18
+ //20
list("key"=/obj/item/stack/cable_coil,
"backkey"=/obj/item/screwdriver,
"desc"="The hydraulic systems are active."),
- //19
+ //21
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/wrench,
"desc"="The hydraulic systems are connected."),
- //20
+ //22
list("key"=/obj/item/wrench,
"desc"="The hydraulic systems are disconnected.")
)
@@ -403,24 +445,24 @@
//TODO: better messages.
switch(index)
- if(20)
+ if(23)
user.visible_message("[user] connects the [holder] hydraulic systems", "You connect the [holder] hydraulic systems.")
holder.icon_state = "gygax1"
- if(19)
+ if(22)
if(diff==FORWARD)
user.visible_message("[user] activates the [holder] hydraulic systems.", "You activate the [holder] hydraulic systems.")
holder.icon_state = "gygax2"
else
user.visible_message("[user] disconnects the [holder] hydraulic systems", "You disconnect the [holder] hydraulic systems.")
holder.icon_state = "gygax0"
- if(18)
+ if(21)
if(diff==FORWARD)
user.visible_message("[user] adds the wiring to the [holder].", "You add the wiring to the [holder].")
holder.icon_state = "gygax3"
else
user.visible_message("[user] deactivates the [holder] hydraulic systems.", "You deactivate the [holder] hydraulic systems.")
holder.icon_state = "gygax1"
- if(17)
+ if(20)
if(diff==FORWARD)
user.visible_message("[user] adjusts the wiring of the [holder].", "You adjust the wiring of the [holder].")
holder.icon_state = "gygax4"
@@ -429,7 +471,7 @@
var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder))
coil.amount = 4
holder.icon_state = "gygax2"
- if(16)
+ if(19)
if(diff==FORWARD)
user.visible_message("[user] installs the central control module into the [holder].", "You install the central computer mainboard into the [holder].")
qdel(used_atom)
@@ -437,7 +479,7 @@
else
user.visible_message("[user] disconnects the wiring of the [holder].", "You disconnect the wiring of the [holder].")
holder.icon_state = "gygax3"
- if(15)
+ if(18)
if(diff==FORWARD)
user.visible_message("[user] secures the mainboard.", "You secure the mainboard.")
holder.icon_state = "gygax6"
@@ -445,7 +487,7 @@
user.visible_message("[user] removes the central control module from the [holder].", "You remove the central computer mainboard from the [holder].")
new /obj/item/circuitboard/mecha/gygax/main(get_turf(holder))
holder.icon_state = "gygax4"
- if(14)
+ if(17)
if(diff==FORWARD)
user.visible_message("[user] installs the peripherals control module into the [holder].", "You install the peripherals control module into the [holder].")
qdel(used_atom)
@@ -453,7 +495,7 @@
else
user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.")
holder.icon_state = "gygax5"
- if(13)
+ if(16)
if(diff==FORWARD)
user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.")
holder.icon_state = "gygax8"
@@ -461,7 +503,7 @@
user.visible_message("[user] removes the peripherals control module from the [holder].", "You remove the peripherals control module from the [holder].")
new /obj/item/circuitboard/mecha/gygax/peripherals(get_turf(holder))
holder.icon_state = "gygax6"
- if(12)
+ if(15)
if(diff==FORWARD)
user.visible_message("[user] installs the weapon control module into the [holder].", "You install the weapon control module into the [holder].")
qdel(used_atom)
@@ -469,7 +511,7 @@
else
user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.")
holder.icon_state = "gygax7"
- if(11)
+ if(14)
if(diff==FORWARD)
user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.")
holder.icon_state = "gygax10"
@@ -477,7 +519,7 @@
user.visible_message("[user] removes the weapon control module from the [holder].", "You remove the weapon control module from the [holder].")
new /obj/item/circuitboard/mecha/gygax/targeting(get_turf(holder))
holder.icon_state = "gygax8"
- if(10)
+ if(13)
if(diff==FORWARD)
user.visible_message("[user] installs scanner module to the [holder].", "You install scanner module to the [holder].")
var/obj/item/I = used_atom
@@ -486,7 +528,7 @@
else
user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.")
holder.icon_state = "gygax9"
- if(9)
+ if(12)
if(diff==FORWARD)
user.visible_message("[user] secures the advanced scanner module.", "You secure the scanner module.")
holder.icon_state = "gygax12"
@@ -495,7 +537,7 @@
var/obj/item/I = locate(/obj/item/stock_parts/scanning_module) in holder
I.loc = get_turf(holder)
holder.icon_state = "gygax10"
- if(8)
+ if(11)
if(diff==FORWARD)
user.visible_message("[user] installs capacitor to the [holder].", "You install capacitor to the [holder].")
var/obj/item/I = used_atom
@@ -504,7 +546,7 @@
else
user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.")
holder.icon_state = "gygax11"
- if(7)
+ if(10)
if(diff==FORWARD)
user.visible_message("[user] secures the capacitor.", "You secure the capacitor.")
holder.icon_state = "gygax14"
@@ -513,57 +555,74 @@
var/obj/item/I = locate(/obj/item/stock_parts/capacitor) in holder
I.loc = get_turf(holder)
holder.icon_state = "gygax12"
- if(6)
+ if(9)
if(diff==FORWARD)
- user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ user.visible_message("[user] installs the power cell into the [holder].", "You install the power cell into the [holder].")
+ var/obj/item/I = used_atom
+ user.transferItemToLoc(I, holder, TRUE)
holder.icon_state = "gygax15"
else
user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.")
holder.icon_state = "gygax13"
- if(5)
+ if(8)
+ if(diff==FORWARD)
+ user.visible_message("[user] secures the power cell.", "You secure the power cell.")
+ holder.icon_state = "gygax16"
+ else
+ user.visible_message("[user] prys the power cell from [holder].", "You pry the power cell from [holder].")
+ var/obj/item/I = locate(/obj/item/stock_parts/cell) in holder
+ I.forceMove(holder.drop_location())
+ holder.icon_state = "gygax14"
+ if(7)
+ if(diff==FORWARD)
+ user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ holder.icon_state = "gygax17"
+ else
+ user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.")
+ holder.icon_state = "gygax15"
+ if(6)
if(diff==FORWARD)
user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.")
- holder.icon_state = "gygax16"
+ holder.icon_state = "gygax18"
else
user.visible_message("[user] pries internal armor layer from the [holder].", "You pry internal armor layer from the [holder].")
var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder))
MS.amount = 5
- holder.icon_state = "gygax14"
- if(4)
+ holder.icon_state = "gygax16"
+ if(5)
if(diff==FORWARD)
user.visible_message("[user] welds the internal armor layer to the [holder].", "You weld the internal armor layer to the [holder].")
- holder.icon_state = "gygax17"
+ holder.icon_state = "gygax19"
else
user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.")
- holder.icon_state = "gygax15"
- if(3)
+ holder.icon_state = "gygax17"
+ if(4)
if(diff==FORWARD)
user.visible_message("[user] installs Gygax Armor Plates to the [holder].", "You install Gygax Armor Plates to the [holder].")
qdel(used_atom)
- holder.icon_state = "gygax18"
+ holder.icon_state = "gygax20"
else
user.visible_message("[user] cuts the internal armor layer from the [holder].", "You cut the internal armor layer from the [holder].")
- holder.icon_state = "gygax16"
- if(2)
+ holder.icon_state = "gygax18"
+ if(3)
if(diff==FORWARD)
user.visible_message("[user] secures Gygax Armor Plates.", "You secure Gygax Armor Plates.")
- holder.icon_state = "gygax19"
+ holder.icon_state = "gygax21"
else
user.visible_message("[user] pries Gygax Armor Plates from the [holder].", "You pry Gygax Armor Plates from the [holder].")
new /obj/item/mecha_parts/part/gygax_armor(get_turf(holder))
- holder.icon_state = "gygax17"
- if(1)
+ holder.icon_state = "gygax19"
+ if(2)
if(diff==FORWARD)
user.visible_message("[user] welds Gygax Armor Plates to the [holder].", "You weld Gygax Armor Plates to the [holder].")
+ spawn_mecha_result()
else
user.visible_message("[user] unfastens Gygax Armor Plates.", "You unfasten Gygax Armor Plates.")
- holder.icon_state = "gygax18"
+ holder.icon_state = "gygax20"
return 1
-/datum/construction/reversible/mecha/gygax/spawn_result()
- var/obj/mecha/combat/gygax/M = new result(get_turf(holder))
- M.CheckParts(holder.contents)
- qdel(holder)
+/datum/construction/reversible/mecha/gygax/spawn_mecha_result()
+ ..()
SSblackbox.inc("mecha_gygax_created",1)
return
@@ -596,13 +655,16 @@
/datum/construction/reversible/mecha/firefighter
- result = "/obj/mecha/working/ripley/firefighter"
+ result = /obj/mecha/working/ripley/firefighter
steps = list(
- //1
- list("key"=/obj/item/weldingtool,
+ //0, dummy step used to stop the steps from finishing and spawn_result() being called automatically.
+ list("desc"="You shouldn't be able to see this."),
+
+ //1
+ list("key"=/obj/item/weldingtool,
"backkey"=/obj/item/wrench,
"desc"="External armor is wrenched."),
- //2
+ //2
list("key"=/obj/item/wrench,
"backkey"=/obj/item/crowbar,
"desc"="External armor is installed."),
@@ -622,40 +684,47 @@
list("key"=/obj/item/wrench,
"backkey"=/obj/item/crowbar,
"desc"="Internal armor is installed."),
-
//7
list("key"=/obj/item/stack/sheet/plasteel,
"backkey"=/obj/item/screwdriver,
- "desc"="Peripherals control module is secured."),
+ "desc"="The power cell is secured."),
//8
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Peripherals control module is installed."),
+ "desc"="The power cell is installed."),
//9
- list("key"=/obj/item/circuitboard/mecha/ripley/peripherals,
+ list("key"=/obj/item/stock_parts/cell,
"backkey"=/obj/item/screwdriver,
- "desc"="Central control module is secured."),
+ "desc"="Peripherals control module is secured."),
//10
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Central control module is installed."),
+ "desc"="Peripherals control module is installed."),
//11
+ list("key"=/obj/item/circuitboard/mecha/ripley/peripherals,
+ "backkey"=/obj/item/screwdriver,
+ "desc"="Central control module is secured."),
+ //12
+ list("key"=/obj/item/screwdriver,
+ "backkey"=/obj/item/crowbar,
+ "desc"="Central control module is installed."),
+ //13
list("key"=/obj/item/circuitboard/mecha/ripley/main,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is adjusted."),
- //12
+ //14
list("key"=/obj/item/wirecutters,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is added."),
- //13
+ //15
list("key"=/obj/item/stack/cable_coil,
"backkey"=/obj/item/screwdriver,
"desc"="The hydraulic systems are active."),
- //14
+ //16
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/wrench,
"desc"="The hydraulic systems are connected."),
- //15
+ //17
list("key"=/obj/item/wrench,
"desc"="The hydraulic systems are disconnected.")
)
@@ -669,24 +738,24 @@
//TODO: better messages.
switch(index)
- if(15)
+ if(18)
user.visible_message("[user] connects the [holder] hydraulic systems", "You connect the [holder] hydraulic systems.")
holder.icon_state = "fireripley1"
- if(14)
+ if(17)
if(diff==FORWARD)
user.visible_message("[user] activates the [holder] hydraulic systems.", "You activate the [holder] hydraulic systems.")
holder.icon_state = "fireripley2"
else
user.visible_message("[user] disconnects the [holder] hydraulic systems", "You disconnect the [holder] hydraulic systems.")
holder.icon_state = "fireripley0"
- if(13)
+ if(16)
if(diff==FORWARD)
user.visible_message("[user] adds the wiring to the [holder].", "You add the wiring to the [holder].")
holder.icon_state = "fireripley3"
else
user.visible_message("[user] deactivates the [holder] hydraulic systems.", "You deactivate the [holder] hydraulic systems.")
holder.icon_state = "fireripley1"
- if(12)
+ if(15)
if(diff==FORWARD)
user.visible_message("[user] adjusts the wiring of the [holder].", "You adjust the wiring of the [holder].")
holder.icon_state = "fireripley4"
@@ -695,7 +764,7 @@
var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder))
coil.amount = 4
holder.icon_state = "fireripley2"
- if(11)
+ if(14)
if(diff==FORWARD)
user.visible_message("[user] installs the central control module into the [holder].", "You install the central computer mainboard into the [holder].")
qdel(used_atom)
@@ -703,7 +772,7 @@
else
user.visible_message("[user] disconnects the wiring of the [holder].", "You disconnect the wiring of the [holder].")
holder.icon_state = "fireripley3"
- if(10)
+ if(13)
if(diff==FORWARD)
user.visible_message("[user] secures the mainboard.", "You secure the mainboard.")
holder.icon_state = "fireripley6"
@@ -711,7 +780,7 @@
user.visible_message("[user] removes the central control module from the [holder].", "You remove the central computer mainboard from the [holder].")
new /obj/item/circuitboard/mecha/ripley/main(get_turf(holder))
holder.icon_state = "fireripley4"
- if(9)
+ if(12)
if(diff==FORWARD)
user.visible_message("[user] installs the peripherals control module into the [holder].", "You install the peripherals control module into the [holder].")
qdel(used_atom)
@@ -719,7 +788,7 @@
else
user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.")
holder.icon_state = "fireripley5"
- if(8)
+ if(11)
if(diff==FORWARD)
user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.")
holder.icon_state = "fireripley8"
@@ -727,64 +796,82 @@
user.visible_message("[user] removes the peripherals control module from the [holder].", "You remove the peripherals control module from the [holder].")
new /obj/item/circuitboard/mecha/ripley/peripherals(get_turf(holder))
holder.icon_state = "fireripley6"
- if(7)
+ if(10)
if(diff==FORWARD)
- user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ user.visible_message("[user] installs the power cell into the [holder].", "You install the power cell into the [holder].")
+ var/obj/item/I = used_atom
+ user.transferItemToLoc(I, holder, TRUE)
holder.icon_state = "fireripley9"
else
user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.")
holder.icon_state = "fireripley7"
-
- if(6)
+ if(9)
+ if(diff==FORWARD)
+ user.visible_message("[user] secures the power cell.", "You secure the power cell.")
+ holder.icon_state = "fireripley10"
+ else
+ user.visible_message("[user] prys the power cell from [holder].", "You pry the power cell from [holder].")
+ var/obj/item/I = locate(/obj/item/stock_parts/cell) in holder
+ I.forceMove(holder.drop_location())
+ holder.icon_state = "fireripley8"
+ if(8)
+ if(diff==FORWARD)
+ user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ holder.icon_state = "fireripley11"
+ else
+ user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.")
+ holder.icon_state = "fireripley9"
+ if(7)
if(diff==FORWARD)
user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.")
- holder.icon_state = "fireripley10"
+ holder.icon_state = "fireripley12"
else
user.visible_message("[user] pries internal armor layer from the [holder].", "You pry internal armor layer from the [holder].")
var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder))
MS.amount = 5
- holder.icon_state = "fireripley8"
- if(5)
+ holder.icon_state = "fireripley10"
+ if(6)
if(diff==FORWARD)
user.visible_message("[user] welds the internal armor layer to the [holder].", "You weld the internal armor layer to the [holder].")
- holder.icon_state = "fireripley11"
+ holder.icon_state = "fireripley13"
else
user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.")
- holder.icon_state = "fireripley9"
- if(4)
+ holder.icon_state = "fireripley11"
+ if(5)
if(diff==FORWARD)
user.visible_message("[user] starts to install the external armor layer to the [holder].", "You install the external armor layer to the [holder].")
- holder.icon_state = "fireripley12"
+ holder.icon_state = "fireripley14"
else
user.visible_message("[user] cuts the internal armor layer from the [holder].", "You cut the internal armor layer from the [holder].")
- holder.icon_state = "fireripley10"
- if(3)
+ holder.icon_state = "fireripley12"
+ if(4)
if(diff==FORWARD)
user.visible_message("[user] installs the external reinforced armor layer to the [holder].", "You install the external reinforced armor layer to the [holder].")
- holder.icon_state = "fireripley13"
+ holder.icon_state = "fireripley15"
else
user.visible_message("[user] removes the external armor from the [holder].", "You remove the external armor from the [holder].")
var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder))
MS.amount = 5
- holder.icon_state = "fireripley11"
- if(2)
+ holder.icon_state = "fireripley13"
+ if(3)
if(diff==FORWARD)
user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.")
- holder.icon_state = "fireripley14"
+ holder.icon_state = "fireripley16"
else
user.visible_message("[user] pries external armor layer from the [holder].", "You pry external armor layer from the [holder].")
var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder))
MS.amount = 5
- holder.icon_state = "fireripley12"
- if(1)
+ holder.icon_state = "fireripley14"
+ if(2)
if(diff==FORWARD)
user.visible_message("[user] welds the external armor layer to the [holder].", "You weld the external armor layer to the [holder].")
+ spawn_mecha_result()
else
user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.")
- holder.icon_state = "fireripley13"
+ holder.icon_state = "fireripley15"
return 1
-/datum/construction/reversible/mecha/firefighter/spawn_result()
+/datum/construction/reversible/mecha/firefighter/spawn_mecha_result()
..()
SSblackbox.inc("mecha_firefighter_created",1)
return
@@ -818,19 +905,23 @@
/datum/construction/mecha/honker
- result = "/obj/mecha/combat/honker"
- steps = list(list("key"=/obj/item/bikehorn), //1
+ result = /obj/mecha/combat/honker
+ steps = list(
+ list("desc"="You shouldn't be able to see this."), //0, note steps in the construction path are +1 to the ones here
+ list("key"=/obj/item/bikehorn), //1
list("key"=/obj/item/clothing/shoes/clown_shoes), //2
list("key"=/obj/item/bikehorn), //3
list("key"=/obj/item/clothing/mask/gas/clown_hat), //4
list("key"=/obj/item/bikehorn), //5
- list("key"=/obj/item/circuitboard/mecha/honker/targeting), //6
+ list("key"=/obj/item/stock_parts/cell), //6
list("key"=/obj/item/bikehorn), //7
- list("key"=/obj/item/circuitboard/mecha/honker/peripherals), //8
+ list("key"=/obj/item/circuitboard/mecha/honker/targeting), //8
list("key"=/obj/item/bikehorn), //9
- list("key"=/obj/item/circuitboard/mecha/honker/main), //10
+ list("key"=/obj/item/circuitboard/mecha/honker/peripherals), //10
list("key"=/obj/item/bikehorn), //11
- )
+ list("key"=/obj/item/circuitboard/mecha/honker/main), //12
+ list("key"=/obj/item/bikehorn), //13
+ )
/datum/construction/mecha/honker/action(atom/used_atom,mob/user)
return check_step(used_atom,user)
@@ -842,27 +933,34 @@
if(istype(used_atom, /obj/item/bikehorn))
playsound(holder, 'sound/items/bikehorn.ogg', 50, 1)
user.visible_message("HONK!")
+ if(step==2)
+ spawn_mecha_result()
+
//TODO: better messages.
switch(step)
- if(10)
+ if(13)
user.visible_message("[user] installs the central control module into the [holder].", "You install the central control module into the [holder].")
qdel(used_atom)
- if(8)
+ if(11)
user.visible_message("[user] installs the peripherals control module into the [holder].", "You install the peripherals control module into the [holder].")
qdel(used_atom)
- if(6)
+ if(9)
user.visible_message("[user] installs the weapon control module into the [holder].", "You install the weapon control module into the [holder].")
qdel(used_atom)
- if(4)
+ if(7)
+ user.visible_message("[user] installs the power cell into the [holder].", "You install the power cell into the [holder].")
+ var/obj/item/I = used_atom
+ user.transferItemToLoc(I, holder, TRUE)
+ if(5)
user.visible_message("[user] puts clown wig and mask on the [holder].", "You put clown wig and mask on the [holder].")
qdel(used_atom)
- if(2)
+ if(3)
user.visible_message("[user] puts clown boots on the [holder].", "You put clown boots on the [holder].")
qdel(used_atom)
return 1
-/datum/construction/mecha/honker/spawn_result()
+/datum/construction/mecha/honker/spawn_mecha_result()
..()
SSblackbox.inc("mecha_honker_created",1)
return
@@ -895,10 +993,13 @@
return
/datum/construction/reversible/mecha/durand
- result = "/obj/mecha/combat/durand"
+ result = /obj/mecha/combat/durand
steps = list(
- //1
- list("key"=/obj/item/weldingtool,
+ //0, dummy step used to stop the steps from finishing and spawn_result() being called automatically.
+ list("desc"="You shouldn't be able to see this."),
+
+ //1
+ list("key"=/obj/item/weldingtool,
"backkey"=/obj/item/wrench,
"desc"="External armor is wrenched."),
//2
@@ -920,60 +1021,68 @@
//6
list("key"=/obj/item/stack/sheet/metal,
"backkey"=/obj/item/screwdriver,
- "desc"="Super capacitor is secured."),
+ "desc"="The power cell is secured."),
//7
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Super capacitor is installed."),
+ "desc"="The power cell is installed."),
//8
- list("key"=/obj/item/stock_parts/capacitor,
+ list("key"=/obj/item/stock_parts/cell,
"backkey"=/obj/item/screwdriver,
- "desc"="Phasic scanner module is secured."),
+ "desc"="Super capacitor is secured."),
//9
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Phasic scanner module is installed."),
+ "desc"="Super capacitor is installed."),
//10
- list("key"=/obj/item/stock_parts/scanning_module,
+ list("key"=/obj/item/stock_parts/capacitor,
"backkey"=/obj/item/screwdriver,
- "desc"="Weapon control module is secured."),
+ "desc"="Phasic scanner module is secured."),
//11
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Weapon control module is installed."),
+ "desc"="Phasic scanner module is installed."),
//12
- list("key"=/obj/item/circuitboard/mecha/durand/targeting,
+ list("key"=/obj/item/stock_parts/scanning_module,
"backkey"=/obj/item/screwdriver,
- "desc"="Peripherals control module is secured."),
+ "desc"="Weapon control module is secured."),
//13
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Peripherals control module is installed."),
+ "desc"="Weapon control module is installed."),
//14
- list("key"=/obj/item/circuitboard/mecha/durand/peripherals,
+ list("key"=/obj/item/circuitboard/mecha/durand/targeting,
"backkey"=/obj/item/screwdriver,
- "desc"="Central control module is secured."),
+ "desc"="Peripherals control module is secured."),
//15
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Central control module is installed."),
+ "desc"="Peripherals control module is installed."),
//16
+ list("key"=/obj/item/circuitboard/mecha/durand/peripherals,
+ "backkey"=/obj/item/screwdriver,
+ "desc"="Central control module is secured."),
+ //17
+ list("key"=/obj/item/screwdriver,
+ "backkey"=/obj/item/crowbar,
+ "desc"="Central control module is installed."),
+ //18
list("key"=/obj/item/circuitboard/mecha/durand/main,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is adjusted."),
- //17
+ //19
list("key"=/obj/item/wirecutters,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is added."),
- //18
+ //20
list("key"=/obj/item/stack/cable_coil,
"backkey"=/obj/item/screwdriver,
"desc"="The hydraulic systems are active."),
- //19
+ //21
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/wrench,
"desc"="The hydraulic systems are connected."),
- //20
+ //22
list("key"=/obj/item/wrench,
"desc"="The hydraulic systems are disconnected.")
)
@@ -988,24 +1097,24 @@
//TODO: better messages.
switch(index)
- if(20)
+ if(23)
user.visible_message("[user] connects the [holder] hydraulic systems", "You connect the [holder] hydraulic systems.")
holder.icon_state = "durand1"
- if(19)
+ if(22)
if(diff==FORWARD)
user.visible_message("[user] activates the [holder] hydraulic systems.", "You activate the [holder] hydraulic systems.")
holder.icon_state = "durand2"
else
user.visible_message("[user] disconnects the [holder] hydraulic systems", "You disconnect the [holder] hydraulic systems.")
holder.icon_state = "durand0"
- if(18)
+ if(21)
if(diff==FORWARD)
user.visible_message("[user] adds the wiring to the [holder].", "You add the wiring to the [holder].")
holder.icon_state = "durand3"
else
user.visible_message("[user] deactivates the [holder] hydraulic systems.", "You deactivate the [holder] hydraulic systems.")
holder.icon_state = "durand1"
- if(17)
+ if(20)
if(diff==FORWARD)
user.visible_message("[user] adjusts the wiring of the [holder].", "You adjust the wiring of the [holder].")
holder.icon_state = "durand4"
@@ -1014,7 +1123,7 @@
var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder))
coil.amount = 4
holder.icon_state = "durand2"
- if(16)
+ if(19)
if(diff==FORWARD)
user.visible_message("[user] installs the central control module into the [holder].", "You install the central computer mainboard into the [holder].")
qdel(used_atom)
@@ -1022,7 +1131,7 @@
else
user.visible_message("[user] disconnects the wiring of the [holder].", "You disconnect the wiring of the [holder].")
holder.icon_state = "durand3"
- if(15)
+ if(18)
if(diff==FORWARD)
user.visible_message("[user] secures the mainboard.", "You secure the mainboard.")
holder.icon_state = "durand6"
@@ -1030,7 +1139,7 @@
user.visible_message("[user] removes the central control module from the [holder].", "You remove the central computer mainboard from the [holder].")
new /obj/item/circuitboard/mecha/durand/main(get_turf(holder))
holder.icon_state = "durand4"
- if(14)
+ if(17)
if(diff==FORWARD)
user.visible_message("[user] installs the peripherals control module into the [holder].", "You install the peripherals control module into the [holder].")
qdel(used_atom)
@@ -1038,7 +1147,7 @@
else
user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.")
holder.icon_state = "durand5"
- if(13)
+ if(16)
if(diff==FORWARD)
user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.")
holder.icon_state = "durand8"
@@ -1046,7 +1155,7 @@
user.visible_message("[user] removes the peripherals control module from the [holder].", "You remove the peripherals control module from the [holder].")
new /obj/item/circuitboard/mecha/durand/peripherals(get_turf(holder))
holder.icon_state = "durand6"
- if(12)
+ if(15)
if(diff==FORWARD)
user.visible_message("[user] installs the weapon control module into the [holder].", "You install the weapon control module into the [holder].")
qdel(used_atom)
@@ -1054,7 +1163,7 @@
else
user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.")
holder.icon_state = "durand7"
- if(11)
+ if(14)
if(diff==FORWARD)
user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.")
holder.icon_state = "durand10"
@@ -1062,7 +1171,7 @@
user.visible_message("[user] removes the weapon control module from the [holder].", "You remove the weapon control module from the [holder].")
new /obj/item/circuitboard/mecha/durand/targeting(get_turf(holder))
holder.icon_state = "durand8"
- if(10)
+ if(13)
if(diff==FORWARD)
user.visible_message("[user] installs scanner module to the [holder].", "You install phasic scanner module to the [holder].")
var/obj/item/I = used_atom
@@ -1071,7 +1180,7 @@
else
user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.")
holder.icon_state = "durand9"
- if(9)
+ if(12)
if(diff==FORWARD)
user.visible_message("[user] secures the scanner module.", "You secure the scanner module.")
holder.icon_state = "durand12"
@@ -1080,7 +1189,7 @@
var/obj/item/I = locate(/obj/item/stock_parts/scanning_module) in holder
I.loc = get_turf(holder)
holder.icon_state = "durand10"
- if(8)
+ if(11)
if(diff==FORWARD)
user.visible_message("[user] installs capacitor to the [holder].", "You install capacitor to the [holder].")
var/obj/item/I = used_atom
@@ -1089,7 +1198,7 @@
else
user.visible_message("[user] unfastens the scanner module.", "You unfasten the scanner module.")
holder.icon_state = "durand11"
- if(7)
+ if(10)
if(diff==FORWARD)
user.visible_message("[user] secures the capacitor.", "You secure the capacitor.")
holder.icon_state = "durand14"
@@ -1098,64 +1207,80 @@
var/obj/item/I = locate(/obj/item/stock_parts/capacitor) in holder
I.loc = get_turf(holder)
holder.icon_state = "durand12"
- if(6)
+ if(9)
if(diff==FORWARD)
- user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ user.visible_message("[user] installs the power cell into the [holder].", "You install the power cell into the [holder].")
+ var/obj/item/I = used_atom
+ user.transferItemToLoc(I, holder, TRUE)
holder.icon_state = "durand15"
else
- user.visible_message("[user] unfastens the super capacitor.", "You unfasten the capacitor.")
+ user.visible_message("[user] unfastens the capacitor.", "You unfasten the capacitor.")
holder.icon_state = "durand13"
- if(5)
+ if(8)
+ if(diff==FORWARD)
+ user.visible_message("[user] secures the power cell.", "You secure the power cell.")
+ holder.icon_state = "durand16"
+ else
+ user.visible_message("[user] prys the power cell from [holder].", "You pry the power cell from [holder].")
+ var/obj/item/I = locate(/obj/item/stock_parts/cell) in holder
+ I.forceMove(holder.drop_location())
+ holder.icon_state = "durand14"
+ if(7)
+ if(diff==FORWARD)
+ user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ holder.icon_state = "durand17"
+ else
+ user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.")
+ holder.icon_state = "durand15"
+ if(6)
if(diff==FORWARD)
user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.")
- holder.icon_state = "durand16"
+ holder.icon_state = "durand18"
else
user.visible_message("[user] pries internal armor layer from the [holder].", "You pry internal armor layer from the [holder].")
var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder))
MS.amount = 5
- holder.icon_state = "durand14"
- if(4)
+ holder.icon_state = "durand16"
+ if(5)
if(diff==FORWARD)
user.visible_message("[user] welds the internal armor layer to the [holder].", "You weld the internal armor layer to the [holder].")
- holder.icon_state = "durand17"
+ holder.icon_state = "durand19"
else
user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.")
- holder.icon_state = "durand15"
- if(3)
+ holder.icon_state = "durand17"
+ if(4)
if(diff==FORWARD)
user.visible_message("[user] installs Durand Armor Plates to the [holder].", "You install Durand Armor Plates to the [holder].")
qdel(used_atom)
- holder.icon_state = "durand18"
+ holder.icon_state = "durand20"
else
user.visible_message("[user] cuts the internal armor layer from the [holder].", "You cut the internal armor layer from the [holder].")
- holder.icon_state = "durand16"
- if(2)
+ holder.icon_state = "durand18"
+ if(3)
if(diff==FORWARD)
user.visible_message("[user] secures Durand Armor Plates.", "You secure Durand Armor Plates.")
- holder.icon_state = "durand19"
+ holder.icon_state = "durand21"
else
user.visible_message("[user] pries Durand Armor Plates from the [holder].", "You pry Durand Armor Plates from the [holder].")
new /obj/item/mecha_parts/part/durand_armor(get_turf(holder))
- holder.icon_state = "durand17"
- if(1)
+ holder.icon_state = "durand19"
+ if(2)
if(diff==FORWARD)
user.visible_message("[user] welds Durand Armor Plates to the [holder].", "You weld Durand Armor Plates to the [holder].")
+ spawn_mecha_result()
else
user.visible_message("[user] unfastens Durand Armor Plates.", "You unfasten Durand Armor Plates.")
- holder.icon_state = "durand18"
+ holder.icon_state = "durand20"
return 1
-/datum/construction/reversible/mecha/durand/spawn_result()
- var/obj/mecha/combat/gygax/M = new result(get_turf(holder))
- M.CheckParts(holder.contents)
- qdel(holder)
+/datum/construction/reversible/mecha/durand/spawn_mecha_result()
+ ..()
SSblackbox.inc("mecha_durand_created",1)
return
//PHAZON
/datum/construction/mecha/phazon_chassis
- result = "/obj/mecha/combat/phazon"
steps = list(list("key"=/obj/item/mecha_parts/part/phazon_torso), //1
list("key"=/obj/item/mecha_parts/part/phazon_left_arm), //2
list("key"=/obj/item/mecha_parts/part/phazon_right_arm), //3
@@ -1183,15 +1308,17 @@
return
/datum/construction/reversible/mecha/phazon
- result = "/obj/mecha/combat/phazon"
+ result = /obj/mecha/combat/phazon
steps = list(
- //1
- list("key"=/obj/item/device/assembly/signaler/anomaly,
+ //0, dummy step used to stop the steps from finishing and spawn_result() being called automatically.
+ list("desc"="You shouldn't be able to see this."),
+
+ //1
+ list("key"=/obj/item/device/assembly/signaler/anomaly,
"backkey"=null, //Cannot remove the anomaly core once it's in
"desc"="Anomaly core socket is open and awaiting connection."),
-
- //2
- list("key"=/obj/item/weldingtool,
+ //2
+ list("key"=/obj/item/weldingtool,
"backkey"=/obj/item/wrench,
"desc"="External armor is wrenched."),
//3
@@ -1213,72 +1340,80 @@
//7
list("key"=/obj/item/stack/sheet/plasteel,
"backkey"=/obj/item/screwdriver,
- "desc"="The bluespace crystal is engaged."),
+ "desc"="The power cell is secured."),
//8
+ list("key"=/obj/item/screwdriver,
+ "backkey"=/obj/item/crowbar,
+ "desc"="The power cell is installed."),
+ //9
+ list("key"=/obj/item/stock_parts/cell,
+ "backkey"=/obj/item/screwdriver,
+ "desc"="The bluespace crystal is engaged."),
+ //10
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/wirecutters,
"desc"="The bluespace crystal is connected."),
- //9
+ //11
list("key"=/obj/item/stack/cable_coil,
"backkey"=/obj/item/crowbar,
"desc"="The bluespace crystal is installed."),
- //10
+ //12
list("key"=/obj/item/ore/bluespace_crystal,
"backkey"=/obj/item/screwdriver,
"desc"="Super capacitor is secured."),
- //12
- list("key"=/obj/item/screwdriver,
- "backkey"=/obj/item/crowbar,
- "desc"="Super capacitor is installed."),
- //12
- list("key"=/obj/item/stock_parts/capacitor,
- "backkey"=/obj/item/screwdriver,
- "desc"="Phasic scanner module is secured."),
//13
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Phasic scanner module is installed."),
+ "desc"="Super capacitor is installed."),
//14
- list("key"=/obj/item/stock_parts/scanning_module,
+ list("key"=/obj/item/stock_parts/capacitor,
"backkey"=/obj/item/screwdriver,
- "desc"="Weapon control module is secured."),
+ "desc"="Phasic scanner module is secured."),
//15
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Weapon control is installed."),
+ "desc"="Phasic scanner module is installed."),
//16
- list("key"=/obj/item/circuitboard/mecha/phazon/targeting,
+ list("key"=/obj/item/stock_parts/scanning_module,
"backkey"=/obj/item/screwdriver,
- "desc"="Peripherals control module is secured."),
+ "desc"="Weapon control module is secured."),
//17
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Peripherals control module is installed"),
+ "desc"="Weapon control is installed."),
//18
- list("key"=/obj/item/circuitboard/mecha/phazon/peripherals,
+ list("key"=/obj/item/circuitboard/mecha/phazon/targeting,
"backkey"=/obj/item/screwdriver,
- "desc"="Central control module is secured."),
+ "desc"="Peripherals control module is secured."),
//19
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Central control module is installed."),
+ "desc"="Peripherals control module is installed"),
//20
+ list("key"=/obj/item/circuitboard/mecha/phazon/peripherals,
+ "backkey"=/obj/item/screwdriver,
+ "desc"="Central control module is secured."),
+ //21
+ list("key"=/obj/item/screwdriver,
+ "backkey"=/obj/item/crowbar,
+ "desc"="Central control module is installed."),
+ //22
list("key"=/obj/item/circuitboard/mecha/phazon/main,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is adjusted."),
- //21
+ //23
list("key"=/obj/item/wirecutters,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is added."),
- //22
+ //24
list("key"=/obj/item/stack/cable_coil,
"backkey"=/obj/item/screwdriver,
"desc"="The hydraulic systems are active."),
- //23
+ //25
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/wrench,
"desc"="The hydraulic systems are connected."),
- //24
+ //26
list("key"=/obj/item/wrench,
"desc"="The hydraulic systems are disconnected.")
)
@@ -1293,24 +1428,24 @@
//TODO: better messages.
switch(index)
- if(24)
+ if(27)
user.visible_message("[user] connects the [holder] hydraulic systems", "You connect the [holder] hydraulic systems.")
holder.icon_state = "phazon1"
- if(23)
+ if(26)
if(diff==FORWARD)
user.visible_message("[user] activates the [holder] hydraulic systems.", "You activate the [holder] hydraulic systems.")
holder.icon_state = "phazon2"
else
user.visible_message("[user] disconnects the [holder] hydraulic systems", "You disconnect the [holder] hydraulic systems.")
holder.icon_state = "phazon0"
- if(22)
+ if(25)
if(diff==FORWARD)
user.visible_message("[user] adds the wiring to the [holder].", "You add the wiring to the [holder].")
holder.icon_state = "phazon3"
else
user.visible_message("[user] deactivates the [holder] hydraulic systems.", "You deactivate the [holder] hydraulic systems.")
holder.icon_state = "phazon1"
- if(21)
+ if(24)
if(diff==FORWARD)
user.visible_message("[user] adjusts the wiring of the [holder].", "You adjust the wiring of the [holder].")
holder.icon_state = "phazon4"
@@ -1319,7 +1454,7 @@
var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder))
coil.amount = 4
holder.icon_state = "phazon2"
- if(20)
+ if(23)
if(diff==FORWARD)
user.visible_message("[user] installs the central control module into the [holder].", "You install the central computer mainboard into the [holder].")
qdel(used_atom)
@@ -1327,7 +1462,7 @@
else
user.visible_message("[user] disconnects the wiring of the [holder].", "You disconnect the wiring of the [holder].")
holder.icon_state = "phazon3"
- if(19)
+ if(22)
if(diff==FORWARD)
user.visible_message("[user] secures the mainboard.", "You secure the mainboard.")
holder.icon_state = "phazon6"
@@ -1335,7 +1470,7 @@
user.visible_message("[user] removes the central control module from the [holder].", "You remove the central computer mainboard from the [holder].")
new /obj/item/circuitboard/mecha/phazon/main(get_turf(holder))
holder.icon_state = "phazon4"
- if(18)
+ if(21)
if(diff==FORWARD)
user.visible_message("[user] installs the peripherals control module into the [holder].", "You install the peripherals control module into the [holder].")
qdel(used_atom)
@@ -1343,7 +1478,7 @@
else
user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.")
holder.icon_state = "phazon5"
- if(17)
+ if(20)
if(diff==FORWARD)
user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.")
holder.icon_state = "phazon8"
@@ -1351,7 +1486,7 @@
user.visible_message("[user] removes the peripherals control module from the [holder].", "You remove the peripherals control module from the [holder].")
new /obj/item/circuitboard/mecha/phazon/peripherals(get_turf(holder))
holder.icon_state = "phazon6"
- if(16)
+ if(19)
if(diff==FORWARD)
user.visible_message("[user] installs the weapon control module into the [holder].", "You install the weapon control module into the [holder].")
qdel(used_atom)
@@ -1359,7 +1494,7 @@
else
user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.")
holder.icon_state = "phazon7"
- if(15)
+ if(18)
if(diff==FORWARD)
user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.")
holder.icon_state = "phazon10"
@@ -1367,7 +1502,7 @@
user.visible_message("[user] removes the weapon control module from the [holder].", "You remove the weapon control module from the [holder].")
new /obj/item/circuitboard/mecha/phazon/targeting(get_turf(holder))
holder.icon_state = "phazon8"
- if(14)
+ if(17)
if(diff==FORWARD)
user.visible_message("[user] installs phasic scanner module to the [holder].", "You install scanner module to the [holder].")
var/obj/item/I = used_atom
@@ -1376,7 +1511,7 @@
else
user.visible_message("[user] unfastens the weapon control module.", "You unfasten the weapon control module.")
holder.icon_state = "phazon9"
- if(13)
+ if(16)
if(diff==FORWARD)
user.visible_message("[user] secures the phasic scanner module.", "You secure the scanner module.")
holder.icon_state = "phazon12"
@@ -1385,7 +1520,7 @@
var/obj/item/I = locate(/obj/item/stock_parts/scanning_module) in holder
I.loc = get_turf(holder)
holder.icon_state = "phazon10"
- if(12)
+ if(15)
if(diff==FORWARD)
user.visible_message("[user] installs super capacitor to the [holder].", "You install capacitor to the [holder].")
var/obj/item/I = used_atom
@@ -1394,7 +1529,7 @@
else
user.visible_message("[user] unfastens the phasic scanner module.", "You unfasten the scanner module.")
holder.icon_state = "phazon11"
- if(11)
+ if(14)
if(diff==FORWARD)
user.visible_message("[user] secures the super capacitor.", "You secure the capacitor.")
holder.icon_state = "phazon14"
@@ -1403,7 +1538,7 @@
var/obj/item/I = locate(/obj/item/stock_parts/capacitor) in holder
I.loc = get_turf(holder)
holder.icon_state = "phazon12"
- if(10)
+ if(13)
if(diff==FORWARD)
user.visible_message("[user] installs the bluespace crystal.", "You install the bluespace crystal.")
qdel(used_atom)
@@ -1411,7 +1546,7 @@
else
user.visible_message("[user] unsecures the super capacitor from the [holder].", "You unsecure the capacitor from the [holder].")
holder.icon_state = "phazon13"
- if(9)
+ if(12)
if(diff==FORWARD)
user.visible_message("[user] connects the bluespace crystal.", "You connect the bluespace crystal.")
holder.icon_state = "phazon16"
@@ -1419,68 +1554,85 @@
user.visible_message("[user] removes the bluespace crystal from the [holder].", "You remove the bluespace crystal from the [holder].")
new /obj/item/ore/bluespace_crystal(get_turf(holder))
holder.icon_state = "phazon14"
- if(8)
+ if(11)
if(diff==FORWARD)
user.visible_message("[user] engages the bluespace crystal.", "You engage the bluespace crystal.")
holder.icon_state = "phazon17"
else
user.visible_message("[user] disconnects the bluespace crystal from the [holder].", "You disconnect the bluespace crystal from the [holder].")
holder.icon_state = "phazon15"
- if(7)
+ if(10)
if(diff==FORWARD)
- user.visible_message("[user] installs the phase armor layer to the [holder].", "You install the phase armor layer to the [holder].")
+ user.visible_message("[user] installs the power cell into the [holder].", "You install the power cell into the [holder].")
+ var/obj/item/I = used_atom
+ user.transferItemToLoc(I, holder, TRUE)
holder.icon_state = "phazon18"
else
user.visible_message("[user] disengages the bluespace crystal.", "You disengage the bluespace crystal.")
holder.icon_state = "phazon16"
- if(6)
+ if(9)
+ if(diff==FORWARD)
+ user.visible_message("[user] secures the power cell.", "You secure the power cell.")
+ holder.icon_state = "phazon19"
+ else
+ user.visible_message("[user] prys the power cell from [holder].", "You pry the power cell from [holder].")
+ var/obj/item/I = locate(/obj/item/stock_parts/cell) in holder
+ I.forceMove(holder.drop_location())
+ holder.icon_state = "phazon17"
+ if(8)
+ if(diff==FORWARD)
+ user.visible_message("[user] installs the phase armor layer to the [holder].", "You install the phase armor layer to the [holder].")
+ holder.icon_state = "phazon20"
+ else
+ user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.")
+ holder.icon_state = "durand18"
+ if(7)
if(diff==FORWARD)
user.visible_message("[user] secures the phase armor layer.", "You secure the phase armor layer.")
- holder.icon_state = "phazon19"
+ holder.icon_state = "phazon21"
else
user.visible_message("[user] pries the phase armor layer from the [holder].", "You pry the phase armor layer from the [holder].")
var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder))
MS.amount = 5
- holder.icon_state = "phazon17"
- if(5)
+ holder.icon_state = "phazon19"
+ if(6)
if(diff==FORWARD)
user.visible_message("[user] welds the phase armor layer to the [holder].", "You weld the phase armor layer to the [holder].")
- holder.icon_state = "phazon20"
+ holder.icon_state = "phazon22"
else
user.visible_message("[user] unfastens the phase armor layer.", "You unfasten the phase armor layer.")
- holder.icon_state = "phazon18"
- if(4)
+ holder.icon_state = "phazon20"
+ if(5)
if(diff==FORWARD)
user.visible_message("[user] installs Phazon Armor Plates to the [holder].", "You install Phazon Armor Plates to the [holder].")
qdel(used_atom)
- holder.icon_state = "phazon21"
+ holder.icon_state = "phazon23"
else
user.visible_message("[user] cuts phase armor layer from the [holder].", "You cut the phase armor layer from the [holder].")
- holder.icon_state = "phazon19"
- if(3)
+ holder.icon_state = "phazon21"
+ if(4)
if(diff==FORWARD)
user.visible_message("[user] secures Phazon Armor Plates.", "You secure Phazon Armor Plates.")
- holder.icon_state = "phazon22"
+ holder.icon_state = "phazon24"
else
user.visible_message("[user] pries Phazon Armor Plates from the [holder].", "You pry Phazon Armor Plates from the [holder].")
new /obj/item/mecha_parts/part/phazon_armor(get_turf(holder))
- holder.icon_state = "phazon20"
- if(2)
+ holder.icon_state = "phazon22"
+ if(3)
if(diff==FORWARD)
user.visible_message("[user] welds Phazon Armor Plates to the [holder].", "You weld Phazon Armor Plates to the [holder].")
else
user.visible_message("[user] unfastens Phazon Armor Plates.", "You unfasten Phazon Armor Plates.")
- holder.icon_state = "phazon21"
- if(1)
+ holder.icon_state = "phazon23"
+ if(2)
if(diff==FORWARD)
user.visible_message("[user] carefully inserts the anomaly core into \the [holder] and secures it.", "You slowly place the anomaly core into its socket and close its chamber.")
qdel(used_atom)
+ spawn_mecha_result()
return 1
-/datum/construction/reversible/mecha/phazon/spawn_result()
- var/obj/mecha/combat/gygax/M = new result(get_turf(holder))
- M.CheckParts(holder.contents)
- qdel(holder)
+/datum/construction/reversible/mecha/phazon/spawn_mecha_result()
+ ..()
SSblackbox.inc("mecha_phazon_created",1)
return
@@ -1515,13 +1667,16 @@
/datum/construction/reversible/mecha/odysseus
- result = "/obj/mecha/medical/odysseus"
+ result = /obj/mecha/medical/odysseus
steps = list(
- //1
- list("key"=/obj/item/weldingtool,
+ //0, dummy step used to stop the steps from finishing and spawn_result() being called automatically.
+ list("desc"="You shouldn't be able to see this."),
+
+ //1
+ list("key"=/obj/item/weldingtool,
"backkey"=/obj/item/wrench,
"desc"="External armor is wrenched."),
- //2
+ //2
list("key"=/obj/item/wrench,
"backkey"=/obj/item/crowbar,
"desc"="External armor is installed."),
@@ -1540,36 +1695,44 @@
//6
list("key"=/obj/item/stack/sheet/metal,
"backkey"=/obj/item/screwdriver,
- "desc"="Peripherals control module is secured."),
+ "desc"="The power cell is secured."),
//7
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Peripherals control module is installed."),
+ "desc"="The power cell is installed."),
//8
- list("key"=/obj/item/circuitboard/mecha/odysseus/peripherals,
+ list("key"=/obj/item/stock_parts/cell,
"backkey"=/obj/item/screwdriver,
- "desc"="Central control module is secured."),
+ "desc"="Peripherals control module is secured."),
//9
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/crowbar,
- "desc"="Central control module is installed."),
+ "desc"="Peripherals control module is installed."),
//10
+ list("key"=/obj/item/circuitboard/mecha/odysseus/peripherals,
+ "backkey"=/obj/item/screwdriver,
+ "desc"="Central control module is secured."),
+ //11
+ list("key"=/obj/item/screwdriver,
+ "backkey"=/obj/item/crowbar,
+ "desc"="Central control module is installed."),
+ //12
list("key"=/obj/item/circuitboard/mecha/odysseus/main,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is adjusted."),
- //11
+ //13
list("key"=/obj/item/wirecutters,
"backkey"=/obj/item/screwdriver,
"desc"="The wiring is added."),
- //12
+ //14
list("key"=/obj/item/stack/cable_coil,
"backkey"=/obj/item/screwdriver,
"desc"="The hydraulic systems are active."),
- //13
+ //15
list("key"=/obj/item/screwdriver,
"backkey"=/obj/item/wrench,
"desc"="The hydraulic systems are connected."),
- //14
+ //16
list("key"=/obj/item/wrench,
"desc"="The hydraulic systems are disconnected.")
)
@@ -1583,24 +1746,24 @@
//TODO: better messages.
switch(index)
- if(14)
+ if(17)
user.visible_message("[user] connects the [holder] hydraulic systems", "You connect the [holder] hydraulic systems.")
holder.icon_state = "odysseus1"
- if(13)
+ if(16)
if(diff==FORWARD)
user.visible_message("[user] activates the [holder] hydraulic systems.", "You activate the [holder] hydraulic systems.")
holder.icon_state = "odysseus2"
else
user.visible_message("[user] disconnects the [holder] hydraulic systems", "You disconnect the [holder] hydraulic systems.")
holder.icon_state = "odysseus0"
- if(12)
+ if(15)
if(diff==FORWARD)
user.visible_message("[user] adds the wiring to the [holder].", "You add the wiring to the [holder].")
holder.icon_state = "odysseus3"
else
user.visible_message("[user] deactivates the [holder] hydraulic systems.", "You deactivate the [holder] hydraulic systems.")
holder.icon_state = "odysseus1"
- if(11)
+ if(14)
if(diff==FORWARD)
user.visible_message("[user] adjusts the wiring of the [holder].", "You adjust the wiring of the [holder].")
holder.icon_state = "odysseus4"
@@ -1609,7 +1772,7 @@
var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder))
coil.amount = 4
holder.icon_state = "odysseus2"
- if(10)
+ if(13)
if(diff==FORWARD)
user.visible_message("[user] installs the central control module into the [holder].", "You install the central computer mainboard into the [holder].")
qdel(used_atom)
@@ -1617,7 +1780,7 @@
else
user.visible_message("[user] disconnects the wiring of the [holder].", "You disconnect the wiring of the [holder].")
holder.icon_state = "odysseus3"
- if(9)
+ if(12)
if(diff==FORWARD)
user.visible_message("[user] secures the mainboard.", "You secure the mainboard.")
holder.icon_state = "odysseus6"
@@ -1625,7 +1788,7 @@
user.visible_message("[user] removes the central control module from the [holder].", "You remove the central computer mainboard from the [holder].")
new /obj/item/circuitboard/mecha/odysseus/main(get_turf(holder))
holder.icon_state = "odysseus4"
- if(8)
+ if(11)
if(diff==FORWARD)
user.visible_message("[user] installs the peripherals control module into the [holder].", "You install the peripherals control module into the [holder].")
qdel(used_atom)
@@ -1633,7 +1796,7 @@
else
user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.")
holder.icon_state = "odysseus5"
- if(7)
+ if(10)
if(diff==FORWARD)
user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.")
holder.icon_state = "odysseus8"
@@ -1641,56 +1804,74 @@
user.visible_message("[user] removes the peripherals control module from the [holder].", "You remove the peripherals control module from the [holder].")
new /obj/item/circuitboard/mecha/odysseus/peripherals(get_turf(holder))
holder.icon_state = "odysseus6"
- if(6)
+ if(9)
if(diff==FORWARD)
- user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ user.visible_message("[user] installs the power cell into the [holder].", "You install the power cell into the [holder].")
+ var/obj/item/I = used_atom
+ user.transferItemToLoc(I, holder, TRUE)
holder.icon_state = "odysseus9"
else
user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.")
holder.icon_state = "odysseus7"
- if(5)
+ if(8)
+ if(diff==FORWARD)
+ user.visible_message("[user] secures the power cell.", "You secure the power cell.")
+ holder.icon_state = "odysseus10"
+ else
+ user.visible_message("[user] prys the power cell from [holder].", "You pry the power cell from [holder].")
+ var/obj/item/I = locate(/obj/item/stock_parts/cell) in holder
+ I.forceMove(holder.drop_location())
+ holder.icon_state = "odysseus8"
+ if(7)
+ if(diff==FORWARD)
+ user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ holder.icon_state = "odysseus11"
+ else
+ user.visible_message("[user] unfastens the power cell.", "You unfasten the power cell.")
+ holder.icon_state = "odysseus9"
+ if(6)
if(diff==FORWARD)
user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.")
- holder.icon_state = "odysseus10"
+ holder.icon_state = "odysseus12"
else
user.visible_message("[user] pries internal armor layer from the [holder].", "You pry internal armor layer from the [holder].")
var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder))
MS.amount = 5
- holder.icon_state = "odysseus8"
- if(4)
+ holder.icon_state = "odysseus10"
+ if(5)
if(diff==FORWARD)
user.visible_message("[user] welds the internal armor layer to the [holder].", "You weld the internal armor layer to the [holder].")
- holder.icon_state = "odysseus11"
+ holder.icon_state = "odysseus13"
else
user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.")
- holder.icon_state = "odysseus9"
- if(3)
+ holder.icon_state = "odysseus11"
+ if(4)
if(diff==FORWARD)
user.visible_message("[user] installs [used_atom] layer to the [holder].", "You install the external reinforced armor layer to the [holder].")
- holder.icon_state = "odysseus12"
+ holder.icon_state = "odysseus14"
else
user.visible_message("[user] cuts the internal armor layer from the [holder].", "You cut the internal armor layer from the [holder].")
- holder.icon_state = "odysseus10"
- if(2)
+ holder.icon_state = "odysseus12"
+ if(3)
if(diff==FORWARD)
user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.")
- holder.icon_state = "odysseus13"
+ holder.icon_state = "odysseus15"
else
var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder))
MS.amount = 5
user.visible_message("[user] pries [MS] from the [holder].", "You pry [MS] from the [holder].")
- holder.icon_state = "odysseus11"
- if(1)
+ holder.icon_state = "odysseus13"
+ if(2)
if(diff==FORWARD)
user.visible_message("[user] welds the external armor layer to the [holder].", "You weld the external armor layer to the [holder].")
- holder.icon_state = "odysseus14"
+ spawn_mecha_result()
else
user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.")
- holder.icon_state = "odysseus12"
+ holder.icon_state = "odysseus14"
return 1
-/datum/construction/reversible/mecha/odysseus/spawn_result()
+/datum/construction/reversible/mecha/odysseus/spawn_mecha_result()
..()
SSblackbox.inc("mecha_odysseus_created",1)
return
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index 13f86ec999..32face5c02 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -157,11 +157,27 @@
/obj/effect/landmark/start/wizard
name = "wizard"
-/obj/effect/landmark/start/wizard/Initialize(mapload)
+/obj/effect/landmark/start/wizard/Initialize()
..()
GLOB.wizardstart += loc
return INITIALIZE_HINT_QDEL
+/obj/effect/landmark/start/nukeop
+ name = "nukeop"
+
+/obj/effect/landmark/start/nukeop/Initialize()
+ ..()
+ GLOB.nukeop_start += loc
+ return INITIALIZE_HINT_QDEL
+
+/obj/effect/landmark/start/nukeop_leader
+ name = "nukeop leader"
+
+/obj/effect/landmark/start/nukeop_leader/Initialize()
+ ..()
+ GLOB.nukeop_leader_start += loc
+ return INITIALIZE_HINT_QDEL
+
/obj/effect/landmark/start/new_player
name = "New Player"
@@ -205,23 +221,6 @@
/obj/effect/landmark/tripai
name = "tripai"
-// marauder entry (XXX WTF IS MAURADER ENTRY???)
-
-/obj/effect/landmark/marauder_entry
- name = "Marauder Entry"
-
-// syndicate breach area (XXX I DON'T KNOW WHAT THIS IS EITHER)
-
-/obj/effect/landmark/syndicate_breach_area
- name = "Syndicate Breach Area"
-
-// teleport scroll landmark, XXX DOES THIS DO ANYTHING?
-/obj/effect/landmark/teleport_scroll
- name = "Teleport-Scroll"
-
-/obj/effect/landmark/syndicate_spawn
- name = "Syndicate-Spawn"
-
// xenos.
/obj/effect/landmark/xeno_spawn
name = "xeno_spawn"
diff --git a/code/game/objects/effects/proximity.dm b/code/game/objects/effects/proximity.dm
index 62471505d0..70128be7ee 100644
--- a/code/game/objects/effects/proximity.dm
+++ b/code/game/objects/effects/proximity.dm
@@ -33,7 +33,7 @@
if(!force_rebuild && range == current_range)
return FALSE
. = TRUE
-
+
current_range = range
var/list/checkers_local = checkers
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index 0e6e75ec04..6722ffd89b 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -52,6 +52,7 @@
icon_state = "eggs"
var/amount_grown = 0
var/player_spiders = 0
+ var/directive = "" //Message from the mother
var/poison_type = "toxin"
var/poison_per_bite = 5
var/list/faction = list("spiders")
@@ -71,6 +72,7 @@
S.poison_type = poison_type
S.poison_per_bite = poison_per_bite
S.faction = faction.Copy()
+ S.directive = directive
if(player_spiders)
S.player_spiders = 1
qdel(src)
@@ -87,6 +89,7 @@
var/obj/machinery/atmospherics/components/unary/vent_pump/entry_vent
var/travelling_in_vent = 0
var/player_spiders = 0
+ var/directive = "" //Message from the mother
var/poison_type = "toxin"
var/poison_per_bite = 5
var/list/faction = list("spiders")
@@ -192,6 +195,7 @@
S.poison_per_bite = poison_per_bite
S.poison_type = poison_type
S.faction = faction.Copy()
+ S.directive = directive
if(player_spiders)
S.playable_spider = TRUE
notify_ghosts("Spider [S.name] can be controlled", null, enter_link="(Click to play)", source=S, action=NOTIFY_ATTACK)
@@ -210,12 +214,12 @@
. = ..()
/obj/structure/spider/cocoon/container_resist(mob/living/user)
- var/breakout_time = 1
+ var/breakout_time = 600
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
- to_chat(user, "You struggle against the tight bonds... (This will take about [breakout_time] minutes.)")
+ to_chat(user, "You struggle against the tight bonds... (This will take about [DisplayTimeText(breakout_time)].)")
visible_message("You see something struggling and writhing in \the [src]!")
- if(do_after(user,(breakout_time*60*10), target = src))
+ if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src)
return
qdel(src)
diff --git a/code/game/objects/items/charter.dm b/code/game/objects/items/charter.dm
index 3edb5be090..ee7a91140c 100644
--- a/code/game/objects/items/charter.dm
+++ b/code/game/objects/items/charter.dm
@@ -59,7 +59,7 @@
to_chat(user, "Your name has been sent to your employers for approval.")
// Autoapproves after a certain time
response_timer_id = addtimer(CALLBACK(src, .proc/rename_station, new_name, user.name, user.real_name, key_name(user)), approval_time, TIMER_STOPPABLE)
- to_chat(GLOB.admins, "CUSTOM STATION RENAME:[ADMIN_LOOKUPFLW(user)] proposes to rename the [name_type] to [new_name] (will autoapprove in [approval_time / 10] seconds). [ADMIN_SMITE(user)] (REJECT) [ADMIN_CENTCOM_REPLY(user)]")
+ to_chat(GLOB.admins, "CUSTOM STATION RENAME:[ADMIN_LOOKUPFLW(user)] proposes to rename the [name_type] to [new_name] (will autoapprove in [DisplayTimeText(approval_time)]). [ADMIN_SMITE(user)] (REJECT) [ADMIN_CENTCOM_REPLY(user)]")
/obj/item/station_charter/proc/reject_proposed(user)
if(!user)
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 15a7c1ab0b..f04f8d4441 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -234,6 +234,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/cigarette/attack(mob/living/carbon/M, mob/living/carbon/user)
if(!istype(M))
return ..()
+ if(M.on_fire && !lit)
+ light("[user] lights [src] with [M]'s burning body. What a cold-blooded badass.")
+ return
var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
if(lit && cig && user.a_intent == INTENT_HELP)
if(cig.lit)
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index eb521d8510..ccfe70e662 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -26,6 +26,14 @@ GLOBAL_LIST_EMPTY(PDAs)
var/obj/item/cartridge/cartridge = null //current cartridge
var/mode = 0 //Controls what menu the PDA will display. 0 is hub; the rest are either built in or based on cartridge.
var/icon_alert = "pda-r" //Icon to be overlayed for message alerts. Taken from the pda icon file.
+ var/font_index = 0 //This int tells DM which font is currently selected and lets DM know when the last font has been selected so that it can cycle back to the first font when "toggle font" is pressed again.
+ var/font_mode = "font-family:\"VT323\", monospace;letter-spacing:1px;" //The currently selected font.
+ var/background_color = "#808000" //The currently selected background color.
+
+ #define FONT_VT 0
+ #define FONT_SHARE 1
+ #define FONT_ORBITRON 2
+ #define FONT_MONO 3
//Secondary variables
var/scanmode = 0 //1 is medical scanner, 2 is forensics, 3 is reagent scanner.
@@ -58,6 +66,13 @@ GLOBAL_LIST_EMPTY(PDAs)
var/obj/item/inserted_item //Used for pen, crayon, and lipstick insertion or removal. Same as above.
var/overlays_x_offset = 0 //x offset to use for certain overlays
+/obj/item/device/pda/examine(mob/user)
+ ..()
+ if(!id && !inserted_item)
+ return
+ else
+ to_chat(user, "Alt-click to remove contents.")
+
/obj/item/device/pda/Initialize()
. = ..()
if(fon)
@@ -121,7 +136,8 @@ GLOBAL_LIST_EMPTY(PDAs)
hidden_uplink.interact(user)
return
- var/dat = "Personal Data Assistant"
+ var/dat = "Personal Data Assistant"
+
dat += " Refresh"
@@ -130,6 +146,12 @@ GLOBAL_LIST_EMPTY(PDAs)
if (mode)
dat += " | Return"
+ if (mode == 0)
+ dat += "
"
if(SSshuttle.emergency)
switch(SSshuttle.emergency.mode)
diff --git a/code/modules/mob/dead/new_player/sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories.dm
index 1eb1379dce..03b7fd53ec 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories.dm
@@ -67,30 +67,317 @@
/datum/sprite_accessory/hair
icon = 'icons/mob/human_face.dmi' // default icon for all hairs
-/datum/sprite_accessory/hair/short
- name = "Short Hair" // try to capatilize the names please~ // try to spell
- icon_state = "hair_a" // you do not need to define _s or _l sub-states, game automatically does this for you
+//Place in order by major style E.G "Afro, Bun, Ponytail"
+//Place different versions under the same style E.G "Bun > Large Bun, Ponytail > Long Ponytail"
+//A
-/datum/sprite_accessory/hair/shorthair2
- name = "Short Hair 2"
- icon_state = "hair_shorthair2"
+/datum/sprite_accessory/hair/afro
+ name = "Afro" // try to capatilize the names please~ // try to spell
+ icon_state = "hair_afro" // you do not need to define _s or _l sub-states, game automatically does this for you
-/datum/sprite_accessory/hair/shorthair3
- name = "Short Hair 3"
- icon_state = "hair_shorthair3"
+/datum/sprite_accessory/hair/afro2
+ name = "Afro 2"
+ icon_state = "hair_afro2"
+
+/datum/sprite_accessory/hair/afro_large
+ name = "Big Afro"
+ icon_state = "hair_bigafro"
+
+/datum/sprite_accessory/hair/antenna
+ name = "Ahoge"
+ icon_state = "hair_antenna"
+//B
+
+/datum/sprite_accessory/hair/bald
+ name = "Bald"
+ icon_state = null
+
+/datum/sprite_accessory/hair/balding
+ name = "Balding Hair"
+ icon_state = "hair_e"
+
+/datum/sprite_accessory/hair/longbangs
+ name = "Long Bangs"
+ icon_state = "hair_lbangs"
+
+/datum/sprite_accessory/hair/bedhead
+ name = "Bedhead"
+ icon_state = "hair_bedhead"
+
+/datum/sprite_accessory/hair/bedhead2
+ name = "Bedhead 2"
+ icon_state = "hair_bedheadv2"
+
+/datum/sprite_accessory/hair/bedhead3
+ name = "Bedhead 3"
+ icon_state = "hair_bedheadv3"
+
+/datum/sprite_accessory/hair/beehive
+ name = "Beehive"
+ icon_state = "hair_beehive"
+
+/datum/sprite_accessory/hair/beehive2
+ name = "Beehive 2"
+ icon_state = "hair_beehivev2"
+
+/datum/sprite_accessory/hair/bob
+ name = "Bob"
+ icon_state = "hair_bobcut"
+
+/datum/sprite_accessory/hair/bobcurl
+ name = "Bobcurl"
+ icon_state = "hair_bobcurl"
+
+/datum/sprite_accessory/hair/bob
+ name = "Bob Hair"
+ icon_state = "hair_bob"
+
+/datum/sprite_accessory/hair/bob2
+ name = "Bob Hair 2"
+ icon_state = "hair_bob2"
+
+/datum/sprite_accessory/hair/boddicker
+ name = "Boddicker"
+ icon_state = "hair_boddicker"
+
+/datum/sprite_accessory/hair/bowl
+ name = "Bowl"
+ icon_state = "hair_bowlcut"
+
+/datum/sprite_accessory/hair/braided
+ name = "Braided"
+ icon_state = "hair_braided"
+
+/datum/sprite_accessory/hair/front_braid
+ name = "Braided front"
+ icon_state = "hair_braidfront"
+
+/datum/sprite_accessory/hair/braidtail
+ name = "Braided Tail"
+ icon_state = "hair_braidtail"
+
+/datum/sprite_accessory/hair/lowbraid
+ name = "Low Braid"
+ icon_state = "hair_hbraid"
+
+/datum/sprite_accessory/hair/not_floorlength_braid
+ name = "High Braid"
+ icon_state = "hair_braid2"
+
+/datum/sprite_accessory/hair/shortbraid
+ name = "Short Braid"
+ icon_state = "hair_shortbraid"
+
+/datum/sprite_accessory/hair/braid
+ name = "Floorlength Braid"
+ icon_state = "hair_braid"
+
+/datum/sprite_accessory/hair/business
+ name = "Business Hair"
+ icon_state = "hair_business"
+
+/datum/sprite_accessory/hair/business2
+ name = "Business Hair 2"
+ icon_state = "hair_business2"
+
+/datum/sprite_accessory/hair/business3
+ name = "Business Hair 3"
+ icon_state = "hair_business3"
+
+/datum/sprite_accessory/hair/business4
+ name = "Business Hair 4"
+ icon_state = "hair_business4"
+
+/datum/sprite_accessory/hair/bun
+ name = "Bun Head"
+ icon_state = "hair_bun"
+
+/datum/sprite_accessory/hair/bun2
+ name = "Bun Head 2"
+ icon_state = "hair_bunhead2"
+
+/datum/sprite_accessory/hair/largebun
+ name = "Large Bun"
+ icon_state = "hair_largebun"
+
+/datum/sprite_accessory/hair/buzz
+ name = "Buzzcut"
+ icon_state = "hair_buzzcut"
+
+//C
+
+/datum/sprite_accessory/hair/crew
+ name = "Crewcut"
+ icon_state = "hair_crewcut"
+
+/datum/sprite_accessory/hair/combover
+ name = "Combover"
+ icon_state = "hair_combover"
+
+/datum/sprite_accessory/hair/curls
+ name = "Curls"
+ icon_state = "hair_curls"
+
+//D
+
+/datum/sprite_accessory/hair/devillock
+ name = "Devil Lock"
+ icon_state = "hair_devilock"
+
+/datum/sprite_accessory/hair/dreadlocks
+ name = "Dreadlocks"
+ icon_state = "hair_dreads"
+
+/datum/sprite_accessory/hair/drillhair
+ name = "Drill Hair"
+ icon_state = "hair_drillhair"
+
+//E
+
+/datum/sprite_accessory/hair/emo
+ name = "Emo"
+ icon_state = "hair_emo"
+
+/datum/sprite_accessory/hair/longemo
+ name = "Long Emo"
+ icon_state = "hair_longemo"
+
+//F
+
+/datum/sprite_accessory/hair/feather
+ name = "Feather"
+ icon_state = "hair_feather"
+
+/datum/sprite_accessory/hair/sargeant
+ name = "Flat Top"
+ icon_state = "hair_sargeant"
+
+/datum/sprite_accessory/hair/bigflattop
+ name = "Big Flat Top"
+ icon_state = "hair_bigflattop"
+
+/datum/sprite_accessory/hair/fag
+ name = "Flow Hair"
+ icon_state = "hair_f"
+
+/datum/sprite_accessory/hair/longfringe
+ name = "Long Fringe"
+ icon_state = "hair_longfringe"
+
+/datum/sprite_accessory/hair/longestalt
+ name = "Longer Fringe"
+ icon_state = "hair_vlongfringe"
+
+//G
+
+/datum/sprite_accessory/hair/gelled
+ name = "Gelled Back"
+ icon_state = "hair_gelled"
+
+/datum/sprite_accessory/hair/gentle
+ name = "Gentle"
+ icon_state = "hair_gentle"
+
+//H
/datum/sprite_accessory/hair/cut
name = "Cut Hair"
icon_state = "hair_c"
-/datum/sprite_accessory/hair/long
- name = "Shoulder-length Hair"
- icon_state = "hair_b"
+/datum/sprite_accessory/hair/halfbang
+ name = "Half-banged Hair"
+ icon_state = "hair_halfbang"
+
+/datum/sprite_accessory/hair/halfbang2
+ name = "Half-banged Hair 2"
+ icon_state = "hair_halfbang2"
+
+/datum/sprite_accessory/hair/hedgehog
+ name = "Hedgehog Hair"
+ icon_state = "hair_hedgehog"
+
+/datum/sprite_accessory/hair/hitop
+ name = "Hitop"
+ icon_state = "hair_hitop"
+
+/datum/sprite_accessory/hair/himecut
+ name = "Hime Cut"
+ icon_state = "hair_himecut"
+
+/datum/sprite_accessory/hair/himecut2
+ name = "Hime Cut 2"
+ icon_state = "hair_himecut2"
+
+/datum/sprite_accessory/hair/himeup
+ name = "Hime Updo"
+ icon_state = "hair_himeup"
+
+//I
+
+//J
+
+/datum/sprite_accessory/hair/jensen
+ name = "Jensen Hair"
+ icon_state = "hair_jensen"
+
+//K
+
+/datum/sprite_accessory/hair/keanu
+ name = "Keanu Hair"
+ icon_state = "hair_keanu"
+
+/datum/sprite_accessory/hair/kusangi
+ name = "Kusanagi Hair"
+ icon_state = "hair_kusanagi"
+
+//L
/datum/sprite_accessory/hair/longer
name = "Long Hair"
icon_state = "hair_vlong"
+/datum/sprite_accessory/hair/long
+ name = "Long Hair 1"
+ icon_state = "hair_long"
+
+/datum/sprite_accessory/hair/long2
+ name = "Long Hair 2"
+ icon_state = "hair_long2"
+
+/datum/sprite_accessory/hair/longest
+ name = "Very Long Hair"
+ icon_state = "hair_longest"
+
+//M
+
+/datum/sprite_accessory/hair/megaeyebrows
+ name = "Mega Eyebrows"
+ icon_state = "hair_megaeyebrows"
+
+/datum/sprite_accessory/hair/messy
+ name = "Messy"
+ icon_state = "hair_messy"
+
+/datum/sprite_accessory/hair/mohawk
+ name = "Mohawk"
+ icon_state = "hair_d"
+
+/datum/sprite_accessory/hair/reversemohawk
+ name = "Reverse Mohawk"
+ icon_state = "hair_reversemohawk"
+
+//N
+
+//O
+
+/datum/sprite_accessory/hair/odango
+ name = "Odango"
+ icon_state = "hair_odango"
+
+/datum/sprite_accessory/hair/ombre
+ name = "Ombre"
+ icon_state = "hair_ombre"
+
/datum/sprite_accessory/hair/over_eye
name = "Over Eye"
icon_state = "hair_shortovereye"
@@ -103,29 +390,39 @@
name = "Very Long Over Eye"
icon_state = "hair_longest2"
-/datum/sprite_accessory/hair/longest
- name = "Very Long Hair"
- icon_state = "hair_longest"
+//P
-/datum/sprite_accessory/hair/longfringe
- name = "Long Fringe"
- icon_state = "hair_longfringe"
+/datum/sprite_accessory/hair/parted
+ name = "Parted"
+ icon_state = "hair_parted"
-/datum/sprite_accessory/hair/longestalt
- name = "Longer Fringe"
- icon_state = "hair_vlongfringe"
+/datum/sprite_accessory/hair/sidepartlongalt
+ name = "Long Side Part"
+ icon_state = "hair_longsidepart"
-/datum/sprite_accessory/hair/gentle
- name = "Gentle"
- icon_state = "hair_gentle"
+/datum/sprite_accessory/hair/kagami
+ name = "Pigtails"
+ icon_state = "hair_kagami"
-/datum/sprite_accessory/hair/halfbang
- name = "Half-banged Hair"
- icon_state = "hair_halfbang"
+/datum/sprite_accessory/hair/pigtail
+ name = "Pigtails 2"
+ icon_state = "hair_pigtails"
-/datum/sprite_accessory/hair/halfbang2
- name = "Half-banged Hair 2"
- icon_state = "hair_halfbang2"
+/datum/sprite_accessory/hair/pigtail
+ name = "Pigtails 3"
+ icon_state = "hair_pigtails2"
+
+/datum/sprite_accessory/hair/pixie
+ name = "Pixie Cut"
+ icon_state = "hair_pixie"
+
+/datum/sprite_accessory/hair/pompadour
+ name = "Pompadour"
+ icon_state = "hair_pompadour"
+
+/datum/sprite_accessory/hair/bigpompadour
+ name = "Big Pompadour"
+ icon_state = "hair_bigpompadour"
/datum/sprite_accessory/hair/ponytail1
name = "Ponytail"
@@ -147,6 +444,36 @@
name = "Ponytail 5"
icon_state = "hair_ponytail5"
+/datum/sprite_accessory/hair/highponytail
+ name = "High Ponytail"
+ icon_state = "hair_highponytail"
+
+/datum/sprite_accessory/hair/longponytail
+ name = "Long Ponytail"
+ icon_state = "hair_longstraightponytail"
+
+//Q
+
+/datum/sprite_accessory/hair/quiff
+ name = "Quiff"
+ icon_state = "hair_quiff"
+
+
+//R
+
+//S
+
+/datum/sprite_accessory/hair/oneshoulder
+ name = "One Shoulder"
+ icon_state = "hair_oneshoulder"
+
+/datum/sprite_accessory/hair/tressshoulder
+ name = "Tress Shoulder"
+ icon_state = "hair_tressshoulder"
+
+/datum/sprite_accessory/hair/sidecut
+ name = "Sidecut"
+ icon_state = "hair_sidecut"
/datum/sprite_accessory/hair/sidetail
name = "Side Pony"
@@ -164,141 +491,33 @@
name = "Side Pony 4"
icon_state = "hair_sidetail4"
-/datum/sprite_accessory/hair/oneshoulder
- name = "One Shoulder"
- icon_state = "hair_oneshoulder"
+/datum/sprite_accessory/hair/short
+ name = "Short Hair"
+ icon_state = "hair_a"
-/datum/sprite_accessory/hair/tressshoulder
- name = "Tress Shoulder"
- icon_state = "hair_tressshoulder"
+/datum/sprite_accessory/hair/shorthair2
+ name = "Short Hair 2"
+ icon_state = "hair_shorthair2"
+
+/datum/sprite_accessory/hair/shorthair3
+ name = "Short Hair 3"
+ icon_state = "hair_shorthair3"
+
+/datum/sprite_accessory/hair/long
+ name = "Shoulder-length Hair"
+ icon_state = "hair_b"
/datum/sprite_accessory/hair/parted
- name = "Parted"
- icon_state = "hair_parted"
+ name = "Side Part"
+ icon_state = "hair_part"
-/datum/sprite_accessory/hair/pompadour
- name = "Pompadour"
- icon_state = "hair_pompadour"
+/datum/sprite_accessory/hair/skinhead
+ name = "Skinhead"
+ icon_state = "hair_skinhead"
-/datum/sprite_accessory/hair/bigpompadour
- name = "Big Pompadour"
- icon_state = "hair_bigpompadour"
-
-/datum/sprite_accessory/hair/quiff
- name = "Quiff"
- icon_state = "hair_quiff"
-
-/datum/sprite_accessory/hair/bedhead
- name = "Bedhead"
- icon_state = "hair_bedhead"
-
-/datum/sprite_accessory/hair/bedhead2
- name = "Bedhead 2"
- icon_state = "hair_bedheadv2"
-
-/datum/sprite_accessory/hair/bedhead3
- name = "Bedhead 3"
- icon_state = "hair_bedheadv3"
-
-/datum/sprite_accessory/hair/messy
- name = "Messy"
- icon_state = "hair_messy"
-
-/datum/sprite_accessory/hair/beehive
- name = "Beehive"
- icon_state = "hair_beehive"
-
-/datum/sprite_accessory/hair/beehive2
- name = "Beehive 2"
- icon_state = "hair_beehivev2"
-
-/datum/sprite_accessory/hair/bobcurl
- name = "Bobcurl"
- icon_state = "hair_bobcurl"
-
-/datum/sprite_accessory/hair/bob
- name = "Bob"
- icon_state = "hair_bobcut"
-
-/datum/sprite_accessory/hair/bowl
- name = "Bowl"
- icon_state = "hair_bowlcut"
-
-/datum/sprite_accessory/hair/buzz
- name = "Buzzcut"
- icon_state = "hair_buzzcut"
-
-/datum/sprite_accessory/hair/crew
- name = "Crewcut"
- icon_state = "hair_crewcut"
-
-/datum/sprite_accessory/hair/combover
- name = "Combover"
- icon_state = "hair_combover"
-
-/datum/sprite_accessory/hair/devillock
- name = "Devil Lock"
- icon_state = "hair_devilock"
-
-/datum/sprite_accessory/hair/dreadlocks
- name = "Dreadlocks"
- icon_state = "hair_dreads"
-
-/datum/sprite_accessory/hair/curls
- name = "Curls"
- icon_state = "hair_curls"
-
-/datum/sprite_accessory/hair/afro
- name = "Afro"
- icon_state = "hair_afro"
-
-/datum/sprite_accessory/hair/afro2
- name = "Afro 2"
- icon_state = "hair_afro2"
-
-/datum/sprite_accessory/hair/afro_large
- name = "Big Afro"
- icon_state = "hair_bigafro"
-
-/datum/sprite_accessory/hair/sargeant
- name = "Flat Top"
- icon_state = "hair_sargeant"
-
-/datum/sprite_accessory/hair/emo
- name = "Emo"
- icon_state = "hair_emo"
-
-/datum/sprite_accessory/hair/longemo
- name = "Long Emo"
- icon_state = "hair_longemo"
-
-/datum/sprite_accessory/hair/fag
- name = "Flow Hair"
- icon_state = "hair_f"
-
-/datum/sprite_accessory/hair/feather
- name = "Feather"
- icon_state = "hair_feather"
-
-/datum/sprite_accessory/hair/hitop
- name = "Hitop"
- icon_state = "hair_hitop"
-
-/datum/sprite_accessory/hair/mohawk
- name = "Mohawk"
- icon_state = "hair_d"
-
-/datum/sprite_accessory/hair/reversemohawk
- name = "Reverse Mohawk"
- icon_state = "hair_reversemohawk"
-
-/datum/sprite_accessory/hair/jensen
- name = "Jensen Hair"
- icon_state = "hair_jensen"
-
-/datum/sprite_accessory/hair/gelled
- name = "Gelled Back"
- icon_state = "hair_gelled"
+/datum/sprite_accessory/hair/protagonist
+ name = "Slightly Long"
+ icon_state = "hair_protagonist"
/datum/sprite_accessory/hair/spiky
name = "Spiky"
@@ -312,122 +531,6 @@
name = "Spiky 3"
icon_state = "hair_spiky2"
-/datum/sprite_accessory/hair/protagonist
- name = "Slightly Long"
- icon_state = "hair_protagonist"
-
-/datum/sprite_accessory/hair/kusangi
- name = "Kusanagi Hair"
- icon_state = "hair_kusanagi"
-
-/datum/sprite_accessory/hair/kagami
- name = "Pigtails"
- icon_state = "hair_kagami"
-
-/datum/sprite_accessory/hair/pigtail
- name = "Pigtails 2"
- icon_state = "hair_pigtails"
-
-/datum/sprite_accessory/hair/pigtail
- name = "Pigtails 3"
- icon_state = "hair_pigtails2"
-
-/datum/sprite_accessory/hair/himecut
- name = "Hime Cut"
- icon_state = "hair_himecut"
-
-/datum/sprite_accessory/hair/himecut2
- name = "Hime Cut 2"
- icon_state = "hair_himecut2"
-
-/datum/sprite_accessory/hair/himeup
- name = "Hime Updo"
- icon_state = "hair_himeup"
-
-/datum/sprite_accessory/hair/antenna
- name = "Ahoge"
- icon_state = "hair_antenna"
-
-/datum/sprite_accessory/hair/front_braid
- name = "Braided front"
- icon_state = "hair_braidfront"
-
-/datum/sprite_accessory/hair/lowbraid
- name = "Low Braid"
- icon_state = "hair_hbraid"
-
-/datum/sprite_accessory/hair/not_floorlength_braid
- name = "High Braid"
- icon_state = "hair_braid2"
-
-/datum/sprite_accessory/hair/shortbraid
- name = "Short Braid"
- icon_state = "hair_shortbraid"
-
-/datum/sprite_accessory/hair/braid
- name = "Floorlength Braid"
- icon_state = "hair_braid"
-
-/datum/sprite_accessory/hair/odango
- name = "Odango"
- icon_state = "hair_odango"
-
-/datum/sprite_accessory/hair/ombre
- name = "Ombre"
- icon_state = "hair_ombre"
-
-/datum/sprite_accessory/hair/updo
- name = "Updo"
- icon_state = "hair_updo"
-
-/datum/sprite_accessory/hair/skinhead
- name = "Skinhead"
- icon_state = "hair_skinhead"
-
-/datum/sprite_accessory/hair/longbangs
- name = "Long Bangs"
- icon_state = "hair_lbangs"
-
-/datum/sprite_accessory/hair/balding
- name = "Balding Hair"
- icon_state = "hair_e"
-
-/datum/sprite_accessory/hair/bald
- name = "Bald"
- icon_state = null
-
-/datum/sprite_accessory/hair/parted
- name = "Side Part"
- icon_state = "hair_part"
-
-/datum/sprite_accessory/hair/braided
- name = "Braided"
- icon_state = "hair_braided"
-
-/datum/sprite_accessory/hair/bun
- name = "Bun Head"
- icon_state = "hair_bun"
-
-/datum/sprite_accessory/hair/bun2
- name = "Bun Head 2"
- icon_state = "hair_bunhead2"
-
-/datum/sprite_accessory/hair/braidtail
- name = "Braided Tail"
- icon_state = "hair_braidtail"
-
-/datum/sprite_accessory/hair/bigflattop
- name = "Big Flat Top"
- icon_state = "hair_bigflattop"
-
-/datum/sprite_accessory/hair/drillhair
- name = "Drill Hair"
- icon_state = "hair_drillhair"
-
-/datum/sprite_accessory/hair/keanu
- name = "Keanu Hair"
- icon_state = "hair_keanu"
-
/datum/sprite_accessory/hair/swept
name = "Swept Back Hair"
icon_state = "hair_swept"
@@ -436,73 +539,24 @@
name = "Swept Back Hair 2"
icon_state = "hair_swept2"
-/datum/sprite_accessory/hair/business
- name = "Business Hair"
- icon_state = "hair_business"
+//T
-/datum/sprite_accessory/hair/business2
- name = "Business Hair 2"
- icon_state = "hair_business2"
+//U
-/datum/sprite_accessory/hair/business3
- name = "Business Hair 3"
- icon_state = "hair_business3"
+/datum/sprite_accessory/hair/updo
+ name = "Updo"
+ icon_state = "hair_updo"
-/datum/sprite_accessory/hair/business4
- name = "Business Hair 4"
- icon_state = "hair_business4"
+//V
-/datum/sprite_accessory/hair/hedgehog
- name = "Hedgehog Hair"
- icon_state = "hair_hedgehog"
+//W
-/datum/sprite_accessory/hair/bob
- name = "Bob Hair"
- icon_state = "hair_bob"
+//X
-/datum/sprite_accessory/hair/bob2
- name = "Bob Hair 2"
- icon_state = "hair_bob2"
+//Y
-/datum/sprite_accessory/hair/boddicker
- name = "Boddicker"
- icon_state = "hair_boddicker"
+//Z
-/datum/sprite_accessory/hair/long
- name = "Long Hair 1"
- icon_state = "hair_long"
-
-/datum/sprite_accessory/hair/long2
- name = "Long Hair 2"
- icon_state = "hair_long2"
-
-/datum/sprite_accessory/hair/pixie
- name = "Pixie Cut"
- icon_state = "hair_pixie"
-
-/datum/sprite_accessory/hair/megaeyebrows
- name = "Mega Eyebrows"
- icon_state = "hair_megaeyebrows"
-
-/datum/sprite_accessory/hair/highponytail
- name = "High Ponytail"
- icon_state = "hair_highponytail"
-
-/datum/sprite_accessory/hair/longponytail
- name = "Long Ponytail"
- icon_state = "hair_longstraightponytail"
-
-/datum/sprite_accessory/hair/sidepartlongalt
- name = "Long Side Part"
- icon_state = "hair_longsidepart"
-
-/datum/sprite_accessory/hair/sidecut
- name = "Sidecut"
- icon_state = "hair_sidecut"
-
-/datum/sprite_accessory/hair/largebun
- name = "Large Bun"
- icon_state = "hair_largebun"
/////////////////////////////
// Facial Hair Definitions //
@@ -516,82 +570,81 @@
icon_state = null
gender = NEUTER
-/datum/sprite_accessory/facial_hair/watson
- name = "Watson Mustache"
- icon_state = "facial_watson"
-
-/datum/sprite_accessory/facial_hair/hogan
- name = "Hulk Hogan Mustache"
- icon_state = "facial_hogan" //-Neek
-
-/datum/sprite_accessory/facial_hair/vandyke
- name = "Van Dyke Mustache"
- icon_state = "facial_vandyke"
-
-/datum/sprite_accessory/facial_hair/chaplin
- name = "Square Mustache"
- icon_state = "facial_chaplin"
-
-/datum/sprite_accessory/facial_hair/selleck
- name = "Selleck Mustache"
- icon_state = "facial_selleck"
-
-/datum/sprite_accessory/facial_hair/neckbeard
- name = "Neckbeard"
- icon_state = "facial_neckbeard"
-
-/datum/sprite_accessory/facial_hair/fullbeard
- name = "Full Beard"
- icon_state = "facial_fullbeard"
-
-/datum/sprite_accessory/facial_hair/longbeard
- name = "Long Beard"
- icon_state = "facial_longbeard"
-
-/datum/sprite_accessory/facial_hair/vlongbeard
- name = "Very Long Beard"
- icon_state = "facial_wise"
-
-/datum/sprite_accessory/facial_hair/elvis
- name = "Elvis Sideburns"
- icon_state = "facial_elvis"
-
/datum/sprite_accessory/facial_hair/abe
name = "Abraham Lincoln Beard"
icon_state = "facial_abe"
-
+
+/datum/sprite_accessory/facial_hair/brokenman
+ name = "Broken Man"
+ icon_state = "facial_brokenman"
+
/datum/sprite_accessory/facial_hair/chinstrap
name = "Chinstrap"
icon_state = "facial_chin"
-
+
+/datum/sprite_accessory/facial_hair/dwarf
+ name = "Dwarf Beard"
+ icon_state = "facial_dwarf"
+
+/datum/sprite_accessory/facial_hair/elvis
+ name = "Elvis Sideburns"
+ icon_state = "facial_elvis"
+
+/datum/sprite_accessory/facial_hair/fiveoclock
+ name = "Five o Clock Shadow"
+ icon_state = "facial_fiveoclock"
+
+/datum/sprite_accessory/facial_hair/fullbeard
+ name = "Full Beard"
+ icon_state = "facial_fullbeard"
+
+/datum/sprite_accessory/facial_hair/fu
+ name = "Fu Manchu"
+ icon_state = "facial_fumanchu"
+
+/datum/sprite_accessory/facial_hair/gt
+ name = "Goatee"
+ icon_state = "facial_gt"
+
/datum/sprite_accessory/facial_hair/hip
name = "Hipster Beard"
icon_state = "facial_hip"
-/datum/sprite_accessory/facial_hair/gt
- name = "Goatee"
- icon_state = "facial_gt"
-
+/datum/sprite_accessory/facial_hair/hogan
+ name = "Hulk Hogan Mustache"
+ icon_state = "facial_hogan" //-Neek
+
/datum/sprite_accessory/facial_hair/jensen
name = "Jensen Beard"
icon_state = "facial_jensen"
-
-/datum/sprite_accessory/facial_hair/dwarf
- name = "Dwarf Beard"
- icon_state = "facial_dwarf"
-
-/datum/sprite_accessory/facial_hair/fiveoclock
- name = "Five o Clock Shadow"
- icon_state = "facial_fiveoclock"
-
-/datum/sprite_accessory/facial_hair/fu
- name = "Fu Manchu"
- icon_state = "facial_fumanchu"
-
-/datum/sprite_accessory/facial_hair/brokenman
- name = "Broken Man"
- icon_state = "facial_brokenman"
-
+
+/datum/sprite_accessory/facial_hair/longbeard
+ name = "Long Beard"
+ icon_state = "facial_longbeard"
+
+/datum/sprite_accessory/facial_hair/neckbeard
+ name = "Neckbeard"
+ icon_state = "facial_neckbeard"
+
+/datum/sprite_accessory/facial_hair/selleck
+ name = "Selleck Mustache"
+ icon_state = "facial_selleck"
+
+/datum/sprite_accessory/facial_hair/chaplin
+ name = "Square Mustache"
+ icon_state = "facial_chaplin"
+
+/datum/sprite_accessory/facial_hair/vandyke
+ name = "Van Dyke Mustache"
+ icon_state = "facial_vandyke"
+
+/datum/sprite_accessory/facial_hair/vlongbeard
+ name = "Very Long Beard"
+ icon_state = "facial_wise"
+
+/datum/sprite_accessory/facial_hair/watson
+ name = "Watson Mustache"
+ icon_state = "facial_watson"
///////////////////////////
// Underwear Definitions //
diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm
index 8e919491bb..83dd63cc74 100644
--- a/code/modules/mob/living/brain/MMI.dm
+++ b/code/modules/mob/living/brain/MMI.dm
@@ -13,6 +13,7 @@
var/obj/item/organ/brain/brain = null //The actual brain
var/datum/ai_laws/laws = new()
var/force_replace_ai_name = FALSE
+ var/overrides_aicore_laws = FALSE // Whether the laws on the MMI, if any, override possible pre-existing laws loaded on the AI core.
/obj/item/device/mmi/update_icon()
if(brain)
@@ -198,13 +199,16 @@
else
to_chat(user, "The MMI indicates the brain is active.")
+/obj/item/device/mmi/relaymove()
+ return //so that the MMI won't get a warning about not being able to move if it tries to move
/obj/item/device/mmi/syndie
name = "Syndicate Man-Machine Interface"
desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs and AIs created with it."
origin_tech = "biotech=4;programming=4;syndicate=2"
+ overrides_aicore_laws = TRUE
-/obj/item/device/mmi/syndie/New()
- ..()
+/obj/item/device/mmi/syndie/Initialize()
+ . = ..()
laws = new /datum/ai_laws/syndicate_override()
radio.on = 0
diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
index e6a5f58d69..1390028282 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
@@ -10,15 +10,15 @@ Doesn't work on other aliens/AI.*/
name = "Alien Power"
panel = "Alien"
var/plasma_cost = 0
- var/check_turf = 0
- var/has_action = 1
- var/datum/action/spell_action/alien/action = null
- var/action_icon = 'icons/mob/actions/actions_xeno.dmi'
- var/action_icon_state = "spell_default"
- var/action_background_icon_state = "bg_alien"
+ var/check_turf = FALSE
+ has_action = TRUE
+ datum/action/spell_action/alien/action
+ action_icon = 'icons/mob/actions/actions_xeno.dmi'
+ action_icon_state = "spell_default"
+ action_background_icon_state = "bg_alien"
-/obj/effect/proc_holder/alien/New()
- ..()
+/obj/effect/proc_holder/alien/Initialize()
+ . = ..()
action = new(src)
/obj/effect/proc_holder/alien/Click()
@@ -30,15 +30,20 @@ Doesn't work on other aliens/AI.*/
user.adjustPlasma(-plasma_cost)
return 1
-/obj/effect/proc_holder/alien/proc/on_gain(mob/living/carbon/user)
+/obj/effect/proc_holder/alien/on_gain(mob/living/carbon/user)
return
-/obj/effect/proc_holder/alien/proc/on_lose(mob/living/carbon/user)
+/obj/effect/proc_holder/alien/on_lose(mob/living/carbon/user)
return
-/obj/effect/proc_holder/alien/proc/fire(mob/living/carbon/user)
+/obj/effect/proc_holder/alien/fire(mob/living/carbon/user)
return 1
+/obj/effect/proc_holder/alien/get_panel_text()
+ . = ..()
+ if(plasma_cost > 0)
+ return "[plasma_cost]"
+
/obj/effect/proc_holder/alien/proc/cost_check(check_turf=0,mob/living/carbon/user,silent = 0)
if(user.stat)
if(!silent)
@@ -168,7 +173,6 @@ Doesn't work on other aliens/AI.*/
if(user.getPlasma() > A.plasma_cost && A.corrode(O))
user.adjustPlasma(-A.plasma_cost)
-
/obj/effect/proc_holder/alien/neurotoxin
name = "Spit Neurotoxin"
desc = "Spits neurotoxin at someone, paralyzing them for a short time."
@@ -179,7 +183,7 @@ Doesn't work on other aliens/AI.*/
var/message
if(active)
message = "You empty your neurotoxin gland."
- remove_ranged_ability(user,message)
+ remove_ranged_ability(message)
else
message = "You prepare your neurotoxin gland. Left-click to fire at a target!"
add_ranged_ability(user, message, TRUE)
@@ -193,7 +197,7 @@ Doesn't work on other aliens/AI.*/
return
var/p_cost = 50
if(!iscarbon(ranged_ability_user) || ranged_ability_user.lying || ranged_ability_user.stat)
- remove_ranged_ability(ranged_ability_user)
+ remove_ranged_ability()
return
var/mob/living/carbon/user = ranged_ability_user
@@ -219,8 +223,7 @@ Doesn't work on other aliens/AI.*/
return TRUE
/obj/effect/proc_holder/alien/neurotoxin/on_lose(mob/living/carbon/user)
- if(user.ranged_ability == src)
- user.ranged_ability = null
+ remove_ranged_ability()
/obj/effect/proc_holder/alien/neurotoxin/add_ranged_ability(mob/living/user, msg)
..()
@@ -328,7 +331,3 @@ Doesn't work on other aliens/AI.*/
return 1
return 0
-
-
-/proc/cmp_abilities_cost(obj/effect/proc_holder/alien/a, obj/effect/proc_holder/alien/b)
- return b.plasma_cost - a.plasma_cost
diff --git a/code/modules/mob/living/carbon/alien/larva/powers.dm b/code/modules/mob/living/carbon/alien/larva/powers.dm
index 36191203ad..906ba71c96 100644
--- a/code/modules/mob/living/carbon/alien/larva/powers.dm
+++ b/code/modules/mob/living/carbon/alien/larva/powers.dm
@@ -34,6 +34,7 @@
if(L.handcuffed || L.legcuffed) // Cuffing larvas ? Eh ?
to_chat(user, "You cannot evolve when you are cuffed.")
+ return
if(L.amount_grown >= L.max_grown) //TODO ~Carn
to_chat(L, "You are growing into a beautiful alien! It is time to choose a caste.")
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 4109166ebd..80c6d836a0 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -302,10 +302,9 @@
return
I.being_removed = TRUE
breakouttime = I.breakouttime
- var/displaytime = breakouttime / 600
if(!cuff_break)
visible_message("[src] attempts to remove [I]!")
- to_chat(src, "You attempt to remove [I]... (This will take around [displaytime] minutes and you need to stand still.)")
+ to_chat(src, "You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")
if(do_after(src, breakouttime, 0, target = src))
clear_cuffs(I, cuff_break)
else
@@ -426,23 +425,6 @@
var/turf/target = get_turf(loc)
I.throw_at(target,I.throw_range,I.throw_speed,src)
-/mob/living/carbon/proc/AddAbility(obj/effect/proc_holder/alien/A)
- abilities.Add(A)
- A.on_gain(src)
- if(A.has_action)
- A.action.Grant(src)
- sortInsert(abilities, /proc/cmp_abilities_cost, 0)
-
-/mob/living/carbon/proc/RemoveAbility(obj/effect/proc_holder/alien/A)
- abilities.Remove(A)
- A.on_lose(src)
- if(A.action)
- A.action.Remove(src)
-
-/mob/living/carbon/proc/add_abilities_to_panel()
- for(var/obj/effect/proc_holder/alien/A in abilities)
- statpanel("[A.panel]",A.plasma_cost > 0?"([A.plasma_cost])":"",A)
-
/mob/living/carbon/Stat()
..()
if(statpanel("Status"))
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 8e9f66de31..45c10c6ae9 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -35,7 +35,6 @@
has_limbs = 1
var/obj/item/reagent_containers/food/snacks/meat/slab/type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab
- var/list/obj/effect/proc_holder/alien/abilities = list()
var/gib_type = /obj/effect/decal/cleanable/blood/gibs
var/rotate_on_lying = 1
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index d48d8608bc..74ccdab19c 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -311,7 +311,7 @@
if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/medical))
var/cyberimp_detect
for(var/obj/item/organ/cyberimp/CI in internal_organs)
- if(CI.status == ORGAN_ROBOTIC)
+ if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant)
cyberimp_detect += "[name] is modified with a [CI.name]. "
if(cyberimp_detect)
msg += "Detected cybernetic modifications: "
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 58b0c673a7..d66e6f808a 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -235,7 +235,7 @@
if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
return
var/time_taken = I.embedded_unsafe_removal_time*I.w_class
- usr.visible_message("[usr] attempts to remove [I] from their [L.name].","You attempt to remove [I] from your [L.name]... (It will take [time_taken/10] seconds.)")
+ usr.visible_message("[usr] attempts to remove [I] from their [L.name].","You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)")
if(do_after(usr, time_taken, needhand = 1, target = src))
if(!I || !L || I.loc != src || !(I in L.embedded_objects))
return
@@ -941,3 +941,124 @@
riding_datum.unequip_buckle_inhands(M)
riding_datum.restore_position(M)
. = ..(M, force)
+
+/mob/living/carbon/human/species
+ var/race = null
+
+/mob/living/carbon/human/species/Initialize()
+ . = ..()
+ set_species(race)
+
+/mob/living/carbon/human/species/abductor
+ race = /datum/species/abductor
+
+/mob/living/carbon/human/species/android
+ race = /datum/species/android
+
+/mob/living/carbon/human/species/angel
+ race = /datum/species/angel
+
+/mob/living/carbon/human/species/corporate
+ race = /datum/species/corporate
+
+/mob/living/carbon/human/species/fly
+ race = /datum/species/fly
+
+/mob/living/carbon/human/species/golem
+ race = /datum/species/golem
+
+/mob/living/carbon/human/species/golem/random
+ race = /datum/species/golem/random
+
+/mob/living/carbon/human/species/golem/adamantine
+ race = /datum/species/golem/adamantine
+
+/mob/living/carbon/human/species/golem/plasma
+ race = /datum/species/golem/plasma
+
+/mob/living/carbon/human/species/golem/diamond
+ race = /datum/species/golem/diamond
+
+/mob/living/carbon/human/species/golem/gold
+ race = /datum/species/golem/gold
+
+/mob/living/carbon/human/species/golem/silver
+ race = /datum/species/golem/silver
+
+/mob/living/carbon/human/species/golem/plasteel
+ race = /datum/species/golem/plasteel
+
+/mob/living/carbon/human/species/golem/titanium
+ race = /datum/species/golem/titanium
+
+/mob/living/carbon/human/species/golem/plastitanium
+ race = /datum/species/golem/plastitanium
+
+/mob/living/carbon/human/species/golem/alien_alloy
+ race = /datum/species/golem/alloy
+
+/mob/living/carbon/human/species/golem/wood
+ race = /datum/species/golem/wood
+
+/mob/living/carbon/human/species/golem/uranium
+ race = /datum/species/golem/uranium
+
+/mob/living/carbon/human/species/golem/sand
+ race = /datum/species/golem/sand
+
+/mob/living/carbon/human/species/golem/glass
+ race = /datum/species/golem/glass
+
+/mob/living/carbon/human/species/golem/bluespace
+ race = /datum/species/golem/bluespace
+
+/mob/living/carbon/human/species/golem/bananium
+ race = /datum/species/golem/bananium
+
+/mob/living/carbon/human/species/golem/blood_cult
+ race = /datum/species/golem/runic
+
+/mob/living/carbon/human/species/golem/cloth
+ race = /datum/species/golem/cloth
+
+/mob/living/carbon/human/species/golem/plastic
+ race = /datum/species/golem/plastic
+
+/mob/living/carbon/human/species/jelly
+ race = /datum/species/jelly
+
+/mob/living/carbon/human/species/jelly/slime
+ race = /datum/species/jelly/slime
+
+/mob/living/carbon/human/species/lizard
+ race = /datum/species/lizard
+
+/mob/living/carbon/human/species/lizard/ashwalker
+ race = /datum/species/lizard/ashwalker
+
+/mob/living/carbon/human/species/plasma
+ race = /datum/species/plasmaman
+
+/mob/living/carbon/human/species/pod
+ race = /datum/species/pod
+
+/mob/living/carbon/human/species/shadow
+ race = /datum/species/shadow
+
+/mob/living/carbon/human/species/skeleton
+ race = /datum/species/skeleton
+
+/mob/living/carbon/human/species/synth
+ race = /datum/species/synth
+
+/mob/living/carbon/human/species/synth/military
+ race = /datum/species/synth/military
+
+/mob/living/carbon/human/species/zombie
+ race = /datum/species/zombie
+
+/mob/living/carbon/human/species/zombie/infectious
+ race = /datum/species/zombie/infectious
+
+/mob/living/carbon/human/species/zombie/krokodil_addict
+ race = /datum/species/krokodil_addict
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm
index 80d64b29d4..160b0b73a1 100644
--- a/code/modules/mob/living/carbon/human/species_types/abductors.dm
+++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm
@@ -2,12 +2,10 @@
name = "Abductor"
id = "abductor"
say_mod = "gibbers"
- sexes = 0
+ sexes = FALSE
species_traits = list(NOBLOOD,NOBREATH,VIRUSIMMUNE,NOGUNS,NOHUNGER)
mutanttongue = /obj/item/organ/tongue/abductor
- var/scientist = 0 // vars to not pollute spieces list with castes
- var/team = 1
+ var/scientist = FALSE // vars to not pollute spieces list with castes
/datum/species/abductor/copy_properties_from(datum/species/abductor/old_species)
scientist = old_species.scientist
- team = old_species.team
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index b2e88e278a..47458b01d2 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -412,8 +412,9 @@
liver_failure()
else
liver.failing = FALSE
-
- if(((!(NOLIVER in dna.species.species_traits)) && (!liver)))
+ else
+ if((dna && dna.species && (NOLIVER in dna.species.species_traits)))
+ return
liver_failure()
/mob/living/carbon/proc/undergoing_liver_failure()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 649e19ba29..1cf99e8d9e 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -982,3 +982,19 @@
client.move_delay = world.time + movement_delay()
lying_prev = lying
return canmove
+
+/mob/living/proc/AddAbility(obj/effect/proc_holder/A)
+ abilities.Add(A)
+ A.on_gain(src)
+ if(A.has_action)
+ A.action.Grant(src)
+
+/mob/living/proc/RemoveAbility(obj/effect/proc_holder/A)
+ abilities.Remove(A)
+ A.on_lose(src)
+ if(A.action)
+ A.action.Remove(src)
+
+/mob/living/proc/add_abilities_to_panel()
+ for(var/obj/effect/proc_holder/A in abilities)
+ statpanel("[A.panel]",A.get_panel_text(),A)
\ No newline at end of file
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index f32ca97b09..36b8c62cca 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -77,3 +77,5 @@
var/datum/language/selected_default_language
var/last_words //used for database logging
+
+ var/list/obj/effect/proc_holder/abilities = list()
diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm
index 4d0453a17c..e148bd2763 100644
--- a/code/modules/mob/living/silicon/ai/say.dm
+++ b/code/modules/mob/living/silicon/ai/say.dm
@@ -97,7 +97,7 @@
/mob/living/silicon/ai/proc/announcement()
var/static/announcing_vox = 0 // Stores the time of the last announcement
if(announcing_vox > world.time)
- to_chat(src, "Please wait [round((announcing_vox - world.time) / 10)] seconds.")
+ to_chat(src, "Please wait [DisplayTimeText(announcing_vox - world.time)].")
return
var/message = input(src, "WARNING: Misuse of this verb can result in you being job banned. More help is available in 'Announcement Help'", "Announcement", src.last_announcement) as text
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 01baf578ee..e264f00cf1 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -810,7 +810,35 @@
cell = null
qdel(src)
-/mob/living/silicon/robot/syndicate
+/mob/living/silicon/robot/modules
+ var/set_module = null
+
+/mob/living/silicon/robot/modules/Initialize()
+ . = ..()
+ module.transform_to(set_module)
+
+/mob/living/silicon/robot/modules/standard
+ set_module = /obj/item/robot_module/standard
+
+/mob/living/silicon/robot/modules/medical
+ set_module = /obj/item/robot_module/medical
+
+/mob/living/silicon/robot/modules/engineering
+ set_module = /obj/item/robot_module/engineering
+
+/mob/living/silicon/robot/modules/security
+ set_module = /obj/item/robot_module/security
+
+/mob/living/silicon/robot/modules/peacekeeper
+ set_module = /obj/item/robot_module/peacekeeper
+
+/mob/living/silicon/robot/modules/miner
+ set_module = /obj/item/robot_module/miner
+
+/mob/living/silicon/robot/modules/janitor
+ set_module = /obj/item/robot_module/janitor
+
+/mob/living/silicon/robot/modules/syndicate
icon_state = "syndie_bloodhound"
faction = list("syndicate")
bubble_icon = "syndibot"
@@ -822,25 +850,24 @@
You are armed with powerful offensive tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \
Your cyborg LMG will slowly produce ammunition from your power supply, and your operative pinpointer will find and locate fellow nuclear operatives. \
Help the operatives secure the disk at all costs!"
- var/set_module = /obj/item/robot_module/syndicate
+ set_module = /obj/item/robot_module/syndicate
-/mob/living/silicon/robot/syndicate/Initialize()
+/mob/living/silicon/robot/modules/syndicate/Initialize()
. = ..()
cell.maxcharge = 25000
cell.charge = 25000
radio = new /obj/item/device/radio/borg/syndicate(src)
- module.transform_to(set_module)
laws = new /datum/ai_laws/syndicate_override()
addtimer(CALLBACK(src, .proc/show_playstyle), 5)
-/mob/living/silicon/robot/syndicate/proc/show_playstyle()
+/mob/living/silicon/robot/modules/syndicate/proc/show_playstyle()
if(playstyle_string)
to_chat(src, playstyle_string)
-/mob/living/silicon/robot/syndicate/ResetModule()
+/mob/living/silicon/robot/modules/syndicate/ResetModule()
return
-/mob/living/silicon/robot/syndicate/medical
+/mob/living/silicon/robot/modules/syndicate/medical
icon_state = "syndi-medi"
playstyle_string = "You are a Syndicate medical cyborg! \
You are armed with powerful medical tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \
diff --git a/code/modules/mob/living/silicon/silicon_movement.dm b/code/modules/mob/living/silicon/silicon_movement.dm
index c7267acf76..590326eda1 100644
--- a/code/modules/mob/living/silicon/silicon_movement.dm
+++ b/code/modules/mob/living/silicon/silicon_movement.dm
@@ -4,7 +4,9 @@
/mob/living/silicon/forceMove(atom/destination)
. = ..()
- update_camera_location(destination)
+ //Only bother updating the camera if we actually managed to move
+ if(.)
+ update_camera_location(destination)
/mob/living/silicon/proc/do_camera_update(oldLoc)
if(!QDELETED(builtInCamera) && oldLoc != get_turf(src))
diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
index b49534808a..0218ce5726 100644
--- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
@@ -27,7 +27,7 @@
del_on_death = 1
/mob/living/simple_animal/cockroach/death(gibbed)
- if(SSticker.cinematic) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes.
+ if(SSticker.mode && SSticker.mode.station_was_nuked) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes.
return
..()
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
index d8a2985594..144f7081e0 100644
--- a/code/modules/mob/living/simple_animal/guardian/guardian.dm
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -159,7 +159,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
resulthealth = round((summoner.health / summoner.maxHealth) * 100, 0.5)
stat(null, "Summoner Health: [resulthealth]%")
if(cooldown >= world.time)
- stat(null, "Manifest/Recall Cooldown Remaining: [max(round((cooldown - world.time)*0.1, 0.1), 0)] seconds")
+ stat(null, "Manifest/Recall Cooldown Remaining: [DisplayTimeText(cooldown - world.time)]")
/mob/living/simple_animal/hostile/guardian/Move() //Returns to summoner if they move out of range
. = ..()
diff --git a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm
index 9632ce3ff9..45d8c17d0c 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm
@@ -30,7 +30,7 @@
..()
if(statpanel("Status"))
if(stealthcooldown >= world.time)
- stat(null, "Stealth Cooldown Remaining: [max(round((stealthcooldown - world.time)*0.1, 0.1), 0)] seconds")
+ stat(null, "Stealth Cooldown Remaining: [DisplayTimeText(stealthcooldown - world.time)]")
/mob/living/simple_animal/hostile/guardian/assassin/AttackingTarget()
. = ..()
@@ -79,7 +79,7 @@
updatestealthalert()
toggle = TRUE
else if(!forced)
- to_chat(src, "You cannot yet enter stealth, wait another [max(round((stealthcooldown - world.time)*0.1, 0.1), 0)] seconds!")
+ to_chat(src, "You cannot yet enter stealth, wait another [DisplayTimeText(stealthcooldown - world.time)]!")
/mob/living/simple_animal/hostile/guardian/assassin/proc/updatestealthalert()
if(stealthcooldown <= world.time)
diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
index 45c093bbf2..c21b1474d8 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
@@ -14,7 +14,7 @@
..()
if(statpanel("Status"))
if(bomb_cooldown >= world.time)
- stat(null, "Bomb Cooldown Remaining: [max(round((bomb_cooldown - world.time)*0.1, 0.1), 0)] seconds")
+ stat(null, "Bomb Cooldown Remaining: [DisplayTimeText(bomb_cooldown - world.time)]")
/mob/living/simple_animal/hostile/guardian/bomb/AttackingTarget()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm
index 33ad25291c..db1581d8cb 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/support.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm
@@ -24,7 +24,7 @@
..()
if(statpanel("Status"))
if(beacon_cooldown >= world.time)
- stat(null, "Beacon Cooldown Remaining: [max(round((beacon_cooldown - world.time)*0.1, 0.1), 0)] seconds")
+ stat(null, "Beacon Cooldown Remaining: [DisplayTimeText(beacon_cooldown - world.time)]")
/mob/living/simple_animal/hostile/guardian/healer/AttackingTarget()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index 7e8bd6d2c8..75cc53e0c9 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -49,6 +49,17 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
var/playable_spider = FALSE
devourable = TRUE
+ var/datum/action/innate/spider/lay_web/lay_web
+ var/directive = "" //Message passed down to children, to relay the creator's orders
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Initialize()
+ . = ..()
+ lay_web = new
+ lay_web.Grant(src)
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Destroy()
+ QDEL_NULL(lay_web)
+ return ..()
/mob/living/simple_animal/hostile/poison/giant_spider/Topic(href, href_list)
if(href_list["activate"])
@@ -56,6 +67,12 @@
if(istype(ghost) && playable_spider)
humanize_spider(ghost)
+/mob/living/simple_animal/hostile/poison/giant_spider/Login()
+ ..()
+ if(directive)
+ to_chat(src, "Your mother left you a directive! Follow it at all costs.")
+ to_chat(src, "[directive]")
+
/mob/living/simple_animal/hostile/poison/giant_spider/attack_ghost(mob/user)
if(!humanize_spider(user))
return ..()
@@ -87,8 +104,26 @@
poison_per_bite = 3
var/atom/movable/cocoon_target
var/fed = 0
+ var/obj/effect/proc_holder/wrap/wrap
+ var/datum/action/innate/spider/lay_eggs/lay_eggs
+ var/datum/action/innate/spider/set_directive/set_directive
var/static/list/consumed_mobs = list() //the tags of mobs that have been consumed by nurse spiders to lay eggs
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Initialize()
+ . = ..()
+ wrap = new
+ AddAbility(wrap)
+ lay_eggs = new
+ lay_eggs.Grant(src)
+ set_directive = new
+ set_directive.Grant(src)
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Destroy()
+ RemoveAbility(wrap)
+ QDEL_NULL(lay_eggs)
+ QDEL_NULL(set_directive)
+ return ..()
+
//hunters have the most poison and move the fastest, so they can find prey
/mob/living/simple_animal/hostile/poison/giant_spider/hunter
desc = "Furry and black, it makes you shudder to look at it. This one has sparkling purple eyes."
@@ -117,6 +152,7 @@
move_to_delay = 4
poison_type = "venom" //all in venom, glass cannon. you bite 5 times and they are DEFINITELY dead, but 40 health and you are extremely obvious. Ambush, maybe?
speed = 1
+ gold_core_spawnable = 0
//tarantulas are really tanky, regenerating (maybe), hulky monster but are also extremely slow, so.
/mob/living/simple_animal/hostile/poison/giant_spider/tarantula
@@ -134,6 +170,7 @@
speed = 7
status_flags = NONE
mob_size = MOB_SIZE_LARGE
+ gold_core_spawnable = 0
/mob/living/simple_animal/hostile/poison/giant_spider/tarantula/movement_delay()
var/turf/T = get_turf(src)
@@ -153,12 +190,16 @@
maxHealth = 40
health = 40
var/datum/action/innate/spider/comm/letmetalkpls
+ gold_core_spawnable = 0
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife/Initialize()
. = ..()
letmetalkpls = new
letmetalkpls.Grant(src)
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife/Destroy()
+ QDEL_NULL(letmetalkpls)
+ return ..()
/mob/living/simple_animal/hostile/poison/giant_spider/ice //spiders dont usually like tempatures of 140 kelvin who knew
name = "giant ice spider"
@@ -222,11 +263,11 @@
//second, spin a sticky spiderweb on this tile
var/obj/structure/spider/stickyweb/W = locate() in get_turf(src)
if(!W)
- Web()
+ lay_web.Activate()
else
//third, lay an egg cluster there
if(fed)
- LayEggs()
+ lay_eggs.Activate()
else
//fourthly, cocoon any nearby items so those pesky pinkskins can't use them
for(var/obj/O in can_see)
@@ -244,62 +285,28 @@
else if(busy == MOVING_TO_TARGET && cocoon_target)
if(get_dist(src, cocoon_target) <= 1)
- Wrap()
+ cocoon()
else
busy = SPIDER_IDLE
stop_automated_movement = FALSE
-/mob/living/simple_animal/hostile/poison/giant_spider/verb/Web()
- set name = "Lay Web"
- set category = "Spider"
- set desc = "Spread a sticky web to slow down prey."
-
- var/T = src.loc
-
- if(stat == DEAD)
- return
- if(busy != SPINNING_WEB)
- busy = SPINNING_WEB
- src.visible_message("\the [src] begins to secrete a sticky substance.")
- stop_automated_movement = 1
- if(do_after(src, 40, target = T))
- if(busy == SPINNING_WEB && src.loc == T)
- new /obj/structure/spider/stickyweb(T)
- busy = SPIDER_IDLE
- stop_automated_movement = FALSE
-
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/verb/Wrap()
- set name = "Wrap"
- set category = "Spider"
- set desc = "Wrap up prey to feast upon and objects for safe keeping."
-
- if(stat == DEAD)
- return
- if(!cocoon_target)
- var/list/choices = list()
- for(var/mob/living/L in view(1,src))
- if(L == src || L.anchored)
- continue
- if(istype(L, /mob/living/simple_animal/hostile/poison/giant_spider))
- continue
- if(Adjacent(L))
- choices += L
- for(var/obj/O in src.loc)
- if(O.anchored)
- continue
- if(Adjacent(O))
- choices += O
- var/temp_input = input(src,"What do you wish to cocoon?") in null|choices
- if(temp_input && !cocoon_target)
- cocoon_target = temp_input
-
- if(stat != DEAD && cocoon_target && Adjacent(cocoon_target) && !cocoon_target.anchored)
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/cocoon()
+ if(stat != DEAD && cocoon_target && !cocoon_target.anchored)
+ if(cocoon_target == src)
+ to_chat(src, "You can't wrap yourself!")
+ return
+ if(istype(cocoon_target, /mob/living/simple_animal/hostile/poison/giant_spider))
+ to_chat(src, "You can't wrap other spiders!")
+ return
+ if(!Adjacent(cocoon_target))
+ to_chat(src, "You can't reach [cocoon_target]!")
+ return
if(busy == SPINNING_COCOON)
+ to_chat(src, "You're already spinning a cocoon!")
return //we're already doing this, don't cancel out or anything
busy = SPINNING_COCOON
- visible_message("\the [src] begins to secrete a sticky substance around \the [cocoon_target].")
+ visible_message("[src] begins to secrete a sticky substance around [cocoon_target].","You begin wrapping [cocoon_target] into a cocoon.")
stop_automated_movement = TRUE
walk(src,0)
if(do_after(src, 50, target = cocoon_target))
@@ -310,7 +317,8 @@
if(L.blood_volume && (L.stat != DEAD || !consumed_mobs[L.tag])) //if they're not dead, you can consume them anyway
consumed_mobs[L.tag] = TRUE
fed++
- visible_message("\the [src] sticks a proboscis into \the [L] and sucks a viscous substance out.")
+ lay_eggs.UpdateButtonIcon(TRUE)
+ visible_message("[src] sticks a proboscis into [L] and sucks a viscous substance out.","You suck the nutriment out of [L], feeding you enough to lay a cluster of eggs.")
L.death() //you just ate them, they're dead.
else
to_chat(src, "[L] cannot sate your hunger!")
@@ -322,35 +330,155 @@
busy = SPIDER_IDLE
stop_automated_movement = FALSE
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/verb/LayEggs()
- set name = "Lay Eggs"
- set category = "Spider"
- set desc = "Lay a clutch of eggs, but you must wrap a creature for feeding first."
+/datum/action/innate/spider
+ icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ background_icon_state = "bg_alien"
- var/obj/structure/spider/eggcluster/E = locate() in get_turf(src)
- if(stat == DEAD)
+/datum/action/innate/spider/lay_web
+ name = "Spin Web"
+ desc = "Spin a web to slow down potential prey."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "lay_web"
+
+/datum/action/innate/spider/lay_web/Activate()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
return
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+
+ if(!isturf(S.loc))
+ return
+ var/turf/T = get_turf(S)
+
+ var/obj/structure/spider/stickyweb/W = locate() in T
+ if(W)
+ to_chat(S, "There's already a web here!")
+ return
+
+ if(S.busy != SPINNING_WEB)
+ S.busy = SPINNING_WEB
+ S.visible_message("[S] begins to secrete a sticky substance.","You begin to lay a web.")
+ S.stop_automated_movement = TRUE
+ if(do_after(S, 40, target = T))
+ if(S.busy == SPINNING_WEB && S.loc == T)
+ new /obj/structure/spider/stickyweb(T)
+ S.busy = SPIDER_IDLE
+ S.stop_automated_movement = FALSE
+ else
+ to_chat(S, "You're already spinning a web!")
+
+/obj/effect/proc_holder/wrap
+ name = "Wrap"
+ panel = "Spider"
+ active = FALSE
+ datum/action/spell_action/action = null
+ desc = "Wrap something or someone in a cocoon. If it's a living being, you'll also consume them, allowing you to lay eggs."
+ ranged_mousepointer = 'icons/effects/wrap_target.dmi'
+ action_icon = 'icons/mob/actions/actions_animal.dmi'
+ action_icon_state = "wrap_0"
+ action_background_icon_state = "bg_alien"
+
+/obj/effect/proc_holder/wrap/Initialize()
+ . = ..()
+ action = new(src)
+
+/obj/effect/proc_holder/wrap/update_icon()
+ action.button_icon_state = "wrap_[active]"
+ action.UpdateButtonIcon()
+
+/obj/effect/proc_holder/wrap/Click()
+ if(!istype(usr, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return TRUE
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/user = usr
+ activate(user)
+ return TRUE
+
+/obj/effect/proc_holder/wrap/proc/activate(mob/living/user)
+ var/message
+ if(active)
+ message = "You no longer prepare to wrap something in a cocoon."
+ remove_ranged_ability(message)
+ else
+ message = "You prepare to wrap something in a cocoon. Left-click your target to start wrapping!"
+ add_ranged_ability(user, message, TRUE)
+ return 1
+
+/obj/effect/proc_holder/wrap/InterceptClickOn(mob/living/caller, params, atom/target)
+ if(..())
+ return
+ if(ranged_ability_user.incapacitated() || !istype(ranged_ability_user, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ remove_ranged_ability()
+ return
+
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/user = ranged_ability_user
+
+ if(user.Adjacent(target) && (ismob(target) || isobj(target)))
+ var/atom/movable/target_atom = target
+ if(target_atom.anchored)
+ return
+ user.cocoon_target = target_atom
+ INVOKE_ASYNC(user, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/.proc/cocoon)
+ remove_ranged_ability()
+ return TRUE
+
+/obj/effect/proc_holder/wrap/on_lose(mob/living/carbon/user)
+ remove_ranged_ability()
+
+/datum/action/innate/spider/lay_eggs
+ name = "Lay Eggs"
+ desc = "Lay a cluster of eggs, which will soon grow into more spiders. You must wrap a living being to do this."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "lay_eggs"
+
+/datum/action/innate/spider/lay_eggs/IsAvailable()
+ if(..())
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return 0
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+ if(S.fed)
+ return 1
+ return 0
+
+/datum/action/innate/spider/lay_eggs/Activate()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+
+ var/obj/structure/spider/eggcluster/E = locate() in get_turf(S)
if(E)
- to_chat(src, "There is already a cluster of eggs here!")
- else if(!fed)
- to_chat(src, "You are too hungry to do this!")
- else if(busy != LAYING_EGGS)
- busy = LAYING_EGGS
- src.visible_message("\the [src] begins to lay a cluster of eggs.")
- stop_automated_movement = 1
- if(do_after(src, 50, target = src.loc))
- if(busy == LAYING_EGGS)
- E = locate() in get_turf(src)
- if(!E)
- var/obj/structure/spider/eggcluster/C = new /obj/structure/spider/eggcluster(src.loc)
- if(ckey)
- C.player_spiders = 1
- C.poison_type = poison_type
- C.poison_per_bite = poison_per_bite
- C.faction = faction.Copy()
- fed--
- busy = SPIDER_IDLE
- stop_automated_movement = FALSE
+ to_chat(S, "There is already a cluster of eggs here!")
+ else if(!S.fed)
+ to_chat(S, "You are too hungry to do this!")
+ else if(S.busy != LAYING_EGGS)
+ S.busy = LAYING_EGGS
+ S.visible_message("[S] begins to lay a cluster of eggs.","You begin to lay a cluster of eggs.")
+ S.stop_automated_movement = TRUE
+ if(do_after(S, 50, target = get_turf(S)))
+ if(S.busy == LAYING_EGGS)
+ E = locate() in get_turf(S)
+ if(!E || !isturf(S.loc))
+ var/obj/structure/spider/eggcluster/C = new /obj/structure/spider/eggcluster(get_turf(S))
+ if(S.ckey)
+ C.player_spiders = TRUE
+ C.directive = S.directive
+ C.poison_type = S.poison_type
+ C.poison_per_bite = S.poison_per_bite
+ C.faction = S.faction.Copy()
+ S.fed--
+ UpdateButtonIcon(TRUE)
+ S.busy = SPIDER_IDLE
+ S.stop_automated_movement = FALSE
+
+/datum/action/innate/spider/set_directive
+ name = "Set Directive"
+ desc = "Set a directive for your children to follow."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "directive"
+
+/datum/action/innate/spider/set_directive/Activate()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+ S.directive = stripped_input(S, "Enter the new directive", "Create directive", "[S.directive]", MAX_MESSAGE_LEN)
/mob/living/simple_animal/hostile/poison/giant_spider/Login()
. = ..()
@@ -362,7 +490,8 @@
/datum/action/innate/spider/comm
name = "Command"
- button_icon_state = "cult_comms"
+ desc = "Send a command to all living spiders."
+ button_icon_state = "command"
/datum/action/innate/spider/comm/IsAvailable()
if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife))
@@ -370,19 +499,22 @@
return TRUE
/datum/action/innate/spider/comm/Trigger()
- var/input = stripped_input(usr, "Input a message for your legions to follow.", "Command", "")
+ var/input = stripped_input(owner, "Input a command for your legions to follow.", "Command", "")
if(QDELETED(src) || !input || !IsAvailable())
return FALSE
- spider_command(usr, input)
+ spider_command(owner, input)
return TRUE
/datum/action/innate/spider/comm/proc/spider_command(mob/living/user, message)
if(!message)
return
var/my_message
- my_message = "COMMAND FROM SPIDER QUEEN: [message]"
+ my_message = "Command from [user]: [message]"
for(var/mob/living/simple_animal/hostile/poison/giant_spider/M in GLOB.spidermobs)
to_chat(M, my_message)
+ for(var/M in GLOB.dead_mob_list)
+ var/link = FOLLOW_LINK(M, user)
+ to_chat(M, "[link] [my_message]")
log_talk(user, "SPIDERCOMMAND: [key_name(user)] : [message]",LOGSAY)
/mob/living/simple_animal/hostile/poison/giant_spider/handle_temperature_damage()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
index 5f45d47494..a80340c28a 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -144,44 +144,42 @@
return TRUE
/proc/UnlockMedal(medal,client/player)
-
+ set waitfor = FALSE
if(!player || !medal)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
- spawn()
- var/result = world.SetMedal(medal, player, global.medal_hub, global.medal_pass)
- if(isnull(result))
- global.medals_enabled = FALSE
- log_game("MEDAL ERROR: Could not contact hub to award medal:[medal] player:[player.ckey]")
- message_admins("Error! Failed to contact hub to award [medal] medal to [player.ckey]!")
- else if (result)
- to_chat(player, "Achievement unlocked: [medal]!")
+ var/result = world.SetMedal(medal, player, global.medal_hub, global.medal_pass)
+ if(isnull(result))
+ global.medals_enabled = FALSE
+ log_game("MEDAL ERROR: Could not contact hub to award medal:[medal] player:[player.ckey]")
+ message_admins("Error! Failed to contact hub to award [medal] medal to [player.ckey]!")
+ else if (result)
+ to_chat(player, "Achievement unlocked: [medal]!")
/proc/SetScore(score,client/player,increment,force)
-
+ set waitfor = FALSE
if(!score || !player)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
- spawn()
- var/list/oldscore = GetScore(score,player,1)
+ var/list/oldscore = GetScore(score,player,1)
- if(increment)
- if(!oldscore[score])
- oldscore[score] = 1
- else
- oldscore[score] = (text2num(oldscore[score]) + 1)
+ if(increment)
+ if(!oldscore[score])
+ oldscore[score] = 1
else
- oldscore[score] = force
+ oldscore[score] = (text2num(oldscore[score]) + 1)
+ else
+ oldscore[score] = force
- var/newscoreparam = list2params(oldscore)
+ var/newscoreparam = list2params(oldscore)
- var/result = world.SetScores(player.ckey, newscoreparam, global.medal_hub, global.medal_pass)
+ var/result = world.SetScores(player.ckey, newscoreparam, global.medal_hub, global.medal_pass)
- if(isnull(result))
- global.medals_enabled = FALSE
- log_game("SCORE ERROR: Could not contact hub to set score. Score:[score] player:[player.ckey]")
- message_admins("Error! Failed to contact hub to set [score] score for [player.ckey]!")
+ if(isnull(result))
+ global.medals_enabled = FALSE
+ log_game("SCORE ERROR: Could not contact hub to set score. Score:[score] player:[player.ckey]")
+ message_admins("Error! Failed to contact hub to set [score] score for [player.ckey]!")
/proc/GetScore(score,client/player,returnlist)
diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm
index b6cf404248..1618b68478 100644
--- a/code/modules/modular_computers/computers/item/laptop.dm
+++ b/code/modules/modular_computers/computers/item/laptop.dm
@@ -21,6 +21,11 @@
var/w_class_open = WEIGHT_CLASS_BULKY
var/slowdown_open = TRUE
+/obj/item/device/modular_computer/laptop/examine(mob/user)
+ ..()
+ if(screen_on)
+ to_chat(user, "Alt-click to close it.")
+
/obj/item/device/modular_computer/laptop/Initialize()
. = ..()
diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm
index bc188485bc..25fa05ef1e 100644
--- a/code/modules/modular_computers/computers/machinery/console_presets.dm
+++ b/code/modules/modular_computers/computers/machinery/console_presets.dm
@@ -44,6 +44,10 @@
desc = "A stationary computer. This one comes preloaded with research programs."
_has_ai = 1
+/obj/machinery/modular_computer/console/preset/research/examine(mob/user)
+ ..()
+ to_chat(user, "Alt-click to eject the intelliCard.")
+
/obj/machinery/modular_computer/console/preset/research/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/ntnetmonitor())
@@ -59,6 +63,10 @@
_has_id_slot = 1
_has_printer = 1
+/obj/machinery/modular_computer/console/preset/command/examine(mob/user)
+ ..()
+ to_chat(user, "Alt-click [src] to eject the identification card.")
+
/obj/machinery/modular_computer/console/preset/command/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/chatclient())
@@ -72,4 +80,4 @@
/obj/machinery/modular_computer/console/preset/civilian/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/chatclient())
- hard_drive.store_file(new/datum/computer_file/program/nttransfer())
\ No newline at end of file
+ hard_drive.store_file(new/datum/computer_file/program/nttransfer())
diff --git a/code/modules/modular_computers/file_system/programs/file_browser.dm b/code/modules/modular_computers/file_system/programs/file_browser.dm
index 4a94090ed4..f42174320e 100644
--- a/code/modules/modular_computers/file_system/programs/file_browser.dm
+++ b/code/modules/modular_computers/file_system/programs/file_browser.dm
@@ -170,12 +170,19 @@
t = replacetext(t, "\[td\]", "
")
t = replacetext(t, "\[cell\]", "
")
t = replacetext(t, "\[tab\]", " ")
+
+ t = parsemarkdown_basic(t)
+
return t
/datum/computer_file/program/filemanager/proc/prepare_printjob(t) // Additional stuff to parse if we want to print it and make a happy Head of Personnel. Forms FTW.
t = replacetext(t, "\[field\]", "")
t = replacetext(t, "\[sign\]", "")
+
t = parse_tags(t)
+
+ t = replacetext(t, regex("(?:%s(?:ign)|%f(?:ield))(?=\\s|$)", "ig"), "")
+
return t
/datum/computer_file/program/filemanager/ui_data(mob/user)
diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm
index 8ff3652367..a3184cbb20 100644
--- a/code/modules/ninja/ninja_event.dm
+++ b/code/modules/ninja/ninja_event.dm
@@ -71,13 +71,9 @@ Contents:
var/datum/antagonist/ninja/ninjadatum = add_ninja(Ninja)
ninjadatum.equip_space_ninja()
- Ninja.internal = Ninja.s_store
- Ninja.update_internals_hud_icon(1)
-
if(Ninja.mind != Mind) //something has gone wrong!
throw EXCEPTION("Ninja created with incorrect mind")
-
SSticker.mode.update_ninja_icons_added(Ninja)
spawned_mobs += Ninja
message_admins("[key_name_admin(Ninja)] has been made into a ninja by an event.")
diff --git a/code/modules/ninja/outfit.dm b/code/modules/ninja/outfit.dm
new file mode 100644
index 0000000000..4ec9cde23c
--- /dev/null
+++ b/code/modules/ninja/outfit.dm
@@ -0,0 +1,25 @@
+/datum/outfit/ninja
+ name = "Space Ninja"
+ uniform = /obj/item/clothing/under/color/black
+ suit = /obj/item/clothing/suit/space/space_ninja
+ glasses = /obj/item/clothing/glasses/night
+ mask = /obj/item/clothing/mask/gas/space_ninja
+ head = /obj/item/clothing/head/helmet/space/space_ninja
+ ears = /obj/item/device/radio/headset
+ shoes = /obj/item/clothing/shoes/space_ninja
+ gloves = /obj/item/clothing/gloves/space_ninja
+ back = /obj/item/tank/jetpack/carbondioxide
+ l_pocket = /obj/item/grenade/plastic/x4
+ r_pocket = /obj/item/tank/internals/emergency_oxygen
+ internals_slot = slot_r_store
+ belt = /obj/item/dash/energy_katana
+ implants = list(/obj/item/implant/explosive)
+
+
+/datum/outfit/ninja/post_equip(mob/living/carbon/human/H)
+ if(istype(H.wear_suit, suit))
+ var/obj/item/clothing/suit/space/space_ninja/S = H.wear_suit
+ if(istype(H.belt, belt))
+ S.energyKatana = H.belt
+ S.randomize_param()
+
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index e3d6154606..5abf1b7998 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -64,6 +64,8 @@
/obj/item/paper/examine(mob/user)
..()
+ to_chat(user, "Alt-click to fold it.")
+
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper)
assets.send(user)
@@ -79,7 +81,7 @@
user << browse("[name][stars(info)][stamps]", "window=[name]")
onclose(user, "[name]")
else
- to_chat(user, "It is too far away.")
+ to_chat(user, "You're too far away to read it!")
/obj/item/paper/verb/rename()
@@ -101,10 +103,12 @@
name = "paper[(n_name ? text("- '[n_name]'") : null)]"
add_fingerprint(usr)
+
/obj/item/paper/suicide_act(mob/user)
user.visible_message("[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku...")
return (BRUTELOSS)
+
/obj/item/paper/attack_self(mob/user)
user.examinate(src)
if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS]))
@@ -187,47 +191,15 @@
if(length(t) < 1) //No input means nothing needs to be parsed
return
-// t = copytext(sanitize(t),1,MAX_MESSAGE_LEN)
-
- t = replacetext(t, "\[center\]", "
")
- t = replacetext(t, "\[/center\]", "
")
- t = replacetext(t, "\[br\]", " ")
- t = replacetext(t, "\n", " ")
- t = replacetext(t, "\[b\]", "")
- t = replacetext(t, "\[/b\]", "")
- t = replacetext(t, "\[i\]", "")
- t = replacetext(t, "\[/i\]", "")
- t = replacetext(t, "\[u\]", "")
- t = replacetext(t, "\[/u\]", "")
- t = replacetext(t, "\[large\]", "")
- t = replacetext(t, "\[/large\]", "")
- t = replacetext(t, "\[sign\]", "[user.real_name]")
- t = replacetext(t, "\[field\]", "")
- t = replacetext(t, "\[tab\]", " ")
+ t = parsemarkdown(t, user, iscrayon)
if(!iscrayon)
- t = replacetext(t, "\[*\]", "
")
- t = replacetext(t, "\[hr\]", "")
- t = replacetext(t, "\[small\]", "")
- t = replacetext(t, "\[/small\]", "")
- t = replacetext(t, "\[list\]", "
")
- t = replacetext(t, "\[/list\]", "
")
-
t = "[t]"
- else // If it is a crayon, and he still tries to use these, make them empty!
+ else
var/obj/item/toy/crayon/C = P
- t = replacetext(t, "\[*\]", "")
- t = replacetext(t, "\[hr\]", "")
- t = replacetext(t, "\[small\]", "")
- t = replacetext(t, "\[/small\]", "")
- t = replacetext(t, "\[list\]", "")
- t = replacetext(t, "\[/list\]", "")
-
t = "[t]"
-// t = replacetext(t, "#", "") // Junk converted to nothing!
-
-//Count the fields
+ // Count the fields
var/laststart = 1
while(1)
var/i = findtext(t, "", laststart)
@@ -253,22 +225,23 @@
/obj/item/paper/proc/openhelp(mob/user)
user << browse({"Paper Help
+ You can use backslash (\\) to escape special characters.
+
Crayon&Pen commands
- \[br\] : Creates a linebreak.
- \[center\] - \[/center\] : Centers the text.
- \[b\] - \[/b\] : Makes the text bold.
- \[i\] - \[/i\] : Makes the text italic.
- \[u\] - \[/u\] : Makes the text underlined.
- \[large\] - \[/large\] : Increases the size of the text.
- \[sign\] : Inserts a signature of your name in a foolproof way.
- \[field\] : Inserts an invisible field which lets you start type from there. Useful for forms.
+ # text : Defines a header.
+ |text| : Centers the text.
+ **text** : Makes the text bold.
+ *text* : Makes the text italic.
+ ^text^ : Increases the size of the text.
+ %s : Inserts a signature of your name in a foolproof way.
+ %f : Inserts an invisible field which lets you start type from there. Useful for forms.
Pen exclusive commands
- \[small\] - \[/small\] : Decreases the size of the text.
- \[list\] - \[/list\] : A list.
- \[*\] : A dot used for lists.
- \[hr\] : Adds a horizontal rule.
+ ((text)) : Decreases the size of the text.
+ * item : An unordered list item.
+ * item: An unordered list child item.
+ --- : Adds a horizontal rule.
"}, "window=paper_help")
@@ -399,4 +372,5 @@
return
/obj/item/paper/crumpled/bloody
- icon_state = "scrap_bloodied"
\ No newline at end of file
+ icon_state = "scrap_bloodied"
+
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index 381dcbaa75..b566d65f49 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -73,7 +73,6 @@
resolved = TRUE
sound_to_playing_players('sound/machines/alarm.ogg')
addtimer(CALLBACK(GLOBAL_PROC, .proc/cult_ending_helper), 120)
- addtimer(CALLBACK(GLOBAL_PROC, .proc/ending_helper), 220)
/obj/singularity/narsie/large/cult/Destroy()
GLOB.cult_narsie = null
@@ -83,7 +82,7 @@
SSticker.force_ending = 1
/proc/cult_ending_helper(var/no_explosion = 0)
- SSticker.station_explosion_cinematic(no_explosion, "cult", null)
+ Cinematic(CINEMATIC_CULT,world,CALLBACK(GLOBAL_PROC,.ending_helper))
/obj/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob)
diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm
index 382853066d..d0f17c5210 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_control.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm
@@ -204,8 +204,8 @@
/obj/machinery/particle_accelerator/control_box/proc/toggle_power()
active = !active
investigate_log("turned [active?"ON":"OFF"] by [usr ? key_name(usr) : "outside forces"]", INVESTIGATE_SINGULO)
- message_admins("PA Control Computer turned [active ?"ON":"OFF"] by [usr ? key_name_admin(usr) : "outside forces"](?) (FLW) in ([x],[y],[z] - JMP)",0,1)
- log_game("PA Control Computer turned [active ?"ON":"OFF"] by [usr ? "[key_name(usr)]" : "outside forces"] in ([x],[y],[z])")
+ message_admins("PA Control Computer turned [active ?"ON":"OFF"] by [usr ? key_name_admin(usr) : "outside forces"][ADMIN_QUE(usr)] [ADMIN_FLW(usr)] in [ADMIN_COORDJMP(src)]",0,1)
+ log_game("PA Control Computer turned [active ?"ON":"OFF"] by [usr ? "[key_name(usr)]" : "outside forces"] in [COORD(src)]")
if(active)
use_power = ACTIVE_POWER_USE
for(var/CP in connected_parts)
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 07cb98ea6d..eb6b3f0c52 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -537,7 +537,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_shard)
to_chat(user, "You carefully begin to scrape \the [src] with \the [W]...")
if(do_after(user, 60 * W.toolspeed, TRUE, src))
to_chat(user, "You extract a sliver from \the [src]. \The [src] begins to react violently!")
- new /obj/item/nuke_core/supermatter_sliver(user.loc)
+ new /obj/item/nuke_core/supermatter_sliver(drop_location())
matter_power += 200
else if(user.dropItemToGround(W))
user.visible_message("As [user] touches \the [src] with \a [W], silence fills the room...",\
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index a9ea558072..58ff061e9d 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -136,13 +136,27 @@
boolets += magazine.ammo_count()
return boolets
+#define BRAINS_BLOWN_THROW_RANGE 3
+#define BRAINS_BLOWN_THROW_SPEED 1
/obj/item/gun/ballistic/suicide_act(mob/user)
- if (chambered && chambered.BB && can_trigger_gun(user) && !chambered.BB.nodamage)
+ var/obj/item/organ/brain/B = user.getorganslot("brain")
+ if (B && chambered && chambered.BB && can_trigger_gun(user) && !chambered.BB.nodamage)
user.visible_message("[user] is putting the barrel of [src] in [user.p_their()] mouth. It looks like [user.p_theyre()] trying to commit suicide!")
sleep(25)
if(user.is_holding(src))
+ var/turf/T = get_turf(user)
process_fire(user, user, 0, zone_override = "head")
user.visible_message("[user] blows [user.p_their()] brain[user.p_s()] out with [src]!")
+ var/turf/target = get_ranged_target_turf(user, turn(user.dir, 180), BRAINS_BLOWN_THROW_RANGE)
+ B.Remove(user)
+ B.forceMove(T)
+ var/datum/dna/user_dna
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ user_dna = C.dna
+ B.add_blood(user_dna)
+ var/datum/callback/gibspawner = CALLBACK(GLOBAL_PROC, /proc/spawn_atom_to_turf, /obj/effect/gibspawner/generic, B, 1, FALSE, list(user_dna))
+ B.throw_at(target, BRAINS_BLOWN_THROW_RANGE, BRAINS_BLOWN_THROW_SPEED, callback=gibspawner)
return(BRUTELOSS)
else
user.visible_message("[user] panics and starts choking to death!")
@@ -151,8 +165,8 @@
user.visible_message("[user] is pretending to blow [user.p_their()] brain[user.p_s()] out with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
playsound(loc, 'sound/weapons/empty.ogg', 50, 1, -1)
return (OXYLOSS)
-
-
+#undef BRAINS_BLOWN_THROW_SPEED
+#undef BRAINS_BLOWN_THROW_RANGE
/obj/item/gun/ballistic/proc/sawoff(mob/user)
if(sawn_state == SAWN_OFF)
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index 71bdce7f28..bbaf20689c 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -213,6 +213,10 @@
var/toggled = FALSE
var/obj/item/ammo_box/magazine/internal/shot/alternate_magazine
+/obj/item/gun/ballistic/shotgun/automatic/dual_tube/examine(mob/user)
+ ..()
+ to_chat(user, "Alt-click to pump it.")
+
/obj/item/gun/ballistic/shotgun/automatic/dual_tube/Initialize()
. = ..()
if (!alternate_magazine)
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index 27284a1712..8c4f80b772 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -139,9 +139,9 @@
if("syndiborg")
var/path
if(prob(50))
- path = /mob/living/silicon/robot/syndicate
+ path = /mob/living/silicon/robot/modules/syndicate
else
- path = /mob/living/silicon/robot/syndicate/medical
+ path = /mob/living/silicon/robot/modules/syndicate/medical
new_mob = new path(M.loc)
if("drone")
new_mob = new /mob/living/simple_animal/drone/polymorphed(M.loc)
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index 7e08a11b49..62e5fd723d 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -151,6 +151,12 @@
for(var/i in 1 to 4 + rand(1,2))
var/chosen = pick(borks)
var/obj/B = new chosen(T)
+ if(prob(5))//Fry it!
+ var/obj/item/reagent_containers/food/snacks/deepfryholder/D = new(T)
+ var/datum/reagents/reagents = new(25)
+ reagents.add_reagent("nutriment", 25)
+ D.fry(B, reagents)
+ B = D
if(prob(50))
for(var/j in 1 to rand(1, 3))
step(B, pick(NORTH,SOUTH,EAST,WEST))
@@ -173,6 +179,7 @@
/obj/item/reagent_containers/food/snacks/soup,
/obj/item/reagent_containers/food/snacks/grown,
/obj/item/reagent_containers/food/snacks/grown/mushroom,
+ /obj/item/reagent_containers/food/snacks/deepfryholder
)
blocked |= typesof(/obj/item/reagent_containers/food/snacks/customizable)
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 0b3c930962..6eedd257d0 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -542,84 +542,6 @@
log_admin("[key_name(G)] was made a golem by [key_name(user)].")
qdel(src)
-
-
-
-/obj/effect/timestop
- anchored = TRUE
- name = "chronofield"
- desc = "ZA WARUDO"
- icon = 'icons/effects/160x160.dmi'
- icon_state = "time"
- layer = FLY_LAYER
- pixel_x = -64
- pixel_y = -64
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- var/mob/living/immune = list() // the one who creates the timestop is immune
- var/list/stopped_atoms = list()
- var/freezerange = 2
- var/duration = 140
- alpha = 125
-
-/obj/effect/timestop/Initialize()
- . = ..()
- for(var/mob/living/L in GLOB.player_list)
- if(locate(/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop) in L.mind.spell_list) //People who can stop time are immune to its effects
- immune += L
- timestop()
-
-
-/obj/effect/timestop/proc/timestop()
- set waitfor = FALSE
- playsound(src, 'sound/magic/timeparadox2.ogg', 75, 1, -1)
- for(var/i in 1 to duration-1)
- for(var/atom/A in orange (freezerange, src.loc))
- if(isliving(A))
- var/mob/living/M = A
- if(M in immune)
- continue
- M.Stun(200, 1, 1)
- M.anchored = TRUE
- if(ishostile(M))
- var/mob/living/simple_animal/hostile/H = M
- H.AIStatus = AI_OFF
- H.LoseTarget()
- stopped_atoms |= M
- else if(istype(A, /obj/item/projectile))
- var/obj/item/projectile/P = A
- P.paused = TRUE
- stopped_atoms |= P
-
- for(var/mob/living/M in stopped_atoms)
- if(get_dist(get_turf(M),get_turf(src)) > freezerange) //If they lagged/ran past the timestop somehow, just ignore them
- unfreeze_mob(M)
- stopped_atoms -= M
- stoplag()
-
- //End
- playsound(src, 'sound/magic/timeparadox2.ogg', 75, TRUE, frequency = -1) //reverse!
- for(var/mob/living/M in stopped_atoms)
- unfreeze_mob(M)
-
- for(var/obj/item/projectile/P in stopped_atoms)
- P.paused = FALSE
- qdel(src)
- return
-
-
-
-/obj/effect/timestop/proc/unfreeze_mob(mob/living/M)
- M.AdjustStun(-200, 1, 1)
- M.anchored = FALSE
- if(ishostile(M))
- var/mob/living/simple_animal/hostile/H = M
- H.AIStatus = initial(H.AIStatus)
-
-
-/obj/effect/timestop/wizard
- duration = 100
-
-
/obj/item/stack/tile/bluespace
name = "bluespace floor tile"
singular_name = "floor tile"
diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index 9199e5eb14..65669d8251 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -1,7 +1,6 @@
/obj/machinery/computer/camera_advanced/shuttle_docker
name = "navigation computer"
desc = "Used to designate a precise transit location for a spacecraft."
- z_lock = ZLEVEL_STATION_PRIMARY
jump_action = null
var/datum/action/innate/shuttledocker_rotate/rotate_action = new
var/datum/action/innate/shuttledocker_place/place_action = new
@@ -133,7 +132,7 @@
if(!V)
continue
var/obj/docking_port/stationary/S = V
- if(z_lock && (S.z != z_lock))
+ if(z_lock.len && !(S.z in z_lock))
continue
if((S.id == shuttlePortId) || jumpto_ports[S.id])
continue
@@ -222,7 +221,7 @@
if(!V)
continue
var/obj/docking_port/stationary/S = V
- if(console.z_lock && (S.z != console.z_lock))
+ if(console.z_lock.len && !(S.z in console.z_lock))
continue
if(console.jumpto_ports[S.id])
L[S.name] = S
diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm
index b21df4000c..ac1339d33e 100644
--- a/code/modules/shuttle/syndicate.dm
+++ b/code/modules/shuttle/syndicate.dm
@@ -20,7 +20,7 @@
if(href_list["move"])
var/obj/item/circuitboard/computer/syndicate_shuttle/board = circuit
if(board.challenge && world.time < SYNDICATE_CHALLENGE_TIMER)
- to_chat(usr, "You've issued a combat challenge to the station! You've got to give them at least [round(((SYNDICATE_CHALLENGE_TIMER - world.time) / 10) / 60)] more minutes to allow them to prepare.")
+ to_chat(usr, "You've issued a combat challenge to the station! You've got to give them at least [DisplayTimeText(SYNDICATE_CHALLENGE_TIMER - world.time)] more to allow them to prepare.")
return 0
board.moved = TRUE
..()
@@ -47,8 +47,8 @@
desc = "Used to designate a precise transit location for the syndicate shuttle."
icon_screen = "syndishuttle"
icon_keyboard = "syndie_key"
- z_lock = ZLEVEL_STATION_PRIMARY
shuttleId = "syndicate"
+ station_lock_override = TRUE
shuttlePortId = "syndicate_custom"
shuttlePortName = "custom location"
jumpto_ports = list("syndicate_ne" = 1, "syndicate_nw" = 1, "syndicate_n" = 1, "syndicate_se" = 1, "syndicate_sw" = 1, "syndicate_s" = 1)
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 3cb56becf8..d3008625cf 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -8,6 +8,28 @@
var/ranged_mousepointer
var/mob/living/ranged_ability_user
var/ranged_clickcd_override = -1
+ var/has_action = TRUE
+ var/datum/action/spell_action/action = null
+ var/action_icon = 'icons/mob/actions/actions_spells.dmi'
+ var/action_icon_state = "spell_default"
+ var/action_background_icon_state = "bg_spell"
+
+/obj/effect/proc_holder/Initialize()
+ . = ..()
+ if(has_action)
+ action = new(src)
+
+/obj/effect/proc_holder/proc/on_gain(mob/living/user)
+ return
+
+/obj/effect/proc_holder/proc/on_lose(mob/living/user)
+ return
+
+/obj/effect/proc_holder/proc/fire(mob/living/user)
+ return TRUE
+
+/obj/effect/proc_holder/proc/get_panel_text()
+ return ""
GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for the badmin verb for now
@@ -118,10 +140,10 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
var/critfailchance = 0
var/centcom_cancast = 1 //Whether or not the spell should be allowed on z2
- var/action_icon = 'icons/mob/actions/actions_spells.dmi'
- var/action_icon_state = "spell_default"
- var/action_background_icon_state = "bg_spell"
- var/datum/action/spell_action/action
+ action_icon = 'icons/mob/actions/actions_spells.dmi'
+ action_icon_state = "spell_default"
+ action_background_icon_state = "bg_spell"
+ datum/action/spell_action/spell/action
/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
diff --git a/code/modules/stock_market/computer.dm b/code/modules/stock_market/computer.dm
index d693b86527..90ad08c4bb 100644
--- a/code/modules/stock_market/computer.dm
+++ b/code/modules/stock_market/computer.dm
@@ -82,7 +82,7 @@ a.updated {
mystocks = S.shareholders[logged_in]
dat += "
[S.name]([S.short_name])[S.bankrupt ? " BANKRUPT" : null] "
if (S.last_unification)
- dat += "Unified shares [(world.time - S.last_unification) / 600] minutes ago. "
+ dat += "Unified shares [DisplayTimeText(world.time - S.last_unification)] ago. "
dat += "Current value per share: [S.current_value] | View history
"
dat += "You currently own [mystocks] shares in this company. There are [S.available_shares] purchasable shares on the market currently. "
if (S.bankrupt)
diff --git a/code/modules/surgery/organs/augments_chest.dm b/code/modules/surgery/organs/augments_chest.dm
index bdd385bcac..7fd09d69c2 100644
--- a/code/modules/surgery/organs/augments_chest.dm
+++ b/code/modules/surgery/organs/augments_chest.dm
@@ -61,7 +61,7 @@
else
cooldown = revive_cost + world.time
reviving = FALSE
- to_chat(owner, "Your reviver implant shuts down and starts recharging. It will be ready again in [revive_cost/10] seconds.")
+ to_chat(owner, "Your reviver implant shuts down and starts recharging. It will be ready again in [DisplayTimeText(revive_cost)].")
return
if(cooldown > world.time)
diff --git a/code/modules/surgery/organs/augments_eyes.dm b/code/modules/surgery/organs/augments_eyes.dm
index 75014626be..eda6e34677 100644
--- a/code/modules/surgery/organs/augments_eyes.dm
+++ b/code/modules/surgery/organs/augments_eyes.dm
@@ -39,3 +39,8 @@
desc = "These cybernetic eye implants will display a security HUD over everything you see."
origin_tech = "materials=4;programming=4;biotech=3;combat=3"
HUD_type = DATA_HUD_SECURITY_ADVANCED
+
+/obj/item/organ/cyberimp/eyes/hud/security/syndicate
+ name = "Contraband Security HUD Implant"
+ desc = "A Cybersun Industries brand Security HUD Implant. These illicit cybernetic eye implants will display a security HUD over everything you see."
+ syndicate_implant = TRUE
diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm
index 4e478d3420..1eec609fc0 100644
--- a/code/modules/surgery/organs/augments_internal.dm
+++ b/code/modules/surgery/organs/augments_internal.dm
@@ -6,6 +6,7 @@
status = ORGAN_ROBOTIC
var/implant_color = "#FFFFFF"
var/implant_overlay
+ var/syndicate_implant = FALSE //Makes the implant invisible to health analyzers and medical HUDs.
/obj/item/organ/cyberimp/New(var/mob/M = null)
if(iscarbon(M))
diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm
index b69c1f4c5c..5e67e73a8a 100644
--- a/code/modules/surgery/organs/tongue.dm
+++ b/code/modules/surgery/organs/tongue.dm
@@ -85,10 +85,9 @@
var/obj/item/organ/tongue/T = H.getorganslot("tongue")
if(!T || T.type != type)
continue
- else if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor")
- var/datum/species/abductor/Ayy = user.dna.species
- var/datum/species/abductor/Byy = H.dna.species
- if(Ayy.team != Byy.team)
+ if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor")
+ var/datum/antagonist/abductor/A = user.mind.has_antag_datum(ANTAG_DATUM_ABDUCTOR)
+ if(!A || !(H.mind in A.team.members))
continue
to_chat(H, rendered)
for(var/mob/M in GLOB.dead_mob_list)
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index 8f32aa89eb..eed05c6161 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -91,7 +91,7 @@
. = ..()
if(!IsAvailable())
if(world.time < cords.next_command)
- to_chat(owner, "You must wait [(cords.next_command - world.time)/10] seconds before Speaking again.")
+ to_chat(owner, "You must wait [DisplayTimeText(cords.next_command - world.time)] before Speaking again.")
return
var/command = input(owner, "Speak with the Voice of God", "Command")
if(QDELETED(src) || QDELETED(owner))
@@ -102,7 +102,7 @@
/obj/item/organ/vocal_cords/colossus/can_speak_with()
if(world.time < next_command)
- to_chat(owner, "You must wait [(next_command - world.time)/10] seconds before Speaking again.")
+ to_chat(owner, "You must wait [DisplayTimeText(next_command - world.time)] before Speaking again.")
return FALSE
if(!owner)
return FALSE
diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm
index 3a12d580c4..afafbbdf66 100644
--- a/code/modules/tooltip/tooltip.dm
+++ b/code/modules/tooltip/tooltip.dm
@@ -65,6 +65,10 @@ Notes:
else if (!title && content)
content = "
[content]
"
+ // Strip macros from item names
+ title = replacetext(title, "\proper", "")
+ title = replacetext(title, "\improper", "")
+
//Make our dumb param object
params = {"{ "cursor": "[params]", "screenLoc": "[thing.screen_loc]" }"}
diff --git a/code/modules/uplink/uplink_item_cit.dm b/code/modules/uplink/uplink_item_cit.dm
index c9bb091303..3aa1fd8bb1 100644
--- a/code/modules/uplink/uplink_item_cit.dm
+++ b/code/modules/uplink/uplink_item_cit.dm
@@ -31,12 +31,133 @@
/datum/uplink_item/dangerous/antitank
name = "Anti Tank Pistol"
- desc = "Essentially amounting to a sniper rifle with no stock and barrel (or indeed, any rifling at all),\
- this extremely dubious pistol is guaranteed to dislocate your wrists and hit the broad side of a barn!\
- Uses sniper ammo.\
+ desc = "Essentially amounting to a sniper rifle with no stock and barrel (or indeed, any rifling at all), \
+ this extremely dubious pistol is guaranteed to dislocate your wrists and hit the broad side of a barn! \
+ Uses sniper ammo. \
Bullets tend to veer off-course. We are not responsible for any unintentional damage or injury resulting from inaacuracy."
item = /obj/item/gun/ballistic/automatic/pistol/antitank/syndicate
- refundable = TRUE
cost = 14
surplus = 25
include_modes = list(/datum/game_mode/nuclear)
+
+/* Commented out due to introduction of reskinnable stetchkins. May still have a niche if people decide it somehow has value.
+/datum/uplink_item/dangerous/stealthpistol
+ name = "Stealth Pistol"
+ desc = "A compact, easily concealable bullpup pistol that fires 10mm auto rounds in 8 round magazines. \
+ Has an integrated suppressor."
+ item = /obj/item/gun/ballistic/automatic/pistol/stealth
+ cost = 10
+ surplus = 30
+*/
+
+///Soporific 10mm mags///
+
+/datum/uplink_item/ammo/pistolzzz
+ name = "10mm Soporific Magazine"
+ desc = "An additional 8-round 10mm magazine; compatible with the Stechkin Pistol. Loaded with soporific rounds that put the target to sleep. \
+ NOTE: Soporific is not instant acting due to the constraints of the round's scale. Will usually require two shots to take effect."
+ item = /obj/item/ammo_box/magazine/m10mm/soporific
+ cost = 2
+
+///flechette memes///
+
+/datum/uplink_item/dangerous/flechettegun
+ name = "Flechette Launcher"
+ desc = "A compact bullpup that fires micro-flechettes.\
+ Flechettes have very poor performance idividually, but can be very deadly in numbers. \
+ Pre-loaded with armor piercing flechettes that are capable of puncturing most kinds of armor."
+ item = /obj/item/gun/ballistic/automatic/flechette
+ cost = 12
+ surplus = 30
+ include_modes = list(/datum/game_mode/nuclear)
+
+/datum/uplink_item/ammo/flechetteap
+ name = "Armor Piercing Flechette Magazine"
+ desc = "An additional 40-round flechette magazine; compatible with the Flechette Launcer. \
+ Loaded with armor piercing flechettes that very nearly ignore armor, but are not very effective agaisnt flesh."
+ item = /obj/item/ammo_box/magazine/flechette
+ cost = 2
+ include_modes = list(/datum/game_mode/nuclear)
+
+/datum/uplink_item/ammo/flechettes
+ name = "Serrated Flechette Magazine"
+ desc = "An additional 40-round flechette magazine; compatible with the Flechette Launcer. \
+ Loaded with serrated flechettes that shreds flesh, but is stopped dead in its tracks by armor. \
+ These flechettes are highly likely to sever arteries, and even limbs."
+ item = /obj/item/ammo_box/magazine/flechette/s
+ cost = 2
+ include_modes = list(/datum/game_mode/nuclear)
+
+///shredder///
+
+/datum/uplink_item/nukeoffer/shredder
+ name = "Shredder bundle"
+ desc = "A truly horrific weapon designed simply to maim its victim, the CX Shredder is banned by several intergalactic treaties. \
+ You'll get two of them with this. And spare ammo to boot. And we'll throw in an extra elite hardsuit and chest rig to hold them all!"
+ item = /obj/item/storage/backpack/duffelbag/syndie/shredderbundle
+ cost = 30 // normally 41
+
+///Modular Pistols///
+
+/datum/uplink_item/bundle/modular
+ name="Modular Pistol Kit"
+ desc="A heavy briefcase containing one modular pistol (chambered in 10mm), one supressor, and spare ammunition, including a box of soporific ammo. \
+ Includes a suit jacket that is padded with a robust liner."
+ item = /obj/item/storage/briefcase/modularbundle
+ cost = 12
+
+//////Bundle stuff//////
+
+///bundle category///
+
+/datum/uplink_item/bundle
+ category = "Bundles"
+ surplus = 0
+ cant_discount = TRUE
+
+///place bundle storage items here I guess///
+
+/obj/item/storage/briefcase/modularbundle
+ name = "briefcase"
+ desc = "It's label reads genuine hardened Captain leather, but suspiciously has no other tags or branding."
+ icon_state = "briefcase"
+ flags_1 = CONDUCT_1
+ force = 10
+ hitsound = "swing_hit"
+ throw_speed = 2
+ throw_range = 4
+ w_class = WEIGHT_CLASS_BULKY
+ max_w_class = WEIGHT_CLASS_NORMAL
+ max_combined_w_class = 21
+ attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked")
+ resistance_flags = FLAMMABLE
+ max_integrity = 150
+
+/obj/item/storage/briefcase/modularbundle/PopulateContents()
+ new /obj/item/gun/ballistic/automatic/pistol/modular(src)
+ new /obj/item/suppressor(src)
+ new /obj/item/ammo_box/magazine/m10mm(src)
+ new /obj/item/ammo_box/magazine/m10mm/soporific(src)
+ new /obj/item/ammo_box/c10mm/soporific(src)
+ new /obj/item/clothing/under/lawyer/blacksuit(src)
+ new /obj/item/clothing/accessory/waistcoat(src)
+ new /obj/item/clothing/suit/toggle/lawyer/black/syndie(src)
+
+/obj/item/clothing/suit/toggle/lawyer/black/syndie
+ desc = "A snappy dress jacket. Suspiciously has no tags or branding."
+ armor = list(melee = 10, bullet = 10, laser = 10, energy = 10, bomb = 10)
+
+/obj/item/storage/backpack/duffelbag/syndie/shredderbundle
+ desc = "A large duffel bag containing two CX Shredders, some magazines, an elite hardsuit, and a chest rig."
+
+/obj/item/storage/backpack/duffelbag/syndie/shredderbundle/PopulateContents()
+ new /obj/item/ammo_box/magazine/flechette/shredder(src)
+ new /obj/item/ammo_box/magazine/flechette/shredder(src)
+ new /obj/item/ammo_box/magazine/flechette/shredder(src)
+ new /obj/item/ammo_box/magazine/flechette/shredder(src)
+ new /obj/item/gun/ballistic/automatic/flechette/shredder(src)
+ new /obj/item/gun/ballistic/automatic/flechette/shredder(src)
+ new /obj/item/storage/belt/military(src)
+ new /obj/item/clothing/suit/space/hardsuit/syndi/elite(src)
+
+///End of Bundle stuff///
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-2918.yml b/html/changelogs/AutoChangeLog-pr-2918.yml
new file mode 100644
index 0000000000..3f67bc015e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2918.yml
@@ -0,0 +1,4 @@
+author: "JJRcop"
+delete-after: True
+changes:
+ - rscadd: "Suiciding with a ballistic gun now actually blows your brain out."
diff --git a/html/changelogs/AutoChangeLog-pr-2953.yml b/html/changelogs/AutoChangeLog-pr-2953.yml
new file mode 100644
index 0000000000..db1399b5b0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2953.yml
@@ -0,0 +1,4 @@
+author: "Naksu"
+delete-after: True
+changes:
+ - bugfix: "Syndicate MMIs will now properly transfer their laws to newly-constructed AIs"
diff --git a/html/changelogs/AutoChangeLog-pr-2956.yml b/html/changelogs/AutoChangeLog-pr-2956.yml
new file mode 100644
index 0000000000..4ec2f2aaa0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2956.yml
@@ -0,0 +1,5 @@
+author: "GLA Coding"
+delete-after: True
+changes:
+ - tweak: "Cells must now be installed in mechs when being constructed, this step is always before the application of internal armor."
+ - bugfix: "Combat mechs now get stats upgrades from their scanning modules and capacitors"
diff --git a/html/changelogs/AutoChangeLog-pr-2958.yml b/html/changelogs/AutoChangeLog-pr-2958.yml
new file mode 100644
index 0000000000..c02b758502
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2958.yml
@@ -0,0 +1,15 @@
+author: "Toriate"
+delete-after: True
+changes:
+ - rscadd: "Adds Magrifles, RnD"
+ - rscadd: "Adds Modular Pistols, reskinnable stetchkins available only in a bundle"
+ - rscadd: "Adds Bundle category for regular traitor uplink"
+ - rscadd: "Adds Flechette Launcher, nukeop exclusive, unique variant available in bundle"
+ - rscadd: "Adds 10mm Soporific rounds"
+ - rscadd: "adds Foam X9 assault rifle, adminspawn"
+ - bugfix: "Anti Tank Pistol no longer refundable"
+ - wip: "Adds Hyper-Burst Rifle, adminspawn only weapon, intended for nukeops"
+ - soundadd: "added Magrifle sounds"
+ - soundadd: "added Hyper-Burst Rifle sounds"
+ - imageadd: "added 6 alternative sprites for 10mm pistols, includes suppressed sprites"
+ - spellcheck: "Anti Tank Pistol description fixed"
diff --git a/html/changelogs/AutoChangeLog-pr-2960.yml b/html/changelogs/AutoChangeLog-pr-2960.yml
new file mode 100644
index 0000000000..905ec4764f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2960.yml
@@ -0,0 +1,4 @@
+author: "Robustin"
+delete-after: True
+changes:
+ - tweak: "Revheads no longer spawn with chameleon glasses or a spraycan, instead they will start with a cybernetic security HUD implanted into their eyes."
diff --git a/html/changelogs/AutoChangeLog-pr-2963.yml b/html/changelogs/AutoChangeLog-pr-2963.yml
new file mode 100644
index 0000000000..056e7a17fc
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2963.yml
@@ -0,0 +1,4 @@
+author: "ShizCalev"
+delete-after: True
+changes:
+ - tweak: "The mining vendor will now provide more verbose feedback about your interactions."
diff --git a/html/changelogs/AutoChangeLog-pr-2966.yml b/html/changelogs/AutoChangeLog-pr-2966.yml
new file mode 100644
index 0000000000..3570d4a852
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2966.yml
@@ -0,0 +1,4 @@
+author: "RandomMarine"
+delete-after: True
+changes:
+ - imageadd: "Air tanks (o2+n2) now have a different appearance from oxygen tanks."
diff --git a/html/changelogs/AutoChangeLog-pr-2968.yml b/html/changelogs/AutoChangeLog-pr-2968.yml
new file mode 100644
index 0000000000..8ece28e6e9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2968.yml
@@ -0,0 +1,5 @@
+author: "Augustfox"
+delete-after: True
+changes:
+ - tweak: "Reordered hair in a semi-alphabetized list for easier use in character creation."
+ - tweak: "Alphabetized facial hair for easier use in character creation."
diff --git a/html/changelogs/AutoChangeLog-pr-2979.yml b/html/changelogs/AutoChangeLog-pr-2979.yml
new file mode 100644
index 0000000000..00ac0a8d08
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2979.yml
@@ -0,0 +1,6 @@
+author: "XDTM"
+delete-after: True
+changes:
+ - rscadd: "Nurse spiders can now set a directive that will be seen by their spiderlings, when they get controlled by a player."
+ - rscadd: "Spiders' actions are now action buttons instead of verbs."
+ - rscadd: "Wrapping stuff in a cocoon is now a targeted action!"
diff --git a/html/changelogs/AutoChangeLog-pr-2996.yml b/html/changelogs/AutoChangeLog-pr-2996.yml
new file mode 100644
index 0000000000..2ab98f3845
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2996.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - spellcheck: "You can now find out if an item uses alt-clicking by examining it."
diff --git a/html/changelogs/AutoChangeLog-pr-3024.yml b/html/changelogs/AutoChangeLog-pr-3024.yml
new file mode 100644
index 0000000000..cb263b6ffe
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3024.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - rscadd: "Paperwork now uses Markdown instead of BBCode, see the writing help for changes."
diff --git a/html/changelogs/AutoChangeLog-pr-3028.yml b/html/changelogs/AutoChangeLog-pr-3028.yml
new file mode 100644
index 0000000000..c0892a94d1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3028.yml
@@ -0,0 +1,4 @@
+author: "Raeschen"
+delete-after: True
+changes:
+ - tweak: "Changed MIN_AGE to 18"
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 971eb849f6..fd53873c18 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/effects/wrap_target.dmi b/icons/effects/wrap_target.dmi
new file mode 100644
index 0000000000..2e9a338c9e
Binary files /dev/null and b/icons/effects/wrap_target.dmi differ
diff --git a/icons/mecha/mech_construction.dmi b/icons/mecha/mech_construction.dmi
index 38b3b04c5d..42cc8eeb57 100644
Binary files a/icons/mecha/mech_construction.dmi and b/icons/mecha/mech_construction.dmi differ
diff --git a/icons/mob/actions/actions_animal.dmi b/icons/mob/actions/actions_animal.dmi
new file mode 100644
index 0000000000..1dcf7590cd
Binary files /dev/null and b/icons/mob/actions/actions_animal.dmi differ
diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi
index 06699662c0..064fedb3df 100644
Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ
diff --git a/icons/mob/inhands/equipment/tanks_lefthand.dmi b/icons/mob/inhands/equipment/tanks_lefthand.dmi
index a317e1080c..71a2dee416 100644
Binary files a/icons/mob/inhands/equipment/tanks_lefthand.dmi and b/icons/mob/inhands/equipment/tanks_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/tanks_righthand.dmi b/icons/mob/inhands/equipment/tanks_righthand.dmi
index c795999441..c8626f1f8b 100644
Binary files a/icons/mob/inhands/equipment/tanks_righthand.dmi and b/icons/mob/inhands/equipment/tanks_righthand.dmi differ
diff --git a/icons/obj/guns/cit_guns.dmi b/icons/obj/guns/cit_guns.dmi
index 2db84677d2..c6b2ffe49f 100644
Binary files a/icons/obj/guns/cit_guns.dmi and b/icons/obj/guns/cit_guns.dmi differ
diff --git a/icons/obj/tank.dmi b/icons/obj/tank.dmi
index 8e41c003a4..f5ce551e7f 100644
Binary files a/icons/obj/tank.dmi and b/icons/obj/tank.dmi differ
diff --git a/icons/pda_icons/pda_atmos.png b/icons/pda_icons/pda_atmos.png
index 89a55a0a6c..4485e39799 100644
Binary files a/icons/pda_icons/pda_atmos.png and b/icons/pda_icons/pda_atmos.png differ
diff --git a/icons/pda_icons/pda_back.png b/icons/pda_icons/pda_back.png
index 4708824853..d12effb55e 100644
Binary files a/icons/pda_icons/pda_back.png and b/icons/pda_icons/pda_back.png differ
diff --git a/icons/pda_icons/pda_bell.png b/icons/pda_icons/pda_bell.png
index 1e989c2747..70faf96f64 100644
Binary files a/icons/pda_icons/pda_bell.png and b/icons/pda_icons/pda_bell.png differ
diff --git a/icons/pda_icons/pda_blank.png b/icons/pda_icons/pda_blank.png
index 665861d3c7..14c58ad5d7 100644
Binary files a/icons/pda_icons/pda_blank.png and b/icons/pda_icons/pda_blank.png differ
diff --git a/icons/pda_icons/pda_boom.png b/icons/pda_icons/pda_boom.png
index 70e473c3c4..508798c451 100644
Binary files a/icons/pda_icons/pda_boom.png and b/icons/pda_icons/pda_boom.png differ
diff --git a/icons/pda_icons/pda_bucket.png b/icons/pda_icons/pda_bucket.png
index ee030e3a37..039b23b292 100644
Binary files a/icons/pda_icons/pda_bucket.png and b/icons/pda_icons/pda_bucket.png differ
diff --git a/icons/pda_icons/pda_chatroom.png b/icons/pda_icons/pda_chatroom.png
index a00221c4e0..2f253bdcf4 100644
Binary files a/icons/pda_icons/pda_chatroom.png and b/icons/pda_icons/pda_chatroom.png differ
diff --git a/icons/pda_icons/pda_cleanbot.png b/icons/pda_icons/pda_cleanbot.png
index cecbcf4077..f3b976d6a2 100644
Binary files a/icons/pda_icons/pda_cleanbot.png and b/icons/pda_icons/pda_cleanbot.png differ
diff --git a/icons/pda_icons/pda_color.png b/icons/pda_icons/pda_color.png
new file mode 100644
index 0000000000..8e8bcfe627
Binary files /dev/null and b/icons/pda_icons/pda_color.png differ
diff --git a/icons/pda_icons/pda_crate.png b/icons/pda_icons/pda_crate.png
index e1e076e279..fce2f952af 100644
Binary files a/icons/pda_icons/pda_crate.png and b/icons/pda_icons/pda_crate.png differ
diff --git a/icons/pda_icons/pda_cuffs.png b/icons/pda_icons/pda_cuffs.png
index 71958c8abc..ff7e0cf3fe 100644
Binary files a/icons/pda_icons/pda_cuffs.png and b/icons/pda_icons/pda_cuffs.png differ
diff --git a/icons/pda_icons/pda_dronephone.png b/icons/pda_icons/pda_dronephone.png
index 7cf392eb97..cd7a1e22ec 100644
Binary files a/icons/pda_icons/pda_dronephone.png and b/icons/pda_icons/pda_dronephone.png differ
diff --git a/icons/pda_icons/pda_eject.png b/icons/pda_icons/pda_eject.png
index 4168be03f6..a9323f8f9f 100644
Binary files a/icons/pda_icons/pda_eject.png and b/icons/pda_icons/pda_eject.png differ
diff --git a/icons/pda_icons/pda_exit.png b/icons/pda_icons/pda_exit.png
index cd983a4a9a..b440e2cda8 100644
Binary files a/icons/pda_icons/pda_exit.png and b/icons/pda_icons/pda_exit.png differ
diff --git a/icons/pda_icons/pda_flashlight.png b/icons/pda_icons/pda_flashlight.png
index 3476727930..dafbec2c18 100644
Binary files a/icons/pda_icons/pda_flashlight.png and b/icons/pda_icons/pda_flashlight.png differ
diff --git a/icons/pda_icons/pda_floorbot.png b/icons/pda_icons/pda_floorbot.png
index 999e45aed2..1572a02f03 100644
Binary files a/icons/pda_icons/pda_floorbot.png and b/icons/pda_icons/pda_floorbot.png differ
diff --git a/icons/pda_icons/pda_font.png b/icons/pda_icons/pda_font.png
new file mode 100644
index 0000000000..8ae56bfc49
Binary files /dev/null and b/icons/pda_icons/pda_font.png differ
diff --git a/icons/pda_icons/pda_honk.png b/icons/pda_icons/pda_honk.png
index 55632bf40b..49c2b5c0da 100644
Binary files a/icons/pda_icons/pda_honk.png and b/icons/pda_icons/pda_honk.png differ
diff --git a/icons/pda_icons/pda_locked.PNG b/icons/pda_icons/pda_locked.PNG
index 79fe582916..ca1e641732 100644
Binary files a/icons/pda_icons/pda_locked.PNG and b/icons/pda_icons/pda_locked.PNG differ
diff --git a/icons/pda_icons/pda_mail.png b/icons/pda_icons/pda_mail.png
index 6bfb1e8cd7..d41d8dd1ae 100644
Binary files a/icons/pda_icons/pda_mail.png and b/icons/pda_icons/pda_mail.png differ
diff --git a/icons/pda_icons/pda_medbot.png b/icons/pda_icons/pda_medbot.png
index 24ae212be2..338c2c7ece 100644
Binary files a/icons/pda_icons/pda_medbot.png and b/icons/pda_icons/pda_medbot.png differ
diff --git a/icons/pda_icons/pda_medical.png b/icons/pda_icons/pda_medical.png
index 448063ecf5..bdee5abfa3 100644
Binary files a/icons/pda_icons/pda_medical.png and b/icons/pda_icons/pda_medical.png differ
diff --git a/icons/pda_icons/pda_menu.png b/icons/pda_icons/pda_menu.png
index abd6ccb225..afb8d7c5ca 100644
Binary files a/icons/pda_icons/pda_menu.png and b/icons/pda_icons/pda_menu.png differ
diff --git a/icons/pda_icons/pda_mule.png b/icons/pda_icons/pda_mule.png
index b8c1b636f5..71396128b3 100644
Binary files a/icons/pda_icons/pda_mule.png and b/icons/pda_icons/pda_mule.png differ
diff --git a/icons/pda_icons/pda_notes.png b/icons/pda_icons/pda_notes.png
index eb076d3ca3..2fe05ee351 100644
Binary files a/icons/pda_icons/pda_notes.png and b/icons/pda_icons/pda_notes.png differ
diff --git a/icons/pda_icons/pda_power.png b/icons/pda_icons/pda_power.png
index 04175e7c83..86909ea730 100644
Binary files a/icons/pda_icons/pda_power.png and b/icons/pda_icons/pda_power.png differ
diff --git a/icons/pda_icons/pda_rdoor.png b/icons/pda_icons/pda_rdoor.png
index 6eab5a8817..95c0dfd075 100644
Binary files a/icons/pda_icons/pda_rdoor.png and b/icons/pda_icons/pda_rdoor.png differ
diff --git a/icons/pda_icons/pda_reagent.png b/icons/pda_icons/pda_reagent.png
index b900af5ae6..65daeb0063 100644
Binary files a/icons/pda_icons/pda_reagent.png and b/icons/pda_icons/pda_reagent.png differ
diff --git a/icons/pda_icons/pda_refresh.png b/icons/pda_icons/pda_refresh.png
index 08439c6bca..c5e2d24f17 100644
Binary files a/icons/pda_icons/pda_refresh.png and b/icons/pda_icons/pda_refresh.png differ
diff --git a/icons/pda_icons/pda_scanner.png b/icons/pda_icons/pda_scanner.png
index eabdc511cd..be21fc5d40 100644
Binary files a/icons/pda_icons/pda_scanner.png and b/icons/pda_icons/pda_scanner.png differ
diff --git a/icons/pda_icons/pda_signaler.png b/icons/pda_icons/pda_signaler.png
index f71398f70d..43a69798bc 100644
Binary files a/icons/pda_icons/pda_signaler.png and b/icons/pda_icons/pda_signaler.png differ
diff --git a/icons/pda_icons/pda_status.png b/icons/pda_icons/pda_status.png
index fe955e66a6..dec0ec88df 100644
Binary files a/icons/pda_icons/pda_status.png and b/icons/pda_icons/pda_status.png differ
diff --git a/sound/weapons/magburst.ogg b/sound/weapons/magburst.ogg
new file mode 100644
index 0000000000..33068de0ea
Binary files /dev/null and b/sound/weapons/magburst.ogg differ
diff --git a/sound/weapons/magrifle.ogg b/sound/weapons/magrifle.ogg
new file mode 100644
index 0000000000..2ec2e72af6
Binary files /dev/null and b/sound/weapons/magrifle.ogg differ
diff --git a/strings/tips.txt b/strings/tips.txt
index 51e1210e03..e76b88c625 100644
--- a/strings/tips.txt
+++ b/strings/tips.txt
@@ -76,7 +76,6 @@ As a Security Officer, communicate and coordinate with your fellow officers usin
As a Security Officer, your sechuds or HUDsunglasses can not only see crewmates' job assignments and criminal status, but also if they are mindshield implanted. Use this to your advantage in a revolution to definitively tell who is on your side!
As a Security Officer, mindshield implants can only prevent someone from being turned into a cultist: unlike revolutionaries, it will not de-cult them if they have already been converted.
As a Security Officer, examining someone while wearing sechuds or HUDsunglasses will let you set their arrest level, which will cause Beepsky and other security bots to chase after them.
-As a Security Officer, implanting a gang member the first time will deconvert them, but destroy the implant. You must implant them a second time to protect them from further conversion attempts. Keep in mind that gang members have ways to destroy implants in people!
As the Detective, people leave fingerprints everywhere and on everything. With the exception of white latex, gloves will hide them. All is not lost, however, as gloves leave fibers specific to their kind such as black or nitrile, pointing to a general department.
As the Detective, you can use your forensics scanner from a distance.
As the Lawyer, try to negotiate with the Warden if sentences seem too high for the crime.
@@ -181,10 +180,6 @@ As a Wizard, the fireball spell performs very poorly at close range, as it can e
As a Wizard, summoning guns will turn a large portion of the crew against themselves, but will also give everyone anything from a pea shooter to a BFG 9000. Use at your own risk!
As a Wizard, the staff of chaos can fire any type of bolts from the magical wands. This can range from bolts of instant death to healing or reviving someone.
As a Wizard, most spells become unusable if you are not wearing your robe, hat, and sandals.
-As a Gangster, you can destroy mindshield implants with an implant breaker, letting you reconvert that person.
-As a Gangster, your influence is based on how many areas you have tagged and how many people are wearing your gang's outfit; more areas and more people wearing the outfit will give you more influence.
-As a Gangster, your gang outfits are very robust, giving moderate resistances to most direct damage at the cost of stealth.
-As a Gang Boss, don't wait too long to promote lieutenants! If you get caught by security or enemy gangsters, hopefully you have a backup.
As an Abductor, you can select where your victims will be sent on the ship control console.
As an Abductor Agent, the combat mode vest has much higher resistance to every kind of weapon, and your helmet prevents the AI from tracking you.
As an Abductor, the baton can cycle between four modes: stun, sleep, cuff and probe.
diff --git a/tgstation.dme b/tgstation.dme
index f6a230d74c..c72669901f 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -29,6 +29,7 @@
#include "code\__DEFINES\atom_hud.dm"
#include "code\__DEFINES\callbacks.dm"
#include "code\__DEFINES\citadel_defines.dm"
+#include "code\__DEFINES\cinematics.dm"
#include "code\__DEFINES\clockcult.dm"
#include "code\__DEFINES\combat.dm"
#include "code\__DEFINES\components.dm"
@@ -250,6 +251,7 @@
#include "code\datums\beam.dm"
#include "code\datums\browser.dm"
#include "code\datums\callback.dm"
+#include "code\datums\cinematic.dm"
#include "code\datums\datacore.dm"
#include "code\datums\datum.dm"
#include "code\datums\datumvars.dm"
@@ -275,6 +277,7 @@
#include "code\datums\spawners_menu.dm"
#include "code\datums\verbs.dm"
#include "code\datums\antagonists\antag_datum.dm"
+#include "code\datums\antagonists\datum_abductor.dm"
#include "code\datums\antagonists\datum_brother.dm"
#include "code\datums\antagonists\datum_clockcult.dm"
#include "code\datums\antagonists\datum_cult.dm"
@@ -1360,6 +1363,7 @@
#include "code\modules\events\wizard\summons.dm"
#include "code\modules\fields\fields.dm"
#include "code\modules\fields\peaceborg_dampener.dm"
+#include "code\modules\fields\timestop.dm"
#include "code\modules\fields\turf_objects.dm"
#include "code\modules\flufftext\Dreaming.dm"
#include "code\modules\flufftext\Hallucination.dm"
@@ -1904,6 +1908,7 @@
#include "code\modules\ninja\energy_katana.dm"
#include "code\modules\ninja\ninja_event.dm"
#include "code\modules\ninja\Ninja_Readme.dm"
+#include "code\modules\ninja\outfit.dm"
#include "code\modules\ninja\suit\gloves.dm"
#include "code\modules\ninja\suit\head.dm"
#include "code\modules\ninja\suit\mask.dm"
diff --git a/tools/WebhookProcessor/github_webhook_processor.php b/tools/WebhookProcessor/github_webhook_processor.php
index 4e20a7e902..a8b32c7a92 100644
--- a/tools/WebhookProcessor/github_webhook_processor.php
+++ b/tools/WebhookProcessor/github_webhook_processor.php
@@ -456,6 +456,7 @@ function get_pr_code_friendliness($payload, $oldbalance = null){
'Fix' => 2,
'Refactor' => 2,
'Code Improvement' => 1,
+ 'Grammar and Formatting' => 1,
'Priority: High' => 4,
'Priority: CRITICAL' => 5,
'Atmospherics' => 4,