Merge pull request #15486 from SandPoot/kills-cache

Solves issues with overlays by updating the whole subsystem
This commit is contained in:
deathride58
2024-04-12 23:31:54 -04:00
committed by GitHub
36 changed files with 280 additions and 214 deletions
-2
View File
@@ -33,8 +33,6 @@ GLOBAL_LIST_INIT(bitflags, list(
#define CONDUCT_1 (1<<5)
///For machines and structures that should not break into parts, eg, holodeck stuff.
#define NODECONSTRUCT_1 (1<<7)
///Atom queued to SSoverlay.
#define OVERLAY_QUEUED_1 (1<<8)
///Item has priority to check when entering or leaving.
#define ON_BORDER_1 (1<<9)
///Whether or not this atom shows screentips when hovered over
+24
View File
@@ -0,0 +1,24 @@
// A reasonable number of maximum overlays an object needs
// If you think you need more, rethink it
#define MAX_ATOM_OVERLAYS 100
/// Checks if an atom has reached the overlay limit, and make a loud error if it does.
#define VALIDATE_OVERLAY_LIMIT(changed_on) \
if(length(changed_on.overlays) >= MAX_ATOM_OVERLAYS) { \
var/text_lays = overlays2text(changed_on.overlays); \
stack_trace("Too many overlays on [changed_on.type] - [length(changed_on.overlays)], refusing to update and cutting.\
\n What follows is a printout of all existing overlays at the time of the overflow \n[text_lays]"); \
changed_on.overlays.Cut(); \
changed_on.add_overlay(mutable_appearance('icons/testing/greyscale_error.dmi')); \
} \
/// Performs any operations that ought to run after an appearance change
/* #define POST_OVERLAY_CHANGE(changed_on) \
if(alternate_appearances) { \
for(var/I in changed_on.alternate_appearances){\
var/datum/atom_hud/alternate_appearance/AA = changed_on.alternate_appearances[I];\
if(AA.transfer_overlays){\
AA.copy_overlays(changed_on, TRUE);\
}\
} \
} */
-19
View File
@@ -228,25 +228,6 @@
#define SSMOBS_DT (SSmobs.wait/10)
#define SSOBJ_DT (SSobj.wait/10)
//! ## Overlays subsystem
///Compile all the overlays for an atom from the cache lists
// |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway.
#define COMPILE_OVERLAYS(A)\
do {\
var/list/ad = A.add_overlays;\
var/list/rm = A.remove_overlays;\
if(LAZYLEN(rm)){\
A.overlays -= rm;\
rm.Cut();\
}\
if(LAZYLEN(ad)){\
A.overlays |= ad;\
ad.Cut();\
}\
A.flags_1 &= ~OVERLAY_QUEUED_1;\
} while(FALSE)
/**
Create a new timer and add it to the queue.
* Arguments:
-1
View File
@@ -25,7 +25,6 @@
var/icon/combined = new
for(var/d in GLOB.cardinals)
mannequin.setDir(d)
COMPILE_OVERLAYS(mannequin)
CHECK_TICK
var/icon/capture = getFlatIcon(mannequin)
CHECK_TICK
-1
View File
@@ -1065,7 +1065,6 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing")
COMPILE_OVERLAYS(body)
for(var/D in showDirs)
var/icon/partial = getFlatIcon(body, defdir = D, no_anim = no_anim)
out_icon.Insert(partial,dir=D)
-4
View File
@@ -79,10 +79,6 @@
#define CBT
#endif
// A reasonable number of maximum overlays an object needs
// If you think you need more, rethink it
#define MAX_ATOM_OVERLAYS 100
#if !defined(CBT) && !defined(SPACEMAN_DMM)
#warn Building with Dream Maker is no longer supported and will result in errors.
#warn In order to build, run BUILD.bat in the root directory.
-1
View File
@@ -164,7 +164,6 @@ DEFINE_BITFIELD(flags_1, list(
"NO_LAVA_GEN_1" = NO_LAVA_GEN_1,
"NO_RUINS_1" = NO_RUINS_1,
"NO_SCREENTIPS_1" = NO_SCREENTIPS_1,
"OVERLAY_QUEUED_1" = OVERLAY_QUEUED_1,
"ON_BORDER_1" = ON_BORDER_1,
"PREVENT_CLICK_UNDER_1" = PREVENT_CLICK_UNDER_1,
"PREVENT_CONTENTS_EXPLOSION_1" = PREVENT_CONTENTS_EXPLOSION_1,
+168 -144
View File
@@ -1,187 +1,114 @@
SUBSYSTEM_DEF(overlays)
name = "Overlay"
flags = SS_TICKER
wait = 1
priority = FIRE_PRIORITY_OVERLAYS
init_order = INIT_ORDER_OVERLAY
var/list/queue
flags = SS_NO_FIRE|SS_NO_INIT
var/list/stats
var/list/overlay_icon_state_caches
var/list/overlay_icon_cache
/datum/controller/subsystem/overlays/PreInit()
overlay_icon_state_caches = list()
overlay_icon_cache = list()
queue = list()
stats = list()
/datum/controller/subsystem/overlays/Initialize()
initialized = TRUE
fire(mc_check = FALSE)
return ..()
/datum/controller/subsystem/overlays/stat_entry(msg)
msg = "Ov:[length(queue)]"
return ..()
/datum/controller/subsystem/overlays/Shutdown()
text2file(render_stats(stats), "[GLOB.log_directory]/overlay.log")
/datum/controller/subsystem/overlays/Recover()
overlay_icon_state_caches = SSoverlays.overlay_icon_state_caches
overlay_icon_cache = SSoverlays.overlay_icon_cache
queue = SSoverlays.queue
stats = SSoverlays.stats
/datum/controller/subsystem/overlays/fire(resumed = FALSE, mc_check = TRUE)
var/list/queue = src.queue
var/static/count = 0
if (count)
var/c = count
count = 0 //so if we runtime on the Cut, we don't try again.
queue.Cut(1,c+1)
for (var/thing in queue)
count++
if(thing)
var/atom/A = thing
if(A.overlays.len >= MAX_ATOM_OVERLAYS)
//Break it real GOOD
stack_trace("Too many overlays on [A.type] - [A.overlays.len], refusing to update and cutting")
A.overlays.Cut()
continue
STAT_START_STOPWATCH
COMPILE_OVERLAYS(A)
UNSETEMPTY(A.add_overlays)
UNSETEMPTY(A.remove_overlays)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(stats, A.type)
if(mc_check)
if(MC_TICK_CHECK)
break
else
CHECK_TICK
if (count)
queue.Cut(1,count+1)
count = 0
/// Converts an overlay list into text for debug printing
/// Of note: overlays aren't actually mutable appearances, they're just appearances
/// Don't have access to that type tho, so this is the best you're gonna get
/proc/overlays2text(list/overlays)
var/list/unique_overlays = list()
// As anything because we're basically doing type coerrsion, rather then actually filtering for mutable apperances
for(var/mutable_appearance/overlay as anything in overlays)
var/key = "[overlay.icon]-[overlay.icon_state]-[overlay.dir]"
unique_overlays[key] += 1
var/list/output_text = list()
for(var/key in unique_overlays)
output_text += "([key]) = [unique_overlays[key]]"
return output_text.Join("\n")
/proc/iconstate2appearance(icon, iconstate)
var/static/image/stringbro = new()
var/list/icon_states_cache = SSoverlays.overlay_icon_state_caches
var/list/cached_icon = icon_states_cache[icon]
if (cached_icon)
var/cached_appearance = cached_icon["[iconstate]"]
if (cached_appearance)
return cached_appearance
stringbro.icon = icon
stringbro.icon_state = iconstate
if (!cached_icon) //not using the macro to save an associated lookup
cached_icon = list()
icon_states_cache[icon] = cached_icon
var/cached_appearance = stringbro.appearance
cached_icon["[iconstate]"] = cached_appearance
return cached_appearance
return stringbro.appearance
/proc/icon2appearance(icon)
var/static/image/iconbro = new()
var/list/icon_cache = SSoverlays.overlay_icon_cache
. = icon_cache[icon]
if (!.)
iconbro.icon = icon
. = iconbro.appearance
icon_cache[icon] = .
iconbro.icon = icon
return iconbro.appearance
/atom/proc/build_appearance_list(old_overlays)
var/static/image/appearance_bro = new()
var/list/new_overlays = list()
if (!islist(old_overlays))
old_overlays = list(old_overlays)
for (var/overlay in old_overlays)
/atom/proc/build_appearance_list(list/build_overlays)
if (!islist(build_overlays))
build_overlays = list(build_overlays)
for (var/overlay in build_overlays)
if(!overlay)
build_overlays -= overlay
continue
if (istext(overlay))
new_overlays += iconstate2appearance(icon, overlay)
#ifdef UNIT_TESTS
// This is too expensive to run normally but running it during CI is a good test
var/list/icon_states_available = icon_states(icon)
if(!(overlay in icon_states_available))
var/icon_file = "[icon]" || "Unknown Generated Icon"
stack_trace("Invalid overlay: Icon object '[icon_file]' [REF(icon)] used in '[src]' [type] is missing icon state [overlay].")
continue
#endif
var/index = build_overlays.Find(overlay)
build_overlays[index] = iconstate2appearance(icon, overlay)
else if(isicon(overlay))
new_overlays += icon2appearance(overlay)
else
if(isloc(overlay))
var/atom/A = overlay
if (A.flags_1 & OVERLAY_QUEUED_1)
COMPILE_OVERLAYS(A)
appearance_bro.appearance = overlay //this works for images and atoms too!
if(!ispath(overlay))
var/image/I = overlay
appearance_bro.dir = I.dir
new_overlays += appearance_bro.appearance
return new_overlays
var/index = build_overlays.Find(overlay)
build_overlays[index] = icon2appearance(overlay)
return build_overlays
#define NOT_QUEUED_ALREADY (!(flags_1 & OVERLAY_QUEUED_1))
#define QUEUE_FOR_COMPILE flags_1 |= OVERLAY_QUEUED_1; SSoverlays.queue += src;
/atom/proc/cut_overlays()
LAZYINITLIST(remove_overlays)
remove_overlays = overlays.Copy()
add_overlays = null
STAT_START_STOPWATCH
overlays = null
// POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
//If not already queued for work and there are overlays to remove
if(NOT_QUEUED_ALREADY && remove_overlays.len)
QUEUE_FOR_COMPILE
/atom/proc/cut_overlay(list/overlays)
/atom/proc/cut_overlay(list/remove_overlays)
if(!overlays)
return
overlays = build_appearance_list(overlays)
LAZYINITLIST(add_overlays)
LAZYINITLIST(remove_overlays)
var/a_len = add_overlays.len
var/r_len = remove_overlays.len
remove_overlays += overlays
add_overlays -= overlays
STAT_START_STOPWATCH
overlays -= build_appearance_list(remove_overlays)
// POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
var/fa_len = add_overlays.len
var/fr_len = remove_overlays.len
//If not already queued and there is work to be done
if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len ))
QUEUE_FOR_COMPILE
UNSETEMPTY(add_overlays)
/atom/proc/add_overlay(list/overlays)
/atom/proc/add_overlay(list/add_overlays)
if(!overlays)
return
STAT_START_STOPWATCH
overlays += build_appearance_list(add_overlays)
VALIDATE_OVERLAY_LIMIT(src)
// POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
overlays = build_appearance_list(overlays)
LAZYINITLIST(add_overlays) //always initialized after this point
var/a_len = add_overlays.len
add_overlays += overlays
var/fa_len = add_overlays.len
if(NOT_QUEUED_ALREADY && fa_len != a_len)
QUEUE_FOR_COMPILE
/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom
/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom
if(!other)
if(cut_old)
cut_overlays()
return
STAT_START_STOPWATCH
var/list/cached_other = other.overlays.Copy()
if(cached_other)
if(cut_old || !LAZYLEN(overlays))
remove_overlays = overlays
add_overlays = cached_other
if(NOT_QUEUED_ALREADY)
QUEUE_FOR_COMPILE
else if(cut_old)
cut_overlays()
#undef NOT_QUEUED_ALREADY
#undef QUEUE_FOR_COMPILE
if(cut_old)
if(cached_other)
overlays = cached_other
else
overlays = null
VALIDATE_OVERLAY_LIMIT(src)
// POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
else if(cached_other)
overlays += cached_other
VALIDATE_OVERLAY_LIMIT(src)
// POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
//TODO: Better solution for these?
/image/proc/add_overlay(x)
@@ -207,3 +134,100 @@ SUBSYSTEM_DEF(overlays)
overlays |= cached_other
else if(cut_old)
cut_overlays()
// Debug procs
/atom
/// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the overlays list
var/list/realized_overlays
/// List of underlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the underlays list
var/list/realized_underlays
/image
/// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the overlays list
var/list/realized_overlays
/// List of underlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the underlays list
var/list/realized_underlays
/// Takes the atoms's existing overlays and underlays, and makes them mutable so they can be properly vv'd in the realized_overlays/underlays list
/atom/proc/realize_overlays()
realized_overlays = realize_appearance_queue(overlays)
realized_underlays = realize_appearance_queue(underlays)
/// Takes the image's existing overlays, and makes them mutable so they can be properly vv'd in the realized_overlays list
/image/proc/realize_overlays()
realized_overlays = realize_appearance_queue(overlays)
realized_underlays = realize_appearance_queue(underlays)
/// Takes a list of appearnces, makes them mutable so they can be properly vv'd and inspected
/proc/realize_appearance_queue(list/appearances)
var/list/real_appearances = list()
var/list/queue = appearances.Copy()
var/queue_index = 0
while(queue_index < length(queue))
queue_index++
// If it's not a command, we assert that it's an appearance
var/mutable_appearance/appearance = queue[queue_index]
if(!appearance) // Who fucking adds nulls to their sublists god you people are the worst
continue
var/mutable_appearance/new_appearance = new /mutable_appearance()
new_appearance.appearance = appearance
var/key = "[appearance.icon]-[appearance.icon_state]-[appearance.plane]-[appearance.layer]-[appearance.dir]-[appearance.color]"
var/tmp_key = key
var/appearance_indx = 1
while(real_appearances[tmp_key])
tmp_key = "[key]-[appearance_indx]"
appearance_indx++
real_appearances[tmp_key] = new_appearance
var/add_index = queue_index
// Now check its children
for(var/mutable_appearance/child_appearance as anything in appearance.overlays)
add_index++
queue.Insert(add_index, child_appearance)
for(var/mutable_appearance/child_appearance as anything in appearance.underlays)
add_index++
queue.Insert(add_index, child_appearance)
return real_appearances
/// Takes two appearances as args, prints out, logs, and returns a text representation of their differences
/// Including suboverlays
/proc/diff_appearances(mutable_appearance/first, mutable_appearance/second, iter = 0)
var/list/diffs = list()
var/list/firstdeet = first.vars
var/list/seconddeet = second.vars
var/diff_found = FALSE
for(var/name in first.vars)
var/firstv = firstdeet[name]
var/secondv = seconddeet[name]
if(firstv ~= secondv)
continue
if((islist(firstv) || islist(secondv)) && length(firstv) == 0 && length(secondv) == 0)
continue
if(name == "vars") // Go away
continue
if(name == "_listen_lookup") // This is just gonna happen with marked datums, don't care
continue
if(name == "overlays")
first.realize_overlays()
second.realize_overlays()
var/overlays_differ = FALSE
for(var/i in 1 to length(first.realized_overlays))
if(diff_appearances(first.realized_overlays[i], second.realized_overlays[i], iter + 1))
overlays_differ = TRUE
if(!overlays_differ)
continue
diff_found = TRUE
diffs += "Diffs detected at [name]: First ([firstv]), Second ([secondv])"
var/text = "Depth of: [iter]\n\t[diffs.Join("\n\t")]"
message_admins(text)
log_world(text)
return diff_found
-1
View File
@@ -317,7 +317,6 @@
if(outfit_type)
mannequin.equipOutfit(outfit_type,TRUE)
mannequin.setDir(SOUTH)
COMPILE_OVERLAYS(mannequin)
. = image(mannequin)
unset_busy_human_dummy("HOLODISK_PRESET")
+15 -10
View File
@@ -43,18 +43,23 @@
/obj/machinery/computer/update_overlays()
. = ..()
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
if(stat & NOPOWER)
. += "[icon_keyboard]_off"
return
. += icon_keyboard
if(icon_keyboard)
if(stat & NOPOWER)
. += "[icon_keyboard]_off"
else
. += icon_keyboard
// This whole block lets screens ignore lighting and be visible even in the darkest room
// We can't do this for many things that emit light unfortunately because it layers over things that would be on top of it
var/overlay_state = icon_screen
if(stat & BROKEN)
overlay_state = "[icon_state]_broken"
. += mutable_appearance(icon, overlay_state)
. += emissive_appearance(icon, overlay_state)
. += mutable_appearance(icon, "[icon_state]_broken")
return // If we don't do this broken computers glow in the dark.
if(stat & NOPOWER) // Your screen can't be on if you've got no damn charge
return
// This lets screens ignore lighting and be visible even in the darkest room
if(icon_screen)
. += mutable_appearance(icon, icon_screen)
. += emissive_appearance(icon, icon_screen)
/obj/machinery/computer/power_change()
..()
+1 -1
View File
@@ -69,7 +69,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list(
name = "random arcade"
desc = "random arcade machine"
icon_state = "arcade"
icon_keyboard = "no_keyboard"
icon_keyboard = null
icon_screen = "invaders"
light_color = LIGHT_COLOR_GREEN
var/list/prize_override
+2 -1
View File
@@ -209,7 +209,7 @@
name = "security camera monitor"
desc = "An old TV hooked into the station's camera network."
icon_state = "television"
icon_keyboard = "no_keyboard"
icon_keyboard = null
icon_screen = "detective_tv"
pass_flags = PASSTABLE
@@ -252,6 +252,7 @@
desc = "Used for watching an empty arena."
icon = 'icons/obj/stationobjs.dmi'
icon_state = "telescreen"
icon_keyboard = null
layer = SIGN_LAYER
network = list("thunder")
density = FALSE
+2 -2
View File
@@ -138,13 +138,13 @@
name = "\improper DoorMex control console"
icon_state = "oldcomp"
icon_screen = "library"
icon_keyboard = "no_keyboard"
icon_keyboard = null
// /obj/machinery/computer/pod/old/mass_driver_controller
// name = "\improper Mass Driver Controller"
// icon = 'icons/obj/airlock_machines.dmi'
// icon_state = "airlock_control_standby"
// icon_keyboard = "no_keyboard"
// icon_keyboard = null
// density = FALSE
// /obj/machinery/computer/pod/old/mass_driver_controller/toxinsdriver
+1
View File
@@ -19,6 +19,7 @@
desc = "Gambling for the antisocial."
icon = 'icons/obj/economy.dmi'
icon_state = "slots1"
icon_keyboard = null
density = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 50
+3 -2
View File
@@ -558,8 +558,9 @@ RLD
. = ..()
if(has_ammobar)
var/ratio = CEILING((matter / max_matter) * ammo_sections, 1)
cut_overlays() //To prevent infinite stacking of overlays
add_overlay("[icon_state]_charge[ratio]")
if(ratio)
cut_overlays() //To prevent infinite stacking of overlays
add_overlay("[icon_state]_charge[ratio]")
/obj/item/construction/rcd/Initialize(mapload)
. = ..()
+47 -17
View File
@@ -19,6 +19,8 @@
var/on = FALSE //if the paddles are equipped (1) or on the defib (0)
var/safety = TRUE //if you can zap people with the defibs on harm mode
var/powered = FALSE //if there's a cell in the defib with enough power for a revive, blocks paddles from reviving otherwise
/// If the cell can be removed via screwdriver
var/cell_removable = TRUE
var/obj/item/shockpaddles/paddles
var/obj/item/stock_parts/cell/cell
var/combat = FALSE //if true, revive through hardsuits, allow for combat shocking, and tint paddles syndicate colors
@@ -29,6 +31,16 @@
var/timedeath = 10
var/disarm_shock_time = 10
var/always_emagged = FALSE
/// The icon state for the paddle overlay, not applied if null
var/paddle_state = "defibunit-paddles"
/// The icon state for the powered on overlay, not applied if null
var/powered_state = "defibunit-powered"
/// The icon state for the charge bar overlay, not applied if null
var/charge_state = "defibunit-charge"
/// The icon state for the missing cell overlay, not applied if null
var/nocell_state = "defibunit-nocell"
/// The icon state for the emagged overlay, not applied if null
var/emagged_state = "defibunit-emagged"
/obj/item/defibrillator/get_cell()
return cell
@@ -56,18 +68,19 @@
/obj/item/defibrillator/update_overlays()
. = ..()
if(!on)
. += "[initial(icon_state)]-paddles"
if(powered)
. += "[initial(icon_state)]-powered"
if(!QDELETED(cell))
if(!on && paddle_state)
. += paddle_state
if(powered && powered_state)
. += powered_state
if(!QDELETED(cell) && charge_state)
var/ratio = cell.charge / cell.maxcharge
ratio = CEILING(ratio*4, 1) * 25
add_overlay("[initial(icon_state)]-charge[ratio]")
if(!cell)
. += "[initial(icon_state)]-nocell"
if(!safety)
. += "[initial(icon_state)]-emagged"
. += "[charge_state][ratio]"
if(!cell && nocell_state)
. += "[nocell_state]"
if(!safety && emagged_state)
. += emagged_state
/obj/item/defibrillator/CheckParts(list/parts_list)
..()
@@ -103,6 +116,18 @@
var/atom/movable/screen/inventory/hand/H = over_object
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
/obj/item/defibrillator/screwdriver_act(mob/living/user, obj/item/tool)
if(!cell || !cell_removable)
return FALSE
cell.update_appearance()
cell.forceMove(get_turf(src))
balloon_alert(user, "removed [cell]")
cell = null
tool.play_tool_sound(src, 50)
update_power()
return TRUE
/obj/item/defibrillator/attackby(obj/item/W, mob/user, params)
if(W == paddles)
toggle_paddles()
@@ -120,13 +145,6 @@
to_chat(user, "<span class='notice'>You install a cell in [src].</span>")
update_power()
else if(W.tool_behaviour == TOOL_SCREWDRIVER)
if(cell)
cell.update_icon()
cell.forceMove(get_turf(src))
cell = null
to_chat(user, "<span class='notice'>You remove the cell from [src].</span>")
update_power()
else
return ..()
@@ -236,6 +254,11 @@
item_state = "defibcompact"
w_class = WEIGHT_CLASS_NORMAL
slot_flags = ITEM_SLOT_BELT
paddle_state = "defibcompact-paddles"
powered_state = "defibcompact-powered"
charge_state = "defibcompact-charge"
nocell_state = "defibcompact-nocell"
emagged_state = "defibcompact-emagged"
/obj/item/defibrillator/compact/item_action_slot_check(slot, mob/user, datum/action/A)
if(slot == user.getBeltSlot())
@@ -254,6 +277,13 @@
always_emagged = TRUE
disarm_shock_time = 0
cell = /obj/item/stock_parts/cell/infinite
paddles = /obj/item/shockpaddles/syndicate
paddle_state = "defibcombat-paddles"
powered_state = null
emagged_state = null
/obj/item/defibrillator/compact/combat/loaded
cell_removable = FALSE // Don't let people just have an infinite power cell
/obj/item/defibrillator/compact/combat/loaded/attackby(obj/item/W, mob/user, params)
if(W == paddles)
+1
View File
@@ -639,6 +639,7 @@
icon = 'icons/obj/cigarettes.dmi'
icon_state = "matchbox"
item_state = "zippo"
illustration = null
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_BELT
custom_price = PRICE_REALLY_CHEAP
@@ -76,7 +76,8 @@
. += "[icon_door_override ? icon_door : icon_state]_open"
return
. += "[icon_door || icon_state]_door"
if(icon_door)
. += "[icon_door || icon_state]_door"
if(welded)
. += icon_welded
@@ -3,6 +3,7 @@
name = "large cardboard box"
desc = "Just a box..."
icon_state = "cardboard"
icon_door = null
mob_storage_capacity = 1
resistance_flags = FLAMMABLE
max_integrity = 70
-1
View File
@@ -307,7 +307,6 @@ GLOBAL_VAR_INIT(say_disabled, FALSE)
qdel(I)
randomize_human(D)
JB.equip(D, TRUE, FALSE)
COMPILE_OVERLAYS(D)
var/icon/I = icon(getFlatIcon(D), frame = 1)
final.Insert(I, JB.title)
qdel(D)
@@ -314,7 +314,6 @@
equipAntagOnDummy(mannequin, ert)
COMPILE_OVERLAYS(mannequin)
CHECK_TICK
var/icon/preview_icon = icon('icons/effects/effects.dmi', "nothing")
preview_icon.Scale(48+32, 16+32)
@@ -391,7 +391,6 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/render_preview_outfit(datum/outfit/outfit, mob/living/carbon/human/dummy)
dummy = dummy || new /mob/living/carbon/human/dummy/consistent
dummy.equipOutfit(outfit, visualsOnly = TRUE)
COMPILE_OVERLAYS(dummy)
var/icon = getFlatIcon(dummy)
// We don't want to qdel the dummy right away, since its items haven't initialized yet.
@@ -13,6 +13,7 @@
icon = 'icons/obj/abductor.dmi'
icon_state = "camera"
icon_keyboard = null
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/obj/machinery/computer/camera_advanced/abductor/CreateEye()
-1
View File
@@ -1342,7 +1342,6 @@ GLOBAL_LIST_INIT(hallucination_list, list(
var/datum/preferences/prefs = C.client.prefs
var/mob/living/carbon/human/dummy/M = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_HALLUCINATION)
prefs.copy_to(M)
COMPILE_OVERLAYS(M)
CHECK_TICK
image = image(M,C)
unset_busy_human_dummy(DUMMY_HUMAN_SLOT_HALLUCINATION)
+1
View File
@@ -15,6 +15,7 @@
name = "auxillary base management console"
icon = 'icons/obj/terminals.dmi'
icon_state = "dorm_available"
icon_keyboard = null
var/shuttleId = "colony_drop"
desc = "Allows a deployable expedition base to be dropped from the station to a designated mining location. It can also \
interface with the mining shuttle at the landing site if a mobile beacon is also deployed."
@@ -70,7 +70,6 @@
mannequin.regenerate_icons()
COMPILE_OVERLAYS(mannequin)
parent.show_character_previews(new /mutable_appearance(mannequin))
unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES)
+4 -2
View File
@@ -20,7 +20,8 @@
var/chargerate = 100 //how much power is given every tick in a recharger
var/self_recharge = 0 //does it self recharge, over time, or not?
var/ratingdesc = TRUE
var/grown_battery = FALSE // If it's a grown that acts as a battery, add a wire overlay to it.
///If it's a grown that acts as a battery, add a wire overlay to it.
var/grown_battery = FALSE
rad_flags = RAD_NO_CONTAMINATE // Prevent the same cheese as with the stock parts
/obj/item/stock_parts/cell/get_cell()
@@ -61,7 +62,8 @@
/obj/item/stock_parts/cell/update_overlays()
. = ..()
if(grown_battery)
. += image('icons/obj/power.dmi',"grown_wires")
. += image('icons/obj/power.dmi', "grown_wires")
return
if(charge < 0.01)
return
else if(charge/maxcharge >=0.995)
@@ -220,6 +220,7 @@
can_suppress = FALSE
burst_size = 3
burst_shot_delay = 1
automatic_burst_overlay = FALSE
// Bulldog shotgun //
@@ -45,6 +45,8 @@
desc = "A modified version of the basic phaser gun, this one fires less concentrated energy bolts designed for target practice."
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/practice)
icon_state = "decloner"
//You have no icons for energy types, you're a decloner
modifystate = FALSE
/obj/item/gun/energy/e_gun/hos
name = "\improper X-01 MultiPhase Energy Gun"
@@ -78,6 +80,7 @@
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
ammo_type = list(/obj/item/ammo_casing/energy/net, /obj/item/ammo_casing/energy/trap)
modifystate = FALSE
can_flashlight = 0
ammo_x_offset = 1
@@ -7,6 +7,7 @@
density = TRUE
icon = 'icons/obj/chemical.dmi'
icon_state = "mixer0"
icon_keyboard = null
use_power = TRUE
idle_power_usage = 20
resistance_flags = ACID_PROOF
+1
View File
@@ -45,6 +45,7 @@
desc = "Controls the drop pod's launch system."
icon = 'icons/obj/terminals.dmi'
icon_state = "dorm_available"
icon_keyboard = null
light_color = LIGHT_COLOR_BLUE
req_access = list(ACCESS_SYNDICATE)
shuttleId = "steel_rain"