Merge branch 'phaser-handbow' of https://github.com/TheDavestDave/VOREStation into phaser-handbow

This commit is contained in:
TheDavestDave
2021-06-20 00:52:38 +01:00
843 changed files with 208603 additions and 14623 deletions
+1 -5
View File
@@ -306,13 +306,9 @@
var/output = {"<form><input type="hidden" name="src" value="\ref[src]"><ul class="sparse">"}
if (inputtype == "checkbox" || inputtype == "radio")
for (var/i in values)
var/div_slider = slidecolor
if(!i["allowed_edit"])
div_slider = "locked"
output += {"<li>
<label class="switch">
<input type="[inputtype]" value="1" name="[i["name"]]"[i["checked"] ? " checked" : ""][i["allowed_edit"] ? "" : " onclick='return false' onkeydown='return false'"]>
<div class="slider [div_slider ? "[div_slider]" : ""]"></div>
<input type="[inputtype]" value="1" name="[i["name"]]"[i["checked"] ? " checked" : ""][i["allowed_edit"] ? "" : " disabled onclick='return false' onkeydown='return false'"]>
<span>[i["name"]]</span>
</label>
</li>"}
+3
View File
@@ -196,6 +196,9 @@ var/list/runechat_image_cache = list()
message.maptext_y = message_loc.runechat_y_offset(msgwidth, mheight)
message.maptext = complete_text
if(!owner)
qdel(src)
return
if(owner.contains(target)) // Special case, holding an atom speaking (pAI, recorder...)
message.plane = PLANE_PLAYER_HUD_ABOVE
+5 -1
View File
@@ -188,7 +188,11 @@
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override && procs[target][sig_type])
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
var/trace_msg = "[sig_type] overridden. Use override = TRUE to suppress this warning."
if(isatom(target))
var/atom/A = target
trace_msg += " [A.x],[A.y],[A.z]"
stack_trace(trace_msg)
procs[target][sig_type] = proctype
+518
View File
@@ -0,0 +1,518 @@
///For switchable lights, is it on and currently emitting light?
#define LIGHTING_ON (1<<0)
///Is the parent attached to something else, its loc? Then we need to keep an eye of this.
#define LIGHTING_ATTACHED (1<<1)
#define GET_PARENT (parent_attached_to || parent)
#define GET_LIGHT_SOURCE (directional_atom || current_holder)
#define SHORT_CAST 2
/**
* Movable atom overlay-based lighting component.
*
* * Component works by applying a visual object to the parent target.
*
* * The component tracks the parent's loc to determine the current_holder.
* * The current_holder is either the parent or its loc, whichever is on a turf. If none, then the current_holder is null and the light is not visible.
*
* * Lighting works at its base by applying a dark overlay and "cutting" said darkness with light, adding (possibly colored) transparency.
* * This component uses the visible_mask visual object to apply said light mask on the darkness.
*
* * The main limitation of this system is that it uses a limited number of pre-baked geometrical shapes, but for most uses it does the job.
*
* * Another limitation is for big lights: you only see the light if you see the object emiting it.
* * For small objects this is good (you can't see them behind a wall), but for big ones this quickly becomes prety clumsy.
*/
/datum/component/overlay_lighting
///How far the light reaches, float.
var/range = 1
///Ceiling of range, integer without decimal entries.
var/lumcount_range = 0
///How much this light affects the dynamic_lumcount of turfs.
var/lum_power = 0.5
///Transparency value.
var/set_alpha = 0
///For light sources that can be turned on and off.
var/overlay_lighting_flags = NONE
///Cache of the possible light overlays, according to size.
var/static/list/light_overlays = list(
"32" = 'icons/effects/light_overlays/light_32.dmi',
"64" = 'icons/effects/light_overlays/light_64.dmi',
"96" = 'icons/effects/light_overlays/light_96.dmi',
"128" = 'icons/effects/light_overlays/light_128.dmi',
"160" = 'icons/effects/light_overlays/light_160.dmi',
"192" = 'icons/effects/light_overlays/light_192.dmi',
"224" = 'icons/effects/light_overlays/light_224.dmi',
"256" = 'icons/effects/light_overlays/light_256.dmi',
"288" = 'icons/effects/light_overlays/light_288.dmi',
"320" = 'icons/effects/light_overlays/light_320.dmi',
"352" = 'icons/effects/light_overlays/light_352.dmi',
)
///Overlay effect to cut into the darkness and provide light.
var/obj/effect/overlay/light_visible/visible_mask
///Lazy list to track the turfs being affected by our light, to determine their visibility.
var/list/turf/affected_turfs
///Movable atom currently holding the light. Parent might be a flashlight, for example, but that might be held by a mob or something else.
var/atom/movable/current_holder
///Movable atom the parent is attached to. For example, a flashlight into a helmet or gun. We'll need to track the thing the parent is attached to as if it were the parent itself.
var/atom/movable/parent_attached_to
///Whether we're a directional light
var/directional
///Abstractional atom for directional light, we move this around to make the directional effect
var/obj/effect/abstract/directional_lighting/directional_atom
///A cone overlay for directional light, it's alpha and color are dependant on the light
var/obj/effect/overlay/light_cone/cone
///Current tracked direction for the directional cast behaviour
var/current_direction
///Cast range for the directional cast (how far away the atom is moved)
var/cast_range = 2
///Cone offset X hint from atom, used when facing south, inverted when facing north
var/cone_hint_x
///Cone offset Y hint from atom, when facing east/west, ignored for north/south (uses 16 in those cases)
var/cone_hint_y
/datum/component/overlay_lighting/Initialize(_range, _power, _color, starts_on, is_directional)
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE
var/atom/movable/movable_parent = parent
if(movable_parent.light_system != MOVABLE_LIGHT && movable_parent.light_system != MOVABLE_LIGHT_DIRECTIONAL)
stack_trace("[type] added to [parent], with [movable_parent.light_system] value for the light_system var. Use [MOVABLE_LIGHT] or [MOVABLE_LIGHT_DIRECTIONAL] instead.")
return COMPONENT_INCOMPATIBLE
. = ..()
visible_mask = new()
if(is_directional)
directional = TRUE
directional_atom = new()
cone = new()
cone_hint_x = movable_parent.light_cone_x_offset
cone_hint_y = movable_parent.light_cone_y_offset
cone.transform = cone.transform.Translate(-32, -32)
set_direction(movable_parent.dir)
if(!isnull(_range))
movable_parent.set_light_range(_range)
set_range(parent, movable_parent.light_range)
if(!isnull(_power))
movable_parent.set_light_power(_power)
set_power(parent, movable_parent.light_power)
if(!isnull(_color))
movable_parent.set_light_color(_color)
set_color(parent, movable_parent.light_color)
if(!isnull(starts_on))
movable_parent.set_light_on(starts_on)
/datum/component/overlay_lighting/RegisterWithParent()
. = ..()
if(directional)
RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, .proc/on_parent_dir_change)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_parent_moved)
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_RANGE, .proc/set_range)
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_POWER, .proc/set_power)
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_COLOR, .proc/set_color)
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_ON, .proc/on_toggle)
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_FLAGS, .proc/on_light_flags_change)
RegisterSignal(parent, COMSIG_ATOM_USED_IN_CRAFT, .proc/on_parent_crafted)
RegisterSignal(parent, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater)
var/atom/movable/movable_parent = parent
if(movable_parent.light_flags & LIGHT_ATTACHED)
overlay_lighting_flags |= LIGHTING_ATTACHED
set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null)
check_holder()
if(movable_parent.light_on)
turn_on()
/datum/component/overlay_lighting/UnregisterFromParent()
overlay_lighting_flags &= ~LIGHTING_ATTACHED
set_parent_attached_to(null)
set_holder(null)
clean_old_turfs()
UnregisterSignal(parent, list(
COMSIG_MOVABLE_MOVED,
COMSIG_ATOM_UPDATE_LIGHT_RANGE,
COMSIG_ATOM_UPDATE_LIGHT_POWER,
COMSIG_ATOM_UPDATE_LIGHT_COLOR,
COMSIG_ATOM_UPDATE_LIGHT_ON,
COMSIG_ATOM_UPDATE_LIGHT_FLAGS,
COMSIG_ATOM_USED_IN_CRAFT,
COMSIG_LIGHT_EATER_QUEUE,
))
if(directional)
UnregisterSignal(parent, COMSIG_ATOM_DIR_CHANGE)
if(overlay_lighting_flags & LIGHTING_ON)
turn_off()
return ..()
/datum/component/overlay_lighting/Destroy()
set_parent_attached_to(null)
set_holder(null)
clean_old_turfs()
qdel(visible_mask, TRUE)
visible_mask = null
if(directional)
qdel(directional_atom, TRUE)
directional_atom = null
qdel(cone, TRUE)
cone = null
return ..()
///Clears the affected_turfs lazylist, removing from its contents the effects of being near the light.
/datum/component/overlay_lighting/proc/clean_old_turfs()
for(var/t in affected_turfs)
var/turf/lit_turf = t
lit_turf.dynamic_lumcount -= lum_power
affected_turfs = null
///Populates the affected_turfs lazylist, adding to its contents the effects of being near the light.
/datum/component/overlay_lighting/proc/get_new_turfs()
if(!current_holder)
return
var/atom/movable/light_source = GET_LIGHT_SOURCE
for(var/turf/lit_turf in view(lumcount_range, get_turf(light_source)))
lit_turf.dynamic_lumcount += lum_power
LAZYADD(affected_turfs, lit_turf)
///Clears the old affected turfs and populates the new ones.
/datum/component/overlay_lighting/proc/make_luminosity_update()
clean_old_turfs()
if(!isturf(current_holder?.loc))
return
if(directional)
cast_directional_light()
get_new_turfs()
///Adds the luminosity and source for the afected movable atoms to keep track of their visibility.
/datum/component/overlay_lighting/proc/add_dynamic_lumi()
var/atom/movable/light_source = GET_LIGHT_SOURCE
LAZYSET(light_source.affected_dynamic_lights, src, lumcount_range + 1)
light_source.vis_contents += visible_mask
light_source.update_dynamic_luminosity()
if(directional)
current_holder.vis_contents += cone
///Removes the luminosity and source for the afected movable atoms to keep track of their visibility.
/datum/component/overlay_lighting/proc/remove_dynamic_lumi()
var/atom/movable/light_source = GET_LIGHT_SOURCE
LAZYREMOVE(light_source.affected_dynamic_lights, src)
light_source.vis_contents -= visible_mask
light_source.update_dynamic_luminosity()
if(directional)
current_holder.vis_contents -= cone
directional_atom.moveToNullspace()
///Called to change the value of parent_attached_to.
/datum/component/overlay_lighting/proc/set_parent_attached_to(atom/movable/new_parent_attached_to)
if(new_parent_attached_to == parent_attached_to)
return
. = parent_attached_to
parent_attached_to = new_parent_attached_to
if(.)
var/atom/movable/old_parent_attached_to = .
UnregisterSignal(old_parent_attached_to, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE))
if(old_parent_attached_to == current_holder)
RegisterSignal(old_parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel)
RegisterSignal(old_parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved)
RegisterSignal(old_parent_attached_to, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater)
if(parent_attached_to)
if(parent_attached_to == current_holder)
UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE))
RegisterSignal(parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_parent_attached_to_qdel)
RegisterSignal(parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_parent_attached_to_moved)
RegisterSignal(parent_attached_to, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater)
check_holder()
///Called to change the value of current_holder.
/datum/component/overlay_lighting/proc/set_holder(atom/movable/new_holder)
if(new_holder == current_holder)
return
if(current_holder)
if(current_holder != parent && current_holder != parent_attached_to)
UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE))
if(directional)
UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE)
if(overlay_lighting_flags & LIGHTING_ON)
remove_dynamic_lumi()
current_holder = new_holder
if(new_holder == null)
clean_old_turfs()
return
if(new_holder != parent && new_holder != parent_attached_to)
RegisterSignal(new_holder, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel)
RegisterSignal(new_holder, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved)
RegisterSignal(new_holder, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater)
if(directional)
RegisterSignal(new_holder, COMSIG_ATOM_DIR_CHANGE, .proc/on_holder_dir_change)
if(overlay_lighting_flags & LIGHTING_ON)
make_luminosity_update()
add_dynamic_lumi()
///Used to determine the new valid current_holder from the parent's loc.
/datum/component/overlay_lighting/proc/check_holder()
var/atom/movable/movable_parent = GET_PARENT
if(isturf(movable_parent.loc))
set_holder(movable_parent)
return
var/atom/inside = movable_parent.loc //Parent's loc
if(isnull(inside))
set_holder(null)
return
if(isturf(inside.loc))
set_holder(inside)
return
set_holder(null)
///Called when the current_holder is qdeleted, to remove the light effect.
/datum/component/overlay_lighting/proc/on_holder_qdel(atom/movable/source, force)
SIGNAL_HANDLER
UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
if(directional)
UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE)
set_holder(null)
///Called when current_holder changes loc.
/datum/component/overlay_lighting/proc/on_holder_moved(atom/movable/source, OldLoc, Dir, Forced)
SIGNAL_HANDLER
if(!(overlay_lighting_flags & LIGHTING_ON))
return
make_luminosity_update()
///Called when parent changes loc.
/datum/component/overlay_lighting/proc/on_parent_moved(atom/movable/source, OldLoc, Dir, Forced)
SIGNAL_HANDLER
var/atom/movable/movable_parent = parent
if(overlay_lighting_flags & LIGHTING_ATTACHED)
set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null)
check_holder()
if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder)
return
make_luminosity_update()
///Called when the current_holder is qdeleted, to remove the light effect.
/datum/component/overlay_lighting/proc/on_parent_attached_to_qdel(atom/movable/source, force)
SIGNAL_HANDLER
UnregisterSignal(parent_attached_to, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
if(directional)
UnregisterSignal(parent_attached_to, COMSIG_ATOM_DIR_CHANGE)
if(parent_attached_to == current_holder)
set_holder(null)
set_parent_attached_to(null)
///Called when parent_attached_to changes loc.
/datum/component/overlay_lighting/proc/on_parent_attached_to_moved(atom/movable/source, OldLoc, Dir, Forced)
SIGNAL_HANDLER
check_holder()
if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder)
return
make_luminosity_update()
///Changes the range which the light reaches. 0 means no light, 6 is the maximum value.
/datum/component/overlay_lighting/proc/set_range(atom/source, old_range)
SIGNAL_HANDLER
var/new_range = source.light_range
if(range == new_range)
return
if(range == 0)
turn_off()
range = clamp(CEILING(new_range, 0.5), 1, 6)
var/pixel_bounds = ((range - 1) * 64) + 32
lumcount_range = CEILING(range, 1)
visible_mask.icon = light_overlays["[pixel_bounds]"]
if(pixel_bounds == 32)
visible_mask.transform = null
return
var/offset = (pixel_bounds - 32) * 0.5
var/matrix/transform = new
transform.Translate(-offset, -offset)
visible_mask.transform = transform
if(directional)
cast_range = clamp(round(new_range * 0.5), 1, 3)
if(overlay_lighting_flags & LIGHTING_ON)
make_luminosity_update()
///Changes the intensity/brightness of the light by altering the visual object's alpha.
/datum/component/overlay_lighting/proc/set_power(atom/source, old_power)
SIGNAL_HANDLER
var/new_power = source.light_power
set_lum_power(new_power >= 0 ? 0.5 : -0.5)
set_alpha = min(230, (abs(new_power) * 120) + 30)
visible_mask.alpha = set_alpha
if(directional)
cone.alpha = min(200, (abs(new_power) * 90)+20)
///Changes the light's color, pretty straightforward.
/datum/component/overlay_lighting/proc/set_color(atom/source, old_color)
SIGNAL_HANDLER
var/new_color = source.light_color
visible_mask.color = new_color
if(directional)
cone.color = new_color
///Toggles the light on and off.
/datum/component/overlay_lighting/proc/on_toggle(atom/source, old_value)
SIGNAL_HANDLER
var/new_value = source.light_on
if(new_value) //Truthy value input, turn on.
turn_on()
return
turn_off() //Falsey value, turn off.
///Triggered right after the parent light flags change.
/datum/component/overlay_lighting/proc/on_light_flags_change(atom/source, old_flags)
SIGNAL_HANDLER
var/new_flags = source.light_flags
var/atom/movable/movable_parent = parent
if(!((new_flags ^ old_flags) & LIGHT_ATTACHED))
return
if(new_flags & LIGHT_ATTACHED) // Gained the [LIGHT_ATTACHED] property
overlay_lighting_flags |= LIGHTING_ATTACHED
if(ismovable(movable_parent.loc))
set_parent_attached_to(movable_parent.loc)
else // Lost the [LIGHT_ATTACHED] property
overlay_lighting_flags &= ~LIGHTING_ATTACHED
set_parent_attached_to(null)
///Toggles the light on.
/datum/component/overlay_lighting/proc/turn_on()
if(overlay_lighting_flags & LIGHTING_ON)
return
if(current_holder)
if(directional)
cast_directional_light()
add_dynamic_lumi()
overlay_lighting_flags |= LIGHTING_ON
get_new_turfs()
///Toggles the light off.
/datum/component/overlay_lighting/proc/turn_off()
if(!(overlay_lighting_flags & LIGHTING_ON))
return
if(current_holder)
remove_dynamic_lumi()
overlay_lighting_flags &= ~LIGHTING_ON
clean_old_turfs()
///Here we append the behavior associated to changing lum_power.
/datum/component/overlay_lighting/proc/set_lum_power(new_lum_power)
if(lum_power == new_lum_power)
return
. = lum_power
lum_power = new_lum_power
var/difference = . - lum_power
for(var/t in affected_turfs)
var/turf/lit_turf = t
lit_turf.dynamic_lumcount -= difference
///Here we append the behavior associated to changing lum_power.
/datum/component/overlay_lighting/proc/cast_directional_light()
var/final_distance = cast_range
//Lower the distance by 1 if we're not looking at a cardinal direction, and we're not a short cast
if(final_distance > SHORT_CAST && !(ALL_CARDINALS & current_direction))
final_distance -= 1
var/turf/scanning = get_turf(current_holder)
for(var/i in 1 to final_distance)
var/turf/next_turf = get_step(scanning, current_direction)
if(isnull(next_turf) || IS_OPAQUE_TURF(next_turf))
break
scanning = next_turf
directional_atom.forceMove(scanning)
///Called when current_holder changes loc.
/datum/component/overlay_lighting/proc/on_holder_dir_change(atom/movable/source, olddir, newdir)
SIGNAL_HANDLER
set_direction(newdir)
///Called when parent changes loc.
/datum/component/overlay_lighting/proc/on_parent_dir_change(atom/movable/source, olddir, newdir)
SIGNAL_HANDLER
set_direction(newdir)
///Sets a new direction for the directional cast, then updates luminosity
/datum/component/overlay_lighting/proc/set_direction(newdir)
if(!newdir)
return
if(current_direction == newdir)
return
current_direction = newdir
cone.set_dir(newdir)
if(newdir & NORTH)
cone.pixel_y = 16
else if(newdir & SOUTH)
cone.pixel_y = -16
else
if(!isnull(cone_hint_y))
cone.pixel_y = cone_hint_y
else
cone.pixel_y = 0
if(newdir & EAST)
cone.pixel_x = 16
else if(newdir & WEST)
cone.pixel_x = -16
else
if(!isnull(cone_hint_x))
if(newdir & NORTH)
cone.pixel_x = -1*cone_hint_x
else
cone.pixel_x = cone_hint_x
else
cone.pixel_x = 0
if(overlay_lighting_flags & LIGHTING_ON)
make_luminosity_update()
/datum/component/overlay_lighting/proc/on_parent_crafted(datum/source, atom/movable/new_craft)
SIGNAL_HANDLER
if(!istype(new_craft))
return
UnregisterSignal(parent, COMSIG_ATOM_USED_IN_CRAFT)
RegisterSignal(new_craft, COMSIG_ATOM_USED_IN_CRAFT, .proc/on_parent_crafted)
set_parent_attached_to(new_craft)
/// Handles putting the source for overlay lights into the light eater queue since we aren't tracked by [/atom/var/light_sources]
/datum/component/overlay_lighting/proc/on_light_eater(datum/source, list/light_queue, datum/light_eater)
SIGNAL_HANDLER
light_queue[parent] = TRUE
return NONE
#undef LIGHTING_ON
#undef LIGHTING_ATTACHED
#undef GET_PARENT
#undef GET_LIGHT_SOURCE
#undef SHORT_CAST
+25 -13
View File
@@ -1,9 +1,9 @@
/**
* A holder for simple behaviour that can be attached to many different types
*
* Only one element of each type is instanced during game init.
* Otherwise acts basically like a lightweight component.
*/
* A holder for simple behaviour that can be attached to many different types
*
* Only one element of each type is instanced during game init.
* Otherwise acts basically like a lightweight component.
*/
/datum/element
/// Option flags for element behaviour
var/element_flags = NONE
@@ -18,17 +18,23 @@
/// Activates the functionality defined by the element on the given target datum
/datum/element/proc/Attach(datum/target)
SHOULD_CALL_PARENT(1)
SHOULD_CALL_PARENT(TRUE)
if(type == /datum/element)
return ELEMENT_INCOMPATIBLE
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
if(element_flags & ELEMENT_DETACH)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/OnTargetDelete, override = TRUE)
/datum/element/proc/OnTargetDelete(datum/source, force)
SIGNAL_HANDLER
Detach(source)
/// Deactivates the functionality defines by the element on the given datum
/datum/element/proc/Detach(datum/source, force)
/datum/element/proc/Detach(datum/source, ...)
SIGNAL_HANDLER
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
SHOULD_CALL_PARENT(1)
SHOULD_CALL_PARENT(TRUE)
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
/datum/element/Destroy(force)
@@ -41,15 +47,21 @@
/// Finds the singleton for the element type given and attaches it to src
/datum/proc/_AddElement(list/arguments)
if(QDELING(src))
CRASH("We just tried to add an element to a qdeleted datum, something is fucked")
var/datum/element/ele = SSdcs.GetElement(arguments)
arguments[1] = src
if(ele.Attach(arglist(arguments)) == ELEMENT_INCOMPATIBLE)
CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]")
/**
* Finds the singleton for the element type given and detaches it from src
* You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
*/
* Finds the singleton for the element type given and detaches it from src
* You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
*/
/datum/proc/_RemoveElement(list/arguments)
var/datum/element/ele = SSdcs.GetElement(arguments)
ele.Detach(src)
if(ele.element_flags & ELEMENT_COMPLEX_DETACH)
arguments[1] = src
ele.Detach(arglist(arguments))
else
ele.Detach(src)
+36
View File
@@ -0,0 +1,36 @@
/**
* Attached to movable atoms with opacity. Listens to them move and updates their old and new turf loc's opacity accordingly.
*/
/datum/element/light_blocking
element_flags = ELEMENT_DETACH
/datum/element/light_blocking/Attach(datum/target)
. = ..()
if(!ismovable(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/on_target_move)
var/atom/movable/movable_target = target
if(isturf(movable_target.loc))
var/turf/turf_loc = movable_target.loc
turf_loc.add_opacity_source(target)
/datum/element/light_blocking/Detach(atom/movable/target)
. = ..()
UnregisterSignal(target, list(COMSIG_MOVABLE_MOVED))
var/atom/movable/movable_target = target
if(isturf(movable_target.loc))
var/turf/turf_loc = movable_target.loc
turf_loc.remove_opacity_source(target)
///Updates old and new turf loc opacities.
/datum/element/light_blocking/proc/on_target_move(atom/movable/source, atom/OldLoc, Dir, Forced = FALSE)
SIGNAL_HANDLER
if(isturf(OldLoc))
var/turf/old_turf = OldLoc
old_turf.remove_opacity_source(source)
if(isturf(source.loc))
var/turf/new_turf = source.loc
new_turf.add_opacity_source(source)
@@ -1,160 +0,0 @@
/*
DO NOT USE THIS. THIS IS BEING DEPRECATED BY PROCESSING SUBSYSTEMS (controllers/subsystems/processing) AND TIMERS.
*/
/*
README:
The global_iterator datum is supposed to provide a simple and robust way to
create some constantly "looping" processes with ability to stop and restart them at will.
Generally, the only thing you want to play with (meaning, redefine) is the process() proc.
It must contain all the things you want done.
Control functions:
new - used to create datum. First argument (optional) - var list(to use in process() proc) as list,
second (optional) - autostart control.
If autostart == TRUE, the loop will be started immediately after datum creation.
start(list/arguments) - starts the loop. Takes arguments(optional) as a list, which is then used
by process() proc. Returns null if datum already active, 1 if loop started succesfully and 0 if there's
an error in supplied arguments (not list or empty list).
stop() - stops the loop. Returns null if datum is already inactive and 1 on success.
set_delay(new_delay) - sets the delay between iterations. Pretty selfexplanatory.
Returns 0 on error(new_delay is not numerical), 1 otherwise.
set_process_args(list/arguments) - passes the supplied arguments to the process() proc.
active() - Returns 1 if datum is active, 0 otherwise.
toggle() - toggles datum state. Returns new datum state (see active()).
Misc functions:
get_last_exec_time() - Returns the time of last iteration.
get_last_exec_time_as_text() - Returns the time of last iteration as text
Control vars:
delay - delay between iterations
check_for_null - if equals TRUE, on each iteration the supplied arguments will be checked for nulls.
If some varible equals null (and null only), the loop is stopped.
Usefull, if some var unexpectedly becomes null - due to object deletion, for example.
Of course, you can also check the variables inside process() proc to prevent runtime errors.
Data storage vars:
result - stores the value returned by process() proc
*/
/datum/global_iterator
var/control_switch = 0
var/delay = 10
var/list/arg_list = new
var/last_exec = null
var/check_for_null = 1
var/forbid_garbage = 0
var/result
var/state = 0
New(list/arguments=null,autostart=1)
delay = delay>0?(delay):1
if(forbid_garbage) //prevents garbage collection with tag != null
tag = "\ref[src]"
set_process_args(arguments)
if(autostart)
start()
return
proc/main()
state = 1
while(src && control_switch)
last_exec = world.timeofday
if(check_for_null && has_null_args())
stop()
return 0
result = process(arglist(arg_list))
for(var/sleep_time=delay;sleep_time>0;sleep_time--) //uhh, this is ugly. But I see no other way to terminate sleeping proc. Such disgrace.
if(!control_switch)
return 0
sleep(1)
return 0
proc/start(list/arguments=null)
if(active())
return
if(arguments)
if(!set_process_args(arguments))
return 0
if(!state_check()) //the main loop is sleeping, wait for it to terminate.
return
control_switch = 1
spawn()
state = main()
return 1
proc/stop()
if(!active())
return
control_switch = 0
spawn(-1) //report termination error but don't wait for state_check().
state_check()
return 1
proc/state_check()
var/lag = 0
while(state)
sleep(1)
if(++lag>10)
CRASH("The global_iterator loop \ref[src] failed to terminate in designated timeframe. This may be caused by server lagging.")
return 1
proc/active()
return control_switch
proc/has_null_args()
if(null in arg_list)
return 1
return 0
proc/set_delay(new_delay)
if(isnum(new_delay))
delay = max(1, round(new_delay))
return 1
else
return 0
proc/get_last_exec_time()
return (last_exec||0)
proc/get_last_exec_time_as_text()
return (time2text(last_exec)||"Wasn't executed yet")
proc/set_process_args(list/arguments)
if(arguments && istype(arguments, /list) && arguments.len)
arg_list = arguments
return 1
else
// to_world("<span class='danger'>Invalid arguments supplied for [src.type], ref = \ref[src]</span>")
return 0
proc/toggle_null_checks()
check_for_null = !check_for_null
return check_for_null
proc/toggle()
if(!stop())
start()
return active()
/datum/global_iterator/Destroy()
tag = null
arg_list.Cut()
stop()
return QDEL_HINT_LETMELIVE
//Do not call ..()
+6 -3
View File
@@ -10,10 +10,13 @@
plane = FLOAT_PLANE // No clue why this is 0 by default yet images are on FLOAT_PLANE
// And yes this does have to be in the constructor, BYOND ignores it if you set it as a normal var
// Helper similar to image()
/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER)
/// Helper similar to image()
/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, plane = FLOAT_PLANE, alpha = 255, appearance_flags = NONE)
var/mutable_appearance/MA = new()
MA.icon = icon
MA.icon_state = icon_state
MA.layer = layer
return MA
MA.plane = plane
MA.alpha = alpha
MA.appearance_flags |= appearance_flags
return MA
+2 -1
View File
@@ -66,7 +66,8 @@
/obj/item/weapon/surgical/bonegel,
/obj/item/weapon/surgical/retractor,
/obj/item/weapon/surgical/bonesetter,
/obj/item/weapon/surgical/circular_saw
/obj/item/weapon/surgical/circular_saw,
/obj/item/weapon/surgical/bioregen
)
cost = 25
containertype = /obj/structure/closet/crate/secure/veymed