Merge branch 'master' into Arokha/machinerybreak

This commit is contained in:
Aronai Sieyes
2021-06-21 11:11:31 -04:00
committed by GitHub
999 changed files with 250656 additions and 483402 deletions
+1 -1
View File
@@ -1609,7 +1609,7 @@ datum/admins/var/obj/item/weapon/paper/admin/faxreply // var to hold fax replies
if(!P.stamped)
P.stamped = new
P.stamped += /obj/item/weapon/stamp/centcomm
P.overlays += stampoverlay
P.add_overlay(stampoverlay)
var/obj/item/rcvdcopy
rcvdcopy = destination.copy(P)
+1 -1
View File
@@ -126,7 +126,7 @@
if(path_display)
var/turf/T = src.path[1]
T.overlays -= path_overlay
T.cut_overlay(path_overlay)
// step_towards(holder, src.path[1])
if(holder.IMove(get_step_towards(holder, src.path[1])) != MOVEMENT_ON_COOLDOWN)
+2 -2
View File
@@ -14,7 +14,7 @@
ai_log("forget_path() : Entering.", AI_LOG_DEBUG)
if(path_display)
for(var/turf/T in path)
T.overlays -= path_overlay
T.cut_overlay(path_overlay)
path.Cut()
ai_log("forget_path() : Exiting.", AI_LOG_DEBUG)
@@ -49,7 +49,7 @@
ai_log("get_path() : Made new path.",AI_LOG_DEBUG)
if(path_display)
for(var/turf/T in path)
T.overlays |= path_overlay
T.add_overlay(path_overlay)
else
ai_log("get_path() : Failed to make new path. Exiting.",AI_LOG_DEBUG)
return 0
+3 -3
View File
@@ -222,17 +222,17 @@
lose_target_position()
if(last_turf_display && target_last_seen_turf)
target_last_seen_turf.overlays -= last_turf_overlay
target_last_seen_turf.cut_overlay(last_turf_overlay)
target_last_seen_turf = get_turf(target)
if(last_turf_display)
target_last_seen_turf.overlays += last_turf_overlay
target_last_seen_turf.add_overlay(last_turf_overlay)
// Resets the last known position to null.
/datum/ai_holder/proc/lose_target_position()
if(last_turf_display && target_last_seen_turf)
target_last_seen_turf.overlays -= last_turf_overlay
target_last_seen_turf.cut_overlay(last_turf_overlay)
ai_log("lose_target_position() : Last position is being reset.", AI_LOG_INFO)
target_last_seen_turf = null
+1 -1
View File
@@ -129,7 +129,7 @@
/obj/item/weapon/telecube/proc/teleport_to_mate(var/atom/movable/A, var/areaporting = FALSE)
. = FALSE
if(!A)
if(!istype(A))
return .
if(A == src || A == mate)
+1 -1
View File
@@ -3,7 +3,7 @@
desc = "A small electronic device able to ignite combustable substances."
icon_state = "igniter"
origin_tech = list(TECH_MAGNET = 1)
matter = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 50, "waste" = 10)
matter = list(DEFAULT_WALL_MATERIAL = 500, MAT_GLASS = 50)
secured = 1
wires = WIRE_RECEIVE
+1 -1
View File
@@ -5,7 +5,7 @@
desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted."
icon_state = "infrared"
origin_tech = list(TECH_MAGNET = 2)
matter = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 500, "waste" = 100)
matter = list(DEFAULT_WALL_MATERIAL = 1000, MAT_GLASS = 500)
wires = WIRE_PULSE
+1 -1
View File
@@ -3,7 +3,7 @@
desc = "A handy little spring-loaded trap for catching pesty rodents."
icon_state = "mousetrap"
origin_tech = list(TECH_COMBAT = 1)
matter = list(DEFAULT_WALL_MATERIAL = 100, "waste" = 10)
matter = list(DEFAULT_WALL_MATERIAL = 100)
var/armed = 0
+1 -1
View File
@@ -3,7 +3,7 @@
desc = "Used for scanning and alerting when someone enters a certain proximity."
icon_state = "prox"
origin_tech = list(TECH_MAGNET = 1)
matter = list(DEFAULT_WALL_MATERIAL = 800, "glass" = 200, "waste" = 50)
matter = list(DEFAULT_WALL_MATERIAL = 800, MAT_GLASS = 200)
wires = WIRE_PULSE
secured = 0
+1 -1
View File
@@ -4,7 +4,7 @@
icon_state = "signaller"
item_state = "signaler"
origin_tech = list(TECH_MAGNET = 1)
matter = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 200, "waste" = 100)
matter = list(DEFAULT_WALL_MATERIAL = 1000, MAT_GLASS = 200)
wires = WIRE_RECEIVE | WIRE_PULSE | WIRE_RADIO_PULSE | WIRE_RADIO_RECEIVE
secured = TRUE
+3 -3
View File
@@ -3,7 +3,7 @@
desc = "Used to time things. Works well with contraptions which has to count down. Tick tock."
icon_state = "timer"
origin_tech = list(TECH_MAGNET = 1)
matter = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 50, "waste" = 10)
matter = list(DEFAULT_WALL_MATERIAL = 500, MAT_GLASS = 50)
wires = WIRE_PULSE
@@ -53,10 +53,10 @@
time = 10
/obj/item/device/assembly/timer/update_icon()
overlays.Cut()
cut_overlays()
attached_overlays = list()
if(timing)
overlays += "timer_timing"
add_overlay("timer_timing")
attached_overlays += "timer_timing"
if(holder)
holder.update_icon()
+1 -1
View File
@@ -3,7 +3,7 @@
desc = "A small electronic device able to record a voice sample, and send a signal when that sample is repeated."
icon_state = "voice"
origin_tech = list(TECH_MAGNET = 1)
matter = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 50, "waste" = 10)
matter = list(DEFAULT_WALL_MATERIAL = 500, MAT_GLASS = 50)
var/listening = 0
var/recorded //the activation message
+17 -2
View File
@@ -1,11 +1,18 @@
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/tgui_common
// keep_local_name = TRUE
assets = list(
"tgui-common.bundle.js" = file("tgui/public/tgui-common.bundle.js"),
)
/datum/asset/simple/tgui
// keep_local_name = TRUE
assets = list(
"tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js',
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
"tgui.bundle.js" = file("tgui/public/tgui.bundle.js"),
"tgui.bundle.css" = file("tgui/public/tgui.bundle.css"),
)
/datum/asset/simple/headers
assets = list(
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
@@ -175,6 +182,14 @@
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
)
/datum/asset/simple/tgfont
assets = list(
"tgfont.eot" = file("tgui/packages/tgfont/dist/tgfont.eot"),
"tgfont.woff2" = file("tgui/packages/tgfont/dist/tgfont.woff2"),
"tgfont.css" = file("tgui/packages/tgfont/dist/tgfont.css"),
)
// /datum/asset/spritesheet/goonchat
// name = "chat"
+8 -1
View File
@@ -148,6 +148,13 @@ obj/machinery/gateway/centerstation/process()
if(dest)
M.forceMove(dest.loc)
M.set_dir(SOUTH)
//VOREStation Addition Start: Mcguffin time!
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.client)
awaygate.entrydetect()
//VOREStation Addition End: Mcguffin time!
//VOREStation Addition Start: Abduction!
if(istype(M, /mob/living) && dest.abductor)
var/mob/living/L = M
@@ -318,4 +325,4 @@ obj/machinery/gateway/centerstation/process()
else
to_chat(user, "<font color='blue'><b>Recalibration successful!</b>:</font><font color='black'> This gate's systems have been fine tuned. Travel to this gate will now be on target.</font>")
calibrated = 1
return
return
+79
View File
@@ -0,0 +1,79 @@
//This gateway type takes a special item that you will have to find on the map to activate, instead of using a multitool//
/obj/machinery/gateway/centeraway/mcguffin
icon = 'icons/obj/machines/gateway_vr.dmi'
calibrated = 0
var/mcguffin_type = /obj/item/device/mcguffin/brass //you should be able to change the var to be whatever kind of path you like, so maybe you can use other things on it sometimes
var/key //holds a ref to the key we spawned
/obj/machinery/gateway/centeraway/mcguffin/attackby(obj/item/device/W as obj, mob/user as mob)
if(calibrated && stationgate)
to_chat(user, "<span class='info'>The gate is already configured, you should be able to activate it.</span>")
return
else if(!stationgate)
to_chat(user, "<span class='danger'>Error: Configuration failed. No destination found... That can't be good.</span>")
return
if(istype(W,mcguffin_type) && !calibrated)
to_chat(user, "<span class='emote'>As the device nears the gateway, mechanical clunks and whirrs can be heard. <br><font color='blue'><b>Configuration successful! </b></font><br>This gate's systems have been fine tuned. Travel to this gate will now be on target.</span>")
calibrated = 1
return
else
to_chat(user, "<span class='danger'>This device does not seem to interface correctly with the gateway. Perhaps you should try something else.</span>")
return
//If you use this kind of gateway you NEED one of these on the map or the players won't be able to leave//
//You should use the random spawner though so it won't always be in the same place//
/obj/item/device/mcguffin/brass
name = "mysterious brass device"
desc = "A curious object made of what appears to be brass and silver. Its purpose is unclear by looking at it. Perhaps it should be used with something of similar materials?"
icon = 'icons/obj/machines/gateway_vr.dmi'
icon_state = "mcguffin"
drop_sound = 'sound/items/drop/wrench.ogg'
pickup_sound = 'sound/items/pickup/wrench.ogg'
/obj/effect/landmark/mcguffin_spawner
name = "gateway key spawner"
icon = 'icons/mob/randomlandmarks.dmi'
icon_state = "key"
/obj/machinery/gateway/centeraway/proc/entrydetect()
return
/obj/machinery/gateway/centeraway/mcguffin/entrydetect()
if(key)
return
var/list/spawners = list()
for(var/obj/effect/landmark/mcguffin_spawner/sp in world)
spawners += sp
var/obj/effect/landmark/mcguffin_spawner/the_cool_one = pick(spawners)
var/atom/destination = get_turf(the_cool_one)
var/obj/structure/closet/CL = locate() in destination
if(CL)
destination = CL
if(!destination)
warning("A gateway is trying to spawn it's mcguffin but there are no mapped in spawner landmarks")
destination = get_turf(src)
key = new mcguffin_type(destination)
/obj/machinery/gateway/centeraway/mcguffin/Bumped(atom/movable/M as mob|obj)
if(!ready) return
if(!active) return
M.forceMove(get_step(stationgate.loc, SOUTH))
M.set_dir(SOUTH)
M << 'sound/effects/swooshygate.ogg'
playsound(src, 'sound/effects/swooshygate.ogg', 100, 1)
/obj/machinery/gateway/brass
name = "mysterious brass gateway"
desc = "A gateway of strange construction. It appears to be made primarily of materials resembling brass and silver."
icon = 'icons/obj/machines/gateway_vr.dmi'
//No, you can't digest the key to leave the gateway.
/obj/item/device/mcguffin/digest_act(var/atom/movable/item_storage = null)
return FALSE
+3 -3
View File
@@ -119,14 +119,14 @@ var/list/blob_cores = list()
return ..()
/obj/structure/blob/core/update_icon()
overlays.Cut()
cut_overlays()
color = null
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
if(overmind)
blob_overlay.color = overmind.blob_type.color
name = "[overmind.blob_type.name] [base_name]"
overlays += blob_overlay
overlays += mutable_appearance('icons/mob/blob.dmi', "blob_core_overlay")
add_overlay(blob_overlay)
add_overlay("blob_core_overlay")
/obj/structure/blob/core/process()
set waitfor = FALSE
+3 -3
View File
@@ -21,14 +21,14 @@ var/list/blob_nodes = list()
return ..()
/obj/structure/blob/node/update_icon()
overlays.Cut()
cut_overlays()
color = null
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
if(overmind)
name = "[overmind.blob_type.name] [base_name]"
blob_overlay.color = overmind.blob_type.color
overlays += blob_overlay
overlays += mutable_appearance('icons/mob/blob.dmi', "blob_node_overlay")
add_overlay(blob_overlay)
add_overlay("blob_node_overlay")
/obj/structure/blob/node/process()
set waitfor = FALSE
+3 -3
View File
@@ -61,14 +61,14 @@
set_light(0)
if(is_infesting)
overlays.Cut()
cut_overlays()
icon = infested.icon
overlays = infested.overlays
add_overlay(infested.overlays)
var/mutable_appearance/blob_head_overlay = mutable_appearance('icons/mob/blob.dmi', "blob_head")
if(overmind)
blob_head_overlay.color = overmind.blob_type.complementary_color
color = initial(color)//looks better.
overlays += blob_head_overlay
add_overlay(blob_head_overlay)
/mob/living/simple_mob/hostile/blob/spore/Life()
if(can_infest && !is_infesting && isturf(src.loc))
@@ -338,6 +338,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
character.set_gender(pref.biological_gender)
// Destroy/cyborgize organs and limbs.
character.synthetic = null //Clear the existing var.
for(var/name in list(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_ARM, BP_R_ARM, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_GROIN, BP_TORSO))
var/status = pref.organ_data[name]
var/obj/item/organ/external/O = character.organs_by_name[name]
@@ -102,7 +102,7 @@
display_name = "pilot qualification pin"
description = "An iron pin denoting the qualification to fly SCG spacecraft."
path = /obj/item/clothing/accessory/solgov/specialty/pilot
allowed_roles = list("Pathfinder","Pilot","Field Medic","Talon Pilot")
allowed_roles = list("Pathfinder","Pilot","Field Medic","Talon Pilot")
/datum/gear/accessory/flops
display_name = "drop straps"
@@ -112,3 +112,11 @@
/datum/gear/accessory/flops/New()
..()
gear_tweaks += gear_tweak_free_color_choice
/*
Talon pin
*/
/datum/gear/accessory/talonpin
display_name = "ITV pin"
description = "A small enamel pin of the ITV logo."
path = /obj/item/clothing/accessory/talon
@@ -770,6 +770,12 @@
ckeywhitelist = list("pandora029")
character_name = list("Evelyn Tareen")
/datum/gear/fluff/evelyn_coat
path = /obj/item/clothing/suit/storage/hooded/wintercoat/security/fluff/evelyn/
display_name = "warden's navy winter coat"
ckeywhitelist = list("pandora029")
character_name = list("Evelyn Tareen")
/datum/gear/fluff/lily_medal
path = /obj/item/clothing/accessory/medal/silver/unity
display_name = "Lily's Unity Medal"
@@ -47,4 +47,16 @@
/datum/gear/head/tigerpeltpink
display_name = "pink tiger pelt"
path = /obj/item/clothing/head/pelt/tigerpeltpink
path = /obj/item/clothing/head/pelt/tigerpeltpink
/*
Talon hats
*/
/datum/gear/head/cap/talon
display_name = "cap, ITV"
path = /obj/item/clothing/head/soft/talon
/datum/gear/head/beret/talon
display_name = "beret, ITV"
path = /obj/item/clothing/head/beret
@@ -72,4 +72,11 @@
/datum/gear/suit/oversize/New()
..()
gear_tweaks += gear_tweak_free_color_choice
gear_tweaks += gear_tweak_free_color_choice
/*
Talon winter coat
*/
/datum/gear/suit/wintercoat/talon
display_name = "winter coat, ITV"
path = /obj/item/clothing/suit/storage/hooded/wintercoat/talon
@@ -215,4 +215,12 @@ Bluespace jumpsuit
/datum/gear/uniform/hfjumpsuit
display_name = "HYPER jumpsuit"
path = /obj/item/clothing/under/hyperfiber
cost = 2
cost = 2
/*
Talon jumpsuit
*/
/datum/gear/uniform/talonbasic
display_name = "ITV Jumpsuit"
description = "A jumpsuit that is usually issued to ITV contractors, however others can purchase it to show their support towards ITV."
path = /obj/item/clothing/under/rank/talon/basic
@@ -61,6 +61,10 @@
path = /obj/item/weapon/storage/backpack/dufflebag/explorer
allowed_roles = list("Pathfinder","Explorer")
/datum/gear/utility/dufflebag/talon
display_name = "ITV dufflebag"
path = /obj/item/weapon/storage/backpack/dufflebag/explorer
/datum/gear/utility/ID
display_name = "contractor identification card"
path = /obj/item/weapon/card/id/event/polymorphic/altcard
+9 -1
View File
@@ -86,7 +86,8 @@ datum/preferences
"2" = "character_preview_map:2,5",
"4" = "character_preview_map:2,3",
"8" = "character_preview_map:2,1",
"BG" = "character_preview_map:1,1 to 3,8"
"BG" = "character_preview_map:1,1 to 3,8",
"PMH" = "character_preview_map:2,7"
)
//Jobs, uses bitflags
@@ -270,6 +271,13 @@ datum/preferences
if(!client)
return
var/obj/screen/setup_preview/pm_helper/PMH = LAZYACCESS(char_render_holders, "PMH")
if(!PMH)
PMH = new
LAZYSET(char_render_holders, "PMH", PMH)
client.screen |= PMH
PMH.screen_loc = preview_screen_locs["PMH"]
var/obj/screen/setup_preview/bg/BG = LAZYACCESS(char_render_holders, "BG")
if(!BG)
BG = new
+76 -158
View File
@@ -6,55 +6,46 @@
var/list/Lines = list()
if(holder && (R_ADMIN & holder.rights || R_MOD & holder.rights))
for(var/client/C in GLOB.clients)
var/entry = "\t[C.key]"
if(C.holder && C.holder.fakekey)
entry += " <i>(as [C.holder.fakekey])</i>"
entry += " - Playing as [C.mob.real_name]"
switch(C.mob.stat)
if(UNCONSCIOUS)
entry += " - <font color='darkgray'><b>Unconscious</b></font>"
if(DEAD)
if(isobserver(C.mob))
var/mob/observer/dead/O = C.mob
if(O.started_as_observer)
entry += " - <font color='gray'>Observing</font>"
else
entry += " - <font color='black'><b>DEAD</b></font>"
for(var/client/C in GLOB.clients)
if(!check_rights_for(src, R_ADMIN|R_MOD))
Lines += "\t[C.holder?.fakekey || C.key]"
continue
var/entry = "\t[C.key]"
if(C.holder?.fakekey)
entry += " <i>(as [C.holder.fakekey])</i>"
entry += " - Playing as [C.mob.real_name]"
switch(C.mob.stat)
if(UNCONSCIOUS)
entry += " - <font color='darkgray'><b>Unconscious</b></font>"
if(DEAD)
if(isobserver(C.mob))
var/mob/observer/dead/O = C.mob
if(O.started_as_observer)
entry += " - <font color='gray'>Observing</font>"
else
entry += " - <font color='black'><b>DEAD</b></font>"
else
entry += " - <font color='black'><b>DEAD</b></font>"
var/age
if(isnum(C.player_age))
age = C.player_age
else
age = 0
if(C.player_age != initial(C.player_age) && isnum(C.player_age)) // database is on
var/age = C.player_age
switch(age)
if(0 to 1)
age = "<font color='#ff0000'><b>[age] days old</b></font>"
if(1 to 10)
age = "<font color='#ff8c00'><b>[age] days old</b></font>"
else
entry += " - [age] days old"
if(age <= 1)
age = "<font color='#ff0000'><b>[age]</b></font>"
else if(age < 10)
age = "<font color='#ff8c00'><b>[age]</b></font>"
if(is_special_character(C.mob))
entry += " - <b><font color='red'>Antagonist</font></b>"
entry += " - [age]"
if(C.is_afk())
var/seconds = C.last_activity_seconds()
entry += " (AFK - [round(seconds / 60)] minutes, [seconds % 60] seconds)"
if(is_special_character(C.mob))
entry += " - <b><font color='red'>Antagonist</font></b>"
if(C.is_afk())
var/seconds = C.last_activity_seconds()
entry += " (AFK - "
entry += "[round(seconds / 60)] minutes, "
entry += "[seconds % 60] seconds)"
entry += " (<A HREF='?_src_=holder;adminmoreinfo=\ref[C.mob]'>?</A>)"
Lines += entry
else
for(var/client/C in GLOB.clients)
if(C.holder && C.holder.fakekey)
Lines += C.holder.fakekey
else
Lines += C.key
entry += " (<A HREF='?_src_=holder;adminmoreinfo=\ref[C.mob]'>?</A>)"
Lines += entry
for(var/line in sortList(Lines))
msg += "[line]\n"
@@ -66,11 +57,6 @@
set category = "Admin"
set name = "Staffwho"
var/message = get_staffwho_message(holder)
to_chat(src, message)
// VOREStation Edit - This whole proc has various vorestation edits throughout. Practically every other line.
/proc/get_staffwho_message(datum/admins/holder)
var/msg = ""
var/modmsg = ""
var/devmsg = ""
@@ -79,117 +65,50 @@
var/num_admins_online = 0
var/num_devs_online = 0
var/num_event_managers_online = 0
if(holder)
for(var/client/C in GLOB.admins)
if(R_ADMIN & C.holder.rights && R_BAN & C.holder.rights)
if(C.holder.fakekey && !((R_ADMIN & holder.rights) || (R_MOD & holder.rights))) //Event Managerss can't see stealthmins
continue
msg += "\t[C] is a [C.holder.rank]"
if(C.holder.fakekey)
msg += " <i>(as [C.holder.fakekey])</i>"
if(isobserver(C.mob))
msg += " - Observing"
else if(istype(C.mob,/mob/new_player))
msg += " - Lobby"
else
msg += " - Playing"
if(C.is_afk())
var/seconds = C.last_activity_seconds()
msg += " (AFK - "
msg += "[round(seconds / 60)] minutes, "
msg += "[seconds % 60] seconds)"
msg += "\n"
num_admins_online++
else if(R_ADMIN & C.holder.rights && !(R_SERVER & C.holder.rights))
modmsg += "\t[C] is a [C.holder.rank]"
if(C.holder.fakekey && !((R_ADMIN & holder.rights) || (R_MOD & holder.rights)))
continue
if(C.holder.fakekey)
msg += " <i>(as [C.holder.fakekey])</i>"
if(isobserver(C.mob))
modmsg += " - Observing"
else if(istype(C.mob,/mob/new_player))
modmsg += " - Lobby"
else
modmsg += " - Playing"
if(C.is_afk())
var/seconds = C.last_activity_seconds()
modmsg += " (AFK - "
modmsg += "[round(seconds / 60)] minutes, "
modmsg += "[seconds % 60] seconds)"
modmsg += "\n"
num_mods_online++
else if(R_SERVER & C.holder.rights)
if(C.holder.fakekey && !((R_ADMIN & holder.rights) || (R_MOD & holder.rights)))
continue
devmsg += "\t[C] is a [C.holder.rank]"
if(C.holder.fakekey)
devmsg += " <i>(as [C.holder.fakekey])</i>"
if(isobserver(C.mob))
devmsg += " - Observing"
else if(istype(C.mob,/mob/new_player))
devmsg += " - Lobby"
else
devmsg += " - Playing"
if(C.is_afk())
var/seconds = C.last_activity_seconds()
devmsg += "(AFK - "
devmsg += "[round(seconds / 60)] minutes, "
devmsg += "[seconds % 60] seconds)"
devmsg += "\n"
num_devs_online++
for(var/client/C in GLOB.admins) // VOREStation Edit - GLOB
var/temp = ""
var/category = R_ADMIN
// VOREStation Edit - Apply stealthmin protection to all levels
if(C.holder.fakekey && check_rights(R_ADMIN|R_MOD, FALSE, src)) // Only admins and mods can see stealthmins
continue
// VOREStation Edit End
if(check_rights(R_BAN, FALSE, C)) // admins //VOREStation Edit
num_admins_online++
else if(check_rights(R_ADMIN, FALSE, C) && !check_rights(R_SERVER, FALSE, C)) // mods //VOREStation Edit: Game masters
category = R_MOD
num_mods_online++
else if(check_rights(R_SERVER, FALSE, C)) // developers
category = R_SERVER
num_devs_online++
else if(check_rights(R_STEALTH, FALSE, C)) // event managers //VOREStation Edit: Retired Staff
category = R_EVENT
num_event_managers_online++
temp += "\t[C] is a [C.holder.rank]"
if(holder)
if(C.holder.fakekey)
temp += " <i>(as [C.holder.fakekey])</i>"
if(isobserver(C.mob))
temp += " - Observing"
else if(istype(C.mob,/mob/new_player))
temp += " - Lobby"
else
if(C.holder.fakekey && !((R_ADMIN & holder.rights) || (R_MOD & holder.rights)))
continue
eventMmsg += "\t[C] is a [C.holder.rank]"
if(C.holder.fakekey)
eventMmsg += " <i>(as [C.holder.fakekey])</i>"
if(isobserver(C.mob))
eventMmsg += " - Observing"
else if(istype(C.mob,/mob/new_player))
eventMmsg += " - Lobby"
else
eventMmsg += " - Playing"
temp += " - Playing"
if(C.is_afk())
var/seconds = C.last_activity_seconds()
eventMmsg += " (AFK - "
eventMmsg += "[round(seconds / 60)] minutes, "
eventMmsg += "[seconds % 60] seconds)"
eventMmsg += "\n"
num_event_managers_online++
else
for(var/client/C in GLOB.admins)
if(R_ADMIN & C.holder.rights && R_BAN & C.holder.rights)
if(!C.holder.fakekey)
msg += "\t[C] is a [C.holder.rank]\n"
num_admins_online++
else if(R_ADMIN & C.holder.rights && !(R_SERVER & C.holder.rights))
if(!C.holder.fakekey)
modmsg += "\t[C] is a [C.holder.rank]\n"
num_mods_online++
else if(R_SERVER & C.holder.rights)
if(!C.holder.fakekey)
devmsg += "\t[C] is a [C.holder.rank]\n"
num_devs_online++
else
if(!C.holder.fakekey)
eventMmsg += "\t[C] is a [C.holder.rank]\n"
num_event_managers_online++
if(C.is_afk())
var/seconds = C.last_activity_seconds()
temp += " (AFK - [round(seconds / 60)] minutes, [seconds % 60] seconds)"
temp += "\n"
switch(category)
if(R_ADMIN)
msg += temp
if(R_MOD)
modmsg += temp
if(R_SERVER)
devmsg += temp
if(R_EVENT)
eventMmsg += temp
msg = "<b>Current Admins ([num_admins_online]):</b>\n" + msg
@@ -204,5 +123,4 @@
msg += "\n<span class='info'>Adminhelps are also sent to Discord. If no admins are available in game try anyway and an admin on Discord may see it and respond.</span>"
return msg
to_chat(src, msg)
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -19,7 +19,7 @@
//HELMET: May have a lighting overlay
/obj/item/clothing/head/make_worn_icon(var/body_type,var/slot_name,var/inhands,var/default_icon,var/default_layer = 0,var/icon/clip_mask = null)
var/image/standing = ..()
if(on && slot_name == slot_head_str)
if(light_on && slot_name == slot_head_str)
var/cache_key = "[light_overlay][LAZYACCESS(sprite_sheets,body_type) ? "_[body_type]" : ""]"
if(standing && light_overlay_cache[cache_key])
standing.add_overlay(light_overlay_cache[cache_key])
+2 -1
View File
@@ -2,7 +2,8 @@
name = "hard hat"
desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight."
icon_state = "hardhat0_yellow"
brightness_on = 4 //luminosity when on
light_range = 4 //luminosity when on
light_cone_y_offset = 14
light_overlay = "hardhat_light"
armor = list(melee = 30, bullet = 5, laser = 20,energy = 10, bomb = 20, bio = 10, rad = 20)
flags_inv = 0
+1 -1
View File
@@ -111,7 +111,7 @@
icon_state = "flexitac"
armor = list(melee = 40, bullet = 40, laser = 60, energy = 35, bomb = 30, bio = 0, rad = 0)
siemens_coefficient = 0.6
brightness_on = 6
light_range = 6
light_overlay = "helmet_light_dual_green"
action_button_name = "Toggle Head-light"
min_cold_protection_temperature = T0C - 20
+1
View File
@@ -152,6 +152,7 @@
light_range = 3
light_power = 1
light_color = "#B18B25" //clockwork slab background top color
light_on = TRUE
/obj/item/clothing/head/hood/winter/narsie
name = "runed winter hood"
+13 -6
View File
@@ -2,17 +2,17 @@
name = "techpriest hood"
armor = list(melee = 20, bullet = 10, laser = 10, energy = 10, bomb = 25, bio = 50, rad = 25)
// Armor versions here
// Armor versions here
/obj/item/clothing/head/hood/galahad
name = "galahad hood"
armor = list(melee = 80, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0)
siemens_coefficient = 2
/obj/item/clothing/head/hood/lancelot
name = "lancelot hood"
armor = list(melee = 80, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0)
siemens_coefficient = 2
/obj/item/clothing/head/hood/robin
name = "robin hood"
armor = list(melee = 80, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0)
@@ -21,9 +21,16 @@
// Costume Versions Here
/obj/item/clothing/head/hood/galahad_costume
name = "galahad costume hood"
/obj/item/clothing/head/hood/lancelot_costume
name = "lancelot costume hood"
/obj/item/clothing/head/hood/robin_costume
name = "robin costume hood"
name = "robin costume hood"
// Talon Winter Hood
/obj/item/clothing/head/hood/winter/talon
name = "ITV winter hood"
desc = "A cozy winter hood attached to a heavy winter jacket."
icon_override = 'icons/mob/head_vr.dmi'
icon_state = "winterhood_talon"
+1 -1
View File
@@ -167,7 +167,7 @@
icon_state = "hardhat0_pumpkin"//Could stand to be renamed
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR
body_parts_covered = HEAD|FACE|EYES
brightness_on = 2
light_range = 2
light_overlay = "jackolantern"
w_class = ITEMSIZE_NORMAL
drop_sound = 'sound/items/drop/herb.ogg'
+36 -1
View File
@@ -93,4 +93,39 @@
desc = "A fancy visor showing alignment to pizza delivery service. Extremely risky career choice."
icon_state = "pizzadelivery"
icon = 'icons/obj/clothing/hats_vr.dmi'
icon_override = 'icons/mob/head_vr.dmi'
icon_override = 'icons/mob/head_vr.dmi'
//////////TALON HATS//////////
/obj/item/clothing/head/soft/talon
name = "ITV baseball cap"
desc = "It's a ballcap bearing the colors of ITV."
icon = 'icons/obj/clothing/hats_vr.dmi'
icon_override = 'icons/mob/head_vr.dmi'
icon_state = "talonsoft"
item_state = "talonsoft"
item_state_slots = list(slot_r_hand_str = "blacksoft", slot_l_hand_str = "blacksoft")
/obj/item/clothing/head/caphat/talon
name = "ITV nautical hat"
desc = "It's a classic nautical hat bearing the colors of ITV. Perfect for commanding the Talon."
icon = 'icons/obj/clothing/hats_vr.dmi'
icon_override = 'icons/mob/head_vr.dmi'
icon_state = "talon_captain_cap"
item_state = "taloncaptaincap"
obj/item/clothing/head/beret/talon
name = "ITV beret"
desc = "It's a basic baret colored to match ITV's uniforms."
icon = 'icons/obj/clothing/hats_vr.dmi'
icon_override = 'icons/mob/head_vr.dmi'
icon_state = "beret_talon"
item_state = "baret_talon"
obj/item/clothing/head/beret/talon/command
name = "ITV officer beret"
desc = "It's a basic baret colored to match ITV's uniforms with a badge pinned on the front. Perfect for commanders."
icon = 'icons/obj/clothing/hats_vr.dmi'
icon_override = 'icons/mob/head_vr.dmi'
icon_state = "beret_talon_officer"
item_state = "baret_talon_command"
@@ -44,3 +44,24 @@
src.icon_state = initial(icon_state)
to_chat(user, "You lower the visor on the pilot helmet.")
update_clothing_icon() //so our mob-overlays update
//////////Talon Pilot Headgear//////////
/obj/item/clothing/head/pilot_vr/talon
name = "ITV pilot helmet"
desc = "An ITV version of the standard pilot helmet. Protects the head from impacts. This one has a retractable visor"
icon_state = "pilot3"
item_icons = list(slot_head_str = 'icons/mob/head_vr.dmi')
sprite_sheets = list(
SPECIES_TESHARI = 'icons/mob/species/teshari/helmet_vr.dmi'
)
action_button_name = "Toggle Visor"
/obj/item/clothing/head/pilot_vr/alt/attack_self(mob/user as mob)
if(src.icon_state == initial(icon_state))
src.icon_state = "[icon_state]up"
to_chat(user, "You raise the visor on the pilot helmet.")
else
src.icon_state = initial(icon_state)
to_chat(user, "You lower the visor on the pilot helmet.")
update_clothing_icon() //so our mob-overlays update
+4 -5
View File
@@ -585,8 +585,7 @@
/obj/item/weapon/rig/update_icon(var/update_mob_icon)
//TODO: Maybe consider a cache for this (use mob_icon as blank canvas, use suit icon overlay).
overlays.Cut()
cut_overlays()
if(!mob_icon || update_mob_icon)
var/species_icon = 'icons/mob/rig_back.dmi'
// Since setting mob_icon will override the species checks in
@@ -598,7 +597,7 @@
if(installed_modules.len)
for(var/obj/item/rig_module/module in installed_modules)
if(module.suit_overlay)
chest.overlays += image("icon" = 'icons/mob/rig_modules.dmi', "icon_state" = "[module.suit_overlay]", "dir" = SOUTH)
chest.add_overlay(image('icons/mob/rig_modules.dmi', icon_state = "[module.suit_overlay]", dir = SOUTH))
if(wearer)
wearer.update_inv_shoes()
@@ -729,8 +728,8 @@
to_chat(H, "<span class='notice'>Your [use_obj.name] [use_obj.gender == PLURAL ? "deploy" : "deploys"] swiftly.</span>")
playsound(src, 'sound/machines/rig/rigservo.ogg', 10, FALSE)
if(piece == "helmet" && helmet)
helmet.update_light(H)
if(piece == "helmet" && helmet?.light_system == STATIC_LIGHT)
helmet.update_light()
/obj/item/weapon/rig/proc/deploy(mob/M,var/sealed)
@@ -9,7 +9,7 @@
body_parts_covered = HEAD|FACE|EYES
heat_protection = HEAD|FACE|EYES
cold_protection = HEAD|FACE|EYES
brightness_on = 4
light_range = 4
sprite_sheets = list(
SPECIES_TAJ = 'icons/mob/species/tajaran/helmet.dmi',
SPECIES_SKRELL = 'icons/mob/species/skrell/helmet.dmi',
@@ -29,8 +29,7 @@
action_button_name = "Toggle Helmet Light"
light_overlay = "helmet_light"
brightness_on = 4
on = 0
light_range = 4
/obj/item/clothing/head/helmet/space/Initialize()
. = ..()
@@ -20,7 +20,7 @@
/obj/item/clothing/suit/space/void/responseteam/command/Initialize()
..()
helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/command //autoinstall the helmet
attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/command) //autoinstall the helmet
/obj/item/clothing/suit/space/void/responseteam/medical
name = "Mark VII-M Emergency Medical Response Suit"
@@ -29,7 +29,7 @@
/obj/item/clothing/suit/space/void/responseteam/medical/Initialize()
..()
helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/medical //autoinstall the helmet
attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/medical) //autoinstall the helmet
/obj/item/clothing/suit/space/void/responseteam/engineer
name = "Mark VII-E Emergency Engineering Response Suit"
@@ -38,7 +38,7 @@
/obj/item/clothing/suit/space/void/responseteam/engineer/Initialize()
..()
helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/engineer //autoinstall the helmet
attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/engineer) //autoinstall the helmet
/obj/item/clothing/suit/space/void/responseteam/security
name = "Mark VII-S Emergency Security Response Suit"
@@ -47,7 +47,7 @@
/obj/item/clothing/suit/space/void/responseteam/security/Initialize()
..()
helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/security //autoinstall the helmet
attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/security) //autoinstall the helmet
/obj/item/clothing/suit/space/void/responseteam/janitor
name = "Mark VII-J Emergency Cleanup Response Suit"
@@ -59,7 +59,7 @@
/obj/item/clothing/suit/space/void/responseteam/janitor/Initialize()
..()
helmet = new /obj/item/clothing/head/helmet/space/void/responseteam/janitor //autoinstall the helmet
attach_helmet(new /obj/item/clothing/head/helmet/space/void/responseteam/janitor) //autoinstall the helmet
//override the attackby screwdriver proc so that people can't remove the helmet
+21 -6
View File
@@ -120,7 +120,6 @@
to_chat(M, "Your suit's cooling unit deploys.")
cooler.canremove = 0
/obj/item/clothing/suit/space/void/dropped()
..()
@@ -150,6 +149,22 @@
cooler.canremove = 1
cooler.forceMove(src)
/obj/item/clothing/suit/space/void/proc/attach_helmet(var/obj/item/clothing/head/helmet/space/void/helm)
if(!istype(helm) || helmet)
return
helm.forceMove(src)
helm.set_light_flags(helm.light_flags | LIGHT_ATTACHED)
helmet = helm
/obj/item/clothing/suit/space/void/proc/remove_helmet()
if(!helmet)
return
helmet.forceMove(get_turf(src))
helmet.set_light_flags(helmet.light_flags & ~LIGHT_ATTACHED)
helmet = null
/obj/item/clothing/suit/space/void/verb/toggle_helmet()
set name = "Toggle Helmet"
@@ -184,7 +199,9 @@
helmet.pickup(H)
helmet.canremove = 0
to_chat(H, "<span class='info'>You deploy your suit helmet, sealing you off from the world.</span>")
helmet.update_light(H)
if(helmet.light_system == STATIC_LIGHT)
helmet.update_light()
/obj/item/clothing/suit/space/void/verb/eject_tank()
@@ -243,9 +260,8 @@
src.cooler = null
else if(choice == helmet)
to_chat(user, "You detach \the [helmet] from \the [src]'s helmet mount.")
helmet.forceMove(get_turf(src))
remove_helmet()
playsound(src, W.usesound, 50, 1)
src.helmet = null
else if(choice == boots)
to_chat(user, "You detach \the [boots] from \the [src]'s boot mounts.")
boots.forceMove(get_turf(src))
@@ -260,8 +276,7 @@
else
to_chat(user, "You attach \the [W] to \the [src]'s helmet mount.")
user.drop_item()
W.forceMove(src)
src.helmet = W
attach_helmet(W)
return
else if(istype(W,/obj/item/clothing/shoes/magboots))
if(boots)
+2
View File
@@ -322,6 +322,7 @@
light_range = 3
light_power = 1
light_color = "#B18B25" //clockwork slab background top color
light_on = TRUE
/obj/item/clothing/suit/storage/hooded/wintercoat/narsie
name = "runed winter coat"
@@ -336,6 +337,7 @@
hoodtype = /obj/item/clothing/head/hood/winter/cosmic
light_power = 1.8
light_range = 1.2
light_on = TRUE
// winter coats end here
+11 -1
View File
@@ -67,4 +67,14 @@
name = "crusader's armor"
desc = "ye olde knight, risen again. This one seems slightly faster than the rest, but weaker."
icon_state = "robin"
hoodtype = /obj/item/clothing/head/hood/robin_costume
hoodtype = /obj/item/clothing/head/hood/robin_costume
// Talon Winter Coat
/obj/item/clothing/suit/storage/hooded/wintercoat/talon
name = "ITV winter coat"
desc = "A cozy winter coat, covered in thick fur and baring the colors of ITV."
icon = 'icons/obj/clothing/suits_vr.dmi'
icon_override = 'icons/mob/suit_vr.dmi'
icon_state = "taloncoat"
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
hoodtype = /obj/item/clothing/head/hood/winter/talon
@@ -100,3 +100,12 @@
icon_override = 'icons/mob/suit_vr.dmi'
icon_state = "cyberpunksleek_long"
item_state = "cyberpunksleek_long"
//Talon Hoodie
/obj/item/clothing/suit/storage/toggle/hoodie/talon
name = "ITV hoodie"
desc = "A warm, blue sweatshirt bearing ITV markings."
icon = 'icons/obj/clothing/suits_vr.dmi'
icon_override = 'icons/mob/suit_vr.dmi'
icon_state = "talonhoodie"
item_state_slots = list(slot_r_hand_str = "suit_blue", slot_l_hand_str = "suit_blue")
@@ -366,3 +366,12 @@
item_state = "silverthree"
overlay_state = "silverthree"
desc = "A silver medal awarded to a group which has demonstrated exceptional teamwork to achieve a notable feat. This one has three bronze service stars, denoting that it has been awarded four times."
/obj/item/clothing/accessory/talon
name = "ITV pin"
desc = "A collectable enamel pin that resembles ITV's company logo."
icon = 'icons/obj/clothing/ties_vr.dmi'
icon_override = 'icons/mob/ties_vr.dmi'
icon_state = "talon_pin"
item_state = "talonpin"
overlay_state = "talonpin"
@@ -146,3 +146,60 @@
icon_state = "pizzadelivery"
item_state = "pizzadelivery"
rolled_down = 0
//////////////////////TALON JUMPSUITS//////////////////////
/obj/item/clothing/under/rank/talon/basic
name = "ITV jumpsuit"
desc = "A basic jumpsuit that bares the ITV logo on the breast."
icon = 'icons/obj/clothing/uniforms_vr.dmi'
index = "vr"
rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
icon_override = 'icons/mob/uniform_vr.dmi'
icon_state = "talon_basic"
item_state = "talon_basic"
rolled_sleeves = 0
/obj/item/clothing/under/rank/talon/proper
name = "ITV proper jumpsuit"
desc = "A neat and proper uniform for a proper company."
icon = 'icons/obj/clothing/uniforms_vr.dmi'
index = "vr"
rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
icon_override = 'icons/mob/uniform_vr.dmi'
icon_state = "talon_jumpsuit"
item_state = "talon_jumpsuit"
rolled_sleeves = 0
/obj/item/clothing/under/rank/talon/security
name = "ITV security jumpsuit"
desc = "A sleek, streamlined version of ITV's standard jumpsuit that bares security markings."
icon = 'icons/obj/clothing/uniforms_vr.dmi'
index = "vr"
rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
icon_override = 'icons/mob/uniform_vr.dmi'
icon_state = "talon_security"
item_state = "talon_security"
rolled_sleeves = 0
/obj/item/clothing/under/rank/talon/pilot
name = "ITV pilot jumpsuit"
desc = "A sleek, streamlined version of ITV's standard jumpsuit. Made from cushioned fabric to handle intense flight."
icon = 'icons/obj/clothing/uniforms_vr.dmi'
index = "vr"
rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
icon_override = 'icons/mob/uniform_vr.dmi'
icon_state = "talon_pilot"
item_state = "talon_pilot"
rolled_sleeves = 0
/obj/item/clothing/under/rank/talon/command
name = "ITV command jumpsuit"
desc = "A commanding jumpsuit fit for a commanding officer."
icon = 'icons/obj/clothing/uniforms_vr.dmi'
index = "vr"
rolled_down_icon = 'icons/mob/uniform_rolled_down_vr.dmi'
icon_override = 'icons/mob/uniform_vr.dmi'
icon_state = "talon_captain"
item_state = "talon_captain"
rolled_sleeves = 0
+1 -1
View File
@@ -75,7 +75,7 @@
var/set_overlays = (compass_static_labels | compass_waypoint_markers)
if(show_heading)
set_overlays |= compass_heading_marker
overlays = set_overlays
overlays = set_overlays // ???
/obj/compass_holder/proc/clear_waypoint(var/id)
LAZYREMOVE(compass_waypoints, id)
@@ -111,7 +111,8 @@
var/obj/item/weapon/paper/P = new(src)
P.name = "[src] report #[++report_num]: [bloodsamp.name]"
P.stamped = list(/obj/item/weapon/stamp)
P.overlays = list("paper_stamped")
P.cut_overlays()
P.add_overlay("paper_stamped")
//dna data itself
var/data = "No scan information available."
if(bloodsamp.dna != null)
@@ -62,8 +62,8 @@
var/image/img = image("icon"=I, "layer"=FLOAT_LAYER) //take a snapshot. (necessary to stop the underlays appearing under our inventory-HUD slots ~Carn
I.pixel_x = xx //and then return it
I.pixel_y = yy
overlays += img
overlays += "evidence" //should look nicer for transparent stuff. not really that important, but hey.
add_overlay(img)
add_overlay("evidence") //should look nicer for transparent stuff. not really that important, but hey.
desc = "An evidence bag containing [I]."
I.loc = src
@@ -77,7 +77,7 @@
var/obj/item/I = contents[1]
user.visible_message("[user] takes [I] out of [src]", "You take [I] out of [src].",\
"You hear someone rustle around in a plastic bag, and remove something.")
overlays.Cut() //remove the overlays
cut_overlays() //remove the overlays
user.put_in_hands(I)
stored_item = null
+2 -2
View File
@@ -42,7 +42,7 @@
stored_alpha.Cut()
if(reset_objects.len)
for(var/obj/item/I in reset_objects)
I.overlays -= I.blood_overlay
I.cut_overlay(I.blood_overlay)
if(I.fluorescent == 2) I.fluorescent = 1
reset_objects.Cut()
@@ -66,5 +66,5 @@
if(istype(A, /obj/item))
var/obj/item/O = A
if(O.was_bloodied && !(O.blood_overlay in O.overlays))
O.overlays |= O.blood_overlay
O.add_overlay(O.blood_overlay)
reset_objects |= O
+2 -2
View File
@@ -379,7 +379,7 @@ log transactions
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
R.overlays += stampoverlay
R.add_overlay(stampoverlay)
R.stamps += "<HR><i>This paper has been stamped by the Automatic Teller Machine.</i>"
if(prob(50))
@@ -421,7 +421,7 @@ log transactions
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
R.overlays += stampoverlay
R.add_overlay(stampoverlay)
R.stamps += "<HR><i>This paper has been stamped by the Automatic Teller Machine.</i>"
if(prob(50))
+1 -1
View File
@@ -69,7 +69,7 @@
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
R.overlays += stampoverlay
R.add_overlay(stampoverlay)
R.stamps += "<HR><i>This paper has been stamped by the Accounts Database.</i>"
//add the account
+2 -2
View File
@@ -44,7 +44,7 @@
R.offset_y += 0
R.ico += "paper_stamp-cent"
R.stamped += /obj/item/weapon/stamp
R.overlays += stampoverlay
R.add_overlay(stampoverlay)
R.stamps += "<HR><i>This paper has been stamped by the EFTPOS device.</i>"
/obj/item/device/eftpos/Destroy()
@@ -64,7 +64,7 @@
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
R.overlays += stampoverlay
R.add_overlay(stampoverlay)
R.stamps += "<HR><i>This paper has been stamped by the EFTPOS device.</i>"
var/obj/item/smallDelivery/D = new(R.loc)
R.loc = D
+3 -3
View File
@@ -36,7 +36,7 @@
qdel(src)
/obj/item/weapon/spacecash/update_icon()
overlays.Cut()
cut_overlays()
name = "[worth] [initial_name]\s"
if(worth in list(1000,500,200,100,50,20,10,1))
icon_state = "spacecash[worth]"
@@ -53,14 +53,14 @@
M.Translate(rand(-6, 6), rand(-4, 8))
M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45))
banknote.transform = M
src.overlays += banknote
add_overlay(banknote)
if(num == 0) // Less than one thaler, let's just make it look like 1 for ease
var/image/banknote = image('icons/obj/items.dmi', "spacecash1")
var/matrix/M = matrix()
M.Translate(rand(-6, 6), rand(-4, 8))
M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45))
banknote.transform = M
src.overlays += banknote
add_overlay(banknote)
src.desc = "They are worth [worth] [initial_name]s."
/obj/item/weapon/spacecash/proc/adjust_worth(var/adjust_worth = 0, var/update = 1)
+8 -8
View File
@@ -50,7 +50,7 @@
if(cash_stored)
spawn_money(cash_stored, loc, user)
cash_stored = 0
overlays -= "register_cash"
cut_overlay("register_cash")
else
open_cash_box()
else
@@ -181,7 +181,7 @@
if(cash_open)
to_chat(user, "You neatly sort the cash into the box.")
cash_stored += SC.worth
overlays |= "register_cash"
add_overlay("register_cash")
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.drop_from_inventory(SC)
@@ -468,15 +468,15 @@
if(cash_open)
cash_open = 0
overlays -= "register_approve"
overlays -= "register_open"
overlays -= "register_cash"
cut_overlay("register_approve")
cut_overlay("register_open")
cut_overlay("register_cash")
else if(!cash_locked)
cash_open = 1
overlays += "register_approve"
overlays += "register_open"
add_overlay("register_approve")
add_overlay("register_open")
if(cash_stored)
overlays += "register_cash"
add_overlay("register_cash")
else
to_chat(usr, "<span class='warning'>The cash box is locked.</span>")
+2 -2
View File
@@ -65,7 +65,7 @@
to_chat(user, "<span class='notice'>There already is a string attached to this coin.</span>")
return
if (CC.use(1))
overlays += image('icons/obj/items.dmi',"coin_string_overlay")
add_overlay("coin_string_overlay")
string_attached = 1
to_chat(user, "<span class='notice'>You attach a string to the coin.</span>")
else
@@ -79,7 +79,7 @@
var/obj/item/stack/cable_coil/CC = new/obj/item/stack/cable_coil(user.loc)
CC.amount = 1
CC.update_icon()
overlays = list()
cut_overlays()
string_attached = null
to_chat(user, "<font color='blue'>You detach the string from the coin.</font>")
else ..()
+55
View File
@@ -0,0 +1,55 @@
//Weird coins that I would prefer didn't work with normal vending machines. Might use them to make weird vending machines later.
/obj/item/weapon/aliencoin
icon = 'icons/obj/aliencoins.dmi'
name = "curious coin"
desc = "A curious triangular coin made primarily of some kind of dark, smooth metal. "
icon_state = "triangle"
randpixel = 8
force = 0.5
throwforce = 0.5
w_class = ITEMSIZE_TINY
slot_flags = SLOT_EARS
var/sides = 2
var/value = 1
drop_sound = 'sound/items/drop/ring.ogg'
pickup_sound = 'sound/items/pickup/ring.ogg'
/obj/item/weapon/aliencoin/New()
randpixel_xy()
/obj/item/weapon/aliencoin/gold
name = "curious coin"
icon_state = "triangle-g"
desc = "A curious triangular coin made primarily of some kind of dark, smooth metal. This one's markings appear to reveal a golden material underneath."
value = 3
/obj/item/weapon/aliencoin/silver
name = "curious coin"
icon_state = "triangle-s"
desc = "A curious triangular coin made primarily of some kind of dark, smooth metal. This one's markings appear to reveal a silver material underneath."
value = 2
/obj/item/weapon/aliencoin/phoron
name = "curious coin"
icon_state = "triangle-p"
desc = "A curious triangular coin made primarily of some kind of dark, smooth metal. This one's markings appear to reveal a purple material underneath."
value = 4
/obj/item/weapon/aliencoin/attack_self(mob/user as mob)
var/result = rand(1, sides)
var/comment = ""
if(result == 1)
comment = "tails"
else if(result == 2)
comment = "heads"
user.visible_message("<span class='notice'>[user] has thrown [src]. It lands on [comment]! </span>", runemessage = "[src] landed on [comment]")
if(rand(1,20) == 1)
user.visible_message("<span class='notice'>[user] fumbled the [src]!</span>", runemessage = "fumbles [src]")
user.remove_from_mob(src)
/obj/item/weapon/aliencoin/examine(var/mob/user)
. = ..()
if(Adjacent(user))
. += "<span class='notice'>It has some writing along its edge that seems to be some language that you are not familiar with. The face of the coin is very smooth, with what appears to be some kind of angular logo along the left side, and a couple of lines of the alien text along the opposite side. The reverse side is similarly smooth, the top of it features what appears to be some kind of vortex, surrounded by six stars, three on either side, with further swirls and intricate patterns along the bottom sections of this face. Looking closely, you can see that there is more text hidden among the swirls.</span>"
+7 -7
View File
@@ -12,7 +12,7 @@
emote_message_radio_synthetic = emote_message_synthetic_3p
/decl/emote/audible/deathgasp_alien
key = "deathgasp"
key = "adeathgasp"
emote_message_3p = "lets out a waning guttural screech, green blood bubbling from its maw."
/decl/emote/audible/whimper
@@ -29,7 +29,7 @@
emote_message_3p = "scretches."
/decl/emote/audible/choke
key ="choke"
key = "choke"
emote_message_3p = "chokes."
conscious = FALSE
@@ -63,7 +63,7 @@
emote_message_3p = "boops."
/decl/emote/audible/beep
key = "beep"
key = "bbeep"
emote_message_3p = "You beep."
emote_message_3p = "beeps."
emote_sound = 'sound/machines/twobeep.ogg'
@@ -133,18 +133,18 @@
emote_message_3p = "grunts."
/decl/emote/audible/bug_hiss
key ="hiss"
key = "bhiss"
emote_message_3p_target = "hisses at TARGET."
emote_message_3p = "hisses."
emote_sound = 'sound/voice/BugHiss.ogg'
/decl/emote/audible/bug_buzz
key ="buzz"
key = "bbuzz"
emote_message_3p = "buzzes its wings."
emote_sound = 'sound/voice/BugBuzz.ogg'
/decl/emote/audible/bug_chitter
key ="chitter"
key = "chitter"
emote_message_3p = "chitters."
emote_sound = 'sound/voice/Bug.ogg'
@@ -213,7 +213,7 @@
emote_sound = 'sound/voice/teshsqueak.ogg' // Copyright CC BY 3.0 InspectorJ (freesound.org) for the source audio.
/decl/emote/audible/teshchirp
key = "tchirp" // VOREStation Edit
key = "tchirp"
emote_message_1p = "You chirp!"
emote_message_3p = "chirps!"
emote_message_1p_target = "You chirp at TARGET!"
@@ -9,7 +9,7 @@
return "You [H.species.scream_verb_1p]!"
. = ..()
/decl/emote/audible/cough/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params)
/decl/emote/audible/scream/get_emote_message_3p(var/atom/user, var/atom/target, var/extra_params)
if(ishuman(user))
var/mob/living/carbon/human/H = user
return "[H.species.scream_verb_3p]!"
+5 -5
View File
@@ -12,21 +12,21 @@
return ..() && isslime(user)
/decl/emote/slime/pout
key = "pout"
key = "mpout"
mood = "pout"
/decl/emote/slime/sad
key = "sad"
key = "msad"
mood = "sad"
/decl/emote/slime/angry
key = "angry"
key = "mangry"
mood = "angry"
/decl/emote/slime/frown
key = "frown"
key = "mfrown"
mood = "mischevous"
/decl/emote/slime/smile
key = "smile"
key = "msmile"
mood = ":3"
+12 -12
View File
@@ -1,5 +1,5 @@
/decl/emote/visible
key ="tail"
key = "tail"
emote_message_3p = "waves USER_THEIR tail."
message_type = VISIBLE_MESSAGE
@@ -9,48 +9,48 @@
emote_message_3p = "scratches."
/decl/emote/visible/drool
key ="drool"
key = "drool"
emote_message_3p = "drools."
conscious = FALSE
/decl/emote/visible/nod
key ="nod"
key = "nod"
emote_message_3p_target = "nods USER_THEIR head at TARGET."
emote_message_3p = "nods USER_THEIR head."
/decl/emote/visible/sway
key ="sway"
key = "sways"
emote_message_3p = "sways around dizzily."
/decl/emote/visible/sulk
key ="sulk"
key = "sulk"
emote_message_3p = "sulks down sadly."
/decl/emote/visible/dance
key ="dance"
key = "dance"
check_restraints = TRUE
emote_message_3p = "dances around happily."
/decl/emote/visible/roll
key ="roll"
key = "roll"
check_restraints = TRUE
emote_message_3p = "rolls."
/decl/emote/visible/shake
key ="shake"
key = "shake"
emote_message_3p = "shakes USER_THEIR head."
/decl/emote/visible/jump
key ="jump"
key = "jump"
emote_message_3p = "jumps!"
/decl/emote/visible/shiver
key ="shiver"
key = "shiver"
emote_message_3p = "shivers."
conscious = FALSE
/decl/emote/visible/collapse
key ="collapse"
key = "collapse"
emote_message_3p = "collapses!"
/decl/emote/visible/collapse/do_extra(var/mob/user)
@@ -216,7 +216,7 @@
emote_message_3p = "vibrates!"
/decl/emote/visible/deathgasp_robot
key = "deathgasp"
key = "rdeathgasp"
emote_message_3p = "shudders violently for a moment, then becomes motionless, USER_THEIR eyes slowly darkening."
/decl/emote/visible/handshake
+1 -1
View File
@@ -79,7 +79,7 @@
return
if(!use_emote.mob_can_use(src))
to_chat(src, SPAN_WARNING("You cannot use the emote '[act]'. Type <b>say *help</b> for a list of usable emotes."))
to_chat(src, SPAN_WARNING("You cannot use the emote '[act]'. Type <b>say *help</b> for a list of usable emotes."))
return
if(m_type != use_emote.message_type && use_emote.conscious && stat != CONSCIOUS)
+1 -1
View File
@@ -78,7 +78,7 @@
/obj/item/weapon/material/fishing_net/update_icon() // Also updates name and desc
underlays.Cut()
overlays.Cut()
cut_overlays()
..()
+2 -2
View File
@@ -78,10 +78,10 @@
return ..()
/obj/item/weapon/material/fishing_rod/update_icon()
overlays.Cut()
cut_overlays()
..()
if(strung)
overlays += image(icon, "[icon_state]_string")
add_overlay("[icon_state]_string")
/obj/item/weapon/material/fishing_rod/proc/update_bait()
if(istype(Bait, bait_type))
@@ -118,8 +118,8 @@
glass_center_of_mass = list("x"=16, "y"=8)
glass_icon_file = 'icons/obj/drinks_vr.dmi'
/datum/reagent/ethanol/pink_moo
glass_icon_state = "pinkmooglass"
/datum/reagent/ethanol/pink_russian
glass_icon_state = "pinkrussianglass"
glass_center_of_mass = list("x"=16, "y"=9)
glass_icon_file = 'icons/obj/drinks_vr.dmi'
@@ -118,7 +118,7 @@
matter = list("glass" = 175)
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/shotglass/on_reagent_change()
overlays.Cut()
cut_overlays()
if(reagents.total_volume)
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]1")
@@ -129,7 +129,7 @@
if(8 to INFINITY) filling.icon_state = "[icon_state]12"
filling.color += reagents.get_color()
overlays += filling
add_overlay(filling)
name = "shot glass of " + reagents.get_master_reagent_name() //No matter what, the glass will tell you the reagent's name. Might be too abusable in the future.
else
name = "shot glass"
@@ -146,7 +146,7 @@
icon_state = pick("fitness-cup_black", "fitness-cup_red", "fitness-cup_black")
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/fitnessflask/on_reagent_change()
overlays.Cut()
cut_overlays()
if(reagents.total_volume)
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "fitness-cup10")
@@ -164,7 +164,7 @@
if(90 to INFINITY) filling.icon_state = "fitness-cup100"
filling.color += reagents.get_color()
overlays += filling
add_overlay(filling)
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/fitnessflask/proteinshake
name = "protein shake"
+3 -3
View File
@@ -46,7 +46,7 @@
var/fullname = "" //We need to build this from the contents of the var.
var/i = 0
overlays.Cut()
cut_overlays()
for(var/obj/item/weapon/reagent_containers/food/snacks/O in ingredients)
@@ -62,12 +62,12 @@
I.color = O.filling_color
I.pixel_x = pick(list(-1,0,1))
I.pixel_y = (i*2)+1
overlays += I
add_overlay(I)
var/image/T = new(src.icon, "sandwich_top")
T.pixel_x = pick(list(-1,0,1))
T.pixel_y = (ingredients.len * 2)+1
overlays += T
add_overlay(T)
name = lowertext("[fullname] sandwich")
if(length(name) > 80) name = "[pick(list("absurd","colossal","enormous","ridiculous"))] sandwich"
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -1,8 +1,8 @@
// Chaos cake
/datum/recipe/chaoscake_layerone
reagents = list("flour" = 300,"milk" = 200, "sugar" = 100, "egg" = 30)
fruit = list("poisonberries" = 15, "cherries" = 15)
reagents = list("flour" = 30,"milk" = 20, "sugar" = 10, "egg" = 9)
fruit = list("poisonberries" = 2, "cherries" = 2)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/meat/,
/obj/item/weapon/reagent_containers/food/snacks/meat/,
@@ -12,8 +12,8 @@
result = /obj/structure/chaoscake
/datum/recipe/chaoscake_layertwo
reagents = list("flour" = 300, "milk" = 200, "sugar" = 100, "egg" = 30, )
fruit = list("vanilla" = 15, "banana" = 15)
reagents = list("flour" = 30, "milk" = 20, "sugar" = 10, "egg" = 9, )
fruit = list("vanilla" = 2, "banana" = 2)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -23,8 +23,8 @@
result = /obj/item/weapon/chaoscake_layer
/datum/recipe/chaoscake_layerthree
reagents = list("flour" = 240, "milk" = 150, "sugar" = 80, "egg" = 24, "deathbell" = 100)
fruit = list("grapes" = 30)
reagents = list("flour" = 25, "milk" = 15, "sugar" = 10, "egg" = 6, "deathbell" = 10)
fruit = list("grapes" = 3)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -33,8 +33,8 @@
result = /obj/item/weapon/chaoscake_layer/three
/datum/recipe/chaoscake_layerfour
reagents = list("flour" = 240, "milk" = 150, "sugar" = 80, "egg" = 24, "milkshake" = 300)
fruit = list("rice" = 30)
reagents = list("flour" = 25, "milk" = 15, "sugar" = 10, "egg" = 6, "milkshake" = 30)
fruit = list("rice" = 3)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -43,14 +43,14 @@
result = /obj/item/weapon/chaoscake_layer/four
/datum/recipe/chaoscake_layerfive
reagents = list("flour" = 180, "milk" = 100, "sugar" = 60, "egg" = 18, "blood" = 300)
fruit = list("tomato" = 20)
reagents = list("flour" = 20, "milk" = 10, "sugar" = 10, "egg" = 6, "blood" = 30)
fruit = list("tomato" = 2)
items = list() //supposed to be made with lobster, still has to be ported.
result = /obj/item/weapon/chaoscake_layer/five
/datum/recipe/chaoscake_layersix
reagents = list("flour" = 180, "milk" = 100, "sugar" = 60, "egg" = 18, "sprinkles" = 10)
fruit = list("apple" = 30)
reagents = list("flour" = 20, "milk" = 10, "sugar" = 10, "egg" = 6, "sprinkles" = 5)
fruit = list("apple" = 2)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -62,8 +62,8 @@
result = /obj/item/weapon/chaoscake_layer/six
/datum/recipe/chaoscake_layerseven
reagents = list("flour" = 120, "milk" = 50, "sugar" = 40, "egg" = 12, "devilskiss" = 200)
fruit = list("potato" = 10)
reagents = list("flour" = 15, "milk" = 10, "sugar" = 5, "egg" = 3, "devilskiss" = 20)
fruit = list("potato" = 1)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -72,8 +72,8 @@
result = /obj/item/weapon/chaoscake_layer/seven
/datum/recipe/chaoscake_layereight
reagents = list("flour" = 120, "milk" = 50, "sugar" = 40, "egg" = 12, "cream" = 200)
fruit = list("lemon" = 10)
reagents = list("flour" = 15, "milk" = 10, "sugar" = 5, "egg" = 3, "cream" = 20)
fruit = list("lemon" = 1)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -82,8 +82,8 @@
result = /obj/item/weapon/chaoscake_layer/eight
/datum/recipe/chaoscake_layernine
reagents = list("water" = 100, "blood" = 100)
fruit = list("goldapple" = 50)
reagents = list("water" = 10, "blood" = 10)
fruit = list("goldapple" = 1)
items = list()
result = /obj/item/weapon/chaoscake_layer/nine
+6 -6
View File
@@ -55,14 +55,14 @@ var/global/ingredientLimit = 20
ingredients += S
if(src.addTop)
overlays -= topping //thank you Comic
if(!fullyCustom && !stackIngredients && overlays.len)
overlays -= filling //we can't directly modify the overlay, so we have to remove it and then add it again
cut_overlay(topping)
if(!fullyCustom && !stackIngredients && our_overlays.len)
cut_overlay(filling) //we can't directly modify the overlay, so we have to remove it and then add it again
var/newcolor = S.filling_color != "#FFFFFF" ? S.filling_color : AverageColor(getFlatIcon(S, S.dir, 0), 1, 1)
filling.color = BlendRGB(filling.color, newcolor, 1/ingredients.len)
overlays += filling
add_overlay(filling)
else
overlays += generateFilling(S)
add_overlay(generateFilling(S))
if(addTop)
drawTopping()
@@ -129,7 +129,7 @@ var/global/ingredientLimit = 20
/obj/item/weapon/reagent_containers/food/snacks/customizable/proc/drawTopping()
var/image/I = topping
I.pixel_y = (ingredients.len+1)*2
overlays += I
add_overlay(I)
// Sandwiches //////////////////////////////////////////////////
+3 -3
View File
@@ -35,7 +35,7 @@
icon_state = "bottle-[rand(1,4)]"
/obj/item/weapon/reagent_containers/glass/bottle/update_icon()
overlays.Cut()
cut_overlays()
if(reagents.total_volume && (icon_state == "bottle-1" || icon_state == "bottle-2" || icon_state == "bottle-3" || icon_state == "bottle-4"))
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10")
@@ -51,11 +51,11 @@
if(91 to INFINITY) filling.icon_state = "[icon_state]-100"
filling.color = reagents.get_color()
overlays += filling
add_overlay(filling)
if (!is_open_container())
var/image/lid = image(icon, src, "lid_bottle")
overlays += lid
add_overlay(lid)
/obj/item/weapon/reagent_containers/glass/bottle/inaprovaline
name = "inaprovaline bottle"
@@ -36,10 +36,10 @@
var/image/food_image = image(CI.object.icon, CI.object.icon_state)
food_image.color = CI.object.color
food_image.overlays += CI.object.overlays
food_image.add_overlay(CI.object.overlays)
food_image.transform *= 0.7
product.overlays += food_image
product.add_overlay(food_image)
*/
/obj/machinery/appliance/mixer/cereal/update_icon()
@@ -83,4 +83,4 @@
result.color = result.filling_color
for (var/i in images)
result.overlays += images[i]
result.add_overlay(images[i])
+6 -6
View File
@@ -58,20 +58,20 @@
/obj/machinery/gibber/New()
..()
src.overlays += image('icons/obj/kitchen.dmi', "grjam")
add_overlay("grjam")
/obj/machinery/gibber/update_icon()
overlays.Cut()
cut_overlays()
if (dirty)
src.overlays += image('icons/obj/kitchen.dmi', "grbloody")
add_overlay("grbloody")
if(stat & (NOPOWER|BROKEN))
return
if (!occupant)
src.overlays += image('icons/obj/kitchen.dmi', "grjam")
add_overlay("grjam")
else if (operating)
src.overlays += image('icons/obj/kitchen.dmi', "gruse")
add_overlay("gruse")
else
src.overlays += image('icons/obj/kitchen.dmi', "gridle")
add_overlay("gridle")
/obj/machinery/gibber/relaymove(mob/user as mob)
src.go_out()
+1 -1
View File
@@ -183,7 +183,7 @@
/obj/item/weapon/reagent_containers/food/snacks/icecream/proc/add_ice_cream(var/flavour_name)
name = "[flavour_name] icecream"
src.overlays += "icecream_[flavour_name]"
add_overlay("icecream_[flavour_name]")
desc = "Delicious [cone_type] cone with a dollop of [flavour_name] ice cream."
ice_creamed = 1
+8 -10
View File
@@ -314,20 +314,18 @@
// When exact is false, extraneous ingredients are ignored
// When exact is true, extraneous ingredients will fail the recipe
// In both cases, the full complement of required inredients is still needed
// In both cases, the full set of required ingredients is still needed
/proc/select_recipe(var/list/datum/recipe/available_recipes, var/obj/obj as obj, var/exact)
var/list/datum/recipe/possible_recipes = list()
var/highest_count = 0
var/count = 0
for (var/datum/recipe/recipe in available_recipes)
if(!recipe.check_reagents(obj.reagents, exact) || !recipe.check_items(obj, exact) || !recipe.check_fruit(obj, exact))
continue
possible_recipes |= recipe
if (!possible_recipes.len)
return null
else if (possible_recipes.len == 1)
return possible_recipes[1]
else //okay, let's select the most complicated recipe
sortTim(possible_recipes, /proc/cmp_recipe_complexity_dsc)
return possible_recipes[1]
// Taken from cmp_recipe_complexity_dsc, but is way faster.
count = LAZYLEN(recipe.items) + LAZYLEN(recipe.reagents) + LAZYLEN(recipe.fruit)
if(count >= highest_count)
highest_count = count
. = recipe
// Both of these are just placeholders to allow special behavior for mob holders, but you can do other things in here later if you feel like it.
/datum/recipe/proc/before_cook(obj/container) // Called Before the Microwave starts delays and cooking stuff
+3 -3
View File
@@ -410,7 +410,7 @@
name = "a playing card"
desc = "A playing card."
overlays.Cut()
cut_overlays()
if(cards.len == 1)
@@ -418,7 +418,7 @@
var/image/I = new(src.icon, (concealed ? "[P.back_icon]" : "[P.card_icon]") )
I.pixel_x += (-5+rand(10))
I.pixel_y += (-5+rand(10))
overlays += I
add_overlay(I)
return
var/offset = FLOOR(20/cards.len, 1)
@@ -450,7 +450,7 @@
else
I.pixel_x = -7+(offset*i)
I.transform = M
overlays += I
add_overlay(I)
i++
/obj/item/weapon/hand/dropped(mob/user as mob)
+4 -4
View File
@@ -20,15 +20,15 @@
legend.pixel_x = HOLOMAP_LEGEND_X(T.z)
legend.pixel_y = HOLOMAP_LEGEND_Y(T.z)
station_map.overlays |= cursor
station_map.overlays |= legend
station_map.add_overlay(cursor)
station_map.add_overlay(legend)
/datum/station_holomap/proc/initialize_holomap_bogus()
station_map = image('icons/480x480.dmi', "stationmap")
legend = image('icons/effects/64x64.dmi', "notfound")
legend.pixel_x = 7 * WORLD_ICON_SIZE
legend.pixel_y = 7 * WORLD_ICON_SIZE
station_map.overlays |= legend
station_map.add_overlay(legend)
// TODO - Strategic Holomap support
// /datum/station_holomap/strategic/initialize_holomap(var/turf/T, var/isAI=null, var/mob/user=null)
@@ -37,4 +37,4 @@
// legend = image('icons/effects/64x64.dmi', "strategic")
// legend.pixel_x = 3*WORLD_ICON_SIZE
// legend.pixel_y = 3*WORLD_ICON_SIZE
// station_map.overlays |= legend
// station_map.add_overlay(legend)
+26 -28
View File
@@ -265,7 +265,7 @@
markerImage.appearance_flags = RESET_COLOR|PIXEL_SCALE
markerImage.pixel_x = holomarker.x+holomarker.offset_x
markerImage.pixel_y = holomarker.y+holomarker.offset_y
map_app.overlays += markerImage
map_app.add_overlay(markerImage)
var/obj/screen/mapper/map/tmp = new()
tmp.appearance = map_app
@@ -286,13 +286,10 @@
continue
var/mob_indicator = HOLOMAP_ERROR
var/turf/TU = get_turf(HC)
if(TU.z != T_z)
// Mapper not on a turf or elsewhere
if(!TU || (TU.z != T_z))
continue
// Marker not on a turf
if(!TU)
continue
// We're the marker
if(HC == src)
mob_indicator = HOLOMAP_YOU
@@ -342,26 +339,27 @@
handle_marker(mark,TU.x,TU.y)
extras += mark
// Marker beacon items
for(var/hb in mapping_beacons)
var/obj/item/device/holomap_beacon/HB = hb
if(HB.mapper_filter != mapper_filter)
continue
var/turf/TB = get_turf(HB)
if(TU.z != T_z)
continue
var/marker_cache_key = "\ref[HB]_marker"
if(!(marker_cache_key in icon_image_cache))
var/obj/screen/mapper/marker/mark = new()
mark.icon_state = "beacon"
mark.layer = 1
icon_image_cache[marker_cache_key] = mark
var/obj/screen/mapper/marker/mark = icon_image_cache[marker_cache_key]
handle_marker(mark,TB.x,TB.y)
extras += mark
// Marker beacon items
for(var/hb in mapping_beacons)
var/obj/item/device/holomap_beacon/HB = hb
if(HB.mapper_filter != mapper_filter)
continue
var/turf/TB = get_turf(HB)
// Marker beacon not on a turf or elsewhere
if(!TB || (TB.z != T_z))
continue
var/marker_cache_key = "\ref[HB]_marker"
if(!(marker_cache_key in icon_image_cache))
var/obj/screen/mapper/marker/mark = new()
mark.icon_state = "beacon"
mark.layer = 1
icon_image_cache[marker_cache_key] = mark
var/obj/screen/mapper/marker/mark = icon_image_cache[marker_cache_key]
handle_marker(mark,TB.x,TB.y)
extras += mark
if(badmap)
var/obj/O = icon_image_cache["bad"]
@@ -419,7 +417,7 @@
else
in_list = FALSE
mapping_beacons -= src
icon_state = initial(icon_state) + in_list ? "_on" : ""
icon_state = "[initial(icon_state)][in_list ? "_on" : ""]"
to_chat(user,SPAN_NOTICE("The [src] is now [in_list ? "broadcasting" : "disabled"]."))
/obj/item/device/holomap_beacon/Destroy()
+6 -6
View File
@@ -169,7 +169,7 @@
if(!holomap_datum)
return //Not yet.
overlays.Cut()
cut_overlays()
if(stat & BROKEN)
icon_state = "station_mapb"
else if((stat & NOPOWER) || !anchored)
@@ -180,8 +180,8 @@
if(bogus)
holomap_datum.initialize_holomap_bogus()
else
small_station_map.icon = SSholomaps.extraMiniMaps["[HOLOMAP_EXTRA_STATIONMAPSMALL]_[original_zLevel]"]
overlays |= small_station_map
small_station_map = image(SSholomaps.extraMiniMaps["[HOLOMAP_EXTRA_STATIONMAPSMALL]_[original_zLevel]"], dir = src.dir)
add_overlay(small_station_map)
holomap_datum.initialize_holomap(get_turf(src))
// Put the little "map" overlay down where it looks nice
@@ -189,12 +189,12 @@
floor_markings.dir = src.dir
floor_markings.pixel_x = -src.pixel_x
floor_markings.pixel_y = -src.pixel_y
overlays += floor_markings
add_overlay(floor_markings)
if(panel_open)
overlays += "station_map-panel"
add_overlay("station_map-panel")
else
overlays -= "station_map-panel"
cut_overlay("station_map-panel")
/obj/machinery/station_map/attackby(obj/item/weapon/W as obj, mob/user as mob)
src.add_fingerprint(user)
+13 -13
View File
@@ -13,22 +13,22 @@
var/maxFrames = 5
/obj/machinery/beehive/update_icon()
overlays.Cut()
cut_overlays()
icon_state = "beehive"
if(closed)
overlays += "lid"
add_overlay("lid")
if(frames)
overlays += "empty[frames]"
add_overlay("empty[frames]")
if(honeycombs >= 100)
overlays += "full[round(honeycombs / 100)]"
add_overlay("full[round(honeycombs / 100)]")
if(!smoked)
switch(bee_count)
if(1 to 40)
overlays += "bees1"
add_overlay("bees1")
if(41 to 80)
overlays += "bees2"
add_overlay("bees2")
if(81 to 100)
overlays += "bees3"
add_overlay("bees3")
/obj/machinery/beehive/examine(var/mob/user)
. = ..()
@@ -217,7 +217,7 @@
/obj/item/honey_frame/filled/New()
..()
overlays += "honeycomb"
add_overlay("honeycomb")
/obj/item/beehive_assembly
name = "beehive assembly"
@@ -269,18 +269,18 @@ var/global/list/datum/stack_recipe/wax_recipes = list( \
/obj/item/bee_pack/New()
..()
overlays += "beepack-full"
add_overlay("beepack-full")
/obj/item/bee_pack/proc/empty()
full = 0
name = "empty bee pack"
desc = "A stasis pack for moving bees. It's empty."
overlays.Cut()
overlays += "beepack-empty"
cut_overlays()
add_overlay("beepack-empty")
/obj/item/bee_pack/proc/fill()
full = initial(full)
name = initial(name)
desc = initial(desc)
overlays.Cut()
overlays += "beepack-full"
cut_overlays()
add_overlay("beepack-full")
+6 -6
View File
@@ -125,7 +125,7 @@
/obj/item/weapon/reagent_containers/food/snacks/grown/update_icon()
if(!seed || !SSplants || !SSplants.plant_icon_cache)
return
overlays.Cut()
cut_overlays()
var/image/plant_icon
var/icon_key = "fruit-[seed.get_trait(TRAIT_PRODUCT_ICON)]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"
if(SSplants.plant_icon_cache[icon_key])
@@ -134,13 +134,13 @@
plant_icon = image('icons/obj/hydroponics_products.dmi',"blank")
var/image/fruit_base = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-product")
fruit_base.color = "[seed.get_trait(TRAIT_PRODUCT_COLOUR)]"
plant_icon.overlays |= fruit_base
plant_icon.add_overlay(fruit_base)
if("[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf" in cached_icon_states('icons/obj/hydroponics_products.dmi'))
var/image/fruit_leaves = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf")
fruit_leaves.color = "[seed.get_trait(TRAIT_PLANT_COLOUR)]"
plant_icon.overlays |= fruit_leaves
add_overlay(fruit_leaves)
SSplants.plant_icon_cache[icon_key] = plant_icon
overlays |= plant_icon
add_overlay(plant_icon)
/obj/item/weapon/reagent_containers/food/snacks/grown/Crossed(var/mob/living/M)
if(M.is_incorporeal())
@@ -363,9 +363,9 @@ var/list/fruit_icon_cache = list()
var/image/I = image(icon,"fruit_rind")
I.color = rind_colour
fruit_icon_cache["rind-[rind_colour]"] = I
overlays |= fruit_icon_cache["rind-[rind_colour]"]
add_overlay(fruit_icon_cache["rind-[rind_colour]"])
if(!fruit_icon_cache["slice-[rind_colour]"])
var/image/I = image(icon,"fruit_slice")
I.color = flesh_colour
fruit_icon_cache["slice-[rind_colour]"] = I
overlays |= fruit_icon_cache["slice-[rind_colour]"]
add_overlay(fruit_icon_cache["slice-[rind_colour]"])
+3 -3
View File
@@ -28,7 +28,7 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds)
if(!seed) return
// Update icon.
overlays.Cut()
cut_overlays()
var/is_seeds = ((seed.seed_noun in list("seeds","pits","nodes")) ? 1 : 0)
var/image/seed_mask
var/seed_base_key = "base-[is_seeds ? seed.get_trait(TRAIT_PLANT_COLOUR) : "spores"]"
@@ -49,8 +49,8 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds)
seed_overlay.color = seed.get_trait(TRAIT_PRODUCT_COLOUR)
plant_seed_sprites[seed_overlay_key] = seed_overlay
overlays |= seed_mask
overlays |= seed_overlay
add_overlay(seed_mask)
add_overlay(seed_overlay)
if(is_seeds)
src.name = "packet of [seed.seed_name] [seed.seed_noun]"
+2 -2
View File
@@ -405,9 +405,9 @@
panel_open = !panel_open
to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
playsound(src, O.usesound, 50, 1)
overlays.Cut()
cut_overlays()
if(panel_open)
overlays += image(icon, "[initial(icon_state)]-panel")
add_overlay("[initial(icon_state)]-panel")
else if((O.is_wirecutter() || istype(O, /obj/item/device/multitool)) && panel_open)
wires.Interact(user)
@@ -100,14 +100,14 @@ a creative player the means to solve many problems. Circuits are held inside an
data["power_draw_per_use"] = power_draw_per_use
data["extended_desc"] = extended_desc
var/list/inputs = list()
var/list/outputs = list()
var/list/activators = list()
var/list/inputs_list = list()
var/list/outputs_list = list()
var/list/activators_list = list()
for(var/datum/integrated_io/io in inputs)
inputs.Add(list(tgui_pin_data(io)))
inputs_list.Add(list(tgui_pin_data(io)))
for(var/datum/integrated_io/io in outputs)
outputs.Add(list(tgui_pin_data(io)))
outputs_list.Add(list(tgui_pin_data(io)))
for(var/datum/integrated_io/io in activators)
var/list/list/activator = list(
@@ -124,11 +124,11 @@ a creative player the means to solve many problems. Circuits are held inside an
"holder_name" = linked.holder.displayed_name,
)))
activators.Add(list(activator))
activators_list.Add(list(activator))
data["inputs"] = inputs
data["outputs"] = outputs
data["activators"] = activators
data["inputs"] = inputs_list
data["outputs"] = outputs_list
data["activators"] = activators_list
return data
+46
View File
@@ -0,0 +1,46 @@
/**
* Internal atom that copies an appearance on to the blocker plane
*
* Copies an appearance vis render_target and render_source on to the emissive blocking plane.
* This means that the atom in question will block any emissive sprites.
* This should only be used internally. If you are directly creating more of these, you're
* almost guaranteed to be doing something wrong.
*/
/atom/movable/emissive_blocker
name = "emissive blocker"
plane = PLANE_EMISSIVE
layer = FLOAT_LAYER
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
//Why?
//render_targets copy the transform of the target as well, but vis_contents also applies the transform
//to what's in it. Applying RESET_TRANSFORM here makes vis_contents not apply the transform.
//Since only render_target handles transform we don't get any applied transform "stacking"
appearance_flags = RESET_TRANSFORM
/atom/movable/emissive_blocker/Initialize(mapload, source)
. = ..()
verbs.Cut() //Cargo culting from lighting object, this maybe affects memory usage?
render_source = source
color = GLOB.em_block_color
/atom/movable/emissive_blocker/ex_act(severity)
return FALSE
/atom/movable/emissive_blocker/singularity_act()
return
/atom/movable/emissive_blocker/singularity_pull()
return
/atom/movable/emissive_blocker/blob_act()
return
/atom/movable/emissive_blocker/onTransitZ()
return
//Prevents people from moving these after creation, because they shouldn't be.
/atom/movable/emissive_blocker/forceMove(atom/destination, no_tp=FALSE, harderforce = FALSE)
if(harderforce)
return ..()
+185 -77
View File
@@ -1,110 +1,218 @@
/atom
var/light_power = 1 // intensity of the light
var/light_range = 0 // range in tiles of the light
var/light_color // Hexadecimal RGB string representing the colour of the light
///Light systems, both shouldn't be active at the same time.
var/light_system = STATIC_LIGHT
///Range of the light in tiles. Zero means no light.
var/light_range = 0
///Intensity of the light. The stronger, the less shadows you will see on the lit area.
var/light_power = 1
///Hexadecimal RGB string representing the colour of the light. White by default.
var/light_color = COLOR_WHITE
///Boolean variable for toggleable lights. Has no effect without the proper light_system, light_range and light_power values.
var/light_on = FALSE
///Bitflags to determine lighting-related atom properties.
var/light_flags = NONE
///Our light source. Don't fuck with this directly unless you have a good reason!
var/tmp/datum/light_source/light
///Any light sources that are "inside" of us, for example, if src here was a mob that's carrying a flashlight, that flashlight's light source would be part of this list.
var/tmp/list/light_sources
var/datum/light_source/light
var/list/light_sources
/atom/movable
///Hint for directional light cone positioning. X is relevant when facing north/south (this setting is for south and inverted for north)
var/light_cone_x_offset // When facing south, inverted when facing north
///Hint for directional light cone positioning. Y is relevant when facing east/west (same value used for both east and west)
var/light_cone_y_offset // When facing east/west, ignored for north/south (uses 16 in those cases)
///Highest-intensity light affecting us, which determines our visibility.
var/affecting_dynamic_lumi = 0
///Lazylist to keep track on the sources of illumination.
var/list/affected_dynamic_lights
///Either FALSE, [EMISSIVE_BLOCK_GENERIC], or [EMISSIVE_BLOCK_UNIQUE]
var/blocks_emissive = FALSE
///Internal holder for emissive blocker object, do not use directly use blocks_emissive
var/atom/movable/emissive_blocker/em_block
// Nonsensical value for l_color default, so we can detect if it gets set to null.
// The proc you should always use to set the light of this atom.
// Nonesensical value for l_color default, so we can detect if it gets set to null.
#define NONSENSICAL_VALUE -99999
/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE)
. = 0 //make it less costly if nothing's changed
/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, l_on)
if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE)
l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4, which is just barely brighter than the soft lighting that surrounds players.
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT, l_range, l_power, l_color, l_on) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
// Legacy behavior helper
if(l_range == 0)
l_on = FALSE
else if(l_range > 0)
l_on = TRUE
var/needs_update = FALSE
if(!isnull(l_power) && l_power != light_power)
if(!isnull(set_light_power(l_power)))
needs_update = TRUE
if(!isnull(l_range) && l_range != light_range)
if(!isnull(set_light_range(l_range)))
needs_update = TRUE
if(l_power != null && l_power != light_power)
light_power = l_power
. = 1
if(l_range != null && l_range != light_range)
light_range = l_range
. = 1
if(l_color != NONSENSICAL_VALUE && l_color != light_color)
light_color = l_color
. = 1
if(!isnull(set_light_color(l_color)))
needs_update = TRUE
if(.) update_light()
if(!isnull(l_on) && l_on != light_on)
if(!isnull(set_light_on(l_on)))
needs_update = TRUE
if(needs_update)
update_light()
#undef NONSENSICAL_VALUE
// Will update the light (duh).
// Creates or destroys it if needed, makes it update values, makes sure it's got the correct source turf...
/atom/proc/update_light()
set waitfor = FALSE
if (QDELETED(src))
return
if(!light_power || !light_range)
if(light)
light.destroy()
light = null
if(light_system != STATIC_LIGHT)
CRASH("update_light() for [src] with following light_system value: [light_system]")
if (!light_on || !light_power || !light_range) // We won't emit light anyways, destroy the light source.
QDEL_NULL(light)
else
if(!istype(loc, /atom/movable))
if (!ismovable(loc)) // We choose what atom should be the top atom of the light here.
. = src
else
. = loc
if(light)
if (light) // Update the light or create it if it does not exist.
light.update(.)
else
light = new /datum/light_source(src, .)
light = new/datum/light_source(src, .)
/atom/New()
. = ..()
if(light_power && light_range)
update_light()
if(opacity && isturf(loc))
var/turf/T = loc
T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guranteed to be on afterwards anyways.
/atom/Destroy()
if(light)
light.destroy()
light = null
return ..()
/atom/movable/Destroy()
var/turf/T = loc
if(opacity && istype(T))
T.reconsider_lights()
return ..()
/atom/movable/Moved(atom/old_loc, direction, forced = FALSE)
. = ..()
for(var/datum/light_source/L in light_sources)
L.source_atom.update_light()
var/turf/new_turf = loc
var/turf/old_turf = old_loc
if(istype(old_turf) && opacity)
old_turf.reconsider_lights()
if(istype(new_turf) && opacity)
new_turf.reconsider_lights()
/**
* Updates the atom's opacity value.
*
* This exists to act as a hook for associated behavior.
* It notifies (potentially) affected light sources so they can update (if needed).
*/
/atom/proc/set_opacity(new_opacity)
if(new_opacity == opacity)
return
SEND_SIGNAL(src, COMSIG_ATOM_SET_OPACITY, new_opacity)
. = opacity
opacity = new_opacity
var/turf/T = isturf(src) ? src : loc
if(!isturf(T))
/atom/movable/set_opacity(new_opacity)
. = ..()
if(isnull(.) || !isturf(loc))
return
if(new_opacity == TRUE)
T.has_opaque_atom = TRUE
T.reconsider_lights()
if(opacity)
AddElement(/datum/element/light_blocking)
else
var/old_has_opaque_atom = T.has_opaque_atom
T.recalc_atom_opacity()
if(old_has_opaque_atom != T.has_opaque_atom)
T.reconsider_lights()
RemoveElement(/datum/element/light_blocking)
/obj/item/equipped()
. = ..()
update_light()
/obj/item/pickup()
/turf/set_opacity(new_opacity)
. = ..()
update_light()
if(isnull(.))
return
recalculate_directional_opacity()
/obj/item/dropped()
. = ..()
update_light()
/atom/proc/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
return
/turf/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
if(!_duration)
stack_trace("Lighting FX obj created on a turf without a duration")
new /obj/effect/dummy/lighting_obj (src, _range, _power, _color, _duration)
/obj/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
if(!_duration)
stack_trace("Lighting FX obj created on a obj without a duration")
new /obj/effect/dummy/lighting_obj (get_turf(src), _range, _power, _color, _duration)
/mob/living/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
mob_light(_range, _power, _color, _duration)
/mob/living/proc/mob_light(_range, _power, _color, _duration)
var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj = new (src, _range, _power, _color, _duration)
return mob_light_obj
/// Setter for the light power of this atom.
/atom/proc/set_light_power(new_power)
if(new_power == light_power)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_POWER, new_power) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_power
light_power = new_power
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_POWER, .)
/// Setter for the light range of this atom.
/atom/proc/set_light_range(new_range)
if(new_range == light_range)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_RANGE, new_range) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_range
light_range = new_range
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_RANGE, .)
/// Setter for the light color of this atom.
/atom/proc/set_light_color(new_color)
if(new_color == light_color)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_COLOR, new_color) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_color
light_color = new_color
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_COLOR, .)
/// Setter for whether or not this atom's light is on.
/atom/proc/set_light_on(new_value)
if(new_value == light_on)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_ON, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_on
light_on = new_value
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_ON, .)
/// Setter for the light flags of this atom.
/atom/proc/set_light_flags(new_value)
if(new_value == light_flags)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_FLAGS, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_flags
light_flags = new_value
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_FLAGS, .)
///Keeps track of the sources of dynamic luminosity and updates our visibility with the highest.
/atom/movable/proc/update_dynamic_luminosity()
var/highest = 0
for(var/i in affected_dynamic_lights)
if(affected_dynamic_lights[i] <= highest)
continue
highest = affected_dynamic_lights[i]
if(highest == affecting_dynamic_lumi)
return
luminosity -= affecting_dynamic_lumi
affecting_dynamic_lumi = highest
luminosity += affecting_dynamic_lumi
///Helper to change several lighting overlay settings.
/atom/movable/proc/set_light_range_power_color(range, power, color)
set_light_range(range)
set_light_power(power)
set_light_color(color)
+113 -76
View File
@@ -1,41 +1,37 @@
/var/total_lighting_corners = 0
/var/datum/lighting_corner/dummy/dummy_lighting_corner = new
// Because we can control each corner of every lighting overlay.
// Because we can control each corner of every lighting object.
// And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't).
// For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting.
// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list.
/var/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST)
/datum/lighting_corner
var/list/turf/masters = list()
var/list/datum/light_source/affecting = list() // Light sources affecting us.
var/active = FALSE // TRUE if one of our masters has dynamic lighting.
var/list/datum/light_source/affecting // Light sources affecting us.
var/x = 0
var/y = 0
var/z = 0
var/x = 0
var/y = 0
var/turf/master_NE
var/turf/master_SE
var/turf/master_SW
var/turf/master_NW
//"raw" color values, changed by update_lumcount()
var/lum_r = 0
var/lum_g = 0
var/lum_b = 0
//true color values, guaranteed to be between 0 and 1
var/cache_r = LIGHTING_SOFT_THRESHOLD
var/cache_g = LIGHTING_SOFT_THRESHOLD
var/cache_b = LIGHTING_SOFT_THRESHOLD
///the maximum of lum_r, lum_g, and lum_b. if this is > 1 then the three cached color values are divided by this
var/largest_color_luminosity = 0
///whether we are to be added to SSlighting's corners_queue list for an update
var/needs_update = FALSE
var/cache_r = LIGHTING_SOFT_THRESHOLD
var/cache_g = LIGHTING_SOFT_THRESHOLD
var/cache_b = LIGHTING_SOFT_THRESHOLD
var/cache_mx = 0
var/update_gen = 0
/datum/lighting_corner/New(var/turf/new_turf, var/diagonal)
/datum/lighting_corner/New(turf/new_turf, diagonal)
. = ..()
total_lighting_corners++
masters[new_turf] = turn(diagonal, 180)
z = new_turf.z
save_master(new_turf, turn(diagonal, 180))
var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction.
var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one.
@@ -46,69 +42,75 @@
// My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal).
// Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered.
// So we'll have this hardcode instead.
var/turf/T
var/i
var/turf/new_master_turf
// Diagonal one is easy.
T = get_step(new_turf, diagonal)
if (T) // In case we're on the map's border.
if (!T.corners)
T.corners = list(null, null, null, null)
masters[T] = diagonal
i = LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180))
T.corners[i] = src
new_master_turf = get_step(new_turf, diagonal)
if (new_master_turf) // In case we're on the map's border.
save_master(new_master_turf, diagonal)
// Now the horizontal one.
T = get_step(new_turf, horizontal)
if (T) // Ditto.
if (!T.corners)
T.corners = list(null, null, null, null)
masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
T.corners[i] = src
new_master_turf = get_step(new_turf, horizontal)
if (new_master_turf) // Ditto.
save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
// And finally the vertical one.
T = get_step(new_turf, vertical)
if (T)
if (!T.corners)
T.corners = list(null, null, null, null)
new_master_turf = get_step(new_turf, vertical)
if (new_master_turf)
save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
T.corners[i] = src
/datum/lighting_corner/proc/save_master(turf/master, dir)
switch (dir)
if (NORTHEAST)
master_NE = master
master.lighting_corner_SW = src
if (SOUTHEAST)
master_SE = master
master.lighting_corner_NW = src
if (SOUTHWEST)
master_SW = master
master.lighting_corner_NE = src
if (NORTHWEST)
master_NW = master
master.lighting_corner_SE = src
update_active()
/datum/lighting_corner/proc/self_destruct_if_idle()
if (!LAZYLEN(affecting))
qdel(src, force = TRUE)
/datum/lighting_corner/proc/update_active()
active = FALSE
for (var/turf/T in masters)
if (T.lighting_overlay)
active = TRUE
/datum/lighting_corner/proc/vis_update()
for (var/datum/light_source/light_source as anything in affecting)
light_source.vis_update()
/datum/lighting_corner/proc/full_update()
for (var/datum/light_source/light_source as anything in affecting)
light_source.recalc_corner(src)
// God that was a mess, now to do the rest of the corner code! Hooray!
/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b)
/datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b)
if (!(delta_r || delta_g || delta_b)) // 0 is falsey ok
return
lum_r += delta_r
lum_g += delta_g
lum_b += delta_b
if (!needs_update)
needs_update = TRUE
lighting_update_corners += src
SSlighting.corners_queue += src
/datum/lighting_corner/proc/update_overlays()
// Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually.
var/lum_r = src.lum_r > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_r) : src.lum_r
var/lum_g = src.lum_g > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_g) : src.lum_g
var/lum_b = src.lum_b > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_b) : src.lum_b
var/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1.
/datum/lighting_corner/proc/update_objects()
// Cache these values ahead of time so 4 individual lighting objects don't all calculate them individually.
var/lum_r = src.lum_r
var/lum_g = src.lum_g
var/lum_b = src.lum_b
var/largest_color_luminosity = max(lum_r, lum_g, lum_b) // Scale it so one of them is the strongest lum, if it is above 1.
. = 1 // factor
if (mx > 1)
. = 1 / mx
if (largest_color_luminosity > 1)
. = 1 / largest_color_luminosity
#if LIGHTING_SOFT_THRESHOLD != 0
else if (mx < LIGHTING_SOFT_THRESHOLD)
else if (largest_color_luminosity < LIGHTING_SOFT_THRESHOLD)
. = 0 // 0 means soft lighting.
cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD
@@ -119,21 +121,56 @@
cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE)
cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE)
#endif
cache_mx = round(mx, LIGHTING_ROUND_VALUE)
for (var/TT in masters)
var/turf/T = TT
if (T.lighting_overlay)
if (!T.lighting_overlay.needs_update)
T.lighting_overlay.needs_update = TRUE
lighting_update_overlays += T.lighting_overlay
src.largest_color_luminosity = round(largest_color_luminosity, LIGHTING_ROUND_VALUE)
var/datum/lighting_object/lighting_object = master_NE?.lighting_object
if (lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
lighting_object = master_SE?.lighting_object
if (lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
lighting_object = master_SW?.lighting_object
if (lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
lighting_object = master_NW?.lighting_object
if (lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
self_destruct_if_idle()
/datum/lighting_corner/dummy/New()
return
/datum/lighting_corner/Destroy(var/force)
/datum/lighting_corner/Destroy(force)
if (!force)
return QDEL_HINT_LETMELIVE
crash_with("Who decided to force qdel() a lighting corner? Why did you do this?")
for (var/datum/light_source/light_source as anything in affecting)
LAZYREMOVE(light_source.effect_str, src)
affecting = null
if (master_NE)
master_NE.lighting_corner_SW = null
master_NE.lighting_corners_initialised = FALSE
if (master_SE)
master_SE.lighting_corner_NW = null
master_SE.lighting_corners_initialised = FALSE
if (master_SW)
master_SW.lighting_corner_NE = null
master_SW.lighting_corners_initialised = FALSE
if (master_NW)
master_NW.lighting_corner_SE = null
master_NW.lighting_corners_initialised = FALSE
if(needs_update)
SSlighting.corners_queue -= src
return ..()
+110 -23
View File
@@ -3,6 +3,8 @@
desc = "Deletes itself, but first updates all the lighting on outdoor turfs."
icon = 'icons/effects/effects_vr.dmi'
icon_state = "fakesun"
invisibility = INVISIBILITY_ABSTRACT
var/datum/light_source/sun/fake_sun
var/list/possible_light_setups = list(
list(
@@ -17,6 +19,22 @@
"brightness" = 2.5,
"color" = "#EE9AC6"
),
list(
"brightness" = 1.5,
"color" = "#F07AD8"
),
list(
"brightness" = 1.5,
"color" = "#61AEF3"
),
list(
"brightness" = 1,
"color" = "#f3932d"
),
list(
"brightness" = 1,
"color" = "#631E8A"
),
list(
"brightness" = 1.0,
"color" = "#A3A291"
@@ -66,28 +84,97 @@
/obj/effect/fake_sun/LateInitialize()
. = ..()
var/list/choice = pick(possible_light_setups)
if(choice["brightness"] <= LIGHTING_SOFT_THRESHOLD) // dark!
return
var/list/our_choice = pick(possible_light_setups)
fake_sun = new
fake_sun.light_color = choice["color"]
fake_sun.light_power = choice["brightness"]
var/list/zees = GetConnectedZlevels()
var/min = z
var/max = z
for(var/zee in zees)
if(zee < min)
min = z
if(zee > max)
max = z
var/list/all_turfs = block(locate(1, 1, min), locate(world.maxx, world.maxy, max))
var/list/turfs_to_use = list()
for(var/turf/T as anything in all_turfs)
if(T.outdoors)
turfs_to_use += T
// Calculate new values to apply
var/new_brightness = our_choice["brightness"]
var/new_color = our_choice["color"]
var/lum_r = new_brightness * GetRedPart (new_color) / 255
var/lum_g = new_brightness * GetGreenPart(new_color) / 255
var/lum_b = new_brightness * GetBluePart (new_color) / 255
var/static/update_gen = -1 // Used to prevent double-processing corners. Otherwise would happen when looping over adjacent turfs.
var/list/turfs = block(locate(1,1,z),locate(world.maxx,world.maxy,z))
for(var/turf/simulated/T as anything in turfs)
if(!T.lighting_overlay)
T.lighting_build_overlay()
if(!T.outdoors)
continue
for(var/C in T.get_corners())
var/datum/lighting_corner/LC = C
if(LC.update_gen != update_gen && LC.active)
LC.update_gen = update_gen
LC.update_lumcount(lum_r, lum_g, lum_b)
update_gen--
qdel(src)
if(!turfs_to_use.len)
warning("Fake sun placed on a level where it can't find any outdoor turfs to color at [x],[y],[z].")
return
fake_sun.update_corners(turfs_to_use)
/obj/effect/fake_sun/warm
name = "warm fake sun"
desc = "Deletes itself, but first updates all the lighting on outdoor turfs to warm colors."
possible_light_setups = list(
list(
"brightness" = 6.0,
"color" = "#E9FFB8"
),
list(
"brightness" = 4.0,
"color" = "#F4EA55"
),
list(
"brightness" = 1.0,
"color" = "#F07AD8"
),
list(
"brightness" = 1.0,
"color" = "#b4361f"
),
list(
"brightness" = 0.7,
"color" = "#f3932d"
),
list(
"brightness" = 0.1,
"color" = "#B92B00"
)
)
/obj/effect/fake_sun/cool
name = "fake sun"
desc = "Deletes itself, but first updates all the lighting on outdoor turfs to cool colors."
possible_light_setups = list(
list(
"brightness" = 6.0,
"color" = "#abfff7"
),
list(
"brightness" = 4.0,
"color" = "#2e30c9"
),
list(
"brightness" = 1.0,
"color" = "#61AEF3"
),
list(
"brightness" = 1.0,
"color" = "#61ddf3"
),
list(
"brightness" = 0.3,
"color" = "#253682"
),
list(
"brightness" = 0.1,
"color" = "#27024B"
)
)
+78 -100
View File
@@ -1,51 +1,51 @@
/var/total_lighting_overlays = 0
/atom/movable/lighting_overlay
name = ""
mouse_opacity = 0
simulated = 0
anchored = 1
icon = LIGHTING_ICON
plane = PLANE_LIGHTING
//invisibility = INVISIBILITY_LIGHTING
color = LIGHTING_BASE_MATRIX
icon_state = "light1"
//auto_init = 0 // doesn't need special init
blend_mode = BLEND_OVERLAY
var/lum_r = 0
var/lum_g = 0
var/lum_b = 0
/datum/lighting_object
///the underlay we are currently applying to our turf to apply light
var/mutable_appearance/current_underlay
///whether we are already in the SSlighting.objects_queue list
var/needs_update = FALSE
/atom/movable/lighting_overlay/Initialize()
// doesn't need special init
initialized = TRUE
return INITIALIZE_HINT_NORMAL
///the turf that our light is applied to
var/turf/affected_turf
/atom/movable/lighting_overlay/New(var/atom/loc, var/no_update = FALSE)
. = ..()
verbs.Cut()
total_lighting_overlays++
var/turf/T = loc //If this runtimes atleast we'll know what's creating overlays outside of turfs.
T.lighting_overlay = src
T.luminosity = 0
if(no_update)
/datum/lighting_object/New(turf/source)
if(!SSlighting.subsystem_initialized)
stack_trace("lighting_object created before SSlighting up!")
return
update_overlay()
/atom/movable/lighting_overlay/proc/update_overlay()
set waitfor = FALSE
var/turf/T = loc
if(!istype(T))
if(loc)
log_debug("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : "null"]) in update_overlay() and got qdel'ed!")
else
log_debug("A lighting overlay realised it was in nullspace in update_overlay() and got pooled!")
if(!isturf(source))
qdel(src, force=TRUE)
stack_trace("a lighting object was assigned to [source], a non turf! ")
return
. = ..()
current_underlay = mutable_appearance(LIGHTING_ICON, "transparent", source.z, PLANE_LIGHTING, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM)
affected_turf = source
if (affected_turf.lighting_object)
qdel(affected_turf.lighting_object, force = TRUE)
stack_trace("a lighting object was assigned to a turf that already had a lighting object!")
affected_turf.lighting_object = src
affected_turf.luminosity = 0
for(var/turf/space/space_tile in RANGE_TURFS(1, affected_turf))
space_tile.update_starlight()
needs_update = TRUE
SSlighting.objects_queue += src
/datum/lighting_object/Destroy(force)
if (!force)
return QDEL_HINT_LETMELIVE
SSlighting.objects_queue -= src
if (isturf(affected_turf))
affected_turf.lighting_object = null
affected_turf.luminosity = 1
affected_turf.underlays -= current_underlay
affected_turf = null
return ..()
/datum/lighting_object/proc/update()
// To the future coder who sees this and thinks
// "Why didn't he just use a loop?"
@@ -55,50 +55,54 @@
// Oh it's also shorter line wise.
// Including with these comments.
// See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are.
// No I seriously cannot think of a more efficient method, fuck off Comic.
var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new
var/datum/lighting_corner/cr = LAZYACCESS(T.corners,3) || dummy_lighting_corner
var/datum/lighting_corner/cg = LAZYACCESS(T.corners,2) || dummy_lighting_corner
var/datum/lighting_corner/cb = LAZYACCESS(T.corners,4) || dummy_lighting_corner
var/datum/lighting_corner/ca = LAZYACCESS(T.corners,1) || dummy_lighting_corner
var/datum/lighting_corner/red_corner = affected_turf.lighting_corner_SW || dummy_lighting_corner
var/datum/lighting_corner/green_corner = affected_turf.lighting_corner_SE || dummy_lighting_corner
var/datum/lighting_corner/blue_corner = affected_turf.lighting_corner_NW || dummy_lighting_corner
var/datum/lighting_corner/alpha_corner = affected_turf.lighting_corner_NE || dummy_lighting_corner
var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx)
var/max = max(red_corner.largest_color_luminosity, green_corner.largest_color_luminosity, blue_corner.largest_color_luminosity, alpha_corner.largest_color_luminosity)
var/rr = cr.cache_r
var/rg = cr.cache_g
var/rb = cr.cache_b
var/rr = red_corner.cache_r
var/rg = red_corner.cache_g
var/rb = red_corner.cache_b
var/gr = cg.cache_r
var/gg = cg.cache_g
var/gb = cg.cache_b
var/gr = green_corner.cache_r
var/gg = green_corner.cache_g
var/gb = green_corner.cache_b
var/br = cb.cache_r
var/bg = cb.cache_g
var/bb = cb.cache_b
var/br = blue_corner.cache_r
var/bg = blue_corner.cache_g
var/bb = blue_corner.cache_b
var/ar = ca.cache_r
var/ag = ca.cache_g
var/ab = ca.cache_b
var/ar = alpha_corner.cache_r
var/ag = alpha_corner.cache_g
var/ab = alpha_corner.cache_b
#if LIGHTING_SOFT_THRESHOLD != 0
var/set_luminosity = max > LIGHTING_SOFT_THRESHOLD
#else
// Because of floating points, it won't even be a flat 0.
// Because of floating points™?, it won't even be a flat 0.
// This number is mostly arbitrary.
var/set_luminosity = max > 1e-6
#endif
if((rr & gr & br & ar) && (rg + gg + bg + ag + rb + gb + bb + ab == 8))
//anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
icon_state = "transparent"
color = null
//anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "transparent"
current_underlay.color = null
affected_turf.underlays += current_underlay
else if(!set_luminosity)
icon_state = LIGHTING_ICON_STATE_DARK
color = null
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "dark"
current_underlay.color = null
affected_turf.underlays += current_underlay
else
icon_state = null
color = list(
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "gradient"
current_underlay.color = list(
rr, rg, rb, 00,
gr, gg, gb, 00,
br, bg, bb, 00,
@@ -106,38 +110,12 @@
00, 00, 00, 01
)
luminosity = set_luminosity
affected_turf.underlays += current_underlay
// Variety of overrides so the overlays don't get affected by weird things.
/atom/movable/lighting_overlay/ex_act()
return
affected_turf.luminosity = set_luminosity
/atom/movable/lighting_overlay/singularity_act()
return
/datum/lighting_object/proc/removefromturf()
affected_turf.underlays -= current_underlay
/atom/movable/lighting_overlay/singularity_pull()
return
/atom/movable/lighting_overlay/forceMove()
return 0 //should never move
/atom/movable/lighting_overlay/Move()
return 0
/atom/movable/lighting_overlay/throw_at()
return 0
/atom/movable/lighting_overlay/Destroy(var/force)
if (force)
total_lighting_overlays--
global.lighting_update_overlays -= src
LAZYREMOVE(SSlighting.currentrun, src)
var/turf/T = loc
if(istype(T))
T.lighting_overlay = null
T.luminosity = 1
return ..()
else
return QDEL_HINT_LETMELIVE
/datum/lighting_object/proc/addtoturf()
affected_turf.underlays += current_underlay
+4 -22
View File
@@ -1,24 +1,6 @@
// Create lighting overlays on all turfs with dynamic lighting in areas with dynamic lighting.
/proc/create_all_lighting_overlays()
for(var/area/A in world)
if(!A.dynamic_lighting)
continue
for(var/turf/T in A)
if(!T.dynamic_lighting)
continue
new /atom/movable/lighting_overlay(T, TRUE)
CHECK_TICK
/proc/create_all_lighting_objects()
var/list/all_turfs = block(locate(1,1,1), locate(world.maxx, world.maxy, world.maxz))
for(var/turf/T as anything in all_turfs)
T.lighting_build_overlay()
CHECK_TICK
/proc/create_lighting_overlays_zlevel(var/zlevel)
ASSERT(zlevel)
for(var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel)))
if(!T.dynamic_lighting)
continue
var/area/A = T.loc
if(!A.dynamic_lighting)
continue
new /atom/movable/lighting_overlay(T, TRUE)
+295 -210
View File
@@ -1,15 +1,22 @@
/var/total_lighting_sources = 0
// This is where the fun begins.
// These are the main datums that emit light.
/datum/light_source
var/atom/top_atom // The atom we're emitting light from(for example a mob if we're from a flashlight that's being held).
var/atom/source_atom // The atom that we belong to.
///The atom we're emitting light from (for example a mob if we're from a flashlight that's being held).
var/atom/top_atom
///The atom that we belong to.
var/atom/source_atom
var/turf/source_turf // The turf under the above.
var/light_power // Intensity of the emitter light.
var/light_range // The range of the emitted light.
var/light_color // The colour of the light, string, decomposed by parse_light_color()
///The turf under the source atom.
var/turf/source_turf
///The turf the top_atom appears to over.
var/turf/pixel_turf
///Intensity of the emitter light.
var/light_power
/// The range of the emitted light.
var/light_range
/// The colour of the light, string, decomposed by parse_light_color()
var/light_color
// Variables for keeping track of the colour.
var/lum_r
@@ -21,142 +28,83 @@
var/tmp/applied_lum_g
var/tmp/applied_lum_b
var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners.
var/list/turf/affecting_turfs
/// List used to store how much we're affecting corners.
var/list/datum/lighting_corner/effect_str
var/applied = FALSE // Whether we have applied our light yet or not.
/// Whether we have applied our light yet or not.
var/applied = FALSE
var/vis_update // Whether we should smartly recalculate visibility. and then only update tiles that became(in)visible to us.
var/needs_update // Whether we are queued for an update.
var/destroyed // Whether we are destroyed and need to stop emitting light.
var/force_update
/// whether we are to be added to SSlighting's sources_queue list for an update
var/needs_update = LIGHTING_NO_UPDATE
/datum/light_source/New(var/atom/owner, var/atom/top)
total_lighting_sources++
/datum/light_source/New(atom/owner, atom/top)
source_atom = owner // Set our new owner.
if(!source_atom.light_sources)
source_atom.light_sources = list()
source_atom.light_sources += src // Add us to the lights of our owner.
LAZYADD(source_atom.light_sources, src)
top_atom = top
if(top_atom != source_atom)
if(!top.light_sources)
top.light_sources = list()
top_atom.light_sources += src
if (top_atom != source_atom)
LAZYADD(top_atom.light_sources, src)
source_turf = top_atom
pixel_turf = get_turf_pixel(top_atom) || source_turf
light_power = source_atom.light_power
light_range = source_atom.light_range
light_color = source_atom.light_color
parse_light_color()
effect_str = list()
affecting_turfs = list()
PARSE_LIGHT_COLOR(src)
update()
/datum/light_source/Destroy(force)
remove_lum()
if (source_atom)
LAZYREMOVE(source_atom.light_sources, src)
if (top_atom)
LAZYREMOVE(top_atom.light_sources, src)
if (needs_update)
SSlighting.sources_queue -= src
top_atom = null
source_atom = null
source_turf = null
pixel_turf = null
return ..()
// Kill ourselves.
/datum/light_source/proc/destroy()
total_lighting_sources--
destroyed = TRUE
force_update()
if(source_atom)
if(!source_atom.light_sources)
log_runtime(EXCEPTION("Atom [source_atom] was a light source, but lacked a light source list!\n"), source_atom)
else
source_atom.light_sources -= src
// Yes this doesn't align correctly on anything other than 4 width tabs.
// If you want it to go switch everybody to elastic tab stops.
// Actually that'd be great if you could!
#define EFFECT_UPDATE(level) \
if (needs_update == LIGHTING_NO_UPDATE) \
SSlighting.sources_queue += src; \
if (needs_update < level) \
needs_update = level; \
if(top_atom)
top_atom.light_sources -= src
// Call it dirty, I don't care.
// This is here so there's no performance loss on non-instant updates from the fact that the engine can also do instant updates.
// If you're wondering what's with the "BYOND" argument: BYOND won't let me have a() macro that has no arguments :|.
#define effect_update(BYOND) \
if(!needs_update) \
{ \
lighting_update_lights += src; \
needs_update = TRUE; \
}
// This proc will cause the light source to update the top atom, and add itself to the update queue.
/datum/light_source/proc/update(var/atom/new_top_atom)
/datum/light_source/proc/update(atom/new_top_atom)
// This top atom is different.
if(new_top_atom && new_top_atom != top_atom)
if(top_atom != source_atom) // Remove ourselves from the light sources of that top atom.
top_atom.light_sources -= src
if (new_top_atom && new_top_atom != top_atom)
if(top_atom != source_atom && top_atom.light_sources) // Remove ourselves from the light sources of that top atom.
LAZYREMOVE(top_atom.light_sources, src)
top_atom = new_top_atom
if(top_atom != source_atom)
if(!top_atom.light_sources)
top_atom.light_sources = list()
if (top_atom != source_atom)
LAZYADD(top_atom.light_sources, src) // Add ourselves to the light sources of our new top atom.
top_atom.light_sources += src // Add ourselves to the light sources of our new top atom.
effect_update(null)
EFFECT_UPDATE(LIGHTING_CHECK_UPDATE)
// Will force an update without checking if it's actually needed.
/datum/light_source/proc/force_update()
force_update = 1
effect_update(null)
EFFECT_UPDATE(LIGHTING_FORCE_UPDATE)
// Will cause the light source to recalculate turfs that were removed or added to visibility only.
/datum/light_source/proc/vis_update()
vis_update = 1
effect_update(null)
// Will check if we actually need to update, and update any variables that may need to be updated.
/datum/light_source/proc/check()
if(!source_atom || !light_range || !light_power)
destroy()
return 1
if(!top_atom)
top_atom = source_atom
. = 1
if(isturf(top_atom))
if(source_turf != top_atom)
source_turf = top_atom
. = 1
else if(top_atom.loc != source_turf)
source_turf = top_atom.loc
. = 1
if(source_atom.light_power != light_power)
light_power = source_atom.light_power
. = 1
if(source_atom.light_range != light_range)
light_range = source_atom.light_range
. = 1
if(light_range && light_power && !applied)
. = 1
if(source_atom.light_color != light_color)
light_color = source_atom.light_color
parse_light_color()
. = 1
// Decompile the hexadecimal colour into lumcounts of each perspective.
/datum/light_source/proc/parse_light_color()
if(light_color)
lum_r = GetRedPart (light_color) / 255
lum_g = GetGreenPart(light_color) / 255
lum_b = GetBluePart (light_color) / 255
else
lum_r = 1
lum_g = 1
lum_b = 1
EFFECT_UPDATE(LIGHTING_VIS_UPDATE)
// Macro that applies light to a new corner.
// It is a macro in the interest of speed, yet not having to copy paste it.
@@ -164,127 +112,264 @@
// As such this all gets counted as a single line.
// The braces and semicolons are there to be able to do this on a single line.
#define APPLY_CORNER(C) \
. = LUM_FALLOFF(C, source_turf); \
\
. *= light_power; \
\
effect_str[C] = .; \
\
C.update_lumcount \
( \
. * applied_lum_r, \
. * applied_lum_g, \
. * applied_lum_b \
// /tg/ falloff alg
#define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range)))
// Bay/Polaris falloff alg
//#define LUM_FALLOFF(C, T)(1 - CLAMP01(((C.x - T.x) ** 2 +(C.y - T.y) ** 2 + LIGHTING_HEIGHT) ** 0.6 / max(1, light_range)))
#define APPLY_CORNER(C) \
. = LUM_FALLOFF(C, pixel_turf); \
. *= light_power; \
var/OLD = effect_str[C]; \
\
C.update_lumcount \
( \
(. * lum_r) - (OLD * applied_lum_r), \
(. * lum_g) - (OLD * applied_lum_g), \
(. * lum_b) - (OLD * applied_lum_b) \
); \
#define REMOVE_CORNER(C) \
. = -effect_str[C]; \
C.update_lumcount \
( \
. * applied_lum_r, \
. * applied_lum_g, \
. * applied_lum_b \
);
// I don't need to explain what this does, do I?
#define REMOVE_CORNER(C) \
. = -effect_str[C]; \
C.update_lumcount \
( \
. * applied_lum_r, \
. * applied_lum_g, \
. * applied_lum_b \
);
#define APPLY_CORNER_SIMPLE(C) \
. = light_power; \
var/OLD = effect_str[C]; \
\
C.update_lumcount \
( \
(. * lum_r) - (OLD * applied_lum_r), \
(. * lum_g) - (OLD * applied_lum_g), \
(. * lum_b) - (OLD * applied_lum_b) \
); \
// This is the define used to calculate falloff.
#define LUM_FALLOFF(C, T)(1 - CLAMP01(((C.x - T.x) ** 2 +(C.y - T.y) ** 2 + LIGHTING_HEIGHT) ** 0.6 / max(1, light_range)))
/datum/light_source/proc/apply_lum()
var/static/update_gen = 1
applied = 1
/datum/light_source/proc/remove_lum()
applied = FALSE
for (var/datum/lighting_corner/corner as anything in effect_str)
REMOVE_CORNER(corner)
LAZYREMOVE(corner.affecting, src)
effect_str = null
/datum/light_source/proc/recalc_corner(datum/lighting_corner/corner)
LAZYINITLIST(effect_str)
if (effect_str[corner]) // Already have one.
REMOVE_CORNER(corner)
effect_str[corner] = 0
APPLY_CORNER(corner)
effect_str[corner] = .
/datum/light_source/proc/get_turfs_in_range()
return view(CEILING(light_range, 1), source_turf)
/datum/light_source/proc/update_corners()
var/update = FALSE
var/atom/source_atom = src.source_atom
if (QDELETED(source_atom))
qdel(src)
return
if (source_atom.light_power != light_power)
light_power = source_atom.light_power
update = TRUE
if (source_atom.light_range != light_range)
light_range = source_atom.light_range
update = TRUE
if (!top_atom)
top_atom = source_atom
update = TRUE
if (!light_range || !light_power)
qdel(src)
return
if (isturf(top_atom))
if (source_turf != top_atom)
source_turf = top_atom
pixel_turf = source_turf
update = TRUE
else if (top_atom.loc != source_turf)
source_turf = top_atom.loc
pixel_turf = get_turf_pixel(top_atom)
update = TRUE
else
var/pixel_loc = get_turf_pixel(top_atom)
if (pixel_loc != pixel_turf)
pixel_turf = pixel_loc
update = TRUE
if (!isturf(source_turf))
if (applied)
remove_lum()
return
if (light_range && light_power && !applied)
update = TRUE
if (source_atom.light_color != light_color)
light_color = source_atom.light_color
PARSE_LIGHT_COLOR(src)
update = TRUE
else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b)
update = TRUE
if (update)
needs_update = LIGHTING_CHECK_UPDATE
applied = TRUE
else if (needs_update == LIGHTING_CHECK_UPDATE)
return //nothing's changed
var/list/datum/lighting_corner/corners = list()
var/list/turf/turfs = list()
if (source_turf)
var/oldlum = source_turf.luminosity
source_turf.luminosity = CEILING(light_range, 1)
for(var/turf/T in get_turfs_in_range())
if(!IS_OPAQUE_TURF(T))
if (!T.lighting_corners_initialised)
T.generate_missing_corners()
corners[T.lighting_corner_NE] = 0
corners[T.lighting_corner_SE] = 0
corners[T.lighting_corner_SW] = 0
corners[T.lighting_corner_NW] = 0
turfs += T
source_turf.luminosity = oldlum
var/list/datum/lighting_corner/new_corners = (corners - effect_str)
LAZYINITLIST(effect_str)
if (needs_update == LIGHTING_VIS_UPDATE)
for (var/datum/lighting_corner/corner as anything in new_corners)
APPLY_CORNER(corner)
if (. != 0)
LAZYADD(corner.affecting, src)
effect_str[corner] = .
else
for (var/datum/lighting_corner/corner as anything in new_corners)
APPLY_CORNER(corner)
if (. != 0)
LAZYADD(corner.affecting, src)
effect_str[corner] = .
for (var/datum/lighting_corner/corner as anything in corners - new_corners) // Existing corners
APPLY_CORNER(corner)
if (. != 0)
effect_str[corner] = .
else
LAZYREMOVE(corner.affecting, src)
effect_str -= corner
var/list/datum/lighting_corner/gone_corners = effect_str - corners
for (var/datum/lighting_corner/corner as anything in gone_corners)
REMOVE_CORNER(corner)
LAZYREMOVE(corner.affecting, src)
effect_str -= gone_corners
// Keep track of the last applied lum values so that the lighting can be reversed
applied_lum_r = lum_r
applied_lum_g = lum_g
applied_lum_b = lum_b
FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING)
if(!T.lighting_corners_initialised)
T.generate_missing_corners()
UNSETEMPTY(effect_str)
for(var/datum/lighting_corner/C in T.get_corners())
if(C.update_gen == update_gen)
continue
// For planets and fake suns
/datum/light_source/sun
light_range = 1
light_color = "#FFFFFF"
light_power = 2
var/applied_power = 2
C.update_gen = update_gen
C.affecting += src
/datum/light_source/sun/New()
return
if(!C.active)
effect_str[C] = 0
continue
/datum/light_source/sun/force_update()
return
APPLY_CORNER(C)
/datum/light_source/sun/vis_update()
return
if(!T.affecting_lights)
T.affecting_lights = list()
/datum/light_source/sun/update_corners(var/list/turfs_to_update)
if(!LAZYLEN(turfs_to_update))
stack_trace("Planet sun tried to update with no turfs given")
return
T.affecting_lights += src
affecting_turfs += T
// Update lum_r/g/b from our light_color
PARSE_LIGHT_COLOR(src)
// Noop update
if(lum_r == applied_lum_r && lum_g == applied_lum_g && lum_b == applied_lum_b && light_power == applied_power)
return
// No reason to unapply on the first run or if previous run was 0 power
if(applied)
remove_lum()
update_gen++
// Entirely dark, just stop now that we've remove_lum()'d
if(!light_power)
applied = FALSE
return
/datum/light_source/proc/remove_lum()
applied = FALSE
LAZYINITLIST(effect_str)
for(var/turf/T in affecting_turfs)
if(!T.affecting_lights)
T.affecting_lights = list()
else
T.affecting_lights -= src
affecting_turfs.Cut()
for(var/datum/lighting_corner/C in effect_str)
REMOVE_CORNER(C)
C.affecting -= src
effect_str.Cut()
/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C)
if(effect_str.Find(C)) // Already have one.
REMOVE_CORNER(C)
APPLY_CORNER(C)
/datum/light_source/proc/smart_vis_update()
var/list/datum/lighting_corner/corners = list()
var/list/turf/turfs = list()
FOR_DVIEW(var/turf/T, light_range, source_turf, 0)
if(!T.lighting_corners_initialised)
T.generate_missing_corners()
corners |= T.get_corners()
turfs += T
for(var/turf/T as anything in turfs_to_update)
if(!IS_OPAQUE_TURF(T))
if(!T.lighting_corners_initialised)
T.generate_missing_corners()
var/datum/lighting_corner/LC = T.lighting_corner_NE
if(!corners[LC])
corners[LC] = 1
APPLY_CORNER_SIMPLE(LC)
LAZYADD(LC.affecting, src)
effect_str[LC] = .
LC = T.lighting_corner_SE
if(!corners[LC])
corners[LC] = 1
APPLY_CORNER_SIMPLE(LC)
LAZYADD(LC.affecting, src)
effect_str[LC] = .
LC = T.lighting_corner_NW
if(!corners[LC])
corners[LC] = 1
APPLY_CORNER_SIMPLE(LC)
LAZYADD(LC.affecting, src)
effect_str[LC] = .
LC = T.lighting_corner_SW
if(!corners[LC])
corners[LC] = 1
APPLY_CORNER_SIMPLE(LC)
LAZYADD(LC.affecting, src)
effect_str[LC] = .
var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them.
affecting_turfs += L
for(var/turf/T in L)
if(!T.affecting_lights)
T.affecting_lights = list(src)
else
T.affecting_lights += src
CHECK_TICK
L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights.
affecting_turfs -= L
for(var/turf/T in L)
T.affecting_lights -= src
applied_lum_r = lum_r
applied_lum_g = lum_g
applied_lum_b = lum_b
applied_power = light_power
applied = TRUE // remove_lum() now necessary in the future
for(var/datum/lighting_corner/C in corners - effect_str) // New corners
C.affecting += src
if(!C.active)
effect_str[C] = 0
continue
UNSETEMPTY(effect_str)
APPLY_CORNER(C)
for(var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners.
REMOVE_CORNER(C)
C.affecting -= src
effect_str -= C
#undef effect_update
#undef EFFECT_UPDATE
#undef LUM_FALLOFF
#undef REMOVE_CORNER
#undef APPLY_CORNER
#undef REMOVE_CORNER_SIMPLE
#undef APPLY_CORNER_SIMPLE
+110 -64
View File
@@ -1,96 +1,142 @@
/turf
var/dynamic_lighting = TRUE // Does the turf use dynamic lighting?
luminosity = 1
///Lumcount added by sources other than lighting datum objects, such as the overlay lighting component.
var/dynamic_lumcount = 0
var/dynamic_lighting = TRUE
var/tmp/lighting_corners_initialised = FALSE
var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf.
var/tmp/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay.
var/tmp/list/datum/lighting_corner/corners
var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile.
///Our lighting object.
var/tmp/datum/lighting_object/lighting_object
///Lighting Corner datums.
var/tmp/datum/lighting_corner/lighting_corner_NE
var/tmp/datum/lighting_corner/lighting_corner_SE
var/tmp/datum/lighting_corner/lighting_corner_SW
var/tmp/datum/lighting_corner/lighting_corner_NW
///Which directions does this turf block the vision of, taking into account both the turf's opacity and the movable opacity_sources.
var/directional_opacity = NONE
///Lazylist of movable atoms providing opacity sources.
var/list/atom/movable/opacity_sources
// Causes any affecting light sources to be queued for a visibility update, for example a door got opened.
/turf/proc/reconsider_lights()
for(var/datum/light_source/L in affecting_lights)
L.vis_update()
lighting_corner_NE?.vis_update()
lighting_corner_SE?.vis_update()
lighting_corner_SW?.vis_update()
lighting_corner_NW?.vis_update()
/turf/proc/lighting_clear_overlay()
if(lighting_overlay)
qdel(lighting_overlay, force = TRUE)
if(lighting_object)
qdel(lighting_object, force=TRUE)
for(var/datum/lighting_corner/C in corners)
C.update_active()
// Builds a lighting overlay for us, but only if our area is dynamic.
// Builds a lighting object for us, but only if our area is dynamic.
/turf/proc/lighting_build_overlay()
if(lighting_overlay)
if(!has_dynamic_lighting())
return
var/area/A = loc
if(A.dynamic_lighting && dynamic_lighting)
if(!lighting_corners_initialised)
generate_missing_corners()
new /atom/movable/lighting_overlay(src)
for(var/datum/lighting_corner/C in corners)
if(!C.active) // We would activate the corner, calculate the lighting for it.
for(var/L in C.affecting)
var/datum/light_source/S = L
S.recalc_corner(C)
C.active = TRUE
lighting_clear_overlay()
new/datum/lighting_object(src)
// Used to get a scaled lumcount.
/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1)
if(!lighting_overlay)
/turf/proc/get_lumcount(minlum = 0, maxlum = 1)
if (!lighting_object)
return 1
var/totallums = 0
for(var/datum/lighting_corner/L in corners)
totallums += max(L.lum_r, L.lum_g, L.lum_b)
var/datum/lighting_corner/L
L = lighting_corner_NE
if (L)
totallums += L.lum_r + L.lum_b + L.lum_g
L = lighting_corner_SE
if (L)
totallums += L.lum_r + L.lum_b + L.lum_g
L = lighting_corner_SW
if (L)
totallums += L.lum_r + L.lum_b + L.lum_g
L = lighting_corner_NW
if (L)
totallums += L.lum_r + L.lum_b + L.lum_g
totallums /= 4 // 4 corners, max channel selected, return the average
totallums =(totallums - minlum) /(maxlum - minlum)
totallums /= 12 // 4 corners, each with 3 channels, get the average.
totallums = (totallums - minlum) / (maxlum - minlum)
totallums += dynamic_lumcount
return CLAMP01(totallums)
// Can't think of a good name, this proc will recalculate the has_opaque_atom variable.
/turf/proc/recalc_atom_opacity()
has_opaque_atom = FALSE
for(var/atom/A in src.contents + src) // Loop through every movable atom on our tile PLUS ourselves (we matter too...)
if(A.opacity)
has_opaque_atom = TRUE
// Returns a boolean whether the turf is on soft lighting.
// Soft lighting being the threshold at which point the overlay considers
// itself as too dark to allow sight and see_in_dark becomes useful.
// So basically if this returns true the tile is unlit black.
/turf/proc/is_softly_lit()
if (!lighting_object)
return FALSE
// If an opaque movable atom moves around we need to potentially update visibility.
/turf/Entered(var/atom/movable/Obj, var/atom/OldLoc)
. = ..()
return !(luminosity || dynamic_lumcount)
if(Obj && Obj.opacity)
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/Exited(var/atom/movable/Obj, var/atom/newloc)
. = ..()
///Proc to add movable sources of opacity on the turf and let it handle lighting code.
/turf/proc/add_opacity_source(atom/movable/new_source)
LAZYADD(opacity_sources, new_source)
if(opacity)
return
recalculate_directional_opacity()
if(Obj && Obj.opacity)
recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates.
reconsider_lights()
/turf/proc/get_corners()
if(has_opaque_atom)
return null // Since this proc gets used in a for loop, null won't be looped though.
///Proc to remove movable sources of opacity on the turf and let it handle lighting code.
/turf/proc/remove_opacity_source(atom/movable/old_source)
LAZYREMOVE(opacity_sources, old_source)
if(opacity) //Still opaque, no need to worry on updating.
return
recalculate_directional_opacity()
return corners
///Calculate on which directions this turfs block view.
/turf/proc/recalculate_directional_opacity()
. = directional_opacity
if(opacity)
directional_opacity = ALL_CARDINALS
if(. != directional_opacity)
reconsider_lights()
return
directional_opacity = NONE
for(var/atom/movable/opacity_source as anything in opacity_sources)
if(opacity_source.flags & ON_BORDER)
directional_opacity |= opacity_source.dir
else //If fulltile and opaque, then the whole tile blocks view, no need to continue checking.
directional_opacity = ALL_CARDINALS
break
if(. != directional_opacity && (. == ALL_CARDINALS || directional_opacity == ALL_CARDINALS))
reconsider_lights() //The lighting system only cares whether the tile is fully concealed from all directions or not.
/turf/proc/change_area(area/old_area, area/new_area)
if(SSlighting.subsystem_initialized)
if (new_area.dynamic_lighting != old_area.dynamic_lighting)
if (new_area.dynamic_lighting)
lighting_build_overlay()
else
lighting_clear_overlay()
/turf/proc/has_dynamic_lighting()
var/area/A = loc
return (IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A))
/turf/proc/generate_missing_corners()
if (!lighting_corner_NE)
lighting_corner_NE = new/datum/lighting_corner(src, NORTH|EAST)
if (!lighting_corner_SE)
lighting_corner_SE = new/datum/lighting_corner(src, SOUTH|EAST)
if (!lighting_corner_SW)
lighting_corner_SW = new/datum/lighting_corner(src, SOUTH|WEST)
if (!lighting_corner_NW)
lighting_corner_NW = new/datum/lighting_corner(src, NORTH|WEST)
lighting_corners_initialised = TRUE
if(!corners)
corners = list(null, null, null, null)
for(var/i = 1 to 4)
if(corners[i]) // Already have a corner on this direction.
continue
corners[i] = new /datum/lighting_corner(src, LIGHTING_CORNER_DIAGONAL[i])
@@ -1,7 +0,0 @@
#undef LIGHTING_FALLOFF
#undef LIGHTING_LAMBERTIAN
#undef LIGHTING_HEIGHT
#undef LIGHTING_ICON
#undef LIGHTING_BASE_MATRIX
+1 -1
View File
@@ -4,7 +4,7 @@
for(var/turf/simulated/T in block(locate(1,1,z), locate(world.maxx, world.maxy, z)))
T.update_air_properties()
//We missed sslighting init!
if(lighting_overlays_initialised)
if(SSlighting.subsystem_initialized)
for(var/Trf in block(locate(1,1,z), locate(world.maxx, world.maxy, z)))
var/turf/T = Trf //faster than implicit istype with typed for loop
T.lighting_build_overlay()
-1
View File
@@ -159,7 +159,6 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new)
var/model_key = copytext(line, tpos, tpos + key_len)
line_keys[++line_keys.len] = model_key
#ifdef TESTING
else
++turfsSkipped
#endif
CHECK_TICK
+86 -1
View File
@@ -49,6 +49,24 @@ var/list/name_to_material
if(material)
return material.name
/**
* Returns the material composition of the atom.
*
* Used when recycling items, specifically to turn alloys back into their component mats.
*
* Exists because I'd need to add a way to un-alloy alloys or otherwise deal
* with people converting the entire stations material supply into alloys.
*
* Arguments:
* - breakdown_flags: A set of flags determining how exactly the materials are broken down. (unused)
*/
/obj/proc/get_material_composition(breakdown_flags=NONE)
. = list()
for(var/mat in matter)
var/datum/material/M = GET_MATERIAL_REF(mat)
.[M] = matter[mat]
// Builds the datum list above.
/proc/populate_material_list(force_remake=0)
if(name_to_material && !force_remake) return // Already set up!
@@ -72,6 +90,73 @@ var/list/name_to_material
return material.display_name
return null
/** Fetches a cached material singleton when passed sufficient arguments.
*
* Arguments:
* - [arguments][/list]: The list of arguments used to fetch the material ref.
* - The first element is a material datum, text string, or material type.
* - [Material datums][/datum/material] are assumed to be references to the cached datum and are returned
* - Text is assumed to be the text ID of a material and the corresponding material is fetched from the cache
* - A material type is checked for bespokeness:
* - If the material type is not bespoke the type is assumed to be the id for a material and the corresponding material is loaded from the cache.
* - If the material type is bespoke a text ID is generated from the arguments list and used to load a material datum from the cache.
* - The following elements are used to generate bespoke IDs
*/
/proc/_GetMaterialRef(list/arguments)
if(!name_to_material)
populate_material_list()
var/datum/material/key = arguments[1]
if(istype(key))
return key // we want to convert anything we're given to a material
if(istext(key)) // text ID
. = name_to_material[key]
if(!.)
warning("Attempted to fetch material ref with invalid text id '[key]'")
return
if(!ispath(key, /datum/material))
CRASH("Attempted to fetch material ref with invalid key [key]")
key = GetIdFromArguments(arguments)
. = name_to_material[key]
if(!.)
warning("Attempted to fetch nonexistent material with key [key]")
/** I'm not going to lie, this was swiped from [SSdcs][/datum/controller/subsystem/processing/dcs].
* Credit does to ninjanomnom
*
* Generates an id for bespoke ~~elements~~ materials when given the argument list
* Generating the id here is a bit complex because we need to support named arguments
* Named arguments can appear in any order and we need them to appear after ordered arguments
* We assume that no one will pass in a named argument with a value of null
**/
/proc/GetIdFromArguments(list/arguments)
var/datum/material/mattype = arguments[1]
var/list/fullid = list("[initial(mattype.name) || mattype]")
var/list/named_arguments = list()
for(var/i in 2 to length(arguments))
var/key = arguments[i]
var/value
if(istext(key))
value = arguments[key]
if(!(istext(key) || isnum(key)))
key = REF(key)
key = "[key]" // Key is stringified so numbers dont break things
if(!isnull(value))
if(!(istext(value) || isnum(value)))
value = REF(value)
named_arguments["[key]"] = value
else
fullid += "[key]"
if(length(named_arguments))
named_arguments = sortList(named_arguments)
fullid += named_arguments
return replacetext(list2params(fullid), "+", " ")
// Material definition and procs follow.
/datum/material
var/name // Unique name for use in indexing the list.
@@ -131,7 +216,7 @@ var/list/name_to_material
var/tableslam_noise = 'sound/weapons/tablehit1.ogg'
// Noise made when a simple door made of this material opens or closes.
var/dooropen_noise = 'sound/effects/stonedoor_openclose.ogg'
// Path to resulting stacktype. Todo remove need for this.
// Path to resulting stacktype.
var/stack_type
// Wallrot crumble message.
var/rotting_touch_message = "crumbles under your touch"
@@ -27,14 +27,12 @@
. += "\The [drying] is [drying.get_dryness_text()]."
/obj/structure/tanning_rack/update_icon()
overlays.Cut()
cut_overlays()
if(drying)
var/image/I
if(drying.wetness)
I = image(icon, "leather_wet")
add_overlay("leather_wet")
else
I = image(icon, "leather_dry")
add_overlay(I)
add_overlay("leather_dry")
/obj/structure/tanning_rack/attackby(var/atom/A, var/mob/user)
if(istype(A, /obj/item/stack/wetleather))
+1 -1
View File
@@ -4,7 +4,7 @@
name = "lantern"
icon_state = "lantern"
desc = "A mining lantern."
brightness_on = 6 // luminosity when on
light_range = 6 // luminosity when on
light_color = "FF9933" // A slight yellow/orange color.
/*****************************Pickaxe********************************/
+1 -1
View File
@@ -14,7 +14,7 @@
/obj/structure/outcrop/Initialize()
. = ..()
if(prob(1))
overlays += image(icon, "[initial(icon_state)]-egg")
add_overlay("[initial(icon_state)]-egg")
/obj/structure/outcrop/diamond
name = "shiny outcrop"
+1 -1
View File
@@ -125,7 +125,7 @@ turf/simulated/mineral/floor/light_corner
/turf/simulated/mineral/proc/update_general()
update_icon(1)
recalc_atom_opacity()
recalculate_directional_opacity()
if(ticker && ticker.current_state == GAME_STATE_PLAYING)
reconsider_lights()
if(air_master)

Some files were not shown because too many files have changed in this diff Show More