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:
Cadyn
2024-02-27 11:17:32 -08:00
committed by GitHub
parent 96a43a09c1
commit b90f7ec922
254 changed files with 2135 additions and 1576 deletions
+1 -1
View File
@@ -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)
+8 -2
View File
@@ -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()
+3 -3
View File
@@ -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
+4
View File
@@ -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
+1 -1
View File
@@ -134,4 +134,4 @@
emote_hear = list("hisses")
/datum/say_list/crab
emote_hear = list("hisses")
emote_hear = list("hisses")
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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()
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+3 -3
View File
@@ -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
-110
View File
@@ -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))]"
+7 -17
View 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
+45 -14
View File
@@ -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
+404 -36
View File
@@ -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
+10 -15
View File
@@ -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
+4
View File
@@ -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')
+2 -1
View File
@@ -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',
)
+3 -1
View File
@@ -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"),
)
+37
View File
@@ -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>
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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))
+2 -1
View File
@@ -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))
+2 -2
View File
@@ -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"]."
+9 -8
View File
@@ -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
View File
@@ -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))
+21 -21
View File
@@ -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?
+22 -22
View File
@@ -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()
+17 -17
View File
@@ -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()
+1 -1
View File
@@ -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))
+2 -2
View File
@@ -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()
. = ..()
+2 -2
View File
@@ -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()
. = ..()
+8 -7
View File
@@ -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")
+2 -2
View File
@@ -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()
. = ..()
+2 -2
View File
@@ -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()
. = ..()
+2 -2
View File
@@ -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()
. = ..()
+2 -2
View File
@@ -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()
. = ..()
+2 -2
View File
@@ -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()
+1 -1
View File
@@ -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)
+7 -7
View File
@@ -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"
+5 -5
View File
@@ -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
+13 -13
View File
@@ -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()
+2 -2
View File
@@ -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()
+2 -2
View File
@@ -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>")
+1 -1
View File
@@ -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))
+4 -4
View File
@@ -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
+4 -6
View File
@@ -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()
+31 -31
View File
@@ -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()
+5 -10
View File
@@ -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)
+14 -15
View File
@@ -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 ..()
+1 -1
View File
@@ -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
View File
@@ -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)
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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.
+8 -2
View File
@@ -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)
+17 -18
View File
@@ -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!"))
+1 -1
View File
@@ -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 ..()
+1 -1
View File
@@ -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
+5
View File
@@ -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
+2 -2
View File
@@ -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))
+9 -9
View File
@@ -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])
+3 -3
View File
@@ -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
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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>")
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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
+42 -15
View File
@@ -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
+21 -1
View File
@@ -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