ASYNC EVERYTHING!

This commit is contained in:
Letter N
2020-12-21 16:24:51 +08:00
parent cf692e8426
commit a808f805d4
63 changed files with 1009 additions and 574 deletions

View File

@@ -22,49 +22,45 @@
#define START_PROCESSING(Processor, Datum) if (!(Datum.datum_flags & DF_ISPROCESSING)) {Datum.datum_flags |= DF_ISPROCESSING;Processor.processing += Datum}
#define STOP_PROCESSING(Processor, Datum) Datum.datum_flags &= ~DF_ISPROCESSING;Processor.processing -= Datum;Processor.currentrun -= Datum
//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
//! SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
//subsystem does not initialize.
#define SS_NO_INIT (1<<0)
/// subsystem does not initialize.
#define SS_NO_INIT 1
//subsystem does not fire.
// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
// (Requires a MC restart to change)
#define SS_NO_FIRE (1<<1)
/** subsystem does not fire. */
/// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
/// (Requires a MC restart to change)
#define SS_NO_FIRE 2
//subsystem only runs on spare cpu (after all non-background subsystems have ran that tick)
// SS_BACKGROUND has its own priority bracket
#define SS_BACKGROUND (1<<2)
/** Subsystem only runs on spare cpu (after all non-background subsystems have ran that tick) */
/// SS_BACKGROUND has its own priority bracket, this overrides SS_TICKER's priority bump
#define SS_BACKGROUND 4
//subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
#define SS_NO_TICK_CHECK (1<<3)
/// subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
#define SS_NO_TICK_CHECK 8
//Treat wait as a tick count, not DS, run every wait ticks.
// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems)
// (implies all runlevels because of how it works)
// (overrides SS_BACKGROUND)
// This is designed for basically anything that works as a mini-mc (like SStimer)
#define SS_TICKER (1<<4)
/** Treat wait as a tick count, not DS, run every wait ticks. */
/// (also forces it to run first in the tick (unless SS_BACKGROUND))
/// (implies all runlevels because of how it works)
/// This is designed for basically anything that works as a mini-mc (like SStimer)
#define SS_TICKER 16
//keep the subsystem's timing on point by firing early if it fired late last fire because of lag
// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
#define SS_KEEP_TIMING (1<<5)
/** keep the subsystem's timing on point by firing early if it fired late last fire because of lag */
/// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
#define SS_KEEP_TIMING 32
//Calculate its next fire after its fired.
// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
// This flag overrides SS_KEEP_TIMING
#define SS_POST_FIRE_TIMING (1<<6)
/** Calculate its next fire after its fired. */
/// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
/// This flag overrides SS_KEEP_TIMING
#define SS_POST_FIRE_TIMING 64
/// Show in stat() by default even if SS_NO_FIRE
#define SS_ALWAYS_SHOW_STAT (1<<7)
//SUBSYSTEM STATES
#define SS_IDLE 0 //aint doing shit.
#define SS_QUEUED 1 //queued to run
#define SS_RUNNING 2 //actively running
#define SS_PAUSED 3 //paused by mc_tick_check
#define SS_SLEEPING 4 //fire() slept.
#define SS_PAUSING 5 //in the middle of pausing
//! SUBSYSTEM STATES
#define SS_IDLE 0 /// ain't doing shit.
#define SS_QUEUED 1 /// queued to run
#define SS_RUNNING 2 /// actively running
#define SS_PAUSED 3 /// paused by mc_tick_check
#define SS_SLEEPING 4 /// fire() slept.
#define SS_PAUSING 5 /// in the middle of pausing
#define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\
/datum/controller/subsystem/##X/New(){\

View File

@@ -6,9 +6,16 @@
#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
/// Signifies that this proc is used to handle signals.
/// Every proc you pass to RegisterSignal must have this.
#define SIGNAL_HANDLER SHOULD_NOT_SLEEP(TRUE)
/// Signifies that this proc is used to handle signals, but also sleeps.
/// Do not use this for new work.
#define SIGNAL_HANDLER_DOES_SLEEP
/// A wrapper for _AddElement that allows us to pretend we're using normal named arguments
#define AddElement(arguments...) _AddElement(list(##arguments))
/// A wrapper for _RemoveElement that allows us to pretend we're using normal named arguments
#define RemoveElement(arguments...) _RemoveElement(list(##arguments))

View File

@@ -0,0 +1,16 @@
/// The minimum for glide_size to be clamped to.
#define MIN_GLIDE_SIZE 1
/// The maximum for glide_size to be clamped to.
/// This shouldn't be higher than the icon size, and generally you shouldn't be changing this, but it's here just in case.
#define MAX_GLIDE_SIZE 32
/// Compensating for time dialation
GLOBAL_VAR_INIT(glide_size_multiplier, 1.0)
///Broken down, here's what this does:
/// divides the world icon_size (32) by delay divided by ticklag to get the number of pixels something should be moving each tick.
/// The division result is given a min value of 1 to prevent obscenely slow glide sizes from being set
/// Then that's multiplied by the global glide size multiplier. 1.25 by default feels pretty close to spot on. This is just to try to get byond to behave.
/// The whole result is then clamped to within the range above.
/// Not very readable but it works
#define DELAY_TO_GLIDE_SIZE(delay) (clamp(((32 / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE))

View File

@@ -174,7 +174,6 @@
#define FIRE_PRIORITY_AIR_TURFS 40
#define FIRE_PRIORITY_DEFAULT 50
#define FIRE_PRIORITY_PARALLAX 65
#define FIRE_PRIORITY_INSTRUMENTS 80
#define FIRE_PRIORITY_MOBS 100
#define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_PROJECTILES 200

View File

@@ -1202,7 +1202,7 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
//Version of view() which ignores darkness, because BYOND doesn't have it (I actually suggested it but it was tagged redundant, BUT HEARERS IS A T- /rant).
/proc/dview(var/range = world.view, var/center, var/invis_flags = 0)
/proc/dview(range = world.view, center, invis_flags = 0)
if(!center)
return
@@ -1222,6 +1222,10 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
var/ready_to_die = FALSE
/mob/dview/Initialize() //Properly prevents this mob from gaining huds or joining any global lists
SHOULD_CALL_PARENT(FALSE)
if(flags_1 & INITIALIZED_1)
stack_trace("Warning: [src]([type]) initialized multiple times!")
flags_1 |= INITIALIZED_1
return INITIALIZE_HINT_NORMAL
/mob/dview/Destroy(force = FALSE)

View File

@@ -1,14 +1,15 @@
GLOBAL_LIST_EMPTY(lighting_update_lights) // List of lighting sources queued for update.
GLOBAL_LIST_EMPTY(lighting_update_corners) // List of lighting corners queued for update.
GLOBAL_LIST_EMPTY(lighting_update_objects) // List of lighting objects queued for update.
SUBSYSTEM_DEF(lighting)
name = "Lighting"
wait = 2
init_order = INIT_ORDER_LIGHTING
flags = SS_TICKER
var/static/list/sources_queue = list() // List of lighting sources queued for update.
var/static/list/corners_queue = list() // List of lighting corners queued for update.
var/static/list/objects_queue = list() // List of lighting objects queued for update.
/datum/controller/subsystem/lighting/stat_entry(msg)
msg = "L:[length(sources_queue)]|C:[length(corners_queue)]|O:[length(objects_queue)]"
msg = "L:[length(GLOB.lighting_update_lights)]|C:[length(GLOB.lighting_update_corners)]|O:[length(GLOB.lighting_update_objects)]"
return ..()
@@ -31,10 +32,9 @@ SUBSYSTEM_DEF(lighting)
MC_SPLIT_TICK_INIT(3)
if(!init_tick_checks)
MC_SPLIT_TICK
var/list/queue = sources_queue
var/i = 0
for (i in 1 to length(queue))
var/datum/light_source/L = queue[i]
for (i in 1 to GLOB.lighting_update_lights.len)
var/datum/light_source/L = GLOB.lighting_update_lights[i]
L.update_corners()
@@ -45,15 +45,14 @@ SUBSYSTEM_DEF(lighting)
else if (MC_TICK_CHECK)
break
if (i)
queue.Cut(1, i+1)
GLOB.lighting_update_lights.Cut(1, i+1)
i = 0
if(!init_tick_checks)
MC_SPLIT_TICK
queue = corners_queue
for (i in 1 to length(queue))
var/datum/lighting_corner/C = queue[i]
for (i in 1 to GLOB.lighting_update_corners.len)
var/datum/lighting_corner/C = GLOB.lighting_update_corners[i]
C.update_objects()
C.needs_update = FALSE
@@ -62,16 +61,15 @@ SUBSYSTEM_DEF(lighting)
else if (MC_TICK_CHECK)
break
if (i)
queue.Cut(1, i+1)
GLOB.lighting_update_corners.Cut(1, i+1)
i = 0
if(!init_tick_checks)
MC_SPLIT_TICK
queue = objects_queue
for (i in 1 to length(queue))
var/atom/movable/lighting_object/O = queue[i]
for (i in 1 to GLOB.lighting_update_objects.len)
var/atom/movable/lighting_object/O = GLOB.lighting_update_objects[i]
if (QDELETED(O))
continue
@@ -83,7 +81,7 @@ SUBSYSTEM_DEF(lighting)
else if (MC_TICK_CHECK)
break
if (i)
queue.Cut(1, i+1)
GLOB.lighting_update_objects.Cut(1, i+1)
/datum/controller/subsystem/lighting/Recover()

View File

@@ -1,7 +1,7 @@
SUBSYSTEM_DEF(min_spawns)
name = "Minimum Spawns" /// this hot steaming pile of garbage makes sure theres a minimum of tendrils scattered around
init_order = INIT_ORDER_DEFAULT
flags = SS_BACKGROUND | SS_NO_FIRE | SS_ALWAYS_SHOW_STAT
flags = SS_BACKGROUND | SS_NO_FIRE
wait = 2
var/where_we_droppin_boys_iterations = 0
var/snaxi_snowflake_check = FALSE

View File

@@ -57,6 +57,7 @@ SUBSYSTEM_DEF(throwing)
var/dx
var/dy
var/force = MOVE_FORCE_DEFAULT
var/gentle = FALSE
var/pure_diagonal
var/diagonal_error
var/datum/callback/callback
@@ -64,15 +65,42 @@ SUBSYSTEM_DEF(throwing)
var/delayed_time = 0
var/last_move = 0
/datum/thrownthing/New(thrownthing, target, target_turf, init_dir, maxrange, speed, thrower, diagonals_first, force, gentle, callback, target_zone)
. = ..()
src.thrownthing = thrownthing
RegisterSignal(thrownthing, COMSIG_PARENT_QDELETING, .proc/on_thrownthing_qdel)
src.target = target
src.target_turf = target_turf
src.init_dir = init_dir
src.maxrange = maxrange
src.speed = speed
src.thrower = thrower
src.diagonals_first = diagonals_first
src.force = force
src.gentle = gentle
src.callback = callback
src.target_zone = target_zone
/datum/thrownthing/Destroy()
SSthrowing.processing -= thrownthing
thrownthing.throwing = null
thrownthing = null
target = null
thrower = null
callback = null
if(callback)
QDEL_NULL(callback) //It stores a reference to the thrownthing, its source. Let's clean that.
return ..()
///Defines the datum behavior on the thrownthing's qdeletion event.
/datum/thrownthing/proc/on_thrownthing_qdel(atom/movable/source, force)
SIGNAL_HANDLER
qdel(src)
/datum/thrownthing/proc/tick()
var/atom/movable/AM = thrownthing
if (!isturf(AM.loc) || !AM.throwing)
@@ -112,7 +140,7 @@ SUBSYSTEM_DEF(throwing)
finalize()
return
AM.Move(step, get_dir(AM, step))
AM.Move(step, get_dir(AM, step), DELAY_TO_GLIDE_SIZE(1 / speed))
if (!AM.throwing) // we hit something during our move
finalize(hit = TRUE)
@@ -136,15 +164,21 @@ SUBSYSTEM_DEF(throwing)
if (A == target)
hit = TRUE
thrownthing.throw_impact(A, src)
if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing
return //deletion should already be handled by on_thrownthing_qdel()
break
if (!hit)
thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground.
if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing
return //deletion should already be handled by on_thrownthing_qdel()
thrownthing.newtonian_move(init_dir)
else
thrownthing.newtonian_move(init_dir)
if(target)
thrownthing.throw_impact(target, src)
if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing
return //deletion should already be handled by on_thrownthing_qdel()
if (callback)
callback.Invoke()

View File

@@ -5,10 +5,12 @@ SUBSYSTEM_DEF(vis_overlays)
init_order = INIT_ORDER_VIS
var/list/vis_overlay_cache
var/list/unique_vis_overlays
var/list/currentrun
/datum/controller/subsystem/vis_overlays/Initialize()
vis_overlay_cache = list()
unique_vis_overlays = list()
return ..()
/datum/controller/subsystem/vis_overlays/fire(resumed = FALSE)
@@ -29,11 +31,36 @@ SUBSYSTEM_DEF(vis_overlays)
return
//the "thing" var can be anything with vis_contents which includes images
/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE)
/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE, unique = FALSE)
var/obj/effect/overlay/vis/overlay
if(!unique)
. = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
var/obj/effect/overlay/vis/overlay = vis_overlay_cache[.]
overlay = vis_overlay_cache[.]
if(!overlay)
overlay = new
overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
vis_overlay_cache[.] = overlay
else
overlay.unused = 0
else
overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
overlay.cache_expiration = -1
var/cache_id = "\ref[overlay]@{[world.time]}"
unique_vis_overlays += overlay
vis_overlay_cache[cache_id] = overlay
. = overlay
thing.vis_contents += overlay
if(!isatom(thing)) // Automatic rotation is not supported on non atoms
return overlay
if(!thing.managed_vis_overlays)
thing.managed_vis_overlays = list(overlay)
else
thing.managed_vis_overlays += overlay
return overlay
/datum/controller/subsystem/vis_overlays/proc/_create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
var/obj/effect/overlay/vis/overlay = new
overlay.icon = icon
overlay.icon_state = iconstate
overlay.layer = layer
@@ -41,19 +68,8 @@ SUBSYSTEM_DEF(vis_overlays)
overlay.dir = dir
overlay.alpha = alpha
overlay.appearance_flags |= add_appearance_flags
vis_overlay_cache[.] = overlay
else
overlay.unused = 0
thing.vis_contents += overlay
return overlay
if(!isatom(thing)) // Automatic rotation is not supported on non atoms
return
if(!thing.managed_vis_overlays)
thing.managed_vis_overlays = list(overlay)
RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_vis_overlay)
else
thing.managed_vis_overlays += overlay
/datum/controller/subsystem/vis_overlays/proc/remove_vis_overlay(atom/movable/thing, list/overlays)
thing.vis_contents -= overlays
@@ -62,15 +78,3 @@ SUBSYSTEM_DEF(vis_overlays)
thing.managed_vis_overlays -= overlays
if(!length(thing.managed_vis_overlays))
thing.managed_vis_overlays = null
UnregisterSignal(thing, COMSIG_ATOM_DIR_CHANGE)
/datum/controller/subsystem/vis_overlays/proc/rotate_vis_overlay(atom/thing, old_dir, new_dir)
if(old_dir == new_dir)
return
var/rotation = dir2angle(old_dir) - dir2angle(new_dir)
var/list/overlays_to_remove = list()
for(var/i in thing.managed_vis_overlays)
var/obj/effect/overlay/vis/overlay = i
add_vis_overlay(thing, overlay.icon, overlay.icon_state, overlay.layer, overlay.plane, turn(overlay.dir, rotation), overlay.alpha, overlay.appearance_flags)
overlays_to_remove += overlay
remove_vis_overlay(thing, overlays_to_remove)

View File

@@ -92,7 +92,7 @@
trauma = _trauma
owner = trauma.owner
setup_friend()
INVOKE_ASYNC(src, .proc/setup_friend)
join = new
join.Grant(src)

View File

@@ -237,7 +237,7 @@
/obj/item/disk/holodisk/Initialize(mapload)
. = ..()
if(preset_record_text)
build_record()
INVOKE_ASYNC(src, .proc/build_record)
/obj/item/disk/holodisk/Destroy()
QDEL_NULL(record)

View File

@@ -1,12 +1,22 @@
/**
* The base type for nearly all physical objects in SS13
* Lots and lots of functionality lives here, although in general we are striving to move
* as much as possible to the components/elements system
*/
/atom
layer = TURF_LAYER
plane = GAME_PLANE
var/level = 2
var/article // If non-null, overrides a/an/some in all cases
appearance_flags = TILE_BOUND
var/level = 2
///If non-null, overrides a/an/some in all cases
var/article
///First atom flags var
var/flags_1 = NONE
///Intearaction flags
var/interaction_flags_atom = NONE
var/datum/reagents/reagents = null
var/flags_ricochet = NONE
@@ -15,35 +25,52 @@
///When a projectile ricochets off this atom, it deals the normal damage * this modifier to this atom
var/ricochet_damage_mod = 0.33
//This atom's HUD (med/sec, etc) images. Associative list.
///Reagents holder
var/datum/reagents/reagents = null
///This atom's HUD (med/sec, etc) images. Associative list.
var/list/image/hud_list = null
//HUD images that this atom can provide.
///HUD images that this atom can provide.
var/list/hud_possible
//Value used to increment ex_act() if reactionary_explosions is on
///Value used to increment ex_act() if reactionary_explosions is on
var/explosion_block = 0
var/list/atom_colours //used to store the different colors on an atom
//its inherent color, the colored paint applied on it, special color effect etc...
/**
* used to store the different colors on an atom
*
* its inherent color, the colored paint applied on it, special color effect etc...
*/
var/list/atom_colours
var/list/remove_overlays // a very temporary list of overlays to remove
var/list/add_overlays // a very temporary list of overlays to add
var/list/managed_vis_overlays //vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays
///overlays managed by update_overlays() to prevent removing overlays that weren't added by the same proc
/// a very temporary list of overlays to remove
var/list/remove_overlays
/// a very temporary list of overlays to add
var/list/add_overlays
///vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays
var/list/managed_vis_overlays
///overlays managed by [update_overlays][/atom/proc/update_overlays] to prevent removing overlays that weren't added by the same proc
var/list/managed_overlays
///Proximity monitor associated with this atom
var/datum/proximity_monitor/proximity_monitor
///Last fingerprints to touch this atom
var/fingerprintslast
var/list/filter_data //For handling persistent filters
///Price of an item in a vending machine, overriding the base vending machine price. Define in terms of paycheck defines as opposed to raw numbers.
var/custom_price
///Price of an item in a vending machine, overriding the premium vending machine price. Define in terms of paycheck defines as opposed to raw numbers.
var/custom_premium_price
//List of datums orbiting this atom
var/datum/component/orbiter/orbiters
var/rad_flags = NONE // Will move to flags_1 when i can be arsed to
/// Radiation insulation types
var/rad_insulation = RAD_NO_INSULATION
///The custom materials this atom is made of, used by a lot of things like furniture, walls, and floors (if I finish the functionality, that is.)
@@ -72,6 +99,16 @@
///Mobs that are currently do_after'ing this atom, to be cleared from on Destroy()
var/list/targeted_by
/**
* Called when an atom is created in byond (built in engine proc)
*
* Not a lot happens here in SS13 code, as we offload most of the work to the
* [Intialization][/atom/proc/Initialize] proc, mostly we run the preloader
* if the preloader is being used and then call [InitAtom][/datum/controller/subsystem/atoms/proc/InitAtom] of which the ultimate
* result is that the Intialize proc is called.
*
* We also generate a tag here if the DF_USE_TAG flag is set on the atom
*/
/atom/New(loc, ...)
//atom creation method that preloads variables at creation
if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
@@ -87,24 +124,50 @@
//we were deleted
return
//Called after New if the map is being loaded. mapload = TRUE
//Called from base of New if the map is not being loaded. mapload = FALSE
//This base must be called or derivatives must set initialized to TRUE
//must not sleep
//Other parameters are passed from New (excluding loc), this does not happen if mapload is TRUE
//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm
//Note: the following functions don't call the base for optimization and must copypasta:
// /turf/Initialize
// /turf/open/space/Initialize
/**
* The primary method that objects are setup in SS13 with
*
* we don't use New as we have better control over when this is called and we can choose
* to delay calls or hook other logic in and so forth
*
* During roundstart map parsing, atoms are queued for intialization in the base atom/New(),
* After the map has loaded, then Initalize is called on all atoms one by one. NB: this
* is also true for loading map templates as well, so they don't Initalize until all objects
* in the map file are parsed and present in the world
*
* If you're creating an object at any point after SSInit has run then this proc will be
* immediately be called from New.
*
* mapload: This parameter is true if the atom being loaded is either being intialized during
* the Atom subsystem intialization, or if the atom is being loaded from the map template.
* If the item is being created at runtime any time after the Atom subsystem is intialized then
* it's false.
*
* You must always call the parent of this proc, otherwise failures will occur as the item
* will not be seen as initalized (this can lead to all sorts of strange behaviour, like
* the item being completely unclickable)
*
* You must not sleep in this proc, or any subprocs
*
* Any parameters from new are passed through (excluding loc), naturally if you're loading from a map
* there are no other arguments
*
* Must return an [initialization hint][INITIALIZE_HINT_NORMAL] or a runtime will occur.
*
* Note: the following functions don't call the base for optimization and must copypasta handling:
* * [/turf/proc/Initialize]
* * [/turf/open/space/proc/Initialize]
*/
/atom/proc/Initialize(mapload, ...)
// SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(TRUE)
if(flags_1 & INITIALIZED_1)
stack_trace("Warning: [src]([type]) initialized multiple times!")
flags_1 |= INITIALIZED_1
if(loc)
SEND_SIGNAL(loc, COMSIG_ATOM_CREATED, src) /// Sends a signal that the new atom `src`, has been created at `loc`
//atom color stuff
if(color)
add_atom_colour(color, FIXED_COLOUR_PRIORITY)
@@ -126,14 +189,34 @@
return INITIALIZE_HINT_NORMAL
//called if Initialize returns INITIALIZE_HINT_LATELOAD
/**
* Late Intialization, for code that should run after all atoms have run Intialization
*
* To have your LateIntialize proc be called, your atoms [Initalization][/atom/proc/Initialize]
* proc must return the hint
* [INITIALIZE_HINT_LATELOAD] otherwise you will never be called.
*
* useful for doing things like finding other machines on GLOB.machines because you can guarantee
* that all atoms will actually exist in the "WORLD" at this time and that all their Intialization
* code has been run
*/
/atom/proc/LateInitialize()
return
set waitfor = FALSE
// Put your AddComponent() calls here
/// Put your [AddComponent] calls here
/atom/proc/ComponentInitialize()
return
/**
* Top level of the destroy chain for most atoms
*
* Cleans up the following:
* * Removes alternate apperances from huds that see them
* * qdels the reagent holder from atoms if it exists
* * clears the orbiters list
* * clears overlays and priority overlays
* * clears the light object
*/
/atom/Destroy()
if(alternate_appearances)
for(var/K in alternate_appearances)
@@ -143,6 +226,8 @@
if(reagents)
qdel(reagents)
orbiters = null // The component is attached to us normaly and will be deleted elsewhere
LAZYCLEARLIST(overlays)
for(var/i in targeted_by)
@@ -179,6 +264,16 @@
/atom/proc/CanPass(atom/movable/mover, turf/target)
return !density
/**
* Is this atom currently located on centcom
*
* Specifically, is it on the z level and within the centcom areas
*
* You can also be in a shuttleshuttle during endgame transit
*
* Used in gamemode to identify mobs who have escaped and for some other areas of the code
* who don't want atoms where they shouldn't be
*/
/atom/proc/onCentCom()
var/turf/T = get_turf(src)
if(!T)
@@ -209,6 +304,13 @@
if(T in shuttle_area)
return TRUE
/**
* Is the atom in any of the centcom syndicate areas
*
* Either in the syndie base on centcom, or any of their shuttles
*
* Also used in gamemode code for win conditions
*/
/atom/proc/onSyndieBase()
var/turf/T = get_turf(src)
if(!T)
@@ -222,6 +324,23 @@
return FALSE
/**
* Is the atom in an away mission
*
* Must be in the away mission z-level to return TRUE
*
* Also used in gamemode code for win conditions
*/
/atom/proc/onAwayMission()
var/turf/T = get_turf(src)
if(!T)
return FALSE
if(is_away_level(T.z))
return TRUE
return FALSE
/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user)
if(does_attack_animation)
@@ -415,7 +534,7 @@
/// Updates the overlays of the atom
/atom/proc/update_overlays()
SHOULD_CALL_PARENT(1)
SHOULD_CALL_PARENT(TRUE)
. = list()
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_OVERLAYS, .)
@@ -1161,3 +1280,4 @@
// first of all make sure we valid
var/mouseparams = list2params(paramslist)
usr_client.Click(src, loc, null, mouseparams)
return TRUE

View File

@@ -1,5 +1,7 @@
/atom/movable
layer = OBJ_LAYER
glide_size = 8
appearance_flags = TILE_BOUND|PIXEL_SCALE
var/last_move = null
var/last_move_time = 0
var/anchored = FALSE
@@ -28,8 +30,6 @@
var/atom/movable/moving_from_pull //attempt to resume grab after moving instead of before.
var/list/client_mobs_in_contents // This contains all the client mobs within this container
var/list/acted_explosions //for explosion dodging
glide_size = 8
appearance_flags = TILE_BOUND|PIXEL_SCALE
var/datum/forced_movement/force_moving = null //handled soley by forced_movement.dm
var/movement_type = GROUND //Incase you have multiple types, you automatically use the most useful one. IE: Skating on ice, flippers on water, flying over chasm/space, etc.
var/atom/movable/pulling
@@ -59,6 +59,42 @@
em_block = new(src, render_target)
vis_contents += em_block
/atom/movable/Destroy(force)
QDEL_NULL(proximity_monitor)
QDEL_NULL(language_holder)
QDEL_NULL(em_block)
unbuckle_all_mobs(force = TRUE)
if(loc)
//Restore air flow if we were blocking it (movables with ATMOS_PASS_PROC will need to do this manually if necessary)
if(((CanAtmosPass == ATMOS_PASS_DENSITY && density) || CanAtmosPass == ATMOS_PASS_NO) && isturf(loc))
CanAtmosPass = ATMOS_PASS_YES
air_update_turf(TRUE)
loc.handle_atom_del(src)
// if(opacity)
// RemoveElement(/datum/element/light_blocking)
invisibility = INVISIBILITY_ABSTRACT
if(pulledby)
pulledby.stop_pulling()
if(orbiting)
orbiting.end_orbit(src)
orbiting = null
. = ..()
for(var/movable_content in contents)
qdel(movable_content)
LAZYCLEARLIST(client_mobs_in_contents)
moveToNullspace()
/atom/movable/proc/update_emissive_block()
if(blocks_emissive != EMISSIVE_BLOCK_GENERIC)
return
@@ -114,12 +150,13 @@
return T.zPassOut(src, direction, destination) && destination.zPassIn(src, direction, T)
/atom/movable/vv_edit_var(var_name, var_value)
var/static/list/banned_edits = list("step_x", "step_y", "step_size")
var/static/list/careful_edits = list("bound_x", "bound_y", "bound_width", "bound_height")
if(var_name in banned_edits)
var/static/list/banned_edits = list("step_x" = TRUE, "step_y" = TRUE, "step_size" = TRUE, "bounds" = TRUE)
var/static/list/careful_edits = list("bound_x" = TRUE, "bound_y" = TRUE, "bound_width" = TRUE, "bound_height" = TRUE)
if(banned_edits[var_name])
return FALSE //PLEASE no.
if((var_name in careful_edits) && (var_value % world.icon_size) != 0)
if((careful_edits[var_name]) && (var_value % world.icon_size) != 0)
return FALSE
switch(var_name)
if(NAMEOF(src, x))
var/turf/T = locate(var_value, y, z)
@@ -140,13 +177,24 @@
return TRUE
return FALSE
if(NAMEOF(src, loc))
if(istype(var_value, /atom))
if(isatom(var_value) || isnull(var_value))
forceMove(var_value)
return TRUE
else if(isnull(var_value))
moveToNullspace()
return TRUE
return FALSE
if(NAMEOF(src, anchored))
set_anchored(var_value)
. = TRUE
if(NAMEOF(src, pulledby))
set_pulledby(var_value)
. = TRUE
if(NAMEOF(src, glide_size))
set_glide_size(var_value)
. = TRUE
if(!isnull(.))
datum_flags |= DF_VAR_EDITED
return
return ..()
/atom/movable/proc/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
@@ -168,48 +216,68 @@
AMob.grabbedby(src)
return TRUE
stop_pulling()
// SEND_SIGNAL(src, COMSIG_ATOM_START_PULL, AM, state, force)
if(AM.pulledby)
log_combat(AM, AM.pulledby, "pulled from", src)
AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once.
pulling = AM
AM.pulledby = src
AM.set_pulledby(src)
setGrabState(state)
if(ismob(AM))
var/mob/M = AM
log_combat(src, M, "grabbed", addition="passive grab")
if(!supress_message)
visible_message("<span class='warning'>[src] has grabbed [M] passively!</span>")
M.visible_message("<span class='warning'>[src] grabs [M] passively.</span>", \
"<span class='danger'>[src] grabs you passively.</span>")
return TRUE
/atom/movable/proc/stop_pulling()
if(!pulling)
return
pulling.pulledby = null
pulling.set_pulledby(null)
var/mob/living/ex_pulled = pulling
setGrabState(GRAB_PASSIVE)
pulling = null
setGrabState(0)
if(isliving(ex_pulled))
var/mob/living/L = ex_pulled
L.update_mobility()// mob gets up if it was lyng down in a chokehold
///Reports the event of the change in value of the pulledby variable.
/atom/movable/proc/set_pulledby(new_pulledby)
if(new_pulledby == pulledby)
return FALSE //null signals there was a change, be sure to return FALSE if none happened here.
. = pulledby
pulledby = new_pulledby
/atom/movable/proc/Move_Pulled(atom/A)
if(!pulling)
return
return FALSE
if(pulling.anchored || pulling.move_resist > move_force || !pulling.Adjacent(src))
stop_pulling()
return
return FALSE
if(isliving(pulling))
var/mob/living/L = pulling
if(L.buckled && L.buckled.buckle_prevents_pull) //if they're buckled to something that disallows pulling, prevent it
stop_pulling()
return
return FALSE
if(A == loc && pulling.density)
return
if(!Process_Spacemove(get_dir(pulling.loc, A)))
return
step(pulling, get_dir(pulling.loc, A))
return FALSE
var/move_dir = get_dir(pulling.loc, A)
if(!Process_Spacemove(move_dir))
return FALSE
pulling.Move(get_step(pulling.loc, move_dir), move_dir, glide_size)
return TRUE
/mob/living/Move_Pulled(atom/A)
. = ..()
if(!. || !isliving(A))
return
var/mob/living/L = A
set_pull_offsets(L, grab_state)
/atom/movable/proc/check_pulling()
if(pulling)
var/atom/movable/pullee = pulling
@@ -229,54 +297,51 @@
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
/atom/movable/Destroy(force)
QDEL_NULL(proximity_monitor)
QDEL_NULL(language_holder)
QDEL_NULL(em_block)
unbuckle_all_mobs(force=1)
/atom/movable/proc/set_glide_size(target = 8)
// SEND_SIGNAL(src, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, target)
glide_size = target
. = ..()
for(var/m in buckled_mobs)
var/mob/buckled_mob = m
buckled_mob.set_glide_size(target)
if(loc)
//Restore air flow if we were blocking it (movables with ATMOS_PASS_PROC will need to do this manually if necessary)
if(((CanAtmosPass == ATMOS_PASS_DENSITY && density) || CanAtmosPass == ATMOS_PASS_NO) && isturf(loc))
CanAtmosPass = ATMOS_PASS_YES
air_update_turf(TRUE)
loc.handle_atom_del(src)
for(var/atom/movable/AM in contents)
qdel(AM)
moveToNullspace()
invisibility = INVISIBILITY_ABSTRACT
if(pulledby)
pulledby.stop_pulling()
if(orbiting)
orbiting.end_orbit(src)
orbiting = null
///Sets the anchored var and returns if it was sucessfully changed or not.
/atom/movable/proc/set_anchored(anchorvalue)
SHOULD_CALL_PARENT(TRUE)
if(anchored == anchorvalue)
return
. = anchored
anchored = anchorvalue
// SEND_SIGNAL(src, COMSIG_MOVABLE_SET_ANCHORED, anchorvalue)
/atom/movable/proc/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
set waitfor = 0
set waitfor = FALSE
var/hitpush = TRUE
var/impact_signal = SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum)
if(impact_signal & COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH)
hitpush = FALSE // hacky, tie this to something else or a proper workaround later
if(impact_signal & ~COMPONENT_MOVABLE_IMPACT_NEVERMIND) // in case a signal interceptor broke or deleted the thing before we could process our hit
return hit_atom.hitby(src, throwingdatum = throwingdatum, hitpush = hitpush)
if(!(impact_signal && (impact_signal & COMPONENT_MOVABLE_IMPACT_NEVERMIND))) // in case a signal interceptor broke or deleted the thing before we could process our hit
return hit_atom.hitby(src, throwingdatum=throwingdatum, hitpush=hitpush)
/atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked, datum/thrownthing/throwingdatum)
if(!anchored && hitpush && (!throwingdatum || (throwingdatum.force >= (move_resist * MOVE_FORCE_PUSH_RATIO))))
step(src, AM.dir)
..()
/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = INFINITY, messy_throw = TRUE)
/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE)
if((force < (move_resist * MOVE_FORCE_THROW_RATIO)) || (move_resist == INFINITY))
return
return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, force, messy_throw)
return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, force, gentle)
/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = INFINITY, messy_throw = TRUE) //If this returns FALSE then callback will not be called.
///If this returns FALSE then callback will not be called.
/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE, quickstart = TRUE)
. = FALSE
if(QDELETED(src))
CRASH("Qdeleted thing being thrown around.")
if (!target || speed <= 0)
return
@@ -288,7 +353,7 @@
//They are moving! Wouldn't it be cool if we calculated their momentum and added it to the throw?
if (thrower && thrower.last_move && thrower.client && thrower.client.move_delay >= world.time + world.tick_lag*2)
var/user_momentum = thrower.movement_delay()
var/user_momentum = thrower.movement_delay() //cached_multiplicative_slowdown
if (!user_momentum) //no movement_delay, this means they move once per byond tick, lets calculate from that instead.
user_momentum = world.tick_lag
@@ -312,19 +377,13 @@
. = TRUE // No failure conditions past this point.
var/datum/thrownthing/TT = new()
TT.thrownthing = src
TT.target = target
TT.target_turf = get_turf(target)
TT.init_dir = get_dir(src, target)
TT.maxrange = range
TT.speed = speed
TT.thrower = thrower
TT.diagonals_first = diagonals_first
TT.force = force
TT.callback = callback
if(!QDELETED(thrower))
TT.target_zone = thrower.zone_selected
var/target_zone
if(QDELETED(thrower))
thrower = null //Let's not pass a qdeleting reference if any.
else
target_zone = thrower.zone_selected
var/datum/thrownthing/TT = new(src, target, get_turf(target), get_dir(src, target), range, speed, thrower, diagonals_first, force, gentle, callback, target_zone)
var/dist_x = abs(target.x - src.x)
var/dist_y = abs(target.y - src.y)
@@ -359,6 +418,7 @@
SSthrowing.processing[src] = TT
if (SSthrowing.state == SS_PAUSED && length(SSthrowing.currentrun))
SSthrowing.currentrun[src] = TT
if (quickstart)
TT.tick()
/atom/movable/proc/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
@@ -382,13 +442,13 @@
return TRUE
return ..()
// called when this atom is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called.
/atom/movable/proc/on_exit_storage(datum/component/storage/concrete/S)
return
/// called when this atom is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called.
/atom/movable/proc/on_exit_storage(datum/component/storage/concrete/S) // rename S to master_storage
// SEND_SIGNAL(src, COMSIG_STORAGE_EXITED, master_storage)
// called when this atom is added into a storage item, which is passed on as S. The loc variable is already set to the storage item.
/// called when this atom is added into a storage item, which is passed on as S. The loc variable is already set to the storage item.
/atom/movable/proc/on_enter_storage(datum/component/storage/concrete/S)
return
// SEND_SIGNAL(src, COMSIG_STORAGE_ENTERED, master_storage)
/atom/movable/proc/get_spacemove_backup()
var/atom/movable/dense_object_backup
@@ -422,24 +482,26 @@
return //don't do an animation if attacking self
var/pixel_x_diff = 0
var/pixel_y_diff = 0
var/turn_dir = 1
var/direction = get_dir(src, A)
if(direction & NORTH)
pixel_y_diff = 8
turn_dir = prob(50) ? -1 : 1
else if(direction & SOUTH)
pixel_y_diff = -8
turn_dir = prob(50) ? -1 : 1
if(direction & EAST)
pixel_x_diff = 8
else if(direction & WEST)
pixel_x_diff = -8
turn_dir = -1
var/matrix/OM = matrix(transform)
var/matrix/M = matrix(transform)
M.Turn(pixel_x_diff ? pixel_x_diff*2 : pick(-16, 16))
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, transform = M, time = 2)
animate(src, pixel_x = pixel_x - pixel_x_diff, pixel_y = pixel_y - pixel_y_diff, transform = OM, time = 2)
var/matrix/initial_transform = matrix(transform)
var/matrix/rotated_transform = transform.Turn(15 * turn_dir)
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, transform=rotated_transform, time = 1, easing=BACK_EASING|EASE_IN)
animate(pixel_x = pixel_x - pixel_x_diff, pixel_y = pixel_y - pixel_y_diff, transform=initial_transform, time = 2, easing=SINE_EASING)
/atom/movable/proc/do_item_attack_animation(atom/A, visual_effect_icon, obj/item/used_item)
var/image/I
@@ -450,21 +512,21 @@
I.plane = GAME_PLANE
// Scale the icon.
I.transform *= 0.75
I.transform *= 0.4
// The icon should not rotate.
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
// Set the direction of the icon animation.
var/direction = get_dir(src, A)
if(direction & NORTH)
I.pixel_y = -16
I.pixel_y = -12
else if(direction & SOUTH)
I.pixel_y = 16
I.pixel_y = 12
if(direction & EAST)
I.pixel_x = -16
I.pixel_x = -14
else if(direction & WEST)
I.pixel_x = 16
I.pixel_x = 14
if(!direction) // Attacked self?!
I.pixel_z = 16
@@ -472,10 +534,12 @@
if(!I)
return
flick_overlay(I, GLOB.clients, 5) // 5 ticks/half a second
flick_overlay(I, GLOB.clients, 10)
// And animate the attack!
animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3)
animate(I, alpha = 175, transform = matrix() * 0.75, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3)
animate(time = 1)
animate(alpha = 0, time = 3, easing = CIRCULAR_EASING|EASE_OUT)
/atom/movable/vv_get_dropdown()
. = ..()
@@ -495,16 +559,14 @@
/atom/movable/proc/float(on)
if(throwing)
return
if(on && (!(movement_type & FLOATING) || floating_need_update))
animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1)
sleep(10)
animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1)
if(!(movement_type & FLOATING))
if(on && !(movement_type & FLOATING))
animate(src, pixel_y = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
animate(pixel_y = -2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
setMovetype(movement_type | FLOATING)
else if (!on && movement_type & FLOATING)
else if (!on && (movement_type & FLOATING))
animate(src, pixel_y = initial(pixel_y), time = 10)
setMovetype(movement_type & ~FLOATING)
floating_need_update = FALSE
floating_need_update = FALSE // assume it's done
/* Language procs
* Unless you are doing something very specific, these are the ones you want to use.
@@ -611,10 +673,32 @@
return FALSE
return TRUE
/// Updates the grab state of the movable
/// This exists to act as a hook for behaviour
/**
* Updates the grab state of the movable
*
* This exists to act as a hook for behaviour
*/
/atom/movable/proc/setGrabState(newstate)
if(newstate == grab_state)
return
// SEND_SIGNAL(src, COMSIG_MOVABLE_SET_GRAB_STATE, newstate)
. = grab_state
grab_state = newstate
// switch(grab_state) // Current state.
// if(GRAB_PASSIVE)
// REMOVE_TRAIT(pulling, TRAIT_IMMOBILIZED, CHOKEHOLD_TRAIT)
// REMOVE_TRAIT(pulling, TRAIT_HANDS_BLOCKED, CHOKEHOLD_TRAIT)
// if(. >= GRAB_NECK) // Previous state was a a neck-grab or higher.
// REMOVE_TRAIT(pulling, TRAIT_FLOORED, CHOKEHOLD_TRAIT)
// if(GRAB_AGGRESSIVE)
// if(. >= GRAB_NECK) // Grab got downgraded.
// REMOVE_TRAIT(pulling, TRAIT_FLOORED, CHOKEHOLD_TRAIT)
// else // Grab got upgraded from a passive one.
// ADD_TRAIT(pulling, TRAIT_IMMOBILIZED, CHOKEHOLD_TRAIT)
// ADD_TRAIT(pulling, TRAIT_HANDS_BLOCKED, CHOKEHOLD_TRAIT)
// if(GRAB_NECK, GRAB_KILL)
// if(. <= GRAB_AGGRESSIVE)
// ADD_TRAIT(pulling, TRAIT_FLOORED, CHOKEHOLD_TRAIT)
/obj/item/proc/do_pickup_animation(atom/target)
set waitfor = FALSE
@@ -626,31 +710,24 @@
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
var/turf/T = get_turf(src)
var/direction
var/to_x = 0
var/to_y = 0
var/to_x = initial(target.pixel_x)
var/to_y = initial(target.pixel_y)
if(!QDELETED(T) && !QDELETED(target))
direction = get_dir(T, target)
if(direction & NORTH)
to_y = 32
to_y += 32
else if(direction & SOUTH)
to_y = -32
to_y -= 32
if(direction & EAST)
to_x = 32
to_x += 32
else if(direction & WEST)
to_x = -32
to_x -= 32
if(!direction)
to_y = 16
to_y += 16
flick_overlay(I, GLOB.clients, 6)
var/matrix/M = new
M.Turn(pick(-30, 30))
animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = M, easing = CUBIC_EASING)
sleep(1)
animate(I, alpha = 0, transform = matrix(), time = 1)
/atom/movable/proc/set_anchored(anchorvalue) //literally only for plumbing ran
SHOULD_CALL_PARENT(TRUE)
if(anchored == anchorvalue)
return
. = anchored
anchored = anchorvalue

View File

@@ -5,8 +5,7 @@
// Here's where we rewrite how byond handles movement except slightly different
// To be removed on step_ conversion
// All this work to prevent a second bump
/atom/movable/Move(atom/newloc, direct=0)
set waitfor = FALSE //n o
/atom/movable/Move(atom/newloc, direct=0, glide_size_override = 0)
. = FALSE
if(!newloc || newloc == loc)
return
@@ -52,8 +51,7 @@
//
////////////////////////////////////////
/atom/movable/Move(atom/newloc, direct)
set waitfor = FALSE //n o
/atom/movable/Move(atom/newloc, direct, glide_size_override = 0)
var/atom/movable/pullee = pulling
var/turf/T = loc
if(!moving_from_pull)
@@ -61,6 +59,9 @@
if(!loc || !newloc)
return FALSE
var/atom/oldloc = loc
//Early override for some cases like diagonal movement
if(glide_size_override)
set_glide_size(glide_size_override)
if(loc != newloc)
if (!(direct & (direct - 1))) //Cardinal move
@@ -120,17 +121,12 @@
return
if(!loc || (loc == oldloc && oldloc != newloc))
last_move = NONE
last_move = 0
return
if(.)
last_move = direct
setDir(direct)
if(has_buckled_mobs() && !handle_buckled_mob_movement(loc,direct)) //movement failed due to buckled mob(s)
return FALSE
if(pulling && pulling == pullee && pulling != moving_from_pull) //we were pulling a thing and didn't lose it during our move.
Moved(oldloc, direct)
if(. && pulling && pulling == pullee && pulling != moving_from_pull) //we were pulling a thing and didn't lose it during our move.
if(pulling.anchored)
stop_pulling()
else
@@ -138,14 +134,25 @@
//puller and pullee more than one tile away or in diagonal position
if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir)))
pulling.moving_from_pull = src
pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position
pulling.Move(T, get_dir(pulling, T), glide_size) //the pullee tries to reach our previous position
pulling.moving_from_pull = null
Moved(oldloc, direct)
check_pulling()
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)
//glide_size strangely enough can change mid movement animation and update correctly while the animation is playing
//This means that if you don't override it late like this, it will just be set back by the movement update that's called when you move turfs.
if(glide_size_override)
set_glide_size(glide_size_override)
last_move = direct
setDir(direct)
if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc, direct, glide_size_override)) //movement failed due to buckled mob(s)
return FALSE
/atom/movable/proc/handle_buckled_mob_movement(newloc, direct, glide_size_override)
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
if(!buckled_mob.Move(newloc, direct))
if(!buckled_mob.Move(newloc, direct, glide_size_override))
forceMove(buckled_mob.loc)
last_move = buckled_mob.last_move
inertia_dir = last_move
@@ -155,6 +162,7 @@
//Called after a successful Move(). By this point, we've already moved
/atom/movable/proc/Moved(atom/OldLoc, Dir, Forced = FALSE)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, OldLoc, Dir, Forced)
if (!inertia_moving)
inertia_next_move = world.time + inertia_move_delay
@@ -174,6 +182,8 @@
//oldloc = old location on atom, inserted when forceMove is called and ONLY when forceMove is called!
/atom/movable/Crossed(atom/movable/AM, oldloc)
// SHOULD_CALL_PARENT(TRUE)
. = ..()
SEND_SIGNAL(src, COMSIG_MOVABLE_CROSSED, AM)
/atom/movable/Uncross(atom/movable/AM, atom/newloc)
@@ -204,7 +214,11 @@
var/atom/movable/AM = item
AM.onTransitZ(old_z,new_z)
///Proc to modify the movement_type and hook behavior associated with it changing.
/atom/movable/proc/setMovetype(newval)
if(movement_type == newval)
return
. = movement_type
movement_type = newval
///////////// FORCED MOVEMENT /////////////
@@ -268,37 +282,44 @@
old_area.Exited(src, null)
loc = null
//Called whenever an object moves and by mobs when they attempt to move themselves through space
//And when an object or action applies a force on src, see newtonian_move() below
//Return 0 to have src start/keep drifting in a no-grav area and 1 to stop/not start drifting
//Mobs should return 1 if they should be able to move of their own volition, see client/Move() in mob_movement.dm
//movement_dir == 0 when stopping or any dir when trying to move
/**
* Called whenever an object moves and by mobs when they attempt to move themselves through space
* And when an object or action applies a force on src, see [newtonian_move][/atom/movable/proc/newtonian_move]
*
* Return 0 to have src start/keep drifting in a no-grav area and 1 to stop/not start drifting
*
* Mobs should return 1 if they should be able to move of their own volition, see [/client/proc/Move]
*
* Arguments:
* * movement_dir - 0 when stopping or any dir when trying to move
*/
/atom/movable/proc/Process_Spacemove(movement_dir = 0)
if(has_gravity(src))
return 1
return TRUE
if(pulledby)
return 1
if(pulledby && (pulledby.pulledby != src || moving_from_pull))
return TRUE
if(throwing)
return 1
return TRUE
if(!isturf(loc))
return 1
return TRUE
if(locate(/obj/structure/lattice) in range(1, get_turf(src))) //Not realistic but makes pushing things in space easier
return 1
return TRUE
return 0
return FALSE
/atom/movable/proc/newtonian_move(direction) //Only moves the object if it's under no gravity
if(!loc || Process_Spacemove(0))
/// Only moves the object if it's under no gravity
/atom/movable/proc/newtonian_move(direction)
if(!isturf(loc) || Process_Spacemove(0))
inertia_dir = 0
return 0
return FALSE
inertia_dir = direction
if(!direction)
return 1
return TRUE
inertia_last_loc = loc
SSspacedrift.processing[src] = src
return 1
return TRUE

View File

@@ -23,7 +23,7 @@
. = ..()
SSradio.remove_object(src, air_frequency)
air_connection = SSradio.add_object(src, air_frequency, RADIO_TO_AIRALARM)
open()
INVOKE_ASYNC(src, .proc/open)
/obj/machinery/door/airlock/alarmlock/receive_signal(datum/signal/signal)
..()

View File

@@ -11,6 +11,8 @@
#define SPIN_TIME 65 //As always, deciseconds.
#define REEL_DEACTIVATE_DELAY 7
#define SEVEN "<font color='red'>7</font>"
#define HOLOCHIP 1
#define COIN 2
/obj/machinery/computer/slot_machine
name = "slot machine"
@@ -21,40 +23,48 @@
use_power = IDLE_POWER_USE
idle_power_usage = 50
circuit = /obj/item/circuitboard/computer/slot_machine
light_color = LIGHT_COLOR_BROWN
var/money = 3000 //How much money it has CONSUMED
var/plays = 0
var/working = 0
var/working = FALSE
var/balance = 0 //How much money is in the machine, ready to be CONSUMED.
var/jackpots = 0
var/paymode = HOLOCHIP //toggles between HOLOCHIP/COIN, defined above
var/cointype = /obj/item/coin/iron //default cointype
var/list/coinvalues = list()
var/list/reels = list(list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0)
var/list/symbols = list(SEVEN = 1, "<font color='orange'>&</font>" = 2, "<font color='yellow'>@</font>" = 2, "<font color='green'>$</font>" = 2, "<font color='blue'>?</font>" = 2, "<font color='grey'>#</font>" = 2, "<font color='white'>!</font>" = 2, "<font color='fuchsia'>%</font>" = 2) //if people are winning too much, multiply every number in this list by 2 and see if they are still winning too much.
light_color = LIGHT_COLOR_BROWN
/obj/machinery/computer/slot_machine/Initialize()
. = ..()
jackpots = rand(1, 4) //false hope
plays = rand(75, 200)
toggle_reel_spin(1) //The reels won't spin unless we activate them
INVOKE_ASYNC(src, .proc/toggle_reel_spin, TRUE)//The reels won't spin unless we activate them
var/list/reel = reels[1]
for(var/i = 0, i < reel.len, i++) //Populate the reels.
randomize_reels()
toggle_reel_spin(0)
INVOKE_ASYNC(src, .proc/toggle_reel_spin, FALSE)
for(cointype in typesof(/obj/item/coin))
var/obj/item/coin/C = new cointype
coinvalues["[cointype]"] = C.get_item_credit_value()
qdel(C) //Sigh
/obj/machinery/computer/slot_machine/Destroy()
if(balance)
give_coins(balance)
give_payout(balance)
return ..()
/obj/machinery/computer/slot_machine/process()
/obj/machinery/computer/slot_machine/process(delta_time)
. = ..() //Sanity checks.
if(!.)
return .
money++ //SPESSH MAJICKS
money += round(delta_time / 2) //SPESSH MAJICKS
/obj/machinery/computer/slot_machine/update_icon_state()
if(stat & NOPOWER)
@@ -69,13 +79,10 @@
else
icon_state = "slots1"
/obj/machinery/computer/slot_machine/power_change()
..()
update_icon()
/obj/machinery/computer/slot_machine/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/coin))
var/obj/item/coin/C = I
if(paymode == COIN)
if(prob(2))
if(!user.transferItemToLoc(C, drop_location()))
return
@@ -90,6 +97,28 @@
to_chat(user, "<span class='notice'>You insert [C] into [src]'s slot!</span>")
balance += C.value
qdel(C)
else
to_chat(user, "<span class='warning'>This machine is only accepting holochips!</span>")
else if(istype(I, /obj/item/holochip))
if(paymode == HOLOCHIP)
var/obj/item/holochip/H = I
if(!user.temporarilyRemoveItemFromInventory(H))
return
to_chat(user, "<span class='notice'>You insert [H.credits] holocredits into [src]'s slot!</span>")
balance += H.credits
qdel(H)
else
to_chat(user, "<span class='warning'>This machine is only accepting coins!</span>")
else if(I.tool_behaviour == TOOL_MULTITOOL)
if(balance > 0)
visible_message("<b>[src]</b> says, 'ERROR! Please empty the machine balance before altering paymode'") //Prevents converting coins into holocredits and vice versa
else
if(paymode == HOLOCHIP)
paymode = COIN
visible_message("<b>[src]</b> says, 'This machine now works with COINS!'")
else
paymode = HOLOCHIP
visible_message("<b>[src]</b> says, 'This machine now works with HOLOCHIPS!'")
else
return ..()
@@ -101,8 +130,7 @@
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread()
spark_system.set_up(4, 0, src.loc)
spark_system.start()
playsound(src, "sparks", 50, 1)
return TRUE
playsound(src, "sparks", 50, TRUE)
/obj/machinery/computer/slot_machine/ui_interact(mob/living/user)
. = ..()
@@ -127,8 +155,9 @@
<A href='?src=[REF(src)];spin=1'>Play!</A><BR>
<BR>
[reeltext]
<BR>
<font size='1'><A href='?src=[REF(src)];refund=1'>Refund balance</A><BR>"}
<BR>"}
if(balance > 0)
dat+="<font size='1'><A href='?src=[REF(src)];refund=1'>Refund balance</A><BR>"
var/datum/browser/popup = new(user, "slotmachine", "Slot Machine")
popup.set_content(dat)
@@ -143,21 +172,22 @@
spin(usr)
else if(href_list["refund"])
give_coins(balance)
if(balance > 0)
give_payout(balance)
balance = 0
/obj/machinery/computer/slot_machine/emp_act(severity)
. = ..()
if(stat & (NOPOWER|BROKEN) || . & EMP_PROTECT_SELF)
return
if(prob(1500 / severity))
if(prob(15 * severity))
return
if(prob(1 * severity/100)) // :^)
if(prob(1)) // :^)
obj_flags |= EMAGGED
var/severity_ascending = 4 - severity
money = max(rand(money - (200 * severity_ascending), money + (200 * severity_ascending)), 0)
balance = max(rand(balance - (50 * severity_ascending), balance + (50 * severity_ascending)), 0)
money -= max(0, give_coins(min(rand(-50, 100 * severity_ascending)), money)) //This starts at -50 because it shouldn't always dispense coins yo
money -= max(0, give_payout(min(rand(-50, 100 * severity_ascending)), money)) //This starts at -50 because it shouldn't always dispense coins yo
spin()
/obj/machinery/computer/slot_machine/proc/spin(mob/user)
@@ -174,21 +204,25 @@
balance -= SPIN_PRICE
money += SPIN_PRICE
plays += 1
working = 1
working = TRUE
toggle_reel_spin(1)
update_icon()
updateDialog()
spawn(0)
while(working)
var/spin_loop = addtimer(CALLBACK(src, .proc/do_spin), 2, TIMER_LOOP|TIMER_STOPPABLE)
addtimer(CALLBACK(src, .proc/finish_spinning, spin_loop, user, the_name), SPIN_TIME - (REEL_DEACTIVATE_DELAY * reels.len))
//WARNING: no sanity checking for user since it's not needed and would complicate things (machine should still spin even if user is gone), be wary of this if you're changing this code.
/obj/machinery/computer/slot_machine/proc/do_spin()
randomize_reels()
updateDialog()
sleep(2)
spawn(SPIN_TIME - (REEL_DEACTIVATE_DELAY * reels.len)) //WARNING: no sanity checking for user since it's not needed and would complicate things (machine should still spin even if user is gone), be wary of this if you're changing this code.
/obj/machinery/computer/slot_machine/proc/finish_spinning(spin_loop, mob/user, the_name)
toggle_reel_spin(0, REEL_DEACTIVATE_DELAY)
working = 0
working = FALSE
deltimer(spin_loop)
give_prizes(the_name, user)
update_icon()
updateDialog()
@@ -196,15 +230,17 @@
/obj/machinery/computer/slot_machine/proc/can_spin(mob/user)
if(stat & NOPOWER)
to_chat(user, "<span class='warning'>The slot machine has no power!</span>")
return FALSE
if(stat & BROKEN)
to_chat(user, "<span class='warning'>The slot machine is broken!</span>")
return FALSE
if(working)
to_chat(user, "<span class='warning'>You need to wait until the machine stops spinning before you can play again!</span>")
return 0
return FALSE
if(balance < SPIN_PRICE)
to_chat(user, "<span class='warning'>Insufficient money to play!</span>")
return 0
return 1
return FALSE
return TRUE
/obj/machinery/computer/slot_machine/proc/toggle_reel_spin(value, delay = 0) //value is 1 or 0 aka on or off
for(var/list/reel in reels)
@@ -223,23 +259,25 @@
var/linelength = get_lines()
if(reels[1][2] + reels[2][2] + reels[3][2] + reels[4][2] + reels[5][2] == "[SEVEN][SEVEN][SEVEN][SEVEN][SEVEN]")
visible_message("<b>[src]</b> says, 'JACKPOT! You win [money] credits worth of coins!'")
visible_message("<b>[src]</b> says, 'JACKPOT! You win [money] credits!'")
priority_announce("Congratulations to [user ? user.real_name : usrname] for winning the jackpot at the slot machine in [get_area(src)]!")
jackpots += 1
balance += money - give_coins(JACKPOT)
balance += money - give_payout(JACKPOT)
money = 0
if(paymode == HOLOCHIP)
new /obj/item/holochip(loc,JACKPOT)
else
for(var/i = 0, i < 5, i++)
var/cointype = pick(subtypesof(/obj/item/coin))
cointype = pick(subtypesof(/obj/item/coin))
var/obj/item/coin/C = new cointype(loc)
random_step(C, 2, 50)
else if(linelength == 5)
visible_message("<b>[src]</b> says, 'Big Winner! You win a thousand credits worth of coins!'")
visible_message("<b>[src]</b> says, 'Big Winner! You win a thousand credits!'")
give_money(BIG_PRIZE)
else if(linelength == 4)
visible_message("<b>[src]</b> says, 'Winner! You win four hundred credits worth of coins!'")
visible_message("<b>[src]</b> says, 'Winner! You win four hundred credits!'")
give_money(SMALL_PRIZE)
else if(linelength == 3)
@@ -271,12 +309,15 @@
/obj/machinery/computer/slot_machine/proc/give_money(amount)
var/amount_to_give = money >= amount ? amount : money
var/surplus = amount_to_give - give_coins(amount_to_give)
var/surplus = amount_to_give - give_payout(amount_to_give)
money = max(0, money - amount)
balance += surplus
/obj/machinery/computer/slot_machine/proc/give_coins(amount)
var/cointype = obj_flags & EMAGGED ? /obj/item/coin/iron : /obj/item/coin/silver
/obj/machinery/computer/slot_machine/proc/give_payout(amount)
if(paymode == HOLOCHIP)
cointype = /obj/item/holochip
else
cointype = obj_flags & EMAGGED ? /obj/item/coin/iron : /obj/item/coin/silver
if(!(obj_flags & EMAGGED))
amount = dispense(amount, cointype, null, 0)
@@ -288,22 +329,25 @@
return amount
/obj/machinery/computer/slot_machine/proc/dispense(amount = 0, cointype = /obj/item/coin/silver, mob/living/target, throwit = FALSE)
var/value = GLOB.coin_values[cointype] || GLOB.coin_values[/obj/item/coin/iron]
INVOKE_ASYNC(src, .proc/become_rich, amount, value, cointype, target, throwit)
return amount % value
/obj/machinery/computer/slot_machine/proc/dispense(amount = 0, cointype = /obj/item/coin/silver, mob/living/target, throwit = 0)
if(paymode == HOLOCHIP)
var/obj/item/holochip/H = new /obj/item/holochip(loc,amount)
/obj/machinery/computer/slot_machine/proc/become_rich(amount, value, cointype = /obj/item/coin/silver, mob/living/target, throwit = FALSE)
if(throwit && target)
H.throw_at(target, 3, 10)
else
var/value = coinvalues["[cointype]"]
if(value <= 0)
return
while(amount >= value && !QDELETED(src))
CRASH("Coin value of zero, refusing to payout in dispenser")
while(amount >= value)
var/obj/item/coin/C = new cointype(loc) //DOUBLE THE PAIN
amount -= value
if(throwit && target)
C.throw_at(target, 3, 10)
else
random_step(C, 2, 40)
CHECK_TICK
return amount
#undef SEVEN
#undef SPIN_TIME
@@ -311,3 +355,5 @@
#undef BIG_PRIZE
#undef SMALL_PRIZE
#undef SPIN_PRICE
#undef HOLOCHIP
#undef COIN

View File

@@ -53,6 +53,7 @@
return 0
/obj/effect/acid/Crossed(AM as mob|obj)
. = ..()
if(isliving(AM))
var/mob/living/L = AM
if(L.movement_type & FLYING)

View File

@@ -138,7 +138,7 @@
/obj/effect/anomaly/grav/high/Initialize(mapload, new_lifespan)
. = ..()
setup_grav_field()
INVOKE_ASYNC(src, .proc/setup_grav_field)
/obj/effect/anomaly/grav/high/proc/setup_grav_field()
grav_field = make_field(/datum/proximity_monitor/advanced/gravity, list("current_range" = 7, "host" = src, "gravity_value" = rand(0,3)))

View File

@@ -65,4 +65,5 @@
/obj/effect/decal/cleanable/oil/slippery
/obj/effect/decal/cleanable/oil/slippery/Initialize()
. = ..()
AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE))

View File

@@ -5,6 +5,7 @@
var/list/checkers //list of /obj/effect/abstract/proximity_checkers
var/current_range
var/ignore_if_not_on_turf //don't check turfs in range if the host's loc isn't a turf
var/wire = FALSE
/datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE)
checkers = list()
@@ -35,6 +36,8 @@
return ..()
/datum/proximity_monitor/proc/HandleMove()
SIGNAL_HANDLER
var/atom/_host = host
var/atom/new_host_loc = _host.loc
if(last_host_loc != new_host_loc)
@@ -58,6 +61,8 @@
var/atom/_host = host
var/atom/loc_to_use = ignore_if_not_on_turf ? _host.loc : get_turf(_host)
if(wire && !isturf(loc_to_use)) //it makes assemblies attached on wires work
loc_to_use = get_turf(loc_to_use)
if(!isturf(loc_to_use)) //only check the host's loc
if(range)
var/obj/effect/abstract/proximity_checker/pc
@@ -109,4 +114,5 @@
/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM)
set waitfor = FALSE
monitor?.hasprox_receiver.HasProximity(AM)
. = ..()
monitor?.hasprox_receiver?.HasProximity(AM)

View File

@@ -170,6 +170,7 @@
/obj/item/clothing/under/rank/civilian/mime/sexy)
/obj/effect/spawner/bundle/crate/Initialize(mapload)
SHOULD_CALL_PARENT(FALSE)
if(items && items.len)
var/turf/T = get_turf(src)
var/obj/structure/closet/LC = locate(/obj/structure/closet) in T

View File

@@ -84,6 +84,7 @@
/obj/item/grenade/plastic/Crossed(atom/movable/AM)
if(nadeassembly)
nadeassembly.Crossed(AM)
. = ..()
/obj/item/grenade/plastic/on_found(mob/finder)
if(nadeassembly)

View File

@@ -447,6 +447,7 @@ GLOBAL_LIST_INIT(valid_plushie_paths, valid_plushie_paths())
can_random_spawn = FALSE
/obj/item/toy/plush/random/Initialize()
SHOULD_CALL_PARENT(FALSE)
var/newtype
var/list/snowflake_list = CONFIG_GET(keyed_list/snowflake_plushies)

View File

@@ -134,11 +134,10 @@
/obj/item/pressure_plate/hologrid/Crossed(atom/movable/AM)
. = ..()
if(trigger_item && istype(AM, specific_item) && !claimed)
AM.anchored = TRUE
AM.set_anchored(TRUE)
flick("laserbox_burn", AM)
trigger()
sleep(15)
qdel(AM)
QDEL_IN(AM, 15)
// snowflake code until undertile elements
/obj/item/pressure_plate/hologrid/hide()

View File

@@ -65,7 +65,7 @@
if(merge)
for(var/obj/item/stack/S in loc)
if(S.merge_type == merge_type)
merge(S)
INVOKE_ASYNC(src, .proc/merge, S)
var/list/temp_recipes = get_main_recipes()
recipes = temp_recipes.Copy()
if(material_type)

View File

@@ -531,6 +531,7 @@
pop_burst()
/obj/item/toy/snappop/Crossed(H as mob|obj)
. = ..()
if(ishuman(H) || issilicon(H)) //i guess carp and shit shouldn't set them off
var/mob/living/carbon/M = H
if(issilicon(H) || M.m_intent == MOVE_INTENT_RUN)

View File

@@ -269,13 +269,13 @@
UnregisterSignal(source, COMSIG_MOVABLE_MOVED)
/obj/structure/table/rolling/Moved(atom/OldLoc, Dir)
. = ..()
for(var/mob/M in OldLoc.contents)//Kidnap everyone on top
M.forceMove(loc)
for(var/x in attached_items)
var/atom/movable/AM = x
if(!AM.Move(loc))
RemoveItemFromTable(AM, AM.loc)
return TRUE
/*
* Glass tables

View File

@@ -56,6 +56,7 @@
animate(src, alpha = initial(alpha), time = time_between_triggers)
/obj/structure/trap/Crossed(atom/movable/AM)
. = ..()
if(last_trigger + time_between_triggers > world.time)
return
// Don't want the traps triggered by sparks, ghosts or projectiles.
@@ -67,6 +68,7 @@
return
if(M.anti_magic_check())
flare()
return
if(charges <= 0)
return
flare()

View File

@@ -24,7 +24,13 @@
//This is used to optimize the map loader
return
/**
* Space Initialize
*
* Doesn't call parent, see [/atom/proc/Initialize]
*/
/turf/open/space/Initialize()
SHOULD_CALL_PARENT(FALSE)
icon_state = SPACE_ICON_STATE
air = space_gas
update_air_ref()
@@ -35,6 +41,15 @@
stack_trace("Warning: [src]([type]) initialized multiple times!")
flags_1 |= INITIALIZED_1
// if (length(smoothing_groups))
// sortTim(smoothing_groups) //In case it's not properly ordered, let's avoid duplicate entries with the same values.
// SET_BITFLAG_LIST(smoothing_groups)
// if (length(canSmoothWith))
// sortTim(canSmoothWith)
// if(canSmoothWith[length(canSmoothWith)] > MAX_S_TURF) //If the last element is higher than the maximum turf-only value, then it must scan turf contents for smoothing targets.
// smoothing_flags |= SMOOTH_OBJ
// SET_BITFLAG_LIST(canSmoothWith)
var/area/A = loc
if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A))
add_overlay(/obj/effect/fullbright)
@@ -48,6 +63,13 @@
if (opacity)
has_opaque_atom = TRUE
var/turf/T = SSmapping.get_turf_above(src)
if(T)
T.multiz_turf_new(src, DOWN)
T = SSmapping.get_turf_below(src)
if(T)
T.multiz_turf_new(src, UP)
ComponentInitialize()
return INITIALIZE_HINT_NORMAL
@@ -73,6 +95,10 @@
/turf/open/space/Assimilate_Air()
return
//IT SHOULD RETURN NULL YOU MONKEY, WHY IN TARNATION WHAT THE FUCKING FUCK
/turf/open/space/remove_air(amount)
return null
/turf/open/space/proc/update_starlight()
if(CONFIG_GET(flag/starlight))
for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm
@@ -89,9 +115,8 @@
/turf/open/space/proc/CanBuildHere()
return TRUE
/turf/open/space/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube)
if(lube & FLYING_DOESNT_HELP)
return ..()
/turf/open/space/handle_slip()
return // no lube bullshit, this is space
/turf/open/space/attackby(obj/item/C, mob/user, params)
..()
@@ -106,15 +131,16 @@
return
if(L)
if(R.use(1))
qdel(L)
to_chat(user, "<span class='notice'>You construct a catwalk.</span>")
playsound(src, 'sound/weapons/genhit.ogg', 50, 1)
playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE)
new/obj/structure/lattice/catwalk(src)
else
to_chat(user, "<span class='warning'>You need two rods to build a catwalk!</span>")
return
if(R.use(1))
to_chat(user, "<span class='notice'>You construct a lattice.</span>")
playsound(src, 'sound/weapons/genhit.ogg', 50, 1)
playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE)
ReplaceWithLattice()
else
to_chat(user, "<span class='warning'>You need one rod to build a lattice.</span>")
@@ -125,7 +151,7 @@
var/obj/item/stack/tile/plasteel/S = C
if(S.use(1))
qdel(L)
playsound(src, 'sound/weapons/genhit.ogg', 50, 1)
playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE)
to_chat(user, "<span class='notice'>You build a floor.</span>")
PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
else

View File

@@ -1,8 +1,11 @@
GLOBAL_LIST_EMPTY(station_turfs)
/// Any floor or wall. What makes up the station and the rest of the map.
/turf
icon = 'icons/turf/floors.dmi'
level = 1
vis_flags = VIS_INHERIT_PLANE|VIS_INHERIT_ID //when this be added to vis_contents of something it inherit something.plane and be associatet with something on clicking,
//important for visualisation of turf in openspace and interraction with openspace that show you turf.
flags_1 = CAN_BE_DIRTY_1
vis_flags = VIS_INHERIT_ID|VIS_INHERIT_PLANE // Important for interaction with and visualization of openspace.
luminosity = 1
var/intact = 1
@@ -19,8 +22,6 @@
var/blocks_air = FALSE
flags_1 = CAN_BE_DIRTY_1
var/list/image/blueprint_data //for the station blueprints, images of objects eg: pipes
var/explosion_level = 0 //for preventing explosion dodging
@@ -41,7 +42,13 @@
return FALSE
. = ..()
/**
* Turf Initialize
*
* Doesn't call parent, see [/atom/proc/Initialize]
*/
/turf/Initialize(mapload)
SHOULD_CALL_PARENT(FALSE)
if(flags_1 & INITIALIZED_1)
stack_trace("Warning: [src]([type]) initialized multiple times!")
flags_1 |= INITIALIZED_1
@@ -49,7 +56,7 @@
// by default, vis_contents is inherited from the turf that was here before
vis_contents.Cut()
if(color)
if(color) // is this being used? This is here because parent isn't being called
add_atom_colour(color, FIXED_COLOUR_PRIORITY)
assemble_baseturfs()
@@ -57,6 +64,7 @@
levelupdate()
if(smooth)
queue_smooth(src)
visibilityChanged()
for(var/atom/movable/AM in src)
@@ -76,11 +84,10 @@
var/turf/T = SSmapping.get_turf_above(src)
if(T)
T.multiz_turf_new(src, DOWN)
SEND_SIGNAL(T, COMSIG_TURF_MULTIZ_NEW, src, DOWN)
T = SSmapping.get_turf_below(src)
if(T)
T.multiz_turf_new(src, UP)
SEND_SIGNAL(T, COMSIG_TURF_MULTIZ_NEW, src, UP)
if (opacity)
has_opaque_atom = TRUE
@@ -112,8 +119,6 @@
var/turf/B = new world.turf(src)
for(var/A in B.contents)
qdel(A)
for(var/I in B.vars)
B.vars[I] = null
return
SSair.remove_from_active(src)
visibilityChanged()
@@ -122,12 +127,14 @@
requires_activation = FALSE
..()
/turf/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
/turf/on_attack_hand(mob/user)
user.Move_Pulled(src)
/turf/proc/multiz_turf_del(turf/T, dir)
// SEND_SIGNAL(src, COMSIG_TURF_MULTIZ_DEL, T, dir)
/turf/proc/multiz_turf_new(turf/T, dir)
SEND_SIGNAL(src, COMSIG_TURF_MULTIZ_NEW, T, dir)
//zPassIn doesn't necessarily pass an atom!
//direction is direction of travel of air
@@ -158,13 +165,14 @@
prev_turf.visible_message("<span class='danger'>[mov_name] falls through [prev_turf]!</span>")
if(flags & FALL_INTERCEPTED)
return
if(zFall(A, ++levels))
if(zFall(A, levels + 1))
return FALSE
A.visible_message("<span class='danger'>[A] crashes into [src]!</span>")
A.onZImpact(src, levels)
return TRUE
/turf/proc/can_zFall(atom/movable/A, levels = 1, turf/target)
SHOULD_BE_PURE(TRUE)
return zPassOut(A, DOWN, target) && target.zPassIn(A, DOWN, src)
/turf/proc/zFall(atom/movable/A, levels = 1, force = FALSE)
@@ -217,49 +225,54 @@
stack_trace("Non movable passed to turf CanPass : [mover]")
return FALSE
//There's a lot of QDELETED() calls here if someone can figure out how to optimize this but not runtime when something gets deleted by a Bump/CanPass/Cross call, lemme know or go ahead and fix this mess - kevinz000
/turf/Enter(atom/movable/mover, atom/oldloc)
// Do not call ..()
// Byond's default turf/Enter() doesn't have the behaviour we want with Bump()
// By default byond will call Bump() on the first dense object in contents
// Here's hoping it doesn't stay like this for years before we finish conversion to step_
var/atom/firstbump
if(!CanPass(mover, src))
firstbump = src
else
var/canPassSelf = CanPass(mover, src)
if(canPassSelf || (mover.movement_type & UNSTOPPABLE))
for(var/i in contents)
if(QDELETED(mover))
return FALSE //We were deleted, do not attempt to proceed with movement.
if(i == mover || i == mover.loc) // Multi tile objects and moving out of other objects
continue
if(QDELETED(mover))
break
var/atom/movable/thing = i
if(!thing.Cross(mover))
if(CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
if(QDELETED(mover)) //Mover deleted from Cross/CanPass, do not proceed.
return FALSE
if((mover.movement_type & UNSTOPPABLE))
mover.Bump(thing)
continue
else
if(!firstbump || ((thing.layer > firstbump.layer || thing.flags_1 & ON_BORDER_1) && !(firstbump.flags_1 & ON_BORDER_1)))
firstbump = thing
if(QDELETED(mover)) //Mover deleted from Cross/CanPass/Bump, do not proceed.
return FALSE
if(!canPassSelf) //Even if mover is unstoppable they need to bump us.
firstbump = src
if(firstbump)
if(!QDELETED(mover))
mover.Bump(firstbump)
return CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE)
return (mover.movement_type & UNSTOPPABLE)
return TRUE
/turf/Exit(atom/movable/mover, atom/newloc)
. = ..()
if(!.)
if(!. || QDELETED(mover))
return FALSE
for(var/i in contents)
if(QDELETED(mover))
break
if(i == mover)
continue
var/atom/movable/thing = i
if(!thing.Uncross(mover, newloc))
if(thing.flags_1 & ON_BORDER_1)
mover.Bump(thing)
if(!CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
if(!(mover.movement_type & UNSTOPPABLE))
return FALSE
if(QDELETED(mover))
return FALSE //We were deleted.
/turf/Entered(atom/movable/AM)
..()
@@ -271,6 +284,7 @@
has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case.
reconsider_lights()
/turf/open/Entered(atom/movable/AM)
..()
//melting
@@ -278,7 +292,6 @@
var/obj/O = AM
if(O.obj_flags & FROZEN)
O.make_unfrozen()
if(!AM.zfalling)
zFall(AM)
@@ -336,14 +349,13 @@
/turf/proc/levelupdate()
for(var/obj/O in src)
if(O.level == 1 && (O.flags_1 & INITIALIZED_1))
O.hide(src.intact)
if(O.flags_1 & INITIALIZED_1)
// SEND_SIGNAL(O, COMSIG_OBJ_HIDE, intact)
O.hide(intact)
// override for space turfs, since they should never hide anything
/turf/open/space/levelupdate()
for(var/obj/O in src)
if(O.level == 1 && (O.flags_1 & INITIALIZED_1))
O.hide(0)
return
// Removes all signs of lattice on the pos of the turf -Donkieyo
/turf/proc/RemoveLattice()
@@ -368,13 +380,13 @@
if(.)
return
if(length(src_object.contents()))
to_chat(user, "<span class='notice'>You start dumping out the contents...</span>")
if(!do_after(user,20,target=src_object.parent))
to_chat(usr, "<span class='notice'>You start dumping out the contents...</span>")
if(!do_after(usr,20,target=src_object.parent))
return FALSE
var/list/things = src_object.contents()
var/datum/progressbar/progress = new(user, things.len, src)
while (do_after(user, 10, TRUE, src, FALSE, CALLBACK(src_object, /datum/component/storage.proc/mass_remove_from_storage, src, things, progress)))
while (do_after(usr, 1 SECONDS, TRUE, src, FALSE, CALLBACK(src_object, /datum/component/storage.proc/mass_remove_from_storage, src, things, progress)))
stoplag(1)
qdel(progress)
@@ -494,10 +506,8 @@
I.loc = src
I.setDir(AM.dir)
I.alpha = 128
LAZYADD(blueprint_data, I)
/turf/proc/add_blueprints_preround(atom/movable/AM)
if(!SSticker.HasRoundStarted())
add_blueprints(AM)
@@ -531,7 +541,7 @@
if(!forced)
return
if(has_gravity(src))
playsound(src, "bodyfall", 50, 1)
playsound(src, "bodyfall", 50, TRUE)
faller.drop_all_held_items()
/turf/proc/photograph(limit=20)

View File

@@ -13,8 +13,9 @@
var/nightime_duration = 900 //15 Minutes
/obj/effect/sunlight/Initialize()
countdown()
hud_tick()
. = ..()
INVOKE_ASYNC(src, .proc/countdown)
INVOKE_ASYNC(src, .proc/hud_tick)
/obj/effect/sunlight/proc/countdown()
set waitfor = FALSE

View File

@@ -15,3 +15,5 @@
audible_message("<i>*click*</i>")
playsound(src, 'sound/items/screwdriver2.ogg', 50, TRUE)
activate()
. = ..()

View File

@@ -8,7 +8,7 @@
alpha = 75
/obj/structure/destructible/clockwork/trap/trigger/pressure_sensor/mech/Crossed(atom/movable/AM)
. = ..()
if(!istype(AM,/obj/mecha/))
return

View File

@@ -21,3 +21,5 @@
if(isliving(AM) && opacity)
var/mob/living/L = AM
L.adjust_fire_stacks(-1) //It's wet!
return
. = ..()

View File

@@ -62,6 +62,7 @@
master.update_icon()
/obj/item/assembly_holder/Crossed(atom/movable/AM as mob|obj)
. = ..()
if(a_left)
a_left.Crossed(AM)
if(a_right)

View File

@@ -49,6 +49,7 @@
SSair.add_to_active(T)
return ..()
/// Function for Extools Atmos
/turf/proc/update_air_ref()
/////////////////GAS MIXTURE PROCS///////////////////

View File

@@ -7,6 +7,8 @@
#define AMMO_DROP_LIFETIME 300
#define CTF_REQUIRED_PLAYERS 4
/obj/item/ctf
name = "banner"
icon = 'icons/obj/items_and_weapons.dmi'
@@ -16,13 +18,13 @@
righthand_file = 'icons/mob/inhands/equipment/banners_righthand.dmi'
desc = "A banner with Nanotrasen's logo on it."
slowdown = 2
item_flags = SLOWS_WHILE_IN_HAND
throw_speed = 0
throw_range = 1
force = 200
armour_penetration = 1000
resistance_flags = INDESTRUCTIBLE
anchored = TRUE
item_flags = SLOWS_WHILE_IN_HAND
var/team = WHITE_TEAM
var/reset_cooldown = 0
var/anyonecanpickup = TRUE
@@ -53,12 +55,13 @@
to_chat(M, "<span class='userdanger'>\The [src] has been returned to base!</span>")
STOP_PROCESSING(SSobj, src)
/obj/item/ctf/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/ctf/on_attack_hand(mob/living/user)
if(!is_ctf_target(user) && !anyonecanpickup)
to_chat(user, "Non players shouldn't be moving the flag!")
to_chat(user, "<span class='warning'>Non-players shouldn't be moving the flag!</span>")
return
if(team in user.faction)
to_chat(user, "You can't move your own flag!")
to_chat(user, "<span class='warning'>You can't move your own flag!</span>")
return
if(loc == user)
if(!user.dropItemToGround(src))
@@ -68,7 +71,7 @@
if(!user.put_in_active_hand(src))
dropped(user)
return
user.anchored = TRUE
user.set_anchored(TRUE)
user.status_flags &= ~CANPUSH
for(var/mob/M in GLOB.player_list)
var/area/mob_area = get_area(M)
@@ -79,7 +82,7 @@
/obj/item/ctf/dropped(mob/user)
..()
user.anchored = FALSE
user.set_anchored(FALSE)
user.status_flags |= CANPUSH
reset_cooldown = world.time + 200 //20 seconds
START_PROCESSING(SSobj, src)
@@ -172,20 +175,20 @@
GLOB.poi_list.Remove(src)
..()
/obj/machinery/capture_the_flag/process()
/obj/machinery/capture_the_flag/process(delta_time)
for(var/i in spawned_mobs)
if(!i)
spawned_mobs -= i
continue
// Anyone in crit, automatically reap
var/mob/living/M = i
if(M.InCritical() || M.stat == DEAD)
ctf_dust_old(M)
var/mob/living/living_participant = i
if(living_participant.InCritical() || living_participant.stat == DEAD)
ctf_dust_old(living_participant)
else
// The changes that you've been hit with no shield but not
// instantly critted are low, but have some healing.
M.adjustBruteLoss(-5)
M.adjustFireLoss(-5)
living_participant.adjustBruteLoss(-2.5 * delta_time)
living_participant.adjustFireLoss(-2.5 * delta_time)
/obj/machinery/capture_the_flag/red
name = "Red CTF Controller"
@@ -212,6 +215,10 @@
toggle_all_ctf(user)
return
// if(!(GLOB.ghost_role_flags & GHOSTROLE_MINIGAME))
// to_chat(user, "<span class='warning'>CTF has been temporarily disabled by admins.</span>")
// return
people_who_want_to_play |= user.ckey
var/num = people_who_want_to_play.len
var/remaining = CTF_REQUIRED_PLAYERS - num
@@ -227,7 +234,7 @@
return
if(user.ckey in team_members)
if(user.ckey in recently_dead_ckeys)
to_chat(user, "It must be more than [DisplayTimeText(respawn_cooldown)] from your last death to respawn!")
to_chat(user, "<span class='warning'>It must be more than [DisplayTimeText(respawn_cooldown)] from your last death to respawn!</span>")
return
var/client/new_team_member = user.client
if(user.mind && user.mind.current)
@@ -239,10 +246,10 @@
if(CTF == src || CTF.ctf_enabled == FALSE)
continue
if(user.ckey in CTF.team_members)
to_chat(user, "No switching teams while the round is going!")
to_chat(user, "<span class='warning'>No switching teams while the round is going!</span>")
return
if(CTF.team_members.len < src.team_members.len)
to_chat(user, "[src.team] has more team members than [CTF.team]. Try joining [CTF.team] team to even things up.")
to_chat(user, "<span class='warning'>[src.team] has more team members than [CTF.team]! Try joining [CTF.team] team to even things up.</span>")
return
team_members |= user.ckey
var/client/new_team_member = user.client
@@ -258,7 +265,7 @@
addtimer(CALLBACK(src, .proc/clear_cooldown, body.ckey), respawn_cooldown, TIMER_UNIQUE)
body.dust()
/obj/machinery/capture_the_flag/proc/clear_cooldown(var/ckey)
/obj/machinery/capture_the_flag/proc/clear_cooldown(ckey)
recently_dead_ckeys -= ckey
/obj/machinery/capture_the_flag/proc/spawn_team_member(client/new_team_member)
@@ -270,7 +277,7 @@
M.equipOutfit(ctf_gear)
M.dna.species.punchdamagehigh = 25
M.dna.species.punchdamagelow = 25
M.AddElement(/datum/element/ghost_role_eligibility)
M.AddElement(/datum/element/ghost_role_eligibility) //??
spawned_mobs += M
/obj/machinery/capture_the_flag/Topic(href, href_list)
@@ -293,14 +300,15 @@
victory()
/obj/machinery/capture_the_flag/proc/victory()
for(var/mob/M in GLOB.mob_list)
var/area/mob_area = get_area(M)
for(var/mob/_competitor in GLOB.mob_living_list)
var/mob/living/competitor = _competitor
var/area/mob_area = get_area(competitor)
if(istype(mob_area, /area/ctf))
to_chat(M, "<span class='narsie [team_span]'>[team] team wins!</span>")
to_chat(M, "<span class='userdanger'>Teams have been cleared. Click on the machines to vote to begin another round.</span>")
for(var/obj/item/ctf/W in M)
M.dropItemToGround(W)
M.dust()
to_chat(competitor, "<span class='narsie [team_span]'>[team] team wins!</span>")
to_chat(competitor, "<span class='userdanger'>Teams have been cleared. Click on the machines to vote to begin another round.</span>")
for(var/obj/item/ctf/W in competitor)
competitor.dropItemToGround(W)
competitor.dust()
for(var/obj/machinery/control_point/control in GLOB.machines)
control.icon_state = "dominator"
control.controlling = null
@@ -328,7 +336,7 @@
dead_barricades.Cut()
notify_ghosts("[name] has been activated!", enter_link="<a href=?src=[REF(src)];join=1>(Click to join the [team] team!)</a> or click on the controller directly!", source = src, action=NOTIFY_ATTACK)
notify_ghosts("[name] has been activated!", enter_link="<a href=?src=[REF(src)];join=1>(Click to join the [team] team!)</a> or click on the controller directly!", source = src, action=NOTIFY_ATTACK, header = "CTF has been activated")
if(!arena_reset)
reset_the_arena()
@@ -355,10 +363,10 @@
ctf_enabled = FALSE
arena_reset = FALSE
var/area/A = get_area(src)
for(var/i in GLOB.mob_list)
var/mob/M = i
if((get_area(A) == A) && (M.ckey in team_members))
M.dust()
for(var/_competitor in GLOB.mob_living_list)
var/mob/living/competitor = _competitor
if((get_area(A) == A) && (competitor.ckey in team_members))
competitor.dust()
team_members.Cut()
spawned_mobs.Cut()
recently_dead_ckeys.Cut()
@@ -375,18 +383,18 @@
CTF.ctf_gear = initial(ctf_gear)
CTF.respawn_cooldown = DEFAULT_RESPAWN
/proc/ctf_floor_vanish(atom/target)
if(isturf(target.loc))
qdel(target)
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf
desc = "This looks like it could really hurt in melee."
force = 75
mag_type = /obj/item/ammo_box/magazine/m50/ctf
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped(mob/user)
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped()
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
addtimer(CALLBACK(src, .proc/floor_vanish), 1)
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/obj/item/ammo_box/magazine/m50/ctf
ammo_type = /obj/item/ammo_casing/a50/ctf
@@ -400,6 +408,7 @@
/obj/item/projectile/bullet/ctf/prehit(atom/target)
if(is_ctf_target(target))
damage = 60
return //PROJECTILE_PIERCE_NONE /// hey uhh don't hit anyone behind them
. = ..()
/obj/item/gun/ballistic/automatic/laser/ctf
@@ -407,16 +416,24 @@
desc = "This looks like it could really hurt in melee."
force = 50
/obj/item/gun/ballistic/automatic/laser/ctf/dropped(mob/user)
/obj/item/gun/ballistic/automatic/laser/ctf/dropped()
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
addtimer(CALLBACK(src, .proc/floor_vanish), 1)
/obj/item/gun/ballistic/automatic/laser/ctf/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/obj/item/ammo_box/magazine/recharge/ctf
ammo_type = /obj/item/ammo_casing/caseless/laser/ctf
/obj/item/ammo_box/magazine/recharge/ctf/dropped(mob/user)
/obj/item/ammo_box/magazine/recharge/ctf/dropped()
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
addtimer(CALLBACK(src, .proc/floor_vanish), 1)
/obj/item/ammo_box/magazine/recharge/ctf/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/obj/item/ammo_casing/caseless/laser/ctf
projectile_type = /obj/item/projectile/beam/ctf
@@ -428,15 +445,16 @@
/obj/item/projectile/beam/ctf/prehit(atom/target)
if(is_ctf_target(target))
damage = 150
return //PROJECTILE_PIERCE_NONE /// hey uhhh don't hit anyone behind them
. = ..()
/proc/is_ctf_target(atom/target)
. = FALSE
if(istype(target, /obj/structure/barricade/security/ctf))
. = TRUE
if(isliving(target))
var/mob/living/H = target
if((RED_TEAM in H.faction) || (BLUE_TEAM in H.faction))
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/shielded/ctf))
. = TRUE
// RED TEAM GUNS
@@ -482,7 +500,11 @@
/obj/item/claymore/ctf/dropped(mob/user)
. = ..()
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
addtimer(CALLBACK(src, .proc/floor_vanish), 1)
/obj/item/claymore/ctf/proc/floor_vanish()
if(isturf(loc))
qdel(src)
/datum/outfit/ctf
name = "CTF"
@@ -491,27 +513,28 @@
suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf
toggle_helmet = FALSE // see the whites of their eyes
shoes = /obj/item/clothing/shoes/combat
gloves = /obj/item/clothing/gloves/tackler/combat
gloves = /obj/item/clothing/gloves/combat
id = /obj/item/card/id/away
belt = /obj/item/gun/ballistic/automatic/pistol/deagle/ctf
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf
back = /obj/item/claymore/ctf
/datum/outfit/ctf/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
/datum/outfit/ctf/post_equip(mob/living/carbon/human/H, visualsOnly=FALSE)
if(visualsOnly)
return
var/list/no_drops = list()
var/obj/item/card/id/W = H.wear_id
no_drops += W
W.registered_name = H.real_name
W.update_label(W.registered_name, W.assignment)
W.update_label()
// The shielded hardsuit is already TRAIT_NODROP
no_drops += H.get_item_by_slot(SLOT_GLOVES)
no_drops += H.get_item_by_slot(SLOT_SHOES)
no_drops += H.get_item_by_slot(SLOT_W_UNIFORM)
no_drops += H.get_item_by_slot(SLOT_EARS)
no_drops += H.get_item_by_slot(ITEM_SLOT_OCLOTHING)
no_drops += H.get_item_by_slot(ITEM_SLOT_GLOVES)
no_drops += H.get_item_by_slot(ITEM_SLOT_FEET)
no_drops += H.get_item_by_slot(ITEM_SLOT_ICLOTHING)
no_drops += H.get_item_by_slot(ITEM_SLOT_EARS)
for(var/i in no_drops)
var/obj/item/I = i
ADD_TRAIT(I, TRAIT_NODROP, CAPTURE_THE_FLAG_TRAIT)
@@ -525,6 +548,7 @@
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/red
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red
id = /obj/item/card/id/syndicate_command //it's red
/datum/outfit/ctf/red/instagib
r_hand = /obj/item/gun/energy/laser/instakill/red
@@ -535,12 +559,13 @@
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/blue
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue
id = /obj/item/card/id/centcom //it's blue
/datum/outfit/ctf/blue/instagib
r_hand = /obj/item/gun/energy/laser/instakill/blue
shoes = /obj/item/clothing/shoes/jackboots/fast
/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
/datum/outfit/ctf/red/post_equip(mob/living/carbon/human/H)
..()
var/obj/item/radio/R = H.ears
R.set_frequency(FREQ_CTF_RED)
@@ -548,7 +573,7 @@
R.independent = TRUE
H.dna.species.stunmod = 0
/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
/datum/outfit/ctf/blue/post_equip(mob/living/carbon/human/H)
..()
var/obj/item/radio/R = H.ears
R.set_frequency(FREQ_CTF_BLUE)
@@ -595,6 +620,10 @@
/obj/structure/barricade/security/ctf/make_debris()
new /obj/effect/ctf/dead_barricade(get_turf(src))
/obj/structure/table/reinforced/ctf
resistance_flags = INDESTRUCTIBLE
flags_1 = NODECONSTRUCT_1
/obj/effect/ctf
density = FALSE
anchored = TRUE
@@ -617,10 +646,11 @@
QDEL_IN(src, AMMO_DROP_LIFETIME)
/obj/effect/ctf/ammo/Crossed(atom/movable/AM)
. = ..()
reload(AM)
/obj/effect/ctf/ammo/Bump(atom/movable/AM)
reload(AM)
/obj/effect/ctf/ammo/Bump(atom/A)
reload(A)
/obj/effect/ctf/ammo/Bumped(atom/movable/AM)
reload(AM)
@@ -636,7 +666,7 @@
qdel(G)
O.equip(M)
to_chat(M, "<span class='notice'>Ammunition reloaded!</span>")
playsound(get_turf(M), 'sound/weapons/shotgunpump.ogg', 50, 1, -1)
playsound(get_turf(M), 'sound/weapons/shotgunpump.ogg', 50, TRUE, -1)
qdel(src)
break
@@ -667,18 +697,18 @@
resistance_flags = INDESTRUCTIBLE
var/obj/machinery/capture_the_flag/controlling
var/team = "none"
var/point_rate = 1
var/point_rate = 0.5
/obj/machinery/control_point/process()
/obj/machinery/control_point/process(delta_time)
if(controlling)
controlling.control_points += point_rate
controlling.control_points += point_rate * delta_time
if(controlling.control_points >= controlling.control_points_to_win)
controlling.victory()
/obj/machinery/control_point/attackby(mob/user, params)
capture(user)
/obj/machinery/control_point/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
/obj/machinery/control_point/on_attack_hand(mob/user)
capture(user)
/obj/machinery/control_point/proc/capture(mob/user)

View File

@@ -66,7 +66,7 @@
/obj/effect/mob_spawn/Initialize(mapload)
. = ..()
if(instant || (roundstart && (mapload || (SSticker && SSticker.current_state > GAME_STATE_SETTING_UP))))
create()
INVOKE_ASYNC(src, .proc/create)
else if(ghost_usable)
GLOB.poi_list |= src
LAZYADD(GLOB.mob_spawners[job_description ? job_description : name], src)

View File

@@ -132,6 +132,7 @@
var/triggered = 0
/obj/effect/meatgrinder/Crossed(atom/movable/AM)
. = ..()
Bumped(AM)
/obj/effect/meatgrinder/Bumped(atom/movable/AM)

View File

@@ -340,6 +340,7 @@
playsound(src.loc, 'sound/items/welder.ogg', 100, TRUE)
/obj/structure/spacevine/Crossed(atom/movable/AM)
. = ..()
if(!isliving(AM))
return
for(var/datum/spacevine_mutation/SM in mutations)

View File

@@ -99,7 +99,7 @@
new reward(get_turf(src))
/mob/living/carbon/human/dummy/travelling_trader/Initialize()
..()
. = ..() // return a hint you fuck
add_atom_colour("#570d6b", FIXED_COLOUR_PRIORITY) //make them purple (otherworldly!)
set_light(1, -0.7, "#AAD84B")
ADD_TRAIT(src,TRAIT_PIERCEIMMUNE, "trader_pierce_immune") //don't let people take their blood

View File

@@ -16,7 +16,7 @@
if(!F.check_variables() && !override_checks)
QDEL_NULL(F)
if(start_field && (F || override_checks))
F.Initialize()
F.begin_field()
return F
/datum/proximity_monitor/advanced
@@ -78,11 +78,11 @@
/datum/proximity_monitor/advanced/proc/process_edge_turf(turf/T)
/datum/proximity_monitor/advanced/New()
/datum/proximity_monitor/advanced/New(atom/_host, range, _ignore_if_not_on_turf = TRUE)
if(requires_processing)
START_PROCESSING(SSfields, src)
/datum/proximity_monitor/advanced/proc/Initialize()
/datum/proximity_monitor/advanced/proc/begin_field()
setup_field()
post_setup_field()
@@ -154,7 +154,7 @@
var/atom/_host = host
var/atom/new_host_loc = _host.loc
if(last_host_loc != new_host_loc)
recalculate_field()
INVOKE_ASYNC(src, .proc/recalculate_field)
/datum/proximity_monitor/advanced/proc/post_setup_field()
@@ -302,7 +302,7 @@
/obj/item/multitool/field_debug/attack_self(mob/user)
operating = !operating
to_chat(user, "You turn [src] [operating? "on":"off"].")
to_chat(user, "<span class='notice'>You turn [src] [operating? "on":"off"].</span>")
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
if(!istype(current) && operating)
@@ -312,13 +312,15 @@
else if(!operating)
QDEL_NULL(current)
/obj/item/multitool/field_debug/dropped(mob/user)
/obj/item/multitool/field_debug/dropped()
. = ..()
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
/obj/item/multitool/field_debug/proc/on_mob_move()
SIGNAL_HANDLER
check_turf(get_turf(src))
/obj/item/multitool/field_debug/process()

View File

@@ -33,7 +33,7 @@
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()
INVOKE_ASYNC(src, .proc/timestop)
/obj/effect/timestop/Destroy()
qdel(chronofield)
@@ -42,7 +42,7 @@
/obj/effect/timestop/proc/timestop()
target = get_turf(src)
playsound(src, 'sound/magic/timeparadox2.ogg', 75, 1, -1)
playsound(src, 'sound/magic/timeparadox2.ogg', 75, TRUE, -1)
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)
@@ -112,6 +112,8 @@
unfreeze_turf(T)
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_atom(atom/movable/A)
SIGNAL_HANDLER
if(A.throwing)
unfreeze_throwing(A)
if(isliving(A))
@@ -128,12 +130,14 @@
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
@@ -160,7 +164,7 @@
/datum/proximity_monitor/advanced/timestop/process()
for(var/i in frozen_mobs)
var/mob/living/m = i
m.Stun(20, 1, 1)
m.Stun(20, ignore_canstun = TRUE)
/datum/proximity_monitor/advanced/timestop/setup_field_turf(turf/T)
for(var/i in T.contents)
@@ -168,6 +172,7 @@
freeze_turf(T)
return ..()
/datum/proximity_monitor/advanced/timestop/proc/freeze_projectile(obj/item/projectile/P)
P.paused = TRUE
@@ -176,7 +181,7 @@
/datum/proximity_monitor/advanced/timestop/proc/freeze_mob(mob/living/L)
frozen_mobs += L
L.Stun(20, 1, 1)
L.Stun(20, ignore_canstun = TRUE)
ADD_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT)
walk(L, 0) //stops them mid pathing even if they're stunimmune
if(isanimal(L))
@@ -187,7 +192,7 @@
H.LoseTarget()
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mob(mob/living/L)
L.AdjustStun(-20, 1, 1)
L.AdjustStun(-20, ignore_canstun = TRUE)
REMOVE_TRAIT(L, TRAIT_MUTE, TIMESTOP_TRAIT)
frozen_mobs -= L
if(isanimal(L))

View File

@@ -24,11 +24,12 @@
desc = "Get off my turf!"
/obj/effect/abstract/proximity_checker/advanced/field_turf/CanPass(atom/movable/AM, turf/target)
. = ..()
if(parent)
return parent.field_turf_canpass(AM, src, target)
return TRUE
/obj/effect/abstract/proximity_checker/advanced/field_turf/Crossed(atom/movable/AM)
. = ..()
if(parent)
return parent.field_turf_crossed(AM, src)
return TRUE
@@ -48,11 +49,12 @@
desc = "Edgy description here."
/obj/effect/abstract/proximity_checker/advanced/field_edge/CanPass(atom/movable/AM, turf/target)
. = ..()
if(parent)
return parent.field_edge_canpass(AM, src, target)
return TRUE
/obj/effect/abstract/proximity_checker/advanced/field_edge/Crossed(atom/movable/AM)
. = ..()
if(parent)
return parent.field_edge_crossed(AM, src)
return TRUE

View File

@@ -139,10 +139,11 @@ GLOBAL_LIST_INIT(hallucination_list, list(
Show()
/obj/effect/hallucination/simple/Moved(atom/OldLoc, Dir)
. = ..()
Show()
/obj/effect/hallucination/simple/Destroy()
if(target && target.client)
if(target?.client)
target.client.images.Remove(current_image)
active = FALSE
return ..()
@@ -1093,6 +1094,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
target.client.images += image
/obj/effect/hallucination/danger/lava/Crossed(atom/movable/AM)
. = ..()
if(AM == target)
target.adjustStaminaLoss(20)
new /datum/hallucination/fire(target)

View File

@@ -50,16 +50,18 @@
var/cached_z
/// I'm busy, don't move.
var/busy = FALSE
var/static/blacklisted_items = typecacheof(list(
/obj/effect,
/obj/belly,
/obj/mafia_game_board,
/obj/docking_port,
/obj/shapeshift_holder,
/obj/screen))
/obj/screen
))
/mob/living/simple_animal/jacq/Initialize()
..()
. = ..() //fuck you jacq, return a hint you shit
cached_z = z
poof()
@@ -158,23 +160,18 @@
return FALSE
/mob/living/simple_animal/jacq/proc/gender_check(mob/living/carbon/C)
var/gender = "lamb"
if(C)
if(C.gender == MALE)
gender = "laddie"
if(C.gender == FEMALE)
gender = "lassie"
return gender
. = "lamb"
switch(C)
if(MALE)
. = "laddie"
if(FEMALE)
. = "lassie"
//Ye wee bugger, gerrout of it. Ye've nae tae enjoy reading the code fer mae secrets like.
/mob/living/simple_animal/jacq/proc/chit_chat(mob/living/carbon/C)
//Very important
var/gender = gender_check(C)
if(C)
if(C.gender == MALE)
gender = "laddie"
if(C.gender == FEMALE)
gender = "lassie"
// it physicaly cannot fail*. Why is there a fucking dupe
if(!progression["[C.real_name]"] || !(progression["[C.real_name]"] & JACQ_HELLO))
visible_message("<b>[src]</b> smiles ominously at [C], <span class='spooky'>\"Well halo there [gender]! Ah'm Jacqueline, tae great Pumpqueen, great tae meet ye.\"</span>")

View File

@@ -578,6 +578,7 @@
return FALSE
/obj/item/electronic_assembly/Moved(oldLoc, dir)
. = ..()
for(var/I in assembly_components)
var/obj/item/integrated_circuit/IC = I
IC.ext_moved(oldLoc, dir)

View File

@@ -8,6 +8,7 @@ INITIALIZE_IMMEDIATE(/mob/dead)
throwforce = 0
/mob/dead/Initialize()
SHOULD_CALL_PARENT(FALSE)
if(flags_1 & INITIALIZED_1)
stack_trace("Warning: [src]([type]) initialized multiple times!")
flags_1 |= INITIALIZED_1
@@ -68,14 +69,15 @@ INITIALIZE_IMMEDIATE(/mob/dead)
set desc= "Jump to the other server"
if(mob_transforming)
return
var/list/csa = CONFIG_GET(keyed_list/cross_server)
var/list/our_id = CONFIG_GET(string/cross_comms_name)
var/list/csa = CONFIG_GET(keyed_list/cross_server) - our_id
var/pick
switch(csa.len)
if(0)
remove_verb(src, /mob/dead/proc/server_hop)
to_chat(src, "<span class='notice'>Server Hop has been disabled.</span>")
if(1)
pick = csa[0]
pick = csa[1]
else
pick = input(src, "Pick a server to jump to", "Server Hop") as null|anything in csa
@@ -100,7 +102,7 @@ INITIALIZE_IMMEDIATE(/mob/dead)
winset(src, null, "command=.options") //other wise the user never knows if byond is downloading resources
C << link("[addr]?server_hop=[key]")
C << link("[addr]")
/mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister
if (registered_z != new_z)

View File

@@ -91,8 +91,8 @@
Attach(M)
/obj/item/clothing/mask/facehugger/Crossed(atom/target)
. = ..()
HasProximity(target)
return
/obj/item/clothing/mask/facehugger/on_found(mob/finder)
if(stat == CONSCIOUS)

View File

@@ -99,14 +99,6 @@
if(lying && !buckled && prob(getBruteLoss()*200/maxHealth))
makeTrail(newloc, T, old_direction)
/mob/living/Move_Pulled(atom/A)
. = ..()
if(!. || !isliving(A))
return
var/mob/living/L = A
set_pull_offsets(L, grab_state)
/mob/living/forceMove(atom/destination)
stop_pulling()
if(buckled)

View File

@@ -37,20 +37,22 @@
return
..()
/mob/living/simple_animal/cockroach/Crossed(var/atom/movable/AM)
if(ismob(AM))
/mob/living/simple_animal/cockroach/Crossed(atom/movable/AM)
. = ..()
if(isliving(AM))
var/mob/living/A = AM
if(A.mob_size > MOB_SIZE_SMALL && !(A.movement_type & FLYING))
if(HAS_TRAIT(A, TRAIT_PACIFISM))
A.visible_message("<span class='notice'>[A] carefully steps over [src].</span>", "<span class='notice'>You carefully step over [src] to avoid hurting it.</span>")
return
if(prob(squish_chance))
A.visible_message("<span class='notice'>[A] squashed [src].</span>", "<span class='notice'>You squashed [src].</span>")
adjustBruteLoss(1) //kills a normal cockroach
else
visible_message("<span class='notice'>[src] avoids getting crushed.</span>")
else
if(isstructure(AM))
else if(isstructure(AM))
if(prob(squish_chance))
AM.visible_message("<span class='notice'>[src] was crushed under [AM].</span>")
AM.visible_message("<span class='notice'>[src] is crushed under [AM].</span>")
adjustBruteLoss(1)
else
visible_message("<span class='notice'>[src] avoids getting crushed.</span>")

View File

@@ -263,7 +263,7 @@
/mob/living/simple_animal/pet/dog/corgi/proc/place_on_head(obj/item/item_to_add, mob/user)
if(istype(item_to_add, /obj/item/grenade/plastic)) // last thing he ever wears, I guess
item_to_add.afterattack(src,user,1)
INVOKE_ASYNC(item_to_add, /obj/item.proc/afterattack, src, user, 1)
return
if(inventory_head)
@@ -271,13 +271,15 @@
to_chat(user, "<span class='warning'>You can't put more than one hat on [src]!</span>")
return
if(!item_to_add)
user.visible_message("[user] pets [src].","<span class='notice'>You rest your hand on [src]'s head for a moment.</span>")
user.visible_message("<span class='notice'>[user] pets [src].</span>", "<span class='notice'>You rest your hand on [src]'s head for a moment.</span>")
if(flags_1 & HOLOGRAM_1)
return
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, src, /datum/mood_event/pet_animal, src)
return
if(user && !user.temporarilyRemoveItemFromInventory(item_to_add))
to_chat(user, "<span class='warning'>\The [item_to_add] is stuck to your hand, you cannot put it on [src]'s head!</span>")
return 0
return
var/valid = FALSE
if(ispath(item_to_add.dog_fashion, /datum/dog_fashion/head))
@@ -287,11 +289,11 @@
if(valid)
if(health <= 0)
to_chat(user, "<span class ='notice'>There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()].</span>")
to_chat(user, "<span class='notice'>There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()].</span>")
else if(user)
user.visible_message("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once.",
user.visible_message("<span class='notice'>[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once.</span>",
"<span class='notice'>You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks.</span>",
"<span class='italics'>You hear a friendly-sounding bark.</span>")
"<span class='hear'>You hear a friendly-sounding bark.</span>")
item_to_add.forceMove(src)
src.inventory_head = item_to_add
update_corgi_fluff()
@@ -361,7 +363,7 @@
icon_state = "old_corgi"
icon_living = "old_corgi"
icon_dead = "old_corgi_dead"
desc = "At a ripe old age of [record_age] Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP
desc = "At a ripe old age of [record_age], Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP
turns_per_move = 20
RemoveElement(/datum/element/mob_holder, held_icon)
AddElement(/datum/element/mob_holder, "old_corgi")

View File

@@ -110,6 +110,7 @@
/obj/effect/snare/Crossed(AM as mob|obj)
. = ..()
if(isliving(AM) && spawner && spawner.summoner && AM != spawner && !spawner.hasmatchingsummoner(AM))
to_chat(spawner.summoner, "<span class='danger'><B>[AM] has crossed surveillance snare, [name].</span></B>")
var/list/guardians = spawner.summoner.hasparasites()

View File

@@ -219,6 +219,9 @@
/obj/effect/temp_visual/goliath_tentacle/broodmother/patch/Initialize(mapload, new_spawner)
. = ..()
INVOKE_ASYNC(src, .proc/createpatch)
/obj/effect/temp_visual/goliath_tentacle/broodmother/patch/proc/createpatch()
var/tentacle_locs = spiral_range_turfs(1, get_turf(src))
for(var/T in tentacle_locs)
new /obj/effect/temp_visual/goliath_tentacle/broodmother(T, spawner)

View File

@@ -42,7 +42,8 @@
butcher_results = list(/obj/item/reagent_containers/food/snacks/nugget = 5)
/mob/living/simple_animal/hostile/retaliate/frog/Crossed(AM as mob|obj)
. = ..()
if(!stat && isliving(AM))
var/mob/living/L = AM
if(L.mob_size > MOB_SIZE_TINY)
playsound(src, stepped_sound, 50, 1)
playsound(src, stepped_sound, 50, TRUE)

View File

@@ -96,7 +96,7 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache)
return TRUE
remove_movespeed_modifier(existing, FALSE)
if(length(movespeed_modification))
BINARY_INSERT(type_or_datum.id, movespeed_modification, datum/movespeed_modifier, type_or_datum, priority, COMPARE_VALUE)
BINARY_INSERT(type_or_datum.id, movespeed_modification, /datum/movespeed_modifier, type_or_datum, priority, COMPARE_VALUE)
LAZYSET(movespeed_modification, type_or_datum.id, type_or_datum)
if(update)
update_movespeed()

View File

@@ -56,12 +56,14 @@
else
..()
/obj/machinery/field/containment/Crossed(mob/mover)
if(isliving(mover))
shock(mover)
/obj/machinery/field/containment/Crossed(atom/movable/AM)
. = ..()
if(isliving(AM))
shock(AM)
if(ismachinery(AM) || isstructure(AM) || ismecha(AM))
bump_field(AM)
if(ismachinery(mover) || isstructure(mover) || ismecha(mover))
bump_field(mover)
/obj/machinery/field/containment/proc/set_master(master1,master2)
if(!master1 || !master2)

View File

@@ -44,6 +44,7 @@
movement_range = 0
/obj/effect/accelerated_particle/Crossed(atom/A)
. = ..()
if(isliving(A))
toxmob(A)

View File

@@ -14,12 +14,12 @@
var/obj/pipe_type = /obj/structure/disposalpipe/segment
var/pipename
/obj/structure/disposalconstruct/Initialize(loc, _pipe_type, _dir = SOUTH, flip = FALSE, obj/make_from)
/obj/structure/disposalconstruct/Initialize(mapload, _pipe_type, _dir = SOUTH, flip = FALSE, obj/make_from)
. = ..()
if(make_from)
pipe_type = make_from.type
setDir(make_from.dir)
anchored = TRUE
set_anchored(TRUE)
else
if(_pipe_type)
@@ -34,6 +34,8 @@
update_icon()
// AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE)
/obj/structure/disposalconstruct/Move()
var/old_dir = dir
..()

View File

@@ -274,6 +274,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate)
return
/obj/structure/stone_tile/Crossed(atom/movable/AM)
. = ..()
if(falling || fallen)
return
var/turf/T = get_turf(src)

View File

@@ -21,6 +21,9 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337)
/obj/item/hilbertshotel/Initialize()
. = ..()
//Load templates
INVOKE_ASYNC(src, .proc/prepare_rooms)
/obj/item/hilbertshotel/proc/prepare_rooms()
hotelRoomTemp = new()
hotelRoomTempEmpty = new()
hotelRoomTempLore = new()

View File

@@ -1,6 +1,6 @@
/obj/effect/proc_holder/spell/spacetime_dist
name = "Spacetime Distortion"
desc = "Entangle the strings of spacetime to deny easy movement around you. The strings vibrate..."
desc = "Entangle the strings of space-time in an area around you, randomizing the layout and making proper movement impossible. The strings vibrate..."
charge_max = 300
var/duration = 150
range = 7
@@ -10,8 +10,9 @@
sound = 'sound/effects/magic.ogg'
cooldown_min = 300
level_max = 0
// action_icon_state = "spacetime"
/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr, skipcharge = FALSE, silent = FALSE)
/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr)
if(ready)
return ..()
return FALSE
@@ -97,10 +98,11 @@
busy = TRUE
flick("purplesparkles", src)
AM.forceMove(get_turf(src))
playsound(get_turf(src),sound,70,0)
playsound(get_turf(src),sound,70,FALSE)
busy = FALSE
/obj/effect/cross_action/spacetime_dist/Crossed(atom/movable/AM)
. = ..()
if(!busy)
walk_link(AM)
@@ -110,7 +112,8 @@
else
walk_link(user)
/obj/effect/cross_action/spacetime_dist/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/effect/cross_action/spacetime_dist/on_attack_hand(mob/user)
walk_link(user)
/obj/effect/cross_action/spacetime_dist/attack_paw(mob/user)

View File

@@ -78,6 +78,7 @@
#include "code\__DEFINES\mobs.dm"
#include "code\__DEFINES\monkeys.dm"
#include "code\__DEFINES\move_force.dm"
#include "code\__DEFINES\movement.dm"
#include "code\__DEFINES\movespeed_modification.dm"
#include "code\__DEFINES\nanites.dm"
#include "code\__DEFINES\networks.dm"