[MIRROR] Reworks janitor cyborg cleaning, focus on the slipping [MDB IGNORE] (#10961)

* Reworks janitor cyborg cleaning, focus on the slipping

* Feex

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
This commit is contained in:
SkyratBot
2022-01-24 23:21:42 +01:00
committed by GitHub
parent 105ddac2b0
commit c8ec74bee2
18 changed files with 246 additions and 17 deletions
+2
View File
@@ -91,6 +91,8 @@
#define REAGENT_IGNORE_STASIS (1<<6)
///This reagent won't be used in most randomized recipes. Meant for reagents that could be synthetized but are normally inaccessible or TOO hard to get.
#define REAGENT_NO_RANDOM_RECIPE (1<<7)
///Does this reagent clean things?
#define REAGENT_CLEANS (1<<8)
//Chemical reaction flags, for determining reaction specialties
///Convert into impure/pure on reaction completion
+3
View File
@@ -322,6 +322,9 @@ DEFINE_BITFIELD(chemical_flags, list(
"REAGENT_SNEAKYNAME" = REAGENT_SNEAKYNAME,
"REAGENT_SPLITRETAINVOL" = REAGENT_SPLITRETAINVOL,
"REAGENT_CAN_BE_SYNTHESIZED" = REAGENT_CAN_BE_SYNTHESIZED,
"REAGENT_IGNORE_STASIS" = REAGENT_IGNORE_STASIS,
"REAGENT_NO_RANDOM_RECIPE" = REAGENT_NO_RANDOM_RECIPE,
"REAGENT_CLEANS" = REAGENT_CLEANS,
))
DEFINE_BITFIELD(reaction_flags, list(
+4 -3
View File
@@ -1,6 +1,4 @@
/*
output_atoms (list of atoms) The destination(s) for the sounds
mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end.
mid_length (num) The length to wait between playing mid_sounds
@@ -60,7 +58,7 @@
return
on_start()
/datum/looping_sound/proc/stop(null_parent)
/datum/looping_sound/proc/stop(null_parent = FALSE)
if(null_parent)
set_parent(null)
if(!timerid)
@@ -114,6 +112,9 @@
if(parent)
RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/handle_parent_del)
/datum/looping_sound/proc/is_active()
return !!timerid
/datum/looping_sound/proc/handle_parent_del(datum/source)
SIGNAL_HANDLER
set_parent(null)
+10
View File
@@ -0,0 +1,10 @@
/datum/looping_sound/wash
mid_sounds = list('sound/creatures/cyborg/wash1.ogg' = 1, 'sound/creatures/cyborg/wash2.ogg' = 1)
mid_length = 1.5 SECONDS // This makes them overlap slightly, which works out well for masking the fade in/out
start_volume = 100
start_sound = 'sound/creatures/cyborg/wash_start.ogg'
start_length = 3.6 SECONDS // again, slightly shorter then the real time of 4 seconds, will make the transition to midsounds more seemless
end_volume = 100
end_sound = 'sound/creatures/cyborg/wash_end.ogg'
vary = TRUE
extra_range = 5
+1 -1
View File
@@ -39,7 +39,7 @@
//SKYRAT EDIT END
/obj/item/mop/proc/clean(turf/A, mob/living/cleaner)
if(reagents.has_reagent(/datum/reagent/water, 1) || reagents.has_reagent(/datum/reagent/water/holywater, 1) || reagents.has_reagent(/datum/reagent/consumable/ethanol/vodka, 1) || reagents.has_reagent(/datum/reagent/space_cleaner, 1))
if(reagents.has_chemical_flag(REAGENT_CLEANS, 1))
// If there's a cleaner with a mind, let's gain some experience!
if(cleaner?.mind)
var/total_experience_gain = 0
@@ -768,11 +768,6 @@
for(var/trait in model.model_traits)
ADD_TRAIT(src, trait, MODEL_TRAIT)
if(model.clean_on_move)
AddElement(/datum/element/cleaning)
else
RemoveElement(/datum/element/cleaning)
hat_offset = model.hat_offset
INVOKE_ASYNC(src, .proc/updatename)
@@ -37,8 +37,6 @@
var/list/model_traits = null
///List of radio channels added to the cyborg
var/list/radio_channels = list()
///Do we clean when we move
var/clean_on_move = FALSE
///Whether the borg loses tool slots with damage.
var/breakable_modules = TRUE
///Whether swapping to this configuration should lockcharge the borg
@@ -361,14 +359,212 @@
/obj/item/reagent_containers/glass/bucket,
/obj/item/paint/paint_remover,
/obj/item/lightreplacer/cyborg,
/obj/item/holosign_creator/janibarrier,
/obj/item/holosign_creator,
/obj/item/reagent_containers/spray/cyborg_drying)
radio_channels = list(RADIO_CHANNEL_SERVICE)
emag_modules = list(/obj/item/reagent_containers/spray/cyborg_lube)
cyborg_base_icon = "janitor"
model_select_icon = "janitor"
hat_offset = -5
clean_on_move = TRUE
/// Weakref to the wash toggle action we own
var/datum/weakref/wash_toggle_ref
/obj/item/robot_model/janitor/be_transformed_to(obj/item/robot_model/old_model, forced = FALSE)
. = ..()
if(!.)
return
var/datum/action/wash_toggle = new /datum/action/toggle_buffer(loc)
wash_toggle.Grant(loc)
wash_toggle_ref = WEAKREF(wash_toggle)
/obj/item/robot_model/janitor/Destroy()
QDEL_NULL(wash_toggle_ref)
return ..()
/datum/action/toggle_buffer
name = "Activate Auto-Wash"
desc = "Trade speed and water for a clean floor."
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "activate_wash"
var/static/datum/callback/allow_buffer_activate
var/block_buffer_change = FALSE
var/buffer_on = FALSE
///The bucket we draw water from
var/datum/weakref/bucket_ref
///Our looping sound
var/datum/looping_sound/wash/wash_audio
///Toggle cooldown to prevent sound spam
COOLDOWN_DECLARE(toggle_cooldown)
/datum/action/toggle_buffer/New(Target)
if(!allow_buffer_activate)
allow_buffer_activate = CALLBACK(src, .proc/allow_buffer_activate)
return ..()
/datum/action/toggle_buffer/Destroy()
if(buffer_on)
turn_off_wash()
QDEL_NULL(wash_audio)
return ..()
/datum/action/toggle_buffer/Grant(mob/M)
. = ..()
wash_audio = new(owner)
/datum/action/toggle_buffer/IsAvailable()
if(!istype(owner, /mob/living/silicon/robot))
return FALSE
return ..()
/datum/action/toggle_buffer/Trigger(trigger_flags)
. = ..()
if(!.)
return
var/mob/living/silicon/robot/robot_owner = owner
block_buffer_change = DOING_INTERACTION(owner, "auto_wash_toggle")
if(block_buffer_change)
return FALSE
var/obj/item/reagent_containers/glass/bucket/our_bucket = locate(/obj/item/reagent_containers/glass/bucket) in robot_owner.model.modules
bucket_ref = WEAKREF(our_bucket)
if(!buffer_on)
if(!COOLDOWN_FINISHED(src, toggle_cooldown))
robot_owner.balloon_alert(robot_owner, "auto-wash refreshing, please hold...")
return FALSE
COOLDOWN_START(src, toggle_cooldown, 4 SECONDS)
if(!allow_buffer_activate())
return FALSE
robot_owner.balloon_alert(robot_owner, "activating auto-wash...")
// Start the sound. it'll just last the 4 seconds it takes for us to rev up
wash_audio.start()
// We're just gonna shake the borg a bit. Not a ton, but just enough that it feels like the audio makes sense
var/base_x = robot_owner.base_pixel_x
var/base_y = robot_owner.base_pixel_y
animate(robot_owner, pixel_x = base_x, pixel_y = base_y, time = 1, loop = -1)
for(var/i in 1 to 17) //Startup rumble
var/x_offset = base_x + rand(-1, 1)
var/y_offset = base_y + rand(-1, 1)
animate(pixel_x = x_offset, pixel_y = y_offset, time = 1)
if(!do_after(robot_owner, 4 SECONDS, interaction_key = "auto_wash_toggle", extra_checks = allow_buffer_activate))
wash_audio.stop() // Coward
animate(robot_owner, pixel_x = base_x, pixel_y = base_y, time = 1)
return FALSE
else
if(!COOLDOWN_FINISHED(src, toggle_cooldown))
robot_owner.balloon_alert(robot_owner, "auto-wash deactivating, please hold...")
return FALSE
robot_owner.balloon_alert(robot_owner, "de-activating auto-wash...")
toggle_wash()
/// Toggle our wash mode
/datum/action/toggle_buffer/proc/toggle_wash()
if(buffer_on)
deactivate_wash()
else
activate_wash()
/// Activate the buffer, comes with a nice animation that loops while it's on
/datum/action/toggle_buffer/proc/activate_wash()
var/mob/living/silicon/robot/robot_owner = owner
buffer_on = TRUE
// Slow em down a bunch
robot_owner.add_movespeed_modifier(/datum/movespeed_modifier/auto_wash)
RegisterSignal(robot_owner, COMSIG_MOVABLE_MOVED, .proc/clean)
//This is basically just about adding a shake to the borg, effect should look ilke an engine's running
var/base_x = robot_owner.base_pixel_x
var/base_y = robot_owner.base_pixel_y
robot_owner.pixel_x = base_x + rand(-7, 7)
robot_owner.pixel_y = base_y + rand(-7, 7)
//Larger shake with more changes to start out, feels like "Revving"
animate(robot_owner, pixel_x = base_x, pixel_y = base_y, time = 1, loop = -1)
for(var/i in 1 to 100)
var/x_offset = base_x + rand(-2, 2)
var/y_offset = base_y + rand(-2, 2)
animate(pixel_x = x_offset, pixel_y = y_offset, time = 1)
if(!wash_audio.is_active())
wash_audio.start()
clean()
UpdateButtonIcon()
/// Start the process of disabling the buffer. Plays some effects, waits a bit, then finishes
/datum/action/toggle_buffer/proc/deactivate_wash()
var/mob/living/silicon/robot/robot_owner = owner
var/time_left = timeleft(wash_audio.timerid) // We delay by the timer of our wash cause well, we want to hear the ramp down
var/finished_by = time_left + 2.6 SECONDS
// Need to ensure that people don't spawn the deactivate button
COOLDOWN_START(src, toggle_cooldown, finished_by)
// Diable the cleaning, we're revving down
UnregisterSignal(robot_owner, COMSIG_MOVABLE_MOVED)
// Do the rumble animation till we're all finished
var/base_x = robot_owner.base_pixel_x
var/base_y = robot_owner.base_pixel_y
animate(robot_owner, pixel_x = base_x, pixel_y = base_y, time = 1)
for(var/i in 1 to finished_by - 0.1 SECONDS) //We rumble until we're finished making noise
var/x_offset = base_x + rand(-1, 1)
var/y_offset = base_y + rand(-1, 1)
animate(pixel_x = x_offset, pixel_y = y_offset, time = 1)
// Reset our animations
animate(pixel_x = base_x, pixel_y = base_y, time = 2)
addtimer(CALLBACK(wash_audio, /datum/looping_sound/proc/stop), time_left)
addtimer(CALLBACK(src, .proc/turn_off_wash), finished_by)
/// Called by [deactivate_wash] on a timer to allow noises and animation to play out.
/// Finally disables the buffer. Doesn't do everything mind, just the stuff that we wanted to delay
/datum/action/toggle_buffer/proc/turn_off_wash()
var/mob/living/silicon/robot/robot_owner = owner
buffer_on = FALSE
robot_owner.remove_movespeed_modifier(/datum/movespeed_modifier/auto_wash)
UpdateButtonIcon()
/// Should we keep trying to activate our buffer, or did you fuck it up somehow
/datum/action/toggle_buffer/proc/allow_buffer_activate()
var/mob/living/silicon/robot/robot_owner = owner
if(block_buffer_change)
robot_owner.balloon_alert(robot_owner, "activation cancelled!")
return FALSE
var/obj/item/reagent_containers/glass/bucket/our_bucket = bucket_ref?.resolve()
if(!buffer_on && our_bucket?.reagents?.total_volume < 0.1)
robot_owner.balloon_alert(robot_owner, "bucket is empty!")
return FALSE
return TRUE
/// Call this to attempt to actually clean the turf underneath us
/datum/action/toggle_buffer/proc/clean()
SIGNAL_HANDLER
var/mob/living/silicon/robot/robot_owner = owner
var/obj/item/reagent_containers/glass/bucket/our_bucket = bucket_ref?.resolve()
var/datum/reagents/reagents = our_bucket?.reagents
if(!reagents || reagents.total_volume < 0.1)
robot_owner.balloon_alert(robot_owner, "bucket is empty, de-activating...")
deactivate_wash()
return
var/turf/our_turf = get_turf(robot_owner)
if(reagents.has_chemical_flag(REAGENT_CLEANS, 1))
our_turf.wash(CLEAN_SCRUB)
reagents.expose(our_turf, TOUCH, 10)
// We use more water doing this then mopping
reagents.remove_any(2) //reaction() doesn't use up the reagents
/datum/action/toggle_buffer/UpdateButtonIcon(status_only = FALSE, force = FALSE)
if(buffer_on)
name = "De-Activate Auto-Wash"
button_icon_state = "deactivate_wash"
else
name = "Activate Auto-Wash"
button_icon_state = "activate_wash"
return ..()
/obj/item/reagent_containers/spray/cyborg_drying
name = "drying agent spray"
+3
View File
@@ -126,3 +126,6 @@
/datum/movespeed_modifier/morph_disguised
multiplicative_slowdown = 1
/datum/movespeed_modifier/auto_wash
multiplicative_slowdown = 3
@@ -194,5 +194,8 @@
if(reagent.chemical_flags & REAGENT_DEAD_PROCESS)
outstring += "\n<br>Works on the dead"
if(reagent.chemical_flags & REAGENT_CLEANS)
outstring += "\n<br>Sanitizes well"
outstring += "\n|-"
return outstring
+15
View File
@@ -428,6 +428,21 @@
return holder_reagent
return FALSE
/**
* Check if this holder contains a reagent with a chemical_flags containing this flag
* Reagent takes the bitflag to search for
* Amount checks for having a specific amount of reagents matching that chemical
*/
/datum/reagents/proc/has_chemical_flag(chemical_flag, amount = 0)
var/found_amount = 0
var/list/cached_reagents = reagent_list
for(var/datum/reagent/holder_reagent as anything in cached_reagents)
if (holder_reagent.chemical_flags & chemical_flag)
found_amount += holder_reagent.volume
if(found_amount >= amount)
return TRUE
return FALSE
/**
* Transfer some stuff from this holder to a target object
@@ -290,7 +290,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_desc = "The glass contain wodka. Xynta."
shot_glass_icon_state = "shotglassclear"
ph = 8.1
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_CLEANS //Very high proof
/datum/reagent/consumable/ethanol/bilk
name = "Bilk"
@@ -156,7 +156,7 @@
glass_name = "glass of water"
glass_desc = "The father of all refreshments."
shot_glass_icon_state = "shotglassclear"
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_CLEANS
evaporates = TRUE //SKYRAT EDIT ADDITION
/*
@@ -242,7 +242,7 @@
glass_desc = "A glass of holy water."
self_consuming = TRUE //divine intervention won't be limited by the lack of a liver
ph = 7.5 //God is alkaline
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_CLEANS
// Holy water. Mostly the same as water, it also heals the plant a little with the power of the spirits. Also ALSO increases instability.
/datum/reagent/water/holywater/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray)
@@ -1157,7 +1157,7 @@
penetrates_skin = NONE
var/clean_types = CLEAN_WASH
ph = 5.5
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_CLEANS
/datum/reagent/space_cleaner/expose_obj(obj/exposed_obj, reac_volume)
. = ..()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -1032,6 +1032,7 @@
#include "code\datums\keybinding\robot.dm"
#include "code\datums\looping_sounds\_looping_sound.dm"
#include "code\datums\looping_sounds\acid.dm"
#include "code\datums\looping_sounds\cyborg.dm"
#include "code\datums\looping_sounds\item_sounds.dm"
#include "code\datums\looping_sounds\machinery_sounds.dm"
#include "code\datums\looping_sounds\weather.dm"