This commit is contained in:
Fordoxia
2024-05-05 20:44:16 +01:00
69 changed files with 1518 additions and 802 deletions
+1 -1
View File
@@ -24,8 +24,8 @@ _build_dependencies.sh @AffectedArc07
# Executables that need to be security-cleared
dreamchecker.exe @AffectedArc07
milla.dll @AffectedArc07
rust_g.dll @AffectedArc07
librust_g.so @AffectedArc07
### S34NW
+93
View File
@@ -0,0 +1,93 @@
name: Build MILLA
on:
issue_comment:
types: created
jobs:
build-milla:
if: |
github.event.issue.pull_request &&
(github.event.comment.body == '!build_milla') &&
((github.event.sender.id == github.event.issue.user.id) ||
(github.event.comment.author_association == 'COLLABORATOR') ||
(github.event.comment.author_association == 'MEMBER') ||
(github.event.comment.author_association == 'OWNER'))
runs-on: ubuntu-latest
steps:
- name: Like the comment
env:
BASE_REPOSITORY: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/$BASE_REPOSITORY/issues/comments/${{ github.event.comment.id }}/reactions \
-f content='+1'
- name: PR Data
run: |
pr_json=$(curl -L -s --fail-with-body -H "Authorization: token ${{ github.token }}" ${{ github.event.issue.pull_request.url }})
if [ `jq -r '.maintainer_can_modify' <<<$pr_json` == "false" ] ; then
gh pr comment ${{ github.event.issue.html_url }} --body 'GitHub Actions can not push to the repository without "Allow edits and access to secrets by maintainers" checked.'
echo "FAIL_NOTIFIED=true" >> "$GITHUB_ENV"
exit 1
fi
echo "PR_REPO=`jq -r '.head.repo.full_name' <<<$pr_json`" >> $GITHUB_ENV
echo "PR_BRANCH=`jq -r '.head.ref' <<<$pr_json`" >> $GITHUB_ENV
echo "PR_HEAD_LABEL=`jq -r '.head.label' <<<$pr_json`" >> $GITHUB_ENV
- uses: actions/checkout@v4
with:
repository: ${{ env.PR_REPO }}
ref: ${{ env.PR_BRANCH }}
token: ${{ github.token }}
- name: Build MILLA
env:
BASE_BRANCH: ${{ github.event.repository.default_branch }}
BASE_REPOSITORY: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: |
# Get the code.
git config user.name paradisess13[bot]
git config user.email "165046124+paradisess13[bot]@users.noreply.github.com"
git pull origin "$PR_BRANCH" --depth=$((ahead_by + 1))
git remote add upstream "https://github.com/$BASE_REPOSITORY.git"
git fetch upstream "$BASE_BRANCH" --depth=$((behind_by + 1))
cd milla
# Get dependencies.
rustup target add i686-unknown-linux-gnu
rustup target add i686-pc-windows-gnu
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install zlib1g-dev:i386 lib32gcc-11-dev mingw-w64 mingw-w64-i686-dev
# Build it.
cargo build --release --target i686-unknown-linux-gnu
cargo build --release --target i686-pc-windows-gnu
# Copy the built targets to their checked-in locations.
cp target/i686-unknown-linux-gnu/release/libmilla.so ../tools/ci/libmilla_ci.so
cp target/i686-pc-windows-gnu/release/milla.dll ../milla.dll
# Check if a workflow file would be modified by the merge (permissions prevent pushes if so)
latest_workflow_commit=$(git log -n 1 --pretty=format:"%H" upstream/$BASE_BRANCH -- .github/workflows)
if ! git branch --contains $latest_workflow_commit | grep -q "$(git rev-parse --abbrev-ref HEAD)"; then
gh pr comment ${{ github.event.issue.html_url }} --body "GitHub Actions can not push to this branch as workflow files have been changed since your branch was last updated. Please update your branch past https://github.com/$BASE_REPOSITORY/commit/$latest_workflow_commit before using this command again."
echo "FAIL_NOTIFIED=true" >> "$GITHUB_ENV"
exit 1
fi
git commit -a -m "Build MILLA" --allow-empty
git push origin
- name: Notify Failure
if: failure() && env.FAIL_NOTIFIED != 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
gh pr comment ${{ github.event.issue.html_url }} -b 'Building MILLA failed, see the action run log for details: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'
@@ -109,6 +109,16 @@ jobs:
git merge FETCH_HEAD
git push origin
- name: Rebuild TGUI
run: |
if git diff-tree --name-only -r $(git rev-parse HEAD~2) | grep "tgui/public/"
bash tgui/bin/tgui
git commit -m "Rebuild TGUI"
git push origin
else
echo "No changes to rebuild TGUI"
fi
- name: Notify Failure
if: failure() && env.FAIL_NOTIFIED != 'true'
run: |
+3 -1
View File
@@ -171,9 +171,11 @@
#define HUD_STYLE_STANDARD 1
#define HUD_STYLE_REDUCED 2
#define HUD_STYLE_NOHUD 3
#define HUD_STYLE_ACTIONHUD 4
#define HUD_VERSIONS 3 //used in show_hud()
#define HUD_VERSIONS 4 //used in show_hud()
//1 = standard hud
//2 = reduced hud (just hands and intent switcher)
//3 = no hud (for screenshots)
//4 = Only action buttons (so vampires / changelings and such can use abilities while asleep)
+73 -38
View File
@@ -1,21 +1,30 @@
/mob/proc/overlay_fullscreen(category, type, severity)
/mob/proc/overlay_fullscreen(category, type, severity, animated = 0)
var/atom/movable/screen/fullscreen/screen = screens[category]
var/is_centered = istype(screen, /atom/movable/screen/fullscreen/center)
if(!screen || screen.type != type)
// needs to be recreated
clear_fullscreen(category, FALSE)
screens[category] = screen = new type()
else if((!severity || severity == screen.severity) && (!client || screen.screen_loc != "CENTER-7,CENTER-7" || screen.view == client.view))
else if((!severity || severity == screen.severity) && (!is_centered && (!client || screen.screen_loc != "CENTER-7,CENTER-7" || screen.view == client.view)))
// doesn't need to be updated
return screen
screen.icon_state = "[initial(screen.icon_state)][severity]"
screen.severity = severity
if(client && screen.should_show_to(src))
screen.update_for_view(client.view)
if(animated)
INVOKE_ASYNC(src, PROC_REF(apply_screen_animation), animated, screen)
if(!is_centered)
screen.update_for_view(client.view)
client.screen += screen
return screen
/mob/proc/apply_screen_animation(animated = 0, atom/movable/screen/fullscreen/screen)
screen.alpha = 0
animate(screen, alpha = 255, time = animated)
/mob/proc/clear_fullscreen(category, animated = 10)
var/atom/movable/screen/fullscreen/screen = screens[category]
if(!screen)
@@ -30,10 +39,11 @@
if(client)
client.screen -= screen
qdel(screen)
else
if(client)
client.screen -= screen
qdel(screen)
return
if(client)
client.screen -= screen
qdel(screen)
/mob/proc/clear_fullscreens()
for(var/category in screens)
@@ -46,28 +56,21 @@
for(var/category in screens)
screen = screens[category]
if(screen.should_show_to(mymob))
screen.update_for_view(mymob.client.view)
mymob.client.screen |= screen
else
mymob.client.screen -= screen
continue
mymob.client.screen -= screen
/atom/movable/screen/fullscreen
icon = 'icons/mob/screen_full.dmi'
icon_state = "default"
screen_loc = "CENTER-7,CENTER-7"
var/view
layer = FULLSCREEN_LAYER
plane = FULLSCREEN_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
var/view = 7
var/severity = 0
var/show_when_dead = FALSE
/atom/movable/screen/fullscreen/proc/update_for_view(client_view)
if(screen_loc == "CENTER-7,CENTER-7" && view != client_view)
var/list/actualview = getviewsize(client_view)
view = client_view
transform = matrix(actualview[1]/FULLSCREEN_OVERLAY_RESOLUTION_X, 0, 0, 0, actualview[2]/FULLSCREEN_OVERLAY_RESOLUTION_Y, 0)
/atom/movable/screen/fullscreen/proc/should_show_to(mob/mymob)
if(!show_when_dead && mymob.stat == DEAD)
return FALSE
@@ -77,51 +80,62 @@
severity = 0
return ..()
/atom/movable/screen/fullscreen/brute
/// Stretch version is suitable for images that stick to screen edges, as they scale with user screen size
/// For centrally located screen objects, use /atom/movable/screen/fullscreen/center
/atom/movable/screen/fullscreen/stretch
view = 7
/atom/movable/screen/fullscreen/proc/update_for_view(client_view)
if(screen_loc == "CENTER-7,CENTER-7" && view != client_view)
var/list/actualview = getviewsize(client_view)
view = client_view
transform = matrix(actualview[1]/FULLSCREEN_OVERLAY_RESOLUTION_X, 0, 0, 0, actualview[2]/FULLSCREEN_OVERLAY_RESOLUTION_Y, 0)
/atom/movable/screen/fullscreen/stretch/brute
icon_state = "brutedamageoverlay"
layer = UI_DAMAGE_LAYER
/atom/movable/screen/fullscreen/oxy
/atom/movable/screen/fullscreen/stretch/oxy
icon_state = "oxydamageoverlay"
layer = UI_DAMAGE_LAYER
/atom/movable/screen/fullscreen/crit
/atom/movable/screen/fullscreen/stretch/crit
icon_state = "passage"
layer = CRIT_LAYER
/atom/movable/screen/fullscreen/blind
/atom/movable/screen/fullscreen/stretch/blind
icon_state = "blackimageoverlay"
layer = BLIND_LAYER
/atom/movable/screen/fullscreen/impaired
/atom/movable/screen/fullscreen/stretch/impaired
icon_state = "impairedoverlay"
/atom/movable/screen/fullscreen/payback
/atom/movable/screen/fullscreen/stretch/payback
icon = 'icons/mob/screen_payback.dmi'
icon_state = "payback"
show_when_dead = TRUE
/atom/movable/screen/fullscreen/fog
/atom/movable/screen/fullscreen/stretch/fog
icon = 'icons/mob/screen_fog.dmi'
icon_state = "fog"
color = "#FF0000"
/atom/movable/screen/fullscreen/flash
/atom/movable/screen/fullscreen/stretch/flash
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
/atom/movable/screen/fullscreen/flash/noise
/atom/movable/screen/fullscreen/stretch/flash/noise
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "noise"
/atom/movable/screen/fullscreen/high
/atom/movable/screen/fullscreen/stretch/high
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "druggy"
/atom/movable/screen/fullscreen/lighting_backdrop
/atom/movable/screen/fullscreen/stretch/lighting_backdrop
icon = 'icons/mob/screen_gen.dmi'
icon_state = "flash"
transform = matrix(200, 0, 0, 0, 200, 0)
@@ -130,18 +144,18 @@
show_when_dead = TRUE
//Provides darkness to the back of the lighting plane
/atom/movable/screen/fullscreen/lighting_backdrop/lit
/atom/movable/screen/fullscreen/stretch/lighting_backdrop/lit
invisibility = INVISIBILITY_LIGHTING
layer = BACKGROUND_LAYER+21
color = "#000"
show_when_dead = TRUE
//Provides whiteness in case you don't see lights so everything is still visible
/atom/movable/screen/fullscreen/lighting_backdrop/unlit
/atom/movable/screen/fullscreen/stretch/lighting_backdrop/unlit
layer = BACKGROUND_LAYER+20
show_when_dead = TRUE
/atom/movable/screen/fullscreen/see_through_darkness
/atom/movable/screen/fullscreen/stretch/see_through_darkness
icon_state = "nightvision"
plane = LIGHTING_PLANE
layer = LIGHTING_LAYER
@@ -149,7 +163,7 @@
show_when_dead = TRUE
/// An effect which tracks the cursor's location on the screen
/atom/movable/screen/fullscreen/cursor_catcher
/atom/movable/screen/fullscreen/stretch/cursor_catcher
icon_state = "fullscreen_blocker" // Fullscreen semi transparent icon
plane = HUD_PLANE
mouse_opacity = MOUSE_OPACITY_ICON
@@ -167,14 +181,14 @@
var/mouse_params
/// Links this up with a mob
/atom/movable/screen/fullscreen/cursor_catcher/proc/assign_to_mob(mob/owner)
/atom/movable/screen/fullscreen/stretch/cursor_catcher/proc/assign_to_mob(mob/owner)
src.owner = owner
view_list = getviewsize(owner.client.view)
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
calculate_params()
/// Update when the mob we're assigned to has moved
/atom/movable/screen/fullscreen/cursor_catcher/proc/on_move(atom/source, atom/oldloc, dir, forced)
/atom/movable/screen/fullscreen/stretch/cursor_catcher/proc/on_move(atom/source, atom/oldloc, dir, forced)
SIGNAL_HANDLER
if(!given_turf)
@@ -183,19 +197,18 @@
var/y_offset = source.loc.y - oldloc.y
given_turf = locate(given_turf.x + x_offset, given_turf.y + y_offset, given_turf.z)
/atom/movable/screen/fullscreen/cursor_catcher/MouseEntered(location, control, params)
/atom/movable/screen/fullscreen/stretch/cursor_catcher/MouseEntered(location, control, params)
. = ..()
MouseMove(location, control, params)
if(usr == owner)
calculate_params()
/atom/movable/screen/fullscreen/cursor_catcher/MouseMove(location, control, params)
/atom/movable/screen/fullscreen/stretch/cursor_catcher/MouseMove(location, control, params)
if(usr != owner)
return
mouse_params = params
/atom/movable/screen/fullscreen/cursor_catcher/proc/calculate_params()
/atom/movable/screen/fullscreen/stretch/cursor_catcher/proc/calculate_params()
var/list/modifiers = params2list(mouse_params)
var/icon_x = text2num(LAZYACCESS(modifiers, "vis-x"))
if(isnull(icon_x))
@@ -209,6 +222,28 @@
given_x = round(icon_x - world.icon_size * our_x, 1)
given_y = round(icon_y - world.icon_size * our_y, 1)
/// Centered fullscreen atoms
/// These are used to center a widescreen image so it scales properly across screen sizes, not suitable for screen images that eminate from the edge of the screen
/atom/movable/screen/fullscreen/center
appearance_flags = TILE_BOUND
/atom/movable/screen/fullscreen/center/Initialize(mapload)
. = ..()
var/icon/I = new(icon)
var/x_offset = -((I.Width() - world.icon_size) / 2)
var/y_offset = -((I.Height() - world.icon_size) / 2)
qdel(I)
screen_loc = "CENTER:[x_offset],CENTER:[y_offset]"
/atom/movable/screen/fullscreen/center/blind/sleeping
icon = 'icons/mob/screen_sleeping.dmi'
icon_state = "sleepblind"
layer = BLIND_LAYER
/atom/movable/screen/fullscreen/center/blind/disky
icon = 'icons/mob/screen_tight.dmi'
icon_state = "disky"
layer = BLIND_LAYER
#undef FULLSCREEN_LAYER
#undef BLIND_LAYER
+12
View File
@@ -210,6 +210,15 @@
if(length(infodisplay))
mymob.client.screen -= infodisplay
if(HUD_STYLE_ACTIONHUD) //No HUD
hud_shown = TRUE //Governs behavior of other procs
if(static_inventory.len)
mymob.client.screen -= static_inventory
if(toggleable_inventory.len)
mymob.client.screen -= toggleable_inventory
if(infodisplay.len)
mymob.client.screen -= infodisplay
hud_version = display_hud_version
persistent_inventory_update()
mymob.update_action_buttons(1)
@@ -244,6 +253,9 @@
return
/mob/proc/hide_hud()
if(HAS_TRAIT(src, TRAIT_KNOCKEDOUT) && isliving(src))
to_chat(src, "<span class='warning'>You can not change huds while asleep!</span>")
return
if(hud_used && client)
hud_used.show_hud() //Shows the next hud preset
to_chat(src, "<span class='info'>Switched HUD mode. Press the key you just pressed to toggle the HUD mode again.</span>")
+3 -3
View File
@@ -59,7 +59,7 @@
/datum/hud/human/New(mob/living/carbon/human/owner, ui_style = 'icons/mob/screen_white.dmi', ui_color = "#ffffff", ui_alpha = 255)
..()
owner.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/see_through_darkness)
owner.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/stretch/see_through_darkness)
var/atom/movable/screen/using
var/atom/movable/screen/inventory/inv_box
@@ -393,7 +393,7 @@
if(!mymob)
return
var/mob/living/carbon/human/H = mymob
if(inventory_shown && hud_shown)
if(inventory_shown && hud_version == HUD_STYLE_STANDARD)
if(H.shoes)
H.shoes.screen_loc = ui_shoes
H.client.screen += H.shoes
@@ -436,7 +436,7 @@
if(!mymob)
return
var/mob/living/carbon/human/H = mymob
if(hud_shown)
if(hud_version == HUD_STYLE_STANDARD)
if(H.s_store)
H.s_store.screen_loc = ui_sstore1
H.client.screen += H.s_store
+1 -1
View File
@@ -10,7 +10,7 @@
static_inventory += using
action_intent = using
user.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/see_through_darkness)
user.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/stretch/see_through_darkness)
/datum/hud/corgi/New(mob/user)
..()
+2 -2
View File
@@ -44,8 +44,8 @@
/atom/movable/screen/plane_master/lighting/backdrop(mob/mymob)
. = ..()
mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/lighting_backdrop/lit)
mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/lighting_backdrop/unlit)
mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/stretch/lighting_backdrop/lit)
mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/stretch/lighting_backdrop/unlit)
/atom/movable/screen/plane_master/lighting/Initialize()
. = ..()
+1 -1
View File
@@ -205,7 +205,7 @@
if(!R.module)
return
if(R.shown_robot_modules && hud_shown)
if(R.shown_robot_modules && hud_version == HUD_STYLE_STANDARD)
//Modules display is shown
R.client.screen += module_store_icon //"store" icon
+5 -2
View File
@@ -187,7 +187,7 @@ SUBSYSTEM_DEF(tgui)
*
* return int The number of UIs updated.
*/
/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object, full_update = FALSE)
var/count = 0
var/key = "[src_object.UID()]"
// No UIs opened for this src_object
@@ -196,7 +196,10 @@ SUBSYSTEM_DEF(tgui)
for(var/datum/tgui/ui in open_uis_by_src[key])
// Check if UI is valid.
if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user))
ui.process(force = TRUE)
if(full_update)
ui.send_full_update(null, TRUE)
else
ui.process(force = TRUE)
count++
return count
+2 -2
View File
@@ -670,13 +670,13 @@
return ..()
/datum/status_effect/drill_payback/on_apply()
owner.overlay_fullscreen("payback", /atom/movable/screen/fullscreen/payback, 0)
owner.overlay_fullscreen("payback", /atom/movable/screen/fullscreen/stretch/payback, 0)
addtimer(CALLBACK(src, PROC_REF(payback_phase_2)), 2.7 SECONDS)
return TRUE
/datum/status_effect/drill_payback/proc/payback_phase_2()
owner.clear_fullscreen("payback")
owner.overlay_fullscreen("payback", /atom/movable/screen/fullscreen/payback, 1)
owner.overlay_fullscreen("payback", /atom/movable/screen/fullscreen/stretch/payback, 1)
/datum/status_effect/drill_payback/tick() //They are not staying down. This will be a fight.
if(!drilled_successfully && (get_dist(owner, drilled) >= 9)) //We don't want someone drilling the safe at arivals then raiding bridge with the buff
+2 -2
View File
@@ -1023,7 +1023,7 @@
/datum/status_effect/bubblegum_curse/on_creation(mob/living/new_owner, mob/living/source)
. = ..()
source_UID = source.UID()
owner.overlay_fullscreen("Bubblegum", /atom/movable/screen/fullscreen/fog, 1)
owner.overlay_fullscreen("Bubblegum", /atom/movable/screen/fullscreen/stretch/fog, 1)
/datum/status_effect/bubblegum_curse/tick()
var/mob/living/simple_animal/hostile/megafauna/bubblegum/attacker = locateUID(source_UID)
@@ -1031,7 +1031,7 @@
qdel(src)
if(attacker.health <= attacker.maxHealth / 2)
owner.clear_fullscreen("Bubblegum")
owner.overlay_fullscreen("Bubblegum", /atom/movable/screen/fullscreen/fog, 2)
owner.overlay_fullscreen("Bubblegum", /atom/movable/screen/fullscreen/stretch/fog, 2)
if(!coward_checking)
if(owner.z != attacker.z)
addtimer(CALLBACK(src, PROC_REF(onstation_coward_callback)), 12 SECONDS)
+6 -6
View File
@@ -26,7 +26,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
uplink_items[I.category] = list()
uplink_items[I.category] += I
if(I.limited_stock < 0 && !I.cant_discount && I.item && I.cost > 5)
if(I.limited_stock < 0 && I.can_discount && I.item && I.cost > 5)
sales_items += I
for(var/datum/uplink_item/I in last)
@@ -79,7 +79,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
/// This makes an item on the uplink only show up to the specified species
var/list/species = null
var/surplus = 100 //Chance of being included in the surplus crate (when pick() selects it)
var/cant_discount = FALSE
var/can_discount = TRUE
var/limited_stock = -1 // Can you only buy so many? -1 allows for infinite purchases
var/hijack_only = FALSE //can this item be purchased only during hijackings?
var/refundable = FALSE
@@ -379,7 +379,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
reference = "SKD"
item = /obj/item/melee/knuckleduster/syndie
cost = 10
cant_discount = TRUE
can_discount = FALSE
// GRENADES AND EXPLOSIVES
@@ -751,7 +751,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 10
surplus = 0
hijack_only = TRUE //This is an item only useful for a hijack traitor, as such, it should only be available in those scenarios.
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/device_tools/advpinpointer
name = "Advanced Pinpointer"
@@ -887,7 +887,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
reference = "BABA"
item = /obj/item/toy/syndicateballoon
cost = 100
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/badass/bomber
name = "Syndicate Bomber Jacket"
@@ -906,7 +906,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
/datum/uplink_item/bundles_TC
category = "Bundles and Telecrystals"
surplus = 0
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/bundles_TC/telecrystal
name = "Raw Telecrystal"
+6 -6
View File
@@ -120,7 +120,7 @@
refund_path = /obj/item/antag_spawner/nuke_ops
cost = 100
refundable = TRUE
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/support/reinforcement/assault_borg
name = "Syndicate Assault Cyborg"
@@ -347,7 +347,7 @@
reference = "C4B"
item = /obj/item/storage/backpack/duffel/syndie/c4
cost = 40 //20% discount!
cant_discount = TRUE
can_discount = FALSE
uplinktypes = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)
/datum/uplink_item/explosives/breaching_charge
@@ -366,7 +366,7 @@
reference = "X4B"
item = /obj/item/storage/backpack/duffel/syndie/x4
cost = 20
cant_discount = TRUE
can_discount = FALSE
uplinktypes = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)
/datum/uplink_item/explosives/grenadier
@@ -643,7 +643,7 @@
cost = 55
excludefrom = list(UPLINK_TYPE_TRAITOR, UPLINK_TYPE_SIT)
surplus = 0
cant_discount = TRUE
can_discount = FALSE
hijack_only = FALSE
/datum/uplink_item/explosives/emp_bomb/nuke
@@ -651,7 +651,7 @@
cost = 50
excludefrom = list(UPLINK_TYPE_TRAITOR, UPLINK_TYPE_SIT)
surplus = 0
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/explosives/atmosfiregrenades/nuke
reference = "NAPG"
@@ -659,7 +659,7 @@
cost = 60
excludefrom = list(UPLINK_TYPE_TRAITOR, UPLINK_TYPE_SIT)
surplus = 0
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/stealthy_tools/chameleon/nuke
reference = "NCHAM"
+1 -1
View File
@@ -1,7 +1,7 @@
/// This uplink catagory is for uplink items avalible by special circumstances. Think station traits, or if some event rolling in a round gave traitors special items, or an objective.
/datum/uplink_item/special
category = "Special Offers"
cant_discount = TRUE
can_discount = FALSE
surplus = 0
excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST, UPLINK_TYPE_TRAITOR, UPLINK_TYPE_SIT)
+8 -8
View File
@@ -4,7 +4,7 @@
/datum/uplink_item/jobspecific
category = "Job Specific Tools"
cant_discount = TRUE
can_discount = FALSE
excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST) // Stops the job specific category appearing for nukies
//Clown
@@ -333,7 +333,7 @@
/datum/uplink_item/species_restricted
category = "Species Specific Gear"
cant_discount = TRUE
can_discount = FALSE
excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST) // Stops the job specific category appearing for nukies
//skrell
@@ -420,7 +420,7 @@
refund_path = /obj/item/guardiancreator/tech/choose
refundable = TRUE
surplus = 0 // This being refundable makes this a big no no in my mind.
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/stealthy_weapons/martialarts
name = "Martial Arts Scroll"
@@ -431,7 +431,7 @@
item = /obj/item/sleeping_carp_scroll
cost = 65
excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/stealthy_weapons/bearserk
name = "Bearserker Pelt"
@@ -548,7 +548,7 @@
cost = 70
excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)
surplus = 0
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/cyber_implants/sensory_enhancer
name = "Qani-Laaca Sensory Computer Autoimplanter"
@@ -659,7 +659,7 @@
cost = 40
excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)
surplus = 0
cant_discount = TRUE
can_discount = FALSE
hijack_only = TRUE
/datum/uplink_item/explosives/emp_bomb
@@ -671,7 +671,7 @@
cost = 40
excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)
surplus = 0
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/explosives/emp_bomb/New()
..()
@@ -687,7 +687,7 @@
cost = 50
excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)
surplus = 0
cant_discount = TRUE
can_discount = FALSE
/datum/uplink_item/stealthy_tools/chameleon
name = "Chameleon Kit"
+63 -107
View File
@@ -1,7 +1,3 @@
//This is a beta game mode to test ways to implement an "infinite" traitor round in which more traitors are automatically added in as needed.
//Automatic traitor adding is complete pending the inevitable bug fixes. Need to add a respawn system to let dead people respawn after 30 minutes or so.
/datum/game_mode/traitor/autotraitor
name = "AutoTraitor"
config_tag = "extend-a-traitormongous"
@@ -11,10 +7,9 @@
/datum/game_mode/traitor/autotraitor/announce()
..()
to_chat(world, "<B>Game mode is AutoTraitor. Traitors will be added to the round automagically as needed.</B>")
to_chat(world, "<b>Game mode is AutoTraitor. Traitors will be added to the round automagically as needed.</b>")
/datum/game_mode/traitor/autotraitor/pre_setup()
if(GLOB.configuration.gamemode.prevent_mindshield_antags)
restricted_jobs += protected_jobs
@@ -24,7 +19,6 @@
if(P.client && P.ready)
num_players++
//var/r = rand(5)
var/num_traitors = 1
var/max_traitors = 1
var/traitor_prob = 0
@@ -33,7 +27,7 @@
// Stop setup if no possible traitors
if(!length(possible_traitors))
return 0
return FALSE
if(GLOB.configuration.gamemode.traitor_scaling)
num_traitors = max_traitors - 1 + prob(traitor_prob)
@@ -42,8 +36,7 @@
else
num_traitors = max(1, min(num_players(), traitors_possible))
for(var/i = 0, i < num_traitors, i++)
for(var/i in 1 to num_traitors)
var/datum/mind/traitor = pick(possible_traitors)
pre_traitors += traitor
possible_traitors.Remove(traitor)
@@ -56,128 +49,91 @@
traitor.special_role = SPECIAL_ROLE_TRAITOR
traitor.restricted_roles = restricted_jobs
// if(!length(traitors))
// return 0
return 1
return TRUE
/datum/game_mode/traitor/autotraitor/post_setup()
..()
traitorcheckloop()
addtimer(CALLBACK(src, PROC_REF(traitor_check_loop)), 15 MINUTES)
/datum/game_mode/traitor/autotraitor/proc/traitorcheckloop()
spawn(9000)
if(SSshuttle.emergency.mode >= SHUTTLE_ESCAPE)
return
//message_admins("Performing AutoTraitor Check")
var/playercount = 0
var/traitorcount = 0
var/possible_traitors[0]
for(var/mob/living/player in GLOB.mob_list)
if(player.client && player.stat != DEAD)
playercount += 1
if(!player.mind)
continue
if(player.mind.special_role)
traitorcount += 1
continue
if(ishuman(player) || isAI(player))
if((ROLE_TRAITOR in player.client.prefs.be_special) && !player.client.skip_antag && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, ROLE_SYNDICATE))
possible_traitors += player.mind
for(var/datum/mind/player in possible_traitors)
for(var/job in restricted_jobs)
if(player.assigned_role == job)
possible_traitors -= player
if(!player.current || !ishuman(player.current)) // Remove mindshield-implanted mobs from the list
/datum/game_mode/traitor/autotraitor/proc/traitor_check_loop()
if(SSshuttle.emergency.mode >= SHUTTLE_ESCAPE)
return
var/player_count = 0
var/traitor_count = 0
var/list/possible_traitors = list()
for(var/mob/living/player in GLOB.mob_list)
if(player.client && player.stat != DEAD)
player_count += 1
if(!player.mind)
continue
var/mob/living/carbon/human/H = player.current
for(var/obj/item/bio_chip/mindshield/I in H.contents)
if(I && I.implanted)
possible_traitors -= player
if(!H.job || H.mind.offstation_role) //Golems, special events stuff, etc.
if(player.mind.special_role)
traitor_count += 1
continue
if(ishuman(player) || isAI(player))
if((ROLE_TRAITOR in player.client.prefs.be_special) && !player.client.skip_antag && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, ROLE_SYNDICATE))
possible_traitors += player.mind
for(var/datum/mind/player in possible_traitors)
for(var/job in restricted_jobs)
if(player.assigned_role == job)
possible_traitors -= player
//message_admins("Live Players: [playercount]")
//message_admins("Live Traitors: [traitorcount]")
// message_admins("Potential Traitors:")
// for(var/mob/living/traitorlist in possible_traitors)
// message_admins("[traitorlist.real_name]")
if(!player.current || !ishuman(player.current)) // Remove mindshield-implanted mobs from the list
continue
var/mob/living/carbon/human/H = player.current
for(var/obj/item/bio_chip/mindshield/I in H.contents)
if(I && I.implanted)
possible_traitors -= player
if(!H.job || H.mind.offstation_role) //Golems, special events stuff, etc.
possible_traitors -= player
// var/r = rand(5)
// var/target_traitors = 1
var/max_traitors = 1
var/traitor_prob = 0
max_traitors = round(playercount / 10) + 1
traitor_prob = (playercount - (max_traitors - 1) * 10) * 5
if(traitorcount < max_traitors - 1)
traitor_prob += 50
var/max_traitors = 1
var/traitor_prob = 0
max_traitors = round(player_count / 10) + 1
traitor_prob = (player_count - (max_traitors - 1) * 10) * 5
if(traitor_count < max_traitors - 1)
traitor_prob += 50
if(traitor_count < max_traitors)
if(prob(traitor_prob))
message_admins("Making a new Traitor.")
if(!length(possible_traitors))
message_admins("No potential traitors. Cancelling new traitor.")
addtimer(CALLBACK(src, PROC_REF(traitor_check_loop)), 15 MINUTES)
return
var/datum/mind/new_traitor_mind = pick(possible_traitors)
var/mob/living/new_traitor = new_traitor_mind.current
if(traitorcount < max_traitors)
//message_admins("Number of Traitors is below maximum. Rolling for new Traitor.")
//message_admins("The probability of a new traitor is [traitor_prob]%")
if(prob(traitor_prob))
message_admins("Making a new Traitor.")
if(!length(possible_traitors))
message_admins("No potential traitors. Cancelling new traitor.")
traitorcheckloop()
return
var/datum/mind/newtraitormind = pick(possible_traitors)
var/mob/living/newtraitor = newtraitormind.current
//message_admins("[newtraitor.real_name] is the new Traitor.")
to_chat(newtraitor, "<span class='danger'>ATTENTION:</span> It is time to pay your debt to the Syndicate...")
newtraitor.mind.add_antag_datum(/datum/antagonist/traitor)
//else
//message_admins("No new traitor being added.")
//else
//message_admins("Number of Traitors is at maximum. Not making a new Traitor.")
traitorcheckloop()
to_chat(new_traitor, "<span class='danger'>ATTENTION:</span> It is time to pay your debt to the Syndicate...")
new_traitor.mind.add_antag_datum(/datum/antagonist/traitor)
addtimer(CALLBACK(src, PROC_REF(traitor_check_loop)), 15 MINUTES)
/datum/game_mode/traitor/autotraitor/latespawn(mob/living/carbon/human/character)
..()
if(SSshuttle.emergency.mode >= SHUTTLE_ESCAPE)
return
//message_admins("Late Join Check")
if(character.client && (ROLE_TRAITOR in character.client.prefs.be_special) && !character.client.skip_antag && !jobban_isbanned(character, ROLE_TRAITOR) && !jobban_isbanned(character, ROLE_SYNDICATE))
//message_admins("Late Joiner has Be Syndicate")
//message_admins("Checking number of players")
var/playercount = 0
var/traitorcount = 0
var/player_count = 0
var/traitor_count = 0
for(var/mob/living/player in GLOB.mob_list)
if(player.client && player.stat != DEAD)
playercount += 1
player_count += 1
if(player.mind && player.mind.special_role)
traitorcount += 1
//message_admins("Live Players: [playercount]")
//message_admins("Live Traitors: [traitorcount]")
traitor_count += 1
//var/r = rand(5)
//var/target_traitors = 1
var/max_traitors = 2
var/traitor_prob = 0
max_traitors = round(playercount / 10) + 1
traitor_prob = (playercount - (max_traitors - 1) * 10) * 5
if(traitorcount < max_traitors - 1)
max_traitors = round(player_count / 10) + 1
traitor_prob = (player_count - (max_traitors - 1) * 10) * 5
if(traitor_count < max_traitors - 1)
traitor_prob += 50
//target_traitors = max(1, min(round((playercount + r) / 10, 1), traitors_possible))
//message_admins("Target Traitor Count is: [target_traitors]")
if(traitorcount < max_traitors)
if(traitor_count < max_traitors)
for(var/job in restricted_jobs)
if(character.mind.assigned_role == job || !ishuman(character))
return
//message_admins("Number of Traitors is below maximum. Rolling for New Arrival Traitor.")
//message_admins("The probability of a new traitor is [traitor_prob]%")
if(prob(traitor_prob))
message_admins("New traitor roll passed. Making a new Traitor.")
character.mind.make_Traitor() //TEMP: Add proper checks for loyalty here. uc_guy
//else
//message_admins("New traitor roll failed. No new traitor.")
//else
//message_admins("Late Joiner does not have Be Syndicate")
message_admins("New traitor roll passed. Making a new Traitor.")
character.mind.make_Traitor()
+1 -1
View File
@@ -398,7 +398,7 @@
/obj/machinery/camera/get_remote_view_fullscreens(mob/user)
if(view_range == short_range) //unfocused
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/stretch/impaired, 2)
/obj/machinery/camera/update_remote_sight(mob/living/user)
if(isXRay() && isAI(user))
@@ -208,7 +208,7 @@
if(final)
playsound(origin, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
remote_eye.setLoc(get_turf(final))
C.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash/noise)
C.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/stretch/flash/noise)
C.clear_fullscreen("flash", 3) //Shorter flash than normal since it's an ~~advanced~~ console!
else
playsound(origin, 'sound/machines/terminal_prompt_deny.ogg', 25, FALSE)
+55 -9
View File
@@ -35,6 +35,28 @@ Possible to do for anyone motivated enough:
GLOBAL_LIST_EMPTY(holopads)
/**
* A stationary holopad for projecting hologram and making and receiving holocalls.
*
* Holopads are floor-plane machines similar, in appearance and interactive function, to quantum pads. They can be
* used by crew members to make and answer holocalls, or by the AI to project holograms autonomously.
*
* Holopads are machines which can project a hologram up to `holo_range` tiles away. They do this in one of two modes:
* holocalls, and AI holograms. Holocalls require a user to stand on a holopad, use its menu to select a remote holopad,
* and make a call. Holocalls must be answered by the receiving holopad, or they will fail. Holopads can be configured
* globally to auto-accept instead of failing, with the debug static variable `force_answer_call`. They can also be
* individually configured to auto-accept calls immediately by setting their public mode option (`public_mode`),
* which can be done in-game by using a screwdriver and then a multitool on a holopad. Holocalls will automatically end
* if power goes out, the caller moves off the calling holopad, the caller projects outside the receiving holopad's
* range, the caller is killed or incapacitated, the caller ghosts or disconnects, or the caller is QDELETED. AI
* holograms require the AI to focus on the originating holopad and click on it; no answer is required. If the AI moves
* out of a holopad's range and into the range of another, it will attempt to transfer its hologram to the next holopad.
* Otherwise, AI holograms will stop projecting if power goes out for the originating holopad, the AI clicks on its
* origin holopad, or, like holocalls, if the AI is killed, incapacitated, disconnected, QDELETED, or ghosts.
* Holopads relay speech from the caller made with the :h radio key, and relay all speech on the answering end to the
* caller or AI.
*/
/obj/machinery/hologram/holopad
name = "holopad"
desc = "It's a floor-mounted device for projecting holographic images."
@@ -47,17 +69,29 @@ GLOBAL_LIST_EMPTY(holopads)
max_integrity = 300
armor = list(melee = 50, bullet = 20, laser = 20, energy = 20, bomb = 0, rad = 0, fire = 50, acid = 0)
var/list/masters = list()//List of living mobs that use the holopad
var/list/holorays = list()//Holoray-mob link.
var/last_request = 0 //to prevent request spam. ~Carn
var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating.
/// List of living mobs currently using the holopad
var/list/masters = list()
/// Holoray-mob link.
var/list/holorays = list()
/// Last request time, to prevent request spam. ~Carn
var/last_request = 0
/// The range, in tiles, that a holopad can project a hologram.
var/holo_range = 5
var/temp = ""
var/list/holo_calls //array of /datum/holocalls
var/datum/holocall/outgoing_call //do not modify the datums only check and call the public procs
var/static/force_answer_call = FALSE //Calls will be automatically answered after a couple rings, here for debugging
/// A list of holocalls associated with this holopad.
var/list/holo_calls
/// The outgoing holocall currently being processed by this holopad.
var/datum/holocall/outgoing_call
/// Universal debug toggle for whether holopads will automatically answer calls after a few rings.
var/static/force_answer_call = FALSE
/// Toggle for auto-answering calls immediately, set via multitool.
var/public_mode = FALSE
/// The ray effect emanating from this holopad to the produced hologram.
var/obj/effect/overlay/holoray/ray
/// Whether or not this holopad is currently ringing, from being called by another pad.
var/ringing = FALSE
var/dialling_input = FALSE //The user is currently selecting where to send their call
/// Whether or not the user is currently selecting where to send their call.
var/dialling_input = FALSE
/obj/machinery/hologram/holopad/Initialize(mapload)
. = ..()
@@ -120,6 +154,13 @@ GLOBAL_LIST_EMPTY(holopads)
return
return ..()
/obj/machinery/hologram/holopad/multitool_act(mob/living/user, obj/item/I)
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
public_mode = !public_mode
to_chat(user, "<span class='notice'>You [public_mode ? "enable" : "disable"] the holopad's public mode setting.</span>")
/obj/machinery/hologram/holopad/screwdriver_act(mob/user, obj/item/I)
. = TRUE
default_deconstruction_screwdriver(user, "holopad_open", "holopad0", I)
@@ -143,6 +184,11 @@ GLOBAL_LIST_EMPTY(holopads)
user.set_machine(src)
interact(user)
/obj/machinery/hologram/holopad/examine(mob/user)
. = ..()
. += "<span class='notice'>Its maintenance panel can be <b>screwed [panel_open ? "closed" : "open"]</b>.</span>"
. += "<span class='notice'>Its public mode indicator reads <b>[public_mode ? "on" : "off"]</b>. It can be <b>turned [public_mode ? "off" : "on"]</b> by using a multitool while the maintenance panel is open.</span>"
/obj/machinery/hologram/holopad/AltClick(mob/living/carbon/human/user)
if(..())
return
@@ -300,7 +346,7 @@ GLOBAL_LIST_EMPTY(holopads)
continue
if(HC.connected_holopad != src)
if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2)))
if((force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2))) || public_mode)
HC.Answer(src)
break
if(outgoing_call)
+228 -241
View File
@@ -1,7 +1,3 @@
#define MATTER_100 100
#define MATTER_500 500
#define TAB_AIRLOCK_TYPE 1
#define TAB_AIRLOCK_ACCESS 2
@@ -10,6 +6,204 @@
#define MODE_WINDOW "Windows"
#define MODE_DECON "Deconstruction"
/// A generic action for an RCD.
/datum/rcd_act
/// How much compressed matter this action costs.
var/cost = 0
/// How long this action takes.
var/delay = 0
/// The message (if any) to send the user when the action starts.
var/start_message
/// The effect (if any) to create when the action starts.
var/obj/effect/start_effect_type
/// The effect (if any) to create when the action completes.
var/obj/effect/end_effect_type
/// The mode the RCD must be in.
var/mode
/// Attempt the action. This should not need to be overridden.
/datum/rcd_act/proc/try_act(atom/A, obj/item/rcd/rcd, mob/user)
if(!can_act(A, rcd))
return FALSE
// We don't use the sound effect from use_tool because RCDs have a different sound effect for the start and end.
playsound(get_turf(rcd), 'sound/machines/click.ogg', 50, TRUE)
if(!rcd.tool_use_check(user, cost))
return FALSE
if(start_message)
to_chat(user, start_message)
var/obj/effect/start_effect
if(start_effect_type)
start_effect = new start_effect_type(get_turf(A))
if(!rcd.use_tool(A, user, delay, cost))
if(!QDELETED(start_effect))
qdel(start_effect)
return FALSE
if(start_effect)
qdel(start_effect)
// If time elapsed, check our preconditions again.
if(delay && !can_act(A, rcd))
return FALSE
if(end_effect_type)
new end_effect_type(get_turf(A))
playsound(get_turf(rcd), 'sound/items/deconstruct.ogg', 50, TRUE)
act(A, rcd, user)
return TRUE
/// Test to see if the act is possible. You should usually override this.
/datum/rcd_act/proc/can_act(atom/A, obj/item/rcd/rcd)
SHOULD_CALL_PARENT(TRUE)
return rcd.mode == mode
/// Perform the act. You should usually override this.
/datum/rcd_act/proc/act(atom/A, obj/item/rcd/rcd, mob/user)
return
/datum/rcd_act/place_floor
mode = MODE_TURF
cost = 1
start_message = "Building floor..."
end_effect_type = /obj/effect/temp_visual/rcd_effect/end
/datum/rcd_act/place_floor/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isspaceturf(A) || istype(A, /obj/structure/lattice)
/datum/rcd_act/place_floor/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
act_on.ChangeTurf(/turf/simulated/floor/plating)
/datum/rcd_act/place_wall
mode = MODE_TURF
cost = 3
start_message = "Building wall..."
delay = 2 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/short
end_effect_type = /obj/effect/temp_visual/rcd_effect/end
/datum/rcd_act/place_wall/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isfloorturf(A)
/datum/rcd_act/place_wall/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
act_on.ChangeTurf(/turf/simulated/wall)
/datum/rcd_act/place_airlock
mode = MODE_AIRLOCK
cost = 10
start_message = "Building airlock..."
delay = 5 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect
end_effect_type = /obj/effect/temp_visual/rcd_effect/end
/datum/rcd_act/place_airlock/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isfloorturf(A) && !(/obj/machinery/door/airlock in A.contents)
/datum/rcd_act/place_airlock/act(atom/A, obj/item/rcd/rcd, mob/user)
var/obj/machinery/door/airlock/T = new rcd.door_type(A)
if(T.glass)
T.polarized_glass = rcd.electrochromic
T.name = rcd.door_name
T.autoclose = TRUE
if(rcd.one_access)
T.req_one_access = rcd.selected_accesses.Copy()
else
T.req_access = rcd.selected_accesses.Copy()
/datum/rcd_act/place_window
mode = MODE_WINDOW
cost = 2
start_message = "Building window..."
delay = 2 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/short
end_effect_type = /obj/effect/temp_visual/rcd_effect/end
/datum/rcd_act/place_window/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isfloorturf(A) && !(/obj/structure/grille in A.contents)
/datum/rcd_act/place_window/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on= A
for(var/obj/structure/window/window_to_delete in act_on)
qdel(window_to_delete)
new /obj/structure/grille(act_on)
new /obj/structure/window/full/reinforced(act_on)
act_on.ChangeTurf(/turf/simulated/floor/plating) // Platings go under windows.
/datum/rcd_act/remove_floor
mode = MODE_DECON
cost = 5
start_message = "Deconstructing floor..."
delay = 5 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse
/datum/rcd_act/remove_floor/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isfloorturf(A)
/datum/rcd_act/remove_floor/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
act_on.ChangeTurf(act_on.baseturf)
/datum/rcd_act/remove_wall
mode = MODE_DECON
cost = 5
start_message = "Deonstructing wall..."
delay = 5 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse
/datum/rcd_act/remove_wall/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
if(isreinforcedwallturf(A) && !rcd.canRwall)
return FALSE
if(istype(A, /turf/simulated/wall/indestructible))
return FALSE
return iswallturf(A)
/datum/rcd_act/remove_wall/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
act_on.ChangeTurf(/turf/simulated/floor/plating)
/datum/rcd_act/remove_airlock
mode = MODE_DECON
cost = 20
start_message = "Deconstructing airlock..."
delay = 5 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse
/datum/rcd_act/remove_airlock/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return istype(A, /obj/machinery/door/airlock)
/datum/rcd_act/remove_airlock/act(atom/A, obj/item/rcd/rcd, mob/user)
qdel(A)
/datum/rcd_act/remove_window
mode = MODE_DECON
cost = 2
start_message = "Deconstructing window..."
delay = 2 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse_short
/datum/rcd_act/remove_window/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return istype(A, /obj/structure/window)
/datum/rcd_act/remove_window/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
qdel(A)
for(var/obj/structure/grille/grill_to_destroy in act_on)
qdel(grill_to_destroy)
/obj/item/rcd
name = "rapid-construction-device (RCD)"
desc = "A device used to rapidly build and deconstruct walls, floors and airlocks."
@@ -25,7 +219,6 @@
materials = list(MAT_METAL = 30000)
origin_tech = "engineering=4;materials=2"
toolspeed = 1
usesound = 'sound/items/deconstruct.ogg'
flags_2 = NO_MAT_REDEMPTION_2
req_access = list(ACCESS_ENGINE)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 50)
@@ -37,7 +230,7 @@
/// The current amount of matter stored.
var/matter = NONE
/// The max amount of matter that can be stored.
var/max_matter = MATTER_100
var/max_matter = 100
/// The RCD's current build mode.
var/mode = MODE_TURF
/// If the RCD can deconstruct reinforced walls.
@@ -65,9 +258,16 @@
var/static/list/door_types_ui_list = list()
/// An associative list containing all station accesses. Includes their name and access number. For use with the UI.
var/static/list/door_accesses_list = list()
/// The list of potential RCD actions.
var/static/list/possible_actions
/obj/item/rcd/Initialize()
. = ..()
if(!length(possible_actions))
possible_actions = list()
for(var/action_type in subtypesof(/datum/rcd_act))
possible_actions += new action_type()
spark_system = new /datum/effect_system/spark_spread
spark_system.set_up(5, 0, src)
spark_system.attach(src)
@@ -364,214 +564,6 @@
else
return FALSE
/**
* Called in `afterattack()` if `mode` is set to `MODE_TURF`.
*
* Creates either a plating, or a wall, depending on the turf that already exists at the location.
*
* Arguments:
* * A - the location we're trying to build at.
* * user - the mob using the RCD.
*/
/obj/item/rcd/proc/mode_turf(atom/A, mob/user)
if(isspaceturf(A) || istype(A, /obj/structure/lattice))
if(useResource(1, user))
to_chat(user, "Building Floor...")
playsound(loc, usesound, 50, 1)
var/turf/AT = get_turf(A)
new/obj/effect/temp_visual/rcd_effect/end(get_turf(A))
AT.ChangeTurf(/turf/simulated/floor/plating)
return TRUE
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
if(isfloorturf(A))
if(checkResource(3, user))
to_chat(user, "Building Wall...")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
var/obj/effect/temp_visual/rcd_effect/short/E = new(get_turf(A))
if(do_after(user, 2 SECONDS * toolspeed, target = A))
if(!isfloorturf(A))
return FALSE
if(!useResource(3, user))
return FALSE
playsound(loc, usesound, 50, 1)
var/turf/AT = A
new/obj/effect/temp_visual/rcd_effect/end(get_turf(A))
AT.ChangeTurf(/turf/simulated/wall)
return TRUE
qdel(E)
return FALSE
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
to_chat(user, "<span class='warning'>ERROR! Location unsuitable for wall construction!</span>")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
/**
* Called in `afterattack()` if `mode` is set to `MODE_AIRLOCK`.
*
* Creates an `door_type` airlock at the given location `A`, and assigns it accesses from `selected_accesses`.
*
* Arguments:
* * A - the location we're trying to build at.
* * user - the mob using the RCD.
*/
/obj/item/rcd/proc/mode_airlock(atom/A, mob/user)
if(isfloorturf(A))
if(checkResource(10, user))
to_chat(user, "Building Airlock...")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
var/obj/effect/temp_visual/rcd_effect/E = new(get_turf(A))
if(do_after(user, 5 SECONDS * toolspeed, target = A))
if(locate(/obj/machinery/door/airlock) in A.contents)
return FALSE
if(!useResource(10, user))
return FALSE
playsound(loc, usesound, 50, 1)
new/obj/effect/temp_visual/rcd_effect/end(get_turf(A))
var/obj/machinery/door/airlock/T = new door_type(A)
if(T.glass)
T.polarized_glass = electrochromic
T.name = door_name
T.autoclose = TRUE
if(one_access)
T.req_one_access = selected_accesses.Copy()
else
T.req_access = selected_accesses.Copy()
return FALSE
qdel(E)
return FALSE
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
to_chat(user, "<span class='warning'>ERROR! Location unsuitable for airlock construction!</span>")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
/**
* Called in `afterattack()` if `mode` is set to `MODE_DECON`.
*
* Deconstrcts the target atom `A`.
* Valid atoms are: basic walls, reinforced walls (if `canRwall` is `TRUE`), airlocks, and windows.
*
* Arguments:
* * A - the location we're trying to build at.
* * user - the mob using the RCD.
*/
/obj/item/rcd/proc/mode_decon(atom/A, mob/user)
if(iswallturf(A))
if(isreinforcedwallturf(A) && !canRwall)
return FALSE
if(istype(A, /turf/simulated/wall/indestructible))
return FALSE
if(checkResource(5, user))
to_chat(user, "Deconstructing Wall...")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
var/obj/effect/temp_visual/rcd_effect/reverse/E = new(get_turf(A))
if(do_after(user, 5 SECONDS * toolspeed, target = A))
if(!useResource(5, user))
return FALSE
playsound(loc, usesound, 50, 1)
var/turf/AT = A
AT.ChangeTurf(/turf/simulated/floor/plating)
return TRUE
qdel(E)
return FALSE
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
if(isfloorturf(A))
if(checkResource(5, user))
to_chat(user, "Deconstructing Floor...")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
var/obj/effect/temp_visual/rcd_effect/reverse/E = new(get_turf(A))
if(do_after(user, 5 SECONDS * toolspeed, target = A))
if(!useResource(5, user))
return FALSE
playsound(loc, usesound, 50, 1)
var/turf/AT = A
AT.ChangeTurf(AT.baseturf)
return TRUE
qdel(E)
return FALSE
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
if(istype(A, /obj/machinery/door/airlock))
if(checkResource(20, user))
to_chat(user, "Deconstructing Airlock...")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
var/obj/effect/temp_visual/rcd_effect/reverse/E = new(get_turf(A))
if(do_after(user, 5 SECONDS * toolspeed, target = A))
if(!useResource(20, user))
return FALSE
playsound(loc, usesound, 50, 1)
qdel(A)
return TRUE
qdel(E)
return FALSE
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
if(istype(A, /obj/structure/window))
if(!checkResource(2, user))
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
to_chat(user, "Deconstructing window...")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
var/obj/effect/temp_visual/rcd_effect/reverse_short/E = new(get_turf(A))
if(!do_after(user, 20 * toolspeed, target = A))
qdel(E)
return FALSE
if(!useResource(2, user))
return FALSE
playsound(loc, usesound, 50, 1)
var/turf/T1 = get_turf(A)
QDEL_NULL(A)
for(var/obj/structure/grille/G in T1.contents)
qdel(G)
return TRUE
return FALSE
/**
* Called in `afterattack()` if `mode` is set to `MODE_WINDOW`.
*
* Constructs a grille and 4 reinforced window panes at the given location `A`.
*
* Arguments:
* * A - the location we're trying to build at.
* * user - the mob using the RCD.
*/
/obj/item/rcd/proc/mode_window(atom/A, mob/user)
if(isfloorturf(A))
if(locate(/obj/structure/grille) in A)
return FALSE // We already have window
if(!checkResource(2, user))
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
to_chat(user, "Constructing window...")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
var/obj/effect/temp_visual/rcd_effect/short/E = new(get_turf(A))
if(!do_after(user, 20 * toolspeed, target = A))
qdel(E)
return FALSE
if(locate(/obj/structure/grille) in A)
return FALSE // We already have window
if(!useResource(2, user))
return FALSE
playsound(loc, usesound, 50, 1)
new/obj/effect/temp_visual/rcd_effect/end(get_turf(A))
new /obj/structure/grille(A)
for(var/obj/structure/window/W in A)
qdel(W)
new /obj/structure/window/full/reinforced(A)
var/turf/AT = A
AT.ChangeTurf(/turf/simulated/floor/plating) // Platings go under windows.
return TRUE
to_chat(user, "<span class='warning'>ERROR! Location unsuitable for window construction!</span>")
playsound(loc, 'sound/machines/click.ogg', 50, 1)
return FALSE
/obj/item/rcd/afterattack(atom/A, mob/user, proximity)
if(!proximity)
return FALSE
@@ -580,31 +572,29 @@
if(!is_type_in_list(A, allowed_targets))
return FALSE
switch(mode)
if(MODE_TURF)
. = mode_turf(A, user)
if(MODE_AIRLOCK)
. = mode_airlock(A, user)
if(MODE_DECON)
. = mode_decon(A, user)
if(MODE_WINDOW)
. = mode_window(A, user)
else
to_chat(user, "ERROR: RCD in MODE: [mode] attempted use by [user]. Send this text #coderbus or an admin.")
. = 0
for(var/datum/rcd_act/act in possible_actions)
if(act.can_act(A, src))
. = act.try_act(A, src, user)
update_icon(UPDATE_OVERLAYS)
SStgui.update_uis(src)
return
if(mode == MODE_DECON)
to_chat(user, "<span class='warning'>You can't deconstruct that!</span>")
else
to_chat(user, "<span class='warning'>Location unsuitable for construction.</span>")
update_icon(UPDATE_OVERLAYS)
SStgui.update_uis(src)
return FALSE
/**
* Called in each of the four build modes after an object is successfully built.
*
* Subtracts the amount of matter used from `matter`.
* Attempts to use matter from the RCD.
*
* Arguments:
* * amount - the amount of matter that was used.
* * amount - the amount of matter to use
*/
/obj/item/rcd/proc/useResource(amount, mob/user)
/obj/item/rcd/use(amount)
if(matter < amount)
return FALSE
matter -= amount
@@ -617,7 +607,7 @@
* Arguments:
* * amount - an amount of matter to check for
*/
/obj/item/rcd/proc/checkResource(amount, mob/user)
/obj/item/rcd/tool_use_check(mob/user, amount)
. = matter >= amount
if(!. && user)
to_chat(user, no_ammo_message)
@@ -639,13 +629,13 @@
/obj/item/rcd/borg/syndicate
power_use_multiplier = 80
/obj/item/rcd/borg/useResource(amount, mob/user)
if(!isrobot(user))
/obj/item/rcd/borg/use(amount)
var/mob/living/silicon/robot/R = usr
if(!istype(R))
return FALSE
var/mob/living/silicon/robot/R = user
return R.cell.use(amount * power_use_multiplier)
/obj/item/rcd/borg/checkResource(amount, mob/user)
/obj/item/rcd/borg/tool_use_check(mob/user, amount)
if(!isrobot(user))
return FALSE
var/mob/living/silicon/robot/R = user
@@ -675,8 +665,8 @@
name = "combat RCD"
icon_state = "crcd"
item_state = "crcd"
max_matter = MATTER_500
matter = MATTER_500
max_matter = 500
matter = 500
canRwall = TRUE
/obj/item/rcd_ammo
@@ -701,9 +691,6 @@
/obj/item/rcd_ammo/large
ammoamt = 100
#undef MATTER_100
#undef MATTER_500
#undef TAB_AIRLOCK_TYPE
#undef TAB_AIRLOCK_ACCESS
#undef MODE_TURF
@@ -19,14 +19,14 @@
//Bottles for borg liquid squirters. PSSH PSSH
/obj/item/reagent_containers/spray/alien
name = "liquid synthesizer"
desc = "squirts alien liquids."
name = "generic chemical synthesizer"
desc = "If you can see this, make an issue report on GitHub. Something has gone wrong!"
icon = 'icons/mob/alien.dmi'
icon_state = "borg-default"
/obj/item/reagent_containers/spray/alien/smoke
name = "smoke synthesizer"
desc = "squirts smokey liquids."
name = "smokescreen module"
desc = "Releases a dense smoke cloud that cannot be seen through. Your thermal vision is still able to see targets through it."
icon = 'icons/mob/alien.dmi'
icon_state = "borg-spray-smoke"
list_reagents = list("water" = 50)
@@ -50,8 +50,8 @@
reagents.check_and_add("water", volume, 2 * coeff)
/obj/item/reagent_containers/spray/alien/acid
name = "acid synthesizer"
desc = "squirts burny liquids."
name = "polyacid synthesizer"
desc = "Sprays concentrated polyacid."
icon = 'icons/mob/alien.dmi'
icon_state = "borg-spray-acid"
list_reagents = list("facid" = 125, "sacid" = 125)
@@ -60,20 +60,14 @@
reagents.check_and_add("facid", volume / 2, 2 * coeff) // Volume / 2 here becuase there should be an even amount of both chems.
reagents.check_and_add("sacid", volume / 2, 2 * coeff)
/obj/item/reagent_containers/spray/alien/stun
name = "paralytic toxin synthesizer"
desc = "squirts ether."
icon = 'icons/mob/alien.dmi'
icon_state = "borg-spray-stun"
list_reagents = list("ether" = 250)
/obj/item/reagent_containers/spray/alien/stun/cyborg_recharge(coeff, emagged)
reagents.check_and_add("ether", volume, 2 * coeff)
//SKREEEEEEEEEEEE tool
/obj/item/flash/cyborg/alien
name = "eye flash"
desc = "Useful for taking pictures, making friends and flash-frying chips."
icon = 'icons/mob/alien.dmi'
icon_state = "borg-flash"
/obj/item/flash/cyborg/alien/cyborg_recharge(coeff, emagged)
if(broken)
broken = FALSE
times_used = 0
icon_state = "borg-flash"
@@ -374,7 +374,7 @@
/obj/structure/closet/get_remote_view_fullscreens(mob/user)
if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1)
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/stretch/impaired, 1)
/obj/structure/closet/ex_act(severity)
for(var/atom/A in contents)
+2 -2
View File
@@ -241,7 +241,7 @@
/obj/structure/morgue/get_remote_view_fullscreens(mob/user)
if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/stretch/impaired, 2)
/*
* Morgue tray
@@ -534,7 +534,7 @@ GLOBAL_LIST_EMPTY(crematoriums)
/obj/structure/crematorium/get_remote_view_fullscreens(mob/user)
if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/stretch/impaired, 2)
/*
* Crematorium tray
+2 -2
View File
@@ -359,13 +359,13 @@ GLOBAL_LIST_EMPTY(safes)
drill.song.start_playing(driller)
notify_ghosts("Security assault in progress in [get_area(src)]!", enter_link="<a href=byond://?src=[UID()];follow=1>(Click to jump to!)</a>", source = src, action = NOTIFY_FOLLOW)
for(var/mob/dead/observer/O in GLOB.player_list)
O.overlay_fullscreen("payback", /atom/movable/screen/fullscreen/payback, 0)
O.overlay_fullscreen("payback", /atom/movable/screen/fullscreen/stretch/payback, 0)
addtimer(CALLBACK(src, PROC_REF(ghost_payback_phase_2)), 2.7 SECONDS)
/obj/structure/safe/proc/ghost_payback_phase_2()
for(var/mob/dead/observer/O in GLOB.player_list)
O.clear_fullscreen("payback")
O.overlay_fullscreen("payback", /atom/movable/screen/fullscreen/payback, 1)
O.overlay_fullscreen("payback", /atom/movable/screen/fullscreen/stretch/payback, 1)
addtimer(CALLBACK(src, PROC_REF(clear_payback)), 2 MINUTES)
/obj/structure/safe/proc/clear_payback()
+7 -5
View File
@@ -2149,18 +2149,20 @@
if(ismindshielded(player.current))
possible_traitors -= player
if(length(possible_traitors))
var/datum/mind/newtraitormind = pick(possible_traitors)
var/datum/mind/new_traitor_mind = pick(possible_traitors)
var/datum/objective/assassinate/kill_objective = new()
kill_objective.target = H.mind
kill_objective.explanation_text = "Assassinate [H.mind.name], the [H.mind.assigned_role]"
newtraitormind.add_mind_objective(kill_objective)
new_traitor_mind.add_mind_objective(kill_objective)
var/datum/antagonist/traitor/T = new()
T.give_objectives = FALSE
to_chat(newtraitormind.current, "<span class='danger'>ATTENTION:</span> It is time to pay your debt to the Syndicate...")
to_chat(newtraitormind.current, "<b>Goal: <span class='danger'>KILL [H.real_name]</span>, currently in [get_area(H.loc)]</b>")
newtraitormind.add_antag_datum(T)
to_chat(new_traitor_mind.current, "<span class='danger'>ATTENTION:</span> It is time to pay your debt to the Syndicate...")
to_chat(new_traitor_mind.current, "<b>Goal: <span class='danger'>KILL [H.real_name]</span>, currently in [get_area(H.loc)]</b>")
new_traitor_mind.add_antag_datum(T)
message_admins("[key_name_admin(new_traitor_mind)] was chosen to be the traitor for a smite!")
log_admin("[key_name(new_traitor_mind)] was made into a traitor to hunt [key_name(H)] for 'Crew Traitor' smite.")
else
to_chat(usr, "<span class='warning'>ERROR: Unable to find any valid candidate to send after [H].</span>")
return
@@ -482,7 +482,7 @@
return
/obj/machinery/atmospherics/unary/cryo_cell/get_remote_view_fullscreens(mob/user)
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1)
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/stretch/impaired, 1)
/obj/machinery/atmospherics/unary/cryo_cell/update_remote_sight(mob/living/user)
return //we don't see the pipe network while inside cryo.
@@ -270,7 +270,7 @@
//bad recipe, ruins the drink
var/contents = pick("thick goop", "pungent sludge", "unspeakable slurry", "gross-looking concoction", "eldritch abomination of liquids")
visible_message("<span class='warning'>The [con_type] fills with \an [contents]...</span>")
drink_container.reagents.add_reagent(pick("????", "toxic_slurry", "meatslurry", "glowing_slury", "fishwater"), pick(30, 50))
drink_container.reagents.add_reagent(pick("????", "toxic_slurry", "meatslurry", "glowing_slurry", "fishwater"), pick(30, 50))
drink_container.name = "Liquid Mistakes"
drink_container.desc = "WARNING: CONTENTS MAY BE AWFUL, DRINK AT OWN RISK."
else
@@ -234,7 +234,7 @@
/obj/effect/hallucination/delamination_alarm/Initialize(mapload, mob/living/carbon/target)
. = ..()
target.playsound_local(target, 'sound/machines/engine_alert2.ogg', 25, FALSE, 30, 30)
target.hear_radio(message_to_multilingual("Danger! Crystal hyperstructure integrity faltering! Integrity: [rand(30, 50)]%"), vname = "supermatter crystal", part_a = "<span class='[SSradio.frequency_span_class(PUB_FREQ)]'><b>\[[get_frequency_name(PUB_FREQ)]\]</b> <span class='name'>", part_b = "</span> <span class='message'>")
target.hear_radio(message_to_multilingual("<b>Danger! Crystal hyperstructure integrity faltering! Integrity: [rand(30, 50)]%</b>"), vname = "supermatter crystal", part_a = "<span class='[SSradio.frequency_span_class(PUB_FREQ)]'><b>\[[get_frequency_name(PUB_FREQ)]\]</b> <span class='name'>", part_b = "</span> <span class='message'>")
/**
* # Hallucination - Plasma Flood
@@ -72,7 +72,7 @@
inv.update_icon()
if(wear_suit)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown) //if the inventory is open ...
wear_suit.screen_loc = ui_oclothing //TODO //...draw the item in the inventory screen
client.screen += wear_suit //Either way, add the item to the HUD
@@ -319,7 +319,7 @@
severity = 9
if(-INFINITY to -95)
severity = 10
overlay_fullscreen("crit", /atom/movable/screen/fullscreen/crit, severity)
overlay_fullscreen("crit", /atom/movable/screen/fullscreen/stretch/crit, severity)
else if(stat == CONSCIOUS)
if(check_death_method())
clear_fullscreen("crit")
@@ -340,7 +340,7 @@
severity = 6
if(45 to INFINITY)
severity = 7
overlay_fullscreen("oxy", /atom/movable/screen/fullscreen/oxy, severity)
overlay_fullscreen("oxy", /atom/movable/screen/fullscreen/stretch/oxy, severity)
else
clear_fullscreen("oxy")
@@ -356,7 +356,7 @@
if(45 to 70) severity = 4
if(70 to 85) severity = 5
if(85 to INFINITY) severity = 6
overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity)
overlay_fullscreen("brute", /atom/movable/screen/fullscreen/stretch/brute, severity)
else
clear_fullscreen("brute")
@@ -353,7 +353,7 @@
if((E && (E.status & ORGAN_DEAD)) || !.)
return FALSE
/mob/living/carbon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, laser_pointer = FALSE, type = /atom/movable/screen/fullscreen/flash)
/mob/living/carbon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, laser_pointer = FALSE, type = /atom/movable/screen/fullscreen/stretch/flash)
//Parent proc checks if a mob can_be_flashed()
. = ..()
@@ -1201,9 +1201,9 @@ so that different stomachs can handle things in different ways VB*/
/mob/living/carbon/proc/update_tint()
var/tinttotal = get_total_tint()
if(tinttotal >= TINT_BLIND)
overlay_fullscreen("tint", /atom/movable/screen/fullscreen/blind)
overlay_fullscreen("tint", /atom/movable/screen/fullscreen/stretch/blind)
else if(tinttotal >= TINT_IMPAIR)
overlay_fullscreen("tint", /atom/movable/screen/fullscreen/impaired, 2)
overlay_fullscreen("tint", /atom/movable/screen/fullscreen/stretch/impaired, 2)
else
clear_fullscreen("tint", 0)
@@ -567,7 +567,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
inv.update_icon()
if(w_uniform && istype(w_uniform, /obj/item/clothing/under))
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown) //if the inventory is open ...
w_uniform.screen_loc = ui_iclothing //...draw the item in the inventory screen
client.screen += w_uniform //Either way, add the item to the HUD
@@ -644,7 +644,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
inv.update_icon()
if(wear_id)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
wear_id.screen_loc = ui_id
client.screen += wear_id
@@ -660,7 +660,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
inv.update_icon()
if(gloves)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown) //if the inventory is open ...
gloves.screen_loc = ui_gloves //...draw the item in the inventory screen
client.screen += gloves //Either way, add the item to the HUD
@@ -702,7 +702,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
if(glasses)
var/mutable_appearance/new_glasses
var/obj/item/organ/external/head/head_organ = get_organ("head")
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown) //if the inventory is open ...
glasses.screen_loc = ui_glasses //...draw the item in the inventory screen
client.screen += glasses //Either way, add the item to the HUD
@@ -744,7 +744,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
if(l_ear || r_ear)
if(l_ear)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown) //if the inventory is open ...
l_ear.screen_loc = ui_l_ear //...draw the item in the inventory screen
client.screen += l_ear //Either way, add the item to the HUD
@@ -761,7 +761,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
overlays_standing[EARS_LAYER] = mutable_appearance('icons/mob/clothing/ears.dmi', "[t_type]", layer = -EARS_LAYER)
if(r_ear)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown) //if the inventory is open ...
r_ear.screen_loc = ui_r_ear //...draw the item in the inventory screen
client.screen += r_ear //Either way, add the item to the HUD
@@ -786,7 +786,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
inv.update_icon()
if(shoes)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown) //if the inventory is open ...
shoes.screen_loc = ui_shoes //...draw the item in the inventory screen
client.screen += shoes //Either way, add the item to the HUD
@@ -822,7 +822,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
inv.update_icon()
if(s_store)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
s_store.screen_loc = ui_sstore1
client.screen += s_store
@@ -872,7 +872,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
if(inv)
inv.update_icon()
if(hud_used.hud_shown && belt)
if(hud_used.hud_version == HUD_STYLE_STANDARD && belt)
client.screen += belt
belt.screen_loc = ui_belt
@@ -899,7 +899,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
inv.update_icon()
if(wear_suit && istype(wear_suit, /obj/item/clothing/suit))
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown) //if the inventory is open ...
wear_suit.screen_loc = ui_oclothing //TODO //...draw the item in the inventory screen
client.screen += wear_suit //Either way, add the item to the HUD
@@ -948,7 +948,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
if(inv)
inv.update_icon()
if(hud_used.hud_shown)
if(hud_used.hud_version == HUD_STYLE_STANDARD)
if(l_store)
client.screen += l_store
l_store.screen_loc = ui_storage1
@@ -1082,21 +1082,21 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
//update whether our head item appears on our hud.
/mob/living/carbon/human/update_hud_head(obj/item/I)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown)
I.screen_loc = ui_head
client.screen += I
//update whether our mask item appears on our hud.
/mob/living/carbon/human/update_hud_wear_mask(obj/item/I)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
if(hud_used.inventory_shown)
I.screen_loc = ui_mask
client.screen += I
//update whether our back item appears on our hud.
/mob/living/carbon/human/update_hud_back(obj/item/I)
if(client && hud_used && hud_used.hud_shown)
if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD)
I.screen_loc = ui_back
client.screen += I
@@ -13,7 +13,7 @@
/mob/living/carbon/human/update_nearsighted_effects()
var/obj/item/clothing/glasses/G = glasses
if(HAS_TRAIT(src, TRAIT_NEARSIGHT) && (!istype(G) || !G.prescription))
overlay_fullscreen("nearsighted", /atom/movable/screen/fullscreen/impaired, 1)
overlay_fullscreen("nearsighted", /atom/movable/screen/fullscreen/stretch/impaired, 1)
else
clear_fullscreen("nearsighted")
+1 -1
View File
@@ -828,7 +828,7 @@
return TRUE
//called when the mob receives a bright flash
/mob/living/proc/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, laser_pointer = FALSE, type = /atom/movable/screen/fullscreen/flash)
/mob/living/proc/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, laser_pointer = FALSE, type = /atom/movable/screen/fullscreen/stretch/flash)
if(can_be_flashed(intensity, override_blindness_check))
overlay_fullscreen("flash", type)
addtimer(CALLBACK(src, PROC_REF(clear_fullscreen), "flash", 25), 25)
+1 -1
View File
@@ -173,7 +173,7 @@
healths.icon_state = "health7"
severity = 6
if(severity > 0)
overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity)
overlay_fullscreen("brute", /atom/movable/screen/fullscreen/stretch/brute, severity)
else
clear_fullscreen("brute")
if(health <= HEALTH_THRESHOLD_CRIT)
@@ -1,12 +1,22 @@
/mob/living/update_blind_effects()
/mob/living/update_blind_effects(sleeping = FALSE, force_clear_sleeping = FALSE)
if(force_clear_sleeping) //We force it on waking up, as if you are blind from other methods it will refuse to clear it.
clear_fullscreen("sleepblind")
clear_fullscreen("disky")
if(!has_vision(information_only=TRUE))
overlay_fullscreen("blind", /atom/movable/screen/fullscreen/blind)
if(sleeping)
overlay_fullscreen("sleepblind", /atom/movable/screen/fullscreen/center/blind/sleeping, animated = 2 SECONDS)
overlay_fullscreen("disky", /atom/movable/screen/fullscreen/center/blind/disky, animated = 7 SECONDS)
throw_alert("blind", /atom/movable/screen/alert/blind)
return TRUE
overlay_fullscreen("blind", /atom/movable/screen/fullscreen/stretch/blind)
throw_alert("blind", /atom/movable/screen/alert/blind)
return TRUE
else
clear_fullscreen("blind")
clear_fullscreen("sleepblind")
clear_fullscreen("disky")
clear_alert("blind")
return 0
return FALSE
/mob/living/update_blurry_effects()
var/atom/movable/plane_master_controller/game_plane_master_controller = hud_used?.plane_master_controllers[PLANE_MASTERS_GAME]
@@ -19,7 +29,7 @@
/mob/living/update_druggy_effects()
if(AmountDruggy())
overlay_fullscreen("high", /atom/movable/screen/fullscreen/high)
overlay_fullscreen("high", /atom/movable/screen/fullscreen/stretch/high)
throw_alert("high", /atom/movable/screen/alert/high)
sound_environment_override = SOUND_ENVIRONMENT_DRUGGED
else
@@ -29,7 +39,7 @@
/mob/living/update_nearsighted_effects()
if(HAS_TRAIT(src, TRAIT_NEARSIGHT))
overlay_fullscreen("nearsighted", /atom/movable/screen/fullscreen/impaired, 1)
overlay_fullscreen("nearsighted", /atom/movable/screen/fullscreen/stretch/impaired, 1)
else
clear_fullscreen("nearsighted")
@@ -821,13 +821,11 @@
/obj/item/crowbar/cyborg/red,
/obj/item/melee/energy/alien/claws,
/obj/item/flash/cyborg/alien,
/obj/item/reagent_containers/spray/alien/stun,
/obj/item/reagent_containers/spray/alien/smoke,
)
emag_override_modules = list(/obj/item/reagent_containers/spray/alien/acid)
special_rechargables = list(
/obj/item/reagent_containers/spray/alien/acid,
/obj/item/reagent_containers/spray/alien/stun,
/obj/item/reagent_containers/spray/alien/smoke
)
@@ -447,7 +447,7 @@
/mob/living/silicon/get_access()
return IGNORE_ACCESS //silicons always have access
/mob/living/silicon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/flash/noise)
/mob/living/silicon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/stretch/flash/noise)
if(affect_silicon)
return ..()
@@ -285,12 +285,11 @@
back_to_hunt()
return
if(no_handcuffs) // should we not cuff?
if(!(iscarbon(target) && target.canBeHandcuffed()))
back_to_idle()
return
if(!(iscarbon(target) && target.canBeHandcuffed()))
back_to_idle()
if(no_handcuffs) // should we not cuff?
return
if(currently_cuffing)
@@ -347,14 +347,14 @@
back_to_hunt()
return
// target is stunned and nearby
if(no_handcuffs) // should we not cuff?
back_to_idle()
return
if(!(iscarbon(target) && target.canBeHandcuffed()))
back_to_idle()
return
if(no_handcuffs) // should we not cuff?
return
if(currently_cuffing)
return
@@ -103,9 +103,21 @@ Difficulty: Hard
BL = new /mob/living/simple_animal/hostile/ancient_robot_leg(loc, src, BOTTOM_LEFT)
beam = new /obj/effect/abstract(loc)
mode = pick(BLUESPACE, GRAV, PYRO, FLUX, VORTEX, CRYO) //picks one of the 6 cores
if(mode == FLUX) // Main attack is shock, so flux makes it stronger
melee_damage_lower = 25
melee_damage_upper = 25
switch(mode)
if(BLUESPACE)
desc += " It emits sparks of blue energy."
if(GRAV)
desc += " Gravity seems to distort around it."
if(PYRO)
desc += " You see flames burning around it."
if(FLUX) // Main attack is shock, so flux makes it stronger
melee_damage_lower = 25
melee_damage_upper = 25
desc += " It seems to overflow with energy."
if(VORTEX)
desc += " You see space bend and distort around it."
if(CRYO)
desc += " The air surrounding it is cold and listless."
body_shield()
add_overlay("[mode]")
add_overlay("eyes")
@@ -141,7 +141,7 @@ Difficulty: Hard
H.apply_status_effect(STATUS_EFFECT_BUBBLEGUM_CURSE, src)
if(second_life)
H.clear_fullscreen("Bubblegum")
H.overlay_fullscreen("Bubblegum", /atom/movable/screen/fullscreen/fog, 2)
H.overlay_fullscreen("Bubblegum", /atom/movable/screen/fullscreen/stretch/fog, 2)
/mob/living/simple_animal/hostile/megafauna/bubblegum/death(gibbed)
@@ -194,7 +194,7 @@
healths.icon_state = "slime_health7"
severity = 6
if(severity > 0)
overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity)
overlay_fullscreen("brute", /atom/movable/screen/fullscreen/stretch/brute, severity)
else
clear_fullscreen("brute")
+6 -2
View File
@@ -19,8 +19,10 @@
if(updating)
update_sight()
update_blind_effects()
update_blind_effects(TRUE)
set_typing_indicator(FALSE)
if(hud_used && client)
hud_used.show_hud(HUD_STYLE_ACTIONHUD)
return TRUE
@@ -40,7 +42,9 @@
if(updating)
update_sight()
update_blind_effects()
update_blind_effects(force_clear_sleeping = TRUE)
if(hud_used && client)
hud_used.show_hud(HUD_STYLE_STANDARD)
return TRUE
+1 -1
View File
@@ -1254,7 +1254,7 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
sync_nightvision_screen() //Sync up the overlay used for nightvision to the amount of see_in_dark a mob has. This needs to be called everywhere sync_lighting_plane_alpha() is.
/mob/proc/sync_nightvision_screen()
var/atom/movable/screen/fullscreen/see_through_darkness/S = screens["see_through_darkness"]
var/atom/movable/screen/fullscreen/stretch/see_through_darkness/S = screens["see_through_darkness"]
if(S)
var/suffix = ""
switch(see_in_dark)
+2 -2
View File
@@ -363,8 +363,8 @@
if(!Process_Spacemove(get_dir(pulling.loc, A)))
return
var/target_turf = get_step(pulling, get_dir(pulling.loc, A))
if(!Adjacent(target_turf)) //Make sure the turf we are trying to pull to is adjacent to the user.
return
if(get_dist(target_turf, loc) > 1) // Make sure the turf we are trying to pull to is adjacent to the user.
return // We do not use Adjacent() here because it checks if there are dense objects in the way, making it impossible to move an object to the side if we're blocked on both sides.
if(ismob(pulling))
var/mob/M = pulling
var/atom/movable/t = M.pulling
+3 -3
View File
@@ -30,7 +30,7 @@
/// Overlay we add to each grabbed atom.
var/image/kinesis_icon
/// Our mouse movement catcher.
var/atom/movable/screen/fullscreen/cursor_catcher/kinesis/kinesis_catcher
var/atom/movable/screen/fullscreen/stretch/cursor_catcher/kinesis/kinesis_catcher
/// The sounds playing while we grabbed an object.
var/datum/looping_sound/kinesis/soundloop
///The pixel_X of whatever we were grabbing before hand.
@@ -83,7 +83,7 @@
pre_pixel_x = grabbed_atom.pixel_x
pre_pixel_y = grabbed_atom.pixel_y
beam.chain = beam.Beam(grabbed_atom, icon_state = "kinesis", icon='icons/effects/beam.dmi', time = 100 SECONDS, maxdistance = 15, beam_type = /obj/effect/ebeam, beam_sleep_time = 3)
kinesis_catcher = mod.wearer.overlay_fullscreen("kinesis", /atom/movable/screen/fullscreen/cursor_catcher/kinesis, 0)
kinesis_catcher = mod.wearer.overlay_fullscreen("kinesis", /atom/movable/screen/fullscreen/stretch/cursor_catcher/kinesis, 0)
kinesis_catcher.assign_to_mob(mod.wearer)
soundloop.start()
START_PROCESSING(SSfastprocess, src)
@@ -249,7 +249,7 @@
complexity = 0
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
/atom/movable/screen/fullscreen/cursor_catcher/kinesis
/atom/movable/screen/fullscreen/stretch/cursor_catcher/kinesis
icon = 'icons/mob/screen_kinesis.dmi'
icon_state = "kinesis"
@@ -348,7 +348,7 @@
if(STAGE_ONE)
steps = 1
if(STAGE_TWO)
steps = 3//Yes this is right
steps = 2
if(STAGE_THREE)
steps = 3
if(STAGE_FOUR)
@@ -323,7 +323,7 @@
var/image/causality_field = image(icon, null, "causality_field")
add_overlay(causality_field)
var/speaking = "[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated."
var/speaking = "<span class='reallybig'>[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated.</span>"
for(var/mob/M in GLOB.player_list) // for all players
var/turf/T = get_turf(M)
if(istype(T) && atoms_share_level(T, src)) // if the player is on the same zlevel as the SM shared
@@ -336,7 +336,7 @@
damage = explosion_point - 1 // One point below exploding, so it will re-start the countdown once unfrozen
return
if(damage < explosion_point) // Cutting it a bit close there engineers
radio.autosay("[safe_alert] Failsafe has been disengaged.", name, null)
radio.autosay("<span class='big'>[safe_alert] Failsafe has been disengaged.</span>", name, null)
cut_overlay(causality_field, TRUE)
final_countdown = FALSE
remove_filter(list("outline", "icon"))
@@ -345,9 +345,9 @@
sleep(10)
continue
else if(i > 50)
speaking = "[DisplayTimeText(i, TRUE)] remain before causality stabilization."
speaking = "<b>[DisplayTimeText(i, TRUE)] remain before causality stabilization.</b>"
else
speaking = "[i*0.1]..."
speaking = "<span class='reallybig'>[i * 0.1]...</span>"
radio.autosay(speaking, name, null)
sleep(10)
@@ -648,27 +648,27 @@
//Oh shit it's bad, time to freak out
if(damage > emergency_point)
radio.autosay("[emergency_alert] Integrity: [get_integrity()]%", name, null)
radio.autosay("<span class='big'>[emergency_alert] Integrity: [get_integrity()]%</span>", name, null)
lastwarning = REALTIMEOFDAY
if(!has_reached_emergency)
investigate_log("has reached the emergency point for the first time.", "supermatter")
message_admins("[src] has reached the emergency point [ADMIN_JMP(src)].")
has_reached_emergency = TRUE
else if(damage >= damage_archived) // The damage is still going up
radio.autosay("[warning_alert] Integrity: [get_integrity()]%", name, "Engineering")
radio.autosay("<b>[warning_alert] Integrity: [get_integrity()]%</b>", name, "Engineering")
lastwarning = REALTIMEOFDAY - (WARNING_DELAY * 5)
else // Phew, we're safe
radio.autosay("[safe_alert] Integrity: [get_integrity()]%", name, "Engineering")
radio.autosay("<b>[safe_alert] Integrity: [get_integrity()]%</b>", name, "Engineering")
lastwarning = REALTIMEOFDAY
if(power > POWER_PENALTY_THRESHOLD)
radio.autosay("Warning: Hyperstructure has reached dangerous power level.", name, "Engineering")
radio.autosay("<b>Warning: Hyperstructure has reached dangerous power level.</b>", name, "Engineering")
if(powerloss_inhibitor < 0.5)
radio.autosay("DANGER: CHARGE INERTIA CHAIN REACTION IN PROGRESS.", name, "Engineering")
radio.autosay("<b>DANGER: CHARGE INERTIA CHAIN REACTION IN PROGRESS.</b>", name, "Engineering")
if(combined_gas > MOLE_CRUNCH_THRESHOLD)
radio.autosay("Warning: Critical coolant mass reached.", name, "Engineering")
radio.autosay("<b>Warning: Critical coolant mass reached.</b>", name, "Engineering")
//Boom (Mind blown)
if(damage > explosion_point)
countdown()
@@ -33,7 +33,7 @@
return
/datum/supermatter_event/proc/on_end()
sm_radio_say("Anomalous crystal activity has ended.")
sm_radio_say("<b>Anomalous crystal activity has ended.</b>")
supermatter.heat_penalty_threshold = SUPERMATTER_HEAT_PENALTY_THRESHOLD
supermatter.gas_multiplier = 1
supermatter.power_additive = 0
@@ -120,7 +120,7 @@
duration = 1 MINUTES
/datum/supermatter_event/bravo_tier/alert_engi()
sm_radio_say("Anomalous crystal activity detected! Activity class: [name]. Operator intervention is required!")
sm_radio_say("<b>Anomalous crystal activity detected! Activity class: [name]. Operator intervention is required!</b>")
// more gas
@@ -150,7 +150,7 @@
duration = 10 SECONDS
/datum/supermatter_event/alpha_tier/alert_engi()
sm_radio_say("ALERT: Critical anomalous crystal activity detected! Activity class: [name]. IMMEDIATE Operator intervention is REQUIRED!")
sm_radio_say("<span class='big'>ALERT: Critical anomalous crystal activity detected! Activity class: [name]. IMMEDIATE Operator intervention is REQUIRED!</span>")
/datum/supermatter_event/alpha_tier/apc_short
name = "A-1"
@@ -181,16 +181,16 @@
duration = 7 MINUTES // 2 MINUTES of s-tier anomaly
/datum/supermatter_event/sierra_tier/alert_engi()
general_radio_say("ALERT: Anomalous supermatter state expected in: 5 minutes.")
sm_radio_say("EMERGENCY ALERT: 5 MINUTES UNTIL [supermatter] EXHIBITS [name] CLASS ANOMALOUS ACTIVITY!")
general_radio_say("<span class='big'>ALERT: Anomalous supermatter state expected in: 5 minutes.</span>")
sm_radio_say("<span class='reallybig'>EMERGENCY ALERT: 5 MINUTES UNTIL [supermatter] EXHIBITS [name] CLASS ANOMALOUS ACTIVITY!</span>")
/datum/supermatter_event/sierra_tier/on_start()
addtimer(CALLBACK(src, PROC_REF(start_sierra_event)), 5 MINUTES)
supermatter.has_run_sclass = TRUE
/datum/supermatter_event/sierra_tier/proc/start_sierra_event()
general_radio_say("ALERT: ANOMALOUS SUPERMATTER STATE DETECTED!")
sm_radio_say("EMERGENCY ALERT: Class [name] anomalous behavior in progress!")
general_radio_say("<span class='big'>ALERT: ANOMALOUS SUPERMATTER STATE DETECTED!</span>")
sm_radio_say("<span class='reallybig'>EMERGENCY ALERT: Class [name] anomalous behavior in progress!</span>")
//S class events
//Arc-type
@@ -11,6 +11,7 @@
var/temp_html = ""
var/printing = null
var/wait = null
var/selected_strain_index = 1
var/obj/item/reagent_containers/beaker = null
/obj/machinery/computer/pandemic/Initialize(mapload)
@@ -26,23 +27,33 @@
stat |= BROKEN
update_icon()
/obj/machinery/computer/pandemic/proc/GetVirusByIndex(index)
/obj/machinery/computer/pandemic/proc/GetViruses()
if(beaker && beaker.reagents)
if(length(beaker.reagents.reagent_list))
var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list
if(BL)
if(BL.data && BL.data["viruses"])
var/list/viruses = BL.data["viruses"]
return viruses[index]
return viruses
/obj/machinery/computer/pandemic/proc/GetResistancesByIndex(index)
/obj/machinery/computer/pandemic/proc/GetVirusByIndex(index)
var/list/viruses = GetViruses()
if(viruses && index > 0 && index <= length(viruses))
return viruses[index]
/obj/machinery/computer/pandemic/proc/GetResistances()
if(beaker && beaker.reagents)
if(length(beaker.reagents.reagent_list))
var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list
if(BL)
if(BL.data && BL.data["resistances"])
var/list/resistances = BL.data["resistances"]
return resistances[index]
return resistances
/obj/machinery/computer/pandemic/proc/GetResistancesByIndex(index)
var/list/resistances = GetResistances()
if(resistances && index > 0 && index <= length(resistances))
return resistances[index]
/obj/machinery/computer/pandemic/proc/GetVirusTypeByIndex(index)
var/datum/disease/D = GetVirusByIndex(index)
@@ -68,117 +79,233 @@
if(!wait)
. += "waitlight"
/obj/machinery/computer/pandemic/Topic(href, href_list)
/obj/machinery/computer/pandemic/proc/create_culture(name, bottle_type = "culture", cooldown = 50)
var/obj/item/reagent_containers/glass/bottle/B = new/obj/item/reagent_containers/glass/bottle(loc)
B.icon_state = "round_bottle"
B.pixel_x = rand(-3, 3)
B.pixel_y = rand(-3, 3)
replicator_cooldown(cooldown)
B.name = "[name] [bottle_type] bottle"
return B
/obj/machinery/computer/pandemic/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
usr.set_machine(src)
if(!beaker) return
if(href_list["create_vaccine"])
if(!wait)
var/obj/item/reagent_containers/glass/bottle/B = new/obj/item/reagent_containers/glass/bottle(loc)
if(B)
B.pixel_x = rand(-3, 3)
B.pixel_y = rand(-3, 3)
var/path = GetResistancesByIndex(text2num(href_list["create_vaccine"]))
var/vaccine_type = path
var/vaccine_name = "Unknown"
if(!ispath(vaccine_type))
if(GLOB.archive_diseases[path])
var/datum/disease/D = GLOB.archive_diseases[path]
if(D)
vaccine_name = D.name
vaccine_type = path
else if(vaccine_type)
var/datum/disease/D = new vaccine_type(0, null)
if(D)
vaccine_name = D.name
if(vaccine_type)
B.name = "[vaccine_name] vaccine bottle"
B.reagents.add_reagent("vaccine", 15, list(vaccine_type))
replicator_cooldown(200)
else
temp_html = "The replicator is not ready yet."
updateUsrDialog()
if(inoperable())
return
else if(href_list["create_virus_culture"])
if(!wait)
var/type = GetVirusTypeByIndex(text2num(href_list["create_virus_culture"]))//the path is received as string - converting
. = TRUE
switch(action)
if("clone_strain")
if(wait)
atom_say("The replicator is not ready yet.")
return
var/strain_index = text2num(params["strain_index"])
if(isnull(strain_index))
atom_say("Unable to respond to command.")
return
var/datum/disease/virus = GetVirusByIndex(strain_index)
var/datum/disease/D = null
if(!virus)
atom_say("Unable to find requested strain.")
return
var/type = virus.GetDiseaseID()
if(!ispath(type))
D = GetVirusByIndex(text2num(href_list["create_virus_culture"]))
var/datum/disease/advance/A = GLOB.archive_diseases[D.GetDiseaseID()]
var/datum/disease/advance/A = GLOB.archive_diseases[type]
if(A)
D = new A.type(0, A)
else if(type)
if(type in GLOB.diseases) // Make sure this is a disease
D = new type(0, null)
if(!D)
atom_say("Unable to synthesize requested strain.")
return
var/name = tgui_input_text(usr, "Name:", "Name the culture", D.name, MAX_NAME_LEN)
var/default_name = ""
if(D.name == "Unknown" || D.name == "")
default_name = replacetext(beaker.name, new/regex(" culture bottle\\Z", "g"), "")
else
default_name = D.name
var/name = tgui_input_text(usr, "Name:", "Name the culture", default_name, MAX_NAME_LEN)
if(name == null || wait)
return
var/obj/item/reagent_containers/glass/bottle/B = new/obj/item/reagent_containers/glass/bottle(loc)
B.icon_state = "round_bottle"
B.pixel_x = rand(-3, 3)
B.pixel_y = rand(-3, 3)
replicator_cooldown(50)
var/list/data = list("viruses"=list(D))
B.name = "[name] culture bottle"
var/obj/item/reagent_containers/glass/bottle/B = create_culture(name)
B.desc = "A small bottle. Contains [D.agent] culture in synthblood medium."
B.reagents.add_reagent("blood",20,data)
updateUsrDialog()
else
temp_html = "The replicator is not ready yet."
updateUsrDialog()
return
else if(href_list["empty_beaker"])
beaker.reagents.clear_reagents()
eject_beaker()
updateUsrDialog()
return
else if(href_list["eject"])
eject_beaker()
updateUsrDialog()
return
else if(href_list["clear"])
temp_html = ""
updateUsrDialog()
return
else if(href_list["name_disease"])
var/new_name = tgui_input_text(usr, "Name the Disease", "New Name", max_length = MAX_NAME_LEN)
if(!new_name)
return
if(..())
return
var/id = GetVirusTypeByIndex(text2num(href_list["name_disease"]))
if(GLOB.archive_diseases[id])
var/datum/disease/advance/A = GLOB.archive_diseases[id]
B.reagents.add_reagent("blood", 20, list("viruses" = list(D)))
if("clone_vaccine")
if(wait)
atom_say("The replicator is not ready yet.")
return
var/resistance_index = text2num(params["resistance_index"])
if(isnull(resistance_index))
atom_say("Unable to find requested antibody.")
return
var/vaccine_type = GetResistancesByIndex(resistance_index)
var/vaccine_name = "Unknown"
if(!ispath(vaccine_type))
if(GLOB.archive_diseases[vaccine_type])
var/datum/disease/D = GLOB.archive_diseases[vaccine_type]
if(D)
vaccine_name = D.name
else if(vaccine_type)
var/datum/disease/D = new vaccine_type(0, null)
if(D)
vaccine_name = D.name
if(!vaccine_type)
atom_say("Unable to synthesize requested antibody.")
return
var/obj/item/reagent_containers/glass/bottle/B = create_culture(vaccine_name, "vaccine", 200)
B.reagents.add_reagent("vaccine", 15, list(vaccine_type))
if("eject_beaker")
eject_beaker()
if("destroy_eject_beaker")
beaker.reagents.clear_reagents()
eject_beaker()
if("print_release_forms")
var/strain_index = text2num(params["strain_index"])
if(isnull(strain_index))
atom_say("Unable to respond to command.")
return
var/type = GetVirusTypeByIndex(strain_index)
if(!type)
atom_say("Unable to find requested strain.")
return
var/datum/disease/advance/A = GLOB.archive_diseases[type]
if(!A)
atom_say("Unable to find requested strain.")
return
print_form(A, usr)
if("name_strain")
var/strain_index = text2num(params["strain_index"])
if(isnull(strain_index))
atom_say("Unable to respond to command.")
return
var/type = GetVirusTypeByIndex(strain_index)
if(!type)
atom_say("Unable to find requested strain.")
return
var/datum/disease/advance/A = GLOB.archive_diseases[type]
if(!A)
atom_say("Unable to find requested strain.")
return
if(A.name != "Unknown")
atom_say("Request rejected. Strain already has a name.")
return
var/new_name = tgui_input_text(usr, "Name the Strain", "New Name", max_length = MAX_NAME_LEN)
if(!new_name)
return
A.AssignName(new_name)
for(var/datum/disease/advance/AD in GLOB.active_diseases)
AD.Refresh()
updateUsrDialog()
else if(href_list["print_form"])
var/datum/disease/D = GetVirusByIndex(text2num(href_list["print_form"]))
D = GLOB.archive_diseases[D.GetDiseaseID()]//We know it's advanced no need to check
print_form(D, usr)
if("switch_strain")
var/strain_index = text2num(params["strain_index"])
if(isnull(strain_index) || strain_index < 1)
atom_say("Unable to respond to command.")
return
var/list/viruses = GetViruses()
if(strain_index > length(viruses))
atom_say("Unable to find requested strain.")
return
selected_strain_index = strain_index;
else
return FALSE
/obj/machinery/computer/pandemic/ui_state(mob/user)
return GLOB.default_state
else
usr << browse(null, "window=pandemic")
updateUsrDialog()
return
/obj/machinery/computer/pandemic/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "PanDEMIC", name)
ui.open()
add_fingerprint(usr)
/obj/machinery/computer/pandemic/ui_data(mob/user)
var/datum/reagent/blood/Blood = null
if(beaker)
var/datum/reagents/R = beaker.reagents
for(var/datum/reagent/blood/B in R.reagent_list)
if(B)
Blood = B
break
var/list/data = list(
"synthesisCooldown" = wait ? TRUE : FALSE,
"beakerLoaded" = beaker ? TRUE : FALSE,
"beakerContainsBlood" = Blood ? TRUE : FALSE,
"beakerContainsVirus" = length(Blood?.data["viruses"]) != 0,
"selectedStrainIndex" = selected_strain_index,
)
return data
/obj/machinery/computer/pandemic/ui_static_data(mob/user)
var/list/data = list()
. = data
var/datum/reagent/blood/Blood = null
if(beaker)
var/datum/reagents/R = beaker.reagents
for(var/datum/reagent/blood/B in R.reagent_list)
if(B)
Blood = B
break
var/list/strains = list()
for(var/datum/disease/D in GetViruses())
if(D.visibility_flags & HIDDEN_PANDEMIC)
continue
var/list/symptoms = list()
if(istype(D, /datum/disease/advance))
var/datum/disease/advance/A = D
D = GLOB.archive_diseases[A.GetDiseaseID()]
if(!D)
CRASH("We weren't able to get the advance disease from the archive.")
for(var/datum/symptom/S in A.symptoms)
symptoms += list(list(
"name" = S.name,
"stealth" = S.stealth,
"resistance" = S.resistance,
"stageSpeed" = S.stage_speed,
"transmissibility" = S.transmittable,
"complexity" = S.level,
))
strains += list(list(
"commonName" = D.name,
"description" = D.desc,
"bloodDNA" = Blood.data["blood_DNA"],
"bloodType" = Blood.data["blood_type"],
"diseaseAgent" = D.agent,
"possibleTreatments" = D.cure_text,
"transmissionRoute" = D.spread_text,
"symptoms" = symptoms,
"isAdvanced" = istype(D, /datum/disease/advance),
))
data["strains"] = strains
var/list/resistances = list()
for(var/resistance in GetResistances())
if(!ispath(resistance))
var/datum/disease/D = GLOB.archive_diseases[resistance]
if(D)
resistances += list(D.name)
else if(resistance)
var/datum/disease/D = new resistance(0, null)
if(D)
resistances += list(D.name)
data["resistances"] = resistances
/obj/machinery/computer/pandemic/proc/eject_beaker()
beaker.forceMove(loc)
beaker = null
icon_state = "pandemic0"
selected_strain_index = 1
//Prints a nice virus release form. Props to Urbanliner for the layout
/obj/machinery/computer/pandemic/proc/print_form(datum/disease/advance/D, mob/living/user)
@@ -241,108 +368,16 @@
P.info = info_text.Join("")
P.update_icon()
/obj/machinery/computer/pandemic/attack_ai(mob/user)
return attack_hand(user)
/obj/machinery/computer/pandemic/attack_hand(mob/user)
if(..())
return
user.set_machine(src)
var/dat = ""
if(temp_html)
dat = "[temp_html]<BR><BR><A href='byond://?src=[UID()];clear=1'>Main Menu</A>"
else if(!beaker)
dat += "Please insert beaker.<BR>"
dat += "<A href='byond://?src=[user.UID()];mach_close=pandemic'>Close</A>"
else
var/datum/reagents/R = beaker.reagents
var/datum/reagent/blood/Blood = null
for(var/datum/reagent/blood/B in R.reagent_list)
if(B)
Blood = B
break
if(!R.total_volume||!length(R.reagent_list))
dat += "The beaker is empty<BR>"
else if(!Blood)
dat += "No blood sample found in beaker."
else if(!Blood.data)
dat += "No blood data found in beaker."
else
dat += "<h3>Blood sample data:</h3>"
dat += "<b>Blood DNA:</b> [(Blood.data["blood_DNA"]||"none")]<BR>"
dat += "<b>Blood Type:</b> [(Blood.data["blood_type"]||"none")]<BR>"
if(Blood.data["viruses"])
var/list/vir = Blood.data["viruses"]
if(length(vir))
var/i = 0
for(var/thing in Blood.data["viruses"])
var/datum/disease/D = thing
i++
if(!(D.visibility_flags & HIDDEN_PANDEMIC))
if(istype(D, /datum/disease/advance))
var/datum/disease/advance/A = D
D = GLOB.archive_diseases[A.GetDiseaseID()]
if(D)
if(D.name == "Unknown")
dat += "<b><a href='byond://?src=[UID()];name_disease=[i]'>Name Disease</a></b><BR>"
else
dat += "<b><a href='byond://?src=[UID()];print_form=[i]'>Print release form</a></b><BR>"
if(!D)
CRASH("We weren't able to get the advance disease from the archive.")
dat += "<b>Disease Agent:</b> [D?"[D.agent] - <A href='byond://?src=[UID()];create_virus_culture=[i]'>Create virus culture bottle</A>":"none"]<BR>"
dat += "<b>Common name:</b> [(D.name||"none")]<BR>"
dat += "<b>Description: </b> [(D.desc||"none")]<BR>"
dat += "<b>Spread:</b> [(D.spread_text||"none")]<BR>"
dat += "<b>Possible cure:</b> [(D.cure_text||"none")]<BR><BR>"
if(istype(D, /datum/disease/advance))
var/datum/disease/advance/A = D
dat += "<b>Symptoms:</b> "
var/english_symptoms = list()
for(var/datum/symptom/S in A.symptoms)
english_symptoms += S.name
dat += english_list(english_symptoms)
else
dat += "No detectable virus in the sample."
else
dat += "No detectable virus in the sample."
dat += "<BR><b>Contains antibodies to:</b> "
if(Blood.data["resistances"])
var/list/res = Blood.data["resistances"]
if(length(res))
dat += "<ul>"
var/i = 0
for(var/type in Blood.data["resistances"])
i++
var/disease_name = "Unknown"
if(!ispath(type))
var/datum/disease/advance/A = GLOB.archive_diseases[type]
if(A)
disease_name = A.name
else
var/datum/disease/D = new type(0, null)
disease_name = D.name
dat += "<li>[disease_name] - <A href='byond://?src=[UID()];create_vaccine=[i]'>Create vaccine bottle</A></li>"
dat += "</ul><BR>"
else
dat += "nothing<BR>"
else
dat += "nothing<BR>"
dat += "<BR><A href='byond://?src=[UID()];eject=1'>Eject beaker</A>[((R.total_volume&&length(R.reagent_list)) ? "-- <A href='byond://?src=[UID()];empty_beaker=1'>Empty and eject beaker</A>":"")]<BR>"
dat += "<A href='byond://?src=[user.UID()];mach_close=pandemic'>Close</A>"
var/datum/browser/popup = new(user, "pandemic", name, 575, 400)
popup.set_content(dat)
popup.open(0)
onclose(user, "pandemic")
ui_interact(user)
/obj/machinery/computer/pandemic/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/computer/pandemic/attackby(obj/item/I, mob/user, params)
if(default_unfasten_wrench(user, I, time = 4 SECONDS))
@@ -361,6 +396,7 @@
beaker.loc = src
to_chat(user, "<span class='notice'>You add the beaker to the machine.</span>")
updateUsrDialog()
SStgui.update_uis(src, TRUE)
icon_state = "pandemic1"
else
return ..()
+1 -1
View File
@@ -545,7 +545,7 @@
/obj/machinery/disposal/get_remote_view_fullscreens(mob/user)
if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/stretch/impaired, 2)
/obj/machinery/disposal/force_eject_occupant(mob/target)
target.forceMove(get_turf(src))
+103
View File
@@ -0,0 +1,103 @@
/obj/item/whiteship_port_generator
name = "docking area signaller"
desc = "A signaling device for the NT expeditionary vessel, used to designate new docking areas."
icon = 'icons/obj/device.dmi'
icon_state = "gangtool-white"
var/list/placed_docks = list()
var/max_docks = 3
/obj/item/whiteship_port_generator/examine(mob/user)
. = ..()
var/count = max_docks - length(placed_docks)
var/plural = count > 1
. += "There [plural ? "are" : "is"] [count] use[plural ? "s" : ""] left."
/obj/item/whiteship_port_generator/attack_self(mob/living/user)
if(is_station_level(user.z))
log_admin("[key_name(user)] attempted to create a whiteship dock in the station's sector at [COORD(user)].")
to_chat(user, "<span class='notice'>New docking areas cannot be designated within the station's sector!</span>")
return
if(is_admin_level(user.z))
log_admin("[key_name(user)] attempted to create a whiteship dock on Centcomm level at [COORD(user)].")
to_chat(user, "<span class='notice'>New docking areas cannot be designated in this sector!</span>")
return
if(is_mining_level(user.z))
log_admin("[key_name(user)] attempted to create a whiteship dock on Lavaland at [COORD(user)].")
to_chat(user, "<span class='notice'>New docking areas cannot be designated planet side!</span>")
return
for(var/obj/placed_dock in placed_docks)
if(placed_dock.z == user.z)
to_chat(user, "<span class='notice'>A docking area has already been placed in this sector!</span>")
return
var/list/dir_choices = list("North" = NORTH, "East" = EAST, "South" = SOUTH, "West" = WEST)
var/dir_choice = tgui_input_list(user, "Select the new docking area orientation.", "Dock Orientation", dir_choices)
if(!dir_choice)
return
var/dest_dir = dir_choices[dir_choice]
var/turf/destination = get_step(user.loc, dest_dir)
var/obj/docking_port/stationary/whiteship/port = new(destination)
port.dir = dest_dir
var/min_x = -1
var/min_y = -1
var/max_x = -1
var/max_y = -1
var/list/ordered_turfs = port.return_ordered_turfs()
for(var/turf/T in ordered_turfs)
min_x = min_x < 0 ? T.x : min(min_x, T.x)
min_y = min_y < 0 ? T.y : min(min_y, T.y)
max_x = max_x < 0 ? T.x : max(max_x, T.x)
max_y = max_y < 0 ? T.y : max(max_y, T.y)
if(!isspaceturf(T))
to_chat(user, "<span class='notice'>Obstruction found in docking space area, aborting!</span>")
qdel(port, force = TRUE)
return
for(var/obj/O in T.contents)
if(O == port)
continue
else
to_chat(user, "<span class='notice'>Objects found in docking space area, aborting!</span>")
qdel(port, force = TRUE)
return
if(min_x <= TRANSITION_BORDER_WEST + 1 || max_x >= TRANSITION_BORDER_EAST - 1)
to_chat(user, "<span class='notice'>Docking space area too close to edge of sector, aborting!</span>")
qdel(port, force = TRUE)
return
if(min_y <= TRANSITION_BORDER_SOUTH + 1 || max_y >= TRANSITION_BORDER_NORTH - 1)
to_chat(user, "<span class='notice'>Docking space area too close to edge of sector, aborting!</span>")
qdel(port, force = TRUE)
return
placed_docks += port
var/dock_count = length(placed_docks)
var/basename = "Custom Dock #[dock_count]"
var/name = tgui_input_text(user,
message = "Select the new docking area name.",
title = "New Dock Name",
default = basename,
max_length = 20
)
port.name = name ? name : basename
port.id = "whiteship_custom_[dock_count]"
port.register()
for(var/obj/machinery/computer/shuttle/white_ship/S in GLOB.machines)
S.possible_destinations = null
S.connect()
log_admin("[key_name(user)] created a whiteship dock named '[name]' at [COORD(port)].")
if(dock_count < max_docks)
to_chat(user, "<span class='info'>Landing zone set.</span>")
else
to_chat(user, "<span class='info'>Landing zone set. The signaller vanishes!</span>")
qdel(src)
@@ -98,10 +98,12 @@
SSticker.mode.secondary_goals -= src
message_admins("[key_name_admin(usr)] removed secondary goal [src] ([admin_desc])")
log_admin("[key_name_admin(usr)] removed secondary goal [src] ([admin_desc])")
tracker.unregister(SSshuttle.supply)
qdel(src)
usr.client.modify_goals()
else if(href_list["mark_complete"])
completed = 1
tracker.unregister(SSshuttle.supply)
usr.client.modify_goals()
message_admins("[key_name_admin(usr)] marked secondary goal [src] ([admin_desc]) as complete")
log_admin("[key_name_admin(usr)] marked secondary goal [src] ([admin_desc]) as complete")
@@ -2,6 +2,7 @@
var/datum/secondary_goal_progress/real_progress
var/datum/secondary_goal_progress/temporary_progress
var/datum/station_goal/secondary/goal
var/registered = FALSE
/datum/secondary_goal_tracker/New(datum/station_goal/secondary/goal_in, datum/secondary_goal_progress/progress)
goal = goal_in
@@ -11,6 +12,8 @@
/datum/secondary_goal_tracker/proc/reset()
real_progress = new real_progress.type(goal)
temporary_progress = real_progress.Copy()
if(!registered)
register(SSshuttle.supply)
/datum/secondary_goal_tracker/proc/register(shuttle)
RegisterSignal(shuttle, COMSIG_CARGO_BEGIN_SCAN, PROC_REF(reset_tempporary_progress))
@@ -19,6 +22,7 @@
RegisterSignal(shuttle, COMSIG_CARGO_DO_PRIORITY_SELL, PROC_REF(update_progress))
RegisterSignal(shuttle, COMSIG_CARGO_SEND_ERROR, PROC_REF(update_progress))
RegisterSignal(shuttle, COMSIG_CARGO_END_SELL, PROC_REF(check_for_completion))
registered = TRUE
/datum/secondary_goal_tracker/proc/unregister(shuttle)
UnregisterSignal(shuttle, COMSIG_CARGO_BEGIN_SCAN)
@@ -27,6 +31,7 @@
UnregisterSignal(shuttle, COMSIG_CARGO_DO_PRIORITY_SELL)
UnregisterSignal(shuttle, COMSIG_CARGO_SEND_ERROR)
UnregisterSignal(shuttle, COMSIG_CARGO_END_SELL)
registered = FALSE
// Resets the temporary porgress to match the real progress.
/datum/secondary_goal_tracker/proc/reset_tempporary_progress(obj/docking_port/mobile/supply/shuttle)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 22 KiB

+1
View File
@@ -2713,6 +2713,7 @@
#include "code\modules\server_commands\servermsg.dm"
#include "code\modules\server_commands\commands\newroundannounce.dm"
#include "code\modules\shuttle\assault_pod.dm"
#include "code\modules\shuttle\dock_generator.dm"
#include "code\modules\shuttle\emergency.dm"
#include "code\modules\shuttle\ert_shuttle.dm"
#include "code\modules\shuttle\navigation_computer.dm"
+3 -2
View File
@@ -24,10 +24,11 @@ export const computeFlexClassName = (props: FlexProps) => {
};
export const computeFlexProps = (props: FlexProps) => {
const { className, direction, wrap, align, justify, inline, ...rest } = props;
const { className, direction, wrap, align, justify, inline, style, ...rest } =
props;
return computeBoxProps({
style: {
...rest.style,
...style,
'flex-direction': direction,
'flex-wrap': wrap === true ? 'wrap' : wrap,
'align-items': align,
+374
View File
@@ -0,0 +1,374 @@
import { BooleanLike } from '../../common/react';
import { InfernoNode } from 'inferno';
import { useBackend } from '../backend';
import {
Button,
Flex,
LabeledList,
Section,
Stack,
Table,
Tabs,
} from '../components';
import { Window } from '../layouts';
interface PathogenSymptom {
name: string;
stealth: number;
resistance: number;
stageSpeed: number;
transmissibility: number;
}
interface PathogenStrain {
commonName?: string;
description?: string;
bloodDNA?: string;
bloodType?: string;
diseaseAgent: string;
possibleTreatments?: string;
transmissionRoute?: string;
symptoms?: PathogenSymptom[];
isAdvanced: BooleanLike;
}
interface PanDEMICData {
synthesisCooldown: BooleanLike;
beakerLoaded: BooleanLike;
beakerContainsBlood: BooleanLike;
beakerContainsVirus: BooleanLike;
selectedStrainIndex: number;
strains?: PathogenStrain[];
resistances?: string[];
}
export const PanDEMIC = (props, context) => {
const { data } = useBackend<PanDEMICData>(context);
const {
beakerLoaded,
beakerContainsBlood,
beakerContainsVirus,
resistances = [],
} = data;
let emptyPlaceholder;
if (!beakerLoaded) {
emptyPlaceholder = <>No container loaded.</>;
} else if (!beakerContainsBlood) {
emptyPlaceholder = <>No blood sample found in the loaded container.</>;
}
return (
<Window width={575} height={510}>
<Window.Content>
<Stack fill vertical>
{emptyPlaceholder && (
<Section
title="Container Information"
buttons={<CommonCultureActions />}
>
{emptyPlaceholder}
</Section>
)}
{!!beakerContainsVirus && <CultureInformationSection />}
{resistances?.length > 0 && <ResistancesSection />}
</Stack>
</Window.Content>
</Window>
);
};
const CommonCultureActions = (props, context) => {
const { act, data } = useBackend<PanDEMICData>(context);
const { beakerLoaded } = data;
return (
<>
<Button
icon="eject"
content="Eject"
disabled={!beakerLoaded}
onClick={() => act('eject_beaker')}
/>
<Button.Confirm
icon="trash-alt"
confirmIcon="eraser"
content="Destroy"
confirmContent="Destroy"
disabled={!beakerLoaded}
onClick={() => act('destroy_eject_beaker')}
/>
</>
);
};
const StrainInformation = (
props: { strain: PathogenStrain; strainIndex: number },
context
) => {
const { act, data } = useBackend<PanDEMICData>(context);
const { beakerContainsVirus } = data;
const {
commonName,
description,
diseaseAgent,
bloodDNA,
bloodType,
possibleTreatments,
transmissionRoute,
isAdvanced,
} = props.strain;
const bloodInformation = (
<>
<LabeledList.Item label="Blood DNA">
{!bloodDNA ? (
'Undetectable'
) : (
<span style={{ 'font-family': "'Courier New', monospace" }}>
{bloodDNA}
</span>
)}
</LabeledList.Item>
<LabeledList.Item label="Blood Type">
{
<div
// blood type can sometimes contain a span
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: bloodType ?? 'Undetectable' }}
/>
}
</LabeledList.Item>
</>
);
if (!beakerContainsVirus) {
return <LabeledList>{bloodInformation}</LabeledList>;
}
let nameButtons;
if (isAdvanced) {
if (
commonName !== undefined &&
commonName !== null &&
commonName !== 'Unknown'
) {
nameButtons = (
<Button
icon="print"
content="Print Release Forms"
onClick={() =>
act('print_release_forms', {
strain_index: props.strainIndex,
})
}
style={{ 'margin-left': 'auto' }}
/>
);
} else {
nameButtons = (
<Button
icon="pen"
content="Name Disease"
onClick={() =>
act('name_strain', { strain_index: props.strainIndex })
}
style={{ 'margin-left': 'auto' }}
/>
);
}
}
return (
<LabeledList>
<LabeledList.Item label="Common Name" className="common-name-label">
<Stack horizontal align="center">
{commonName ?? 'Unknown'}
{nameButtons}
</Stack>
</LabeledList.Item>
{description && (
<LabeledList.Item label="Description">{description}</LabeledList.Item>
)}
<LabeledList.Item label="Disease Agent">{diseaseAgent}</LabeledList.Item>
{bloodInformation}
<LabeledList.Item label="Spread Vector">
{transmissionRoute ?? 'None'}
</LabeledList.Item>
<LabeledList.Item label="Possible Cures">
{possibleTreatments ?? 'None'}
</LabeledList.Item>
</LabeledList>
);
};
const StrainInformationSection = (
props: {
strain: PathogenStrain;
strainIndex: number;
sectionTitle?: string;
sectionButtons?: InfernoNode | InfernoNode[];
},
context
) => {
const { act, data } = useBackend<PanDEMICData>(context);
let synthesisCooldown = !!data.synthesisCooldown;
const appliedSectionButtons = (
<>
<Button
icon={synthesisCooldown ? 'spinner' : 'clone'}
iconSpin={synthesisCooldown}
content="Clone"
disabled={synthesisCooldown}
onClick={() => act('clone_strain', { strain_index: props.strainIndex })}
/>
{props.sectionButtons}
</>
);
return (
<Flex.Item>
<Section
title={props.sectionTitle ?? 'Strain Information'}
buttons={appliedSectionButtons}
>
<StrainInformation
strain={props.strain}
strainIndex={props.strainIndex}
/>
</Section>
</Flex.Item>
);
};
const CultureInformationSection = (props, context) => {
const { act, data } = useBackend<PanDEMICData>(context);
const { selectedStrainIndex, strains } = data;
const selectedStrain = strains[selectedStrainIndex - 1];
if (strains.length === 1) {
return (
<>
<StrainInformationSection
strain={strains[0]}
strainIndex={1}
sectionButtons={<CommonCultureActions />}
/>
{strains[0].symptoms?.length > 0 && (
<StrainSymptomsSection strain={strains[0]} />
)}
</>
);
}
const sectionButtons = <CommonCultureActions />;
return (
<Stack.Item grow>
<Section title="Culture Information" fill buttons={sectionButtons}>
<Flex direction="column" style={{ 'height': '100%' }}>
<Flex.Item>
<Tabs>
{strains.map((strain, i) => (
<Tabs.Tab
key={i}
icon="virus"
selected={selectedStrainIndex - 1 === i}
onClick={() => act('switch_strain', { strain_index: i + 1 })}
>
{strain.commonName ?? 'Unknown'}
</Tabs.Tab>
))}
</Tabs>
</Flex.Item>
<StrainInformationSection
strain={selectedStrain}
strainIndex={selectedStrainIndex}
/>
{selectedStrain.symptoms?.length > 0 && (
<StrainSymptomsSection
className="remove-section-bottom-padding"
strain={selectedStrain}
/>
)}
</Flex>
</Section>
</Stack.Item>
);
};
const sum = (values: number[]) => {
return values.reduce((r, value) => r + value, 0);
};
const StrainSymptomsSection = (props: {
className?: string;
strain: PathogenStrain;
}) => {
const { symptoms } = props.strain;
return (
<Flex.Item grow>
<Section title="Infection Symptoms" fill className={props.className}>
<Table className="symptoms-table">
<Table.Row>
<Table.Cell>Name</Table.Cell>
<Table.Cell>Stealth</Table.Cell>
<Table.Cell>Resistance</Table.Cell>
<Table.Cell>Stage Speed</Table.Cell>
<Table.Cell>Transmissibility</Table.Cell>
</Table.Row>
{symptoms.map((symptom, index) => (
<Table.Row key={index}>
<Table.Cell>{symptom.name}</Table.Cell>
<Table.Cell>{symptom.stealth}</Table.Cell>
<Table.Cell>{symptom.resistance}</Table.Cell>
<Table.Cell>{symptom.stageSpeed}</Table.Cell>
<Table.Cell>{symptom.transmissibility}</Table.Cell>
</Table.Row>
))}
<Table.Row className="table-spacer" />
<Table.Row>
<Table.Cell style={{ 'font-weight': 'bold' }}>Total</Table.Cell>
<Table.Cell>{sum(symptoms.map((s) => s.stealth))}</Table.Cell>
<Table.Cell>{sum(symptoms.map((s) => s.resistance))}</Table.Cell>
<Table.Cell>{sum(symptoms.map((s) => s.stageSpeed))}</Table.Cell>
<Table.Cell>
{sum(symptoms.map((s) => s.transmissibility))}
</Table.Cell>
</Table.Row>
</Table>
</Section>
</Flex.Item>
);
};
const VaccineSynthesisIcons = ['flask', 'vial', 'eye-dropper'];
const ResistancesSection = (props, context) => {
const { act, data } = useBackend<PanDEMICData>(context);
const { synthesisCooldown, beakerContainsVirus, resistances } = data;
return (
<Stack.Item>
<Section
title="Antibodies"
fill
buttons={!beakerContainsVirus && <CommonCultureActions />}
>
<Stack horizontal wrap>
{resistances.map((r, i) => (
<Stack.Item key={i}>
<Button
icon={VaccineSynthesisIcons[i % VaccineSynthesisIcons.length]}
disabled={!!synthesisCooldown}
onClick={() =>
act('clone_vaccine', { resistance_index: i + 1 })
}
mr="0.5em"
/>
{r}
</Stack.Item>
))}
</Stack>
</Section>
</Stack.Item>
);
};
@@ -0,0 +1,30 @@
.symptoms-table {
border-collapse: separate;
border-spacing: 0 0.5ex;
height: 100%;
}
.symptoms-table > tbody > tr:first-child {
width: 100%;
font-weight: bold;
}
.symptoms-table > tbody > tr:nth-child(2) > td:first-child {
padding-top: 0.5ex;
}
.symptoms-table > tbody > tr > td:nth-child(n + 2) {
text-align: center;
}
.common-name-label > .LabeledList__cell {
vertical-align: middle;
}
.table-spacer {
height: 100%;
}
.remove-section-bottom-padding .Section__content {
padding-bottom: 0;
}
+1
View File
@@ -57,6 +57,7 @@
@include meta.load-css('./interfaces/Newscaster.scss');
@include meta.load-css('./interfaces/NuclearBomb.scss');
@include meta.load-css('./interfaces/OreRedemption.scss');
@include meta.load-css('./interfaces/PanDEMIC.scss');
@include meta.load-css('./interfaces/PDA.scss');
@include meta.load-css('./interfaces/PdaPainter.scss');
@include meta.load-css('./interfaces/PoolController.scss');
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long