mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-07-26 23:51:16 +01:00
The 515 MegaPR early downport (#7783)
Co-authored-by: Selis <selis@xynolabs.com> Co-authored-by: Selis <sirlionfur@hotmail.de> Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> Co-authored-by: SatinIsle <thesatinisle@gmail.com> Co-authored-by: Heroman <alesha3000@list.ru> Co-authored-by: Casey <a.roaming.shadow@gmail.com> Co-authored-by: Raeschen <rycoop29@gmail.com>
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
return
|
||||
|
||||
var/icon/cross = icon('icons/obj/storage.dmi',"bible")
|
||||
var/msg = "<span class='filter_pray'>" + span_blue("\icon[cross][bicon(cross)] <b>" + span_purple("PRAY: ") + "[key_name(src, 1)] [ADMIN_QUE(src)] [ADMIN_PP(src)] [ADMIN_VV(src)] [ADMIN_SM(src)] ([admin_jump_link(src, src)]) [ADMIN_CA(src)] [ADMIN_SC(src)] [ADMIN_SMITE(src)]:</b> [raw_msg]") + "</span>"
|
||||
var/msg = "<span class='filter_pray'>" + span_blue("[icon2html(cross, GLOB.admins)] <b>" + span_purple("PRAY: ") + "[key_name(src, 1)] [ADMIN_QUE(src)] [ADMIN_PP(src)] [ADMIN_VV(src)] [ADMIN_SM(src)] ([admin_jump_link(src, src)]) [ADMIN_CA(src)] [ADMIN_SC(src)] [ADMIN_SMITE(src)]:</b> [raw_msg]") + "</span>"
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(R_ADMIN|R_EVENT & C.holder.rights)
|
||||
|
||||
@@ -20,7 +20,13 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/Destroy()
|
||||
QDEL_NULL(ai_holder)
|
||||
if(ai_holder)
|
||||
ai_holder.holder = null
|
||||
ai_holder.UnregisterSignal(src,COMSIG_MOB_STATCHANGE)
|
||||
if(ai_holder.faction_friends && ai_holder.faction_friends.len) //This list is shared amongst the faction
|
||||
ai_holder.faction_friends -= src
|
||||
ai_holder.faction_friends = null
|
||||
QDEL_NULL(ai_holder)
|
||||
return ..()
|
||||
|
||||
/mob/living/Login()
|
||||
@@ -222,7 +228,7 @@
|
||||
holder = new_holder
|
||||
home_turf = get_turf(holder)
|
||||
manage_processing(AI_PROCESSING)
|
||||
GLOB.stat_set_event.register(holder, src, PROC_REF(holder_stat_change))
|
||||
RegisterSignal(holder, COMSIG_MOB_STATCHANGE, PROC_REF(holder_stat_change))
|
||||
..()
|
||||
|
||||
/datum/ai_holder/Destroy()
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
build_faction_friends()
|
||||
|
||||
/datum/ai_holder/Destroy()
|
||||
if(faction_friends.len) //This list is shared amongst the faction
|
||||
faction_friends -= src
|
||||
if(faction_friends)
|
||||
if(faction_friends.len) //This list is shared amongst the faction
|
||||
faction_friends -= src
|
||||
return ..()
|
||||
|
||||
// Handles everything about that list.
|
||||
@@ -114,4 +115,3 @@
|
||||
add_attacker(their_target) // We won't wait and 'warn' them while they're stabbing our ally
|
||||
set_follow(friend, 10 SECONDS)
|
||||
ai_log("help_requested() : Exiting.", AI_LOG_DEBUG)
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
/datum/ai_holder/simple_mob/humanoid/hostile/post_ranged_attack(atom/A)
|
||||
//Pick a random turf to step into
|
||||
var/turf/T = get_step(holder, pick(alldirs))
|
||||
if(check_trajectory(A, T)) // Can we even hit them from there?
|
||||
if((A in check_trajectory(A, T))) // Can we even hit them from there?
|
||||
holder.IMove(T)
|
||||
holder.face_atom(A)
|
||||
|
||||
@@ -197,4 +197,3 @@
|
||||
|
||||
/datum/ai_holder/simple_mob/passive/speedy
|
||||
base_wander_delay = 1
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@
|
||||
|
||||
target = new_target
|
||||
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(remove_target))
|
||||
|
||||
if(target != null)
|
||||
lose_target_time = 0
|
||||
track_target_position()
|
||||
@@ -188,6 +190,7 @@
|
||||
ai_log("lose_target() : Entering.", AI_LOG_TRACE)
|
||||
if(target)
|
||||
ai_log("lose_target() : Had a target, setting to null and LTT.", AI_LOG_DEBUG)
|
||||
UnregisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(remove_target))
|
||||
target = null
|
||||
lose_target_time = world.time
|
||||
|
||||
@@ -203,6 +206,7 @@
|
||||
/datum/ai_holder/proc/remove_target()
|
||||
ai_log("remove_target() : Entering.", AI_LOG_TRACE)
|
||||
if(target)
|
||||
UnregisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(remove_target))
|
||||
target = null
|
||||
|
||||
lose_target_time = 0
|
||||
|
||||
@@ -134,4 +134,4 @@
|
||||
emote_hear = list("hisses")
|
||||
|
||||
/datum/say_list/crab
|
||||
emote_hear = list("hisses")
|
||||
emote_hear = list("hisses")
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
if(!D)
|
||||
return 0
|
||||
if(!secured)
|
||||
visible_message("\icon[src][bicon(src)] *beep* *beep*", "*beep* *beep*")
|
||||
visible_message("[icon2html(src,viewers(src))] *beep* *beep*", "*beep* *beep*")
|
||||
if((normal) && (a_right) && (a_left))
|
||||
if(a_right != D)
|
||||
a_right.pulsed(0)
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
pulse(0)
|
||||
QDEL_LIST_NULL(i_beams) //They will get recreated next process() if the situation is still appropriate
|
||||
if(!holder)
|
||||
visible_message("\icon[src][bicon(src)] *beep* *beep*")
|
||||
visible_message("[icon2html(src,viewers(src))] *beep* *beep*")
|
||||
|
||||
/obj/item/device/assembly/infra/tgui_interact(mob/user, datum/tgui/ui)
|
||||
if(!secured)
|
||||
@@ -178,4 +178,4 @@
|
||||
return
|
||||
if(istype(AM, /obj/effect/beam))
|
||||
return
|
||||
hit()
|
||||
hit()
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
var/turf/mainloc = get_turf(src)
|
||||
pulse(0)
|
||||
if(!holder)
|
||||
mainloc.visible_message("\icon[src][bicon(src)] *beep* *beep*", "*beep* *beep*")
|
||||
mainloc.visible_message("[icon2html(src,viewers(src))] *beep* *beep*", "*beep* *beep*")
|
||||
|
||||
/obj/item/device/assembly/prox_sensor/process()
|
||||
if(scanning)
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
|
||||
if(!holder)
|
||||
for(var/mob/O in hearers(1, src.loc))
|
||||
O.show_message("\icon[src][bicon(src)] *beep* *beep*", 3, "*beep* *beep*", 2)
|
||||
O.show_message("[icon2html(src, O.client)] *beep* *beep*", 3, "*beep* *beep*", 2)
|
||||
|
||||
/obj/item/device/assembly/signaler/proc/set_frequency(new_frequency)
|
||||
if(!frequency)
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
return 0
|
||||
pulse(0)
|
||||
if(!holder)
|
||||
visible_message("\icon[src][bicon(src)] *beep* *beep*", "*beep* *beep*")
|
||||
visible_message("[icon2html(src,viewers(src))] *beep* *beep*", "*beep* *beep*")
|
||||
|
||||
/obj/item/device/assembly/timer/process()
|
||||
if(timing && time-- <= 0)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
recorded = msg
|
||||
listening = 0
|
||||
var/turf/T = get_turf(src) //otherwise it won't work in hand
|
||||
T.visible_message("\icon[src][bicon(src)] beeps, \"Activation message is '[recorded]'.\"")
|
||||
T.visible_message("[icon2html(src,viewers(src))] beeps, \"Activation message is '[recorded]'.\"")
|
||||
else
|
||||
if(findtext(msg, recorded))
|
||||
pulse(0)
|
||||
@@ -23,7 +23,7 @@
|
||||
if(!holder)
|
||||
listening = !listening
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message("\icon[src][bicon(src)] beeps, \"[listening ? "Now" : "No longer"] recording input.\"")
|
||||
T.visible_message("[icon2html(src,viewers(src))] beeps, \"[listening ? "Now" : "No longer"] recording input.\"")
|
||||
|
||||
|
||||
/obj/item/device/assembly/voice/attack_self(mob/user)
|
||||
@@ -34,4 +34,4 @@
|
||||
|
||||
/obj/item/device/assembly/voice/toggle_secure()
|
||||
. = ..()
|
||||
listening = 0
|
||||
listening = 0
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
Asset cache quick users guide:
|
||||
|
||||
Make a datum in asset_list_items.dm with your assets for your thing.
|
||||
Checkout asset_list.dm for the helper subclasses
|
||||
The simple subclass will most like be of use for most cases.
|
||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||
Then call .send(client) on that stored return value.
|
||||
|
||||
Note: If your code uses output() with assets you will need to call asset_flush on the client and wait for it to return before calling output(). You only need do this if .send(client) returned TRUE
|
||||
*/
|
||||
|
||||
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
//This proc sends the asset to the client, but only if it needs it.
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset(client/client, asset_name)
|
||||
return send_asset_list(client, list(asset_name))
|
||||
|
||||
/// Sends a list of assets to a client
|
||||
/// This proc will no longer block, use client.asset_flush() if you to need know when the client has all assets (such as for output()). (This is not required for browse() calls as they use the same message queue as asset sends)
|
||||
/// client - a client or mob
|
||||
/// asset_list - A list of asset filenames to be sent to the client.
|
||||
/// Returns TRUE if any assets were sent.
|
||||
/proc/send_asset_list(client/client, list/asset_list)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
else
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
var/list/unreceived = list()
|
||||
|
||||
for (var/asset_name in asset_list)
|
||||
var/datum/asset_cache_item/asset = SSassets.cache[asset_name]
|
||||
if (!asset)
|
||||
continue
|
||||
var/asset_file = asset.resource
|
||||
if (!asset_file)
|
||||
continue
|
||||
|
||||
var/asset_md5 = asset.md5
|
||||
if (client.sent_assets[asset_name] == asset_md5)
|
||||
continue
|
||||
unreceived[asset_name] = asset_md5
|
||||
|
||||
if (unreceived.len)
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
to_chat(client, "Sending Resources...")
|
||||
|
||||
for(var/asset in unreceived)
|
||||
var/datum/asset_cache_item/ACI
|
||||
if ((ACI = SSassets.cache[asset]))
|
||||
// log_asset("Sending asset [asset] to client [client]") CHOMP Edit Commenting this out to STOP THE FUCKING SPAM. THE LOGS ARE BLOATING
|
||||
client << browse_rsc(ACI.resource, asset)
|
||||
|
||||
client.sent_assets |= unreceived
|
||||
addtimer(CALLBACK(client, /client/proc/asset_cache_update_json), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
//The proc calls procs that sleep for long times.
|
||||
/proc/getFilesSlow(client/client, list/files, register_asset = TRUE, filerate = 3)
|
||||
var/startingfilerate = filerate
|
||||
for(var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (register_asset)
|
||||
register_asset(file, files[file])
|
||||
|
||||
if (send_asset(client, file))
|
||||
if (!(--filerate))
|
||||
filerate = startingfilerate
|
||||
client.asset_flush()
|
||||
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
//icons and virtual assets get copied to the dyn rsc before use
|
||||
/proc/register_asset(asset_name, asset)
|
||||
var/datum/asset_cache_item/ACI = new(asset_name, asset)
|
||||
|
||||
//this is technically never something that was supported and i want metrics on how often it happens if at all.
|
||||
if (SSassets.cache[asset_name])
|
||||
var/datum/asset_cache_item/OACI = SSassets.cache[asset_name]
|
||||
if (OACI.md5 != ACI.md5)
|
||||
stack_trace("ERROR: new asset added to the asset cache with the same name as another asset: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]")
|
||||
else
|
||||
var/list/stacktrace = gib_stack_trace()
|
||||
log_asset("WARNING: dupe asset added to the asset cache: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]\n[stacktrace.Join("\n")]")
|
||||
SSassets.cache[asset_name] = ACI
|
||||
return ACI
|
||||
|
||||
/// Returns the url of the asset, currently this is just its name, here to allow further work cdn'ing assets.
|
||||
/// Can be given an asset as well, this is just a work around for buggy edge cases where two assets may have the same name, doesn't matter now, but it will when the cdn comes.
|
||||
/proc/get_asset_url(asset_name, asset = null)
|
||||
var/datum/asset_cache_item/ACI = SSassets.cache[asset_name]
|
||||
return ACI?.url
|
||||
|
||||
//Generated names do not include file extention.
|
||||
//Used mainly for code that deals with assets in a generic way
|
||||
//The same asset will always lead to the same asset name
|
||||
/proc/generate_asset_name(file)
|
||||
return "asset.[md5(fcopy_rsc(file))]"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
/// Process asset cache client topic calls for "asset_cache_confirm_arrival=[INT]"
|
||||
/// Process asset cache client topic calls for `"asset_cache_confirm_arrival=[INT]"`
|
||||
/client/proc/asset_cache_confirm_arrival(job_id)
|
||||
var/asset_cache_job = round(text2num(job_id))
|
||||
//because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us into letting them append to a list without limit.
|
||||
@@ -10,17 +10,9 @@
|
||||
return asset_cache_job || TRUE
|
||||
|
||||
|
||||
/// Process asset cache client topic calls for "asset_cache_preload_data=[HTML+JSON_STRING]
|
||||
/// Process asset cache client topic calls for `"asset_cache_preload_data=[HTML+JSON_STRING]"`
|
||||
/client/proc/asset_cache_preload_data(data)
|
||||
/*var/jsonend = findtextEx(data, "{{{ENDJSONDATA}}}")
|
||||
if (!jsonend)
|
||||
CRASH("invalid asset_cache_preload_data, no jsonendmarker")*/
|
||||
//var/json = html_decode(copytext(data, 1, jsonend))
|
||||
var/json = data
|
||||
|
||||
// This is a stupid workaround to BYOND injecting this pngfix mess into IE7 clients browse()
|
||||
json = replacetext(json, "<!--\[if lt IE 7.]>\n<script defer type=text/javascript src=pngfix.js></script>\n<!\[endif]-->", "")
|
||||
|
||||
var/list/preloaded_assets = json_decode(json)
|
||||
|
||||
for (var/preloaded_asset in preloaded_assets)
|
||||
@@ -30,19 +22,17 @@
|
||||
sent_assets |= preloaded_assets
|
||||
|
||||
|
||||
/// Updates the client side stored html/json combo file used to keep track of what assets the client has between restarts/reconnects.
|
||||
/client/proc/asset_cache_update_json(verify = FALSE, list/new_assets = list())
|
||||
/// Updates the client side stored json file used to keep track of what assets the client has between restarts/reconnects.
|
||||
/client/proc/asset_cache_update_json()
|
||||
if (world.time - connection_time < 10 SECONDS) //don't override the existing data file on a new connection
|
||||
return
|
||||
if (!islist(new_assets))
|
||||
new_assets = list("[new_assets]" = md5(SSassets.cache[new_assets]))
|
||||
|
||||
src << browse(json_encode(new_assets|sent_assets), "file=asset_data.json&display=0")
|
||||
src << browse(json_encode(sent_assets), "file=asset_data.json&display=0")
|
||||
|
||||
/// Blocks until all currently sending browser assets have been sent.
|
||||
/// Blocks until all currently sending browse and browse_rsc assets have been sent.
|
||||
/// Due to byond limitations, this proc will sleep for 1 client round trip even if the client has no pending asset sends.
|
||||
/// This proc will return an untrue value if it had to return before confirming the send, such as timeout or the client going away.
|
||||
/client/proc/asset_flush(timeout = 50)
|
||||
/client/proc/browse_queue_flush(timeout = 50)
|
||||
var/job = ++last_asset_job
|
||||
var/t = 0
|
||||
var/timeout_time = timeout
|
||||
|
||||
@@ -1,23 +1,54 @@
|
||||
/**
|
||||
* # asset_cache_item
|
||||
*
|
||||
* An internal datum containing info on items in the asset cache. Mainly used to cache md5 info for speed.
|
||||
**/
|
||||
* # asset_cache_item
|
||||
*
|
||||
* An internal datum containing info on items in the asset cache. Mainly used to cache md5 info for speed.
|
||||
*/
|
||||
/datum/asset_cache_item
|
||||
/// the name of this asset item, becomes the key in SSassets.cache list
|
||||
var/name
|
||||
var/url
|
||||
var/md5
|
||||
/// md5() of the file this asset item represents.
|
||||
var/hash
|
||||
/// the file this asset represents
|
||||
var/resource
|
||||
/// our file extension e.g. .png, .gif, etc
|
||||
var/ext = ""
|
||||
/// Should this file also be sent via the legacy browse_rsc system
|
||||
/// when cdn transports are enabled?
|
||||
var/legacy = FALSE
|
||||
/// Used by the cdn system to keep legacy css assets with their parent
|
||||
/// css file. (css files resolve urls relative to the css file, so the
|
||||
/// legacy system can't be used if the css file itself could go out over
|
||||
/// the cdn)
|
||||
var/namespace = null
|
||||
/// True if this is the parent css or html file for an asset's namespace
|
||||
var/namespace_parent = FALSE
|
||||
/// TRUE for keeping local asset names when browse_rsc backend is used
|
||||
var/keep_local_name = FALSE
|
||||
|
||||
/datum/asset_cache_item/New(name, file)
|
||||
///pass in a valid file_hash if you have one to save it from needing to do it again.
|
||||
///pass in a valid dmi file path string e.g. "icons/path/to/dmi_file.dmi" to make generating the hash less expensive
|
||||
/datum/asset_cache_item/New(name, file, file_hash, dmi_file_path)
|
||||
if (!isfile(file))
|
||||
file = fcopy_rsc(file)
|
||||
md5 = md5(file)
|
||||
if (!md5)
|
||||
md5 = md5(fcopy_rsc(file))
|
||||
if (!md5)
|
||||
CRASH("invalid asset sent to asset cache")
|
||||
log_world("asset cache unexpected success of second fcopy_rsc")
|
||||
|
||||
hash = file_hash
|
||||
|
||||
//the given file is directly from a dmi file and is thus in the rsc already, we know that its file_hash will be correct
|
||||
if(!hash)
|
||||
if(dmi_file_path)
|
||||
hash = md5(file)
|
||||
else
|
||||
hash = md5asfile(file) //icons sent to the rsc md5 incorrectly when theyre given incorrect data
|
||||
if (!hash)
|
||||
CRASH("invalid asset sent to asset cache")
|
||||
src.name = name
|
||||
url = name
|
||||
var/extstart = findlasttext(name, ".")
|
||||
if (extstart)
|
||||
ext = ".[copytext(name, extstart+1)]"
|
||||
resource = file
|
||||
|
||||
/datum/asset_cache_item/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
/datum/asset_cache_item/CanProcCall(procname)
|
||||
return FALSE
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define ASSET_CROSS_ROUND_CACHE_DIRECTORY "tmp/assets"
|
||||
|
||||
//These datums are used to populate the asset cache, the proc "register()" does this.
|
||||
//Place any asset datums you create in asset_list_items.dm
|
||||
@@ -6,46 +7,101 @@
|
||||
GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
//get an assetdatum or make a new one
|
||||
/proc/get_asset_datum(type)
|
||||
//does NOT ensure it's filled, if you want that use get_asset_datum()
|
||||
/proc/load_asset_datum(type)
|
||||
return GLOB.asset_datums[type] || new type()
|
||||
|
||||
/proc/get_asset_datum(type)
|
||||
var/datum/asset/loaded_asset = GLOB.asset_datums[type] || new type()
|
||||
return loaded_asset.ensure_ready()
|
||||
|
||||
/datum/asset
|
||||
var/_abstract = /datum/asset
|
||||
var/cached_serialized_url_mappings
|
||||
var/cached_serialized_url_mappings_transport_type
|
||||
|
||||
/// Whether or not this asset should be loaded in the "early assets" SS
|
||||
var/early = FALSE
|
||||
|
||||
/// Whether or not this asset can be cached across rounds of the same commit under the `CACHE_ASSETS` config.
|
||||
/// This is not a *guarantee* the asset will be cached. Not all asset subtypes respect this field, and the
|
||||
/// config can, of course, be disabled.
|
||||
/// Disable this if your asset can change between rounds on the same exact version of the code.
|
||||
var/cross_round_cachable = FALSE
|
||||
|
||||
/datum/asset/New()
|
||||
GLOB.asset_datums[type] = src
|
||||
register()
|
||||
|
||||
/// Stub that allows us to react to something trying to get us
|
||||
/// Not useful here, more handy for sprite sheets
|
||||
/datum/asset/proc/ensure_ready()
|
||||
return src
|
||||
|
||||
/// Stub to hook into if your asset is having its generation queued by SSasset_loading
|
||||
/datum/asset/proc/queued_generation()
|
||||
CRASH("[type] inserted into SSasset_loading despite not implementing /proc/queued_generation")
|
||||
|
||||
/datum/asset/proc/get_url_mappings()
|
||||
return list()
|
||||
|
||||
/// Returns a cached tgui message of URL mappings
|
||||
/datum/asset/proc/get_serialized_url_mappings()
|
||||
if (isnull(cached_serialized_url_mappings) || cached_serialized_url_mappings_transport_type != SSassets.transport.type)
|
||||
cached_serialized_url_mappings = TGUI_CREATE_MESSAGE("asset/mappings", get_url_mappings())
|
||||
cached_serialized_url_mappings_transport_type = SSassets.transport.type
|
||||
|
||||
return cached_serialized_url_mappings
|
||||
|
||||
/datum/asset/proc/register()
|
||||
return
|
||||
|
||||
/datum/asset/proc/send(client)
|
||||
return
|
||||
|
||||
/// Returns whether or not the asset should attempt to read from cache
|
||||
/datum/asset/proc/should_refresh()
|
||||
return !cross_round_cachable || !config.cache_assets
|
||||
|
||||
//If you don't need anything complicated.
|
||||
/// Simply takes any generated file and saves it to the round-specific /logs folder. Useful for debugging potential issues with spritesheet generation/display.
|
||||
/// Only called when the SAVE_SPRITESHEETS config option is uncommented.
|
||||
/datum/asset/proc/save_to_logs(file_name, file_location)
|
||||
var/asset_path = "[log_path]/generated_assets/[file_name]"
|
||||
fdel(asset_path) // just in case, sadly we can't use rust_g stuff here.
|
||||
fcopy(file_location, asset_path)
|
||||
|
||||
/// If you don't need anything complicated.
|
||||
/datum/asset/simple
|
||||
_abstract = /datum/asset/simple
|
||||
/// list of assets for this datum in the form of:
|
||||
/// asset_filename = asset_file. At runtime the asset_file will be
|
||||
/// converted into a asset_cache datum.
|
||||
var/assets = list()
|
||||
/// Set to true to have this asset also be sent via the legacy browse_rsc
|
||||
/// system when cdn transports are enabled?
|
||||
var/legacy = FALSE
|
||||
/// TRUE for keeping local asset names when browse_rsc backend is used
|
||||
var/keep_local_name = FALSE
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
assets[asset_name] = register_asset(asset_name, assets[asset_name])
|
||||
var/datum/asset_cache_item/ACI = SSassets.transport.register_asset(asset_name, assets[asset_name])
|
||||
if (!ACI)
|
||||
log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]")
|
||||
continue
|
||||
if (legacy)
|
||||
ACI.legacy = legacy
|
||||
if (keep_local_name)
|
||||
ACI.keep_local_name = keep_local_name
|
||||
assets[asset_name] = ACI
|
||||
|
||||
/datum/asset/simple/send(client)
|
||||
. = send_asset_list(client, assets)
|
||||
. = SSassets.transport.send_assets(client, assets)
|
||||
|
||||
/datum/asset/simple/get_url_mappings()
|
||||
. = list()
|
||||
for (var/asset_name in assets)
|
||||
var/datum/asset_cache_item/ACI = assets[asset_name]
|
||||
if (!ACI)
|
||||
continue
|
||||
.[asset_name] = ACI.url
|
||||
|
||||
.[asset_name] = SSassets.transport.get_asset_url(asset_name, assets[asset_name])
|
||||
|
||||
// For registering or sending multiple others at once
|
||||
/datum/asset/group
|
||||
@@ -54,7 +110,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
/datum/asset/group/register()
|
||||
for(var/type in children)
|
||||
get_asset_datum(type)
|
||||
load_asset_datum(type)
|
||||
|
||||
/datum/asset/group/send(client/C)
|
||||
for(var/type in children)
|
||||
@@ -78,40 +134,122 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
/datum/asset/spritesheet
|
||||
_abstract = /datum/asset/spritesheet
|
||||
cross_round_cachable = TRUE
|
||||
var/name
|
||||
/// List of arguments to pass into queuedInsert
|
||||
/// Exists so we can queue icon insertion, mostly for stuff like preferences
|
||||
var/list/to_generate = list()
|
||||
var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
|
||||
var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
|
||||
var/list/cached_spritesheets_needed
|
||||
var/generating_cache = FALSE
|
||||
var/fully_generated = FALSE
|
||||
/// If this asset should be fully loaded on new
|
||||
/// Defaults to false so we can process this stuff nicely
|
||||
var/load_immediately = FALSE
|
||||
VAR_PRIVATE
|
||||
// Kept in state so that the result is the same, even when the files are created, for this run
|
||||
should_refresh = null
|
||||
|
||||
/datum/asset/spritesheet/proc/should_load_immediately()
|
||||
#ifdef DO_NOT_DEFER_ASSETS
|
||||
return TRUE
|
||||
#else
|
||||
return load_immediately
|
||||
#endif
|
||||
|
||||
|
||||
/datum/asset/spritesheet/should_refresh()
|
||||
if (..())
|
||||
return TRUE
|
||||
|
||||
if (isnull(should_refresh))
|
||||
// `fexists` seems to always fail on static-time
|
||||
should_refresh = !fexists(css_cache_filename()) || !fexists(data_cache_filename())
|
||||
|
||||
return should_refresh
|
||||
|
||||
/datum/asset/spritesheet/register()
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
|
||||
if (!name)
|
||||
CRASH("spritesheet [type] cannot register without a name")
|
||||
|
||||
if (!should_refresh() && read_from_cache())
|
||||
fully_generated = TRUE
|
||||
return
|
||||
|
||||
// If it's cached, may as well load it now, while the loading is cheap
|
||||
if(config.cache_assets && cross_round_cachable)
|
||||
load_immediately = TRUE
|
||||
|
||||
create_spritesheets()
|
||||
if(should_load_immediately())
|
||||
realize_spritesheets(yield = FALSE)
|
||||
else
|
||||
SSasset_loading.queue_asset(src)
|
||||
|
||||
/datum/asset/spritesheet/proc/realize_spritesheets(yield)
|
||||
if(fully_generated)
|
||||
return
|
||||
while(length(to_generate))
|
||||
var/list/stored_args = to_generate[to_generate.len]
|
||||
to_generate.len--
|
||||
queuedInsert(arglist(stored_args))
|
||||
if(yield && TICK_CHECK)
|
||||
return
|
||||
|
||||
ensure_stripped()
|
||||
for(var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
||||
var/res_name = "spritesheet_[name].css"
|
||||
var/fname = "data/spritesheets/[res_name]"
|
||||
fdel(fname)
|
||||
text2file(generate_css(), fname)
|
||||
register_asset(res_name, fcopy_rsc(fname))
|
||||
fdel(fname)
|
||||
SSassets.transport.register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
||||
var/css_name = "spritesheet_[name].css"
|
||||
var/file_directory = "data/spritesheets/[css_name]"
|
||||
fdel(file_directory)
|
||||
text2file(generate_css(), file_directory)
|
||||
SSassets.transport.register_asset(css_name, fcopy_rsc(file_directory))
|
||||
|
||||
/datum/asset/spritesheet/send(client/C)
|
||||
if(config.save_spritesheets)
|
||||
save_to_logs(file_name = css_name, file_location = file_directory)
|
||||
|
||||
fdel(file_directory)
|
||||
|
||||
if (config.cache_assets && cross_round_cachable)
|
||||
write_to_cache()
|
||||
fully_generated = TRUE
|
||||
// If we were ever in there, remove ourselves
|
||||
SSasset_loading.dequeue_asset(src)
|
||||
|
||||
/datum/asset/spritesheet/queued_generation()
|
||||
realize_spritesheets(yield = TRUE)
|
||||
|
||||
/datum/asset/spritesheet/ensure_ready()
|
||||
if(!fully_generated)
|
||||
realize_spritesheets(yield = FALSE)
|
||||
return ..()
|
||||
|
||||
/datum/asset/spritesheet/send(client/client)
|
||||
if (!name)
|
||||
return
|
||||
|
||||
if (!should_refresh())
|
||||
return send_from_cache(client)
|
||||
|
||||
var/all = list("spritesheet_[name].css")
|
||||
for(var/size_id in sizes)
|
||||
all += "[name]_[size_id].png"
|
||||
. = send_asset_list(C, all)
|
||||
. = SSassets.transport.send_assets(client, all)
|
||||
|
||||
/datum/asset/spritesheet/get_url_mappings()
|
||||
if (!name)
|
||||
return
|
||||
. = list("spritesheet_[name].css" = get_asset_url("spritesheet_[name].css"))
|
||||
|
||||
if (!should_refresh())
|
||||
return get_cached_url_mappings()
|
||||
|
||||
. = list("spritesheet_[name].css" = SSassets.transport.get_asset_url("spritesheet_[name].css"))
|
||||
for(var/size_id in sizes)
|
||||
.["[name]_[size_id].png"] = get_asset_url("[name]_[size_id].png")
|
||||
|
||||
|
||||
.["[name]_[size_id].png"] = SSassets.transport.get_asset_url("[name]_[size_id].png")
|
||||
|
||||
/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
|
||||
for(var/size_id in sizes_to_strip)
|
||||
@@ -120,13 +258,19 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
continue
|
||||
|
||||
// save flattened version
|
||||
var/fname = "data/spritesheets/[name]_[size_id].png"
|
||||
fcopy(size[SPRSZ_ICON], fname)
|
||||
var/error = rustg_dmi_strip_metadata(fname)
|
||||
var/png_name = "[name]_[size_id].png"
|
||||
var/file_directory = "data/spritesheets/[png_name]"
|
||||
fcopy(size[SPRSZ_ICON], file_directory)
|
||||
var/error = rustg_dmi_strip_metadata(file_directory)
|
||||
if(length(error))
|
||||
stack_trace("Failed to strip [name]_[size_id].png: [error]")
|
||||
size[SPRSZ_STRIPPED] = icon(fname)
|
||||
fdel(fname)
|
||||
stack_trace("Failed to strip [png_name]: [error]")
|
||||
size[SPRSZ_STRIPPED] = icon(file_directory)
|
||||
|
||||
// this is useful here for determining if weird sprite issues (like having a white background) are a cause of what we're doing DM-side or not since we can see the full flattened thing at-a-glance.
|
||||
if(config.save_spritesheets)
|
||||
save_to_logs(file_name = png_name, file_location = file_directory)
|
||||
|
||||
fdel(file_directory)
|
||||
|
||||
/datum/asset/spritesheet/proc/generate_css()
|
||||
var/list/out = list()
|
||||
@@ -134,7 +278,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
for (var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[get_asset_url("[name]_[size_id].png")]') no-repeat;}"
|
||||
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[get_background_url("[name]_[size_id].png")]') no-repeat;}"
|
||||
|
||||
for (var/sprite_id in sprites)
|
||||
var/sprite = sprites[sprite_id]
|
||||
@@ -152,10 +296,109 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
return out.Join("\n")
|
||||
|
||||
/datum/asset/spritesheet/proc/css_cache_filename()
|
||||
return "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css"
|
||||
|
||||
/datum/asset/spritesheet/proc/data_cache_filename()
|
||||
return "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].json"
|
||||
|
||||
/datum/asset/spritesheet/proc/read_from_cache()
|
||||
return read_css_from_cache() && read_data_from_cache()
|
||||
|
||||
/datum/asset/spritesheet/proc/read_css_from_cache()
|
||||
var/replaced_css = file2text(css_cache_filename())
|
||||
|
||||
var/regex/find_background_urls = regex(@"background:url\('%(.+?)%'\)", "g")
|
||||
while (find_background_urls.Find(replaced_css))
|
||||
var/asset_id = find_background_urls.group[1]
|
||||
var/asset_cache_item = SSassets.transport.register_asset(asset_id, "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[asset_id]")
|
||||
var/asset_url = SSassets.transport.get_asset_url(asset_cache_item = asset_cache_item)
|
||||
replaced_css = replacetext(replaced_css, find_background_urls.match, "background:url('[asset_url]')")
|
||||
LAZYADD(cached_spritesheets_needed, asset_id)
|
||||
|
||||
var/finalized_name = "spritesheet_[name].css"
|
||||
var/replaced_css_filename = "data/spritesheets/[finalized_name]"
|
||||
rustg_file_write(replaced_css, replaced_css_filename)
|
||||
SSassets.transport.register_asset(finalized_name, replaced_css_filename)
|
||||
|
||||
if(config.save_spritesheets)
|
||||
save_to_logs(file_name = finalized_name, file_location = replaced_css_filename)
|
||||
|
||||
fdel(replaced_css_filename)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/asset/spritesheet/proc/read_data_from_cache()
|
||||
var/json = json_decode(file2text(data_cache_filename()))
|
||||
|
||||
if (islist(json["sprites"]))
|
||||
sprites = json["sprites"]
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/asset/spritesheet/proc/send_from_cache(client/client)
|
||||
if (isnull(cached_spritesheets_needed))
|
||||
stack_trace("cached_spritesheets_needed was null when sending assets from [type] from cache")
|
||||
cached_spritesheets_needed = list()
|
||||
|
||||
return SSassets.transport.send_assets(client, cached_spritesheets_needed + "spritesheet_[name].css")
|
||||
|
||||
/// Returns the URL to put in the background:url of the CSS asset
|
||||
/datum/asset/spritesheet/proc/get_background_url(asset)
|
||||
if (generating_cache)
|
||||
return "%[asset]%"
|
||||
else
|
||||
return SSassets.transport.get_asset_url(asset)
|
||||
|
||||
/datum/asset/spritesheet/proc/write_to_cache()
|
||||
write_css_to_cache()
|
||||
write_data_to_cache()
|
||||
|
||||
/datum/asset/spritesheet/proc/write_css_to_cache()
|
||||
for (var/size_id in sizes)
|
||||
fcopy(SSassets.cache["[name]_[size_id].png"].resource, "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name]_[size_id].png")
|
||||
|
||||
generating_cache = TRUE
|
||||
var/mock_css = generate_css()
|
||||
generating_cache = FALSE
|
||||
|
||||
rustg_file_write(mock_css, css_cache_filename())
|
||||
|
||||
/datum/asset/spritesheet/proc/write_data_to_cache()
|
||||
rustg_file_write(json_encode(list(
|
||||
"sprites" = sprites,
|
||||
)), data_cache_filename())
|
||||
|
||||
/datum/asset/spritesheet/proc/get_cached_url_mappings()
|
||||
var/list/mappings = list()
|
||||
mappings["spritesheet_[name].css"] = SSassets.transport.get_asset_url("spritesheet_[name].css")
|
||||
|
||||
for (var/asset_name in cached_spritesheets_needed)
|
||||
mappings[asset_name] = SSassets.transport.get_asset_url(asset_name)
|
||||
|
||||
return mappings
|
||||
|
||||
/// Override this in order to start the creation of the spritehseet.
|
||||
/// This is where all your Insert, InsertAll, etc calls should be inside.
|
||||
/datum/asset/spritesheet/proc/create_spritesheets()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
CRASH("create_spritesheets() not implemented for [type]!")
|
||||
|
||||
/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
|
||||
if(should_load_immediately())
|
||||
queuedInsert(sprite_name, I, icon_state, dir, frame, moving)
|
||||
else
|
||||
to_generate += list(args.Copy())
|
||||
|
||||
/datum/asset/spritesheet/proc/queuedInsert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
|
||||
I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
|
||||
if (!I || !length(icon_states(I))) // that direction or state doesn't exist
|
||||
return
|
||||
|
||||
//var/start_usage = world.tick_usage
|
||||
|
||||
//any sprite modifications we want to do (aka, coloring a greyscaled asset)
|
||||
I = ModifyInserted(I)
|
||||
var/size_id = "[I.Width()]x[I.Height()]"
|
||||
var/size = sizes[size_id]
|
||||
|
||||
@@ -164,14 +407,34 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
if (size)
|
||||
var/position = size[SPRSZ_COUNT]++
|
||||
// Icons are essentially representations of files + modifications
|
||||
// Because of this, byond keeps them in a cache. It does this in a really dumb way tho
|
||||
// It's essentially a FIFO queue. So after we do icon() some amount of times, our old icons go out of cache
|
||||
// When this happens it becomes impossible to modify them, trying to do so will instead throw a
|
||||
// "bad icon" error.
|
||||
// What we're doing here is ensuring our icon is in the cache by refreshing it, so we can modify it w/o runtimes.
|
||||
var/icon/sheet = size[SPRSZ_ICON]
|
||||
var/icon/sheet_copy = icon(sheet)
|
||||
size[SPRSZ_STRIPPED] = null
|
||||
sheet.Insert(I, icon_state=sprite_name)
|
||||
sheet_copy.Insert(I, icon_state=sprite_name)
|
||||
size[SPRSZ_ICON] = sheet_copy
|
||||
|
||||
sprites[sprite_name] = list(size_id, position)
|
||||
else
|
||||
sizes[size_id] = size = list(1, I, null)
|
||||
sprites[sprite_name] = list(size_id, 0)
|
||||
|
||||
//SSblackbox.record_feedback("tally", "spritesheet_queued_insert_time", TICK_USAGE_TO_MS(start_usage), name)
|
||||
|
||||
/**
|
||||
* A simple proc handing the Icon for you to modify before it gets turned into an asset.
|
||||
*
|
||||
* Arguments:
|
||||
* * I: icon being turned into an asset
|
||||
*/
|
||||
/datum/asset/spritesheet/proc/ModifyInserted(icon/pre_asset)
|
||||
return pre_asset
|
||||
|
||||
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
|
||||
if (length(prefix))
|
||||
prefix = "[prefix]-"
|
||||
@@ -188,14 +451,14 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
return {"<link rel="stylesheet" href="[css_filename()]" />"}
|
||||
|
||||
/datum/asset/spritesheet/proc/css_filename()
|
||||
return get_asset_url("spritesheet_[name].css")
|
||||
return SSassets.transport.get_asset_url("spritesheet_[name].css")
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"<span class="[name][size_id] [sprite_name]"></span>"}
|
||||
return {"<span class='[name][size_id] [sprite_name]'></span>"}
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
@@ -204,6 +467,19 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"[name][size_id] [sprite_name]"}
|
||||
|
||||
/**
|
||||
* Returns the size class (ex design32x32) for a given sprite's icon
|
||||
*
|
||||
* Arguments:
|
||||
* * sprite_name - The sprite to get the size of
|
||||
*/
|
||||
/datum/asset/spritesheet/proc/icon_size_id(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return "[name][size_id]"
|
||||
|
||||
#undef SPR_SIZE
|
||||
#undef SPR_IDX
|
||||
#undef SPRSZ_COUNT
|
||||
@@ -211,14 +487,31 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
#undef SPRSZ_STRIPPED
|
||||
|
||||
|
||||
/datum/asset/changelog_item
|
||||
_abstract = /datum/asset/changelog_item
|
||||
var/item_filename
|
||||
|
||||
/datum/asset/changelog_item/New(date)
|
||||
item_filename = sanitize_filename("[date].yml")
|
||||
SSassets.transport.register_asset(item_filename, file("html/changelogs_ch/archive/" + item_filename))
|
||||
|
||||
/datum/asset/changelog_item/send(client)
|
||||
if (!item_filename)
|
||||
return
|
||||
. = SSassets.transport.send_assets(client, item_filename)
|
||||
|
||||
/datum/asset/changelog_item/get_url_mappings()
|
||||
if (!item_filename)
|
||||
return
|
||||
. = list("[item_filename]" = SSassets.transport.get_asset_url(item_filename))
|
||||
|
||||
/datum/asset/spritesheet/simple
|
||||
_abstract = /datum/asset/spritesheet/simple
|
||||
var/list/assets
|
||||
|
||||
/datum/asset/spritesheet/simple/register()
|
||||
/datum/asset/spritesheet/simple/create_spritesheets()
|
||||
for (var/key in assets)
|
||||
Insert(key, assets[key])
|
||||
..()
|
||||
|
||||
//Generates assets based on iconstates of a single icon
|
||||
/datum/asset/simple/icon_states
|
||||
@@ -243,7 +536,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
if (generic_icon_names)
|
||||
asset_name = "[generate_asset_name(asset)].png"
|
||||
|
||||
register_asset(asset_name, asset)
|
||||
SSassets.transport.register_asset(asset_name, asset)
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons
|
||||
_abstract = /datum/asset/simple/icon_states/multiple_icons
|
||||
@@ -253,4 +546,79 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
for(var/i in icons)
|
||||
..(i)
|
||||
|
||||
/// Namespace'ed assets (for static css and html files)
|
||||
/// When sent over a cdn transport, all assets in the same asset datum will exist in the same folder, as their plain names.
|
||||
/// Used to ensure css files can reference files by url() without having to generate the css at runtime, both the css file and the files it depends on must exist in the same namespace asset datum. (Also works for html)
|
||||
/// For example `blah.css` with asset `blah.png` will get loaded as `namespaces/a3d..14f/f12..d3c.css` and `namespaces/a3d..14f/blah.png`. allowing the css file to load `blah.png` by a relative url rather then compute the generated url with get_url_mappings().
|
||||
/// The namespace folder's name will change if any of the assets change. (excluding parent assets)
|
||||
/datum/asset/simple/namespaced
|
||||
_abstract = /datum/asset/simple/namespaced
|
||||
/// parents - list of the parent asset or assets (in name = file assoicated format) for this namespace.
|
||||
/// parent assets must be referenced by their generated url, but if an update changes a parent asset, it won't change the namespace's identity.
|
||||
var/list/parents = list()
|
||||
|
||||
/datum/asset/simple/namespaced/register()
|
||||
if (legacy)
|
||||
assets |= parents
|
||||
var/list/hashlist = list()
|
||||
var/list/sorted_assets = sortList(assets)
|
||||
|
||||
for (var/asset_name in sorted_assets)
|
||||
var/datum/asset_cache_item/ACI = new(asset_name, sorted_assets[asset_name])
|
||||
if (!ACI?.hash)
|
||||
log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]")
|
||||
continue
|
||||
hashlist += ACI.hash
|
||||
sorted_assets[asset_name] = ACI
|
||||
var/namespace = md5(hashlist.Join())
|
||||
|
||||
for (var/asset_name in parents)
|
||||
var/datum/asset_cache_item/ACI = new(asset_name, parents[asset_name])
|
||||
if (!ACI?.hash)
|
||||
log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]")
|
||||
continue
|
||||
ACI.namespace_parent = TRUE
|
||||
sorted_assets[asset_name] = ACI
|
||||
|
||||
for (var/asset_name in sorted_assets)
|
||||
var/datum/asset_cache_item/ACI = sorted_assets[asset_name]
|
||||
if (!ACI?.hash)
|
||||
log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]")
|
||||
continue
|
||||
ACI.namespace = namespace
|
||||
|
||||
assets = sorted_assets
|
||||
..()
|
||||
|
||||
/// Get a html string that will load a html asset.
|
||||
/// Needed because byond doesn't allow you to browse() to a url.
|
||||
/datum/asset/simple/namespaced/proc/get_htmlloader(filename)
|
||||
return url2htmlloader(SSassets.transport.get_asset_url(filename, assets[filename]))
|
||||
|
||||
/// A subtype to generate a JSON file from a list
|
||||
/datum/asset/json
|
||||
_abstract = /datum/asset/json
|
||||
/// The filename, will be suffixed with ".json"
|
||||
var/name
|
||||
|
||||
/datum/asset/json/send(client)
|
||||
return SSassets.transport.send_assets(client, "[name].json")
|
||||
|
||||
/datum/asset/json/get_url_mappings()
|
||||
return list(
|
||||
"[name].json" = SSassets.transport.get_asset_url("[name].json"),
|
||||
)
|
||||
|
||||
/datum/asset/json/register()
|
||||
var/filename = "data/[name].json"
|
||||
fdel(filename)
|
||||
text2file(json_encode(generate()), filename)
|
||||
SSassets.transport.register_asset("[name].json", fcopy_rsc(filename))
|
||||
fdel(filename)
|
||||
|
||||
/// Returns the data that will be JSON encoded
|
||||
/datum/asset/json/proc/generate()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
CRASH("generate() not implemented for [type]!")
|
||||
|
||||
#undef ASSET_CROSS_ROUND_CACHE_DIRECTORY
|
||||
|
||||
@@ -260,29 +260,26 @@
|
||||
/datum/asset/spritesheet/pipes
|
||||
name = "pipes"
|
||||
|
||||
/datum/asset/spritesheet/pipes/register()
|
||||
/datum/asset/spritesheet/pipes/create_spritesheets()
|
||||
for(var/each in list('icons/obj/pipe-item.dmi', 'icons/obj/pipes/disposal.dmi'))
|
||||
InsertAll("", each, global.alldirs)
|
||||
..()
|
||||
|
||||
//VOREStation Add
|
||||
/datum/asset/spritesheet/vore
|
||||
name = "vore"
|
||||
|
||||
/datum/asset/spritesheet/vore/register()
|
||||
/datum/asset/spritesheet/vore/create_spritesheets()
|
||||
var/icon/downscaled = icon('modular_chomp/icons/mob/screen_full_vore_ch.dmi') //CHOMPedit: preserving save data
|
||||
downscaled.Scale(240, 240)
|
||||
InsertAll("", downscaled)
|
||||
..()
|
||||
|
||||
/datum/asset/spritesheet/vore_fixed //This should be getting loaded in the TGUI vore panel but the game refuses to do so, for some reason. It only loads the vore spritesheet. //CHOMPedit
|
||||
name = "fixedvore" //CHOMPedit
|
||||
|
||||
/datum/asset/spritesheet/vore_fixed/register() //CHOMPedi start: preserving save data
|
||||
/datum/asset/spritesheet/vore_fixed/create_spritesheets() //CHOMPedi start: preserving save data
|
||||
var/icon/downscaledVF = icon('icons/mob/screen_full_vore.dmi')
|
||||
downscaledVF.Scale(240, 240)
|
||||
InsertAll("", downscaledVF) //CHOMpedit end
|
||||
..()
|
||||
|
||||
//VOREStation Add End
|
||||
|
||||
@@ -348,7 +345,7 @@
|
||||
/datum/asset/spritesheet/vending
|
||||
name = "vending"
|
||||
|
||||
/datum/asset/spritesheet/vending/register()
|
||||
/datum/asset/spritesheet/vending/create_spritesheets()
|
||||
populate_vending_products()
|
||||
for(var/atom/item as anything in GLOB.vending_products)
|
||||
if(!ispath(item, /atom))
|
||||
@@ -386,7 +383,6 @@
|
||||
var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
|
||||
|
||||
Insert(imgid, I)
|
||||
return ..()
|
||||
|
||||
// this is cursed but necessary or else vending product icons can be missing
|
||||
// basically, if there's any vending machines that aren't already mapped in, our register() will not know
|
||||
@@ -447,10 +443,10 @@
|
||||
assets["patch[i].png"] = icon('icons/obj/chemical.dmi', "patch[i]") // CHOMPedit
|
||||
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
SSassets.transport.register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/chem_master/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
SSassets.transport.send_assets(client, assets, verify)
|
||||
|
||||
//Cloning pod sprites for UIs
|
||||
/datum/asset/cloning
|
||||
@@ -462,10 +458,10 @@
|
||||
assets["pod_cloning.gif"] = icon('icons/obj/cloning.dmi', "pod_cloning")
|
||||
assets["pod_mess.gif"] = icon('icons/obj/cloning.dmi', "pod_mess")
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
SSassets.transport.register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/cloning/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
SSassets.transport.send_assets(client, assets, verify)
|
||||
|
||||
// VOREStation Add
|
||||
/datum/asset/cloning/resleeving
|
||||
@@ -476,15 +472,14 @@
|
||||
assets["synthprinter.gif"] = icon('icons/obj/machines/synthpod.dmi', "pod_0")
|
||||
assets["synthprinter_working.gif"] = icon('icons/obj/machines/synthpod.dmi', "pod_1")
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
SSassets.transport.register_asset(asset_name, assets[asset_name])
|
||||
// VOREStation Add End
|
||||
|
||||
/datum/asset/spritesheet/sheetmaterials
|
||||
name = "sheetmaterials"
|
||||
|
||||
/datum/asset/spritesheet/sheetmaterials/register()
|
||||
/datum/asset/spritesheet/sheetmaterials/create_spritesheets()
|
||||
InsertAll("", 'icons/obj/stacks.dmi')
|
||||
..()
|
||||
|
||||
// Nanomaps
|
||||
/datum/asset/simple/nanomaps
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
/datum/asset/spritesheet/chat
|
||||
name = "chat"
|
||||
|
||||
/datum/asset/spritesheet/chat/create_spritesheets()
|
||||
//honk
|
||||
//This function has to be overridden otherwise it will generate runtimes
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/datum/asset/simple/fontawesome
|
||||
/datum/asset/simple/namespaced/fontawesome
|
||||
assets = list(
|
||||
"fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
|
||||
"fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
|
||||
"fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
|
||||
"fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
|
||||
"font-awesome.css" = 'html/font-awesome/css/all.min.css',
|
||||
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
|
||||
"fa-regular-400.ttf" = 'html/font-awesome/webfonts/fa-regular-400.ttf',
|
||||
"fa-solid-900.ttf" = 'html/font-awesome/webfonts/fa-solid-900.ttf',
|
||||
"fa-v4compatibility.ttf" = 'html/font-awesome/webfonts/fa-v4compatibility.ttf',
|
||||
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css',
|
||||
)
|
||||
parents = list("font-awesome.css" = 'html/font-awesome/css/all.min.css')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/datum/asset/simple/jquery
|
||||
legacy = TRUE
|
||||
assets = list(
|
||||
"jquery.min.js" = 'code/modules/tooltip/jquery.min.js',
|
||||
"jquery.min.js" = 'html/jquery/jquery.min.js',
|
||||
)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/asset/simple/tgfont
|
||||
/datum/asset/simple/namespaced/tgfont
|
||||
assets = list(
|
||||
"tgfont.eot" = file("tgui/packages/tgfont/dist/tgfont.eot"),
|
||||
"tgfont.woff2" = file("tgui/packages/tgfont/dist/tgfont.woff2"),
|
||||
)
|
||||
parents = list(
|
||||
"tgfont.css" = file("tgui/packages/tgfont/dist/tgfont.css"),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# Asset cache system
|
||||
|
||||
## Framework for managing browser assets (javascript,css,images,etc)
|
||||
|
||||
This manages getting the asset to the client without doing unneeded re-sends, as well as utilizing any configured cdns.
|
||||
|
||||
There are two frameworks for using this system:
|
||||
|
||||
### Asset datum:
|
||||
|
||||
Make a datum in asset_list_items.dm with your browser assets for your thing.
|
||||
|
||||
Checkout asset_list.dm for the helper subclasses
|
||||
|
||||
The `simple` subclass will most likely be of use for most cases.
|
||||
|
||||
Call get_asset_datum() with the type of the datum you created to get your asset cache datum
|
||||
|
||||
Call .send(client|usr) on that datum to send the asset to the client. Depending on the asset transport this may or may not block.
|
||||
|
||||
Call .get_url_mappings() to get an associated list with the urls your assets can be found at.
|
||||
|
||||
### Manual backend:
|
||||
|
||||
See the documentation for `/datum/asset_transport` for the backend api the asset datums utilize.
|
||||
|
||||
The global variable `SSassets.transport` contains the currently configured transport.
|
||||
|
||||
|
||||
|
||||
### Notes:
|
||||
|
||||
Because byond browse() calls use non-blocking queues, if your code uses output() (which bypasses all of these queues) to invoke javascript functions you will need to first have the javascript announce to the server it has loaded before trying to invoke js functions.
|
||||
|
||||
To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details.
|
||||
|
||||
CSS files that use url() can be made to use the CDN without needing to rewrite all url() calls in code by using the namespaced helper datum. See the documentation for `/datum/asset/simple/namespaced` for details.
|
||||
@@ -0,0 +1,162 @@
|
||||
/// When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
/// Base browse_rsc asset transport
|
||||
/datum/asset_transport
|
||||
var/name = "Simple browse_rsc asset transport"
|
||||
var/static/list/preload
|
||||
/// Don't mutate the filename of assets when sending via browse_rsc.
|
||||
/// This is to make it easier to debug issues with assets, and allow server operators to bypass issues that make it to production.
|
||||
/// If turning this on fixes asset issues, something isn't using get_asset_url and the asset isn't marked legacy, fix one of those.
|
||||
var/dont_mutate_filenames = FALSE
|
||||
|
||||
/// Called when the transport is loaded by the config controller, not called on the default transport unless it gets loaded by a config change.
|
||||
/datum/asset_transport/proc/Load()
|
||||
if (config.asset_simple_preload)
|
||||
for(var/client/C in GLOB.clients)
|
||||
addtimer(CALLBACK(src, PROC_REF(send_assets_slow), C, preload), 1 SECONDS)
|
||||
|
||||
/// Initialize - Called when SSassets initializes.
|
||||
/datum/asset_transport/proc/Initialize(list/assets)
|
||||
preload = assets.Copy()
|
||||
if (!config.asset_simple_preload)
|
||||
return
|
||||
for(var/client/C in GLOB.clients)
|
||||
addtimer(CALLBACK(src, PROC_REF(send_assets_slow), C, preload), 1 SECONDS)
|
||||
|
||||
|
||||
/**
|
||||
* Register a browser asset with the asset cache system.
|
||||
* returns a /datum/asset_cache_item.
|
||||
* mutiple calls to register the same asset under the same asset_name return the same datum.
|
||||
*
|
||||
* Arguments:
|
||||
* * asset_name - the identifier of the asset.
|
||||
* * asset - the actual asset file (or an asset_cache_item datum).
|
||||
* * file_hash - optional, a hash of the contents of the asset files contents. used so asset_cache_item doesnt have to hash it again
|
||||
* * dmi_file_path - optional, means that the given asset is from the rsc and thus we dont need to do some expensive operations
|
||||
*/
|
||||
/datum/asset_transport/proc/register_asset(asset_name, asset, file_hash, dmi_file_path)
|
||||
var/datum/asset_cache_item/ACI = asset
|
||||
if (!istype(ACI))
|
||||
ACI = new(asset_name, asset, file_hash, dmi_file_path)
|
||||
if (!ACI || !ACI.hash)
|
||||
CRASH("ERROR: Invalid asset: [asset_name]:[asset]:[ACI]")
|
||||
if (SSassets.cache[asset_name])
|
||||
var/datum/asset_cache_item/OACI = SSassets.cache[asset_name]
|
||||
OACI.legacy = ACI.legacy = (ACI.legacy|OACI.legacy)
|
||||
OACI.namespace_parent = ACI.namespace_parent = (ACI.namespace_parent | OACI.namespace_parent)
|
||||
OACI.namespace = OACI.namespace || ACI.namespace
|
||||
if (OACI.hash != ACI.hash)
|
||||
var/error_msg = "ERROR: new asset added to the asset cache with the same name as another asset: [asset_name] existing asset hash: [OACI.hash] new asset hash:[ACI.hash]"
|
||||
stack_trace(error_msg)
|
||||
log_asset(error_msg)
|
||||
else
|
||||
if (length(ACI.namespace))
|
||||
return ACI
|
||||
return OACI
|
||||
|
||||
SSassets.cache[asset_name] = ACI
|
||||
return ACI
|
||||
|
||||
|
||||
/// Returns a url for a given asset.
|
||||
/// asset_name - Name of the asset.
|
||||
/// asset_cache_item - asset cache item datum for the asset, optional, overrides asset_name
|
||||
/datum/asset_transport/proc/get_asset_url(asset_name, datum/asset_cache_item/asset_cache_item)
|
||||
if (!istype(asset_cache_item))
|
||||
asset_cache_item = SSassets.cache[asset_name]
|
||||
// To ensure code that breaks on cdns breaks in local testing, we only
|
||||
// use the normal filename on legacy assets and name space assets.
|
||||
var/keep_local_name = dont_mutate_filenames \
|
||||
|| asset_cache_item.legacy \
|
||||
|| asset_cache_item.keep_local_name \
|
||||
|| (asset_cache_item.namespace && !asset_cache_item.namespace_parent)
|
||||
if (keep_local_name)
|
||||
return url_encode(asset_cache_item.name)
|
||||
return url_encode("asset.[asset_cache_item.hash][asset_cache_item.ext]")
|
||||
|
||||
|
||||
/// Sends a list of browser assets to a client
|
||||
/// client - a client or mob
|
||||
/// asset_list - A list of asset filenames to be sent to the client. Can optionally be assoicated with the asset's asset_cache_item datum.
|
||||
/// Returns TRUE if any assets were sent.
|
||||
/datum/asset_transport/proc/send_assets(client/client, list/asset_list)
|
||||
if (!istype(client))
|
||||
if (ismob(client))
|
||||
var/mob/M = client
|
||||
if (M.client)
|
||||
client = M.client
|
||||
else //no stacktrace because this will mainly happen because the client went away
|
||||
return
|
||||
else
|
||||
CRASH("Invalid argument: client: `[client]`")
|
||||
if (!islist(asset_list))
|
||||
asset_list = list(asset_list)
|
||||
var/list/unreceived = list()
|
||||
|
||||
for (var/asset_name in asset_list)
|
||||
var/datum/asset_cache_item/ACI = asset_list[asset_name]
|
||||
if (!istype(ACI) && !(ACI = SSassets.cache[asset_name]))
|
||||
log_asset("ERROR: can't send asset `[asset_name]`: unregistered or invalid state: `[ACI]`")
|
||||
continue
|
||||
var/asset_file = ACI.resource
|
||||
if (!asset_file)
|
||||
log_asset("ERROR: can't send asset `[asset_name]`: invalid registered resource: `[ACI.resource]`")
|
||||
continue
|
||||
|
||||
var/asset_hash = ACI.hash
|
||||
var/new_asset_name = asset_name
|
||||
var/keep_local_name = dont_mutate_filenames \
|
||||
|| ACI.legacy \
|
||||
|| ACI.keep_local_name \
|
||||
|| (ACI.namespace && !ACI.namespace_parent)
|
||||
if (!keep_local_name)
|
||||
new_asset_name = "asset.[ACI.hash][ACI.ext]"
|
||||
if (client.sent_assets[new_asset_name] == asset_hash)
|
||||
/*if (GLOB.Debug2)
|
||||
log_asset("DEBUG: Skipping send of `[asset_name]` (as `[new_asset_name]`) for `[client]` because it already exists in the client's sent_assets list")*/
|
||||
continue
|
||||
unreceived[asset_name] = ACI
|
||||
|
||||
if (unreceived.len)
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
to_chat(client, "<span class='infoplain'>Sending Resources...</span>")
|
||||
|
||||
for (var/asset_name in unreceived)
|
||||
var/new_asset_name = asset_name
|
||||
var/datum/asset_cache_item/ACI = unreceived[asset_name]
|
||||
var/keep_local_name = dont_mutate_filenames \
|
||||
|| ACI.legacy \
|
||||
|| ACI.keep_local_name \
|
||||
|| (ACI.namespace && !ACI.namespace_parent)
|
||||
if (!keep_local_name)
|
||||
new_asset_name = "asset.[ACI.hash][ACI.ext]"
|
||||
log_asset("Sending asset `[asset_name]` to client `[client]` as `[new_asset_name]`")
|
||||
client << browse_rsc(ACI.resource, new_asset_name)
|
||||
|
||||
client.sent_assets[new_asset_name] = ACI.hash
|
||||
|
||||
addtimer(CALLBACK(client, TYPE_PROC_REF(/client, asset_cache_update_json)), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/// Precache files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
/datum/asset_transport/proc/send_assets_slow(client/client, list/files, filerate = 6)
|
||||
var/startingfilerate = filerate
|
||||
for (var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (send_assets(client, file))
|
||||
if (!(--filerate))
|
||||
filerate = startingfilerate
|
||||
client.browse_queue_flush()
|
||||
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
/// Check the config is valid to load this transport
|
||||
/// Returns TRUE or FALSE
|
||||
/datum/asset_transport/proc/validate_config(log = TRUE)
|
||||
return TRUE
|
||||
|
||||
#undef ASSET_CACHE_TELL_CLIENT_AMOUNT
|
||||
@@ -0,0 +1,87 @@
|
||||
/// CDN Webroot asset transport.
|
||||
/datum/asset_transport/webroot
|
||||
name = "CDN Webroot asset transport"
|
||||
|
||||
/datum/asset_transport/webroot/Load()
|
||||
if (validate_config(log = FALSE))
|
||||
load_existing_assets()
|
||||
|
||||
/// Processes thru any assets that were registered before we were loaded as a transport.
|
||||
/datum/asset_transport/webroot/proc/load_existing_assets()
|
||||
for (var/asset_name in SSassets.cache)
|
||||
var/datum/asset_cache_item/ACI = SSassets.cache[asset_name]
|
||||
save_asset_to_webroot(ACI)
|
||||
|
||||
/// Register a browser asset with the asset cache system
|
||||
/// We also save it to the CDN webroot at this step instead of waiting for send_assets()
|
||||
/// asset_name - the identifier of the asset
|
||||
/// asset - the actual asset file or an asset_cache_item datum.
|
||||
/datum/asset_transport/webroot/register_asset(asset_name, asset)
|
||||
. = ..()
|
||||
var/datum/asset_cache_item/ACI = .
|
||||
|
||||
if (istype(ACI) && ACI.hash)
|
||||
save_asset_to_webroot(ACI)
|
||||
|
||||
/// Saves the asset to the webroot taking into account namespaces and hashes.
|
||||
/datum/asset_transport/webroot/proc/save_asset_to_webroot(datum/asset_cache_item/ACI)
|
||||
var/webroot = config.asset_cdn_webroot
|
||||
var/newpath = "[webroot][get_asset_suffex(ACI)]"
|
||||
if (fexists(newpath))
|
||||
return
|
||||
if (fexists("[newpath].gz")) //its a common pattern in webhosting to save gzip'ed versions of text files and let the webserver serve them up as gzip compressed normal files, sometimes without keeping the original version.
|
||||
return
|
||||
return fcopy(ACI.resource, newpath)
|
||||
|
||||
/// Returns a url for a given asset.
|
||||
/// asset_name - Name of the asset.
|
||||
/// asset_cache_item - asset cache item datum for the asset, optional, overrides asset_name
|
||||
/datum/asset_transport/webroot/get_asset_url(asset_name, datum/asset_cache_item/asset_cache_item)
|
||||
if (!istype(asset_cache_item))
|
||||
asset_cache_item = SSassets.cache[asset_name]
|
||||
var/url = config.asset_cdn_url //config loading will handle making sure this ends in a /
|
||||
return "[url][get_asset_suffex(asset_cache_item)]"
|
||||
|
||||
/datum/asset_transport/webroot/proc/get_asset_suffex(datum/asset_cache_item/asset_cache_item)
|
||||
var/base = "[copytext(asset_cache_item.hash, 1, 3)]/"
|
||||
var/filename = "asset.[asset_cache_item.hash][asset_cache_item.ext]"
|
||||
if (length(asset_cache_item.namespace))
|
||||
base = "namespaces/[copytext(asset_cache_item.namespace, 1, 3)]/[asset_cache_item.namespace]/"
|
||||
if (!asset_cache_item.namespace_parent)
|
||||
filename = "[asset_cache_item.name]"
|
||||
return base + filename
|
||||
|
||||
|
||||
/// webroot asset sending - does nothing unless passed legacy assets
|
||||
/datum/asset_transport/webroot/send_assets(client/client, list/asset_list)
|
||||
. = FALSE
|
||||
var/list/legacy_assets = list()
|
||||
if (!islist(asset_list))
|
||||
asset_list = list(asset_list)
|
||||
for (var/asset_name in asset_list)
|
||||
var/datum/asset_cache_item/ACI = asset_list[asset_name]
|
||||
if (!istype(ACI))
|
||||
ACI = SSassets.cache[asset_name]
|
||||
if (!ACI)
|
||||
legacy_assets += asset_name //pass it on to base send_assets so it can output an error
|
||||
continue
|
||||
if (ACI.legacy)
|
||||
legacy_assets[asset_name] = ACI
|
||||
if (length(legacy_assets))
|
||||
. = ..(client, legacy_assets)
|
||||
|
||||
|
||||
/// webroot slow asset sending - does nothing.
|
||||
/datum/asset_transport/webroot/send_assets_slow(client/client, list/files, filerate)
|
||||
return FALSE
|
||||
|
||||
/datum/asset_transport/webroot/validate_config(log = TRUE)
|
||||
if (!config.asset_cdn_url)
|
||||
if (log)
|
||||
log_asset("ERROR: [type]: Invalid Config: ASSET_CDN_URL")
|
||||
return FALSE
|
||||
if (!config.asset_cdn_webroot)
|
||||
if (log)
|
||||
log_asset("ERROR: [type]: Invalid Config: ASSET_CDN_WEBROOT")
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -26,4 +26,4 @@
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
/obj/item/weapon/blobcore_chunk/attack_self(var/mob/user)
|
||||
if(blob_type && world.time > active_ability_cooldown + last_active_use)
|
||||
last_active_use = world.time
|
||||
to_chat(user, "<span class='alien'>\icon [src] \The [src] gesticulates.</span>")
|
||||
to_chat(user, "<span class='alien'>[icon2html(src, user.client)] \The [src] gesticulates.</span>")
|
||||
blob_type.on_chunk_use(src, user)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>\The [src] doesn't seem to respond.</span>")
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
break
|
||||
|
||||
if(!beamtarget_exists && GetAnomalySusceptibility(L) >= 0.5)
|
||||
carrier.visible_message("<span class='danger'>\icon [B] \The [B] lashes out at \the [L]!</span>")
|
||||
carrier.visible_message("<span class='danger'>[icon2html(B,viewers(carrier))] \The [B] lashes out at \the [L]!</span>")
|
||||
var/datum/beam/drain_beam = carrier.Beam(L, icon_state = "drain_life", time = 10 SECONDS)
|
||||
active_beams |= drain_beam
|
||||
spawn(9 SECONDS)
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
/datum/blob_type/ravenous_macrophage/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
|
||||
var/mob/living/L = locate() in range(world.view, B)
|
||||
if(prob(5) && !L.stat) // There's some active living thing nearby, produce offgas.
|
||||
B.visible_message("<span class='alien'>\icon [B] \The [B] disgorches a cloud of noxious gas!</span>")
|
||||
B.visible_message("<span class='alien'>[icon2html(B,viewers(B))] \The [B] disgorches a cloud of noxious gas!</span>")
|
||||
var/turf/T = get_turf(B)
|
||||
var/datum/effect/effect/system/smoke_spread/noxious/BS = new /datum/effect/effect/system/smoke_spread/noxious
|
||||
BS.attach(T)
|
||||
BS.set_up(3, 0, T)
|
||||
playsound(T, 'sound/effects/smoke.ogg', 50, 1, -3)
|
||||
BS.start()
|
||||
BS.start()
|
||||
|
||||
@@ -55,5 +55,11 @@
|
||||
return
|
||||
|
||||
/datum/blob_type/reactive_spines/chunk_setup(obj/item/weapon/blobcore_chunk/B)
|
||||
GLOB.moved_event.register_global(B, /obj/item/weapon/blobcore_chunk/proc/call_chunk_unique)
|
||||
return
|
||||
B.RegisterSignal(SSmobs, COMSIG_OBSERVER_GLOBALMOVED, /obj/item/weapon/blobcore_chunk/proc/call_chunk_unique)
|
||||
return
|
||||
|
||||
//I'm putting this here so everybody knows that it's this shitty code that is why that comsig exists.
|
||||
//I'm just reimplementing the way it worked before but with comsigs. I don't have the patience to refactor this.
|
||||
/mob/living/Moved()
|
||||
. = ..()
|
||||
SEND_SIGNAL(SSmobs, COMSIG_OBSERVER_GLOBALMOVED)
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
return
|
||||
var/mob/living/L = locate() in (view(world.view + 3, get_turf(B)) - view(2,get_turf(B)) - previous_targets) // No adjacent mobs.
|
||||
|
||||
if(!check_trajectory(L, B, PASSTABLE))
|
||||
if(!(L in check_trajectory(L, B, PASSTABLE)))
|
||||
if(!LAZYLEN(previous_targets))
|
||||
previous_targets = list()
|
||||
|
||||
@@ -53,12 +53,12 @@
|
||||
if(istype(user) && user == L)
|
||||
continue
|
||||
|
||||
if(!check_trajectory(L, B, PASSTABLE)) // Can't fire at things on the other side of walls / windows.
|
||||
if(!(L in check_trajectory(L, B, PASSTABLE))) // Can't fire at things on the other side of walls / windows.
|
||||
continue
|
||||
|
||||
var/obj/item/projectile/P = new spore_projectile(get_turf(B))
|
||||
|
||||
user.visible_message("<span class='danger'>\icon [B] \The [B] discharges energy toward \the [L]!</span>")
|
||||
user.visible_message("<span class='danger'>[icon2html(B,viewers(user))] \The [B] discharges energy toward \the [L]!</span>")
|
||||
P.launch_projectile(L, BP_TORSO, user)
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
@@ -68,5 +68,5 @@
|
||||
carrier.adjustFireLoss(-3 / nearby_mobs.len)
|
||||
|
||||
if(need_beam)
|
||||
carrier.visible_message("<span class='alien'>\icon [B] \The [B] sends noxious spores toward \the [victim]!</span>")
|
||||
carrier.Beam(victim, icon_state = "lichbeam", time = 2 SECONDS)
|
||||
carrier.visible_message("<span class='alien'>[icon2html(B,viewers(carrier))] \The [B] sends noxious spores toward \the [victim]!</span>")
|
||||
carrier.Beam(victim, icon_state = "lichbeam", time = 2 SECONDS)
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
/obj/machinery/casino_prize_dispenser/proc/pay_with_chips(var/obj/item/weapon/spacecasinocash/cashmoney, mob/user, var/price)
|
||||
//"cashmoney_:[cashmoney] user:[user] currently_vending:[currently_vending]"
|
||||
if(price > cashmoney.worth)
|
||||
to_chat(usr, "\icon[cashmoney] <span class='warning'>That is not enough chips.</span>")
|
||||
to_chat(usr, "[icon2html(cashmoney, user.client)] <span class='warning'>That is not enough chips.</span>")
|
||||
return 0
|
||||
|
||||
if(istype(cashmoney, /obj/item/weapon/spacecasinocash))
|
||||
|
||||
@@ -456,7 +456,8 @@
|
||||
src << browse('code/modules/asset_cache/validate_assets.html', "window=asset_cache_browser")
|
||||
|
||||
//Precache the client with all other assets slowly, so as to not block other browse() calls
|
||||
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(getFilesSlow), src, SSassets.preload, FALSE), 5 SECONDS)
|
||||
if (config.asset_simple_preload)
|
||||
addtimer(CALLBACK(SSassets.transport, TYPE_PROC_REF(/datum/asset_transport, send_assets_slow), src, SSassets.transport.preload), 5 SECONDS)
|
||||
|
||||
/mob/proc/MayRespawn()
|
||||
return 0
|
||||
|
||||
@@ -50,13 +50,18 @@
|
||||
display_name = "Adjust - No Shoes"
|
||||
path = /obj/item/clothing/shoes/none
|
||||
cost = 0
|
||||
|
||||
|
||||
/obj/item/clothing/shoes/none
|
||||
name = "No Shoes"
|
||||
desc = "shoeless?"
|
||||
icon_state = ""
|
||||
species_restricted = null
|
||||
|
||||
|
||||
/obj/item/clothing/shoes/none/Initialize()
|
||||
. = INITIALIZE_HINT_QDEL //Fuck them shoes
|
||||
..()
|
||||
if(istype(loc, /mob))
|
||||
var/mob/m = loc
|
||||
m.drop_from_inventory(src, get_turf(m))
|
||||
m.update_inv_shoes()
|
||||
moveToNullspace()
|
||||
return INITIALIZE_HINT_QDEL //Fuck them shoes
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
var/mob/living/carbon/human/H = holder.wearer
|
||||
to_chat(H,"<span class='notice'>You activate the P.A.T. module.</span>")
|
||||
GLOB.moved_event.register(H, src, /obj/item/rig_module/pat_module/proc/boop)
|
||||
RegisterSignal(H, COMSIG_OBSERVER_MOVED, /obj/item/rig_module/pat_module/proc/boop)
|
||||
|
||||
/obj/item/rig_module/pat_module/deactivate()
|
||||
if(!..())
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
var/mob/living/carbon/human/H = holder.wearer
|
||||
to_chat(H,"<span class='notice'>Your disable the P.A.T. module.</span>")
|
||||
GLOB.moved_event.unregister(H, src)
|
||||
UnregisterSignal(H, COMSIG_OBSERVER_MOVED)
|
||||
|
||||
/obj/item/rig_module/pat_module/proc/boop(var/mob/living/carbon/human/user,var/turf/To,var/turf/Tn)
|
||||
if(!istype(user) || !istype(To) || !istype(Tn))
|
||||
|
||||
@@ -172,13 +172,13 @@
|
||||
spark_system = null
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/rig/examine()
|
||||
/obj/item/weapon/rig/examine(mob/user)
|
||||
. = ..()
|
||||
if(wearer)
|
||||
for(var/obj/item/piece in list(helmet,gloves,chest,boots))
|
||||
if(!piece || piece.loc != wearer)
|
||||
continue
|
||||
. += "\icon[piece][bicon(piece)] \The [piece] [piece.gender == PLURAL ? "are" : "is"] deployed."
|
||||
. += "[icon2html(piece, user.client)] \The [piece] [piece.gender == PLURAL ? "are" : "is"] deployed."
|
||||
|
||||
if(src.loc == usr)
|
||||
. += "The access panel is [locked? "locked" : "unlocked"]."
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
..()
|
||||
|
||||
/obj/item/clothing/suit/storage/hooded/Destroy()
|
||||
qdel(hood)
|
||||
QDEL_NULL(hood)
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/storage/hooded/proc/MakeHood()
|
||||
@@ -34,12 +34,13 @@
|
||||
/obj/item/clothing/suit/storage/hooded/proc/RemoveHood()
|
||||
hood_up = FALSE
|
||||
update_icon()
|
||||
hood.canremove = TRUE // This shouldn't matter anyways but just incase.
|
||||
if(ishuman(hood.loc))
|
||||
var/mob/living/carbon/H = hood.loc
|
||||
H.unEquip(hood, 1)
|
||||
H.update_inv_wear_suit()
|
||||
hood.forceMove(src)
|
||||
if(hood)
|
||||
hood.canremove = TRUE // This shouldn't matter anyways but just incase.
|
||||
if(ishuman(hood.loc))
|
||||
var/mob/living/carbon/H = hood.loc
|
||||
H.unEquip(hood, 1)
|
||||
H.update_inv_wear_suit()
|
||||
hood.forceMove(src)
|
||||
|
||||
/obj/item/clothing/suit/storage/hooded/dropped()
|
||||
RemoveHood()
|
||||
@@ -350,7 +351,7 @@
|
||||
light_power = 1.8
|
||||
light_range = 1.2
|
||||
light_on = TRUE
|
||||
|
||||
|
||||
/obj/item/clothing/suit/storage/hooded/wintercoat/christmasred
|
||||
name = "red christmas winter coat"
|
||||
desc = "A festive red Christmas coat! Smells like Candy Cane!"
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
last_process_worldtime = world.time
|
||||
|
||||
/obj/machinery/dnaforensics/proc/complete_scan()
|
||||
visible_message("<span class='notice'>\icon[src][bicon(src)] makes an insistent chime.</span>", 2)
|
||||
visible_message("<span class='notice'>[icon2html(src,viewers(src))] makes an insistent chime.</span>", 2)
|
||||
update_icon()
|
||||
if(bloodsamp)
|
||||
var/obj/item/weapon/paper/P = new(src)
|
||||
@@ -142,4 +142,4 @@
|
||||
else if(bloodsamp)
|
||||
icon_state = "dnaclosed"
|
||||
else
|
||||
icon_state = "dnaopen"
|
||||
icon_state = "dnaopen"
|
||||
|
||||
+11
-11
@@ -76,7 +76,7 @@ log transactions
|
||||
|
||||
//display a message to the user
|
||||
var/response = pick("Initiating withdraw. Have a nice day!", "CRITICAL ERROR: Activating cash chamber panic siphon.","PIN Code accepted! Emptying account balance.", "Jackpot!")
|
||||
to_chat(user, "<span class='warning'>\icon[src][bicon(src)] The [src] beeps: \"[response]\"</span>")
|
||||
to_chat(user, "<span class='warning'>[icon2html(src, user.client)] The [src] beeps: \"[response]\"</span>")
|
||||
return 1
|
||||
|
||||
/obj/machinery/atm/attackby(obj/item/I as obj, mob/user as mob)
|
||||
@@ -85,7 +85,7 @@ log transactions
|
||||
if(istype(I, /obj/item/weapon/card))
|
||||
if(emagged > 0)
|
||||
//prevent inserting id into an emagged ATM
|
||||
to_chat(user, span_red("\icon[src][bicon(src)] CARD READER ERROR. This system has been compromised!"))
|
||||
to_chat(user, span_red("[icon2html(src, user.client)] CARD READER ERROR. This system has been compromised!"))
|
||||
return
|
||||
else if(istype(I,/obj/item/weapon/card/emag))
|
||||
I.resolve_attackby(src, user)
|
||||
@@ -234,7 +234,7 @@ log transactions
|
||||
var/target_account_number = text2num(href_list["target_acc_number"])
|
||||
var/transfer_purpose = href_list["purpose"]
|
||||
if(charge_to_account(target_account_number, authenticated_account.owner_name, transfer_purpose, machine_id, transfer_amount))
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='info'>Funds transfer successful.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='info'>Funds transfer successful.</span>")
|
||||
authenticated_account.money -= transfer_amount
|
||||
|
||||
//create an entry in the account transaction log
|
||||
@@ -247,10 +247,10 @@ log transactions
|
||||
T.amount = "([transfer_amount])"
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Funds transfer failed.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Funds transfer failed.</span>")
|
||||
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
if("view_screen")
|
||||
view_screen = text2num(href_list["view_screen"])
|
||||
if("change_security_level")
|
||||
@@ -288,11 +288,11 @@ log transactions
|
||||
T.time = stationtime2text()
|
||||
failed_account.transaction_log.Add(T)
|
||||
else
|
||||
to_chat(usr, span_red("\icon[src][bicon(src)] Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining."))
|
||||
to_chat(usr, span_red("[icon2html(src, usr.client)] Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining."))
|
||||
previous_account_number = tried_account_num
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 1)
|
||||
else
|
||||
to_chat(usr, span_red("\icon[src][bicon(src)] incorrect pin/account combination entered."))
|
||||
to_chat(usr, span_red("[icon2html(src, usr.client)] incorrect pin/account combination entered."))
|
||||
number_incorrect_tries = 0
|
||||
else
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
@@ -308,7 +308,7 @@ log transactions
|
||||
T.time = stationtime2text()
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
|
||||
to_chat(usr, span_blue("\icon[src][bicon(src)] Access granted. Welcome user '[authenticated_account.owner_name].'"))
|
||||
to_chat(usr, span_blue("[icon2html(src, usr.client)] Access granted. Welcome user '[authenticated_account.owner_name].'"))
|
||||
|
||||
previous_account_number = tried_account_num
|
||||
if("e_withdrawal")
|
||||
@@ -336,7 +336,7 @@ log transactions
|
||||
T.time = stationtime2text()
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
if("withdrawal")
|
||||
var/amount = max(text2num(href_list["funds_amount"]),0)
|
||||
amount = round(amount, 0.01)
|
||||
@@ -361,7 +361,7 @@ log transactions
|
||||
T.time = stationtime2text()
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>You don't have enough funds to do that!</span>")
|
||||
if("balance_statement")
|
||||
if(authenticated_account)
|
||||
var/obj/item/weapon/paper/R = new(src.loc)
|
||||
@@ -433,7 +433,7 @@ log transactions
|
||||
if(!held_card)
|
||||
//this might happen if the user had the browser window open when somebody emagged it
|
||||
if(emagged > 0)
|
||||
to_chat(usr, span_red("\icon[src][bicon(src)] The ATM card reader rejected your ID because this machine has been sabotaged!"))
|
||||
to_chat(usr, span_red("[icon2html(src, usr.client)] The ATM card reader rejected your ID because this machine has been sabotaged!"))
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card/id))
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
if(linked_account)
|
||||
scan_card(I, O)
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
else if (istype(O, /obj/item/weapon/spacecash/ewallet))
|
||||
var/obj/item/weapon/spacecash/ewallet/E = O
|
||||
if (linked_account)
|
||||
@@ -115,7 +115,7 @@
|
||||
if(transaction_locked && !transaction_paid)
|
||||
if(transaction_amount <= E.worth)
|
||||
playsound(src, 'sound/machines/chime.ogg', 50, 1)
|
||||
src.visible_message("\icon[src][bicon(src)] \The [src] chimes.")
|
||||
src.visible_message("[icon2html(src,viewers(src))] \The [src] chimes.")
|
||||
transaction_paid = 1
|
||||
|
||||
//transfer the money
|
||||
@@ -132,11 +132,11 @@
|
||||
T.time = stationtime2text()
|
||||
linked_account.transaction_log.Add(T)
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>\The [O] doesn't have that much money!</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>\The [O] doesn't have that much money!</span>")
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Connected account has been suspended.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Connected account has been suspended.</span>")
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>EFTPOS is not connected to an account.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>EFTPOS is not connected to an account.</span>")
|
||||
|
||||
else
|
||||
..()
|
||||
@@ -154,14 +154,14 @@
|
||||
tgui_alert_async(usr, "That is not a valid code!")
|
||||
print_reference()
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Incorrect code entered.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Incorrect code entered.</span>")
|
||||
if("change_id")
|
||||
var/attempt_code = text2num(input(usr, "Re-enter the current EFTPOS access code", "Confirm EFTPOS code"))
|
||||
if(attempt_code == access_code)
|
||||
eftpos_name = sanitize(input(usr, "Enter a new terminal ID for this device", "Enter new EFTPOS ID"), MAX_NAME_LEN) + " EFTPOS scanner"
|
||||
print_reference()
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Incorrect code entered.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Incorrect code entered.</span>")
|
||||
if("link_account")
|
||||
var/attempt_account_num = tgui_input_number(usr, "Enter account number to pay EFTPOS charges into", "New account number")
|
||||
var/attempt_pin = tgui_input_number(usr, "Enter pin code", "Account pin")
|
||||
@@ -169,9 +169,9 @@
|
||||
if(linked_account)
|
||||
if(linked_account.suspended)
|
||||
linked_account = null
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Account has been suspended.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Account has been suspended.</span>")
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Account not found.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Account not found.</span>")
|
||||
if("trans_purpose")
|
||||
var/choice = sanitize(input(usr, "Enter reason for EFTPOS transaction", "Transaction purpose"))
|
||||
if(choice) transaction_purpose = choice
|
||||
@@ -194,14 +194,14 @@
|
||||
else if(linked_account)
|
||||
transaction_locked = 1
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>No account connected to send transactions to.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>No account connected to send transactions to.</span>")
|
||||
if("scan_card")
|
||||
if(linked_account)
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card))
|
||||
scan_card(I)
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Unable to link accounts.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Unable to link accounts.</span>")
|
||||
if("reset")
|
||||
//reset the access code - requires HoP/captain access
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
@@ -209,10 +209,10 @@
|
||||
var/obj/item/weapon/card/id/C = I
|
||||
if((access_cent_captain in C.access) || (access_hop in C.access) || (access_captain in C.access))
|
||||
access_code = 0
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='info'>Access code reset to 0.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='info'>Access code reset to 0.</span>")
|
||||
else if (istype(I, /obj/item/weapon/card/emag))
|
||||
access_code = 0
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='info'>Access code reset to 0.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='info'>Access code reset to 0.</span>")
|
||||
|
||||
src.attack_self(usr)
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
if(!D.suspended)
|
||||
if(transaction_amount <= D.money)
|
||||
playsound(src, 'sound/machines/chime.ogg', 50, 1)
|
||||
src.visible_message("\icon[src][bicon(src)] \The [src] chimes.")
|
||||
src.visible_message("[icon2html(src,viewers(src))] \The [src] chimes.")
|
||||
transaction_paid = 1
|
||||
|
||||
//transfer the money
|
||||
@@ -265,25 +265,25 @@
|
||||
T.time = stationtime2text()
|
||||
linked_account.transaction_log.Add(T)
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>You don't have that much money!</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>You don't have that much money!</span>")
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Your account has been suspended.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Your account has been suspended.</span>")
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Connected account has been suspended.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Connected account has been suspended.</span>")
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>EFTPOS is not connected to an account.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>EFTPOS is not connected to an account.</span>")
|
||||
else if (istype(I, /obj/item/weapon/card/emag))
|
||||
if(transaction_locked)
|
||||
if(transaction_paid)
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='info'>You stealthily swipe \the [I] through \the [src].</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='info'>You stealthily swipe \the [I] through \the [src].</span>")
|
||||
transaction_locked = 0
|
||||
transaction_paid = 0
|
||||
else
|
||||
usr.visible_message("<span class='info'>\The [usr] swipes a card through \the [src].</span>")
|
||||
playsound(src, 'sound/machines/chime.ogg', 50, 1)
|
||||
src.visible_message("\icon[src][bicon(src)] \The [src] chimes.")
|
||||
src.visible_message("[icon2html(src,viewers(src))] \The [src] chimes.")
|
||||
transaction_paid = 1
|
||||
|
||||
//emag?
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
if(allowed(usr))
|
||||
locked = !locked
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Insufficient access.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Insufficient access.</span>")
|
||||
if("toggle_cash_lock")
|
||||
cash_locked = !cash_locked
|
||||
if("link_account")
|
||||
@@ -113,9 +113,9 @@
|
||||
if(linked_account)
|
||||
if(linked_account.suspended)
|
||||
linked_account = null
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Account has been suspended.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Account has been suspended.</span>")
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Account not found.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Account not found.</span>")
|
||||
if("custom_order")
|
||||
var/t_purpose = sanitize(tgui_input_text(usr, "Enter purpose", "New purpose"))
|
||||
if (!t_purpose || !Adjacent(usr)) return
|
||||
@@ -126,7 +126,7 @@
|
||||
transaction_amount += t_amount
|
||||
price_list += t_amount
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 25)
|
||||
src.visible_message("\icon[src][bicon(src)][transaction_purpose]: [t_amount] Thaler\s.")
|
||||
src.visible_message("[icon2html(src,viewers(src))][transaction_purpose]: [t_amount] Thaler\s.")
|
||||
if("set_amount")
|
||||
var/item_name = locate(href_list["item"])
|
||||
var/n_amount = round(tgui_input_number(usr, "Enter amount", "New amount", 0, 20, 0))
|
||||
@@ -163,7 +163,7 @@
|
||||
price_list.Cut()
|
||||
if("reset_log")
|
||||
transaction_logs.Cut()
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='notice'>Transaction log reset.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='notice'>Transaction log reset.</span>")
|
||||
updateDialog()
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
return 1
|
||||
else
|
||||
confirm_item = I
|
||||
src.visible_message("\icon[src][bicon(src)]<b>Total price:</b> [transaction_amount] Thaler\s. Swipe again to confirm.")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<b>Total price:</b> [transaction_amount] Thaler\s. Swipe again to confirm.")
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 25)
|
||||
return 0
|
||||
|
||||
@@ -219,14 +219,14 @@
|
||||
|
||||
if (cash_open)
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 25)
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>The cash box is open.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>The cash box is open.</span>")
|
||||
return
|
||||
|
||||
if((item_list.len > 1 || item_list[item_list[1]] > 1) && !confirm(I))
|
||||
return
|
||||
|
||||
if (!linked_account)
|
||||
usr.visible_message("\icon[src][bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
usr.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
return
|
||||
|
||||
// Access account for transaction
|
||||
@@ -239,13 +239,13 @@
|
||||
D = attempt_account_access(I.associated_account_number, attempt_pin, 2)
|
||||
|
||||
if(!D)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
|
||||
else
|
||||
if(D.suspended)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Your account has been suspended.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Your account has been suspended.</span>")
|
||||
else
|
||||
if(transaction_amount > D.money)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Not enough funds.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Not enough funds.</span>")
|
||||
else
|
||||
// Transfer the money
|
||||
D.money -= transaction_amount
|
||||
@@ -284,7 +284,7 @@
|
||||
|
||||
if (cash_open)
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 25)
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>The cash box is open.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>The cash box is open.</span>")
|
||||
return
|
||||
|
||||
if((item_list.len > 1 || item_list[item_list[1]] > 1) && !confirm(E))
|
||||
@@ -293,7 +293,7 @@
|
||||
// Access account for transaction
|
||||
if(check_account())
|
||||
if(transaction_amount > E.worth)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Not enough funds.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Not enough funds.</span>")
|
||||
else
|
||||
// Transfer the money
|
||||
E.worth -= transaction_amount
|
||||
@@ -322,14 +322,14 @@
|
||||
|
||||
if (cash_open)
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 25)
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>The cash box is open.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>The cash box is open.</span>")
|
||||
return
|
||||
|
||||
if((item_list.len > 1 || item_list[item_list[1]] > 1) && !confirm(SC))
|
||||
return
|
||||
|
||||
if(transaction_amount > SC.worth)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Not enough money.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Not enough money.</span>")
|
||||
else
|
||||
// Insert cash into magical slot
|
||||
SC.worth -= transaction_amount
|
||||
@@ -351,20 +351,20 @@
|
||||
/obj/machinery/cash_register/proc/scan_item_price(obj/O)
|
||||
if(!istype(O)) return
|
||||
if(item_list.len > 10)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Only up to ten different items allowed per purchase.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Only up to ten different items allowed per purchase.</span>")
|
||||
return
|
||||
if (cash_open)
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 25)
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>The cash box is open.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>The cash box is open.</span>")
|
||||
return
|
||||
|
||||
// First check if item has a valid price
|
||||
var/price = O.get_item_cost()
|
||||
if(isnull(price))
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Unable to find item in database.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Unable to find item in database.</span>")
|
||||
return
|
||||
// Call out item cost
|
||||
src.visible_message("\icon[src][bicon(src)]\A [O]: [price ? "[price] Thaler\s" : "free of charge"].")
|
||||
src.visible_message("[icon2html(src,viewers(src))]\A [O]: [price ? "[price] Thaler\s" : "free of charge"].")
|
||||
// Note the transaction purpose for later use
|
||||
if(transaction_purpose)
|
||||
transaction_purpose += "<br>"
|
||||
@@ -432,11 +432,11 @@
|
||||
|
||||
/obj/machinery/cash_register/proc/check_account()
|
||||
if (!linked_account)
|
||||
usr.visible_message("\icon[src][bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
usr.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
return 0
|
||||
|
||||
if(linked_account.suspended)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Connected account has been suspended.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Connected account has been suspended.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
@@ -444,7 +444,7 @@
|
||||
/obj/machinery/cash_register/proc/transaction_complete()
|
||||
/// Visible confirmation
|
||||
playsound(src, 'sound/machines/chime.ogg', 25)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='notice'>Transaction complete.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='notice'>Transaction complete.</span>")
|
||||
flick("register_approve", src)
|
||||
reset_memory()
|
||||
updateDialog()
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
if(allowed(usr))
|
||||
locked = !locked
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Insufficient access.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Insufficient access.</span>")
|
||||
if("link_account")
|
||||
var/attempt_account_num = tgui_input_number(usr, "Enter account number", "New account number")
|
||||
var/attempt_pin = tgui_input_number(usr, "Enter PIN", "Account PIN")
|
||||
@@ -107,9 +107,9 @@
|
||||
if(linked_account)
|
||||
if(linked_account.suspended)
|
||||
linked_account = null
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Account has been suspended.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Account has been suspended.</span>")
|
||||
else
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='warning'>Account not found.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='warning'>Account not found.</span>")
|
||||
if("custom_order")
|
||||
var/t_purpose = sanitize(tgui_input_text(usr, "Enter purpose", "New purpose"))
|
||||
if (!t_purpose || !Adjacent(usr)) return
|
||||
@@ -120,7 +120,7 @@
|
||||
transaction_amount += t_amount
|
||||
price_list += t_amount
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 25)
|
||||
src.visible_message("\icon[src][bicon(src)][transaction_purpose]: [t_amount] Thaler\s.")
|
||||
src.visible_message("[icon2html(src,viewers(src))][transaction_purpose]: [t_amount] Thaler\s.")
|
||||
if("set_amount")
|
||||
var/item_name = locate(href_list["item"])
|
||||
var/n_amount = round(tgui_input_number(usr, "Enter amount", "New amount", 0, 20, 0))
|
||||
@@ -157,7 +157,7 @@
|
||||
price_list.Cut()
|
||||
if("reset_log")
|
||||
transaction_logs.Cut()
|
||||
to_chat(usr, "\icon[src][bicon(src)]<span class='notice'>Transaction log reset.</span>")
|
||||
to_chat(usr, "[icon2html(src, usr.client)]<span class='notice'>Transaction log reset.</span>")
|
||||
updateDialog()
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
return 1
|
||||
else
|
||||
confirm_item = I
|
||||
src.visible_message("\icon[src][bicon(src)]<b>Total price:</b> [transaction_amount] Thaler\s. Swipe again to confirm.")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<b>Total price:</b> [transaction_amount] Thaler\s. Swipe again to confirm.")
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 25)
|
||||
return 0
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
return
|
||||
|
||||
if (!linked_account)
|
||||
usr.visible_message("\icon[src][bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
usr.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
return
|
||||
|
||||
// Access account for transaction
|
||||
@@ -216,13 +216,13 @@
|
||||
D = attempt_account_access(I.associated_account_number, attempt_pin, 2)
|
||||
|
||||
if(!D)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
|
||||
else
|
||||
if(D.suspended)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Your account has been suspended.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Your account has been suspended.</span>")
|
||||
else
|
||||
if(transaction_amount > D.money)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Not enough funds.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Not enough funds.</span>")
|
||||
else
|
||||
// Transfer the money
|
||||
D.money -= transaction_amount
|
||||
@@ -265,7 +265,7 @@
|
||||
// Access account for transaction
|
||||
if(check_account())
|
||||
if(transaction_amount > E.worth)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Not enough funds.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Not enough funds.</span>")
|
||||
else
|
||||
// Transfer the money
|
||||
E.worth -= transaction_amount
|
||||
@@ -291,16 +291,16 @@
|
||||
/obj/item/device/retail_scanner/proc/scan_item_price(var/obj/O)
|
||||
if(!istype(O)) return
|
||||
if(item_list.len > 10)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Only up to ten different items allowed per purchase.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Only up to ten different items allowed per purchase.</span>")
|
||||
return
|
||||
|
||||
// First check if item has a valid price
|
||||
var/price = O.get_item_cost()
|
||||
if(isnull(price))
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Unable to find item in database.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Unable to find item in database.</span>")
|
||||
return
|
||||
// Call out item cost
|
||||
src.visible_message("\icon[src][bicon(src)]\A [O]: [price ? "[price] Thaler\s" : "free of charge"].")
|
||||
src.visible_message("[icon2html(src,viewers(src))]\A [O]: [price ? "[price] Thaler\s" : "free of charge"].")
|
||||
// Note the transaction purpose for later use
|
||||
if(transaction_purpose)
|
||||
transaction_purpose += "<br>"
|
||||
@@ -368,11 +368,11 @@
|
||||
|
||||
/obj/item/device/retail_scanner/proc/check_account()
|
||||
if (!linked_account)
|
||||
usr.visible_message("\icon[src][bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
usr.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Unable to connect to linked account.</span>")
|
||||
return 0
|
||||
|
||||
if(linked_account.suspended)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='warning'>Connected account has been suspended.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='warning'>Connected account has been suspended.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
@@ -380,7 +380,7 @@
|
||||
/obj/item/device/retail_scanner/proc/transaction_complete()
|
||||
/// Visible confirmation
|
||||
playsound(src, 'sound/machines/chime.ogg', 25)
|
||||
src.visible_message("\icon[src][bicon(src)]<span class='notice'>Transaction complete.</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))]<span class='notice'>Transaction complete.</span>")
|
||||
flick("retail_approve", src)
|
||||
reset_memory()
|
||||
updateDialog()
|
||||
|
||||
@@ -270,7 +270,7 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
|
||||
// This is not a status display message, since it's something the character
|
||||
// themselves is meant to see BEFORE putting the money in
|
||||
to_chat(usr, "\icon[cashmoney][bicon(cashmoney)] <span class='warning'>That is not enough money.</span>")
|
||||
to_chat(usr, "[icon2html(cashmoney, user.client)] <span class='warning'>That is not enough money.</span>")
|
||||
return 0
|
||||
|
||||
if(istype(cashmoney, /obj/item/weapon/spacecash))
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
// Spawn a single carp at given location.
|
||||
/datum/event/carp_migration/proc/spawn_one_carp(var/loc)
|
||||
var/mob/living/simple_mob/animal/M = new /mob/living/simple_mob/animal/space/carp/event(loc)
|
||||
GLOB.destroyed_event.register(M, src, PROC_REF(on_carp_destruction))
|
||||
RegisterSignal(M, COMSIG_OBSERVER_DESTROYED, PROC_REF(on_carp_destruction))
|
||||
spawned_carp.Add(M)
|
||||
return M
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
// If carp is bomphed, remove it from the list.
|
||||
/datum/event/carp_migration/proc/on_carp_destruction(var/mob/M)
|
||||
spawned_carp -= M
|
||||
GLOB.destroyed_event.unregister(M, src, PROC_REF(on_carp_destruction))
|
||||
UnregisterSignal(M, COMSIG_OBSERVER_DESTROYED)
|
||||
|
||||
/datum/event/carp_migration/end()
|
||||
. = ..()
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
// Spawn a single gnat at given location.
|
||||
/datum/event/gnat_migration/proc/spawn_one_gnat(var/loc)
|
||||
var/mob/living/simple_mob/animal/M = new /mob/living/simple_mob/animal/space/gnat(loc)
|
||||
GLOB.destroyed_event.register(M, src, PROC_REF(on_gnat_destruction))
|
||||
RegisterSignal(M, COMSIG_OBSERVER_DESTROYED, PROC_REF(on_gnat_destruction))
|
||||
spawned_gnat.Add(M)
|
||||
return M
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
// If gnat is bomphed, remove it from the list.
|
||||
/datum/event/gnat_migration/proc/on_gnat_destruction(var/mob/M)
|
||||
spawned_gnat -= M
|
||||
GLOB.destroyed_event.unregister(M, src, PROC_REF(on_gnat_destruction))
|
||||
UnregisterSignal(M, COMSIG_OBSERVER_DESTROYED)
|
||||
|
||||
/datum/event/gnat_migration/end()
|
||||
. = ..()
|
||||
|
||||
@@ -87,28 +87,28 @@
|
||||
min_number = 2 //CHOMP Add
|
||||
max_number = 6
|
||||
vermstring = "lizards"
|
||||
|
||||
|
||||
// ChompEDIT Begin
|
||||
if(VERM_SPIDERS)
|
||||
spawn_types = list(/obj/effect/spider/spiderling)
|
||||
min_number = 4 //CHOMP Add
|
||||
max_number = 8 //CHOMP edit
|
||||
vermstring = "spiders"
|
||||
|
||||
|
||||
/* //Chomp REMOVE - in upstream file, not used here
|
||||
// Check if any landmarks exist!
|
||||
for(var/obj/effect/landmark/C in landmarks_list)
|
||||
if(C.name == "verminstart")
|
||||
spawn_locations.Add(C.loc)
|
||||
*/ //Chomp REMOVE END
|
||||
|
||||
|
||||
spawn(0)
|
||||
var/num = rand(min_number,max_number)
|
||||
while(turfs.len > 0 && num > 0)
|
||||
var/turf/simulated/floor/T = pick(turfs)
|
||||
turfs.Remove(T)
|
||||
num--
|
||||
|
||||
|
||||
if(vermin == VERM_SPIDERS)
|
||||
var/obj/effect/spider/spiderling/S = new(T)
|
||||
S.amount_grown = -1
|
||||
@@ -136,7 +136,7 @@
|
||||
// Spawn a single vermin at given location.
|
||||
/datum/event/infestation/proc/spawn_one_vermin(var/loc)
|
||||
var/mob/living/simple_mob/animal/M = new spawn_types(loc)
|
||||
GLOB.destroyed_event.register(M, src, PROC_REF(on_vermin_destruction))
|
||||
RegisterSignal(M, COMSIG_OBSERVER_DESTROYED, PROC_REF(on_vermin_destruction))
|
||||
spawned_vermin.Add(M)
|
||||
return M
|
||||
|
||||
@@ -150,8 +150,9 @@
|
||||
// If vermin is kill, remove it from the list.
|
||||
/datum/event/infestation/proc/on_vermin_destruction(var/mob/M)
|
||||
spawned_vermin -= M
|
||||
GLOB.destroyed_event.unregister(M, src, PROC_REF(on_vermin_destruction))
|
||||
*/ // CHOMPedit End
|
||||
UnregisterSignal(M, COMSIG_OBSERVER_DESTROYED)
|
||||
*/
|
||||
|
||||
|
||||
/datum/event/infestation/announce()
|
||||
command_announcement.Announce("Bioscans indicate that [vermstring] have been breeding in [locstring]. Clear them out, before this starts to affect productivity.", "Vermin infestation")
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
// Spawn a single jellyfish at given location.
|
||||
/datum/event/jellyfish_migration/proc/spawn_one_jellyfish(var/loc)
|
||||
var/mob/living/simple_mob/animal/M = new /mob/living/simple_mob/vore/alienanimals/space_jellyfish(loc)
|
||||
GLOB.destroyed_event.register(M, src, PROC_REF(on_jellyfish_destruction))
|
||||
RegisterSignal(M, COMSIG_OBSERVER_DESTROYED, PROC_REF(on_jellyfish_destruction))
|
||||
spawned_jellyfish.Add(M)
|
||||
return M
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
// If jellyfish is bomphed, remove it from the list.
|
||||
/datum/event/jellyfish_migration/proc/on_jellyfish_destruction(var/mob/M)
|
||||
spawned_jellyfish -= M
|
||||
GLOB.destroyed_event.unregister(M, src, PROC_REF(on_jellyfish_destruction))
|
||||
UnregisterSignal(M, COMSIG_OBSERVER_DESTROYED)
|
||||
|
||||
/datum/event/jellyfish_migration/end()
|
||||
. = ..()
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
// Spawn a single ray at given location.
|
||||
/datum/event/ray_migration/proc/spawn_one_ray(var/loc)
|
||||
var/mob/living/simple_mob/animal/M = new /mob/living/simple_mob/animal/space/ray(loc)
|
||||
GLOB.destroyed_event.register(M, src, PROC_REF(on_ray_destruction))
|
||||
RegisterSignal(M, COMSIG_OBSERVER_DESTROYED, PROC_REF(on_ray_destruction))
|
||||
spawned_ray.Add(M)
|
||||
return M
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
// If ray is bomphed, remove it from the list.
|
||||
/datum/event/ray_migration/proc/on_ray_destruction(var/mob/M)
|
||||
spawned_ray -= M
|
||||
GLOB.destroyed_event.unregister(M, src, PROC_REF(on_ray_destruction))
|
||||
UnregisterSignal(M, COMSIG_OBSERVER_DESTROYED)
|
||||
|
||||
/datum/event/ray_migration/end()
|
||||
. = ..()
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
// Spawn a single shark at given location.
|
||||
/datum/event/shark_migration/proc/spawn_one_shark(var/loc)
|
||||
var/mob/living/simple_mob/animal/M = new /mob/living/simple_mob/animal/space/shark/event(loc)
|
||||
GLOB.destroyed_event.register(M, src, PROC_REF(on_shark_destruction))
|
||||
RegisterSignal(M, COMSIG_OBSERVER_DESTROYED, PROC_REF(on_shark_destruction))
|
||||
spawned_shark.Add(M)
|
||||
return M
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
// If shark is bomphed, remove it from the list.
|
||||
/datum/event/shark_migration/proc/on_shark_destruction(var/mob/M)
|
||||
spawned_shark -= M
|
||||
GLOB.destroyed_event.unregister(M, src, PROC_REF(on_shark_destruction))
|
||||
UnregisterSignal(M, COMSIG_OBSERVER_DESTROYED)
|
||||
|
||||
/datum/event/shark_migration/end()
|
||||
. = ..()
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
// Spawn a single fish at given location.
|
||||
/datum/event/spacefish_migration/proc/spawn_one_fish(var/loc)
|
||||
var/mob/living/simple_mob/animal/M = new fish_type(loc)
|
||||
GLOB.destroyed_event.register(M, src, PROC_REF(on_fish_destruction))
|
||||
RegisterSignal(M, COMSIG_OBSERVER_DESTROYED, PROC_REF(on_fish_destruction))
|
||||
spawned_fish.Add(M)
|
||||
return M
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
// If fish is bomphed, remove it from the list.
|
||||
/datum/event/spacefish_migration/proc/on_fish_destruction(var/mob/M)
|
||||
spawned_fish -= M
|
||||
GLOB.destroyed_event.unregister(M, src, PROC_REF(on_fish_destruction))
|
||||
UnregisterSignal(M, COMSIG_OBSERVER_DESTROYED)
|
||||
|
||||
/datum/event/spacefish_migration/end()
|
||||
. = ..()
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
// Quickly adds the boilerplate code to add an image and padding for the image.
|
||||
/proc/desc_panel_image(var/icon_state)
|
||||
return "\icon[description_icons[icon_state]][EXAMINE_PANEL_PADDING]"
|
||||
return "[bicon(description_icons[icon_state])][EXAMINE_PANEL_PADDING]"
|
||||
|
||||
/mob/living/get_description_fluff()
|
||||
if(flavor_text) //Get flavor text for the green text.
|
||||
@@ -56,7 +56,7 @@
|
||||
description_holders["interactions"] = A.get_description_interaction()
|
||||
|
||||
description_holders["name"] = "[A.name]"
|
||||
description_holders["icon"] = "\icon[A.examine_icon()]"
|
||||
description_holders["icon"] = "[icon2html(A.examine_icon(),src)]"
|
||||
description_holders["desc"] = A.desc
|
||||
|
||||
/mob/Stat()
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/icecream/I = O
|
||||
if(!I.ice_creamed)
|
||||
if(product_types[dispense_flavour] > 0)
|
||||
src.visible_message("\icon[src][bicon(src)] <span class='info'>[user] scoops delicious [flavour_name] icecream into [I].</span>")
|
||||
src.visible_message("[icon2html(src,viewers(src))] <span class='info'>[user] scoops delicious [flavour_name] icecream into [I].</span>")
|
||||
product_types[dispense_flavour] -= 1
|
||||
I.add_ice_cream(flavour_name)
|
||||
// if(beaker)
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
/datum/event2/event/mob_spawning/proc/spawn_one_mob(new_loc, mob_type)
|
||||
var/mob/living/simple_mob/M = new mob_type(new_loc)
|
||||
GLOB.destroyed_event.register(M, src, PROC_REF(on_mob_destruction))
|
||||
RegisterSignal(M, COMSIG_OBSERVER_DESTROYED, PROC_REF(on_mob_destruction))
|
||||
spawned_mobs += M
|
||||
return M
|
||||
|
||||
@@ -94,4 +94,4 @@
|
||||
// If simple_mob is bomphed, remove it from the list.
|
||||
/datum/event2/event/mob_spawning/proc/on_mob_destruction(mob/M)
|
||||
spawned_mobs -= M
|
||||
GLOB.destroyed_event.unregister(M, src, PROC_REF(on_mob_destruction))
|
||||
UnregisterSignal(M, COMSIG_OBSERVER_DESTROYED)
|
||||
|
||||
@@ -112,9 +112,9 @@
|
||||
user.client.images |= holomap_datum.station_map
|
||||
|
||||
watching_mob = user
|
||||
GLOB.moved_event.register(watching_mob, src, /obj/machinery/station_map/proc/checkPosition)
|
||||
GLOB.dir_set_event.register(watching_mob, src, /obj/machinery/station_map/proc/checkPosition)
|
||||
GLOB.destroyed_event.register(watching_mob, src, /obj/machinery/station_map/proc/stopWatching)
|
||||
RegisterSignal(watching_mob, COMSIG_OBSERVER_MOVED, /obj/machinery/station_map/proc/checkPosition)
|
||||
//GLOB.dir_set_event.register(watching_mob, src, /obj/machinery/station_map/proc/checkPosition)
|
||||
RegisterSignal(watching_mob, COMSIG_OBSERVER_DESTROYED, /obj/machinery/station_map/proc/stopWatching)
|
||||
update_use_power(USE_POWER_ACTIVE)
|
||||
|
||||
if(bogus)
|
||||
@@ -141,9 +141,9 @@
|
||||
var/mob/M = watching_mob
|
||||
spawn(5) //we give it time to fade out
|
||||
M.client.images -= holomap_datum.station_map
|
||||
GLOB.moved_event.unregister(watching_mob, src)
|
||||
GLOB.dir_set_event.unregister(watching_mob, src)
|
||||
GLOB.destroyed_event.unregister(watching_mob, src)
|
||||
UnregisterSignal(watching_mob, COMSIG_OBSERVER_MOVED)
|
||||
//GLOB.dir_set_event.unregister(watching_mob, src)
|
||||
UnregisterSignal(watching_mob, COMSIG_OBSERVER_DESTROYED)
|
||||
watching_mob = null
|
||||
update_use_power(USE_POWER_IDLE)
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
/obj/machinery/station_map/update_icon()
|
||||
if(!holomap_datum)
|
||||
return //Not yet.
|
||||
|
||||
|
||||
cut_overlays()
|
||||
if(stat & BROKEN)
|
||||
icon_state = "station_mapb"
|
||||
|
||||
@@ -68,15 +68,15 @@
|
||||
active = 0
|
||||
if(failed_task)
|
||||
failed_task = 0
|
||||
visible_message("<span class='filter_notice'>\icon[src][bicon(src)] [src] pings unhappily, flashing a red warning light.</span>")
|
||||
visible_message("<span class='filter_notice'>[icon2html(src,viewers(src))] [src] pings unhappily, flashing a red warning light.</span>")
|
||||
else
|
||||
visible_message("<span class='filter_notice'>\icon[src][bicon(src)] [src] pings happily.</span>")
|
||||
visible_message("<span class='filter_notice'>[icon2html(src,viewers(src))] [src] pings happily.</span>")
|
||||
|
||||
if(eject_disk)
|
||||
eject_disk = 0
|
||||
if(loaded_disk)
|
||||
loaded_disk.loc = get_turf(src)
|
||||
visible_message("<span class='filter_notice'>\icon[src][bicon(src)] [src] beeps and spits out [loaded_disk].</span>")
|
||||
visible_message("<span class='filter_notice'>[icon2html(src,viewers(src))] [src] beeps and spits out [loaded_disk].</span>")
|
||||
loaded_disk = null
|
||||
|
||||
/obj/machinery/botany/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
@@ -190,7 +190,7 @@
|
||||
SSplants.seeds[seed.seed.name] = seed.seed
|
||||
|
||||
seed.update_seed()
|
||||
visible_message("\icon[src][bicon(src)] [src] beeps and spits out [seed].")
|
||||
visible_message("[icon2html(src,viewers(src))] [src] beeps and spits out [seed].")
|
||||
|
||||
seed = null
|
||||
return TRUE
|
||||
@@ -199,7 +199,7 @@
|
||||
if(!loaded_disk)
|
||||
return
|
||||
loaded_disk.forceMove(get_turf(src))
|
||||
visible_message("\icon[src][bicon(src)] [src] beeps and spits out [loaded_disk].")
|
||||
visible_message("[icon2html(src,viewers(src))] [src] beeps and spits out [loaded_disk].")
|
||||
loaded_disk = null
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
)
|
||||
|
||||
var/list/datum/reagent/allowed_reagents = list() //compile the list of reagents we're allowed to splice in
|
||||
|
||||
|
||||
|
||||
/obj/machinery/botany/precisioneditor/Initialize()
|
||||
for(var/R in SSchemistry.chemical_reagents)
|
||||
@@ -108,7 +108,7 @@
|
||||
seed.seed.name = "[seed.seed.uid]"
|
||||
SSplants.seeds[seed.seed.name] = seed.seed
|
||||
seed.update_seed()
|
||||
visible_message("[bicon(src)] [src] beeps and spits out [seed].")
|
||||
visible_message("[icon2html(src,viewers(src))] [src] beeps and spits out [seed].")
|
||||
|
||||
seed = null
|
||||
screen_state = "main"
|
||||
@@ -117,7 +117,7 @@
|
||||
if(!loaded_beaker)
|
||||
return
|
||||
loaded_beaker.loc = get_turf(src)
|
||||
visible_message("[bicon(src)] [src] beeps and politely sets out [loaded_beaker].")
|
||||
visible_message("[icon2html(src,viewers(src))] [src] beeps and politely sets out [loaded_beaker].")
|
||||
loaded_beaker = null
|
||||
. = TRUE
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
//Remove the chosen chem from the plant's product
|
||||
//TODO: this will be a cheaper operation the fewer chems the plant already
|
||||
//produces
|
||||
//produces
|
||||
if("prune")
|
||||
if(!isnull(SSplants.seeds[seed.seed.name]))
|
||||
seed.seed = seed.seed.diverge(1)
|
||||
@@ -141,7 +141,7 @@
|
||||
//TODO: additionally allow for changing the plant's glow color, if applicable
|
||||
if("change_color")
|
||||
var/newcolor = uppertext(input(usr, "Choose the desired color for the plant in hex:", "Color preference", rgb(128,128,128)))
|
||||
if(is_valid_hex(newcolor))
|
||||
if(is_valid_hex(newcolor))
|
||||
if(!isnull(SSplants.seeds[seed.seed.name]))
|
||||
seed.seed = seed.seed.diverge(1)
|
||||
seed.seed_type = seed.seed.name
|
||||
@@ -153,7 +153,7 @@
|
||||
seed.seed.traits["[TRAIT_PRODUCT_COLOUR]"] = newcolor
|
||||
else
|
||||
else
|
||||
visible_message("[bicon(src)] Error: Invalid input detected.")
|
||||
visible_message("[icon2html(src,viewers(src))] Error: Invalid input detected.")
|
||||
. = TRUE
|
||||
if("add_chem")
|
||||
add_chem_to_seed(params["target_chem"])
|
||||
@@ -170,7 +170,7 @@
|
||||
var/safety_check = 1
|
||||
if(!(length(input) == 7))
|
||||
return FALSE //input is either too short or too long
|
||||
|
||||
|
||||
var/char = copytext(input, 1, 2)
|
||||
if(char != "#")
|
||||
return FALSE //ensure that the first character is a #
|
||||
@@ -180,18 +180,18 @@
|
||||
if(!(char in list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")))
|
||||
return FALSE
|
||||
safety_check++
|
||||
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/machinery/botany/precisioneditor/proc/add_chem_to_seed(var/chem_name)
|
||||
if(!loaded_beaker)
|
||||
return
|
||||
var/chem_amount = loaded_beaker.reagents.get_reagent_amount(chem_name)
|
||||
if(!(chem_name in allowed_reagents))
|
||||
visible_message("[bicon(src)] Error: The chosen compound is too complex to synthesize biologically.")
|
||||
visible_message("[icon2html(src,viewers(src))] Error: The chosen compound is too complex to synthesize biologically.")
|
||||
return
|
||||
if(chem_amount < 100)
|
||||
visible_message("[bicon(src)] Error: A minimum of 100 [SSchemistry.chemical_reagents[chem_name]] is required to perform this action.")
|
||||
visible_message("[icon2html(src,viewers(src))] Error: A minimum of 100 [SSchemistry.chemical_reagents[chem_name]] is required to perform this action.")
|
||||
return
|
||||
else
|
||||
if(!isnull(SSplants.seeds[seed.seed.name])) //diverge the seed into a new species
|
||||
@@ -204,7 +204,7 @@
|
||||
seed.modified += rand(15,25)
|
||||
if(prob(seed.modified))
|
||||
seed.modified = 101
|
||||
visible_message("[bicon(src)] [src] pings unhappily, flashing a red warning light.")
|
||||
visible_message("[icon2html(src,viewers(src))] [src] pings unhappily, flashing a red warning light.")
|
||||
loaded_beaker.reagents.remove_reagent(chem_name, chem_amount) //remove ALL of the reagent from the beaker
|
||||
visible_message("[bicon(src)] The [src] beeps, indicating genetic synthesis was successful.")
|
||||
visible_message("[icon2html(src,viewers(src))] The [src] beeps, indicating genetic synthesis was successful.")
|
||||
return
|
||||
|
||||
@@ -415,7 +415,7 @@
|
||||
|
||||
if(loc)
|
||||
for(var/mob/O in hearers(1, get_turf(src)))
|
||||
O.show_message("\icon[src][bicon(src)] *beep* *beep*", 3, "*beep* *beep*", 2)
|
||||
O.show_message("[icon2html(src, usr.client)] *beep* *beep*", 3, "*beep* *beep*", 2)
|
||||
|
||||
/obj/item/integrated_circuit/input/EPv2
|
||||
name = "\improper EPv2 circuit"
|
||||
|
||||
@@ -188,14 +188,14 @@
|
||||
// These procs do not relocate the grenade, that's the callers responsibility
|
||||
/obj/item/integrated_circuit/manipulation/grenade/proc/attach_grenade(var/obj/item/weapon/grenade/G)
|
||||
attached_grenade = G
|
||||
GLOB.destroyed_event.register(attached_grenade, src, /obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade)
|
||||
RegisterSignal(attached_grenade, COMSIG_OBSERVER_DESTROYED, /obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade)
|
||||
size += G.w_class
|
||||
desc += " \An [attached_grenade] is attached to it!"
|
||||
|
||||
/obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade()
|
||||
if(!attached_grenade)
|
||||
return
|
||||
GLOB.destroyed_event.unregister(attached_grenade, src, /obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade)
|
||||
UnregisterSignal(attached_grenade, COMSIG_OBSERVER_DESTROYED)
|
||||
attached_grenade = null
|
||||
size = initial(size)
|
||||
desc = initial(desc)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
var/list/nearby_things = range(0, get_turf(src))
|
||||
for(var/mob/M in nearby_things)
|
||||
var/obj/O = assembly ? assembly : src
|
||||
to_chat(M, "<span class='notice'>\icon[O][bicon(O)] [stuff_to_display]</span>")
|
||||
to_chat(M, "<span class='notice'>[icon2html(O,M.client)] [stuff_to_display]</span>")
|
||||
|
||||
/obj/item/integrated_circuit/output/screen/large
|
||||
name = "large screen"
|
||||
@@ -56,7 +56,7 @@
|
||||
/obj/item/integrated_circuit/output/screen/large/do_work()
|
||||
..()
|
||||
var/obj/O = assembly ? loc : assembly
|
||||
O.visible_message("<span class='notice'>\icon[O][bicon(O)] [stuff_to_display]</span>")
|
||||
O.visible_message("<span class='notice'>[icon2html(O,viewers(O))] [stuff_to_display]</span>")
|
||||
|
||||
/obj/item/integrated_circuit/output/light
|
||||
name = "light"
|
||||
@@ -138,7 +138,7 @@
|
||||
text = get_pin_data(IC_INPUT, 1)
|
||||
if(!isnull(text))
|
||||
var/obj/O = assembly ? loc : assembly
|
||||
audible_message("\icon[O][bicon(O)] \The [O.name] states, \"[text]\"", runemessage = text)
|
||||
audible_message("[icon2html(O,hearers(src))] \The [O.name] states, \"[text]\"", runemessage = text)
|
||||
|
||||
/obj/item/integrated_circuit/output/text_to_speech/advanced
|
||||
name = "advanced text-to-speech circuit"
|
||||
@@ -448,11 +448,11 @@
|
||||
|
||||
/obj/item/integrated_circuit/output/holographic_projector/Initialize()
|
||||
. = ..()
|
||||
GLOB.moved_event.register(src, src, PROC_REF(on_moved))
|
||||
RegisterSignal(src, COMSIG_OBSERVER_MOVED, PROC_REF(on_moved))
|
||||
|
||||
/obj/item/integrated_circuit/output/holographic_projector/Destroy()
|
||||
destroy_hologram()
|
||||
GLOB.moved_event.unregister(src, src, PROC_REF(on_moved))
|
||||
UnregisterSignal(src, COMSIG_OBSERVER_MOVED)
|
||||
return ..()
|
||||
|
||||
/obj/item/integrated_circuit/output/holographic_projector/do_work()
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
list(/obj/item/toy/syndicateballoon, 3) = 2,
|
||||
list(/obj/item/clothing/suit/ianshirt, 3) = 2,
|
||||
list(/obj/item/clothing/head/bearpelt, 4) = 2,
|
||||
list(/obj/item/weapon/archaeological_find, 3) = 2,
|
||||
//list(/obj/item/weapon/archaeological_find, 3) = 2, //ChompREMOVE - causes runtimes
|
||||
list(pick(subtypesof(/obj/item/toy/mecha)), 4) = 2,
|
||||
list(pick(subtypesof(/obj/item/toy/figure)), 4) = 2,
|
||||
list(pick(subtypesof(/obj/item/toy/plushie)), 4) = 2,
|
||||
@@ -172,4 +172,4 @@
|
||||
/obj/item/weapon/storage/backpack/sport/hyd/catchemall/Initialize() //gotta have your starter 'mon too (or an improved way to catch one)
|
||||
..()
|
||||
var/path = pick(subtypesof(/obj/item/capture_crystal))
|
||||
contents += new path()
|
||||
contents += new path()
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
if(ore_type) metals[ore_type] += T.resources[metal]
|
||||
|
||||
var/message = "\icon[src][bicon(src)] <span class='notice'>The scanner beeps and displays a readout.</span>"
|
||||
var/message = "[icon2html(src, user.client)] <span class='notice'>The scanner beeps and displays a readout.</span>"
|
||||
|
||||
for(var/ore_type in metals)
|
||||
var/result = "no sign"
|
||||
@@ -87,4 +87,4 @@
|
||||
var/custom_range = tgui_input_list(usr, "Scanner Range","Pick a range to scan. ", list(0,1,2,3,4,5,6,7))
|
||||
if(custom_range)
|
||||
range = custom_range
|
||||
to_chat(usr, "<span class='notice'>Scanner will now look up to [range] tile(s) away.</span>")
|
||||
to_chat(usr, "<span class='notice'>Scanner will now look up to [range] tile(s) away.</span>")
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
else
|
||||
if(mind && mind.assigned_role) //CHOMPEdit
|
||||
return //CHOMPEdit
|
||||
cleanup_timer = QDEL_IN(src, 10 MINUTES)
|
||||
cleanup_timer = QDEL_IN_STOPPABLE(src, 10 MINUTES)
|
||||
|
||||
@@ -462,6 +462,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(target != src)
|
||||
if(following && following == target)
|
||||
return
|
||||
if(following)
|
||||
src.stop_following()
|
||||
following = target
|
||||
to_chat(src, "<span class='notice'>Now following [target]</span>")
|
||||
if(ismob(target))
|
||||
|
||||
@@ -214,17 +214,17 @@
|
||||
say("Down on the floor, [suspect_name]! You have [SECBOT_WAIT_TIME*2] seconds to comply.")
|
||||
playsound(src, pick(preparing_arrest_sounds), 50)
|
||||
// Register to be told when the target moves
|
||||
GLOB.moved_event.register(target, src, /mob/living/bot/secbot/proc/target_moved)
|
||||
RegisterSignal(target, COMSIG_OBSERVER_MOVED, /mob/living/bot/secbot/proc/target_moved)
|
||||
|
||||
// Callback invoked if the registered target moves
|
||||
/mob/living/bot/secbot/proc/target_moved(atom/movable/moving_instance, atom/old_loc, atom/new_loc)
|
||||
if(get_dist(get_turf(src), get_turf(target)) >= 1)
|
||||
awaiting_surrender = INFINITY // Done waiting!
|
||||
GLOB.moved_event.unregister(moving_instance, src)
|
||||
UnregisterSignal(moving_instance, COMSIG_OBSERVER_MOVED)
|
||||
|
||||
/mob/living/bot/secbot/resetTarget()
|
||||
..()
|
||||
GLOB.moved_event.unregister(target, src)
|
||||
UnregisterSignal(target, COMSIG_OBSERVER_MOVED)
|
||||
awaiting_surrender = 0
|
||||
attacked = FALSE
|
||||
walk_to(src, 0)
|
||||
@@ -478,4 +478,4 @@
|
||||
return
|
||||
if(!in_range(src, user) && loc != user)
|
||||
return
|
||||
created_name = t
|
||||
created_name = t
|
||||
|
||||
@@ -18,13 +18,11 @@
|
||||
germ_level++
|
||||
|
||||
/mob/living/carbon/Destroy()
|
||||
qdel(ingested)
|
||||
qdel(touching)
|
||||
QDEL_NULL(ingested)
|
||||
QDEL_NULL(touching)
|
||||
// We don't qdel(bloodstr) because it's the same as qdel(reagents)
|
||||
for(var/guts in internal_organs)
|
||||
qdel(guts)
|
||||
for(var/food in stomach_contents)
|
||||
qdel(food)
|
||||
bloodstr = null
|
||||
QDEL_NULL_LIST(stomach_contents)
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/rejuvenate()
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
else if(species.name != "Human")
|
||||
name_ender = ", <b><font color='[species.get_flesh_colour(src)]'>\a [species.get_examine_name()]!</font></b>[species.get_additional_examine_text(src)]"
|
||||
|
||||
var/list/msg = list("<span class='info'>*---------*","This is \icon[src.examine_icon()][bicon(src)] <EM>[src.name]</EM>[name_ender]")
|
||||
var/list/msg = list("<span class='info'>*---------*","This is [icon2html(src, user.client)] <EM>[src.name]</EM>[name_ender]")
|
||||
|
||||
//uniform
|
||||
if(w_uniform && !(skip_gear & EXAMINE_SKIPJUMPSUIT) && w_uniform.show_examine)
|
||||
@@ -125,16 +125,16 @@
|
||||
|
||||
tie_msg += " [lowertext(english_list(accessory_descs))]."
|
||||
if(w_uniform.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[w_uniform][bicon(w_uniform)] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[w_uniform]'>[w_uniform.name]</a>![tie_msg]</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] wearing [icon2html(w_uniform,user.client)] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[w_uniform]'>[w_uniform.name]</a>![tie_msg]</span>"
|
||||
else
|
||||
msg += "[T.He] [T.is] wearing [bicon(w_uniform)] <a href='?src=\ref[src];lookitem_desc_only=\ref[w_uniform]'>\a [w_uniform]</a>.[tie_msg]"
|
||||
msg += "[T.He] [T.is] wearing [icon2html(w_uniform,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[w_uniform]'>\a [w_uniform]</a>.[tie_msg]"
|
||||
|
||||
//head
|
||||
if(head && !(skip_gear & EXAMINE_SKIPHELMET) && head.show_examine)
|
||||
if(head.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[w_uniform][bicon(head)] [head.gender==PLURAL?"some":"a"] [(head.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[head]'>[head.name]</a> on [T.his] head!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] wearing [icon2html(head,user.client)] [head.gender==PLURAL?"some":"a"] [(head.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[head]'>[head.name]</a> on [T.his] head!</span>"
|
||||
else
|
||||
msg += "[T.He] [T.is] wearing [bicon(head)] <a href='?src=\ref[src];lookitem_desc_only=\ref[head]'>\a [head]</a> on [T.his] head."
|
||||
msg += "[T.He] [T.is] wearing [icon2html(head,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[head]'>\a [head]</a> on [T.his] head."
|
||||
|
||||
//suit/armour
|
||||
if(wear_suit)
|
||||
@@ -151,71 +151,71 @@
|
||||
tie_msg += " [lowertext(english_list(accessory_descs))]."
|
||||
|
||||
if(wear_suit.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[wear_suit][bicon(wear_suit)] [wear_suit.gender==PLURAL?"some":"a"] [(wear_suit.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_suit]'>[wear_suit.name]</a>![tie_msg]</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] wearing [icon2html(wear_suit,user.client)] [wear_suit.gender==PLURAL?"some":"a"] [(wear_suit.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_suit]'>[wear_suit.name]</a>![tie_msg]</span>"
|
||||
else
|
||||
msg += "[T.He] [T.is] wearing \icon[wear_suit][bicon(wear_suit)] <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_suit]'>\a [wear_suit]</a>.[tie_msg]"
|
||||
msg += "[T.He] [T.is] wearing [icon2html(wear_suit,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_suit]'>\a [wear_suit]</a>.[tie_msg]"
|
||||
|
||||
//suit/armour storage
|
||||
if(s_store && !(skip_gear & EXAMINE_SKIPSUITSTORAGE) && s_store.show_examine)
|
||||
if(s_store.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.is] carrying \icon[s_store][bicon(s_store)] [s_store.gender==PLURAL?"some":"a"] [(s_store.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[s_store]'>[s_store.name]</a> on [T.his] [wear_suit.name]!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] carrying [icon2html(s_store,user.client)] [s_store.gender==PLURAL?"some":"a"] [(s_store.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[s_store]'>[s_store.name]</a> on [T.his] [wear_suit.name]!</span>"
|
||||
else
|
||||
msg += "[T.He] [T.is] carrying \icon[s_store][bicon(s_store)] <a href='?src=\ref[src];lookitem_desc_only=\ref[s_store]'>\a [s_store]</a> on [T.his] [wear_suit.name]."
|
||||
msg += "[T.He] [T.is] carrying [icon2html(s_store,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[s_store]'>\a [s_store]</a> on [T.his] [wear_suit.name]."
|
||||
|
||||
//back
|
||||
if(back && !(skip_gear & EXAMINE_SKIPBACKPACK) && back.show_examine)
|
||||
if(back.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.has] \icon[back][bicon(back)] [back.gender==PLURAL?"some":"a"] [(back.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[back]'>[back]</a> on [T.his] back.</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.has] [icon2html(back,user.client)] [back.gender==PLURAL?"some":"a"] [(back.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[back]'>[back]</a> on [T.his] back.</span>"
|
||||
else
|
||||
msg += "[T.He] [T.has] \icon[back][bicon(back)] <a href='?src=\ref[src];lookitem_desc_only=\ref[back]'>\a [back]</a> on [T.his] back."
|
||||
msg += "[T.He] [T.has] [icon2html(back,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[back]'>\a [back]</a> on [T.his] back."
|
||||
|
||||
//left hand
|
||||
if(l_hand && l_hand.show_examine)
|
||||
if(l_hand.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.is] holding \icon[l_hand][bicon(l_hand)] [l_hand.gender==PLURAL?"some":"a"] [(l_hand.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[l_hand]'>[l_hand.name]</a> in [T.his] left hand!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] holding [icon2html(l_hand,user.client)] [l_hand.gender==PLURAL?"some":"a"] [(l_hand.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[l_hand]'>[l_hand.name]</a> in [T.his] left hand!</span>"
|
||||
else
|
||||
msg += "[T.He] [T.is] holding \icon[l_hand][bicon(l_hand)] <a href='?src=\ref[src];lookitem_desc_only=\ref[l_hand]'>\a [l_hand]</a> in [T.his] left hand."
|
||||
msg += "[T.He] [T.is] holding [icon2html(l_hand,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[l_hand]'>\a [l_hand]</a> in [T.his] left hand."
|
||||
|
||||
//right hand
|
||||
if(r_hand && r_hand.show_examine)
|
||||
if(r_hand.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.is] holding \icon[r_hand][bicon(r_hand)] [r_hand.gender==PLURAL?"some":"a"] [(r_hand.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[r_hand]'>[r_hand.name]</a> in [T.his] right hand!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] holding [icon2html(r_hand,user.client)] [r_hand.gender==PLURAL?"some":"a"] [(r_hand.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[r_hand]'>[r_hand.name]</a> in [T.his] right hand!</span>"
|
||||
else
|
||||
msg += "[T.He] [T.is] holding \icon[r_hand][bicon(r_hand)] <a href='?src=\ref[src];lookitem_desc_only=\ref[r_hand]'>\a [r_hand]</a> in [T.his] right hand."
|
||||
msg += "[T.He] [T.is] holding [icon2html(r_hand,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[r_hand]'>\a [r_hand]</a> in [T.his] right hand."
|
||||
|
||||
//gloves
|
||||
if(gloves && !(skip_gear & EXAMINE_SKIPGLOVES) && gloves.show_examine)
|
||||
if(gloves.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.has] \icon[gloves][bicon(gloves)] [gloves.gender==PLURAL?"some":"a"] [(gloves.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[gloves]'>[gloves.name]</a> on [T.his] hands!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.has] [icon2html(gloves,user.client)] [gloves.gender==PLURAL?"some":"a"] [(gloves.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[gloves]'>[gloves.name]</a> on [T.his] hands!</span>"
|
||||
else
|
||||
msg += "[T.He] [T.has] \icon[gloves][bicon(gloves)] <a href='?src=\ref[src];lookitem_desc_only=\ref[gloves]'>\a [gloves]</a> on [T.his] hands."
|
||||
msg += "[T.He] [T.has] [icon2html(gloves,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[gloves]'>\a [gloves]</a> on [T.his] hands."
|
||||
else if(blood_DNA && !(skip_body & EXAMINE_SKIPHANDS))
|
||||
msg += "<span class='warning'>[T.He] [T.has] [(hand_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained hands!</span>"
|
||||
|
||||
//handcuffed?
|
||||
if(handcuffed && handcuffed.show_examine)
|
||||
if(istype(handcuffed, /obj/item/weapon/handcuffs/cable))
|
||||
msg += "<span class='warning'>[T.He] [T.is] \icon[handcuffed][bicon(handcuffed)] restrained with cable!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] [icon2html(handcuffed,user.client)] restrained with cable!</span>"
|
||||
else
|
||||
msg += "<span class='warning'>[T.He] [T.is] \icon[handcuffed][bicon(handcuffed)] handcuffed!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] [icon2html(handcuffed,user.client)] handcuffed!</span>"
|
||||
|
||||
//buckled
|
||||
if(buckled)
|
||||
msg += "<span class='warning'>[T.He] [T.is] \icon[buckled][bicon(buckled)] buckled to [buckled]!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] [icon2html(buckled,user.client)] buckled to [buckled]!</span>"
|
||||
|
||||
//belt
|
||||
if(belt && !(skip_gear & EXAMINE_SKIPBELT) && belt.show_examine)
|
||||
if(belt.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.has] \icon[belt][bicon(belt)] [belt.gender==PLURAL?"some":"a"] [(belt.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[belt]'>[belt.name]</a> about [T.his] waist!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.has] [icon2html(belt,user.client)] [belt.gender==PLURAL?"some":"a"] [(belt.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[belt]'>[belt.name]</a> about [T.his] waist!</span>"
|
||||
else
|
||||
msg += "[T.He] [T.has] \icon[belt][bicon(belt)] <a href='?src=\ref[src];lookitem_desc_only=\ref[belt]'>\a [belt]</a> about [T.his] waist."
|
||||
msg += "[T.He] [T.has] [icon2html(belt,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[belt]'>\a [belt]</a> about [T.his] waist."
|
||||
|
||||
//shoes
|
||||
if(shoes && !(skip_gear & EXAMINE_SKIPSHOES) && shoes.show_examine)
|
||||
if(shoes.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[shoes][bicon(shoes)] [shoes.gender==PLURAL?"some":"a"] [(shoes.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[shoes]'>[shoes.name]</a> on [T.his] feet!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.is] wearing [icon2html(shoes,user.client)] [shoes.gender==PLURAL?"some":"a"] [(shoes.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[shoes]'>[shoes.name]</a> on [T.his] feet!</span>"
|
||||
else
|
||||
msg += "[T.He] [T.is] wearing \icon[shoes][bicon(shoes)] <a href='?src=\ref[src];lookitem_desc_only=\ref[shoes]'>\a [shoes]</a> on [T.his] feet."
|
||||
msg += "[T.He] [T.is] wearing [icon2html(shoes,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[shoes]'>\a [shoes]</a> on [T.his] feet."
|
||||
else if(feet_blood_DNA && !(skip_body & EXAMINE_SKIPHANDS))
|
||||
msg += "<span class='warning'>[T.He] [T.has] [(feet_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained feet!</span>"
|
||||
|
||||
@@ -226,28 +226,28 @@
|
||||
descriptor = "in [T.his] mouth"
|
||||
|
||||
if(wear_mask.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.has] \icon[wear_mask][bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] [(wear_mask.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_mask]'>[wear_mask.name]</a> [descriptor]!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.has] [icon2html(wear_mask,user.client)] [wear_mask.gender==PLURAL?"some":"a"] [(wear_mask.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_mask]'>[wear_mask.name]</a> [descriptor]!</span>"
|
||||
else
|
||||
msg += "[T.He] [T.has] \icon[wear_mask][bicon(wear_mask)] <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_mask]'>\a [wear_mask]</a> [descriptor]."
|
||||
msg += "[T.He] [T.has] [icon2html(wear_mask,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[wear_mask]'>\a [wear_mask]</a> [descriptor]."
|
||||
|
||||
//eyes
|
||||
if(glasses && !(skip_gear & EXAMINE_SKIPEYEWEAR) && glasses.show_examine)
|
||||
if(glasses.blood_DNA)
|
||||
msg += "<span class='warning'>[T.He] [T.has] \icon[glasses][bicon(glasses)] [glasses.gender==PLURAL?"some":"a"] [(glasses.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[glasses]'>[glasses]</a> covering [T.his] eyes!</span>"
|
||||
msg += "<span class='warning'>[T.He] [T.has] [icon2html(glasses,user.client)] [glasses.gender==PLURAL?"some":"a"] [(glasses.blood_color != "#030303") ? "blood" : "oil"]-stained <a href='?src=\ref[src];lookitem_desc_only=\ref[glasses]'>[glasses]</a> covering [T.his] eyes!</span>"
|
||||
else
|
||||
msg += "[T.He] [T.has] \icon[glasses][bicon(glasses)] <a href='?src=\ref[src];lookitem_desc_only=\ref[glasses]'>\a [glasses]</a> covering [T.his] eyes."
|
||||
msg += "[T.He] [T.has] [icon2html(glasses,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[glasses]'>\a [glasses]</a> covering [T.his] eyes."
|
||||
|
||||
//left ear
|
||||
if(l_ear && !(skip_gear & EXAMINE_SKIPEARS) && l_ear.show_examine)
|
||||
msg += "[T.He] [T.has] \icon[l_ear][bicon(l_ear)] <a href='?src=\ref[src];lookitem_desc_only=\ref[l_ear]'>\a [l_ear]</a> on [T.his] left ear."
|
||||
msg += "[T.He] [T.has] [icon2html(l_ear,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[l_ear]'>\a [l_ear]</a> on [T.his] left ear."
|
||||
|
||||
//right ear
|
||||
if(r_ear && !(skip_gear & EXAMINE_SKIPEARS) && r_ear.show_examine)
|
||||
msg += "[T.He] [T.has] \icon[r_ear][bicon(r_ear)] <a href='?src=\ref[src];lookitem_desc_only=\ref[r_ear]'>\a [r_ear]</a> on [T.his] right ear."
|
||||
msg += "[T.He] [T.has] [icon2html(r_ear,user.client)] <a href='?src=\ref[src];lookitem_desc_only=\ref[r_ear]'>\a [r_ear]</a> on [T.his] right ear."
|
||||
|
||||
//ID
|
||||
if(wear_id && wear_id.show_examine)
|
||||
msg += "[T.He] [T.is] wearing \icon[wear_id][bicon(wear_id)]<a href='?src=\ref[src];lookitem_desc_only=\ref[wear_id]'>\a [wear_id]</a>."
|
||||
msg += "[T.He] [T.is] wearing [icon2html(wear_id,user.client)]<a href='?src=\ref[src];lookitem_desc_only=\ref[wear_id]'>\a [wear_id]</a>."
|
||||
|
||||
//Jitters
|
||||
if(is_jittery)
|
||||
|
||||
@@ -58,10 +58,17 @@
|
||||
|
||||
/mob/living/carbon/human/Destroy()
|
||||
human_mob_list -= src
|
||||
/* //Chomp REMOVE - this is done on mob/living/Destroy
|
||||
for(var/organ in organs)
|
||||
qdel(organ)
|
||||
QDEL_NULL(nif) //VOREStation Add
|
||||
*/
|
||||
if(nif)
|
||||
QDEL_NULL(nif) //VOREStation Add
|
||||
worn_clothing.Cut()
|
||||
|
||||
|
||||
if(vessel)
|
||||
QDEL_NULL(vessel)
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/Stat()
|
||||
|
||||
@@ -73,13 +73,13 @@
|
||||
// Called in robotize(), replaced() and removed() to update our modular limb verbs.
|
||||
/mob/living/carbon/human/proc/refresh_modular_limb_verbs()
|
||||
if(length(get_modular_limbs(return_first_found = TRUE, validate_proc = /obj/item/organ/external/proc/can_attach_modular_limb_here)))
|
||||
verbs |= PROC_REF(attach_limb_verb)
|
||||
verbs |= /mob/living/carbon/human/proc/attach_limb_verb
|
||||
else
|
||||
verbs -= PROC_REF(attach_limb_verb)
|
||||
verbs -= /mob/living/carbon/human/proc/attach_limb_verb
|
||||
if(length(get_modular_limbs(return_first_found = TRUE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb)))
|
||||
verbs |= PROC_REF(detach_limb_verb)
|
||||
verbs |= /mob/living/carbon/human/proc/detach_limb_verb
|
||||
else
|
||||
verbs -= PROC_REF(detach_limb_verb)
|
||||
verbs -= /mob/living/carbon/human/proc/detach_limb_verb
|
||||
|
||||
// Proc helper for attachment verb.
|
||||
/mob/living/carbon/human/proc/check_can_attach_modular_limb(var/obj/item/organ/external/E)
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
img.override = TRUE
|
||||
add_alt_appearance("animals", img, displayTo = alt_farmanimals)
|
||||
|
||||
|
||||
/mob/living/carbon/human/Destroy()
|
||||
alt_farmanimals -= src
|
||||
|
||||
@@ -18,4 +17,3 @@
|
||||
|
||||
/mob/living/carbon/human/get_digestion_efficiency_modifier()
|
||||
return species.digestion_efficiency
|
||||
|
||||
|
||||
@@ -101,20 +101,15 @@
|
||||
|
||||
return new_copy
|
||||
|
||||
//We REALLY don't need to go through every variable. Doing so makes this lag like hell on 515
|
||||
/datum/species/proc/copy_variables(var/datum/species/S, var/list/whitelist)
|
||||
//List of variables to ignore, trying to copy type will runtime.
|
||||
var/list/blacklist = list("type", "loc", "client", "ckey")
|
||||
//var/list/blacklist = list("type", "loc", "client", "ckey")
|
||||
//Makes thorough copy of species datum.
|
||||
for(var/i in vars)
|
||||
for(var/i in whitelist)
|
||||
if(!(i in S.vars)) //Don't copy incompatible vars.
|
||||
continue
|
||||
if(S.vars[i] != vars[i] && !islist(vars[i])) //If vars are same, no point in copying.
|
||||
if(i in blacklist)
|
||||
continue
|
||||
if(whitelist)//If whitelist is provided, only vars in the list will be copied.
|
||||
if(i in whitelist)
|
||||
S.vars[i] = vars[i]
|
||||
continue
|
||||
S.vars[i] = vars[i]
|
||||
|
||||
/datum/species/get_bodytype()
|
||||
|
||||
@@ -83,8 +83,7 @@
|
||||
if(stored_blob)
|
||||
stored_blob.drop_l_hand()
|
||||
stored_blob.drop_r_hand()
|
||||
stored_blob = null
|
||||
qdel(stored_blob)
|
||||
QDEL_NULL(stored_blob)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_mob/slime/promethean/Stat()
|
||||
|
||||
@@ -50,22 +50,17 @@
|
||||
B.owner = tf_mob_holder
|
||||
tf_mob_holder.vore_organs |= B
|
||||
vore_organs -= B
|
||||
|
||||
if(tf_mob_holder)
|
||||
tf_mob_holder = null
|
||||
//VOREStation Addition End
|
||||
//ChompEDIT START
|
||||
if(selected_image) // prune out images
|
||||
selected_image = null
|
||||
if(hud_list) //prune out images in hud_list
|
||||
for(var/item in hud_list)
|
||||
if(item)
|
||||
item = null
|
||||
//ChompEDIT END
|
||||
|
||||
qdel(selected_image)
|
||||
QDEL_NULL(vorePanel) //VOREStation Add
|
||||
QDEL_LIST_NULL(vore_organs) //VOREStation Add
|
||||
if(selected_image)
|
||||
selected_image = null
|
||||
//QDEL_NULL(vorePanel) //VOREStation Add commented and moved to /mob
|
||||
//QDEL_LIST_NULL(vore_organs) //VOREStation Add commented and moved to /mob
|
||||
temp_language_sources = null //VOREStation Add
|
||||
temp_languages = null //VOREStation Add
|
||||
|
||||
@@ -1329,7 +1324,7 @@
|
||||
/datum/component/character_setup/proc/character_setup_click(source, location, control, params, user)
|
||||
var/mob/owner = user
|
||||
if(owner.client?.prefs)
|
||||
INVOKE_ASYNC(owner.client.prefs, /datum/preferences/proc/ShowChoices, owner)
|
||||
INVOKE_ASYNC(owner.client.prefs, TYPE_PROC_REF(/datum/preferences, ShowChoices), owner)
|
||||
|
||||
/**
|
||||
* Screen object for vore panel
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
spawn(0)
|
||||
R.send_signal("ACTIVATE")
|
||||
for(var/mob/O in hearers(1, R.loc))
|
||||
O.show_message("\icon[R][bicon(R)] *beep* *beep*", 3, "*beep* *beep*", 2)
|
||||
O.show_message("[icon2html(R,O.client)] *beep* *beep*", 3, "*beep* *beep*", 2)
|
||||
if("freq")
|
||||
var/frequency = unformat_frequency(params["freq"])
|
||||
frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ)
|
||||
|
||||
@@ -229,21 +229,20 @@
|
||||
else
|
||||
src.healths.icon_state = "health6"
|
||||
else
|
||||
switch(health)
|
||||
if(200 to INFINITY)
|
||||
src.healths.icon_state = "health0"
|
||||
if(150 to 200)
|
||||
src.healths.icon_state = "health1"
|
||||
if(100 to 150)
|
||||
src.healths.icon_state = "health2"
|
||||
if(50 to 100)
|
||||
src.healths.icon_state = "health3"
|
||||
if(0 to 50)
|
||||
src.healths.icon_state = "health4"
|
||||
if(config.health_threshold_dead to 0)
|
||||
src.healths.icon_state = "health5"
|
||||
else
|
||||
src.healths.icon_state = "health6"
|
||||
if(health >= 200)
|
||||
src.healths.icon_state = "health0"
|
||||
else if(health >= 150)
|
||||
src.healths.icon_state = "health1"
|
||||
else if(health >= 100)
|
||||
src.healths.icon_state = "health2"
|
||||
else if(health >= 50)
|
||||
src.healths.icon_state = "health3"
|
||||
else if(health >= 0)
|
||||
src.healths.icon_state = "health4"
|
||||
else if(health >= config.health_threshold_dead)
|
||||
src.healths.icon_state = "health5"
|
||||
else
|
||||
src.healths.icon_state = "health6"
|
||||
else
|
||||
src.healths.icon_state = "health7"
|
||||
|
||||
|
||||
@@ -226,9 +226,7 @@
|
||||
return
|
||||
visible_message("<span class='notice'>\The [src] pushes [M]'s hand away from their tummy and furrows their brow!</span>")
|
||||
if(prob(5))
|
||||
ai_holder.target = M
|
||||
ai_holder.track_target_position()
|
||||
ai_holder.set_stance(STANCE_FIGHT)
|
||||
ai_holder.give_target(M, urgent = TRUE)
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -455,9 +453,7 @@
|
||||
return
|
||||
visible_message("<span class='notice'>\The [src] pushes [M]'s hand away from their tummy and furrows their brow, frantically pressing at the buttons [M] so carelessly pushed!</span>")
|
||||
if(prob(5))
|
||||
ai_holder.target = M
|
||||
ai_holder.track_target_position()
|
||||
ai_holder.set_stance(STANCE_FIGHT)
|
||||
ai_holder.give_target(M, urgent = TRUE)
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -557,9 +553,7 @@
|
||||
return
|
||||
visible_message("<span class='notice'>\The [src] pushes [M]'s hand away from their tummy and furrows their brow!</span>")
|
||||
if(prob(5))
|
||||
ai_holder.target = M
|
||||
ai_holder.track_target_position()
|
||||
ai_holder.set_stance(STANCE_FIGHT)
|
||||
ai_holder.give_target(M, urgent = TRUE)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
if( ishuman(AM) )
|
||||
if(!stat)
|
||||
var/mob/M = AM
|
||||
M.visible_message(span_blue("\icon[src][bicon(src)] Squeek!"))
|
||||
M.visible_message(span_blue("[icon2html(src,viewers(src))] Squeek!"))
|
||||
playsound(src, 'sound/effects/mouse_squeak.ogg', 35, 1)
|
||||
..()
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
if( ishuman(AM) )
|
||||
if(!stat)
|
||||
var/mob/M = AM
|
||||
M.visible_message(span_blue("\icon[src] Squeek!"))
|
||||
M.visible_message(span_blue("[icon2html(src,viewers(M))] Squeek!"))
|
||||
playsound(src, 'sound/effects/mouse_squeak.ogg', 35, 1)
|
||||
..()
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ var/global/list/grub_machine_overlays = list()
|
||||
sparks.start()
|
||||
if(machine_effect)
|
||||
QDEL_NULL(machine_effect)
|
||||
ai_holder.target = null
|
||||
ai_holder.remove_target()
|
||||
powermachine.draining = 1
|
||||
spawn(30)
|
||||
set_AI_busy(FALSE)
|
||||
@@ -305,4 +305,4 @@ var/global/list/grub_machine_overlays = list()
|
||||
grub.eject_from_machine(O)
|
||||
to_chat(user, "<span class='warning'>You disturb a grub nesting in \the [O]!</span>")
|
||||
return
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
var/new_name = sanitizeSafe(tgui_input_text(src, "Who would you like to be now?", "Communicator", src.client.prefs.real_name, MAX_NAME_LEN), MAX_NAME_LEN)
|
||||
if(new_name)
|
||||
if(comm)
|
||||
comm.visible_message("<span class='notice'>\icon[comm][bicon(comm)] [src.name] has left, and now you see [new_name].</span>")
|
||||
comm.visible_message("<span class='notice'>[icon2html(comm,viewers(comm))] [src.name] has left, and now you see [new_name].</span>")
|
||||
//Do a bit of logging in-case anyone tries to impersonate other characters for whatever reason.
|
||||
var/msg = "[src.client.key] ([src]) has changed their communicator identity's name to [new_name]."
|
||||
message_admins(msg)
|
||||
|
||||
+32
-5
@@ -2,21 +2,38 @@
|
||||
mob_list -= src
|
||||
dead_mob_list -= src
|
||||
living_mob_list -= src
|
||||
player_list -= src
|
||||
unset_machine()
|
||||
qdel(hud_used)
|
||||
QDEL_NULL(hud_used)
|
||||
clear_fullscreen()
|
||||
if(client)
|
||||
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
|
||||
qdel(spell_master)
|
||||
remove_screen_obj_references()
|
||||
client.screen = list()
|
||||
client.screen.Cut()
|
||||
if(mind && mind.current == src)
|
||||
spellremove(src)
|
||||
if(!istype(src,/mob/observer)) //CHOMPEdit
|
||||
ghostize() //CHOMPEdit
|
||||
//ChompEDIT start - fix hard qdels
|
||||
QDEL_NULL(plane_holder)
|
||||
..()
|
||||
return QDEL_HINT_HARDDEL_NOW
|
||||
|
||||
if(pulling)
|
||||
stop_pulling() //TG does this on atom/movable but our stop_pulling proc is here so whatever
|
||||
|
||||
previewing_belly = null // from code/modules/vore/eating/mob_ch.dm
|
||||
vore_selected = null // from code/modules/vore/eating/mob_vr
|
||||
|
||||
|
||||
if(mind)
|
||||
if(mind.current == src)
|
||||
mind.current = null
|
||||
if(mind.original == src)
|
||||
mind.original = null
|
||||
|
||||
. = ..()
|
||||
update_client_z(null)
|
||||
//return QDEL_HINT_HARDDEL_NOW
|
||||
|
||||
/mob/proc/remove_screen_obj_references()
|
||||
hands = null
|
||||
@@ -44,7 +61,8 @@
|
||||
set_focus(src) // VOREStation Add - Key Handling
|
||||
hook_vr("mob_new",list(src)) //VOREStation Code
|
||||
update_transform() // Some mobs may start bigger or smaller than normal.
|
||||
return ..()
|
||||
. = ..()
|
||||
//return QDEL_HINT_HARDDEL_NOW Just keep track of mob references. They delete SO much faster now.
|
||||
|
||||
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
|
||||
var/time = say_timestamp()
|
||||
@@ -1210,6 +1228,15 @@
|
||||
var/exploitmsg = html_decode("\n" + "Has " + I.name + ".")
|
||||
exploit_record += exploitmsg
|
||||
|
||||
|
||||
/obj/Destroy()
|
||||
if(istype(src.loc, /mob))
|
||||
var/mob/holder = src.loc
|
||||
if(src in holder.exploit_addons)
|
||||
holder.exploit_addons -= src
|
||||
. = ..()
|
||||
|
||||
|
||||
/client/proc/check_has_body_select()
|
||||
return mob && mob.hud_used && istype(mob.zone_sel, /obj/screen/zone_sel)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
plane_masters[VIS_CH_BACKUP] = new /obj/screen/plane_master{plane = PLANE_CH_BACKUP} //Backup implant status
|
||||
plane_masters[VIS_CH_VANTAG] = new /obj/screen/plane_master{plane = PLANE_CH_VANTAG} //Vore Antags
|
||||
|
||||
plane_masters[VIS_AUGMENTED] = new /obj/screen/plane_master/augmented(my_mob) //Augmented reality
|
||||
plane_masters[VIS_AUGMENTED] = new /obj/screen/plane_master/augmented(M = my_mob) //Augmented reality
|
||||
..()
|
||||
|
||||
/////////////////
|
||||
@@ -15,7 +15,7 @@
|
||||
var/state = FALSE //Saves cost with the lists
|
||||
var/mob/my_mob
|
||||
|
||||
/obj/screen/plane_master/augmented/New(var/mob/M)
|
||||
/obj/screen/plane_master/augmented/New(null, var/mob/M)
|
||||
..()
|
||||
my_mob = M
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
..()
|
||||
|
||||
if(created_for)
|
||||
del_mannequin(created_for)
|
||||
//if(created_for)
|
||||
//del_mannequin(created_for) No need to delete this, honestly. It saves up hardly any memory in the long run and fucks the GC in the short run.
|
||||
|
||||
if(!spawning)//Here so that if they are spawning and log out, the other procs can play out and they will have a mob to come back to.
|
||||
key = null//We null their key before deleting the mob, so they are properly kicked out.
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
verbs |= /mob/proc/insidePanel
|
||||
initialized = TRUE // Explicitly don't use Initialize(). New players join super early and use New()
|
||||
|
||||
|
||||
/mob/new_player/Destroy()
|
||||
if(panel)
|
||||
QDEL_NULL(panel)
|
||||
. = ..()
|
||||
|
||||
/mob/new_player/verb/new_player_panel()
|
||||
set src = usr
|
||||
new_player_panel_proc()
|
||||
@@ -172,11 +178,11 @@
|
||||
if(!client) return 1
|
||||
|
||||
//Make a new mannequin quickly, and allow the observer to take the appearance
|
||||
var/mob/living/carbon/human/dummy/mannequin = new()
|
||||
var/mob/living/carbon/human/dummy/mannequin = get_mannequin(client.ckey)
|
||||
client.prefs.dress_preview_mob(mannequin)
|
||||
var/mob/observer/dead/observer = new(mannequin)
|
||||
observer.moveToNullspace() //Let's not stay in our doomed mannequin
|
||||
qdel(mannequin)
|
||||
//qdel(mannequin)
|
||||
|
||||
spawning = 1
|
||||
if(client.media)
|
||||
|
||||
@@ -177,15 +177,15 @@
|
||||
climb_time += 10 SECONDS
|
||||
if(climbing_delay_min > 1.0)
|
||||
climb_time += 2.5 SECONDS
|
||||
switch(L.nutrition) //Values are 50 lower than the warning icon appearing
|
||||
if(100 to 200)
|
||||
to_chat(L, SPAN_NOTICE("Climbing while [L.isSynthetic() ? "low on power" : "hungry"] slows you down"))
|
||||
climb_time += 1 SECONDS
|
||||
if(nutrition_cost to 100)
|
||||
to_chat(L, SPAN_DANGER("You [L.isSynthetic() ? "lack enough power" : "are too hungry"] to climb safely!"))
|
||||
climb_time +=3 SECONDS
|
||||
if(fall_chance < 30)
|
||||
fall_chance = 30
|
||||
|
||||
if(L.nutrition >= 100 && L.nutrition <= 200)
|
||||
to_chat(L, SPAN_NOTICE("Climbing while [L.isSynthetic() ? "low on power" : "hungry"] slows you down"))
|
||||
climb_time += 1 SECONDS
|
||||
else if(L.nutrition >= nutrition_cost && L.nutrition < 100)
|
||||
to_chat(L, SPAN_DANGER("You [L.isSynthetic() ? "lack enough power" : "are too hungry"] to climb safely!"))
|
||||
climb_time +=3 SECONDS
|
||||
if(fall_chance < 30)
|
||||
fall_chance = 30
|
||||
L.visible_message(message = "<b>[L]</b> begins to climb up on <b>\The [src]</b>", self_message = "You begin to clumb up on <b>\The [src]</b>", \
|
||||
blind_message = "You hear the sounds of climbing!", runemessage = "Tap Tap")
|
||||
var/oops_time = world.time
|
||||
@@ -294,15 +294,14 @@
|
||||
climb_time += 10 SECONDS
|
||||
if(climbing_delay_min > 1.0)
|
||||
climb_time += 2.5 SECONDS
|
||||
switch(nutrition) //Values are 50 lower than the warning icon appearing
|
||||
if(100 to 200)
|
||||
to_chat(src, SPAN_NOTICE("Climbing while [isSynthetic() ? "low on power" : "hungry"] slows you down"))
|
||||
climb_time += 1 SECONDS
|
||||
if(nutrition_cost to 100)
|
||||
to_chat(src, SPAN_DANGER("You [isSynthetic() ? "lack enough power" : "are too hungry"] to climb safely!"))
|
||||
climb_time +=3 SECONDS
|
||||
if(fall_chance < 30)
|
||||
fall_chance = 30
|
||||
if(nutrition >= 100 && nutrition <= 200)
|
||||
to_chat(src, SPAN_NOTICE("Climbing while [isSynthetic() ? "low on power" : "hungry"] slows you down"))
|
||||
climb_time += 1 SECONDS
|
||||
else if(nutrition >= nutrition_cost && nutrition < 100)
|
||||
to_chat(src, SPAN_DANGER("You [isSynthetic() ? "lack enough power" : "are too hungry"] to climb safely!"))
|
||||
climb_time +=3 SECONDS
|
||||
if(fall_chance < 30)
|
||||
fall_chance = 30
|
||||
|
||||
if(!climbing_surface.climbable)
|
||||
to_chat(src, SPAN_DANGER("\The [climbing_surface] is not suitable for climbing! Even for a master climber, this is risky!"))
|
||||
|
||||
@@ -387,7 +387,7 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable
|
||||
|
||||
last_notification = message // TGUI Hook
|
||||
|
||||
to_chat(human,"<span class='filter_nif'><b>\[\icon[src.big_icon][bicon(src.big_icon)]NIF\]</b> displays, \"<span class='[alert ? "danger" : "notice"]'>[message]</span>\"</span>")
|
||||
to_chat(human,"<span class='filter_nif'><b>\[[icon2html(src.big_icon, human.client)]NIF\]</b> displays, \"<span class='[alert ? "danger" : "notice"]'>[message]</span>\"</span>")
|
||||
if(prob(1)) human.visible_message("<span class='notice'>\The [human] [pick(look_messages)].</span>")
|
||||
if(alert)
|
||||
human << bad_sound
|
||||
|
||||
@@ -74,13 +74,13 @@
|
||||
|
||||
to_chat(nif.human,
|
||||
type = MESSAGE_TYPE_NIF,
|
||||
html = "<span class='nif'><b>\[\icon[nif.big_icon][bicon(nif.big_icon)]NIF\]</b> <b>Soulcatcher</b> displays, \"<span class='notice nif'>[message]</span>\"</span>")
|
||||
html = "<span class='nif'><b>\[[icon2html(nif.big_icon, nif.human)]NIF\]</b> <b>Soulcatcher</b> displays, \"<span class='notice nif'>[message]</span>\"</span>")
|
||||
nif.human << sound
|
||||
|
||||
for(var/mob/living/carbon/brain/caught_soul/CS as anything in brainmobs)
|
||||
to_chat(CS,
|
||||
type = MESSAGE_TYPE_NIF,
|
||||
html = "<span class='nif'><b>\[\icon[nif.big_icon][bicon(nif.big_icon)]NIF\]</b> <b>Soulcatcher</b> displays, \"<span class='notice nif'>[message]</span>\"</span>")
|
||||
html = "<span class='nif'><b>\[[icon2html(nif.big_icon, CS.client)]NIF\]</b> <b>Soulcatcher</b> displays, \"<span class='notice nif'>[message]</span>\"</span>")
|
||||
CS << sound
|
||||
|
||||
/datum/nifsoft/soulcatcher/proc/say_into(var/message, var/mob/living/sender, var/mob/eyeobj)
|
||||
@@ -94,11 +94,11 @@
|
||||
else
|
||||
to_chat(nif.human,
|
||||
type = MESSAGE_TYPE_NIF,
|
||||
html = "<span class='nif'><b>\[\icon[nif.big_icon][bicon(nif.big_icon)]NIF\]</b> <b>[sender_name]</b> speaks, \"[message]\"</span>")
|
||||
html = "<span class='nif'><b>\[[icon2html(nif.big_icon, nif.human.client)]NIF\]</b> <b>[sender_name]</b> speaks, \"[message]\"</span>")
|
||||
for(var/mob/living/carbon/brain/caught_soul/CS as anything in brainmobs)
|
||||
to_chat(CS,
|
||||
type = MESSAGE_TYPE_NIF,
|
||||
html = "<span class='nif'><b>\[\icon[nif.big_icon][bicon(nif.big_icon)]NIF\]</b> <b>[sender_name]</b> speaks, \"[message]\"</span>")
|
||||
html = "<span class='nif'><b>\[[icon2html(nif.big_icon, CS.client)]NIF\]</b> <b>[sender_name]</b> speaks, \"[message]\"</span>")
|
||||
|
||||
log_nsay(message,nif.human.real_name,sender)
|
||||
|
||||
@@ -113,11 +113,11 @@
|
||||
else
|
||||
to_chat(nif.human,
|
||||
type = MESSAGE_TYPE_NIF,
|
||||
html = "<span class='nif'><b>\[\icon[nif.big_icon][bicon(nif.big_icon)]NIF\]</b> <b>[sender_name]</b> [message]</span>")
|
||||
html = "<span class='nif'><b>\[[icon2html(nif.big_icon,nif.human.client)]NIF\]</b> <b>[sender_name]</b> [message]</span>")
|
||||
for(var/mob/living/carbon/brain/caught_soul/CS as anything in brainmobs)
|
||||
to_chat(CS,
|
||||
type = MESSAGE_TYPE_NIF,
|
||||
html = "<span class='nif'><b>\[\icon[nif.big_icon][bicon(nif.big_icon)]NIF\]</b> <b>[sender_name]</b> [message]</span>")
|
||||
html = "<span class='nif'><b>\[[icon2html(nif.big_icon,CS.client)]NIF\]</b> <b>[sender_name]</b> [message]</span>")
|
||||
|
||||
log_nme(message,nif.human.real_name,sender)
|
||||
|
||||
@@ -427,7 +427,7 @@
|
||||
real_name = brainmob.real_name //And the OTHER name
|
||||
|
||||
forceMove(get_turf(parent_human))
|
||||
GLOB.moved_event.register(parent_human, src, /mob/observer/eye/ar_soul/proc/human_moved)
|
||||
RegisterSignal(parent_human, COMSIG_OBSERVER_MOVED, /mob/observer/eye/ar_soul/proc/human_moved)
|
||||
|
||||
//Time to play dressup
|
||||
if(brainmob.client.prefs)
|
||||
@@ -442,7 +442,7 @@
|
||||
|
||||
/mob/observer/eye/ar_soul/Destroy()
|
||||
if(parent_human) //It's POSSIBLE they've been deleted before the NIF somehow
|
||||
GLOB.moved_event.unregister(parent_human, src)
|
||||
UnregisterSignal(parent_human, COMSIG_OBSERVER_MOVED)
|
||||
parent_human = null
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
var/message = combined["formatted"]
|
||||
var/name_used = M.GetVoice()
|
||||
var/rendered = null
|
||||
rendered = "<span class='game say'>\icon[icon_object][bicon(icon_object)] <span class='name'>[name_used]</span> [message]</span>"
|
||||
rendered = "<span class='game say'>[icon2html(icon_object,mob.client)] <span class='name'>[name_used]</span> [message]</span>"
|
||||
mob.show_message(rendered, 2)
|
||||
|
||||
//Not supported by the internal one
|
||||
|
||||
@@ -88,16 +88,21 @@
|
||||
|
||||
if(parent && parent.children)
|
||||
parent.children -= src
|
||||
parent = null
|
||||
|
||||
if(children)
|
||||
for(var/obj/item/organ/external/C in children)
|
||||
children -= C
|
||||
C.parent = null
|
||||
qdel(C)
|
||||
|
||||
if(internal_organs)
|
||||
for(var/obj/item/organ/O in internal_organs)
|
||||
internal_organs -= O
|
||||
qdel(O)
|
||||
|
||||
if(splinted && splinted.loc == src)
|
||||
splinted.loc = null
|
||||
qdel(splinted)
|
||||
splinted = null
|
||||
|
||||
|
||||
@@ -55,9 +55,9 @@
|
||||
middle = M
|
||||
back = B
|
||||
if(is_valid_setup())
|
||||
GLOB.destroyed_event.register(F, src, PROC_REF(release_links))
|
||||
GLOB.destroyed_event.register(M, src, PROC_REF(release_links))
|
||||
GLOB.destroyed_event.register(B, src, PROC_REF(release_links))
|
||||
RegisterSignal(F, COMSIG_OBSERVER_DESTROYED, PROC_REF(release_links))
|
||||
RegisterSignal(M, COMSIG_OBSERVER_DESTROYED, PROC_REF(release_links))
|
||||
RegisterSignal(B, COMSIG_OBSERVER_DESTROYED, PROC_REF(release_links))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -69,9 +69,9 @@
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/ship/disperser/proc/release_links()
|
||||
GLOB.destroyed_event.unregister(front, src, PROC_REF(release_links))
|
||||
GLOB.destroyed_event.unregister(middle, src, PROC_REF(release_links))
|
||||
GLOB.destroyed_event.unregister(back, src, PROC_REF(release_links))
|
||||
UnregisterSignal(front, COMSIG_OBSERVER_DESTROYED)
|
||||
UnregisterSignal(middle, COMSIG_OBSERVER_DESTROYED)
|
||||
UnregisterSignal(back, COMSIG_OBSERVER_DESTROYED)
|
||||
front = null
|
||||
middle = null
|
||||
back = null
|
||||
|
||||
@@ -77,7 +77,7 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
|
||||
L.looking_elsewhere = 1
|
||||
L.handle_vision()
|
||||
user.set_viewsize(world.view + extra_view)
|
||||
GLOB.moved_event.register(user, src, /obj/machinery/computer/ship/proc/unlook)
|
||||
RegisterSignal(user, COMSIG_OBSERVER_MOVED, /obj/machinery/computer/ship/proc/unlook, override = TRUE) //This needs override or else it will spam runtimes because it is called repeatedly.
|
||||
// TODO GLOB.stat_set_event.register(user, src, /obj/machinery/computer/ship/proc/unlook)
|
||||
LAZYDISTINCTADD(viewers, WEAKREF(user))
|
||||
|
||||
@@ -90,7 +90,7 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
|
||||
L.looking_elsewhere = 0
|
||||
L.handle_vision()
|
||||
user.set_viewsize() // reset to default
|
||||
GLOB.moved_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook)
|
||||
UnregisterSignal(user, COMSIG_OBSERVER_MOVED)
|
||||
// TODO GLOB.stat_set_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook)
|
||||
LAZYREMOVE(viewers, WEAKREF(user))
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
icon_state = "shuttle_nosprite"
|
||||
|
||||
/obj/effect/overmap/visitable/ship/landable/Destroy()
|
||||
GLOB.shuttle_pre_move_event.unregister(SSshuttles.shuttles[shuttle], src)
|
||||
GLOB.shuttle_moved_event.unregister(SSshuttles.shuttles[shuttle], src)
|
||||
UnregisterSignal(SSshuttles.shuttles[shuttle], COMSIG_OBSERVER_SHUTTLE_PRE_MOVE)
|
||||
UnregisterSignal(SSshuttles.shuttles[shuttle], COMSIG_OBSERVER_SHUTTLE_MOVED)
|
||||
return ..()
|
||||
|
||||
/obj/effect/overmap/visitable/ship/landable/can_burn()
|
||||
@@ -71,8 +71,8 @@
|
||||
if(istype(shuttle_datum,/datum/shuttle/autodock/overmap))
|
||||
var/datum/shuttle/autodock/overmap/oms = shuttle_datum
|
||||
oms.myship = src
|
||||
GLOB.shuttle_pre_move_event.register(shuttle_datum, src, PROC_REF(pre_shuttle_jump))
|
||||
GLOB.shuttle_moved_event.register(shuttle_datum, src, PROC_REF(on_shuttle_jump))
|
||||
RegisterSignal(shuttle_datum, COMSIG_OBSERVER_SHUTTLE_PRE_MOVE, PROC_REF(pre_shuttle_jump))
|
||||
RegisterSignal(shuttle_datum, COMSIG_OBSERVER_SHUTTLE_MOVED, PROC_REF(on_shuttle_jump))
|
||||
on_landing(landmark, shuttle_datum.current_location) // We "land" at round start to properly place ourselves on the overmap.
|
||||
|
||||
|
||||
@@ -123,11 +123,11 @@
|
||||
core_landmark = master
|
||||
name = _name
|
||||
landmark_tag = master.shuttle_name + _name
|
||||
GLOB.destroyed_event.register(master, src, /datum/proc/qdel_self)
|
||||
RegisterSignal(master, COMSIG_OBSERVER_DESTROYED, /datum/proc/qdel_self)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/shuttle_landmark/visiting_shuttle/Destroy()
|
||||
GLOB.destroyed_event.unregister(core_landmark, src)
|
||||
UnregisterSignal(core_landmark, COMSIG_OBSERVER_DESTROYED)
|
||||
LAZYREMOVE(core_landmark.visitors, src)
|
||||
core_landmark = null
|
||||
. = ..()
|
||||
@@ -144,11 +144,11 @@
|
||||
|
||||
/obj/effect/shuttle_landmark/visiting_shuttle/shuttle_arrived(datum/shuttle/shuttle)
|
||||
LAZYSET(core_landmark.visitors, src, shuttle)
|
||||
GLOB.shuttle_moved_event.register(shuttle, src, PROC_REF(shuttle_left))
|
||||
RegisterSignal(shuttle, COMSIG_OBSERVER_SHUTTLE_MOVED, PROC_REF(shuttle_left))
|
||||
|
||||
/obj/effect/shuttle_landmark/visiting_shuttle/proc/shuttle_left(datum/shuttle/shuttle, obj/effect/shuttle_landmark/old_landmark, obj/effect/shuttle_landmark/new_landmark)
|
||||
if(old_landmark == src)
|
||||
GLOB.shuttle_moved_event.unregister(shuttle, src)
|
||||
UnregisterSignal(shuttle, COMSIG_OBSERVER_SHUTTLE_MOVED)
|
||||
LAZYREMOVE(core_landmark.visitors, src)
|
||||
|
||||
//
|
||||
@@ -160,7 +160,7 @@
|
||||
return
|
||||
if(into == landmark)
|
||||
setup_overmap_location() // They're coming boys, better actually exist!
|
||||
GLOB.shuttle_pre_move_event.unregister(SSshuttles.shuttles[shuttle], src)
|
||||
UnregisterSignal(SSshuttles.shuttles[shuttle], COMSIG_OBSERVER_SHUTTLE_PRE_MOVE)
|
||||
|
||||
/obj/effect/overmap/visitable/ship/landable/proc/on_shuttle_jump(datum/shuttle/given_shuttle, obj/effect/shuttle_landmark/from, obj/effect/shuttle_landmark/into)
|
||||
if(given_shuttle != SSshuttles.shuttles[shuttle])
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
|
||||
/obj/item/weapon/paper/sticky/Initialize()
|
||||
. = ..()
|
||||
GLOB.moved_event.register(src, src, /obj/item/weapon/paper/sticky/proc/reset_persistence_tracking)
|
||||
RegisterSignal(src, COMSIG_OBSERVER_MOVED, /obj/item/weapon/paper/sticky/proc/reset_persistence_tracking)
|
||||
|
||||
/obj/item/weapon/paper/sticky/proc/reset_persistence_tracking()
|
||||
SSpersistence.forget_value(src, /datum/persistent/paper/sticky)
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
/obj/item/weapon/paper/sticky/Destroy()
|
||||
reset_persistence_tracking()
|
||||
GLOB.moved_event.unregister(src, src)
|
||||
UnregisterSignal(src, COMSIG_OBSERVER_MOVED)
|
||||
. = ..()
|
||||
|
||||
/obj/item/weapon/paper/sticky/update_icon()
|
||||
@@ -149,4 +149,4 @@
|
||||
if(dir_offset & NORTH)
|
||||
pixel_y += 32
|
||||
else if(dir_offset & SOUTH)
|
||||
pixel_y -= 32
|
||||
pixel_y -= 32
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
L = get(pda, /mob/living/silicon)
|
||||
|
||||
if(L)
|
||||
to_chat(L, "\icon[pda][bicon(pda)] [message]")
|
||||
to_chat(L, "[icon2html(pda,L.client)] [message]")
|
||||
SStgui.update_user_uis(L, pda) // Update the receiving user's PDA UI so that they can see the new message
|
||||
|
||||
if(!notify_silent)
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
|
||||
SStgui.update_user_uis(U, P) // Update the sending user's PDA UI so that they can see the new message
|
||||
log_pda("(PDA: [src.name]) sent \"[t]\" to [P.name]", usr)
|
||||
to_chat(U, "\icon[pda][bicon(pda)] <b>Sent message to [P.owner] ([P.ownjob]), </b>\"[t]\"")
|
||||
to_chat(U, "[icon2html(pda,U.client)] <b>Sent message to [P.owner] ([P.ownjob]), </b>\"[t]\"")
|
||||
else
|
||||
to_chat(U, "<span class='notice'>ERROR: Messaging server is not responding.</span>")
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
S = 'sound/machines/twobeep.ogg'
|
||||
playsound(loc, S, 50, 1)
|
||||
for(var/mob/O in hearers(3, loc))
|
||||
O.show_message(text("\icon[src][bicon(src)] *[ttone]*"))
|
||||
O.show_message(text("[icon2html(src, O.client)] *[ttone]*"))
|
||||
|
||||
/obj/item/device/pda/proc/set_ringtone()
|
||||
var/t = tgui_input_text(usr, "Please enter new ringtone", name, ttone)
|
||||
|
||||
@@ -542,7 +542,7 @@
|
||||
return 2
|
||||
//just assume we can shoot through glass and stuff. No big deal, the player can just choose to not target someone
|
||||
//on the other side of a window if it makes a difference. Or if they run behind a window, too bad.
|
||||
if(check_trajectory(target, user))
|
||||
if(target in check_trajectory(target, user))
|
||||
return 1 // Magic numbers are fun.
|
||||
|
||||
//called if there was no projectile to shoot
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
var/ricochets_max = 2
|
||||
var/ricochet_chance = 30
|
||||
var/can_miss = TRUE
|
||||
var/bump_targets = TRUE //Should we bump and/or attack objects we hit? Used only for 'raytraces' e.g. subtype /test
|
||||
|
||||
//Hitscan
|
||||
var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored.
|
||||
@@ -145,6 +146,14 @@
|
||||
var/hud_state = "unknown" // What HUD state we use when we have ammunition.
|
||||
var/hud_state_empty = "unknown" // The empty state. DON'T USE _FLASH IN THE NAME OF THE EMPTY STATE STRING, THAT IS ADDED BY THE CODE.
|
||||
|
||||
var/obj/item/ammo_casing/my_case = null
|
||||
|
||||
|
||||
/obj/item/projectile/New()
|
||||
if(istype(loc, /obj/item/ammo_casing))
|
||||
my_case = loc
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/proc/Range()
|
||||
range--
|
||||
if(range <= 0 && loc)
|
||||
@@ -231,7 +240,7 @@
|
||||
after_move()
|
||||
if(can_hit_target(original, permutated))
|
||||
Bump(original)
|
||||
if(!hitscanning && !forcemoved)
|
||||
if(!hitscanning && !forcemoved && trajectory)
|
||||
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier * SSprojectiles.global_iterations_per_move
|
||||
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier * SSprojectiles.global_iterations_per_move
|
||||
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
|
||||
@@ -320,7 +329,8 @@
|
||||
/obj/item/projectile/proc/fire(angle, atom/direct_target)
|
||||
//If no angle needs to resolve it from xo/yo!
|
||||
if(direct_target)
|
||||
direct_target.bullet_act(src, def_zone)
|
||||
if(bump_targets)
|
||||
direct_target.bullet_act(src, def_zone)
|
||||
qdel(src)
|
||||
return
|
||||
if(isnum(angle))
|
||||
@@ -459,7 +469,16 @@
|
||||
impacted_mobs.Cut()
|
||||
impacted_mobs = null
|
||||
|
||||
qdel(trajectory)
|
||||
trajectory = null
|
||||
beam_index = null
|
||||
beam_components = null
|
||||
|
||||
|
||||
if(my_case)
|
||||
if(my_case.BB == src)
|
||||
my_case.BB = null
|
||||
my_case = null
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/proc/cleanup_beam_segments()
|
||||
@@ -565,25 +584,31 @@
|
||||
var/shield_chance = min(80, (30 * (M.mob_size / 10))) //Small mobs have a harder time keeping a dead body as a shield than a human-sized one. Unathi would have an easier job, if they are made to be SIZE_LARGE in the future. -Mech
|
||||
if(prob(shield_chance))
|
||||
visible_message("<span class='danger'>\The [M] uses [G.affecting] as a shield!</span>")
|
||||
if(Bump(G.affecting))
|
||||
return
|
||||
if(bump_targets)
|
||||
if(Bump(G.affecting))
|
||||
return
|
||||
else
|
||||
visible_message("<span class='danger'>\The [M] tries to use [G.affecting] as a shield, but fails!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>\The [M] uses [G.affecting] as a shield!</span>")
|
||||
if(Bump(G.affecting))
|
||||
return //If Bump() returns 0 (keep going) then we continue on to attack M.
|
||||
if(bump_targets)
|
||||
if(Bump(G.affecting))
|
||||
return //If Bump() returns 0 (keep going) then we continue on to attack M.
|
||||
|
||||
passthrough = !attack_mob(M, distance)
|
||||
if(bump_targets)
|
||||
passthrough = !attack_mob(M, distance)
|
||||
else
|
||||
passthrough = 1 //Projectiles that don't bump (raytraces) always pass through
|
||||
else
|
||||
passthrough = 1 //so ghosts don't stop bullets
|
||||
else
|
||||
passthrough = (A.bullet_act(src, def_zone) == PROJECTILE_CONTINUE) //backwards compatibility
|
||||
if(isturf(A))
|
||||
for(var/obj/O in A)
|
||||
O.bullet_act(src)
|
||||
for(var/mob/living/M in A)
|
||||
attack_mob(M, distance)
|
||||
if(bump_targets) // only attack/act a turf's contents if our projectile is not a raytrace
|
||||
if(isturf(A))
|
||||
for(var/obj/O in A)
|
||||
O.bullet_act(src)
|
||||
for(var/mob/living/M in A)
|
||||
attack_mob(M, distance)
|
||||
|
||||
//penetrating projectiles can pass through things that otherwise would not let them
|
||||
if(!passthrough && penetrating > 0)
|
||||
@@ -606,7 +631,7 @@
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
return FALSE
|
||||
|
||||
if(A)
|
||||
if(A && bump_targets)
|
||||
on_impact(A)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
@@ -649,7 +674,9 @@
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/proc/check_fire(atom/target as mob, mob/living/user as mob) //Checks if you can hit them or not.
|
||||
check_trajectory(target, user, pass_flags, flags)
|
||||
if(target in check_trajectory(target, user, pass_flags, flags))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/projectile/CanPass()
|
||||
return TRUE
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
return trace.launch_projectile(target) //Test it!
|
||||
|
||||
/obj/item/projectile/proc/_check_fire(atom/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not.
|
||||
check_trajectory(target, user, pass_flags, flags)
|
||||
if(target in check_trajectory(target, user, pass_flags, flags))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//"Tracing" projectile
|
||||
/obj/item/projectile/test //Used to see if you can hit them.
|
||||
@@ -22,6 +24,7 @@
|
||||
hitscan = TRUE
|
||||
nodamage = TRUE
|
||||
damage = 0
|
||||
bump_targets = FALSE
|
||||
var/list/hit = list()
|
||||
|
||||
/obj/item/projectile/test/process_hitscan()
|
||||
@@ -33,7 +36,24 @@
|
||||
/obj/item/projectile/test/Bump(atom/A)
|
||||
if(A != src)
|
||||
hit |= A
|
||||
if(isturf(A))
|
||||
for(var/obj/O in A)
|
||||
hit |= A
|
||||
for(var/mob/living/M in A)
|
||||
hit |= A
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/test/fire(angle, atom/direct_target)
|
||||
. = ..()
|
||||
if(direct_target)
|
||||
if(direct_target != src)
|
||||
hit |= direct_target
|
||||
. = hit
|
||||
|
||||
|
||||
/obj/item/projectile/test/attack_mob()
|
||||
return
|
||||
|
||||
//Don't generate tracers - they are generated on Destroy()
|
||||
/obj/item/projectile/test/finalize_hitscan_and_generate_tracers()
|
||||
return
|
||||
|
||||
@@ -31,4 +31,4 @@
|
||||
metabolism_speed = 0.5
|
||||
|
||||
/datum/reagents/metabolism/touch
|
||||
metabolism_class = CHEM_TOUCH
|
||||
metabolism_class = CHEM_TOUCH
|
||||
|
||||
@@ -119,10 +119,10 @@
|
||||
var/list/seen = viewers(4, T)
|
||||
for(var/mob/M in seen)
|
||||
if(M.client)
|
||||
M.show_message("<span class='notice'>\icon[container][bicon(container)] [mix_message]</span>", 1)
|
||||
M.show_message("<span class='notice'>[icon2html(container,M.client)] [mix_message]</span>", 1)
|
||||
playsound(T, reaction_sound, 80, 1)
|
||||
|
||||
//obtains any special data that will be provided to the reaction products
|
||||
//this is called just before reactants are removed.
|
||||
/decl/chemical_reaction/proc/send_data(var/datum/reagents/holder, var/reaction_limit)
|
||||
return null
|
||||
return null
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user