diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index c157be159a4e..c1472d132ff8 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -9908,8 +9908,9 @@
"doR" = (
/obj/machinery/power/apc/auto_name/directional/south,
/obj/structure/cable,
-/obj/effect/mapping_helpers/apc/cell_5k,
/obj/machinery/plumbing/ooze_compressor,
+/obj/effect/mapping_helpers/apc/cell_10k,
+/obj/effect/mapping_helpers/apc/full_charge,
/turf/open/floor/iron/white,
/area/station/science/xenobiology)
"doW" = (
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 29a07339b6ba..43768adc6127 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -42678,6 +42678,8 @@
/obj/effect/turf_decal/siding/purple{
dir = 9
},
+/obj/effect/mapping_helpers/apc/cell_10k,
+/obj/effect/mapping_helpers/apc/full_charge,
/turf/open/floor/iron,
/area/station/science/xenobiology)
"kpy" = (
@@ -89711,6 +89713,11 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron,
/area/station/engineering/atmos)
+"vUy" = (
+/obj/machinery/duct,
+/obj/machinery/light/floor/has_bulb,
+/turf/open/floor/engine,
+/area/station/science/xenobiology)
"vUz" = (
/obj/structure/disposalpipe/segment,
/turf/open/floor/iron/white,
@@ -121069,7 +121076,7 @@ feF
gcr
pTC
iLv
-gvX
+vUy
duq
fMl
fMl
@@ -121079,7 +121086,7 @@ taA
fMl
fMl
xsN
-gvX
+vUy
iLv
mAt
aAx
@@ -122868,7 +122875,7 @@ woj
rrU
pTC
iLv
-gvX
+vUy
pQz
fMl
fMl
@@ -122878,7 +122885,7 @@ taA
fMl
fMl
esm
-gvX
+vUy
iLv
mAt
cZl
diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
index 6cae56e2d386..10dc68395186 100644
--- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm
+++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
@@ -1194,6 +1194,8 @@
},
/obj/machinery/power/apc/auto_name/directional/south,
/obj/structure/cable,
+/obj/effect/mapping_helpers/apc/cell_10k,
+/obj/effect/mapping_helpers/apc/full_charge,
/turf/open/floor/iron/white,
/area/station/science/xenobiology)
"aut" = (
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index bcc8844dcc25..b477ff8f1011 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -13278,6 +13278,8 @@
/obj/effect/turf_decal/tile/purple/half/contrasted{
dir = 8
},
+/obj/effect/mapping_helpers/apc/cell_10k,
+/obj/effect/mapping_helpers/apc/full_charge,
/turf/open/floor/iron/white,
/area/station/science/cytology)
"eYw" = (
@@ -32577,8 +32579,6 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/duct,
-/obj/machinery/power/apc/auto_name/directional/west,
-/obj/structure/cable,
/turf/open/floor/stone,
/area/station/science/xenobiology)
"lJh" = (
@@ -49930,6 +49930,10 @@
/obj/effect/turf_decal/stripes/line{
dir = 9
},
+/obj/effect/mapping_helpers/apc/cell_10k,
+/obj/machinery/power/apc/auto_name/directional/north,
+/obj/effect/mapping_helpers/apc/full_charge,
+/obj/structure/cable,
/turf/open/floor/stone,
/area/station/science/xenobiology)
"rMz" = (
diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm
index 096c0677e899..cef5e292f535 100644
--- a/_maps/map_files/tramstation/tramstation.dmm
+++ b/_maps/map_files/tramstation/tramstation.dmm
@@ -44309,6 +44309,16 @@
/obj/structure/cable,
/turf/open/floor/carpet,
/area/station/command/heads_quarters/hos)
+"nme" = (
+/obj/effect/turf_decal/trimline/purple/filled/line{
+ dir = 1
+ },
+/obj/machinery/power/apc/auto_name/directional/north,
+/obj/structure/cable,
+/obj/effect/mapping_helpers/apc/cell_10k,
+/obj/effect/mapping_helpers/apc/full_charge,
+/turf/open/floor/stone,
+/area/station/science/xenobiology)
"nmf" = (
/obj/structure/table/wood,
/obj/machinery/computer/security/wooden_tv,
@@ -54558,14 +54568,6 @@
/obj/structure/cable,
/turf/open/space/basic,
/area/space/nearstation)
-"qCW" = (
-/obj/effect/turf_decal/trimline/purple/filled/line{
- dir = 1
- },
-/obj/machinery/power/apc/auto_name/directional/north,
-/obj/structure/cable,
-/turf/open/floor/stone,
-/area/station/science/xenobiology)
"qCX" = (
/obj/effect/turf_decal/stripes/line{
dir = 9
@@ -67170,6 +67172,16 @@
/obj/machinery/door/firedoor,
/turf/open/floor/iron,
/area/station/cargo/drone_bay)
+"uAW" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/cable,
+/obj/structure/disposalpipe/segment{
+ dir = 10
+ },
+/turf/open/floor/catwalk_floor,
+/area/station/maintenance/starboard/central)
"uAZ" = (
/obj/effect/turf_decal/trimline/white/warning{
dir = 8
@@ -124257,7 +124269,7 @@ xPQ
vud
tml
qVr
-qCW
+nme
pbt
xcM
dtN
@@ -126540,8 +126552,8 @@ hFC
bwz
xks
qxm
-icR
-icR
+uAW
+lLW
iix
tuN
tuN
@@ -127825,7 +127837,7 @@ oys
oys
gDw
gDw
-nop
+bay
nop
hPn
eyE
@@ -128080,8 +128092,8 @@ kHX
gDw
gDw
gDw
-nop
-nop
+bay
+uJu
nop
oys
oys
diff --git a/_maps/~monkestation/RandomBars/Icebox/BarSM.dmm b/_maps/~monkestation/RandomBars/Icebox/BarSM.dmm
index a283cdc68cd6..3b341440cb3c 100644
--- a/_maps/~monkestation/RandomBars/Icebox/BarSM.dmm
+++ b/_maps/~monkestation/RandomBars/Icebox/BarSM.dmm
@@ -1385,6 +1385,7 @@
/obj/effect/turf_decal/trimline/yellow/warning{
dir = 5
},
+/obj/effect/mapping_helpers/mail_sorting/service/bar,
/turf/open/floor/pod/dark,
/area/station/commons/lounge)
"Vg" = (
diff --git a/_maps/~monkestation/RandomBars/Icebox/clockwork_icebox.dmm b/_maps/~monkestation/RandomBars/Icebox/clockwork_icebox.dmm
index e2dfb4976558..a8890927c179 100644
--- a/_maps/~monkestation/RandomBars/Icebox/clockwork_icebox.dmm
+++ b/_maps/~monkestation/RandomBars/Icebox/clockwork_icebox.dmm
@@ -304,10 +304,11 @@
"oS" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/structure/disposalpipe/junction/flip{
+/obj/structure/cable,
+/obj/structure/disposalpipe/sorting/mail/flip{
dir = 4
},
-/obj/structure/cable,
+/obj/effect/mapping_helpers/mail_sorting/service/bar,
/turf/open/floor/bronze,
/area/station/commons/lounge)
"qk" = (
@@ -412,16 +413,6 @@
},
/turf/open/floor/bronze/filled,
/area/station/service/bar)
-"va" = (
-/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible/layer2,
-/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/obj/effect/mapping_helpers/mail_sorting/service/bar,
-/obj/structure/cable,
-/turf/open/floor/bronze,
-/area/station/commons/lounge)
"vh" = (
/obj/structure/chair/bronze{
dir = 1
@@ -993,7 +984,7 @@ Pz
Xo
cx
vh
-va
+Xp
TP
EK
EK
diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm
index 18a07c0d0197..b86931a592a5 100644
--- a/code/__DEFINES/maths.dm
+++ b/code/__DEFINES/maths.dm
@@ -7,6 +7,9 @@
#define IS_FINITE__UNSAFE(a) (a-a == a-a)
#define IS_FINITE(a) (isnum(a) && IS_FINITE__UNSAFE(a))
+
+#define IS_SAFE_NUM(a) (isnum(a) && !IS_INF__UNSAFE(a) && IS_FINITE__UNSAFE(a))
+
// ------------------------------------
// Aight dont remove the rest
diff --git a/code/__DEFINES/~monkestation/clock_cult.dm b/code/__DEFINES/~monkestation/clock_cult.dm
index 8a1bb92a7446..e9c9424b50dd 100644
--- a/code/__DEFINES/~monkestation/clock_cult.dm
+++ b/code/__DEFINES/~monkestation/clock_cult.dm
@@ -5,5 +5,16 @@
#define SIGIL_TRANSMISSION_RANGE 4
+///base state the ark is created in, any state besides this will be a hostile environment
+#define ARK_STATE_BASE 0
+///state for the grace period after the cult has reached its member count max and have enough activing anchoring crystals to summon
+#define ARK_STATE_CHARGING 1
+///state for after the cult has been annouced as well as the first half of the assault
+#define ARK_STATE_ACTIVE 2
+///state for the halfway point of ark activation
+#define ARK_STATE_SUMMONING 3
+///the ark has either finished opening or been destroyed in this state
+#define ARK_STATE_FINAL 4
+
///max damage taken per hit by "important" clock structures
#define MAX_IMPORTANT_CLOCK_DAMAGE 30
diff --git a/code/__DEFINES/~monkestation/traits.dm b/code/__DEFINES/~monkestation/traits.dm
index 0ab61cb18a9a..91ef22414513 100644
--- a/code/__DEFINES/~monkestation/traits.dm
+++ b/code/__DEFINES/~monkestation/traits.dm
@@ -14,6 +14,8 @@
#define TRAIT_ALL_SURGERIES "all_surgeries"
/// Prevents the user from ever (unintentionally) failing a surgery step, and ensures they always have the maximum surgery speed.
#define TRAIT_PERFECT_SURGEON "perfect_surgeon"
+/// Prevents the user from casting spells using sign language. Works on both /datum/mind and /mob/living.
+#define TRAIT_CANT_SIGN_SPELLS "cant_sign_spells"
/// Station trait for when the clown has bridge access *shudders*
#define STATION_TRAIT_CLOWN_BRIDGE "clown_bridge"
diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm
index 6d294a153cdc..2b2ee17563d0 100644
--- a/code/_globalvars/traits.dm
+++ b/code/_globalvars/traits.dm
@@ -201,6 +201,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_EXPANDED_FOV" = TRAIT_EXPANDED_FOV,
"TRAIT_ANALGESIA" = TRAIT_ANALGESIA,
"TRAIT_ON_ELEVATED_SURFACE" = TRAIT_ON_ELEVATED_SURFACE,
+ "TRAIT_CANT_SIGN_SPELLS" = TRAIT_CANT_SIGN_SPELLS, // monke edit
),
/obj/item/bodypart = list(
"TRAIT_PARALYSIS" = TRAIT_PARALYSIS,
diff --git a/code/controllers/subsystem/polling.dm b/code/controllers/subsystem/polling.dm
index 2bed96ac7d40..6d9821ca85be 100644
--- a/code/controllers/subsystem/polling.dm
+++ b/code/controllers/subsystem/polling.dm
@@ -181,6 +181,9 @@ SUBSYSTEM_DEF(polling)
/datum/controller/subsystem/polling/proc/poll_ghost_candidates_for_mob(question, role, check_jobban, poll_time = 30 SECONDS, mob/target_mob, ignore_category = null, flashwindow = TRUE, pic_source, role_name_text)
var/static/list/mob/currently_polling_mobs = list()
+ if(!isnull(target_mob) && !ismob(target_mob))
+ stack_trace("attempted to use a non-mob as the target mob ([target_mob] | [target_mob.type])")
+
if(currently_polling_mobs.Find(target_mob))
return list()
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index 2ef99e3dc5f2..99d5fd4e91c9 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -508,6 +508,7 @@
/obj/item/reagent_containers/syringe,
/obj/item/slime_extract,
/obj/item/swab,
+ /obj/item/stack/biomass // monke: make science bags able to hold biomass cubes
))
/*
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index 736e438ab6c1..b1c08db0e731 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -1227,8 +1227,8 @@
var/particle_chance = ((PARTICLE_CHANCE_CONSTANT)/(reaction_energy-PARTICLE_CHANCE_CONSTANT)) + 1//Asymptopically approaches 100% as the energy of the reaction goes up.
if(prob(PERCENT(particle_chance)))
location.fire_nuclear_particle()
- var/rad_power = max((FUSION_RAD_COEFFICIENT/instability) + 5000, 0)
- radiation_pulse(location,rad_power)
+ var/rad_power = max((FUSION_RAD_COEFFICIENT/instability) + 250, 15000) //Wow!
+ radiation_pulse(location, rand(1,30), 9, 60, 2 SECONDS, rad_power, 1) // Nonmodular. Fixes fusion going wacko mode - makes it significantly harder to irradiate people through walls, and fixes the range issue.
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY && (air.temperature <= FUSION_MAXIMUM_TEMPERATURE || reaction_energy <= 0)) //If above FUSION_MAXIMUM_TEMPERATURE, will only adjust temperature for endothermic reactions.
air.temperature = clamp(((air.temperature*old_heat_capacity + reaction_energy)/new_heat_capacity),TCMB,INFINITY)
diff --git a/code/modules/mob/living/basic/guardian/guardian_verbs.dm b/code/modules/mob/living/basic/guardian/guardian_verbs.dm
index abf536503b2a..f2e81306c515 100644
--- a/code/modules/mob/living/basic/guardian/guardian_verbs.dm
+++ b/code/modules/mob/living/basic/guardian/guardian_verbs.dm
@@ -170,9 +170,8 @@
"Do you want to play as [owner.real_name]'s [chosen_guardian.theme.name]?",
check_jobban = ROLE_PAI,
poll_time = 10 SECONDS,
- target_mob = src,
+ target_mob = owner,
ignore_category = POLL_IGNORE_HOLOPARASITE,
- pic_source = src,
role_name_text = chosen_guardian.theme.name
)
if (!LAZYLEN(ghost_candidates))
diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm
index 52f516ee4060..d1488a60b3bb 100644
--- a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm
+++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm
@@ -36,13 +36,6 @@
modified_speech = copytext_char(speech, 3)
else
- // monke start - stfu poly
- var/speak_prob = speaking_pawn.ears.use_command ? 25 : 50
- for(var/channel in list(RADIO_KEY_COMMON, RADIO_TOKEN_COMMAND))
- if(channel in available_channels)
- speak_prob = max(FLOOR(speak_prob * 0.4, 5), 5)
- use_radio = prob(speak_prob)
- // monke end
if(HAS_CHANNEL_PREFIX)
modified_speech = "[use_radio ? pick(available_channels) : ""][copytext_char(speech, 3)]"
else
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index a7c6c3baed07..366e4d2e692a 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -470,8 +470,8 @@
colour = "grey"
/datum/status_effect/stabilized/grey/tick()
- for(var/mob/living/basic/slime/S in range(1, get_turf(owner)))
- SEND_SIGNAL(S, COMSIG_FRIENDSHIP_CHANGE, owner, 1)
+ for(var/mob/living/basic/slime/new_friend in range(3, get_turf(owner)))
+ SEND_SIGNAL(new_friend, COMSIG_FRIENDSHIP_CHANGE, owner, 1)
return ..()
/datum/status_effect/stabilized/orange
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index b72a363faaf9..77d567b78186 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -378,6 +378,8 @@
return FALSE
if((invocation_type == INVOCATION_WHISPER || invocation_type == INVOCATION_SHOUT) && !living_owner.can_speak())
+ if(HAS_TRAIT(living_owner, TRAIT_SIGN_LANG) && !HAS_MIND_TRAIT(living_owner, TRAIT_CANT_SIGN_SPELLS)) // monkestation edit: allow sign language users to cast spells
+ return TRUE
if(feedback)
to_chat(owner, span_warning("You can't get the words out to invoke [src]!"))
return FALSE
diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm
index deae8acc20fe..6a8f4fa52bb8 100644
--- a/code/modules/vending/autodrobe.dm
+++ b/code/modules/vending/autodrobe.dm
@@ -14,6 +14,8 @@
"products" = list(
/obj/item/clothing/under/costume/gladiator = 1,
/obj/item/clothing/head/helmet/gladiator = 1,
+ /obj/item/clothing/head/viking/fake_helmet = 1, //monkestation edit
+ /obj/item/clothing/under/viking/fake_tunic = 1, //monkestation edit
/obj/item/clothing/suit/toggle/labcoat/mad = 1,
/obj/item/clothing/suit/bio_suit/plaguedoctorsuit = 1,
/obj/item/clothing/head/bio_hood/plague = 1,
diff --git a/html/changelogs/AutoChangeLog-pr-1638.yml b/html/changelogs/AutoChangeLog-pr-1638.yml
new file mode 100644
index 000000000000..f4143ee6fb7c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1638.yml
@@ -0,0 +1,16 @@
+author: "Absolucy"
+delete-after: True
+changes:
+ - rscadd: "Added a HUD that appears when hovering your mouse over ooze compressors, showing the current extract it is making, and the progress on making said extract."
+ - bugfix: "Fixed the normal slime extract menu coming up on ooze compressors after selecting a crossbreed."
+ - bugfix: "Fixed xenobiology machinery taking up absurd amounts of power while doing nothing."
+ - balance: "Increased range of stabilized grey extract from 1 to 3."
+ - qol: "Increased biomass cube stack size (5 -> 15)."
+ - qol: "Biocubes now fit in science bags."
+ - qol: "You can dump biocubes from a science bag into the biomass recycler."
+ - qol: "You can right click the slime market with a science bag to sell all the extracts without the confirmation prompt."
+ - rscadd: "Added balloon alerts to lots of xenobio-related actions."
+ - qol: "You can toggle ooze suckers directly via right click."
+ - qol: "You can now right click an active ooze compressor to cancel the current recipe."
+ - qol: "Slime mutation syringes now show whether they've been used or not in the examine text."
+ - bugfix: "Removing accessories from slimes now works properly."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-1658.yml b/html/changelogs/AutoChangeLog-pr-1658.yml
new file mode 100644
index 000000000000..6e6f666425ed
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1658.yml
@@ -0,0 +1,5 @@
+author: "Absolucy"
+delete-after: True
+changes:
+ - bugfix: "Fix holoparasite resetting not working."
+ - code_imp: "Added a safety check that'll emit a (harmless) runtime if something tries to pass an invalid target mob to `SSpolling.poll_ghost_candidates_for_mob`."
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml
index 00d92a7b69be..b77717544386 100644
--- a/html/changelogs/archive/2024-04.yml
+++ b/html/changelogs/archive/2024-04.yml
@@ -172,3 +172,33 @@
2024-04-14:
KnigTheThrasher:
- rscadd: Added composters into every perma botany
+2024-04-15:
+ Absolucy:
+ - qol: People who can't taste things also can't smell things.
+ - qol: Mute people who can still use sign language are now capable of using sign
+ language to invoke spells. Wizards are still too egotistical to even consider
+ doing so, tho.
+2024-04-16:
+ KnigTheThrasher:
+ - bugfix: Fixed Icebox tests
+2024-04-17:
+ Absolucy:
+ - qol: Heavily increases and randomizes the speech cooldown of parrots.
+ DimWhat:
+ - rscadd: Added two new tails to the anime quirk
+ KittyNoodle:
+ - balance: Hardlight spears can no longer be used with scarp.
+ - balance: Hardlight spear damage and wounding reduced.
+ - balance: Hardlight spear homing removed.
+ - balance: Hardlight spear embed chance halved
+ - balance: Hardlight spears now have cooldown after firing before you can use another
+ spear.
+ KnigTheThrasher:
+ - bugfix: Tram disposals should work now
+ TTNT789:
+ - rscadd: adds a viking costume to the autodrobe
+ Yawet330:
+ - bugfix: Fusion, why?
+ wraith-54321:
+ - balance: Clockwork airlocks lose their damage deflection when placed on reebe
+ - balance: Clockwork walls take half as long to deconstruct on reebe
diff --git a/monkestation/code/__HELPERS/reagents.dm b/monkestation/code/__HELPERS/reagents.dm
index 4803b2044356..5400bdedafed 100644
--- a/monkestation/code/__HELPERS/reagents.dm
+++ b/monkestation/code/__HELPERS/reagents.dm
@@ -1,7 +1,8 @@
///Returns a random reagent object minus ethanol reagents
/proc/get_random_reagent_id_unrestricted_non_ethanol()
- var/static/list/random_reagents = list()
- if(!random_reagents.len)
+ var/static/list/random_reagents
+ if(!random_reagents)
+ random_reagents = list()
for(var/datum/reagent/reagent_path as anything in subtypesof(/datum/reagent))
if(istype(reagent_path, /datum/reagent/consumable) && !initial(reagent_path.bypass_restriction))
continue
diff --git a/monkestation/code/game/objects/items/implants/hardlight.dm b/monkestation/code/game/objects/items/implants/hardlight.dm
index 5d7518b40a53..c77e5885472c 100644
--- a/monkestation/code/game/objects/items/implants/hardlight.dm
+++ b/monkestation/code/game/objects/items/implants/hardlight.dm
@@ -234,12 +234,6 @@
back_spear_overlay.pixel_x = -32
. += back_spear_overlay
-
-/obj/item/gun/magic/hardlight_spear/can_trigger_gun(mob/living/user, akimbo_usage) // This isn't really a gun, so it shouldn't be checking for TRAIT_NOGUNS, a firing pin (pinless), or a trigger guard (guardless)
- if(akimbo_usage)
- return FALSE //this would be kinda weird while shooting someone down.
- return TRUE
-
/obj/item/gun/magic/hardlight_spear/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
. = ..()
if(!.)
@@ -247,11 +241,16 @@
if(spears_left)
var/obj/item/gun/magic/hardlight_spear/spear = new type
spear.spears_left = spears_left - 1
+ spear.apply_cooldown()
qdel(src)
user.put_in_hands(spear)
else
user.dropItemToGround(src, TRUE)
+/obj/item/gun/magic/hardlight_spear/proc/apply_cooldown()
+ semicd = TRUE
+ addtimer(CALLBACK(src, PROC_REF(reset_semicd)), 1.5 SECONDS)
+
/obj/item/ammo_casing/magic/hardlight_spear
name = "please god report this"
desc = "Why god why"
@@ -259,34 +258,23 @@
projectile_type = /obj/projectile/bullet/hardlight_spear
heavy_metal = FALSE
-/obj/item/ammo_casing/magic/hardlight_spear/ready_proj(atom/target, mob/living/user, quiet, zone_override, atom/fired_from)
- if(!loaded_projectile)
- return
-
- if(isliving(target))
- loaded_projectile.homing = TRUE
- loaded_projectile.homing_turn_speed = 40
- loaded_projectile.set_homing_target(target)
-
- return ..()
-
/obj/projectile/bullet/hardlight_spear
name = "hardlight spear"
icon = 'monkestation/icons/obj/guns/projectiles.dmi'
icon_state = "lightspear"
- damage = 45
- armour_penetration = 10
- wound_bonus = 5
- bare_wound_bonus = 60
- wound_falloff_tile = 0
- embed_falloff_tile = 0
- speed = 0.4 //lower = faster
+ damage = 40
+ armour_penetration = 5
+ wound_bonus = -5
+ bare_wound_bonus = 50
+ wound_falloff_tile = -1
+ embed_falloff_tile = -1
+ speed = 0.7 //lower = faster
shrapnel_type = /obj/item/shrapnel/bullet/spear
light_outer_range = 1
light_power = 1
hitsound = 'sound/weapons/bladeslice.ogg'
hitsound_wall = 'sound/weapons/parry.ogg'
- embedding = list(embed_chance=100, fall_chance=2, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.5, pain_mult=5, jostle_pain_mult=6, rip_time=10)
+ embedding = list(embed_chance=70, fall_chance=6, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.5, pain_mult=2, jostle_pain_mult=3, rip_time=10)
/obj/item/shrapnel/bullet/spear
name = "hardlight spear"
diff --git a/monkestation/code/modules/antagonists/clock_cult/machines/observation_console.dm b/monkestation/code/modules/antagonists/clock_cult/machines/observation_console.dm
index be7c8c793de2..42b7795e2773 100644
--- a/monkestation/code/modules/antagonists/clock_cult/machines/observation_console.dm
+++ b/monkestation/code/modules/antagonists/clock_cult/machines/observation_console.dm
@@ -4,18 +4,23 @@
icon_screen = "ratvar1"
icon_keyboard = "ratvar_key1"
icon_state = "ratvarcomputer"
+ resistance_flags = INDESTRUCTIBLE
clockwork = TRUE
lock_override = TRUE
circuit = /obj/item/circuitboard/machine/camera_console_ratvar
+ ///List of areas we are allowed to warp to
+ var/static/list/allowed_areas = list()
/obj/machinery/computer/camera_advanced/ratvar/Initialize(mapload)
. = ..()
START_PROCESSING(SSobj, src)
actions += new /datum/action/innate/clockcult/warp(src)
+ actions += new /datum/action/innate/clockcult/console_info(src)
+ actions += new /datum/action/innate/clockcult/add_warp_area(src, src)
/obj/machinery/computer/camera_advanced/ratvar/Destroy()
STOP_PROCESSING(SSobj, src)
- . = ..()
+ return ..()
/obj/machinery/computer/camera_advanced/ratvar/process(seconds_per_tick)
if(SPT_PROB(3, seconds_per_tick))
@@ -52,7 +57,7 @@
/datum/action/innate/clockcult/warp/Activate()
if(!isliving(owner))
return
- if(GLOB.clock_ark && GLOB.clock_ark.current_state >= 2) //equal to ARK_STATE_ACTIVE, not using the defines so we can #undef them
+ if(GLOB.clock_ark && GLOB.clock_ark.current_state >= ARK_STATE_ACTIVE)
to_chat(owner, span_brass("You cannot warp while the gateway is opening!"))
return
if(warping)
@@ -76,14 +81,34 @@
warping = TRUE
button_icon_state = "warp_cancel"
build_all_button_icons(UPDATE_BUTTON_ICON)
- if(do_after(cam_user, 5 SECONDS, target = target_loc, extra_checks = CALLBACK(src, PROC_REF(special_check))))
+ if(do_after(cam_user, 5 SECONDS, target = target_loc, extra_checks = CALLBACK(src, PROC_REF(warping_check))))
try_servant_warp(cam_user, target_loc)
button_icon_state = "warp_down"
build_all_button_icons(UPDATE_BUTTON_ICON)
warping = FALSE
-/datum/action/innate/clockcult/warp/proc/special_check()
+/datum/action/innate/clockcult/warp/proc/warping_check()
return warping
+/datum/action/innate/clockcult/console_info
+ name = "Console info"
+ desc = "Get info on this console."
+ button_icon_state = "console_info"
+
+/datum/action/innate/clockcult/add_warp_area
+ name = "Add Warp Area"
+ desc = "Add an additional area you can warp to."
+ button_icon_state = "Spatial Warp"
+ ///Ref to the console we are linked to
+ var/obj/machinery/computer/camera_advanced/ratvar/linked_console
+
+/datum/action/innate/clockcult/add_warp_area/New(Target, console)
+ . = ..()
+ linked_console = console
+
+/datum/action/innate/clockcult/add_warp_area/Destroy()
+ linked_console = null
+ return ..()
+
/obj/item/circuitboard/machine/camera_console_ratvar
build_path = /obj/machinery/computer/camera_advanced/ratvar
diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/airlock.dm b/monkestation/code/modules/antagonists/clock_cult/structures/airlock.dm
index 0b678db0a8e0..c14bf31356c6 100644
--- a/monkestation/code/modules/antagonists/clock_cult/structures/airlock.dm
+++ b/monkestation/code/modules/antagonists/clock_cult/structures/airlock.dm
@@ -11,6 +11,11 @@
req_access = list(ACCESS_CLOCKCULT)
damage_deflection = 10
+/obj/machinery/door/airlock/bronze/clock/Initialize(mapload)
+ . = ..()
+ if(on_reebe(src))
+ damage_deflection = 0
+
/obj/machinery/door/airlock/bronze/clock/canAIControl(mob/user)
return (IS_CLOCK(user) && !isAllPowerCut())
diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/the_ark.dm b/monkestation/code/modules/antagonists/clock_cult/structures/the_ark.dm
index 48fb92ad8923..a10d48c3f560 100644
--- a/monkestation/code/modules/antagonists/clock_cult/structures/the_ark.dm
+++ b/monkestation/code/modules/antagonists/clock_cult/structures/the_ark.dm
@@ -1,11 +1,6 @@
GLOBAL_DATUM(clock_ark, /obj/structure/destructible/clockwork/the_ark) //set to be equal to the ark on creation if none
GLOBAL_VAR_INIT(ratvar_risen, FALSE)
-#define ARK_STATE_BASE 0 //base state the ark is created in, any state besides this will be a hostile environment
-#define ARK_STATE_CHARGING 1 //state for the grace period after the cult has reached its member count max and have an active anchor crystal
-#define ARK_STATE_ACTIVE 2 //state for after the cult has been annouced as well as the first half of the assault
-#define ARK_STATE_SUMMONING 3 //state for the halfway point of ark activation
-#define ARK_STATE_FINAL 4 //the ark has either finished opening or been destroyed in this state
#define ARK_READY_PERIOD 300 SECONDS //how long until the cult is annouced after they reach max members, 5 minutes
#define ARK_GRACE_PERIOD 210 SECONDS //how long until the portals open after the cult is annouced, 3 minutes 30 seconds
#define ARK_ASSAULT_PERIOD 600 //how long the crew has to destroy the ark after the assault begins, 10 minutes
@@ -239,11 +234,6 @@ GLOBAL_VAR_INIT(ratvar_risen, FALSE)
explosion(pick(GLOB.abscond_markers), 50, 40, 30, 30, FALSE, TRUE)
SSticker.force_ending = TRUE
-#undef ARK_STATE_BASE
-#undef ARK_STATE_CHARGING
-#undef ARK_STATE_ACTIVE
-#undef ARK_STATE_SUMMONING
-#undef ARK_STATE_FINAL
#undef ARK_READY_PERIOD
#undef ARK_GRACE_PERIOD
#undef ARK_ASSAULT_PERIOD
diff --git a/monkestation/code/modules/antagonists/clock_cult/turf.dm b/monkestation/code/modules/antagonists/clock_cult/turf.dm
index c8e33fe5e01d..8bd077ff4d42 100644
--- a/monkestation/code/modules/antagonists/clock_cult/turf.dm
+++ b/monkestation/code/modules/antagonists/clock_cult/turf.dm
@@ -195,6 +195,9 @@
//do the deconstruction stuff, this really should be a proc on Rwalls as well
/turf/closed/wall/clockwork/proc/next_decon_state(obj/item/used_tool, mob/user, current_state, set_state, sent_message, use_time = 4 SECONDS)
+ if(on_reebe(src))
+ use_time = round(use_time / 2, 0.1) //each stage takes half as long on reebe
+
if(used_tool.use_tool(src, user, use_time, volume=100))
if(!istype(src, /turf/closed/wall/clockwork) || d_state != current_state)
return TRUE
diff --git a/monkestation/code/modules/antagonists/wizard/wizard_antagonist.dm b/monkestation/code/modules/antagonists/wizard/wizard.dm
similarity index 90%
rename from monkestation/code/modules/antagonists/wizard/wizard_antagonist.dm
rename to monkestation/code/modules/antagonists/wizard/wizard.dm
index b644296388a7..ec0c23effe79 100644
--- a/monkestation/code/modules/antagonists/wizard/wizard_antagonist.dm
+++ b/monkestation/code/modules/antagonists/wizard/wizard.dm
@@ -1,3 +1,11 @@
+/datum/antagonist/wizard/on_gain()
+ . = ..()
+ ADD_TRAIT(owner, TRAIT_CANT_SIGN_SPELLS, REF(src))
+
+/datum/antagonist/wizard/on_removal()
+ REMOVE_TRAITS_IN(owner, REF(src))
+ return ..()
+
/datum/antagonist/wizard/traitor // traitors that complete a final objective to become a wizard, this subtype is mainly for wizard look things
name = "\improper Syndicate Space Wizard"
roundend_category = "syndicate wizards/witches"
diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/anime.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/anime.dm
index 2ffaa4b5f2ef..6faea383a344 100644
--- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/anime.dm
+++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/anime.dm
@@ -165,3 +165,13 @@
/datum/sprite_accessory/anime_bottom/bunny
name = "Bunny Puff"
icon_state = "playbunny"
+
+/datum/sprite_accessory/anime_bottom/mouse
+ name = "Mouse Tail"
+ icon_state = "mouse"
+ color_src = null
+
+/datum/sprite_accessory/anime_bottom/plug
+ name = "Plug"
+ icon_state = "plug"
+ hasinner = TRUE
diff --git a/monkestation/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm b/monkestation/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm
new file mode 100644
index 000000000000..96c6ed44340c
--- /dev/null
+++ b/monkestation/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm
@@ -0,0 +1,5 @@
+/datum/ai_behavior/perform_speech/parrot
+ action_cooldown = 45 SECONDS // SHUT UP
+
+/datum/ai_behavior/perform_speech/parrot/perform(seconds_per_tick, datum/ai_controller/controller, ...)
+ controller.behavior_cooldowns[src] = world.time + rand(45 SECONDS, 3 MINUTES)
diff --git a/monkestation/code/modules/pollution/pollution.dm b/monkestation/code/modules/pollution/pollution.dm
index 548a51c0e5fd..47c35eb04491 100644
--- a/monkestation/code/modules/pollution/pollution.dm
+++ b/monkestation/code/modules/pollution/pollution.dm
@@ -38,6 +38,8 @@
/// When a user smells this pollution
/datum/pollution/proc/smell_act(mob/living/sniffer)
+ if(HAS_TRAIT(sniffer, TRAIT_AGEUSIA)) // can't taste, can't smell.
+ return
var/list/singleton_cache = SSpollution.singletons
var/datum/pollutant/dominant_pollutant
var/dominiant_smell_power
diff --git a/monkestation/code/modules/slimecore/items/mutation_syringe.dm b/monkestation/code/modules/slimecore/items/mutation_syringe.dm
index fd3998c06be8..75883df8a3ff 100644
--- a/monkestation/code/modules/slimecore/items/mutation_syringe.dm
+++ b/monkestation/code/modules/slimecore/items/mutation_syringe.dm
@@ -5,25 +5,41 @@
icon = 'monkestation/code/modules/slimecore/icons/slimes.dmi'
icon_state = "mutation_syringe"
- ///the path we infuse
+ w_class = WEIGHT_CLASS_SMALL
+
+ /// Type path of the slime trait to infuse.
var/datum/slime_trait/infusing_trait_path
- /// have we been used?
- var/used = FALSE
+ /// Amount of uses remaining.
+ var/uses = 1
+/obj/item/slime_mutation_syringe/examine(mob/user)
+ . = ..()
+ if(uses)
+ . += span_notice("It has [uses] uses left.")
+ else
+ . += span_warning("It has been completely used up.")
/obj/item/slime_mutation_syringe/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
- if(!infusing_trait_path || used)
+ if(!ispath(infusing_trait_path))
+ return
+ if(!uses)
+ user.balloon_alert(user, "used up")
+ to_chat(user, span_warning("[src] has been completely used up!"))
return
if(!istype(target, /mob/living/basic/slime))
return
var/mob/living/basic/slime/slime = target
if(slime.add_trait(infusing_trait_path))
- used = TRUE
- icon_state = "mutation_syringe-empty"
+ uses--
+ update_icon_state()
+ user.balloon_alert_to_viewers("injected mutator")
to_chat(user, span_notice("You inject [target] with [src]."))
+/obj/item/slime_mutation_syringe/update_icon_state()
+ . = ..()
+ icon_state = uses ? initial(icon_state) : "[initial(icon_state)]-empty"
/obj/item/slime_mutation_syringe/cleaner
name = "cleaner slime mutation syringe"
@@ -64,19 +80,32 @@
icon = 'monkestation/code/modules/slimecore/icons/slimes.dmi'
icon_state = "mutation_syringe"
- /// have we been used?
- var/used = FALSE
+ /// Amount of uses remaining.
+ var/uses = 1
+/obj/item/slime_mutation_syringe_random/examine(mob/user)
+ . = ..()
+ if(uses)
+ . += span_notice("It has [uses] uses left.")
+ else
+ . += span_warning("It has been completely used up.")
/obj/item/slime_mutation_syringe_random/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
- if(used)
+ if(!uses)
+ user.balloon_alert(user, "used up")
+ to_chat(user, span_warning("[src] has been completely used up!"))
return
if(!istype(target, /mob/living/basic/slime))
return
var/mob/living/basic/slime/slime = target
slime.start_mutating(TRUE)
- used = TRUE
- icon_state = "mutation_syringe-empty"
+ uses--
+ update_icon_state()
+ user.balloon_alert_to_viewers("injected mutator")
to_chat(user, span_notice("You inject [target] with [src]."))
+
+/obj/item/slime_mutation_syringe_random/update_icon_state()
+ . = ..()
+ icon_state = uses ? initial(icon_state) : "[initial(icon_state)]-empty"
diff --git a/monkestation/code/modules/slimecore/machines/biomass_recycler.dm b/monkestation/code/modules/slimecore/machines/biomass_recycler.dm
index be89b669ffe2..bdb0a50209e1 100644
--- a/monkestation/code/modules/slimecore/machines/biomass_recycler.dm
+++ b/monkestation/code/modules/slimecore/machines/biomass_recycler.dm
@@ -34,37 +34,38 @@ GLOBAL_LIST_INIT(biomass_unlocks, list())
power_change()
return TOOL_ACT_TOOLTYPE_SUCCESS
-/obj/machinery/biomass_recycler/attackby(obj/item/O, mob/user, params)
- if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", O))
- return
-
- if(default_pry_open(O))
- return
-
- if(default_deconstruction_crowbar(O))
+/obj/machinery/biomass_recycler/attackby(obj/item/item, mob/user, params)
+ . = ..()
+ if(. || default_deconstruction_screwdriver(user, "grinder_open", "grinder", item) || default_pry_open(item) || default_deconstruction_crowbar(item) || machine_stat)
return
-
- if(machine_stat) //NOPOWER etc
+ if(istype(item, /obj/item/storage/bag/xeno))
+ var/total_biomass = 0
+ for(var/obj/item/stack/biomass/biomass in item)
+ total_biomass += biomass.amount
+ stored_matter += biomass.amount
+ qdel(biomass)
+ if(total_biomass > 0)
+ to_chat(user, span_notice("You dump [total_biomass] cube\s of biomass from [item] into [src]."))
+ user.balloon_alert_to_viewers("inserted biomass")
return
-
- if(HAS_TRAIT(O, TRAIT_NODROP))
+ else if(HAS_TRAIT(item, TRAIT_NODROP))
return
-
- if(istype(O, /obj/item/stack/biomass))
- var/obj/item/stack/biomass/biomass = O
+ else if(istype(item, /obj/item/stack/biomass))
+ var/obj/item/stack/biomass/biomass = item
to_chat(user, span_notice("You insert [biomass.amount] cube\s of biomass into [src]."))
+ user.balloon_alert_to_viewers("inserted biomass")
stored_matter += biomass.amount
qdel(biomass)
return
var/can_recycle
for(var/recycable_type in recyclable_types)
- if(istype(O, recycable_type))
+ if(istype(item, recycable_type))
can_recycle = recycable_type
break
if(can_recycle)
- recycle(O, user, can_recycle)
+ recycle(item, user, can_recycle)
/obj/machinery/biomass_recycler/MouseDrop_T(mob/living/target, mob/living/user)
if(!istype(target))
@@ -125,6 +126,7 @@ GLOBAL_LIST_INIT(biomass_unlocks, list())
var/spawn_type = item_names[pick]
if(stored_matter < printable_types[spawn_type])
to_chat(user, span_warning("[src] does not have enough stored biomass for that! It currently has [stored_matter] out of [printable_types[spawn_type]] unit\s required."))
+ balloon_alert(user, "not enough biomass")
return
var/spawned = new spawn_type(user.loc)
@@ -139,7 +141,7 @@ GLOBAL_LIST_INIT(biomass_unlocks, list())
icon = 'monkestation/code/modules/slimecore/icons/stack_objects.dmi'
icon_state = "biomass"
base_icon_state = "biomass"
- max_amount = 5
+ max_amount = 15
singular_name = "biomass cube"
merge_type = /obj/item/stack/biomass
flags_1 = CONDUCT_1
diff --git a/monkestation/code/modules/slimecore/machines/extract_requestor.dm b/monkestation/code/modules/slimecore/machines/extract_requestor.dm
index 1e254d48b130..faed4fff0690 100644
--- a/monkestation/code/modules/slimecore/machines/extract_requestor.dm
+++ b/monkestation/code/modules/slimecore/machines/extract_requestor.dm
@@ -6,8 +6,8 @@
base_icon_state = "civilian_pad"
density = TRUE
use_power = IDLE_POWER_USE
- idle_power_usage = 10
- active_power_usage = 2000
+ idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION
+ active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION
circuit = /obj/item/circuitboard/machine/slime_extract_requestor
var/obj/machinery/computer/slime_market/console
var/list/current_requests = list()
diff --git a/monkestation/code/modules/slimecore/machines/ooze_compressor/ooze_compressor.dm b/monkestation/code/modules/slimecore/machines/ooze_compressor/ooze_compressor.dm
index 8baef0b70d46..5ed9b18e56d8 100644
--- a/monkestation/code/modules/slimecore/machines/ooze_compressor/ooze_compressor.dm
+++ b/monkestation/code/modules/slimecore/machines/ooze_compressor/ooze_compressor.dm
@@ -18,12 +18,13 @@
icon = 'monkestation/code/modules/slimecore/icons/machinery.dmi'
base_icon_state = "cross_compressor"
icon_state = "cross_compressor"
- category="Distribution"
+ category = "Distribution"
anchored = TRUE
- idle_power_usage = 10
- active_power_usage = 1000
+ use_power = IDLE_POWER_USE
+ idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION
+ active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION
buffer = 5000
reagent_flags = NO_REACT
@@ -74,9 +75,12 @@
/obj/machinery/plumbing/ooze_compressor/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
- context[SCREENTIP_CONTEXT_ALT_LMB] = "Toggle Repeated Extract Compression"
- context[SCREENTIP_CONTEXT_LMB] = "Select a normal extract to make"
- context[SCREENTIP_CONTEXT_RMB] = "Select a crossbreed to make"
+ if(current_recipe)
+ context[SCREENTIP_CONTEXT_RMB] = "Cancel current recipe"
+ else
+ context[SCREENTIP_CONTEXT_LMB] = "Select a normal extract to make"
+ context[SCREENTIP_CONTEXT_RMB] = "Select a crossbreed to make"
+ context[SCREENTIP_CONTEXT_CTRL_LMB] = "[repeat_recipe ? "Disable" : "Enable"] repeated extract compression"
return CONTEXTUAL_SCREENTIP_SET
/obj/machinery/plumbing/ooze_compressor/create_reagents(max_vol, flags)
@@ -86,10 +90,7 @@
/obj/machinery/plumbing/ooze_compressor/update_icon_state()
. = ..()
- if(compressing)
- icon_state = "cross_compressor_running"
- else
- icon_state = base_icon_state
+ icon_state = compressing ? "cross_compressor_running" : base_icon_state
/obj/machinery/plumbing/ooze_compressor/examine(mob/user)
. = ..()
@@ -152,44 +153,73 @@
update_appearance()
if(holder.total_volume == 0 && !compressing) //we were emptying, but now we aren't
holder.flags |= NO_REACT
+ manage_hud_as_needed()
return NONE
-/obj/machinery/plumbing/ooze_compressor/process(seconds_per_tick)
- if(!compressing)
- use_power(active_power_usage * seconds_per_tick)
-
/obj/machinery/plumbing/ooze_compressor/proc/compress_recipe()
compressing = TRUE
update_appearance()
if(!repeat_recipe)
reagents_for_recipe = list()
+ manage_hud_as_needed()
+ update_power_usage()
addtimer(CALLBACK(src, PROC_REF(finish_compressing)), 3 SECONDS)
/obj/machinery/plumbing/ooze_compressor/proc/finish_compressing()
for(var/i in 1 to current_recipe.created_amount)
- new current_recipe.output_item(loc)
+ new current_recipe.output_item(drop_location())
compressing = FALSE
update_appearance()
reagents.clear_reagents()
if(!repeat_recipe)
current_recipe = null
+ update_power_usage()
+ manage_hud_as_needed()
+
+/obj/machinery/plumbing/ooze_compressor/proc/update_power_usage()
+ if(compressing)
+ update_use_power(ACTIVE_POWER_USE)
+ else if(current_recipe)
+ update_use_power(IDLE_POWER_USE)
+ else
+ update_use_power(NO_POWER_USE)
/obj/machinery/plumbing/ooze_compressor/attack_hand(mob/living/user, list/modifiers)
. = ..()
+ if(. || !can_interact(user))
+ return
+ if(!anchored)
+ balloon_alert(user, "unanchored!")
+ return TRUE
if(change_recipe(user))
reagents.clear_reagents()
+ return TRUE
/obj/machinery/plumbing/ooze_compressor/attack_hand_secondary(mob/living/user, list/modifiers)
. = ..()
- if(change_recipe(user, TRUE))
- reagents.clear_reagents()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN || !can_interact(user))
+ return
+ . = SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ if(!anchored)
+ balloon_alert(user, "unanchored!")
+ return
+ if(current_recipe)
+ repeat_recipe = FALSE
+ if(!compressing)
+ current_recipe = null
+ reagents.clear_reagents()
+ update_power_usage()
+ balloon_alert_to_viewers("cancelled recipe")
+ else
+ if(change_recipe(user, TRUE))
+ reagents.clear_reagents()
-/obj/machinery/plumbing/ooze_compressor/AltClick(mob/user)
- if(anchored)
- visible_message(span_notice("[user] presses a button turning the repeat recipe system [repeat_recipe ? "Off" : "On"]"))
+/obj/machinery/plumbing/ooze_compressor/CtrlClick(mob/user)
+ if(anchored && can_interact(user))
repeat_recipe = !repeat_recipe
- return TRUE
- . = ..()
+ balloon_alert_to_viewers("[repeat_recipe ? "enabled" : "disabled"] repeating")
+ visible_message(span_notice("[user] presses a button turning the repeat recipe system [repeat_recipe ? span_green("on") : span_red("off")]"))
+ return ..()
/obj/machinery/plumbing/ooze_compressor/proc/change_recipe(mob/user, cross_breed = FALSE)
var/choice
@@ -201,14 +231,14 @@
else
choice = show_radial_menu(user, src, recipe_choices, require_near = TRUE, tooltips = TRUE)
- if(!(choice in choice_to_datum))
- return
-
- if(compressing)
+ if(compressing || !(choice in choice_to_datum))
return
current_recipe = choice_to_datum[choice]
reagents_for_recipe = list()
reagents_for_recipe += current_recipe.required_oozes
+ balloon_alert_to_viewers("set extract recipe")
+ manage_hud_as_needed()
+ update_power_usage()
#undef CROSSBREED_BASE_PATHS
diff --git a/monkestation/code/modules/slimecore/machines/ooze_compressor/ooze_compressor_hud.dm b/monkestation/code/modules/slimecore/machines/ooze_compressor/ooze_compressor_hud.dm
new file mode 100644
index 000000000000..bec098500afa
--- /dev/null
+++ b/monkestation/code/modules/slimecore/machines/ooze_compressor/ooze_compressor_hud.dm
@@ -0,0 +1,127 @@
+/obj/machinery/plumbing/ooze_compressor
+ var/image/hover_appearance
+ var/datum/atom_hud/alternate_appearance/basic/ooze_compressor/hover_popup
+
+/obj/machinery/plumbing/ooze_compressor/Destroy()
+ QDEL_NULL(hover_popup)
+ return ..()
+
+/obj/machinery/plumbing/ooze_compressor/MouseEntered(location, control, params)
+ . = ..()
+ if(!QDELETED(usr) && anchored)
+ manage_hud_as_needed()
+ hover_popup?.show_to(usr)
+
+/obj/machinery/plumbing/ooze_compressor/MouseExited(location, control, params)
+ . = ..()
+ if(!QDELETED(usr) && !QDELETED(hover_popup))
+ hover_popup.hide_from(usr)
+ manage_hud_as_needed(cleanup = TRUE)
+
+/obj/machinery/plumbing/ooze_compressor/set_anchored(anchorvalue)
+ . = ..()
+ if(!anchored)
+ manage_hud_as_needed()
+
+/obj/machinery/plumbing/ooze_compressor/proc/manage_hud_as_needed(cleanup = FALSE)
+ if(!anchored || (cleanup && !QDELETED(hover_popup) && !length(hover_popup.hud_users_all_z_levels)))
+ // don't bother keeping the hud around if it isn't needed
+ QDEL_NULL(hover_popup)
+ return
+ setup_hud()
+
+/obj/machinery/plumbing/ooze_compressor/proc/setup_hud()
+ // delete old hud if it exists and collect a list of its users
+ var/list/mob/old_users
+ if(!QDELETED(hover_popup))
+ old_users = hover_popup.hud_users_all_z_levels.Copy()
+ QDEL_NULL(hover_popup)
+
+ if(!length(GLOB.compressor_recipe_previews)) // we can't initialize this normally bc it will shit itself if initialized early
+ GLOB.compressor_recipe_previews = create_compressor_previews()
+
+ // setup new hover appearance
+ if(current_recipe)
+ hover_appearance = image(GLOB.compressor_recipe_previews[current_recipe.type], loc = src, layer = CHAT_LAYER)
+ hover_appearance.add_filter("extract_outline", 1, outline_filter(size = 1, color = COLOR_WHITE))
+ hover_appearance.pixel_y = 10
+ else
+ hover_appearance = image(loc = src, layer = CHAT_LAYER)
+ hover_appearance.pixel_y = 18
+ SET_PLANE_EXPLICIT(hover_appearance, HUD_PLANE, src)
+ hover_appearance.plane = HUD_PLANE
+ hover_appearance.appearance_flags = RESET_COLOR
+
+ // now setup the actual hud
+ hover_popup = add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/ooze_compressor, "ooze_compressor", hover_appearance)
+ // and the cooldown maptext
+ refresh_info_maptext()
+
+ for(var/mob/old_user as anything in old_users)
+ if(QDELETED(old_user))
+ continue
+ hover_popup.show_to(old_user)
+
+/obj/machinery/plumbing/ooze_compressor/proc/refresh_info_maptext()
+ if(!hover_popup)
+ return
+ if(!hover_popup.info_maptext)
+ hover_popup.info_maptext = image(loc = src, layer = CHAT_LAYER + 0.1)
+ SET_PLANE_EXPLICIT(hover_popup.info_maptext, HUD_PLANE, src)
+ hover_popup.info_maptext.plane = HUD_PLANE
+ hover_popup.info_maptext.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART
+ hover_popup.info_maptext.maptext_height = world.icon_size / 2
+ hover_popup.info_maptext.maptext_y = 4
+ var/maptext
+ if(compressing)
+ hover_popup.info_maptext.maptext_width = world.icon_size * 2
+ hover_popup.info_maptext.maptext_x = -(world.icon_size / 2)
+ maptext = "compressing..."
+ else
+ hover_popup.info_maptext.maptext_width = world.icon_size
+ hover_popup.info_maptext.maptext_x = 0
+ maptext = current_recipe ? "[get_progress()]%" : "inactive"
+ hover_popup.info_maptext.maptext = MAPTEXT_TINY_UNICODE("[maptext]")
+ hover_popup.give_info()
+
+/obj/machinery/plumbing/ooze_compressor/proc/get_progress()
+ if(!current_recipe || compressing)
+ return 0
+ var/current = 0
+ var/needed = 0
+ for(var/datum/reagent/reagent as anything in current_recipe.required_oozes)
+ needed += current_recipe.required_oozes[reagent] || 0
+ for(var/datum/reagent/listed_reagent as anything in reagents.reagent_list)
+ if(listed_reagent.type != reagent)
+ continue
+ current += listed_reagent.volume
+ return clamp(round((current / needed) * 100, 1), 0, 100)
+
+/datum/atom_hud/alternate_appearance/basic/ooze_compressor
+ var/image/info_maptext
+
+/datum/atom_hud/alternate_appearance/basic/ooze_compressor/show_to(mob/new_viewer)
+ . = ..()
+ if(info_maptext && !QDELETED(new_viewer) && !QDELETED(new_viewer.client))
+ new_viewer.client.images |= info_maptext
+
+/datum/atom_hud/alternate_appearance/basic/ooze_compressor/hide_from(mob/former_viewer, absolute)
+ . = ..()
+ if(info_maptext && !QDELETED(former_viewer) && !QDELETED(former_viewer.client))
+ former_viewer.client.images -= info_maptext
+
+/datum/atom_hud/alternate_appearance/basic/ooze_compressor/proc/give_info()
+ if(!info_maptext)
+ return
+ for(var/mob/user as anything in hud_users_all_z_levels)
+ if(QDELETED(user) || QDELETED(user.client))
+ continue
+ user.client.images |= info_maptext
+
+/datum/atom_hud/alternate_appearance/basic/ooze_compressor/proc/take_cooldowns()
+ if(!info_maptext)
+ return
+ for(var/mob/user as anything in hud_users_all_z_levels)
+ if(QDELETED(user) || QDELETED(user.client))
+ continue
+ user.client.images -= info_maptext
diff --git a/monkestation/code/modules/slimecore/machines/ooze_compressor/recipes/_base_recipe.dm b/monkestation/code/modules/slimecore/machines/ooze_compressor/recipes/_base_recipe.dm
index a60288732cb3..dbc827f25b35 100644
--- a/monkestation/code/modules/slimecore/machines/ooze_compressor/recipes/_base_recipe.dm
+++ b/monkestation/code/modules/slimecore/machines/ooze_compressor/recipes/_base_recipe.dm
@@ -1,6 +1,18 @@
+GLOBAL_LIST_EMPTY_TYPED(compressor_recipe_previews, /image)
+
/datum/compressor_recipe
var/list/required_oozes = list()
var/obj/item/output_item
var/created_amount = 1
/datum/compressor_recipe/crossbreed
+
+/proc/create_compressor_previews()
+ . = list()
+ for(var/datum/compressor_recipe/recipe as anything in subtypesof(/datum/compressor_recipe))
+ var/output_type = recipe::output_item
+ if(!ispath(output_type, /obj/item))
+ continue
+ var/obj/item/preview = new output_type(null)
+ .[recipe] = image(getFlatIcon(preview))
+ qdel(preview)
diff --git a/monkestation/code/modules/slimecore/machines/ooze_sucker.dm b/monkestation/code/modules/slimecore/machines/ooze_sucker.dm
index 216edb7dfdbe..69f2f497ee76 100644
--- a/monkestation/code/modules/slimecore/machines/ooze_sucker.dm
+++ b/monkestation/code/modules/slimecore/machines/ooze_sucker.dm
@@ -7,10 +7,13 @@
icon_state = "ooze_sucker"
anchored = FALSE
density = FALSE
- idle_power_usage = 10
- active_power_usage = 1000
+
+ use_power = IDLE_POWER_USE
+ idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.1
+ active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.15
+
buffer = 3000
- category="Distribution"
+ category = "Distribution"
reagent_flags = NO_REACT
/// Pump is turned on by engineer, etc.
@@ -31,6 +34,9 @@
/// Additional ratio of liquid volume to drain
var/drain_percent = 1
+ /// Whether draining was performed last process or not.
+ var/drained_last_process = FALSE
+
/obj/machinery/plumbing/ooze_sucker/Initialize(mapload, bolt, layer)
. = ..()
AddComponent(/datum/component/plumbing/simple_supply, bolt, layer)
@@ -68,6 +74,22 @@
turned_on = FALSE
update_icon_state()
+/obj/machinery/plumbing/ooze_sucker/create_reagents(max_vol, flags)
+ . = ..()
+ RegisterSignals(reagents, list(COMSIG_REAGENTS_REM_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_CLEAR_REAGENTS, COMSIG_REAGENTS_REACTED), PROC_REF(on_reagent_change))
+ RegisterSignal(reagents, COMSIG_QDELETING, PROC_REF(on_reagents_del))
+
+/// Handles properly detaching signal hooks.
+/obj/machinery/plumbing/ooze_sucker/proc/on_reagents_del(datum/reagents/reagents)
+ SIGNAL_HANDLER
+ UnregisterSignal(reagents, list(COMSIG_REAGENTS_REM_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_CLEAR_REAGENTS, COMSIG_REAGENTS_REACTED, COMSIG_QDELETING))
+ return NONE
+
+/// Handles ensuring power usage becomes idle when reagents are full.
+/obj/machinery/plumbing/ooze_sucker/proc/on_reagent_change(datum/reagents/holder, ...)
+ SIGNAL_HANDLER
+ update_power_usage()
+ return NONE
/obj/machinery/plumbing/ooze_sucker/proc/toggle_state()
turned_on = !turned_on
@@ -109,12 +131,25 @@
// We're good, actually pump.
for(var/turf/affected_turf as anything in affected_turfs)
pump_turf(affected_turf, seconds_per_tick, multiplier)
+ update_power_usage()
+
+/obj/machinery/plumbing/ooze_sucker/proc/update_power_usage()
+ if(!turned_on)
+ update_use_power(NO_POWER_USE)
+ else if(reagents && reagents.total_volume >= reagents.maximum_volume)
+ update_use_power(IDLE_POWER_USE)
+ else if(drained_last_process)
+ update_use_power(ACTIVE_POWER_USE)
+ else
+ update_use_power(IDLE_POWER_USE)
/obj/machinery/plumbing/ooze_sucker/proc/pump_turf(turf/affected_turf, seconds_per_tick, multiplier)
if(processes < processes_required)
processes++
return
processes = 0
+ drained_last_process = FALSE
+
if(!affected_turf.liquids || !affected_turf.liquids.liquid_group)
return
@@ -128,3 +163,12 @@
if(!targeted_group.reagents_per_turf)
return
targeted_group.transfer_specific_reagents(reagents, target_value, reagents_to_check = typesof(/datum/reagent/slime_ooze), merge = TRUE)
+ drained_last_process = TRUE
+
+/obj/machinery/plumbing/ooze_sucker/attack_hand_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
+ return
+ toggle_state()
+ balloon_alert_to_viewers("[turned_on ? "enabled" : "disabled"] ooze sucker")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
diff --git a/monkestation/code/modules/slimecore/machines/slime_grinder.dm b/monkestation/code/modules/slimecore/machines/slime_grinder.dm
index 4cb79b472b19..b5ef7280e7c1 100644
--- a/monkestation/code/modules/slimecore/machines/slime_grinder.dm
+++ b/monkestation/code/modules/slimecore/machines/slime_grinder.dm
@@ -7,8 +7,11 @@
icon = 'monkestation/code/modules/slimecore/icons/slime_grinder.dmi'
icon_state = "slime_grinder_backdrop"
base_icon_state = "slime_grinder_backdrop"
- idle_power_usage = 10
- active_power_usage = 1000
+
+ use_power = IDLE_POWER_USE
+ idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION
+ active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION
+
buffer = 3000
category="Distribution"
diff --git a/monkestation/code/modules/slimecore/machines/slime_market.dm b/monkestation/code/modules/slimecore/machines/slime_market.dm
index 8e299bec9cda..57cd96c8397b 100644
--- a/monkestation/code/modules/slimecore/machines/slime_market.dm
+++ b/monkestation/code/modules/slimecore/machines/slime_market.dm
@@ -6,25 +6,11 @@
base_icon_state = "market_pad"
density = TRUE
use_power = IDLE_POWER_USE
- idle_power_usage = 10
- active_power_usage = 2000
+ idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION
+ active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION
circuit = /obj/item/circuitboard/machine/slime_market_pad
var/obj/machinery/computer/slime_market/console
-/obj/machinery/slime_market_pad/attackby(obj/item/I, mob/user, params)
- if(default_deconstruction_screwdriver(user, icon_state, icon_state, I))
- user.visible_message(span_notice("\The [user] [panel_open ? "opens" : "closes"] the hatch on \the [src]."), span_notice("You [panel_open ? "open" : "close"] the hatch on \the [src]."))
- update_appearance()
- return TRUE
-
- if(default_unfasten_wrench(user, I))
- return TRUE
-
- if(default_deconstruction_crowbar(I))
- return TRUE
-
- . = ..()
-
/obj/machinery/slime_market_pad/examine(mob/user)
. = ..()
if(!panel_open)
@@ -41,6 +27,8 @@
/obj/machinery/slime_market_pad/AltClick(mob/user)
. = ..()
+ if(!.)
+ return
link_console()
/obj/machinery/slime_market_pad/proc/link_console()
@@ -53,30 +41,39 @@
console.link_market_pad()
break
-/obj/machinery/slime_market_pad/attackby(obj/item/I, mob/living/user, params)
+/obj/machinery/slime_market_pad/attackby(obj/item/item, mob/living/user, params)
. = ..()
- if(!console)
+ if(. || !can_interact(user))
+ return
+ if(default_deconstruction_screwdriver(user, icon_state, icon_state, item))
+ user.visible_message(span_notice("\The [user] [panel_open ? "opens" : "closes"] the hatch on \the [src]."), span_notice("You [panel_open ? "open" : "close"] the hatch on \the [src]."))
+ update_appearance()
+ return TRUE
+ if(default_unfasten_wrench(user, item) || default_deconstruction_crowbar(item))
+ return TRUE
+ if(QDELETED(console))
to_chat(user, span_warning("[src] does not have a console linked to it!"))
return
-
- if(istype(I, /obj/item/slime_extract))
- var/obj/item/slime_extract/extract = I
+ if(istype(item, /obj/item/slime_extract))
+ var/obj/item/slime_extract/extract = item
if(extract.tier == 0)
to_chat(user, span_warning("[src] doesn't seem to accept this extract!"))
return
flick("[base_icon_state]_vend", src)
sell_extract(extract)
return
-
- else if(istype(I, /obj/item/storage/bag/xeno))
- if(tgui_alert(user, "Are you sure you want to sell all extracts from [I]?", "<3?", list("Yes", "No")) != "Yes")
+ else if(istype(item, /obj/item/storage/bag/xeno))
+ if(tgui_alert(user, "Are you sure you want to sell all extracts from [item]?", "<3?", list("Yes", "No")) != "Yes")
return
-
flick("[base_icon_state]_vend", src)
- for(var/obj/item/slime_extract/extract in I)
+ var/sold_extracts = 0
+ for(var/obj/item/slime_extract/extract in item)
if(extract.tier == 0)
continue
sell_extract(extract)
+ sold_extracts++
+ if(sold_extracts > 0)
+ user.balloon_alert_to_viewers("sold [sold_extracts] extracts")
return
/obj/machinery/slime_market_pad/proc/sell_extract(obj/item/slime_extract/extract)
@@ -97,23 +94,38 @@
SSresearch.slime_core_prices[core_type] = (1 + price_mod * price_limiter) * SSresearch.slime_core_prices[core_type]
qdel(extract)
-/obj/machinery/slime_market_pad/attackby_secondary(obj/item/weapon, mob/user, params)
- if(!console)
- to_chat(user, span_warning("[src] does not have a console linked to it!"))
+/obj/machinery/slime_market_pad/attackby_secondary(obj/item/item, mob/user, params)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN || !can_interact(user))
return
+ if(QDELETED(console))
+ to_chat(user, span_warning("[src] does not have a console linked to it!"))
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
- if(!console.request_pad)
+ if(istype(item, /obj/item/storage/bag/xeno))
+ flick("[base_icon_state]_vend", src)
+ var/sold_extracts = 0
+ for(var/obj/item/slime_extract/extract in item)
+ if(extract.tier == 0)
+ continue
+ sell_extract(extract)
+ sold_extracts++
+ if(sold_extracts > 0)
+ user.balloon_alert_to_viewers("sold [sold_extracts] extracts")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+ if(QDELETED(console.request_pad))
to_chat(user, span_warning("[console] does not have a request_pad linked to it!"))
- return
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(!length(console.request_pad.current_requests))
to_chat(user, span_warning("There are no current extract requests!"))
- return
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
- if(istype(weapon, /obj/item/slime_extract))
+ if(istype(item, /obj/item/slime_extract))
var/list/radial_choices = list()
var/list/choice_to_request = list()
- var/obj/item/slime_extract/extract = weapon
+ var/obj/item/slime_extract/extract = item
for(var/datum/extract_request_data/current as anything in console.request_pad.current_requests)
if((current.extract_path != extract.type) || current.ready_for_pickup)
continue
@@ -134,4 +146,4 @@
flick("[base_icon_state]_vend", src)
qdel(extract)
- return
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
diff --git a/monkestation/code/modules/slimecore/machines/slime_market_computer.dm b/monkestation/code/modules/slimecore/machines/slime_market_computer.dm
index 3c86eb44af7a..a3394c7a0105 100644
--- a/monkestation/code/modules/slimecore/machines/slime_market_computer.dm
+++ b/monkestation/code/modules/slimecore/machines/slime_market_computer.dm
@@ -66,7 +66,7 @@ GLOBAL_DATUM(default_slime_market, /obj/machinery/computer/slime_market)
/obj/machinery/computer/slime_market/ui_assets(mob/user)
return list(
- get_asset_datum(/datum/asset/spritesheet/xenobio_market),
+ get_asset_datum(/datum/asset/spritesheet/xenobio_market)
)
/obj/machinery/computer/slime_market/ui_interact(mob/user, datum/tgui/ui)
@@ -110,19 +110,21 @@ GLOBAL_DATUM(default_slime_market, /obj/machinery/computer/slime_market)
iter += 1
var/obj/item/slime_extract/core = core_type
- var/list/core_data = list("icon" = "[initial(core.icon_state)]",
- "price" = SSresearch.slime_core_prices[core_type],
- "key" = iter % 4,
- )
+ var/list/core_data = list(
+ "icon" = "[initial(core.icon_state)]",
+ "price" = SSresearch.slime_core_prices[core_type],
+ "key" = iter % 4
+ )
price_row.Add(list(core_data))
iter += 1
if(core_type == /obj/item/slime_extract/grey)
core = /obj/item/slime_extract/rainbow
- var/list/rainbow_core_data = list("icon" = "[initial(core.icon_state)]",
- "price" = SSresearch.slime_core_prices[/obj/item/slime_extract/rainbow],
- "key" = iter % 4,
- )
+ var/list/rainbow_core_data = list(
+ "icon" = "[initial(core.icon_state)]",
+ "price" = SSresearch.slime_core_prices[/obj/item/slime_extract/rainbow],
+ "key" = iter % 4
+ )
price_row.Add(list(rainbow_core_data))
iter += 1
price_row.Add(list(list("key" = iter % 4)))
diff --git a/monkestation/code/modules/slimecore/machines/slime_pen_controller.dm b/monkestation/code/modules/slimecore/machines/slime_pen_controller.dm
index e071ac929ecb..862b41467872 100644
--- a/monkestation/code/modules/slimecore/machines/slime_pen_controller.dm
+++ b/monkestation/code/modules/slimecore/machines/slime_pen_controller.dm
@@ -28,7 +28,6 @@
. = ..()
locate_machinery()
-
/obj/machinery/slime_pen_controller/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
@@ -69,13 +68,13 @@
var/list/mutation_info = list()
var/mob_string
for(var/mob/living/mob as anything in mutation_data.latch_needed)
- mob_string += "[mutation_data.latch_needed[mob]] units of genetic data from [initial(mob.name)]. \n"
+ mob_string += "[mutation_data.latch_needed[mob]] units of genetic data from [mob::name]. \n"
var/item_string
for(var/obj/item/item as anything in mutation_data.needed_items)
- item_string += "[initial(item.name)]. \n"
+ item_string += "[item:name]. \n"
mutation_info += list(
- "color" = capitalize(initial(mutation_data.output.name)),
+ "color" = capitalize(mutation_data.output::name),
"weight" = mutation_data.weight,
"mutate_chance" = mutation_data.mutate_probability,
"mobs_needed" = mob_string,
@@ -135,7 +134,6 @@
. = ..()
if(.)
return
-
switch(action)
if("buy")
for(var/datum/corral_upgrade/item as anything in subtypesof(/datum/corral_upgrade))
@@ -146,7 +144,7 @@
/obj/machinery/slime_pen_controller/proc/try_buy(datum/corral_upgrade/item)
if(!linked_data)
return
- if(SSresearch.xenobio_points < initial(item.cost))
+ if(SSresearch.xenobio_points < item::cost)
return
var/datum/corral_upgrade/new_upgrade = new item
@@ -165,25 +163,23 @@
return
/obj/machinery/slime_pen_controller/attack_hand_secondary(mob/user, list/modifiers)
- if(linked_sucker)
- visible_message(span_notice("[user] fiddles with the [src] toggling the pens ooze sucker."))
- linked_sucker.toggle_state()
- return TRUE
. = ..()
-
-/obj/machinery/slime_pen_controller/attackby(obj/item/weapon, mob/user, params)
- if(weapon.tool_behaviour == TOOL_MULTITOOL)
- if(!multitool_check_buffer(user, weapon))
- return
- var/obj/item/multitool/M = weapon
- if(!M.buffer)
- return
- var/obj/machinery/corral_corner/pad = M.buffer
- if(!istype(pad))
- return
- if(!pad.connected_data)
- return
- linked_data = pad.connected_data
- to_chat(user, span_notice("You link the [pad] to the [src]."))
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
+ if(!QDELETED(linked_sucker))
+ linked_sucker.toggle_state()
+ balloon_alert_to_viewers("[linked_sucker.turned_on ? "enabled" : "disabled"] ooze sucker")
+ visible_message(span_notice("[user] fiddles with the [src], [linked_sucker.turned_on ? "enabling" : "disabling"] the pens ooze sucker."))
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/obj/machinery/slime_pen_controller/multitool_act(mob/living/user, obj/item/multitool/multitool)
. = ..()
+ if(!multitool_check_buffer(user, multitool) || QDELETED(multitool.buffer))
+ return
+ var/obj/machinery/corral_corner/pad = multitool.buffer
+ if(!istype(pad) || !pad.connected_data)
+ return
+ linked_data = pad.connected_data
+ balloon_alert_to_viewers("linked pad")
+ pad.balloon_alert_to_viewers("linked to controller")
+ to_chat(user, span_notice("You link the [pad] to the [src]."))
diff --git a/monkestation/code/modules/slimecore/mobs/_base_slime.dm b/monkestation/code/modules/slimecore/mobs/_base_slime.dm
index dfbe5d102b8a..5b21399ca0ba 100644
--- a/monkestation/code/modules/slimecore/mobs/_base_slime.dm
+++ b/monkestation/code/modules/slimecore/mobs/_base_slime.dm
@@ -162,6 +162,7 @@
/mob/living/basic/slime/mob_try_pickup(mob/living/user, instant)
if(!SEND_SIGNAL(src, COMSIG_FRIENDSHIP_CHECK_LEVEL, user, FRIENDSHIP_FRIEND))
to_chat(user, span_notice("[src] doesn't trust you enough to let you pick them up"))
+ balloon_alert(user, "not enough trust!")
return FALSE
. = ..()
@@ -188,10 +189,9 @@
/mob/living/basic/slime/proc/recompile_ai_tree()
var/list/new_planning_subtree = list()
+ RemoveElement(/datum/element/basic_eating, food_types = compiled_liked_foods)
rebuild_foods()
- RemoveElement(/datum/element/basic_eating)
-
new_planning_subtree |= add_or_replace_tree(/datum/ai_planning_subtree/pet_planning)
if(!HAS_TRAIT(src, TRAIT_SLIME_RABID))
@@ -310,6 +310,7 @@
slime_flags |= SPLITTING_SLIME
visible_message(span_notice("[name] starts to flatten, it looks to be splitting."))
+ balloon_alert_to_viewers("splitting...")
addtimer(CALLBACK(src, PROC_REF(finish_splitting)), 15 SECONDS)
@@ -331,6 +332,7 @@
ai_controller.set_ai_status(AI_STATUS_OFF)
visible_message(span_notice("[name] starts to undulate, it looks to be mutating."))
+ balloon_alert_to_viewers("mutating...")
slime_flags |= MUTATING_SLIME
ungulate()
@@ -414,8 +416,9 @@
. = ..()
if(worn_accessory)
visible_message("[user] takes the [worn_accessory] off the [src].")
+ balloon_alert_to_viewers("removed accessory")
+ worn_accessory.forceMove(user.drop_location())
worn_accessory = null
- worn_accessory.forceMove(get_turf(user))
update_appearance()
/mob/living/basic/slime/Life(seconds_per_tick, times_fired)
diff --git a/monkestation/code/modules/trading/lootbox_odds.dm b/monkestation/code/modules/trading/lootbox_odds.dm
index 33619926ab6c..18773422b2bb 100644
--- a/monkestation/code/modules/trading/lootbox_odds.dm
+++ b/monkestation/code/modules/trading/lootbox_odds.dm
@@ -32,8 +32,9 @@
user.client.client_token_holder.adjust_antag_tokens(LOW_THREAT, 1)
if("Loadout Item")
- var/static/list/viable_types = list()
- if(!length(viable_types))
+ var/static/list/viable_types
+ if(!viable_types)
+ viable_types = list()
for(var/datum/loadout_item/type as anything in subtypesof(/datum/loadout_item))
var/datum/loadout_item/listed = new type()
if(!istype(listed))
diff --git a/monkestation/code/modules/viking/viking_armour.dm b/monkestation/code/modules/viking/viking_armour.dm
index 9c5bacd94e5e..046378082285 100644
--- a/monkestation/code/modules/viking/viking_armour.dm
+++ b/monkestation/code/modules/viking/viking_armour.dm
@@ -97,6 +97,18 @@
clothing_flags = STOPSPRESSUREDAMAGE
female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY
+/obj/item/clothing/under/viking/fake_tunic
+ name = "viking pelt"
+ desc = "A faux wolf pelt made to cosplay with"
+ worn_icon_state = "pelts"
+ icon_state = "pelts"
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/clothing/head/viking/fake_helmet
+ name = "foam helmet"
+ desc = "a foam helmet that looks like that of a vikings helmet"
+ worn_icon_state = "honeless_helm_worn"
+ icon_state = "hornless_helm_item"
/datum/armor/viking
melee = 45
bullet = 30
diff --git a/monkestation/icons/mob/anime/anime_bottom.dmi b/monkestation/icons/mob/anime/anime_bottom.dmi
index bc6d43e412f0..03db82988211 100644
Binary files a/monkestation/icons/mob/anime/anime_bottom.dmi and b/monkestation/icons/mob/anime/anime_bottom.dmi differ
diff --git a/monkestation/icons/mob/clock_cult/actions_clock.dmi b/monkestation/icons/mob/clock_cult/actions_clock.dmi
index 76cda1eed569..a6b6f3832af3 100644
Binary files a/monkestation/icons/mob/clock_cult/actions_clock.dmi and b/monkestation/icons/mob/clock_cult/actions_clock.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 62dc515675d0..c31a3328ff04 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -5942,7 +5942,7 @@
#include "monkestation\code\modules\antagonists\traitor\objectives\tide_bug_department.dm"
#include "monkestation\code\modules\antagonists\traitor\objectives\final_objective\become_wizard.dm"
#include "monkestation\code\modules\antagonists\traitor\objectives\final_objective\final_objective.dm"
-#include "monkestation\code\modules\antagonists\wizard\wizard_antagonist.dm"
+#include "monkestation\code\modules\antagonists\wizard\wizard.dm"
#include "monkestation\code\modules\antagonists\wizard\equipment\artefact.dm"
#include "monkestation\code\modules\antagonists\wizard\equipment\spellbook_entries\defensive.dm"
#include "monkestation\code\modules\antagonists\wizard\equipment\spellbook_entries\mobility.dm"
@@ -6412,6 +6412,7 @@
#include "monkestation\code\modules\mob\living\basic\animatronic.dm"
#include "monkestation\code\modules\mob\living\basic\ggg\glerm.dm"
#include "monkestation\code\modules\mob\living\basic\ggg\susflash.dm"
+#include "monkestation\code\modules\mob\living\basic\pets\parrot\parrot_ai\parroting_action.dm"
#include "monkestation\code\modules\mob\living\basic\space_fauna\fugu_gland.dm"
#include "monkestation\code\modules\mob\living\basic\vermin\mouse.dm"
#include "monkestation\code\modules\mob\living\carbon\carbon_death.dm"
@@ -6758,6 +6759,7 @@
#include "monkestation\code\modules\slimecore\machines\slime_market_computer.dm"
#include "monkestation\code\modules\slimecore\machines\slime_pen_controller.dm"
#include "monkestation\code\modules\slimecore\machines\ooze_compressor\ooze_compressor.dm"
+#include "monkestation\code\modules\slimecore\machines\ooze_compressor\ooze_compressor_hud.dm"
#include "monkestation\code\modules\slimecore\machines\ooze_compressor\ooze_compressor_plumbing.dm"
#include "monkestation\code\modules\slimecore\machines\ooze_compressor\shitcode.dm"
#include "monkestation\code\modules\slimecore\machines\ooze_compressor\recipes\_base_recipe.dm"