diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03d42b2638..370a5c01fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: run: | sudo dpkg --add-architecture i386 sudo apt update || true - sudo apt install zlib1g-dev:i386 libssl-dev:i386 + sudo apt install zlib1g-dev:i386 ldd librust_g.so ldd libbapi_dmm_reader.so ldd libverdigris.so diff --git a/Dockerfile b/Dockerfile index e143dd1d9c..ccdf7188d5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,79 +1,79 @@ -FROM i386/ubuntu:xenial as base +FROM ubuntu:22.04 AS base -ARG BYOND_MAJOR=514 -ARG BYOND_MINOR=1589 +RUN dpkg --add-architecture i386 \ + && apt-get update \ + && apt-get upgrade -y \ + && apt-get dist-upgrade -y \ + && apt-get install -y --no-install-recommends \ + ca-certificates -RUN apt-get update \ - && apt-get install -y \ - curl \ - unzip \ - make \ - libstdc++6 \ - && curl "https://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip \ - && unzip byond.zip \ - && cd byond \ - && sed -i 's|install:|&\n\tmkdir -p $(MAN_DIR)/man6|' Makefile \ - && make install \ - && chmod 644 /usr/local/byond/man/man6/* \ - && apt-get purge -y --auto-remove curl unzip make \ - && cd .. \ - && rm -rf byond byond.zip /var/lib/apt/lists/* - -FROM base as rust_g - -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - git \ - ca-certificates - -WORKDIR /rust_g +FROM base AS byond +WORKDIR /byond RUN apt-get install -y --no-install-recommends \ - libssl-dev \ - pkg-config \ - curl \ - gcc-multilib \ - && curl https://sh.rustup.rs -sSf | sh -s -- -y --default-host i686-unknown-linux-gnu \ - && git init \ - && git remote add origin https://github.com/VOREStation/rust-g + curl \ + unzip \ + make \ + libstdc++6:i386 -COPY _build_dependencies.sh . +COPY dependencies.sh . -RUN /bin/bash -c "source _build_dependencies.sh \ - && git fetch --depth 1 origin \$RUST_G_VERSION" \ - && git checkout FETCH_HEAD \ - && ~/.cargo/bin/cargo build --release +RUN . ./dependencies.sh \ + && curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip \ + && unzip byond.zip \ + && cd byond \ + && sed -i 's|install:|&\n\tmkdir -p $(MAN_DIR)/man6|' Makefile \ + && make install \ + && chmod 644 /usr/local/byond/man/man6/* \ + && apt-get purge -y --auto-remove curl unzip make \ + && cd .. \ + && rm -rf byond byond.zip -FROM base as dm_base +FROM byond AS build WORKDIR /vorestation -FROM dm_base as build +RUN apt-get install -y --no-install-recommends \ + curl COPY . . -RUN DreamMaker -max_errors 0 vorestation.dme +RUN env TG_BOOTSTRAP_NODE_LINUX=1 tools/build/build -FROM dm_base +FROM base AS rust +RUN apt-get install -y --no-install-recommends \ + curl && \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal \ + && ~/.cargo/bin/rustup target add i686-unknown-linux-gnu -EXPOSE 2303 +FROM rust AS rust_g +WORKDIR /rust_g -RUN apt-get update \ - && apt-get install -y --no-install-recommends software-properties-common \ - && add-apt-repository ppa:ubuntu-toolchain-r/test \ - && apt-get update \ - && apt-get upgrade -y \ - && apt-get dist-upgrade -y \ - && apt-get install -y --no-install-recommends \ - libmariadb2 \ - mariadb-client \ - libssl1.0.0 \ - && rm -rf /var/lib/apt/lists/* \ - && mkdir -p /root/.byond/bin +RUN apt-get install -y --no-install-recommends \ + libssl3 \ + gcc-multilib \ + git \ + && git init \ + && git remote add origin https://github.com/tgstation/rust-g + +COPY dependencies.sh . + +RUN . ./dependencies.sh \ + && git fetch --depth 1 origin "${RUST_G_VERSION}" \ + && git checkout FETCH_HEAD \ + && env PKG_CONFIG_ALLOW_CROSS=1 ~/.cargo/bin/cargo build --release --target i686-unknown-linux-gnu --features all + +FROM byond +WORKDIR /vorestation + +RUN apt-get install -y --no-install-recommends \ + libssl3 \ + zlib1g:i386 COPY --from=build /vorestation/ ./ -COPY --from=rust_g /rust_g/target/release/librust_g.so ./librust_g.so +COPY --from=rust_g /rust_g/target/i686-unknown-linux-gnu/release/librust_g.so ./librust_g.so #VOLUME [ "/vorestation/config", "/vorestation/data" ] ENTRYPOINT [ "DreamDaemon", "vorestation.dmb", "-port", "2303", "-trusted", "-close", "-verbose" ] +EXPOSE 2303 diff --git a/_build_dependencies.sh b/_build_dependencies.sh deleted file mode 100644 index 7902bb3ca5..0000000000 --- a/_build_dependencies.sh +++ /dev/null @@ -1,11 +0,0 @@ -# This file has all the information on what versions of libraries are thrown into the code -# For dreamchecker -export SPACEMAN_DMM_VERSION=suite-1.8 -# For NanoUI + TGUI -export NODE_VERSION=20 -# Byond Major -export BYOND_MAJOR=515 -# Byond Minor -export BYOND_MINOR=1642 -# Macro Count -export MACRO_COUNT=9 # YW EDIT FIXTHIS diff --git a/code/__defines/assets.dm b/code/__defines/assets.dm new file mode 100644 index 0000000000..bec54e1e54 --- /dev/null +++ b/code/__defines/assets.dm @@ -0,0 +1,16 @@ +#define ASSET_CROSS_ROUND_CACHE_DIRECTORY "data/spritesheets/legacy_cache" +#define ASSET_CROSS_ROUND_SMART_CACHE_DIRECTORY "data/spritesheets/smart_cache" + +/// When sending mutiple assets, how many before we give the client a quaint little sending resources message +#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8 + +/// How many assets can be sent at once during legacy asset transport +#define SLOW_ASSET_SEND_RATE 6 + +/// Constructs a universal icon. This is done in the same manner as the icon() BYOND proc. +/// "color" will not do anything if a transform is provided. Blend it yourself or use color_transform(). +/// Do note that transforms are NOT COPIED, and are internally lists. So take care not to re-use transforms. +/// This is a DEFINE for performance reasons. +/// Parameters (in order): +/// icon_file, icon_state, dir, frame, transform, color +#define uni_icon(I, icon_state, rest...) new /datum/universal_icon(I, icon_state, ##rest) diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm index fff94f906e..f56b590be9 100644 --- a/code/__defines/is_helpers.dm +++ b/code/__defines/is_helpers.dm @@ -71,3 +71,6 @@ // Diveable water #define isdiveablewater(A) istype(A, /turf/simulated/floor/water/deep/ocean/diving) + +/// NaN isn't a number, damn it. Infinity is a problem too. +#define isnum_safe(x) ( isnum((x)) && !isnan((x)) && !isinf((x)) ) diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index b6b6cffd65..790d8dcf4a 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -379,6 +379,14 @@ #define STRUCTURE_MIN_DAMAGE_THRESHOLD 5 //Vision flags, for dealing with plane visibility +/// AS A SIDE NOTE, PLEASE PLEASE PLEASE PLEASE PLEASE PLEAS PLEASE PLEASE PLEASE for the LOVE OF ALL THAT IS HOLY +/// IF YOU ARE ADDING MORE VISION PLANES, ADD THEM IN HERE. DO NOT ADD THEM TO A _VR FILE. DO NOT ADD THEM TO A _CH FILE. DON'T ADD THEM TO A _VFX FILE. +/// ADD. THEM. HERE. YES, YOU CAN OVERRIDE THE VIS_COUNT IN ANOTHER FILE AND ADD A NEW DEFINE THERE AS WELL, BUT IT WILL LEAD TO +/// HEADACHES AND SUFFERING LATER DOWN THE LINE WHEN SOMEONE ADDS A NEW VISION LAYER HERE AND IT CONFLICTS WITH ONE IN ANOTHER FILE +/// AND EVERYONE SCRATCHES THEIR HEAD AND GOES "WHY IS THIS SUDDENLY BROKE" +/// AND THEN SOMEONE HAD TO DIG THROUGH VISION, PLANE, AND LAYER CODE. THEY WILL NOT BE HAPPY. +/// SO PLEASE, ADD THEM H E R E +/// Thank you :) #define VIS_FULLBRIGHT 1 #define VIS_LIGHTING 2 #define VIS_O_LIGHT 3 @@ -416,7 +424,16 @@ #define VIS_STATUS 28 -#define VIS_COUNT 28 //Must be highest number from above. +#define VIS_CH_STATUS_R 29 +#define VIS_CH_HEALTH_VR 30 +#define VIS_CH_BACKUP 31 +#define VIS_CH_VANTAG 32 + +#define VIS_AUGMENTED 33 + +#define VIS_CH_STOMACH 34 + +#define VIS_COUNT 34 //Must be highest number from above. //Some mob icon layering defines #define BODY_LAYER -100 diff --git a/code/__defines/mobs_vr.dm b/code/__defines/mobs_vr.dm index 1d6ecb049d..af0eddf426 100644 --- a/code/__defines/mobs_vr.dm +++ b/code/__defines/mobs_vr.dm @@ -1,16 +1,3 @@ -#undef VIS_COUNT - -#define VIS_CH_STATUS_R 28 -#define VIS_CH_HEALTH_VR 29 -#define VIS_CH_BACKUP 30 -#define VIS_CH_VANTAG 31 - -#define VIS_AUGMENTED 32 - -#define VIS_CH_STOMACH 33 - -#define VIS_COUNT 33 - //Protean organs #define O_ORCH "orchestrator" #define O_FACT "refactory" diff --git a/code/_helpers/_lists.dm b/code/_helpers/_lists.dm index b71b20e037..babe0b58d2 100644 --- a/code/_helpers/_lists.dm +++ b/code/_helpers/_lists.dm @@ -960,3 +960,18 @@ var/global/list/json_cache = list() return_list += bit return return_list + +/// A version of deep_copy_list that actually supports associative list nesting: list(list(list("a" = "b"))) will actually copy correctly. +/proc/deep_copy_list_alt(list/inserted_list) + if(!islist(inserted_list)) + return inserted_list + var/copied_list = inserted_list.Copy() + . = copied_list + for(var/key_or_value in inserted_list) + if(isnum_safe(key_or_value) || !inserted_list[key_or_value]) + continue + var/value = inserted_list[key_or_value] + var/new_value = value + if(islist(value)) + new_value = deep_copy_list_alt(value) + copied_list[key_or_value] = new_value diff --git a/code/controllers/configuration/entries/resources.dm b/code/controllers/configuration/entries/resources.dm index 475cb8ca70..8623f4d75c 100644 --- a/code/controllers/configuration/entries/resources.dm +++ b/code/controllers/configuration/entries/resources.dm @@ -8,4 +8,6 @@ /datum/config_entry/flag/cache_assets +/datum/config_entry/flag/smart_cache_assets + /datum/config_entry/flag/save_spritesheets diff --git a/code/controllers/subsystems/asset_loading.dm b/code/controllers/subsystems/asset_loading.dm index 2d2939de4b..ecdf406894 100644 --- a/code/controllers/subsystems/asset_loading.dm +++ b/code/controllers/subsystems/asset_loading.dm @@ -7,6 +7,7 @@ SUBSYSTEM_DEF(asset_loading) flags = SS_NO_INIT runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT var/list/datum/asset/generate_queue = list() + var/last_queue_len = 0 /datum/controller/subsystem/asset_loading/fire(resumed) while(length(generate_queue)) @@ -16,7 +17,12 @@ SUBSYSTEM_DEF(asset_loading) if(MC_TICK_CHECK) return + last_queue_len = length(generate_queue) generate_queue.len-- + // We just emptied the queue + if(last_queue_len && !length(generate_queue)) + // Clean up cached icons, freeing memory. + rustg_iconforge_cleanup() /datum/controller/subsystem/asset_loading/proc/queue_asset(datum/asset/queue) #ifdef DO_NOT_DEFER_ASSETS diff --git a/code/modules/admin/admin_verb_lists.dm b/code/modules/admin/admin_verb_lists.dm index edb02c8e65..b4d6f2fd49 100644 --- a/code/modules/admin/admin_verb_lists.dm +++ b/code/modules/admin/admin_verb_lists.dm @@ -237,6 +237,8 @@ var/list/admin_verbs_debug = list( /client/proc/show_gm_status, /datum/admins/proc/change_weather, /datum/admins/proc/change_time, + /client/proc/cmd_regenerate_asset_cache, + /client/proc/cmd_clear_smart_asset_cache, /client/proc/admin_give_modifier, /client/proc/simple_DPS, /datum/admins/proc/view_feedback, @@ -391,6 +393,8 @@ var/list/admin_verbs_event_manager = list( /proc/release, /datum/admins/proc/change_weather, /datum/admins/proc/change_time, + /client/proc/cmd_regenerate_asset_cache, + /client/proc/cmd_clear_smart_asset_cache, /client/proc/admin_give_modifier, /client/proc/Jump, /client/proc/jumptomob, @@ -418,6 +422,8 @@ var/list/admin_verbs_event_manager = list( /client/proc/show_gm_status, /datum/admins/proc/change_weather, /datum/admins/proc/change_time, + /client/proc/cmd_regenerate_asset_cache, + /client/proc/cmd_clear_smart_asset_cache, /client/proc/admin_give_modifier, /datum/admins/proc/cmd_admin_dress, /client/proc/cmd_admin_gib_self, diff --git a/code/modules/admin/admin_verb_lists_vr.dm b/code/modules/admin/admin_verb_lists_vr.dm index 6883e0d32f..52a8cc3cb4 100644 --- a/code/modules/admin/admin_verb_lists_vr.dm +++ b/code/modules/admin/admin_verb_lists_vr.dm @@ -283,6 +283,8 @@ var/list/admin_verbs_debug = list( /datum/admins/proc/set_uplink, //VOREStation Add, /datum/admins/proc/change_weather, /datum/admins/proc/change_time, + /client/proc/cmd_regenerate_asset_cache, + /client/proc/cmd_clear_smart_asset_cache, /client/proc/admin_give_modifier, /client/proc/simple_DPS, /datum/admins/proc/view_feedback, @@ -455,6 +457,8 @@ var/list/admin_verbs_event_manager = list( /proc/release, /datum/admins/proc/change_weather, /datum/admins/proc/change_time, + /client/proc/cmd_regenerate_asset_cache, + /client/proc/cmd_clear_smart_asset_cache, /client/proc/admin_give_modifier, /client/proc/Jump, /client/proc/jumptomob, @@ -482,6 +486,8 @@ var/list/admin_verbs_event_manager = list( // /client/proc/show_gm_status, // VOREStation Edit - We don't use SSgame_master yet. /datum/admins/proc/change_weather, /datum/admins/proc/change_time, + /client/proc/cmd_regenerate_asset_cache, + /client/proc/cmd_clear_smart_asset_cache, /client/proc/admin_give_modifier, /datum/admins/proc/cmd_admin_dress, /client/proc/cmd_admin_gib_self, diff --git a/code/modules/admin/player_effects.dm b/code/modules/admin/player_effects.dm index 63cf456148..0931c53988 100644 --- a/code/modules/admin/player_effects.dm +++ b/code/modules/admin/player_effects.dm @@ -614,6 +614,12 @@ add_verb(Tar, /mob/living/proc/eat_trash) add_verb(Tar, /mob/living/proc/toggle_trash_catching) + if("active_cloaking") + var/mob/living/Tar = target + if(!istype(Tar)) + return + add_verb(Tar, /mob/living/proc/toggle_active_cloaking) + ////////INVENTORY////////////// diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 180062c1b3..cac043768a 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -695,3 +695,36 @@ var/log = "[key_name(src)] changed [planet.name]'s time to [planet.current_time.show_time("hh:mm")]." message_admins(log) log_admin(log) + +/client/proc/cmd_regenerate_asset_cache() + set category = "Debug.Assets" + set name = "Regenerate Asset Cache" + set desc = "Clears the asset cache and regenerates it immediately." + if(!CONFIG_GET(flag/cache_assets)) + to_chat(usr, span_warning("Asset caching is disabled in the config!")) + return + var/regenerated = 0 + for(var/datum/asset/A as() in subtypesof(/datum/asset)) + if(!initial(A.cross_round_cachable)) + continue + if(A == initial(A._abstract)) + continue + var/datum/asset/asset_datum = GLOB.asset_datums[A] + asset_datum.regenerate() + regenerated++ + to_chat(usr, span_notice("Regenerated [regenerated] asset\s.")) + +/client/proc/cmd_clear_smart_asset_cache() + set category = "Debug.Assets" + set name = "Clear Smart Asset Cache" + set desc = "Clears the smart asset cache." + if(!CONFIG_GET(flag/smart_cache_assets)) + to_chat(usr, span_warning("Smart asset caching is disabled in the config!")) + return + var/cleared = 0 + for(var/datum/asset/spritesheet_batched/A as() in subtypesof(/datum/asset/spritesheet_batched)) + if(A == initial(A._abstract)) + continue + fdel("[ASSET_CROSS_ROUND_SMART_CACHE_DIRECTORY]/spritesheet_cache.[initial(A.name)].json") + cleared++ + to_chat(usr, span_notice("Cleared [cleared] asset\s.")) diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index a21d95c14e..de3e6da4af 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -411,14 +411,18 @@ else if(href_list["addverb"]) if(!check_rights(R_DEBUG)) return - var/mob/living/H = locate(href_list["addverb"]) + var/mob/H = locate(href_list["addverb"]) - if(!istype(H)) - to_chat(usr, "This can only be done to instances of type /mob/living") + if(!ismob(H)) + to_chat(usr, "This can only be done to instances of type /mob") return var/list/possibleverbs = list() possibleverbs += "Cancel" // One for the top... - possibleverbs += typesof(/mob/proc,/mob/verb,/mob/living/proc,/mob/living/verb) + possibleverbs += typesof(/mob/proc, /mob/verb) + if(istype(H,/mob/observer/dead)) + possibleverbs += typesof(/mob/observer/dead/proc,/mob/observer/dead/verb) + if(istype(H,/mob/living)) + possibleverbs += typesof(/mob/living/proc,/mob/living/verb) if(istype(H,/mob/living/carbon/human)) possibleverbs += typesof(/mob/living/carbon/proc,/mob/living/carbon/verb,/mob/living/carbon/human/verb,/mob/living/carbon/human/proc) if(istype(H,/mob/living/silicon/robot)) diff --git a/code/modules/asset_cache/asset_cache_item.dm b/code/modules/asset_cache/asset_cache_item.dm index ad4596bded..dbee71b525 100644 --- a/code/modules/asset_cache/asset_cache_item.dm +++ b/code/modules/asset_cache/asset_cache_item.dm @@ -28,22 +28,28 @@ ///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)) + if(!isfile(file)) file = fcopy_rsc(file) - hash = file_hash + if(length(file) == 0) + log_asset("WARNING: [name] is an empty file, this is almost certainly not intended and could indicate a bad boot!") + message_admins("ASSET WARNING: [name] is an empty file, this is almost certainly not intended and could indicate a bad boot!") + 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") + if(!hash) + hash = md5(fcopy_rsc(file)) + if (!hash) + CRASH("invalid asset sent to asset cache") + log_debug("asset cache unexpected success of second fcopy_rsc") src.name = name var/extstart = findlasttext(name, ".") - if (extstart) + if(extstart) ext = ".[copytext(name, extstart+1)]" resource = file diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index bdc062e066..d3c75b77e6 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -1,5 +1,3 @@ -#define ASSET_CROSS_ROUND_CACHE_DIRECTORY "cache/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 @@ -20,15 +18,15 @@ GLOBAL_LIST_EMPTY(asset_datums) 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 + /// Whether or not this asset should be loaded in the "early assets" SS + var/early = FALSE + /datum/asset/New() GLOB.asset_datums[type] = src register() @@ -63,6 +61,19 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/proc/should_refresh() return !cross_round_cachable || !CONFIG_GET(flag/cache_assets) +/// Immediately regenerate the asset, overwriting any cache. +/datum/asset/proc/regenerate() + SHOULD_CALL_PARENT(FALSE) + unregister() + cached_serialized_url_mappings = null + cached_serialized_url_mappings_transport_type = null + register() + +/// Unregisters any assets from the transport. +/datum/asset/proc/unregister() + SHOULD_CALL_PARENT(FALSE) + CRASH("unregister() not implemented for asset [type]!") + /// 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) @@ -86,12 +97,12 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/simple/register() for(var/asset_name in assets) var/datum/asset_cache_item/ACI = SSassets.transport.register_asset(asset_name, assets[asset_name]) - if (!ACI) + if(!istype(ACI)) log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]") continue - if (legacy) + if(legacy) ACI.legacy = legacy - if (keep_local_name) + if(keep_local_name) ACI.keep_local_name = keep_local_name assets[asset_name] = ACI @@ -103,6 +114,7 @@ GLOBAL_LIST_EMPTY(asset_datums) for (var/asset_name in assets) .[asset_name] = SSassets.transport.get_asset_url(asset_name, assets[asset_name]) + // For registering or sending multiple others at once /datum/asset/group _abstract = /datum/asset/group @@ -123,6 +135,11 @@ GLOBAL_LIST_EMPTY(asset_datums) var/datum/asset/A = get_asset_datum(type) . += A.get_url_mappings() +/datum/asset/group/unregister() + for(var/type in children) + var/datum/asset/A = get_asset_datum(type) + A.unregister() + // spritesheet implementation - coalesces various icons into a single .png file // and uses CSS to select icons out of that file - saves on transferring some // 1400-odd individual PNG files @@ -147,9 +164,10 @@ GLOBAL_LIST_EMPTY(asset_datums) /// 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 + /// Allows resizing all icons it comes across by a multiplier (32x32 * 2 = 64x64) + var/resize = 1 + /// If this asset should CRASH or ignore when duplicate sprite keys are added + var/duplicates_allowed = FALSE /datum/asset/spritesheet/proc/should_load_immediately() #ifdef DO_NOT_DEFER_ASSETS @@ -158,28 +176,58 @@ GLOBAL_LIST_EMPTY(asset_datums) return load_immediately #endif - /datum/asset/spritesheet/should_refresh() if (..()) return TRUE + // Static so that the result is the same, even when the files are created, for this run + var/static/should_refresh = null + if (isnull(should_refresh)) // `fexists` seems to always fail on static-time - should_refresh = !fexists(css_cache_filename()) || !fexists(data_cache_filename()) + should_refresh = !fexists("[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css") return should_refresh +/datum/asset/spritesheet/unregister() + SSassets.transport.unregister_asset("spritesheet_[name].css") + if(length(sizes)) + for(var/size_id in sizes) + SSassets.transport.unregister_asset("[name]_[size_id].png") + else + for(var/sheet in cached_spritesheets_needed) + SSassets.transport.unregister_asset(sheet) + +/datum/asset/spritesheet/regenerate() + unregister() + sprites = list() + fdel("[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css") + for(var/sheet in cached_spritesheets_needed) + fdel("[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[sheet].png") + fdel("data/spritesheets/spritesheet_[name].css") + for(var/size_id in sizes) + fdel("data/spritesheets/[name]_[size_id].png") + sizes = list() + to_generate = list() + cached_serialized_url_mappings = null + cached_serialized_url_mappings_transport_type = null + fully_generated = FALSE + var/old_load = load_immediately + load_immediately = TRUE + create_spritesheets() + realize_spritesheets(yield = FALSE) + load_immediately = old_load + /datum/asset/spritesheet/register() SHOULD_NOT_OVERRIDE(TRUE) - if (!name) + if(!name) CRASH("spritesheet [type] cannot register without a name") - if (!should_refresh() && read_from_cache()) + 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_GET(flag/cache_assets) && cross_round_cachable) load_immediately = TRUE @@ -202,17 +250,19 @@ GLOBAL_LIST_EMPTY(asset_datums) ensure_stripped() for(var/size_id in sizes) var/size = sizes[size_id] - 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)) - + var/file_path = size[SPRSZ_STRIPPED] + var/file_hash = rustg_hash_file("md5", file_path) + SSassets.transport.register_asset("[name]_[size_id].png", file_path, file_hash=file_hash) + var/res_name = "spritesheet_[name].css" + var/fname = "data/spritesheets/[res_name]" + fdel(fname) + var/css = generate_css() + rustg_file_write(css, fname) + var/css_hash = rustg_hash_string("md5", css) + SSassets.transport.register_asset(res_name, fcopy_rsc(fname), file_hash=css_hash) if(CONFIG_GET(flag/save_spritesheets)) - save_to_logs(file_name = css_name, file_location = file_directory) - - fdel(file_directory) + save_to_logs(file_name = res_name, file_location = fname) + fdel(fname) if (CONFIG_GET(flag/cache_assets) && cross_round_cachable) write_to_cache() @@ -229,10 +279,10 @@ GLOBAL_LIST_EMPTY(asset_datums) return ..() /datum/asset/spritesheet/send(client/client) - if (!name) + if(!name) return - if (!should_refresh()) + if(!should_refresh()) return send_from_cache(client) var/all = list("spritesheet_[name].css") @@ -254,33 +304,46 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes) for(var/size_id in sizes_to_strip) var/size = sizes[size_id] - if (size[SPRSZ_STRIPPED]) + if(size[SPRSZ_STRIPPED]) continue // save flattened version - 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) + var/fname = "data/spritesheets/[name]_[size_id].png" + fcopy(size[SPRSZ_ICON], fname) + var/error = rustg_dmi_strip_metadata(fname) if(length(error)) - stack_trace("Failed to strip [png_name]: [error]") - size[SPRSZ_STRIPPED] = icon(file_directory) + stack_trace("Failed to strip [name]_[size_id].png: [error]") + + // Difference from Beestation: Resizing handling + var/icon/stripped = icon(fname) + if(resize != 1) + var/new_width = round(stripped.Width() * resize) + var/new_height = round(stripped.Height() * resize) + // Note: arguments MUST be strings or they don't make it past ffi + var/error_two = rustg_dmi_resize_png(fname, "[new_width]", "[new_height]", "nearest") + if(error_two) + stack_trace("Failed to resize [name]_[size_id].png to [new_width]x[new_height]: [error_two]") + + size[SPRSZ_STRIPPED] = icon(fname) + else + size[SPRSZ_STRIPPED] = stripped // 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_GET(flag/save_spritesheets)) - save_to_logs(file_name = png_name, file_location = file_directory) + save_to_logs(file_name = "[name]_[size_id].png", file_location = fname) - fdel(file_directory) + fdel(fname) /datum/asset/spritesheet/proc/generate_css() var/list/out = list() - for (var/size_id in sizes) + 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_background_url("[name]_[size_id].png")]') no-repeat;}" + // Difference from Beestation: * resize on width and height + out += ".[name][size_id]{display:inline-block;width:[round(tiny.Width() * resize)]px;height:[round(tiny.Height() * resize)]px;background:url('[get_background_url("[name]_[size_id].png")]') no-repeat;}" - for (var/sprite_id in sprites) + for(var/sprite_id in sprites) var/sprite = sprites[sprite_id] var/size_id = sprite[SPR_SIZE] var/idx = sprite[SPR_IDX] @@ -288,9 +351,10 @@ GLOBAL_LIST_EMPTY(asset_datums) var/icon/tiny = size[SPRSZ_ICON] var/icon/big = size[SPRSZ_STRIPPED] - var/per_line = big.Width() / tiny.Width() - var/x = (idx % per_line) * tiny.Width() - var/y = round(idx / per_line) * tiny.Height() + // Difference from Beestation: Resizing handling + var/per_line = big.Width() / round(tiny.Width() * resize) + var/x = (idx % per_line) * round(tiny.Width() * resize) + var/y = round(idx / per_line) * round(tiny.Height() * resize) out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}" @@ -303,39 +367,31 @@ GLOBAL_LIST_EMPTY(asset_datums) 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/replaced_css = rustg_file_read("[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css") 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/file_path = "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[asset_id]" + // Hashing it here is a *lot* faster. + var/hash = rustg_hash_file("md5", file_path) + var/asset_cache_item = SSassets.transport.register_asset(asset_id, file_path, file_hash=hash) 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]" + var/replaced_css_filename = "data/spritesheets/spritesheet_[name].css" + var/css_hash = rustg_hash_string("md5", replaced_css) rustg_file_write(replaced_css, replaced_css_filename) - SSassets.transport.register_asset(finalized_name, replaced_css_filename) + SSassets.transport.register_asset("spritesheet_[name].css", replaced_css_filename, file_hash=css_hash) if(CONFIG_GET(flag/save_spritesheets)) - save_to_logs(file_name = finalized_name, file_location = replaced_css_filename) + save_to_logs(file_name = "spritesheet_[name].css", 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") @@ -351,23 +407,15 @@ GLOBAL_LIST_EMPTY(asset_datums) 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") + var/datum/asset_cache_item/temp = SSassets.cache["[name]_[size_id].png"] + fcopy(temp.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()) + rustg_file_write(mock_css, "[ASSET_CROSS_ROUND_CACHE_DIRECTORY]/spritesheet.[name].css") /datum/asset/spritesheet/proc/get_cached_url_mappings() var/list/mappings = list() @@ -392,20 +440,17 @@ GLOBAL_LIST_EMPTY(asset_datums) /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 + 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] - if (sprites[sprite_name]) + if(sprites[sprite_name]) + if(duplicates_allowed) + return // No crash CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])") - if (size) + 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 @@ -424,26 +469,15 @@ GLOBAL_LIST_EMPTY(asset_datums) 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)) + if(length(prefix)) prefix = "[prefix]-" - if (!directions) + if(!directions) directions = list(SOUTH) - for (var/icon_state_name in icon_states(I)) - for (var/direction in directions) + for(var/icon_state_name in icon_states(I)) + for(var/direction in directions) var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : "" Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction) @@ -455,10 +489,10 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/spritesheet/proc/icon_tag(sprite_name) var/sprite = sprites[sprite_name] - if (!sprite) + if(!sprite) return null var/size_id = sprite[SPR_SIZE] - return {""} + return {""} /datum/asset/spritesheet/proc/icon_class_name(sprite_name) var/sprite = sprites[sprite_name] @@ -486,6 +520,13 @@ GLOBAL_LIST_EMPTY(asset_datums) #undef SPRSZ_ICON #undef SPRSZ_STRIPPED +/datum/asset/spritesheet/simple + _abstract = /datum/asset/spritesheet/simple + var/list/assets + +/datum/asset/spritesheet/simple/create_spritesheets() + for(var/key in assets) + Insert(key, assets[key]) /datum/asset/changelog_item _abstract = /datum/asset/changelog_item @@ -505,14 +546,6 @@ GLOBAL_LIST_EMPTY(asset_datums) 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/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 _abstract = /datum/asset/simple/icon_states @@ -528,7 +561,7 @@ GLOBAL_LIST_EMPTY(asset_datums) for(var/icon_state_name in icon_states(_icon)) for(var/direction in directions) var/asset = icon(_icon, icon_state_name, direction, frame, movement_states) - if (!asset) + if(!asset) continue asset = fcopy_rsc(asset) //dedupe var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : "" @@ -558,36 +591,37 @@ GLOBAL_LIST_EMPTY(asset_datums) var/list/parents = list() /datum/asset/simple/namespaced/register() - if (legacy) + if(legacy) assets |= parents var/list/hashlist = list() - var/list/sorted_assets = sortList(assets) + var/list/created_items = list() - for (var/asset_name in sorted_assets) + 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) + if (!istype(ACI) || !ACI.hash) log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]") continue hashlist += ACI.hash - sorted_assets[asset_name] = ACI + created_items[asset_name] = ACI var/namespace = md5(hashlist.Join()) - for (var/asset_name in parents) + for(var/asset_name in parents) var/datum/asset_cache_item/ACI = new(asset_name, parents[asset_name]) - if (!ACI?.hash) + if (!istype(ACI) || !ACI.hash) log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]") continue ACI.namespace_parent = TRUE - sorted_assets[asset_name] = ACI + created_items[asset_name] = ACI - for (var/asset_name in sorted_assets) - var/datum/asset_cache_item/ACI = sorted_assets[asset_name] - if (!ACI?.hash) + for(var/asset_name in created_items) + var/datum/asset_cache_item/ACI = created_items[asset_name] + if (!istype(ACI) || !ACI.hash) log_asset("ERROR: Invalid asset: [type]:[asset_name]:[ACI]") continue ACI.namespace = namespace - assets = sorted_assets + assets = created_items ..() /// Get a html string that will load a html asset. @@ -612,7 +646,7 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/json/register() var/filename = "data/[name].json" fdel(filename) - text2file(json_encode(generate()), filename) + rustg_file_write(json_encode(generate()), filename) SSassets.transport.register_asset("[name].json", fcopy_rsc(filename)) fdel(filename) @@ -621,4 +655,5 @@ GLOBAL_LIST_EMPTY(asset_datums) SHOULD_CALL_PARENT(FALSE) CRASH("generate() not implemented for [type]!") -#undef ASSET_CROSS_ROUND_CACHE_DIRECTORY +/datum/asset/json/unregister() + SSassets.transport.unregister_asset("[name].json") diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm deleted file mode 100644 index 59bd2b040e..0000000000 --- a/code/modules/asset_cache/asset_list_items.dm +++ /dev/null @@ -1,544 +0,0 @@ -//DEFINITIONS FOR ASSET DATUMS START HERE. -/datum/asset/simple/headers - assets = list( - "alarm_green.gif" = 'icons/program_icons/alarm_green.gif', - "alarm_red.gif" = 'icons/program_icons/alarm_red.gif', - "batt_5.gif" = 'icons/program_icons/batt_5.gif', - "batt_20.gif" = 'icons/program_icons/batt_20.gif', - "batt_40.gif" = 'icons/program_icons/batt_40.gif', - "batt_60.gif" = 'icons/program_icons/batt_60.gif', - "batt_80.gif" = 'icons/program_icons/batt_80.gif', - "batt_100.gif" = 'icons/program_icons/batt_100.gif', - "charging.gif" = 'icons/program_icons/charging.gif', - "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif', - "downloader_running.gif" = 'icons/program_icons/downloader_running.gif', - "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif', - "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif', - "power_norm.gif" = 'icons/program_icons/power_norm.gif', - "power_warn.gif" = 'icons/program_icons/power_warn.gif', - "sig_high.gif" = 'icons/program_icons/sig_high.gif', - "sig_low.gif" = 'icons/program_icons/sig_low.gif', - "sig_lan.gif" = 'icons/program_icons/sig_lan.gif', - "sig_none.gif" = 'icons/program_icons/sig_none.gif', - "smmon_0.gif" = 'icons/program_icons/smmon_0.gif', - "smmon_1.gif" = 'icons/program_icons/smmon_1.gif', - "smmon_2.gif" = 'icons/program_icons/smmon_2.gif', - "smmon_3.gif" = 'icons/program_icons/smmon_3.gif', - "smmon_4.gif" = 'icons/program_icons/smmon_4.gif', - "smmon_5.gif" = 'icons/program_icons/smmon_5.gif', - "smmon_6.gif" = 'icons/program_icons/smmon_6.gif', - // "borg_mon.gif" = 'icons/program_icons/borg_mon.gif' - ) - -// /datum/asset/simple/radar_assets -// assets = list( -// "ntosradarbackground.png" = 'icons/UI_Icons/tgui/ntosradar_background.png', -// "ntosradarpointer.png" = 'icons/UI_Icons/tgui/ntosradar_pointer.png', -// "ntosradarpointerS.png" = 'icons/UI_Icons/tgui/ntosradar_pointer_S.png' -// ) - -// /datum/asset/spritesheet/simple/pda -// name = "pda" -// assets = list( -// "atmos" = 'icons/pda_icons/pda_atmos.png', -// "back" = 'icons/pda_icons/pda_back.png', -// "bell" = 'icons/pda_icons/pda_bell.png', -// "blank" = 'icons/pda_icons/pda_blank.png', -// "boom" = 'icons/pda_icons/pda_boom.png', -// "bucket" = 'icons/pda_icons/pda_bucket.png', -// "medbot" = 'icons/pda_icons/pda_medbot.png', -// "floorbot" = 'icons/pda_icons/pda_floorbot.png', -// "cleanbot" = 'icons/pda_icons/pda_cleanbot.png', -// "crate" = 'icons/pda_icons/pda_crate.png', -// "cuffs" = 'icons/pda_icons/pda_cuffs.png', -// "eject" = 'icons/pda_icons/pda_eject.png', -// "flashlight" = 'icons/pda_icons/pda_flashlight.png', -// "honk" = 'icons/pda_icons/pda_honk.png', -// "mail" = 'icons/pda_icons/pda_mail.png', -// "medical" = 'icons/pda_icons/pda_medical.png', -// "menu" = 'icons/pda_icons/pda_menu.png', -// "mule" = 'icons/pda_icons/pda_mule.png', -// "notes" = 'icons/pda_icons/pda_notes.png', -// "power" = 'icons/pda_icons/pda_power.png', -// "rdoor" = 'icons/pda_icons/pda_rdoor.png', -// "reagent" = 'icons/pda_icons/pda_reagent.png', -// "refresh" = 'icons/pda_icons/pda_refresh.png', -// "scanner" = 'icons/pda_icons/pda_scanner.png', -// "signaler" = 'icons/pda_icons/pda_signaler.png', -// "skills" = 'icons/pda_icons/pda_skills.png', -// "status" = 'icons/pda_icons/pda_status.png', -// "dronephone" = 'icons/pda_icons/pda_dronephone.png', -// "emoji" = 'icons/pda_icons/pda_emoji.png' -// ) - -// /datum/asset/spritesheet/simple/paper -// name = "paper" -// assets = list( -// "stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png', -// "stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png', -// "stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png', -// "stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png', -// "stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png', -// "stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png', -// "stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png', -// "stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png', -// "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png', -// "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png', -// "stamp-law" = 'icons/stamp_icons/large_stamp-law.png', -// "stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png', -// "stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png', -// "stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png', -// "stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png' -// ) - - -// /datum/asset/simple/irv -// assets = list( -// "jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js', -// ) - -// /datum/asset/group/irv -// children = list( -// /datum/asset/simple/jquery, -// /datum/asset/simple/irv -// ) - -/datum/asset/simple/generic - assets = list( - "search.js" = 'html/search.js', - "panels.css" = 'html/panels.css', - "loading.gif" = 'html/images/loading.gif', - "ntlogo.png" = 'html/images/ntlogo.png', - "sglogo.png" = 'html/images/sglogo.png', - "talisman.png" = 'html/images/talisman.png', - "paper_bg.png" = 'html/images/paper_bg.png', - "no_image32.png" = 'html/images/no_image32.png', - ) - -/datum/asset/simple/changelog - assets = list( - "88x31.png" = 'html/88x31.png', - "bug-minus.png" = 'html/bug-minus.png', - "cross-circle.png" = 'html/cross-circle.png', - "hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png', - "image-minus.png" = 'html/image-minus.png', - "image-plus.png" = 'html/image-plus.png', - "map-pencil.png" = 'html/map-pencil.png', - "music-minus.png" = 'html/music-minus.png', - "music-plus.png" = 'html/music-plus.png', - "tick-circle.png" = 'html/tick-circle.png', - "wrench-screwdriver.png" = 'html/wrench-screwdriver.png', - "spell-check.png" = 'html/spell-check.png', - "burn-exclamation.png" = 'html/burn-exclamation.png', - "chevron.png" = 'html/chevron.png', - "chevron-expand.png" = 'html/chevron-expand.png', - "changelog.css" = 'html/changelog.css', - "changelog.js" = 'html/changelog.js', - "changelog.html" = 'html/changelog.html' - ) - -// /datum/asset/group/goonchat -// children = list( -// /datum/asset/simple/jquery, -// /datum/asset/simple/goonchat, -// /datum/asset/spritesheet/goonchat, -// /datum/asset/simple/fontawesome -// ) - -// /datum/asset/simple/goonchat -// assets = list( -// "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', -// "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', -// "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', -// "browserOutput_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput_white.css', -// ) - -// /datum/asset/spritesheet/goonchat -// name = "chat" - -// /datum/asset/spritesheet/goonchat/register() -// InsertAll("emoji", 'icons/emoji.dmi') - -// // pre-loading all lanugage icons also helps to avoid meta -// InsertAll("language", 'icons/misc/language.dmi') -// // catch languages which are pulling icons from another file -// for(var/path in typesof(/datum/language)) -// var/datum/language/L = path -// var/icon = initial(L.icon) -// if (icon != 'icons/misc/language.dmi') -// var/icon_state = initial(L.icon_state) -// Insert("language-[icon_state]", icon, icon_state=icon_state) - -// ..() - -// /datum/asset/simple/permissions -// assets = list( -// "padlock.png" = 'html/padlock.png' -// ) - -// /datum/asset/simple/notes -// assets = list( -// "high_button.png" = 'html/high_button.png', -// "medium_button.png" = 'html/medium_button.png', -// "minor_button.png" = 'html/minor_button.png', -// "none_button.png" = 'html/none_button.png', -// ) - -/datum/asset/simple/arcade - assets = list( - "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif', - "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif', - "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif', - "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif', - "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif', - "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif', - ) - -// /datum/asset/spritesheet/simple/achievements -// name ="achievements" -// assets = list( -// "default" = 'icons/UI_Icons/Achievements/default.png', -// "basemisc" = 'icons/UI_Icons/Achievements/basemisc.png', -// "baseboss" = 'icons/UI_Icons/Achievements/baseboss.png', -// "baseskill" = 'icons/UI_Icons/Achievements/baseskill.png', -// "bbgum" = 'icons/UI_Icons/Achievements/Boss/bbgum.png', -// "colossus" = 'icons/UI_Icons/Achievements/Boss/colossus.png', -// "hierophant" = 'icons/UI_Icons/Achievements/Boss/hierophant.png', -// "legion" = 'icons/UI_Icons/Achievements/Boss/legion.png', -// "miner" = 'icons/UI_Icons/Achievements/Boss/miner.png', -// "swarmer" = 'icons/UI_Icons/Achievements/Boss/swarmer.png', -// "tendril" = 'icons/UI_Icons/Achievements/Boss/tendril.png', -// "featofstrength" = 'icons/UI_Icons/Achievements/Misc/featofstrength.png', -// "helbital" = 'icons/UI_Icons/Achievements/Misc/helbital.png', -// "jackpot" = 'icons/UI_Icons/Achievements/Misc/jackpot.png', -// "meteors" = 'icons/UI_Icons/Achievements/Misc/meteors.png', -// "timewaste" = 'icons/UI_Icons/Achievements/Misc/timewaste.png', -// "upgrade" = 'icons/UI_Icons/Achievements/Misc/upgrade.png', -// "clownking" = 'icons/UI_Icons/Achievements/Misc/clownking.png', -// "clownthanks" = 'icons/UI_Icons/Achievements/Misc/clownthanks.png', -// "rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png', -// "snail" = 'icons/UI_Icons/Achievements/Misc/snail.png', -// "mining" = 'icons/UI_Icons/Achievements/Skills/mining.png', -// ) - -// /datum/asset/spritesheet/simple/pills -// name ="pills" -// assets = list( -// "pill1" = 'icons/UI_Icons/Pills/pill1.png', -// "pill2" = 'icons/UI_Icons/Pills/pill2.png', -// "pill3" = 'icons/UI_Icons/Pills/pill3.png', -// "pill4" = 'icons/UI_Icons/Pills/pill4.png', -// "pill5" = 'icons/UI_Icons/Pills/pill5.png', -// "pill6" = 'icons/UI_Icons/Pills/pill6.png', -// "pill7" = 'icons/UI_Icons/Pills/pill7.png', -// "pill8" = 'icons/UI_Icons/Pills/pill8.png', -// "pill9" = 'icons/UI_Icons/Pills/pill9.png', -// "pill10" = 'icons/UI_Icons/Pills/pill10.png', -// "pill11" = 'icons/UI_Icons/Pills/pill11.png', -// "pill12" = 'icons/UI_Icons/Pills/pill12.png', -// "pill13" = 'icons/UI_Icons/Pills/pill13.png', -// "pill14" = 'icons/UI_Icons/Pills/pill14.png', -// "pill15" = 'icons/UI_Icons/Pills/pill15.png', -// "pill16" = 'icons/UI_Icons/Pills/pill16.png', -// "pill17" = 'icons/UI_Icons/Pills/pill17.png', -// "pill18" = 'icons/UI_Icons/Pills/pill18.png', -// "pill19" = 'icons/UI_Icons/Pills/pill19.png', -// "pill20" = 'icons/UI_Icons/Pills/pill20.png', -// "pill21" = 'icons/UI_Icons/Pills/pill21.png', -// "pill22" = 'icons/UI_Icons/Pills/pill22.png', -// ) - -// //this exists purely to avoid meta by pre-loading all language icons. -// /datum/asset/language/register() -// for(var/path in typesof(/datum/language)) -// set waitfor = FALSE -// var/datum/language/L = new path () -// L.get_icon() - -/datum/asset/spritesheet/pipes - name = "pipes" - -/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/create_spritesheets() - var/icon/downscaled = icon('icons/mob/screen_full_vore.dmi') - downscaled.Scale(240, 240) - InsertAll("", downscaled) - -/datum/asset/spritesheet/vore_colorized //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. - name = "colorizedvore" - -/datum/asset/spritesheet/vore_colorized/create_spritesheets() - var/icon/downscaledVC = icon('icons/mob/screen_full_colorized_vore.dmi') - downscaledVC.Scale(240, 240) - InsertAll("", downscaledVC) - -//VOREStation Add End - -// // Representative icons for each research design -// /datum/asset/spritesheet/research_designs -// name = "design" - -// /datum/asset/spritesheet/research_designs/register() -// for (var/path in subtypesof(/datum/design)) -// var/datum/design/D = path - -// var/icon_file -// var/icon_state -// var/icon/I - -// if(initial(D.research_icon) && initial(D.research_icon_state)) //If the design has an icon replacement skip the rest -// icon_file = initial(D.research_icon) -// icon_state = initial(D.research_icon_state) -// if(!(icon_state in icon_states(icon_file))) -// warning("design [D] with icon '[icon_file]' missing state '[icon_state]'") -// continue -// I = icon(icon_file, icon_state, SOUTH) - -// else -// // construct the icon and slap it into the resource cache -// var/atom/item = initial(D.build_path) -// if (!ispath(item, /atom)) -// // biogenerator outputs to beakers by default -// if (initial(D.build_type) & BIOGENERATOR) -// item = /obj/item/reagent_containers/glass/beaker/large -// else -// continue // shouldn't happen, but just in case - -// // circuit boards become their resulting machines or computers -// if (ispath(item, /obj/item/circuitboard)) -// var/obj/item/circuitboard/C = item -// var/machine = initial(C.build_path) -// if (machine) -// item = machine - -// icon_file = initial(item.icon) -// icon_state = initial(item.icon_state) - -// if(!(icon_state in icon_states(icon_file))) -// warning("design [D] with icon '[icon_file]' missing state '[icon_state]'") -// continue -// I = icon(icon_file, icon_state, SOUTH) - -// // computers (and snowflakes) get their screen and keyboard sprites -// if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control)) -// var/obj/machinery/computer/C = item -// var/screen = initial(C.icon_screen) -// var/keyboard = initial(C.icon_keyboard) -// var/all_states = icon_states(icon_file) -// if (screen && (screen in all_states)) -// I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY) -// if (keyboard && (keyboard in all_states)) -// I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY) - -// Insert(initial(D.id), I) -// return ..() - -/datum/asset/spritesheet/vending - name = "vending" - -/datum/asset/spritesheet/vending/create_spritesheets() - populate_vending_products() - for(var/atom/item as anything in GLOB.vending_products) - if(!ispath(item, /atom)) - continue - - var/icon_file = initial(item.icon) - var/icon_state = initial(item.icon_state) - - // I really don't like the fact that I have to do this, but what the hell else *can* I do to make all of these - // random special items work? - if(ispath(item, /obj/item/reagent_containers/food/drinks/glass2) && !ispath(item, /obj/item/reagent_containers/food/drinks/glass2/fitnessflask)) - var/obj/item/reagent_containers/food/drinks/glass2/G = item - icon_state = initial(G.base_icon) - if(ispath(item, /obj/item/reagent_containers/hypospray/autoinjector)) - icon_state += "0" - - var/icon/I - - var/icon_states_list = icon_states(icon_file) - if(icon_state in icon_states_list) - I = icon(icon_file, icon_state, SOUTH) - var/c = initial(item.color) - if(!isnull(c) && c != "#FFFFFF") - I.Blend(c, ICON_MULTIPLY) - else - var/icon_states_string - for(var/an_icon_state in icon_states_list) - if(!icon_states_string) - icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])" - else - icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])" - stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]") - I = icon('icons/turf/floors.dmi', "", SOUTH) - - var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-") - - Insert(imgid, I) - -// 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 -// that they exist, and therefore can't generate the entries in the spritesheet for them -// and since assets are unique and can't be reloaded later, we have to make sure that GLOB.vending_products -// is populated with every single type of vending machine -// As this is only done at runtime, we have to create all the vending machines in existence and force them -// to register their products when this asset initializes. -/datum/asset/spritesheet/vending/proc/populate_vending_products() - SSatoms.map_loader_begin() - for(var/path in subtypesof(/obj/machinery/vending)) - var/obj/machinery/vending/x = new path(null) - // force an inventory build; with map_loader_begin active, init isn't called - x.build_inventory() - qdel(x) - SSatoms.map_loader_stop() - -// /datum/asset/simple/genetics -// assets = list( -// "dna_discovered.gif" = 'html/dna_discovered.gif', -// "dna_undiscovered.gif" = 'html/dna_undiscovered.gif', -// "dna_extra.gif" = 'html/dna_extra.gif' -// ) - -// /datum/asset/simple/orbit -// assets = list( -// "ghost.png" = 'html/ghost.png' -// ) - -// /datum/asset/simple/vv -// assets = list( -// "view_variables.css" = 'html/admin/view_variables.css' -// ) - -// /datum/asset/spritesheet/sheetmaterials -// name = "sheetmaterials" - -// /datum/asset/spritesheet/sheetmaterials/register() -// InsertAll("", 'icons/obj/stack_objects.dmi') - -// // Special case to handle Bluespace Crystals -// Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal") -// ..() - -//Pill sprites for UIs -/datum/asset/spritesheet/chem_master - name = "chem_master" - -/datum/asset/spritesheet/chem_master/create_spritesheets() - for(var/i = 1 to 24) - Insert("pill[i]", 'icons/obj/chemical.dmi', "pill[i]") - - for(var/i = 1 to 4) - Insert("bottle-[i]", 'icons/obj/chemical.dmi', "bottle-[i]") - - -// Robot UI sprites -/datum/asset/spritesheet/robot_icons - name = "robot_icons" - -/datum/asset/spritesheet/robot_icons/create_spritesheets() - for(var/datum/robot_sprite/S as anything in typesof(/datum/robot_sprite)) - if(!S.name || !S.sprite_icon_state) // snowflake out those customs... they suck - continue - var/icon/I_N = icon(S.sprite_icon, S.sprite_icon_state, NORTH) - var/icon/I_S = icon(S.sprite_icon, S.sprite_icon_state, SOUTH) - var/icon/I_W = icon(S.sprite_icon, S.sprite_icon_state, WEST) - var/icon/I_E = icon(S.sprite_icon, S.sprite_icon_state, EAST) - if(S.has_eye_sprites) - var/icon/I_NE = icon(S.sprite_icon, "[S.sprite_icon_state]-eyes", NORTH) - if(I_NE) - I_N.Blend(I_NE, ICON_OVERLAY) - if(S.has_eye_sprites) - var/icon/I_SE = icon(S.sprite_icon, "[S.sprite_icon_state]-eyes", SOUTH) - if(I_SE) - I_S.Blend(I_SE, ICON_OVERLAY) - if(S.has_eye_sprites) - var/icon/I_WE = icon(S.sprite_icon, "[S.sprite_icon_state]-eyes", WEST) - if(I_WE) - I_W.Blend(I_WE, ICON_OVERLAY) - if(S.has_eye_sprites) - var/icon/I_EE = icon(S.sprite_icon, "[S.sprite_icon_state]-eyes", EAST) - if(I_EE) - I_E.Blend(I_EE, ICON_OVERLAY) - var/imgid = sanitize_css_class_name("[S.type]") - I_N.Scale(120, 120) - I_S.Scale(120, 120) - I_W.Scale(120, 120) - I_E.Scale(120, 120) - Insert(imgid + "N", I_N) - Insert(imgid + "S", I_S) - Insert(imgid + "W", I_W) - Insert(imgid + "E", I_E) - - -//Cloning pod sprites for UIs -/datum/asset/simple/cloning - assets = list( - "pod_idle.gif" = 'icons/UI_Icons/synthprinter.gif', - "pod_cloning.gif" = 'icons/UI_Icons/synthprinter_working.gif', - ) - -// VOREStation Add -/datum/asset/simple/cloning/resleeving - assets = list( - "sleeve_empty.gif" = 'icons/UI_Icons/sleeve_empty.gif', - "sleeve_occupied.gif" = 'icons/UI_Icons/sleeve_occupied.gif', - "synthprinter.gif" = 'icons/UI_Icons/synthprinter.gif', - "synthprinter_working.gif" = 'icons/UI_Icons/synthprinter_working.gif', - ) - -/datum/asset/spritesheet/sheetmaterials - name = "sheetmaterials" - -/datum/asset/spritesheet/sheetmaterials/create_spritesheets() - InsertAll("", 'icons/obj/stacks.dmi') - -// Nanomaps -/datum/asset/simple/nanomaps - // It REALLY doesnt matter too much if these arent up to date - // They are relatively big - assets = list( - // YW Edit: We don't need Southern Cross, groundbase or tether - // "southern_cross_nanomap_z1.png" = 'icons/_nanomaps/southern_cross_nanomap_z1.png', - // "southern_cross_nanomap_z10.png" = 'icons/_nanomaps/southern_cross_nanomap_z10.png', - // "southern_cross_nanomap_z2.png" = 'icons/_nanomaps/southern_cross_nanomap_z2.png', - // "southern_cross_nanomap_z3.png" = 'icons/_nanomaps/southern_cross_nanomap_z3.png', - // "southern_cross_nanomap_z5.png" = 'icons/_nanomaps/southern_cross_nanomap_z5.png', - // "southern_cross_nanomap_z6.png" = 'icons/_nanomaps/southern_cross_nanomap_z6.png', - //"tether_nanomap_z1.png" = 'icons/_nanomaps/tether_nanomap_z1.png', - //"tether_nanomap_z2.png" = 'icons/_nanomaps/tether_nanomap_z2.png', - //"tether_nanomap_z3.png" = 'icons/_nanomaps/tether_nanomap_z3.png', - //"tether_nanomap_z4.png" = 'icons/_nanomaps/tether_nanomap_z4.png', - //"tether_nanomap_z5.png" = 'icons/_nanomaps/tether_nanomap_z5.png', - //"tether_nanomap_z6.png" = 'icons/_nanomaps/tether_nanomap_z6.png', - //"tether_nanomap_z7.png" = 'icons/_nanomaps/tether_nanomap_z7.png', - //"tether_nanomap_z8.png" = 'icons/_nanomaps/tether_nanomap_z8.png', - //"tether_nanomap_z9.png" = 'icons/_nanomaps/tether_nanomap_z9.png', - //"tether_nanomap_z10.png" = 'icons/_nanomaps/tether_nanomap_z10.png', - //"tether_nanomap_z13.png" = 'icons/_nanomaps/tether_nanomap_z13.png', - //"tether_nanomap_z14.png" = 'icons/_nanomaps/tether_nanomap_z14.png', - //"stellardelight_nanomap_z1.png" = 'icons/_nanomaps/sd_deck1.png', - //"stellardelight_nanomap_z2.png" = 'icons/_nanomaps/sd_deck2.png', - //"stellardelight_nanomap_z3.png" = 'icons/_nanomaps/sd_deck3.png', - //"groundbase_nanomap_z1.png" = 'icons/_nanomaps/gb1.png', - //"groundbase_nanomap_z2.png" = 'icons/_nanomaps/gb2.png', - //"groundbase_nanomap_z3.png" = 'icons/_nanomaps/gb3.png', - //"groundbase_nanomap_z4.png" = 'icons/_nanomaps/gbnorth.png', - //"groundbase_nanomap_z5.png" = 'icons/_nanomaps/gbsouth.png', - //"groundbase_nanomap_z6.png" = 'icons/_nanomaps/gbeast.png', - //"groundbase_nanomap_z7.png" = 'icons/_nanomaps/gbwest.png', - //"groundbase_nanomap_z10.png" = 'icons/_nanomaps/gbmining.png', - "cryogaia_nanomap_z2.png" = 'icons/_nanomaps/cryogaia_nanomap_z2.png', - "cryogaia_nanomap_z3.png" = 'icons/_nanomaps/cryogaia_nanomap_z3.png', - "cryogaia_nanomap_z4.png" = 'icons/_nanomaps/cryogaia_nanomap_z4.png', - "cryogaia_nanomap_z5.png" = 'icons/_nanomaps/cryogaia_nanomap_z5.png', - "cryogaia_nanomap_z6.png" = 'icons/_nanomaps/cryogaia_nanomap_z6.png', - "cryogaia_nanomap_z13.png" = 'icons/_nanomaps/cryogaia_nanomap_z13.png', - // YW Edit End - - ) diff --git a/code/modules/asset_cache/assets/browser.dm b/code/modules/asset_cache/assets/browser.dm new file mode 100644 index 0000000000..8d5b4da198 --- /dev/null +++ b/code/modules/asset_cache/assets/browser.dm @@ -0,0 +1,43 @@ +/datum/asset/simple/generic + assets = list( + "search.js" = 'html/search.js', + "panels.css" = 'html/panels.css', + "loading.gif" = 'html/images/loading.gif', + "ntlogo.png" = 'html/images/ntlogo.png', + "sglogo.png" = 'html/images/sglogo.png', + "talisman.png" = 'html/images/talisman.png', + "paper_bg.png" = 'html/images/paper_bg.png', + "no_image32.png" = 'html/images/no_image32.png', + ) + +/datum/asset/simple/changelog + assets = list( + "88x31.png" = 'html/88x31.png', + "bug-minus.png" = 'html/bug-minus.png', + "cross-circle.png" = 'html/cross-circle.png', + "hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png', + "image-minus.png" = 'html/image-minus.png', + "image-plus.png" = 'html/image-plus.png', + "map-pencil.png" = 'html/map-pencil.png', + "music-minus.png" = 'html/music-minus.png', + "music-plus.png" = 'html/music-plus.png', + "tick-circle.png" = 'html/tick-circle.png', + "wrench-screwdriver.png" = 'html/wrench-screwdriver.png', + "spell-check.png" = 'html/spell-check.png', + "burn-exclamation.png" = 'html/burn-exclamation.png', + "chevron.png" = 'html/chevron.png', + "chevron-expand.png" = 'html/chevron-expand.png', + "changelog.css" = 'html/changelog.css', + "changelog.js" = 'html/changelog.js', + "changelog.html" = 'html/changelog.html' + ) + +/datum/asset/simple/arcade + assets = list( + "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif', + "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif', + "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif', + "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif', + "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif', + "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif', + ) diff --git a/code/modules/asset_cache/assets/cloning.dm b/code/modules/asset_cache/assets/cloning.dm new file mode 100644 index 0000000000..152a5041c5 --- /dev/null +++ b/code/modules/asset_cache/assets/cloning.dm @@ -0,0 +1,14 @@ +//Cloning pod sprites for UIs +/datum/asset/simple/cloning + assets = list( + "pod_idle.gif" = 'icons/UI_Icons/synthprinter.gif', + "pod_cloning.gif" = 'icons/UI_Icons/synthprinter_working.gif', + ) + +/datum/asset/simple/cloning/resleeving + assets = list( + "sleeve_empty.gif" = 'icons/UI_Icons/sleeve_empty.gif', + "sleeve_occupied.gif" = 'icons/UI_Icons/sleeve_occupied.gif', + "synthprinter.gif" = 'icons/UI_Icons/synthprinter.gif', + "synthprinter_working.gif" = 'icons/UI_Icons/synthprinter_working.gif', + ) diff --git a/code/modules/asset_cache/assets/kitchen_recipes.dm b/code/modules/asset_cache/assets/kitchen_recipes.dm deleted file mode 100644 index 2cca2ed670..0000000000 --- a/code/modules/asset_cache/assets/kitchen_recipes.dm +++ /dev/null @@ -1,26 +0,0 @@ -/datum/asset/spritesheet/kitchen_recipes - name = "kitchen_recipes" - -/datum/asset/spritesheet/kitchen_recipes/create_spritesheets() - for(var/datum/recipe/R as anything in subtypesof(/datum/recipe)) - add_atom_icon(R.result, sanitize_css_class_name("[R.type]")) - -/datum/asset/spritesheet/kitchen_recipes/proc/add_atom_icon(typepath, id) - var/icon_file - var/icon_state - var/obj/preview_item = typepath - - // if(ispath(ingredient_typepath, /datum/reagent)) - // var/datum/reagent/reagent = ingredient_typepath - // preview_item = initial(reagent.default_container) - // var/datum/glass_style/style = GLOB.glass_style_singletons[preview_item]?[reagent] - // if(istype(style)) - // icon_file = style.icon - // icon_state = style.icon_state - - // icon_file ||= initial(preview_item.icon_preview) || initial(preview_item.icon) - // icon_state ||= initial(preview_item.icon_state_preview) || initial(preview_item.icon_state) - icon_file = initial(preview_item.icon) - icon_state = initial(preview_item.icon_state) - - Insert("[id]", icon_file, icon_state) diff --git a/code/modules/asset_cache/assets/ntos.dm b/code/modules/asset_cache/assets/ntos.dm new file mode 100644 index 0000000000..92fbc163d6 --- /dev/null +++ b/code/modules/asset_cache/assets/ntos.dm @@ -0,0 +1,30 @@ +/datum/asset/simple/headers + assets = list( + "alarm_green.gif" = 'icons/program_icons/alarm_green.gif', + "alarm_red.gif" = 'icons/program_icons/alarm_red.gif', + "batt_5.gif" = 'icons/program_icons/batt_5.gif', + "batt_20.gif" = 'icons/program_icons/batt_20.gif', + "batt_40.gif" = 'icons/program_icons/batt_40.gif', + "batt_60.gif" = 'icons/program_icons/batt_60.gif', + "batt_80.gif" = 'icons/program_icons/batt_80.gif', + "batt_100.gif" = 'icons/program_icons/batt_100.gif', + "charging.gif" = 'icons/program_icons/charging.gif', + "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif', + "downloader_running.gif" = 'icons/program_icons/downloader_running.gif', + "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif', + "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif', + "power_norm.gif" = 'icons/program_icons/power_norm.gif', + "power_warn.gif" = 'icons/program_icons/power_warn.gif', + "sig_high.gif" = 'icons/program_icons/sig_high.gif', + "sig_low.gif" = 'icons/program_icons/sig_low.gif', + "sig_lan.gif" = 'icons/program_icons/sig_lan.gif', + "sig_none.gif" = 'icons/program_icons/sig_none.gif', + "smmon_0.gif" = 'icons/program_icons/smmon_0.gif', + "smmon_1.gif" = 'icons/program_icons/smmon_1.gif', + "smmon_2.gif" = 'icons/program_icons/smmon_2.gif', + "smmon_3.gif" = 'icons/program_icons/smmon_3.gif', + "smmon_4.gif" = 'icons/program_icons/smmon_4.gif', + "smmon_5.gif" = 'icons/program_icons/smmon_5.gif', + "smmon_6.gif" = 'icons/program_icons/smmon_6.gif', + // "borg_mon.gif" = 'icons/program_icons/borg_mon.gif' + ) diff --git a/code/modules/asset_cache/assets/chat.dm b/code/modules/asset_cache/assets/spritesheets/chat.dm similarity index 100% rename from code/modules/asset_cache/assets/chat.dm rename to code/modules/asset_cache/assets/spritesheets/chat.dm diff --git a/code/modules/asset_cache/assets/spritesheets/chem_master.dm b/code/modules/asset_cache/assets/spritesheets/chem_master.dm new file mode 100644 index 0000000000..f066d4b17e --- /dev/null +++ b/code/modules/asset_cache/assets/spritesheets/chem_master.dm @@ -0,0 +1,10 @@ +//Pill sprites for UIs +/datum/asset/spritesheet/chem_master + name = "chem_master" + +/datum/asset/spritesheet/chem_master/create_spritesheets() + for(var/i = 1 to 24) + Insert("pill[i]", 'icons/obj/chemical.dmi', "pill[i]") + + for(var/i = 1 to 4) + Insert("bottle-[i]", 'icons/obj/chemical.dmi', "bottle-[i]") diff --git a/code/modules/asset_cache/assets/spritesheets/kitchen_recipes.dm b/code/modules/asset_cache/assets/spritesheets/kitchen_recipes.dm new file mode 100644 index 0000000000..4fe048a84e --- /dev/null +++ b/code/modules/asset_cache/assets/spritesheets/kitchen_recipes.dm @@ -0,0 +1,13 @@ +/datum/asset/spritesheet_batched/kitchen_recipes + name = "kitchen_recipes" + +/datum/asset/spritesheet_batched/kitchen_recipes/create_spritesheets() + for(var/datum/recipe/R as anything in subtypesof(/datum/recipe)) + var/key = sanitize_css_class_name("[R.type]") + + var/atom/item = R.result + var/datum/universal_icon/icon = get_display_icon_for(item) + if(!icon || !icon.icon_file) + continue + + insert_icon(key, icon) diff --git a/code/modules/asset_cache/assets/spritesheets/nanomaps.dm b/code/modules/asset_cache/assets/spritesheets/nanomaps.dm new file mode 100644 index 0000000000..049d19a536 --- /dev/null +++ b/code/modules/asset_cache/assets/spritesheets/nanomaps.dm @@ -0,0 +1,38 @@ +/datum/asset/simple/nanomaps + // It REALLY doesnt matter too much if these arent up to date + // They are relatively big + assets = list( + // VOREStation Edit: We don't need Southern Cross + // "southern_cross_nanomap_z1.png" = 'icons/_nanomaps/southern_cross_nanomap_z1.png', + // "southern_cross_nanomap_z10.png" = 'icons/_nanomaps/southern_cross_nanomap_z10.png', + // "southern_cross_nanomap_z2.png" = 'icons/_nanomaps/southern_cross_nanomap_z2.png', + // "southern_cross_nanomap_z3.png" = 'icons/_nanomaps/southern_cross_nanomap_z3.png', + // "southern_cross_nanomap_z5.png" = 'icons/_nanomaps/southern_cross_nanomap_z5.png', + // "southern_cross_nanomap_z6.png" = 'icons/_nanomaps/southern_cross_nanomap_z6.png', + "tether_nanomap_z1.png" = 'icons/_nanomaps/tether_nanomap_z1.png', + "tether_nanomap_z2.png" = 'icons/_nanomaps/tether_nanomap_z2.png', + "tether_nanomap_z3.png" = 'icons/_nanomaps/tether_nanomap_z3.png', + "tether_nanomap_z4.png" = 'icons/_nanomaps/tether_nanomap_z4.png', + "tether_nanomap_z5.png" = 'icons/_nanomaps/tether_nanomap_z5.png', + "tether_nanomap_z6.png" = 'icons/_nanomaps/tether_nanomap_z6.png', + "tether_nanomap_z7.png" = 'icons/_nanomaps/tether_nanomap_z7.png', + "tether_nanomap_z8.png" = 'icons/_nanomaps/tether_nanomap_z8.png', + "tether_nanomap_z9.png" = 'icons/_nanomaps/tether_nanomap_z9.png', + "tether_nanomap_z10.png" = 'icons/_nanomaps/tether_nanomap_z10.png', + "tether_nanomap_z13.png" = 'icons/_nanomaps/tether_nanomap_z13.png', + "tether_nanomap_z14.png" = 'icons/_nanomaps/tether_nanomap_z14.png', + "stellardelight_nanomap_z1.png" = 'icons/_nanomaps/sd_deck1.png', + "stellardelight_nanomap_z2.png" = 'icons/_nanomaps/sd_deck2.png', + "stellardelight_nanomap_z3.png" = 'icons/_nanomaps/sd_deck3.png', + "groundbase_nanomap_z1.png" = 'icons/_nanomaps/gb1.png', + "groundbase_nanomap_z2.png" = 'icons/_nanomaps/gb2.png', + "groundbase_nanomap_z3.png" = 'icons/_nanomaps/gb3.png', + "groundbase_nanomap_z4.png" = 'icons/_nanomaps/gbnorth.png', + "groundbase_nanomap_z5.png" = 'icons/_nanomaps/gbsouth.png', + "groundbase_nanomap_z6.png" = 'icons/_nanomaps/gbeast.png', + "groundbase_nanomap_z7.png" = 'icons/_nanomaps/gbwest.png', + "groundbase_nanomap_z10.png" = 'icons/_nanomaps/gbmining.png', + + + // VOREStation Edit End + ) diff --git a/code/modules/asset_cache/assets/spritesheets/pipes.dm b/code/modules/asset_cache/assets/spritesheets/pipes.dm new file mode 100644 index 0000000000..b0f5935a95 --- /dev/null +++ b/code/modules/asset_cache/assets/spritesheets/pipes.dm @@ -0,0 +1,6 @@ +/datum/asset/spritesheet/pipes + name = "pipes" + +/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) diff --git a/code/modules/asset_cache/assets/spritesheets/robot_icons.dm b/code/modules/asset_cache/assets/spritesheets/robot_icons.dm new file mode 100644 index 0000000000..7935c5af7e --- /dev/null +++ b/code/modules/asset_cache/assets/spritesheets/robot_icons.dm @@ -0,0 +1,36 @@ +/datum/asset/spritesheet/robot_icons + name = "robot_icons" + +/datum/asset/spritesheet/robot_icons/create_spritesheets() + for(var/datum/robot_sprite/S as anything in typesof(/datum/robot_sprite)) + if(!S.name || !S.sprite_icon_state) // snowflake out those customs... they suck + continue + var/icon/I_N = icon(S.sprite_icon, S.sprite_icon_state, NORTH) + var/icon/I_S = icon(S.sprite_icon, S.sprite_icon_state, SOUTH) + var/icon/I_W = icon(S.sprite_icon, S.sprite_icon_state, WEST) + var/icon/I_E = icon(S.sprite_icon, S.sprite_icon_state, EAST) + if(S.has_eye_sprites) + var/icon/I_NE = icon(S.sprite_icon, "[S.sprite_icon_state]-eyes", NORTH) + if(I_NE) + I_N.Blend(I_NE, ICON_OVERLAY) + if(S.has_eye_sprites) + var/icon/I_SE = icon(S.sprite_icon, "[S.sprite_icon_state]-eyes", SOUTH) + if(I_SE) + I_S.Blend(I_SE, ICON_OVERLAY) + if(S.has_eye_sprites) + var/icon/I_WE = icon(S.sprite_icon, "[S.sprite_icon_state]-eyes", WEST) + if(I_WE) + I_W.Blend(I_WE, ICON_OVERLAY) + if(S.has_eye_sprites) + var/icon/I_EE = icon(S.sprite_icon, "[S.sprite_icon_state]-eyes", EAST) + if(I_EE) + I_E.Blend(I_EE, ICON_OVERLAY) + var/imgid = sanitize_css_class_name("[S.type]") + I_N.Scale(120, 120) + I_S.Scale(120, 120) + I_W.Scale(120, 120) + I_E.Scale(120, 120) + Insert(imgid + "N", I_N) + Insert(imgid + "S", I_S) + Insert(imgid + "W", I_W) + Insert(imgid + "E", I_E) diff --git a/code/modules/asset_cache/assets/spritesheets/stacks.dm b/code/modules/asset_cache/assets/spritesheets/stacks.dm new file mode 100644 index 0000000000..2dd3093663 --- /dev/null +++ b/code/modules/asset_cache/assets/spritesheets/stacks.dm @@ -0,0 +1,5 @@ +/datum/asset/spritesheet/sheetmaterials + name = "sheetmaterials" + +/datum/asset/spritesheet/sheetmaterials/create_spritesheets() + InsertAll("", 'icons/obj/stacks.dmi') diff --git a/code/modules/asset_cache/assets/spritesheets/vending.dm b/code/modules/asset_cache/assets/spritesheets/vending.dm new file mode 100644 index 0000000000..c1ceafd814 --- /dev/null +++ b/code/modules/asset_cache/assets/spritesheets/vending.dm @@ -0,0 +1,57 @@ +/datum/asset/spritesheet/vending + name = "vending" + +/datum/asset/spritesheet/vending/create_spritesheets() + populate_vending_products() + for(var/atom/item as anything in GLOB.vending_products) + if(!ispath(item, /atom)) + continue + + var/icon_file = initial(item.icon) + var/icon_state = initial(item.icon_state) + + // I really don't like the fact that I have to do this, but what the hell else *can* I do to make all of these + // random special items work? + if(ispath(item, /obj/item/reagent_containers/food/drinks/glass2) && !ispath(item, /obj/item/reagent_containers/food/drinks/glass2/fitnessflask)) + var/obj/item/reagent_containers/food/drinks/glass2/G = item + icon_state = initial(G.base_icon) + if(ispath(item, /obj/item/reagent_containers/hypospray/autoinjector)) + icon_state += "0" + + var/icon/I + + var/icon_states_list = icon_states(icon_file) + if(icon_state in icon_states_list) + I = icon(icon_file, icon_state, SOUTH) + var/c = initial(item.color) + if(!isnull(c) && c != "#FFFFFF") + I.Blend(c, ICON_MULTIPLY) + else + var/icon_states_string + for(var/an_icon_state in icon_states_list) + if(!icon_states_string) + icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])" + else + icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])" + stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]") + I = icon('icons/turf/floors.dmi', "", SOUTH) + + var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-") + + Insert(imgid, I) + +// 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 +// that they exist, and therefore can't generate the entries in the spritesheet for them +// and since assets are unique and can't be reloaded later, we have to make sure that GLOB.vending_products +// is populated with every single type of vending machine +// As this is only done at runtime, we have to create all the vending machines in existence and force them +// to register their products when this asset initializes. +/datum/asset/spritesheet/vending/proc/populate_vending_products() + SSatoms.map_loader_begin() + for(var/path in subtypesof(/obj/machinery/vending)) + var/obj/machinery/vending/x = new path(null) + // force an inventory build; with map_loader_begin active, init isn't called + x.build_inventory() + qdel(x) + SSatoms.map_loader_stop() diff --git a/code/modules/asset_cache/assets/spritesheets/vore.dm b/code/modules/asset_cache/assets/spritesheets/vore.dm new file mode 100644 index 0000000000..625043d89d --- /dev/null +++ b/code/modules/asset_cache/assets/spritesheets/vore.dm @@ -0,0 +1,15 @@ +/datum/asset/spritesheet/vore + name = "vore" + +/datum/asset/spritesheet/vore/create_spritesheets() + var/icon/downscaled = icon('icons/mob/screen_full_vore.dmi') + downscaled.Scale(240, 240) + InsertAll("", downscaled) + +/datum/asset/spritesheet/vore_colorized //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. + name = "colorizedvore" + +/datum/asset/spritesheet/vore_colorized/create_spritesheets() + var/icon/downscaledVC = icon('icons/mob/screen_full_colorized_vore.dmi') + downscaledVC.Scale(240, 240) + InsertAll("", downscaledVC) diff --git a/code/modules/asset_cache/iconforge/batched_spritesheet.dm b/code/modules/asset_cache/iconforge/batched_spritesheet.dm new file mode 100644 index 0000000000..c49248f417 --- /dev/null +++ b/code/modules/asset_cache/iconforge/batched_spritesheet.dm @@ -0,0 +1,356 @@ +#define SPR_SIZE "size_id" +#define SPR_IDX "position" +#define CACHE_WAIT "wait" +#define CACHE_INVALID TRUE +#define CACHE_VALID FALSE + +#define WHATTHEFUCKAMIDOING_FILE "data/WHATTHEFUCKFILE.json" + +/datum/asset/spritesheet_batched + _abstract = /datum/asset/spritesheet_batched + var/name + /// list("32x32") + var/list/sizes = list() + /// "foo_bar" -> list("32x32", 5, entry_obj) + var/list/sprites = list() + + // "foo_bar" -> entry_obj + var/list/entries = list() + + /// JSON encoded version of entries. + var/entries_json = null + + /// If this spritesheet exists in a completed state. + 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 + /// If we should avoid propogating 'invalid dir' errors from rust-g. Because sometimes, you just don't know what dirs are valid. + var/ignore_dir_errors = FALSE + /// Avoid propogating 'Could not find associated icon state' errors because we know our input data fucking sucks + var/ignore_associated_icon_state_errors = FALSE + + /// Forces use of the smart cache. This is for unit tests, please respect the config <3 + var/force_cache = FALSE + + /// If there is currently an async job, its ID + var/job_id = null + /// If there is currently an async cache job, its ID. + var/cache_job_id = null + + // Fields to store async cache task inputs. + var/cache_data = null + var/cache_sizes_data = null + var/cache_sprites_data = null + var/cache_input_hash = null + var/cache_dmi_hashes = null + var/cache_dmi_hashes_json = null + /// Used to prevent async cache refresh jobs from looping on failure. + var/cache_result = null + +/datum/asset/spritesheet_batched/proc/should_load_immediately() +#ifdef DO_NOT_DEFER_ASSETS + return TRUE +#else + return load_immediately +#endif + +/// Returns true if the cache should be invalidated/doesn't exist. +/datum/asset/spritesheet_batched/should_refresh(yield) + . = CACHE_INVALID // in the case of any errors, we need to regenerate. + if(!fexists("[ASSET_CROSS_ROUND_SMART_CACHE_DIRECTORY]/spritesheet_cache.[name].json")) + return CACHE_INVALID + if(!fexists("data/spritesheets/spritesheet_[name].css")) + return CACHE_INVALID + if(isnull(cache_data) || isnull(cache_dmi_hashes_json)) + cache_data = rustg_file_read("[ASSET_CROSS_ROUND_SMART_CACHE_DIRECTORY]/spritesheet_cache.[name].json") + if(!findtext(cache_data, "{", 1, 2)) // cache isn't valid JSON + log_asset("Cache for spritesheet_[name] was not valid JSON. This is abnormal. Likely tampered with or IO failure.") + return CACHE_INVALID + var/cache_json = json_decode(cache_data) + // Best to invalidate if rustg updates, since the way icons are handled can change. + var/cached_rustg_version = cache_json["rustg_version"] + if(isnull(cached_rustg_version)) + log_asset("Cache for spritesheet_[name] did not contain a rustg_version!") + return CACHE_INVALID + var/rustg_version = rustg_get_version() + if(cached_rustg_version != rustg_version) + log_asset("Invalidated cache for spritesheet_[name] due to rustg updating from [cached_rustg_version] to [rustg_version].") + return CACHE_INVALID + cache_sizes_data = cache_json["sizes"] + cache_sprites_data = cache_json["sprites"] + cache_input_hash = cache_json["input_hash"] + cache_dmi_hashes = cache_json["dmi_hashes"] + if(!length(cache_dmi_hashes) || !length(cache_input_hash) || !length(cache_sizes_data) || !length(cache_sprites_data)) + log_asset("Cache for spritesheet_[name] did not contain the correct data. This is abnormal. Likely tampered with.") + return CACHE_INVALID + cache_dmi_hashes_json = json_encode(cache_dmi_hashes) + var/data_out + + if(yield || !isnull(cache_job_id)) + if(isnull(cache_job_id)) + cache_job_id = rustg_iconforge_cache_valid_async(cache_input_hash, cache_dmi_hashes_json, entries_json) + . = CACHE_WAIT // if we return during this, WAIT!! + UNTIL((data_out = rustg_iconforge_check(cache_job_id)) != RUSTG_JOB_NO_RESULTS_YET) + cache_job_id = null + . = CACHE_INVALID // reset back to normal, invalid on CRASH + else + data_out = rustg_iconforge_cache_valid(cache_input_hash, cache_dmi_hashes_json, entries_json) + if (data_out == RUSTG_JOB_ERROR) + CRASH("Spritesheet [name] cache JOB PANIC") + else if(!findtext(data_out, "{", 1, 2)) + rustg_file_write(cache_data, "[log_path]-spritesheet_cache_debug.[name].json") + rustg_file_write(entries_json, "[log_path]-spritesheet_debug_[name].json") + CRASH("Spritesheet [name] cache check UNKNOWN ERROR: [data_out]") + var/result = json_decode(data_out) + var/fail = result["fail_reason"] + if(length(fail) || result["result"] != "1") + if(findtextEx(fail, "ERROR:")) + CRASH("Spritesheet [name] cache check UNKNOWN [fail]") + log_asset("Invalidated cache for spritesheet_[name]: [fail]") + return CACHE_INVALID + // Populate the sizes and sprites list. + sizes = cache_sizes_data + sprites = cache_sprites_data + log_asset("Validated cache for spritesheet_[name]!") + return CACHE_VALID + +/datum/asset/spritesheet_batched/proc/insert_icon(sprite_name, datum/universal_icon/entry) + if(!istext(sprite_name) || !length(sprite_name)) + CRASH("Invalid sprite_name \"[sprite_name]\" given to insert_icon()! Providing non-strings will break icon generation.") + entries[sprite_name] = entry.to_list() + +/datum/asset/spritesheet_batched/register() + SHOULD_NOT_OVERRIDE(TRUE) + + if (!name) + CRASH("spritesheet [type] cannot register without a name") + + // Create our input data first, so we can compare to the cache. + create_spritesheets() + + if(should_load_immediately()) + realize_spritesheets(yield = FALSE) + else + SSasset_loading.queue_asset(src) + +/datum/asset/spritesheet_batched/unregister() + CRASH("unregister() called on batched spritesheet! Bad!") + +/// Call insert_icon or insert_all_icons here, building a spritesheet! +/datum/asset/spritesheet_batched/proc/create_spritesheets() + SHOULD_CALL_PARENT(FALSE) + CRASH("create_spritesheets() not implemented for [type]!") + +/datum/asset/spritesheet_batched/proc/insert_all_icons(prefix, icon/I, list/directions, prefix_with_dirs = TRUE) + if (length(prefix)) + prefix = "[prefix]-" + + if (!directions) + directions = list(SOUTH) + + for (var/icon_state_name in icon_states(I)) + if(icon_state_name == "") + icon_state_name = "byond-default" + for (var/direction in directions) + var/prefix2 = (directions.len > 1 && prefix_with_dirs) ? "[dir2text(direction)]-" : "" + insert_icon("[prefix][prefix2][icon_state_name]", uni_icon(I, icon_state_name, direction)) + +/datum/asset/spritesheet_batched/proc/realize_spritesheets(yield) + if(fully_generated) + return + if(!length(entries)) + CRASH("Spritesheet [name] ([type]) is empty! What are you doing?") + + if(isnull(entries_json)) + entries_json = json_encode(entries) + + if(isnull(cache_result)) + cache_result = should_refresh(yield) + if(cache_result == CACHE_WAIT) // sleep interrupted by MC. We'll get queried again later. + cache_result = null + return + + // read_from_cache returns false if config is disabled, otherwise it fully loads the spritesheet. + if (cache_result == CACHE_VALID && read_from_cache()) + SSasset_loading.dequeue_asset(src) + fully_generated = TRUE + return + // Remove the cache, since it's invalid if we get to this point. + fdel("[ASSET_CROSS_ROUND_SMART_CACHE_DIRECTORY]/spritesheet_cache.[name].json") + + var/do_cache = CONFIG_GET(flag/smart_cache_assets) || force_cache + var/data_out + if(yield || !isnull(job_id)) + if(isnull(job_id)) + job_id = rustg_iconforge_generate_async("data/spritesheets/", name, entries_json, do_cache) + UNTIL((data_out = rustg_iconforge_check(job_id)) != RUSTG_JOB_NO_RESULTS_YET) + else + //rustg_file_write(entries_json, "fuckoff.json") + data_out = rustg_iconforge_generate("data/spritesheets/", name, entries_json, do_cache) + if (data_out == RUSTG_JOB_ERROR) + CRASH("Spritesheet [name] JOB PANIC") + else if(!findtext(data_out, "{", 1, 2)) + rustg_file_write(entries_json, "[log_path]-spritesheet_debug_[name].json") + CRASH("Spritesheet [name] UNKNOWN ERROR: [data_out]") + var/data = json_decode(data_out) + sizes = data["sizes"] + sprites = data["sprites"] + var/input_hash = data["sprites_hash"] + var/dmi_hashes = data["dmi_hashes"] // this only contains values if do_cache is TRUE. + + for(var/size_id in sizes) + var/file_path = "data/spritesheets/[name]_[size_id].png" + var/file_hash = rustg_hash_file("md5", file_path) + SSassets.transport.register_asset("[name]_[size_id].png", fcopy_rsc(file_path), file_hash) + var/res_name = "spritesheet_[name].css" + var/fname = "data/spritesheets/[res_name]" + + fdel(fname) + var/css = generate_css() + rustg_file_write(css, fname) + var/css_hash = rustg_hash_string("md5", css) + SSassets.transport.register_asset(res_name, fcopy_rsc(fname), file_hash=css_hash) + + if (do_cache) + write_cache_meta(input_hash, dmi_hashes) + fully_generated = TRUE + // If we were ever in there, remove ourselves + SSasset_loading.dequeue_asset(src) + if(data["error"]) + var/err = data["error"] + if(ignore_dir_errors && findtext(err, "is not in the set of valid dirs")) + return + if(ignore_associated_icon_state_errors && findtext(err, "Could not find associated icon state")) + return + CRASH("Error during spritesheet generation for [name]: [err]") + +/datum/asset/spritesheet_batched/queued_generation() + realize_spritesheets(yield = TRUE) + +/datum/asset/spritesheet_batched/ensure_ready() + if(!fully_generated) + realize_spritesheets(yield = FALSE) + return ..() + +/datum/asset/spritesheet_batched/send(client/client) + if (!name) + return + + var/all = list("spritesheet_[name].css") + for(var/size_id in sizes) + all += "[name]_[size_id].png" + . = SSassets.transport.send_assets(client, all) + +/datum/asset/spritesheet_batched/get_url_mappings() + if (!name) + return + + . = list("spritesheet_[name].css" = SSassets.transport.get_asset_url("spritesheet_[name].css")) + for(var/size_id in sizes) + .["[name]_[size_id].png"] = SSassets.transport.get_asset_url("[name]_[size_id].png") + +/datum/asset/spritesheet_batched/proc/generate_css() + var/list/out = list() + + for (var/size_id in sizes) + var/size_split = splittext(size_id, "x") + var/width = text2num(size_split[1]) + var/height = text2num(size_split[2]) + out += ".[name][size_id]{display:inline-block;width:[width]px;height:[height]px;background:url('[get_background_url("[name]_[size_id].png")]') no-repeat;}" + + for (var/sprite_id in sprites) + var/sprite = sprites[sprite_id] + var/size_id = sprite[SPR_SIZE] + var/idx = sprite[SPR_IDX] + + var/size_split = splittext(size_id, "x") + var/width = text2num(size_split[1]) + var/x = idx * width + var/y = 0 + + out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}" + + return out.Join("\n") + +/datum/asset/spritesheet_batched/proc/read_from_cache() + if(!CONFIG_GET(flag/smart_cache_assets) && !force_cache) + return FALSE + // this is already guaranteed to exist. + var/css_fname = "data/spritesheets/spritesheet_[name].css" + + // sizes gets filled during should_refresh() + for(var/size_id in sizes) + var/fname = "data/spritesheets/[name]_[size_id].png" + if(!fexists(fname)) + return FALSE + + var/css_hash = rustg_hash_file("md5", css_fname) + SSassets.transport.register_asset("spritesheet_[name].css", fcopy_rsc(css_fname), file_hash=css_hash) + for(var/size_id in sizes) + var/fname = "data/spritesheets/[name]_[size_id].png" + var/hash = rustg_hash_file("md5", fname) + SSassets.transport.register_asset("[name]_[size_id].png", fcopy_rsc(fname), file_hash=hash) + + return TRUE + +/// Returns the URL to put in the background:url of the CSS asset +/datum/asset/spritesheet_batched/proc/get_background_url(asset) + return SSassets.transport.get_asset_url(asset) + +/datum/asset/spritesheet_batched/proc/write_cache_meta(input_hash, dmi_hashes) + var/list/cache_data = list( + "input_hash" = input_hash, + "dmi_hashes" = dmi_hashes, + "sizes" = sizes, + "sprites" = sprites, + "rustg_version" = rustg_get_version() + ) + rustg_file_write(json_encode(cache_data), "[ASSET_CROSS_ROUND_SMART_CACHE_DIRECTORY]/spritesheet_cache.[name].json") + +/** + * Third party helpers + * =================== + */ + +/datum/asset/spritesheet_batched/proc/css_tag() + return {""} + +/datum/asset/spritesheet_batched/proc/css_filename() + return SSassets.transport.get_asset_url("spritesheet_[name].css") + +/datum/asset/spritesheet_batched/proc/icon_tag(sprite_name) + var/sprite = sprites[sprite_name] + if (!sprite) + return null + var/size_id = sprite[SPR_SIZE] + return "" + +/datum/asset/spritesheet_batched/proc/icon_class_name(sprite_name) + var/sprite = sprites[sprite_name] + if (!sprite) + return null + 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_batched/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 CACHE_WAIT +#undef CACHE_INVALID +#undef CACHE_VALID + +#undef WHATTHEFUCKAMIDOING_FILE diff --git a/code/modules/asset_cache/iconforge/universal_icon.dm b/code/modules/asset_cache/iconforge/universal_icon.dm new file mode 100644 index 0000000000..3446151c9b --- /dev/null +++ b/code/modules/asset_cache/iconforge/universal_icon.dm @@ -0,0 +1,186 @@ +/// This is intended to replace /icon, allowing rustg to generate icons much faster than DM can at scale. +/// Construct these with the uni_icon() proc, in the same manner as BYOND's icon() proc. +/// Additionally supports a number of transform procs (lowercase, rather than BYOND's uppercase) +/// such as Crop, Scale, and Blend (as blend_icon/blend_color). +/datum/universal_icon + var/icon/icon_file + var/icon_state + var/dir + var/frame + var/datum/icon_transformer/transform + +/// Don't instantiate these yourself, use uni_icon. +/datum/universal_icon/New(icon/icon_file, icon_state="", dir=SOUTH, frame=1, datum/icon_transformer/transform=null, color=null) + #ifdef UNIT_TESTS + // This check is kinda slow and shouldn't fail unless a developer makes a mistake. So it'll get caught in unit tests. + if(!isicon(icon_file) || !isfile(icon_file) || "[icon_file]" == "/icon") + // bad! use 'icons/path_to_dmi.dmi' format only + CRASH("FATAL: universal_icon was provided icon_file: [icon_file] - icons provided to batched spritesheets MUST be DMI files, they cannot be /image, /icon, or other runtime generated icons.") + #endif + src.icon_file = icon_file + src.icon_state = icon_state + src.dir = dir + src.frame = frame + if(isnull(transform) && !isnull(color) && uppertext(color) != "#FFFFFF") + var/datum/icon_transformer/T = new() + if(color) + T.blend_color(color, ICON_MULTIPLY) + src.transform = T + else if(!isnull(transform)) + src.transform = transform + else // null = empty list + src.transform = null + +/datum/universal_icon/proc/copy() + RETURN_TYPE(/datum/universal_icon) + var/datum/universal_icon/new_icon = new(icon_file, icon_state, dir, frame) + if(!isnull(src.transform)) + new_icon.transform = src.transform.copy() + return new_icon + +/datum/universal_icon/proc/blend_color(color, blend_mode) + if(!transform) + transform = new + transform.blend_color(color, blend_mode) + return src + +/datum/universal_icon/proc/blend_icon(datum/universal_icon/icon_object, blend_mode) + if(!transform) + transform = new + transform.blend_icon(icon_object, blend_mode) + return src + +/datum/universal_icon/proc/scale(width, height) + if(!transform) + transform = new + transform.scale(width, height) + return src + +/datum/universal_icon/proc/crop(x1, y1, x2, y2) + if(!transform) + transform = new + transform.crop(x1, y1, x2, y2) + return src + +/datum/universal_icon/proc/to_list() + RETURN_TYPE(/list) + return list("icon_file" = "[icon_file]", "icon_state" = icon_state, "dir" = dir, "frame" = frame, "transform" = !isnull(transform) ? transform.to_list() : list()) + +/proc/universal_icon_from_list(list/input_in) + RETURN_TYPE(/datum/universal_icon) + var/list/input = input_in.Copy() // copy, since icon_transformer_from_list will mutate the list. + return uni_icon(input["icon_file"], input["icon_state"], input["dir"], input["frame"], icon_transformer_from_list(input["transform"])) + +/datum/universal_icon/proc/to_json() + return json_encode(to_list()) + +/datum/universal_icon/proc/to_icon() + RETURN_TYPE(/icon) + var/icon/self = icon(src.icon_file, src.icon_state, dir=src.dir, frame=src.frame) + if(istype(src.transform)) + src.transform.apply(self) + return self + +/datum/icon_transformer + var/list/transforms = null + +/datum/icon_transformer/New() + transforms = list() + +/// Applies the contained set of transforms to an icon +/datum/icon_transformer/proc/apply(icon/target) + RETURN_TYPE(/icon) + for(var/transform in src.transforms) + switch(transform["type"]) + if(RUSTG_ICONFORGE_BLEND_COLOR) + target.Blend(target["color"], target["blend_mode"]) + if(RUSTG_ICONFORGE_BLEND_ICON) + var/datum/universal_icon/icon_object = target["icon"] + if(!istype(icon_object)) + stack_trace("Invalid icon found in icon transformer during apply()! [icon_object]") + continue + target.Blend(icon_object.to_icon(), target["blend_mode"]) + if(RUSTG_ICONFORGE_SCALE) + target.Scale(target["width"], target["height"]) + if(RUSTG_ICONFORGE_CROP) + target.Crop(target["x1"], target["y1"], target["x2"], target["y2"]) + return target + +/datum/icon_transformer/proc/copy() + RETURN_TYPE(/datum/icon_transformer) + var/datum/icon_transformer/new_transformer = new() + new_transformer.transforms = list() + for(var/transform in src.transforms) + new_transformer.transforms += list(deep_copy_list_alt(transform)) + return new_transformer + +/datum/icon_transformer/proc/blend_color(color, blend_mode) + transforms += list(list("type" = RUSTG_ICONFORGE_BLEND_COLOR, "color" = color, "blend_mode" = blend_mode)) + +/datum/icon_transformer/proc/blend_icon(datum/universal_icon/icon_object, blend_mode) + transforms += list(list("type" = RUSTG_ICONFORGE_BLEND_ICON, "icon" = icon_object, "blend_mode" = blend_mode)) + +/datum/icon_transformer/proc/scale(width, height) + transforms += list(list("type" = RUSTG_ICONFORGE_SCALE, "width" = width, "height" = height)) + +/datum/icon_transformer/proc/crop(x1, y1, x2, y2) + transforms += list(list("type" = RUSTG_ICONFORGE_CROP, "x1" = x1, "y1" = y1, "x2" = x2, "y2" = y2)) + +/datum/icon_transformer/proc/to_list() + RETURN_TYPE(/list) + var/list/transforms_out = list() + for(var/transform in src.transforms.Copy()) + var/this_transform = transform + if(transform["type"] == RUSTG_ICONFORGE_BLEND_ICON) + var/datum/universal_icon/icon_object = this_transform["icon"] + if(!istype(icon_object)) + stack_trace("Invalid icon found in icon transformer during to_list()! [icon_object]") + continue + this_transform["icon"] = icon_object.to_list() + transforms_out += list(this_transform) + return transforms_out + +/proc/icon_transformer_from_list(list/input) + RETURN_TYPE(/datum/icon_transformer) + var/list/transforms = list() + for(var/transform in input) + var/this_transform = transform + if(transform["type"] == RUSTG_ICONFORGE_BLEND_ICON) + this_transform["icon"] = universal_icon_from_list(transform["icon"]) + transforms += list(this_transform) + var/datum/icon_transformer/transformer = new() + transformer.transforms = transforms + return transformer + +/// Constructs a transformer, with optional color multiply pre-added. +/proc/color_transform(color=null) + RETURN_TYPE(/datum/icon_transformer) + var/datum/icon_transformer/transform = new() + if(color) + transform.blend_color(color, ICON_MULTIPLY) + return transform + +/// Converts a GAGS item to a universal icon by generating blend operations. +// /proc/gags_to_universal_icon(obj/item/path) +// RETURN_TYPE(/datum/universal_icon) +// if(!ispath(path, /obj/item) || !initial(path.greyscale_config) || !initial(path.greyscale_colors)) +// CRASH("gags_to_universal_icon() received an invalid path!") +// var/datum/greyscale_config/config = initial(path.greyscale_config) +// var/colors = initial(path.greyscale_colors) +// var/datum/universal_icon/entry = SSgreyscale.GetColoredIconEntryByType(config, colors, initial(path.icon_state)) +// return entry + +/// Gets the relevant universal icon for an atom, when displayed in TGUI. (see: icon_state_preview) +/// Supports GAGS items and colored items. +/proc/get_display_icon_for(atom/A) + if (!ispath(A, /atom)) + return FALSE + var/icon_file = initial(A.icon) + var/icon_state = initial(A.icon_state) + // if(ispath(A, /obj/item)) + // var/obj/item/I = A + // if(initial(I.icon_state_preview)) + // icon_state = initial(I.icon_state_preview) + // if(initial(I.greyscale_config) && initial(I.greyscale_colors)) + // return gags_to_universal_icon(I) + return uni_icon(icon_file, icon_state, color=initial(A.color)) diff --git a/code/modules/asset_cache/transports/asset_transport.dm b/code/modules/asset_cache/transports/asset_transport.dm index db19277abf..77daee2a60 100644 --- a/code/modules/asset_cache/transports/asset_transport.dm +++ b/code/modules/asset_cache/transports/asset_transport.dm @@ -1,6 +1,3 @@ -/// 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" @@ -59,6 +56,10 @@ SSassets.cache[asset_name] = ACI return ACI +/// Immediately removes an asset from the asset cache. +/datum/asset_transport/proc/unregister_asset(asset_name) + SSassets.cache[asset_name] = null + SSassets.cache.Remove(null) /// Returns a url for a given asset. /// asset_name - Name of the asset. @@ -66,6 +67,8 @@ /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] + if (!istype(asset_cache_item)) + return null // 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 \ @@ -82,6 +85,9 @@ /// 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 defined(UNIT_TESTS) + return +#endif if (!istype(client)) if (ismob(client)) var/mob/M = client @@ -143,7 +149,7 @@ /// 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) +/datum/asset_transport/proc/send_assets_slow(client/client, list/files, filerate = SLOW_ASSET_SEND_RATE) var/startingfilerate = filerate for (var/file in files) if (!client) diff --git a/code/modules/asset_cache/transports/webroot_transport.dm b/code/modules/asset_cache/transports/webroot_transport.dm index e3cb33b8fa..d67d097b0b 100644 --- a/code/modules/asset_cache/transports/webroot_transport.dm +++ b/code/modules/asset_cache/transports/webroot_transport.dm @@ -16,7 +16,7 @@ /// 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) +/datum/asset_transport/webroot/register_asset(asset_name, asset, file_hash, dmi_file_path) . = ..() var/datum/asset_cache_item/ACI = . diff --git a/code/modules/clothing/suits/hooded.dm b/code/modules/clothing/suits/hooded.dm index aa7d1bf8fb..9efe8ab494 100644 --- a/code/modules/clothing/suits/hooded.dm +++ b/code/modules/clothing/suits/hooded.dm @@ -44,6 +44,7 @@ /obj/item/clothing/suit/storage/hooded/dropped() RemoveHood() + ..() /obj/item/clothing/suit/storage/hooded/proc/ToggleHood() if(!hood_up) diff --git a/code/modules/food/kitchen/microwave.dm b/code/modules/food/kitchen/microwave.dm index 9cd7ccd1bc..9ebc0c15a5 100644 --- a/code/modules/food/kitchen/microwave.dm +++ b/code/modules/food/kitchen/microwave.dm @@ -253,7 +253,7 @@ /obj/machinery/microwave/ui_assets(mob/user) return list( - get_asset_datum(/datum/asset/spritesheet/kitchen_recipes) + get_asset_datum(/datum/asset/spritesheet_batched/kitchen_recipes) ) /obj/machinery/microwave/tgui_static_data(mob/user) diff --git a/code/modules/mob/_modifiers/feysight.dm b/code/modules/mob/_modifiers/feysight.dm index 5ff99307b9..0cf07c935f 100644 --- a/code/modules/mob/_modifiers/feysight.dm +++ b/code/modules/mob/_modifiers/feysight.dm @@ -13,10 +13,12 @@ /datum/modifier/feysight/on_applied() holder.see_invisible = 60 holder.see_invisible_default = 60 + holder.plane_holder.set_vis(VIS_GHOSTS,TRUE) /datum/modifier/feysight/on_expire() holder.see_invisible_default = initial(holder.see_invisible_default) holder.see_invisible = holder.see_invisible_default + holder.plane_holder.set_vis(VIS_GHOSTS,FALSE) /datum/modifier/feysight/can_apply(var/mob/living/L) if(L.stat) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 556c04083c..c278fcefa5 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -36,6 +36,7 @@ incorporeal_move = 1 var/is_manifest = 0 //If set to 1, the ghost is able to whisper. Usually only set if a cultist drags them through the veil. + var/toggled_invisible = 0 var/ghost_sprite = null var/global/list/possible_ghost_sprites = list( "Clear" = "blank", @@ -841,15 +842,19 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/observer/dead/proc/manifest(mob/user) is_manifest = TRUE - add_verb(src, /mob/observer/dead/proc/toggle_visibility) - add_verb(src, /mob/observer/dead/proc/ghost_whisper) + // Allows them to use the 'toggle_visibility' verb add_verb(src, /mob/observer/dead/verb/toggle_visibility) + // Allows them to use the 'ghost whisper' verb add_verb(src, /mob/observer/dead/verb/ghost_whisper) to_chat(src, span_filter_notice(span_purple("As you are now in the realm of the living, you can whisper to the living with the " + span_bold("Spectral Whisper") + " verb, inside the IC tab."))) + if(!user) + visible_message(span_deadsay("The ghost of \the [src] is dragged back in to our plane of reality!")) + toggle_ghost_visibility(TRUE) + return if(plane != PLANE_WORLD) user.visible_message( \ span_warning("\The [user] drags ghost, [src], to our plane of reality!"), \ span_warning("You drag [src] to our plane of reality!") \ ) - toggle_visibility(TRUE) + toggle_ghost_visibility(TRUE) else var/datum/gender/T = gender_datums[user.get_visible_gender()] user.visible_message ( \ @@ -871,12 +876,17 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/image/J = image('icons/mob/mob.dmi', loc = src, icon_state = icon) client.images += J -/mob/observer/dead/proc/toggle_visibility(var/forced = 0) - set category = "Ghost.Settings" +/mob/observer/dead/verb/toggle_visibility() + set name = "Toggle Visibility" set desc = "Allows you to turn (in)visible (almost) at will." + set category = "Ghost.Settings" + toggle_ghost_visibility() - var/toggled_invisible +/mob/observer/dead/proc/toggle_ghost_visibility(var/forced = FALSE) + if(!is_manifest) + to_chat(src, span_filter_notice("You are not strong enough to pierce the veil...")) + return if(!forced && plane == PLANE_GHOSTS && world.time < toggled_invisible + 600) to_chat(src, span_filter_notice("You must gather strength before you can turn visible again...")) return @@ -972,7 +982,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp //Culted Ghosts -/mob/observer/dead/proc/ghost_whisper() +/mob/observer/dead/verb/ghost_whisper() set name = "Spectral Whisper" set category = "IC.Subtle" @@ -992,7 +1002,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return return 1 else - to_chat(src, span_danger("You have not been pulled past the veil!")) + to_chat(src, span_danger("You have not been pulled past the veil! You can not whisper to the living.")) /mob/observer/dead/verb/choose_ghost_sprite() set category = "Ghost.Settings" diff --git a/code/modules/mob/living/carbon/carbon_powers.dm b/code/modules/mob/living/carbon/carbon_powers.dm index d6fdc94788..284224604d 100644 --- a/code/modules/mob/living/carbon/carbon_powers.dm +++ b/code/modules/mob/living/carbon/carbon_powers.dm @@ -60,3 +60,23 @@ else to_chat(src, span_warning("You do not have enough chemicals stored to reproduce.")) return + +/mob/living/proc/toggle_active_cloaking() // Borrowed from Rogue Star, thanks guys! + set category = "Abilities.General" + set name = "Toggle Active Cloaking" + + if(invisibility == INVISIBILITY_OBSERVER) + invisibility = initial(invisibility) + to_chat(src, span_notice("You are now visible.")) + alpha = max(alpha + 100, 255) + else + invisibility = INVISIBILITY_OBSERVER + to_chat(src, span_notice("You are now invisible.")) + alpha = max(alpha - 100, 0) + + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(5, 0, src) + sparks.attach(loc) + sparks.start() + visible_message(span_warning("Electrical sparks manifest around \the [src] as they suddenly appear!")) + qdel(sparks) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 338c72451f..2cc6a561ea 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -302,3 +302,4 @@ . = ..() if(. && (species.tail || tail_style)) update_tail_showing() + update_inv_wear_suit() diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index d23aa3d781..bd97cc2e0c 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1631,7 +1631,11 @@ else //We aren't dead sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) - see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : see_invisible_default + + if(see_invisible_default > SEE_INVISIBLE_LEVEL_ONE) + see_invisible = see_invisible_default + else + see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : see_invisible_default // Do this early so certain stuff gets turned off before vision is assigned. var/area/A = get_area(src) @@ -1659,7 +1663,10 @@ else sight = species.get_vision_flags(src) see_in_dark = species.darksight - see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : see_invisible_default + if(see_invisible_default > SEE_INVISIBLE_LEVEL_ONE) + see_invisible = see_invisible_default + else + see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : see_invisible_default var/glasses_processed = 0 var/obj/item/rig/rig = get_rig() @@ -1673,7 +1680,8 @@ if(XRAY in mutations) sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS see_in_dark = 8 - if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO + if(!druggy) + see_invisible = SEE_INVISIBLE_LEVEL_TWO for(var/datum/modifier/M in modifiers) if(!isnull(M.vision_flags)) diff --git a/code/modules/mob/living/default_language.dm b/code/modules/mob/living/default_language.dm index 66cdcb28ad..ff72f448f1 100644 --- a/code/modules/mob/living/default_language.dm +++ b/code/modules/mob/living/default_language.dm @@ -5,30 +5,34 @@ set name = "Set Default Language" set category = "IC.Settings" - var/language = tgui_input_list(usr, "Select your default language", "Available languages", languages) + if(!LAZYLEN(languages)) + to_chat(src, span_warning("You can't speak any languages.")) + return + + var/language = tgui_input_list(src, "Select your default language", "Available languages", languages) + if(!language) + return apply_default_language(language) // Silicons can't neccessarily speak everything in their languages list /mob/living/silicon/set_default_language() - var/language = tgui_input_list(usr, "Select your default language", "Available languages", speech_synthesizer_langs) - // Silicons have no species language usually. So let's default them to GALCOM - if(!language) - to_chat(src, span_notice("You will now speak your standard default language, common, if you do not specify a language when speaking.")) - for(var/datum/language/lang in speech_synthesizer_langs) - if(lang.name == LANGUAGE_GALCOM) - default_language = lang - break + if(!LAZYLEN(speech_synthesizer_langs)) + to_chat(src, span_warning("You can't speak any languages.")) return + var/language = tgui_input_list(src, "Select your default language", "Available languages", speech_synthesizer_langs) + if(!language) + return + apply_default_language(language) /mob/living/proc/apply_default_language(var/language) - if (only_species_language && language != GLOB.all_languages[src.species_language]) - to_chat(src, span_notice("You can only speak your species language, [src.species_language].")) + if (only_species_language && language != GLOB.all_languages[species_language]) + to_chat(src, span_notice("You can only speak your species language, [species_language].")) return 0 - if(language == GLOB.all_languages[src.species_language]) - to_chat(src, span_notice("You will now speak your standard default language, [language ? language : "common"], if you do not specify a language when speaking.")) + if(language == GLOB.all_languages[species_language]) + to_chat(src, span_notice("You will now speak your standard default language, [language], if you do not specify a language when speaking.")) else if (language) if(language && !can_speak(language)) diff --git a/code/modules/mob/living/silicon/pai/pai_vr.dm b/code/modules/mob/living/silicon/pai/pai_vr.dm index 49d34c454e..3db2418ce2 100644 --- a/code/modules/mob/living/silicon/pai/pai_vr.dm +++ b/code/modules/mob/living/silicon/pai/pai_vr.dm @@ -1,5 +1,4 @@ /mob/living/silicon/pai - var/people_eaten = 0 icon = 'icons/mob/pai_vr.dmi' softfall = TRUE var/eye_glow = TRUE @@ -156,14 +155,18 @@ add_eyes() return update_fullness() - if(!people_eaten && !resting) + //Add a check when selecting a chassis if you add in support for this, to set vore_capacity to 2 or however many states you have. + var/fullness_extension = "" + if(vore_capacity > 1 && vore_fullness > 1) + fullness_extension = "_[vore_fullness]" + if(!vore_fullness && !resting) icon_state = "[chassis]" - else if(!people_eaten && resting) + else if(!vore_fullness && resting) icon_state = "[chassis]_rest" - else if(people_eaten && !resting) - icon_state = "[chassis]_full" - else if(people_eaten && resting) - icon_state = "[chassis]_rest_full" + else if(vore_fullness && !resting) + icon_state = "[chassis]_full[fullness_extension]" + else if(vore_fullness && resting) + icon_state = "[chassis]_rest_full[fullness_extension]" if(chassis in wide_chassis) pixel_x = -16 default_pixel_x = -16 diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 8f0b9a3412..032fe3ed43 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -24,6 +24,7 @@ var/crisis //Admin-settable for combat module use. var/crisis_override = 0 var/integrated_light_power = 6 + var/robotdecal_on = 0 var/datum/wires/robot/wires can_be_antagged = TRUE @@ -443,6 +444,13 @@ handle_light() update_icon() +/mob/living/silicon/robot/verb/toggle_robot_decals() // loads overlay UNDER lights. + set category = "Abilities.Silicon" + set name = "Toggle extras" + robotdecal_on = !robotdecal_on + to_chat(usr, span_filter_notice("You [robotdecal_on ? "enable" : "disable"] your extra apperances.")) + update_icon() + /mob/living/silicon/robot/verb/spark_plug() //So you can still sparkle on demand without violence. set category = "Abilities.Silicon" set name = "Emit Sparks" @@ -956,6 +964,12 @@ if(eyes_overlay) add_overlay(eyes_overlay) + if(robotdecal_on && sprite_datum.has_robotdecal_sprites) + if(!shell || deployed) // Shell borgs that are not deployed will have no eyes. + var/robotdecal_overlay = sprite_datum.get_robotdecal_overlay(src) + if(robotdecal_overlay) + add_overlay(robotdecal_overlay) + if(lights_on && sprite_datum.has_eye_light_sprites) if(!shell || deployed) // Shell borgs that are not deployed will have no eyes. var/eyes_overlay = sprite_datum.get_eye_light_overlay(src) diff --git a/code/modules/mob/living/silicon/robot/robot_ui_module.dm b/code/modules/mob/living/silicon/robot/robot_ui_module.dm index ba69581df5..ef1545831c 100644 --- a/code/modules/mob/living/silicon/robot/robot_ui_module.dm +++ b/code/modules/mob/living/silicon/robot/robot_ui_module.dm @@ -42,7 +42,7 @@ modules.Add(shell_module_types) else modules.Add(robot_module_types) - if(R.crisis || security_level == SEC_LEVEL_RED || R.crisis_override) + if(R.crisis || security_level >= SEC_LEVEL_RED || R.crisis_override) to_chat(R, span_red("Crisis mode active. Combat module available.")) modules |= emergency_module_types for(var/module_name in whitelisted_module_types) diff --git a/code/modules/mob/living/silicon/robot/sprites/_sprite_datum.dm b/code/modules/mob/living/silicon/robot/sprites/_sprite_datum.dm index 0d8135fe3e..8fe2277b0f 100644 --- a/code/modules/mob/living/silicon/robot/sprites/_sprite_datum.dm +++ b/code/modules/mob/living/silicon/robot/sprites/_sprite_datum.dm @@ -10,6 +10,7 @@ var/has_eye_sprites = TRUE var/has_eye_light_sprites = FALSE + var/has_robotdecal_sprites = FALSE var/has_custom_open_sprites = FALSE var/has_vore_belly_sprites = FALSE var/has_vore_belly_resting_sprites = FALSE @@ -131,6 +132,12 @@ else return +/datum/robot_sprite/proc/get_robotdecal_overlay(var/mob/living/silicon/robot/ourborg) + if(!(ourborg.resting && has_rest_sprites)) + return "[sprite_icon_state]-decals" + else + return + /datum/robot_sprite/proc/get_rest_sprite(var/mob/living/silicon/robot/ourborg) if(!(ourborg.rest_style in rest_sprite_options)) ourborg.rest_style = "Default" @@ -181,21 +188,7 @@ has_dead_sprite_overlay = TRUE has_custom_equipment_sprites = TRUE pixel_x = -16 -/* //Does not need to be dogborg-only, letting all borgs use these -Reo -/datum/robot_sprite/dogborg/get_rest_sprite(var/mob/living/silicon/robot/ourborg) - if(!(ourborg.rest_style in rest_sprite_options)) - ourborg.rest_style = "Default" - switch(ourborg.rest_style) - if("Sit") - return "[sprite_icon_state]-sit" - if("Bellyup") - return "[sprite_icon_state]-bellyup" - else - return "[sprite_icon_state]-rest" -/datum/robot_sprite/dogborg/get_belly_overlay(var/mob/living/silicon/robot/ourborg) - return "[sprite_icon_state]-sleeper" -*/ /datum/robot_sprite/dogborg/do_equipment_glamour(var/obj/item/robot_module/module) if(!has_custom_equipment_sprites) return diff --git a/code/modules/mob/living/silicon/robot/sprites/civilian.dm b/code/modules/mob/living/silicon/robot/sprites/civilian.dm index d4b2664e63..05a0333d7d 100644 --- a/code/modules/mob/living/silicon/robot/sprites/civilian.dm +++ b/code/modules/mob/living/silicon/robot/sprites/civilian.dm @@ -308,6 +308,27 @@ has_vore_belly_sprites = FALSE rest_sprite_options = list("Default", "Bellyup") +/datum/robot_sprite/dogborg/tall/service/dullahan + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + //named v3 to avoid conflicts with downstream + +/datum/robot_sprite/dogborg/tall/service/dullahan/basic + name = "Dullahan service v3" + sprite_icon_state = "dullahanservice" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") + +/datum/robot_sprite/dogborg/tall/service/dullahanv3/barista + name = "Dullahan matcha v3" + sprite_icon_state = "dullahanbarista" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") // Clerical diff --git a/code/modules/mob/living/silicon/robot/sprites/engineering.dm b/code/modules/mob/living/silicon/robot/sprites/engineering.dm index 99ebeedb25..9ffaa658de 100644 --- a/code/modules/mob/living/silicon/robot/sprites/engineering.dm +++ b/code/modules/mob/living/silicon/robot/sprites/engineering.dm @@ -212,4 +212,17 @@ has_eye_light_sprites = TRUE has_custom_open_sprites = TRUE has_vore_belly_sprites = FALSE - rest_sprite_options = list("Default", "Bellyup") \ No newline at end of file + rest_sprite_options = list("Default", "Bellyup") + +/datum/robot_sprite/dogborg/tall/engineering/dullahanv3 + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + //named v3 to avoid conflicts with downstream + +/datum/robot_sprite/dogborg/tall/engineering/dullahanv3/engineerdully + name = "Dullahan engineer v3" + sprite_icon_state = "dullahanengineer" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") diff --git a/code/modules/mob/living/silicon/robot/sprites/janitor.dm b/code/modules/mob/living/silicon/robot/sprites/janitor.dm index e634df2d29..cdc5f817ce 100644 --- a/code/modules/mob/living/silicon/robot/sprites/janitor.dm +++ b/code/modules/mob/living/silicon/robot/sprites/janitor.dm @@ -191,10 +191,23 @@ has_vore_belly_sprites = FALSE rest_sprite_options = list("Default", "Bellyup") -/datum/robot_sprite/dogborg/tall/mining/k4t_alt1 +/datum/robot_sprite/dogborg/tall/janitor/k4t_alt1 name = "K4T Alt" sprite_icon_state = "k4t_alt1" has_eye_light_sprites = TRUE has_custom_open_sprites = TRUE has_vore_belly_sprites = FALSE rest_sprite_options = list("Default", "Bellyup") + +/datum/robot_sprite/dogborg/tall/janitor/dullahanv3 + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + //named v3 to avoid conflicts with downstream + +/datum/robot_sprite/dogborg/tall/janitor/dullahanv3/janitordully + name = "Dullahan janitor v3" + sprite_icon_state = "dullahanjanitor" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") diff --git a/code/modules/mob/living/silicon/robot/sprites/medical.dm b/code/modules/mob/living/silicon/robot/sprites/medical.dm index 1a058aada4..f53b9894a2 100644 --- a/code/modules/mob/living/silicon/robot/sprites/medical.dm +++ b/code/modules/mob/living/silicon/robot/sprites/medical.dm @@ -137,6 +137,18 @@ has_vore_belly_sprites = FALSE rest_sprite_options = list("Default", "Bellyup") +/datum/robot_sprite/dogborg/tall/medical/dullahanv3 + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + //named v3 to avoid conflicts with downstream + +/datum/robot_sprite/dogborg/tall/medical/dullahanv3/medicaldully + name = "Dullahan medical v3" + sprite_icon_state = "dullahanmedical" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") // Surgeon diff --git a/code/modules/mob/living/silicon/robot/sprites/mining.dm b/code/modules/mob/living/silicon/robot/sprites/mining.dm index fba89f2c9e..d074a510a6 100644 --- a/code/modules/mob/living/silicon/robot/sprites/mining.dm +++ b/code/modules/mob/living/silicon/robot/sprites/mining.dm @@ -182,4 +182,17 @@ has_eye_light_sprites = TRUE has_custom_open_sprites = TRUE has_vore_belly_sprites = FALSE - rest_sprite_options = list("Default", "Bellyup") \ No newline at end of file + rest_sprite_options = list("Default", "Bellyup") + +/datum/robot_sprite/dogborg/tall/mining/dullahanv3 + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + //named v3 to avoid conflicts with downstream + +/datum/robot_sprite/dogborg/tall/mining/dullahanv3/miningdully + name = "Dullahan mining v3" + sprite_icon_state = "dullahanmining" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") diff --git a/code/modules/mob/living/silicon/robot/sprites/science.dm b/code/modules/mob/living/silicon/robot/sprites/science.dm index ee6ffdc178..51159d9cb3 100644 --- a/code/modules/mob/living/silicon/robot/sprites/science.dm +++ b/code/modules/mob/living/silicon/robot/sprites/science.dm @@ -205,3 +205,16 @@ has_custom_open_sprites = TRUE has_vore_belly_sprites = FALSE rest_sprite_options = list("Default", "Bellyup") + +/datum/robot_sprite/dogborg/tall/science/dullahanv3 + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + //named v3 to avoid conflicts with downstream + +/datum/robot_sprite/dogborg/tall/science/dullahanv3/sciencedully + name = "Dullahan science v3" + sprite_icon_state = "dullahanscience" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") diff --git a/code/modules/mob/living/silicon/robot/sprites/security.dm b/code/modules/mob/living/silicon/robot/sprites/security.dm index 3a8cd71e07..8ddd148260 100644 --- a/code/modules/mob/living/silicon/robot/sprites/security.dm +++ b/code/modules/mob/living/silicon/robot/sprites/security.dm @@ -211,3 +211,16 @@ has_custom_open_sprites = TRUE has_vore_belly_sprites = FALSE rest_sprite_options = list("Default", "Bellyup") + +/datum/robot_sprite/dogborg/tall/security/dullahanv3 + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + //named v3 to avoid conflicts with downstream + +/datum/robot_sprite/dogborg/tall/security/dullahanv3/securitydully + name = "Dullahan security v3" + sprite_icon_state = "dullahansecurity" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") diff --git a/code/modules/mob/living/silicon/robot/sprites/standard.dm b/code/modules/mob/living/silicon/robot/sprites/standard.dm index 6678633003..0190d40a67 100644 --- a/code/modules/mob/living/silicon/robot/sprites/standard.dm +++ b/code/modules/mob/living/silicon/robot/sprites/standard.dm @@ -126,4 +126,21 @@ sprite_icon = 'icons/mob/robot/standard_large.dmi' // None yet -*/ \ No newline at end of file +*/ + +/datum/robot_sprite/dogborg/tall/standard + module_type = "Standard" + //sprite_icon = 'icons/mob/robot/standard_large.dmi' NOT USED YET + +/datum/robot_sprite/dogborg/tall/standard/dullahanv3 + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + //named v3 to avoid conflicts with downstream + +/datum/robot_sprite/dogborg/tall/standard/dullahanv3/standarddully + name = "Dullahan standard v3" + sprite_icon_state = "dullahanstandard" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") diff --git a/code/modules/mob/living/silicon/robot/sprites/syndicate.dm b/code/modules/mob/living/silicon/robot/sprites/syndicate.dm index 86d1a0ade3..685d934225 100644 --- a/code/modules/mob/living/silicon/robot/sprites/syndicate.dm +++ b/code/modules/mob/living/silicon/robot/sprites/syndicate.dm @@ -69,6 +69,15 @@ has_vore_belly_sprites = FALSE rest_sprite_options = list("Default", "Bellyup") +/datum/robot_sprite/dogborg/tall/syndie/dullahanv3syndi + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + sprite_icon_state = "dullahansyndi" + name = "Dullahan syndie v3" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") // Protector @@ -158,6 +167,16 @@ sprite_icon = 'icons/mob/robot/syndie_large.dmi' sprite_hud_icon_state = "malf" +/datum/robot_sprite/dogborg/tall/mechanist/dullahanv3mech + sprite_icon = 'icons/mob/tallborg/dullahans64x64.dmi' + sprite_icon_state = "dullahanmechanist" + name = "Dullahan mechanist v3" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = TRUE + has_robotdecal_sprites = TRUE + rest_sprite_options = list("Default", "sit") + /datum/robot_sprite/dogborg/tall/mechanist/syndimechraptor name = "Raptor V-4" sprite_icon_state = "syndimechraptor" diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 3f917a15ce..9ee2d05f50 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -33,7 +33,7 @@ silicon_mob_list |= src ..() add_language(LANGUAGE_GALCOM) - set_default_language(GLOB.all_languages[LANGUAGE_GALCOM]) + apply_default_language(GLOB.all_languages[LANGUAGE_GALCOM]) init_id() init_subsystems() diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/pakkun.dm b/code/modules/mob/living/simple_mob/subtypes/vore/pakkun.dm index ba0e5becbe..d64d84e250 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/pakkun.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/pakkun.dm @@ -81,11 +81,13 @@ return if(resting) - vore_selected.digest_mode = DM_UNABSORB + if(isbelly(vore_selected)) + vore_selected.digest_mode = DM_UNABSORB ai_holder.go_sleep() else - vore_selected.digest_mode = vore_default_mode + if(isbelly(vore_selected)) + vore_selected.digest_mode = vore_default_mode ai_holder.go_wake() /mob/living/simple_mob/vore/pakkun/attack_hand(mob/user) diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm index 3924029ece..9f8c640874 100644 --- a/code/modules/mob/living/voice/voice.dm +++ b/code/modules/mob/living/voice/voice.dm @@ -9,7 +9,7 @@ /mob/living/voice/Initialize(loc) add_language(LANGUAGE_GALCOM) - set_default_language(GLOB.all_languages[LANGUAGE_GALCOM]) + apply_default_language(GLOB.all_languages[LANGUAGE_GALCOM]) if(istype(loc, /obj/item/communicator)) comm = loc diff --git a/code/modules/organs/subtypes/machine.dm b/code/modules/organs/subtypes/machine.dm index bbd7513240..7cdff12d42 100644 --- a/code/modules/organs/subtypes/machine.dm +++ b/code/modules/organs/subtypes/machine.dm @@ -46,12 +46,15 @@ stored_mmi = null return ..() -/obj/item/organ/internal/mmi_holder/New(var/mob/living/carbon/human/new_owner, var/internal) +/obj/item/organ/internal/mmi_holder/New(var/mob/living/carbon/human/new_owner, var/internal, var/obj/item/mmi/installed) ..(new_owner, internal) var/mob/living/carbon/human/dummy/mannequin/M = new_owner if(istype(M)) return - stored_mmi = new brain_type(src) + if(installed) + stored_mmi = installed + else + stored_mmi = new brain_type(src) sleep(-1) update_from_mmi() diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm index ab5551855b..8c6795f67f 100644 --- a/code/modules/surgery/robotics.dm +++ b/code/modules/surgery/robotics.dm @@ -491,20 +491,18 @@ var/obj/item/mmi/M = tool // VOREstation edit begin - Select the proper mmi holder subtype based on the brain inserted var/obj/item/organ/internal/mmi_holder/holder = null + user.drop_from_inventory(M) + M.loc = holder if(istype(M,/obj/item/mmi/digital/posibrain/nano)) - holder = new /obj/item/organ/internal/mmi_holder/posibrain/nano(target, 1) + holder = new /obj/item/organ/internal/mmi_holder/posibrain/nano(target, 1, M) else if(istype(M,/obj/item/mmi/digital/posibrain)) - holder = new /obj/item/organ/internal/mmi_holder/posibrain(target, 1) + holder = new /obj/item/organ/internal/mmi_holder/posibrain(target, 1, M) else if(istype(M,/obj/item/mmi/digital/robot)) - holder = new /obj/item/organ/internal/mmi_holder/robot(target, 1) + holder = new /obj/item/organ/internal/mmi_holder/robot(target, 1, M) else - holder = new /obj/item/organ/internal/mmi_holder(target, 1) // Fallback to old behavior if organic MMI or if no subtype exists. - //VOREstation edit end + holder = new /obj/item/organ/internal/mmi_holder(target, 1, M) // Fallback to old behavior if organic MMI or if no subtype exists. + //VOREstation edit end target.internal_organs_by_name["brain"] = holder - user.drop_from_inventory(tool) - tool.loc = holder - holder.stored_mmi = tool - holder.update_from_mmi() if(M.brainmob && M.brainmob.mind) M.brainmob.mind.transfer_to(target) diff --git a/code/modules/tgui/tgui_window.dm b/code/modules/tgui/tgui_window.dm index 9e0a5491ab..3bae28e39c 100644 --- a/code/modules/tgui/tgui_window.dm +++ b/code/modules/tgui/tgui_window.dm @@ -322,7 +322,10 @@ if(istype(asset, /datum/asset/spritesheet)) var/datum/asset/spritesheet/spritesheet = asset send_message("asset/stylesheet", spritesheet.css_filename()) - send_message("asset/mappings", asset.get_url_mappings()) + else if(istype(asset, /datum/asset/spritesheet_batched)) + var/datum/asset/spritesheet_batched/spritesheet = asset + send_message("asset/stylesheet", spritesheet.css_filename()) + send_raw_message(asset.get_serialized_url_mappings()) /** * private diff --git a/code/modules/vore/eating/bellymodes_datum_vr.dm b/code/modules/vore/eating/bellymodes_datum_vr.dm index 54c2ff9c10..3fd14c2ec6 100644 --- a/code/modules/vore/eating/bellymodes_datum_vr.dm +++ b/code/modules/vore/eating/bellymodes_datum_vr.dm @@ -142,10 +142,10 @@ GLOBAL_LIST_INIT(digest_modes, list()) if(L.size_multiplier > B.shrink_grow_size && B.owner.size_multiplier < 2) //Grow until either pred is large or prey is small. B.owner.resize(B.owner.size_multiplier + 0.01) //Grow by 1% per tick. if(B.owner.size_multiplier >= 2) // Adds some feedback so the pred knows they can't grow anymore. - to_chat(B.owner, span_notice("You feel you have grown as much as you can.")) + to_chat(B.owner, span_vnotice("You feel you have grown as much as you can.")) L.resize(L.size_multiplier - 0.01) //Shrink by 1% per tick if(L.size_multiplier <= B.shrink_grow_size) // Adds some feedback so the pred knows their prey has stopped shrinking. - to_chat(B.owner, span_notice("You feel [L] get as small as you would like within your [lowertext(B.name)].")) + to_chat(B.owner, span_vnotice("You feel [L] get as small as you would like within your [lowertext(B.name)].")) B.owner.update_fullness() . = ..() diff --git a/config/example/resources.txt b/config/example/resources.txt index f9a536e341..338cbcd408 100644 --- a/config/example/resources.txt +++ b/config/example/resources.txt @@ -31,6 +31,13 @@ ## but enabled on production (the default). #CACHE_ASSETS +## Enables 'smart' asset caching, for assets that support it. +## This is a type of asset cache that automatically invalidates itself based on inputs to the asset generation. +## It lowers the generation cost and is safe to enable on development and production. +## This cache is only cleared by the game or manually, but it shouldn't affect the results. +## This setting is independent of `CACHE_ASSETS`, they do not affect each other whatsoever. +SMART_CACHE_ASSETS + ## If this is uncommented, we will save all associated spritesheet PNGs and CSS files to a folder in the round-specific logs folder. ## Useful for developers to debug potential spritesheet issues to determine where the issue is cropping up (either in DM-side sprite generation or in the TGUI-side display of said spritesheet). ## Will only seek to waste disk space if ran on production. diff --git a/dependencies.sh b/dependencies.sh index 57e14e9c8c..89b861043f 100644 --- a/dependencies.sh +++ b/dependencies.sh @@ -5,10 +5,13 @@ # byond version export BYOND_MAJOR=515 -export BYOND_MINOR=1637 +export BYOND_MINOR=1647 + +# Macro Count +export MACRO_COUNT=8 #rust_g git tag -export RUST_G_VERSION=3.3.0 +export RUST_G_VERSION=3.5.1 #node version export NODE_VERSION_LTS=20.13.0 diff --git a/icons/mob/tallborg/dullahan_credit.txt b/icons/mob/tallborg/dullahan_credit.txt new file mode 100644 index 0000000000..588de68ad0 --- /dev/null +++ b/icons/mob/tallborg/dullahan_credit.txt @@ -0,0 +1,13 @@ + +Credit: +these sprites were originally made by: +- https://github.com/Cecily-C-Catherine +- Toriate +and was partly canabalized from meka. +: for bubberstation + +----------------------- + + +the original sprites were recolored and edited by asher-49 and MAK for chompstation, then downstreamed to virgo. +- animations made by asher-49 diff --git a/icons/mob/tallborg/dullahans64x64.dmi b/icons/mob/tallborg/dullahans64x64.dmi new file mode 100644 index 0000000000..fe06ae0645 Binary files /dev/null and b/icons/mob/tallborg/dullahans64x64.dmi differ diff --git a/icons/mob/tallborg/dullahans64x64.txt b/icons/mob/tallborg/dullahans64x64.txt new file mode 100644 index 0000000000..f064111edc --- /dev/null +++ b/icons/mob/tallborg/dullahans64x64.txt @@ -0,0 +1,3 @@ +the work in this file was done by asher-49 ckey. asher-42 on GitHub. + +original design / base sprite artist info is dullahan_credit.txt \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlAbilities.tsx b/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlAbilities.tsx index 366c44cb66..5a187f228c 100644 --- a/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlAbilities.tsx +++ b/tgui/packages/tgui/interfaces/PlayerEffects/PlayerEffectsTabs/ControlAbilities.tsx @@ -45,6 +45,9 @@ export const ControlAbilities = (props) => { + ); }; diff --git a/tgui/public/tgui.html b/tgui/public/tgui.html index 476d48763c..67f357ef57 100644 --- a/tgui/public/tgui.html +++ b/tgui/public/tgui.html @@ -315,6 +315,7 @@ var node = document.createElement('link'); node.type = 'text/css'; node.rel = 'stylesheet'; + node.crossOrigin = 'anonymous'; node.href = url; // Temporarily set media to something inapplicable // to ensure it'll fetch without blocking render diff --git a/tools/ci/build_tgui.sh b/tools/ci/build_tgui.sh index 8eea60c083..774e4a838b 100755 --- a/tools/ci/build_tgui.sh +++ b/tools/ci/build_tgui.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -source _build_dependencies.sh +source dependencies.sh source ~/.nvm/nvm.sh nvm use $NODE_VERSION diff --git a/tools/ci/install_byond.sh b/tools/ci/install_byond.sh index b11c7387f5..4a688755d3 100755 --- a/tools/ci/install_byond.sh +++ b/tools/ci/install_byond.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -source _build_dependencies.sh +source dependencies.sh if [ -d "$HOME/BYOND/byond/bin" ] && grep -Fxq "${BYOND_MAJOR}.${BYOND_MINOR}" $HOME/BYOND/version.txt; then @@ -18,4 +18,4 @@ else make here echo "$BYOND_MAJOR.$BYOND_MINOR" > "$HOME/BYOND/version.txt" cd ~/ -fi \ No newline at end of file +fi diff --git a/tools/ci/install_rust_g.sh b/tools/ci/install_rust_g.sh new file mode 100644 index 0000000000..c237162d8f --- /dev/null +++ b/tools/ci/install_rust_g.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +source dependencies.sh + +mkdir -p ~/.byond/bin +wget -nv -O ~/.byond/bin/librust_g.so "https://github.com/tgstation/rust-g/releases/download/$RUST_G_VERSION/librust_g.so" +chmod +x ~/.byond/bin/librust_g.so +ldd ~/.byond/bin/librust_g.so diff --git a/tools/ci/install_spaceman_dmm.sh b/tools/ci/install_spaceman_dmm.sh index afd89b17b0..d92dca4e95 100755 --- a/tools/ci/install_spaceman_dmm.sh +++ b/tools/ci/install_spaceman_dmm.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -source _build_dependencies.sh +source dependencies.sh if [ ! -f ~/$1 ]; then mkdir -p "$HOME/SpacemanDMM" @@ -16,4 +16,4 @@ if [ ! -f ~/$1 ]; then ln -s "$CACHEFILE" ~/$1 fi -~/$1 --version \ No newline at end of file +~/$1 --version diff --git a/tools/ci/validate_files.sh b/tools/ci/validate_files.sh index 462df7dfdb..c63aed9037 100755 --- a/tools/ci/validate_files.sh +++ b/tools/ci/validate_files.sh @@ -4,7 +4,7 @@ set -euo pipefail # nb: must be bash to support shopt globstar shopt -s globstar extglob -source _build_dependencies.sh +source dependencies.sh # ANSI Colors RED='\033[0;31m' diff --git a/vorestation.dme b/vorestation.dme index 331a05f737..e07df198e6 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -39,6 +39,7 @@ #include "code\__defines\appearance.dm" #include "code\__defines\assemblies.dm" #include "code\__defines\assert.dm" +#include "code\__defines\assets.dm" #include "code\__defines\atmos.dm" #include "code\__defines\atoms_movable.dm" #include "code\__defines\belly_modes_vr.dm" @@ -2023,16 +2024,27 @@ #include "code\modules\asset_cache\asset_cache_client.dm" #include "code\modules\asset_cache\asset_cache_item.dm" #include "code\modules\asset_cache\asset_list.dm" -#include "code\modules\asset_cache\asset_list_items.dm" -#include "code\modules\asset_cache\assets\chat.dm" +#include "code\modules\asset_cache\assets\browser.dm" #include "code\modules\asset_cache\assets\circuits.dm" +#include "code\modules\asset_cache\assets\cloning.dm" #include "code\modules\asset_cache\assets\fontawesome.dm" #include "code\modules\asset_cache\assets\icon_ref_map.dm" #include "code\modules\asset_cache\assets\jquery.dm" -#include "code\modules\asset_cache\assets\kitchen_recipes.dm" +#include "code\modules\asset_cache\assets\ntos.dm" #include "code\modules\asset_cache\assets\preferences.dm" #include "code\modules\asset_cache\assets\tgfont.dm" #include "code\modules\asset_cache\assets\tgui.dm" +#include "code\modules\asset_cache\assets\spritesheets\chat.dm" +#include "code\modules\asset_cache\assets\spritesheets\chem_master.dm" +#include "code\modules\asset_cache\assets\spritesheets\kitchen_recipes.dm" +#include "code\modules\asset_cache\assets\spritesheets\nanomaps.dm" +#include "code\modules\asset_cache\assets\spritesheets\pipes.dm" +#include "code\modules\asset_cache\assets\spritesheets\robot_icons.dm" +#include "code\modules\asset_cache\assets\spritesheets\stacks.dm" +#include "code\modules\asset_cache\assets\spritesheets\vending.dm" +#include "code\modules\asset_cache\assets\spritesheets\vore.dm" +#include "code\modules\asset_cache\iconforge\batched_spritesheet.dm" +#include "code\modules\asset_cache\iconforge\universal_icon.dm" #include "code\modules\asset_cache\transports\asset_transport.dm" #include "code\modules\asset_cache\transports\webroot_transport.dm" #include "code\modules\awaymissions\bluespaceartillery.dm"