mirror of
https://github.com/KabKebab/GS13.git
synced 2026-02-09 15:17:41 +00:00
Merge pull request #10541 from Detective-Google/the-p-o-o-l
adds the POOL
This commit is contained in:
422
code/modules/pool/pool_controller.dm
Normal file
422
code/modules/pool/pool_controller.dm
Normal file
@@ -0,0 +1,422 @@
|
||||
#define POOL_NO_OVERDOSE_MEDICINE_MAX 5 //max units of no-overdose medicine to allow mobs to have through duplication
|
||||
|
||||
//Originally stolen from paradise. Credits to tigercat2000.
|
||||
//Modified a lot by Kokojo and Tortellini Tony for hippiestation.
|
||||
//Heavily refactored by tgstation
|
||||
/obj/machinery/pool
|
||||
icon = 'icons/obj/machines/pool.dmi'
|
||||
anchored = TRUE
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
|
||||
/obj/machinery/pool/controller
|
||||
name = "\improper Pool Controller"
|
||||
desc = "An advanced substance generation and fluid tank management system that can refill the contents of a pool to a completely different substance in minutes."
|
||||
icon_state = "poolc_3"
|
||||
density = TRUE
|
||||
use_power = TRUE
|
||||
idle_power_usage = 75
|
||||
/// How far it scans for pool objects
|
||||
var/scan_range = 6
|
||||
/// Is pool mist currently on?
|
||||
var/mist_state = FALSE
|
||||
/// Linked mist effects
|
||||
var/list/obj/effect/mist/linked_mist = list()
|
||||
/// Pool turfs
|
||||
var/list/turf/open/pool/linked_turfs = list()
|
||||
/// All mobs in pool
|
||||
var/list/mob/living/mobs_in_pool = list()
|
||||
/// Is the pool bloody?
|
||||
var/bloody = 0
|
||||
/// Last time we process_reagents()'d
|
||||
var/last_reagent_process = 0
|
||||
/// Maximum amount we will take from a beaker
|
||||
var/max_beaker_transfer = 100
|
||||
/// Minimum amount of a reagent for it to work on us
|
||||
var/min_reagent_amount = 10
|
||||
/// ADMINBUS ONLY - WHETHER OR NOT WE HAVE NOREACT ;)
|
||||
var/noreact_reagents = FALSE
|
||||
/// how fast in deciseconds between reagent processes
|
||||
var/reagent_tick_interval = 5
|
||||
/// Can we use unsafe temperatures
|
||||
var/temperature_unlocked = FALSE
|
||||
/// See __DEFINES/pool.dm, temperature defines
|
||||
var/temperature = POOL_NORMAL
|
||||
/// Whether or not the pool can be drained
|
||||
var/drainable = FALSE
|
||||
// Whether or not the pool is drained
|
||||
var/drained = FALSE
|
||||
/// Pool drain
|
||||
var/obj/machinery/pool/drain/linked_drain
|
||||
/// Pool filter
|
||||
var/obj/machinery/pool/filter/linked_filter
|
||||
/// Next world.time you can interact with settings
|
||||
var/interact_delay = 0
|
||||
/// Airlock style shocks
|
||||
var/shocked = FALSE
|
||||
/// Old reagent color, used to determine if update_color needs to reset colors.
|
||||
var/old_rcolor
|
||||
/// Just to prevent spam
|
||||
var/draining = FALSE
|
||||
/// Reagent blacklisting
|
||||
var/respect_reagent_blacklist = TRUE
|
||||
|
||||
/obj/machinery/pool/controller/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='boldnotice'>Alt click to drain reagents.</span>"
|
||||
|
||||
/obj/machinery/pool/controller/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
create_reagents(1000)
|
||||
if(noreact_reagents)
|
||||
reagents.reagents_holder_flags |= NO_REACT
|
||||
wires = new /datum/wires/poolcontroller(src)
|
||||
scan_things()
|
||||
|
||||
/obj/machinery/pool/controller/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
linked_drain = null
|
||||
linked_filter = null
|
||||
linked_turfs.Cut()
|
||||
mobs_in_pool.Cut()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/controller/proc/scan_things()
|
||||
var/list/cached = range(scan_range, src)
|
||||
for(var/turf/open/pool/W in cached)
|
||||
linked_turfs += W
|
||||
W.controller = src
|
||||
for(var/obj/machinery/pool/drain/pooldrain in cached)
|
||||
linked_drain = pooldrain
|
||||
linked_drain.controller = src
|
||||
break
|
||||
for(var/obj/machinery/pool/filter/F in cached)
|
||||
linked_filter = F
|
||||
linked_filter.controller = src
|
||||
break
|
||||
|
||||
/obj/machinery/pool/controller/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(!(obj_flags & EMAGGED)) //If it is not already emagged, emag it.
|
||||
to_chat(user, "<span class='warning'>You disable the [src]'s safety features.</span>")
|
||||
do_sparks(5, TRUE, src)
|
||||
obj_flags |= EMAGGED
|
||||
temperature_unlocked = TRUE
|
||||
drainable = TRUE
|
||||
log_game("[key_name(user)] emagged [src]")
|
||||
message_admins("[key_name_admin(user)] emagged [src]")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The interface on [src] is already too damaged to short it again.</span>")
|
||||
return
|
||||
|
||||
/obj/machinery/pool/controller/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!isliving(user) || !user.Adjacent(src) || !user.CanReach(src) || user.IsStun() || user.IsKnockdown() || user.incapacitated())
|
||||
return FALSE
|
||||
visible_message("<span class='boldwarning'>[user] starts to drain [src]!</span>")
|
||||
draining = TRUE
|
||||
if(!do_after(user, 50, target = src))
|
||||
draining = FALSE
|
||||
return TRUE
|
||||
reagents.remove_all(INFINITY)
|
||||
visible_message("<span class='boldnotice'>[user] drains [src].</span>")
|
||||
say("Reagents cleared.")
|
||||
update_color()
|
||||
draining = FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/pool/controller/attackby(obj/item/W, mob/user)
|
||||
if(shocked && !(stat & NOPOWER))
|
||||
shock(user,50)
|
||||
if(stat & (BROKEN))
|
||||
return
|
||||
if(istype(W,/obj/item/reagent_containers))
|
||||
if(W.reagents.total_volume) //check if there's reagent
|
||||
user.visible_message("<span class='boldwarning'>[user] is feeding [src] some chemicals from [W].</span>")
|
||||
if(do_after(user, 50, target = src))
|
||||
for(var/datum/reagent/R in W.reagents.reagent_list)
|
||||
if(R.type in GLOB.blacklisted_pool_reagents)
|
||||
to_chat(user, "[src] cannot accept [R.name].")
|
||||
return
|
||||
if(R.reagent_state == SOLID)
|
||||
to_chat(user, "The pool cannot accept reagents in solid form!.")
|
||||
return
|
||||
reagents.clear_reagents()
|
||||
// This also reacts them. No nitroglycerin deathpools, sorry gamers :(
|
||||
W.reagents.trans_to(reagents, max_beaker_transfer)
|
||||
user.visible_message("<span class='notice'>[src] makes a slurping noise.</span>", "<span class='notice'>All of the contents of [W] are quickly suctioned out by the machine!</span")
|
||||
updateUsrDialog()
|
||||
var/list/reagent_names = list()
|
||||
var/list/rejected = list()
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
if((R.volume >= min_reagent_amount) && (!respect_reagent_blacklist || R.can_synth))
|
||||
reagent_names += R.name
|
||||
else
|
||||
reagents.remove_reagent(R.type, INFINITY)
|
||||
rejected += R.name
|
||||
if(length(reagent_names))
|
||||
reagent_names = english_list(reagent_names)
|
||||
var/msg = "POOL: [key_name(user)] has changed [src]'s chems to [reagent_names]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
if(length(rejected))
|
||||
rejected = english_list(rejected)
|
||||
to_chat(user, "<span class='warning'>[src] rejects the following chemicals as they do not have at least [min_reagent_amount] units of volume: [rejected]</span>")
|
||||
update_color()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[src] beeps unpleasantly as it rejects the beaker. Why are you trying to feed it an empty beaker?</span>")
|
||||
return
|
||||
else if(panel_open && is_wire_tool(W))
|
||||
wires.interact(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/controller/screwdriver_act(mob/living/user, obj/item/W)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
cut_overlays()
|
||||
panel_open = !panel_open
|
||||
to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
|
||||
W.play_tool_sound(src)
|
||||
if(panel_open)
|
||||
add_overlay("wires")
|
||||
return TRUE
|
||||
|
||||
//procs
|
||||
/obj/machinery/pool/controller/proc/shock(mob/user, prb)
|
||||
if(stat & (BROKEN|NOPOWER)) // unpowered, no shock
|
||||
return FALSE
|
||||
if(!prob(prb))
|
||||
return FALSE
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
if(electrocute_mob(user, get_area(src), src, 0.7))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/controller/proc/process_reagents()
|
||||
if(last_reagent_process > world.time + reagent_tick_interval)
|
||||
return
|
||||
if(!length(reagents.reagent_list))
|
||||
return
|
||||
for(var/turf/open/pool/W in linked_turfs)
|
||||
for(var/mob/living/carbon/human/swimee in W)
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
if(R.reagent_state == SOLID)
|
||||
R.reagent_state = LIQUID
|
||||
if(!swimee.reagents.has_reagent(POOL_NO_OVERDOSE_MEDICINE_MAX))
|
||||
swimee.reagents.add_reagent(R.type, 0.5) //osmosis
|
||||
reagents.reaction(swimee, VAPOR, 0.03) //3 percent. Need to find a way to prevent this from stacking chems at some point like the above.
|
||||
for(var/obj/objects in W)
|
||||
if(W.reagents)
|
||||
W.reagents.reaction(objects, VAPOR, 1)
|
||||
last_reagent_process = world.time
|
||||
|
||||
/obj/machinery/pool/controller/process()
|
||||
updateUsrDialog()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(drained)
|
||||
return
|
||||
process_pool()
|
||||
process_reagents()
|
||||
|
||||
/obj/machinery/pool/controller/proc/process_pool()
|
||||
if(drained)
|
||||
return
|
||||
for(var/mob/living/M in mobs_in_pool)
|
||||
switch(temperature) //Apply different effects based on what the temperature is set to.
|
||||
if(POOL_SCALDING) //Scalding
|
||||
M.adjust_bodytemperature(50,0,500)
|
||||
if(POOL_WARM) //Warm
|
||||
M.adjust_bodytemperature(20,0,360) //Heats up mobs till the termometer shows up
|
||||
//Normal temp does nothing, because it's just room temperature water.
|
||||
if(POOL_COOL)
|
||||
M.adjust_bodytemperature(-20,250) //Cools mobs till the termometer shows up
|
||||
if(POOL_FRIGID) //Freezing
|
||||
M.adjust_bodytemperature(-60) //cool mob at -35k per cycle, less would not affect the mob enough.
|
||||
if(M.bodytemperature <= 50 && !M.stat)
|
||||
M.apply_status_effect(/datum/status_effect/freon)
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/drownee = M
|
||||
if(!drownee || drownee.stat == DEAD)
|
||||
return
|
||||
if(drownee.resting && !drownee.internal)
|
||||
if(drownee.stat != CONSCIOUS)
|
||||
drownee.adjustOxyLoss(9)
|
||||
else
|
||||
drownee.adjustOxyLoss(4)
|
||||
if(prob(35))
|
||||
to_chat(drownee, "<span class='danger'>You're drowning!</span>")
|
||||
|
||||
/obj/machinery/pool/controller/proc/set_bloody(state)
|
||||
if(bloody == state)
|
||||
return
|
||||
bloody = state
|
||||
update_color()
|
||||
|
||||
/obj/machinery/pool/controller/proc/update_color()
|
||||
if(drained)
|
||||
return
|
||||
var/rcolor
|
||||
if(reagents.reagent_list.len)
|
||||
rcolor = mix_color_from_reagents(reagents.reagent_list)
|
||||
if(rcolor == old_rcolor)
|
||||
return // small performance upgrade hopefully?
|
||||
old_rcolor = rcolor
|
||||
for(var/X in linked_turfs)
|
||||
var/turf/open/pool/color1 = X
|
||||
if(bloody)
|
||||
if(rcolor)
|
||||
var/thecolor = BlendRGB(rgb(150, 20, 20), rcolor, 0.5)
|
||||
color1.watereffect.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
var/thecolor = rgb(150, 20, 20)
|
||||
color1.watereffect.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.add_atom_colour(thecolor, FIXED_COLOUR_PRIORITY)
|
||||
else if(!bloody && rcolor)
|
||||
color1.watereffect.add_atom_colour(rcolor, FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.add_atom_colour(rcolor, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
color1.watereffect.remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
color1.watertop.remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/obj/machinery/pool/controller/proc/update_temp()
|
||||
if(mist_state)
|
||||
if(temperature < POOL_SCALDING)
|
||||
mist_off()
|
||||
else
|
||||
if(temperature == POOL_SCALDING)
|
||||
mist_on()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/pool/controller/update_icon()
|
||||
. = ..()
|
||||
icon_state = "poolc_[temperature]"
|
||||
|
||||
/obj/machinery/pool/controller/proc/CanUpTemp(mob/user)
|
||||
if(temperature == POOL_WARM && (temperature_unlocked || issilicon(user) || IsAdminGhost(user)) || temperature < POOL_WARM)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/controller/proc/CanDownTemp(mob/user)
|
||||
if(temperature == POOL_COOL && (temperature_unlocked || issilicon(user) || IsAdminGhost(user)) || temperature > POOL_COOL)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/controller/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(interact_delay > world.time)
|
||||
return
|
||||
if(href_list["IncreaseTemp"])
|
||||
if(CanUpTemp(usr))
|
||||
visible_message("<span class='warning'>[usr] presses a button on [src].</span>")
|
||||
temperature++
|
||||
update_temp()
|
||||
var/msg = "POOL: [key_name(usr)] increased [src]'s pool temperature at [COORD(src)] to [temperature]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
interact_delay = world.time + 15
|
||||
if(href_list["DecreaseTemp"])
|
||||
if(CanDownTemp(usr))
|
||||
visible_message("<span class='warning'>[usr] presses a button on [src].</span>")
|
||||
temperature--
|
||||
update_temp()
|
||||
var/msg = "POOL: [key_name(usr)] decreased [src]'s pool temperature at [COORD(src)] to [temperature]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
interact_delay = world.time + 15
|
||||
if(href_list["Activate Drain"])
|
||||
if((drainable || issilicon(usr) || IsAdminGhost(usr)) && !linked_drain.active)
|
||||
var/msg = "POOL: [key_name(usr)] activated [src]'s pool drain in [linked_drain.filling? "FILLING" : "DRAINING"] mode at [COORD(src)]"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
visible_message("<span class='warning'>[usr] presses a button on [src].</span>")
|
||||
mist_off()
|
||||
interact_delay = world.time + 60
|
||||
linked_drain.active = TRUE
|
||||
linked_drain.cycles_left = 75
|
||||
if(!linked_drain.filling)
|
||||
new /obj/effect/whirlpool(linked_drain.loc)
|
||||
temperature = POOL_NORMAL
|
||||
else
|
||||
new /obj/effect/waterspout(linked_drain.loc)
|
||||
temperature = POOL_NORMAL
|
||||
update_temp()
|
||||
bloody = FALSE
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/pool/controller/proc/temp2text()
|
||||
switch(temperature)
|
||||
if(POOL_FRIGID)
|
||||
return "<span class='boldwarning'>Frigid</span>"
|
||||
if(POOL_COOL)
|
||||
return "<span class='boldnotice'>Cool</span>"
|
||||
if(POOL_NORMAL)
|
||||
return "<span class='notice'>Normal</span>"
|
||||
if(POOL_WARM)
|
||||
return "<span class='boldnotice'>Warm</span>"
|
||||
if(POOL_SCALDING)
|
||||
return "<span class='boldwarning'>Scalding</span>"
|
||||
else
|
||||
return "Outside of possible range."
|
||||
|
||||
/obj/machinery/pool/controller/ui_interact(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(shocked && !(stat & NOPOWER))
|
||||
shock(user,50)
|
||||
if(panel_open && !isAI(user))
|
||||
return wires.interact(user)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
var/datum/browser/popup = new(user, "Pool Controller", name, 300, 450)
|
||||
var/dat = ""
|
||||
if(interact_delay > world.time)
|
||||
dat += "<span class='notice'>[round((interact_delay - world.time)/10, 0.1)] seconds left until [src] can operate again.</span><BR>"
|
||||
dat += text({"
|
||||
<h3>Temperature</h3>
|
||||
<div class='statusDisplay'>
|
||||
<B>Current temperature:</B> [temp2text()]<BR>
|
||||
[CanUpTemp(user) ? "<a href='?src=\ref[src];IncreaseTemp=1'>Increase Temperature</a><br>" : "<span class='linkOff'>Increase Temperature</span><br>"]
|
||||
[CanDownTemp(user) ? "<a href='?src=\ref[src];DecreaseTemp=1'>Decrease Temperature</a><br>" : "<span class='linkOff'>Decrease Temperature</span><br>"]
|
||||
</div>
|
||||
<h3>Drain</h3>
|
||||
<div class='statusDisplay'>
|
||||
<B>Drain status:</B> [(issilicon(user) || IsAdminGhost(user) || drainable) ? "<span class='bad'>Enabled</span>" : "<span class='good'>Disabled</span>"]
|
||||
<br><b>Pool status:</b> "})
|
||||
if(!drained)
|
||||
dat += "<span class='good'>Full</span><BR>"
|
||||
else
|
||||
dat += "<span class='bad'>Drained</span><BR>"
|
||||
if((issilicon(user) || IsAdminGhost(user) || drainable) && !linked_drain.active)
|
||||
dat += "<a href='?src=\ref[src];Activate Drain=1'>[drained ? "Fill" : "Drain"] Pool</a><br>"
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/pool/controller/proc/reset(wire)
|
||||
switch(wire)
|
||||
if(WIRE_SHOCK)
|
||||
if(!wires.is_cut(wire))
|
||||
shocked = FALSE
|
||||
|
||||
/obj/machinery/pool/controller/proc/mist_on() //Spawn /obj/effect/mist (from the shower) on all linked pool tiles
|
||||
if(mist_state)
|
||||
return
|
||||
mist_state = TRUE
|
||||
for(var/X in linked_turfs)
|
||||
var/turf/open/pool/W = X
|
||||
if(W.filled)
|
||||
var/M = new /obj/effect/mist(W)
|
||||
linked_mist += M
|
||||
|
||||
/obj/machinery/pool/controller/proc/mist_off() //Delete all /obj/effect/mist from all linked pool tiles.
|
||||
for(var/M in linked_mist)
|
||||
qdel(M)
|
||||
mist_state = FALSE
|
||||
160
code/modules/pool/pool_drain.dm
Normal file
160
code/modules/pool/pool_drain.dm
Normal file
@@ -0,0 +1,160 @@
|
||||
/obj/machinery/pool/drain
|
||||
name = "drain"
|
||||
icon_state = "drain"
|
||||
desc = "A suction system to remove the contents of the pool, and sometimes small objects. Do not insert fingers."
|
||||
anchored = TRUE
|
||||
/// Active/on?
|
||||
var/active = FALSE
|
||||
/// Filling or draining
|
||||
var/filling = FALSE
|
||||
/// Drain item suction range
|
||||
var/item_suction_range = 2
|
||||
/// Fill mode knock away range
|
||||
var/fill_push_range = 6
|
||||
/// Drain mode suction range
|
||||
var/drain_suck_range = 6
|
||||
/// Parent controller
|
||||
var/obj/machinery/pool/controller/controller
|
||||
/// Cycles left for fill/drain while active
|
||||
var/cycles_left = 0
|
||||
/// Mobs we are swirling around
|
||||
var/list/whirling_mobs
|
||||
/// Suck in once per x ticks
|
||||
var/suck_in_once_per = 3
|
||||
|
||||
var/cooldown
|
||||
|
||||
/obj/machinery/pool/drain/Initialize()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
whirling_mobs = list()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/drain/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
controller.linked_drain = null
|
||||
controller = null
|
||||
whirling_mobs = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/drain/proc/is_in_our_pool(atom/A)
|
||||
. = FALSE
|
||||
if(istype(A.loc, /turf/open/pool))
|
||||
var/turf/open/pool/P = A.loc
|
||||
if(P.controller == controller)
|
||||
. = TRUE
|
||||
|
||||
// This should probably start using move force sometime in the future but I'm lazy.
|
||||
/obj/machinery/pool/drain/process()
|
||||
if(!filling)
|
||||
for(var/obj/item/I in range(min(item_suction_range, 10), src))
|
||||
if(!I.anchored && (I.w_class <= WEIGHT_CLASS_SMALL))
|
||||
step_towards(I, src)
|
||||
if((I.w_class <= WEIGHT_CLASS_TINY) && (get_dist(I, src) == 0))
|
||||
I.forceMove(controller.linked_filter)
|
||||
if(active)
|
||||
if(filling)
|
||||
if(cycles_left-- > 0)
|
||||
playsound(src, 'sound/effects/fillingwatter.ogg', 100, TRUE)
|
||||
for(var/obj/O in orange(min(fill_push_range, 10), src))
|
||||
if(!O.anchored && is_in_our_pool(O))
|
||||
step_away(O, src)
|
||||
for(var/mob/M in orange(min(fill_push_range, 10), src)) //compiler fastpath apparently?
|
||||
if(!M.anchored && isliving(M) && is_in_our_pool(M))
|
||||
step_away(M, src)
|
||||
else
|
||||
for(var/turf/open/pool/P in controller.linked_turfs)
|
||||
P.filled = TRUE
|
||||
P.update_icon_state()
|
||||
for(var/obj/effect/waterspout/S in range(1, src))
|
||||
qdel(S)
|
||||
controller.drained = FALSE
|
||||
if(controller.bloody < 1000)
|
||||
controller.bloody /= 2
|
||||
else
|
||||
controller.bloody /= 4
|
||||
controller.update_color()
|
||||
filling = FALSE
|
||||
active = FALSE
|
||||
else
|
||||
if(cycles_left-- > 0)
|
||||
playsound(src, 'sound/effects/pooldrain.ogg', 100, TRUE)
|
||||
playsound(src, "water_wade", 60, TRUE)
|
||||
for(var/obj/O in orange(min(drain_suck_range, 10), src))
|
||||
if(!O.anchored && is_in_our_pool(O))
|
||||
step_towards(O, src)
|
||||
for(var/mob/M in orange(min(drain_suck_range, 10), src))
|
||||
if(isliving(M) && !M.anchored && is_in_our_pool(M))
|
||||
if(!(cycles_left % suck_in_once_per))
|
||||
step_towards(M, src)
|
||||
whirl_mob(M)
|
||||
if(ishuman(M) && (get_dist(M, src) <= 1))
|
||||
var/mob/living/carbon/human/H = M
|
||||
playsound(src, pick('sound/misc/crack.ogg','sound/misc/crunch.ogg'), 50, TRUE)
|
||||
if(H.lying) //down for any reason
|
||||
H.adjustBruteLoss(2)
|
||||
to_chat(H, "<span class='danger'>You're caught in the drain!</span>")
|
||||
else
|
||||
H.apply_damage(2.5, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) //drain should only target the legs
|
||||
to_chat(H, "<span class='danger'>Your legs are caught in the drain!</span>")
|
||||
else
|
||||
for(var/turf/open/pool/P in controller.linked_turfs)
|
||||
P.filled = FALSE
|
||||
P.update_icon_state()
|
||||
for(var/obj/effect/whirlpool/W in range(1, src))
|
||||
qdel(W)
|
||||
controller.drained = TRUE
|
||||
controller.mist_off()
|
||||
active = FALSE
|
||||
filling = TRUE
|
||||
|
||||
/// dangerous proc don't fuck with, admins
|
||||
/obj/machinery/pool/drain/proc/whirl_mob(mob/living/L, duration = 8, delay = 1)
|
||||
set waitfor = FALSE
|
||||
if(whirling_mobs[L])
|
||||
return
|
||||
whirling_mobs[L] = TRUE
|
||||
for(var/i in 1 to min(duration, 100))
|
||||
L.setDir(turn(L.dir, 90))
|
||||
sleep(delay)
|
||||
if(QDELETED(L))
|
||||
break
|
||||
if(QDELETED(src))
|
||||
return
|
||||
whirling_mobs -= L
|
||||
|
||||
/obj/machinery/pool/filter
|
||||
name = "Filter"
|
||||
icon_state = "filter"
|
||||
desc = "The part of the pool where all the IDs, ATV keys, and pens, and other dangerous things get trapped."
|
||||
var/obj/machinery/pool/controller/controller
|
||||
|
||||
/obj/machinery/pool/filter/Destroy()
|
||||
controller.linked_filter = null
|
||||
controller = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pool/filter/emag_act(mob/living/user)
|
||||
. = ..()
|
||||
if(!(obj_flags & EMAGGED))
|
||||
to_chat(user, "<span class='warning'>You disable the [src]'s shark filter! Run!</span>")
|
||||
obj_flags |= EMAGGED
|
||||
do_sparks(5, TRUE, src)
|
||||
icon_state = "filter_b"
|
||||
addtimer(CALLBACK(src, /obj/machinery/pool/filter/proc/spawn_shark), 50)
|
||||
var/msg = "[key_name(user)] emagged the pool filter and spawned a shark"
|
||||
log_game(msg)
|
||||
message_admins(msg)
|
||||
|
||||
/obj/machinery/pool/filter/proc/spawn_shark()
|
||||
if(prob(50))
|
||||
new /mob/living/simple_animal/hostile/shark(loc)
|
||||
else
|
||||
if(prob(50))
|
||||
new /mob/living/simple_animal/hostile/shark/kawaii(loc)
|
||||
else
|
||||
new /mob/living/simple_animal/hostile/shark/laser(loc)
|
||||
|
||||
/obj/machinery/pool/filter/attack_hand(mob/user)
|
||||
to_chat(user, "You search the filter.")
|
||||
for(var/obj/O in contents)
|
||||
O.forceMove(loc)
|
||||
29
code/modules/pool/pool_effects.dm
Normal file
29
code/modules/pool/pool_effects.dm
Normal file
@@ -0,0 +1,29 @@
|
||||
/obj/effect/splash
|
||||
name = "splash"
|
||||
desc = "Wataaa!."
|
||||
icon = 'icons/turf/pool.dmi'
|
||||
icon_state = "splash"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
|
||||
/obj/effect/whirlpool
|
||||
name = "Whirlpool"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "whirlpool"
|
||||
layer = 5
|
||||
anchored = TRUE
|
||||
mouse_opacity = 0
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
alpha = 90
|
||||
|
||||
/obj/effect/waterspout
|
||||
name = "Waterspout"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "waterspout"
|
||||
color = "#3399AA"
|
||||
layer = 5
|
||||
anchored = TRUE
|
||||
mouse_opacity = 0
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
alpha = 120
|
||||
191
code/modules/pool/pool_main.dm
Normal file
191
code/modules/pool/pool_main.dm
Normal file
@@ -0,0 +1,191 @@
|
||||
/turf/open/pool
|
||||
icon = 'icons/turf/pool.dmi'
|
||||
name = "poolwater"
|
||||
desc = "You're safer here than in the deep."
|
||||
icon_state = "pool_tile"
|
||||
heat_capacity = INFINITY
|
||||
var/filled = TRUE
|
||||
var/next_splash = 0
|
||||
var/obj/machinery/pool/controller/controller
|
||||
var/obj/effect/overlay/water/watereffect
|
||||
var/obj/effect/overlay/water/top/watertop
|
||||
|
||||
/turf/open/pool/Initialize(mapload)
|
||||
. = ..()
|
||||
update_icon_state()
|
||||
|
||||
/turf/open/pool/Destroy()
|
||||
if(controller)
|
||||
controller.linked_turfs -= src
|
||||
controller = null
|
||||
QDEL_NULL(watereffect)
|
||||
QDEL_NULL(watertop)
|
||||
return ..()
|
||||
|
||||
/turf/open/pool/update_icon_state()
|
||||
. = ..()
|
||||
if(!filled)
|
||||
name = "drained pool"
|
||||
desc = "No diving!"
|
||||
QDEL_NULL(watereffect)
|
||||
QDEL_NULL(watertop)
|
||||
else
|
||||
name = "poolwater"
|
||||
desc = "You're safer here than in the deep."
|
||||
watereffect = new /obj/effect/overlay/water(src)
|
||||
watertop = new /obj/effect/overlay/water/top(src)
|
||||
|
||||
/obj/effect/overlay/water
|
||||
name = "water"
|
||||
icon = 'icons/turf/pool.dmi'
|
||||
icon_state = "bottom"
|
||||
density = FALSE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
layer = ABOVE_MOB_LAYER
|
||||
anchored = TRUE
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
|
||||
/obj/effect/overlay/water/top
|
||||
icon_state = "top"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
// Mousedrop hook to normal turfs to get out of pools.
|
||||
/turf/open/MouseDrop_T(atom/from, mob/user)
|
||||
// I could make this /open/floor and not have the !istype but ehh - kev
|
||||
if(isliving(from) && HAS_TRAIT(from, TRAIT_SWIMMING) && isliving(user) && ((user == from) || user.CanReach(from)) && !user.IsStun() && !user.IsKnockdown() && !user.incapacitated() && !istype(src, /turf/open/pool))
|
||||
var/mob/living/L = from
|
||||
//The element only exists if you're on water and a living mob, so let's skip those checks.
|
||||
var/pre_msg
|
||||
var/post_msg
|
||||
if(user == from)
|
||||
pre_msg = "<span class='notice'>[L] is getting out of the pool.</span>"
|
||||
post_msg = "<span class='notice'>[L] gets out of the pool.</span>"
|
||||
else
|
||||
pre_msg = "<span class='notice'>[L] is being pulled out of the pool by [user].</span>"
|
||||
post_msg = "<span class='notice'>[user] pulls [L] out of the pool.</span>"
|
||||
L.visible_message(pre_msg)
|
||||
if(do_mob(user, L, 20))
|
||||
L.visible_message(post_msg)
|
||||
L.forceMove(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
// Exit check
|
||||
/turf/open/pool/Exit(atom/movable/AM, atom/newloc)
|
||||
if(!AM.has_gravity(src))
|
||||
return ..()
|
||||
if(isliving(AM) || isstructure(AM))
|
||||
if(AM.throwing)
|
||||
return ..() //WHEEEEEEEEEEE
|
||||
if(istype(AM, /obj/structure) && isliving(AM.pulledby))
|
||||
return ..() //people pulling stuff out of pool
|
||||
if(!ishuman(AM))
|
||||
return ..() //human weak, monkey (and anyone else) ook ook eek eek strong
|
||||
if(isliving(AM) && (locate(/obj/structure/pool/ladder) in src))
|
||||
return ..() //climbing out
|
||||
return istype(newloc, /turf/open/pool)
|
||||
return ..()
|
||||
|
||||
// Exited logic
|
||||
/turf/open/pool/Exited(atom/A, atom/newLoc)
|
||||
. = ..()
|
||||
if(isliving(A))
|
||||
var/turf/open/pool/P = newLoc
|
||||
if(!istype(P) || (P.controller != controller))
|
||||
controller?.mobs_in_pool -= A
|
||||
|
||||
// Entered logic
|
||||
/turf/open/pool/Entered(atom/movable/AM, atom/oldloc)
|
||||
if(istype(AM, /obj/effect/decal/cleanable))
|
||||
var/obj/effect/decal/cleanable/C = AM
|
||||
if(prob(C.bloodiness))
|
||||
controller.set_bloody(TRUE)
|
||||
QDEL_IN(AM, 25)
|
||||
animate(AM, alpha = 10, time = 20)
|
||||
return ..()
|
||||
if(!AM.has_gravity(src))
|
||||
return ..()
|
||||
if(isliving(AM))
|
||||
var/mob/living/victim = AM
|
||||
if(!HAS_TRAIT(victim, TRAIT_SWIMMING)) //poor guy not swimming time to dunk them!
|
||||
victim.AddElement(/datum/element/swimming)
|
||||
controller.mobs_in_pool += victim
|
||||
if(locate(/obj/structure/pool/ladder) in src) //safe climbing
|
||||
return
|
||||
if(iscarbon(AM)) //FUN TIME!
|
||||
var/mob/living/carbon/H = victim
|
||||
if(filled)
|
||||
if (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSMOUTH)
|
||||
H.visible_message("<span class='danger'>[H] falls in the water!</span>",
|
||||
"<span class='userdanger'>You fall in the water!</span>")
|
||||
playsound(src, 'sound/effects/splash.ogg', 60, TRUE, 1)
|
||||
H.Knockdown(20)
|
||||
return
|
||||
else
|
||||
H.Knockdown(60)
|
||||
H.adjustOxyLoss(5)
|
||||
H.emote("cough")
|
||||
H.visible_message("<span class='danger'>[H] falls in and takes a drink!</span>",
|
||||
"<span class='userdanger'>You fall in and swallow some water!</span>")
|
||||
playsound(src, 'sound/effects/splash.ogg', 60, TRUE, 1)
|
||||
else if(!H.head || !(H.head.armor.getRating("melee") > 20))
|
||||
if(prob(75))
|
||||
H.visible_message("<span class='danger'>[H] falls in the drained pool!</span>",
|
||||
"<span class='userdanger'>You fall in the drained pool!</span>")
|
||||
H.adjustBruteLoss(7)
|
||||
H.Knockdown(80)
|
||||
playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1)
|
||||
else
|
||||
H.visible_message("<span class='danger'>[H] falls in the drained pool, and cracks his skull!</span>",
|
||||
"<span class='userdanger'>You fall in the drained pool, and crack your skull!</span>")
|
||||
H.apply_damage(15, BRUTE, "head")
|
||||
H.Knockdown(200) // This should hurt. And it does.
|
||||
playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1)
|
||||
playsound(src, 'sound/misc/crack.ogg', 100, TRUE)
|
||||
else
|
||||
H.visible_message("<span class='danger'>[H] falls in the drained pool, but had an helmet!</span>",
|
||||
"<span class='userdanger'>You fall in the drained pool, but you had an helmet!</span>")
|
||||
H.Knockdown(40)
|
||||
playsound(src, 'sound/effects/woodhit.ogg', 60, TRUE, 1)
|
||||
else if(filled)
|
||||
victim.adjustStaminaLoss(1)
|
||||
playsound(src, "water_wade", 20, TRUE)
|
||||
return ..()
|
||||
|
||||
/turf/open/pool/MouseDrop_T(atom/from, mob/user)
|
||||
. = ..()
|
||||
if(!isliving(from))
|
||||
return
|
||||
var/mob/living/victim = from
|
||||
if(user.stat || user.lying || !Adjacent(user) || !from.Adjacent(user) || !iscarbon(user) || !victim.has_gravity(src) || HAS_TRAIT(victim, TRAIT_SWIMMING))
|
||||
return
|
||||
var/victimname = victim == user? "themselves" : "[victim]"
|
||||
var/starttext = victim == user? "[user] is descending into [src]." : "[user] is lowering [victim] into [src]."
|
||||
user.visible_message("<span class='notice'>[starttext]</span>")
|
||||
if(do_mob(user, victim, 20))
|
||||
user.visible_message("<span class='notice'>[user] lowers [victimname] into [src].</span>")
|
||||
victim.AddElement(/datum/element/swimming) //make sure they have it so they don't fall/whatever
|
||||
victim.forceMove(src)
|
||||
|
||||
/turf/open/pool/attackby(obj/item/W, mob/living/user)
|
||||
if(istype(W, /obj/item/mop) && filled)
|
||||
W.reagents.add_reagent("water", 5)
|
||||
to_chat(user, "<span class='notice'>You wet [W] in [src].</span>")
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/turf/open/pool/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if((user.loc != src) && !user.IsStun() && !user.IsKnockdown() && !user.incapacitated() && Adjacent(user) && HAS_TRAIT(user, TRAIT_SWIMMING) && filled && (next_splash < world.time))
|
||||
playsound(src, 'sound/effects/watersplash.ogg', 8, TRUE, 1)
|
||||
next_splash = world.time + 25
|
||||
var/obj/effect/splash/S = new(src)
|
||||
animate(S, alpha = 0, time = 8)
|
||||
QDEL_IN(S, 10)
|
||||
for(var/mob/living/carbon/human/H in src)
|
||||
if(!H.wear_mask && (H.stat == CONSCIOUS))
|
||||
H.emote("cough")
|
||||
H.adjustStaminaLoss(4)
|
||||
32
code/modules/pool/pool_noodles.dm
Normal file
32
code/modules/pool/pool_noodles.dm
Normal file
@@ -0,0 +1,32 @@
|
||||
//Pool noodles
|
||||
|
||||
/obj/item/toy/poolnoodle
|
||||
icon = 'icons/obj/toy.dmi'
|
||||
icon_state = "noodle"
|
||||
name = "pool noodle"
|
||||
desc = "A strange, bulky, bendable toy that can annoy people."
|
||||
force = 0
|
||||
color = "#000000"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throwforce = 1
|
||||
throw_speed = 10 //weeee
|
||||
hitsound = 'sound/weapons/tap.ogg'
|
||||
attack_verb = list("flogged", "poked", "jabbed", "slapped", "annoyed")
|
||||
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
|
||||
/obj/item/toy/poolnoodle/attack(target as mob, mob/living/user as mob)
|
||||
. = ..()
|
||||
user.spin(prob(20)? 16 : 8, 1)
|
||||
|
||||
/obj/item/toy/poolnoodle/red
|
||||
item_state = "noodlered"
|
||||
color = "#ff4c4c"
|
||||
|
||||
/obj/item/toy/poolnoodle/blue
|
||||
item_state = "noodleblue"
|
||||
color = "#3232ff"
|
||||
|
||||
/obj/item/toy/poolnoodle/yellow
|
||||
item_state = "noodleyellow"
|
||||
color = "#ffff66"
|
||||
159
code/modules/pool/pool_structures.dm
Normal file
159
code/modules/pool/pool_structures.dm
Normal file
@@ -0,0 +1,159 @@
|
||||
/obj/structure/pool
|
||||
name = "pool"
|
||||
icon = 'icons/obj/machines/pool.dmi'
|
||||
anchored = TRUE
|
||||
resistance_flags = UNACIDABLE|INDESTRUCTIBLE
|
||||
|
||||
/obj/structure/pool/ladder
|
||||
name = "Ladder"
|
||||
icon_state = "ladder"
|
||||
desc = "Are you getting in or are you getting out?."
|
||||
layer = ABOVE_MOB_LAYER
|
||||
dir = EAST
|
||||
|
||||
/obj/structure/pool/ladder/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!HAS_TRAIT(user, TRAIT_SWIMMING))
|
||||
if(user.CanReach(src))
|
||||
user.AddElement(/datum/element/swimming)
|
||||
user.forceMove(get_step(src, dir))
|
||||
else
|
||||
if(user.loc == loc)
|
||||
user.forceMove(get_step(src, turn(dir, 180))) //If this moves them out the element cleans up after itself.
|
||||
|
||||
/obj/structure/pool/Rboard
|
||||
name = "JumpBoard"
|
||||
density = FALSE
|
||||
icon_state = "boardright"
|
||||
desc = "The less-loved portion of the jumping board."
|
||||
dir = EAST
|
||||
|
||||
/obj/structure/pool/Lboard
|
||||
name = "JumpBoard"
|
||||
icon_state = "boardleft"
|
||||
desc = "Get on there to jump!"
|
||||
layer = FLY_LAYER
|
||||
dir = WEST
|
||||
var/jumping = FALSE
|
||||
var/timer
|
||||
|
||||
/obj/structure/pool/Lboard/proc/backswim()
|
||||
if(jumping)
|
||||
for(var/mob/living/jumpee in loc) //hackzors.
|
||||
playsound(jumpee, 'sound/effects/splash.ogg', 60, TRUE, 1)
|
||||
if(!HAS_TRAIT(jumpee, TRAIT_SWIMMING))
|
||||
jumpee.AddElement(/datum/element/swimming)
|
||||
jumpee.Stun(2)
|
||||
|
||||
/obj/structure/pool/Lboard/proc/reset_position(mob/user, initial_layer, initial_px, initial_py)
|
||||
user.layer = initial_layer
|
||||
user.pixel_x = initial_px
|
||||
user.pixel_y = initial_py
|
||||
|
||||
/obj/structure/pool/Lboard/attack_hand(mob/living/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/jumper = user
|
||||
if(jumping)
|
||||
to_chat(user, "<span class='notice'>Someone else is already making a jump!</span>")
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(HAS_TRAIT(user, TRAIT_SWIMMING))
|
||||
return
|
||||
else
|
||||
if(Adjacent(jumper))
|
||||
jumper.visible_message("<span class='notice'>[user] climbs up \the [src]!</span>", \
|
||||
"<span class='notice'>You climb up \the [src] and prepares to jump!</span>")
|
||||
jumper.Stun(40)
|
||||
jumping = TRUE
|
||||
var/original_layer = jumper.layer
|
||||
var/original_px = jumper.pixel_x
|
||||
var/original_py = jumper.pixel_y
|
||||
jumper.layer = RIPPLE_LAYER
|
||||
jumper.pixel_x = 3
|
||||
jumper.pixel_y = 7
|
||||
jumper.dir = WEST
|
||||
jumper.AddElement(/datum/element/swimming)
|
||||
sleep(1)
|
||||
jumper.forceMove(T)
|
||||
addtimer(CALLBACK(src, .proc/dive, jumper, original_layer, original_px, original_py), 10)
|
||||
|
||||
/obj/structure/pool/Lboard/proc/dive(mob/living/carbon/jumper, original_layer, original_px, original_py)
|
||||
switch(rand(1, 100))
|
||||
if(1 to 20)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for a small dive!</span>", \
|
||||
"<span class='notice'>You go for a small dive.</span>")
|
||||
sleep(15)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 1, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
|
||||
if(21 to 40)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for a dive!</span>", \
|
||||
"<span class='notice'>You're going for a dive!</span>")
|
||||
sleep(20)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 2, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
|
||||
if(41 to 60)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for a long dive! Stay far away!</span>", \
|
||||
"<span class='notice'>You're going for a long dive!!</span>")
|
||||
sleep(25)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 3, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
|
||||
if(61 to 80)
|
||||
jumper.visible_message("<span class='notice'>[jumper] goes for an awesome dive! Don't stand in [jumper.p_their()] way!</span>", \
|
||||
"<span class='notice'>You feel like this dive will be awesome</span>")
|
||||
sleep(30)
|
||||
backswim()
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 4, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
if(81 to 91)
|
||||
sleep(20)
|
||||
backswim()
|
||||
jumper.visible_message("<span class='danger'>[jumper] misses [jumper.p_their()] step!</span>", \
|
||||
"<span class='userdanger'>You misstep!</span>")
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 0, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
jumper.Knockdown(100)
|
||||
jumper.adjustBruteLoss(10)
|
||||
|
||||
if(91 to 100)
|
||||
jumper.visible_message("<span class='notice'>[jumper] is preparing for the legendary dive! Can [jumper.p_they()] make it?</span>", \
|
||||
"<span class='userdanger'>You start preparing for a legendary dive!</span>")
|
||||
jumper.SpinAnimation(7,1)
|
||||
|
||||
sleep(30)
|
||||
if(prob(75))
|
||||
backswim()
|
||||
jumper.visible_message("<span class='notice'>[jumper] fails!</span>", \
|
||||
"<span class='userdanger'>You can't quite do it!</span>")
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 1, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
else
|
||||
jumper.fire_stacks = min(1,jumper.fire_stacks + 1)
|
||||
jumper.IgniteMob()
|
||||
sleep(5)
|
||||
backswim()
|
||||
jumper.visible_message("<span class='danger'>[jumper] bursts into flames of pure awesomness!</span>", \
|
||||
"<span class='userdanger'>No one can stop you now!</span>")
|
||||
var/atom/throw_target = get_edge_target_turf(src, dir)
|
||||
jumper.throw_at(throw_target, 6, 1, callback = CALLBACK(src, .proc/on_finish_jump, jumper))
|
||||
addtimer(CALLBACK(src, .proc/togglejumping), 35)
|
||||
reset_position(jumper, original_layer, original_px, original_py)
|
||||
|
||||
/obj/structure/pool/Lboard/proc/togglejumping()
|
||||
jumping = FALSE
|
||||
|
||||
/obj/structure/pool/Lboard/proc/on_finish_jump(mob/living/victim)
|
||||
if(istype(victim.loc, /turf/open/pool))
|
||||
var/turf/open/pool/P = victim.loc
|
||||
if(!P.filled) //you dun fucked up now
|
||||
to_chat(victim, "<span class='warning'>That was stupid of you..</span>")
|
||||
victim.visible_message("<span class='danger'>[victim] smashes into the ground!</span>")
|
||||
victim.apply_damage(50)
|
||||
victim.Knockdown(200)
|
||||
59
code/modules/pool/pool_wires.dm
Normal file
59
code/modules/pool/pool_wires.dm
Normal file
@@ -0,0 +1,59 @@
|
||||
#define POOL_WIRE_DRAIN "drain"
|
||||
#define POOL_WIRE_TEMP "temp"
|
||||
|
||||
|
||||
/datum/wires/poolcontroller
|
||||
holder_type = /obj/machinery/pool/controller
|
||||
proper_name = "Pool"
|
||||
|
||||
/datum/wires/poolcontroller/New(atom/holder)
|
||||
wires = list(
|
||||
POOL_WIRE_DRAIN, WIRE_SHOCK, WIRE_ZAP, POOL_WIRE_TEMP
|
||||
)
|
||||
add_duds(3)
|
||||
..()
|
||||
|
||||
/datum/wires/poolcontroller/interactable(mob/user)
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
if(P.panel_open)
|
||||
return TRUE
|
||||
|
||||
/datum/wires/poolcontroller/get_status()
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
var/list/status = list()
|
||||
status += "The blue light is [P.drainable ? "on" : "off"]."
|
||||
status += "The red light is [P.temperature_unlocked ? "on" : "off"]."
|
||||
status += "The yellow light is [P.shocked ? "on" : "off"]."
|
||||
return status
|
||||
|
||||
/datum/wires/poolcontroller/on_pulse(wire)
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
switch(wire)
|
||||
if(POOL_WIRE_DRAIN)
|
||||
P.drainable = FALSE
|
||||
if(POOL_WIRE_TEMP)
|
||||
P.temperature_unlocked = FALSE
|
||||
if(WIRE_SHOCK)
|
||||
P.shocked = !P.shocked
|
||||
addtimer(CALLBACK(P, /obj/machinery/autolathe.proc/reset, wire), 60)
|
||||
|
||||
/datum/wires/poolcontroller/on_cut(wire, mend)
|
||||
var/obj/machinery/pool/controller/P = holder
|
||||
switch(wire)
|
||||
if(POOL_WIRE_DRAIN)
|
||||
if(mend)
|
||||
P.drainable = FALSE
|
||||
else
|
||||
P.drainable = TRUE
|
||||
if(POOL_WIRE_TEMP)
|
||||
if(mend)
|
||||
P.temperature_unlocked = FALSE
|
||||
else
|
||||
P.temperature_unlocked = TRUE
|
||||
if(WIRE_ZAP)
|
||||
P.shock(usr, 50)
|
||||
if(WIRE_SHOCK)
|
||||
if(mend)
|
||||
P.stat &= ~NOPOWER
|
||||
else
|
||||
P.stat |= NOPOWER
|
||||
Reference in New Issue
Block a user