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
@@ -71,7 +71,7 @@ GLOBAL_LIST_INIT(minimum_snow_under_spawns, list(
continue
if(typesof(/turf/open/lava) in orange(9, TT))
continue
valid_mining_turfs_2.Add(TT)
valid_mining_turfs_2.Add(TT)
else
for(var/z_level in SSmapping.levels_by_trait(ZTRAIT_LAVA_RUINS))
for(var/turf/TT in Z_TURFS(z_level))
@@ -103,14 +103,14 @@ GLOBAL_LIST_INIT(minimum_snow_under_spawns, list(
for(var/mob/living/simple_animal/hostile/megafauna/H in urange(70,RT)) //prevents mob clumps
if((istype(MS_tospawn, /mob/living/simple_animal/hostile/megafauna)) && get_dist(RT, H) <= 70)
active_spawns.Add(MS_tospawn)
continue //let's try not to dump megas too close to each other?
continue //let's try not to dump megas too close to each other?
if((istype(MS_tospawn, /obj/structure/spawner)) && get_dist(RT, H) <= 40)
active_spawns.Add(MS_tospawn)
continue //let's at least /try/ to space these out?
for(var/obj/structure/spawner/LT in urange(70,RT)) //prevents tendril/mega clumps
if((istype(MS_tospawn, /mob/living/simple_animal/hostile/megafauna)) && get_dist(RT, LT) <= 70)
active_spawns.Add(MS_tospawn)
continue //let's try not to dump megas too close to each other?
continue //let's try not to dump megas too close to each other?
if((istype(MS_tospawn, /obj/structure/spawner)) && get_dist(RT, LT) <= 40)
active_spawns.Add(MS_tospawn)
continue //let's at least /try/ to space these out?
@@ -127,7 +127,7 @@ GLOBAL_LIST_INIT(minimum_snow_under_spawns, list(
for(var/mob/living/simple_animal/hostile/H in urange(70,RT2)) //prevents mob clumps
if((istype(MS2_tospawn, /mob/living/simple_animal/hostile/megafauna) || ismegafauna(H)) && get_dist(RT2, H) <= 70)
active_spawns_2.Add(MS2_tospawn)
continue //let's try not to dump megas too close to each other?
continue //let's try not to dump megas too close to each other?
if((istype(MS2_tospawn, /obj/structure/spawner)) && get_dist(RT2, H) <= 40)
active_spawns_2.Add(MS2_tospawn)
continue //let's at least /try/ to space these out?

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,31 +31,45 @@ 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)
. = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
var/obj/effect/overlay/vis/overlay = vis_overlay_cache[.]
if(!overlay)
overlay = new
overlay.icon = icon
overlay.icon_state = iconstate
overlay.layer = layer
overlay.plane = plane
overlay.dir = dir
overlay.alpha = alpha
overlay.appearance_flags |= add_appearance_flags
vis_overlay_cache[.] = overlay
/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]"
overlay = vis_overlay_cache[.]
if(!overlay)
overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
vis_overlay_cache[.] = overlay
else
overlay.unused = 0
else
overlay.unused = 0
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
return overlay
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
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
overlay.plane = plane
overlay.dir = dir
overlay.alpha = alpha
overlay.appearance_flags |= add_appearance_flags
return 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)
@@ -425,42 +425,42 @@
"}
/obj/item/disk/holodisk/ruin/snowengieruin
name = "Blackbox Print-out #EB412"
desc = "A holodisk containing the last moments of EB412. There's a bloody fingerprint on it."
preset_image_type = /datum/preset_holoimage/engineer
preset_record_text = {"
NAME Dave Tundrale
SAY Maria, how's Build?
DELAY 10
NAME Maria Dell
PRESET /datum/preset_holoimage/engineer/atmos
SAY It's fine, don't worry. I've got Plastic on it. And frankly, i'm kinda busy with, the, uhhm, incinerator.
DELAY 30
NAME Dave Tundrale
PRESET /datum/preset_holoimage/engineer
SAY Aight, wonderful. The science mans been kinda shit though. No RCDs-
DELAY 20
NAME Maria Dell
PRESET /datum/preset_holoimage/engineer/atmos
SAY Enough about your RCDs. They're not even that important, just bui-
DELAY 15
SOUND explosion
DELAY 10
SAY Oh, shit!
DELAY 10
PRESET /datum/preset_holoimage/engineer/atmos/rig
LANGUAGE /datum/language/narsie
NAME Unknown
SAY RISE, MY LORD!!
DELAY 10
LANGUAGE /datum/language/common
NAME Plastic
PRESET /datum/preset_holoimage/engineer/rig
SAY Fuck, fuck, fuck!
DELAY 20
SAY It's loose! CALL THE FUCKING SHUTT-
DELAY 10
PRESET /datum/preset_holoimage/corgi
NAME Blackbox Automated Message
SAY Connection lost. Dumping audio logs to disk.
DELAY 50"}
name = "Blackbox Print-out #EB412"
desc = "A holodisk containing the last moments of EB412. There's a bloody fingerprint on it."
preset_image_type = /datum/preset_holoimage/engineer
preset_record_text = {"
NAME Dave Tundrale
SAY Maria, how's Build?
DELAY 10
NAME Maria Dell
PRESET /datum/preset_holoimage/engineer/atmos
SAY It's fine, don't worry. I've got Plastic on it. And frankly, i'm kinda busy with, the, uhhm, incinerator.
DELAY 30
NAME Dave Tundrale
PRESET /datum/preset_holoimage/engineer
SAY Aight, wonderful. The science mans been kinda shit though. No RCDs-
DELAY 20
NAME Maria Dell
PRESET /datum/preset_holoimage/engineer/atmos
SAY Enough about your RCDs. They're not even that important, just bui-
DELAY 15
SOUND explosion
DELAY 10
SAY Oh, shit!
DELAY 10
PRESET /datum/preset_holoimage/engineer/atmos/rig
LANGUAGE /datum/language/narsie
NAME Unknown
SAY RISE, MY LORD!!
DELAY 10
LANGUAGE /datum/language/common
NAME Plastic
PRESET /datum/preset_holoimage/engineer/rig
SAY Fuck, fuck, fuck!
DELAY 20
SAY It's loose! CALL THE FUCKING SHUTT-
DELAY 10
PRESET /datum/preset_holoimage/corgi
NAME Blackbox Automated Message
SAY Connection lost. Dumping audio logs to disk.
DELAY 50"}

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,7 +418,8 @@
SSthrowing.processing[src] = TT
if (SSthrowing.state == SS_PAUSED && length(SSthrowing.currentrun))
SSthrowing.currentrun[src] = TT
TT.tick()
if (quickstart)
TT.tick()
/atom/movable/proc/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
return FALSE
@@ -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))
setMovetype(movement_type | FLOATING)
else if (!on && 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))
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,32 +121,38 @@
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.
if(pulling.anchored)
stop_pulling()
else
var/pull_dir = get_dir(src, pulling)
//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.moving_from_pull = null
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
var/pull_dir = get_dir(src, pulling)
//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), glide_size) //the pullee tries to reach our previous position
pulling.moving_from_pull = null
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,27 +79,46 @@
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(prob(2))
if(!user.transferItemToLoc(C, drop_location()))
return
C.throw_at(user, 3, 10)
if(prob(10))
balance = max(balance - SPIN_PRICE, 0)
to_chat(user, "<span class='warning'>[src] spits your coin back out!</span>")
if(paymode == COIN)
if(prob(2))
if(!user.transferItemToLoc(C, drop_location()))
return
C.throw_at(user, 3, 10)
if(prob(10))
balance = max(balance - SPIN_PRICE, 0)
to_chat(user, "<span class='warning'>[src] spits your coin back out!</span>")
else
if(!user.temporarilyRemoveItemFromInventory(C))
return
to_chat(user, "<span class='notice'>You insert [C] into [src]'s slot!</span>")
balance += C.value
qdel(C)
else
if(!user.temporarilyRemoveItemFromInventory(C))
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 [C] into [src]'s slot!</span>")
balance += C.value
qdel(C)
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)
balance = 0
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,37 +204,43 @@
balance -= SPIN_PRICE
money += SPIN_PRICE
plays += 1
working = 1
working = TRUE
toggle_reel_spin(1)
update_icon()
updateDialog()
spawn(0)
while(working)
randomize_reels()
updateDialog()
sleep(2)
var/spin_loop = addtimer(CALLBACK(src, .proc/do_spin), 2, TIMER_LOOP|TIMER_STOPPABLE)
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.
toggle_reel_spin(0, REEL_DEACTIVATE_DELAY)
working = 0
give_prizes(the_name, user)
update_icon()
updateDialog()
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()
/obj/machinery/computer/slot_machine/proc/finish_spinning(spin_loop, mob/user, the_name)
toggle_reel_spin(0, REEL_DEACTIVATE_DELAY)
working = FALSE
deltimer(spin_loop)
give_prizes(the_name, user)
update_icon()
updateDialog()
/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
for(var/i = 0, i < 5, i++)
var/cointype = pick(subtypesof(/obj/item/coin))
var/obj/item/coin/C = new cointype(loc)
random_step(C, 2, 50)
if(paymode == HOLOCHIP)
new /obj/item/holochip(loc,JACKPOT)
else
for(var/i = 0, i < 5, i++)
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(value <= 0)
return
while(amount >= value && !QDELETED(src))
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
H.throw_at(target, 3, 10)
else
var/value = coinvalues["[cointype]"]
if(value <= 0)
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)
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)
mover.Bump(firstbump)
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,18 +181,18 @@
/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))
var/mob/living/simple_animal/S = L
S.toggle_ai(AI_OFF)
if(ishostile(L))
var/mob/living/simple_animal/hostile/H = L
H.LoseTarget()
if(ishostile(L))
var/mob/living/simple_animal/hostile/H = L
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/effect,
/obj/belly,
/obj/mafia_game_board,
/obj/docking_port,
/obj/shapeshift_holder,
/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,23 +37,25 @@
return
..()
/mob/living/simple_animal/cockroach/Crossed(var/atom/movable/AM)
if(ismob(AM))
if(isliving(AM))
var/mob/living/A = AM
if(A.mob_size > MOB_SIZE_SMALL && !(A.movement_type & FLYING))
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))
/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))
AM.visible_message("<span class='notice'>[src] was crushed under [AM].</span>")
adjustBruteLoss(1)
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))
if(prob(squish_chance))
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>")
/mob/living/simple_animal/cockroach/ex_act() //Explosions are a terrible way to handle a cockroach.
return

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.",
"<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>")
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='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"