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
@@ -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)