Merge remote-tracking branch 'upstream/master' into more_ss_ports

# Conflicts:
#	paradise.dme
This commit is contained in:
tigercat2000
2018-04-30 09:27:11 -07:00
102 changed files with 1311 additions and 311 deletions
+1 -1
View File
@@ -298,7 +298,7 @@
/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...).
addtimer(src, "hitby_react", 2, TRUE, AM)
addtimer(CALLBACK(src, .proc/hitby_react, AM), 2)
/atom/proc/hitby_react(atom/movable/AM)
if(AM && isturf(AM.loc))
+3 -3
View File
@@ -166,11 +166,11 @@
/mob/living/forceMove(atom/destination)
if(buckled)
addtimer(src, "check_buckled", 1, TRUE)
addtimer(CALLBACK(src, .proc/check_buckled), 1, TIMER_UNIQUE)
if(buckled_mob)
addtimer(buckled_mob, "check_buckled", 1, TRUE)
addtimer(CALLBACK(buckled_mob, .proc/check_buckled), 1, TIMER_UNIQUE)
if(pulling)
addtimer(src, "check_pull", 1, TRUE)
addtimer(CALLBACK(src, .proc/check_pull), 1, TIMER_UNIQUE)
. = ..()
if(client)
reset_perspective(destination)
@@ -18,7 +18,7 @@
return FALSE
user.visible_message("<span class='warning'>[user] vomits a glob of acid on \his [O]!</span>", \
"<span class='warning'>We vomit acidic ooze onto our restraints!</span>")
addtimer(src, "dissolve_handcuffs", 30, FALSE, user, O)
addtimer(CALLBACK(src, .proc/dissolve_handcuffs, user, O), 30)
used = TRUE
if(user.wear_suit && user.wear_suit.breakouttime && !used)
@@ -27,7 +27,7 @@
return FALSE
user.visible_message("<span class='warning'>[user] vomits a glob of acid across the front of \his [S]!</span>", \
"<span class='warning'>We vomit acidic ooze onto our straight jacket!</span>")
addtimer(src, "dissolve_straightjacket", 30, FALSE, user, S)
addtimer(CALLBACK(src, .proc/dissolve_straightjacket, user, S), 30)
used = TRUE
@@ -37,7 +37,7 @@
return FALSE
C.visible_message("<span class='warning'>[C]'s hinges suddenly begin to melt and run!</span>")
to_chat(user, "<span class='warning'>We vomit acidic goop onto the interior of [C]!</span>")
addtimer(src, "open_closet", 70, FALSE, user, C)
addtimer(CALLBACK(src, .proc/open_closet, user, C), 70)
used = TRUE
if(istype(user.loc, /obj/structure/spider/cocoon) && !used)
@@ -46,7 +46,7 @@
return FALSE
C.visible_message("<span class='warning'>[src] shifts and starts to fall apart!</span>")
to_chat(user, "<span class='warning'>We secrete acidic enzymes from our skin and begin melting our cocoon...</span>")
addtimer(src, "dissolve_cocoon", 25, FALSE, user, C) //Very short because it's just webs
addtimer(CALLBACK(src, .proc/dissolve_cocoon, user, C), 25) //Very short because it's just webs
used = TRUE
if(used)
@@ -17,7 +17,7 @@
user.status_flags |= FAKEDEATH //play dead
user.update_canmove()
addtimer(src, "ready_to_regenerate", LING_FAKEDEATH_TIME, FALSE, user)
addtimer(CALLBACK(src, .proc/ready_to_regenerate, user), LING_FAKEDEATH_TIME)
feedback_add_details("changeling_powers","FD")
return 1
@@ -31,7 +31,7 @@
by quick repeated use!</span>")
recent_uses++
addtimer(src, "fleshmend", 0, FALSE, user)
INVOKE_ASYNC(src, .proc/fleshmend, user)
feedback_add_details("changeling_powers","RR")
return TRUE
@@ -159,9 +159,8 @@
for(var/obj/machinery/door/D in airlocks)
if(!is_station_level(D.z))
continue
spawn(0)
D.hostile_lockdown(src)
addtimer(D, "disable_lockdown", 900)
INVOKE_ASYNC(D, /obj/machinery/door.proc/hostile_lockdown, src)
addtimer(CALLBACK(D, /obj/machinery/door.proc/disable_lockdown), 900)
post_status("alert", "lockdown")
@@ -43,7 +43,8 @@
to_chat(B.host, "<span class='danger'>You feel the captive mind of [src] begin to resist your control.</span>")
var/delay = (rand(350,450) + B.host.brainloss)
addtimer(src, "return_control", delay, FALSE, B)
addtimer(CALLBACK(src, .proc/return_control, B), delay)
/mob/living/captive_brain/proc/return_control(mob/living/simple_animal/borer/B)
if(!B || !B.controlling)
@@ -534,7 +535,7 @@
leaving = TRUE
addtimer(src, "let_go", 200)
addtimer(CALLBACK(src, .proc/let_go), 200)
/mob/living/simple_animal/borer/proc/let_go()
@@ -611,7 +612,7 @@
bonding = TRUE
var/delay = 300+(host.getBrainLoss()*5)
addtimer(src, "assume_control", delay)
addtimer(CALLBACK(src, .proc/assume_control), delay)
/mob/living/simple_animal/borer/proc/assume_control()
if(!host || !src || controlling)
+7 -11
View File
@@ -118,7 +118,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/Initialize()
. = ..()
if(closeOtherId != null)
addtimer(src, "update_other_id", 5)
addtimer(CALLBACK(src, .proc/update_other_id), 5)
if(glass)
airlock_material = "glass"
if(security_level > AIRLOCK_SECURITY_METAL)
@@ -226,13 +226,11 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/proc/loseMainPower()
main_power_lost_until = mainPowerCablesCut() ? -1 : world.time + SecondsToTicks(60)
if(main_power_lost_until > 0)
main_power_timer = addtimer(src, "regainMainPower", SecondsToTicks(60), 1)
main_power_timer = addtimer(CALLBACK(src, .proc/regainMainPower), SecondsToTicks(60), TIMER_UNIQUE | TIMER_STOPPABLE)
// If backup power is permanently disabled then activate in 10 seconds if possible, otherwise it's already enabled or a timer is already running
if(backup_power_lost_until == -1 && !backupPowerCablesCut())
backup_power_lost_until = world.time + SecondsToTicks(10)
backup_power_timer = addtimer(src, "regainBackupPower", SecondsToTicks(10), 1)
backup_power_timer = addtimer(CALLBACK(src, .proc/regainBackupPower), SecondsToTicks(10), TIMER_UNIQUE | TIMER_STOPPABLE)
// Disable electricity if required
if(electrified_until && isAllPowerLoss())
electrify(0)
@@ -240,7 +238,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/proc/loseBackupPower()
backup_power_lost_until = backupPowerCablesCut() ? -1 : world.time + SecondsToTicks(60)
if(backup_power_lost_until > 0)
backup_power_timer = addtimer(src, "regainBackupPower", SecondsToTicks(60), 1)
backup_power_timer = addtimer(CALLBACK(src, .proc/regainBackupPower), SecondsToTicks(60), TIMER_UNIQUE | TIMER_STOPPABLE)
// Disable electricity if required
if(electrified_until && isAllPowerLoss())
@@ -288,8 +286,7 @@ About the new airlock wires panel:
message = "The door is now electrified [duration == -1 ? "permanently" : "for [duration] second\s"]."
electrified_until = duration == -1 ? -1 : world.time + SecondsToTicks(duration)
if(duration != -1)
electrified_timer = addtimer(src, "electrify", SecondsToTicks(duration), 1, 0)
electrified_timer = addtimer(CALLBACK(src, .proc/electrify, 0), SecondsToTicks(duration), TIMER_UNIQUE | TIMER_STOPPABLE)
if(feedback && message)
to_chat(usr, message)
@@ -1080,8 +1077,7 @@ About the new airlock wires panel:
// The `addtimer` system has the advantage of being cancelable
if(autoclose)
autoclose_timer = addtimer(src, "autoclose", normalspeed ? auto_close_time : auto_close_time_dangerous, unique = 1)
autoclose_timer = addtimer(CALLBACK(src, .proc/autoclose), normalspeed ? auto_close_time : auto_close_time_dangerous, TIMER_UNIQUE | TIMER_STOPPABLE)
return TRUE
/obj/machinery/door/airlock/close(forced=0, override = 0)
@@ -1098,7 +1094,7 @@ About the new airlock wires panel:
for(var/turf/turf in locs)
for(var/atom/movable/M in turf)
if(M.density && M != src) //something is blocking the door
addtimer(src, "autoclose", 60)
addtimer(CALLBACK(src, .proc/autoclose), 60)
use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people
if(forced)
+4 -2
View File
@@ -150,13 +150,15 @@
/obj/machinery/door/airlock/uranium/New()
..()
addtimer(src, "radiate", event_step)
addtimer(CALLBACK(src, .proc/radiate), event_step)
/obj/machinery/door/airlock/uranium/proc/radiate()
if(prob(50))
for(var/mob/living/L in range (3,src))
L.apply_effect(15,IRRADIATE,0)
addtimer(src, "radiate", event_step)
addtimer(CALLBACK(src, .proc/radiate), event_step)
/obj/machinery/door/airlock/uranium/glass
opacity = 0
+2 -2
View File
@@ -279,7 +279,7 @@
// The `addtimer` system has the advantage of being cancelable
if(autoclose)
autoclose_timer = addtimer(src, "autoclose", normalspeed ? auto_close_time : auto_close_time_dangerous, unique = 1)
autoclose_timer = addtimer(CALLBACK(src, .proc/autoclose), normalspeed ? auto_close_time : auto_close_time_dangerous, TIMER_UNIQUE | TIMER_STOPPABLE)
return TRUE
@@ -292,7 +292,7 @@
for(var/atom/movable/M in get_turf(src))
if(M.density && M != src) //something is blocking the door
if(autoclose)
addtimer(src, "autoclose", 60)
addtimer(CALLBACK(src, .proc/autoclose), 60)
return
operating = TRUE
+1 -1
View File
@@ -143,7 +143,7 @@ var/const/SAFETY_COOLDOWN = 100
safety_mode = 1
update_icon()
L.loc = loc
addtimer(src, "reboot", SAFETY_COOLDOWN)
addtimer(CALLBACK(src, .proc/reboot), SAFETY_COOLDOWN)
/obj/machinery/recycler/proc/reboot()
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
+1 -1
View File
@@ -438,7 +438,7 @@
chem_splash(get_turf(src), spread_range, list(reactants), temp_boost)
// Detonate it again in one second, until it's out of juice.
addtimer(src, "detonate", 10)
addtimer(CALLBACK(src, .proc/detonate), 10)
// If it's not a time release bomb, do normal explosion
+1 -1
View File
@@ -90,7 +90,7 @@
/obj/item/mecha_parts/mecha_equipment/proc/start_cooldown()
set_ready_state(0)
chassis.use_power(energy_drain)
addtimer(src, "set_ready_state", equip_cooldown, FALSE, 1)
addtimer(CALLBACK(src, .proc/set_ready_state, 1), equip_cooldown)
/obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(atom/target)
if(!chassis)
@@ -44,7 +44,7 @@ var/global/list/image/splatter_cache=list()
if(B.blood_DNA)
blood_DNA |= B.blood_DNA.Copy()
qdel(B)
dry_timer = addtimer(src, "dry", DRYING_TIME * (amount+1))
dry_timer = addtimer(CALLBACK(src, .proc/dry), DRYING_TIME * (amount+1), TIMER_STOPPABLE)
/obj/effect/decal/cleanable/blood/Destroy()
if(GAMEMODE_IS_CULT)
@@ -51,7 +51,7 @@ would spawn and follow the beaker, even if it is carried or thrown.
for(var/i in 1 to number)
if(total_effects > 20)
return
addtimer(src, "generate_effect", 0)
INVOKE_ASYNC(src, .proc/generate_effect)
/datum/effect_system/proc/generate_effect()
if(holder)
@@ -67,7 +67,7 @@ would spawn and follow the beaker, even if it is carried or thrown.
for(var/j in 1 to steps_amt)
sleep(5)
step(E,direction)
addtimer(src, "decrement_total_effect", 20)
addtimer(CALLBACK(src, .proc/decrement_total_effect), 20)
/datum/effect_system/proc/decrement_total_effect()
total_effects--
@@ -58,4 +58,4 @@
/datum/effect_system/explosion/smoke/start()
..()
addtimer(src, "create_smoke", 5)
addtimer(CALLBACK(src, .proc/create_smoke), 5)
@@ -39,7 +39,7 @@
/obj/effect/particle_effect/smoke/proc/kill_smoke()
processing_objects.Remove(src)
addtimer(src, "fade_out", 0)
INVOKE_ASYNC(src, .proc/fade_out)
QDEL_IN(src, 10)
/obj/effect/particle_effect/smoke/process()
@@ -67,7 +67,7 @@
if(C.smoke_delay)
return FALSE
C.smoke_delay++
addtimer(src, "remove_smoke_delay", 10, FALSE, C)
addtimer(CALLBACK(src, .proc/remove_smoke_delay, C), 10)
return TRUE
/obj/effect/particle_effect/smoke/proc/remove_smoke_delay(mob/living/carbon/C)
+2 -2
View File
@@ -72,7 +72,7 @@
else //if on the floor, glowshroom on-floor sprite
icon_state = "[base_icon_state]f"
addtimer(src, "Spread", delay, FALSE)
addtimer(CALLBACK(src, .proc/Spread), delay)
/obj/structure/glowshroom/proc/Spread()
var/turf/ownturf = get_turf(src)
@@ -117,7 +117,7 @@
shrooms_planted++ //if we failed due to generation, don't try to plant one later
if(shrooms_planted < myseed.yield) //if we didn't get all possible shrooms planted, try again later
myseed.yield -= shrooms_planted
addtimer(src, "Spread", delay, FALSE)
addtimer(CALLBACK(src, .proc/Spread), delay)
/obj/structure/glowshroom/proc/CalcDir(turf/location = loc)
var/direction = 16
+2 -2
View File
@@ -208,7 +208,7 @@
to_chat(I.owner, "<span class='warning'>Your photon projector implant overheats and deactivates!</span>")
I.Retract()
overheat = FALSE
addtimer(src, "cooldown", flashcd * 2)
addtimer(CALLBACK(src, .proc/cooldown), flashcd * 2)
/obj/item/flash/armimplant/try_use_flash(mob/user = null)
if(overheat)
@@ -216,7 +216,7 @@
to_chat(I.owner, "<span class='warning'>Your photon projector is running too hot to be used again so quickly!</span>")
return FALSE
overheat = TRUE
addtimer(src, "cooldown", flashcd)
addtimer(CALLBACK(src, .proc/cooldown), flashcd)
playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1)
update_icon(1)
return TRUE
@@ -271,7 +271,7 @@ var/global/list/default_medbay_channels = list(
universal_speak = 1
/mob/living/automatedannouncer/New()
lifetime_timer = addtimer(src, "autocleanup", SecondsToTicks(10))
lifetime_timer = addtimer(CALLBACK(src, .proc/autocleanup), SecondsToTicks(10), TIMER_STOPPABLE)
..()
/mob/living/automatedannouncer/Destroy()
@@ -620,7 +620,7 @@ var/global/list/default_medbay_channels = list(
/obj/item/radio/emp_act(severity)
on = 0
disable_timer++
addtimer(src, "enable_radio", rand(100, 200))
addtimer(CALLBACK(src, .proc/enable_radio), rand(100, 200))
if(listening)
visible_message("<span class='warning'>[src] buzzes violently!</span>")
+1 -1
View File
@@ -303,7 +303,7 @@
/obj/effect/decal/cleanable/ash/snappop_phoenix/New()
. = ..()
addtimer(src, "respawn", respawn_time)
addtimer(CALLBACK(src, .proc/respawn), respawn_time)
/obj/effect/decal/cleanable/ash/snappop_phoenix/proc/respawn()
new /obj/item/toy/snappop/phoenix(get_turf(src))
+1 -1
View File
@@ -385,7 +385,7 @@ RCD
buzz loudly!</b></span>","<span class='danger'><b>[src] begins \
vibrating violently!</b></span>")
// 5 seconds to get rid of it
addtimer(src, "detonate_pulse_explode", 50)
addtimer(CALLBACK(src, .proc/detonate_pulse_explode), 50)
/obj/item/rcd/proc/detonate_pulse_explode()
explosion(src, 0, 0, 3, 1, flame_range = 1)
@@ -85,7 +85,7 @@
target.overlays += image_overlay
if(!nadeassembly)
to_chat(user, "<span class='notice'>You plant the bomb. Timer counting down from [det_time].</span>")
addtimer(src, "prime", det_time*10)
addtimer(CALLBACK(src, .proc/prime), det_time*10)
/obj/item/grenade/plastic/suicide_act(mob/user)
message_admins("[key_name_admin(user)](<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</A>) suicided with [src.name] at ([user.x],[user.y],[user.z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)",0,1)
@@ -422,7 +422,7 @@
message_admins("grenade primed by an assembly, attached by [key_name_admin(M)]<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>(?)</A> (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[M]'>FLW</A>) and last touched by [key_name_admin(last)]<A HREF='?_src_=holder;adminmoreinfo=\ref[last]'>(?)</A> (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[last]'>FLW</A>) ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>[A.name] (JMP)</a>.")
log_game("grenade primed by an assembly, attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [A.name] ([T.x], [T.y], [T.z])")
else
addtimer(src, "prime", det_time)
addtimer(CALLBACK(src, .proc/prime), det_time)
var/turf/DT = get_turf(src)
var/area/DA = get_area(DT)
log_game("A grenade detonated at [DA.name] ([DT.x], [DT.y], [DT.z])")
@@ -53,7 +53,7 @@
if(iscarbon(user))
var/mob/living/carbon/C = user
C.throw_mode_on()
addtimer(src, "prime", det_time)
addtimer(CALLBACK(src, .proc/prime), det_time)
/obj/item/grenade/iedcasing/prime() //Blowing that can up
update_mob()
+1 -1
View File
@@ -132,7 +132,7 @@
/obj/item/restraints/legcuffs/beartrap/energy/New()
..()
addtimer(src, "dissipate", 100)
addtimer(CALLBACK(src, .proc/dissipate), 100)
/obj/item/restraints/legcuffs/beartrap/energy/proc/dissipate()
if(!ismob(loc))
+1 -1
View File
@@ -162,7 +162,7 @@
being_shocked = TRUE
var/power_bounced = power * 0.5
tesla_zap(src, 3, power_bounced)
addtimer(src, "reset_shocked", 10)
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
/obj/proc/reset_shocked()
being_shocked = FALSE
+1 -1
View File
@@ -105,7 +105,7 @@
to_chat(user, "<span class='warning'>Nothing interesting happens!</span>")
return
to_chat(user, "<span class='notice'>You emag the barsign. Takeover in progress...</span>")
addtimer(src, "post_emag", 100)
addtimer(CALLBACK(src, .proc/post_emag), 100)
/obj/structure/sign/barsign/proc/post_emag()
if(broken || emagged)
+32 -50
View File
@@ -146,6 +146,7 @@
return ..()
/obj/structure/grille/proc/build_window(obj/item/stack/sheet/S, mob/user)
var/dir_to_set = NORTH
if(!istype(S) || !user)
return
if(broken)
@@ -160,59 +161,40 @@
if(!getRelativeDirection(src, user) && (user.loc != loc)) //essentially a cardinal direction adjacent or sharing same loc check
to_chat(user, "<span class='warning'>You can't reach.</span>")
return
if(/obj/structure/window/full in loc) //check for a full window already present (blocks the whole tile)
to_chat(user, "<span class='warning'>There is already a full window there.</span>")
return
var/selection = alert(user, "What type of window would you like to place?", "Window Construction", "One Direction", "Full", "Cancel")
if(selection == "Cancel")
return
if(selection == "Full")
if(S.get_amount() < 2)
to_chat(user, "<span class='warning'>You need at least two sheets of glass for that!</span>")
if(loc == user.loc)
dir_to_set = user.dir
else
if(x == user.x)
if(y > user.y)
dir_to_set = SOUTH
else
dir_to_set = NORTH
else if(y == user.y)
if(x > user.x)
dir_to_set = WEST
else
dir_to_set = EAST
for(var/obj/structure/window/WINDOW in loc)
if(WINDOW.dir == dir_to_set)
to_chat(user, "<span class='notice'>There is already a window facing this way there.</span>")
return
if(do_after(user, 20, target = src)) //glass doesn't have a toolspeed, so no multiplier
if(broken || !anchored || !src) //make sure the grille is still intact, anchored, and exists!
return
if(S.get_amount() < 2) //make sure we still have enough for this!
return
if(!getRelativeDirection(src, user) && (user.loc != loc)) //make sure we can still do this from our location
return
var/obj/structure/window/W = new S.full_window(get_turf(src))
S.use(2)
W.anchored = 0
W.state = 0
to_chat(user, "<span class='notice'>You place [W] on [src].</span>")
W.update_icon()
return
if(selection == "One Direction")
var/dir_selection = input("Which direction will this window face?", "Direction") as null|anything in list("north", "east", "south", "west")
if(!dir_selection)
to_chat(user, "<span class='notice'>You start placing the window...</span>")
if(do_after(user, 20, target = src))
if(!loc || !anchored) //Grille destroyed or unanchored while waiting
return
var/temp_dir = text2dir(dir_selection)
for(var/obj/structure/window/W in loc)
if(istype(W, /obj/structure/window/full)) //double checking in case a full window was created while selecting direction
to_chat(user, "<span class='warning'>There is already a full window there.</span>")
for(var/obj/structure/window/WINDOW in loc)
if(WINDOW.dir == dir_to_set)//checking this for a 2nd time to check if a window was made while we were waiting.
to_chat(user, "<span class='notice'>There is already a window facing this way there.</span>")
return
if(W.dir == temp_dir) //to avoid building a window on top of an existing window
to_chat(user, "<span class='warning'>There is already a window facing this direction there.</span>")
return
if(do_after(user, 20, target = src))
if(broken || !anchored || !src) //make sure the grille is still intact, anchored, and exists!
return
if(S.get_amount() < 1) //make sure we still have enough fir this!
to_chat(user, "<span class='warning'>You need at least one sheet of glass for that!</span>")
return
if(!getRelativeDirection(src, user) && (user.loc != loc)) //make sure we can still do this from our location
return
var/obj/structure/window/W = new S.created_window(get_turf(src))
S.use(1)
W.setDir(temp_dir)
W.ini_dir = temp_dir
W.anchored = 0
W.state = 0
to_chat(user, "<span class='notice'>You place [W] on [src].</span>")
W.update_icon()
return
var/obj/structure/window/W = new S.created_window(get_turf(src))
S.use(1)
W.setDir(dir_to_set)
W.ini_dir = dir_to_set
W.anchored = 0
W.state = 0
to_chat(user, "<span class='notice'>You place the [W] on [src].</span>")
W.update_icon()
return
/obj/structure/grille/attacked_by(obj/item/I, mob/living/user)
user.changeNext_move(CLICK_CD_MELEE)
+235
View File
@@ -0,0 +1,235 @@
#define GUILLOTINE_BLADE_MAX_SHARP 10 // This is maxiumum sharpness that will decapitate without failure
#define GUILLOTINE_DECAP_MIN_SHARP 7 // Minimum amount of sharpness for decapitation. Any less and it will just deal brute damage
#define GUILLOTINE_ANIMATION_LENGTH 9 // How many deciseconds the animation is
#define GUILLOTINE_BLADE_RAISED 1
#define GUILLOTINE_BLADE_MOVING 2
#define GUILLOTINE_BLADE_DROPPED 3
#define GUILLOTINE_BLADE_SHARPENING 4
#define GUILLOTINE_HEAD_OFFSET 16 // How much we need to move the player to center their head
#define GUILLOTINE_LAYER_DIFF 1.2 // How much to increase/decrease a head when it's buckled/unbuckled
#define GUILLOTINE_ACTIVATE_DELAY 30 // Delay for executing someone
#define GUILLOTINE_WRENCH_DELAY 10
#define GUILLOTINE_ACTION_INUSE 5
#define GUILLOTINE_ACTION_WRENCH 6
/obj/structure/guillotine
name = "guillotine"
desc = "A large structure used to remove the heads of traitors and treasonists."
icon = 'icons/obj/guillotine.dmi'
icon_state = "guillotine_raised"
can_buckle = TRUE
anchored = TRUE
density = FALSE
buckle_lying = FALSE
layer = ABOVE_MOB_LAYER
var/blade_status = GUILLOTINE_BLADE_RAISED
var/blade_sharpness = GUILLOTINE_BLADE_MAX_SHARP // How sharp the blade is
var/kill_count = 0
var/force_clap = FALSE //You WILL clap if I want you to
var/current_action = 0 // What's currently happening to the guillotine
/obj/structure/guillotine/examine(mob/user)
..()
var/msg = ""
msg += "It is [anchored ? "wrenched to the floor." : "unsecured. A wrench should fix that."]<br/>"
if(blade_status == GUILLOTINE_BLADE_RAISED)
msg += "The blade is raised, ready to fall, and"
if(blade_sharpness >= GUILLOTINE_DECAP_MIN_SHARP)
msg += " looks sharp enough to decapitate without any resistance."
else
msg += " doesn't look particularly sharp. Perhaps a whetstone can be used to sharpen it."
else
msg += "The blade is hidden inside the stocks."
if(has_buckled_mobs())
msg += "<br/>"
msg += "Someone appears to be strapped in. You can help them out, or you can harm them by activating the guillotine."
to_chat(user, msg)
return msg
/obj/structure/guillotine/attack_hand(mob/user)
add_fingerprint(user)
// Currently being used by something
if(current_action)
return
switch(blade_status)
if(GUILLOTINE_BLADE_MOVING)
return
if(GUILLOTINE_BLADE_DROPPED)
blade_status = GUILLOTINE_BLADE_MOVING
icon_state = "guillotine_raise"
addtimer(CALLBACK(src, .proc/raise_blade), GUILLOTINE_ANIMATION_LENGTH)
return
if(GUILLOTINE_BLADE_RAISED)
if(has_buckled_mobs())
if(user.a_intent == INTENT_HARM)
user.visible_message("<span class='warning'>[user] begins to pull the lever!</span>",
"<span class='warning'>You begin to the pull the lever.</span>")
current_action = GUILLOTINE_ACTION_INUSE
if(do_after(user, GUILLOTINE_ACTIVATE_DELAY, target = src) && blade_status == GUILLOTINE_BLADE_RAISED)
current_action = 0
blade_status = GUILLOTINE_BLADE_MOVING
icon_state = "guillotine_drop"
playsound(src, 'sound/items/unsheath.ogg', 100, 1)
addtimer(CALLBACK(src, .proc/drop_blade, user), GUILLOTINE_ANIMATION_LENGTH - 2) // Minus two so we play the sound and decap faster
else
current_action = 0
else
unbuckle_mob()
else
blade_status = GUILLOTINE_BLADE_MOVING
icon_state = "guillotine_drop"
playsound(src, 'sound/items/unsheath.ogg', 100, 1)
addtimer(CALLBACK(src, .proc/drop_blade), GUILLOTINE_ANIMATION_LENGTH)
/obj/structure/guillotine/proc/raise_blade()
blade_status = GUILLOTINE_BLADE_RAISED
icon_state = "guillotine_raised"
/obj/structure/guillotine/proc/drop_blade(mob/user)
if(has_buckled_mobs() && blade_sharpness)
var/mob/living/carbon/human/H = buckled_mob
if(!H)
blade_status = GUILLOTINE_BLADE_DROPPED
icon_state = "guillotine"
return
var/obj/item/organ/external/head/head = H.get_organ("head")
if(QDELETED(head))
blade_status = GUILLOTINE_BLADE_DROPPED
icon_state = "guillotine"
return
playsound(src, 'sound/weapons/bladeslice.ogg', 100, 1)
if(blade_sharpness >= GUILLOTINE_DECAP_MIN_SHARP || head.brute_dam >= 100)
head.droplimb()
add_attack_logs(user, H, "beheaded with [src]")
H.regenerate_icons()
unbuckle_mob()
kill_count += 1
var/blood_overlay = "bloody"
if(kill_count == 2)
blood_overlay = "bloodier"
else if(kill_count > 2)
blood_overlay = "bloodiest"
blood_overlay = "guillotine_" + blood_overlay + "_overlay"
overlays.Cut()
overlays += mutable_appearance(icon, blood_overlay)
if(force_clap)
// The crowd is pleased
// The delay is to make large crowds have a longer lasting applause
var/delay_offset = 0
for(var/mob/living/carbon/human/HM in viewers(src, 7))
addtimer(CALLBACK(HM, /mob/.proc/emote, "clap"), delay_offset * 0.3)
delay_offset++
else
H.apply_damage(15 * blade_sharpness, BRUTE, head)
add_attack_logs(user, H, "non-fatally dropped the blade on with [src]")
H.emote("scream")
if(blade_sharpness > 1)
blade_sharpness -= 1
blade_status = GUILLOTINE_BLADE_DROPPED
icon_state = "guillotine"
/obj/structure/guillotine/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/whetstone))
add_fingerprint(user)
if(blade_status == GUILLOTINE_BLADE_SHARPENING)
return
if(blade_status == GUILLOTINE_BLADE_RAISED)
if(blade_sharpness < GUILLOTINE_BLADE_MAX_SHARP)
blade_status = GUILLOTINE_BLADE_SHARPENING
if(do_after(user, 7, target = src))
blade_status = GUILLOTINE_BLADE_RAISED
user.visible_message("<span class='notice'>[user] sharpens the large blade of the guillotine.</span>",
"<span class='notice'>You sharpen the large blade of the guillotine.</span>")
blade_sharpness += 1
playsound(src, 'sound/items/Screwdriver.ogg', 100, 1)
return
else
blade_status = GUILLOTINE_BLADE_RAISED
return
else
to_chat(user, "<span class='warning'>The blade is sharp enough!</span>")
return
else
to_chat(user, "<span class='warning'>You need to raise the blade in order to sharpen it!</span>")
return
if(iswrench(W))
if(current_action)
return
current_action = GUILLOTINE_ACTION_WRENCH
if(do_after(user, GUILLOTINE_WRENCH_DELAY, target = src))
current_action = 0
if(has_buckled_mobs())
to_chat(user, "<span class='warning'>Can't unfasten, someone's strapped in!</span>")
return
if(current_action)
return
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [src].</span>")
anchored = !anchored
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
dir = SOUTH
return TRUE
else
current_action = 0
else
return ..()
/obj/structure/guillotine/buckle_mob(mob/living/M, force = 0)
if(!anchored)
to_chat(usr, "<span class='warning'>The [src] needs to be wrenched to the floor!</span>")
return FALSE
if(!ishuman(M))
to_chat(usr, "<span class='warning'>It doesn't look like they can fit into this properly!</span>")
return FALSE // Can't decapitate non-humans
if(blade_status != GUILLOTINE_BLADE_RAISED)
to_chat(usr, "<span class='warning'>You need to raise the blade before buckling someone in!</span>")
return FALSE
if(..())
M.pixel_y -= GUILLOTINE_HEAD_OFFSET // Offset their body so it looks like they're in the guillotine
M.layer += GUILLOTINE_LAYER_DIFF
/obj/structure/guillotine/unbuckle_mob(force = 0)
if(buckled_mob)
buckled_mob.pixel_y += GUILLOTINE_HEAD_OFFSET // Move their body back
buckled_mob.layer -= GUILLOTINE_LAYER_DIFF
. = ..()
#undef GUILLOTINE_BLADE_MAX_SHARP
#undef GUILLOTINE_DECAP_MIN_SHARP
#undef GUILLOTINE_ANIMATION_LENGTH
#undef GUILLOTINE_BLADE_RAISED
#undef GUILLOTINE_BLADE_MOVING
#undef GUILLOTINE_BLADE_DROPPED
#undef GUILLOTINE_BLADE_SHARPENING
#undef GUILLOTINE_HEAD_OFFSET
#undef GUILLOTINE_LAYER_DIFF
#undef GUILLOTINE_ACTIVATE_DELAY
#undef GUILLOTINE_WRENCH_DELAY
#undef GUILLOTINE_ACTION_INUSE
#undef GUILLOTINE_ACTION_WRENCH
+1 -1
View File
@@ -376,7 +376,7 @@
return
// Don't break if they're just flying past
if(AM.throwing)
addtimer(src, "throw_check", 5, FALSE, AM)
addtimer(CALLBACK(src, .proc/throw_check, AM), 5)
else
check_break(AM)
+9 -4
View File
@@ -249,9 +249,11 @@
var/ismist = 0 //needs a var so we can make it linger~
var/watertemp = "normal" //freezing, normal, or boiling
var/mobpresent = 0 //true if there is a mob on the shower's loc, this is to ease process()
var/datum/looping_sound/showering/soundloop
/obj/machinery/shower/New(turf/T, newdir = SOUTH, building = FALSE)
..()
soundloop = new(list(src), FALSE)
if(building)
dir = newdir
pixel_x = 0
@@ -264,8 +266,8 @@
layer = FLY_LAYER
/obj/machinery/shower/Destroy()
if(mymist)
QDEL_NULL(mymist)
QDEL_NULL(mymist)
QDEL_NULL(soundloop)
return ..()
//add heat controls? when emagged, you can freeze to death in it?
@@ -282,6 +284,7 @@
on = !on
update_icon()
if(on)
soundloop.start()
if(M.loc == loc)
wash(M)
check_heat(M)
@@ -289,6 +292,8 @@
for(var/atom/movable/G in src.loc)
G.clean_blood()
G.water_act(100, convertHeat(), src)
else
soundloop.stop()
/obj/machinery/shower/attackby(obj/item/I as obj, mob/user as mob, params)
if(I.type == /obj/item/analyzer)
@@ -338,9 +343,9 @@
mist_time = 70 //7 seconds on freezing temperature to disperse existing mist
if(watertemp == "boiling")
mist_time = 20 //2 seconds on boiling temperature to build up mist
addtimer(src, "update_mist", mist_time)
addtimer(CALLBACK(src, .proc/update_mist), mist_time)
else
addtimer(src, "update_mist", 250) //25 seconds for mist to disperse after being turned off
addtimer(CALLBACK(src, .proc/update_mist), 250) //25 seconds for mist to disperse after being turned off
/obj/machinery/shower/proc/update_mist()
if(on)
+20 -9
View File
@@ -1,4 +1,4 @@
/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE)
/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE)
if(isarea(source))
error("[source] is an area and is trying to make the sound: [soundin]")
return
@@ -11,7 +11,10 @@
// Looping through the player list has the added bonus of working for mobs inside containers
var/sound/S = sound(get_sfx(soundin))
var/maxdistance = (world.view + extrarange) * 3
for(var/P in player_list)
var/list/listeners = player_list
if(!ignore_walls) //these sounds don't carry through walls
listeners = listeners & hearers(maxdistance, turf_source)
for(var/P in listeners)
var/mob/M = P
if(!M || !M.client)
continue
@@ -78,13 +81,15 @@
S.y = 1
S.falloff = (falloff ? falloff : FALLOFF_SOUNDS)
src << S
SEND_SOUND(src, S)
/client/proc/playtitlemusic()
if(!ticker || !ticker.login_music || config.disable_lobby_music)
return
if(prefs.sound & SOUND_LOBBY)
src << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = CHANNEL_LOBBYMUSIC) // MAD JAMS
/proc/sound_to_playing_players(soundin, volume = 100, vary = FALSE, frequency = 0, falloff = FALSE, channel = 0, pressure_affected = FALSE, sound/S)
if(!S)
S = sound(get_sfx(soundin))
for(var/m in player_list)
if(ismob(m) && !isnewplayer(m))
var/mob/M = m
M.playsound_local(M, null, volume, vary, frequency, falloff, channel, pressure_affected, S)
/proc/open_sound_channel()
var/static/next_channel = 1 //loop through the available 1024 - (the ones we reserve) channels and pray that its not still being used
@@ -93,7 +98,13 @@
next_channel = 1
/mob/proc/stop_sound_channel(chan)
src << sound(null, repeat = 0, wait = 0, channel = chan)
SEND_SOUND(src, sound(null, repeat = 0, wait = 0, channel = chan))
/client/proc/playtitlemusic()
if(!ticker || !ticker.login_music || config.disable_lobby_music)
return
if(prefs.sound & SOUND_LOBBY)
SEND_SOUND(src, sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = CHANNEL_LOBBYMUSIC)) // MAD JAMS
/proc/get_rand_frequency()
return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs.