[BOUNTY] Liquids try #3: Return of the pee (#22169)

* pee

* strange reagent fix

* smell mop

* throwing?

* evaporation + more effects

* Update pyrotechnic_reagents.dm

* doors/airlocks

* smell mop

* Update liquid_groups.dm

* borbop changes

* breathing in liquids

* fixes liquids going into dense tiles

* increases mopcap to 45

* liquids fixes

* lol

* more liquid stuff

* fixes this

* more changes

* fix all this stupid stuff

* fix phantom pixel

* liquid pump fix

* gives you better ability to scoop things up

* fix liquid pump

* BUUURN BABY BURN + blud

* slipping reaction checking

* change liquid push reaction

* removes liquid_fire_power
This commit is contained in:
Byemoh
2024-08-08 14:54:33 -05:00
committed by GitHub
parent 9acc635bd1
commit 4c7d381f6b
68 changed files with 3144 additions and 41 deletions

View File

@@ -303,6 +303,7 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=23;TEMP=300"
#define ICEMOON_DEFAULT_ATMOS "o2=14;n2=23;TEMP=180"
#define JUNGLELAND_DEFAULT_ATMOS "o2=44;n2=164;TEMP=300" //yogs edit
#define OCEAN_DEFAULT_ATMOS "o2=10;co2=10;TEMP=293.15"
//ATMOSIA GAS MONITOR TAGS
#define ATMOS_GAS_MONITOR_INPUT_O2 "o2_in"

View File

@@ -44,3 +44,4 @@
#define COMSIG_ATOM_SECONDARY_TOOL_ACT(tooltype) "tool_secondary_act_[tooltype]"
// We have the same returns here as COMSIG_ATOM_TOOL_ACT
// #define COMPONENT_BLOCK_TOOL_ATTACK (1<<0)
#define COMSIG_ATOM_DOOR_OPEN "atom_door_open"

View File

@@ -47,3 +47,13 @@
#define COMSIG_TURF_IGNITED "turf_ignited"
///Prevents hotspots and turf fires
#define SUPPRESS_FIRE (1<<0)
///called on liquid creation
#define COMSIG_TURF_LIQUIDS_CREATION "turf_liquids_creation"
#define COMSIG_TURF_MOB_FALL "turf_mob_fall"
///this is called whenever a turf is destroyed
#define COMSIG_TURF_DESTROY "turf_destroy"
///this is called whenever a turfs air is updated
#define COMSIG_TURF_UPDATE_AIR "turf_air_change"

View File

@@ -165,6 +165,8 @@ DEFINE_BITFIELD(smoothing_junction, list(
#define SMOOTH_GROUP_BAMBOO_WALLS S_TURF(17) //![/turf/closed/wall/mineral/bamboo, /obj/structure/falsewall/bamboo]
#define SMOOTH_GROUP_PLASTINUM_WALLS S_TURF(18) //![turf/closed/indestructible/riveted/plastinum]
#define SMOOTH_GROUP_CLOCKWORK_WALLS S_TURF(19) //![/turf/closed/wall/clockwork, /obj/structure/falsewall/brass]
#define SMOOTH_GROUP_ELEVATED_PLASTEEL S_TURF(20)
#define SMOOTH_GROUP_LOWERED_PLASTEEL S_TURF(21)
#define SMOOTH_GROUP_PAPERFRAME S_OBJ(21) ///obj/structure/window/paperframe, /obj/structure/mineral_door/paperframe
@@ -208,6 +210,8 @@ DEFINE_BITFIELD(smoothing_junction, list(
#define SMOOTH_GROUP_GAS_TANK S_OBJ(72)
#define SMOOTH_GROUP_WATER S_OBJ(73) ///obj/effect/abstract/liquid_turf
/// Performs the work to set smoothing_groups and canSmoothWith.
/// An inlined function used in both turf/Initialize and atom/Initialize.

View File

@@ -83,3 +83,5 @@
#define MOVESPEED_ID_RESIN_FOAM "RESIN_FOAM"
#define MOVESPEED_ID_SYNTH_SUSPICION "SYNTH_SUSPICION"
#define MOVESPEED_ID_LIQUID "LIQUID"

View File

@@ -332,3 +332,13 @@
//Wardrobe callback master list indexes
#define WARDROBE_CALLBACK_INSERT 1
#define WARDROBE_CALLBACK_REMOVE 2
///liquid defines
#define SSLIQUIDS_RUN_TYPE_TURFS 1
#define SSLIQUIDS_RUN_TYPE_GROUPS 2
#define SSLIQUIDS_RUN_TYPE_IMMUTABLES 3
#define SSLIQUIDS_RUN_TYPE_EVAPORATION 4
#define SSLIQUIDS_RUN_TYPE_FIRE 5
#define SSLIQUIDS_RUN_TYPE_OCEAN 6
#define SSLIQUIDS_RUN_TYPE_TEMPERATURE 7
#define SSLIQUIDS_RUN_TYPE_CACHED_EDGES 8

View File

@@ -285,3 +285,6 @@
///reduces the cooldown of all used /datum/action/cooldown by 25%
#define TRAIT_FAST_COOLDOWNS "short_spell_cooldowns"
/// One can breath under water, you get me?
#define TRAIT_WATER_BREATHING "water_breathing"

View File

@@ -1,7 +1,7 @@
#define CHANGETURF_DEFER_CHANGE (1<<0)
#define CHANGETURF_IGNORE_AIR (1<<1) // This flag prevents changeturf from gathering air from nearby turfs to fill the new turf with an approximation of local air
#define CHANGETURF_FORCEOP (1<<2)
#define CHANGETURF_SKIP (1<<3) // A flag for PlaceOnTop to just instance the new turf instead of calling ChangeTurf. Used for uninitialized turfs NOTHING ELSE
#define CHANGETURF_SKIP (1<<3) // A flag for place_on_top to just instance the new turf instead of calling ChangeTurf. Used for uninitialized turfs NOTHING ELSE
#define CHANGETURF_INHERIT_AIR (1<<4) // Inherit air from previous turf. Implies CHANGETURF_IGNORE_AIR
#define CHANGETURF_RECALC_ADJACENT (1<<5) //Immediately recalc adjacent atmos turfs instead of queuing.
#define CHANGETURF_TRAPDOOR_INDUCED (1<<6) // Caused by a trapdoor, for trapdoor to know that this changeturf was caused by itself

View File

@@ -0,0 +1,86 @@
#define WATER_HEIGH_DIFFERENCE_SOUND_CHANCE 50
#define WATER_HEIGH_DIFFERENCE_DELTA_SPLASH 7 //Delta needed for the splash effect to be made in 1 go
#define REQUIRED_MEMBER_PROCESSES 10
#define REQUIRED_EVAPORATION_PROCESSES 20
#define EVAPORATION_CHANCE 50
#define REQUIRED_FIRE_PROCESSES 10
#define REQUIRED_FIRE_POWER_PER_UNIT 5
#define FIRE_BURN_PERCENT 10
#define REQUIRED_OCEAN_PROCESSES 5
#define PARTIAL_TRANSFER_AMOUNT 0.3
#define LIQUID_MUTUAL_SHARE 1
#define LIQUID_NOT_MUTUAL_SHARE 2
#define LIQUID_GIVER 1
#define LIQUID_TAKER 2
//Required amount of a reagent to be simulated on turf exposures from liquids (to prevent gaming the system with cheap dillutions)
#define LIQUID_REAGENT_THRESHOLD_TURF_EXPOSURE 5
//Threshold at which the difference of height makes us need to climb/blocks movement/allows to fall down
#define TURF_HEIGHT_BLOCK_THRESHOLD 20
#define LIQUID_HEIGHT_DIVISOR 10
#define ONE_LIQUIDS_HEIGHT LIQUID_HEIGHT_DIVISOR
#define LIQUID_ATTRITION_TO_STOP_ACTIVITY 2
//Percieved heat capacity for calculations with atmos sharing
#define REAGENT_HEAT_CAPACITY 5
#define LIQUID_STATE_PUDDLE 1
#define LIQUID_STATE_ANKLES 2
#define LIQUID_STATE_WAIST 3
#define LIQUID_STATE_SHOULDERS 4
#define LIQUID_STATE_FULLTILE 5
#define TOTAL_LIQUID_STATES 5
#define LYING_DOWN_SUBMERGEMENT_STATE_BONUS 2
#define LIQUID_STATE_FOR_HEAT_EXCHANGERS LIQUID_STATE_WAIST
#define LIQUID_ANKLES_LEVEL_HEIGHT 8
#define LIQUID_WAIST_LEVEL_HEIGHT 19
#define LIQUID_SHOULDERS_LEVEL_HEIGHT 29
#define LIQUID_FULLTILE_LEVEL_HEIGHT 39
#define LIQUID_FIRE_STATE_NONE 0
#define LIQUID_FIRE_STATE_SMALL 1
#define LIQUID_FIRE_STATE_MILD 2
#define LIQUID_FIRE_STATE_MEDIUM 3
#define LIQUID_FIRE_STATE_HUGE 4
#define LIQUID_FIRE_STATE_INFERNO 5
//Threshold at which we "choke" on the water, instead of holding our breath
#define OXYGEN_DAMAGE_CHOKING_THRESHOLD 15
#define IMMUTABLE_LIQUID_SHARE 1
#define LIQUID_RECURSIVE_LOOP_SAFETY 255
//Height at which we consider the tile "full" and dont drop liquids on it from the upper Z level
#define LIQUID_HEIGHT_CONSIDER_FULL_TILE 50
#define LIQUID_GROUP_DECAY_TIME 3
//Scaled with how much a person is submerged
#define SUBMERGEMENT_REAGENTS_TOUCH_AMOUNT 60
#define CHOKE_REAGENTS_INGEST_ON_FALL_AMOUNT 4
#define CHOKE_REAGENTS_INGEST_ON_BREATH_AMOUNT 2
#define SUBMERGEMENT_PERCENT(carbon, liquids) min(1,(!MOBILITY_STAND ? liquids.liquid_group.group_overlay_state+LYING_DOWN_SUBMERGEMENT_STATE_BONUS : liquids.liquid_group.group_overlay_state)/TOTAL_LIQUID_STATES)
#define LIQUID_PROTECTION "liquid_protection"
GLOBAL_LIST_INIT(liquid_blacklist, list(
/datum/reagent/sorium,
/datum/reagent/liquid_dark_matter
))

View File

@@ -878,7 +878,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
CRASH("Bad op: area/drop_location() called")
/// A hook so areas can modify the incoming args (of what??)
/area/proc/PlaceOnTopReact(list/new_baseturfs, turf/fake_turf_type, flags)
/area/proc/place_on_topReact(list/new_baseturfs, turf/fake_turf_type, flags)
return flags
/// Called when a living mob that spawned here, joining the round, receives the player client.

View File

@@ -20,7 +20,7 @@
///list of miners & their mining points from gems to be given once all exports are processed, used by supply shuttles
var/list/gem_payout = list()
/area/shuttle/PlaceOnTopReact(list/new_baseturfs, turf/fake_turf_type, flags)
/area/shuttle/place_on_topReact(list/new_baseturfs, turf/fake_turf_type, flags)
. = ..()
if(length(new_baseturfs) > 1 || fake_turf_type)
return // More complicated larger changes indicate this isn't a player

View File

@@ -1341,6 +1341,7 @@
locked = !locked
if(welded)
welded = !welded
SEND_SIGNAL(src, COMSIG_AIRLOCK_OPEN, forced)
operating = TRUE
update_icon(state = AIRLOCK_OPENING, override = TRUE)
sleep(0.1 SECONDS)
@@ -1357,6 +1358,7 @@
if(delayed_close_requested)
delayed_close_requested = FALSE
addtimer(CALLBACK(src, PROC_REF(close)), 1)
SEND_SIGNAL(src, COMSIG_ATOM_DOOR_OPEN) /// this is different because we need one that covers all doors
return TRUE
@@ -1386,6 +1388,20 @@
if(killthis)
SSexplosions.med_mov_atom += killthis
SEND_SIGNAL(src, COMSIG_AIRLOCK_CLOSE, forced)
var/turf/open/open_turf = get_turf(src)
if(open_turf.liquids)
var/datum/liquid_group/turfs_group = open_turf.liquids.liquid_group
turfs_group.remove_from_group(open_turf)
qdel(open_turf.liquids)
turfs_group.try_split(open_turf)
for(var/dir in GLOB.cardinals)
var/turf/open/direction_turf = get_step(open_turf, dir)
if(!isopenturf(direction_turf) || !direction_turf.liquids)
continue
turfs_group.check_edges(direction_turf)
operating = TRUE
update_icon(state = AIRLOCK_CLOSING, override = TRUE)
layer = CLOSED_DOOR_LAYER

View File

@@ -379,6 +379,7 @@
operating = FALSE
air_update_turf()
update_freelook_sight()
SEND_SIGNAL(src, COMSIG_ATOM_DOOR_OPEN)
if(autoclose)
spawn(autoclose)
close()
@@ -399,6 +400,19 @@
operating = TRUE
do_animate("closing")
var/turf/open/open_turf = get_turf(src)
if(open_turf.liquids)
var/datum/liquid_group/turfs_group = open_turf.liquids.liquid_group
turfs_group.remove_from_group(open_turf)
qdel(open_turf.liquids)
turfs_group.try_split(open_turf)
for(var/dir in GLOB.cardinals)
var/turf/open/direction_turf = get_step(open_turf, dir)
if(!isopenturf(direction_turf) || !direction_turf.liquids)
continue
turfs_group.check_edges(direction_turf)
layer = closingLayer
if(air_tight)
density = TRUE

View File

@@ -163,3 +163,14 @@
user.gib()
playsound(src, 'sound/items/eatfood.ogg', 50, 1, -1)
return MANUAL_SUICIDE
/obj/item/choice_beacon/liquids
name = "Free Liquid Pump Kit"
desc = "Kit containing a free liquid pump from SPAAAACE."
icon = 'icons/obj/device.dmi'
icon_state = "gangtool-blue"
item_state = "radio"
// LIQUIDS TM REMOVE THIS
/obj/item/choice_beacon/liquids/generate_display_names()
return list("Liquid Pump" = /obj/structure/liquid_pump)

View File

@@ -14,7 +14,7 @@
resistance_flags = FLAMMABLE
var/mopping = 0
var/mopcount = 0
var/mopcap = 15
var/mopcap = 45
var/mopspeed = 15
force_string = "robust... against germs"
var/insertable = TRUE
@@ -22,6 +22,7 @@
/obj/item/mop/Initialize(mapload)
. = ..()
create_reagents(mopcap, REFILLABLE)
AddComponent(/datum/component/liquids_interaction, TYPE_PROC_REF(/obj/item/mop, attack_on_liquids_turf))
/obj/item/mop/proc/clean(turf/A)
@@ -46,6 +47,11 @@
return
if(T)
// Disable normal cleaning if there are liquids.
if(T.liquids)
to_chat(user, span_warning("It would be quite difficult to clean this with a pool of liquids on top!"))
return
user.visible_message("[user] begins to clean \the [T] with [src].", span_notice("You begin to clean \the [T] with [src]..."))
var/realspeed = mopspeed
@@ -73,6 +79,33 @@
to_chat(user, span_warning("You are unable to fit your [name] into the [J.name]."))
return
/obj/item/mop/proc/attack_on_liquids_turf(obj/item/mop/the_mop, turf/target, mob/user, obj/effect/abstract/liquid_turf/liquids)
if(!user.Adjacent(target))
return FALSE
var/free_space = mopcap - reagents.total_volume
var/speed_mult = 1
var/datum/liquid_group/targeted_group = target?.liquids?.liquid_group
while(!QDELETED(targeted_group))
if(speed_mult >= 0.2)
speed_mult -= 0.05
if(free_space <= 0)
to_chat(user, span_warning("You cant absorb any more liquid with \the [src]!"))
return TRUE
if(!do_after(user, src.mopspeed * speed_mult, target = target))
break
if(the_mop.reagents.total_volume == the_mop.mopcap)
to_chat(user, span_warning("You cant absorb any more liquid with \the [src]!"))
break
if(targeted_group?.reagents_per_turf)
targeted_group?.trans_to_seperate_group(the_mop.reagents, min(targeted_group?.reagents_per_turf, 5))
to_chat(user, span_notice("You soak up some liquids with \the [src]."))
else if(!QDELETED(target?.liquids?.liquid_group))
targeted_group = target.liquids.liquid_group
else
break
user.changeNext_move(CLICK_CD_MELEE)
return TRUE
/obj/item/mop/cyborg
insertable = FALSE

View File

@@ -39,6 +39,30 @@
return
return ..()
/obj/structure/mop_bucket/attackby_secondary(obj/item/weapon, mob/user, params)
if(istype(weapon, /obj/item/mop))
if(!weapon.reagents.total_volume)
if(weapon.reagents.total_volume >= weapon.reagents.maximum_volume)
balloon_alert(user, "mop is already soaked!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(!reagents.total_volume < 1)
balloon_alert(user, "mop bucket is empty!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
reagents.trans_to(weapon, weapon.reagents.maximum_volume, transfered_by = user)
balloon_alert(user, "wet mop")
playsound(src, 'sound/effects/slosh.ogg', 25, vary = TRUE)
else
var/obj/item/mop/attacked_mop = weapon
to_chat(user, "You completly wring out the [attacked_mop.name] into the waste bucket of the cart.")
attacked_mop.reagents.remove_all(attacked_mop.mopcap)
if(istype(weapon, /obj/item/reagent_containers) || istype(weapon, /obj/item/mop))
update_appearance(UPDATE_OVERLAYS)
return SECONDARY_ATTACK_CONTINUE_CHAIN // skip attack animations when refilling cart
return SECONDARY_ATTACK_CONTINUE_CHAIN
/obj/structure/mopbucket/update_overlays()
. = ..()
if(reagents.total_volume > 0)

View File

@@ -40,11 +40,11 @@
/// Places a turf on top - for map loading
/turf/proc/load_on_top(turf/added_layer, flags)
var/area/our_area = get_area(src)
flags = our_area.PlaceOnTopReact(list(baseturfs), added_layer, flags)
flags = our_area.place_on_topReact(list(baseturfs), added_layer, flags)
if(flags & CHANGETURF_SKIP) // We haven't been initialized
if(flags_1 & INITIALIZED_1)
stack_trace("CHANGETURF_SKIP was used in a PlaceOnTop call for a turf that's initialized. This is a mistake. [src]([type])")
stack_trace("CHANGETURF_SKIP was used in a place_on_top call for a turf that's initialized. This is a mistake. [src]([type])")
assemble_baseturfs()
var/turf/new_turf

View File

@@ -82,6 +82,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
var/old_lighting_corner_NW = lighting_corner_NW
var/old_directional_opacity = directional_opacity
var/old_dynamic_lumcount = dynamic_lumcount
var/old_rcd_memory = rcd_memory
var/old_explosion_throw_details = explosion_throw_details
var/old_opacity = opacity
@@ -206,6 +207,14 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
//don't
if(!SSair.initialized)
return ..()
var/obj/effect/abstract/liquid_turf/old_liquids = liquids
var/datum/liquid_group/old_group = liquids?.liquid_group
var/evaporating = FALSE
if(old_group)
old_group.remove_from_group(liquids.my_turf)
if(SSliquids.evaporation_queue[src])
evaporating = TRUE
SSliquids.evaporation_queue -= src
if ((flags & CHANGETURF_INHERIT_AIR) && ispath(path, /turf/open))
var/datum/gas_mixture/stashed_air = new()
stashed_air.copy_from(air)
@@ -223,9 +232,17 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
QDEL_NULL(newTurf.air)
newTurf.air = stashed_air
update_air_ref(planetary_atmos ? 1 : 2)
if(old_liquids)
old_liquids.my_turf = newTurf
newTurf.liquids = old_liquids
old_group.add_to_group(newTurf)
if(evaporating)
SSliquids.evaporation_queue[newTurf] = TRUE
else
if(turf_fire)
qdel(turf_fire)
if(old_liquids)
qdel(old_liquids)
if(ispath(path, /turf/closed) || ispath(path, /turf/cordon))
flags |= CHANGETURF_RECALC_ADJACENT
update_air_ref(-1)

View File

@@ -93,7 +93,7 @@
* This replaces the current turf if it is plating and is passed plating, is tile and is passed tile.
* It places the new turf on top of itself if it is plating and is passed a tile.
* It also replaces the turf if it is tile and is passed plating, essentially destroying the over turf.
* Flags argument is passed directly to ChangeTurf or PlaceOnTop
* Flags argument is passed directly to ChangeTurf or place_on_top
*/
/turf/open/proc/replace_floor(turf/open/new_floor_path, flags)
if (!overfloor_placed && initial(new_floor_path.overfloor_placed))

View File

@@ -215,6 +215,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
if(length(vis_contents))
vis_contents.Cut()
SEND_SIGNAL(src, COMSIG_TURF_DESTROY)
/// WARNING WARNING
/// Turfs DO NOT lose their signals when they get replaced, REMEMBER THIS

View File

@@ -132,7 +132,9 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
/client/proc/admin_away,
/client/proc/centcom_podlauncher,/*Open a window to launch a Supplypod and configure it or it's contents*/
/client/proc/load_json_admin_event,
/client/proc/event_role_manager
/client/proc/event_role_manager,
/client/proc/spawn_liquid,
/client/proc/remove_liquid
))
GLOBAL_PROTECT(admin_verbs_fun)
GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character, /datum/admins/proc/beaker_panel))

View File

@@ -17,6 +17,9 @@
if(!air)
return
if(liquids && liquids.liquid_group && !liquids.fire_state)
liquids.liquid_group.ignite_turf(src)
if (air.get_moles(GAS_O2) < 0.5 || air.get_moles(GAS_HYPERNOB) > REACTION_OPPRESSION_THRESHOLD)
return

View File

@@ -3292,3 +3292,11 @@
small_item = TRUE
contains = list(/obj/item/wallframe/telescreen/preset)
crate_name = "telescreen crate"
// LIQUIDS TM REMOVE THIS
/datum/supply_pack/service/janitor/pump
name = "Liquids Pump Crate"
desc = "A crate containing a portable liquid pump, for stations that lack proper liquid infrastructure."
cost = 2000
crate_name = "liquid pump crate"
contains = list(/obj/structure/liquid_pump)

View File

@@ -48,3 +48,5 @@
ears = /obj/item/radio/headset/headset_srv
uniform = /obj/item/clothing/under/rank/civilian/janitor
uniform_skirt = /obj/item/clothing/under/rank/civilian/janitor/skirt
// LIQUIDS TM REMOVE THIS
backpack_contents = list(/obj/item/choice_beacon/liquids)

View File

@@ -149,7 +149,7 @@
* - y_upper: The maximum y coordinate to load
* - z_lower: The minimum z coordinate to load
* - z_upper: The maximum z coordinate to load
* - place_on_top: Whether to use /turf/proc/PlaceOnTop rather than /turf/proc/ChangeTurf
* - place_on_top: Whether to use /turf/proc/place_on_top rather than /turf/proc/ChangeTurf
* - new_z: If true, a new z level will be created for the map
*/
/proc/load_map(

View File

@@ -345,6 +345,10 @@
T = get_turf(src)
var/list/temp_blood_DNA
if(small_drip)
if(!QDELETED(T.liquids)) //just add it to our liquids
var/list/blood_drop = list(get_blood_id() = 0.1)
T.add_liquid_list(blood_drop, FALSE, 300)
return
// Only a certain number of drips (or one large splatter) can be on a given turf.
var/obj/effect/decal/cleanable/blood/drip/drop = locate() in T
if(drop)

View File

@@ -113,6 +113,21 @@
breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME)
else if(isturf(loc)) //Breathe from loc as turf
var/turf/our_turf = loc
if(our_turf.liquids && !HAS_TRAIT(src, TRAIT_NOBREATH) && ((body_position == LYING_DOWN && our_turf.liquids.liquid_state >= LIQUID_STATE_WAIST) || (body_position == STANDING_UP && our_turf.liquids.liquid_state >= LIQUID_STATE_FULLTILE)))
//Officially trying to breathe underwater
if(HAS_TRAIT(src, TRAIT_WATER_BREATHING))
failed_last_breath = FALSE
clear_alert("not_enough_oxy")
return FALSE
adjustOxyLoss(3)
failed_last_breath = TRUE
if(oxyloss <= OXYGEN_DAMAGE_CHOKING_THRESHOLD && stat == CONSCIOUS)
to_chat(src, span_userdanger("You hold in your breath!"))
else
//Try and drink water
our_turf.liquids.liquid_group.transfer_to_atom(src, CHOKE_REAGENTS_INGEST_ON_BREATH_AMOUNT)
visible_message(span_warning("[src] chokes on water!"), span_userdanger("You're choking on water!"))
var/breath_ratio = 0
if(environment)
breath_ratio = BREATH_VOLUME/environment.return_volume()

View File

@@ -42,6 +42,7 @@
return ..()
/mob/living/proc/ZImpactDamage(turf/T, levels)
SEND_SIGNAL(T, COMSIG_TURF_MOB_FALL, src)
visible_message(span_danger("[src] crashes into [T] with a sickening noise!"))
adjustBruteLoss((levels * 5) ** 1.5)
Knockdown(levels * 50)
@@ -633,6 +634,21 @@
cure_fakedeath()
SEND_SIGNAL(src, COMSIG_LIVING_POST_FULLY_HEAL)
/mob/living/proc/do_strange_reagent_revival()
if(iscarbon(src))
var/mob/living/carbon/C = src
for(var/organ in C.internal_organs)
var/obj/item/organ/O = organ
O.setOrganDamage(0)
adjustBruteLoss(-100)
adjustFireLoss(-100)
adjustOxyLoss(-200, 0)
adjustToxLoss(-200, 0, TRUE)
updatehealth()
if(revive())
emote("gasp")
log_combat(src, src, "revived", src)
//proc called by revive(), to check if we can actually ressuscitate the mob (we don't want to revive him and have him instantly die again)
/mob/living/proc/can_be_revived()
. = 1

View File

@@ -742,10 +742,10 @@
return TRUE
/// Like add_reagent but you can enter a list. Format it like this: list(/datum/reagent/toxin = 10, "beer" = 15)
/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null)
/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null, _no_react = FALSE)
for(var/r_id in list_reagents)
var/amt = list_reagents[r_id]
add_reagent(r_id, amt, data)
add_reagent(r_id, amt, data, no_react = _no_react)
/// Remove a specific reagent
/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to

View File

@@ -1,5 +1,7 @@
#define REM REAGENTS_EFFECT_MULTIPLIER
GLOBAL_VAR_INIT(global_evaporation_rate, 1)
GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
/proc/build_name2reagent()
@@ -62,8 +64,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
var/addiction_name = null
/// What biotypes can process this? We'll assume by default that it affects organics (and undead, for plasmemes)
var/compatible_biotypes = ALL_NON_ROBOTIC
/// How flammable is this material?
var/accelerant_quality = 0
/// You fucked up and this is now triggering its overdose effects, purge that shit quick.
var/overdosed = 0
///if false stops metab in liverless mobs
@@ -76,8 +77,23 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
var/harmful = FALSE
/// The default reagent container for the reagent. Currently only used for crafting icon/displays.
var/obj/item/reagent_containers/default_container = /obj/item/reagent_containers/glass/bottle
/// Are we from a material? We might wanna know that for special stuff. Like metalgen. Is replaced with a ref of the material on New()
///Whether it will evaporate if left untouched on a liquids simulated puddle
var/evaporates = TRUE
/// How flammable is this material? For liquid spills and molotov cocktails
var/accelerant_quality = 0
///Whether a fire from this requires oxygen in the atmosphere
var/fire_needs_oxygen = TRUE
///The opacity of the chems used to determine the alpha of liquid turfs
var/opacity = 175
///The rate of evaporation in units per call
var/evaporation_rate = 1
///The rate of evaporation for the entire GROUP per call, for special things like drying agent
var/group_evaporation_rate = 0
/// do we have a turf exposure (used to prevent liquids doing un-needed processes)
var/turf_exposure = FALSE
/// are we slippery?
var/slippery = TRUE
/datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references
. = ..()
@@ -149,6 +165,9 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
/datum/reagent/proc/on_ex_act(severity)
return
/datum/reagent/proc/evaporate(turf/exposed_turf, reac_volume)
return
/// Called if the reagent has passed the overdose threshold and is set to be triggering overdose effects
/datum/reagent/proc/overdose_process(mob/living/M)
return

View File

@@ -935,20 +935,7 @@
M.do_jitter_animation(10)
addtimer(CALLBACK(M, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 10), 40) //jitter immediately, then again after 4 and 8 seconds
addtimer(CALLBACK(M, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 10), 80)
sleep(10 SECONDS) //so the ghost has time to re-enter
if(iscarbon(M))
var/mob/living/carbon/C = M
for(var/organ in C.internal_organs)
var/obj/item/organ/O = organ
O.setOrganDamage(0)
M.adjustBruteLoss(-100)
M.adjustFireLoss(-100)
M.adjustOxyLoss(-200, 0)
M.adjustToxLoss(-200, 0, TRUE)
M.updatehealth()
if(M.revive())
M.emote("gasp")
log_combat(M, M, "revived", src)
addtimer(CALLBACK(M, TYPE_PROC_REF(/mob/living, do_strange_reagent_revival)), 10 SECONDS)
..()
/datum/reagent/medicine/strange_reagent/on_mob_life(mob/living/carbon/M)

View File

@@ -141,8 +141,9 @@
/datum/reagent/water
name = "Water"
description = "An ubiquitous chemical substance that is composed of hydrogen and oxygen."
color = "#609bdf77" // rgb: 96, 155, 223, 77 (alpha)
color = "#00B8FF" // rgb: 170, 170, 170, 77 (alpha)
taste_description = "water"
evaporation_rate = 4 // water goes fast
glass_icon_state = "glass_clear"
glass_name = "glass of water"
glass_desc = "The father of all refreshments."
@@ -1126,7 +1127,7 @@
glass_icon_state = "dr_gibb_glass"
glass_name = "glass of Dr. Gibb"
glass_desc = "Dr. Gibb. Not as dangerous as the glass_name might imply."
accelerant_quality = 10
accelerant_quality = 15
compatible_biotypes = ALL_BIOTYPES
/datum/reagent/fuel/reaction_mob(mob/living/M, methods=TOUCH, reac_volume, show_message = TRUE, permeability = 1)//Splashing people with welding fuel to make them easy to ignite!
@@ -1447,6 +1448,7 @@
color = "#C8A5DC"
taste_description = "oil"
compatible_biotypes = ALL_BIOTYPES
accelerant_quality = 8
/datum/reagent/oil/on_mob_life(mob/living/carbon/M)
M.adjustFireLoss(-2*REM, FALSE, FALSE, BODYPART_ROBOTIC)
@@ -1628,6 +1630,8 @@
reagent_state = LIQUID
color = "#A70FFF"
taste_description = "dryness"
group_evaporation_rate = 16
evaporation_rate = 0 //will never evaporate on it's own
/datum/reagent/drying_agent/reaction_turf(turf/open/T, reac_volume)
if(istype(T))

View File

@@ -38,6 +38,7 @@
taste_description = "burning"
accelerant_quality = 20
compatible_biotypes = ALL_BIOTYPES
evaporation_rate = 100
/datum/reagent/clf3/on_mob_life(mob/living/carbon/M)
M.adjust_fire_stacks(2)

View File

@@ -7,6 +7,7 @@
color = "#CF3600" // rgb: 207, 54, 0
taste_description = "bitterness"
taste_mult = 1.2
evaporation_rate = 3 //6x faster than normal chems
var/toxpwr = 1.5
var/silent_toxin = FALSE //won't produce a pain message when processed by liver/Life(seconds_per_tick = SSMOBS_DT, times_fired) if there isn't another non-silent toxin present.
@@ -59,7 +60,7 @@
taste_mult = 1.5
color = "#8228A0"
toxpwr = 3
accelerant_quality = 10
accelerant_quality = 50 //OWWW
compatible_biotypes = ALL_BIOTYPES
/datum/reagent/toxin/plasma/on_mob_life(mob/living/carbon/C)

View File

@@ -11,7 +11,6 @@
var/list/list_reagents = null
var/spawned_disease = null
var/disease_amount = 20
var/spillable = FALSE
/obj/item/reagent_containers/Initialize(mapload, vol)
. = ..()
@@ -25,6 +24,37 @@
add_initial_reagents()
AddComponent(/datum/component/liquids_interaction, TYPE_PROC_REF(/obj/item/reagent_containers, attack_on_liquids_turf))
/obj/item/reagent_containers/proc/attack_on_liquids_turf(obj/item/reagent_containers/my_beaker, turf/T, mob/living/user, obj/effect/abstract/liquid_turf/liquids)
if(!user.Adjacent(T))
return FALSE
if(!my_beaker.is_open_container())
return FALSE
if(!user.Adjacent(T))
return FALSE
if(user.combat_mode)
return FALSE
if(liquids.fire_state) //Use an extinguisher first
to_chat(user, "<span class='warning'>You can't scoop up anything while it's on fire!</span>")
return TRUE
if(liquids.liquid_group.expected_turf_height == 1)
to_chat(user, "<span class='warning'>The puddle is too shallow to scoop anything up!</span>")
return TRUE
var/free_space = my_beaker.reagents.maximum_volume - my_beaker.reagents.total_volume
if(free_space <= 0)
to_chat(user, "<span class='warning'>You can't fit any more liquids inside [my_beaker]!</span>")
return TRUE
var/desired_transfer = my_beaker.amount_per_transfer_from_this
if(desired_transfer > free_space)
desired_transfer = free_space
if(desired_transfer > liquids.liquid_group.reagents_per_turf)
desired_transfer = liquids.liquid_group.reagents_per_turf
liquids.liquid_group.trans_to_seperate_group(my_beaker.reagents, desired_transfer, liquids)
to_chat(user, "<span class='notice'>You scoop up around [round(desired_transfer)] units of liquids with [my_beaker].</span>")
user.changeNext_move(CLICK_CD_MELEE)
return TRUE
/obj/item/reagent_containers/proc/add_initial_reagents()
if(list_reagents)
reagents.add_reagent_list(list_reagents)
@@ -118,17 +148,34 @@
return
else
if(isturf(target) && reagents.reagent_list.len && thrownby)
log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]", "in [AREACOORD(target)]")
log_game("[key_name(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [AREACOORD(target)].")
message_admins("[ADMIN_LOOKUPFLW(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [ADMIN_VERBOSEJMP(target)].")
if(isturf(target))
var/turf/T = target
if(istype(T, /turf/open))
T.add_liquid_from_reagents(reagents, FALSE, reagents.chem_temp)
if(reagents.reagent_list.len && thrownby)
log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]", "in [AREACOORD(target)]")
log_game("[key_name(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [AREACOORD(target)].")
message_admins("[ADMIN_LOOKUPFLW(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [ADMIN_VERBOSEJMP(target)].")
else
reagents.reaction(target, TOUCH)
var/turf/targets_loc = target.loc
if(istype(targets_loc, /turf/open) && !target.density)
targets_loc.add_liquid_from_reagents(reagents)
else
targets_loc = get_step_towards(targets_loc, thrownby)
targets_loc.add_liquid_from_reagents(reagents) //not perfect but i can't figure out how to move something to the nearest visible turf from throw_target
visible_message(span_notice("[src] spills its contents all over [target]."))
reagents.reaction(target, TOUCH)
if(QDELETED(src))
return
if(!isturf(target)) // it all ends up on the floor because gravity exists
reagents.reaction(get_turf(target), TOUCH)
playsound(target, 'sound/effects/slosh.ogg', 25, TRUE)
var/image/splash_animation = image('icons/effects/effects.dmi', target, "splash")
if(isturf(target))
splash_animation = image('icons/effects/effects.dmi', target, "splash_floor")
splash_animation.color = mix_color_from_reagents(reagents.reagent_list)
flick_overlay_global(splash_animation, GLOB.clients, 1.0 SECONDS)
reagents.clear_reagents()
/obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M)

View File

@@ -460,7 +460,7 @@
base_icon_state = "coffee_cup"
possible_transfer_amounts = list(10)
volume = 30
spillable = TRUE
reagent_flags = OPENCONTAINER
/obj/item/reagent_containers/glass/coffee_cup/update_icon_state()
icon_state = reagents.total_volume ? base_icon_state : "[base_icon_state]_e"
@@ -715,7 +715,7 @@
fill_icon_thresholds = list(0, 20, 40, 60, 80, 100)
possible_transfer_amounts = list(5, 10)
amount_per_transfer_from_this = 5
spillable = FALSE
reagent_flags = OPENCONTAINER_NOSPILL
///variable to tell if the bottle can be refilled
var/cap_on = TRUE
obj_flags = UNIQUE_RENAME | UNIQUE_REDESC

View File

@@ -278,6 +278,24 @@
ITEM_SLOT_DEX_STORAGE
)
/obj/item/reagent_containers/glass/bucket/attackby_secondary(obj/item/weapon, mob/user, params)
. = ..()
if(istype(weapon, /obj/item/mop))
if(reagents.total_volume == volume)
to_chat(user, "The [src.name] can't hold anymore liquids")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
var/obj/item/mop/attacked_mop = weapon
if(attacked_mop.reagents.total_volume < 0.1)
to_chat(user, span_warning("Your [attacked_mop.name] is already dry!"))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
to_chat(user, "You wring out the [attacked_mop.name] into the [src.name].")
attacked_mop.reagents.trans_to(src, attacked_mop.mopcap * 0.25)
attacked_mop.reagents.remove_all(attacked_mop.mopcap)
return SECONDARY_ATTACK_CONTINUE_CHAIN
/obj/item/reagent_containers/glass/bucket/wooden
name = "wooden bucket"
icon_state = "woodbucket"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 928 KiB

After

Width:  |  Height:  |  Size: 843 KiB

View File

@@ -236,6 +236,7 @@
#include "code\__DEFINES\{yogs_defines}\is_helpers.dm"
#include "code\__DEFINES\{yogs_defines}\jungle.dm"
#include "code\__DEFINES\{yogs_defines}\layers.dm"
#include "code\__DEFINES\{yogs_defines}\liquids.dm"
#include "code\__DEFINES\{yogs_defines}\logging.dm"
#include "code\__DEFINES\{yogs_defines}\mapping.dm"
#include "code\__DEFINES\{yogs_defines}\maps.dm"
@@ -4429,6 +4430,19 @@
#include "yogstation\code\modules\jungleland\kinetic_javelin.dm"
#include "yogstation\code\modules\language\darkspeak.dm"
#include "yogstation\code\modules\language\japanese.dm"
#include "yogstation\code\modules\liquids\drains.dm"
#include "yogstation\code\modules\liquids\height_floors.dm"
#include "yogstation\code\modules\liquids\liquid_controller.dm"
#include "yogstation\code\modules\liquids\liquid_effect.dm"
#include "yogstation\code\modules\liquids\liquid_groups.dm"
#include "yogstation\code\modules\liquids\liquid_height.dm"
#include "yogstation\code\modules\liquids\liquid_interaction.dm"
#include "yogstation\code\modules\liquids\liquid_ocean.dm"
#include "yogstation\code\modules\liquids\liquid_plumbers.dm"
#include "yogstation\code\modules\liquids\liquid_pump.dm"
#include "yogstation\code\modules\liquids\liquid_status_effect.dm"
#include "yogstation\code\modules\liquids\liquid_turf.dm"
#include "yogstation\code\modules\liquids\tools.dm"
#include "yogstation\code\modules\language\language_holder.dm"
#include "yogstation\code\modules\language\voxpidgin.dm"
#include "yogstation\code\modules\mentor\follow.dm"

View File

@@ -0,0 +1,80 @@
//Structure as this doesn't need any power to work
/obj/structure/drain
name = "drain"
icon = 'yogstation/icons/obj/structures/drains.dmi'
icon_state = "drain"
desc = "Drainage inlet embedded in the floor to prevent flooding."
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
density = FALSE
plane = FLOOR_PLANE
layer = GAS_SCRUBBER_LAYER
anchored = TRUE
var/processing = FALSE
var/drain_flat = 5
var/drain_percent = 0.1
var/welded = FALSE
var/turf/my_turf //need to keep track of it for the signal, if in any bizarre cases something would be moving the drain
/obj/structure/drain/update_icon()
. = ..()
if(welded)
icon_state = "[initial(icon_state)]_welded"
else
icon_state = "[initial(icon_state)]"
/obj/structure/drain/welder_act(mob/living/user, obj/item/I)
..()
if(!I.tool_start_check(user, amount=0))
return TRUE
playsound(src, 'sound/items/welder2.ogg', 50, TRUE)
to_chat(user, span_notice("You start [welded ? "unwelding" : "welding"] [src]..."))
if(I.use_tool(src, user, 20))
to_chat(user, span_notice("You [welded ? "unweld" : "weld"] [src]."))
welded = !welded
update_icon()
if(welded)
if(processing)
STOP_PROCESSING(SSobj, src)
processing = FALSE
else if (my_turf.liquids)
START_PROCESSING(SSobj, src)
processing = TRUE
return TRUE
/obj/structure/drain/process()
if(!my_turf.liquids)
STOP_PROCESSING(SSobj, src)
processing = FALSE
return
my_turf.liquids.liquid_group.remove_any(my_turf.liquids, drain_flat + (drain_percent * my_turf.liquids.liquid_group.total_reagent_volume))
/obj/structure/drain/Initialize()
. = ..()
if(!isturf(loc))
stack_trace("Drain structure initialized not on a turf")
my_turf = loc
RegisterSignal(my_turf, COMSIG_TURF_LIQUIDS_CREATION, PROC_REF(liquids_signal))
if(my_turf.liquids)
START_PROCESSING(SSobj, src)
processing = TRUE
/obj/structure/drain/proc/liquids_signal()
SIGNAL_HANDLER
if(processing || welded)
return
START_PROCESSING(SSobj, src)
processing = TRUE
/obj/structure/drain/Destroy()
if(processing)
STOP_PROCESSING(SSobj, src)
UnregisterSignal(my_turf, COMSIG_TURF_LIQUIDS_CREATION)
my_turf = null
return ..()
/obj/structure/drain/big
desc = "Drainage inlet embedded in the floor to prevent flooding. This one seems large."
icon_state = "bigdrain"
drain_percent = 0.3
drain_flat = 15

View File

@@ -0,0 +1,57 @@
/obj/item/stack/tile/elevated
name = "elevated floor tile"
singular_name = "elevated floor tile"
turf_type = /turf/open/floor/elevated
merge_type = /obj/item/stack/tile/elevated
icon = 'yogstation/icons/obj/items/tiles.dmi'
icon_state = "elevated"
/obj/item/stack/tile/lowered
name = "lowered floor tile"
singular_name = "lowered floor tile"
turf_type = /turf/open/floor/lowered
merge_type = /obj/item/stack/tile/lowered
icon = 'yogstation/icons/obj/items/tiles.dmi'
icon_state = "lowered"
/obj/item/stack/tile/lowered/iron
name = "lowered floor tile"
singular_name = "lowered floor tile"
turf_type = /turf/open/floor/lowered
merge_type = /obj/item/stack/tile/lowered
icon = 'yogstation/icons/obj/items/tiles.dmi'
icon_state = "lowered"
/turf/open/floor/iron/pool/rust_heretic_act()
return
/turf/open/floor/elevated
name = "elevated floor"
floor_tile = /obj/item/stack/tile/elevated
icon = 'yogstation/icons/turf/floors/elevated_iron.dmi'
icon_state = "elevated_plasteel-0"
base_icon_state = "elevated_plasteel-0"
smoothing_flags = SMOOTH_CORNERS
smoothing_groups = SMOOTH_GROUP_ELEVATED_PLASTEEL
canSmoothWith = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_ELEVATED_PLASTEEL
liquid_height = 30
turf_height = 30
/turf/open/floor/elevated/rust_heretic_act()
return
/turf/open/floor/lowered
name = "lowered floor"
floor_tile = /obj/item/stack/tile/lowered
icon = 'yogstation/icons/turf/floors/lowered_iron.dmi'
icon_state = "lowered_plasteel-0"
base_icon_state = "lowered_plasteel-0"
smoothing_flags = SMOOTH_CORNERS
smoothing_groups = SMOOTH_GROUP_LOWERED_PLASTEEL
canSmoothWith = SMOOTH_GROUP_WALLS + SMOOTH_GROUP_LOWERED_PLASTEEL
liquid_height = -30
turf_height = -30
/turf/open/floor/lowered/rust_heretic_act()
return

View File

@@ -0,0 +1,233 @@
SUBSYSTEM_DEF(liquids)
name = "Liquid Turfs"
wait = 0.5 SECONDS
flags = SS_KEEP_TIMING | SS_NO_INIT
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/active_groups = list()
var/list/evaporation_queue = list()
var/evaporation_counter = 0 //Only process evaporation on intervals
var/list/temperature_queue = list()
var/list/active_ocean_turfs = list()
var/list/ocean_turfs = list()
var/list/currentrun_active_ocean_turfs = list()
var/list/unvalidated_oceans = list()
var/ocean_counter = 0
var/run_type = SSLIQUIDS_RUN_TYPE_GROUPS
///debug variable to toggle evaporation from running
var/debug_evaporation = FALSE
var/list/burning_turfs = list()
var/fire_counter = 0
var/member_counter = 0
var/list/arrayed_groups = list()
///list of groups to work on for cached edges
var/list/cached_edge_work_queue = list()
///list of groups we are going to work on in group process
var/list/group_process_work_queue = list()
///list of all work queue for turf processing
var/list/active_turf_group_queue = list()
/datum/controller/subsystem/liquids/stat_entry(msg)
msg += "AG:[length(active_groups)]|BT:[length(burning_turfs)]|EQ:[length(evaporation_queue)]|AO:[length(active_ocean_turfs)]|UO:[length(unvalidated_oceans)]"
return ..()
/datum/controller/subsystem/liquids/fire(resumed)
if(!length(active_groups) && !length(evaporation_queue) && !length(active_ocean_turfs) && !length(burning_turfs) && !length(unvalidated_oceans))
return
listclearnulls(active_groups)
if(length(unvalidated_oceans))
for(var/turf/open/floor/plating/ocean/unvalidated_turf in unvalidated_oceans)
if(MC_TICK_CHECK)
return
unvalidated_turf.assume_self()
if(length(arrayed_groups))
listclearnulls(arrayed_groups)
for(var/datum/liquid_group/liquid_group as anything in arrayed_groups)
if(QDELETED(liquid_group))
arrayed_groups -= liquid_group
continue
while(!MC_TICK_CHECK && length(liquid_group?.splitting_array)) // three at a time until we either finish or over-run, this should be done before anything else
liquid_group.work_on_split_queue()
liquid_group.cleanse_members()
if(!length(temperature_queue))
for(var/datum/liquid_group/liquid_group as anything in active_groups)
if(MC_TICK_CHECK)
return
if(QDELETED(liquid_group))
temperature_queue -= active_groups
continue
var/list/turfs = liquid_group.fetch_temperature_queue()
temperature_queue += turfs
if(run_type == SSLIQUIDS_RUN_TYPE_GROUPS)
if(!length(group_process_work_queue))
group_process_work_queue |= active_groups
listclearnulls(group_process_work_queue)
if(length(group_process_work_queue))
var/populate_evaporation = FALSE
if(!length(evaporation_queue))
populate_evaporation = TRUE
for(var/datum/liquid_group/liquid_group as anything in group_process_work_queue)
if(MC_TICK_CHECK)
return
if(QDELETED(liquid_group))
group_process_work_queue -= liquid_group
continue
liquid_group.process_group(TRUE)
if(populate_evaporation && (liquid_group.expected_turf_height < LIQUID_ANKLES_LEVEL_HEIGHT) && liquid_group.evaporates)
for(var/turf/listed_turf as anything in liquid_group.members)
if(QDELETED(listed_turf))
continue
evaporation_queue |= listed_turf
group_process_work_queue -= liquid_group
run_type = SSLIQUIDS_RUN_TYPE_TEMPERATURE
if(run_type == SSLIQUIDS_RUN_TYPE_TEMPERATURE)
listclearnulls(temperature_queue)
if(length(temperature_queue))
for(var/turf/open/temperature_turf as anything in temperature_queue)
if(MC_TICK_CHECK)
return
temperature_queue -= temperature_turf
if(QDELETED(temperature_turf.liquids))
continue
if(QDELETED(temperature_turf.liquids.liquid_group))
QDEL_NULL(temperature_turf.liquids)
continue
temperature_turf.liquids.liquid_group.act_on_queue(temperature_turf)
run_type = SSLIQUIDS_RUN_TYPE_EVAPORATION
if(run_type == SSLIQUIDS_RUN_TYPE_EVAPORATION && !debug_evaporation)
listclearnulls(evaporation_queue)
evaporation_counter++
if(evaporation_counter >= REQUIRED_EVAPORATION_PROCESSES)
evaporation_counter = 0
for(var/datum/liquid_group/liquid_group as anything in active_groups)
if(MC_TICK_CHECK)
return
if(QDELETED(liquid_group))
active_groups -= liquid_group
continue
liquid_group.check_dead()
if(!length(liquid_group?.splitting_array))
liquid_group.process_turf_disperse()
for(var/turf/liquid_turf as anything in evaporation_queue)
if(MC_TICK_CHECK)
return
if(!prob(EVAPORATION_CHANCE) || QDELETED(liquid_turf))
evaporation_queue -= liquid_turf
continue
liquid_turf?.liquids?.process_evaporation()
run_type = SSLIQUIDS_RUN_TYPE_FIRE
if(run_type == SSLIQUIDS_RUN_TYPE_FIRE)
fire_counter++
for(var/datum/liquid_group/liquid_group as anything in active_groups)
if(MC_TICK_CHECK)
return
if(length(liquid_group?.burning_members))
for(var/turf/burning_turf as anything in liquid_group.burning_members)
if(MC_TICK_CHECK)
return
if(!istype(burning_turf) || QDELING(burning_turf))
liquid_group.burning_members -= burning_turf
continue
liquid_group.process_spread(burning_turf)
if(fire_counter > REQUIRED_FIRE_PROCESSES)
for(var/datum/liquid_group/liquid_group as anything in active_groups)
if(MC_TICK_CHECK)
return
if(QDELETED(liquid_group))
active_groups -= liquid_group
continue
if(length(liquid_group.burning_members))
liquid_group.process_fire()
fire_counter = 0
run_type = SSLIQUIDS_RUN_TYPE_OCEAN
if(!length(currentrun_active_ocean_turfs))
currentrun_active_ocean_turfs = active_ocean_turfs
if(run_type == SSLIQUIDS_RUN_TYPE_OCEAN)
listclearnulls(currentrun_active_ocean_turfs)
ocean_counter++
if(ocean_counter >= REQUIRED_OCEAN_PROCESSES)
for(var/turf/open/floor/plating/ocean/active_ocean in currentrun_active_ocean_turfs)
if(MC_TICK_CHECK)
return
active_ocean.process_turf()
ocean_counter = 0
run_type = SSLIQUIDS_RUN_TYPE_TURFS
if(run_type == SSLIQUIDS_RUN_TYPE_TURFS)
member_counter++
if(!length(active_turf_group_queue))
active_turf_group_queue += active_groups
listclearnulls(active_turf_group_queue)
if(member_counter > REQUIRED_MEMBER_PROCESSES)
for(var/datum/liquid_group/liquid_group as anything in active_turf_group_queue)
if(MC_TICK_CHECK)
return
if(QDELETED(liquid_group))
active_turf_group_queue -= liquid_group
continue
liquid_group.build_turf_reagent()
active_turf_group_queue -= liquid_group
if(!liquid_group.exposure)
continue
for(var/turf/member as anything in liquid_group.members)
if(MC_TICK_CHECK)
return
if(!istype(member) || QDELING(member))
liquid_group.members -= member
continue
liquid_group.process_member(member)
member_counter = 0
run_type = SSLIQUIDS_RUN_TYPE_CACHED_EDGES
if(run_type == SSLIQUIDS_RUN_TYPE_CACHED_EDGES)
if(!length(cached_edge_work_queue))
cached_edge_work_queue |= active_groups
listclearnulls(cached_edge_work_queue)
if(length(cached_edge_work_queue))
for(var/datum/liquid_group/liquid_group as anything in cached_edge_work_queue)
if(MC_TICK_CHECK)
return
if(QDELETED(liquid_group))
cached_edge_work_queue -= liquid_group
continue
liquid_group.build_turf_reagent()
if(liquid_group.reagents_per_turf > LIQUID_HEIGHT_DIVISOR)
liquid_group.process_cached_edges()
cached_edge_work_queue -= liquid_group
run_type = SSLIQUIDS_RUN_TYPE_GROUPS
/client/proc/toggle_liquid_debug()
set category = "Debug"
set name = "Liquid Groups Color Debug"
set desc = "Liquid Groups Color Debug."
if(!holder)
return
GLOB.liquid_debug_colors = !GLOB.liquid_debug_colors

View File

@@ -0,0 +1,312 @@
/obj/effect/abstract/liquid_turf
name = "liquid"
icon = 'yogstation/icons/obj/effects/liquid.dmi'
icon_state = "water-0"
base_icon_state = "water"
anchored = TRUE
plane = FLOOR_PLANE
color = "#DDF"
alpha = 175
//For being on fire
light_power = 1
light_color = LIGHT_COLOR_FIRE
smoothing_flags = SMOOTH_BITMASK | SMOOTH_OBJ
smoothing_groups = SMOOTH_GROUP_WATER
canSmoothWith = SMOOTH_GROUP_WATER + SMOOTH_GROUP_WINDOW_FULLTILE + SMOOTH_GROUP_WALLS
mouse_opacity = FALSE
var/datum/liquid_group/liquid_group
var/turf/my_turf
var/fire_state = LIQUID_FIRE_STATE_NONE
var/liquid_state = LIQUID_STATE_PUDDLE
var/no_effects = FALSE
var/static/obj/effect/abstract/fire/small_fire/small_fire
var/static/obj/effect/abstract/fire/medium_fire/medium_fire
var/static/obj/effect/abstract/fire/big_fire/big_fire
var/mutable_appearance/displayed_content
/// State-specific message chunks for examine_turf()
var/static/list/liquid_state_messages = list(
"[LIQUID_STATE_PUDDLE]" = "a puddle of $",
"[LIQUID_STATE_ANKLES]" = "$ going [span_warning("up to your ankles")]",
"[LIQUID_STATE_WAIST]" = "$ going [span_warning("up to your waist")]",
"[LIQUID_STATE_SHOULDERS]" = "$ going [span_warning("up to your shoulders")]",
"[LIQUID_STATE_FULLTILE]" = "$ going [span_danger("over your head")]",
)
var/temporary_split_key
/obj/effect/abstract/liquid_turf/proc/process_evaporation()
if(liquid_group.expected_turf_height > LIQUID_ANKLES_LEVEL_HEIGHT)
SSliquids.evaporation_queue -= my_turf
return
//See if any of our reagents evaporates
var/any_change = FALSE
var/datum/reagent/R //Faster declaration
for(var/reagent_type in liquid_group.reagents.reagent_list)
R = reagent_type
//We evaporate. bye bye
if(initial(R.evaporates))
var/remove_amount = min((initial(R.evaporation_rate) * GLOB.global_evaporation_rate), R.volume, (liquid_group.reagents_per_turf / length(liquid_group.reagents.reagent_list)))
liquid_group.remove_specific(src, remove_amount, R, TRUE)
any_change = TRUE
R.evaporate(src.loc, remove_amount)
if(initial(R.group_evaporation_rate))
var/remove_amount = min((initial(R.group_evaporation_rate) * GLOB.global_evaporation_rate), liquid_group.total_reagent_volume, (liquid_group.reagents_per_turf / length(liquid_group.reagents.reagent_list)))
liquid_group.remove_any(src, remove_amount)
any_change = TRUE
R.evaporate(src.loc, remove_amount)
if(!any_change)
SSliquids.evaporation_queue -= my_turf
return
/obj/effect/abstract/liquid_turf/forceMove(atom/destination, no_tp=FALSE, harderforce = FALSE)
if(harderforce)
. = ..()
/obj/effect/abstract/liquid_turf/proc/set_new_liquid_state(new_state)
if(no_effects)
return
liquid_state = new_state
var/number = new_state - 1
if(number != 0)
icon_state = null
base_icon_state = null
update_appearance()
else
icon_state = initial(icon_state)
base_icon_state = initial(base_icon_state)
QUEUE_SMOOTH(src)
QUEUE_SMOOTH_NEIGHBORS(src)
/obj/effect/abstract/liquid_turf/update_overlays()
. = ..()
var/number = liquid_state - 1
if(number != 0)
. += mutable_appearance('yogstation/icons/obj/effects/liquid_overlays.dmi', "stage[number]_bottom", offset_spokesman = my_turf, plane = ABOVE_GAME_PLANE, layer = ABOVE_MOB_LAYER)
. += mutable_appearance('yogstation/icons/obj/effects/liquid_overlays.dmi', "stage[number]_top", offset_spokesman = my_turf, plane =GAME_PLANE, layer = GATEWAY_UNDERLAY_LAYER)
/obj/effect/abstract/liquid_turf/proc/set_fire_effect()
if(displayed_content)
vis_contents -= displayed_content
if(!liquid_group)
return
switch(liquid_group.group_fire_state)
if(LIQUID_FIRE_STATE_SMALL)
displayed_content = small_fire
if(LIQUID_FIRE_STATE_MILD)
displayed_content = small_fire
if(LIQUID_FIRE_STATE_MEDIUM)
displayed_content = medium_fire
if(LIQUID_FIRE_STATE_HUGE)
displayed_content = big_fire
if(LIQUID_FIRE_STATE_INFERNO)
displayed_content = big_fire
else
displayed_content = null
if(displayed_content)
vis_contents |= displayed_content
//Takes a flat of our reagents and returns it, possibly qdeling our liquids
/obj/effect/abstract/liquid_turf/proc/take_reagents_flat(flat_amount)
liquid_group.remove_any(src, flat_amount)
/obj/effect/abstract/liquid_turf/proc/movable_entered(datum/source, atom/movable/AM)
SIGNAL_HANDLER
if(!liquid_group)
qdel(src)
return
var/turf/T = source
if(isobserver(AM))
return //ghosts, camera eyes, etc. don't make water splashy splashy
if(liquid_group.group_overlay_state >= LIQUID_STATE_ANKLES)
if(prob(30))
var/sound_to_play = pick(list(
'yogstation/sound/effects/water_wade1.ogg',
'yogstation/sound/effects/water_wade2.ogg',
'yogstation/sound/effects/water_wade3.ogg',
'yogstation/sound/effects/water_wade4.ogg'
))
playsound(T, sound_to_play, 50, 0)
if(iscarbon(AM))
var/mob/living/carbon/C = AM
C.apply_status_effect(/datum/status_effect/water_affected)
if(isliving(AM))
var/mob/living/carbon/human/stepped_human = AM
liquid_group.expose_atom(stepped_human, 1, TOUCH)
else if (isliving(AM))
var/mob/living/L = AM
if(liquid_group.slippery)
if(prob(7) && !(L.movement_type & FLYING) && L.body_position == STANDING_UP)
L.slip(30, T, NO_SLIP_WHEN_WALKING, 0, TRUE)
if(fire_state)
AM.fire_act((T20C+50) + (50*fire_state), 125)
/obj/effect/abstract/liquid_turf/proc/mob_fall(datum/source, mob/M)
SIGNAL_HANDLER
var/turf/T = source
if(liquid_group.group_overlay_state >= LIQUID_STATE_ANKLES && T.has_gravity(T))
playsound(T, 'yogstation/sound/effects/splash.ogg', 50, 0)
if(iscarbon(M))
var/mob/living/carbon/C = M
if(C.wear_mask && C.wear_mask.flags_cover & MASKCOVERSMOUTH)
to_chat(C, span_userdanger("You fall in the water!"))
else
liquid_group.transfer_to_atom(src, CHOKE_REAGENTS_INGEST_ON_FALL_AMOUNT, C)
C.adjustOxyLoss(5)
//C.emote("cough")
INVOKE_ASYNC(C, TYPE_PROC_REF(/mob, emote), "cough")
to_chat(C, span_userdanger("You fall in and swallow some water!"))
else
to_chat(M, span_userdanger("You fall in the water!"))
/obj/effect/abstract/liquid_turf/Initialize(mapload, datum/liquid_group/group_to_add)
. = ..()
if(!small_fire)
small_fire = new
if(!medium_fire)
medium_fire = new
if(!big_fire)
big_fire = new
if(!my_turf)
my_turf = loc
if(!my_turf.liquids)
my_turf.liquids = src
if(group_to_add)
group_to_add.add_to_group(my_turf)
set_new_liquid_state(liquid_group.group_overlay_state)
if(!liquid_group && !group_to_add)
liquid_group = new(1, src)
if(!SSliquids)
CRASH("Liquid Turf created with the liquids sybsystem not yet initialized!")
my_turf = loc
RegisterSignal(my_turf, COMSIG_ATOM_ENTERED, PROC_REF(movable_entered))
RegisterSignal(my_turf, COMSIG_TURF_MOB_FALL, PROC_REF(mob_fall))
RegisterSignal(my_turf, COMSIG_ATOM_EXAMINE, PROC_REF(examine_turf))
SEND_SIGNAL(my_turf, COMSIG_TURF_LIQUIDS_CREATION, src)
if(z)
QUEUE_SMOOTH(src)
QUEUE_SMOOTH_NEIGHBORS(src)
/obj/effect/abstract/liquid_turf/Destroy(force)
UnregisterSignal(my_turf, list(COMSIG_ATOM_ENTERED, COMSIG_TURF_MOB_FALL, COMSIG_ATOM_EXAMINE))
if(liquid_group)
liquid_group.remove_from_group(my_turf)
if(my_turf in SSliquids.evaporation_queue)
SSliquids.evaporation_queue -= my_turf
if(my_turf in SSliquids.burning_turfs)
SSliquids.burning_turfs -= my_turf
my_turf.liquids = null
my_turf = null
QUEUE_SMOOTH_NEIGHBORS(src)
return ..()
/obj/effect/abstract/liquid_turf/proc/ChangeToNewTurf(turf/NewT)
if(NewT.liquids)
stack_trace("Liquids tried to change to a new turf, that already had liquids on it!")
UnregisterSignal(my_turf, list(COMSIG_ATOM_ENTERED, COMSIG_TURF_MOB_FALL))
if(SSliquids.evaporation_queue[my_turf])
SSliquids.evaporation_queue -= my_turf
SSliquids.evaporation_queue[NewT] = TRUE
my_turf.liquids = null
my_turf = NewT
liquid_group.move_liquid_group(src)
NewT.liquids = src
loc = NewT
RegisterSignal(my_turf, COMSIG_ATOM_ENTERED, PROC_REF(movable_entered))
RegisterSignal(my_turf, COMSIG_TURF_MOB_FALL, PROC_REF(mob_fall))
/**
* Handles COMSIG_ATOM_EXAMINE for the turf.
*
* Adds reagent info to examine text.
* Arguments:
* * source - the turf we're peekin at
* * examiner - the user
* * examine_text - the examine list
* */
/obj/effect/abstract/liquid_turf/proc/examine_turf(turf/source, mob/examiner, list/examine_list)
SIGNAL_HANDLER
if(!liquid_group)
qdel(src)
return
// This should always have reagents if this effect object exists, but as a sanity check...
if(!length(liquid_group.reagents.reagent_list))
return
var/liquid_state_template = liquid_state_messages["[liquid_group.group_overlay_state]"]
examine_list += "<hr>"
if(examiner.can_see_reagents())
examine_list += "<hr>"
if(length(liquid_group.reagents.reagent_list) == 1)
// Single reagent text.
var/datum/reagent/reagent_type = liquid_group.reagents.reagent_list[1]
var/reagent_name = initial(reagent_type.name)
var/volume = round(reagent_type.volume / length(liquid_group.members), 0.01)
examine_list += span_notice("There is [replacetext(liquid_state_template, "$", "[volume] units of [reagent_name]")] here.")
else
// Show each individual reagent
examine_list += "There is [replacetext(liquid_state_template, "$", "the following")] here:"
for(var/datum/reagent/reagent_type as anything in liquid_group.reagents.reagent_list)
var/reagent_name = initial(reagent_type.name)
var/volume = round(reagent_type.volume / length(liquid_group.members), 0.01)
examine_list += "&bull; [volume] units of [reagent_name]"
examine_list += span_notice("The solution has a temperature of [liquid_group.group_temperature]K.")
examine_list += "<hr>"
return
// Otherwise, just show the total volume
examine_list += span_notice("There is [replacetext(liquid_state_template, "$", "liquid")] here.")
/obj/effect/temp_visual/liquid_splash
icon = 'yogstation/icons/obj/effects/splash.dmi'
icon_state = "splash"
layer = FLY_LAYER
randomdir = FALSE
/obj/effect/abstract/fire
icon = 'yogstation/icons/obj/effects/liquid.dmi'
plane = FLOOR_PLANE
layer = BELOW_MOB_LAYER
mouse_opacity = FALSE
appearance_flags = RESET_COLOR | RESET_ALPHA
/obj/effect/abstract/fire/small_fire
icon_state = "fire_small"
/obj/effect/abstract/fire/medium_fire
icon_state = "fire_medium"
/obj/effect/abstract/fire/big_fire
icon_state = "fire_big"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
/**
* Liquid Height element; for dynamically applying liquid blockages.
*
* Used for reinforced tables, sandbags, and the likes.
*/
/datum/element/liquids_height
element_flags = ELEMENT_BESPOKE
argument_hash_start_idx = 2
///Height applied by this element
var/height_applied
/datum/element/liquids_height/Attach(datum/target, height_applied)
. = ..()
if(!ismovable(target))
return ELEMENT_INCOMPATIBLE
src.height_applied = height_applied
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_target_move))
var/atom/movable/movable_target = target
if(isturf(movable_target.loc))
var/turf/turf_loc = movable_target.loc
turf_loc.turf_height += height_applied
turf_loc.reasses_liquids()
/datum/element/liquids_height/Detach(atom/movable/target)
. = ..()
UnregisterSignal(target, list(COMSIG_MOVABLE_MOVED))
var/atom/movable/movable_target = target
if(isturf(movable_target.loc))
var/turf/turf_loc = movable_target.loc
turf_loc.turf_height -= height_applied
turf_loc.reasses_liquids()
/datum/element/liquids_height/proc/on_target_move(atom/movable/source, atom/OldLoc, Dir, Forced = FALSE)
SIGNAL_HANDLER
if(isturf(OldLoc))
var/turf/old_turf = OldLoc
old_turf.turf_height += height_applied
old_turf.reasses_liquids()
if(isturf(source.loc))
var/turf/new_turf = source.loc
new_turf.turf_height -= height_applied
new_turf.reasses_liquids()

View File

@@ -0,0 +1,28 @@
///This element allows for items to interact with liquids on turfs.
/datum/component/liquids_interaction
///Callback interaction called when the turf has some liquids on it
var/datum/callback/interaction_callback
/datum/component/liquids_interaction/Initialize(on_interaction_callback)
. = ..()
if(!istype(parent, /obj/item))
return COMPONENT_INCOMPATIBLE
interaction_callback = CALLBACK(parent, on_interaction_callback)
/datum/component/liquids_interaction/RegisterWithParent()
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, PROC_REF(AfterAttack)) //The only signal allowing item -> turf interaction
/datum/component/liquids_interaction/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_ITEM_AFTERATTACK)
/datum/component/liquids_interaction/proc/AfterAttack(datum/source, atom/victim, mob/caster, proximity_flag, click_parameters)
SIGNAL_HANDLER
var/turf/turf_target = victim
if(!isturf(turf_target) || !turf_target.liquids)
return NONE
if(interaction_callback.Invoke(parent, victim, caster, turf_target.liquids))
return COMPONENT_CANCEL_ATTACK_CHAIN

View File

@@ -0,0 +1,332 @@
GLOBAL_LIST_INIT(initalized_ocean_areas, list())
/area/ocean
name = "Ocean"
icon = 'yogstation/icons/obj/effects/liquid.dmi'
base_icon_state = "ocean"
icon_state = "ocean"
alpha = 120
requires_power = TRUE
always_unpowered = TRUE
power_light = FALSE
power_equip = FALSE
power_environ = FALSE
outdoors = TRUE
ambience_index = AMBIENCE_SPACE
flags_1 = CAN_BE_DIRTY_1
sound_environment = SOUND_AREA_SPACE
/area/ocean/Initialize(mapload)
. = ..()
GLOB.initalized_ocean_areas += src
/area/ocean/dark
base_lighting_alpha = 0
/area/ruin/ocean
has_gravity = TRUE
/area/ruin/ocean/listening_outpost
unique = TRUE
/area/ruin/ocean/bunker
unique = TRUE
/area/ruin/ocean/bioweapon_research
unique = TRUE
/area/ruin/ocean/mining_site
unique = TRUE
/area/ocean/near_station_powered
requires_power = FALSE
/turf/open/openspace/ocean
name = "ocean"
planetary_atmos = TRUE
baseturfs = /turf/open/openspace/ocean
var/replacement_turf = /turf/open/floor/plating/ocean
/turf/open/openspace/ocean/Initialize()
. = ..()
ChangeTurf(replacement_turf, null, CHANGETURF_IGNORE_AIR)
/turf/open/floor/plating
///do we still call parent but dont want other stuff?
var/overwrites_attack_by = FALSE
/turf/open/floor/plating/ocean
plane = FLOOR_PLANE
layer = TURF_LAYER
force_no_gravity = FALSE
gender = PLURAL
name = "ocean sand"
baseturfs = /turf/open/floor/plating/ocean
icon = 'yogstation/icons/turf/floors/seafloor.dmi'
icon_state = "seafloor"
base_icon_state = "seafloor"
footstep = FOOTSTEP_SAND
barefootstep = FOOTSTEP_SAND
clawfootstep = FOOTSTEP_SAND
heavyfootstep = FOOTSTEP_GENERIC_HEAVY
planetary_atmos = TRUE
initial_gas_mix = OCEAN_DEFAULT_ATMOS
upgradable = FALSE
attachment_holes = FALSE
resistance_flags = INDESTRUCTIBLE
overwrites_attack_by = TRUE
var/static/obj/effect/abstract/ocean_overlay/static_overlay
var/static/list/ocean_reagents = list(/datum/reagent/water = 10)
var/ocean_temp = T20C
var/list/ocean_turfs = list()
var/list/open_turfs = list()
///are we captured, this is easier than having to run checks on turfs for vents
var/captured = FALSE
var/rand_variants = 0
var/rand_chance = 30
/// Itemstack to drop when dug by a shovel
var/obj/item/stack/dig_result = /obj/item/stack/ore/glass
/// Whether the turf has been dug or not
var/dug = FALSE
/// do we build a catwalk or plating with rods
var/catwalk = FALSE
/turf/open/floor/plating/ocean/Initialize()
. = ..()
RegisterSignal(src, COMSIG_ATOM_ENTERED, PROC_REF(movable_entered))
RegisterSignal(src, COMSIG_TURF_MOB_FALL, PROC_REF(mob_fall))
if(!static_overlay)
static_overlay = new(null, ocean_reagents)
vis_contents += static_overlay
light_color = static_overlay.color
SSliquids.unvalidated_oceans |= src
SSliquids.ocean_turfs |= src
if(rand_variants && prob(rand_chance))
var/random = rand(1,rand_variants)
icon_state = "[base_icon_state][random]"
base_icon_state = "[base_icon_state][random]"
/turf/open/floor/plating/ocean/Destroy()
. = ..()
UnregisterSignal(src, list(COMSIG_ATOM_ENTERED, COMSIG_TURF_MOB_FALL))
SSliquids.active_ocean_turfs -= src
SSliquids.ocean_turfs -= src
for(var/turf/open/floor/plating/ocean/listed_ocean as anything in ocean_turfs)
listed_ocean.rebuild_adjacent()
/turf/open/floor/plating/ocean/attackby(obj/item/C, mob/user, params)
if(..())
return
if(istype(C, /obj/item/stack/rods))
var/obj/item/stack/rods/R = C
if (R.get_amount() < 2)
to_chat(user, span_warning("You need two rods to make a [catwalk ? "catwalk" : "plating"]!"))
return
else
to_chat(user, span_notice("You begin constructing a [catwalk ? "catwalk" : "plating"]..."))
if(do_after(user, 30, target = src))
if (R.get_amount() >= 2 && !catwalk)
place_on_top(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
playsound(src, 'sound/items/deconstruct.ogg', 80, TRUE)
R.use(2)
to_chat(user, span_notice("You reinforce the [src]."))
else if(R.get_amount() >= 2 && catwalk)
new /obj/structure/lattice/catwalk(src)
playsound(src, 'sound/items/deconstruct.ogg', 80, TRUE)
R.use(2)
to_chat(user, span_notice("You build a catwalk over the [src]."))
/// Drops itemstack when dug and changes icon
/turf/open/floor/plating/ocean/proc/getDug()
dug = TRUE
new dig_result(src, 5)
/// If the user can dig the turf
/turf/open/floor/plating/ocean/proc/can_dig(mob/user)
if(!dug)
return TRUE
if(user)
to_chat(user, span_warning("Looks like someone has dug here already!"))
/turf/open/floor/plating/ocean/proc/assume_self()
if(!atmos_adjacent_turfs)
immediate_calculate_adjacent_turfs()
for(var/direction in GLOB.cardinals)
var/turf/directional_turf = get_step(src, direction)
if(istype(directional_turf, /turf/open/floor/plating/ocean))
ocean_turfs |= directional_turf
else
if(isclosedturf(directional_turf))
RegisterSignal(directional_turf, COMSIG_TURF_DESTROY, PROC_REF(add_turf_direction), TRUE)
continue
else if(!(directional_turf in atmos_adjacent_turfs))
var/obj/machinery/door/found_door = locate(/obj/machinery/door) in directional_turf
if(found_door)
RegisterSignal(found_door, COMSIG_ATOM_DOOR_OPEN, TYPE_PROC_REF(/turf/open/floor/plating/ocean, door_opened))
RegisterSignal(directional_turf, COMSIG_TURF_UPDATE_AIR, PROC_REF(add_turf_direction_non_closed), TRUE)
continue
else
open_turfs.Add(direction)
if(open_turfs.len)
SSliquids.active_ocean_turfs |= src
SSliquids.unvalidated_oceans -= src
/turf/open/floor/plating/ocean/proc/door_opened(datum/source)
SIGNAL_HANDLER
var/obj/machinery/door/found_door = source
var/turf/turf = get_turf(found_door)
if(turf.can_atmos_pass())
turf.add_liquid_list(ocean_reagents, FALSE, ocean_temp)
/turf/open/floor/plating/ocean/proc/process_turf()
for(var/direction in open_turfs)
var/turf/directional_turf = get_step(src, direction)
if(isspaceturf(directional_turf) || istype(directional_turf, /turf/open/floor/plating/ocean))
RegisterSignal(directional_turf, COMSIG_TURF_DESTROY, PROC_REF(add_turf_direction), TRUE)
open_turfs -= direction
if(!open_turfs.len)
SSliquids.active_ocean_turfs -= src
return
else if(!(directional_turf in atmos_adjacent_turfs))
RegisterSignal(directional_turf, COMSIG_TURF_UPDATE_AIR, PROC_REF(add_turf_direction_non_closed), TRUE)
open_turfs -= direction
if(!open_turfs.len)
SSliquids.active_ocean_turfs -= src
return
directional_turf.add_liquid_list(ocean_reagents, FALSE, ocean_temp)
/turf/open/floor/plating/ocean/proc/rebuild_adjacent()
ocean_turfs = list()
open_turfs = list()
for(var/direction in GLOB.cardinals)
var/turf/directional_turf = get_step(src, direction)
if(istype(directional_turf, /turf/open/floor/plating/ocean))
ocean_turfs |= directional_turf
else
open_turfs.Add(direction)
if(open_turfs.len)
SSliquids.active_ocean_turfs |= src
else if(src in SSliquids.active_ocean_turfs)
SSliquids.active_ocean_turfs -= src
/turf/open/floor/plating/ocean/attackby(obj/item/C, mob/user, params)
. = ..()
if(C.tool_behaviour == TOOL_SHOVEL || C.tool_behaviour == TOOL_MINING)
if(!can_dig(user))
return TRUE
if(!isturf(user.loc))
return
balloon_alert(user, "digging...")
if(C.use_tool(src, user, 40, volume=50))
if(!can_dig(user))
return TRUE
getDug()
SSblackbox.record_feedback("tally", "pick_used_mining", 1, C.type)
return TRUE
/obj/effect/abstract/ocean_overlay
icon = 'yogstation/icons/obj/effects/liquid.dmi'
icon_state = "ocean"
base_icon_state = "ocean"
plane = AREA_PLANE //Same as weather, etc.
layer = ABOVE_MOB_LAYER
vis_flags = NONE
mouse_opacity = FALSE
alpha = 120
/obj/effect/abstract/ocean_overlay/Initialize(mapload, list/ocean_contents)
. = ..()
var/datum/reagents/fake_reagents = new
fake_reagents.add_reagent_list(ocean_contents)
color = mix_color_from_reagents(fake_reagents.reagent_list)
qdel(fake_reagents)
if(istype(loc, /area/ocean))
var/area/area_loc = loc
area_loc.base_lighting_color = color
/obj/effect/abstract/ocean_overlay/proc/mix_colors(list/ocean_contents)
var/datum/reagents/fake_reagents = new
fake_reagents.add_reagent_list(ocean_contents)
color = mix_color_from_reagents(fake_reagents.reagent_list)
qdel(fake_reagents)
if(istype(loc, /area/ocean))
var/area/area_loc = loc
area_loc.base_lighting_color = color
/turf/open/floor/plating/ocean/proc/mob_fall(datum/source, mob/M)
SIGNAL_HANDLER
var/turf/T = source
playsound(T, 'yogstation/sound/effects/splash.ogg', 50, 0)
if(iscarbon(M))
var/mob/living/carbon/C = M
to_chat(C, span_userdanger("You fall in the water!"))
/turf/open/floor/plating/ocean/proc/movable_entered(datum/source, atom/movable/AM)
SIGNAL_HANDLER
var/turf/T = source
if(isobserver(AM))
return //ghosts, camera eyes, etc. don't make water splashy splashy
if(prob(30))
var/sound_to_play = pick(list(
'yogstation/sound/effects/water_wade1.ogg',
'yogstation/sound/effects/water_wade2.ogg',
'yogstation/sound/effects/water_wade3.ogg',
'yogstation/sound/effects/water_wade4.ogg'
))
playsound(T, sound_to_play, 50, 0)
if(isliving(AM))
var/mob/living/arrived = AM
if(!arrived.has_status_effect(/datum/status_effect/ocean_affected))
arrived.apply_status_effect(/datum/status_effect/ocean_affected)
SEND_SIGNAL(AM, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WASH)
/turf/open/floor/plating/ocean/proc/add_turf_direction(datum/source)
SIGNAL_HANDLER
var/turf/direction_turf = source
if(istype(direction_turf, /turf/open/floor/plating/ocean))
return
open_turfs.Add(get_dir(src, direction_turf))
if(!(src in SSliquids.active_ocean_turfs))
SSliquids.active_ocean_turfs |= src
/turf/open/floor/plating/ocean/proc/add_turf_direction_non_closed(datum/source)
SIGNAL_HANDLER
var/turf/direction_turf = source
if(!(direction_turf in atmos_adjacent_turfs))
return
open_turfs.Add(get_dir(src, direction_turf))
if(!(src in SSliquids.active_ocean_turfs))
SSliquids.active_ocean_turfs |= src

View File

@@ -0,0 +1,336 @@
/**
* Base class for underfloor plumbing machines that mess with floor liquids.
*/
/obj/machinery/plumbing/floor_pump
icon = 'yogstation/icons/obj/structures/drains.dmi'
base_icon_state = "active_input"
icon_state = "active_input"
anchored = FALSE
density = FALSE
idle_power_usage = 10
active_power_usage = 1000
//buffer = 300
//category="Distribution"
//reagent_flags = NO_REACT
/// Pump is turned on by engineer, etc.
var/turned_on = FALSE
/// Only pump to this liquid level height. 0 means pump the most possible.
var/height_regulator = 0
/// The default duct layer for mapping
var/duct_layer = 0
/// Base amount to drain
var/drain_flat = 20
/// Additional ratio of liquid volume to drain
var/drain_percent = 1
/// Currently pumping.
var/is_pumping = FALSE
/// Floor tile is placed down
var/tile_placed = FALSE
var/processes = 0
var/processes_required = 25
/obj/machinery/plumbing/floor_pump/Initialize(mapload, bolt, layer)
. = ..()
RegisterSignal(src, COMSIG_OBJ_HIDE, PROC_REF(on_hide))
/obj/machinery/plumbing/floor_pump/examine(mob/user)
. = ..()
. += span_notice("It's currently turned [turned_on ? "ON" : "OFF"].")
. += span_notice("Its height regulator [height_regulator ? "points at [height_regulator]" : "is disabled"]. Click while unanchored to change.")
/obj/machinery/plumbing/floor_pump/update_appearance(updates)
. = ..()
layer = tile_placed ? GAS_SCRUBBER_LAYER : BELOW_OBJ_LAYER
plane = tile_placed ? FLOOR_PLANE : GAME_PLANE
/obj/machinery/plumbing/floor_pump/update_icon_state()
. = ..()
if(panel_open)
icon_state = "[base_icon_state]-open"
else if(is_pumping)
icon_state = "[base_icon_state]-pumping"
else if(is_operational() && turned_on)
icon_state = "[base_icon_state]-idle"
else
icon_state = base_icon_state
/obj/machinery/plumbing/floor_pump/default_unfasten_wrench(mob/user, obj/item/I, time = 20)
. = ..()
if(. == SUCCESSFUL_UNFASTEN)
turned_on = FALSE
update_icon_state()
/obj/machinery/plumbing/floor_pump/attack_hand(mob/user)
if(!anchored)
set_regulator(user)
return
balloon_alert(user, "turned [turned_on ? "off" : "on"]")
turned_on = !turned_on
update_icon_state()
/**
* Change regulator level -- ie. what liquid depth we are OK with, like a thermostat.
*/
/obj/machinery/plumbing/floor_pump/proc/set_regulator(mob/living/user)
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
var/new_height = tgui_input_number(user,
"At what water level should the pump stop pumping from 0 to [LIQUID_HEIGHT_CONSIDER_FULL_TILE]? 0 disables.",
"[src]",
default = height_regulator,
min_value = 0,
max_value = LIQUID_HEIGHT_CONSIDER_FULL_TILE)
if(QDELETED(src) || new_height == null)
return
height_regulator = new_height
/**
* Handle COMSIG_OBJ_HIDE to toggle whether we're on the floor
*/
/obj/machinery/plumbing/floor_pump/proc/on_hide(atom/movable/AM, should_hide)
tile_placed = should_hide
update_appearance()
/**
* Can the pump actually run at all?
*/
/obj/machinery/plumbing/floor_pump/proc/can_run()
return is_operational() \
&& turned_on \
&& anchored \
&& !panel_open \
&& isturf(loc) \
&& are_reagents_ready()
/**
* Is the internal reagents container able to give or take liquid as appropriate?
*/
/obj/machinery/plumbing/floor_pump/proc/are_reagents_ready()
CRASH("are_reagents_ready() must be overriden.")
/**
* Should we actually be pumping this tile right now?
* Arguments:
* * affected_turf - the turf to check.
*/
/obj/machinery/plumbing/floor_pump/proc/should_pump(turf/affected_turf)
return isturf(affected_turf) \
&& should_regulator_permit(affected_turf)
/**
* Should the liquid height regulator allow water to be pumped here?
*/
/obj/machinery/plumbing/floor_pump/proc/should_regulator_permit(turf/affected_turf)
CRASH("should_regulator_permit() must be overriden.")
/obj/machinery/plumbing/floor_pump/process(seconds_per_tick)
var/was_pumping = is_pumping
if(!can_run())
is_pumping = FALSE
if(was_pumping)
update_icon_state()
return
// Determine what tiles should be pumped. We grab from a 3x3 area,
// but overall try to pump the same volume regardless of number of affected tiles
var/turf/local_turf = get_turf(src)
var/list/turf/candidate_turfs = local_turf.get_atmos_adjacent_turfs(alldir = TRUE)
candidate_turfs += local_turf
var/list/turf/affected_turfs = list()
for(var/turf/candidate as anything in candidate_turfs)
if(should_pump(candidate))
affected_turfs += candidate
// Update state
is_pumping = length(affected_turfs) > 0
if(is_pumping != was_pumping)
update_icon_state()
if(!is_pumping)
return
// note that the length was verified to be > 0 directly above and is a local var.
var/multiplier = 1 / length(affected_turfs)
// We're good, actually pump.
for(var/turf/affected_turf as anything in affected_turfs)
pump_turf(affected_turf, seconds_per_tick, multiplier)
/**
* Pump out the liquids on a turf.
*
* Arguments:
* * affected_turf - the turf to pump liquids out of.
* * seconds_per_tick - machine process delta time
* * multiplier - Multiplier to apply to final volume we want to pump.
*/
/obj/machinery/plumbing/floor_pump/proc/pump_turf(turf/affected_turf, seconds_per_tick, multiplier)
CRASH("pump_turf() must be overriden.")
/obj/machinery/plumbing/floor_pump/input
name = "liquid input pump"
desc = "Pump used to siphon liquids from a location into the plumbing pipenet."
icon_state = "active_input"
base_icon_state = "active_input"
/obj/machinery/plumbing/floor_pump/input/Initialize(mapload, bolt, layer)
. = ..()
AddComponent(/datum/component/plumbing/simple_supply, bolt, layer || duct_layer)
/obj/machinery/plumbing/floor_pump/input/are_reagents_ready()
return reagents.total_volume < reagents.maximum_volume
/obj/machinery/plumbing/floor_pump/input/should_regulator_permit(turf/affected_turf)
return affected_turf.liquids && affected_turf.liquids.liquid_group.expected_turf_height > height_regulator
/obj/machinery/plumbing/floor_pump/input/pump_turf(turf/affected_turf, seconds_per_tick, multiplier)
if(processes < processes_required)
processes++
return
processes = 0
if(!affected_turf.liquids || !affected_turf.liquids.liquid_group || reagents.total_volume)
return
var/target_value = seconds_per_tick * (drain_flat + (affected_turf.liquids.liquid_group.total_reagent_volume * drain_percent)) * multiplier
//Free space handling
var/free_space = reagents.maximum_volume - reagents.total_volume
if(target_value > free_space)
target_value = free_space
var/datum/liquid_group/targeted_group = affected_turf.liquids.liquid_group
if(!targeted_group.reagents_per_turf)
return
var/turfs_to_pull = round(target_value / targeted_group.reagents_per_turf,1)
var/list/removed_turfs = targeted_group.return_connected_liquids_in_range(affected_turf.liquids, turfs_to_pull)
targeted_group.trans_to_seperate_group(reagents, target_value, merge = TRUE)
for(var/turf/listed_turf in removed_turfs)
var/datum/liquid_group/listed_group = listed_turf.liquids.liquid_group
targeted_group.remove_from_group(listed_turf)
qdel(listed_turf.liquids)
for(var/dir in GLOB.cardinals)
var/turf/open/direction_turf = get_step(listed_turf, dir)
if(!isopenturf(direction_turf) || !direction_turf.liquids)
continue
if(!listed_group)
continue
listed_group.check_edges(direction_turf)
///recalculate the values here because processing
targeted_group.total_reagent_volume = targeted_group.reagents.total_volume
targeted_group.reagents_per_turf = targeted_group.total_reagent_volume / length(targeted_group.members)
if(!removed_turfs.len)
return
while(removed_turfs.len)
var/turf/picked_turf = pick(removed_turfs)
var/list/output = targeted_group.try_split(picked_turf, TRUE)
removed_turfs -= picked_turf
for(var/turf/outputted_turf in output)
if(outputted_turf in removed_turfs)
removed_turfs -= outputted_turf
/obj/machinery/plumbing/floor_pump/input/on
icon_state = "active_input-mapping"
anchored = TRUE
turned_on = TRUE
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/plumbing/floor_pump/input/on, 0)
/obj/machinery/plumbing/floor_pump/input/on/waste
icon_state = "active_input-mapping2"
duct_layer = SECOND_DUCT_LAYER
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/plumbing/floor_pump/input/on/waste, 0)
/obj/machinery/plumbing/floor_pump/output
name = "liquid output pump"
desc = "Pump used to dump liquids out from a plumbing pipenet into a location."
icon_state = "active_output"
base_icon_state = "active_output"
/// Is the turf too full to pump more?
var/over_volume = FALSE
/// Max liquid volume on the turf before we stop pumping.
var/max_ext_volume = LIQUID_HEIGHT_CONSIDER_FULL_TILE
/// Is the turf too high-pressured to pump more?
var/over_pressure = FALSE
/// Max pressure on the turf before we stop pumping.
var/max_ext_kpa = WARNING_HIGH_PRESSURE
/obj/machinery/plumbing/floor_pump/output/Initialize(mapload, bolt, layer)
. = ..()
AddComponent(/datum/component/plumbing/simple_demand, bolt, layer || duct_layer)
/obj/machinery/plumbing/floor_pump/output/examine(mob/user)
. = ..()
if(over_pressure)
. += span_warning("The gas regulator light is blinking.")
if(over_volume)
. += span_warning("The liquid volume regulator light is blinking.")
/obj/machinery/plumbing/floor_pump/output/are_reagents_ready()
return reagents.total_volume > 0
/obj/machinery/plumbing/floor_pump/output/should_regulator_permit(turf/affected_turf)
// 0 means keep pumping forever.
return !height_regulator || affected_turf.liquids.liquid_group.expected_turf_height < height_regulator
/obj/machinery/plumbing/floor_pump/output/process()
over_pressure = FALSE
return ..()
/obj/machinery/plumbing/floor_pump/output/should_pump(turf/affected_turf)
. = ..()
if(!.)
return FALSE
if(affected_turf.liquids?.liquid_group.expected_turf_height >= max_ext_volume)
return FALSE
var/turf/open/open_turf = affected_turf
var/datum/gas_mixture/gas_mix = open_turf?.return_air()
if(gas_mix?.return_pressure() > max_ext_kpa)
over_pressure = TRUE
return FALSE
return TRUE
/obj/machinery/plumbing/floor_pump/output/pump_turf(turf/affected_turf, seconds_per_tick, multiplier)
var/target_value = seconds_per_tick * (drain_flat + (reagents.total_volume * drain_percent)) * multiplier
if(target_value > reagents.total_volume)
target_value = reagents.total_volume
var/datum/reagents/tempr = new(10000)
reagents.trans_to(tempr, target_value, no_react = TRUE)
affected_turf.add_liquid_from_reagents(tempr)
qdel(tempr)
/obj/machinery/plumbing/floor_pump/output/on
icon_state = "active_output-mapping"
anchored = TRUE
turned_on = TRUE
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/plumbing/floor_pump/output/on, 0)
/obj/machinery/plumbing/floor_pump/output/on/supply
icon_state = "active_output-mapping2"
duct_layer = FOURTH_DUCT_LAYER
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/plumbing/floor_pump/output/on/supply, 0)
// Helpers for maps
/obj/machinery/duct/supply
duct_color = COLOR_CYAN
duct_layer = FOURTH_DUCT_LAYER
/obj/machinery/duct/waste
duct_color = COLOR_BROWN
duct_layer = SECOND_DUCT_LAYER

View File

@@ -0,0 +1,99 @@
//Right now it's a structure that works off of magic, as it'd require an internal power source for what its supposed to do
/obj/structure/liquid_pump
name = "portable liquid pump"
desc = "An industrial grade pump, capable of either siphoning or spewing liquids. Needs to be anchored first to work. Has a limited capacity internal storage."
icon = 'yogstation/icons/obj/structures/liquid_pump.dmi'
icon_state = "liquid_pump"
density = TRUE
max_integrity = 500
anchored = FALSE
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/// How many reagents at maximum can it hold
var/max_volume = 10000
/// Whether spewing reagents out, instead of siphoning them
var/spewing_mode = FALSE
/// Whether its turned on and processing
var/turned_on = FALSE
/// How fast does the pump work, in percentages relative to the volume we're working with
var/pump_speed_percentage = 0.4
/// How fast does the pump work, in flat values. Flat values on top of percentages to help processing
var/pump_speed_flat = 20
/obj/structure/liquid_pump/wrench_act(mob/living/user, obj/item/I)
. = ..()
default_unfasten_wrench(user, I, 40)
if(!anchored && turned_on)
toggle_working()
return TRUE
/obj/structure/liquid_pump/attack_hand(mob/user)
if(!anchored)
to_chat(user, span_warning("[src] needs to be anchored first!"))
return
to_chat(user, span_notice("You turn [src] [turned_on ? "off" : "on"]."))
toggle_working()
/obj/structure/liquid_pump/AltClick(mob/living/user)
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
to_chat(user, span_notice("You flick [src]'s spewing mode [spewing_mode ? "off" : "on"]."))
spewing_mode = !spewing_mode
update_icon()
/obj/structure/liquid_pump/examine(mob/user)
. = ..()
. += span_notice("It's anchor bolts are [anchored ? "down and secured" : "up"].")
. += span_notice("It's currently [turned_on ? "ON" : "OFF"].")
. += span_notice("It's mode currently is set to [spewing_mode ? "SPEWING" : "SIPHONING"]. (Alt-click to switch)")
. += span_notice("The pressure gauge shows [reagents.total_volume]/[reagents.maximum_volume].")
/obj/structure/liquid_pump/process()
if(!isturf(loc))
return
var/turf/T = loc
if(spewing_mode)
if(!reagents.total_volume)
return
var/datum/reagents/tempr = new(10000)
reagents.trans_to(tempr, (reagents.total_volume * pump_speed_percentage) + pump_speed_flat, no_react = TRUE)
T.add_liquid_from_reagents(tempr)
qdel(tempr)
else
if(!T.liquids)
return
var/free_space = reagents.maximum_volume - reagents.total_volume
if(!free_space)
return
var/target_siphon_amt = (T.liquids.liquid_group.total_reagent_volume * pump_speed_percentage) + pump_speed_flat
if(target_siphon_amt > free_space)
target_siphon_amt = free_space
T.liquids.liquid_group.transfer_to_atom(T.liquids, target_siphon_amt, src)
return
/obj/structure/liquid_pump/update_icon()
. = ..()
if(turned_on)
if(spewing_mode)
icon_state = "[initial(icon_state)]_spewing"
else
icon_state = "[initial(icon_state)]_siphoning"
else
icon_state = "[initial(icon_state)]"
/obj/structure/liquid_pump/proc/toggle_working()
if(turned_on)
STOP_PROCESSING(SSobj, src)
else
START_PROCESSING(SSobj, src)
turned_on = !turned_on
update_icon()
/obj/structure/liquid_pump/Initialize()
. = ..()
create_reagents(max_volume)
/obj/structure/liquid_pump/Destroy()
if(turned_on)
STOP_PROCESSING(SSobj, src)
qdel(reagents)
return ..()

View File

@@ -0,0 +1,46 @@
/datum/status_effect/water_affected
id = "wateraffected"
alert_type = null
duration = -1
/datum/status_effect/water_affected/on_apply()
//We should be inside a liquid turf if this is applied
calculate_water_slow()
return TRUE
/datum/status_effect/water_affected/proc/calculate_water_slow()
//Factor in swimming skill here?
var/turf/T = get_turf(owner)
var/slowdown_amount = T.liquids.liquid_group.group_overlay_state * 0.5
owner.add_movespeed_modifier(MOVESPEED_ID_LIQUID, multiplicative_slowdown = slowdown_amount)
/datum/status_effect/water_affected/tick()
var/turf/owner_turf = get_turf(owner)
if(QDELETED(owner_turf) || QDELETED(owner_turf.liquids) || owner_turf.liquids.liquid_group.group_overlay_state == LIQUID_STATE_PUDDLE)
qdel(src)
return
calculate_water_slow()
//Make the reagents touch the person
var/fraction = SUBMERGEMENT_PERCENT(owner, owner_turf.liquids)
owner_turf.liquids.liquid_group.expose_members_turf(owner_turf.liquids)
owner_turf.liquids.liquid_group.transfer_to_atom(owner_turf.liquids, ((SUBMERGEMENT_REAGENTS_TOUCH_AMOUNT * fraction / 20)), owner)
return ..()
/datum/status_effect/water_affected/on_remove()
owner.remove_movespeed_modifier(MOVESPEED_ID_LIQUID)
/datum/status_effect/ocean_affected
alert_type = null
duration = -1
/datum/status_effect/ocean_affected/tick()
var/turf/ocean_turf = get_turf(owner)
if(!istype(ocean_turf, /turf/open/floor/plating/ocean))
qdel(src)
if(ishuman(owner))
var/mob/living/carbon/human/arrived = owner
if(is_species(owner, /datum/species/ipc) && !(arrived.wear_suit?.clothing_flags & STOPSPRESSUREDAMAGE))
arrived.adjustFireLoss(5)

View File

@@ -0,0 +1,58 @@
/turf
var/obj/effect/abstract/liquid_turf/liquids
var/liquid_height = 0
var/turf_height = 0
/turf/proc/reasses_liquids()
if(!liquids)
return
if(!liquids.liquid_group)
liquids.liquid_group = new(1, liquids)
/turf/proc/liquid_update_turf()
if(!liquids)
return
//Check atmos adjacency to cut off any disconnected groups
if(liquids.liquid_group)
var/assoc_atmos_turfs = list()
for(var/tur in get_atmos_adjacent_turfs())
assoc_atmos_turfs[tur] = TRUE
//Check any cardinals that may have a matching group
for(var/direction in GLOB.cardinals)
var/turf/T = get_step(src, direction)
if(!T.liquids)
return
/turf/proc/add_liquid_from_reagents(datum/reagents/giver, no_react = FALSE, chem_temp)
var/list/compiled_list = list()
for(var/r in giver.reagent_list)
var/datum/reagent/R = r
if(!(R.type in GLOB.liquid_blacklist))
compiled_list[R.type] = R.volume
if(!compiled_list.len) //No reagents to add, don't bother going further
return
if(!liquids)
liquids = new(src)
liquids.liquid_group.add_reagents(liquids, compiled_list, chem_temp)
//More efficient than add_liquid for multiples
/turf/proc/add_liquid_list(reagent_list, no_react = FALSE, chem_temp)
if(liquids && !liquids.liquid_group)
qdel(liquids)
return
if(!liquids)
liquids = new(src)
liquids.liquid_group.add_reagents(liquids, reagent_list, chem_temp)
//Expose turf
liquids.liquid_group.expose_members_turf(liquids)
/turf/proc/add_liquid(reagent, amount, no_react = FALSE, chem_temp = 300)
if(reagent in GLOB.liquid_blacklist)
return
if(!liquids)
liquids = new(src)
liquids.liquid_group.add_reagent(liquids, reagent, amount, chem_temp)
//Expose turf
liquids.liquid_group.expose_members_turf(liquids)

View File

@@ -0,0 +1,75 @@
/client/proc/spawn_liquid()
set category = "Misc.Unused"
set name = "Spawn Liquid"
set desc = "Spawns an amount of chosen liquid at your current location."
var/choice
var/valid_id
while(!valid_id)
choice = stripped_input(usr, "Enter the ID of the reagent you want to add.", "Search reagents")
if(isnull(choice)) //Get me out of here!
break
if (!ispath(text2path(choice)))
choice = pick_closest_path(choice, make_types_fancy(subtypesof(/datum/reagent)))
if (ispath(choice))
valid_id = TRUE
else
valid_id = TRUE
if(!valid_id)
to_chat(usr, span_warning("A reagent with that ID doesn't exist!"))
if(!choice)
return
var/volume = input(usr, "Volume:", "Choose volume") as num
if(!volume)
return
if(volume >= 100000)
to_chat(usr, span_warning("Please limit the volume to below 100000 units!"))
return
var/turf/epicenter = get_turf(mob)
epicenter.add_liquid(choice, volume, FALSE, 300)
message_admins("[ADMIN_LOOKUPFLW(usr)] spawned liquid at [epicenter.loc] ([choice] - [volume]).")
log_admin("[key_name(usr)] spawned liquid at [epicenter.loc] ([choice] - [volume]).")
/client/proc/remove_liquid()
set name = "Remove Liquids"
set category = "Misc.Unused"
set desc = "Removes liquids in a specified radius."
var/turf/epicenter = get_turf(mob)
var/range = input(usr, "Enter range:", "Range selection", 2) as num
for(var/obj/effect/abstract/liquid_turf/liquid in range(range, epicenter))
if(QDELETED(liquid))
continue
if(!liquid)
continue
if(!liquid.liquid_group)
continue
liquid.liquid_group.remove_any(liquid, liquid.liquid_group.reagents_per_turf)
qdel(liquid)
message_admins("[key_name_admin(usr)] removed liquids with range [range] in [epicenter.loc.name]")
log_game("[key_name_admin(usr)] removed liquids with range [range] in [epicenter.loc.name]")
/client/proc/change_ocean()
set category = "Admin.Fun"
set name = "Change Ocean Liquid"
set desc = "Changes the reagent of the ocean."
var/choice = tgui_input_list(usr, "Choose a reagent", "Ocean Reagent", subtypesof(/datum/reagent))
if(!choice)
return
var/datum/reagent/chosen_reagent = choice
var/rebuilt = FALSE
for(var/turf/open/floor/plating/ocean/listed_ocean as anything in SSliquids.ocean_turfs)
if(!rebuilt)
listed_ocean.ocean_reagents = list()
listed_ocean.ocean_reagents[chosen_reagent] = 10
listed_ocean.static_overlay.mix_colors(listed_ocean.ocean_reagents)
for(var/area/ocean/ocean_types in GLOB.initalized_ocean_areas)
ocean_types.base_lighting_color = listed_ocean.static_overlay.color
ocean_types.update_base_lighting()
rebuilt = TRUE

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.