diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 00000000000..2c261a62216 --- /dev/null +++ b/.gitconfig @@ -0,0 +1,8 @@ +[merge "merge-dmm"] + name = mapmerge driver + driver = ./tools/mapmerger/mapmerge.sh %O %A %B + recursive = text + +[merge "merge-dmi"] + name = iconfile merge driver + driver = ./tools/dmitool/dmimerge.sh %O %A %B diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index 553b2101e1b..a80404a2fcf 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -13,20 +13,11 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - - name: Restore SpacemanDMM cache - uses: actions/cache@v3 + - name: Setup cache + uses: actions/cache@v2 with: - path: ~/SpacemanDMM - key: ${{ runner.os }}-spacemandmm-${{ secrets.CACHE_PURGE_KEY }} - # - name: Restore Yarn cache - # uses: actions/cache@v3 - # with: - # path: tgui/.yarn/cache - # key: ${{ runner.os }}-yarn-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('tgui/yarn.lock') }} - # restore-keys: | - # ${{ runner.os }}-build-${{ secrets.CACHE_PURGE_KEY }}- - # ${{ runner.os }}-build- - # ${{ runner.os }}- + path: $HOME/SpacemanDMM + key: ${{ runner.os }}-spacemandmm - name: Install Tools run: | pip3 install setuptools @@ -37,7 +28,6 @@ jobs: run: | bash tools/ci/check_filedirs.sh cev_eris.dme bash tools/ci/check_grep.sh - bash tools/ci/check_misc.sh tools/bootstrap/python -m dmi.test tools/bootstrap/python -m mapmerge2.dmm_test ~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1 @@ -53,17 +43,17 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - - name: Restore BYOND cache - uses: actions/cache@v3 + - name: Setup cache + uses: actions/cache@v2 with: - path: ~/BYOND - key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }} + path: $HOME/BYOND + key: ${{ runner.os }}-byond - name: Compile All Maps run: | bash tools/ci/install_byond.sh source $HOME/BYOND/byond/bin/byondsetup - tools/build/build --ci dm -DCIBUILDING -DCITESTING -DALL_MAPS - + python3 tools/ci/template_dm_generator.py + tools/build/build dm -DCIBUILDING -DCITESTING -DALL_MAPS run_all_tests: if: "!contains(github.event.head_commit.message, '[ci skip]')" name: Integration Tests @@ -78,11 +68,11 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - uses: actions/checkout@v2 - - name: Restore BYOND cache - uses: actions/cache@v3 + - name: Setup cache + uses: actions/cache@v2 with: - path: ~/BYOND - key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }} + path: $HOME/BYOND + key: ${{ runner.os }}-byond - name: Setup database run: | sudo systemctl start mysql @@ -94,31 +84,18 @@ jobs: sudo apt update || true sudo apt install -o APT::Immediate-Configure=false libssl1.1:i386 bash tools/ci/install_rust_g.sh - - name: Compile Tests + - name: Compile and run tests run: | bash tools/ci/install_byond.sh source $HOME/BYOND/byond/bin/byondsetup - tools/build/build --ci dm -DCIBUILDING -DANSICOLORS - - name: Run Tests - run: | - source $HOME/BYOND/byond/bin/byondsetup - bash tools/ci/run_server.sh ${{ matrix.map }} - + tools/build/build -DCIBUILDING + bash tools/ci/run_server.sh test_windows: if: "!contains(github.event.head_commit.message, '[ci skip]')" name: Windows Build runs-on: windows-latest steps: - uses: actions/checkout@v2 - - name: Restore Yarn cache - uses: actions/cache@v3 - with: - path: tgui/.yarn/cache - key: ${{ runner.os }}-yarn-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('tgui/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-build-${{ secrets.CACHE_PURGE_KEY }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: Compile run: pwsh tools/ci/build.ps1 env: diff --git a/.github/workflows/conflicts.yml b/.github/workflows/conflicts.yml index cfc332b3097..95ac68f967f 100644 --- a/.github/workflows/conflicts.yml +++ b/.github/workflows/conflicts.yml @@ -11,4 +11,3 @@ jobs: with: CONFLICT_LABEL_NAME: 'Merge Conflict' GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - WAIT_MS: 10000 diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml index bd0759ad4fc..c1b7a2d5e13 100644 --- a/.github/workflows/generate_documentation.yml +++ b/.github/workflows/generate_documentation.yml @@ -3,30 +3,24 @@ on: push: branches: - master -permissions: - contents: read - jobs: generate_documentation: - permissions: - contents: write # for JamesIves/github-pages-deploy-action to push changes in repo if: "!contains(github.event.head_commit.message, '[ci skip]')" runs-on: ubuntu-20.04 - concurrency: gen-docs steps: - uses: actions/checkout@v2 - name: Setup cache uses: actions/cache@v2 with: - path: ~/SpacemanDMM - key: ${{ runner.os }}-spacemandmm-${{ secrets.CACHE_PURGE_KEY }} + path: $HOME/SpacemanDMM + key: ${{ runner.os }}-spacemandmm - name: Install SpacemanDMM run: bash tools/ci/install_spaceman_dmm.sh dmdoc - name: Generate documentation run: | ~/dmdoc touch dmdoc/.nojekyll - echo codedocs.cev-eris.net > dmdoc/CNAME + echo codedocs.tgstation13.org > dmdoc/CNAME - name: Deploy uses: JamesIves/github-pages-deploy-action@3.7.1 with: diff --git a/.gitignore b/.gitignore index ff8369853a1..125fd2e5805 100644 --- a/.gitignore +++ b/.gitignore @@ -16,11 +16,8 @@ #Ignore compiled files and other files generated during compilation. *.mdme -*.mdme.* *.dmb *.rsc -*.m.dme -*.test.dme *.lk *.int *.backup diff --git a/BUILD.bat b/BUILD.bat new file mode 100644 index 00000000000..8225158e4d8 --- /dev/null +++ b/BUILD.bat @@ -0,0 +1,2 @@ +@call "%~dp0\tools\build\build" +@pause diff --git a/Build.bat b/Build.bat deleted file mode 100644 index 68eaef0c2d3..00000000000 --- a/Build.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -call "%~dp0\tools\build\build.bat" %* -pause diff --git a/Build.sh b/Build.sh deleted file mode 100755 index f36de6e9d0a..00000000000 --- a/Build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -cd "$(dirname "$(readlink -f "$0")")" -cd ./tools/build -sudo bash ./build diff --git a/SpacemanDMM.toml b/SpacemanDMM.toml index 66076d83802..2518c2e3308 100755 --- a/SpacemanDMM.toml +++ b/SpacemanDMM.toml @@ -1,14 +1,5 @@ -environment = "cev_eris.dme" - -[langserver] -dreamchecker = true - -[code_standards] -# disallow_relative_type_definitions = true -# disallow_relative_proc_definitions = true - -[dmdoc] -use_typepath_names = true - -[debugger] -engine = "auxtools" +[langserver] +dreamchecker = true + +[debugger] +engine = "auxtools" diff --git a/bin/build.cmd b/bin/build.cmd deleted file mode 100644 index 98c2ef45e15..00000000000 --- a/bin/build.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error build %* diff --git a/bin/clean.cmd b/bin/clean.cmd deleted file mode 100644 index 8eacd92ebd7..00000000000 --- a/bin/clean.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error clean-all %* diff --git a/bin/server.cmd b/bin/server.cmd deleted file mode 100644 index c6e6642baf4..00000000000 --- a/bin/server.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error server %* diff --git a/bin/test.cmd b/bin/test.cmd deleted file mode 100644 index a76a9c6745c..00000000000 --- a/bin/test.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error dm-test %* diff --git a/bin/tgui-bench.cmd b/bin/tgui-bench.cmd deleted file mode 100644 index 333115f7954..00000000000 --- a/bin/tgui-bench.cmd +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error tgui-bench %* -pause diff --git a/bin/tgui-build.cmd b/bin/tgui-build.cmd deleted file mode 100644 index 7804fc6daaa..00000000000 --- a/bin/tgui-build.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error tgui tgui-lint tgui-test %* diff --git a/bin/tgui-dev.cmd b/bin/tgui-dev.cmd deleted file mode 100644 index 25ff3495d42..00000000000 --- a/bin/tgui-dev.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error tgui-dev %* diff --git a/bin/tgui-sonar.cmd b/bin/tgui-sonar.cmd deleted file mode 100644 index e083f65362a..00000000000 --- a/bin/tgui-sonar.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error tgui-sonar %* diff --git a/cev_eris.dme b/cev_eris.dme index 1aec8dd1a6d..7ba16f112fb 100644 --- a/cev_eris.dme +++ b/cev_eris.dme @@ -62,7 +62,6 @@ #include "code\__DEFINES\reagents.dm" #include "code\__DEFINES\research.dm" #include "code\__DEFINES\rust_g.dm" -#include "code\__DEFINES\rust_g_overrides.dm" #include "code\__DEFINES\sanity.dm" #include "code\__DEFINES\shields.dm" #include "code\__DEFINES\spaceman_dmm.dm" @@ -72,7 +71,6 @@ #include "code\__DEFINES\subsystems-priority.dm" #include "code\__DEFINES\subsystems.dm" #include "code\__DEFINES\targeting.dm" -#include "code\__DEFINES\tgui.dm" #include "code\__DEFINES\tick.dm" #include "code\__DEFINES\time.dm" #include "code\__DEFINES\tools_and_qualities.dm" @@ -87,7 +85,6 @@ #include "code\__DEFINES\spawner\frozen_star.dm" #include "code\__HELPERS\_global_objects.dm" #include "code\__HELPERS\_lists.dm" -#include "code\__HELPERS\_logging.dm" #include "code\__HELPERS\antag.dm" #include "code\__HELPERS\areas.dm" #include "code\__HELPERS\artwork_names.dm" @@ -101,6 +98,7 @@ #include "code\__HELPERS\game.dm" #include "code\__HELPERS\global_lists.dm" #include "code\__HELPERS\icons.dm" +#include "code\__HELPERS\logging.dm" #include "code\__HELPERS\manifest.dm" #include "code\__HELPERS\matrices.dm" #include "code\__HELPERS\mobs.dm" @@ -214,7 +212,6 @@ #include "code\controllers\evacuation\~evac.dm" #include "code\controllers\subsystems\air.dm" #include "code\controllers\subsystems\alarm.dm" -#include "code\controllers\subsystems\assets.dm" #include "code\controllers\subsystems\atoms.dm" #include "code\controllers\subsystems\chat.dm" #include "code\controllers\subsystems\chemistry.dm" @@ -1411,11 +1408,6 @@ #include "code\modules\assembly\signaler.dm" #include "code\modules\assembly\timer.dm" #include "code\modules\assembly\voice.dm" -#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\transports\asset_transport.dm" #include "code\modules\biomatter_manipulation\biogenerator.dm" #include "code\modules\biomatter_manipulation\solidifier.dm" #include "code\modules\biomatter_manipulation\toxic_biomass.dm" @@ -1433,18 +1425,7 @@ #include "code\modules\cargo\order.dm" #include "code\modules\cargo\packs.dm" #include "code\modules\cargo\supplyshuttle.dm" -#include "code\modules\cargo\exports\gear.dm" -#include "code\modules\cargo\exports\large_objects.dm" -#include "code\modules\cargo\exports\manifest.dm" -#include "code\modules\cargo\exports\medical_shit.dm" -#include "code\modules\cargo\exports\misc.dm" -#include "code\modules\cargo\exports\money.dm" -#include "code\modules\cargo\exports\parts.dm" -#include "code\modules\cargo\exports\research.dm" -#include "code\modules\cargo\exports\rnd_shit.dm" -#include "code\modules\cargo\exports\sheets.dm" -#include "code\modules\cargo\exports\tools.dm" -#include "code\modules\cargo\exports\weapons.dm" +#include "code\modules\client\asset_cache.dm" #include "code\modules\client\client procs.dm" #include "code\modules\client\client_defines.dm" #include "code\modules\client\darkmode.dm" @@ -1678,6 +1659,7 @@ #include "code\modules\genetics\stationary_scanner.dm" #include "code\modules\genetics\stationary_scanner_console.dm" #include "code\modules\ghosttrap\trap.dm" +#include "code\modules\goonchat\assets.dm" #include "code\modules\goonchat\browserOutput.dm" #include "code\modules\goonchat\helpers.dm" #include "code\modules\hivemind\core.dm" diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 460fbb37846..9e527a5619b 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -46,24 +46,3 @@ #define ADMIN_VV(atom) "(VV)" #define ADMIN_SM(user) "(SM)" #define ADMIN_TP(user) "(TP)" - -#define ADMIN_JMP(src) "(JMP)" -#define COORD(src) "[src ? src.Admin_Coordinates_Readable() : "nonexistent location"]" - -/atom/proc/Admin_Coordinates_Readable(area_name, admin_jump_ref) - var/turf/T = Safe_COORD_Location() - return T ? "[area_name ? "[get_area_name_litteral(T, TRUE)] " : " "]([T.x],[T.y],[T.z])[admin_jump_ref ? " [ADMIN_JMP(T)]" : ""]" : "nonexistent location" - -/atom/proc/Safe_COORD_Location() - var/atom/A = drop_location() - if(!A) - return //not a valid atom. - var/turf/T = get_step(A, 0) //resolve where the thing is. - if(!T) //incase it's inside a valid drop container, inside another container. ie if a mech picked up a closet and has it inside it's internal storage. - var/atom/last_try = A.loc?.drop_location() //one last try, otherwise fuck it. - if(last_try) - T = get_step(last_try, 0) - return T - -/turf/Safe_COORD_Location() - return src diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index c0ab8ab1196..85efd644341 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -1,15 +1,6 @@ -// simple is_type and similar inline helpers - -#define in_range(source, user) (get_dist(source, user) <= 1 && (get_step(source, 0)?:z) == (get_step(user, 0)?:z)) - -/// Within given range, but not counting z-levels -#define IN_GIVEN_RANGE(source, other, given_range) (get_dist(source, other) <= given_range && (get_step(source, 0)?:z) == (get_step(other, 0)?:z)) - -#define isatom(A) (isloc(A)) #define isweakref(D) (istype(D, /datum/weakref)) - #define islist(A) istype(A, /list) #define ismob(A) istype(A, /mob) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index c070dec166a..d0bde6a0218 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -348,8 +348,6 @@ //Prevent the master controller from starting automatically #define NO_INIT_PARAMETER "no-init" -//Force the log directory to be something specific in the data/logs folder -#define OVERRIDE_LOG_DIRECTORY_PARAMETER "log-directory" /// Required minimum values to see reagents in a beaker #define HUMAN_REQ_COG_FOR_REG 35 diff --git a/code/__DEFINES/rust_g_overrides.dm b/code/__DEFINES/rust_g_overrides.dm deleted file mode 100644 index 57de7d96acd..00000000000 --- a/code/__DEFINES/rust_g_overrides.dm +++ /dev/null @@ -1,3 +0,0 @@ -// RUSTG_OVERRIDE_BUILTINS is not used since the file APIs don't work well over Linux. -#define url_encode(text) rustg_url_encode("[text]") -#define url_decode(text) rustg_url_decode("[text]") diff --git a/code/__DEFINES/tgui.dm b/code/__DEFINES/tgui.dm deleted file mode 100644 index 43f626b97a1..00000000000 --- a/code/__DEFINES/tgui.dm +++ /dev/null @@ -1,36 +0,0 @@ -// /// Green eye; fully interactive -// #define UI_INTERACTIVE 2 -// /// Orange eye; updates but is not interactive -// #define UI_UPDATE 1 -// /// Red eye; disabled, does not update -// #define UI_DISABLED 0 -// /// UI Should close -// #define UI_CLOSE -1 - -// /// Maximum number of windows that can be suspended/reused -// #define TGUI_WINDOW_SOFT_LIMIT 5 -// /// Maximum number of open windows -// #define TGUI_WINDOW_HARD_LIMIT 9 - -// /// Maximum ping timeout allowed to detect zombie windows -// #define TGUI_PING_TIMEOUT 4 SECONDS - -// /// Window does not exist -// #define TGUI_WINDOW_CLOSED 0 -// /// Window was just opened, but is still not ready to be sent data -// #define TGUI_WINDOW_LOADING 1 -// /// Window is free and ready to receive data -// #define TGUI_WINDOW_READY 2 - -/// Get a window id based on the provided pool index -#define TGUI_WINDOW_ID(index) "tgui-window-[index]" -/// Get a pool index of the provided window id -#define TGUI_WINDOW_INDEX(window_id) text2num(copytext(window_id, 13)) - -/// Creates a message packet for sending via output() -// This is {"type":type,"payload":payload}, but pre-encoded. This is much faster -// than doing it the normal way. -// To ensure this is correct, this is unit tested in tgui_create_message. -#define TGUI_CREATE_MESSAGE(type, payload) ( \ - "%7b%22type%22%3a%22[type]%22%2c%22payload%22%3a[url_encode(json_encode(payload))]%7d" \ -) diff --git a/code/__HELPERS/files.dm b/code/__HELPERS/files.dm index 2f000119fe1..2bac54fa253 100644 --- a/code/__HELPERS/files.dm +++ b/code/__HELPERS/files.dm @@ -54,22 +54,7 @@ var/time_to_wait = fileaccess_timer - world.time if(time_to_wait > 0) to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.") - return TRUE + return 1 fileaccess_timer = world.time + FTPDELAY - return FALSE + return 0 #undef FTPDELAY - -/// Returns the md5 of a file at a given path. -/proc/md5filepath(path) - . = md5(file(path)) - -/// Save file as an external file then md5 it. -/// Used because md5ing files stored in the rsc sometimes gives incorrect md5 results. -/proc/md5asfile(file) - var/static/notch = 0 - // its importaint this code can handle md5filepath sleeping instead of hard blocking, if it's converted to use rust_g. - var/filename = "tmp/md5asfile.[world.realtime].[world.timeofday].[world.time].[world.tick_usage].[notch]" - notch = WRAP(notch+1, 0, 2**15) - fcopy(file, filename) - . = md5filepath(filename) - fdel(filename) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index f0bb91bab86..f5a1fa75fad 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -19,18 +19,17 @@ return A return 0 -// get the area's name -/proc/get_area_name_litteral(atom/X, format_text = FALSE) - var/area/A = isarea(X) ? X : get_area(X) - if(!A) - return null - return format_text ? format_text(A.name) : A.name - /proc/get_area_master(const/O) var/area/A = get_area(O) if (isarea(A)) return A +/proc/in_range(source, user) + if(get_dist(source, user) <= 1) + return TRUE + + return FALSE //not in range and not telekinetic + // Like view but bypasses luminosity check /proc/hear(range, atom/source) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index fe1f2ce1eb7..a3784a2ad7a 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -757,7 +757,7 @@ proc var/flatX2 = flat.Width() var/flatY1 = 1 var/flatY2 = flat.Height() - + // Dimensions of overlay being added var/addX1 var/addX2 @@ -825,36 +825,30 @@ proc return icon(flat, "", SOUTH) -/proc/getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N - var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A. - for(var/V in A.overlays)//For every image in overlays. var/image/I will not work, don't try it. - var/image/I = V - if(I.layer>A.layer) - continue//If layer is greater than what we need, skip it. - var/icon/image_overlay = new(I.icon,I.icon_state)//Blend only works with icon objects. - //Also, icons cannot directly set icon_state. Slower than changing variables but whatever. - alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay. - return alpha_mask//And now return the mask. + getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N + var/icon/alpha_mask = new(A.icon, A.icon_state)//So we want the default icon and icon state of A. + for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it. + if(I:layer>A.layer) continue//If layer is greater than what we need, skip it. + var/icon/image_overlay = new(I:icon, I:icon_state)//Blend only works with icon objects. + //Also, icons cannot directly set icon_state. Slower than changing variables but whatever. + alpha_mask.Blend(image_overlay, ICON_OR)//OR so they are lumped together in a nice overlay. + return alpha_mask//And now return the mask. /mob/proc/AddCamoOverlay(atom/A)//A is the atom which we are using as the overlay. var/icon/opacity_icon = new(A.icon, A.icon_state)//Don't really care for overlays/underlays. //Now we need to culculate overlays+underlays and add them together to form an image for a mask. - var/icon/alpha_mask = getIconMask(src)//getFlatIcon(src) is accurate but SLOW. Not designed for running each tick. This is also a little slow since it's blending a bunch of icons together but good enough. + //var/icon/alpha_mask = getFlatIcon(src)//Accurate but SLOW. Not designed for running each tick. Could have other uses I guess. + var/icon/alpha_mask = getIconMask(src)//Which is why I created that proc. Also a little slow since it's blending a bunch of icons together but good enough. opacity_icon.AddAlphaMask(alpha_mask)//Likely the main source of lag for this proc. Probably not designed to run each tick. opacity_icon.ChangeOpacity(0.4)//Front end for MapColors so it's fast. 0.5 means half opacity and looks the best in my opinion. - for(var/i=0,i<5,i++)//And now we add it as overlays. It's faster than creating an icon and then merging it. + for(var/i=0, i<5, i++)//And now we add it as overlays. It's faster than creating an icon and then merging it. var/image/I = image("icon" = opacity_icon, "icon_state" = A.icon_state, "layer" = layer+0.8)//So it's above other stuff but below weapons and the like. switch(i)//Now to determine offset so the result is somewhat blurred. - if(1) - I.pixel_x-- - if(2) - I.pixel_x++ - if(3) - I.pixel_y-- - if(4) - I.pixel_y++ + if(1) I.pixel_x-- + if(2) I.pixel_x++ + if(3) I.pixel_y-- + if(4) I.pixel_y++ overlays += I//And finally add the overlay. - // add_overlay(I)//And finally add the overlay. /proc/getHologramIcon(icon/A, safety=1, var/hologram_opacity = 0.5, var/hologram_color)//If safety is on, a new icon is not created. var/icon/flat_icon = safety ? A : new(A)//Has to be a new icon to not constantly change the same icon. @@ -1044,137 +1038,4 @@ proc/get_average_color(var/icon, var/icon_state, var/image_dir) average_rgb[3] = round(average_rgb[3] / pixel_count) GLOB.average_icon_color["[icon]:[icon_state]:[image_dir]"] = rgb(average_rgb[1],average_rgb[2],average_rgb[3]) - return GLOB.average_icon_color["[icon]:[icon_state]:[image_dir]"] - -/// Generate a filename for this asset -/// The same asset will always lead to the same asset name -/// (Generated names do not include file extention.) -/proc/generate_asset_name(file) - return "asset.[md5(fcopy_rsc(file))]" - -/** - * Converts an icon to base64. Operates by putting the icon in the iconCache savefile, - * exporting it as text, and then parsing the base64 from that. - * (This relies on byond automatically storing icons in savefiles as base64) - */ -/proc/icon2base64(icon/icon) - if (!isicon(icon)) - return FALSE - var/savefile/dummySave = new("tmp/dummySave.sav") - WRITE_FILE(dummySave["dummy"], icon) - var/iconData = dummySave.ExportText("dummy") - var/list/partial = splittext(iconData, "{") - . = replacetext(copytext_char(partial[2], 3, -5), "\n", "") //if cleanup fails we want to still return the correct base64 - dummySave.Unlock() - dummySave = null - fdel("tmp/dummySave.sav") //if you get the idea to try and make this more optimized, make sure to still call unlock on the savefile after every write to unlock it. - -/proc/icon2html(thing, target, icon_state, dir = SOUTH, frame = 1, moving = FALSE, sourceonly = FALSE, extra_classes = null) - if (!thing) - return - - var/key - var/icon/I = thing - - if (!target) - return - if (target == world) - target = clients - - var/list/targets - if (!islist(target)) - targets = list(target) - else - targets = target - if (!targets.len) - return - if (!isicon(I)) - if (isfile(thing)) //special snowflake - var/name = sanitize_filename("[generate_asset_name(thing)].png") - if (!SSassets.cache[name]) - SSassets.transport.register_asset(name, thing) - for (var/thing2 in targets) - SSassets.transport.send_assets(thing2, name) - if(sourceonly) - return SSassets.transport.get_asset_url(name) - return "" - var/atom/A = thing - - I = A.icon - - if (isnull(icon_state)) - icon_state = A.icon_state - //Despite casting to atom, this code path supports mutable appearances, so let's be nice to them - if(isnull(icon_state) || (isatom(thing) /* && A.flags_1 & HTML_USE_INITAL_ICON_1 */)) - icon_state = initial(A.icon_state) - if (isnull(dir)) - dir = initial(A.dir) - - if (isnull(dir)) - dir = A.dir - - if (ishuman(thing)) // Shitty workaround for a BYOND issue. - var/icon/temp = I - I = icon() - I.Insert(temp, dir = SOUTH) - dir = SOUTH - else - if (isnull(dir)) - dir = SOUTH - if (isnull(icon_state)) - icon_state = "" - - I = icon(I, icon_state, dir, frame, moving) - - key = "[generate_asset_name(I)].png" - if(!SSassets.cache[key]) - SSassets.transport.register_asset(key, I) - for (var/thing2 in targets) - SSassets.transport.send_assets(thing2, key) - if(sourceonly) - return SSassets.transport.get_asset_url(key) - return "" - -/proc/icon2base64html(thing) - if (!thing) - return - var/static/list/bicon_cache = list() - if (isicon(thing)) - var/icon/I = thing - var/icon_base64 = icon2base64(I) - - if (I.Height() > world.icon_size || I.Width() > world.icon_size) - var/icon_md5 = md5(icon_base64) - icon_base64 = bicon_cache[icon_md5] - if (!icon_base64) // Doesn't exist yet, make it. - bicon_cache[icon_md5] = icon_base64 = icon2base64(I) - - - return "" - - // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with. - var/atom/A = thing - var/key = "[istype(A.icon, /icon) ? "[REF(A.icon)]" : A.icon]:[A.icon_state]" - - - if (!bicon_cache[key]) // Doesn't exist, make it. - var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1) - if (ishuman(thing)) // Shitty workaround for a BYOND issue. - var/icon/temp = I - I = icon() - I.Insert(temp, dir = SOUTH) - - bicon_cache[key] = icon2base64(I) - - return "" - -//Costlier version of icon2html() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs. -/proc/costly_icon2html(thing, target, sourceonly = FALSE) - if (!thing) - return - - if (isicon(thing)) - return icon2html(thing, target) - - var/icon/I = getFlatIcon(thing) - return icon2html(I, target, sourceonly = sourceonly) + return GLOB.average_icon_color["[icon]:[icon_state]:[image_dir]"] \ No newline at end of file diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/logging.dm similarity index 79% rename from code/__HELPERS/_logging.dm rename to code/__HELPERS/logging.dm index d6572f7e2fd..abd5bcf5fcc 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/logging.dm @@ -113,9 +113,6 @@ /proc/log_qdel(text) world_qdel_log << "\[[time_stamp()]] [game_id] QDEL: [text][log_end]" -/proc/log_asset(text) - game_log("ASSET", text) - //pretty print a direction bitflag, can be useful for debugging. /proc/print_dir(var/dir) var/list/comps = list() @@ -128,87 +125,58 @@ return english_list(comps, nothing_text="0", and_text="|", comma_text="|") -/* Helper procs for building detailed log lines */ -/proc/key_name(whom, include_link = null, include_name = TRUE, highlight_special_characters = TRUE) +//more or less a logging utility +/proc/key_name(var/whom, var/include_link = null, var/include_name = 1, var/highlight_special_characters = 1) var/mob/M var/client/C var/key - var/ckey - var/fallback_name - if(!whom) - return "*null*" + if(!whom) return "*null*" if(istype(whom, /client)) C = whom M = C.mob key = C.key - ckey = C.ckey else if(ismob(whom)) M = whom C = M.client key = M.key - ckey = M.ckey - else if(istext(whom)) - key = whom - ckey = ckey(whom) - // C = GLOB.directory[ckey] - // if(C) - // M = C.mob else if(istype(whom, /datum/mind)) - var/datum/mind/mind = whom - key = mind.key - ckey = ckey(key) - if(mind.current) - M = mind.current - if(M.client) - C = M.client - else - fallback_name = mind.name - else // Catch-all cases if none of the types above match - var/swhom = null - - if(istype(whom, /atom)) - var/atom/A = whom - swhom = "[A.name]" - else if(istype(whom, /datum)) - swhom = "[whom]" - - if(!swhom) - swhom = "*invalid*" - - return "\[[swhom]\]" + var/datum/mind/D = whom + key = D.key + M = D.current + if(D.current) + C = D.current.client + else if(istype(whom, /datum)) + var/datum/D = whom + return "*invalid:[D.type]*" + else + return "*invalid*" . = "" - if(!ckey) - include_link = FALSE - if(key) - if(C?.holder && C.holder.fakekey && !include_name) - if(include_link) - . += "" + if(include_link && C) + . += "" + + if(C && C.holder && C.holder.fakekey && !include_name) . += "Administrator" else - if(include_link) - . += "" . += key - if(!C) - . += "\[DC\]" if(include_link) - . += "" + if(C) . += "" + else . += " (DC)" else . += "*no key*" - if(include_name) + if(include_name && M) var/name - if(M) - if(M.real_name) - name += "/([M.real_name])" - else if(M.name) - name += "/([M.name])" - else if(fallback_name) - name += "/([fallback_name])" + + if(M.real_name) + name = M.real_name + else if(M.name) + name = M.name + if(include_link && is_special_character(M) && highlight_special_characters) . += "/([name])" //Orange @@ -217,8 +185,8 @@ return . -/proc/key_name_admin(whom, include_name = TRUE) - return key_name(whom, TRUE, include_name) +/proc/key_name_admin(var/whom, var/include_name = 1) + return key_name(whom, 1, include_name) // Helper procs for building detailed log lines /datum/proc/get_log_info_line() diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 1a936975c39..d8a6e7b72a4 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -164,19 +164,6 @@ /proc/sanitize_old(var/t, var/list/repl_chars = list("\n"="#", "\t"="#")) return html_encode(replace_characters(t, repl_chars)) -//Removes a few problematic characters -/proc/sanitize_simple(t,list/repl_chars = list("\n"="#","\t"="#")) - for(var/char in repl_chars) - var/index = findtext(t, char) - while(index) - t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index + length(char)) - index = findtext(t, char, index + length(char)) - return t - -/proc/sanitize_filename(t) - return sanitize_simple(t, list("\n"="", "\t"="", "/"="", "\\"="", "?"="", "%"="", "*"="", ":"="", "|"="", "\""="", "<"="", ">"="")) - - /* * Text searches */ @@ -378,7 +365,7 @@ proc/TextPreview(var/string, var/len=40) /proc/create_text_tag(var/tagname, var/tagdesc = tagname, var/client/C = null) if(!(C && C.get_preference_value(/datum/client_preference/chat_tags) == GLOB.PREF_SHOW)) return tagdesc - return icon2html(icon(text_tag_icons, tagname), world) + return icon2html(icon(text_tag_icons, tagname), world, realsize=TRUE) /proc/contains_az09(var/input) for(var/i=1, i<=length(input), i++) diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index aa2e8b8d29e..973ef4ee677 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -97,31 +97,29 @@ var/global/list/hexdigits = list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9 if ("SOUTHEAST") return 6 if ("SOUTHWEST") return 10 -//Converts an angle (degrees) into a ss13 direction -GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH,SOUTHWEST,WEST,NORTHWEST)) -#define angle2dir(X) (GLOB.modulo_angle_to_dir[round((((X%360)+382.5)%360)/45)+1]) - -//returns the north-zero clockwise angle in degrees, given a direction -/proc/dir2angle(D) - switch(D) - if(NORTH) - return 0 - if(SOUTH) - return 180 - if(EAST) - return 90 - if(WEST) - return 270 - if(NORTHEAST) - return 45 - if(SOUTHEAST) - return 135 - if(NORTHWEST) - return 315 - if(SOUTHWEST) - return 225 - else - return null +// Converts an angle (degrees) into an ss13 direction +/proc/angle2dir(var/degree) + degree = (degree + 22.5) % 365 // 22.5 = 45 / 2 + if (degree < 45) return NORTH + if (degree < 90) return NORTHEAST + if (degree < 135) return EAST + if (degree < 180) return SOUTHEAST + if (degree < 225) return SOUTH + if (degree < 270) return SOUTHWEST + if (degree < 315) return WEST + return NORTH|WEST + +// Returns the north-zero clockwise angle in degrees, given a direction +/proc/dir2angle(var/D) + switch (D) + if (NORTH) return 0 + if (SOUTH) return 180 + if (EAST) return 90 + if (WEST) return 270 + if (NORTHEAST) return 45 + if (SOUTHEAST) return 135 + if (NORTHWEST) return 315 + if (SOUTHWEST) return 225 // Returns the angle in english /proc/angle2text(var/degree) @@ -157,14 +155,12 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH, else . = max(0, min(255, 329.698727446 * (temp - 60) ** -0.1332047592)) - /proc/heat2color_g(temp) temp /= 100 if(temp <= 66) . = max(0, min(255, 99.4708025861 * log(temp) - 161.1195681661)) else - . = max(0, min(255, 288.1221685293 * ((temp - 60) ** -0.075148492))) - + . = max(0, min(255, 288.1221695283 * ((temp - 60) ** -0.0755148492))) /proc/heat2color_b(temp) temp /= 100 @@ -254,9 +250,9 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH, switch(child) if(/datum) return null - if(/obj, /mob) + if(/obj || /mob) return /atom/movable - if(/area, /turf) + if(/area || /turf) return /atom else return /datum @@ -283,7 +279,3 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH, else //regex everything else (works for /proc too) return lowertext(replacetext("[the_type]", "[type2parent(the_type)]/", "")) -/// Return html to load a url. -/// for use inside of browse() calls to html assets that might be loaded on a cdn. -/proc/url2htmlloader(url) - return {""} diff --git a/code/_global_vars/misc.dm b/code/_global_vars/misc.dm index bc60878dec5..5c91e0a8fbb 100644 --- a/code/_global_vars/misc.dm +++ b/code/_global_vars/misc.dm @@ -26,7 +26,3 @@ GLOBAL_LIST_INIT(custom_kits, list( /obj/item/ammo_magazine/ihclrifle, /obj/item/ammo_magazine/ihclrifle, /obj/item/ammo_magazine/ihclrifle))) - -// LOGGING MOVE ME // -GLOBAL_VAR(log_directory) -GLOBAL_PROTECT(log_directory) diff --git a/code/controllers/subsystems/assets.dm b/code/controllers/subsystems/assets.dm deleted file mode 100644 index 0e8c5e1369e..00000000000 --- a/code/controllers/subsystems/assets.dm +++ /dev/null @@ -1,37 +0,0 @@ -SUBSYSTEM_DEF(assets) - name = "Assets" - init_order = INIT_ORDER_ASSETS - flags = SS_NO_FIRE - var/list/cache = list() - var/list/preload = list() - var/datum/asset_transport/transport = new() - -/datum/controller/subsystem/assets/OnConfigLoad() - var/newtransporttype = /datum/asset_transport - // switch (CONFIG_GET(string/asset_transport)) - // if ("webroot") - // newtransporttype = /datum/asset_transport/webroot - - if (newtransporttype == transport.type) - return - - var/datum/asset_transport/newtransport = new newtransporttype () - if (newtransport.validate_config()) - transport = newtransport - transport.Load() - - - -/datum/controller/subsystem/assets/Initialize(timeofday) - for(var/type in typesof(/datum/asset)) - var/datum/asset/A = type - if (type != initial(A._abstract)) - get_asset_datum(type) - - transport.Initialize(cache) - - ..() - -/datum/controller/subsystem/assets/Recover() - cache = SSassets.cache - preload = SSassets.preload diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm index cb363e3d932..0ff053be7db 100644 --- a/code/controllers/subsystems/ticker.dm +++ b/code/controllers/subsystems/ticker.dm @@ -89,6 +89,7 @@ SUBSYSTEM_DEF(ticker) if(!start_immediately) to_chat(world, "Please, setup your character and select ready. Game will start in [pregame_timeleft] seconds.") current_state = GAME_STATE_PREGAME + send_assets() fire() if(GAME_STATE_PREGAME) diff --git a/code/datums/autolathe/autolathe_datums.dm b/code/datums/autolathe/autolathe_datums.dm index 7bb5ec2523c..bd7fe3fa095 100644 --- a/code/datums/autolathe/autolathe_datums.dm +++ b/code/datums/autolathe/autolathe_datums.dm @@ -128,6 +128,7 @@ "id" = "[id]", "name" = name, "desc" = desc, "time" = time, "category" = category, "adjust_materials" = adjust_materials ) + // ui_data["icon"] is set in asset code. if(length(materials)) var/list/RS = list() diff --git a/code/datums/browser.dm b/code/datums/browser.dm index 513843881b0..b922b24175e 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -4,20 +4,21 @@ var/window_id // window_id is used as the window name for browse and onclose var/width = 0 var/height = 0 - var/datum/weakref/ref = null - var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id + var/atom/ref = null + var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id var/stylesheets[0] var/scripts[0] + var/title_image var/head_elements var/body_elements var/head_content = "" var/content = "" - var/static/datum/asset/simple/namespaced/common/common_asset = get_asset_datum(/datum/asset/simple/namespaced/common) + var/title_buttons = "" -/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null) +/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null) + user = nuser - RegisterSignal(user, COMSIG_PARENT_QDELETING, .proc/user_deleted) window_id = nwindow_id if (ntitle) title = format_text(ntitle) @@ -26,40 +27,33 @@ if (nheight) height = nheight if (nref) - ref = WEAKREF(nref) + ref = nref + + // If a client exists, but they have disabled fancy windowing, disable it! + if(user && user.client && user.client.get_preference_value(/datum/client_preference/browser_style) == GLOB.PREF_PLAIN) + return + add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs -/datum/browser/proc/user_deleted(datum/source) - SIGNAL_HANDLER - user = null +/datum/browser/proc/set_title(ntitle) + title = format_text(ntitle) /datum/browser/proc/add_head_content(nhead_content) head_content = nhead_content /datum/browser/proc/set_title_buttons(ntitle_buttons) - // do nothing + title_buttons = ntitle_buttons /datum/browser/proc/set_window_options(nwindow_options) window_options = nwindow_options - /datum/browser/proc/set_title_image(ntitle_image) - // do nothing + //title_image = ntitle_image /datum/browser/proc/add_stylesheet(name, file) - if (istype(name, /datum/asset/spritesheet)) - var/datum/asset/spritesheet/sheet = name - stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]" - else - var/asset_name = "[name].css" - - stylesheets[asset_name] = file - - if (!SSassets.cache[asset_name]) - SSassets.transport.register_asset(asset_name, file) + stylesheets[name] = file /datum/browser/proc/add_script(name, file) - scripts["[ckey(name)].js"] = file - SSassets.transport.register_asset("[ckey(name)].js", file) + scripts[name] = file /datum/browser/proc/set_content(ncontent) content = ncontent @@ -68,28 +62,36 @@ content += ncontent /datum/browser/proc/get_header() - var/file - head_content += "" - for (file in stylesheets) - head_content += "" - - - for (file in scripts) - head_content += "" - - return {" + var/key + var/filename + for (key in stylesheets) + filename = "[ckey(key)].css" + user << browse_rsc(stylesheets[key], filename) + head_content += "" + + for (key in scripts) + filename = "[ckey(key)].js" + user << browse_rsc(scripts[key], filename) + head_content += "" + + var/title_attributes = "class='uiTitle'" + if (title_image) + title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'" + + return {" + + - - + [head_content]
- [title ? "
[title]
" : ""] + [title ? "
[title]
[title_buttons]
" : ""]
"} -//" This is here because else the rest of the file looks like a string in notepad++. + /datum/browser/proc/get_footer() return {"
@@ -104,40 +106,34 @@ [get_footer()] "} -/datum/browser/proc/open(use_onclose = TRUE) - if(isnull(window_id)) //null check because this can potentially nuke goonchat - WARNING("Browser [title] tried to open with a null ID") - to_chat(user, span_userdanger("The [title] browser you tried to open failed a sanity check! Please report this on github!")) - return +/datum/browser/proc/open(var/use_onclose = 1, var/mob/target = user) var/window_size = "" if (width && height) window_size = "size=[width]x[height];" - common_asset.send(user) - if (stylesheets.len) - SSassets.transport.send_assets(user, stylesheets) - if (scripts.len) - SSassets.transport.send_assets(user, scripts) - user << browse(get_content(), "window=[window_id];[window_size][window_options]") + target << browse(get_content(), "window=[window_id];[window_size][window_options]") if (use_onclose) - setup_onclose() - -/datum/browser/proc/setup_onclose() - set waitfor = 0 //winexists sleeps, so we don't need to. - for (var/i in 1 to 10) - if (user?.client && winexists(user, window_id)) - var/atom/send_ref - if(ref) - send_ref = ref.resolve() - if(!send_ref) - ref = null - onclose(user, window_id, send_ref) - break + onclose(target, window_id, ref) /datum/browser/proc/close() - if(!isnull(window_id))//null check because this can potentially nuke goonchat - user << browse(null, "window=[window_id]") + user << browse(null, "window=[window_id]") + +// This will allow you to show an icon in the browse window +// This is added to mob so that it can be used without a reference to the browser object +// There is probably a better place for this... +/mob/proc/browse_rsc_icon(icon, icon_state, dir = -1) + /* + var/icon/I + if (dir >= 0) + I = new /icon(icon, icon_state, dir) else - WARNING("Browser [title] tried to close with a null ID") + I = new /icon(icon, icon_state) + dir = "default" + + var/filename = "[ckey("[icon]_[icon_state]_[dir]")].png" + src << browse_rsc(I, filename) + return filename + */ + // Registers the on-close verb for a browse window (client/verb/.windowclose) // this will be called when the close-button of a window is pressed. @@ -146,22 +142,22 @@ // e.g. canisters, timers, etc. // // windowid should be the specified window name -// e.g. code is : user << browse(text, "window=fred") -// then use : onclose(user, "fred") +// e.g. code is : user << browse(text, "window=fred") +// then use : onclose(user, "fred") // // Optionally, specify the "ref" parameter as the controlled atom (usually src) // to pass a "close=1" parameter to the atom's Topic() proc for special handling. // Otherwise, the user mob's machine var will be reset directly. // -/proc/onclose(mob/user, windowid, atom/ref=null) - if(!user.client) - return +/proc/onclose(mob/user, windowid, var/atom/ref) + if(!user || !user.client) return var/param = "null" if(ref) - param = "[REF(ref)]" + param = "\ref[ref]" winset(user, windowid, "on-close=\".windowclose [param]\"") + //world << "OnClose [user]: [windowid] : ["on-close=\".windowclose [param]\""]" // the on-close client verb @@ -169,19 +165,28 @@ // if a valid atom reference is supplied, call the atom's Topic() with "close=1" // otherwise, just reset the client mob's machine var. // -/client/verb/windowclose(atomref as text) - set hidden = TRUE // hide this verb from the user's panel - set name = ".windowclose" // no autocomplete on cmd line +/client/verb/windowclose(var/atomref as text) + set hidden = 1 // hide this verb from the user's panel + set name = ".windowclose" // no autocomplete on cmd line - if(atomref!="null") // if passed a real atomref - var/hsrc = locate(atomref) // find the reffed atom - var/href = "close=1" + //world << "windowclose: [atomref]" + if(atomref!="null") // if passed a real atomref + var/hsrc = locate(atomref) // find the reffed atom if(hsrc) + //world << "[src] Topic [href] [hsrc]" usr = src.mob - src.Topic(href, params2list(href), hsrc) // this will direct to the atom's - return // Topic() proc via client.Topic() + src.Topic("close=1", list("close"="1"), hsrc) // this will direct to the atom's + return // Topic() proc via client.Topic() // no atomref specified (or not found) // so just reset the user mob's machine var - if(src?.mob) + if(src && src.mob) + //world << "[src] was [src.mob.machine], setting to null" src.mob.unset_machine() + return + +/datum/browser/proc/update(var/force_open = 0, var/use_onclose = 1) + if(force_open) + open(use_onclose) + else + send_output(user, get_content(), "[window_id].browser") diff --git a/code/datums/craft/crafting_items.dm b/code/datums/craft/crafting_items.dm index 7c750aa3c81..42db52479ed 100644 --- a/code/datums/craft/crafting_items.dm +++ b/code/datums/craft/crafting_items.dm @@ -145,11 +145,6 @@ /obj/item/craft_frame/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui, force_open = NANOUI_FOCUS) var/list/data = list() - var/datum/asset/craftIcons = get_asset_datum(/datum/asset/simple/craft) - var/datum/asset/materialIcons = get_asset_datum(/datum/asset/simple/materials) - if (craftIcons.send(user.client) || materialIcons.send(user.client)) - user.client.browse_queue_flush() // stall loading nanoui until assets actualy gets sent - var/list/listed_products = list() for(var/key = 1 to view_only) var/obj/item/I = items[key] diff --git a/code/datums/craft/menu.dm b/code/datums/craft/menu.dm index e5e09e37755..8f4254eb25d 100644 --- a/code/datums/craft/menu.dm +++ b/code/datums/craft/menu.dm @@ -55,7 +55,7 @@ if(CR) data["cur_item"] = list( "name" = CR.name, - "icon" = SSassets.transport.get_asset_url(CR.result), + "icon" = getAtomCacheFilename(CR.result), "ref" = "\ref[CR]", "desc" = CR.get_description(), "batch" = CR.flags & CRAFT_BATCH @@ -69,10 +69,6 @@ )) data["items"] = items - var/datum/asset/craftIcons = get_asset_datum(/datum/asset/simple/craft) - var/datum/asset/materialIcons = get_asset_datum(/datum/asset/simple/materials) - if (craftIcons.send(user.client) || materialIcons.send(user.client)) - user.client.browse_queue_flush() // stall loading nanoui until assets actualy gets sent ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) diff --git a/code/datums/extensions/multitool/multitool.dm b/code/datums/extensions/multitool/multitool.dm index aa5f8f4d9dc..0ec2a05c13d 100644 --- a/code/datums/extensions/multitool/multitool.dm +++ b/code/datums/extensions/multitool/multitool.dm @@ -10,6 +10,7 @@ if(html) var/datum/browser/popup = new(usr, "multitool", "Multitool Menu", window_x, window_y) popup.set_content(html) + popup.set_title_image(user.browse_rsc_icon(M.icon, M.icon_state)) popup.open() else close_window(usr) diff --git a/code/datums/topic/admin.dm b/code/datums/topic/admin.dm index 51a72c3a357..dce99c2ce9b 100644 --- a/code/datums/topic/admin.dm +++ b/code/datums/topic/admin.dm @@ -1540,7 +1540,7 @@ WANTED.backup_author = source.admincaster_signature //Submitted by WANTED.is_admin_message = 1 news_network.wanted_issue = WANTED - for(var/obj/machinery/newscaster/NEWSCASTER in GLOB.allCasters) + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) NEWSCASTER.newsAlert() NEWSCASTER.update_icon() source.admincaster_screen = 15 @@ -1556,7 +1556,7 @@ var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel") if(choice=="Confirm") news_network.wanted_issue = null - for(var/obj/machinery/newscaster/NEWSCASTER in GLOB.allCasters) + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) NEWSCASTER.update_icon() source.admincaster_screen=17 source.access_news_network() diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm index 85110919d66..dcf60dfe1b1 100644 --- a/code/datums/wires/wires.dm +++ b/code/datums/wires/wires.dm @@ -105,6 +105,7 @@ var/list/wireColours = list("red", "blue", "green", "darkred", "orange", "brown" var/datum/browser/popup = new(user, "wires", holder.name, window_x, window_y) popup.set_content(html) + popup.set_title_image(user.browse_rsc_icon(holder.icon, holder.icon_state)) popup.open() /datum/wires/proc/GetInteractWindow(mob/living/user) diff --git a/code/game/machinery/autolathe/autolathe.dm b/code/game/machinery/autolathe/autolathe.dm index 85efda0e196..f76475cc515 100644 --- a/code/game/machinery/autolathe/autolathe.dm +++ b/code/game/machinery/autolathe/autolathe.dm @@ -233,10 +233,6 @@ /obj/machinery/autolathe/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = NANOUI_FOCUS) var/list/data = ui_data(user, ui_key) - var/datum/asset/designIcons = get_asset_datum(/datum/asset/simple/design_icons) - if (designIcons.send(user.client)) - user.client.browse_queue_flush() // stall loading nanoui until assets actualy gets sent - ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) // the ui does not exist, so we'll create a new() one diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm index 31d62c65708..77948e31b3e 100644 --- a/code/game/machinery/newscaster.dm +++ b/code/game/machinery/newscaster.dm @@ -1,27 +1,20 @@ -// GLOBAL_DATUM_INIT(news_network, /datum/feed_network, new) -GLOBAL_LIST_EMPTY(allCasters) -var/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list. +//############################################## +//################### NEWSCASTERS BE HERE! #### +//###-Agouri################################### /datum/feed_message - ///Who is the author of the full-size article to the feed channel? var/author ="" - ///Body of the full-size article to the feed channel. var/body ="" var/message_type ="Story" var/datum/feed_channel/parent_channel var/is_admin_message = 0 - ///Is there an image tied to the feed message? var/icon/img = null - ///At what time was the full-size article sent? Time is in station time. + var/icon/caption = "" var/time_stamp = "" - ///If the message has an image, what is that image's caption? - var/caption = "" var/backup_body = "" var/backup_author = "" var/icon/backup_img = null var/icon/backup_caption = "" - ///Referece to the photo used in picture messages. - var/photo_file /datum/feed_channel var/channel_name="" @@ -80,66 +73,49 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n newChannel.announcement = "Breaking news from [channel_name]!" network_channels += newChannel -/datum/feed_network/proc/SubmitArticle(msg, author, channel_name, obj/item/photo/picture, adminMessage = FALSE, message_type = "", allow_comments = TRUE, update_alert = TRUE) +/datum/feed_network/proc/SubmitArticle(var/msg, var/author, var/channel_name, var/obj/item/photo/photo, var/adminMessage = 0, var/message_type = "") var/datum/feed_message/newMsg = new /datum/feed_message newMsg.author = author newMsg.body = msg newMsg.time_stamp = "[stationtime2text()]" newMsg.is_admin_message = adminMessage - if(picture) - newMsg.img = picture.img - newMsg.caption = picture.scribble - newMsg.photo_file = save_photo(picture.img) if(message_type) newMsg.message_type = message_type - + if(photo) + newMsg.img = photo.img + newMsg.caption = photo.scribble for(var/datum/feed_channel/FC in network_channels) if(FC.channel_name == channel_name) insert_message_in_channel(FC, newMsg) //Adding message to the network's appropriate feed_channel break - for(var/obj/machinery/newscaster/NEWSCASTER in GLOB.allCasters) - NEWSCASTER.newsAlert(channel_name, update_alert) - -/datum/feed_network/proc/submitWanted(criminal, body, scanned_user, obj/item/photo/picture, adminMsg = FALSE, newMessage = FALSE) - var/datum/feed_message/WANTED = new /datum/feed_message - WANTED.author = criminal - WANTED.body = body - WANTED.backup_author = scanned_user - if(picture) - WANTED.img = picture.img - WANTED.photo_file = save_photo(picture.img) - - news_network.wanted_issue = WANTED - - if(newMessage) - for(var/obj/machinery/newscaster/N in GLOB.allCasters) - N.newsAlert() - N.update_icon() - -/datum/feed_network/proc/insert_message_in_channel(datum/feed_channel/FC, datum/feed_message/newMsg) + +/datum/feed_network/proc/insert_message_in_channel(var/datum/feed_channel/FC, var/datum/feed_message/newMsg) FC.messages += newMsg - newMsg.parent_channel = FC // ?? + if(newMsg.img) + register_asset("newscaster_photo_[sanitize(FC.channel_name)]_[FC.messages.len].png", newMsg.img) + newMsg.parent_channel = FC FC.update() + alert_readers(FC.announcement) + +/datum/feed_network/proc/alert_readers(var/annoncement) + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + NEWSCASTER.newsAlert(annoncement) + NEWSCASTER.update_icon() + +var/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list. + +var/list/obj/machinery/newscaster/allCasters = list() //Global list that will contain reference to all newscasters in existence. -/datum/feed_network/proc/save_photo(icon/photo) - var/photo_file = copytext_char(md5("\icon[photo]"), 1, 6) - if(!fexists("[GLOB.log_directory]/photos/[photo_file].png")) - //Clean up repeated frames - var/icon/clean = new /icon() - clean.Insert(photo, "", SOUTH, 1, 0) - fcopy(clean, "[GLOB.log_directory]/photos/[photo_file].png") - return photo_file /obj/machinery/newscaster name = "newscaster" desc = "A standard newsfeed handler. All the news you absolutely have no use for, in one place!" icon = 'icons/obj/terminals.dmi' icon_state = "newscaster_normal" - light_range = 0 - anchored = TRUE - var/isbroken = 0 //1 if someone banged it with something heavy var/ispowered = 1 //starts powered, changes with power_change() + //var/list/datum/feed_channel/channel_list = list() //This list will contain the names of the feed channels. Each name will refer to a data region where the messages of the feed channels are stored. + //OBSOLETE: We're now using a global news network var/screen = 0 //Or maybe I'll make it into a list within a list afterwards... whichever I prefer, go fuck yourselves :3 // 0 = welcome screen - main menu // 1 = view feed channels @@ -154,7 +130,7 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n // 10 = censor feed story // 11 = censor feed channel //Holy shit this is outdated, made this when I was still starting newscasters :3 - var/paper_remaining = 15 + var/paper_remaining = 0 var/securityCaster = 0 // 0 = Caster cannot be used to issue wanted posters // 1 = the opposite @@ -164,7 +140,9 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n // 0 = there's no WANTED issued, we don't need a special icon_state // 1 = Guess what. var/alert_delay = 500 - var/alert = FALSE + var/alert = 0 + // 0 = there hasn't been a news/wanted update in the last alert_delay + // 1 = there has var/scanned_user = "Unknown" //Will contain the name of the person who currently uses the newscaster var/msg = ""; //Feed message var/datum/news_photo/photo_data = null @@ -172,52 +150,25 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n var/c_locked=0; //Will our new channel be locked to public submissions? var/hitstaken = 0 //Death at 3 hits from an item with force>=15 var/datum/feed_channel/viewing_channel = null + light_range = 0 + anchored = TRUE -/obj/machinery/newscaster/directional/north - pixel_y = 32 - -/obj/machinery/newscaster/directional/south - pixel_y = -28 - -/obj/machinery/newscaster/directional/east - pixel_x = 28 - -/obj/machinery/newscaster/directional/west - pixel_x = -28 /obj/machinery/newscaster/security_unit //Security unit name = "Security Newscaster" securityCaster = 1 -/obj/machinery/newscaster/security_unit/directional/north - pixel_y = 32 - -/obj/machinery/newscaster/security_unit/directional/south - pixel_y = -28 - -/obj/machinery/newscaster/security_unit/directional/east - pixel_x = 28 - -/obj/machinery/newscaster/security_unit/directional/west - pixel_x = -28 - -/obj/machinery/newscaster/Initialize(mapload, ndir, building) - . = ..() - if(building) - // setDir(ndir) - dir = ndir - pixel_x = (dir & 3)? 0 : (dir == 4 ? -32 : 32) - pixel_y = (dir & 3)? (dir ==1 ? -32 : 32) : 0 - - GLOB.allCasters += src - unit_no = GLOB.allCasters.len - update_icon() +/obj/machinery/newscaster/New() //Constructor, ho~ + allCasters += src + src.paper_remaining = 15 // Will probably change this to something better + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) // Let's give it an appropriate unit number + src.unit_no++ + src.update_icon() //for any custom ones on the map... + ..() //I just realised the newscasters weren't in the global machines list. The superconstructor call will tend to that /obj/machinery/newscaster/Destroy() - GLOB.allCasters -= src - viewing_channel = null - // picture = null - return ..() + allCasters -= src + . = ..() /obj/machinery/newscaster/update_icon() if(!ispowered || isbroken) @@ -283,28 +234,31 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n if(ishuman(user) || issilicon(user)) var/mob/living/human_or_robot_user = user var/dat - scan_user(human_or_robot_user) //Newscaster scans you + dat = text("Newscaster

Newscaster Unit #[src.unit_no]

") + + src.scan_user(human_or_robot_user) //Newscaster scans you switch(screen) if(0) - dat += "Welcome to Newscasting Unit #[unit_no].
Interface & News networks Operational." + dat += "Welcome to Newscasting Unit #[src.unit_no].
Interface & News networks Operational." dat += "
Property of Nanotrasen Inc" if(news_network.wanted_issue) - dat+= "
Read Wanted Issue" - dat+= "

Create Feed Channel" - dat+= "
View Feed Channels" - dat+= "
Submit new Feed story" - dat+= "
Print newspaper" - dat+= "
Re-scan User" + dat+= "
Read Wanted Issue" + dat+= "

Create Feed Channel" + dat+= "
View Feed Channels" + dat+= "
Submit new Feed story" + dat+= "
Print newspaper" + dat+= "
Re-scan User" dat+= "

Exit" if(src.securityCaster) - var/wanted_already = FALSE + var/wanted_already = 0 if(news_network.wanted_issue) - wanted_already = TRUE + wanted_already = 1 + dat+="
Feed Security functions:
" - dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" - dat+="
Censor Feed Stories" - dat+="
Mark Feed Channel with [company_name] D-Notice" + dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" + dat+="
Censor Feed Stories" + dat+="
Mark Feed Channel with [company_name] D-Notice" dat+="

The newscaster recognises you as: [src.scanned_user]" if(1) dat+= "Station Feed Channels
" @@ -313,30 +267,30 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n else for(var/datum/feed_channel/CHANNEL in news_network.network_channels) if(CHANNEL.is_admin_channel) - dat+="[CHANNEL.channel_name]
" + dat+="[CHANNEL.channel_name]
" else - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
" - dat+="

Refresh" - dat+="
Back" + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
" + dat+="

Refresh" + dat+="
Back" if(2) dat+="Creating new Feed Channel..." - dat+="
Channel Name: [src.channel_name]
" + dat+="
Channel Name: [src.channel_name]
" dat+="Channel Author: [src.scanned_user]
" - dat+="Will Accept Public Feeds: [(src.c_locked) ? ("NO") : ("YES")]

" - dat+="
Submit

Cancel
" + dat+="Will Accept Public Feeds: [(src.c_locked) ? ("NO") : ("YES")]

" + dat+="
Submit

Cancel
" if(3) dat+="Creating new Feed Message..." - dat+="
Receiving Channel: [src.channel_name]
" //MARK + dat+="
Receiving Channel: [src.channel_name]
" //MARK dat+="Message Author: [src.scanned_user]
" - dat+="Message Body: [src.msg]
" - dat+="Attach Photo: [(src.photo_data ? "Photo Attached" : "No Photo")]
" - dat+="
Submit

Cancel
" + dat+="Message Body: [src.msg]
" + dat+="Attach Photo: [(src.photo_data ? "Photo Attached" : "No Photo")]
" + dat+="
Submit

Cancel
" if(4) dat+="Feed story successfully submitted to [src.channel_name].

" - dat+="
Return
" + dat+="
Return
" if(5) dat+="Feed Channel [src.channel_name] created successfully.

" - dat+="
Return
" + dat+="
Return
" if(6) dat+="ERROR: Could not submit Feed story to Network.

" if(src.channel_name=="") @@ -346,7 +300,7 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n if(src.msg == "" || src.msg == "\[REDACTED\]") dat+="Invalid message body.
" - dat+="
Return
" + dat+="
Return
" if(7) dat+="ERROR: Could not submit Feed Channel to Network.

" var/list/existing_authors = list() @@ -368,7 +322,7 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n dat+="Channel name already in use.
" if(src.scanned_user=="Unknown") dat+="Channel author unverified.
" - dat+="
Return
" + dat+="
Return
" if(8) var/total_num=length(news_network.network_channels) var/active_num=total_num @@ -380,30 +334,31 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n active_num-- dat+="Network currently serves a total of [total_num] Feed channels, [active_num] of which are active, and a total of [message_num] Feed Stories." //TODO: CONTINUE dat+="

Liquid Paper remaining: [(src.paper_remaining) *100 ] cm^3" - dat+="

Print Paper" - dat+="
Cancel" + dat+="

Print Paper" + dat+="
Cancel" if(9) - dat+="[viewing_channel.channel_name]: \[created by: [viewing_channel.author]\]
" - if(viewing_channel.censored) + dat+="[src.viewing_channel.channel_name]: \[created by: [src.viewing_channel.author]\]
" + if(src.viewing_channel.censored) dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [company_name] D-Notice.
" dat+="No further feed story additions are allowed while the D-Notice is in effect.

" else - if( !length(viewing_channel.messages) ) + if( isemptylist(src.viewing_channel.messages) ) dat+="No feed messages found in channel...
" else var/i = 0 - for(var/datum/feed_message/MESSAGE in viewing_channel.messages) - i++ + for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + ++i dat+="-[MESSAGE.body]
" if(MESSAGE.img) - usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png") - dat+="
" + var/resourc_name = "newscaster_photo_[sanitize(viewing_channel.channel_name)]_[i].png" + send_asset(usr.client, resourc_name) + dat+="
" if(MESSAGE.caption) dat+="[MESSAGE.caption]
" dat+="
" dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]
" - dat+="

Refresh" - dat+="
Back" + dat+="

Refresh" + dat+="
Back" if(10) dat+="[company_name] Feed Censorship Tool
" dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
" @@ -413,8 +368,8 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n dat+="No feed channels found active...
" else for(var/datum/feed_channel/CHANNEL in news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
" - dat+="
Cancel" + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
" + dat+="
Cancel" if(11) dat+="[company_name] D-Notice Handler
" dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's" @@ -424,12 +379,12 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n dat+="No feed channels found active...
" else for(var/datum/feed_channel/CHANNEL in news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
" + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
" - dat+="
Back" + dat+="
Back" if(12) dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
" - dat+="[(src.viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
" + dat+="[(src.viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
" if( isemptylist(src.viewing_channel.messages) ) @@ -437,11 +392,11 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n else for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) dat+="-[MESSAGE.body]
\[[MESSAGE.message_type] by [MESSAGE.author]\]
" - dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
" - dat+="
Back" + dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
" + dat+="
Back" if(13) dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
" - dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
" + dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
" if(src.viewing_channel.censored) dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [company_name] D-Notice.
" dat+="No further feed story additions are allowed while the D-Notice is in effect.

" @@ -452,7 +407,7 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) dat+="-[MESSAGE.body]
\[[MESSAGE.message_type] by [MESSAGE.author]\]
" - dat+="
Back" + dat+="
Back" if(14) dat+="Wanted Issue Handler:" var/wanted_already = 0 @@ -464,20 +419,20 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n if(wanted_already) dat+="
A wanted issue is already in Feed Circulation. You can edit or cancel it below.
" dat+="
" - dat+="Criminal Name: [src.channel_name]
" - dat+="Description: [src.msg]
" - dat+="Attach Photo: [(src.photo_data ? "Photo Attached" : "No Photo")]
" + dat+="Criminal Name: [src.channel_name]
" + dat+="Description: [src.msg]
" + dat+="Attach Photo: [(src.photo_data ? "Photo Attached" : "No Photo")]
" if(wanted_already) dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
" else dat+="Wanted Issue will be created under prosecutor: [src.scanned_user]
" - dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]" + dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]" if(wanted_already) - dat+="
Take down Issue" - dat+="
Cancel" + dat+="
Take down Issue" + dat+="
Cancel" if(15) dat+="Wanted issue for [src.channel_name] is now in Network Circulation.

" - dat+="
Return
" + dat+="
Return
" if(16) dat+="ERROR: Wanted Issue rejected by Network.

" if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") @@ -486,10 +441,10 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n dat+="Issue author unverified.
" if(src.msg == "" || src.msg == "\[REDACTED\]") dat+="Invalid description.
" - dat+="
Return
" + dat+="
Return
" if(17) dat+="Wanted Issue successfully deleted from Circulation
" - dat+="
Return
" + dat+="
Return
" if(18) dat+="-- STATIONWIDE WANTED ISSUE --
\[Submitted by: [news_network.wanted_issue.backup_author]\]
" dat+="Criminal: [news_network.wanted_issue.author]
" @@ -500,57 +455,61 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n dat+="
" else dat+="None" - dat+="

Back
" + dat+="

Back
" if(19) dat+="Wanted issue for [src.channel_name] successfully edited.

" - dat+="
Return
" + dat+="
Return
" if(20) dat+="Printing successful. Please receive your newspaper from the bottom of the machine.

" - dat+="Return" + dat+="Return" if(21) dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.

" - dat+="Return" + dat+="Return" + else + dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" + - var/datum/browser/popup = new(human_or_robot_user, "newscaster_main", "Newscaster Unit #[unit_no]", 400, 600) - popup.set_content(dat) - popup.open() + human_or_robot_user << browse(dat, "window=newscaster_main;size=400x600") + onclose(human_or_robot_user, "newscaster_main") /obj/machinery/newscaster/Topic(href, href_list) if(..()) return if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (issilicon(usr))) usr.set_machine(src) - scan_user(usr) - if(href_list["set_channel_name"]) - channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN) - updateUsrDialog() + src.channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN) + src.updateUsrDialog() + //src.update_icon() else if(href_list["set_channel_lock"]) - c_locked = !c_locked - updateUsrDialog() + src.c_locked = !src.c_locked + src.updateUsrDialog() + //src.update_icon() else if(href_list["submit_new_channel"]) + //var/list/existing_channels = list() //OBSOLETE var/list/existing_authors = list() for(var/datum/feed_channel/FC in news_network.network_channels) + //existing_channels += FC.channel_name if(FC.author == "\[REDACTED\]") existing_authors += FC.backup_author else - existing_authors += FC.author - var/check = FALSE + existing_authors +=FC.author + var/check = 0 for(var/datum/feed_channel/FC in news_network.network_channels) - if(FC.channel_name == channel_name) - check = TRUE + if(FC.channel_name == src.channel_name) + check = 1 break - if(channel_name == "" || channel_name == "\[REDACTED\]" || scanned_user == "Unknown" || check || (scanned_user in existing_authors) ) - screen=7 + if(src.channel_name == "" || src.channel_name == "\[REDACTED\]" || src.scanned_user == "Unknown" || check || (src.scanned_user in existing_authors) ) + src.screen=7 else var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") if(choice=="Confirm") - scan_user(usr) news_network.CreateFeedChannel(src.channel_name, src.scanned_user, c_locked) - screen=5 - updateUsrDialog() + src.screen=5 + src.updateUsrDialog() + //src.update_icon() else if(href_list["set_channel_receiving"]) //var/list/datum/feed_channel/available_channels = list() @@ -558,16 +517,16 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n for(var/datum/feed_channel/F in news_network.network_channels) if( (!F.locked || F.author == scanned_user) && !F.censored) available_channels += F.channel_name - channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in sortList(available_channels) - updateUsrDialog() + src.channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels + src.updateUsrDialog() else if(href_list["set_new_message"]) - msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", "")) - updateUsrDialog() + src.msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", "")) + src.updateUsrDialog() else if(href_list["set_attachment"]) AttachPhoto(usr) - updateUsrDialog() + src.updateUsrDialog() else if(href_list["submit_new_message"]) if(src.msg =="" || src.msg=="\[REDACTED\]" || src.scanned_user == "Unknown" || src.channel_name == "" ) @@ -629,22 +588,33 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n else if(href_list["submit_wanted"]) var/input_param = text2num(href_list["submit_wanted"]) - if(msg == "" || channel_name == "" || scanned_user == "Unknown") - screen = 16 + if(src.msg == "" || src.channel_name == "" || src.scanned_user == "Unknown") + src.screen = 16 else var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") if(choice=="Confirm") - scan_user(usr) - if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. - news_network.submitWanted(channel_name, msg, scanned_user, photo_data, 0 , 1) - screen = 15 + if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below + var/datum/feed_message/WANTED = new /datum/feed_message + WANTED.author = src.channel_name + WANTED.body = src.msg + WANTED.backup_author = src.scanned_user //I know, a bit wacky + if(photo_data) + WANTED.img = photo_data.photo.img + news_network.wanted_issue = WANTED + news_network.alert_readers() + src.screen = 15 else if(news_network.wanted_issue.is_admin_message) alert("The wanted issue has been distributed by a [company_name] higherup. You cannot edit it.","Ok") return - news_network.submitWanted(channel_name, msg, scanned_user, photo_data) - screen = 19 - updateUsrDialog() + news_network.wanted_issue.author = src.channel_name + news_network.wanted_issue.body = src.msg + news_network.wanted_issue.backup_author = src.scanned_user + if(photo_data) + news_network.wanted_issue.img = photo_data.photo.img + src.screen = 19 + + src.updateUsrDialog() else if(href_list["cancel_wanted"]) if(news_network.wanted_issue.is_admin_message) @@ -653,7 +623,7 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel") if(choice=="Confirm") news_network.wanted_issue = null - for(var/obj/machinery/newscaster/NEWSCASTER in GLOB.allCasters) + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) NEWSCASTER.update_icon() src.screen=17 src.updateUsrDialog() @@ -832,17 +802,17 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n var/scribble= "" var/scribble_page -/obj/item/newspaper/attack_self(mob/user) +obj/item/newspaper/attack_self(mob/user as mob) if(ishuman(user)) var/mob/living/carbon/human/human_user = user var/dat - pages = 0 + src.pages = 0 switch(screen) if(0) //Cover dat+="
The Griffon
" dat+="
[company_name]-standard newspaper, for use on [company_name]© Space Facilities

" - if(!length(news_content)) - if(important_message) + if(isemptylist(src.news_content)) + if(src.important_message) dat+="Contents:
    **Important Security Announcement** \[page [src.pages+2]\]
" else dat+="Other than the title, the rest of the newspaper is unprinted..." @@ -859,36 +829,32 @@ var/datum/feed_network/news_network = new /datum/feed_network //The global n dat+="" if(scribble_page==curr_page) dat+="
There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" - dat+= "
Next Page
Done reading
" + dat+= "
Next Page
Done reading
" if(1) // X channel pages inbetween. - for(var/datum/feed_channel/NP in news_content) - pages++ //Let's get it right again. - var/datum/feed_channel/C = news_content[curr_page] + for(var/datum/feed_channel/NP in src.news_content) + src.pages++ //Let's get it right again. + var/datum/feed_channel/C = src.news_content[src.curr_page] dat+="[C.channel_name] \[created by: [C.author]\]

" if(C.censored) dat+="This channel was deemed dangerous to the general welfare of the station and therefore marked with a D-Notice. Its contents were not transferred to the newspaper at the time of printing." else - if(!length(C.messages)) + if(isemptylist(C.messages)) dat+="No Feed stories stem from this channel..." else + dat+="