diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm
index a79850b04f..c6ca2cf0ec 100644
--- a/code/__DEFINES/atmospherics.dm
+++ b/code/__DEFINES/atmospherics.dm
@@ -174,3 +174,5 @@
#define LAVALAND_EQUIPMENT_EFFECT_PRESSURE 50 //what pressure you have to be under to increase the effect of equipment meant for lavaland
#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=23;TEMP=300"
+
+#define THERMAL_ENERGY(gas) (gas.temperature * gas.heat_capacity())
\ No newline at end of file
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 46d6c2ce5c..75985f9c2e 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -1,544 +1,547 @@
-/*
- * Holds procs designed to change one type of value, into another.
- * Contains:
- * hex2num & num2hex
- * file2list
- * angle2dir
- * angle2text
- * worldtime2text
- * text2dir_extended & dir2text_short
- */
-
-//Returns an integer given a hex input, supports negative values "-ff"
-//skips preceding invalid characters
-//breaks when hittin invalid characters thereafter
-/proc/hex2num(hex)
- . = 0
- if(istext(hex))
- var/negative = 0
- var/len = length(hex)
- for(var/i=1, i<=len, i++)
- var/num = text2ascii(hex,i)
- switch(num)
- if(48 to 57)
- num -= 48 //0-9
- if(97 to 102)
- num -= 87 //a-f
- if(65 to 70)
- num -= 55 //A-F
- if(45)
- negative = 1//-
- else
- if(num)
- break
- else
- continue
- . *= 16
- . += num
- if(negative)
- . *= -1
- return .
-
-//Returns the hex value of a decimal number
-//len == length of returned string
-//if len < 0 then the returned string will be as long as it needs to be to contain the data
-//Only supports positive numbers
-//if an invalid number is provided, it assumes num==0
-//Note, unlike previous versions, this one works from low to high <-- that way
-/proc/num2hex(num, len=2)
- if(!isnum(num))
- num = 0
- num = round(abs(num))
- . = ""
- var/i=0
- while(1)
- if(len<=0)
- if(!num)
- break
- else
- if(i>=len)
- break
- var/remainder = num/16
- num = round(remainder)
- remainder = (remainder - num) * 16
- switch(remainder)
- if(9,8,7,6,5,4,3,2,1)
- . = "[remainder]" + .
- if(10,11,12,13,14,15)
- . = ascii2text(remainder+87) + .
- else
- . = "0" + .
- i++
- return .
-
-//Splits the text of a file at seperator and returns them in a list.
+/*
+ * Holds procs designed to change one type of value, into another.
+ * Contains:
+ * hex2num & num2hex
+ * file2list
+ * angle2dir
+ * angle2text
+ * worldtime2text
+ * text2dir_extended & dir2text_short
+ */
+
+//Returns an integer given a hex input, supports negative values "-ff"
+//skips preceding invalid characters
+//breaks when hittin invalid characters thereafter
+/proc/hex2num(hex)
+ . = 0
+ if(istext(hex))
+ var/negative = 0
+ var/len = length(hex)
+ for(var/i=1, i<=len, i++)
+ var/num = text2ascii(hex,i)
+ switch(num)
+ if(48 to 57)
+ num -= 48 //0-9
+ if(97 to 102)
+ num -= 87 //a-f
+ if(65 to 70)
+ num -= 55 //A-F
+ if(45)
+ negative = 1//-
+ else
+ if(num)
+ break
+ else
+ continue
+ . *= 16
+ . += num
+ if(negative)
+ . *= -1
+ return .
+
+//Returns the hex value of a decimal number
+//len == length of returned string
+//if len < 0 then the returned string will be as long as it needs to be to contain the data
+//Only supports positive numbers
+//if an invalid number is provided, it assumes num==0
+//Note, unlike previous versions, this one works from low to high <-- that way
+/proc/num2hex(num, len=2)
+ if(!isnum(num))
+ num = 0
+ num = round(abs(num))
+ . = ""
+ var/i=0
+ while(1)
+ if(len<=0)
+ if(!num)
+ break
+ else
+ if(i>=len)
+ break
+ var/remainder = num/16
+ num = round(remainder)
+ remainder = (remainder - num) * 16
+ switch(remainder)
+ if(9,8,7,6,5,4,3,2,1)
+ . = "[remainder]" + .
+ if(10,11,12,13,14,15)
+ . = ascii2text(remainder+87) + .
+ else
+ . = "0" + .
+ i++
+ return .
+
+//Splits the text of a file at seperator and returns them in a list.
/world/proc/file2list(filename, seperator="\n", trim = TRUE)
if (trim)
return splittext(trim(file2text(filename)),seperator)
- return splittext(file2text(filename),seperator)
-
-//Turns a direction into text
-/proc/dir2text(direction)
- switch(direction)
- if(1)
- return "north"
- if(2)
- return "south"
- if(4)
- return "east"
- if(8)
- return "west"
- if(5)
- return "northeast"
- if(6)
- return "southeast"
- if(9)
- return "northwest"
- if(10)
- return "southwest"
- else
- return
-
-//Turns text into proper directions
-/proc/text2dir(direction)
- switch(uppertext(direction))
- if("NORTH")
- return 1
- if("SOUTH")
- return 2
- if("EAST")
- return 4
- if("WEST")
- return 8
- if("NORTHEAST")
- return 5
- if("NORTHWEST")
- return 9
- if("SOUTHEAST")
- return 6
- if("SOUTHWEST")
- return 10
- else
- return
-
-//Converts an angle (degrees) into an ss13 direction
-/proc/angle2dir(degree)
-
- degree = SimplifyDegrees(degree)
-
- if(degree < 45)
- return NORTH
- if(degree < 90)
- return NORTHEAST
- if(degree < 135)
- return EAST
- if(degree < 180)
- return SOUTHEAST
- if(degree < 225)
- return SOUTH
- if(degree < 270)
- return SOUTHWEST
- if(degree < 315)
- return WEST
- return NORTH|WEST
-
-//returns the north-zero clockwise angle in degrees, given a direction
-
-/proc/dir2angle(D)
- switch(D)
- if(NORTH)
- return 0
- if(SOUTH)
- return 180
- if(EAST)
- return 90
- if(WEST)
- return 270
- if(NORTHEAST)
- return 45
- if(SOUTHEAST)
- return 135
- if(NORTHWEST)
- return 315
- if(SOUTHWEST)
- return 225
- else
- return null
-
-//Returns the angle in english
-/proc/angle2text(degree)
- return dir2text(angle2dir(degree))
-
-//Converts a blend_mode constant to one acceptable to icon.Blend()
-/proc/blendMode2iconMode(blend_mode)
- switch(blend_mode)
- if(BLEND_MULTIPLY)
- return ICON_MULTIPLY
- if(BLEND_ADD)
- return ICON_ADD
- if(BLEND_SUBTRACT)
- return ICON_SUBTRACT
- else
- return ICON_OVERLAY
-
-//Converts a rights bitfield into a string
-/proc/rights2text(rights, seperator="", list/adds, list/subs)
- if(rights & R_BUILDMODE)
- . += "[seperator]+BUILDMODE"
- if(rights & R_ADMIN)
- . += "[seperator]+ADMIN"
- if(rights & R_BAN)
- . += "[seperator]+BAN"
- if(rights & R_FUN)
- . += "[seperator]+FUN"
- if(rights & R_SERVER)
- . += "[seperator]+SERVER"
- if(rights & R_DEBUG)
- . += "[seperator]+DEBUG"
- if(rights & R_POSSESS)
- . += "[seperator]+POSSESS"
- if(rights & R_PERMISSIONS)
- . += "[seperator]+PERMISSIONS"
- if(rights & R_STEALTH)
- . += "[seperator]+STEALTH"
- if(rights & R_POLL)
- . += "[seperator]+POLL"
- if(rights & R_VAREDIT)
- . += "[seperator]+VAREDIT"
- if(rights & R_SOUNDS)
- . += "[seperator]+SOUND"
- if(rights & R_SPAWN)
- . += "[seperator]+SPAWN"
-
- for(var/verbpath in adds)
- . += "[seperator]+[verbpath]"
- for(var/verbpath in subs)
- . += "[seperator]-[verbpath]"
- return .
-
-/proc/ui_style2icon(ui_style)
- switch(ui_style)
- if("Retro")
- return 'icons/mob/screen_retro.dmi'
- if("Plasmafire")
- return 'icons/mob/screen_plasmafire.dmi'
- if("Slimecore")
- return 'icons/mob/screen_slimecore.dmi'
- if("Operative")
- return 'icons/mob/screen_operative.dmi'
- if("Clockwork")
- return 'icons/mob/screen_clockwork.dmi'
- else
- return 'icons/mob/screen_midnight.dmi'
-
-//colour formats
-/proc/rgb2hsl(red, green, blue)
- red /= 255;green /= 255;blue /= 255;
- var/max = max(red,green,blue)
- var/min = min(red,green,blue)
- var/range = max-min
-
- var/hue=0;var/saturation=0;var/lightness=0;
- lightness = (max + min)/2
- if(range != 0)
- if(lightness < 0.5)
- saturation = range/(max+min)
- else
- saturation = range/(2-max-min)
-
- var/dred = ((max-red)/(6*max)) + 0.5
- var/dgreen = ((max-green)/(6*max)) + 0.5
- var/dblue = ((max-blue)/(6*max)) + 0.5
-
- if(max==red)
- hue = dblue - dgreen
- else if(max==green)
- hue = dred - dblue + (1/3)
- else
- hue = dgreen - dred + (2/3)
- if(hue < 0)
- hue++
- else if(hue > 1)
- hue--
-
- return list(hue, saturation, lightness)
-
-/proc/hsl2rgb(hue, saturation, lightness)
- var/red;var/green;var/blue;
- if(saturation == 0)
- red = lightness * 255
- green = red
- blue = red
- else
- var/a;var/b;
- if(lightness < 0.5)
- b = lightness*(1+saturation)
- else
- b = (lightness+saturation) - (saturation*lightness)
- a = 2*lightness - b
-
- red = round(255 * hue2rgb(a, b, hue+(1/3)))
- green = round(255 * hue2rgb(a, b, hue))
- blue = round(255 * hue2rgb(a, b, hue-(1/3)))
-
- return list(red, green, blue)
-
-/proc/hue2rgb(a, b, hue)
- if(hue < 0)
- hue++
- else if(hue > 1)
- hue--
- if(6*hue < 1)
- return (a+(b-a)*6*hue)
- if(2*hue < 1)
- return b
- if(3*hue < 2)
- return (a+(b-a)*((2/3)-hue)*6)
- return a
-
-// Very ugly, BYOND doesn't support unix time and rounding errors make it really hard to convert it to BYOND time.
-// returns "YYYY-MM-DD" by default
-/proc/unix2date(timestamp, seperator = "-")
-
- if(timestamp < 0)
- return 0 //Do not accept negative values
-
- var/year = 1970 //Unix Epoc begins 1970-01-01
- var/dayInSeconds = 86400 //60secs*60mins*24hours
- var/daysInYear = 365 //Non Leap Year
- var/daysInLYear = daysInYear + 1//Leap year
- var/days = round(timestamp / dayInSeconds) //Days passed since UNIX Epoc
- var/tmpDays = days + 1 //If passed (timestamp < dayInSeconds), it will return 0, so add 1
- var/monthsInDays = list() //Months will be in here ***Taken from the PHP source code***
- var/month = 1 //This will be the returned MONTH NUMBER.
- var/day //This will be the returned day number.
-
- while(tmpDays > daysInYear) //Start adding years to 1970
- year++
- if(isLeap(year))
- tmpDays -= daysInLYear
- else
- tmpDays -= daysInYear
-
- if(isLeap(year)) //The year is a leap year
- monthsInDays = list(-1,30,59,90,120,151,181,212,243,273,304,334)
- else
- monthsInDays = list(0,31,59,90,120,151,181,212,243,273,304,334)
-
- var/mDays = 0;
- var/monthIndex = 0;
-
- for(var/m in monthsInDays)
- monthIndex++
- if(tmpDays > m)
- mDays = m
- month = monthIndex
-
- day = tmpDays - mDays //Setup the date
-
- return "[year][seperator][((month < 10) ? "0[month]" : month)][seperator][((day < 10) ? "0[day]" : day)]"
-
-/proc/isLeap(y)
- return ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
-
-
-
-//Turns a Body_parts_covered bitfield into a list of organ/limb names.
-//(I challenge you to find a use for this)
-/proc/body_parts_covered2organ_names(bpc)
- var/list/covered_parts = list()
-
- if(!bpc)
- return 0
-
- if(bpc & FULL_BODY)
- covered_parts |= list("l_arm","r_arm","head","chest","l_leg","r_leg")
-
- else
- if(bpc & HEAD)
- covered_parts |= list("head")
- if(bpc & CHEST)
- covered_parts |= list("chest")
- if(bpc & GROIN)
- covered_parts |= list("chest")
-
- if(bpc & ARMS)
- covered_parts |= list("l_arm","r_arm")
- else
- if(bpc & ARM_LEFT)
- covered_parts |= list("l_arm")
- if(bpc & ARM_RIGHT)
- covered_parts |= list("r_arm")
-
- if(bpc & HANDS)
- covered_parts |= list("l_arm","r_arm")
- else
- if(bpc & HAND_LEFT)
- covered_parts |= list("l_arm")
- if(bpc & HAND_RIGHT)
- covered_parts |= list("r_arm")
-
- if(bpc & LEGS)
- covered_parts |= list("l_leg","r_leg")
- else
- if(bpc & LEG_LEFT)
- covered_parts |= list("l_leg")
- if(bpc & LEG_RIGHT)
- covered_parts |= list("r_leg")
-
- if(bpc & FEET)
- covered_parts |= list("l_leg","r_leg")
- else
- if(bpc & FOOT_LEFT)
- covered_parts |= list("l_leg")
- if(bpc & FOOT_RIGHT)
- covered_parts |= list("r_leg")
-
- return covered_parts
-
-
-
-//adapted from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
-/proc/heat2colour(temp)
- return rgb(heat2colour_r(temp), heat2colour_g(temp), heat2colour_b(temp))
-
-
-/proc/heat2colour_r(temp)
- temp /= 100
- if(temp <= 66)
- . = 255
- else
- . = max(0, min(255, 329.698727446 * (temp - 60) ** -0.1332047592))
-
-
-/proc/heat2colour_g(temp)
- temp /= 100
- if(temp <= 66)
- . = max(0, min(255, 99.4708025861 * log(temp) - 161.1195681661))
- else
- . = max(0, min(255, 288.1221685293 * ((temp - 60) ** -0.075148492)))
-
-
-/proc/heat2colour_b(temp)
- temp /= 100
- if(temp >= 66)
- . = 255
- else
- if(temp <= 16)
- . = 0
- else
- . = max(0, min(255, 138.5177312231 * log(temp - 10) - 305.0447927307))
-
-/proc/color2hex(color) //web colors
- if(!color)
- return "#000000"
-
- switch(color)
- if("white")
- return "#FFFFFF"
- if("black")
- return "#000000"
- if("gray")
- return "#808080"
- if("brown")
- return "#A52A2A"
- if("red")
- return "#FF0000"
- if("darkred")
- return "#8B0000"
- if("crimson")
- return "#DC143C"
- if("orange")
- return "#FFA500"
- if("yellow")
- return "#FFFF00"
- if("green")
- return "#008000"
- if("lime")
- return "#00FF00"
- if("darkgreen")
- return "#006400"
- if("cyan")
- return "#00FFFF"
- if("blue")
- return "#0000FF"
- if("navy")
- return "#000080"
- if("teal")
- return "#008080"
- if("purple")
- return "#800080"
- if("indigo")
- return "#4B0082"
- else
- return "#FFFFFF"
-
-
-//This is a weird one:
-//It returns a list of all var names found in the string
-//These vars must be in the [var_name] format
-//It's only a proc because it's used in more than one place
-
-//Takes a string and a datum
-//The string is well, obviously the string being checked
-//The datum is used as a source for var names, to check validity
-//Otherwise every single word could technically be a variable!
-/proc/string2listofvars(var/t_string, var/datum/var_source)
- if(!t_string || !var_source)
- return list()
-
- . = list()
-
- var/var_found = findtext(t_string,"\[") //Not the actual variables, just a generic "should we even bother" check
- if(var_found)
- //Find var names
-
- // "A dog said hi [name]!"
- // splittext() --> list("A dog said hi ","name]!"
- // jointext() --> "A dog said hi name]!"
- // splittext() --> list("A","dog","said","hi","name]!")
-
- t_string = replacetext(t_string,"\[","\[ ")//Necessary to resolve "word[var_name]" scenarios
- var/list/list_value = splittext(t_string,"\[")
- var/intermediate_stage = jointext(list_value, null)
-
- list_value = splittext(intermediate_stage," ")
- for(var/value in list_value)
- if(findtext(value,"]"))
- value = splittext(value,"]") //"name]!" --> list("name","!")
- for(var/A in value)
- if(var_source.vars.Find(A))
- . += A
-
-//assumes format #RRGGBB #rrggbb
-/proc/color_hex2num(A)
- if(!A)
- return 0
- var/R = hex2num(copytext(A,2,4))
- var/G = hex2num(copytext(A,4,6))
- var/B = hex2num(copytext(A,6,0))
- return R+G+B
-
-//word of warning: using a matrix like this as a color value will simplify it back to a string after being set
-/proc/color_hex2color_matrix(string)
- var/length = length(string)
- if(length != 7 && length != 9)
- return color_matrix_identity()
- var/r = hex2num(copytext(string, 2, 4))/255
- var/g = hex2num(copytext(string, 4, 6))/255
- var/b = hex2num(copytext(string, 6, 8))/255
- var/a = 1
- if(length == 9)
- a = hex2num(copytext(string, 8, 10))/255
- if(!isnum(r) || !isnum(g) || !isnum(b) || !isnum(a))
- return color_matrix_identity()
- return list(r,0,0,0, 0,g,0,0, 0,0,b,0, 0,0,0,a, 0,0,0,0)
-
-//will drop all values not on the diagonal
-/proc/color_matrix2color_hex(list/the_matrix)
- if(!istype(the_matrix) || the_matrix.len != 20)
- return "#ffffffff"
- return rgb(the_matrix[1]*255, the_matrix[6]*255, the_matrix[11]*255, the_matrix[16]*255)
+ return splittext(file2text(filename),seperator)
+
+//Turns a direction into text
+/proc/dir2text(direction)
+ switch(direction)
+ if(1)
+ return "north"
+ if(2)
+ return "south"
+ if(4)
+ return "east"
+ if(8)
+ return "west"
+ if(5)
+ return "northeast"
+ if(6)
+ return "southeast"
+ if(9)
+ return "northwest"
+ if(10)
+ return "southwest"
+ else
+ return
+
+//Turns text into proper directions
+/proc/text2dir(direction)
+ switch(uppertext(direction))
+ if("NORTH")
+ return 1
+ if("SOUTH")
+ return 2
+ if("EAST")
+ return 4
+ if("WEST")
+ return 8
+ if("NORTHEAST")
+ return 5
+ if("NORTHWEST")
+ return 9
+ if("SOUTHEAST")
+ return 6
+ if("SOUTHWEST")
+ return 10
+ else
+ return
+
+//Converts an angle (degrees) into an ss13 direction
+/proc/angle2dir(degree)
+
+ degree = SimplifyDegrees(degree)
+ switch(degree)
+ if(0 to 22.5) //north requires two angle ranges
+ return NORTH
+ if(22.5 to 67.5) //each range covers 45 degrees
+ return NORTHEAST
+ if(67.5 to 112.5)
+ return EAST
+ if(112.5 to 157.5)
+ return SOUTHEAST
+ if(157.5 to 202.5)
+ return SOUTH
+ if(202.5 to 247.5)
+ return SOUTHWEST
+ if(247.5 to 292.5)
+ return WEST
+ if(292.5 to 337.5)
+ return NORTHWEST
+ if(337.5 to 360)
+ return NORTH
+
+//returns the north-zero clockwise angle in degrees, given a direction
+
+/proc/dir2angle(D)
+ switch(D)
+ if(NORTH)
+ return 0
+ if(SOUTH)
+ return 180
+ if(EAST)
+ return 90
+ if(WEST)
+ return 270
+ if(NORTHEAST)
+ return 45
+ if(SOUTHEAST)
+ return 135
+ if(NORTHWEST)
+ return 315
+ if(SOUTHWEST)
+ return 225
+ else
+ return null
+
+//Returns the angle in english
+/proc/angle2text(degree)
+ return dir2text(angle2dir(degree))
+
+//Converts a blend_mode constant to one acceptable to icon.Blend()
+/proc/blendMode2iconMode(blend_mode)
+ switch(blend_mode)
+ if(BLEND_MULTIPLY)
+ return ICON_MULTIPLY
+ if(BLEND_ADD)
+ return ICON_ADD
+ if(BLEND_SUBTRACT)
+ return ICON_SUBTRACT
+ else
+ return ICON_OVERLAY
+
+//Converts a rights bitfield into a string
+/proc/rights2text(rights, seperator="", list/adds, list/subs)
+ if(rights & R_BUILDMODE)
+ . += "[seperator]+BUILDMODE"
+ if(rights & R_ADMIN)
+ . += "[seperator]+ADMIN"
+ if(rights & R_BAN)
+ . += "[seperator]+BAN"
+ if(rights & R_FUN)
+ . += "[seperator]+FUN"
+ if(rights & R_SERVER)
+ . += "[seperator]+SERVER"
+ if(rights & R_DEBUG)
+ . += "[seperator]+DEBUG"
+ if(rights & R_POSSESS)
+ . += "[seperator]+POSSESS"
+ if(rights & R_PERMISSIONS)
+ . += "[seperator]+PERMISSIONS"
+ if(rights & R_STEALTH)
+ . += "[seperator]+STEALTH"
+ if(rights & R_POLL)
+ . += "[seperator]+POLL"
+ if(rights & R_VAREDIT)
+ . += "[seperator]+VAREDIT"
+ if(rights & R_SOUNDS)
+ . += "[seperator]+SOUND"
+ if(rights & R_SPAWN)
+ . += "[seperator]+SPAWN"
+
+ for(var/verbpath in adds)
+ . += "[seperator]+[verbpath]"
+ for(var/verbpath in subs)
+ . += "[seperator]-[verbpath]"
+ return .
+
+/proc/ui_style2icon(ui_style)
+ switch(ui_style)
+ if("Retro")
+ return 'icons/mob/screen_retro.dmi'
+ if("Plasmafire")
+ return 'icons/mob/screen_plasmafire.dmi'
+ if("Slimecore")
+ return 'icons/mob/screen_slimecore.dmi'
+ if("Operative")
+ return 'icons/mob/screen_operative.dmi'
+ if("Clockwork")
+ return 'icons/mob/screen_clockwork.dmi'
+ else
+ return 'icons/mob/screen_midnight.dmi'
+
+//colour formats
+/proc/rgb2hsl(red, green, blue)
+ red /= 255;green /= 255;blue /= 255;
+ var/max = max(red,green,blue)
+ var/min = min(red,green,blue)
+ var/range = max-min
+
+ var/hue=0;var/saturation=0;var/lightness=0;
+ lightness = (max + min)/2
+ if(range != 0)
+ if(lightness < 0.5)
+ saturation = range/(max+min)
+ else
+ saturation = range/(2-max-min)
+
+ var/dred = ((max-red)/(6*max)) + 0.5
+ var/dgreen = ((max-green)/(6*max)) + 0.5
+ var/dblue = ((max-blue)/(6*max)) + 0.5
+
+ if(max==red)
+ hue = dblue - dgreen
+ else if(max==green)
+ hue = dred - dblue + (1/3)
+ else
+ hue = dgreen - dred + (2/3)
+ if(hue < 0)
+ hue++
+ else if(hue > 1)
+ hue--
+
+ return list(hue, saturation, lightness)
+
+/proc/hsl2rgb(hue, saturation, lightness)
+ var/red;var/green;var/blue;
+ if(saturation == 0)
+ red = lightness * 255
+ green = red
+ blue = red
+ else
+ var/a;var/b;
+ if(lightness < 0.5)
+ b = lightness*(1+saturation)
+ else
+ b = (lightness+saturation) - (saturation*lightness)
+ a = 2*lightness - b
+
+ red = round(255 * hue2rgb(a, b, hue+(1/3)))
+ green = round(255 * hue2rgb(a, b, hue))
+ blue = round(255 * hue2rgb(a, b, hue-(1/3)))
+
+ return list(red, green, blue)
+
+/proc/hue2rgb(a, b, hue)
+ if(hue < 0)
+ hue++
+ else if(hue > 1)
+ hue--
+ if(6*hue < 1)
+ return (a+(b-a)*6*hue)
+ if(2*hue < 1)
+ return b
+ if(3*hue < 2)
+ return (a+(b-a)*((2/3)-hue)*6)
+ return a
+
+// Very ugly, BYOND doesn't support unix time and rounding errors make it really hard to convert it to BYOND time.
+// returns "YYYY-MM-DD" by default
+/proc/unix2date(timestamp, seperator = "-")
+
+ if(timestamp < 0)
+ return 0 //Do not accept negative values
+
+ var/year = 1970 //Unix Epoc begins 1970-01-01
+ var/dayInSeconds = 86400 //60secs*60mins*24hours
+ var/daysInYear = 365 //Non Leap Year
+ var/daysInLYear = daysInYear + 1//Leap year
+ var/days = round(timestamp / dayInSeconds) //Days passed since UNIX Epoc
+ var/tmpDays = days + 1 //If passed (timestamp < dayInSeconds), it will return 0, so add 1
+ var/monthsInDays = list() //Months will be in here ***Taken from the PHP source code***
+ var/month = 1 //This will be the returned MONTH NUMBER.
+ var/day //This will be the returned day number.
+
+ while(tmpDays > daysInYear) //Start adding years to 1970
+ year++
+ if(isLeap(year))
+ tmpDays -= daysInLYear
+ else
+ tmpDays -= daysInYear
+
+ if(isLeap(year)) //The year is a leap year
+ monthsInDays = list(-1,30,59,90,120,151,181,212,243,273,304,334)
+ else
+ monthsInDays = list(0,31,59,90,120,151,181,212,243,273,304,334)
+
+ var/mDays = 0;
+ var/monthIndex = 0;
+
+ for(var/m in monthsInDays)
+ monthIndex++
+ if(tmpDays > m)
+ mDays = m
+ month = monthIndex
+
+ day = tmpDays - mDays //Setup the date
+
+ return "[year][seperator][((month < 10) ? "0[month]" : month)][seperator][((day < 10) ? "0[day]" : day)]"
+
+/proc/isLeap(y)
+ return ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
+
+
+
+//Turns a Body_parts_covered bitfield into a list of organ/limb names.
+//(I challenge you to find a use for this)
+/proc/body_parts_covered2organ_names(bpc)
+ var/list/covered_parts = list()
+
+ if(!bpc)
+ return 0
+
+ if(bpc & FULL_BODY)
+ covered_parts |= list("l_arm","r_arm","head","chest","l_leg","r_leg")
+
+ else
+ if(bpc & HEAD)
+ covered_parts |= list("head")
+ if(bpc & CHEST)
+ covered_parts |= list("chest")
+ if(bpc & GROIN)
+ covered_parts |= list("chest")
+
+ if(bpc & ARMS)
+ covered_parts |= list("l_arm","r_arm")
+ else
+ if(bpc & ARM_LEFT)
+ covered_parts |= list("l_arm")
+ if(bpc & ARM_RIGHT)
+ covered_parts |= list("r_arm")
+
+ if(bpc & HANDS)
+ covered_parts |= list("l_arm","r_arm")
+ else
+ if(bpc & HAND_LEFT)
+ covered_parts |= list("l_arm")
+ if(bpc & HAND_RIGHT)
+ covered_parts |= list("r_arm")
+
+ if(bpc & LEGS)
+ covered_parts |= list("l_leg","r_leg")
+ else
+ if(bpc & LEG_LEFT)
+ covered_parts |= list("l_leg")
+ if(bpc & LEG_RIGHT)
+ covered_parts |= list("r_leg")
+
+ if(bpc & FEET)
+ covered_parts |= list("l_leg","r_leg")
+ else
+ if(bpc & FOOT_LEFT)
+ covered_parts |= list("l_leg")
+ if(bpc & FOOT_RIGHT)
+ covered_parts |= list("r_leg")
+
+ return covered_parts
+
+
+
+//adapted from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
+/proc/heat2colour(temp)
+ return rgb(heat2colour_r(temp), heat2colour_g(temp), heat2colour_b(temp))
+
+
+/proc/heat2colour_r(temp)
+ temp /= 100
+ if(temp <= 66)
+ . = 255
+ else
+ . = max(0, min(255, 329.698727446 * (temp - 60) ** -0.1332047592))
+
+
+/proc/heat2colour_g(temp)
+ temp /= 100
+ if(temp <= 66)
+ . = max(0, min(255, 99.4708025861 * log(temp) - 161.1195681661))
+ else
+ . = max(0, min(255, 288.1221685293 * ((temp - 60) ** -0.075148492)))
+
+
+/proc/heat2colour_b(temp)
+ temp /= 100
+ if(temp >= 66)
+ . = 255
+ else
+ if(temp <= 16)
+ . = 0
+ else
+ . = max(0, min(255, 138.5177312231 * log(temp - 10) - 305.0447927307))
+
+/proc/color2hex(color) //web colors
+ if(!color)
+ return "#000000"
+
+ switch(color)
+ if("white")
+ return "#FFFFFF"
+ if("black")
+ return "#000000"
+ if("gray")
+ return "#808080"
+ if("brown")
+ return "#A52A2A"
+ if("red")
+ return "#FF0000"
+ if("darkred")
+ return "#8B0000"
+ if("crimson")
+ return "#DC143C"
+ if("orange")
+ return "#FFA500"
+ if("yellow")
+ return "#FFFF00"
+ if("green")
+ return "#008000"
+ if("lime")
+ return "#00FF00"
+ if("darkgreen")
+ return "#006400"
+ if("cyan")
+ return "#00FFFF"
+ if("blue")
+ return "#0000FF"
+ if("navy")
+ return "#000080"
+ if("teal")
+ return "#008080"
+ if("purple")
+ return "#800080"
+ if("indigo")
+ return "#4B0082"
+ else
+ return "#FFFFFF"
+
+
+//This is a weird one:
+//It returns a list of all var names found in the string
+//These vars must be in the [var_name] format
+//It's only a proc because it's used in more than one place
+
+//Takes a string and a datum
+//The string is well, obviously the string being checked
+//The datum is used as a source for var names, to check validity
+//Otherwise every single word could technically be a variable!
+/proc/string2listofvars(var/t_string, var/datum/var_source)
+ if(!t_string || !var_source)
+ return list()
+
+ . = list()
+
+ var/var_found = findtext(t_string,"\[") //Not the actual variables, just a generic "should we even bother" check
+ if(var_found)
+ //Find var names
+
+ // "A dog said hi [name]!"
+ // splittext() --> list("A dog said hi ","name]!"
+ // jointext() --> "A dog said hi name]!"
+ // splittext() --> list("A","dog","said","hi","name]!")
+
+ t_string = replacetext(t_string,"\[","\[ ")//Necessary to resolve "word[var_name]" scenarios
+ var/list/list_value = splittext(t_string,"\[")
+ var/intermediate_stage = jointext(list_value, null)
+
+ list_value = splittext(intermediate_stage," ")
+ for(var/value in list_value)
+ if(findtext(value,"]"))
+ value = splittext(value,"]") //"name]!" --> list("name","!")
+ for(var/A in value)
+ if(var_source.vars.Find(A))
+ . += A
+
+//assumes format #RRGGBB #rrggbb
+/proc/color_hex2num(A)
+ if(!A)
+ return 0
+ var/R = hex2num(copytext(A,2,4))
+ var/G = hex2num(copytext(A,4,6))
+ var/B = hex2num(copytext(A,6,0))
+ return R+G+B
+
+//word of warning: using a matrix like this as a color value will simplify it back to a string after being set
+/proc/color_hex2color_matrix(string)
+ var/length = length(string)
+ if(length != 7 && length != 9)
+ return color_matrix_identity()
+ var/r = hex2num(copytext(string, 2, 4))/255
+ var/g = hex2num(copytext(string, 4, 6))/255
+ var/b = hex2num(copytext(string, 6, 8))/255
+ var/a = 1
+ if(length == 9)
+ a = hex2num(copytext(string, 8, 10))/255
+ if(!isnum(r) || !isnum(g) || !isnum(b) || !isnum(a))
+ return color_matrix_identity()
+ return list(r,0,0,0, 0,g,0,0, 0,0,b,0, 0,0,0,a, 0,0,0,0)
+
+//will drop all values not on the diagonal
+/proc/color_matrix2color_hex(list/the_matrix)
+ if(!istype(the_matrix) || the_matrix.len != 20)
+ return "#ffffffff"
+ return rgb(the_matrix[1]*255, the_matrix[6]*255, the_matrix[11]*255, the_matrix[16]*255)
/proc/type2parent(child)
var/string_type = "[child]"
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 987818924f..4c0eeccf1d 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -20,7 +20,7 @@
return SendSignal(COMSIG_PARENT_ATTACKBY, W, user, params)
/obj/attackby(obj/item/I, mob/living/user, params)
- return ..() || I.attack_obj(src, user)
+ return ..() || (can_be_hit && I.attack_obj(src, user))
/mob/living/attackby(obj/item/I, mob/living/user, params)
user.changeNext_move(CLICK_CD_MELEE)
diff --git a/code/datums/components/paintable.dm b/code/datums/components/paintable.dm
new file mode 100644
index 0000000000..2ea94334d0
--- /dev/null
+++ b/code/datums/components/paintable.dm
@@ -0,0 +1,29 @@
+/datum/component/spraycan_paintable
+ var/current_paint
+
+/datum/component/spraycan_paintable/Initialize()
+ RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/Repaint)
+
+/datum/component/spraycan_paintable/Destroy()
+ RemoveCurrentCoat()
+ return ..()
+
+/datum/component/spraycan_paintable/proc/RemoveCurrentCoat()
+ var/atom/A = parent
+ A.remove_atom_colour(FIXED_COLOUR_PRIORITY, current_paint)
+
+/datum/component/spraycan_paintable/proc/Repaint(obj/item/toy/crayon/spraycan/spraycan, mob/living/user)
+ if(!istype(spraycan) || user.a_intent == INTENT_HARM)
+ return FALSE
+ . = TRUE
+ if(spraycan.is_capped)
+ to_chat(user, "Take the cap off first!")
+ return
+ RemoveCurrentCoat()
+ if(spraycan.use_charges(user, 2))
+ var/colour = spraycan.paint_color
+ current_paint = colour
+ var/atom/A = parent
+ A.add_atom_colour(colour, FIXED_COLOUR_PRIORITY)
+ playsound(spraycan, 'sound/effects/spray.ogg', 5, 1, 5)
+ to_chat(user, "You spray [spraycan] on [A], painting it.")
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index 455ec0f62a..88e6148c5f 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -42,7 +42,7 @@
I.trigger(key, L)
if(!msg)
- return FALSE
+ return
user.log_message(msg, INDIVIDUAL_EMOTE_LOG)
msg = "[user] " + msg
@@ -91,21 +91,22 @@
/datum/emote/proc/select_param(mob/user, params)
return replacetext(message_param, "%t", params)
-/datum/emote/proc/can_run_emote(mob/user, help_check)
+/datum/emote/proc/can_run_emote(mob/user, status_check = TRUE)
. = TRUE
if(!is_type_in_typecache(user, mob_type_allowed_typecache))
return FALSE
if(is_type_in_typecache(user, mob_type_blacklist_typecache))
return FALSE
- if(!help_check)
+ if(status_check)
if(user.stat > stat_allowed || (user.status_flags & FAKEDEATH))
+ to_chat(user, "You cannot [key] while unconscious.")
return FALSE
- if(restraint_check && user.restrained())
+ if(restraint_check && (user.restrained() || user.buckled))
+ to_chat(user, "You cannot [key] while restrained.")
return FALSE
if(user.reagents && user.reagents.has_reagent("mimesbane"))
return FALSE
-
/datum/emote/sound
var/sound //Sound to play when emote is called
var/vary = FALSE //used for the honk borg emote
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index b062b8f054..222ce73f92 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -449,10 +449,11 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(!L.client.played)
SEND_SOUND(L, sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE))
- L.client.played = 1
- sleep(600) //ewww - this is very very bad
- if(L.&& L.client)
- L.client.played = 0
+ L.client.played = TRUE
+ addtimer(CALLBACK(L.client, /client/proc/ResetAmbiencePlayed), 600)
+
+/client/proc/ResetAmbiencePlayed()
+ played = FALSE
/atom/proc/has_gravity(turf/T)
if(!T || !isturf(T))
diff --git a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
index cdff486eea..364c967ae9 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
@@ -11,7 +11,7 @@
break_message = "The warden's eye gives a glare of utter hate before falling dark!"
debris = list(/obj/item/clockwork/component/belligerent_eye/blind_eye = 1)
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
- var/damage_per_tick = 2.5
+ var/damage_per_tick = 3
var/sight_range = 3
var/atom/movable/target
var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.")
@@ -141,8 +141,12 @@
. = 1
if(target)
for(var/turf/T in getline(src, target))
+ if(T.density)
+ . -= 0.1
+ continue
for(var/obj/structure/O in T)
- if(O.density)
- . -= 0.15
+ if(O != src && O.density)
+ . -= 0.1
+ break
. -= (get_dist(src, target) * 0.05)
. = max(., 0.1) //The lowest damage a warden can do is 10% of its normal amount (0.25 by default)
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index b3a7f99758..d4a06d0580 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -1009,8 +1009,9 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
/obj/item/clothing/mask/joy = 1,
/obj/item/clothing/head/cueball = 1,
/obj/item/clothing/under/scratch = 1,
- /obj/item/clothing/under/sailor = 1,
- /obj/item/clothing/ears/headphones = 2)
+ /obj/item/clothing/under/sailor = 1,
+ /obj/item/clothing/ears/headphones = 2,
+ /obj/item/clothing/head/wig/random = 3)
contraband = list(/obj/item/clothing/suit/judgerobe = 1, /obj/item/clothing/head/powdered_wig = 1, /obj/item/gun/magic/wand = 2, /obj/item/clothing/glasses/sunglasses/garb = 2, /obj/item/clothing/glasses/sunglasses/blindfold = 1, /obj/item/clothing/mask/muzzle = 2)
premium = list(/obj/item/clothing/suit/pirate/captain = 2, /obj/item/clothing/head/pirate/captain = 2, /obj/item/clothing/head/helmet/roman = 1, /obj/item/clothing/head/helmet/roman/legionaire = 1, /obj/item/clothing/under/roman = 1, /obj/item/clothing/shoes/roman = 1, /obj/item/shield/riot/roman = 1, /obj/item/skub = 1)
refill_canister = /obj/item/vending_refill/autodrobe
diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm
index 4406c32fbd..d5f8e28d2a 100644
--- a/code/game/objects/effects/effects.dm
+++ b/code/game/objects/effects/effects.dm
@@ -4,9 +4,7 @@
/obj/effect
icon = 'icons/effects/effects.dmi'
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
-
-/obj/effect/attackby(obj/item/I, mob/living/user, params)
- return
+ can_be_hit = FALSE
/obj/effect/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
return
@@ -57,4 +55,4 @@
return
/obj/effect/abstract/singularity_act()
- return
\ No newline at end of file
+ return
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 072896ac01..362148c801 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -26,6 +26,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
max_integrity = 200
+ can_be_hit = FALSE
+
var/hitsound = null
var/usesound = null
var/throwhitsound = null
@@ -322,6 +324,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// Due to storage type consolidation this should get used more now.
// I have cleaned it up a little, but it could probably use more. -Sayu
// The lack of ..() is intentional, do not add one
+// added one, fuck the police
/obj/item/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/storage))
var/obj/item/storage/S = W
@@ -346,9 +349,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
qdel(progress)
to_chat(user, "You put everything you could [S.preposition] [S].")
+ return
else if(S.can_be_inserted(src))
S.handle_item_insertion(src)
+ return
+ return ..()
/obj/item/proc/handle_mass_pickup(obj/item/storage/S, list/things, atom/thing_loc, list/rejections, datum/progressbar/progress)
for(var/obj/item/I in things)
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 23905200e9..882335d5e7 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -107,20 +107,19 @@
var/amount = weight * units_per_weight
reagents.add_reagent(reagent, amount)
-/obj/item/toy/crayon/proc/use_charges(amount)
+/obj/item/toy/crayon/proc/use_charges(mob/user, amount = 1, requires_full = TRUE)
// Returns number of charges actually used
- switch(paint_mode)
- if(PAINT_LARGE_HORIZONTAL)
- amount *= 3
-
if(charges == -1)
. = amount
refill()
else
- . = min(charges_left, amount)
- charges_left -= .
+ if(check_empty(user, amount, requires_full))
+ return 0
+ else
+ . = min(charges_left, amount)
+ charges_left -= .
-/obj/item/toy/crayon/proc/check_empty(mob/user)
+/obj/item/toy/crayon/proc/check_empty(mob/user, amount = 1, requires_full = TRUE)
// When eating a crayon, check_empty() can be called twice producing
// two messages unless we check for being deleted first
if(QDELETED(src))
@@ -131,10 +130,13 @@
if(charges == -1)
. = FALSE
else if(!charges_left)
- to_chat(user, "There is no more of \the [src.name] left!")
+ to_chat(user, "There is no more of [src] left!")
if(self_contained)
qdel(src)
. = TRUE
+ else if(charges_left < amount && requires_full)
+ to_chat(user, "There is not enough of [src] left!")
+ . = TRUE
/obj/item/toy/crayon/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
// tgui is a plague upon this codebase
@@ -298,7 +300,7 @@
var/takes_time = !instant
var/wait_time = 50
- if(PAINT_LARGE_HORIZONTAL)
+ if(paint_mode == PAINT_LARGE_HORIZONTAL)
wait_time *= 3
if(takes_time)
@@ -343,7 +345,7 @@
var/cost = 1
if(paint_mode == PAINT_LARGE_HORIZONTAL)
cost = 5
- . = use_charges(cost)
+ . = use_charges(user, cost)
var/fraction = min(1, . / reagents.maximum_volume)
if(affected_turfs.len)
fraction /= affected_turfs.len
@@ -355,7 +357,7 @@
/obj/item/toy/crayon/attack(mob/M, mob/user)
if(edible && (M == user))
to_chat(user, "You take a bite of the [src.name]. Delicious!")
- var/eaten = use_charges(5)
+ var/eaten = use_charges(user, 5, FALSE)
if(check_empty(user)) //Prevents divsion by zero
return
var/fraction = min(eaten / reagents.total_volume, 1)
@@ -527,7 +529,7 @@
H.lip_style = "spray_face"
H.lip_color = paint_color
H.update_body()
- var/used = use_charges(10)
+ var/used = use_charges(user, 10, FALSE)
var/fraction = min(1, used / reagents.maximum_volume)
reagents.reaction(user, VAPOR, fraction * volume_multiplier)
reagents.trans_to(user, used, volume_multiplier)
@@ -583,7 +585,7 @@
H.update_body()
// Caution, spray cans contain inflammable substances
- . = use_charges(10)
+ . = use_charges(user, 10, FALSE)
var/fraction = min(1, . / reagents.maximum_volume)
reagents.reaction(C, VAPOR, fraction * volume_multiplier)
@@ -596,7 +598,7 @@
target.set_opacity(255)
else
target.set_opacity(initial(target.opacity))
- . = use_charges(2)
+ . = use_charges(user, 2)
var/fraction = min(1, . / reagents.maximum_volume)
reagents.reaction(target, TOUCH, fraction * volume_multiplier)
reagents.trans_to(target, ., volume_multiplier)
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 6e7ffddeb3..7cef6094ea 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -151,7 +151,11 @@
if(!building_checks(R, multiplier))
return
- var/obj/O = new R.result_type()
+ var/obj/O
+ if(R.max_res_amount > 1) //Is it a stack?
+ O = new R.result_type(usr.drop_location(), R.res_amount * multiplier)
+ else
+ O = new R.result_type(usr.drop_location())
O.setDir(usr.dir)
use(R.req_amount * multiplier)
@@ -164,16 +168,11 @@
W.ini_dir = W.dir
//END: oh fuck i'm so sorry
- //is it a stack ?
- if (R.max_res_amount > 1)
- var/obj/item/stack/new_item = O
- new_item.amount = R.res_amount*multiplier
- new_item.update_icon()
+ if (QDELETED(O))
+ return //It's a stack and has already been merged
if (isitem(O))
usr.put_in_hands(O)
- else
- O.forceMove(usr.drop_location())
O.add_fingerprint(usr)
//BubbleWrap - so newly formed boxes are empty
diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm
deleted file mode 100644
index f8a020b677..0000000000
--- a/code/game/objects/items/weapons/storage/belt.dm
+++ /dev/null
@@ -1,531 +0,0 @@
-/obj/item/weapon/storage/belt
- name = "belt"
- desc = "Can hold various things."
- icon = 'icons/obj/clothing/belts.dmi'
- icon_state = "utilitybelt"
- item_state = "utility"
- slot_flags = SLOT_BELT
- attack_verb = list("whipped", "lashed", "disciplined")
- max_integrity = 300
- var/content_overlays = FALSE //If this is true, the belt will gain overlays based on what it's holding
-
-/obj/item/weapon/storage/belt/update_icon()
- cut_overlays()
- if(content_overlays)
- for(var/obj/item/I in contents)
- var/mutable_appearance/M = I.get_belt_overlay()
- add_overlay(M)
- ..()
-
-/obj/item/weapon/storage/belt/Initialize()
- . = ..()
- update_icon()
-
-/obj/item/weapon/storage/belt/utility
- name = "toolbelt" //Carn: utility belt is nicer, but it bamboozles the text parsing.
- desc = "Holds tools."
- icon_state = "utilitybelt"
- item_state = "utility"
- can_hold = list(
- /obj/item/weapon/crowbar,
- /obj/item/weapon/screwdriver,
- /obj/item/weapon/weldingtool,
- /obj/item/weapon/wirecutters,
- /obj/item/weapon/wrench,
- /obj/item/device/multitool,
- /obj/item/device/flashlight,
- /obj/item/stack/cable_coil,
- /obj/item/device/t_scanner,
- /obj/item/device/analyzer,
- /obj/item/weapon/extinguisher/mini,
- /obj/item/device/radio,
- /obj/item/clothing/gloves
- )
- content_overlays = TRUE
-
-/obj/item/weapon/storage/belt/utility/chief
- name = "\improper Chief Engineer's toolbelt" //"the Chief Engineer's toolbelt", because "Chief Engineer's toolbelt" is not a proper noun
- desc = "Holds tools, looks snazzy."
- icon_state = "utilitybelt_ce"
- item_state = "utility_ce"
-
-/obj/item/weapon/storage/belt/utility/chief/full/PopulateContents()
- new /obj/item/weapon/screwdriver/power(src)
- new /obj/item/weapon/crowbar/power(src)
- new /obj/item/weapon/weldingtool/experimental(src)//This can be changed if this is too much
- new /obj/item/device/multitool(src)
- new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange"))
- new /obj/item/weapon/extinguisher/mini(src)
- new /obj/item/device/analyzer(src)
- //much roomier now that we've managed to remove two tools
-
-
-/obj/item/weapon/storage/belt/utility/full/PopulateContents()
- new /obj/item/weapon/screwdriver(src)
- new /obj/item/weapon/wrench(src)
- new /obj/item/weapon/weldingtool(src)
- new /obj/item/weapon/crowbar(src)
- new /obj/item/weapon/wirecutters(src)
- new /obj/item/device/multitool(src)
- new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange"))
-
-/obj/item/weapon/storage/belt/utility/full/engi/PopulateContents()
- new /obj/item/weapon/screwdriver(src)
- new /obj/item/weapon/wrench(src)
- new /obj/item/weapon/weldingtool/largetank(src)
- new /obj/item/weapon/crowbar(src)
- new /obj/item/weapon/wirecutters(src)
- new /obj/item/device/multitool(src)
- new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange"))
-
-
-/obj/item/weapon/storage/belt/utility/atmostech/PopulateContents()
- new /obj/item/weapon/screwdriver(src)
- new /obj/item/weapon/wrench(src)
- new /obj/item/weapon/weldingtool(src)
- new /obj/item/weapon/crowbar(src)
- new /obj/item/weapon/wirecutters(src)
- new /obj/item/device/t_scanner(src)
- new /obj/item/weapon/extinguisher/mini(src)
-
-
-/obj/item/weapon/storage/belt/utility/servant/PopulateContents()
- new /obj/item/weapon/screwdriver/brass(src)
- new /obj/item/weapon/wirecutters/brass(src)
- new /obj/item/weapon/wrench/brass(src)
- new /obj/item/weapon/crowbar/brass(src)
- new /obj/item/weapon/weldingtool/experimental/brass(src)
- new /obj/item/device/multitool(src)
- new /obj/item/stack/cable_coil(src, 30, "yellow")
-
-
-/obj/item/weapon/storage/belt/medical
- name = "medical belt"
- desc = "Can hold various medical equipment."
- icon_state = "medicalbelt"
- item_state = "medical"
- max_w_class = WEIGHT_CLASS_BULKY
- can_hold = list(
- /obj/item/device/healthanalyzer,
- /obj/item/weapon/dnainjector,
- /obj/item/weapon/reagent_containers/dropper,
- /obj/item/weapon/reagent_containers/glass/beaker,
- /obj/item/weapon/reagent_containers/glass/bottle,
- /obj/item/weapon/reagent_containers/pill,
- /obj/item/weapon/reagent_containers/syringe,
- /obj/item/weapon/lighter,
- /obj/item/weapon/storage/fancy/cigarettes,
- /obj/item/weapon/storage/pill_bottle,
- /obj/item/stack/medical,
- /obj/item/device/flashlight/pen,
- /obj/item/weapon/extinguisher/mini,
- /obj/item/weapon/reagent_containers/hypospray,
- /obj/item/device/sensor_device,
- /obj/item/device/radio,
- /obj/item/clothing/gloves/,
- /obj/item/weapon/lazarus_injector,
- /obj/item/weapon/bikehorn/rubberducky,
- /obj/item/clothing/mask/surgical,
- /obj/item/clothing/mask/breath,
- /obj/item/clothing/mask/breath/medical,
- /obj/item/weapon/surgical_drapes, //for true paramedics
- /obj/item/weapon/scalpel,
- /obj/item/weapon/circular_saw,
- /obj/item/weapon/surgicaldrill,
- /obj/item/weapon/retractor,
- /obj/item/weapon/cautery,
- /obj/item/weapon/hemostat,
- /obj/item/device/geiger_counter,
- /obj/item/clothing/neck/stethoscope,
- /obj/item/weapon/stamp,
- /obj/item/clothing/glasses,
- /obj/item/weapon/wrench/medical,
- /obj/item/clothing/mask/muzzle,
- /obj/item/weapon/storage/bag/chemistry,
- /obj/item/weapon/storage/bag/bio,
- /obj/item/weapon/reagent_containers/blood,
- /obj/item/weapon/tank/internals/emergency_oxygen
- )
-
-
-/obj/item/weapon/storage/belt/security
- name = "security belt"
- desc = "Can hold security gear like handcuffs and flashes."
- icon_state = "securitybelt"
- item_state = "security"//Could likely use a better one.
- storage_slots = 5
- max_w_class = WEIGHT_CLASS_NORMAL //Because the baton wouldn't fit otherwise. - Neerti
- can_hold = list(
- /obj/item/weapon/melee/baton,
- /obj/item/weapon/melee/classic_baton,
- /obj/item/weapon/grenade,
- /obj/item/weapon/reagent_containers/spray/pepper,
- /obj/item/weapon/restraints/handcuffs,
- /obj/item/device/assembly/flash/handheld,
- /obj/item/clothing/glasses,
- /obj/item/ammo_casing/shotgun,
- /obj/item/ammo_box,
- /obj/item/weapon/reagent_containers/food/snacks/donut,
- /obj/item/weapon/reagent_containers/food/snacks/donut/jelly,
- /obj/item/weapon/kitchen/knife/combat,
- /obj/item/device/flashlight/seclite,
- /obj/item/weapon/melee/classic_baton/telescopic,
- /obj/item/device/radio,
- /obj/item/clothing/gloves/,
- /obj/item/weapon/restraints/legcuffs/bola
- )
- content_overlays = TRUE
-
-/obj/item/weapon/storage/belt/security/full/PopulateContents()
- new /obj/item/weapon/reagent_containers/spray/pepper(src)
- new /obj/item/weapon/restraints/handcuffs(src)
- new /obj/item/weapon/grenade/flashbang(src)
- new /obj/item/device/assembly/flash/handheld(src)
- new /obj/item/weapon/melee/baton/loaded(src)
- update_icon()
-
-
-/obj/item/weapon/storage/belt/mining
- name = "explorer's webbing"
- desc = "A versatile chest rig, cherished by miners and hunters alike."
- icon_state = "explorer1"
- item_state = "explorer1"
- storage_slots = 6
- w_class = WEIGHT_CLASS_BULKY
- max_w_class = WEIGHT_CLASS_BULKY //Pickaxes are big.
- max_combined_w_class = 20 //Not an issue with this whitelist, probably.
- can_hold = list(
- /obj/item/weapon/crowbar,
- /obj/item/weapon/screwdriver,
- /obj/item/weapon/weldingtool,
- /obj/item/weapon/wirecutters,
- /obj/item/weapon/wrench,
- /obj/item/device/flashlight,
- /obj/item/stack/cable_coil,
- /obj/item/device/analyzer,
- /obj/item/weapon/extinguisher/mini,
- /obj/item/device/radio,
- /obj/item/clothing/gloves,
- /obj/item/weapon/resonator,
- /obj/item/device/mining_scanner,
- /obj/item/weapon/pickaxe,
- /obj/item/stack/sheet/animalhide,
- /obj/item/stack/sheet/sinew,
- /obj/item/stack/sheet/bone,
- /obj/item/weapon/lighter,
- /obj/item/weapon/storage/fancy/cigarettes,
- /obj/item/weapon/reagent_containers/food/drinks/bottle,
- /obj/item/stack/medical,
- /obj/item/weapon/kitchen/knife,
- /obj/item/weapon/reagent_containers/hypospray,
- /obj/item/device/gps,
- /obj/item/weapon/storage/bag/ore,
- /obj/item/weapon/survivalcapsule,
- /obj/item/device/t_scanner/adv_mining_scanner,
- /obj/item/weapon/reagent_containers/pill,
- /obj/item/weapon/storage/pill_bottle,
- /obj/item/weapon/ore,
- /obj/item/weapon/reagent_containers/food/drinks,
- /obj/item/organ/regenerative_core,
- /obj/item/device/wormhole_jaunter,
- /obj/item/weapon/storage/bag/plants,
- /obj/item/stack/marker_beacon
- )
-
-
-/obj/item/weapon/storage/belt/mining/vendor
- contents = newlist(/obj/item/weapon/survivalcapsule)
-
-/obj/item/weapon/storage/belt/mining/alt
- icon_state = "explorer2"
- item_state = "explorer2"
-
-/obj/item/weapon/storage/belt/mining/primitive
- name = "hunter's belt"
- desc = "A versatile belt, woven from sinew."
- storage_slots = 5
- icon_state = "ebelt"
- item_state = "ebelt"
-
-/obj/item/weapon/storage/belt/soulstone
- name = "soul stone belt"
- desc = "Designed for ease of access to the shards during a fight, as to not let a single enemy spirit slip away"
- icon_state = "soulstonebelt"
- item_state = "soulstonebelt"
- storage_slots = 6
- can_hold = list(
- /obj/item/device/soulstone
- )
-
-/obj/item/weapon/storage/belt/soulstone/full/PopulateContents()
- for(var/i in 1 to 6)
- new /obj/item/device/soulstone(src)
-
-/obj/item/weapon/storage/belt/champion
- name = "championship belt"
- desc = "Proves to the world that you are the strongest!"
- icon_state = "championbelt"
- item_state = "champion"
- materials = list(MAT_GOLD=400)
- storage_slots = 1
- can_hold = list(
- /obj/item/clothing/mask/luchador
- )
-
-/obj/item/weapon/storage/belt/military
- name = "chest rig"
- desc = "A set of tactical webbing worn by Syndicate boarding parties."
- icon_state = "militarywebbing"
- item_state = "militarywebbing"
- max_w_class = WEIGHT_CLASS_SMALL
-
-/obj/item/weapon/storage/belt/military/abductor
- name = "agent belt"
- desc = "A belt used by abductor agents."
- icon = 'icons/obj/abductor.dmi'
- icon_state = "belt"
- item_state = "security"
-
-/obj/item/weapon/storage/belt/military/abductor/full/PopulateContents()
- new /obj/item/weapon/screwdriver/abductor(src)
- new /obj/item/weapon/wrench/abductor(src)
- new /obj/item/weapon/weldingtool/abductor(src)
- new /obj/item/weapon/crowbar/abductor(src)
- new /obj/item/weapon/wirecutters/abductor(src)
- new /obj/item/device/multitool/abductor(src)
- new /obj/item/stack/cable_coil(src,30,"white")
-
-
-/obj/item/weapon/storage/belt/military/army
- name = "army belt"
- desc = "A belt used by military forces."
- icon_state = "grenadebeltold"
- item_state = "security"
-
-/obj/item/weapon/storage/belt/military/assault
- name = "assault belt"
- desc = "A tactical assault belt."
- icon_state = "assaultbelt"
- item_state = "security"
- storage_slots = 6
-
-/obj/item/weapon/storage/belt/grenade
- name = "grenadier belt"
- desc = "A belt for holding grenades."
- icon_state = "grenadebeltnew"
- item_state = "security"
- max_w_class = WEIGHT_CLASS_BULKY
- display_contents_with_number = TRUE
- storage_slots = 30
- max_combined_w_class = 60 //needs to be this high
- can_hold = list(
- /obj/item/weapon/grenade,
- /obj/item/weapon/screwdriver,
- /obj/item/weapon/lighter,
- /obj/item/device/multitool,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/molotov,
- /obj/item/weapon/grenade/plastic/c4,
- )
-/obj/item/weapon/storage/belt/grenade/full/PopulateContents()
- new /obj/item/weapon/grenade/flashbang(src)
- new /obj/item/weapon/grenade/smokebomb(src)
- new /obj/item/weapon/grenade/smokebomb(src)
- new /obj/item/weapon/grenade/smokebomb(src)
- new /obj/item/weapon/grenade/smokebomb(src)
- new /obj/item/weapon/grenade/empgrenade(src)
- new /obj/item/weapon/grenade/empgrenade(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/syndieminibomb/concussion/frag(src)
- new /obj/item/weapon/grenade/gluon(src)
- new /obj/item/weapon/grenade/gluon(src)
- new /obj/item/weapon/grenade/gluon(src)
- new /obj/item/weapon/grenade/gluon(src)
- new /obj/item/weapon/grenade/chem_grenade/incendiary(src)
- new /obj/item/weapon/grenade/chem_grenade/incendiary(src)
- new /obj/item/weapon/grenade/chem_grenade/facid(src)
- new /obj/item/weapon/grenade/syndieminibomb(src)
- new /obj/item/weapon/grenade/syndieminibomb(src)
- new /obj/item/weapon/screwdriver(src)
- new /obj/item/device/multitool(src)
-
-/obj/item/weapon/storage/belt/wands
- name = "wand belt"
- desc = "A belt designed to hold various rods of power. A veritable fanny pack of exotic magic."
- icon_state = "soulstonebelt"
- item_state = "soulstonebelt"
- storage_slots = 6
- can_hold = list(
- /obj/item/weapon/gun/magic/wand
- )
-
-/obj/item/weapon/storage/belt/wands/full/PopulateContents()
- new /obj/item/weapon/gun/magic/wand/death(src)
- new /obj/item/weapon/gun/magic/wand/resurrection(src)
- new /obj/item/weapon/gun/magic/wand/polymorph(src)
- new /obj/item/weapon/gun/magic/wand/teleport(src)
- new /obj/item/weapon/gun/magic/wand/door(src)
- new /obj/item/weapon/gun/magic/wand/fireball(src)
-
- for(var/obj/item/weapon/gun/magic/wand/W in contents) //All wands in this pack come in the best possible condition
- W.max_charges = initial(W.max_charges)
- W.charges = W.max_charges
-
-/obj/item/weapon/storage/belt/janitor
- name = "janibelt"
- desc = "A belt used to hold most janitorial supplies."
- icon_state = "janibelt"
- item_state = "janibelt"
- storage_slots = 6
- max_w_class = WEIGHT_CLASS_BULKY // Set to this so the light replacer can fit.
- can_hold = list(
- /obj/item/weapon/grenade/chem_grenade,
- /obj/item/device/lightreplacer,
- /obj/item/device/flashlight,
- /obj/item/weapon/reagent_containers/spray,
- /obj/item/weapon/soap,
- /obj/item/weapon/holosign_creator,
- /obj/item/key/janitor,
- /obj/item/clothing/gloves
- )
-
-/obj/item/weapon/storage/belt/bandolier
- name = "bandolier"
- desc = "A bandolier for holding shotgun ammunition."
- icon_state = "bandolier"
- item_state = "bandolier"
- storage_slots = 18
- display_contents_with_number = TRUE
- can_hold = list(
- /obj/item/ammo_casing/shotgun
- )
-
-/obj/item/weapon/storage/belt/holster
- name = "shoulder holster"
- desc = "A holster to carry a handgun and ammo. WARNING: Badasses only."
- icon_state = "holster"
- item_state = "holster"
- storage_slots = 3
- max_w_class = WEIGHT_CLASS_NORMAL
- can_hold = list(
- /obj/item/weapon/gun/ballistic/automatic/pistol,
- /obj/item/weapon/gun/ballistic/revolver,
- /obj/item/ammo_box,
- )
- alternate_worn_layer = UNDER_SUIT_LAYER
-
-/obj/item/weapon/storage/belt/holster/full/PopulateContents()
- new /obj/item/weapon/gun/ballistic/revolver/detective(src)
- new /obj/item/ammo_box/c38(src)
- new /obj/item/ammo_box/c38(src)
-
-/obj/item/weapon/storage/belt/fannypack
- name = "fannypack"
- desc = "A dorky fannypack for keeping small items in."
- icon_state = "fannypack_leather"
- item_state = "fannypack_leather"
- storage_slots = 3
- max_w_class = WEIGHT_CLASS_SMALL
-
-/obj/item/weapon/storage/belt/fannypack/black
- name = "black fannypack"
- icon_state = "fannypack_black"
- item_state = "fannypack_black"
-
-/obj/item/weapon/storage/belt/fannypack/red
- name = "red fannypack"
- icon_state = "fannypack_red"
- item_state = "fannypack_red"
-
-/obj/item/weapon/storage/belt/fannypack/purple
- name = "purple fannypack"
- icon_state = "fannypack_purple"
- item_state = "fannypack_purple"
-
-/obj/item/weapon/storage/belt/fannypack/blue
- name = "blue fannypack"
- icon_state = "fannypack_blue"
- item_state = "fannypack_blue"
-
-/obj/item/weapon/storage/belt/fannypack/orange
- name = "orange fannypack"
- icon_state = "fannypack_orange"
- item_state = "fannypack_orange"
-
-/obj/item/weapon/storage/belt/fannypack/white
- name = "white fannypack"
- icon_state = "fannypack_white"
- item_state = "fannypack_white"
-
-/obj/item/weapon/storage/belt/fannypack/green
- name = "green fannypack"
- icon_state = "fannypack_green"
- item_state = "fannypack_green"
-
-/obj/item/weapon/storage/belt/fannypack/pink
- name = "pink fannypack"
- icon_state = "fannypack_pink"
- item_state = "fannypack_pink"
-
-/obj/item/weapon/storage/belt/fannypack/cyan
- name = "cyan fannypack"
- icon_state = "fannypack_cyan"
- item_state = "fannypack_cyan"
-
-/obj/item/weapon/storage/belt/fannypack/yellow
- name = "yellow fannypack"
- icon_state = "fannypack_yellow"
- item_state = "fannypack_yellow"
-
-/obj/item/weapon/storage/belt/sabre
- name = "sabre sheath"
- desc = "An ornate sheath designed to hold an officer's blade."
- icon_state = "sheath"
- item_state = "sheath"
- storage_slots = 1
- rustle_jimmies = FALSE
- w_class = WEIGHT_CLASS_BULKY
- max_w_class = WEIGHT_CLASS_BULKY
- can_hold = list(
- /obj/item/weapon/melee/sabre
- )
-
-/obj/item/weapon/storage/belt/sabre/examine(mob/user)
- ..()
- if(contents.len)
- to_chat(user, "Alt-click it to quickly draw the blade.")
-
-/obj/item/weapon/storage/belt/sabre/AltClick(mob/user)
- if(!ishuman(user) || !user.canUseTopic(src, be_close=TRUE))
- return
- if(contents.len)
- var/obj/item/I = contents[1]
- user.visible_message("[user] takes [I] out of [src].", "You take [I] out of [src].",\
- )
- user.put_in_hands(I)
- update_icon()
- else
- to_chat(user, "[src] is empty.")
-
-/obj/item/weapon/storage/belt/sabre/update_icon()
- icon_state = "sheath"
- item_state = "sheath"
- if(contents.len)
- icon_state += "-sabre"
- item_state += "-sabre"
- if(loc && isliving(loc))
- var/mob/living/L = loc
- L.regenerate_icons()
- ..()
-
-
-/obj/item/weapon/storage/belt/sabre/PopulateContents()
- new /obj/item/weapon/melee/sabre(src)
- update_icon()
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index f2537945db..fb5a4344f0 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -13,6 +13,7 @@
var/integrity_failure = 0 //0 if we have no special broken behavior
var/resistance_flags = 0 // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF
+ var/can_be_hit = TRUE //can this be bludgeoned by items?
var/acid_level = 0 //how much acid is on that obj
diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
index ad1ba46d86..ac8349f5f7 100644
--- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
@@ -119,9 +119,6 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
/datum/gas_mixture/proc/return_volume() //liters
return max(0, volume)
-/datum/gas_mixture/proc/thermal_energy() //joules
- return temperature * heat_capacity()
-
/datum/gas_mixture/proc/archive()
//Update archived versions of variables
//Returns: 1 in all cases
@@ -424,7 +421,7 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
var/list/cached_gases = gases
var/temp = temperature
- var/ener = thermal_energy()
+ var/ener = THERMAL_ENERGY(src)
reaction_loop:
for(var/r in SSair.gas_reactions)
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index a37e4d61c4..abbfcf8924 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -199,13 +199,13 @@
var/old_heat_capacity = air.heat_capacity()
var/carbon_efficency = min(cached_gases["plasma"][MOLES]/cached_gases["co2"][MOLES],MAX_CARBON_EFFICENCY)
- var/reaction_energy = air.thermal_energy()
+ var/reaction_energy = THERMAL_ENERGY(air)
var/moles_impurities = air.total_moles()-(cached_gases["plasma"][MOLES]+cached_gases["co2"][MOLES])
var/plasma_fused = (PLASMA_FUSED_COEFFICENT*carbon_efficency)*(temperature/PLASMA_BINDING_ENERGY)
var/carbon_catalyzed = (CARBON_CATALYST_COEFFICENT*carbon_efficency)*(temperature/PLASMA_BINDING_ENERGY)
var/oxygen_added = carbon_catalyzed
- var/nitrogen_added = (plasma_fused-oxygen_added)-(air.thermal_energy()/PLASMA_BINDING_ENERGY)
+ var/nitrogen_added = (plasma_fused-oxygen_added)-(THERMAL_ENERGY(air)/PLASMA_BINDING_ENERGY)
reaction_energy = max(reaction_energy+((carbon_efficency*cached_gases["plasma"][MOLES])/((moles_impurities/carbon_efficency)+2)*10)+((plasma_fused/(moles_impurities/carbon_efficency))*PLASMA_BINDING_ENERGY),0)
diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm
index 11a7881a98..ad7fdb921a 100644
--- a/code/modules/atmospherics/machinery/datum_pipeline.dm
+++ b/code/modules/atmospherics/machinery/datum_pipeline.dm
@@ -232,7 +232,7 @@
total_gas_mixture.merge(G)
- total_thermal_energy += G.thermal_energy()
+ total_thermal_energy += THERMAL_ENERGY(G)
total_heat_capacity += G.heat_capacity()
total_gas_mixture.temperature = total_heat_capacity ? total_thermal_energy/total_heat_capacity : 0
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index d89671d06d..da4fe1cf5c 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -17,13 +17,25 @@
dog_fashion = /datum/dog_fashion/head/helmet
-
-/obj/item/clothing/head/helmet/Initialize()
- . = ..()
-
/obj/item/clothing/head/helmet/sec
can_flashlight = 1
+/obj/item/clothing/head/helmet/sec/attackby(obj/item/I, mob/user, params)
+ if(issignaler(I))
+ var/obj/item/device/assembly/signaler/S = I
+ if(F) //Has a flashlight. Player must remove it, else it will be lost forever.
+ to_chat(user, "The mounted flashlight is in the way, remove it first!")
+ return
+
+ if(S.secured)
+ qdel(S)
+ var/obj/item/secbot_assembly/A = new /obj/item/secbot_assembly
+ user.put_in_hands(A)
+ to_chat(user, "You add the signaler to the helmet.")
+ qdel(src)
+ return
+ return ..()
+
/obj/item/clothing/head/helmet/alt
name = "bulletproof helmet"
desc = "A bulletproof combat helmet that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent."
@@ -281,7 +293,7 @@
qdel(THL)
return
- ..()
+ return ..()
/obj/item/clothing/head/helmet/proc/toggle_helmlight()
set name = "Toggle Helmetlight"
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 314f39f48b..4a86008ad2 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -1,179 +1,221 @@
-/*
- * Contents:
- * Welding mask
- * Cakehat
- * Ushanka
- * Pumpkin head
- * Kitty ears
- * Cardborg disguise
- */
-
-/*
- * Welding mask
- */
-/obj/item/clothing/head/welding
- name = "welding helmet"
- desc = "A head-mounted face cover designed to protect the wearer completely from space-arc eye."
- icon_state = "welding"
- flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
- item_state = "welding"
- materials = list(MAT_METAL=1750, MAT_GLASS=400)
-// var/up = 0
- flash_protect = 2
- tint = 2
- armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 60)
- flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
- actions_types = list(/datum/action/item_action/toggle)
- visor_flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
- visor_flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
- resistance_flags = FIRE_PROOF
-
-/obj/item/clothing/head/welding/attack_self(mob/user)
- weldingvisortoggle(user)
-
-
-/*
- * Cakehat
- */
-/obj/item/clothing/head/hardhat/cakehat
- name = "cakehat"
- desc = "You put the cake on your head. Brilliant."
- icon_state = "hardhat0_cakehat"
- item_state = "hardhat0_cakehat"
- item_color = "cakehat"
- hitsound = 'sound/weapons/tap.ogg'
- flags_inv = HIDEEARS|HIDEHAIR
- armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
- brightness_on = 2 //luminosity when on
- flags_cover = HEADCOVERSEYES
- heat = 100
-
-/obj/item/clothing/head/hardhat/cakehat/process()
- var/turf/location = src.loc
- if(ishuman(location))
- var/mob/living/carbon/human/M = location
- if(M.is_holding(src) || M.head == src)
- location = M.loc
-
- if(isturf(location))
- location.hotspot_expose(700, 1)
-
-/obj/item/clothing/head/hardhat/cakehat/turn_on()
- ..()
- force = 2
- throwforce = 2
- damtype = BURN
- hitsound = 'sound/items/welder.ogg'
- START_PROCESSING(SSobj, src)
-
-/obj/item/clothing/head/hardhat/cakehat/turn_off()
- ..()
- force = 0
- throwforce = 0
- damtype = BRUTE
- hitsound = 'sound/weapons/tap.ogg'
- STOP_PROCESSING(SSobj, src)
-
-/obj/item/clothing/head/hardhat/cakehat/is_hot()
- return on * heat
-/*
- * Ushanka
- */
-/obj/item/clothing/head/ushanka
- name = "ushanka"
- desc = "Perfect for winter in Siberia, da?"
- icon_state = "ushankadown"
- item_state = "ushankadown"
- flags_inv = HIDEEARS|HIDEHAIR
- var/earflaps = 1
- cold_protection = HEAD
- min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
-
- dog_fashion = /datum/dog_fashion/head/ushanka
-
-/obj/item/clothing/head/ushanka/attack_self(mob/user)
- if(earflaps)
- src.icon_state = "ushankaup"
- src.item_state = "ushankaup"
- earflaps = 0
- to_chat(user, "You raise the ear flaps on the ushanka.")
- else
- src.icon_state = "ushankadown"
- src.item_state = "ushankadown"
- earflaps = 1
- to_chat(user, "You lower the ear flaps on the ushanka.")
-
-/*
- * Pumpkin head
- */
-/obj/item/clothing/head/hardhat/pumpkinhead
- name = "carved pumpkin"
- desc = "A jack o' lantern! Believed to ward off evil spirits."
- icon_state = "hardhat0_pumpkin"
- item_state = "hardhat0_pumpkin"
- item_color = "pumpkin"
- flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
- armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
- brightness_on = 2 //luminosity when on
- flags_cover = HEADCOVERSEYES
-
-/*
- * Kitty ears
- */
-/obj/item/clothing/head/kitty
- name = "kitty ears"
- desc = "A pair of kitty ears. Meow!"
- icon_state = "kitty"
- color = "#999999"
- dynamic_hair_suffix = ""
-
- dog_fashion = /datum/dog_fashion/head/kitty
-
-/obj/item/clothing/head/kitty/equipped(mob/living/carbon/human/user, slot)
- if(ishuman(user) && slot == slot_head)
- update_icon(user)
- user.update_inv_head() //Color might have been changed by update_icon.
- ..()
-
-/obj/item/clothing/head/kitty/update_icon(mob/living/carbon/human/user)
- if(ishuman(user))
- add_atom_colour("#[user.hair_color]", FIXED_COLOUR_PRIORITY)
-
-/obj/item/clothing/head/kitty/genuine
- desc = "A pair of kitty ears. A tag on the inside says \"Hand made from real cats.\""
-
-
-/obj/item/clothing/head/hardhat/reindeer
- name = "novelty reindeer hat"
- desc = "Some fake antlers and a very fake red nose."
- icon_state = "hardhat0_reindeer"
- item_state = "hardhat0_reindeer"
- item_color = "reindeer"
- flags_inv = 0
- armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
- brightness_on = 1 //luminosity when on
- dynamic_hair_suffix = ""
-
- dog_fashion = /datum/dog_fashion/head/reindeer
-
-/obj/item/clothing/head/cardborg
- name = "cardborg helmet"
- desc = "A helmet made out of a box."
- icon_state = "cardborg_h"
- item_state = "cardborg_h"
- flags_cover = HEADCOVERSEYES
- flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
-
- dog_fashion = /datum/dog_fashion/head/cardborg
-
-/obj/item/clothing/head/cardborg/equipped(mob/living/user, slot)
- ..()
- if(ishuman(user) && slot == slot_head)
- var/mob/living/carbon/human/H = user
- if(istype(H.wear_suit, /obj/item/clothing/suit/cardborg))
- var/obj/item/clothing/suit/cardborg/CB = H.wear_suit
- CB.disguise(user, src)
-
-/obj/item/clothing/head/cardborg/dropped(mob/living/user)
- ..()
- user.remove_alt_appearance("standard_borg_disguise")
+/*
+ * Contents:
+ * Welding mask
+ * Cakehat
+ * Ushanka
+ * Pumpkin head
+ * Kitty ears
+ * Cardborg disguise
+ */
+
+/*
+ * Welding mask
+ */
+/obj/item/clothing/head/welding
+ name = "welding helmet"
+ desc = "A head-mounted face cover designed to protect the wearer completely from space-arc eye."
+ icon_state = "welding"
+ flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
+ item_state = "welding"
+ materials = list(MAT_METAL=1750, MAT_GLASS=400)
+// var/up = 0
+ flash_protect = 2
+ tint = 2
+ armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 60)
+ flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
+ actions_types = list(/datum/action/item_action/toggle)
+ visor_flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
+ visor_flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
+ resistance_flags = FIRE_PROOF
+
+/obj/item/clothing/head/welding/attack_self(mob/user)
+ weldingvisortoggle(user)
+
+
+/*
+ * Cakehat
+ */
+/obj/item/clothing/head/hardhat/cakehat
+ name = "cakehat"
+ desc = "You put the cake on your head. Brilliant."
+ icon_state = "hardhat0_cakehat"
+ item_state = "hardhat0_cakehat"
+ item_color = "cakehat"
+ hitsound = 'sound/weapons/tap.ogg'
+ flags_inv = HIDEEARS|HIDEHAIR
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
+ brightness_on = 2 //luminosity when on
+ flags_cover = HEADCOVERSEYES
+ heat = 1000
+
+/obj/item/clothing/head/hardhat/cakehat/process()
+ var/turf/location = src.loc
+ if(ishuman(location))
+ var/mob/living/carbon/human/M = location
+ if(M.is_holding(src) || M.head == src)
+ location = M.loc
+
+ if(isturf(location))
+ location.hotspot_expose(700, 1)
+
+/obj/item/clothing/head/hardhat/cakehat/turn_on()
+ ..()
+ force = 15
+ throwforce = 15
+ damtype = BURN
+ hitsound = 'sound/items/welder.ogg'
+ START_PROCESSING(SSobj, src)
+
+/obj/item/clothing/head/hardhat/cakehat/turn_off()
+ ..()
+ force = 0
+ throwforce = 0
+ damtype = BRUTE
+ hitsound = 'sound/weapons/tap.ogg'
+ STOP_PROCESSING(SSobj, src)
+
+/obj/item/clothing/head/hardhat/cakehat/is_hot()
+ return on * heat
+/*
+ * Ushanka
+ */
+/obj/item/clothing/head/ushanka
+ name = "ushanka"
+ desc = "Perfect for winter in Siberia, da?"
+ icon_state = "ushankadown"
+ item_state = "ushankadown"
+ flags_inv = HIDEEARS|HIDEHAIR
+ var/earflaps = 1
+ cold_protection = HEAD
+ min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
+
+ dog_fashion = /datum/dog_fashion/head/ushanka
+
+/obj/item/clothing/head/ushanka/attack_self(mob/user)
+ if(earflaps)
+ src.icon_state = "ushankaup"
+ src.item_state = "ushankaup"
+ earflaps = 0
+ to_chat(user, "You raise the ear flaps on the ushanka.")
+ else
+ src.icon_state = "ushankadown"
+ src.item_state = "ushankadown"
+ earflaps = 1
+ to_chat(user, "You lower the ear flaps on the ushanka.")
+
+/*
+ * Pumpkin head
+ */
+/obj/item/clothing/head/hardhat/pumpkinhead
+ name = "carved pumpkin"
+ desc = "A jack o' lantern! Believed to ward off evil spirits."
+ icon_state = "hardhat0_pumpkin"
+ item_state = "hardhat0_pumpkin"
+ item_color = "pumpkin"
+ flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
+ brightness_on = 2 //luminosity when on
+ flags_cover = HEADCOVERSEYES
+
+/*
+ * Kitty ears
+ */
+/obj/item/clothing/head/kitty
+ name = "kitty ears"
+ desc = "A pair of kitty ears. Meow!"
+ icon_state = "kitty"
+ color = "#999999"
+ dynamic_hair_suffix = ""
+
+ dog_fashion = /datum/dog_fashion/head/kitty
+
+/obj/item/clothing/head/kitty/equipped(mob/living/carbon/human/user, slot)
+ if(ishuman(user) && slot == slot_head)
+ update_icon(user)
+ user.update_inv_head() //Color might have been changed by update_icon.
+ ..()
+
+/obj/item/clothing/head/kitty/update_icon(mob/living/carbon/human/user)
+ if(ishuman(user))
+ add_atom_colour("#[user.hair_color]", FIXED_COLOUR_PRIORITY)
+
+/obj/item/clothing/head/kitty/genuine
+ desc = "A pair of kitty ears. A tag on the inside says \"Hand made from real cats.\""
+
+
+/obj/item/clothing/head/hardhat/reindeer
+ name = "novelty reindeer hat"
+ desc = "Some fake antlers and a very fake red nose."
+ icon_state = "hardhat0_reindeer"
+ item_state = "hardhat0_reindeer"
+ item_color = "reindeer"
+ flags_inv = 0
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
+ brightness_on = 1 //luminosity when on
+ dynamic_hair_suffix = ""
+
+ dog_fashion = /datum/dog_fashion/head/reindeer
+
+/obj/item/clothing/head/cardborg
+ name = "cardborg helmet"
+ desc = "A helmet made out of a box."
+ icon_state = "cardborg_h"
+ item_state = "cardborg_h"
+ flags_cover = HEADCOVERSEYES
+ flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
+
+ dog_fashion = /datum/dog_fashion/head/cardborg
+
+/obj/item/clothing/head/cardborg/equipped(mob/living/user, slot)
+ ..()
+ if(ishuman(user) && slot == slot_head)
+ var/mob/living/carbon/human/H = user
+ if(istype(H.wear_suit, /obj/item/clothing/suit/cardborg))
+ var/obj/item/clothing/suit/cardborg/CB = H.wear_suit
+ CB.disguise(user, src)
+
+/obj/item/clothing/head/cardborg/dropped(mob/living/user)
+ ..()
+ user.remove_alt_appearance("standard_borg_disguise")
+
+
+
+/obj/item/clothing/head/wig
+ name = "wig"
+ desc = "A bunch of hair without a head attached."
+ icon_state = ""
+ item_state = "pwig"
+ flags_inv = HIDEHAIR
+ var/hair_style = "Very Long Hair"
+ var/hair_color = "#000"
+
+/obj/item/clothing/head/wig/Initialize(mapload)
+ . = ..()
+ update_icon()
+
+/obj/item/clothing/head/wig/update_icon()
+ cut_overlays()
+ var/datum/sprite_accessory/S = GLOB.hair_styles_list[hair_style]
+ if(!S)
+ icon_state = "pwig"
+ else
+ var/mutable_appearance/M = mutable_appearance(S.icon,S.icon_state)
+ M.appearance_flags |= RESET_COLOR
+ M.color = hair_color
+ add_overlay(M)
+
+/obj/item/clothing/head/wig/worn_overlays(isinhands = FALSE, file2use)
+ . = list()
+ if(!isinhands)
+ var/datum/sprite_accessory/S = GLOB.hair_styles_list[hair_style]
+ if(!S)
+ return
+ var/mutable_appearance/M = mutable_appearance(S.icon, S.icon_state,layer = -HAIR_LAYER)
+ M.appearance_flags |= RESET_COLOR
+ M.color = hair_color
+ . += M
+
+/obj/item/clothing/head/wig/random/Initialize(mapload)
+ hair_style = pick(GLOB.hair_styles_list - "Bald") //Don't want invisible wig
+ hair_color = "#[random_short_color()]"
+ . = ..()
diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm
index 1b21b88447..f2cdefa9a4 100644
--- a/code/modules/mining/equipment/explorer_gear.dm
+++ b/code/modules/mining/equipment/explorer_gear.dm
@@ -46,3 +46,64 @@
/obj/item/clothing/mask/gas/explorer/folded/New()
..()
adjustmask()
+
+/obj/item/clothing/suit/space/hostile_environment
+ name = "H.E.C.K. suit"
+ desc = "Hostile Environiment Cross-Kinetic Suit: A suit designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner."
+ icon_state = "hostile_env"
+ item_state = "hostile_env"
+ flags_1 = THICKMATERIAL_1 //not spaceproof
+ max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
+ resistance_flags = FIRE_PROOF | LAVA_PROOF
+ slowdown = 0
+ armor = list("melee" = 70, "bullet" = 40, "laser" = 10, "energy" = 10, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
+ allowed = list(/obj/item/device/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/device/mining_scanner, /obj/item/device/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe)
+
+/obj/item/clothing/suit/space/hostile_environment/Initialize()
+ . = ..()
+ AddComponent(/datum/component/spraycan_paintable)
+ START_PROCESSING(SSobj, src)
+
+/obj/item/clothing/suit/space/hostile_environment/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/item/clothing/suit/space/hostile_environment/process()
+ var/mob/living/carbon/C = loc
+ if(istype(C) && prob(2)) //cursed by bubblegum
+ if(prob(15))
+ new /datum/hallucination/oh_yeah(C)
+ to_chat(C, "[pick("I AM IMMORTAL.","I SHALL TAKE BACK WHAT'S MINE.","I SEE YOU.","YOU CANNOT ESCAPE ME FOREVER.","DEATH CANNOT HOLD ME.")]")
+ else
+ to_chat(C, "[pick("You hear faint whispers.","You smell ash.","You feel hot.","You hear a roar in the distance.")]")
+
+/obj/item/clothing/head/helmet/space/hostile_environment
+ name = "H.E.C.K. helmet"
+ desc = "Hostile Environiment Cross-Kinetic Helmet: A helmet designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner."
+ icon_state = "hostile_env"
+ item_state = "hostile_env"
+ w_class = WEIGHT_CLASS_NORMAL
+ max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT
+ flags_1 = THICKMATERIAL_1 // no space protection
+ armor = list("melee" = 70, "bullet" = 40, "laser" = 10, "energy" = 10, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
+ resistance_flags = FIRE_PROOF | LAVA_PROOF
+
+/obj/item/clothing/head/helmet/space/hostile_environment/Initialize()
+ . = ..()
+ AddComponent(/datum/component/spraycan_paintable)
+ update_icon()
+
+/obj/item/clothing/head/helmet/space/hostile_environment/update_icon()
+ ..()
+ cut_overlays()
+ var/mutable_appearance/glass_overlay = mutable_appearance(icon, "hostile_env_glass")
+ glass_overlay.appearance_flags = RESET_COLOR
+ add_overlay(glass_overlay)
+
+/obj/item/clothing/head/helmet/space/hostile_environment/worn_overlays(isinhands)
+ . = ..()
+ if(!isinhands)
+ var/mutable_appearance/M = mutable_appearance('icons/mob/head.dmi', "hostile_env_glass")
+ M.appearance_flags = RESET_COLOR
+ . += M
+
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index e16077fec1..95c4898605 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -932,6 +932,8 @@
name = "bubblegum chest"
/obj/structure/closet/crate/necropolis/bubblegum/PopulateContents()
+ new /obj/item/clothing/suit/space/hostile_environment(src)
+ new /obj/item/clothing/head/helmet/space/hostile_environment(src)
var/loot = rand(1,3)
switch(loot)
if(1)
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 666fd767ba..8a978bc44b 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -79,9 +79,12 @@
if(SSticker.current_state == GAME_STATE_PREGAME)
var/time_remaining = SSticker.GetTimeLeft()
- if(time_remaining >= 0)
- time_remaining /= 10
- stat("Time To Start:", (time_remaining >= 0) ? "[round(time_remaining)]s" : "DELAYED")
+ if(time_remaining > 0)
+ stat("Time To Start:", "[round(time_remaining/10)]s")
+ else if(time_remaining == -10)
+ stat("Time To Start:", "DELAYED")
+ else
+ stat("Time To Start:", "SOON")
stat("Players:", "[SSticker.totalPlayers]")
if(client.holder)
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 9f31c5b055..bbe02a3f8e 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -29,6 +29,7 @@
key_third_person = "bows"
message = "bows."
message_param = "bows to %t."
+ restraint_check = TRUE
/datum/emote/living/burp
key = "burp"
@@ -119,6 +120,7 @@
key = "flap"
key_third_person = "flaps"
message = "flaps their wings."
+ restraint_check = TRUE
var/wing_time = 20
/datum/emote/living/flap/run_emote(mob/user, params)
@@ -138,6 +140,7 @@
key = "aflap"
key_third_person = "aflaps"
message = "flaps their wings ANGRILY!"
+ restraint_check = TRUE
wing_time = 10
/datum/emote/living/flip
@@ -147,7 +150,7 @@
/datum/emote/living/flip/run_emote(mob/user, params)
. = ..()
- if(!.)
+ if(.)
user.SpinAnimation(7,1)
/datum/emote/living/frown
@@ -454,7 +457,7 @@
if(e in keys)
continue
E = emote_list[e]
- if(E.can_run_emote(user, TRUE))
+ if(E.can_run_emote(user, status_check = FALSE))
keys += E.key
keys = sortList(keys)
@@ -481,18 +484,21 @@
/datum/emote/living/spin
key = "spin"
key_third_person = "spins"
+ restraint_check = TRUE
/datum/emote/living/spin/run_emote(mob/user)
- user.spin(20, 1)
- if(iscyborg(user))
- var/mob/living/silicon/robot/R = user
- if(R.buckled_mobs)
- for(var/mob/M in R.buckled_mobs)
- if(R.riding_datum)
- R.riding_datum.force_dismount(M)
- else
- R.unbuckle_all_mobs()
- ..()
+ . = ..()
+ if(.)
+ user.spin(20, 1)
+ if(iscyborg(user))
+ var/mob/living/silicon/robot/R = user
+ if(R.buckled_mobs)
+ for(var/mob/M in R.buckled_mobs)
+ if(R.riding_datum)
+ R.riding_datum.force_dismount(M)
+ else
+ R.unbuckle_all_mobs()
+
/datum/emote/living/circle
key = "circle"
diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm
index 0d1f346dcf..c53925e076 100644
--- a/code/modules/mob/living/simple_animal/bot/construction.dm
+++ b/code/modules/mob/living/simple_animal/bot/construction.dm
@@ -357,28 +357,6 @@
var/build_step = 0
var/created_name = "Securitron" //To preserve the name if it's a unique securitron I guess
-/obj/item/clothing/head/helmet/attackby(obj/item/device/assembly/signaler/S, mob/user, params)
- ..()
- if(!issignaler(S))
- ..()
- return
-
- if(type != /obj/item/clothing/head/helmet/sec) //Eh, but we don't want people making secbots out of space helmets.
- return
-
- if(F) //Has a flashlight. Player must remove it, else it will be lost forever.
- to_chat(user, "The mounted flashlight is in the way, remove it first!")
- return
-
- if(S.secured)
- qdel(S)
- var/obj/item/secbot_assembly/A = new /obj/item/secbot_assembly
- user.put_in_hands(A)
- to_chat(user, "You add the signaler to the helmet.")
- qdel(src)
- else
- return
-
/obj/item/secbot_assembly/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/weldingtool))
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 8395ef4d83..cf38d5bfff 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -8,7 +8,7 @@
hitsound_wall = "ricochet"
impact_effect_type = /obj/effect/temp_visual/impact_effect
-/obj/item/projectile/bullet/pellet/Range()
+/obj/item/projectile/bullet/pellet/shotgun_buckshot/Range()
..()
damage -= 0.75
if(damage < 0)
diff --git a/html/changelogs/AutoChangeLog-pr-3157.yml b/html/changelogs/AutoChangeLog-pr-3157.yml
new file mode 100644
index 0000000000..69e7b10920
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3157.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - rscadd: "Wigs are now available in AutoDrobe"
diff --git a/html/changelogs/AutoChangeLog-pr-3159.yml b/html/changelogs/AutoChangeLog-pr-3159.yml
new file mode 100644
index 0000000000..d835ae4122
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3159.yml
@@ -0,0 +1,7 @@
+author: "XDTM"
+delete-after: True
+changes:
+ - rscadd: "Added the H.E.C.K. suit, a guaranteed loot frop from Bubblegum."
+ - rscadd: "The H.E.C.K. suit is fully fire (and ash) proof, and has very good melee armor."
+ - rscadd: "H.E.C.K. suits can also be painted with spraycans, to fully customize your experience."
+ - rscadd: "Despite spending centuries inside a demon king, H.E.C.K. suits are most definitely safe."
diff --git a/html/changelogs/AutoChangeLog-pr-3160.yml b/html/changelogs/AutoChangeLog-pr-3160.yml
new file mode 100644
index 0000000000..c9d48dc583
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3160.yml
@@ -0,0 +1,5 @@
+author: "Kevak/Neri"
+delete-after: True
+changes:
+ - bugfix: "Fixed plasmaman organsprites being missing"
+ - imageadd: "Plasmaman organ sprites added. Credit to Toriate for the sprites"
diff --git a/html/changelogs/AutoChangeLog-pr-3163.yml b/html/changelogs/AutoChangeLog-pr-3163.yml
new file mode 100644
index 0000000000..3c82b42146
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3163.yml
@@ -0,0 +1,4 @@
+author: "Robustin"
+delete-after: True
+changes:
+ - bugfix: "Emotes (e.g. spinning and flipping) will now properly check for consciousness, restraints, etc. when appropriate."
diff --git a/html/changelogs/AutoChangeLog-pr-3168.yml b/html/changelogs/AutoChangeLog-pr-3168.yml
new file mode 100644
index 0000000000..ee61a58860
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3168.yml
@@ -0,0 +1,4 @@
+author: "Naksu"
+delete-after: True
+changes:
+ - tweak: "Made atmos tiny bit faster"
diff --git a/html/changelogs/AutoChangeLog-pr-3170.yml b/html/changelogs/AutoChangeLog-pr-3170.yml
new file mode 100644
index 0000000000..eeb9a06f55
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3170.yml
@@ -0,0 +1,6 @@
+author: "Joan"
+delete-after: True
+changes:
+ - balance: "Ocular Warden base damage per second changed from 12.5 to 15."
+ - bugfix: "Ocular Wardens no longer count themselves when checking for dense objects, which decreased their overall damage by 15%."
+ - balance: "Ocular Wardens now only reduce their damage by 10% per dense object, and only do so once per turf. However, dense turfs now reduce their damage with the same 10% penalty."
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index d18a1bf262..18bbcb3610 100755
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 8b927cf2bb..b996531842 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -294,6 +294,7 @@
#include "code\datums\components\_component.dm"
#include "code\datums\components\archaeology.dm"
#include "code\datums\components\material_container.dm"
+#include "code\datums\components\paintable.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\squeek.dm"
#include "code\datums\diseases\_disease.dm"