diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 30a2af7457..9c944ee1b7 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -5898,6 +5898,15 @@
},
/turf/open/floor/plasteel,
/area/security/prison)
+"alN" = (
+/obj/machinery/camera{
+ c_tag = "Dormitory Toilets";
+ dir = 1
+ },
+/obj/structure/table,
+/obj/structure/bedsheetbin/towel,
+/turf/open/floor/plasteel/freezer,
+/area/crew_quarters/toilet)
"alO" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -15668,13 +15677,6 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
-"aJz" = (
-/obj/machinery/camera{
- c_tag = "Dormitory Toilets";
- dir = 1
- },
-/turf/open/floor/plasteel/freezer,
-/area/crew_quarters/toilet)
"aJA" = (
/obj/machinery/door/airlock/maintenance{
name = "Kitchen Maintenance";
@@ -57422,6 +57424,10 @@
/obj/machinery/vending/wardrobe/bar_wardrobe,
/turf/open/floor/wood,
/area/crew_quarters/bar)
+"moD" = (
+/obj/effect/landmark/barthpot,
+/turf/open/floor/wood,
+/area/library)
"mpI" = (
/obj/structure/table/wood,
/turf/open/floor/wood{
@@ -90144,7 +90150,7 @@ aDL
aFf
aGk
aHU
-aJz
+alN
aAh
aLQ
aJq
@@ -102489,7 +102495,7 @@ aQq
aRP
aIt
aIt
-aIt
+moD
aWd
aXV
aIt
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 2b14f91a11..b0f513e41d 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -124,6 +124,36 @@
},
/turf/open/floor/plating,
/area/crew_quarters/abandoned_gambling_den)
+"aaq" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 4
+ },
+/obj/machinery/airalarm{
+ dir = 1;
+ pixel_y = -22
+ },
+/obj/effect/turf_decal/tile/neutral,
+/obj/effect/turf_decal/tile/neutral{
+ dir = 8
+ },
+/obj/structure/table,
+/obj/structure/bedsheetbin/towel,
+/turf/open/floor/plasteel,
+/area/crew_quarters/toilet/restrooms)
+"aar" = (
+/obj/structure/table,
+/obj/machinery/light{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/structure/bedsheetbin/color,
+/turf/open/floor/plasteel/white/corner{
+ dir = 1
+ },
+/area/crew_quarters/dorms)
"aas" = (
/obj/docking_port/stationary/random{
id = "pod_lavaland1";
@@ -80845,21 +80875,6 @@
},
/turf/open/floor/plating,
/area/crew_quarters/toilet/restrooms)
-"cFc" = (
-/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 4
- },
-/obj/machinery/airalarm{
- dir = 1;
- pixel_y = -22
- },
-/obj/effect/turf_decal/tile/neutral,
-/obj/effect/turf_decal/tile/neutral{
- dir = 8
- },
-/turf/open/floor/plasteel,
-/area/crew_quarters/toilet/restrooms)
"cFd" = (
/obj/machinery/shower{
dir = 8;
@@ -84352,19 +84367,6 @@
/obj/item/reagent_containers/dropper,
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
-"cKT" = (
-/obj/structure/table,
-/obj/structure/bedsheetbin,
-/obj/machinery/light{
- dir = 8
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
-/turf/open/floor/plasteel/white/corner{
- dir = 1
- },
-/area/crew_quarters/dorms)
"cKU" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/effect/turf_decal/tile/neutral{
@@ -127152,6 +127154,10 @@
},
/turf/open/floor/plasteel/white,
/area/science/mixing)
+"kZu" = (
+/obj/effect/landmark/barthpot,
+/turf/open/floor/wood,
+/area/library)
"lak" = (
/turf/open/floor/plasteel/white/side{
dir = 10
@@ -160651,7 +160657,7 @@ caG
chU
cjt
ckR
-cmt
+kZu
cnR
cpv
cqQ
@@ -172742,7 +172748,7 @@ bsE
cAm
cBI
cDo
-cFc
+aaq
cAm
cHW
cIW
@@ -177115,7 +177121,7 @@ cFr
cGP
cqd
cJe
-cKT
+aar
cMq
cAw
cPM
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 93bd61964c..43c8b1155b 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -2,6 +2,17 @@
"aaa" = (
/turf/open/space/basic,
/area/space)
+"aab" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 5
+ },
+/obj/structure/sign/poster/official/random{
+ pixel_y = -32
+ },
+/obj/structure/table,
+/obj/structure/bedsheetbin/towel,
+/turf/open/floor/plasteel/freezer,
+/area/crew_quarters/toilet/restrooms)
"aac" = (
/obj/effect/landmark/carpspawn,
/turf/open/space,
@@ -43777,6 +43788,7 @@
/turf/open/floor/wood,
/area/library)
"bGt" = (
+/obj/effect/landmark/barthpot,
/turf/open/floor/wood{
icon_state = "wood-broken7"
},
@@ -78462,6 +78474,7 @@
/turf/open/floor/engine,
/area/science/xenobiology)
"dbq" = (
+/mob/living/simple_animal/hostile/retaliate/goose,
/turf/open/floor/wood{
icon_state = "wood-broken6"
},
@@ -80884,15 +80897,6 @@
},
/turf/open/floor/plasteel,
/area/quartermaster/warehouse)
-"dhD" = (
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
- },
-/obj/structure/sign/poster/official/random{
- pixel_y = -32
- },
-/turf/open/floor/plasteel/freezer,
-/area/crew_quarters/toilet/restrooms)
"dhE" = (
/obj/structure/sign/poster/contraband/random{
pixel_x = 32
@@ -118789,7 +118793,7 @@ aBu
aCB
aDU
aFg
-dhD
+aab
axC
axC
axC
diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm
index 5202f170d0..24a5cd834a 100644
--- a/_maps/map_files/OmegaStation/OmegaStation.dmm
+++ b/_maps/map_files/OmegaStation/OmegaStation.dmm
@@ -955,6 +955,19 @@
},
/turf/open/floor/plasteel/dark,
/area/bridge)
+"abn" = (
+/obj/structure/table,
+/obj/machinery/camera{
+ c_tag = "Locker Room East";
+ dir = 8
+ },
+/obj/effect/turf_decal/bot,
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/structure/bedsheetbin/color,
+/turf/open/floor/plasteel/white/corner,
+/area/crew_quarters/dorms)
"abo" = (
/obj/effect/turf_decal/tile/neutral,
/obj/effect/turf_decal/tile/neutral{
@@ -15282,19 +15295,6 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/dorms)
-"aAJ" = (
-/obj/structure/table,
-/obj/structure/bedsheetbin,
-/obj/machinery/camera{
- c_tag = "Locker Room East";
- dir = 8
- },
-/obj/effect/turf_decal/bot,
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/turf/open/floor/plasteel/white/corner,
-/area/crew_quarters/dorms)
"aAK" = (
/obj/structure/sign/poster/random,
/turf/closed/wall,
@@ -26273,7 +26273,7 @@
/turf/open/floor/wood,
/area/library)
"aUZ" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
+/obj/effect/landmark/barthpot,
/turf/open/floor/wood,
/area/library)
"aVa" = (
@@ -82334,7 +82334,7 @@ awQ
axK
ayC
awQ
-aAJ
+abn
aBT
awQ
aDI
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index d43f5927a0..386ab45c6b 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -2,6 +2,33 @@
"aaa" = (
/turf/open/space/basic,
/area/space)
+"aab" = (
+/obj/machinery/newscaster{
+ pixel_x = 32
+ },
+/obj/structure/cable{
+ icon_state = "1-8"
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/obj/structure/bedsheetbin/color,
+/turf/open/floor/plasteel/cafeteria,
+/area/crew_quarters/dorms)
+"aac" = (
+/obj/structure/cable{
+ icon_state = "1-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
+ dir = 9
+ },
+/obj/structure/table,
+/obj/structure/bedsheetbin/towel,
+/turf/open/floor/plasteel/freezer,
+/area/crew_quarters/toilet/restrooms)
"aad" = (
/obj/effect/spawner/lootdrop/maintenance,
/turf/open/floor/plating{
@@ -7254,22 +7281,6 @@
},
/turf/open/floor/plasteel/cafeteria,
/area/crew_quarters/dorms)
-"asg" = (
-/obj/structure/bedsheetbin,
-/obj/machinery/newscaster{
- pixel_x = 32
- },
-/obj/structure/cable{
- icon_state = "1-8"
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue{
- dir = 8
- },
-/turf/open/floor/plasteel/cafeteria,
-/area/crew_quarters/dorms)
"ash" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -14880,15 +14891,6 @@
},
/turf/open/floor/plasteel/freezer,
/area/crew_quarters/toilet/restrooms)
-"aJo" = (
-/obj/structure/cable{
- icon_state = "1-8"
- },
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 9
- },
-/turf/open/floor/plasteel/freezer,
-/area/crew_quarters/toilet/restrooms)
"aJp" = (
/obj/item/chair,
/turf/open/floor/plating,
@@ -54391,6 +54393,10 @@
},
/turf/open/floor/plating,
/area/maintenance/department/cargo)
+"ggg" = (
+/mob/living/simple_animal/hostile/retaliate/goose,
+/turf/open/floor/wood,
+/area/maintenance/department/crew_quarters/dorms)
"gih" = (
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 4
@@ -60874,6 +60880,10 @@
},
/turf/open/floor/plasteel,
/area/engine/engineering)
+"vkd" = (
+/obj/effect/landmark/barthpot,
+/turf/open/floor/carpet,
+/area/library/lounge)
"vlF" = (
/obj/item/coin/silver,
/obj/effect/decal/cleanable/oil{
@@ -79870,7 +79880,7 @@ ckT
xhj
xhj
cwK
-xhj
+vkd
xhj
cxn
xhj
@@ -99280,7 +99290,7 @@ cBk
jhD
cBo
alQ
-alb
+ggg
cBw
noC
aiS
@@ -100835,7 +100845,7 @@ aiT
aiS
apX
cod
-asg
+aab
atj
apX
avi
@@ -102394,7 +102404,7 @@ aFH
aGG
aHo
aIk
-aJo
+aac
aGF
aEd
aMr
diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index 6474b6c28d..d898ba2213 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -230,6 +230,8 @@
//Mood
#define COMSIG_ADD_MOOD_EVENT "add_mood" //Called when you send a mood event from anywhere in the code.
#define COMSIG_CLEAR_MOOD_EVENT "clear_mood" //Called when you clear a mood event from anywhere in the code.
+#define COMSIG_INCREASE_SANITY "decrease_sanity" //Called when you want to increase sanity from anywhere in the code.
+#define COMSIG_DECREASE_SANITY "increase_sanity" //Same as above but to decrease sanity instead.
//NTnet
#define COMSIG_COMPONENT_NTNET_RECEIVE "ntnet_receive" //called on an object by its NTNET connection component on receive. (sending_id(number), sending_netname(text), data(datum/netdata))
diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm
index e6eb9f313e..ed45da9923 100644
--- a/code/__DEFINES/jobs.dm
+++ b/code/__DEFINES/jobs.dm
@@ -48,6 +48,7 @@
#define JOB_UNAVAILABLE_PLAYTIME 3
#define JOB_UNAVAILABLE_ACCOUNTAGE 4
#define JOB_UNAVAILABLE_SLOTFULL 5
+#define JOB_UNAVAILABLE_SPECIESLOCK 6
#define DEFAULT_RELIGION "Christianity"
#define DEFAULT_DEITY "Space Jesus"
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index ba5e105041..bccf1f28dd 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -314,7 +314,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define MAP_MAXZ 6
// Defib stats
-#define DEFIB_TIME_LIMIT 960
+#define DEFIB_TIME_LIMIT 1500
#define DEFIB_TIME_LOSS 60
// Diagonal movement
@@ -499,3 +499,6 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define VOMIT_TOXIC 1
#define VOMIT_PURPLE 2
+
+//Misc text define. Does 4 spaces. Used as a makeshift tabulator.
+#define FOURSPACES " "
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index fed2987a89..a4ae6590bf 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -233,11 +233,15 @@
#define OFFSET_S_STORE "s_store"
#define OFFSET_FACEMASK "mask"
#define OFFSET_HEAD "head"
-#define OFFSET_FACE "face"
+#define OFFSET_EYES "eyes"
+#define OFFSET_LIPS "lips"
#define OFFSET_BELT "belt"
#define OFFSET_BACK "back"
#define OFFSET_SUIT "suit"
#define OFFSET_NECK "neck"
+#define OFFSET_HAIR "hair"
+#define OFFSET_FHAIR "fhair"
+#define OFFSET_MUTPARTS "mutantparts"
//MINOR TWEAKS/MISC
#define AGE_MIN 18 //youngest a character can be //CITADEL EDIT - 17 --> 18
diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm
index ba8d229f12..1917d73a1b 100644
--- a/code/__DEFINES/obj_flags.dm
+++ b/code/__DEFINES/obj_flags.dm
@@ -47,4 +47,4 @@
#define ORGAN_FAILING (1<<2) //Failing organs perform damaging effects until replaced or fixed
#define ORGAN_EXTERNAL (1<<3) //Was this organ implanted/inserted/etc, if true will not be removed during species change.
#define ORGAN_VITAL (1<<4) //Currently only the brain
-#define ORGAN_NO_SPOIL (1<<5) //Currently only the brain
+#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 3394fba90c..d4086bc4d9 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -83,7 +83,9 @@
#define INIT_ORDER_SHUTTLE -21
#define INIT_ORDER_MINOR_MAPPING -40
#define INIT_ORDER_PATH -50
-#define INIT_ORDER_PERSISTENCE -100
+#define INIT_ORDER_PERSISTENCE -95
+#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
+
// Subsystem fire priority, from lowest to highest priority
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
@@ -114,6 +116,7 @@
#define FIRE_PRIORITY_MOBS 100
#define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_TICKER 200
+#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
diff --git a/code/__DEFINES/tools.dm b/code/__DEFINES/tools.dm
index 878d35608d..00e08129ae 100644
--- a/code/__DEFINES/tools.dm
+++ b/code/__DEFINES/tools.dm
@@ -8,6 +8,12 @@
#define TOOL_ANALYZER "analyzer"
#define TOOL_MINING "mining"
#define TOOL_SHOVEL "shovel"
+#define TOOL_RETRACTOR "retractor"
+#define TOOL_HEMOSTAT "hemostat"
+#define TOOL_CAUTERY "cautery"
+#define TOOL_DRILL "drill"
+#define TOOL_SCALPEL "scalpel"
+#define TOOL_SAW "saw"
// If delay between the start and the end of tool operation is less than MIN_TOOL_SOUND_DELAY,
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 0e9413520b..8e59106d98 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -280,41 +280,41 @@
if(GLOB.round_id)
var/statspage = CONFIG_GET(string/roundstatsurl)
var/info = statspage ? "[GLOB.round_id]" : GLOB.round_id
- parts += "[GLOB.TAB]Round ID: [info]"
+ parts += "[FOURSPACES]Round ID: [info]"
var/list/voting_results = SSvote.stored_gamemode_votes
if(length(voting_results))
- parts += "[GLOB.TAB]Voting: "
+ parts += "[FOURSPACES]Voting: "
var/total_score = 0
for(var/choice in voting_results)
var/score = voting_results[choice]
total_score += score
- parts += "[GLOB.TAB][GLOB.TAB][choice]: [score]"
+ parts += "[FOURSPACES][FOURSPACES][choice]: [score]"
- parts += "[GLOB.TAB]Shift Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]"
- parts += "[GLOB.TAB]Station Integrity: [mode.station_was_nuked ? "Destroyed" : "[popcount["station_integrity"]]%"]"
+ parts += "[FOURSPACES]Shift Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]"
+ parts += "[FOURSPACES]Station Integrity: [mode.station_was_nuked ? "Destroyed" : "[popcount["station_integrity"]]%"]"
var/total_players = GLOB.joined_player_list.len
if(total_players)
- parts+= "[GLOB.TAB]Total Population: [total_players]"
+ parts+= "[FOURSPACES]Total Population: [total_players]"
if(station_evacuated)
- parts += "
[GLOB.TAB]Evacuation Rate: [popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)"
- parts += "[GLOB.TAB](on emergency shuttle): [popcount[POPCOUNT_SHUTTLE_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_SHUTTLE_ESCAPEES]/total_players)]%)"
- parts += "[GLOB.TAB]Survival Rate: [popcount[POPCOUNT_SURVIVORS]] ([PERCENT(popcount[POPCOUNT_SURVIVORS]/total_players)]%)"
+ parts += "
[FOURSPACES]Evacuation Rate: [popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)"
+ parts += "[FOURSPACES](on emergency shuttle): [popcount[POPCOUNT_SHUTTLE_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_SHUTTLE_ESCAPEES]/total_players)]%)"
+ parts += "[FOURSPACES]Survival Rate: [popcount[POPCOUNT_SURVIVORS]] ([PERCENT(popcount[POPCOUNT_SURVIVORS]/total_players)]%)"
if(SSblackbox.first_death)
var/list/ded = SSblackbox.first_death
if(ded.len)
- parts += "[GLOB.TAB]First Death: [ded["name"]], [ded["role"]], at [ded["area"]]. Damage taken: [ded["damage"]].[ded["last_words"] ? " Their last words were: \"[ded["last_words"]]\"" : ""]"
+ parts += "[FOURSPACES]First Death: [ded["name"]], [ded["role"]], at [ded["area"]]. Damage taken: [ded["damage"]].[ded["last_words"] ? " Their last words were: \"[ded["last_words"]]\"" : ""]"
//ignore this comment, it fixes the broken sytax parsing caused by the " above
else
- parts += "[GLOB.TAB]Nobody died this shift!"
+ parts += "[FOURSPACES]Nobody died this shift!"
if(istype(SSticker.mode, /datum/game_mode/dynamic))
var/datum/game_mode/dynamic/mode = SSticker.mode
- parts += "[GLOB.TAB]Threat level: [mode.threat_level]"
- parts += "[GLOB.TAB]Threat left: [mode.threat]"
- parts += "[GLOB.TAB]Executed rules:"
+ parts += "[FOURSPACES]Threat level: [mode.threat_level]"
+ parts += "[FOURSPACES]Threat left: [mode.threat]"
+ parts += "[FOURSPACES]Executed rules:"
for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
- parts += "[GLOB.TAB][GLOB.TAB][rule.ruletype] - [rule.name]: -[rule.cost] threat"
+ parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - [rule.name]: -[rule.cost] threat"
return parts.Join("
")
/client/proc/roundend_report_file()
diff --git a/code/_globalvars/lists/poll_ignore.dm b/code/_globalvars/lists/poll_ignore.dm
index 94723cae38..626bba9fc3 100644
--- a/code/_globalvars/lists/poll_ignore.dm
+++ b/code/_globalvars/lists/poll_ignore.dm
@@ -13,6 +13,7 @@
#define POLL_IGNORE_GOLEM "golem"
#define POLL_IGNORE_SWARMER "swarmer"
#define POLL_IGNORE_DRONE "drone"
+#define POLL_IGNORE_CLONE "clone"
GLOBAL_LIST_INIT(poll_ignore_desc, list(
POLL_IGNORE_SENTIENCE_POTION = "Sentience potion",
@@ -28,6 +29,7 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list(
POLL_IGNORE_GOLEM = "Golems",
POLL_IGNORE_SWARMER = "Swarmer shells",
POLL_IGNORE_DRONE = "Drone shells",
+ POLL_IGNORE_CLONE = "Defective/SDGF clones"
))
GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore())
diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm
index e7b2ae6cbe..037e5067d8 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -6,8 +6,6 @@ GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the hos
// However it'd be ok to use for accessing attack logs and such too, which are even laggier.
GLOBAL_VAR_INIT(fileaccess_timer, 0)
-GLOBAL_VAR_INIT(TAB, " ")
-
GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
GLOBAL_VAR_INIT(CELLRATE, 0.002) // conversion ratio between a watt-tick and kilojoule
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 4c666d708c..f796f75407 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -157,7 +157,7 @@
var/image/item_overlay = image(holding)
item_overlay.alpha = 92
- if(!user.can_equip(holding, slot_id, disable_warning = TRUE))
+ if(!user.can_equip(holding, slot_id, TRUE))
item_overlay.color = "#FF0000"
else
item_overlay.color = "#00ff00"
diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm
new file mode 100644
index 0000000000..37e53e8990
--- /dev/null
+++ b/code/controllers/subsystem/chat.dm
@@ -0,0 +1,67 @@
+SUBSYSTEM_DEF(chat)
+ name = "Chat"
+ flags = SS_TICKER|SS_NO_INIT
+ wait = 1
+ priority = FIRE_PRIORITY_CHAT
+ init_order = INIT_ORDER_CHAT
+ var/list/payload = list()
+
+
+/datum/controller/subsystem/chat/fire()
+ for(var/i in payload)
+ var/client/C = i
+ C << output(payload[C], "browseroutput:output")
+ payload -= C
+
+ if(MC_TICK_CHECK)
+ return
+
+
+/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE)
+ if(!target || !message)
+ return
+
+ if(!istext(message))
+ stack_trace("to_chat called with invalid input type")
+ return
+
+ if(target == world)
+ target = GLOB.clients
+
+ //Some macros remain in the string even after parsing and fuck up the eventual output
+ message = replacetext(message, "\improper", "")
+ message = replacetext(message, "\proper", "")
+ if(handle_whitespace)
+ message = replacetext(message, "\n", "
")
+ message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
+ message += "
"
+
+
+ //url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
+ //Do the double-encoding here to save nanoseconds
+ var/twiceEncoded = url_encode(url_encode(message))
+
+ if(islist(target))
+ for(var/I in target)
+ var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
+
+ if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
+ continue
+
+ if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
+ C.chatOutput.messageQueue += message
+ continue
+
+ payload[C] += twiceEncoded
+
+ else
+ var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
+
+ if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
+ return
+
+ if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
+ C.chatOutput.messageQueue += message
+ return
+
+ payload[C] += twiceEncoded
diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm
index 730ffa9ff0..eb381af577 100644
--- a/code/datums/components/mood.dm
+++ b/code/datums/components/mood.dm
@@ -21,6 +21,8 @@
RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/add_event)
RegisterSignal(parent, COMSIG_CLEAR_MOOD_EVENT, .proc/clear_event)
+ RegisterSignal(parent, COMSIG_INCREASE_SANITY, .proc/IncreaseSanity)
+ RegisterSignal(parent, COMSIG_DECREASE_SANITY, .proc/DecreaseSanity)
RegisterSignal(parent, COMSIG_MOB_HUD_CREATED, .proc/modify_hud)
var/mob/living/owner = parent
@@ -129,23 +131,23 @@
switch(mood_level)
if(1)
- DecreaseSanity(0.2)
+ DecreaseSanity(src, 0.2)
if(2)
- DecreaseSanity(0.125, SANITY_CRAZY)
+ DecreaseSanity(src, 0.125, SANITY_CRAZY)
if(3)
- DecreaseSanity(0.075, SANITY_UNSTABLE)
+ DecreaseSanity(src, 0.075, SANITY_UNSTABLE)
if(4)
- DecreaseSanity(0.025, SANITY_DISTURBED)
+ DecreaseSanity(src, 0.025, SANITY_DISTURBED)
if(5)
- IncreaseSanity(0.1)
+ IncreaseSanity(src, 0.1)
if(6)
- IncreaseSanity(0.15)
+ IncreaseSanity(src, 0.15)
if(7)
- IncreaseSanity(0.20)
+ IncreaseSanity(src, 0.20)
if(8)
- IncreaseSanity(0.25, SANITY_GREAT)
+ IncreaseSanity(src, 0.25, SANITY_GREAT)
if(9)
- IncreaseSanity(0.4, SANITY_GREAT)
+ IncreaseSanity(src, 0.4, SANITY_GREAT)
if(insanity_effect != holdmyinsanityeffect)
if(insanity_effect > holdmyinsanityeffect)
@@ -218,9 +220,9 @@
master.crit_threshold = (master.crit_threshold - insanity_effect) + newval
insanity_effect = newval
-/datum/component/mood/proc/DecreaseSanity(amount, minimum = SANITY_INSANE)
+/datum/component/mood/proc/DecreaseSanity(datum/source, amount, minimum = SANITY_INSANE)
if(sanity < minimum) //This might make KevinZ stop fucking pinging me.
- IncreaseSanity(0.5)
+ IncreaseSanity(src, 0.5)
else
sanity = max(minimum, sanity - amount)
if(sanity < SANITY_UNSTABLE)
@@ -229,13 +231,13 @@
else
insanity_effect = (MINOR_INSANITY_PEN)
-/datum/component/mood/proc/IncreaseSanity(amount, maximum = SANITY_NEUTRAL)
+/datum/component/mood/proc/IncreaseSanity(datum/source, amount, maximum = SANITY_NEUTRAL)
// Disturbed stops you from getting any more sane - I'm just gonna bung this in here
var/mob/living/owner = parent
if(HAS_TRAIT(owner, TRAIT_UNSTABLE))
return
if(sanity > maximum)
- DecreaseSanity(0.5) //Removes some sanity to go back to our current limit.
+ DecreaseSanity(src, 0.5) //Removes some sanity to go back to our current limit.
else
sanity = min(maximum, sanity + amount)
if(sanity > SANITY_CRAZY)
@@ -262,6 +264,8 @@
if(the_event.timeout)
addtimer(CALLBACK(src, .proc/clear_event, null, category), the_event.timeout, TIMER_UNIQUE|TIMER_OVERRIDE)
+ return the_event
+
/datum/component/mood/proc/clear_event(datum/source, category)
var/datum/mood_event/event = mood_events[category]
if(!event)
diff --git a/code/datums/components/riding.dm b/code/datums/components/riding.dm
index 6fc58b9f5d..0af90f694c 100644
--- a/code/datums/components/riding.dm
+++ b/code/datums/components/riding.dm
@@ -162,12 +162,12 @@
if(!Process_Spacemove(direction) || !isturf(AM.loc))
return
step(AM, direction)
-
+
if((direction & (direction - 1)) && (AM.loc == next)) //moved diagonally
last_move_diagonal = TRUE
else
last_move_diagonal = FALSE
-
+
handle_vehicle_layer()
handle_vehicle_offsets()
else
@@ -234,7 +234,7 @@
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(0, 6), TEXT_WEST = list(0, 6))
else
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4))
-
+
/datum/component/riding/human/force_dismount(mob/living/user)
var/atom/movable/AM = parent
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
index 69f1a66814..f747c563ad 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -169,3 +169,10 @@
/datum/mood_event/sad_empath/add_effects(mob/sadtarget)
description = "[sadtarget.name] seems upset...\n"
+
+/datum/mood_event/revenant_blight
+ description = "Just give up, honk...\n"
+ mood_change = -5
+
+/datum/mood_event/revenant_blight/add_effects()
+ description = "Just give up, [pick("no one will miss you", "there is nothing you can do to help", "even a clown would be more useful than you", "does it even matter in the end?")]...\n"
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index d8bfbd0353..da59c79ac5 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -358,19 +358,20 @@
else
new /obj/effect/temp_visual/bleed(get_turf(owner))
-/mob/living/proc/apply_necropolis_curse(set_curse)
+/mob/living/proc/apply_necropolis_curse(set_curse, duration = 10 MINUTES)
var/datum/status_effect/necropolis_curse/C = has_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE)
if(!set_curse)
set_curse = pick(CURSE_BLINDING, CURSE_SPAWNING, CURSE_WASTING, CURSE_GRASPING)
if(QDELETED(C))
- apply_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE, set_curse)
+ apply_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE, set_curse, duration)
+
else
C.apply_curse(set_curse)
- C.duration += 3000 //additional curses add 5 minutes
+ C.duration += duration * 0.5 //additional curses add half their duration
/datum/status_effect/necropolis_curse
id = "necrocurse"
- duration = 6000 //you're cursed for 10 minutes have fun
+ duration = 10 MINUTES //you're cursed for 10 minutes have fun
tick_interval = 50
alert_type = null
var/curse_flags = NONE
@@ -378,7 +379,9 @@
var/effect_cooldown = 100
var/obj/effect/temp_visual/curse/wasting_effect = new
-/datum/status_effect/necropolis_curse/on_creation(mob/living/new_owner, set_curse)
+/datum/status_effect/necropolis_curse/on_creation(mob/living/new_owner, set_curse, _duration)
+ if(_duration)
+ duration = _duration
. = ..()
if(.)
apply_curse(set_curse)
diff --git a/code/game/area/Space_Station_13_areas.dm b/code/game/area/Space_Station_13_areas.dm
index 8a40fc8b56..798cd9c026 100644
--- a/code/game/area/Space_Station_13_areas.dm
+++ b/code/game/area/Space_Station_13_areas.dm
@@ -339,6 +339,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/crew_quarters/heads/captain
name = "Captain's Office"
icon_state = "captain"
+ clockwork_warp_allowed = FALSE
/area/crew_quarters/heads/captain/private
name = "Captain's Quarters"
diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm
index 4116e18f59..b594991a7d 100644
--- a/code/game/machinery/exp_cloner.dm
+++ b/code/game/machinery/exp_cloner.dm
@@ -49,7 +49,7 @@
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
- var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H)
+ var/list/candidates = pollCandidatesForMob("Do you want and agree to play as a [clonename]'s defective clone, respect their character and not engage in ERP without permission from the original?", null, null, null, 100, H, POLL_IGNORE_CLONE)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
C.transfer_ckey(H)
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index d27357d654..d308d180d0 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -245,6 +245,7 @@
visible_message("[src]'s door slides open. The glowing yellow lights dim to a gentle green.")
else
visible_message("[src]'s door slides open, barraging you with the nauseating smell of charred flesh.")
+ mob_occupant.radiation = 0
playsound(src, 'sound/machines/airlockclose.ogg', 25, 1)
var/list/things_to_clear = list() //Done this way since using GetAllContents on the SSU itself would include circuitry and such.
if(suit)
diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm
index a1ed7fb848..8a33241d46 100644
--- a/code/game/machinery/syndicatebeacon.dm
+++ b/code/game/machinery/syndicatebeacon.dm
@@ -1,3 +1,7 @@
+GLOBAL_VAR_INIT(singularity_counter, 0)
+
+#define METEOR_DISASTER_MODIFIER 0.5
+
////////////////////////////////////////
//Singularity beacon
////////////////////////////////////////
@@ -13,39 +17,57 @@
stat = 0
verb_say = "states"
var/cooldown = 0
-
- var/active = 0
+ var/active = FALSE
+ var/meteor_buff = FALSE
var/icontype = "beacon"
-
/obj/machinery/power/singularity_beacon/proc/Activate(mob/user = null)
+ if(active)
+ return FALSE
if(surplus() < 1500)
if(user)
to_chat(user, "The connected wire doesn't have enough current.")
- return
+ return FALSE
+ if(is_station_level(z))
+ increment_meteor_waves()
for(var/obj/singularity/singulo in GLOB.singularities)
if(singulo.z == z)
singulo.target = src
icon_state = "[icontype]1"
- active = 1
+ active = TRUE
if(user)
to_chat(user, "You activate the beacon.")
+ return TRUE
-
-/obj/machinery/power/singularity_beacon/proc/Deactivate(mob/user = null)
+/obj/machinery/power/singularity_beacon/proc/Deactivate(mob/user)
+ if(!active)
+ return FALSE
for(var/obj/singularity/singulo in GLOB.singularities)
if(singulo.target == src)
singulo.target = null
icon_state = "[icontype]0"
- active = 0
+ active = FALSE
if(user)
to_chat(user, "You deactivate the beacon.")
+ if(meteor_buff)
+ decrement_meteor_waves()
+ return TRUE
+/obj/machinery/power/singularity_beacon/proc/increment_meteor_waves()
+ meteor_buff = TRUE
+ GLOB.singularity_counter++
+ for(var/datum/round_event_control/meteor_wave/W in SSevents.control)
+ W.weight += round(initial(W.weight) * METEOR_DISASTER_MODIFIER)
+
+/obj/machinery/power/singularity_beacon/proc/decrement_meteor_waves()
+ meteor_buff = FALSE
+ GLOB.singularity_counter--
+ for(var/datum/round_event_control/meteor_wave/W in SSevents.control)
+ W.weight -= round(initial(W.weight) * METEOR_DISASTER_MODIFIER)
/obj/machinery/power/singularity_beacon/attack_ai(mob/user)
return
-
/obj/machinery/power/singularity_beacon/attack_hand(mob/user)
. = ..()
if(.)
@@ -86,6 +108,12 @@
if(!active)
return
+ var/is_on_station = is_station_level(z)
+ if(meteor_buff && !is_on_station)
+ decrement_meteor_waves()
+ else if(!meteor_buff && is_on_station)
+ increment_meteor_waves()
+
if(surplus() >= 1500)
add_load(1500)
if(cooldown <= world.time)
@@ -133,3 +161,5 @@
/obj/item/sbeacondrop/clownbomb
desc = "A label on it reads: Warning: Activating this device will send a silly explosive to your location."
droptype = /obj/machinery/syndicatebomb/badmin/clown
+
+#undef METEOR_DISASTER_MODIFIER
diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm
index d539e0a9d5..eb3261bb27 100644
--- a/code/game/mecha/equipment/tools/mining_tools.dm
+++ b/code/game/mecha/equipment/tools/mining_tools.dm
@@ -13,6 +13,8 @@
energy_drain = 10
force = 15
harmful = TRUE
+ tool_behaviour = TOOL_DRILL
+ toolspeed = 0.9
var/drill_delay = 7
var/drill_level = DRILL_BASIC
@@ -141,6 +143,7 @@
drill_delay = 4
drill_level = DRILL_HARDENED
force = 15
+ toolspeed = 0.7
/obj/item/mecha_parts/mecha_equipment/mining_scanner
diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm
index ea9465184a..36708fcf90 100644
--- a/code/game/mecha/equipment/tools/work_tools.dm
+++ b/code/game/mecha/equipment/tools/work_tools.dm
@@ -11,6 +11,8 @@
var/dam_force = 20
var/obj/mecha/working/ripley/cargo_holder
harmful = TRUE
+ tool_behaviour = TOOL_RETRACTOR
+ toolspeed = 0.8
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/mecha/working/ripley/M as obj)
if(..())
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index 9c3df5395f..693d32e545 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -89,6 +89,7 @@
buckled_mob.clear_alert("buckled")
buckled_mobs -= buckled_mob
SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force)
+ SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, src, force)
post_unbuckle_mob(.)
diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm
index 79deac475b..028110170a 100644
--- a/code/game/objects/effects/effect_system/effects_smoke.dm
+++ b/code/game/objects/effects/effect_system/effects_smoke.dm
@@ -288,7 +288,7 @@
contained = "\[[contained]\]"
var/where = "[AREACOORD(location)]"
- if(carry.my_atom.fingerprintslast)
+ if(carry.my_atom && carry.my_atom.fingerprintslast)
var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast)
var/more = ""
if(M)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index b1e5505fa8..6a706fede9 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -421,10 +421,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
//the mob M is attempting to equip this item into the slot passed through as 'slot'. Return 1 if it can do this and 0 if it can't.
//if this is being done by a mob other than M, it will include the mob equipper, who is trying to equip the item to mob M. equipper will be null otherwise.
//If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen.
-//Set disable_warning to 1 if you wish it to not give you outputs.
+//Set disable_warning to TRUE if you wish it to not give you outputs.
/obj/item/proc/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
if(!M)
- return 0
+ return FALSE
return M.can_equip(src, slot, disable_warning, bypass_equip_delay_self)
diff --git a/code/game/objects/items/devices/dogborg_sleeper.dm b/code/game/objects/items/devices/dogborg_sleeper.dm
index ca1648bb07..c1a9136f76 100644
--- a/code/game/objects/items/devices/dogborg_sleeper.dm
+++ b/code/game/objects/items/devices/dogborg_sleeper.dm
@@ -544,4 +544,26 @@
user.visible_message("[hound.name]'s garbage processor groans lightly as [trashman] slips inside.", "Your garbage compactor groans lightly as [trashman] slips inside.")
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1)
return
+ else if(issilicon(target))
+ var/mob/living/silicon/trashbot = target
+ if (!trashbot.devourable)
+ to_chat(user, "[target] registers an error code to your [src]")
+ return
+ if(patient)
+ to_chat(user,"Your [src] is already occupied.")
+ return
+ if(trashbot.buckled)
+ to_chat(user,"[trashbot] is buckled and can not be put into your [src].")
+ return
+ user.visible_message("[hound.name] is ingesting [trashbot] into their [src].", "You start ingesting [trashbot] into your [src.name]...")
+ if(do_after(user, 30, target = trashbot) && !patient && !trashbot.buckled && length(contents) < max_item_count)
+ if(!in_range(src, trashbot)) //Proximity is probably old news by now, do a new check.
+ return //If they moved away, you can't eat them.
+ trashbot.forceMove(src)
+ trashbot.reset_perspective(src)
+ update_gut()
+ user.visible_message("[hound.name]'s garbage processor groans lightly as [trashbot] slips inside.", "Your garbage compactor groans lightly as [trashbot] slips inside.")
+ playsound(hound, 'sound/effects/bin_close.ogg', 80, 1)
+ return
+
return
diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm
index e4e16fbfb4..fdb016df38 100644
--- a/code/game/objects/items/granters.dm
+++ b/code/game/objects/items/granters.dm
@@ -302,7 +302,7 @@
spellname = "charge"
icon_state ="bookcharge"
desc = "This book is made of 100% postconsumer wizard."
- remarks = list("I feel ALIVE!", "I CAN TASTE THE MANA!", "What a RUSH!", "I'm FLYING through these pages!", "THIS GENIUS IS MAKING IT!", "This book is ACTION PAcKED!", "HE'S DONE IT", "LETS GOOOOOOOOOOOO")
+ remarks = list("I feel ALIVE!", "I CAN TASTE THE MANA!", "What a RUSH!", "I'm FLYING through these pages!", "THIS GENIUS IS MAKING IT!", "This book is ACTION PAcKED!", "HE'S DONE IT", "LETS GOOOOOOOOOOOO", "Just wait faster is all...")
/obj/item/book/granter/spell/charge/recoil(mob/user)
..()
diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm
index 5e8250ea00..ccb82f7029 100644
--- a/code/game/objects/items/holy_weapons.dm
+++ b/code/game/objects/items/holy_weapons.dm
@@ -358,6 +358,8 @@
slot_flags = ITEM_SLOT_BELT
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
+ tool_behaviour = TOOL_SAW
+ toolspeed = 1.5 //slower than a real saw
/obj/item/nullrod/claymore/glowing
icon_state = "swordon"
@@ -513,7 +515,8 @@
slot_flags = ITEM_SLOT_BELT
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
-
+ tool_behaviour = TOOL_SAW
+ toolspeed = 0.5
/obj/item/nullrod/hammmer
icon_state = "hammeron"
@@ -539,6 +542,8 @@
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
total_mass = TOTAL_MASS_HAND_REPLACEMENT
+ tool_behaviour = TOOL_SAW
+ toolspeed = 2
/obj/item/nullrod/chainsaw/Initialize()
. = ..()
diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm
index d854ab9f5a..57b9973aa3 100644
--- a/code/game/objects/items/melee/energy.dm
+++ b/code/game/objects/items/melee/energy.dm
@@ -142,6 +142,8 @@
w_class = WEIGHT_CLASS_NORMAL
sharpness = IS_SHARP
light_color = "#40ceff"
+ tool_behaviour = TOOL_SAW
+ toolspeed = 0.7
/obj/item/melee/transforming/energy/sword/cyborg/saw/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return 0
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index fcadbf4270..c9fc59a3fe 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -89,6 +89,7 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plasmaglass
grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10)
+ tableVariant = /obj/structure/table/plasmaglass
/obj/item/stack/sheet/plasmaglass/fifty
amount = 50
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 6532e9f7a5..ad8c4306a5 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -493,12 +493,9 @@
desc = "A large duffel bag for holding surgical tools. Bears the logo of an advanced med-tech firm."
/obj/item/storage/backpack/duffelbag/syndie/surgery_adv/PopulateContents()
- new /obj/item/hemostat/adv(src)
- new /obj/item/circular_saw/adv(src)
- new /obj/item/scalpel/adv(src)
- new /obj/item/retractor/adv(src)
- new /obj/item/cautery/adv(src)
- new /obj/item/surgicaldrill/adv(src)
+ new /obj/item/scalpel/advanced(src)
+ new /obj/item/retractor/advanced(src)
+ new /obj/item/surgicaldrill/advanced(src)
new /obj/item/surgical_drapes(src)
new /obj/item/storage/firstaid/tactical(src)
new /obj/item/clothing/suit/straight_jacket(src)
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 3fe4abeeec..a2b497cc07 100755
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -185,12 +185,9 @@
content_overlays = FALSE
/obj/item/storage/belt/medical/surgery_belt_adv/PopulateContents()
- new /obj/item/hemostat/adv(src)
- new /obj/item/circular_saw/adv(src)
- new /obj/item/scalpel/adv(src)
- new /obj/item/retractor/adv(src)
- new /obj/item/cautery/adv(src)
- new /obj/item/surgicaldrill/adv(src)
+ new /obj/item/scalpel/advanced(src)
+ new /obj/item/retractor/advanced(src)
+ new /obj/item/surgicaldrill/advanced(src)
new /obj/item/surgical_drapes(src)
/obj/item/storage/belt/security
diff --git a/code/game/objects/items/theft_tools.dm b/code/game/objects/items/theft_tools.dm
index 0c74f610df..b99be7e988 100644
--- a/code/game/objects/items/theft_tools.dm
+++ b/code/game/objects/items/theft_tools.dm
@@ -232,7 +232,7 @@
. = ..()
if(!sliver)
return
- if(ismovableatom(O) && O != sliver)
+ if(proximity && ismovableatom(O) && O != sliver)
Consume(O, user)
/obj/item/hemostat/supermatter/throw_impact(atom/hit_atom) // no instakill supermatter javelins
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 49190cdb6c..b1c2c36585 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -599,6 +599,8 @@
sharpness = IS_SHARP
actions_types = list(/datum/action/item_action/startchainsaw)
var/on = FALSE
+ tool_behaviour = TOOL_SAW
+ toolspeed = 0.5
/obj/item/twohanded/required/chainsaw/Initialize()
. = ..()
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 4cb6fc74c0..4552e846ad 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -436,6 +436,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
total_mass = TOTAL_MASS_HAND_REPLACEMENT
+ tool_behaviour = TOOL_SAW
+ toolspeed = 1
/obj/item/mounted_chainsaw/Initialize()
. = ..()
diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index b493f84240..1f7f0ab391 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -288,17 +288,19 @@ LINEN BINS
resistance_flags = FLAMMABLE
max_integrity = 70
var/amount = 10
+ var/list/sheet_types = list(/obj/item/bedsheet)
+ var/static/allowed_sheets = list(/obj/item/bedsheet, /obj/item/reagent_containers/rag/towel)
var/list/sheets = list()
var/obj/item/hidden = null
/obj/structure/bedsheetbin/examine(mob/user)
..()
if(amount < 1)
- to_chat(user, "There are no bed sheets in the bin.")
+ to_chat(user, "There are no sheets in the bin.")
else if(amount == 1)
- to_chat(user, "There is one bed sheet in the bin.")
+ to_chat(user, "There is one sheet in the bin.")
else
- to_chat(user, "There are [amount] bed sheets in the bin.")
+ to_chat(user, "There are [amount] sheets in the bin.")
/obj/structure/bedsheetbin/update_icon()
@@ -317,8 +319,9 @@ LINEN BINS
..()
/obj/structure/bedsheetbin/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/bedsheet))
+ if(is_type_in_list(I, allowed_sheets))
if(!user.transferItemToLoc(I, src))
+ to_chat(user, "\The [I] is stuck to your hand, you cannot place it into the bin!")
return
sheets.Add(I)
amount++
@@ -339,18 +342,19 @@ LINEN BINS
. = ..()
if(.)
return
- if(user.lying)
+ if(user.incapacitated())
return
if(amount >= 1)
amount--
- var/obj/item/bedsheet/B
+ var/obj/item/B
if(sheets.len > 0)
B = sheets[sheets.len]
sheets.Remove(B)
else
- B = new /obj/item/bedsheet(loc)
+ var/chosen = pick(sheet_types)
+ B = new chosen
B.forceMove(drop_location())
user.put_in_hands(B)
@@ -362,19 +366,20 @@ LINEN BINS
to_chat(user, "[hidden] falls out of [B]!")
hidden = null
-
add_fingerprint(user)
+
/obj/structure/bedsheetbin/attack_tk(mob/user)
if(amount >= 1)
amount--
- var/obj/item/bedsheet/B
+ var/obj/item/B
if(sheets.len > 0)
B = sheets[sheets.len]
sheets.Remove(B)
else
- B = new /obj/item/bedsheet(loc)
+ var/chosen = pick(sheet_types)
+ B = new chosen
B.forceMove(drop_location())
to_chat(user, "You telekinetically remove [B] from [src].")
@@ -384,5 +389,11 @@ LINEN BINS
hidden.forceMove(drop_location())
hidden = null
+/obj/structure/bedsheetbin/towel
+ desc = "It looks rather cosy. This one is designed to hold towels."
+ sheet_types = list(/obj/item/reagent_containers/rag/towel)
- add_fingerprint(user)
+/obj/structure/bedsheetbin/color
+ sheet_types = list(/obj/item/bedsheet, /obj/item/bedsheet/blue, /obj/item/bedsheet/green, /obj/item/bedsheet/orange, \
+ /obj/item/bedsheet/purple, /obj/item/bedsheet/red, /obj/item/bedsheet/yellow, /obj/item/bedsheet/brown, \
+ /obj/item/bedsheet/black)
\ No newline at end of file
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 6caa7d834b..23703c7891 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -99,6 +99,25 @@
name = "freezer"
icon_state = "freezer"
+//Snowflake organ freezer code
+//Order is important, since we check source, we need to do the check whenever we have all the organs in the crate
+
+/obj/structure/closet/crate/freezer/open()
+ recursive_organ_check(src)
+ ..()
+
+/obj/structure/closet/crate/freezer/close()
+ ..()
+ recursive_organ_check(src)
+
+/obj/structure/closet/crate/freezer/Destroy()
+ recursive_organ_check(src)
+ ..()
+
+/obj/structure/closet/crate/freezer/Initialize()
+ . = ..()
+ recursive_organ_check(src)
+
/obj/structure/closet/crate/freezer/blood
name = "blood freezer"
desc = "A freezer containing packs of blood."
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index 4a56272ac1..b820e93c7b 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -45,7 +45,7 @@
death = FALSE
anchored = FALSE
density = FALSE
- flavour_text = "You are an ash walker. Your tribe worships the Necropolis. The wastes are sacred ground, its monsters a blessed bounty. \
+ flavour_text = "You are an ash walker. Your tribe worships the Necropolis. The wastes are sacred ground, its monsters a blessed bounty. You would never leave its beautiful expanse. \
You have seen lights in the distance... they foreshadow the arrival of outsiders that seek to tear apart the Necropolis and its domain. Fresh sacrifices for your nest."
assignedrole = "Ash Walker"
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 5503c6103d..e7562476a8 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -182,6 +182,8 @@
soundin = pick('sound/voice/beepsky/god.ogg', 'sound/voice/beepsky/iamthelaw.ogg', 'sound/voice/beepsky/secureday.ogg', 'sound/voice/beepsky/radio.ogg', 'sound/voice/beepsky/insult.ogg', 'sound/voice/beepsky/creep.ogg')
if("honkbot_e")
soundin = pick('sound/items/bikehorn.ogg', 'sound/items/AirHorn2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/items/AirHorn.ogg', 'sound/effects/reee.ogg', 'sound/items/WEEOO1.ogg', 'sound/voice/beepsky/iamthelaw.ogg', 'sound/voice/beepsky/creep.ogg','sound/magic/Fireball.ogg' ,'sound/effects/pray.ogg', 'sound/voice/hiss1.ogg','sound/machines/buzz-sigh.ogg', 'sound/machines/ping.ogg', 'sound/weapons/flashbang.ogg', 'sound/weapons/bladeslice.ogg')
+ if("goose")
+ soundin = pick('sound/creatures/goose1.ogg', 'sound/creatures/goose2.ogg', 'sound/creatures/goose3.ogg', 'sound/creatures/goose4.ogg')
//START OF CIT CHANGES - adds random vore sounds
if ("struggle_sound")
soundin = pick( 'sound/vore/pred/struggle_01.ogg','sound/vore/pred/struggle_02.ogg','sound/vore/pred/struggle_03.ogg',
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 181b72e4a2..ebf6f6626c 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -465,16 +465,21 @@
/turf/AllowDrop()
return TRUE
-/turf/proc/add_vomit_floor(mob/living/carbon/M, toxvomit = NONE)
+/turf/proc/add_vomit_floor(mob/living/M, toxvomit = NONE)
+
var/obj/effect/decal/cleanable/vomit/V = new /obj/effect/decal/cleanable/vomit(src, M.get_static_viruses())
- // If the vomit combined, apply toxicity and reagents to the old vomit
+ //if the vomit combined, apply toxicity and reagents to the old vomit
if (QDELETED(V))
V = locate() in src
// Make toxins and blazaam vomit look different
if(toxvomit == VOMIT_PURPLE)
V.icon_state = "vomitpurp_[pick(1,4)]"
- else if(toxvomit == VOMIT_TOXIC)
+ else if (toxvomit == VOMIT_TOXIC)
V.icon_state = "vomittox_[pick(1,4)]"
+ if (iscarbon(M))
+ var/mob/living/carbon/C = M
+ if(C.reagents)
+ clear_reagents_to_vomit_pool(C,V)
/proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V)
M.reagents.trans_to(V, M.reagents.total_volume / 10)
@@ -487,4 +492,4 @@
//Whatever happens after high temperature fire dies out or thermite reaction works.
//Should return new turf
/turf/proc/Melt()
- return ScrapeAway()
\ No newline at end of file
+ return ScrapeAway()
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 91fdc78d20..4e58a9cba5 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -413,9 +413,9 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
dat += "CLOSED"
else
dat += "UNKNOWN"
- dat += "[GLOB.TAB][TicketHref("Refresh", ref_src)][GLOB.TAB][TicketHref("Re-Title", ref_src, "retitle")]"
+ dat += "[FOURSPACES][TicketHref("Refresh", ref_src)][FOURSPACES][TicketHref("Re-Title", ref_src, "retitle")]"
if(state != AHELP_ACTIVE)
- dat += "[GLOB.TAB][TicketHref("Reopen", ref_src, "reopen")]"
+ dat += "[FOURSPACES][TicketHref("Reopen", ref_src, "reopen")]"
dat += "
Opened at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - opened_at)] ago)"
if(closed_at)
dat += "
Closed at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - closed_at)] ago)"
@@ -423,7 +423,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
if(initiator)
dat += "Actions: [FullMonty(ref_src)]
"
else
- dat += "DISCONNECTED[GLOB.TAB][ClosureLinks(ref_src)]
"
+ dat += "DISCONNECTED[FOURSPACES][ClosureLinks(ref_src)]
"
dat += "
Log:
"
for(var/I in _interactions)
dat += "[I]
"
diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm
index 3f2bd003a3..dc649025d2 100644
--- a/code/modules/antagonists/devil/devil.dm
+++ b/code/modules/antagonists/devil/devil.dm
@@ -539,10 +539,10 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
var/list/parts = list()
parts += "The devil's true name is: [truename]"
parts += "The devil's bans were:"
- parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]"
- parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]"
- parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]"
- parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]"
+ parts += "[FOURSPACES][GLOB.lawlorify[LORE][ban]]"
+ parts += "[FOURSPACES][GLOB.lawlorify[LORE][bane]]"
+ parts += "[FOURSPACES][GLOB.lawlorify[LORE][obligation]]"
+ parts += "[FOURSPACES][GLOB.lawlorify[LORE][banish]]"
return parts.Join("
")
/datum/antagonist/devil/roundend_report()
diff --git a/code/modules/antagonists/revenant/revenant_blight.dm b/code/modules/antagonists/revenant/revenant_blight.dm
index 7037ecae86..89d8de283a 100644
--- a/code/modules/antagonists/revenant/revenant_blight.dm
+++ b/code/modules/antagonists/revenant/revenant_blight.dm
@@ -11,9 +11,9 @@
viable_mobtypes = list(/mob/living/carbon/human)
disease_flags = CURABLE
permeability_mod = 1
- severity = DISEASE_SEVERITY_HARMFUL
- var/stagedamage = 0 //Highest stage reached.
+ severity = DISEASE_SEVERITY_DANGEROUS
var/finalstage = 0 //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects.
+ var/datum/mood_event/revenant_blight/depression
/datum/disease/revblight/cure()
if(affected_mob)
@@ -21,12 +21,13 @@
if(affected_mob.dna && affected_mob.dna.species)
affected_mob.dna.species.handle_mutant_bodyparts(affected_mob)
affected_mob.dna.species.handle_hair(affected_mob)
- to_chat(affected_mob, "You feel better.")
+ SEND_SIGNAL(affected_mob, COMSIG_CLEAR_MOOD_EVENT, "rev_blight")
..()
/datum/disease/revblight/stage_act()
if(!finalstage)
- if(affected_mob.lying && prob(stage*6))
+ if(affected_mob.lying && prob(stage*4))
+ to_chat(affected_mob, "You feel better.")
cure()
return
if(prob(stage*3))
@@ -34,10 +35,6 @@
affected_mob.confused += 8
affected_mob.adjustStaminaLoss(8)
new /obj/effect/temp_visual/revenant(affected_mob.loc)
- if(stagedamage < stage)
- stagedamage++
- affected_mob.adjustToxLoss(stage*2) //should, normally, do about 30 toxin damage.
- new /obj/effect/temp_visual/revenant(affected_mob.loc)
if(prob(45))
affected_mob.adjustStaminaLoss(stage)
..() //So we don't increase a stage before applying the stage damage.
@@ -46,9 +43,13 @@
if(prob(5))
affected_mob.emote("pale")
if(3)
+ if(!depression)
+ depression = SEND_SIGNAL(affected_mob, COMSIG_ADD_MOOD_EVENT, "rev_blight", /datum/mood_event/revenant_blight)
+ SEND_SIGNAL(affected_mob, COMSIG_DECREASE_SANITY, 0.12, SANITY_CRAZY)
if(prob(10))
affected_mob.emote(pick("pale","shiver"))
if(4)
+ SEND_SIGNAL(affected_mob, COMSIG_DECREASE_SANITY, 0.18, SANITY_CRAZY)
if(prob(15))
affected_mob.emote(pick("pale","shiver","cries"))
if(5)
@@ -56,12 +57,18 @@
finalstage = TRUE
to_chat(affected_mob, "You feel like [pick("nothing's worth it anymore", "nobody ever needed your help", "nothing you did mattered", "everything you tried to do was worthless")].")
affected_mob.adjustStaminaLoss(45)
- new /obj/effect/temp_visual/revenant(affected_mob.loc)
- if(affected_mob.dna && affected_mob.dna.species)
+ if(affected_mob.dna?.species)
affected_mob.dna.species.handle_mutant_bodyparts(affected_mob,"#1d2953")
affected_mob.dna.species.handle_hair(affected_mob,"#1d2953")
affected_mob.visible_message("[affected_mob] looks terrifyingly gaunt...", "You suddenly feel like your skin is wrong...")
affected_mob.add_atom_colour("#1d2953", TEMPORARY_COLOUR_PRIORITY)
- addtimer(CALLBACK(src, .proc/cure), 100)
- else
- return
+ new /obj/effect/temp_visual/revenant(affected_mob.loc)
+ addtimer(CALLBACK(src, .proc/curses), 150)
+
+/datum/disease/revblight/proc/curses()
+ if(QDELETED(affected_mob))
+ return
+ affected_mob.playsound_local(affected_mob, 'sound/effects/curse5.ogg', 40, 1, -1)
+ to_chat(affected_mob, "You sense the terrific curse of a vengeful ghost befall upon you...")
+ affected_mob.apply_necropolis_curse(null, 7 MINUTES) //Once the blight has done its course without being cured beforehand, it will cast a necrocurse to compensate how underpowered it's.
+ cure()
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index fa28da74d0..8d845badd4 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -2246,6 +2246,13 @@
contains = list(/mob/living/simple_animal/hostile/retaliate/goat)
crate_name = "goat crate"
+/datum/supply_pack/critter/goose
+ name = "Goose Crate"
+ desc = "Angry and violent birds. Evil, evil creatures."
+ cost = 2500
+ contains = list(/mob/living/simple_animal/hostile/retaliate/goose)
+ crate_name = "goose crate"
+
/datum/supply_pack/critter/monkey
name = "Monkey Cube Crate"
desc = "Stop monkeying around! Contains seven monkey cubes. Just add water!"
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index ed3e9f9b89..20a8c518f4 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -41,6 +41,13 @@
var/dynamic_hair_suffix = ""//head > mask for head hair
var/dynamic_fhair_suffix = ""//mask > head for facial hair
+ //basically a restriction list.
+ var/list/species_restricted = null
+ //Basically syntax is species_restricted = list("Species Name","Species Name")
+ //Add a "exclude" string to do the opposite, making it only only species listed that can't wear it.
+ //You append this to clothing objects.
+
+
/obj/item/clothing/Initialize()
. = ..()
if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE))
@@ -338,3 +345,38 @@ BLIND // can't see anything
deconstruct(FALSE)
else
..()
+
+
+//Species-restricted clothing check. - Thanks Oraclestation, BS13, /vg/station etc.
+/obj/item/clothing/mob_can_equip(mob/M, slot, disable_warning = TRUE)
+
+ //if we can't equip the item anyway, don't bother with species_restricted (also cuts down on spam)
+ if(!..())
+ return FALSE
+
+ // Skip species restriction checks on non-equipment slots
+ if(slot in list(SLOT_IN_BACKPACK, SLOT_L_STORE, SLOT_R_STORE))
+ return TRUE
+
+ if(species_restricted && ishuman(M))
+
+ var/wearable = null
+ var/exclusive = null
+ var/mob/living/carbon/human/H = M
+
+ if("exclude" in species_restricted) //TURNS IT INTO A BLACKLIST - AKA ALL MINUS SPECIES LISTED.
+ exclusive = TRUE
+
+ if(H.dna.species)
+ if(exclusive)
+ if(!(H.dna.species.name in species_restricted))
+ wearable = TRUE
+ else
+ if(H.dna.species.name in species_restricted)
+ wearable = TRUE
+
+ if(!wearable)
+ to_chat(M, "Your species cannot wear [src].")
+ return FALSE
+
+ return TRUE
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index 942fdaed73..bc885868c5 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -324,6 +324,23 @@
item_state = "officertanjacket"
body_parts_covered = CHEST|ARMS
+/obj/item/clothing/suit/ran
+ name = "Shikigami costume"
+ desc = "A costume that looks like a certain shikigami, is super fluffy."
+ icon_state = "ran_suit"
+ item_state = "ran_suit"
+ body_parts_covered = CHEST|GROIN|LEGS
+ flags_inv = HIDEJUMPSUIT|HIDETAUR
+ heat_protection = CHEST|GROIN|LEGS //fluffy tails!
+//2061
+
+/obj/item/clothing/head/ran
+ name = "Shikigami hat"
+ desc = "A hat that looks like it keeps any fluffy ears contained super warm, has little charms over it."
+ icon_state = "ran_hat"
+ item_state = "ran_hat"
+ flags_inv = HIDEEARS
+
/*
* Misc
*/
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index 878030bc5d..6dd6164d79 100644
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -355,6 +355,14 @@
above_suit = TRUE
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 20, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25)
+/obj/item/clothing/accessory/skullcodpiece/fake
+ name = "false codpiece"
+ desc = "A plastic ornament, intended to protect the important things in life. It's not very good at it."
+ icon_state = "skull"
+ item_color = "skull"
+ above_suit = TRUE
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
+
/////////////////////
//Synda Accessories//
/////////////////////
diff --git a/code/modules/events/holiday/halloween.dm b/code/modules/events/holiday/halloween.dm
index 9b72020047..66495d833d 100644
--- a/code/modules/events/holiday/halloween.dm
+++ b/code/modules/events/holiday/halloween.dm
@@ -19,6 +19,7 @@
new /mob/living/simple_animal/parrot/Poly/ghost(Poly.loc)
qdel(Poly)
+
/datum/round_event/spooky/announce(fake)
priority_announce(pick("RATTLE ME BONES!","THE RIDE NEVER ENDS!", "A SKELETON POPS OUT!", "SPOOKY SCARY SKELETONS!", "CREWMEMBERS BEWARE, YOU'RE IN FOR A SCARE!") , "THE CALL IS COMING FROM INSIDE THE HOUSE")
diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm
index af22ae3b96..c575c97901 100644
--- a/code/modules/events/meteor_wave.dm
+++ b/code/modules/events/meteor_wave.dm
@@ -1,5 +1,8 @@
// Normal strength
+#define SINGULO_BEACON_DISTURBANCE 0.2 //singularity beacon also improve the odds of meteor waves and speed them up a little.
+#define SINGULO_BEACON_MAX_DISTURBANCE 0.6 //maximum cap due to how meteor waves can be potentially round ending.
+
/datum/round_event_control/meteor_wave
name = "Meteor Wave: Normal"
typepath = /datum/round_event/meteor_wave
@@ -18,6 +21,8 @@
/datum/round_event/meteor_wave/setup()
announceWhen = 1
startWhen = rand(300, 600) //Yeah for SOME REASON this is measured in seconds and not deciseconds???
+ if(GLOB.singularity_counter)
+ startWhen *= 1 - min(GLOB.singularity_counter * SINGULO_BEACON_DISTURBANCE, SINGULO_BEACON_MAX_DISTURBANCE)
endWhen = startWhen + 60
@@ -52,7 +57,7 @@
kill()
/datum/round_event/meteor_wave/announce(fake)
- priority_announce("Meteors have been detected on collision course with the station. Estimated time until impact: [round(startWhen/60)] minutes.", "Meteor Alert", 'sound/ai/meteors.ogg')
+ priority_announce("Meteors have been detected on collision course with the station. Estimated time until impact: [round(startWhen/60)] minutes.[GLOB.singularity_counter ? " Warning: Anomalous gravity pulse detected, Syndicate technology interference likely." : ""]", "Meteor Alert", 'sound/ai/meteors.ogg')
/datum/round_event/meteor_wave/tick()
if(ISMULTIPLE(activeFor, 3))
@@ -79,3 +84,6 @@
/datum/round_event/meteor_wave/catastrophic
wave_name = "catastrophic"
+
+#undef SINGULO_BEACON_DISTURBANCE
+#undef SINGULO_BEACON_MAX_DISTURBANCE
diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm
index ae49e2cb45..c273690571 100644
--- a/code/modules/goonchat/browserOutput.dm
+++ b/code/modules/goonchat/browserOutput.dm
@@ -162,7 +162,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
var/list/row = src.connectionHistory[i]
if (!row || row.len < 3 || (!row["ckey"] || !row["compid"] || !row["ip"])) //Passed malformed history object
return
- if (world.IsBanned(row["ckey"], row["compid"], row["ip"], real_bans_only=TRUE))
+ if (world.IsBanned(row["ckey"], row["ip"], row["compid"], real_bans_only=TRUE))
found = row
break
@@ -183,8 +183,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]")
//Global chat procs
-/proc/to_chat(target, message, handle_whitespace=TRUE)
- if(!target)
+/proc/to_chat_immediate(target, message, handle_whitespace=TRUE)
+ if(!target || !message)
return
//Ok so I did my best but I accept that some calls to this will be for shit like sound and images
@@ -206,7 +206,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
message = replacetext(message, "\proper", "")
if(handle_whitespace)
message = replacetext(message, "\n", "
")
- message = replacetext(message, "\t", "[GLOB.TAB][GLOB.TAB]")
+ message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
if(islist(target))
// Do the double-encoding outside the loop to save nanoseconds
@@ -248,3 +248,15 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
// url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
C << output(url_encode(url_encode(message)), "browseroutput:output")
+
+/proc/to_chat(target, message, handle_whitespace = TRUE)
+ if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized)
+ to_chat_immediate(target, message, handle_whitespace)
+ return
+ SSchat.queue(target, message, handle_whitespace)
+
+/datum/chatOutput/proc/swaptolightmode() //Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation)
+ owner.force_white_theme()
+
+/datum/chatOutput/proc/swaptodarkmode()
+ owner.force_dark_theme()
diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css
index 164d0d65c6..796d630693 100644
--- a/code/modules/goonchat/browserassets/css/browserOutput.css
+++ b/code/modules/goonchat/browserassets/css/browserOutput.css
@@ -401,6 +401,7 @@ h1.alert, h2.alert {color: #000000;}
.redtext {color: #FF0000; font-size: 24px;}
.clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
+.spooky {color: #FF6100;}
.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;}
@keyframes velvet {
0% { color: #400020; }
diff --git a/code/modules/holiday/halloween/bartholomew.dm b/code/modules/holiday/halloween/bartholomew.dm
new file mode 100644
index 0000000000..129f4e29b6
--- /dev/null
+++ b/code/modules/holiday/halloween/bartholomew.dm
@@ -0,0 +1,148 @@
+/obj/effect/landmark/barthpot
+ name = "barthpot"
+
+/obj/item/barthpot
+ name = "Bartholomew"
+ icon = 'icons/obj/halloween_items.dmi'
+ icon_state = "barthpot"
+ anchored = TRUE
+ var/items_list = list()
+ speech_span = "spooky"
+ var/active = TRUE
+
+/obj/item/barthpot/Destroy()
+ var/obj/item/barthpot/n = new src(loc)
+ n.items_list = items_list
+ ..()
+
+
+/obj/item/barthpot/attackby(obj/item/I, mob/user, params)
+ if(!active)
+ say("Meow!")
+ return
+ for(var/I2 in items_list)
+ if(istype(I, I2))
+ qdel(I)
+ new /obj/item/reagent_containers/food/snacks/special_candy(loc)
+ to_chat(user, "You add the [I.name] to the pot and watch as it melts into the mixture, a candy crystalising in it's wake.")
+ say("Hooray! Thank you!")
+ items_list -= I2
+ return
+ say("It doesn't seem like that's magical enough!")
+
+/obj/item/barthpot/attack_hand(mob/user)
+ if(!active)
+ say("Meow!")
+ return
+ say("Hello there, I'm Bartholomew, Jacqueline's Familiar.")
+ sleep(20)
+ say("I'm currently seeking items to put into my pot, if we get the right items, it should crystalise into a magic candy!")
+ if(!iscarbon(user))
+ say("Though... I'm not sure you can help me.")
+
+ var/message = "From what I can tell, "
+ if(LAZYLEN(items_list) < 5)
+ generate_items()
+ for(var/I2 in items_list)
+ if(!I2)
+ items_list -= I2
+ continue
+ var/obj/item/I3 = new I2
+ message += "a [I3.name], "
+ message += "currently seem to have the most magic potential."
+ sleep(15)
+ say("[message]")
+
+/obj/item/barthpot/proc/generate_items()
+ var/length = LAZYLEN(items_list)
+ var/rand_items = list(/obj/item/bodybag = 1,
+ /obj/item/clothing/glasses/meson = 2,
+ /obj/item/clothing/glasses/sunglasses = 1,
+ /obj/item/clothing/gloves/color/fyellow = 1,
+ /obj/item/clothing/head/hardhat = 1,
+ /obj/item/clothing/head/hardhat/red = 1,
+ /obj/item/clothing/head/that = 1,
+ /obj/item/clothing/head/ushanka = 1,
+ /obj/item/clothing/head/welding = 1,
+ /obj/item/clothing/mask/gas = 15,
+ /obj/item/clothing/suit/hazardvest = 1,
+ /obj/item/clothing/under/rank/vice = 1,
+ /obj/item/clothing/suit/hooded/flashsuit = 2,
+ /obj/item/clothing/accessory/medal/greytide = 1,
+ /obj/item/assembly/prox_sensor = 4,
+ /obj/item/assembly/timer = 3,
+ /obj/item/flashlight = 4,
+ /obj/item/flashlight/pen = 1,
+ /obj/effect/spawner/lootdrop/glowstick = 4,
+ /obj/effect/spawner/lootdrop/mre = 3,
+ /obj/item/multitool = 2,
+ /obj/item/radio/off = 2,
+ /obj/item/t_scanner = 5,
+ /obj/item/airlock_painter = 1,
+ /obj/item/stack/cable_coil/ = 4,
+ /obj/item/stack/medical/bruise_pack = 1,
+ /obj/item/stack/rods = 3,
+ /obj/item/stack/sheet/cardboard = 2,
+ /obj/item/stack/sheet/metal = 1,
+ /obj/item/stack/sheet/mineral/plasma = 1,
+ /obj/item/stack/sheet/rglass = 1,
+ /obj/item/book/manual/wiki/engineering_construction = 1,
+ /obj/item/book/manual/wiki/engineering_hacking = 1,
+ /obj/item/clothing/head/cone = 1,
+ /obj/item/coin/silver = 1,
+ /obj/item/coin/twoheaded = 1,
+ /obj/item/poster/random_contraband = 1,
+ /obj/item/poster/random_official = 1,
+ /obj/item/crowbar = 1,
+ /obj/item/crowbar/red = 1,
+ /obj/item/extinguisher = 11,
+ /obj/item/hand_labeler = 1,
+ /obj/item/paper/crumpled = 1,
+ /obj/item/pen = 1,
+ /obj/item/reagent_containers/spray/pestspray = 1,
+ /obj/item/reagent_containers/rag = 3,
+ /obj/item/stock_parts/cell = 3,
+ /obj/item/storage/belt/utility = 2,
+ /obj/item/storage/box = 2,
+ /obj/item/storage/box/cups = 1,
+ /obj/item/storage/box/donkpockets = 1,
+ /obj/item/storage/box/lights/mixed = 3,
+ /obj/item/storage/box/hug/medical = 1,
+ /obj/item/storage/fancy/cigarettes/dromedaryco = 1,
+ /obj/item/storage/toolbox/mechanical = 1,
+ /obj/item/screwdriver = 3,
+ /obj/item/tank/internals/emergency_oxygen = 2,
+ /obj/item/vending_refill/cola = 1,
+ /obj/item/weldingtool = 3,
+ /obj/item/wirecutters = 1,
+ /obj/item/wrench = 4,
+ /obj/item/relic = 3,
+ /obj/item/weaponcrafting/receiver = 2,
+ /obj/item/clothing/head/cone = 2,
+ /obj/item/grenade/smokebomb = 2,
+ /obj/item/geiger_counter = 3,
+ /obj/item/reagent_containers/food/snacks/grown/citrus/orange = 1,
+ /obj/item/radio/headset = 1,
+ /obj/item/assembly/infra = 1,
+ /obj/item/assembly/igniter = 2,
+ /obj/item/assembly/signaler = 2,
+ /obj/item/assembly/mousetrap = 2,
+ /obj/item/reagent_containers/syringe = 2,
+ /obj/item/clothing/gloves = 8,
+ /obj/item/clothing/shoes/laceup = 1,
+ /obj/item/storage/secure/briefcase = 3,
+ /obj/item/storage/toolbox/artistic = 2,
+ /obj/item/toy/eightball = 1,
+ /obj/item/reagent_containers/pill/floorpill = 1,
+ /obj/item/reagent_containers/food/snacks/cannedpeaches/maint = 2,
+ /obj/item/clothing/shoes = 2)
+ if(length == 5)
+ return TRUE
+ //var/metalist = pickweight(GLOB.maintenance_loot)
+ for(var/i = length, i <= 5, i+=1)
+ var/obj/item = pickweight(rand_items)
+ if(!item)
+ i-=1
+ continue
+ items_list += item
+ return TRUE
diff --git a/code/modules/holiday/halloween.dm b/code/modules/holiday/halloween/halloween.dm
similarity index 92%
rename from code/modules/holiday/halloween.dm
rename to code/modules/holiday/halloween/halloween.dm
index a27db8dd38..5635994a7a 100644
--- a/code/modules/holiday/halloween.dm
+++ b/code/modules/holiday/halloween/halloween.dm
@@ -5,19 +5,27 @@
//spooky recipes
-/datum/recipe/sugarcookie/spookyskull
- reagents = list("flour" = 5, "sugar" = 5, "milk" = 5)
- items = list(
- /obj/item/reagent_containers/food/snacks/egg,
+/datum/crafting_recipe/food/sugarcookie/spookyskull
+ time = 15
+ name = "Sugar cookie"
+ reqs = list(
+ /datum/reagent/consumable/sugar = 5,
+ /obj/item/reagent_containers/food/snacks/pastrybase = 1
)
result = /obj/item/reagent_containers/food/snacks/sugarcookie/spookyskull
+ subcategory = CAT_PASTRY
-/datum/recipe/sugarcookie/spookycoffin
- reagents = list("flour" = 5, "sugar" = 5, "coffee" = 5)
- items = list(
- /obj/item/reagent_containers/food/snacks/egg,
+/datum/crafting_recipe/food/sugarcookie/spookycoffin
+ time = 15
+ name = "Sugar cookie"
+ reqs = list(
+ /datum/reagent/consumable/sugar = 5,
+ /datum/reagent/consumable/coffee = 5,
+ /obj/item/reagent_containers/food/snacks/pastrybase = 1
)
result = /obj/item/reagent_containers/food/snacks/sugarcookie/spookycoffin
+ subcategory = CAT_PASTRY
+
//////////////////////////////
//Spookoween trapped closets//
@@ -34,12 +42,12 @@
var/trapped = 0
var/mob/trapped_mob
-/obj/structure/closet/initialize()
+/obj/structure/closet/Initialize()
..()
if(prob(30))
set_spooky_trap()
-/obj/structure/closet/dump_contents()
+/obj/structure/closet/dump_contents(var/override = TRUE)
..()
trigger_spooky_trap()
@@ -256,6 +264,7 @@
desc = "A standard miniature energy crossbow that uses a hard-light projector to transform bolts into candy corn. Happy Halloween!"
category = "Holiday"
item = /obj/item/gun/energy/kinetic_accelerator/crossbow/halloween
+ cost = 12
surplus = 0
/datum/uplink_item/device_tools/emag/hack_o_lantern
diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm
new file mode 100644
index 0000000000..b2f69df2e4
--- /dev/null
+++ b/code/modules/holiday/halloween/jacqueen.dm
@@ -0,0 +1,442 @@
+//Conversation
+#define JACQ_HELLO (1<<0)
+#define JACQ_CANDIES (1<<1)
+#define JACQ_HEAD (1<<2)
+#define JACQ_FAR (1<<3)
+#define JACQ_WITCH (1<<4)
+#define JACQ_EXPELL (1<<5)
+#define JACQ_DATE (1<<6)
+
+/////// EVENT
+/datum/round_event_control/jacqueen
+ name = "Jacqueline's visit"
+ holidayID = "jacqueen"
+ typepath = /datum/round_event/jacqueen
+ weight = -1 //forces it to be called, regardless of weight
+ max_occurrences = 1
+ earliest_start = 0 MINUTES
+
+/datum/round_event/jacqueen/start()
+ ..()
+
+ for(var/mob/living/carbon/human/H in GLOB.carbon_list)
+ playsound(H, 'sound/spookoween/ahaha.ogg', 100, 0.25)
+
+ for(var/obj/effect/landmark/barthpot/bp in GLOB.landmarks_list)
+ new /obj/item/barthpot(bp.loc)
+ new /mob/living/simple_animal/jacq(bp.loc)
+
+/////// MOBS
+
+//Whacha doing in here like? Yae wan tae ruin ta magicks?
+/mob/living/simple_animal/jacq
+ name = "Jacqueline the Pumpqueen"
+ real_name = "Jacqueline"
+ icon = 'icons/obj/halloween_items.dmi'
+ icon_state = "jacqueline"
+ maxHealth = 25
+ health = 25
+ density = FALSE
+ speech_span = "spooky"
+ friendly = "pets"
+ response_help = "chats with"
+ var/last_poof
+ var/progression = list() //Keep track of where people are in the story.
+ var/active = TRUE //Turn this to false to keep normal mob behavour
+
+/mob/living/simple_animal/jacq/Initialize()
+ ..()
+ poof()
+
+/mob/living/simple_animal/jacq/Life()
+ ..()
+ if(!ckey)
+ if((last_poof+4 MINUTES) < world.realtime)
+ poof()
+
+/mob/living/simple_animal/jacq/Destroy() //I.e invincible
+ visible_message("[src] cackles, \"You'll nae get rid a me that easily!\"")
+ playsound(loc, 'sound/spookoween/ahaha.ogg', 100, 0.25)
+ var/mob/living/simple_animal/jacq/Jacq = new src.type(loc)
+ Jacq.progression = progression
+ ..()
+
+/mob/living/simple_animal/jacq/death() //What is alive may never die
+ visible_message("[src] cackles, \"You'll nae get rid a me that easily!\"")
+ playsound(loc, 'sound/spookoween/ahaha.ogg', 100, 0.25)
+ health = 20
+ poof()
+
+/mob/living/simple_animal/jacq/attack_hand(mob/living/carbon/human/M)
+ if(!active)
+ say("Hello there [gender_check(M)]!")
+ return ..()
+ if(!ckey)
+ canmove = FALSE
+ chit_chat(M)
+ canmove = TRUE
+ ..()
+
+/mob/living/simple_animal/jacq/attack_paw(mob/living/carbon/monkey/M)
+ if(!active)
+ say("Hello there [gender_check(M)]!")
+ return ..()
+ if(!ckey)
+ canmove = FALSE
+ chit_chat(M)
+ canmove = TRUE
+ ..()
+
+/mob/living/simple_animal/jacq/proc/poof()
+ last_poof = world.realtime
+ var/datum/reagents/R = new/datum/reagents(100)//Hey, just in case.
+ var/datum/effect_system/smoke_spread/chem/s = new()
+ R.add_reagent("secretcatchem", (10))
+ s.set_up(R, 0, loc)
+ s.start()
+ visible_message("[src] disappears in a puff of smoke!")
+ canmove = TRUE
+
+ var/hp_list = list()
+ for(var/obj/machinery/holopad/hp in world)
+ hp_list += hp
+
+ var/obj/machinery/holopad/hp = pick(hp_list)
+ if(forceMove(pick(hp.loc)))
+ return TRUE
+
+ return FALSE
+
+/mob/living/simple_animal/jacq/proc/gender_check(mob/living/carbon/C)
+ var/gender = "lamb"
+ if(C)
+ if(C.gender == MALE)
+ gender = "laddie"
+ if(C.gender == FEMALE)
+ gender = "lassie"
+ return gender
+
+//Ye wee bugger, gerrout of it. Ye've nae tae enjoy reading the code fer mae secrets like.
+/mob/living/simple_animal/jacq/proc/chit_chat(mob/living/carbon/C)
+ //Very important
+ var/gender = gender_check(C)
+ if(C)
+ if(C.gender == MALE)
+ gender = "laddie"
+ if(C.gender == FEMALE)
+ gender = "lassie"
+
+ if(!progression["[C.real_name]"] || !(progression["[C.real_name]"] & JACQ_HELLO))
+ visible_message("[src] smiles ominously at [C], \"Well halo there [gender]! Ah'm Jacqueline, tae great Pumpqueen, great tae meet ye.\"")
+ sleep(20)
+ visible_message("[src] continues, says, \"Ah'm sure yae well stunned, but ah've got nae taem fer that. Ah'm after the candies around this station. If yae get mae enoof o the wee buggers, Ah'll give ye a treat, or if yae feeling bold, Ah ken trick ye instead.\" giving [C] a wide grin.")
+ if(!progression["[C.real_name]"])
+ progression["[C.real_name]"] = NONE //TO MAKE SURE THAT THE LIST ENTRY EXISTS.
+
+ progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_HELLO
+
+ var/choices = list("Trick", "Treat", "How do I get candies?")
+ var/choice = input(C, "Trick or Treat?", "Trick or Treat?") in choices
+ switch(choice)
+ if("Trick")
+ trick(C)
+ return
+ if("Treat")
+ if(check_candies(C))
+ treat(C, gender)
+ else
+ visible_message("[src] raises an eyebrow, \"You've nae got any candies Ah want! They're the orange round ones, now bugger off an go get em first.\"")
+ return
+ if("How do I get candies?")
+ visible_message("[src] says, \"Gae find my familiar; Bartholomew. Ee's tendin the cauldron which ken bring oot t' magic energy in items scattered aroond. Knowing him, ee's probably gone tae somewhere with books.\"")
+ return
+
+/mob/living/simple_animal/jacq/proc/treat(mob/living/carbon/C, gender)
+ visible_message("[src] gives off a glowing smile, \"What ken Ah offer ye? I can magic up an object, a potion or a plushie fer ye.\"")
+ var/choices_reward = list("Object - 3 candies", "Potion - 2 candies", "Plushie - 1 candy", "Can I ask you a question instead?")
+ var/choice_reward = input(usr, "Trick or Treat?", "Trick or Treat?") in choices_reward
+
+ //rewards
+ switch(choice_reward)
+ if("Object - 3 candies")
+ if(!take_candies(C, 3))
+ visible_message("[src] raises an eyebrown, \"It's 3 candies per trinket [gender]! Thems the rules!\"")
+ return
+
+ var/new_obj = pick(subtypesof(/obj))
+ //for(var/item in blacklist)
+ // if(new_obj == item)
+ // panic()
+ var/reward = new new_obj(C.loc)
+ C.put_in_hands(reward)
+ visible_message("[src] waves her hands, magicing up a [reward] from thin air, \"There ye are [gender], enjoy! \"")
+ sleep(20)
+ poof()
+ return
+ if("Potion - 2 candies")
+ if(!take_candies(C, 2))
+ visible_message("[src] raises an eyebrow, \"It's 2 candies per potion [gender]! Thems the rules!\"")
+ return
+
+ var/reward = new /obj/item/reagent_containers/potion_container(C.loc)
+ C.put_in_hands(reward)
+ visible_message("[src] waves her hands, magicing up a [reward] from thin air, \"There ye are [gender], enjoy! \"")
+ sleep(20)
+ poof()
+ return
+ if("Plushie - 1 candy")
+ if(!take_candies(C, 1))
+ visible_message("[src] raises an eyebrow, \"It's 1 candy per plushie [gender]! Thems the rules!\"")
+ return
+
+ new /obj/item/toy/plush/random(C.loc)
+ visible_message("[src] waves her hands, magicing up a plushie from thin air, \"There ye are [gender], enjoy! \"")
+ sleep(20)
+ poof()
+ return
+
+ //chitchats!
+ if("Can I ask you a question instead?")
+ var/choices = list()
+ //Figure out where the C is in the story
+ if(!progression["[C.real_name]"]) //I really don't want to get here withoot a hello, but just to be safe
+ progression["[C.real_name]"] = NONE
+ if(!(progression["[C.real_name]"] & JACQ_FAR))
+ if(progression["[C.real_name]"] & JACQ_CANDIES)
+ choices += "You really came all this way for candy?"
+ else
+ choices += "Why do you want the candies?"
+ if(!(progression["[C.real_name]"] & JACQ_HEAD))
+ choices += "What is that on your head?"
+ if(!(progression["[C.real_name]"] & JACQ_EXPELL))
+ if(progression["[C.real_name]"] & JACQ_WITCH)
+ choices += "So you got ex-spell-ed?"
+ else
+ choices += "Are you a witch?"
+
+ //for Kepler, delete this, or just delete the whole story aspect if you want.
+ //If fully completed
+ /*
+ if(progression["[C.real_name]"] & JACQ_FAR)//Damnit this is a pain
+ if(progression["[C.real_name]"] & JACQ_EXPELL) //I give up
+ if(progression["[C.real_name]"] & JACQ_HEAD) //This is only an event thing
+ choices += "Can I take you out on a date?"
+ */
+ if(progression["[C.real_name]"] == 63)//Damnit this is a pain
+ choices += "Can I take you out on a date?"
+
+ //If you've nothing to ask
+ if(!LAZYLEN(choices))
+ visible_message("[src] sighs, \"Ah'm all questioned oot fer noo, [gender].\"")
+ return
+ //Otherwise, lets go!
+ visible_message("[src] says, \"A question? Sure, it'll cost you a candy though!\"")
+ choices += "Nevermind"
+ //Candies for chitchats
+ var/choice = input(C, "What do you want to ask?", "What do you want to ask?") in choices
+ if(!take_candies(C, 1))
+ visible_message("[src] raises an eyebrow, \"It's a candy per question [gender]! Thems the rules!\"")
+ return
+ //Talking
+ switch(choice)
+ if("Why do you want the candies?")
+ visible_message("[src] says, \"Ave ye tried them? They're full of all sorts of reagents. Ah'm after them so ah ken magic em up an hopefully find rare stuff fer me brews. Honestly it's a lot easier magicking up tatt fer ye lot than runnin aroond on me own like. I'd ask me familiars but most a my familiars are funny fellows 'n constantly bugger off on adventures when given simple objectives like; Go grab me a tea cake or watch over me cauldron. Ah mean, ye might run into Bartholomew my cat. Ee's supposed tae be tending my cauldron, but I've nae idea where ee's got tae.\"")
+ progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_CANDIES
+ sleep(30)
+ poof()
+
+ if("You really came all this way for candy?")
+ visible_message("[src] looks tae the side sheepishly, \"Aye, well, tae be honest, Ah'm here tae see me sis, but dunnae let her knew that. She's an alchemist too like, but she dunnae use a caldron like mae, she buggered off like tae her posh ivory tower tae learn bloody chemistry instead!\" [src] scowls, \"She's tae black sheep o' the family too, so we dunnae see eye tae eye sometimes on alchemy. Ah mean, she puts moles in her brews! Ye dunnae put moles in yer brews! Yae threw your brews at tae wee bastards an blew em up!\" [src] sighs, \"But she's a heart o gold so.. Ah wanted tae see her an check up oon her, make sure she's okay.\"")
+ progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_FAR
+ sleep(30)
+ poof()
+
+ if("What is that on your head?")
+ visible_message("[src] pats the pumpkin atop her head, \"This thing? This ain't nae ordinary pumpkin! Me Ma grew this monster ooer a year o love, dedication an hard work. Honestly it felt like she loved this thing more than any of us, which Ah knew ain't true an it's not like she was hartless or anything but.. well, we had a falling oot when Ah got back home with all me stuff in tow. An all she had done is sent me owl after owl over t' last year aboot this bloody pumpkin and ah had enough. So ah took it, an put it on me head. You know, as ye do. Ah am the great Pumpqueen after all, Ah deserve this.\"")
+ progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_HEAD
+ sleep(30)
+ poof()
+
+ if("Are you a witch?")
+ visible_message("[src] grumbles, \"If ye must know, Ah got kicked oot of the witch academy fer being too much of a \"loose cannon\". A bloody loose cannon? Nae they were just pissed off Ah had the brass tae proclaim myself as the Pumpqueen! And also maybe the time Ah went and blew up one of the towers by trying tae make a huge batch of astrogen might've had something tae do with it. Ah mean it would've worked fine if the cauldrons weren't so shite and were actually upgraded by the faculty. So technically no, I'm not a witch.\"")
+ progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_WITCH
+ sleep(30)
+ poof()
+
+ if("So you got ex-spell-ed?")
+ visible_message("[src] Gives you a blank look at the pun, before continuing, \"Not quite, Ah know Ah ken get back into the academy, it's only an explosion, they happen all the time, but, tae be fair it's my fault that things came tae their explosive climax. You don't know what it's like when you're after a witch doctorate, everyone else is doing well, everyone's making new spells and the like, and I'm just good at making explosions really, or fireworks. So, Ah did something Ah knew was dangerous, because Ah had tae do something tae stand oot, but Ah know this life ain't fer me, Ah don't want tae be locked up in dusty towers, grinding reagent after reagent together, trying tae find new reactions, some of the wizards in there haven't left fer years. Ah want tae live, Ah want tae fly around on a broom, turn people into cats fer a day and disappear cackling! That's what got me into witchcraft!\" she throws her arms up in the arm, spinning the pumpkin upon her head slightly. She carefully spins it back to face you, giving oot a soft sigh, \"Ah know my mother's obsession with this dumb thing on my head is just her trying tae fill the void of me and my sis moving oot, and it really shouldn't be on my head. And Ah know that I'm really here tae get help from my sis.. She's the sensible one, and she gives good hugs.\"")
+ sleep(30)
+ visible_message("[src] says, \"Thanks [C], Ah guess Ah didn't realise Ah needed someone tae talk tae but, I'm glad ye spent all your candies talking tae me. Funny how things seem much worse in yer head.\"")
+ progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_EXPELL
+ sleep(30)
+ poof()
+
+ if("Can I take you out on a date?")
+ visible_message("[src] blushes, \"...You want tae ask me oot on a date? Me? After all that nonsense Ah just said? It seems a waste of a candy honestly.\"")
+ progression["[C.real_name]"] = progression["[C.real_name]"] | JACQ_DATE
+ visible_message("[src] looks to the side, deep in thought.")
+ dating_start(C, gender)
+
+ if("Nevermind")
+ visible_message("[src] shrugs, \"Suit yerself then, here's your candy back.\"")
+ new /obj/item/reagent_containers/food/snacks/special_candy(loc)
+
+
+/mob/living/simple_animal/jacq/proc/trick(mob/living/carbon/C, gender)
+ var/option
+ if(ishuman(C))
+ option = rand(1,7)
+ else
+ option = rand(1,6)
+ switch(option)
+ if(1)
+ visible_message("[src] waves their arms around, \"Hocus pocus, making friends is now your focus!\"")
+ var/datum/objective/brainwashing/objective = pick("Make a tasty sandwich for", "Compose a poem for", "Aquire a nice outfit to give to", "Strike up a conversation about pumpkins with", "Write a letter and deliver it to", "Give a nice hat to")
+ var/mob/living/L2 = pick(GLOB.player_list)
+ objective += " [L2.name]."
+ brainwash(C, objective)
+ if(2)
+ visible_message("[src] waves their arms around, \"Off comes your head, a pumpkin taking it's stead!\"")
+ C.reagents.add_reagent("pumpkinmutationtoxin", 5)
+ if(3)
+ visible_message("[src] waves their arms around, \"If only you had a better upbringing, your ears are now full of my singing!\"")
+ var/client/C2 = C.client
+ C2.chatOutput.sendMusic("https://a.uguu.se/rQ8FxxUQ1Xzc_SpOwOkyOwOkyPumpkinSong-PFrPrIxluWk.mp4", 1)//I hope this works!
+ if(4)
+ visible_message("[src] waves their arms around, \"You're cute little bumpkin, On your head is a pumpkin!\"")
+ if(C.head)
+ var/obj/item/W = C.head
+ C.dropItemToGround(W, TRUE)
+ var/jaqc_latern = new /obj/item/clothing/head/hardhat/pumpkinhead/jaqc
+ C.equip_to_slot(jaqc_latern, SLOT_HEAD, 1, 1)
+ if(5)
+ visible_message("[src] waves their arms around, \"In your body there's something amiss, you'll find it's a chem made by my sis!\"")
+ C.reagents.add_reagent("eigenstate", 30)
+ if(6)
+ visible_message("[src] waves their arms around, \"A new familiar for me, and you'll see it's thee!\"")
+ C.reagents.add_reagent("secretcatchem", 30)
+ if(7)
+ visible_message("[src] waves their arms around, \"While you may not be a ghost, for this sheet you'll always be it's host.\"")
+ var/mob/living/carbon/human/H = C
+ if(H.wear_suit)
+ var/obj/item/W = H.wear_suit
+ H.dropItemToGround(W, TRUE)
+ var/ghost = new /obj/item/clothing/suit/ghost_sheet/sticky
+ H.equip_to_slot(ghost, SLOT_WEAR_SUIT, 1, 1)
+ poof()
+
+//Blame Fel
+/mob/living/simple_animal/jacq/proc/dating_start(mob/living/carbon/C, gender)
+ var/candies = pollGhostCandidates("Do you want to go on a date with [C] as Jacqueline the great pumpqueen?")
+ //sleep(30) //If the poll doesn't autopause.
+ if(candies)
+ candies = shuffle(candies)//Shake those ghosts up!
+ for(var/mob/dead/observer/C2 in candies)
+ if(C2.key && C2)
+ key = C2.key
+ message_admins("[C2]/[C2.key] has agreed to go on a date with [C] as Jacqueline.")
+ log_game("HALLOWEEN: [C2]/[C2.key] has agreed to go on a date with [C] as Jacqueline")
+ to_chat(src, "You are Jacqueline the great pumpqueen, witch Extraordinaire! You're a very Scottish lass with a kind heart, but also a little crazy. You also blew up the wizarding school and you're suspended for a while, so you visited the station before heading home. On your head lies the prize pumpkin of your Mother's pumpkin patch. You're currently on a date with [C] and well, I didn't think anyone would get this far. Please be good so I can do events like this in the future. ")
+ return
+ else
+ candies =- C2
+ visible_message("[src] looks to the side, \"Look, Ah like ye but, Ah don't think Ah can right now. If ye can't tell, the stations covered in volatile candies, I've a few other laddies and lassies running after me treats, and tae top it all off, I've the gods breathing down me neck, watching every treat Ah make fer the lot of yous.\" she sighs, \"But that's not a no, right? That's.. just a nae right noo.\"")
+ sleep(20)
+ visible_message("[src] takes off the pumpkin on her head, a rich blush on her cheeks. She leans over planting a kiss upon your forehead quickly befere popping the pumpkin back on her head.")
+ sleep(10)
+ visible_message("[src] waves their arms around, \"There, that aught tae be worth a candy.\"")
+ sleep(20)
+ poof()
+
+/obj/item/clothing/head/hardhat/pumpkinhead/jaqc
+ name = "Jacq o' latern"
+ desc = "A jacqueline o' lantern! You can't seem to get rid of it."
+ icon_state = "hardhat0_pumpkin_j"
+ item_state = "hardhat0_pumpkin_j"
+ item_color = "pumpkin_j"
+ brightness_on = 4
+
+/obj/item/clothing/head/hardhat/pumpkinhead/jaqc/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, GLUED_ITEM_TRAIT)
+
+/obj/item/clothing/suit/ghost_sheet/sticky
+
+/obj/item/clothing/suit/ghost_sheet/sticky/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, GLUED_ITEM_TRAIT)
+
+/obj/item/clothing/suit/ghost_sheet/sticky/attack_hand(mob/user)
+ if(iscarbon(user))
+ to_chat(user, "Boooooo~!")
+ return
+ else
+ ..()
+
+/obj/item/clothing/suit/ghost_sheet/sticky/attack_hand(mob/user)
+ if(iscarbon(user))
+ to_chat(user, "Boooooo~!")
+ return
+ else
+ ..()
+
+/datum/reagent/mutationtoxin/pumpkinhead
+ name = "Pumpkin head mutation toxin"
+ id = "pumpkinmutationtoxin"
+ race = /datum/species/dullahan/pumpkin
+ mutationtext = "The pain subsides. You feel your head roll off your shoulders... and you smell pumpkin."
+ //I couldn't get the replace head sprite with a pumpkin to work so, it is what it is.
+
+/mob/living/simple_animal/jacq/proc/check_candies(mob/living/carbon/C)
+ var/invs = C.get_contents()
+ var/candy_count = 0
+ for(var/item in invs)
+ if(istype(item, /obj/item/reagent_containers/food/snacks/special_candy))
+ candy_count++
+ return candy_count
+
+/mob/living/simple_animal/jacq/proc/take_candies(mob/living/carbon/C, candy_amount = 1)
+ var/inv = C.get_contents()
+ var/candies = list()
+ for(var/item in inv)
+ if(istype(item, /obj/item/reagent_containers/food/snacks/special_candy))
+ candies += item
+ if(LAZYLEN(candies) == candy_amount)
+ break
+ if(LAZYLEN(candies) == candy_amount) //I know it's a double check but eh, to be safe.
+ for(var/candy in candies)
+ qdel(candy)
+ return TRUE
+ return FALSE
+
+//Potions
+/obj/item/reagent_containers/potion_container
+ name = "potion"
+ icon = 'icons/obj/halloween_items.dmi'
+ icon_state = "jacq_potion"
+ desc = "A potion with a strange concoction within. Be careful, as if it's thrown it explodes in a puff of smoke like Jacqueline."
+
+/obj/item/reagent_containers/potion_container/Initialize()
+ .=..()
+ var/R = get_random_reagent_id()
+ reagents.add_reagent(R, 30)
+ name = "[R] Potion"
+
+/obj/item/reagent_containers/potion_container/throw_impact(atom/target)
+ ..()
+ sleep(20)
+ var/datum/effect_system/smoke_spread/chem/s = new()
+ s.set_up(src.reagents, 3, src.loc)
+ s.start()
+ qdel(src)
+
+//Candies
+/obj/item/reagent_containers/food/snacks/special_candy
+ name = "Magic candy"
+ icon = 'icons/obj/halloween_items.dmi'
+ icon_state = "jacq_candy"
+ desc = "A candy with strange magic within. Be careful, as the magic isn't always helpful."
+
+/obj/item/reagent_containers/food/snacks/special_candy/Initialize()
+ .=..()
+ reagents.add_reagent(get_random_reagent_id(), 5)
diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm
index 7d1e25235d..9d075857a7 100644
--- a/code/modules/holiday/holidays.dm
+++ b/code/modules/holiday/holidays.dm
@@ -333,6 +333,16 @@
/datum/holiday/halloween/getStationPrefix()
return pick("Bone-Rattling","Mr. Bones' Own","2SPOOKY","Spooky","Scary","Skeletons")
+/datum/holiday/jacqueen //Subset of halloween
+ name = "jacqueen"
+ begin_day = 27
+ begin_month = OCTOBER
+ end_day = 2
+ end_month = NOVEMBER
+
+/datum/holiday/jacqueen/greet()
+ return "Jacqueline the great Pumpqueen has come to visit!"
+
/datum/holiday/vegan
name = "Vegan Day"
begin_day = 1
diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm
index 6cc11afdf5..889706744a 100644
--- a/code/modules/holodeck/computer.dm
+++ b/code/modules/holodeck/computer.dm
@@ -111,6 +111,11 @@
if(A)
load_program(A)
if("safety")
+ if(!issilicon(usr) && !IsAdminGhost(usr))
+ var/msg = "[key_name(usr)] attempted to emag the holodeck using a href they shouldn't have!"
+ message_admins(msg)
+ log_admin(msg)
+ return
obj_flags ^= EMAGGED
if((obj_flags & EMAGGED) && program && emag_programs[program.name])
emergency_shutdown()
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index f0b7c18b28..591fc650b4 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -145,7 +145,13 @@
ViewManifest()
if(href_list["SelectedJob"])
-
+ if(!SSticker || !SSticker.IsRoundInProgress())
+ var/msg = "[key_name(usr)] attempted to join the round using a href that shouldn't be available at this moment!"
+ log_admin(msg)
+ message_admins(msg)
+ to_chat(usr, "The round is either not ready, or has already finished...")
+ return
+
if(!GLOB.enter_allowed)
to_chat(usr, "There is an administrative lock on entering the game!")
return
@@ -315,6 +321,8 @@
return "Your account is not old enough for [jobtitle]."
if(JOB_UNAVAILABLE_SLOTFULL)
return "[jobtitle] is already filled to capacity."
+ if(JOB_UNAVAILABLE_SPECIESLOCK)
+ return "Your species cannot play as a [jobtitle]."
return "Error: Unknown job availability."
/mob/dead/new_player/proc/IsJobUnavailable(rank, latejoin = FALSE)
@@ -340,6 +348,8 @@
return JOB_UNAVAILABLE_PLAYTIME
if(latejoin && !job.special_check_latejoin(client))
return JOB_UNAVAILABLE_GENERIC
+ if(!client.prefs.pref_species.qualifies_for_rank(rank, client.prefs.features))
+ return JOB_UNAVAILABLE_SPECIESLOCK
return JOB_AVAILABLE
/mob/dead/new_player/proc/AttemptLateSpawn(rank)
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
index aaffc0389d..554b7edfdb 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
@@ -30,7 +30,7 @@
// Decorative wings
/datum/sprite_accessory/deco_wings
icon = 'icons/mob/wings.dmi'
-
+
/datum/sprite_accessory/deco_wings/plain
name = "Plain"
icon_state = "plain"
@@ -96,10 +96,13 @@
name = "Snow"
icon_state = "snow"
-
/datum/sprite_accessory/deco_wings/angel
name = "Angel"
icon_state = "angel"
+ color_src = 0
+ dimension_x = 46
+ center = TRUE
+ dimension_y = 34
/datum/sprite_accessory/deco_wings/none
name = "None"
@@ -155,7 +158,6 @@
/datum/sprite_accessory/insect_wings/punished
name = "Burnt Off"
icon_state = "punished"
- locked = TRUE
/datum/sprite_accessory/insect_wings/firewatch
name = "Firewatch"
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 9569d4826c..760fb7a29f 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -158,7 +158,7 @@
//Returns if a certain item can be equipped to a certain slot.
// Currently invalid for two-handed items - call obj/item/mob_can_equip() instead.
-/mob/proc/can_equip(obj/item/I, slot, disable_warning = 0)
+/mob/proc/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
return FALSE
/mob/proc/can_put_in_hand(I, hand_index)
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 41a8944015..4192c2235b 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -11,6 +11,7 @@
attack_verb = list("attacked", "slapped", "whacked")
///The brain's organ variables are significantly more different than the other organs, with half the decay rate for balance reasons, and twice the maxHealth
decay_factor = STANDARD_ORGAN_DECAY / 4 //30 minutes of decaying to result in a fully damaged brain, since a fast decay rate would be unfun gameplay-wise
+ healing_factor = STANDARD_ORGAN_HEALING / 2
maxHealth = BRAIN_DAMAGE_DEATH
low_threshold = 45
@@ -247,11 +248,13 @@
to_chat(owner, "The last spark of life in your brain fizzles out...")
owner.death()
brain_death = TRUE
+ return
+ ..()
/obj/item/organ/brain/on_death()
if(damage <= BRAIN_DAMAGE_DEATH) //rip
brain_death = FALSE
- applyOrganDamage(maxHealth * decay_factor)
+ ..()
/obj/item/organ/brain/applyOrganDamage(var/d, var/maximum = maxHealth)
diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm
index 155f203708..df1be454ee 100644
--- a/code/modules/mob/living/carbon/alien/organs.dm
+++ b/code/modules/mob/living/carbon/alien/organs.dm
@@ -1,6 +1,7 @@
/obj/item/organ/alien
icon_state = "xgibmid2"
var/list/alien_powers = list()
+ organ_flags = ORGAN_NO_SPOIL
/obj/item/organ/alien/Initialize()
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 85dfe66725..02e6043462 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -865,7 +865,7 @@
piggyback(target)
return
//If you dragged them to you and you're aggressively grabbing try to fireman carry them
- else if(user != target && can_be_firemanned(target))
+ else if(user != target)
fireman_carry(target)
return
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index e248fe22fb..1f843483ee 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -9,9 +9,29 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/name // this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever
var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race
- var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
+ var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
- var/list/offset_features = list(OFFSET_UNIFORM = list(0,0), OFFSET_ID = list(0,0), OFFSET_GLOVES = list(0,0), OFFSET_GLASSES = list(0,0), OFFSET_EARS = list(0,0), OFFSET_SHOES = list(0,0), OFFSET_S_STORE = list(0,0), OFFSET_FACEMASK = list(0,0), OFFSET_HEAD = list(0,0), OFFSET_FACE = list(0,0), OFFSET_BELT = list(0,0), OFFSET_BACK = list(0,0), OFFSET_SUIT = list(0,0), OFFSET_NECK = list(0,0))
+ //Species Icon Drawing Offsets - Pixel X, Pixel Y, Aka X = Horizontal and Y = Vertical, from bottom left corner
+ var/list/offset_features = list(
+ OFFSET_UNIFORM = list(0,0),
+ OFFSET_ID = list(0,0),
+ OFFSET_GLOVES = list(0,0),
+ OFFSET_GLASSES = list(0,0),
+ OFFSET_EARS = list(0,0),
+ OFFSET_SHOES = list(0,0),
+ OFFSET_S_STORE = list(0,0),
+ OFFSET_FACEMASK = list(0,0),
+ OFFSET_HEAD = list(0,0),
+ OFFSET_EYES = list(0,0),
+ OFFSET_LIPS = list(0,0),
+ OFFSET_BELT = list(0,0),
+ OFFSET_BACK = list(0,0),
+ OFFSET_HAIR = list(0,0),
+ OFFSET_FHAIR = list(0,0),
+ OFFSET_SUIT = list(0,0),
+ OFFSET_NECK = list(0,0),
+ OFFSET_MUTPARTS = list(0,0)
+ )
var/hair_color // this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color
var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent.
@@ -401,6 +421,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
facial_overlay.alpha = hair_alpha
+ if(OFFSET_FHAIR in H.dna.species.offset_features)
+ facial_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FHAIR][1]
+ facial_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FHAIR][2]
+
standing += facial_overlay
if(H.head)
@@ -458,9 +482,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
else
hair_overlay.color = forced_colour
hair_overlay.alpha = hair_alpha
- if(OFFSET_FACE in H.dna.species.offset_features)
- hair_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1]
- hair_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2]
+
+ if(OFFSET_HAIR in H.dna.species.offset_features)
+ hair_overlay.pixel_x += H.dna.species.offset_features[OFFSET_HAIR][1]
+ hair_overlay.pixel_y += H.dna.species.offset_features[OFFSET_HAIR][2]
+
if(hair_overlay.icon)
standing += hair_overlay
@@ -481,9 +507,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(H.lip_style && (LIPS in species_traits))
var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER)
lip_overlay.color = H.lip_color
- if(OFFSET_FACE in H.dna.species.offset_features)
- lip_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1]
- lip_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2]
+
+ if(OFFSET_LIPS in H.dna.species.offset_features)
+ lip_overlay.pixel_x += H.dna.species.offset_features[OFFSET_LIPS][1]
+ lip_overlay.pixel_y += H.dna.species.offset_features[OFFSET_LIPS][2]
+
standing += lip_overlay
// eyes
@@ -496,9 +524,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes", -BODY_LAYER)
if((EYECOLOR in species_traits) && has_eyes)
eye_overlay.color = "#" + H.eye_color
- if(OFFSET_FACE in H.dna.species.offset_features)
- eye_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1]
- eye_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2]
+
+ if(OFFSET_EYES in H.dna.species.offset_features)
+ eye_overlay.pixel_x += H.dna.species.offset_features[OFFSET_EYES][1]
+ eye_overlay.pixel_y += H.dna.species.offset_features[OFFSET_EYES][2]
+
standing += eye_overlay
//Underwear, Undershirts & Socks
@@ -784,6 +814,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
bodypart = "snout"
if(bodypart == "xenohead")
bodypart = "xhead"
+ if(bodypart == "insect_wings" || bodypart == "deco_wings")
+ bodypart = "insect_wings"
if(S.gender_specific)
accessory_overlay.icon_state = "[g]_[bodypart]_[S.icon_state]_[layertext]"
@@ -853,6 +885,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
for(var/index=1, index<=husklist.len, index++)
husklist[index] = husklist[index]/255
accessory_overlay.color = husklist
+
+ if(OFFSET_MUTPARTS in H.dna.species.offset_features)
+ accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
+ accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2]
+
standing += accessory_overlay
if(S.hasinner)
@@ -865,6 +902,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(S.center)
inner_accessory_overlay = center_image(inner_accessory_overlay, S.dimension_x, S.dimension_y)
+ if(OFFSET_MUTPARTS in H.dna.species.offset_features)
+ inner_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
+ inner_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2]
+
standing += inner_accessory_overlay
if(S.extra) //apply the extra overlay, if there is one
@@ -905,6 +946,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(HORNCOLOR)
extra_accessory_overlay.color = "#[H.horn_color]"
+
+ if(OFFSET_MUTPARTS in H.dna.species.offset_features)
+ extra_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
+ extra_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2]
+
standing += extra_accessory_overlay
if(S.extra2) //apply the extra overlay, if there is one
@@ -939,6 +985,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
extra2_accessory_overlay.color = "#[H.hair_color]"
if(HORNCOLOR)
extra2_accessory_overlay.color = "#[H.horn_color]"
+
+ if(OFFSET_MUTPARTS in H.dna.species.offset_features)
+ extra2_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
+ extra2_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2]
+
standing += extra2_accessory_overlay
@@ -1345,9 +1396,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/obj/item/organ/cyberimp/chest/thrusters/T = H.getorganslot(ORGAN_SLOT_THRUSTERS)
if(!istype(J) && istype(C))
J = C.jetpack
- if(istype(J) && J.full_speed && J.allow_thrust(0.005, H)) //Prevents stacking
+ if(istype(J) && J.full_speed && J.allow_thrust(0.01, H)) //Prevents stacking
. -= 0.4
- else if(istype(T) && T.allow_thrust(0.005, H))
+ else if(istype(T) && T.allow_thrust(0.01, H))
. -= 0.4
if(!ignoreslow && gravity)
diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
index b7d5130cd8..eba4ff6d2f 100644
--- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
@@ -13,9 +13,12 @@
blacklisted = TRUE
limbs_id = "human"
skinned_type = /obj/item/stack/sheet/animalhide/human
+ var/pumpkin = FALSE
var/obj/item/dullahan_relay/myhead
+/datum/species/dullahan/pumpkin
+ pumpkin = TRUE
/datum/species/dullahan/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
@@ -27,11 +30,19 @@
H.flags_1 &= ~HEAR_1
var/obj/item/bodypart/head/head = H.get_bodypart(BODY_ZONE_HEAD)
if(head)
+ if(pumpkin)//Pumpkinhead!
+ head.animal_origin = 100
+ head.icon = 'icons/obj/clothing/hats.dmi'
+ head.icon_state = "hardhat1_pumpkin_j"
+ head.custom_head = TRUE
head.drop_limb()
head.flags_1 = HEAR_1
head.throwforce = 25
myhead = new /obj/item/dullahan_relay (head, H)
H.put_in_hands(head)
+ var/obj/item/organ/eyes/E = H.getorganslot(ORGAN_SLOT_EYES)
+ for(var/datum/action/item_action/organ_action/OA in E.actions)
+ OA.Trigger()
/datum/species/dullahan/on_species_loss(mob/living/carbon/human/H)
H.flags_1 |= ~HEAR_1
@@ -64,7 +75,7 @@
/obj/item/organ/brain/dullahan
decoy_override = TRUE
- organ_flags = 0
+ organ_flags = ORGAN_NO_SPOIL//Do not decay
/obj/item/organ/tongue/dullahan
zone = "abstract"
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 84c44ea81c..8f84590ff4 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -581,7 +581,7 @@
limbs_id = "cultgolem"
sexes = FALSE
info_text = "As a Runic Golem, you possess eldritch powers granted by the Elder Goddess Nar'Sie."
- species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES) //no mutcolors
+ species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES,NOGENITALS,NOAROUSAL) //no mutcolors
prefix = "Runic"
special_names = null
@@ -635,7 +635,7 @@
say_mod = "clicks"
limbs_id = "clockgolem"
info_text = "As a Clockwork Golem, you are faster than other types of golems. On death, you will break down into scrap."
- species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES)
+ species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES,NOGENITALS,NOAROUSAL)
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
armor = 20 //Reinforced, but much less so to allow for fast movement
attack_verb = "smash"
@@ -691,7 +691,7 @@
sexes = FALSE
info_text = "As a Cloth Golem, you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable. \
Being made of cloth, your body is magic resistant and faster than that of other golems, but weaker and less resilient."
- species_traits = list(NOBLOOD,NO_UNDERWEAR) //no mutcolors, and can burn
+ species_traits = list(NOBLOOD,NO_UNDERWEAR,NOGENITALS,NOAROUSAL) //no mutcolors, and can burn
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOGUNS)
inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
armor = 15 //feels no pain, but not too resistant
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index 46207e5e60..f0dd48c6c1 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -36,8 +36,8 @@
var/turf/T = H.loc
light_amount = min(1,T.get_lumcount()) - 0.5
H.nutrition += light_amount * light_nutrition_gain_factor
- if(H.nutrition > NUTRITION_LEVEL_FULL)
- H.nutrition = NUTRITION_LEVEL_FULL
+ if(H.nutrition >= NUTRITION_LEVEL_FULL)
+ H.nutrition = NUTRITION_LEVEL_FULL - 1
if(light_amount > 0.2) //if there's enough light, heal
H.heal_overall_damage(light_bruteheal, light_burnheal)
H.adjustToxLoss(-light_toxheal)
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 03c7209152..91ff5a3066 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -709,9 +709,9 @@ generate/load female uniform sprites matching all previously decided variables
if(lip_style && (LIPS in dna.species.species_traits))
var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[lip_style]", -BODY_LAYER)
lip_overlay.color = lip_color
- if(OFFSET_FACE in dna.species.offset_features)
- lip_overlay.pixel_x += dna.species.offset_features[OFFSET_FACE][1]
- lip_overlay.pixel_y += dna.species.offset_features[OFFSET_FACE][2]
+ if(OFFSET_LIPS in dna.species.offset_features)
+ lip_overlay.pixel_x += dna.species.offset_features[OFFSET_LIPS][1]
+ lip_overlay.pixel_y += dna.species.offset_features[OFFSET_LIPS][2]
add_overlay(lip_overlay)
// eyes
@@ -724,9 +724,9 @@ generate/load female uniform sprites matching all previously decided variables
eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes", -BODY_LAYER)
if((EYECOLOR in dna.species.species_traits) && has_eyes)
eye_overlay.color = "#" + eye_color
- if(OFFSET_FACE in dna.species.offset_features)
- eye_overlay.pixel_x += dna.species.offset_features[OFFSET_FACE][1]
- eye_overlay.pixel_y += dna.species.offset_features[OFFSET_FACE][2]
+ if(OFFSET_EYES in dna.species.offset_features)
+ eye_overlay.pixel_x += dna.species.offset_features[OFFSET_EYES][1]
+ eye_overlay.pixel_y += dna.species.offset_features[OFFSET_EYES][2]
add_overlay(eye_overlay)
dna.species.handle_hair(src)
diff --git a/code/modules/mob/living/carbon/monkey/inventory.dm b/code/modules/mob/living/carbon/monkey/inventory.dm
index fdc28d13a0..d5fffc70a2 100644
--- a/code/modules/mob/living/carbon/monkey/inventory.dm
+++ b/code/modules/mob/living/carbon/monkey/inventory.dm
@@ -1,4 +1,4 @@
-/mob/living/carbon/monkey/can_equip(obj/item/I, slot, disable_warning = 0)
+/mob/living/carbon/monkey/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
switch(slot)
if(SLOT_HANDS)
if(get_empty_held_indexes())
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 46d9525046..a5943aa0e6 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -290,7 +290,7 @@
to_chat(user, "Access denied.")
else if(istype(W, /obj/item/paicard))
insertpai(user, W)
- else if(istype(W, /obj/item/hemostat) && paicard)
+ else if(W.tool_behaviour == TOOL_HEMOSTAT && paicard)
if(open)
to_chat(user, "Close the access panel before manipulating the personality slot!")
else
@@ -808,11 +808,18 @@ Pass a positive integer as an argument to override a bot's default speed.
switch(href_list["operation"])
if("patrol")
+ if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked))
+ return TRUE
auto_patrol = !auto_patrol
bot_reset()
if("remote")
remote_disabled = !remote_disabled
if("hack")
+ if(!issilicon(usr) && !IsAdminGhost(usr))
+ var/msg = "[key_name(usr)] attempted to hack a bot with a href that shouldn't be available!"
+ message_admins(msg)
+ log_admin(msg)
+ return TRUE
if(emagged != 2)
emagged = 2
hacked = TRUE
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index 9572b4dafc..f22139ac22 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -131,7 +131,8 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
if(..())
return 1
-
+ if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked))
+ return TRUE
switch(href_list["operation"])
if("idcheck")
idcheck = !idcheck
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm
index 3f344c2936..6e89f045da 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm
@@ -19,7 +19,7 @@
return 0
-/mob/living/simple_animal/drone/can_equip(obj/item/I, slot)
+/mob/living/simple_animal/drone/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
switch(slot)
if(SLOT_HEAD)
if(head)
diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm
index a43d4b6d5c..52a007e24c 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm
@@ -52,7 +52,7 @@
return 1
return 0
-/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/I, slot)
+/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
switch(slot)
if(SLOT_GENERC_DEXTROUS_STORAGE)
if(internal_storage)
diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm
new file mode 100644
index 0000000000..b67770fb4b
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/goose.dm
@@ -0,0 +1,35 @@
+#define GOOSE_SATIATED 50
+
+/mob/living/simple_animal/hostile/retaliate/goose
+ name = "goose"
+ desc = "It's loose"
+ icon_state = "goose" // sprites by cogwerks from goonstation, used with permission
+ icon_living = "goose"
+ icon_dead = "goose_dead"
+ mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
+ speak_chance = 0
+ turns_per_move = 5
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat = 2)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ emote_taunt = list("hisses")
+ taunt_chance = 30
+ speed = 0
+ maxHealth = 25
+ health = 25
+ harm_intent_damage = 5
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ attacktext = "pecks"
+ attack_sound = "goose"
+ speak_emote = list("honks")
+ faction = list("neutral")
+ attack_same = TRUE
+ gold_core_spawnable = HOSTILE_SPAWN
+ var/random_retaliate = TRUE
+
+/mob/living/simple_animal/hostile/retaliate/goose/handle_automated_movement()
+ . = ..()
+ if(prob(5) && random_retaliate == TRUE)
+ Retaliate()
diff --git a/code/modules/mob/living/taste.dm b/code/modules/mob/living/taste.dm
index 8b0c54653c..e4d1aa94a5 100644
--- a/code/modules/mob/living/taste.dm
+++ b/code/modules/mob/living/taste.dm
@@ -52,13 +52,11 @@
switch(from.pH)
if(11.5 to INFINITY)
to_chat(src, "You taste a strong alkaline flavour!")
- T.applyOrganDamage(1)
if(8.5 to 11.5)
to_chat(src, "You taste a sort of soapy tone in the mixture.")
if(2.5 to 5.5)
to_chat(src, "You taste a sort of acid tone in the mixture.")
if(-INFINITY to 2.5)
to_chat(src, "You taste a strong acidic flavour!")
- T.applyOrganDamage(1)
#undef DEFAULT_TASTE_SENSITIVITY
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 3e93d9f42b..1759f31344 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -191,7 +191,7 @@
/obj/item/stock_parts/cell/secborg
name = "security borg rechargeable D battery"
- maxcharge = 1750 //35/17/8 disabler/laser/taser shots.
+ maxcharge = 1250 //25/12/6 disabler/laser/taser shots.
materials = list(MAT_GLASS=40)
/obj/item/stock_parts/cell/secborg/empty/Initialize()
diff --git a/code/modules/projectiles/ammunition/energy/stun.dm b/code/modules/projectiles/ammunition/energy/stun.dm
index c9e60ddc1d..36d6e16496 100644
--- a/code/modules/projectiles/ammunition/energy/stun.dm
+++ b/code/modules/projectiles/ammunition/energy/stun.dm
@@ -25,3 +25,6 @@
fire_sound = 'sound/weapons/taser2.ogg'
harmful = FALSE
click_cooldown_override = 3.5
+
+/obj/item/ammo_casing/energy/disabler/secborg
+ e_cost = 50
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index f455e0f138..a5fb8a85aa 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -277,12 +277,12 @@
..()
if(istype(A, /obj/item/ammo_box) || istype(A, /obj/item/ammo_casing))
chamber_round()
+ if(A.tool_behaviour == TOOL_SAW || istype(A, /obj/item/gun/energy/plasmacutter))
+ sawoff(user)
if(istype(A, /obj/item/melee/transforming/energy))
var/obj/item/melee/transforming/energy/W = A
if(W.active)
sawoff(user)
- if(istype(A, /obj/item/circular_saw) || istype(A, /obj/item/gun/energy/plasmacutter))
- sawoff(user)
/obj/item/gun/ballistic/revolver/doublebarrel/attack_self(mob/living/user)
var/num_unloaded = 0
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index d1b99c0e3c..47ccb6076f 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -95,7 +95,7 @@
/obj/item/gun/ballistic/shotgun/riot/attackby(obj/item/A, mob/user, params)
..()
- if(istype(A, /obj/item/circular_saw) || istype(A, /obj/item/gun/energy/plasmacutter))
+ if(A.tool_behaviour == TOOL_SAW || istype(A, /obj/item/gun/energy/plasmacutter))
sawoff(user)
if(istype(A, /obj/item/melee/transforming/energy))
var/obj/item/melee/transforming/energy/W = A
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index 3733dad9a3..44c7894467 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -49,6 +49,7 @@
name = "cyborg disabler"
desc = "An integrated disabler that draws from a cyborg's power cell. This one contains a limiter to prevent the cyborg's power cell from overheating."
can_charge = FALSE
+ ammo_type = list(/obj/item/ammo_casing/energy/disabler/secborg)
selfcharge = EGUN_SELFCHARGE_BORG
cell_type = /obj/item/stock_parts/cell/secborg
charge_delay = 5
diff --git a/code/modules/reagents/chem_wiki_render.dm b/code/modules/reagents/chem_wiki_render.dm
index d4a629c508..efb6bdecfd 100644
--- a/code/modules/reagents/chem_wiki_render.dm
+++ b/code/modules/reagents/chem_wiki_render.dm
@@ -1,14 +1,46 @@
//Generates a markdown txt file for use with the wiki
+/proc/find_reagent(input)
+ . = FALSE
+ if(GLOB.chemical_reagents_list[input]) //prefer IDs!
+ var/datum/reagent/R = GLOB.chemical_reagents_list[input]
+ return R
+ else
+ for(var/X in GLOB.chemical_reagents_list)
+ var/datum/reagent/R = GLOB.chemical_reagents_list[X]
+ if(input == replacetext(lowertext(R.name), " ", ""))
+ return R
+ if(input == replacetext(lowertext(R.id), " ", ""))
+ return R
+
+
+
+
/client/proc/generate_wikichem_list()
set name = "Generate Wikichems"
set category = "Debug"
set desc = "Generate a huge loglist of all the chems. Do not click unless you want lag."
- message_admins("Someone pressed the lag button. (Generate Wikichems)")
- to_chat(usr, "Generating list")
- var/prefix = "|Name | Reagents | Reaction vars | Description | Chem properties |\n|---|---|---|-----------|---|\n"
+
+ var/prefix = "|Name | Reagents | Reaction vars | Description | Chem properties |\n|---|---|---|-----------|---|\n"
+ var/input_reagent = replacetext(lowertext(input("Input the name/id of a reagent to get it's description on it's own, or leave blank to parse every chem.", "Input") as text), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name
+ if(input_reagent)
+ var/input_reagent2 = find_reagent(input_reagent)
+ if(!input_reagent2)
+ to_chat(usr, "Unable to find reagent, stopping proc.")
+ var/single_parse = generate_chemwiki_line(input_reagent2, input_reagent, FALSE)
+ text2file(single_parse, "[GLOB.log_directory]/chem_parse.md")
+ to_chat(usr, "[single_parse].")
+
+ single_parse = generate_chemwiki_line(input_reagent2, input_reagent, FALSE)
+ text2file(single_parse, "[GLOB.log_directory]/chem_parse.md")
+ to_chat(usr, "[single_parse].")
+ to_chat(usr, "Saved line to (wherever your root folder is, i.e. where the DME is)/[GLOB.log_directory]/chem_parse.md OR use the Get Current Logs verb under the Admin tab. (if you click Open, and it does nothing, that's because you've not set a .md default program! Try downloading it instead, and use that file to set a default program! Also have a cute day.)")
+ //Do things here
+ return
+ to_chat(usr, "Generating big list")
+ message_admins("Someone pressed the lag button. (Generate Wikichems)")
///datum/reagent/medicine, /datum/reagent/toxin, /datum/reagent/consumable, /datum/reagent/plantnutriment, /datum/reagent/uranium,
///datum/reagent/colorful_reagent, /datum/reagent/mutationtoxin, /datum/reagent/fermi, /datum/reagent/drug, /datum/reagent/impure
@@ -33,7 +65,7 @@
var/alco = ""
var/grinded = ""
var/blob = ""
- //var/impure
+ var/impure = ""
//Chem_dispencer
var/list/dispensable_reagents = list(
@@ -129,36 +161,46 @@
"applejack"
)
-
+ var/breakout = FALSE
for(var/i = 1, i <= 2, i+=1)
for(var/X in GLOB.chemical_reagents_list)
R = GLOB.chemical_reagents_list[X]
+ if(!R.description) //No description? It's not worth my time.
+ continue
for(var/Y in dispensable_reagents) //Why do you have to do this
if(R.id == Y)
basic += generate_chemwiki_line(R, X, processCR)
+ breakout = TRUE
continue
for(var/Y in components)
if(R.id == Y)
upgraded += generate_chemwiki_line(R, X, processCR)
+ breakout = TRUE
continue
for(var/Y in dispence_drinks)
if(R.id == Y)
drinks += generate_chemwiki_line(R, X, processCR)
+ breakout = TRUE
continue
for(var/Y in dispence_alco)
if(R.id == Y)
alco += generate_chemwiki_line(R, X, processCR)
+ breakout = TRUE
continue
for(var/Y in grind)
if(R.id == Y)
grinded += generate_chemwiki_line(R, X, processCR)
+ breakout = TRUE
continue
+ if(breakout)
+ breakout = FALSE
+ continue
if(istype(R, /datum/reagent/medicine))
medicine += generate_chemwiki_line(R, X, processCR)
@@ -190,10 +232,8 @@
else if(istype(R, /datum/reagent/blob))
blob += generate_chemwiki_line(R, X, processCR)
- /*
else if(istype(R, /datum/reagent/impure))
impure += generate_chemwiki_line(R, X, processCR)
- */
else
remainder += generate_chemwiki_line(R, X, processCR)
@@ -206,8 +246,8 @@
to_chat(usr, "finished chems")
- var/wholeString = ("\n# DISPENCEABLE REAGENTS\n\n[prefix][basic]\n\n# COMPONENT REAGENTS\n\n[prefix][upgraded]\n\n# GRINDABLE REAGENTS\n\n[prefix][grinded]\n")
- wholeString += ("\n# MEDICINE:\n\n[prefix][medicine]\n\n# TOXIN:\n\n[prefix][toxin]\n\n# DRUGS\n\n[prefix][drug]\n\n# FERMI\n\nThese chems lie on the cutting edge of chemical technology, and as such are not recommended for beginners!\n\n[prefix][fermi]\n\n# GENERAL REAGENTS\n\n[prefix][remainder]\n\n# DISPENCEABLE SOFT DRINKS\n\n[prefix][drinks]\n\n# DISPENCEABLE HARD DRINKS\n\n[prefix][alco]\n\n# CONSUMABLE\n\n[prefix][consumable]\n\n# PLANTS\n\n[prefix][plant]\n\n# URANIUM\n\n[prefix][uranium]\n\n# COLOURS\n\n[prefix][colours]\n\n# RACE MUTATIONS\n\n[prefix][muta]\n\n\n# BLOB REAGENTS\n\n[prefix][blob]\n")
+ var/wholeString = ("\n# DISPENCEABLE REAGENTS\n\n[prefix][basic]\n\n# COMPONENT REAGENTS\n\n[prefix][upgraded]\n\n# GROUND REAGENTS\n\n[prefix][grinded]\n")
+ wholeString += ("\n# MEDICINE:\n\n[prefix][medicine]\n\n# TOXIN:\n\n[prefix][toxin]\n\n# DRUGS\n\n[prefix][drug]\n\n# FERMI\n\nThese chems lie on the cutting edge of chemical technology, and as such are not recommended for beginners!\n\n[prefix][fermi]\n\n# IMPURE REAGENTS\n\n[prefix][impure]\n\n# GENERAL REAGENTS\n\n[prefix][remainder]\n\n# DISPENCEABLE SOFT DRINKS\n\n[prefix][drinks]\n\n# DISPENCEABLE HARD DRINKS\n\n[prefix][alco]\n\n# CONSUMABLE\n\n[prefix][consumable]\n\n# PLANTS\n\n[prefix][plant]\n\n# URANIUM\n\n[prefix][uranium]\n\n# COLOURS\n\n[prefix][colours]\n\n# RACE MUTATIONS\n\n[prefix][muta]\n\n\n# BLOB REAGENTS\n\n[prefix][blob]\n")
prefix = "|Name | Reagents | Reaction vars | Description |\n|---|---|---|----------|\n"
var/CRparse = ""
@@ -257,6 +297,8 @@
//Temp, Explosions and pH
if(CR)
outstring += "[(CR.FermiChem?"- Min react temp: [CR.OptimalTempMin]K
":"[(CR.required_temp?"- Min react temp: [CR.required_temp]K
":"")]")] [(CR.FermiChem?"- Explosion_temp: [CR.ExplodeTemp]K
":"")] [(CR.FermiChem?"- pH range: [max((CR.OptimalpHMin - CR.ReactpHLim), 0)] to [min((CR.OptimalpHMax + CR.ReactpHLim), 14)]
":"")] "
+ if(CR.FermiChem)
+ outstring += "[(CR.PurityMin?"- Min explosive purity: [CR.PurityMin]
":"")] [(CR.FermiExplode?"- Special explosion: Yes
":"")]"
else
outstring += ""
@@ -288,17 +330,15 @@
outstring += " | "
//Description, OD, Addict, Meta
- outstring += "[R.description] | - Metabolism_rate: [R.metabolization_rate/2]u/s
[(R.overdose_threshold?"- Overdose: [R.overdose_threshold]u
":"")] [(R.addiction_threshold?"- Addiction: [R.addiction_threshold]u
":"")] "
+ outstring += "[R.description] | - Metabolism rate: [R.metabolization_rate/2]u/s
[(R.overdose_threshold?"- Overdose: [R.overdose_threshold]u
":"")] [(R.addiction_threshold?"- Addiction: [R.addiction_threshold]u
":"")] "
- if(R.impure_chem != "fermiTox" && R.impure_chem)
+ if(R.impure_chem && R.impure_chem != "fermiTox")
R3 = GLOB.chemical_reagents_list[R.impure_chem]
outstring += "- Impure chem:[R3.name]
"
- if(R.inverse_chem != "fermiTox" && R.inverse_chem)
+ if(R.inverse_chem && R.impure_chem != "fermiTox")
R3 = GLOB.chemical_reagents_list[R.inverse_chem]
- outstring += "- Inverse chem:[R3.name]
"
-
-
+ outstring += "- Inverse chem:[R3.name]
[(R3.inverse_chem_val?"- Inverse purity: [R3.inverse_chem_val]
":"")] "
if(CR)
if(CR.required_container)
@@ -307,16 +347,9 @@
outstring += "- Required container: [I.name]
"*/
outstring += "- Required container: [CR.required_container]
"
- if(CR.FermiChem)
- outstring += "- Minimum purity: [CR.PurityMin]
[(CR.FermiExplode?"- Special explosion: Yes
":"")]"
-
-
outstring += "
|\n"
return outstring
-
-
-
//Generate the big list of reaction based reactions.
//|Name | Reagents | Reaction vars | Description | Chem properties
/proc/generate_chemreactwiki_line(datum/chemical_reaction/CR)
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 1be30301ec..fb064b6146 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -63,7 +63,7 @@
var/targetVol = 0 //the target volume, i.e. the total amount that can be created during a fermichem reaction.
var/reactedVol = 0 //how much of the reagent is reacted during a fermireaction
var/fermiIsReacting = FALSE //that prevents multiple reactions from occurring (i.e. add_reagent calls to process_reactions(), this stops any extra reactions.)
- var/fermiReactID = null //ID of the chem being made during a fermireaction, kept here so it's cache isn't lost between loops/procs.
+ var/fermiReactID //ID of the chem being made during a fermireaction, kept here so it's cache isn't lost between loops/procs.
/datum/reagents/New(maximum=100, new_flags)
maximum_volume = maximum
@@ -128,14 +128,12 @@
/datum/reagents/proc/remove_all(amount = 1)
var/list/cached_reagents = reagent_list
- if((total_volume - amount) <= 0)//Because this can result in 0, I don't want it to crash.
- pH = 7
if(total_volume > 0)
var/part = amount / total_volume
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
remove_reagent(R.id, R.volume * part, ignore_pH = TRUE)
-
+ pH = REAGENT_NORMAL_PH
update_total()
handle_reactions()
return amount
@@ -365,7 +363,7 @@
/datum/reagents/proc/handle_reactions()//HERE EDIT HERE THE MAIN REACTION
- if(fermiIsReacting == TRUE)
+ if(fermiIsReacting) //This ARRESTS other reactions. If you don't want this, then remove it.
return
if(reagents_holder_flags & NO_REACT)
@@ -404,7 +402,7 @@
for(var/B in cached_required_reagents)
- if(!has_reagent(B, cached_required_reagents[B]))
+ if(!has_reagent(B, cached_required_reagents[B]))//Allows vols at less than 1 to react.
break
total_matching_reagents++
for(var/B in cached_required_catalysts)
@@ -464,7 +462,7 @@
//Temperature plays into a larger role too.
var/datum/chemical_reaction/C = selected_reaction
- if (C.FermiChem == TRUE && !continue_reacting)
+ if (C.FermiChem && !continue_reacting)
if (chem_temp > C.ExplodeTemp) //This is first to ensure explosions.
var/datum/chemical_reaction/Ferm = selected_reaction
fermiIsReacting = FALSE
@@ -472,31 +470,28 @@
Ferm.FermiExplode(src, my_atom, volume = total_volume, temp = chem_temp, pH = pH)
return 0
+ //This is just to calc the on_reaction multiplier, and is a candidate for removal.
for(var/B in cached_required_reagents)
- multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), CHEMICAL_QUANTISATION_LEVEL))
+ multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.0001))
for(var/P in selected_reaction.results)
targetVol = cached_results[P]*multiplier
- if( (chem_temp <= C.ExplodeTemp) && (chem_temp >= C.OptimalTempMin))
- if( (pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) )//To prevent pointless reactions
-
- if (fermiIsReacting == TRUE)
- return 0
- else
- START_PROCESSING(SSprocessing, src)
- selected_reaction.on_reaction(src, my_atom, multiplier)
- fermiIsReacting = TRUE
- fermiReactID = selected_reaction
- reaction_occurred = 1
-
- else //It's a little bit of a confusing nest, but esstentially we check if it's a fermireaction, then temperature, then pH. If this is true, the remainer of this handler is run.
- return 0 //If pH is out of range
+ if(!((chem_temp <= C.ExplodeTemp) && (chem_temp >= C.OptimalTempMin)))
+ return 0 //Not hot enough
+ if(! ((pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) ))//To prevent pointless reactions
+ return 0
+ if (fermiIsReacting)
+ return 0
else
- return 0 //If not hot enough
+ START_PROCESSING(SSprocessing, src)
+ selected_reaction.on_reaction(src, my_atom, multiplier)
+ fermiIsReacting = TRUE
+ fermiReactID = selected_reaction
+ reaction_occurred = 1
//Standard reaction mechanics:
else
- if (C.FermiChem == TRUE)//Just to make sure, should only proc when grenades are combining.
+ if (C.FermiChem)//Just to make sure, should only proc when grenades are combining.
if (chem_temp > C.ExplodeTemp) //To allow fermigrenades
var/datum/chemical_reaction/fermi/Ferm = selected_reaction
fermiIsReacting = FALSE
@@ -507,6 +502,7 @@
for(var/B in cached_required_reagents) //
multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), CHEMICAL_QUANTISATION_LEVEL))
+
for(var/B in cached_required_reagents)
remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1, ignore_pH = TRUE)
@@ -549,40 +545,45 @@
var/list/cached_required_reagents = C.required_reagents//update reagents list
var/list/cached_results = C.results//resultant chemical list
var/multiplier = INFINITY
-
for(var/B in cached_required_reagents) //
- multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.001))
- if (multiplier == 0)
+ multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.0001))
+ if (multiplier <= 0)//clarity
fermiEnd()
return
- for(var/P in C.required_catalysts)
- if(!has_reagent(P))
- fermiEnd()
- return
- for(var/P in cached_results)
- targetVol = cached_results[P]*multiplier
- if (fermiIsReacting == FALSE)
- CRASH("Fermi has refused to stop reacting even though we asked her nicely.")
-
- if (chem_temp > C.OptimalTempMin && fermiIsReacting == TRUE)//To prevent pointless reactions
- if( (pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) )
- if (reactedVol < targetVol)
- reactedVol = fermiReact(fermiReactID, chem_temp, pH, reactedVol, targetVol, cached_required_reagents, cached_results, multiplier)
- else//Volume is used up
+ if(C.required_catalysts)
+ for(var/P in C.required_catalysts)
+ if(!has_reagent(P))
fermiEnd()
return
- else//pH is out of range
- fermiEnd()
- return
- else//Temperature is too low, or reaction has stopped.
+
+ if (!fermiIsReacting)
+ CRASH("Fermi has refused to stop reacting even though we asked her nicely.")
+
+ if (!(chem_temp >= C.OptimalTempMin))//To prevent pointless reactions
fermiEnd()
return
+ if (!( (pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) )) //if pH is too far out, (could possibly allow reactions at this point, after the reaction has started, but make purity = 0)
+ fermiEnd()
+ return
+
+ reactedVol = fermiReact(fermiReactID, chem_temp, pH, reactedVol, targetVol, cached_required_reagents, cached_results, multiplier)
+ if(round(reactedVol, CHEMICAL_QUANTISATION_LEVEL) == round(targetVol, CHEMICAL_QUANTISATION_LEVEL))
+ fermiEnd()
+ if(!reactedVol)//Maybe unnessicary.
+ fermiEnd()
+ return
+
/datum/reagents/proc/fermiEnd()
var/datum/chemical_reaction/C = fermiReactID
STOP_PROCESSING(SSprocessing, src)
fermiIsReacting = FALSE
+ reactedVol = 0
+ targetVol = 0
+ //Cap off values
+ for(var/datum/reagent/R in reagent_list)
+ R.volume = round(R.volume, CHEMICAL_QUANTISATION_LEVEL)//To prevent runaways.
//pH check, handled at the end to reduce calls.
if(istype(my_atom, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = my_atom
@@ -593,7 +594,6 @@
handle_reactions()
update_total()
//Reaction sounds and words
- playsound(get_turf(my_atom), C.mix_sound, 80, 1)
var/list/seen = viewers(5, get_turf(my_atom))
var/iconhtml = icon2html(my_atom, seen)
for(var/mob/M in seen)
@@ -650,16 +650,18 @@
//ONLY WORKS FOR ONE PRODUCT AT THE MOMENT
//Calculate how much product to make and how much reactant to remove factors..
for(var/P in cached_results)
- //stepChemAmmount = CLAMP(((deltaT * multiplier), 0, ((targetVol - reactedVol)/cached_results[P])) //used to have multipler, now it does
stepChemAmmount = (multiplier*cached_results[P])
- if (stepChemAmmount >= C.RateUpLim)
- stepChemAmmount = (C.RateUpLim)
+ if (stepChemAmmount > C.RateUpLim)
+ stepChemAmmount = C.RateUpLim
addChemAmmount = deltaT * stepChemAmmount
if (addChemAmmount >= (targetVol - reactedVol))
addChemAmmount = (targetVol - reactedVol)
if (addChemAmmount < CHEMICAL_QUANTISATION_LEVEL)
addChemAmmount = CHEMICAL_QUANTISATION_LEVEL
removeChemAmmount = (addChemAmmount/cached_results[P])
+ //keep limited.
+ addChemAmmount = round(addChemAmmount, CHEMICAL_QUANTISATION_LEVEL)
+ removeChemAmmount = round(removeChemAmmount, CHEMICAL_QUANTISATION_LEVEL)
//This is kept for future bugtesters.
//message_admins("Reaction vars: PreReacted: [reactedVol] of [targetVol]. deltaT [deltaT], multiplier [multiplier], Step [stepChemAmmount], uncapped Step [deltaT*(multiplier*cached_results[P])], addChemAmmount [addChemAmmount], removeFactor [removeChemAmmount] Pfactor [cached_results[P]], adding [addChemAmmount]")
@@ -672,7 +674,7 @@
for(var/P in cached_results)
SSblackbox.record_feedback("tally", "chemical_reaction", addChemAmmount, P)//log
SSblackbox.record_feedback("tally", "fermi_chem", addChemAmmount, P)
- add_reagent(P, (addChemAmmount), null, cached_temp, purity)//add reagent function!! I THINK I can do this:
+ add_reagent(P, (addChemAmmount), null, cached_temp, purity)
TotalStep += addChemAmmount//for multiple products
//Above should reduce yeild based on holder purity.
//Purity Check
@@ -681,9 +683,9 @@
if (R.purity < C.PurityMin)//If purity is below the min, blow it up.
fermiIsReacting = FALSE
SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[P] explosion"))
- C.FermiExplode(src, my_atom, (reactedVol+targetVol), cached_temp, pH)
+ C.FermiExplode(src, my_atom, (total_volume), cached_temp, pH)
STOP_PROCESSING(SSprocessing, src)
- return 0
+ return
C.FermiCreate(src, addChemAmmount, purity)//proc that calls when step is done
@@ -698,11 +700,11 @@
//go to explode proc
fermiIsReacting = FALSE
SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[C] explosions"))
- C.FermiExplode(src, my_atom, (reactedVol+targetVol), chem_temp, pH)
+ C.FermiExplode(src, my_atom, (total_volume), chem_temp, pH)
STOP_PROCESSING(SSprocessing, src)
return
- //Make sure things are limited.
+ //Make sure things are limited, but superacids/bases can push forward the reaction
pH = CLAMP(pH, 0, 14)
//return said amount to compare for next step.
@@ -717,6 +719,8 @@
if (R in cached_reagents)
cachedPurity += R.purity
i++
+ if(!i)//I've never seen it get here with 0, but in case
+ CRASH("No reactants found mid reaction for [fermiReactID]/[C], how it got here is beyond me. Beaker: [holder]")
return cachedPurity/i
/datum/reagents/proc/uncache_purity(id)
@@ -758,14 +762,14 @@
total_volume = 0
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
- if(R.volume == 0)
+ if(R.volume <= 0)//For clarity
del_reagent(R.id)
if((R.volume < 0.01) && !fermiIsReacting)
del_reagent(R.id)
else
total_volume += R.volume
- if(!reagent_list)
- pH = 7
+ if(!reagent_list || !total_volume)
+ pH = REAGENT_NORMAL_PH
return 0
/datum/reagents/proc/clear_reagents()
@@ -830,7 +834,7 @@
if(!isnum(amount) || !amount)
return FALSE
- if(amount <= CHEMICAL_QUANTISATION_LEVEL)//To prevent small ammount problems.
+ if(amount < CHEMICAL_QUANTISATION_LEVEL)//To prevent small ammount problems.
return FALSE
var/datum/reagent/D = GLOB.chemical_reagents_list[reagent]
@@ -838,7 +842,7 @@
WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])")
return FALSE
- if (D.id == "water" && no_react == FALSE && !istype(my_atom, /obj/item/reagent_containers/food)) //Do like an otter, add acid to water, but also don't blow up botany.
+ if (D.id == "water" && !no_react && !istype(my_atom, /obj/item/reagent_containers/food)) //Do like an otter, add acid to water, but also don't blow up botany.
if (pH <= 2)
SSblackbox.record_feedback("tally", "fermi_chem", 1, "water-acid explosions")
var/datum/effect_system/smoke_spread/chem/s = new
@@ -864,7 +868,6 @@
var/new_total = cached_total + amount
var/cached_temp = chem_temp
var/list/cached_reagents = reagent_list
-
var/cached_pH = pH
@@ -881,7 +884,7 @@
chem_temp = thermal_energy / (specific_heat * new_total)
//cacluate reagent based pH shift.
- if(ignore_pH == TRUE)
+ if(ignore_pH)
pH = ((cached_pH * cached_total)+(other_pH * amount))/(cached_total + amount)//should be right
else
pH = ((cached_pH * cached_total)+(D.pH * amount))/(cached_total + amount)//should be right
@@ -958,9 +961,9 @@
var/datum/reagent/R = A
if (R.id == reagent)
if((total_volume - amount) <= 0)//Because this can result in 0, I don't want it to crash.
- pH = 7
+ pH = REAGENT_NORMAL_PH
//In practice this is really confusing and players feel like it randomly melts their beakers, but I'm not sure how else to handle it. We'll see how it goes and I can remove this if it confuses people.
- else if (ignore_pH == FALSE)
+ else if (!ignore_pH)
//if (((pH > R.pH) && (pH <= 7)) || ((pH < R.pH) && (pH >= 7)))
pH = (((pH - R.pH) / total_volume) * amount) + pH
if(istype(my_atom, /obj/item/reagent_containers/))
diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm
index e1c9bcd44f..6efa4276b6 100644
--- a/code/modules/reagents/chemistry/machinery/pandemic.dm
+++ b/code/modules/reagents/chemistry/machinery/pandemic.dm
@@ -244,9 +244,9 @@
/obj/machinery/computer/pandemic/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
if(beaker)
- beaker.forceMove(drop_location())
if(user && Adjacent(user) && !issiliconoradminghost(user))
- user.put_in_hands(beaker)
+ if(!user.put_in_hands(beaker))
+ beaker.forceMove(drop_location())
if(new_beaker)
beaker = new_beaker
else
diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents.dm
index e24b811131..c96347cda2 100644
--- a/code/modules/reagents/chemistry/reagents/impure_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/impure_reagents.dm
@@ -9,7 +9,7 @@
/datum/reagent/impure/fermiTox
name = "Chemical Isomers"
id = "fermiTox"
- description = "Toxic chemical isomers made from impure reactions. At low volumes will cause light toxin damage, but as the volume increases, it deals larger amounts, damages the liver, then eventually the heart."
+ description = "Toxic chemical isomers made from impure reactions. At low volumes will cause light toxin damage, but as the volume increases, it deals larger amounts, damages the liver, then eventually the heart. This is default impure chem for all chems, and changes only if stated."
data = "merge"
color = "FFFFFF"
can_synth = FALSE
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 6b5e6d94bd..95b4a33c0d 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -3,6 +3,7 @@
name = "Blood"
id = "blood"
color = "#C80000" // rgb: 200, 0, 0
+ description = "Blood from a human, or otherwise."
metabolization_rate = 5 //fast rate so it disappears fast.
taste_description = "iron"
taste_mult = 1.3
diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm
index 11dd8b7475..2ed9a31107 100644
--- a/code/modules/reagents/chemistry/recipes/medicine.dm
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -71,8 +71,8 @@
/datum/chemical_reaction/synthtissue
name = "Synthtissue"
id = "synthtissue"
- results = list("synthtissue" = 0.05)
- required_reagents = list("synthflesh" = 0.01)
+ results = list("synthtissue" = 5)
+ required_reagents = list("synthflesh" = 1)
required_catalysts = list("nutriment" = 0.1)
//FermiChem vars:
OptimalTempMin = 305 // Lower area of bell curve for determining heat based rate reactions
@@ -101,8 +101,10 @@
if(St.purity < 1)
St.volume *= St.purity
St.purity = 1
- N.volume -= 0.002
+ var/amount = CLAMP(0.002, 0, N.volume)
+ N.volume -= amount
St.data["grown_volume"] = St.data["grown_volume"] + added_volume
+ St.name = "[initial(St.name)] [round(St.data["grown_volume"], 0.1)]u colony"
/datum/chemical_reaction/styptic_powder
name = "Styptic Powder"
diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm
index 249ed56d20..afe48ab3fb 100644
--- a/code/modules/reagents/reagent_containers/bottle.dm
+++ b/code/modules/reagents/reagent_containers/bottle.dm
@@ -404,3 +404,25 @@
/obj/item/reagent_containers/glass/bottle/bromine
name = "bromine bottle"
list_reagents = list("bromine" = 30)
+
+//Lewd Stuff
+
+/obj/item/reagent_containers/glass/bottle/crocin
+ name = "Crocin bottle"
+ desc = "A bottle of mild aphrodisiac. Increases libido."
+ list_reagents = list("aphro" = 30)
+
+/obj/item/reagent_containers/glass/bottle/hexacrocin
+ name = "Hexacrocin bottle"
+ desc = "A bottle of strong aphrodisiac. Increases libido."
+ list_reagents = list("aphro+" = 30)
+
+/obj/item/reagent_containers/glass/bottle/camphor
+ name = "Camphor bottle"
+ desc = "A bottle of mild anaphrodisiac. Reduces libido."
+ list_reagents = list("anaphro" = 30)
+
+/obj/item/reagent_containers/glass/bottle/hexacamphor
+ name = "Hexacamphor bottle"
+ desc = "A bottle of strong anaphrodisiac. Reduces libido."
+ list_reagents = list("anaphro+" = 30)
\ No newline at end of file
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index d4f13f6a2e..ae01b75dd9 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -601,63 +601,34 @@
/datum/design/retractor_adv
name = "Advanced Retractor"
- desc = "A high-class, premium retractor, featuring precision crafted, silver-plated hook-ends and an electrum handle."
+ desc = "An almagation of rods and gears, able to function as both a surgical clamp and retractor. "
id = "retractor_adv"
build_type = PROTOLATHE
materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1500, MAT_GOLD = 1000)
- build_path = /obj/item/retractor/adv
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
-
-/datum/design/hemostat_adv
- name = "Advanced Hemostat"
- desc = "An exceptionally fine pair of arterial forceps. These appear to be plated in electrum and feel soft to the touch."
- id = "hemostat_adv"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1000, MAT_GOLD = 1500)
- build_path = /obj/item/hemostat/adv
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
-
-/datum/design/cautery_adv
- name = "Electrocautery" //This is based on real-life science.
- desc = "A high-tech unipolar Electrocauter. This tiny device contains an extremely powerful microbattery that uses arcs of electricity to painlessly sear wounds shut. It seems to recharge with the user's body-heat. Wow!"
- id = "cautery_adv"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1000, MAT_GOLD = 1500)
- build_path = /obj/item/cautery/adv
+ build_path = /obj/item/retractor/advanced
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/surgicaldrill_adv
- name = "Surgical Autodrill"
- desc = "With a diamond tip and built-in depth and safety sensors, this drill alerts the user before overpenetrating a patient's skull or tooth. There also appears to be a disable switch."
+ name = "Surgical Laser Drill"
+ desc = "It projects a high power laser used for medical applications."
id = "surgicaldrill_adv"
build_type = PROTOLATHE
materials = list(MAT_METAL = 2500, MAT_GLASS = 2500, MAT_SILVER = 6000, MAT_GOLD = 5500, MAT_DIAMOND = 3500)
- build_path = /obj/item/surgicaldrill/adv
+ build_path = /obj/item/surgicaldrill/advanced
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/scalpel_adv
- name = "Precision Scalpel"
- desc = "A perfectly balanced electrum scalpel with a silicon-coated edge to eliminate wear and tear."
+ name = "Laser Scalpel"
+ desc = "An advanced scalpel which uses laser technology to cut."
id = "scalpel_adv"
build_type = PROTOLATHE
materials = list(MAT_METAL = 1500, MAT_GLASS = 1500, MAT_SILVER = 4000, MAT_GOLD = 2500)
- build_path = /obj/item/scalpel/adv
+ build_path = /obj/item/scalpel/advanced
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
-/datum/design/circular_saw_adv
- name = "Diamond-Grit Circular Saw"
- desc = "For those Assistants with REALLY thick skulls."
- id = "circular_saw_adv"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 7500, MAT_GLASS = 6000, MAT_SILVER = 6500, MAT_GOLD = 7500, MAT_DIAMOND = 4500)
- build_path = /obj/item/circular_saw/adv
- category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/////////////////////////////////////////
//////////Alien Surgery Tools////////////
@@ -756,7 +727,7 @@
research_icon = 'icons/obj/surgery.dmi'
research_icon_state = "surgery_any"
var/surgery
-
+
/datum/design/surgery/experimental_dissection
name = "Experimental Dissection"
desc = "A surgical procedure which deeply analyzes the biology of a corpse, and automatically adds new findings to the research database."
diff --git a/code/modules/research/nanites/nanite_programs/healing.dm b/code/modules/research/nanites/nanite_programs/healing.dm
index 66a5344d6c..1113f11e87 100644
--- a/code/modules/research/nanites/nanite_programs/healing.dm
+++ b/code/modules/research/nanites/nanite_programs/healing.dm
@@ -72,8 +72,10 @@
/datum/nanite_program/brain_heal/check_conditions()
if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob
- if(length(C.get_traumas()))
- return ..()
+ for(var/X in C.get_traumas())
+ var/datum/brain_trauma/BT = X
+ if(BT.resilience <= TRAUMA_RESILIENCE_BASIC)
+ return ..()
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN))
return ..()
return FALSE
@@ -193,8 +195,10 @@
/datum/nanite_program/brain_heal_advanced/check_conditions()
if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob
- if(length(C.get_traumas()))
- return ..()
+ for(var/X in C.get_traumas())
+ var/datum/brain_trauma/BT = X
+ if(BT.resilience <= TRAUMA_RESILIENCE_LOBOTOMY)
+ return ..()
if(host_mob.getOrganLoss(ORGAN_SLOT_BRAIN))
return ..()
return FALSE
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 590a1d787b..477bfbe1a1 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -96,7 +96,7 @@
display_name = "Advanced Surgery Tools"
description = "Refined and improved redesigns for the run-of-the-mill medical utensils."
prereq_ids = list("adv_biotech", "adv_surgery")
- design_ids = list("drapes", "retractor_adv", "hemostat_adv", "cautery_adv", "surgicaldrill_adv", "scalpel_adv", "circular_saw_adv")
+ design_ids = list("drapes", "retractor_adv", "surgicaldrill_adv", "scalpel_adv")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
diff --git a/code/modules/surgery/advanced/bioware/experimental_dissection.dm b/code/modules/surgery/advanced/bioware/experimental_dissection.dm
index 6266480baf..5dac3e744d 100644
--- a/code/modules/surgery/advanced/bioware/experimental_dissection.dm
+++ b/code/modules/surgery/advanced/bioware/experimental_dissection.dm
@@ -20,7 +20,7 @@
/datum/surgery_step/dissection
name = "dissection"
- implements = list(/obj/item/scalpel = 60, /obj/item/kitchen/knife = 30, /obj/item/shard = 15)
+ implements = list(TOOL_SCALPEL = 60, /obj/item/kitchen/knife = 30, /obj/item/shard = 15)
time = 125
/datum/surgery_step/dissection/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/advanced/brainwashing.dm b/code/modules/surgery/advanced/brainwashing.dm
index 68deca4729..28d2f8fe28 100644
--- a/code/modules/surgery/advanced/brainwashing.dm
+++ b/code/modules/surgery/advanced/brainwashing.dm
@@ -12,7 +12,7 @@
/datum/surgery_step/clamp_bleeders,
/datum/surgery_step/brainwash,
/datum/surgery_step/close)
-
+
species = list(/mob/living/carbon/human)
possible_locs = list(BODY_ZONE_HEAD)
/datum/surgery/advanced/brainwashing/can_start(mob/user, mob/living/carbon/target)
@@ -24,7 +24,7 @@
return TRUE
/datum/surgery_step/brainwash
name = "brainwash"
- implements = list(/obj/item/hemostat = 85, TOOL_WIRECUTTER = 50, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15)
+ implements = list(TOOL_HEMOSTAT = 85, TOOL_WIRECUTTER = 50, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15)
time = 200
var/objective
/datum/surgery_step/brainwash/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/advanced/lobotomy.dm b/code/modules/surgery/advanced/lobotomy.dm
index 12c5e4dab2..c8c699bfbd 100644
--- a/code/modules/surgery/advanced/lobotomy.dm
+++ b/code/modules/surgery/advanced/lobotomy.dm
@@ -21,7 +21,7 @@
return TRUE
/datum/surgery_step/lobotomize
name = "perform lobotomy"
- implements = list(/obj/item/scalpel = 85, /obj/item/melee/transforming/energy/sword = 55, /obj/item/kitchen/knife = 35,
+ implements = list(TOOL_SCALPEL = 85, /obj/item/melee/transforming/energy/sword = 55, /obj/item/kitchen/knife = 35,
/obj/item/shard = 25, /obj/item = 20)
time = 100
/datum/surgery_step/lobotomize/tool_check(mob/user, obj/item/tool)
diff --git a/code/modules/surgery/advanced/necrotic_revival.dm b/code/modules/surgery/advanced/necrotic_revival.dm
index 8c57930252..f8fb160a8a 100644
--- a/code/modules/surgery/advanced/necrotic_revival.dm
+++ b/code/modules/surgery/advanced/necrotic_revival.dm
@@ -16,7 +16,7 @@
/datum/surgery_step/bionecrosis
name = "start bionecrosis"
- implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30)
time = 50
chems_needed = list("zombiepowder", "rezadone")
diff --git a/code/modules/surgery/advanced/pacification.dm b/code/modules/surgery/advanced/pacification.dm
index d5585d71a8..8a236709a4 100644
--- a/code/modules/surgery/advanced/pacification.dm
+++ b/code/modules/surgery/advanced/pacification.dm
@@ -17,7 +17,7 @@
return FALSE
/datum/surgery_step/pacify
name = "rewire brain"
- implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
time = 40
/datum/surgery_step/pacify/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -37,4 +37,4 @@
"[user] screws up, causing brain damage!",
"[user] completes the surgery on [target]'s brain.")
target.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY)
- return FALSE
+ return FALSE
diff --git a/code/modules/surgery/advanced/reconstruction.dm b/code/modules/surgery/advanced/reconstruction.dm
index 84d9f5b9f8..b5369838d4 100644
--- a/code/modules/surgery/advanced/reconstruction.dm
+++ b/code/modules/surgery/advanced/reconstruction.dm
@@ -17,7 +17,7 @@
/datum/surgery_step/reconstruct
name = "repair body"
- implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
repeatable = TRUE
time = 25
diff --git a/code/modules/surgery/advanced/toxichealing.dm b/code/modules/surgery/advanced/toxichealing.dm
index a82287831c..998ca47b45 100644
--- a/code/modules/surgery/advanced/toxichealing.dm
+++ b/code/modules/surgery/advanced/toxichealing.dm
@@ -1,6 +1,6 @@
/datum/surgery/advanced/toxichealing
name = "Body Rejuvenation"
- desc = "A surgical procedure that helps deal with oxygen deprecation, and treat toxic damaged. Works on corpses and alive alike without chemicals."
+ desc = "A surgical procedure that helps deal with oxygen deprivation, and treats parts damaged due to toxic compounds. Works on corpses and alive alike without chemicals."
steps = list(/datum/surgery_step/incise,
/datum/surgery_step/incise,
/datum/surgery_step/retract_skin,
@@ -17,7 +17,7 @@
/datum/surgery_step/toxichealing
name = "rejuvenate body"
- implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
repeatable = TRUE
time = 25
diff --git a/code/modules/surgery/advanced/viral_bonding.dm b/code/modules/surgery/advanced/viral_bonding.dm
index b87d5e001c..bdfd0e1552 100644
--- a/code/modules/surgery/advanced/viral_bonding.dm
+++ b/code/modules/surgery/advanced/viral_bonding.dm
@@ -17,7 +17,7 @@
return TRUE
/datum/surgery_step/viral_bond
name = "viral bond"
- implements = list(/obj/item/cautery = 100, TOOL_WELDER = 50, /obj/item = 30) // 30% success with any hot item.
+ implements = list(TOOL_CAUTERY = 100, TOOL_WELDER = 50, /obj/item = 30) // 30% success with any hot item.
time = 100
chems_needed = list("spaceacillin","virusfood","formaldehyde")
diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm
index 01cf6ae112..59493872e2 100644
--- a/code/modules/surgery/amputation.dm
+++ b/code/modules/surgery/amputation.dm
@@ -6,7 +6,7 @@
requires_bodypart_type = 0
/datum/surgery_step/sever_limb
name = "sever limb"
- implements = list(/obj/item/scalpel = 100, /obj/item/circular_saw = 100, /obj/item/melee/transforming/energy/sword/cyborg/saw = 100, /obj/item/melee/arm_blade = 80, /obj/item/twohanded/required/chainsaw = 80, /obj/item/mounted_chainsaw = 80, /obj/item/twohanded/fireaxe = 50, /obj/item/hatchet = 40, /obj/item/kitchen/knife/butcher = 25)
+ implements = list(TOOL_SCALPEL = 100, TOOL_SAW = 100, /obj/item/melee/transforming/energy/sword/cyborg/saw = 100, /obj/item/melee/arm_blade = 80, /obj/item/twohanded/required/chainsaw = 80, /obj/item/mounted_chainsaw = 80, /obj/item/twohanded/fireaxe = 50, /obj/item/hatchet = 40, /obj/item/kitchen/knife/butcher = 25)
time = 64
/datum/surgery_step/sever_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index 46ee10a3fd..23d49e98bb 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -32,6 +32,8 @@
var/lip_style = null
var/lip_color = "white"
+ //If the head is a special sprite
+ var/custom_head
/obj/item/bodypart/head/can_dismember(obj/item/I)
if(!((owner.stat == DEAD) || owner.InFullCritical()))
@@ -128,6 +130,8 @@
add_overlay(standing)
/obj/item/bodypart/head/get_limb_icon(dropped)
+ if(custom_head)
+ return
cut_overlays()
. = ..()
if(dropped) //certain overlays only appear when the limb is being detached from its owner.
diff --git a/code/modules/surgery/brain_surgery.dm b/code/modules/surgery/brain_surgery.dm
index c553d05448..63a5f8c728 100644
--- a/code/modules/surgery/brain_surgery.dm
+++ b/code/modules/surgery/brain_surgery.dm
@@ -12,7 +12,7 @@
requires_bodypart_type = 0
/datum/surgery_step/fix_brain
name = "fix brain"
- implements = list(/obj/item/hemostat = 85, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) //don't worry, pouring some alcohol on their open brain will get that chance to 100
+ implements = list(TOOL_HEMOSTAT = 85, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) //don't worry, pouring some alcohol on their open brain will get that chance to 100
time = 120 //long and complicated
/datum/surgery/brain_surgery/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN)
diff --git a/code/modules/surgery/core_removal.dm b/code/modules/surgery/core_removal.dm
index 6243405f8d..1ded00da2b 100644
--- a/code/modules/surgery/core_removal.dm
+++ b/code/modules/surgery/core_removal.dm
@@ -11,7 +11,7 @@
//extract brain
/datum/surgery_step/extract_core
name = "extract core"
- implements = list(/obj/item/hemostat = 100, TOOL_CROWBAR = 100)
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_CROWBAR = 100)
time = 16
/datum/surgery_step/extract_core/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm
index 3e36e9aa9b..c620b83d1f 100644
--- a/code/modules/surgery/coronary_bypass.dm
+++ b/code/modules/surgery/coronary_bypass.dm
@@ -15,7 +15,7 @@
//an incision but with greater bleed, and a 90% base success chance
/datum/surgery_step/incise_heart
name = "incise heart"
- implements = list(/obj/item/scalpel = 90, /obj/item/melee/transforming/energy/sword = 45, /obj/item/kitchen/knife = 45,
+ implements = list(TOOL_SCALPEL = 90, /obj/item/melee/transforming/energy/sword = 45, /obj/item/kitchen/knife = 45,
/obj/item/shard = 25)
time = 16
@@ -74,4 +74,4 @@
"[user] screws up, causing blood to spurt out of [H]'s chest profusely!")
H.adjustOrganLoss(ORGAN_SLOT_HEART, 20)
H.bleed_rate += 30
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/surgery/embalming.dm b/code/modules/surgery/embalming.dm
index f74d864245..e1053374c7 100644
--- a/code/modules/surgery/embalming.dm
+++ b/code/modules/surgery/embalming.dm
@@ -1,6 +1,6 @@
/datum/surgery/embalming //Fast and easy way to husk bodys
name = "Embalming"
- desc = "A surgical procedure that prevents a corps from producing."
+ desc = "A surgical procedure that prevents a corpse from producing miasma."
steps = list(/datum/surgery_step/incise,
/datum/surgery_step/embalming,
/datum/surgery_step/close)
@@ -11,8 +11,7 @@
/datum/surgery_step/embalming
name = "embalming body"
- implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
- implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30)
+ implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30)
time = 10
chems_needed = list("drying_agent", "sterilizine")
require_all_chems = FALSE
@@ -28,4 +27,4 @@
/datum/surgery_step/embalming/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] screws up!", "You screwed up!")
ADD_TRAIT(target, TRAIT_NOCLONE, MAGIC_TRAIT) //That body is ruined, but still gives miasma
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/surgery/eye_surgery.dm b/code/modules/surgery/eye_surgery.dm
index 29385ef20b..3e0c9c4ec3 100644
--- a/code/modules/surgery/eye_surgery.dm
+++ b/code/modules/surgery/eye_surgery.dm
@@ -7,7 +7,7 @@
//fix eyes
/datum/surgery_step/fix_eyes
name = "fix eyes"
- implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 45, /obj/item/pen = 25)
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 45, /obj/item/pen = 25)
time = 64
/datum/surgery/eye_surgery/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/eyes/E = target.getorganslot(ORGAN_SLOT_EYES)
diff --git a/code/modules/surgery/graft_synthtissue.dm b/code/modules/surgery/graft_synthtissue.dm
index 8826de7171..d9b03ca47f 100644
--- a/code/modules/surgery/graft_synthtissue.dm
+++ b/code/modules/surgery/graft_synthtissue.dm
@@ -19,7 +19,7 @@
//repair organs
/datum/surgery_step/graft_synthtissue
name = "graft synthtissue"
- implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
repeatable = TRUE
time = 75
chems_needed = list("synthtissue")
@@ -61,8 +61,9 @@
target.reagents.remove_reagent("synthtissue", 10)
/datum/surgery_step/graft_synthtissue/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] successfully repairs part of [chosen_organ].", "You succeed in repairing parts of [chosen_organ].")
- chosen_organ.applyOrganDamage(health_restored)
+ user.visible_message("[user] successfully grafts synthtissue to [chosen_organ].", "You succeed in grafting 10u of the synthflesh to the [chosen_organ].")
+ chosen_organ.applyOrganDamage(-health_restored)
+ return TRUE
/datum/surgery_step/graft_synthtissue/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] accidentally damages part of [chosen_organ]!", "You damage [chosen_organ]! Apply more synthtissue if it's run out.")
diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm
index 05119b365d..c7597b6858 100644
--- a/code/modules/surgery/implant_removal.dm
+++ b/code/modules/surgery/implant_removal.dm
@@ -6,7 +6,7 @@
//extract implant
/datum/surgery_step/extract_implant
name = "extract implant"
- implements = list(/obj/item/hemostat = 100, TOOL_CROWBAR = 65)
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_CROWBAR = 65)
time = 64
var/obj/item/implant/I = null
/datum/surgery_step/extract_implant/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm
index 7ba8dbc49d..e704485da4 100644
--- a/code/modules/surgery/limb_augmentation.dm
+++ b/code/modules/surgery/limb_augmentation.dm
@@ -2,7 +2,7 @@
//SURGERY STEPS
/datum/surgery_step/replace
name = "sever muscles"
- implements = list(/obj/item/scalpel = 100, TOOL_WIRECUTTER = 55)
+ implements = list(TOOL_SCALPEL = 100, TOOL_WIRECUTTER = 55)
time = 32
diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm
index bb297b4604..b28b439f9f 100644
--- a/code/modules/surgery/lipoplasty.dm
+++ b/code/modules/surgery/lipoplasty.dm
@@ -9,7 +9,7 @@
//cut fat
/datum/surgery_step/cut_fat
name = "cut excess fat"
- implements = list(/obj/item/circular_saw = 100, /obj/item/melee/transforming/energy/sword/cyborg/saw = 100, /obj/item/hatchet = 35, /obj/item/kitchen/knife/butcher = 25)
+ implements = list(TOOL_SAW = 100, /obj/item/hatchet = 35, /obj/item/kitchen/knife/butcher = 25) //why we need a saw to cut adipose tissue is beyond me, shit's soft as fuck
time = 64
/datum/surgery_step/cut_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -26,7 +26,7 @@
//remove fat
/datum/surgery_step/remove_fat
name = "remove loose fat"
- implements = list(/obj/item/retractor = 100, TOOL_SCREWDRIVER = 45, TOOL_WIRECUTTER = 35)
+ implements = list(TOOL_RETRACTOR = 100, TOOL_SCREWDRIVER = 45, TOOL_WIRECUTTER = 35)
time = 32
/datum/surgery_step/remove_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/mechanic_steps.dm b/code/modules/surgery/mechanic_steps.dm
index 7d364d9ecf..23f9c167a0 100644
--- a/code/modules/surgery/mechanic_steps.dm
+++ b/code/modules/surgery/mechanic_steps.dm
@@ -3,7 +3,7 @@
name = "unscrew shell"
implements = list(
TOOL_SCREWDRIVER = 100,
- /obj/item/scalpel = 75, // med borgs could try to unskrew shell with scalpel
+ TOOL_SCALPEL = 75, // med borgs could try to unskrew shell with scalpel
/obj/item/kitchen/knife = 50,
/obj/item = 10) // 10% success with any sharp item.
time = 24
@@ -22,7 +22,7 @@
name = "screw shell"
implements = list(
TOOL_SCREWDRIVER = 100,
- /obj/item/scalpel = 75,
+ TOOL_SCALPELl = 75,
/obj/item/kitchen/knife = 50,
/obj/item = 10) // 10% success with any sharp item.
time = 24
@@ -41,7 +41,7 @@
name = "prepare electronics"
implements = list(
TOOL_MULTITOOL = 100,
- /obj/item/hemostat = 10) // try to reboot internal controllers via short circuit with some conductor
+ TOOL_HEMOSTAT = 10) // try to reboot internal controllers via short circuit with some conductor
time = 24
/datum/surgery_step/prepare_electronics/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -54,7 +54,7 @@
name = "unwrench bolts"
implements = list(
TOOL_WRENCH = 100,
- /obj/item/retractor = 10)
+ TOOL_RETRACTOR = 10)
time = 24
/datum/surgery_step/mechanic_unwrench/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -67,7 +67,7 @@
name = "wrench bolts"
implements = list(
TOOL_WRENCH = 100,
- /obj/item/retractor = 10)
+ TOOL_RETRACTOR = 10)
time = 24
/datum/surgery_step/mechanic_wrench/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -84,4 +84,4 @@
/datum/surgery_step/open_hatch/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
display_results(user, target, "You begin to open the hatch holders in [target]'s [parse_zone(target_zone)]...",
"[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].",
- "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].")
+ "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].")
diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm
index 6bffed7452..42c049edd2 100644
--- a/code/modules/surgery/organ_manipulation.dm
+++ b/code/modules/surgery/organ_manipulation.dm
@@ -62,7 +62,7 @@
name = "manipulate organs"
repeatable = 1
implements = list(/obj/item/organ = 100, /obj/item/reagent_containers/food/snacks/organ = 0, /obj/item/organ_storage = 100)
- var/implements_extract = list(/obj/item/hemostat = 100, TOOL_CROWBAR = 55)
+ var/implements_extract = list(TOOL_HEMOSTAT = 100, TOOL_CROWBAR = 55)
var/current_type
var/obj/item/organ/I = null
/datum/surgery_step/manipulate_organs/New()
diff --git a/code/modules/surgery/organic_steps.dm b/code/modules/surgery/organic_steps.dm
index da03771a27..459a540f26 100644
--- a/code/modules/surgery/organic_steps.dm
+++ b/code/modules/surgery/organic_steps.dm
@@ -1,7 +1,7 @@
//make incision
/datum/surgery_step/incise
name = "make incision"
- implements = list(/obj/item/scalpel = 100, /obj/item/melee/transforming/energy/sword = 75, /obj/item/kitchen/knife = 65,
+ implements = list(TOOL_SCALPEL = 100, /obj/item/melee/transforming/energy/sword = 75, /obj/item/kitchen/knife = 65,
/obj/item/shard = 45, /obj/item = 30) // 30% success with any sharp item.
time = 16
@@ -27,7 +27,7 @@
//clamp bleeders
/datum/surgery_step/clamp_bleeders
name = "clamp bleeders"
- implements = list(/obj/item/hemostat = 100, TOOL_WIRECUTTER = 60, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15)
+ implements = list(TOOL_HEMOSTAT = 100, TOOL_WIRECUTTER = 60, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15)
time = 24
/datum/surgery_step/clamp_bleeders/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -45,7 +45,7 @@
//retract skin
/datum/surgery_step/retract_skin
name = "retract skin"
- implements = list(/obj/item/retractor = 100, TOOL_SCREWDRIVER = 45, TOOL_WIRECUTTER = 35)
+ implements = list(TOOL_RETRACTOR = 100, TOOL_SCREWDRIVER = 45, TOOL_WIRECUTTER = 35)
time = 24
/datum/surgery_step/retract_skin/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -58,7 +58,7 @@
//close incision
/datum/surgery_step/close
name = "mend incision"
- implements = list(/obj/item/cautery = 100, /obj/item/gun/energy/laser = 90, TOOL_WELDER = 70,
+ implements = list(TOOL_CAUTERY = 100, /obj/item/gun/energy/laser = 90, TOOL_WELDER = 70,
/obj/item = 30) // 30% success with any hot item.
time = 24
@@ -81,9 +81,7 @@
//saw bone
/datum/surgery_step/saw
name = "saw bone"
- implements = list(/obj/item/circular_saw = 100, /obj/item/melee/transforming/energy/sword/cyborg/saw = 100,
- /obj/item/melee/arm_blade = 75, /obj/item/mounted_chainsaw = 65, /obj/item/twohanded/required/chainsaw = 50,
- /obj/item/twohanded/fireaxe = 50, /obj/item/hatchet = 35, /obj/item/kitchen/knife/butcher = 25)
+ implements = list(TOOL_SAW = 100, /obj/item/melee/arm_blade = 75, /obj/item/twohanded/fireaxe = 50, /obj/item/hatchet = 35, /obj/item/kitchen/knife/butcher = 25)
time = 54
/datum/surgery_step/saw/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -101,7 +99,7 @@
//drill bone
/datum/surgery_step/drill
name = "drill bone"
- implements = list(/obj/item/surgicaldrill = 100, /obj/item/screwdriver/power = 80, /obj/item/pickaxe/drill = 60, /obj/item/mecha_parts/mecha_equipment/drill = 60, TOOL_SCREWDRIVER = 20)
+ implements = list(TOOL_DRILL = 100, /obj/item/screwdriver/power = 80, /obj/item/pickaxe/drill = 60, TOOL_SCREWDRIVER = 20)
time = 30
/datum/surgery_step/drill/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/organs/autosurgeon.dm b/code/modules/surgery/organs/autosurgeon.dm
index 2cc5c554c6..27bf575627 100644
--- a/code/modules/surgery/organs/autosurgeon.dm
+++ b/code/modules/surgery/organs/autosurgeon.dm
@@ -17,9 +17,10 @@
if(starting_organ)
insert_organ(new starting_organ(src))
-/obj/item/autosurgeon/proc/insert_organ(var/obj/item/I)
+/obj/item/autosurgeon/proc/insert_organ(var/obj/item/organ/I)
storedorgan = I
I.forceMove(src)
+ I.organ_flags |= ORGAN_FROZEN //Stops decay
name = "[initial(name)] ([storedorgan.name])"
/obj/item/autosurgeon/attack_self(mob/user)//when the object it used...
@@ -125,4 +126,4 @@
/obj/item/autosurgeon/womb
desc = "A single use autosurgeon that contains a womb. A screwdriver can be used to remove it, but implants can't be placed back in."
uses = 1
- starting_organ = /obj/item/organ/genital/womb
\ No newline at end of file
+ starting_organ = /obj/item/organ/genital/womb
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index cb890082cd..95258c709a 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -117,6 +117,7 @@
/obj/item/organ/eyes/night_vision/zombie
name = "undead eyes"
desc = "Somewhat counterintuitively, these half-rotten eyes actually have superior vision to those of a living human."
+ sight_flags = SEE_MOBS
/obj/item/organ/eyes/night_vision/nightmare
name = "burning red eyes"
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index 5fea801ba0..8e4caab436 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -6,7 +6,7 @@
slot = ORGAN_SLOT_HEART
healing_factor = STANDARD_ORGAN_HEALING
- decay_factor = 4 * STANDARD_ORGAN_DECAY //designed to fail about 5 minutes after death
+ decay_factor = 3 * STANDARD_ORGAN_DECAY //designed to fail about 5 minutes after death
low_threshold_passed = "Prickles of pain appear then die out from within your chest..."
high_threshold_passed = "Something inside your chest hurts, and the pain isn't subsiding. You notice yourself breathing far faster than before."
@@ -61,6 +61,7 @@
return S
/obj/item/organ/heart/on_life()
+ ..()
if(owner.client && beating)
failed = FALSE
var/sound/slowbeat = sound('sound/health/slowbeat.ogg', repeat = TRUE)
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index f3eaba1a1b..6b0e4f01ae 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -12,10 +12,12 @@
var/operated = FALSE //whether we can still have our damages fixed through surgery
//health
- maxHealth = LUNGS_MAX_HEALTH
+ maxHealth = 3 * STANDARD_ORGAN_THRESHOLD
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = STANDARD_ORGAN_DECAY
+ high_threshold = 0.6 * LUNGS_MAX_HEALTH //threshold at 180
+ low_threshold = 0.3 * LUNGS_MAX_HEALTH //threshold at 90
high_threshold_passed = "You feel some sort of constriction around your chest as your breathing becomes shallow and rapid."
now_fixed = "Your lungs seem to once again be able to hold air."
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index a17d4906bf..593614372a 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -41,6 +41,9 @@
else
qdel(replaced)
+ //Hopefully this doesn't cause problems
+ organ_flags &= ~ORGAN_FROZEN
+
owner = M
M.internal_organs |= src
M.internal_organs_slot[slot] = src
@@ -64,30 +67,88 @@
A.Remove(M)
START_PROCESSING(SSobj, src)
-
/obj/item/organ/proc/on_find(mob/living/finder)
return
-/obj/item/organ/process()
+/obj/item/organ/process() //runs decay when outside of a person AND ONLY WHEN OUTSIDE (i.e. long obj).
on_death() //Kinda hate doing it like this, but I really don't want to call process directly.
-/obj/item/organ/proc/on_death() //runs decay when outside of a person
- if(organ_flags & (ORGAN_SYNTHETIC | ORGAN_FROZEN | ORGAN_NO_SPOIL))
+//Sources; life.dm process_organs
+/obj/item/organ/proc/on_death() //Runs when outside AND inside.
+ decay()
+
+//Applys the slow damage over time decay
+/obj/item/organ/proc/decay()
+ if(!can_decay())
+ STOP_PROCESSING(SSobj, src)
+ return
+ is_cold()
+ if(organ_flags & ORGAN_FROZEN)
return
applyOrganDamage(maxHealth * decay_factor)
+/obj/item/organ/proc/can_decay()
+ if(CHECK_BITFIELD(organ_flags, ORGAN_NO_SPOIL | ORGAN_SYNTHETIC | ORGAN_FAILING))
+ return FALSE
+ return TRUE
+
+//Checks to see if the organ is frozen from temperature
+/obj/item/organ/proc/is_cold()
+ var/freezing_objects = list(/obj/structure/closet/crate/freezer, /obj/structure/closet/secure_closet/freezer, /obj/structure/bodycontainer, /obj/item/autosurgeon)
+ if(istype(loc, /obj/))//Freezer of some kind, I hope.
+ if(is_type_in_list(loc, freezing_objects))
+ if(!(organ_flags & ORGAN_FROZEN))//Incase someone puts them in when cold, but they warm up inside of the thing. (i.e. they have the flag, the thing turns it off, this rights it.)
+ organ_flags |= ORGAN_FROZEN
+ return TRUE
+ return
+
+ var/local_temp
+ if(istype(loc, /turf/))//Only concern is adding an organ to a freezer when the area around it is cold.
+ var/turf/T = loc
+ var/datum/gas_mixture/enviro = T.return_air()
+ local_temp = enviro.temperature
+
+ else if(istype(loc, /mob/) && !owner)
+ var/mob/M = loc
+ if(is_type_in_list(M.loc, freezing_objects))
+ if(!(organ_flags & ORGAN_FROZEN))
+ organ_flags |= ORGAN_FROZEN
+ return TRUE
+ var/turf/T = M.loc
+ var/datum/gas_mixture/enviro = T.return_air()
+ local_temp = enviro.temperature
+
+ if(owner)
+ //Don't interfere with bodies frozen by structures.
+ if(is_type_in_list(owner.loc, freezing_objects))
+ if(!(organ_flags & ORGAN_FROZEN))
+ organ_flags |= ORGAN_FROZEN
+ return TRUE
+ local_temp = owner.bodytemperature
+
+ if(!local_temp)//Shouldn't happen but in case
+ return
+ if(local_temp < 154)//I have a pretty shaky citation that states -120 allows indefinite cyrostorage
+ organ_flags |= ORGAN_FROZEN
+ return TRUE
+ organ_flags &= ~ORGAN_FROZEN
+ return FALSE
+
/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing
- if(!(organ_flags & ORGAN_FAILING))
- ///Damage decrements by a percent of its maxhealth
- var/healing_amount = -(maxHealth * healing_factor)
- ///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's health
- healing_amount -= owner.satiety > 0 ? 4 * healing_factor * owner.satiety / MAX_SATIETY : 0
- applyOrganDamage(healing_amount) //to FERMI_TWEAK
- //Make it so each threshold is stuck.
+ if(organ_flags & ORGAN_FAILING)
+ return
+ if(is_cold())
+ return
+ ///Damage decrements by a percent of its maxhealth
+ var/healing_amount = -(maxHealth * healing_factor)
+ ///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's health
+ healing_amount -= owner.satiety > 0 ? 4 * healing_factor * owner.satiety / MAX_SATIETY : 0
+ applyOrganDamage(healing_amount) //to FERMI_TWEAK
+ //Make it so each threshold is stuck.
/obj/item/organ/examine(mob/user)
. = ..()
- if(!organ_flags & ORGAN_FAILING)
+ if(organ_flags & ORGAN_FAILING)
if(status == ORGAN_ROBOTIC)
. += "[src] seems to be broken!"
return
@@ -177,6 +238,8 @@
return low_threshold_passed
else
organ_flags &= ~ORGAN_FAILING
+ if(!owner)//Processing is stopped when the organ is dead and outside of someone. This hopefully should restart it if a removed organ is repaired outside of a body.
+ START_PROCESSING(SSobj, src)
if(prev_damage > low_threshold && damage <= low_threshold)
return low_threshold_cleared
if(prev_damage > high_threshold && damage <= high_threshold)
diff --git a/code/modules/surgery/organs/stomach.dm b/code/modules/surgery/organs/stomach.dm
index 8ddaa951d8..a1624efd61 100755
--- a/code/modules/surgery/organs/stomach.dm
+++ b/code/modules/surgery/organs/stomach.dm
@@ -17,6 +17,7 @@
low_threshold_cleared = "The last bouts of pain in your stomach have died out."
/obj/item/organ/stomach/on_life()
+ ..()
var/datum/reagent/consumable/nutriment/Nutri
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm
index 3dd5c7b2b7..cee20dddee 100644
--- a/code/modules/surgery/organs/tongue.dm
+++ b/code/modules/surgery/organs/tongue.dm
@@ -23,6 +23,8 @@
/datum/language/aphasia,
/datum/language/slime,
))
+ healing_factor = STANDARD_ORGAN_HEALING*5 //Fast!!
+ decay_factor = STANDARD_ORGAN_DECAY/2
/obj/item/organ/tongue/Initialize(mapload)
. = ..()
@@ -209,6 +211,8 @@
phomeme_type = pick(phomeme_types)
/obj/item/organ/tongue/bone/applyOrganDamage(var/d, var/maximum = maxHealth)
+ if(d < 0)
+ return
if(!owner)
return
var/target = owner.get_bodypart(BODY_ZONE_HEAD)
diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm
index 39077ae235..fe22ffaede 100644
--- a/code/modules/surgery/plastic_surgery.dm
+++ b/code/modules/surgery/plastic_surgery.dm
@@ -5,7 +5,7 @@
//reshape_face
/datum/surgery_step/reshape_face
name = "reshape face"
- implements = list(/obj/item/scalpel = 100, /obj/item/kitchen/knife = 50, TOOL_WIRECUTTER = 35)
+ implements = list(TOOL_SCALPEL = 100, /obj/item/kitchen/knife = 50, TOOL_WIRECUTTER = 35)
time = 64
/datum/surgery_step/reshape_face/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -48,4 +48,4 @@
"[user] screws up, disfiguring [target]'s appearance!",
"[user] finishes the operation on [target]'s face.")
ADD_TRAIT(target, TRAIT_DISFIGURED, TRAIT_GENERIC)
- return FALSE
+ return FALSE
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index db7445e0b0..001ef8d0e6 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -7,16 +7,30 @@
item_flags = SURGICAL_TOOL
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_TINY
+ tool_behaviour = TOOL_RETRACTOR
+ toolspeed = 1
-/obj/item/retractor/adv
- name = "Advanced Retractor"
- desc = "A high-class, premium retractor, featuring precision crafted, silver-plated hook-ends and an electrum handle."
+/obj/item/retractor/advanced
+ name = "mechanical pinches"
+ desc = "An agglomerate of rods and gears."
icon = 'icons/obj/surgery.dmi'
- icon_state = "retractor"
- materials = list(MAT_METAL=6000, MAT_GLASS=3000)
- flags_1 = CONDUCT_1
- w_class = WEIGHT_CLASS_TINY
- toolspeed = 0.65
+ icon_state = "retractor_a"
+ toolspeed = 0.7
+
+/obj/item/retractor/advanced/attack_self(mob/user)
+ playsound(get_turf(user), 'sound/items/change_drill.ogg', 50, TRUE)
+ if(tool_behaviour == TOOL_RETRACTOR)
+ tool_behaviour = TOOL_HEMOSTAT
+ to_chat(user, "You configure the gears of [src], they are now in hemostat mode.")
+ icon_state = "hemostat_a"
+ else
+ tool_behaviour = TOOL_RETRACTOR
+ to_chat(user, "You configure the gears of [src], they are now in retractor mode.")
+ icon_state = "retractor_a"
+
+/obj/item/retractor/advanced/examine(mob/living/user)
+ . = ..()
+ to_chat(user, "You focus the lenses of [src], it is now in mending mode.")
+ icon_state = "cautery_a"
+ else
+ tool_behaviour = TOOL_DRILL
+ to_chat(user, "You dilate the lenses of [src], it is now in drilling mode.")
+ icon_state = "surgicaldrill_a"
+
+/obj/item/surgicaldrill/advanced/examine(mob/living/user)
+ . = ..()
+ to_chat(user, "")
/obj/item/surgicaldrill/augment
name = "surgical drill"
@@ -159,30 +167,47 @@
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP_ACCURATE
+ tool_behaviour = TOOL_SCALPEL
+ toolspeed = 1
/obj/item/scalpel/Initialize()
. = ..()
AddComponent(/datum/component/butchering, 80 * toolspeed, 100, 0)
-/obj/item/scalpel/adv
- name = "Precision Scalpel"
- desc = "A perfectly balanced electrum scalpel with a silicon-coated edge to eliminate wear and tear."
+/obj/item/scalpel/advanced
+ name = "laser scalpel"
+ desc = "An advanced scalpel which uses laser technology to cut."
icon = 'icons/obj/surgery.dmi'
- icon_state = "scalpel"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- flags_1 = CONDUCT_1
- force = 8
- w_class = WEIGHT_CLASS_TINY
- throwforce = 7
- throw_speed = 3
- throw_range = 6
- materials = list(MAT_METAL=4000, MAT_GLASS=1000)
- attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
- toolspeed = 0.65
- hitsound = 'sound/weapons/bladeslice.ogg'
+ icon_state = "scalpel_a"
+ hitsound = 'sound/weapons/blade1.ogg'
+ force = 16
+ toolspeed = 0.7
+ light_color = LIGHT_COLOR_GREEN
sharpness = IS_SHARP_ACCURATE
+/obj/item/scalpel/advanced/Initialize()
+ . = ..()
+ set_light(1)
+
+/obj/item/scalpel/advanced/attack_self(mob/user)
+ playsound(get_turf(user), 'sound/machines/click.ogg', 50, TRUE)
+ if(tool_behaviour == TOOL_SCALPEL)
+ tool_behaviour = TOOL_SAW
+ to_chat(user, "You increase the power of [src], now it can cut bones.")
+ set_light(2)
+ force += 1 //we don't want to ruin sharpened stuff
+ icon_state = "saw_a"
+ else
+ tool_behaviour = TOOL_SCALPEL
+ to_chat(user, "You lower the power of [src], it can no longer cut bones.")
+ set_light(1)
+ force -= 1
+ icon_state = "scalpel_a"
+
+/obj/item/scalpel/advanced/examine(mob/living/user)
+ . = ..()
+ to_chat(user, "")
+
/obj/item/scalpel/augment
name = "scalpel"
desc = "Ultra-sharp blade attached directly to your bone for extra-accuracy."
@@ -224,30 +249,13 @@
materials = list(MAT_METAL=10000, MAT_GLASS=6000)
attack_verb = list("attacked", "slashed", "sawed", "cut")
sharpness = IS_SHARP
+ tool_behaviour = TOOL_SAW
+ toolspeed = 1
/obj/item/circular_saw/Initialize()
. = ..()
AddComponent(/datum/component/butchering, 40 * toolspeed, 100, 5, 'sound/weapons/circsawhit.ogg') //saws are very accurate and fast at butchering
-/obj/item/circular_saw/adv
- name = "Diamond-Grit Circular Saw"
- desc = "For those Assistants with REALLY thick skulls."
- icon = 'icons/obj/surgery.dmi'
- icon_state = "saw"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- hitsound = 'sound/weapons/circsawhit.ogg'
- throwhitsound = 'sound/weapons/pierce.ogg'
- flags_1 = CONDUCT_1
- force = 13
- w_class = WEIGHT_CLASS_NORMAL
- throwforce = 6
- throw_speed = 1
- throw_range = 3
- materials = list(MAT_METAL=10000, MAT_GLASS=6000)
- attack_verb = list("attacked", "slashed", "sawed", "cut")
- toolspeed = 0.65
- sharpness = IS_SHARP
/obj/item/circular_saw/augment
name = "circular saw"
@@ -332,7 +340,7 @@
icon_state = "spectrometer"
item_flags = NOBLUDGEON
var/list/advanced_surgeries = list()
-
+
/obj/item/surgical_processor/afterattack(obj/item/O, mob/user, proximity)
. = ..()
if(!proximity)
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 23b4581600..61af0eaf78 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -1490,9 +1490,10 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
/datum/uplink_item/device_tools/singularity_beacon
name = "Power Beacon"
desc = "When screwed to wiring attached to an electric grid and activated, this large device pulls any \
- active gravitational singularities or tesla balls towards it. This will not work when the engine is still \
- in containment. Because of its size, it cannot be carried. Ordering this \
- sends you a small beacon that will teleport the larger beacon to your location upon activation."
+ active gravitational singularities or tesla balls towards it (provided they are not safely \
+ contained), as well as increasing the odds of incoming meteor waves. \
+ Because of its size, it cannot be carried. Ordering this sends you a small beacon \
+ that will teleport the larger beacon to your location upon activation."
item = /obj/item/sbeacondrop
cost = 14
diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm
index c577643df3..3879fc70cb 100644
--- a/code/modules/vending/autodrobe.dm
+++ b/code/modules/vending/autodrobe.dm
@@ -7,107 +7,109 @@
product_slogans = "Dress for success!;Suited and booted!;It's show time!;Why leave style up to fate? Use AutoDrobe!"
vend_reply = "Thank you for using AutoDrobe!"
products = list(/obj/item/clothing/suit/chickensuit = 1,
- /obj/item/clothing/head/chicken = 1,
- /obj/item/clothing/under/gladiator = 1,
- /obj/item/clothing/head/helmet/gladiator = 1,
- /obj/item/clothing/under/gimmick/rank/captain/suit = 1,
- /obj/item/clothing/head/flatcap = 1,
- /obj/item/clothing/suit/toggle/labcoat/mad = 1,
- /obj/item/clothing/shoes/jackboots = 1,
- /obj/item/clothing/under/schoolgirl = 1,
- /obj/item/clothing/under/schoolgirl/red = 1,
- /obj/item/clothing/under/schoolgirl/green = 1,
- /obj/item/clothing/under/schoolgirl/orange = 1,
- /obj/item/clothing/head/kitty = 1,
- /obj/item/clothing/under/skirt/black = 1,
- /obj/item/clothing/head/beret = 1,
- /obj/item/clothing/accessory/waistcoat = 1,
- /obj/item/clothing/under/suit_jacket = 1,
- /obj/item/clothing/head/that = 1,
- /obj/item/clothing/under/kilt = 1,
- /obj/item/clothing/head/beret = 1,
- /obj/item/clothing/accessory/waistcoat = 1,
- /obj/item/clothing/glasses/monocle =1,
- /obj/item/clothing/head/bowler = 1,
- /obj/item/cane = 1,
- /obj/item/clothing/under/sl_suit = 1,
- /obj/item/clothing/mask/fakemoustache = 1,
- /obj/item/clothing/suit/bio_suit/plaguedoctorsuit = 1,
- /obj/item/clothing/head/plaguedoctorhat = 1,
- /obj/item/clothing/mask/gas/plaguedoctor = 1,
- /obj/item/clothing/suit/toggle/owlwings = 1,
- /obj/item/clothing/under/owl = 1,
- /obj/item/clothing/mask/gas/owl_mask = 1,
- /obj/item/clothing/suit/toggle/owlwings/griffinwings = 1,
- /obj/item/clothing/under/griffin = 1,
- /obj/item/clothing/shoes/griffin = 1,
- /obj/item/clothing/head/griffin = 1,
- /obj/item/clothing/suit/apron = 1,
- /obj/item/clothing/under/waiter = 1,
- /obj/item/clothing/suit/jacket/miljacket = 1,
- /obj/item/clothing/under/pirate = 1,
- /obj/item/clothing/suit/pirate = 1,
- /obj/item/clothing/head/pirate = 1,
- /obj/item/clothing/head/bandana = 1,
- /obj/item/clothing/head/bandana = 1,
- /obj/item/clothing/under/soviet = 1,
- /obj/item/clothing/head/ushanka = 1,
- /obj/item/clothing/suit/imperium_monk = 1,
- /obj/item/clothing/mask/gas/cyborg = 1,
- /obj/item/clothing/suit/chaplain/holidaypriest = 1,
- /obj/item/clothing/head/wizard/marisa/fake = 1,
- /obj/item/clothing/suit/wizrobe/marisa/fake = 1,
- /obj/item/clothing/under/sundress = 1,
- /obj/item/clothing/head/witchwig = 1,
- /obj/item/staff/broom = 1,
- /obj/item/clothing/suit/wizrobe/fake = 1,
- /obj/item/clothing/head/wizard/fake = 1,
- /obj/item/staff = 3,
- /obj/item/clothing/under/rank/mime/skirt = 1,
- /obj/item/clothing/under/gimmick/rank/captain/suit/skirt = 1,
- /obj/item/clothing/mask/gas/sexyclown = 1,
- /obj/item/clothing/under/rank/clown/sexy = 1,
- /obj/item/clothing/mask/gas/sexymime = 1,
- /obj/item/clothing/under/sexymime = 1,
- /obj/item/clothing/mask/rat/bat = 1,
- /obj/item/clothing/mask/rat/bee = 1,
- /obj/item/clothing/mask/rat/bear = 1,
- /obj/item/clothing/mask/rat/raven = 1,
- /obj/item/clothing/mask/rat/jackal = 1,
- /obj/item/clothing/mask/rat/fox = 1,
- /obj/item/clothing/mask/frog = 1,
- /obj/item/clothing/mask/rat/tribal = 1,
- /obj/item/clothing/mask/rat = 1,
- /obj/item/clothing/suit/apron/overalls = 1,
- /obj/item/clothing/head/rabbitears =1,
- /obj/item/clothing/head/sombrero = 1,
- /obj/item/clothing/head/sombrero/green = 1,
- /obj/item/clothing/suit/poncho = 1,
- /obj/item/clothing/suit/poncho/green = 1,
- /obj/item/clothing/suit/poncho/red = 1,
- /obj/item/clothing/under/maid = 1,
- /obj/item/clothing/under/janimaid = 1,
- /obj/item/clothing/glasses/cold=1,
- /obj/item/clothing/glasses/heat=1,
- /obj/item/clothing/suit/whitedress = 1,
- /obj/item/clothing/under/jester = 1,
- /obj/item/clothing/head/jester = 1,
- /obj/item/clothing/under/villain = 1,
- /obj/item/clothing/shoes/singery = 1,
- /obj/item/clothing/under/singery = 1,
- /obj/item/clothing/shoes/singerb = 1,
- /obj/item/clothing/under/singerb = 1,
- /obj/item/clothing/suit/hooded/carp_costume = 1,
- /obj/item/clothing/suit/hooded/ian_costume = 1,
- /obj/item/clothing/suit/hooded/bee_costume = 1,
- /obj/item/clothing/suit/snowman = 1,
- /obj/item/clothing/head/snowman = 1,
- /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/head/wig/random = 3)
+ /obj/item/clothing/head/chicken = 1,
+ /obj/item/clothing/under/gladiator = 1,
+ /obj/item/clothing/head/helmet/gladiator = 1,
+ /obj/item/clothing/under/gimmick/rank/captain/suit = 1,
+ /obj/item/clothing/head/flatcap = 1,
+ /obj/item/clothing/suit/toggle/labcoat/mad = 1,
+ /obj/item/clothing/shoes/jackboots = 1,
+ /obj/item/clothing/under/schoolgirl = 1,
+ /obj/item/clothing/under/schoolgirl/red = 1,
+ /obj/item/clothing/under/schoolgirl/green = 1,
+ /obj/item/clothing/under/schoolgirl/orange = 1,
+ /obj/item/clothing/head/kitty = 1,
+ /obj/item/clothing/under/skirt/black = 1,
+ /obj/item/clothing/head/beret = 1,
+ /obj/item/clothing/accessory/waistcoat = 1,
+ /obj/item/clothing/under/suit_jacket = 1,
+ /obj/item/clothing/head/that = 1,
+ /obj/item/clothing/under/kilt = 1,
+ /obj/item/clothing/head/beret = 1,
+ /obj/item/clothing/accessory/waistcoat = 1,
+ /obj/item/clothing/glasses/monocle =1,
+ /obj/item/clothing/head/bowler = 1,
+ /obj/item/cane = 1,
+ /obj/item/clothing/under/sl_suit = 1,
+ /obj/item/clothing/mask/fakemoustache = 1,
+ /obj/item/clothing/suit/bio_suit/plaguedoctorsuit = 1,
+ /obj/item/clothing/head/plaguedoctorhat = 1,
+ /obj/item/clothing/mask/gas/plaguedoctor = 1,
+ /obj/item/clothing/suit/toggle/owlwings = 1,
+ /obj/item/clothing/under/owl = 1,
+ /obj/item/clothing/mask/gas/owl_mask = 1,
+ /obj/item/clothing/suit/toggle/owlwings/griffinwings = 1,
+ /obj/item/clothing/under/griffin = 1,
+ /obj/item/clothing/shoes/griffin = 1,
+ /obj/item/clothing/head/griffin = 1,
+ /obj/item/clothing/suit/apron = 1,
+ /obj/item/clothing/under/waiter = 1,
+ /obj/item/clothing/suit/jacket/miljacket = 1,
+ /obj/item/clothing/under/pirate = 1,
+ /obj/item/clothing/suit/pirate = 1,
+ /obj/item/clothing/head/pirate = 1,
+ /obj/item/clothing/head/bandana = 1,
+ /obj/item/clothing/head/bandana = 1,
+ /obj/item/clothing/under/soviet = 1,
+ /obj/item/clothing/head/ushanka = 1,
+ /obj/item/clothing/suit/imperium_monk = 1,
+ /obj/item/clothing/mask/gas/cyborg = 1,
+ /obj/item/clothing/suit/chaplain/holidaypriest = 1,
+ /obj/item/clothing/head/wizard/marisa/fake = 1,
+ /obj/item/clothing/suit/wizrobe/marisa/fake = 1,
+ /obj/item/clothing/under/sundress = 1,
+ /obj/item/clothing/head/witchwig = 1,
+ /obj/item/staff/broom = 1,
+ /obj/item/clothing/suit/wizrobe/fake = 1,
+ /obj/item/clothing/head/wizard/fake = 1,
+ /obj/item/staff = 3,
+ /obj/item/clothing/under/rank/mime/skirt = 1,
+ /obj/item/clothing/under/gimmick/rank/captain/suit/skirt = 1,
+ /obj/item/clothing/mask/gas/sexyclown = 1,
+ /obj/item/clothing/under/rank/clown/sexy = 1,
+ /obj/item/clothing/mask/gas/sexymime = 1,
+ /obj/item/clothing/under/sexymime = 1,
+ /obj/item/clothing/mask/rat/bat = 1,
+ /obj/item/clothing/mask/rat/bee = 1,
+ /obj/item/clothing/mask/rat/bear = 1,
+ /obj/item/clothing/mask/rat/raven = 1,
+ /obj/item/clothing/mask/rat/jackal = 1,
+ /obj/item/clothing/mask/rat/fox = 1,
+ /obj/item/clothing/mask/frog = 1,
+ /obj/item/clothing/mask/rat/tribal = 1,
+ /obj/item/clothing/mask/rat = 1,
+ /obj/item/clothing/suit/apron/overalls = 1,
+ /obj/item/clothing/head/rabbitears =1,
+ /obj/item/clothing/head/sombrero = 1,
+ /obj/item/clothing/head/sombrero/green = 1,
+ /obj/item/clothing/suit/poncho = 1,
+ /obj/item/clothing/suit/poncho/green = 1,
+ /obj/item/clothing/suit/poncho/red = 1,
+ /obj/item/clothing/under/maid = 1,
+ /obj/item/clothing/under/janimaid = 1,
+ /obj/item/clothing/glasses/cold=1,
+ /obj/item/clothing/glasses/heat=1,
+ /obj/item/clothing/suit/whitedress = 1,
+ /obj/item/clothing/under/jester = 1,
+ /obj/item/clothing/head/jester = 1,
+ /obj/item/clothing/under/villain = 1,
+ /obj/item/clothing/shoes/singery = 1,
+ /obj/item/clothing/under/singery = 1,
+ /obj/item/clothing/shoes/singerb = 1,
+ /obj/item/clothing/under/singerb = 1,
+ /obj/item/clothing/suit/hooded/carp_costume = 1,
+ /obj/item/clothing/suit/hooded/ian_costume = 1,
+ /obj/item/clothing/suit/hooded/bee_costume = 1,
+ /obj/item/clothing/suit/snowman = 1,
+ /obj/item/clothing/head/snowman = 1,
+ /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/head/wig/random = 3,
+ /obj/item/clothing/suit/ran = 2,
+ /obj/item/clothing/head/ran = 2)
contraband = list(/obj/item/clothing/suit/judgerobe = 1,
/obj/item/clothing/head/powdered_wig = 1,
/obj/item/gun/magic/wand = 2,
diff --git a/config/config.txt b/config/config.txt
index c75cd6dc1b..0501d1fd2f 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -233,22 +233,22 @@ CHECK_RANDOMIZER
# SERVER ss13.example.com:2506
## forum address
-# FORUMURL http://tgstation13.org/phpBB/index.php
+# FORUMURL https://citadel-station.net/forum/
## Wiki address
-# WIKIURL http://www.tgstation13.org/wiki
+# WIKIURL https://katlin.dog/citadel-wiki
## Rules address
-# RULESURL http://www.tgstation13.org/wiki/Rules
+# RULESURL https://katlin.dog/citadel-rules/main
## Github address
-# GITHUBURL https://www.github.com/tgstation/tgstation
+# GITHUBURL https://github.com/Citadel-Station-13/Citadel-Station-13
## Round specific stats address
## Link to round specific parsed logs; IE statbus. It is appended with the RoundID automatically by ticker/Reboot()
## This will take priority over the game logs address during reboot.
## Example: https://atlantaned.space/statbus/round.php?round=
-# ROUNDSTATSURL
+# ROUNDSTATSURL http://citadel-station.net/slimbus/
## Game Logs address
## Incase you don't have a fancy parsing system, but still want players to be able to find where you keep your server's logs.
@@ -258,10 +258,10 @@ CHECK_RANDOMIZER
## Github repo id
##This can be found by going to https://api.github.com/users//repos
##Or https://api.github.com/orgs//repos if the repo owner is an organization
-# GITHUBREPOID 3234987
+# GITHUBREPOID 62485194
## Ban appeals URL - usually for a forum or wherever people should go to contact your admins.
-# BANAPPEALS http://justanotherday.example.com
+# BANAPPEALS https://citadel-station.net/forum/viewforum.php?f=8&sid=a0ce5331d5594ef6d49661609c6f4ff9
## System command that invokes youtube-dl, used by Play Internet Sound.
## You can install youtube-dl with
diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css
index 58129ac1cb..174aa8a22f 100644
--- a/goon/browserassets/css/browserOutput.css
+++ b/goon/browserassets/css/browserOutput.css
@@ -393,6 +393,7 @@ h1.alert, h2.alert {color: #000000;}
.redtext {color: #FF0000; font-size: 24px;}
.clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
+.spooky {color: #FF6100;}
.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;}
@keyframes velvet {
0% { color: #400020; }
diff --git a/html/changelogs/AutoChangeLog-pr-9339.yml b/html/changelogs/AutoChangeLog-pr-9339.yml
new file mode 100644
index 0000000000..eeb5ae632c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9339.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - balance: "Removes revenant blight's shabby toxin damage in favor of mood maluses, and a dangerous necropolis curse if not cured in time. Remember"
diff --git a/html/changelogs/AutoChangeLog-pr-9374.yml b/html/changelogs/AutoChangeLog-pr-9374.yml
new file mode 100644
index 0000000000..f43f28118b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9374.yml
@@ -0,0 +1,5 @@
+author: "kappa-sama"
+delete-after: True
+changes:
+ - rscadd: "hugbox (/s)"
+ - tweak: "ashwalker spawn text now tells them \"i\" \"c\" not to leave lavaland"
diff --git a/html/changelogs/AutoChangeLog-pr-9386.yml b/html/changelogs/AutoChangeLog-pr-9386.yml
new file mode 100644
index 0000000000..8426b0be7c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9386.yml
@@ -0,0 +1,4 @@
+author: "original by Bumtickley00, port by sishen1542"
+delete-after: True
+changes:
+ - tweak: "Suit storage units will now also remove radiation from mobs."
diff --git a/html/changelogs/AutoChangeLog-pr-9387.yml b/html/changelogs/AutoChangeLog-pr-9387.yml
new file mode 100644
index 0000000000..6fa03cd817
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9387.yml
@@ -0,0 +1,4 @@
+author: "original by: WJohnston, Antur, Arcane, plapatin, sprites by cogwerks and edited by mrdoombringer. port by sishen1542"
+delete-after: True
+changes:
+ - rscadd: "THE GOOSE IS LOOSE"
diff --git a/html/changelogs/AutoChangeLog-pr-9416.yml b/html/changelogs/AutoChangeLog-pr-9416.yml
new file mode 100644
index 0000000000..cf36873498
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9416.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "Singularity beacons now also moderately increases the odds meteor waves, while lowering their estimeed arrival countdown."
diff --git a/html/changelogs/AutoChangeLog-pr-9435.yml b/html/changelogs/AutoChangeLog-pr-9435.yml
new file mode 100644
index 0000000000..4c7a2ab1a1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9435.yml
@@ -0,0 +1,4 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - bugfix: "having one of your hands used up if you fireman carry but the person being carried dismounts any way other than you dropping them"
diff --git a/html/changelogs/AutoChangeLog-pr-9437.yml b/html/changelogs/AutoChangeLog-pr-9437.yml
new file mode 100644
index 0000000000..262fd2a86e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9437.yml
@@ -0,0 +1,4 @@
+author: "JTGSZ"
+delete-after: True
+changes:
+ - rscadd: "Optional species based clothing restrictions"
diff --git a/html/changelogs/AutoChangeLog-pr-9441.yml b/html/changelogs/AutoChangeLog-pr-9441.yml
new file mode 100644
index 0000000000..a1321fb3a3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9441.yml
@@ -0,0 +1,6 @@
+author: "lolman360"
+delete-after: True
+changes:
+ - tweak: "chainsaw kind of weapons and the mecha drill and the CLAMP can now be used with 100% accuracy for surgery"
+ - refactor: "surgery tools now work on defines"
+ - balance: "advanced surgerytools can now switch types instead of just being faster"
diff --git a/html/changelogs/AutoChangeLog-pr-9442.yml b/html/changelogs/AutoChangeLog-pr-9442.yml
new file mode 100644
index 0000000000..1cde8b15f4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9442.yml
@@ -0,0 +1,4 @@
+author: "YakumoChen"
+delete-after: True
+changes:
+ - tweak: "Jetpacks no longer last twice as long between air refills."
diff --git a/html/changelogs/AutoChangeLog-pr-9444.yml b/html/changelogs/AutoChangeLog-pr-9444.yml
new file mode 100644
index 0000000000..0a317feda1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9444.yml
@@ -0,0 +1,8 @@
+author: "Fermis"
+delete-after: True
+changes:
+ - bugfix: "fixes reaction mechanics at low volumes"
+ - bugfix: "stops reactions constantly bubbling on the edge of reaction temperature"
+ - bugfix: "stops small amount reactions from occurring, and prevents disappearing tiny numbers"
+ - tweak: "Reduced minimum reaction volume from 1 to 0.01"
+ - refactor: "cleaned up Fermichem"
diff --git a/html/changelogs/AutoChangeLog-pr-9450.yml b/html/changelogs/AutoChangeLog-pr-9450.yml
new file mode 100644
index 0000000000..7616262604
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9450.yml
@@ -0,0 +1,4 @@
+author: "JTGSZ"
+delete-after: True
+changes:
+ - rscadd: "Adds more control over species based offsets."
diff --git a/html/changelogs/AutoChangeLog-pr-9451.yml b/html/changelogs/AutoChangeLog-pr-9451.yml
new file mode 100644
index 0000000000..12843efb68
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9451.yml
@@ -0,0 +1,4 @@
+author: "Ghommie (original PR by ShizCalev)"
+delete-after: True
+changes:
+ - bugfix: "As a non-human mob, hovering your cursor over an inventory slot while holding an object in your active hand shouldn't runtime now."
diff --git a/html/changelogs/AutoChangeLog-pr-9456.yml b/html/changelogs/AutoChangeLog-pr-9456.yml
new file mode 100644
index 0000000000..e4392394b8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9456.yml
@@ -0,0 +1,7 @@
+author: "Fermis"
+delete-after: True
+changes:
+ - rscadd: "Adds Jacqueline the Pumpqueen and her familiar Bartholomew for the spooky season"
+ - soundadd: "Adds a giggle"
+ - imageadd: "Adds cauldron, Jacq and Jacq o lanterns, and a costume for halloween!
+mapedit: adds a new landmark so Bartholomew can spawn somewhere sensible."
diff --git a/html/changelogs/AutoChangeLog-pr-9458.yml b/html/changelogs/AutoChangeLog-pr-9458.yml
new file mode 100644
index 0000000000..44fc8370d8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9458.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - balance: "Nerfs cyborg disabler and its internal power cell to hold 25 disabler beam shots rather than 43/44, just like a normal disabler."
diff --git a/html/changelogs/AutoChangeLog-pr-9459.yml b/html/changelogs/AutoChangeLog-pr-9459.yml
new file mode 100644
index 0000000000..5b4cf5736a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9459.yml
@@ -0,0 +1,4 @@
+author: "dapnee"
+delete-after: True
+changes:
+ - bugfix: "You can now make plasmaglass tables again."
diff --git a/html/changelogs/AutoChangeLog-pr-9461.yml b/html/changelogs/AutoChangeLog-pr-9461.yml
new file mode 100644
index 0000000000..91288f23fe
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9461.yml
@@ -0,0 +1,4 @@
+author: "r4d6"
+delete-after: True
+changes:
+ - rscadd: "Added decoratives angel wings for Mammalians only"
diff --git a/html/changelogs/AutoChangeLog-pr-9463.yml b/html/changelogs/AutoChangeLog-pr-9463.yml
new file mode 100644
index 0000000000..3a465c5a05
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9463.yml
@@ -0,0 +1,6 @@
+author: "Owai-Seek"
+delete-after: True
+changes:
+ - rscadd: "false codpiece"
+ - rscadd: "crocin/camphor bottles"
+ - tweak: "updated kinkmate item list"
diff --git a/html/changelogs/AutoChangeLog-pr-9464.yml b/html/changelogs/AutoChangeLog-pr-9464.yml
new file mode 100644
index 0000000000..79a5960abd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9464.yml
@@ -0,0 +1,4 @@
+author: "JTGSZ"
+delete-after: True
+changes:
+ - bugfix: "qualifies_for_rank now checks latejoin menu"
diff --git a/html/changelogs/AutoChangeLog-pr-9467.yml b/html/changelogs/AutoChangeLog-pr-9467.yml
new file mode 100644
index 0000000000..b57d60f9dd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9467.yml
@@ -0,0 +1,4 @@
+author: "Bhijn"
+delete-after: True
+changes:
+ - bugfix: "The server no longer attempts to check if the CID matches the IP of any bans, or if the IP matches any CIDs of any active bans, during client analyzation"
diff --git a/html/changelogs/AutoChangeLog-pr-9472.yml b/html/changelogs/AutoChangeLog-pr-9472.yml
new file mode 100644
index 0000000000..dd0aac8954
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9472.yml
@@ -0,0 +1,5 @@
+author: "Fermis"
+delete-after: True
+changes:
+ - bugfix: "fixes food reactions and explosion runtimes,"
+ - bugfix: "fixes the too much yes problem"
diff --git a/html/changelogs/AutoChangeLog-pr-9473.yml b/html/changelogs/AutoChangeLog-pr-9473.yml
new file mode 100644
index 0000000000..def08d4acd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9473.yml
@@ -0,0 +1,4 @@
+author: "PersianXerxes"
+delete-after: True
+changes:
+ - code_imp: "Adds the clockwork_warp_allowed flag to the Captain's Office area, set to FALSE the same way it is for the chapel and armory."
diff --git a/html/changelogs/AutoChangeLog-pr-9474.yml b/html/changelogs/AutoChangeLog-pr-9474.yml
new file mode 100644
index 0000000000..1e3737f1a5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9474.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - bugfix: "neural nanites only work/drain if you have brain damage or traumas the nanites can fix"
diff --git a/html/changelogs/AutoChangeLog-pr-9477.yml b/html/changelogs/AutoChangeLog-pr-9477.yml
new file mode 100644
index 0000000000..cf13d15860
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9477.yml
@@ -0,0 +1,8 @@
+author: "Fermis"
+delete-after: True
+changes:
+ - bugfix: "Heart, Tongue and stomach regen."
+ - bugfix: "lung damage threshholds."
+ - bugfix: "Graft synthtissue"
+ - bugfix: "Skeleton's burning for no reason"
+ - bugfix: "Organ freezing handling."
diff --git a/html/changelogs/AutoChangeLog-pr-9478.yml b/html/changelogs/AutoChangeLog-pr-9478.yml
new file mode 100644
index 0000000000..d2c80d08fb
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9478.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - tweak: "Pod people can no longer get fat from standing in the light"
diff --git a/html/changelogs/AutoChangeLog-pr-9479.yml b/html/changelogs/AutoChangeLog-pr-9479.yml
new file mode 100644
index 0000000000..cea218193e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9479.yml
@@ -0,0 +1,4 @@
+author: "lolman360"
+delete-after: True
+changes:
+ - bugfix: "fixes bug with new surgerytools examine"
diff --git a/html/changelogs/AutoChangeLog-pr-9486.yml b/html/changelogs/AutoChangeLog-pr-9486.yml
new file mode 100644
index 0000000000..c624e6472c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9486.yml
@@ -0,0 +1,4 @@
+author: "ZeroNetAlpha"
+delete-after: True
+changes:
+ - tweak: "Silicons are now consumable by scrub pups."
diff --git a/html/changelogs/AutoChangeLog-pr-9488.yml b/html/changelogs/AutoChangeLog-pr-9488.yml
new file mode 100644
index 0000000000..dd5ac89610
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9488.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Adds some missing species_traits for cloth, clockwork and cult golems."
diff --git a/html/changelogs/AutoChangeLog-pr-9489.yml b/html/changelogs/AutoChangeLog-pr-9489.yml
new file mode 100644
index 0000000000..a395af0749
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9489.yml
@@ -0,0 +1,4 @@
+author: "Ghommie (original PR by nemvar)"
+delete-after: True
+changes:
+ - imageadd: "Some drinks have new icons or slightly altered icons. In particular Wizz Fizz, Bug Spray, Jack Rose, Champagne and Applejack."
diff --git a/html/changelogs/AutoChangeLog-pr-9491.yml b/html/changelogs/AutoChangeLog-pr-9491.yml
new file mode 100644
index 0000000000..0bfd6b6ee2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9491.yml
@@ -0,0 +1,4 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - bugfix: "fixed missing deco wing states"
diff --git a/html/changelogs/AutoChangeLog-pr-9492.yml b/html/changelogs/AutoChangeLog-pr-9492.yml
new file mode 100644
index 0000000000..5481265898
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9492.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "Added towel linen bins, found in dormitory restrooms. Also enhanced the bedsheet bins found in some stations' dormitories"
+ - imageadd: "Resprited bedsheet bins in 3/4 perspective"
diff --git a/html/changelogs/AutoChangeLog-pr-9493.yml b/html/changelogs/AutoChangeLog-pr-9493.yml
new file mode 100644
index 0000000000..69aef9dbec
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9493.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - tweak: "Made SDGF ghost poll message less verbose, made the experimental cloner's complaint with the former, and added ghost poll ignore options for both."
diff --git a/html/changelogs/AutoChangeLog-pr-9499.yml b/html/changelogs/AutoChangeLog-pr-9499.yml
new file mode 100644
index 0000000000..a4d41485cd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9499.yml
@@ -0,0 +1,4 @@
+author: "r4d6"
+delete-after: True
+changes:
+ - rscadd: "Added blindfolds to the Loadout list"
diff --git a/html/changelogs/AutoChangeLog-pr-9502.yml b/html/changelogs/AutoChangeLog-pr-9502.yml
new file mode 100644
index 0000000000..71939adfd8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9502.yml
@@ -0,0 +1,4 @@
+author: "Putnam3145"
+delete-after: True
+changes:
+ - tweak: "PanD.E.M.I.C 2200 now ejects onto itself instead of onto user if user's hands are full"
diff --git a/html/changelogs/AutoChangeLog-pr-9506.yml b/html/changelogs/AutoChangeLog-pr-9506.yml
new file mode 100644
index 0000000000..e3a0e63b18
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9506.yml
@@ -0,0 +1,4 @@
+author: "izzyinbox"
+delete-after: True
+changes:
+ - rscadd: "*bark emote"
diff --git a/html/changelogs/AutoChangeLog-pr-9517.yml b/html/changelogs/AutoChangeLog-pr-9517.yml
new file mode 100644
index 0000000000..06442cae43
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9517.yml
@@ -0,0 +1,4 @@
+author: "kappa-sama"
+delete-after: True
+changes:
+ - bugfix: "you can no longer have infinite ebows"
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index 2a85f8a422..e9343c7ed2 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 0197507b9d..842562b007 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 740ad43d42..38ac61f318 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index 06b2eee2eb..c8a007041b 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index dc5fa1399d..fb406fb65e 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi
index f9c1a197e7..e8b3d434f5 100644
Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ
diff --git a/icons/obj/halloween_items.dmi b/icons/obj/halloween_items.dmi
index c08ea71148..b4f11165dc 100644
Binary files a/icons/obj/halloween_items.dmi and b/icons/obj/halloween_items.dmi differ
diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi
index 7bbfdfd11d..cad28e12fe 100644
Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index eed8ee64e7..bdfbae3d75 100755
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm
index 2ecd9f9004..c51778bbdb 100644
--- a/interface/stylesheet.dm
+++ b/interface/stylesheet.dm
@@ -153,6 +153,7 @@ h1.alert, h2.alert {color: #000000;}
.redtext {color: #FF0000; font-size: 3;}
.clown {color: #FF69Bf; font-size: 3; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
+.spooky {color: #FF9100;}
.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;}
@keyframes velvet {
0% { color: #400020; }
diff --git a/modular_citadel/code/game/machinery/vending.dm b/modular_citadel/code/game/machinery/vending.dm
index 2de98a3171..6a91810173 100755
--- a/modular_citadel/code/game/machinery/vending.dm
+++ b/modular_citadel/code/game/machinery/vending.dm
@@ -43,18 +43,33 @@
vend_reply = "Have fun, you shameless pervert!"
products = list(
/obj/item/clothing/under/maid = 5,
- /obj/item/clothing/under/stripper_pink = 5,
- /obj/item/clothing/under/stripper_green = 5,
- /obj/item/dildo/custom = 5
- )
- contraband = list(/obj/item/restraints/handcuffs/fake/kinky = 5,
/obj/item/clothing/neck/petcollar = 5,
- /obj/item/clothing/under/mankini = 1,
- /obj/item/dildo/flared/huge = 1
+ /obj/item/clothing/neck/petcollar/choker = 5,
+ /obj/item/clothing/neck/petcollar/leather = 5,
+ /obj/item/restraints/handcuffs/fake/kinky = 5,
+ /obj/item/clothing/glasses/sunglasses/blindfold = 4,
+ /obj/item/clothing/mask/muzzle = 4,
+ /obj/item/clothing/under/stripper_pink = 3,
+ /obj/item/clothing/under/stripper_green = 3,
+ /obj/item/dildo/custom = 5,
+ /obj/item/electropack/shockcollar = 3,
+ /obj/item/assembly/signaler = 3
+ )
+ contraband = list(
+ /obj/item/clothing/neck/petcollar/locked = 2,
+ /obj/item/key/collar = 2,
+ /obj/item/clothing/head/kitty = 3,
+ /obj/item/clothing/head/rabbitears = 3,
+ /obj/item/clothing/under/mankini = 2,
+ /obj/item/clothing/under/jabroni = 2,
+ /obj/item/dildo/flared/huge = 3,
+ /obj/item/reagent_containers/glass/bottle/crocin = 5,
+ /obj/item/reagent_containers/glass/bottle/camphor = 5
)
premium = list(
- /obj/item/electropack/shockcollar = 3,
- /obj/item/clothing/neck/petcollar/locked = 1
+ /obj/item/clothing/accessory/skullcodpiece/fake = 3,
+ /obj/item/clothing/under/gear_harness = 10,
+ /obj/item/reagent_containers/glass/bottle/hexacrocin = 10
)
refill_canister = /obj/item/vending_refill/kink
/*
diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm
index 136aefb8f5..7e7038cb31 100644
--- a/modular_citadel/code/modules/client/loadout/__donator.dm
+++ b/modular_citadel/code/modules/client/loadout/__donator.dm
@@ -450,5 +450,5 @@ datum/gear/darksabresheath
/datum/gear/donorgoggles
name = "Flight Goggles"
category = SLOT_HEAD
- path = /obj/item/clothing/glasses/flight
+ path = /obj/item/clothing/head/flight
ckeywhitelist = list("maxlynchy")
diff --git a/modular_citadel/code/modules/client/loadout/glasses.dm b/modular_citadel/code/modules/client/loadout/glasses.dm
index 9e7b68bf0d..57270d8e57 100644
--- a/modular_citadel/code/modules/client/loadout/glasses.dm
+++ b/modular_citadel/code/modules/client/loadout/glasses.dm
@@ -1,3 +1,8 @@
+/datum/gear/blindfold
+ name = "Blindfold"
+ category = SLOT_GLASSES
+ path = /obj/item/clothing/glasses/sunglasses/blindfold
+
/datum/gear/cold
name = "Cold goggles"
category = SLOT_GLASSES
diff --git a/modular_citadel/code/modules/custom_loadout/custom_items.dm b/modular_citadel/code/modules/custom_loadout/custom_items.dm
index 0cabdca6ee..32c73cc40a 100644
--- a/modular_citadel/code/modules/custom_loadout/custom_items.dm
+++ b/modular_citadel/code/modules/custom_loadout/custom_items.dm
@@ -494,11 +494,10 @@
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
-/obj/item/clothing/glasses/flight
+/obj/item/clothing/head/flight
name = "flight goggles"
desc = "Old style flight goggles with a leather cap attached."
icon_state = "flight-g"
item_state = "flight-g"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
- actions_types = list(/datum/action/item_action/toggle)
diff --git a/modular_citadel/code/modules/mob/cit_emotes.dm b/modular_citadel/code/modules/mob/cit_emotes.dm
index a34b7b0526..7e7a77538a 100644
--- a/modular_citadel/code/modules/mob/cit_emotes.dm
+++ b/modular_citadel/code/modules/mob/cit_emotes.dm
@@ -213,3 +213,18 @@
user.nextsoundemote = world.time + 7
playsound(user, 'modular_citadel/sound/voice/merp.ogg', 50, 1, -1)
. = ..()
+
+/datum/emote/living/bark
+ key = "bark"
+ key_third_person = "barks"
+ message = "barks!"
+ emote_type = EMOTE_AUDIBLE
+
+/datum/emote/living/bark/run_emote(mob/living/user, params)
+ if(ishuman(user))
+ if(user.nextsoundemote >= world.time)
+ return
+ user.nextsoundemote = world.time + 7
+ var/sound = pick('modular_citadel/sound/voice/bark1.ogg', 'modular_citadel/sound/voice/bark2.ogg')
+ playsound(user, sound, 50, 1, -1)
+ . = ..()
\ No newline at end of file
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
index a7e1ac8e92..e5844f204a 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
@@ -68,11 +68,10 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
startHunger = M.nutrition
if(pollStarted == FALSE)
pollStarted = TRUE
- candies = pollGhostCandidates("Do you want to play as a clone of [M], and do you agree to respect their character and act in a similar manner to them? Do not engage in ERP as them unless you have LOOC permission from them, and ensure it is permission from the original, not a clone.")
+ candies = pollGhostCandidates("Do you want and agree to play as a clone of [M], respect their character and not engage in ERP without permission from the original?", ignore_category = POLL_IGNORE_CLONE)
log_game("FERMICHEM: [M] ckey: [M.key] has taken SDGF, and ghosts have been polled.")
if(20 to INFINITY)
if(LAZYLEN(candies) && playerClone == FALSE) //If there's candidates, clone the person and put them in there!
- log_game("FERMICHEM: [M] ckey: [M.key] is creating a clone, controlled by [candies]")
to_chat(M, "The cells reach a critical micelle concentration, nucleating rapidly within your body!")
var/typepath = M.type
var/mob/living/carbon/human/fermi_Gclone = new typepath(M.loc)
@@ -91,7 +90,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
log_game("FERMICHEM: [M] ckey: [M.key] is creating a clone, controlled by [C2]")
break
else
- candies =- C2
+ candies -= C2
if(!SM.mind) //Something went wrong, use alt mechanics
return ..()
SM.mind.enslave_mind_to_creator(M)
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
index b9a79fe228..4acfda0573 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
@@ -168,7 +168,7 @@
//Writen by Trilby!! Embellsished a little by me.
/datum/reagent/fermi/nanite_b_gone
- name = "Naninte bane"
+ name = "Nanite bane"
id = "nanite_b_gone"
description = "A stablised EMP that is highly volatile, shocking small nano machines that will kill them off at a rapid rate in a patient's system."
color = "#708f8f"
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm
index 8b76c9b4e6..4949cc6ecf 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm
@@ -100,7 +100,7 @@
id = "synthtissue"
description = "Synthetic tissue used for grafting onto damaged organs during surgery, or for treating limb damage. Has a very tight growth window between 305-320, any higher and the temperature will cause the cells to die. Additionally, growth time is considerably long, so chemists are encouraged to leave beakers with said reaction ongoing, while they tend to their other duties."
pH = 7.6
- metabolization_rate = 0.1
+ metabolization_rate = 0.05 //Give them time to graft
data = list("grown_volume" = 0, "injected_vol" = 0)
/datum/reagent/synthtissue/reaction_mob(mob/living/M, method=TOUCH, reac_volume,show_message = 1)
@@ -115,7 +115,7 @@
to_chat(M, "You feel your [target] heal! It stings like hell!")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
if(method==INJECT)
- data["injected_vol"] = data["injected_vol"] + reac_volume
+ data["injected_vol"] = reac_volume
..()
/datum/reagent/synthtissue/on_mob_life(mob/living/carbon/C)
@@ -136,6 +136,9 @@
return ..()
if(passed_data["grown_volume"] > data["grown_volume"])
data["grown_volume"] = passed_data["grown_volume"]
+ if(iscarbon(holder.my_atom))
+ data["injected_vol"] = data["injected_vol"] + passed_data["injected_vol"]
+ passed_data["injected_vol"] = 0
..()
/datum/reagent/synthtissue/on_new(passed_data)
diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
index b7d45b0cb1..47f71d1acf 100644
--- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
@@ -28,7 +28,7 @@
return
//Called when temperature is above a certain threshold, or if purity is too low.
-/datum/chemical_reaction/proc/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH, Exploding = FALSE)
+/datum/chemical_reaction/proc/FermiExplode(datum/reagents/R0, var/atom/my_atom, volume, temp, pH, Exploding = FALSE)
if (Exploding == TRUE)
return
@@ -76,7 +76,7 @@
var/datum/effect_system/smoke_spread/chem/s = new()
R.my_atom = my_atom //Give the gas a fingerprint
- for (var/datum/reagent/reagent in my_atom.reagents.reagent_list) //make gas for reagents, has to be done this way, otherwise it never stops Exploding
+ for (var/datum/reagent/reagent in R0.reagent_list) //make gas for reagents, has to be done this way, otherwise it never stops Exploding
R.add_reagent(reagent.id, reagent.volume/3) //Seems fine? I think I fixed the infinite explosion bug.
if (reagent.purity < 0.6)
@@ -104,8 +104,8 @@
/datum/chemical_reaction/fermi/eigenstate
name = "Eigenstasium"
id = "eigenstate"
- results = list("eigenstate" = 0.1)
- required_reagents = list("bluespace" = 0.1, "stable_plasma" = 0.1, "sugar" = 0.1)
+ results = list("eigenstate" = 1)
+ required_reagents = list("bluespace" = 1, "stable_plasma" = 1, "sugar" = 1)
mix_message = "the reaction zaps suddenly!"
//FermiChem vars:
OptimalTempMin = 350 // Lower area of bell curve for determining heat based rate reactions
@@ -138,8 +138,8 @@
/datum/chemical_reaction/fermi/SDGF
name = "Synthetic-derived growth factor"
id = "SDGF"
- results = list("SDGF" = 0.3)
- required_reagents = list("stable_plasma" = 0.15, "clonexadone" = 0.15, "uranium" = 0.15, "synthflesh" = 0.15)
+ results = list("SDGF" = 3)
+ required_reagents = list("stable_plasma" = 1.5, "clonexadone" = 1.5, "uranium" = 1.5, "synthflesh" = 1.5)
mix_message = "the reaction gives off a blorble!"
required_temp = 1
//FermiChem vars:
@@ -179,8 +179,8 @@
/datum/chemical_reaction/fermi/breast_enlarger
name = "Sucubus milk"
id = "breast_enlarger"
- results = list("breast_enlarger" = 0.8)
- required_reagents = list("salglu_solution" = 0.1, "milk" = 0.1, "synthflesh" = 0.2, "silicon" = 0.3, "aphro" = 0.3)
+ results = list("breast_enlarger" = 8)
+ required_reagents = list("salglu_solution" = 1, "milk" = 1, "synthflesh" = 2, "silicon" = 3, "aphro" = 3)
mix_message = "the reaction gives off a mist of milk."
//FermiChem vars:
OptimalTempMin = 200
@@ -219,8 +219,8 @@
/datum/chemical_reaction/fermi/penis_enlarger
name = "Incubus draft"
id = "penis_enlarger"
- results = list("penis_enlarger" = 0.8)
- required_reagents = list("blood" = 0.5, "synthflesh" = 0.2, "carbon" = 0.2, "aphro" = 0.2, "salglu_solution" = 0.1,)
+ results = list("penis_enlarger" = 8)
+ required_reagents = list("blood" = 5, "synthflesh" = 2, "carbon" = 2, "aphro" = 2, "salglu_solution" = 1)
mix_message = "the reaction gives off a spicy mist."
//FermiChem vars:
OptimalTempMin = 200
@@ -258,8 +258,8 @@
/datum/chemical_reaction/fermi/astral
name = "Astrogen"
id = "astral"
- results = list("astral" = 0.5)
- required_reagents = list("eigenstate" = 0.1, "plasma" = 0.3, "synaptizine" = 0.1, "aluminium" = 0.5)
+ results = list("astral" = 5)
+ required_reagents = list("eigenstate" = 1, "plasma" = 3, "synaptizine" = 1, "aluminium" = 5)
//FermiChem vars:
OptimalTempMin = 700
OptimalTempMax = 800
@@ -281,10 +281,10 @@
/datum/chemical_reaction/fermi/enthrall/ //check this
name = "MKUltra"
id = "enthrall"
- results = list("enthrall" = 0.5)
+ results = list("enthrall" = 5)
//required_reagents = list("iron" = 1, "iodine" = 1) Test vars
- //required_reagents = list("cocoa" = 0.1, "astral" = 0.1, "mindbreaker" = 0.1, "psicodine" = 0.1, "happiness" = 0.1)
- required_reagents = list("cocoa" = 0.1, "bluespace" = 0.1, "mindbreaker" = 0.1, "psicodine" = 0.1, "happiness" = 0.1) //TEMPORARY UNTIL HEADMINS GIVE THE OKAY FOR MK USE.
+ //required_reagents = list("cocoa" = 1, "astral" = 1, "mindbreaker" = 1, "psicodine" = 1, "happiness" = 1)
+ required_reagents = list("cocoa" = 1, "bluespace" = 1, "mindbreaker" = 1, "psicodine" = 1, "happiness" = 1) //TEMPORARY UNTIL HEADMINS GIVE THE OKAY FOR MK USE.
required_catalysts = list("blood" = 1)
mix_message = "the reaction gives off a burgundy plume of smoke!"
//FermiChem vars:
@@ -360,8 +360,8 @@
/datum/chemical_reaction/fermi/hatmium // done
name = "Hat growth serum"
id = "hatmium"
- results = list("hatmium" = 0.5)
- required_reagents = list("ethanol" = 0.1, "nutriment" = 0.3, "cooking_oil" = 0.2, "iron" = 0.1, "gold" = 0.3)
+ results = list("hatmium" = 5)
+ required_reagents = list("ethanol" = 1, "nutriment" = 3, "cooking_oil" = 2, "iron" = 1, "gold" = 3)
//mix_message = ""
//FermiChem vars:
OptimalTempMin = 500
@@ -395,8 +395,8 @@
/datum/chemical_reaction/fermi/furranium
name = "Furranium"
id = "furranium"
- results = list("furranium" = 0.5)
- required_reagents = list("aphro" = 0.1, "moonsugar" = 0.1, "silver" = 0.2, "salglu_solution" = 0.1)
+ results = list("furranium" = 5)
+ required_reagents = list("aphro" = 1, "moonsugar" = 1, "silver" = 2, "salglu_solution" = 1)
mix_message = "You think you can hear a howl come from the beaker."
//FermiChem vars:
OptimalTempMin = 350
@@ -415,7 +415,7 @@
PurityMin = 0.3
/datum/chemical_reaction/fermi/furranium/organic
- required_reagents = list("aphro" = 0.1, "catnip" = 0.1, "silver" = 0.2, "salglu_solution" = 0.1)
+ required_reagents = list("aphro" = 1, "catnip" = 1, "silver" = 2, "salglu_solution" = 1)
//FOR INSTANT REACTIONS - DO NOT MULTIPLY LIMIT BY 10.
//There's a weird rounding error or something ugh.
@@ -446,8 +446,8 @@
/datum/chemical_reaction/fermi/acidic_buffer//done test
name = "Acetic acid buffer"
id = "acidic_buffer"
- results = list("acidic_buffer" = 2) //acetic acid
- required_reagents = list("salglu_solution" = 0.2, "ethanol" = 0.6, "oxygen" = 0.6, "water" = 0.6)
+ results = list("acidic_buffer" = 10) //acetic acid
+ required_reagents = list("salglu_solution" = 1, "ethanol" = 3, "oxygen" = 3, "water" = 3)
//FermiChem vars:
OptimalTempMin = 250
OptimalTempMax = 500
@@ -473,10 +473,10 @@
/datum/chemical_reaction/fermi/basic_buffer//done test
name = "Ethyl Ethanoate buffer"
id = "basic_buffer"
- results = list("basic_buffer" = 1.5)
- required_reagents = list("lye" = 0.3, "ethanol" = 0.6, "water" = 0.6)
+ results = list("basic_buffer" = 5)
+ required_reagents = list("lye" = 1, "ethanol" = 2, "water" = 2)
required_catalysts = list("sacid" = 1) //vagely acetic
- //FermiChem vars:x
+ //FermiChem vars:
OptimalTempMin = 250
OptimalTempMax = 500
ExplodeTemp = 9999 //check to see overflow doesn't happen!
@@ -505,8 +505,8 @@
/datum/chemical_reaction/fermi/secretcatchem //DONE
name = "secretcatchem"
id = "secretcatchem"
- results = list("secretcatchem" = 0.5)
- required_reagents = list("stable_plasma" = 0.1, "sugar" = 0.1, "cream" = 0.1, "clonexadone" = 0.1)//Yes this will make a plushie if you don't lucky guess. It'll eat all your reagents too.
+ results = list("secretcatchem" = 5)
+ required_reagents = list("stable_plasma" = 1, "sugar" = 1, "cream" = 1, "clonexadone" = 1)//Yes this will make a plushie if you don't lucky guess. It'll eat all your reagents too.
required_catalysts = list("SDGF" = 1)
required_temp = 600
mix_message = "the reaction gives off a meow!"
@@ -539,7 +539,7 @@
RateUpLim += (rand(1, 1000)/100)
PurityMin += (rand(-1, 1)/10)
var/additions = list("aluminium", "silver", "gold", "plasma", "silicon", "uranium", "milk")
- required_reagents[pick(additions)] = rand(0.1, 0.5)//weird
+ required_reagents[pick(additions)] = rand(1, 5)//weird
/datum/chemical_reaction/fermi/secretcatchem/FermiFinish(datum/reagents/holder, var/atom/my_atom)
SSblackbox.record_feedback("tally", "catgirlium")//log
@@ -558,8 +558,8 @@
/datum/chemical_reaction/fermi/yamerol//done test
name = "Yamerol"
id = "yamerol"
- results = list("yamerol" = 1.5)
- required_reagents = list("perfluorodecalin" = 0.5, "salbutamol" = 0.5, "water" = 0.5)
+ results = list("yamerol" = 3)
+ required_reagents = list("perfluorodecalin" = 1, "salbutamol" = 1, "water" = 1)
//FermiChem vars:
OptimalTempMin = 300
OptimalTempMax = 500
diff --git a/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm b/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
index 9e7da03f9b..4aa634a488 100755
--- a/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
+++ b/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
@@ -96,7 +96,10 @@
/obj/item/hypospray/mkii/examine(mob/user)
. = ..()
- to_chat(user, "[vial] has [vial.reagents.total_volume]u remaining.")
+ if(vial)
+ to_chat(user, "[vial] has [vial.reagents.total_volume]u remaining.")
+ else
+ to_chat(user, "It has no vial loaded in.")
to_chat(user, "[src] is set to [mode ? "Inject" : "Spray"] contents on application.")
/obj/item/hypospray/mkii/proc/unload_hypo(obj/item/I, mob/user)
diff --git a/sound/creatures/goose1.ogg b/sound/creatures/goose1.ogg
new file mode 100644
index 0000000000..3d605ad622
Binary files /dev/null and b/sound/creatures/goose1.ogg differ
diff --git a/sound/creatures/goose2.ogg b/sound/creatures/goose2.ogg
new file mode 100644
index 0000000000..735faba791
Binary files /dev/null and b/sound/creatures/goose2.ogg differ
diff --git a/sound/creatures/goose3.ogg b/sound/creatures/goose3.ogg
new file mode 100644
index 0000000000..1aeec77369
Binary files /dev/null and b/sound/creatures/goose3.ogg differ
diff --git a/sound/creatures/goose4.ogg b/sound/creatures/goose4.ogg
new file mode 100644
index 0000000000..699f143bd3
Binary files /dev/null and b/sound/creatures/goose4.ogg differ
diff --git a/sound/spookoween/ahaha.ogg b/sound/spookoween/ahaha.ogg
new file mode 100644
index 0000000000..2e830ad6c7
Binary files /dev/null and b/sound/spookoween/ahaha.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index dc556999d2..b2a58fe27f 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -231,6 +231,7 @@
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\augury.dm"
#include "code\controllers\subsystem\blackbox.dm"
+#include "code\controllers\subsystem\chat.dm"
#include "code\controllers\subsystem\communications.dm"
#include "code\controllers\subsystem\dbcore.dm"
#include "code\controllers\subsystem\dcs.dm"
@@ -1706,6 +1707,9 @@
#include "code\modules\goonchat\jsErrorHandler.dm"
#include "code\modules\holiday\easter.dm"
#include "code\modules\holiday\holidays.dm"
+#include "code\modules\holiday\halloween\bartholomew.dm"
+#include "code\modules\holiday\halloween\halloween.dm"
+#include "code\modules\holiday\halloween\jacqueen.dm"
#include "code\modules\holodeck\area_copy.dm"
#include "code\modules\holodeck\computer.dm"
#include "code\modules\holodeck\holo_effect.dm"
@@ -2199,6 +2203,7 @@
#include "code\modules\mob\living\simple_animal\hostile\eyeballs.dm"
#include "code\modules\mob\living\simple_animal\hostile\faithless.dm"
#include "code\modules\mob\living\simple_animal\hostile\giant_spider.dm"
+#include "code\modules\mob\living\simple_animal\hostile\goose.dm"
#include "code\modules\mob\living\simple_animal\hostile\headcrab.dm"
#include "code\modules\mob\living\simple_animal\hostile\hivebot.dm"
#include "code\modules\mob\living\simple_animal\hostile\hostile.dm"