mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2025-12-29 19:52:12 +00:00
This converts the machine and mob processes to the SMC. Additionally, it adds the Atom subsystem, which handles all Initialize() calls in place of the old gameticker. Due to incompatibility with our atmospherics (FUCK OUR ATMOSPHERICS FOR FUCKING EVER JESUS CHRIST WHO THE FUCK MADE THIS PIECE OF GODDAMN SHIT) atmospherics machines do not use Initialize() as they should, instead opting for a custom atmos_init proc that the air controller handles.
369 lines
9.6 KiB
Plaintext
369 lines
9.6 KiB
Plaintext
/area/awaymission/upperlevel
|
|
name = "Open Space"
|
|
color = "#888"
|
|
dynamic_lighting = 0
|
|
requires_power = 0
|
|
|
|
// Used by /turf/unsimulated/floor/upperlevel as a reference for where the other floor is
|
|
/obj/effect/levelref
|
|
name = "level reference"
|
|
icon = 'icons/mob/screen_gen.dmi'
|
|
icon_state = "x2"
|
|
invisibility = 101
|
|
|
|
var/id = null
|
|
var/obj/effect/levelref/other = null
|
|
var/offset_x
|
|
var/offset_y
|
|
var/offset_z
|
|
var/global/list/levels[0]
|
|
|
|
/obj/effect/levelref/New()
|
|
..()
|
|
levels += src
|
|
|
|
/obj/effect/levelref/Initialize()
|
|
..()
|
|
for(var/obj/effect/levelref/O in levels)
|
|
if(id == O.id && O != src)
|
|
other = O
|
|
update_offset()
|
|
O.other = src
|
|
O.update_offset()
|
|
for(var/turf/unsimulated/floor/upperlevel/U in get_area(loc))
|
|
U.init(src)
|
|
return
|
|
|
|
/obj/effect/levelref/Destroy()
|
|
levels -= src
|
|
return ..()
|
|
|
|
/obj/effect/levelref/proc/update_offset()
|
|
offset_x = other.x - x
|
|
offset_y = other.y - y
|
|
offset_z = other.z - z
|
|
|
|
// Used by /turf/unsimulated/floor/upperlevel and /obj/effect/view_portal/visual
|
|
// to know if the world changed on the remote side
|
|
/obj/effect/portal_sensor
|
|
invisibility = 101
|
|
var/light_hash = -1
|
|
var/triggered_this_tick = 0
|
|
var/datum/owner // owner that receive signals
|
|
var/list/params[0] // what to send to the main object to indicate which sensor
|
|
var/trigger_limit = 5 // number of time we're allowed to trigger per ptick
|
|
|
|
/obj/effect/portal_sensor/New(loc, o, ...)
|
|
..()
|
|
owner = o
|
|
if(args.len >= 3)
|
|
params = args.Copy(3)
|
|
processing_objects += src
|
|
trigger()
|
|
|
|
/obj/effect/portal_sensor/Destroy()
|
|
processing_objects -= src
|
|
return ..()
|
|
|
|
/obj/effect/portal_sensor/Crossed(A)
|
|
trigger()
|
|
|
|
/obj/effect/portal_sensor/Uncrossed(A)
|
|
trigger()
|
|
|
|
/obj/effect/portal_sensor/process()
|
|
check_light()
|
|
if(triggered_this_tick >= trigger_limit)
|
|
call(owner, "trigger")(arglist(params))
|
|
triggered_this_tick = 0
|
|
|
|
/obj/effect/portal_sensor/proc/trigger()
|
|
triggered_this_tick++
|
|
if(triggered_this_tick < trigger_limit)
|
|
call(owner, "trigger")(arglist(params))
|
|
|
|
/obj/effect/portal_sensor/proc/check_light()
|
|
var/turf/T = loc
|
|
if(istype(T) && T.lighting_overlay && !T.lighting_overlay.needs_update)
|
|
var/atom/movable/lighting_overlay/O = T.lighting_overlay
|
|
var/hash = O.lum_r + O.lum_g + O.lum_b
|
|
if(hash != light_hash)
|
|
light_hash = hash
|
|
trigger()
|
|
else
|
|
if(light_hash != -1)
|
|
light_hash = -1
|
|
trigger()
|
|
|
|
// for second floor showing floor below
|
|
/turf/unsimulated/floor/upperlevel
|
|
icon = 'icons/turf/areas.dmi'
|
|
icon_state = "dark128"
|
|
layer = AREA_LAYER + 0.5
|
|
appearance_flags = TILE_BOUND | KEEP_TOGETHER
|
|
var/turf/lower_turf
|
|
var/obj/effect/portal_sensor/sensor
|
|
|
|
/turf/unsimulated/floor/upperlevel/New()
|
|
..()
|
|
var/obj/effect/levelref/R = locate() in get_area(src)
|
|
if(R && R.other)
|
|
init(R)
|
|
|
|
/turf/unsimulated/floor/upperlevel/Destroy()
|
|
QDEL_NULL(sensor)
|
|
return ..()
|
|
|
|
/turf/unsimulated/floor/upperlevel/proc/init(var/obj/effect/levelref/R)
|
|
lower_turf = locate(x + R.offset_x, y + R.offset_y, z + R.offset_z)
|
|
if(lower_turf)
|
|
sensor = new(lower_turf, src)
|
|
|
|
/turf/unsimulated/floor/upperlevel/Entered(atom/movable/AM, atom/OL, ignoreRest = 0)
|
|
if(isliving(AM) || istype(AM, /obj))
|
|
if(isliving(AM))
|
|
var/mob/living/M = AM
|
|
M.emote("scream")
|
|
M.SpinAnimation(5, 1)
|
|
AM.forceMove(lower_turf)
|
|
|
|
/turf/unsimulated/floor/upperlevel/attack_ghost(mob/user)
|
|
user.forceMove(lower_turf)
|
|
|
|
/turf/unsimulated/floor/upperlevel/proc/trigger()
|
|
name = lower_turf.name
|
|
desc = lower_turf.desc
|
|
|
|
// render each atom
|
|
underlays.Cut()
|
|
for(var/X in list(lower_turf) + lower_turf.contents)
|
|
var/atom/A = X
|
|
if(A && A.invisibility <= SEE_INVISIBLE_LIVING)
|
|
var/image/I = image(A, layer = AREA_LAYER + A.layer * 0.01, dir = A.dir)
|
|
I.pixel_x = A.pixel_x
|
|
I.pixel_y = A.pixel_y
|
|
underlays += I
|
|
|
|
// remote end of narnia portal
|
|
/obj/effect/view_portal
|
|
name = "portal target"
|
|
icon = 'icons/mob/screen_gen.dmi'
|
|
icon_state = "x2"
|
|
invisibility = 101
|
|
anchored = 1
|
|
|
|
var/id = null // id of other portal turf we connect to
|
|
|
|
var/obj/effect/view_portal/other = null
|
|
var/global/list/portals[0]
|
|
|
|
/obj/effect/view_portal/New()
|
|
..()
|
|
portals += src
|
|
|
|
/obj/effect/view_portal/Initialize()
|
|
..()
|
|
if(id)
|
|
for(var/obj/effect/view_portal/O in portals)
|
|
if(id == O.id && O != src && can_link(O))
|
|
other = O
|
|
O.other = src
|
|
linkup()
|
|
O.linkup()
|
|
if(other)
|
|
return
|
|
|
|
/obj/effect/view_portal/Destroy()
|
|
portals -= src
|
|
return ..()
|
|
|
|
/obj/effect/view_portal/proc/can_link(obj/effect/view_portal/P)
|
|
return P.type == /obj/effect/view_portal/visual && !P.other
|
|
|
|
/obj/effect/view_portal/proc/linkup()
|
|
// allow it to link to multiple visual nodes
|
|
other = null
|
|
|
|
// near end of nania portal
|
|
/obj/effect/view_portal/visual
|
|
name = "???"
|
|
desc = "You'll have to get closer to clearly see what this is."
|
|
|
|
icon = 'icons/turf/floors.dmi'
|
|
icon_state = "loadingarea"
|
|
opacity = 1
|
|
density = 1
|
|
invisibility = 0
|
|
appearance_flags = TILE_BOUND | KEEP_TOGETHER
|
|
var/dist = 6 // dist that we render out
|
|
var/radius = 3 // dist we render on other axis, in each direction
|
|
var/frustrum = 0 // if 1, get wider and wider at each step outward
|
|
var/teleport = 1 // should teleport?
|
|
|
|
var/list/render_block
|
|
var/list/sensors[0]
|
|
var/list/tiles[0]
|
|
|
|
var/list/near_render_block
|
|
var/turf/near_viewpoint
|
|
|
|
/obj/effect/view_portal/visual/Destroy()
|
|
for(var/T in sensors)
|
|
qdel(sensors[T])
|
|
sensors.Cut()
|
|
sensors = null
|
|
for(var/T in tiles)
|
|
qdel(tiles[T])
|
|
tiles.Cut()
|
|
tiles = null
|
|
render_block = null
|
|
near_render_block = null
|
|
near_viewpoint = null
|
|
return ..()
|
|
|
|
/obj/effect/view_portal/visual/can_link(obj/effect/view_portal/P)
|
|
return P.type == /obj/effect/view_portal
|
|
|
|
/obj/effect/view_portal/visual/linkup()
|
|
icon = null
|
|
icon_state = null
|
|
var/turf/Tloc = get_turf(loc)
|
|
if(Tloc)
|
|
Tloc.icon = null
|
|
Tloc.icon_state = null
|
|
Tloc.dynamic_lighting = 0
|
|
layer = AREA_LAYER + 0.5
|
|
|
|
// setup references
|
|
var/crossdir = angle2dir((dir2angle(dir) + 90) % 360)
|
|
near_viewpoint = get_step(get_turf(src), GetOppositeDir(dir))
|
|
|
|
// setup far turfs
|
|
var/turf/T1 = get_turf(other)
|
|
var/turf/T2 = T1
|
|
|
|
for(var/i in 1 to radius)
|
|
T1 = get_step(T1, crossdir)
|
|
T2 = get_step(T2, GetOppositeDir(crossdir))
|
|
if(frustrum)
|
|
// make a trapazoid, with length dist, short end radius*2 long,
|
|
// and 45 degree angles
|
|
render_block = block(T1, T2)
|
|
for(var/i in 1 to dist)
|
|
T1 = get_step(get_step(T1, dir), crossdir)
|
|
T2 = get_step(get_step(T2, dir), GetOppositeDir(crossdir))
|
|
render_block += block(T1, T2)
|
|
else
|
|
// else make a box dist x radius*2
|
|
for(var/i in 1 to dist)
|
|
T2 = get_step(T2, dir)
|
|
render_block = block(T1, T2)
|
|
for(var/turf/T in render_block)
|
|
sensors[T] = new /obj/effect/portal_sensor(T, src, 0, T)
|
|
|
|
// setup turfs on this side of the portal to cover the map streaming
|
|
// has to be done later for view() to be correct (so it happens when the walls exist)
|
|
/obj/effect/view_portal/visual/proc/setup_near()
|
|
var/nvs = dir & (EAST|WEST) ? near_viewpoint.x - x : near_viewpoint.y - y
|
|
if(nvs)
|
|
nvs = SIGN(nvs)
|
|
// need a mob for view() to work correctly
|
|
var/mob/M = new(near_viewpoint)
|
|
M.see_invisible = SEE_INVISIBLE_LIVING
|
|
near_render_block = view(M, world.view)
|
|
qdel(M)
|
|
for(var/A in near_render_block)
|
|
var/turf/T = A
|
|
if(istype(T))
|
|
var/ts = dir & (EAST|WEST) ? T.x - x : T.y - y
|
|
if(ts)
|
|
ts = SIGN(ts)
|
|
if(nvs == ts)
|
|
sensors[T] = new /obj/effect/portal_sensor(T, src, 1, T)
|
|
else
|
|
near_render_block -= T
|
|
else
|
|
near_render_block -= T
|
|
|
|
/obj/effect/view_portal/visual/Bumped(atom/movable/thing)
|
|
if((istype(thing, /obj) || isliving(thing)) && other && teleport)
|
|
if(!near_render_block)
|
|
setup_near()
|
|
|
|
var/mob/living/M = thing
|
|
// make the person glide onto the dest, giving a smooth transition
|
|
var/ox = thing.x - x
|
|
var/oy = thing.y - y
|
|
if(istype(M) && M.client)
|
|
M.notransform = 1
|
|
// cover up client-side map loading
|
|
M.screen_loc = "CENTER"
|
|
M.client.screen += M
|
|
for(var/T in tiles)
|
|
M.client.screen += tiles[T]
|
|
|
|
// wait a tick for the screen to replicate across network
|
|
// or this whole exercise of covering the transition is pointless
|
|
spawn(1)
|
|
thing.forceMove(locate(other.x + ox, other.y + oy, other.z))
|
|
sleep(1)
|
|
if(istype(M) && M.client)
|
|
for(var/T in tiles)
|
|
M.client.screen -= tiles[T]
|
|
M.client.screen -= M
|
|
M.screen_loc = initial(M.screen_loc)
|
|
thing.forceMove(get_turf(other.loc))
|
|
if(istype(M) && M.client)
|
|
M.notransform = 0
|
|
|
|
/obj/effect/view_portal/visual/attack_ghost(mob/user)
|
|
user.forceMove(get_turf(other.loc))
|
|
|
|
/obj/effect/view_portal/visual/proc/trigger(near, turf/T)
|
|
var/obj/effect/view_portal_dummy/D = tiles[T]
|
|
if(D)
|
|
D.overlays.Cut()
|
|
else
|
|
D = new(src, near, T)
|
|
tiles[T] = D
|
|
|
|
// render atoms to overlays of a dummy object
|
|
if(D.name != T.name)
|
|
D.name = T.name
|
|
D.desc = T.desc
|
|
for(var/AX in list(T) + T.contents)
|
|
var/atom/A = AX
|
|
if(A && A.invisibility <= SEE_INVISIBLE_LIVING)
|
|
var/image/I = image(A, layer = D.layer + A.layer * 0.01, dir = A.dir)
|
|
I.pixel_x = A.pixel_x
|
|
I.pixel_y = A.pixel_y
|
|
D.overlays += I
|
|
|
|
// tile of rendered other side for narnia portal
|
|
/obj/effect/view_portal_dummy
|
|
var/obj/effect/view_portal/visual/owner
|
|
|
|
/obj/effect/view_portal_dummy/New(obj/effect/view_portal/visual/V, near, turf/T)
|
|
..()
|
|
if(!near)
|
|
loc = V.loc
|
|
owner = V
|
|
|
|
var/ox
|
|
var/oy
|
|
if(near)
|
|
ox = (T.x - V.near_viewpoint.x)
|
|
oy = (T.y - V.near_viewpoint.y)
|
|
layer = AREA_LAYER + 0.4
|
|
else
|
|
ox = T.x - V.other.x + V.x - V.near_viewpoint.x
|
|
oy = T.y - V.other.y + V.y - V.near_viewpoint.y
|
|
pixel_x = 32 * (T.x - V.other.x)
|
|
pixel_y = 32 * (T.y - V.other.y)
|
|
layer = AREA_LAYER + 0.5
|
|
if(abs(ox) <= world.view && abs(oy) <= world.view)
|
|
screen_loc = "CENTER[ox >= 0 ? "+" : ""][ox],CENTER[oy >= 0 ? "+" : ""][oy]"
|
|
|
|
/obj/effect/view_portal_dummy/attack_ghost(mob/user)
|
|
owner.attack_ghost(user)
|