mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-11 10:22:13 +00:00
Ports timestop and sepia extracts improvements/tweaks.
This commit is contained in:
@@ -117,6 +117,7 @@
|
||||
#define COMSIG_TURF_MULTIZ_NEW "turf_multiz_new" //from base of turf/New(): (turf/source, direction)
|
||||
|
||||
// /atom/movable signals
|
||||
#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move" //from base of atom/movable/Moved(): (/atom)
|
||||
#define COMSIG_MOVABLE_MOVED "movable_moved" //from base of atom/movable/Moved(): (/atom, dir)
|
||||
#define COMSIG_MOVABLE_CROSS "movable_cross" //from base of atom/movable/Cross(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (/atom/movable)
|
||||
|
||||
@@ -219,3 +219,4 @@
|
||||
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
|
||||
#define ABDUCTOR_ANTAGONIST "abductor-antagonist"
|
||||
#define MADE_UNCLONEABLE "made-uncloneable"
|
||||
#define TIMESTOP_TRAIT "timestop"
|
||||
|
||||
107
code/datums/components/dejavu.dm
Normal file
107
code/datums/components/dejavu.dm
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* A component to reset the parent to its previous state after some time passes
|
||||
*/
|
||||
/datum/component/dejavu
|
||||
/// The turf the parent was on when this components was applied, they get moved back here after the duration
|
||||
var/turf/starting_turf
|
||||
/// Determined by the type of the parent so different behaviours can happen per type
|
||||
var/rewind_type
|
||||
/// How many rewinds will happen before the effect ends
|
||||
var/rewinds_remaining
|
||||
/// How long to wait between each rewind
|
||||
var/rewind_interval
|
||||
|
||||
/// The starting value of clone loss at the beginning of the effect
|
||||
var/clone_loss = 0
|
||||
/// The starting value of toxin loss at the beginning of the effect
|
||||
var/tox_loss = 0
|
||||
/// The starting value of oxygen loss at the beginning of the effect
|
||||
var/oxy_loss = 0
|
||||
/// The starting value of brain loss at the beginning of the effect
|
||||
var/brain_loss = 0
|
||||
/// The starting value of brute loss at the beginning of the effect
|
||||
/// This only applies to simple animals
|
||||
var/brute_loss
|
||||
/// The starting value of integrity at the beginning of the effect
|
||||
/// This only applies to objects
|
||||
var/integrity
|
||||
/// A list of body parts saved at the beginning of the effect
|
||||
var/list/datum/saved_bodypart/saved_bodyparts
|
||||
|
||||
/datum/component/dejavu/Initialize(rewinds = 1, interval = 10 SECONDS)
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
starting_turf = get_turf(parent)
|
||||
rewinds_remaining = rewinds
|
||||
rewind_interval = interval
|
||||
|
||||
if(isliving(parent))
|
||||
var/mob/living/L = parent
|
||||
clone_loss = L.getCloneLoss()
|
||||
tox_loss = L.getToxLoss()
|
||||
oxy_loss = L.getOxyLoss()
|
||||
brain_loss = L.getOrganLoss(ORGAN_SLOT_BRAIN)
|
||||
rewind_type = .proc/rewind_living
|
||||
|
||||
if(iscarbon(parent))
|
||||
var/mob/living/carbon/C = parent
|
||||
saved_bodyparts = C.save_bodyparts()
|
||||
rewind_type = .proc/rewind_carbon
|
||||
|
||||
else if(isanimal(parent))
|
||||
var/mob/living/simple_animal/M = parent
|
||||
brute_loss = M.bruteloss
|
||||
rewind_type = .proc/rewind_animal
|
||||
|
||||
else if(isobj(parent))
|
||||
var/obj/O = parent
|
||||
integrity = O.obj_integrity
|
||||
rewind_type = .proc/rewind_obj
|
||||
|
||||
addtimer(CALLBACK(src, rewind_type), rewind_interval)
|
||||
|
||||
/datum/component/dejavu/Destroy()
|
||||
starting_turf = null
|
||||
saved_bodyparts = null
|
||||
return ..()
|
||||
|
||||
/datum/component/dejavu/proc/rewind()
|
||||
to_chat(parent, "<span class=notice>You remember a time not so long ago...</span>")
|
||||
|
||||
//comes after healing so new limbs comically drop to the floor
|
||||
if(starting_turf)
|
||||
var/atom/movable/master = parent
|
||||
master.forceMove(starting_turf)
|
||||
|
||||
rewinds_remaining --
|
||||
if(rewinds_remaining)
|
||||
addtimer(CALLBACK(src, rewind_type), rewind_interval)
|
||||
else
|
||||
to_chat(parent, "<span class=notice>But the memory falls out of your reach.</span>")
|
||||
qdel(src)
|
||||
|
||||
/datum/component/dejavu/proc/rewind_living()
|
||||
var/mob/living/master = parent
|
||||
master.setCloneLoss(clone_loss)
|
||||
master.setToxLoss(tox_loss)
|
||||
master.setOxyLoss(oxy_loss)
|
||||
master.setOrganLoss(ORGAN_SLOT_BRAIN, brain_loss)
|
||||
rewind()
|
||||
|
||||
/datum/component/dejavu/proc/rewind_carbon()
|
||||
if(saved_bodyparts)
|
||||
var/mob/living/carbon/master = parent
|
||||
master.apply_saved_bodyparts(saved_bodyparts)
|
||||
rewind_living()
|
||||
|
||||
/datum/component/dejavu/proc/rewind_animal()
|
||||
var/mob/living/simple_animal/master = parent
|
||||
master.bruteloss = brute_loss
|
||||
master.updatehealth()
|
||||
rewind_living()
|
||||
|
||||
/datum/component/dejavu/proc/rewind_obj()
|
||||
var/obj/master = parent
|
||||
master.obj_integrity = integrity
|
||||
rewind()
|
||||
@@ -159,7 +159,7 @@
|
||||
/atom/movable/proc/Move_Pulled(atom/A)
|
||||
if(!pulling)
|
||||
return
|
||||
if(pulling.anchored || !pulling.Adjacent(src))
|
||||
if(pulling.anchored || pulling.move_resist > move_force || !pulling.Adjacent(src))
|
||||
stop_pulling()
|
||||
return
|
||||
if(isliving(pulling))
|
||||
@@ -186,7 +186,7 @@
|
||||
log_game("DEBUG:[src]'s pull on [pullee] wasn't broken despite [pullee] being in [pullee.loc]. Pull stopped manually.")
|
||||
stop_pulling()
|
||||
return
|
||||
if(pulling.anchored)
|
||||
if(pulling.anchored || pulling.move_resist > move_force)
|
||||
stop_pulling()
|
||||
return
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
var/lights = FALSE
|
||||
var/lights_power = 6
|
||||
var/last_user_hud = 1 // used to show/hide the mecha hud while preserving previous preference
|
||||
var/completely_disabled = FALSE //stops the mech from doing anything
|
||||
var/breach_time = 0
|
||||
var/recharge_rate = 0
|
||||
|
||||
@@ -431,6 +432,8 @@
|
||||
return
|
||||
if(!locate(/turf) in list(target,target.loc)) // Prevents inventory from being drilled
|
||||
return
|
||||
if(completely_disabled)
|
||||
return
|
||||
if(phasing)
|
||||
occupant_message("Unable to interact with objects while phasing")
|
||||
return
|
||||
@@ -508,6 +511,8 @@
|
||||
return 1
|
||||
|
||||
/obj/mecha/relaymove(mob/user,direction)
|
||||
if(completely_disabled)
|
||||
return
|
||||
if(!direction)
|
||||
return
|
||||
if(user != occupant) //While not "realistic", this piece is player friendly.
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
|
||||
/datum/spellbook_entry/timestop
|
||||
name = "Time Stop"
|
||||
spell_type = /obj/effect/proc_holder/spell/aoe_turf/conjure/timestop
|
||||
spell_type = /obj/effect/proc_holder/spell/aoe_turf/timestop
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/smoke
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
pixel_x = -64
|
||||
pixel_y = -64
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
var/list/immune = list() // the one who creates the timestop is immune
|
||||
var/list/immune = list() // the one who creates the timestop is immune, which includes wizards and the dead slime you murdered to make this chronofield
|
||||
var/turf/target
|
||||
var/freezerange = 2
|
||||
var/duration = 140
|
||||
@@ -27,10 +27,10 @@
|
||||
for(var/A in immune_atoms)
|
||||
immune[A] = TRUE
|
||||
for(var/mob/living/L in GLOB.player_list)
|
||||
if(locate(/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop) in L.mind.spell_list) //People who can stop time are immune to its effects
|
||||
if(locate(/obj/effect/proc_holder/spell/aoe_turf/timestop) in L.mind.spell_list) //People who can stop time are immune to its effects
|
||||
immune[L] = TRUE
|
||||
for(var/mob/living/simple_animal/hostile/guardian/G in GLOB.parasites)
|
||||
if(G.summoner && locate(/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop) in G.summoner.mind.spell_list) //It would only make sense that a person's stand would also be immune.
|
||||
if(G.summoner && locate(/obj/effect/proc_holder/spell/aoe_turf/timestop) in G.summoner.mind.spell_list) //It would only make sense that a person's stand would also be immune.
|
||||
immune[G] = TRUE
|
||||
if(start)
|
||||
timestop()
|
||||
@@ -46,9 +46,8 @@
|
||||
chronofield = make_field(/datum/proximity_monitor/advanced/timestop, list("current_range" = freezerange, "host" = src, "immune" = immune, "check_anti_magic" = check_anti_magic, "check_holy" = check_holy))
|
||||
QDEL_IN(src, duration)
|
||||
|
||||
/obj/effect/timestop/wizard
|
||||
/obj/effect/timestop/magic
|
||||
check_anti_magic = TRUE
|
||||
duration = 100
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop
|
||||
name = "chronofield"
|
||||
@@ -56,9 +55,10 @@
|
||||
field_shape = FIELD_SHAPE_RADIUS_SQUARE
|
||||
requires_processing = TRUE
|
||||
var/list/immune = list()
|
||||
var/list/mob/living/frozen_mobs = list()
|
||||
var/list/obj/item/projectile/frozen_projectiles = list()
|
||||
var/list/atom/movable/frozen_throws = list()
|
||||
var/list/frozen_things = list()
|
||||
var/list/frozen_mobs = list() //cached separately for processing
|
||||
var/list/frozen_structures = list() //Also machinery, and only frozen aestethically
|
||||
var/list/frozen_turfs = list() //Only aesthetically
|
||||
var/check_anti_magic = FALSE
|
||||
var/check_holy = FALSE
|
||||
|
||||
@@ -74,85 +74,125 @@
|
||||
/datum/proximity_monitor/advanced/timestop/proc/freeze_atom(atom/movable/A)
|
||||
if(immune[A] || global_frozen_atoms[A] || !istype(A))
|
||||
return FALSE
|
||||
if(A.throwing)
|
||||
freeze_throwing(A)
|
||||
if(ismob(A))
|
||||
var/mob/M = A
|
||||
if(M.anti_magic_check(check_anti_magic, check_holy))
|
||||
immune[A] = TRUE
|
||||
return
|
||||
var/frozen = TRUE
|
||||
if(isliving(A))
|
||||
freeze_mob(A)
|
||||
else if(istype(A, /obj/item/projectile))
|
||||
freeze_projectile(A)
|
||||
else if(istype(A, /obj/mecha))
|
||||
freeze_mecha(A)
|
||||
else if((ismachinery(A) && !istype(A, /obj/machinery/light)) || isstructure(A)) //Special exception for light fixtures since recoloring causes them to change light
|
||||
freeze_structure(A)
|
||||
else
|
||||
return FALSE
|
||||
frozen = FALSE
|
||||
if(A.throwing)
|
||||
freeze_throwing(A)
|
||||
frozen = TRUE
|
||||
if(!frozen)
|
||||
return
|
||||
|
||||
frozen_things[A] = A.move_resist
|
||||
A.move_resist = INFINITY
|
||||
global_frozen_atoms[A] = src
|
||||
into_the_negative_zone(A)
|
||||
RegisterSignal(A, COMSIG_MOVABLE_PRE_MOVE, .proc/unfreeze_atom)
|
||||
RegisterSignal(A, COMSIG_ITEM_PICKUP, .proc/unfreeze_atom)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_all()
|
||||
for(var/i in frozen_projectiles)
|
||||
unfreeze_projectile(i)
|
||||
for(var/i in frozen_mobs)
|
||||
unfreeze_mob(i)
|
||||
for(var/i in frozen_throws)
|
||||
unfreeze_throw(i)
|
||||
for(var/i in frozen_things)
|
||||
unfreeze_atom(i)
|
||||
for(var/T in frozen_turfs)
|
||||
unfreeze_turf(T)
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_atom(atom/movable/A)
|
||||
if(A.throwing)
|
||||
unfreeze_throwing(A)
|
||||
if(isliving(A))
|
||||
unfreeze_mob(A)
|
||||
else if(istype(A, /obj/item/projectile))
|
||||
unfreeze_projectile(A)
|
||||
else if(istype(A, /obj/mecha))
|
||||
unfreeze_mecha(A)
|
||||
|
||||
UnregisterSignal(A, COMSIG_MOVABLE_PRE_MOVE)
|
||||
UnregisterSignal(A, COMSIG_ITEM_PICKUP)
|
||||
escape_the_negative_zone(A)
|
||||
A.move_resist = frozen_things[A]
|
||||
frozen_things -= A
|
||||
global_frozen_atoms -= A
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/freeze_mecha(obj/mecha/M)
|
||||
M.completely_disabled = TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mecha(obj/mecha/M)
|
||||
M.completely_disabled = FALSE
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/freeze_throwing(atom/movable/AM)
|
||||
var/datum/thrownthing/T = AM.throwing
|
||||
T.paused = TRUE
|
||||
frozen_throws[AM] = T
|
||||
global_frozen_atoms[AM] = TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_throw(atom/movable/AM)
|
||||
var/datum/thrownthing/T = frozen_throws[AM]
|
||||
T.paused = FALSE
|
||||
frozen_throws -= AM
|
||||
global_frozen_atoms -= AM
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_throwing(atom/movable/AM)
|
||||
var/datum/thrownthing/T = AM.throwing
|
||||
if(T)
|
||||
T.paused = FALSE
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/freeze_turf(turf/T)
|
||||
into_the_negative_zone(T)
|
||||
frozen_turfs += T
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_turf(turf/T)
|
||||
escape_the_negative_zone(T)
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/freeze_structure(obj/O)
|
||||
into_the_negative_zone(O)
|
||||
frozen_structures += O
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_structure(obj/O)
|
||||
escape_the_negative_zone(O)
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/process()
|
||||
for(var/i in frozen_mobs)
|
||||
var/mob/living/m = i
|
||||
if(get_dist(get_turf(m), get_turf(host)) > current_range)
|
||||
unfreeze_mob(m)
|
||||
else
|
||||
m.Stun(20, 1, 1)
|
||||
m.Stun(20, 1, 1)
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/setup_field_turf(turf/T)
|
||||
for(var/i in T.contents)
|
||||
freeze_atom(i)
|
||||
freeze_turf(T)
|
||||
return ..()
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_projectile(obj/item/projectile/P)
|
||||
escape_the_negative_zone(P)
|
||||
frozen_projectiles -= P
|
||||
P.paused = FALSE
|
||||
global_frozen_atoms -= P
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/freeze_projectile(obj/item/projectile/P)
|
||||
frozen_projectiles[P] = TRUE
|
||||
P.paused = TRUE
|
||||
global_frozen_atoms[P] = TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_projectile(obj/item/projectile/P)
|
||||
P.paused = FALSE
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/freeze_mob(mob/living/L)
|
||||
if(L.anti_magic_check(check_anti_magic, check_holy))
|
||||
immune += L
|
||||
return
|
||||
frozen_mobs += L
|
||||
L.Stun(20, 1, 1)
|
||||
frozen_mobs[L] = L.anchored
|
||||
L.anchored = TRUE
|
||||
global_frozen_atoms[L] = TRUE
|
||||
if(ishostile(L))
|
||||
var/mob/living/simple_animal/hostile/H = L
|
||||
H.toggle_ai(AI_OFF)
|
||||
H.LoseTarget()
|
||||
ADD_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT)
|
||||
walk(L, 0) //stops them mid pathing even if they're stunimmune
|
||||
if(isanimal(L))
|
||||
var/mob/living/simple_animal/S = L
|
||||
S.toggle_ai(AI_OFF)
|
||||
if(ishostile(L))
|
||||
var/mob/living/simple_animal/hostile/H = L
|
||||
H.LoseTarget()
|
||||
|
||||
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mob(mob/living/L)
|
||||
escape_the_negative_zone(L)
|
||||
L.AdjustStun(-20, 1, 1)
|
||||
L.anchored = frozen_mobs[L]
|
||||
REMOVE_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT)
|
||||
frozen_mobs -= L
|
||||
global_frozen_atoms -= L
|
||||
if(ishostile(L))
|
||||
var/mob/living/simple_animal/hostile/H = L
|
||||
H.toggle_ai(initial(H.AIStatus))
|
||||
if(isanimal(L))
|
||||
var/mob/living/simple_animal/S = L
|
||||
S.toggle_ai(initial(S.AIStatus))
|
||||
|
||||
//you don't look quite right, is something the matter?
|
||||
/datum/proximity_monitor/advanced/timestop/proc/into_the_negative_zone(atom/A)
|
||||
@@ -160,4 +200,4 @@
|
||||
|
||||
//let's put some colour back into your cheeks
|
||||
/datum/proximity_monitor/advanced/timestop/proc/escape_the_negative_zone(atom/A)
|
||||
A.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
A.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
|
||||
@@ -84,8 +84,10 @@
|
||||
if(now_pushing)
|
||||
return TRUE
|
||||
|
||||
var/they_can_move = TRUE
|
||||
if(isliving(M))
|
||||
var/mob/living/L = M
|
||||
they_can_move = L.canmove //L.mobility_flags & MOBILITY_MOVE
|
||||
//Also spread diseases
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
@@ -138,13 +140,17 @@
|
||||
return 1
|
||||
|
||||
if(!M.buckled && !M.has_buckled_mobs())
|
||||
var/mob_swap
|
||||
//the puller can always swap with its victim if on grab intent
|
||||
if(M.pulledby == src && a_intent == INTENT_GRAB)
|
||||
mob_swap = 1
|
||||
//restrained people act if they were on 'help' intent to prevent a person being pulled from being separated from their puller
|
||||
else if((M.restrained() || M.a_intent == INTENT_HELP) && (restrained() || a_intent == INTENT_HELP))
|
||||
mob_swap = 1
|
||||
var/mob_swap = FALSE
|
||||
var/too_strong = (M.move_resist > move_force) //can't swap with immovable objects unless they help us
|
||||
if(!they_can_move) //we have to physically move them
|
||||
if(!too_strong)
|
||||
mob_swap = TRUE
|
||||
else
|
||||
if(M.pulledby == src && a_intent == INTENT_GRAB)
|
||||
mob_swap = TRUE
|
||||
//restrained people act if they were on 'help' intent to prevent a person being pulled from being separated from their puller
|
||||
else if((M.restrained() || M.a_intent == INTENT_HELP) && (restrained() || a_intent == INTENT_HELP))
|
||||
mob_swap = TRUE
|
||||
if(mob_swap)
|
||||
//switch our position with M
|
||||
if(loc && !loc.Adjacent(M.loc))
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
var/datum/personal_crafting/handcrafting
|
||||
|
||||
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players)
|
||||
var/can_have_ai = TRUE //once we have become sentient, we can never go back
|
||||
|
||||
var/shouldwakeup = FALSE //convenience var for forcibly waking up an idling AI on next check.
|
||||
|
||||
@@ -424,6 +425,9 @@
|
||||
canmove = FALSE
|
||||
else
|
||||
canmove = value_otherwise
|
||||
if(!canmove) // !(mobility_flags & MOBILITY_MOVE)
|
||||
walk(src, 0) //stop mid walk
|
||||
|
||||
update_transform()
|
||||
update_action_buttons_icon()
|
||||
return canmove
|
||||
@@ -442,6 +446,7 @@
|
||||
|
||||
/mob/living/simple_animal/proc/sentience_act() //Called when a simple animal gains sentience via gold slime potion
|
||||
toggle_ai(AI_OFF) // To prevent any weirdness.
|
||||
can_have_ai = FALSE
|
||||
|
||||
/mob/living/simple_animal/update_sight()
|
||||
if(!client)
|
||||
@@ -556,6 +561,8 @@
|
||||
LoadComponent(/datum/component/riding)
|
||||
|
||||
/mob/living/simple_animal/proc/toggle_ai(togglestatus)
|
||||
if(!can_have_ai && (togglestatus != AI_OFF))
|
||||
return
|
||||
if (AIStatus != togglestatus)
|
||||
if (togglestatus > 0 && togglestatus < 5)
|
||||
if (togglestatus == AI_Z_OFF || AIStatus == AI_Z_OFF)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
AIproc = 1
|
||||
|
||||
while(AIproc && stat != DEAD && (attacked || hungry || rabid || buckled))
|
||||
if(buckled) // can't eat AND have this little process at the same time
|
||||
if(!canmove) // !(mobility_flags & MOBILITY_MOVE) //also covers buckling. Not sure why buckled is in the while condition if we're going to immediately break, honestly
|
||||
break
|
||||
|
||||
if(!Target || client)
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
var/picture_size_y_min = 1
|
||||
var/picture_size_x_max = 4
|
||||
var/picture_size_y_max = 4
|
||||
var/can_customise = TRUE
|
||||
var/default_picture_name
|
||||
|
||||
/obj/item/camera/attack_self(mob/user)
|
||||
if(!disk)
|
||||
@@ -198,8 +200,10 @@
|
||||
user.put_in_hands(p)
|
||||
pictures_left--
|
||||
to_chat(user, "<span class='notice'>[pictures_left] photos left.</span>")
|
||||
var/customize = alert(user, "Do you want to customize the photo?", "Customization", "Yes", "No")
|
||||
if(customize == "Yes")
|
||||
var/customise = "No"
|
||||
if(can_customise)
|
||||
customise = alert(user, "Do you want to customize the photo?", "Customization", "Yes", "No")
|
||||
if(customise == "Yes")
|
||||
var/name1 = stripped_input(user, "Set a name for this photo, or leave blank. 32 characters max.", "Name", max_length = 32)
|
||||
var/desc1 = stripped_input(user, "Set a description to add to photo, or leave blank. 128 characters max.", "Caption", max_length = 128)
|
||||
var/caption = stripped_input(user, "Set a caption for this photo, or leave blank. 256 characters max.", "Caption", max_length = 256)
|
||||
@@ -209,6 +213,10 @@
|
||||
picture.picture_desc = "[desc1] - [picture.picture_desc]"
|
||||
if(caption)
|
||||
picture.caption = caption
|
||||
else
|
||||
if(default_picture_name)
|
||||
picture.picture_name = default_picture_name
|
||||
|
||||
p.set_picture(picture, TRUE, TRUE)
|
||||
if(CONFIG_GET(flag/picture_logging_camera))
|
||||
picture.log_to_file()
|
||||
@@ -565,9 +565,16 @@
|
||||
required_other = TRUE
|
||||
|
||||
/datum/chemical_reaction/slime/slimestop/on_reaction(datum/reagents/holder)
|
||||
sleep(50)
|
||||
var/obj/item/slime_extract/sepia/extract = holder.my_atom
|
||||
var/turf/T = get_turf(holder.my_atom)
|
||||
var/list/M = list(get_mob_by_key(holder.my_atom.fingerprintslast))
|
||||
new /obj/effect/timestop(T, null, null, M)
|
||||
new /obj/effect/timestop(T, null, null, null)
|
||||
if(istype(extract))
|
||||
if(extract.Uses > 0)
|
||||
var/mob/lastheld = get_mob_by_key(holder.my_atom.fingerprintslast)
|
||||
if(lastheld && !lastheld.equip_to_slot_if_possible(extract, SLOT_HANDS, disable_warning = TRUE))
|
||||
extract.forceMove(get_turf(lastheld))
|
||||
|
||||
..()
|
||||
|
||||
/datum/chemical_reaction/slime/slimecamera
|
||||
|
||||
@@ -154,7 +154,7 @@ Burning extracts:
|
||||
|
||||
/obj/item/slimecross/burning/sepia/do_effect(mob/user)
|
||||
user.visible_message("<span class='notice'>[src] shapes itself into a camera!</span>")
|
||||
new /obj/item/camera/timefreeze(get_turf(user))
|
||||
new /obj/item/camera/rewind(get_turf(user))
|
||||
..()
|
||||
|
||||
/obj/item/slimecross/burning/cerulean
|
||||
@@ -289,25 +289,88 @@ Burning extracts:
|
||||
|
||||
//Misc. things added
|
||||
|
||||
//Rewind camera - I'm already Burning Sepia
|
||||
/obj/item/camera/rewind
|
||||
name = "sepia-tinted camera"
|
||||
desc = "They say a picture is like a moment stopped in time."
|
||||
pictures_left = 1
|
||||
pictures_max = 1
|
||||
can_customise = FALSE
|
||||
default_picture_name = "A nostalgic picture"
|
||||
var/used = FALSE
|
||||
|
||||
/datum/saved_bodypart
|
||||
var/obj/item/bodypart/old_part
|
||||
var/bodypart_type
|
||||
var/brute_dam
|
||||
var/burn_dam
|
||||
var/stamina_dam
|
||||
|
||||
/datum/saved_bodypart/New(obj/item/bodypart/part)
|
||||
old_part = part
|
||||
bodypart_type = part.type
|
||||
brute_dam = part.brute_dam
|
||||
burn_dam = part.burn_dam
|
||||
stamina_dam = part.stamina_dam
|
||||
|
||||
/mob/living/carbon/proc/apply_saved_bodyparts(list/datum/saved_bodypart/parts)
|
||||
var/list/dont_chop = list()
|
||||
for(var/zone in parts)
|
||||
var/datum/saved_bodypart/saved_part = parts[zone]
|
||||
var/obj/item/bodypart/already = get_bodypart(zone)
|
||||
if(QDELETED(saved_part.old_part))
|
||||
saved_part.old_part = new saved_part.bodypart_type
|
||||
if(!already || already != saved_part.old_part)
|
||||
saved_part.old_part.replace_limb(src, TRUE)
|
||||
saved_part.old_part.heal_damage(INFINITY, INFINITY, INFINITY, null, FALSE)
|
||||
saved_part.old_part.receive_damage(saved_part.brute_dam, saved_part.burn_dam, saved_part.stamina_dam)
|
||||
dont_chop[zone] = TRUE
|
||||
for(var/_part in bodyparts)
|
||||
var/obj/item/bodypart/part = _part
|
||||
if(dont_chop[part.body_zone])
|
||||
continue
|
||||
part.drop_limb(TRUE)
|
||||
|
||||
/mob/living/carbon/proc/save_bodyparts()
|
||||
var/list/datum/saved_bodypart/ret = list()
|
||||
for(var/_part in bodyparts)
|
||||
var/obj/item/bodypart/part = _part
|
||||
var/datum/saved_bodypart/saved_part = new(part)
|
||||
|
||||
ret[part.body_zone] = saved_part
|
||||
return ret
|
||||
|
||||
/obj/item/camera/rewind/afterattack(atom/target, mob/user, flag)
|
||||
if(!on || !pictures_left || !isturf(target.loc))
|
||||
return
|
||||
if(!used)//selfie time
|
||||
if(user == target)
|
||||
to_chat(user, "<span class=notice>You take a selfie!</span>")
|
||||
else
|
||||
to_chat(user, "<span class=notice>You take a photo with [target]!</span>")
|
||||
to_chat(target, "<span class=notice>[user] takes a photo with you!</span>")
|
||||
to_chat(target, "<span class=notice>You'll remember this moment forever!</span>")
|
||||
|
||||
used = TRUE
|
||||
target.AddComponent(/datum/component/dejavu, 2)
|
||||
.=..()
|
||||
|
||||
//Timefreeze camera - Old Burning Sepia result. Kept in case admins want to spawn it
|
||||
/obj/item/camera/timefreeze
|
||||
name = "sepia-tinted camera"
|
||||
desc = "They say a picture is like a moment stopped in time."
|
||||
pictures_left = 1
|
||||
pictures_max = 1
|
||||
var/used = FALSE
|
||||
|
||||
/obj/item/camera/timefreeze/afterattack(atom/target, mob/user, flag)
|
||||
if(!on || !pictures_left || !isturf(target.loc))
|
||||
return
|
||||
new /obj/effect/timestop(get_turf(target), 2, 50, list(user))
|
||||
. = ..()
|
||||
var/text = "The camera fades away"
|
||||
if(disk)
|
||||
text += ", leaving the disk behind!"
|
||||
user.put_in_hands(disk)
|
||||
else
|
||||
text += "!"
|
||||
to_chat(user,"<span class='notice'>[text]</span>")
|
||||
qdel(src)
|
||||
if(!used) //refilling the film does not refill the timestop
|
||||
new /obj/effect/timestop(get_turf(target), 2, 50, list(user))
|
||||
used = TRUE
|
||||
desc = "This camera has seen better days."
|
||||
return ..()
|
||||
|
||||
/obj/item/slimepotion/extract_cloner
|
||||
name = "extract cloning potion"
|
||||
|
||||
@@ -148,8 +148,9 @@ Regenerative extracts:
|
||||
/obj/item/slimecross/regenerative/sepia
|
||||
colour = "sepia"
|
||||
|
||||
/obj/item/slimecross/regenerative/sepia/core_effect(mob/living/target, mob/user)
|
||||
new /obj/effect/timestop(get_turf(target), 2, 50, list(user,target))
|
||||
/obj/item/slimecross/regenerative/sepia/core_effect_before(mob/living/target, mob/user)
|
||||
to_chat(target, "<span class=notice>You try to forget how you feel.</span>")
|
||||
target.AddComponent(/datum/component/dejavu)
|
||||
|
||||
/obj/item/slimecross/regenerative/cerulean
|
||||
colour = "cerulean"
|
||||
|
||||
@@ -152,19 +152,21 @@
|
||||
sound1 = 'sound/magic/teleport_diss.ogg'
|
||||
sound2 = 'sound/magic/teleport_app.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop
|
||||
/obj/effect/proc_holder/spell/aoe_turf/timestop
|
||||
name = "Stop Time"
|
||||
desc = "This spell stops time for everyone except for you, allowing you to move freely while your enemies and even projectiles are frozen."
|
||||
charge_max = 500
|
||||
clothes_req = 1
|
||||
invocation = "TOKI WO TOMARE"
|
||||
invocation = "TOKI YO TOMARE"
|
||||
invocation_type = "shout"
|
||||
range = 0
|
||||
cooldown_min = 100
|
||||
summon_amt = 1
|
||||
action_icon_state = "time"
|
||||
var/timestop_range = 2
|
||||
var/timestop_duration = 100
|
||||
|
||||
summon_type = list(/obj/effect/timestop/wizard)
|
||||
/obj/effect/proc_holder/spell/aoe_turf/timestop/cast(list/targets, mob/user = usr)
|
||||
new /obj/effect/timestop/magic(get_turf(user), timestop_range, timestop_duration, list(user))
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/carp
|
||||
name = "Summon Carp"
|
||||
|
||||
@@ -356,6 +356,7 @@
|
||||
#include "code\datums\components\chasm.dm"
|
||||
#include "code\datums\components\construction.dm"
|
||||
#include "code\datums\components\decal.dm"
|
||||
#include "code\datums\components\dejavu.dm"
|
||||
#include "code\datums\components\earprotection.dm"
|
||||
#include "code\datums\components\edit_complainer.dm"
|
||||
#include "code\datums\components\empprotection.dm"
|
||||
|
||||
Reference in New Issue
Block a user